From d3bb4185d06450111ecae1c72f0d3af1b46cc4e1 Mon Sep 17 00:00:00 2001 From: pst Date: Sun, 3 Nov 1996 17:03:03 +0000 Subject: [PATCH] Import GDB in its full glory (all 25mb). We'll put it on a diet once it's fully registered. (This is the second try, the first import ignored .info files but not .info-* files, for some reason. I'm going to make this consistent.) Reviewed by: core Approved for: 2.2 --- contrib/gdb/COPYING | 339 + contrib/gdb/COPYING.LIB | 481 ++ contrib/gdb/Makefile.in | 1366 +++ contrib/gdb/README | 50 + contrib/gdb/bfd/COPYING | 339 + contrib/gdb/bfd/Makefile.in | 1090 +++ contrib/gdb/bfd/PORTING | 83 + contrib/gdb/bfd/TODO | 25 + contrib/gdb/bfd/VERSION | 1 + contrib/gdb/bfd/acconfig.h | 19 + contrib/gdb/bfd/aclocal.m4 | 43 + contrib/gdb/bfd/aix386-core.c | 285 + contrib/gdb/bfd/aout-adobe.c | 528 ++ contrib/gdb/bfd/aout-arm.c | 548 ++ contrib/gdb/bfd/aout-encap.c | 236 + contrib/gdb/bfd/aout-ns32k.c | 399 + contrib/gdb/bfd/aout-target.h | 607 ++ contrib/gdb/bfd/aout0.c | 32 + contrib/gdb/bfd/aout32.c | 23 + contrib/gdb/bfd/aout64.c | 31 + contrib/gdb/bfd/aoutf1.h | 788 ++ contrib/gdb/bfd/aoutx.h | 5525 ++++++++++++ contrib/gdb/bfd/archive.c | 2094 +++++ contrib/gdb/bfd/archures.c | 720 ++ contrib/gdb/bfd/bfd-in.h | 668 ++ contrib/gdb/bfd/bfd-in2.h | 2479 ++++++ contrib/gdb/bfd/bfd.c | 1144 +++ contrib/gdb/bfd/binary.c | 348 + contrib/gdb/bfd/bout.c | 1471 ++++ contrib/gdb/bfd/cache.c | 347 + contrib/gdb/bfd/cf-i386lynx.c | 31 + contrib/gdb/bfd/cf-m68klynx.c | 223 + contrib/gdb/bfd/cf-sparclynx.c | 28 + contrib/gdb/bfd/cisco-core.c | 313 + contrib/gdb/bfd/coff-a29k.c | 641 ++ contrib/gdb/bfd/coff-alpha.c | 2390 ++++++ contrib/gdb/bfd/coff-apollo.c | 162 + contrib/gdb/bfd/coff-arm.c | 537 ++ contrib/gdb/bfd/coff-aux.c | 332 + contrib/gdb/bfd/coff-go32.c | 25 + contrib/gdb/bfd/coff-h8300.c | 650 ++ contrib/gdb/bfd/coff-h8500.c | 355 + contrib/gdb/bfd/coff-i386.c | 493 ++ contrib/gdb/bfd/coff-i860.c | 423 + contrib/gdb/bfd/coff-i960.c | 683 ++ contrib/gdb/bfd/coff-m68k.c | 203 + contrib/gdb/bfd/coff-m88k.c | 311 + contrib/gdb/bfd/coff-mips.c | 2596 ++++++ contrib/gdb/bfd/coff-pmac.c | 27 + contrib/gdb/bfd/coff-ppc.c | 3255 ++++++++ contrib/gdb/bfd/coff-rs6000.c | 1403 ++++ contrib/gdb/bfd/coff-sh.c | 1525 ++++ contrib/gdb/bfd/coff-sparc.c | 278 + contrib/gdb/bfd/coff-u68k.c | 35 + contrib/gdb/bfd/coff-w65.c | 446 + contrib/gdb/bfd/coff-we32k.c | 110 + contrib/gdb/bfd/coff-z8k.c | 281 + contrib/gdb/bfd/coffcode.h | 3612 ++++++++ contrib/gdb/bfd/coffgen.c | 2121 +++++ contrib/gdb/bfd/cofflink.c | 2327 ++++++ contrib/gdb/bfd/coffswap.h | 807 ++ contrib/gdb/bfd/config.bfd | 491 ++ contrib/gdb/bfd/config.in | 67 + contrib/gdb/bfd/configure | 2439 ++++++ contrib/gdb/bfd/configure.bat | 18 + contrib/gdb/bfd/configure.host | 128 + contrib/gdb/bfd/configure.in | 577 ++ contrib/gdb/bfd/corefile.c | 106 + contrib/gdb/bfd/cpu-a29k.c | 39 + contrib/gdb/bfd/cpu-alpha.c | 38 + contrib/gdb/bfd/cpu-arm.c | 39 + contrib/gdb/bfd/cpu-h8300.c | 246 + contrib/gdb/bfd/cpu-h8500.c | 199 + contrib/gdb/bfd/cpu-hppa.c | 54 + contrib/gdb/bfd/cpu-i386.c | 38 + contrib/gdb/bfd/cpu-i860.c | 40 + contrib/gdb/bfd/cpu-i960.c | 162 + contrib/gdb/bfd/cpu-m68k.c | 42 + contrib/gdb/bfd/cpu-m88k.c | 42 + contrib/gdb/bfd/cpu-mips.c | 85 + contrib/gdb/bfd/cpu-ns32k.c | 868 ++ contrib/gdb/bfd/cpu-powerpc.c | 124 + contrib/gdb/bfd/cpu-rs6000.c | 70 + contrib/gdb/bfd/cpu-sh.c | 68 + contrib/gdb/bfd/cpu-sparc.c | 111 + contrib/gdb/bfd/cpu-vax.c | 39 + contrib/gdb/bfd/cpu-w65.c | 54 + contrib/gdb/bfd/cpu-we32k.c | 39 + contrib/gdb/bfd/cpu-z8k.c | 198 + contrib/gdb/bfd/demo64.c | 24 + contrib/gdb/bfd/dep-in.sed | 24 + contrib/gdb/bfd/doc/ChangeLog | 268 + contrib/gdb/bfd/doc/Makefile.in | 311 + contrib/gdb/bfd/doc/bfd.texinfo | 348 + contrib/gdb/bfd/doc/bfdsumm.texi | 148 + contrib/gdb/bfd/doc/chew.c | 1551 ++++ contrib/gdb/bfd/doc/doc.str | 158 + contrib/gdb/bfd/doc/proto.str | 135 + contrib/gdb/bfd/ecoff.c | 4740 +++++++++++ contrib/gdb/bfd/ecofflink.c | 2452 ++++++ contrib/gdb/bfd/ecoffswap.h | 853 ++ contrib/gdb/bfd/elf-bfd.h | 858 ++ contrib/gdb/bfd/elf.c | 3318 ++++++++ contrib/gdb/bfd/elf32-gen.c | 37 + contrib/gdb/bfd/elf32-hppa.c | 2984 +++++++ contrib/gdb/bfd/elf32-hppa.h | 152 + contrib/gdb/bfd/elf32-i386.c | 1546 ++++ contrib/gdb/bfd/elf32-i860.c | 33 + contrib/gdb/bfd/elf32-m68k.c | 1600 ++++ contrib/gdb/bfd/elf32-m88k.c | 35 + contrib/gdb/bfd/elf32-mips.c | 5867 +++++++++++++ contrib/gdb/bfd/elf32-ppc.c | 2554 ++++++ contrib/gdb/bfd/elf32-sparc.c | 1795 ++++ contrib/gdb/bfd/elf32.c | 23 + contrib/gdb/bfd/elf64-gen.c | 37 + contrib/gdb/bfd/elf64-sparc.c | 421 + contrib/gdb/bfd/elf64.c | 22 + contrib/gdb/bfd/elfcode.h | 1406 ++++ contrib/gdb/bfd/elfcore.h | 475 ++ contrib/gdb/bfd/elflink.c | 372 + contrib/gdb/bfd/elflink.h | 3424 ++++++++ contrib/gdb/bfd/elfxx-target.h | 450 + contrib/gdb/bfd/filemode.c | 193 + contrib/gdb/bfd/format.c | 319 + contrib/gdb/bfd/freebsd.h | 109 + contrib/gdb/bfd/gen-aout.c | 101 + contrib/gdb/bfd/genlink.h | 106 + contrib/gdb/bfd/hash.c | 734 ++ contrib/gdb/bfd/host-aout.c | 83 + contrib/gdb/bfd/hosts/alphalinux.h | 6 + contrib/gdb/bfd/hosts/decstation.h | 17 + contrib/gdb/bfd/hosts/delta68.h | 18 + contrib/gdb/bfd/hosts/dpx2.h | 8 + contrib/gdb/bfd/hosts/hp300bsd.h | 13 + contrib/gdb/bfd/hosts/i386bsd.h | 25 + contrib/gdb/bfd/hosts/i386linux.h | 8 + contrib/gdb/bfd/hosts/i386mach3.h | 25 + contrib/gdb/bfd/hosts/i386sco.h | 19 + contrib/gdb/bfd/hosts/i860mach3.h | 27 + contrib/gdb/bfd/hosts/m68kaux.h | 16 + contrib/gdb/bfd/hosts/m68klinux.h | 6 + contrib/gdb/bfd/hosts/m88kmach3.h | 11 + contrib/gdb/bfd/hosts/mipsbsd.h | 12 + contrib/gdb/bfd/hosts/mipsmach3.h | 10 + contrib/gdb/bfd/hosts/news-mips.h | 12 + contrib/gdb/bfd/hosts/news.h | 9 + contrib/gdb/bfd/hosts/pc532mach.h | 24 + contrib/gdb/bfd/hosts/riscos.h | 10 + contrib/gdb/bfd/hosts/symmetry.h | 20 + contrib/gdb/bfd/hosts/tahoe.h | 12 + contrib/gdb/bfd/hosts/vaxbsd.h | 19 + contrib/gdb/bfd/hosts/vaxult.h | 8 + contrib/gdb/bfd/hosts/vaxult2.h | 8 + contrib/gdb/bfd/hp300bsd.c | 38 + contrib/gdb/bfd/hp300hpux.c | 865 ++ contrib/gdb/bfd/hppa_stubs.h | 23 + contrib/gdb/bfd/hppabsd-core.c | 305 + contrib/gdb/bfd/hpux-core.c | 270 + contrib/gdb/bfd/i386aout.c | 68 + contrib/gdb/bfd/i386bsd.c | 46 + contrib/gdb/bfd/i386dynix.c | 80 + contrib/gdb/bfd/i386freebsd.c | 33 + contrib/gdb/bfd/i386linux.c | 762 ++ contrib/gdb/bfd/i386lynx.c | 563 ++ contrib/gdb/bfd/i386mach3.c | 65 + contrib/gdb/bfd/i386msdos.c | 243 + contrib/gdb/bfd/i386netbsd.c | 33 + contrib/gdb/bfd/i386os9k.c | 370 + contrib/gdb/bfd/ieee.c | 3738 +++++++++ contrib/gdb/bfd/ihex.c | 1005 +++ contrib/gdb/bfd/init.c | 50 + contrib/gdb/bfd/irix-core.c | 263 + contrib/gdb/bfd/libaout.h | 608 ++ contrib/gdb/bfd/libbfd-in.h | 503 ++ contrib/gdb/bfd/libbfd.c | 1197 +++ contrib/gdb/bfd/libbfd.h | 735 ++ contrib/gdb/bfd/libcoff-in.h | 482 ++ contrib/gdb/bfd/libcoff.h | 823 ++ contrib/gdb/bfd/libecoff.h | 352 + contrib/gdb/bfd/libhppa.h | 549 ++ contrib/gdb/bfd/libieee.h | 135 + contrib/gdb/bfd/libnlm.h | 264 + contrib/gdb/bfd/liboasys.h | 83 + contrib/gdb/bfd/linker.c | 2781 ++++++ contrib/gdb/bfd/lynx-core.c | 233 + contrib/gdb/bfd/m68k4knetbsd.c | 35 + contrib/gdb/bfd/m68klinux.c | 767 ++ contrib/gdb/bfd/m68klynx.c | 54 + contrib/gdb/bfd/m68knetbsd.c | 35 + contrib/gdb/bfd/m88kmach3.c | 38 + contrib/gdb/bfd/makefile.dos | 49 + contrib/gdb/bfd/mipsbsd.c | 467 ++ contrib/gdb/bfd/mpw-config.in | 73 + contrib/gdb/bfd/mpw-make.sed | 70 + contrib/gdb/bfd/netbsd-core.c | 310 + contrib/gdb/bfd/netbsd.h | 108 + contrib/gdb/bfd/newsos3.c | 40 + contrib/gdb/bfd/nlm-target.h | 228 + contrib/gdb/bfd/nlm.c | 55 + contrib/gdb/bfd/nlm32-alpha.c | 892 ++ contrib/gdb/bfd/nlm32-i386.c | 451 + contrib/gdb/bfd/nlm32-ppc.c | 1045 +++ contrib/gdb/bfd/nlm32-sparc.c | 440 + contrib/gdb/bfd/nlm32.c | 21 + contrib/gdb/bfd/nlm64.c | 21 + contrib/gdb/bfd/nlmcode.h | 2057 +++++ contrib/gdb/bfd/nlmswap.h | 157 + contrib/gdb/bfd/ns32knetbsd.c | 53 + contrib/gdb/bfd/oasys.c | 1533 ++++ contrib/gdb/bfd/opncls.c | 604 ++ contrib/gdb/bfd/osf-core.c | 256 + contrib/gdb/bfd/pc532-mach.c | 121 + contrib/gdb/bfd/pe-arm.c | 32 + contrib/gdb/bfd/pe-i386.c | 30 + contrib/gdb/bfd/pe-ppc.c | 39 + contrib/gdb/bfd/pei-arm.c | 33 + contrib/gdb/bfd/pei-i386.c | 33 + contrib/gdb/bfd/pei-ppc.c | 44 + contrib/gdb/bfd/peicode.h | 1861 +++++ contrib/gdb/bfd/ptrace-core.c | 233 + contrib/gdb/bfd/reloc.c | 2391 ++++++ contrib/gdb/bfd/reloc16.c | 289 + contrib/gdb/bfd/riscix.c | 644 ++ contrib/gdb/bfd/rs6000-core.c | 396 + contrib/gdb/bfd/section.c | 976 +++ contrib/gdb/bfd/som.c | 5999 +++++++++++++ contrib/gdb/bfd/som.h | 224 + contrib/gdb/bfd/sparclynx.c | 265 + contrib/gdb/bfd/sparcnetbsd.c | 33 + contrib/gdb/bfd/srec.c | 1324 +++ contrib/gdb/bfd/stab-syms.c | 57 + contrib/gdb/bfd/sunos.c | 2767 ++++++ contrib/gdb/bfd/syms.c | 1084 +++ contrib/gdb/bfd/sysdep.h | 114 + contrib/gdb/bfd/targets.c | 886 ++ contrib/gdb/bfd/tekhex.c | 1031 +++ contrib/gdb/bfd/trad-core.c | 316 + contrib/gdb/bfd/versados.c | 906 ++ contrib/gdb/bfd/xcofflink.c | 5798 +++++++++++++ contrib/gdb/gdb/.gdbinit | 16 + contrib/gdb/gdb/COPYING | 339 + contrib/gdb/gdb/ChangeLog | 1415 ++++ contrib/gdb/gdb/ChangeLog-93 | 7597 +++++++++++++++++ contrib/gdb/gdb/ChangeLog-94 | 5705 +++++++++++++ contrib/gdb/gdb/ChangeLog-95 | 4882 +++++++++++ contrib/gdb/gdb/Makefile.in | 1534 ++++ contrib/gdb/gdb/NEWS | 1338 +++ contrib/gdb/gdb/README | 583 ++ contrib/gdb/gdb/TODO | 468 ++ contrib/gdb/gdb/acconfig.h | 9 + contrib/gdb/gdb/aclocal.m4 | 605 ++ contrib/gdb/gdb/alpha-nat.c | 243 + contrib/gdb/gdb/alpha-tdep.c | 1274 +++ contrib/gdb/gdb/annotate.c | 540 ++ contrib/gdb/gdb/annotate.h | 95 + contrib/gdb/gdb/arm-convert.s | 16 + contrib/gdb/gdb/arm-tdep.c | 826 ++ contrib/gdb/gdb/arm-xdep.c | 276 + contrib/gdb/gdb/bcache.c | 189 + contrib/gdb/gdb/bcache.h | 72 + contrib/gdb/gdb/blockframe.c | 854 ++ contrib/gdb/gdb/breakpoint.c | 4117 +++++++++ contrib/gdb/gdb/breakpoint.h | 424 + contrib/gdb/gdb/buildsym.c | 1039 +++ contrib/gdb/gdb/buildsym.h | 259 + contrib/gdb/gdb/c-exp.tab.c | 2705 ++++++ contrib/gdb/gdb/c-exp.y | 1641 ++++ contrib/gdb/gdb/c-lang.c | 478 ++ contrib/gdb/gdb/c-lang.h | 84 + contrib/gdb/gdb/c-typeprint.c | 831 ++ contrib/gdb/gdb/c-valprint.c | 469 ++ contrib/gdb/gdb/call-cmds.h | 28 + contrib/gdb/gdb/callback.c | 349 + contrib/gdb/gdb/callback.h | 41 + contrib/gdb/gdb/ch-exp.c | 2090 +++++ contrib/gdb/gdb/ch-lang.c | 653 ++ contrib/gdb/gdb/ch-lang.h | 39 + contrib/gdb/gdb/ch-typeprint.c | 346 + contrib/gdb/gdb/ch-valprint.c | 664 ++ contrib/gdb/gdb/coff-solib.c | 131 + contrib/gdb/gdb/coff-solib.h | 60 + contrib/gdb/gdb/coffread.c | 2164 +++++ contrib/gdb/gdb/command.c | 1466 ++++ contrib/gdb/gdb/command.h | 259 + contrib/gdb/gdb/complaints.c | 171 + contrib/gdb/gdb/complaints.h | 46 + contrib/gdb/gdb/config.in | 90 + contrib/gdb/gdb/config/i386/cygwin32.mh | 6 + contrib/gdb/gdb/config/i386/cygwin32.mt | 6 + contrib/gdb/gdb/config/i386/fbsd.mh | 5 + contrib/gdb/gdb/config/i386/fbsd.mt | 3 + contrib/gdb/gdb/config/i386/gdbserve.mt | 3 + contrib/gdb/gdb/config/i386/go32.mh | 9 + contrib/gdb/gdb/config/i386/i386aix.mh | 12 + contrib/gdb/gdb/config/i386/i386aix.mt | 7 + contrib/gdb/gdb/config/i386/i386aout.mt | 3 + contrib/gdb/gdb/config/i386/i386bsd.mh | 7 + contrib/gdb/gdb/config/i386/i386bsd.mt | 3 + contrib/gdb/gdb/config/i386/i386dgux.mh | 14 + contrib/gdb/gdb/config/i386/i386gnu.mh | 36 + contrib/gdb/gdb/config/i386/i386gnu.mt | 3 + contrib/gdb/gdb/config/i386/i386lynx.mh | 11 + contrib/gdb/gdb/config/i386/i386lynx.mt | 3 + contrib/gdb/gdb/config/i386/i386m3.mh | 11 + contrib/gdb/gdb/config/i386/i386m3.mt | 3 + contrib/gdb/gdb/config/i386/i386mach.mh | 10 + contrib/gdb/gdb/config/i386/i386mk.mh | 8 + contrib/gdb/gdb/config/i386/i386mk.mt | 6 + contrib/gdb/gdb/config/i386/i386nw.mt | 3 + contrib/gdb/gdb/config/i386/i386os9k.mt | 3 + contrib/gdb/gdb/config/i386/i386sco.mh | 13 + contrib/gdb/gdb/config/i386/i386sco4.mh | 12 + contrib/gdb/gdb/config/i386/i386sco5.mh | 17 + contrib/gdb/gdb/config/i386/i386sol2.mh | 12 + contrib/gdb/gdb/config/i386/i386sol2.mt | 3 + contrib/gdb/gdb/config/i386/i386v.mh | 8 + contrib/gdb/gdb/config/i386/i386v.mt | 3 + contrib/gdb/gdb/config/i386/i386v32.mh | 9 + contrib/gdb/gdb/config/i386/i386v4.mh | 14 + contrib/gdb/gdb/config/i386/i386v4.mt | 3 + contrib/gdb/gdb/config/i386/linux.mh | 13 + contrib/gdb/gdb/config/i386/linux.mt | 3 + contrib/gdb/gdb/config/i386/nbsd.mh | 5 + contrib/gdb/gdb/config/i386/nbsd.mt | 3 + contrib/gdb/gdb/config/i386/ncr3000.mh | 21 + contrib/gdb/gdb/config/i386/ncr3000.mt | 3 + contrib/gdb/gdb/config/i386/nm-fbsd.h | 101 + contrib/gdb/gdb/config/i386/nm-gnu.h | 22 + contrib/gdb/gdb/config/i386/nm-i386aix.h | 42 + contrib/gdb/gdb/config/i386/nm-i386bsd.h | 39 + contrib/gdb/gdb/config/i386/nm-i386lynx.h | 25 + contrib/gdb/gdb/config/i386/nm-i386mach.h | 26 + contrib/gdb/gdb/config/i386/nm-i386sco.h | 47 + contrib/gdb/gdb/config/i386/nm-i386sco4.h | 32 + contrib/gdb/gdb/config/i386/nm-i386sco5.h | 41 + contrib/gdb/gdb/config/i386/nm-i386v.h | 38 + contrib/gdb/gdb/config/i386/nm-i386v4.h | 21 + contrib/gdb/gdb/config/i386/nm-linux.h | 82 + contrib/gdb/gdb/config/i386/nm-m3.h | 22 + contrib/gdb/gdb/config/i386/nm-nbsd.h | 34 + contrib/gdb/gdb/config/i386/nm-ptx4.h | 62 + contrib/gdb/gdb/config/i386/nm-sun386.h | 27 + contrib/gdb/gdb/config/i386/nm-symmetry.h | 47 + contrib/gdb/gdb/config/i386/ptx.mh | 7 + contrib/gdb/gdb/config/i386/ptx.mt | 3 + contrib/gdb/gdb/config/i386/ptx4.mh | 7 + contrib/gdb/gdb/config/i386/ptx4.mt | 3 + contrib/gdb/gdb/config/i386/sun386.mh | 5 + contrib/gdb/gdb/config/i386/sun386.mt | 3 + contrib/gdb/gdb/config/i386/symmetry.mh | 5 + contrib/gdb/gdb/config/i386/symmetry.mt | 3 + contrib/gdb/gdb/config/i386/tm-cygwin32.h | 125 + contrib/gdb/gdb/config/i386/tm-i386.h | 309 + contrib/gdb/gdb/config/i386/tm-i386aix.h | 67 + contrib/gdb/gdb/config/i386/tm-i386bsd.h | 43 + contrib/gdb/gdb/config/i386/tm-i386gnu.h | 48 + contrib/gdb/gdb/config/i386/tm-i386lynx.h | 33 + contrib/gdb/gdb/config/i386/tm-i386m3.h | 60 + contrib/gdb/gdb/config/i386/tm-i386mk.h | 25 + contrib/gdb/gdb/config/i386/tm-i386nw.h | 49 + contrib/gdb/gdb/config/i386/tm-i386os9k.h | 63 + contrib/gdb/gdb/config/i386/tm-i386v.h | 161 + contrib/gdb/gdb/config/i386/tm-i386v4.h | 78 + contrib/gdb/gdb/config/i386/tm-linux.h | 35 + contrib/gdb/gdb/config/i386/tm-nbsd.h | 42 + contrib/gdb/gdb/config/i386/tm-ptx.h | 232 + contrib/gdb/gdb/config/i386/tm-ptx4.h | 24 + contrib/gdb/gdb/config/i386/tm-sun386.h | 205 + contrib/gdb/gdb/config/i386/tm-symmetry.h | 321 + contrib/gdb/gdb/config/i386/xm-cygwin32.h | 41 + contrib/gdb/gdb/config/i386/xm-go32.h | 31 + contrib/gdb/gdb/config/i386/xm-i386aix.h | 33 + contrib/gdb/gdb/config/i386/xm-i386bsd.h | 23 + contrib/gdb/gdb/config/i386/xm-i386gnu.h | 23 + contrib/gdb/gdb/config/i386/xm-i386lynx.h | 24 + contrib/gdb/gdb/config/i386/xm-i386m3.h | 38 + contrib/gdb/gdb/config/i386/xm-i386mach.h | 35 + contrib/gdb/gdb/config/i386/xm-i386mk.h | 25 + contrib/gdb/gdb/config/i386/xm-i386sco.h | 42 + contrib/gdb/gdb/config/i386/xm-i386v.h | 45 + contrib/gdb/gdb/config/i386/xm-i386v32.h | 24 + contrib/gdb/gdb/config/i386/xm-i386v4.h | 37 + contrib/gdb/gdb/config/i386/xm-linux.h | 46 + contrib/gdb/gdb/config/i386/xm-nbsd.h | 21 + contrib/gdb/gdb/config/i386/xm-ptx.h | 41 + contrib/gdb/gdb/config/i386/xm-ptx4.h | 25 + contrib/gdb/gdb/config/i386/xm-sun386.h | 20 + contrib/gdb/gdb/config/i386/xm-symmetry.h | 28 + contrib/gdb/gdb/config/nm-empty.h | 2 + contrib/gdb/gdb/config/nm-gnu.h | 46 + contrib/gdb/gdb/config/nm-lynx.h | 83 + contrib/gdb/gdb/config/nm-m3.h | 123 + contrib/gdb/gdb/config/nm-nbsd.h | 86 + contrib/gdb/gdb/config/nm-sysv4.h | 34 + contrib/gdb/gdb/config/tm-lynx.h | 34 + contrib/gdb/gdb/config/tm-nbsd.h | 19 + contrib/gdb/gdb/config/tm-sunos.h | 31 + contrib/gdb/gdb/config/tm-sysv4.h | 45 + contrib/gdb/gdb/config/xm-aix4.h | 96 + contrib/gdb/gdb/config/xm-lynx.h | 22 + contrib/gdb/gdb/config/xm-mpw.h | 81 + contrib/gdb/gdb/config/xm-nbsd.h | 37 + contrib/gdb/gdb/config/xm-sysv4.h | 36 + contrib/gdb/gdb/configure | 2745 ++++++ contrib/gdb/gdb/configure.in | 615 ++ contrib/gdb/gdb/copying.awk | 77 + contrib/gdb/gdb/copying.c | 327 + contrib/gdb/gdb/core-aout.c | 143 + contrib/gdb/gdb/core-regset.c | 130 + contrib/gdb/gdb/core-sol2.c | 133 + contrib/gdb/gdb/corefile.c | 339 + contrib/gdb/gdb/corelow.c | 419 + contrib/gdb/gdb/cp-valprint.c | 600 ++ contrib/gdb/gdb/cpu32bug-rom.c | 171 + contrib/gdb/gdb/cxux-nat.c | 523 ++ contrib/gdb/gdb/dbxread.c | 2556 ++++++ contrib/gdb/gdb/dcache.c | 564 ++ contrib/gdb/gdb/dcache.h | 50 + contrib/gdb/gdb/defs.h | 973 +++ contrib/gdb/gdb/demangle.c | 206 + contrib/gdb/gdb/doc/ChangeLog | 1206 +++ contrib/gdb/gdb/doc/GDBvn.texi | 1 + contrib/gdb/gdb/doc/Makefile.in | 331 + contrib/gdb/gdb/doc/a4rc.sed | 11 + contrib/gdb/gdb/doc/all-cfg.texi | 120 + contrib/gdb/gdb/doc/annotate.texi | 717 ++ contrib/gdb/gdb/doc/configure.in | 7 + contrib/gdb/gdb/doc/gdb.texinfo | 9282 +++++++++++++++++++++ contrib/gdb/gdb/doc/gdbint.texinfo | 2543 ++++++ contrib/gdb/gdb/doc/h8-cfg.texi | 47 + contrib/gdb/gdb/doc/libgdb.texinfo | 878 ++ contrib/gdb/gdb/doc/lpsrc.sed | 13 + contrib/gdb/gdb/doc/psrc.sed | 13 + contrib/gdb/gdb/doc/refcard.dvi | Bin 0 -> 21732 bytes contrib/gdb/gdb/doc/refcard.tex | 645 ++ contrib/gdb/gdb/doc/remote.texi | 1531 ++++ contrib/gdb/gdb/doc/stabs.texinfo | 4004 +++++++++ contrib/gdb/gdb/dwarfread.c | 3883 +++++++++ contrib/gdb/gdb/elfread.c | 826 ++ contrib/gdb/gdb/environ.c | 194 + contrib/gdb/gdb/environ.h | 58 + contrib/gdb/gdb/eval.c | 1780 ++++ contrib/gdb/gdb/exc_request.defs | 51 + contrib/gdb/gdb/exec.c | 677 ++ contrib/gdb/gdb/expprint.c | 634 ++ contrib/gdb/gdb/expression.h | 386 + contrib/gdb/gdb/f-exp.tab.c | 2089 +++++ contrib/gdb/gdb/f-exp.y | 1170 +++ contrib/gdb/gdb/f-lang.c | 944 +++ contrib/gdb/gdb/f-lang.h | 94 + contrib/gdb/gdb/f-typeprint.c | 454 + contrib/gdb/gdb/f-valprint.c | 748 ++ contrib/gdb/gdb/findvar.c | 1444 ++++ contrib/gdb/gdb/fork-child.c | 309 + contrib/gdb/gdb/frame.h | 196 + contrib/gdb/gdb/gdb-stabs.h | 78 + contrib/gdb/gdb/gdb.1 | 371 + contrib/gdb/gdb/gdb.gdb | 35 + contrib/gdb/gdb/gdb_stat.h | 68 + contrib/gdb/gdb/gdb_string.h | 48 + contrib/gdb/gdb/gdba.el | 2607 ++++++ contrib/gdb/gdb/gdbcmd.h | 106 + contrib/gdb/gdb/gdbcore.h | 155 + contrib/gdb/gdb/gdbserver/Makefile.in | 245 + contrib/gdb/gdb/gdbserver/README | 127 + contrib/gdb/gdb/gdbserver/configure.in | 335 + contrib/gdb/gdb/gdbserver/gdbreplay.c | 319 + contrib/gdb/gdb/gdbserver/gdbserver.1 | 103 + contrib/gdb/gdb/gdbserver/low-hppabsd.c | 379 + contrib/gdb/gdb/gdbserver/low-linux.c | 420 + contrib/gdb/gdb/gdbserver/low-lynx.c | 746 ++ contrib/gdb/gdb/gdbserver/low-sparc.c | 334 + contrib/gdb/gdb/gdbserver/low-sun3.c | 313 + contrib/gdb/gdb/gdbserver/remote-utils.c | 479 ++ contrib/gdb/gdb/gdbserver/server.c | 249 + contrib/gdb/gdb/gdbserver/server.h | 50 + contrib/gdb/gdb/gdbserver/utils.c | 113 + contrib/gdb/gdb/gdbtypes.c | 1683 ++++ contrib/gdb/gdb/gdbtypes.h | 789 ++ contrib/gdb/gdb/gnu-nat.c | 2814 +++++++ contrib/gdb/gdb/gnu-nat.h | 91 + contrib/gdb/gdb/gnu-regex.c | 1759 ++++ contrib/gdb/gdb/gnu-regex.h | 181 + contrib/gdb/gdb/go32-xdep.c | 35 + contrib/gdb/gdb/i386-stub.c | 915 ++ contrib/gdb/gdb/i386-tdep.c | 688 ++ contrib/gdb/gdb/i386aix-nat.c | 360 + contrib/gdb/gdb/i386b-nat.c | 284 + contrib/gdb/gdb/i386gnu-nat.c | 348 + contrib/gdb/gdb/i386ly-tdep.c | 42 + contrib/gdb/gdb/i386m3-nat.c | 421 + contrib/gdb/gdb/i386mach-nat.c | 163 + contrib/gdb/gdb/i386v-nat.c | 371 + contrib/gdb/gdb/i386v4-nat.c | 163 + contrib/gdb/gdb/i387-tdep.c | 107 + contrib/gdb/gdb/infcmd.c | 1375 +++ contrib/gdb/gdb/inferior.h | 382 + contrib/gdb/gdb/inflow.c | 718 ++ contrib/gdb/gdb/infptrace.c | 534 ++ contrib/gdb/gdb/infrun.c | 2224 +++++ contrib/gdb/gdb/inftarg.c | 390 + contrib/gdb/gdb/irix4-nat.c | 192 + contrib/gdb/gdb/irix5-nat.c | 1067 +++ contrib/gdb/gdb/isi-xdep.c | 20 + contrib/gdb/gdb/kdb-start.c | 35 + contrib/gdb/gdb/language.c | 1400 ++++ contrib/gdb/gdb/language.h | 431 + contrib/gdb/gdb/lynx-nat.c | 838 ++ contrib/gdb/gdb/m2-exp.tab.c | 2095 +++++ contrib/gdb/gdb/m2-exp.y | 1094 +++ contrib/gdb/gdb/m2-lang.c | 465 ++ contrib/gdb/gdb/m2-lang.h | 31 + contrib/gdb/gdb/m2-typeprint.c | 49 + contrib/gdb/gdb/m2-valprint.c | 45 + contrib/gdb/gdb/m3-nat.c | 4640 ++++++++++ contrib/gdb/gdb/m68k-stub.c | 1014 +++ contrib/gdb/gdb/m68k-tdep.c | 514 ++ contrib/gdb/gdb/m68knbsd-nat.c | 86 + contrib/gdb/gdb/m88k-nat.c | 285 + contrib/gdb/gdb/m88k-tdep.c | 616 ++ contrib/gdb/gdb/main.c | 627 ++ contrib/gdb/gdb/maint.c | 370 + contrib/gdb/gdb/mdebugread.c | 4368 ++++++++++ contrib/gdb/gdb/mem-break.c | 121 + contrib/gdb/gdb/minimon.h | 562 ++ contrib/gdb/gdb/minsyms.c | 855 ++ contrib/gdb/gdb/mipsread.c | 477 ++ contrib/gdb/gdb/mon960-rom.c | 270 + contrib/gdb/gdb/monitor.c | 1541 ++++ contrib/gdb/gdb/monitor.h | 177 + contrib/gdb/gdb/mpw-config.in | 82 + contrib/gdb/gdb/mpw-make.sed | 167 + contrib/gdb/gdb/msg.defs | 1 + contrib/gdb/gdb/msg_reply.defs | 1 + contrib/gdb/gdb/news-xdep.c | 65 + contrib/gdb/gdb/nindy-tdep.c | 73 + contrib/gdb/gdb/nlm/Makefile.in | 173 + contrib/gdb/gdb/nlm/configure | 864 ++ contrib/gdb/gdb/nlm/configure.in | 55 + contrib/gdb/gdb/nlm/gdbserve.c | 1056 +++ contrib/gdb/gdb/nlm/gdbserve.def | 42 + contrib/gdb/gdb/nlm/i386.c | 108 + contrib/gdb/gdb/nlm/i386.h | 13 + contrib/gdb/gdb/nlm/ppc.c | 257 + contrib/gdb/gdb/nlm/ppc.h | 165 + contrib/gdb/gdb/nlm/prelude.c | 67 + contrib/gdb/gdb/nlmread.c | 308 + contrib/gdb/gdb/notify.defs | 1 + contrib/gdb/gdb/ns32k-tdep.c | 27 + contrib/gdb/gdb/ns32km3-nat.c | 181 + contrib/gdb/gdb/objfiles.c | 911 ++ contrib/gdb/gdb/objfiles.h | 502 ++ contrib/gdb/gdb/op50-rom.c | 146 + contrib/gdb/gdb/os9kread.c | 1659 ++++ contrib/gdb/gdb/osfsolib.c | 955 +++ contrib/gdb/gdb/parse.c | 1013 +++ contrib/gdb/gdb/parser-defs.h | 191 + contrib/gdb/gdb/partial-stab.h | 774 ++ contrib/gdb/gdb/ppcbug-rom.c | 233 + contrib/gdb/gdb/printcmd.c | 2248 +++++ contrib/gdb/gdb/process_reply.defs | 1 + contrib/gdb/gdb/procfs.c | 3815 +++++++++ contrib/gdb/gdb/ptx4-nat.c | 209 + contrib/gdb/gdb/pyr-tdep.c | 452 + contrib/gdb/gdb/pyr-xdep.c | 370 + contrib/gdb/gdb/remote-adapt.c | 1359 +++ contrib/gdb/gdb/remote-array.c | 1465 ++++ contrib/gdb/gdb/remote-bug.c | 1053 +++ contrib/gdb/gdb/remote-e7000.c | 2066 +++++ contrib/gdb/gdb/remote-eb.c | 1009 +++ contrib/gdb/gdb/remote-es.c | 2152 +++++ contrib/gdb/gdb/remote-est.c | 174 + contrib/gdb/gdb/remote-hms.c | 1463 ++++ contrib/gdb/gdb/remote-mips.c | 2997 +++++++ contrib/gdb/gdb/remote-mm.c | 1627 ++++ contrib/gdb/gdb/remote-nindy.c | 820 ++ contrib/gdb/gdb/remote-nrom.c | 332 + contrib/gdb/gdb/remote-os9k.c | 1230 +++ contrib/gdb/gdb/remote-pa.c | 1540 ++++ contrib/gdb/gdb/remote-rdp.c | 1247 +++ contrib/gdb/gdb/remote-sim.c | 468 ++ contrib/gdb/gdb/remote-sim.h | 142 + contrib/gdb/gdb/remote-st.c | 847 ++ contrib/gdb/gdb/remote-udi.c | 1689 ++++ contrib/gdb/gdb/remote-utils.c | 646 ++ contrib/gdb/gdb/remote-utils.h | 142 + contrib/gdb/gdb/remote-vx.c | 1488 ++++ contrib/gdb/gdb/remote-vx29k.c | 188 + contrib/gdb/gdb/remote-vx68.c | 158 + contrib/gdb/gdb/remote-vx960.c | 163 + contrib/gdb/gdb/remote-vxmips.c | 201 + contrib/gdb/gdb/remote-vxsparc.c | 196 + contrib/gdb/gdb/remote.c | 1839 ++++ contrib/gdb/gdb/reply_mig_hack.awk | 123 + contrib/gdb/gdb/saber.suppress | 451 + contrib/gdb/gdb/scm-exp.c | 414 + contrib/gdb/gdb/scm-lang.c | 268 + contrib/gdb/gdb/scm-lang.h | 50 + contrib/gdb/gdb/scm-tags.h | 385 + contrib/gdb/gdb/scm-valprint.c | 404 + contrib/gdb/gdb/ser-e7kpc.c | 420 + contrib/gdb/gdb/ser-go32.c | 957 +++ contrib/gdb/gdb/ser-mac.c | 361 + contrib/gdb/gdb/ser-tcp.c | 343 + contrib/gdb/gdb/ser-unix.c | 730 ++ contrib/gdb/gdb/serial.c | 484 ++ contrib/gdb/gdb/serial.h | 182 + contrib/gdb/gdb/signals.h | 27 + contrib/gdb/gdb/solib.c | 1714 ++++ contrib/gdb/gdb/solib.h | 60 + contrib/gdb/gdb/somread.c | 470 ++ contrib/gdb/gdb/somsolib.c | 820 ++ contrib/gdb/gdb/somsolib.h | 51 + contrib/gdb/gdb/source.c | 1506 ++++ contrib/gdb/gdb/srec.h | 35 + contrib/gdb/gdb/stabsread.c | 4017 +++++++++ contrib/gdb/gdb/stabsread.h | 225 + contrib/gdb/gdb/stack.c | 1502 ++++ contrib/gdb/gdb/standalone.c | 593 ++ contrib/gdb/gdb/stop-gdb.c | 110 + contrib/gdb/gdb/stuff.c | 174 + contrib/gdb/gdb/symfile.c | 1774 ++++ contrib/gdb/gdb/symfile.h | 211 + contrib/gdb/gdb/symm-nat.c | 846 ++ contrib/gdb/gdb/symm-tdep.c | 93 + contrib/gdb/gdb/symmisc.c | 1053 +++ contrib/gdb/gdb/symtab.c | 3346 ++++++++ contrib/gdb/gdb/symtab.h | 1222 +++ contrib/gdb/gdb/target.c | 1858 +++++ contrib/gdb/gdb/target.h | 765 ++ contrib/gdb/gdb/terminal.h | 89 + contrib/gdb/gdb/thread.c | 476 ++ contrib/gdb/gdb/thread.h | 46 + contrib/gdb/gdb/top.c | 3557 ++++++++ contrib/gdb/gdb/top.h | 48 + contrib/gdb/gdb/typeprint.c | 302 + contrib/gdb/gdb/typeprint.h | 21 + contrib/gdb/gdb/umax-xdep.c | 133 + contrib/gdb/gdb/utils.c | 1948 +++++ contrib/gdb/gdb/valarith.c | 1213 +++ contrib/gdb/gdb/valops.c | 2346 ++++++ contrib/gdb/gdb/valprint.c | 1015 +++ contrib/gdb/gdb/valprint.h | 44 + contrib/gdb/gdb/value.h | 491 ++ contrib/gdb/gdb/values.c | 1418 ++++ contrib/gdb/gdb/xcoffread.c | 2767 ++++++ contrib/gdb/gdb/xcoffsolib.c | 211 + contrib/gdb/gdb/xcoffsolib.h | 56 + contrib/gdb/gdb/xmodem.c | 284 + contrib/gdb/gdb/xmodem.h | 29 + contrib/gdb/include/COPYING | 339 + contrib/gdb/include/ChangeLog | 973 +++ contrib/gdb/include/ansidecl.h | 141 + contrib/gdb/include/aout/ChangeLog | 174 + contrib/gdb/include/aout/adobe.h | 297 + contrib/gdb/include/aout/aout64.h | 475 ++ contrib/gdb/include/aout/ar.h | 36 + contrib/gdb/include/aout/dynix3.h | 71 + contrib/gdb/include/aout/encap.h | 135 + contrib/gdb/include/aout/host.h | 22 + contrib/gdb/include/aout/hp.h | 82 + contrib/gdb/include/aout/hp300hpux.h | 119 + contrib/gdb/include/aout/hppa.h | 7 + contrib/gdb/include/aout/ranlib.h | 62 + contrib/gdb/include/aout/reloc.h | 66 + contrib/gdb/include/aout/stab.def | 264 + contrib/gdb/include/aout/stab_gnu.h | 37 + contrib/gdb/include/aout/sun4.h | 219 + contrib/gdb/include/bfdlink.h | 452 + contrib/gdb/include/bout.h | 182 + contrib/gdb/include/coff/ChangeLog | 622 ++ contrib/gdb/include/coff/a29k.h | 305 + contrib/gdb/include/coff/alpha.h | 342 + contrib/gdb/include/coff/apollo.h | 248 + contrib/gdb/include/coff/arm.h | 215 + contrib/gdb/include/coff/aux-coff.h | 31 + contrib/gdb/include/coff/ecoff.h | 408 + contrib/gdb/include/coff/h8300.h | 203 + contrib/gdb/include/coff/h8500.h | 201 + contrib/gdb/include/coff/i386.h | 224 + contrib/gdb/include/coff/i860.h | 204 + contrib/gdb/include/coff/i960.h | 251 + contrib/gdb/include/coff/internal.h | 648 ++ contrib/gdb/include/coff/m68k.h | 221 + contrib/gdb/include/coff/m88k.h | 218 + contrib/gdb/include/coff/mips.h | 368 + contrib/gdb/include/coff/pe.h | 161 + contrib/gdb/include/coff/powerpc.h | 196 + contrib/gdb/include/coff/rs6000.h | 242 + contrib/gdb/include/coff/sh.h | 253 + contrib/gdb/include/coff/sparc.h | 209 + contrib/gdb/include/coff/sym.h | 484 ++ contrib/gdb/include/coff/symconst.h | 177 + contrib/gdb/include/coff/w65.h | 201 + contrib/gdb/include/coff/we32k.h | 206 + contrib/gdb/include/coff/z8k.h | 201 + contrib/gdb/include/demangle.h | 108 + contrib/gdb/include/dis-asm.h | 175 + contrib/gdb/include/elf/ChangeLog | 195 + contrib/gdb/include/elf/common.h | 239 + contrib/gdb/include/elf/dwarf.h | 319 + contrib/gdb/include/elf/external.h | 195 + contrib/gdb/include/elf/hppa.h | 94 + contrib/gdb/include/elf/internal.h | 207 + contrib/gdb/include/elf/mips.h | 298 + contrib/gdb/include/elf/ppc.h | 54 + contrib/gdb/include/elf/sparc.h | 73 + contrib/gdb/include/floatformat.h | 88 + contrib/gdb/include/fopen-bin.h | 27 + contrib/gdb/include/fopen-same.h | 27 + contrib/gdb/include/gdbm.h | 91 + contrib/gdb/include/getopt.h | 129 + contrib/gdb/include/hp-symtab.h | 983 +++ contrib/gdb/include/ieee.h | 139 + contrib/gdb/include/libiberty.h | 133 + contrib/gdb/include/mpw/ChangeLog | 61 + contrib/gdb/include/mpw/README | 1 + contrib/gdb/include/mpw/dir.h | 23 + contrib/gdb/include/mpw/dirent.h | 31 + contrib/gdb/include/mpw/fcntl.h | 124 + contrib/gdb/include/mpw/grp.h | 10 + contrib/gdb/include/mpw/mpw.h | 130 + contrib/gdb/include/mpw/pwd.h | 15 + contrib/gdb/include/mpw/spin.h | 64 + contrib/gdb/include/mpw/stat.h | 75 + contrib/gdb/include/mpw/sys/file.h | 1 + contrib/gdb/include/mpw/sys/param.h | 1 + contrib/gdb/include/mpw/sys/resource.h | 9 + contrib/gdb/include/mpw/sys/stat.h | 44 + contrib/gdb/include/mpw/sys/time.h | 13 + contrib/gdb/include/mpw/sys/types.h | 15 + contrib/gdb/include/mpw/utime.h | 7 + contrib/gdb/include/mpw/varargs.h | 9 + contrib/gdb/include/nlm/ChangeLog | 83 + contrib/gdb/include/nlm/alpha-ext.h | 166 + contrib/gdb/include/nlm/common.h | 124 + contrib/gdb/include/nlm/external.h | 174 + contrib/gdb/include/nlm/i386-ext.h | 116 + contrib/gdb/include/nlm/internal.h | 309 + contrib/gdb/include/nlm/ppc-ext.h | 163 + contrib/gdb/include/nlm/sparc32-ext.h | 120 + contrib/gdb/include/oasys.h | 152 + contrib/gdb/include/obstack.h | 518 ++ contrib/gdb/include/opcode/ChangeLog | 812 ++ contrib/gdb/include/opcode/a29k.h | 285 + contrib/gdb/include/opcode/arm.h | 294 + contrib/gdb/include/opcode/convex.h | 1711 ++++ contrib/gdb/include/opcode/h8300.h | 550 ++ contrib/gdb/include/opcode/hppa.h | 471 ++ contrib/gdb/include/opcode/i386.h | 898 ++ contrib/gdb/include/opcode/i860.h | 491 ++ contrib/gdb/include/opcode/i960.h | 509 ++ contrib/gdb/include/opcode/m68k.h | 297 + contrib/gdb/include/opcode/m88k.h | 923 ++ contrib/gdb/include/opcode/mips.h | 481 ++ contrib/gdb/include/opcode/np1.h | 422 + contrib/gdb/include/opcode/ns32k.h | 491 ++ contrib/gdb/include/opcode/pn.h | 282 + contrib/gdb/include/opcode/ppc.h | 248 + contrib/gdb/include/opcode/pyr.h | 287 + contrib/gdb/include/opcode/rs6k.h | 254 + contrib/gdb/include/opcode/sparc.h | 220 + contrib/gdb/include/opcode/tahoe.h | 213 + contrib/gdb/include/opcode/vax.h | 382 + contrib/gdb/include/os9k.h | 169 + contrib/gdb/include/progress.h | 37 + contrib/gdb/include/wait.h | 63 + contrib/gdb/libiberty/COPYING.LIB | 481 ++ contrib/gdb/libiberty/ChangeLog | 1815 ++++ contrib/gdb/libiberty/Makefile.in | 321 + contrib/gdb/libiberty/README | 129 + contrib/gdb/libiberty/alloca-botch.h | 5 + contrib/gdb/libiberty/alloca-norm.h | 16 + contrib/gdb/libiberty/alloca.c | 475 ++ contrib/gdb/libiberty/argv.c | 328 + contrib/gdb/libiberty/atexit.c | 14 + contrib/gdb/libiberty/basename.c | 43 + contrib/gdb/libiberty/bcmp.c | 49 + contrib/gdb/libiberty/bcopy.c | 35 + contrib/gdb/libiberty/bzero.c | 31 + contrib/gdb/libiberty/clock.c | 73 + contrib/gdb/libiberty/concat.c | 167 + contrib/gdb/libiberty/config.table | 63 + contrib/gdb/libiberty/config/mh-a68bsd | 2 + contrib/gdb/libiberty/config/mh-aix | 10 + contrib/gdb/libiberty/config/mh-apollo68 | 2 + contrib/gdb/libiberty/config/mh-cxux7 | 3 + contrib/gdb/libiberty/config/mh-go32 | 4 + contrib/gdb/libiberty/config/mh-hpbsd | 2 + contrib/gdb/libiberty/config/mh-irix4 | 4 + contrib/gdb/libiberty/config/mh-lynxos | 1 + contrib/gdb/libiberty/config/mh-ncr3000 | 19 + contrib/gdb/libiberty/config/mh-riscix | 6 + contrib/gdb/libiberty/config/mh-sysv | 1 + contrib/gdb/libiberty/config/mh-sysv4 | 3 + contrib/gdb/libiberty/config/mt-sunos4 | 2 + contrib/gdb/libiberty/config/mt-vxworks5 | 27 + contrib/gdb/libiberty/configure.bat | 15 + contrib/gdb/libiberty/configure.in | 77 + contrib/gdb/libiberty/copysign.c | 140 + contrib/gdb/libiberty/cplus-dem.c | 3019 +++++++ contrib/gdb/libiberty/dummy.c | 49 + contrib/gdb/libiberty/fdmatch.c | 73 + contrib/gdb/libiberty/floatformat.c | 385 + contrib/gdb/libiberty/functions.def | 67 + contrib/gdb/libiberty/getcwd.c | 52 + contrib/gdb/libiberty/getopt.c | 757 ++ contrib/gdb/libiberty/getopt1.c | 190 + contrib/gdb/libiberty/getpagesize.c | 89 + contrib/gdb/libiberty/getruntime.c | 82 + contrib/gdb/libiberty/hex.c | 33 + contrib/gdb/libiberty/index.c | 11 + contrib/gdb/libiberty/insque.c | 50 + contrib/gdb/libiberty/makefile.dos | 29 + contrib/gdb/libiberty/memchr.c | 60 + contrib/gdb/libiberty/memcmp.c | 38 + contrib/gdb/libiberty/memcpy.c | 28 + contrib/gdb/libiberty/memmove.c | 18 + contrib/gdb/libiberty/memset.c | 19 + contrib/gdb/libiberty/mpw-config.in | 9 + contrib/gdb/libiberty/mpw-make.sed | 49 + contrib/gdb/libiberty/mpw.c | 1010 +++ contrib/gdb/libiberty/msdos.c | 15 + contrib/gdb/libiberty/obstack.c | 507 ++ contrib/gdb/libiberty/random.c | 373 + contrib/gdb/libiberty/rename.c | 22 + contrib/gdb/libiberty/rindex.c | 11 + contrib/gdb/libiberty/sigsetmask.c | 30 + contrib/gdb/libiberty/spaces.c | 71 + contrib/gdb/libiberty/strcasecmp.c | 81 + contrib/gdb/libiberty/strchr.c | 34 + contrib/gdb/libiberty/strdup.c | 10 + contrib/gdb/libiberty/strerror.c | 829 ++ contrib/gdb/libiberty/strncasecmp.c | 82 + contrib/gdb/libiberty/strrchr.c | 34 + contrib/gdb/libiberty/strsignal.c | 627 ++ contrib/gdb/libiberty/strstr.c | 51 + contrib/gdb/libiberty/strtod.c | 122 + contrib/gdb/libiberty/strtol.c | 143 + contrib/gdb/libiberty/strtoul.c | 110 + contrib/gdb/libiberty/tmpnam.c | 39 + contrib/gdb/libiberty/vasprintf.c | 165 + contrib/gdb/libiberty/vfork.c | 8 + contrib/gdb/libiberty/vfprintf.c | 13 + contrib/gdb/libiberty/vmsbuild.com | 142 + contrib/gdb/libiberty/vprintf.c | 11 + contrib/gdb/libiberty/vsprintf.c | 55 + contrib/gdb/libiberty/waitpid.c | 11 + contrib/gdb/libiberty/xatexit.c | 82 + contrib/gdb/libiberty/xexit.c | 36 + contrib/gdb/libiberty/xmalloc.c | 106 + contrib/gdb/libiberty/xstrdup.c | 17 + contrib/gdb/libiberty/xstrerror.c | 54 + contrib/gdb/opcodes/ChangeLog | 1772 ++++ contrib/gdb/opcodes/Makefile.in | 305 + contrib/gdb/opcodes/dis-buf.c | 70 + contrib/gdb/opcodes/disassemble.c | 166 + contrib/gdb/opcodes/i386-dis.c | 2031 +++++ contrib/gdb/opcodes/sysdep.h | 38 + contrib/gdb/readline/doc/ChangeLog | 12 + contrib/gdb/readline/doc/Makefile.in | 94 + contrib/gdb/readline/doc/configure.in | 8 + contrib/gdb/readline/doc/hist.texinfo | 106 + contrib/gdb/readline/doc/hstech.texinfo | 311 + contrib/gdb/readline/doc/hsuser.texinfo | 153 + contrib/gdb/readline/doc/inc-hist.texi | 159 + contrib/gdb/readline/doc/rlman.texinfo | 103 + contrib/gdb/readline/doc/rltech.texinfo | 1012 +++ contrib/gdb/readline/doc/rluser.texinfo | 566 ++ 869 files changed, 441264 insertions(+) create mode 100644 contrib/gdb/COPYING create mode 100644 contrib/gdb/COPYING.LIB create mode 100644 contrib/gdb/Makefile.in create mode 100644 contrib/gdb/README create mode 100644 contrib/gdb/bfd/COPYING create mode 100644 contrib/gdb/bfd/Makefile.in create mode 100644 contrib/gdb/bfd/PORTING create mode 100644 contrib/gdb/bfd/TODO create mode 100644 contrib/gdb/bfd/VERSION create mode 100644 contrib/gdb/bfd/acconfig.h create mode 100644 contrib/gdb/bfd/aclocal.m4 create mode 100644 contrib/gdb/bfd/aix386-core.c create mode 100644 contrib/gdb/bfd/aout-adobe.c create mode 100644 contrib/gdb/bfd/aout-arm.c create mode 100644 contrib/gdb/bfd/aout-encap.c create mode 100644 contrib/gdb/bfd/aout-ns32k.c create mode 100644 contrib/gdb/bfd/aout-target.h create mode 100644 contrib/gdb/bfd/aout0.c create mode 100644 contrib/gdb/bfd/aout32.c create mode 100644 contrib/gdb/bfd/aout64.c create mode 100644 contrib/gdb/bfd/aoutf1.h create mode 100644 contrib/gdb/bfd/aoutx.h create mode 100644 contrib/gdb/bfd/archive.c create mode 100644 contrib/gdb/bfd/archures.c create mode 100644 contrib/gdb/bfd/bfd-in.h create mode 100644 contrib/gdb/bfd/bfd-in2.h create mode 100644 contrib/gdb/bfd/bfd.c create mode 100644 contrib/gdb/bfd/binary.c create mode 100644 contrib/gdb/bfd/bout.c create mode 100644 contrib/gdb/bfd/cache.c create mode 100644 contrib/gdb/bfd/cf-i386lynx.c create mode 100644 contrib/gdb/bfd/cf-m68klynx.c create mode 100644 contrib/gdb/bfd/cf-sparclynx.c create mode 100644 contrib/gdb/bfd/cisco-core.c create mode 100644 contrib/gdb/bfd/coff-a29k.c create mode 100644 contrib/gdb/bfd/coff-alpha.c create mode 100644 contrib/gdb/bfd/coff-apollo.c create mode 100644 contrib/gdb/bfd/coff-arm.c create mode 100644 contrib/gdb/bfd/coff-aux.c create mode 100644 contrib/gdb/bfd/coff-go32.c create mode 100644 contrib/gdb/bfd/coff-h8300.c create mode 100644 contrib/gdb/bfd/coff-h8500.c create mode 100644 contrib/gdb/bfd/coff-i386.c create mode 100644 contrib/gdb/bfd/coff-i860.c create mode 100644 contrib/gdb/bfd/coff-i960.c create mode 100644 contrib/gdb/bfd/coff-m68k.c create mode 100644 contrib/gdb/bfd/coff-m88k.c create mode 100644 contrib/gdb/bfd/coff-mips.c create mode 100644 contrib/gdb/bfd/coff-pmac.c create mode 100644 contrib/gdb/bfd/coff-ppc.c create mode 100644 contrib/gdb/bfd/coff-rs6000.c create mode 100644 contrib/gdb/bfd/coff-sh.c create mode 100644 contrib/gdb/bfd/coff-sparc.c create mode 100644 contrib/gdb/bfd/coff-u68k.c create mode 100644 contrib/gdb/bfd/coff-w65.c create mode 100644 contrib/gdb/bfd/coff-we32k.c create mode 100644 contrib/gdb/bfd/coff-z8k.c create mode 100644 contrib/gdb/bfd/coffcode.h create mode 100644 contrib/gdb/bfd/coffgen.c create mode 100644 contrib/gdb/bfd/cofflink.c create mode 100644 contrib/gdb/bfd/coffswap.h create mode 100644 contrib/gdb/bfd/config.bfd create mode 100644 contrib/gdb/bfd/config.in create mode 100644 contrib/gdb/bfd/configure create mode 100644 contrib/gdb/bfd/configure.bat create mode 100644 contrib/gdb/bfd/configure.host create mode 100644 contrib/gdb/bfd/configure.in create mode 100644 contrib/gdb/bfd/corefile.c create mode 100644 contrib/gdb/bfd/cpu-a29k.c create mode 100644 contrib/gdb/bfd/cpu-alpha.c create mode 100644 contrib/gdb/bfd/cpu-arm.c create mode 100644 contrib/gdb/bfd/cpu-h8300.c create mode 100644 contrib/gdb/bfd/cpu-h8500.c create mode 100644 contrib/gdb/bfd/cpu-hppa.c create mode 100644 contrib/gdb/bfd/cpu-i386.c create mode 100644 contrib/gdb/bfd/cpu-i860.c create mode 100644 contrib/gdb/bfd/cpu-i960.c create mode 100644 contrib/gdb/bfd/cpu-m68k.c create mode 100644 contrib/gdb/bfd/cpu-m88k.c create mode 100644 contrib/gdb/bfd/cpu-mips.c create mode 100644 contrib/gdb/bfd/cpu-ns32k.c create mode 100644 contrib/gdb/bfd/cpu-powerpc.c create mode 100644 contrib/gdb/bfd/cpu-rs6000.c create mode 100644 contrib/gdb/bfd/cpu-sh.c create mode 100644 contrib/gdb/bfd/cpu-sparc.c create mode 100644 contrib/gdb/bfd/cpu-vax.c create mode 100644 contrib/gdb/bfd/cpu-w65.c create mode 100644 contrib/gdb/bfd/cpu-we32k.c create mode 100644 contrib/gdb/bfd/cpu-z8k.c create mode 100644 contrib/gdb/bfd/demo64.c create mode 100644 contrib/gdb/bfd/dep-in.sed create mode 100644 contrib/gdb/bfd/doc/ChangeLog create mode 100644 contrib/gdb/bfd/doc/Makefile.in create mode 100644 contrib/gdb/bfd/doc/bfd.texinfo create mode 100644 contrib/gdb/bfd/doc/bfdsumm.texi create mode 100644 contrib/gdb/bfd/doc/chew.c create mode 100644 contrib/gdb/bfd/doc/doc.str create mode 100644 contrib/gdb/bfd/doc/proto.str create mode 100644 contrib/gdb/bfd/ecoff.c create mode 100644 contrib/gdb/bfd/ecofflink.c create mode 100644 contrib/gdb/bfd/ecoffswap.h create mode 100644 contrib/gdb/bfd/elf-bfd.h create mode 100644 contrib/gdb/bfd/elf.c create mode 100644 contrib/gdb/bfd/elf32-gen.c create mode 100644 contrib/gdb/bfd/elf32-hppa.c create mode 100644 contrib/gdb/bfd/elf32-hppa.h create mode 100644 contrib/gdb/bfd/elf32-i386.c create mode 100644 contrib/gdb/bfd/elf32-i860.c create mode 100644 contrib/gdb/bfd/elf32-m68k.c create mode 100644 contrib/gdb/bfd/elf32-m88k.c create mode 100644 contrib/gdb/bfd/elf32-mips.c create mode 100644 contrib/gdb/bfd/elf32-ppc.c create mode 100644 contrib/gdb/bfd/elf32-sparc.c create mode 100644 contrib/gdb/bfd/elf32.c create mode 100644 contrib/gdb/bfd/elf64-gen.c create mode 100644 contrib/gdb/bfd/elf64-sparc.c create mode 100644 contrib/gdb/bfd/elf64.c create mode 100644 contrib/gdb/bfd/elfcode.h create mode 100644 contrib/gdb/bfd/elfcore.h create mode 100644 contrib/gdb/bfd/elflink.c create mode 100644 contrib/gdb/bfd/elflink.h create mode 100644 contrib/gdb/bfd/elfxx-target.h create mode 100644 contrib/gdb/bfd/filemode.c create mode 100644 contrib/gdb/bfd/format.c create mode 100644 contrib/gdb/bfd/freebsd.h create mode 100644 contrib/gdb/bfd/gen-aout.c create mode 100644 contrib/gdb/bfd/genlink.h create mode 100644 contrib/gdb/bfd/hash.c create mode 100644 contrib/gdb/bfd/host-aout.c create mode 100644 contrib/gdb/bfd/hosts/alphalinux.h create mode 100644 contrib/gdb/bfd/hosts/decstation.h create mode 100644 contrib/gdb/bfd/hosts/delta68.h create mode 100644 contrib/gdb/bfd/hosts/dpx2.h create mode 100644 contrib/gdb/bfd/hosts/hp300bsd.h create mode 100644 contrib/gdb/bfd/hosts/i386bsd.h create mode 100644 contrib/gdb/bfd/hosts/i386linux.h create mode 100644 contrib/gdb/bfd/hosts/i386mach3.h create mode 100644 contrib/gdb/bfd/hosts/i386sco.h create mode 100644 contrib/gdb/bfd/hosts/i860mach3.h create mode 100644 contrib/gdb/bfd/hosts/m68kaux.h create mode 100644 contrib/gdb/bfd/hosts/m68klinux.h create mode 100644 contrib/gdb/bfd/hosts/m88kmach3.h create mode 100644 contrib/gdb/bfd/hosts/mipsbsd.h create mode 100644 contrib/gdb/bfd/hosts/mipsmach3.h create mode 100644 contrib/gdb/bfd/hosts/news-mips.h create mode 100644 contrib/gdb/bfd/hosts/news.h create mode 100644 contrib/gdb/bfd/hosts/pc532mach.h create mode 100644 contrib/gdb/bfd/hosts/riscos.h create mode 100644 contrib/gdb/bfd/hosts/symmetry.h create mode 100644 contrib/gdb/bfd/hosts/tahoe.h create mode 100644 contrib/gdb/bfd/hosts/vaxbsd.h create mode 100644 contrib/gdb/bfd/hosts/vaxult.h create mode 100644 contrib/gdb/bfd/hosts/vaxult2.h create mode 100644 contrib/gdb/bfd/hp300bsd.c create mode 100644 contrib/gdb/bfd/hp300hpux.c create mode 100644 contrib/gdb/bfd/hppa_stubs.h create mode 100644 contrib/gdb/bfd/hppabsd-core.c create mode 100644 contrib/gdb/bfd/hpux-core.c create mode 100644 contrib/gdb/bfd/i386aout.c create mode 100644 contrib/gdb/bfd/i386bsd.c create mode 100644 contrib/gdb/bfd/i386dynix.c create mode 100644 contrib/gdb/bfd/i386freebsd.c create mode 100644 contrib/gdb/bfd/i386linux.c create mode 100644 contrib/gdb/bfd/i386lynx.c create mode 100644 contrib/gdb/bfd/i386mach3.c create mode 100644 contrib/gdb/bfd/i386msdos.c create mode 100644 contrib/gdb/bfd/i386netbsd.c create mode 100644 contrib/gdb/bfd/i386os9k.c create mode 100644 contrib/gdb/bfd/ieee.c create mode 100644 contrib/gdb/bfd/ihex.c create mode 100644 contrib/gdb/bfd/init.c create mode 100644 contrib/gdb/bfd/irix-core.c create mode 100644 contrib/gdb/bfd/libaout.h create mode 100644 contrib/gdb/bfd/libbfd-in.h create mode 100644 contrib/gdb/bfd/libbfd.c create mode 100644 contrib/gdb/bfd/libbfd.h create mode 100644 contrib/gdb/bfd/libcoff-in.h create mode 100644 contrib/gdb/bfd/libcoff.h create mode 100644 contrib/gdb/bfd/libecoff.h create mode 100644 contrib/gdb/bfd/libhppa.h create mode 100644 contrib/gdb/bfd/libieee.h create mode 100644 contrib/gdb/bfd/libnlm.h create mode 100644 contrib/gdb/bfd/liboasys.h create mode 100644 contrib/gdb/bfd/linker.c create mode 100644 contrib/gdb/bfd/lynx-core.c create mode 100644 contrib/gdb/bfd/m68k4knetbsd.c create mode 100644 contrib/gdb/bfd/m68klinux.c create mode 100644 contrib/gdb/bfd/m68klynx.c create mode 100644 contrib/gdb/bfd/m68knetbsd.c create mode 100644 contrib/gdb/bfd/m88kmach3.c create mode 100644 contrib/gdb/bfd/makefile.dos create mode 100644 contrib/gdb/bfd/mipsbsd.c create mode 100644 contrib/gdb/bfd/mpw-config.in create mode 100644 contrib/gdb/bfd/mpw-make.sed create mode 100644 contrib/gdb/bfd/netbsd-core.c create mode 100644 contrib/gdb/bfd/netbsd.h create mode 100644 contrib/gdb/bfd/newsos3.c create mode 100644 contrib/gdb/bfd/nlm-target.h create mode 100644 contrib/gdb/bfd/nlm.c create mode 100644 contrib/gdb/bfd/nlm32-alpha.c create mode 100644 contrib/gdb/bfd/nlm32-i386.c create mode 100644 contrib/gdb/bfd/nlm32-ppc.c create mode 100644 contrib/gdb/bfd/nlm32-sparc.c create mode 100644 contrib/gdb/bfd/nlm32.c create mode 100644 contrib/gdb/bfd/nlm64.c create mode 100644 contrib/gdb/bfd/nlmcode.h create mode 100644 contrib/gdb/bfd/nlmswap.h create mode 100644 contrib/gdb/bfd/ns32knetbsd.c create mode 100644 contrib/gdb/bfd/oasys.c create mode 100644 contrib/gdb/bfd/opncls.c create mode 100644 contrib/gdb/bfd/osf-core.c create mode 100644 contrib/gdb/bfd/pc532-mach.c create mode 100644 contrib/gdb/bfd/pe-arm.c create mode 100644 contrib/gdb/bfd/pe-i386.c create mode 100644 contrib/gdb/bfd/pe-ppc.c create mode 100644 contrib/gdb/bfd/pei-arm.c create mode 100644 contrib/gdb/bfd/pei-i386.c create mode 100644 contrib/gdb/bfd/pei-ppc.c create mode 100644 contrib/gdb/bfd/peicode.h create mode 100644 contrib/gdb/bfd/ptrace-core.c create mode 100644 contrib/gdb/bfd/reloc.c create mode 100644 contrib/gdb/bfd/reloc16.c create mode 100644 contrib/gdb/bfd/riscix.c create mode 100644 contrib/gdb/bfd/rs6000-core.c create mode 100644 contrib/gdb/bfd/section.c create mode 100644 contrib/gdb/bfd/som.c create mode 100644 contrib/gdb/bfd/som.h create mode 100644 contrib/gdb/bfd/sparclynx.c create mode 100644 contrib/gdb/bfd/sparcnetbsd.c create mode 100644 contrib/gdb/bfd/srec.c create mode 100644 contrib/gdb/bfd/stab-syms.c create mode 100644 contrib/gdb/bfd/sunos.c create mode 100644 contrib/gdb/bfd/syms.c create mode 100644 contrib/gdb/bfd/sysdep.h create mode 100644 contrib/gdb/bfd/targets.c create mode 100644 contrib/gdb/bfd/tekhex.c create mode 100644 contrib/gdb/bfd/trad-core.c create mode 100644 contrib/gdb/bfd/versados.c create mode 100644 contrib/gdb/bfd/xcofflink.c create mode 100644 contrib/gdb/gdb/.gdbinit create mode 100644 contrib/gdb/gdb/COPYING create mode 100644 contrib/gdb/gdb/ChangeLog create mode 100644 contrib/gdb/gdb/ChangeLog-93 create mode 100644 contrib/gdb/gdb/ChangeLog-94 create mode 100644 contrib/gdb/gdb/ChangeLog-95 create mode 100644 contrib/gdb/gdb/Makefile.in create mode 100644 contrib/gdb/gdb/NEWS create mode 100644 contrib/gdb/gdb/README create mode 100644 contrib/gdb/gdb/TODO create mode 100644 contrib/gdb/gdb/acconfig.h create mode 100644 contrib/gdb/gdb/aclocal.m4 create mode 100644 contrib/gdb/gdb/alpha-nat.c create mode 100644 contrib/gdb/gdb/alpha-tdep.c create mode 100644 contrib/gdb/gdb/annotate.c create mode 100644 contrib/gdb/gdb/annotate.h create mode 100644 contrib/gdb/gdb/arm-convert.s create mode 100644 contrib/gdb/gdb/arm-tdep.c create mode 100644 contrib/gdb/gdb/arm-xdep.c create mode 100644 contrib/gdb/gdb/bcache.c create mode 100644 contrib/gdb/gdb/bcache.h create mode 100644 contrib/gdb/gdb/blockframe.c create mode 100644 contrib/gdb/gdb/breakpoint.c create mode 100644 contrib/gdb/gdb/breakpoint.h create mode 100644 contrib/gdb/gdb/buildsym.c create mode 100644 contrib/gdb/gdb/buildsym.h create mode 100644 contrib/gdb/gdb/c-exp.tab.c create mode 100644 contrib/gdb/gdb/c-exp.y create mode 100644 contrib/gdb/gdb/c-lang.c create mode 100644 contrib/gdb/gdb/c-lang.h create mode 100644 contrib/gdb/gdb/c-typeprint.c create mode 100644 contrib/gdb/gdb/c-valprint.c create mode 100644 contrib/gdb/gdb/call-cmds.h create mode 100644 contrib/gdb/gdb/callback.c create mode 100644 contrib/gdb/gdb/callback.h create mode 100644 contrib/gdb/gdb/ch-exp.c create mode 100644 contrib/gdb/gdb/ch-lang.c create mode 100644 contrib/gdb/gdb/ch-lang.h create mode 100644 contrib/gdb/gdb/ch-typeprint.c create mode 100644 contrib/gdb/gdb/ch-valprint.c create mode 100644 contrib/gdb/gdb/coff-solib.c create mode 100644 contrib/gdb/gdb/coff-solib.h create mode 100644 contrib/gdb/gdb/coffread.c create mode 100644 contrib/gdb/gdb/command.c create mode 100644 contrib/gdb/gdb/command.h create mode 100644 contrib/gdb/gdb/complaints.c create mode 100644 contrib/gdb/gdb/complaints.h create mode 100644 contrib/gdb/gdb/config.in create mode 100644 contrib/gdb/gdb/config/i386/cygwin32.mh create mode 100644 contrib/gdb/gdb/config/i386/cygwin32.mt create mode 100644 contrib/gdb/gdb/config/i386/fbsd.mh create mode 100644 contrib/gdb/gdb/config/i386/fbsd.mt create mode 100644 contrib/gdb/gdb/config/i386/gdbserve.mt create mode 100644 contrib/gdb/gdb/config/i386/go32.mh create mode 100644 contrib/gdb/gdb/config/i386/i386aix.mh create mode 100644 contrib/gdb/gdb/config/i386/i386aix.mt create mode 100644 contrib/gdb/gdb/config/i386/i386aout.mt create mode 100644 contrib/gdb/gdb/config/i386/i386bsd.mh create mode 100644 contrib/gdb/gdb/config/i386/i386bsd.mt create mode 100644 contrib/gdb/gdb/config/i386/i386dgux.mh create mode 100644 contrib/gdb/gdb/config/i386/i386gnu.mh create mode 100644 contrib/gdb/gdb/config/i386/i386gnu.mt create mode 100644 contrib/gdb/gdb/config/i386/i386lynx.mh create mode 100644 contrib/gdb/gdb/config/i386/i386lynx.mt create mode 100644 contrib/gdb/gdb/config/i386/i386m3.mh create mode 100644 contrib/gdb/gdb/config/i386/i386m3.mt create mode 100644 contrib/gdb/gdb/config/i386/i386mach.mh create mode 100644 contrib/gdb/gdb/config/i386/i386mk.mh create mode 100644 contrib/gdb/gdb/config/i386/i386mk.mt create mode 100644 contrib/gdb/gdb/config/i386/i386nw.mt create mode 100644 contrib/gdb/gdb/config/i386/i386os9k.mt create mode 100644 contrib/gdb/gdb/config/i386/i386sco.mh create mode 100644 contrib/gdb/gdb/config/i386/i386sco4.mh create mode 100644 contrib/gdb/gdb/config/i386/i386sco5.mh create mode 100644 contrib/gdb/gdb/config/i386/i386sol2.mh create mode 100644 contrib/gdb/gdb/config/i386/i386sol2.mt create mode 100644 contrib/gdb/gdb/config/i386/i386v.mh create mode 100644 contrib/gdb/gdb/config/i386/i386v.mt create mode 100644 contrib/gdb/gdb/config/i386/i386v32.mh create mode 100644 contrib/gdb/gdb/config/i386/i386v4.mh create mode 100644 contrib/gdb/gdb/config/i386/i386v4.mt create mode 100644 contrib/gdb/gdb/config/i386/linux.mh create mode 100644 contrib/gdb/gdb/config/i386/linux.mt create mode 100644 contrib/gdb/gdb/config/i386/nbsd.mh create mode 100644 contrib/gdb/gdb/config/i386/nbsd.mt create mode 100644 contrib/gdb/gdb/config/i386/ncr3000.mh create mode 100644 contrib/gdb/gdb/config/i386/ncr3000.mt create mode 100644 contrib/gdb/gdb/config/i386/nm-fbsd.h create mode 100644 contrib/gdb/gdb/config/i386/nm-gnu.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386aix.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386bsd.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386lynx.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386mach.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386sco.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386sco4.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386sco5.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386v.h create mode 100644 contrib/gdb/gdb/config/i386/nm-i386v4.h create mode 100644 contrib/gdb/gdb/config/i386/nm-linux.h create mode 100644 contrib/gdb/gdb/config/i386/nm-m3.h create mode 100644 contrib/gdb/gdb/config/i386/nm-nbsd.h create mode 100644 contrib/gdb/gdb/config/i386/nm-ptx4.h create mode 100644 contrib/gdb/gdb/config/i386/nm-sun386.h create mode 100644 contrib/gdb/gdb/config/i386/nm-symmetry.h create mode 100644 contrib/gdb/gdb/config/i386/ptx.mh create mode 100644 contrib/gdb/gdb/config/i386/ptx.mt create mode 100644 contrib/gdb/gdb/config/i386/ptx4.mh create mode 100644 contrib/gdb/gdb/config/i386/ptx4.mt create mode 100644 contrib/gdb/gdb/config/i386/sun386.mh create mode 100644 contrib/gdb/gdb/config/i386/sun386.mt create mode 100644 contrib/gdb/gdb/config/i386/symmetry.mh create mode 100644 contrib/gdb/gdb/config/i386/symmetry.mt create mode 100644 contrib/gdb/gdb/config/i386/tm-cygwin32.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386aix.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386bsd.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386gnu.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386lynx.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386m3.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386mk.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386nw.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386os9k.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386v.h create mode 100644 contrib/gdb/gdb/config/i386/tm-i386v4.h create mode 100644 contrib/gdb/gdb/config/i386/tm-linux.h create mode 100644 contrib/gdb/gdb/config/i386/tm-nbsd.h create mode 100644 contrib/gdb/gdb/config/i386/tm-ptx.h create mode 100644 contrib/gdb/gdb/config/i386/tm-ptx4.h create mode 100644 contrib/gdb/gdb/config/i386/tm-sun386.h create mode 100644 contrib/gdb/gdb/config/i386/tm-symmetry.h create mode 100644 contrib/gdb/gdb/config/i386/xm-cygwin32.h create mode 100644 contrib/gdb/gdb/config/i386/xm-go32.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386aix.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386bsd.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386gnu.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386lynx.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386m3.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386mach.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386mk.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386sco.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386v.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386v32.h create mode 100644 contrib/gdb/gdb/config/i386/xm-i386v4.h create mode 100644 contrib/gdb/gdb/config/i386/xm-linux.h create mode 100644 contrib/gdb/gdb/config/i386/xm-nbsd.h create mode 100644 contrib/gdb/gdb/config/i386/xm-ptx.h create mode 100644 contrib/gdb/gdb/config/i386/xm-ptx4.h create mode 100644 contrib/gdb/gdb/config/i386/xm-sun386.h create mode 100644 contrib/gdb/gdb/config/i386/xm-symmetry.h create mode 100644 contrib/gdb/gdb/config/nm-empty.h create mode 100644 contrib/gdb/gdb/config/nm-gnu.h create mode 100644 contrib/gdb/gdb/config/nm-lynx.h create mode 100644 contrib/gdb/gdb/config/nm-m3.h create mode 100644 contrib/gdb/gdb/config/nm-nbsd.h create mode 100644 contrib/gdb/gdb/config/nm-sysv4.h create mode 100644 contrib/gdb/gdb/config/tm-lynx.h create mode 100644 contrib/gdb/gdb/config/tm-nbsd.h create mode 100644 contrib/gdb/gdb/config/tm-sunos.h create mode 100644 contrib/gdb/gdb/config/tm-sysv4.h create mode 100644 contrib/gdb/gdb/config/xm-aix4.h create mode 100644 contrib/gdb/gdb/config/xm-lynx.h create mode 100644 contrib/gdb/gdb/config/xm-mpw.h create mode 100644 contrib/gdb/gdb/config/xm-nbsd.h create mode 100644 contrib/gdb/gdb/config/xm-sysv4.h create mode 100644 contrib/gdb/gdb/configure create mode 100644 contrib/gdb/gdb/configure.in create mode 100644 contrib/gdb/gdb/copying.awk create mode 100644 contrib/gdb/gdb/copying.c create mode 100644 contrib/gdb/gdb/core-aout.c create mode 100644 contrib/gdb/gdb/core-regset.c create mode 100644 contrib/gdb/gdb/core-sol2.c create mode 100644 contrib/gdb/gdb/corefile.c create mode 100644 contrib/gdb/gdb/corelow.c create mode 100644 contrib/gdb/gdb/cp-valprint.c create mode 100644 contrib/gdb/gdb/cpu32bug-rom.c create mode 100644 contrib/gdb/gdb/cxux-nat.c create mode 100644 contrib/gdb/gdb/dbxread.c create mode 100644 contrib/gdb/gdb/dcache.c create mode 100644 contrib/gdb/gdb/dcache.h create mode 100644 contrib/gdb/gdb/defs.h create mode 100644 contrib/gdb/gdb/demangle.c create mode 100644 contrib/gdb/gdb/doc/ChangeLog create mode 100644 contrib/gdb/gdb/doc/GDBvn.texi create mode 100644 contrib/gdb/gdb/doc/Makefile.in create mode 100644 contrib/gdb/gdb/doc/a4rc.sed create mode 100644 contrib/gdb/gdb/doc/all-cfg.texi create mode 100644 contrib/gdb/gdb/doc/annotate.texi create mode 100644 contrib/gdb/gdb/doc/configure.in create mode 100644 contrib/gdb/gdb/doc/gdb.texinfo create mode 100644 contrib/gdb/gdb/doc/gdbint.texinfo create mode 100644 contrib/gdb/gdb/doc/h8-cfg.texi create mode 100644 contrib/gdb/gdb/doc/libgdb.texinfo create mode 100644 contrib/gdb/gdb/doc/lpsrc.sed create mode 100644 contrib/gdb/gdb/doc/psrc.sed create mode 100644 contrib/gdb/gdb/doc/refcard.dvi create mode 100644 contrib/gdb/gdb/doc/refcard.tex create mode 100644 contrib/gdb/gdb/doc/remote.texi create mode 100644 contrib/gdb/gdb/doc/stabs.texinfo create mode 100644 contrib/gdb/gdb/dwarfread.c create mode 100644 contrib/gdb/gdb/elfread.c create mode 100644 contrib/gdb/gdb/environ.c create mode 100644 contrib/gdb/gdb/environ.h create mode 100644 contrib/gdb/gdb/eval.c create mode 100644 contrib/gdb/gdb/exc_request.defs create mode 100644 contrib/gdb/gdb/exec.c create mode 100644 contrib/gdb/gdb/expprint.c create mode 100644 contrib/gdb/gdb/expression.h create mode 100644 contrib/gdb/gdb/f-exp.tab.c create mode 100644 contrib/gdb/gdb/f-exp.y create mode 100644 contrib/gdb/gdb/f-lang.c create mode 100644 contrib/gdb/gdb/f-lang.h create mode 100644 contrib/gdb/gdb/f-typeprint.c create mode 100644 contrib/gdb/gdb/f-valprint.c create mode 100644 contrib/gdb/gdb/findvar.c create mode 100644 contrib/gdb/gdb/fork-child.c create mode 100644 contrib/gdb/gdb/frame.h create mode 100644 contrib/gdb/gdb/gdb-stabs.h create mode 100644 contrib/gdb/gdb/gdb.1 create mode 100644 contrib/gdb/gdb/gdb.gdb create mode 100644 contrib/gdb/gdb/gdb_stat.h create mode 100644 contrib/gdb/gdb/gdb_string.h create mode 100644 contrib/gdb/gdb/gdba.el create mode 100644 contrib/gdb/gdb/gdbcmd.h create mode 100644 contrib/gdb/gdb/gdbcore.h create mode 100644 contrib/gdb/gdb/gdbserver/Makefile.in create mode 100644 contrib/gdb/gdb/gdbserver/README create mode 100644 contrib/gdb/gdb/gdbserver/configure.in create mode 100644 contrib/gdb/gdb/gdbserver/gdbreplay.c create mode 100644 contrib/gdb/gdb/gdbserver/gdbserver.1 create mode 100644 contrib/gdb/gdb/gdbserver/low-hppabsd.c create mode 100644 contrib/gdb/gdb/gdbserver/low-linux.c create mode 100644 contrib/gdb/gdb/gdbserver/low-lynx.c create mode 100644 contrib/gdb/gdb/gdbserver/low-sparc.c create mode 100644 contrib/gdb/gdb/gdbserver/low-sun3.c create mode 100644 contrib/gdb/gdb/gdbserver/remote-utils.c create mode 100644 contrib/gdb/gdb/gdbserver/server.c create mode 100644 contrib/gdb/gdb/gdbserver/server.h create mode 100644 contrib/gdb/gdb/gdbserver/utils.c create mode 100644 contrib/gdb/gdb/gdbtypes.c create mode 100644 contrib/gdb/gdb/gdbtypes.h create mode 100644 contrib/gdb/gdb/gnu-nat.c create mode 100644 contrib/gdb/gdb/gnu-nat.h create mode 100644 contrib/gdb/gdb/gnu-regex.c create mode 100644 contrib/gdb/gdb/gnu-regex.h create mode 100644 contrib/gdb/gdb/go32-xdep.c create mode 100644 contrib/gdb/gdb/i386-stub.c create mode 100644 contrib/gdb/gdb/i386-tdep.c create mode 100644 contrib/gdb/gdb/i386aix-nat.c create mode 100644 contrib/gdb/gdb/i386b-nat.c create mode 100644 contrib/gdb/gdb/i386gnu-nat.c create mode 100644 contrib/gdb/gdb/i386ly-tdep.c create mode 100644 contrib/gdb/gdb/i386m3-nat.c create mode 100644 contrib/gdb/gdb/i386mach-nat.c create mode 100644 contrib/gdb/gdb/i386v-nat.c create mode 100644 contrib/gdb/gdb/i386v4-nat.c create mode 100644 contrib/gdb/gdb/i387-tdep.c create mode 100644 contrib/gdb/gdb/infcmd.c create mode 100644 contrib/gdb/gdb/inferior.h create mode 100644 contrib/gdb/gdb/inflow.c create mode 100644 contrib/gdb/gdb/infptrace.c create mode 100644 contrib/gdb/gdb/infrun.c create mode 100644 contrib/gdb/gdb/inftarg.c create mode 100644 contrib/gdb/gdb/irix4-nat.c create mode 100644 contrib/gdb/gdb/irix5-nat.c create mode 100644 contrib/gdb/gdb/isi-xdep.c create mode 100644 contrib/gdb/gdb/kdb-start.c create mode 100644 contrib/gdb/gdb/language.c create mode 100644 contrib/gdb/gdb/language.h create mode 100644 contrib/gdb/gdb/lynx-nat.c create mode 100644 contrib/gdb/gdb/m2-exp.tab.c create mode 100644 contrib/gdb/gdb/m2-exp.y create mode 100644 contrib/gdb/gdb/m2-lang.c create mode 100644 contrib/gdb/gdb/m2-lang.h create mode 100644 contrib/gdb/gdb/m2-typeprint.c create mode 100644 contrib/gdb/gdb/m2-valprint.c create mode 100644 contrib/gdb/gdb/m3-nat.c create mode 100644 contrib/gdb/gdb/m68k-stub.c create mode 100644 contrib/gdb/gdb/m68k-tdep.c create mode 100644 contrib/gdb/gdb/m68knbsd-nat.c create mode 100644 contrib/gdb/gdb/m88k-nat.c create mode 100644 contrib/gdb/gdb/m88k-tdep.c create mode 100644 contrib/gdb/gdb/main.c create mode 100644 contrib/gdb/gdb/maint.c create mode 100644 contrib/gdb/gdb/mdebugread.c create mode 100644 contrib/gdb/gdb/mem-break.c create mode 100644 contrib/gdb/gdb/minimon.h create mode 100644 contrib/gdb/gdb/minsyms.c create mode 100644 contrib/gdb/gdb/mipsread.c create mode 100644 contrib/gdb/gdb/mon960-rom.c create mode 100644 contrib/gdb/gdb/monitor.c create mode 100644 contrib/gdb/gdb/monitor.h create mode 100644 contrib/gdb/gdb/mpw-config.in create mode 100644 contrib/gdb/gdb/mpw-make.sed create mode 100644 contrib/gdb/gdb/msg.defs create mode 100644 contrib/gdb/gdb/msg_reply.defs create mode 100644 contrib/gdb/gdb/news-xdep.c create mode 100644 contrib/gdb/gdb/nindy-tdep.c create mode 100644 contrib/gdb/gdb/nlm/Makefile.in create mode 100644 contrib/gdb/gdb/nlm/configure create mode 100644 contrib/gdb/gdb/nlm/configure.in create mode 100644 contrib/gdb/gdb/nlm/gdbserve.c create mode 100644 contrib/gdb/gdb/nlm/gdbserve.def create mode 100644 contrib/gdb/gdb/nlm/i386.c create mode 100644 contrib/gdb/gdb/nlm/i386.h create mode 100644 contrib/gdb/gdb/nlm/ppc.c create mode 100644 contrib/gdb/gdb/nlm/ppc.h create mode 100644 contrib/gdb/gdb/nlm/prelude.c create mode 100644 contrib/gdb/gdb/nlmread.c create mode 100644 contrib/gdb/gdb/notify.defs create mode 100644 contrib/gdb/gdb/ns32k-tdep.c create mode 100644 contrib/gdb/gdb/ns32km3-nat.c create mode 100644 contrib/gdb/gdb/objfiles.c create mode 100644 contrib/gdb/gdb/objfiles.h create mode 100644 contrib/gdb/gdb/op50-rom.c create mode 100644 contrib/gdb/gdb/os9kread.c create mode 100644 contrib/gdb/gdb/osfsolib.c create mode 100644 contrib/gdb/gdb/parse.c create mode 100644 contrib/gdb/gdb/parser-defs.h create mode 100644 contrib/gdb/gdb/partial-stab.h create mode 100644 contrib/gdb/gdb/ppcbug-rom.c create mode 100644 contrib/gdb/gdb/printcmd.c create mode 100644 contrib/gdb/gdb/process_reply.defs create mode 100644 contrib/gdb/gdb/procfs.c create mode 100644 contrib/gdb/gdb/ptx4-nat.c create mode 100644 contrib/gdb/gdb/pyr-tdep.c create mode 100644 contrib/gdb/gdb/pyr-xdep.c create mode 100644 contrib/gdb/gdb/remote-adapt.c create mode 100644 contrib/gdb/gdb/remote-array.c create mode 100644 contrib/gdb/gdb/remote-bug.c create mode 100644 contrib/gdb/gdb/remote-e7000.c create mode 100644 contrib/gdb/gdb/remote-eb.c create mode 100644 contrib/gdb/gdb/remote-es.c create mode 100644 contrib/gdb/gdb/remote-est.c create mode 100644 contrib/gdb/gdb/remote-hms.c create mode 100644 contrib/gdb/gdb/remote-mips.c create mode 100644 contrib/gdb/gdb/remote-mm.c create mode 100644 contrib/gdb/gdb/remote-nindy.c create mode 100644 contrib/gdb/gdb/remote-nrom.c create mode 100644 contrib/gdb/gdb/remote-os9k.c create mode 100644 contrib/gdb/gdb/remote-pa.c create mode 100644 contrib/gdb/gdb/remote-rdp.c create mode 100644 contrib/gdb/gdb/remote-sim.c create mode 100644 contrib/gdb/gdb/remote-sim.h create mode 100644 contrib/gdb/gdb/remote-st.c create mode 100644 contrib/gdb/gdb/remote-udi.c create mode 100644 contrib/gdb/gdb/remote-utils.c create mode 100644 contrib/gdb/gdb/remote-utils.h create mode 100644 contrib/gdb/gdb/remote-vx.c create mode 100644 contrib/gdb/gdb/remote-vx29k.c create mode 100644 contrib/gdb/gdb/remote-vx68.c create mode 100644 contrib/gdb/gdb/remote-vx960.c create mode 100644 contrib/gdb/gdb/remote-vxmips.c create mode 100644 contrib/gdb/gdb/remote-vxsparc.c create mode 100644 contrib/gdb/gdb/remote.c create mode 100644 contrib/gdb/gdb/reply_mig_hack.awk create mode 100644 contrib/gdb/gdb/saber.suppress create mode 100644 contrib/gdb/gdb/scm-exp.c create mode 100644 contrib/gdb/gdb/scm-lang.c create mode 100644 contrib/gdb/gdb/scm-lang.h create mode 100644 contrib/gdb/gdb/scm-tags.h create mode 100644 contrib/gdb/gdb/scm-valprint.c create mode 100644 contrib/gdb/gdb/ser-e7kpc.c create mode 100644 contrib/gdb/gdb/ser-go32.c create mode 100644 contrib/gdb/gdb/ser-mac.c create mode 100644 contrib/gdb/gdb/ser-tcp.c create mode 100644 contrib/gdb/gdb/ser-unix.c create mode 100644 contrib/gdb/gdb/serial.c create mode 100644 contrib/gdb/gdb/serial.h create mode 100644 contrib/gdb/gdb/signals.h create mode 100644 contrib/gdb/gdb/solib.c create mode 100644 contrib/gdb/gdb/solib.h create mode 100644 contrib/gdb/gdb/somread.c create mode 100644 contrib/gdb/gdb/somsolib.c create mode 100644 contrib/gdb/gdb/somsolib.h create mode 100644 contrib/gdb/gdb/source.c create mode 100644 contrib/gdb/gdb/srec.h create mode 100644 contrib/gdb/gdb/stabsread.c create mode 100644 contrib/gdb/gdb/stabsread.h create mode 100644 contrib/gdb/gdb/stack.c create mode 100644 contrib/gdb/gdb/standalone.c create mode 100644 contrib/gdb/gdb/stop-gdb.c create mode 100644 contrib/gdb/gdb/stuff.c create mode 100644 contrib/gdb/gdb/symfile.c create mode 100644 contrib/gdb/gdb/symfile.h create mode 100644 contrib/gdb/gdb/symm-nat.c create mode 100644 contrib/gdb/gdb/symm-tdep.c create mode 100644 contrib/gdb/gdb/symmisc.c create mode 100644 contrib/gdb/gdb/symtab.c create mode 100644 contrib/gdb/gdb/symtab.h create mode 100644 contrib/gdb/gdb/target.c create mode 100644 contrib/gdb/gdb/target.h create mode 100644 contrib/gdb/gdb/terminal.h create mode 100644 contrib/gdb/gdb/thread.c create mode 100644 contrib/gdb/gdb/thread.h create mode 100644 contrib/gdb/gdb/top.c create mode 100644 contrib/gdb/gdb/top.h create mode 100644 contrib/gdb/gdb/typeprint.c create mode 100644 contrib/gdb/gdb/typeprint.h create mode 100644 contrib/gdb/gdb/umax-xdep.c create mode 100644 contrib/gdb/gdb/utils.c create mode 100644 contrib/gdb/gdb/valarith.c create mode 100644 contrib/gdb/gdb/valops.c create mode 100644 contrib/gdb/gdb/valprint.c create mode 100644 contrib/gdb/gdb/valprint.h create mode 100644 contrib/gdb/gdb/value.h create mode 100644 contrib/gdb/gdb/values.c create mode 100644 contrib/gdb/gdb/xcoffread.c create mode 100644 contrib/gdb/gdb/xcoffsolib.c create mode 100644 contrib/gdb/gdb/xcoffsolib.h create mode 100644 contrib/gdb/gdb/xmodem.c create mode 100644 contrib/gdb/gdb/xmodem.h create mode 100644 contrib/gdb/include/COPYING create mode 100644 contrib/gdb/include/ChangeLog create mode 100644 contrib/gdb/include/ansidecl.h create mode 100644 contrib/gdb/include/aout/ChangeLog create mode 100644 contrib/gdb/include/aout/adobe.h create mode 100644 contrib/gdb/include/aout/aout64.h create mode 100644 contrib/gdb/include/aout/ar.h create mode 100644 contrib/gdb/include/aout/dynix3.h create mode 100644 contrib/gdb/include/aout/encap.h create mode 100644 contrib/gdb/include/aout/host.h create mode 100644 contrib/gdb/include/aout/hp.h create mode 100644 contrib/gdb/include/aout/hp300hpux.h create mode 100644 contrib/gdb/include/aout/hppa.h create mode 100644 contrib/gdb/include/aout/ranlib.h create mode 100644 contrib/gdb/include/aout/reloc.h create mode 100644 contrib/gdb/include/aout/stab.def create mode 100644 contrib/gdb/include/aout/stab_gnu.h create mode 100644 contrib/gdb/include/aout/sun4.h create mode 100644 contrib/gdb/include/bfdlink.h create mode 100644 contrib/gdb/include/bout.h create mode 100644 contrib/gdb/include/coff/ChangeLog create mode 100644 contrib/gdb/include/coff/a29k.h create mode 100644 contrib/gdb/include/coff/alpha.h create mode 100644 contrib/gdb/include/coff/apollo.h create mode 100644 contrib/gdb/include/coff/arm.h create mode 100644 contrib/gdb/include/coff/aux-coff.h create mode 100644 contrib/gdb/include/coff/ecoff.h create mode 100644 contrib/gdb/include/coff/h8300.h create mode 100644 contrib/gdb/include/coff/h8500.h create mode 100644 contrib/gdb/include/coff/i386.h create mode 100644 contrib/gdb/include/coff/i860.h create mode 100644 contrib/gdb/include/coff/i960.h create mode 100644 contrib/gdb/include/coff/internal.h create mode 100644 contrib/gdb/include/coff/m68k.h create mode 100644 contrib/gdb/include/coff/m88k.h create mode 100644 contrib/gdb/include/coff/mips.h create mode 100644 contrib/gdb/include/coff/pe.h create mode 100644 contrib/gdb/include/coff/powerpc.h create mode 100644 contrib/gdb/include/coff/rs6000.h create mode 100644 contrib/gdb/include/coff/sh.h create mode 100644 contrib/gdb/include/coff/sparc.h create mode 100644 contrib/gdb/include/coff/sym.h create mode 100644 contrib/gdb/include/coff/symconst.h create mode 100644 contrib/gdb/include/coff/w65.h create mode 100644 contrib/gdb/include/coff/we32k.h create mode 100644 contrib/gdb/include/coff/z8k.h create mode 100644 contrib/gdb/include/demangle.h create mode 100644 contrib/gdb/include/dis-asm.h create mode 100644 contrib/gdb/include/elf/ChangeLog create mode 100644 contrib/gdb/include/elf/common.h create mode 100644 contrib/gdb/include/elf/dwarf.h create mode 100644 contrib/gdb/include/elf/external.h create mode 100644 contrib/gdb/include/elf/hppa.h create mode 100644 contrib/gdb/include/elf/internal.h create mode 100644 contrib/gdb/include/elf/mips.h create mode 100644 contrib/gdb/include/elf/ppc.h create mode 100644 contrib/gdb/include/elf/sparc.h create mode 100644 contrib/gdb/include/floatformat.h create mode 100644 contrib/gdb/include/fopen-bin.h create mode 100644 contrib/gdb/include/fopen-same.h create mode 100644 contrib/gdb/include/gdbm.h create mode 100644 contrib/gdb/include/getopt.h create mode 100644 contrib/gdb/include/hp-symtab.h create mode 100644 contrib/gdb/include/ieee.h create mode 100644 contrib/gdb/include/libiberty.h create mode 100644 contrib/gdb/include/mpw/ChangeLog create mode 100644 contrib/gdb/include/mpw/README create mode 100644 contrib/gdb/include/mpw/dir.h create mode 100644 contrib/gdb/include/mpw/dirent.h create mode 100644 contrib/gdb/include/mpw/fcntl.h create mode 100644 contrib/gdb/include/mpw/grp.h create mode 100644 contrib/gdb/include/mpw/mpw.h create mode 100644 contrib/gdb/include/mpw/pwd.h create mode 100644 contrib/gdb/include/mpw/spin.h create mode 100644 contrib/gdb/include/mpw/stat.h create mode 100644 contrib/gdb/include/mpw/sys/file.h create mode 100644 contrib/gdb/include/mpw/sys/param.h create mode 100644 contrib/gdb/include/mpw/sys/resource.h create mode 100644 contrib/gdb/include/mpw/sys/stat.h create mode 100644 contrib/gdb/include/mpw/sys/time.h create mode 100644 contrib/gdb/include/mpw/sys/types.h create mode 100644 contrib/gdb/include/mpw/utime.h create mode 100644 contrib/gdb/include/mpw/varargs.h create mode 100644 contrib/gdb/include/nlm/ChangeLog create mode 100644 contrib/gdb/include/nlm/alpha-ext.h create mode 100644 contrib/gdb/include/nlm/common.h create mode 100644 contrib/gdb/include/nlm/external.h create mode 100644 contrib/gdb/include/nlm/i386-ext.h create mode 100644 contrib/gdb/include/nlm/internal.h create mode 100644 contrib/gdb/include/nlm/ppc-ext.h create mode 100644 contrib/gdb/include/nlm/sparc32-ext.h create mode 100644 contrib/gdb/include/oasys.h create mode 100644 contrib/gdb/include/obstack.h create mode 100644 contrib/gdb/include/opcode/ChangeLog create mode 100644 contrib/gdb/include/opcode/a29k.h create mode 100644 contrib/gdb/include/opcode/arm.h create mode 100644 contrib/gdb/include/opcode/convex.h create mode 100644 contrib/gdb/include/opcode/h8300.h create mode 100644 contrib/gdb/include/opcode/hppa.h create mode 100644 contrib/gdb/include/opcode/i386.h create mode 100644 contrib/gdb/include/opcode/i860.h create mode 100644 contrib/gdb/include/opcode/i960.h create mode 100644 contrib/gdb/include/opcode/m68k.h create mode 100644 contrib/gdb/include/opcode/m88k.h create mode 100644 contrib/gdb/include/opcode/mips.h create mode 100644 contrib/gdb/include/opcode/np1.h create mode 100644 contrib/gdb/include/opcode/ns32k.h create mode 100644 contrib/gdb/include/opcode/pn.h create mode 100644 contrib/gdb/include/opcode/ppc.h create mode 100644 contrib/gdb/include/opcode/pyr.h create mode 100644 contrib/gdb/include/opcode/rs6k.h create mode 100644 contrib/gdb/include/opcode/sparc.h create mode 100644 contrib/gdb/include/opcode/tahoe.h create mode 100644 contrib/gdb/include/opcode/vax.h create mode 100644 contrib/gdb/include/os9k.h create mode 100644 contrib/gdb/include/progress.h create mode 100644 contrib/gdb/include/wait.h create mode 100644 contrib/gdb/libiberty/COPYING.LIB create mode 100644 contrib/gdb/libiberty/ChangeLog create mode 100644 contrib/gdb/libiberty/Makefile.in create mode 100644 contrib/gdb/libiberty/README create mode 100644 contrib/gdb/libiberty/alloca-botch.h create mode 100644 contrib/gdb/libiberty/alloca-norm.h create mode 100644 contrib/gdb/libiberty/alloca.c create mode 100644 contrib/gdb/libiberty/argv.c create mode 100644 contrib/gdb/libiberty/atexit.c create mode 100644 contrib/gdb/libiberty/basename.c create mode 100644 contrib/gdb/libiberty/bcmp.c create mode 100644 contrib/gdb/libiberty/bcopy.c create mode 100644 contrib/gdb/libiberty/bzero.c create mode 100644 contrib/gdb/libiberty/clock.c create mode 100644 contrib/gdb/libiberty/concat.c create mode 100644 contrib/gdb/libiberty/config.table create mode 100644 contrib/gdb/libiberty/config/mh-a68bsd create mode 100644 contrib/gdb/libiberty/config/mh-aix create mode 100644 contrib/gdb/libiberty/config/mh-apollo68 create mode 100644 contrib/gdb/libiberty/config/mh-cxux7 create mode 100644 contrib/gdb/libiberty/config/mh-go32 create mode 100644 contrib/gdb/libiberty/config/mh-hpbsd create mode 100644 contrib/gdb/libiberty/config/mh-irix4 create mode 100644 contrib/gdb/libiberty/config/mh-lynxos create mode 100644 contrib/gdb/libiberty/config/mh-ncr3000 create mode 100644 contrib/gdb/libiberty/config/mh-riscix create mode 100644 contrib/gdb/libiberty/config/mh-sysv create mode 100644 contrib/gdb/libiberty/config/mh-sysv4 create mode 100644 contrib/gdb/libiberty/config/mt-sunos4 create mode 100644 contrib/gdb/libiberty/config/mt-vxworks5 create mode 100644 contrib/gdb/libiberty/configure.bat create mode 100644 contrib/gdb/libiberty/configure.in create mode 100644 contrib/gdb/libiberty/copysign.c create mode 100644 contrib/gdb/libiberty/cplus-dem.c create mode 100644 contrib/gdb/libiberty/dummy.c create mode 100644 contrib/gdb/libiberty/fdmatch.c create mode 100644 contrib/gdb/libiberty/floatformat.c create mode 100644 contrib/gdb/libiberty/functions.def create mode 100644 contrib/gdb/libiberty/getcwd.c create mode 100644 contrib/gdb/libiberty/getopt.c create mode 100644 contrib/gdb/libiberty/getopt1.c create mode 100644 contrib/gdb/libiberty/getpagesize.c create mode 100644 contrib/gdb/libiberty/getruntime.c create mode 100644 contrib/gdb/libiberty/hex.c create mode 100644 contrib/gdb/libiberty/index.c create mode 100644 contrib/gdb/libiberty/insque.c create mode 100644 contrib/gdb/libiberty/makefile.dos create mode 100644 contrib/gdb/libiberty/memchr.c create mode 100644 contrib/gdb/libiberty/memcmp.c create mode 100644 contrib/gdb/libiberty/memcpy.c create mode 100644 contrib/gdb/libiberty/memmove.c create mode 100644 contrib/gdb/libiberty/memset.c create mode 100644 contrib/gdb/libiberty/mpw-config.in create mode 100644 contrib/gdb/libiberty/mpw-make.sed create mode 100644 contrib/gdb/libiberty/mpw.c create mode 100644 contrib/gdb/libiberty/msdos.c create mode 100644 contrib/gdb/libiberty/obstack.c create mode 100644 contrib/gdb/libiberty/random.c create mode 100644 contrib/gdb/libiberty/rename.c create mode 100644 contrib/gdb/libiberty/rindex.c create mode 100644 contrib/gdb/libiberty/sigsetmask.c create mode 100644 contrib/gdb/libiberty/spaces.c create mode 100644 contrib/gdb/libiberty/strcasecmp.c create mode 100644 contrib/gdb/libiberty/strchr.c create mode 100644 contrib/gdb/libiberty/strdup.c create mode 100644 contrib/gdb/libiberty/strerror.c create mode 100644 contrib/gdb/libiberty/strncasecmp.c create mode 100644 contrib/gdb/libiberty/strrchr.c create mode 100644 contrib/gdb/libiberty/strsignal.c create mode 100644 contrib/gdb/libiberty/strstr.c create mode 100644 contrib/gdb/libiberty/strtod.c create mode 100644 contrib/gdb/libiberty/strtol.c create mode 100644 contrib/gdb/libiberty/strtoul.c create mode 100644 contrib/gdb/libiberty/tmpnam.c create mode 100644 contrib/gdb/libiberty/vasprintf.c create mode 100644 contrib/gdb/libiberty/vfork.c create mode 100644 contrib/gdb/libiberty/vfprintf.c create mode 100644 contrib/gdb/libiberty/vmsbuild.com create mode 100644 contrib/gdb/libiberty/vprintf.c create mode 100644 contrib/gdb/libiberty/vsprintf.c create mode 100644 contrib/gdb/libiberty/waitpid.c create mode 100644 contrib/gdb/libiberty/xatexit.c create mode 100644 contrib/gdb/libiberty/xexit.c create mode 100644 contrib/gdb/libiberty/xmalloc.c create mode 100644 contrib/gdb/libiberty/xstrdup.c create mode 100644 contrib/gdb/libiberty/xstrerror.c create mode 100644 contrib/gdb/opcodes/ChangeLog create mode 100644 contrib/gdb/opcodes/Makefile.in create mode 100644 contrib/gdb/opcodes/dis-buf.c create mode 100644 contrib/gdb/opcodes/disassemble.c create mode 100644 contrib/gdb/opcodes/i386-dis.c create mode 100644 contrib/gdb/opcodes/sysdep.h create mode 100644 contrib/gdb/readline/doc/ChangeLog create mode 100644 contrib/gdb/readline/doc/Makefile.in create mode 100644 contrib/gdb/readline/doc/configure.in create mode 100644 contrib/gdb/readline/doc/hist.texinfo create mode 100644 contrib/gdb/readline/doc/hstech.texinfo create mode 100644 contrib/gdb/readline/doc/hsuser.texinfo create mode 100644 contrib/gdb/readline/doc/inc-hist.texi create mode 100644 contrib/gdb/readline/doc/rlman.texinfo create mode 100644 contrib/gdb/readline/doc/rltech.texinfo create mode 100644 contrib/gdb/readline/doc/rluser.texinfo diff --git a/contrib/gdb/COPYING b/contrib/gdb/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/contrib/gdb/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/gdb/COPYING.LIB b/contrib/gdb/COPYING.LIB new file mode 100644 index 000000000000..eb685a5ec981 --- /dev/null +++ b/contrib/gdb/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/contrib/gdb/Makefile.in b/contrib/gdb/Makefile.in new file mode 100644 index 000000000000..60a80256bbe9 --- /dev/null +++ b/contrib/gdb/Makefile.in @@ -0,0 +1,1366 @@ +# +# Makefile for directory with subdirs to build. +# Copyright (C) 1990, 1991, 1992, 1993 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 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +srcdir = . + +prefix = /usr/local + +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(exec_prefix)/$(target) + +program_transform_name = + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc +GDB_NLM_DEPS = + +SHELL = /bin/sh + +INSTALL = $${srcroot}/install.sh -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) -m 644 +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' + +INSTALL_DOSREL = install-dosrel-fake + +AS = as +AR = ar +AR_FLAGS = rc +CC = cc + +# Special variables passed down in EXTRA_GCC_FLAGS. They are defined +# here so that they can be overridden by Makefile fragments. +HOST_CC = $(CC_FOR_BUILD) +HOST_PREFIX = +HOST_PREFIX_1 = loser- + +# We don't specify -g -O because many compilers don't support -g -O, +# and/or -O is broken in and of itself. +CFLAGS = -g +LIBCFLAGS = $(CFLAGS) +CFLAGS_FOR_TARGET = $(CFLAGS) +LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARGET) +PICFLAG = +PICFLAG_FOR_TARGET = + +CXX = gcc + +# Use -O2 to stress test the compiler. +CXXFLAGS = -g -O2 +LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates +CXXFLAGS_FOR_TARGET = $(CXXFLAGS) +LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates + +RANLIB = ranlib + +DLLTOOL = dlltool + +NM = nm +# Not plain GZIP, since gzip looks there for extra command-line options. +GZIPPROG = gzip + +# These values are substituted by configure. +DEFAULT_YACC = yacc +DEFAULT_LEX = lex + +BISON = bison -y +LEX = `if [ -f $$r/flex/flex ] ; \ + then echo $$r/flex/flex ; \ + else echo ${DEFAULT_LEX} ; fi` + +M4 = `if [ -f $$r/m4/m4 ] ; \ + then echo $$r/m4/m4 ; \ + else echo m4 ; fi` + +MAKEINFO = `if [ -f $$r/texinfo/makeinfo/makeinfo ] ; \ + then echo $$r/texinfo/makeinfo/makeinfo ; \ + else echo makeinfo ; fi` + +# This just becomes part of the MAKEINFO definition passed down to +# sub-makes. It lets flags be given on the command line while still +# using the makeinfo from the object tree. +MAKEINFOFLAGS = + +EXPECT = `if [ -f $$r/expect/expect ] ; \ + then echo $$r/expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $${srcroot}/dejagnu/runtest ] ; \ + then echo $${srcroot}/dejagnu/runtest ; \ + else echo runtest ; fi` + + +# compilers to use to create programs which must be run in the build +# environment. +CC_FOR_BUILD = $(CC) +CXX_FOR_BUILD = $(CXX) + +SUBDIRS = "this is set via configure, don't edit this" +OTHERS = + +# This is set by the configure script to the list of directories which +# should be built using the target tools. +TARGET_CONFIGDIRS = libiberty libgloss newlib libio librx libstdc++ libg++ winsup + +# Target libraries are put under this directory: +TARGET_SUBDIR = . # Changed by configure to $(target_alias) if cross. + +# This is set by the configure script to the arguments passed to configure. +CONFIG_ARGUMENTS = + +# This is set by configure to REALLY_SET_LIB_PATH if --enable-shared +# was used. +SET_LIB_PATH = + +# This is the name of the environment variable used for the path to +# the libraries. This may be changed by configure.in. +RPATH_ENVVAR = LD_LIBRARY_PATH + +# configure.in sets SET_LIB_PATH to this if --enable-shared was used. +REALLY_SET_LIB_PATH = \ + $(RPATH_ENVVAR)=$$r/bfd:$$r/opcodes:$$$(RPATH_ENVVAR); \ + export $(RPATH_ENVVAR); + +ALL = all.normal +INSTALL_TARGET = install-dirs \ + $(INSTALL_MODULES) \ + $(INSTALL_TARGET_MODULES) \ + $(INSTALL_X11_MODULES) \ + install-gcc \ + $(INSTALL_DOSREL) + + +CC_FOR_TARGET = ` \ + if [ -f $$r/gcc/Makefile ] ; then \ + if [ -f $$r/$(TARGET_SUBDIR)/newlib/Makefile ] ; then \ + echo $$r/gcc/xgcc -B$$r/gcc/ -idirafter $$r/$(TARGET_SUBDIR)/newlib/targ-include -idirafter $${srcroot}/newlib/libc/include -nostdinc; \ + else \ + echo $$r/gcc/xgcc -B$$r/gcc/; \ + fi; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(CC); \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e 's/x/x/' $$t; \ + fi; \ + fi` + + +CXX_FOR_TARGET = ` \ + if [ -f $$r/gcc/Makefile ] ; then \ + if [ -f $$r/$(TARGET_SUBDIR)/newlib/Makefile ] ; then \ + echo $$r/gcc/xgcc -B$$r/gcc/ -idirafter $$r/$(TARGET_SUBDIR)/newlib/targ-include -idirafter $${srcroot}/newlib/libc/include -nostdinc; \ + else \ + echo $$r/gcc/xgcc -B$$r/gcc/; \ + fi; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(CXX); \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e 's/x/x/' $$t; \ + fi; \ + fi` + +AS_FOR_TARGET = ` \ + if [ -f $$r/gas/as.new ] ; then \ + echo $$r/gas/as.new ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(AS); \ + else \ + t='$(program_transform_name)'; echo as | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +LD_FOR_TARGET = ` \ + if [ -f $$r/ld/ld.new ] ; then \ + echo $$r/ld/ld.new ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(LD); \ + else \ + t='$(program_transform_name)'; echo ld | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +DLLTOOL_FOR_TARGET = ` \ + if [ -f $$r/binutils/dlltool ] ; then \ + echo $$r/binutils/dlltool ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(DLLTOOL); \ + else \ + t='$(program_transform_name)'; echo dlltool | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +AR_FOR_TARGET = ` \ + if [ -f $$r/binutils/ar ] ; then \ + echo $$r/binutils/ar ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(AR); \ + else \ + t='$(program_transform_name)'; echo ar | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +RANLIB_FOR_TARGET = ` \ + if [ -f $$r/binutils/ranlib ] ; then \ + echo $$r/binutils/ranlib ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(RANLIB); \ + else \ + t='$(program_transform_name)'; echo ranlib | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +NM_FOR_TARGET = ` \ + if [ -f $$r/binutils/nm.new ] ; then \ + echo $$r/binutils/nm.new ; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(NM); \ + else \ + t='$(program_transform_name)'; echo nm | sed -e 's/x/x/' $$t ; \ + fi; \ + fi` + +#### host and target specific makefile fragments come in here. +### + +# Flags to pass down to all sub-makes. +# Please keep these in alphabetical order. +BASE_FLAGS_TO_PASS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "AR_FOR_TARGET=$(AR_FOR_TARGET)" \ + "AS_FOR_TARGET=$(AS_FOR_TARGET)" \ + "BISON=$(BISON)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CC_FOR_TARGET=$(CC_FOR_TARGET)" \ + "CFLAGS=$(CFLAGS)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "CXX_FOR_BUILD=$(CXX_FOR_BUILD)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CXXFLAGS_FOR_TARGET=$(CXXFLAGS_FOR_TARGET)" \ + "CXX_FOR_TARGET=$(CXX_FOR_TARGET)" \ + "DLLTOOL_FOR_TARGET=$(DLLTOOL_FOR_TARGET)" \ + "GCC_FOR_TARGET=$(CC_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_XFORM=$(INSTALL_XFORM)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LEX=$(LEX)" \ + "LD_FOR_TARGET=$(LD_FOR_TARGET)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "LIBCXXFLAGS=$(LIBCXXFLAGS)" \ + "LIBCXXFLAGS_FOR_TARGET=$(LIBCXXFLAGS_FOR_TARGET)" \ + "M4=$(M4)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "NM_FOR_TARGET=$(NM_FOR_TARGET)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "RANLIB_FOR_TARGET=$(RANLIB_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "EXPECT=$(EXPECT)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "YACC=$(BISON)" \ + "exec_prefix=$(exec_prefix)" \ + "prefix=$(prefix)" \ + "tooldir=$(tooldir)" + +# Flags to pass down to most sub-makes, in which we're building with +# the host environment. +# If any variables are added here, they must be added to do-*, below. +EXTRA_HOST_FLAGS = \ + 'AR=$(AR)' \ + 'AS=$(AS)' \ + 'CC=$(CC)' \ + 'CXX=$(CXX)' \ + 'DLLTOOL=$(DLLTOOL)' \ + 'NM=$(NM)' \ + 'RANLIB=$(RANLIB)' + + +FLAGS_TO_PASS = $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) + +# Flags that are concerned with the location of the X11 include files +# and library files +# +# NOTE: until the top-level is getting the values via autoconf, it only +# causes problems to have this top-level Makefile overriding the autoconf-set +# values in child directories. Only variables that don't conflict with +# autoconf'ed ones should be passed by X11_FLAGS_TO_PASS for now. +# +X11_FLAGS_TO_PASS = \ + 'X11_EXTRA_CFLAGS=$(X11_EXTRA_CFLAGS)' \ + 'X11_EXTRA_LIBS=$(X11_EXTRA_LIBS)' + +# Flags to pass down to makes which are built with the target environment. +# The double $ decreases the length of the command line; the variables +# are set in BASE_FLAGS_TO_PASS, and the sub-make will expand them. +# If any variables are added here, they must be added to do-*, below. +EXTRA_TARGET_FLAGS = \ + 'AR=$$(AR_FOR_TARGET)' \ + 'AS=$$(AS_FOR_TARGET)' \ + 'CC=$$(CC_FOR_TARGET)' \ + 'CFLAGS=$$(CFLAGS_FOR_TARGET)' \ + 'CXX=$$(CXX_FOR_TARGET)' \ + 'CXXFLAGS=$$(CXXFLAGS_FOR_TARGET)' \ + 'DLLTOOL=$$(DLLTOOL_FOR_TARGET)' \ + 'LD=$$(LD_FOR_TARGET)' \ + 'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \ + 'LIBCXXFLAGS=$$(LIBCXXFLAGS_FOR_TARGET)' \ + 'NM=$$(NM_FOR_TARGET)' \ + 'PICFLAG=$$(PICFLAG_FOR_TARGET)' \ + 'RANLIB=$$(RANLIB_FOR_TARGET)' + +TARGET_FLAGS_TO_PASS = $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) + +# Flags to pass down to gcc. gcc builds a library, libgcc.a, so it +# unfortunately needs the native compiler and the target ar and +# ranlib. +# If any variables are added here, they must be added to do-*, below. +# The HOST_* variables are a special case, which are used for the gcc +# cross-building scheme. +EXTRA_GCC_FLAGS = \ + 'AR=$$(AR_FOR_TARGET)' \ + 'AS=$(AS)' \ + 'CC=$(CC)' \ + 'CXX=$(CXX)' \ + 'DLLTOOL=$$(DLLTOOL_FOR_TARGET)' \ + 'HOST_CC=$(CC_FOR_BUILD)' \ + 'HOST_PREFIX=$(HOST_PREFIX)' \ + 'HOST_PREFIX_1=$(HOST_PREFIX_1)' \ + 'NM=$(NM)' \ + 'RANLIB=$$(RANLIB_FOR_TARGET)' \ + `if test x"$(LANGUAGES)" != x; then echo "LANGUAGES=$(LANGUAGES)"; fi` \ + `if test x"$(STMP_FIXPROTO)" != x; then echo "STMP_FIXPROTO=$(STMP_FIXPROTO)"; fi` \ + `if test x"$(LIMITS_H_TEST)" != x; then echo "LIMITS_H_TEST=$(LIMITS_H_TEST)"; fi` \ + `if test x"$(LIBGCC1_TEST)" != x; then echo "LIBGCC1_TEST=$(LIBGCC1_TEST)"; fi` \ + `if test x"$(LIBGCC2_CFLAGS)" != x; then echo "LIBGCC2_CFLAGS=$(LIBGCC2_CFLAGS)"; fi` \ + `if test x"$(LIBGCC2_INCLUDES)" != x; then echo "LIBGCC2_INCLUDES=$(LIBGCC2_INCLUDES)"; fi` \ + `if test x"$(ENQUIRE)" != x; then echo "ENQUIRE=$(ENQUIRE)"; fi` \ + `if test x"$(BOOT_CFLAGS)" != x; then echo "BOOT_CFLAGS=$(BOOT_CFLAGS)"; fi` + +GCC_FLAGS_TO_PASS = $(BASE_FLAGS_TO_PASS) $(EXTRA_GCC_FLAGS) + +# This is a list of the targets for all of the modules which are compiled +# using $(FLAGS_TO_PASS). +ALL_MODULES = \ + all-autoconf \ + all-bfd \ + all-binutils \ + all-byacc \ + all-cvs \ + all-dejagnu \ + all-diff \ + all-dosutils \ + all-etc \ + all-fileutils \ + all-find \ + all-flex \ + all-gas \ + all-gawk \ + all-gprof \ + all-grep \ + all-grez \ + all-gzip \ + all-hello \ + all-indent \ + all-ispell \ + all-ld \ + all-libiberty \ + all-m4 \ + all-make \ + all-mmalloc \ + all-opcodes \ + all-patch \ + all-prms \ + all-rcs \ + all-readline \ + all-release \ + all-recode \ + all-sed \ + all-send-pr \ + all-shellutils \ + all-sim \ + all-tar \ + all-tcl \ + all-texinfo \ + all-textutils \ + all-tgas \ + all-time \ + all-uudecode \ + all-wdiff + +# This is a list of the check targets for all of the modules which are +# compiled using $(FLAGS_TO_PASS). +# This is a list of the check targets for all of the modules which are +# compiled using $(FLAGS_TO_PASS). +# +# The list is in two parts. The first lists those tools which +# are tested as part of the host's native tool-chain, and not +# tested in a cross configuration. +NATIVE_CHECK_MODULES = \ + check-byacc \ + check-flex + +CROSS_CHECK_MODULES = \ + check-autoconf \ + check-bfd \ + check-binutils \ + check-cvs \ + check-dejagnu \ + check-diff \ + check-etc \ + check-fileutils \ + check-find \ + check-gas \ + check-gawk \ + check-gprof \ + check-grep \ + check-gzip \ + check-hello \ + check-indent \ + check-ispell \ + check-ld \ + check-libiberty \ + check-m4 \ + check-make \ + check-mmcheckoc \ + check-opcodes \ + check-patch \ + check-prms \ + check-rcs \ + check-readline \ + check-recode \ + check-sed \ + check-send-pr \ + check-shellutils \ + check-sim \ + check-tar \ + check-tcl \ + check-texinfo \ + check-textutils \ + check-tgas \ + check-time \ + check-uudecode \ + check-wdiff + +CHECK_MODULES=$(NATIVE_CHECK_MODULES) $(CROSS_CHECK_MODULES) + +# This is a list of the install targets for all of the modules which are +# compiled using $(FLAGS_TO_PASS). +INSTALL_MODULES = \ + install-autoconf \ + install-bfd \ + install-binutils \ + install-byacc \ + install-cvs \ + install-dejagnu \ + install-diff \ + install-dosutils \ + install-etc \ + install-fileutils \ + install-find \ + install-flex \ + install-gas \ + install-gawk \ + install-gprof \ + install-grep \ + install-grez \ + install-gzip \ + install-hello \ + install-indent \ + install-ispell \ + install-ld \ + install-libiberty \ + install-m4 \ + install-make \ + install-mmalloc \ + install-opcodes \ + install-patch \ + install-prms \ + install-rcs \ + install-readline \ + install-recode \ + install-sed \ + install-send-pr \ + install-shellutils \ + install-sim \ + install-tar \ + install-tcl \ + install-textutils \ + install-tgas \ + install-time \ + install-uudecode \ + install-wdiff + +# This is a list of the targets for all of the modules which are compiled +# using $(X11_FLAGS_TO_PASS). +ALL_X11_MODULES = \ + all-emacs \ + all-emacs19 \ + all-gdb \ + all-expect \ + all-gash \ + all-tclX \ + all-tk + +# This is a list of the check targets for all of the modules which are +# compiled using $(X11_FLAGS_TO_PASS). +CHECK_X11_MODULES = \ + check-emacs \ + check-gdb \ + check-expect \ + check-gash \ + check-tclX \ + check-tk + +# This is a list of the install targets for all the modules which are +# compiled using $(X11_FLAGS_TO_PASS). +INSTALL_X11_MODULES = \ + install-emacs \ + install-emacs19 \ + install-gdb \ + install-expect \ + install-gash \ + install-tclX \ + install-tk + +# This is a list of the targets for all of the modules which are compiled +# using $(TARGET_FLAGS_TO_PASS). +ALL_TARGET_MODULES = \ + all-target-libio \ + all-target-libstdc++ \ + all-target-librx \ + all-target-libg++ \ + all-target-newlib \ + all-target-winsup \ + all-target-libgloss \ + all-target-libiberty \ + all-target-examples + +# This is a list of the configure targets for all of the modules which +# are compiled using the target tools. +CONFIGURE_TARGET_MODULES = \ + configure-target-libio \ + configure-target-libstdc++ \ + configure-target-librx \ + configure-target-libg++ \ + configure-target-newlib \ + configure-target-winsup \ + configure-target-libgloss \ + configure-target-libiberty \ + configure-target-examples + +# This is a list of the check targets for all of the modules which are +# compiled using $(TARGET_FLAGS_TO_PASS). +CHECK_TARGET_MODULES = \ + check-target-libio \ + check-target-libstdc++ \ + check-target-libg++ \ + check-target-newlib \ + check-target-winsup \ + check-target-libiberty + +# This is a list of the install targets for all of the modules which are +# compiled using $(TARGET_FLAGS_TO_PASS). +INSTALL_TARGET_MODULES = \ + install-target-libio \ + install-target-libstdc++ \ + install-target-libg++ \ + install-target-newlib \ + install-target-winsup \ + install-target-libgloss \ + install-target-libiberty + +# The first rule in the file had better be this one. Don't put any above it. +all: all.normal +.PHONY: all + +# The target built for a native build. +.PHONY: all.normal +all.normal: \ + $(ALL_MODULES) \ + $(ALL_TARGET_MODULES) \ + $(ALL_X11_MODULES) \ + all-gcc + +# Do a target for all the subdirectories. A ``make do-X'' will do a +# ``make X'' in all subdirectories (because, in general, there is a +# dependency (below) of X upon do-X, a ``make X'' will also do this, +# but it may do additional work as well). +# This target ensures that $(BASE_FLAGS_TO_PASS) appears only once, +# because it is so large that it can easily overflow the command line +# length limit on some systems. +DO_X = \ + do-clean \ + do-distclean \ + do-dvi \ + do-info \ + do-install-info \ + do-installcheck \ + do-mostlyclean \ + do-maintainer-clean \ + do-TAGS +.PHONY: $(DO_X) +$(DO_X): + @target=`echo $@ | sed -e 's/^do-//'`; \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + for i in $(SUBDIRS) -dummy-; do \ + if [ -f ./$$i/Makefile ]; then \ + case $$i in \ + gcc) \ + for flag in $(EXTRA_GCC_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'|"`; \ + done; \ + ;; \ + *) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'|"`; \ + done; \ + ;; \ + esac ; \ + export AR AS CC CXX NM RANLIB DLLTOOL; \ + if (cd ./$$i; \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" \ + $${target}); \ + then true; else exit 1; fi; \ + else true; fi; \ + done + @target=`echo $@ | sed -e 's/^do-//'`; \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + for i in $(TARGET_CONFIGDIRS) -dummy-; do \ + if [ -f $(TARGET_SUBDIR)/$$i/Makefile ]; then \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'|"`; \ + done; \ + export AR AS CC CXX NM RANLIB DLLTOOL; \ + if (cd $(TARGET_SUBDIR)/$$i; \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" \ + $${target}); \ + then true; else exit 1; fi; \ + else true; fi; \ + done + +# Here are the targets which correspond to the do-X targets. + +.PHONY: info installcheck dvi install-info +.PHONY: clean distclean mostlyclean maintainer-clean realclean +.PHONY: local-clean local-distclean local-maintainer-clean +info: do-info +installcheck: do-installcheck +dvi: do-dvi + +install-info: do-install-info dir.info + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + if [ -f dir.info ] ; then \ + $(INSTALL_DATA) dir.info $(infodir)/dir.info ; \ + else true ; fi + +local-clean: + -rm -f *.a TEMP errs core *.o *~ \#* TAGS *.E + +local-distclean: + -rm -f Makefile config.status + -if [ "$(TARGET_SUBDIR)" != "." ]; then \ + rm -rf $(TARGET_SUBDIR); \ + else true; fi + +local-maintainer-clean: + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +clean: do-clean local-clean +mostlyclean: do-mostlyclean local-clean +distclean: do-distclean local-clean local-distclean +maintainer-clean: local-maintainer-clean do-maintainer-clean local-clean +maintainer-clean: local-distclean +realclean: maintainer-clean + +# Check target. + +.PHONY: check +check: $(CHECK_MODULES) \ + $(CHECK_TARGET_MODULES) \ + $(CHECK_X11_MODULES) \ + check-gcc + +# Installation targets. + +.PHONY: install uninstall source-vault binary-vault vault-install +install: $(INSTALL_TARGET) + +uninstall: + @echo "the uninstall target is not supported in this tree" + +source-vault: + $(MAKE) -f ./release/Build-A-Release \ + host=$(host_alias) source-vault + +binary-vault: + $(MAKE) -f ./release/Build-A-Release \ + host=$(host_alias) target=$(target_alias) + +vault-install: + @if [ -f ./release/vault-install ] ; then \ + ./release/vault-install $(host_alias) $(target_alias) ; \ + else \ + true ; \ + fi + +.PHONY: install.all +install.all: install-no-fixedincludes + @if [ -f ./gcc/Makefile ] ; then \ + r=`pwd` ; export r ; \ + $(SET_LIB_PATH) \ + (cd ./gcc; \ + $(MAKE) $(FLAGS_TO_PASS) install-headers) ; \ + else \ + true ; \ + fi + +# install-no-fixedincludes is used because Cygnus can not distribute +# the fixed header files. +.PHONY: install-no-fixedincludes +install-no-fixedincludes: \ + install-dirs \ + $(INSTALL_MODULES) \ + $(INSTALL_TARGET_MODULES) \ + $(INSTALL_X11_MODULES) \ + gcc-no-fixedincludes + +# Install the gcc headers files, but not the fixed include files, +# which Cygnus is not allowed to distribute. This rule is very +# dependent on the workings of the gcc Makefile.in. +.PHONY: gcc-no-fixedincludes +gcc-no-fixedincludes: + @if [ -f ./gcc/Makefile ]; then \ + rm -rf gcc/tmp-include; \ + mv gcc/include gcc/tmp-include 2>/dev/null; \ + mkdir gcc/include; \ + cp $(srcdir)/gcc/gsyslimits.h gcc/include/syslimits.h; \ + touch gcc/stmp-fixinc gcc/include/fixed; \ + rm -f gcc/stmp-headers gcc/stmp-int-hdrs; \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd` ; export srcroot; \ + $(SET_LIB_PATH) \ + (cd ./gcc; \ + $(MAKE) $(GCC_FLAGS_TO_PASS) install); \ + rm -rf gcc/include; \ + mv gcc/tmp-include gcc/include 2>/dev/null; \ + else true; fi + +# This rule is used to build the modules which use FLAGS_TO_PASS. To +# build a target all-X means to cd to X and make all. +# +# all-gui, and all-libproc are handled specially because +# they are still experimental, and if they fail to build, that +# shouldn't stop "make all". +.PHONY: $(ALL_MODULES) all-gui all-libproc +$(ALL_MODULES) all-gui all-libproc: + @dir=`echo $@ | sed -e 's/all-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) all); \ + else \ + true; \ + fi + +# These rules are used to check the modules which use FLAGS_TO_PASS. +# To build a target check-X means to cd to X and make check. Some +# modules are only tested in a native toolchain. + +.PHONY: $(CHECK_MODULES) $(NATIVE_CHECK_MODULES) $(CROSS_CHECK_MODULES) +$(NATIVE_CHECK_MODULES): + @if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + dir=`echo $@ | sed -e 's/check-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) check); \ + else \ + true; \ + fi; \ + fi + +$(CROSS_CHECK_MODULES): + @dir=`echo $@ | sed -e 's/check-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) check); \ + else \ + true; \ + fi + +# This rule is used to install the modules which use FLAGS_TO_PASS. +# To build a target install-X means to cd to X and make install. +.PHONY: $(INSTALL_MODULES) +$(INSTALL_MODULES): install-dirs + @dir=`echo $@ | sed -e 's/install-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) install); \ + else \ + true; \ + fi + +# This rule is used to configure the modules which are built with the +# target tools. +.PHONY: $(CONFIGURE_TARGET_MODULES) +$(CONFIGURE_TARGET_MODULES): + @dir=`echo $@ | sed -e 's/configure-target-//'`; \ + if [ -f $(TARGET_SUBDIR)/$${dir}/Makefile ] ; then \ + true; \ + elif echo " $(TARGET_CONFIGDIRS) " | grep " $${dir} " >/dev/null 2>&1; then \ + if [ -d $(srcdir)/$${dir} ]; then \ + [ -d $(TARGET_SUBDIR)/$${dir} ] || mkdir $(TARGET_SUBDIR)/$${dir};\ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + AR="$(AR_FOR_TARGET)"; export AR; \ + AS="$(AS_FOR_TARGET)"; export AS; \ + CC="$(CC_FOR_TARGET)"; export CC; \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXX="$(CXX_FOR_TARGET)"; export CXX; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ + LD="$(LD_FOR_TARGET)"; export LD; \ + NM="$(NM_FOR_TARGET)"; export NM; \ + RANLIB="$(RANLIB_FOR_TARGET)"; export RANLIB; \ + echo Configuring in $(TARGET_SUBDIR)/$${dir}; \ + cd $(TARGET_SUBDIR)/$${dir}; \ + case $(srcdir) in \ + /*) \ + topdir=$(srcdir) ;; \ + *) \ + case "$(TARGET_SUBDIR)" in \ + .) topdir="../$(srcdir)" ;; \ + *) topdir="../../$(srcdir)" ;; \ + esac ;; \ + esac; \ + if [ "$(srcdir)" = "." ] ; then \ + if [ "$(TARGET_SUBDIR)" != "." ] ; then \ + if $(SHELL) $${srcroot}/symlink-tree $${topdir}/$${dir} "no-such-file" ; then \ + if [ -f Makefile ]; then \ + if $(MAKE) distclean; then \ + true; \ + else \ + exit 1; \ + fi; \ + else \ + true; \ + fi; \ + else \ + exit 1; \ + fi; \ + else \ + true; \ + fi; \ + srcdiroption="--srcdir=."; \ + libsrcdir="."; \ + else \ + srcdiroption="--srcdir=$${topdir}/$${dir}"; \ + libsrcdir="$${srcroot}/$${dir}"; \ + fi; \ + if [ -f $${libsrcdir}/configure ] ; then \ + $(SHELL) $${libsrcdir}/configure \ + $(CONFIG_ARGUMENTS) $${srcdiroption} \ + --with-target-subdir="$(TARGET_SUBDIR)"; \ + else \ + $(SHELL) $${srcroot}/configure \ + $(CONFIG_ARGUMENTS) $${srcdiroption} \ + --with-target-subdir="$(TARGET_SUBDIR)"; \ + fi; \ + else \ + true; \ + fi; \ + else \ + true; \ + fi + +# This rule is used to build the modules which use TARGET_FLAGS_TO_PASS. +# To build a target all-X means to cd to X and make all. +.PHONY: $(ALL_TARGET_MODULES) +$(ALL_TARGET_MODULES): + @dir=`echo $@ | sed -e 's/all-target-//'`; \ + if [ -f $(TARGET_SUBDIR)/$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/$${dir}; $(MAKE) $(TARGET_FLAGS_TO_PASS) all); \ + else \ + true; \ + fi + +# This rule is used to check the modules which use TARGET_FLAGS_TO_PASS. +# To build a target install-X means to cd to X and make install. +.PHONY: $(CHECK_TARGET_MODULES) +$(CHECK_TARGET_MODULES): + @dir=`echo $@ | sed -e 's/check-target-//'`; \ + if [ -f $(TARGET_SUBDIR)/$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/$${dir};$(MAKE) $(TARGET_FLAGS_TO_PASS) check);\ + else \ + true; \ + fi + +# This rule is used to install the modules which use +# TARGET_FLAGS_TO_PASS. To build a target install-X means to cd to X +# and make install. +.PHONY: $(INSTALL_TARGET_MODULES) +$(INSTALL_TARGET_MODULES): install-dirs + @dir=`echo $@ | sed -e 's/install-target-//'`; \ + if [ -f $(TARGET_SUBDIR)/$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/$${dir}; \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install); \ + else \ + true; \ + fi + +# This rule is used to build the modules which use X11_FLAGS_TO_PASS. +# To build a target all-X means to cd to X and make all. +.PHONY: $(ALL_X11_MODULES) +$(ALL_X11_MODULES): + @dir=`echo $@ | sed -e 's/all-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; \ + $(MAKE) $(FLAGS_TO_PASS) $(X11_FLAGS_TO_PASS) all); \ + else \ + true; \ + fi + +# This rule is used to check the modules which use X11_FLAGS_TO_PASS. +# To build a target check-X means to cd to X and make all. +.PHONY: $(CHECK_X11_MODULES) +$(CHECK_X11_MODULES): + @dir=`echo $@ | sed -e 's/check-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; \ + $(MAKE) $(FLAGS_TO_PASS) $(X11_FLAGS_TO_PASS) check); \ + else \ + true; \ + fi + +# This rule is used to install the modules which use X11_FLAGS_TO_PASS. +# To build a target install-X means to cd to X and make install. +.PHONY: $(INSTALL_X11_MODULES) +$(INSTALL_X11_MODULES): + @dir=`echo $@ | sed -e 's/install-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; \ + $(MAKE) $(FLAGS_TO_PASS) $(X11_FLAGS_TO_PASS) install); \ + else \ + true; \ + fi + +# gcc is the only module which uses GCC_FLAGS_TO_PASS. +.PHONY: all-gcc +all-gcc: + @if [ -f ./gcc/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd gcc; $(MAKE) $(GCC_FLAGS_TO_PASS) all); \ + else \ + true; \ + fi + +.PHONY: all-bootstrap +all-bootstrap: + @if [ -f ./gcc/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd gcc; $(MAKE) $(GCC_FLAGS_TO_PASS) bootstrap); \ + else \ + true; \ + fi + +.PHONY: check-gcc +check-gcc: + @if [ -f ./gcc/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd gcc; $(MAKE) $(GCC_FLAGS_TO_PASS) check); \ + else \ + true; \ + fi + +.PHONY: install-gcc +install-gcc: + @if [ -f ./gcc/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd gcc; $(MAKE) $(GCC_FLAGS_TO_PASS) install); \ + else \ + true; \ + fi + + +# EXPERIMENTAL STUFF +# This rule is used to install the modules which use FLAGS_TO_PASS. +# To build a target install-X means to cd to X and make install. +.PHONY: install-dosrel +install-dosrel: install-dirs info + @dir=`echo $@ | sed -e 's/install-//'`; \ + if [ -f ./$${dir}/Makefile ] ; then \ + r=`pwd`; export r; \ + srcroot=`cd $(srcdir); pwd`; export srcroot; \ + $(SET_LIB_PATH) \ + (cd $${dir}; $(MAKE) $(FLAGS_TO_PASS) install); \ + else \ + true; \ + fi + +install-dosrel-fake: + + +# This is a list of inter-dependencies among modules. +all-autoconf: all-m4 +all-bfd: +all-binutils: all-libiberty all-opcodes all-bfd all-flex all-byacc +all-byacc: +all-cvs: +all-dejagnu: all-tcl all-expect all-tk +all-diff: all-libiberty +all-emacs: +all-emacs19: all-byacc +all-etc: +configure-target-examples: $(ALL_GCC) +all-target-examples: configure-target-examples +all-expect: all-tcl all-tk +all-fileutils: all-libiberty +all-find: +all-flex: all-libiberty all-byacc +all-gas: all-libiberty all-opcodes all-bfd +all-gash: all-tcl +all-gawk: +ALL_GCC = all-gcc +all-gcc: all-libiberty all-byacc all-binutils all-gas all-ld +all-bootstrap: all-libiberty all-byacc all-binutils all-gas all-ld +GDB_TK = all-tk all-tcl +all-gdb: all-libiberty all-opcodes all-bfd all-mmalloc all-readline all-byacc all-sim $(gdbnlmrequirements) $(GDB_TK) +all-gprof: all-libiberty all-bfd all-opcodes +all-grep: all-libiberty +all-grez: all-libiberty all-bfd all-opcodes +all-gui: all-gdb all-libproc all-target-librx +all-gzip: all-libiberty +all-hello: all-libiberty +all-indent: +all-ispell: all-emacs19 +all-ld: all-libiberty all-bfd all-opcodes all-byacc all-flex +configure-target-libg++: $(ALL_GCC) configure-target-librx +all-target-libg++: configure-target-libg++ all-gas all-ld all-gcc all-target-libiberty all-target-newlib all-target-libio all-target-librx all-target-libstdc++ +configure-target-libgloss: $(ALL_GCC) +all-target-libgloss: configure-target-libgloss configure-target-newlib +configure-target-libio: $(ALL_GCC) +all-target-libio: configure-target-libio all-gas all-ld all-gcc all-target-libiberty all-target-newlib +all-libiberty: +configure-target-librx: $(ALL_GCC) configure-target-newlib +all-target-librx: configure-target-librx +configure-target-libstdc++: $(ALL_GCC) +all-target-libstdc++: configure-target-libstdc++ all-gas all-ld all-gcc all-target-libiberty all-target-newlib all-target-libio +all-m4: all-libiberty +all-make: all-libiberty +all-mmalloc: +configure-target-newlib: $(ALL_GCC) +all-target-newlib: configure-target-newlib all-binutils all-gas all-gcc +all-opcodes: all-bfd all-libiberty +all-patch: all-libiberty +all-prms: all-libiberty +all-rcs: +all-readline: +all-recode: all-libiberty +all-sed: all-libiberty +all-send-pr: all-prms +all-shellutils: +all-sim: all-libiberty all-bfd all-opcodes +all-tar: all-libiberty +all-tcl: +all-tclX: all-tcl all-tk +all-tk: all-tcl +all-texinfo: all-libiberty +all-textutils: +all-tgas: all-libiberty all-bfd all-opcodes +all-time: +all-wdiff: +all-target-winsup: all-target-newlib all-target-libiberty configure-target-winsup +configure-target-winsup: configure-target-newlib +all-uudecode: all-libiberty +configure-target-libiberty: $(ALL_GCC) +all-target-libiberty: configure-target-libiberty all-gcc all-ld all-target-newlib + +### other supporting targets + +MAKEDIRS= \ + $(prefix) \ + $(exec_prefix) \ + $(tooldir) + +.PHONY: install-dirs +install-dirs: + @for i in $(MAKEDIRS) ; do \ + echo Making $$i... ; \ + parent=`echo $$i | sed -e 's@/[^/]*$$@@' | sed -e 's@^$$@/@'`; \ + if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi ; \ + if [ ! -d $$i ] ; then \ + if mkdir $$i ; then \ + true ; \ + else \ + exit 1 ; \ + fi ; \ + else \ + true ; \ + fi ; \ + done + + +dir.info: do-install-info + if [ -f $(srcdir)/texinfo/gen-info-dir ] ; then \ + $(srcdir)/texinfo/gen-info-dir $(infodir) $(srcdir)/texinfo/dir.info-template > dir.info.new ; \ + mv -f dir.info.new dir.info ; \ + else true ; \ + fi + +dist: + @echo "Building a full distribution of this tree isn't done" + @echo "via 'make dist'. Check out the etc/ subdirectory" + +etags tags: TAGS + +# Right now this just builds TAGS in each subdirectory. emacs19 has the +# ability to use several tags files at once, so there is probably no need +# to combine them into one big TAGS file (like CVS 1.3 does). We could +# (if we felt like it) have this Makefile write a piece of elisp which +# the user could load to tell emacs19 where all the TAGS files we just +# built are. +TAGS: do-TAGS + +# with the gnu make, this is done automatically. + +Makefile: Makefile.in configure.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + +# +# Support for building net releases + +# Files in devo used in any net release. +# ChangeLog omitted because it may refer to files which are not in this +# distribution (perhaps it would be better to include it anyway). +DEVO_SUPPORT= README Makefile.in configure configure.in \ + config.guess config.sub config move-if-change \ + mpw-README mpw-build.in mpw-config.in mpw-configure \ + COPYING COPYING.LIB install.sh config-ml.in symlink-tree + +# Files in devo/etc used in any net release. +# ChangeLog omitted because it may refer to files which are not in this +# distribution (perhaps it would be better to include it anyway). +ETC_SUPPORT= Makefile.in cfg-paper.texi configure.in configure.man \ + configure.texi standards.texi make-stds.texi \ + configure.info* standards.info* cfg-paper.info* + +# When you use `make setup-dirs' or `make taz' you should always redefine +# this macro. +SUPPORT_FILES = list-of-support-files-for-tool-in-question +# Files where "byacc" (Cygnus version) should be changed to "bison -y" (FSF). +DISTBISONFILES= binutils/Makefile.in gas/Makefile.in gdb/Makefile.in + +.PHONY: taz + +taz: $(DEVO_SUPPORT) $(SUPPORT_FILES) \ + texinfo/texinfo.tex texinfo/gpl.texinfo texinfo/lgpl.texinfo + # Make sure "diststuff" files get built properly. + for f in $(DISTBISONFILES) ; do \ + if [ -r $$f ]; then \ + sed '/^BISON *=.*$$/s/.*/BISON = bison -y/' <$$f >tmp ; \ + mv -f tmp $$f ; \ + else true; fi ; \ + done + # Take out texinfo from a few places; make simple BISON=bison line. + sed -e '/^all\.normal: /s/\all-texinfo //' \ + -e '/^ install-texinfo /d' \ + -e '/^BISON = /,/^$$/d' \ + -e '/^# BISON:/s/.*/BISON = bison -y/' \ + tmp + mv -f tmp Makefile.in + # + ./configure sun4 + [ -z "$(CONFIGURE_TARGET_MODULES)" ] \ + || $(MAKE) $(CONFIGURE_TARGET_MODULES) ALL_GCC="" \ + CC_FOR_TARGET="$(CC)" CXX_FOR_TARGET="$(CXX)" + # Make links, and run "make diststuff" or "make info" when needed. + rm -rf proto-toplev ; mkdir proto-toplev + set -e ; dirs="$(TOOL) $(DEVO_SUPPORT) $(SUPPORT_FILES)" ; \ + for d in $$dirs ; do \ + if [ -d $$d ]; then \ + if [ ! -f $$d/Makefile ] ; then true ; \ + elif grep '^diststuff:' $$d/Makefile >/dev/null ; then \ + (cd $$d ; $(MAKE) diststuff ) || exit 1 ; \ + elif grep '^info:' $$d/Makefile >/dev/null ; then \ + (cd $$d ; $(MAKE) info ) || exit 1 ; \ + fi ; \ + if [ -d $$d/proto-$$d.dir ]; then \ + ln -s ../$$d/proto-$$d.dir proto-toplev/$$d ; \ + else \ + ln -s ../$$d proto-toplev/$$d ; \ + fi ; \ + else ln -s ../$$d proto-toplev/$$d ; fi ; \ + done + cd etc ; $(MAKE) info + $(MAKE) distclean + # + mkdir proto-toplev/etc + (cd proto-toplev/etc; \ + for i in $(ETC_SUPPORT); do \ + ln -s ../../etc/$$i . ; \ + done) + # + # Take out texinfo from configurable dirs + rm proto-toplev/configure.in + sed -e '/^host_tools=/s/texinfo //' \ + proto-toplev/configure.in + # + mkdir proto-toplev/texinfo + ln -s ../../texinfo/texinfo.tex proto-toplev/texinfo/ + ln -s ../../texinfo/gpl.texinfo proto-toplev/texinfo/ + ln -s ../../texinfo/lgpl.texinfo proto-toplev/texinfo/ + ln -s ../../texinfo/tex3patch proto-toplev/texinfo/ + chmod og=u `find . -print` + (VER=`sed <$(TOOL)/Makefile.in -n 's/^VERSION *= *//p'`; \ + echo "==> Making $(TOOL)-$$VER.tar.gz"; \ + rm -f $(TOOL)-$$VER; ln -s proto-toplev $(TOOL)-$$VER; \ + tar cfh - $(TOOL)-$$VER \ + | $(GZIPPROG) -v -9 >$(TOOL)-$$VER.tar.gz ) + +TEXINFO_SUPPORT= texinfo/texinfo.tex texinfo/gpl.texinfo texinfo/lgpl.texinfo +DIST_SUPPORT= $(DEVO_SUPPORT) $(TEXINFO_SUPPORT) + +.PHONY: gas.tar.gz +GAS_SUPPORT_DIRS= bfd include libiberty opcodes +gas.tar.gz: $(DIST_SUPPORT) $(GAS_SUPPORT_DIRS) gas + $(MAKE) -f Makefile.in taz TOOL=gas \ + SUPPORT_FILES="$(GAS_SUPPORT_DIRS)" + +# The FSF "binutils" release includes gprof and ld. +.PHONY: binutils.tar.gz +BINUTILS_SUPPORT_DIRS= bfd gas include libiberty opcodes ld gprof +binutils.tar.gz: $(DIST_SUPPORT) $(BINUTILS_SUPPORT_DIRS) binutils + $(MAKE) -f Makefile.in taz TOOL=binutils \ + SUPPORT_FILES="$(BINUTILS_SUPPORT_DIRS) makeall.bat configure.bat" + +.PHONY: gas+binutils.tar.gz +GASB_SUPPORT_DIRS= $(GAS_SUPPORT_DIRS) binutils ld gprof +gas+binutils.tar.gz: $(DIST_SUPPORT) $(GASB_SUPPORT_DIRS) gas + $(MAKE) -f Makefile.in taz TOOL=gas \ + SUPPORT_FILES="$(GASB_SUPPORT_DIRS) makeall.bat configure.bat" + +.PHONY: libg++.tar.gz +LIBGXX_SUPPORT_DIRS=include libstdc++ libio librx libiberty +libg++.tar.gz: $(DIST_SUPPORT) libg++ + $(MAKE) -f Makefile.in taz TOOL=libg++ \ + SUPPORT_FILES="$(LIBGXX_SUPPORT_DIRS)" + +GNATS_SUPPORT_DIRS=include libiberty send-pr +gnats.tar.gz: $(DIST_SUPPORT) $(GNATS_SUPPORT_DIRS) gnats + $(MAKE) -f Makefile.in taz TOOL=gnats \ + SUPPORT_FILES="$(GNATS_SUPPORT_DIRS)" + +.PHONY: gdb.tar.gz +GDB_SUPPORT_DIRS= bfd include libiberty mmalloc opcodes readline sim utils +gdb.tar.gz: $(DIST_SUPPORT) $(GDB_SUPPORT_DIRS) gdb + $(MAKE) -f Makefile.in taz TOOL=gdb \ + SUPPORT_FILES="$(GDB_SUPPORT_DIRS)" + +.PHONY: newlib.tar.gz +NEWLIB_SUPPORT_DIRS=libgloss +# taz configures for the sun4 target which won't configure newlib. +# We need newlib configured so that the .info files are made. +# Unfortunately, it is not enough to just configure newlib separately: +# taz will build the .info files but since SUBDIRS won't contain newlib, +# distclean won't be run (leaving Makefile, config.status, and the tmp files +# used in building the .info files, eg: *.def, *.ref). +# The problem isn't solvable however without a lot of extra work because +# target libraries are built in subdir $(target_alias) which gets nuked during +# the make distclean. For now punt on the issue of shipping newlib info files +# with newlib net releases and wait for a day when some native target (sun4?) +# supports newlib (if only minimally). +newlib.tar.gz: $(DIST_SUPPORT) $(NEWLIB_SUPPORT_DIRS) newlib + $(MAKE) -f Makefile.in taz TOOL=newlib \ + SUPPORT_FILES="$(NEWLIB_SUPPORT_DIRS)" \ + DEVO_SUPPORT="$(DEVO_SUPPORT) COPYING.NEWLIB" newlib + +.NOEXPORT: +MAKEOVERRIDES= + + +# end of Makefile.in diff --git a/contrib/gdb/README b/contrib/gdb/README new file mode 100644 index 000000000000..7ec34b1a07d5 --- /dev/null +++ b/contrib/gdb/README @@ -0,0 +1,50 @@ + README for GNU development tools + +This directory contains various GNU compilers, assemblers, linkers, +debuggers, etc., plus their support routines, definitions, and documentation. + +If you are receiving this as part of a GDB release, see the file gdb/README. +If with a gas release, see gas/README; if with a libg++ release, +see libg++/README, etc. That'll give you info about this +package -- supported targets, how to use it, how to report bugs, etc. + +It is now possible to automatically configure and build a variety of +tools with one command. To build all of the tools contained herein, +run the ``configure'' script here, e.g.: + + ./configure + make + +To install them (by default in /usr/local/bin, /usr/local/lib, etc), +then do: + make install + +If the configure script can't determine your type of computer, give it +the name as an argument, for instance ``./configure sun4''. You can +use the script ``config.sub'' to test whether a name is recognized; if +it is, config.sub translates it to a triplet specifying CPU, vendor, +and OS.) + +If you have more than one compiler on your system, it is often best to +explicitly set CC in the environment before running configure, and to +also set CC when running make. For example (assuming sh/bash/ksh): + + CC=gcc ./configure + make CC=gcc + +A similar example using csh: + + setenv CC gcc + ./configure + make CC=gcc + +See etc/cfg-paper.texi, etc/configure.texi, and/or the README files in +various subdirectories, for more details. + +Much of the code and documentation enclosed is copyright by +the Free Software Foundation, Inc. See the file COPYING or +COPYING.LIB in the various directories, for a description of the +GNU General Public License terms under which you can copy the files. + +REPORTING BUGS: Again, see gdb/README, gas/README, etc., for info on where and +how to report problems. diff --git a/contrib/gdb/bfd/COPYING b/contrib/gdb/bfd/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/contrib/gdb/bfd/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/gdb/bfd/Makefile.in b/contrib/gdb/bfd/Makefile.in new file mode 100644 index 000000000000..e531cf85dc58 --- /dev/null +++ b/contrib/gdb/bfd/Makefile.in @@ -0,0 +1,1090 @@ +# Makefile template for Configure for the BFD library. +# Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 +# Free Software Foundation, Inc. +# Written by Cygnus Support. +# +# 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 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +VPATH = @srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ + +program_transform_name = @program_transform_name@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +oldincludedir = +docdir = doc + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +AR = @AR@ +AR_FLAGS = rc +CC = @CC@ +CFLAGS = @CFLAGS@ +MAKEINFO = makeinfo +RANLIB = @RANLIB@ + +ALLLIBS = @ALLLIBS@ + +PICFLAG = @PICFLAG@ +SHLIB = @SHLIB@ +SHLIB_CC = @SHLIB_CC@ +SHLIB_CFLAGS = @SHLIB_CFLAGS@ +COMMON_SHLIB = @COMMON_SHLIB@ +SHLINK = @SHLINK@ + +SONAME = lib`echo $(SHLIB) | sed -e 's/^lib//' | sed '$(program_transform_name)'` + +CC_FOR_BUILD = @CC_FOR_BUILD@ + +INCDIR = $(srcdir)/../include +CSEARCH = -I. -I$(srcdir) -I$(INCDIR) +DEP = mkdep + +SUBDIRS = doc + +TARGETLIB = libbfd.a + +# bfd.h goes here, for now +BFD_H = bfd.h + +# Some of these files should be in BFD*_BACKENDS below, but some programs +# won't link without them. So, in order for some of the minimal-bfd +# hacks to work, they're also included here for now. +# gdb: elf.o +# objdump: elf.o +# +# Also, Jim Kingdon notes: +# Writing S-records should be included in all (or at least most) +# *-*-coff, *-*-aout, etc., configurations, because people will want to +# be able to use objcopy to create S-records. (S-records are not useful +# for the debugger, so if you are downloading things as S-records you +# need two copies of the executable, one to download and one for the +# debugger). +BFD_LIBS = \ + archive.o archures.o bfd.o cache.o coffgen.o corefile.o \ + format.o init.o libbfd.o opncls.o reloc.o \ + section.o syms.o targets.o hash.o linker.o \ + elf.o srec.o binary.o tekhex.o ihex.o stab-syms.o + +BFD_LIBS_CFILES = \ + archive.c archures.c bfd.c cache.c coffgen.c corefile.c \ + format.c init.c libbfd.c opncls.c reloc.c \ + section.c syms.c targets.c hash.c linker.c \ + elf.c srec.c binary.c tekhex.c ihex.c stab-syms.c + +# This list is alphabetized to make it easier to keep in sync +# with the decls and initializer in archures.c. +ALL_MACHINES = \ + cpu-a29k.o \ + cpu-alpha.o \ + cpu-arm.o \ + cpu-h8300.o \ + cpu-h8500.o \ + cpu-hppa.o \ + cpu-i386.o \ + cpu-i860.o \ + cpu-i960.o \ + cpu-m68k.o \ + cpu-m88k.o \ + cpu-mips.o \ + cpu-ns32k.o \ + cpu-powerpc.o \ + cpu-rs6000.o \ + cpu-sh.o \ + cpu-sparc.o \ + cpu-vax.o \ + cpu-we32k.o \ + cpu-w65.o \ + cpu-z8k.o + +ALL_MACHINES_CFILES = \ + cpu-a29k.c \ + cpu-alpha.c \ + cpu-arm.c \ + cpu-h8300.c \ + cpu-h8500.c \ + cpu-hppa.c \ + cpu-i386.c \ + cpu-i860.c \ + cpu-i960.c \ + cpu-m68k.c \ + cpu-m88k.c \ + cpu-mips.c \ + cpu-ns32k.c \ + cpu-powerpc.c \ + cpu-rs6000.c \ + cpu-sh.c \ + cpu-sparc.c \ + cpu-vax.c \ + cpu-we32k.c \ + cpu-w65.c \ + cpu-z8k.c + +# The .o files needed by all of the 32 bit vectors that are configured into +# target_vector in targets.c if configured with --enable-targets=all. +BFD32_BACKENDS = \ + aout-adobe.o \ + aout-ns32k.o \ + aout0.o \ + aout32.o \ + bout.o \ + cf-i386lynx.o \ + cf-m68klynx.o \ + cf-sparclynx.o \ + coff-a29k.o \ + coff-apollo.o \ + coff-arm.o \ + coff-aux.o \ + coff-h8300.o \ + coff-h8500.o \ + coff-i386.o \ + coff-go32.o \ + coff-i860.o \ + coff-i960.o \ + coff-m68k.o \ + coff-m88k.o \ + coff-mips.o \ + coff-pmac.o \ + coff-rs6000.o \ + coff-sh.o \ + coff-sparc.o \ + coff-u68k.o \ + coff-we32k.o \ + coff-w65.o \ + coff-z8k.o \ + cofflink.o \ + ecoff.o \ + ecofflink.o \ + elf32-gen.o \ + elf32-hppa.o \ + elf32-i386.o \ + elf32-i860.o \ + elf32-m68k.o \ + elf32-m88k.o \ + elf32-mips.o \ + elf32-ppc.o \ + elf32-sparc.o \ + elf32.o \ + elflink.o \ + hp300hpux.o \ + som.o \ + i386aout.o \ + i386bsd.o \ + i386freebsd.o \ + i386linux.o \ + i386lynx.o \ + i386msdos.o \ + i386netbsd.o \ + i386mach3.o \ + i386os9k.o \ + ieee.o \ + m68klinux.o \ + m68klynx.o \ + m68knetbsd.o \ + m88kmach3.o \ + mipsbsd.o \ + newsos3.o \ + nlm.o \ + nlm32-i386.o \ + nlm32-sparc.o \ + nlm32-ppc.o \ + nlm32.o \ + ns32knetbsd.o \ + oasys.o \ + pc532-mach.o \ + pe-arm.o \ + pei-arm.o \ + pe-i386.o \ + pei-i386.o \ + pe-ppc.o \ + pei-ppc.o \ + reloc16.o \ + sparclynx.o \ + sparcnetbsd.o \ + sunos.o \ + tekhex.o \ + versados.o \ + xcofflink.o + +BFD32_BACKENDS_CFILES = \ + aout-adobe.c \ + aout-ns32k.c \ + aout0.c \ + aout32.c \ + bout.c \ + cf-i386lynx.c \ + cf-m68klynx.c \ + cf-sparclynx.c \ + coff-a29k.c \ + coff-apollo.c \ + coff-arm.c \ + coff-aux.c \ + coff-h8300.c \ + coff-h8500.c \ + coff-i386.c \ + coff-i860.c \ + coff-go32.c \ + coff-i960.c \ + coff-m68k.c \ + coff-m88k.c \ + coff-mips.c \ + coff-pmac.c \ + coff-rs6000.c \ + coff-sh.c \ + coff-sparc.c \ + coff-u68k.c \ + coff-we32k.c \ + coff-w65.c \ + coff-z8k.c \ + cofflink.c \ + ecoff.c \ + ecofflink.c \ + elf32-gen.c \ + elf32-hppa.c \ + elf32-i386.c \ + elf32-i860.c \ + elf32-m68k.c \ + elf32-m88k.c \ + elf32-mips.c \ + elf32-ppc.c \ + elf32-sparc.c \ + elf32.c \ + elflink.c \ + hp300hpux.c \ + som.c \ + i386aout.c \ + i386bsd.c \ + i386freebsd.c \ + i386linux.c \ + i386lynx.c \ + i386msdos.c \ + i386netbsd.c \ + i386mach3.c \ + i386os9k.c \ + ieee.c \ + m68klinux.c \ + m68klynx.c \ + m68knetbsd.c \ + m88kmach3.c \ + mipsbsd.c \ + newsos3.c \ + nlm.c \ + nlm32-i386.c \ + nlm32-sparc.c \ + nlm32-ppc.c \ + nlm32.c \ + ns32knetbsd.c \ + oasys.c \ + pc532-mach.c \ + pe-arm.c \ + pei-arm.c \ + pe-i386.c \ + pei-i386.c \ + pe-ppc.c \ + pei-ppc.c \ + reloc16.c \ + sparclynx.c \ + sparcnetbsd.c \ + sunos.c \ + tekhex.c \ + versados.c \ + xcofflink.c + +# The .o files needed by all of the 64 bit vectors that are configured into +# target_vector in targets.c if configured with --enable-targets=all +# and --enable-64-bit-bfd. +BFD64_BACKENDS = \ + aout64.o \ + coff-alpha.o \ + demo64.o \ + elf64-gen.o \ + elf64-sparc.o \ + elf64.o \ + nlm32-alpha.o \ + nlm64.o + +BFD64_BACKENDS_CFILES = \ + aout64.c \ + coff-alpha.c \ + demo64.c \ + elf64-gen.c \ + elf64-sparc.c \ + elf64.c \ + nlm32-alpha.c \ + nlm64.c + +OPTIONAL_BACKENDS = \ + aix386-core.o \ + hpux-core.o \ + irix-core.o \ + lynx-core.o \ + osf-core.o \ + trad-core.o \ + cisco-core.o + +OPTIONAL_BACKENDS_CFILES = \ + aix386-core.c \ + hpux-core.c \ + irix-core.c \ + lynx-core.c \ + osf-core.c \ + trad-core.c \ + cisco-core.c + +# These are defined by configure.in: +WORDSIZE = @wordsize@ +ALL_BACKENDS = @all_backends@ +BFD_BACKENDS = @bfd_backends@ +BFD_MACHINES = @bfd_machines@ +TDEFAULTS = @tdefaults@ + +all: + +FLAGS_TO_PASS = \ + "prefix=$(prefix)" \ + "exec_prefix=$(exec_prefix)" \ + "against=$(against)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "MAKEINFO=$(MAKEINFO)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" + +ALL_CFLAGS=@HDEFINES@ @COREFLAG@ @TDEFINES@ $(CSEARCH) $(CSWITCHES) $(CFLAGS) +.c.o: + if [ -n "$(PICFLAG)" ]; then \ + $(CC) -c $(PICFLAG) $(ALL_CFLAGS) $< -o pic/$@; \ + else true; fi + $(CC) -c $(ALL_CFLAGS) $< + +bfd_libs_here = +all_machines_here = +bfd32_backends_here = +core_files_here = +configs_not_included_in_all_targets_option_here = + +# C source files that correspond to .o's. +CFILES = \ + $(BFD_LIBS_CFILES) \ + $(ALL_MACHINES_CFILES) \ + $(BFD32_BACKENDS_CFILES) \ + $(BFD64_BACKENDS_CFILES) \ + $(OPTIONAL_BACKENDS_CFILES) \ + i386dynix.c hp300bsd.c + +HFILES = aout-target.h aoutf1.h aoutx.h coffcode.h \ + coffswap.h ecoffswap.h elf32-hppa.h elf32-target.h elf64-target.h \ + elfcode.h hppa_stubs.h libaout.h libbfd.h \ + libcoff.h libecoff.h elf-bfd.h libhppa.h libieee.h libnlm.h \ + liboasys.h nlm-target.h nlmcode.h som.h genlink.h netbsd.h + +all: Makefile $(ALLLIBS) @PICLIST@ + @$(MAKE) subdir_do DO=all "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + +.NOEXPORT: +MAKEOVERRIDES= + +.PHONY: check installcheck +check: + @echo No testsuites exist for the BFD library. Nothing to check. + +installcheck: + @echo No testsuites exist for the BFD library. Nothing to check. + +info dvi : force + @$(MAKE) subdir_do DO=$@ "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + +clean-info: + @$(MAKE) subdir_do DO=clean-info "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + +install-info: force + @$(MAKE) subdir_do DO=install-info "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + +diststuff: info + +# Various kinds of .o files to put in libbfd.a: +# BFD_LIBS Generic routines, always needed. +# BFD_BACKENDS Routines the configured targets need. +# BFD_MACHINES Architecture-specific routines the configured targets need. +# COREFILE Core file routines for a native configuration +OFILES = $(BFD_LIBS) $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ + +stamp-ofiles: Makefile + rm -f tofiles + f=""; \ + for i in $(OFILES) ; do \ + case " $$f " in \ + *" $$i "*) ;; \ + *) f="$$f $$i" ;; \ + esac ; \ + done ; \ + echo $$f > tofiles + $(srcdir)/../move-if-change tofiles ofiles + touch stamp-ofiles + +ofiles: stamp-ofiles ; @true + +$(TARGETLIB): $(OFILES) ofiles + rm -f $(TARGETLIB) + @echo ofiles = `cat ofiles` + $(AR) $(AR_FLAGS) $(TARGETLIB) `cat ofiles` + $(RANLIB) $(TARGETLIB) + +stamp-piclist: ofiles + rm -f tpiclist + if [ -n "$(PICFLAG)" ]; then \ + sed -e 's,\([^ ][^ ]*\),pic/\1,g' ofiles > tpiclist; \ + else \ + cp ofiles tpiclist; \ + fi + $(srcdir)/../move-if-change tpiclist piclist + touch stamp-piclist + +piclist: stamp-piclist ; @true + +$(SHLIB): stamp-picdir $(OFILES) piclist + rm -f $(SHLIB) + $(SHLIB_CC) $(SHLIB_CFLAGS) -o $(SHLIB) `cat piclist` + +# We make a link from libbfd.so to libbfd.so.VERSION for linking, and +# also a link from libTARGET-bfd.so.VERSION for running. +$(SHLINK): $(SHLIB) + ts=lib`echo $(SHLIB) | sed -e 's/^lib//' | sed -e '$(program_transform_name)'`; \ + if [ "$$ts" != "$(SHLIB)" ]; then \ + rm -f $$ts; \ + ln -sf $(SHLIB) $$ts; \ + else true; fi + rm -f $(SHLINK) + ln -sf $(SHLIB) $(SHLINK) + +# This target creates libTARGET-bfd.so.VERSION as a symlink to +# libbfd.so.VERSION. It is used on SunOS, which does not have SONAME. +stamp-tshlink: $(SHLIB) + tf=lib`echo $(SHLIB) | sed -e 's/^lib//' | sed '$(program_transform_name)'`; \ + if [ "$$tf" != "$(SHLIB)" ]; then \ + rm -f $$tf; \ + ln -sf $(SHLIB) $$tf; \ + else true; fi + touch stamp-tshlink + +# When compiling archures.c and targets.c, supply the default target +# info from configure. + +targets.o: targets.c Makefile + if [ -n "$(PICFLAG)" ]; then \ + $(CC) -c $(PICFLAG) $(TDEFAULTS) $(ALL_CFLAGS) $(srcdir)/targets.c -o pic/targets.o; \ + else true; fi + $(CC) -c $(TDEFAULTS) $(ALL_CFLAGS) $(srcdir)/targets.c + +archures.o: archures.c Makefile + if [ -n "$(PICFLAG)" ]; then \ + $(CC) -c $(PICFLAG) $(TDEFAULTS) $(ALL_CFLAGS) $(srcdir)/archures.c -o pic/archures.o; \ + else true; fi + $(CC) -c $(TDEFAULTS) $(ALL_CFLAGS) $(srcdir)/archures.c + +elf32-target.h : elfxx-target.h + rm -f elf32-target.h + sed -e s/NN/32/g < $(srcdir)/elfxx-target.h > elf32-target.new + mv -f elf32-target.new elf32-target.h + +elf64-target.h : elfxx-target.h + rm -f elf64-target.h + sed -e s/NN/64/g < $(srcdir)/elfxx-target.h > elf64-target.new + mv -f elf64-target.new elf64-target.h + +subdir_do: force + @for i in $(DODIRS); do \ + if [ -d ./$$i ] ; then \ + if (cd ./$$i; \ + $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \ + else exit 1 ; fi ; \ + else true ; fi ; \ + done + +tags etags: TAGS + +TAGS: force + etags $(INCDIR)/*.h $(srcdir)/*.h $(srcdir)/*.c + +do_mostlyclean: + rm -f *.o *~ core *.E *.p *.ip aout-params.h gen-aout config.log \ + pic/*.o +do_clean: do_mostlyclean + rm -f libbfd.a TAGS bfd.h stmp-bfd.h ofiles stamp-ofiles \ + elf32-target.h elf64-target.h $(SHLIB) $(SHLINK) \ + piclist stamp-piclist +do_distclean: do_clean + rm -f Makefile config.status config.cache config.h stamp-h + rm -rf pic stamp-picdir +do_maintainer_clean: do_distclean + rm -f $(srcdir)/bfd-in2.h $(srcdir)/libbfd.h $(srcdir)/libcoff.h + +mostlyclean: do_mostlyclean + $(MAKE) subdir_do DO=mostlyclean "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) +clean: do_clean + $(MAKE) subdir_do DO=clean "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) +distclean: + $(MAKE) subdir_do DO=distclean "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + $(MAKE) do_distclean +clobber maintainer-clean realclean: + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + $(MAKE) subdir_do DO=maintainer-clean "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) + $(MAKE) do_maintainer_clean + +BFD_H_DEPS= $(INCDIR)/ansidecl.h $(INCDIR)/obstack.h +LOCAL_H_DEPS= libbfd.h sysdep.h config.h +$(BFD_LIBS): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS) +$(BFD_MACHINES): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS) +$(BFD_BACKENDS): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS) +$(OPTIONAL_BACKENDS): $(BFD_H) $(BFD_H_DEPS) $(LOCAL_H_DEPS) + +# Get around a Sun Make bug in SunOS 4.1.1 with VPATH +cpu-i386.o:cpu-i386.c +cpu-z8k.o: cpu-z8k.c +cpu-h8500.o: cpu-h8500.c +cpu-we32k.o: cpu-we32k.c + +saber: + #suppress 65 on bfd_map_over_sections + #suppress 66 on bfd_map_over_sections + #suppress 67 on bfd_map_over_sections + #suppress 68 on bfd_map_over_sections + #suppress 69 on bfd_map_over_sections + #suppress 70 on bfd_map_over_sections + #suppress 110 in bfd_map_over_sections + #suppress 112 in bfd_map_over_sections + #suppress 530 + #suppress 590 in swap_exec_header + #suppress 590 in _bfd_dummy_core_file_matches_executable_p + #suppress 590 in bfd_dont_truncate_arname + #suppress 590 on ignore + #suppress 590 on abfd + #setopt load_flags $(CFLAGS) + #load $(CFILES) + + +#----------------------------------------------------------------------------- +# 'STANDARD' GNU/960 TARGETS BELOW THIS POINT +# +# 'VERSION' file must be present and contain a string of the form "x.y" +#----------------------------------------------------------------------------- + +ver960.c: FORCE + rm -f ver960.c + echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c + + +# This target should be invoked before building a new release. +# 'VERSION' file must be present and contain a string of the form "x.y" +# +roll: + @V=`cat VERSION` ; \ + MAJ=`sed 's/\..*//' VERSION` ; \ + MIN=`sed 's/.*\.//' VERSION` ; \ + V=$$MAJ.`expr $$MIN + 1` ; \ + rm -f VERSION ; \ + echo $$V >VERSION ; \ + echo Version $$V + +# Dummy target to force execution of dependent targets. +# +force: + +install: $(ALLLIBS) + for f in $(ALLLIBS); do \ + if [ "$$f" = "stamp-tshlink" ]; then \ + continue; \ + fi; \ + tf=lib`echo $$f | sed -e 's/^lib//' | sed '$(program_transform_name)'`; \ + rm -f $(libdir)/$$tf; \ + if [ "$$f" = "$(SHLINK)" ]; then \ + ts=lib`echo $(SHLIB) | sed -e 's/^lib//' | sed '$(program_transform_name)'`; \ + ln -sf $$ts $(libdir)/$$tf; \ + elif [ "$$f" = "$(SHLIB)" ]; then \ + $(INSTALL_PROGRAM) $$f $(libdir)/$$tf; \ + else \ + $(INSTALL_DATA) $$f $(libdir)/$$tf; \ + $(RANLIB) $(libdir)/$$tf; \ + chmod a-x $(libdir)/$$tf; \ + fi; \ + done +# Install BFD include file, and others that it needs. Install them +# both in GCC's include directory, and in the system include dir +# if configured as $(oldincludedir) -- which it usually isnt. + $(INSTALL_DATA) $(BFD_H) $(includedir)/bfd.h + $(INSTALL_DATA) $(INCDIR)/ansidecl.h $(includedir)/ansidecl.h + $(INSTALL_DATA) $(INCDIR)/bfdlink.h $(includedir)/bfdlink.h + $(INSTALL_DATA) $(INCDIR)/obstack.h $(includedir)/obstack.h + -if test -z "$(oldincludedir)"; then true; else \ + test -d $(oldincludedir) || mkdir $(oldincludedir); \ + $(INSTALL_DATA) $(BFD_H) $(oldincludedir)/bfd.h; \ + $(INSTALL_DATA) $(INCDIR)/ansidecl.h $(oldincludedir)/ansidecl.h; \ + $(INSTALL_DATA) $(INCDIR)/bfdlink.h $(oldincludedir)/bfdlink.h; \ + $(INSTALL_DATA) $(INCDIR)/obstack.h $(oldincludedir)/obstack.h; \ + $(MAKE) subdir_do DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS); \ + fi + +Makefile: Makefile.in config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status + +config.status: configure configure.host config.bfd + $(SHELL) config.status --recheck + +# Have to get rid of .dep1 here so that "$?" later includes all of $(CFILES). +.dep: dep.sed $(CFILES) $(HFILES) bfd.h + rm -f .dep1 + $(MAKE) DEP=$(DEP) .dep1 + sed -f dep.sed <.dep1 >.dep + +# This rule really wants a mkdep that runs "gcc -MM". +# The NetBSD mkdep overwrites any existing file contents, and doesn't insert +# the "DO NOT DELETE" line. +# Other mkdep versions require a file that already exists, and do insert it. +# Hence the weirdness.... +.dep1: $(CFILES) + rm -f .dep2 .dep2a + echo '# DO NOT DELETE THIS LINE -- mkdep uses it.' > .dep2 + echo > .dep2a + $(DEP) -f .dep2a $(ALL_CFLAGS) $? + sed -e '/DO NOT DELETE/d' -e '/^$$/d' < .dep2a >> .dep2 + rm -f .dep2a + $(srcdir)/../move-if-change .dep2 .dep1 + +dep.sed: dep-in.sed config.status + sed <$(srcdir)/dep-in.sed >dep.sed \ + -e 's!@BFD_H@!$(BFD_H)!' \ + -e 's!@INCDIR@!$(INCDIR)!' \ + -e 's!@SRCDIR@!$(srcdir)!' + +dep: .dep + sed -e '/^..DO NOT DELETE THIS LINE/,$$d' < Makefile > tmp-Makefile + cat .dep >> tmp-Makefile + $(srcdir)/../move-if-change tmp-Makefile Makefile + +dep-in: .dep + sed -e '/^..DO NOT DELETE THIS LINE/,$$d' < $(srcdir)/Makefile.in > tmp-Makefile.in + cat .dep >> tmp-Makefile.in + $(srcdir)/../move-if-change tmp-Makefile.in $(srcdir)/Makefile.in + +host-aout.o: Makefile + +# The following program can be used to generate a simple config file +# which can be folded into an h-XXX file for a new host, with some editing. +aout-params.h: gen-aout + ./gen-aout host > aout-params.h +gen-aout: $(srcdir)/gen-aout.c Makefile + $(CC) -o gen-aout $(CFLAGS) $(LFLAGS) $(srcdir)/gen-aout.c + +BFDIN_H= $(srcdir)/bfd-in2.h + +$(BFD_H): stmp-bfd.h ; @true + +stmp-bfd.h : $(srcdir)/bfd-in2.h Makefile + rm -f bfd.h-new + sed -e 's/@WORDSIZE@/$(WORDSIZE)/' \ + -e "s/@VERSION@/`cat $(srcdir)/VERSION`/" \ + -e 's/@BFD_HOST_64BIT_LONG@/@HOST_64BIT_LONG@/' \ + < $(srcdir)/bfd-in2.h \ + > bfd.h-new + $(srcdir)/../move-if-change bfd.h-new $(BFD_H) + touch stmp-bfd.h + +# Could really use a "copy-if-change"... +headers: + (cd $(docdir); $(MAKE) protos $(FLAGS_TO_PASS)) + cp $(docdir)/bfd.h bfd-in2.h-new + $(srcdir)/../move-if-change bfd-in2.h-new $(srcdir)/bfd-in2.h + cp $(docdir)/libbfd.h libbfd.h-new + $(srcdir)/../move-if-change libbfd.h-new $(srcdir)/libbfd.h + cp $(docdir)/libcoff.h libcoff.h-new + $(srcdir)/../move-if-change libcoff.h-new $(srcdir)/libcoff.h + +# The rules for the generated header files are here so that people can +# type `make bfd-in2.h' if they remove it. They are not run by default. +$(srcdir)/bfd-in2.h: + (cd $(docdir); $(MAKE) bfd.h $(FLAGS_TO_PASS)) + cp $(docdir)/bfd.h bfd-in2.h-new + $(srcdir)/../move-if-change bfd-in2.h-new $(srcdir)/bfd-in2.h +$(srcdir)/libbfd.h: + (cd $(docdir); $(MAKE) libbfd.h $(FLAGS_TO_PASS)) + cp $(docdir)/libbfd.h libbfd.h-new + $(srcdir)/../move-if-change libbfd.h-new $(srcdir)/libbfd.h +$(srcdir)/libcoff.h: + (cd $(docdir); $(MAKE) libcoff.h $(FLAGS_TO_PASS)) + cp $(docdir)/libcoff.h libcoff.h-new + $(srcdir)/../move-if-change libcoff.h-new $(srcdir)/libcoff.h + +bfd.info: + (cd $(docdir); $(MAKE) bfd.info $(FLAGS_TO_PASS)) + +bfd.dvi: + (cd $(docdir); $(MAKE) bfd.dvi $(FLAGS_TO_PASS)) + +bfd.ps: + (cd $(docdir); $(MAKE) bfd.ps $(FLAGS_TO_PASS)) + + +$(OFILES): stamp-picdir + +stamp-picdir: + if [ -n "$(PICFLAG)" ] && [ ! -d pic ]; then \ + mkdir pic; \ + else true; fi + touch stamp-picdir + +# What appears below is generated by a hacked mkdep using gcc -MM. + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. +archive.o: archive.c $(INCDIR)/aout/ar.h $(INCDIR)/aout/ranlib.h +archures.o: archures.c +bfd.o: bfd.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/sym.h libcoff.h libecoff.h $(INCDIR)/coff/ecoff.h \ + elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h +cache.o: cache.c +coffgen.o: coffgen.c $(INCDIR)/coff/internal.h libcoff.h \ + $(INCDIR)/bfdlink.h +corefile.o: corefile.c +format.o: format.c +init.o: init.c +libbfd.o: libbfd.c +opncls.o: opncls.c +reloc.o: reloc.c $(INCDIR)/bfdlink.h +section.o: section.c +syms.o: syms.c $(INCDIR)/bfdlink.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def +targets.o: targets.c +hash.o: hash.c +linker.o: linker.c $(INCDIR)/bfdlink.h genlink.h +elf.o: elf.c $(INCDIR)/bfdlink.h elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h +srec.o: srec.c $(INCDIR)/libiberty.h +binary.o: binary.c +tekhex.o: tekhex.c $(INCDIR)/libiberty.h +ihex.o: ihex.c $(INCDIR)/libiberty.h +stab-syms.o: stab-syms.c libaout.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab.def +cpu-a29k.o: cpu-a29k.c +cpu-alpha.o: cpu-alpha.c +cpu-arm.o: cpu-arm.c +cpu-h8300.o: cpu-h8300.c +cpu-h8500.o: cpu-h8500.c +cpu-hppa.o: cpu-hppa.c +cpu-i386.o: cpu-i386.c +cpu-i860.o: cpu-i860.c +cpu-i960.o: cpu-i960.c +cpu-m68k.o: cpu-m68k.c +cpu-m88k.o: cpu-m88k.c +cpu-mips.o: cpu-mips.c +cpu-ns32k.o: cpu-ns32k.c +cpu-powerpc.o: cpu-powerpc.c +cpu-rs6000.o: cpu-rs6000.c +cpu-sh.o: cpu-sh.c +cpu-sparc.o: cpu-sparc.c +cpu-vax.o: cpu-vax.c +cpu-we32k.o: cpu-we32k.c +cpu-w65.o: cpu-w65.c +cpu-z8k.o: cpu-z8k.c +aout-adobe.o: aout-adobe.c $(INCDIR)/aout/adobe.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def libaout.h $(INCDIR)/bfdlink.h +aout-ns32k.o: aout-ns32k.c $(INCDIR)/aout/aout64.h \ + libaout.h $(INCDIR)/bfdlink.h +aout0.o: aout0.c aoutf1.h $(INCDIR)/aout/sun4.h libaout.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h aout-target.h +aout32.o: aout32.c aoutx.h $(INCDIR)/bfdlink.h libaout.h \ + $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def \ + $(INCDIR)/aout/ar.h +bout.o: bout.c $(INCDIR)/bfdlink.h genlink.h $(INCDIR)/bout.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def libaout.h +cf-i386lynx.o: cf-i386lynx.c coff-i386.c $(INCDIR)/coff/i386.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +cf-m68klynx.o: cf-m68klynx.c coff-m68k.c $(INCDIR)/coff/m68k.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +cf-sparclynx.o: cf-sparclynx.c coff-sparc.c $(INCDIR)/coff/sparc.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-a29k.o: coff-a29k.c $(INCDIR)/coff/a29k.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-apollo.o: coff-apollo.c $(INCDIR)/coff/apollo.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-arm.o: coff-arm.c $(INCDIR)/coff/arm.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-aux.o: coff-aux.c $(INCDIR)/coff/aux-coff.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/m68k.h coff-m68k.c libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-h8300.o: coff-h8300.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/h8300.h \ + $(INCDIR)/coff/internal.h libcoff.h coffcode.h coffswap.h +coff-h8500.o: coff-h8500.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/h8500.h \ + $(INCDIR)/coff/internal.h libcoff.h coffcode.h coffswap.h +coff-i386.o: coff-i386.c $(INCDIR)/coff/i386.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-i860.o: coff-i860.c $(INCDIR)/coff/i860.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-go32.o: coff-go32.c coff-i386.c $(INCDIR)/coff/i386.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-i960.o: coff-i960.c $(INCDIR)/coff/i960.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-m68k.o: coff-m68k.c $(INCDIR)/coff/m68k.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-m88k.o: coff-m88k.c $(INCDIR)/coff/m88k.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-mips.o: coff-mips.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/sym.h $(INCDIR)/coff/symconst.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/coff/mips.h libcoff.h libecoff.h coffswap.h \ + ecoffswap.h +coff-pmac.o: coff-pmac.c coff-rs6000.c $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/rs6000.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-rs6000.o: coff-rs6000.c $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/rs6000.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-sh.o: coff-sh.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/sh.h \ + $(INCDIR)/coff/internal.h libcoff.h coffcode.h coffswap.h +coff-sparc.o: coff-sparc.c $(INCDIR)/coff/sparc.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-u68k.o: coff-u68k.c coff-m68k.c $(INCDIR)/coff/m68k.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ + coffcode.h coffswap.h +coff-we32k.o: coff-we32k.c $(INCDIR)/coff/we32k.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-w65.o: coff-w65.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/w65.h \ + $(INCDIR)/coff/internal.h libcoff.h coffcode.h coffswap.h +coff-z8k.o: coff-z8k.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/z8k.h \ + $(INCDIR)/coff/internal.h libcoff.h coffcode.h coffswap.h +cofflink.o: cofflink.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ + libcoff.h +ecoff.o: ecoff.c $(INCDIR)/bfdlink.h $(INCDIR)/aout/ar.h \ + $(INCDIR)/aout/ranlib.h $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def \ + libaout.h $(INCDIR)/aout/aout64.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/sym.h $(INCDIR)/coff/symconst.h $(INCDIR)/coff/ecoff.h \ + libcoff.h libecoff.h +ecofflink.o: ecofflink.c $(INCDIR)/bfdlink.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/coff/internal.h $(INCDIR)/coff/sym.h \ + $(INCDIR)/coff/symconst.h $(INCDIR)/coff/ecoff.h +elf32-gen.o: elf32-gen.c elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ + elf32-target.h +elf32-hppa.o: elf32-hppa.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + elf32-hppa.h libhppa.h $(INCDIR)/elf/hppa.h hppa_stubs.h \ + elf32-target.h +elf32-i386.o: elf32-i386.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + elf32-target.h +elf32-i860.o: elf32-i860.c elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ + elf32-target.h +elf32-m68k.o: elf32-m68k.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + elf32-target.h +elf32-m88k.o: elf32-m88k.c elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ + elf32-target.h +elf32-mips.o: elf32-mips.c $(INCDIR)/bfdlink.h genlink.h \ + elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/elf/mips.h $(INCDIR)/coff/sym.h \ + $(INCDIR)/coff/symconst.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/ecoff.h $(INCDIR)/coff/mips.h ecoffswap.h \ + elf32-target.h +elf32-ppc.o: elf32-ppc.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/elf/ppc.h elf32-target.h +elf32-sparc.o: elf32-sparc.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/elf/sparc.h elf32-target.h +elf32.o: elf32.c elfcode.h $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + elfcore.h elflink.h +elflink.o: elflink.c $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h +hp300hpux.o: hp300hpux.c $(INCDIR)/aout/hp300hpux.h \ + aoutx.h $(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h \ + aout-target.h +som.o: som.c +i386aout.o: i386aout.c libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +i386bsd.o: i386bsd.c libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +i386freebsd.o: i386freebsd.c freebsd.h libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +i386linux.o: i386linux.c $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h libaout.h \ + $(INCDIR)/bfdlink.h aout-target.h +i386lynx.o: i386lynx.c libaout.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/aout/aout64.h aout-target.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +i386msdos.o: i386msdos.c libaout.h $(INCDIR)/bfdlink.h +i386netbsd.o: i386netbsd.c netbsd.h libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +i386mach3.o: i386mach3.c $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h libaout.h \ + $(INCDIR)/bfdlink.h aout-target.h +i386os9k.o: i386os9k.c $(INCDIR)/bfdlink.h libaout.h \ + $(INCDIR)/os9k.h +ieee.o: ieee.c $(INCDIR)/ieee.h libieee.h +m68klinux.o: m68klinux.c $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h libaout.h \ + $(INCDIR)/bfdlink.h aout-target.h +m68klynx.o: m68klynx.c libaout.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/aout/aout64.h aout-target.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +m68knetbsd.o: m68knetbsd.c netbsd.h libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +m88kmach3.o: m88kmach3.c libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +mipsbsd.o: mipsbsd.c libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +newsos3.o: newsos3.c $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h libaout.h \ + $(INCDIR)/bfdlink.h aout-target.h +nlm.o: nlm.c libnlm.h $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h \ + $(INCDIR)/nlm/external.h +nlm32-i386.o: nlm32-i386.c $(INCDIR)/nlm/i386-ext.h \ + libnlm.h $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h \ + $(INCDIR)/nlm/external.h nlmswap.h nlm-target.h +nlm32-sparc.o: nlm32-sparc.c $(INCDIR)/nlm/sparc32-ext.h \ + libnlm.h $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h \ + $(INCDIR)/nlm/external.h nlmswap.h nlm-target.h +nlm32-ppc.o: nlm32-ppc.c $(INCDIR)/nlm/ppc-ext.h libnlm.h \ + $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h $(INCDIR)/nlm/external.h \ + nlmswap.h nlm-target.h +nlm32.o: nlm32.c nlmcode.h libnlm.h $(INCDIR)/nlm/common.h \ + $(INCDIR)/nlm/internal.h $(INCDIR)/nlm/external.h +ns32knetbsd.o: ns32knetbsd.c netbsd.h libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +oasys.o: oasys.c $(INCDIR)/oasys.h liboasys.h +pc532-mach.o: pc532-mach.c libaout.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/aout/aout64.h aout-target.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +pe-arm.o: pe-arm.c coff-arm.c $(INCDIR)/coff/arm.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +pei-arm.o: pei-arm.c coff-arm.c $(INCDIR)/coff/arm.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +pe-i386.o: pe-i386.c coff-i386.c $(INCDIR)/coff/i386.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +pei-i386.o: pei-i386.c coff-i386.c $(INCDIR)/coff/i386.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +pe-ppc.o: pe-ppc.c coff-ppc.c $(INCDIR)/coff/powerpc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +pei-ppc.o: pei-ppc.c coff-ppc.c $(INCDIR)/coff/powerpc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/pe.h libcoff.h \ + $(INCDIR)/bfdlink.h coffcode.h peicode.h +reloc16.o: reloc16.c $(INCDIR)/bfdlink.h genlink.h \ + $(INCDIR)/coff/internal.h libcoff.h +sparclynx.o: sparclynx.c $(INCDIR)/aout/sun4.h libaout.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h aout-target.h +sparcnetbsd.o: sparcnetbsd.c netbsd.h libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +sunos.o: sunos.c $(INCDIR)/bfdlink.h libaout.h aoutf1.h \ + $(INCDIR)/aout/sun4.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h aout-target.h +versados.o: versados.c $(INCDIR)/libiberty.h +xcofflink.o: xcofflink.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ + libcoff.h +aout64.o: aout64.c aoutx.h $(INCDIR)/bfdlink.h libaout.h \ + $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def \ + $(INCDIR)/aout/ar.h +coff-alpha.o: coff-alpha.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/sym.h $(INCDIR)/coff/symconst.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/coff/alpha.h $(INCDIR)/aout/ar.h libcoff.h \ + libecoff.h coffswap.h ecoffswap.h +demo64.o: demo64.c aoutf1.h $(INCDIR)/aout/sun4.h libaout.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h aout-target.h +elf64-gen.o: elf64-gen.c elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ + elf64-target.h +elf64-sparc.o: elf64-sparc.c elf-bfd.h $(INCDIR)/elf/common.h \ + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/elf/sparc.h elf64-target.h +elf64.o: elf64.c elfcode.h $(INCDIR)/bfdlink.h elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + elfcore.h elflink.h +nlm32-alpha.o: nlm32-alpha.c $(INCDIR)/nlm/alpha-ext.h \ + libnlm.h $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h \ + $(INCDIR)/nlm/external.h nlmswap.h nlm-target.h +nlm64.o: nlm64.c nlmcode.h libnlm.h $(INCDIR)/nlm/common.h \ + $(INCDIR)/nlm/internal.h $(INCDIR)/nlm/external.h +aix386-core.o: aix386-core.c $(INCDIR)/coff/i386.h \ + $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h +hpux-core.o: hpux-core.c +irix-core.o: irix-core.c +lynx-core.o: lynx-core.c +osf-core.o: osf-core.c +trad-core.o: trad-core.c libaout.h $(INCDIR)/bfdlink.h +cisco-core.o: cisco-core.c +i386dynix.o: i386dynix.c $(INCDIR)/aout/dynix3.h aoutx.h \ + $(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h \ + aout-target.h +hp300bsd.o: hp300bsd.c libaout.h $(INCDIR)/bfdlink.h \ + aout-target.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/contrib/gdb/bfd/PORTING b/contrib/gdb/bfd/PORTING new file mode 100644 index 000000000000..c8bfd77b96ff --- /dev/null +++ b/contrib/gdb/bfd/PORTING @@ -0,0 +1,83 @@ + Preliminary Notes on Porting BFD + -------------------------------- + +The 'host' is the system a tool runs *on*. +The 'target' is the system a tool runs *for*, i.e. +a tool can read/write the binaries of the target. + +Porting to a new host +--------------------- +Pick a name for your host. Call that . +( might be sun4, ...) +Create a file hosts/.mh. + +Porting to a new target +----------------------- +Pick a name for your target. Call that . +Call the name for your CPU architecture . +You need to create .c and config/.mt, +and add a case for it to a case statements in bfd/configure.host and +bfd/config.bfd, which associates each canonical host type with a BFD +host type (used as the base of the makefile fragment names), and to the +table in bfd/configure.in which associates each target vector with +the .o files it uses. + +config/.mt is a Makefile fragment. +The following is usually enough: +DEFAULT_VECTOR=_vec +SELECT_ARCHITECTURES=bfd__arch + +See the list of cpu types in archures.c, or "ls cpu-*.c". +If your architecture is new, you need to add it to the tables +in bfd/archures.c, opcodes/configure.in, and binutils/objdump.c. + +For more information about .mt and .mh files, see config/README. + +The file .c is the hard part. It implements the +bfd_target _vec, which includes pointers to +functions that do the actual -specific methods. + +Porting to a that uses the a.out binary format +------------------------------------------------------- + +In this case, the include file aout-target.h probaby does most +of what you need. The program gen-aout generates .c for +you automatically for many a.out systems. Do: + make gen-aout + ./gen-aout > .c +(This only works if you are building on the target ("native"). +If you must make a cross-port from scratch, copy the most +similar existing file that includes aout-target.h, and fix what is wrong.) + +Check the parameters in .c, and fix anything that is wrong. +(Also let us know about it; perhaps we can improve gen-aout.c.) + +TARGET_IS_BIG_ENDIAN_P + Should be defined if is big-endian. + +N_HEADER_IN_TEXT(x) + See discussion in ../include/aout/aout64.h. + +BYTES_IN_WORD + Number of bytes per word. (Usually 4 but can be 8.) + +ARCH + Number of bits per word. (Usually 32, but can be 64.) + +ENTRY_CAN_BE_ZERO + Define if the extry point (start address of an + executable program) can be 0x0. + +TEXT_START_ADDR + The address of the start of the text segemnt in + virtual memory. Normally, the same as the entry point. + +TARGET_PAGE_SIZE + +SEGMENT_SIZE + Usually, the same as the TARGET_PAGE_SIZE. + Alignment needed for the data segment. + +TARGETNAME + The name of the target, for run-time lookups. + Usually "a.out-" diff --git a/contrib/gdb/bfd/TODO b/contrib/gdb/bfd/TODO new file mode 100644 index 000000000000..08a3641b1ade --- /dev/null +++ b/contrib/gdb/bfd/TODO @@ -0,0 +1,25 @@ +Things that still need to be done: -*- Text -*- + + o - A source of space lossage is that all the target-dependent code + is in a single bfd_target structure. Hence all the code for + *writing* object files is still pulled into all the applications + that only care about *reading* (gdb, nm, objdump), while gas has + to carry along all the unneded baggage for reading objects. And + so on. This would be a substantial change, and the payoff would + not all that great (essentially none if bfd is used as a shared + library). + + o - The storage needed by BFD data structures is also larger than strictly + needed. This may be difficult to do much about. + + o - implement bfd_abort, which should close the bfd but not alter the + filesystem. + + o - update the bfd doc; write a how-to-write-a-backend doc, take out + the stupid quips and fill in all the blanks. + + o - upgrade the reloc handling as per Steve's suggestion. + + + + diff --git a/contrib/gdb/bfd/VERSION b/contrib/gdb/bfd/VERSION new file mode 100644 index 000000000000..9ddf6b5ad1a6 --- /dev/null +++ b/contrib/gdb/bfd/VERSION @@ -0,0 +1 @@ +cygnus-2.6 diff --git a/contrib/gdb/bfd/acconfig.h b/contrib/gdb/bfd/acconfig.h new file mode 100644 index 000000000000..647798cbe9f0 --- /dev/null +++ b/contrib/gdb/bfd/acconfig.h @@ -0,0 +1,19 @@ + +/* Whether malloc must be declared even if is included. */ +#undef NEED_DECLARATION_MALLOC + +/* Whether free must be declared even if is included. */ +#undef NEED_DECLARATION_FREE +@TOP@ + +/* Do we need to use the b modifier when opening binary files? */ +#undef USE_BINARY_FOPEN + +/* Name of host specific header file to include in trad-core.c. */ +#undef TRAD_HEADER + +/* Define only if is available *and* it defines prstatus_t. */ +#undef HAVE_SYS_PROCFS_H + +/* Do we really want to use mmap if it's available? */ +#undef USE_MMAP diff --git a/contrib/gdb/bfd/aclocal.m4 b/contrib/gdb/bfd/aclocal.m4 new file mode 100644 index 000000000000..1f5027e48589 --- /dev/null +++ b/contrib/gdb/bfd/aclocal.m4 @@ -0,0 +1,43 @@ +dnl See whether we need to use fopen-bin.h rather than fopen-same.h. +AC_DEFUN(BFD_BINARY_FOPEN, +[AC_REQUIRE([AC_CANONICAL_SYSTEM]) +case "${host}" in +changequote(,)dnl +i[345]86-*-msdos* | i[345]86-*-go32* | *-*-cygwin32) +changequote([,])dnl + AC_DEFINE(USE_BINARY_FOPEN) ;; +esac])dnl + +dnl Get a default for CC_FOR_BUILD to put into Makefile. +AC_DEFUN(BFD_CC_FOR_BUILD, +[# Put a plausible default for CC_FOR_BUILD in Makefile. +AC_REQUIRE([AC_C_CROSS])dnl +if test -z "$CC_FOR_BUILD"; then + if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' + else + CC_FOR_BUILD=gcc + fi +fi +AC_SUBST(CC_FOR_BUILD)])dnl + +dnl See whether we need a declaration for a function. +AC_DEFUN(BFD_NEED_DECLARATION, +[AC_MSG_CHECKING([whether $1 must be declared]) +AC_CACHE_VAL(bfd_cv_decl_needed_$1, +[AC_TRY_COMPILE([ +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif], +[char *(*pfn) = (char *(*)) $1], +bfd_cv_decl_needed_$1=no, bfd_cv_decl_needed_$1=yes)]) +AC_MSG_RESULT($bfd_cv_decl_needed_$1) +if test $bfd_cv_decl_needed_$1 = yes; then + bfd_tr_decl=NEED_DECLARATION_`echo $1 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + AC_DEFINE_UNQUOTED($bfd_tr_decl) +fi +])dnl diff --git a/contrib/gdb/bfd/aix386-core.c b/contrib/gdb/bfd/aix386-core.c new file mode 100644 index 000000000000..21ec9a6d4313 --- /dev/null +++ b/contrib/gdb/bfd/aix386-core.c @@ -0,0 +1,285 @@ +/* BFD back-end for AIX on PS/2 core files. + This was based on trad-core.c, which was written by John Gilmore of + Cygnus Support. + Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Minh Tran-Le . + Converted to back end form by Ian Lance Taylor . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/i386.h" +#include "coff/internal.h" +#include "libcoff.h" + +#include +#include +#include + +#include + +#if defined (_AIX) && defined (_I386) +#define NOCHECKS /* this is for coredump.h */ +#define _h_USER /* avoid including user.h from coredump.h */ +#include +#include +#endif /* _AIX && _I386 */ + +/* maybe this could work on some other i386 but I have not tried it + * mtranle@paris - Tue Sep 24 12:49:35 1991 + */ + +#ifndef COR_MAGIC +# define COR_MAGIC "core" +#endif + +/* need this cast because ptr is really void * */ +#define core_hdr(bfd) \ + (((bfd->tdata.trad_core_data))->hdr) +#define core_section(bfd,n) \ + (((bfd)->tdata.trad_core_data)->sections[n]) +#define core_regsec(bfd) \ + (((bfd)->tdata.trad_core_data)->reg_section) +#define core_reg2sec(bfd) \ + (((bfd)->tdata.trad_core_data)->reg2_section) + +/* These are stored in the bfd's tdata */ +struct trad_core_struct { + struct corehdr *hdr; /* core file header */ + asection *reg_section; + asection *reg2_section; + asection *sections[MAX_CORE_SEGS]; +}; + +static const bfd_target * +aix386_core_file_p (abfd) + bfd *abfd; +{ + int i,n; + unsigned char longbuf[4]; /* Raw bytes of various header fields */ + int core_size = sizeof (struct corehdr); + struct corehdr *core; + struct mergem { + struct trad_core_struct coredata; + struct corehdr internal_core; + } *mergem; + + if (bfd_read ((PTR)longbuf, 1, sizeof (longbuf), abfd) != sizeof (longbuf)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if (strncmp(longbuf,COR_MAGIC,4)) return 0; + + if (bfd_seek (abfd, 0L, false) < 0) return 0; + + mergem = (struct mergem *)bfd_zalloc (abfd, sizeof (struct mergem)); + if (mergem == NULL) + return 0; + + core = &mergem->internal_core; + + if ((bfd_read ((PTR) core, 1, core_size, abfd)) != core_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + bfd_release (abfd, (char *)mergem); + return 0; + } + + set_tdata (abfd, &mergem->coredata); + core_hdr (abfd) = core; + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_regsec (abfd) == NULL) + { + loser: + bfd_release (abfd, (char *)mergem); + return 0; + } + core_reg2sec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_reg2sec (abfd) == NULL) + { + loser1: + bfd_release (abfd, core_regsec (abfd)); + goto loser; + } + + for (i=0, n=0 ; (i < MAX_CORE_SEGS) && (core->cd_segs[i].cs_type) ; i++) + { + if (core->cd_segs[i].cs_offset == 0) + continue; + core_section (abfd,n) = + (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_section (abfd,n) == NULL) + { + int j; + if (n > 0) + { + for (j=0; j < n; j++) + bfd_release (abfd, core_section(abfd, j)); + } + bfd_release (abfd, (char *)mergem); + goto loser1; + } + + switch (core->cd_segs[i].cs_type) + { + case COR_TYPE_DATA: + core_section (abfd, n)->name = ".data"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_LOAD + + SEC_HAS_CONTENTS); + break; + case COR_TYPE_STACK: + core_section (abfd, n)->name = ".stack"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_LOAD + + SEC_HAS_CONTENTS); + break; + case COR_TYPE_LIBDATA: + core_section (abfd, n)->name = ".libdata"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_HAS_CONTENTS); + break; + case COR_TYPE_WRITE: + core_section (abfd, n)->name = ".writeable"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_HAS_CONTENTS); + break; + case COR_TYPE_MSC: + core_section (abfd, n)->name = ".misc"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_HAS_CONTENTS); + break; + default: + core_section (abfd, n)->name = ".unknown"; + core_section (abfd, n)->flags = (SEC_ALLOC + SEC_HAS_CONTENTS); + break; + } + core_section (abfd, n)->_raw_size = core->cd_segs[i].cs_len; + core_section (abfd, n)->vma = core->cd_segs[i].cs_address; + core_section (abfd, n)->filepos = core->cd_segs[i].cs_offset; + core_section (abfd, n)->alignment_power = 2; + core_section (abfd, n)->next = NULL; + if (n > 0) + core_section (abfd, (n-1))->next = core_section (abfd, n); + + abfd->section_count = ++n; + } + + core_regsec (abfd)->name = ".reg"; + core_reg2sec (abfd)->name = ".reg2"; + + core_regsec (abfd)->flags = SEC_HAS_CONTENTS; + core_reg2sec (abfd)->flags = SEC_HAS_CONTENTS; + + core_regsec (abfd)->_raw_size = sizeof(core->cd_regs); + core_reg2sec (abfd)->_raw_size = sizeof(core->cd_fpregs); + + core_regsec (abfd)->vma = -1; + core_reg2sec (abfd)->vma = -1; + + /* We'll access the regs afresh in the core file, like any section: */ + core_regsec (abfd)->filepos = (file_ptr)offsetof(struct corehdr,cd_regs[0]); + core_reg2sec (abfd)->filepos = (file_ptr)offsetof(struct corehdr, + cd_fpregs); + + /* add the 2 reg fake sections to abfd */ + abfd->section_count += 2; + abfd->sections = core_regsec (abfd); + core_regsec (abfd)->next = core_reg2sec (abfd); + core_reg2sec (abfd)->next = core_section (abfd, 0); + + return abfd->xvec; +} + +static char * +aix386_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->cd_comm; +} + +static int +aix386_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->cd_cursig; +} + +static boolean +aix386_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this + point */ +} + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((PROTO(bfd_vma, (*), ( const bfd_byte *))) swap_abort ) +#define NO_GETS ((PROTO(bfd_signed_vma, (*), (const bfd_byte *))) swap_abort ) +#define NO_PUT ((PROTO(void, (*), (bfd_vma, bfd_byte *))) swap_abort ) + +const bfd_target aix386_core_vec = + { + "aix386-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIANG_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_GETS, NO_PUT, + NO_GET, NO_GETS, NO_PUT, + NO_GET, NO_GETS, NO_PUT, /* data */ + NO_GET, NO_GETS, NO_PUT, + NO_GET, NO_GETS, NO_PUT, + NO_GET, NO_GETS, NO_PUT, /* hdrs */ + + {_bfd_dummy_target, _bfd_dummy_target, + _bfd_dummy_target, aix386_core_file_p}, + {bfd_false, bfd_false, /* bfd_create_object */ + bfd_false, bfd_false}, + {bfd_false, bfd_false, /* bfd_write_contents */ + bfd_false, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (aix386), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/aout-adobe.c b/contrib/gdb/bfd/aout-adobe.c new file mode 100644 index 000000000000..36d230de9e8a --- /dev/null +++ b/contrib/gdb/bfd/aout-adobe.c @@ -0,0 +1,528 @@ +/* BFD back-end for a.out.adobe binaries. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. Based on bout.c. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include "aout/adobe.h" + +#include "aout/stab_gnu.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +extern const bfd_target a_out_adobe_vec; /* Forward decl */ + +static const bfd_target *aout_adobe_callback PARAMS ((bfd *)); + +extern boolean aout_32_slurp_symbol_table PARAMS ((bfd *abfd)); +extern boolean aout_32_write_syms PARAMS ((bfd *)); +static void aout_adobe_write_section PARAMS ((bfd *abfd, sec_ptr sect)); + +/* Swaps the information in an executable header taken from a raw byte + stream memory image, into the internal exec_header structure. */ + +void aout_adobe_swap_exec_header_in + PARAMS ((bfd *abfd, struct external_exec *raw_bytes, + struct internal_exec *execp)); + +void +aout_adobe_swap_exec_header_in (abfd, raw_bytes, execp) + bfd *abfd; + struct external_exec *raw_bytes; + struct internal_exec *execp; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); +} + +/* Swaps the information in an internal exec header structure into the + supplied buffer ready for writing to disk. */ + +PROTO(void, aout_adobe_swap_exec_header_out, + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes)); +void +aout_adobe_swap_exec_header_out (abfd, execp, raw_bytes) + bfd *abfd; + struct internal_exec *execp; + struct external_exec *raw_bytes; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info , bytes->e_info); + PUT_WORD (abfd, execp->a_text , bytes->e_text); + PUT_WORD (abfd, execp->a_data , bytes->e_data); + PUT_WORD (abfd, execp->a_bss , bytes->e_bss); + PUT_WORD (abfd, execp->a_syms , bytes->e_syms); + PUT_WORD (abfd, execp->a_entry , bytes->e_entry); + PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); + PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); +} + + +static const bfd_target * +aout_adobe_object_p (abfd) + bfd *abfd; +{ + struct internal_exec anexec; + struct external_exec exec_bytes; + char *targ; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + anexec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); + + /* Normally we just compare for the magic number. + However, a bunch of Adobe tools aren't fixed up yet; they generate + files using ZMAGIC(!). + If the environment variable GNUTARGET is set to "a.out.adobe", we will + take just about any a.out file as an Adobe a.out file. FIXME! */ + + if (N_BADMAG (anexec)) { + extern char *getenv (); + + targ = getenv ("GNUTARGET"); + if (targ && !strcmp (targ, a_out_adobe_vec.name)) + ; /* Just continue anyway, if specifically set to this format */ + else + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + } + + aout_adobe_swap_exec_header_in (abfd, &exec_bytes, &anexec); + return aout_32_some_aout_object_p (abfd, &anexec, aout_adobe_callback); +} + + +/* Finish up the opening of a b.out file for reading. Fill in all the + fields that are not handled by common code. */ + +static const bfd_target * +aout_adobe_callback (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + asection *sect; + struct external_segdesc ext[1]; + char *section_name; + char try_again[30]; /* name and number */ + char *newname; + int trynum; + flagword flags; + + /* Architecture and machine type -- unknown in this format. */ + bfd_set_arch_mach(abfd, bfd_arch_unknown, 0); + + /* The positions of the string table and symbol table. */ + obj_str_filepos (abfd) = N_STROFF (*execp); + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + + /* Suck up the section information from the file, one section at a time. */ + + for (;;) { + if (bfd_read ((PTR) ext, 1, sizeof (*ext), abfd) != sizeof (*ext)) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + switch (ext->e_type[0]) { + case N_TEXT: + section_name = ".text"; + flags = SEC_CODE | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; + break; + + case N_DATA: + section_name = ".data"; + flags = SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; + break; + + case N_BSS: + section_name = ".bss"; + flags = SEC_DATA | SEC_HAS_CONTENTS; + break; + + case 0: + goto no_more_sections; + + default: + (*_bfd_error_handler) + ("%s: Unknown section type in a.out.adobe file: %x\n", + bfd_get_filename (abfd), ext->e_type[0]); + goto no_more_sections; + } + + /* First one is called ".text" or whatever; subsequent ones are + ".text1", ".text2", ... */ + + bfd_set_error (bfd_error_no_error); + sect = bfd_make_section (abfd, section_name); + trynum = 0; + while (!sect) { + if (bfd_get_error () != bfd_error_no_error) + return 0; /* Some other error -- slide into the sunset */ + sprintf (try_again, "%s%d", section_name, ++trynum); + sect = bfd_make_section (abfd, try_again); + } + + /* Fix the name, if it is a sprintf'd name. */ + if (sect->name == try_again) { + newname = (char *) bfd_zalloc(abfd, strlen (sect->name)); + if (newname == NULL) + return 0; + strcpy (newname, sect->name); + sect->name = newname; + } + + /* Now set the section's attributes. */ + bfd_set_section_flags (abfd, sect, flags); + sect->_raw_size = ((ext->e_size[0] << 8) /* Assumed big-endian */ + | ext->e_size[1] << 8) + | ext->e_size[2]; + sect->_cooked_size = sect->_raw_size; + sect->vma = bfd_h_get_32 (abfd, ext->e_virtbase); + sect->filepos = bfd_h_get_32 (abfd, ext->e_filebase); + /* FIXME XXX alignment? */ + + /* Set relocation information for first section of each type. */ + if (trynum == 0) switch (ext->e_type[0]) { + case N_TEXT: + sect->rel_filepos = N_TRELOFF (*execp); + sect->reloc_count = execp->a_trsize; + break; + + case N_DATA: + sect->rel_filepos = N_DRELOFF (*execp); + sect->reloc_count = execp->a_drsize; + break; + } + } +no_more_sections: + + adata(abfd).reloc_entry_size = sizeof (struct reloc_std_external); + adata(abfd).symbol_entry_size = sizeof (struct external_nlist); + adata(abfd).page_size = 1; /* Not applicable. */ + adata(abfd).segment_size = 1; /* Not applicable. */ + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + + return abfd->xvec; +} + +struct bout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +static boolean +aout_adobe_mkobject (abfd) + bfd *abfd; +{ + struct bout_data_struct *rawptr; + + rawptr = (struct bout_data_struct *) bfd_zalloc (abfd, sizeof (struct bout_data_struct)); + if (rawptr == NULL) + return false; + + abfd->tdata.bout_data = rawptr; + exec_hdr (abfd) = &rawptr->e; + + adata(abfd).reloc_entry_size = sizeof (struct reloc_std_external); + adata(abfd).symbol_entry_size = sizeof (struct external_nlist); + adata(abfd).page_size = 1; /* Not applicable. */ + adata(abfd).segment_size = 1; /* Not applicable. */ + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + + return true; +} + + +static boolean +aout_adobe_write_object_contents (abfd) + bfd *abfd; +{ + struct external_exec swapped_hdr; + static struct external_segdesc sentinel[1]; /* Initialized to zero */ + asection *sect; + + exec_hdr (abfd)->a_info = ZMAGIC; + + /* Calculate text size as total of text sections, etc. */ + + exec_hdr (abfd)->a_text = 0; + exec_hdr (abfd)->a_data = 0; + exec_hdr (abfd)->a_bss = 0; + exec_hdr (abfd)->a_trsize = 0; + exec_hdr (abfd)->a_drsize = 0; + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_CODE) { + exec_hdr (abfd)->a_text += sect->_raw_size; + exec_hdr (abfd)->a_trsize += sect->reloc_count * + sizeof (struct reloc_std_external); + } else if (sect->flags & SEC_DATA) { + exec_hdr (abfd)->a_data += sect->_raw_size; + exec_hdr (abfd)->a_drsize += sect->reloc_count * + sizeof (struct reloc_std_external); + } else if (sect->flags & SEC_ALLOC && !(sect->flags & SEC_LOAD)) { + exec_hdr (abfd)->a_bss += sect->_raw_size; + } + } + + exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) + * sizeof (struct external_nlist); + exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); + + aout_adobe_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) &swapped_hdr, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE)) + return false; + + /* Now write out the section information. Text first, data next, rest + afterward. */ + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_CODE) { + aout_adobe_write_section (abfd, sect); + } + } + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_DATA) { + aout_adobe_write_section (abfd, sect); + } + } + for (sect = abfd->sections; sect; sect = sect->next) { + if (!(sect->flags & (SEC_CODE|SEC_DATA))) { + aout_adobe_write_section (abfd, sect); + } + } + + /* Write final `sentinel` section header (with type of 0). */ + if (bfd_write ((PTR) sentinel, 1, sizeof (*sentinel), abfd) + != sizeof (*sentinel)) + return false; + + /* Now write out reloc info, followed by syms and strings */ + if (bfd_get_symcount (abfd) != 0) + { + if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*exec_hdr(abfd))), SEEK_SET) + != 0) + return false; + + if (! aout_32_write_syms (abfd)) + return false; + + if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*exec_hdr(abfd))), SEEK_SET) + != 0) + return false; + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_CODE) { + if (!aout_32_squirt_out_relocs (abfd, sect)) + return false; + } + } + + if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*exec_hdr(abfd))), SEEK_SET) + != 0) + return false; + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_DATA) { + if (!aout_32_squirt_out_relocs (abfd, sect)) + return false; + } + } + } + return true; +} + +static void +aout_adobe_write_section (abfd, sect) + bfd *abfd; + sec_ptr sect; +{ + /* FIXME XXX */ +} + +static boolean +aout_adobe_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + file_ptr section_start; + sec_ptr sect; + + if (abfd->output_has_begun == false) { /* set by bfd.c handler */ + + /* Assign file offsets to sections. Text sections are first, and + are contiguous. Then data sections. Everything else at the end. */ + + section_start = N_TXTOFF (ignore<-->me); + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_CODE) { + sect->filepos = section_start; + /* FIXME: Round to alignment */ + section_start += sect->_raw_size; + } + } + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_DATA) { + sect->filepos = section_start; + /* FIXME: Round to alignment */ + section_start += sect->_raw_size; + } + } + + for (sect = abfd->sections; sect; sect = sect->next) { + if (sect->flags & SEC_HAS_CONTENTS && + !(sect->flags & (SEC_CODE|SEC_DATA))) { + sect->filepos = section_start; + /* FIXME: Round to alignment */ + section_start += sect->_raw_size; + } + } + } + + /* regardless, once we know what we're doing, we might as well get going */ + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) + return false; + + if (count != 0) { + return (bfd_write ((PTR)location, 1, count, abfd) == count) ?true:false; + } + return true; +} + +static boolean +aout_adobe_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch == bfd_arch_unknown + || arch == bfd_arch_m68k) + return true; + + return false; +} + +static int +aout_adobe_sizeof_headers (ignore_abfd, ignore) + bfd *ignore_abfd; + boolean ignore; +{ + return sizeof(struct internal_exec); +} + + + + +/* Build the transfer vector for Adobe A.Out files. */ + +#define aout_32_close_and_cleanup aout_32_bfd_free_cached_info + +#define aout_32_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +#define aout_32_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) \ + PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) + +#define aout_32_set_arch_mach aout_adobe_set_arch_mach +#define aout_32_set_section_contents aout_adobe_set_section_contents + +#define aout_32_sizeof_headers aout_adobe_sizeof_headers +#define aout_32_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define aout_32_get_section_contents_in_window _bfd_generic_get_section_contents_in_window +#define aout_32_bfd_relax_section bfd_generic_relax_section +#define aout_32_bfd_link_hash_table_create \ + _bfd_generic_link_hash_table_create +#define aout_32_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define aout_32_bfd_final_link _bfd_generic_final_link +#define aout_32_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target a_out_adobe_vec = +{ + "a.out.adobe", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_BIG, /* data byte order is unknown (big assumed) */ + BFD_ENDIAN_BIG, /* hdr byte order is big */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT ), + /* section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_DATA | SEC_RELOC), + '_', /* symbol leading char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + {_bfd_dummy_target, aout_adobe_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, aout_adobe_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, aout_adobe_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (aout_32), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), + BFD_JUMP_TABLE_SYMBOLS (aout_32), + BFD_JUMP_TABLE_RELOCS (aout_32), + BFD_JUMP_TABLE_WRITE (aout_32), + BFD_JUMP_TABLE_LINK (aout_32), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/aout-arm.c b/contrib/gdb/bfd/aout-arm.c new file mode 100644 index 000000000000..978664a48aaf --- /dev/null +++ b/contrib/gdb/bfd/aout-arm.c @@ -0,0 +1,548 @@ +/* BFD back-end for raw ARM a.out binaries. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#define N_TXTADDR(x) \ + ((N_MAGIC(x) == NMAGIC) ? 0x8000 : \ + (N_MAGIC(x) != ZMAGIC) ? 0 : \ + (N_SHARED_LIB(x)) ? ((x).a_entry & ~(TARGET_PAGE_SIZE - 1)) : \ + TEXT_START_ADDR) + +#define TEXT_START_ADDR 0x8000 +#define TARGET_PAGE_SIZE 0x8000 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_arm + +#define MY(OP) CAT(aoutarm_,OP) +#define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) && \ + (((x).a_info & ~006000) != OMAGIC) && \ + ((x).a_info != NMAGIC)) +#define N_MAGIC(x) ((x).a_info & ~07200) + +#include "bfd.h" +#include "sysdep.h" +#include "assert.h" + +#define MYARM(OP) CAT(aoutarm_,OP) +reloc_howto_type *MYARM(bfd_reloc_type_lookup) + PARAMS((bfd *, bfd_reloc_code_real_type)); +static boolean MYARM(write_object_contents) PARAMS((bfd *)); + +/* Avoid multiple defininitions from aoutx if supporting standarad a.out + as well as our own. */ +#define NAME(x,y) CAT3(aoutarm,_32_,y) + +#define MY_bfd_reloc_type_lookup aoutarm_bfd_reloc_type_lookup + +#include "libaout.h" +#include "aout/aout64.h" + +static bfd_reloc_status_type +MY(fix_pcrel_26_done) PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +MY(fix_pcrel_26) PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); +static void MY(swap_std_reloc_in) PARAMS ((bfd *, struct reloc_std_external *, + arelent *, asymbol **, + bfd_size_type)); +void MY(swap_std_reloc_out) PARAMS ((bfd *, arelent *, + struct reloc_std_external *)); + +reloc_howto_type MY(howto_table)[] = +{ + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask + pcdone */ + HOWTO (0, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "8", true, + 0x000000ff, 0x000000ff, false), + HOWTO (1, 0, 1, 16, false, 0, complain_overflow_bitfield, 0, "16", true, + 0x0000ffff, 0x0000ffff, false), + HOWTO (2, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "32", true, + 0xffffffff, 0xffffffff, false), + HOWTO (3, 2, 2, 26, true, 0, complain_overflow_signed, MY(fix_pcrel_26), + "ARM26", true, 0x00ffffff, 0x00ffffff, true), + HOWTO (4, 0, 0, 8, true, 0, complain_overflow_signed, 0, "DISP8", true, + 0x000000ff, 0x000000ff, true), + HOWTO (5, 0, 1, 16, true, 0, complain_overflow_signed, 0, "DISP16", true, + 0x0000ffff, 0x0000ffff, true), + HOWTO (6, 0, 2, 32, true, 0, complain_overflow_signed, 0, "DISP32", true, + 0xffffffff, 0xffffffff, true), + HOWTO (7, 2, 2, 26, false, 0, complain_overflow_signed, + MY(fix_pcrel_26_done), "ARM26D", true, 0x0, 0x0, + false), + {-1}, + HOWTO (9, 0, -1, 16, false, 0, complain_overflow_bitfield, 0, "NEG16", true, + 0x0000ffff, 0x0000ffff, false), + HOWTO (10, 0, -2, 32, false, 0, complain_overflow_bitfield, 0, "NEG32", true, + 0xffffffff, 0xffffffff, false) +}; + +#define RELOC_ARM_BITS_NEG_BIG ((unsigned int) 0x08) +#define RELOC_ARM_BITS_NEG_LITTLE ((unsigned int) 0x10) + +reloc_howto_type * +MY(reloc_howto)(abfd, rel, r_index, r_extern, r_pcrel) + bfd *abfd; + struct reloc_std_external *rel; + int *r_index; + int *r_extern; + int *r_pcrel; +{ + unsigned int r_length; + unsigned int r_pcrel_done; + unsigned int r_neg; + int index; + + *r_pcrel = 0; + if (bfd_header_big_endian (abfd)) + { + *r_index = ((rel->r_index[0] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[2]); + *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); + r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_BIG)); + r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG); + } + else + { + *r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0]); + *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_LITTLE)); + r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE); + } + index = r_length + 4 * r_pcrel_done + 8 * r_neg; + if (index == 3) + *r_pcrel = 1; + + return MY(howto_table) + index; +} + +#define MY_reloc_howto(BFD, REL, IN, EX, PC) \ + MY(reloc_howto) (BFD, REL, &IN, &EX, &PC) + +void +MY(put_reloc)(abfd, r_extern, r_index, value, howto, reloc) + bfd *abfd; + int r_extern; + int r_index; + long value; + reloc_howto_type *howto; + struct reloc_std_external *reloc; +{ + unsigned int r_length; + int r_pcrel; + int r_neg; + + PUT_WORD (abfd, value, reloc->r_address); + r_length = howto->size ; /* Size as a power of two */ + + /* Special case for branch relocations. */ + if (howto->type == 3 || howto->type == 7) + r_length = 3; + + r_pcrel = howto->type & 4; /* PC Relative done? */ + r_neg = howto->type & 8; /* Negative relocation */ + if (bfd_header_big_endian (abfd)) + { + reloc->r_index[0] = r_index >> 16; + reloc->r_index[1] = r_index >> 8; + reloc->r_index[2] = r_index; + reloc->r_type[0] = + ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) + | (r_neg ? RELOC_ARM_BITS_NEG_BIG : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); + } + else + { + reloc->r_index[2] = r_index >> 16; + reloc->r_index[1] = r_index >> 8; + reloc->r_index[0] = r_index; + reloc->r_type[0] = + ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) + | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); + } +} + +#define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \ + MY(put_reloc)(BFD, EXT, IDX, VAL, HOWTO, RELOC) + +void +MY(relocatable_reloc)(howto, abfd, reloc, amount, r_addr) + reloc_howto_type *howto; + bfd *abfd; + struct reloc_std_external *reloc; + bfd_vma *amount; + bfd_vma r_addr; +{ + if (howto->type == 3) + { + if (reloc->r_type[0] + & (bfd_header_big_endian (abfd) + ? RELOC_STD_BITS_EXTERN_BIG : RELOC_STD_BITS_EXTERN_LITTLE)) + { + /* The reloc is still external, so don't modify anything. */ + *amount = 0; + } + else + { + *amount -= r_addr; + /* Change the r_pcrel value -- on the ARM, this bit is set once the + relocation is done. */ + if (bfd_header_big_endian (abfd)) + reloc->r_type[0] |= RELOC_STD_BITS_PCREL_BIG; + else + reloc->r_type[0] |= RELOC_STD_BITS_PCREL_LITTLE; + } + } + else if (howto->type == 7) + *amount = 0; +} + +#define MY_relocatable_reloc(HOW, BFD, REL, AMOUNT, ADDR) \ + MY(relocatable_reloc)(HOW, BFD, REL, &(AMOUNT), ADDR) + +static bfd_reloc_status_type +MY(fix_pcrel_26_done) (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* This is dead simple at present. */ + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +MY(fix_pcrel_26) (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_size_type addr = reloc_entry->address; + long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); + bfd_reloc_status_type flag = bfd_reloc_ok; + + /* If this is an undefined symbol, return error */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0) + return output_bfd ? bfd_reloc_ok : bfd_reloc_undefined; + + /* If the sections are different, and we are doing a partial relocation, + just ignore it for now. */ + if (symbol->section->name != input_section->name + && output_bfd != (bfd *)NULL) + return bfd_reloc_ok; + + relocation = (target & 0x00ffffff) << 2; + relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */ + relocation += symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + relocation -= input_section->output_section->vma; + relocation -= input_section->output_offset; + relocation -= addr; + if (relocation & 3) + return bfd_reloc_overflow; + + /* Check for overflow */ + if (relocation & 0x02000000) + { + if ((relocation & ~0x03ffffff) != ~0x03ffffff) + flag = bfd_reloc_overflow; + } + else if (relocation & ~0x03ffffff) + flag = bfd_reloc_overflow; + + target &= ~0x00ffffff; + target |= (relocation >> 2) & 0x00ffffff; + bfd_put_32 (abfd, target, (bfd_byte *) data + addr); + + /* Now the ARM magic... Change the reloc type so that it is marked as done. + Strictly this is only necessary if we are doing a partial relocation. */ + reloc_entry->howto = &MY(howto_table)[7]; + + return flag; +} + +reloc_howto_type * +MY(bfd_reloc_type_lookup)(abfd,code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ +#define ASTD(i,j) case i: return &MY(howto_table)[j] + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + default: return (CONST struct reloc_howto_struct *) 0; + } + + switch (code) + { + ASTD (BFD_RELOC_16, 1); + ASTD (BFD_RELOC_32, 2); + ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3); + ASTD (BFD_RELOC_8_PCREL, 4); + ASTD (BFD_RELOC_16_PCREL, 5); + ASTD (BFD_RELOC_32_PCREL, 6); + default: return (CONST struct reloc_howto_struct *) 0; + } +} + +#define MY_swap_std_reloc_in MY(swap_std_reloc_in) +#define MY_swap_std_reloc_out MY(swap_std_reloc_out) +#define MY_get_section_contents _bfd_generic_get_section_contents +/* #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create */ +/* #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols */ +/* #define MY_bfd_final_link _bfd_generic_final_link */ + +#include "aoutx.h" + +static void +MY_swap_std_reloc_in (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_std_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + int r_index; + int r_extern; + unsigned int r_length; + int r_pcrel; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel); + + MOVE_ADDRESS (0); +} + +void +MY_swap_std_reloc_out (abfd, g, natptr) + bfd *abfd; + arelent *g; + struct reloc_std_external *natptr; +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + int r_length; + int r_pcrel; + int r_neg = 0; /* Negative relocs use the BASEREL bit. */ + asection *output_section = sym->section->output_section; + + PUT_WORD(abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two */ + if (r_length < 0) + { + r_length = -r_length; + r_neg = 1; + } + + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + + /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the + relocation has been done already (Only for the 26-bit one I think)???!!! + */ + + if (g->howto->type == 3) + { + r_length = 3; + r_pcrel = 0; + } + else if (g->howto->type == 7) + { + r_length = 3; + r_pcrel = 1; + } + + +#if 0 + /* For a standard reloc, the addend is in the object file. */ + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; +#endif + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = (*(g->sym_ptr_ptr))->KEEPIT; + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) + { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + ( (r_extern ? RELOC_STD_BITS_EXTERN_BIG: 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG: 0) + | (r_neg ? RELOC_ARM_BITS_NEG_BIG: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); + } + else + { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + ( (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); + } +} + +#define MY_BFD_TARGET + +#include "aout-target.h" + +const bfd_target aout_arm_little_vec = +{ + "a.out-arm-little", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_LITTLE, /* target byte order (little) */ + BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + AR_PAD_CHAR, /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (MY), + BFD_JUMP_TABLE_COPY (MY), + BFD_JUMP_TABLE_CORE (MY), + BFD_JUMP_TABLE_ARCHIVE (MY), + BFD_JUMP_TABLE_SYMBOLS (MY), + BFD_JUMP_TABLE_RELOCS (MY), + BFD_JUMP_TABLE_WRITE (MY), + BFD_JUMP_TABLE_LINK (MY), + BFD_JUMP_TABLE_DYNAMIC (MY), + + (PTR) MY_backend_data, +}; + +const bfd_target aout_arm_big_vec = +{ + "a.out-arm-big", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_BIG, /* target byte order (big) */ + BFD_ENDIAN_BIG, /* target headers byte order (big) */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + AR_PAD_CHAR, /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (MY), + BFD_JUMP_TABLE_COPY (MY), + BFD_JUMP_TABLE_CORE (MY), + BFD_JUMP_TABLE_ARCHIVE (MY), + BFD_JUMP_TABLE_SYMBOLS (MY), + BFD_JUMP_TABLE_RELOCS (MY), + BFD_JUMP_TABLE_WRITE (MY), + BFD_JUMP_TABLE_LINK (MY), + BFD_JUMP_TABLE_DYNAMIC (MY), + + (PTR) MY_backend_data, +}; diff --git a/contrib/gdb/bfd/aout-encap.c b/contrib/gdb/bfd/aout-encap.c new file mode 100644 index 000000000000..c25f9037dce0 --- /dev/null +++ b/contrib/gdb/bfd/aout-encap.c @@ -0,0 +1,236 @@ +/* BFD back-end for a.out files encapsulated with COFF headers. + Copyright (C) 1990, 1991 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* THIS MODULE IS NOT FINISHED. IT PROBABLY DOESN'T EVEN COMPILE. */ + +#if 0 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define TEXT_START_ADDR 0 +#define BYTES_IN_WORD 4 +#endif + +#include "bfd.h" +#include +#include "libbfd.h" +#include +#include "aout/stab_gnu.h" +#include "aout/ar.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +const bfd_target *encap_real_callback (); + +const bfd_target * +encap_object_p (abfd) + bfd *abfd; +{ + unsigned char magicbuf[4]; /* Raw bytes of magic number from file */ + unsigned long magic; /* Swapped magic number */ + short coff_magic; + struct external_exec exec_bytes; + struct internal_exec exec; + + if (bfd_read ((PTR)magicbuf, 1, sizeof (magicbuf), abfd) != + sizeof (magicbuf)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + coff_magic = bfd_h_get_16 (abfd, magicbuf); + if (coff_magic != COFF_MAGIC) + return 0; /* Not an encap coff file */ + + __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0) + (fseek ((f), HEADER_OFFSET((f)), 1)) + + magic = bfd_h_get_32 (abfd, magicbuf); + + if (N_BADMAG (*((struct internal_exec *) &magic))) return 0; + + struct external_exec exec_bytes; + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec); + + return aout_32_some_aout_object_p (abfd, &exec, encap_realcallback); +} + +/* Finish up the reading of a encapsulated-coff a.out file header */ +const bfd_target * +encap_real_callback (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + + MY(callback)(abfd, execp); + + /* If we have a coff header, it can give us better values for + text_start and exec_data_start. This is particularly useful + for remote debugging of embedded systems. */ + if (N_FLAGS(exec_aouthdr) & N_FLAGS_COFF_ENCAPSULATE) + { + struct coffheader ch; + int val; + val = lseek (execchan, -(sizeof (AOUTHDR) + sizeof (ch)), 1); + if (val == -1) + perror_with_name (filename); + val = myread (execchan, &ch, sizeof (ch)); + if (val < 0) + perror_with_name (filename); + text_start = ch.text_start; + exec_data_start = ch.data_start; + } else + { + text_start = + IS_OBJECT_FILE (exec_aouthdr) ? 0 : N_TXTADDR (exec_aouthdr); + exec_data_start = IS_OBJECT_FILE (exec_aouthdr) + ? exec_aouthdr.a_text : N_DATADDR (exec_aouthdr); + } + + /* Determine the architecture and machine type of the object file. */ + bfd_default_set_arch_mach(abfd, bfd_arch_m68k, 0); /* FIXME */ + + return abfd->xvec; +} + +/* Write an object file in Encapsulated COFF format. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +boolean +encap_write_object_contents (abfd) + bfd *abfd; +{ + bfd_size_type data_pad = 0; + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +/****** FIXME: Fragments from the old GNU LD program for dealing with + encap coff. */ +struct coffheader coffheader; +int need_coff_header; + + /* Determine whether to count the header as part of + the text size, and initialize the text size accordingly. + This depends on the kind of system and on the output format selected. */ + + N_SET_MAGIC (outheader, magic); +#ifdef INITIALIZE_HEADER + INITIALIZE_HEADER; +#endif + + text_size = sizeof (struct exec); +#ifdef COFF_ENCAPSULATE + if (relocatable_output == 0 && file_table[0].just_syms_flag == 0) + { + need_coff_header = 1; + /* set this flag now, since it will change the values of N_TXTOFF, etc */ + N_SET_FLAGS (outheader, aout_backend_info (abfd)->exec_hdr_flags); + text_size += sizeof (struct coffheader); + } +#endif + +#ifdef COFF_ENCAPSULATE + if (need_coff_header) + { + /* We are encapsulating BSD format within COFF format. */ + struct coffscn *tp, *dp, *bp; + + tp = &coffheader.scns[0]; + dp = &coffheader.scns[1]; + bp = &coffheader.scns[2]; + + strcpy (tp->s_name, ".text"); + tp->s_paddr = text_start; + tp->s_vaddr = text_start; + tp->s_size = text_size; + tp->s_scnptr = sizeof (struct coffheader) + sizeof (struct exec); + tp->s_relptr = 0; + tp->s_lnnoptr = 0; + tp->s_nreloc = 0; + tp->s_nlnno = 0; + tp->s_flags = 0x20; + strcpy (dp->s_name, ".data"); + dp->s_paddr = data_start; + dp->s_vaddr = data_start; + dp->s_size = data_size; + dp->s_scnptr = tp->s_scnptr + tp->s_size; + dp->s_relptr = 0; + dp->s_lnnoptr = 0; + dp->s_nreloc = 0; + dp->s_nlnno = 0; + dp->s_flags = 0x40; + strcpy (bp->s_name, ".bss"); + bp->s_paddr = dp->s_vaddr + dp->s_size; + bp->s_vaddr = bp->s_paddr; + bp->s_size = bss_size; + bp->s_scnptr = 0; + bp->s_relptr = 0; + bp->s_lnnoptr = 0; + bp->s_nreloc = 0; + bp->s_nlnno = 0; + bp->s_flags = 0x80; + + coffheader.f_magic = COFF_MAGIC; + coffheader.f_nscns = 3; + /* store an unlikely time so programs can + * tell that there is a bsd header + */ + coffheader.f_timdat = 1; + coffheader.f_symptr = 0; + coffheader.f_nsyms = 0; + coffheader.f_opthdr = 28; + coffheader.f_flags = 0x103; + /* aouthdr */ + coffheader.magic = ZMAGIC; + coffheader.vstamp = 0; + coffheader.tsize = tp->s_size; + coffheader.dsize = dp->s_size; + coffheader.bsize = bp->s_size; + coffheader.entry = outheader.a_entry; + coffheader.text_start = tp->s_vaddr; + coffheader.data_start = dp->s_vaddr; + } +#endif + +#ifdef COFF_ENCAPSULATE + if (need_coff_header) + mywrite (&coffheader, sizeof coffheader, 1, outdesc); +#endif + +#ifndef COFF_ENCAPSULATE + padfile (N_TXTOFF (outheader) - sizeof outheader, outdesc); +#endif + + text_size -= N_TXTOFF (outheader); + WRITE_HEADERS(abfd, execp); + return true; +} + +#define MY_write_object_content encap_write_object_contents +#define MY_object_p encap_object_p +#define MY_exec_hdr_flags N_FLAGS_COFF_ENCAPSULATE + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/aout-ns32k.c b/contrib/gdb/bfd/aout-ns32k.c new file mode 100644 index 000000000000..269e053fe5ac --- /dev/null +++ b/contrib/gdb/bfd/aout-ns32k.c @@ -0,0 +1,399 @@ +/* BFD back-end for ns32k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + Contributed by Ian Dall (idall@eleceng.adelaide.edu.au). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 + +#include "bfd.h" +#include "aout/aout64.h" + +#define MYNS(OP) CAT(ns32kaout_,OP) +reloc_howto_type * +MYNS(bfd_reloc_type_lookup) + PARAMS((bfd *abfd AND + bfd_reloc_code_real_type code)); + +boolean +MYNS(write_object_contents) + PARAMS((bfd *abfd)); + +/* Avoid multiple definitions from aoutx if supporting standard a.out format(s) + * as well as this one + */ +#define NAME(x,y) CAT3(ns32kaout,_32_,y) + +void bfd_ns32k_arch PARAMS ((void)); +long ns32k_get_displacement PARAMS ((bfd_byte *buffer, long offset, long size)); +int ns32k_put_displacement PARAMS ((long value, bfd_byte *buffer, long offset, long size)); +long ns32k_get_immediate PARAMS ((bfd_byte *buffer, long offset, long size)); +int ns32k_put_immediate PARAMS ((long value, bfd_byte *buffer, long offset, long size)); +bfd_reloc_status_type + ns32k_reloc_disp PARAMS ((bfd *abfd, arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); +bfd_reloc_status_type + ns32k_reloc_imm PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); +bfd_reloc_status_type + ns32k_final_link_relocate PARAMS ((reloc_howto_type *howto, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + bfd_vma address, + bfd_vma value, + bfd_vma addend )); +bfd_reloc_status_type + ns32k_relocate_contents PARAMS ((reloc_howto_type *howto, + bfd *input_bfd, + bfd_vma relocation, + bfd_byte *location)); + +#include "libaout.h" + +#define MY(OP) MYNS(OP) + +#define MY_swap_std_reloc_in MY(swap_std_reloc_in) +#define MY_swap_std_reloc_out MY(swap_std_reloc_out) + +static void +MY_swap_std_reloc_in PARAMS ((bfd *abfd, struct reloc_std_external *bytes, + arelent *cache_ptr, asymbol **symbols, + bfd_size_type symcount)); + +static void +MY_swap_std_reloc_out PARAMS ((bfd *abfd, arelent *g, + struct reloc_std_external *natptr)); + +/* The ns32k series is ah, unusual, when it comes to relocation. + * There are three storage methods for relocateable objects. There + * are displacements, immediate operands and ordinary twos complement + * data. Of these, only the last fits into the standard relocation + * scheme. Immediate operands are stored huffman encoded and + * immediate operands are stored big endian (where as the natural byte + * order is little endian for this achitecture). + + * Note that the ns32k displacement storage method is orthogonal to + * whether the relocation is pc relative or not. The "displacement" + * storage scheme is used for essentially all address constants. The + * displacement can be relative to zero (absolute displacement), + * relative to the pc (pc relative), the stack pointer, the frame + * pointer, the static base register and general purpose register etc. + + * For example: + * + * sym1: .long . # pc relative 2's complement + * sym1: .long foo # 2's complement not pc relative + * + * self: movd @self, r0 # pc relative displacement + * movd foo, r0 # non pc relative displacement + * + * self: movd self, r0 # pc relative immediate + * movd foo, r0 # non pc relative immediate + * + * In addition, for historical reasons the encoding of the relocation types + * in the a.out format relocation entries is such that even the relocation + * methods which are standard are not encoded the standard way. + * + */ + +reloc_howto_type MY(howto_table)[] = +{ +/* ns32k immediate operands */ +HOWTO(BFD_RELOC_NS32K_IMM_8, 0, 0, 8, false, 0, true, + ns32k_reloc_imm, "NS32K_IMM_8", + true, 0x000000ff,0x000000ff, false), +HOWTO(BFD_RELOC_NS32K_IMM_16, 0, 1, 16, false, 0, true, + ns32k_reloc_imm, "NS32K_IMM_16", + true, 0x0000ffff,0x0000ffff, false), +HOWTO(BFD_RELOC_NS32K_IMM_32, 0, 2, 32, false, 0, true, + ns32k_reloc_imm, "NS32K_IMM_32", + true, 0xffffffff,0xffffffff, false), +HOWTO(BFD_RELOC_NS32K_IMM_8_PCREL, 0, 0, 8, true, 0, false, + ns32k_reloc_imm, "PCREL_NS32K_IMM_8", + true, 0x000000ff, 0x000000ff, false), +HOWTO(BFD_RELOC_NS32K_IMM_16_PCREL, 0, 1, 16, true, 0, false, + ns32k_reloc_imm, "PCREL_NS32K_IMM_16", + true, 0x0000ffff,0x0000ffff, false), +HOWTO(BFD_RELOC_NS32K_IMM_32_PCREL, 0, 2, 32, true, 0, false, + ns32k_reloc_imm, "PCREL_NS32K_IMM_32", + true, 0xffffffff,0xffffffff, false), + +/* ns32k displacements */ +HOWTO(BFD_RELOC_NS32K_DISP_8, 0, 0, 8, false, 0, true, + ns32k_reloc_disp, "NS32K_DISP_8", + true, 0x000000ff,0x000000ff, false), +HOWTO(BFD_RELOC_NS32K_DISP_16, 0, 1, 16, false, 0, true, + ns32k_reloc_disp, "NS32K_DISP_16", + true, 0x0000ffff, 0x0000ffff, false), +HOWTO(BFD_RELOC_NS32K_DISP_32, 0, 2, 32, false, 0, true, + ns32k_reloc_disp, "NS32K_DISP_32", + true, 0xffffffff, 0xffffffff, false), +HOWTO(BFD_RELOC_NS32K_DISP_8_PCREL, 0, 0, 8, true, 0, false, + ns32k_reloc_disp, "PCREL_NS32K_DISP_8", + true, 0x000000ff,0x000000ff, false), +HOWTO(BFD_RELOC_NS32K_DISP_16_PCREL, 0, 1, 16, true, 0, false, + ns32k_reloc_disp, "PCREL_NS32K_DISP_16", + true, 0x0000ffff,0x0000ffff, false), +HOWTO(BFD_RELOC_NS32K_DISP_32_PCREL, 0, 2, 32, true, 0, false, + ns32k_reloc_disp, "PCREL_NS32K_DISP_32", + true, 0xffffffff,0xffffffff, false), + +/* Normal 2's complement */ +HOWTO(BFD_RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0, + "8", true, 0x000000ff,0x000000ff, false), +HOWTO(BFD_RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0, + "16", true, 0x0000ffff,0x0000ffff, false), +HOWTO(BFD_RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0, + "32", true, 0xffffffff,0xffffffff, false), +HOWTO(BFD_RELOC_8_PCREL, 0, 0, 8, true, 0, complain_overflow_signed, 0, + "PCREL_8", true, 0x000000ff,0x000000ff, false), +HOWTO(BFD_RELOC_16_PCREL, 0, 1, 16, true, 0, complain_overflow_signed, 0, + "PCREL_16", true, 0x0000ffff,0x0000ffff, false), +HOWTO(BFD_RELOC_32_PCREL, 0, 2, 32, true, 0, complain_overflow_signed, 0, + "PCREL_32", true, 0xffffffff,0xffffffff, false), +}; + + +#define CTOR_TABLE_RELOC_HOWTO(BFD) (MY(howto_table) + 14) + +#define RELOC_STD_BITS_NS32K_TYPE_BIG 0x06 +#define RELOC_STD_BITS_NS32K_TYPE_LITTLE 0x60 +#define RELOC_STD_BITS_NS32K_TYPE_SH_BIG 1 +#define RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE 5 + +reloc_howto_type * +MY(reloc_howto)(abfd, rel, r_index, r_extern, r_pcrel) + bfd *abfd; + struct reloc_std_external *rel; + int *r_index; + int *r_extern; + int *r_pcrel; +{ + unsigned int r_length; + int r_ns32k_type; +/* BFD_ASSERT(bfd_header_little_endian (abfd)); */ + *r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0] ); + *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + *r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE); + r_ns32k_type = ((rel->r_type[0] & RELOC_STD_BITS_NS32K_TYPE_LITTLE) + >> RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE); + return (MY(howto_table) + r_length + 3 * (*r_pcrel) + 6 * r_ns32k_type); +} + +#define MY_reloc_howto(BFD,REL,IN,EX,PC) MY(reloc_howto)(BFD, REL, &IN, &EX, &PC) + +void +MY(put_reloc)(abfd, r_extern, r_index, value, howto, reloc) + bfd *abfd; + int r_extern; + int r_index; + long value; + reloc_howto_type *howto; + struct reloc_std_external *reloc; +{ + unsigned int r_length; + int r_pcrel; + int r_ns32k_type; + PUT_WORD (abfd, value, reloc->r_address); + r_length = howto->size ; /* Size as a power of two */ + r_pcrel = (int) howto->pc_relative; /* Relative to PC? */ + r_ns32k_type = (howto - MY(howto_table) )/6; +/* BFD_ASSERT (bfd_header_little_endian (abfd)); */ + reloc->r_index[2] = r_index >> 16; + reloc->r_index[1] = r_index >> 8; + reloc->r_index[0] = r_index; + reloc->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE) + | (r_ns32k_type << RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE); +} + +#define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \ + MY(put_reloc)(BFD, EXT, IDX, VAL, HOWTO, RELOC) + +#define STAT_FOR_EXEC + +#define MY_final_link_relocate ns32k_final_link_relocate +#define MY_relocate_contents ns32k_relocate_contents + +#include + +reloc_howto_type * + MY(bfd_reloc_type_lookup)(abfd,code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + +#define ENTRY(i,j) case i: return &MY(howto_table)[j] + + int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE; + + BFD_ASSERT(ext == 0); + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + } + switch (code) + { + ENTRY(BFD_RELOC_NS32K_IMM_8, 0); + ENTRY(BFD_RELOC_NS32K_IMM_16, 1); + ENTRY(BFD_RELOC_NS32K_IMM_32, 2); + ENTRY(BFD_RELOC_NS32K_IMM_8_PCREL, 3); + ENTRY(BFD_RELOC_NS32K_IMM_16_PCREL, 4); + ENTRY(BFD_RELOC_NS32K_IMM_32_PCREL, 5); + ENTRY(BFD_RELOC_NS32K_DISP_8, 6); + ENTRY(BFD_RELOC_NS32K_DISP_16, 7); + ENTRY(BFD_RELOC_NS32K_DISP_32, 8); + ENTRY(BFD_RELOC_NS32K_DISP_8_PCREL, 9); + ENTRY(BFD_RELOC_NS32K_DISP_16_PCREL, 10); + ENTRY(BFD_RELOC_NS32K_DISP_32_PCREL, 11); + ENTRY(BFD_RELOC_8, 12); + ENTRY(BFD_RELOC_16, 13); + ENTRY(BFD_RELOC_32, 14); + ENTRY(BFD_RELOC_8_PCREL, 15); + ENTRY(BFD_RELOC_16_PCREL, 16); + ENTRY(BFD_RELOC_32_PCREL, 17); + default: return (reloc_howto_type *) NULL; + } +#undef ENTRY +} + + +static void +MY_swap_std_reloc_in (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_std_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + int r_index; + int r_extern; + int r_pcrel; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + /* now the fun stuff */ + + cache_ptr->howto = MY_reloc_howto(abfd, bytes, r_index, r_extern, r_pcrel); + + MOVE_ADDRESS(0); +} + +static void +MY_swap_std_reloc_out (abfd, g, natptr) + bfd *abfd; + arelent *g; + struct reloc_std_external *natptr; +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + unsigned int r_addend; + asection *output_section = sym->section->output_section; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + Check for that here. */ + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; +#undef KEEPIT +#define KEEPIT udata.i + r_index = (*(g->sym_ptr_ptr))->KEEPIT; +#undef KEEPIT + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr); +} + +bfd_reloc_status_type +ns32k_relocate_contents (howto, input_bfd, relocation, location) + reloc_howto_type *howto; + bfd *input_bfd; + bfd_vma relocation; + bfd_byte *location; +{ + int r_ns32k_type = (howto - MY(howto_table)) / 6; + long (*get_data)(); + int (*put_data)(); + + switch (r_ns32k_type) + { + case 0: + get_data = ns32k_get_immediate; + put_data = ns32k_put_immediate; + break; + case 1: + get_data = ns32k_get_displacement; + put_data = ns32k_put_displacement; + break; + case 2: + return _bfd_relocate_contents (howto, input_bfd, relocation, + location); + /* NOT REACHED */ + break; + } + return do_ns32k_reloc_contents (howto, input_bfd, relocation, + location, get_data, put_data); +} diff --git a/contrib/gdb/bfd/aout-target.h b/contrib/gdb/bfd/aout-target.h new file mode 100644 index 000000000000..6711a714a571 --- /dev/null +++ b/contrib/gdb/bfd/aout-target.h @@ -0,0 +1,607 @@ +/* Define a target vector and some small routines for a variant of a.out. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +/*#include "libaout.h"*/ + +extern reloc_howto_type * NAME(aout,reloc_type_lookup) (); + +/* Set parameters about this a.out file that are machine-dependent. + This routine is called from some_aout_object_p just before it returns. */ +#ifndef MY_callback +static const bfd_target * +MY(callback) (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + unsigned int arch_align_power; + unsigned long arch_align; + + /* Calculate the file positions of the parts of a newly read aout header */ + obj_textsec (abfd)->_raw_size = N_TXTSIZE(*execp); + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; + obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; + obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF (*execp); + obj_datasec (abfd)->filepos = N_DATOFF (*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + obj_str_filepos (abfd) = N_STROFF (*execp); + + /* Determine the architecture and machine type of the object file. */ +#ifdef SET_ARCH_MACH + SET_ARCH_MACH(abfd, *execp); +#else + bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0); +#endif + + /* Now that we know the architecture, set the alignments of the + sections. This is normally done by NAME(aout,new_section_hook), + but when the initial sections were created the architecture had + not yet been set. However, for backward compatibility, we don't + set the alignment power any higher than as required by the size + of the section. */ + arch_align_power = bfd_get_arch_info (abfd)->section_align_power; + arch_align = 1 << arch_align_power; + if ((BFD_ALIGN (obj_textsec (abfd)->_raw_size, arch_align) + == obj_textsec (abfd)->_raw_size) + && (BFD_ALIGN (obj_datasec (abfd)->_raw_size, arch_align) + == obj_datasec (abfd)->_raw_size) + && (BFD_ALIGN (obj_bsssec (abfd)->_raw_size, arch_align) + == obj_bsssec (abfd)->_raw_size)) + { + obj_textsec (abfd)->alignment_power = arch_align_power; + obj_datasec (abfd)->alignment_power = arch_align_power; + obj_bsssec (abfd)->alignment_power = arch_align_power; + } + + /* Don't set sizes now -- can't be sure until we know arch & mach. + Sizes get set in set_sizes callback, later. */ +#if 0 + adata(abfd).page_size = TARGET_PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = TARGET_PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + + return abfd->xvec; +} +#endif + +#ifndef MY_object_p +/* Finish up the reading of an a.out file header */ + +static const bfd_target * +MY(object_p) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; /* Raw exec header from file */ + struct internal_exec exec; /* Cleaned-up exec header */ + const bfd_target *target; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + +#ifdef SWAP_MAGIC + exec.a_info = SWAP_MAGIC (exec_bytes.e_info); +#else + exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); +#endif /* SWAP_MAGIC */ + + if (N_BADMAG (exec)) return 0; +#ifdef MACHTYPE_OK + if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0; +#endif + + NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec); + +#ifdef SWAP_MAGIC + /* swap_exec_header_in read in a_info with the wrong byte order */ + exec.a_info = SWAP_MAGIC (exec_bytes.e_info); +#endif /* SWAP_MAGIC */ + + target = NAME(aout,some_aout_object_p) (abfd, &exec, MY(callback)); + +#ifdef ENTRY_CAN_BE_ZERO + /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage) + * means that it isn't obvious if EXEC_P should be set. + * All of the following must be true for an executable: + * There must be no relocations, the bfd can be neither an + * archive nor an archive element, and the file must be executable. */ + + if (exec.a_trsize + exec.a_drsize == 0 + && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL) + { + struct stat buf; +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif + if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR)) + abfd->flags |= EXEC_P; + } +#endif /* ENTRY_CAN_BE_ZERO */ + + return target; +} +#define MY_object_p MY(object_p) +#endif + + +#ifndef MY_mkobject +static boolean +MY(mkobject) (abfd) + bfd *abfd; +{ + if (NAME(aout,mkobject)(abfd) == false) + return false; +#if 0 /* Sizes get set in set_sizes callback, later, after we know + the architecture and machine. */ + adata(abfd).page_size = TARGET_PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = TARGET_PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + return true; +} +#define MY_mkobject MY(mkobject) +#endif + +#ifndef MY_bfd_copy_private_section_data + +/* Copy private section data. This actually does nothing with the + sections. It copies the subformat field. We copy it here, because + we need to know whether this is a QMAGIC file before we set the + section contents, and copy_private_bfd_data is not called until + after the section contents have been set. */ + +/*ARGSUSED*/ +static boolean +MY_bfd_copy_private_section_data (ibfd, isec, obfd, osec) + bfd *ibfd; + asection *isec; + bfd *obfd; + asection *osec; +{ + if (bfd_get_flavour (obfd) == bfd_target_aout_flavour) + obj_aout_subformat (obfd) = obj_aout_subformat (ibfd); + return true; +} + +#endif + +/* Write an object file. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +#ifndef MY_write_object_contents +static boolean +MY(write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + WRITE_HEADERS(abfd, execp); + + return true; +} +#define MY_write_object_contents MY(write_object_contents) +#endif + +#ifndef MY_set_sizes +static boolean +MY(set_sizes) (abfd) + bfd *abfd; +{ + adata(abfd).page_size = TARGET_PAGE_SIZE; + +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = TARGET_PAGE_SIZE; +#endif + +#ifdef ZMAGIC_DISK_BLOCK_SIZE + adata(abfd).zmagic_disk_block_size = ZMAGIC_DISK_BLOCK_SIZE; +#else + adata(abfd).zmagic_disk_block_size = TARGET_PAGE_SIZE; +#endif + + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; +} +#define MY_set_sizes MY(set_sizes) +#endif + +#ifndef MY_exec_hdr_flags +#define MY_exec_hdr_flags 0 +#endif + +#ifndef MY_backend_data + +#ifndef MY_zmagic_contiguous +#define MY_zmagic_contiguous 0 +#endif +#ifndef MY_text_includes_header +#define MY_text_includes_header 0 +#endif +#ifndef MY_exec_header_not_counted +#define MY_exec_header_not_counted 0 +#endif +#ifndef MY_add_dynamic_symbols +#define MY_add_dynamic_symbols 0 +#endif +#ifndef MY_add_one_symbol +#define MY_add_one_symbol 0 +#endif +#ifndef MY_link_dynamic_object +#define MY_link_dynamic_object 0 +#endif +#ifndef MY_write_dynamic_symbol +#define MY_write_dynamic_symbol 0 +#endif +#ifndef MY_check_dynamic_reloc +#define MY_check_dynamic_reloc 0 +#endif +#ifndef MY_finish_dynamic_link +#define MY_finish_dynamic_link 0 +#endif + +static CONST struct aout_backend_data MY(backend_data) = { + MY_zmagic_contiguous, + MY_text_includes_header, + MY_exec_hdr_flags, + 0, /* text vma? */ + MY_set_sizes, + MY_exec_header_not_counted, + MY_add_dynamic_symbols, + MY_add_one_symbol, + MY_link_dynamic_object, + MY_write_dynamic_symbol, + MY_check_dynamic_reloc, + MY_finish_dynamic_link +}; +#define MY_backend_data &MY(backend_data) +#endif + +#ifndef MY_final_link_callback + +/* Callback for the final_link routine to set the section offsets. */ + +static void MY_final_link_callback + PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); + +static void +MY_final_link_callback (abfd, ptreloff, pdreloff, psymoff) + bfd *abfd; + file_ptr *ptreloff; + file_ptr *pdreloff; + file_ptr *psymoff; +{ + struct internal_exec *execp = exec_hdr (abfd); + + *ptreloff = N_TRELOFF (*execp); + *pdreloff = N_DRELOFF (*execp); + *psymoff = N_SYMOFF (*execp); +} + +#endif + +#ifndef MY_bfd_final_link + +/* Final link routine. We need to use a call back to get the correct + offsets in the output file. */ + +static boolean +MY_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return NAME(aout,final_link) (abfd, info, MY_final_link_callback); +} + +#endif + +/* We assume BFD generic archive files. */ +#ifndef MY_openr_next_archived_file +#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file +#endif +#ifndef MY_get_elt_at_index +#define MY_get_elt_at_index _bfd_generic_get_elt_at_index +#endif +#ifndef MY_generic_stat_arch_elt +#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt +#endif +#ifndef MY_slurp_armap +#define MY_slurp_armap bfd_slurp_bsd_armap +#endif +#ifndef MY_slurp_extended_name_table +#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table +#endif +#ifndef MY_construct_extended_name_table +#define MY_construct_extended_name_table \ + _bfd_archive_bsd_construct_extended_name_table +#endif +#ifndef MY_write_armap +#define MY_write_armap bsd_write_armap +#endif +#ifndef MY_read_ar_hdr +#define MY_read_ar_hdr _bfd_generic_read_ar_hdr +#endif +#ifndef MY_truncate_arname +#define MY_truncate_arname bfd_bsd_truncate_arname +#endif +#ifndef MY_update_armap_timestamp +#define MY_update_armap_timestamp _bfd_archive_bsd_update_armap_timestamp +#endif + +/* No core file defined here -- configure in trad-core.c separately. */ +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command _bfd_nocore_core_file_failing_command +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal _bfd_nocore_core_file_failing_signal +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p \ + _bfd_nocore_core_file_matches_executable_p +#endif +#ifndef MY_core_file_p +#define MY_core_file_p _bfd_dummy_target +#endif + +#ifndef MY_bfd_debug_info_start +#define MY_bfd_debug_info_start bfd_void +#endif +#ifndef MY_bfd_debug_info_end +#define MY_bfd_debug_info_end bfd_void +#endif +#ifndef MY_bfd_debug_info_accumulate +#define MY_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd*, struct sec *))) bfd_void +#endif + +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command NAME(aout,core_file_failing_command) +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal NAME(aout,core_file_failing_signal) +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p NAME(aout,core_file_matches_executable_p) +#endif +#ifndef MY_set_section_contents +#define MY_set_section_contents NAME(aout,set_section_contents) +#endif +#ifndef MY_get_section_contents +#define MY_get_section_contents NAME(aout,get_section_contents) +#endif +#ifndef MY_get_section_contents_in_window +#define MY_get_section_contents_in_window _bfd_generic_get_section_contents_in_window +#endif +#ifndef MY_new_section_hook +#define MY_new_section_hook NAME(aout,new_section_hook) +#endif +#ifndef MY_get_symtab_upper_bound +#define MY_get_symtab_upper_bound NAME(aout,get_symtab_upper_bound) +#endif +#ifndef MY_get_symtab +#define MY_get_symtab NAME(aout,get_symtab) +#endif +#ifndef MY_get_reloc_upper_bound +#define MY_get_reloc_upper_bound NAME(aout,get_reloc_upper_bound) +#endif +#ifndef MY_canonicalize_reloc +#define MY_canonicalize_reloc NAME(aout,canonicalize_reloc) +#endif +#ifndef MY_make_empty_symbol +#define MY_make_empty_symbol NAME(aout,make_empty_symbol) +#endif +#ifndef MY_print_symbol +#define MY_print_symbol NAME(aout,print_symbol) +#endif +#ifndef MY_get_symbol_info +#define MY_get_symbol_info NAME(aout,get_symbol_info) +#endif +#ifndef MY_get_lineno +#define MY_get_lineno NAME(aout,get_lineno) +#endif +#ifndef MY_set_arch_mach +#define MY_set_arch_mach NAME(aout,set_arch_mach) +#endif +#ifndef MY_find_nearest_line +#define MY_find_nearest_line NAME(aout,find_nearest_line) +#endif +#ifndef MY_sizeof_headers +#define MY_sizeof_headers NAME(aout,sizeof_headers) +#endif +#ifndef MY_bfd_get_relocated_section_contents +#define MY_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#endif +#ifndef MY_bfd_relax_section +#define MY_bfd_relax_section bfd_generic_relax_section +#endif +#ifndef MY_bfd_reloc_type_lookup +#define MY_bfd_reloc_type_lookup NAME(aout,reloc_type_lookup) +#endif +#ifndef MY_bfd_make_debug_symbol +#define MY_bfd_make_debug_symbol 0 +#endif +#ifndef MY_read_minisymbols +#define MY_read_minisymbols NAME(aout,read_minisymbols) +#endif +#ifndef MY_minisymbol_to_symbol +#define MY_minisymbol_to_symbol NAME(aout,minisymbol_to_symbol) +#endif +#ifndef MY_bfd_link_hash_table_create +#define MY_bfd_link_hash_table_create NAME(aout,link_hash_table_create) +#endif +#ifndef MY_bfd_link_add_symbols +#define MY_bfd_link_add_symbols NAME(aout,link_add_symbols) +#endif +#ifndef MY_bfd_link_split_section +#define MY_bfd_link_split_section _bfd_generic_link_split_section +#endif + + +#ifndef MY_bfd_copy_private_bfd_data +#define MY_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data +#endif + +#ifndef MY_bfd_merge_private_bfd_data +#define MY_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data +#endif + +#ifndef MY_bfd_copy_private_symbol_data +#define MY_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data +#endif + +#ifndef MY_bfd_print_private_bfd_data +#define MY_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data +#endif + +#ifndef MY_bfd_set_private_flags +#define MY_bfd_set_private_flags _bfd_generic_bfd_set_private_flags +#endif + +#ifndef MY_bfd_is_local_label +#define MY_bfd_is_local_label bfd_generic_is_local_label +#endif + +#ifndef MY_bfd_free_cached_info +#define MY_bfd_free_cached_info NAME(aout,bfd_free_cached_info) +#endif + +#ifndef MY_close_and_cleanup +#define MY_close_and_cleanup MY_bfd_free_cached_info +#endif + +#ifndef MY_get_dynamic_symtab_upper_bound +#define MY_get_dynamic_symtab_upper_bound \ + _bfd_nodynamic_get_dynamic_symtab_upper_bound +#endif +#ifndef MY_canonicalize_dynamic_symtab +#define MY_canonicalize_dynamic_symtab \ + _bfd_nodynamic_canonicalize_dynamic_symtab +#endif +#ifndef MY_get_dynamic_reloc_upper_bound +#define MY_get_dynamic_reloc_upper_bound \ + _bfd_nodynamic_get_dynamic_reloc_upper_bound +#endif +#ifndef MY_canonicalize_dynamic_reloc +#define MY_canonicalize_dynamic_reloc \ + _bfd_nodynamic_canonicalize_dynamic_reloc +#endif + +/* Aout symbols normally have leading underscores */ +#ifndef MY_symbol_leading_char +#define MY_symbol_leading_char '_' +#endif + +/* Aout archives normally use spaces for padding */ +#ifndef AR_PAD_CHAR +#define AR_PAD_CHAR ' ' +#endif + +#ifndef MY_BFD_TARGET +const bfd_target MY(vec) = +{ + TARGETNAME, /* name */ + bfd_target_aout_flavour, +#ifdef TARGET_IS_BIG_ENDIAN_P + BFD_ENDIAN_BIG, /* target byte order (big) */ + BFD_ENDIAN_BIG, /* target headers byte order (big) */ +#else + BFD_ENDIAN_LITTLE, /* target byte order (little) */ + BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ +#endif + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + AR_PAD_CHAR, /* ar_pad_char */ + 15, /* ar_max_namelen */ +#ifdef TARGET_IS_BIG_ENDIAN_P + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ +#else + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ +#endif + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (MY), + BFD_JUMP_TABLE_COPY (MY), + BFD_JUMP_TABLE_CORE (MY), + BFD_JUMP_TABLE_ARCHIVE (MY), + BFD_JUMP_TABLE_SYMBOLS (MY), + BFD_JUMP_TABLE_RELOCS (MY), + BFD_JUMP_TABLE_WRITE (MY), + BFD_JUMP_TABLE_LINK (MY), + BFD_JUMP_TABLE_DYNAMIC (MY), + + (PTR) MY_backend_data, +}; +#endif /* MY_BFD_TARGET */ diff --git a/contrib/gdb/bfd/aout0.c b/contrib/gdb/bfd/aout0.c new file mode 100644 index 000000000000..5bc7ae0f67f8 --- /dev/null +++ b/contrib/gdb/bfd/aout0.c @@ -0,0 +1,32 @@ +/* BFD backend for SunOS style a.out with flags set to 0 + Copyright (C) 1990, 91, 92, 93, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGETNAME "a.out-zero-big" +#define MY(OP) CAT(aout0_big_,OP) + +#include "bfd.h" + +#define MY_exec_hdr_flags 0 + +#define MACHTYPE_OK(mtype) \ + ((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) + +/* Include the usual a.out support. */ +#include "aoutf1.h" diff --git a/contrib/gdb/bfd/aout32.c b/contrib/gdb/bfd/aout32.c new file mode 100644 index 000000000000..bfc40b46303b --- /dev/null +++ b/contrib/gdb/bfd/aout32.c @@ -0,0 +1,23 @@ +/* BFD back-end for 32-bit a.out files. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 32 + +#include "aoutx.h" diff --git a/contrib/gdb/bfd/aout64.c b/contrib/gdb/bfd/aout64.c new file mode 100644 index 000000000000..84036c885a29 --- /dev/null +++ b/contrib/gdb/bfd/aout64.c @@ -0,0 +1,31 @@ +/* BFD back-end for 64-bit a.out files. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 64 + +/* aoutx.h requires definitions for BMAGIC and QMAGIC. */ +#ifndef BMAGIC +#define BMAGIC 0 +#endif +#ifndef QMAGIC +#define QMAGIC 0 +#endif + +#include "aoutx.h" diff --git a/contrib/gdb/bfd/aoutf1.h b/contrib/gdb/bfd/aoutf1.h new file mode 100644 index 000000000000..690d528b5c44 --- /dev/null +++ b/contrib/gdb/bfd/aoutf1.h @@ -0,0 +1,788 @@ +/* A.out "format 1" file handling code for BFD. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include "aout/sun4.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" + +/* This is needed to reject a NewsOS file, e.g. in + gdb/testsuite/gdb.t10/crossload.exp. + I needed to add M_UNKNOWN to recognize a 68000 object, so this will + probably no longer reject a NewsOS object. . */ +#ifndef MACHTYPE_OK +#define MACHTYPE_OK(mtype) \ + (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \ + || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \ + && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL)) +#endif + +/* +The file @code{aoutf1.h} contains the code for BFD's +a.out back end. Control over the generated back end is given by these +two preprocessor names: +@table @code +@item ARCH_SIZE +This value should be either 32 or 64, depending upon the size of an +int in the target format. It changes the sizes of the structs which +perform the memory/disk mapping of structures. + +The 64 bit backend may only be used if the host compiler supports 64 +ints (eg long long with gcc), by defining the name @code{BFD_HOST_64_BIT} in @code{bfd.h}. +With this name defined, @emph{all} bfd operations are performed with 64bit +arithmetic, not just those to a 64bit target. + +@item TARGETNAME +The name put into the target vector. +@item +@end table + +*/ + +/*SUPPRESS558*/ +/*SUPPRESS529*/ + +static void +#if ARCH_SIZE == 64 +sunos_64_set_arch_mach +#else +sunos_32_set_arch_mach +#endif + (abfd, machtype) + bfd *abfd; + int machtype; +{ + /* Determine the architecture and machine type of the object file. */ + enum bfd_architecture arch; + long machine; + switch (machtype) + { + + case M_UNKNOWN: + /* Some Sun3s make magic numbers without cpu types in them, so + we'll default to the 68000. */ + arch = bfd_arch_m68k; + machine = 68000; + break; + + case M_68010: + case M_HP200: + arch = bfd_arch_m68k; + machine = 68010; + break; + + case M_68020: + case M_HP300: + arch = bfd_arch_m68k; + machine = 68020; + break; + + case M_SPARC: + arch = bfd_arch_sparc; + machine = 0; + break; + + case M_386: + case M_386_DYNIX: + arch = bfd_arch_i386; + machine = 0; + break; + + case M_29K: + arch = bfd_arch_a29k; + machine = 0; + break; + + case M_HPUX: + arch = bfd_arch_m68k; + machine = 0; + break; + + default: + arch = bfd_arch_obscure; + machine = 0; + break; + } + bfd_set_arch_mach (abfd, arch, machine); +} + +#define SET_ARCH_MACH(ABFD, EXEC) \ + NAME(sunos,set_arch_mach)(ABFD, N_MACHTYPE (EXEC)); \ + choose_reloc_size(ABFD); + +/* Determine the size of a relocation entry, based on the architecture */ +static void +choose_reloc_size (abfd) + bfd *abfd; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_sparc: + case bfd_arch_a29k: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } +} + +/* Write an object file in SunOS format. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +static boolean +#if ARCH_SIZE == 64 +aout_64_sunos4_write_object_contents +#else +aout_32_sunos4_write_object_contents +#endif + (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + + /* Magic number, maestro, please! */ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + switch (bfd_get_mach (abfd)) + { + case 68000: + N_SET_MACHTYPE (*execp, M_UNKNOWN); + break; + case 68010: + N_SET_MACHTYPE (*execp, M_68010); + break; + default: + case 68020: + N_SET_MACHTYPE (*execp, M_68020); + break; + } + break; + case bfd_arch_sparc: + N_SET_MACHTYPE (*execp, M_SPARC); + break; + case bfd_arch_i386: + N_SET_MACHTYPE (*execp, M_386); + break; + case bfd_arch_a29k: + N_SET_MACHTYPE (*execp, M_29K); + break; + default: + N_SET_MACHTYPE (*execp, M_UNKNOWN); + } + + choose_reloc_size (abfd); + + N_SET_FLAGS (*execp, aout_backend_info (abfd)->exec_hdr_flags); + + N_SET_DYNAMIC (*execp, bfd_get_file_flags (abfd) & DYNAMIC); + + WRITE_HEADERS (abfd, execp); + + return true; +} + +/* core files */ + +#define CORE_MAGIC 0x080456 +#define CORE_NAMELEN 16 + +/* The core structure is taken from the Sun documentation. + Unfortunately, they don't document the FPA structure, or at least I + can't find it easily. Fortunately the core header contains its own + length. So this shouldn't cause problems, except for c_ucode, which + so far we don't use but is easy to find with a little arithmetic. */ + +/* But the reg structure can be gotten from the SPARC processor handbook. + This really should be in a GNU include file though so that gdb can use + the same info. */ +struct regs +{ + int r_psr; + int r_pc; + int r_npc; + int r_y; + int r_g1; + int r_g2; + int r_g3; + int r_g4; + int r_g5; + int r_g6; + int r_g7; + int r_o0; + int r_o1; + int r_o2; + int r_o3; + int r_o4; + int r_o5; + int r_o6; + int r_o7; +}; + +/* Taken from Sun documentation: */ + +/* FIXME: It's worse than we expect. This struct contains TWO substructs + neither of whose size we know, WITH STUFF IN BETWEEN THEM! We can't + even portably access the stuff in between! */ + +struct external_sparc_core + { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ +#define SPARC_CORE_LEN 432 + int c_regs[19]; /* General purpose registers -- MACHDEP SIZE */ + struct external_exec c_aouthdr; /* A.out header */ + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + int c_ssize; /* Stack size (bytes) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + double fp_stuff[1]; /* external FPU state (size unknown by us) */ + /* The type "double" is critical here, for alignment. + SunOS declares a struct here, but the struct's alignment + is double since it contains doubles. */ + int c_ucode; /* Exception no. from u_code */ + /* (this member is not accessible by name since we don't + portably know the size of fp_stuff.) */ + }; + +/* Core files generated by the BCP (the part of Solaris which allows + it to run SunOS4 a.out files). */ +struct external_solaris_bcp_core + { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ +#define SOLARIS_BCP_CORE_LEN 456 + int c_regs[19]; /* General purpose registers -- MACHDEP SIZE */ + int c_exdata_vp; /* exdata structure */ + int c_exdata_tsize; + int c_exdata_dsize; + int c_exdata_bsize; + int c_exdata_lsize; + int c_exdata_nshlibs; + short c_exdata_mach; + short c_exdata_mag; + int c_exdata_toffset; + int c_exdata_doffset; + int c_exdata_loffset; + int c_exdata_txtorg; + int c_exdata_datorg; + int c_exdata_entloc; + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + int c_ssize; /* Stack size (bytes) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + double fp_stuff[1]; /* external FPU state (size unknown by us) */ + /* The type "double" is critical here, for alignment. + SunOS declares a struct here, but the struct's alignment + is double since it contains doubles. */ + int c_ucode; /* Exception no. from u_code */ + /* (this member is not accessible by name since we don't + portably know the size of fp_stuff.) */ + }; + +struct external_sun3_core + { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ +#define SUN3_CORE_LEN 826 /* As of SunOS 4.1.1 */ + int c_regs[18]; /* General purpose registers -- MACHDEP SIZE */ + struct external_exec c_aouthdr; /* A.out header */ + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + int c_ssize; /* Stack size (bytes) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + double fp_stuff[1]; /* external FPU state (size unknown by us) */ + /* The type "double" is critical here, for alignment. + SunOS declares a struct here, but the struct's alignment + is double since it contains doubles. */ + int c_ucode; /* Exception no. from u_code */ + /* (this member is not accessible by name since we don't + portably know the size of fp_stuff.) */ + }; + +struct internal_sunos_core + { + int c_magic; /* Corefile magic number */ + int c_len; /* Sizeof (struct core) */ + long c_regs_pos; /* file offset of General purpose registers */ + int c_regs_size; /* size of General purpose registers */ + struct internal_exec c_aouthdr; /* A.out header */ + int c_signo; /* Killing signal, if any */ + int c_tsize; /* Text size (bytes) */ + int c_dsize; /* Data size (bytes) */ + bfd_vma c_data_addr; /* Data start (address) */ + int c_ssize; /* Stack size (bytes) */ + bfd_vma c_stacktop; /* Stack top (address) */ + char c_cmdname[CORE_NAMELEN + 1]; /* Command name */ + long fp_stuff_pos; /* file offset of external FPU state (regs) */ + int fp_stuff_size; /* Size of it */ + int c_ucode; /* Exception no. from u_code */ + }; + +/* byte-swap in the Sun-3 core structure */ +static void +swapcore_sun3 (abfd, ext, intcore) + bfd *abfd; + char *ext; + struct internal_sunos_core *intcore; +{ + struct external_sun3_core *extcore = (struct external_sun3_core *) ext; + + intcore->c_magic = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_magic); + intcore->c_len = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_len); + intcore->c_regs_pos = (long) (((struct external_sun3_core *) 0)->c_regs); + intcore->c_regs_size = sizeof (extcore->c_regs); +#if ARCH_SIZE == 64 + aout_64_swap_exec_header_in +#else + aout_32_swap_exec_header_in +#endif + (abfd, &extcore->c_aouthdr, &intcore->c_aouthdr); + intcore->c_signo = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_signo); + intcore->c_tsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_tsize); + intcore->c_dsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_dsize); + intcore->c_data_addr = N_DATADDR (intcore->c_aouthdr); + intcore->c_ssize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_ssize); + memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); + intcore->fp_stuff_pos = (long) (((struct external_sun3_core *) 0)->fp_stuff); + /* FP stuff takes up whole rest of struct, except c_ucode. */ + intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - + (file_ptr) (((struct external_sun3_core *) 0)->fp_stuff); + /* Ucode is the last thing in the struct -- just before the end */ + intcore->c_ucode = + bfd_h_get_32 (abfd, + intcore->c_len - sizeof (extcore->c_ucode) + (unsigned char *) extcore); + intcore->c_stacktop = 0x0E000000; /* By experimentation */ +} + + +/* byte-swap in the Sparc core structure */ +static void +swapcore_sparc (abfd, ext, intcore) + bfd *abfd; + char *ext; + struct internal_sunos_core *intcore; +{ + struct external_sparc_core *extcore = (struct external_sparc_core *) ext; + + intcore->c_magic = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_magic); + intcore->c_len = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_len); + intcore->c_regs_pos = (long) (((struct external_sparc_core *) 0)->c_regs); + intcore->c_regs_size = sizeof (extcore->c_regs); +#if ARCH_SIZE == 64 + aout_64_swap_exec_header_in +#else + aout_32_swap_exec_header_in +#endif + (abfd, &extcore->c_aouthdr, &intcore->c_aouthdr); + intcore->c_signo = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_signo); + intcore->c_tsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_tsize); + intcore->c_dsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_dsize); + intcore->c_data_addr = N_DATADDR (intcore->c_aouthdr); + intcore->c_ssize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_ssize); + memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); + intcore->fp_stuff_pos = (long) (((struct external_sparc_core *) 0)->fp_stuff); + /* FP stuff takes up whole rest of struct, except c_ucode. */ + intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - + (file_ptr) (((struct external_sparc_core *) 0)->fp_stuff); + /* Ucode is the last thing in the struct -- just before the end */ + intcore->c_ucode = + bfd_h_get_32 (abfd, + intcore->c_len - sizeof (extcore->c_ucode) + (unsigned char *) extcore); + + /* Supposedly the user stack grows downward from the bottom of kernel memory. + Presuming that this remains true, this definition will work. */ + /* Now sun has provided us with another challenge. The value is different + for sparc2 and sparc10 (both running SunOS 4.1.3). We pick one or + the other based on the current value of the stack pointer. This + loses (a) if the stack pointer has been clobbered, or (b) if the stack + is larger than 128 megabytes. + + It's times like these you're glad they're switching to ELF. + + Note that using include files or nlist on /vmunix would be wrong, + because we want the value for this core file, no matter what kind of + machine we were compiled on or are running on. */ +#define SPARC_USRSTACK_SPARC2 ((bfd_vma)0xf8000000) +#define SPARC_USRSTACK_SPARC10 ((bfd_vma)0xf0000000) + { + bfd_vma sp = bfd_h_get_32 + (abfd, (unsigned char *) &((struct regs *) &extcore->c_regs[0])->r_o6); + if (sp < SPARC_USRSTACK_SPARC10) + intcore->c_stacktop = SPARC_USRSTACK_SPARC10; + else + intcore->c_stacktop = SPARC_USRSTACK_SPARC2; + } +} + +/* byte-swap in the Solaris BCP core structure */ +static void +swapcore_solaris_bcp (abfd, ext, intcore) + bfd *abfd; + char *ext; + struct internal_sunos_core *intcore; +{ + struct external_solaris_bcp_core *extcore = + (struct external_solaris_bcp_core *) ext; + + intcore->c_magic = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_magic); + intcore->c_len = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_len); + intcore->c_regs_pos = (long) (((struct external_solaris_bcp_core *) 0)->c_regs); + intcore->c_regs_size = sizeof (extcore->c_regs); + + /* The Solaris BCP exdata structure does not contain an a_syms field, + so we are unable to synthesize an internal exec header. + Luckily we are able to figure out the start address of the data section, + which is the only thing needed from the internal exec header, + from the exdata structure. + + As of Solaris 2.3, BCP core files for statically linked executables + are buggy. The exdata structure is not properly filled in, and + the data section is written from address zero instead of the data + start address. */ + memset ((PTR) &intcore->c_aouthdr, 0, sizeof (struct internal_exec)); + intcore->c_data_addr = + bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_exdata_datorg); + intcore->c_signo = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_signo); + intcore->c_tsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_tsize); + intcore->c_dsize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_dsize); + intcore->c_ssize = bfd_h_get_32 (abfd, (unsigned char *) &extcore->c_ssize); + memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); + intcore->fp_stuff_pos = + (long) (((struct external_solaris_bcp_core *) 0)->fp_stuff); + /* FP stuff takes up whole rest of struct, except c_ucode. */ + intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - + (file_ptr) (((struct external_solaris_bcp_core *) 0)->fp_stuff); + /* Ucode is the last thing in the struct -- just before the end */ + intcore->c_ucode = + bfd_h_get_32 (abfd, + intcore->c_len - sizeof (extcore->c_ucode) + (unsigned char *) extcore); + + /* Supposedly the user stack grows downward from the bottom of kernel memory. + Presuming that this remains true, this definition will work. */ + /* Now sun has provided us with another challenge. The value is different + for sparc2 and sparc10 (both running SunOS 4.1.3). We pick one or + the other based on the current value of the stack pointer. This + loses (a) if the stack pointer has been clobbered, or (b) if the stack + is larger than 128 megabytes. + + It's times like these you're glad they're switching to ELF. + + Note that using include files or nlist on /vmunix would be wrong, + because we want the value for this core file, no matter what kind of + machine we were compiled on or are running on. */ +#define SPARC_USRSTACK_SPARC2 ((bfd_vma)0xf8000000) +#define SPARC_USRSTACK_SPARC10 ((bfd_vma)0xf0000000) + { + bfd_vma sp = bfd_h_get_32 + (abfd, (unsigned char *) &((struct regs *) &extcore->c_regs[0])->r_o6); + if (sp < SPARC_USRSTACK_SPARC10) + intcore->c_stacktop = SPARC_USRSTACK_SPARC10; + else + intcore->c_stacktop = SPARC_USRSTACK_SPARC2; + } +} + +/* need this cast because ptr is really void * */ +#define core_hdr(bfd) ((bfd)->tdata.sun_core_data) +#define core_datasec(bfd) (core_hdr(bfd)->data_section) +#define core_stacksec(bfd) (core_hdr(bfd)->stack_section) +#define core_regsec(bfd) (core_hdr(bfd)->reg_section) +#define core_reg2sec(bfd) (core_hdr(bfd)->reg2_section) + +/* These are stored in the bfd's tdata */ +struct sun_core_struct +{ + struct internal_sunos_core *hdr; /* core file header */ + asection *data_section; + asection *stack_section; + asection *reg_section; + asection *reg2_section; +}; + +static const bfd_target * +sunos4_core_file_p (abfd) + bfd *abfd; +{ + unsigned char longbuf[4]; /* Raw bytes of various header fields */ + bfd_size_type core_size; + unsigned long core_mag; + struct internal_sunos_core *core; + char *extcore; + struct mergem + { + struct sun_core_struct suncoredata; + struct internal_sunos_core internal_sunos_core; + char external_core[1]; + } + *mergem; + + if (bfd_read ((PTR) longbuf, 1, sizeof (longbuf), abfd) != + sizeof (longbuf)) + return 0; + core_mag = bfd_h_get_32 (abfd, longbuf); + + if (core_mag != CORE_MAGIC) + return 0; + + /* SunOS core headers can vary in length; second word is size; */ + if (bfd_read ((PTR) longbuf, 1, sizeof (longbuf), abfd) != + sizeof (longbuf)) + return 0; + core_size = bfd_h_get_32 (abfd, longbuf); + /* Sanity check */ + if (core_size > 20000) + return 0; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) < 0) + return 0; + + mergem = (struct mergem *) bfd_zalloc (abfd, core_size + sizeof (struct mergem)); + if (mergem == NULL) + return 0; + + extcore = mergem->external_core; + + if ((bfd_read ((PTR) extcore, 1, core_size, abfd)) != core_size) + { + bfd_release (abfd, (char *) mergem); + return 0; + } + + /* Validate that it's a core file we know how to handle, due to sun + botching the positioning of registers and other fields in a machine + dependent way. */ + core = &mergem->internal_sunos_core; + switch (core_size) + { + case SPARC_CORE_LEN: + swapcore_sparc (abfd, extcore, core); + break; + case SUN3_CORE_LEN: + swapcore_sun3 (abfd, extcore, core); + break; + case SOLARIS_BCP_CORE_LEN: + swapcore_solaris_bcp (abfd, extcore, core); + break; + default: + bfd_set_error (bfd_error_system_call); /* FIXME */ + bfd_release (abfd, (char *) mergem); + return 0; + } + + abfd->tdata.sun_core_data = &mergem->suncoredata; + abfd->tdata.sun_core_data->hdr = core; + + /* create the sections. This is raunchy, but bfd_close wants to reclaim + them */ + core_stacksec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_stacksec (abfd) == NULL) + { + loser: + bfd_release (abfd, (char *) mergem); + return 0; + } + core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_datasec (abfd) == NULL) + { + loser1: + bfd_release (abfd, core_stacksec (abfd)); + goto loser; + } + core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_regsec (abfd) == NULL) + { + loser2: + bfd_release (abfd, core_datasec (abfd)); + goto loser1; + } + core_reg2sec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_reg2sec (abfd) == NULL) + { + bfd_release (abfd, core_regsec (abfd)); + goto loser2; + } + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + core_reg2sec (abfd)->name = ".reg2"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_regsec (abfd)->flags = SEC_HAS_CONTENTS; + core_reg2sec (abfd)->flags = SEC_HAS_CONTENTS; + + core_stacksec (abfd)->_raw_size = core->c_ssize; + core_datasec (abfd)->_raw_size = core->c_dsize; + core_regsec (abfd)->_raw_size = core->c_regs_size; + core_reg2sec (abfd)->_raw_size = core->fp_stuff_size; + + core_stacksec (abfd)->vma = (core->c_stacktop - core->c_ssize); + core_datasec (abfd)->vma = core->c_data_addr; + core_regsec (abfd)->vma = 0; + core_reg2sec (abfd)->vma = 0; + + core_stacksec (abfd)->filepos = core->c_len + core->c_dsize; + core_datasec (abfd)->filepos = core->c_len; + /* We'll access the regs afresh in the core file, like any section: */ + core_regsec (abfd)->filepos = (file_ptr) core->c_regs_pos; + core_reg2sec (abfd)->filepos = (file_ptr) core->fp_stuff_pos; + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + core_reg2sec (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + core_regsec (abfd)->next = core_reg2sec (abfd); + + abfd->section_count = 4; + + return abfd->xvec; +} + +static char * +sunos4_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->hdr->c_cmdname; +} + +static int +sunos4_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_hdr (abfd)->hdr->c_signo; +} + +static boolean +sunos4_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + if (core_bfd->xvec != exec_bfd->xvec) + { + bfd_set_error (bfd_error_system_call); + return false; + } + + /* Solaris core files do not include an aouthdr. */ + if ((core_hdr (core_bfd)->hdr)->c_len == SOLARIS_BCP_CORE_LEN) + return true; + + return (memcmp ((char *) &((core_hdr (core_bfd)->hdr)->c_aouthdr), + (char *) exec_hdr (exec_bfd), + sizeof (struct internal_exec)) == 0) ? true : false; +} + +#define MY_set_sizes sunos4_set_sizes +static boolean +sunos4_set_sizes (abfd) + bfd *abfd; +{ + switch (bfd_get_arch (abfd)) + { + default: + return false; + case bfd_arch_sparc: + adata (abfd).page_size = 0x2000; + adata (abfd).segment_size = 0x2000; + adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; + case bfd_arch_m68k: + adata (abfd).page_size = 0x2000; + adata (abfd).segment_size = 0x20000; + adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; + } +} + +/* We default to setting the toolversion field to 1, as is required by + SunOS. */ +#ifndef MY_exec_hdr_flags +#define MY_exec_hdr_flags 1 +#endif + +#ifndef MY_add_dynamic_symbols +#define MY_add_dynamic_symbols 0 +#endif +#ifndef MY_add_one_symbol +#define MY_add_one_symbol 0 +#endif +#ifndef MY_link_dynamic_object +#define MY_link_dynamic_object 0 +#endif +#ifndef MY_write_dynamic_symbol +#define MY_write_dynamic_symbol 0 +#endif +#ifndef MY_check_dynamic_reloc +#define MY_check_dynamic_reloc 0 +#endif +#ifndef MY_finish_dynamic_link +#define MY_finish_dynamic_link 0 +#endif + +static CONST struct aout_backend_data sunos4_aout_backend = +{ + 0, /* zmagic files are not contiguous */ + 1, /* text includes header */ + MY_exec_hdr_flags, + 0, /* default text vma */ + sunos4_set_sizes, + 0, /* header is counted in zmagic text */ + MY_add_dynamic_symbols, + MY_add_one_symbol, + MY_link_dynamic_object, + MY_write_dynamic_symbol, + MY_check_dynamic_reloc, + MY_finish_dynamic_link +}; + +#define MY_core_file_failing_command sunos4_core_file_failing_command +#define MY_core_file_failing_signal sunos4_core_file_failing_signal +#define MY_core_file_matches_executable_p sunos4_core_file_matches_executable_p + +#define MY_bfd_debug_info_start bfd_void +#define MY_bfd_debug_info_end bfd_void +#define MY_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd *, struct sec *))) bfd_void +#define MY_core_file_p sunos4_core_file_p +#define MY_write_object_contents NAME(aout,sunos4_write_object_contents) +#define MY_backend_data &sunos4_aout_backend + +#define TARGET_IS_BIG_ENDIAN_P + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/aoutx.h b/contrib/gdb/bfd/aoutx.h new file mode 100644 index 000000000000..4b04943e028b --- /dev/null +++ b/contrib/gdb/bfd/aoutx.h @@ -0,0 +1,5525 @@ +/* BFD semi-generic back-end for a.out binaries. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + a.out backends + + +DESCRIPTION + + BFD supports a number of different flavours of a.out format, + though the major differences are only the sizes of the + structures on disk, and the shape of the relocation + information. + + The support is split into a basic support file @file{aoutx.h} + and other files which derive functions from the base. One + derivation file is @file{aoutf1.h} (for a.out flavour 1), and + adds to the basic a.out functions support for sun3, sun4, 386 + and 29k a.out files, to create a target jump vector for a + specific target. + + This information is further split out into more specific files + for each machine, including @file{sunos.c} for sun3 and sun4, + @file{newsos3.c} for the Sony NEWS, and @file{demo64.c} for a + demonstration of a 64 bit a.out format. + + The base file @file{aoutx.h} defines general mechanisms for + reading and writing records to and from disk and various + other methods which BFD requires. It is included by + @file{aout32.c} and @file{aout64.c} to form the names + <>, <>, etc. + + As an example, this is what goes on to make the back end for a + sun4, from @file{aout32.c}: + +| #define ARCH_SIZE 32 +| #include "aoutx.h" + + Which exports names: + +| ... +| aout_32_canonicalize_reloc +| aout_32_find_nearest_line +| aout_32_get_lineno +| aout_32_get_reloc_upper_bound +| ... + + from @file{sunos.c}: + +| #define TARGET_NAME "a.out-sunos-big" +| #define VECNAME sunos_big_vec +| #include "aoutf1.h" + + requires all the names from @file{aout32.c}, and produces the jump vector + +| sunos_big_vec + + The file @file{host-aout.c} is a special case. It is for a large set + of hosts that use ``more or less standard'' a.out files, and + for which cross-debugging is not interesting. It uses the + standard 32-bit a.out support routines, but determines the + file offsets and addresses of the text, data, and BSS + sections, the machine architecture and machine type, and the + entry point address, in a host-dependent manner. Once these + values have been determined, generic code is used to handle + the object file. + + When porting it to run on a new system, you must supply: + +| HOST_PAGE_SIZE +| HOST_SEGMENT_SIZE +| HOST_MACHINE_ARCH (optional) +| HOST_MACHINE_MACHINE (optional) +| HOST_TEXT_START_ADDR +| HOST_STACK_END_ADDR + + in the file @file{../include/sys/h-@var{XXX}.h} (for your host). These + values, plus the structures and macros defined in @file{a.out.h} on + your host system, will produce a BFD target that will access + ordinary a.out files on your host. To configure a new machine + to use @file{host-aout.c}, specify: + +| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec +| TDEPFILES= host-aout.o trad-core.o + + in the @file{config/@var{XXX}.mt} file, and modify @file{configure.in} + to use the + @file{@var{XXX}.mt} file (by setting "<>") when your + configuration is selected. + +*/ + +/* Some assumptions: + * Any BFD with D_PAGED set is ZMAGIC, and vice versa. + Doesn't matter what the setting of WP_TEXT is on output, but it'll + get set on input. + * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC. + * Any BFD with both flags clear is OMAGIC. + (Just want to make these explicit, so the conditions tested in this + file make sense if you're more familiar with a.out than with BFD.) */ + +#define KEEPIT udata.i + +#include /* For strchr and friends */ +#include +#include "bfd.h" +#include +#include "bfdlink.h" + +#include "libaout.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" + +static boolean aout_get_external_symbols PARAMS ((bfd *)); +static boolean translate_from_native_sym_flags + PARAMS ((bfd *, aout_symbol_type *)); +static boolean translate_to_native_sym_flags + PARAMS ((bfd *, asymbol *, struct external_nlist *)); + +/* +SUBSECTION + Relocations + +DESCRIPTION + The file @file{aoutx.h} provides for both the @emph{standard} + and @emph{extended} forms of a.out relocation records. + + The standard records contain only an + address, a symbol index, and a type field. The extended records + (used on 29ks and sparcs) also have a full integer for an + addend. + +*/ +#ifndef CTOR_TABLE_RELOC_HOWTO +#define CTOR_TABLE_RELOC_IDX 2 +#define CTOR_TABLE_RELOC_HOWTO(BFD) ((obj_reloc_entry_size(BFD) == RELOC_EXT_SIZE \ + ? howto_table_ext : howto_table_std) \ + + CTOR_TABLE_RELOC_IDX) +#endif + +#ifndef MY_swap_std_reloc_in +#define MY_swap_std_reloc_in NAME(aout,swap_std_reloc_in) +#endif + +#ifndef MY_swap_std_reloc_out +#define MY_swap_std_reloc_out NAME(aout,swap_std_reloc_out) +#endif + +#ifndef MY_final_link_relocate +#define MY_final_link_relocate _bfd_final_link_relocate +#endif + +#ifndef MY_relocate_contents +#define MY_relocate_contents _bfd_relocate_contents +#endif + +#define howto_table_ext NAME(aout,ext_howto_table) +#define howto_table_std NAME(aout,std_howto_table) + +reloc_howto_type howto_table_ext[] = +{ + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ + HOWTO(RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", false, 0,0x000000ff, false), + HOWTO(RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", false, 0,0x0000ffff, false), + HOWTO(RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", false, 0,0xffffffff, false), + HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, complain_overflow_signed,0,"DISP8", false, 0,0x000000ff, false), + HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, complain_overflow_signed,0,"DISP16", false, 0,0x0000ffff, false), + HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, complain_overflow_signed,0,"DISP32", false, 0,0xffffffff, false), + HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, complain_overflow_signed,0,"WDISP30", false, 0,0x3fffffff, false), + HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, complain_overflow_signed,0,"WDISP22", false, 0,0x003fffff, false), + HOWTO(RELOC_HI22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"HI22", false, 0,0x003fffff, false), + HOWTO(RELOC_22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"22", false, 0,0x003fffff, false), + HOWTO(RELOC_13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"13", false, 0,0x00001fff, false), + HOWTO(RELOC_LO10, 0, 2, 10, false, 0, complain_overflow_dont,0,"LO10", false, 0,0x000003ff, false), + HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false), + HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false), + HOWTO(RELOC_BASE10, 0, 2, 10, false, 0, complain_overflow_dont,0,"BASE10", false, 0,0x000003ff, false), + HOWTO(RELOC_BASE13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"BASE13", false, 0,0x00001fff, false), + HOWTO(RELOC_BASE22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"BASE22", false, 0,0x003fffff, false), + HOWTO(RELOC_PC10, 0, 2, 10, true, 0, complain_overflow_dont,0,"PC10", false, 0,0x000003ff, true), + HOWTO(RELOC_PC22, 10, 2, 22, true, 0, complain_overflow_signed,0,"PC22", false, 0,0x003fffff, true), + HOWTO(RELOC_JMP_TBL,2, 2, 30, true, 0, complain_overflow_signed,0,"JMP_TBL", false, 0,0x3fffffff, false), + HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, complain_overflow_bitfield,0,"SEGOFF16", false, 0,0x00000000, false), + HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"GLOB_DAT", false, 0,0x00000000, false), + HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_SLOT", false, 0,0x00000000, false), + HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false), +}; + +/* Convert standard reloc records to "arelent" format (incl byte swap). */ + +reloc_howto_type howto_table_std[] = { + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ +HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false), +HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false), +HOWTO( 3, 0, 4, 64, false, 0, complain_overflow_bitfield,0,"64", true, 0xdeaddead,0xdeaddead, false), +HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, false), +HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, false), +HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", true, 0xfeedface,0xfeedface, false), +HOWTO( 8, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"GOT_REL", false, 0,0x00000000, false), +HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false), +HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, + HOWTO(16, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false, 0,0x00000000, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, + HOWTO(32, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, + HOWTO(40, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASEREL", false, 0,0x00000000, false), +}; + +#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0])) + +reloc_howto_type * +NAME(aout,reloc_type_lookup) (abfd,code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ +#define EXT(i,j) case i: return &howto_table_ext[j] +#define STD(i,j) case i: return &howto_table_std[j] + int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE; + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + case 64: + code = BFD_RELOC_64; + break; + } + if (ext) + switch (code) + { + EXT (BFD_RELOC_32, 2); + EXT (BFD_RELOC_HI22, 8); + EXT (BFD_RELOC_LO10, 11); + EXT (BFD_RELOC_32_PCREL_S2, 6); + EXT (BFD_RELOC_SPARC_WDISP22, 7); + EXT (BFD_RELOC_SPARC13, 10); + EXT (BFD_RELOC_SPARC_GOT10, 14); + EXT (BFD_RELOC_SPARC_BASE13, 15); + EXT (BFD_RELOC_SPARC_GOT13, 15); + EXT (BFD_RELOC_SPARC_GOT22, 16); + EXT (BFD_RELOC_SPARC_PC10, 17); + EXT (BFD_RELOC_SPARC_PC22, 18); + EXT (BFD_RELOC_SPARC_WPLT30, 19); + default: return (reloc_howto_type *) NULL; + } + else + /* std relocs */ + switch (code) + { + STD (BFD_RELOC_16, 1); + STD (BFD_RELOC_32, 2); + STD (BFD_RELOC_8_PCREL, 4); + STD (BFD_RELOC_16_PCREL, 5); + STD (BFD_RELOC_32_PCREL, 6); + STD (BFD_RELOC_16_BASEREL, 9); + STD (BFD_RELOC_32_BASEREL, 10); + default: return (reloc_howto_type *) NULL; + } +} + +/* +SUBSECTION + Internal entry points + +DESCRIPTION + @file{aoutx.h} exports several routines for accessing the + contents of an a.out file, which are gathered and exported in + turn by various format specific files (eg sunos.c). + +*/ + +/* +FUNCTION + aout_@var{size}_swap_exec_header_in + +SYNOPSIS + void aout_@var{size}_swap_exec_header_in, + (bfd *abfd, + struct external_exec *raw_bytes, + struct internal_exec *execp); + +DESCRIPTION + Swap the information in an executable header @var{raw_bytes} taken + from a raw byte stream memory image into the internal exec header + structure @var{execp}. +*/ + +#ifndef NAME_swap_exec_header_in +void +NAME(aout,swap_exec_header_in) (abfd, raw_bytes, execp) + bfd *abfd; + struct external_exec *raw_bytes; + struct internal_exec *execp; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* The internal_exec structure has some fields that are unused in this + configuration (IE for i960), so ensure that all such uninitialized + fields are zero'd out. There are places where two of these structs + are memcmp'd, and thus the contents do matter. */ + memset ((PTR) execp, 0, sizeof (struct internal_exec)); + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); +} +#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in) +#endif + +/* +FUNCTION + aout_@var{size}_swap_exec_header_out + +SYNOPSIS + void aout_@var{size}_swap_exec_header_out + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes); + +DESCRIPTION + Swap the information in an internal exec header structure + @var{execp} into the buffer @var{raw_bytes} ready for writing to disk. +*/ +void +NAME(aout,swap_exec_header_out) (abfd, execp, raw_bytes) + bfd *abfd; + struct internal_exec *execp; + struct external_exec *raw_bytes; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info , bytes->e_info); + PUT_WORD (abfd, execp->a_text , bytes->e_text); + PUT_WORD (abfd, execp->a_data , bytes->e_data); + PUT_WORD (abfd, execp->a_bss , bytes->e_bss); + PUT_WORD (abfd, execp->a_syms , bytes->e_syms); + PUT_WORD (abfd, execp->a_entry , bytes->e_entry); + PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); + PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); +} + +/* Make all the section for an a.out file. */ + +boolean +NAME(aout,make_sections) (abfd) + bfd *abfd; +{ + if (obj_textsec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".text") == (asection *) NULL) + return false; + if (obj_datasec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".data") == (asection *) NULL) + return false; + if (obj_bsssec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".bss") == (asection *) NULL) + return false; + return true; +} + +/* +FUNCTION + aout_@var{size}_some_aout_object_p + +SYNOPSIS + const bfd_target *aout_@var{size}_some_aout_object_p + (bfd *abfd, + const bfd_target *(*callback_to_real_object_p)()); + +DESCRIPTION + Some a.out variant thinks that the file open in @var{abfd} + checking is an a.out file. Do some more checking, and set up + for access if it really is. Call back to the calling + environment's "finish up" function just before returning, to + handle any last-minute setup. +*/ + +const bfd_target * +NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p) + bfd *abfd; + struct internal_exec *execp; + const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)); +{ + struct aout_data_struct *rawptr, *oldrawptr; + const bfd_target *result; + + rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + if (rawptr == NULL) + return 0; + + oldrawptr = abfd->tdata.aout_data; + abfd->tdata.aout_data = rawptr; + + /* Copy the contents of the old tdata struct. + In particular, we want the subformat, since for hpux it was set in + hp300hpux.c:swap_exec_header_in and will be used in + hp300hpux.c:callback. */ + if (oldrawptr != NULL) + *abfd->tdata.aout_data = *oldrawptr; + + abfd->tdata.aout_data->a.hdr = &rawptr->e; + *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct */ + execp = abfd->tdata.aout_data->a.hdr; + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + /* Setting of EXEC_P has been deferred to the bottom of this function */ + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + if (N_DYNAMIC(*execp)) + abfd->flags |= DYNAMIC; + + if (N_MAGIC (*execp) == ZMAGIC) + { + abfd->flags |= D_PAGED | WP_TEXT; + adata (abfd).magic = z_magic; + } + else if (N_MAGIC (*execp) == QMAGIC) + { + abfd->flags |= D_PAGED | WP_TEXT; + adata (abfd).magic = z_magic; + adata (abfd).subformat = q_magic_format; + } + else if (N_MAGIC (*execp) == NMAGIC) + { + abfd->flags |= WP_TEXT; + adata (abfd).magic = n_magic; + } + else if (N_MAGIC (*execp) == OMAGIC + || N_MAGIC (*execp) == BMAGIC) + adata (abfd).magic = o_magic; + else + { + /* Should have been checked with N_BADMAG before this routine + was called. */ + abort (); + } + + bfd_get_start_address (abfd) = execp->a_entry; + + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; + bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist); + + /* The default relocation entry size is that of traditional V7 Unix. */ + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + /* The default symbol entry size is that of traditional Unix. */ + obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE; + +#ifdef USE_MMAP + bfd_init_window (&obj_aout_sym_window (abfd)); + bfd_init_window (&obj_aout_string_window (abfd)); +#endif + obj_aout_external_syms (abfd) = NULL; + obj_aout_external_strings (abfd) = NULL; + obj_aout_sym_hashes (abfd) = NULL; + + if (! NAME(aout,make_sections) (abfd)) + return NULL; + + obj_datasec (abfd)->_raw_size = execp->a_data; + obj_bsssec (abfd)->_raw_size = execp->a_bss; + + obj_textsec (abfd)->flags = + (execp->a_trsize != 0 + ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) + : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = + (execp->a_drsize != 0 + ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) + : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + +#ifdef THIS_IS_ONLY_DOCUMENTATION + /* The common code can't fill in these things because they depend + on either the start address of the text segment, the rounding + up of virtual addresses between segments, or the starting file + position of the text segment -- all of which varies among different + versions of a.out. */ + + /* Call back to the format-dependent code to fill in the rest of the + fields and do any further cleanup. Things that should be filled + in by the callback: */ + + struct exec *execp = exec_hdr (abfd); + + obj_textsec (abfd)->size = N_TXTSIZE(*execp); + obj_textsec (abfd)->raw_size = N_TXTSIZE(*execp); + /* data and bss are already filled in since they're so standard */ + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF(*execp); + obj_datasec (abfd)->filepos = N_DATOFF(*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_str_filepos (abfd) = N_STROFF (*execp); + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + + /* Determine the architecture and machine type of the object file. */ + switch (N_MACHTYPE (*exec_hdr (abfd))) { + default: + abfd->obj_arch = bfd_arch_obscure; + break; + } + + adata(abfd)->page_size = TARGET_PAGE_SIZE; + adata(abfd)->segment_size = SEGMENT_SIZE; + adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE; + + return abfd->xvec; + + /* The architecture is encoded in various ways in various a.out variants, + or is not encoded at all in some of them. The relocation size depends + on the architecture and the a.out variant. Finally, the return value + is the bfd_target vector in use. If an error occurs, return zero and + set bfd_error to the appropriate error code. + + Formats such as b.out, which have additional fields in the a.out + header, should cope with them in this callback as well. */ +#endif /* DOCUMENTATION */ + + result = (*callback_to_real_object_p)(abfd); + + /* Now that the segment addresses have been worked out, take a better + guess at whether the file is executable. If the entry point + is within the text segment, assume it is. (This makes files + executable even if their entry point address is 0, as long as + their text starts at zero.). */ + if ((execp->a_entry >= obj_textsec(abfd)->vma) && + (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size)) + abfd->flags |= EXEC_P; +#ifdef STAT_FOR_EXEC + else + { + struct stat stat_buf; + + /* The original heuristic doesn't work in some important cases. + The a.out file has no information about the text start + address. For files (like kernels) linked to non-standard + addresses (ld -Ttext nnn) the entry point may not be between + the default text start (obj_textsec(abfd)->vma) and + (obj_textsec(abfd)->vma) + text size. This is not just a mach + issue. Many kernels are loaded at non standard addresses. */ + if (abfd->iostream != NULL + && (abfd->flags & BFD_IN_MEMORY) == 0 + && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0) + && ((stat_buf.st_mode & 0111) != 0)) + abfd->flags |= EXEC_P; + } +#endif /* STAT_FOR_EXEC */ + + if (result) + { +#if 0 /* These should be set correctly anyways. */ + abfd->sections = obj_textsec (abfd); + obj_textsec (abfd)->next = obj_datasec (abfd); + obj_datasec (abfd)->next = obj_bsssec (abfd); +#endif + } + else + { + free (rawptr); + abfd->tdata.aout_data = oldrawptr; + } + return result; +} + +/* +FUNCTION + aout_@var{size}_mkobject + +SYNOPSIS + boolean aout_@var{size}_mkobject, (bfd *abfd); + +DESCRIPTION + Initialize BFD @var{abfd} for use with a.out files. +*/ + +boolean +NAME(aout,mkobject) (abfd) + bfd *abfd; +{ + struct aout_data_struct *rawptr; + + bfd_set_error (bfd_error_system_call); + + /* Use an intermediate variable for clarity */ + rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + + if (rawptr == NULL) + return false; + + abfd->tdata.aout_data = rawptr; + exec_hdr (abfd) = &(rawptr->e); + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + + return true; +} + + +/* +FUNCTION + aout_@var{size}_machine_type + +SYNOPSIS + enum machine_type aout_@var{size}_machine_type + (enum bfd_architecture arch, + unsigned long machine)); + +DESCRIPTION + Keep track of machine architecture and machine type for + a.out's. Return the <> for a particular + architecture and machine, or <> if that exact architecture + and machine can't be represented in a.out format. + + If the architecture is understood, machine type 0 (default) + is always understood. +*/ + +enum machine_type +NAME(aout,machine_type) (arch, machine, unknown) + enum bfd_architecture arch; + unsigned long machine; + boolean *unknown; +{ + enum machine_type arch_flags; + + arch_flags = M_UNKNOWN; + *unknown = true; + + switch (arch) { + case bfd_arch_sparc: + if (machine == 0 + || machine == bfd_mach_sparc + || machine == bfd_mach_sparc_v9) + arch_flags = M_SPARC; + break; + + case bfd_arch_m68k: + switch (machine) { + case 0: arch_flags = M_68010; break; + case 68000: arch_flags = M_UNKNOWN; *unknown = false; break; + case 68010: arch_flags = M_68010; break; + case 68020: arch_flags = M_68020; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_i386: + if (machine == 0) arch_flags = M_386; + break; + + case bfd_arch_a29k: + if (machine == 0) arch_flags = M_29K; + break; + + case bfd_arch_arm: + if (machine == 0) arch_flags = M_ARM; + break; + + case bfd_arch_mips: + switch (machine) { + case 0: + case 2000: + case 3000: arch_flags = M_MIPS1; break; + case 4000: /* mips3 */ + case 4400: + case 8000: /* mips4 */ + /* real mips2: */ + case 6000: arch_flags = M_MIPS2; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_ns32k: + switch (machine) { + case 0: arch_flags = M_NS32532; break; + case 32032: arch_flags = M_NS32032; break; + case 32532: arch_flags = M_NS32532; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_vax: + *unknown = false; + break; + + + default: + arch_flags = M_UNKNOWN; + } + + if (arch_flags != M_UNKNOWN) + *unknown = false; + + return arch_flags; +} + + +/* +FUNCTION + aout_@var{size}_set_arch_mach + +SYNOPSIS + boolean aout_@var{size}_set_arch_mach, + (bfd *, + enum bfd_architecture arch, + unsigned long machine)); + +DESCRIPTION + Set the architecture and the machine of the BFD @var{abfd} to the + values @var{arch} and @var{machine}. Verify that @var{abfd}'s format + can support the architecture required. +*/ + +boolean +NAME(aout,set_arch_mach) (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch != bfd_arch_unknown) + { + boolean unknown; + + NAME(aout,machine_type) (arch, machine, &unknown); + if (unknown) + return false; + } + + /* Determine the size of a relocation entry */ + switch (arch) { + case bfd_arch_sparc: + case bfd_arch_a29k: + case bfd_arch_mips: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } + + return (*aout_backend_info(abfd)->set_sizes) (abfd); +} + +static void +adjust_o_magic (abfd, execp) + bfd *abfd; + struct internal_exec *execp; +{ + file_ptr pos = adata (abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad = 0; + + /* Text. */ + obj_textsec(abfd)->filepos = pos; + if (!obj_textsec(abfd)->user_set_vma) + obj_textsec(abfd)->vma = vma; + else + vma = obj_textsec(abfd)->vma; + + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + + /* Data. */ + if (!obj_datasec(abfd)->user_set_vma) + { +#if 0 /* ?? Does alignment in the file image really matter? */ + pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma; +#endif + obj_textsec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_datasec(abfd)->vma = vma; + } + else + vma = obj_datasec(abfd)->vma; + obj_datasec(abfd)->filepos = pos; + pos += obj_datasec(abfd)->_raw_size; + vma += obj_datasec(abfd)->_raw_size; + + /* BSS. */ + if (!obj_bsssec(abfd)->user_set_vma) + { +#if 0 + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; +#endif + obj_datasec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_bsssec(abfd)->vma = vma; + } + else + { + /* The VMA of the .bss section is set by the the VMA of the + .data section plus the size of the .data section. We may + need to add padding bytes to make this true. */ + pad = obj_bsssec (abfd)->vma - vma; + if (pad > 0) + { + obj_datasec (abfd)->_raw_size += pad; + pos += pad; + } + } + obj_bsssec(abfd)->filepos = pos; + + /* Fix up the exec header. */ + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, OMAGIC); +} + +static void +adjust_z_magic (abfd, execp) + bfd *abfd; + struct internal_exec *execp; +{ + bfd_size_type data_pad, text_pad; + file_ptr text_end; + CONST struct aout_backend_data *abdp; + int ztih; /* Nonzero if text includes exec header. */ + + abdp = aout_backend_info (abfd); + + /* Text. */ + ztih = (abdp != NULL + && (abdp->text_includes_header + || obj_aout_subformat (abfd) == q_magic_format)); + obj_textsec(abfd)->filepos = (ztih + ? adata(abfd).exec_bytes_size + : adata(abfd).zmagic_disk_block_size); + if (! obj_textsec(abfd)->user_set_vma) + { + /* ?? Do we really need to check for relocs here? */ + obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC) + ? 0 + : (ztih + ? (abdp->default_text_vma + + adata(abfd).exec_bytes_size) + : abdp->default_text_vma)); + text_pad = 0; + } + else + { + /* The .text section is being loaded at an unusual address. We + may need to pad it such that the .data section starts at a page + boundary. */ + if (ztih) + text_pad = ((obj_textsec (abfd)->filepos - obj_textsec (abfd)->vma) + & (adata (abfd).page_size - 1)); + else + text_pad = ((- obj_textsec (abfd)->vma) + & (adata (abfd).page_size - 1)); + } + + /* Find start of data. */ + if (ztih) + { + text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->_raw_size; + text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end; + } + else + { + /* Note that if page_size == zmagic_disk_block_size, then + filepos == page_size, and this case is the same as the ztih + case. */ + text_end = obj_textsec (abfd)->_raw_size; + text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end; + text_end += obj_textsec (abfd)->filepos; + } + obj_textsec(abfd)->_raw_size += text_pad; + text_end += text_pad; + + /* Data. */ + if (!obj_datasec(abfd)->user_set_vma) + { + bfd_vma vma; + vma = obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size; + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + } + if (abdp && abdp->zmagic_mapped_contiguous) + { + text_pad = (obj_datasec(abfd)->vma + - obj_textsec(abfd)->vma + - obj_textsec(abfd)->_raw_size); + obj_textsec(abfd)->_raw_size += text_pad; + } + obj_datasec(abfd)->filepos = (obj_textsec(abfd)->filepos + + obj_textsec(abfd)->_raw_size); + + /* Fix up exec header while we're at it. */ + execp->a_text = obj_textsec(abfd)->_raw_size; + if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted))) + execp->a_text += adata(abfd).exec_bytes_size; + if (obj_aout_subformat (abfd) == q_magic_format) + N_SET_MAGIC (*execp, QMAGIC); + else + N_SET_MAGIC (*execp, ZMAGIC); + + /* Spec says data section should be rounded up to page boundary. */ + obj_datasec(abfd)->_raw_size + = align_power (obj_datasec(abfd)->_raw_size, + obj_bsssec(abfd)->alignment_power); + execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size, + adata(abfd).page_size); + data_pad = execp->a_data - obj_datasec(abfd)->_raw_size; + + /* BSS. */ + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma + + obj_datasec(abfd)->_raw_size); + /* If the BSS immediately follows the data section and extra space + in the page is left after the data section, fudge data + in the header so that the bss section looks smaller by that + amount. We'll start the bss section there, and lie to the OS. + (Note that a linker script, as well as the above assignment, + could have explicitly set the BSS vma to immediately follow + the data section.) */ + if (align_power (obj_bsssec(abfd)->vma, obj_bsssec(abfd)->alignment_power) + == obj_datasec(abfd)->vma + obj_datasec(abfd)->_raw_size) + execp->a_bss = (data_pad > obj_bsssec(abfd)->_raw_size) ? 0 : + obj_bsssec(abfd)->_raw_size - data_pad; + else + execp->a_bss = obj_bsssec(abfd)->_raw_size; +} + +static void +adjust_n_magic (abfd, execp) + bfd *abfd; + struct internal_exec *execp; +{ + file_ptr pos = adata(abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad; + + /* Text. */ + obj_textsec(abfd)->filepos = pos; + if (!obj_textsec(abfd)->user_set_vma) + obj_textsec(abfd)->vma = vma; + else + vma = obj_textsec(abfd)->vma; + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + + /* Data. */ + obj_datasec(abfd)->filepos = pos; + if (!obj_datasec(abfd)->user_set_vma) + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + vma = obj_datasec(abfd)->vma; + + /* Since BSS follows data immediately, see if it needs alignment. */ + vma += obj_datasec(abfd)->_raw_size; + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; + obj_datasec(abfd)->_raw_size += pad; + pos += obj_datasec(abfd)->_raw_size; + + /* BSS. */ + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = vma; + else + vma = obj_bsssec(abfd)->vma; + + /* Fix up exec header. */ + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, NMAGIC); +} + +boolean +NAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end) + bfd *abfd; + bfd_size_type *text_size; + file_ptr *text_end; +{ + struct internal_exec *execp = exec_hdr (abfd); + + if (! NAME(aout,make_sections) (abfd)) + return false; + + if (adata(abfd).magic != undecided_magic) + return true; + + obj_textsec(abfd)->_raw_size = + align_power(obj_textsec(abfd)->_raw_size, + obj_textsec(abfd)->alignment_power); + + *text_size = obj_textsec (abfd)->_raw_size; + /* Rule (heuristic) for when to pad to a new page. Note that there + are (at least) two ways demand-paged (ZMAGIC) files have been + handled. Most Berkeley-based systems start the text segment at + (TARGET_PAGE_SIZE). However, newer versions of SUNOS start the text + segment right after the exec header; the latter is counted in the + text segment size, and is paged in by the kernel with the rest of + the text. */ + + /* This perhaps isn't the right way to do this, but made it simpler for me + to understand enough to implement it. Better would probably be to go + right from BFD flags to alignment/positioning characteristics. But the + old code was sloppy enough about handling the flags, and had enough + other magic, that it was a little hard for me to understand. I think + I understand it better now, but I haven't time to do the cleanup this + minute. */ + + if (abfd->flags & D_PAGED) + /* Whether or not WP_TEXT is set -- let D_PAGED override. */ + adata(abfd).magic = z_magic; + else if (abfd->flags & WP_TEXT) + adata(abfd).magic = n_magic; + else + adata(abfd).magic = o_magic; + +#ifdef BFD_AOUT_DEBUG /* requires gcc2 */ +#if __GNUC__ >= 2 + fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n", + ({ char *str; + switch (adata(abfd).magic) { + case n_magic: str = "NMAGIC"; break; + case o_magic: str = "OMAGIC"; break; + case z_magic: str = "ZMAGIC"; break; + default: abort (); + } + str; + }), + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, + obj_textsec(abfd)->alignment_power, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, + obj_datasec(abfd)->alignment_power, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size, + obj_bsssec(abfd)->alignment_power); +#endif +#endif + + switch (adata(abfd).magic) + { + case o_magic: + adjust_o_magic (abfd, execp); + break; + case z_magic: + adjust_z_magic (abfd, execp); + break; + case n_magic: + adjust_n_magic (abfd, execp); + break; + default: + abort (); + } + +#ifdef BFD_AOUT_DEBUG + fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n", + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, + obj_textsec(abfd)->filepos, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, + obj_datasec(abfd)->filepos, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size); +#endif + + return true; +} + +/* +FUNCTION + aout_@var{size}_new_section_hook + +SYNOPSIS + boolean aout_@var{size}_new_section_hook, + (bfd *abfd, + asection *newsect)); + +DESCRIPTION + Called by the BFD in response to a @code{bfd_make_section} + request. +*/ +boolean +NAME(aout,new_section_hook) (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + /* align to double at least */ + newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power; + + + if (bfd_get_format (abfd) == bfd_object) + { + if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) { + obj_textsec(abfd)= newsect; + newsect->target_index = N_TEXT; + return true; + } + + if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) { + obj_datasec(abfd) = newsect; + newsect->target_index = N_DATA; + return true; + } + + if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) { + obj_bsssec(abfd) = newsect; + newsect->target_index = N_BSS; + return true; + } + + } + + /* We allow more than three sections internally */ + return true; +} + +boolean +NAME(aout,set_section_contents) (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + file_ptr text_end; + bfd_size_type text_size; + + if (! abfd->output_has_begun) + { + if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end)) + return false; + } + + if (section == obj_bsssec (abfd)) + { + bfd_set_error (bfd_error_no_contents); + return false; + } + + if (section != obj_textsec (abfd) + && section != obj_datasec (abfd)) + { + (*_bfd_error_handler) + ("%s: can not represent section `%s' in a.out object file format", + bfd_get_filename (abfd), bfd_get_section_name (abfd, section)); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + + if (count != 0) + { + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 + || bfd_write (location, 1, count, abfd) != count) + return false; + } + + return true; +} + +/* Read the external symbols from an a.out file. */ + +static boolean +aout_get_external_symbols (abfd) + bfd *abfd; +{ + if (obj_aout_external_syms (abfd) == (struct external_nlist *) NULL) + { + bfd_size_type count; + struct external_nlist *syms; + + count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE; + +#ifdef USE_MMAP + if (bfd_get_file_window (abfd, + obj_sym_filepos (abfd), exec_hdr (abfd)->a_syms, + &obj_aout_sym_window (abfd), true) == false) + return false; + syms = (struct external_nlist *) obj_aout_sym_window (abfd).data; +#else + /* We allocate using malloc to make the values easy to free + later on. If we put them on the obstack it might not be + possible to free them. */ + syms = ((struct external_nlist *) + bfd_malloc ((size_t) count * EXTERNAL_NLIST_SIZE)); + if (syms == (struct external_nlist *) NULL && count != 0) + return false; + + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || (bfd_read (syms, 1, exec_hdr (abfd)->a_syms, abfd) + != exec_hdr (abfd)->a_syms)) + { + free (syms); + return false; + } +#endif + + obj_aout_external_syms (abfd) = syms; + obj_aout_external_sym_count (abfd) = count; + } + + if (obj_aout_external_strings (abfd) == NULL + && exec_hdr (abfd)->a_syms != 0) + { + unsigned char string_chars[BYTES_IN_WORD]; + bfd_size_type stringsize; + char *strings; + + /* Get the size of the strings. */ + if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0 + || (bfd_read ((PTR) string_chars, BYTES_IN_WORD, 1, abfd) + != BYTES_IN_WORD)) + return false; + stringsize = GET_WORD (abfd, string_chars); + +#ifdef USE_MMAP + if (bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize, + &obj_aout_string_window (abfd), true) == false) + return false; + strings = (char *) obj_aout_string_window (abfd).data; +#else + strings = (char *) bfd_malloc ((size_t) stringsize + 1); + if (strings == NULL) + return false; + + /* Skip space for the string count in the buffer for convenience + when using indexes. */ + if (bfd_read (strings + BYTES_IN_WORD, 1, stringsize - BYTES_IN_WORD, + abfd) + != stringsize - BYTES_IN_WORD) + { + free (strings); + return false; + } +#endif + + /* Ensure that a zero index yields an empty string. */ + strings[0] = '\0'; + + strings[stringsize - 1] = 0; + + obj_aout_external_strings (abfd) = strings; + obj_aout_external_string_size (abfd) = stringsize; + } + + return true; +} + +/* Translate an a.out symbol into a BFD symbol. The desc, other, type + and symbol->value fields of CACHE_PTR will be set from the a.out + nlist structure. This function is responsible for setting + symbol->flags and symbol->section, and adjusting symbol->value. */ + +static boolean +translate_from_native_sym_flags (abfd, cache_ptr) + bfd *abfd; + aout_symbol_type *cache_ptr; +{ + flagword visible; + + if ((cache_ptr->type & N_STAB) != 0 + || cache_ptr->type == N_FN) + { + asection *sec; + + /* This is a debugging symbol. */ + + cache_ptr->symbol.flags = BSF_DEBUGGING; + + /* Work out the symbol section. */ + switch (cache_ptr->type & N_TYPE) + { + case N_TEXT: + case N_FN: + sec = obj_textsec (abfd); + break; + case N_DATA: + sec = obj_datasec (abfd); + break; + case N_BSS: + sec = obj_bsssec (abfd); + break; + default: + case N_ABS: + sec = bfd_abs_section_ptr; + break; + } + + cache_ptr->symbol.section = sec; + cache_ptr->symbol.value -= sec->vma; + + return true; + } + + /* Get the default visibility. This does not apply to all types, so + we just hold it in a local variable to use if wanted. */ + if ((cache_ptr->type & N_EXT) == 0) + visible = BSF_LOCAL; + else + visible = BSF_GLOBAL; + + switch (cache_ptr->type) + { + default: + case N_ABS: case N_ABS | N_EXT: + cache_ptr->symbol.section = bfd_abs_section_ptr; + cache_ptr->symbol.flags = visible; + break; + + case N_UNDF | N_EXT: + if (cache_ptr->symbol.value != 0) + { + /* This is a common symbol. */ + cache_ptr->symbol.flags = BSF_GLOBAL; + cache_ptr->symbol.section = bfd_com_section_ptr; + } + else + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = bfd_und_section_ptr; + } + break; + + case N_TEXT: case N_TEXT | N_EXT: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + + /* N_SETV symbols used to represent set vectors placed in the + data section. They are no longer generated. Theoretically, + it was possible to extract the entries and combine them with + new ones, although I don't know if that was ever actually + done. Unless that feature is restored, treat them as data + symbols. */ + case N_SETV: case N_SETV | N_EXT: + case N_DATA: case N_DATA | N_EXT: + cache_ptr->symbol.section = obj_datasec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + + case N_BSS: case N_BSS | N_EXT: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + + case N_SETA: case N_SETA | N_EXT: + case N_SETT: case N_SETT | N_EXT: + case N_SETD: case N_SETD | N_EXT: + case N_SETB: case N_SETB | N_EXT: + { + asection *section; + arelent_chain *reloc; + asection *into_section; + + /* This is a set symbol. The name of the symbol is the name + of the set (e.g., __CTOR_LIST__). The value of the symbol + is the value to add to the set. We create a section with + the same name as the symbol, and add a reloc to insert the + appropriate value into the section. + + This action is actually obsolete; it used to make the + linker do the right thing, but the linker no longer uses + this function. */ + + section = bfd_get_section_by_name (abfd, cache_ptr->symbol.name); + if (section == NULL) + { + char *copy; + + copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1); + if (copy == NULL) + return false; + + strcpy (copy, cache_ptr->symbol.name); + section = bfd_make_section (abfd, copy); + if (section == NULL) + return false; + } + + reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + if (reloc == NULL) + return false; + + /* Build a relocation entry for the constructor. */ + switch (cache_ptr->type & N_TYPE) + { + case N_SETA: + into_section = bfd_abs_section_ptr; + cache_ptr->type = N_ABS; + break; + case N_SETT: + into_section = obj_textsec (abfd); + cache_ptr->type = N_TEXT; + break; + case N_SETD: + into_section = obj_datasec (abfd); + cache_ptr->type = N_DATA; + break; + case N_SETB: + into_section = obj_bsssec (abfd); + cache_ptr->type = N_BSS; + break; + } + + /* Build a relocation pointing into the constructor section + pointing at the symbol in the set vector specified. */ + reloc->relent.addend = cache_ptr->symbol.value; + cache_ptr->symbol.section = into_section; + reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr; + + /* We modify the symbol to belong to a section depending upon + the name of the symbol, and add to the size of the section + to contain a pointer to the symbol. Build a reloc entry to + relocate to this symbol attached to this section. */ + section->flags = SEC_CONSTRUCTOR | SEC_RELOC; + + section->reloc_count++; + section->alignment_power = 2; + + reloc->next = section->constructor_chain; + section->constructor_chain = reloc; + reloc->relent.address = section->_raw_size; + section->_raw_size += BYTES_IN_WORD; + + reloc->relent.howto = CTOR_TABLE_RELOC_HOWTO(abfd); + + cache_ptr->symbol.flags |= BSF_CONSTRUCTOR; + } + break; + + case N_WARNING: + /* This symbol is the text of a warning message. The next + symbol is the symbol to associate the warning with. If a + reference is made to that symbol, a warning is issued. */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING; + cache_ptr->symbol.section = bfd_abs_section_ptr; + break; + + case N_INDR: case N_INDR | N_EXT: + /* An indirect symbol. This consists of two symbols in a row. + The first symbol is the name of the indirection. The second + symbol is the name of the target. A reference to the first + symbol becomes a reference to the second. */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible; + cache_ptr->symbol.section = bfd_ind_section_ptr; + break; + + case N_WEAKU: + cache_ptr->symbol.section = bfd_und_section_ptr; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKA: + cache_ptr->symbol.section = bfd_abs_section_ptr; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKT: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKD: + cache_ptr->symbol.section = obj_datasec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKB: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; + } + + return true; +} + +/* Set the fields of SYM_POINTER according to CACHE_PTR. */ + +static boolean +translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer) + bfd *abfd; + asymbol *cache_ptr; + struct external_nlist *sym_pointer; +{ + bfd_vma value = cache_ptr->value; + asection *sec; + bfd_vma off; + + /* Mask out any existing type bits in case copying from one section + to another. */ + sym_pointer->e_type[0] &= ~N_TYPE; + + sec = bfd_get_section (cache_ptr); + off = 0; + + if (sec == NULL) + { + /* This case occurs, e.g., for the *DEBUG* section of a COFF + file. */ + (*_bfd_error_handler) + ("%s: can not represent section `%s' in a.out object file format", + bfd_get_filename (abfd), bfd_get_section_name (abfd, sec)); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + + if (sec->output_section != NULL) + { + off = sec->output_offset; + sec = sec->output_section; + } + + if (bfd_is_abs_section (sec)) + sym_pointer->e_type[0] |= N_ABS; + else if (sec == obj_textsec (abfd)) + sym_pointer->e_type[0] |= N_TEXT; + else if (sec == obj_datasec (abfd)) + sym_pointer->e_type[0] |= N_DATA; + else if (sec == obj_bsssec (abfd)) + sym_pointer->e_type[0] |= N_BSS; + else if (bfd_is_und_section (sec)) + sym_pointer->e_type[0] = N_UNDF | N_EXT; + else if (bfd_is_ind_section (sec)) + sym_pointer->e_type[0] = N_INDR; + else if (bfd_is_com_section (sec)) + sym_pointer->e_type[0] = N_UNDF | N_EXT; + else + { + (*_bfd_error_handler) + ("%s: can not represent section `%s' in a.out object file format", + bfd_get_filename (abfd), bfd_get_section_name (abfd, sec)); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + + /* Turn the symbol from section relative to absolute again */ + value += sec->vma + off; + + if ((cache_ptr->flags & BSF_WARNING) != 0) + sym_pointer->e_type[0] = N_WARNING; + + if ((cache_ptr->flags & BSF_DEBUGGING) != 0) + sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type; + else if ((cache_ptr->flags & BSF_GLOBAL) != 0) + sym_pointer->e_type[0] |= N_EXT; + + if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0) + { + int type = ((aout_symbol_type *) cache_ptr)->type; + switch (type) + { + case N_ABS: type = N_SETA; break; + case N_TEXT: type = N_SETT; break; + case N_DATA: type = N_SETD; break; + case N_BSS: type = N_SETB; break; + } + sym_pointer->e_type[0] = type; + } + + if ((cache_ptr->flags & BSF_WEAK) != 0) + { + int type; + + switch (sym_pointer->e_type[0] & N_TYPE) + { + default: + case N_ABS: type = N_WEAKA; break; + case N_TEXT: type = N_WEAKT; break; + case N_DATA: type = N_WEAKD; break; + case N_BSS: type = N_WEAKB; break; + case N_UNDF: type = N_WEAKU; break; + } + sym_pointer->e_type[0] = type; + } + + PUT_WORD(abfd, value, sym_pointer->e_value); + + return true; +} + +/* Native-level interface to symbols. */ + +asymbol * +NAME(aout,make_empty_symbol) (abfd) + bfd *abfd; +{ + aout_symbol_type *new = + (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type)); + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +/* Translate a set of internal symbols into external symbols. */ + +boolean +NAME(aout,translate_symbol_table) (abfd, in, ext, count, str, strsize, dynamic) + bfd *abfd; + aout_symbol_type *in; + struct external_nlist *ext; + bfd_size_type count; + char *str; + bfd_size_type strsize; + boolean dynamic; +{ + struct external_nlist *ext_end; + + ext_end = ext + count; + for (; ext < ext_end; ext++, in++) + { + bfd_vma x; + + x = GET_WORD (abfd, ext->e_strx); + in->symbol.the_bfd = abfd; + + /* For the normal symbols, the zero index points at the number + of bytes in the string table but is to be interpreted as the + null string. For the dynamic symbols, the number of bytes in + the string table is stored in the __DYNAMIC structure and the + zero index points at an actual string. */ + if (x == 0 && ! dynamic) + in->symbol.name = ""; + else if (x < strsize) + in->symbol.name = str + x; + else + return false; + + in->symbol.value = GET_SWORD (abfd, ext->e_value); + in->desc = bfd_h_get_16 (abfd, ext->e_desc); + in->other = bfd_h_get_8 (abfd, ext->e_other); + in->type = bfd_h_get_8 (abfd, ext->e_type); + in->symbol.udata.p = NULL; + + if (! translate_from_native_sym_flags (abfd, in)) + return false; + + if (dynamic) + in->symbol.flags |= BSF_DYNAMIC; + } + + return true; +} + +/* We read the symbols into a buffer, which is discarded when this + function exits. We read the strings into a buffer large enough to + hold them all plus all the cached symbol entries. */ + +boolean +NAME(aout,slurp_symbol_table) (abfd) + bfd *abfd; +{ + struct external_nlist *old_external_syms; + aout_symbol_type *cached; + size_t cached_size; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL) + return true; + + old_external_syms = obj_aout_external_syms (abfd); + + if (! aout_get_external_symbols (abfd)) + return false; + + cached_size = (obj_aout_external_sym_count (abfd) + * sizeof (aout_symbol_type)); + cached = (aout_symbol_type *) bfd_malloc (cached_size); + if (cached == NULL && cached_size != 0) + return false; + if (cached_size != 0) + memset (cached, 0, cached_size); + + /* Convert from external symbol information to internal. */ + if (! (NAME(aout,translate_symbol_table) + (abfd, cached, + obj_aout_external_syms (abfd), + obj_aout_external_sym_count (abfd), + obj_aout_external_strings (abfd), + obj_aout_external_string_size (abfd), + false))) + { + free (cached); + return false; + } + + bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd); + + obj_aout_symbols (abfd) = cached; + + /* It is very likely that anybody who calls this function will not + want the external symbol information, so if it was allocated + because of our call to aout_get_external_symbols, we free it up + right away to save space. */ + if (old_external_syms == (struct external_nlist *) NULL + && obj_aout_external_syms (abfd) != (struct external_nlist *) NULL) + { +#ifdef USE_MMAP + bfd_free_window (&obj_aout_sym_window (abfd)); +#else + free (obj_aout_external_syms (abfd)); +#endif + obj_aout_external_syms (abfd) = NULL; + } + + return true; +} + +/* We use a hash table when writing out symbols so that we only write + out a particular string once. This helps particularly when the + linker writes out stabs debugging entries, because each different + contributing object file tends to have many duplicate stabs + strings. + + This hash table code breaks dbx on SunOS 4.1.3, so we don't do it + if BFD_TRADITIONAL_FORMAT is set. */ + +static bfd_size_type add_to_stringtab + PARAMS ((bfd *, struct bfd_strtab_hash *, const char *, boolean)); +static boolean emit_stringtab PARAMS ((bfd *, struct bfd_strtab_hash *)); + +/* Get the index of a string in a strtab, adding it if it is not + already present. */ + +static INLINE bfd_size_type +add_to_stringtab (abfd, tab, str, copy) + bfd *abfd; + struct bfd_strtab_hash *tab; + const char *str; + boolean copy; +{ + boolean hash; + bfd_size_type index; + + /* An index of 0 always means the empty string. */ + if (str == 0 || *str == '\0') + return 0; + + /* Don't hash if BFD_TRADITIONAL_FORMAT is set, because SunOS dbx + doesn't understand a hashed string table. */ + hash = true; + if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0) + hash = false; + + index = _bfd_stringtab_add (tab, str, hash, copy); + + if (index != (bfd_size_type) -1) + { + /* Add BYTES_IN_WORD to the return value to account for the + space taken up by the string table size. */ + index += BYTES_IN_WORD; + } + + return index; +} + +/* Write out a strtab. ABFD is already at the right location in the + file. */ + +static boolean +emit_stringtab (abfd, tab) + register bfd *abfd; + struct bfd_strtab_hash *tab; +{ + bfd_byte buffer[BYTES_IN_WORD]; + + /* The string table starts with the size. */ + PUT_WORD (abfd, _bfd_stringtab_size (tab) + BYTES_IN_WORD, buffer); + if (bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd) != BYTES_IN_WORD) + return false; + + return _bfd_stringtab_emit (abfd, tab); +} + +boolean +NAME(aout,write_syms) (abfd) + bfd *abfd; +{ + unsigned int count ; + asymbol **generic = bfd_get_outsymbols (abfd); + struct bfd_strtab_hash *strtab; + + strtab = _bfd_stringtab_init (); + if (strtab == NULL) + return false; + + for (count = 0; count < bfd_get_symcount (abfd); count++) + { + asymbol *g = generic[count]; + bfd_size_type indx; + struct external_nlist nsp; + + indx = add_to_stringtab (abfd, strtab, g->name, false); + if (indx == (bfd_size_type) -1) + goto error_return; + PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx); + + if (bfd_asymbol_flavour(g) == abfd->xvec->flavour) + { + bfd_h_put_16(abfd, aout_symbol(g)->desc, nsp.e_desc); + bfd_h_put_8(abfd, aout_symbol(g)->other, nsp.e_other); + bfd_h_put_8(abfd, aout_symbol(g)->type, nsp.e_type); + } + else + { + bfd_h_put_16(abfd,0, nsp.e_desc); + bfd_h_put_8(abfd, 0, nsp.e_other); + bfd_h_put_8(abfd, 0, nsp.e_type); + } + + if (! translate_to_native_sym_flags (abfd, g, &nsp)) + goto error_return; + + if (bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd) + != EXTERNAL_NLIST_SIZE) + goto error_return; + + /* NB: `KEEPIT' currently overlays `udata.p', so set this only + here, at the end. */ + g->KEEPIT = count; + } + + if (! emit_stringtab (abfd, strtab)) + goto error_return; + + _bfd_stringtab_free (strtab); + + return true; + +error_return: + _bfd_stringtab_free (strtab); + return false; +} + + +long +NAME(aout,get_symtab) (abfd, location) + bfd *abfd; + asymbol **location; +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (!NAME(aout,slurp_symbol_table)(abfd)) + return -1; + + for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *)( symbase++); + *location++ =0; + return bfd_get_symcount (abfd); +} + + +/* Standard reloc stuff */ +/* Output standard relocation information to a file in target byte order. */ + +void +NAME(aout,swap_std_reloc_out) (abfd, g, natptr) + bfd *abfd; + arelent *g; + struct reloc_std_external *natptr; +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + asection *output_section = sym->section->output_section; + + PUT_WORD(abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + /* XXX This relies on relocs coming from a.out files. */ + r_baserel = (g->howto->type & 8) != 0; + r_jmptable = (g->howto->type & 16) != 0; + r_relative = (g->howto->type & 32) != 0; + +#if 0 + /* For a standard reloc, the addend is in the object file. */ + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; +#endif + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + + if (bfd_is_com_section (output_section) + || bfd_is_abs_section (output_section) + || bfd_is_und_section (output_section)) + { + if (bfd_abs_section_ptr->symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = (*(g->sym_ptr_ptr))->KEEPIT; + + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_BIG: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_BIG: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_BIG: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_BIG: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_BIG: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_LITTLE: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_LITTLE: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); + } +} + + +/* Extended stuff */ +/* Output extended relocation information to a file in target byte order. */ + +void +NAME(aout,swap_ext_reloc_out) (abfd, g, natptr) + bfd *abfd; + arelent *g; + register struct reloc_ext_external *natptr; +{ + int r_index; + int r_extern; + unsigned int r_type; + unsigned int r_addend; + asymbol *sym = *(g->sym_ptr_ptr); + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_type = (unsigned int) g->howto->type; + + r_addend = g->addend; + if ((sym->flags & BSF_SECTION_SYM) != 0) + r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here. */ + + if (bfd_is_abs_section (bfd_get_section (sym))) + { + r_extern = 0; + r_index = 0; + } + else if ((sym->flags & BSF_SECTION_SYM) == 0) + { + if (bfd_is_und_section (bfd_get_section (sym)) + || (sym->flags & BSF_GLOBAL) != 0) + r_extern = 1; + else + r_extern = 0; + r_index = (*(g->sym_ptr_ptr))->KEEPIT; + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + ((r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG)); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + PUT_WORD (abfd, r_addend, natptr->r_addend); +} + +/* BFD deals internally with all things based from the section they're + in. so, something in 10 bytes into a text section with a base of + 50 would have a symbol (.text+10) and know .text vma was 50. + + Aout keeps all it's symbols based from zero, so the symbol would + contain 60. This macro subs the base of each section from the value + to give the true offset from the section */ + + +#define MOVE_ADDRESS(ad) \ + if (r_extern) { \ + /* undefined symbol */ \ + cache_ptr->sym_ptr_ptr = symbols + r_index; \ + cache_ptr->addend = ad; \ + } else { \ + /* defined, section relative. replace symbol with pointer to \ + symbol which points to section */ \ + switch (r_index) { \ + case N_TEXT: \ + case N_TEXT | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->textsec->vma; \ + break; \ + case N_DATA: \ + case N_DATA | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->datasec->vma; \ + break; \ + case N_BSS: \ + case N_BSS | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->bsssec->vma; \ + break; \ + default: \ + case N_ABS: \ + case N_ABS | N_EXT: \ + cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \ + cache_ptr->addend = ad; \ + break; \ + } \ + } \ + +void +NAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_ext_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + unsigned int r_index; + int r_extern; + unsigned int r_type; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE; + } + + cache_ptr->howto = howto_table_ext + r_type; + + /* Base relative relocs are always against the symbol table, + regardless of the setting of r_extern. r_extern just reflects + whether the symbol the reloc is against is local or global. */ + if (r_type == RELOC_BASE10 + || r_type == RELOC_BASE13 + || r_type == RELOC_BASE22) + r_extern = 1; + + if (r_extern && r_index > symcount) + { + /* We could arrange to return an error, but it might be useful + to see the file even if it is bad. */ + r_extern = 0; + r_index = N_ABS; + } + + MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend)); +} + +void +NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_std_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + unsigned int r_index; + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + unsigned int howto_idx; + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE; + } + + howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel + + 16 * r_jmptable + 32 * r_relative; + BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); + cache_ptr->howto = howto_table_std + howto_idx; + BFD_ASSERT (cache_ptr->howto->type != (unsigned int) -1); + + /* Base relative relocs are always against the symbol table, + regardless of the setting of r_extern. r_extern just reflects + whether the symbol the reloc is against is local or global. */ + if (r_baserel) + r_extern = 1; + + if (r_extern && r_index > symcount) + { + /* We could arrange to return an error, but it might be useful + to see the file even if it is bad. */ + r_extern = 0; + r_index = N_ABS; + } + + MOVE_ADDRESS(0); +} + +/* Read and swap the relocs for a section. */ + +boolean +NAME(aout,slurp_reloc_table) (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + unsigned int count; + bfd_size_type reloc_size; + PTR relocs; + arelent *reloc_cache; + size_t each_size; + unsigned int counter = 0; + arelent *cache_ptr; + + if (asect->relocation) + return true; + + if (asect->flags & SEC_CONSTRUCTOR) + return true; + + if (asect == obj_datasec (abfd)) + reloc_size = exec_hdr(abfd)->a_drsize; + else if (asect == obj_textsec (abfd)) + reloc_size = exec_hdr(abfd)->a_trsize; + else if (asect == obj_bsssec (abfd)) + reloc_size = 0; + else + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) + return false; + + each_size = obj_reloc_entry_size (abfd); + + count = reloc_size / each_size; + + reloc_cache = (arelent *) bfd_malloc ((size_t) (count * sizeof (arelent))); + if (reloc_cache == NULL && count != 0) + return false; + memset (reloc_cache, 0, count * sizeof (arelent)); + + relocs = bfd_malloc ((size_t) reloc_size); + if (relocs == NULL && reloc_size != 0) + { + free (reloc_cache); + return false; + } + + if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) + { + free (relocs); + free (reloc_cache); + return false; + } + + cache_ptr = reloc_cache; + if (each_size == RELOC_EXT_SIZE) + { + register struct reloc_ext_external *rptr = + (struct reloc_ext_external *) relocs; + + for (; counter < count; counter++, rptr++, cache_ptr++) + NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols, + bfd_get_symcount (abfd)); + } + else + { + register struct reloc_std_external *rptr = + (struct reloc_std_external *) relocs; + + for (; counter < count; counter++, rptr++, cache_ptr++) + MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols, + bfd_get_symcount (abfd)); + } + + free (relocs); + + asect->relocation = reloc_cache; + asect->reloc_count = cache_ptr - reloc_cache; + + return true; +} + +/* Write out a relocation section into an object file. */ + +boolean +NAME(aout,squirt_out_relocs) (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + unsigned char *native, *natptr; + size_t each_size; + + unsigned int count = section->reloc_count; + size_t natsize; + + if (count == 0) return true; + + each_size = obj_reloc_entry_size (abfd); + natsize = each_size * count; + native = (unsigned char *) bfd_zalloc (abfd, natsize); + if (!native) + return false; + + generic = section->orelocation; + + if (each_size == RELOC_EXT_SIZE) + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(aout,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr); + } + else + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + MY_swap_std_reloc_out(abfd, *generic, (struct reloc_std_external *)natptr); + } + + if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) { + bfd_release(abfd, native); + return false; + } + bfd_release (abfd, native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +long +NAME(aout,canonicalize_reloc) (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (section == obj_bsssec (abfd)) + { + *relptr = NULL; + return 0; + } + + if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols))) + return -1; + + if (section->flags & SEC_CONSTRUCTOR) { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count ++) { + *relptr ++ = &chain->relent; + chain = chain->next; + } + } + else { + tblptr = section->relocation; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +long +NAME(aout,get_reloc_upper_bound) (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + if (asect->flags & SEC_CONSTRUCTOR) { + return (sizeof (arelent *) * (asect->reloc_count+1)); + } + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) + * ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd)) + + 1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) + * ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd)) + + 1)); + + if (asect == obj_bsssec (abfd)) + return sizeof (arelent *); + + if (asect == obj_bsssec (abfd)) + return 0; + + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + + +long +NAME(aout,get_symtab_upper_bound) (abfd) + bfd *abfd; +{ + if (!NAME(aout,slurp_symbol_table)(abfd)) + return -1; + + return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *)); +} + +/*ARGSUSED*/ + alent * +NAME(aout,get_lineno) (ignore_abfd, ignore_symbol) + bfd *ignore_abfd; + asymbol *ignore_symbol; +{ +return (alent *)NULL; +} + +/*ARGSUSED*/ +void +NAME(aout,get_symbol_info) (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); + + if (ret->type == '?') + { + int type_code = aout_symbol(symbol)->type & 0xff; + const char *stab_name = bfd_get_stab_name (type_code); + static char buf[10]; + + if (stab_name == NULL) + { + sprintf(buf, "(%d)", type_code); + stab_name = buf; + } + ret->type = '-'; + ret->stab_type = type_code; + ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff); + ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff); + ret->stab_name = stab_name; + } +} + +/*ARGSUSED*/ +void +NAME(aout,print_symbol) (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *)afile; + + switch (how) { + case bfd_print_symbol_name: + if (symbol->name) + fprintf(file,"%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type)); + break; + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section->name; + + + bfd_print_symbol_vandf((PTR)file,symbol); + + fprintf(file," %-5s %04x %02x %02x", + section_name, + (unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type & 0xff)); + if (symbol->name) + fprintf(file," %s", symbol->name); + } + break; + } +} + +/* If we don't have to allocate more than 1MB to hold the generic + symbols, we use the generic minisymbol methord: it's faster, since + it only translates the symbols once, not multiple times. */ +#define MINISYM_THRESHOLD (1000000 / sizeof (asymbol)) + +/* Read minisymbols. For minisymbols, we use the unmodified a.out + symbols. The minisymbol_to_symbol function translates these into + BFD asymbol structures. */ + +long +NAME(aout,read_minisymbols) (abfd, dynamic, minisymsp, sizep) + bfd *abfd; + boolean dynamic; + PTR *minisymsp; + unsigned int *sizep; +{ + if (dynamic) + { + /* We could handle the dynamic symbols here as well, but it's + easier to hand them off. */ + return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep); + } + + if (! aout_get_external_symbols (abfd)) + return -1; + + if (obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD) + return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep); + + *minisymsp = (PTR) obj_aout_external_syms (abfd); + + /* By passing the external symbols back from this routine, we are + giving up control over the memory block. Clear + obj_aout_external_syms, so that we do not try to free it + ourselves. */ + obj_aout_external_syms (abfd) = NULL; + + *sizep = EXTERNAL_NLIST_SIZE; + return obj_aout_external_sym_count (abfd); +} + +/* Convert a minisymbol to a BFD asymbol. A minisymbol is just an + unmodified a.out symbol. The SYM argument is a structure returned + by bfd_make_empty_symbol, which we fill in here. */ + +asymbol * +NAME(aout,minisymbol_to_symbol) (abfd, dynamic, minisym, sym) + bfd *abfd; + boolean dynamic; + const PTR minisym; + asymbol *sym; +{ + if (dynamic + || obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD) + return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym); + + memset (sym, 0, sizeof (aout_symbol_type)); + + /* We call translate_symbol_table to translate a single symbol. */ + if (! (NAME(aout,translate_symbol_table) + (abfd, + (aout_symbol_type *) sym, + (struct external_nlist *) minisym, + (bfd_size_type) 1, + obj_aout_external_strings (abfd), + obj_aout_external_string_size (abfd), + false))) + return NULL; + + return sym; +} + +/* + provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. +*/ + +boolean +NAME(aout,find_nearest_line) + (abfd, section, symbols, offset, filename_ptr, functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *line_ptr; +{ + /* Run down the file looking for the filename, function and linenumber */ + asymbol **p; + CONST char *directory_name = NULL; + CONST char *main_file_name = NULL; + CONST char *current_file_name = NULL; + CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */ + bfd_vma low_line_vma = 0; + bfd_vma low_func_vma = 0; + asymbol *func = 0; + size_t filelen, funclen; + char *buf; + + *filename_ptr = abfd->filename; + *functionname_ptr = 0; + *line_ptr = 0; + if (symbols != (asymbol **)NULL) { + for (p = symbols; *p; p++) { + aout_symbol_type *q = (aout_symbol_type *)(*p); + next: + switch (q->type){ + case N_SO: + main_file_name = current_file_name = q->symbol.name; + /* Look ahead to next symbol to check if that too is an N_SO. */ + p++; + if (*p == NULL) + break; + q = (aout_symbol_type *)(*p); + if (q->type != (int)N_SO) + goto next; + + /* Found a second N_SO First is directory; second is filename. */ + directory_name = current_file_name; + main_file_name = current_file_name = q->symbol.name; + if (obj_textsec(abfd) != section) + goto done; + break; + case N_SOL: + current_file_name = q->symbol.name; + break; + + case N_SLINE: + + case N_DSLINE: + case N_BSLINE: + /* We'll keep this if it resolves nearer than the one we have + already. */ + if (q->symbol.value >= low_line_vma + && q->symbol.value <= offset) + { + *line_ptr = q->desc; + low_line_vma = q->symbol.value; + line_file_name = current_file_name; + } + break; + case N_FUN: + { + /* We'll keep this if it is nearer than the one we have already */ + if (q->symbol.value >= low_func_vma && + q->symbol.value <= offset) { + low_func_vma = q->symbol.value; + func = (asymbol *)q; + } + else if (q->symbol.value > offset) + goto done; + } + break; + } + } + } + + done: + if (*line_ptr != 0) + main_file_name = line_file_name; + + if (main_file_name == NULL + || main_file_name[0] == '/' + || directory_name == NULL) + filelen = 0; + else + filelen = strlen (directory_name) + strlen (main_file_name); + if (func == NULL) + funclen = 0; + else + funclen = strlen (bfd_asymbol_name (func)); + + if (adata (abfd).line_buf != NULL) + free (adata (abfd).line_buf); + if (filelen + funclen == 0) + adata (abfd).line_buf = buf = NULL; + else + { + buf = (char *) bfd_malloc (filelen + funclen + 2); + adata (abfd).line_buf = buf; + if (buf == NULL) + return false; + } + + if (main_file_name != NULL) + { + if (main_file_name[0] == '/' || directory_name == NULL) + *filename_ptr = main_file_name; + else + { + sprintf (buf, "%s%s", directory_name, main_file_name); + *filename_ptr = buf; + buf += filelen + 1; + } + } + + if (func) + { + const char *function = func->name; + char *p; + + /* The caller expects a symbol name. We actually have a + function name, without the leading underscore. Put the + underscore back in, so that the caller gets a symbol name. */ + if (bfd_get_symbol_leading_char (abfd) == '\0') + strcpy (buf, function); + else + { + buf[0] = bfd_get_symbol_leading_char (abfd); + strcpy (buf + 1, function); + } + /* Have to remove : stuff */ + p = strchr (buf, ':'); + if (p != NULL) + *p = '\0'; + *functionname_ptr = buf; + } + + return true; +} + +/*ARGSUSED*/ +int +NAME(aout,sizeof_headers) (abfd, execable) + bfd *abfd; + boolean execable; +{ + return adata(abfd).exec_bytes_size; +} + +/* Free all information we have cached for this BFD. We can always + read it again later if we need it. */ + +boolean +NAME(aout,bfd_free_cached_info) (abfd) + bfd *abfd; +{ + asection *o; + + if (bfd_get_format (abfd) != bfd_object) + return true; + +#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; } + BFCI_FREE (obj_aout_symbols (abfd)); +#ifdef USE_MMAP + obj_aout_external_syms (abfd) = 0; + bfd_free_window (&obj_aout_sym_window (abfd)); + bfd_free_window (&obj_aout_string_window (abfd)); + obj_aout_external_strings (abfd) = 0; +#else + BFCI_FREE (obj_aout_external_syms (abfd)); + BFCI_FREE (obj_aout_external_strings (abfd)); +#endif + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + BFCI_FREE (o->relocation); +#undef BFCI_FREE + + return true; +} + +/* a.out link code. */ + +static boolean aout_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean aout_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *)); +static boolean aout_link_free_symbols PARAMS ((bfd *)); +static boolean aout_link_check_ar_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean aout_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Routine to create an entry in an a.out link hash table. */ + +struct bfd_hash_entry * +NAME(aout,link_hash_newfunc) (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct aout_link_hash_entry *ret = (struct aout_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct aout_link_hash_entry *) NULL) + ret = ((struct aout_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct aout_link_hash_entry))); + if (ret == (struct aout_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct aout_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret) + { + /* Set local fields. */ + ret->written = false; + ret->indx = -1; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an a.out link hash table. */ + +boolean +NAME(aout,link_hash_table_init) (table, abfd, newfunc) + struct aout_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return _bfd_link_hash_table_init (&table->root, abfd, newfunc); +} + +/* Create an a.out link hash table. */ + +struct bfd_link_hash_table * +NAME(aout,link_hash_table_create) (abfd) + bfd *abfd; +{ + struct aout_link_hash_table *ret; + + ret = ((struct aout_link_hash_table *) + bfd_alloc (abfd, sizeof (struct aout_link_hash_table))); + if (ret == NULL) + return (struct bfd_link_hash_table *) NULL; + if (! NAME(aout,link_hash_table_init) (ret, abfd, + NAME(aout,link_hash_newfunc))) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Given an a.out BFD, add symbols to the global hash table as + appropriate. */ + +boolean +NAME(aout,link_add_symbols) (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return aout_link_add_object_symbols (abfd, info); + case bfd_archive: + return _bfd_generic_link_add_archive_symbols + (abfd, info, aout_link_check_archive_element); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add symbols from an a.out object file. */ + +static boolean +aout_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (! aout_get_external_symbols (abfd)) + return false; + if (! aout_link_add_symbols (abfd, info)) + return false; + if (! info->keep_memory) + { + if (! aout_link_free_symbols (abfd)) + return false; + } + return true; +} + +/* Check a single archive element to see if we need to include it in + the link. *PNEEDED is set according to whether this element is + needed in the link or not. This is called from + _bfd_generic_link_add_archive_symbols. */ + +static boolean +aout_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + if (! aout_get_external_symbols (abfd)) + return false; + + if (! aout_link_check_ar_symbols (abfd, info, pneeded)) + return false; + + if (*pneeded) + { + if (! aout_link_add_symbols (abfd, info)) + return false; + } + + if (! info->keep_memory || ! *pneeded) + { + if (! aout_link_free_symbols (abfd)) + return false; + } + + return true; +} + +/* Free up the internal symbols read from an a.out file. */ + +static boolean +aout_link_free_symbols (abfd) + bfd *abfd; +{ + if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL) + { +#ifdef USE_MMAP + bfd_free_window (&obj_aout_sym_window (abfd)); +#else + free ((PTR) obj_aout_external_syms (abfd)); +#endif + obj_aout_external_syms (abfd) = (struct external_nlist *) NULL; + } + if (obj_aout_external_strings (abfd) != (char *) NULL) + { +#ifdef USE_MMAP + bfd_free_window (&obj_aout_string_window (abfd)); +#else + free ((PTR) obj_aout_external_strings (abfd)); +#endif + obj_aout_external_strings (abfd) = (char *) NULL; + } + return true; +} + +/* Look through the internal symbols to see if this object file should + be included in the link. We should include this object file if it + defines any symbols which are currently undefined. If this object + file defines a common symbol, then we may adjust the size of the + known symbol but we do not include the object file in the link + (unless there is some other reason to include it). */ + +static boolean +aout_link_check_ar_symbols (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + register struct external_nlist *p; + struct external_nlist *pend; + char *strings; + + *pneeded = false; + + /* Look through all the symbols. */ + p = obj_aout_external_syms (abfd); + pend = p + obj_aout_external_sym_count (abfd); + strings = obj_aout_external_strings (abfd); + for (; p < pend; p++) + { + int type = bfd_h_get_8 (abfd, p->e_type); + const char *name; + struct bfd_link_hash_entry *h; + + /* Ignore symbols that are not externally visible. This is an + optimization only, as we check the type more thoroughly + below. */ + if (((type & N_EXT) == 0 + || (type & N_STAB) != 0 + || type == N_FN) + && type != N_WEAKA + && type != N_WEAKT + && type != N_WEAKD + && type != N_WEAKB) + { + if (type == N_WARNING + || type == N_INDR) + ++p; + continue; + } + + name = strings + GET_WORD (abfd, p->e_strx); + h = bfd_link_hash_lookup (info->hash, name, false, false, true); + + /* We are only interested in symbols that are currently + undefined or common. */ + if (h == (struct bfd_link_hash_entry *) NULL + || (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common)) + { + if (type == (N_INDR | N_EXT)) + ++p; + continue; + } + + if (type == (N_TEXT | N_EXT) + || type == (N_DATA | N_EXT) + || type == (N_BSS | N_EXT) + || type == (N_ABS | N_EXT) + || type == (N_INDR | N_EXT)) + { + /* This object file defines this symbol. We must link it + in. This is true regardless of whether the current + definition of the symbol is undefined or common. If the + current definition is common, we have a case in which we + have already seen an object file including + int a; + and this object file from the archive includes + int a = 5; + In such a case we must include this object file. + + FIXME: The SunOS 4.1.3 linker will pull in the archive + element if the symbol is defined in the .data section, + but not if it is defined in the .text section. That + seems a bit crazy to me, and I haven't implemented it. + However, it might be correct. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + return false; + *pneeded = true; + return true; + } + + if (type == (N_UNDF | N_EXT)) + { + bfd_vma value; + + value = GET_WORD (abfd, p->e_value); + if (value != 0) + { + /* This symbol is common in the object from the archive + file. */ + if (h->type == bfd_link_hash_undefined) + { + bfd *symbfd; + unsigned int power; + + symbfd = h->u.undef.abfd; + if (symbfd == (bfd *) NULL) + { + /* This symbol was created as undefined from + outside BFD. We assume that we should link + in the object file. This is done for the -u + option in the linker. */ + if (! (*info->callbacks->add_archive_element) (info, + abfd, + name)) + return false; + *pneeded = true; + return true; + } + /* Turn the current link symbol into a common + symbol. It is already on the undefs list. */ + h->type = bfd_link_hash_common; + h->u.c.p = ((struct bfd_link_hash_common_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_common_entry))); + if (h->u.c.p == NULL) + return false; + + h->u.c.size = value; + + /* FIXME: This isn't quite right. The maximum + alignment of a common symbol should be set by the + architecture of the output file, not of the input + file. */ + power = bfd_log2 (value); + if (power > bfd_get_arch_info (abfd)->section_align_power) + power = bfd_get_arch_info (abfd)->section_align_power; + h->u.c.p->alignment_power = power; + + h->u.c.p->section = bfd_make_section_old_way (symbfd, + "COMMON"); + } + else + { + /* Adjust the size of the common symbol if + necessary. */ + if (value > h->u.c.size) + h->u.c.size = value; + } + } + } + + if (type == N_WEAKA + || type == N_WEAKT + || type == N_WEAKD + || type == N_WEAKB) + { + /* This symbol is weak but defined. We must pull it in if + the current link symbol is undefined, but we don't want + it if the current link symbol is common. */ + if (h->type == bfd_link_hash_undefined) + { + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + return false; + *pneeded = true; + return true; + } + } + } + + /* We do not need this object file. */ + return true; +} + +/* Add all symbols from an object file to the hash table. */ + +static boolean +aout_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *, + const char *, flagword, asection *, + bfd_vma, const char *, boolean, + boolean, + struct bfd_link_hash_entry **)); + struct external_nlist *syms; + bfd_size_type sym_count; + char *strings; + boolean copy; + struct aout_link_hash_entry **sym_hash; + register struct external_nlist *p; + struct external_nlist *pend; + + syms = obj_aout_external_syms (abfd); + sym_count = obj_aout_external_sym_count (abfd); + strings = obj_aout_external_strings (abfd); + if (info->keep_memory) + copy = false; + else + copy = true; + + if ((abfd->flags & DYNAMIC) != 0 + && aout_backend_info (abfd)->add_dynamic_symbols != NULL) + { + if (! ((*aout_backend_info (abfd)->add_dynamic_symbols) + (abfd, info, &syms, &sym_count, &strings))) + return false; + } + + /* We keep a list of the linker hash table entries that correspond + to particular symbols. We could just look them up in the hash + table, but keeping the list is more efficient. Perhaps this + should be conditional on info->keep_memory. */ + sym_hash = ((struct aout_link_hash_entry **) + bfd_alloc (abfd, + ((size_t) sym_count + * sizeof (struct aout_link_hash_entry *)))); + if (sym_hash == NULL && sym_count != 0) + return false; + obj_aout_sym_hashes (abfd) = sym_hash; + + add_one_symbol = aout_backend_info (abfd)->add_one_symbol; + if (add_one_symbol == NULL) + add_one_symbol = _bfd_generic_link_add_one_symbol; + + p = syms; + pend = p + sym_count; + for (; p < pend; p++, sym_hash++) + { + int type; + const char *name; + bfd_vma value; + asection *section; + flagword flags; + const char *string; + + *sym_hash = NULL; + + type = bfd_h_get_8 (abfd, p->e_type); + + /* Ignore debugging symbols. */ + if ((type & N_STAB) != 0) + continue; + + name = strings + GET_WORD (abfd, p->e_strx); + value = GET_WORD (abfd, p->e_value); + flags = BSF_GLOBAL; + string = NULL; + switch (type) + { + default: + abort (); + + case N_UNDF: + case N_ABS: + case N_TEXT: + case N_DATA: + case N_BSS: + case N_FN_SEQ: + case N_COMM: + case N_SETV: + case N_FN: + /* Ignore symbols that are not externally visible. */ + continue; + case N_INDR: + /* Ignore local indirect symbol. */ + ++p; + ++sym_hash; + continue; + + case N_UNDF | N_EXT: + if (value == 0) + { + section = bfd_und_section_ptr; + flags = 0; + } + else + section = bfd_com_section_ptr; + break; + case N_ABS | N_EXT: + section = bfd_abs_section_ptr; + break; + case N_TEXT | N_EXT: + section = obj_textsec (abfd); + value -= bfd_get_section_vma (abfd, section); + break; + case N_DATA | N_EXT: + case N_SETV | N_EXT: + /* Treat N_SETV symbols as N_DATA symbol; see comment in + translate_from_native_sym_flags. */ + section = obj_datasec (abfd); + value -= bfd_get_section_vma (abfd, section); + break; + case N_BSS | N_EXT: + section = obj_bsssec (abfd); + value -= bfd_get_section_vma (abfd, section); + break; + case N_INDR | N_EXT: + /* An indirect symbol. The next symbol is the symbol + which this one really is. */ + BFD_ASSERT (p + 1 < pend); + ++p; + string = strings + GET_WORD (abfd, p->e_strx); + section = bfd_ind_section_ptr; + flags |= BSF_INDIRECT; + break; + case N_COMM | N_EXT: + section = bfd_com_section_ptr; + break; + case N_SETA: case N_SETA | N_EXT: + section = bfd_abs_section_ptr; + flags |= BSF_CONSTRUCTOR; + break; + case N_SETT: case N_SETT | N_EXT: + section = obj_textsec (abfd); + flags |= BSF_CONSTRUCTOR; + value -= bfd_get_section_vma (abfd, section); + break; + case N_SETD: case N_SETD | N_EXT: + section = obj_datasec (abfd); + flags |= BSF_CONSTRUCTOR; + value -= bfd_get_section_vma (abfd, section); + break; + case N_SETB: case N_SETB | N_EXT: + section = obj_bsssec (abfd); + flags |= BSF_CONSTRUCTOR; + value -= bfd_get_section_vma (abfd, section); + break; + case N_WARNING: + /* A warning symbol. The next symbol is the one to warn + about. */ + BFD_ASSERT (p + 1 < pend); + ++p; + string = name; + name = strings + GET_WORD (abfd, p->e_strx); + section = bfd_und_section_ptr; + flags |= BSF_WARNING; + break; + case N_WEAKU: + section = bfd_und_section_ptr; + flags = BSF_WEAK; + break; + case N_WEAKA: + section = bfd_abs_section_ptr; + flags = BSF_WEAK; + break; + case N_WEAKT: + section = obj_textsec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; + case N_WEAKD: + section = obj_datasec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; + case N_WEAKB: + section = obj_bsssec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; + } + + if (! ((*add_one_symbol) + (info, abfd, name, flags, section, value, string, copy, false, + (struct bfd_link_hash_entry **) sym_hash))) + return false; + + /* Restrict the maximum alignment of a common symbol based on + the architecture, since a.out has no way to represent + alignment requirements of a section in a .o file. FIXME: + This isn't quite right: it should use the architecture of the + output file, not the input files. */ + if ((*sym_hash)->root.type == bfd_link_hash_common + && ((*sym_hash)->root.u.c.p->alignment_power > + bfd_get_arch_info (abfd)->section_align_power)) + (*sym_hash)->root.u.c.p->alignment_power = + bfd_get_arch_info (abfd)->section_align_power; + + /* If this is a set symbol, and we are not building sets, then + it is possible for the hash entry to not have been set. In + such a case, treat the symbol as not globally defined. */ + if ((*sym_hash)->root.type == bfd_link_hash_new) + { + BFD_ASSERT ((flags & BSF_CONSTRUCTOR) != 0); + *sym_hash = NULL; + } + + if (type == (N_INDR | N_EXT) || type == N_WARNING) + ++sym_hash; + } + + return true; +} + +/* A hash table used for header files with N_BINCL entries. */ + +struct aout_link_includes_table +{ + struct bfd_hash_table root; +}; + +/* A linked list of totals that we have found for a particular header + file. */ + +struct aout_link_includes_totals +{ + struct aout_link_includes_totals *next; + bfd_vma total; +}; + +/* An entry in the header file hash table. */ + +struct aout_link_includes_entry +{ + struct bfd_hash_entry root; + /* List of totals we have found for this file. */ + struct aout_link_includes_totals *totals; +}; + +/* Look up an entry in an the header file hash table. */ + +#define aout_link_includes_lookup(table, string, create, copy) \ + ((struct aout_link_includes_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* During the final link step we need to pass around a bunch of + information, so we do it in an instance of this structure. */ + +struct aout_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output bfd. */ + bfd *output_bfd; + /* Reloc file positions. */ + file_ptr treloff, dreloff; + /* File position of symbols. */ + file_ptr symoff; + /* String table. */ + struct bfd_strtab_hash *strtab; + /* Header file hash table. */ + struct aout_link_includes_table includes; + /* A buffer large enough to hold the contents of any section. */ + bfd_byte *contents; + /* A buffer large enough to hold the relocs of any section. */ + PTR relocs; + /* A buffer large enough to hold the symbol map of any input BFD. */ + int *symbol_map; + /* A buffer large enough to hold output symbols of any input BFD. */ + struct external_nlist *output_syms; +}; + +static struct bfd_hash_entry *aout_link_includes_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean aout_link_input_bfd + PARAMS ((struct aout_final_link_info *, bfd *input_bfd)); +static boolean aout_link_write_symbols + PARAMS ((struct aout_final_link_info *, bfd *input_bfd)); +static boolean aout_link_write_other_symbol + PARAMS ((struct aout_link_hash_entry *, PTR)); +static boolean aout_link_input_section + PARAMS ((struct aout_final_link_info *, bfd *input_bfd, + asection *input_section, file_ptr *reloff_ptr, + bfd_size_type rel_size)); +static boolean aout_link_input_section_std + PARAMS ((struct aout_final_link_info *, bfd *input_bfd, + asection *input_section, struct reloc_std_external *, + bfd_size_type rel_size, bfd_byte *contents)); +static boolean aout_link_input_section_ext + PARAMS ((struct aout_final_link_info *, bfd *input_bfd, + asection *input_section, struct reloc_ext_external *, + bfd_size_type rel_size, bfd_byte *contents)); +static INLINE asection *aout_reloc_index_to_section + PARAMS ((bfd *, int)); +static boolean aout_link_reloc_link_order + PARAMS ((struct aout_final_link_info *, asection *, + struct bfd_link_order *)); + +/* The function to create a new entry in the header file hash table. */ + +static struct bfd_hash_entry * +aout_link_includes_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct aout_link_includes_entry *ret = + (struct aout_link_includes_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct aout_link_includes_entry *) NULL) + ret = ((struct aout_link_includes_entry *) + bfd_hash_allocate (table, + sizeof (struct aout_link_includes_entry))); + if (ret == (struct aout_link_includes_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct aout_link_includes_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret) + { + /* Set local fields. */ + ret->totals = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Do the final link step. This is called on the output BFD. The + INFO structure should point to a list of BFDs linked through the + link_next field which can be used to find each BFD which takes part + in the output. Also, each section in ABFD should point to a list + of bfd_link_order structures which list all the input sections for + the output section. */ + +boolean +NAME(aout,final_link) (abfd, info, callback) + bfd *abfd; + struct bfd_link_info *info; + void (*callback) PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); +{ + struct aout_final_link_info aout_info; + boolean includes_hash_initialized = false; + register bfd *sub; + bfd_size_type trsize, drsize; + size_t max_contents_size; + size_t max_relocs_size; + size_t max_sym_count; + bfd_size_type text_size; + file_ptr text_end; + register struct bfd_link_order *p; + asection *o; + boolean have_link_order_relocs; + + if (info->shared) + abfd->flags |= DYNAMIC; + + aout_info.info = info; + aout_info.output_bfd = abfd; + aout_info.contents = NULL; + aout_info.relocs = NULL; + aout_info.symbol_map = NULL; + aout_info.output_syms = NULL; + + if (! bfd_hash_table_init_n (&aout_info.includes.root, + aout_link_includes_newfunc, + 251)) + goto error_return; + includes_hash_initialized = true; + + /* Figure out the largest section size. Also, if generating + relocateable output, count the relocs. */ + trsize = 0; + drsize = 0; + max_contents_size = 0; + max_relocs_size = 0; + max_sym_count = 0; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + size_t sz; + + if (info->relocateable) + { + if (bfd_get_flavour (sub) == bfd_target_aout_flavour) + { + trsize += exec_hdr (sub)->a_trsize; + drsize += exec_hdr (sub)->a_drsize; + } + else + { + /* FIXME: We need to identify the .text and .data sections + and call get_reloc_upper_bound and canonicalize_reloc to + work out the number of relocs needed, and then multiply + by the reloc size. */ + (*_bfd_error_handler) + ("%s: relocateable link from %s to %s not supported", + bfd_get_filename (abfd), + sub->xvec->name, abfd->xvec->name); + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + } + + if (bfd_get_flavour (sub) == bfd_target_aout_flavour) + { + sz = bfd_section_size (sub, obj_textsec (sub)); + if (sz > max_contents_size) + max_contents_size = sz; + sz = bfd_section_size (sub, obj_datasec (sub)); + if (sz > max_contents_size) + max_contents_size = sz; + + sz = exec_hdr (sub)->a_trsize; + if (sz > max_relocs_size) + max_relocs_size = sz; + sz = exec_hdr (sub)->a_drsize; + if (sz > max_relocs_size) + max_relocs_size = sz; + + sz = obj_aout_external_sym_count (sub); + if (sz > max_sym_count) + max_sym_count = sz; + } + } + + if (info->relocateable) + { + if (obj_textsec (abfd) != (asection *) NULL) + trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd) + ->link_order_head) + * obj_reloc_entry_size (abfd)); + if (obj_datasec (abfd) != (asection *) NULL) + drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd) + ->link_order_head) + * obj_reloc_entry_size (abfd)); + } + + exec_hdr (abfd)->a_trsize = trsize; + exec_hdr (abfd)->a_drsize = drsize; + + exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); + + /* Adjust the section sizes and vmas according to the magic number. + This sets a_text, a_data and a_bss in the exec_hdr and sets the + filepos for each section. */ + if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end)) + goto error_return; + + /* The relocation and symbol file positions differ among a.out + targets. We are passed a callback routine from the backend + specific code to handle this. + FIXME: At this point we do not know how much space the symbol + table will require. This will not work for any (nonstandard) + a.out target that needs to know the symbol table size before it + can compute the relocation file positions. This may or may not + be the case for the hp300hpux target, for example. */ + (*callback) (abfd, &aout_info.treloff, &aout_info.dreloff, + &aout_info.symoff); + obj_textsec (abfd)->rel_filepos = aout_info.treloff; + obj_datasec (abfd)->rel_filepos = aout_info.dreloff; + obj_sym_filepos (abfd) = aout_info.symoff; + + /* We keep a count of the symbols as we output them. */ + obj_aout_external_sym_count (abfd) = 0; + + /* We accumulate the string table as we write out the symbols. */ + aout_info.strtab = _bfd_stringtab_init (); + if (aout_info.strtab == NULL) + goto error_return; + + /* Allocate buffers to hold section contents and relocs. */ + aout_info.contents = (bfd_byte *) bfd_malloc (max_contents_size); + aout_info.relocs = (PTR) bfd_malloc (max_relocs_size); + aout_info.symbol_map = (int *) bfd_malloc (max_sym_count * sizeof (int *)); + aout_info.output_syms = ((struct external_nlist *) + bfd_malloc ((max_sym_count + 1) + * sizeof (struct external_nlist))); + if ((aout_info.contents == NULL && max_contents_size != 0) + || (aout_info.relocs == NULL && max_relocs_size != 0) + || (aout_info.symbol_map == NULL && max_sym_count != 0) + || aout_info.output_syms == NULL) + goto error_return; + + /* If we have a symbol named __DYNAMIC, force it out now. This is + required by SunOS. Doing this here rather than in sunos.c is a + hack, but it's easier than exporting everything which would be + needed. */ + { + struct aout_link_hash_entry *h; + + h = aout_link_hash_lookup (aout_hash_table (info), "__DYNAMIC", + false, false, false); + if (h != NULL) + aout_link_write_other_symbol (h, &aout_info); + } + + /* The most time efficient way to do the link would be to read all + the input object files into memory and then sort out the + information into the output file. Unfortunately, that will + probably use too much memory. Another method would be to step + through everything that composes the text section and write it + out, and then everything that composes the data section and write + it out, and then write out the relocs, and then write out the + symbols. Unfortunately, that requires reading stuff from each + input file several times, and we will not be able to keep all the + input files open simultaneously, and reopening them will be slow. + + What we do is basically process one input file at a time. We do + everything we need to do with an input file once--copy over the + section contents, handle the relocation information, and write + out the symbols--and then we throw away the information we read + from it. This approach requires a lot of lseeks of the output + file, which is unfortunate but still faster than reopening a lot + of files. + + We use the output_has_begun field of the input BFDs to see + whether we have already handled it. */ + for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) + sub->output_has_begun = false; + + have_link_order_relocs = false; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_aout_flavour)) + { + bfd *input_bfd; + + input_bfd = p->u.indirect.section->owner; + if (! input_bfd->output_has_begun) + { + if (! aout_link_input_bfd (&aout_info, input_bfd)) + goto error_return; + input_bfd->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + /* These are handled below. */ + have_link_order_relocs = true; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* Write out any symbols that we have not already written out. */ + aout_link_hash_traverse (aout_hash_table (info), + aout_link_write_other_symbol, + (PTR) &aout_info); + + /* Now handle any relocs we were asked to create by the linker. + These did not come from any input file. We must do these after + we have written out all the symbols, so that we know the symbol + indices to use. */ + if (have_link_order_relocs) + { + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! aout_link_reloc_link_order (&aout_info, o, p)) + goto error_return; + } + } + } + } + + if (aout_info.contents != NULL) + { + free (aout_info.contents); + aout_info.contents = NULL; + } + if (aout_info.relocs != NULL) + { + free (aout_info.relocs); + aout_info.relocs = NULL; + } + if (aout_info.symbol_map != NULL) + { + free (aout_info.symbol_map); + aout_info.symbol_map = NULL; + } + if (aout_info.output_syms != NULL) + { + free (aout_info.output_syms); + aout_info.output_syms = NULL; + } + if (includes_hash_initialized) + { + bfd_hash_table_free (&aout_info.includes.root); + includes_hash_initialized = false; + } + + /* Finish up any dynamic linking we may be doing. */ + if (aout_backend_info (abfd)->finish_dynamic_link != NULL) + { + if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info)) + goto error_return; + } + + /* Update the header information. */ + abfd->symcount = obj_aout_external_sym_count (abfd); + exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE; + obj_str_filepos (abfd) = obj_sym_filepos (abfd) + exec_hdr (abfd)->a_syms; + obj_textsec (abfd)->reloc_count = + exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd); + obj_datasec (abfd)->reloc_count = + exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd); + + /* Write out the string table. */ + if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0) + goto error_return; + return emit_stringtab (abfd, aout_info.strtab); + + error_return: + if (aout_info.contents != NULL) + free (aout_info.contents); + if (aout_info.relocs != NULL) + free (aout_info.relocs); + if (aout_info.symbol_map != NULL) + free (aout_info.symbol_map); + if (aout_info.output_syms != NULL) + free (aout_info.output_syms); + if (includes_hash_initialized) + bfd_hash_table_free (&aout_info.includes.root); + return false; +} + +/* Link an a.out input BFD into the output file. */ + +static boolean +aout_link_input_bfd (finfo, input_bfd) + struct aout_final_link_info *finfo; + bfd *input_bfd; +{ + bfd_size_type sym_count; + + BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object); + + /* If this is a dynamic object, it may need special handling. */ + if ((input_bfd->flags & DYNAMIC) != 0 + && aout_backend_info (input_bfd)->link_dynamic_object != NULL) + { + return ((*aout_backend_info (input_bfd)->link_dynamic_object) + (finfo->info, input_bfd)); + } + + /* Get the symbols. We probably have them already, unless + finfo->info->keep_memory is false. */ + if (! aout_get_external_symbols (input_bfd)) + return false; + + sym_count = obj_aout_external_sym_count (input_bfd); + + /* Write out the symbols and get a map of the new indices. The map + is placed into finfo->symbol_map. */ + if (! aout_link_write_symbols (finfo, input_bfd)) + return false; + + /* Relocate and write out the sections. These functions use the + symbol map created by aout_link_write_symbols. */ + if (! aout_link_input_section (finfo, input_bfd, + obj_textsec (input_bfd), + &finfo->treloff, + exec_hdr (input_bfd)->a_trsize) + || ! aout_link_input_section (finfo, input_bfd, + obj_datasec (input_bfd), + &finfo->dreloff, + exec_hdr (input_bfd)->a_drsize)) + return false; + + /* If we are not keeping memory, we don't need the symbols any + longer. We still need them if we are keeping memory, because the + strings in the hash table point into them. */ + if (! finfo->info->keep_memory) + { + if (! aout_link_free_symbols (input_bfd)) + return false; + } + + return true; +} + +/* Adjust and write out the symbols for an a.out file. Set the new + symbol indices into a symbol_map. */ + +static boolean +aout_link_write_symbols (finfo, input_bfd) + struct aout_final_link_info *finfo; + bfd *input_bfd; +{ + bfd *output_bfd; + bfd_size_type sym_count; + char *strings; + enum bfd_link_strip strip; + enum bfd_link_discard discard; + struct external_nlist *outsym; + bfd_size_type strtab_index; + register struct external_nlist *sym; + struct external_nlist *sym_end; + struct aout_link_hash_entry **sym_hash; + int *symbol_map; + boolean pass; + boolean skip_next; + + output_bfd = finfo->output_bfd; + sym_count = obj_aout_external_sym_count (input_bfd); + strings = obj_aout_external_strings (input_bfd); + strip = finfo->info->strip; + discard = finfo->info->discard; + outsym = finfo->output_syms; + + /* First write out a symbol for this object file, unless we are + discarding such symbols. */ + if (strip != strip_all + && (strip != strip_some + || bfd_hash_lookup (finfo->info->keep_hash, input_bfd->filename, + false, false) != NULL) + && discard != discard_all) + { + bfd_h_put_8 (output_bfd, N_TEXT, outsym->e_type); + bfd_h_put_8 (output_bfd, 0, outsym->e_other); + bfd_h_put_16 (output_bfd, (bfd_vma) 0, outsym->e_desc); + strtab_index = add_to_stringtab (output_bfd, finfo->strtab, + input_bfd->filename, false); + if (strtab_index == (bfd_size_type) -1) + return false; + PUT_WORD (output_bfd, strtab_index, outsym->e_strx); + PUT_WORD (output_bfd, + (bfd_get_section_vma (output_bfd, + obj_textsec (input_bfd)->output_section) + + obj_textsec (input_bfd)->output_offset), + outsym->e_value); + ++obj_aout_external_sym_count (output_bfd); + ++outsym; + } + + pass = false; + skip_next = false; + sym = obj_aout_external_syms (input_bfd); + sym_end = sym + sym_count; + sym_hash = obj_aout_sym_hashes (input_bfd); + symbol_map = finfo->symbol_map; + memset (symbol_map, 0, sym_count * sizeof *symbol_map); + for (; sym < sym_end; sym++, sym_hash++, symbol_map++) + { + const char *name; + int type; + struct aout_link_hash_entry *h; + boolean skip; + asection *symsec; + bfd_vma val = 0; + boolean copy; + + /* We set *symbol_map to 0 above for all symbols. If it has + already been set to -1 for this symbol, it means that we are + discarding it because it appears in a duplicate header file. + See the N_BINCL code below. */ + if (*symbol_map == -1) + continue; + + /* Initialize *symbol_map to -1, which means that the symbol was + not copied into the output file. We will change it later if + we do copy the symbol over. */ + *symbol_map = -1; + + type = bfd_h_get_8 (input_bfd, sym->e_type); + name = strings + GET_WORD (input_bfd, sym->e_strx); + + h = NULL; + + if (pass) + { + /* Pass this symbol through. It is the target of an + indirect or warning symbol. */ + val = GET_WORD (input_bfd, sym->e_value); + pass = false; + } + else if (skip_next) + { + /* Skip this symbol, which is the target of an indirect + symbol that we have changed to no longer be an indirect + symbol. */ + skip_next = false; + continue; + } + else + { + struct aout_link_hash_entry *hresolve; + + /* We have saved the hash table entry for this symbol, if + there is one. Note that we could just look it up again + in the hash table, provided we first check that it is an + external symbol. */ + h = *sym_hash; + + /* Use the name from the hash table, in case the symbol was + wrapped. */ + if (h != NULL) + name = h->root.root.string; + + /* If this is an indirect or warning symbol, then change + hresolve to the base symbol. We also change *sym_hash so + that the relocation routines relocate against the real + symbol. */ + hresolve = h; + if (h != (struct aout_link_hash_entry *) NULL + && (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning)) + { + hresolve = (struct aout_link_hash_entry *) h->root.u.i.link; + while (hresolve->root.type == bfd_link_hash_indirect + || hresolve->root.type == bfd_link_hash_warning) + hresolve = ((struct aout_link_hash_entry *) + hresolve->root.u.i.link); + *sym_hash = hresolve; + } + + /* If the symbol has already been written out, skip it. */ + if (h != (struct aout_link_hash_entry *) NULL + && h->root.type != bfd_link_hash_warning + && h->written) + { + if ((type & N_TYPE) == N_INDR + || type == N_WARNING) + skip_next = true; + *symbol_map = h->indx; + continue; + } + + /* See if we are stripping this symbol. */ + skip = false; + switch (strip) + { + case strip_none: + break; + case strip_debugger: + if ((type & N_STAB) != 0) + skip = true; + break; + case strip_some: + if (bfd_hash_lookup (finfo->info->keep_hash, name, false, false) + == NULL) + skip = true; + break; + case strip_all: + skip = true; + break; + } + if (skip) + { + if (h != (struct aout_link_hash_entry *) NULL) + h->written = true; + continue; + } + + /* Get the value of the symbol. */ + if ((type & N_TYPE) == N_TEXT + || type == N_WEAKT) + symsec = obj_textsec (input_bfd); + else if ((type & N_TYPE) == N_DATA + || type == N_WEAKD) + symsec = obj_datasec (input_bfd); + else if ((type & N_TYPE) == N_BSS + || type == N_WEAKB) + symsec = obj_bsssec (input_bfd); + else if ((type & N_TYPE) == N_ABS + || type == N_WEAKA) + symsec = bfd_abs_section_ptr; + else if (((type & N_TYPE) == N_INDR + && (hresolve == (struct aout_link_hash_entry *) NULL + || (hresolve->root.type != bfd_link_hash_defined + && hresolve->root.type != bfd_link_hash_defweak + && hresolve->root.type != bfd_link_hash_common))) + || type == N_WARNING) + { + /* Pass the next symbol through unchanged. The + condition above for indirect symbols is so that if + the indirect symbol was defined, we output it with + the correct definition so the debugger will + understand it. */ + pass = true; + val = GET_WORD (input_bfd, sym->e_value); + symsec = NULL; + } + else if ((type & N_STAB) != 0) + { + val = GET_WORD (input_bfd, sym->e_value); + symsec = NULL; + } + else + { + /* If we get here with an indirect symbol, it means that + we are outputting it with a real definition. In such + a case we do not want to output the next symbol, + which is the target of the indirection. */ + if ((type & N_TYPE) == N_INDR) + skip_next = true; + + symsec = NULL; + + /* We need to get the value from the hash table. We use + hresolve so that if we have defined an indirect + symbol we output the final definition. */ + if (h == (struct aout_link_hash_entry *) NULL) + { + switch (type & N_TYPE) + { + case N_SETT: + symsec = obj_textsec (input_bfd); + break; + case N_SETD: + symsec = obj_datasec (input_bfd); + break; + case N_SETB: + symsec = obj_bsssec (input_bfd); + break; + case N_SETA: + symsec = bfd_abs_section_ptr; + break; + default: + val = 0; + break; + } + } + else if (hresolve->root.type == bfd_link_hash_defined + || hresolve->root.type == bfd_link_hash_defweak) + { + asection *input_section; + asection *output_section; + + /* This case usually means a common symbol which was + turned into a defined symbol. */ + input_section = hresolve->root.u.def.section; + output_section = input_section->output_section; + BFD_ASSERT (bfd_is_abs_section (output_section) + || output_section->owner == output_bfd); + val = (hresolve->root.u.def.value + + bfd_get_section_vma (output_bfd, output_section) + + input_section->output_offset); + + /* Get the correct type based on the section. If + this is a constructed set, force it to be + globally visible. */ + if (type == N_SETT + || type == N_SETD + || type == N_SETB + || type == N_SETA) + type |= N_EXT; + + type &=~ N_TYPE; + + if (output_section == obj_textsec (output_bfd)) + type |= (hresolve->root.type == bfd_link_hash_defined + ? N_TEXT + : N_WEAKT); + else if (output_section == obj_datasec (output_bfd)) + type |= (hresolve->root.type == bfd_link_hash_defined + ? N_DATA + : N_WEAKD); + else if (output_section == obj_bsssec (output_bfd)) + type |= (hresolve->root.type == bfd_link_hash_defined + ? N_BSS + : N_WEAKB); + else + type |= (hresolve->root.type == bfd_link_hash_defined + ? N_ABS + : N_WEAKA); + } + else if (hresolve->root.type == bfd_link_hash_common) + val = hresolve->root.u.c.size; + else if (hresolve->root.type == bfd_link_hash_undefweak) + { + val = 0; + type = N_WEAKU; + } + else + val = 0; + } + if (symsec != (asection *) NULL) + val = (symsec->output_section->vma + + symsec->output_offset + + (GET_WORD (input_bfd, sym->e_value) + - symsec->vma)); + + /* If this is a global symbol set the written flag, and if + it is a local symbol see if we should discard it. */ + if (h != (struct aout_link_hash_entry *) NULL) + { + h->written = true; + h->indx = obj_aout_external_sym_count (output_bfd); + } + else if ((type & N_TYPE) != N_SETT + && (type & N_TYPE) != N_SETD + && (type & N_TYPE) != N_SETB + && (type & N_TYPE) != N_SETA) + { + switch (discard) + { + case discard_none: + break; + case discard_l: + if (*name == *finfo->info->lprefix + && (finfo->info->lprefix_len == 1 + || strncmp (name, finfo->info->lprefix, + finfo->info->lprefix_len) == 0)) + skip = true; + break; + case discard_all: + skip = true; + break; + } + if (skip) + { + pass = false; + continue; + } + } + + /* An N_BINCL symbol indicates the start of the stabs + entries for a header file. We need to scan ahead to the + next N_EINCL symbol, ignoring nesting, adding up all the + characters in the symbol names, not including the file + numbers in types (the first number after an open + parenthesis). */ + if (type == N_BINCL) + { + struct external_nlist *incl_sym; + int nest; + struct aout_link_includes_entry *incl_entry; + struct aout_link_includes_totals *t; + + val = 0; + nest = 0; + for (incl_sym = sym + 1; incl_sym < sym_end; incl_sym++) + { + int incl_type; + + incl_type = bfd_h_get_8 (input_bfd, incl_sym->e_type); + if (incl_type == N_EINCL) + { + if (nest == 0) + break; + --nest; + } + else if (incl_type == N_BINCL) + ++nest; + else if (nest == 0) + { + const char *s; + + s = strings + GET_WORD (input_bfd, incl_sym->e_strx); + for (; *s != '\0'; s++) + { + val += *s; + if (*s == '(') + { + /* Skip the file number. */ + ++s; + while (isdigit ((unsigned char) *s)) + ++s; + --s; + } + } + } + } + + /* If we have already included a header file with the + same value, then replace this one with an N_EXCL + symbol. */ + copy = ! finfo->info->keep_memory; + incl_entry = aout_link_includes_lookup (&finfo->includes, + name, true, copy); + if (incl_entry == NULL) + return false; + for (t = incl_entry->totals; t != NULL; t = t->next) + if (t->total == val) + break; + if (t == NULL) + { + /* This is the first time we have seen this header + file with this set of stabs strings. */ + t = ((struct aout_link_includes_totals *) + bfd_hash_allocate (&finfo->includes.root, + sizeof *t)); + if (t == NULL) + return false; + t->total = val; + t->next = incl_entry->totals; + incl_entry->totals = t; + } + else + { + int *incl_map; + + /* This is a duplicate header file. We must change + it to be an N_EXCL entry, and mark all the + included symbols to prevent outputting them. */ + type = N_EXCL; + + nest = 0; + for (incl_sym = sym + 1, incl_map = symbol_map + 1; + incl_sym < sym_end; + incl_sym++, incl_map++) + { + int incl_type; + + incl_type = bfd_h_get_8 (input_bfd, incl_sym->e_type); + if (incl_type == N_EINCL) + { + if (nest == 0) + { + *incl_map = -1; + break; + } + --nest; + } + else if (incl_type == N_BINCL) + ++nest; + else if (nest == 0) + *incl_map = -1; + } + } + } + } + + /* Copy this symbol into the list of symbols we are going to + write out. */ + bfd_h_put_8 (output_bfd, type, outsym->e_type); + bfd_h_put_8 (output_bfd, bfd_h_get_8 (input_bfd, sym->e_other), + outsym->e_other); + bfd_h_put_16 (output_bfd, bfd_h_get_16 (input_bfd, sym->e_desc), + outsym->e_desc); + copy = false; + if (! finfo->info->keep_memory) + { + /* name points into a string table which we are going to + free. If there is a hash table entry, use that string. + Otherwise, copy name into memory. */ + if (h != (struct aout_link_hash_entry *) NULL) + name = h->root.root.string; + else + copy = true; + } + strtab_index = add_to_stringtab (output_bfd, finfo->strtab, + name, copy); + if (strtab_index == (bfd_size_type) -1) + return false; + PUT_WORD (output_bfd, strtab_index, outsym->e_strx); + PUT_WORD (output_bfd, val, outsym->e_value); + *symbol_map = obj_aout_external_sym_count (output_bfd); + ++obj_aout_external_sym_count (output_bfd); + ++outsym; + } + + /* Write out the output symbols we have just constructed. */ + if (outsym > finfo->output_syms) + { + bfd_size_type outsym_count; + + if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0) + return false; + outsym_count = outsym - finfo->output_syms; + if (bfd_write ((PTR) finfo->output_syms, + (bfd_size_type) EXTERNAL_NLIST_SIZE, + (bfd_size_type) outsym_count, output_bfd) + != outsym_count * EXTERNAL_NLIST_SIZE) + return false; + finfo->symoff += outsym_count * EXTERNAL_NLIST_SIZE; + } + + return true; +} + +/* Write out a symbol that was not associated with an a.out input + object. */ + +static boolean +aout_link_write_other_symbol (h, data) + struct aout_link_hash_entry *h; + PTR data; +{ + struct aout_final_link_info *finfo = (struct aout_final_link_info *) data; + bfd *output_bfd; + int type; + bfd_vma val; + struct external_nlist outsym; + bfd_size_type indx; + + output_bfd = finfo->output_bfd; + + if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL) + { + if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol) + (output_bfd, finfo->info, h))) + { + /* FIXME: No way to handle errors. */ + abort (); + } + } + + if (h->written) + return true; + + h->written = true; + + /* An indx of -2 means the symbol must be written. */ + if (h->indx != -2 + && (finfo->info->strip == strip_all + || (finfo->info->strip == strip_some + && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string, + false, false) == NULL))) + return true; + + switch (h->root.type) + { + default: + abort (); + /* Avoid variable not initialized warnings. */ + return true; + case bfd_link_hash_new: + /* This can happen for set symbols when sets are not being + built. */ + return true; + case bfd_link_hash_undefined: + type = N_UNDF | N_EXT; + val = 0; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + { + asection *sec; + + sec = h->root.u.def.section->output_section; + BFD_ASSERT (bfd_is_abs_section (sec) + || sec->owner == output_bfd); + if (sec == obj_textsec (output_bfd)) + type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT; + else if (sec == obj_datasec (output_bfd)) + type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD; + else if (sec == obj_bsssec (output_bfd)) + type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB; + else + type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA; + type |= N_EXT; + val = (h->root.u.def.value + + sec->vma + + h->root.u.def.section->output_offset); + } + break; + case bfd_link_hash_common: + type = N_UNDF | N_EXT; + val = h->root.u.c.size; + break; + case bfd_link_hash_undefweak: + type = N_WEAKU; + val = 0; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: Ignore these for now. The circumstances under which + they should be written out are not clear to me. */ + return true; + } + + bfd_h_put_8 (output_bfd, type, outsym.e_type); + bfd_h_put_8 (output_bfd, 0, outsym.e_other); + bfd_h_put_16 (output_bfd, 0, outsym.e_desc); + indx = add_to_stringtab (output_bfd, finfo->strtab, h->root.root.string, + false); + if (indx == (bfd_size_type) -1) + { + /* FIXME: No way to handle errors. */ + abort (); + } + PUT_WORD (output_bfd, indx, outsym.e_strx); + PUT_WORD (output_bfd, val, outsym.e_value); + + if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0 + || bfd_write ((PTR) &outsym, (bfd_size_type) EXTERNAL_NLIST_SIZE, + (bfd_size_type) 1, output_bfd) != EXTERNAL_NLIST_SIZE) + { + /* FIXME: No way to handle errors. */ + abort (); + } + + finfo->symoff += EXTERNAL_NLIST_SIZE; + h->indx = obj_aout_external_sym_count (output_bfd); + ++obj_aout_external_sym_count (output_bfd); + + return true; +} + +/* Link an a.out section into the output file. */ + +static boolean +aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr, + rel_size) + struct aout_final_link_info *finfo; + bfd *input_bfd; + asection *input_section; + file_ptr *reloff_ptr; + bfd_size_type rel_size; +{ + bfd_size_type input_size; + PTR relocs; + + /* Get the section contents. */ + input_size = bfd_section_size (input_bfd, input_section); + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) finfo->contents, + (file_ptr) 0, input_size)) + return false; + + /* Read in the relocs if we haven't already done it. */ + if (aout_section_data (input_section) != NULL + && aout_section_data (input_section)->relocs != NULL) + relocs = aout_section_data (input_section)->relocs; + else + { + relocs = finfo->relocs; + if (rel_size > 0) + { + if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 + || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size) + return false; + } + } + + /* Relocate the section contents. */ + if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) + { + if (! aout_link_input_section_std (finfo, input_bfd, input_section, + (struct reloc_std_external *) relocs, + rel_size, finfo->contents)) + return false; + } + else + { + if (! aout_link_input_section_ext (finfo, input_bfd, input_section, + (struct reloc_ext_external *) relocs, + rel_size, finfo->contents)) + return false; + } + + /* Write out the section contents. */ + if (! bfd_set_section_contents (finfo->output_bfd, + input_section->output_section, + (PTR) finfo->contents, + input_section->output_offset, + input_size)) + return false; + + /* If we are producing relocateable output, the relocs were + modified, and we now write them out. */ + if (finfo->info->relocateable && rel_size > 0) + { + if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0) + return false; + if (bfd_write (relocs, (bfd_size_type) 1, rel_size, finfo->output_bfd) + != rel_size) + return false; + *reloff_ptr += rel_size; + + /* Assert that the relocs have not run into the symbols, and + that if these are the text relocs they have not run into the + data relocs. */ + BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd) + && (reloff_ptr != &finfo->treloff + || (*reloff_ptr + <= obj_datasec (finfo->output_bfd)->rel_filepos))); + } + + return true; +} + +/* Get the section corresponding to a reloc index. */ + +static INLINE asection * +aout_reloc_index_to_section (abfd, indx) + bfd *abfd; + int indx; +{ + switch (indx & N_TYPE) + { + case N_TEXT: + return obj_textsec (abfd); + case N_DATA: + return obj_datasec (abfd); + case N_BSS: + return obj_bsssec (abfd); + case N_ABS: + case N_UNDF: + return bfd_abs_section_ptr; + default: + abort (); + } +} + +/* Relocate an a.out section using standard a.out relocs. */ + +static boolean +aout_link_input_section_std (finfo, input_bfd, input_section, relocs, + rel_size, contents) + struct aout_final_link_info *finfo; + bfd *input_bfd; + asection *input_section; + struct reloc_std_external *relocs; + bfd_size_type rel_size; + bfd_byte *contents; +{ + boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *, + bfd *, asection *, + struct aout_link_hash_entry *, + PTR, bfd_byte *, boolean *, + bfd_vma *)); + bfd *output_bfd; + boolean relocateable; + struct external_nlist *syms; + char *strings; + struct aout_link_hash_entry **sym_hashes; + int *symbol_map; + bfd_size_type reloc_count; + register struct reloc_std_external *rel; + struct reloc_std_external *rel_end; + + output_bfd = finfo->output_bfd; + check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc; + + BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE); + BFD_ASSERT (input_bfd->xvec->header_byteorder + == output_bfd->xvec->header_byteorder); + + relocateable = finfo->info->relocateable; + syms = obj_aout_external_syms (input_bfd); + strings = obj_aout_external_strings (input_bfd); + sym_hashes = obj_aout_sym_hashes (input_bfd); + symbol_map = finfo->symbol_map; + + reloc_count = rel_size / RELOC_STD_SIZE; + rel = relocs; + rel_end = rel + reloc_count; + for (; rel < rel_end; rel++) + { + bfd_vma r_addr; + int r_index; + int r_extern; + int r_pcrel; + int r_baserel = 0; + reloc_howto_type *howto; + struct aout_link_hash_entry *h = NULL; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_addr = GET_SWORD (input_bfd, rel->r_address); + +#ifdef MY_reloc_howto + howto = MY_reloc_howto(input_bfd, rel, r_index, r_extern, r_pcrel); +#else + { + int r_jmptable; + int r_relative; + int r_length; + unsigned int howto_idx; + + if (bfd_header_big_endian (input_bfd)) + { + r_index = ((rel->r_index[0] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[2]); + r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); + r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); + r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG)); + r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG); + } + else + { + r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0]); + r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_baserel = (0 != (rel->r_type[0] + & RELOC_STD_BITS_BASEREL_LITTLE)); + r_jmptable= (0 != (rel->r_type[0] + & RELOC_STD_BITS_JMPTABLE_LITTLE)); + r_relative= (0 != (rel->r_type[0] + & RELOC_STD_BITS_RELATIVE_LITTLE)); + r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE); + } + + howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel + + 16 * r_jmptable + 32 * r_relative); + BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); + howto = howto_table_std + howto_idx; + } +#endif + + if (relocateable) + { + /* We are generating a relocateable output file, and must + modify the reloc accordingly. */ + if (r_extern) + { + /* If we know the symbol this relocation is against, + convert it into a relocation against a section. This + is what the native linker does. */ + h = sym_hashes[r_index]; + if (h != (struct aout_link_hash_entry *) NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + asection *output_section; + + /* Change the r_extern value. */ + if (bfd_header_big_endian (output_bfd)) + rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG; + else + rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE; + + /* Compute a new r_index. */ + output_section = h->root.u.def.section->output_section; + if (output_section == obj_textsec (output_bfd)) + r_index = N_TEXT; + else if (output_section == obj_datasec (output_bfd)) + r_index = N_DATA; + else if (output_section == obj_bsssec (output_bfd)) + r_index = N_BSS; + else + r_index = N_ABS; + + /* Add the symbol value and the section VMA to the + addend stored in the contents. */ + relocation = (h->root.u.def.value + + output_section->vma + + h->root.u.def.section->output_offset); + } + else + { + /* We must change r_index according to the symbol + map. */ + r_index = symbol_map[r_index]; + + if (r_index == -1) + { + if (h != NULL) + { + /* We decided to strip this symbol, but it + turns out that we can't. Note that we + lose the other and desc information here. + I don't think that will ever matter for a + global symbol. */ + if (h->indx < 0) + { + h->indx = -2; + h->written = false; + if (! aout_link_write_other_symbol (h, + (PTR) finfo)) + return false; + } + r_index = h->indx; + } + else + { + const char *name; + + name = strings + GET_WORD (input_bfd, + syms[r_index].e_strx); + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, name, input_bfd, input_section, + r_addr))) + return false; + r_index = 0; + } + } + + relocation = 0; + } + + /* Write out the new r_index value. */ + if (bfd_header_big_endian (output_bfd)) + { + rel->r_index[0] = r_index >> 16; + rel->r_index[1] = r_index >> 8; + rel->r_index[2] = r_index; + } + else + { + rel->r_index[2] = r_index >> 16; + rel->r_index[1] = r_index >> 8; + rel->r_index[0] = r_index; + } + } + else + { + asection *section; + + /* This is a relocation against a section. We must + adjust by the amount that the section moved. */ + section = aout_reloc_index_to_section (input_bfd, r_index); + relocation = (section->output_section->vma + + section->output_offset + - section->vma); + } + + /* Change the address of the relocation. */ + PUT_WORD (output_bfd, + r_addr + input_section->output_offset, + rel->r_address); + + /* Adjust a PC relative relocation by removing the reference + to the original address in the section and including the + reference to the new address. */ + if (r_pcrel) + relocation -= (input_section->output_section->vma + + input_section->output_offset + - input_section->vma); + +#ifdef MY_relocatable_reloc + MY_relocatable_reloc (howto, output_bfd, rel, relocation, r_addr); +#endif + + if (relocation == 0) + r = bfd_reloc_ok; + else + r = MY_relocate_contents (howto, + input_bfd, relocation, + contents + r_addr); + } + else + { + boolean hundef; + + /* We are generating an executable, and must do a full + relocation. */ + hundef = false; + if (r_extern) + { + h = sym_hashes[r_index]; + + if (h != (struct aout_link_hash_entry *) NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + relocation = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + else if (h != (struct aout_link_hash_entry *) NULL + && h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else + { + hundef = true; + relocation = 0; + } + } + else + { + asection *section; + + section = aout_reloc_index_to_section (input_bfd, r_index); + relocation = (section->output_section->vma + + section->output_offset + - section->vma); + if (r_pcrel) + relocation += input_section->vma; + } + + if (check_dynamic_reloc != NULL) + { + boolean skip; + + if (! ((*check_dynamic_reloc) + (finfo->info, input_bfd, input_section, h, + (PTR) rel, contents, &skip, &relocation))) + return false; + if (skip) + continue; + } + + /* Now warn if a global symbol is undefined. We could not + do this earlier, because check_dynamic_reloc might want + to skip this reloc. */ + if (hundef && ! finfo->info->shared && ! r_baserel) + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + name = strings + GET_WORD (input_bfd, syms[r_index].e_strx); + if (! ((*finfo->info->callbacks->undefined_symbol) + (finfo->info, name, input_bfd, input_section, r_addr))) + return false; + } + + r = MY_final_link_relocate (howto, + input_bfd, input_section, + contents, r_addr, relocation, + (bfd_vma) 0); + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (r_extern) + name = strings + GET_WORD (input_bfd, + syms[r_index].e_strx); + else + { + asection *s; + + s = aout_reloc_index_to_section (input_bfd, r_index); + name = bfd_section_name (input_bfd, s); + } + if (! ((*finfo->info->callbacks->reloc_overflow) + (finfo->info, name, howto->name, + (bfd_vma) 0, input_bfd, input_section, r_addr))) + return false; + } + break; + } + } + } + + return true; +} + +/* Relocate an a.out section using extended a.out relocs. */ + +static boolean +aout_link_input_section_ext (finfo, input_bfd, input_section, relocs, + rel_size, contents) + struct aout_final_link_info *finfo; + bfd *input_bfd; + asection *input_section; + struct reloc_ext_external *relocs; + bfd_size_type rel_size; + bfd_byte *contents; +{ + boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *, + bfd *, asection *, + struct aout_link_hash_entry *, + PTR, bfd_byte *, boolean *, + bfd_vma *)); + bfd *output_bfd; + boolean relocateable; + struct external_nlist *syms; + char *strings; + struct aout_link_hash_entry **sym_hashes; + int *symbol_map; + bfd_size_type reloc_count; + register struct reloc_ext_external *rel; + struct reloc_ext_external *rel_end; + + output_bfd = finfo->output_bfd; + check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc; + + BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE); + BFD_ASSERT (input_bfd->xvec->header_byteorder + == output_bfd->xvec->header_byteorder); + + relocateable = finfo->info->relocateable; + syms = obj_aout_external_syms (input_bfd); + strings = obj_aout_external_strings (input_bfd); + sym_hashes = obj_aout_sym_hashes (input_bfd); + symbol_map = finfo->symbol_map; + + reloc_count = rel_size / RELOC_EXT_SIZE; + rel = relocs; + rel_end = rel + reloc_count; + for (; rel < rel_end; rel++) + { + bfd_vma r_addr; + int r_index; + int r_extern; + unsigned int r_type; + bfd_vma r_addend; + struct aout_link_hash_entry *h = NULL; + asection *r_section = NULL; + bfd_vma relocation; + + r_addr = GET_SWORD (input_bfd, rel->r_address); + + if (bfd_header_big_endian (input_bfd)) + { + r_index = ((rel->r_index[0] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[2]); + r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG); + } + else + { + r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0]); + r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); + r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + r_addend = GET_SWORD (input_bfd, rel->r_addend); + + BFD_ASSERT (r_type < TABLE_SIZE (howto_table_ext)); + + if (relocateable) + { + /* We are generating a relocateable output file, and must + modify the reloc accordingly. */ + if (r_extern) + { + /* If we know the symbol this relocation is against, + convert it into a relocation against a section. This + is what the native linker does. */ + h = sym_hashes[r_index]; + if (h != (struct aout_link_hash_entry *) NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + asection *output_section; + + /* Change the r_extern value. */ + if (bfd_header_big_endian (output_bfd)) + rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG; + else + rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE; + + /* Compute a new r_index. */ + output_section = h->root.u.def.section->output_section; + if (output_section == obj_textsec (output_bfd)) + r_index = N_TEXT; + else if (output_section == obj_datasec (output_bfd)) + r_index = N_DATA; + else if (output_section == obj_bsssec (output_bfd)) + r_index = N_BSS; + else + r_index = N_ABS; + + /* Add the symbol value and the section VMA to the + addend. */ + relocation = (h->root.u.def.value + + output_section->vma + + h->root.u.def.section->output_offset); + + /* Now RELOCATION is the VMA of the final + destination. If this is a PC relative reloc, + then ADDEND is the negative of the source VMA. + We want to set ADDEND to the difference between + the destination VMA and the source VMA, which + means we must adjust RELOCATION by the change in + the source VMA. This is done below. */ + } + else + { + /* We must change r_index according to the symbol + map. */ + r_index = symbol_map[r_index]; + + if (r_index == -1) + { + if (h != NULL) + { + /* We decided to strip this symbol, but it + turns out that we can't. Note that we + lose the other and desc information here. + I don't think that will ever matter for a + global symbol. */ + if (h->indx < 0) + { + h->indx = -2; + h->written = false; + if (! aout_link_write_other_symbol (h, + (PTR) finfo)) + return false; + } + r_index = h->indx; + } + else + { + const char *name; + + name = strings + GET_WORD (input_bfd, + syms[r_index].e_strx); + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, name, input_bfd, input_section, + r_addr))) + return false; + r_index = 0; + } + } + + relocation = 0; + + /* If this is a PC relative reloc, then the addend + is the negative of the source VMA. We must + adjust it by the change in the source VMA. This + is done below. */ + } + + /* Write out the new r_index value. */ + if (bfd_header_big_endian (output_bfd)) + { + rel->r_index[0] = r_index >> 16; + rel->r_index[1] = r_index >> 8; + rel->r_index[2] = r_index; + } + else + { + rel->r_index[2] = r_index >> 16; + rel->r_index[1] = r_index >> 8; + rel->r_index[0] = r_index; + } + } + else + { + /* This is a relocation against a section. We must + adjust by the amount that the section moved. */ + r_section = aout_reloc_index_to_section (input_bfd, r_index); + relocation = (r_section->output_section->vma + + r_section->output_offset + - r_section->vma); + + /* If this is a PC relative reloc, then the addend is + the difference in VMA between the destination and the + source. We have just adjusted for the change in VMA + of the destination, so we must also adjust by the + change in VMA of the source. This is done below. */ + } + + /* As described above, we must always adjust a PC relative + reloc by the change in VMA of the source. */ + if (howto_table_ext[r_type].pc_relative) + relocation -= (input_section->output_section->vma + + input_section->output_offset + - input_section->vma); + + /* Change the addend if necessary. */ + if (relocation != 0) + PUT_WORD (output_bfd, r_addend + relocation, rel->r_addend); + + /* Change the address of the relocation. */ + PUT_WORD (output_bfd, + r_addr + input_section->output_offset, + rel->r_address); + } + else + { + boolean hundef; + bfd_reloc_status_type r; + + /* We are generating an executable, and must do a full + relocation. */ + hundef = false; + if (r_extern) + { + h = sym_hashes[r_index]; + + if (h != (struct aout_link_hash_entry *) NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + relocation = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + else if (h != (struct aout_link_hash_entry *) NULL + && h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else + { + hundef = true; + relocation = 0; + } + } + else if (r_type == RELOC_BASE10 + || r_type == RELOC_BASE13 + || r_type == RELOC_BASE22) + { + struct external_nlist *sym; + int type; + + /* For base relative relocs, r_index is always an index + into the symbol table, even if r_extern is 0. */ + sym = syms + r_index; + type = bfd_h_get_8 (input_bfd, sym->e_type); + if ((type & N_TYPE) == N_TEXT + || type == N_WEAKT) + r_section = obj_textsec (input_bfd); + else if ((type & N_TYPE) == N_DATA + || type == N_WEAKD) + r_section = obj_datasec (input_bfd); + else if ((type & N_TYPE) == N_BSS + || type == N_WEAKB) + r_section = obj_bsssec (input_bfd); + else if ((type & N_TYPE) == N_ABS + || type == N_WEAKA) + r_section = bfd_abs_section_ptr; + else + abort (); + relocation = (r_section->output_section->vma + + r_section->output_offset + + (GET_WORD (input_bfd, sym->e_value) + - r_section->vma)); + } + else + { + r_section = aout_reloc_index_to_section (input_bfd, r_index); + + /* If this is a PC relative reloc, then R_ADDEND is the + difference between the two vmas, or + old_dest_sec + old_dest_off - (old_src_sec + old_src_off) + where + old_dest_sec == section->vma + and + old_src_sec == input_section->vma + and + old_src_off == r_addr + + _bfd_final_link_relocate expects RELOCATION + + R_ADDEND to be the VMA of the destination minus + r_addr (the minus r_addr is because this relocation + is not pcrel_offset, which is a bit confusing and + should, perhaps, be changed), or + new_dest_sec + where + new_dest_sec == output_section->vma + output_offset + We arrange for this to happen by setting RELOCATION to + new_dest_sec + old_src_sec - old_dest_sec + + If this is not a PC relative reloc, then R_ADDEND is + simply the VMA of the destination, so we set + RELOCATION to the change in the destination VMA, or + new_dest_sec - old_dest_sec + */ + relocation = (r_section->output_section->vma + + r_section->output_offset + - r_section->vma); + if (howto_table_ext[r_type].pc_relative) + relocation += input_section->vma; + } + + if (check_dynamic_reloc != NULL) + { + boolean skip; + + if (! ((*check_dynamic_reloc) + (finfo->info, input_bfd, input_section, h, + (PTR) rel, contents, &skip, &relocation))) + return false; + if (skip) + continue; + } + + /* Now warn if a global symbol is undefined. We could not + do this earlier, because check_dynamic_reloc might want + to skip this reloc. */ + if (hundef + && ! finfo->info->shared + && r_type != RELOC_BASE10 + && r_type != RELOC_BASE13 + && r_type != RELOC_BASE22) + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + name = strings + GET_WORD (input_bfd, syms[r_index].e_strx); + if (! ((*finfo->info->callbacks->undefined_symbol) + (finfo->info, name, input_bfd, input_section, r_addr))) + return false; + } + + r = MY_final_link_relocate (howto_table_ext + r_type, + input_bfd, input_section, + contents, r_addr, relocation, + r_addend); + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (r_extern + || r_type == RELOC_BASE10 + || r_type == RELOC_BASE13 + || r_type == RELOC_BASE22) + name = strings + GET_WORD (input_bfd, + syms[r_index].e_strx); + else + { + asection *s; + + s = aout_reloc_index_to_section (input_bfd, r_index); + name = bfd_section_name (input_bfd, s); + } + if (! ((*finfo->info->callbacks->reloc_overflow) + (finfo->info, name, howto_table_ext[r_type].name, + r_addend, input_bfd, input_section, r_addr))) + return false; + } + break; + } + } + } + } + + return true; +} + +/* Handle a link order which is supposed to generate a reloc. */ + +static boolean +aout_link_reloc_link_order (finfo, o, p) + struct aout_final_link_info *finfo; + asection *o; + struct bfd_link_order *p; +{ + struct bfd_link_order_reloc *pr; + int r_index; + int r_extern; + reloc_howto_type *howto; + file_ptr *reloff_ptr; + struct reloc_std_external srel; + struct reloc_ext_external erel; + PTR rel_ptr; + + pr = p->u.reloc.p; + + if (p->type == bfd_section_reloc_link_order) + { + r_extern = 0; + if (bfd_is_abs_section (pr->u.section)) + r_index = N_ABS | N_EXT; + else + { + BFD_ASSERT (pr->u.section->owner == finfo->output_bfd); + r_index = pr->u.section->target_index; + } + } + else + { + struct aout_link_hash_entry *h; + + BFD_ASSERT (p->type == bfd_symbol_reloc_link_order); + r_extern = 1; + h = ((struct aout_link_hash_entry *) + bfd_wrapped_link_hash_lookup (finfo->output_bfd, finfo->info, + pr->u.name, false, false, true)); + if (h != (struct aout_link_hash_entry *) NULL + && h->indx >= 0) + r_index = h->indx; + else if (h != NULL) + { + /* We decided to strip this symbol, but it turns out that we + can't. Note that we lose the other and desc information + here. I don't think that will ever matter for a global + symbol. */ + h->indx = -2; + h->written = false; + if (! aout_link_write_other_symbol (h, (PTR) finfo)) + return false; + r_index = h->indx; + } + else + { + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, pr->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + r_index = 0; + } + } + + howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc); + if (howto == 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (o == obj_textsec (finfo->output_bfd)) + reloff_ptr = &finfo->treloff; + else if (o == obj_datasec (finfo->output_bfd)) + reloff_ptr = &finfo->dreloff; + else + abort (); + + if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE) + { +#ifdef MY_put_reloc + MY_put_reloc(finfo->output_bfd, r_extern, r_index, p->offset, howto, + &srel); +#else + { + int r_pcrel; + int r_baserel; + int r_jmptable; + int r_relative; + int r_length; + + r_pcrel = howto->pc_relative; + r_baserel = (howto->type & 8) != 0; + r_jmptable = (howto->type & 16) != 0; + r_relative = (howto->type & 32) != 0; + r_length = howto->size; + + PUT_WORD (finfo->output_bfd, p->offset, srel.r_address); + if (bfd_header_big_endian (finfo->output_bfd)) + { + srel.r_index[0] = r_index >> 16; + srel.r_index[1] = r_index >> 8; + srel.r_index[2] = r_index; + srel.r_type[0] = + ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) + | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0) + | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0) + | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); + } + else + { + srel.r_index[2] = r_index >> 16; + srel.r_index[1] = r_index >> 8; + srel.r_index[0] = r_index; + srel.r_type[0] = + ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) + | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0) + | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0) + | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); + } + } +#endif + rel_ptr = (PTR) &srel; + + /* We have to write the addend into the object file, since + standard a.out relocs are in place. It would be more + reliable if we had the current contents of the file here, + rather than assuming zeroes, but we can't read the file since + it was opened using bfd_openw. */ + if (pr->addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type r; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return false; + r = MY_relocate_contents (howto, finfo->output_bfd, + pr->addend, buf); + switch (r) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*finfo->info->callbacks->reloc_overflow) + (finfo->info, + (p->type == bfd_section_reloc_link_order + ? bfd_section_name (finfo->output_bfd, + pr->u.section) + : pr->u.name), + howto->name, pr->addend, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (finfo->output_bfd, o, + (PTR) buf, + (file_ptr) p->offset, + size); + free (buf); + if (! ok) + return false; + } + } + else + { + PUT_WORD (finfo->output_bfd, p->offset, erel.r_address); + + if (bfd_header_big_endian (finfo->output_bfd)) + { + erel.r_index[0] = r_index >> 16; + erel.r_index[1] = r_index >> 8; + erel.r_index[2] = r_index; + erel.r_type[0] = + ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0) + | (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG)); + } + else + { + erel.r_index[2] = r_index >> 16; + erel.r_index[1] = r_index >> 8; + erel.r_index[0] = r_index; + erel.r_type[0] = + (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0) + | (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + PUT_WORD (finfo->output_bfd, pr->addend, erel.r_addend); + + rel_ptr = (PTR) &erel; + } + + if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0 + || (bfd_write (rel_ptr, (bfd_size_type) 1, + obj_reloc_entry_size (finfo->output_bfd), + finfo->output_bfd) + != obj_reloc_entry_size (finfo->output_bfd))) + return false; + + *reloff_ptr += obj_reloc_entry_size (finfo->output_bfd); + + /* Assert that the relocs have not run into the symbols, and that n + the text relocs have not run into the data relocs. */ + BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd) + && (reloff_ptr != &finfo->treloff + || (*reloff_ptr + <= obj_datasec (finfo->output_bfd)->rel_filepos))); + + return true; +} diff --git a/contrib/gdb/bfd/archive.c b/contrib/gdb/bfd/archive.c new file mode 100644 index 000000000000..248b9181e75e --- /dev/null +++ b/contrib/gdb/bfd/archive.c @@ -0,0 +1,2094 @@ +/* BFD back-end for archive files (libraries). + Copyright 1990, 91, 92, 93, 94, 95, 1996 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. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +@setfilename archive-info +SECTION + Archives + +DESCRIPTION + An archive (or library) is just another BFD. It has a symbol + table, although there's not much a user program will do with it. + + The big difference between an archive BFD and an ordinary BFD + is that the archive doesn't have sections. Instead it has a + chain of BFDs that are considered its contents. These BFDs can + be manipulated like any other. The BFDs contained in an + archive opened for reading will all be opened for reading. You + may put either input or output BFDs into an archive opened for + output; they will be handled correctly when the archive is closed. + + Use <> to step through + the contents of an archive opened for input. You don't + have to read the entire archive if you don't want + to! Read it until you find what you want. + + 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. + + As expected, the BFD archive code is more general than the + archive code of any given environment. BFD archives may + contain files of different formats (e.g., a.out and coff) and + even different architectures. You may even place archives + recursively into archives! + + This can cause unexpected confusion, since some archive + formats are more expressive than others. For instance, Intel + COFF archives can preserve long filenames; SunOS a.out archives + cannot. If you move a file from the first to the second + format and back again, the filename may be truncated. + Likewise, different a.out environments have different + conventions as to how they truncate filenames, whether they + preserve directory names in filenames, etc. When + interoperating with native tools, be sure your files are + homogeneous. + + Beware: most of these formats do not react well to the + presence of spaces in filenames. We do the best we can, but + can't always handle this case due to restrictions in the format of + archives. Many Unix utilities are braindead in regards to + spaces and such in filenames anyway, so this shouldn't be much + of a restriction. + + Archives are supported in BFD in <>. + +*/ + +/* Assumes: + o - all archive elements start on an even boundary, newline padded; + o - all arch headers are char *; + o - all arch headers are the same size (across architectures). +*/ + +/* Some formats provide a way to cram a long filename into the short + (16 chars) space provided by a BSD archive. The trick is: make a + special "file" in the front of the archive, sort of like the SYMDEF + entry. If the filename is too long to fit, put it in the extended + name table, and use its index as the filename. To prevent + confusion prepend the index with a space. This means you can't + have filenames that start with a space, but then again, many Unix + utilities can't handle that anyway. + + This scheme unfortunately requires that you stand on your head in + order to write an archive since you need to put a magic file at the + front, and need to touch every entry to do so. C'est la vie. + + We support two variants of this idea: + The SVR4 format (extended name table is named "//"), + and an extended pseudo-BSD variant (extended name table is named + "ARFILENAMES/"). The origin of the latter format is uncertain. + + BSD 4.4 uses a third scheme: It writes a long filename + directly after the header. This allows 'ar q' to work. + We currently can read BSD 4.4 archives, but not write them. +*/ + +/* Summary of archive member names: + + Symbol table (must be first): + "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib. + "/ " - Symbol table, system 5 style. + + Long name table (must be before regular file members): + "// " - Long name table, System 5 R4 style. + "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4). + + Regular file members with short names: + "filename.o/ " - Regular file, System 5 style (embedded spaces ok). + "filename.o " - Regular file, Berkeley style (no embedded spaces). + + Regular files with long names (or embedded spaces, for BSD variants): + "/18 " - SVR4 style, name at offset 18 in name table. + "#1/23 " - Long name (or embedded paces) 23 characters long, + BSD 4.4 style, full name follows header. + Implemented for reading, not writing. + " 18 " - Long name 18 characters long, extended pseudo-BSD. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include +#include /* For memchr, strrchr and friends */ +#include + +#ifndef errno +extern int errno; +#endif + +#ifdef GNU960 +#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB) +#endif + +/* Can't define this in hosts/foo.h, because (e.g. in gprof) the hosts file + is included, then obstack.h, which thinks if offsetof is defined, it + doesn't need to include stddef.h. */ +/* Define offsetof for those systems which lack it */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* We keep a cache of archive filepointers to archive elements to + speed up searching the archive by filepos. We only add an entry to + the cache when we actually read one. We also don't sort the cache; + 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 +{ + file_ptr ptr; + bfd *arelt; + struct ar_cache *next; +}; + +#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) +#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) + +#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data)) +#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header) + +static char *get_extended_arelt_filename PARAMS ((bfd *arch, + const char *name)); +static boolean do_slurp_bsd_armap PARAMS ((bfd *abfd)); +static boolean do_slurp_coff_armap PARAMS ((bfd *abfd)); +static const char *normalize PARAMS ((bfd *, const char *file)); +static struct areltdata *bfd_ar_hdr_from_filesystem PARAMS ((bfd *abfd, + const char *)); + +boolean +_bfd_generic_mkarchive (abfd) + bfd *abfd; +{ + abfd->tdata.aout_ar_data = ((struct artdata *) + bfd_zalloc (abfd, sizeof (struct artdata))); + + if (bfd_ardata (abfd) == NULL) + return false; + + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + return true; +} + +/* +FUNCTION + bfd_get_next_mapent + +SYNOPSIS + symindex bfd_get_next_mapent(bfd *abfd, symindex previous, carsym **sym); + +DESCRIPTION + Step through archive @var{abfd}'s symbol table (if it + has one). Successively update @var{sym} with the next symbol's + information, returning that symbol's (internal) index into the + symbol table. + + Supply <> as the @var{previous} entry to get + the first one; returns <> when you've already + got the last one. + + A <> is a canonical archive symbol. The only + user-visible element is its name, a null-terminated string. +*/ + +symindex +bfd_get_next_mapent (abfd, prev, entry) + bfd *abfd; + symindex prev; + carsym **entry; +{ + if (!bfd_has_map (abfd)) + { + bfd_set_error (bfd_error_invalid_operation); + return BFD_NO_MORE_SYMBOLS; + } + + if (prev == BFD_NO_MORE_SYMBOLS) + prev = 0; + else + ++prev; + if (prev >= bfd_ardata (abfd)->symdef_count) + return BFD_NO_MORE_SYMBOLS; + + *entry = (bfd_ardata (abfd)->symdefs + prev); + return prev; +} + +/* To be called by backends only */ + +bfd * +_bfd_create_empty_archive_element_shell (obfd) + bfd *obfd; +{ + return _bfd_new_bfd_contained_in (obfd); +} + +/* +FUNCTION + bfd_set_archive_head + +SYNOPSIS + boolean bfd_set_archive_head(bfd *output, bfd *new_head); + +DESCRIPTION + Set the head of the chain of + BFDs contained in the archive @var{output} to @var{new_head}. +*/ + +boolean +bfd_set_archive_head (output_archive, new_head) + bfd *output_archive; + bfd *new_head; +{ + + output_archive->archive_head = new_head; + return true; +} + +bfd * +_bfd_look_for_bfd_in_cache (arch_bfd, filepos) + bfd *arch_bfd; + file_ptr filepos; +{ + struct ar_cache *current; + + for (current = bfd_ardata (arch_bfd)->cache; current != NULL; + current = current->next) + if (current->ptr == filepos) + return current->arelt; + + return NULL; +} + +/* Kind of stupid to call cons for each one, but we don't do too many */ +boolean +_bfd_add_bfd_to_archive_cache (arch_bfd, filepos, new_elt) + bfd *arch_bfd, *new_elt; + file_ptr filepos; +{ + struct ar_cache *new_cache = ((struct ar_cache *) + bfd_zalloc (arch_bfd, + sizeof (struct ar_cache))); + + if (new_cache == NULL) + return false; + + new_cache->ptr = filepos; + new_cache->arelt = new_elt; + new_cache->next = (struct ar_cache *) NULL; + if (bfd_ardata (arch_bfd)->cache == NULL) + bfd_ardata (arch_bfd)->cache = new_cache; + else + { + struct ar_cache *current = bfd_ardata (arch_bfd)->cache; + + while (current->next != NULL) + current = current->next; + current->next = new_cache; + } + + return true; +} + +/* The name begins with space. Hence the rest of the name is an index into + the string table. */ + +static char * +get_extended_arelt_filename (arch, name) + bfd *arch; + const char *name; +{ + unsigned long index = 0; + + /* Should extract string so that I can guarantee not to overflow into + the next region, but I'm too lazy. */ + errno = 0; + /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ + index = strtol (name + 1, NULL, 10); + if (errno != 0) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + return bfd_ardata (arch)->extended_names + index; +} + +/* This functions reads an arch header and returns an areltdata pointer, or + NULL on error. + + Presumes the file pointer is already in the right place (ie pointing + to the ar_hdr in the file). Moves the file pointer; on success it + should be pointing to the front of the file contents; on failure it + could have been moved arbitrarily. +*/ + +PTR +_bfd_generic_read_ar_hdr (abfd) + bfd *abfd; +{ + return _bfd_generic_read_ar_hdr_mag (abfd, (const char *) NULL); +} + +/* Alpha ECOFF uses an optional different ARFMAG value, so we have a + variant of _bfd_generic_read_ar_hdr which accepts a magic string. */ + +PTR +_bfd_generic_read_ar_hdr_mag (abfd, mag) + bfd *abfd; + const char *mag; +{ + struct ar_hdr hdr; + char *hdrp = (char *) &hdr; + unsigned int parsed_size; + struct areltdata *ared; + char *filename = NULL; + unsigned int namelen = 0; + unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); + char *allocptr = 0; + + if (bfd_read ((PTR) hdrp, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + if (strncmp (hdr.ar_fmag, ARFMAG, 2) != 0 + && (mag == NULL + || strncmp (hdr.ar_fmag, mag, 2) != 0)) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + errno = 0; + parsed_size = strtol (hdr.ar_size, NULL, 10); + if (errno != 0) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + /* Extract the filename from the archive - there are two ways to + specify an extendend name table, either the first char of the + name is a space, or it's a slash. */ + if ((hdr.ar_name[0] == '/' + || (hdr.ar_name[0] == ' ' + && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL)) + && bfd_ardata (abfd)->extended_names != NULL) + { + filename = get_extended_arelt_filename (abfd, hdr.ar_name); + if (filename == NULL) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + } + /* BSD4.4-style long filename. + Only implemented for reading, so far! */ + else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1' + && hdr.ar_name[2] == '/' && isdigit (hdr.ar_name[3])) + { + /* BSD-4.4 extended name */ + namelen = atoi (&hdr.ar_name[3]); + allocsize += namelen + 1; + parsed_size -= namelen; + + allocptr = bfd_zalloc (abfd, allocsize); + if (allocptr == NULL) + return NULL; + filename = (allocptr + + sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (bfd_read (filename, 1, namelen, abfd) != namelen) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + filename[namelen] = '\0'; + } + else + { + /* We judge the end of the name by looking for '/' or ' '. + Note: The SYSV format (terminated by '/') allows embedded + spaces, so only look for ' ' if we don't find '/'. */ + + namelen = 0; + while (hdr.ar_name[namelen] != '\0' && + hdr.ar_name[namelen] != '/') + { + namelen++; + if (namelen == (unsigned) ar_maxnamelen (abfd)) + { + namelen = 0; + while (hdr.ar_name[namelen] != ' ' + && namelen < (unsigned) ar_maxnamelen (abfd)) + namelen++; + break; + } + } + + allocsize += namelen + 1; + } + + if (!allocptr) + { + allocptr = bfd_zalloc (abfd, allocsize); + if (allocptr == NULL) + return NULL; + } + + ared = (struct areltdata *) allocptr; + + ared->arch_header = allocptr + sizeof (struct areltdata); + memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr)); + ared->parsed_size = parsed_size; + + if (filename != NULL) + ared->filename = filename; + else + { + ared->filename = allocptr + (sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (namelen) + memcpy (ared->filename, hdr.ar_name, namelen); + ared->filename[namelen] = '\0'; + } + + return (PTR) ared; +} + +/* This is an internal function; it's mainly used when indexing + through the archive symbol table, but also used to get the next + element, since it handles the bookkeeping so nicely for us. */ + +bfd * +_bfd_get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); + if (n_nfd) + return n_nfd; + + if (0 > bfd_seek (archive, filepos, SEEK_SET)) + return NULL; + + if ((new_areldata = (struct areltdata *) _bfd_read_ar_hdr (archive)) == NULL) + return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) + { + bfd_release (archive, (PTR) new_areldata); + return NULL; + } + + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = (PTR) new_areldata; + n_nfd->filename = new_areldata->filename; + + if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) + return n_nfd; + + /* huh? */ + bfd_release (archive, (PTR) n_nfd); + bfd_release (archive, (PTR) new_areldata); + return NULL; +} + +/* Return the BFD which is referenced by the symbol in ABFD indexed by + INDEX. INDEX should have been returned by bfd_get_next_mapent. */ + +bfd * +_bfd_generic_get_elt_at_index (abfd, index) + bfd *abfd; + symindex index; +{ + carsym *entry; + + entry = bfd_ardata (abfd)->symdefs + index; + return _bfd_get_elt_at_filepos (abfd, entry->file_offset); +} + +/* +FUNCTION + bfd_openr_next_archived_file + +SYNOPSIS + bfd *bfd_openr_next_archived_file(bfd *archive, bfd *previous); + +DESCRIPTION + Provided a BFD, @var{archive}, containing an archive and NULL, open + an input BFD on the first contained element and returns that. + Subsequent calls should pass + the archive and the previous return value to return a created + BFD to the next contained element. NULL is returned when there + are no more. + +*/ + +bfd * +bfd_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + if ((bfd_get_format (archive) != bfd_archive) || + (archive->direction == write_direction)) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + return BFD_SEND (archive, + openr_next_archived_file, + (archive, + last_file)); +} + +bfd * +bfd_generic_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (!last_file) + filestart = bfd_ardata (archive)->first_file_filepos; + else + { + unsigned int size = arelt_size (last_file); + /* 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. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return _bfd_get_elt_at_filepos (archive, filestart); +} + + +const bfd_target * +bfd_generic_archive_p (abfd) + bfd *abfd; +{ + struct artdata *tdata_hold; + char armag[SARMAG + 1]; + + tdata_hold = abfd->tdata.aout_ar_data; + + if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + +#ifdef GNU960 + if (strncmp (armag, BFD_GNU960_ARMAG (abfd), SARMAG) != 0) + return 0; +#else + if (strncmp (armag, ARMAG, SARMAG) != 0 && + strncmp (armag, ARMAGB, SARMAG) != 0) + return 0; +#endif + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of assignment. */ + abfd->tdata.aout_ar_data = ((struct artdata *) + bfd_zalloc (abfd, sizeof (struct artdata))); + + if (bfd_ardata (abfd) == NULL) + return NULL; + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = tdata_hold; + return NULL; + } + + if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = tdata_hold; + return NULL; + } + + if (bfd_has_map (abfd)) + { + bfd *first; + + /* This archive has a map, so we may presume that the contents + are object files. Make sure that if the first file in the + archive can be recognized as an object file, it is for this + target. If not, assume that this is the wrong format. If + the first file is not an object file, somebody is doing + something weird, and we permit it so that ar -t will work. + + This is done because any normal format will recognize any + normal archive, regardless of the format of the object files. + We do accept an empty archive. */ + + first = bfd_openr_next_archived_file (abfd, (bfd *) NULL); + if (first != NULL) + { + boolean fail; + + first->target_defaulted = false; + fail = false; + if (bfd_check_format (first, bfd_object) + && first->xvec != abfd->xvec) + { + (void) bfd_close (first); + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = tdata_hold; + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* We ought to close first here, but we can't, because we + have no way to remove it from the archive cache. FIXME. */ + } + } + + return abfd->xvec; +} + +/* Some constants for a 32 bit BSD archive structure. We do not + support 64 bit archives presently; so far as I know, none actually + exist. Supporting them would require changing these constants, and + changing some bfd_h_get_32 to bfd_h_get_64. */ + +/* The size of an external symdef structure. */ +#define BSD_SYMDEF_SIZE 8 + +/* The offset from the start of a symdef structure to the file offset. */ +#define BSD_SYMDEF_OFFSET_SIZE 4 + +/* The size of the symdef count. */ +#define BSD_SYMDEF_COUNT_SIZE 4 + +/* The size of the string count. */ +#define BSD_STRING_COUNT_SIZE 4 + +/* Returns false on error, true otherwise */ + +static boolean +do_slurp_bsd_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + unsigned int counter; + bfd_byte *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int parsed_size; + carsym *set; + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */ + + raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); + if (raw_armap == (bfd_byte *) NULL) + return false; + + if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + byebye: + bfd_release (abfd, (PTR) raw_armap); + return false; + } + + ardata->symdef_count = bfd_h_get_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE; + + if (ardata->symdef_count * BSD_SYMDEF_SIZE > + parsed_size - BSD_SYMDEF_COUNT_SIZE) + { + /* Probably we're using the wrong byte ordering. */ + bfd_set_error (bfd_error_wrong_format); + goto byebye; + } + + ardata->cache = 0; + rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE; + stringbase = ((char *) rbase + + ardata->symdef_count * BSD_SYMDEF_SIZE + + BSD_STRING_COUNT_SIZE); + ardata->symdefs = (carsym *) bfd_alloc (abfd, + (ardata->symdef_count + * sizeof (carsym))); + if (!ardata->symdefs) + return false; + + for (counter = 0, set = ardata->symdefs; + counter < ardata->symdef_count; + counter++, set++, rbase += BSD_SYMDEF_SIZE) + { + set->name = bfd_h_get_32 (abfd, rbase) + stringbase; + set->file_offset = bfd_h_get_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/* Returns false on error, true otherwise */ +static boolean +do_slurp_coff_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + int *raw_armap, *rawptr; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + unsigned int parsed_size; + carsym *carsyms; + unsigned int nsymz; /* Number of symbols in armap. */ + bfd_vma (*swap) PARAMS ((const bfd_byte *)); + char int_buf[sizeof (long)]; + unsigned int carsym_size, ptrsize, i; + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */ + + if (bfd_read ((PTR) int_buf, 1, 4, abfd) != 4) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return false; + } + /* It seems that all numeric information in a coff archive is always + in big endian format, nomatter the host or target. */ + swap = bfd_getb32; + nsymz = bfd_getb32 ((PTR) int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + +#if 1 + /* ... except that some archive formats are broken, and it may be our + fault - the i960 little endian coff sometimes has big and sometimes + little, because our tools changed. Here's a horrible hack to clean + up the crap. */ + + if (stringsize > 0xfffff) + { + /* This looks dangerous, let's do it the other way around */ + nsymz = bfd_getl32 ((PTR) int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + swap = bfd_getl32; + } +#endif + + /* The coff armap must be read sequentially. So we construct a + bsd-style one in core all at once, for simplicity. */ + + carsym_size = (nsymz * sizeof (carsym)); + ptrsize = (4 * nsymz); + + ardata->symdefs = (carsym *) bfd_zalloc (abfd, carsym_size + stringsize + 1); + if (ardata->symdefs == NULL) + return false; + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + /* Allocate and read in the raw offsets. */ + raw_armap = (int *) bfd_alloc (abfd, ptrsize); + if (raw_armap == NULL) + goto release_symdefs; + if (bfd_read ((PTR) raw_armap, 1, ptrsize, abfd) != ptrsize + || bfd_read ((PTR) stringbase, 1, stringsize, abfd) != stringsize) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + goto release_raw_armap; + } + + /* OK, build the carsyms */ + for (i = 0; i < nsymz; i++) + { + rawptr = raw_armap + i; + carsyms->file_offset = swap ((PTR) rawptr); + carsyms->name = stringbase; + stringbase += strlen (stringbase) + 1; + carsyms++; + } + *stringbase = 0; + + ardata->symdef_count = nsymz; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + + + bfd_has_map (abfd) = true; + bfd_release (abfd, (PTR) raw_armap); + + + /* Check for a second archive header (as used by PE) */ + { + struct areltdata *tmp; + + bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET); + tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (tmp != NULL) + { + if (tmp->arch_header[0] == '/' + && tmp->arch_header[1] == ' ') + { + ardata->first_file_filepos += + (tmp->parsed_size + sizeof(struct ar_hdr) + 1) & ~1; + } + bfd_release (abfd, tmp); + } + } + + return true; + +release_raw_armap: + bfd_release (abfd, (PTR) raw_armap); +release_symdefs: + bfd_release (abfd, (PTR) (ardata)->symdefs); + return false; +} + +/* This routine can handle either coff-style or bsd-style armaps. + Returns false on error, true otherwise */ + +boolean +bfd_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + int i = bfd_read ((PTR) nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0) + return false; + + if (!strncmp (nextname, "__.SYMDEF ", 16) + || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */ + return do_slurp_bsd_armap (abfd); + else if (!strncmp (nextname, "/ ", 16)) + return do_slurp_coff_armap (abfd); + + bfd_has_map (abfd) = false; + return true; +} + +/* Returns false on error, true otherwise */ +/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the + header is in a slightly different order and the map name is '/'. + This flavour is used by hp300hpux. */ + +#define HPUX_SYMDEF_COUNT_SIZE 2 + +boolean +bfd_slurp_bsd_armap_f2 (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname[17]; + unsigned int counter; + bfd_byte *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + carsym *set; + int i = bfd_read ((PTR) nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + /* The archive has at least 16 bytes in it */ + if (bfd_seek (abfd, -16L, SEEK_CUR) != 0) + return false; + + if (!strncmp (nextname, "__.SYMDEF ", 16) + || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */ + return do_slurp_bsd_armap (abfd); + + if (strncmp (nextname, "/ ", 16)) + { + bfd_has_map (abfd) = false; + return true; + } + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return false; + + raw_armap = (bfd_byte *) bfd_zalloc (abfd, mapdata->parsed_size); + if (raw_armap == NULL) + { + byebye: + bfd_release (abfd, (PTR) mapdata); + return false; + } + + if (bfd_read ((PTR) raw_armap, 1, mapdata->parsed_size, abfd) != + mapdata->parsed_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + byebyebye: + bfd_release (abfd, (PTR) raw_armap); + goto byebye; + } + + ardata->symdef_count = bfd_h_get_16 (abfd, (PTR) raw_armap); + + if (ardata->symdef_count * BSD_SYMDEF_SIZE + > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE) + { + /* Probably we're using the wrong byte ordering. */ + bfd_set_error (bfd_error_wrong_format); + goto byebyebye; + } + + ardata->cache = 0; + + stringsize = bfd_h_get_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE); + /* skip sym count and string sz */ + stringbase = ((char *) raw_armap + + HPUX_SYMDEF_COUNT_SIZE + + BSD_STRING_COUNT_SIZE); + rbase = (bfd_byte *) stringbase + stringsize; + ardata->symdefs = (carsym *) bfd_alloc (abfd, + (ardata->symdef_count + * BSD_SYMDEF_SIZE)); + if (!ardata->symdefs) + return false; + + for (counter = 0, set = ardata->symdefs; + counter < ardata->symdef_count; + counter++, set++, rbase += BSD_SYMDEF_SIZE) + { + set->name = bfd_h_get_32 (abfd, rbase) + stringbase; + set->file_offset = bfd_h_get_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/** Extended name table. + + Normally archives support only 14-character filenames. + + Intel has extended the format: longer names are stored in a special + element (the first in the archive, or second if there is an armap); + the name in the ar_hdr is replaced by . Index is the P.R. of an int (decimal). Data General have + extended the format by using the prefix // for the special element */ + +/* Returns false on error, true otherwise */ +boolean +_bfd_slurp_extended_name_table (abfd) + bfd *abfd; +{ + char nextname[17]; + struct areltdata *namedata; + + /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, + we probably don't want to return true. */ + bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET); + if (bfd_read ((PTR) nextname, 1, 16, abfd) == 16) + { + if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0) + return false; + + if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 && + strncmp (nextname, "// ", 16) != 0) + { + bfd_ardata (abfd)->extended_names = NULL; + return true; + } + + namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (namedata == NULL) + return false; + + bfd_ardata (abfd)->extended_names = + bfd_zalloc (abfd, namedata->parsed_size); + if (bfd_ardata (abfd)->extended_names == NULL) + { + byebye: + bfd_release (abfd, (PTR) namedata); + return false; + } + + if (bfd_read ((PTR) bfd_ardata (abfd)->extended_names, 1, + namedata->parsed_size, abfd) != namedata->parsed_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + bfd_release (abfd, (PTR) (bfd_ardata (abfd)->extended_names)); + bfd_ardata (abfd)->extended_names = NULL; + goto byebye; + } + + /* Since the archive is supposed to be printable if it contains + text, the entries in the list are newline-padded, not null + padded. In SVR4-style archives, the names also have a + trailing '/'. DOS/NT created archive often have \ in them + We'll fix all problems here.. */ + { + char *temp = bfd_ardata (abfd)->extended_names; + char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) { + if (*temp == '\012') + temp[temp[-1] == '/' ? -1 : 0] = '\0'; + if (*temp == '\\') + *temp = '/'; + } + } + + /* Pad to an even boundary if you have to */ + bfd_ardata (abfd)->first_file_filepos = bfd_tell (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 obstack... */ + /* bfd_release (abfd, namedata); */ + } + return true; +} + +#ifdef VMS + +/* Return a copy of the stuff in the filename between any :]> and a + semicolon */ +static const char * +normalize (abfd, file) + bfd *abfd; + const char *file; +{ + CONST char *first; + CONST char *last; + char *copy; + + first = file + strlen (file) - 1; + last = first + 1; + + while (first != file) + { + if (*first == ';') + last = first; + if (*first == ':' || *first == ']' || *first == '>') + { + first++; + break; + } + first--; + } + + copy = (char *) bfd_alloc (abfd, last - first + 1); + if (copy == NULL) + return NULL; + + memcpy (copy, first, last - first); + copy[last - first] = 0; + + return copy; +} + +#else +static const char * +normalize (abfd, file) + bfd *abfd; + const char *file; +{ + const char *filename = strrchr (file, '/'); + + if (filename != (char *) NULL) + filename++; + else + filename = file; + return filename; +} +#endif + +/* Build a BFD style extended name table. */ + +boolean +_bfd_archive_bsd_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ + *name = "ARFILENAMES/"; + return _bfd_construct_extended_name_table (abfd, false, tabloc, tablen); +} + +/* Build an SVR4 style extended name table. */ + +boolean +_bfd_archive_coff_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ + *name = "//"; + return _bfd_construct_extended_name_table (abfd, true, tabloc, tablen); +} + +/* Follows archive_head and produces an extended name table if + necessary. Returns (in tabloc) a pointer to an extended name + table, and in tablen the length of the table. If it makes an entry + it clobbers the filename so that the element may be written without + further massage. Returns true if it ran successfully, false if + something went wrong. A successful return may still involve a + zero-length tablen! */ + +boolean +_bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen) + bfd *abfd; + boolean trailing_slash; + char **tabloc; + bfd_size_type *tablen; +{ + unsigned int maxname = abfd->xvec->ar_max_namelen; + unsigned int total_namelen = 0; + bfd *current; + char *strptr; + + *tablen = 0; + + /* Figure out how long the table should be */ + for (current = abfd->archive_head; current != NULL; current = current->next) + { + const char *normal; + unsigned int thislen; + + normal = normalize (current, current->filename); + if (normal == NULL) + return false; + + thislen = strlen (normal); + + if (thislen > maxname + && (bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) + thislen = maxname; + + if (thislen > maxname) + { + /* Add one to leave room for \n. */ + total_namelen += thislen + 1; + if (trailing_slash) + { + /* Leave room for trailing slash. */ + ++total_namelen; + } + } + else + { + struct ar_hdr *hdr = arch_hdr (current); + if (strncmp (normal, hdr->ar_name, thislen) != 0 + || (thislen < sizeof hdr->ar_name + && 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. */ + memcpy (hdr->ar_name, normal, thislen); + if (thislen < maxname + || (thislen == maxname && thislen < sizeof hdr->ar_name)) + hdr->ar_name[thislen] = ar_padchar (current); + } + } + } + + if (total_namelen == 0) + return true; + + *tabloc = bfd_zalloc (abfd, total_namelen); + if (*tabloc == NULL) + return false; + + *tablen = total_namelen; + strptr = *tabloc; + + for (current = abfd->archive_head; current != NULL; current = + current->next) + { + const char *normal; + unsigned int thislen; + + normal = normalize (current, current->filename); + if (normal == NULL) + return false; + + thislen = strlen (normal); + if (thislen > maxname) + { + /* Works for now; may need to be re-engineered if we + encounter an oddball archive format and want to + generalise this hack. */ + struct ar_hdr *hdr = arch_hdr (current); + strcpy (strptr, normal); + if (! trailing_slash) + strptr[thislen] = '\012'; + else + { + strptr[thislen] = '/'; + strptr[thislen + 1] = '\012'; + } + hdr->ar_name[0] = ar_padchar (current); + /* We know there will always be enough room (one of the few + cases where you may safely use sprintf). */ + sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc)); + /* Kinda Kludgy. We should just use the returned value of + sprintf but not all implementations get this right */ + { + char *temp = hdr->ar_name + 2; + for (; temp < hdr->ar_name + maxname; temp++) + if (*temp == '\0') + *temp = ' '; + } + strptr += thislen + 1; + if (trailing_slash) + ++strptr; + } + } + + return true; +} + +/** A couple of functions for creating ar_hdrs */ + +/* Takes a filename, returns an arelt_data for it, or NULL if it can't + make one. The filename must refer to a filename in the filesystem. + The filename field of the ar_hdr will NOT be initialized */ + +static struct areltdata * +bfd_ar_hdr_from_filesystem (abfd, filename) + bfd *abfd; + const char *filename; +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + char *temp, *temp1; + + if (stat (filename, &status) != 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + ared = (struct areltdata *) bfd_zalloc (abfd, sizeof (struct ar_hdr) + + sizeof (struct areltdata)); + if (ared == NULL) + return NULL; + hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); + + /* ar headers are space padded, not null padded! */ + memset ((PTR) hdr, ' ', sizeof (struct ar_hdr)); + + strncpy (hdr->ar_fmag, ARFMAG, 2); + + /* Goddamned sprintf doesn't permit MAXIMUM field lengths */ + sprintf ((hdr->ar_date), "%-12ld", (long) status.st_mtime); + sprintf ((hdr->ar_uid), "%ld", (long) status.st_uid); + sprintf ((hdr->ar_gid), "%ld", (long) status.st_gid); + sprintf ((hdr->ar_mode), "%-8o", (unsigned int) status.st_mode); + sprintf ((hdr->ar_size), "%-10ld", (long) status.st_size); + /* Correct for a lossage in sprintf whereby it null-terminates. I cannot + understand how these C losers could design such a ramshackle bunch of + IO operations */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; temp++) + { + if (*temp == '\0') + *temp = ' '; + } + strncpy (hdr->ar_fmag, ARFMAG, 2); + ared->parsed_size = status.st_size; + ared->arch_header = (char *) hdr; + + return ared; +} + +/* This is magic required by the "ar" program. Since it's + undocumented, it's undocumented. You may think that it would take + a strong stomach to write this, and it does, but it takes even a + stronger stomach to try to code around such a thing! */ + +struct ar_hdr * +bfd_special_undocumented_glue (abfd, filename) + bfd *abfd; + char *filename; +{ + struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename); + if (ar_elt == NULL) + return NULL; + return (struct ar_hdr *) ar_elt->arch_header; +} + + +/* Analogous to stat call */ +int +bfd_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + struct ar_hdr *hdr; + char *aloser; + + if (abfd->arelt_data == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + hdr = arch_hdr (abfd); + +#define foo(arelt, stelt, size) \ + buf->stelt = strtol (hdr->arelt, &aloser, size); \ + if (aloser == hdr->arelt) return -1; + + foo (ar_date, st_mtime, 10); + foo (ar_uid, st_uid, 10); + foo (ar_gid, st_gid, 10); + foo (ar_mode, st_mode, 8); + + buf->st_size = arch_eltdata (abfd)->parsed_size; + + return 0; +} + +void +bfd_dont_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + /* FIXME: This interacts unpleasantly with ar's quick-append option. + Fortunately ic960 users will never use that option. Fixing this + is very hard; fortunately I know how to do it and will do so once + intel's release is out the door. */ + + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + size_t length; + const char *filename; + size_t maxlen = ar_maxnamelen (abfd); + + if ((bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) + { + bfd_bsd_truncate_arname (abfd, pathname, arhdr); + return; + } + + filename = normalize (abfd, pathname); + if (filename == NULL) + { + /* FIXME */ + abort (); + } + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + + /* Add the padding character if there is room for it. */ + if (length < maxlen + || (length == maxlen && length < sizeof hdr->ar_name)) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +void +bfd_bsd_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else + { + /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + length = maxlen; + } + + if (length < maxlen) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* Store name into ar header. Truncates the name to fit. + 1> strip pathname to be just the basename. + 2> if it's short enuf to fit, stuff it in. + 3> If it doesn't end with .o, truncate it to fit + 4> truncate it before the .o, append .o, stuff THAT in. */ + +/* This is what gnu ar does. It's better but incompatible with the + bsd ar. */ + +void +bfd_gnu_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else + { /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) + { + hdr->ar_name[maxlen - 2] = '.'; + hdr->ar_name[maxlen - 1] = 'o'; + } + length = maxlen; + } + + if (length < 16) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* The BFD is open for write and has its format set to bfd_archive */ + +boolean +_bfd_write_archive_contents (arch) + bfd *arch; +{ + bfd *current; + char *etable = NULL; + bfd_size_type elength = 0; + const char *ename = NULL; + boolean makemap = bfd_has_map (arch); + boolean hasobjects = false; /* if no .o's, don't bother to make a map */ + bfd_size_type wrote; + unsigned int i; + int tries; + + /* Verify the viability of all entries; if any of them live in the + filesystem (as opposed to living in an archive open for input) + then construct a fresh ar_hdr for them. */ + for (current = arch->archive_head; current; current = current->next) + { + if (bfd_write_p (current)) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + if (!current->arelt_data) + { + current->arelt_data = + (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename); + if (!current->arelt_data) + return false; + + /* Put in the file name */ + BFD_SEND (arch, _bfd_truncate_arname, (arch, + current->filename, + (char *) arch_hdr (current))); + } + + if (makemap && ! hasobjects) + { /* don't bother if we won't make a map! */ + if ((bfd_check_format (current, bfd_object)) +#if 0 /* FIXME -- these are not set correctly */ + && ((bfd_get_file_flags (current) & HAS_SYMS)) +#endif + ) + hasobjects = true; + } + } + + if (!BFD_SEND (arch, _bfd_construct_extended_name_table, + (arch, &etable, &elength, &ename))) + return false; + + if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0) + return false; +#ifdef GNU960 + wrote = bfd_write (BFD_GNU960_ARMAG (arch), 1, SARMAG, arch); +#else + wrote = bfd_write (ARMAG, 1, SARMAG, arch); +#endif + if (wrote != SARMAG) + return false; + + if (makemap && hasobjects) + { + if (_bfd_compute_and_write_armap (arch, elength) != true) + return false; + } + + if (elength != 0) + { + struct ar_hdr hdr; + + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + strcpy (hdr.ar_name, ename); + /* Round size up to even number in archive header. */ + sprintf (&(hdr.ar_size[0]), "%-10d", + (int) ((elength + 1) & ~1)); + strncpy (hdr.ar_fmag, ARFMAG, 2); + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + if ((bfd_write ((char *) &hdr, 1, sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + || bfd_write (etable, 1, elength, arch) != elength) + return false; + if ((elength % 2) == 1) + { + if (bfd_write ("\012", 1, 1, arch) != 1) + return false; + } + } + + for (current = arch->archive_head; current; current = current->next) + { + char buffer[DEFAULT_BUFFERSIZE]; + unsigned int remaining = arelt_size (current); + struct ar_hdr *hdr = arch_hdr (current); + + /* write ar header */ + if (bfd_write ((char *) hdr, 1, sizeof (*hdr), arch) != sizeof (*hdr)) + return false; + if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) + return false; + while (remaining) + { + unsigned int amt = DEFAULT_BUFFERSIZE; + if (amt > remaining) + amt = remaining; + errno = 0; + if (bfd_read (buffer, amt, 1, current) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return false; + } + if (bfd_write (buffer, amt, 1, arch) != amt) + return false; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) + { + if (bfd_write ("\012", 1, 1, arch) != 1) + return false; + } + } + + if (makemap && hasobjects) + { + /* Verify the timestamp in the archive file. If it would not be + accepted by the linker, rewrite it until it would be. If + anything odd happens, break out and just return. (The + Berkeley linker checks the timestamp and refuses to read the + table-of-contents if it is >60 seconds less than the file's + modified-time. That painful hack requires this painful hack. */ + tries = 1; + do + { + if (bfd_update_armap_timestamp (arch)) + break; + (*_bfd_error_handler) + ("Warning: writing archive was slow: rewriting timestamp\n"); + } + while (++tries < 6); + } + + return true; +} + +/* Note that the namidx for the first symbol is 0 */ + +boolean +_bfd_compute_and_write_armap (arch, elength) + bfd *arch; + unsigned int elength; +{ + char *first_name = NULL; + bfd *current; + file_ptr elt_no = 0; + struct orl *map = NULL; + int orl_max = 1024; /* fine initial default */ + int orl_count = 0; + int stridx = 0; /* string index */ + asymbol **syms = NULL; + long syms_max = 0; + boolean ret; + + /* Dunno if this is the best place for this info... */ + if (elength != 0) + elength += sizeof (struct ar_hdr); + elength += elength % 2; + + map = (struct orl *) bfd_malloc (orl_max * sizeof (struct orl)); + if (map == NULL) + goto error_return; + + /* We put the symbol names on the arch obstack, and then discard + them when done. */ + first_name = bfd_alloc (arch, 1); + if (first_name == NULL) + goto error_return; + + /* Drop all the files called __.SYMDEF, we're going to make our + own */ + while (arch->archive_head && + strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) + arch->archive_head = arch->archive_head->next; + + /* Map over each element */ + for (current = arch->archive_head; + current != (bfd *) NULL; + current = current->next, elt_no++) + { + if ((bfd_check_format (current, bfd_object) == true) + && ((bfd_get_file_flags (current) & HAS_SYMS))) + { + long storage; + long symcount; + long src_count; + + storage = bfd_get_symtab_upper_bound (current); + if (storage < 0) + goto error_return; + + if (storage != 0) + { + if (storage > syms_max) + { + if (syms_max > 0) + free (syms); + syms_max = storage; + syms = (asymbol **) bfd_malloc ((size_t) syms_max); + if (syms == NULL) + goto error_return; + } + symcount = bfd_canonicalize_symtab (current, syms); + if (symcount < 0) + goto error_return; + + /* Now map over all the symbols, picking out the ones we 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 || + bfd_is_com_section (sec)) + && ! bfd_is_und_section (sec)) + { + size_t namelen; + struct orl *new_map; + + /* This symbol will go into the archive header */ + if (orl_count == orl_max) + { + orl_max *= 2; + new_map = + ((struct orl *) + bfd_realloc (map, orl_max * sizeof (struct orl))); + if (new_map == (struct orl *) NULL) + goto error_return; + + map = new_map; + } + + namelen = strlen (syms[src_count]->name); + map[orl_count].name = ((char **) + bfd_alloc (arch, + sizeof (char *))); + if (map[orl_count].name == NULL) + goto error_return; + *(map[orl_count].name) = bfd_alloc (arch, namelen + 1); + if (*(map[orl_count].name) == NULL) + goto error_return; + strcpy (*(map[orl_count].name), syms[src_count]->name); + (map[orl_count]).pos = (file_ptr) current; + (map[orl_count]).namidx = stridx; + + stridx += namelen + 1; + ++orl_count; + } + } + } + + /* Now ask the BFD to free up any cached information, so we + don't fill all of memory with symbol tables. */ + if (! bfd_free_cached_info (current)) + goto error_return; + } + } + + /* OK, now we have collected all the data, let's write them out */ + ret = BFD_SEND (arch, write_armap, + (arch, elength, map, orl_count, stridx)); + + if (syms_max > 0) + free (syms); + if (map != NULL) + free (map); + if (first_name != NULL) + bfd_release (arch, first_name); + + return ret; + + error_return: + if (syms_max > 0) + free (syms); + if (map != NULL) + free (map); + if (first_name != NULL) + bfd_release (arch, first_name); + + return false; +} + +boolean +bsd_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + int padit = stridx & 1; + unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE; + unsigned int stringsize = stridx + padit; + /* Include 8 bytes to store ranlibsize and stringsize in output. */ + unsigned int mapsize = ranlibsize + stringsize + 8; + file_ptr firstreal; + bfd *current = arch->archive_head; + bfd *last_elt = current; /* last element arch seen */ + bfd_byte temp[4]; + unsigned int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + stat (arch->filename, &statbuf); + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + sprintf (hdr.ar_name, RANLIBMAG); + /* Remember the timestamp, to keep it holy. But fudge it a little. */ + bfd_ardata (arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET; + bfd_ardata (arch)->armap_datepos = (SARMAG + + offsetof (struct ar_hdr, ar_date[0])); + sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp); + sprintf (hdr.ar_uid, "%ld", (long) getuid ()); + sprintf (hdr.ar_gid, "%ld", (long) getgid ()); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + strncpy (hdr.ar_fmag, ARFMAG, 2); + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + if (bfd_write ((char *) &hdr, 1, sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return false; + bfd_h_put_32 (arch, (bfd_vma) ranlibsize, temp); + if (bfd_write (temp, 1, sizeof (temp), arch) != sizeof (temp)) + return false; + + for (count = 0; count < orl_count; count++) + { + bfd_byte buf[BSD_SYMDEF_SIZE]; + + if (((bfd *) (map[count]).pos) != last_elt) + { + do + { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } + while (current != (bfd *) (map[count]).pos); + } /* if new archive element */ + + last_elt = current; + bfd_h_put_32 (arch, map[count].namidx, buf); + bfd_h_put_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE); + if (bfd_write (buf, BSD_SYMDEF_SIZE, 1, arch) != BSD_SYMDEF_SIZE) + return false; + } + + /* now write the strings themselves */ + bfd_h_put_32 (arch, stringsize, temp); + if (bfd_write (temp, 1, sizeof (temp), arch) != sizeof (temp)) + return false; + for (count = 0; count < orl_count; count++) + { + size_t len = strlen (*map[count].name) + 1; + + if (bfd_write (*map[count].name, 1, len, arch) != len) + return false; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for sun's ar we use a null. */ + if (padit) + { + if (bfd_write ("", 1, 1, arch) != 1) + return false; + } + + return true; +} + +/* At the end of archive file handling, update the timestamp in the + file, so the linker will accept it. + + Return true if the timestamp was OK, or an unusual problem happened. + Return false if we updated the timestamp. */ + +boolean +_bfd_archive_bsd_update_armap_timestamp (arch) + bfd *arch; +{ + struct stat archstat; + struct ar_hdr hdr; + unsigned int i; + + /* Flush writes, get last-write timestamp from file, and compare it + to the timestamp IN the file. */ + bfd_flush (arch); + if (bfd_stat (arch, &archstat) == -1) + { + perror ("Reading archive file mod timestamp"); + return true; /* Can't read mod time for some reason */ + } + if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp) + return true; /* OK by the linker's rules */ + + /* Update the timestamp. */ + bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET; + + /* Prepare an ASCII version suitable for writing. */ + memset (hdr.ar_date, 0, sizeof (hdr.ar_date)); + sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp); + for (i = 0; i < sizeof (hdr.ar_date); i++) + if (hdr.ar_date[i] == '\0') + (hdr.ar_date)[i] = ' '; + + /* Write it into the file. */ + bfd_ardata (arch)->armap_datepos = (SARMAG + + offsetof (struct ar_hdr, ar_date[0])); + if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0 + || (bfd_write (hdr.ar_date, sizeof (hdr.ar_date), 1, arch) + != sizeof (hdr.ar_date))) + { + /* FIXME: bfd can't call perror. */ + perror ("Writing updated armap timestamp"); + return true; /* Some error while writing */ + } + + return false; /* We updated the timestamp successfully. */ +} + +/* A coff armap looks like : + lARMAG + struct ar_hdr with name = '/' + number of symbols + offset of file for symbol 0 + offset of file for symbol 1 + + offset of file for symbol n-1 + symbol name 0 + symbol name 1 + + symbol name n-1 +*/ + +boolean +coff_write_armap (arch, elength, map, symbol_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int symbol_count; + int stridx; +{ + /* The size of the ranlib is the number of exported symbols in the + archive * the number of bytes in a int, + an int for the count */ + unsigned int ranlibsize = (symbol_count * 4) + 4; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr archive_member_file_ptr; + bfd *current = arch->archive_head; + unsigned int count; + struct ar_hdr hdr; + unsigned int i; + int padit = mapsize & 1; + + if (padit) + mapsize++; + + /* work out where the first object file will go in the archive */ + archive_member_file_ptr = (mapsize + + elength + + sizeof (struct ar_hdr) + + SARMAG); + + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", (long) time (NULL)); + /* This, at least, is what Intel coff sets the values to.: */ + sprintf ((hdr.ar_uid), "%d", 0); + sprintf ((hdr.ar_gid), "%d", 0); + sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0); + strncpy (hdr.ar_fmag, ARFMAG, 2); + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols */ + + if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return false; + + bfd_write_bigendian_4byte_int (arch, symbol_count); + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary. */ + + /* Write out the file offset for the file associated with each + symbol, and remember to keep the offsets padded out. */ + + current = arch->archive_head; + count = 0; + while (current != (bfd *) NULL && count < symbol_count) + { + /* For each symbol which is used defined in this object, write out + the object file's address in the archive */ + + while (((bfd *) (map[count]).pos) == current) + { + bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr); + count++; + } + /* Add size of this archive entry */ + archive_member_file_ptr += (arelt_size (current) + + sizeof (struct ar_hdr)); + /* remember aboout the even alignment */ + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + } + + /* now write the strings themselves */ + for (count = 0; count < symbol_count; count++) + { + size_t len = strlen (*map[count].name) + 1; + + if (bfd_write (*map[count].name, 1, len, arch) != len) + return false; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for arc960 we use a null. */ + if (padit) + { + if (bfd_write ("", 1, 1, arch) != 1) + return false; + } + + return true; +} diff --git a/contrib/gdb/bfd/archures.c b/contrib/gdb/bfd/archures.c new file mode 100644 index 000000000000..1db8bc24b86f --- /dev/null +++ b/contrib/gdb/bfd/archures.c @@ -0,0 +1,720 @@ +/* BFD library support routines for architectures. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 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. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include + +/* + +SECTION + Architectures + + BFD keeps one atom in a BFD describing the + architecture of the data attached to the BFD: a pointer to a + <>. + + Pointers to structures can be requested independently of a BFD + so that an architecture's information can be interrogated + without access to an open BFD. + + The architecture information is provided by each architecture package. + The set of default architectures is selected by the macro + <>. This is normally set up in the + @file{config/@var{target}.mt} file of your choice. If the name is not + defined, then all the architectures supported are included. + + When BFD starts up, all the architectures are called with an + initialize method. It is up to the architecture back end to + insert as many items into the list of architectures as it wants to; + generally this would be one for each machine and one for the + default case (an item with a machine field of 0). + + BFD's idea of an architecture is implemented in @file{archures.c}. +*/ + +/* + +SUBSECTION + bfd_architecture + +DESCRIPTION + This enum gives the object file's CPU architecture, in a + global sense---i.e., what processor family does it belong to? + Another field indicates which processor within + the family is in use. The machine gives a number which + distinguishes different versions of the architecture, + containing, for example, 2 and 3 for Intel i960 KA and i960 KB, + and 68020 and 68030 for Motorola 68020 and 68030. + +.enum bfd_architecture +.{ +. bfd_arch_unknown, {* File arch not known *} +. bfd_arch_obscure, {* Arch known, not one of these *} +. bfd_arch_m68k, {* Motorola 68xxx *} +. bfd_arch_vax, {* DEC Vax *} +. bfd_arch_i960, {* Intel 960 *} +. {* The order of the following is important. +. lower number indicates a machine type that +. only accepts a subset of the instructions +. available to machines with higher numbers. +. The exception is the "ca", which is +. incompatible with all other machines except +. "core". *} +. +.#define bfd_mach_i960_core 1 +.#define bfd_mach_i960_ka_sa 2 +.#define bfd_mach_i960_kb_sb 3 +.#define bfd_mach_i960_mc 4 +.#define bfd_mach_i960_xa 5 +.#define bfd_mach_i960_ca 6 +.#define bfd_mach_i960_jx 7 +.#define bfd_mach_i960_hx 8 +. +. bfd_arch_a29k, {* AMD 29000 *} +. bfd_arch_sparc, {* SPARC *} +.#define bfd_mach_sparc 1 +.{* The difference between v8plus and v9 is that v9 is a true 64 bit env. *} +.#define bfd_mach_sparc_v8plus 2 +.#define bfd_mach_sparc_v8plusa 3 {* with ultrasparc add'ns *} +.#define bfd_mach_sparc_v9 4 +.#define bfd_mach_sparc_v9a 5 {* with ultrasparc add'ns *} +.{* Nonzero if MACH has the v9 instruction set. *} +.#define bfd_mach_sparc_v9_p(mach) ((mach) != bfd_mach_sparc) +. bfd_arch_mips, {* MIPS Rxxxx *} +. bfd_arch_i386, {* Intel 386 *} +. bfd_arch_we32k, {* AT&T WE32xxx *} +. bfd_arch_tahoe, {* CCI/Harris Tahoe *} +. bfd_arch_i860, {* Intel 860 *} +. bfd_arch_romp, {* IBM ROMP PC/RT *} +. bfd_arch_alliant, {* Alliant *} +. bfd_arch_convex, {* Convex *} +. bfd_arch_m88k, {* Motorola 88xxx *} +. bfd_arch_pyramid, {* Pyramid Technology *} +. bfd_arch_h8300, {* Hitachi H8/300 *} +.#define bfd_mach_h8300 1 +.#define bfd_mach_h8300h 2 +. bfd_arch_powerpc, {* PowerPC *} +. bfd_arch_rs6000, {* IBM RS/6000 *} +. bfd_arch_hppa, {* HP PA RISC *} +. bfd_arch_z8k, {* Zilog Z8000 *} +.#define bfd_mach_z8001 1 +.#define bfd_mach_z8002 2 +. bfd_arch_h8500, {* Hitachi H8/500 *} +. bfd_arch_sh, {* Hitachi SH *} +. bfd_arch_alpha, {* Dec Alpha *} +. bfd_arch_arm, {* Advanced Risc Machines ARM *} +. bfd_arch_ns32k, {* National Semiconductors ns32000 *} +. bfd_arch_w65, {* WDC 65816 *} +. bfd_arch_last +. }; + + +*/ + +/* + +SUBSECTION + bfd_arch_info + +DESCRIPTION + This structure contains information on architectures for use + within BFD. + +. +.typedef struct bfd_arch_info +.{ +. int bits_per_word; +. int bits_per_address; +. int bits_per_byte; +. enum bfd_architecture arch; +. unsigned long mach; +. const char *arch_name; +. const char *printable_name; +. unsigned int section_align_power; +. {* true if this is the default machine for the architecture *} +. boolean the_default; +. const struct bfd_arch_info * (*compatible) +. PARAMS ((const struct bfd_arch_info *a, +. const struct bfd_arch_info *b)); +. +. boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); +. +. const struct bfd_arch_info *next; +.} bfd_arch_info_type; +*/ + +extern const bfd_arch_info_type bfd_a29k_arch; +extern const bfd_arch_info_type bfd_alpha_arch; +extern const bfd_arch_info_type bfd_arm_arch; +extern const bfd_arch_info_type bfd_h8300_arch; +extern const bfd_arch_info_type bfd_h8500_arch; +extern const bfd_arch_info_type bfd_hppa_arch; +extern const bfd_arch_info_type bfd_i386_arch; +extern const bfd_arch_info_type bfd_i860_arch; +extern const bfd_arch_info_type bfd_i960_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_mips_arch; +extern const bfd_arch_info_type bfd_powerpc_arch; +extern const bfd_arch_info_type bfd_rs6000_arch; +extern const bfd_arch_info_type bfd_sh_arch; +extern const bfd_arch_info_type bfd_sparc_arch; +extern const bfd_arch_info_type bfd_vax_arch; +extern const bfd_arch_info_type bfd_we32k_arch; +extern const bfd_arch_info_type bfd_z8k_arch; +extern const bfd_arch_info_type bfd_ns32k_arch; +extern const bfd_arch_info_type bfd_w65_arch; + +static const bfd_arch_info_type * const bfd_archures_list[] = +{ +#ifdef SELECT_ARCHITECTURES + SELECT_ARCHITECTURES, +#else + &bfd_a29k_arch, + &bfd_alpha_arch, + &bfd_arm_arch, + &bfd_h8300_arch, + &bfd_h8500_arch, + &bfd_hppa_arch, + &bfd_i386_arch, + &bfd_i860_arch, + &bfd_i960_arch, + &bfd_m68k_arch, + &bfd_m88k_arch, + &bfd_mips_arch, + &bfd_powerpc_arch, + &bfd_rs6000_arch, + &bfd_sh_arch, + &bfd_sparc_arch, + &bfd_vax_arch, + &bfd_we32k_arch, + &bfd_z8k_arch, + &bfd_ns32k_arch, + &bfd_w65_arch, +#endif + 0 +}; + +/* +FUNCTION + bfd_printable_name + +SYNOPSIS + const char *bfd_printable_name(bfd *abfd); + +DESCRIPTION + Return a printable string representing the architecture and machine + from the pointer to the architecture info structure. + +*/ + +const char * +bfd_printable_name (abfd) + bfd *abfd; +{ + return abfd->arch_info->printable_name; +} + + + +/* +FUNCTION + bfd_scan_arch + +SYNOPSIS + const bfd_arch_info_type *bfd_scan_arch(const char *string); + +DESCRIPTION + Figure out if BFD supports any cpu which could be described with + the name @var{string}. Return a pointer to an <> + structure if a machine is found, otherwise NULL. + +*/ + +const bfd_arch_info_type * +bfd_scan_arch (string) + const char *string; +{ + const bfd_arch_info_type * const *app, *ap; + + /* Look through all the installed architectures */ + for (app = bfd_archures_list; *app != NULL; app++) + { + for (ap = *app; ap != NULL; ap = ap->next) + { + if (ap->scan (ap, string)) + return ap; + } + } + + return NULL; +} + + + +/* +FUNCTION + bfd_arch_get_compatible + +SYNOPSIS + const bfd_arch_info_type *bfd_arch_get_compatible( + const bfd *abfd, + const bfd *bbfd); + +DESCRIPTION + Determine whether two BFDs' + architectures and machine types are compatible. Calculates + the lowest common denominator between the two architectures + and machine types implied by the BFDs and returns a pointer to + an <> structure describing the compatible machine. +*/ + +const bfd_arch_info_type * +bfd_arch_get_compatible (abfd, bbfd) + const bfd *abfd; + const bfd *bbfd; +{ + /* If either architecture is unknown, then all we can do is assume + the user knows what he's doing. */ + if (abfd->arch_info->arch == bfd_arch_unknown) + return bbfd->arch_info; + if (bbfd->arch_info->arch == bfd_arch_unknown) + return abfd->arch_info; + + /* Otherwise architecture-specific code has to decide. */ + return abfd->arch_info->compatible (abfd->arch_info, bbfd->arch_info); +} + + +/* +INTERNAL_DEFINITION + bfd_default_arch_struct + +DESCRIPTION + The <> is an item of + <> which has been initialized to a fairly + generic state. A BFD starts life by pointing to this + structure, until the correct back end has determined the real + architecture of the file. + +.extern const bfd_arch_info_type bfd_default_arch_struct; + +*/ + +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, + 0, +}; + +/* +FUNCTION + bfd_set_arch_info + +SYNOPSIS + void bfd_set_arch_info(bfd *abfd, const bfd_arch_info_type *arg); + +DESCRIPTION + Set the architecture info of @var{abfd} to @var{arg}. +*/ + +void +bfd_set_arch_info (abfd, arg) + bfd *abfd; + const bfd_arch_info_type *arg; +{ + abfd->arch_info = arg; +} + +/* +INTERNAL_FUNCTION + bfd_default_set_arch_mach + +SYNOPSIS + boolean bfd_default_set_arch_mach(bfd *abfd, + enum bfd_architecture arch, + unsigned long mach); + +DESCRIPTION + Set the architecture and machine type in BFD @var{abfd} + to @var{arch} and @var{mach}. Find the correct + pointer to a structure and insert it into the <> + pointer. +*/ + +boolean +bfd_default_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ + const bfd_arch_info_type * const *app, *ap; + + for (app = bfd_archures_list; *app != NULL; app++) + { + for (ap = *app; ap != NULL; ap = ap->next) + { + if (ap->arch == arch + && (ap->mach == mach + || (mach == 0 && ap->the_default))) + { + abfd->arch_info = ap; + return true; + } + } + } + + abfd->arch_info = &bfd_default_arch_struct; + bfd_set_error (bfd_error_bad_value); + return false; +} + + +/* +FUNCTION + bfd_get_arch + +SYNOPSIS + enum bfd_architecture bfd_get_arch(bfd *abfd); + +DESCRIPTION + Return the enumerated type which describes the BFD @var{abfd}'s + architecture. + +*/ + +enum bfd_architecture +bfd_get_arch (abfd) + bfd *abfd; +{ + return abfd->arch_info->arch; +} + +/* +FUNCTION + bfd_get_mach + +SYNOPSIS + unsigned long bfd_get_mach(bfd *abfd); + +DESCRIPTION + Return the long type which describes the BFD @var{abfd}'s + machine. +*/ + +unsigned long +bfd_get_mach (abfd) + bfd *abfd; +{ + return abfd->arch_info->mach; +} + +/* +FUNCTION + bfd_arch_bits_per_byte + +SYNOPSIS + unsigned int bfd_arch_bits_per_byte(bfd *abfd); + +DESCRIPTION + Return the number of bits in one of the BFD @var{abfd}'s + architecture's bytes. + +*/ + +unsigned int +bfd_arch_bits_per_byte (abfd) + bfd *abfd; +{ + return abfd->arch_info->bits_per_byte; +} + +/* +FUNCTION + bfd_arch_bits_per_address + +SYNOPSIS + unsigned int bfd_arch_bits_per_address(bfd *abfd); + +DESCRIPTION + Return the number of bits in one of the BFD @var{abfd}'s + architecture's addresses. +*/ + +unsigned int +bfd_arch_bits_per_address (abfd) + bfd *abfd; +{ + return abfd->arch_info->bits_per_address; +} + + +/* +INTERNAL_FUNCTION + bfd_default_compatible + +SYNOPSIS + const bfd_arch_info_type *bfd_default_compatible + (const bfd_arch_info_type *a, + const bfd_arch_info_type *b); + +DESCRIPTION + The default function for testing for compatibility. +*/ + +const bfd_arch_info_type * +bfd_default_compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->arch != b->arch) + return NULL; + + if (a->mach > b->mach) + return a; + + if (b->mach > a->mach) + return b; + + return a; +} + + +/* +INTERNAL_FUNCTION + bfd_default_scan + +SYNOPSIS + boolean bfd_default_scan(const struct bfd_arch_info *info, const char *string); + +DESCRIPTION + The default function for working out whether this is an + architecture hit and a machine hit. +*/ + +boolean +bfd_default_scan (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + const char *ptr_src; + const char *ptr_tst; + unsigned long number; + enum bfd_architecture arch; + + /* First test for an exact match */ + if (strcmp (string, info->printable_name) == 0) + return true; + + /* See how much of the supplied string matches with the + architecture, eg the string m68k:68020 would match the 68k entry + up to the :, then we get left with the machine number */ + + for (ptr_src = string, ptr_tst = info->arch_name; + *ptr_src && *ptr_tst; + ptr_src++, ptr_tst++) + { + if (*ptr_src != *ptr_tst) break; + } + + /* Chewed up as much of the architecture as will match, skip any + colons */ + if (*ptr_src == ':') + ptr_src++; + + if (*ptr_src == 0) + { + /* nothing more, then only keep this one if it is the default + machine for this architecture */ + return info->the_default; + } + + number = 0; + while (isdigit(*ptr_src)) + { + number = number * 10 + *ptr_src - '0'; + ptr_src++; + } + + switch (number) + { + case 65: + arch = bfd_arch_w65; + break; + + case 300: + arch = bfd_arch_h8300; + break; + + case 500: + arch = bfd_arch_h8500; + break; + + case 68010: + case 68020: + case 68030: + case 68040: + case 68332: + case 68050: + case 68000: + arch = bfd_arch_m68k; + break; + + case 386: + case 80386: + case 486: + case 80486: + arch = bfd_arch_i386; + break; + + case 29000: + arch = bfd_arch_a29k; + break; + + case 8000: + arch = bfd_arch_z8k; + break; + + case 32000: + arch = bfd_arch_we32k; + break; + + case 860: + case 80860: + arch = bfd_arch_i860; + break; + case 960: + case 80960: + arch = bfd_arch_i960; + break; + + case 2000: + case 3000: + case 4000: + case 4400: + arch = bfd_arch_mips; + break; + + case 6000: + arch = bfd_arch_rs6000; + break; + + default: + return false; + } + + if (arch != info->arch) + return false; + + if (number != info->mach) + return false; + + return true; +} + + +/* +FUNCTION + bfd_get_arch_info + +SYNOPSIS + const bfd_arch_info_type * bfd_get_arch_info(bfd *abfd); + +DESCRIPTION + Return the architecture info struct in @var{abfd}. +*/ + +const bfd_arch_info_type * +bfd_get_arch_info (abfd) + bfd *abfd; +{ + return abfd->arch_info; +} + + +/* +FUNCTION + bfd_lookup_arch + +SYNOPSIS + const bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture + arch, + unsigned long machine); + +DESCRIPTION + Look for the architecure info structure which matches the + arguments @var{arch} and @var{machine}. A machine of 0 matches the + machine/architecture structure which marks itself as the + default. +*/ + +const bfd_arch_info_type * +bfd_lookup_arch (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + const bfd_arch_info_type * const *app, *ap; + + for (app = bfd_archures_list; *app != NULL; app++) + { + for (ap = *app; ap != NULL; ap = ap->next) + { + if (ap->arch == arch + && (ap->mach == machine + || (machine == 0 && ap->the_default))) + return ap; + } + } + + return NULL; +} + + +/* +FUNCTION + bfd_printable_arch_mach + +SYNOPSIS + const char *bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); + +DESCRIPTION + Return a printable string representing the architecture and + machine type. + + This routine is depreciated. +*/ + +const char * +bfd_printable_arch_mach (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + const bfd_arch_info_type *ap = bfd_lookup_arch (arch, machine); + + if (ap) + return ap->printable_name; + return "UNKNOWN!"; +} diff --git a/contrib/gdb/bfd/bfd-in.h b/contrib/gdb/bfd/bfd-in.h new file mode 100644 index 000000000000..d2912396551a --- /dev/null +++ b/contrib/gdb/bfd/bfd-in.h @@ -0,0 +1,668 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" +#include "obstack.h" + +/* These two lines get substitutions done by commands in Makefile.in. */ +#define BFD_VERSION "@VERSION@" +#define BFD_ARCH_SIZE @WORDSIZE@ +#define BFD_HOST_64BIT_LONG @BFD_HOST_64BIT_LONG@ + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in -fnf */ +/* It gets worse if the host also defines a true/false enum... -sts */ +/* And even worse if your compiler has built-in boolean types... -law */ +#if defined (__GNUG__) && (__GNUC_MINOR__ > 5) +#define TRUE_FALSE_ALREADY_DEFINED +#endif +#ifdef MPW +/* Pre-emptive strike - get the file with the enum. */ +#include +#define TRUE_FALSE_ALREADY_DEFINED +#endif /* MPW */ +#ifndef TRUE_FALSE_ALREADY_DEFINED +typedef enum bfd_boolean {false, true} boolean; +#define BFD_TRUE_FALSE +#else +/* Use enum names that will appear nowhere else. */ +typedef enum bfd_boolean {bfd_fffalse, bfd_tttrue} boolean; +#endif + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. + If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be + set to 1 above. Otherwise, if gcc is being used, this code will + use gcc's "long long" type. Otherwise, the compilation will fail + if 64-bit targets are requested. */ + +#ifdef BFD64 + +#ifndef BFD_HOST_64_BIT +#if BFD_HOST_64BIT_LONG +#define BFD_HOST_64_BIT long +#else +#ifdef __GNUC__ +#define BFD_HOST_64_BIT long long +#endif /* defined (__GNUC__) */ +#endif /* ! BFD_HOST_64BIT_LONG */ +#endif /* ! defined (BFD_HOST_64_BIT) */ + +typedef unsigned BFD_HOST_64_BIT bfd_vma; +typedef BFD_HOST_64_BIT bfd_signed_vma; +typedef unsigned BFD_HOST_64_BIT bfd_size_type; +typedef unsigned BFD_HOST_64_BIT symvalue; + +#ifndef fprintf_vma +#if BFD_HOST_64BIT_LONG +#define sprintf_vma(s,x) sprintf (s, "%016lx", x) +#define fprintf_vma(f,x) fprintf (f, "%016lx", x) +#else +#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) +#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) +#define fprintf_vma(s,x) \ + fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#define sprintf_vma(s,x) \ + sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#endif +#endif + +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf(s, "%08lx", x) +#define sprintf_vma(s,x) sprintf(s, "%08lx", x) +#endif /* not BFD64 */ +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ +typedef unsigned char bfd_byte; + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Values that may appear in the flags field of a BFD. These also + appear in the object_flags field of the bfd_target structure, where + they indicate the set of flags used by that backend (not all flags + are meaningful for all object file formats) (FIXME: at the moment, + the object_flags values have mostly just been copied from backend + to another, and are not necessarily correct). */ + +/* No flags. */ +#define NO_FLAGS 0x00 + +/* BFD contains relocation entries. */ +#define HAS_RELOC 0x01 + +/* BFD is directly executable. */ +#define EXEC_P 0x02 + +/* BFD has line number information (basically used for F_LNNO in a + COFF header). */ +#define HAS_LINENO 0x04 + +/* BFD has debugging information. */ +#define HAS_DEBUG 0x08 + +/* BFD has symbols. */ +#define HAS_SYMS 0x10 + +/* BFD has local symbols (basically used for F_LSYMS in a COFF + header). */ +#define HAS_LOCALS 0x20 + +/* BFD is a dynamic object. */ +#define DYNAMIC 0x40 + +/* Text section is write protected (if D_PAGED is not set, this is + like an a.out NMAGIC file) (the linker sets this by default, but + clears it for -r or -N). */ +#define WP_TEXT 0x80 + +/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the + linker sets this by default, but clears it for -r or -n or -N). */ +#define D_PAGED 0x100 + +/* BFD is relaxable (this means that bfd_relax_section may be able to + do something) (sometimes bfd_relax_section can do something even if + this is not set). */ +#define BFD_IS_RELAXABLE 0x200 + +/* This may be set before writing out a BFD to request using a + traditional format. For example, this is used to request that when + writing out an a.out object the symbols not be hashed to eliminate + duplicates. */ +#define BFD_TRADITIONAL_FORMAT 0x400 + +/* This flag indicates that the BFD contents are actually cached in + memory. If this is set, iostream points to a bfd_in_memory struct. */ +#define BFD_IN_MEMORY 0x800 + +/* symbols and relocation */ + +/* A count of carsyms (canonical archive symbols). */ +typedef unsigned long symindex; + +/* How to perform a relocation. */ +typedef const struct reloc_howto_struct reloc_howto_type; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +/* General purpose part of a symbol X; + target specific parts are in libcoff.h, libaout.h, etc. */ + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* A canonical archive symbol. */ +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + + +/* Used in generating armaps (archive tables of contents). + Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *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_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#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_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = (boolean)true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; + CONST char *name; /* Symbol name. */ + unsigned char stab_type; /* Stab type. */ + char stab_other; /* Stab other. */ + short stab_desc; /* Stab desc. */ + CONST char *stab_name; /* String for stab type. */ +} symbol_info; + +/* Get the name of a stabs type code. */ + +extern const char *bfd_get_stab_name PARAMS ((int)); + +/* Hash table routines. There is no way to free up a hash table. */ + +/* An element in the hash table. Most uses will actually use a larger + structure, and an instance of this will be the first field. */ + +struct bfd_hash_entry +{ + /* Next entry for this hash code. */ + struct bfd_hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; +}; + +/* A hash table. */ + +struct bfd_hash_table +{ + /* The hash array. */ + struct bfd_hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* A function used to create new elements in the hash table. The + first entry is itself a pointer to an element. When this + function is first invoked, this pointer will be NULL. However, + having the pointer permits a hierarchy of method functions to be + built each of which calls the function in the superclass. Thus + each function should be written to allocate a new block of memory + only if the argument is NULL. */ + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + /* An obstack for this hash table. */ + struct obstack memory; +}; + +/* Initialize a hash table. */ +extern boolean bfd_hash_table_init + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Initialize a hash table specifying a size. */ +extern boolean bfd_hash_table_init_n + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int size)); + +/* Free up a hash table. */ +extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *)); + +/* Look up a string in a hash table. If CREATE is true, a new entry + will be created for this string if one does not already exist. The + COPY argument must be true if this routine should copy the string + into newly allocated memory when adding an entry. */ +extern struct bfd_hash_entry *bfd_hash_lookup + PARAMS ((struct bfd_hash_table *, const char *, boolean create, + boolean copy)); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old, + struct bfd_hash_entry *nw)); + +/* Base method for creating a hash table entry. */ +extern struct bfd_hash_entry *bfd_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Grab some space for a hash table entry. */ +extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *, + unsigned int)); + +/* Traverse a hash table in a random order, calling a function on each + element. If the function returns false, the traversal stops. The + INFO argument is passed to the function. */ +extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *, + boolean (*) (struct bfd_hash_entry *, + PTR), + PTR info)); + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#if defined(__STDC__) || defined(ALMOST_STDC) +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + +/* User program access to BFD facilities */ + +/* Direct I/O routines, for programs which know more about the object + file than BFD does. Use higher level routines if possible. */ + +extern bfd_size_type bfd_read + PARAMS ((PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern bfd_size_type bfd_write + PARAMS ((const PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern int bfd_seek PARAMS ((bfd *abfd, file_ptr fp, int direction)); +extern long bfd_tell PARAMS ((bfd *abfd)); +extern int bfd_flush PARAMS ((bfd *abfd)); +extern int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_cacheable(abfd) ((abfd)->cacheable) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) +#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) +#define bfd_header_big_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) +#define bfd_header_little_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (boolean)(bool)), true) + +extern boolean bfd_record_phdr + PARAMS ((bfd *, unsigned long, boolean, flagword, boolean, bfd_vma, + boolean, boolean, unsigned int, struct sec **)); + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((const unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct symbol_cache_entry; +struct bfd_link_info; +struct bfd_link_hash_entry; +#endif +extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd)); +extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value)); +extern boolean bfd_ecoff_set_regmasks + PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask)); +extern PTR bfd_ecoff_debug_init + PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern void bfd_ecoff_debug_free + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + bfd *input_bfd, struct ecoff_debug_info *input_debug, + const struct ecoff_debug_swap *input_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate_other + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, bfd *input_bfd, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_externals + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + boolean relocateable, + boolean (*get_extr) (struct symbol_cache_entry *, + struct ecoff_extr *), + void (*set_index) (struct symbol_cache_entry *, + bfd_size_type))); +extern boolean bfd_ecoff_debug_one_external + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + const char *name, struct ecoff_extr *esym)); +extern bfd_size_type bfd_ecoff_debug_size + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +extern boolean bfd_ecoff_write_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where)); +extern boolean bfd_ecoff_write_accumulated_debug + PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where)); +extern boolean bfd_mips_ecoff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +extern boolean bfd_elf32_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern boolean bfd_elf64_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf32_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, + struct bfd_link_info *, struct sec **)); +extern boolean bfd_elf64_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, + struct bfd_link_info *, struct sec **)); +extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *)); +extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *)); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sunos_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_sunos_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **, + struct sec **)); + +/* Linux shared library support routines for the linker. */ + +extern boolean bfd_i386linux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_m68klinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +extern void bfd_init_window PARAMS ((bfd_window *)); +extern void bfd_free_window PARAMS ((bfd_window *)); +extern boolean bfd_get_file_window + PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, boolean)); + +/* XCOFF support routines for the linker. */ + +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); +extern boolean bfd_xcoff_import_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_vma, const char *, const char *, const char *)); +extern boolean bfd_xcoff_export_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, boolean, + int, boolean, boolean, struct sec **)); + +/* And more from the source. */ diff --git a/contrib/gdb/bfd/bfd-in2.h b/contrib/gdb/bfd/bfd-in2.h new file mode 100644 index 000000000000..d238d5afa4a0 --- /dev/null +++ b/contrib/gdb/bfd/bfd-in2.h @@ -0,0 +1,2479 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" +#include "obstack.h" + +/* These two lines get substitutions done by commands in Makefile.in. */ +#define BFD_VERSION "@VERSION@" +#define BFD_ARCH_SIZE @WORDSIZE@ +#define BFD_HOST_64BIT_LONG @BFD_HOST_64BIT_LONG@ + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in -fnf */ +/* It gets worse if the host also defines a true/false enum... -sts */ +/* And even worse if your compiler has built-in boolean types... -law */ +#if defined (__GNUG__) && (__GNUC_MINOR__ > 5) +#define TRUE_FALSE_ALREADY_DEFINED +#endif +#ifdef MPW +/* Pre-emptive strike - get the file with the enum. */ +#include +#define TRUE_FALSE_ALREADY_DEFINED +#endif /* MPW */ +#ifndef TRUE_FALSE_ALREADY_DEFINED +typedef enum bfd_boolean {false, true} boolean; +#define BFD_TRUE_FALSE +#else +/* Use enum names that will appear nowhere else. */ +typedef enum bfd_boolean {bfd_fffalse, bfd_tttrue} boolean; +#endif + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. + If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be + set to 1 above. Otherwise, if gcc is being used, this code will + use gcc's "long long" type. Otherwise, the compilation will fail + if 64-bit targets are requested. */ + +#ifdef BFD64 + +#ifndef BFD_HOST_64_BIT +#if BFD_HOST_64BIT_LONG +#define BFD_HOST_64_BIT long +#else +#ifdef __GNUC__ +#define BFD_HOST_64_BIT long long +#endif /* defined (__GNUC__) */ +#endif /* ! BFD_HOST_64BIT_LONG */ +#endif /* ! defined (BFD_HOST_64_BIT) */ + +typedef unsigned BFD_HOST_64_BIT bfd_vma; +typedef BFD_HOST_64_BIT bfd_signed_vma; +typedef unsigned BFD_HOST_64_BIT bfd_size_type; +typedef unsigned BFD_HOST_64_BIT symvalue; + +#ifndef fprintf_vma +#if BFD_HOST_64BIT_LONG +#define sprintf_vma(s,x) sprintf (s, "%016lx", x) +#define fprintf_vma(f,x) fprintf (f, "%016lx", x) +#else +#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) +#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) +#define fprintf_vma(s,x) \ + fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#define sprintf_vma(s,x) \ + sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#endif +#endif + +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf(s, "%08lx", x) +#define sprintf_vma(s,x) sprintf(s, "%08lx", x) +#endif /* not BFD64 */ +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ +typedef unsigned char bfd_byte; + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Values that may appear in the flags field of a BFD. These also + appear in the object_flags field of the bfd_target structure, where + they indicate the set of flags used by that backend (not all flags + are meaningful for all object file formats) (FIXME: at the moment, + the object_flags values have mostly just been copied from backend + to another, and are not necessarily correct). */ + +/* No flags. */ +#define NO_FLAGS 0x00 + +/* BFD contains relocation entries. */ +#define HAS_RELOC 0x01 + +/* BFD is directly executable. */ +#define EXEC_P 0x02 + +/* BFD has line number information (basically used for F_LNNO in a + COFF header). */ +#define HAS_LINENO 0x04 + +/* BFD has debugging information. */ +#define HAS_DEBUG 0x08 + +/* BFD has symbols. */ +#define HAS_SYMS 0x10 + +/* BFD has local symbols (basically used for F_LSYMS in a COFF + header). */ +#define HAS_LOCALS 0x20 + +/* BFD is a dynamic object. */ +#define DYNAMIC 0x40 + +/* Text section is write protected (if D_PAGED is not set, this is + like an a.out NMAGIC file) (the linker sets this by default, but + clears it for -r or -N). */ +#define WP_TEXT 0x80 + +/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the + linker sets this by default, but clears it for -r or -n or -N). */ +#define D_PAGED 0x100 + +/* BFD is relaxable (this means that bfd_relax_section may be able to + do something) (sometimes bfd_relax_section can do something even if + this is not set). */ +#define BFD_IS_RELAXABLE 0x200 + +/* This may be set before writing out a BFD to request using a + traditional format. For example, this is used to request that when + writing out an a.out object the symbols not be hashed to eliminate + duplicates. */ +#define BFD_TRADITIONAL_FORMAT 0x400 + +/* This flag indicates that the BFD contents are actually cached in + memory. If this is set, iostream points to a bfd_in_memory struct. */ +#define BFD_IN_MEMORY 0x800 + +/* symbols and relocation */ + +/* A count of carsyms (canonical archive symbols). */ +typedef unsigned long symindex; + +/* How to perform a relocation. */ +typedef const struct reloc_howto_struct reloc_howto_type; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +/* General purpose part of a symbol X; + target specific parts are in libcoff.h, libaout.h, etc. */ + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* A canonical archive symbol. */ +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + + +/* Used in generating armaps (archive tables of contents). + Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *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_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#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_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = (boolean)true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; + CONST char *name; /* Symbol name. */ + unsigned char stab_type; /* Stab type. */ + char stab_other; /* Stab other. */ + short stab_desc; /* Stab desc. */ + CONST char *stab_name; /* String for stab type. */ +} symbol_info; + +/* Get the name of a stabs type code. */ + +extern const char *bfd_get_stab_name PARAMS ((int)); + +/* Hash table routines. There is no way to free up a hash table. */ + +/* An element in the hash table. Most uses will actually use a larger + structure, and an instance of this will be the first field. */ + +struct bfd_hash_entry +{ + /* Next entry for this hash code. */ + struct bfd_hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; +}; + +/* A hash table. */ + +struct bfd_hash_table +{ + /* The hash array. */ + struct bfd_hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* A function used to create new elements in the hash table. The + first entry is itself a pointer to an element. When this + function is first invoked, this pointer will be NULL. However, + having the pointer permits a hierarchy of method functions to be + built each of which calls the function in the superclass. Thus + each function should be written to allocate a new block of memory + only if the argument is NULL. */ + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + /* An obstack for this hash table. */ + struct obstack memory; +}; + +/* Initialize a hash table. */ +extern boolean bfd_hash_table_init + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Initialize a hash table specifying a size. */ +extern boolean bfd_hash_table_init_n + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int size)); + +/* Free up a hash table. */ +extern void bfd_hash_table_free PARAMS ((struct bfd_hash_table *)); + +/* Look up a string in a hash table. If CREATE is true, a new entry + will be created for this string if one does not already exist. The + COPY argument must be true if this routine should copy the string + into newly allocated memory when adding an entry. */ +extern struct bfd_hash_entry *bfd_hash_lookup + PARAMS ((struct bfd_hash_table *, const char *, boolean create, + boolean copy)); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old, + struct bfd_hash_entry *nw)); + +/* Base method for creating a hash table entry. */ +extern struct bfd_hash_entry *bfd_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Grab some space for a hash table entry. */ +extern PTR bfd_hash_allocate PARAMS ((struct bfd_hash_table *, + unsigned int)); + +/* Traverse a hash table in a random order, calling a function on each + element. If the function returns false, the traversal stops. The + INFO argument is passed to the function. */ +extern void bfd_hash_traverse PARAMS ((struct bfd_hash_table *, + boolean (*) (struct bfd_hash_entry *, + PTR), + PTR info)); + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#if defined(__STDC__) || defined(ALMOST_STDC) +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + +/* User program access to BFD facilities */ + +/* Direct I/O routines, for programs which know more about the object + file than BFD does. Use higher level routines if possible. */ + +extern bfd_size_type bfd_read + PARAMS ((PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern bfd_size_type bfd_write + PARAMS ((const PTR, bfd_size_type size, bfd_size_type nitems, bfd *abfd)); +extern int bfd_seek PARAMS ((bfd *abfd, file_ptr fp, int direction)); +extern long bfd_tell PARAMS ((bfd *abfd)); +extern int bfd_flush PARAMS ((bfd *abfd)); +extern int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_cacheable(abfd) ((abfd)->cacheable) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) +#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) +#define bfd_header_big_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) +#define bfd_header_little_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = (boolean)(bool)), true) + +extern boolean bfd_record_phdr + PARAMS ((bfd *, unsigned long, boolean, flagword, boolean, bfd_vma, + boolean, boolean, unsigned int, struct sec **)); + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((const unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((const unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((const unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct symbol_cache_entry; +struct bfd_link_info; +struct bfd_link_hash_entry; +#endif +extern bfd_vma bfd_ecoff_get_gp_value PARAMS ((bfd * abfd)); +extern boolean bfd_ecoff_set_gp_value PARAMS ((bfd *abfd, bfd_vma gp_value)); +extern boolean bfd_ecoff_set_regmasks + PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask)); +extern PTR bfd_ecoff_debug_init + PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern void bfd_ecoff_debug_free + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + bfd *input_bfd, struct ecoff_debug_info *input_debug, + const struct ecoff_debug_swap *input_swap, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_accumulate_other + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, bfd *input_bfd, + struct bfd_link_info *)); +extern boolean bfd_ecoff_debug_externals + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + boolean relocateable, + boolean (*get_extr) (struct symbol_cache_entry *, + struct ecoff_extr *), + void (*set_index) (struct symbol_cache_entry *, + bfd_size_type))); +extern boolean bfd_ecoff_debug_one_external + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + const char *name, struct ecoff_extr *esym)); +extern bfd_size_type bfd_ecoff_debug_size + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +extern boolean bfd_ecoff_write_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where)); +extern boolean bfd_ecoff_write_accumulated_debug + PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where)); +extern boolean bfd_mips_ecoff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +extern boolean bfd_elf32_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern boolean bfd_elf64_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean)); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf32_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, + struct bfd_link_info *, struct sec **)); +extern boolean bfd_elf64_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, boolean, + struct bfd_link_info *, struct sec **)); +extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *)); +extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *)); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_sunos_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_sunos_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **, + struct sec **)); + +/* Linux shared library support routines for the linker. */ + +extern boolean bfd_i386linux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_m68klinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window { + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} bfd_window; + +extern void bfd_init_window PARAMS ((bfd_window *)); +extern void bfd_free_window PARAMS ((bfd_window *)); +extern boolean bfd_get_file_window + PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, boolean)); + +/* XCOFF support routines for the linker. */ + +extern boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); +extern boolean bfd_xcoff_import_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_vma, const char *, const char *, const char *)); +extern boolean bfd_xcoff_export_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + boolean)); +extern boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern boolean bfd_xcoff_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, boolean, + int, boolean, boolean, struct sec **)); + +/* And more from the source. */ +void +bfd_init PARAMS ((void)); + +bfd * +bfd_openr PARAMS ((CONST char *filename, CONST char *target)); + +bfd * +bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd)); + +bfd * +bfd_openstreamr PARAMS (()); + +bfd * +bfd_openw PARAMS ((CONST char *filename, CONST char *target)); + +boolean +bfd_close PARAMS ((bfd *abfd)); + +boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd_size_type +bfd_alloc_size PARAMS ((bfd *abfd)); + +bfd * +bfd_create PARAMS ((CONST char *filename, bfd *templ)); + + + /* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + (*((unsigned char *)(ptr)) = (unsigned char)(val)) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *)(ptr)) +#define bfd_get_signed_8(abfd, ptr) \ + ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + + + /* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx16,(ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx32,(ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx64,(ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) + +typedef struct sec +{ + /* The name of the section; the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + + CONST char *name; + + /* Which section is it; 0..nth. */ + + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + + struct sec *next; + + /* The field flags contains attributes of the section. Some + flags are read in from the object file, and some are + synthesized from other information. */ + + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loading. + This is clear for a section containing debug information + only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This is clear for a .bss section. */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there is + some relocation information too. */ +#define SEC_RELOC 0x004 + +#if 0 /* Obsolete ? */ +#define SEC_BALIGN 0x008 +#endif + + /* A signal to the OS that the section contains read only + data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (e.g., <<__CTOR_LIST__>>), attaches + the symbol to it, and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocate the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section is a constuctor, and should be placed at the + end of the text, data, or bss section(?). */ +#define SEC_CONSTRUCTOR_TEXT 0x1100 +#define SEC_CONSTRUCTOR_DATA 0x2100 +#define SEC_CONSTRUCTOR_BSS 0x3100 + + /* The section has contents - a data section could be + <> | <>; a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a COFF shared library section. This flag is + only for the linker. If this type of section appears in + the input file, the linker must copy it to the output file + without changing the vma or size. FIXME: Although this + was originally intended to be general, it really is COFF + specific (and the flag was renamed to indicate this). It + might be cleaner to have some more general mechanism to + allow the back end to control what the linker does with + sections. */ +#define SEC_COFF_SHARED_LIBRARY 0x800 + + /* The section is a common section (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section_ptr), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* The contents of this section are held in memory pointed to + by the contents field. This is checked by + bfd_get_section_contents, and the data is retrieved from + memory if appropriate. */ +#define SEC_IN_MEMORY 0x20000 + + /* The contents of this section are to be excluded by the + linker for executable and shared objects unless those + objects are to be further relocated. */ +#define SEC_EXCLUDE 0x40000 + + /* The contents of this section are to be sorted by the + based on the address specified in the associated symbol + table. */ +#define SEC_SORT_ENTRIES 0x80000 + + /* End of section flags. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + + bfd_vma vma; + boolean user_set_vma; + + /* The load address of the section - where it would be in a + rom image; really only used for writing section header + information. */ + + bfd_vma lma; + + /* The size of the section in bytes, as it will be output. + contains a value even if the section has no contents (e.g., the + size of <<.bss>>). This will be filled in after relocation */ + + bfd_size_type _cooked_size; + + /* The original size on disk of the section, in bytes. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset into the output section of the first byte in the input + section. E.g., if this was going to start at the 100th byte in + the output section, this value would be 100. */ + + bfd_vma output_offset; + + /* The output section through which to map on output. */ + + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent of 2 - + e.g., 3 aligns to 2^3 (or 8). */ + + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above */ + + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data */ + + file_ptr filepos; + + /* File position of relocation info */ + + file_ptr rel_filepos; + + /* File position of line data */ + + file_ptr line_filepos; + + /* Pointer to data for applications */ + + PTR userdata; + + /* If the SEC_IN_MEMORY flag is set, this points to the actual + contents. */ + unsigned char *contents; + + /* Attached line number information */ + + alent *lineno; + + /* Number of line number records */ + + unsigned int lineno_count; + + /* When a section is being output, this value changes as more + linenumbers are written out */ + + file_ptr moving_line_filepos; + + /* What the section number is in the target world */ + + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + + bfd *owner; + + boolean reloc_done; + /* A symbol which points at this section only */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_link_order *link_order_head; + struct bfd_link_order *link_order_tail; +} asection ; + + /* 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. */ +#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 const 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 const 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 const asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) + /* Pointer to the indirect section */ +extern const asection bfd_ind_section; +#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) + +extern const struct symbol_cache_entry * const bfd_abs_symbol; +extern const struct symbol_cache_entry * const bfd_com_symbol; +extern const struct symbol_cache_entry * const bfd_und_symbol; +extern const struct symbol_cache_entry * const bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + (section->reloc_done ? (abort(),1): (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, CONST char *name)); + +boolean +bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +boolean +bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val)); + +boolean +bfd_set_section_contents + PARAMS ((bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count)); + +boolean +bfd_get_section_contents + PARAMS ((bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count)); + +boolean +bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, bfd *obfd, asection *osec)); + +#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ + BFD_SEND (ibfd, _bfd_copy_private_section_data, \ + (ibfd, isection, obfd, osection)) +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 + /* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_v8plus 2 +#define bfd_mach_sparc_v8plusa 3 /* with ultrasparc add'ns */ +#define bfd_mach_sparc_v9 4 +#define bfd_mach_sparc_v9a 5 /* with ultrasparc add'ns */ + /* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) ((mach) != bfd_mach_sparc) + bfd_arch_mips, /* MIPS Rxxxx */ + bfd_arch_i386, /* Intel 386 */ + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 + bfd_arch_powerpc, /* PowerPC */ + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ + bfd_arch_alpha, /* Dec Alpha */ + bfd_arch_arm, /* Advanced Risc Machines ARM */ + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + unsigned long mach; + const char *arch_name; + const char *printable_name; + unsigned int section_align_power; + /* true if this is the default machine for the architecture */ + boolean the_default; + const struct bfd_arch_info * (*compatible) + PARAMS ((const struct bfd_arch_info *a, + const struct bfd_arch_info *b)); + + boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); + + const struct bfd_arch_info *next; +} bfd_arch_info_type; +const char * +bfd_printable_name PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_scan_arch PARAMS ((const char *string)); + +const bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + const bfd *abfd, + const bfd *bbfd)); + +void +bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_lookup_arch + PARAMS ((enum bfd_architecture + arch, + unsigned long machine)); + +const char * +bfd_printable_arch_mach + PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +typedef enum bfd_reloc_status +{ + /* No errors detected */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions */ + bfd_reloc_continue, + + /* Unsupported relocation size requested. */ + bfd_reloc_notsupported, + + /* Unused */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. If this type is returned, the error_message argument + to bfd_perform_relocation will be set. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section */ + bfd_size_type address; + + /* addend for relocation value */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation */ + reloc_howto_type *howto; + +} arelent; +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +struct reloc_howto_struct +{ + /* The type field has mainly a documetary use - the back end can + do what it wants with it, though normally the back end's + external idea of what a reloc number is stored + in this field. For example, a PC relative word relocation + in a coff environment has the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. To get the number of bytes operated + on by a type of relocation, use bfd_get_reloc_size. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + + /* The textual name of the relocation type. */ + char *name; + + /* When performing a partial link, some formats must modify the + relocations rather than the data - this flag signals this.*/ + boolean partial_inplace; + + /* The src_mask selects which parts of the read in data + are to be used in the relocation sum. E.g., if this was an 8 bit + bit of data which we read and relocated, this would be + 0x000000ff. When we have relocs which have an addend, such as + sun4 extended relocs, the value in the offset part of a + relocating field is garbage so we never use it. In this case + the mask would be 0x00000000. */ + bfd_vma src_mask; + + /* The dst_mask selects which parts of the instruction are replaced + into the instruction. In most cases src_mask == dst_mask, + except in the above special case, where dst_mask would be + 0x000000ff, and src_mask would be 0x00000000. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs); this flag signals the fact.*/ + boolean pcrel_offset; + +}; +#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} +#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *)NULL) { \ + if (bfd_is_com_section (symbol->section)) { \ + relocation = 0; \ + } \ + else { \ + relocation = symbol->value; \ + } \ + } \ +} +int +bfd_get_reloc_size PARAMS ((reloc_howto_type *)); + +typedef struct relent_chain { + arelent relent; + struct relent_chain *next; +} arelent_chain; +bfd_reloc_status_type + +bfd_perform_relocation + PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + +bfd_reloc_status_type + +bfd_install_relocation + PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message)); + +enum bfd_reloc_code_real { + _dummy_first_bfd_reloc_code_real, + + +/* Basic absolute relocations of N bits. */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_26, + BFD_RELOC_16, + BFD_RELOC_14, + BFD_RELOC_8, + +/* PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, + BFD_RELOC_16_PCREL, + BFD_RELOC_12_PCREL, + BFD_RELOC_8_PCREL, + +/* For ELF. */ + BFD_RELOC_32_GOT_PCREL, + BFD_RELOC_16_GOT_PCREL, + BFD_RELOC_8_GOT_PCREL, + BFD_RELOC_32_GOTOFF, + BFD_RELOC_16_GOTOFF, + BFD_RELOC_LO16_GOTOFF, + BFD_RELOC_HI16_GOTOFF, + BFD_RELOC_HI16_S_GOTOFF, + BFD_RELOC_8_GOTOFF, + BFD_RELOC_32_PLT_PCREL, + BFD_RELOC_24_PLT_PCREL, + BFD_RELOC_16_PLT_PCREL, + BFD_RELOC_8_PLT_PCREL, + BFD_RELOC_32_PLTOFF, + BFD_RELOC_16_PLTOFF, + BFD_RELOC_LO16_PLTOFF, + BFD_RELOC_HI16_PLTOFF, + BFD_RELOC_HI16_S_PLTOFF, + BFD_RELOC_8_PLTOFF, + +/* Relocations used by 68K ELF. */ + BFD_RELOC_68K_GLOB_DAT, + BFD_RELOC_68K_JMP_SLOT, + BFD_RELOC_68K_RELATIVE, + +/* Linkage-table relative. */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_LO16_BASEREL, + BFD_RELOC_HI16_BASEREL, + BFD_RELOC_HI16_S_BASEREL, + BFD_RELOC_8_BASEREL, + BFD_RELOC_RVA, + +/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ + BFD_RELOC_8_FFnn, + +/* These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. */ + BFD_RELOC_32_PCREL_S2, + BFD_RELOC_16_PCREL_S2, + BFD_RELOC_23_PCREL_S2, + +/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. */ + BFD_RELOC_HI22, + BFD_RELOC_LO10, + +/* For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. */ + BFD_RELOC_GPREL16, + BFD_RELOC_GPREL32, + +/* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + +/* SPARC ELF relocations. There is probably some overlap with other +relocation types already defined. */ + BFD_RELOC_NONE, + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA32, + +/* I think these are specific to SPARC a.out (e.g., Sun 4). */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + +/* Some relocations we're using for SPARC V9 -- subject to change. */ +#define BFD_RELOC_SPARC_64 BFD_RELOC_64 + BFD_RELOC_SPARC_10, + BFD_RELOC_SPARC_11, + BFD_RELOC_SPARC_OLO10, + BFD_RELOC_SPARC_HH22, + BFD_RELOC_SPARC_HM10, + BFD_RELOC_SPARC_LM22, + BFD_RELOC_SPARC_PC_HH22, + BFD_RELOC_SPARC_PC_HM10, + BFD_RELOC_SPARC_PC_LM22, + BFD_RELOC_SPARC_WDISP16, + BFD_RELOC_SPARC_WDISP19, + BFD_RELOC_SPARC_GLOB_JMP, + BFD_RELOC_SPARC_7, + BFD_RELOC_SPARC_6, + BFD_RELOC_SPARC_5, + +/* Alpha ECOFF relocations. Some of these treat the symbol or "addend" +in some special way. +For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when +writing; when reading, it will be the absolute section symbol. The +addend is the displacement in bytes of the "lda" instruction from +the "ldah" instruction (which is at the address of this reloc). */ + BFD_RELOC_ALPHA_GPDISP_HI16, + +/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as +with GPDISP_HI16 relocs. The addend is ignored when writing the +relocations out, and is filled in with the file's GP value on +reading, for convenience. */ + BFD_RELOC_ALPHA_GPDISP_LO16, + +/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; +the assembler turns it into a LDQ instruction to load the address of +the symbol, and then fills in a register in the real instruction. + +The LITERAL reloc, at the LDQ instruction, refers to the .lita +section symbol. The addend is ignored when writing, but is filled +in with the file's GP value on reading, for convenience, as with the +GPDISP_LO16 reloc. + +The LITUSE reloc, on the instruction using the loaded address, gives +information to the linker that it might be able to use to optimize +away some literal section references. The symbol is ignored (read +as the absolute section symbol), and the "addend" indicates the type +of instruction using the register: +1 - "memory" fmt insn +2 - byte-manipulation (byte offset reg) +3 - jsr (target of branch) + +The GNU linker currently doesn't do any of this optimizing. */ + BFD_RELOC_ALPHA_LITERAL, + BFD_RELOC_ALPHA_LITUSE, + +/* The HINT relocation indicates a value that should be filled into the +"hint" field of a jmp/jsr/ret instruction, for possible branch- +prediction logic which may be provided on some processors. */ + BFD_RELOC_ALPHA_HINT, + +/* Bits 27..2 of the relocation address shifted right 2 bits; +simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + +/* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + +/* High 16 bits of 32-bit value but the low 16 bits will be sign +extended and added to form the final result. If the low 16 +bits form a negative number, we need to add one to the high value +to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + +/* Low 16 bits. */ + BFD_RELOC_LO16, + +/* Like BFD_RELOC_HI16_S, but PC relative. */ + BFD_RELOC_PCREL_HI16_S, + +/* Like BFD_RELOC_LO16, but PC relative. */ + BFD_RELOC_PCREL_LO16, + +/* Relocation relative to the global pointer. */ +#define BFD_RELOC_MIPS_GPREL BFD_RELOC_GPREL16 + +/* Relocation against a MIPS literal section. */ + BFD_RELOC_MIPS_LITERAL, + +/* MIPS ELF relocations. */ + BFD_RELOC_MIPS_GOT16, + BFD_RELOC_MIPS_CALL16, +#define BFD_RELOC_MIPS_GPREL32 BFD_RELOC_GPREL32 + BFD_RELOC_MIPS_GOT_HI16, + BFD_RELOC_MIPS_GOT_LO16, + BFD_RELOC_MIPS_CALL_HI16, + BFD_RELOC_MIPS_CALL_LO16, + +/* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + +/* ns32k relocations */ + BFD_RELOC_NS32K_IMM_8, + BFD_RELOC_NS32K_IMM_16, + BFD_RELOC_NS32K_IMM_32, + BFD_RELOC_NS32K_IMM_8_PCREL, + BFD_RELOC_NS32K_IMM_16_PCREL, + BFD_RELOC_NS32K_IMM_32_PCREL, + BFD_RELOC_NS32K_DISP_8, + BFD_RELOC_NS32K_DISP_16, + BFD_RELOC_NS32K_DISP_32, + BFD_RELOC_NS32K_DISP_8_PCREL, + BFD_RELOC_NS32K_DISP_16_PCREL, + BFD_RELOC_NS32K_DISP_32_PCREL, + +/* Power(rs6000) and PowerPC relocations. */ + BFD_RELOC_PPC_B26, + BFD_RELOC_PPC_BA26, + BFD_RELOC_PPC_TOC16, + BFD_RELOC_PPC_B16, + BFD_RELOC_PPC_B16_BRTAKEN, + BFD_RELOC_PPC_B16_BRNTAKEN, + BFD_RELOC_PPC_BA16, + BFD_RELOC_PPC_BA16_BRTAKEN, + BFD_RELOC_PPC_BA16_BRNTAKEN, + BFD_RELOC_PPC_COPY, + BFD_RELOC_PPC_GLOB_DAT, + BFD_RELOC_PPC_JMP_SLOT, + BFD_RELOC_PPC_RELATIVE, + BFD_RELOC_PPC_LOCAL24PC, + BFD_RELOC_PPC_EMB_NADDR32, + BFD_RELOC_PPC_EMB_NADDR16, + BFD_RELOC_PPC_EMB_NADDR16_LO, + BFD_RELOC_PPC_EMB_NADDR16_HI, + BFD_RELOC_PPC_EMB_NADDR16_HA, + BFD_RELOC_PPC_EMB_SDAI16, + BFD_RELOC_PPC_EMB_SDA2I16, + BFD_RELOC_PPC_EMB_SDA2REL, + BFD_RELOC_PPC_EMB_SDA21, + BFD_RELOC_PPC_EMB_MRKREF, + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, + +/* The type of reloc used to build a contructor table - at the moment +probably a 32 bit wide absolute relocation, but the target can choose. +It generally does map to one of the other relocation types. */ + BFD_RELOC_CTOR, + +/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. */ + BFD_RELOC_ARM_PCREL_BRANCH, + +/* These relocs are only used within the ARM assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_ARM_IMMEDIATE, + BFD_RELOC_ARM_OFFSET_IMM, + BFD_RELOC_ARM_SHIFT_IMM, + BFD_RELOC_ARM_SWI, + BFD_RELOC_ARM_MULTI, + BFD_RELOC_ARM_CP_OFF_IMM, + BFD_RELOC_ARM_ADR_IMM, + BFD_RELOC_ARM_LDR_IMM, + BFD_RELOC_ARM_LITERAL, + BFD_RELOC_ARM_IN_POOL, + BFD_RELOC_UNUSED }; +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +reloc_howto_type * + +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +const char * +bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code)); + + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + + struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied; the + application may not alter it. */ + CONST char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol: */ + +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <> in <>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* no real difference */ + + /* A normal C symbol would be one of: + <>, <>, <> or + <> */ + + /* The symbol is a debugging record. The value has an arbitary + meaning. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <> symbol + which is also <> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ + +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. The name is a + warning. The name of the next symbol is the one to warn about; + if a reference is made to a symbol with the same name as the next + symbol, a warning is issued by the linker. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. This symbol is an indirect + pointer to the symbol with the same name as the next symbol. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + /* Symbol is from dynamic linking information. */ +#define BSF_DYNAMIC 0x8000 + + /* The symbol denotes a data object. Used in ELF, and perhaps + others someday. */ +#define BSF_OBJECT 0x10000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols. */ + struct sec *section; + + /* Back end special data. */ + union + { + PTR p; + bfd_vma i; + } udata; + +} asymbol; +#define bfd_get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) +boolean +bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym)); + +#define bfd_is_local_label(abfd, sym) \ + BFD_SEND (abfd, _bfd_is_local_label,(abfd, sym)) +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) +boolean +bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count)); + +void +bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +boolean +bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); + +#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ + BFD_SEND (ibfd, _bfd_copy_private_symbol_data, \ + (ibfd, isymbol, obfd, osymbol)) +struct _bfd +{ + /* The filename the application opened the BFD with. */ + CONST char *filename; + + /* A pointer to the target jump table. */ + const struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<>', IOSTREAM has been declared as a "char + *", and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. However, if the + BFD_IN_MEMORY flag is set, then iostream is actually a pointer + to a bfd_in_memory struct. */ + PTR iostream; + + /* Is the file descriptor being cached? That is, can it be closed as + needed, and re-opened when accessed later? */ + + boolean cacheable; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select which matching algorithm + to use to choose the back end. */ + + boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs */ + + struct _bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here: */ + + file_ptr where; + + /* and here: (``once'' means at least once) */ + + boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time: */ + + boolean mtime_set; + + /* File modified time, if mtime_set is true: */ + + long mtime; + + /* Reserved for an unimplemented file locking extension.*/ + + int ifd; + + /* The format which belongs to the BFD. (object, core, etc.) */ + + bfd_format format; + + /* The direction the BFD was opened with*/ + + enum bfd_direction {no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3} direction; + + /* Format_specific flags*/ + + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + + file_ptr origin; + + /* Remember when output has begun, to stop strange things + from happening. */ + boolean output_has_begun; + + /* Pointer to linked list of sections*/ + struct sec *sections; + + /* The number of sections */ + unsigned int section_count; + + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; + + /* Used for input and output*/ + unsigned int symcount; + + /* Symbol table for output BFD (with symcount entries) */ + struct symbol_cache_entry **outsymbols; + + /* Pointer to structure which contains architecture information*/ + const struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives:*/ + PTR arelt_data; + struct _bfd *my_archive; /* The containing archive BFD. */ + struct _bfd *next; /* The next BFD in the archive. */ + struct _bfd *archive_head; /* The first BFD in the archive. */ + boolean has_armap; + + /* A chain of BFD structures involved in a link. */ + struct _bfd *link_next; + + /* A field used by _bfd_generic_link_add_archive_symbols. This will + be used only for archive elements. */ + int archive_pass; + + /* Used by the back end to hold private data. */ + + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct pe_tdata *pe_obj_data; + struct xcoff_tdata *xcoff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct ihex_data_struct *ihex_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct sun_core_struct *sun_core_data; + struct trad_core_struct *trad_core_data; + struct som_data_struct *som_data; + struct hpux_core_struct *hpux_core_data; + struct hppabsd_core_struct *hppabsd_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + struct cisco_core_struct *cisco_core_data; + struct versados_data_struct *versados_data; + struct netbsd_core_struct *netbsd_core_data; + PTR any; + } tdata; + + /* Used by the application to hold private data*/ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes */ + struct obstack memory; +}; + +typedef enum bfd_error +{ + bfd_error_no_error = 0, + bfd_error_system_call, + bfd_error_invalid_target, + bfd_error_wrong_format, + bfd_error_invalid_operation, + bfd_error_no_memory, + bfd_error_no_symbols, + bfd_error_no_armap, + bfd_error_no_more_archived_files, + bfd_error_malformed_archive, + bfd_error_file_not_recognized, + bfd_error_file_ambiguously_recognized, + bfd_error_no_contents, + bfd_error_nonrepresentable_section, + bfd_error_no_debug_section, + bfd_error_bad_value, + bfd_error_file_truncated, + bfd_error_file_too_big, + bfd_error_invalid_error_code +} bfd_error_type; + +bfd_error_type +bfd_get_error PARAMS ((void)); + +void +bfd_set_error PARAMS ((bfd_error_type error_tag)); + +CONST char * +bfd_errmsg PARAMS ((bfd_error_type error_tag)); + +void +bfd_perror PARAMS ((CONST char *message)); + +typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); + +bfd_error_handler_type +bfd_set_error_handler PARAMS ((bfd_error_handler_type)); + +void +bfd_set_error_program_name PARAMS ((const char *)); + +long +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +long +bfd_canonicalize_reloc + PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +void +bfd_set_reloc + PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count) + + ); + +boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +boolean +bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma)); + +long +bfd_get_mtime PARAMS ((bfd *abfd)); + +long +bfd_get_size PARAMS ((bfd *abfd)); + +int +bfd_get_gp_size PARAMS ((bfd *abfd)); + +void +bfd_set_gp_size PARAMS ((bfd *abfd, int i)); + +bfd_vma +bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base)); + +boolean +bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_copy_private_bfd_data(ibfd, obfd) \ + BFD_SEND (ibfd, _bfd_copy_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_merge_private_bfd_data(ibfd, obfd) \ + BFD_SEND (ibfd, _bfd_merge_private_bfd_data, \ + (ibfd, obfd)) +boolean +bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); + +#define bfd_set_private_flags(abfd, flags) \ + BFD_SEND (abfd, _bfd_set_private_flags, \ + (abfd, flags)) +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ + BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) + + /* Do these three do anything useful at all, for any back end? */ +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_update_armap_timestamp(abfd) \ + BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_relax_section(abfd, section, link_info, again) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) + +#define bfd_link_hash_table_create(abfd) \ + BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) + +#define bfd_link_add_symbols(abfd, info) \ + BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) + +#define bfd_final_link(abfd, info) \ + BFD_SEND (abfd, _bfd_final_link, (abfd, info)) + +#define bfd_free_cached_info(abfd) \ + BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) + +#define bfd_get_dynamic_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) + +#define bfd_print_private_bfd_data(abfd, file)\ + BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) + +#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) + +#define bfd_get_dynamic_reloc_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) + +#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) + +extern bfd_byte *bfd_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, + boolean, asymbol **)); + +symindex +bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym)); + +boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +CONST char * +bfd_core_file_failing_command PARAMS ((bfd *abfd)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *abfd)); + +boolean +core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND +#define BFD_SEND(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + ((*((bfd)->xvec->message)) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND_FMT +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + + /* Forward declaration. */ +typedef struct bfd_link_info _bfd_link_info; + +typedef struct bfd_target +{ + char *name; + enum bfd_flavour flavour; + enum bfd_endian byteorder; + enum bfd_endian header_byteorder; + flagword object_flags; + flagword section_flags; + char symbol_leading_char; + char ar_pad_char; + unsigned short ar_max_namelen; + bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME)\ +CAT(NAME,_close_and_cleanup),\ +CAT(NAME,_bfd_free_cached_info),\ +CAT(NAME,_new_section_hook),\ +CAT(NAME,_get_section_contents),\ +CAT(NAME,_get_section_contents_in_window) + + /* Called when the BFD is being closed to do any necessary cleanup. */ + boolean (*_close_and_cleanup) PARAMS ((bfd *)); + /* Ask the BFD to free all cached information. */ + boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); + /* Called when a new section is created. */ + boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + /* Read the contents of a section. */ + boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents_in_window) + PARAMS ((bfd *, sec_ptr, bfd_window *, + file_ptr, bfd_size_type)); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME)\ +CAT(NAME,_bfd_copy_private_bfd_data),\ +CAT(NAME,_bfd_merge_private_bfd_data),\ +CAT(NAME,_bfd_copy_private_section_data),\ +CAT(NAME,_bfd_copy_private_symbol_data),\ +CAT(NAME,_bfd_set_private_flags),\ +CAT(NAME,_bfd_print_private_bfd_data)\ + /* Called to copy BFD general private data from one object file + to another. */ + boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to merge BFD general private data from one object file + to a common output file when linking. */ + boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to copy BFD private section data from one object file + to another. */ + boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr, + bfd *, sec_ptr)); + /* Called to copy BFD private symbol data from one symbol + to another. */ + boolean (*_bfd_copy_private_symbol_data) PARAMS ((bfd *, asymbol *, + bfd *, asymbol *)); + /* Called to set private backend flags */ + boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); + + /* Called to print private BFD data */ + boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME)\ +CAT(NAME,_core_file_failing_command),\ +CAT(NAME,_core_file_failing_signal),\ +CAT(NAME,_core_file_matches_executable_p) + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME)\ +CAT(NAME,_slurp_armap),\ +CAT(NAME,_slurp_extended_name_table),\ +CAT(NAME,_construct_extended_name_table),\ +CAT(NAME,_truncate_arname),\ +CAT(NAME,_write_armap),\ +CAT(NAME,_read_ar_hdr),\ +CAT(NAME,_openr_next_archived_file),\ +CAT(NAME,_get_elt_at_index),\ +CAT(NAME,_generic_stat_arch_elt),\ +CAT(NAME,_update_armap_timestamp) + boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + boolean (*_bfd_construct_extended_name_table) + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); + boolean (*write_armap) PARAMS ((bfd *arch, + unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); + PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); + bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) + bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME)\ +CAT(NAME,_get_symtab_upper_bound),\ +CAT(NAME,_get_symtab),\ +CAT(NAME,_make_empty_symbol),\ +CAT(NAME,_print_symbol),\ +CAT(NAME,_get_symbol_info),\ +CAT(NAME,_bfd_is_local_label),\ +CAT(NAME,_get_lineno),\ +CAT(NAME,_find_nearest_line),\ +CAT(NAME,_bfd_make_debug_symbol),\ +CAT(NAME,_read_minisymbols),\ +CAT(NAME,_minisymbol_to_symbol) + long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); + long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, + struct symbol_cache_entry *, + bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) PARAMS ((bfd *, + struct symbol_cache_entry *, + symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + boolean (*_bfd_is_local_label) PARAMS ((bfd *, asymbol *)); + + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, + struct sec *section, struct symbol_cache_entry **symbols, + bfd_vma offset, CONST char **file, CONST char **func, + unsigned int *line)); + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) PARAMS (( + bfd *abfd, + void *ptr, + unsigned long size)); +#define bfd_read_minisymbols(b, d, m, s) \ + BFD_SEND (b, _read_minisymbols, (b, d, m, s)) + long (*_read_minisymbols) PARAMS ((bfd *, boolean, PTR *, + unsigned int *)); +#define bfd_minisymbol_to_symbol(b, d, m, f) \ + BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) + asymbol *(*_minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR, + asymbol *)); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME)\ +CAT(NAME,_get_reloc_upper_bound),\ +CAT(NAME,_canonicalize_reloc),\ +CAT(NAME,_bfd_reloc_type_lookup) + long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, + struct symbol_cache_entry **)); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME)\ +CAT(NAME,_set_arch_mach),\ +CAT(NAME,_set_section_contents) + boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME)\ +CAT(NAME,_sizeof_headers),\ +CAT(NAME,_bfd_get_relocated_section_contents),\ +CAT(NAME,_bfd_relax_section),\ +CAT(NAME,_bfd_link_hash_table_create),\ +CAT(NAME,_bfd_link_add_symbols),\ +CAT(NAME,_bfd_final_link),\ +CAT(NAME,_bfd_link_split_section) + int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); + bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, + struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *data, boolean relocateable, + struct symbol_cache_entry **)); + + boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, + struct bfd_link_info *, boolean *again)); + + /* Create a hash table for the linker. Different backends store + different information in this table. */ + struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *)); + + /* Add symbols from this object file into the hash table. */ + boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Should this section be split up into smaller pieces during linking. */ + boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME)\ +CAT(NAME,_get_dynamic_symtab_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_symtab),\ +CAT(NAME,_get_dynamic_reloc_upper_bound),\ +CAT(NAME,_canonicalize_dynamic_reloc) + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + PARAMS ((bfd *, struct symbol_cache_entry **)); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); + + PTR backend_data; +} bfd_target; +const bfd_target * +bfd_find_target PARAMS ((CONST char *target_name, bfd *abfd)); + +const char ** +bfd_target_list PARAMS ((void)); + +boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +boolean +bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching)); + +boolean +bfd_set_format PARAMS ((bfd *abfd, bfd_format format)); + +CONST char * +bfd_format_string PARAMS ((bfd_format format)); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/gdb/bfd/bfd.c b/contrib/gdb/bfd/bfd.c new file mode 100644 index 000000000000..10ec67efaa6f --- /dev/null +++ b/contrib/gdb/bfd/bfd.c @@ -0,0 +1,1144 @@ +/* Generic BFD library interface and support routines. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + <> + + A BFD has type <>; objects of this type are the + cornerstone of any application using BFD. Using BFD + consists of making references though the BFD and to data in the BFD. + + Here is the structure that defines the type <>. It + contains the major data about the file and pointers + to the rest of the data. + +CODE_FRAGMENT +. +.struct _bfd +.{ +. {* The filename the application opened the BFD with. *} +. CONST char *filename; +. +. {* A pointer to the target jump table. *} +. const struct bfd_target *xvec; +. +. {* To avoid dragging too many header files into every file that +. includes `<>', IOSTREAM has been declared as a "char +. *", and MTIME as a "long". Their correct types, to which they +. are cast when used, are "FILE *" and "time_t". The iostream +. is the result of an fopen on the filename. However, if the +. BFD_IN_MEMORY flag is set, then iostream is actually a pointer +. to a bfd_in_memory struct. *} +. PTR iostream; +. +. {* Is the file descriptor being cached? That is, can it be closed as +. needed, and re-opened when accessed later? *} +. +. boolean cacheable; +. +. {* Marks whether there was a default target specified when the +. BFD was opened. This is used to select which matching algorithm +. to use to choose the back end. *} +. +. boolean target_defaulted; +. +. {* The caching routines use these to maintain a +. least-recently-used list of BFDs *} +. +. struct _bfd *lru_prev, *lru_next; +. +. {* When a file is closed by the caching routines, BFD retains +. state information on the file here: *} +. +. file_ptr where; +. +. {* and here: (``once'' means at least once) *} +. +. boolean opened_once; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time: *} +. +. boolean mtime_set; +. +. {* File modified time, if mtime_set is true: *} +. +. long mtime; +. +. {* Reserved for an unimplemented file locking extension.*} +. +. int ifd; +. +. {* The format which belongs to the BFD. (object, core, etc.) *} +. +. bfd_format format; +. +. {* The direction the BFD was opened with*} +. +. enum bfd_direction {no_direction = 0, +. read_direction = 1, +. write_direction = 2, +. both_direction = 3} direction; +. +. {* Format_specific flags*} +. +. flagword flags; +. +. {* Currently my_archive is tested before adding origin to +. anything. I believe that this can become always an add of +. origin, with origin set to 0 for non archive files. *} +. +. file_ptr origin; +. +. {* Remember when output has begun, to stop strange things +. from happening. *} +. boolean output_has_begun; +. +. {* Pointer to linked list of sections*} +. struct sec *sections; +. +. {* The number of sections *} +. unsigned int section_count; +. +. {* Stuff only useful for object files: +. The start address. *} +. bfd_vma start_address; +. +. {* Used for input and output*} +. unsigned int symcount; +. +. {* Symbol table for output BFD (with symcount entries) *} +. struct symbol_cache_entry **outsymbols; +. +. {* Pointer to structure which contains architecture information*} +. const struct bfd_arch_info *arch_info; +. +. {* Stuff only useful for archives:*} +. PTR arelt_data; +. struct _bfd *my_archive; {* The containing archive BFD. *} +. struct _bfd *next; {* The next BFD in the archive. *} +. struct _bfd *archive_head; {* The first BFD in the archive. *} +. boolean has_armap; +. +. {* A chain of BFD structures involved in a link. *} +. struct _bfd *link_next; +. +. {* A field used by _bfd_generic_link_add_archive_symbols. This will +. be used only for archive elements. *} +. int archive_pass; +. +. {* Used by the back end to hold private data. *} +. +. union +. { +. struct aout_data_struct *aout_data; +. struct artdata *aout_ar_data; +. struct _oasys_data *oasys_obj_data; +. struct _oasys_ar_data *oasys_ar_data; +. struct coff_tdata *coff_obj_data; +. struct pe_tdata *pe_obj_data; +. struct xcoff_tdata *xcoff_obj_data; +. struct ecoff_tdata *ecoff_obj_data; +. struct ieee_data_struct *ieee_data; +. struct ieee_ar_data_struct *ieee_ar_data; +. struct srec_data_struct *srec_data; +. struct ihex_data_struct *ihex_data; +. struct tekhex_data_struct *tekhex_data; +. struct elf_obj_tdata *elf_obj_data; +. struct nlm_obj_tdata *nlm_obj_data; +. struct bout_data_struct *bout_data; +. struct sun_core_struct *sun_core_data; +. struct trad_core_struct *trad_core_data; +. struct som_data_struct *som_data; +. struct hpux_core_struct *hpux_core_data; +. struct hppabsd_core_struct *hppabsd_core_data; +. struct sgi_core_struct *sgi_core_data; +. struct lynx_core_struct *lynx_core_data; +. struct osf_core_struct *osf_core_data; +. struct cisco_core_struct *cisco_core_data; +. struct versados_data_struct *versados_data; +. struct netbsd_core_struct *netbsd_core_data; +. PTR any; +. } tdata; +. +. {* Used by the application to hold private data*} +. PTR usrdata; +. +. {* Where all the allocated stuff under this BFD goes *} +. struct obstack memory; +.}; +. +*/ + +#include "bfd.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "libcoff.h" +#include "libecoff.h" +#undef obj_symbols +#include "elf-bfd.h" + +#include + +/* provide storage for subsystem, stack and heap data which may have been + passed in on the command line. Ld puts this data into a bfd_link_info + struct which ultimately gets passed in to the bfd. When it arrives, copy + it to the following struct so that the data will be available in coffcode.h + where it is needed. The typedef's used are defined in bfd.h */ + + + +/* +SECTION + Error reporting + + Most BFD functions return nonzero on success (check their + individual documentation for precise semantics). On an error, + they call <> to set an error condition that callers + can check by calling <>. + If that returns <>, then check + <>. + + The easiest way to report a BFD error to the user is to + use <>. + +SUBSECTION + Type <> + + The values returned by <> are defined by the + enumerated type <>. + +CODE_FRAGMENT +. +.typedef enum bfd_error +.{ +. bfd_error_no_error = 0, +. bfd_error_system_call, +. bfd_error_invalid_target, +. bfd_error_wrong_format, +. bfd_error_invalid_operation, +. bfd_error_no_memory, +. bfd_error_no_symbols, +. bfd_error_no_armap, +. bfd_error_no_more_archived_files, +. bfd_error_malformed_archive, +. bfd_error_file_not_recognized, +. bfd_error_file_ambiguously_recognized, +. bfd_error_no_contents, +. bfd_error_nonrepresentable_section, +. bfd_error_no_debug_section, +. bfd_error_bad_value, +. bfd_error_file_truncated, +. bfd_error_file_too_big, +. bfd_error_invalid_error_code +.} bfd_error_type; +. +*/ + +#undef strerror +extern char *strerror(); + +static bfd_error_type bfd_error = bfd_error_no_error; + +CONST char *CONST bfd_errmsgs[] = { + "No error", + "System call error", + "Invalid bfd target", + "File in wrong format", + "Invalid operation", + "Memory exhausted", + "No symbols", + "Archive has no index; run ranlib to add one", + "No more archived files", + "Malformed archive", + "File format not recognized", + "File format is ambiguous", + "Section has no contents", + "Nonrepresentable section on output", + "Symbol needs debug section which does not exist", + "Bad value", + "File truncated", + "File too big", + "#" + }; + +/* +FUNCTION + bfd_get_error + +SYNOPSIS + bfd_error_type bfd_get_error (void); + +DESCRIPTION + Return the current BFD error condition. +*/ + +bfd_error_type +bfd_get_error () +{ + return bfd_error; +} + +/* +FUNCTION + bfd_set_error + +SYNOPSIS + void bfd_set_error (bfd_error_type error_tag); + +DESCRIPTION + Set the BFD error condition to be @var{error_tag}. +*/ + +void +bfd_set_error (error_tag) + bfd_error_type error_tag; +{ + bfd_error = error_tag; +} + +/* +FUNCTION + bfd_errmsg + +SYNOPSIS + CONST char *bfd_errmsg (bfd_error_type error_tag); + +DESCRIPTION + Return a string describing the error @var{error_tag}, or + the system error if @var{error_tag} is <>. +*/ + +CONST char * +bfd_errmsg (error_tag) + bfd_error_type error_tag; +{ +#ifndef errno + extern int errno; +#endif + if (error_tag == bfd_error_system_call) + { + const char *errmsg; + + errmsg = strerror (errno); + if (errmsg == NULL) + { + static char buf[32]; + + sprintf (buf, "Error %d", errno); + errmsg = buf; + } + return errmsg; + } + + if ((((int)error_tag <(int) bfd_error_no_error) || + ((int)error_tag > (int)bfd_error_invalid_error_code))) + error_tag = bfd_error_invalid_error_code;/* sanity check */ + + return bfd_errmsgs [(int)error_tag]; +} + +/* +FUNCTION + bfd_perror + +SYNOPSIS + void bfd_perror (CONST char *message); + +DESCRIPTION + Print to the standard error stream a string describing the + last BFD error that occurred, or the last system error if + the last BFD error was a system call failure. If @var{message} + is non-NULL and non-empty, the error string printed is preceded + by @var{message}, a colon, and a space. It is followed by a newline. +*/ + +void +bfd_perror (message) + CONST char *message; +{ + if (bfd_get_error () == bfd_error_system_call) + perror((char *)message); /* must be system error then... */ + else { + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); + else + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); + } +} + +/* +SUBSECTION + BFD error handler + + Some BFD functions want to print messages describing the + problem. They call a BFD error handler function. This + function may be overriden by the program. + + The BFD error handler acts like printf. + +CODE_FRAGMENT +. +.typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); +. +*/ + +/* The program name used when printing BFD error messages. */ + +static const char *_bfd_error_program_name; + +/* This is the default routine to handle BFD error messages. */ + +#ifdef ANSI_PROTOTYPES + +static void _bfd_default_error_handler PARAMS ((const char *s, ...)); + +static void +_bfd_default_error_handler (const char *s, ...) +{ + va_list p; + + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); + + va_start (p, s); + + vfprintf (stderr, s, p); + + va_end (p); + + fprintf (stderr, "\n"); +} + +#else /* ! defined (ANSI_PROTOTYPES) */ + +static void _bfd_default_error_handler (); + +static void +_bfd_default_error_handler (va_alist) + va_dcl +{ + va_list p; + const char *s; + + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); + + va_start (p); + + s = va_arg (p, const char *); + vfprintf (stderr, s, p); + + va_end (p); + + fprintf (stderr, "\n"); +} + +#endif /* ! defined (ANSI_PROTOTYPES) */ + +/* This is a function pointer to the routine which should handle BFD + error messages. It is called when a BFD routine encounters an + error for which it wants to print a message. Going through a + function pointer permits a program linked against BFD to intercept + the messages and deal with them itself. */ + +bfd_error_handler_type _bfd_error_handler = _bfd_default_error_handler; + +/* +FUNCTION + bfd_set_error_handler + +SYNOPSIS + bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); + +DESCRIPTION + Set the BFD error handler function. Returns the previous + function. +*/ + +bfd_error_handler_type +bfd_set_error_handler (pnew) + bfd_error_handler_type pnew; +{ + bfd_error_handler_type pold; + + pold = _bfd_error_handler; + _bfd_error_handler = pnew; + return pold; +} + +/* +FUNCTION + bfd_set_error_program_name + +SYNOPSIS + void bfd_set_error_program_name (const char *); + +DESCRIPTION + Set the program name to use when printing a BFD error. This + is printed before the error message followed by a colon and + space. The string must not be changed after it is passed to + this function. +*/ + +void +bfd_set_error_program_name (name) + const char *name; +{ + _bfd_error_program_name = name; +} + +/* +SECTION + Symbols +*/ + +/* +FUNCTION + bfd_get_reloc_upper_bound + +SYNOPSIS + long bfd_get_reloc_upper_bound(bfd *abfd, asection *sect); + +DESCRIPTION + Return the number of bytes required to store the + relocation information associated with section @var{sect} + attached to bfd @var{abfd}. If an error occurs, return -1. + +*/ + + +long +bfd_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); +} + +/* +FUNCTION + bfd_canonicalize_reloc + +SYNOPSIS + long bfd_canonicalize_reloc + (bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms); + +DESCRIPTION + Call the back end associated with the open BFD + @var{abfd} and translate the external form of the relocation + information attached to @var{sec} into the internal canonical + form. Place the table into memory at @var{loc}, which has + been preallocated, usually by a call to + <>. Returns the number of relocs, or + -1 on error. + + The @var{syms} table is also needed for horrible internal magic + reasons. + + +*/ +long +bfd_canonicalize_reloc (abfd, asect, location, symbols) + bfd *abfd; + sec_ptr asect; + arelent **location; + asymbol **symbols; +{ + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + return BFD_SEND (abfd, _bfd_canonicalize_reloc, + (abfd, asect, location, symbols)); +} + +/* +FUNCTION + bfd_set_reloc + +SYNOPSIS + void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count) + +DESCRIPTION + Set the relocation pointer and count within + section @var{sec} to the values @var{rel} and @var{count}. + The argument @var{abfd} is ignored. + +*/ +/*ARGSUSED*/ +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd; + sec_ptr asect; + arelent **location; + unsigned int count; +{ + asect->orelocation = location; + asect->reloc_count = count; +} + +/* +FUNCTION + bfd_set_file_flags + +SYNOPSIS + boolean bfd_set_file_flags(bfd *abfd, flagword flags); + +DESCRIPTION + Set the flag word in the BFD @var{abfd} to the value @var{flags}. + + Possible errors are: + o <> - The target bfd was not of object format. + o <> - The target bfd was open for reading. + o <> - + The flag word contained a bit which was not applicable to the + type of file. E.g., an attempt was made to set the <> bit + on a BFD format which does not support demand paging. + +*/ + +boolean +bfd_set_file_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + if (abfd->format != bfd_object) { + bfd_set_error (bfd_error_wrong_format); + return false; + } + + if (bfd_read_p (abfd)) { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + bfd_get_file_flags (abfd) = flags; + if ((flags & bfd_applicable_file_flags (abfd)) != flags) { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + +return true; +} + +void +bfd_assert (file, line) + const char *file; + int line; +{ + (*_bfd_error_handler) ("bfd assertion fail %s:%d", file, line); +} + + +/* +FUNCTION + bfd_set_start_address + +SYNOPSIS + boolean bfd_set_start_address(bfd *abfd, bfd_vma vma); + +DESCRIPTION + Make @var{vma} the entry point of output BFD @var{abfd}. + +RETURNS + Returns <> on success, <> otherwise. +*/ + +boolean +bfd_set_start_address(abfd, vma) +bfd *abfd; +bfd_vma vma; +{ + abfd->start_address = vma; + return true; +} + + +/* +FUNCTION + bfd_get_mtime + +SYNOPSIS + long bfd_get_mtime(bfd *abfd); + +DESCRIPTION + Return the file modification time (as read from the file system, or + from the archive header for archive members). + +*/ + +long +bfd_get_mtime (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ + return buf.st_mtime; +} + +/* +FUNCTION + bfd_get_size + +SYNOPSIS + long bfd_get_size(bfd *abfd); + +DESCRIPTION + Return the file size (as read from file system) for the file + associated with BFD @var{abfd}. + + The initial motivation for, and use of, this routine is not + so we can get the exact size of the object the BFD applies to, since + that might not be generally possible (archive members for example). + It would be ideal if someone could eventually modify + it so that such results were guaranteed. + + Instead, we want to ask questions like "is this NNN byte sized + object I'm about to try read from file offset YYY reasonable?" + As as example of where we might do this, some object formats + use string tables for which the first <> bytes of the + table contain the size of the table itself, including the size bytes. + If an application tries to read what it thinks is one of these + string tables, without some way to validate the size, and for + some reason the size is wrong (byte swapping error, wrong location + for the string table, etc.), the only clue is likely to be a read + error when it tries to read the table, or a "virtual memory + exhausted" error when it tries to allocate 15 bazillon bytes + of space for the 15 bazillon byte table it is about to read. + This function at least allows us to answer the quesion, "is the + size reasonable?". +*/ + +long +bfd_get_size (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return ((struct bfd_in_memory *) abfd->iostream)->size; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + return buf.st_size; +} + +/* +FUNCTION + bfd_get_gp_size + +SYNOPSIS + int bfd_get_gp_size(bfd *abfd); + +DESCRIPTION + Return the maximum size of objects to be optimized using the GP + register under MIPS ECOFF. This is typically set by the <<-G>> + argument to the compiler, assembler or linker. +*/ + +int +bfd_get_gp_size (abfd) + bfd *abfd; +{ + if (abfd->format == bfd_object) + { + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp_size; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp_size (abfd); + } + return 0; +} + +/* +FUNCTION + bfd_set_gp_size + +SYNOPSIS + void bfd_set_gp_size(bfd *abfd, int i); + +DESCRIPTION + Set the maximum size of objects to be optimized using the GP + register under ECOFF or MIPS ELF. This is typically set by + the <<-G>> argument to the compiler, assembler or linker. +*/ + +void +bfd_set_gp_size (abfd, i) + bfd *abfd; + int i; +{ + /* Don't try to set GP size on an archive or core file! */ + if (abfd->format != bfd_object) + return; + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp_size = i; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp_size (abfd) = i; +} + +/* Get the GP value. This is an internal function used by some of the + relocation special_function routines on targets which support a GP + register. */ + +bfd_vma +_bfd_get_gp_value (abfd) + bfd *abfd; +{ + if (abfd->format == bfd_object) + { + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp (abfd); + } + return 0; +} + +/* Set the GP value. */ + +void +_bfd_set_gp_value (abfd, v) + bfd *abfd; + bfd_vma v; +{ + if (abfd->format != bfd_object) + return; + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp = v; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp (abfd) = v; +} + +/* +FUNCTION + bfd_scan_vma + +SYNOPSIS + bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base); + +DESCRIPTION + Convert, like <>, a numerical expression + @var{string} into a <> integer, and return that integer. + (Though without as many bells and whistles as <>.) + The expression is assumed to be unsigned (i.e., positive). + If given a @var{base}, it is used as the base for conversion. + A base of 0 causes the function to interpret the string + in hex if a leading "0x" or "0X" is found, otherwise + in octal if a leading zero is found, otherwise in decimal. + + Overflow is not detected. +*/ + +bfd_vma +bfd_scan_vma (string, end, base) + CONST char *string; + CONST char **end; + int base; +{ + bfd_vma value; + int digit; + + /* Let the host do it if possible. */ + if (sizeof(bfd_vma) <= sizeof(unsigned long)) + return (bfd_vma) strtoul (string, (char **) end, base); + + /* A negative base makes no sense, and we only need to go as high as hex. */ + if ((base < 0) || (base > 16)) + return (bfd_vma) 0; + + if (base == 0) + { + if (string[0] == '0') + { + if ((string[1] == 'x') || (string[1] == 'X')) + base = 16; + /* XXX should we also allow "0b" or "0B" to set base to 2? */ + else + base = 8; + } + else + base = 10; + } + if ((base == 16) && + (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + string += 2; + /* XXX should we also skip over "0b" or "0B" if base is 2? */ + +/* Speed could be improved with a table like hex_value[] in gas. */ +#define HEX_VALUE(c) \ + (isxdigit(c) ? \ + (isdigit(c) ? \ + (c - '0') : \ + (10 + c - (islower(c) ? 'a' : 'A'))) : \ + 42) + + for (value = 0; (digit = HEX_VALUE(*string)) < base; string++) + { + value = value * base + digit; + } + + if (end) + *end = string; + + return value; +} + +/* +FUNCTION + bfd_copy_private_bfd_data + +SYNOPSIS + boolean bfd_copy_private_bfd_data(bfd *ibfd, bfd *obfd); + +DESCRIPTION + Copy private BFD information from the BFD @var{ibfd} to the + the BFD @var{obfd}. Return <> on success, <> on error. + Possible error returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_copy_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (ibfd, _bfd_copy_private_bfd_data, \ +. (ibfd, obfd)) + +*/ + +/* +FUNCTION + bfd_merge_private_bfd_data + +SYNOPSIS + boolean bfd_merge_private_bfd_data(bfd *ibfd, bfd *obfd); + +DESCRIPTION + Merge private BFD information from the BFD @var{ibfd} to the + the output file BFD @var{obfd} when linking. Return <> + on success, <> on error. Possible error returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_merge_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (ibfd, _bfd_merge_private_bfd_data, \ +. (ibfd, obfd)) + +*/ + +/* +FUNCTION + bfd_set_private_flags + +SYNOPSIS + boolean bfd_set_private_flags(bfd *abfd, flagword flags); + +DESCRIPTION + Set private BFD flag information in the BFD @var{abfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_set_private_flags(abfd, flags) \ +. BFD_SEND (abfd, _bfd_set_private_flags, \ +. (abfd, flags)) + +*/ + +/* +FUNCTION + stuff + +DESCRIPTION + Stuff which should be documented: + +.#define bfd_sizeof_headers(abfd, reloc) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +. +.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ +. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) +. +. {* Do these three do anything useful at all, for any back end? *} +.#define bfd_debug_info_start(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) +. +.#define bfd_debug_info_end(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) +. +.#define bfd_debug_info_accumulate(abfd, section) \ +. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) +. +. +.#define bfd_stat_arch_elt(abfd, stat) \ +. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) +. +.#define bfd_update_armap_timestamp(abfd) \ +. BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) +. +.#define bfd_set_arch_mach(abfd, arch, mach)\ +. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) +. +.#define bfd_relax_section(abfd, section, link_info, again) \ +. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) +. +.#define bfd_link_hash_table_create(abfd) \ +. BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) +. +.#define bfd_link_add_symbols(abfd, info) \ +. BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) +. +.#define bfd_final_link(abfd, info) \ +. BFD_SEND (abfd, _bfd_final_link, (abfd, info)) +. +.#define bfd_free_cached_info(abfd) \ +. BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) +. +.#define bfd_get_dynamic_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) +. +.#define bfd_print_private_bfd_data(abfd, file)\ +. BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) +. +.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) +. +.#define bfd_get_dynamic_reloc_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) +. +.#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) +. +.extern bfd_byte *bfd_get_relocated_section_contents +. PARAMS ((bfd *, struct bfd_link_info *, +. struct bfd_link_order *, bfd_byte *, +. boolean, asymbol **)); +. + +*/ + +bfd_byte * +bfd_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + bfd *abfd2; + bfd_byte *(*fn) PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, boolean, + asymbol **)); + + if (link_order->type == bfd_indirect_link_order) + { + abfd2 = link_order->u.indirect.section->owner; + if (abfd2 == 0) + abfd2 = abfd; + } + else + abfd2 = abfd; + fn = abfd2->xvec->_bfd_get_relocated_section_contents; + + return (*fn) (abfd, link_info, link_order, data, relocateable, symbols); +} + +/* Record information about an ELF program header. */ + +boolean +bfd_record_phdr (abfd, type, flags_valid, flags, at_valid, at, + includes_filehdr, includes_phdrs, count, secs) + bfd *abfd; + unsigned long type; + boolean flags_valid; + flagword flags; + boolean at_valid; + bfd_vma at; + boolean includes_filehdr; + boolean includes_phdrs; + unsigned int count; + asection **secs; +{ + struct elf_segment_map *m, **pm; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return true; + + m = ((struct elf_segment_map *) + bfd_alloc (abfd, + (sizeof (struct elf_segment_map) + + (count - 1) * sizeof (asection *)))); + if (m == NULL) + return false; + + m->next = NULL; + m->p_type = type; + m->p_flags = flags; + m->p_paddr = at; + m->p_flags_valid = flags_valid; + m->p_paddr_valid = at_valid; + m->includes_filehdr = includes_filehdr; + m->includes_phdrs = includes_phdrs; + m->count = count; + if (count > 0) + memcpy (m->sections, secs, count * sizeof (asection *)); + + for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + + return true; +} diff --git a/contrib/gdb/bfd/binary.c b/contrib/gdb/bfd/binary.c new file mode 100644 index 000000000000..a480e464e96b --- /dev/null +++ b/contrib/gdb/bfd/binary.c @@ -0,0 +1,348 @@ +/* BFD back-end for binary objects. + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support, + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is a BFD backend which may be used to write binary objects. + It may only be used for output, not input. The intention is that + this may be used as an output format for objcopy in order to + generate raw binary data. + + This is very simple. The only complication is that the real data + will start at some address X, and in some cases we will not want to + include X zeroes just to get to that point. Since the start + address is not meaningful for this object file format, we use it + instead to indicate the number of zeroes to skip at the start of + the file. objcopy cooperates by specially setting the start + address to zero by default. */ + +#include + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* Any bfd we create by reading a binary file has three symbols: + a start symbol, an end symbol, and an absolute length symbol. */ +#define BIN_SYMS 3 + +static boolean binary_mkobject PARAMS ((bfd *)); +static const bfd_target *binary_object_p PARAMS ((bfd *)); +static boolean binary_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static long binary_get_symtab_upper_bound PARAMS ((bfd *)); +static char *mangle_name PARAMS ((bfd *, char *)); +static long binary_get_symtab PARAMS ((bfd *, asymbol **)); +static asymbol *binary_make_empty_symbol PARAMS ((bfd *)); +static void binary_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); +static boolean binary_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static int binary_sizeof_headers PARAMS ((bfd *, boolean)); + +/* Create a binary object. Invoked via bfd_set_format. */ + +static boolean +binary_mkobject (abfd) + bfd *abfd; +{ + return true; +} + +/* Any file may be considered to be a binary file, provided the target + was not defaulted. That is, it must be explicitly specified as + being binary. */ + +static const bfd_target * +binary_object_p (abfd) + bfd *abfd; +{ + struct stat statbuf; + asection *sec; + + if (abfd->target_defaulted) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + abfd->symcount = BIN_SYMS; + + /* Find the file size. */ + if (bfd_stat (abfd, &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + /* One data section. */ + sec = bfd_make_section (abfd, ".data"); + if (sec == NULL) + return NULL; + sec->flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS; + sec->vma = 0; + sec->_raw_size = statbuf.st_size; + sec->filepos = 0; + + abfd->tdata.any = (PTR) sec; + + return abfd->xvec; +} + +#define binary_close_and_cleanup _bfd_generic_close_and_cleanup +#define binary_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define binary_new_section_hook _bfd_generic_new_section_hook + +/* Get contents of the only section. */ + +static boolean +binary_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (bfd_seek (abfd, offset, SEEK_SET) != 0 + || bfd_read (location, 1, count, abfd) != count) + return false; + return true; +} + +/* Return the amount of memory needed to read the symbol table. */ + +static long +binary_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (BIN_SYMS + 1) * sizeof (asymbol *); +} + +/* Create a symbol name based on the bfd's filename. */ + +static char * +mangle_name (abfd, suffix) + bfd *abfd; + char *suffix; +{ + int size; + char *buf; + char *p; + + size = (strlen (bfd_get_filename (abfd)) + + strlen (suffix) + + sizeof "_binary__"); + + buf = (char *) bfd_alloc (abfd, size); + if (buf == NULL) + return ""; + + sprintf (buf, "_binary_%s_%s", bfd_get_filename (abfd), suffix); + + /* Change any non-alphanumeric characters to underscores. */ + for (p = buf; *p; p++) + if (! isalnum (*p)) + *p = '_'; + + return buf; +} + +/* Return the symbol table. */ + +static long +binary_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + asection *sec = (asection *) abfd->tdata.any; + asymbol *syms; + unsigned int i; + + syms = (asymbol *) bfd_alloc (abfd, BIN_SYMS * sizeof (asymbol)); + if (syms == NULL) + return false; + + /* Start symbol. */ + syms[0].the_bfd = abfd; + syms[0].name = mangle_name (abfd, "start"); + syms[0].value = 0; + syms[0].flags = BSF_GLOBAL; + syms[0].section = sec; + syms[0].udata.p = NULL; + + /* End symbol. */ + syms[1].the_bfd = abfd; + syms[1].name = mangle_name (abfd, "end"); + syms[1].value = sec->_raw_size; + syms[1].flags = BSF_GLOBAL; + syms[1].section = sec; + syms[1].udata.p = NULL; + + /* Size symbol. */ + syms[2].the_bfd = abfd; + syms[2].name = mangle_name (abfd, "size"); + syms[2].value = sec->_raw_size; + syms[2].flags = BSF_GLOBAL; + syms[2].section = bfd_abs_section_ptr; + syms[2].udata.p = NULL; + + for (i = 0; i < BIN_SYMS; i++) + *alocation++ = syms++; + *alocation = NULL; + + return BIN_SYMS; +} + +/* Make an empty symbol. */ + +static asymbol * +binary_make_empty_symbol (abfd) + bfd *abfd; +{ + return (asymbol *) bfd_alloc (abfd, sizeof (asymbol)); +} + +#define binary_print_symbol _bfd_nosymbols_print_symbol + +/* Get information about a symbol. */ + +static void +binary_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +#define binary_bfd_is_local_label bfd_generic_is_local_label +#define binary_get_lineno _bfd_nosymbols_get_lineno +#define binary_find_nearest_line _bfd_nosymbols_find_nearest_line +#define binary_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define binary_read_minisymbols _bfd_generic_read_minisymbols +#define binary_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define binary_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define binary_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define binary_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +/* Set the architecture of a binary file. */ +#define binary_set_arch_mach _bfd_generic_set_arch_mach + +/* Write section contents of a binary file. */ + +static boolean +binary_set_section_contents (abfd, sec, data, offset, size) + bfd *abfd; + asection *sec; + PTR data; + file_ptr offset; + bfd_size_type size; +{ + if (! abfd->output_has_begun) + { + bfd_vma low; + asection *s; + + /* The lowest section VMA sets the virtual address of the start + of the file. We use the set the file position of all the + sections. */ + low = abfd->sections->vma; + for (s = abfd->sections->next; s != NULL; s = s->next) + if (s->vma < low) + low = s->vma; + + for (s = abfd->sections; s != NULL; s = s->next) + s->filepos = s->vma - low; + + abfd->output_has_begun = true; + } + + return _bfd_generic_set_section_contents (abfd, sec, data, offset, size); +} + +/* No space is required for header information. */ + +static int +binary_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +#define binary_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define binary_bfd_relax_section bfd_generic_relax_section +#define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define binary_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define binary_bfd_final_link _bfd_generic_final_link +#define binary_bfd_link_split_section _bfd_generic_link_split_section +#define binary_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +const bfd_target binary_vec = +{ + "binary", /* name */ + bfd_target_unknown_flavour, /* flavour */ + BFD_ENDIAN_UNKNOWN, /* byteorder */ + BFD_ENDIAN_UNKNOWN, /* header_byteorder */ + EXEC_P, /* object_flags */ + (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA + | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */ + 0, /* symbol_leading_char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + { /* bfd_check_format */ + _bfd_dummy_target, + binary_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { /* bfd_set_format */ + bfd_false, + binary_mkobject, + bfd_false, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + bfd_true, + bfd_false, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (binary), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (binary), + BFD_JUMP_TABLE_RELOCS (binary), + BFD_JUMP_TABLE_WRITE (binary), + BFD_JUMP_TABLE_LINK (binary), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL +}; diff --git a/contrib/gdb/bfd/bout.c b/contrib/gdb/bfd/bout.c new file mode 100644 index 000000000000..9da4b825b02a --- /dev/null +++ b/contrib/gdb/bfd/bout.c @@ -0,0 +1,1471 @@ +/* BFD back-end for Intel 960 b.out binaries. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "bout.h" + +#include "aout/stab_gnu.h" +#include "libaout.h" /* BFD a.out internal data structures */ + + +static int aligncode PARAMS ((bfd *abfd, asection *input_section, + arelent *r, unsigned int shrink)); +static void perform_slip PARAMS ((bfd *abfd, unsigned int slip, + asection *input_section, bfd_vma value)); +static boolean b_out_squirt_out_relocs PARAMS ((bfd *abfd, asection *section)); +static const bfd_target *b_out_callback PARAMS ((bfd *)); +static bfd_reloc_status_type calljx_callback + PARAMS ((bfd *, struct bfd_link_info *, arelent *, PTR src, PTR dst, + asection *)); +static bfd_reloc_status_type callj_callback + PARAMS ((bfd *, struct bfd_link_info *, arelent *, PTR data, + unsigned int srcidx, unsigned int dstidx, asection *, boolean)); +static bfd_vma get_value PARAMS ((arelent *, struct bfd_link_info *, + asection *)); +static int abs32code PARAMS ((bfd *, asection *, arelent *, + unsigned int, struct bfd_link_info *)); +static boolean b_out_bfd_relax_section PARAMS ((bfd *, asection *, + struct bfd_link_info *, + boolean *)); +static bfd_byte *b_out_bfd_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean, asymbol **)); + +/* Swaps the information in an executable header taken from a raw byte + stream memory image, into the internal exec_header structure. */ + +void +bout_swap_exec_header_in (abfd, raw_bytes, execp) + bfd *abfd; + struct external_exec *raw_bytes; + struct internal_exec *execp; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); + execp->a_tload = GET_WORD (abfd, bytes->e_tload); + execp->a_dload = GET_WORD (abfd, bytes->e_dload); + execp->a_talign = bytes->e_talign[0]; + execp->a_dalign = bytes->e_dalign[0]; + execp->a_balign = bytes->e_balign[0]; + execp->a_relaxable = bytes->e_relaxable[0]; +} + +/* Swaps the information in an internal exec header structure into the + supplied buffer ready for writing to disk. */ + +PROTO(void, bout_swap_exec_header_out, + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes)); +void +bout_swap_exec_header_out (abfd, execp, raw_bytes) + bfd *abfd; + struct internal_exec *execp; + struct external_exec *raw_bytes; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info , bytes->e_info); + PUT_WORD (abfd, execp->a_text , bytes->e_text); + PUT_WORD (abfd, execp->a_data , bytes->e_data); + PUT_WORD (abfd, execp->a_bss , bytes->e_bss); + PUT_WORD (abfd, execp->a_syms , bytes->e_syms); + PUT_WORD (abfd, execp->a_entry , bytes->e_entry); + PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); + PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); + PUT_WORD (abfd, execp->a_tload , bytes->e_tload); + PUT_WORD (abfd, execp->a_dload , bytes->e_dload); + bytes->e_talign[0] = execp->a_talign; + bytes->e_dalign[0] = execp->a_dalign; + bytes->e_balign[0] = execp->a_balign; + bytes->e_relaxable[0] = execp->a_relaxable; +} + + +static const bfd_target * +b_out_object_p (abfd) + bfd *abfd; +{ + struct internal_exec anexec; + struct external_exec exec_bytes; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + anexec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); + + if (N_BADMAG (anexec)) { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + bout_swap_exec_header_in (abfd, &exec_bytes, &anexec); + return aout_32_some_aout_object_p (abfd, &anexec, b_out_callback); +} + + +/* Finish up the opening of a b.out file for reading. Fill in all the + fields that are not handled by common code. */ + +static const bfd_target * +b_out_callback (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + unsigned long bss_start; + + /* Architecture and machine type */ + bfd_set_arch_mach(abfd, + bfd_arch_i960, /* B.out only used on i960 */ + bfd_mach_i960_core /* Default */ + ); + + /* The positions of the string table and symbol table. */ + obj_str_filepos (abfd) = N_STROFF (*execp); + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + + /* The alignments of the sections */ + obj_textsec (abfd)->alignment_power = execp->a_talign; + obj_datasec (abfd)->alignment_power = execp->a_dalign; + obj_bsssec (abfd)->alignment_power = execp->a_balign; + + /* The starting addresses of the sections. */ + obj_textsec (abfd)->vma = execp->a_tload; + obj_datasec (abfd)->vma = execp->a_dload; + + /* And reload the sizes, since the aout module zaps them */ + obj_textsec (abfd)->_raw_size = execp->a_text; + + bss_start = execp->a_dload + execp->a_data; /* BSS = end of data section */ + obj_bsssec (abfd)->vma = align_power (bss_start, execp->a_balign); + + /* The file positions of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF(*execp); + obj_datasec (abfd)->filepos = N_DATOFF(*execp); + + /* The file positions of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TROFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DROFF(*execp); + + adata(abfd).page_size = 1; /* Not applicable. */ + adata(abfd).segment_size = 1; /* Not applicable. */ + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + + if (execp->a_relaxable) + abfd->flags |= BFD_IS_RELAXABLE; + return abfd->xvec; +} + +struct bout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +static boolean +b_out_mkobject (abfd) + bfd *abfd; +{ + struct bout_data_struct *rawptr; + + rawptr = (struct bout_data_struct *) bfd_zalloc (abfd, sizeof (struct bout_data_struct)); + if (rawptr == NULL) + return false; + + abfd->tdata.bout_data = rawptr; + exec_hdr (abfd) = &rawptr->e; + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + + return true; +} + +static boolean +b_out_write_object_contents (abfd) + bfd *abfd; +{ + struct external_exec swapped_hdr; + + if (! aout_32_make_sections (abfd)) + return false; + + exec_hdr (abfd)->a_info = BMAGIC; + + exec_hdr (abfd)->a_text = obj_textsec (abfd)->_raw_size; + exec_hdr (abfd)->a_data = obj_datasec (abfd)->_raw_size; + exec_hdr (abfd)->a_bss = obj_bsssec (abfd)->_raw_size; + exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist); + exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); + exec_hdr (abfd)->a_trsize = ((obj_textsec (abfd)->reloc_count) * + sizeof (struct relocation_info)); + exec_hdr (abfd)->a_drsize = ((obj_datasec (abfd)->reloc_count) * + sizeof (struct relocation_info)); + + exec_hdr (abfd)->a_talign = obj_textsec (abfd)->alignment_power; + exec_hdr (abfd)->a_dalign = obj_datasec (abfd)->alignment_power; + exec_hdr (abfd)->a_balign = obj_bsssec (abfd)->alignment_power; + + exec_hdr (abfd)->a_tload = obj_textsec (abfd)->vma; + exec_hdr (abfd)->a_dload = obj_datasec (abfd)->vma; + + bout_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) &swapped_hdr, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE)) + return false; + + /* Now write out reloc info, followed by syms and strings */ + if (bfd_get_symcount (abfd) != 0) + { + if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*exec_hdr(abfd))), SEEK_SET) + != 0) + return false; + + if (! aout_32_write_syms (abfd)) + return false; + + if (bfd_seek (abfd, (file_ptr)(N_TROFF(*exec_hdr(abfd))), SEEK_SET) != 0) + return false; + + if (!b_out_squirt_out_relocs (abfd, obj_textsec (abfd))) return false; + if (bfd_seek (abfd, (file_ptr)(N_DROFF(*exec_hdr(abfd))), SEEK_SET) + != 0) + return false; + + if (!b_out_squirt_out_relocs (abfd, obj_datasec (abfd))) return false; + } + return true; +} + +/** Some reloc hackery */ + +#define CALLS 0x66003800 /* Template for 'calls' instruction */ +#define BAL 0x0b000000 /* Template for 'bal' instruction */ +#define BALX 0x85000000 /* Template for 'balx' instruction */ +#define BAL_MASK 0x00ffffff +#define CALL 0x09000000 +#define PCREL13_MASK 0x1fff + + +#define output_addr(sec) ((sec)->output_offset+(sec)->output_section->vma) + +/* Magic to turn callx into calljx */ +static bfd_reloc_status_type +calljx_callback (abfd, link_info, reloc_entry, src, dst, input_section) + bfd *abfd; + struct bfd_link_info *link_info; + arelent *reloc_entry; + PTR src; + PTR dst; + asection *input_section; +{ + int word = bfd_get_32 (abfd, src); + asymbol *symbol_in = *(reloc_entry->sym_ptr_ptr); + aout_symbol_type *symbol = aout_symbol (symbol_in); + bfd_vma value; + + value = get_value (reloc_entry, link_info, input_section); + + if (IS_CALLNAME (symbol->other)) + { + aout_symbol_type *balsym = symbol+1; + int inst = bfd_get_32 (abfd, (bfd_byte *) src-4); + /* The next symbol should be an N_BALNAME */ + BFD_ASSERT (IS_BALNAME (balsym->other)); + inst &= BAL_MASK; + inst |= BALX; + bfd_put_32 (abfd, inst, (bfd_byte *) dst-4); + symbol = balsym; + value = (symbol->symbol.value + + output_addr (symbol->symbol.section)); + } + + word += value + reloc_entry->addend; + + bfd_put_32(abfd, word, dst); + return bfd_reloc_ok; +} + + +/* Magic to turn call into callj */ +static bfd_reloc_status_type +callj_callback (abfd, link_info, reloc_entry, data, srcidx, dstidx, + input_section, shrinking) + bfd *abfd; + struct bfd_link_info *link_info; + arelent *reloc_entry; + PTR data; + unsigned int srcidx; + unsigned int dstidx; + asection *input_section; + boolean shrinking; +{ + int word = bfd_get_32 (abfd, (bfd_byte *) data + srcidx); + asymbol *symbol_in = *(reloc_entry->sym_ptr_ptr); + aout_symbol_type *symbol = aout_symbol (symbol_in); + bfd_vma value; + + value = get_value (reloc_entry, link_info, input_section); + + if (IS_OTHER(symbol->other)) + { + /* Call to a system procedure - replace code with system + procedure number. */ + word = CALLS | (symbol->other - 1); + } + else if (IS_CALLNAME(symbol->other)) + { + aout_symbol_type *balsym = symbol+1; + + /* The next symbol should be an N_BALNAME. */ + BFD_ASSERT(IS_BALNAME(balsym->other)); + + /* We are calling a leaf, so replace the call instruction with a + bal. */ + word = BAL | ((word + + output_addr (balsym->symbol.section) + + balsym->symbol.value + reloc_entry->addend + - dstidx + - output_addr (input_section)) + & BAL_MASK); + } + else if ((symbol->symbol.flags & BSF_SECTION_SYM) != 0) + { + /* A callj against a symbol in the same section is a fully + resolved relative call. We don't need to do anything here. + If the symbol is not in the same section, I'm not sure what + to do; fortunately, this case will probably never arise. */ + BFD_ASSERT (! shrinking); + BFD_ASSERT (symbol->symbol.section == input_section); + } + else + { + word = CALL | (((word & BAL_MASK) + + value + + reloc_entry->addend + - (shrinking ? dstidx : 0) + - output_addr (input_section)) + & BAL_MASK); + } + bfd_put_32(abfd, word, (bfd_byte *) data + dstidx); + return bfd_reloc_ok; +} + +/* type rshift size bitsize pcrel bitpos absolute overflow check*/ + +#define ABS32CODE 0 +#define ABS32CODE_SHRUNK 1 +#define PCREL24 2 +#define CALLJ 3 +#define ABS32 4 +#define PCREL13 5 +#define ABS32_MAYBE_RELAXABLE 1 +#define ABS32_WAS_RELAXABLE 2 + +#define ALIGNER 10 +#define ALIGNDONE 11 +static reloc_howto_type howto_reloc_callj = +HOWTO(CALLJ, 0, 2, 24, true, 0, complain_overflow_signed, 0,"callj", true, 0x00ffffff, 0x00ffffff,false); +static reloc_howto_type howto_reloc_abs32 = +HOWTO(ABS32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"abs32", true, 0xffffffff,0xffffffff,false); +static reloc_howto_type howto_reloc_pcrel24 = +HOWTO(PCREL24, 0, 2, 24, true, 0, complain_overflow_signed,0,"pcrel24", true, 0x00ffffff,0x00ffffff,false); + +static reloc_howto_type howto_reloc_pcrel13 = +HOWTO(PCREL13, 0, 2, 13, true, 0, complain_overflow_signed,0,"pcrel13", true, 0x00001fff,0x00001fff,false); + + +static reloc_howto_type howto_reloc_abs32codeshrunk = +HOWTO(ABS32CODE_SHRUNK, 0, 2, 24, true, 0, complain_overflow_signed, 0,"callx->callj", true, 0x00ffffff, 0x00ffffff,false); + +static reloc_howto_type howto_reloc_abs32code = +HOWTO(ABS32CODE, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"callx", true, 0xffffffff,0xffffffff,false); + +static reloc_howto_type howto_align_table[] = { + HOWTO (ALIGNER, 0, 0x1, 0, false, 0, complain_overflow_dont, 0, "align16", false, 0, 0, false), + HOWTO (ALIGNER, 0, 0x3, 0, false, 0, complain_overflow_dont, 0, "align32", false, 0, 0, false), + HOWTO (ALIGNER, 0, 0x7, 0, false, 0, complain_overflow_dont, 0, "align64", false, 0, 0, false), + HOWTO (ALIGNER, 0, 0xf, 0, false, 0, complain_overflow_dont, 0, "align128", false, 0, 0, false), +}; + +static reloc_howto_type howto_done_align_table[] = { + HOWTO (ALIGNDONE, 0x1, 0x1, 0, false, 0, complain_overflow_dont, 0, "donealign16", false, 0, 0, false), + HOWTO (ALIGNDONE, 0x3, 0x3, 0, false, 0, complain_overflow_dont, 0, "donealign32", false, 0, 0, false), + HOWTO (ALIGNDONE, 0x7, 0x7, 0, false, 0, complain_overflow_dont, 0, "donealign64", false, 0, 0, false), + HOWTO (ALIGNDONE, 0xf, 0xf, 0, false, 0, complain_overflow_dont, 0, "donealign128", false, 0, 0, false), +}; + +static reloc_howto_type * +b_out_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + default: + return 0; + case BFD_RELOC_I960_CALLJ: + return &howto_reloc_callj; + case BFD_RELOC_32: + case BFD_RELOC_CTOR: + return &howto_reloc_abs32; + case BFD_RELOC_24_PCREL: + return &howto_reloc_pcrel24; + } +} + +/* Allocate enough room for all the reloc entries, plus pointers to them all */ + +static boolean +b_out_slurp_reloc_table (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + register struct relocation_info *rptr; + unsigned int counter ; + arelent *cache_ptr ; + int extern_mask, pcrel_mask, callj_mask, length_shift; + int incode_mask; + int size_mask; + bfd_vma prev_addr = 0; + unsigned int count; + size_t reloc_size; + struct relocation_info *relocs; + arelent *reloc_cache; + + if (asect->relocation) + return true; + if (!aout_32_slurp_symbol_table (abfd)) + return false; + + if (asect == obj_datasec (abfd)) { + reloc_size = exec_hdr(abfd)->a_drsize; + goto doit; + } + + if (asect == obj_textsec (abfd)) { + reloc_size = exec_hdr(abfd)->a_trsize; + goto doit; + } + + if (asect == obj_bsssec (abfd)) { + reloc_size = 0; + goto doit; + } + + bfd_set_error (bfd_error_invalid_operation); + return false; + + doit: + if (bfd_seek (abfd, (file_ptr)(asect->rel_filepos), SEEK_SET) != 0) + return false; + count = reloc_size / sizeof (struct relocation_info); + + relocs = (struct relocation_info *) bfd_malloc (reloc_size); + if (!relocs && reloc_size != 0) + return false; + reloc_cache = (arelent *) bfd_malloc ((count+1) * sizeof (arelent)); + if (!reloc_cache) { + if (relocs != NULL) + free ((char*)relocs); + return false; + } + + if (bfd_read ((PTR) relocs, 1, reloc_size, abfd) != reloc_size) { + free (reloc_cache); + if (relocs != NULL) + free (relocs); + return false; + } + + + + if (bfd_header_big_endian (abfd)) { + /* big-endian bit field allocation order */ + pcrel_mask = 0x80; + extern_mask = 0x10; + incode_mask = 0x08; + callj_mask = 0x02; + size_mask = 0x20; + length_shift = 5; + } else { + /* little-endian bit field allocation order */ + pcrel_mask = 0x01; + extern_mask = 0x08; + incode_mask = 0x10; + callj_mask = 0x40; + size_mask = 0x02; + length_shift = 1; + } + + for (rptr = relocs, cache_ptr = reloc_cache, counter = 0; + counter < count; + counter++, rptr++, cache_ptr++) + { + unsigned char *raw = (unsigned char *)rptr; + unsigned int symnum; + cache_ptr->address = bfd_h_get_32 (abfd, raw + 0); + cache_ptr->howto = 0; + if (bfd_header_big_endian (abfd)) + { + symnum = (raw[4] << 16) | (raw[5] << 8) | raw[6]; + } + else + { + symnum = (raw[6] << 16) | (raw[5] << 8) | raw[4]; + } + + if (raw[7] & extern_mask) + { + /* if this is set then the r_index is a index into the symbol table; + * if the bit is not set then r_index contains a section map. + * we either fill in the sym entry with a pointer to the symbol, + * or point to the correct section + */ + cache_ptr->sym_ptr_ptr = symbols + symnum; + cache_ptr->addend = 0; + } else + { + /* in a.out symbols are relative to the beginning of the + * file rather than sections ? + * (look in translate_from_native_sym_flags) + * the reloc entry addend has added to it the offset into the + * file of the data, so subtract the base to make the reloc + * section relative */ + int s; + { + /* sign-extend symnum from 24 bits to whatever host uses */ + s = symnum; + if (s & (1 << 23)) + s |= (~0) << 24; + } + cache_ptr->sym_ptr_ptr = (asymbol **)NULL; + switch (s) + { + case N_TEXT: + case N_TEXT | N_EXT: + cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; + cache_ptr->addend = - obj_textsec(abfd)->vma; + break; + case N_DATA: + case N_DATA | N_EXT: + cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; + cache_ptr->addend = - obj_datasec(abfd)->vma; + break; + case N_BSS: + case N_BSS | N_EXT: + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; + cache_ptr->addend = - obj_bsssec(abfd)->vma; + break; + case N_ABS: + case N_ABS | N_EXT: + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; + cache_ptr->addend = 0; + break; + case -2: /* .align */ + if (raw[7] & pcrel_mask) + { + cache_ptr->howto = &howto_align_table[(raw[7] >> length_shift) & 3]; + cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + else + { + /* .org? */ + abort (); + } + cache_ptr->addend = 0; + break; + default: + BFD_ASSERT(0); + break; + } + + } + + /* the i960 only has a few relocation types: + abs 32-bit and pcrel 24bit. except for callj's! */ + if (cache_ptr->howto != 0) + ; + else if (raw[7] & callj_mask) + { + cache_ptr->howto = &howto_reloc_callj; + } + else if ( raw[7] & pcrel_mask) + { + if (raw[7] & size_mask) + cache_ptr->howto = &howto_reloc_pcrel13; + else + cache_ptr->howto = &howto_reloc_pcrel24; + } + else + { + if (raw[7] & incode_mask) + { + cache_ptr->howto = &howto_reloc_abs32code; + } + else + { + cache_ptr->howto = &howto_reloc_abs32; + } + } + if (cache_ptr->address < prev_addr) + { + /* Ouch! this reloc is out of order, insert into the right place + */ + arelent tmp; + arelent *cursor = cache_ptr-1; + bfd_vma stop = cache_ptr->address; + tmp = *cache_ptr; + while (cursor->address > stop && cursor >= reloc_cache) + { + cursor[1] = cursor[0]; + cursor--; + } + cursor[1] = tmp; + } + else + { + prev_addr = cache_ptr->address; + } + } + + + if (relocs != NULL) + free (relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + + + return true; +} + + +static boolean +b_out_squirt_out_relocs (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + int r_extern = 0; + int r_idx; + int incode_mask; + int len_1; + unsigned int count = section->reloc_count; + struct relocation_info *native, *natptr; + size_t natsize = count * sizeof (struct relocation_info); + int extern_mask, pcrel_mask, len_2, callj_mask; + if (count == 0) return true; + generic = section->orelocation; + native = ((struct relocation_info *) bfd_malloc (natsize)); + if (!native && natsize != 0) + return false; + + if (bfd_header_big_endian (abfd)) + { + /* Big-endian bit field allocation order */ + pcrel_mask = 0x80; + extern_mask = 0x10; + len_2 = 0x40; + len_1 = 0x20; + callj_mask = 0x02; + incode_mask = 0x08; + } + else + { + /* Little-endian bit field allocation order */ + pcrel_mask = 0x01; + extern_mask = 0x08; + len_2 = 0x04; + len_1 = 0x02; + callj_mask = 0x40; + incode_mask = 0x10; + } + + for (natptr = native; count > 0; --count, ++natptr, ++generic) + { + arelent *g = *generic; + unsigned char *raw = (unsigned char *)natptr; + asymbol *sym = *(g->sym_ptr_ptr); + + asection *output_section = sym->section->output_section; + + bfd_h_put_32(abfd, g->address, raw); + /* Find a type in the output format which matches the input howto - + * at the moment we assume input format == output format FIXME!! + */ + r_idx = 0; + /* FIXME: Need callj stuff here, and to check the howto entries to + be sure they are real for this architecture. */ + if (g->howto== &howto_reloc_callj) + { + raw[7] = callj_mask + pcrel_mask + len_2; + } + else if (g->howto == &howto_reloc_pcrel24) + { + raw[7] = pcrel_mask + len_2; + } + else if (g->howto == &howto_reloc_pcrel13) + { + raw[7] = pcrel_mask + len_1; + } + else if (g->howto == &howto_reloc_abs32code) + { + raw[7] = len_2 + incode_mask; + } + else if (g->howto >= howto_align_table + && g->howto <= (howto_align_table + + sizeof (howto_align_table) / sizeof (howto_align_table[0]) + - 1)) + { + /* symnum == -2; extern_mask not set, pcrel_mask set */ + r_idx = -2; + r_extern = 0; + raw[7] = (pcrel_mask + | ((g->howto - howto_align_table) << 1)); + } + else { + raw[7] = len_2; + } + + if (r_idx != 0) + /* already mucked with r_extern, r_idx */; + else if (bfd_is_com_section (output_section) + || bfd_is_abs_section (output_section) + || bfd_is_und_section (output_section)) + { + + if (bfd_abs_section_ptr->symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_idx = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + + r_extern = 1; + r_idx = (*g->sym_ptr_ptr)->udata.i; + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_idx = output_section->target_index; + } + + if (bfd_header_big_endian (abfd)) { + raw[4] = (unsigned char) (r_idx >> 16); + raw[5] = (unsigned char) (r_idx >> 8); + raw[6] = (unsigned char) (r_idx ); + } else { + raw[6] = (unsigned char) (r_idx >> 16); + raw[5] = (unsigned char) (r_idx>> 8); + raw[4] = (unsigned char) (r_idx ); + } + if (r_extern) + raw[7] |= extern_mask; + } + + if (bfd_write ((PTR) native, 1, natsize, abfd) != natsize) { + free((PTR)native); + return false; + } + free ((PTR)native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +static long +b_out_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr; + unsigned int count; + + if ((section->flags & SEC_CONSTRUCTOR) != 0) + { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = &chain->relent; + chain = chain->next; + } + } + else + { + if (section->relocation == NULL + && ! b_out_slurp_reloc_table (abfd, section, symbols)) + return -1; + + tblptr = section->relocation; + for (count = 0; count++ < section->reloc_count;) + *relptr++ = tblptr++; + } + + *relptr = NULL; + + return section->reloc_count; +} + +static long +b_out_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + if (asect->flags & SEC_CONSTRUCTOR) + return sizeof (arelent *) * (asect->reloc_count + 1); + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_drsize / sizeof (struct relocation_info)) + +1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_trsize / sizeof (struct relocation_info)) + +1)); + + if (asect == obj_bsssec (abfd)) + return 0; + + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + +static boolean +b_out_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + + if (abfd->output_has_begun == false) { /* set by bfd.c handler */ + if (! aout_32_make_sections (abfd)) + return false; + + obj_textsec (abfd)->filepos = sizeof(struct internal_exec); + obj_datasec(abfd)->filepos = obj_textsec(abfd)->filepos + + obj_textsec (abfd)->_raw_size; + + } + /* regardless, once we know what we're doing, we might as well get going */ + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) + return false; + + if (count != 0) { + return (bfd_write ((PTR)location, 1, count, abfd) == count) ?true:false; + } + return true; +} + +static boolean +b_out_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach(abfd, arch, machine); + + if (arch == bfd_arch_unknown) /* Unknown machine arch is OK */ + return true; + if (arch == bfd_arch_i960) /* i960 default is OK */ + switch (machine) { + case bfd_mach_i960_core: + case bfd_mach_i960_kb_sb: + case bfd_mach_i960_mc: + case bfd_mach_i960_xa: + case bfd_mach_i960_ca: + case bfd_mach_i960_ka_sa: + case bfd_mach_i960_jx: + case bfd_mach_i960_hx: + case 0: + return true; + default: + return false; + } + + return false; +} + +static int +b_out_sizeof_headers (ignore_abfd, ignore) + bfd *ignore_abfd; + boolean ignore; +{ + return sizeof(struct internal_exec); +} + + + +/************************************************************************/ +static bfd_vma +get_value (reloc, link_info, input_section) + arelent *reloc; + struct bfd_link_info *link_info; + asection *input_section; +{ + bfd_vma value; + asymbol *symbol = *(reloc->sym_ptr_ptr); + + /* A symbol holds a pointer to a section, and an offset from the + base of the section. To relocate, we find where the section will + live in the output and add that in */ + + if (bfd_is_und_section (symbol->section)) + { + struct bfd_link_hash_entry *h; + + /* The symbol is undefined in this BFD. Look it up in the + global linker hash table. FIXME: This should be changed when + we convert b.out to use a specific final_link function and + change the interface to bfd_relax_section to not require the + generic symbols. */ + h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info, + bfd_asymbol_name (symbol), + false, false, true); + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + value = h->u.def.value + output_addr (h->u.def.section); + else if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_common) + value = h->u.c.size; + else + { + if (! ((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (symbol), + input_section->owner, input_section, reloc->address))) + abort (); + value = 0; + } + } + else + { + value = symbol->value + output_addr (symbol->section); + } + + /* Add the value contained in the relocation */ + value += reloc->addend; + + return value; +} + +static void +perform_slip (abfd, slip, input_section, value) + bfd *abfd; + unsigned int slip; + asection *input_section; + bfd_vma value; +{ + asymbol **s; + + s = _bfd_generic_link_get_symbols (abfd); + BFD_ASSERT (s != (asymbol **) NULL); + + /* Find all symbols past this point, and make them know + what's happened */ + while (*s) + { + asymbol *p = *s; + if (p->section == input_section) + { + /* This was pointing into this section, so mangle it */ + if (p->value > value) + { + p->value -=slip; + if (p->udata.p != NULL) + { + struct generic_link_hash_entry *h; + + h = (struct generic_link_hash_entry *) p->udata.p; + BFD_ASSERT (h->root.type == bfd_link_hash_defined); + h->root.u.def.value -= slip; + BFD_ASSERT (h->root.u.def.value == p->value); + } + } + } + s++; + + } +} + +/* This routine works out if the thing we want to get to can be + reached with a 24bit offset instead of a 32 bit one. + If it can, then it changes the amode */ + +static int +abs32code (abfd, input_section, r, shrink, link_info) + bfd *abfd; + asection *input_section; + arelent *r; + unsigned int shrink; + struct bfd_link_info *link_info; +{ + bfd_vma value = get_value (r, link_info, input_section); + bfd_vma dot = output_addr (input_section) + r->address; + bfd_vma gap; + + /* See if the address we're looking at within 2^23 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - (dot - shrink); + + + if (-1<<23 < (long)gap && (long)gap < 1<<23 ) + { + /* Change the reloc type from 32bitcode possible 24, to 24bit + possible 32 */ + + r->howto = &howto_reloc_abs32codeshrunk; + /* The place to relc moves back by four bytes */ + r->address -=4; + + /* This will be four bytes smaller in the long run */ + shrink += 4 ; + perform_slip (abfd, 4, input_section, r->address-shrink + 4); + } + return shrink; +} + +static int +aligncode (abfd, input_section, r, shrink) + bfd *abfd; + asection *input_section; + arelent *r; + unsigned int shrink; +{ + bfd_vma dot = output_addr (input_section) + r->address; + bfd_vma gap; + bfd_vma old_end; + bfd_vma new_end; + int shrink_delta; + int size = r->howto->size; + + /* Reduce the size of the alignment so that it's still aligned but + smaller - the current size is already the same size as or bigger + than the alignment required. */ + + /* calculate the first byte following the padding before we optimize */ + old_end = ((dot + size ) & ~size) + size+1; + /* work out where the new end will be - remember that we're smaller + than we used to be */ + new_end = ((dot - shrink + size) & ~size); + + /* This is the new end */ + gap = old_end - ((dot + size) & ~size); + + shrink_delta = (old_end - new_end) - shrink; + + if (shrink_delta) + { + /* Change the reloc so that it knows how far to align to */ + r->howto = howto_done_align_table + (r->howto - howto_align_table); + + /* Encode the stuff into the addend - for future use we need to + know how big the reloc used to be */ + r->addend = old_end - dot + r->address; + + /* This will be N bytes smaller in the long run, adjust all the symbols */ + perform_slip (abfd, shrink_delta, input_section, r->address - shrink); + shrink += shrink_delta; + } + return shrink; +} + +static boolean +b_out_bfd_relax_section (abfd, i, link_info, again) + bfd *abfd; + asection *i; + struct bfd_link_info *link_info; + boolean *again; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = i->owner; + asection *input_section = i; + int shrink = 0 ; + arelent **reloc_vector = NULL; + long reloc_size = bfd_get_reloc_upper_bound(input_bfd, + input_section); + + if (reloc_size < 0) + return false; + + /* We only run this relaxation once. It might work to run it + multiple times, but it hasn't been tested. */ + *again = false; + + if (reloc_size) + { + long reloc_count; + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + /* Get the relocs and think about them */ + reloc_count = + bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, + _bfd_generic_link_get_symbols (input_bfd)); + if (reloc_count < 0) + goto error_return; + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent; parent++) + { + arelent *r = *parent; + switch (r->howto->type) + { + case ALIGNER: + /* An alignment reloc */ + shrink = aligncode (abfd, input_section, r, shrink); + break; + case ABS32CODE: + /* A 32bit reloc in an addressing mode */ + shrink = abs32code (input_bfd, input_section, r, shrink, + link_info); + break; + case ABS32CODE_SHRUNK: + shrink+=4; + break; + } + } + } + } + input_section->_cooked_size = input_section->_raw_size - shrink; + + if (reloc_vector != NULL) + free (reloc_vector); + return true; + error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return false; +} + +static bfd_byte * +b_out_bfd_get_relocated_section_contents (in_abfd, link_info, link_order, + data, relocateable, symbols) + bfd *in_abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size = bfd_get_reloc_upper_bound(input_bfd, + input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + if (reloc_size < 0) + goto error_return; + + /* If producing relocateable output, don't bother to relax. */ + if (relocateable) + return bfd_generic_get_relocated_section_contents (in_abfd, link_info, + link_order, + data, relocateable, + symbols); + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + input_section->reloc_done = 1; + + /* read in the section */ + BFD_ASSERT (true == bfd_get_section_contents(input_bfd, + input_section, + data, + 0, + input_section->_raw_size)); + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + goto error_return; + if (reloc_count > 0) + { + arelent **parent = reloc_vector; + arelent *reloc ; + + unsigned int dst_address = 0; + unsigned int src_address = 0; + unsigned int run; + unsigned int idx; + + /* Find how long a run we can do */ + while (dst_address < link_order->size) + { + reloc = *parent; + if (reloc) + { + /* Note that the relaxing didn't tie up the addresses in the + relocation, so we use the original address to work out the + run of non-relocated data */ + BFD_ASSERT (reloc->address >= src_address); + run = reloc->address - src_address; + parent++; + } + else + { + run = link_order->size - dst_address; + } + /* Copy the bytes */ + for (idx = 0; idx < run; idx++) + { + data[dst_address++] = data[src_address++]; + } + + /* Now do the relocation */ + + if (reloc) + { + switch (reloc->howto->type) + { + case ABS32CODE: + calljx_callback (in_abfd, link_info, reloc, + src_address + data, dst_address + data, + input_section); + src_address+=4; + dst_address+=4; + break; + case ABS32: + bfd_put_32(in_abfd, + (bfd_get_32 (in_abfd, data+src_address) + + get_value (reloc, link_info, input_section)), + data+dst_address); + src_address+=4; + dst_address+=4; + break; + case CALLJ: + callj_callback (in_abfd, link_info, reloc, data, src_address, + dst_address, input_section, false); + src_address+=4; + dst_address+=4; + break; + case ALIGNDONE: + BFD_ASSERT (reloc->addend >= src_address); + BFD_ASSERT (reloc->addend <= input_section->_raw_size); + src_address = reloc->addend; + dst_address = ((dst_address + reloc->howto->size) + & ~reloc->howto->size); + break; + case ABS32CODE_SHRUNK: + /* This used to be a callx, but we've found out that a + callj will reach, so do the right thing. */ + callj_callback (in_abfd, link_info, reloc, data, + src_address + 4, dst_address, input_section, + true); + dst_address+=4; + src_address+=8; + break; + case PCREL24: + { + long int word = bfd_get_32(in_abfd, data+src_address); + bfd_vma value; + + value = get_value (reloc, link_info, input_section); + word = ((word & ~BAL_MASK) + | (((word & BAL_MASK) + + value + - output_addr (input_section) + + reloc->addend) + & BAL_MASK)); + + bfd_put_32(in_abfd,word, data+dst_address); + dst_address+=4; + src_address+=4; + + } + break; + + case PCREL13: + { + long int word = bfd_get_32(in_abfd, data+src_address); + bfd_vma value; + + value = get_value (reloc, link_info, input_section); + word = ((word & ~PCREL13_MASK) + | (((word & PCREL13_MASK) + + value + + reloc->addend + - output_addr (input_section)) + & PCREL13_MASK)); + + bfd_put_32(in_abfd,word, data+dst_address); + dst_address+=4; + src_address+=4; + + } + break; + + default: + abort(); + } + } + } + } + if (reloc_vector != NULL) + free (reloc_vector); + return data; + error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return NULL; +} +/***********************************************************************/ + +/* Build the transfer vectors for Big and Little-Endian B.OUT files. */ + +#define aout_32_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define aout_32_close_and_cleanup aout_32_bfd_free_cached_info + +#define b_out_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define b_out_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define b_out_bfd_final_link _bfd_generic_final_link +#define b_out_bfd_link_split_section _bfd_generic_link_split_section + +#define aout_32_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +const bfd_target b_out_vec_big_host = +{ + "b.out.big", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_BIG, /* hdr byte order is big */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* symbol leading char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + {_bfd_dummy_target, b_out_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, b_out_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, b_out_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (aout_32), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), + BFD_JUMP_TABLE_SYMBOLS (aout_32), + BFD_JUMP_TABLE_RELOCS (b_out), + BFD_JUMP_TABLE_WRITE (b_out), + BFD_JUMP_TABLE_LINK (b_out), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0, +}; + + +const bfd_target b_out_vec_little_host = +{ + "b.out.little", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* symbol leading char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, b_out_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, b_out_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, b_out_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (aout_32), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), + BFD_JUMP_TABLE_SYMBOLS (aout_32), + BFD_JUMP_TABLE_RELOCS (b_out), + BFD_JUMP_TABLE_WRITE (b_out), + BFD_JUMP_TABLE_LINK (b_out), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/cache.c b/contrib/gdb/bfd/cache.c new file mode 100644 index 000000000000..ef15877ccd57 --- /dev/null +++ b/contrib/gdb/bfd/cache.c @@ -0,0 +1,347 @@ +/* BFD library -- caching of file descriptors. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + File caching + + The file caching mechanism is embedded within BFD and allows + the application to open as many BFDs as it wants without + regard to the underlying operating system's file descriptor + limit (often as low as 20 open files). The module in + <> maintains a least recently used list of + <> files, and exports the name + <>, which runs around and makes sure that + the required BFD is open. If not, then it chooses a file to + close, closes it and opens the one wanted, returning its file + handle. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static void insert PARAMS ((bfd *)); +static void snip PARAMS ((bfd *)); +static boolean close_one PARAMS ((void)); +static boolean bfd_cache_delete PARAMS ((bfd *)); + +/* +INTERNAL_FUNCTION + BFD_CACHE_MAX_OPEN macro + +DESCRIPTION + The maximum number of files which the cache will keep open at + one time. + +.#define BFD_CACHE_MAX_OPEN 10 + +*/ + +/* The number of BFD files we have open. */ + +static int open_files; + +/* +INTERNAL_FUNCTION + bfd_last_cache + +SYNOPSIS + extern bfd *bfd_last_cache; + +DESCRIPTION + Zero, or a pointer to the topmost BFD on the chain. This is + used by the <> macro in @file{libbfd.h} to + determine when it can avoid a function call. +*/ + +bfd *bfd_last_cache; + +/* + INTERNAL_FUNCTION + bfd_cache_lookup + + DESCRIPTION + Check to see if the required BFD is the same as the last one + looked up. If so, then it can use the stream in the BFD with + impunity, since it can't have changed since the last lookup; + otherwise, it has to perform the complicated lookup function. + + .#define bfd_cache_lookup(x) \ + . ((x)==bfd_last_cache? \ + . (FILE*)(bfd_last_cache->iostream): \ + . bfd_cache_lookup_worker(x)) + + + */ + +/* Insert a BFD into the cache. */ + +static INLINE void +insert (abfd) + bfd *abfd; +{ + if (bfd_last_cache == NULL) + { + abfd->lru_next = abfd; + abfd->lru_prev = abfd; + } + else + { + abfd->lru_next = bfd_last_cache; + abfd->lru_prev = bfd_last_cache->lru_prev; + abfd->lru_prev->lru_next = abfd; + abfd->lru_next->lru_prev = abfd; + } + bfd_last_cache = abfd; +} + +/* Remove a BFD from the cache. */ + +static INLINE void +snip (abfd) + bfd *abfd; +{ + abfd->lru_prev->lru_next = abfd->lru_next; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (abfd == bfd_last_cache) + { + bfd_last_cache = abfd->lru_next; + if (abfd == bfd_last_cache) + bfd_last_cache = NULL; + } +} + +/* We need to open a new file, and the cache is full. Find the least + recently used cacheable BFD and close it. */ + +static boolean +close_one () +{ + register bfd *kill; + + if (bfd_last_cache == NULL) + kill = NULL; + else + { + for (kill = bfd_last_cache->lru_prev; + ! kill->cacheable; + kill = kill->lru_prev) + { + if (kill == bfd_last_cache) + { + kill = NULL; + break; + } + } + } + + if (kill == NULL) + { + /* There are no open cacheable BFD's. */ + return true; + } + + kill->where = ftell ((FILE *) kill->iostream); + + return bfd_cache_delete (kill); +} + +/* Close a BFD and remove it from the cache. */ + +static boolean +bfd_cache_delete (abfd) + bfd *abfd; +{ + boolean ret; + + if (fclose ((FILE *) abfd->iostream) == 0) + ret = true; + else + { + ret = false; + bfd_set_error (bfd_error_system_call); + } + + snip (abfd); + + abfd->iostream = NULL; + --open_files; + + return ret; +} + +/* +INTERNAL_FUNCTION + bfd_cache_init + +SYNOPSIS + boolean bfd_cache_init (bfd *abfd); + +DESCRIPTION + Add a newly opened BFD to the cache. +*/ + +boolean +bfd_cache_init (abfd) + bfd *abfd; +{ + BFD_ASSERT (abfd->iostream != NULL); + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return false; + } + insert (abfd); + ++open_files; + return true; +} + +/* +INTERNAL_FUNCTION + bfd_cache_close + +SYNOPSIS + boolean bfd_cache_close (bfd *abfd); + +DESCRIPTION + Remove the BFD @var{abfd} from the cache. If the attached file is open, + then close it too. + +RETURNS + <> is returned if closing the file fails, <> is + returned if all is well. +*/ + +boolean +bfd_cache_close (abfd) + bfd *abfd; +{ + if (abfd->iostream == NULL + || (abfd->flags & BFD_IN_MEMORY) != 0) + return true; + + return bfd_cache_delete (abfd); +} + +/* +INTERNAL_FUNCTION + bfd_open_file + +SYNOPSIS + FILE* bfd_open_file(bfd *abfd); + +DESCRIPTION + Call the OS to open a file for @var{abfd}. Return the <> + (possibly <>) that results from this operation. Set up the + BFD so that future accesses know the file is open. If the <> + returned is <>, then it won't have been put in the + cache, so it won't have to be removed from it. +*/ + +FILE * +bfd_open_file (abfd) + bfd *abfd; +{ + abfd->cacheable = true; /* Allow it to be closed later. */ + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return NULL; + } + + switch (abfd->direction) + { + case read_direction: + case no_direction: + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once == true) + { + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB); + if (abfd->iostream == NULL) + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); + } + else + { + /*open for creat */ + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WB); + abfd->opened_once = true; + } + break; + } + + if (abfd->iostream != NULL) + { + if (! bfd_cache_init (abfd)) + return NULL; + } + + return (FILE *) abfd->iostream; +} + +/* +INTERNAL_FUNCTION + bfd_cache_lookup_worker + +SYNOPSIS + FILE *bfd_cache_lookup_worker(bfd *abfd); + +DESCRIPTION + Called when the macro <> fails to find a + quick answer. Find a file descriptor for @var{abfd}. If + necessary, it open it. If there are already more than + <> files open, it tries to close one first, to + avoid running out of file descriptors. +*/ + +FILE * +bfd_cache_lookup_worker (abfd) + bfd *abfd; +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + if (abfd->my_archive) + abfd = abfd->my_archive; + + if (abfd->iostream != NULL) + { + /* Move the file to the start of the cache. */ + if (abfd != bfd_last_cache) + { + snip (abfd); + insert (abfd); + } + } + else + { + if (bfd_open_file (abfd) == NULL) + return NULL; + if (fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0) + return NULL; + } + + return (FILE *) abfd->iostream; +} diff --git a/contrib/gdb/bfd/cf-i386lynx.c b/contrib/gdb/bfd/cf-i386lynx.c new file mode 100644 index 000000000000..2a14bde8f12d --- /dev/null +++ b/contrib/gdb/bfd/cf-i386lynx.c @@ -0,0 +1,31 @@ +/* BFD back-end for Intel 386 COFF LynxOS files. + Copyright 1993, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM i386lynx_coff_vec +#define TARGET_NAME "coff-i386-lynx" + +#define LYNXOS + +#define COFF_LONG_FILENAMES + +#include "coff-i386.c" diff --git a/contrib/gdb/bfd/cf-m68klynx.c b/contrib/gdb/bfd/cf-m68klynx.c new file mode 100644 index 000000000000..8149dc68319a --- /dev/null +++ b/contrib/gdb/bfd/cf-m68klynx.c @@ -0,0 +1,223 @@ +/* BFD back-end for Motorola M68K COFF LynxOS files. + Copyright 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM m68klynx_coff_vec +#define TARGET_NAME "coff-m68k-lynx" + +#define LYNXOS + +#define COFF_LONG_FILENAMES + +#define _bfd_m68kcoff_howto_table _bfd_m68klynx_howto_table +#define _bfd_m68kcoff_rtype2howto _bfd_m68klynx_rtype2howto +#define _bfd_m68kcoff_howto2rtype _bfd_m68klynx_howto2rtype +#define _bfd_m68kcoff_reloc_type_lookup _bfd_m68klynx_reloc_type_lookup + +#define LYNX_SPECIAL_FN _bfd_m68klynx_special_fn + +#include "bfd.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +struct internal_reloc; +struct coff_link_hash_entry; +struct internal_syment; +#endif + +static bfd_reloc_status_type _bfd_m68klynx_special_fn + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *coff_m68k_lynx_rtype_to_howto + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *)); + +/* For some reason when using m68k COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. (taken from work done by Ian Taylor, Cygnus Support, + for I386 COFF). */ + +/* If we are producing relocateable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +_bfd_m68klynx_special_fn (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + if (bfd_is_com_section (symbol->section)) + { + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocateable output. This seems to be always wrong for 386 + COFF, so we handle the addend here instead. */ + diff = reloc_entry->addend; + } + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && (reloc.r_type == R_PCRBYTE \ + || reloc.r_type == R_PCRWORD \ + || reloc.r_type == R_PCRLONG)) \ + cache_ptr->addend += asect->vma; \ + } + +#define coff_rtype_to_howto coff_m68k_lynx_rtype_to_howto + +#include "coff-m68k.c" + +/* coff-m68k.c uses the special COFF backend linker. We need to + adjust common symbols. + + We can't define this function until after we have included + coff-m68k.c, because it uses RTYPE2HOWTO. */ + +/*ARGSUSED*/ +static reloc_howto_type * +coff_m68k_lynx_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + arelent relent; + reloc_howto_type *howto; + + RTYPE2HOWTO (&relent, rel); + + howto = relent.howto; + + if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) + { + /* This is a common symbol. The section contents include the + size (sym->n_value) as an addend. The relocate_section + function will be adding in the final value of the symbol. We + need to subtract out the current size in order to get the + correct result. */ + BFD_ASSERT (h != NULL); + *addendp -= sym->n_value; + } + + /* If the output symbol is common (in which case this must be a + relocateable link), we need to add in the final size of the + common symbol. */ + if (h != NULL && h->root.type == bfd_link_hash_common) + *addendp += h->root.u.c.size; + + return howto; +} diff --git a/contrib/gdb/bfd/cf-sparclynx.c b/contrib/gdb/bfd/cf-sparclynx.c new file mode 100644 index 000000000000..774a099fefbc --- /dev/null +++ b/contrib/gdb/bfd/cf-sparclynx.c @@ -0,0 +1,28 @@ +/* BFD back-end for Sparc COFF LynxOS files. + Copyright 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM sparclynx_coff_vec +#define TARGET_NAME "coff-sparc-lynx" + +#define LYNXOS + +#define COFF_LONG_FILENAMES + +#include "coff-sparc.c" diff --git a/contrib/gdb/bfd/cisco-core.c b/contrib/gdb/bfd/cisco-core.c new file mode 100644 index 000000000000..a25115cc5238 --- /dev/null +++ b/contrib/gdb/bfd/cisco-core.c @@ -0,0 +1,313 @@ +/* BFD back-end for CISCO crash dumps. + +Copyright 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +/* core_file_failing_signal returns a host signal (this probably should + be fixed). */ +#include + +#define CRASH_INFO (0xffc) +#define CRASH_MAGIC 0xdead1234 + +typedef enum { + CRASH_REASON_NOTCRASHED = 0, + CRASH_REASON_EXCEPTION = 1, + CRASH_REASON_CORRUPT = 2, + } crashreason; + +struct crashinfo_external +{ + char magic[4]; /* Magic number */ + char version[4]; /* Version number */ + char reason[4]; /* Crash reason */ + char cpu_vector[4]; /* CPU vector for exceptions */ + char registers[4]; /* Pointer to saved registers */ + char rambase[4]; /* Base of RAM (not in V1 crash info) */ +}; + +struct cisco_core_struct +{ + int sig; +}; + +static const bfd_target * +cisco_core_file_p (abfd) + bfd *abfd; +{ + char buf[4]; + unsigned int crashinfo_offset; + struct crashinfo_external crashinfo; + int nread; + unsigned int rambase; + sec_ptr asect; + struct stat statbuf; + + if (bfd_seek (abfd, CRASH_INFO, SEEK_SET) != 0) + return NULL; + + nread = bfd_read (buf, 1, 4, abfd); + if (nread != 4) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + crashinfo_offset = bfd_get_32 (abfd, buf); + + if (bfd_seek (abfd, crashinfo_offset, SEEK_SET) != 0) + return NULL; + + nread = bfd_read (&crashinfo, 1, sizeof (crashinfo), abfd); + if (nread != sizeof (crashinfo)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (bfd_stat (abfd, &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + if (bfd_get_32 (abfd, crashinfo.magic) != CRASH_MAGIC) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + switch (bfd_get_32 (abfd, crashinfo.version)) + { + case 0: + bfd_set_error (bfd_error_wrong_format); + return NULL; + case 1: + rambase = 0; + break; + default: + case 2: + rambase = bfd_get_32 (abfd, crashinfo.rambase); + break; + } + + /* OK, we believe you. You're a core file. */ + + abfd->tdata.cisco_core_data = + ((struct cisco_core_struct *) + bfd_zmalloc (sizeof (struct cisco_core_struct))); + if (abfd->tdata.cisco_core_data == NULL) + return NULL; + + switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason)) + { + case CRASH_REASON_NOTCRASHED: + /* Crash file probably came from write core. */ + abfd->tdata.cisco_core_data->sig = 0; + break; + case CRASH_REASON_CORRUPT: + /* The crash context area was corrupt -- proceed with caution. + We have no way of passing this information back to the caller. */ + abfd->tdata.cisco_core_data->sig = 0; + break; + case CRASH_REASON_EXCEPTION: + /* Crash occured due to CPU exception. */ + + /* This is 68k-specific; for MIPS we'll need to interpret + cpu_vector differently based on the target configuration + (since CISCO core files don't seem to have the processor + encoded in them). */ + + switch (bfd_get_32 (abfd, crashinfo.cpu_vector)) + { + /* bus error */ + case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; + /* address error */ + case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; + /* illegal instruction */ + case 4 : abfd->tdata.cisco_core_data->sig = SIGILL; break; + /* zero divide */ + case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* chk instruction */ + case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* trapv instruction */ + case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* privilege violation */ + case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break; + /* trace trap */ + case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP; break; + /* line 1010 emulator */ + case 10: abfd->tdata.cisco_core_data->sig = SIGILL; break; + /* line 1111 emulator */ + case 11: abfd->tdata.cisco_core_data->sig = SIGILL; break; + + /* Coprocessor protocol violation. Using a standard MMU or FPU + this cannot be triggered by software. Call it a SIGBUS. */ + case 13: abfd->tdata.cisco_core_data->sig = SIGBUS; break; + + /* interrupt */ + case 31: abfd->tdata.cisco_core_data->sig = SIGINT; break; + /* breakpoint */ + case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP; break; + + /* floating point err */ + case 48: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* floating point err */ + case 49: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* zero divide */ + case 50: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* underflow */ + case 51: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* operand error */ + case 52: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* overflow */ + case 53: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + /* NAN */ + case 54: abfd->tdata.cisco_core_data->sig = SIGFPE; break; + default: + /* "software generated"*/ + abfd->tdata.cisco_core_data->sig = SIGEMT; + } + break; + default: + /* Unknown crash reason. */ + abfd->tdata.cisco_core_data->sig = 0; + break; + } + + abfd->sections = NULL; + abfd->section_count = 0; + + asect = (asection *) bfd_zmalloc (sizeof (asection)); + if (asect == NULL) + goto error_return; + asect->name = ".reg"; + asect->flags = SEC_HAS_CONTENTS; + /* This can be bigger than the real size. Set it to the size of the whole + core file. */ + asect->_raw_size = statbuf.st_size; + asect->vma = 0; + asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase; + asect->next = abfd->sections; + abfd->sections = asect; + ++abfd->section_count; + + /* There is only one section containing data from the target system's RAM. + We call it .data. */ + asect = (asection *) bfd_zmalloc (sizeof (asection)); + if (asect == NULL) + goto error_return; + asect->name = ".data"; + asect->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; + /* The size of memory is the size of the core file itself. */ + asect->_raw_size = statbuf.st_size; + asect->vma = rambase; + asect->filepos = 0; + asect->next = abfd->sections; + abfd->sections = asect; + ++abfd->section_count; + + return abfd->xvec; + + error_return: + { + sec_ptr nextsect; + for (asect = abfd->sections; asect != NULL;) + { + nextsect = asect->next; + free (asect); + asect = nextsect; + } + free (abfd->tdata.cisco_core_data); + return NULL; + } +} + +char * +cisco_core_file_failing_command (abfd) + bfd *abfd; +{ + return NULL; +} + +int +cisco_core_file_failing_signal (abfd) + bfd *abfd; +{ + return abfd->tdata.cisco_core_data->sig; +} + +boolean +cisco_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + return true; +} + +const bfd_target cisco_core_vec = + { + "trad-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + cisco_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (cisco), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; diff --git a/contrib/gdb/bfd/coff-a29k.c b/contrib/gdb/bfd/coff-a29k.c new file mode 100644 index 000000000000..3ceabfba5c46 --- /dev/null +++ b/contrib/gdb/bfd/coff-a29k.c @@ -0,0 +1,641 @@ +/* BFD back-end for AMD 29000 COFF binaries. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by David Wood at New York University 7/8/91. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define A29K 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/a29k.h" +#include "coff/internal.h" +#include "libcoff.h" + +static long get_symbol_value PARAMS ((asymbol *)); +static bfd_reloc_status_type a29k_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static boolean coff_a29k_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); +static boolean coff_a29k_adjust_symndx + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, + struct internal_reloc *, boolean *)); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) + +#define INSERT_HWORD(WORD,HWORD) \ + (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff)) +#define EXTRACT_HWORD(WORD) \ + ((((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff)) +#define SIGN_EXTEND_HWORD(HWORD) \ + ((HWORD) & 0x8000 ? (HWORD)|(~0xffffL) : (HWORD)) + +/* Provided the symbol, returns the value reffed */ +static long +get_symbol_value (symbol) + asymbol *symbol; +{ + long relocation = 0; + + if (bfd_is_com_section (symbol->section)) + { + relocation = 0; + } + else + { + relocation = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + } + + return(relocation); +} + +/* this function is in charge of performing all the 29k relocations */ + +static bfd_reloc_status_type +a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* the consth relocation comes in two parts, we have to remember + the state between calls, in these variables */ + static boolean part1_consth_active = false; + static unsigned long part1_consth_value; + + unsigned long insn; + unsigned long sym_value; + unsigned long unsigned_value; + unsigned short r_type; + long signed_value; + + unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/ + bfd_byte *hit_data =addr + (bfd_byte *)(data); + + r_type = reloc_entry->howto->type; + + if (output_bfd) { + /* Partial linking - do nothing */ + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + + } + + if (symbol_in != NULL + && bfd_is_und_section (symbol_in->section)) + { + /* Keep the state machine happy in case we're called again */ + if (r_type == R_IHIHALF) + { + part1_consth_active = true; + part1_consth_value = 0; + } + return(bfd_reloc_undefined); + } + + if ((part1_consth_active) && (r_type != R_IHCONST)) + { + part1_consth_active = false; + *error_message = (char *) "Missing IHCONST"; + return(bfd_reloc_dangerous); + } + + + sym_value = get_symbol_value(symbol_in); + + switch (r_type) + { + case R_IREL: + insn = bfd_get_32(abfd, hit_data); + /* Take the value in the field and sign extend it */ + signed_value = EXTRACT_HWORD(insn); + signed_value = SIGN_EXTEND_HWORD(signed_value); + signed_value <<= 2; + + /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */ + if (signed_value == - (long) reloc_entry->address) + signed_value = 0; + + signed_value += sym_value + reloc_entry->addend; + if ((signed_value & ~0x3ffff) == 0) + { /* Absolute jmp/call */ + insn |= (1<<24); /* Make it absolute */ + /* FIXME: Should we change r_type to R_IABS */ + } + else + { + /* Relative jmp/call, so subtract from the value the + address of the place we're coming from */ + signed_value -= (reloc_entry->address + + input_section->output_section->vma + + input_section->output_offset); + if (signed_value>0x1ffff || signed_value<-0x20000) + return(bfd_reloc_overflow); + } + signed_value >>= 2; + insn = INSERT_HWORD(insn, signed_value); + bfd_put_32(abfd, insn ,hit_data); + break; + case R_ILOHALF: + insn = bfd_get_32(abfd, hit_data); + unsigned_value = EXTRACT_HWORD(insn); + unsigned_value += sym_value + reloc_entry->addend; + insn = INSERT_HWORD(insn, unsigned_value); + bfd_put_32(abfd, insn, hit_data); + break; + case R_IHIHALF: + insn = bfd_get_32(abfd, hit_data); + /* consth, part 1 + Just get the symbol value that is referenced */ + part1_consth_active = true; + part1_consth_value = sym_value + reloc_entry->addend; + /* Don't modify insn until R_IHCONST */ + break; + case R_IHCONST: + insn = bfd_get_32(abfd, hit_data); + /* consth, part 2 + Now relocate the reference */ + if (part1_consth_active == false) { + *error_message = (char *) "Missing IHIHALF"; + return(bfd_reloc_dangerous); + } + /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */ + unsigned_value = 0; /*EXTRACT_HWORD(insn) << 16;*/ + unsigned_value += reloc_entry->addend; /* r_symndx */ + unsigned_value += part1_consth_value; + unsigned_value = unsigned_value >> 16; + insn = INSERT_HWORD(insn, unsigned_value); + part1_consth_active = false; + bfd_put_32(abfd, insn, hit_data); + break; + case R_BYTE: + insn = bfd_get_8(abfd, hit_data); + unsigned_value = insn + sym_value + reloc_entry->addend; + if (unsigned_value & 0xffffff00) + return(bfd_reloc_overflow); + bfd_put_8(abfd, unsigned_value, hit_data); + break; + case R_HWORD: + insn = bfd_get_16(abfd, hit_data); + unsigned_value = insn + sym_value + reloc_entry->addend; + if (unsigned_value & 0xffff0000) + return(bfd_reloc_overflow); + bfd_put_16(abfd, insn, hit_data); + break; + case R_WORD: + insn = bfd_get_32(abfd, hit_data); + insn += sym_value + reloc_entry->addend; + bfd_put_32(abfd, insn, hit_data); + break; + default: + *error_message = "Unrecognized reloc"; + return (bfd_reloc_dangerous); + } + + + return(bfd_reloc_ok); +} + +/* type rightshift + size + bitsize + pc-relative + bitpos + absolute + complain_on_overflow + special_function + relocation name + partial_inplace + src_mask +*/ + +/*FIXME: I'm not real sure about this table */ +static reloc_howto_type howto_table[] = +{ + {R_ABS, 0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS", true, 0xffffffff,0xffffffff, false}, + {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, + {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20}, + {21}, {22}, {23}, + {R_IREL, 0, 3, 32, true, 0, complain_overflow_signed,a29k_reloc,"IREL", true, 0xffffffff,0xffffffff, false}, + {R_IABS, 0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS", true, 0xffffffff,0xffffffff, false}, + {R_ILOHALF, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false}, + {R_IHIHALF, 0, 3, 16, true, 16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false}, + {R_IHCONST, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false}, + {R_BYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE", true, 0x000000ff,0x000000ff, false}, + {R_HWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD", true, 0x0000ffff,0x0000ffff, false}, + {R_WORD, 0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD", true, 0xffffffff,0xffffffff, false}, +}; + +#define BADMAG(x) A29KBADMAG(x) + +#define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void +reloc_processing (relent,reloc, symbols, abfd, section) + arelent *relent; + struct internal_reloc *reloc; + asymbol **symbols; + bfd *abfd; + asection *section; +{ + static bfd_vma ihihalf_vaddr = (bfd_vma) -1; + + relent->address = reloc->r_vaddr; + relent->howto = howto_table + reloc->r_type; + if (reloc->r_type == R_IHCONST) + { + /* The address of an R_IHCONST should always be the address of + the immediately preceding R_IHIHALF. relocs generated by gas + are correct, but relocs generated by High C are different (I + can't figure out what the address means for High C). We can + handle both gas and High C by ignoring the address here, and + simply reusing the address saved for R_IHIHALF. */ + if (ihihalf_vaddr == (bfd_vma) -1) + abort (); + relent->address = ihihalf_vaddr; + ihihalf_vaddr = (bfd_vma) -1; + relent->addend = reloc->r_symndx; + relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr; + } + else + { + asymbol *ptr; + relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx]; + + ptr = *(relent->sym_ptr_ptr); + + if (ptr + && bfd_asymbol_bfd(ptr) == abfd + + && ((ptr->flags & BSF_OLD_COMMON)== 0)) + { + relent->addend = 0; + } + else + { + relent->addend = 0; + } + relent->address-= section->vma; + if (reloc->r_type == R_IHIHALF) + ihihalf_vaddr = relent->address; + else if (ihihalf_vaddr != (bfd_vma) -1) + abort (); + } +} + +/* The reloc processing routine for the optimized COFF linker. */ + +static boolean +coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, syms, sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + boolean hihalf; + bfd_vma hihalf_val; + + /* If we are performing a relocateable link, we don't need to do a + thing. The caller will take care of adjusting the reloc + addresses and symbol indices. */ + if (info->relocateable) + return true; + + hihalf = false; + hihalf_val = 0; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + bfd_byte *loc; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + asection *sec; + bfd_vma val; + boolean overflow; + unsigned long insn; + long signed_value; + unsigned long unsigned_value; + bfd_reloc_status_type rstat; + + symndx = rel->r_symndx; + loc = contents + rel->r_vaddr - input_section->vma; + + if (symndx == -1) + h = NULL; + else + h = obj_coff_sym_hashes (input_bfd)[symndx]; + + sym = NULL; + sec = NULL; + val = 0; + + /* An R_IHCONST reloc does not have a symbol. Instead, the + symbol index is an addend. R_IHCONST is always used in + conjunction with R_IHHALF. */ + if (rel->r_type != R_IHCONST) + { + if (h == NULL) + { + if (symndx == -1) + sec = bfd_abs_section_ptr; + else + { + sym = syms + symndx; + sec = sections[symndx]; + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + val = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + if (hihalf) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, "missing IHCONST reloc", input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + hihalf = false; + } + } + + overflow = false; + + switch (rel->r_type) + { + default: + bfd_set_error (bfd_error_bad_value); + return false; + + case R_IREL: + insn = bfd_get_32 (input_bfd, loc); + + /* Extract the addend. */ + signed_value = EXTRACT_HWORD (insn); + signed_value = SIGN_EXTEND_HWORD (signed_value); + signed_value <<= 2; + + /* Unfortunately, there are two different versions of COFF + a29k. In the original AMD version, the value stored in + the field for the R_IREL reloc is a simple addend. In + the GNU version, the value is the negative of the address + of the reloc within section. We try to cope here by + assuming the AMD version, unless the addend is exactly + the negative of the address; in the latter case we assume + the GNU version. This means that something like + .text + nop + jmp i-4 + will fail, because the addend of -4 will happen to equal + the negative of the address within the section. The + compiler will never generate code like this. + + At some point in the future we may want to take out this + check. */ + + if (signed_value == - (long) (rel->r_vaddr - input_section->vma)) + signed_value = 0; + + /* Determine the destination of the jump. */ + signed_value += val; + + if ((signed_value & ~0x3ffff) == 0) + { + /* We can use an absolute jump. */ + insn |= (1 << 24); + } + else + { + /* Make the destination PC relative. */ + signed_value -= (input_section->output_section->vma + + input_section->output_offset + + (rel->r_vaddr - input_section->vma)); + if (signed_value > 0x1ffff || signed_value < - 0x20000) + { + overflow = true; + signed_value = 0; + } + } + + /* Put the adjusted value back into the instruction. */ + signed_value >>= 2; + insn = INSERT_HWORD (insn, signed_value); + + bfd_put_32 (input_bfd, (bfd_vma) insn, loc); + + break; + + case R_ILOHALF: + insn = bfd_get_32 (input_bfd, loc); + unsigned_value = EXTRACT_HWORD (insn); + unsigned_value += val; + insn = INSERT_HWORD (insn, unsigned_value); + bfd_put_32 (input_bfd, insn, loc); + break; + + case R_IHIHALF: + /* Save the value for the R_IHCONST reloc. */ + hihalf = true; + hihalf_val = val; + break; + + case R_IHCONST: + if (! hihalf) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, "missing IHIHALF reloc", input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + hihalf_val = 0; + } + + insn = bfd_get_32 (input_bfd, loc); + unsigned_value = rel->r_symndx + hihalf_val; + unsigned_value >>= 16; + insn = INSERT_HWORD (insn, unsigned_value); + bfd_put_32 (input_bfd, (bfd_vma) insn, loc); + + hihalf = false; + + break; + + case R_BYTE: + case R_HWORD: + case R_WORD: + rstat = _bfd_relocate_contents (howto_table + rel->r_type, + input_bfd, val, loc); + if (rstat == bfd_reloc_overflow) + overflow = true; + else if (rstat != bfd_reloc_ok) + abort (); + break; + } + + if (overflow) + { + const char *name; + char buf[SYMNMLEN + 1]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.string; + else if (sym == NULL) + name = "*unknown*"; + else if (sym->_n._n_n._n_zeroes == 0 + && sym->_n._n_n._n_offset != 0) + name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; + else + { + strncpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + name = buf; + } + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto_table[rel->r_type].name, (bfd_vma) 0, + input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + return true; +} + +#define coff_relocate_section coff_a29k_relocate_section + +/* We don't want to change the symndx of a R_IHCONST reloc, since it + is actually an addend, not a symbol index at all. */ + +/*ARGSUSED*/ +static boolean +coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp) + bfd *obfd; + struct bfd_link_info *info; + bfd *ibfd; + asection *sec; + struct internal_reloc *irel; + boolean *adjustedp; +{ + if (irel->r_type == R_IHCONST) + *adjustedp = true; + else + *adjustedp = false; + return true; +} + +#define coff_adjust_symndx coff_a29k_adjust_symndx + +#include "coffcode.h" + +const bfd_target a29kcoff_big_vec = +{ + "coff-a29k-big", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */ + | SEC_LOAD | SEC_RELOC + | SEC_READONLY ), + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + /* hdrs */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + { + + _bfd_dummy_target, + coff_object_p, + bfd_generic_archive_p, + _bfd_dummy_target + }, + { + bfd_false, + coff_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + { + bfd_false, + coff_write_object_contents, + _bfd_write_archive_contents, + bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE + }; diff --git a/contrib/gdb/bfd/coff-alpha.c b/contrib/gdb/bfd/coff-alpha.c new file mode 100644 index 000000000000..b14f3ef207b6 --- /dev/null +++ b/contrib/gdb/bfd/coff-alpha.c @@ -0,0 +1,2390 @@ +/* BFD back-end for ALPHA Extended-Coff files. + Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Modified from coff-mips.c by Steve Chamberlain and + Ian Lance Taylor . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "coff/alpha.h" +#include "aout/ar.h" +#include "libcoff.h" +#include "libecoff.h" + +/* Prototypes for static functions. */ + +static const bfd_target *alpha_ecoff_object_p PARAMS ((bfd *)); +static boolean alpha_ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr)); +static PTR alpha_ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr)); +static void alpha_ecoff_swap_reloc_in PARAMS ((bfd *, PTR, + struct internal_reloc *)); +static void alpha_ecoff_swap_reloc_out PARAMS ((bfd *, + const struct internal_reloc *, + PTR)); +static void alpha_adjust_reloc_in PARAMS ((bfd *, + const struct internal_reloc *, + arelent *)); +static void alpha_adjust_reloc_out PARAMS ((bfd *, const arelent *, + struct internal_reloc *)); +static bfd_byte *alpha_ecoff_get_relocated_section_contents + PARAMS ((bfd *abfd, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *data, boolean relocateable, asymbol **symbols)); +static bfd_vma alpha_convert_external_reloc + PARAMS ((bfd *, struct bfd_link_info *, bfd *, struct external_reloc *, + struct ecoff_link_hash_entry *)); +static boolean alpha_relocate_section PARAMS ((bfd *, struct bfd_link_info *, + bfd *, asection *, + bfd_byte *, PTR)); +static boolean alpha_adjust_headers + PARAMS ((bfd *, struct internal_filehdr *, struct internal_aouthdr *)); +static PTR alpha_ecoff_read_ar_hdr PARAMS ((bfd *)); +static bfd *alpha_ecoff_get_elt_at_filepos PARAMS ((bfd *, file_ptr)); +static bfd *alpha_ecoff_openr_next_archived_file PARAMS ((bfd *, bfd *)); +static bfd *alpha_ecoff_get_elt_at_index PARAMS ((bfd *, symindex)); + +/* ECOFF has COFF sections, but the debugging information is stored in + a completely different format. ECOFF targets use some of the + swapping routines from coffswap.h, and some of the generic COFF + routines in coffgen.c, but, unlike the real COFF targets, do not + use coffcode.h itself. + + Get the generic COFF swapping routines, except for the reloc, + symbol, and lineno ones. Give them ecoff names. Define some + accessor macros for the large sizes used for Alpha ECOFF. */ + +#define GET_FILEHDR_SYMPTR bfd_h_get_64 +#define PUT_FILEHDR_SYMPTR bfd_h_put_64 +#define GET_AOUTHDR_TSIZE bfd_h_get_64 +#define PUT_AOUTHDR_TSIZE bfd_h_put_64 +#define GET_AOUTHDR_DSIZE bfd_h_get_64 +#define PUT_AOUTHDR_DSIZE bfd_h_put_64 +#define GET_AOUTHDR_BSIZE bfd_h_get_64 +#define PUT_AOUTHDR_BSIZE bfd_h_put_64 +#define GET_AOUTHDR_ENTRY bfd_h_get_64 +#define PUT_AOUTHDR_ENTRY bfd_h_put_64 +#define GET_AOUTHDR_TEXT_START bfd_h_get_64 +#define PUT_AOUTHDR_TEXT_START bfd_h_put_64 +#define GET_AOUTHDR_DATA_START bfd_h_get_64 +#define PUT_AOUTHDR_DATA_START bfd_h_put_64 +#define GET_SCNHDR_PADDR bfd_h_get_64 +#define PUT_SCNHDR_PADDR bfd_h_put_64 +#define GET_SCNHDR_VADDR bfd_h_get_64 +#define PUT_SCNHDR_VADDR bfd_h_put_64 +#define GET_SCNHDR_SIZE bfd_h_get_64 +#define PUT_SCNHDR_SIZE bfd_h_put_64 +#define GET_SCNHDR_SCNPTR bfd_h_get_64 +#define PUT_SCNHDR_SCNPTR bfd_h_put_64 +#define GET_SCNHDR_RELPTR bfd_h_get_64 +#define PUT_SCNHDR_RELPTR bfd_h_put_64 +#define GET_SCNHDR_LNNOPTR bfd_h_get_64 +#define PUT_SCNHDR_LNNOPTR bfd_h_put_64 + +#define ALPHAECOFF + +#define NO_COFF_RELOCS +#define NO_COFF_SYMBOLS +#define NO_COFF_LINENOS +#define coff_swap_filehdr_in alpha_ecoff_swap_filehdr_in +#define coff_swap_filehdr_out alpha_ecoff_swap_filehdr_out +#define coff_swap_aouthdr_in alpha_ecoff_swap_aouthdr_in +#define coff_swap_aouthdr_out alpha_ecoff_swap_aouthdr_out +#define coff_swap_scnhdr_in alpha_ecoff_swap_scnhdr_in +#define coff_swap_scnhdr_out alpha_ecoff_swap_scnhdr_out +#include "coffswap.h" + +/* Get the ECOFF swapping routines. */ +#define ECOFF_64 +#include "ecoffswap.h" + +/* How to process the various reloc types. */ + +static bfd_reloc_status_type +reloc_nil PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message) + bfd *abfd; + arelent *reloc; + asymbol *sym; + PTR data; + asection *sec; + bfd *output_bfd; + char **error_message; +{ + return bfd_reloc_ok; +} + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value + from smaller values. Start with zero, widen, *then* decrement. */ +#define MINUS_ONE (((bfd_vma)0) - 1) + +static reloc_howto_type alpha_howto_table[] = +{ + /* Reloc type 0 is ignored by itself. However, it appears after a + GPDISP reloc to identify the location where the low order 16 bits + of the gp register are loaded. */ + HOWTO (ALPHA_R_IGNORE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "IGNORE", /* name */ + true, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 32 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "REFLONG", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFQUAD, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "REFQUAD", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit GP relative offset. This is just like REFLONG except + that when the value is used the value of the gp register will be + added in. */ + HOWTO (ALPHA_R_GPREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "GPREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Used for an instruction that refers to memory off the GP + register. The offset is 16 bits of the 32 bit instruction. This + reloc always seems to be against the .lita section. */ + HOWTO (ALPHA_R_LITERAL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "LITERAL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* This reloc only appears immediately following a LITERAL reloc. + It identifies a use of the literal. It seems that the linker can + use this to eliminate a portion of the .lita section. The symbol + index is special: 1 means the literal address is in the base + register of a memory format instruction; 2 means the literal + address is in the byte offset register of a byte-manipulation + instruction; 3 means the literal address is in the target + register of a jsr instruction. This does not actually do any + relocation. */ + HOWTO (ALPHA_R_LITUSE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "LITUSE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Load the gp register. This is always used for a ldah instruction + which loads the upper 16 bits of the gp register. The next reloc + will be an IGNORE reloc which identifies the location of the lda + instruction which loads the lower 16 bits. The symbol index of + the GPDISP instruction appears to actually be the number of bytes + between the ldah and lda instructions. This gives two different + ways to determine where the lda instruction is; I don't know why + both are used. The value to use for the relocation is the + difference between the GP value and the current location; the + load will always be done against a register holding the current + address. */ + HOWTO (ALPHA_R_GPDISP, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + reloc_nil, /* special_function */ + "GPDISP", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 21 bit branch. The native assembler generates these for + branches within the text segment, and also fills in the PC + relative offset in the instruction. */ + HOWTO (ALPHA_R_BRADDR, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "BRADDR", /* name */ + true, /* partial_inplace */ + 0x1fffff, /* src_mask */ + 0x1fffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A hint for a jump to a register. */ + HOWTO (ALPHA_R_HINT, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "HINT", /* name */ + true, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL64", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Push a value on the reloc evaluation stack. */ + HOWTO (ALPHA_R_OP_PUSH, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PUSH", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Store the value from the stack at the given address. Store it in + a bitfield of size r_size starting at bit position r_offset. */ + HOWTO (ALPHA_R_OP_STORE, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_STORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Subtract the reloc address from the value on the top of the + relocation stack. */ + HOWTO (ALPHA_R_OP_PSUB, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PSUB", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Shift the value on the top of the relocation stack right by the + given value. */ + HOWTO (ALPHA_R_OP_PRSHIFT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PRSHIFT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Adjust the GP value for a new range in the object file. */ + HOWTO (ALPHA_R_GPVALUE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "GPVALUE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false) /* pcrel_offset */ +}; + +/* Recognize an Alpha ECOFF file. */ + +static const bfd_target * +alpha_ecoff_object_p (abfd) + bfd *abfd; +{ + static const bfd_target *ret; + + ret = coff_object_p (abfd); + + if (ret != NULL) + { + asection *sec; + + /* Alpha ECOFF has a .pdata section. The lnnoptr field of the + .pdata section is the number of entries it contains. Each + entry takes up 8 bytes. The number of entries is required + since the section is aligned to a 16 byte boundary. When we + link .pdata sections together, we do not want to include the + alignment bytes. We handle this on input by faking the size + of the .pdata section to remove the unwanted alignment bytes. + On output we will set the lnnoptr field and force the + alignment. */ + sec = bfd_get_section_by_name (abfd, _PDATA); + if (sec != (asection *) NULL) + { + bfd_size_type size; + + size = sec->line_filepos * 8; + BFD_ASSERT (size == bfd_section_size (abfd, sec) + || size + 8 == bfd_section_size (abfd, sec)); + if (! bfd_set_section_size (abfd, sec, size)) + return NULL; + } + } + + return ret; +} + +/* See whether the magic number matches. */ + +static boolean +alpha_ecoff_bad_format_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + if (ALPHA_ECOFF_BADMAG (*internal_f)) + return false; + + return true; +} + +/* This is a hook called by coff_real_object_p to create any backend + specific information. */ + +static PTR +alpha_ecoff_mkobject_hook (abfd, filehdr, aouthdr) + bfd *abfd; + PTR filehdr; + PTR aouthdr; +{ + PTR ecoff; + + ecoff = _bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr); + + if (ecoff != NULL) + { + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + /* Set additional BFD flags according to the object type from the + machine specific file header flags. */ + switch (internal_f->f_flags & F_ALPHA_OBJECT_TYPE_MASK) + { + case F_ALPHA_SHARABLE: + abfd->flags |= DYNAMIC; + break; + case F_ALPHA_CALL_SHARED: + /* Always executable if using shared libraries as the run time + loader might resolve undefined references. */ + abfd->flags |= (DYNAMIC | EXEC_P); + break; + } + } + return ecoff; +} + +/* Reloc handling. */ + +/* Swap a reloc in. */ + +static void +alpha_ecoff_swap_reloc_in (abfd, ext_ptr, intern) + bfd *abfd; + PTR ext_ptr; + struct internal_reloc *intern; +{ + const RELOC *ext = (RELOC *) ext_ptr; + + intern->r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext->r_vaddr); + intern->r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_symndx); + + BFD_ASSERT (bfd_header_little_endian (abfd)); + + intern->r_type = ((ext->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) + >> RELOC_BITS0_TYPE_SH_LITTLE); + intern->r_extern = (ext->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; + intern->r_offset = ((ext->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) + >> RELOC_BITS1_OFFSET_SH_LITTLE); + /* Ignored the reserved bits. */ + intern->r_size = ((ext->r_bits[3] & RELOC_BITS3_SIZE_LITTLE) + >> RELOC_BITS3_SIZE_SH_LITTLE); + + if (intern->r_type == ALPHA_R_LITUSE + || intern->r_type == ALPHA_R_GPDISP) + { + /* Handle the LITUSE and GPDISP relocs specially. Its symndx + value is not actually a symbol index, but is instead a + special code. We put the code in the r_size field, and + clobber the symndx. */ + if (intern->r_size != 0) + abort (); + intern->r_size = intern->r_symndx; + intern->r_symndx = RELOC_SECTION_NONE; + } + else if (intern->r_type == ALPHA_R_IGNORE) + { + /* The IGNORE reloc generally follows a GPDISP reloc, and is + against the .lita section. The section is irrelevant. */ + if (! intern->r_extern && + intern->r_symndx == RELOC_SECTION_ABS) + abort (); + if (! intern->r_extern && intern->r_symndx == RELOC_SECTION_LITA) + intern->r_symndx = RELOC_SECTION_ABS; + } +} + +/* Swap a reloc out. */ + +static void +alpha_ecoff_swap_reloc_out (abfd, intern, dst) + bfd *abfd; + const struct internal_reloc *intern; + PTR dst; +{ + RELOC *ext = (RELOC *) dst; + long symndx; + unsigned char size; + + /* Undo the hackery done in swap_reloc_in. */ + if (intern->r_type == ALPHA_R_LITUSE + || intern->r_type == ALPHA_R_GPDISP) + { + symndx = intern->r_size; + size = 0; + } + else if (intern->r_type == ALPHA_R_IGNORE + && ! intern->r_extern + && intern->r_symndx == RELOC_SECTION_ABS) + { + symndx = RELOC_SECTION_LITA; + size = intern->r_size; + } + else + { + symndx = intern->r_symndx; + size = intern->r_size; + } + + BFD_ASSERT (intern->r_extern + || (intern->r_symndx >= 0 && intern->r_symndx <= 14)); + + bfd_h_put_64 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr); + bfd_h_put_32 (abfd, symndx, (bfd_byte *) ext->r_symndx); + + BFD_ASSERT (bfd_header_little_endian (abfd)); + + ext->r_bits[0] = ((intern->r_type << RELOC_BITS0_TYPE_SH_LITTLE) + & RELOC_BITS0_TYPE_LITTLE); + ext->r_bits[1] = ((intern->r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0) + | ((intern->r_offset << RELOC_BITS1_OFFSET_SH_LITTLE) + & RELOC_BITS1_OFFSET_LITTLE)); + ext->r_bits[2] = 0; + ext->r_bits[3] = ((size << RELOC_BITS3_SIZE_SH_LITTLE) + & RELOC_BITS3_SIZE_LITTLE); +} + +/* Finish canonicalizing a reloc. Part of this is generic to all + ECOFF targets, and that part is in ecoff.c. The rest is done in + this backend routine. It must fill in the howto field. */ + +static void +alpha_adjust_reloc_in (abfd, intern, rptr) + bfd *abfd; + const struct internal_reloc *intern; + arelent *rptr; +{ + if (intern->r_type > ALPHA_R_GPVALUE) + abort (); + + switch (intern->r_type) + { + case ALPHA_R_BRADDR: + case ALPHA_R_SREL16: + case ALPHA_R_SREL32: + case ALPHA_R_SREL64: + /* The PC relative relocs do not seem to use the section VMA as + a negative addend. */ + rptr->addend = 0; + break; + + case ALPHA_R_GPREL32: + case ALPHA_R_LITERAL: + /* Copy the gp value for this object file into the addend, to + ensure that we are not confused by the linker. */ + if (! intern->r_extern) + rptr->addend += ecoff_data (abfd)->gp; + break; + + case ALPHA_R_LITUSE: + case ALPHA_R_GPDISP: + /* The LITUSE and GPDISP relocs do not use a symbol, or an + addend, but they do use a special code. Put this code in the + addend field. */ + rptr->addend = intern->r_size; + break; + + case ALPHA_R_OP_STORE: + /* The STORE reloc needs the size and offset fields. We store + them in the addend. */ + BFD_ASSERT (intern->r_offset <= 256 && intern->r_size <= 256); + rptr->addend = (intern->r_offset << 8) + intern->r_size; + break; + + case ALPHA_R_OP_PUSH: + case ALPHA_R_OP_PSUB: + case ALPHA_R_OP_PRSHIFT: + /* The PUSH, PSUB and PRSHIFT relocs do not actually use an + address. I believe that the address supplied is really an + addend. */ + rptr->addend = intern->r_vaddr; + break; + + case ALPHA_R_GPVALUE: + /* Set the addend field to the new GP value. */ + rptr->addend = intern->r_symndx + ecoff_data (abfd)->gp; + break; + + case ALPHA_R_IGNORE: + /* If the type is ALPHA_R_IGNORE, make sure this is a reference + to the absolute section so that the reloc is ignored. For + some reason the address of this reloc type is not adjusted by + the section vma. We record the gp value for this object file + here, for convenience when doing the GPDISP relocation. */ + rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + rptr->address = intern->r_vaddr; + rptr->addend = ecoff_data (abfd)->gp; + break; + + default: + break; + } + + rptr->howto = &alpha_howto_table[intern->r_type]; +} + +/* When writing out a reloc we need to pull some values back out of + the addend field into the reloc. This is roughly the reverse of + alpha_adjust_reloc_in, except that there are several changes we do + not need to undo. */ + +static void +alpha_adjust_reloc_out (abfd, rel, intern) + bfd *abfd; + const arelent *rel; + struct internal_reloc *intern; +{ + switch (intern->r_type) + { + case ALPHA_R_LITUSE: + case ALPHA_R_GPDISP: + intern->r_size = rel->addend; + break; + + case ALPHA_R_OP_STORE: + intern->r_size = rel->addend & 0xff; + intern->r_offset = (rel->addend >> 8) & 0xff; + break; + + case ALPHA_R_OP_PUSH: + case ALPHA_R_OP_PSUB: + case ALPHA_R_OP_PRSHIFT: + intern->r_vaddr = rel->addend; + break; + + case ALPHA_R_IGNORE: + intern->r_vaddr = rel->address; + break; + + default: + break; + } +} + +/* The size of the stack for the relocation evaluator. */ +#define RELOC_STACKSIZE (10) + +/* Alpha ECOFF relocs have a built in expression evaluator as well as + other interdependencies. Rather than use a bunch of special + functions and global variables, we use a single routine to do all + the relocation for a section. I haven't yet worked out how the + assembler is going to handle this. */ + +static bfd_byte * +alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order, + data, relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + bfd *output_bfd = relocateable ? abfd : (bfd *) NULL; + bfd_vma gp; + boolean gp_undefined; + bfd_vma stack[RELOC_STACKSIZE]; + int tos = 0; + + if (reloc_size < 0) + goto error_return; + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + if (! bfd_get_section_contents (input_bfd, input_section, data, + (file_ptr) 0, input_section->_raw_size)) + goto error_return; + + /* The section size is not going to change. */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = true; + + reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, + reloc_vector, symbols); + if (reloc_count < 0) + goto error_return; + if (reloc_count == 0) + goto successful_return; + + /* Get the GP value for the output BFD. */ + gp_undefined = false; + gp = _bfd_get_gp_value (abfd); + if (gp == 0) + { + if (relocateable != false) + { + asection *sec; + bfd_vma lo; + + /* Make up a value. */ + lo = (bfd_vma) -1; + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (sec->vma < lo + && (strcmp (sec->name, ".sbss") == 0 + || strcmp (sec->name, ".sdata") == 0 + || strcmp (sec->name, ".lit4") == 0 + || strcmp (sec->name, ".lit8") == 0 + || strcmp (sec->name, ".lita") == 0)) + lo = sec->vma; + } + gp = lo + 0x8000; + _bfd_set_gp_value (abfd, gp); + } + else + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info->hash, "_gp", false, false, + true); + if (h == (struct bfd_link_hash_entry *) NULL + || h->type != bfd_link_hash_defined) + gp_undefined = true; + else + { + gp = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + _bfd_set_gp_value (abfd, gp); + } + } + } + + for (; *reloc_vector != (arelent *) NULL; reloc_vector++) + { + arelent *rel; + bfd_reloc_status_type r; + char *err; + + rel = *reloc_vector; + r = bfd_reloc_ok; + switch (rel->howto->type) + { + case ALPHA_R_IGNORE: + rel->address += input_section->output_offset; + break; + + case ALPHA_R_REFLONG: + case ALPHA_R_REFQUAD: + case ALPHA_R_BRADDR: + case ALPHA_R_HINT: + case ALPHA_R_SREL16: + case ALPHA_R_SREL32: + case ALPHA_R_SREL64: + if (relocateable + && ((*rel->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) + { + rel->address += input_section->output_offset; + break; + } + r = bfd_perform_relocation (input_bfd, rel, data, input_section, + output_bfd, &err); + break; + + case ALPHA_R_GPREL32: + /* This relocation is used in a switch table. It is a 32 + bit offset from the current GP value. We must adjust it + by the different between the original GP value and the + current GP value. The original GP value is stored in the + addend. We adjust the addend and let + bfd_perform_relocation finish the job. */ + rel->addend -= gp; + r = bfd_perform_relocation (input_bfd, rel, data, input_section, + output_bfd, &err); + if (r == bfd_reloc_ok && gp_undefined) + { + r = bfd_reloc_dangerous; + err = (char *) "GP relative relocation used when GP not defined"; + } + break; + + case ALPHA_R_LITERAL: + /* This is a reference to a literal value, generally + (always?) in the .lita section. This is a 16 bit GP + relative relocation. Sometimes the subsequent reloc is a + LITUSE reloc, which indicates how this reloc is used. + This sometimes permits rewriting the two instructions + referred to by the LITERAL and the LITUSE into different + instructions which do not refer to .lita. This can save + a memory reference, and permits removing a value from + .lita thus saving GP relative space. + + We do not these optimizations. To do them we would need + to arrange to link the .lita section first, so that by + the time we got here we would know the final values to + use. This would not be particularly difficult, but it is + not currently implemented. */ + + { + unsigned long insn; + + /* I believe that the LITERAL reloc will only apply to a + ldq or ldl instruction, so check my assumption. */ + insn = bfd_get_32 (input_bfd, data + rel->address); + BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 + || ((insn >> 26) & 0x3f) == 0x28); + + rel->addend -= gp; + r = bfd_perform_relocation (input_bfd, rel, data, input_section, + output_bfd, &err); + if (r == bfd_reloc_ok && gp_undefined) + { + r = bfd_reloc_dangerous; + err = + (char *) "GP relative relocation used when GP not defined"; + } + } + break; + + case ALPHA_R_LITUSE: + /* See ALPHA_R_LITERAL above for the uses of this reloc. It + does not cause anything to happen, itself. */ + rel->address += input_section->output_offset; + break; + + case ALPHA_R_GPDISP: + /* This marks the ldah of an ldah/lda pair which loads the + gp register with the difference of the gp value and the + current location. The second of the pair is r_size bytes + ahead; it used to be marked with an ALPHA_R_IGNORE reloc, + but that no longer happens in OSF/1 3.2. */ + { + unsigned long insn1, insn2; + bfd_vma addend; + + /* Get the two instructions. */ + insn1 = bfd_get_32 (input_bfd, data + rel->address); + insn2 = bfd_get_32 (input_bfd, data + rel->address + rel->addend); + + BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ + BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ + + /* Get the existing addend. We must account for the sign + extension done by lda and ldah. */ + addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); + if (insn1 & 0x8000) + { + addend -= 0x80000000; + addend -= 0x80000000; + } + if (insn2 & 0x8000) + addend -= 0x10000; + + /* The existing addend includes the different between the + gp of the input BFD and the address in the input BFD. + Subtract this out. */ + addend -= (ecoff_data (input_bfd)->gp + - (input_section->vma + rel->address)); + + /* Now add in the final gp value, and subtract out the + final address. */ + addend += (gp + - (input_section->output_section->vma + + input_section->output_offset + + rel->address)); + + /* Change the instructions, accounting for the sign + extension, and write them out. */ + if (addend & 0x8000) + addend += 0x10000; + insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); + insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); + + bfd_put_32 (input_bfd, (bfd_vma) insn1, data + rel->address); + bfd_put_32 (input_bfd, (bfd_vma) insn2, + data + rel->address + rel->addend); + + rel->address += input_section->output_offset; + } + break; + + case ALPHA_R_OP_PUSH: + /* Push a value on the reloc evaluation stack. */ + { + asymbol *symbol; + bfd_vma relocation; + + if (relocateable) + { + rel->address += input_section->output_offset; + break; + } + + /* Figure out the relocation of this symbol. */ + symbol = *rel->sym_ptr_ptr; + + if (bfd_is_und_section (symbol->section)) + r = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += rel->addend; + + if (tos >= RELOC_STACKSIZE) + abort (); + + stack[tos++] = relocation; + } + break; + + case ALPHA_R_OP_STORE: + /* Store a value from the reloc stack into a bitfield. */ + { + bfd_vma val; + int offset, size; + + if (relocateable) + { + rel->address += input_section->output_offset; + break; + } + + if (tos == 0) + abort (); + + /* The offset and size for this reloc are encoded into the + addend field by alpha_adjust_reloc_in. */ + offset = (rel->addend >> 8) & 0xff; + size = rel->addend & 0xff; + + val = bfd_get_64 (abfd, data + rel->address); + val &=~ (((1 << size) - 1) << offset); + val |= (stack[--tos] & ((1 << size) - 1)) << offset; + bfd_put_64 (abfd, val, data + rel->address); + } + break; + + case ALPHA_R_OP_PSUB: + /* Subtract a value from the top of the stack. */ + { + asymbol *symbol; + bfd_vma relocation; + + if (relocateable) + { + rel->address += input_section->output_offset; + break; + } + + /* Figure out the relocation of this symbol. */ + symbol = *rel->sym_ptr_ptr; + + if (bfd_is_und_section (symbol->section)) + r = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += rel->addend; + + if (tos == 0) + abort (); + + stack[tos - 1] -= relocation; + } + break; + + case ALPHA_R_OP_PRSHIFT: + /* Shift the value on the top of the stack. */ + { + asymbol *symbol; + bfd_vma relocation; + + if (relocateable) + { + rel->address += input_section->output_offset; + break; + } + + /* Figure out the relocation of this symbol. */ + symbol = *rel->sym_ptr_ptr; + + if (bfd_is_und_section (symbol->section)) + r = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += rel->addend; + + if (tos == 0) + abort (); + + stack[tos - 1] >>= relocation; + } + break; + + case ALPHA_R_GPVALUE: + /* I really don't know if this does the right thing. */ + gp = rel->addend; + gp_undefined = false; + break; + + default: + abort (); + } + + if (relocateable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs. */ + os->orelocation[os->reloc_count] = rel; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (! ((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*rel->sym_ptr_ptr), + input_bfd, input_section, rel->address))) + goto error_return; + break; + case bfd_reloc_dangerous: + if (! ((*link_info->callbacks->reloc_dangerous) + (link_info, err, input_bfd, input_section, + rel->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*rel->sym_ptr_ptr), + rel->howto->name, rel->addend, input_bfd, + input_section, rel->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + default: + abort (); + break; + } + } + } + + if (tos != 0) + abort (); + + successful_return: + if (reloc_vector != NULL) + free (reloc_vector); + return data; + + error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return NULL; +} + +/* Get the howto structure for a generic reloc type. */ + +static reloc_howto_type * +alpha_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + int alpha_type; + + switch (code) + { + case BFD_RELOC_32: + alpha_type = ALPHA_R_REFLONG; + break; + case BFD_RELOC_64: + case BFD_RELOC_CTOR: + alpha_type = ALPHA_R_REFQUAD; + break; + case BFD_RELOC_GPREL32: + alpha_type = ALPHA_R_GPREL32; + break; + case BFD_RELOC_ALPHA_LITERAL: + alpha_type = ALPHA_R_LITERAL; + break; + case BFD_RELOC_ALPHA_LITUSE: + alpha_type = ALPHA_R_LITUSE; + break; + case BFD_RELOC_ALPHA_GPDISP_HI16: + alpha_type = ALPHA_R_GPDISP; + break; + case BFD_RELOC_ALPHA_GPDISP_LO16: + alpha_type = ALPHA_R_IGNORE; + break; + case BFD_RELOC_23_PCREL_S2: + alpha_type = ALPHA_R_BRADDR; + break; + case BFD_RELOC_ALPHA_HINT: + alpha_type = ALPHA_R_HINT; + break; + case BFD_RELOC_16_PCREL: + alpha_type = ALPHA_R_SREL16; + break; + case BFD_RELOC_32_PCREL: + alpha_type = ALPHA_R_SREL32; + break; + case BFD_RELOC_64_PCREL: + alpha_type = ALPHA_R_SREL64; + break; +#if 0 + case ???: + alpha_type = ALPHA_R_OP_PUSH; + break; + case ???: + alpha_type = ALPHA_R_OP_STORE; + break; + case ???: + alpha_type = ALPHA_R_OP_PSUB; + break; + case ???: + alpha_type = ALPHA_R_OP_PRSHIFT; + break; + case ???: + alpha_type = ALPHA_R_GPVALUE; + break; +#endif + default: + return (reloc_howto_type *) NULL; + } + + return &alpha_howto_table[alpha_type]; +} + +/* A helper routine for alpha_relocate_section which converts an + external reloc when generating relocateable output. Returns the + relocation amount. */ + +static bfd_vma +alpha_convert_external_reloc (output_bfd, info, input_bfd, ext_rel, h) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + struct external_reloc *ext_rel; + struct ecoff_link_hash_entry *h; +{ + unsigned long r_symndx; + bfd_vma relocation; + + BFD_ASSERT (info->relocateable); + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + const char *name; + + /* This symbol is defined in the output. Convert the reloc from + being against the symbol to being against the section. */ + + /* Clear the r_extern bit. */ + ext_rel->r_bits[1] &=~ RELOC_BITS1_EXTERN_LITTLE; + + /* Compute a new r_symndx value. */ + hsec = h->root.u.def.section; + name = bfd_get_section_name (output_bfd, hsec->output_section); + + r_symndx = -1; + switch (name[1]) + { + case 'A': + if (strcmp (name, "*ABS*") == 0) + r_symndx = RELOC_SECTION_ABS; + break; + case 'b': + if (strcmp (name, ".bss") == 0) + r_symndx = RELOC_SECTION_BSS; + break; + case 'd': + if (strcmp (name, ".data") == 0) + r_symndx = RELOC_SECTION_DATA; + break; + case 'f': + if (strcmp (name, ".fini") == 0) + r_symndx = RELOC_SECTION_FINI; + break; + case 'i': + if (strcmp (name, ".init") == 0) + r_symndx = RELOC_SECTION_INIT; + break; + case 'l': + if (strcmp (name, ".lita") == 0) + r_symndx = RELOC_SECTION_LITA; + else if (strcmp (name, ".lit8") == 0) + r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + r_symndx = RELOC_SECTION_LIT4; + break; + case 'p': + if (strcmp (name, ".pdata") == 0) + r_symndx = RELOC_SECTION_PDATA; + break; + case 'r': + if (strcmp (name, ".rdata") == 0) + r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".rconst") == 0) + r_symndx = RELOC_SECTION_RCONST; + break; + case 's': + if (strcmp (name, ".sdata") == 0) + r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + r_symndx = RELOC_SECTION_SBSS; + break; + case 't': + if (strcmp (name, ".text") == 0) + r_symndx = RELOC_SECTION_TEXT; + break; + case 'x': + if (strcmp (name, ".xdata") == 0) + r_symndx = RELOC_SECTION_XDATA; + break; + } + + if (r_symndx == -1) + abort (); + + /* Add the section VMA and the symbol value. */ + relocation = (h->root.u.def.value + + hsec->output_section->vma + + hsec->output_offset); + } + else + { + /* Change the symndx value to the right one for + the output BFD. */ + r_symndx = h->indx; + if (r_symndx == -1) + { + /* Caller must give an error. */ + r_symndx = 0; + } + relocation = 0; + } + + /* Write out the new r_symndx value. */ + bfd_h_put_32 (input_bfd, (bfd_vma) r_symndx, + (bfd_byte *) ext_rel->r_symndx); + + return relocation; +} + +/* Relocate a section while linking an Alpha ECOFF file. This is + quite similar to get_relocated_section_contents. Perhaps they + could be combined somehow. */ + +static boolean +alpha_relocate_section (output_bfd, info, input_bfd, input_section, + contents, external_relocs) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + PTR external_relocs; +{ + asection **symndx_to_section, *lita_sec; + struct ecoff_link_hash_entry **sym_hashes; + bfd_vma gp; + boolean gp_undefined; + bfd_vma stack[RELOC_STACKSIZE]; + int tos = 0; + struct external_reloc *ext_rel; + struct external_reloc *ext_rel_end; + + /* We keep a table mapping the symndx found in an internal reloc to + the appropriate section. This is faster than looking up the + section by name each time. */ + symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; + if (symndx_to_section == (asection **) NULL) + { + symndx_to_section = ((asection **) + bfd_alloc (input_bfd, + (NUM_RELOC_SECTIONS + * sizeof (asection *)))); + if (!symndx_to_section) + return false; + + symndx_to_section[RELOC_SECTION_NONE] = NULL; + symndx_to_section[RELOC_SECTION_TEXT] = + bfd_get_section_by_name (input_bfd, ".text"); + symndx_to_section[RELOC_SECTION_RDATA] = + bfd_get_section_by_name (input_bfd, ".rdata"); + symndx_to_section[RELOC_SECTION_DATA] = + bfd_get_section_by_name (input_bfd, ".data"); + symndx_to_section[RELOC_SECTION_SDATA] = + bfd_get_section_by_name (input_bfd, ".sdata"); + symndx_to_section[RELOC_SECTION_SBSS] = + bfd_get_section_by_name (input_bfd, ".sbss"); + symndx_to_section[RELOC_SECTION_BSS] = + bfd_get_section_by_name (input_bfd, ".bss"); + symndx_to_section[RELOC_SECTION_INIT] = + bfd_get_section_by_name (input_bfd, ".init"); + symndx_to_section[RELOC_SECTION_LIT8] = + bfd_get_section_by_name (input_bfd, ".lit8"); + symndx_to_section[RELOC_SECTION_LIT4] = + bfd_get_section_by_name (input_bfd, ".lit4"); + symndx_to_section[RELOC_SECTION_XDATA] = + bfd_get_section_by_name (input_bfd, ".xdata"); + symndx_to_section[RELOC_SECTION_PDATA] = + bfd_get_section_by_name (input_bfd, ".pdata"); + symndx_to_section[RELOC_SECTION_FINI] = + bfd_get_section_by_name (input_bfd, ".fini"); + symndx_to_section[RELOC_SECTION_LITA] = + bfd_get_section_by_name (input_bfd, ".lita"); + symndx_to_section[RELOC_SECTION_ABS] = bfd_abs_section_ptr; + symndx_to_section[RELOC_SECTION_RCONST] = + bfd_get_section_by_name (input_bfd, ".rconst"); + + ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; + } + + sym_hashes = ecoff_data (input_bfd)->sym_hashes; + + /* On the Alpha, the .lita section must be addressable by the global + pointer. To support large programs, we need to allow multiple + global pointers. This works as long as each input .lita section + is <64KB big. This implies that when producing relocatable + output, the .lita section is limited to 64KB. . */ + + lita_sec = symndx_to_section[RELOC_SECTION_LITA]; + gp = _bfd_get_gp_value (output_bfd); + if (! info->relocateable && lita_sec != NULL) + { + struct ecoff_section_tdata *lita_sec_data; + + /* Make sure we have a section data structure to which we can + hang on to the gp value we pick for the section. */ + lita_sec_data = ecoff_section_data (input_bfd, lita_sec); + if (lita_sec_data == NULL) + { + lita_sec_data = ((struct ecoff_section_tdata *) + bfd_zalloc (input_bfd, + sizeof (struct ecoff_section_tdata))); + ecoff_section_data (input_bfd, lita_sec) = lita_sec_data; + } + + if (lita_sec_data->gp != 0) + { + /* If we already assigned a gp to this section, we better + stick with that value. */ + gp = lita_sec_data->gp; + } + else + { + bfd_vma lita_vma; + bfd_size_type lita_size; + + lita_vma = lita_sec->output_offset + lita_sec->output_section->vma; + lita_size = lita_sec->_cooked_size; + if (lita_size == 0) + lita_size = lita_sec->_raw_size; + + if (gp == 0 + || lita_vma < gp - 0x8000 + || lita_vma + lita_size >= gp + 0x8000) + { + /* Either gp hasn't been set at all or the current gp + cannot address this .lita section. In both cases we + reset the gp to point into the "middle" of the + current input .lita section. */ + if (gp && !ecoff_data (output_bfd)->issued_multiple_gp_warning) + { + (*info->callbacks->warning) (info, + "using multiple gp values", + (char *) NULL, output_bfd, + (asection *) NULL, (bfd_vma) 0); + ecoff_data (output_bfd)->issued_multiple_gp_warning = true; + } + if (lita_vma < gp - 0x8000) + gp = lita_vma + lita_size - 0x8000; + else + gp = lita_vma + 0x8000; + + } + + lita_sec_data->gp = gp; + } + + _bfd_set_gp_value (output_bfd, gp); + } + + gp_undefined = (gp == 0); + + BFD_ASSERT (bfd_header_little_endian (output_bfd)); + BFD_ASSERT (bfd_header_little_endian (input_bfd)); + + ext_rel = (struct external_reloc *) external_relocs; + ext_rel_end = ext_rel + input_section->reloc_count; + for (; ext_rel < ext_rel_end; ext_rel++) + { + bfd_vma r_vaddr; + unsigned long r_symndx; + int r_type; + int r_extern; + int r_offset; + int r_size; + boolean relocatep; + boolean adjust_addrp; + boolean gp_usedp; + bfd_vma addend; + + r_vaddr = bfd_h_get_64 (input_bfd, (bfd_byte *) ext_rel->r_vaddr); + r_symndx = bfd_h_get_32 (input_bfd, (bfd_byte *) ext_rel->r_symndx); + + r_type = ((ext_rel->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) + >> RELOC_BITS0_TYPE_SH_LITTLE); + r_extern = (ext_rel->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; + r_offset = ((ext_rel->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) + >> RELOC_BITS1_OFFSET_SH_LITTLE); + /* Ignored the reserved bits. */ + r_size = ((ext_rel->r_bits[3] & RELOC_BITS3_SIZE_LITTLE) + >> RELOC_BITS3_SIZE_SH_LITTLE); + + relocatep = false; + adjust_addrp = true; + gp_usedp = false; + addend = 0; + + switch (r_type) + { + default: + abort (); + + case ALPHA_R_IGNORE: + /* This reloc appears after a GPDISP reloc. On earlier + versions of OSF/1, It marked the position of the second + instruction to be altered by the GPDISP reloc, but it is + not otherwise used for anything. For some reason, the + address of the relocation does not appear to include the + section VMA, unlike the other relocation types. */ + if (info->relocateable) + bfd_h_put_64 (input_bfd, + input_section->output_offset + r_vaddr, + (bfd_byte *) ext_rel->r_vaddr); + adjust_addrp = false; + break; + + case ALPHA_R_REFLONG: + case ALPHA_R_REFQUAD: + case ALPHA_R_BRADDR: + case ALPHA_R_HINT: + case ALPHA_R_SREL16: + case ALPHA_R_SREL32: + case ALPHA_R_SREL64: + relocatep = true; + break; + + case ALPHA_R_GPREL32: + /* This relocation is used in a switch table. It is a 32 + bit offset from the current GP value. We must adjust it + by the different between the original GP value and the + current GP value. */ + relocatep = true; + addend = ecoff_data (input_bfd)->gp - gp; + gp_usedp = true; + break; + + case ALPHA_R_LITERAL: + /* This is a reference to a literal value, generally + (always?) in the .lita section. This is a 16 bit GP + relative relocation. Sometimes the subsequent reloc is a + LITUSE reloc, which indicates how this reloc is used. + This sometimes permits rewriting the two instructions + referred to by the LITERAL and the LITUSE into different + instructions which do not refer to .lita. This can save + a memory reference, and permits removing a value from + .lita thus saving GP relative space. + + We do not these optimizations. To do them we would need + to arrange to link the .lita section first, so that by + the time we got here we would know the final values to + use. This would not be particularly difficult, but it is + not currently implemented. */ + + /* I believe that the LITERAL reloc will only apply to a ldq + or ldl instruction, so check my assumption. */ + { + unsigned long insn; + + insn = bfd_get_32 (input_bfd, + contents + r_vaddr - input_section->vma); + BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 + || ((insn >> 26) & 0x3f) == 0x28); + } + + relocatep = true; + addend = ecoff_data (input_bfd)->gp - gp; + gp_usedp = true; + break; + + case ALPHA_R_LITUSE: + /* See ALPHA_R_LITERAL above for the uses of this reloc. It + does not cause anything to happen, itself. */ + break; + + case ALPHA_R_GPDISP: + /* This marks the ldah of an ldah/lda pair which loads the + gp register with the difference of the gp value and the + current location. The second of the pair is r_symndx + bytes ahead. It used to be marked with an ALPHA_R_IGNORE + reloc, but OSF/1 3.2 no longer does that. */ + { + unsigned long insn1, insn2; + + /* Get the two instructions. */ + insn1 = bfd_get_32 (input_bfd, + contents + r_vaddr - input_section->vma); + insn2 = bfd_get_32 (input_bfd, + (contents + + r_vaddr + - input_section->vma + + r_symndx)); + + BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ + BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ + + /* Get the existing addend. We must account for the sign + extension done by lda and ldah. */ + addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); + if (insn1 & 0x8000) + { + /* This is addend -= 0x100000000 without causing an + integer overflow on a 32 bit host. */ + addend -= 0x80000000; + addend -= 0x80000000; + } + if (insn2 & 0x8000) + addend -= 0x10000; + + /* The existing addend includes the difference between the + gp of the input BFD and the address in the input BFD. + We want to change this to the difference between the + final GP and the final address. */ + addend += (gp + - ecoff_data (input_bfd)->gp + + input_section->vma + - (input_section->output_section->vma + + input_section->output_offset)); + + /* Change the instructions, accounting for the sign + extension, and write them out. */ + if (addend & 0x8000) + addend += 0x10000; + insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); + insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); + + bfd_put_32 (input_bfd, (bfd_vma) insn1, + contents + r_vaddr - input_section->vma); + bfd_put_32 (input_bfd, (bfd_vma) insn2, + contents + r_vaddr - input_section->vma + r_symndx); + + gp_usedp = true; + } + break; + + case ALPHA_R_OP_PUSH: + case ALPHA_R_OP_PSUB: + case ALPHA_R_OP_PRSHIFT: + /* Manipulate values on the reloc evaluation stack. The + r_vaddr field is not an address in input_section, it is + the current value (including any addend) of the object + being used. */ + if (! r_extern) + { + asection *s; + + s = symndx_to_section[r_symndx]; + if (s == (asection *) NULL) + abort (); + addend = s->output_section->vma + s->output_offset - s->vma; + } + else + { + struct ecoff_link_hash_entry *h; + + h = sym_hashes[r_symndx]; + if (h == (struct ecoff_link_hash_entry *) NULL) + abort (); + + if (! info->relocateable) + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + addend = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + else + { + /* Note that we pass the address as 0, since we + do not have a meaningful number for the + location within the section that is being + relocated. */ + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, (bfd_vma) 0))) + return false; + addend = 0; + } + } + else + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak + && h->indx == -1) + { + /* This symbol is not being written out. Pass + the address as 0, as with undefined_symbol, + above. */ + if (! ((*info->callbacks->unattached_reloc) + (info, h->root.root.string, input_bfd, + input_section, (bfd_vma) 0))) + return false; + } + + addend = alpha_convert_external_reloc (output_bfd, info, + input_bfd, + ext_rel, h); + } + } + + addend += r_vaddr; + + if (info->relocateable) + { + /* Adjust r_vaddr by the addend. */ + bfd_h_put_64 (input_bfd, addend, + (bfd_byte *) ext_rel->r_vaddr); + } + else + { + switch (r_type) + { + case ALPHA_R_OP_PUSH: + if (tos >= RELOC_STACKSIZE) + abort (); + stack[tos++] = addend; + break; + + case ALPHA_R_OP_PSUB: + if (tos == 0) + abort (); + stack[tos - 1] -= addend; + break; + + case ALPHA_R_OP_PRSHIFT: + if (tos == 0) + abort (); + stack[tos - 1] >>= addend; + break; + } + } + + adjust_addrp = false; + break; + + case ALPHA_R_OP_STORE: + /* Store a value from the reloc stack into a bitfield. If + we are generating relocateable output, all we do is + adjust the address of the reloc. */ + if (! info->relocateable) + { + bfd_vma mask; + bfd_vma val; + + if (tos == 0) + abort (); + + /* Get the relocation mask. The separate steps and the + casts to bfd_vma are attempts to avoid a bug in the + Alpha OSF 1.3 C compiler. See reloc.c for more + details. */ + mask = 1; + mask <<= (bfd_vma) r_size; + mask -= 1; + + /* FIXME: I don't know what kind of overflow checking, + if any, should be done here. */ + val = bfd_get_64 (input_bfd, + contents + r_vaddr - input_section->vma); + val &=~ mask << (bfd_vma) r_offset; + val |= (stack[--tos] & mask) << (bfd_vma) r_offset; + bfd_put_64 (input_bfd, val, + contents + r_vaddr - input_section->vma); + } + break; + + case ALPHA_R_GPVALUE: + /* I really don't know if this does the right thing. */ + gp = ecoff_data (input_bfd)->gp + r_symndx; + gp_undefined = false; + break; + } + + if (relocatep) + { + reloc_howto_type *howto; + struct ecoff_link_hash_entry *h = NULL; + asection *s = NULL; + bfd_vma relocation; + bfd_reloc_status_type r; + + /* Perform a relocation. */ + + howto = &alpha_howto_table[r_type]; + + if (r_extern) + { + h = sym_hashes[r_symndx]; + /* If h is NULL, that means that there is a reloc + against an external symbol which we thought was just + a debugging symbol. This should not happen. */ + if (h == (struct ecoff_link_hash_entry *) NULL) + abort (); + } + else + { + if (r_symndx >= NUM_RELOC_SECTIONS) + s = NULL; + else + s = symndx_to_section[r_symndx]; + + if (s == (asection *) NULL) + abort (); + } + + if (info->relocateable) + { + /* We are generating relocateable output, and must + convert the existing reloc. */ + if (r_extern) + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak + && h->indx == -1) + { + /* This symbol is not being written out. */ + if (! ((*info->callbacks->unattached_reloc) + (info, h->root.root.string, input_bfd, + input_section, r_vaddr - input_section->vma))) + return false; + } + + relocation = alpha_convert_external_reloc (output_bfd, + info, + input_bfd, + ext_rel, + h); + } + else + { + /* This is a relocation against a section. Adjust + the value by the amount the section moved. */ + relocation = (s->output_section->vma + + s->output_offset + - s->vma); + } + + /* If this is PC relative, the existing object file + appears to already have the reloc worked out. We + must subtract out the old value and add in the new + one. */ + if (howto->pc_relative) + relocation -= (input_section->output_section->vma + + input_section->output_offset + - input_section->vma); + + /* Put in any addend. */ + relocation += addend; + + /* Adjust the contents. */ + r = _bfd_relocate_contents (howto, input_bfd, relocation, + (contents + + r_vaddr + - input_section->vma)); + } + else + { + /* We are producing a final executable. */ + if (r_extern) + { + /* This is a reloc against a symbol. */ + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + + hsec = h->root.u.def.section; + relocation = (h->root.u.def.value + + hsec->output_section->vma + + hsec->output_offset); + } + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, + r_vaddr - input_section->vma))) + return false; + relocation = 0; + } + } + else + { + /* This is a reloc against a section. */ + relocation = (s->output_section->vma + + s->output_offset + - s->vma); + + /* Adjust a PC relative relocation by removing the + reference to the original source section. */ + if (howto->pc_relative) + relocation += input_section->vma; + } + + r = _bfd_final_link_relocate (howto, + input_bfd, + input_section, + contents, + r_vaddr - input_section->vma, + relocation, + addend); + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (r_extern) + name = sym_hashes[r_symndx]->root.root.string; + else + name = bfd_section_name (input_bfd, + symndx_to_section[r_symndx]); + if (! ((*info->callbacks->reloc_overflow) + (info, name, alpha_howto_table[r_type].name, + (bfd_vma) 0, input_bfd, input_section, + r_vaddr - input_section->vma))) + return false; + } + break; + } + } + } + + if (info->relocateable && adjust_addrp) + { + /* Change the address of the relocation. */ + bfd_h_put_64 (input_bfd, + (input_section->output_section->vma + + input_section->output_offset + - input_section->vma + + r_vaddr), + (bfd_byte *) ext_rel->r_vaddr); + } + + if (gp_usedp && gp_undefined) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, "GP relative relocation when GP not defined", + input_bfd, input_section, r_vaddr - input_section->vma))) + return false; + /* Only give the error once per link. */ + gp = 4; + _bfd_set_gp_value (output_bfd, gp); + gp_undefined = false; + } + } + + if (tos != 0) + abort (); + + return true; +} + +/* Do final adjustments to the filehdr and the aouthdr. This routine + sets the dynamic bits in the file header. */ + +/*ARGSUSED*/ +static boolean +alpha_adjust_headers (abfd, fhdr, ahdr) + bfd *abfd; + struct internal_filehdr *fhdr; + struct internal_aouthdr *ahdr; +{ + if ((abfd->flags & (DYNAMIC | EXEC_P)) == (DYNAMIC | EXEC_P)) + fhdr->f_flags |= F_ALPHA_CALL_SHARED; + else if ((abfd->flags & DYNAMIC) != 0) + fhdr->f_flags |= F_ALPHA_SHARABLE; + return true; +} + +/* Archive handling. In OSF/1 (or Digital Unix) v3.2, Digital + introduced archive packing, in which the elements in an archive are + optionally compressed using a simple dictionary scheme. We know + how to read such archives, but we don't write them. */ + +#define alpha_ecoff_slurp_armap _bfd_ecoff_slurp_armap +#define alpha_ecoff_slurp_extended_name_table \ + _bfd_ecoff_slurp_extended_name_table +#define alpha_ecoff_construct_extended_name_table \ + _bfd_ecoff_construct_extended_name_table +#define alpha_ecoff_truncate_arname _bfd_ecoff_truncate_arname +#define alpha_ecoff_write_armap _bfd_ecoff_write_armap +#define alpha_ecoff_generic_stat_arch_elt _bfd_ecoff_generic_stat_arch_elt +#define alpha_ecoff_update_armap_timestamp _bfd_ecoff_update_armap_timestamp + +/* A compressed file uses this instead of ARFMAG. */ + +#define ARFZMAG "Z\012" + +/* Read an archive header. This is like the standard routine, but it + also accepts ARFZMAG. */ + +static PTR +alpha_ecoff_read_ar_hdr (abfd) + bfd *abfd; +{ + struct areltdata *ret; + struct ar_hdr *h; + + ret = (struct areltdata *) _bfd_generic_read_ar_hdr_mag (abfd, ARFZMAG); + if (ret == NULL) + return NULL; + + h = (struct ar_hdr *) ret->arch_header; + if (strncmp (h->ar_fmag, ARFZMAG, 2) == 0) + { + bfd_byte ab[8]; + + /* This is a compressed file. We must set the size correctly. + The size is the eight bytes after the dummy file header. */ + if (bfd_seek (abfd, FILHSZ, SEEK_CUR) != 0 + || bfd_read (ab, 1, 8, abfd) != 8 + || bfd_seek (abfd, - (FILHSZ + 8), SEEK_CUR) != 0) + return NULL; + + ret->parsed_size = bfd_h_get_64 (abfd, ab); + } + + return (PTR) ret; +} + +/* Get an archive element at a specified file position. This is where + we uncompress the archive element if necessary. */ + +static bfd * +alpha_ecoff_get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + bfd *nbfd = NULL; + struct areltdata *tdata; + struct ar_hdr *hdr; + bfd_byte ab[8]; + bfd_size_type size; + bfd_byte *buf, *p; + struct bfd_in_memory *bim; + + nbfd = _bfd_get_elt_at_filepos (archive, filepos); + if (nbfd == NULL) + goto error_return; + + if ((nbfd->flags & BFD_IN_MEMORY) != 0) + { + /* We have already expanded this BFD. */ + return nbfd; + } + + tdata = (struct areltdata *) nbfd->arelt_data; + hdr = (struct ar_hdr *) tdata->arch_header; + if (strncmp (hdr->ar_fmag, ARFZMAG, 2) != 0) + return nbfd; + + /* We must uncompress this element. We do this by copying it into a + memory buffer, and making bfd_read and bfd_seek use that buffer. + This can use a lot of memory, but it's simpler than getting a + temporary file, making that work with the file descriptor caching + code, and making sure that it is deleted at all appropriate + times. It can be changed if it ever becomes important. */ + + /* The compressed file starts with a dummy ECOFF file header. */ + if (bfd_seek (nbfd, FILHSZ, SEEK_SET) != 0) + goto error_return; + + /* The next eight bytes are the real file size. */ + if (bfd_read (ab, 1, 8, nbfd) != 8) + goto error_return; + size = bfd_h_get_64 (nbfd, ab); + + if (size == 0) + buf = NULL; + else + { + bfd_size_type left; + bfd_byte dict[4096]; + unsigned int h; + bfd_byte b; + + buf = (bfd_byte *) bfd_alloc (nbfd, size); + if (buf == NULL) + goto error_return; + p = buf; + + left = size; + + /* I don't know what the next eight bytes are for. */ + if (bfd_read (ab, 1, 8, nbfd) != 8) + goto error_return; + + /* This is the uncompression algorithm. It's a simple + dictionary based scheme in which each character is predicted + by a hash of the previous three characters. A control byte + indicates whether the character is predicted or whether it + appears in the input stream; each control byte manages the + next eight bytes in the output stream. */ + memset (dict, 0, sizeof dict); + h = 0; + while (bfd_read (&b, 1, 1, nbfd) == 1) + { + unsigned int i; + + for (i = 0; i < 8; i++, b >>= 1) + { + bfd_byte n; + + if ((b & 1) == 0) + n = dict[h]; + else + { + if (! bfd_read (&n, 1, 1, nbfd)) + goto error_return; + dict[h] = n; + } + + *p++ = n; + + --left; + if (left == 0) + break; + + h <<= 4; + h ^= n; + h &= sizeof dict - 1; + } + + if (left == 0) + break; + } + } + + /* Now the uncompressed file contents are in buf. */ + bim = ((struct bfd_in_memory *) + bfd_alloc (nbfd, sizeof (struct bfd_in_memory))); + if (bim == NULL) + goto error_return; + bim->size = size; + bim->buffer = buf; + + nbfd->mtime_set = true; + nbfd->mtime = strtol (hdr->ar_date, (char **) NULL, 10); + + nbfd->flags |= BFD_IN_MEMORY; + nbfd->iostream = (PTR) bim; + BFD_ASSERT (! nbfd->cacheable); + + return nbfd; + + error_return: + if (nbfd != NULL) + bfd_close (nbfd); + return NULL; +} + +/* Open the next archived file. */ + +static bfd * +alpha_ecoff_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + { + struct areltdata *t; + struct ar_hdr *h; + bfd_size_type size; + + /* We can't use arelt_size here, because that uses parsed_size, + which is the uncompressed size. We need the compressed size. */ + t = (struct areltdata *) last_file->arelt_data; + h = (struct ar_hdr *) t->arch_header; + size = strtol (h->ar_size, (char **) NULL, 10); + + /* 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. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return alpha_ecoff_get_elt_at_filepos (archive, filestart); +} + +/* Open the archive file given an index into the armap. */ + +static bfd * +alpha_ecoff_get_elt_at_index (abfd, index) + bfd *abfd; + symindex index; +{ + carsym *entry; + + entry = bfd_ardata (abfd)->symdefs + index; + return alpha_ecoff_get_elt_at_filepos (abfd, entry->file_offset); +} + +/* This is the ECOFF backend structure. The backend field of the + target vector points to this. */ + +static const struct ecoff_backend_data alpha_ecoff_backend_data = +{ + /* COFF backend structure. */ + { + (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */ + (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */ + (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */ + (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */ + alpha_ecoff_swap_filehdr_out, alpha_ecoff_swap_aouthdr_out, + alpha_ecoff_swap_scnhdr_out, + FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, true, + alpha_ecoff_swap_filehdr_in, alpha_ecoff_swap_aouthdr_in, + alpha_ecoff_swap_scnhdr_in, NULL, + alpha_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, + alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, + _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }, + /* Supported architecture. */ + bfd_arch_alpha, + /* Initial portion of armap string. */ + "________64", + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + 0x2000, + /* True if the .rdata section is part of the text segment, as on the + Alpha. False if .rdata is part of the data segment, as on the + MIPS. */ + true, + /* Bitsize of constructor entries. */ + 64, + /* Reloc to use for constructor entries. */ + &alpha_howto_table[ALPHA_R_REFQUAD], + { + /* Symbol table magic number. */ + magicSym2, + /* Alignment of debugging information. E.g., 4. */ + 8, + /* Sizes of external symbolic information. */ + sizeof (struct hdr_ext), + sizeof (struct dnr_ext), + sizeof (struct pdr_ext), + sizeof (struct sym_ext), + sizeof (struct opt_ext), + sizeof (struct fdr_ext), + sizeof (struct rfd_ext), + sizeof (struct ext_ext), + /* Functions to swap in external symbolic data. */ + ecoff_swap_hdr_in, + ecoff_swap_dnr_in, + ecoff_swap_pdr_in, + ecoff_swap_sym_in, + ecoff_swap_opt_in, + ecoff_swap_fdr_in, + ecoff_swap_rfd_in, + ecoff_swap_ext_in, + _bfd_ecoff_swap_tir_in, + _bfd_ecoff_swap_rndx_in, + /* Functions to swap out external symbolic data. */ + ecoff_swap_hdr_out, + ecoff_swap_dnr_out, + ecoff_swap_pdr_out, + ecoff_swap_sym_out, + ecoff_swap_opt_out, + ecoff_swap_fdr_out, + ecoff_swap_rfd_out, + ecoff_swap_ext_out, + _bfd_ecoff_swap_tir_out, + _bfd_ecoff_swap_rndx_out, + /* Function to read in symbolic data. */ + _bfd_ecoff_slurp_symbolic_info + }, + /* External reloc size. */ + RELSZ, + /* Reloc swapping functions. */ + alpha_ecoff_swap_reloc_in, + alpha_ecoff_swap_reloc_out, + /* Backend reloc tweaking. */ + alpha_adjust_reloc_in, + alpha_adjust_reloc_out, + /* Relocate section contents while linking. */ + alpha_relocate_section, + /* Do final adjustments to filehdr and aouthdr. */ + alpha_adjust_headers, + /* Read an element from an archive at a given file position. */ + alpha_ecoff_get_elt_at_filepos +}; + +/* Looking up a reloc type is Alpha specific. */ +#define _bfd_ecoff_bfd_reloc_type_lookup alpha_bfd_reloc_type_lookup + +/* So is getting relocated section contents. */ +#define _bfd_ecoff_bfd_get_relocated_section_contents \ + alpha_ecoff_get_relocated_section_contents + +/* Handling file windows is generic. */ +#define _bfd_ecoff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +/* Relaxing sections is generic. */ +#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section + +const bfd_target ecoffalpha_little_vec = +{ + "ecoff-littlealpha", /* name */ + bfd_target_ecoff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, alpha_ecoff_object_p, /* bfd_check_format */ + _bfd_ecoff_archive_p, _bfd_dummy_target}, + {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), + BFD_JUMP_TABLE_COPY (_bfd_ecoff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (alpha_ecoff), + BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), + BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), + BFD_JUMP_TABLE_WRITE (_bfd_ecoff), + BFD_JUMP_TABLE_LINK (_bfd_ecoff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) &alpha_ecoff_backend_data +}; diff --git a/contrib/gdb/bfd/coff-apollo.c b/contrib/gdb/bfd/coff-apollo.c new file mode 100644 index 000000000000..561b1c7ab62f --- /dev/null +++ b/contrib/gdb/bfd/coff-apollo.c @@ -0,0 +1,162 @@ +/* BFD back-end for Apollo 68000 COFF binaries. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + By Troy Rollo (troy@cbme.unsw.edu.au) + Based on m68k standard COFF version Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/apollo.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +#ifdef ONLY_DECLARE_RELOCS +extern reloc_howto_type apollocoff_howto_table[]; +#else +reloc_howto_type apollocoff_howto_table[] = +{ + HOWTO(R_RELBYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_RELWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, 0, "16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_RELLONG, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "32", true, 0xffffffff,0xffffffff, false), + HOWTO(R_PCRBYTE, 0, 0, 8, true, 0, complain_overflow_signed, 0, "DISP8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_PCRWORD, 0, 1, 16, true, 0, complain_overflow_signed, 0, "DISP16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_PCRLONG, 0, 2, 32, true, 0, complain_overflow_signed, 0, "DISP32", true, 0xffffffff,0xffffffff, false), + HOWTO(R_RELLONG_NEG, 0, -2, 32, false, 0, complain_overflow_bitfield, 0, "-32", true, 0xffffffff,0xffffffff, false), +}; +#endif /* not ONLY_DECLARE_RELOCS */ + +#ifndef BADMAG +#define BADMAG(x) M68KBADMAG(x) +#endif +#define APOLLO_M68 1 /* Customize coffcode.h */ + +/* Turn a howto into a reloc number */ + +#ifdef ONLY_DECLARE_RELOCS +extern void apollo_rtype2howto PARAMS ((arelent *internal, int relocentry)); +extern int apollo_howto2rtype PARAMS ((reloc_howto_type *)); +#else +void +apollo_rtype2howto(internal, relocentry) + arelent *internal; + int relocentry; +{ + switch (relocentry) + { + case R_RELBYTE: internal->howto = apollocoff_howto_table + 0; break; + case R_RELWORD: internal->howto = apollocoff_howto_table + 1; break; + case R_RELLONG: internal->howto = apollocoff_howto_table + 2; break; + case R_PCRBYTE: internal->howto = apollocoff_howto_table + 3; break; + case R_PCRWORD: internal->howto = apollocoff_howto_table + 4; break; + case R_PCRLONG: internal->howto = apollocoff_howto_table + 5; break; + case R_RELLONG_NEG: internal->howto = apollocoff_howto_table + 6; break; + } +} + +int +apollo_howto2rtype (internal) + reloc_howto_type *internal; +{ + if (internal->pc_relative) + { + switch (internal->bitsize) + { + case 32: return R_PCRLONG; + case 16: return R_PCRWORD; + case 8: return R_PCRBYTE; + } + } + else + { + switch (internal->bitsize) + { + case 32: return R_RELLONG; + case 16: return R_RELWORD; + case 8: return R_RELBYTE; + } + } + return R_RELLONG; +} +#endif /* not ONLY_DECLARE_RELOCS */ + +#define RTYPE2HOWTO(internal, relocentry) \ + apollo_rtype2howto(internal, (relocentry)->r_type) + +#define SELECT_RELOC(external, internal) \ + external.r_type = apollo_howto2rtype(internal); + +#include "coffcode.h" + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + apollocoff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "apollo-m68k", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ +#ifdef NAMES_HAVE_UNDERSCORE + '_', +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE + }; diff --git a/contrib/gdb/bfd/coff-arm.c b/contrib/gdb/bfd/coff-arm.c new file mode 100644 index 000000000000..bb16b046ae14 --- /dev/null +++ b/contrib/gdb/bfd/coff-arm.c @@ -0,0 +1,537 @@ +/* BFD back-end for ARM COFF files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +#include "coff/arm.h" + +#include "coff/internal.h" + +#ifdef COFF_WITH_PE +#include "coff/pe.h" +#endif + +#include "libcoff.h" + +static bfd_reloc_status_type +aoutarm_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +aoutarm_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + + +static bfd_reloc_status_type coff_arm_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + + +/* Used by the assembler. */ +static bfd_reloc_status_type +coff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + diff = reloc_entry->addend; + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + +#ifndef PCRELOFFSET +#define PCRELOFFSET true +#endif + +static reloc_howto_type aoutarm_std_reloc_howto[] = +{ + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ + HOWTO(0, /* type */ + 0, /* rs */ + 0, /* size */ + 8, /* bsz */ + false, /* pcrel */ + 0, /* bitpos */ + complain_overflow_bitfield, /* ovf */ + coff_arm_reloc, /* sf */ + "8", /*name */ + true, /* partial */ + 0x000000ff, /*read mask */ + 0x000000ff, /* setmask */ + PCRELOFFSET /* pcdone */), + HOWTO(1, + 0, + 1, + 16, + false, + 0, + complain_overflow_bitfield, + coff_arm_reloc, + "16", + true, + 0x0000ffff, + 0x0000ffff, + PCRELOFFSET), + HOWTO( 2, + 0, + 2, + 32, + false, + 0, + complain_overflow_bitfield, + coff_arm_reloc, + "32", + true, + 0xffffffff, + 0xffffffff, + PCRELOFFSET), + HOWTO( 3, + 2, + 2, + 26, + true, + 0, + complain_overflow_signed, + aoutarm_fix_pcrel_26 , + "ARM26", + false, + 0x00ffffff, + 0x00ffffff, + PCRELOFFSET), + HOWTO( 4, + 0, + 0, + 8, + true, + 0, + complain_overflow_signed, + coff_arm_reloc, + "DISP8", + true, + 0x000000ff, + 0x000000ff, + true), + HOWTO( 5, + 0, + 1, + 16, + true, + 0, + complain_overflow_signed, + coff_arm_reloc, + "DISP16", + true, + 0x0000ffff, + 0x0000ffff, + true), + HOWTO( 6, + 0, + 2, + 32, + true, + 0, + complain_overflow_signed, + coff_arm_reloc, + "DISP32", + true, + 0xffffffff, + 0xffffffff, + true), + HOWTO( 7, + 2, + 2, + 26, + false, + 0, + complain_overflow_signed, + aoutarm_fix_pcrel_26_done, + "ARM26D", + true, + 0x00ffffff, + 0x00ffffff, + false), + {-1}, + HOWTO( 9, + 0, + -1, + 16, + false, + 0, + complain_overflow_bitfield, + coff_arm_reloc, + "NEG16", + true, + 0x0000ffff, + 0x0000ffff, + false), + HOWTO( 10, + 0, + -2, + 32, + false, + 0, + complain_overflow_bitfield, + coff_arm_reloc, + "NEG32", + true, + 0xffffffff, + 0xffffffff, + false), + HOWTO( 11, + 0, + 2, + 32, + false, + 0, + complain_overflow_bitfield, + coff_arm_reloc, + "rva32", + true, + 0xffffffff, + 0xffffffff, + PCRELOFFSET), +}; +#ifdef COFF_WITH_PE +/* Return true if this relocation should + appear in the output .reloc section. */ + +static boolean in_reloc_p (abfd, howto) + bfd * abfd; + reloc_howto_type *howto; +{ + return !howto->pc_relative && howto->type != 11; +} +#endif + + +#define RTYPE2HOWTO(cache_ptr, dst) \ + (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type; + +#define coff_rtype_to_howto coff_arm_rtype_to_howto + +static reloc_howto_type * +coff_arm_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + reloc_howto_type *howto; + + howto = aoutarm_std_reloc_howto + rel->r_type; + + if (rel->r_type == 11) + { + *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; + } + return howto; + +} +/* Used by the assembler. */ + +static bfd_reloc_status_type +aoutarm_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* This is dead simple at present. */ + return bfd_reloc_ok; +} + +/* Used by the assembler. */ + +static bfd_reloc_status_type +aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_size_type addr = reloc_entry->address; + long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); + bfd_reloc_status_type flag = bfd_reloc_ok; + + /* If this is an undefined symbol, return error */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0) + return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; + + /* If the sections are different, and we are doing a partial relocation, + just ignore it for now. */ + if (symbol->section->name != input_section->name + && output_bfd != (bfd *)NULL) + return bfd_reloc_continue; + + relocation = (target & 0x00ffffff) << 2; + relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */ + relocation += symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + relocation -= input_section->output_section->vma; + relocation -= input_section->output_offset; + relocation -= addr; + if (relocation & 3) + return bfd_reloc_overflow; + + /* Check for overflow */ + if (relocation & 0x02000000) + { + if ((relocation & ~0x03ffffff) != ~0x03ffffff) + flag = bfd_reloc_overflow; + } + else if (relocation & ~0x03ffffff) + flag = bfd_reloc_overflow; + + target &= ~0x00ffffff; + target |= (relocation >> 2) & 0x00ffffff; + bfd_put_32 (abfd, target, (bfd_byte *) data + addr); + + /* Now the ARM magic... Change the reloc type so that it is marked as done. + Strictly this is only necessary if we are doing a partial relocation. */ + reloc_entry->howto = &aoutarm_std_reloc_howto[7]; + + return flag; +} + + +static CONST struct reloc_howto_struct * +arm_reloc_type_lookup(abfd,code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ +#define ASTD(i,j) case i: return &aoutarm_std_reloc_howto[j] + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + default: return (CONST struct reloc_howto_struct *) 0; + } + + switch (code) + { + ASTD (BFD_RELOC_16, 1); + ASTD (BFD_RELOC_32, 2); + ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3); + ASTD (BFD_RELOC_8_PCREL, 4); + ASTD (BFD_RELOC_16_PCREL, 5); + ASTD (BFD_RELOC_32_PCREL, 6); + ASTD (BFD_RELOC_RVA, 11); + default: return (CONST struct reloc_howto_struct *) 0; + } +} + + +#define coff_bfd_reloc_type_lookup arm_reloc_type_lookup + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) +#define COFF_PAGE_SIZE 0x1000 +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define BADMAG(x) ARMBADMAG(x) +#define ARM 1 /* Customize coffcode.h */ + + +/* We use the special COFF backend linker. */ +#define coff_relocate_section _bfd_coff_generic_relocate_section + + +#include "coffcode.h" + +const bfd_target +#ifdef TARGET_LITTLE_SYM +TARGET_LITTLE_SYM = +#else +armcoff_little_vec = +#endif +{ +#ifdef TARGET_LITTLE_NAME + TARGET_LITTLE_NAME, +#else + "coff-arm-little", +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ +#ifdef TARGET_UNDERSCORE + TARGET_UNDERSCORE, /* leading underscore */ +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; + +const bfd_target +#ifdef TARGET_BIG_SYM +TARGET_BIG_SYM = +#else +armcoff_big_vec = +#endif +{ +#ifdef TARGET_BIG_NAME + TARGET_BIG_NAME, +#else + "coff-arm-big", +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ +#ifdef TARGET_UNDERSCORE + TARGET_UNDERSCORE, /* leading underscore */ +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-aux.c b/contrib/gdb/bfd/coff-aux.c new file mode 100644 index 000000000000..1dba9d5c465a --- /dev/null +++ b/contrib/gdb/bfd/coff-aux.c @@ -0,0 +1,332 @@ +/* BFD back-end for Apple M68K COFF A/UX 3.x files. + Copyright 1996 Free Software Foundation, Inc. + Portions written by Richard Henderson , + COMMON symbol munging cribbed from cf-m68klynx.c which was + written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM m68kaux_coff_vec +#define TARGET_NAME "coff-m68k-aux" + +#ifndef TARG_AUX +#define TARG_AUX +#endif + +#define COFF_LONG_FILENAMES + +/* 4k pages */ +#define COFF_PAGE_SIZE 0x1000 + +/* On AUX, a STYP_NOLOAD|STYP_BSS section is part of a shared library. */ +#define BSS_NOLOAD_IS_SHARED_LIBRARY + +#define _bfd_m68kcoff_howto_table _bfd_m68kaux_howto_table +#define _bfd_m68kcoff_rtype2howto _bfd_m68kaux_rtype2howto +#define _bfd_m68kcoff_howto2rtype _bfd_m68kaux_howto2rtype +#define _bfd_m68kcoff_reloc_type_lookup _bfd_m68kaux_reloc_type_lookup + +/* Rather than change names lots of places, reuse the same hack */ +#define LYNX_SPECIAL_FN _bfd_m68kaux_special_fn + +#include "bfd.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +struct internal_reloc; +struct coff_link_hash_entry; +struct internal_syment; +#endif + + +static bfd_reloc_status_type _bfd_m68kaux_special_fn + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *coff_m68k_aux_rtype_to_howto + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *)); +static boolean coff_m68k_aux_link_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, + asection *, bfd_vma, const char *, boolean, boolean, + struct bfd_link_hash_entry **)); + + +#define coff_rtype_to_howto coff_m68k_aux_rtype_to_howto +#define coff_link_add_one_symbol coff_m68k_aux_link_add_one_symbol + + +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && (reloc.r_type == R_PCRBYTE \ + || reloc.r_type == R_PCRWORD \ + || reloc.r_type == R_PCRLONG)) \ + cache_ptr->addend += asect->vma; \ + } + + + +#include "coff/aux-coff.h" /* override coff/internal.h and coff/m68k.h */ +#include "coff-m68k.c" + + + +/* For some reason when using m68k COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. (taken from work done by Ian Taylor, Cygnus Support, + for I386 COFF). */ + +/* If we are producing relocateable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +_bfd_m68kaux_special_fn (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + if (bfd_is_com_section (symbol->section)) + { + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocateable output. This seems to be always wrong for 386 + COFF, so we handle the addend here instead. */ + diff = reloc_entry->addend; + } + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | \ + (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + + +/* coff-m68k.c uses the special COFF backend linker. We need to + adjust common symbols. */ + +/*ARGSUSED*/ +static reloc_howto_type * +coff_m68k_aux_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + arelent relent; + reloc_howto_type *howto; + + RTYPE2HOWTO (&relent, rel); + + howto = relent.howto; + + if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) + { + /* This is a common symbol. The section contents include the + size (sym->n_value) as an addend. The relocate_section + function will be adding in the final value of the symbol. We + need to subtract out the current size in order to get the + correct result. */ + BFD_ASSERT (h != NULL); + *addendp -= sym->n_value; + } + + /* If the output symbol is common (in which case this must be a + relocateable link), we need to add in the final size of the + common symbol. */ + if (h != NULL && h->root.type == bfd_link_hash_common) + *addendp += h->root.u.c.size; + + return howto; +} + + +/* We need non-absolute symbols to override absolute symbols. This + mirrors Apple's "solution" to let a static library symbol override + a shared library symbol. On the whole not a good thing, given how + shared libraries work here, but can work if you are careful with + what you include in the shared object. */ + +boolean +coff_m68k_aux_link_add_one_symbol (info, abfd, name, flags, section, value, + string, copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + struct bfd_link_hash_entry *h; + + if ((flags & (BSF_WARNING | BSF_CONSTRUCTOR | BSF_WEAK)) == 0 && + !bfd_is_und_section (section) && + !bfd_is_com_section (section)) + { + /* The new symbol is a definition or an indirect definition */ + + /* This bit copied from linker.c */ + if (hashp != NULL && *hashp != NULL) + { + h = *hashp; + BFD_ASSERT (strcmp (h->root.string, name) == 0); + } + else + { + h = bfd_link_hash_lookup (info->hash, name, true, copy, false); + if (h == NULL) + { + if (hashp != NULL) + *hashp = NULL; + return false; + } + } + + if (info->notice_hash != (struct bfd_hash_table *) NULL + && (bfd_hash_lookup (info->notice_hash, name, false, false) + != (struct bfd_hash_entry *) NULL)) + { + if (! (*info->callbacks->notice) (info, name, abfd, section, value)) + return false; + } + + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = h; + /* end duplication from linker.c */ + + if (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_indirect) + { + asection *msec; + + if (h->type == bfd_link_hash_defined) + msec = h->u.def.section; + else + msec = bfd_ind_section_ptr; + + if (bfd_is_abs_section (msec) && !bfd_is_abs_section (section)) + { + h->u.def.section = section; + h->u.def.value = value; + return true; + } + else if (bfd_is_abs_section (section) && !bfd_is_abs_section (msec)) + return true; + } + } + + /* If we didn't exit early, finish processing in the generic routine */ + return _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, + value, string, copy, collect, + hashp); +} diff --git a/contrib/gdb/bfd/coff-go32.c b/contrib/gdb/bfd/coff-go32.c new file mode 100644 index 000000000000..be4adb24f529 --- /dev/null +++ b/contrib/gdb/bfd/coff-go32.c @@ -0,0 +1,25 @@ +/* BFD back-end for Intel 386 COFF files (go32 variant). + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by DJ Delorie. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM go32coff_vec +#define TARGET_NAME "coff-go32" +#define TARGET_UNDERSCORE '_' + +#include "coff-i386.c" diff --git a/contrib/gdb/bfd/coff-h8300.c b/contrib/gdb/bfd/coff-h8300.c new file mode 100644 index 000000000000..48d0d5a213b7 --- /dev/null +++ b/contrib/gdb/bfd/coff-h8300.c @@ -0,0 +1,650 @@ +/* BFD back-end for Hitachi H8/300 COFF binaries. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "coff/h8300.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) + + +/* special handling for H8/300 relocs. + We only come here for pcrel stuff and return normally if not an -r link. + When doing -r, we can't do any arithmetic for the pcrel stuff, because + the code in reloc.c assumes that we can manipulate the targets of + the pcrel branches. This isn't so, since the H8/300 can do relaxing, + which means that the gap after the instruction may not be enough to + contain the offset required for the branch, so we have to use the only + the addend until the final link */ + +static bfd_reloc_status_type +special (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_ok; +} + +static reloc_howto_type howto_table[] = +{ + HOWTO (R_RELBYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "8", false, 0x000000ff, 0x000000ff, false), + HOWTO (R_RELWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "16", false, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_RELLONG, 0, 2, 32, false, 0, complain_overflow_bitfield, special, "32", false, 0xffffffff, 0xffffffff, false), + HOWTO (R_PCRBYTE, 0, 0, 8, true, 0, complain_overflow_signed, special, "DISP8", false, 0x000000ff, 0x000000ff, true), + HOWTO (R_PCRWORD, 0, 1, 16, true, 0, complain_overflow_signed, special, "DISP16", false, 0x0000ffff, 0x0000ffff, true), + HOWTO (R_PCRLONG, 0, 2, 32, true, 0, complain_overflow_signed, special, "DISP32", false, 0xffffffff, 0xffffffff, true), + HOWTO (R_MOVB1, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "16/8", false, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_MOVB2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "8/16", false, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_JMP1, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "16/pcrel", false, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_JMP2, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "pcrecl/16", false, 0x000000ff, 0x000000ff, false), + + + HOWTO (R_JMPL1, 0, 2, 32, false, 0, complain_overflow_bitfield, special, "24/pcrell", false, 0x00ffffff, 0x00ffffff, false), + HOWTO (R_JMPL_B8, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "pc8/24", false, 0x000000ff, 0x000000ff, false), + + HOWTO (R_MOVLB1, 0, 1, 16, false, 0, complain_overflow_bitfield,special, "24/8", false, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_MOVLB2, 0, 1, 16, false, 0, complain_overflow_bitfield, special, "8/24", false, 0x0000ffff, 0x0000ffff, false), + + /* An indirect reference to a function. This causes the function's address + to be added to the function vector in lo-mem and puts the address of + the function vector's entry in the jsr instruction. */ + HOWTO (R_MEM_INDIRECT, 0, 0, 8, false, 0, complain_overflow_bitfield, special, "8/indirect", false, 0x000000ff, 0x000000ff, false), + +}; + + +/* Turn a howto into a reloc number */ + +#define SELECT_RELOC(x,howto) \ + { x.r_type = select_reloc(howto); } + +#define BADMAG(x) (H8300BADMAG(x)&& H8300HBADMAG(x)) +#define H8300 1 /* Customize coffcode.h */ +#define __A_MAGIC_SET__ + + + +/* Code to swap in the reloc */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 +#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ + dst->r_stuff[0] = 'S'; \ + dst->r_stuff[1] = 'C'; + + +static int +select_reloc (howto) + reloc_howto_type *howto; +{ + return howto->type; +} + +/* Code to turn a r_type into a howto ptr, uses the above howto table + */ + +static void +rtype2howto (internal, dst) + arelent *internal; + struct internal_reloc *dst; +{ + switch (dst->r_type) + { + case R_RELBYTE: + internal->howto = howto_table + 0; + break; + case R_RELWORD: + internal->howto = howto_table + 1; + break; + case R_RELLONG: + internal->howto = howto_table + 2; + break; + case R_PCRBYTE: + internal->howto = howto_table + 3; + break; + case R_PCRWORD: + internal->howto = howto_table + 4; + break; + case R_PCRLONG: + internal->howto = howto_table + 5; + break; + case R_MOVB1: + internal->howto = howto_table + 6; + break; + case R_MOVB2: + internal->howto = howto_table + 7; + break; + case R_JMP1: + internal->howto = howto_table + 8; + break; + case R_JMP2: + internal->howto = howto_table + 9; + break; + case R_JMPL1: + internal->howto = howto_table + 10; + break; + case R_JMPL_B8: + internal->howto = howto_table + 11; + break; + case R_MOVLB1: + internal->howto = howto_table + 12; + break; + case R_MOVLB2: + internal->howto = howto_table + 13; + break; + case R_MEM_INDIRECT: + internal->howto = howto_table + 14; + break; + default: + abort (); + break; + } +} + +#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) + + +/* Perform any necessaru magic to the addend in a reloc entry */ + + +#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ + cache_ptr->addend = ext_reloc.r_offset; + + +#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void +reloc_processing (relent, reloc, symbols, abfd, section) + arelent * relent; + struct internal_reloc *reloc; + asymbol ** symbols; + bfd * abfd; + asection * section; +{ + relent->address = reloc->r_vaddr; + rtype2howto (relent, reloc); + + if (((int) reloc->r_symndx) > 0) + { + relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; + } + else + { + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + + + + relent->addend = reloc->r_offset; + + relent->address -= section->vma; + /* relent->section = 0;*/ +} + + +static int +h8300_reloc16_estimate(abfd, input_section, reloc, shrink, link_info) + bfd *abfd; + asection *input_section; + arelent *reloc; + unsigned int shrink; + struct bfd_link_info *link_info; +{ + bfd_vma value; + bfd_vma dot; + bfd_vma gap; + + /* The address of the thing to be relocated will have moved back by + the size of the shrink - but we don't change reloc->address here, + since we need it to know where the relocation lives in the source + uncooked section */ + + /* reloc->address -= shrink; conceptual */ + + bfd_vma address = reloc->address - shrink; + + + switch (reloc->howto->type) + { + case R_MOVB2: + case R_JMP2: + shrink+=2; + break; + + /* Thing is a move one byte */ + case R_MOVB1: + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + if (value >= 0xff00) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + reloc->howto = reloc->howto + 1; + /* The place to relc moves back by one */ + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + + break; + /* This is the 24 bit branch which could become an 8 bitter, + the relocation points to the first byte of the insn, not the + actual data */ + + case R_JMPL1: + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + dot = input_section->output_section->vma + + input_section->output_offset + address; + + /* See if the address we're looking at within 127 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - dot ; + + if (-120 < (long)gap && (long)gap < 120 ) + { + + /* Change the reloc type from 24bit, possible 8 to 8bit + possible 32 */ + reloc->howto = reloc->howto + 1; + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + break; + + case R_JMP1: + + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + dot = input_section->output_section->vma + + input_section->output_offset + address; + + /* See if the address we're looking at within 127 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - (dot - shrink); + + + if (-120 < (long)gap && (long)gap < 120 ) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + reloc->howto = reloc->howto + 1; + /* The place to relc moves back by one */ + + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + break; + } + + + return shrink; +} + + +/* First phase of a relaxing link */ + +/* Reloc types + large small + R_MOVB1 R_MOVB2 mov.b with 16bit or 8 bit address + R_JMP1 R_JMP2 jmp or pcrel branch + R_JMPL1 R_JMPL_B8 24jmp or pcrel branch + R_MOVLB1 R_MOVLB2 24 or 8 bit reloc for mov.b + +*/ + +static void +h8300_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr, + dst_ptr) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + unsigned int src_address = *src_ptr; + unsigned int dst_address = *dst_ptr; + asection *input_section = link_order->u.indirect.section; + + switch (reloc->howto->type) + { + /* A 24 bit branch which could be a 8 bit pcrel, really pointing to + the byte before the 24bit hole, so we can treat it as a 32bit pointer */ + case R_PCRBYTE: + { + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + - dot); + if (gap > 127 || gap < -128) + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + gap &= ~1; + bfd_put_8 (abfd, gap, data + dst_address); + dst_address++; + src_address++; + + break; + } + case R_PCRWORD: + { + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + - dot) - 1; + if (gap > 32767 || gap < -32768) + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + + bfd_put_16 (abfd, gap, data + dst_address); + dst_address+=2; + src_address+=2; + + break; + } + + case R_MEM_INDIRECT: /* Temporary */ + case R_RELBYTE: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + if (gap < 0xff + || (gap >= 0x0000ff00 + && gap <= 0x0000ffff) + || ( gap >= 0x00ffff00 + && gap <= 0x00ffffff) + || ( gap >= 0xffffff00 + && gap <= 0xffffffff)) + { + bfd_put_8 (abfd, gap, data + dst_address); + dst_address += 1; + src_address += 1; + } + else + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + } + break; + case R_JMP1: + /* A relword which would have like to have been a pcrel */ + case R_MOVB1: + /* A relword which would like to have been modified but + didn't make it */ + case R_RELWORD: + bfd_put_16 (abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + dst_address); + dst_address += 2; + src_address += 2; + break; + case R_RELLONG: + bfd_put_32 (abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + dst_address); + dst_address += 4; + src_address += 4; + break; + + case R_MOVB2: + /* Special relaxed type, there will be a gap between where we + get stuff from and where we put stuff to now + + for a mov.b @aa:16 -> mov.b @aa:8 + opcode 0x6a 0x0y offset + -> 0x2y off + */ + if (data[dst_address - 1] != 0x6a) + abort (); + switch (data[src_address] & 0xf0) + { + case 0x00: + /* Src is memory */ + data[dst_address - 1] = (data[src_address] & 0xf) | 0x20; + break; + case 0x80: + /* Src is reg */ + data[dst_address - 1] = (data[src_address] & 0xf) | 0x30; + break; + default: + abort (); + } + + /* the offset must fit ! after all, what was all the relaxing + about ? */ + + bfd_put_8 (abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + dst_address); + + /* Note the magic - src goes up by two bytes, but dst by only + one */ + dst_address += 1; + src_address += 3; + + break; + + case R_JMP2: + + /* Speciial relaxed type */ + { + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + + int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + - dot - 1); + + if ((gap & ~0xff) != 0 && ((gap & 0xff00) != 0xff00)) + abort (); + + bfd_put_8 (abfd, gap, data + dst_address); + + switch (data[dst_address - 1]) + { + case 0x5e: + /* jsr -> bsr */ + bfd_put_8 (abfd, 0x55, data + dst_address - 1); + break; + case 0x5a: + /* jmp ->bra */ + bfd_put_8 (abfd, 0x40, data + dst_address - 1); + break; + + default: + abort (); + } + dst_address++; + src_address += 3; + + break; + } + break; + + case R_JMPL_B8: /* 24 bit branch which is now 8 bits */ + + /* Speciial relaxed type */ + { + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + + int gap = (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + - dot - 2); + + if ((gap & ~0xff) != 0 && ((gap & 0xff00) != 0xff00)) + abort (); + + switch (data[src_address]) + { + case 0x5e: + /* jsr -> bsr */ + bfd_put_8 (abfd, 0x55, data + dst_address); + break; + case 0x5a: + /* jmp ->bra */ + bfd_put_8 (abfd, 0x40, data + dst_address); + break; + + default: + bfd_put_8 (abfd, 0xde, data + dst_address); + break; + } + + bfd_put_8 (abfd, gap, data + dst_address + 1); + dst_address += 2; + src_address += 4; + + break; + } + + case R_JMPL1: + { + int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section); + int o = bfd_get_32 (abfd, data + src_address); + v = (v & 0x00ffffff) | (o & 0xff000000); + bfd_put_32 (abfd, v, data + dst_address); + dst_address += 4; + src_address += 4; + } + + break; + + + /* A 24 bit mov which could be an 8 bit move, really pointing to + the byte before the 24bit hole, so we can treat it as a 32bit pointer */ + case R_MOVLB1: + { + int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section); + int o = bfd_get_32 (abfd, data + dst_address); + v = (v & 0x00ffffff) | (o & 0xff000000); + bfd_put_32 (abfd, v, data + dst_address); + dst_address += 4; + src_address += 4; + } + + break; + default: + + abort (); + break; + + } + *src_ptr = src_address; + *dst_ptr = dst_address; + +} + +#define coff_reloc16_extra_cases h8300_reloc16_extra_cases +#define coff_reloc16_estimate h8300_reloc16_estimate + +#define COFF_LONG_FILENAMES +#include "coffcode.h" + + +#undef coff_bfd_get_relocated_section_contents +#undef coff_bfd_relax_section +#define coff_bfd_get_relocated_section_contents \ + bfd_coff_reloc16_get_relocated_section_contents +#define coff_bfd_relax_section bfd_coff_reloc16_relax_section + + + +const bfd_target h8300coff_vec = +{ + "coff-h8300", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading char */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-h8500.c b/contrib/gdb/bfd/coff-h8500.c new file mode 100644 index 000000000000..f416f8fa2825 --- /dev/null +++ b/contrib/gdb/bfd/coff-h8500.c @@ -0,0 +1,355 @@ +/* BFD back-end for Hitachi H8/500 COFF binaries. + Copyright 1993, 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Written by Steve Chamberlain, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "coff/h8500.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) + +static reloc_howto_type r_imm8 = +HOWTO (R_H8500_IMM8, 0, 1, 8, false, 0, + complain_overflow_bitfield, 0, "r_imm8", true, 0x000000ff, 0x000000ff, false); + +static reloc_howto_type r_imm16 = +HOWTO (R_H8500_IMM16, 0, 1, 16, false, 0, + complain_overflow_bitfield, 0, "r_imm16", true, 0x0000ffff, 0x0000ffff, false); + +static reloc_howto_type r_imm24 = +HOWTO (R_H8500_IMM24, 0, 1, 24, false, 0, + complain_overflow_bitfield, 0, "r_imm24", true, 0x00ffffff, 0x00ffffff, false); + +static reloc_howto_type r_imm32 = +HOWTO (R_H8500_IMM32, 0, 1, 32, false, 0, + complain_overflow_bitfield, 0, "r_imm32", true, 0xffffffff, 0xffffffff, false); + + +static reloc_howto_type r_high8 = +HOWTO (R_H8500_HIGH8, 0, 1, 8, false, 0, + complain_overflow_dont, 0, "r_high8", true, 0x000000ff, 0x000000ff, false); + +static reloc_howto_type r_low16 = +HOWTO (R_H8500_LOW16, 0, 1, 16, false, 0, + complain_overflow_dont, 0, "r_low16", true, 0x0000ffff, 0x0000ffff, false); + +static reloc_howto_type r_pcrel8 = +HOWTO (R_H8500_PCREL8, 0, 1, 8, true, 0, complain_overflow_signed, 0, "r_pcrel8", true, 0, 0, true); + + +static reloc_howto_type r_pcrel16 = +HOWTO (R_H8500_PCREL16, 0, 1, 16, true, 0, complain_overflow_signed, 0, "r_pcrel16", true, 0, 0, true); + +static reloc_howto_type r_high16 = +HOWTO (R_H8500_HIGH16, 0, 1, 8, false, 0, + complain_overflow_dont, 0, "r_high16", true, 0x000ffff, 0x0000ffff, false); + + +/* Turn a howto into a reloc number */ + +static int +coff_h8500_select_reloc (howto) + reloc_howto_type *howto; +{ + return howto->type; +} + +#define SELECT_RELOC(x,howto) x.r_type = coff_h8500_select_reloc(howto) + + +#define BADMAG(x) H8500BADMAG(x) +#define H8500 1 /* Customize coffcode.h */ + +#define __A_MAGIC_SET__ + +/* Code to swap in the reloc */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 +#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ + dst->r_stuff[0] = 'S'; \ + dst->r_stuff[1] = 'C'; + +/* Code to turn a r_type into a howto ptr, uses the above howto table + */ + +static void +rtype2howto(internal, dst) + arelent * internal; + struct internal_reloc *dst; +{ + switch (dst->r_type) + { + default: + abort (); + break; + case R_H8500_IMM8: + internal->howto = &r_imm8; + break; + case R_H8500_IMM16: + internal->howto = &r_imm16; + break; + case R_H8500_IMM24: + internal->howto = &r_imm24; + break; + case R_H8500_IMM32: + internal->howto = &r_imm32; + break; + case R_H8500_PCREL8: + internal->howto = &r_pcrel8; + break; + case R_H8500_PCREL16: + internal->howto = &r_pcrel16; + break; + case R_H8500_HIGH8: + internal->howto = &r_high8; + break; + case R_H8500_HIGH16: + internal->howto = &r_high16; + break; + case R_H8500_LOW16: + internal->howto = &r_low16; + break; + } +} + +#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) + + +/* Perform any necessaru magic to the addend in a reloc entry */ + + +#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ + cache_ptr->addend = ext_reloc.r_offset; + + +#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void reloc_processing (relent, reloc, symbols, abfd, section) + arelent * relent; + struct internal_reloc *reloc; + asymbol ** symbols; + bfd * abfd; + asection * section; +{ + relent->address = reloc->r_vaddr; + rtype2howto (relent, reloc); + + if (reloc->r_symndx > 0) + { + relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; + } + else + { + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + + + relent->addend = reloc->r_offset; + relent->address -= section->vma; +} + +static void +extra_case (in_abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr) + bfd *in_abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + bfd_byte *d = data+*dst_ptr; + asection *input_section = link_order->u.indirect.section; + switch (reloc->howto->type) + { + case R_H8500_IMM8: + bfd_put_8 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + d); + (*dst_ptr) += 1; + (*src_ptr) += 1; + break; + + case R_H8500_HIGH8: + bfd_put_8 (in_abfd, + (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + >> 16), + d ); + (*dst_ptr) += 1; + (*src_ptr) += 1; + break; + + case R_H8500_IMM16: + bfd_put_16 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + d ); + (*dst_ptr) += 2; + (*src_ptr) += 2; + break; + + case R_H8500_LOW16: + bfd_put_16 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + d); + + (*dst_ptr) += 2; + (*src_ptr) += 2; + break; + + case R_H8500_HIGH16: + bfd_put_16 (in_abfd, + (bfd_coff_reloc16_get_value (reloc, link_info, input_section) + >>16), + d); + + (*dst_ptr) += 2; + (*src_ptr) += 2; + break; + + case R_H8500_IMM24: + { + int v = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + int o = bfd_get_32(in_abfd, data+ *dst_ptr -1); + v = (v & 0x00ffffff) | (o & 0xff00000); + bfd_put_32 (in_abfd, v, data + *dst_ptr -1); + (*dst_ptr) +=3; + (*src_ptr)+=3;; + } + break; + case R_H8500_IMM32: + { + int v = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + bfd_put_32 (in_abfd, v, data + *dst_ptr); + (*dst_ptr) +=4; + (*src_ptr)+=4;; + } + break; + + + case R_H8500_PCREL8: + { + bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_vma dot = link_order->offset + + *dst_ptr + + link_order->u.indirect.section->output_section->vma; + int gap = dst - dot - 1; /* -1 since were in the odd byte of the + word and the pc's been incremented */ + + if (gap > 128 || gap < -128) + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + bfd_put_8 (in_abfd, gap, data + *dst_ptr); + (*dst_ptr)++; + (*src_ptr)++; + break; + } + case R_H8500_PCREL16: + { + bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_vma dot = link_order->offset + + *dst_ptr + + link_order->u.indirect.section->output_section->vma; + int gap = dst - dot - 1; /* -1 since were in the odd byte of the + word and the pc's been incremented */ + + if (gap > 32767 || gap < -32768) + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + bfd_put_16 (in_abfd, gap, data + *dst_ptr); + (*dst_ptr)+=2; + (*src_ptr)+=2; + break; + } + + default: + abort (); + } +} + +#define coff_reloc16_extra_cases extra_case + +#include "coffcode.h" + + +#undef coff_bfd_get_relocated_section_contents +#undef coff_bfd_relax_section +#define coff_bfd_get_relocated_section_contents \ + bfd_coff_reloc16_get_relocated_section_contents +#define coff_bfd_relax_section bfd_coff_reloc16_relax_section + +const bfd_target h8500coff_vec = +{ + "coff-h8500", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading symbol underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-i386.c b/contrib/gdb/bfd/coff-i386.c new file mode 100644 index 000000000000..d905b53cda83 --- /dev/null +++ b/contrib/gdb/bfd/coff-i386.c @@ -0,0 +1,493 @@ +/* BFD back-end for Intel 386 COFF files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +#include "coff/i386.h" + +#include "coff/internal.h" + +#ifdef COFF_WITH_PE +#include "coff/pe.h" +#endif + +#include "libcoff.h" + +static bfd_reloc_status_type coff_i386_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *coff_i386_rtype_to_howto + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + + bfd_vma *)); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) +/* The page size is a guess based on ELF. */ + +#define COFF_PAGE_SIZE 0x1000 + +/* For some reason when using i386 COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. Ian Taylor, Cygnus Support. */ + +/* If we are producing relocateable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +coff_i386_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + + if (bfd_is_com_section (symbol->section)) + { + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocateable output. This seems to be always wrong for 386 + COFF, so we handle the addend here instead. */ + diff = reloc_entry->addend; + } + + +#ifdef COFF_WITH_PE + if (reloc_entry->howto->type == 7) + { +/* diff -= coff_data(output_bfd)->link_info->pe_info.image_base.value;*/ + exit(1); + } +#endif + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + +#ifdef COFF_WITH_PE +/* Return true if this relocation should + appear in the output .reloc section. */ + +static boolean in_reloc_p(abfd, howto) + bfd * abfd; + reloc_howto_type *howto; +{ + return ! howto->pc_relative && howto->type != R_IMAGEBASE; +} +#endif + +#ifndef PCRELOFFSET +#define PCRELOFFSET false +#endif + +static reloc_howto_type howto_table[] = +{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + HOWTO (R_DIR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "dir32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + /* {7}, */ + HOWTO (R_IMAGEBASE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "rva32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + {010}, + {011}, + {012}, + {013}, + {014}, + {015}, + {016}, + HOWTO (R_RELBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_RELWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_RELLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET) /* pcrel_offset */ +}; + +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define BADMAG(x) I386BADMAG(x) +#define I386 1 /* Customize coffcode.h */ + +#define RTYPE2HOWTO(cache_ptr, dst) \ + (cache_ptr)->howto = howto_table + (dst)->r_type; + +/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared + library. On some other COFF targets STYP_BSS is normally + STYP_NOLOAD. */ +#define BSS_NOLOAD_IS_SHARED_LIBRARY + +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && howto_table[reloc.r_type].pc_relative) \ + cache_ptr->addend += asect->vma; \ + } + +/* We use the special COFF backend linker. */ +#define coff_relocate_section _bfd_coff_generic_relocate_section + +static reloc_howto_type * +coff_i386_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + + reloc_howto_type *howto; + + howto = howto_table + rel->r_type; + +#ifdef COFF_WITH_PE + *addendp = 0; +#endif + + if (howto->pc_relative) + *addendp += sec->vma; + + if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) + { + /* This is a common symbol. The section contents include the + size (sym->n_value) as an addend. The relocate_section + function will be adding in the final value of the symbol. We + need to subtract out the current size in order to get the + correct result. */ + + BFD_ASSERT (h != NULL); + + +#ifndef COFF_WITH_PE + /* I think we *do* want to bypass this. If we don't, I have seen some data + parameters get the wrong relcation address. If I link two versions + with and without this section bypassed and then do a binary comparison, + the addresses which are different can be looked up in the map. The + case in which this section has been bypassed has addresses which correspond + to values I can find in the map */ + *addendp -= sym->n_value; +#endif + } + + /* If the output symbol is common (in which case this must be a + relocateable link), we need to add in the final size of the + common symbol. */ + if (h != NULL && h->root.type == bfd_link_hash_common) + *addendp += h->root.u.c.size; + + +#ifdef COFF_WITH_PE + if (howto->pc_relative) + *addendp -= 4; + + if (rel->r_type == R_IMAGEBASE) + { + *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; + } +#endif + + return howto; +} + + +#define coff_bfd_reloc_type_lookup coff_i386_reloc_type_lookup + + +static reloc_howto_type * +coff_i386_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_RVA: + return howto_table +R_IMAGEBASE; + case BFD_RELOC_32: + return howto_table + R_DIR32; + case BFD_RELOC_32_PCREL: + return howto_table + R_PCRLONG; + default: + BFD_FAIL (); + return 0; + } +} + + + +#define coff_rtype_to_howto coff_i386_rtype_to_howto + +#include "coffcode.h" + +static const bfd_target * +i3coff_object_p(a) + bfd *a; +{ + return coff_object_p(a); +} + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + i386coff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-i386", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ +#ifdef TARGET_UNDERSCORE + TARGET_UNDERSCORE, /* leading underscore */ +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, i3coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-i860.c b/contrib/gdb/bfd/coff-i860.c new file mode 100644 index 000000000000..9605cdf0b852 --- /dev/null +++ b/contrib/gdb/bfd/coff-i860.c @@ -0,0 +1,423 @@ +/* BFD back-end for Intel 860 COFF files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Created mostly by substituting "860" for "386" in coff-i386.c + Harry Dolan , October 1995 + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +#include "coff/i860.h" + +#include "coff/internal.h" + +#include "libcoff.h" + +static bfd_reloc_status_type coff_i860_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *coff_i860_rtype_to_howto + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *)); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) +/* The page size is a guess based on ELF. */ + +#define COFF_PAGE_SIZE 0x1000 + +/* For some reason when using i860 COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. Ian Taylor, Cygnus Support. */ + +/* If we are producing relocateable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +coff_i860_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + + if (bfd_is_com_section (symbol->section)) + { + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocateable output. This seems to be always wrong for 860 + COFF, so we handle the addend here instead. */ + diff = reloc_entry->addend; + } + + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + +#ifndef PCRELOFFSET +#define PCRELOFFSET false +#endif + +static reloc_howto_type howto_table[] = +{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + HOWTO (R_DIR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "dir32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + /* {7}, */ + HOWTO (R_IMAGEBASE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "rva32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + {010}, + {011}, + {012}, + {013}, + {014}, + {015}, + {016}, + HOWTO (R_RELBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_RELWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_RELLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "DISP8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "DISP16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + PCRELOFFSET), /* pcrel_offset */ + HOWTO (R_PCRLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i860_reloc, /* special_function */ + "DISP32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + PCRELOFFSET) /* pcrel_offset */ +}; + +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define BADMAG(x) I860BADMAG(x) +#define I860 1 /* Customize coffcode.h */ + +#define RTYPE2HOWTO(cache_ptr, dst) \ + (cache_ptr)->howto = howto_table + (dst)->r_type; + +/* For 860 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared + library. On some other COFF targets STYP_BSS is normally + STYP_NOLOAD. */ +#define BSS_NOLOAD_IS_SHARED_LIBRARY + +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && howto_table[reloc.r_type].pc_relative) \ + cache_ptr->addend += asect->vma; \ + } + +/* We use the special COFF backend linker. */ +#define coff_relocate_section _bfd_coff_generic_relocate_section + +static reloc_howto_type * +coff_i860_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + + reloc_howto_type *howto; + + howto = howto_table + rel->r_type; + + if (howto->pc_relative) + *addendp += sec->vma; + + if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) + { + /* This is a common symbol. The section contents include the + size (sym->n_value) as an addend. The relocate_section + function will be adding in the final value of the symbol. We + need to subtract out the current size in order to get the + correct result. */ + + BFD_ASSERT (h != NULL); + + + /* I think we *do* want to bypass this. If we don't, I have seen some data + parameters get the wrong relcation address. If I link two versions + with and without this section bypassed and then do a binary comparison, + the addresses which are different can be looked up in the map. The + case in which this section has been bypassed has addresses which correspond + to values I can find in the map */ + *addendp -= sym->n_value; + } + + /* If the output symbol is common (in which case this must be a + relocateable link), we need to add in the final size of the + common symbol. */ + if (h != NULL && h->root.type == bfd_link_hash_common) + *addendp += h->root.u.c.size; + + return howto; +} + +#define coff_rtype_to_howto coff_i860_rtype_to_howto + +#include "coffcode.h" + +static const bfd_target * +i3coff_object_p(a) + bfd *a; +{ + return coff_object_p(a); +} + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + i860coff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-i860", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, i3coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-i960.c b/contrib/gdb/bfd/coff-i960.c new file mode 100644 index 000000000000..ed30125f0fa4 --- /dev/null +++ b/contrib/gdb/bfd/coff-i960.c @@ -0,0 +1,683 @@ +/* BFD back-end for Intel 960 COFF files. + Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define I960 1 +#define BADMAG(x) I960BADMAG(x) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/i960.h" +#include "coff/internal.h" +#include "libcoff.h" /* to allow easier abstraction-breaking */ + +static bfd_reloc_status_type optcall_callback + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type coff_i960_relocate + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static reloc_howto_type *coff_i960_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static boolean coff_i960_start_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean coff_i960_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); +static boolean coff_i960_adjust_symndx + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, + struct internal_reloc *, boolean *)); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +/* The i960 does not support an MMU, so COFF_PAGE_SIZE can be + arbitrarily small. */ +#define COFF_PAGE_SIZE 1 + +#define COFF_LONG_FILENAMES + +/* This is just like the usual CALC_ADDEND, but it includes the + section VMA for PC relative relocs. */ +#ifndef CALC_ADDEND +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = 0; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && (reloc.r_type == 25 || reloc.r_type == 27)) \ + cache_ptr->addend += asect->vma; \ + } +#endif + +#define CALLS 0x66003800 /* Template for 'calls' instruction */ +#define BAL 0x0b000000 /* Template for 'bal' instruction */ +#define BAL_MASK 0x00ffffff + +static bfd_reloc_status_type +optcall_callback (abfd, reloc_entry, symbol_in, data, + input_section, ignore_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *ignore_bfd; + char **error_message; +{ + /* This item has already been relocated correctly, but we may be + * able to patch in yet better code - done by digging out the + * correct info on this symbol */ + bfd_reloc_status_type result; + coff_symbol_type *cs = coffsymbol(symbol_in); + + /* Don't do anything with symbols which aren't tied up yet, + except move the reloc. */ + if (bfd_is_und_section (cs->symbol.section)) { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* So the target symbol has to be of coff type, and the symbol + has to have the correct native information within it */ + if ((bfd_asymbol_flavour(&cs->symbol) != bfd_target_coff_flavour) + || (cs->native == (combined_entry_type *)NULL)) + { + /* This is interesting, consider the case where we're outputting coff + from a mix n match input, linking from coff to a symbol defined in a + bout file will cause this match to be true. Should I complain? This + will only work if the bout symbol is non leaf. */ + *error_message = + (char *) "uncertain calling convention for non-COFF symbol"; + result = bfd_reloc_dangerous; + } + else + { + switch (cs->native->u.syment.n_sclass) + { + case C_LEAFSTAT: + case C_LEAFEXT: + /* This is a call to a leaf procedure, replace instruction with a bal + to the correct location. */ + { + union internal_auxent *aux = &((cs->native+2)->u.auxent); + int word = bfd_get_32(abfd, (bfd_byte *)data + reloc_entry->address); + int olf = (aux->x_bal.x_balntry - cs->native->u.syment.n_value); + BFD_ASSERT(cs->native->u.syment.n_numaux==2); + + /* We replace the original call instruction with a bal to + the bal entry point - the offset of which is described in + the 2nd auxent of the original symbol. We keep the native + sym and auxents untouched, so the delta between the two + is the offset of the bal entry point. */ + word = ((word + olf) & BAL_MASK) | BAL; + bfd_put_32(abfd, word, (bfd_byte *) data + reloc_entry->address); + } + result = bfd_reloc_ok; + break; + case C_SCALL: + /* This is a call to a system call, replace with a calls to # */ + BFD_ASSERT(0); + result = bfd_reloc_ok; + break; + default: + result = bfd_reloc_ok; + break; + } + } + return result; +} + +/* i960 COFF is used by VxWorks 5.1. However, VxWorks 5.1 does not + appear to correctly handle a reloc against a symbol defined in the + same object file. It appears to simply discard such relocs, rather + than adding their values into the object file. We handle this here + by converting all relocs against defined symbols into relocs + against the section symbol, when generating a relocateable output + file. + + Note that this function is only called if we are not using the COFF + specific backend linker. It only does something when doing a + relocateable link, which will almost certainly fail when not + generating COFF i960 output, so this function is actually no longer + useful. It was used before this target was converted to use the + COFF specific backend linker. */ + +static bfd_reloc_status_type +coff_i960_relocate (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + asection *osec; + + if (output_bfd == NULL) + { + /* Not generating relocateable output file. */ + return bfd_reloc_continue; + } + + if (bfd_is_und_section (bfd_get_section (symbol))) + { + /* Symbol is not defined, so no need to worry about it. */ + return bfd_reloc_continue; + } + + if (bfd_is_com_section (bfd_get_section (symbol))) + { + /* I don't really know what the right action is for a common + symbol. */ + return bfd_reloc_continue; + } + + /* Convert the reloc to use the section symbol. FIXME: This method + is ridiculous. */ + osec = bfd_get_section (symbol)->output_section; + if (coff_section_data (output_bfd, osec) != NULL + && coff_section_data (output_bfd, osec)->tdata != NULL) + reloc_entry->sym_ptr_ptr = + (asymbol **) coff_section_data (output_bfd, osec)->tdata; + else + { + const char *sec_name; + asymbol **syms, **sym_end; + + sec_name = bfd_get_section_name (output_bfd, osec); + syms = bfd_get_outsymbols (output_bfd); + sym_end = syms + bfd_get_symcount (output_bfd); + for (; syms < sym_end; syms++) + { + if (bfd_asymbol_name (*syms) != NULL + && (*syms)->value == 0 + && strcmp ((*syms)->section->output_section->name, + sec_name) == 0) + break; + } + + if (syms >= sym_end) + abort (); + + reloc_entry->sym_ptr_ptr = syms; + + if (coff_section_data (output_bfd, osec) == NULL) + { + osec->used_by_bfd = + ((PTR) bfd_zalloc (abfd, + sizeof (struct coff_section_tdata))); + if (osec->used_by_bfd == NULL) + return bfd_reloc_overflow; + } + coff_section_data (output_bfd, osec)->tdata = (PTR) syms; + } + + /* Let bfd_perform_relocation do its thing, which will include + stuffing the symbol addend into the object file. */ + return bfd_reloc_continue; +} + +static reloc_howto_type howto_rellong = + HOWTO ((unsigned int) R_RELLONG, 0, 2, 32,false, 0, + complain_overflow_bitfield, coff_i960_relocate,"rellong", true, + 0xffffffff, 0xffffffff, 0); +static reloc_howto_type howto_iprmed = + HOWTO (R_IPRMED, 0, 2, 24,true,0, complain_overflow_signed, + coff_i960_relocate, "iprmed ", true, 0x00ffffff, 0x00ffffff, 0); +static reloc_howto_type howto_optcall = + HOWTO (R_OPTCALL, 0,2,24,true,0, complain_overflow_signed, + optcall_callback, "optcall", true, 0x00ffffff, 0x00ffffff, 0); + +static reloc_howto_type * +coff_i960_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + default: + return 0; + case BFD_RELOC_I960_CALLJ: + return &howto_optcall; + case BFD_RELOC_32: + case BFD_RELOC_CTOR: + return &howto_rellong; + case BFD_RELOC_24_PCREL: + return &howto_iprmed; + } +} + +/* The real code is in coffcode.h */ + +#define RTYPE2HOWTO(cache_ptr, dst) \ +{ \ + reloc_howto_type *howto_ptr; \ + switch ((dst)->r_type) { \ + case 17: howto_ptr = &howto_rellong; break; \ + case 25: howto_ptr = &howto_iprmed; break; \ + case 27: howto_ptr = &howto_optcall; break; \ + default: howto_ptr = 0; break; \ + } \ + (cache_ptr)->howto = howto_ptr; \ + } + +/* i960 COFF is used by VxWorks 5.1. However, VxWorks 5.1 does not + appear to correctly handle a reloc against a symbol defined in the + same object file. It appears to simply discard such relocs, rather + than adding their values into the object file. We handle this by + converting all relocs against global symbols into relocs against + internal symbols at the start of the section. This routine is + called at the start of the linking process, and it creates the + necessary symbols. */ + +static boolean +coff_i960_start_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_size_type symesz = bfd_coff_symesz (abfd); + asection *o; + bfd_byte *esym; + + if (! info->relocateable) + return true; + + esym = (bfd_byte *) bfd_malloc (symesz); + if (esym == NULL) + return false; + + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) + return false; + + for (o = abfd->sections; o != NULL; o = o->next) + { + struct internal_syment isym; + + strncpy (isym._n._n_name, o->name, SYMNMLEN); + isym.n_value = 0; + isym.n_scnum = o->target_index; + isym.n_type = T_NULL; + isym.n_sclass = C_STAT; + isym.n_numaux = 0; + + bfd_coff_swap_sym_out (abfd, (PTR) &isym, (PTR) esym); + + if (bfd_write (esym, symesz, 1, abfd) != symesz) + { + free (esym); + return false; + } + + obj_raw_syment_count (abfd) += 1; + } + + free (esym); + + return true; +} + +/* The reloc processing routine for the optimized COFF linker. */ + +static boolean +coff_i960_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, syms, sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma addend; + bfd_vma val; + reloc_howto_type *howto; + bfd_reloc_status_type rstat = bfd_reloc_ok; + boolean done; + + symndx = rel->r_symndx; + + if (symndx == -1) + { + h = NULL; + sym = NULL; + } + else + { + h = obj_coff_sym_hashes (input_bfd)[symndx]; + sym = syms + symndx; + } + + if (sym != NULL && sym->n_scnum != 0) + addend = - sym->n_value; + else + addend = 0; + + switch (rel->r_type) + { + case 17: howto = &howto_rellong; break; + case 25: howto = &howto_iprmed; break; + case 27: howto = &howto_optcall; break; + default: + bfd_set_error (bfd_error_bad_value); + return false; + } + + val = 0; + + if (h == NULL) + { + asection *sec; + + if (symndx == -1) + { + sec = bfd_abs_section_ptr; + val = 0; + } + else + { + sec = sections[symndx]; + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *sec; + + sec = h->root.u.def.section; + val = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (! info->relocateable) + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + done = false; + + if (howto->type == R_OPTCALL && ! info->relocateable && symndx != -1) + { + int class; + + if (h != NULL) + class = h->class; + else + class = sym->n_sclass; + + switch (class) + { + case C_NULL: + /* This symbol is apparently not from a COFF input file. + We warn, and then assume that it is not a leaf + function. */ + if (! ((*info->callbacks->reloc_dangerous) + (info, + "uncertain calling convention for non-COFF symbol", + input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + break; + case C_LEAFSTAT: + case C_LEAFEXT: + /* This is a call to a leaf procedure; use the bal + instruction. */ + { + long olf; + unsigned long word; + + if (h != NULL) + { + BFD_ASSERT (h->numaux == 2); + olf = h->aux[1].x_bal.x_balntry; + } + else + { + bfd_byte *esyms; + union internal_auxent aux; + + BFD_ASSERT (sym->n_numaux == 2); + esyms = (bfd_byte *) obj_coff_external_syms (input_bfd); + esyms += (symndx + 2) * bfd_coff_symesz (input_bfd); + bfd_coff_swap_aux_in (input_bfd, (PTR) esyms, sym->n_type, + sym->n_sclass, 1, sym->n_numaux, + (PTR) &aux); + olf = aux.x_bal.x_balntry; + } + + word = bfd_get_32 (input_bfd, + (contents + + (rel->r_vaddr - input_section->vma))); + word = ((word + olf - val) & BAL_MASK) | BAL; + bfd_put_32 (input_bfd, + word, + (contents + + (rel->r_vaddr - input_section->vma))); + done = true; + } + break; + case C_SCALL: + BFD_ASSERT (0); + break; + } + } + + if (! done) + { + if (howto->pc_relative) + addend += input_section->vma; + rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, + rel->r_vaddr - input_section->vma, + val, addend); + } + + switch (rstat) + { + default: + abort (); + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + { + const char *name; + char buf[SYMNMLEN + 1]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.string; + else + { + name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); + if (name == NULL) + return false; + } + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + } + } + } + + return true; +} + +/* Adjust the symbol index of any reloc against a global symbol to + instead be a reloc against the internal symbol we created specially + for the section. */ + +/*ARGSUSED*/ +static boolean +coff_i960_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp) + bfd *obfd; + struct bfd_link_info *info; + bfd *ibfd; + asection *sec; + struct internal_reloc *irel; + boolean *adjustedp; +{ + struct coff_link_hash_entry *h; + + *adjustedp = false; + + h = obj_coff_sym_hashes (ibfd)[irel->r_symndx]; + if (h == NULL + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)) + return true; + + irel->r_symndx = h->root.u.def.section->output_section->target_index - 1; + *adjustedp = true; + + return true; +} + +#define coff_start_final_link coff_i960_start_final_link + +#define coff_relocate_section coff_i960_relocate_section + +#define coff_adjust_symndx coff_i960_adjust_symndx + +#define coff_bfd_reloc_type_lookup coff_i960_reloc_type_lookup + +#include "coffcode.h" + +const bfd_target icoff_little_vec = +{ + "coff-Intel-little", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; + + +const bfd_target icoff_big_vec = +{ + "coff-Intel-big", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + +bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ +bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-m68k.c b/contrib/gdb/bfd/coff-m68k.c new file mode 100644 index 000000000000..77fb45b6d640 --- /dev/null +++ b/contrib/gdb/bfd/coff-m68k.c @@ -0,0 +1,203 @@ +/* BFD back-end for Motorola 68000 COFF binaries. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/m68k.h" +#include "coff/internal.h" +#include "libcoff.h" + +#ifndef LYNX_SPECIAL_FN +#define LYNX_SPECIAL_FN 0 +#endif + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) + +#ifndef COFF_PAGE_SIZE +/* The page size is a guess based on ELF. */ +#define COFF_PAGE_SIZE 0x2000 +#endif + +/* Clean up namespace. */ +#define m68kcoff_howto_table _bfd_m68kcoff_howto_table +#define m68k_rtype2howto _bfd_m68kcoff_rtype2howto +#define m68k_howto2rtype _bfd_m68kcoff_howto2rtype +#define m68k_reloc_type_lookup _bfd_m68kcoff_reloc_type_lookup + +#ifdef ONLY_DECLARE_RELOCS +extern reloc_howto_type m68kcoff_howto_table[]; +#else +reloc_howto_type m68kcoff_howto_table[] = +{ + HOWTO(R_RELBYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, LYNX_SPECIAL_FN, "8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_RELWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, LYNX_SPECIAL_FN, "16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_RELLONG, 0, 2, 32, false, 0, complain_overflow_bitfield, LYNX_SPECIAL_FN, "32", true, 0xffffffff,0xffffffff, false), + HOWTO(R_PCRBYTE, 0, 0, 8, true, 0, complain_overflow_signed, LYNX_SPECIAL_FN, "DISP8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_PCRWORD, 0, 1, 16, true, 0, complain_overflow_signed, LYNX_SPECIAL_FN, "DISP16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_PCRLONG, 0, 2, 32, true, 0, complain_overflow_signed, LYNX_SPECIAL_FN, "DISP32", true, 0xffffffff,0xffffffff, false), + HOWTO(R_RELLONG_NEG, 0, -2, 32, false, 0, complain_overflow_bitfield, LYNX_SPECIAL_FN, "-32", true, 0xffffffff,0xffffffff, false), +}; +#endif /* not ONLY_DECLARE_RELOCS */ + +#ifndef BADMAG +#define BADMAG(x) M68KBADMAG(x) +#endif +#define M68 1 /* Customize coffcode.h */ + +/* Turn a howto into a reloc number */ + +#ifdef ONLY_DECLARE_RELOCS +extern void m68k_rtype2howto PARAMS ((arelent *internal, int relocentry)); +extern int m68k_howto2rtype PARAMS ((reloc_howto_type *)); +extern reloc_howto_type *m68k_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +#else +void +m68k_rtype2howto(internal, relocentry) + arelent *internal; + int relocentry; +{ + switch (relocentry) + { + case R_RELBYTE: internal->howto = m68kcoff_howto_table + 0; break; + case R_RELWORD: internal->howto = m68kcoff_howto_table + 1; break; + case R_RELLONG: internal->howto = m68kcoff_howto_table + 2; break; + case R_PCRBYTE: internal->howto = m68kcoff_howto_table + 3; break; + case R_PCRWORD: internal->howto = m68kcoff_howto_table + 4; break; + case R_PCRLONG: internal->howto = m68kcoff_howto_table + 5; break; + case R_RELLONG_NEG: internal->howto = m68kcoff_howto_table + 6; break; + } +} + +int +m68k_howto2rtype (internal) + reloc_howto_type *internal; +{ + if (internal->pc_relative) + { + switch (internal->bitsize) + { + case 32: return R_PCRLONG; + case 16: return R_PCRWORD; + case 8: return R_PCRBYTE; + } + } + else + { + switch (internal->bitsize) + { + case 32: return R_RELLONG; + case 16: return R_RELWORD; + case 8: return R_RELBYTE; + } + } + return R_RELLONG; +} + +reloc_howto_type * +m68k_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + default: return NULL; + case BFD_RELOC_8: return m68kcoff_howto_table + 0; + case BFD_RELOC_16: return m68kcoff_howto_table + 1; + case BFD_RELOC_CTOR: + case BFD_RELOC_32: return m68kcoff_howto_table + 2; + case BFD_RELOC_8_PCREL: return m68kcoff_howto_table + 3; + case BFD_RELOC_16_PCREL: return m68kcoff_howto_table + 4; + case BFD_RELOC_32_PCREL: return m68kcoff_howto_table + 5; + /* FIXME: There doesn't seem to be a code for R_RELLONG_NEG. */ + } + /*NOTREACHED*/ +} + +#endif /* not ONLY_DECLARE_RELOCS */ + +#define RTYPE2HOWTO(internal, relocentry) \ + m68k_rtype2howto(internal, (relocentry)->r_type) + +#define SELECT_RELOC(external, internal) \ + external.r_type = m68k_howto2rtype(internal); + +#define coff_bfd_reloc_type_lookup m68k_reloc_type_lookup + +#define coff_relocate_section _bfd_coff_generic_relocate_section + +#include "coffcode.h" + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + m68kcoff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-m68k", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ +#ifdef NAMES_HAVE_UNDERSCORE + '_', +#else + 0, /* leading underscore */ +#endif + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE + }; diff --git a/contrib/gdb/bfd/coff-m88k.c b/contrib/gdb/bfd/coff-m88k.c new file mode 100644 index 000000000000..414106d7bcb0 --- /dev/null +++ b/contrib/gdb/bfd/coff-m88k.c @@ -0,0 +1,311 @@ +/* BFD back-end for Motorola 88000 COFF "Binary Compatability Standard" files. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define M88 1 /* Customize various include files */ +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/m88k.h" +#include "coff/internal.h" +#include "libcoff.h" + +static bfd_reloc_status_type m88k_special_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static void rtype2howto PARAMS ((arelent *, struct internal_reloc *)); +static void reloc_processing + PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *)); + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +static bfd_reloc_status_type +m88k_special_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + reloc_howto_type *howto = reloc_entry->howto; + + switch (howto->type) + { + case R_HVRT16: + case R_LVRT16: + if (output_bfd != (bfd *) NULL) + { + /* This is a partial relocation, and we want to apply the + relocation to the reloc entry rather than the raw data. + Modify the reloc inplace to reflect what we now know. */ + + reloc_entry->address += input_section->output_offset; + } + else + { + bfd_vma output_base = 0; + bfd_vma addr = reloc_entry->address; + bfd_vma x = bfd_get_16 (abfd, (bfd_byte *) data + addr); + asection *reloc_target_output_section; + long relocation = 0; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (output_bfd) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += ((reloc_entry->addend << howto->bitsize) + x); + + reloc_entry->addend = 0; + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= (bfd_vma) howto->bitpos; + + if (relocation) + bfd_put_16 (abfd, relocation, (unsigned char *) data + addr); + } + + return bfd_reloc_ok; + break; + + default: + if (output_bfd != (bfd *) NULL) + { + /* This is a partial relocation, and we want to apply the + relocation to the reloc entry rather than the raw data. + Modify the reloc inplace to reflect what we now know. */ + + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + break; + } + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_ok; +} + +static reloc_howto_type howto_table[] = +{ + HOWTO (R_PCR16L, /* type */ + 02, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "PCR16L", /* name */ + false, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_PCR26L, /* type */ + 02, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "PCR26L", /* name */ + false, /* partial_inplace */ + 0x03ffffff, /* src_mask */ + 0x03ffffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_VRT16, /* type */ + 00, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "VRT16", /* name */ + false, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_HVRT16, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "HVRT16", /* name */ + false, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_LVRT16, /* type */ + 00, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "LVRT16", /* name */ + false, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_VRT32, /* type */ + 00, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + m88k_special_reloc, /* special_function */ + "VRT32", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ +}; + +/* Code to turn an external r_type into a pointer to an entry in the + above howto table. */ +static void +rtype2howto (cache_ptr, dst) + arelent *cache_ptr; + struct internal_reloc *dst; +{ + if (dst->r_type >= R_PCR16L && dst->r_type <= R_VRT32) + { + cache_ptr->howto = howto_table + dst->r_type - R_PCR16L; + } + else + { + BFD_ASSERT (0); + } +} + +#define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst) + + +/* Code to swap in the reloc offset */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_16 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_16 + + +#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void +reloc_processing (relent, reloc, symbols, abfd, section) + arelent *relent; + struct internal_reloc *reloc; + asymbol **symbols; + bfd *abfd; + asection *section; +{ + relent->address = reloc->r_vaddr; + rtype2howto (relent, reloc); + + if (((int) reloc->r_symndx) > 0) + { + relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; + } + else + { + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + + relent->addend = reloc->r_offset; + relent->address -= section->vma; +} + +#define BADMAG(x) MC88BADMAG(x) +#include "coffcode.h" + +#undef coff_write_armap + +const bfd_target m88kbcs_vec = +{ + "coff-m88kbcs", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-mips.c b/contrib/gdb/bfd/coff-mips.c new file mode 100644 index 000000000000..c860f9a4d539 --- /dev/null +++ b/contrib/gdb/bfd/coff-mips.c @@ -0,0 +1,2596 @@ +/* BFD back-end for MIPS Extended-Coff files. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Original version by Per Bothner. + Full support added by Ian Lance Taylor, ian@cygnus.com. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "coff/mips.h" +#include "libcoff.h" +#include "libecoff.h" + +/* Prototypes for static functions. */ + +static boolean mips_ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr)); +static void mips_ecoff_swap_reloc_in PARAMS ((bfd *, PTR, + struct internal_reloc *)); +static void mips_ecoff_swap_reloc_out PARAMS ((bfd *, + const struct internal_reloc *, + PTR)); +static void mips_adjust_reloc_in PARAMS ((bfd *, + const struct internal_reloc *, + arelent *)); +static void mips_adjust_reloc_out PARAMS ((bfd *, const arelent *, + struct internal_reloc *)); +static bfd_reloc_status_type mips_generic_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_refhi_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_reflo_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_gprel_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_relhi_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_rello_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_switch_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static void mips_relocate_hi PARAMS ((struct internal_reloc *refhi, + struct internal_reloc *reflo, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + size_t adjust, + bfd_vma relocation, + boolean pcrel)); +static boolean mips_relocate_section PARAMS ((bfd *, struct bfd_link_info *, + bfd *, asection *, + bfd_byte *, PTR)); +static boolean mips_read_relocs PARAMS ((bfd *, asection *)); +static boolean mips_relax_section PARAMS ((bfd *, asection *, + struct bfd_link_info *, + boolean *)); +static boolean mips_relax_pcrel16 PARAMS ((struct bfd_link_info *, bfd *, + asection *, + struct ecoff_link_hash_entry *, + bfd_byte *, bfd_vma)); + +/* ECOFF has COFF sections, but the debugging information is stored in + a completely different format. ECOFF targets use some of the + swapping routines from coffswap.h, and some of the generic COFF + routines in coffgen.c, but, unlike the real COFF targets, do not + use coffcode.h itself. + + Get the generic COFF swapping routines, except for the reloc, + symbol, and lineno ones. Give them ECOFF names. */ +#define MIPSECOFF +#define NO_COFF_RELOCS +#define NO_COFF_SYMBOLS +#define NO_COFF_LINENOS +#define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in +#define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out +#define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in +#define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out +#define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in +#define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out +#include "coffswap.h" + +/* Get the ECOFF swapping routines. */ +#define ECOFF_32 +#include "ecoffswap.h" + +/* How to process the various relocs types. */ + +static reloc_howto_type mips_howto_table[] = +{ + /* Reloc type 0 is ignored. The reloc reading code ensures that + this is a reference to the .abs section, which will cause + bfd_perform_relocation to do nothing. */ + HOWTO (MIPS_R_IGNORE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "IGNORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 16 bit reference to a symbol, normally from a data section. */ + HOWTO (MIPS_R_REFHALF, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + mips_generic_reloc, /* special_function */ + "REFHALF", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit reference to a symbol, normally from a data section. */ + HOWTO (MIPS_R_REFWORD, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + mips_generic_reloc, /* special_function */ + "REFWORD", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 26 bit absolute jump address. */ + HOWTO (MIPS_R_JMPADDR, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + /* This needs complex overflow + detection, because the upper four + bits must match the PC. */ + mips_generic_reloc, /* special_function */ + "JMPADDR", /* name */ + true, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high 16 bits of a symbol value. Handled by the function + mips_refhi_reloc. */ + HOWTO (MIPS_R_REFHI, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + mips_refhi_reloc, /* special_function */ + "REFHI", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The low 16 bits of a symbol value. */ + HOWTO (MIPS_R_REFLO, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + mips_reflo_reloc, /* special_function */ + "REFLO", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A reference to an offset from the gp register. Handled by the + function mips_gprel_reloc. */ + HOWTO (MIPS_R_GPREL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_gprel_reloc, /* special_function */ + "GPREL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A reference to a literal using an offset from the gp register. + Handled by the function mips_gprel_reloc. */ + HOWTO (MIPS_R_LITERAL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_gprel_reloc, /* special_function */ + "LITERAL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 8 }, + { 9 }, + { 10 }, + { 11 }, + + /* This reloc is a Cygnus extension used when generating position + independent code for embedded systems. It represents a 16 bit PC + relative reloc rightshifted twice as used in the MIPS branch + instructions. */ + HOWTO (MIPS_R_PCREL16, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_generic_reloc, /* special_function */ + "PCREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* This reloc is a Cygnus extension used when generating position + independent code for embedded systems. It represents the high 16 + bits of a PC relative reloc. The next reloc must be + MIPS_R_RELLO, and the addend is formed from the addends of the + two instructions, just as in MIPS_R_REFHI and MIPS_R_REFLO. The + final value is actually PC relative to the location of the + MIPS_R_RELLO reloc, not the MIPS_R_RELHI reloc. */ + HOWTO (MIPS_R_RELHI, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + mips_relhi_reloc, /* special_function */ + "RELHI", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* This reloc is a Cygnus extension used when generating position + independent code for embedded systems. It represents the low 16 + bits of a PC relative reloc. */ + HOWTO (MIPS_R_RELLO, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + mips_rello_reloc, /* special_function */ + "RELLO", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + { 15 }, + { 16 }, + { 17 }, + { 18 }, + { 19 }, + { 20 }, + { 21 }, + + /* This reloc is a Cygnus extension used when generating position + independent code for embedded systems. It represents an entry in + a switch table, which is the difference between two symbols in + the .text section. The symndx is actually the offset from the + reloc address to the subtrahend. See include/coff/mips.h for + more details. */ + HOWTO (MIPS_R_SWITCH, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + mips_switch_reloc, /* special_function */ + "SWITCH", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true) /* pcrel_offset */ +}; + +#define MIPS_HOWTO_COUNT \ + (sizeof mips_howto_table / sizeof mips_howto_table[0]) + +/* When the linker is doing relaxing, it may change a external PCREL16 + reloc. This typically represents an instruction like + bal foo + We change it to + .set noreorder + bal $L1 + lui $at,%hi(foo - $L1) + $L1: + addiu $at,%lo(foo - $L1) + addu $at,$at,$31 + jalr $at + PCREL16_EXPANSION_ADJUSTMENT is the number of bytes this changes the + instruction by. */ + +#define PCREL16_EXPANSION_ADJUSTMENT (4 * 4) + +/* See whether the magic number matches. */ + +static boolean +mips_ecoff_bad_format_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + switch (internal_f->f_magic) + { + case MIPS_MAGIC_1: + /* I don't know what endianness this implies. */ + return true; + + case MIPS_MAGIC_BIG: + case MIPS_MAGIC_BIG2: + case MIPS_MAGIC_BIG3: + return bfd_big_endian (abfd); + + case MIPS_MAGIC_LITTLE: + case MIPS_MAGIC_LITTLE2: + case MIPS_MAGIC_LITTLE3: + return bfd_little_endian (abfd); + + default: + return false; + } +} + +/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in + external form. They use a bit which indicates whether the symbol + is external. */ + +/* Swap a reloc in. */ + +static void +mips_ecoff_swap_reloc_in (abfd, ext_ptr, intern) + bfd *abfd; + PTR ext_ptr; + struct internal_reloc *intern; +{ + const RELOC *ext = (RELOC *) ext_ptr; + + intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr); + if (bfd_header_big_endian (abfd)) + { + intern->r_symndx = (((int) ext->r_bits[0] + << RELOC_BITS0_SYMNDX_SH_LEFT_BIG) + | ((int) ext->r_bits[1] + << RELOC_BITS1_SYMNDX_SH_LEFT_BIG) + | ((int) ext->r_bits[2] + << RELOC_BITS2_SYMNDX_SH_LEFT_BIG)); + intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG) + >> RELOC_BITS3_TYPE_SH_BIG); + intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0; + } + else + { + intern->r_symndx = (((int) ext->r_bits[0] + << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE) + | ((int) ext->r_bits[1] + << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE) + | ((int) ext->r_bits[2] + << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE)); + intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE) + >> RELOC_BITS3_TYPE_SH_LITTLE) + | ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE) + << RELOC_BITS3_TYPEHI_SH_LITTLE)); + intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0; + } + + /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or + MIPS_R_RELLO reloc, r_symndx is actually the offset from the + reloc address to the base of the difference (see + include/coff/mips.h for more details). We copy symndx into the + r_offset field so as not to confuse ecoff_slurp_reloc_table in + ecoff.c. In adjust_reloc_in we then copy r_offset into the reloc + addend. */ + if (intern->r_type == MIPS_R_SWITCH + || (! intern->r_extern + && (intern->r_type == MIPS_R_RELLO + || intern->r_type == MIPS_R_RELHI))) + { + BFD_ASSERT (! intern->r_extern); + intern->r_offset = intern->r_symndx; + if (intern->r_offset & 0x800000) + intern->r_offset -= 0x1000000; + intern->r_symndx = RELOC_SECTION_TEXT; + } +} + +/* Swap a reloc out. */ + +static void +mips_ecoff_swap_reloc_out (abfd, intern, dst) + bfd *abfd; + const struct internal_reloc *intern; + PTR dst; +{ + RELOC *ext = (RELOC *) dst; + long r_symndx; + + BFD_ASSERT (intern->r_extern + || (intern->r_symndx >= 0 && intern->r_symndx <= 12)); + + /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELLO or + MIPS_R_RELHI reloc, we actually want to write the contents of + r_offset out as the symbol index. This undoes the change made by + mips_ecoff_swap_reloc_in. */ + if (intern->r_type != MIPS_R_SWITCH + && (intern->r_extern + || (intern->r_type != MIPS_R_RELHI + && intern->r_type != MIPS_R_RELLO))) + r_symndx = intern->r_symndx; + else + { + BFD_ASSERT (intern->r_symndx == RELOC_SECTION_TEXT); + r_symndx = intern->r_offset & 0xffffff; + } + + bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr); + if (bfd_header_big_endian (abfd)) + { + ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG; + ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG; + ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG; + ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG) + & RELOC_BITS3_TYPE_BIG) + | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0)); + } + else + { + ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE; + ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE; + ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE; + ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE) + & RELOC_BITS3_TYPE_LITTLE) + | ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE + & RELOC_BITS3_TYPEHI_LITTLE)) + | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0)); + } +} + +/* Finish canonicalizing a reloc. Part of this is generic to all + ECOFF targets, and that part is in ecoff.c. The rest is done in + this backend routine. It must fill in the howto field. */ + +static void +mips_adjust_reloc_in (abfd, intern, rptr) + bfd *abfd; + const struct internal_reloc *intern; + arelent *rptr; +{ + if (intern->r_type > MIPS_R_SWITCH) + abort (); + + if (! intern->r_extern + && (intern->r_type == MIPS_R_GPREL + || intern->r_type == MIPS_R_LITERAL)) + rptr->addend += ecoff_data (abfd)->gp; + + /* If the type is MIPS_R_IGNORE, make sure this is a reference to + the absolute section so that the reloc is ignored. */ + if (intern->r_type == MIPS_R_IGNORE) + rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + + /* If this is a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or + MIPS_R_RELLO reloc, we want the addend field of the BFD relocto + hold the value which was originally in the symndx field of the + internal MIPS ECOFF reloc. This value was copied into + intern->r_offset by mips_swap_reloc_in, and here we copy it into + the addend field. */ + if (intern->r_type == MIPS_R_SWITCH + || (! intern->r_extern + && (intern->r_type == MIPS_R_RELHI + || intern->r_type == MIPS_R_RELLO))) + rptr->addend = intern->r_offset; + + rptr->howto = &mips_howto_table[intern->r_type]; +} + +/* Make any adjustments needed to a reloc before writing it out. None + are needed for MIPS. */ + +static void +mips_adjust_reloc_out (abfd, rel, intern) + bfd *abfd; + const arelent *rel; + struct internal_reloc *intern; +{ + /* For a MIPS_R_SWITCH reloc, or an internal MIPS_R_RELHI or + MIPS_R_RELLO reloc, we must copy rel->addend into + intern->r_offset. This will then be written out as the symbol + index by mips_ecoff_swap_reloc_out. This operation parallels the + action of mips_adjust_reloc_in. */ + if (intern->r_type == MIPS_R_SWITCH + || (! intern->r_extern + && (intern->r_type == MIPS_R_RELHI + || intern->r_type == MIPS_R_RELLO))) + intern->r_offset = rel->addend; +} + +/* ECOFF relocs are either against external symbols, or against + sections. If we are producing relocateable output, and the reloc + is against an external symbol, and nothing has given us any + additional addend, the resulting reloc will also be against the + same symbol. In such a case, we don't want to change anything + about the way the reloc is handled, since it will all be done at + final link time. Rather than put special case code into + bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +static bfd_reloc_status_type +mips_generic_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} + +/* Do a REFHI relocation. This has to be done in combination with a + REFLO reloc, because there is a carry from the REFLO to the REFHI. + Here we just save the information we need; we do the actual + relocation when we see the REFLO. MIPS ECOFF requires that the + REFLO immediately follow the REFHI, so this ought to work. */ + +static bfd_byte *mips_refhi_addr; +static bfd_vma mips_refhi_addend; + +static bfd_reloc_status_type +mips_refhi_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + + /* If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + ret = bfd_reloc_ok; + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Save the information, and let REFLO do the actual relocation. */ + mips_refhi_addr = (bfd_byte *) data + reloc_entry->address; + mips_refhi_addend = relocation; + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +/* Do a REFLO relocation. This is a straightforward 16 bit inplace + relocation; this function exists in order to do the REFHI + relocation described above. */ + +static bfd_reloc_status_type +mips_reflo_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (mips_refhi_addr != (bfd_byte *) NULL) + { + unsigned long insn; + unsigned long val; + unsigned long vallo; + + /* Do the REFHI relocation. Note that we actually don't need to + know anything about the REFLO itself, except where to find + the low 16 bits of the addend needed by the REFHI. */ + insn = bfd_get_32 (abfd, mips_refhi_addr); + vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) + & 0xffff); + val = ((insn & 0xffff) << 16) + vallo; + val += mips_refhi_addend; + + /* The low order 16 bits are always treated as a signed value. + Therefore, a negative value in the low order bits requires an + adjustment in the high order bits. We need to make this + adjustment in two ways: once for the bits we took from the + data, and once for the bits we are putting back in to the + data. */ + if ((vallo & 0x8000) != 0) + val -= 0x10000; + if ((val & 0x8000) != 0) + val += 0x10000; + + insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); + bfd_put_32 (abfd, insn, mips_refhi_addr); + + mips_refhi_addr = (bfd_byte *) NULL; + } + + /* Now do the REFLO reloc in the usual way. */ + return mips_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} + +/* Do a GPREL relocation. This is a 16 bit value which must become + the offset from the gp register. */ + +static bfd_reloc_status_type +mips_gprel_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + boolean relocateable; + bfd_vma gp; + bfd_vma relocation; + unsigned long val; + unsigned long insn; + + /* If we're relocating, and this is an external symbol with no + addend, we don't want to change anything. We will only have an + addend if this is a newly created reloc, not read from an ECOFF + file. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != (bfd *) NULL) + relocateable = true; + else + { + relocateable = false; + output_bfd = symbol->section->output_section->owner; + } + + if (bfd_is_und_section (symbol->section) + && relocateable == false) + return bfd_reloc_undefined; + + /* We have to figure out the gp value, so that we can adjust the + symbol value correctly. We look up the symbol _gp in the output + BFD. If we can't find it, we're stuck. We cache it in the ECOFF + target data. We don't need to adjust the symbol value for an + external symbol if we are producing relocateable output. */ + gp = _bfd_get_gp_value (output_bfd); + if (gp == 0 + && (relocateable == false + || (symbol->flags & BSF_SECTION_SYM) != 0)) + { + if (relocateable != false) + { + /* Make up a value. */ + gp = symbol->section->output_section->vma + 0x4000; + _bfd_set_gp_value (output_bfd, gp); + } + else + { + unsigned int count; + asymbol **sym; + unsigned int i; + + count = bfd_get_symcount (output_bfd); + sym = bfd_get_outsymbols (output_bfd); + + if (sym == (asymbol **) NULL) + i = count; + else + { + for (i = 0; i < count; i++, sym++) + { + register CONST char *name; + + name = bfd_asymbol_name (*sym); + if (*name == '_' && strcmp (name, "_gp") == 0) + { + gp = bfd_asymbol_value (*sym); + _bfd_set_gp_value (output_bfd, gp); + break; + } + } + } + + if (i >= count) + { + /* Only get the error once. */ + gp = 4; + _bfd_set_gp_value (output_bfd, gp); + *error_message = + (char *) "GP relative relocation when _gp not defined"; + return bfd_reloc_dangerous; + } + } + } + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + + /* Set val to the offset into the section or symbol. */ + val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; + if (val & 0x8000) + val -= 0x10000; + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (relocateable == false + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + insn = (insn &~ 0xffff) | (val & 0xffff); + bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); + + if (relocateable != false) + reloc_entry->address += input_section->output_offset; + + /* Make sure it fit in 16 bits. */ + if (val >= 0x8000 && val < 0xffff8000) + return bfd_reloc_overflow; + + return bfd_reloc_ok; +} + +/* Do a RELHI relocation. We do this in conjunction with a RELLO + reloc, just as REFHI and REFLO are done together. RELHI and RELLO + are Cygnus extensions used when generating position independent + code for embedded systems. */ + +static bfd_byte *mips_relhi_addr; +static bfd_vma mips_relhi_addend; + +static bfd_reloc_status_type +mips_relhi_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + + /* If this is a reloc against a section symbol, then it is correct + in the object file. The only time we want to change this case is + when we are relaxing, and that is handled entirely by + mips_relocate_section and never calls this function. */ + if ((symbol->flags & BSF_SECTION_SYM) != 0) + { + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* This is an external symbol. If we're relocating, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + ret = bfd_reloc_ok; + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Save the information, and let RELLO do the actual relocation. */ + mips_relhi_addr = (bfd_byte *) data + reloc_entry->address; + mips_relhi_addend = relocation; + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +/* Do a RELLO relocation. This is a straightforward 16 bit PC + relative relocation; this function exists in order to do the RELHI + relocation described above. */ + +static bfd_reloc_status_type +mips_rello_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (mips_relhi_addr != (bfd_byte *) NULL) + { + unsigned long insn; + unsigned long val; + unsigned long vallo; + + /* Do the RELHI relocation. Note that we actually don't need to + know anything about the RELLO itself, except where to find + the low 16 bits of the addend needed by the RELHI. */ + insn = bfd_get_32 (abfd, mips_relhi_addr); + vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) + & 0xffff); + val = ((insn & 0xffff) << 16) + vallo; + val += mips_relhi_addend; + + /* If the symbol is defined, make val PC relative. If the + symbol is not defined we don't want to do this, because we + don't want the value in the object file to incorporate the + address of the reloc. */ + if (! bfd_is_und_section (bfd_get_section (symbol)) + && ! bfd_is_com_section (bfd_get_section (symbol))) + val -= (input_section->output_section->vma + + input_section->output_offset + + reloc_entry->address); + + /* The low order 16 bits are always treated as a signed value. + Therefore, a negative value in the low order bits requires an + adjustment in the high order bits. We need to make this + adjustment in two ways: once for the bits we took from the + data, and once for the bits we are putting back in to the + data. */ + if ((vallo & 0x8000) != 0) + val -= 0x10000; + if ((val & 0x8000) != 0) + val += 0x10000; + + insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); + bfd_put_32 (abfd, insn, mips_relhi_addr); + + mips_relhi_addr = (bfd_byte *) NULL; + } + + /* If this is a reloc against a section symbol, then it is correct + in the object file. The only time we want to change this case is + when we are relaxing, and that is handled entirely by + mips_relocate_section and never calls this function. */ + if ((symbol->flags & BSF_SECTION_SYM) != 0) + { + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* bfd_perform_relocation does not handle pcrel_offset relocations + correctly when generating a relocateable file, so handle them + directly here. */ + if (output_bfd != (bfd *) NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Now do the RELLO reloc in the usual way. */ + return mips_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} + +/* This is the special function for the MIPS_R_SWITCH reloc. This + special reloc is normally correct in the object file, and only + requires special handling when relaxing. We don't want + bfd_perform_relocation to tamper with it at all. */ + +/*ARGSUSED*/ +static bfd_reloc_status_type +mips_switch_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + return bfd_reloc_ok; +} + +/* Get the howto structure for a generic reloc type. */ + +static reloc_howto_type * +mips_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + int mips_type; + + switch (code) + { + case BFD_RELOC_16: + mips_type = MIPS_R_REFHALF; + break; + case BFD_RELOC_32: + case BFD_RELOC_CTOR: + mips_type = MIPS_R_REFWORD; + break; + case BFD_RELOC_MIPS_JMP: + mips_type = MIPS_R_JMPADDR; + break; + case BFD_RELOC_HI16_S: + mips_type = MIPS_R_REFHI; + break; + case BFD_RELOC_LO16: + mips_type = MIPS_R_REFLO; + break; + case BFD_RELOC_MIPS_GPREL: + mips_type = MIPS_R_GPREL; + break; + case BFD_RELOC_MIPS_LITERAL: + mips_type = MIPS_R_LITERAL; + break; + case BFD_RELOC_16_PCREL_S2: + mips_type = MIPS_R_PCREL16; + break; + case BFD_RELOC_PCREL_HI16_S: + mips_type = MIPS_R_RELHI; + break; + case BFD_RELOC_PCREL_LO16: + mips_type = MIPS_R_RELLO; + break; + case BFD_RELOC_GPREL32: + mips_type = MIPS_R_SWITCH; + break; + default: + return (reloc_howto_type *) NULL; + } + + return &mips_howto_table[mips_type]; +} + +/* A helper routine for mips_relocate_section which handles the REFHI + and RELHI relocations. The REFHI relocation must be followed by a + REFLO relocation (and RELHI by a RELLO), and the addend used is + formed from the addends of both instructions. */ + +static void +mips_relocate_hi (refhi, reflo, input_bfd, input_section, contents, adjust, + relocation, pcrel) + struct internal_reloc *refhi; + struct internal_reloc *reflo; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + size_t adjust; + bfd_vma relocation; + boolean pcrel; +{ + unsigned long insn; + unsigned long val; + unsigned long vallo; + + insn = bfd_get_32 (input_bfd, + contents + adjust + refhi->r_vaddr - input_section->vma); + vallo = (bfd_get_32 (input_bfd, + contents + adjust + reflo->r_vaddr - input_section->vma) + & 0xffff); + val = ((insn & 0xffff) << 16) + vallo; + val += relocation; + + /* The low order 16 bits are always treated as a signed value. + Therefore, a negative value in the low order bits requires an + adjustment in the high order bits. We need to make this + adjustment in two ways: once for the bits we took from the data, + and once for the bits we are putting back in to the data. */ + if ((vallo & 0x8000) != 0) + val -= 0x10000; + + if (pcrel) + val -= (input_section->output_section->vma + + input_section->output_offset + + (reflo->r_vaddr - input_section->vma + adjust)); + + if ((val & 0x8000) != 0) + val += 0x10000; + + insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); + bfd_put_32 (input_bfd, (bfd_vma) insn, + contents + adjust + refhi->r_vaddr - input_section->vma); +} + +/* Relocate a section while linking a MIPS ECOFF file. */ + +static boolean +mips_relocate_section (output_bfd, info, input_bfd, input_section, + contents, external_relocs) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + PTR external_relocs; +{ + asection **symndx_to_section; + struct ecoff_link_hash_entry **sym_hashes; + bfd_vma gp; + boolean gp_undefined; + size_t adjust; + long *offsets; + struct external_reloc *ext_rel; + struct external_reloc *ext_rel_end; + unsigned int i; + boolean got_lo; + struct internal_reloc lo_int_rel; + + BFD_ASSERT (input_bfd->xvec->header_byteorder + == output_bfd->xvec->header_byteorder); + + /* We keep a table mapping the symndx found in an internal reloc to + the appropriate section. This is faster than looking up the + section by name each time. */ + symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; + if (symndx_to_section == (asection **) NULL) + { + symndx_to_section = ((asection **) + bfd_alloc (input_bfd, + (NUM_RELOC_SECTIONS + * sizeof (asection *)))); + if (!symndx_to_section) + return false; + + symndx_to_section[RELOC_SECTION_NONE] = NULL; + symndx_to_section[RELOC_SECTION_TEXT] = + bfd_get_section_by_name (input_bfd, ".text"); + symndx_to_section[RELOC_SECTION_RDATA] = + bfd_get_section_by_name (input_bfd, ".rdata"); + symndx_to_section[RELOC_SECTION_DATA] = + bfd_get_section_by_name (input_bfd, ".data"); + symndx_to_section[RELOC_SECTION_SDATA] = + bfd_get_section_by_name (input_bfd, ".sdata"); + symndx_to_section[RELOC_SECTION_SBSS] = + bfd_get_section_by_name (input_bfd, ".sbss"); + symndx_to_section[RELOC_SECTION_BSS] = + bfd_get_section_by_name (input_bfd, ".bss"); + symndx_to_section[RELOC_SECTION_INIT] = + bfd_get_section_by_name (input_bfd, ".init"); + symndx_to_section[RELOC_SECTION_LIT8] = + bfd_get_section_by_name (input_bfd, ".lit8"); + symndx_to_section[RELOC_SECTION_LIT4] = + bfd_get_section_by_name (input_bfd, ".lit4"); + symndx_to_section[RELOC_SECTION_XDATA] = NULL; + symndx_to_section[RELOC_SECTION_PDATA] = NULL; + symndx_to_section[RELOC_SECTION_FINI] = + bfd_get_section_by_name (input_bfd, ".fini"); + symndx_to_section[RELOC_SECTION_LITA] = NULL; + symndx_to_section[RELOC_SECTION_ABS] = NULL; + + ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; + } + + sym_hashes = ecoff_data (input_bfd)->sym_hashes; + + gp = _bfd_get_gp_value (output_bfd); + if (gp == 0) + gp_undefined = true; + else + gp_undefined = false; + + got_lo = false; + + adjust = 0; + + if (ecoff_section_data (input_bfd, input_section) == NULL) + offsets = NULL; + else + offsets = ecoff_section_data (input_bfd, input_section)->offsets; + + ext_rel = (struct external_reloc *) external_relocs; + ext_rel_end = ext_rel + input_section->reloc_count; + for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++) + { + struct internal_reloc int_rel; + bfd_vma addend; + reloc_howto_type *howto; + struct ecoff_link_hash_entry *h = NULL; + asection *s = NULL; + bfd_vma relocation; + bfd_reloc_status_type r; + + if (! got_lo) + mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel); + else + { + int_rel = lo_int_rel; + got_lo = false; + } + + BFD_ASSERT (int_rel.r_type + < sizeof mips_howto_table / sizeof mips_howto_table[0]); + + /* The REFHI and RELHI relocs requires special handling. they + must be followed by a REFLO or RELLO reloc, respectively, and + the addend is formed from both relocs. */ + if (int_rel.r_type == MIPS_R_REFHI + || int_rel.r_type == MIPS_R_RELHI) + { + BFD_ASSERT ((ext_rel + 1) < ext_rel_end); + mips_ecoff_swap_reloc_in (input_bfd, (PTR) (ext_rel + 1), + &lo_int_rel); + BFD_ASSERT ((lo_int_rel.r_type + == (int_rel.r_type == MIPS_R_REFHI + ? MIPS_R_REFLO + : MIPS_R_RELLO)) + && int_rel.r_extern == lo_int_rel.r_extern + && int_rel.r_symndx == lo_int_rel.r_symndx); + got_lo = true; + } + + howto = &mips_howto_table[int_rel.r_type]; + + /* The SWITCH reloc must be handled specially. This reloc is + marks the location of a difference between two portions of an + object file. The symbol index does not reference a symbol, + but is actually the offset from the reloc to the subtrahend + of the difference. This reloc is correct in the object file, + and needs no further adjustment, unless we are relaxing. If + we are relaxing, we may have to add in an offset. Since no + symbols are involved in this reloc, we handle it completely + here. */ + if (int_rel.r_type == MIPS_R_SWITCH) + { + if (offsets != NULL + && offsets[i] != 0) + { + r = _bfd_relocate_contents (howto, input_bfd, + (bfd_vma) offsets[i], + (contents + + adjust + + int_rel.r_vaddr + - input_section->vma)); + BFD_ASSERT (r == bfd_reloc_ok); + } + + continue; + } + + if (int_rel.r_extern) + { + h = sym_hashes[int_rel.r_symndx]; + /* If h is NULL, that means that there is a reloc against an + external symbol which we thought was just a debugging + symbol. This should not happen. */ + if (h == (struct ecoff_link_hash_entry *) NULL) + abort (); + } + else + { + if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS) + s = NULL; + else + s = symndx_to_section[int_rel.r_symndx]; + + if (s == (asection *) NULL) + abort (); + } + + /* The GPREL reloc uses an addend: the difference in the GP + values. */ + if (int_rel.r_type != MIPS_R_GPREL + && int_rel.r_type != MIPS_R_LITERAL) + addend = 0; + else + { + if (gp_undefined) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, "GP relative relocation when GP not defined", + input_bfd, input_section, + int_rel.r_vaddr - input_section->vma))) + return false; + /* Only give the error once per link. */ + gp = 4; + _bfd_set_gp_value (output_bfd, gp); + gp_undefined = false; + } + if (! int_rel.r_extern) + { + /* This is a relocation against a section. The current + addend in the instruction is the difference between + INPUT_SECTION->vma and the GP value of INPUT_BFD. We + must change this to be the difference between the + final definition (which will end up in RELOCATION) + and the GP value of OUTPUT_BFD (which is in GP). */ + addend = ecoff_data (input_bfd)->gp - gp; + } + else if (! info->relocateable + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + /* This is a relocation against a defined symbol. The + current addend in the instruction is simply the + desired offset into the symbol (normally zero). We + are going to change this into a relocation against a + defined symbol, so we want the instruction to hold + the difference between the final definition of the + symbol (which will end up in RELOCATION) and the GP + value of OUTPUT_BFD (which is in GP). */ + addend = - gp; + } + else + { + /* This is a relocation against an undefined or common + symbol. The current addend in the instruction is + simply the desired offset into the symbol (normally + zero). We are generating relocateable output, and we + aren't going to define this symbol, so we just leave + the instruction alone. */ + addend = 0; + } + } + + /* If we are relaxing, mips_relax_section may have set + offsets[i] to some value. A value of 1 means we must expand + a PC relative branch into a multi-instruction of sequence, + and any other value is an addend. */ + if (offsets != NULL + && offsets[i] != 0) + { + BFD_ASSERT (! info->relocateable); + BFD_ASSERT (int_rel.r_type == MIPS_R_PCREL16 + || int_rel.r_type == MIPS_R_RELHI + || int_rel.r_type == MIPS_R_RELLO); + if (offsets[i] != 1) + addend += offsets[i]; + else + { + bfd_byte *here; + + BFD_ASSERT (int_rel.r_extern + && int_rel.r_type == MIPS_R_PCREL16); + + /* Move the rest of the instructions up. */ + here = (contents + + adjust + + int_rel.r_vaddr + - input_section->vma); + memmove (here + PCREL16_EXPANSION_ADJUSTMENT, here, + (size_t) (input_section->_raw_size + - (int_rel.r_vaddr - input_section->vma))); + + /* Generate the new instructions. */ + if (! mips_relax_pcrel16 (info, input_bfd, input_section, + h, here, + (input_section->output_section->vma + + input_section->output_offset + + (int_rel.r_vaddr + - input_section->vma) + + adjust))) + return false; + + /* We must adjust everything else up a notch. */ + adjust += PCREL16_EXPANSION_ADJUSTMENT; + + /* mips_relax_pcrel16 handles all the details of this + relocation. */ + continue; + } + } + + /* If we are relaxing, and this is a reloc against the .text + segment, we may need to adjust it if some branches have been + expanded. The reloc types which are likely to occur in the + .text section are handled efficiently by mips_relax_section, + and thus do not need to be handled here. */ + if (ecoff_data (input_bfd)->debug_info.adjust != NULL + && ! int_rel.r_extern + && int_rel.r_symndx == RELOC_SECTION_TEXT + && (strcmp (bfd_get_section_name (input_bfd, input_section), + ".text") != 0 + || (int_rel.r_type != MIPS_R_PCREL16 + && int_rel.r_type != MIPS_R_SWITCH + && int_rel.r_type != MIPS_R_RELHI + && int_rel.r_type != MIPS_R_RELLO))) + { + bfd_vma adr; + struct ecoff_value_adjust *a; + + /* We need to get the addend so that we know whether we need + to adjust the address. */ + BFD_ASSERT (int_rel.r_type == MIPS_R_REFWORD); + + adr = bfd_get_32 (input_bfd, + (contents + + adjust + + int_rel.r_vaddr + - input_section->vma)); + + for (a = ecoff_data (input_bfd)->debug_info.adjust; + a != (struct ecoff_value_adjust *) NULL; + a = a->next) + { + if (adr >= a->start && adr < a->end) + addend += a->adjust; + } + } + + if (info->relocateable) + { + /* We are generating relocateable output, and must convert + the existing reloc. */ + if (int_rel.r_extern) + { + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && ! bfd_is_abs_section (h->root.u.def.section)) + { + const char *name; + + /* This symbol is defined in the output. Convert + the reloc from being against the symbol to being + against the section. */ + + /* Clear the r_extern bit. */ + int_rel.r_extern = 0; + + /* Compute a new r_symndx value. */ + s = h->root.u.def.section; + name = bfd_get_section_name (output_bfd, + s->output_section); + + int_rel.r_symndx = -1; + switch (name[1]) + { + case 'b': + if (strcmp (name, ".bss") == 0) + int_rel.r_symndx = RELOC_SECTION_BSS; + break; + case 'd': + if (strcmp (name, ".data") == 0) + int_rel.r_symndx = RELOC_SECTION_DATA; + break; + case 'f': + if (strcmp (name, ".fini") == 0) + int_rel.r_symndx = RELOC_SECTION_FINI; + break; + case 'i': + if (strcmp (name, ".init") == 0) + int_rel.r_symndx = RELOC_SECTION_INIT; + break; + case 'l': + if (strcmp (name, ".lit8") == 0) + int_rel.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + int_rel.r_symndx = RELOC_SECTION_LIT4; + break; + case 'r': + if (strcmp (name, ".rdata") == 0) + int_rel.r_symndx = RELOC_SECTION_RDATA; + break; + case 's': + if (strcmp (name, ".sdata") == 0) + int_rel.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + int_rel.r_symndx = RELOC_SECTION_SBSS; + break; + case 't': + if (strcmp (name, ".text") == 0) + int_rel.r_symndx = RELOC_SECTION_TEXT; + break; + } + + if (int_rel.r_symndx == -1) + abort (); + + /* Add the section VMA and the symbol value. */ + relocation = (h->root.u.def.value + + s->output_section->vma + + s->output_offset); + + /* For a PC relative relocation, the object file + currently holds just the addend. We must adjust + by the address to get the right value. */ + if (howto->pc_relative) + { + relocation -= int_rel.r_vaddr - input_section->vma; + + /* If we are converting a RELHI or RELLO reloc + from being against an external symbol to + being against a section, we must put a + special value into the r_offset field. This + value is the old addend. The r_offset for + both the RELOHI and RELLO relocs are the + same, and we set both when we see RELHI. */ + if (int_rel.r_type == MIPS_R_RELHI) + { + long addhi, addlo; + + addhi = bfd_get_32 (input_bfd, + (contents + + adjust + + int_rel.r_vaddr + - input_section->vma)); + addhi &= 0xffff; + if (addhi & 0x8000) + addhi -= 0x10000; + addhi <<= 16; + + addlo = bfd_get_32 (input_bfd, + (contents + + adjust + + lo_int_rel.r_vaddr + - input_section->vma)); + addlo &= 0xffff; + if (addlo & 0x8000) + addlo -= 0x10000; + + int_rel.r_offset = addhi + addlo; + lo_int_rel.r_offset = int_rel.r_offset; + } + } + + h = NULL; + } + else + { + /* Change the symndx value to the right one for the + output BFD. */ + int_rel.r_symndx = h->indx; + if (int_rel.r_symndx == -1) + { + /* This symbol is not being written out. */ + if (! ((*info->callbacks->unattached_reloc) + (info, h->root.root.string, input_bfd, + input_section, + int_rel.r_vaddr - input_section->vma))) + return false; + int_rel.r_symndx = 0; + } + relocation = 0; + } + } + else + { + /* This is a relocation against a section. Adjust the + value by the amount the section moved. */ + relocation = (s->output_section->vma + + s->output_offset + - s->vma); + } + + relocation += addend; + addend = 0; + + /* Adjust a PC relative relocation by removing the reference + to the original address in the section and including the + reference to the new address. However, external RELHI + and RELLO relocs are PC relative, but don't include any + reference to the address. The addend is merely an + addend. */ + if (howto->pc_relative + && (! int_rel.r_extern + || (int_rel.r_type != MIPS_R_RELHI + && int_rel.r_type != MIPS_R_RELLO))) + relocation -= (input_section->output_section->vma + + input_section->output_offset + - input_section->vma); + + /* Adjust the contents. */ + if (relocation == 0) + r = bfd_reloc_ok; + else + { + if (int_rel.r_type != MIPS_R_REFHI + && int_rel.r_type != MIPS_R_RELHI) + r = _bfd_relocate_contents (howto, input_bfd, relocation, + (contents + + adjust + + int_rel.r_vaddr + - input_section->vma)); + else + { + mips_relocate_hi (&int_rel, &lo_int_rel, + input_bfd, input_section, contents, + adjust, relocation, + int_rel.r_type == MIPS_R_RELHI); + r = bfd_reloc_ok; + } + } + + /* Adjust the reloc address. */ + int_rel.r_vaddr += (input_section->output_section->vma + + input_section->output_offset + - input_section->vma); + + /* Save the changed reloc information. */ + mips_ecoff_swap_reloc_out (input_bfd, &int_rel, (PTR) ext_rel); + } + else + { + /* We are producing a final executable. */ + if (int_rel.r_extern) + { + /* This is a reloc against a symbol. */ + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + + hsec = h->root.u.def.section; + relocation = (h->root.u.def.value + + hsec->output_section->vma + + hsec->output_offset); + } + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, + int_rel.r_vaddr - input_section->vma))) + return false; + relocation = 0; + } + } + else + { + /* This is a reloc against a section. */ + relocation = (s->output_section->vma + + s->output_offset + - s->vma); + + /* A PC relative reloc is already correct in the object + file. Make it look like a pcrel_offset relocation by + adding in the start address. */ + if (howto->pc_relative) + { + if (int_rel.r_type != MIPS_R_RELHI) + relocation += int_rel.r_vaddr + adjust; + else + relocation += lo_int_rel.r_vaddr + adjust; + } + } + + if (int_rel.r_type != MIPS_R_REFHI + && int_rel.r_type != MIPS_R_RELHI) + r = _bfd_final_link_relocate (howto, + input_bfd, + input_section, + contents, + (int_rel.r_vaddr + - input_section->vma + + adjust), + relocation, + addend); + else + { + mips_relocate_hi (&int_rel, &lo_int_rel, input_bfd, + input_section, contents, adjust, + relocation, + int_rel.r_type == MIPS_R_RELHI); + r = bfd_reloc_ok; + } + } + + /* MIPS_R_JMPADDR requires peculiar overflow detection. The + instruction provides a 28 bit address (the two lower bits are + implicit zeroes) which is combined with the upper four bits + of the instruction address. */ + if (r == bfd_reloc_ok + && int_rel.r_type == MIPS_R_JMPADDR + && (((relocation + + addend + + (int_rel.r_extern ? 0 : s->vma)) + & 0xf0000000) + != ((input_section->output_section->vma + + input_section->output_offset + + (int_rel.r_vaddr - input_section->vma) + + adjust) + & 0xf0000000))) + r = bfd_reloc_overflow; + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (int_rel.r_extern) + name = h->root.root.string; + else + name = bfd_section_name (input_bfd, s); + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, + int_rel.r_vaddr - input_section->vma))) + return false; + } + break; + } + } + } + + return true; +} + +/* Read in the relocs for a section. */ + +static boolean +mips_read_relocs (abfd, sec) + bfd *abfd; + asection *sec; +{ + struct ecoff_section_tdata *section_tdata; + + section_tdata = ecoff_section_data (abfd, sec); + if (section_tdata == (struct ecoff_section_tdata *) NULL) + { + sec->used_by_bfd = + (PTR) bfd_alloc_by_size_t (abfd, sizeof (struct ecoff_section_tdata)); + if (sec->used_by_bfd == NULL) + return false; + + section_tdata = ecoff_section_data (abfd, sec); + section_tdata->external_relocs = NULL; + section_tdata->contents = NULL; + section_tdata->offsets = NULL; + } + + if (section_tdata->external_relocs == NULL) + { + bfd_size_type external_relocs_size; + + external_relocs_size = (ecoff_backend (abfd)->external_reloc_size + * sec->reloc_count); + + section_tdata->external_relocs = + (PTR) bfd_alloc (abfd, external_relocs_size); + if (section_tdata->external_relocs == NULL && external_relocs_size != 0) + return false; + + if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 + || (bfd_read (section_tdata->external_relocs, 1, + external_relocs_size, abfd) + != external_relocs_size)) + return false; + } + + return true; +} + +/* Relax a section when linking a MIPS ECOFF file. This is used for + embedded PIC code, which always uses PC relative branches which + only have an 18 bit range on MIPS. If a branch is not in range, we + generate a long instruction sequence to compensate. Each time we + find a branch to expand, we have to check all the others again to + make sure they are still in range. This is slow, but it only has + to be done when -relax is passed to the linker. + + This routine figures out which branches need to expand; the actual + expansion is done in mips_relocate_section when the section + contents are relocated. The information is stored in the offsets + field of the ecoff_section_tdata structure. An offset of 1 means + that the branch must be expanded into a multi-instruction PC + relative branch (such an offset will only occur for a PC relative + branch to an external symbol). Any other offset must be a multiple + of four, and is the amount to change the branch by (such an offset + will only occur for a PC relative branch within the same section). + + We do not modify the section relocs or contents themselves so that + if memory usage becomes an issue we can discard them and read them + again. The only information we must save in memory between this + routine and the mips_relocate_section routine is the table of + offsets. */ + +static boolean +mips_relax_section (abfd, sec, info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *info; + boolean *again; +{ + struct ecoff_section_tdata *section_tdata; + bfd_byte *contents = NULL; + long *offsets; + struct external_reloc *ext_rel; + struct external_reloc *ext_rel_end; + unsigned int i; + + /* Assume we are not going to need another pass. */ + *again = false; + + /* If we are not generating an ECOFF file, this is much too + confusing to deal with. */ + if (info->hash->creator->flavour != bfd_get_flavour (abfd)) + return true; + + /* If there are no relocs, there is nothing to do. */ + if (sec->reloc_count == 0) + return true; + + /* We are only interested in PC relative relocs, and why would there + ever be one from anything but the .text section? */ + if (strcmp (bfd_get_section_name (abfd, sec), ".text") != 0) + return true; + + /* Read in the relocs, if we haven't already got them. */ + section_tdata = ecoff_section_data (abfd, sec); + if (section_tdata == (struct ecoff_section_tdata *) NULL + || section_tdata->external_relocs == NULL) + { + if (! mips_read_relocs (abfd, sec)) + goto error_return; + section_tdata = ecoff_section_data (abfd, sec); + } + + if (sec->_cooked_size == 0) + { + /* We must initialize _cooked_size only the first time we are + called. */ + sec->_cooked_size = sec->_raw_size; + } + + contents = section_tdata->contents; + offsets = section_tdata->offsets; + + /* Look for any external PC relative relocs. Internal PC relative + relocs are already correct in the object file, so they certainly + can not overflow. */ + ext_rel = (struct external_reloc *) section_tdata->external_relocs; + ext_rel_end = ext_rel + sec->reloc_count; + for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++) + { + struct internal_reloc int_rel; + struct ecoff_link_hash_entry *h; + asection *hsec; + bfd_signed_vma relocation; + struct external_reloc *adj_ext_rel; + unsigned int adj_i; + unsigned long ext_count; + struct ecoff_link_hash_entry **adj_h_ptr; + struct ecoff_link_hash_entry **adj_h_ptr_end; + struct ecoff_value_adjust *adjust; + + /* If we have already expanded this reloc, we certainly don't + need to do it again. */ + if (offsets != (long *) NULL && offsets[i] == 1) + continue; + + /* Quickly check that this reloc is external PCREL16. */ + if (bfd_header_big_endian (abfd)) + { + if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_BIG) == 0 + || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_BIG) + >> RELOC_BITS3_TYPE_SH_BIG) + != MIPS_R_PCREL16)) + continue; + } + else + { + if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) == 0 + || (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_LITTLE) + >> RELOC_BITS3_TYPE_SH_LITTLE) + != MIPS_R_PCREL16)) + continue; + } + + mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel); + + h = ecoff_data (abfd)->sym_hashes[int_rel.r_symndx]; + if (h == (struct ecoff_link_hash_entry *) NULL) + abort (); + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + { + /* Just ignore undefined symbols. These will presumably + generate an error later in the link. */ + continue; + } + + /* Get the value of the symbol. */ + hsec = h->root.u.def.section; + relocation = (h->root.u.def.value + + hsec->output_section->vma + + hsec->output_offset); + + /* Subtract out the current address. */ + relocation -= (sec->output_section->vma + + sec->output_offset + + (int_rel.r_vaddr - sec->vma)); + + /* The addend is stored in the object file. In the normal case + of ``bal symbol'', the addend will be -4. It will only be + different in the case of ``bal symbol+constant''. To avoid + always reading in the section contents, we don't check the + addend in the object file (we could easily check the contents + if we happen to have already read them in, but I fear that + this could be confusing). This means we will screw up if + there is a branch to a symbol that is in range, but added to + a constant which puts it out of range; in such a case the + link will fail with a reloc overflow error. Since the + compiler will never generate such code, it should be easy + enough to work around it by changing the assembly code in the + source file. */ + relocation -= 4; + + /* Now RELOCATION is the number we want to put in the object + file. See whether it fits. */ + if (relocation >= -0x20000 && relocation < 0x20000) + continue; + + /* Now that we know this reloc needs work, which will rarely + happen, go ahead and grab the section contents. */ + if (contents == (bfd_byte *) NULL) + { + if (info->keep_memory) + contents = (bfd_byte *) bfd_alloc (abfd, sec->_raw_size); + else + contents = (bfd_byte *) bfd_malloc ((size_t) sec->_raw_size); + if (contents == (bfd_byte *) NULL) + goto error_return; + if (! bfd_get_section_contents (abfd, sec, (PTR) contents, + (file_ptr) 0, sec->_raw_size)) + goto error_return; + if (info->keep_memory) + section_tdata->contents = contents; + } + + /* We only support changing the bal instruction. It would be + possible to handle other PC relative branches, but some of + them (the conditional branches) would require a different + length instruction sequence which would complicate both this + routine and mips_relax_pcrel16. It could be written if + somebody felt it were important. Ignoring this reloc will + presumably cause a reloc overflow error later on. */ + if (bfd_get_32 (abfd, contents + int_rel.r_vaddr - sec->vma) + != 0x0411ffff) /* bgezal $0,. == bal . */ + continue; + + /* Bother. We need to expand this reloc, and we will need to + make another relaxation pass since this change may put other + relocs out of range. We need to examine the local branches + and we need to allocate memory to hold the offsets we must + add to them. We also need to adjust the values of all + symbols in the object file following this location. */ + + sec->_cooked_size += PCREL16_EXPANSION_ADJUSTMENT; + *again = true; + + if (offsets == (long *) NULL) + { + size_t size; + + size = sec->reloc_count * sizeof (long); + offsets = (long *) bfd_alloc_by_size_t (abfd, size); + if (offsets == (long *) NULL) + goto error_return; + memset (offsets, 0, size); + section_tdata->offsets = offsets; + } + + offsets[i] = 1; + + /* Now look for all PC relative references that cross this reloc + and adjust their offsets. */ + adj_ext_rel = (struct external_reloc *) section_tdata->external_relocs; + for (adj_i = 0; adj_ext_rel < ext_rel_end; adj_ext_rel++, adj_i++) + { + struct internal_reloc adj_int_rel; + bfd_vma start, stop; + int change; + + mips_ecoff_swap_reloc_in (abfd, (PTR) adj_ext_rel, &adj_int_rel); + + if (adj_int_rel.r_type == MIPS_R_PCREL16) + { + unsigned long insn; + + /* We only care about local references. External ones + will be relocated correctly anyhow. */ + if (adj_int_rel.r_extern) + continue; + + /* We are only interested in a PC relative reloc within + this section. FIXME: Cross section PC relative + relocs may not be handled correctly; does anybody + care? */ + if (adj_int_rel.r_symndx != RELOC_SECTION_TEXT) + continue; + + start = adj_int_rel.r_vaddr; + + insn = bfd_get_32 (abfd, + contents + adj_int_rel.r_vaddr - sec->vma); + + stop = (insn & 0xffff) << 2; + if ((stop & 0x20000) != 0) + stop -= 0x40000; + stop += adj_int_rel.r_vaddr + 4; + } + else if (adj_int_rel.r_type == MIPS_R_RELHI) + { + struct internal_reloc rello; + long addhi, addlo; + + /* The next reloc must be MIPS_R_RELLO, and we handle + them together. */ + BFD_ASSERT (adj_ext_rel + 1 < ext_rel_end); + + mips_ecoff_swap_reloc_in (abfd, (PTR) (adj_ext_rel + 1), &rello); + + BFD_ASSERT (rello.r_type == MIPS_R_RELLO); + + addhi = bfd_get_32 (abfd, + contents + adj_int_rel.r_vaddr - sec->vma); + addhi &= 0xffff; + if (addhi & 0x8000) + addhi -= 0x10000; + addhi <<= 16; + + addlo = bfd_get_32 (abfd, contents + rello.r_vaddr - sec->vma); + addlo &= 0xffff; + if (addlo & 0x8000) + addlo -= 0x10000; + + if (adj_int_rel.r_extern) + { + /* The value we want here is + sym - RELLOaddr + addend + which we can express as + sym - (RELLOaddr - addend) + Therefore if we are expanding the area between + RELLOaddr and RELLOaddr - addend we must adjust + the addend. This is admittedly ambiguous, since + we might mean (sym + addend) - RELLOaddr, but in + practice we don't, and there is no way to handle + that case correctly since at this point we have + no idea whether any reloc is being expanded + between sym and sym + addend. */ + start = rello.r_vaddr - (addhi + addlo); + stop = rello.r_vaddr; + } + else + { + /* An internal RELHI/RELLO pair represents the + difference between two addresses, $LC0 - foo. + The symndx value is actually the difference + between the reloc address and $LC0. This lets us + compute $LC0, and, by considering the addend, + foo. If the reloc we are expanding falls between + those two relocs, we must adjust the addend. At + this point, the symndx value is actually in the + r_offset field, where it was put by + mips_ecoff_swap_reloc_in. */ + start = rello.r_vaddr - adj_int_rel.r_offset; + stop = start + addhi + addlo; + } + } + else if (adj_int_rel.r_type == MIPS_R_SWITCH) + { + /* A MIPS_R_SWITCH reloc represents a word of the form + .word $L3-$LS12 + The value in the object file is correct, assuming the + original value of $L3. The symndx value is actually + the difference between the reloc address and $LS12. + This lets us compute the original value of $LS12 as + vaddr - symndx + and the original value of $L3 as + vaddr - symndx + addend + where addend is the value from the object file. At + this point, the symndx value is actually found in the + r_offset field, since it was moved by + mips_ecoff_swap_reloc_in. */ + start = adj_int_rel.r_vaddr - adj_int_rel.r_offset; + stop = start + bfd_get_32 (abfd, + (contents + + adj_int_rel.r_vaddr + - sec->vma)); + } + else + continue; + + /* If the range expressed by this reloc, which is the + distance between START and STOP crosses the reloc we are + expanding, we must adjust the offset. The sign of the + adjustment depends upon the direction in which the range + crosses the reloc being expanded. */ + if (start <= int_rel.r_vaddr && stop > int_rel.r_vaddr) + change = PCREL16_EXPANSION_ADJUSTMENT; + else if (start > int_rel.r_vaddr && stop <= int_rel.r_vaddr) + change = - PCREL16_EXPANSION_ADJUSTMENT; + else + change = 0; + + offsets[adj_i] += change; + + if (adj_int_rel.r_type == MIPS_R_RELHI) + { + adj_ext_rel++; + adj_i++; + offsets[adj_i] += change; + } + } + + /* Find all symbols in this section defined by this object file + and adjust their values. Note that we decide whether to + adjust the value based on the value stored in the ECOFF EXTR + structure, because the value stored in the hash table may + have been changed by an earlier expanded reloc and thus may + no longer correctly indicate whether the symbol is before or + after the expanded reloc. */ + ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax; + adj_h_ptr = ecoff_data (abfd)->sym_hashes; + adj_h_ptr_end = adj_h_ptr + ext_count; + for (; adj_h_ptr < adj_h_ptr_end; adj_h_ptr++) + { + struct ecoff_link_hash_entry *adj_h; + + adj_h = *adj_h_ptr; + if (adj_h != (struct ecoff_link_hash_entry *) NULL + && (adj_h->root.type == bfd_link_hash_defined + || adj_h->root.type == bfd_link_hash_defweak) + && adj_h->root.u.def.section == sec + && adj_h->esym.asym.value > int_rel.r_vaddr) + adj_h->root.u.def.value += PCREL16_EXPANSION_ADJUSTMENT; + } + + /* Add an entry to the symbol value adjust list. This is used + by bfd_ecoff_debug_accumulate to adjust the values of + internal symbols and FDR's. */ + adjust = ((struct ecoff_value_adjust *) + bfd_alloc (abfd, sizeof (struct ecoff_value_adjust))); + if (adjust == (struct ecoff_value_adjust *) NULL) + goto error_return; + + adjust->start = int_rel.r_vaddr; + adjust->end = sec->vma + sec->_raw_size; + adjust->adjust = PCREL16_EXPANSION_ADJUSTMENT; + + adjust->next = ecoff_data (abfd)->debug_info.adjust; + ecoff_data (abfd)->debug_info.adjust = adjust; + } + + if (contents != (bfd_byte *) NULL && ! info->keep_memory) + free (contents); + + return true; + + error_return: + if (contents != (bfd_byte *) NULL && ! info->keep_memory) + free (contents); + return false; +} + +/* This routine is called from mips_relocate_section when a PC + relative reloc must be expanded into the five instruction sequence. + It handles all the details of the expansion, including resolving + the reloc. */ + +static boolean +mips_relax_pcrel16 (info, input_bfd, input_section, h, location, address) + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + struct ecoff_link_hash_entry *h; + bfd_byte *location; + bfd_vma address; +{ + bfd_vma relocation; + + /* 0x0411ffff is bgezal $0,. == bal . */ + BFD_ASSERT (bfd_get_32 (input_bfd, location) == 0x0411ffff); + + /* We need to compute the distance between the symbol and the + current address plus eight. */ + relocation = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + relocation -= address + 8; + + /* If the lower half is negative, increment the upper 16 half. */ + if ((relocation & 0x8000) != 0) + relocation += 0x10000; + + bfd_put_32 (input_bfd, 0x04110001, location); /* bal .+8 */ + bfd_put_32 (input_bfd, + 0x3c010000 | ((relocation >> 16) & 0xffff), /* lui $at,XX */ + location + 4); + bfd_put_32 (input_bfd, + 0x24210000 | (relocation & 0xffff), /* addiu $at,$at,XX */ + location + 8); + bfd_put_32 (input_bfd, 0x003f0821, location + 12); /* addu $at,$at,$ra */ + bfd_put_32 (input_bfd, 0x0020f809, location + 16); /* jalr $at */ + + return true; +} + +/* Given a .sdata section and a .rel.sdata in-memory section, store + relocation information into the .rel.sdata section which can be + used at runtime to relocate the section. This is called by the + linker when the --embedded-relocs switch is used. This is called + after the add_symbols entry point has been called for all the + objects, and before the final_link entry point is called. This + function presumes that the object was compiled using + -membedded-pic. */ + +boolean +bfd_mips_ecoff_create_embedded_relocs (abfd, info, datasec, relsec, errmsg) + bfd *abfd; + struct bfd_link_info *info; + asection *datasec; + asection *relsec; + char **errmsg; +{ + struct ecoff_link_hash_entry **sym_hashes; + struct ecoff_section_tdata *section_tdata; + struct external_reloc *ext_rel; + struct external_reloc *ext_rel_end; + bfd_byte *p; + + BFD_ASSERT (! info->relocateable); + + *errmsg = NULL; + + if (datasec->reloc_count == 0) + return true; + + sym_hashes = ecoff_data (abfd)->sym_hashes; + + if (! mips_read_relocs (abfd, datasec)) + return false; + + relsec->contents = (bfd_byte *) bfd_alloc (abfd, datasec->reloc_count * 4); + if (relsec->contents == NULL) + return false; + + p = relsec->contents; + + section_tdata = ecoff_section_data (abfd, datasec); + ext_rel = (struct external_reloc *) section_tdata->external_relocs; + ext_rel_end = ext_rel + datasec->reloc_count; + for (; ext_rel < ext_rel_end; ext_rel++, p += 4) + { + struct internal_reloc int_rel; + boolean text_relative; + + mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel); + + /* We are going to write a four byte word into the runtime reloc + section. The word will be the address in the data section + which must be relocated. This must be on a word boundary, + which means the lower two bits must be zero. We use the + least significant bit to indicate how the value in the data + section must be relocated. A 0 means that the value is + relative to the text section, while a 1 indicates that the + value is relative to the data section. Given that we are + assuming the code was compiled using -membedded-pic, there + should not be any other possibilities. */ + + /* We can only relocate REFWORD relocs at run time. */ + if (int_rel.r_type != MIPS_R_REFWORD) + { + *errmsg = "unsupported reloc type"; + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (int_rel.r_extern) + { + struct ecoff_link_hash_entry *h; + + h = sym_hashes[int_rel.r_symndx]; + /* If h is NULL, that means that there is a reloc against an + external symbol which we thought was just a debugging + symbol. This should not happen. */ + if (h == (struct ecoff_link_hash_entry *) NULL) + abort (); + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section->flags & SEC_CODE) != 0) + text_relative = true; + else + text_relative = false; + } + else + { + switch (int_rel.r_symndx) + { + case RELOC_SECTION_TEXT: + text_relative = true; + break; + case RELOC_SECTION_SDATA: + case RELOC_SECTION_SBSS: + case RELOC_SECTION_LIT8: + text_relative = false; + break; + default: + /* No other sections should appear in -membedded-pic + code. */ + *errmsg = "reloc against unsupported section"; + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + if ((int_rel.r_offset & 3) != 0) + { + *errmsg = "reloc not properly aligned"; + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_put_32 (abfd, + (int_rel.r_vaddr - datasec->vma + datasec->output_offset + + (text_relative ? 0 : 1)), + p); + } + + return true; +} + +/* This is the ECOFF backend structure. The backend field of the + target vector points to this. */ + +static const struct ecoff_backend_data mips_ecoff_backend_data = +{ + /* COFF backend structure. */ + { + (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */ + (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */ + (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */ + (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */ + (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */ + mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out, + mips_ecoff_swap_scnhdr_out, + FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, true, + mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in, + mips_ecoff_swap_scnhdr_in, NULL, + mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, + _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, + _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }, + /* Supported architecture. */ + bfd_arch_mips, + /* Initial portion of armap string. */ + "__________", + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + 0x1000, + /* True if the .rdata section is part of the text segment, as on the + Alpha. False if .rdata is part of the data segment, as on the + MIPS. */ + false, + /* Bitsize of constructor entries. */ + 32, + /* Reloc to use for constructor entries. */ + &mips_howto_table[MIPS_R_REFWORD], + { + /* Symbol table magic number. */ + magicSym, + /* Alignment of debugging information. E.g., 4. */ + 4, + /* Sizes of external symbolic information. */ + sizeof (struct hdr_ext), + sizeof (struct dnr_ext), + sizeof (struct pdr_ext), + sizeof (struct sym_ext), + sizeof (struct opt_ext), + sizeof (struct fdr_ext), + sizeof (struct rfd_ext), + sizeof (struct ext_ext), + /* Functions to swap in external symbolic data. */ + ecoff_swap_hdr_in, + ecoff_swap_dnr_in, + ecoff_swap_pdr_in, + ecoff_swap_sym_in, + ecoff_swap_opt_in, + ecoff_swap_fdr_in, + ecoff_swap_rfd_in, + ecoff_swap_ext_in, + _bfd_ecoff_swap_tir_in, + _bfd_ecoff_swap_rndx_in, + /* Functions to swap out external symbolic data. */ + ecoff_swap_hdr_out, + ecoff_swap_dnr_out, + ecoff_swap_pdr_out, + ecoff_swap_sym_out, + ecoff_swap_opt_out, + ecoff_swap_fdr_out, + ecoff_swap_rfd_out, + ecoff_swap_ext_out, + _bfd_ecoff_swap_tir_out, + _bfd_ecoff_swap_rndx_out, + /* Function to read in symbolic data. */ + _bfd_ecoff_slurp_symbolic_info + }, + /* External reloc size. */ + RELSZ, + /* Reloc swapping functions. */ + mips_ecoff_swap_reloc_in, + mips_ecoff_swap_reloc_out, + /* Backend reloc tweaking. */ + mips_adjust_reloc_in, + mips_adjust_reloc_out, + /* Relocate section contents while linking. */ + mips_relocate_section, + /* Do final adjustments to filehdr and aouthdr. */ + NULL, + /* Read an element from an archive at a given file position. */ + _bfd_get_elt_at_filepos +}; + +/* Looking up a reloc type is MIPS specific. */ +#define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup + +/* Getting relocated section contents is generic. */ +#define _bfd_ecoff_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents + +/* Handling file windows is generic. */ +#define _bfd_ecoff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +/* Relaxing sections is MIPS specific. */ +#define _bfd_ecoff_bfd_relax_section mips_relax_section + +const bfd_target ecoff_little_vec = +{ + "ecoff-littlemips", /* name */ + bfd_target_ecoff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + _bfd_ecoff_archive_p, _bfd_dummy_target}, + {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), + BFD_JUMP_TABLE_COPY (_bfd_ecoff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), + BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), + BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), + BFD_JUMP_TABLE_WRITE (_bfd_ecoff), + BFD_JUMP_TABLE_LINK (_bfd_ecoff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) &mips_ecoff_backend_data +}; + +const bfd_target ecoff_big_vec = +{ + "ecoff-bigmips", /* name */ + bfd_target_ecoff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + _bfd_ecoff_archive_p, _bfd_dummy_target}, + {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), + BFD_JUMP_TABLE_COPY (_bfd_ecoff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), + BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), + BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), + BFD_JUMP_TABLE_WRITE (_bfd_ecoff), + BFD_JUMP_TABLE_LINK (_bfd_ecoff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) &mips_ecoff_backend_data +}; diff --git a/contrib/gdb/bfd/coff-pmac.c b/contrib/gdb/bfd/coff-pmac.c new file mode 100644 index 000000000000..f3332d98959b --- /dev/null +++ b/contrib/gdb/bfd/coff-pmac.c @@ -0,0 +1,27 @@ +/* BFD back-end for Apple et al PowerPC Mac "XCOFF" files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM pmac_xcoff_vec +#define TARGET_NAME "xcoff-powermac" + +/* Tweak coffcode.h based on this being a PowerMac instead of RS/6000. */ + +#define POWERMAC + +#include "coff-rs6000.c" diff --git a/contrib/gdb/bfd/coff-ppc.c b/contrib/gdb/bfd/coff-ppc.c new file mode 100644 index 000000000000..4caf3d8dc01d --- /dev/null +++ b/contrib/gdb/bfd/coff-ppc.c @@ -0,0 +1,3255 @@ +/* BFD back-end for PowerPC Microsoft Portable Executable files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Original version pieced together by Kim Knuttila (krk@cygnus.com) + + There is nothing new under the sun. This file draws a lot on other + coff files, in particular, those for the rs/6000, alpha, mips, and + intel backends, and the PE work for the arm. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Current State: + - objdump works + - relocs generated by gas + - ld will link files, but they do not run. + - dlltool will not produce correct output in some .reloc cases, and will + not produce the right glue code for dll function calls. +*/ + + +#include "bfd.h" +#include "sysdep.h" + +#include "libbfd.h" +#include "obstack.h" + +#include "coff/powerpc.h" +#include "coff/internal.h" + +#include "coff/pe.h" + +#ifdef BADMAG +#undef BADMAG +#endif + +#define BADMAG(x) PPCBADMAG(x) + +#include "libcoff.h" + +/* The toc is a set of bfd_vma fields. We use the fact that valid */ +/* addresses are even (i.e. the bit representing "1" is off) to allow */ +/* us to encode a little extra information in the field */ +/* - Unallocated addresses are intialized to 1. */ +/* - Allocated addresses are even numbers. */ +/* The first time we actually write a reference to the toc in the bfd, */ +/* we want to record that fact in a fixup file (if it is asked for), so */ +/* we keep track of whether or not an address has been written by marking */ +/* the low order bit with a "1" upon writing */ + +#define SET_UNALLOCATED(x) ((x) = 1) +#define IS_UNALLOCATED(x) ((x) == 1) + +#define IS_WRITTEN(x) ((x) & 1) +#define MARK_AS_WRITTEN(x) ((x) |= 1) +#define MAKE_ADDR_AGAIN(x) ((x) &= ~1) + +/* In order not to add an int to every hash table item for every coff + linker, we define our own hash table, derived from the coff one */ + +/* PE linker hash table entries. */ + +struct ppc_coff_link_hash_entry +{ + struct coff_link_hash_entry root; /* First entry, as required */ + + /* As we wonder around the relocs, we'll keep the assigned toc_offset + here */ + bfd_vma toc_offset; /* Our addition, as required */ + int symbol_is_glue; + unsigned long int glue_insn; + char eye_catcher[8]; +}; + +/* Need a 7 char string for an eye catcher */ +#define EYE "krkjunk" + +#define CHECK_EYE(addr) \ + if (strcmp(addr, EYE) != 0) \ + { \ + fprintf(stderr,\ + "File %s, line %d, Hash check failure, bad eye %8s\n", \ + __FILE__, __LINE__, addr); \ + abort(); \ + } + +/* PE linker hash table. */ + +struct ppc_coff_link_hash_table +{ + struct coff_link_hash_table root; /* First entry, as required */ +}; + +static struct bfd_hash_entry *ppc_coff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Routine to create an entry in the link hash table. */ + +static struct bfd_hash_entry * +ppc_coff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ppc_coff_link_hash_entry *ret = + (struct ppc_coff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct ppc_coff_link_hash_entry *) NULL) + ret = (struct ppc_coff_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct ppc_coff_link_hash_entry)); + + if (ret == (struct ppc_coff_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ppc_coff_link_hash_entry *) + _bfd_coff_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Initialize the local fields. */ + SET_UNALLOCATED(ret->toc_offset); + ret->symbol_is_glue = 0; + ret->glue_insn = 0; + strcpy(ret->eye_catcher, EYE); + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a PE linker hash table. */ + +static boolean +ppc_coff_link_hash_table_init (table, abfd, newfunc) + struct ppc_coff_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc); +} + +/* Create a PE linker hash table. */ + +static struct bfd_link_hash_table * +ppc_coff_link_hash_table_create (abfd) + bfd *abfd; +{ + struct ppc_coff_link_hash_table *ret; + + ret = ((struct ppc_coff_link_hash_table *) + bfd_alloc (abfd, sizeof (struct ppc_coff_link_hash_table))); + if (ret == NULL) + return NULL; + if (! ppc_coff_link_hash_table_init (ret, abfd, + ppc_coff_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root.root; +} + +/* Now, tailor coffcode.h to use our hash stuff */ + +#define coff_bfd_link_hash_table_create ppc_coff_link_hash_table_create + + +/* The nt loader points the toc register to &toc + 32768, in order to */ +/* use the complete range of a 16-bit displacement (I guess). We have */ +/* to adjust for this when we fix up loads displaced off the toc reg. */ +#define TOC_LOAD_ADJUSTMENT (-32768) +#define TOC_SECTION_NAME ".private.toc" + +/* The main body of code is in coffcode.h. */ + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value + from smaller values. Start with zero, widen, *then* decrement. */ +#define MINUS_ONE (((bfd_vma)0) - 1) + +/* these should definitely go in a header file somewhere... */ + +/* NOP */ +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 + +/* 64-bit address */ +#define IMAGE_REL_PPC_ADDR64 0x0001 + +/* 32-bit address */ +#define IMAGE_REL_PPC_ADDR32 0x0002 + +/* 26-bit address, shifted left 2 (branch absolute) */ +#define IMAGE_REL_PPC_ADDR24 0x0003 + +/* 16-bit address */ +#define IMAGE_REL_PPC_ADDR16 0x0004 + +/* 16-bit address, shifted left 2 (load doubleword) */ +#define IMAGE_REL_PPC_ADDR14 0x0005 + +/* 26-bit PC-relative offset, shifted left 2 (branch relative) */ +#define IMAGE_REL_PPC_REL24 0x0006 + +/* 16-bit PC-relative offset, shifted left 2 (br cond relative) */ +#define IMAGE_REL_PPC_REL14 0x0007 + +/* 16-bit offset from TOC base */ +#define IMAGE_REL_PPC_TOCREL16 0x0008 + +/* 16-bit offset from TOC base, shifted left 2 (load doubleword) */ +#define IMAGE_REL_PPC_TOCREL14 0x0009 + +/* 32-bit addr w/o image base */ +#define IMAGE_REL_PPC_ADDR32NB 0x000A + +/* va of containing section (as in an image sectionhdr) */ +#define IMAGE_REL_PPC_SECREL 0x000B + +/* sectionheader number */ +#define IMAGE_REL_PPC_SECTION 0x000C + +/* substitute TOC restore instruction iff symbol is glue code */ +#define IMAGE_REL_PPC_IFGLUE 0x000D + +/* symbol is glue code; virtual address is TOC restore instruction */ +#define IMAGE_REL_PPC_IMGLUE 0x000E + +/* va of containing section (limited to 16 bits) */ +#define IMAGE_REL_PPC_SECREL16 0x000F + +/* stuff to handle immediate data when the number of bits in the */ +/* data is greater than the number of bits in the immediate field */ +/* We need to do (usually) 32 bit arithmetic on 16 bit chunks */ +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 + +/* This is essentially the same as tocrel16, with TOCDEFN assumed */ +#define IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 + +/* Flag bits in IMAGE_RELOCATION.TYPE */ + +/* subtract reloc value rather than adding it */ +#define IMAGE_REL_PPC_NEG 0x0100 + +/* fix branch prediction bit to predict branch taken */ +#define IMAGE_REL_PPC_BRTAKEN 0x0200 + +/* fix branch prediction bit to predict branch not taken */ +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 + +/* toc slot defined in file (or, data in toc) */ +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +/* masks to isolate above values in IMAGE_RELOCATION.Type */ +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +#define IMAGE_REL_PPC_FLAGMASK 0x0F00 + +#define EXTRACT_TYPE(x) ((x) & IMAGE_REL_PPC_TYPEMASK) +#define EXTRACT_FLAGS(x) ((x) & IMAGE_REL_PPC_FLAGMASK) +#define EXTRACT_JUNK(x) \ + ((x) & ~(IMAGE_REL_PPC_TYPEMASK | IMAGE_REL_PPC_FLAGMASK)) + + +/* static helper functions to make relocation work */ +/* (Work In Progress) */ + +static bfd_reloc_status_type ppc_refhi_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type ppc_reflo_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type ppc_pair_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + + +static bfd_reloc_status_type ppc_toc16_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + +static bfd_reloc_status_type ppc_addr32nb_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + +static bfd_reloc_status_type ppc_section_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + +static bfd_reloc_status_type ppc_secrel_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + +static bfd_reloc_status_type ppc_imglue_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); + + + +static boolean in_reloc_p PARAMS((bfd *abfd, reloc_howto_type *howto)); + + +/* FIXME: It'll take a while to get through all of these. I only need a few to + get us started, so those I'll make sure work. Those marked FIXME are either + completely unverified or have a specific unknown marked in the comment */ + +/*---------------------------------------------------------------------------*/ +/* */ +/* Relocation entries for Windows/NT on PowerPC. */ +/* */ +/* From the document "" we find the following listed as used relocs: */ +/* */ +/* ABSOLUTE : The noop */ +/* ADDR[64|32|16] : fields that hold addresses in data fields or the */ +/* 16 bit displacement field on a load/store. */ +/* ADDR[24|14] : fields that hold addresses in branch and cond */ +/* branches. These represent [26|16] bit addresses. */ +/* The low order 2 bits are preserved. */ +/* REL[24|14] : branches relative to the Instruction Address */ +/* register. These represent [26|16] bit addresses, */ +/* as before. The instruction field will be zero, and */ +/* the address of the SYM will be inserted at link time. */ +/* TOCREL16 : 16 bit displacement field referring to a slot in */ +/* toc. */ +/* TOCREL14 : 16 bit displacement field, similar to REL14 or ADDR14. */ +/* ADDR32NB : 32 bit address relative to the virtual origin. */ +/* (On the alpha, this is always a linker generated thunk)*/ +/* (i.e. 32bit addr relative to the image base) */ +/* SECREL : The value is relative to the start of the section */ +/* containing the symbol. */ +/* SECTION : access to the header containing the item. Supports the */ +/* codeview debugger. */ +/* */ +/* In particular, note that the document does not indicate that the */ +/* relocations listed in the header file are used. */ +/* */ +/* */ +/* */ +/*---------------------------------------------------------------------------*/ + +static reloc_howto_type ppc_coff_howto_table[] = +{ + /* IMAGE_REL_PPC_ABSOLUTE 0x0000 NOP */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_ABSOLUTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* dont complain_on_overflow */ + 0, /* special_function */ + "ABSOLUTE", /* name */ + false, /* partial_inplace */ + 0x00, /* src_mask */ + 0x00, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR64 0x0001 64-bit address */ + /* Unused: */ + HOWTO(IMAGE_REL_PPC_ADDR64, /* type */ + 0, /* rightshift */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR64", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR32 0x0002 32-bit address */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_ADDR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR24 0x0003 26-bit address, shifted left 2 (branch absolute) */ + /* the LI field is in bit 6 through bit 29 is 24 bits, + 2 for the shift */ + /* Of course, That's the IBM approved bit numbering, which is not what */ + /* anyone else uses.... The li field is in bit 2 thru 25 */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_ADDR24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR24", /* name */ + true, /* partial_inplace */ + 0x07fffffc, /* src_mask */ + 0x07fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR16 0x0004 16-bit address */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_ADDR16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR14 0x0005 */ + /* 16-bit address, shifted left 2 (load doubleword) */ + /* FIXME: the mask is likely wrong, and the bit position may be as well */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_ADDR14, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_REL24 0x0006 */ + /* 26-bit PC-relative offset, shifted left 2 (branch relative) */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_REL24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "REL24", /* name */ + true, /* partial_inplace */ + 0x3fffffc, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_REL14 0x0007 */ + /* 16-bit PC-relative offset, shifted left 2 (br cond relative) */ + /* FIXME: the mask is likely wrong, and the bit position may be as well */ + /* FIXME: how does it know how far to shift? */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_ADDR14, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* IMAGE_REL_PPC_TOCREL16 0x0008 */ + /* 16-bit offset from TOC base */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_TOCREL16,/* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_toc16_reloc, /* special_function */ + "TOCREL16", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_TOCREL14 0x0009 */ + /* 16-bit offset from TOC base, shifted left 2 (load doubleword) */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_TOCREL14,/* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "TOCREL14", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_ADDR32NB 0x000A */ + /* 32-bit addr w/ image base */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_ADDR32NB,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "ADDR32NB", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_SECREL 0x000B */ + /* va of containing section (as in an image sectionhdr) */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_SECREL,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_secrel_reloc, /* special_function */ + "SECREL", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* IMAGE_REL_PPC_SECTION 0x000C */ + /* sectionheader number */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_SECTION,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_section_reloc, /* special_function */ + "SECTION", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* IMAGE_REL_PPC_IFGLUE 0x000D */ + /* substitute TOC restore instruction iff symbol is glue code */ + /* Used: */ + HOWTO (IMAGE_REL_PPC_IFGLUE,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "IFGLUE", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_IMGLUE 0x000E */ + /* symbol is glue code; virtual address is TOC restore instruction */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_IMGLUE,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_imglue_reloc, /* special_function */ + "IMGLUE", /* name */ + false, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_SECREL16 0x000F */ + /* va of containing section (limited to 16 bits) */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_SECREL16,/* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SECREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* IMAGE_REL_PPC_REFHI 0x0010 */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_REFHI, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_refhi_reloc, /* special_function */ + "REFHI", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_REFLO 0x0011 */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_REFLO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_refhi_reloc, /* special_function */ + "REFLO", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_PAIR 0x0012 */ + /* Unused: */ + HOWTO (IMAGE_REL_PPC_PAIR, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_pair_reloc, /* special_function */ + "PAIR", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 */ + /* 16-bit offset from TOC base, without causing a definition */ + /* Used: */ + HOWTO ( (IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN), /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "TOCREL16, TOCDEFN", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + +}; + + + + +/* Some really cheezy macros that can be turned on to test stderr :-) */ + +#ifdef DEBUG_RELOC +#define UN_IMPL(x) \ +{ \ + static int i; \ + if (i == 0) \ + { \ + i = 1; \ + fprintf(stderr,"Unimplemented Relocation -- %s\n",x); \ + } \ +} + +#define DUMP_RELOC(n,r) \ +{ \ + fprintf(stderr,"%s sym %d, addr %d, addend %d\n", \ + n, (*(r->sym_ptr_ptr))->name, \ + r->address, r->addend); \ +} + +/* Given a reloc name, n, and a pointer to an internal_reloc, + dump out interesting information on the contents + +#define n_name _n._n_name +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + +*/ + +#define DUMP_RELOC2(n,r) \ +{ \ + fprintf(stderr,"%s sym %d, r_vaddr %d %s\n", \ + n, r->r_symndx, r->r_vaddr,\ + (((r->r_type) & IMAGE_REL_PPC_TOCDEFN) == 0) \ + ?" ":" TOCDEFN" ); \ +} + +#else +#define UN_IMPL(x) +#define DUMP_RELOC(n,r) +#define DUMP_RELOC2(n,r) +#endif + + + +/* toc construction and management routines */ +extern bfd* bfd_of_toc_owner; +extern long int global_toc_size; + +extern long int import_table_size; +extern long int first_thunk_address; +extern long int thunk_size; + +enum toc_type +{ + default_toc, + toc_32, + toc_64 +}; + +enum ref_category +{ + priv, + pub, + data +}; + +struct list_ele +{ + struct list_ele *next; + bfd_vma addr; + enum ref_category cat; + int offset; + const char *name; +}; + +extern struct list_ele *head; +extern struct list_ele *tail; + +static void +record_toc(toc_section, our_toc_offset, cat, name) + asection *toc_section; + int our_toc_offset; + enum ref_category cat; + const char *name; +{ + /* add this entry to our toc addr-offset-name list */ + struct list_ele *t; + t = bfd_malloc (sizeof (struct list_ele)); + if (t == NULL) + abort (); + t->next = 0; + t->offset = our_toc_offset; + t->name = name; + t->cat = cat; + t->addr = toc_section->output_offset + our_toc_offset; + + if (head == 0) + { + head = t; + tail = t; + } + else + { + tail->next = t; + tail = t; + } +} + +/* record a toc offset against a symbol */ +static int +ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + int sym; + enum toc_type toc_kind; +{ + bfd_byte *t; + bfd_byte *old_contents; + asection *s; + int element_size; + int data; + int offset; + struct ppc_coff_link_hash_entry *h; + struct coff_symbol_struct *target; + int ret_val; + const char *name; + + int *local_syms; + + h = 0; + + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + if (h != 0) + { + CHECK_EYE(h->eye_catcher); + } + + if (h == 0) + { + local_syms = obj_coff_local_toc_table(abfd); + if (local_syms == 0) + { + int i; + /* allocate a table */ + local_syms = + (int *) bfd_zalloc (abfd, + obj_raw_syment_count(abfd) * sizeof(int)); + if (local_syms == 0) + return false; + obj_coff_local_toc_table(abfd) = local_syms; + for (i = 0; i < obj_raw_syment_count(abfd); ++i) + { + SET_UNALLOCATED(local_syms[i]); + } + } + + if (IS_UNALLOCATED(local_syms[sym])) + { + local_syms[sym] = global_toc_size; + ret_val = global_toc_size; + global_toc_size += 4; + + /* The size must fit in a 16bit displacment */ + if (global_toc_size >= 65535) + { + fprintf(stderr, + "Exceeded toc size of 65535\n"); + abort(); + } + +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting toc_offset for local sym %d to %d\n", + sym, ret_val); +#endif + } + else + { + ret_val = local_syms[sym]; +#ifdef TOC_DEBUG + fprintf(stderr, + "toc_offset already set for local sym %d to %d\n", + sym, ret_val); +#endif + } + } + else + { + name = h->root.root.root.string; + + /* check to see if there's a toc slot allocated. If not, do it + here. It will be used in relocate_section */ + if (IS_UNALLOCATED(h->toc_offset)) + { + h->toc_offset = global_toc_size; + ret_val = global_toc_size; + global_toc_size += 4; + + /* The size must fit in a 16bit displacment */ + if (global_toc_size >= 65535) + { + fprintf(stderr, + "Exceeded toc size of 65535\n"); + abort(); + } + +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting toc_offset for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + else + { + ret_val = h->toc_offset; +#ifdef TOC_DEBUG + fprintf(stderr, + "toc_offset already set for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + } + + return ret_val; +} +/* FIXME: record a toc offset against a data-in-toc symbol */ +/* Now, there is currenly some confusion on what this means. In some + compilers one sees the moral equivalent of: + .tocd + define some data + .text + refer to the data with a [tocv] qualifier + In general, one sees something to indicate that a tocd has been + seen, and that would trigger the allocation of data in toc. The IBM + docs seem to suggest that anything with the TOCDEFN qualifier should + never trigger storage allocation. However, in the kernel32.lib that + we've been using for our test bed, there are a couple of variables + referenced that fail that test. + + So it can't work that way. +*/ +static int +ppc_record_data_in_toc_entry(abfd, info, sec, sym, toc_kind) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + int sym; + enum toc_type toc_kind; +{ + bfd_byte *t; + bfd_byte *old_contents; + asection *s; + int element_size; + int data; + int offset; + struct ppc_coff_link_hash_entry *h = 0; + struct coff_symbol_struct *target; + int ret_val; + const char *name; + + int *local_syms; + + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + + if (h == 0) + { + local_syms = obj_coff_local_toc_table(abfd); + if (local_syms == 0) + { + int i; + /* allocate a table */ + local_syms = + (int *) bfd_zalloc (abfd, + obj_raw_syment_count(abfd) * sizeof(int)); + if (local_syms == 0) + return false; + obj_coff_local_toc_table(abfd) = local_syms; + for (i = 0; i < obj_raw_syment_count(abfd); ++i) + { + SET_UNALLOCATED(local_syms[i]); + } + } + + if (IS_UNALLOCATED(local_syms[sym])) + { + local_syms[sym] = global_toc_size; + ret_val = global_toc_size; + global_toc_size += 4; +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting data_in_toc_offset for local sym %d to %d\n", + sym, ret_val); +#endif + } + else + { + ret_val = local_syms[sym]; +#ifdef TOC_DEBUG + fprintf(stderr, + "data_in_toc_offset already set for local sym %d to %d\n", + sym, ret_val); +#endif + } + } + else + { + CHECK_EYE(h->eye_catcher); + + name = h->root.root.root.string; + + /* check to see if there's a toc slot allocated. If not, do it + here. It will be used in relocate_section */ + if (IS_UNALLOCATED(h->toc_offset)) + { +#if 0 + h->toc_offset = global_toc_size; +#endif + ret_val = global_toc_size; + /* We're allocating a chunk of the toc, as opposed to a slot */ + /* FIXME: alignment? */ + + global_toc_size += 4; +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting data_in_toc_offset for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + else + { + ret_val = h->toc_offset; +#ifdef TOC_DEBUG + fprintf(stderr, + "data_in_toc_offset already set for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + } + + return ret_val; +} + +/* record a toc offset against a symbol */ +static void +ppc_mark_symbol_as_glue(abfd, sym, rel) + bfd *abfd; + int sym; + struct internal_reloc *rel; +{ + struct ppc_coff_link_hash_entry *h; + + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + + CHECK_EYE(h->eye_catcher); + + h->symbol_is_glue = 1; + h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr); + + return; +} + + +/* Provided the symbol, returns the value reffed */ +static long get_symbol_value PARAMS ((asymbol *)); + +static long +get_symbol_value (symbol) + asymbol *symbol; +{ + long relocation = 0; + + if (bfd_is_com_section (symbol->section)) + { + relocation = 0; + } + else + { + relocation = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + } + + return(relocation); +} + +/* Return true if this relocation should + appear in the output .reloc section. */ + +static boolean in_reloc_p(abfd, howto) + bfd * abfd; + reloc_howto_type *howto; +{ + return + (! howto->pc_relative) + && (howto->type != IMAGE_REL_PPC_ADDR32NB) + && (howto->type != IMAGE_REL_PPC_TOCREL16) + && (howto->type != IMAGE_REL_PPC_IMGLUE) + && (howto->type != IMAGE_REL_PPC_IFGLUE) + && (howto->type != IMAGE_REL_PPC_SECREL) + && (howto->type != IMAGE_REL_PPC_SECTION) + && (howto->type != IMAGE_REL_PPC_SECREL16) + && (howto->type != IMAGE_REL_PPC_REFHI) + && (howto->type != IMAGE_REL_PPC_REFLO) + && (howto->type != IMAGE_REL_PPC_PAIR) + && (howto->type != IMAGE_REL_PPC_TOCREL16_DEFN) ; +} + +/* this function is in charge of performing all the ppc PE relocations */ +/* Don't yet know if we want to do this this particular way ... (krk) */ +/* FIXME: (it is not yet enabled) */ + +static bfd_reloc_status_type +pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* the consth relocation comes in two parts, we have to remember + the state between calls, in these variables */ + static boolean part1_consth_active = false; + static unsigned long part1_consth_value; + + unsigned long insn; + unsigned long sym_value; + unsigned long unsigned_value; + unsigned short r_type; + long signed_value; + + unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/ + bfd_byte *hit_data =addr + (bfd_byte *)(data); + + fprintf(stderr, "pe_ppc_reloc (%s)\n", TARGET_LITTLE_NAME); + + r_type = reloc_entry->howto->type; + + if (output_bfd) + { + /* Partial linking - do nothing */ + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (symbol_in != NULL + && bfd_is_und_section (symbol_in->section)) + { + /* Keep the state machine happy in case we're called again */ + if (r_type == IMAGE_REL_PPC_REFHI) + { + part1_consth_active = true; + part1_consth_value = 0; + } + return(bfd_reloc_undefined); + } + + if ((part1_consth_active) && (r_type != IMAGE_REL_PPC_PAIR)) + { + part1_consth_active = false; + *error_message = (char *) "Missing PAIR"; + return(bfd_reloc_dangerous); + } + + + sym_value = get_symbol_value(symbol_in); + + return(bfd_reloc_ok); +} + +/* The reloc processing routine for the optimized COFF linker. */ + +static boolean +coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, syms, sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + boolean hihalf; + bfd_vma hihalf_val; + asection *toc_section = 0; + bfd_vma relocation; + reloc_howto_type *howto = 0; + +#ifdef DEBUG_RELOC + fprintf(stderr, + "pe_ppc_relocate_section (%s) for %s in bfd %s\n", + TARGET_LITTLE_NAME, + input_section->name, + input_bfd->filename); + +#endif + + /* If we are performing a relocateable link, we don't need to do a + thing. The caller will take care of adjusting the reloc + addresses and symbol indices. */ + if (info->relocateable) + return true; + + hihalf = false; + hihalf_val = 0; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + struct ppc_coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma val; + + asection *sec; + bfd_reloc_status_type rstat; + bfd_byte *loc; + + unsigned short r_type = EXTRACT_TYPE (rel->r_type); + unsigned short r_flags = EXTRACT_FLAGS(rel->r_type); + unsigned short junk = EXTRACT_JUNK (rel->r_type); + +#ifdef DEBUG_RELOC + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } +#endif + + symndx = rel->r_symndx; + loc = contents + rel->r_vaddr - input_section->vma; + + /* FIXME: check bounds on r_type */ + howto = ppc_coff_howto_table + r_type; + + if (symndx == -1) + { + h = NULL; + sym = NULL; + } + else + { + h = (struct ppc_coff_link_hash_entry *) + (obj_coff_sym_hashes (input_bfd)[symndx]); + if (h != 0) + { + CHECK_EYE(h->eye_catcher); + } + + sym = syms + symndx; + } + + sec = NULL; + val = 0; + + /* FIXME: PAIR unsupported in the following code */ + if (h == NULL) + { + if (symndx == -1) + sec = bfd_abs_section_ptr; + else + { + sec = sections[symndx]; + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + CHECK_EYE(h->eye_catcher); + + if (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + { + sec = h->root.root.u.def.section; + val = (h->root.root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else + { +fprintf(stderr, + "missing %s\n",h->root.root.root.string); + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + rstat = bfd_reloc_ok; + + /* Each case must do its own relocation, setting rstat appropriately */ + switch (r_type) + { + default: + fprintf( stderr, + "ERROR: during reloc processing -- unsupported reloc %s\n", + howto->name); + bfd_set_error (bfd_error_bad_value); + abort(); + return false; + case IMAGE_REL_PPC_TOCREL16: + { + bfd_vma our_toc_offset; + int fixit; + + DUMP_RELOC2(howto->name, rel); + + if (toc_section == 0) + { + toc_section = bfd_get_section_by_name (bfd_of_toc_owner, + TOC_SECTION_NAME); +#ifdef TOC_DEBUG + + fprintf(stderr, + "BFD of toc owner %p (%s), section addr of %s %p\n", + bfd_of_toc_owner, bfd_of_toc_owner->filename, + TOC_SECTION_NAME, toc_section); +#endif + + if ( toc_section == NULL ) + { + fprintf(stderr, "No Toc section!\n"); + abort(); + } + } + + /* + * Amazing bit tricks present. As we may have seen earlier, we + * use the 1 bit to tell us whether or not a toc offset has been + * allocated. Now that they've all been allocated, we will use + * the 1 bit to tell us if we've written this particular toc + * entry out. + */ + fixit = false; + if (h == 0) + { /* it is a file local symbol */ + int *local_toc_table; + const char *name; + + sym = syms + symndx; + name = sym->_n._n_name; + + local_toc_table = obj_coff_local_toc_table(input_bfd); + our_toc_offset = local_toc_table[symndx]; + + if (IS_WRITTEN(our_toc_offset)) + { + /* if it has been written out, it is marked with the + 1 bit. Fix up our offset, but do not write it out + again. + */ + MAKE_ADDR_AGAIN(our_toc_offset); +#ifdef TOC_DEBUG + + fprintf(stderr, + "Not writing out toc_offset of %d for %s\n", + our_toc_offset, name); +#endif + } + else + { + /* write out the toc entry */ + record_toc(toc_section, our_toc_offset, priv, strdup(name)); +#ifdef TOC_DEBUG + fprintf(stderr, + "Writing out toc_offset " + "toc_section (%p,%p)+%d val %d for %s\n", + toc_section, + toc_section->contents, + our_toc_offset, + val, + name); +#endif + + bfd_put_32(output_bfd, + val, + toc_section->contents + our_toc_offset); + + MARK_AS_WRITTEN(local_toc_table[symndx]); + fixit = true; + } + } + else + { + const char *name = h->root.root.root.string; + our_toc_offset = h->toc_offset; + + if ((r_flags & IMAGE_REL_PPC_TOCDEFN) + == IMAGE_REL_PPC_TOCDEFN ) +#if 0 + /* This is wrong. If tocdefn is on, we must unconditionally + assume the following path */ + && IS_UNALLOCATED(our_toc_offset)) +#endif + { + /* This is unbelievable cheese. Some knowledgable asm + hacker has decided to use r2 as a base for loading + a value. He/She does this by setting the tocdefn bit, + and not supplying a toc definition. The behaviour is + then to use the difference between the value of the + symbol and the actual location of the toc as the toc + index. + + In fact, what is usually happening is, because the + Import Address Table is mapped immediately following + the toc, some trippy library code trying for speed on + dll linkage, takes advantage of that and considers + the IAT to be part of the toc, thus saving a load. + */ +#ifdef DEBUG_RELOC + fprintf(stderr, + "TOCDEFN is on, (%s) (%p) our_toc_offset = %x\n", + name, h, our_toc_offset); +#endif + + our_toc_offset = val - + (toc_section->output_section->vma + + toc_section->output_offset); + +#ifdef DEBUG_RELOC + fprintf(stderr, + " our_toc_offset set to %x\n", our_toc_offset); +#endif + + /* The size must still fit in a 16bit displacment */ + if (our_toc_offset >= 65535) + { + fprintf(stderr, + "TOCDEFN Relocation exceeded " + "displacment of 65535\n"); + abort(); + } + + record_toc(toc_section, our_toc_offset, pub, strdup(name)); + } + else if (IS_WRITTEN(our_toc_offset)) + { + /* if it has been written out, it is marked with the + 1 bit. Fix up our offset, but do not write it out + again. + */ + MAKE_ADDR_AGAIN(our_toc_offset); +#ifdef TOC_DEBUG + fprintf(stderr, + "Not writing out toc_offset of %d for %s\n", + our_toc_offset, name); +#endif + } + else + { + record_toc(toc_section, our_toc_offset, pub, strdup(name)); + +#ifdef TOC_DEBUG + /* write out the toc entry */ + fprintf(stderr, + "Writing out toc_offset " + "toc_section (%p,%p)+%d val %d for %s\n", + toc_section, + toc_section->contents, + our_toc_offset, + val, + name); +#endif + + /* write out the toc entry */ + bfd_put_32(output_bfd, + val, + toc_section->contents + our_toc_offset); + + MARK_AS_WRITTEN(h->toc_offset); + /* The tricky part is that this is the address that */ + /* needs a .reloc entry for it */ + fixit = true; + } + } + + if (fixit && info->base_file) + { + /* So if this is non pcrelative, and is referenced + to a section or a common symbol, then it needs a reloc */ + + /* relocation to a symbol in a section which + isn't absolute - we output the address here + to a file */ + + bfd_vma addr = toc_section->output_section->vma + + toc_section->output_offset + our_toc_offset; + + if (coff_data(output_bfd)->pe) + addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; + +#ifdef DEBUG_RELOC + fprintf(stderr, + " Toc Section .reloc candidate addr = %x\n", addr); +#endif + fwrite (&addr, 1,4, (FILE *) info->base_file); + } + + + /* FIXME: this test is conservative */ + if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN && + our_toc_offset > toc_section->_raw_size) + { + fprintf(stderr, + "reloc offset is bigger than the toc size!\n"); + abort(); + } + + /* Now we know the relocation for this toc reference */ + relocation = our_toc_offset + TOC_LOAD_ADJUSTMENT; + rstat = _bfd_relocate_contents (howto, + input_bfd, + relocation, + loc); + } + break; + case IMAGE_REL_PPC_IFGLUE: + { + /* To solve this, we need to know whether or not the symbol */ + /* appearing on the call instruction is a glue function or not. */ + /* A glue function must announce itself via a IMGLUE reloc, and */ + /* the reloc contains the required toc restore instruction */ + + bfd_vma x; + const char *my_name; + DUMP_RELOC2(howto->name, rel); + + if (h != 0) + { + my_name = h->root.root.root.string; + if (h->symbol_is_glue == 1) + { + x = bfd_get_32(input_bfd, loc); + bfd_put_32(input_bfd, h->glue_insn, loc); + } + } + } + break; + case IMAGE_REL_PPC_SECREL: + /* Unimplemented: codeview debugging information */ + /* For fast access to the header of the section + containing the item. */ + break; + case IMAGE_REL_PPC_SECTION: + /* Unimplemented: codeview debugging information */ + /* Is used to indicate that the value should be relative + to the beginning of the section that contains the + symbol */ + break; + case IMAGE_REL_PPC_ABSOLUTE: + { + const char *my_name; + if (h == 0) + my_name = (syms+symndx)->_n._n_name; + else + { + my_name = h->root.root.root.string; + } + + fprintf(stderr, + "Warning: unsupported reloc %s \n", + howto->name, + bfd_get_filename(input_bfd), + input_section->name); + + fprintf(stderr,"sym %d (%s), r_vaddr %d (%x)\n", + rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr); + } + break; + case IMAGE_REL_PPC_IMGLUE: + { + /* There is nothing to do now. This reloc was noted in the first + pass over the relocs, and the glue instruction extracted */ + const char *my_name; + if (h->symbol_is_glue == 1) + break; + my_name = h->root.root.root.string; + fprintf(stderr, + "Warning: previously missed IMGLUE reloc %s \n", + howto->name, + bfd_get_filename(input_bfd), + input_section->name); + break; + + } + break; + + case IMAGE_REL_PPC_ADDR32NB: + { + struct coff_link_hash_entry *myh = 0; + const char *name = 0; + DUMP_RELOC2(howto->name, rel); + + if (strncmp(".idata$2",input_section->name,8) == 0 && first_thunk_address == 0) + { + /* set magic values */ + int idata5offset; + struct coff_link_hash_entry *myh = 0; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata5_magic__", + false, false, true); + first_thunk_address = myh->root.u.def.value + + sec->output_section->vma + + sec->output_offset - + pe_data(output_bfd)->pe_opthdr.ImageBase; + + idata5offset = myh->root.u.def.value; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata6_magic__", + false, false, true); + + thunk_size = myh->root.u.def.value - idata5offset; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata4_magic__", + false, false, true); + import_table_size = myh->root.u.def.value; +#ifdef DEBUG_RELOC + fprintf(stderr, + "first computation triggered fta %x, ts %d(%x), its %d(%x)\n", + first_thunk_address, thunk_size, thunk_size, import_table_size, + import_table_size); +#endif + } + + if (h == 0) + { /* it is a file local symbol */ + sym = syms + symndx; + name = sym->_n._n_name; + } + else + { + char *target = 0; + + name = h->root.root.root.string; + if (strcmp(".idata$2", name) == 0) + target = "__idata2_magic__"; + else if (strcmp(".idata$4", name) == 0) + target = "__idata4_magic__"; + else if (strcmp(".idata$5", name) == 0) + target = "__idata5_magic__"; + + if (target != 0) + { + myh = 0; + + myh = coff_link_hash_lookup (coff_hash_table (info), + target, + false, false, true); + if (myh == 0) + { + fprintf(stderr, "Missing idata magic cookies, " + "this cannot work anyway...\n"); + abort(); + } + + val = myh->root.u.def.value + + sec->output_section->vma + sec->output_offset; + if (first_thunk_address == 0) + { + int idata5offset; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata5_magic__", + false, false, true); + first_thunk_address = myh->root.u.def.value + + sec->output_section->vma + + sec->output_offset - + pe_data(output_bfd)->pe_opthdr.ImageBase; + + idata5offset = myh->root.u.def.value; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata6_magic__", + false, false, true); + + thunk_size = myh->root.u.def.value - idata5offset; + myh = coff_link_hash_lookup (coff_hash_table (info), + "__idata4_magic__", + false, false, true); + import_table_size = myh->root.u.def.value; +#ifdef DEBUG_RELOC + + fprintf(stderr, + "second computation triggered fta %x, ts %d(%x), its %d(%x)\n", + first_thunk_address, thunk_size, thunk_size, import_table_size, + import_table_size); +#endif + } + } + } + + rstat = _bfd_relocate_contents (howto, + input_bfd, + val - + pe_data(output_bfd)->pe_opthdr.ImageBase, + loc); + } + break; + + case IMAGE_REL_PPC_REL24: + DUMP_RELOC2(howto->name, rel); + val -= (input_section->output_section->vma + + input_section->output_offset); + + rstat = _bfd_relocate_contents (howto, + input_bfd, + val, + loc); + break; + case IMAGE_REL_PPC_ADDR16: + case IMAGE_REL_PPC_ADDR24: + case IMAGE_REL_PPC_ADDR32: + DUMP_RELOC2(howto->name, rel); + rstat = _bfd_relocate_contents (howto, + input_bfd, + val, + loc); + break; + } + + if ( info->base_file ) + { + /* So if this is non pcrelative, and is referenced + to a section or a common symbol, then it needs a reloc */ + if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)) + { + /* relocation to a symbol in a section which + isn't absolute - we output the address here + to a file */ + bfd_vma addr = rel->r_vaddr + - input_section->vma + + input_section->output_offset + + input_section->output_section->vma; + + if (coff_data(output_bfd)->pe) + { + bfd_vma before_addr = addr; + addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; +#ifdef DEBUG_RELOC + fprintf(stderr, + " adjusted down from %x to %x", before_addr, addr); +#endif + } +#ifdef DEBUG_RELOC + fprintf(stderr, "\n"); +#endif + + fwrite (&addr, 1,4, (FILE *) info->base_file); + } + } + + switch (rstat) + { + default: + abort (); + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + { + const char *name; + char buf[SYMNMLEN + 1]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.root.string; + else if (sym == NULL) + name = "*unknown*"; + else if (sym->_n._n_n._n_zeroes == 0 + && sym->_n._n_n._n_offset != 0) + name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; + else + { + strncpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + name = buf; + } +#if 0 + else + { + name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); + if (name == NULL) + return false; + } +#endif + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, + (bfd_vma) 0, input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + { +#ifdef DEBUG_RELOC + fprintf(stderr, + "pe_ppc_relocate_section (%s) for %s in bfd %s RETURNING TRUE\n", + TARGET_LITTLE_NAME, + input_section->name, + input_bfd->filename); + +#endif + return false; + } + } + } + + } + +#ifdef DEBUG_RELOC + fprintf(stderr, + "pe_ppc_relocate_section (%s) for %s in bfd %s RETURNING TRUE\n", + TARGET_LITTLE_NAME, + input_section->name, + input_bfd->filename); + +#endif + + return true; +} + + +#ifdef COFF_IMAGE_WITH_PE + +long int global_toc_size = 4; + +bfd* bfd_of_toc_owner = 0; + +long int import_table_size; +long int first_thunk_address; +long int thunk_size; + +struct list_ele *head; +struct list_ele *tail; + +static char * +h1 = "\n\t\t\tTOC MAPPING\n\n"; +static char * +h2 = " TOC disassembly Comments Name\n"; +static char * +h3 = " Offset spelling (if present)\n"; + +void +dump_toc(vfile) + void *vfile; +{ + FILE *file = vfile; + struct list_ele *t; + + fprintf(file, h1); + fprintf(file, h2); + fprintf(file, h3); + + for(t = head; t != 0; t=t->next) + { + char *cat; + + if (t->cat == priv) + cat = "private "; + else if (t->cat == pub) + cat = "public "; + else if (t->cat == data) + cat = "data-in-toc "; + + if (t->offset > global_toc_size) + { + if (t->offset <= global_toc_size + thunk_size) + cat = "IAT reference "; + else + { + fprintf(file, + "**** global_toc_size %d(%x), thunk_size %d(%x)\n", + global_toc_size, global_toc_size, thunk_size, thunk_size); + cat = "Out of bounds!"; + } + } + + fprintf(file, + " %04lx (%d)", t->offset, t->offset - 32768); + fprintf(file, + " %s %s\n", + cat, t->name); + + } + + fprintf(file, "\n"); +} + +boolean +ppc_allocate_toc_section (info) + struct bfd_link_info *info; +{ + asection *s; + bfd_byte *foo; + static char test_char = '1'; + + if ( global_toc_size == 0 ) /* FIXME: does this get me in trouble? */ + return true; + + if (bfd_of_toc_owner == 0) + { + fprintf(stderr, + "There is no bfd that owns the toc section!\n"); + abort(); + } + + s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME); + if (s == NULL) + { + fprintf(stderr, "No Toc section!\n"); + abort(); + } + + foo = bfd_alloc(bfd_of_toc_owner, global_toc_size); + memset(foo, test_char, global_toc_size); + + s->_raw_size = s->_cooked_size = global_toc_size; + s->contents = foo; + + return true; +} + +boolean +ppc_process_before_allocation (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *sec; + struct internal_reloc *i, *rel; + +#ifdef DEBUG_RELOC + fprintf(stderr, + "ppc_process_before_allocation: BFD %s\n", + bfd_get_filename(abfd)); +#endif + + /* here we have a bfd that is to be included on the link. We have a hook + to do reloc rummaging, before section sizes are nailed down. */ + + _bfd_coff_get_external_symbols(abfd); + + /* rummage around all the relocs and map the toc */ + sec = abfd->sections; + + if (sec == 0) + { + return true; + } + + for (; sec != 0; sec = sec->next) + { + int toc_offset; + +#ifdef DEBUG_RELOC + fprintf(stderr, + " section %s reloc count %d\n", + sec->name, + sec->reloc_count); +#endif + + if (sec->reloc_count == 0) + continue; + + /* load the relocs */ + /* FIXME: there may be a storage leak here */ + i=_bfd_coff_read_internal_relocs(abfd,sec,1,0,0,0); + + if (i == 0) + abort(); + + for (rel=i;relreloc_count;++rel) + { + unsigned short r_type = EXTRACT_TYPE (rel->r_type); + unsigned short r_flags = EXTRACT_FLAGS(rel->r_type); + unsigned short junk = EXTRACT_JUNK (rel->r_type); + +#ifdef DEBUG_RELOC + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } +#endif + + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); + + switch(r_type) + { + case IMAGE_REL_PPC_TOCREL16: +#if 0 + /* FIXME: + This remains unimplemented for now, as it currently adds + un-necessary elements to the toc. All we need to do today + is not do anything if TOCDEFN is on. + */ + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + toc_offset = ppc_record_data_in_toc_entry(abfd, info, sec, + rel->r_symndx, + default_toc); + else + toc_offset = ppc_record_toc_entry(abfd, info, sec, + rel->r_symndx, default_toc); +#endif + if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN ) + toc_offset = ppc_record_toc_entry(abfd, info, sec, + rel->r_symndx, default_toc); + break; + case IMAGE_REL_PPC_IMGLUE: + ppc_mark_symbol_as_glue(abfd, rel->r_symndx, rel); + break; + default: + break; + } + } + } +} + +#endif + + +static bfd_reloc_status_type +ppc_refhi_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("REFHI"); + DUMP_RELOC("REFHI",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_undefined; +} + +static bfd_reloc_status_type +ppc_reflo_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("REFLO"); + DUMP_RELOC("REFLO",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_undefined; +} + +static bfd_reloc_status_type +ppc_pair_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("PAIR"); + DUMP_RELOC("PAIR",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_undefined; +} + + +static bfd_reloc_status_type +ppc_toc16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("TOCREL16"); + DUMP_RELOC("TOCREL16",reloc_entry); + + if (output_bfd == (bfd *) NULL) + { + return bfd_reloc_continue; + } + + return bfd_reloc_ok; +} + +/* ADDR32NB : 32 bit address relative to the virtual origin. */ +/* (On the alpha, this is always a linker generated thunk)*/ +/* (i.e. 32bit addr relative to the image base) */ +/* */ +/* */ + +static bfd_reloc_status_type +ppc_addr32nb_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("ADDR32NB"); + DUMP_RELOC("ADDR32NB",reloc_entry); + + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +ppc_secrel_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("SECREL"); + DUMP_RELOC("SECREL",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +ppc_section_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("SECTION"); + DUMP_RELOC("SECTION",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +ppc_imglue_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + UN_IMPL("IMGLUE"); + DUMP_RELOC("IMGLUE",reloc_entry); + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + return bfd_reloc_ok; +} + + + +#define MAX_RELOC_INDEX \ + (sizeof(ppc_coff_howto_table) / sizeof(ppc_coff_howto_table[0]) - 1) + + +/* FIXME: There is a possiblity that when we read in a reloc from a file, + that there are some bits encoded in the upper portion of the + type field. Not yet implemented. +*/ +static void ppc_coff_rtype2howto PARAMS ((arelent *relent, + struct internal_reloc *internal)); + +static void +ppc_coff_rtype2howto (relent, internal) + arelent *relent; + struct internal_reloc *internal; +{ + + /* We can encode one of three things in the type field, aside from the + type: + 1. IMAGE_REL_PPC_NEG - indicates the value field is a subtraction + value, rather than an addition value + 2. IMAGE_REL_PPC_BRTAKEN, IMAGE_REL_PPC_BRNTAKEN - indicates that + the branch is expected to be taken or not. + 3. IMAGE_REL_PPC_TOCDEFN - toc slot definition in the file + For now, we just strip this stuff to find the type, and ignore it other + than that. + */ + reloc_howto_type *howto; + unsigned short r_type = EXTRACT_TYPE (internal->r_type); + unsigned short r_flags = EXTRACT_FLAGS(internal->r_type); + unsigned short junk = EXTRACT_JUNK (internal->r_type); + + /* the masking process only slices off the bottom byte for r_type. */ + if ( r_type > MAX_RELOC_INDEX ) + { + fprintf(stderr, + "ppc_coff_rtype2howto: reloc index %d out of range [%d, %d]\n", + internal->r_type, 0, MAX_RELOC_INDEX); + abort(); + } + + /* check for absolute crap */ + if ( junk != 0 ) + { + fprintf(stderr, + "ppc_coff_rtype2howto: reloc index %d contains junk %d\n", + internal->r_type, junk); + abort(); + } + +#ifdef DEBUG_RELOC + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } +#endif + + switch(r_type) + { + case IMAGE_REL_PPC_ADDR16: + case IMAGE_REL_PPC_REL24: + case IMAGE_REL_PPC_ADDR24: + case IMAGE_REL_PPC_ADDR32: + case IMAGE_REL_PPC_IFGLUE: + case IMAGE_REL_PPC_ADDR32NB: + case IMAGE_REL_PPC_SECTION: + case IMAGE_REL_PPC_SECREL: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal); + howto = ppc_coff_howto_table + r_type; + break; + case IMAGE_REL_PPC_IMGLUE: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal); + howto = ppc_coff_howto_table + r_type; + break; + case IMAGE_REL_PPC_TOCREL16: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal); + if (r_flags & IMAGE_REL_PPC_TOCDEFN) + howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN; + else + howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16; + break; + default: + fprintf(stderr, + "Warning: Unsupported reloc %s [%d] used -- it may not work.\n", + ppc_coff_howto_table[r_type].name, + r_type); + howto = ppc_coff_howto_table + r_type; + break; + } + + relent->howto = howto; + +} + +static reloc_howto_type * +coff_ppc_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + reloc_howto_type *howto; + + /* We can encode one of three things in the type field, aside from the + type: + 1. IMAGE_REL_PPC_NEG - indicates the value field is a subtraction + value, rather than an addition value + 2. IMAGE_REL_PPC_BRTAKEN, IMAGE_REL_PPC_BRNTAKEN - indicates that + the branch is expected to be taken or not. + 3. IMAGE_REL_PPC_TOCDEFN - toc slot definition in the file + For now, we just strip this stuff to find the type, and ignore it other + than that. + */ + + unsigned short r_type = EXTRACT_TYPE (rel->r_type); + unsigned short r_flags = EXTRACT_FLAGS(rel->r_type); + unsigned short junk = EXTRACT_JUNK (rel->r_type); + + /* the masking process only slices off the bottom byte for r_type. */ + if ( r_type > MAX_RELOC_INDEX ) + { + fprintf(stderr, + "coff_ppc_rtype_to_howto: index %d out of range [%d, %d]\n", + r_type, 0, MAX_RELOC_INDEX); + abort(); + } + + /* check for absolute crap */ + if ( junk != 0 ) + { + fprintf(stderr, + "coff_ppc_rtype_to_howto: reloc index %d contains junk %d\n", + rel->r_type, junk); + abort(); + } + +#ifdef DEBUG_RELOC + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } +#endif + + switch(r_type) + { + case IMAGE_REL_PPC_ADDR32NB: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); + *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; + howto = ppc_coff_howto_table + r_type; + break; + case IMAGE_REL_PPC_TOCREL16: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); + if (r_flags & IMAGE_REL_PPC_TOCDEFN) + howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN; + else + howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16; + break; + case IMAGE_REL_PPC_ADDR16: + case IMAGE_REL_PPC_REL24: + case IMAGE_REL_PPC_ADDR24: + case IMAGE_REL_PPC_ADDR32: + case IMAGE_REL_PPC_IFGLUE: + case IMAGE_REL_PPC_SECTION: + case IMAGE_REL_PPC_SECREL: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); + howto = ppc_coff_howto_table + r_type; + break; + case IMAGE_REL_PPC_IMGLUE: + DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); + howto = ppc_coff_howto_table + r_type; + break; + default: + fprintf(stderr, + "Warning: Unsupported reloc %s [%d] used -- it may not work.\n", + ppc_coff_howto_table[r_type].name, + r_type); + howto = ppc_coff_howto_table + r_type; + break; + } + + return howto; +} + + +/* a cheesy little macro to make the code a little more readable */ +#define HOW2MAP(bfd_rtype,ppc_rtype) \ + case bfd_rtype: return &ppc_coff_howto_table[ppc_rtype] + +static reloc_howto_type *ppc_coff_reloc_type_lookup +PARAMS ((bfd *, bfd_reloc_code_real_type)); + +static reloc_howto_type * +ppc_coff_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + +#ifdef DEBUG_RELOC + fprintf(stderr, "ppc_coff_reloc_type_lookup for %s\n", + bfd_get_reloc_code_name(code)); +#endif + + switch (code) + { + HOW2MAP(BFD_RELOC_32_GOTOFF, IMAGE_REL_PPC_IMGLUE); + HOW2MAP(BFD_RELOC_16_GOT_PCREL, IMAGE_REL_PPC_IFGLUE); + HOW2MAP(BFD_RELOC_16, IMAGE_REL_PPC_ADDR16); + HOW2MAP(BFD_RELOC_PPC_B26, IMAGE_REL_PPC_REL24); + HOW2MAP(BFD_RELOC_PPC_BA26, IMAGE_REL_PPC_ADDR24); + HOW2MAP(BFD_RELOC_PPC_TOC16, IMAGE_REL_PPC_TOCREL16); + HOW2MAP(BFD_RELOC_16_GOTOFF, IMAGE_REL_PPC_TOCREL16_DEFN); + HOW2MAP(BFD_RELOC_32, IMAGE_REL_PPC_ADDR32); + HOW2MAP(BFD_RELOC_RVA, IMAGE_REL_PPC_ADDR32NB); + default: + return NULL; + } + + return NULL; +} + +#undef HOW2MAP + + +/* Tailor coffcode.h -- macro heaven. */ + +#define RTYPE2HOWTO(cache_ptr, dst) ppc_coff_rtype2howto (cache_ptr, dst) + +#ifndef COFF_IMAGE_WITH_PE +static void +ppc_coff_swap_sym_in_hook (); +#endif + +/* We use the special COFF backend linker, with our own special touch. */ + +#define coff_bfd_reloc_type_lookup ppc_coff_reloc_type_lookup +#define coff_rtype_to_howto coff_ppc_rtype_to_howto +#define coff_relocate_section coff_ppc_relocate_section +#define coff_bfd_final_link ppc_bfd_coff_final_link + +#ifndef COFF_IMAGE_WITH_PE +#define coff_swap_sym_in_hook ppc_coff_swap_sym_in_hook +#endif + +#define SELECT_RELOC(internal, howto) {internal.r_type=howto->type;} + +#define COFF_PAGE_SIZE 0x1000 + +#define POWERPC_LE_PE + +#include "coffcode.h" + + + +#ifndef COFF_IMAGE_WITH_PE +/* FIXME: + What we're trying to do here is allocate a toc section (early), and attach + it to the last bfd to be processed. This avoids the problem of having a toc + written out before all files have been processed. This code allocates + a toc section for every file, and records the last one seen. There are + at least two problems with this approach: + 1. We allocate whole bunches of toc sections that are ignored, but at + at least we will not allocate a toc if no .toc is present. + 2. It's not clear to me that being the last bfd read necessarily means + that you are the last bfd closed. + 3. Doing it on a "swap in" hook depends on when the "swap in" is called, + and how often, etc. It's not clear to me that there isn't a hole here. +*/ + +static void +ppc_coff_swap_sym_in_hook (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + SYMENT *ext = (SYMENT *)ext1; + struct internal_syment *in = (struct internal_syment *)in1; + + if (bfd_of_toc_owner != 0) /* we already have a toc, so go home */ + return; + + if (strcmp(in->_n._n_name, ".toc") == 0) + { + flagword flags; + register asection *s; + char *foo; + + s = bfd_get_section_by_name ( abfd , TOC_SECTION_NAME); + if (s != NULL) + { + return; + } + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ; + +#ifdef TOC_DEBUG + fprintf(stderr, + "ppc_coff_swap_sym_in_hook: about to create the %s section\n", + TOC_SECTION_NAME); +#endif + + s = bfd_make_section (abfd, TOC_SECTION_NAME); + + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, 2)) + { + fprintf(stderr, + "toc section allocation failed!\n"); + abort(); + } + + /* save the bfd for later allocation */ + bfd_of_toc_owner = abfd; + } + + return; +} +#endif + +boolean +ppc_bfd_coff_final_link (); + +#ifndef COFF_IMAGE_WITH_PE + +static boolean +ppc_do_last(abfd) + bfd *abfd; +{ + if (abfd == bfd_of_toc_owner) + return true; + else + return false; +} + +static bfd * +ppc_get_last() +{ + return bfd_of_toc_owner; +} + +/* this piece of machinery exists only to guarantee that the bfd that holds + the toc section is written last. + + This does depend on bfd_make_section attaching a new section to the + end of the section list for the bfd. + + This is otherwise intended to be functionally the same as + cofflink.c:_bfd_coff_final_link(). It is specifically different only + where the POWERPC_LE_PE macro modifies the code. It is left in as a + precise form of comment. krk@cygnus.com +*/ +#define POWERPC_LE_PE + + +/* Do the final link step. */ + +boolean +ppc_bfd_coff_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_size_type symesz; + struct coff_final_link_info finfo; + boolean debug_merge_allocated; + asection *o; + struct bfd_link_order *p; + size_t max_sym_count; + size_t max_lineno_count; + size_t max_reloc_count; + size_t max_output_reloc_count; + size_t max_contents_size; + file_ptr rel_filepos; + unsigned int relsz; + file_ptr line_filepos; + unsigned int linesz; + bfd *sub; + bfd_byte *external_relocs = NULL; + char strbuf[STRING_SIZE_SIZE]; + + symesz = bfd_coff_symesz (abfd); + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.strtab = NULL; + finfo.section_info = NULL; + finfo.last_file_index = -1; + finfo.internal_syms = NULL; + finfo.sec_ptrs = NULL; + finfo.sym_indices = NULL; + finfo.outsyms = NULL; + finfo.linenos = NULL; + finfo.contents = NULL; + finfo.external_relocs = NULL; + finfo.internal_relocs = NULL; + debug_merge_allocated = false; + + coff_data (abfd)->link_info = info; + + finfo.strtab = _bfd_stringtab_init (); + if (finfo.strtab == NULL) + goto error_return; + + if (! coff_debug_merge_hash_table_init (&finfo.debug_merge)) + goto error_return; + debug_merge_allocated = true; + + /* Compute the file positions for all the sections. */ + if (! abfd->output_has_begun) + bfd_coff_compute_section_file_positions (abfd); + + /* Count the line numbers and relocation entries required for the + output file. Set the file positions for the relocs. */ + rel_filepos = obj_relocbase (abfd); + relsz = bfd_coff_relsz (abfd); + max_contents_size = 0; + max_lineno_count = 0; + max_reloc_count = 0; + + for (o = abfd->sections; o != NULL; o = o->next) + { + o->reloc_count = 0; + o->lineno_count = 0; + for (p = o->link_order_head; p != NULL; p = p->next) + { + + if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + + if (info->strip == strip_none + || info->strip == strip_some) + o->lineno_count += sec->lineno_count; + + if (info->relocateable) + o->reloc_count += sec->reloc_count; + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->lineno_count > max_lineno_count) + max_lineno_count = sec->lineno_count; + if (sec->reloc_count > max_reloc_count) + max_reloc_count = sec->reloc_count; + } + else if (info->relocateable + && (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order)) + ++o->reloc_count; + } + if (o->reloc_count == 0) + o->rel_filepos = 0; + else + { + o->flags |= SEC_RELOC; + o->rel_filepos = rel_filepos; + rel_filepos += o->reloc_count * relsz; + } + } + + /* If doing a relocateable link, allocate space for the pointers we + need to keep. */ + if (info->relocateable) + { + unsigned int i; + + /* We use section_count + 1, rather than section_count, because + the target_index fields are 1 based. */ + finfo.section_info = + ((struct coff_link_section_info *) + bfd_malloc ((abfd->section_count + 1) + * sizeof (struct coff_link_section_info))); + if (finfo.section_info == NULL) + goto error_return; + for (i = 0; i <= abfd->section_count; i++) + { + finfo.section_info[i].relocs = NULL; + finfo.section_info[i].rel_hashes = NULL; + } + } + + /* We now know the size of the relocs, so we can determine the file + positions of the line numbers. */ + line_filepos = rel_filepos; + linesz = bfd_coff_linesz (abfd); + max_output_reloc_count = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + if (o->lineno_count == 0) + o->line_filepos = 0; + else + { + o->line_filepos = line_filepos; + line_filepos += o->lineno_count * linesz; + } + + if (o->reloc_count != 0) + { + /* We don't know the indices of global symbols until we have + written out all the local symbols. For each section in + the output file, we keep an array of pointers to hash + table entries. Each entry in the array corresponds to a + reloc. When we find a reloc against a global symbol, we + set the corresponding entry in this array so that we can + fix up the symbol index after we have written out all the + local symbols. + + Because of this problem, we also keep the relocs in + memory until the end of the link. This wastes memory, + but only when doing a relocateable link, which is not the + common case. */ + BFD_ASSERT (info->relocateable); + finfo.section_info[o->target_index].relocs = + ((struct internal_reloc *) + bfd_malloc (o->reloc_count * sizeof (struct internal_reloc))); + finfo.section_info[o->target_index].rel_hashes = + ((struct coff_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct coff_link_hash_entry *))); + if (finfo.section_info[o->target_index].relocs == NULL + || finfo.section_info[o->target_index].rel_hashes == NULL) + goto error_return; + + if (o->reloc_count > max_output_reloc_count) + max_output_reloc_count = o->reloc_count; + } + + /* Reset the reloc and lineno counts, so that we can use them to + count the number of entries we have output so far. */ + o->reloc_count = 0; + o->lineno_count = 0; + } + + obj_sym_filepos (abfd) = line_filepos; + + /* Figure out the largest number of symbols in an input BFD. Take + the opportunity to clear the output_has_begun fields of all the + input BFD's. */ + max_sym_count = 0; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + size_t sz; + + sub->output_has_begun = false; + sz = obj_raw_syment_count (sub); + if (sz > max_sym_count) + max_sym_count = sz; + } + + /* Allocate some buffers used while linking. */ + finfo.internal_syms = ((struct internal_syment *) + bfd_malloc (max_sym_count + * sizeof (struct internal_syment))); + finfo.sec_ptrs = (asection **) bfd_malloc (max_sym_count + * sizeof (asection *)); + finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long)); + finfo.outsyms = ((bfd_byte *) + bfd_malloc ((size_t) ((max_sym_count + 1) * symesz))); + finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count + * bfd_coff_linesz (abfd)); + finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz); + if (! info->relocateable) + finfo.internal_relocs = ((struct internal_reloc *) + bfd_malloc (max_reloc_count + * sizeof (struct internal_reloc))); + if ((finfo.internal_syms == NULL && max_sym_count > 0) + || (finfo.sec_ptrs == NULL && max_sym_count > 0) + || (finfo.sym_indices == NULL && max_sym_count > 0) + || finfo.outsyms == NULL + || (finfo.linenos == NULL && max_lineno_count > 0) + || (finfo.contents == NULL && max_contents_size > 0) + || (finfo.external_relocs == NULL && max_reloc_count > 0) + || (! info->relocateable + && finfo.internal_relocs == NULL + && max_reloc_count > 0)) + goto error_return; + + /* We now know the position of everything in the file, except that + we don't know the size of the symbol table and therefore we don't + know where the string table starts. We just build the string + table in memory as we go along. We process all the relocations + for a single input file at once. */ + obj_raw_syment_count (abfd) = 0; + + if (coff_backend_info (abfd)->_bfd_coff_start_final_link) + { + if (! bfd_coff_start_final_link (abfd, info)) + goto error_return; + } + + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_coff_flavour)) + { + sub = p->u.indirect.section->owner; +#ifdef POWERPC_LE_PE + if (! sub->output_has_begun && !ppc_do_last(sub)) +#else + if (! sub->output_has_begun) +#endif + { + if (! _bfd_coff_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + +#ifdef POWERPC_LE_PE + { + extern bfd* ppc_get_last(); + bfd* last_one = ppc_get_last(); + if (last_one) + { + if (! _bfd_coff_link_input_bfd (&finfo, last_one)) + goto error_return; + } + last_one->output_has_begun = true; + } +#endif + + /* Free up the buffers used by _bfd_coff_link_input_bfd. */ + + coff_debug_merge_hash_table_free (&finfo.debug_merge); + debug_merge_allocated = false; + + if (finfo.internal_syms != NULL) + { + free (finfo.internal_syms); + finfo.internal_syms = NULL; + } + if (finfo.sec_ptrs != NULL) + { + free (finfo.sec_ptrs); + finfo.sec_ptrs = NULL; + } + if (finfo.sym_indices != NULL) + { + free (finfo.sym_indices); + finfo.sym_indices = NULL; + } + if (finfo.linenos != NULL) + { + free (finfo.linenos); + finfo.linenos = NULL; + } + if (finfo.contents != NULL) + { + free (finfo.contents); + finfo.contents = NULL; + } + if (finfo.external_relocs != NULL) + { + free (finfo.external_relocs); + finfo.external_relocs = NULL; + } + if (finfo.internal_relocs != NULL) + { + free (finfo.internal_relocs); + finfo.internal_relocs = NULL; + } + + /* The value of the last C_FILE symbol is supposed to be the symbol + index of the first external symbol. Write it out again if + necessary. */ + if (finfo.last_file_index != -1 + && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd)) + { + finfo.last_file.n_value = obj_raw_syment_count (abfd); + bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file, + (PTR) finfo.outsyms); + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + finfo.last_file_index * symesz), + SEEK_SET) != 0 + || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz) + return false; + } + + /* Write out the global symbols. */ + finfo.failed = false; + coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym, + (PTR) &finfo); + if (finfo.failed) + goto error_return; + + /* The outsyms buffer is used by _bfd_coff_write_global_sym. */ + if (finfo.outsyms != NULL) + { + free (finfo.outsyms); + finfo.outsyms = NULL; + } + + if (info->relocateable) + { + /* Now that we have written out all the global symbols, we know + the symbol indices to use for relocs against them, and we can + finally write out the relocs. */ + external_relocs = ((bfd_byte *) + bfd_malloc (max_output_reloc_count * relsz)); + if (external_relocs == NULL) + goto error_return; + + for (o = abfd->sections; o != NULL; o = o->next) + { + struct internal_reloc *irel; + struct internal_reloc *irelend; + struct coff_link_hash_entry **rel_hash; + bfd_byte *erel; + + if (o->reloc_count == 0) + continue; + + irel = finfo.section_info[o->target_index].relocs; + irelend = irel + o->reloc_count; + rel_hash = finfo.section_info[o->target_index].rel_hashes; + erel = external_relocs; + for (; irel < irelend; irel++, rel_hash++, erel += relsz) + { + if (*rel_hash != NULL) + { + BFD_ASSERT ((*rel_hash)->indx >= 0); + irel->r_symndx = (*rel_hash)->indx; + } + bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel); + } + + if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0 + || bfd_write ((PTR) external_relocs, relsz, o->reloc_count, + abfd) != relsz * o->reloc_count) + goto error_return; + } + + free (external_relocs); + external_relocs = NULL; + } + + /* Free up the section information. */ + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + finfo.section_info = NULL; + } + + /* Write out the string table. */ + if (obj_raw_syment_count (abfd) != 0) + { + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + obj_raw_syment_count (abfd) * symesz), + SEEK_SET) != 0) + return false; + +#if STRING_SIZE_SIZE == 4 + bfd_h_put_32 (abfd, + _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE, + (bfd_byte *) strbuf); +#else + #error Change bfd_h_put_32 +#endif + + if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE) + return false; + + if (! _bfd_stringtab_emit (abfd, finfo.strtab)) + return false; + } + + _bfd_stringtab_free (finfo.strtab); + + /* Setting bfd_get_symcount to 0 will cause write_object_contents to + not try to write out the symbols. */ + bfd_get_symcount (abfd) = 0; + + return true; + + error_return: + if (debug_merge_allocated) + coff_debug_merge_hash_table_free (&finfo.debug_merge); + if (finfo.strtab != NULL) + _bfd_stringtab_free (finfo.strtab); + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + } + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.sec_ptrs != NULL) + free (finfo.sec_ptrs); + if (finfo.sym_indices != NULL) + free (finfo.sym_indices); + if (finfo.outsyms != NULL) + free (finfo.outsyms); + if (finfo.linenos != NULL) + free (finfo.linenos); + 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 (external_relocs != NULL) + free (external_relocs); + return false; +} +#endif + + +/* The transfer vectors that lead the outside world to all of the above. */ + +#ifdef TARGET_LITTLE_SYM +const bfd_target +TARGET_LITTLE_SYM = +{ + TARGET_LITTLE_NAME, /* name or coff-arm-little */ + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* FIXME: object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading char */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen??? FIXMEmgo */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p }, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; +#endif + +#ifdef TARGET_BIG_SYM +const bfd_target +TARGET_BIG_SYM = +{ + TARGET_BIG_NAME, + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* FIXME: object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading char */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen??? FIXMEmgo */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p }, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; + +#endif diff --git a/contrib/gdb/bfd/coff-rs6000.c b/contrib/gdb/bfd/coff-rs6000.c new file mode 100644 index 000000000000..c065bd4f0054 --- /dev/null +++ b/contrib/gdb/bfd/coff-rs6000.c @@ -0,0 +1,1403 @@ +/* BFD back-end for IBM RS/6000 "XCOFF" files. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365, + and John Gilmore. + Archive support from Damon A. Permezel. + Contributed by IBM Corporation and Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Internalcoff.h and coffcode.h modify themselves based on this flag. */ +#define RS6000COFF_C 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/internal.h" +#include "coff/rs6000.h" +#include "libcoff.h" + +/* The main body of code is in coffcode.h. */ + +static boolean xcoff_mkobject PARAMS ((bfd *)); +static boolean xcoff_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +static void xcoff_rtype2howto + PARAMS ((arelent *, struct internal_reloc *)); +static reloc_howto_type *xcoff_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static boolean xcoff_slurp_armap PARAMS ((bfd *)); +static const bfd_target *xcoff_archive_p PARAMS ((bfd *)); +static PTR xcoff_read_ar_hdr PARAMS ((bfd *)); +static bfd *xcoff_openr_next_archived_file PARAMS ((bfd *, bfd *)); +static int xcoff_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); +static const char *normalize_filename PARAMS ((bfd *)); +static boolean xcoff_write_armap + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); +static boolean xcoff_write_archive_contents PARAMS ((bfd *)); + +/* We use our own tdata type. Its first field is the COFF tdata type, + so the COFF routines are compatible. */ + +static boolean +xcoff_mkobject (abfd) + bfd *abfd; +{ + coff_data_type *coff; + + abfd->tdata.xcoff_obj_data = + ((struct xcoff_tdata *) + bfd_zalloc (abfd, sizeof (struct xcoff_tdata))); + if (abfd->tdata.xcoff_obj_data == NULL) + return false; + coff = coff_data (abfd); + coff->symbols = (coff_symbol_type *) NULL; + coff->conversion_table = (unsigned int *) NULL; + coff->raw_syments = (struct coff_ptr_struct *) NULL; + coff->relocbase = 0; + + xcoff_data (abfd)->modtype = ('1' << 8) | 'L'; + + /* We set cputype to -1 to indicate that it has not been + initialized. */ + xcoff_data (abfd)->cputype = -1; + + xcoff_data (abfd)->csects = NULL; + xcoff_data (abfd)->debug_indices = NULL; + + return true; +} + +/* Copy XCOFF data from one BFD to another. */ + +static boolean +xcoff_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + struct xcoff_tdata *ix, *ox; + asection *sec; + + if (ibfd->xvec != obfd->xvec) + return true; + ix = xcoff_data (ibfd); + ox = xcoff_data (obfd); + ox->full_aouthdr = ix->full_aouthdr; + ox->toc = ix->toc; + if (ix->sntoc == 0) + ox->sntoc = 0; + else + { + sec = coff_section_from_bfd_index (ibfd, ix->sntoc); + if (sec == NULL) + ox->sntoc = 0; + else + ox->sntoc = sec->output_section->target_index; + } + if (ix->snentry == 0) + ox->snentry = 0; + else + { + sec = coff_section_from_bfd_index (ibfd, ix->snentry); + if (sec == NULL) + ox->snentry = 0; + else + ox->snentry = sec->output_section->target_index; + } + ox->text_align_power = ix->text_align_power; + ox->data_align_power = ix->data_align_power; + ox->modtype = ix->modtype; + ox->cputype = ix->cputype; + ox->maxdata = ix->maxdata; + ox->maxstack = ix->maxstack; + return true; +} + +/* The XCOFF reloc table. Actually, XCOFF relocations specify the + bitsize and whether they are signed or not, along with a + conventional type. This table is for the types, which are used for + different algorithms for putting in the reloc. Many of these + relocs need special_function entries, which I have not written. */ + +static reloc_howto_type xcoff_howto_table[] = +{ + /* Standard 32 bit relocation. */ + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_POS", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit relocation, but store negative value. */ + HOWTO (1, /* type */ + 0, /* rightshift */ + -2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_NEG", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative relocation. */ + HOWTO (2, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit TOC relative relocation. */ + HOWTO (3, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TOC", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* I don't really know what this is. */ + HOWTO (4, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RTB", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* External TOC relative symbol. */ + HOWTO (5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_GL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Local TOC relative symbol. */ + HOWTO (6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TCL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 7 }, + + /* Non modifiable absolute branch. */ + HOWTO (8, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_BA", /* name */ + true, /* partial_inplace */ + 0x3fffffc, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + { 9 }, + + /* Non modifiable relative branch. */ + HOWTO (0xa, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_BR", /* name */ + true, /* partial_inplace */ + 0x3fffffc, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + { 0xb }, + + /* Indirect load. */ + HOWTO (0xc, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Load address. */ + HOWTO (0xd, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RLA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 0xe }, + + /* Non-relocating reference. */ + HOWTO (0xf, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_REF", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + { 0x10 }, + { 0x11 }, + + /* TOC relative indirect load. */ + HOWTO (0x12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TRL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* TOC relative load address. */ + HOWTO (0x13, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TRLA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable relative branch. */ + HOWTO (0x14, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RRTBI", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable absolute branch. */ + HOWTO (0x15, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RRTBA", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable call absolute indirect. */ + HOWTO (0x16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_CAI", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable call relative. */ + HOWTO (0x17, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_CREL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x18, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x19, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBAC", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch relative. */ + HOWTO (0x1a, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBR", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x1b, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBRC", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false) /* pcrel_offset */ +}; + +static void +xcoff_rtype2howto (relent, internal) + arelent *relent; + struct internal_reloc *internal; +{ + relent->howto = xcoff_howto_table + internal->r_type; + + /* The r_size field of an XCOFF reloc encodes the bitsize of the + relocation, as well as indicating whether it is signed or not. + Doublecheck that the relocation information gathered from the + type matches this information. */ + if (relent->howto->bitsize != ((unsigned int) internal->r_size & 0x1f) + 1) + abort (); +#if 0 + if ((internal->r_size & 0x80) != 0 + ? (relent->howto->complain_on_overflow != complain_overflow_signed) + : (relent->howto->complain_on_overflow != complain_overflow_bitfield)) + abort (); +#endif +} + +static reloc_howto_type * +xcoff_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_PPC_B26: + return &xcoff_howto_table[0xa]; + case BFD_RELOC_PPC_BA26: + return &xcoff_howto_table[8]; + case BFD_RELOC_PPC_TOC16: + return &xcoff_howto_table[3]; + case BFD_RELOC_32: + case BFD_RELOC_CTOR: + return &xcoff_howto_table[0]; + default: + return NULL; + } +} + +#define SELECT_RELOC(internal, howto) \ + { \ + internal.r_type = howto->type; \ + internal.r_size = \ + ((howto->complain_on_overflow == complain_overflow_signed \ + ? 0x80 \ + : 0) \ + | (howto->bitsize - 1)); \ + } + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +#define COFF_LONG_FILENAMES + +#define RTYPE2HOWTO(cache_ptr, dst) xcoff_rtype2howto (cache_ptr, dst) + +#define coff_mkobject xcoff_mkobject +#define coff_bfd_copy_private_bfd_data xcoff_copy_private_bfd_data +#define coff_bfd_reloc_type_lookup xcoff_reloc_type_lookup +#define coff_relocate_section _bfd_ppc_xcoff_relocate_section + +#include "coffcode.h" + +/* XCOFF archive support. The original version of this code was by + Damon A. Permezel. It was enhanced to permit cross support, and + writing archive files, by Ian Lance Taylor, Cygnus Support. + + XCOFF uses its own archive format. Everything is hooked together + with file offset links, so it is possible to rapidly update an + archive in place. Of course, we don't do that. An XCOFF archive + has a real file header, not just an ARMAG string. The structure of + the file header and of each archive header appear below. + + An XCOFF archive also has a member table, which is a list of + elements in the archive (you can get that by looking through the + linked list, but you have to read a lot more of the file). The + member table has a normal archive header with an empty name. It is + normally (and perhaps must be) the second to last entry in the + archive. The member table data is almost printable ASCII. It + starts with a 12 character decimal string which is the number of + entries in the table. For each entry it has a 12 character decimal + string which is the offset in the archive of that member. These + entries are followed by a series of null terminated strings which + are the member names for each entry. + + Finally, an XCOFF archive has a global symbol table, which is what + we call the armap. The global symbol table has a normal archive + header with an empty name. It is normally (and perhaps must be) + the last entry in the archive. The contents start with a four byte + binary number which is the number of entries. This is followed by + a that many four byte binary numbers; each is the file offset of an + entry in the archive. These numbers are followed by a series of + null terminated strings, which are symbol names. */ + +/* XCOFF archives use this as a magic string. */ + +#define XCOFFARMAG "\012" +#define SXCOFFARMAG 8 + +/* This terminates an XCOFF archive member name. */ + +#define XCOFFARFMAG "`\012" +#define SXCOFFARFMAG 2 + +/* XCOFF archives start with this (printable) structure. */ + +struct xcoff_ar_file_hdr +{ + /* Magic string. */ + char magic[SXCOFFARMAG]; + + /* Offset of the member table (decimal ASCII string). */ + char memoff[12]; + + /* Offset of the global symbol table (decimal ASCII string). */ + char symoff[12]; + + /* Offset of the first member in the archive (decimal ASCII string). */ + char firstmemoff[12]; + + /* Offset of the last member in the archive (decimal ASCII string). */ + char lastmemoff[12]; + + /* Offset of the first member on the free list (decimal ASCII + string). */ + char freeoff[12]; +}; + +#define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG) + +/* Each XCOFF archive member starts with this (printable) structure. */ + +struct xcoff_ar_hdr +{ + /* File size not including the header (decimal ASCII string). */ + char size[12]; + + /* File offset of next archive member (decimal ASCII string). */ + char nextoff[12]; + + /* File offset of previous archive member (decimal ASCII string). */ + char prevoff[12]; + + /* File mtime (decimal ASCII string). */ + char date[12]; + + /* File UID (decimal ASCII string). */ + char uid[12]; + + /* File GID (decimal ASCII string). */ + char gid[12]; + + /* File mode (octal ASCII string). */ + char mode[12]; + + /* Length of file name (decimal ASCII string). */ + char namlen[4]; + + /* This structure is followed by the file name. The length of the + name is given in the namlen field. If the length of the name is + odd, the name is followed by a null byte. The name and optional + null byte are followed by XCOFFARFMAG, which is not included in + namlen. The contents of the archive member follow; the number of + bytes is given in the size field. */ +}; + +#define SIZEOF_AR_HDR (7 * 12 + 4) + +/* We store a copy of the xcoff_ar_file_hdr in the tdata field of the + artdata structure. */ +#define xcoff_ardata(abfd) \ + ((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata) + +/* We store a copy of the xcoff_ar_hdr in the arelt_data field of an + archive element. */ +#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) +#define arch_xhdr(bfd) \ + ((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header) + +/* XCOFF archives do not have anything which corresponds to an + extended name table. */ + +#define xcoff_slurp_extended_name_table bfd_false +#define xcoff_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_false) +#define xcoff_truncate_arname bfd_dont_truncate_arname + +/* We can use the standard get_elt_at_index routine. */ + +#define xcoff_get_elt_at_index _bfd_generic_get_elt_at_index + +/* XCOFF archives do not have a timestamp. */ + +#define xcoff_update_armap_timestamp bfd_true + +/* Read in the armap of an XCOFF archive. */ + +static boolean +xcoff_slurp_armap (abfd) + bfd *abfd; +{ + file_ptr off; + struct xcoff_ar_hdr hdr; + size_t namlen; + bfd_size_type sz; + bfd_byte *contents, *cend; + unsigned int c, i; + carsym *arsym; + bfd_byte *p; + + if (xcoff_ardata (abfd) == NULL) + { + bfd_has_map (abfd) = false; + return true; + } + + off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10); + if (off == 0) + { + bfd_has_map (abfd) = false; + return true; + } + + if (bfd_seek (abfd, off, SEEK_SET) != 0) + return false; + + /* The symbol table starts with a normal archive header. */ + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) + return false; + + /* Skip the name (normally empty). */ + namlen = strtol (hdr.namlen, (char **) NULL, 10); + if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return false; + + /* Read in the entire symbol table. */ + sz = strtol (hdr.size, (char **) NULL, 10); + contents = (bfd_byte *) bfd_alloc (abfd, sz); + if (contents == NULL) + return false; + if (bfd_read ((PTR) contents, 1, sz, abfd) != sz) + return false; + + /* The symbol table starts with a four byte count. */ + c = bfd_h_get_32 (abfd, contents); + + if (c * 4 >= sz) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_ardata (abfd)->symdefs = ((carsym *) + bfd_alloc (abfd, c * sizeof (carsym))); + if (bfd_ardata (abfd)->symdefs == NULL) + return false; + + /* After the count comes a list of four byte file offsets. */ + for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4; + i < c; + ++i, ++arsym, p += 4) + arsym->file_offset = bfd_h_get_32 (abfd, p); + + /* After the file offsets come null terminated symbol names. */ + cend = contents + sz; + for (i = 0, arsym = bfd_ardata (abfd)->symdefs; + i < c; + ++i, ++arsym, p += strlen ((char *) p) + 1) + { + if (p >= cend) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + arsym->name = (char *) p; + } + + bfd_ardata (abfd)->symdef_count = c; + bfd_has_map (abfd) = true; + + return true; +} + +/* See if this is an XCOFF archive. */ + +static const bfd_target * +xcoff_archive_p (abfd) + bfd *abfd; +{ + struct xcoff_ar_file_hdr hdr; + + if (bfd_read ((PTR) &hdr, SIZEOF_AR_FILE_HDR, 1, abfd) + != SIZEOF_AR_FILE_HDR) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (strncmp (hdr.magic, XCOFFARMAG, SXCOFFARMAG) != 0) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of + assignment. */ + abfd->tdata.aout_ar_data = + (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); + + if (bfd_ardata (abfd) == (struct artdata *) NULL) + return NULL; + + bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff, + (char **) NULL, 10); + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + + bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR); + if (bfd_ardata (abfd)->tdata == NULL) + return NULL; + + memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR); + + if (! xcoff_slurp_armap (abfd)) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = (struct artdata *) NULL; + return NULL; + } + + return abfd->xvec; +} + +/* Read the archive header in an XCOFF archive. */ + +static PTR +xcoff_read_ar_hdr (abfd) + bfd *abfd; +{ + struct xcoff_ar_hdr hdr; + size_t namlen; + struct xcoff_ar_hdr *hdrp; + struct areltdata *ret; + + if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR) + return NULL; + + namlen = strtol (hdr.namlen, (char **) NULL, 10); + hdrp = bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1); + if (hdrp == NULL) + return NULL; + memcpy (hdrp, &hdr, SIZEOF_AR_HDR); + if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen) + return NULL; + ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0'; + + ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata)); + if (ret == NULL) + return NULL; + ret->arch_header = (char *) hdrp; + ret->parsed_size = strtol (hdr.size, (char **) NULL, 10); + ret->filename = (char *) hdrp + SIZEOF_AR_HDR; + + /* Skip over the XCOFFARFMAG at the end of the file name. */ + if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0) + return NULL; + + return (PTR) ret; +} + +/* Open the next element in an XCOFF archive. */ + +static bfd * +xcoff_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (xcoff_ardata (archive) == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + if (last_file == NULL) + filestart = bfd_ardata (archive)->first_file_filepos; + else + filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, 10); + + if (filestart == 0 + || filestart == strtol (xcoff_ardata (archive)->memoff, + (char **) NULL, 10) + || filestart == strtol (xcoff_ardata (archive)->symoff, + (char **) NULL, 10)) + { + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + + return _bfd_get_elt_at_filepos (archive, filestart); +} + +/* Stat an element in an XCOFF archive. */ + +static int +xcoff_generic_stat_arch_elt (abfd, s) + bfd *abfd; + struct stat *s; +{ + struct xcoff_ar_hdr *hdrp; + + if (abfd->arelt_data == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + hdrp = arch_xhdr (abfd); + + s->st_mtime = strtol (hdrp->date, (char **) NULL, 10); + s->st_uid = strtol (hdrp->uid, (char **) NULL, 10); + s->st_gid = strtol (hdrp->gid, (char **) NULL, 10); + s->st_mode = strtol (hdrp->mode, (char **) NULL, 8); + s->st_size = arch_eltdata (abfd)->parsed_size; + + return 0; +} + +/* Normalize a file name for inclusion in an archive. */ + +static const char * +normalize_filename (abfd) + bfd *abfd; +{ + const char *file; + const char *filename; + + file = bfd_get_filename (abfd); + filename = strrchr (file, '/'); + if (filename != NULL) + filename++; + else + filename = file; + return filename; +} + +/* Write out an XCOFF armap. */ + +/*ARGSUSED*/ +static boolean +xcoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + struct xcoff_ar_hdr hdr; + char *p; + unsigned char buf[4]; + bfd *sub; + file_ptr fileoff; + unsigned int i; + + memset (&hdr, 0, sizeof hdr); + sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx)); + sprintf (hdr.nextoff, "%d", 0); + memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12); + sprintf (hdr.date, "%d", 0); + sprintf (hdr.uid, "%d", 0); + sprintf (hdr.gid, "%d", 0); + sprintf (hdr.mode, "%d", 0); + sprintf (hdr.namlen, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR + || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG) + return false; + + bfd_h_put_32 (abfd, orl_count, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + + sub = abfd->archive_head; + fileoff = SIZEOF_AR_FILE_HDR; + i = 0; + while (sub != NULL && i < orl_count) + { + size_t namlen; + + while (((bfd *) (map[i]).pos) == sub) + { + bfd_h_put_32 (abfd, fileoff, buf); + if (bfd_write (buf, 1, 4, abfd) != 4) + return false; + ++i; + } + namlen = strlen (normalize_filename (sub)); + namlen = (namlen + 1) &~ 1; + fileoff += (SIZEOF_AR_HDR + + namlen + + SXCOFFARFMAG + + arelt_size (sub)); + fileoff = (fileoff + 1) &~ 1; + sub = sub->next; + } + + for (i = 0; i < orl_count; i++) + { + const char *name; + size_t namlen; + + name = *map[i].name; + namlen = strlen (name); + if (bfd_write (name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + + if ((stridx & 1) != 0) + { + char b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* Write out an XCOFF archive. We always write an entire archive, + rather than fussing with the freelist and so forth. */ + +static boolean +xcoff_write_archive_contents (abfd) + bfd *abfd; +{ + struct xcoff_ar_file_hdr fhdr; + size_t count; + size_t total_namlen; + file_ptr *offsets; + boolean makemap; + boolean hasobjects; + file_ptr prevoff, nextoff; + bfd *sub; + unsigned int i; + struct xcoff_ar_hdr ahdr; + bfd_size_type size; + char *p; + char decbuf[13]; + + memset (&fhdr, 0, sizeof fhdr); + strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG); + sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR); + sprintf (fhdr.freeoff, "%d", 0); + + count = 0; + total_namlen = 0; + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + ++count; + total_namlen += strlen (normalize_filename (sub)) + 1; + } + offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr)); + if (offsets == NULL) + return false; + + if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR, SEEK_SET) != 0) + return false; + + makemap = bfd_has_map (abfd); + hasobjects = false; + prevoff = 0; + nextoff = SIZEOF_AR_FILE_HDR; + for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++) + { + const char *name; + size_t namlen; + struct xcoff_ar_hdr *ahdrp; + bfd_size_type remaining; + + if (makemap && ! hasobjects) + { + if (bfd_check_format (sub, bfd_object)) + hasobjects = true; + } + + name = normalize_filename (sub); + namlen = strlen (name); + + if (sub->arelt_data != NULL) + ahdrp = arch_xhdr (sub); + else + ahdrp = NULL; + + if (ahdrp == NULL) + { + struct stat s; + + memset (&ahdr, 0, sizeof ahdr); + ahdrp = &ahdr; + if (stat (bfd_get_filename (sub), &s) != 0) + { + bfd_set_error (bfd_error_system_call); + return false; + } + + sprintf (ahdrp->size, "%ld", (long) s.st_size); + sprintf (ahdrp->date, "%ld", (long) s.st_mtime); + sprintf (ahdrp->uid, "%ld", (long) s.st_uid); + sprintf (ahdrp->gid, "%ld", (long) s.st_gid); + sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode); + + if (sub->arelt_data == NULL) + { + sub->arelt_data = ((struct areltdata *) + bfd_alloc (sub, sizeof (struct areltdata))); + if (sub->arelt_data == NULL) + return false; + } + + arch_eltdata (sub)->parsed_size = s.st_size; + } + + sprintf (ahdrp->prevoff, "%ld", (long) prevoff); + sprintf (ahdrp->namlen, "%ld", (long) namlen); + + /* If the length of the name is odd, we write out the null byte + after the name as well. */ + namlen = (namlen + 1) &~ 1; + + remaining = arelt_size (sub); + size = (SIZEOF_AR_HDR + + namlen + + SXCOFFARFMAG + + remaining); + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + + offsets[i] = nextoff; + + prevoff = nextoff; + nextoff += size + (size & 1); + + sprintf (ahdrp->nextoff, "%ld", (long) nextoff); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR + || bfd_write ((PTR) name, 1, namlen, abfd) != namlen + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) + return false; + + if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0) + return false; + while (remaining != 0) + { + bfd_size_type amt; + bfd_byte buffer[DEFAULT_BUFFERSIZE]; + + amt = sizeof buffer; + if (amt > remaining) + amt = remaining; + if (bfd_read (buffer, 1, amt, sub) != amt + || bfd_write (buffer, 1, amt, abfd) != amt) + return false; + remaining -= amt; + } + + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write (&b, 1, 1, abfd) != 1) + return false; + } + } + + sprintf (fhdr.lastmemoff, "%ld", (long) prevoff); + + /* Write out the member table. */ + + BFD_ASSERT (nextoff == bfd_tell (abfd)); + sprintf (fhdr.memoff, "%ld", (long) nextoff); + + memset (&ahdr, 0, sizeof ahdr); + sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen)); + sprintf (ahdr.prevoff, "%ld", (long) prevoff); + sprintf (ahdr.date, "%d", 0); + sprintf (ahdr.uid, "%d", 0); + sprintf (ahdr.gid, "%d", 0); + sprintf (ahdr.mode, "%d", 0); + sprintf (ahdr.namlen, "%d", 0); + + size = (SIZEOF_AR_HDR + + 12 + + count * 12 + + total_namlen + + SXCOFFARFMAG); + + prevoff = nextoff; + nextoff += size + (size & 1); + + if (makemap && hasobjects) + sprintf (ahdr.nextoff, "%ld", (long) nextoff); + else + sprintf (ahdr.nextoff, "%d", 0); + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR + || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) + != SXCOFFARFMAG)) + return false; + + sprintf (decbuf, "%-12ld", (long) count); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + for (i = 0; i < count; i++) + { + sprintf (decbuf, "%-12ld", (long) offsets[i]); + if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12) + return false; + } + for (sub = abfd->archive_head; sub != NULL; sub = sub->next) + { + const char *name; + size_t namlen; + + name = normalize_filename (sub); + namlen = strlen (name); + if (bfd_write ((PTR) name, 1, namlen + 1, abfd) != namlen + 1) + return false; + } + if ((size & 1) != 0) + { + bfd_byte b; + + b = '\0'; + if (bfd_write ((PTR) &b, 1, 1, abfd) != 1) + return false; + } + + /* Write out the armap, if appropriate. */ + + if (! makemap || ! hasobjects) + sprintf (fhdr.symoff, "%d", 0); + else + { + BFD_ASSERT (nextoff == bfd_tell (abfd)); + sprintf (fhdr.symoff, "%ld", (long) nextoff); + bfd_ardata (abfd)->tdata = (PTR) &fhdr; + if (! _bfd_compute_and_write_armap (abfd, 0)) + return false; + } + + /* Write out the archive file header. */ + + /* We need spaces, not null bytes, in the header. */ + for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR; p++) + if (*p == '\0') + *p = ' '; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR, 1, abfd) != + SIZEOF_AR_FILE_HDR)) + return false; + + return true; +} + +/* We can't use the usual coff_sizeof_headers routine, because AIX + always uses an a.out header. */ + +/*ARGSUSED*/ +static int +_bfd_xcoff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + int size; + + size = FILHSZ; + if (xcoff_data (abfd)->full_aouthdr) + size += AOUTSZ; + else + size += SMALL_AOUTSZ; + size += abfd->section_count * SCNHSZ; + return size; +} + +#define CORE_FILE_P _bfd_dummy_target + +#define coff_core_file_failing_command _bfd_nocore_core_file_failing_command +#define coff_core_file_failing_signal _bfd_nocore_core_file_failing_signal +#define coff_core_file_matches_executable_p \ + _bfd_nocore_core_file_matches_executable_p + +#ifdef AIX_CORE +#undef CORE_FILE_P +#define CORE_FILE_P rs6000coff_core_p +extern const bfd_target * rs6000coff_core_p (); +extern boolean rs6000coff_get_section_contents (); +extern boolean rs6000coff_core_file_matches_executable_p (); + +#undef coff_core_file_matches_executable_p +#define coff_core_file_matches_executable_p \ + rs6000coff_core_file_matches_executable_p + +extern char *rs6000coff_core_file_failing_command PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_command +#define coff_core_file_failing_command rs6000coff_core_file_failing_command + +extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_signal +#define coff_core_file_failing_signal rs6000coff_core_file_failing_signal + +#undef coff_get_section_contents +#define coff_get_section_contents rs6000coff_get_section_contents +#endif /* AIX_CORE */ + +#ifdef LYNX_CORE + +#undef CORE_FILE_P +#define CORE_FILE_P lynx_core_file_p +extern const bfd_target *lynx_core_file_p PARAMS ((bfd *abfd)); + +extern boolean lynx_core_file_matches_executable_p PARAMS ((bfd *core_bfd, + bfd *exec_bfd)); +#undef coff_core_file_matches_executable_p +#define coff_core_file_matches_executable_p lynx_core_file_matches_executable_p + +extern char *lynx_core_file_failing_command PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_command +#define coff_core_file_failing_command lynx_core_file_failing_command + +extern int lynx_core_file_failing_signal PARAMS ((bfd *abfd)); +#undef coff_core_file_failing_signal +#define coff_core_file_failing_signal lynx_core_file_failing_signal + +#endif /* LYNX_CORE */ + +#define _bfd_xcoff_bfd_get_relocated_section_contents \ + coff_bfd_get_relocated_section_contents +#define _bfd_xcoff_bfd_relax_section coff_bfd_relax_section +#define _bfd_xcoff_bfd_link_split_section coff_bfd_link_split_section + +/* The transfer vector that leads the outside world to all of the above. */ + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + rs6000coff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "aixcoff-rs6000", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | DYNAMIC | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading char */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen??? FIXMEmgo */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + xcoff_archive_p, CORE_FILE_P}, + {bfd_false, coff_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + xcoff_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (coff), + BFD_JUMP_TABLE_ARCHIVE (xcoff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (_bfd_xcoff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-sh.c b/contrib/gdb/bfd/coff-sh.c new file mode 100644 index 000000000000..17bb4b17d817 --- /dev/null +++ b/contrib/gdb/bfd/coff-sh.c @@ -0,0 +1,1525 @@ +/* BFD back-end for Hitachi Super-H COFF binaries. + Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Written by Steve Chamberlain, . + Relaxing code written by Ian Lance Taylor, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "coff/sh.h" +#include "coff/internal.h" +#include "libcoff.h" + +/* Internal functions. */ +static bfd_reloc_status_type sh_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static long get_symbol_value PARAMS ((asymbol *)); +static boolean sh_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); +static boolean sh_relax_delete_bytes + PARAMS ((bfd *, asection *, bfd_vma, int)); +static boolean sh_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); +static bfd_byte *sh_coff_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean, asymbol **)); + +/* Default section alignment to 2**2. */ +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) + +/* Generate long file names. */ +#define COFF_LONG_FILENAMES + +/* The supported relocations. There are a lot of relocations defined + in coff/internal.h which we do not expect to ever see. */ +static reloc_howto_type sh_coff_howtos[] = +{ + { 0 }, + { 1 }, + { 2 }, + { 3 }, /* R_SH_PCREL8 */ + { 4 }, /* R_SH_PCREL16 */ + { 5 }, /* R_SH_HIGH8 */ + { 6 }, /* R_SH_IMM24 */ + { 7 }, /* R_SH_LOW16 */ + { 8 }, + { 9 }, /* R_SH_PCDISP8BY4 */ + + HOWTO (R_SH_PCDISP8BY2, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_pcdisp8by2", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + { 11 }, /* R_SH_PCDISP8 */ + + HOWTO (R_SH_PCDISP, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 12, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_pcdisp12by2", /* name */ + true, /* partial_inplace */ + 0xfff, /* src_mask */ + 0xfff, /* dst_mask */ + true), /* pcrel_offset */ + + { 13 }, + + HOWTO (R_SH_IMM32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_imm32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 15 }, + { 16 }, /* R_SH_IMM8 */ + { 17 }, /* R_SH_IMM8BY2 */ + { 18 }, /* R_SH_IMM8BY4 */ + { 19 }, /* R_SH_IMM4 */ + { 20 }, /* R_SH_IMM4BY2 */ + { 21 }, /* R_SH_IMM4BY4 */ + + HOWTO (R_SH_PCRELIMM8BY2, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_pcrelimm8by2", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_SH_PCRELIMM8BY4, /* type */ + 2, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_unsigned, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_pcrelimm8by4", /* name */ + true, /* partial_inplace */ + 0xff, /* src_mask */ + 0xff, /* dst_mask */ + true), /* pcrel_offset */ + + HOWTO (R_SH_IMM16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_imm16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_SH_SWITCH16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_switch16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_SH_SWITCH32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_switch32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_SH_USES, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_uses", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_SH_COUNT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_count", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + HOWTO (R_SH_ALIGN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + sh_reloc, /* special_function */ + "r_align", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false) /* pcrel_offset */ +}; + +#define SH_COFF_HOWTO_COUNT (sizeof sh_coff_howtos / sizeof sh_coff_howtos[0]) + +/* Check for a bad magic number. */ +#define BADMAG(x) SHBADMAG(x) + +/* Customize coffcode.h (this is not currently used). */ +#define SH 1 + +/* FIXME: This should not be set here. */ +#define __A_MAGIC_SET__ + +/* Swap the r_offset field in and out. */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 + +/* Swap out extra information in the reloc structure. */ +#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ + do \ + { \ + dst->r_stuff[0] = 'S'; \ + dst->r_stuff[1] = 'C'; \ + } \ + while (0) + +/* Get the value of a symbol, when performing a relocation. */ + +static long +get_symbol_value (symbol) + asymbol *symbol; +{ + bfd_vma relocation; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset); + + return relocation; +} + +/* This macro is used in coffcode.h to get the howto corresponding to + an internal reloc. */ + +#define RTYPE2HOWTO(relent, internal) \ + ((relent)->howto = \ + ((internal)->r_type < SH_COFF_HOWTO_COUNT \ + ? &sh_coff_howtos[(internal)->r_type] \ + : (reloc_howto_type *) NULL)) + +/* This is the same as the macro in coffcode.h, except that it copies + r_offset into reloc_entry->addend for some relocs. */ +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = 0; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if ((reloc).r_type == R_SH_SWITCH16 \ + || (reloc).r_type == R_SH_SWITCH32 \ + || (reloc).r_type == R_SH_USES \ + || (reloc).r_type == R_SH_COUNT \ + || (reloc).r_type == R_SH_ALIGN) \ + cache_ptr->addend = (reloc).r_offset; \ + } + +/* This is the howto function for the SH relocations. */ + +static bfd_reloc_status_type +sh_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + unsigned long insn; + bfd_vma sym_value; + unsigned short r_type; + bfd_vma addr = reloc_entry->address; + bfd_byte *hit_data = addr + (bfd_byte *) data; + + r_type = reloc_entry->howto->type; + + if (output_bfd != NULL) + { + /* Partial linking--do nothing. */ + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Almost all relocs have to do with relaxing. If any work must be + done for them, it has been done in sh_relax_section. */ + if (r_type != R_SH_IMM32 + && (r_type != R_SH_PCDISP + || (symbol_in->flags & BSF_LOCAL) != 0)) + return bfd_reloc_ok; + + if (symbol_in != NULL + && bfd_is_und_section (symbol_in->section)) + return bfd_reloc_undefined; + + sym_value = get_symbol_value (symbol_in); + + switch (r_type) + { + case R_SH_IMM32: + insn = bfd_get_32 (abfd, hit_data); + insn += sym_value + reloc_entry->addend; + bfd_put_32 (abfd, insn, hit_data); + break; + case R_SH_PCDISP: + insn = bfd_get_16 (abfd, hit_data); + sym_value += reloc_entry->addend; + sym_value -= (input_section->output_section->vma + + input_section->output_offset + + addr + + 4); + sym_value += (insn & 0xfff) << 1; + if (insn & 0x800) + sym_value -= 0x1000; + insn = (insn & 0xf000) | (sym_value & 0xfff); + bfd_put_16 (abfd, insn, hit_data); + if (sym_value < (bfd_vma) -0x1000 || sym_value >= 0x1000) + return bfd_reloc_overflow; + break; + default: + abort (); + break; + } + + return bfd_reloc_ok; +} + +/* We can do relaxing. */ +#define coff_bfd_relax_section sh_relax_section + +/* We use the special COFF backend linker. */ +#define coff_relocate_section sh_relocate_section + +/* When relaxing, we need to use special code to get the relocated + section contents. */ +#define coff_bfd_get_relocated_section_contents \ + sh_coff_get_relocated_section_contents + +#include "coffcode.h" + +/* This function handles relaxing on the SH. + + Function calls on the SH look like this: + + movl L1,r0 + ... + jsr @r0 + ... + L1: + .long function + + The compiler and assembler will cooperate to create R_SH_USES + relocs on the jsr instructions. The r_offset field of the + R_SH_USES reloc is the PC relative offset to the instruction which + loads the register (the r_offset field is computed as though it + were a jump instruction, so the offset value is actually from four + bytes past the instruction). The linker can use this reloc to + determine just which function is being called, and thus decide + whether it is possible to replace the jsr with a bsr. + + If multiple function calls are all based on a single register load + (i.e., the same function is called multiple times), the compiler + guarantees that each function call will have an R_SH_USES reloc. + Therefore, if the linker is able to convert each R_SH_USES reloc + which refers to that address, it can safely eliminate the register + load. + + When the assembler creates an R_SH_USES reloc, it examines it to + determine which address is being loaded (L1 in the above example). + It then counts the number of references to that address, and + creates an R_SH_COUNT reloc at that address. The r_offset field of + the R_SH_COUNT reloc will be the number of references. If the + linker is able to eliminate a register load, it can use the + R_SH_COUNT reloc to see whether it can also eliminate the function + address. */ + +static boolean +sh_relax_section (abfd, sec, link_info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + boolean *again; +{ + struct internal_reloc *internal_relocs; + struct internal_reloc *free_relocs = NULL; + struct internal_reloc *irel, *irelend; + bfd_byte *contents = NULL; + bfd_byte *free_contents = NULL; + + *again = false; + + if (link_info->relocateable + || (sec->flags & SEC_RELOC) == 0 + || sec->reloc_count == 0) + return true; + + /* If this is the first time we have been called for this section, + initialize the cooked size. */ + if (sec->_cooked_size == 0) + sec->_cooked_size = sec->_raw_size; + + internal_relocs = (_bfd_coff_read_internal_relocs + (abfd, sec, link_info->keep_memory, + (bfd_byte *) NULL, false, + (struct internal_reloc *) NULL)); + if (internal_relocs == NULL) + goto error_return; + if (! link_info->keep_memory) + free_relocs = internal_relocs; + + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma laddr, paddr, symval; + unsigned short insn; + struct internal_reloc *irelfn, *irelscan, *irelcount; + struct internal_syment sym; + bfd_signed_vma foff; + + if (irel->r_type != R_SH_USES) + continue; + + /* Get the section contents. */ + if (contents == NULL) + { + if (coff_section_data (abfd, sec) != NULL + && coff_section_data (abfd, sec)->contents != NULL) + contents = coff_section_data (abfd, sec)->contents; + else + { + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents == NULL) + goto error_return; + free_contents = contents; + + if (! bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + goto error_return; + } + } + + /* The r_offset field of the R_SH_USES reloc will point us to + the register load. The 4 is because the r_offset field is + computed as though it were a jump offset, which are based + from 4 bytes after the jump instruction. */ + laddr = irel->r_vaddr - sec->vma + 4 + irel->r_offset; + if (laddr >= sec->_raw_size) + { + (*_bfd_error_handler) ("%s: 0x%lx: warning: bad R_SH_USES offset", + bfd_get_filename (abfd), + (unsigned long) irel->r_vaddr); + continue; + } + insn = bfd_get_16 (abfd, contents + laddr); + + /* If the instruction is not mov.l NN,rN, we don't know what to + do. */ + if ((insn & 0xf000) != 0xd000) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: R_SH_USES points to unrecognized insn 0x%x", + bfd_get_filename (abfd), (unsigned long) irel->r_vaddr, insn)); + continue; + } + + /* Get the address from which the register is being loaded. The + displacement in the mov.l instruction is quadrupled. It is a + displacement from four bytes after the movl instruction, but, + before adding in the PC address, two least significant bits + of the PC are cleared. We assume that the section is aligned + on a four byte boundary. */ + paddr = insn & 0xff; + paddr *= 4; + paddr += (laddr + 4) &~ 3; + if (paddr >= sec->_raw_size) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: bad R_SH_USES load offset", + bfd_get_filename (abfd), (unsigned long) irel->r_vaddr)); + continue; + } + + /* Get the reloc for the address from which the register is + being loaded. This reloc will tell us which function is + actually being called. */ + paddr += sec->vma; + for (irelfn = internal_relocs; irelfn < irelend; irelfn++) + if (irelfn->r_vaddr == paddr + && irelfn->r_type == R_SH_IMM32) + break; + if (irelfn >= irelend) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: could not find expected reloc", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + /* Get the value of the symbol referred to by the reloc. */ + if (! _bfd_coff_get_external_symbols (abfd)) + goto error_return; + bfd_coff_swap_sym_in (abfd, + ((bfd_byte *) obj_coff_external_syms (abfd) + + (irelfn->r_symndx + * bfd_coff_symesz (abfd))), + &sym); + if (sym.n_scnum != 0 && sym.n_scnum != sec->target_index) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: symbol in unexpected section", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + if (sym.n_sclass != C_EXT) + { + symval = (sym.n_value + - sec->vma + + sec->output_section->vma + + sec->output_offset); + } + else + { + struct coff_link_hash_entry *h; + + h = obj_coff_sym_hashes (abfd)[irelfn->r_symndx]; + BFD_ASSERT (h != NULL); + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + { + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + continue; + } + + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + + symval += bfd_get_32 (abfd, contents + paddr - sec->vma); + + /* See if this function call can be shortened. */ + foff = (symval + - (irel->r_vaddr + - sec->vma + + sec->output_section->vma + + sec->output_offset + + 4)); + if (foff < -0x1000 || foff >= 0x1000) + { + /* After all that work, we can't shorten this function call. */ + continue; + } + + /* Shorten the function call. */ + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + if (coff_section_data (abfd, sec) == NULL) + { + sec->used_by_bfd = + ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); + if (sec->used_by_bfd == NULL) + goto error_return; + } + + coff_section_data (abfd, sec)->relocs = internal_relocs; + coff_section_data (abfd, sec)->keep_relocs = true; + free_relocs = NULL; + + coff_section_data (abfd, sec)->contents = contents; + coff_section_data (abfd, sec)->keep_contents = true; + free_contents = NULL; + + obj_coff_keep_syms (abfd) = true; + + /* Replace the jsr with a bsr. */ + + /* Change the R_SH_USES reloc into an R_SH_PCDISP reloc, and + replace the jsr with a bsr. */ + irel->r_type = R_SH_PCDISP; + irel->r_symndx = irelfn->r_symndx; + if (sym.n_sclass != C_EXT) + { + /* If this needs to be changed because of future relaxing, + it will be handled here like other internal PCDISP + relocs. */ + bfd_put_16 (abfd, + 0xb000 | ((foff >> 1) & 0xfff), + contents + irel->r_vaddr - sec->vma); + } + else + { + /* We can't fully resolve this yet, because the external + symbol value may be changed by future relaxing. We let + the final link phase handle it. */ + bfd_put_16 (abfd, 0xb000, contents + irel->r_vaddr - sec->vma); + } + + /* See if there is another R_SH_USES reloc referring to the same + register load. */ + for (irelscan = internal_relocs; irelscan < irelend; irelscan++) + if (irelscan->r_type == R_SH_USES + && laddr == irelscan->r_vaddr - sec->vma + 4 + irelscan->r_offset) + break; + if (irelscan < irelend) + { + /* Some other function call depends upon this register load, + and we have not yet converted that function call. + Indeed, we may never be able to convert it. There is + nothing else we can do at this point. */ + continue; + } + + /* Look for a R_SH_COUNT reloc on the location where the + function address is stored. Do this before deleting any + bytes, to avoid confusion about the address. */ + for (irelcount = internal_relocs; irelcount < irelend; irelcount++) + if (irelcount->r_vaddr == paddr + && irelcount->r_type == R_SH_COUNT) + break; + + /* Delete the register load. */ + if (! sh_relax_delete_bytes (abfd, sec, laddr, 2)) + goto error_return; + + /* That will change things, so, just in case it permits some + other function call to come within range, we should relax + again. Note that this is not required, and it may be slow. */ + *again = true; + + /* Now check whether we got a COUNT reloc. */ + if (irelcount >= irelend) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: warning: could not find expected COUNT reloc", + bfd_get_filename (abfd), (unsigned long) paddr)); + continue; + } + + /* The number of uses is stored in the r_offset field. We've + just deleted one. */ + if (irelcount->r_offset == 0) + { + ((*_bfd_error_handler) ("%s: 0x%lx: warning: bad count", + bfd_get_filename (abfd), + (unsigned long) paddr)); + continue; + } + + --irelcount->r_offset; + + /* If there are no more uses, we can delete the address. Reload + the address from irelfn, in case it was changed by the + previous call to sh_relax_delete_bytes. */ + if (irelcount->r_offset == 0) + { + if (! sh_relax_delete_bytes (abfd, sec, + irelfn->r_vaddr - sec->vma, 4)) + goto error_return; + } + + /* We've done all we can with that function call. */ + } + + if (free_relocs != NULL) + { + free (free_relocs); + free_relocs = NULL; + } + + if (free_contents != NULL) + { + if (! link_info->keep_memory) + free (free_contents); + else + { + /* Cache the section contents for coff_link_input_bfd. */ + if (coff_section_data (abfd, sec) == NULL) + { + sec->used_by_bfd = + ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); + if (sec->used_by_bfd == NULL) + goto error_return; + coff_section_data (abfd, sec)->relocs = NULL; + } + coff_section_data (abfd, sec)->contents = contents; + } + } + + return true; + + error_return: + if (free_relocs != NULL) + free (free_relocs); + if (free_contents != NULL) + free (free_contents); + return false; +} + +/* Delete some bytes from a section while relaxing. */ + +static boolean +sh_relax_delete_bytes (abfd, sec, addr, count) + bfd *abfd; + asection *sec; + bfd_vma addr; + int count; +{ + bfd_byte *contents; + struct internal_reloc *irel, *irelend; + struct internal_reloc *irelalign; + bfd_vma toaddr; + bfd_byte *esym, *esymend; + bfd_size_type symesz; + struct coff_link_hash_entry **sym_hash; + asection *o; + + contents = coff_section_data (abfd, sec)->contents; + + /* The deletion must stop at the next ALIGN reloc for an aligment + power larger than the number of bytes we are deleting. */ + + irelalign = NULL; + toaddr = sec->_cooked_size; + + irel = coff_section_data (abfd, sec)->relocs; + irelend = irel + sec->reloc_count; + for (; irel < irelend; irel++) + { + if (irel->r_type == R_SH_ALIGN + && irel->r_vaddr - sec->vma > addr + && count < (1 << irel->r_offset)) + { + irelalign = irel; + toaddr = irel->r_vaddr - sec->vma; + break; + } + } + + /* Actually delete the bytes. */ + memmove (contents + addr, contents + addr + count, toaddr - addr - count); + if (irelalign == NULL) + sec->_cooked_size -= count; + else + memset (contents + toaddr - count, 0, count); + + /* Adjust all the relocs. */ + for (irel = coff_section_data (abfd, sec)->relocs; irel < irelend; irel++) + { + bfd_vma nraddr, start, stop; + int insn = 0; + struct internal_syment sym; + int off, adjust, oinsn; + bfd_signed_vma voff; + boolean overflow; + + /* Get the new reloc address. */ + nraddr = irel->r_vaddr - sec->vma; + if ((irel->r_vaddr - sec->vma > addr + && irel->r_vaddr - sec->vma < toaddr) + || (irel->r_type == R_SH_ALIGN + && irel->r_vaddr - sec->vma == toaddr)) + nraddr -= count; + + /* See if this reloc was for the bytes we have deleted, in which + case we no longer care about it. */ + if (irel->r_vaddr - sec->vma >= addr + && irel->r_vaddr - sec->vma < addr + count + && irel->r_type != R_SH_ALIGN) + irel->r_type = R_SH_UNUSED; + + /* If this is a PC relative reloc, see if the range it covers + includes the bytes we have deleted. */ + switch (irel->r_type) + { + default: + break; + + case R_SH_PCDISP8BY2: + case R_SH_PCDISP: + case R_SH_PCRELIMM8BY2: + case R_SH_PCRELIMM8BY4: + start = irel->r_vaddr - sec->vma; + insn = bfd_get_16 (abfd, contents + nraddr); + break; + } + + switch (irel->r_type) + { + default: + start = stop = addr; + break; + + case R_SH_IMM32: + /* If this reloc is against a symbol defined in this + section, and the symbol will not be adjusted below, we + must check the addend to see it will put the value in + range to be adjusted, and hence must be changed. */ + bfd_coff_swap_sym_in (abfd, + ((bfd_byte *) obj_coff_external_syms (abfd) + + (irel->r_symndx + * bfd_coff_symesz (abfd))), + &sym); + if (sym.n_sclass != C_EXT + && sym.n_scnum == sec->target_index + && ((bfd_vma) sym.n_value <= addr + || (bfd_vma) sym.n_value >= toaddr)) + { + bfd_vma val; + + val = bfd_get_32 (abfd, contents + nraddr); + val += sym.n_value; + if (val >= addr && val < toaddr) + bfd_put_32 (abfd, val - count, contents + nraddr); + } + start = stop = addr; + break; + + case R_SH_PCDISP8BY2: + off = insn & 0xff; + if (off & 0x80) + off -= 0x100; + stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); + break; + + case R_SH_PCDISP: + bfd_coff_swap_sym_in (abfd, + ((bfd_byte *) obj_coff_external_syms (abfd) + + (irel->r_symndx + * bfd_coff_symesz (abfd))), + &sym); + if (sym.n_sclass == C_EXT) + start = stop = addr; + else + { + off = insn & 0xfff; + if (off & 0x800) + off -= 0x1000; + stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); + } + break; + + case R_SH_PCRELIMM8BY2: + off = insn & 0xff; + stop = start + 4 + off * 2; + break; + + case R_SH_PCRELIMM8BY4: + off = insn & 0xff; + stop = (start &~ (bfd_vma) 3) + 4 + off * 4; + break; + + case R_SH_SWITCH16: + case R_SH_SWITCH32: + /* These relocs types represent + .word L2-L1 + The r_offset field holds the difference between the reloc + address and L1. That is the start of the reloc, and + adding in the contents gives us the top. We must adjust + both the r_offset field and the section contents. */ + + start = irel->r_vaddr - sec->vma; + stop = (bfd_vma) ((bfd_signed_vma) start - (long) irel->r_offset); + + if (start > addr + && start < toaddr + && (stop <= addr || stop >= toaddr)) + irel->r_offset += count; + else if (stop > addr + && stop < toaddr + && (start <= addr || start >= toaddr)) + irel->r_offset -= count; + + start = stop; + + if (irel->r_type == R_SH_SWITCH16) + voff = bfd_get_signed_16 (abfd, contents + nraddr); + else + voff = bfd_get_signed_32 (abfd, contents + nraddr); + stop = (bfd_vma) ((bfd_signed_vma) start + voff); + + break; + + case R_SH_USES: + start = irel->r_vaddr - sec->vma; + stop = (bfd_vma) ((bfd_signed_vma) start + + (long) irel->r_offset + + 4); + break; + } + + if (start > addr + && start < toaddr + && (stop <= addr || stop >= toaddr)) + adjust = count; + else if (stop > addr + && stop < toaddr + && (start <= addr || start >= toaddr)) + adjust = - count; + else + adjust = 0; + + if (adjust != 0) + { + oinsn = insn; + overflow = false; + switch (irel->r_type) + { + default: + abort (); + break; + + case R_SH_PCDISP8BY2: + case R_SH_PCRELIMM8BY2: + insn += adjust / 2; + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_PCDISP: + insn += adjust / 2; + if ((oinsn & 0xf000) != (insn & 0xf000)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_PCRELIMM8BY4: + BFD_ASSERT (adjust == count || count >= 4); + if (count >= 4) + insn += adjust / 4; + else + { + if ((irel->r_vaddr & 3) == 0) + ++insn; + } + if ((oinsn & 0xff00) != (insn & 0xff00)) + overflow = true; + bfd_put_16 (abfd, insn, contents + nraddr); + break; + + case R_SH_SWITCH16: + voff += adjust; + if (voff < - 0x8000 || voff >= 0x8000) + overflow = true; + bfd_put_signed_16 (abfd, voff, contents + nraddr); + break; + + case R_SH_SWITCH32: + voff += adjust; + bfd_put_signed_32 (abfd, voff, contents + nraddr); + break; + + case R_SH_USES: + irel->r_offset += adjust; + break; + } + + if (overflow) + { + ((*_bfd_error_handler) + ("%s: 0x%lx: fatal: reloc overflow while relaxing", + bfd_get_filename (abfd), (unsigned long) irel->r_vaddr)); + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + irel->r_vaddr = nraddr + sec->vma; + } + + /* Look through all the other sections. If there contain any IMM32 + relocs against internal symbols which we are not going to adjust + below, we may need to adjust the addends. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + struct internal_reloc *internal_relocs; + struct internal_reloc *irelscan, *irelscanend; + bfd_byte *ocontents; + + if (o == sec + || (o->flags & SEC_RELOC) == 0 + || o->reloc_count == 0) + continue; + + /* We always cache the relocs. Perhaps, if info->keep_memory is + false, we should free them, if we are permitted to, when we + leave sh_coff_relax_section. */ + internal_relocs = (_bfd_coff_read_internal_relocs + (abfd, o, true, (bfd_byte *) NULL, false, + (struct internal_reloc *) NULL)); + if (internal_relocs == NULL) + return false; + + ocontents = NULL; + irelscanend = internal_relocs + o->reloc_count; + for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) + { + struct internal_syment sym; + + if (irelscan->r_type != R_SH_IMM32) + continue; + + bfd_coff_swap_sym_in (abfd, + ((bfd_byte *) obj_coff_external_syms (abfd) + + (irelscan->r_symndx + * bfd_coff_symesz (abfd))), + &sym); + if (sym.n_sclass != C_EXT + && sym.n_scnum == sec->target_index + && ((bfd_vma) sym.n_value <= addr + || (bfd_vma) sym.n_value >= toaddr)) + { + bfd_vma val; + + if (ocontents == NULL) + { + if (coff_section_data (abfd, o)->contents != NULL) + ocontents = coff_section_data (abfd, o)->contents; + else + { + /* We always cache the section contents. + Perhaps, if info->keep_memory is false, we + should free them, if we are permitted to, + when we leave sh_coff_relax_section. */ + ocontents = (bfd_byte *) bfd_malloc (o->_raw_size); + if (ocontents == NULL) + return false; + if (! bfd_get_section_contents (abfd, o, ocontents, + (file_ptr) 0, + o->_raw_size)) + return false; + coff_section_data (abfd, o)->contents = ocontents; + } + } + + val = bfd_get_32 (abfd, ocontents + irelscan->r_vaddr - o->vma); + val += sym.n_value; + if (val >= addr && val < toaddr) + bfd_put_32 (abfd, val - count, + ocontents + irelscan->r_vaddr - o->vma); + + coff_section_data (abfd, o)->keep_contents = true; + } + } + } + + /* Adjusting the internal symbols will not work if something has + already retrieved the generic symbols. It would be possible to + make this work by adjusting the generic symbols at the same time. + However, this case should not arise in normal usage. */ + if (obj_symbols (abfd) != NULL + || obj_raw_syments (abfd) != NULL) + { + ((*_bfd_error_handler) + ("%s: fatal: generic symbols retrieved before relaxing", + bfd_get_filename (abfd))); + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* Adjust all the symbols. */ + sym_hash = obj_coff_sym_hashes (abfd); + symesz = bfd_coff_symesz (abfd); + esym = (bfd_byte *) obj_coff_external_syms (abfd); + esymend = esym + obj_raw_syment_count (abfd) * symesz; + while (esym < esymend) + { + struct internal_syment isym; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym); + + if (isym.n_scnum == sec->target_index + && (bfd_vma) isym.n_value > addr + && (bfd_vma) isym.n_value < toaddr) + { + isym.n_value -= count; + + bfd_coff_swap_sym_out (abfd, (PTR) &isym, (PTR) esym); + + if (*sym_hash != NULL) + { + BFD_ASSERT ((*sym_hash)->root.type == bfd_link_hash_defined + || (*sym_hash)->root.type == bfd_link_hash_defweak); + BFD_ASSERT ((*sym_hash)->root.u.def.value >= addr + && (*sym_hash)->root.u.def.value < toaddr); + (*sym_hash)->root.u.def.value -= count; + } + } + + esym += (isym.n_numaux + 1) * symesz; + sym_hash += isym.n_numaux + 1; + } + + /* See if we can move the ALIGN reloc forward. We have adjusted + r_vaddr for it already. */ + if (irelalign != NULL) + { + bfd_vma alignaddr; + + alignaddr = BFD_ALIGN (irelalign->r_vaddr - sec->vma, + 1 << irelalign->r_offset); + if (alignaddr != toaddr) + { + /* Tail recursion. */ + return sh_relax_delete_bytes (abfd, sec, + irelalign->r_vaddr - sec->vma, + 1 << irelalign->r_offset); + } + } + + return true; +} + +/* This is a modification of _bfd_coff_generic_relocate_section, which + will handle SH relaxing. */ + +static boolean +sh_relocate_section (output_bfd, info, input_bfd, input_section, contents, + relocs, syms, sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma addend; + bfd_vma val; + reloc_howto_type *howto; + bfd_reloc_status_type rstat; + + /* Almost all relocs have to do with relaxing. If any work must + be done for them, it has been done in sh_relax_section. */ + if (rel->r_type != R_SH_IMM32 + && rel->r_type != R_SH_PCDISP) + continue; + + symndx = rel->r_symndx; + + if (symndx == -1) + { + h = NULL; + sym = NULL; + } + else + { + h = obj_coff_sym_hashes (input_bfd)[symndx]; + sym = syms + symndx; + } + + if (sym != NULL && sym->n_scnum != 0) + addend = - sym->n_value; + else + addend = 0; + + if (rel->r_type == R_SH_PCDISP) + addend -= 4; + + if (rel->r_type >= SH_COFF_HOWTO_COUNT) + howto = NULL; + else + howto = &sh_coff_howtos[rel->r_type]; + + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + val = 0; + + if (h == NULL) + { + asection *sec; + + /* There is nothing to do for an internal PCDISP reloc. */ + if (rel->r_type == R_SH_PCDISP) + continue; + + if (symndx == -1) + { + sec = bfd_abs_section_ptr; + val = 0; + } + else + { + sec = sections[symndx]; + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *sec; + + sec = h->root.u.def.section; + val = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (! info->relocateable) + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, + rel->r_vaddr - input_section->vma, + val, addend); + + switch (rstat) + { + default: + abort (); + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + { + const char *name; + char buf[SYMNMLEN + 1]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.string; + else if (sym->_n._n_n._n_zeroes == 0 + && sym->_n._n_n._n_offset != 0) + name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; + else + { + strncpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + name = buf; + } + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + } + } + } + + return true; +} + +/* This is a version of bfd_generic_get_relocated_section_contents + which uses sh_relocate_section. */ + +static bfd_byte * +sh_coff_get_relocated_section_contents (output_bfd, link_info, link_order, + data, relocateable, symbols) + bfd *output_bfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + asection *input_section = link_order->u.indirect.section; + bfd *input_bfd = input_section->owner; + asection **sections = NULL; + struct internal_reloc *internal_relocs = NULL; + struct internal_syment *internal_syms = NULL; + + /* We only need to handle the case of relaxing, or of having a + particular set of section contents, specially. */ + if (relocateable + || coff_section_data (input_bfd, input_section) == NULL + || coff_section_data (input_bfd, input_section)->contents == NULL) + return bfd_generic_get_relocated_section_contents (output_bfd, link_info, + link_order, data, + relocateable, + symbols); + + memcpy (data, coff_section_data (input_bfd, input_section)->contents, + input_section->_raw_size); + + if ((input_section->flags & SEC_RELOC) != 0 + && input_section->reloc_count > 0) + { + bfd_size_type symesz = bfd_coff_symesz (input_bfd); + bfd_byte *esym, *esymend; + struct internal_syment *isymp; + asection **secpp; + + if (! _bfd_coff_get_external_symbols (input_bfd)) + goto error_return; + + internal_relocs = (_bfd_coff_read_internal_relocs + (input_bfd, input_section, false, (bfd_byte *) NULL, + false, (struct internal_reloc *) NULL)); + if (internal_relocs == NULL) + goto error_return; + + internal_syms = ((struct internal_syment *) + bfd_malloc (obj_raw_syment_count (input_bfd) + * sizeof (struct internal_syment))); + if (internal_syms == NULL) + goto error_return; + + sections = (asection **) bfd_malloc (obj_raw_syment_count (input_bfd) + * sizeof (asection *)); + if (sections == NULL) + goto error_return; + + isymp = internal_syms; + secpp = sections; + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esymend = esym + obj_raw_syment_count (input_bfd) * symesz; + while (esym < esymend) + { + bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp); + + if (isymp->n_scnum != 0) + *secpp = coff_section_from_bfd_index (input_bfd, isymp->n_scnum); + else + { + if (isymp->n_value == 0) + *secpp = bfd_und_section_ptr; + else + *secpp = bfd_com_section_ptr; + } + + esym += (isymp->n_numaux + 1) * symesz; + secpp += isymp->n_numaux + 1; + isymp += isymp->n_numaux + 1; + } + + if (! sh_relocate_section (output_bfd, link_info, input_bfd, + input_section, data, internal_relocs, + internal_syms, sections)) + goto error_return; + + free (sections); + sections = NULL; + free (internal_syms); + internal_syms = NULL; + free (internal_relocs); + internal_relocs = NULL; + } + + return data; + + error_return: + if (internal_relocs != NULL) + free (internal_relocs); + if (internal_syms != NULL) + free (internal_syms); + if (sections != NULL) + free (sections); + return NULL; +} + +/* The target vectors. */ + +const bfd_target shcoff_vec = +{ + "coff-sh", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), + '_', /* leading symbol underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; + +const bfd_target shlcoff_vec = +{ + "coff-shl", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little endian too*/ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), + '_', /* leading symbol underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-sparc.c b/contrib/gdb/bfd/coff-sparc.c new file mode 100644 index 000000000000..b9bc595dc5ab --- /dev/null +++ b/contrib/gdb/bfd/coff-sparc.c @@ -0,0 +1,278 @@ +/* BFD back-end for Sparc COFF files. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/sparc.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +#define BADMAG(x) ((x).f_magic != SPARCMAGIC && (x).f_magic != LYNXCOFFMAGIC) + +/* The page size is a guess based on ELF. */ +#define COFF_PAGE_SIZE 0x10000 + +enum reloc_type + { + R_SPARC_NONE = 0, + R_SPARC_8, R_SPARC_16, R_SPARC_32, + R_SPARC_DISP8, R_SPARC_DISP16, R_SPARC_DISP32, + R_SPARC_WDISP30, R_SPARC_WDISP22, + R_SPARC_HI22, R_SPARC_22, + R_SPARC_13, R_SPARC_LO10, + R_SPARC_GOT10, R_SPARC_GOT13, R_SPARC_GOT22, + R_SPARC_PC10, R_SPARC_PC22, + R_SPARC_WPLT30, + R_SPARC_COPY, + R_SPARC_GLOB_DAT, R_SPARC_JMP_SLOT, + R_SPARC_RELATIVE, + R_SPARC_UA32, + R_SPARC_max + }; + +#if 0 +static CONST char *CONST reloc_type_names[] = +{ + "R_SPARC_NONE", + "R_SPARC_8", "R_SPARC_16", "R_SPARC_32", + "R_SPARC_DISP8", "R_SPARC_DISP16", "R_SPARC_DISP32", + "R_SPARC_WDISP30", "R_SPARC_WDISP22", + "R_SPARC_HI22", "R_SPARC_22", + "R_SPARC_13", "R_SPARC_LO10", + "R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", + "R_SPARC_PC10", "R_SPARC_PC22", + "R_SPARC_WPLT30", + "R_SPARC_COPY", + "R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", + "R_SPARC_RELATIVE", + "R_SPARC_UA32", +}; +#endif + +/* This is stolen pretty directly from elf.c. */ +static bfd_reloc_status_type +bfd_coff_generic_reloc PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +bfd_coff_generic_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} + +static reloc_howto_type coff_sparc_howto_table[] = +{ + HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_NONE", false,0,0x00000000,true), + HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_8", false,0,0x000000ff,true), + HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_32", false,0,0xffffffff,true), + HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP8", false,0,0x000000ff,true), + HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP32", false,0,0x00ffffff,true), + HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_WDISP30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_WDISP22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_HI22", false,0,0x003fffff,true), + HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_22", false,0,0x003fffff,true), + HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_13", false,0,0x00001fff,true), + HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_LO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT13", false,0,0x00001fff,true), + HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC10, 0,2,10,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC22, 0,2,22,false,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC22", false,0,0x003fffff,true), + HOWTO(R_SPARC_WPLT30, 0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_WPLT30", false,0,0x00000000,true), + HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_COPY", false,0,0x00000000,true), + HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_JMP_SLOT",false,0,0x00000000,true), + HOWTO(R_SPARC_RELATIVE,0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_RELATIVE",false,0,0x00000000,true), + HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_UA32", false,0,0x00000000,true), +}; + +struct coff_reloc_map { + unsigned char bfd_reloc_val; + unsigned char coff_reloc_val; +}; + +static CONST struct coff_reloc_map sparc_reloc_map[] = +{ + { BFD_RELOC_NONE, R_SPARC_NONE, }, + { BFD_RELOC_16, R_SPARC_16, }, + { BFD_RELOC_8, R_SPARC_8 }, + { BFD_RELOC_8_PCREL, R_SPARC_DISP8 }, + { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits. */ + { BFD_RELOC_32, R_SPARC_32 }, + { BFD_RELOC_32_PCREL, R_SPARC_DISP32 }, + { BFD_RELOC_HI22, R_SPARC_HI22 }, + { BFD_RELOC_LO10, R_SPARC_LO10, }, + { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 }, + { BFD_RELOC_SPARC22, R_SPARC_22 }, + { BFD_RELOC_SPARC13, R_SPARC_13 }, + { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 }, + { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 }, + { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 }, + { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 }, + { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 }, + { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 }, + { BFD_RELOC_SPARC_COPY, R_SPARC_COPY }, + { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT }, + { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, + { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, + { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, + /* { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */ +}; + +static reloc_howto_type * +coff_sparc_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct coff_reloc_map); i++) + { + if (sparc_reloc_map[i].bfd_reloc_val == code) + return &coff_sparc_howto_table[(int) sparc_reloc_map[i].coff_reloc_val]; + } + return 0; +} +#define coff_bfd_reloc_type_lookup coff_sparc_reloc_type_lookup + +static void +rtype2howto (cache_ptr, dst) + arelent *cache_ptr; + struct internal_reloc *dst; +{ + BFD_ASSERT (dst->r_type < (unsigned int) R_SPARC_max); + cache_ptr->howto = &coff_sparc_howto_table[dst->r_type]; +} + +#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) + +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 +/* This is just like the standard one, except that we don't set up an + addend for relocs against global symbols (otherwise linking objects + created by -r fails), and we add in the reloc offset at the end. */ +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = 0; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL \ + && (ptr->flags & BSF_GLOBAL) == 0) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + cache_ptr->addend += reloc.r_offset; \ + } + +/* Clear the r_spare field in relocs. */ +#define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \ + do { \ + dst->r_spare[0] = 0; \ + dst->r_spare[1] = 0; \ + } while (0) + +#define __A_MAGIC_SET__ + +/* Enable Sparc-specific hacks in coffcode.h. */ + +#define COFF_SPARC + +#include "coffcode.h" + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + sparccoff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-sparc", /* name */ +#endif + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-u68k.c b/contrib/gdb/bfd/coff-u68k.c new file mode 100644 index 000000000000..97ea73fa9c62 --- /dev/null +++ b/contrib/gdb/bfd/coff-u68k.c @@ -0,0 +1,35 @@ +/* BFD back-end for Motorola 68000 COFF binaries having underscore with name. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_SYM m68kcoffun_vec +#define TARGET_NAME "coff-m68k-un" + +#define NAMES_HAVE_UNDERSCORE + +/* define this to not have multiple copy of m68k_rtype2howto + in the executable file */ +#define ONLY_DECLARE_RELOCS + +/* This magic number indicates that the names have underscores. + Other 68k magic numbers indicate that the names do not have + underscores. */ +#define BADMAG(x) ((x).f_magic != MC68KBCSMAGIC) + +#include "coff-m68k.c" diff --git a/contrib/gdb/bfd/coff-w65.c b/contrib/gdb/bfd/coff-w65.c new file mode 100644 index 000000000000..a02243f1d1b9 --- /dev/null +++ b/contrib/gdb/bfd/coff-w65.c @@ -0,0 +1,446 @@ +/* BFD back-end for WDC 65816 COFF binaries. + Copyright 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "coff/w65.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) +static reloc_howto_type howto_table[] = +{ + HOWTO (R_W65_ABS8, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "abs8", true, 0x000000ff, 0x000000ff, false), + HOWTO (R_W65_ABS16, 1, 0, 16, false, 0, complain_overflow_bitfield, 0, "abs16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_W65_ABS24, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "abs24", true, 0x00ffffff, 0x00ffffff, false), + HOWTO (R_W65_ABS8S8, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, ">abs8", true, 0x000000ff, 0x000000ff, false), + HOWTO (R_W65_ABS8S16, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "^abs8", true, 0x000000ff, 0x000000ff, false), + HOWTO (R_W65_ABS16S8, 1, 0, 16, false, 0, complain_overflow_bitfield, 0, ">abs16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_W65_ABS16S16,1, 0, 16, false, 0, complain_overflow_bitfield, 0, "^abs16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_W65_PCR8, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "pcrel8", true, 0x000000ff, 0x000000ff, true), + HOWTO (R_W65_PCR16, 1, 0, 16, false, 0, complain_overflow_bitfield, 0, "pcrel16", true, 0x0000ffff, 0x0000ffff, true), + HOWTO (R_W65_DP, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "dp", true, 0x000000ff, 0x000000ff, false), + +}; + + +/* Turn a howto into a reloc number */ + +#define SELECT_RELOC(x,howto) \ + { x.r_type = select_reloc(howto); } + +#define BADMAG(x) (W65BADMAG(x)) +#define W65 1 /* Customize coffcode.h */ +#define __A_MAGIC_SET__ + + +/* Code to swap in the reloc */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 +#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ + dst->r_stuff[0] = 'S'; \ + dst->r_stuff[1] = 'C'; + + +static int +select_reloc (howto) + reloc_howto_type *howto; +{ + return howto->type ; +} + +/* Code to turn a r_type into a howto ptr, uses the above howto table + */ + +static void +rtype2howto (internal, dst) + arelent *internal; + struct internal_reloc *dst; +{ + internal->howto = howto_table + dst->r_type - 1; +} + +#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) + + +/* Perform any necessaru magic to the addend in a reloc entry */ + + +#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ + cache_ptr->addend = ext_reloc.r_offset; + + +#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void +reloc_processing (relent, reloc, symbols, abfd, section) + arelent * relent; + struct internal_reloc *reloc; + asymbol ** symbols; + bfd * abfd; + asection * section; +{ + relent->address = reloc->r_vaddr; + rtype2howto (relent, reloc); + + if (((int) reloc->r_symndx) > 0) + { + relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; + } + else + { + relent->sym_ptr_ptr = (asymbol **)&(bfd_abs_symbol); + } + + + + relent->addend = reloc->r_offset; + + relent->address -= section->vma; + /* relent->section = 0;*/ +} + + +static int +h8300_reloc16_estimate(abfd, input_section, reloc, shrink, link_info) + bfd *abfd; + asection *input_section; + arelent *reloc; + unsigned int shrink; + struct bfd_link_info *link_info; +{ + bfd_vma value; + bfd_vma dot; + bfd_vma gap; + + /* The address of the thing to be relocated will have moved back by + the size of the shrink - but we don't change reloc->address here, + since we need it to know where the relocation lives in the source + uncooked section */ + + /* reloc->address -= shrink; conceptual */ + + bfd_vma address = reloc->address - shrink; + + + switch (reloc->howto->type) + { + case R_MOVB2: + case R_JMP2: + shrink+=2; + break; + + /* Thing is a move one byte */ + case R_MOVB1: + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + if (value >= 0xff00) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + reloc->howto = reloc->howto + 1; + /* The place to relc moves back by one */ + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + + break; + /* This is the 24 bit branch which could become an 8 bitter, + the relocation points to the first byte of the insn, not the + actual data */ + + case R_JMPL1: + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + dot = input_section->output_section->vma + + input_section->output_offset + address; + + /* See if the address we're looking at within 127 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - dot ; + + if (-120 < (long)gap && (long)gap < 120 ) + { + + /* Change the reloc type from 24bit, possible 8 to 8bit + possible 32 */ + reloc->howto = reloc->howto + 1; + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + break; + + case R_JMP1: + + value = bfd_coff_reloc16_get_value(reloc, link_info, input_section); + + dot = input_section->output_section->vma + + input_section->output_offset + address; + + /* See if the address we're looking at within 127 bytes of where + we are, if so then we can use a small branch rather than the + jump we were going to */ + + gap = value - (dot - shrink); + + + if (-120 < (long)gap && (long)gap < 120 ) + { + + /* Change the reloc type from 16bit, possible 8 to 8bit + possible 16 */ + reloc->howto = reloc->howto + 1; + /* The place to relc moves back by one */ + + /* This will be two bytes smaller in the long run */ + shrink +=2 ; + bfd_perform_slip(abfd, 2, input_section, address); + } + break; + } + + + return shrink; +} + + +/* First phase of a relaxing link */ + +/* Reloc types + large small + R_MOVB1 R_MOVB2 mov.b with 16bit or 8 bit address + R_JMP1 R_JMP2 jmp or pcrel branch + R_JMPL1 R_JMPL_B8 24jmp or pcrel branch + R_MOVLB1 R_MOVLB2 24 or 8 bit reloc for mov.b + +*/ + +static void +h8300_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr, + dst_ptr) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + unsigned int src_address = *src_ptr; + unsigned int dst_address = *dst_ptr; + asection *input_section = link_order->u.indirect.section; + + switch (reloc->howto->type) + { + case R_W65_ABS8: + case R_W65_DP: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_put_8 (abfd, gap, data + dst_address); + dst_address += 1; + src_address += 1; + } + break; + + case R_W65_ABS8S8: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + gap >>= 8; + bfd_put_8 (abfd, gap, data + dst_address); + dst_address += 1; + src_address += 1; + } + break; + + case R_W65_ABS8S16: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + gap >>=16; + bfd_put_8 (abfd, gap, data + dst_address); + dst_address += 1; + src_address += 1; + } + break; + + case R_W65_ABS16: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + + bfd_put_16 (abfd, gap, data + dst_address); + dst_address += 2; + src_address += 2; + } + break; + case R_W65_ABS16S8: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + gap >>= 8; + bfd_put_16 (abfd, gap, data + dst_address); + dst_address += 2; + src_address += 2; + } + break; + case R_W65_ABS16S16: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + gap >>= 16; + bfd_put_16 (abfd, gap, data + dst_address); + dst_address += 2; + src_address += 2; + } + break; + + case R_W65_ABS24: + { + unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_put_16 (abfd, gap, data + dst_address); + bfd_put_8 (abfd, gap>>16, data+dst_address+2); + dst_address += 3; + src_address += 3; + } + break; + + case R_W65_PCR8: + { + int gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + + gap -= dot + 1; + if (gap < -128 || gap > 127) { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort(); + } + bfd_put_8 (abfd, gap, data + dst_address); + dst_address += 1; + src_address += 1; + } + break; + + case R_W65_PCR16: + { + bfd_vma gap = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_vma dot = link_order->offset + + dst_address + + link_order->u.indirect.section->output_section->vma; + + + /* This wraps within the page, so ignore the relativeness, look at the + high part */ + if ((gap & 0xf0000) != (dot & 0xf0000)) { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort(); + } + + gap -= dot + 2; + bfd_put_16 (abfd, gap, data + dst_address); + dst_address += 2; + src_address += 2; + } + break; + default: + printf("ignoring reloc %s\n", reloc->howto->name); + break; + + } + *src_ptr = src_address; + *dst_ptr = dst_address; + +} + +#define coff_reloc16_extra_cases h8300_reloc16_extra_cases +#define coff_reloc16_estimate h8300_reloc16_estimate + +#include "coffcode.h" + + +#undef coff_bfd_get_relocated_section_contents +#undef coff_bfd_relax_section +#define coff_bfd_get_relocated_section_contents \ + bfd_coff_reloc16_get_relocated_section_contents +#define coff_bfd_relax_section bfd_coff_reloc16_relax_section + + + +bfd_target w65_vec = +{ + "coff-w65", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading char */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-we32k.c b/contrib/gdb/bfd/coff-we32k.c new file mode 100644 index 000000000000..36f1fa17fded --- /dev/null +++ b/contrib/gdb/bfd/coff-we32k.c @@ -0,0 +1,110 @@ +/* BFD back-end for we32k COFF files. + Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by Brendan Kehoe (brendan@cs.widener.edu). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/we32k.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) + +static reloc_howto_type howto_table[] = +{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + HOWTO(R_DIR32, 0, 2, 32, false, 0,complain_overflow_bitfield, 0, "dir32", true, 0xffffffff,0xffffffff, false), + {7}, + {010}, + {011}, + {012}, + {013}, + {014}, + {015}, + {016}, + HOWTO(R_RELBYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_RELWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, 0, "16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_RELLONG, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "32", true, 0xffffffff,0xffffffff, false), + HOWTO(R_PCRBYTE, 0, 0, 8, true, 0, complain_overflow_signed, 0, "DISP8", true, 0x000000ff,0x000000ff, false), + HOWTO(R_PCRWORD, 0, 1, 16, true, 0, complain_overflow_signed, 0, "DISP16", true, 0x0000ffff,0x0000ffff, false), + HOWTO(R_PCRLONG, 0, 2, 32, true, 0, complain_overflow_signed, 0, "DISP32", true, 0xffffffff,0xffffffff, false), +}; + +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define BADMAG(x) WE32KBADMAG(x) +#define WE32K 1 + +#define RTYPE2HOWTO(cache_ptr, dst) \ + (cache_ptr)->howto = howto_table + (dst)->r_type; + +#include "coffcode.h" + +#define coff_write_armap bsd_write_armap + +const bfd_target we32kcoff_vec = +{ + "coff-we32k", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coff-z8k.c b/contrib/gdb/bfd/coff-z8k.c new file mode 100644 index 000000000000..5609d35d0f22 --- /dev/null +++ b/contrib/gdb/bfd/coff-z8k.c @@ -0,0 +1,281 @@ +/* BFD back-end for Zilog Z800n COFF binaries. + Copyright 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Written by Steve Chamberlain, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "coff/z8k.h" +#include "coff/internal.h" +#include "libcoff.h" + +#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) + +static reloc_howto_type r_imm32 = +HOWTO (R_IMM32, 0, 1, 32, false, 0, + complain_overflow_bitfield, 0, "r_imm32", true, 0xffffffff, + 0xffffffff, false); + +static reloc_howto_type r_imm4l = +HOWTO (R_IMM4L, 0, 1, 4, false, 0, + complain_overflow_bitfield, 0, "r_imm4l", true, 0xf, 0xf, false); + +static reloc_howto_type r_da = +HOWTO (R_IMM16, 0, 1, 16, false, 0, + complain_overflow_bitfield, 0, "r_da", true, 0x0000ffff, 0x0000ffff, + false); + +static reloc_howto_type r_imm8 = +HOWTO (R_IMM8, 0, 1, 8, false, 0, + complain_overflow_bitfield, 0, "r_imm8", true, 0x000000ff, 0x000000ff, + false); + +static reloc_howto_type r_jr = +HOWTO (R_JR, 0, 1, 8, true, 0, complain_overflow_signed, 0, + "r_jr", true, 0, 0, true); + +/* Turn a howto into a reloc number */ + +static int +coff_z8k_select_reloc (howto) + reloc_howto_type *howto; +{ + return howto->type; +} + +#define SELECT_RELOC(x,howto) x.r_type = coff_z8k_select_reloc(howto) + + +#define BADMAG(x) Z8KBADMAG(x) +#define Z8K 1 /* Customize coffcode.h */ +#define __A_MAGIC_SET__ + + + +/* Code to swap in the reloc */ +#define SWAP_IN_RELOC_OFFSET bfd_h_get_32 +#define SWAP_OUT_RELOC_OFFSET bfd_h_put_32 +#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ + dst->r_stuff[0] = 'S'; \ + dst->r_stuff[1] = 'C'; + +/* Code to turn a r_type into a howto ptr, uses the above howto table + */ + +static void +rtype2howto (internal, dst) + arelent * internal; + struct internal_reloc *dst; +{ + switch (dst->r_type) + { + default: + abort (); + break; + case R_IMM8: + internal->howto = &r_imm8; + break; + case R_IMM16: + internal->howto = &r_da; + break; + case R_JR: + internal->howto = &r_jr; + break; + case R_IMM32: + internal->howto = &r_imm32; + break; + case R_IMM4L: + internal->howto = &r_imm4l; + break; + } +} + +#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) + + +/* Perform any necessaru magic to the addend in a reloc entry */ + + +#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ + cache_ptr->addend = ext_reloc.r_offset; + + +#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ + reloc_processing(relent, reloc, symbols, abfd, section) + +static void +reloc_processing (relent, reloc, symbols, abfd, section) + arelent * relent; + struct internal_reloc *reloc; + asymbol ** symbols; + bfd * abfd; + asection * section; +{ + relent->address = reloc->r_vaddr; + rtype2howto (relent, reloc); + + if (reloc->r_symndx > 0) + { + relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; + } + else + { + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + + + relent->addend = reloc->r_offset; + relent->address -= section->vma; +} + +static void +extra_case (in_abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr) + bfd *in_abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + asection *input_section = link_order->u.indirect.section; + + switch (reloc->howto->type) + { + case R_IMM8: + bfd_put_8 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + *dst_ptr); + (*dst_ptr) += 1; + (*src_ptr) += 1; + break; + + case R_IMM32: + bfd_put_32 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + *dst_ptr); + (*dst_ptr) += 4; + (*src_ptr) += 4; + break; + + case R_IMM4L: + bfd_put_8 (in_abfd, + ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0) + | (0x0f + & bfd_coff_reloc16_get_value (reloc, link_info, + input_section))), + data + *dst_ptr); + (*dst_ptr) += 1; + (*src_ptr) += 1; + break; + + case R_IMM16: + bfd_put_16 (in_abfd, + bfd_coff_reloc16_get_value (reloc, link_info, input_section), + data + *dst_ptr); + (*dst_ptr) += 2; + (*src_ptr) += 2; + break; + + case R_JR: + { + bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, + input_section); + bfd_vma dot = (link_order->offset + + *dst_ptr + + input_section->output_section->vma); + int gap = dst - dot - 1;/* -1 since were in the odd byte of the + word and the pc's been incremented */ + + if (gap & 1) + abort (); + gap /= 2; + if (gap > 128 || gap < -128) + { + if (! ((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*reloc->sym_ptr_ptr), + reloc->howto->name, reloc->addend, input_section->owner, + input_section, reloc->address))) + abort (); + } + bfd_put_8 (in_abfd, gap, data + *dst_ptr); + (*dst_ptr)++; + (*src_ptr)++; + break; + } + default: + abort (); + } +} + +#define coff_reloc16_extra_cases extra_case + +#include "coffcode.h" + + +#undef coff_bfd_get_relocated_section_contents +#undef coff_bfd_relax_section +#define coff_bfd_get_relocated_section_contents \ + bfd_coff_reloc16_get_relocated_section_contents +#define coff_bfd_relax_section bfd_coff_reloc16_relax_section + +const bfd_target z8kcoff_vec = +{ + "coff-z8k", /* name */ + bfd_target_coff_flavour, + BFD_ENDIAN_BIG, /* data byte order is big */ + BFD_ENDIAN_BIG, /* header byte order is big */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + '_', /* leading symbol underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/contrib/gdb/bfd/coffcode.h b/contrib/gdb/bfd/coffcode.h new file mode 100644 index 000000000000..22babd0d0c7f --- /dev/null +++ b/contrib/gdb/bfd/coffcode.h @@ -0,0 +1,3612 @@ +/* Support for the generic parts of most COFF variants, for BFD. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +Most of this hacked by Steve Chamberlain, + sac@cygnus.com +*/ +/* + +SECTION + coff backends + + BFD supports a number of different flavours of coff format. + The major differences between formats are the sizes and + alignments of fields in structures on disk, and the occasional + extra field. + + Coff in all its varieties is implemented with a few common + files and a number of implementation specific files. For + example, The 88k bcs coff format is implemented in the file + @file{coff-m88k.c}. This file @code{#include}s + @file{coff/m88k.h} which defines the external structure of the + coff format for the 88k, and @file{coff/internal.h} which + defines the internal structure. @file{coff-m88k.c} also + defines the relocations used by the 88k format + @xref{Relocations}. + + The Intel i960 processor version of coff is implemented in + @file{coff-i960.c}. This file has the same structure as + @file{coff-m88k.c}, except that it includes @file{coff/i960.h} + rather than @file{coff-m88k.h}. + +SUBSECTION + Porting to a new version of coff + + The recommended method is to select from the existing + implementations the version of coff which is most like the one + you want to use. For example, we'll say that i386 coff is + the one you select, and that your coff flavour is called foo. + Copy @file{i386coff.c} to @file{foocoff.c}, copy + @file{../include/coff/i386.h} to @file{../include/coff/foo.h}, + and add the lines to @file{targets.c} and @file{Makefile.in} + so that your new back end is used. Alter the shapes of the + structures in @file{../include/coff/foo.h} so that they match + what you need. You will probably also have to add + @code{#ifdef}s to the code in @file{coff/internal.h} and + @file{coffcode.h} if your version of coff is too wild. + + You can verify that your new BFD backend works quite simply by + building @file{objdump} from the @file{binutils} directory, + and making sure that its version of what's going on and your + host system's idea (assuming it has the pretty standard coff + dump utility, usually called @code{att-dump} or just + @code{dump}) are the same. Then clean up your code, and send + what you've done to Cygnus. Then your stuff will be in the + next release, and you won't have to keep integrating it. + +SUBSECTION + How the coff backend works + +SUBSUBSECTION + File layout + + The Coff backend is split into generic routines that are + applicable to any Coff target and routines that are specific + to a particular target. The target-specific routines are + further split into ones which are basically the same for all + Coff targets except that they use the external symbol format + or use different values for certain constants. + + The generic routines are in @file{coffgen.c}. These routines + work for any Coff target. They use some hooks into the target + specific code; the hooks are in a @code{bfd_coff_backend_data} + structure, one of which exists for each target. + + The essentially similar target-specific routines are in + @file{coffcode.h}. This header file includes executable C code. + The various Coff targets first include the appropriate Coff + header file, make any special defines that are needed, and + then include @file{coffcode.h}. + + Some of the Coff targets then also have additional routines in + the target source file itself. + + For example, @file{coff-i960.c} includes + @file{coff/internal.h} and @file{coff/i960.h}. It then + defines a few constants, such as @code{I960}, and includes + @file{coffcode.h}. Since the i960 has complex relocation + types, @file{coff-i960.c} also includes some code to + manipulate the i960 relocs. This code is not in + @file{coffcode.h} because it would not be used by any other + target. + +SUBSUBSECTION + Bit twiddling + + Each flavour of coff supported in BFD has its own header file + describing the external layout of the structures. There is also + an internal description of the coff layout, in + @file{coff/internal.h}. A major function of the + coff backend is swapping the bytes and twiddling the bits to + translate the external form of the structures into the normal + internal form. This is all performed in the + @code{bfd_swap}_@i{thing}_@i{direction} routines. Some + elements are different sizes between different versions of + coff; it is the duty of the coff version specific include file + to override the definitions of various packing routines in + @file{coffcode.h}. E.g., the size of line number entry in coff is + sometimes 16 bits, and sometimes 32 bits. @code{#define}ing + @code{PUT_LNSZ_LNNO} and @code{GET_LNSZ_LNNO} will select the + correct one. No doubt, some day someone will find a version of + coff which has a varying field size not catered to at the + moment. To port BFD, that person will have to add more @code{#defines}. + Three of the bit twiddling routines are exported to + @code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in} + and @code{coff_swap_linno_in}. @code{GDB} reads the symbol + table on its own, but uses BFD to fix things up. More of the + bit twiddlers are exported for @code{gas}; + @code{coff_swap_aux_out}, @code{coff_swap_sym_out}, + @code{coff_swap_lineno_out}, @code{coff_swap_reloc_out}, + @code{coff_swap_filehdr_out}, @code{coff_swap_aouthdr_out}, + @code{coff_swap_scnhdr_out}. @code{Gas} currently keeps track + of all the symbol table and reloc drudgery itself, thereby + saving the internal BFD overhead, but uses BFD to swap things + on the way out, making cross ports much safer. Doing so also + allows BFD (and thus the linker) to use the same header files + as @code{gas}, which makes one avenue to disaster disappear. + +SUBSUBSECTION + Symbol reading + + The simple canonical form for symbols used by BFD is not rich + enough to keep all the information available in a coff symbol + table. The back end gets around this problem by keeping the original + symbol table around, "behind the scenes". + + When a symbol table is requested (through a call to + @code{bfd_canonicalize_symtab}), a request gets through to + @code{coff_get_normalized_symtab}. This reads the symbol table from + the coff file and swaps all the structures inside into the + internal form. It also fixes up all the pointers in the table + (represented in the file by offsets from the first symbol in + the table) into physical pointers to elements in the new + internal table. This involves some work since the meanings of + fields change depending upon context: a field that is a + pointer to another structure in the symbol table at one moment + may be the size in bytes of a structure at the next. Another + pass is made over the table. All symbols which mark file names + (<> symbols) are modified so that the internal + string points to the value in the auxent (the real filename) + rather than the normal text associated with the symbol + (@code{".file"}). + + At this time the symbol names are moved around. Coff stores + all symbols less than nine characters long physically + within the symbol table; longer strings are kept at the end of + the file in the string table. This pass moves all strings + into memory and replaces them with pointers to the strings. + + + The symbol table is massaged once again, this time to create + the canonical table used by the BFD application. Each symbol + is inspected in turn, and a decision made (using the + @code{sclass} field) about the various flags to set in the + @code{asymbol}. @xref{Symbols}. The generated canonical table + shares strings with the hidden internal symbol table. + + Any linenumbers are read from the coff file too, and attached + to the symbols which own the functions the linenumbers belong to. + +SUBSUBSECTION + Symbol writing + + Writing a symbol to a coff file which didn't come from a coff + file will lose any debugging information. The @code{asymbol} + structure remembers the BFD from which the symbol was taken, and on + output the back end makes sure that the same destination target as + source target is present. + + When the symbols have come from a coff file then all the + debugging information is preserved. + + Symbol tables are provided for writing to the back end in a + vector of pointers to pointers. This allows applications like + the linker to accumulate and output large symbol tables + without having to do too much byte copying. + + This function runs through the provided symbol table and + patches each symbol marked as a file place holder + (@code{C_FILE}) to point to the next file place holder in the + list. It also marks each @code{offset} field in the list with + the offset from the first symbol of the current symbol. + + Another function of this procedure is to turn the canonical + value form of BFD into the form used by coff. Internally, BFD + expects symbol values to be offsets from a section base; so a + symbol physically at 0x120, but in a section starting at + 0x100, would have the value 0x20. Coff expects symbols to + contain their final value, so symbols have their values + changed at this point to reflect their sum with their owning + section. This transformation uses the + <> field of the @code{asymbol}'s + @code{asection} @xref{Sections}. + + o <> + + This routine runs though the provided symbol table and uses + the offsets generated by the previous pass and the pointers + generated when the symbol table was read in to create the + structured hierachy required by coff. It changes each pointer + to a symbol into the index into the symbol table of the asymbol. + + o <> + + This routine runs through the symbol table and patches up the + symbols from their internal form into the coff way, calls the + bit twiddlers, and writes out the table to the file. + +*/ + +/* +INTERNAL_DEFINITION + coff_symbol_type + +DESCRIPTION + The hidden information for an <> is described in a + <>: + +CODE_FRAGMENT +. +.typedef struct coff_ptr_struct +.{ +. +. {* Remembers the offset from the first symbol in the file for +. this symbol. Generated by coff_renumber_symbols. *} +.unsigned int offset; +. +. {* Should the value of this symbol be renumbered. Used for +. XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. *} +.unsigned int fix_value : 1; +. +. {* Should the tag field of this symbol be renumbered. +. Created by coff_pointerize_aux. *} +.unsigned int fix_tag : 1; +. +. {* Should the endidx field of this symbol be renumbered. +. Created by coff_pointerize_aux. *} +.unsigned int fix_end : 1; +. +. {* Should the x_csect.x_scnlen field be renumbered. +. Created by coff_pointerize_aux. *} +.unsigned int fix_scnlen : 1; +. +. {* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the +. index into the line number entries. Set by +. coff_slurp_symbol_table. *} +.unsigned int fix_line : 1; +. +. {* The container for the symbol structure as read and translated +. from the file. *} +. +.union { +. union internal_auxent auxent; +. struct internal_syment syment; +. } u; +.} combined_entry_type; +. +. +.{* Each canonical asymbol really looks like this: *} +. +.typedef struct coff_symbol_struct +.{ +. {* The actual symbol which the rest of BFD works with *} +.asymbol symbol; +. +. {* A pointer to the hidden information for this symbol *} +.combined_entry_type *native; +. +. {* A pointer to the linenumber information for this symbol *} +.struct lineno_cache_entry *lineno; +. +. {* Have the line numbers been relocated yet ? *} +.boolean done_lineno; +.} coff_symbol_type; + + +*/ + +#ifdef COFF_WITH_PE +#include "peicode.h" +#else +#include "coffswap.h" +#endif + + +/* void warning(); */ + +/* + * Return a word with STYP_* (scnhdr.s_flags) flags set to represent the + * incoming SEC_* flags. The inverse of this function is styp_to_sec_flags(). + * NOTE: If you add to/change this routine, you should mirror the changes + * in styp_to_sec_flags(). + */ +static long +sec_to_styp_flags (sec_name, sec_flags) + CONST char *sec_name; + flagword sec_flags; +{ + long styp_flags = 0; + + if (!strcmp (sec_name, _TEXT)) + { + styp_flags = STYP_TEXT; + } + else if (!strcmp (sec_name, _DATA)) + { + styp_flags = STYP_DATA; + } + else if (!strcmp (sec_name, _BSS)) + { + styp_flags = STYP_BSS; +#ifdef _COMMENT + } + else if (!strcmp (sec_name, _COMMENT)) + { + styp_flags = STYP_INFO; +#endif /* _COMMENT */ +#ifdef _LIB + } + else if (!strcmp (sec_name, _LIB)) + { + styp_flags = STYP_LIB; +#endif /* _LIB */ +#ifdef _LIT + } + else if (!strcmp (sec_name, _LIT)) + { + styp_flags = STYP_LIT; +#endif /* _LIT */ + } + else if (!strcmp (sec_name, ".debug")) + { +#ifdef STYP_DEBUG + styp_flags = STYP_DEBUG; +#else + styp_flags = STYP_INFO; +#endif + } + else if (!strncmp (sec_name, ".stab", 5)) + { + styp_flags = STYP_INFO; + } +#ifdef COFF_WITH_PE + else if (!strcmp (sec_name, ".edata")) + { + styp_flags = STYP_DATA; + } +#endif +#ifdef RS6000COFF_C + else if (!strcmp (sec_name, _PAD)) + { + styp_flags = STYP_PAD; + } + else if (!strcmp (sec_name, _LOADER)) + { + styp_flags = STYP_LOADER; + } +#endif + /* Try and figure out what it should be */ + else if (sec_flags & SEC_CODE) + { + styp_flags = STYP_TEXT; + } + else if (sec_flags & SEC_DATA) + { + styp_flags = STYP_DATA; + } + else if (sec_flags & SEC_READONLY) + { +#ifdef STYP_LIT /* 29k readonly text/data section */ + styp_flags = STYP_LIT; +#else + styp_flags = STYP_TEXT; +#endif /* STYP_LIT */ + } + else if (sec_flags & SEC_LOAD) + { + styp_flags = STYP_TEXT; + } + else if (sec_flags & SEC_ALLOC) + { + styp_flags = STYP_BSS; + } + +#ifdef STYP_NOLOAD + if ((sec_flags & (SEC_NEVER_LOAD | SEC_COFF_SHARED_LIBRARY)) != 0) + styp_flags |= STYP_NOLOAD; +#endif + + return (styp_flags); +} +/* + * Return a word with SEC_* flags set to represent the incoming + * STYP_* flags (from scnhdr.s_flags). The inverse of this + * function is sec_to_styp_flags(). + * NOTE: If you add to/change this routine, you should mirror the changes + * in sec_to_styp_flags(). + */ +static flagword +styp_to_sec_flags (abfd, hdr, name) + bfd *abfd; + PTR hdr; + const char *name; +{ + struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; + long styp_flags = internal_s->s_flags; + flagword sec_flags = 0; + +#ifdef STYP_NOLOAD + if (styp_flags & STYP_NOLOAD) + { + sec_flags |= SEC_NEVER_LOAD; + } +#endif /* STYP_NOLOAD */ + + /* For 386 COFF, at least, an unloadable text or data section is + actually a shared library section. */ + if (styp_flags & STYP_TEXT) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if (styp_flags & STYP_DATA) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + } + else if (styp_flags & STYP_BSS) + { +#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY; + else +#endif + sec_flags |= SEC_ALLOC; + } + else if (styp_flags & STYP_INFO) + { + /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is + defined. coff_compute_section_file_positions uses + COFF_PAGE_SIZE to ensure that the low order bits of the + section VMA and the file offset match. If we don't know + COFF_PAGE_SIZE, we can't ensure the correct correspondence, + and demand page loading of the file will fail. */ +#ifdef COFF_PAGE_SIZE + sec_flags |= SEC_DEBUGGING; +#endif + } + else if (styp_flags & STYP_PAD) + { + sec_flags = 0; + } + else if (strcmp (name, _TEXT) == 0) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if (strcmp (name, _DATA) == 0) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + } + else if (strcmp (name, _BSS) == 0) + { +#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY; + else +#endif + sec_flags |= SEC_ALLOC; + } + else if (strcmp (name, ".debug") == 0 +#ifdef _COMMENT + || strcmp (name, _COMMENT) == 0 +#endif + || strncmp (name, ".stab", 5) == 0) + { +#ifdef COFF_PAGE_SIZE + sec_flags |= SEC_DEBUGGING; +#endif + } +#ifdef _LIB + else if (strcmp (name, _LIB) == 0) + ; +#endif +#ifdef _LIT + else if (strcmp (name, _LIT) == 0) + { + sec_flags = SEC_LOAD | SEC_ALLOC | SEC_READONLY; + } +#endif + else + { + sec_flags |= SEC_ALLOC | SEC_LOAD; + } + +#ifdef STYP_LIT /* A29k readonly text/data section type */ + if ((styp_flags & STYP_LIT) == STYP_LIT) + { + sec_flags = (SEC_LOAD | SEC_ALLOC | SEC_READONLY); + } +#endif /* STYP_LIT */ +#ifdef STYP_OTHER_LOAD /* Other loaded sections */ + if (styp_flags & STYP_OTHER_LOAD) + { + sec_flags = (SEC_LOAD | SEC_ALLOC); + } +#endif /* STYP_SDATA */ + + return (sec_flags); +} + +#define get_index(symbol) ((symbol)->udata.i) + +/* +INTERNAL_DEFINITION + bfd_coff_backend_data + +CODE_FRAGMENT + +Special entry points for gdb to swap in coff symbol table parts: +.typedef struct +.{ +. void (*_bfd_coff_swap_aux_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. int type, +. int class, +. int indaux, +. int numaux, +. PTR in)); +. +. void (*_bfd_coff_swap_sym_in) PARAMS (( +. bfd *abfd , +. PTR ext, +. PTR in)); +. +. void (*_bfd_coff_swap_lineno_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. PTR in)); +. + +Special entry points for gas to swap out coff parts: + +. unsigned int (*_bfd_coff_swap_aux_out) PARAMS (( +. bfd *abfd, +. PTR in, +. int type, +. int class, +. int indaux, +. int numaux, +. PTR ext)); +. +. unsigned int (*_bfd_coff_swap_sym_out) PARAMS (( +. bfd *abfd, +. PTR in, +. PTR ext)); +. +. unsigned int (*_bfd_coff_swap_lineno_out) PARAMS (( +. bfd *abfd, +. PTR in, +. PTR ext)); +. +. unsigned int (*_bfd_coff_swap_reloc_out) PARAMS (( +. bfd *abfd, +. PTR src, +. PTR dst)); +. +. unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS (( +. bfd *abfd, +. PTR in, +. PTR out)); +. +. unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS (( +. bfd *abfd, +. PTR in, +. PTR out)); +. +. unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS (( +. bfd *abfd, +. PTR in, +. PTR out)); +. + +Special entry points for generic COFF routines to call target +dependent COFF routines: + +. unsigned int _bfd_filhsz; +. unsigned int _bfd_aoutsz; +. unsigned int _bfd_scnhsz; +. unsigned int _bfd_symesz; +. unsigned int _bfd_auxesz; +. unsigned int _bfd_relsz; +. unsigned int _bfd_linesz; +. boolean _bfd_coff_long_filenames; +. void (*_bfd_coff_swap_filehdr_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. PTR in)); +. void (*_bfd_coff_swap_aouthdr_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. PTR in)); +. void (*_bfd_coff_swap_scnhdr_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. PTR in)); +. void (*_bfd_coff_swap_reloc_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. PTR in)); +. boolean (*_bfd_coff_bad_format_hook) PARAMS (( +. bfd *abfd, +. PTR internal_filehdr)); +. boolean (*_bfd_coff_set_arch_mach_hook) PARAMS (( +. bfd *abfd, +. PTR internal_filehdr)); +. PTR (*_bfd_coff_mkobject_hook) PARAMS (( +. bfd *abfd, +. PTR internal_filehdr, +. PTR internal_aouthdr)); +. flagword (*_bfd_styp_to_sec_flags_hook) PARAMS (( +. bfd *abfd, +. PTR internal_scnhdr, +. const char *name)); +. void (*_bfd_set_alignment_hook) PARAMS (( +. bfd *abfd, +. asection *sec, +. PTR internal_scnhdr)); +. boolean (*_bfd_coff_slurp_symbol_table) PARAMS (( +. bfd *abfd)); +. boolean (*_bfd_coff_symname_in_debug) PARAMS (( +. bfd *abfd, +. struct internal_syment *sym)); +. boolean (*_bfd_coff_pointerize_aux_hook) PARAMS (( +. bfd *abfd, +. combined_entry_type *table_base, +. combined_entry_type *symbol, +. unsigned int indaux, +. combined_entry_type *aux)); +. boolean (*_bfd_coff_print_aux) PARAMS (( +. bfd *abfd, +. FILE *file, +. combined_entry_type *table_base, +. combined_entry_type *symbol, +. combined_entry_type *aux, +. unsigned int indaux)); +. void (*_bfd_coff_reloc16_extra_cases) PARAMS (( +. bfd *abfd, +. struct bfd_link_info *link_info, +. struct bfd_link_order *link_order, +. arelent *reloc, +. bfd_byte *data, +. unsigned int *src_ptr, +. unsigned int *dst_ptr)); +. int (*_bfd_coff_reloc16_estimate) PARAMS (( +. bfd *abfd, +. asection *input_section, +. arelent *r, +. unsigned int shrink, +. struct bfd_link_info *link_info)); +. boolean (*_bfd_coff_sym_is_global) PARAMS (( +. bfd *abfd, +. struct internal_syment *)); +. void (*_bfd_coff_compute_section_file_positions) PARAMS (( +. bfd *abfd)); +. boolean (*_bfd_coff_start_final_link) PARAMS (( +. bfd *output_bfd, +. struct bfd_link_info *info)); +. boolean (*_bfd_coff_relocate_section) PARAMS (( +. bfd *output_bfd, +. struct bfd_link_info *info, +. bfd *input_bfd, +. asection *input_section, +. bfd_byte *contents, +. struct internal_reloc *relocs, +. struct internal_syment *syms, +. asection **sections)); +. reloc_howto_type *(*_bfd_coff_rtype_to_howto) PARAMS (( +. bfd *abfd, +. asection *sec, +. struct internal_reloc *rel, +. struct coff_link_hash_entry *h, +. struct internal_syment *sym, +. bfd_vma *addendp)); +. boolean (*_bfd_coff_adjust_symndx) PARAMS (( +. bfd *obfd, +. struct bfd_link_info *info, +. bfd *ibfd, +. asection *sec, +. struct internal_reloc *reloc, +. boolean *adjustedp)); +. boolean (*_bfd_coff_link_add_one_symbol) PARAMS (( +. struct bfd_link_info *info, +. bfd *abfd, +. const char *name, +. flagword flags, +. asection *section, +. bfd_vma value, +. const char *string, +. boolean copy, +. boolean collect, +. struct bfd_link_hash_entry **hashp)); +. +.} bfd_coff_backend_data; +. +.#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) +. +.#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ +. ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) +. +.#define bfd_coff_swap_sym_in(a,e,i) \ +. ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) +. +.#define bfd_coff_swap_lineno_in(a,e,i) \ +. ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) +. +.#define bfd_coff_swap_reloc_out(abfd, i, o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) +. +.#define bfd_coff_swap_lineno_out(abfd, i, o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) +. +.#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ +. ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) +. +.#define bfd_coff_swap_sym_out(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) +. +.#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) +. +.#define bfd_coff_swap_filehdr_out(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) +. +.#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) +. +.#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) +.#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) +.#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) +.#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) +.#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) +.#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) +.#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) +.#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames) +.#define bfd_coff_swap_filehdr_in(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) +. +.#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) +. +.#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) +. +.#define bfd_coff_swap_reloc_in(abfd, i, o) \ +. ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) +. +.#define bfd_coff_bad_format_hook(abfd, filehdr) \ +. ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) +. +.#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ +. ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) +.#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ +. ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr)) +. +.#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name)\ +. ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr, name)) +. +.#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ +. ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) +. +.#define bfd_coff_slurp_symbol_table(abfd)\ +. ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) +. +.#define bfd_coff_symname_in_debug(abfd, sym)\ +. ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) +. +.#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ +. ((coff_backend_info (abfd)->_bfd_coff_print_aux)\ +. (abfd, file, base, symbol, aux, indaux)) +. +.#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)\ +. ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ +. (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) +. +.#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ +. ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ +. (abfd, section, reloc, shrink, link_info)) +. +.#define bfd_coff_sym_is_global(abfd, sym)\ +. ((coff_backend_info (abfd)->_bfd_coff_sym_is_global)\ +. (abfd, sym)) +. +.#define bfd_coff_compute_section_file_positions(abfd)\ +. ((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ +. (abfd)) +. +.#define bfd_coff_start_final_link(obfd, info)\ +. ((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ +. (obfd, info)) +.#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ +. ((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ +. (obfd, info, ibfd, o, con, rel, isyms, secs)) +.#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ +. ((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ +. (abfd, sec, rel, h, sym, addendp)) +.#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ +. ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ +. (obfd, info, ibfd, sec, rel, adjustedp)) +.#define bfd_coff_link_add_one_symbol(info,abfd,name,flags,section,value,string,cp,coll,hashp)\ +. ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ +. (info, abfd, name, flags, section, value, string, cp, coll, hashp)) +. +*/ + +/* See whether the magic number matches. */ + +static boolean +coff_bad_format_hook (abfd, filehdr) + bfd * abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + if (BADMAG (*internal_f)) + return false; + + /* if the optional header is NULL or not the correct size then + quit; the only difference I can see between m88k dgux headers (MC88DMAGIC) + and Intel 960 readwrite headers (I960WRMAGIC) is that the + optional header is of a different size. + + But the mips keeps extra stuff in it's opthdr, so dont check + when doing that + */ + +#if defined(M88) || defined(I960) + if (internal_f->f_opthdr != 0 && AOUTSZ != internal_f->f_opthdr) + return false; +#endif + + return true; +} + +/* + initialize a section structure with information peculiar to this + particular implementation of coff +*/ + +static boolean +coff_new_section_hook (abfd, section) + bfd * abfd; + asection * section; +{ + section->alignment_power = COFF_DEFAULT_SECTION_ALIGNMENT_POWER; + +#ifdef RS6000COFF_C + if (xcoff_data (abfd)->text_align_power != 0 + && strcmp (bfd_get_section_name (abfd, section), ".text") == 0) + section->alignment_power = xcoff_data (abfd)->text_align_power; + if (xcoff_data (abfd)->data_align_power != 0 + && strcmp (bfd_get_section_name (abfd, section), ".data") == 0) + section->alignment_power = xcoff_data (abfd)->data_align_power; +#endif + + /* Allocate aux records for section symbols, to store size and + related info. + + @@ Shouldn't use constant multiplier here! */ + coffsymbol (section->symbol)->native = + (combined_entry_type *) bfd_zalloc (abfd, + sizeof (combined_entry_type) * 10); + + /* The .stab section must be aligned to 2**2 at most, because + otherwise there may be gaps in the section which gdb will not + know how to interpret. Examining the section name is a hack, but + that is also how gdb locates the section. + We need to handle the .ctors and .dtors sections similarly, to + avoid introducing null words in the tables. */ + if (COFF_DEFAULT_SECTION_ALIGNMENT_POWER > 2 + && (strncmp (section->name, ".stab", 5) == 0 + || strcmp (section->name, ".ctors") == 0 + || strcmp (section->name, ".dtors") == 0)) + section->alignment_power = 2; + + /* Similarly, the .stabstr section must be aligned to 2**0 at most. */ + if (COFF_DEFAULT_SECTION_ALIGNMENT_POWER > 0 + && strncmp (section->name, ".stabstr", 8) == 0) + section->alignment_power = 0; + + return true; +} + +#ifdef I960 + +/* Set the alignment of a BFD section. */ + +static void +coff_set_alignment_hook (abfd, section, scnhdr) + bfd * abfd; + asection * section; + PTR scnhdr; +{ + struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; + unsigned int i; + + for (i = 0; i < 32; i++) + if ((1 << i) >= hdr->s_align) + break; + section->alignment_power = i; +} + +#else /* ! I960 */ +#ifdef COFF_WITH_PE + +/* a couple of macros to help setting the alignment power field */ +#define ALIGN_SET(field,x,y) \ + if (((field) & IMAGE_SCN_ALIGN_64BYTES) == x )\ + {\ + section->alignment_power = y;\ + } + +#define ELIFALIGN_SET(field,x,y) \ + else if (( (field) & IMAGE_SCN_ALIGN_64BYTES) == x ) \ + {\ + section->alignment_power = y;\ + } + +static void +coff_set_alignment_hook (abfd, section, scnhdr) + bfd * abfd; + asection * section; + PTR scnhdr; +{ + struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; + + ALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_64BYTES, 6) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_32BYTES, 5) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_16BYTES, 4) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_8BYTES, 3) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_4BYTES, 2) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_2BYTES, 1) + ELIFALIGN_SET (hdr->s_flags, IMAGE_SCN_ALIGN_1BYTES, 0) + +#ifdef POWERPC_LE_PE + if (strcmp (section->name, ".idata$2") == 0) + { + section->alignment_power = 0; + } + else if (strcmp (section->name, ".idata$3") == 0) + { + section->alignment_power = 0; + } + else if (strcmp (section->name, ".idata$4") == 0) + { + section->alignment_power = 2; + } + else if (strcmp (section->name, ".idata$5") == 0) + { + section->alignment_power = 2; + } + else if (strcmp (section->name, ".idata$6") == 0) + { + section->alignment_power = 1; + } + else if (strcmp (section->name, ".reloc") == 0) + { + section->alignment_power = 1; + } + else if (strncmp (section->name, ".stab", 5) == 0) + { + section->alignment_power = 2; + } +#endif +} +#undef ALIGN_SET +#undef ELIFALIGN_SET + +#else /* ! COFF_WITH_PE */ +#ifdef RS6000COFF_C + +/* We grossly abuse this function to handle XCOFF overflow headers. + When we see one, we correct the reloc and line number counts in the + real header, and remove the section we just created. */ + +static void +coff_set_alignment_hook (abfd, section, scnhdr) + bfd *abfd; + asection *section; + PTR scnhdr; +{ + struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; + asection *real_sec; + asection **ps; + + if ((hdr->s_flags & STYP_OVRFLO) == 0) + return; + + real_sec = coff_section_from_bfd_index (abfd, hdr->s_nreloc); + if (real_sec == NULL) + return; + + real_sec->reloc_count = hdr->s_paddr; + real_sec->lineno_count = hdr->s_vaddr; + + for (ps = &abfd->sections; *ps != NULL; ps = &(*ps)->next) + { + if (*ps == section) + { + *ps = (*ps)->next; + --abfd->section_count; + break; + } + } +} + +#else /* ! RS6000COFF_C */ + +#define coff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) + +#endif /* ! RS6000COFF_C */ +#endif /* ! COFF_WITH_PE */ +#endif /* ! I960 */ + +#ifndef coff_mkobject +static boolean +coff_mkobject (abfd) + bfd * abfd; +{ + coff_data_type *coff; + + abfd->tdata.coff_obj_data = (struct coff_tdata *) bfd_zalloc (abfd, sizeof (coff_data_type)); + if (abfd->tdata.coff_obj_data == 0) + return false; + coff = coff_data (abfd); + coff->symbols = (coff_symbol_type *) NULL; + coff->conversion_table = (unsigned int *) NULL; + coff->raw_syments = (struct coff_ptr_struct *) NULL; + coff->relocbase = 0; + coff->local_toc_sym_map = 0; + +/* make_abs_section(abfd);*/ + + return true; +} +#endif + +/* Create the COFF backend specific information. */ +#ifndef coff_mkobject_hook +static PTR +coff_mkobject_hook (abfd, filehdr, aouthdr) + bfd * abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + coff_data_type *coff; + + if (coff_mkobject (abfd) == false) + return NULL; + + coff = coff_data (abfd); + + coff->sym_filepos = internal_f->f_symptr; + + /* These members communicate important constants about the symbol + table to GDB's symbol-reading code. These `constants' + unfortunately vary among coff implementations... */ + coff->local_n_btmask = N_BTMASK; + coff->local_n_btshft = N_BTSHFT; + coff->local_n_tmask = N_TMASK; + coff->local_n_tshift = N_TSHIFT; + coff->local_symesz = SYMESZ; + coff->local_auxesz = AUXESZ; + coff->local_linesz = LINESZ; + + obj_raw_syment_count (abfd) = + obj_conv_table_size (abfd) = + internal_f->f_nsyms; + +#ifdef RS6000COFF_C + if ((internal_f->f_flags & F_SHROBJ) != 0) + abfd->flags |= DYNAMIC; + if (aouthdr != NULL && internal_f->f_opthdr >= AOUTSZ) + { + struct internal_aouthdr *internal_a = + (struct internal_aouthdr *) aouthdr; + struct xcoff_tdata *xcoff; + + xcoff = xcoff_data (abfd); + xcoff->full_aouthdr = true; + xcoff->toc = internal_a->o_toc; + xcoff->sntoc = internal_a->o_sntoc; + xcoff->snentry = internal_a->o_snentry; + xcoff->text_align_power = internal_a->o_algntext; + xcoff->data_align_power = internal_a->o_algndata; + xcoff->modtype = internal_a->o_modtype; + xcoff->cputype = internal_a->o_cputype; + xcoff->maxdata = internal_a->o_maxdata; + xcoff->maxstack = internal_a->o_maxstack; + } +#endif + + return (PTR) coff; +} +#endif + +/* Determine the machine architecture and type. FIXME: This is target + dependent because the magic numbers are defined in the target + dependent header files. But there is no particular need for this. + If the magic numbers were moved to a separate file, this function + would be target independent and would also be much more successful + at linking together COFF files for different architectures. */ + +static boolean +coff_set_arch_mach_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + long machine; + enum bfd_architecture arch; + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + machine = 0; + switch (internal_f->f_magic) + { +#ifdef PPCMAGIC + case PPCMAGIC: + arch = bfd_arch_powerpc; + machine = 0; /* what does this mean? (krk) */ + break; +#endif +#ifdef I386MAGIC + case I386MAGIC: + case I386PTXMAGIC: + case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler */ + case LYNXCOFFMAGIC: /* shadows the m68k Lynx number below, sigh */ + arch = bfd_arch_i386; + machine = 0; + break; +#endif +#ifdef A29K_MAGIC_BIG + case A29K_MAGIC_BIG: + case A29K_MAGIC_LITTLE: + arch = bfd_arch_a29k; + machine = 0; + break; +#endif +#ifdef ARMMAGIC + case ARMMAGIC: + arch = bfd_arch_arm; + machine =0; + break; +#endif +#ifdef MC68MAGIC + case MC68MAGIC: + case M68MAGIC: +#ifdef MC68KBCSMAGIC + case MC68KBCSMAGIC: +#endif +#ifdef APOLLOM68KMAGIC + case APOLLOM68KMAGIC: +#endif +#ifdef LYNXCOFFMAGIC + case LYNXCOFFMAGIC: +#endif + arch = bfd_arch_m68k; + machine = 68020; + break; +#endif +#ifdef MC88MAGIC + case MC88MAGIC: + case MC88DMAGIC: + case MC88OMAGIC: + arch = bfd_arch_m88k; + machine = 88100; + break; +#endif +#ifdef Z8KMAGIC + case Z8KMAGIC: + arch = bfd_arch_z8k; + switch (internal_f->f_flags & F_MACHMASK) + { + case F_Z8001: + machine = bfd_mach_z8001; + break; + case F_Z8002: + machine = bfd_mach_z8002; + break; + default: + return false; + } + break; +#endif +#ifdef I860 + case I860MAGIC: + arch = bfd_arch_i860; + break; +#endif +#ifdef I960 +#ifdef I960ROMAGIC + case I960ROMAGIC: + case I960RWMAGIC: + arch = bfd_arch_i960; + switch (F_I960TYPE & internal_f->f_flags) + { + default: + case F_I960CORE: + machine = bfd_mach_i960_core; + break; + case F_I960KB: + machine = bfd_mach_i960_kb_sb; + break; + case F_I960MC: + machine = bfd_mach_i960_mc; + break; + case F_I960XA: + machine = bfd_mach_i960_xa; + break; + case F_I960CA: + machine = bfd_mach_i960_ca; + break; + case F_I960KA: + machine = bfd_mach_i960_ka_sa; + break; + case F_I960JX: + machine = bfd_mach_i960_jx; + break; + case F_I960HX: + machine = bfd_mach_i960_hx; + break; + } + break; +#endif +#endif + +#ifdef RS6000COFF_C + case U802ROMAGIC: + case U802WRMAGIC: + case U802TOCMAGIC: + { + int cputype; + + if (xcoff_data (abfd)->cputype != -1) + cputype = xcoff_data (abfd)->cputype & 0xff; + else + { + /* We did not get a value from the a.out header. If the + file has not been stripped, we may be able to get the + architecture information from the first symbol, if it + is a .file symbol. */ + if (obj_raw_syment_count (abfd) == 0) + cputype = 0; + else + { + bfd_byte buf[SYMESZ]; + struct internal_syment sym; + + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || bfd_read (buf, 1, SYMESZ, abfd) != SYMESZ) + return false; + coff_swap_sym_in (abfd, (PTR) buf, (PTR) &sym); + if (sym.n_sclass == C_FILE) + cputype = sym.n_type & 0xff; + else + cputype = 0; + } + } + + /* FIXME: We don't handle all cases here. */ + switch (cputype) + { + default: + case 0: +#ifdef POWERMAC + /* PowerPC Macs use the same magic numbers as RS/6000 + (because that's how they were bootstrapped originally), + but they are always PowerPC architecture. */ + arch = bfd_arch_powerpc; + machine = 0; +#else + arch = bfd_arch_rs6000; + machine = 6000; +#endif /* POWERMAC */ + break; + + case 1: + arch = bfd_arch_powerpc; + machine = 601; + break; + case 2: /* 64 bit PowerPC */ + arch = bfd_arch_powerpc; + machine = 620; + break; + case 3: + arch = bfd_arch_powerpc; + machine = 0; + break; + case 4: + arch = bfd_arch_rs6000; + machine = 6000; + break; + } + } + break; +#endif + +#ifdef WE32KMAGIC + case WE32KMAGIC: + arch = bfd_arch_we32k; + machine = 0; + break; +#endif + +#ifdef H8300MAGIC + case H8300MAGIC: + arch = bfd_arch_h8300; + machine = bfd_mach_h8300; + /* !! FIXME this probably isn't the right place for this */ + abfd->flags |= BFD_IS_RELAXABLE; + break; +#endif + +#ifdef H8300HMAGIC + case H8300HMAGIC: + arch = bfd_arch_h8300; + machine = bfd_mach_h8300h; + /* !! FIXME this probably isn't the right place for this */ + abfd->flags |= BFD_IS_RELAXABLE; + break; +#endif + +#ifdef SH_ARCH_MAGIC_BIG + case SH_ARCH_MAGIC_BIG: + case SH_ARCH_MAGIC_LITTLE: + arch = bfd_arch_sh; + machine = 0; + break; +#endif + +#ifdef H8500MAGIC + case H8500MAGIC: + arch = bfd_arch_h8500; + machine = 0; + break; +#endif + +#ifdef SPARCMAGIC + case SPARCMAGIC: +#ifdef LYNXCOFFMAGIC + case LYNXCOFFMAGIC: +#endif + arch = bfd_arch_sparc; + machine = 0; + break; +#endif + + default: /* Unreadable input file type */ + arch = bfd_arch_obscure; + break; + } + + bfd_default_set_arch_mach (abfd, arch, machine); + return true; +} + +#ifdef SYMNAME_IN_DEBUG + +static boolean +symname_in_debug_hook (abfd, sym) + bfd * abfd; + struct internal_syment *sym; +{ + return SYMNAME_IN_DEBUG (sym) ? true : false; +} + +#else + +#define symname_in_debug_hook \ + (boolean (*) PARAMS ((bfd *, struct internal_syment *))) bfd_false + +#endif + +#ifdef RS6000COFF_C + +/* Handle the csect auxent of a C_EXT or C_HIDEXT symbol. */ + +static boolean coff_pointerize_aux_hook + PARAMS ((bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *)); + +/*ARGSUSED*/ +static boolean +coff_pointerize_aux_hook (abfd, table_base, symbol, indaux, aux) + bfd *abfd; + combined_entry_type *table_base; + combined_entry_type *symbol; + unsigned int indaux; + combined_entry_type *aux; +{ + int class = symbol->u.syment.n_sclass; + + if ((class == C_EXT || class == C_HIDEXT) + && indaux + 1 == symbol->u.syment.n_numaux) + { + if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) == XTY_LD) + { + aux->u.auxent.x_csect.x_scnlen.p = + table_base + aux->u.auxent.x_csect.x_scnlen.l; + aux->fix_scnlen = 1; + } + + /* Return true to indicate that the caller should not do any + further work on this auxent. */ + return true; + } + + /* Return false to indicate that this auxent should be handled by + the caller. */ + return false; +} + +#else +#ifdef I960 + +/* We don't want to pointerize bal entries. */ + +static boolean coff_pointerize_aux_hook + PARAMS ((bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *)); + +/*ARGSUSED*/ +static boolean +coff_pointerize_aux_hook (abfd, table_base, symbol, indaux, aux) + bfd *abfd; + combined_entry_type *table_base; + combined_entry_type *symbol; + unsigned int indaux; + combined_entry_type *aux; +{ + /* Return true if we don't want to pointerize this aux entry, which + is the case for the lastfirst aux entry for a C_LEAFPROC symbol. */ + return (indaux == 1 + && (symbol->u.syment.n_sclass == C_LEAFPROC + || symbol->u.syment.n_sclass == C_LEAFSTAT + || symbol->u.syment.n_sclass == C_LEAFEXT)); +} + +#else /* ! I960 */ + +#define coff_pointerize_aux_hook 0 + +#endif /* ! I960 */ +#endif /* ! RS6000COFF_C */ + +/* Print an aux entry. This returns true if it has printed it. */ + +static boolean coff_print_aux + PARAMS ((bfd *, FILE *, combined_entry_type *, combined_entry_type *, + combined_entry_type *, unsigned int)); + +static boolean +coff_print_aux (abfd, file, table_base, symbol, aux, indaux) + bfd *abfd; + FILE *file; + combined_entry_type *table_base; + combined_entry_type *symbol; + combined_entry_type *aux; + unsigned int indaux; +{ +#ifdef RS6000COFF_C + if ((symbol->u.syment.n_sclass == C_EXT + || symbol->u.syment.n_sclass == C_HIDEXT) + && indaux + 1 == symbol->u.syment.n_numaux) + { + /* This is a csect entry. */ + fprintf (file, "AUX "); + if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) != XTY_LD) + { + BFD_ASSERT (! aux->fix_scnlen); + fprintf (file, "val %5ld", aux->u.auxent.x_csect.x_scnlen.l); + } + else + { + fprintf (file, "indx "); + if (! aux->fix_scnlen) + fprintf (file, "%4ld", aux->u.auxent.x_csect.x_scnlen.l); + else + fprintf (file, "%4ld", + (long) (aux->u.auxent.x_csect.x_scnlen.p - table_base)); + } + fprintf (file, + " prmhsh %ld snhsh %u typ %d algn %d clss %u stb %ld snstb %u", + aux->u.auxent.x_csect.x_parmhash, + (unsigned int) aux->u.auxent.x_csect.x_snhash, + SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp), + SMTYP_ALIGN (aux->u.auxent.x_csect.x_smtyp), + (unsigned int) aux->u.auxent.x_csect.x_smclas, + aux->u.auxent.x_csect.x_stab, + (unsigned int) aux->u.auxent.x_csect.x_snstab); + return true; + } +#endif + + /* Return false to indicate that no special action was taken. */ + return false; +} + +/* +SUBSUBSECTION + Writing relocations + + To write relocations, the back end steps though the + canonical relocation table and create an + @code{internal_reloc}. The symbol index to use is removed from + the @code{offset} field in the symbol table supplied. The + address comes directly from the sum of the section base + address and the relocation offset; the type is dug directly + from the howto field. Then the @code{internal_reloc} is + swapped into the shape of an @code{external_reloc} and written + out to disk. + +*/ + +#ifdef TARG_AUX + +static int compare_arelent_ptr PARAMS ((const PTR, const PTR)); + +/* AUX's ld wants relocations to be sorted */ +static int +compare_arelent_ptr (x, y) + const PTR x; + const PTR y; +{ + const arelent **a = (const arelent **) x; + const arelent **b = (const arelent **) y; + bfd_size_type aadr = (*a)->address; + bfd_size_type badr = (*b)->address; + + return (aadr < badr ? -1 : badr < aadr ? 1 : 0); +} + +#endif /* TARG_AUX */ + +static boolean +coff_write_relocs (abfd, first_undef) + bfd * abfd; + int first_undef; +{ + asection *s; + + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + unsigned int i; + struct external_reloc dst; + arelent **p; + +#ifndef TARG_AUX + p = s->orelocation; +#else + /* sort relocations before we write them out */ + p = (arelent **) bfd_malloc (s->reloc_count * sizeof (arelent *)); + if (p == NULL && s->reloc_count > 0) + return false; + memcpy (p, s->orelocation, s->reloc_count * sizeof (arelent *)); + qsort (p, s->reloc_count, sizeof (arelent *), compare_arelent_ptr); +#endif + + if (bfd_seek (abfd, s->rel_filepos, SEEK_SET) != 0) + return false; + for (i = 0; i < s->reloc_count; i++) + { + struct internal_reloc n; + arelent *q = p[i]; + memset ((PTR) & n, 0, sizeof (n)); + + /* Now we've renumbered the symbols we know where the + undefined symbols live in the table. Check the reloc + entries for symbols who's output bfd isn't the right one. + This is because the symbol was undefined (which means + that all the pointers are never made to point to the same + place). This is a bad thing,'cause the symbols attached + to the output bfd are indexed, so that the relocation + entries know which symbol index they point to. So we + have to look up the output symbol here. */ + + if (q->sym_ptr_ptr[0]->the_bfd != abfd) + { + int i; + const char *sname = q->sym_ptr_ptr[0]->name; + asymbol **outsyms = abfd->outsymbols; + for (i = first_undef; outsyms[i]; i++) + { + const char *intable = outsyms[i]->name; + if (strcmp (intable, sname) == 0) { + /* got a hit, so repoint the reloc */ + q->sym_ptr_ptr = outsyms + i; + break; + } + } + } + + n.r_vaddr = q->address + s->vma; + +#ifdef R_IHCONST + /* The 29k const/consth reloc pair is a real kludge. The consth + part doesn't have a symbol; it has an offset. So rebuilt + that here. */ + if (q->howto->type == R_IHCONST) + n.r_symndx = q->addend; + else +#endif + if (q->sym_ptr_ptr) + { + if (q->sym_ptr_ptr == bfd_abs_section_ptr->symbol_ptr_ptr) + /* This is a relocation relative to the absolute symbol. */ + n.r_symndx = -1; + else + { + n.r_symndx = get_index ((*(q->sym_ptr_ptr))); + /* Take notice if the symbol reloc points to a symbol + we don't have in our symbol table. What should we + do for this?? */ + if (n.r_symndx > obj_conv_table_size (abfd)) + abort (); + } + } + +#ifdef SWAP_OUT_RELOC_OFFSET + n.r_offset = q->addend; +#endif + +#ifdef SELECT_RELOC + /* Work out reloc type from what is required */ + SELECT_RELOC (n, q->howto); +#else + n.r_type = q->howto->type; +#endif + coff_swap_reloc_out (abfd, &n, &dst); + if (bfd_write ((PTR) & dst, 1, RELSZ, abfd) != RELSZ) + return false; + } + +#ifdef TARG_AUX + if (p != NULL) + free (p); +#endif + } + + return true; +} + +/* Set flags and magic number of a coff file from architecture and machine + type. Result is true if we can represent the arch&type, false if not. */ + +static boolean +coff_set_flags (abfd, magicp, flagsp) + bfd * abfd; + unsigned *magicp; + unsigned short *flagsp; +{ + switch (bfd_get_arch (abfd)) + { +#ifdef Z8KMAGIC + case bfd_arch_z8k: + *magicp = Z8KMAGIC; + switch (bfd_get_mach (abfd)) + { + case bfd_mach_z8001: + *flagsp = F_Z8001; + break; + case bfd_mach_z8002: + *flagsp = F_Z8002; + break; + default: + return false; + } + return true; +#endif +#ifdef I960ROMAGIC + + case bfd_arch_i960: + + { + unsigned flags; + *magicp = I960ROMAGIC; + /* + ((bfd_get_file_flags(abfd) & WP_TEXT) ? I960ROMAGIC : + I960RWMAGIC); FIXME??? + */ + switch (bfd_get_mach (abfd)) + { + case bfd_mach_i960_core: + flags = F_I960CORE; + break; + case bfd_mach_i960_kb_sb: + flags = F_I960KB; + break; + case bfd_mach_i960_mc: + flags = F_I960MC; + break; + case bfd_mach_i960_xa: + flags = F_I960XA; + break; + case bfd_mach_i960_ca: + flags = F_I960CA; + break; + case bfd_mach_i960_ka_sa: + flags = F_I960KA; + break; + case bfd_mach_i960_jx: + flags = F_I960JX; + break; + case bfd_mach_i960_hx: + flags = F_I960HX; + break; + default: + return false; + } + *flagsp = flags; + return true; + } + break; +#endif +#ifdef ARMMAGIC + case bfd_arch_arm: + *magicp = ARMMAGIC; + return true; +#endif +#ifdef PPCMAGIC + case bfd_arch_powerpc: + *magicp = PPCMAGIC; + return true; + break; +#endif +#ifdef I386MAGIC + case bfd_arch_i386: + *magicp = I386MAGIC; +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif +#ifdef I860MAGIC + case bfd_arch_i860: + *magicp = I860MAGIC; + return true; + break; +#endif +#ifdef MC68MAGIC + case bfd_arch_m68k: +#ifdef APOLLOM68KMAGIC + *magicp = APOLLO_COFF_VERSION_NUMBER; +#else + *magicp = MC68MAGIC; +#endif +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif + +#ifdef MC88MAGIC + case bfd_arch_m88k: + *magicp = MC88OMAGIC; + return true; + break; +#endif +#ifdef H8300MAGIC + case bfd_arch_h8300: + switch (bfd_get_mach (abfd)) + { + case bfd_mach_h8300: + *magicp = H8300MAGIC; + return true; + case bfd_mach_h8300h: + *magicp = H8300HMAGIC; + return true; + } + break; +#endif + +#ifdef SH_ARCH_MAGIC_BIG + case bfd_arch_sh: + if (bfd_big_endian (abfd)) + *magicp = SH_ARCH_MAGIC_BIG; + else + *magicp = SH_ARCH_MAGIC_LITTLE; + return true; + break; +#endif + +#ifdef SPARCMAGIC + case bfd_arch_sparc: + *magicp = SPARCMAGIC; +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif + +#ifdef H8500MAGIC + case bfd_arch_h8500: + *magicp = H8500MAGIC; + return true; + break; +#endif +#ifdef A29K_MAGIC_BIG + case bfd_arch_a29k: + if (bfd_big_endian (abfd)) + *magicp = A29K_MAGIC_BIG; + else + *magicp = A29K_MAGIC_LITTLE; + return true; + break; +#endif + +#ifdef WE32KMAGIC + case bfd_arch_we32k: + *magicp = WE32KMAGIC; + return true; + break; +#endif + +#ifdef U802TOCMAGIC + case bfd_arch_rs6000: +#ifndef PPCMAGIC + case bfd_arch_powerpc: +#endif + *magicp = U802TOCMAGIC; + return true; + break; +#endif + + default: /* Unknown architecture */ + /* return false; -- fall through to "return false" below, to avoid + "statement never reached" errors on the one below. */ + break; + } + + return false; +} + + +static boolean +coff_set_arch_mach (abfd, arch, machine) + bfd * abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + unsigned dummy1; + unsigned short dummy2; + + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch != bfd_arch_unknown && + coff_set_flags (abfd, &dummy1, &dummy2) != true) + return false; /* We can't represent this type */ + + return true; /* We're easy ... */ +} + + +/* Calculate the file position for each section. */ + +static void +coff_compute_section_file_positions (abfd) + bfd * abfd; +{ + asection *current; + asection *previous = (asection *) NULL; + file_ptr sofar = FILHSZ; + +#ifndef I960 + file_ptr old_sofar; +#endif + unsigned int count; + +#ifdef RS6000COFF_C + /* On XCOFF, if we have symbols, set up the .debug section. */ + if (bfd_get_symcount (abfd) > 0) + { + bfd_size_type sz; + bfd_size_type i, symcount; + asymbol **symp; + + sz = 0; + symcount = bfd_get_symcount (abfd); + for (symp = abfd->outsymbols, i = 0; i < symcount; symp++, i++) + { + coff_symbol_type *cf; + + cf = coff_symbol_from (abfd, *symp); + if (cf != NULL + && cf->native != NULL + && SYMNAME_IN_DEBUG (&cf->native->u.syment)) + { + size_t len; + + len = strlen (bfd_asymbol_name (*symp)); + if (len > SYMNMLEN) + sz += len + 3; + } + } + if (sz > 0) + { + asection *dsec; + + dsec = bfd_make_section_old_way (abfd, ".debug"); + if (dsec == NULL) + abort (); + dsec->_raw_size = sz; + dsec->flags |= SEC_HAS_CONTENTS; + } + } +#endif + +#ifdef COFF_IMAGE_WITH_PE + int page_size; + if (coff_data (abfd)->link_info) + { + page_size = pe_data (abfd)->pe_opthdr.FileAlignment; + } + else + page_size = PE_DEF_FILE_ALIGNMENT; +#else +#ifdef COFF_PAGE_SIZE + int page_size = COFF_PAGE_SIZE; +#endif +#endif + + if (bfd_get_start_address (abfd)) + { + /* A start address may have been added to the original file. In this + case it will need an optional header to record it. */ + abfd->flags |= EXEC_P; + } + + if (abfd->flags & EXEC_P) + sofar += AOUTSZ; +#ifdef RS6000COFF_C + else if (xcoff_data (abfd)->full_aouthdr) + sofar += AOUTSZ; + else + sofar += SMALL_AOUTSZ; +#endif + + sofar += abfd->section_count * SCNHSZ; + +#ifdef RS6000COFF_C + /* XCOFF handles overflows in the reloc and line number count fields + by allocating a new section header to hold the correct counts. */ + for (current = abfd->sections; current != NULL; current = current->next) + if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) + sofar += SCNHSZ; +#endif + + for (current = abfd->sections, count = 1; + current != (asection *) NULL; + current = current->next, ++count) + { + current->target_index = count; + + /* Only deal with sections which have contents */ + if (!(current->flags & SEC_HAS_CONTENTS)) + continue; + +#ifdef COFF_WITH_PE + /* Do not include the .junk section. This is where we collect section + data which we don't need. This is mainly the MS .debug$ data which + stores codeview debug data. */ + if (strcmp (current->name, ".junk") == 0) + { + continue; + } +#endif + + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. I960 doesn't + do this (FIXME) so we can stay in sync with Intel. 960 + doesn't yet page from files... */ +#ifndef I960 + if ((abfd->flags & EXEC_P) != 0) + { + /* make sure this section is aligned on the right boundary - by + padding the previous section up if necessary */ + + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + if (previous != (asection *) NULL) + { + previous->_raw_size += sofar - old_sofar; + } + } + +#endif + + /* In demand paged files the low order bits of the file offset + must match the low order bits of the virtual address. */ +#ifdef COFF_PAGE_SIZE + if ((abfd->flags & D_PAGED) != 0 + && (current->flags & SEC_ALLOC) != 0) + sofar += (current->vma - sofar) % page_size; +#endif + current->filepos = sofar; + +#ifdef COFF_IMAGE_WITH_PE + /* With PE we have to pad each section to be a multiple of its page size + too, and remember both sizes. Cooked_size becomes very useful. */ + current->_cooked_size = current->_raw_size; + current->_raw_size = (current->_raw_size + page_size -1) & -page_size; +#endif + + sofar += current->_raw_size; + +#ifndef I960 + /* make sure that this section is of the right size too */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + current->_raw_size += sofar - old_sofar; +#endif + +#ifdef _LIB + /* Force .lib sections to start at zero. The vma is then + incremented in coff_set_section_contents. This is right for + SVR3.2. */ + if (strcmp (current->name, _LIB) == 0) + bfd_set_section_vma (abfd, current, 0); +#endif + + previous = current; + } + + obj_relocbase (abfd) = sofar; + abfd->output_has_begun = true; + +} + +#if 0 + +/* This can never work, because it is called too late--after the + section positions have been set. I can't figure out what it is + for, so I am going to disable it--Ian Taylor 20 March 1996. */ + +/* If .file, .text, .data, .bss symbols are missing, add them. */ +/* @@ Should we only be adding missing symbols, or overriding the aux + values for existing section symbols? */ +static boolean +coff_add_missing_symbols (abfd) + bfd *abfd; +{ + unsigned int nsyms = bfd_get_symcount (abfd); + asymbol **sympp = abfd->outsymbols; + asymbol **sympp2; + unsigned int i; + int need_text = 1, need_data = 1, need_bss = 1, need_file = 1; + + for (i = 0; i < nsyms; i++) + { + coff_symbol_type *csym = coff_symbol_from (abfd, sympp[i]); + CONST char *name; + if (csym) + { + /* only do this if there is a coff representation of the input + symbol */ + if (csym->native && csym->native->u.syment.n_sclass == C_FILE) + { + need_file = 0; + continue; + } + name = csym->symbol.name; + if (!name) + continue; + if (!strcmp (name, _TEXT)) + need_text = 0; +#ifdef APOLLO_M68 + else if (!strcmp (name, ".wtext")) + need_text = 0; +#endif + else if (!strcmp (name, _DATA)) + need_data = 0; + else if (!strcmp (name, _BSS)) + need_bss = 0; + } + } + /* Now i == bfd_get_symcount (abfd). */ + /* @@ For now, don't deal with .file symbol. */ + need_file = 0; + + if (!need_text && !need_data && !need_bss && !need_file) + return true; + nsyms += need_text + need_data + need_bss + need_file; + sympp2 = (asymbol **) bfd_alloc_by_size_t (abfd, nsyms * sizeof (asymbol *)); + if (!sympp2) + return false; + memcpy (sympp2, sympp, i * sizeof (asymbol *)); + if (need_file) + { + /* @@ Generate fake .file symbol, in sympp2[i], and increment i. */ + abort (); + } + if (need_text) + sympp2[i++] = coff_section_symbol (abfd, _TEXT); + if (need_data) + sympp2[i++] = coff_section_symbol (abfd, _DATA); + if (need_bss) + sympp2[i++] = coff_section_symbol (abfd, _BSS); + BFD_ASSERT (i == nsyms); + bfd_set_symtab (abfd, sympp2, nsyms); + return true; +} + +#endif /* 0 */ + +/* SUPPRESS 558 */ +/* SUPPRESS 529 */ +static boolean +coff_write_object_contents (abfd) + bfd * abfd; +{ + asection *current; + boolean hasrelocs = false; + boolean haslinno = false; + file_ptr scn_base; + file_ptr reloc_base; + file_ptr lineno_base; + file_ptr sym_base; + unsigned long reloc_size = 0; + unsigned long lnno_size = 0; + asection *text_sec = NULL; + asection *data_sec = NULL; + asection *bss_sec = NULL; + + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + bfd_set_error (bfd_error_system_call); + + /* Make a pass through the symbol table to count line number entries and + put them into the correct asections */ + + lnno_size = coff_count_linenumbers (abfd) * LINESZ; + + if (abfd->output_has_begun == false) + coff_compute_section_file_positions (abfd); + + reloc_base = obj_relocbase (abfd); + + /* Work out the size of the reloc and linno areas */ + + for (current = abfd->sections; current != NULL; current = + current->next) + reloc_size += current->reloc_count * RELSZ; + + lineno_base = reloc_base + reloc_size; + sym_base = lineno_base + lnno_size; + + /* Indicate in each section->line_filepos its actual file address */ + for (current = abfd->sections; current != NULL; current = + current->next) + { + if (current->lineno_count) + { + current->line_filepos = lineno_base; + current->moving_line_filepos = lineno_base; + lineno_base += current->lineno_count * LINESZ; + } + else + { + current->line_filepos = 0; + } + if (current->reloc_count) + { + current->rel_filepos = reloc_base; + reloc_base += current->reloc_count * RELSZ; + } + else + { + current->rel_filepos = 0; + } + } + + /* Write section headers to the file. */ + internal_f.f_nscns = 0; + + if ((abfd->flags & EXEC_P) != 0) + scn_base = FILHSZ + AOUTSZ; + else + { + scn_base = FILHSZ; +#ifdef RS6000COFF_C + if (xcoff_data (abfd)->full_aouthdr) + scn_base += AOUTSZ; + else + scn_base += SMALL_AOUTSZ; +#endif + } + + if (bfd_seek (abfd, scn_base, SEEK_SET) != 0) + return false; + + for (current = abfd->sections; + current != NULL; + current = current->next) + { + struct internal_scnhdr section; + +#ifdef COFF_WITH_PE + /* Do not include the .junk section. This is where we collect section + data which we don't need. This is mainly the MS .debug$ data which + stores codeview debug data. */ + if (strcmp (current->name, ".junk") == 0) + { + continue; + } + + /* If we've got a .reloc section, remember. */ + +#ifdef COFF_IMAGE_WITH_PE + if (strcmp (current->name, ".reloc") == 0) + { + pe_data (abfd)->has_reloc_section = 1; + } +#endif + +#endif + internal_f.f_nscns++; + strncpy (&(section.s_name[0]), current->name, 8); +#ifdef _LIB + /* Always set s_vaddr of .lib to 0. This is right for SVR3.2 + Ian Taylor . */ + if (strcmp (current->name, _LIB) == 0) + section.s_vaddr = 0; + else +#endif + section.s_vaddr = current->vma; + section.s_paddr = current->lma; + section.s_size = current->_raw_size; + +#ifdef COFF_WITH_PE + section.s_paddr = current->_cooked_size; +#endif + + /* + If this section has no size or is unloadable then the scnptr + will be 0 too + */ + if (current->_raw_size == 0 || + (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + { + section.s_scnptr = 0; + } + else + { + section.s_scnptr = current->filepos; + } + section.s_relptr = current->rel_filepos; + section.s_lnnoptr = current->line_filepos; + section.s_nreloc = current->reloc_count; + section.s_nlnno = current->lineno_count; + if (current->reloc_count != 0) + hasrelocs = true; + if (current->lineno_count != 0) + haslinno = true; + +#ifdef RS6000COFF_C + /* Indicate the use of an XCOFF overflow section header. */ + if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) + { + section.s_nreloc = 0xffff; + section.s_nlnno = 0xffff; + } +#endif + + section.s_flags = sec_to_styp_flags (current->name, current->flags); + + if (!strcmp (current->name, _TEXT)) + { + text_sec = current; + } + else if (!strcmp (current->name, _DATA)) + { + data_sec = current; + } + else if (!strcmp (current->name, _BSS)) + { + bss_sec = current; + } + +#ifdef I960 + section.s_align = (current->alignment_power + ? 1 << current->alignment_power + : 0); + +#endif + +#ifdef COFF_IMAGE_WITH_PE + /* suppress output of the sections if they are null. ld includes + the bss and data sections even if there is no size assigned + to them. NT loader doesn't like it if these section headers are + included if the sections themselves are not needed */ + if (section.s_size == 0) + internal_f.f_nscns--; + else +#endif + { + SCNHDR buff; + if (coff_swap_scnhdr_out (abfd, §ion, &buff) == 0 + || bfd_write ((PTR) (&buff), 1, SCNHSZ, abfd) != SCNHSZ) + return false; + } + } + +#ifdef RS6000COFF_C + /* XCOFF handles overflows in the reloc and line number count fields + by creating a new section header to hold the correct values. */ + for (current = abfd->sections; current != NULL; current = current->next) + { + if (current->reloc_count >= 0xffff || current->lineno_count >= 0xffff) + { + struct internal_scnhdr scnhdr; + SCNHDR buff; + + internal_f.f_nscns++; + strncpy (&(scnhdr.s_name[0]), current->name, 8); + scnhdr.s_paddr = current->reloc_count; + scnhdr.s_vaddr = current->lineno_count; + scnhdr.s_size = 0; + scnhdr.s_scnptr = 0; + scnhdr.s_relptr = current->rel_filepos; + scnhdr.s_lnnoptr = current->line_filepos; + scnhdr.s_nreloc = current->target_index; + scnhdr.s_nlnno = current->target_index; + scnhdr.s_flags = STYP_OVRFLO; + if (coff_swap_scnhdr_out (abfd, &scnhdr, &buff) == 0 + || bfd_write ((PTR) &buff, 1, SCNHSZ, abfd) != SCNHSZ) + return false; + } + } +#endif + + /* OK, now set up the filehdr... */ + + /* Don't include the internal abs section in the section count */ + + /* + We will NOT put a fucking timestamp in the header here. Every time you + put it back, I will come in and take it out again. I'm sorry. This + field does not belong here. We fill it with a 0 so it compares the + same but is not a reasonable time. -- gnu@cygnus.com + */ + internal_f.f_timdat = 0; + + internal_f.f_flags = 0; + + if (abfd->flags & EXEC_P) + internal_f.f_opthdr = AOUTSZ; + else + { + internal_f.f_opthdr = 0; +#ifdef RS6000COFF_C + if (xcoff_data (abfd)->full_aouthdr) + internal_f.f_opthdr = AOUTSZ; + else + internal_f.f_opthdr = SMALL_AOUTSZ; +#endif + } + + if (!hasrelocs) + internal_f.f_flags |= F_RELFLG; + if (!haslinno) + internal_f.f_flags |= F_LNNO; + if (abfd->flags & EXEC_P) + internal_f.f_flags |= F_EXEC; + + /* FIXME: this is wrong for PPC_PE! */ + if (bfd_little_endian (abfd)) + internal_f.f_flags |= F_AR32WR; + else + internal_f.f_flags |= F_AR32W; + + /* + FIXME, should do something about the other byte orders and + architectures. + */ + +#ifdef RS6000COFF_C + if ((abfd->flags & DYNAMIC) != 0) + internal_f.f_flags |= F_SHROBJ; + if (bfd_get_section_by_name (abfd, _LOADER) != NULL) + internal_f.f_flags |= F_DYNLOAD; +#endif + + memset (&internal_a, 0, sizeof internal_a); + + /* Set up architecture-dependent stuff */ + + { + unsigned int magic = 0; + unsigned short flags = 0; + coff_set_flags (abfd, &magic, &flags); + internal_f.f_magic = magic; + internal_f.f_flags |= flags; + /* ...and the "opt"hdr... */ + +#ifdef A29K +#ifdef ULTRA3 /* NYU's machine */ + /* FIXME: This is a bogus check. I really want to see if there + * is a .shbss or a .shdata section, if so then set the magic + * number to indicate a shared data executable. + */ + if (internal_f.f_nscns >= 7) + internal_a.magic = SHMAGIC; /* Shared magic */ + else +#endif /* ULTRA3 */ + internal_a.magic = NMAGIC; /* Assume separate i/d */ +#define __A_MAGIC_SET__ +#endif /* A29K */ +#ifdef I860 + /* FIXME: What are the a.out magic numbers for the i860? */ + internal_a.magic = 0; +#define __A_MAGIC_SET__ +#endif /* I860 */ +#ifdef I960 + internal_a.magic = (magic == I960ROMAGIC ? NMAGIC : OMAGIC); +#define __A_MAGIC_SET__ +#endif /* I960 */ +#if M88 +#define __A_MAGIC_SET__ + internal_a.magic = PAGEMAGICBCS; +#endif /* M88 */ + +#if APOLLO_M68 +#define __A_MAGIC_SET__ + internal_a.magic = APOLLO_COFF_VERSION_NUMBER; +#endif + +#if defined(M68) || defined(WE32K) || defined(M68K) +#define __A_MAGIC_SET__ +#if defined(LYNXOS) + internal_a.magic = LYNXCOFFMAGIC; +#else +#if defined(TARG_AUX) + internal_a.magic = (abfd->flags & D_PAGED ? PAGEMAGICPEXECPAGED : + abfd->flags & WP_TEXT ? PAGEMAGICPEXECSWAPPED : + PAGEMAGICEXECSWAPPED); +#else +#if defined (PAGEMAGICPEXECPAGED) + internal_a.magic = PAGEMAGICPEXECPAGED; +#endif +#endif /* TARG_AUX */ +#endif /* LYNXOS */ +#endif /* M68 || WE32K || M68K */ + +#if defined(ARM) +#define __A_MAGIC_SET__ + internal_a.magic = ZMAGIC; +#endif +#if defined(PPC) +#define __A_MAGIC_SET__ + internal_a.magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; +#endif +#if defined(I386) +#define __A_MAGIC_SET__ +#if defined(LYNXOS) + internal_a.magic = LYNXCOFFMAGIC; +#else /* LYNXOS */ + internal_a.magic = ZMAGIC; +#endif /* LYNXOS */ +#endif /* I386 */ + +#if defined(SPARC) +#define __A_MAGIC_SET__ +#if defined(LYNXOS) + internal_a.magic = LYNXCOFFMAGIC; +#endif /* LYNXOS */ +#endif /* SPARC */ + +#if RS6000COFF_C +#define __A_MAGIC_SET__ + internal_a.magic = (abfd->flags & D_PAGED) ? RS6K_AOUTHDR_ZMAGIC : + (abfd->flags & WP_TEXT) ? RS6K_AOUTHDR_NMAGIC : + RS6K_AOUTHDR_OMAGIC; +#endif + +#ifndef __A_MAGIC_SET__ +#include "Your aouthdr magic number is not being set!" +#else +#undef __A_MAGIC_SET__ +#endif + } + + /* FIXME: Does anybody ever set this to another value? */ + internal_a.vstamp = 0; + + /* Now should write relocs, strings, syms */ + obj_sym_filepos (abfd) = sym_base; + + if (bfd_get_symcount (abfd) != 0) + { + int firstundef; +#if 0 + if (!coff_add_missing_symbols (abfd)) + return false; +#endif + if (!coff_renumber_symbols (abfd, &firstundef)) + return false; + coff_mangle_symbols (abfd); + if (! coff_write_symbols (abfd)) + return false; + if (! coff_write_linenumbers (abfd)) + return false; + if (! coff_write_relocs (abfd, firstundef)) + return false; + } +#ifdef COFF_IMAGE_WITH_PE +#ifdef PPC + else if ((abfd->flags & EXEC_P) != 0) + { + bfd_byte b; + + /* PowerPC PE appears to require that all executable files be + rounded up to the page size. */ + b = 0; + if (bfd_seek (abfd, + BFD_ALIGN (sym_base, COFF_PAGE_SIZE) - 1, + SEEK_SET) != 0 + || bfd_write (&b, 1, 1, abfd) != 1) + return false; + } +#endif +#endif + + /* If bfd_get_symcount (abfd) != 0, then we are not using the COFF + backend linker, and obj_raw_syment_count is not valid until after + coff_write_symbols is called. */ + if (obj_raw_syment_count (abfd) != 0) + { + internal_f.f_symptr = sym_base; +#ifdef RS6000COFF_C + /* AIX appears to require that F_RELFLG not be set if there are + local symbols but no relocations. */ + internal_f.f_flags &=~ F_RELFLG; +#endif + } + else + { + internal_f.f_symptr = 0; + internal_f.f_flags |= F_LSYMS; + } + + if (text_sec) + { + internal_a.tsize = bfd_get_section_size_before_reloc (text_sec); + internal_a.text_start = internal_a.tsize ? text_sec->vma : 0; + } + if (data_sec) + { + internal_a.dsize = bfd_get_section_size_before_reloc (data_sec); + internal_a.data_start = internal_a.dsize ? data_sec->vma : 0; + } + if (bss_sec) + { + internal_a.bsize = bfd_get_section_size_before_reloc (bss_sec); + if (internal_a.bsize && bss_sec->vma < internal_a.data_start) + internal_a.data_start = bss_sec->vma; + } + + internal_a.entry = bfd_get_start_address (abfd); + internal_f.f_nsyms = obj_raw_syment_count (abfd); + +#ifdef RS6000COFF_C + if (xcoff_data (abfd)->full_aouthdr) + { + bfd_vma toc; + asection *loader_sec; + + internal_a.vstamp = 1; + + internal_a.o_snentry = xcoff_data (abfd)->snentry; + if (internal_a.o_snentry == 0) + internal_a.entry = (bfd_vma) -1; + + if (text_sec != NULL) + { + internal_a.o_sntext = text_sec->target_index; + internal_a.o_algntext = bfd_get_section_alignment (abfd, text_sec); + } + else + { + internal_a.o_sntext = 0; + internal_a.o_algntext = 0; + } + if (data_sec != NULL) + { + internal_a.o_sndata = data_sec->target_index; + internal_a.o_algndata = bfd_get_section_alignment (abfd, data_sec); + } + else + { + internal_a.o_sndata = 0; + internal_a.o_algndata = 0; + } + loader_sec = bfd_get_section_by_name (abfd, ".loader"); + if (loader_sec != NULL) + internal_a.o_snloader = loader_sec->target_index; + else + internal_a.o_snloader = 0; + if (bss_sec != NULL) + internal_a.o_snbss = bss_sec->target_index; + else + internal_a.o_snbss = 0; + + toc = xcoff_data (abfd)->toc; + internal_a.o_toc = toc; + internal_a.o_sntoc = xcoff_data (abfd)->sntoc; + + internal_a.o_modtype = xcoff_data (abfd)->modtype; + if (xcoff_data (abfd)->cputype != -1) + internal_a.o_cputype = xcoff_data (abfd)->cputype; + else + { + switch (bfd_get_arch (abfd)) + { + case bfd_arch_rs6000: + internal_a.o_cputype = 4; + break; + case bfd_arch_powerpc: + if (bfd_get_mach (abfd) == 0) + internal_a.o_cputype = 3; + else + internal_a.o_cputype = 1; + break; + default: + abort (); + } + } + internal_a.o_maxstack = xcoff_data (abfd)->maxstack; + internal_a.o_maxdata = xcoff_data (abfd)->maxdata; + } +#endif + + /* now write them */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + { + FILHDR buff; + coff_swap_filehdr_out (abfd, (PTR) & internal_f, (PTR) & buff); + if (bfd_write ((PTR) & buff, 1, FILHSZ, abfd) != FILHSZ) + return false; + } + if (abfd->flags & EXEC_P) + { + AOUTHDR buff; + coff_swap_aouthdr_out (abfd, (PTR) & internal_a, (PTR) & buff); + if (bfd_write ((PTR) & buff, 1, AOUTSZ, abfd) != AOUTSZ) + return false; + } +#ifdef RS6000COFF_C + else + { + AOUTHDR buff; + size_t size; + + /* XCOFF seems to always write at least a small a.out header. */ + coff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff); + if (xcoff_data (abfd)->full_aouthdr) + size = AOUTSZ; + else + size = SMALL_AOUTSZ; + if (bfd_write ((PTR) &buff, 1, size, abfd) != size) + return false; + } +#endif + + return true; +} + +static boolean +coff_set_section_contents (abfd, section, location, offset, count) + bfd * abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false) /* set by bfd.c handler */ + coff_compute_section_file_positions (abfd); + +#ifdef _LIB + + /* The physical address field of a .lib section is used to hold the + number of shared libraries in the section. This code counts the + number of sections being written, and increments the lma field + with the number. + + I have found no documentation on the contents of this section. + Experimentation indicates that the section contains zero or more + records, each of which has the following structure: + + - a (four byte) word holding the length of this record, in words, + - a word that always seems to be set to "2", + - the path to a shared library, null-terminated and then padded + to a whole word boundary. + + bfd_assert calls have been added to alert if an attempt is made + to write a section which doesn't follow these assumptions. The + code has been tested on ISC 4.1 by me, and on SCO by Robert Lipe + (Thanks!). + + Gvran Uddeborg */ + + if (strcmp (section->name, _LIB) == 0) + { + bfd_byte *rec, *recend; + + rec = (bfd_byte *) location; + recend = rec + count; + while (rec < recend) + { + ++section->lma; + rec += bfd_get_32 (abfd, rec) * 4; + } + + BFD_ASSERT (rec == recend); + } + +#endif + + /* Don't write out bss sections - one way to do this is to + see if the filepos has not been set. */ + if (section->filepos == 0) + return true; + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0) + return false; + + if (count != 0) + { + return (bfd_write (location, 1, count, abfd) == count) ? true : false; + } + return true; +} +#if 0 +static boolean +coff_close_and_cleanup (abfd) + bfd *abfd; +{ + if (!bfd_read_p (abfd)) + switch (abfd->format) + { + case bfd_archive: + if (!_bfd_write_archive_contents (abfd)) + return false; + break; + case bfd_object: + if (!coff_write_object_contents (abfd)) + return false; + break; + default: + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* We depend on bfd_close to free all the memory on the obstack. */ + /* FIXME if bfd_release is not using obstacks! */ + return true; +} + +#endif + +static PTR +buy_and_read (abfd, where, seek_direction, size) + bfd *abfd; + file_ptr where; + int seek_direction; + size_t size; +{ + PTR area = (PTR) bfd_alloc (abfd, size); + if (!area) + return (NULL); + if (bfd_seek (abfd, where, seek_direction) != 0 + || bfd_read (area, 1, size, abfd) != size) + return (NULL); + return (area); +} /* buy_and_read() */ + +/* +SUBSUBSECTION + Reading linenumbers + + Creating the linenumber table is done by reading in the entire + coff linenumber table, and creating another table for internal use. + + A coff linenumber table is structured so that each function + is marked as having a line number of 0. Each line within the + function is an offset from the first line in the function. The + base of the line number information for the table is stored in + the symbol associated with the function. + + The information is copied from the external to the internal + table, and each symbol which marks a function is marked by + pointing its... + + How does this work ? + +*/ + +static boolean +coff_slurp_line_table (abfd, asect) + bfd *abfd; + asection *asect; +{ + LINENO *native_lineno; + alent *lineno_cache; + + BFD_ASSERT (asect->lineno == (alent *) NULL); + + native_lineno = (LINENO *) buy_and_read (abfd, + asect->line_filepos, + SEEK_SET, + (size_t) (LINESZ * + asect->lineno_count)); + lineno_cache = + (alent *) bfd_alloc (abfd, (size_t) ((asect->lineno_count + 1) * sizeof (alent))); + if (lineno_cache == NULL) + return false; + else + { + unsigned int counter = 0; + alent *cache_ptr = lineno_cache; + LINENO *src = native_lineno; + + while (counter < asect->lineno_count) + { + struct internal_lineno dst; + coff_swap_lineno_in (abfd, src, &dst); + cache_ptr->line_number = dst.l_lnno; + + if (cache_ptr->line_number == 0) + { + coff_symbol_type *sym = + (coff_symbol_type *) (dst.l_addr.l_symndx + + obj_raw_syments (abfd))->u.syment._n._n_n._n_zeroes; + cache_ptr->u.sym = (asymbol *) sym; + if (sym->lineno != NULL) + { + (*_bfd_error_handler) + ("%s: warning: duplicate line number information for `%s'", + bfd_get_filename (abfd), + bfd_asymbol_name (&sym->symbol)); + } + sym->lineno = cache_ptr; + } + else + { + cache_ptr->u.offset = dst.l_addr.l_paddr + - bfd_section_vma (abfd, asect); + } /* If no linenumber expect a symbol index */ + + cache_ptr++; + src++; + counter++; + } + cache_ptr->line_number = 0; + + } + asect->lineno = lineno_cache; + /* FIXME, free native_lineno here, or use alloca or something. */ + return true; +} + +static boolean +coff_slurp_symbol_table (abfd) + bfd * abfd; +{ + combined_entry_type *native_symbols; + coff_symbol_type *cached_area; + unsigned int *table_ptr; + + unsigned int number_of_symbols = 0; + + if (obj_symbols (abfd)) + return true; + + /* Read in the symbol table */ + if ((native_symbols = coff_get_normalized_symtab (abfd)) == NULL) + { + return (false); + } /* on error */ + + /* Allocate enough room for all the symbols in cached form */ + cached_area = ((coff_symbol_type *) + bfd_alloc (abfd, + (obj_raw_syment_count (abfd) + * sizeof (coff_symbol_type)))); + + if (cached_area == NULL) + return false; + table_ptr = ((unsigned int *) + bfd_alloc (abfd, + (obj_raw_syment_count (abfd) + * sizeof (unsigned int)))); + + if (table_ptr == NULL) + return false; + else + { + coff_symbol_type *dst = cached_area; + unsigned int last_native_index = obj_raw_syment_count (abfd); + unsigned int this_index = 0; + while (this_index < last_native_index) + { + combined_entry_type *src = native_symbols + this_index; + table_ptr[this_index] = number_of_symbols; + dst->symbol.the_bfd = abfd; + + dst->symbol.name = (char *) (src->u.syment._n._n_n._n_offset); + /* We use the native name field to point to the cached field. */ + src->u.syment._n._n_n._n_zeroes = (long) dst; + dst->symbol.section = coff_section_from_bfd_index (abfd, + src->u.syment.n_scnum); + dst->symbol.flags = 0; + dst->done_lineno = false; + + switch (src->u.syment.n_sclass) + { +#ifdef I960 + case C_LEAFEXT: +#if 0 + dst->symbol.value = src->u.syment.n_value - dst->symbol.section->vma; + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.flags |= BSF_NOT_AT_END | BSF_FUNCTION; +#endif + /* Fall through to next case */ + +#endif + + case C_EXT: +#ifdef RS6000COFF_C + case C_HIDEXT: +#endif +#ifdef COFF_WITH_PE + /* PE uses storage class 0x68 to denote a section symbol */ + case C_SECTION: + /* PE uses storage class 0x67 for a weak external symbol. */ + case C_NT_WEAK: +#endif + if ((src->u.syment.n_scnum) == 0) + { + if ((src->u.syment.n_value) == 0) + { + dst->symbol.section = bfd_und_section_ptr; + dst->symbol.value = 0; + } + else + { + dst->symbol.section = bfd_com_section_ptr; + dst->symbol.value = (src->u.syment.n_value); + } + } + else + { + /* Base the value as an index from the base of the + section */ + + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.value = (src->u.syment.n_value + - dst->symbol.section->vma); + + if (ISFCN ((src->u.syment.n_type))) + { + /* A function ext does not go at the end of a + file. */ + dst->symbol.flags |= BSF_NOT_AT_END | BSF_FUNCTION; + } + } + +#ifdef RS6000COFF_C + /* A C_HIDEXT symbol is not global. */ + if (src->u.syment.n_sclass == C_HIDEXT) + dst->symbol.flags = BSF_LOCAL; + /* A symbol with a csect entry should not go at the end. */ + if (src->u.syment.n_numaux > 0) + dst->symbol.flags |= BSF_NOT_AT_END; +#endif + +#ifdef COFF_WITH_PE + if (src->u.syment.n_sclass == C_NT_WEAK) + dst->symbol.flags = BSF_WEAK; +#endif + + break; + + case C_STAT: /* static */ +#ifdef I960 + case C_LEAFSTAT: /* static leaf procedure */ +#endif + case C_LABEL: /* label */ + if (src->u.syment.n_scnum == -2) + dst->symbol.flags = BSF_DEBUGGING; + else + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section, if + there is one + */ + if (dst->symbol.section) + dst->symbol.value = (src->u.syment.n_value) - + dst->symbol.section->vma; + else + dst->symbol.value = (src->u.syment.n_value); + break; + + case C_MOS: /* member of structure */ + case C_EOS: /* end of structure */ +#ifdef NOTDEF /* C_AUTOARG has the same value */ +#ifdef C_GLBLREG + case C_GLBLREG: /* A29k-specific storage class */ +#endif +#endif + case C_REGPARM: /* register parameter */ + case C_REG: /* register variable */ +#ifdef C_AUTOARG + case C_AUTOARG: /* 960-specific storage class */ +#endif + case C_TPDEF: /* type definition */ + case C_ARG: + case C_AUTO: /* automatic variable */ + case C_FIELD: /* bit field */ + case C_ENTAG: /* enumeration tag */ + case C_MOE: /* member of enumeration */ + case C_MOU: /* member of union */ + case C_UNTAG: /* union tag */ + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + + case C_FILE: /* file name */ + case C_STRTAG: /* structure tag */ +#ifdef RS6000COFF_C + case C_GSYM: + case C_LSYM: + case C_PSYM: + case C_RSYM: + case C_RPSYM: + case C_STSYM: + case C_BCOMM: + case C_ECOMM: + case C_DECL: + case C_ENTRY: + case C_FUN: + case C_ESTAT: +#endif + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + +#ifdef RS6000COFF_C + case C_BINCL: /* beginning of include file */ + case C_EINCL: /* ending of include file */ + /* The value is actually a pointer into the line numbers + of the file. We locate the line number entry, and + set the section to the section which contains it, and + the value to the index in that section. */ + { + asection *sec; + + dst->symbol.flags = BSF_DEBUGGING; + for (sec = abfd->sections; sec != NULL; sec = sec->next) + if (sec->line_filepos <= (file_ptr) src->u.syment.n_value + && ((file_ptr) (sec->line_filepos + + sec->lineno_count * LINESZ) + > (file_ptr) src->u.syment.n_value)) + break; + if (sec == NULL) + dst->symbol.value = 0; + else + { + dst->symbol.section = sec; + dst->symbol.value = ((src->u.syment.n_value + - sec->line_filepos) + / LINESZ); + src->fix_line = 1; + } + } + break; + + case C_BSTAT: + dst->symbol.flags = BSF_DEBUGGING; + + /* The value is actually a symbol index. Save a pointer + to the symbol instead of the index. FIXME: This + should use a union. */ + src->u.syment.n_value = + (long) (native_symbols + src->u.syment.n_value); + dst->symbol.value = src->u.syment.n_value; + src->fix_value = 1; + break; +#endif + + case C_BLOCK: /* ".bb" or ".eb" */ + case C_FCN: /* ".bf" or ".ef" */ + case C_EFCN: /* physical end of function */ + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section + */ + dst->symbol.value = (src->u.syment.n_value) - dst->symbol.section->vma; + break; + + case C_NULL: + case C_EXTDEF: /* external definition */ + case C_ULABEL: /* undefined label */ + case C_USTATIC: /* undefined static */ +#ifndef COFF_WITH_PE + /* C_LINE in regular coff is 0x68. NT has taken over this storage + class to represent a section symbol */ + case C_LINE: /* line # reformatted as symbol table entry */ + /* NT uses 0x67 for a weak symbol, not C_ALIAS. */ + case C_ALIAS: /* duplicate tag */ +#endif + case C_HIDDEN: /* ext symbol in dmert public lib */ + default: + (*_bfd_error_handler) + ("%s: Unrecognized storage class %d for %s symbol `%s'", + bfd_get_filename (abfd), src->u.syment.n_sclass, + dst->symbol.section->name, dst->symbol.name); + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + } + +/* BFD_ASSERT(dst->symbol.flags != 0);*/ + + dst->native = src; + + dst->symbol.udata.i = 0; + dst->lineno = (alent *) NULL; + this_index += (src->u.syment.n_numaux) + 1; + dst++; + number_of_symbols++; + } /* walk the native symtab */ + } /* bfdize the native symtab */ + + obj_symbols (abfd) = cached_area; + obj_raw_syments (abfd) = native_symbols; + + bfd_get_symcount (abfd) = number_of_symbols; + obj_convert (abfd) = table_ptr; + /* Slurp the line tables for each section too */ + { + asection *p; + p = abfd->sections; + while (p) + { + coff_slurp_line_table (abfd, p); + p = p->next; + } + } + return true; +} /* coff_slurp_symbol_table() */ + +/* Check whether a symbol is globally visible. This is used by the + COFF backend linker code in cofflink.c, since a couple of targets + have globally visible symbols which are not class C_EXT. This + function need not handle the case of n_class == C_EXT. */ + +#undef OTHER_GLOBAL_CLASS + +#ifdef I960 +#define OTHER_GLOBAL_CLASS C_LEAFEXT +#endif + +#ifdef COFF_WITH_PE +#define OTHER_GLOBAL_CLASS C_SECTION +#endif + +#ifdef OTHER_GLOBAL_CLASS + +static boolean +coff_sym_is_global (abfd, syment) + bfd *abfd; + struct internal_syment *syment; +{ + if (syment->n_sclass == OTHER_GLOBAL_CLASS) + return true; + return false; +} + +#undef OTHER_GLOBAL_CLASS + +#else /* ! defined (OTHER_GLOBAL_CLASS) */ + +/* sym_is_global should not be defined if it has nothing to do. */ + +#define coff_sym_is_global 0 + +#endif /* ! defined (OTHER_GLOBAL_CLASS) */ + +/* +SUBSUBSECTION + Reading relocations + + Coff relocations are easily transformed into the internal BFD form + (@code{arelent}). + + Reading a coff relocation table is done in the following stages: + + o Read the entire coff relocation table into memory. + + o Process each relocation in turn; first swap it from the + external to the internal form. + + o Turn the symbol referenced in the relocation's symbol index + into a pointer into the canonical symbol table. + This table is the same as the one returned by a call to + @code{bfd_canonicalize_symtab}. The back end will call that + routine and save the result if a canonicalization hasn't been done. + + o The reloc index is turned into a pointer to a howto + structure, in a back end specific way. For instance, the 386 + and 960 use the @code{r_type} to directly produce an index + into a howto table vector; the 88k subtracts a number from the + @code{r_type} field and creates an addend field. + + +*/ + +#ifndef CALC_ADDEND +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = 0; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + } +#endif + +static boolean +coff_slurp_reloc_table (abfd, asect, symbols) + bfd * abfd; + sec_ptr asect; + asymbol ** symbols; +{ + RELOC *native_relocs; + arelent *reloc_cache; + arelent *cache_ptr; + + unsigned int idx; + + if (asect->relocation) + return true; + if (asect->reloc_count == 0) + return true; + if (asect->flags & SEC_CONSTRUCTOR) + return true; + if (!coff_slurp_symbol_table (abfd)) + return false; + native_relocs = + (RELOC *) buy_and_read (abfd, + asect->rel_filepos, + SEEK_SET, + (size_t) (RELSZ * + asect->reloc_count)); + reloc_cache = (arelent *) + bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent))); + + if (reloc_cache == NULL) + return false; + + + for (idx = 0; idx < asect->reloc_count; idx++) + { +#ifdef RELOC_PROCESSING + struct internal_reloc dst; + struct external_reloc *src; + + cache_ptr = reloc_cache + idx; + src = native_relocs + idx; + coff_swap_reloc_in (abfd, src, &dst); + + RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect); +#else + struct internal_reloc dst; + asymbol *ptr; + struct external_reloc *src; + + cache_ptr = reloc_cache + idx; + src = native_relocs + idx; + + coff_swap_reloc_in (abfd, src, &dst); + + + cache_ptr->address = dst.r_vaddr; + + if (dst.r_symndx != -1) + { + /* @@ Should never be greater than count of symbols! */ + if (dst.r_symndx >= obj_conv_table_size (abfd)) + abort (); + cache_ptr->sym_ptr_ptr = symbols + obj_convert (abfd)[dst.r_symndx]; + ptr = *(cache_ptr->sym_ptr_ptr); + } + else + { + cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + ptr = 0; + } + + /* The symbols definitions that we have read in have been + relocated as if their sections started at 0. But the offsets + refering to the symbols in the raw data have not been + modified, so we have to have a negative addend to compensate. + + Note that symbols which used to be common must be left alone */ + + /* Calculate any reloc addend by looking at the symbol */ + CALC_ADDEND (abfd, ptr, dst, cache_ptr); + + cache_ptr->address -= asect->vma; +/* !! cache_ptr->section = (asection *) NULL;*/ + + /* Fill in the cache_ptr->howto field from dst.r_type */ + RTYPE2HOWTO (cache_ptr, &dst); +#endif + + } + + asect->relocation = reloc_cache; + return true; +} + +#ifndef coff_rtype_to_howto +#ifdef RTYPE2HOWTO + +/* Get the howto structure for a reloc. This is only used if the file + including this one defines coff_relocate_section to be + _bfd_coff_generic_relocate_section, so it is OK if it does not + always work. It is the responsibility of the including file to + make sure it is reasonable if it is needed. */ + +static reloc_howto_type *coff_rtype_to_howto + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *)); + +/*ARGSUSED*/ +static reloc_howto_type * +coff_rtype_to_howto (abfd, sec, rel, h, sym, addendp) + bfd *abfd; + asection *sec; + struct internal_reloc *rel; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma *addendp; +{ + arelent genrel; + + RTYPE2HOWTO (&genrel, rel); + return genrel.howto; +} + +#else /* ! defined (RTYPE2HOWTO) */ + +#define coff_rtype_to_howto NULL + +#endif /* ! defined (RTYPE2HOWTO) */ +#endif /* ! defined (coff_rtype_to_howto) */ + +/* This is stupid. This function should be a boolean predicate. */ +static long +coff_canonicalize_reloc (abfd, section, relptr, symbols) + bfd * abfd; + sec_ptr section; + arelent ** relptr; + asymbol ** symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count = 0; + + + if (section->flags & SEC_CONSTRUCTOR) + { + /* this section has relocs made up by us, they are not in the + file, so take them out of their chain and place them into + the data area provided */ + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = &chain->relent; + chain = chain->next; + } + + } + else + { + if (! coff_slurp_reloc_table (abfd, section, symbols)) + return -1; + + tblptr = section->relocation; + + for (; count++ < section->reloc_count;) + *relptr++ = tblptr++; + + + } + *relptr = 0; + return section->reloc_count; +} + +#ifdef GNU960 +file_ptr +coff_sym_filepos (abfd) + bfd *abfd; +{ + return obj_sym_filepos (abfd); +} +#endif + +#ifndef coff_reloc16_estimate +#define coff_reloc16_estimate dummy_reloc16_estimate + +static int +dummy_reloc16_estimate (abfd, input_section, reloc, shrink, link_info) + bfd *abfd; + asection *input_section; + arelent *reloc; + unsigned int shrink; + struct bfd_link_info *link_info; +{ + abort (); +} + +#endif + +#ifndef coff_reloc16_extra_cases +#define coff_reloc16_extra_cases dummy_reloc16_extra_cases +/* This works even if abort is not declared in any header file. */ +static void +dummy_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr, + dst_ptr) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + abort (); +} +#endif + +/* If coff_relocate_section is defined, we can use the optimized COFF + backend linker. Otherwise we must continue to use the old linker. */ +#ifdef coff_relocate_section +#ifndef coff_bfd_link_hash_table_create +#define coff_bfd_link_hash_table_create _bfd_coff_link_hash_table_create +#endif +#ifndef coff_bfd_link_add_symbols +#define coff_bfd_link_add_symbols _bfd_coff_link_add_symbols +#endif +#ifndef coff_bfd_final_link +#define coff_bfd_final_link _bfd_coff_final_link +#endif +#else /* ! defined (coff_relocate_section) */ +#define coff_relocate_section NULL +#define coff_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#ifndef coff_bfd_link_add_symbols +#define coff_bfd_link_add_symbols _bfd_generic_link_add_symbols +#endif +#define coff_bfd_final_link _bfd_generic_final_link +#endif /* ! defined (coff_relocate_section) */ +#define coff_bfd_link_split_section _bfd_generic_link_split_section + +#ifndef coff_start_final_link +#define coff_start_final_link NULL +#endif + +#ifndef coff_adjust_symndx +#define coff_adjust_symndx NULL +#endif + +#ifndef coff_link_add_one_symbol +#define coff_link_add_one_symbol _bfd_generic_link_add_one_symbol +#endif + +static CONST bfd_coff_backend_data bfd_coff_std_swap_table = +{ + coff_swap_aux_in, coff_swap_sym_in, coff_swap_lineno_in, + coff_swap_aux_out, coff_swap_sym_out, + coff_swap_lineno_out, coff_swap_reloc_out, + coff_swap_filehdr_out, coff_swap_aouthdr_out, + coff_swap_scnhdr_out, + FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, RELSZ, LINESZ, +#ifdef COFF_LONG_FILENAMES + true, +#else + false, +#endif + coff_swap_filehdr_in, coff_swap_aouthdr_in, coff_swap_scnhdr_in, + coff_swap_reloc_in, coff_bad_format_hook, coff_set_arch_mach_hook, + coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook, + coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook, + coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, + coff_sym_is_global, coff_compute_section_file_positions, + coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, + coff_adjust_symndx, coff_link_add_one_symbol +}; + +#define coff_close_and_cleanup _bfd_generic_close_and_cleanup +#define coff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define coff_get_section_contents _bfd_generic_get_section_contents + +#ifndef coff_bfd_copy_private_symbol_data +#define coff_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data +#endif + +#ifndef coff_bfd_copy_private_section_data +#define coff_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data +#endif + +#ifndef coff_bfd_copy_private_bfd_data +#define coff_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data +#endif + +#define coff_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data +#define coff_bfd_set_private_flags _bfd_generic_bfd_set_private_flags + +#ifndef coff_bfd_print_private_bfd_data +#define coff_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data +#endif + +#ifndef coff_bfd_is_local_label +#define coff_bfd_is_local_label bfd_generic_is_local_label +#endif +#ifndef coff_read_minisymbols +#define coff_read_minisymbols _bfd_generic_read_minisymbols +#endif +#ifndef coff_minisymbol_to_symbol +#define coff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +#endif + +/* The reloc lookup routine must be supplied by each individual COFF + backend. */ +#ifndef coff_bfd_reloc_type_lookup +#define coff_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup +#endif + +#ifndef coff_bfd_get_relocated_section_contents +#define coff_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#endif +#ifndef coff_bfd_relax_section +#define coff_bfd_relax_section bfd_generic_relax_section +#endif diff --git a/contrib/gdb/bfd/coffgen.c b/contrib/gdb/bfd/coffgen.c new file mode 100644 index 000000000000..285fe61ccc53 --- /dev/null +++ b/contrib/gdb/bfd/coffgen.c @@ -0,0 +1,2121 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. + Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ + +/* This file contains COFF code that is not dependent on any + particular COFF target. There is only one version of this file in + libbfd.a, so no target specific code may be put in here. Or, to + put it another way, + + ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** + + If you need to add some target specific behaviour, add a new hook + function to bfd_coff_backend_data. + + Some of these functions are also called by the ECOFF routines. + Those functions may not use any COFF specific information, such as + coff_data (abfd). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +static void coff_fix_symbol_name + PARAMS ((bfd *, asymbol *, combined_entry_type *, bfd_size_type *, + asection **, bfd_size_type *)); +static boolean coff_write_symbol + PARAMS ((bfd *, asymbol *, combined_entry_type *, unsigned int *, + bfd_size_type *, asection **, bfd_size_type *)); +static boolean coff_write_alien_symbol + PARAMS ((bfd *, asymbol *, unsigned int *, bfd_size_type *, + asection **, bfd_size_type *)); +static boolean coff_write_native_symbol + PARAMS ((bfd *, coff_symbol_type *, unsigned int *, bfd_size_type *, + asection **, bfd_size_type *)); +static void coff_pointerize_aux + PARAMS ((bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *)); + +#define STRING_SIZE_SIZE (4) + +/* Take a section header read from a coff file (in HOST byte order), + and make a BFD "section" out of it. This is used by ECOFF. */ +static boolean +make_a_section_from_file (abfd, hdr, target_index) + bfd *abfd; + struct internal_scnhdr *hdr; + unsigned int target_index; +{ + asection *return_section; + char *name; + + /* Assorted wastage to null-terminate the name, thanks AT&T! */ + name = bfd_alloc (abfd, sizeof (hdr->s_name) + 1); + if (name == NULL) + return false; + strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); + name[sizeof (hdr->s_name)] = 0; + + return_section = bfd_make_section_anyway (abfd, name); + if (return_section == NULL) + return false; + + return_section->vma = hdr->s_vaddr; + return_section->lma = hdr->s_paddr; + return_section->_raw_size = hdr->s_size; + return_section->filepos = hdr->s_scnptr; + return_section->rel_filepos = hdr->s_relptr; + return_section->reloc_count = hdr->s_nreloc; + + bfd_coff_set_alignment_hook (abfd, return_section, hdr); + + return_section->line_filepos = hdr->s_lnnoptr; + + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name); + + return_section->target_index = target_index; + + /* At least on i386-coff, the line number count for a shared library + section must be ignored. */ + if ((return_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) + return_section->lineno_count = 0; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + /* FIXME: should this check 'hdr->s_size > 0' */ + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + return true; +} + +/* Read in a COFF object and make it into a BFD. This is used by + ECOFF as well. */ + +static const bfd_target * +coff_real_object_p (abfd, nscns, internal_f, internal_a) + bfd *abfd; + unsigned nscns; + struct internal_filehdr *internal_f; + struct internal_aouthdr *internal_a; +{ + flagword oflags = abfd->flags; + bfd_vma ostart = bfd_get_start_address (abfd); + PTR tdata; + size_t readsize; /* length of file_info */ + unsigned int scnhsz; + char *external_sections; + + if (!(internal_f->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((internal_f->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(internal_f->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(internal_f->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + /* FIXME: How can we set D_PAGED correctly? */ + if ((internal_f->f_flags & F_EXEC) != 0) + abfd->flags |= D_PAGED; + + bfd_get_symcount (abfd) = internal_f->f_nsyms; + if (internal_f->f_nsyms) + abfd->flags |= HAS_SYMS; + + if (internal_a != (struct internal_aouthdr *) NULL) + bfd_get_start_address (abfd) = internal_a->entry; + else + bfd_get_start_address (abfd) = 0; + + /* Set up the tdata area. ECOFF uses its own routine, and overrides + abfd->flags. */ + tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a); + if (tdata == NULL) + return 0; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = nscns * scnhsz; + external_sections = (char *) bfd_alloc (abfd, readsize); + if (!external_sections) + goto fail; + + if (bfd_read ((PTR) external_sections, 1, readsize, abfd) != readsize) + goto fail; + + /* Now copy data as required; construct all asections etc */ + if (nscns != 0) + { + unsigned int i; + for (i = 0; i < nscns; i++) + { + struct internal_scnhdr tmp; + bfd_coff_swap_scnhdr_in (abfd, + (PTR) (external_sections + i * scnhsz), + (PTR) & tmp); + make_a_section_from_file (abfd, &tmp, i + 1); + } + } + + /* make_abs_section (abfd); */ + + if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false) + goto fail; + + return abfd->xvec; + + fail: + bfd_release (abfd, tdata); + abfd->flags = oflags; + bfd_get_start_address (abfd) = ostart; + return (const bfd_target *) NULL; +} + +/* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is + not a COFF file. This is also used by ECOFF. */ + +const bfd_target * +coff_object_p (abfd) + bfd *abfd; +{ + unsigned int filhsz; + unsigned int aoutsz; + int nscns; + PTR filehdr; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + /* figure out how much to read */ + filhsz = bfd_coff_filhsz (abfd); + aoutsz = bfd_coff_aoutsz (abfd); + + filehdr = bfd_alloc (abfd, filhsz); + if (filehdr == NULL) + return 0; + if (bfd_read (filehdr, 1, filhsz, abfd) != filhsz) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + bfd_coff_swap_filehdr_in (abfd, filehdr, &internal_f); + bfd_release (abfd, filehdr); + + if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + nscns = internal_f.f_nscns; + + if (internal_f.f_opthdr) + { + PTR opthdr; + + opthdr = bfd_alloc (abfd, aoutsz); + if (opthdr == NULL) + return 0;; + if (bfd_read (opthdr, 1, aoutsz, abfd) != aoutsz) + { + return 0; + } + bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) & internal_a); + } + + /* Seek past the opt hdr stuff */ + if (bfd_seek (abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET) + != 0) + return NULL; + + return coff_real_object_p (abfd, nscns, &internal_f, + (internal_f.f_opthdr != 0 + ? &internal_a + : (struct internal_aouthdr *) NULL)); +} + +/* Get the BFD section from a COFF symbol section number. */ + +asection * +coff_section_from_bfd_index (abfd, index) + bfd *abfd; + int index; +{ + struct sec *answer = abfd->sections; + + if (index == N_ABS) + return bfd_abs_section_ptr; + if (index == N_UNDEF) + return bfd_und_section_ptr; + if (index == N_DEBUG) + return bfd_abs_section_ptr; + + while (answer) + { + if (answer->target_index == index) + return answer; + answer = answer->next; + } + + /* We should not reach this point, but the SCO 3.2v4 /lib/libc_s.a + has a bad symbol table in biglitpow.o. */ + return bfd_und_section_ptr; +} + +/* Get the upper bound of a COFF symbol table. */ + +long +coff_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (!bfd_coff_slurp_symbol_table (abfd)) + return -1; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (coff_symbol_type *)); +} + + +/* Canonicalize a COFF symbol table. */ + +long +coff_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) alocation; + + if (!bfd_coff_slurp_symbol_table (abfd)) + return -1; + + symbase = obj_symbols (abfd); + counter = bfd_get_symcount (abfd); + while (counter-- > 0) + *location++ = symbase++; + + *location = NULL; + + return bfd_get_symcount (abfd); +} + +/* Get the name of a symbol. The caller must pass in a buffer of size + >= SYMNMLEN + 1. */ + +const char * +_bfd_coff_internal_syment_name (abfd, sym, buf) + bfd *abfd; + const struct internal_syment *sym; + char *buf; +{ + /* FIXME: It's not clear this will work correctly if sizeof + (_n_zeroes) != 4. */ + if (sym->_n._n_n._n_zeroes != 0 + || sym->_n._n_n._n_offset == 0) + { + memcpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + return buf; + } + else + { + const char *strings; + + BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE); + strings = obj_coff_strings (abfd); + if (strings == NULL) + { + strings = _bfd_coff_read_string_table (abfd); + if (strings == NULL) + return NULL; + } + return strings + sym->_n._n_n._n_offset; + } +} + +/* Read in and swap the relocs. This returns a buffer holding the + relocs for section SEC in file ABFD. If CACHE is true and + INTERNAL_RELOCS is NULL, the relocs read in will be saved in case + the function is called again. If EXTERNAL_RELOCS is not NULL, it + is a buffer large enough to hold the unswapped relocs. If + INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold + the swapped relocs. If REQUIRE_INTERNAL is true, then the return + value must be INTERNAL_RELOCS. The function returns NULL on error. */ + +struct internal_reloc * +_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs, + require_internal, internal_relocs) + bfd *abfd; + asection *sec; + boolean cache; + bfd_byte *external_relocs; + boolean require_internal; + struct internal_reloc *internal_relocs; +{ + bfd_size_type relsz; + bfd_byte *free_external = NULL; + struct internal_reloc *free_internal = NULL; + bfd_byte *erel; + bfd_byte *erel_end; + struct internal_reloc *irel; + + if (coff_section_data (abfd, sec) != NULL + && coff_section_data (abfd, sec)->relocs != NULL) + { + if (! require_internal) + return coff_section_data (abfd, sec)->relocs; + memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs, + sec->reloc_count * sizeof (struct internal_reloc)); + return internal_relocs; + } + + relsz = bfd_coff_relsz (abfd); + + if (external_relocs == NULL) + { + free_external = (bfd_byte *) bfd_malloc (sec->reloc_count * relsz); + if (free_external == NULL && sec->reloc_count > 0) + goto error_return; + external_relocs = free_external; + } + + if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 + || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd) + != relsz * sec->reloc_count)) + goto error_return; + + if (internal_relocs == NULL) + { + free_internal = ((struct internal_reloc *) + bfd_malloc (sec->reloc_count + * sizeof (struct internal_reloc))); + if (free_internal == NULL && sec->reloc_count > 0) + goto error_return; + internal_relocs = free_internal; + } + + /* Swap in the relocs. */ + erel = external_relocs; + erel_end = erel + relsz * sec->reloc_count; + irel = internal_relocs; + for (; erel < erel_end; erel += relsz, irel++) + bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel); + + if (free_external != NULL) + { + free (free_external); + free_external = NULL; + } + + if (cache && free_internal != NULL) + { + if (coff_section_data (abfd, sec) == NULL) + { + sec->used_by_bfd = + (PTR) bfd_zalloc (abfd, + sizeof (struct coff_section_tdata)); + if (sec->used_by_bfd == NULL) + goto error_return; + coff_section_data (abfd, sec)->contents = NULL; + } + coff_section_data (abfd, sec)->relocs = free_internal; + } + + return internal_relocs; + + error_return: + if (free_external != NULL) + free (free_external); + if (free_internal != NULL) + free (free_internal); + return NULL; +} + +/* Set lineno_count for the output sections of a COFF file. */ + +int +coff_count_linenumbers (abfd) + bfd *abfd; +{ + unsigned int limit = bfd_get_symcount (abfd); + unsigned int i; + int total = 0; + asymbol **p; + asection *s; + + if (limit == 0) + { + /* This may be from the backend linker, in which case the + lineno_count in the sections is correct. */ + for (s = abfd->sections; s != NULL; s = s->next) + total += s->lineno_count; + return total; + } + + for (s = abfd->sections; s != NULL; s = s->next) + BFD_ASSERT (s->lineno_count == 0); + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *q_maybe = *p; + + if (bfd_asymbol_flavour (q_maybe) == bfd_target_coff_flavour) + { + coff_symbol_type *q = coffsymbol (q_maybe); + + /* The AIX 4.1 compiler can sometimes generate line numbers + attached to debugging symbols. We try to simply ignore + those here. */ + if (q->lineno != NULL + && q->symbol.section->owner != NULL) + { + /* This symbol has line numbers. Increment the owning + section's linenumber count. */ + alent *l = q->lineno; + + ++q->symbol.section->output_section->lineno_count; + ++total; + ++l; + while (l->line_number != 0) + { + ++total; + ++q->symbol.section->output_section->lineno_count; + ++l; + } + } + } + } + + return total; +} + +/* Takes a bfd and a symbol, returns a pointer to the coff specific + area of the symbol if there is one. */ + +/*ARGSUSED*/ +coff_symbol_type * +coff_symbol_from (ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + if (bfd_asymbol_flavour (symbol) != bfd_target_coff_flavour) + return (coff_symbol_type *) NULL; + + if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) + return (coff_symbol_type *) NULL; + + return (coff_symbol_type *) symbol; +} + +static void +fixup_symbol_value (coff_symbol_ptr, syment) + coff_symbol_type *coff_symbol_ptr; + struct internal_syment *syment; +{ + + /* Normalize the symbol flags */ + if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) + { + /* a common symbol is undefined with a value */ + syment->n_scnum = N_UNDEF; + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) + { + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (bfd_is_und_section (coff_symbol_ptr->symbol.section)) + { + syment->n_scnum = N_UNDEF; + syment->n_value = 0; + } + else + { + if (coff_symbol_ptr->symbol.section) + { + syment->n_scnum = + coff_symbol_ptr->symbol.section->output_section->target_index; + + syment->n_value = + coff_symbol_ptr->symbol.value + + coff_symbol_ptr->symbol.section->output_offset + + coff_symbol_ptr->symbol.section->output_section->vma; + } + else + { + BFD_ASSERT (0); + /* This can happen, but I don't know why yet (steve@cygnus.com) */ + syment->n_scnum = N_ABS; + syment->n_value = coff_symbol_ptr->symbol.value; + } + } +} + +/* Run through all the symbols in the symbol table and work out what + their indexes into the symbol table will be when output. + + Coff requires that each C_FILE symbol points to the next one in the + chain, and that the last one points to the first external symbol. We + do that here too. */ + +boolean +coff_renumber_symbols (bfd_ptr, first_undef) + bfd *bfd_ptr; + int *first_undef; +{ + unsigned int symbol_count = bfd_get_symcount (bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int native_index = 0; + struct internal_syment *last_file = (struct internal_syment *) NULL; + unsigned int symbol_index; + + /* COFF demands that undefined symbols come after all other symbols. + Since we don't need to impose this extra knowledge on all our + client programs, deal with that here. Sort the symbol table; + just move the undefined symbols to the end, leaving the rest + alone. The O'Reilly book says that defined global symbols come + at the end before the undefined symbols, so we do that here as + well. */ + /* @@ Do we have some condition we could test for, so we don't always + have to do this? I don't think relocatability is quite right, but + I'm not certain. [raeburn:19920508.1711EST] */ + { + asymbol **newsyms; + unsigned int i; + + newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr, + sizeof (asymbol *) + * (symbol_count + 1)); + if (!newsyms) + return false; + bfd_ptr->outsymbols = newsyms; + for (i = 0; i < symbol_count; i++) + if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0 + || (!bfd_is_und_section (symbol_ptr_ptr[i]->section) + && !bfd_is_com_section (symbol_ptr_ptr[i]->section) + && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_FUNCTION)) + != BSF_GLOBAL))) + *newsyms++ = symbol_ptr_ptr[i]; + + for (i = 0; i < symbol_count; i++) + if (!bfd_is_und_section (symbol_ptr_ptr[i]->section) + && (bfd_is_com_section (symbol_ptr_ptr[i]->section) + || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL + | BSF_NOT_AT_END + | BSF_FUNCTION)) + == BSF_GLOBAL))) + *newsyms++ = symbol_ptr_ptr[i]; + + *first_undef = newsyms - bfd_ptr->outsymbols; + + for (i = 0; i < symbol_count; i++) + if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 + && bfd_is_und_section (symbol_ptr_ptr[i]->section)) + *newsyms++ = symbol_ptr_ptr[i]; + *newsyms = (asymbol *) NULL; + symbol_ptr_ptr = bfd_ptr->outsymbols; + } + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; + if (coff_symbol_ptr && coff_symbol_ptr->native) + { + combined_entry_type *s = coff_symbol_ptr->native; + int i; + + if (s->u.syment.n_sclass == C_FILE) + { + if (last_file != (struct internal_syment *) NULL) + last_file->n_value = native_index; + last_file = &(s->u.syment); + } + else + { + + /* Modify the symbol values according to their section and + type */ + + fixup_symbol_value (coff_symbol_ptr, &(s->u.syment)); + } + for (i = 0; i < s->u.syment.n_numaux + 1; i++) + s[i].offset = native_index++; + } + else + { + native_index++; + } + } + obj_conv_table_size (bfd_ptr) = native_index; + + return true; +} + +/* Run thorough the symbol table again, and fix it so that all + pointers to entries are changed to the entries' index in the output + symbol table. */ + +void +coff_mangle_symbols (bfd_ptr) + bfd *bfd_ptr; +{ + unsigned int symbol_count = bfd_get_symcount (bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int symbol_index; + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = + coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + + if (coff_symbol_ptr && coff_symbol_ptr->native) + { + int i; + combined_entry_type *s = coff_symbol_ptr->native; + + if (s->fix_value) + { + /* FIXME: We should use a union here. */ + s->u.syment.n_value = + ((combined_entry_type *) s->u.syment.n_value)->offset; + s->fix_value = 0; + } + if (s->fix_line) + { + /* The value is the offset into the line number entries + for the symbol's section. On output, the symbol's + section should be N_DEBUG. */ + s->u.syment.n_value = + (coff_symbol_ptr->symbol.section->output_section->line_filepos + + s->u.syment.n_value * bfd_coff_linesz (bfd_ptr)); + coff_symbol_ptr->symbol.section = + coff_section_from_bfd_index (bfd_ptr, N_DEBUG); + BFD_ASSERT (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING); + } + for (i = 0; i < s->u.syment.n_numaux; i++) + { + combined_entry_type *a = s + i + 1; + if (a->fix_tag) + { + a->u.auxent.x_sym.x_tagndx.l = + a->u.auxent.x_sym.x_tagndx.p->offset; + a->fix_tag = 0; + } + if (a->fix_end) + { + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; + a->fix_end = 0; + } + if (a->fix_scnlen) + { + a->u.auxent.x_csect.x_scnlen.l = + a->u.auxent.x_csect.x_scnlen.p->offset; + a->fix_scnlen = 0; + } + } + } + } +} + +static void +coff_fix_symbol_name (abfd, symbol, native, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + combined_entry_type *native; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + unsigned int name_length; + union internal_auxent *auxent; + char *name = (char *) (symbol->name); + + if (name == (char *) NULL) + { + /* coff symbols always have names, so we'll make one up */ + symbol->name = "strange"; + name = (char *) symbol->name; + } + name_length = strlen (name); + + if (native->u.syment.n_sclass == C_FILE + && native->u.syment.n_numaux > 0) + { + strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); + auxent = &(native + 1)->u.auxent; + + if (bfd_coff_long_filenames (abfd)) + { + if (name_length <= FILNMLEN) + { + strncpy (auxent->x_file.x_fname, name, FILNMLEN); + } + else + { + auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE; + auxent->x_file.x_n.x_zeroes = 0; + *string_size_p += name_length + 1; + } + } + else + { + strncpy (auxent->x_file.x_fname, name, FILNMLEN); + if (name_length > FILNMLEN) + { + name[FILNMLEN] = '\0'; + } + } + } + else + { + if (name_length <= SYMNMLEN) + { + /* This name will fit into the symbol neatly */ + strncpy (native->u.syment._n._n_name, symbol->name, SYMNMLEN); + } + else if (!bfd_coff_symname_in_debug (abfd, &native->u.syment)) + { + native->u.syment._n._n_n._n_offset = (*string_size_p + + STRING_SIZE_SIZE); + native->u.syment._n._n_n._n_zeroes = 0; + *string_size_p += name_length + 1; + } + else + { + long filepos; + bfd_byte buf[2]; + + /* This name should be written into the .debug section. For + some reason each name is preceded by a two byte length + and also followed by a null byte. FIXME: We assume that + the .debug section has already been created, and that it + is large enough. */ + if (*debug_string_section_p == (asection *) NULL) + *debug_string_section_p = bfd_get_section_by_name (abfd, ".debug"); + filepos = bfd_tell (abfd); + bfd_put_16 (abfd, name_length + 1, buf); + if (!bfd_set_section_contents (abfd, + *debug_string_section_p, + (PTR) buf, + (file_ptr) *debug_string_size_p, + (bfd_size_type) 2) + || !bfd_set_section_contents (abfd, + *debug_string_section_p, + (PTR) symbol->name, + ((file_ptr) *debug_string_size_p + + 2), + (bfd_size_type) name_length + 1)) + abort (); + if (bfd_seek (abfd, filepos, SEEK_SET) != 0) + abort (); + native->u.syment._n._n_n._n_offset = *debug_string_size_p + 2; + native->u.syment._n._n_n._n_zeroes = 0; + *debug_string_size_p += name_length + 3; + } + } +} + +/* We need to keep track of the symbol index so that when we write out + the relocs we can get the index for a symbol. This method is a + hack. FIXME. */ + +#define set_index(symbol, idx) ((symbol)->udata.i = (idx)) + +/* Write a symbol out to a COFF file. */ + +static boolean +coff_write_symbol (abfd, symbol, native, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + combined_entry_type *native; + unsigned int *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + unsigned int numaux = native->u.syment.n_numaux; + int type = native->u.syment.n_type; + int class = native->u.syment.n_sclass; + PTR buf; + bfd_size_type symesz; + + if (native->u.syment.n_sclass == C_FILE) + symbol->flags |= BSF_DEBUGGING; + + if (symbol->flags & BSF_DEBUGGING + && bfd_is_abs_section (symbol->section)) + { + native->u.syment.n_scnum = N_DEBUG; + } + else if (bfd_is_abs_section (symbol->section)) + { + native->u.syment.n_scnum = N_ABS; + } + else if (bfd_is_und_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + } + + coff_fix_symbol_name (abfd, symbol, native, string_size_p, + debug_string_section_p, debug_string_size_p); + + symesz = bfd_coff_symesz (abfd); + buf = bfd_alloc (abfd, symesz); + if (!buf) + return false; + bfd_coff_swap_sym_out (abfd, &native->u.syment, buf); + if (bfd_write (buf, 1, symesz, abfd) != symesz) + return false; + bfd_release (abfd, buf); + + if (native->u.syment.n_numaux > 0) + { + bfd_size_type auxesz; + unsigned int j; + + auxesz = bfd_coff_auxesz (abfd); + buf = bfd_alloc (abfd, auxesz); + if (!buf) + return false; + for (j = 0; j < native->u.syment.n_numaux; j++) + { + bfd_coff_swap_aux_out (abfd, + &((native + j + 1)->u.auxent), + type, + class, + j, + native->u.syment.n_numaux, + buf); + if (bfd_write (buf, 1, auxesz, abfd) != auxesz) + return false; + } + bfd_release (abfd, buf); + } + + /* Store the index for use when we write out the relocs. */ + set_index (symbol, *written); + + *written += numaux + 1; + return true; +} + +/* Write out a symbol to a COFF file that does not come from a COFF + file originally. This symbol may have been created by the linker, + or we may be linking a non COFF file to a COFF file. */ + +static boolean +coff_write_alien_symbol (abfd, symbol, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + unsigned int *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + combined_entry_type *native; + combined_entry_type dummy; + + native = &dummy; + native->u.syment.n_type = T_NULL; + native->u.syment.n_flags = 0; + if (bfd_is_und_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (bfd_is_com_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (symbol->flags & BSF_DEBUGGING) + { + /* There isn't much point to writing out a debugging symbol + unless we are prepared to convert it into COFF debugging + format. So, we just ignore them. We must clobber the symbol + name to keep it from being put in the string table. */ + symbol->name = ""; + return true; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + native->u.syment.n_value = (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset); + + /* Copy the any flags from the the file header into the symbol. + FIXME: Why? */ + { + coff_symbol_type *c = coff_symbol_from (abfd, symbol); + if (c != (coff_symbol_type *) NULL) + native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; + } + } + + native->u.syment.n_type = 0; + if (symbol->flags & BSF_LOCAL) + native->u.syment.n_sclass = C_STAT; + else + native->u.syment.n_sclass = C_EXT; + native->u.syment.n_numaux = 0; + + return coff_write_symbol (abfd, symbol, native, written, string_size_p, + debug_string_section_p, debug_string_size_p); +} + +/* Write a native symbol to a COFF file. */ + +static boolean +coff_write_native_symbol (abfd, symbol, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + coff_symbol_type *symbol; + unsigned int *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + combined_entry_type *native = symbol->native; + alent *lineno = symbol->lineno; + + /* If this symbol has an associated line number, we must store the + symbol index in the line number field. We also tag the auxent to + point to the right place in the lineno table. */ + if (lineno && !symbol->done_lineno && symbol->symbol.section->owner != NULL) + { + unsigned int count = 0; + lineno[count].u.offset = *written; + if (native->u.syment.n_numaux) + { + union internal_auxent *a = &((native + 1)->u.auxent); + + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + symbol->symbol.section->output_section->moving_line_filepos; + } + + /* Count and relocate all other linenumbers. */ + count++; + while (lineno[count].line_number != 0) + { +#if 0 + /* 13 april 92. sac + I've been told this, but still need proof: + > The second bug is also in `bfd/coffcode.h'. This bug + > causes the linker to screw up the pc-relocations for + > all the line numbers in COFF code. This bug isn't only + > specific to A29K implementations, but affects all + > systems using COFF format binaries. Note that in COFF + > object files, the line number core offsets output by + > the assembler are relative to the start of each + > procedure, not to the start of the .text section. This + > patch relocates the line numbers relative to the + > `native->u.syment.n_value' instead of the section + > virtual address. + > modular!olson@cs.arizona.edu (Jon Olson) + */ + lineno[count].u.offset += native->u.syment.n_value; +#else + lineno[count].u.offset += + (symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset); +#endif + count++; + } + symbol->done_lineno = true; + + symbol->symbol.section->output_section->moving_line_filepos += + count * bfd_coff_linesz (abfd); + } + + return coff_write_symbol (abfd, &(symbol->symbol), native, written, + string_size_p, debug_string_section_p, + debug_string_size_p); +} + +/* Write out the COFF symbols. */ + +boolean +coff_write_symbols (abfd) + bfd *abfd; +{ + bfd_size_type string_size; + asection *debug_string_section; + bfd_size_type debug_string_size; + unsigned int i; + unsigned int limit = bfd_get_symcount (abfd); + unsigned int written = 0; + asymbol **p; + + string_size = 0; + debug_string_section = NULL; + debug_string_size = 0; + + /* Seek to the right place */ + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) + return false; + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); + + if (c_symbol == (coff_symbol_type *) NULL + || c_symbol->native == (combined_entry_type *) NULL) + { + if (!coff_write_alien_symbol (abfd, symbol, &written, &string_size, + &debug_string_section, + &debug_string_size)) + return false; + } + else + { + if (!coff_write_native_symbol (abfd, c_symbol, &written, + &string_size, &debug_string_section, + &debug_string_size)) + return false; + } + } + + obj_raw_syment_count (abfd) = written; + + /* Now write out strings */ + + if (string_size != 0) + { + unsigned int size = string_size + STRING_SIZE_SIZE; + bfd_byte buffer[STRING_SIZE_SIZE]; + +#if STRING_SIZE_SIZE == 4 + bfd_h_put_32 (abfd, size, buffer); +#else + #error Change bfd_h_put_32 +#endif + if (bfd_write ((PTR) buffer, 1, sizeof (buffer), abfd) != sizeof (buffer)) + return false; + for (p = abfd->outsymbols, i = 0; + i < limit; + i++, p++) + { + asymbol *q = *p; + size_t name_length = strlen (q->name); + coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); + size_t maxlen; + + /* Figure out whether the symbol name should go in the string + table. Symbol names that are short enough are stored + directly in the syment structure. File names permit a + different, longer, length in the syment structure. On + XCOFF, some symbol names are stored in the .debug section + rather than in the string table. */ + + if (c_symbol == NULL + || c_symbol->native == NULL) + { + /* This is not a COFF symbol, so it certainly is not a + file name, nor does it go in the .debug section. */ + maxlen = SYMNMLEN; + } + else if (bfd_coff_symname_in_debug (abfd, + &c_symbol->native->u.syment)) + { + /* This symbol name is in the XCOFF .debug section. + Don't write it into the string table. */ + maxlen = name_length; + } + else if (c_symbol->native->u.syment.n_sclass == C_FILE + && c_symbol->native->u.syment.n_numaux > 0) + maxlen = FILNMLEN; + else + maxlen = SYMNMLEN; + + if (name_length > maxlen) + { + if (bfd_write ((PTR) (q->name), 1, name_length + 1, abfd) + != name_length + 1) + return false; + } + } + } + else + { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read the + string table even when there isn't one won't croak. */ + unsigned int size = STRING_SIZE_SIZE; + bfd_byte buffer[STRING_SIZE_SIZE]; + +#if STRING_SIZE_SIZE == 4 + bfd_h_put_32 (abfd, size, buffer); +#else + #error Change bfd_h_put_32 +#endif + if (bfd_write ((PTR) buffer, 1, STRING_SIZE_SIZE, abfd) + != STRING_SIZE_SIZE) + return false; + } + + /* Make sure the .debug section was created to be the correct size. + We should create it ourselves on the fly, but we don't because + BFD won't let us write to any section until we know how large all + the sections are. We could still do it by making another pass + over the symbols. FIXME. */ + BFD_ASSERT (debug_string_size == 0 + || (debug_string_section != (asection *) NULL + && (BFD_ALIGN (debug_string_size, + 1 << debug_string_section->alignment_power) + == bfd_section_size (abfd, debug_string_section)))); + + return true; +} + +boolean +coff_write_linenumbers (abfd) + bfd *abfd; +{ + asection *s; + bfd_size_type linesz; + PTR buff; + + linesz = bfd_coff_linesz (abfd); + buff = bfd_alloc (abfd, linesz); + if (!buff) + return false; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if (s->lineno_count) + { + asymbol **q = abfd->outsymbols; + if (bfd_seek (abfd, s->line_filepos, SEEK_SET) != 0) + return false; + /* Find all the linenumbers in this section */ + while (*q) + { + asymbol *p = *q; + if (p->section->output_section == s) + { + alent *l = + BFD_SEND (bfd_asymbol_bfd (p), _get_lineno, + (bfd_asymbol_bfd (p), p)); + if (l) + { + /* Found a linenumber entry, output */ + struct internal_lineno out; + memset ((PTR) & out, 0, sizeof (out)); + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out (abfd, &out, buff); + if (bfd_write (buff, 1, linesz, abfd) != linesz) + return false; + l++; + while (l->line_number) + { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out (abfd, &out, buff); + if (bfd_write (buff, 1, linesz, abfd) != linesz) + return false; + l++; + } + } + } + q++; + } + } + } + bfd_release (abfd, buff); + return true; +} + +/*ARGSUSED */ +alent * +coff_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + return coffsymbol (symbol)->lineno; +} + +#if 0 + +/* This is only called from coff_add_missing_symbols, which has been + disabled. */ + +asymbol * +coff_section_symbol (abfd, name) + bfd *abfd; + char *name; +{ + asection *sec = bfd_make_section_old_way (abfd, name); + asymbol *sym; + combined_entry_type *csym; + + sym = sec->symbol; + csym = coff_symbol_from (abfd, sym)->native; + /* Make sure back-end COFF stuff is there. */ + if (csym == 0) + { + struct foo + { + coff_symbol_type sym; + /* @@FIXME This shouldn't use a fixed size!! */ + combined_entry_type e[10]; + }; + struct foo *f; + f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f)); + if (!f) + { + bfd_set_error (bfd_error_no_error); + return NULL; + } + memset ((char *) f, 0, sizeof (*f)); + coff_symbol_from (abfd, sym)->native = csym = f->e; + } + csym[0].u.syment.n_sclass = C_STAT; + csym[0].u.syment.n_numaux = 1; +/* SF_SET_STATICS (sym); @@ ??? */ + csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size; + csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count; + csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count; + + if (sec->output_section == NULL) + { + sec->output_section = sec; + sec->output_offset = 0; + } + + return sym; +} + +#endif /* 0 */ + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +coff_pointerize_aux (abfd, table_base, symbol, indaux, auxent) + bfd *abfd; + combined_entry_type *table_base; + combined_entry_type *symbol; + unsigned int indaux; + combined_entry_type *auxent; +{ + int type = symbol->u.syment.n_type; + int class = symbol->u.syment.n_sclass; + + if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) + { + if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) + (abfd, table_base, symbol, indaux, auxent)) + return; + } + + /* Don't bother if this is a file or a section */ + if (class == C_STAT && type == T_NULL) + return; + if (class == C_FILE) + return; + + /* 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 (class) || class == C_BLOCK) + && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0) + { + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = + table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + auxent->fix_end = 1; + } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can + generate one, so we must be careful to ignore it. */ + if (auxent->u.auxent.x_sym.x_tagndx.l > 0) + { + auxent->u.auxent.x_sym.x_tagndx.p = + table_base + auxent->u.auxent.x_sym.x_tagndx.l; + auxent->fix_tag = 1; + } +} + +/* Allocate space for the ".debug" section, and read it. + We did not read the debug section until now, because + we didn't want to go to the trouble until someone needed it. */ + +static char * +build_debug_section (abfd) + bfd *abfd; +{ + char *debug_section; + long position; + + asection *sect = bfd_get_section_by_name (abfd, ".debug"); + + if (!sect) + { + bfd_set_error (bfd_error_no_debug_section); + return NULL; + } + + debug_section = (PTR) bfd_alloc (abfd, + bfd_get_section_size_before_reloc (sect)); + if (debug_section == NULL) + return NULL; + + /* Seek to the beginning of the `.debug' section and read it. + Save the current position first; it is needed by our caller. + Then read debug section and reset the file pointer. */ + + position = bfd_tell (abfd); + if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0 + || (bfd_read (debug_section, + bfd_get_section_size_before_reloc (sect), 1, abfd) + != bfd_get_section_size_before_reloc (sect)) + || bfd_seek (abfd, position, SEEK_SET) != 0) + return NULL; + return debug_section; +} + + +/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be + \0-terminated, but will not exceed 'maxlen' characters. The copy *will* + be \0-terminated. */ +static char * +copy_name (abfd, name, maxlen) + bfd *abfd; + char *name; + int maxlen; +{ + int len; + char *newname; + + for (len = 0; len < maxlen; ++len) + { + if (name[len] == '\0') + { + break; + } + } + + if ((newname = (PTR) bfd_alloc (abfd, len + 1)) == NULL) + return (NULL); + strncpy (newname, name, len); + newname[len] = '\0'; + return newname; +} + +/* Read in the external symbols. */ + +boolean +_bfd_coff_get_external_symbols (abfd) + bfd *abfd; +{ + bfd_size_type symesz; + size_t size; + PTR syms; + + if (obj_coff_external_syms (abfd) != NULL) + return true; + + symesz = bfd_coff_symesz (abfd); + + size = obj_raw_syment_count (abfd) * symesz; + + syms = (PTR) bfd_malloc (size); + if (syms == NULL && size != 0) + return false; + + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || bfd_read (syms, size, 1, abfd) != size) + { + if (syms != NULL) + free (syms); + return false; + } + + obj_coff_external_syms (abfd) = syms; + + return true; +} + +/* Read in the external strings. The strings are not loaded until + they are needed. This is because we have no simple way of + detecting a missing string table in an archive. */ + +const char * +_bfd_coff_read_string_table (abfd) + bfd *abfd; +{ + char extstrsize[STRING_SIZE_SIZE]; + size_t strsize; + char *strings; + + if (obj_coff_strings (abfd) != NULL) + return obj_coff_strings (abfd); + + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd)), + SEEK_SET) != 0) + return NULL; + + if (bfd_read (extstrsize, sizeof extstrsize, 1, abfd) != sizeof extstrsize) + { + if (bfd_get_error () != bfd_error_file_truncated) + return NULL; + + /* There is no string table. */ + strsize = STRING_SIZE_SIZE; + } + else + { +#if STRING_SIZE_SIZE == 4 + strsize = bfd_h_get_32 (abfd, (bfd_byte *) extstrsize); +#else + #error Change bfd_h_get_32 +#endif + } + + if (strsize < STRING_SIZE_SIZE) + { + (*_bfd_error_handler) + ("%s: bad string table size %lu", bfd_get_filename (abfd), + (unsigned long) strsize); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + + strings = (char *) bfd_malloc (strsize); + if (strings == NULL) + return NULL; + + if (bfd_read (strings + STRING_SIZE_SIZE, + strsize - STRING_SIZE_SIZE, 1, abfd) + != strsize - STRING_SIZE_SIZE) + { + free (strings); + return NULL; + } + + obj_coff_strings (abfd) = strings; + + return strings; +} + +/* Free up the external symbols and strings read from a COFF file. */ + +boolean +_bfd_coff_free_symbols (abfd) + bfd *abfd; +{ + if (obj_coff_external_syms (abfd) != NULL + && ! obj_coff_keep_syms (abfd)) + { + free (obj_coff_external_syms (abfd)); + obj_coff_external_syms (abfd) = NULL; + } + if (obj_coff_strings (abfd) != NULL + && ! obj_coff_keep_strings (abfd)) + { + free (obj_coff_strings (abfd)); + obj_coff_strings (abfd) = NULL; + } + return true; +} + +/* Read a symbol table into freshly bfd_allocated memory, swap it, and + knit the symbol names into a normalized form. By normalized here I + mean that all symbols have an n_offset pointer that points to a null- + terminated string. */ + +combined_entry_type * +coff_get_normalized_symtab (abfd) + bfd *abfd; +{ + combined_entry_type *internal; + combined_entry_type *internal_ptr; + combined_entry_type *symbol_ptr; + combined_entry_type *internal_end; + bfd_size_type symesz; + char *raw_src; + char *raw_end; + const char *string_table = NULL; + char *debug_section = NULL; + unsigned long size; + + if (obj_raw_syments (abfd) != NULL) + return obj_raw_syments (abfd); + + size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); + internal = (combined_entry_type *) bfd_zalloc (abfd, size); + if (internal == NULL && size != 0) + return NULL; + internal_end = internal + obj_raw_syment_count (abfd); + + if (! _bfd_coff_get_external_symbols (abfd)) + return NULL; + + raw_src = (char *) obj_coff_external_syms (abfd); + + /* mark the end of the symbols */ + symesz = bfd_coff_symesz (abfd); + raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz; + + /* FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. */ + + /* Swap all the raw entries */ + for (internal_ptr = internal; + raw_src < raw_end; + raw_src += symesz, internal_ptr++) + { + + unsigned int i; + bfd_coff_swap_sym_in (abfd, (PTR) raw_src, + (PTR) & internal_ptr->u.syment); + symbol_ptr = internal_ptr; + + for (i = 0; + i < symbol_ptr->u.syment.n_numaux; + i++) + { + internal_ptr++; + raw_src += symesz; + bfd_coff_swap_aux_in (abfd, (PTR) raw_src, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + i, symbol_ptr->u.syment.n_numaux, + &(internal_ptr->u.auxent)); + coff_pointerize_aux (abfd, internal, symbol_ptr, i, + internal_ptr); + } + } + + /* Free the raw symbols, but not the strings (if we have them). */ + obj_coff_keep_strings (abfd) = true; + if (! _bfd_coff_free_symbols (abfd)) + return NULL; + + for (internal_ptr = internal; internal_ptr < internal_end; + internal_ptr++) + { + if (internal_ptr->u.syment.n_sclass == C_FILE + && internal_ptr->u.syment.n_numaux > 0) + { + /* make a file symbol point to the name in the auxent, since + the text ".file" is redundant */ + if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0) + { + /* the filename is a long one, point into the string table */ + if (string_table == NULL) + { + string_table = _bfd_coff_read_string_table (abfd); + if (string_table == NULL) + return NULL; + } + + internal_ptr->u.syment._n._n_n._n_offset = + ((long) + (string_table + + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); + } + else + { + /* ordinary short filename, put into memory anyway */ + internal_ptr->u.syment._n._n_n._n_offset = (long) + copy_name (abfd, (internal_ptr + 1)->u.auxent.x_file.x_fname, + FILNMLEN); + } + } + else + { + if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) + { + /* This is a "short" name. Make it long. */ + unsigned long i = 0; + char *newstring = NULL; + + /* find the length of this string without walking into memory + that isn't ours. */ + for (i = 0; i < 8; ++i) + { + if (internal_ptr->u.syment._n._n_name[i] == '\0') + { + break; + } /* if end of string */ + } /* possible lengths of this string. */ + + if ((newstring = (PTR) bfd_alloc (abfd, ++i)) == NULL) + return (NULL); + memset (newstring, 0, i); + strncpy (newstring, internal_ptr->u.syment._n._n_name, i - 1); + internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring; + internal_ptr->u.syment._n._n_n._n_zeroes = 0; + } + else if (internal_ptr->u.syment._n._n_n._n_offset == 0) + internal_ptr->u.syment._n._n_n._n_offset = (long int) ""; + else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment)) + { + /* Long name already. Point symbol at the string in the + table. */ + if (string_table == NULL) + { + string_table = _bfd_coff_read_string_table (abfd); + if (string_table == NULL) + return NULL; + } + internal_ptr->u.syment._n._n_n._n_offset = + ((long int) + (string_table + + internal_ptr->u.syment._n._n_n._n_offset)); + } + else + { + /* Long name in debug section. Very similar. */ + if (debug_section == NULL) + debug_section = build_debug_section (abfd); + internal_ptr->u.syment._n._n_n._n_offset = (long int) + (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + } + } + internal_ptr += internal_ptr->u.syment.n_numaux; + } + + obj_raw_syments (abfd) = internal; + BFD_ASSERT (obj_raw_syment_count (abfd) + == (unsigned int) (internal_ptr - internal)); + + return (internal); +} /* coff_get_normalized_symtab() */ + +long +coff_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +asymbol * +coff_make_empty_symbol (abfd) + bfd *abfd; +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc (abfd, sizeof (coff_symbol_type)); + if (new == NULL) + return (NULL); + memset (new, 0, sizeof *new); + new->symbol.section = 0; + new->native = 0; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Make a debugging symbol. */ + +asymbol * +coff_bfd_make_debug_symbol (abfd, ptr, sz) + bfd *abfd; + PTR ptr; + unsigned long sz; +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc (abfd, sizeof (coff_symbol_type)); + if (new == NULL) + return (NULL); + /* @@ This shouldn't be using a constant multiplier. */ + new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10); + if (!new->native) + return (NULL); + new->symbol.section = bfd_abs_section_ptr; + new->symbol.flags = BSF_DEBUGGING; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/*ARGSUSED */ +void +coff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); + if (coffsymbol (symbol)->native != NULL + && coffsymbol (symbol)->native->fix_value) + { + combined_entry_type *psym; + + psym = ((combined_entry_type *) + coffsymbol (symbol)->native->u.syment.n_value); + ret->value = (bfd_vma) (psym - obj_raw_syments (abfd)); + } +} + +/* Print out information about COFF symbol. */ + +void +coff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + + case bfd_print_symbol_more: + fprintf (file, "coff %s %s", + coffsymbol (symbol)->native ? "n" : "g", + coffsymbol (symbol)->lineno ? "l" : " "); + break; + + case bfd_print_symbol_all: + if (coffsymbol (symbol)->native) + { + unsigned long val; + unsigned int aux; + combined_entry_type *combined = coffsymbol (symbol)->native; + combined_entry_type *root = obj_raw_syments (abfd); + struct lineno_cache_entry *l = coffsymbol (symbol)->lineno; + + fprintf (file, "[%3ld]", (long) (combined - root)); + + if (! combined->fix_value) + val = (unsigned long) combined->u.syment.n_value; + else + val = ((unsigned long) + ((combined_entry_type *) combined->u.syment.n_value + - root)); + + fprintf (file, + "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x%08lx %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + val, + symbol->name); + + for (aux = 0; aux < combined->u.syment.n_numaux; aux++) + { + combined_entry_type *auxp = combined + aux + 1; + long tagndx; + + if (auxp->fix_tag) + tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; + else + tagndx = auxp->u.auxent.x_sym.x_tagndx.l; + + fprintf (file, "\n"); + + if (bfd_coff_print_aux (abfd, file, root, combined, auxp, aux)) + continue; + + switch (combined->u.syment.n_sclass) + { + case C_FILE: + fprintf (file, "File "); + break; + + case C_STAT: + if (combined->u.syment.n_type == T_NULL) + /* probably a section symbol? */ + { + fprintf (file, "AUX scnlen 0x%lx nreloc %d nlnno %d", + (long) auxp->u.auxent.x_scn.x_scnlen, + auxp->u.auxent.x_scn.x_nreloc, + auxp->u.auxent.x_scn.x_nlinno); + break; + } + /* else fall through */ + + default: + fprintf (file, "AUX lnno %d size 0x%x tagndx %ld", + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size, + tagndx); + if (auxp->fix_end) + fprintf (file, " endndx %ld", + ((long) + (auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p + - root))); + break; + } + } + + if (l) + { + fprintf (file, "\n%s :", l->u.sym->name); + l++; + while (l->line_number) + { + fprintf (file, "\n%4d : 0x%lx", + l->line_number, + ((unsigned long) + (l->u.offset + symbol->section->vma))); + l++; + } + } + } + else + { + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s %s %s", + symbol->section->name, + coffsymbol (symbol)->native ? "n" : "g", + coffsymbol (symbol)->lineno ? "l" : " ", + symbol->name); + } + } +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +/*ARGSUSED*/ +boolean +coff_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *line_ptr; +{ + boolean found; + unsigned int i; + unsigned int line_base; + coff_data_type *cof = coff_data (abfd); + /* Run through the raw syments if available */ + combined_entry_type *p; + combined_entry_type *pend; + alent *l; + struct coff_section_tdata *sec_data; + + /* Before looking through the symbol table, try to use a .stab + section to find the information. */ + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &coff_data (abfd)->line_info)) + return false; + if (found) + return true; + + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + + /* Don't try and find line numbers in a non coff file */ + if (abfd->xvec->flavour != bfd_target_coff_flavour) + return false; + + if (cof == NULL) + return false; + + /* Find the first C_FILE symbol. */ + p = cof->raw_syments; + pend = p + cof->raw_syment_count; + while (p < pend) + { + if (p->u.syment.n_sclass == C_FILE) + break; + p += 1 + p->u.syment.n_numaux; + } + + if (p < pend) + { + bfd_vma maxdiff; + + /* Look through the C_FILE symbols to find the best one. */ + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + maxdiff = (bfd_vma) 0 - (bfd_vma) 1; + while (1) + { + combined_entry_type *p2; + + for (p2 = p + 1 + p->u.syment.n_numaux; + p2 < pend; + p2 += 1 + p2->u.syment.n_numaux) + { + if (p2->u.syment.n_scnum > 0 + && (section + == coff_section_from_bfd_index (abfd, + p2->u.syment.n_scnum))) + break; + if (p2->u.syment.n_sclass == C_FILE) + { + p2 = pend; + break; + } + } + + if (p2 < pend + && offset >= (bfd_vma) p2->u.syment.n_value + && offset - (bfd_vma) p2->u.syment.n_value < maxdiff) + { + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + maxdiff = offset - p2->u.syment.n_value; + } + + /* Avoid endless loops on erroneous files by ensuring that + we always move forward in the file. */ + if (p - cof->raw_syments >= p->u.syment.n_value) + break; + + p = cof->raw_syments + p->u.syment.n_value; + if (p > pend || p->u.syment.n_sclass != C_FILE) + break; + } + } + + /* Now wander though the raw linenumbers of the section */ + /* If we have been called on this section before, and the offset we + want is further down then we can prime the lookup loop. */ + sec_data = coff_section_data (abfd, section); + if (sec_data != NULL + && sec_data->i > 0 + && offset >= sec_data->offset) + { + i = sec_data->i; + *functionname_ptr = sec_data->function; + line_base = sec_data->line_base; + } + else + { + i = 0; + line_base = 0; + } + + if (section->lineno != NULL) + { + l = §ion->lineno[i]; + + for (; i < section->lineno_count; i++) + { + if (l->line_number == 0) + { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + if (coff->symbol.value > offset) + break; + *functionname_ptr = coff->symbol.name; + if (coff->native) + { + combined_entry_type *s = coff->native; + s = s + 1 + s->u.syment.n_numaux; + + /* In XCOFF a debugging symbol can follow the + function symbol. */ + if (s->u.syment.n_scnum == N_DEBUG) + s = s + 1 + s->u.syment.n_numaux; + + /* S should now point to the .bf of the function. */ + if (s->u.syment.n_numaux) + { + /* The linenumber is stored in the auxent. */ + union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; + *line_ptr = line_base; + } + } + } + else + { + if (l->u.offset + bfd_get_section_vma (abfd, section) > offset) + break; + *line_ptr = l->line_number + line_base - 1; + } + l++; + } + } + + /* Cache the results for the next call. */ + if (sec_data == NULL && section->owner == abfd) + { + section->used_by_bfd = + ((PTR) bfd_zalloc (abfd, + sizeof (struct coff_section_tdata))); + sec_data = (struct coff_section_tdata *) section->used_by_bfd; + } + if (sec_data != NULL) + { + sec_data->offset = offset; + sec_data->i = i; + sec_data->function = *functionname_ptr; + sec_data->line_base = line_base; + } + + return true; +} + +int +coff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + size_t size; + + if (reloc == false) + { + size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + } + else + { + size = bfd_coff_filhsz (abfd); + } + + size += abfd->section_count * bfd_coff_scnhsz (abfd); + return size; +} diff --git a/contrib/gdb/bfd/cofflink.c b/contrib/gdb/bfd/cofflink.c new file mode 100644 index 000000000000..c4a42a091478 --- /dev/null +++ b/contrib/gdb/bfd/cofflink.c @@ -0,0 +1,2327 @@ +/* COFF specific linker code. + Copyright 1994, 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains the COFF backend linker code. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +static boolean coff_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean coff_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *)); +static boolean coff_link_check_ar_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean *)); +static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *)); + +/* Create an entry in a COFF linker hash table. */ + +struct bfd_hash_entry * +_bfd_coff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct coff_link_hash_entry *) NULL) + ret = ((struct coff_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry))); + if (ret == (struct coff_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct coff_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct coff_link_hash_entry *) NULL) + { + /* Set local fields. */ + ret->indx = -1; + ret->type = T_NULL; + ret->class = C_NULL; + ret->numaux = 0; + ret->auxbfd = NULL; + ret->aux = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a COFF linker hash table. */ + +boolean +_bfd_coff_link_hash_table_init (table, abfd, newfunc) + struct coff_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return _bfd_link_hash_table_init (&table->root, abfd, newfunc); +} + +/* Create a COFF linker hash table. */ + +struct bfd_link_hash_table * +_bfd_coff_link_hash_table_create (abfd) + bfd *abfd; +{ + struct coff_link_hash_table *ret; + + ret = ((struct coff_link_hash_table *) + bfd_alloc (abfd, sizeof (struct coff_link_hash_table))); + if (ret == NULL) + return NULL; + if (! _bfd_coff_link_hash_table_init (ret, abfd, + _bfd_coff_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Create an entry in a COFF debug merge hash table. */ + +struct bfd_hash_entry * +_bfd_coff_debug_merge_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct coff_debug_merge_hash_entry *ret = + (struct coff_debug_merge_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct coff_debug_merge_hash_entry *) NULL) + ret = ((struct coff_debug_merge_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct coff_debug_merge_hash_entry))); + if (ret == (struct coff_debug_merge_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct coff_debug_merge_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret != (struct coff_debug_merge_hash_entry *) NULL) + { + /* Set local fields. */ + ret->types = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Given a COFF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +_bfd_coff_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return coff_link_add_object_symbols (abfd, info); + case bfd_archive: + return (_bfd_generic_link_add_archive_symbols + (abfd, info, coff_link_check_archive_element)); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add symbols from a COFF object file. */ + +static boolean +coff_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (! _bfd_coff_get_external_symbols (abfd)) + return false; + if (! coff_link_add_symbols (abfd, info)) + return false; + + if (! info->keep_memory) + { + if (! _bfd_coff_free_symbols (abfd)) + return false; + } + return true; +} + +/* Check a single archive element to see if we need to include it in + the link. *PNEEDED is set according to whether this element is + needed in the link or not. This is called via + _bfd_generic_link_add_archive_symbols. */ + +static boolean +coff_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + if (! _bfd_coff_get_external_symbols (abfd)) + return false; + + if (! coff_link_check_ar_symbols (abfd, info, pneeded)) + return false; + + if (*pneeded) + { + if (! coff_link_add_symbols (abfd, info)) + return false; + } + + if (! info->keep_memory || ! *pneeded) + { + if (! _bfd_coff_free_symbols (abfd)) + return false; + } + + return true; +} + +/* Look through the symbols to see if this object file should be + included in the link. */ + +static boolean +coff_link_check_ar_symbols (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); + bfd_size_type symesz; + bfd_byte *esym; + bfd_byte *esym_end; + + *pneeded = false; + + sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global; + + symesz = bfd_coff_symesz (abfd); + esym = (bfd_byte *) obj_coff_external_syms (abfd); + esym_end = esym + obj_raw_syment_count (abfd) * symesz; + while (esym < esym_end) + { + struct internal_syment sym; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); + + if ((sym.n_sclass == C_EXT + || (sym_is_global && (*sym_is_global) (abfd, &sym))) + && (sym.n_scnum != 0 || sym.n_value != 0)) + { + const char *name; + char buf[SYMNMLEN + 1]; + struct bfd_link_hash_entry *h; + + /* This symbol is externally visible, and is defined by this + object file. */ + + name = _bfd_coff_internal_syment_name (abfd, &sym, buf); + if (name == NULL) + return false; + h = bfd_link_hash_lookup (info->hash, name, false, false, true); + + /* We are only interested in symbols that are currently + undefined. If a symbol is currently known to be common, + COFF linkers do not bring in an object file which defines + it. */ + if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_undefined) + { + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + return false; + *pneeded = true; + return true; + } + } + + esym += (sym.n_numaux + 1) * symesz; + } + + /* We do not need this object file. */ + return true; +} + +/* Add all the symbols from an object file to the hash table. */ + +static boolean +coff_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); + boolean default_copy; + bfd_size_type symcount; + struct coff_link_hash_entry **sym_hash; + bfd_size_type symesz; + bfd_byte *esym; + bfd_byte *esym_end; + + sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global; + + if (info->keep_memory) + default_copy = false; + else + default_copy = true; + + symcount = obj_raw_syment_count (abfd); + + /* We keep a list of the linker hash table entries that correspond + to particular symbols. */ + sym_hash = ((struct coff_link_hash_entry **) + bfd_alloc (abfd, + ((size_t) symcount + * sizeof (struct coff_link_hash_entry *)))); + if (sym_hash == NULL && symcount != 0) + return false; + obj_coff_sym_hashes (abfd) = sym_hash; + memset (sym_hash, 0, + (size_t) symcount * sizeof (struct coff_link_hash_entry *)); + + symesz = bfd_coff_symesz (abfd); + BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); + esym = (bfd_byte *) obj_coff_external_syms (abfd); + esym_end = esym + symcount * symesz; + while (esym < esym_end) + { + struct internal_syment sym; + boolean copy; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); + + if (sym.n_sclass == C_EXT + || (sym_is_global && (*sym_is_global) (abfd, &sym))) + { + const char *name; + char buf[SYMNMLEN + 1]; + flagword flags; + asection *section; + bfd_vma value; + + /* This symbol is externally visible. */ + + name = _bfd_coff_internal_syment_name (abfd, &sym, buf); + if (name == NULL) + return false; + + /* We must copy the name into memory if we got it from the + syment itself, rather than the string table. */ + copy = default_copy; + if (sym._n._n_n._n_zeroes != 0 + || sym._n._n_n._n_offset == 0) + copy = true; + + value = sym.n_value; + + if (sym.n_scnum == 0) + { + if (value == 0) + { + flags = 0; + section = bfd_und_section_ptr; + } + else + { + flags = BSF_GLOBAL; + section = bfd_com_section_ptr; + } + } + else + { + flags = BSF_EXPORT | BSF_GLOBAL; + section = coff_section_from_bfd_index (abfd, sym.n_scnum); + value -= section->vma; + } + + if (! (bfd_coff_link_add_one_symbol + (info, abfd, name, flags, section, value, + (const char *) NULL, copy, false, + (struct bfd_link_hash_entry **) sym_hash))) + return false; + + if (info->hash->creator->flavour == bfd_get_flavour (abfd)) + { + if (((*sym_hash)->class == C_NULL + && (*sym_hash)->type == T_NULL) + || sym.n_scnum != 0 + || (sym.n_value != 0 + && (*sym_hash)->root.type != bfd_link_hash_defined)) + { + (*sym_hash)->class = sym.n_sclass; + (*sym_hash)->type = sym.n_type; + (*sym_hash)->numaux = sym.n_numaux; + (*sym_hash)->auxbfd = abfd; + if (sym.n_numaux != 0) + { + union internal_auxent *alloc; + unsigned int i; + bfd_byte *eaux; + union internal_auxent *iaux; + + alloc = ((union internal_auxent *) + bfd_hash_allocate (&info->hash->table, + (sym.n_numaux + * sizeof (*alloc)))); + if (alloc == NULL) + return false; + for (i = 0, eaux = esym + symesz, iaux = alloc; + i < sym.n_numaux; + i++, eaux += symesz, iaux++) + bfd_coff_swap_aux_in (abfd, (PTR) eaux, sym.n_type, + sym.n_sclass, i, sym.n_numaux, + (PTR) iaux); + (*sym_hash)->aux = alloc; + } + } + } + } + + esym += (sym.n_numaux + 1) * symesz; + sym_hash += sym.n_numaux + 1; + } + + return true; +} + +/* Do the final link step. */ + +boolean +_bfd_coff_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_size_type symesz; + struct coff_final_link_info finfo; + boolean debug_merge_allocated; + asection *o; + struct bfd_link_order *p; + size_t max_sym_count; + size_t max_lineno_count; + size_t max_reloc_count; + size_t max_output_reloc_count; + size_t max_contents_size; + file_ptr rel_filepos; + unsigned int relsz; + file_ptr line_filepos; + unsigned int linesz; + bfd *sub; + bfd_byte *external_relocs = NULL; + char strbuf[STRING_SIZE_SIZE]; + + symesz = bfd_coff_symesz (abfd); + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.strtab = NULL; + finfo.section_info = NULL; + finfo.last_file_index = -1; + finfo.internal_syms = NULL; + finfo.sec_ptrs = NULL; + finfo.sym_indices = NULL; + finfo.outsyms = NULL; + finfo.linenos = NULL; + finfo.contents = NULL; + finfo.external_relocs = NULL; + finfo.internal_relocs = NULL; + debug_merge_allocated = false; + + coff_data (abfd)->link_info = info; + + finfo.strtab = _bfd_stringtab_init (); + if (finfo.strtab == NULL) + goto error_return; + + if (! coff_debug_merge_hash_table_init (&finfo.debug_merge)) + goto error_return; + debug_merge_allocated = true; + + /* Compute the file positions for all the sections. */ + if (! abfd->output_has_begun) + bfd_coff_compute_section_file_positions (abfd); + + /* Count the line numbers and relocation entries required for the + output file. Set the file positions for the relocs. */ + rel_filepos = obj_relocbase (abfd); + relsz = bfd_coff_relsz (abfd); + max_contents_size = 0; + max_lineno_count = 0; + max_reloc_count = 0; + + for (o = abfd->sections; o != NULL; o = o->next) + { + o->reloc_count = 0; + o->lineno_count = 0; + for (p = o->link_order_head; p != NULL; p = p->next) + { + + if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + + if (info->strip == strip_none + || info->strip == strip_some) + o->lineno_count += sec->lineno_count; + + if (info->relocateable) + o->reloc_count += sec->reloc_count; + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->lineno_count > max_lineno_count) + max_lineno_count = sec->lineno_count; + if (sec->reloc_count > max_reloc_count) + max_reloc_count = sec->reloc_count; + } + else if (info->relocateable + && (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order)) + ++o->reloc_count; + } + if (o->reloc_count == 0) + o->rel_filepos = 0; + else + { + o->flags |= SEC_RELOC; + o->rel_filepos = rel_filepos; + rel_filepos += o->reloc_count * relsz; + } + } + + /* If doing a relocateable link, allocate space for the pointers we + need to keep. */ + if (info->relocateable) + { + unsigned int i; + + /* We use section_count + 1, rather than section_count, because + the target_index fields are 1 based. */ + finfo.section_info = + ((struct coff_link_section_info *) + bfd_malloc ((abfd->section_count + 1) + * sizeof (struct coff_link_section_info))); + if (finfo.section_info == NULL) + goto error_return; + for (i = 0; i <= abfd->section_count; i++) + { + finfo.section_info[i].relocs = NULL; + finfo.section_info[i].rel_hashes = NULL; + } + } + + /* We now know the size of the relocs, so we can determine the file + positions of the line numbers. */ + line_filepos = rel_filepos; + linesz = bfd_coff_linesz (abfd); + max_output_reloc_count = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + if (o->lineno_count == 0) + o->line_filepos = 0; + else + { + o->line_filepos = line_filepos; + line_filepos += o->lineno_count * linesz; + } + + if (o->reloc_count != 0) + { + /* We don't know the indices of global symbols until we have + written out all the local symbols. For each section in + the output file, we keep an array of pointers to hash + table entries. Each entry in the array corresponds to a + reloc. When we find a reloc against a global symbol, we + set the corresponding entry in this array so that we can + fix up the symbol index after we have written out all the + local symbols. + + Because of this problem, we also keep the relocs in + memory until the end of the link. This wastes memory, + but only when doing a relocateable link, which is not the + common case. */ + BFD_ASSERT (info->relocateable); + finfo.section_info[o->target_index].relocs = + ((struct internal_reloc *) + bfd_malloc (o->reloc_count * sizeof (struct internal_reloc))); + finfo.section_info[o->target_index].rel_hashes = + ((struct coff_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct coff_link_hash_entry *))); + if (finfo.section_info[o->target_index].relocs == NULL + || finfo.section_info[o->target_index].rel_hashes == NULL) + goto error_return; + + if (o->reloc_count > max_output_reloc_count) + max_output_reloc_count = o->reloc_count; + } + + /* Reset the reloc and lineno counts, so that we can use them to + count the number of entries we have output so far. */ + o->reloc_count = 0; + o->lineno_count = 0; + } + + obj_sym_filepos (abfd) = line_filepos; + + /* Figure out the largest number of symbols in an input BFD. Take + the opportunity to clear the output_has_begun fields of all the + input BFD's. */ + max_sym_count = 0; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + size_t sz; + + sub->output_has_begun = false; + sz = obj_raw_syment_count (sub); + if (sz > max_sym_count) + max_sym_count = sz; + } + + /* Allocate some buffers used while linking. */ + finfo.internal_syms = ((struct internal_syment *) + bfd_malloc (max_sym_count + * sizeof (struct internal_syment))); + finfo.sec_ptrs = (asection **) bfd_malloc (max_sym_count + * sizeof (asection *)); + finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long)); + finfo.outsyms = ((bfd_byte *) + bfd_malloc ((size_t) ((max_sym_count + 1) * symesz))); + finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count + * bfd_coff_linesz (abfd)); + finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz); + if (! info->relocateable) + finfo.internal_relocs = ((struct internal_reloc *) + bfd_malloc (max_reloc_count + * sizeof (struct internal_reloc))); + if ((finfo.internal_syms == NULL && max_sym_count > 0) + || (finfo.sec_ptrs == NULL && max_sym_count > 0) + || (finfo.sym_indices == NULL && max_sym_count > 0) + || finfo.outsyms == NULL + || (finfo.linenos == NULL && max_lineno_count > 0) + || (finfo.contents == NULL && max_contents_size > 0) + || (finfo.external_relocs == NULL && max_reloc_count > 0) + || (! info->relocateable + && finfo.internal_relocs == NULL + && max_reloc_count > 0)) + goto error_return; + + /* We now know the position of everything in the file, except that + we don't know the size of the symbol table and therefore we don't + know where the string table starts. We just build the string + table in memory as we go along. We process all the relocations + for a single input file at once. */ + obj_raw_syment_count (abfd) = 0; + + if (coff_backend_info (abfd)->_bfd_coff_start_final_link) + { + if (! bfd_coff_start_final_link (abfd, info)) + goto error_return; + } + + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_coff_flavour)) + { + sub = p->u.indirect.section->owner; + if (! sub->output_has_begun) + { + if (! _bfd_coff_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* Free up the buffers used by _bfd_coff_link_input_bfd. */ + + coff_debug_merge_hash_table_free (&finfo.debug_merge); + debug_merge_allocated = false; + + if (finfo.internal_syms != NULL) + { + free (finfo.internal_syms); + finfo.internal_syms = NULL; + } + if (finfo.sec_ptrs != NULL) + { + free (finfo.sec_ptrs); + finfo.sec_ptrs = NULL; + } + if (finfo.sym_indices != NULL) + { + free (finfo.sym_indices); + finfo.sym_indices = NULL; + } + if (finfo.linenos != NULL) + { + free (finfo.linenos); + finfo.linenos = NULL; + } + if (finfo.contents != NULL) + { + free (finfo.contents); + finfo.contents = NULL; + } + if (finfo.external_relocs != NULL) + { + free (finfo.external_relocs); + finfo.external_relocs = NULL; + } + if (finfo.internal_relocs != NULL) + { + free (finfo.internal_relocs); + finfo.internal_relocs = NULL; + } + + /* The value of the last C_FILE symbol is supposed to be the symbol + index of the first external symbol. Write it out again if + necessary. */ + if (finfo.last_file_index != -1 + && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd)) + { + finfo.last_file.n_value = obj_raw_syment_count (abfd); + bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file, + (PTR) finfo.outsyms); + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + finfo.last_file_index * symesz), + SEEK_SET) != 0 + || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz) + return false; + } + + /* Write out the global symbols. */ + finfo.failed = false; + coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym, + (PTR) &finfo); + if (finfo.failed) + goto error_return; + + /* The outsyms buffer is used by _bfd_coff_write_global_sym. */ + if (finfo.outsyms != NULL) + { + free (finfo.outsyms); + finfo.outsyms = NULL; + } + + if (info->relocateable) + { + /* Now that we have written out all the global symbols, we know + the symbol indices to use for relocs against them, and we can + finally write out the relocs. */ + external_relocs = ((bfd_byte *) + bfd_malloc (max_output_reloc_count * relsz)); + if (external_relocs == NULL) + goto error_return; + + for (o = abfd->sections; o != NULL; o = o->next) + { + struct internal_reloc *irel; + struct internal_reloc *irelend; + struct coff_link_hash_entry **rel_hash; + bfd_byte *erel; + + if (o->reloc_count == 0) + continue; + + irel = finfo.section_info[o->target_index].relocs; + irelend = irel + o->reloc_count; + rel_hash = finfo.section_info[o->target_index].rel_hashes; + erel = external_relocs; + for (; irel < irelend; irel++, rel_hash++, erel += relsz) + { + if (*rel_hash != NULL) + { + BFD_ASSERT ((*rel_hash)->indx >= 0); + irel->r_symndx = (*rel_hash)->indx; + } + bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel); + } + + if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0 + || bfd_write ((PTR) external_relocs, relsz, o->reloc_count, + abfd) != relsz * o->reloc_count) + goto error_return; + } + + free (external_relocs); + external_relocs = NULL; + } + + /* Free up the section information. */ + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + finfo.section_info = NULL; + } + + /* Write out the string table. */ + if (obj_raw_syment_count (abfd) != 0) + { + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + obj_raw_syment_count (abfd) * symesz), + SEEK_SET) != 0) + return false; + +#if STRING_SIZE_SIZE == 4 + bfd_h_put_32 (abfd, + _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE, + (bfd_byte *) strbuf); +#else + #error Change bfd_h_put_32 +#endif + + if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE) + return false; + + if (! _bfd_stringtab_emit (abfd, finfo.strtab)) + return false; + } + + _bfd_stringtab_free (finfo.strtab); + + /* Setting bfd_get_symcount to 0 will cause write_object_contents to + not try to write out the symbols. */ + bfd_get_symcount (abfd) = 0; + + return true; + + error_return: + if (debug_merge_allocated) + coff_debug_merge_hash_table_free (&finfo.debug_merge); + if (finfo.strtab != NULL) + _bfd_stringtab_free (finfo.strtab); + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + } + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.sec_ptrs != NULL) + free (finfo.sec_ptrs); + if (finfo.sym_indices != NULL) + free (finfo.sym_indices); + if (finfo.outsyms != NULL) + free (finfo.outsyms); + if (finfo.linenos != NULL) + free (finfo.linenos); + 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 (external_relocs != NULL) + free (external_relocs); + return false; +} + +/* parse out a -heap , line */ + +static char * +dores_com (ptr, output_bfd, heap) + char *ptr; + bfd *output_bfd; + int heap; +{ + if (coff_data(output_bfd)->pe) + { + int val = strtoul (ptr, &ptr, 0); + if (heap) + pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve =val; + else + pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve =val; + + if (ptr[0] == ',') + { + int val = strtoul (ptr+1, &ptr, 0); + if (heap) + pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit =val; + else + pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit =val; + } + } + return ptr; +} + +static char *get_name(ptr, dst) +char *ptr; +char **dst; +{ + while (*ptr == ' ') + ptr++; + *dst = ptr; + while (*ptr && *ptr != ' ') + ptr++; + *ptr = 0; + return ptr+1; +} + +/* Process any magic embedded commands in a section called .drectve */ + +static int +process_embedded_commands (output_bfd, info, abfd) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *abfd; +{ + asection *sec = bfd_get_section_by_name (abfd, ".drectve"); + char *s; + char *e; + char *copy; + if (!sec) + return 1; + + copy = bfd_malloc ((size_t) sec->_raw_size); + if (!copy) + return 0; + if (! bfd_get_section_contents(abfd, sec, copy, 0, sec->_raw_size)) + { + free (copy); + return 0; + } + e = copy + sec->_raw_size; + for (s = copy; s < e ; ) + { + if (s[0]!= '-') { + s++; + continue; + } + if (strncmp (s,"-attr", 5) == 0) + { + char *name; + char *attribs; + asection *asec; + + int loop = 1; + int had_write = 0; + int had_read = 0; + int had_exec= 0; + int had_shared= 0; + s += 5; + s = get_name(s, &name); + s = get_name(s, &attribs); + while (loop) { + switch (*attribs++) + { + case 'W': + had_write = 1; + break; + case 'R': + had_read = 1; + break; + case 'S': + had_shared = 1; + break; + case 'X': + had_exec = 1; + break; + default: + loop = 0; + } + } + asec = bfd_get_section_by_name (abfd, name); + if (asec) { + if (had_exec) + asec->flags |= SEC_CODE; + if (!had_write) + asec->flags |= SEC_READONLY; + } + } + else if (strncmp (s,"-heap", 5) == 0) + { + s = dores_com (s+5, output_bfd, 1); + } + else if (strncmp (s,"-stack", 6) == 0) + { + s = dores_com (s+6, output_bfd, 0); + } + else + s++; + } + free (copy); + return 1; +} + +/* Link an input file into the linker output file. This function + handles all the sections and relocations of the input file at once. */ + +boolean +_bfd_coff_link_input_bfd (finfo, input_bfd) + struct coff_final_link_info *finfo; + bfd *input_bfd; +{ + boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); + boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *, + asection *, struct internal_reloc *, + boolean *)); + bfd *output_bfd; + const char *strings; + bfd_size_type syment_base; + unsigned int n_tmask; + unsigned int n_btshft; + boolean copy, hash; + bfd_size_type isymesz; + bfd_size_type osymesz; + bfd_size_type linesz; + bfd_byte *esym; + bfd_byte *esym_end; + struct internal_syment *isymp; + asection **secpp; + long *indexp; + unsigned long output_index; + bfd_byte *outsym; + struct coff_link_hash_entry **sym_hash; + asection *o; + + /* Move all the symbols to the output file. */ + + output_bfd = finfo->output_bfd; + sym_is_global = coff_backend_info (input_bfd)->_bfd_coff_sym_is_global; + strings = NULL; + syment_base = obj_raw_syment_count (output_bfd); + isymesz = bfd_coff_symesz (input_bfd); + osymesz = bfd_coff_symesz (output_bfd); + linesz = bfd_coff_linesz (input_bfd); + BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd)); + + n_tmask = coff_data (input_bfd)->local_n_tmask; + n_btshft = coff_data (input_bfd)->local_n_btshft; + + /* Define macros so that ISFCN, et. al., macros work correctly. */ +#define N_TMASK n_tmask +#define N_BTSHFT n_btshft + + copy = false; + if (! finfo->info->keep_memory) + copy = true; + hash = true; + if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) + hash = false; + + if (! _bfd_coff_get_external_symbols (input_bfd)) + return false; + + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; + isymp = finfo->internal_syms; + secpp = finfo->sec_ptrs; + indexp = finfo->sym_indices; + output_index = syment_base; + outsym = finfo->outsyms; + + if (coff_data(output_bfd)->pe) + { + if (!process_embedded_commands (output_bfd, finfo->info, input_bfd)) + return false; + } + + while (esym < esym_end) + { + struct internal_syment isym; + boolean skip; + boolean global; + int add; + + bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp); + + /* Make a copy of *isymp so that the relocate_section function + always sees the original values. This is more reliable than + always recomputing the symbol value even if we are stripping + the symbol. */ + isym = *isymp; + + if (isym.n_scnum != 0) + *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum); + else + { + if (isym.n_value == 0) + *secpp = bfd_und_section_ptr; + else + *secpp = bfd_com_section_ptr; + } + + *indexp = -1; + + skip = false; + global = false; + add = 1 + isym.n_numaux; + + /* If we are stripping all symbols, we want to skip this one. */ + if (finfo->info->strip == strip_all) + skip = true; + + if (! skip) + { + if (isym.n_sclass == C_EXT + || (sym_is_global && (*sym_is_global) (input_bfd, &isym))) + { + /* This is a global symbol. Global symbols come at the + end of the symbol table, so skip them for now. + Function symbols, however, are an exception, and are + not moved to the end. */ + global = true; + if (! ISFCN (isym.n_type)) + skip = true; + } + else + { + /* This is a local symbol. Skip it if we are discarding + local symbols. */ + if (finfo->info->discard == discard_all) + skip = true; + } + } + + /* If we stripping debugging symbols, and this is a debugging + symbol, then skip it. */ + if (! skip + && finfo->info->strip == strip_debugger + && isym.n_scnum == N_DEBUG) + skip = true; + + /* If some symbols are stripped based on the name, work out the + name and decide whether to skip this symbol. */ + if (! skip + && (finfo->info->strip == strip_some + || finfo->info->discard == discard_l)) + { + const char *name; + char buf[SYMNMLEN + 1]; + + name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); + if (name == NULL) + return false; + + if ((finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, name, false, + false) == NULL)) + || (! global + && finfo->info->discard == discard_l + && strncmp (name, finfo->info->lprefix, + finfo->info->lprefix_len) == 0)) + skip = true; + } + + /* If this is an enum, struct, or union tag, see if we have + already output an identical type. */ + if (! skip + && (finfo->output_bfd->flags & BFD_TRADITIONAL_FORMAT) == 0 + && (isym.n_sclass == C_ENTAG + || isym.n_sclass == C_STRTAG + || isym.n_sclass == C_UNTAG) + && isym.n_numaux == 1) + { + const char *name; + char buf[SYMNMLEN + 1]; + struct coff_debug_merge_hash_entry *mh; + struct coff_debug_merge_type *mt; + union internal_auxent aux; + struct coff_debug_merge_element **epp; + bfd_byte *esl, *eslend; + struct internal_syment *islp; + + name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); + if (name == NULL) + return false; + + /* Ignore fake names invented by compiler; treat them all as + the same name. */ + if (*name == '~' || *name == '.' || *name == '$' + || (*name == bfd_get_symbol_leading_char (input_bfd) + && (name[1] == '~' || name[1] == '.' || name[1] == '$'))) + name = ""; + + mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name, + true, true); + if (mh == NULL) + return false; + + /* Allocate memory to hold type information. If this turns + out to be a duplicate, we pass this address to + bfd_release. */ + mt = ((struct coff_debug_merge_type *) + bfd_alloc (input_bfd, + sizeof (struct coff_debug_merge_type))); + if (mt == NULL) + return false; + mt->class = isym.n_sclass; + + /* Pick up the aux entry, which points to the end of the tag + entries. */ + bfd_coff_swap_aux_in (input_bfd, (PTR) (esym + isymesz), + isym.n_type, isym.n_sclass, 0, isym.n_numaux, + (PTR) &aux); + + /* Gather the elements. */ + epp = &mt->elements; + mt->elements = NULL; + islp = isymp + 2; + esl = esym + 2 * isymesz; + eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd) + + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz); + while (esl < eslend) + { + const char *elename; + char elebuf[SYMNMLEN + 1]; + char *copy; + + bfd_coff_swap_sym_in (input_bfd, (PTR) esl, (PTR) islp); + + *epp = ((struct coff_debug_merge_element *) + bfd_alloc (input_bfd, + sizeof (struct coff_debug_merge_element))); + if (*epp == NULL) + return false; + + elename = _bfd_coff_internal_syment_name (input_bfd, islp, + elebuf); + if (elename == NULL) + return false; + + copy = (char *) bfd_alloc (input_bfd, strlen (elename) + 1); + if (copy == NULL) + return false; + strcpy (copy, elename); + + (*epp)->name = copy; + (*epp)->type = islp->n_type; + (*epp)->tagndx = 0; + if (islp->n_numaux >= 1 + && islp->n_type != T_NULL + && islp->n_sclass != C_EOS) + { + union internal_auxent eleaux; + long indx; + + bfd_coff_swap_aux_in (input_bfd, (PTR) (esl + isymesz), + islp->n_type, islp->n_sclass, 0, + islp->n_numaux, (PTR) &eleaux); + indx = eleaux.x_sym.x_tagndx.l; + + /* FIXME: If this tagndx entry refers to a symbol + defined later in this file, we just ignore it. + Handling this correctly would be tedious, and may + not be required. */ + + if (indx > 0 + && (indx + < ((esym - + (bfd_byte *) obj_coff_external_syms (input_bfd)) + / (long) isymesz))) + { + (*epp)->tagndx = finfo->sym_indices[indx]; + if ((*epp)->tagndx < 0) + (*epp)->tagndx = 0; + } + } + epp = &(*epp)->next; + *epp = NULL; + + esl += (islp->n_numaux + 1) * isymesz; + islp += islp->n_numaux + 1; + } + + /* See if we already have a definition which matches this + type. We always output the type if it has no elements, + for simplicity. */ + if (mt->elements == NULL) + bfd_release (input_bfd, (PTR) mt); + else + { + struct coff_debug_merge_type *mtl; + + for (mtl = mh->types; mtl != NULL; mtl = mtl->next) + { + struct coff_debug_merge_element *me, *mel; + + if (mtl->class != mt->class) + continue; + + for (me = mt->elements, mel = mtl->elements; + me != NULL && mel != NULL; + me = me->next, mel = mel->next) + { + if (strcmp (me->name, mel->name) != 0 + || me->type != mel->type + || me->tagndx != mel->tagndx) + break; + } + + if (me == NULL && mel == NULL) + break; + } + + if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base) + { + /* This is the first definition of this type. */ + mt->indx = output_index; + mt->next = mh->types; + mh->types = mt; + } + else + { + /* This is a redefinition which can be merged. */ + bfd_release (input_bfd, (PTR) mt); + *indexp = mtl->indx; + add = (eslend - esym) / isymesz; + skip = true; + } + } + } + + /* We now know whether we are to skip this symbol or not. */ + if (! skip) + { + /* Adjust the symbol in order to output it. */ + + if (isym._n._n_n._n_zeroes == 0 + && isym._n._n_n._n_offset != 0) + { + const char *name; + bfd_size_type indx; + + /* This symbol has a long name. Enter it in the string + table we are building. Note that we do not check + bfd_coff_symname_in_debug. That is only true for + XCOFF, and XCOFF requires different linking code + anyhow. */ + name = _bfd_coff_internal_syment_name (input_bfd, &isym, + (char *) NULL); + if (name == NULL) + return false; + indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy); + if (indx == (bfd_size_type) -1) + return false; + isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; + } + + if (isym.n_scnum > 0) + { + isym.n_scnum = (*secpp)->output_section->target_index; + isym.n_value += ((*secpp)->output_section->vma + + (*secpp)->output_offset + - (*secpp)->vma); + } + + /* The value of a C_FILE symbol is the symbol index of the + next C_FILE symbol. The value of the last C_FILE symbol + is the symbol index to the first external symbol + (actually, coff_renumber_symbols does not get this + right--it just sets the value of the last C_FILE symbol + to zero--and nobody has ever complained about it). We + try to get this right, below, just before we write the + symbols out, but in the general case we may have to write + the symbol out twice. */ + if (isym.n_sclass == C_FILE) + { + if (finfo->last_file_index != -1 + && finfo->last_file.n_value != (long) output_index) + { + /* We must correct the value of the last C_FILE entry. */ + finfo->last_file.n_value = output_index; + if ((bfd_size_type) finfo->last_file_index >= syment_base) + { + /* The last C_FILE symbol is in this input file. */ + bfd_coff_swap_sym_out (output_bfd, + (PTR) &finfo->last_file, + (PTR) (finfo->outsyms + + ((finfo->last_file_index + - syment_base) + * osymesz))); + } + else + { + /* We have already written out the last C_FILE + symbol. We need to write it out again. We + borrow *outsym temporarily. */ + bfd_coff_swap_sym_out (output_bfd, + (PTR) &finfo->last_file, + (PTR) outsym); + if (bfd_seek (output_bfd, + (obj_sym_filepos (output_bfd) + + finfo->last_file_index * osymesz), + SEEK_SET) != 0 + || (bfd_write (outsym, osymesz, 1, output_bfd) + != osymesz)) + return false; + } + } + + finfo->last_file_index = output_index; + finfo->last_file = isym; + } + + /* Output the symbol. */ + + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym); + + *indexp = output_index; + + if (global) + { + long indx; + struct coff_link_hash_entry *h; + + indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) + / isymesz); + h = obj_coff_sym_hashes (input_bfd)[indx]; + BFD_ASSERT (h != NULL); + h->indx = output_index; + } + + output_index += add; + outsym += add * osymesz; + } + + esym += add * isymesz; + isymp += add; + ++secpp; + ++indexp; + for (--add; add > 0; --add) + { + *secpp++ = NULL; + *indexp++ = -1; + } + } + + /* Fix up the aux entries. This must be done in a separate pass, + because we don't know the correct symbol indices until we have + already decided which symbols we are going to keep. */ + + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; + isymp = finfo->internal_syms; + indexp = finfo->sym_indices; + sym_hash = obj_coff_sym_hashes (input_bfd); + outsym = finfo->outsyms; + while (esym < esym_end) + { + int add; + + add = 1 + isymp->n_numaux; + + if ((*indexp < 0 + || (bfd_size_type) *indexp < syment_base) + && (*sym_hash == NULL + || (*sym_hash)->auxbfd != input_bfd)) + esym += add * isymesz; + else + { + struct coff_link_hash_entry *h; + int i; + + h = NULL; + if (*indexp < 0) + { + h = *sym_hash; + BFD_ASSERT (h->numaux == isymp->n_numaux); + } + + esym += isymesz; + + if (h == NULL) + outsym += osymesz; + + /* Handle the aux entries. This handling is based on + coff_pointerize_aux. I don't know if it always correct. */ + for (i = 0; i < isymp->n_numaux && esym < esym_end; i++) + { + union internal_auxent aux; + union internal_auxent *auxp; + + if (h != NULL) + auxp = h->aux + i; + else + { + bfd_coff_swap_aux_in (input_bfd, (PTR) esym, isymp->n_type, + isymp->n_sclass, i, isymp->n_numaux, + (PTR) &aux); + auxp = &aux; + } + + if (isymp->n_sclass == C_FILE) + { + /* If this is a long filename, we must put it in the + string table. */ + if (auxp->x_file.x_n.x_zeroes == 0 + && auxp->x_file.x_n.x_offset != 0) + { + const char *filename; + bfd_size_type indx; + + BFD_ASSERT (auxp->x_file.x_n.x_offset + >= STRING_SIZE_SIZE); + if (strings == NULL) + { + strings = _bfd_coff_read_string_table (input_bfd); + if (strings == NULL) + return false; + } + filename = strings + auxp->x_file.x_n.x_offset; + indx = _bfd_stringtab_add (finfo->strtab, filename, + hash, copy); + if (indx == (bfd_size_type) -1) + return false; + auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; + } + } + else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) + { + unsigned long indx; + + if (ISFCN (isymp->n_type) + || ISTAG (isymp->n_sclass) + || isymp->n_sclass == C_BLOCK) + { + indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l; + if (indx > 0 + && indx < obj_raw_syment_count (input_bfd)) + { + /* We look forward through the symbol for + the index of the next symbol we are going + to include. I don't know if this is + entirely right. */ + while ((finfo->sym_indices[indx] < 0 + || ((bfd_size_type) finfo->sym_indices[indx] + < syment_base)) + && indx < obj_raw_syment_count (input_bfd)) + ++indx; + if (indx >= obj_raw_syment_count (input_bfd)) + indx = output_index; + else + indx = finfo->sym_indices[indx]; + auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx; + } + } + + indx = auxp->x_sym.x_tagndx.l; + if (indx > 0 && indx < obj_raw_syment_count (input_bfd)) + { + long symindx; + + symindx = finfo->sym_indices[indx]; + if (symindx < 0) + auxp->x_sym.x_tagndx.l = 0; + else + auxp->x_sym.x_tagndx.l = symindx; + } + } + + if (h == NULL) + { + bfd_coff_swap_aux_out (output_bfd, (PTR) auxp, isymp->n_type, + isymp->n_sclass, i, isymp->n_numaux, + (PTR) outsym); + outsym += osymesz; + } + + esym += isymesz; + } + } + + indexp += add; + isymp += add; + sym_hash += add; + } + + /* Relocate the line numbers, unless we are stripping them. */ + if (finfo->info->strip == strip_none + || finfo->info->strip == strip_some) + { + for (o = input_bfd->sections; o != NULL; o = o->next) + { + bfd_vma offset; + bfd_byte *eline; + bfd_byte *elineend; + + /* FIXME: If SEC_HAS_CONTENTS is not for the section, then + build_link_order in ldwrite.c will not have created a + link order, which means that we will not have seen this + input section in _bfd_coff_final_link, which means that + we will not have allocated space for the line numbers of + this section. I don't think line numbers can be + meaningful for a section which does not have + SEC_HAS_CONTENTS set, but, if they do, this must be + changed. */ + if (o->lineno_count == 0 + || (o->output_section->flags & SEC_HAS_CONTENTS) == 0) + continue; + + if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0 + || bfd_read (finfo->linenos, linesz, o->lineno_count, + input_bfd) != linesz * o->lineno_count) + return false; + + offset = o->output_section->vma + o->output_offset - o->vma; + eline = finfo->linenos; + elineend = eline + linesz * o->lineno_count; + for (; eline < elineend; eline += linesz) + { + struct internal_lineno iline; + + bfd_coff_swap_lineno_in (input_bfd, (PTR) eline, (PTR) &iline); + + if (iline.l_lnno != 0) + iline.l_addr.l_paddr += offset; + else if (iline.l_addr.l_symndx >= 0 + && ((unsigned long) iline.l_addr.l_symndx + < obj_raw_syment_count (input_bfd))) + { + long indx; + + indx = finfo->sym_indices[iline.l_addr.l_symndx]; + + if (indx < 0) + { + /* These line numbers are attached to a symbol + which we are stripping. We should really + just discard the line numbers, but that would + be a pain because we have already counted + them. */ + indx = 0; + } + else + { + struct internal_syment is; + union internal_auxent ia; + + /* Fix up the lnnoptr field in the aux entry of + the symbol. It turns out that we can't do + this when we modify the symbol aux entries, + because gas sometimes screws up the lnnoptr + field and makes it an offset from the start + of the line numbers rather than an absolute + file index. */ + bfd_coff_swap_sym_in (output_bfd, + (PTR) (finfo->outsyms + + ((indx - syment_base) + * osymesz)), + (PTR) &is); + if ((ISFCN (is.n_type) + || is.n_sclass == C_BLOCK) + && is.n_numaux >= 1) + { + PTR auxptr; + + auxptr = (PTR) (finfo->outsyms + + ((indx - syment_base + 1) + * osymesz)); + bfd_coff_swap_aux_in (output_bfd, auxptr, + is.n_type, is.n_sclass, + 0, is.n_numaux, (PTR) &ia); + ia.x_sym.x_fcnary.x_fcn.x_lnnoptr = + (o->output_section->line_filepos + + o->output_section->lineno_count * linesz + + eline - finfo->linenos); + bfd_coff_swap_aux_out (output_bfd, (PTR) &ia, + is.n_type, is.n_sclass, 0, + is.n_numaux, auxptr); + } + } + + iline.l_addr.l_symndx = indx; + } + + bfd_coff_swap_lineno_out (output_bfd, (PTR) &iline, (PTR) eline); + } + + if (bfd_seek (output_bfd, + (o->output_section->line_filepos + + o->output_section->lineno_count * linesz), + SEEK_SET) != 0 + || bfd_write (finfo->linenos, linesz, o->lineno_count, + output_bfd) != linesz * o->lineno_count) + return false; + + o->output_section->lineno_count += o->lineno_count; + } + } + + /* If we swapped out a C_FILE symbol, guess that the next C_FILE + symbol will be the first symbol in the next input file. In the + normal case, this will save us from writing out the C_FILE symbol + again. */ + if (finfo->last_file_index != -1 + && (bfd_size_type) finfo->last_file_index >= syment_base) + { + finfo->last_file.n_value = output_index; + bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file, + (PTR) (finfo->outsyms + + ((finfo->last_file_index - syment_base) + * osymesz))); + } + + /* Write the modified symbols to the output file. */ + if (outsym > finfo->outsyms) + { + if (bfd_seek (output_bfd, + obj_sym_filepos (output_bfd) + syment_base * osymesz, + SEEK_SET) != 0 + || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1, + output_bfd) + != (bfd_size_type) (outsym - finfo->outsyms))) + return false; + + BFD_ASSERT ((obj_raw_syment_count (output_bfd) + + (outsym - finfo->outsyms) / osymesz) + == output_index); + + obj_raw_syment_count (output_bfd) = output_index; + } + + /* Relocate the contents of each section. */ + adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx; + for (o = input_bfd->sections; o != NULL; o = o->next) + { + bfd_byte *contents; + + if ((o->flags & SEC_HAS_CONTENTS) == 0) + { + if ((o->flags & SEC_RELOC) != 0 + && o->reloc_count != 0) + { + ((*_bfd_error_handler) + ("%s: relocs in section `%s', but it has no contents", + bfd_get_filename (input_bfd), + bfd_get_section_name (input_bfd, o))); + bfd_set_error (bfd_error_no_contents); + return false; + } + + continue; + } + + if (coff_section_data (input_bfd, o) != NULL + && coff_section_data (input_bfd, o)->contents != NULL) + contents = coff_section_data (input_bfd, o)->contents; + else + { + if (! bfd_get_section_contents (input_bfd, o, finfo->contents, + (file_ptr) 0, o->_raw_size)) + return false; + contents = finfo->contents; + } + + if ((o->flags & SEC_RELOC) != 0) + { + int target_index; + struct internal_reloc *internal_relocs; + struct internal_reloc *irel; + + /* Read in the relocs. */ + target_index = o->output_section->target_index; + internal_relocs = (_bfd_coff_read_internal_relocs + (input_bfd, o, false, finfo->external_relocs, + finfo->info->relocateable, + (finfo->info->relocateable + ? (finfo->section_info[target_index].relocs + + o->output_section->reloc_count) + : finfo->internal_relocs))); + if (internal_relocs == NULL) + return false; + + /* Call processor specific code to relocate the section + contents. */ + if (! bfd_coff_relocate_section (output_bfd, finfo->info, + input_bfd, o, + contents, + internal_relocs, + finfo->internal_syms, + finfo->sec_ptrs)) + return false; + + if (finfo->info->relocateable) + { + bfd_vma offset; + struct internal_reloc *irelend; + struct coff_link_hash_entry **rel_hash; + + offset = o->output_section->vma + o->output_offset - o->vma; + irel = internal_relocs; + irelend = irel + o->reloc_count; + rel_hash = (finfo->section_info[target_index].rel_hashes + + o->output_section->reloc_count); + for (; irel < irelend; irel++, rel_hash++) + { + struct coff_link_hash_entry *h; + boolean adjusted; + + *rel_hash = NULL; + + /* Adjust the reloc address and symbol index. */ + + irel->r_vaddr += offset; + + if (irel->r_symndx == -1) + continue; + + if (adjust_symndx) + { + if (! (*adjust_symndx) (output_bfd, finfo->info, + input_bfd, o, irel, + &adjusted)) + return false; + if (adjusted) + continue; + } + + h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx]; + if (h != NULL) + { + /* This is a global symbol. */ + if (h->indx >= 0) + irel->r_symndx = h->indx; + else + { + /* This symbol is being written at the end + of the file, and we do not yet know the + symbol index. We save the pointer to the + hash table entry in the rel_hash list. + We set the indx field to -2 to indicate + that this symbol must not be stripped. */ + *rel_hash = h; + h->indx = -2; + } + } + else + { + long indx; + + indx = finfo->sym_indices[irel->r_symndx]; + if (indx != -1) + irel->r_symndx = indx; + else + { + struct internal_syment *is; + const char *name; + char buf[SYMNMLEN + 1]; + + /* This reloc is against a symbol we are + stripping. It would be possible to + handle this case, but I don't think it's + worth it. */ + is = finfo->internal_syms + irel->r_symndx; + + name = (_bfd_coff_internal_syment_name + (input_bfd, is, buf)); + if (name == NULL) + return false; + + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, name, input_bfd, o, + irel->r_vaddr))) + return false; + } + } + } + + o->output_section->reloc_count += o->reloc_count; + } + } + + /* Write out the modified section contents. */ + if (! bfd_set_section_contents (output_bfd, o->output_section, + contents, o->output_offset, + (o->_cooked_size != 0 + ? o->_cooked_size + : o->_raw_size))) + return false; + } + + if (! finfo->info->keep_memory) + { + if (! _bfd_coff_free_symbols (input_bfd)) + return false; + } + + return true; +} + +/* Write out a global symbol. Called via coff_link_hash_traverse. */ + +boolean +_bfd_coff_write_global_sym (h, data) + struct coff_link_hash_entry *h; + PTR data; +{ + struct coff_final_link_info *finfo = (struct coff_final_link_info *) data; + bfd *output_bfd; + struct internal_syment isym; + bfd_size_type symesz; + unsigned int i; + + output_bfd = finfo->output_bfd; + + if (h->indx >= 0) + return true; + + if (h->indx != -2 + && (finfo->info->strip == strip_all + || (finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, + h->root.root.string, false, false) + == NULL)))) + return true; + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + return false; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + isym.n_scnum = N_UNDEF; + isym.n_value = 0; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + { + asection *sec; + + sec = h->root.u.def.section->output_section; + if (bfd_is_abs_section (sec)) + isym.n_scnum = N_ABS; + else + isym.n_scnum = sec->target_index; + isym.n_value = (h->root.u.def.value + + sec->vma + + h->root.u.def.section->output_offset); + } + break; + + case bfd_link_hash_common: + isym.n_scnum = N_UNDEF; + isym.n_value = h->root.u.c.size; + break; + + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* Just ignore these. They can't be handled anyhow. */ + return true; + } + + if (strlen (h->root.root.string) <= SYMNMLEN) + strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN); + else + { + boolean hash; + bfd_size_type indx; + + hash = true; + if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) + hash = false; + indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string, hash, + false); + if (indx == (bfd_size_type) -1) + { + finfo->failed = true; + return false; + } + isym._n._n_n._n_zeroes = 0; + isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; + } + + isym.n_sclass = h->class; + isym.n_type = h->type; + + if (isym.n_sclass == C_NULL) + isym.n_sclass = C_EXT; + + isym.n_numaux = h->numaux; + + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) finfo->outsyms); + + symesz = bfd_coff_symesz (output_bfd); + + if (bfd_seek (output_bfd, + (obj_sym_filepos (output_bfd) + + obj_raw_syment_count (output_bfd) * symesz), + SEEK_SET) != 0 + || bfd_write (finfo->outsyms, symesz, 1, output_bfd) != symesz) + { + finfo->failed = true; + return false; + } + + h->indx = obj_raw_syment_count (output_bfd); + + ++obj_raw_syment_count (output_bfd); + + /* Write out any associated aux entries. There normally will be + none. If there are any, I have no idea how to modify them. */ + for (i = 0; i < isym.n_numaux; i++) + { + bfd_coff_swap_aux_out (output_bfd, (PTR) (h->aux + i), isym.n_type, + isym.n_sclass, i, isym.n_numaux, + (PTR) finfo->outsyms); + if (bfd_write (finfo->outsyms, symesz, 1, output_bfd) != symesz) + { + finfo->failed = true; + return false; + } + ++obj_raw_syment_count (output_bfd); + } + + return true; +} + +/* Handle a link order which is supposed to generate a reloc. */ + +boolean +_bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order) + bfd *output_bfd; + struct coff_final_link_info *finfo; + asection *output_section; + struct bfd_link_order *link_order; +{ + reloc_howto_type *howto; + struct internal_reloc *irel; + struct coff_link_hash_entry **rel_hash_ptr; + + howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (link_order->u.reloc.p->addend != 0) + { + bfd_size_type size; + bfd_byte *buf; + bfd_reloc_status_type rstat; + boolean ok; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == NULL) + return false; + + rstat = _bfd_relocate_contents (howto, output_bfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*finfo->info->callbacks->reloc_overflow) + (finfo->info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, + link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + /* Store the reloc information in the right place. It will get + swapped and written out at the end of the final_link routine. */ + + irel = (finfo->section_info[output_section->target_index].relocs + + output_section->reloc_count); + rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes + + output_section->reloc_count); + + memset (irel, 0, sizeof (struct internal_reloc)); + *rel_hash_ptr = NULL; + + irel->r_vaddr = output_section->vma + link_order->offset; + + if (link_order->type == bfd_section_reloc_link_order) + { + /* We need to somehow locate a symbol in the right section. The + symbol must either have a value of zero, or we must adjust + the addend by the value of the symbol. FIXME: Write this + when we need it. The old linker couldn't handle this anyhow. */ + abort (); + *rel_hash_ptr = NULL; + irel->r_symndx = 0; + } + else + { + struct coff_link_hash_entry *h; + + h = ((struct coff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, finfo->info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h != NULL) + { + if (h->indx >= 0) + irel->r_symndx = h->indx; + else + { + /* Set the index to -2 to force this symbol to get + written out. */ + h->indx = -2; + *rel_hash_ptr = h; + irel->r_symndx = 0; + } + } + else + { + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + irel->r_symndx = 0; + } + } + + /* FIXME: Is this always right? */ + irel->r_type = howto->type; + + /* r_size is only used on the RS/6000, which needs its own linker + routines anyhow. r_extern is only used for ECOFF. */ + + /* FIXME: What is the right value for r_offset? Is zero OK? */ + + ++output_section->reloc_count; + + return true; +} + +/* A basic reloc handling routine which may be used by processors with + simple relocs. */ + +boolean +_bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, + input_section, contents, relocs, syms, + sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + struct coff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma addend; + bfd_vma val; + reloc_howto_type *howto; + bfd_reloc_status_type rstat; + + symndx = rel->r_symndx; + + if (symndx == -1) + { + h = NULL; + sym = NULL; + } + else + { + h = obj_coff_sym_hashes (input_bfd)[symndx]; + sym = syms + symndx; + } + + /* COFF treats common symbols in one of two ways. Either the + size of the symbol is included in the section contents, or it + is not. We assume that the size is not included, and force + the rtype_to_howto function to adjust the addend as needed. */ + + if (sym != NULL && sym->n_scnum != 0) + addend = - sym->n_value; + else + addend = 0; + + + howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, + sym, &addend); + if (howto == NULL) + return false; + + val = 0; + + if (h == NULL) + { + asection *sec; + + if (symndx == -1) + { + sec = bfd_abs_section_ptr; + val = 0; + } + else + { + sec = sections[symndx]; + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *sec; + + sec = h->root.u.def.section; + val = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + + else if (! info->relocateable) + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + if (info->base_file) + { + /* Emit a reloc if the backend thinks it needs it. */ + if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)) + { + /* relocation to a symbol in a section which + isn't absolute - we output the address here + to a file */ + bfd_vma addr = rel->r_vaddr + - input_section->vma + + input_section->output_offset + + input_section->output_section->vma; + if (coff_data(output_bfd)->pe) + addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; + fwrite (&addr, 1,4, (FILE *) info->base_file); + } + } + + rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, + rel->r_vaddr - input_section->vma, + val, addend); + + switch (rstat) + { + default: + abort (); + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + { + const char *name; + char buf[SYMNMLEN + 1]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.string; + else + { + name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); + if (name == NULL) + return false; + } + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + } + } + } + return true; +} + diff --git a/contrib/gdb/bfd/coffswap.h b/contrib/gdb/bfd/coffswap.h new file mode 100644 index 000000000000..ef1b6b3a913e --- /dev/null +++ b/contrib/gdb/bfd/coffswap.h @@ -0,0 +1,807 @@ +/* Generic COFF swapping routines, for BFD. + Copyright 1990, 1991, 1992, 1993, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains routines used to swap COFF data. It is a header + file because the details of swapping depend on the details of the + structures used by each COFF implementation. This is included by + coffcode.h, as well as by the ECOFF backend. + + Any file which uses this must first include "coff/internal.h" and + "coff/CPU.h". The functions will then be correct for that CPU. */ + +#ifndef IMAGE_BASE +#define IMAGE_BASE 0 +#endif + +#define PUTWORD bfd_h_put_32 +#define PUTHALF bfd_h_put_16 +#define PUTBYTE bfd_h_put_8 + +#ifndef GET_FCN_LNNOPTR +#define GET_FCN_LNNOPTR(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif + +#ifndef GET_FCN_ENDNDX +#define GET_FCN_ENDNDX(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif + +#ifndef PUT_FCN_LNNOPTR +#define PUT_FCN_LNNOPTR(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif +#ifndef PUT_FCN_ENDNDX +#define PUT_FCN_ENDNDX(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif +#ifndef GET_LNSZ_LNNO +#define GET_LNSZ_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef GET_LNSZ_SIZE +#define GET_LNSZ_SIZE(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef PUT_LNSZ_LNNO +#define PUT_LNSZ_LNNO(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef PUT_LNSZ_SIZE +#define PUT_LNSZ_SIZE(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte*) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef GET_SCN_SCNLEN +#define GET_SCN_SCNLEN(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef GET_SCN_NRELOC +#define GET_SCN_NRELOC(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef GET_SCN_NLINNO +#define GET_SCN_NLINNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nlinno) +#endif +#ifndef PUT_SCN_SCNLEN +#define PUT_SCN_SCNLEN(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef PUT_SCN_NRELOC +#define PUT_SCN_NRELOC(abfd,in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef PUT_SCN_NLINNO +#define PUT_SCN_NLINNO(abfd,in, ext) bfd_h_put_16(abfd,in, (bfd_byte *) ext->x_scn.x_nlinno) +#endif +#ifndef GET_LINENO_LNNO +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) (ext->l_lnno)); +#endif +#ifndef PUT_LINENO_LNNO +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_16(abfd,val, (bfd_byte *) (ext->l_lnno)); +#endif + +/* The f_symptr field in the filehdr is sometimes 64 bits. */ +#ifndef GET_FILEHDR_SYMPTR +#define GET_FILEHDR_SYMPTR bfd_h_get_32 +#endif +#ifndef PUT_FILEHDR_SYMPTR +#define PUT_FILEHDR_SYMPTR bfd_h_put_32 +#endif + +/* Some fields in the aouthdr are sometimes 64 bits. */ +#ifndef GET_AOUTHDR_TSIZE +#define GET_AOUTHDR_TSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TSIZE +#define PUT_AOUTHDR_TSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DSIZE +#define GET_AOUTHDR_DSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DSIZE +#define PUT_AOUTHDR_DSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_BSIZE +#define GET_AOUTHDR_BSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_BSIZE +#define PUT_AOUTHDR_BSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_ENTRY +#define GET_AOUTHDR_ENTRY bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_ENTRY +#define PUT_AOUTHDR_ENTRY bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_TEXT_START +#define GET_AOUTHDR_TEXT_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TEXT_START +#define PUT_AOUTHDR_TEXT_START bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DATA_START +#define GET_AOUTHDR_DATA_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DATA_START +#define PUT_AOUTHDR_DATA_START bfd_h_put_32 +#endif + +/* Some fields in the scnhdr are sometimes 64 bits. */ +#ifndef GET_SCNHDR_PADDR +#define GET_SCNHDR_PADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_PADDR +#define PUT_SCNHDR_PADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_VADDR +#define GET_SCNHDR_VADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_VADDR +#define PUT_SCNHDR_VADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SIZE +#define GET_SCNHDR_SIZE bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SIZE +#define PUT_SCNHDR_SIZE bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SCNPTR +#define GET_SCNHDR_SCNPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SCNPTR +#define PUT_SCNHDR_SCNPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_RELPTR +#define GET_SCNHDR_RELPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_RELPTR +#define PUT_SCNHDR_RELPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_LNNOPTR +#define GET_SCNHDR_LNNOPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_LNNOPTR +#define PUT_SCNHDR_LNNOPTR bfd_h_put_32 +#endif + +#ifndef NO_COFF_RELOCS + +static void +coff_swap_reloc_in (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + RELOC *reloc_src = (RELOC *) src; + struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; + + reloc_dst->r_vaddr = bfd_h_get_32(abfd, (bfd_byte *)reloc_src->r_vaddr); + reloc_dst->r_symndx = bfd_h_get_signed_32(abfd, (bfd_byte *) reloc_src->r_symndx); + +#ifdef RS6000COFF_C + reloc_dst->r_type = bfd_h_get_8(abfd, reloc_src->r_type); + reloc_dst->r_size = bfd_h_get_8(abfd, reloc_src->r_size); +#else + reloc_dst->r_type = bfd_h_get_16(abfd, (bfd_byte *) reloc_src->r_type); +#endif + +#ifdef SWAP_IN_RELOC_OFFSET + reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET(abfd, + (bfd_byte *) reloc_src->r_offset); +#endif +} + + +static unsigned int +coff_swap_reloc_out (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + struct internal_reloc *reloc_src = (struct internal_reloc *)src; + struct external_reloc *reloc_dst = (struct external_reloc *)dst; + bfd_h_put_32(abfd, reloc_src->r_vaddr, (bfd_byte *) reloc_dst->r_vaddr); + bfd_h_put_32(abfd, reloc_src->r_symndx, (bfd_byte *) reloc_dst->r_symndx); + +#ifdef RS6000COFF_C + bfd_h_put_8 (abfd, reloc_src->r_type, (bfd_byte *) reloc_dst->r_type); + bfd_h_put_8 (abfd, reloc_src->r_size, (bfd_byte *) reloc_dst->r_size); +#else + bfd_h_put_16(abfd, reloc_src->r_type, (bfd_byte *) + reloc_dst->r_type); +#endif + +#ifdef SWAP_OUT_RELOC_OFFSET + SWAP_OUT_RELOC_OFFSET(abfd, + reloc_src->r_offset, + (bfd_byte *) reloc_dst->r_offset); +#endif +#ifdef SWAP_OUT_RELOC_EXTRA + SWAP_OUT_RELOC_EXTRA(abfd,reloc_src, reloc_dst); +#endif + + return sizeof(struct external_reloc); +} + +#endif /* NO_COFF_RELOCS */ + +static void +coff_swap_filehdr_in (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + FILHDR *filehdr_src = (FILHDR *) src; + struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; + filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *) filehdr_src->f_magic); + filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_nscns); + filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_timdat); + filehdr_dst->f_symptr = + GET_FILEHDR_SYMPTR (abfd, (bfd_byte *) filehdr_src->f_symptr); + filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_nsyms); + filehdr_dst->f_opthdr = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_opthdr); + filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_flags); +} + +static unsigned int +coff_swap_filehdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_filehdr *filehdr_in = (struct internal_filehdr *)in; + FILHDR *filehdr_out = (FILHDR *)out; + + bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic); + bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns); + bfd_h_put_32(abfd, filehdr_in->f_timdat, (bfd_byte *) filehdr_out->f_timdat); + PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr, + (bfd_byte *) filehdr_out->f_symptr); + bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms); + bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr); + bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags); + + return sizeof(FILHDR); +} + + +#ifndef NO_COFF_SYMBOLS + +static void +coff_swap_sym_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + SYMENT *ext = (SYMENT *)ext1; + struct internal_syment *in = (struct internal_syment *)in1; + + if( ext->e.e_name[0] == 0) { + in->_n._n_n._n_zeroes = 0; + in->_n._n_n._n_offset = bfd_h_get_32(abfd, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(in->_n._n_name, ext->e.e_name, SYMNMLEN); +#endif + } + in->n_value = bfd_h_get_32(abfd, (bfd_byte *) ext->e_value); + in->n_scnum = bfd_h_get_16(abfd, (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2){ + in->n_type = bfd_h_get_16(abfd, (bfd_byte *) ext->e_type); + } + else { + in->n_type = bfd_h_get_32(abfd, (bfd_byte *) ext->e_type); + } + in->n_sclass = bfd_h_get_8(abfd, ext->e_sclass); + in->n_numaux = bfd_h_get_8(abfd, ext->e_numaux); +} + +static unsigned int +coff_swap_sym_out (abfd, inp, extp) + bfd *abfd; + PTR inp; + PTR extp; +{ + struct internal_syment *in = (struct internal_syment *)inp; + SYMENT *ext =(SYMENT *)extp; + if(in->_n._n_name[0] == 0) { + bfd_h_put_32(abfd, 0, (bfd_byte *) ext->e.e.e_zeroes); + bfd_h_put_32(abfd, in->_n._n_n._n_offset, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(ext->e.e_name, in->_n._n_name, SYMNMLEN); +#endif + } + bfd_h_put_32(abfd, in->n_value , (bfd_byte *) ext->e_value); + bfd_h_put_16(abfd, in->n_scnum , (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2) + { + bfd_h_put_16(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + else + { + bfd_h_put_32(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + bfd_h_put_8(abfd, in->n_sclass , ext->e_sclass); + bfd_h_put_8(abfd, in->n_numaux , ext->e_numaux); + return sizeof(SYMENT); +} + +static void +coff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1) + bfd *abfd; + PTR ext1; + int type; + int class; + int indx; + int numaux; + PTR in1; +{ + AUXENT *ext = (AUXENT *)ext1; + union internal_auxent *in = (union internal_auxent *)in1; + + switch (class) { + case C_FILE: + if (ext->x_file.x_fname[0] == 0) { + in->x_file.x_n.x_zeroes = 0; + in->x_file.x_n.x_offset = + bfd_h_get_32(abfd, (bfd_byte *) ext->x_file.x_n.x_offset); + } else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN); +#endif + } + return; + + /* RS/6000 "csect" auxents */ +#ifdef RS6000COFF_C + case C_EXT: + case C_HIDEXT: + if (indx + 1 == numaux) + { + in->x_csect.x_scnlen.l = bfd_h_get_32 (abfd, ext->x_csect.x_scnlen); + in->x_csect.x_parmhash = bfd_h_get_32 (abfd, + ext->x_csect.x_parmhash); + in->x_csect.x_snhash = bfd_h_get_16 (abfd, ext->x_csect.x_snhash); + /* We don't have to hack bitfields in x_smtyp because it's + defined by shifts-and-ands, which are equivalent on all + byte orders. */ + in->x_csect.x_smtyp = bfd_h_get_8 (abfd, ext->x_csect.x_smtyp); + in->x_csect.x_smclas = bfd_h_get_8 (abfd, ext->x_csect.x_smclas); + in->x_csect.x_stab = bfd_h_get_32 (abfd, ext->x_csect.x_stab); + in->x_csect.x_snstab = bfd_h_get_16 (abfd, ext->x_csect.x_snstab); + return; + } + break; +#endif + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + in->x_scn.x_scnlen = GET_SCN_SCNLEN(abfd, ext); + in->x_scn.x_nreloc = GET_SCN_NRELOC(abfd, ext); + in->x_scn.x_nlinno = GET_SCN_NLINNO(abfd, ext); + return; + } + break; + } + + in->x_sym.x_tagndx.l = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + in->x_sym.x_tvndx = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (class == C_BLOCK || ISFCN (type) || ISTAG (class)) + { + in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext); + in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext); + } + else + { +#if DIMNUM != E_DIMNUM + #error we need to cope with truncating or extending DIMNUM +#endif + in->x_sym.x_fcnary.x_ary.x_dimen[0] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + in->x_sym.x_fcnary.x_ary.x_dimen[1] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + in->x_sym.x_fcnary.x_ary.x_dimen[2] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + in->x_sym.x_fcnary.x_ary.x_dimen[3] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]); + } + + if (ISFCN(type)) { + in->x_sym.x_misc.x_fsize = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_fsize); + } + else { + in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO(abfd, ext); + in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE(abfd, ext); + } +} + +static unsigned int +coff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp) + bfd *abfd; + PTR inp; + int type; + int class; + int indx; + int numaux; + PTR extp; +{ + union internal_auxent *in = (union internal_auxent *)inp; + AUXENT *ext = (AUXENT *)extp; + + memset((PTR)ext, 0, AUXESZ); + switch (class) { + case C_FILE: + if (in->x_file.x_fname[0] == 0) { + PUTWORD(abfd, 0, (bfd_byte *) ext->x_file.x_n.x_zeroes); + PUTWORD(abfd, + in->x_file.x_n.x_offset, + (bfd_byte *) ext->x_file.x_n.x_offset); + } + else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN); +#endif + } + return sizeof (AUXENT); + +#ifdef RS6000COFF_C + /* RS/6000 "csect" auxents */ + case C_EXT: + case C_HIDEXT: + if (indx + 1 == numaux) + { + PUTWORD (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen); + PUTWORD (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash); + PUTHALF (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash); + /* We don't have to hack bitfields in x_smtyp because it's + defined by shifts-and-ands, which are equivalent on all + byte orders. */ + PUTBYTE (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp); + PUTBYTE (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas); + PUTWORD (abfd, in->x_csect.x_stab, ext->x_csect.x_stab); + PUTHALF (abfd, in->x_csect.x_snstab, ext->x_csect.x_snstab); + return sizeof (AUXENT); + } + break; +#endif + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + PUT_SCN_SCNLEN(abfd, in->x_scn.x_scnlen, ext); + PUT_SCN_NRELOC(abfd, in->x_scn.x_nreloc, ext); + PUT_SCN_NLINNO(abfd, in->x_scn.x_nlinno, ext); + return sizeof (AUXENT); + } + break; + } + + PUTWORD(abfd, in->x_sym.x_tagndx.l, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + bfd_h_put_16(abfd, in->x_sym.x_tvndx , (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (class == C_BLOCK || ISFCN (type) || ISTAG (class)) + { + PUT_FCN_LNNOPTR(abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext); + PUT_FCN_ENDNDX(abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext); + } + else + { +#if DIMNUM != E_DIMNUM + #error we need to cope with truncating or extending DIMNUM +#endif + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]); + } + + if (ISFCN (type)) + PUTWORD (abfd, in->x_sym.x_misc.x_fsize, + (bfd_byte *) ext->x_sym.x_misc.x_fsize); + else + { + PUT_LNSZ_LNNO (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext); + PUT_LNSZ_SIZE (abfd, in->x_sym.x_misc.x_lnsz.x_size, ext); + } + + return sizeof(AUXENT); +} + +#endif /* NO_COFF_SYMBOLS */ + +#ifndef NO_COFF_LINENOS + +static void +coff_swap_lineno_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + LINENO *ext = (LINENO *)ext1; + struct internal_lineno *in = (struct internal_lineno *)in1; + + in->l_addr.l_symndx = bfd_h_get_32(abfd, (bfd_byte *) ext->l_addr.l_symndx); + in->l_lnno = GET_LINENO_LNNO(abfd, ext); +} + +static unsigned int +coff_swap_lineno_out (abfd, inp, outp) + bfd *abfd; + PTR inp; + PTR outp; +{ + struct internal_lineno *in = (struct internal_lineno *)inp; + struct external_lineno *ext = (struct external_lineno *)outp; + PUTWORD(abfd, in->l_addr.l_symndx, (bfd_byte *) + ext->l_addr.l_symndx); + + PUT_LINENO_LNNO (abfd, in->l_lnno, ext); + return sizeof(struct external_lineno); +} + +#endif /* NO_COFF_LINENOS */ + + +static void +coff_swap_aouthdr_in (abfd, aouthdr_ext1, aouthdr_int1) + bfd *abfd; + PTR aouthdr_ext1; + PTR aouthdr_int1; +{ + AOUTHDR *aouthdr_ext = (AOUTHDR *) aouthdr_ext1; + struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1; + + aouthdr_int->magic = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->magic); + aouthdr_int->vstamp = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->vstamp); + aouthdr_int->tsize = + GET_AOUTHDR_TSIZE (abfd, (bfd_byte *) aouthdr_ext->tsize); + aouthdr_int->dsize = + GET_AOUTHDR_DSIZE (abfd, (bfd_byte *) aouthdr_ext->dsize); + aouthdr_int->bsize = + GET_AOUTHDR_BSIZE (abfd, (bfd_byte *) aouthdr_ext->bsize); + aouthdr_int->entry = + GET_AOUTHDR_ENTRY (abfd, (bfd_byte *) aouthdr_ext->entry); + aouthdr_int->text_start = + GET_AOUTHDR_TEXT_START (abfd, (bfd_byte *) aouthdr_ext->text_start); + aouthdr_int->data_start = + GET_AOUTHDR_DATA_START (abfd, (bfd_byte *) aouthdr_ext->data_start); + +#ifdef I960 + aouthdr_int->tagentries = bfd_h_get_32(abfd, (bfd_byte *) aouthdr_ext->tagentries); +#endif + +#ifdef APOLLO_M68 + bfd_h_put_32(abfd, aouthdr_int->o_inlib, (bfd_byte *) aouthdr_ext->o_inlib); + bfd_h_put_32(abfd, aouthdr_int->o_sri, (bfd_byte *) aouthdr_ext->o_sri); + bfd_h_put_32(abfd, aouthdr_int->vid[0], (bfd_byte *) aouthdr_ext->vid); + bfd_h_put_32(abfd, aouthdr_int->vid[1], (bfd_byte *) aouthdr_ext->vid + 4); +#endif + + +#ifdef RS6000COFF_C + aouthdr_int->o_toc = bfd_h_get_32(abfd, aouthdr_ext->o_toc); + aouthdr_int->o_snentry = bfd_h_get_16(abfd, aouthdr_ext->o_snentry); + aouthdr_int->o_sntext = bfd_h_get_16(abfd, aouthdr_ext->o_sntext); + aouthdr_int->o_sndata = bfd_h_get_16(abfd, aouthdr_ext->o_sndata); + aouthdr_int->o_sntoc = bfd_h_get_16(abfd, aouthdr_ext->o_sntoc); + aouthdr_int->o_snloader = bfd_h_get_16(abfd, aouthdr_ext->o_snloader); + aouthdr_int->o_snbss = bfd_h_get_16(abfd, aouthdr_ext->o_snbss); + aouthdr_int->o_algntext = bfd_h_get_16(abfd, aouthdr_ext->o_algntext); + aouthdr_int->o_algndata = bfd_h_get_16(abfd, aouthdr_ext->o_algndata); + aouthdr_int->o_modtype = bfd_h_get_16(abfd, aouthdr_ext->o_modtype); + aouthdr_int->o_cputype = bfd_h_get_16(abfd, aouthdr_ext->o_cputype); + aouthdr_int->o_maxstack = bfd_h_get_32(abfd, aouthdr_ext->o_maxstack); + aouthdr_int->o_maxdata = bfd_h_get_32(abfd, aouthdr_ext->o_maxdata); +#endif + +#ifdef MIPSECOFF + aouthdr_int->bss_start = bfd_h_get_32(abfd, aouthdr_ext->bss_start); + aouthdr_int->gp_value = bfd_h_get_32(abfd, aouthdr_ext->gp_value); + aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask); + aouthdr_int->cprmask[0] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[0]); + aouthdr_int->cprmask[1] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[1]); + aouthdr_int->cprmask[2] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[2]); + aouthdr_int->cprmask[3] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[3]); +#endif + +#ifdef ALPHAECOFF + aouthdr_int->bss_start = bfd_h_get_64(abfd, aouthdr_ext->bss_start); + aouthdr_int->gp_value = bfd_h_get_64(abfd, aouthdr_ext->gp_value); + aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask); + aouthdr_int->fprmask = bfd_h_get_32(abfd, aouthdr_ext->fprmask); +#endif +} + +static unsigned int +coff_swap_aouthdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *)in; + AOUTHDR *aouthdr_out = (AOUTHDR *)out; + + bfd_h_put_16(abfd, aouthdr_in->magic, (bfd_byte *) aouthdr_out->magic); + bfd_h_put_16(abfd, aouthdr_in->vstamp, (bfd_byte *) aouthdr_out->vstamp); + PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, (bfd_byte *) aouthdr_out->tsize); + PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, (bfd_byte *) aouthdr_out->dsize); + PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, (bfd_byte *) aouthdr_out->bsize); + PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, (bfd_byte *) aouthdr_out->entry); + PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, + (bfd_byte *) aouthdr_out->text_start); + PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, + (bfd_byte *) aouthdr_out->data_start); + +#ifdef I960 + bfd_h_put_32(abfd, aouthdr_in->tagentries, (bfd_byte *) aouthdr_out->tagentries); +#endif + +#ifdef RS6000COFF_C + bfd_h_put_32 (abfd, aouthdr_in->o_toc, aouthdr_out->o_toc); + bfd_h_put_16 (abfd, aouthdr_in->o_snentry, aouthdr_out->o_snentry); + bfd_h_put_16 (abfd, aouthdr_in->o_sntext, aouthdr_out->o_sntext); + bfd_h_put_16 (abfd, aouthdr_in->o_sndata, aouthdr_out->o_sndata); + bfd_h_put_16 (abfd, aouthdr_in->o_sntoc, aouthdr_out->o_sntoc); + bfd_h_put_16 (abfd, aouthdr_in->o_snloader, aouthdr_out->o_snloader); + bfd_h_put_16 (abfd, aouthdr_in->o_snbss, aouthdr_out->o_snbss); + bfd_h_put_16 (abfd, aouthdr_in->o_algntext, aouthdr_out->o_algntext); + bfd_h_put_16 (abfd, aouthdr_in->o_algndata, aouthdr_out->o_algndata); + bfd_h_put_16 (abfd, aouthdr_in->o_modtype, aouthdr_out->o_modtype); + bfd_h_put_16 (abfd, aouthdr_in->o_cputype, aouthdr_out->o_cputype); + bfd_h_put_32 (abfd, aouthdr_in->o_maxstack, aouthdr_out->o_maxstack); + bfd_h_put_32 (abfd, aouthdr_in->o_maxdata, aouthdr_out->o_maxdata); + memset (aouthdr_out->o_resv2, 0, sizeof aouthdr_out->o_resv2); +#endif + +#ifdef MIPSECOFF + bfd_h_put_32(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start); + bfd_h_put_32(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value); + bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask); + bfd_h_put_32(abfd, aouthdr_in->cprmask[0], (bfd_byte *) aouthdr_out->cprmask[0]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[1], (bfd_byte *) aouthdr_out->cprmask[1]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[2], (bfd_byte *) aouthdr_out->cprmask[2]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[3], (bfd_byte *) aouthdr_out->cprmask[3]); +#endif + +#ifdef ALPHAECOFF + /* FIXME: What does bldrev mean? */ + bfd_h_put_16(abfd, (bfd_vma) 2, (bfd_byte *) aouthdr_out->bldrev); + bfd_h_put_16(abfd, (bfd_vma) 0, (bfd_byte *) aouthdr_out->padding); + bfd_h_put_64(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start); + bfd_h_put_64(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value); + bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask); + bfd_h_put_32(abfd, aouthdr_in->fprmask, (bfd_byte *) aouthdr_out->fprmask); +#endif + + return sizeof(AOUTHDR); +} + +static void +coff_swap_scnhdr_in (abfd, ext, in) + bfd *abfd; + PTR ext; + PTR in; +{ + SCNHDR *scnhdr_ext = (SCNHDR *) ext; + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + memcpy(scnhdr_int->s_name, scnhdr_ext->s_name, sizeof(scnhdr_int->s_name)); + scnhdr_int->s_vaddr = + GET_SCNHDR_VADDR (abfd, (bfd_byte *) scnhdr_ext->s_vaddr); + scnhdr_int->s_paddr = + GET_SCNHDR_PADDR (abfd, (bfd_byte *) scnhdr_ext->s_paddr); + scnhdr_int->s_size = + GET_SCNHDR_SIZE (abfd, (bfd_byte *) scnhdr_ext->s_size); + + scnhdr_int->s_scnptr = + GET_SCNHDR_SCNPTR (abfd, (bfd_byte *) scnhdr_ext->s_scnptr); + scnhdr_int->s_relptr = + GET_SCNHDR_RELPTR (abfd, (bfd_byte *) scnhdr_ext->s_relptr); + scnhdr_int->s_lnnoptr = + GET_SCNHDR_LNNOPTR (abfd, (bfd_byte *) scnhdr_ext->s_lnnoptr); + scnhdr_int->s_flags = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_flags); +#if defined(M88) + scnhdr_int->s_nreloc = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nlnno); +#else + scnhdr_int->s_nreloc = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nlnno); +#endif +#ifdef I960 + scnhdr_int->s_align = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_align); +#endif +} + +static unsigned int +coff_swap_scnhdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *)in; + SCNHDR *scnhdr_ext = (SCNHDR *)out; + unsigned int ret = sizeof (SCNHDR); + + memcpy(scnhdr_ext->s_name, scnhdr_int->s_name, sizeof(scnhdr_int->s_name)); + + PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr, + (bfd_byte *) scnhdr_ext->s_vaddr); + + + PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr, + (bfd_byte *) scnhdr_ext->s_paddr); + PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size, + (bfd_byte *) scnhdr_ext->s_size); + + PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, + (bfd_byte *) scnhdr_ext->s_scnptr); + PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, + (bfd_byte *) scnhdr_ext->s_relptr); + PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, + (bfd_byte *) scnhdr_ext->s_lnnoptr); + PUTWORD(abfd, scnhdr_int->s_flags, (bfd_byte *) scnhdr_ext->s_flags); +#if defined(M88) + PUTWORD(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno); + PUTWORD(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc); +#else + if (scnhdr_int->s_nlnno <= 0xffff) + PUTHALF(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno); + else + { + (*_bfd_error_handler) ("%s: line number overflow: 0x%lx > 0xffff", + bfd_get_filename (abfd), + scnhdr_int->s_nlnno); + bfd_set_error (bfd_error_file_truncated); + PUTHALF (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nlnno); + ret = 0; + } + if (scnhdr_int->s_nreloc <= 0xffff) + PUTHALF(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc); + else + { + (*_bfd_error_handler) ("%s: reloc overflow: 0x%lx > 0xffff", + bfd_get_filename (abfd), + scnhdr_int->s_nreloc); + bfd_set_error (bfd_error_file_truncated); + PUTHALF (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nreloc); + ret = 0; + } +#endif + +#if defined(I960) + PUTWORD(abfd, scnhdr_int->s_align, (bfd_byte *) scnhdr_ext->s_align); +#endif + return ret; +} diff --git a/contrib/gdb/bfd/config.bfd b/contrib/gdb/bfd/config.bfd new file mode 100644 index 000000000000..7757d5fec299 --- /dev/null +++ b/contrib/gdb/bfd/config.bfd @@ -0,0 +1,491 @@ +# config.bfd +# Convert a canonical host type into a BFD host type. +# Set shell variable targ to canonical target name, and run +# using ``. config.bfd''. +# Sets the following shell variables: +# targ_defvec Default vector for this target +# targ_selvecs Vectors to build for this target +# targ_archs Architectures for this target +# targ_cflags $(CFLAGS) for this target (FIXME: pretty bogus) +# targ_undercore Whether underscores are used: yes or no + +# The binutils c++filt program wants to know whether underscores are +# stripped or not. That is why we set targ_underscore. c++filt uses +# this information to choose a default. This information is +# duplicated in the symbol_leading_char field of the BFD target +# vector, but c++filt does not deal with object files and is not +# linked against libbfd.a. It is not terribly important that c++filt +# get this right; it is just convenient. + +targ_defvec= +targ_selvecs= +targ_cflags= +targ_underscore=no + +targ_cpu=`echo $targ | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +case "${targ_cpu}" in +arm*) targ_archs=bfd_arm_arch ;; +hppa*) targ_archs=bfd_hppa_arch ;; +i[345]86) targ_archs=bfd_i386_arch ;; +m68*) targ_archs=bfd_m68k_arch ;; +m88*) targ_archs=bfd_m88k_arch ;; +mips*) targ_archs=bfd_mips_arch ;; +powerpc*) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; +rs6000) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; +sparc*) targ_archs=bfd_sparc_arch ;; +z8k*) targ_archs=bfd_z8k_arch ;; +*) targ_archs=bfd_${targ_cpu}_arch ;; +esac + +# WHEN ADDING ENTRIES TO THIS MATRIX: +# Make sure that the left side always has two dashes. Otherwise you +# can get spurious matches. Even for unambiguous cases, do this as a +# convention, else the table becomes a real mess to understand and maintain. + +case "${targ}" in + alpha-*-netware*) + targ_defvec=ecoffalpha_little_vec + targ_selvecs=nlm32_alpha_vec + ;; + alpha-*-*) + targ_defvec=ecoffalpha_little_vec + ;; + + + arm-*-riscix*) + targ_defvec=riscix_vec + ;; + arm-*-pe*) + targ_defvec=armpe_little_vec + targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_underscore=yes + ;; + arm-*-aout | armel-*-aout) + targ_defvec=aout_arm_little_vec + targ_selvecs=aout_arm_big_vec + ;; + armeb-*-aout) + targ_defvec=aout_arm_big_vec + targ_selvecs=aout_arm_little_vec + ;; + arm-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + + a29k-*-ebmon* | a29k-*-udi* | a29k-*-coff* | a29k-*-sym1* | \ + a29k-*-vxworks* | a29k-*-sysv*) + targ_defvec=a29kcoff_big_vec + targ_selvecs=sunos_big_vec + targ_underscore=yes + ;; + a29k-*-aout* | a29k-*-bsd* | a29k-*-vsta*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + + h8300*-*-*) + targ_defvec=h8300coff_vec + targ_underscore=yes + ;; + + h8500-*-*) + targ_defvec=h8500coff_vec + targ_underscore=yes + ;; + + sh-*-*) + targ_defvec=shcoff_vec + targ_selvecs="shcoff_vec shlcoff_vec" + targ_underscore=yes + ;; + + hppa*-*-*elf* | hppa*-*-lites* | hppa*-*-sysv4*) + targ_defvec=bfd_elf32_hppa_vec + ;; + hppa*-*-bsd*) + targ_defvec=som_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; + hppa*-*-hpux* | hppa*-*-hiux*) + targ_defvec=som_vec + ;; + hppa*-*-osf*) + targ_defvec=som_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; + + i[345]86-*-sysv4* | i[345]86-*-unixware | i[345]86-*-solaris2* | \ + i[345]86-*-elf | i[345]86-*-sco*elf*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[345]86-*-sysv* | i[345]86-*-isc* | i[345]86-*-sco* | i[345]86-*-coff | \ + i[345]86-*-aix* | i[345]86-*-go32*) + targ_defvec=i386coff_vec + ;; + i[345]86-sequent-bsd*) + targ_defvec=i386dynix_vec + targ_underscore=yes + ;; + i[345]86-*-bsd*) + targ_defvec=i386bsd_vec + targ_underscore=yes + ;; + i[345]86-*-freebsd*) + targ_defvec=i386freebsd_vec + targ_selvecs=i386bsd_vec + targ_underscore=yes + ;; + i[345]86-*-netbsd*) + targ_defvec=i386netbsd_vec + targ_selvecs=i386bsd_vec + targ_underscore=yes + ;; + i[345]86-*-netware*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="nlm32_i386_vec i386coff_vec i386aout_vec" + ;; + i[345]86-*-linuxaout*) + targ_defvec=i386linux_vec + targ_selvecs=bfd_elf32_i386_vec + targ_underscore=yes + ;; + i[345]86-*-linux*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386linux_vec + targ_underscore=yes + ;; + i[345]86-*-lynxos*) + targ_defvec=i386lynx_coff_vec + targ_selvecs=i386lynx_aout_vec + ;; + i[345]86-*-gnu*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386mach3_vec + targ_cflags=-DSTAT_FOR_EXEC + targ_underscore=yes + ;; + i[345]86-*-mach* | i[345]86-*-osf1mk*) + targ_defvec=i386mach3_vec + targ_cflags=-DSTAT_FOR_EXEC + targ_underscore=yes + ;; + i[345]86-*-os9k) + targ_defvec=i386os9k_vec + ;; + i[345]86-*-msdos*) + targ_defvec=i386aout_vec + targ_selvecs=i386msdos_vec + ;; + i[345]86-*-moss*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386msdos_vec i386aout_vec" + ;; + i[345]86-*-cygwin32 | i[345]86-*-winnt | i[345]86-*-pe) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec" + ;; + i[345]86-none-*) + targ_defvec=i386coff_vec + ;; + i[345]86-*-aout* | i[345]86*-*-vsta*) + targ_defvec=i386aout_vec + ;; + + i860-*-mach3* | i860-*-osf1* | i860-*-coff*) + targ_defvec=i860coff_vec + ;; + i860-*-sysv4* | i860-*-elf*) + targ_defvec=bfd_elf32_i860_vec + ;; + + i960-*-vxworks4* | i960-*-vxworks5.0) + targ_defvec=b_out_vec_little_host + targ_selvecs="b_out_vec_big_host icoff_little_vec icoff_big_vec" + targ_underscore=yes + ;; + i960-*-vxworks5.* | i960-*-coff* | i960-*-sysv*) + targ_defvec=icoff_little_vec + targ_selvecs="icoff_big_vec b_out_vec_little_host b_out_vec_big_host" + targ_underscore=yes + ;; + i960-*-vxworks* | i960-*-aout* | i960-*-bout* | i960-*-nindy*) + targ_defvec=b_out_vec_little_host + targ_selvecs="b_out_vec_big_host icoff_little_vec icoff_big_vec" + targ_underscore=yes + ;; + + m68*-apollo-*) + targ_defvec=apollocoff_vec + ;; + m68*-bull-sysv*) + targ_defvec=m68kcoffun_vec + targ_underscore=yes + ;; + m68*-hp-bsd*) + targ_defvec=hp300bsd_vec + targ_underscore=yes + ;; + m68*-*-aout*) + targ_defvec=aout0_big_vec + # We include this here, rather than making a separate cisco + # configuration, so that cisco-core.c gets routinely tested at + # least for compilation. + targ_selvecs=cisco_core_vec + targ_underscore=yes + ;; + m68*-*-elf* | m68*-*-sysv4*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68kcoff_vec + ;; + m68*-*-coff* | m68*-*-sysv*) + targ_defvec=m68kcoff_vec + targ_selvecs="m68kcoff_vec versados_vec" + ;; + m68*-*-hpux*) + targ_defvec=hp300hpux_vec + targ_underscore=yes + ;; + m68*-*-linuxaout*) + targ_defvec=m68klinux_vec + targ_selvecs=bfd_elf32_m68k_vec + targ_underscore=yes + ;; + m68*-*-linux*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68klinux_vec + ;; + m68*-*-lynxos*) + targ_defvec=m68klynx_coff_vec + targ_selvecs=m68klynx_aout_vec + ;; + m68*-hp*-netbsd*) + targ_defvec=m68k4knetbsd_vec + targ_selvecs="m68knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_underscore=yes + ;; + m68*-*-netbsd*) + targ_defvec=m68knetbsd_vec + targ_selvecs="m68k4knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_underscore=yes + ;; + m68*-*-sunos* | m68*-*-os68k* | m68*-*-vxworks* | m68*-netx-* | \ + m68*-*-bsd* | m68*-*-vsta*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + m68*-ericsson-*) + targ_defvec=sunos_big_vec + targ_selvecs="m68kcoff_vec tekhex_vec" + targ_underscore=yes + ;; + m68*-cbm-*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68kcoff_vec + ;; + m68*-apple-aux*) + targ_defvec=m68kaux_coff_vec + ;; + m68*-*-psos*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=ieee_vec + targ_underscore=yes + ;; + + m88*-harris-cxux* | m88*-*-dgux* | m88*-*-sysv4*) + targ_defvec=bfd_elf32_m88k_vec + targ_selvecs=m88kbcs_vec + ;; + m88*-*-mach3*) + targ_defvec=m88kmach3_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + m88*-*-*) + targ_defvec=m88kbcs_vec + targ_underscore=yes + ;; + + mips*-big-*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips-dec-netbsd*) + targ_defvec=bfd_elf32_littlemips_vec + targ_selvecs=bfd_elf32_bigmips_vec + ;; + mips*-dec-bsd*) + targ_defvec=aout_mips_little_vec + targ_underscore=yes + ;; + mips*-dec-mach3*) + targ_defvec=aout_mips_little_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + mips*-dec-* | mips*el-*-ecoff*) + targ_defvec=ecoff_little_vec + targ_selvecs=ecoff_big_vec + ;; + mips*-*-ecoff*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*-*-irix5*) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec ecoff_big_vec ecoff_little_vec" + ;; + mips*-sgi-* | mips*-*-bsd*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*-*-mach3*) + targ_defvec=aout_mips_little_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + mips*-*-sysv4*) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec ecoff_big_vec ecoff_little_vec" + ;; + mips*-*-sysv* | mips*-*-riscos*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*el-*-elf*) + targ_defvec=bfd_elf32_littlemips_vec + targ_selvecs=bfd_elf32_bigmips_vec + ;; + mips*-*-elf*) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs=bfd_elf32_littlemips_vec + ;; + + ns32k-pc532-mach* | ns32k-pc532-ux*) + targ_defvec=pc532machaout_vec + targ_underscore=yes + ;; + ns32k-*-netbsd* | ns32k-*-lites*) + targ_defvec=pc532netbsd_vec + targ_underscore=yes + ;; + + powerpc-*-aix*) + targ_defvec=rs6000coff_vec + ;; + powerpc-*-elf* | powerpc-*-sysv4* | powerpc-*-eabi* | powerpc-*-solaris2*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec" + ;; + powerpc-*-macos* | powerpc-*-mpw*) + targ_defvec=pmac_xcoff_vec + ;; + powerpc-*-netware*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="nlm32_powerpc_vec rs6000coff_vec" + ;; + powerpcle-*-elf* | powerpcle-*-sysv4* | powerpcle-*-eabi* | \ + powerpcle-*-solaris2*) + targ_defvec=bfd_elf32_powerpcle_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec" + ;; + + powerpcle-*-pe | powerpcle-*-winnt* | powerpcle-*-cygwin32) + targ_defvec=bfd_powerpcle_pe_vec + targ_selvecs="bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec" + ;; + + rs6000-*-*) + targ_defvec=rs6000coff_vec + ;; + + sparc-*-lynxos*) + targ_defvec=sparclynx_coff_vec + targ_selvecs=sparclynx_aout_vec + ;; + sparc-*-netbsd*) + targ_defvec=sparcnetbsd_vec + targ_underscore=yes + ;; + sparc-*-elf* | sparc-*-sysv4* | sparc-*-solaris2*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs=sunos_big_vec + ;; + sparc64-*-aout*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + sparc64-*-elf*) + targ_defvec=bfd_elf64_sparc_vec + targ_selvecs=bfd_elf32_sparc_vec + ;; + sparc64-*-solaris2* | sparc64-*-sysv4*) + targ_defvec=bfd_elf32_sparc_vec + # Adding 64 bit support by default causes things like objdump to + # print addresses as 64 bits. + #targ_selvecs=bfd_elf64_sparc_vec + ;; + sparc-*-netware*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="nlm32_sparc_vec sunos_big_vec" + ;; + sparc*-*-coff*) + targ_defvec=sparccoff_vec + ;; + sparc*-*-*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + + tahoe-*-*) + targ_defvec=host_aout_vec + targ_underscore=yes + ;; + + vax-*-vms*) + echo 1>&2 "*** BFD does not support target ${targ}." + echo 1>&2 "*** Look in bfd/config.bfd for supported targets." + exit 1 + ;; + vax-*-*) + targ_defvec=host_aout_vec + targ_underscore=yes + ;; + + we32k-*-*) + targ_defvec=we32kcoff_vec + ;; + + w65-*-*) + targ_defvec=w65_vec + ;; + + z8k*-*-*) + targ_defvec=z8kcoff_vec + targ_underscore=yes + ;; + + *-*-ieee*) + targ_defvec=ieee_vec + ;; + + *-adobe-*) + targ_defvec=a_aout_adobe_vec + targ_underscore=yes + ;; + + *-sony-*) + targ_defvec=newsos3_vec + targ_underscore=yes + ;; + + *-tandem-*) + targ_defvec=m68kcoff_vec + targ_selvecs=ieee_vec + ;; + + *) + echo 1>&2 "*** BFD does not support target ${targ}." + echo 1>&2 "*** Look in bfd/config.bfd for supported targets." + exit 1 + ;; +esac diff --git a/contrib/gdb/bfd/config.in b/contrib/gdb/bfd/config.in new file mode 100644 index 000000000000..dd4f968e7940 --- /dev/null +++ b/contrib/gdb/bfd/config.in @@ -0,0 +1,67 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Whether malloc must be declared even if is included. */ +#undef NEED_DECLARATION_MALLOC + +/* Whether free must be declared even if is included. */ +#undef NEED_DECLARATION_FREE + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Do we need to use the b modifier when opening binary files? */ +#undef USE_BINARY_FOPEN + +/* Name of host specific header file to include in trad-core.c. */ +#undef TRAD_HEADER + +/* Define only if is available *and* it defines prstatus_t. */ +#undef HAVE_SYS_PROCFS_H + +/* Do we really want to use mmap if it's available? */ +#undef USE_MMAP + +/* Define if you have the fcntl function. */ +#undef HAVE_FCNTL + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the madvise function. */ +#undef HAVE_MADVISE + +/* Define if you have the mprotect function. */ +#undef HAVE_MPROTECT + +/* Define if you have the valloc function. */ +#undef HAVE_VALLOC + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H diff --git a/contrib/gdb/bfd/configure b/contrib/gdb/bfd/configure new file mode 100644 index 000000000000..5db14db15a9e --- /dev/null +++ b/contrib/gdb/bfd/configure @@ -0,0 +1,2439 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.8 +# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-64-bit-bfd 64-bit support (on hosts with narrower word sizes)" +ac_help="$ac_help + --enable-targets alternative target configurations" +ac_help="$ac_help + --enable-shared build shared BFD library" +ac_help="$ac_help + --enable-commonbfdlib build shared BFD/opcodes/libiberty library" +ac_help="$ac_help + --with-mmap try using mmap for BFD input files if available" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.8" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=libbfd.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +# Check whether --enable-64-bit-bfd or --disable-64-bit-bfd was given. +if test "${enable_64_bit_bfd+set}" = set; then + enableval="$enable_64_bit_bfd" + case "${enableval}" in + yes) want64=true ;; + no) want64=false ;; + *) { echo "configure: error: bad value ${enableval} for 64-bit-bfd option" 1>&2; exit 1; } ;; +esac +else + want64=false +fi +# Check whether --enable-targets or --disable-targets was given. +if test "${enable_targets+set}" = set; then + enableval="$enable_targets" + case "${enableval}" in + yes | "") { echo "configure: error: enable-targets option must specify target names or 'all'" 1>&2; exit 1; } + ;; + no) enable_targets= ;; + *) enable_targets=$enableval ;; +esac +fi +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + case "${enableval}" in + yes) shared=true ;; + no) shared=false ;; + *) { echo "configure: error: bad value ${enableval} for BFD shared option" 1>&2; exit 1; } ;; +esac +fi +# Check whether --enable-commonbfdlib or --disable-commonbfdlib was given. +if test "${enable_commonbfdlib+set}" = set; then + enableval="$enable_commonbfdlib" + case "${enableval}" in + yes) commonbfdlib=true ;; + no) commonbfdlib=false ;; + *) { echo "configure: error: bad value ${enableval} for BFD commonbfdlib option" 1>&2; exit 1; } ;; +esac +fi +# Check whether --with-mmap or --without-mmap was given. +if test "${with_mmap+set}" = set; then + withval="$with_mmap" + case "${withval}" in + yes) want_mmap=true ;; + no) want_mmap=false ;; + *) { echo "configure: error: bad value ${withval} for BFD with-mmap option" 1>&2; exit 1; } ;; +esac +else + want_mmap=false +fi + + + +ac_aux_dir= +for ac_dir in `cd $srcdir/..;pwd` $srcdir/`cd $srcdir/..;pwd`; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir/..;pwd` $srcdir/`cd $srcdir/..;pwd`" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`$ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`$ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test -z "$target" ; then + { echo "configure: error: Unrecognized target system type; please check config.sub." 1>&2; exit 1; } +fi +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +host64=false +target64=false + +# host stuff: + +ALLLIBS='$(TARGETLIB)' +PICFLAG= +SHLIB=unused-shlib +SHLINK=unused-shlink +if test "${shared}" = "true"; then + PICFLAG=-fpic + if test "${commonbfdlib}" = "true"; then + ALLLIBS='$(TARGETLIB)' + else + ALLLIBS='$(TARGETLIB) $(SHLIB) $(SHLINK)' + SHLIB=libbfd.so.`sed -e 's/[^0-9]*\([0-9.]*\).*/\1/' ${srcdir}/VERSION` + SHLINK=libbfd.so + fi +fi + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 +if test $ac_cv_prog_gcc = yes; then + GCC=yes + if test "${CFLAGS+set}" != set; then + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_gcc_g=yes +else + ac_cv_prog_gcc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 + if test $ac_cv_prog_gcc_g = yes; then + CFLAGS="-g -O" + else + CFLAGS="-O" + fi + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + + +# Permit host specific settings. +. ${srcdir}/configure.host + + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + +# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_RANLIB"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + RANLIB=":" +fi +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_ifs" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +if test "${shared}" = "true"; then + if test "${GCC}" != "yes" && test "${shared_non_gcc}" != "yes"; then + echo "configure: warning: BFD --enable-shared only supported when using gcc" 1>&2 + shared=false + ALLLIBS='$(TARGETLIB)' + PICFLAG= + SHLIB=unused-shlib + fi +fi + + + + + + +if test "${commonbfdlib}" = "true"; then + COMMON_SHLIB=yes + PICLIST=piclist +else + COMMON_SHLIB= + PICLIST= +fi + + + + +HOST_64BIT_LONG=0 +if test "x${HOST_64BIT_TYPE}" = "xlong"; then + HOST_64BIT_LONG=1 +fi + + +# If we cannot run a trivial program, we must be cross compiling. +echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_cross=yes +else +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_c_cross=no +else + ac_cv_c_cross=yes +fi +fi +rm -fr conftest* +fi + +echo "$ac_t""$ac_cv_c_cross" 1>&6 +cross_compiling=$ac_cv_c_cross + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test -z "$CC_FOR_BUILD"; then + if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' + else + CC_FOR_BUILD=gcc + fi +fi + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1119: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in stddef.h string.h strings.h stdlib.h time.h unistd.h +do +ac_safe=`echo "$ac_hdr" | tr './\055' '___'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1152: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in fcntl.h sys/file.h sys/time.h +do +ac_safe=`echo "$ac_hdr" | tr './\055' '___'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1189: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { return 0; } +int t() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:1228: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +for ac_func in fcntl getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1276: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + + +case "${host}" in +i[345]86-*-msdos* | i[345]86-*-go32* | *-*-cygwin32) + cat >> confdefs.h <<\EOF +#define USE_BINARY_FOPEN 1 +EOF + ;; +esac + +echo $ac_n "checking whether malloc must be declared""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'bfd_cv_decl_needed_malloc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +int main() { return 0; } +int t() { +char *(*pfn) = (char *(*)) malloc +; return 0; } +EOF +if { (eval echo configure:1328: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bfd_cv_decl_needed_malloc=no +else + rm -rf conftest* + bfd_cv_decl_needed_malloc=yes +fi +rm -f conftest* + +fi + +echo "$ac_t""$bfd_cv_decl_needed_malloc" 1>&6 +if test $bfd_cv_decl_needed_malloc = yes; then + bfd_tr_decl=NEED_DECLARATION_`echo malloc | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +if eval "test \"`echo '$''{'bfd_cv_decl_needed_free'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +int main() { return 0; } +int t() { +char *(*pfn) = (char *(*)) free +; return 0; } +EOF +if { (eval echo configure:1368: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bfd_cv_decl_needed_free=no +else + rm -rf conftest* + bfd_cv_decl_needed_free=yes +fi +rm -f conftest* + +fi + +echo "$ac_t""$bfd_cv_decl_needed_free" 1>&6 +if test $bfd_cv_decl_needed_free = yes; then + bfd_tr_decl=NEED_DECLARATION_`echo free | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/alphalinux.h" +EOF + + ;; + alpha*-*-*) COREFILE=osf-core.o ;; + arm-*-riscix) COREFILE=trad-core.o ;; + hppa*-*-hpux*) COREFILE=hpux-core.o ;; + hppa*-*-hiux*) COREFILE=hpux-core.o ;; + hppa*-*-bsd*) COREFILE="hpux-core.o hppabsd-core.o" + COREFLAG="-DHPUX_CORE -DHPPABSD_CORE" ;; + i[345]86-sequent-bsd*) + COREFILE=trad-core.o; + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/symmetry.h" +EOF + + ;; + i[345]86-sequent-sysv4*) ;; + i[345]86-sequent-sysv*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/symmetry.h" +EOF + + ;; + i[345]86-*-bsd* | i[345]86-*-freebsd*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/i386bsd.h" +EOF + + ;; + i[345]86-*-netbsd*) + COREFILE=netbsd-core.o + ;; + i[345]86-esix-sysv3*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/esix.h" +EOF + + ;; + i[345]86-*-sco* | i[345]86-*-isc*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/i386sco.h" +EOF + + ;; + i[345]86-*-mach3*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/i386mach3.h" +EOF + + ;; + i[345]86-*-linux*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/i386linux.h" +EOF + + ;; + i[345]86-*-isc*) COREFILE=trad-core.o ;; + i[345]86-*-aix*) COREFILE=aix386-core.o ;; + i860-*-mach3* | i860-*-osf1*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/i860mach3.h" +EOF + + ;; + mips-dec-bsd*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/mipsbsd.h" +EOF + + ;; + mips-dec-mach3*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/mipsmach3.h" +EOF + + ;; + mips-*-netbsd*) + COREFILE=netbsd-core.o + ;; + mips-dec-*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/decstation.h" +EOF + + ;; + mips-sgi-irix4*) COREFILE=irix-core.o ;; + mips-sgi-irix5*) COREFILE=irix-core.o ;; + mips-*-mach3*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/mipsmach3.h" +EOF + + ;; + mips-*-sysv4*) ;; + mips-*-sysv* | mips-*-riscos*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/riscos.h" +EOF + + ;; + mips-sony-bsd*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/news-mips.h" +EOF + + ;; + m68*-bull*-sysv*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/dpx2.h" +EOF + + ;; + m68*-hp-hpux*) COREFILE=hpux-core.o ;; + m68*-hp-bsd*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/hp300bsd.h" +EOF + + ;; + m68*-*-linux*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/m68klinux.h" +EOF + + ;; + m68*-motorola-sysv*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/delta68.h" +EOF + + ;; + m68*-sony-*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/news.h" +EOF + + ;; + m68*-*-netbsd*) + COREFILE=netbsd-core.o + ;; + m68*-apple-aux*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/m68kaux.h" +EOF + + ;; + m88*-*-sysv4*) ;; + m88*-motorola-sysv*) COREFILE=ptrace-core.o ;; + m88*-*-mach3*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/m88kmach3.h" +EOF + + ;; + ns32k-pc532-mach) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/pc532mach.h" +EOF + + ;; + ns32k-*-netbsd*) + COREFILE=netbsd-core.o + ;; + rs6000-*-lynx*) COREFILE=lynx-core.o ;; + rs6000-*-aix4*) COREFILE=rs6000-core.o ;; + rs6000-*-*) COREFILE=rs6000-core.o ;; + powerpc-*-aix4*) COREFILE=rs6000-core.o ;; + powerpc-*-aix*) COREFILE=rs6000-core.o ;; + sparc-*-netbsd*) + COREFILE=netbsd-core.o + ;; + tahoe-*-*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/tahoe.h" +EOF + + ;; + vax-*-ultrix2*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/vaxult2.h" +EOF + + ;; + vax-*-ultrix*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/vaxult2.h" +EOF + + ;; + vax-*-*) + COREFILE=trad-core.o + cat >> confdefs.h <<\EOF +#define TRAD_HEADER "hosts/vaxbsd.h" +EOF + + ;; + esac + + case "$COREFILE" in + aix386-core.o) COREFLAG=-DAIX386_CORE ;; + hppabsd-core.o) COREFLAG=-DHPPABSD_CORE ;; + hpux-core.o) COREFLAG=-DHPUX_CORE ;; + irix-core.o) COREFLAG=-DIRIX_CORE ;; + lynx-core.o) COREFLAG=-DLYNX_CORE ;; + osf-core.o) COREFLAG=-DOSF_CORE ;; + ptrace-core.o) COREFLAG=-DPTRACE_CORE ;; + rs6000-core.o) COREFLAG="$COREFLAG -DAIX_CORE" ;; + trad-core.o) COREFLAG="$COREFLAG -DTRAD_CORE" ;; + esac + + # The ELF code uses the native to handle core files. + # Define HAVE_SYS_PROCFS_H if the file exists and defines + # prstatus_t. + echo $ac_n "checking for sys/procfs.h""... $ac_c" 1>&6 + if eval "test \"`echo '$''{'bfd_cv_header_sys_procfs_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +prstatus_t t; +; return 0; } +EOF +if { (eval echo configure:1648: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + bfd_cv_header_sys_procfs_h=yes +else + rm -rf conftest* + bfd_cv_header_sys_procfs_h=no +fi +rm -f conftest* + +fi + + echo "$ac_t""$bfd_cv_header_sys_procfs_h" 1>&6 + if test $bfd_cv_header_sys_procfs_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_PROCFS_H 1 +EOF + + fi + +fi + + + +# target stuff: + +# Canonicalize the secondary target names. +if test -n "$enable_targets" ; then + for targ in `echo $enable_targets | sed 's/,/ /g'` + do + result=`$ac_config_sub $targ 2>/dev/null` + if test -n "$result" ; then + canon_targets="$canon_targets $result" + else + # Allow targets that config.sub doesn't recognize, like "all". + canon_targets="$canon_targets $targ" + fi + done +fi + +all_targets=false +defvec= +selvecs= +selarchs= +TDEFINES= +for targ in $target $canon_targets +do + if test "x$targ" = "xall"; then + all_targets=true + else + . $srcdir/config.bfd + if test "x$targ" = "x$target"; then + defvec=$targ_defvec + fi + selvecs="$selvecs $targ_defvec $targ_selvecs" + selarchs="$selarchs $targ_archs" + TDEFINES="$TDEFINES $targ_cflags" + fi +done + + +# This processing still needs to be done if we're to decide properly whether +# 64-bit support needs to be compiled in. Currently, it will be included if +# the default or any other explicitly requested target requires it; it +# will not be included on a 32-bit host if no 64-bit target is requested, and +# no "--with-64-bit-bfd" option is given, even if "--with-targets=all" is +# used. + +# uniq the default and selected vectors in all the configured targets. +f="" +for i in $selvecs ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +selvecs="$f" + +# uniq the architectures in all the configured targets. +f="" +for i in $selarchs ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +selarchs="$f" + +# Target backend .o files. +tb= + +elf="elf.o elflink.o" + +for vec in $selvecs +do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. + a29kcoff_big_vec) tb="$tb coff-a29k.o cofflink.o" ;; + a_out_adobe_vec) tb="$tb aout-adobe.o aout32.o" ;; + armcoff_little_vec) tb="$tb coff-arm.o cofflink.o " ;; + armcoff_big_vec) tb="$tb coff-arm.o cofflink.o " ;; + armpe_little_vec) tb="$tb pe-arm.o cofflink.o " ;; + armpe_big_vec) tb="$tb pe-arm.o cofflink.o " ;; + armpei_little_vec) tb="$tb pei-arm.o cofflink.o " ;; + armpei_big_vec) tb="$tb pei-arm.o cofflink.o " ;; + aout0_big_vec) tb="$tb aout0.o aout32.o" ;; + aout_arm_big_vec) tb="$tb aout-arm.o aout32.o" ;; + aout_arm_little_vec) tb="$tb aout-arm.o aout32.o" ;; + aout_mips_big_vec) tb="$tb mipsbsd.o aout32.o" ;; + aout_mips_little_vec) tb="$tb mipsbsd.o aout32.o" ;; + apollocoff_vec) tb="$tb coff-apollo.o" ;; + b_out_vec_big_host) tb="$tb bout.o aout32.o" ;; + b_out_vec_little_host) tb="$tb bout.o aout32.o" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.o elf32.o $elf" ;; + bfd_elf32_bigmips_vec) tb="$tb elf32-mips.o elf32.o $elf ecofflink.o" ;; + bfd_elf32_hppa_vec) tb="$tb elf32-hppa.o elf32.o $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.o elf32.o $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.o elf32.o $elf" ;; + bfd_elf32_little_generic_vec) tb="$tb elf32-gen.o elf32.o $elf" ;; + bfd_elf32_littlemips_vec) tb="$tb elf32-mips.o elf32.o $elf ecofflink.o" ;; + bfd_elf32_m68k_vec) tb="$tb elf32-m68k.o elf32.o $elf" ;; + bfd_elf32_m88k_vec) tb="$tb elf32-m88k.o elf32.o $elf" ;; + bfd_elf32_powerpc_vec) tb="$tb elf32-ppc.o elf32.o $elf" ;; + bfd_elf32_powerpcle_vec) tb="$tb elf32-ppc.o elf32.o $elf" ;; + bfd_elf32_sparc_vec) tb="$tb elf32-sparc.o elf32.o $elf" ;; + bfd_elf64_big_generic_vec) tb="$tb elf64-gen.o elf64.o $elf" + target64=true ;; + bfd_elf64_little_generic_vec) tb="$tb elf64-gen.o elf64.o $elf" + target64=true ;; + bfd_elf64_sparc_vec) tb="$tb elf64-sparc.o elf64.o $elf" + target64=true ;; + cisco_core_vec) tb="$tb cisco-core.o" ;; + demo_64_vec) tb="$tb demo64.o aout64.o" + target64=true ;; + ecoff_big_vec) tb="$tb coff-mips.o ecoff.o ecofflink.o" ;; + ecoff_little_vec) tb="$tb coff-mips.o ecoff.o ecofflink.o" ;; + ecoffalpha_little_vec) tb="$tb coff-alpha.o ecoff.o ecofflink.o" + target64=true ;; + h8300coff_vec) tb="$tb coff-h8300.o reloc16.o" ;; + h8500coff_vec) tb="$tb coff-h8500.o reloc16.o" ;; + host_aout_vec) tb="$tb host-aout.o aout32.o" ;; + hp300bsd_vec) tb="$tb hp300bsd.o aout32.o" ;; + hp300hpux_vec) tb="$tb hp300hpux.o aout32.o" ;; + i386aout_vec) tb="$tb i386aout.o aout32.o" ;; + i386bsd_vec) tb="$tb i386bsd.o aout32.o" ;; + i386coff_vec) tb="$tb coff-i386.o cofflink.o" ;; + i386dynix_vec) tb="$tb i386dynix.o aout32.o" ;; + i386freebsd_vec) tb="$tb i386freebsd.o aout32.o" ;; + i386msdos_vec) tb="$tb i386msdos.o" ;; + i386pe_vec) tb="$tb pe-i386.o cofflink.o " ;; + i386pei_vec) tb="$tb pei-i386.o cofflink.o" ;; + i386linux_vec) tb="$tb i386linux.o aout32.o" ;; + i386lynx_aout_vec) tb="$tb i386lynx.o lynx-core.o aout32.o" ;; + i386lynx_coff_vec) tb="$tb cf-i386lynx.o cofflink.o lynx-core.o" ;; + i386mach3_vec) tb="$tb i386mach3.o aout32.o" ;; + i386netbsd_vec) tb="$tb i386netbsd.o aout32.o" ;; + i386os9k_vec) tb="$tb i386os9k.o aout32.o" ;; + i860coff_vec) tb="$tb coff-i860.o cofflink.o" ;; + icoff_big_vec) tb="$tb coff-i960.o cofflink.o" ;; + icoff_little_vec) tb="$tb coff-i960.o cofflink.o" ;; + ieee_vec) tb="$tb ieee.o" ;; + m68kcoff_vec) tb="$tb coff-m68k.o cofflink.o" ;; + m68kcoffun_vec) tb="$tb coff-u68k.o coff-m68k.o cofflink.o" ;; + m68klinux_vec) tb="$tb m68klinux.o aout32.o" ;; + m68klynx_aout_vec) tb="$tb m68klynx.o lynx-core.o aout32.o" ;; + m68klynx_coff_vec) tb="$tb cf-m68klynx.o coff-m68k.o cofflink.o lynx-core.o" ;; + m68knetbsd_vec) tb="$tb m68knetbsd.o aout32.o" ;; + m68k4knetbsd_vec) tb="$tb m68k4knetbsd.o aout32.o" ;; + m68kaux_coff_vec) tb="$tb coff-aux.o coff-m68k.o cofflink.o" ;; + m88kbcs_vec) tb="$tb coff-m88k.o" ;; + newsos3_vec) tb="$tb newsos3.o aout32.o" ;; + nlm32_i386_vec) tb="$tb nlm32-i386.o nlm32.o nlm.o" ;; + nlm32_sparc_vec) tb="$tb nlm32-sparc.o nlm32.o nlm.o" ;; + nlm32_alpha_vec) tb="$tb nlm32-alpha.o nlm32.o nlm.o" + target64=true ;; + riscix_vec) tb="$tb aout32.o riscix.o" ;; + nlm32_powerpc_vec) tb="$tb nlm32-ppc.o nlm32.o nlm.o" ;; + pc532netbsd_vec) tb="$tb ns32knetbsd.o aout-ns32k.o" ;; + pc532machaout_vec) tb="$tb pc532-mach.o aout-ns32k.o" ;; + pmac_xcoff_vec) tb="$tb coff-pmac.o xcofflink.o" ;; + rs6000coff_vec) tb="$tb coff-rs6000.o xcofflink.o" ;; + bfd_powerpc_pe_vec) tb="$tb pe-ppc.o cofflink.o" ;; + bfd_powerpcle_pe_vec) tb="$tb pe-ppc.o cofflink.o" ;; + bfd_powerpc_pei_vec) tb="$tb pei-ppc.o cofflink.o" ;; + bfd_powerpcle_pei_vec) tb="$tb pei-ppc.o cofflink.o" ;; + shcoff_vec) tb="$tb coff-sh.o cofflink.o" ;; + shlcoff_vec) tb="$tb coff-sh.o cofflink.o" ;; + som_vec) tb="$tb som.o" ;; + sparclynx_aout_vec) tb="$tb sparclynx.o lynx-core.o aout32.o" ;; + sparclynx_coff_vec) tb="$tb cf-sparclynx.o lynx-core.o" ;; + sparcnetbsd_vec) tb="$tb sparcnetbsd.o aout32.o" ;; + sparccoff_vec) tb="$tb coff-sparc.o" ;; + srec_vec) tb="$tb srec.o" ;; + sunos_big_vec) tb="$tb sunos.o aout32.o" ;; + symbolsrec_vec) tb="$tb srec.o" ;; + tekhex_vec) tb="$tb tekhex.o" ;; + we32kcoff_vec) tb="$tb coff-we32k.o" ;; + z8kcoff_vec) tb="$tb coff-z8k.o reloc16.o" ;; + w65_vec) tb="$tb coff-w65.o reloc16.o" ;; + versados_vec) tb="$tb versados.o" ;; + + "") ;; + *) { echo "configure: error: *** unknown target vector $vec" 1>&2; exit 1; } ;; + esac +done + +# Target architecture .o files. +ta=`echo $selarchs | sed -e s/bfd_/cpu-/g -e s/_arch/.o/g` + +# Weed out duplicate .o files. +f="" +for i in $tb ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +tb="$f" + +f="" +for i in $ta ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +ta="$f" + +bfd_backends="$tb" +bfd_machines="$ta" + +if test x${all_targets} = xtrue ; then + bfd_backends="${bfd_backends}"' $(ALL_BACKENDS)' + bfd_machines="${bfd_machines}"' $(ALL_MACHINES)' + selvecs= + selarchs= +else # all_targets is true + # Only set these if they will be nonempty, for the clever echo. + test -n "$selvecs" && + selvecs=`echo $selvecs | sed -e 's/^/\&/' -e 's/ \(.\)/,\&\1/g'` + test -n "$selarchs" && + selarchs=`echo $selarchs | sed -e 's/^/\&/' -e 's/ \(.\)/,\&\1/g'` +fi # all_targets is true + +case ${host64}-${target64}-${want64} in + *true*) + wordsize=64 + all_backends='$(BFD64_BACKENDS) $(BFD32_BACKENDS)' + ;; + false-false-false) + wordsize=32 + all_backends='$(BFD32_BACKENDS)' + ;; +esac + + + + + + +tdefaults="" +test -n "${defvec}" && tdefaults="${tdefaults} -DDEFAULT_VECTOR=${defvec}" +test -n "${selvecs}" && tdefaults="${tdefaults} -DSELECT_VECS='${selvecs}'" +test -n "${selarchs}" && tdefaults="${tdefaults} -DSELECT_ARCHITECTURES='${selarchs}'" + + +for ac_func in valloc getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1950: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_mmap'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap=no +else +cat > conftest.$ac_ext < +#include +#include + +#ifndef HAVE_GETPAGESIZE +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif +# else +# ifdef NBPC +# define getpagesize() NBPC +# else +# define getpagesize() PAGESIZE /* SVR4 */ +# endif +# endif +# endif +#endif + +#ifndef HAVE_VALLOC +# define valloc malloc +#endif + +#ifdef __cplusplus +extern "C" { void *valloc(unsigned), *malloc(unsigned); } +#else +char *valloc(), *malloc(); +#endif + +int +main() +{ + char *buf1, *buf2, *buf3; + int i = getpagesize(), j; + int i2 = i * 2; + int fd; + + buf1 = (char *)valloc(i2); + buf2 = (char *)valloc(i); + buf3 = (char *)malloc(i2); + for (j = 0; j < i2; ++j) + *(buf1 + j) = rand(); + fd = open("conftestmmap", O_CREAT | O_RDWR, 0666); + write(fd, buf1, i2); + mmap(buf2, i, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, fd, 0); + for (j = 0; j < i; ++j) + if (*(buf1 + j) != *(buf2 + j)) + exit(1); + lseek(fd, (long)i, 0); + read(fd, buf2, i); /* read into mapped memory -- file should not change */ + /* (it does in i386 SVR4.0 - Jim Avera, jima@netcom.com) */ + lseek(fd, (long)0, 0); + read(fd, buf3, i2); + for (j = 0; j < i2; ++j) + if (*(buf1 + j) != *(buf3 + j)) + exit(1); + exit(0); +} + +EOF +{ (eval echo configure:2049: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_func_mmap=yes +else + ac_cv_func_mmap=no +fi +fi +rm -fr conftest* +fi + +echo "$ac_t""$ac_cv_func_mmap" 1>&6 +if test $ac_cv_func_mmap = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + +for ac_func in madvise mprotect +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2096: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +case ${want_mmap}+${ac_cv_func_mmap} in + true+yes ) cat >> confdefs.h <<\EOF +#define USE_MMAP 1 +EOF + ;; +esac + +rm -f doc/config.status +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ + >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.8" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile doc/Makefile config.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@HDEFINES@%$HDEFINES%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@ALLLIBS@%$ALLLIBS%g +s%@PICFLAG@%$PICFLAG%g +s%@SHLIB@%$SHLIB%g +s%@SHLIB_CC@%$SHLIB_CC%g +s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g +s%@COMMON_SHLIB@%$COMMON_SHLIB%g +s%@PICLIST@%$PICLIST%g +s%@SHLINK@%$SHLINK%g +s%@HOST_64BIT_LONG@%$HOST_64BIT_LONG%g +s%@CC_FOR_BUILD@%$CC_FOR_BUILD%g +s%@CPP@%$CPP%g +s%@COREFILE@%$COREFILE%g +s%@COREFLAG@%$COREFLAG%g +s%@TDEFINES@%$TDEFINES%g +s%@wordsize@%$wordsize%g +s%@all_backends@%$all_backends%g +s%@bfd_backends@%$bfd_backends%g +s%@bfd_machines@%$bfd_machines%g +s%@tdefaults@%$tdefaults%g + +CEOF +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust relative srcdir, etc. for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file +fi; done +rm -f conftest.subs + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +CONFIG_HEADERS=${CONFIG_HEADERS-"config.h:config.in"} +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + cp $ac_given_srcdir/$ac_file_in conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. +# Maximum number of lines to put in a single here document. +ac_max_here_lines=12 + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + + +case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/contrib/gdb/bfd/configure.bat b/contrib/gdb/bfd/configure.bat new file mode 100644 index 000000000000..78fe79e91123 --- /dev/null +++ b/contrib/gdb/bfd/configure.bat @@ -0,0 +1,18 @@ +@echo off +if "%1" == "h8/300" goto h8300 + +echo Configuring bfd for go32 +update hosts\go32.h sysdep.h +update Makefile.dos Makefile +echo s/@WORDSIZE@/32/g>config.sed +sed -e s/^/s\/@VERSION@\// -e s/$/\/g/g version >>config.sed +sed -f config.sed < bfd-in2.h > bfd.h2 +update bfd.h2 bfd.h +goto exit + +:h8300 +echo Configuring bfd for H8/300 +update hosts\h-go32.h sysdep.h +update Makefile.dos Makefile + +:exit diff --git a/contrib/gdb/bfd/configure.host b/contrib/gdb/bfd/configure.host new file mode 100644 index 000000000000..484e5bda90eb --- /dev/null +++ b/contrib/gdb/bfd/configure.host @@ -0,0 +1,128 @@ +# This file is a shell script that overrides some of the tools and +# flags used on a host specific basis. + +# Since the "bfd/hosts" directory is shared by the bfd, opcodes, and +# binutils directories (at least), the index to it is also shared. +# This is that index. Each configure.in file should source this file +# in its per-host part. + +# This sets the following shell variables: +# HDEFINES host specific compiler options +# host64 set to true if this is a 64 bit host +# HOST_64BIT_TYPE host 64 bit type +# SHLIB_CC compiler to use when building shared library +# SHLIB_CFLAGS flags to use when building shared library +# PICFLAG may be set to flag to use to compile PIC +# SHLINK may be set to the name to link the shared library to +# ALLLIBS may be set to libraries to build +# HLDFLAGS LDFLAGS specific to the host +# RPATH_ENVVAR environment variable used to find shared libraries + +HDEFINES= +host64=false +HOST_64BIT_TYPE= + +case "${host}" in + +alpha-*-*) host64=true; HOST_64BIT_TYPE=long ;; + +hppa*-*-hpux*) HDEFINES=-DHOST_HPPAHPUX ;; +hppa*-*-hiux*) HDEFINES=-DHOST_HPPAHPUX ;; +hppa*-*-bsd*) HDEFINES=-DHOST_HPPABSD ;; +hppa*-*-osf*) HDEFINES=-DHOST_HPPAOSF ;; + +i[345]86-sequent-bsd*) HDEFINES=-Dshared=genshared ;; +i[345]86-sequent-sysv4*) ;; +i[345]86-sequent-sysv*) HDEFINES=-Dshared=genshared ;; + +mips-dec-netbsd*) ;; +mips-dec-*) HDEFINES="-G 4" ;; +mips-sgi-irix3*) HDEFINES="-G 4" ;; +mips-sgi-irix4*) HDEFINES="-G 4" ;; +mips-*-sysv4*) ;; +mips-*-sysv*) HDEFINES="-G 4" ;; +mips-*-riscos*) HDEFINES="-G 4" ;; + +m68*-hp-hpux*) HDEFINES=-DHOST_HP300HPUX ;; + +esac + +# If we are configuring with --enable-shared, adjust the shared +# library support based on the host. This support must work for both +# the BFD and the opcodes libraries. +HLDFLAGS= +RPATH_ENVVAR=LD_LIBRARY_PATH +SHLIB_CC='$(CC)' +SHLIB_CFLAGS='-shared' +if [ "${shared}" = "true" ]; then + case "${host}" in + hppa*-*-*) picfrag=../config/mh-papic ;; + i[3456]86-*-*) picfrag=../config/mh-x86pic ;; + *-*-*) picfrag=../config/mh-${host_cpu}pic ;; + esac + if [ -f "${picfrag}" ]; then + pic=`sed -n -e 's/^PICFLAG[ ]*=[ ]*\(.*\)$/\1/p' ${picfrag}` + if [ -n "${pic}" ]; then + PICFLAG=${pic} + fi + fi + + case "${host}" in + *-dec-osf*) + # -fpic is not needed on the Alpha. + PICFLAG= + ;; + *-*-hpux*) + # HP/UX uses .sl for shared libraries. + SHLINK=`echo ${SHLINK} | sed -e 's/so$/sl/'` + SHLIB_CFLAGS='-shared $(PICFLAG)' + HLDFLAGS='-Wl,+s,+b,$(libdir)' + RPATH_ENVVAR=SHLIB_PATH + ;; + *-*-irix5*) + # -fpic is not needed on Irix 5. + PICFLAG= + SHLIB_CFLAGS='-shared -Wl,-soname,$(SONAME)' + HLDFLAGS='-Wl,-rpath,$(libdir)' + ;; + *-*-linux*aout*) + ;; + *-*-linux*) + SHLIB_CFLAGS='-shared -Wl,-soname,$(SONAME)' + case "$(libdir)" in + /lib | /usr/lib) ;; + *) HLDFLAGS='-Wl,-rpath,$(libdir)' ;; + esac + ;; + *-*-sysv4* | *-*-solaris*) + SHLIB_CFLAGS='-shared -h $(SONAME)' + HLDFLAGS='-R $(libdir)' + ;; + *-*-sunos*) + # Build a libTARGET-bfd.so.VERSION symlink in the object directory. + ALLLIBS=`echo ${ALLLIBS} | sed -e 's/\$(SHLINK)/stamp-tshlink/'` + ;; + esac +fi + +# On SunOS, if the linker supports the -rpath option, use it to +# prevent ../bfd and ../opcodes from being included in the run time +# search path. +case "${host}" in + *-*-sunos*) + echo 'main () { }' > conftest.c + ${CC} -o conftest -Wl,-rpath= conftest.c >/dev/null 2>conftest.t + if grep 'unrecognized' conftest.t >/dev/null 2>&1; then + : + elif grep 'No such file' conftest.t >/dev/null 2>&1; then + : + elif grep 'do not mix' conftest.t >/dev/null 2>&1; then + : + elif [ "${shared}" = "true" ]; then + HLDFLAGS='-Wl,-rpath=$(libdir)' + else + HLDFLAGS='-Wl,-rpath=' + fi + rm -f conftest.t conftest.c conftest + ;; +esac diff --git a/contrib/gdb/bfd/configure.in b/contrib/gdb/bfd/configure.in new file mode 100644 index 000000000000..c8b8de54fe92 --- /dev/null +++ b/contrib/gdb/bfd/configure.in @@ -0,0 +1,577 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +AC_PREREQ(2.3) +AC_INIT(libbfd.c) + +AC_ARG_ENABLE(64-bit-bfd, +[ --enable-64-bit-bfd 64-bit support (on hosts with narrower word sizes)], +[case "${enableval}" in + yes) want64=true ;; + no) want64=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for 64-bit-bfd option) ;; +esac],[want64=false])dnl +AC_ARG_ENABLE(targets, +[ --enable-targets alternative target configurations], +[case "${enableval}" in + yes | "") AC_ERROR(enable-targets option must specify target names or 'all') + ;; + no) enable_targets= ;; + *) enable_targets=$enableval ;; +esac])dnl +AC_ARG_ENABLE(shared, +[ --enable-shared build shared BFD library], +[case "${enableval}" in + yes) shared=true ;; + no) shared=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for BFD shared option]) ;; +esac])dnl +AC_ARG_ENABLE(commonbfdlib, +[ --enable-commonbfdlib build shared BFD/opcodes/libiberty library], +[case "${enableval}" in + yes) commonbfdlib=true ;; + no) commonbfdlib=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for BFD commonbfdlib option]) ;; +esac])dnl +AC_ARG_WITH(mmap, +[ --with-mmap try using mmap for BFD input files if available], +[case "${withval}" in + yes) want_mmap=true ;; + no) want_mmap=false ;; + *) AC_MSG_ERROR(bad value ${withval} for BFD with-mmap option) ;; +esac],[want_mmap=false])dnl + +AC_CONFIG_HEADER(config.h:config.in) + +AC_CONFIG_AUX_DIR(`cd $srcdir/..;pwd`) +AC_CANONICAL_SYSTEM +if test -z "$target" ; then + AC_MSG_ERROR(Unrecognized target system type; please check config.sub.) +fi +AC_ARG_PROGRAM + +host64=false +target64=false + +# host stuff: + +ALLLIBS='$(TARGETLIB)' +PICFLAG= +SHLIB=unused-shlib +SHLINK=unused-shlink +if test "${shared}" = "true"; then + PICFLAG=-fpic + if test "${commonbfdlib}" = "true"; then + ALLLIBS='$(TARGETLIB)' + else + ALLLIBS='$(TARGETLIB) $(SHLIB) $(SHLINK)' +changequote(,)dnl + SHLIB=libbfd.so.`sed -e 's/[^0-9]*\([0-9.]*\).*/\1/' ${srcdir}/VERSION` +changequote([,])dnl + SHLINK=libbfd.so + fi +fi + +AC_PROG_CC + +# Permit host specific settings. +. ${srcdir}/configure.host + +AC_SUBST(HDEFINES) +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_PROG_INSTALL + +if test "${shared}" = "true"; then + if test "${GCC}" != "yes" && test "${shared_non_gcc}" != "yes"; then + AC_MSG_WARN([BFD --enable-shared only supported when using gcc]) + shared=false + ALLLIBS='$(TARGETLIB)' + PICFLAG= + SHLIB=unused-shlib + fi +fi + +AC_SUBST(ALLLIBS) +AC_SUBST(PICFLAG) +AC_SUBST(SHLIB) +AC_SUBST(SHLIB_CC) +AC_SUBST(SHLIB_CFLAGS) +if test "${commonbfdlib}" = "true"; then + COMMON_SHLIB=yes + PICLIST=piclist +else + COMMON_SHLIB= + PICLIST= +fi +AC_SUBST(COMMON_SHLIB) +AC_SUBST(PICLIST) +AC_SUBST(SHLINK) + +HOST_64BIT_LONG=0 +if test "x${HOST_64BIT_TYPE}" = "xlong"; then + HOST_64BIT_LONG=1 +fi +AC_SUBST(HOST_64BIT_LONG) + +BFD_CC_FOR_BUILD + +AC_CHECK_HEADERS(stddef.h string.h strings.h stdlib.h time.h unistd.h) +AC_CHECK_HEADERS(fcntl.h sys/file.h sys/time.h) +AC_HEADER_TIME +AC_CHECK_FUNCS(fcntl getpagesize) + +BFD_BINARY_FOPEN + +BFD_NEED_DECLARATION(malloc) +BFD_NEED_DECLARATION(free) + +# If we are configured native, pick a core file support file. +COREFILE= +COREFLAG= +if test "${target}" = "${host}"; then + case "${host}" in + alpha*-*-linux*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/alphalinux.h") + ;; + alpha*-*-*) COREFILE=osf-core.o ;; + arm-*-riscix) COREFILE=trad-core.o ;; + hppa*-*-hpux*) COREFILE=hpux-core.o ;; + hppa*-*-hiux*) COREFILE=hpux-core.o ;; + hppa*-*-bsd*) COREFILE="hpux-core.o hppabsd-core.o" + COREFLAG="-DHPUX_CORE -DHPPABSD_CORE" ;; +changequote(,)dnl + i[345]86-sequent-bsd*) +changequote([,])dnl + COREFILE=trad-core.o; + AC_DEFINE(TRAD_HEADER,"hosts/symmetry.h") + ;; +changequote(,)dnl + i[345]86-sequent-sysv4*) ;; + i[345]86-sequent-sysv*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/symmetry.h") + ;; +changequote(,)dnl + i[345]86-*-bsd* | i[345]86-*-freebsd*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/i386bsd.h") + ;; +changequote(,)dnl + i[345]86-*-netbsd*) +changequote([,])dnl + COREFILE=netbsd-core.o + ;; +changequote(,)dnl + i[345]86-esix-sysv3*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/esix.h") + ;; +changequote(,)dnl + i[345]86-*-sco* | i[345]86-*-isc*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/i386sco.h") + ;; +changequote(,)dnl + i[345]86-*-mach3*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/i386mach3.h") + ;; +changequote(,)dnl + i[345]86-*-linux*) +changequote([,])dnl + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/i386linux.h") + ;; +changequote(,)dnl + i[345]86-*-isc*) COREFILE=trad-core.o ;; + i[345]86-*-aix*) COREFILE=aix386-core.o ;; +changequote([,])dnl + i860-*-mach3* | i860-*-osf1*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/i860mach3.h") + ;; + mips-dec-bsd*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/mipsbsd.h") + ;; + mips-dec-mach3*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/mipsmach3.h") + ;; + mips-*-netbsd*) + COREFILE=netbsd-core.o + ;; + mips-dec-*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/decstation.h") + ;; + mips-sgi-irix4*) COREFILE=irix-core.o ;; + mips-sgi-irix5*) COREFILE=irix-core.o ;; + mips-*-mach3*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/mipsmach3.h") + ;; + mips-*-sysv4*) ;; + mips-*-sysv* | mips-*-riscos*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/riscos.h") + ;; + mips-sony-bsd*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/news-mips.h") + ;; + m68*-bull*-sysv*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/dpx2.h") + ;; + m68*-hp-hpux*) COREFILE=hpux-core.o ;; + m68*-hp-bsd*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/hp300bsd.h") + ;; + m68*-*-linux*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/m68klinux.h") + ;; + m68*-motorola-sysv*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER, "hosts/delta68.h") + ;; + m68*-sony-*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/news.h") + ;; + m68*-*-netbsd*) + COREFILE=netbsd-core.o + ;; + m68*-apple-aux*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/m68kaux.h") + ;; + m88*-*-sysv4*) ;; + m88*-motorola-sysv*) COREFILE=ptrace-core.o ;; + m88*-*-mach3*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/m88kmach3.h") + ;; + ns32k-pc532-mach) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/pc532mach.h") + ;; + ns32k-*-netbsd*) + COREFILE=netbsd-core.o + ;; + rs6000-*-lynx*) COREFILE=lynx-core.o ;; + rs6000-*-aix4*) COREFILE=rs6000-core.o ;; + rs6000-*-*) COREFILE=rs6000-core.o ;; + powerpc-*-aix4*) COREFILE=rs6000-core.o ;; + powerpc-*-aix*) COREFILE=rs6000-core.o ;; + sparc-*-netbsd*) + COREFILE=netbsd-core.o + ;; + tahoe-*-*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/tahoe.h") + ;; + vax-*-ultrix2*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/vaxult2.h") + ;; + vax-*-ultrix*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/vaxult2.h") + ;; + vax-*-*) + COREFILE=trad-core.o + AC_DEFINE(TRAD_HEADER,"hosts/vaxbsd.h") + ;; + esac + + case "$COREFILE" in + aix386-core.o) COREFLAG=-DAIX386_CORE ;; + hppabsd-core.o) COREFLAG=-DHPPABSD_CORE ;; + hpux-core.o) COREFLAG=-DHPUX_CORE ;; + irix-core.o) COREFLAG=-DIRIX_CORE ;; + lynx-core.o) COREFLAG=-DLYNX_CORE ;; + osf-core.o) COREFLAG=-DOSF_CORE ;; + ptrace-core.o) COREFLAG=-DPTRACE_CORE ;; + rs6000-core.o) COREFLAG="$COREFLAG -DAIX_CORE" ;; + trad-core.o) COREFLAG="$COREFLAG -DTRAD_CORE" ;; + esac + + # The ELF code uses the native to handle core files. + # Define HAVE_SYS_PROCFS_H if the file exists and defines + # prstatus_t. + AC_MSG_CHECKING([for sys/procfs.h]) + AC_CACHE_VAL(bfd_cv_header_sys_procfs_h, + [AC_TRY_COMPILE([#include ], + [prstatus_t t;], + bfd_cv_header_sys_procfs_h=yes, bfd_cv_header_sys_procfs_h=no)]) + AC_MSG_RESULT($bfd_cv_header_sys_procfs_h) + if test $bfd_cv_header_sys_procfs_h = yes; then + AC_DEFINE(HAVE_SYS_PROCFS_H) + fi + +fi +AC_SUBST(COREFILE) +AC_SUBST(COREFLAG) + +# target stuff: + +# Canonicalize the secondary target names. +if test -n "$enable_targets" ; then + for targ in `echo $enable_targets | sed 's/,/ /g'` + do + result=`$ac_config_sub $targ 2>/dev/null` + if test -n "$result" ; then + canon_targets="$canon_targets $result" + else + # Allow targets that config.sub doesn't recognize, like "all". + canon_targets="$canon_targets $targ" + fi + done +fi + +all_targets=false +defvec= +selvecs= +selarchs= +TDEFINES= +for targ in $target $canon_targets +do + if test "x$targ" = "xall"; then + all_targets=true + else + . $srcdir/config.bfd + if test "x$targ" = "x$target"; then + defvec=$targ_defvec + fi + selvecs="$selvecs $targ_defvec $targ_selvecs" + selarchs="$selarchs $targ_archs" + TDEFINES="$TDEFINES $targ_cflags" + fi +done +AC_SUBST(TDEFINES) + +# This processing still needs to be done if we're to decide properly whether +# 64-bit support needs to be compiled in. Currently, it will be included if +# the default or any other explicitly requested target requires it; it +# will not be included on a 32-bit host if no 64-bit target is requested, and +# no "--with-64-bit-bfd" option is given, even if "--with-targets=all" is +# used. + +# uniq the default and selected vectors in all the configured targets. +f="" +for i in $selvecs ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +selvecs="$f" + +# uniq the architectures in all the configured targets. +f="" +for i in $selarchs ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +selarchs="$f" + +# Target backend .o files. +tb= + +elf="elf.o elflink.o" + +for vec in $selvecs +do + case "$vec" in + # This list is alphabetized to make it easy to compare + # with the two vector lists in targets.c. + a29kcoff_big_vec) tb="$tb coff-a29k.o cofflink.o" ;; + a_out_adobe_vec) tb="$tb aout-adobe.o aout32.o" ;; + armcoff_little_vec) tb="$tb coff-arm.o cofflink.o " ;; + armcoff_big_vec) tb="$tb coff-arm.o cofflink.o " ;; + armpe_little_vec) tb="$tb pe-arm.o cofflink.o " ;; + armpe_big_vec) tb="$tb pe-arm.o cofflink.o " ;; + armpei_little_vec) tb="$tb pei-arm.o cofflink.o " ;; + armpei_big_vec) tb="$tb pei-arm.o cofflink.o " ;; + aout0_big_vec) tb="$tb aout0.o aout32.o" ;; + aout_arm_big_vec) tb="$tb aout-arm.o aout32.o" ;; + aout_arm_little_vec) tb="$tb aout-arm.o aout32.o" ;; + aout_mips_big_vec) tb="$tb mipsbsd.o aout32.o" ;; + aout_mips_little_vec) tb="$tb mipsbsd.o aout32.o" ;; + apollocoff_vec) tb="$tb coff-apollo.o" ;; + b_out_vec_big_host) tb="$tb bout.o aout32.o" ;; + b_out_vec_little_host) tb="$tb bout.o aout32.o" ;; + bfd_elf32_big_generic_vec) tb="$tb elf32-gen.o elf32.o $elf" ;; + bfd_elf32_bigmips_vec) tb="$tb elf32-mips.o elf32.o $elf ecofflink.o" ;; + bfd_elf32_hppa_vec) tb="$tb elf32-hppa.o elf32.o $elf" ;; + bfd_elf32_i386_vec) tb="$tb elf32-i386.o elf32.o $elf" ;; + bfd_elf32_i860_vec) tb="$tb elf32-i860.o elf32.o $elf" ;; + bfd_elf32_little_generic_vec) tb="$tb elf32-gen.o elf32.o $elf" ;; + bfd_elf32_littlemips_vec) tb="$tb elf32-mips.o elf32.o $elf ecofflink.o" ;; + bfd_elf32_m68k_vec) tb="$tb elf32-m68k.o elf32.o $elf" ;; + bfd_elf32_m88k_vec) tb="$tb elf32-m88k.o elf32.o $elf" ;; + bfd_elf32_powerpc_vec) tb="$tb elf32-ppc.o elf32.o $elf" ;; + bfd_elf32_powerpcle_vec) tb="$tb elf32-ppc.o elf32.o $elf" ;; + bfd_elf32_sparc_vec) tb="$tb elf32-sparc.o elf32.o $elf" ;; + bfd_elf64_big_generic_vec) tb="$tb elf64-gen.o elf64.o $elf" + target64=true ;; + bfd_elf64_little_generic_vec) tb="$tb elf64-gen.o elf64.o $elf" + target64=true ;; + bfd_elf64_sparc_vec) tb="$tb elf64-sparc.o elf64.o $elf" + target64=true ;; + cisco_core_vec) tb="$tb cisco-core.o" ;; + demo_64_vec) tb="$tb demo64.o aout64.o" + target64=true ;; + ecoff_big_vec) tb="$tb coff-mips.o ecoff.o ecofflink.o" ;; + ecoff_little_vec) tb="$tb coff-mips.o ecoff.o ecofflink.o" ;; + ecoffalpha_little_vec) tb="$tb coff-alpha.o ecoff.o ecofflink.o" + target64=true ;; + h8300coff_vec) tb="$tb coff-h8300.o reloc16.o" ;; + h8500coff_vec) tb="$tb coff-h8500.o reloc16.o" ;; + host_aout_vec) tb="$tb host-aout.o aout32.o" ;; + hp300bsd_vec) tb="$tb hp300bsd.o aout32.o" ;; + hp300hpux_vec) tb="$tb hp300hpux.o aout32.o" ;; + i386aout_vec) tb="$tb i386aout.o aout32.o" ;; + i386bsd_vec) tb="$tb i386bsd.o aout32.o" ;; + i386coff_vec) tb="$tb coff-i386.o cofflink.o" ;; + i386dynix_vec) tb="$tb i386dynix.o aout32.o" ;; + i386freebsd_vec) tb="$tb i386freebsd.o aout32.o" ;; + i386msdos_vec) tb="$tb i386msdos.o" ;; + i386pe_vec) tb="$tb pe-i386.o cofflink.o " ;; + i386pei_vec) tb="$tb pei-i386.o cofflink.o" ;; + i386linux_vec) tb="$tb i386linux.o aout32.o" ;; + i386lynx_aout_vec) tb="$tb i386lynx.o lynx-core.o aout32.o" ;; + i386lynx_coff_vec) tb="$tb cf-i386lynx.o cofflink.o lynx-core.o" ;; + i386mach3_vec) tb="$tb i386mach3.o aout32.o" ;; + i386netbsd_vec) tb="$tb i386netbsd.o aout32.o" ;; + i386os9k_vec) tb="$tb i386os9k.o aout32.o" ;; + i860coff_vec) tb="$tb coff-i860.o cofflink.o" ;; + icoff_big_vec) tb="$tb coff-i960.o cofflink.o" ;; + icoff_little_vec) tb="$tb coff-i960.o cofflink.o" ;; + ieee_vec) tb="$tb ieee.o" ;; + m68kcoff_vec) tb="$tb coff-m68k.o cofflink.o" ;; + m68kcoffun_vec) tb="$tb coff-u68k.o coff-m68k.o cofflink.o" ;; + m68klinux_vec) tb="$tb m68klinux.o aout32.o" ;; + m68klynx_aout_vec) tb="$tb m68klynx.o lynx-core.o aout32.o" ;; + m68klynx_coff_vec) tb="$tb cf-m68klynx.o coff-m68k.o cofflink.o lynx-core.o" ;; + m68knetbsd_vec) tb="$tb m68knetbsd.o aout32.o" ;; + m68k4knetbsd_vec) tb="$tb m68k4knetbsd.o aout32.o" ;; + m68kaux_coff_vec) tb="$tb coff-aux.o coff-m68k.o cofflink.o" ;; + m88kbcs_vec) tb="$tb coff-m88k.o" ;; + newsos3_vec) tb="$tb newsos3.o aout32.o" ;; + nlm32_i386_vec) tb="$tb nlm32-i386.o nlm32.o nlm.o" ;; + nlm32_sparc_vec) tb="$tb nlm32-sparc.o nlm32.o nlm.o" ;; + nlm32_alpha_vec) tb="$tb nlm32-alpha.o nlm32.o nlm.o" + target64=true ;; + riscix_vec) tb="$tb aout32.o riscix.o" ;; + nlm32_powerpc_vec) tb="$tb nlm32-ppc.o nlm32.o nlm.o" ;; + pc532netbsd_vec) tb="$tb ns32knetbsd.o aout-ns32k.o" ;; + pc532machaout_vec) tb="$tb pc532-mach.o aout-ns32k.o" ;; + pmac_xcoff_vec) tb="$tb coff-pmac.o xcofflink.o" ;; + rs6000coff_vec) tb="$tb coff-rs6000.o xcofflink.o" ;; + bfd_powerpc_pe_vec) tb="$tb pe-ppc.o cofflink.o" ;; + bfd_powerpcle_pe_vec) tb="$tb pe-ppc.o cofflink.o" ;; + bfd_powerpc_pei_vec) tb="$tb pei-ppc.o cofflink.o" ;; + bfd_powerpcle_pei_vec) tb="$tb pei-ppc.o cofflink.o" ;; + shcoff_vec) tb="$tb coff-sh.o cofflink.o" ;; + shlcoff_vec) tb="$tb coff-sh.o cofflink.o" ;; + som_vec) tb="$tb som.o" ;; + sparclynx_aout_vec) tb="$tb sparclynx.o lynx-core.o aout32.o" ;; + sparclynx_coff_vec) tb="$tb cf-sparclynx.o lynx-core.o" ;; + sparcnetbsd_vec) tb="$tb sparcnetbsd.o aout32.o" ;; + sparccoff_vec) tb="$tb coff-sparc.o" ;; + srec_vec) tb="$tb srec.o" ;; + sunos_big_vec) tb="$tb sunos.o aout32.o" ;; + symbolsrec_vec) tb="$tb srec.o" ;; + tekhex_vec) tb="$tb tekhex.o" ;; + we32kcoff_vec) tb="$tb coff-we32k.o" ;; + z8kcoff_vec) tb="$tb coff-z8k.o reloc16.o" ;; + w65_vec) tb="$tb coff-w65.o reloc16.o" ;; + versados_vec) tb="$tb versados.o" ;; + + "") ;; + *) AC_MSG_ERROR(*** unknown target vector $vec) ;; + esac +done + +# Target architecture .o files. +ta=`echo $selarchs | sed -e s/bfd_/cpu-/g -e s/_arch/.o/g` + +# Weed out duplicate .o files. +f="" +for i in $tb ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +tb="$f" + +f="" +for i in $ta ; do + case " $f " in + *" $i "*) ;; + *) f="$f $i" ;; + esac +done +ta="$f" + +bfd_backends="$tb" +bfd_machines="$ta" + +if test x${all_targets} = xtrue ; then + bfd_backends="${bfd_backends}"' $(ALL_BACKENDS)' + bfd_machines="${bfd_machines}"' $(ALL_MACHINES)' + selvecs= + selarchs= +else # all_targets is true + # Only set these if they will be nonempty, for the clever echo. + test -n "$selvecs" && + selvecs=`echo $selvecs | sed -e 's/^/\&/' -e 's/ \(.\)/,\&\1/g'` + test -n "$selarchs" && + selarchs=`echo $selarchs | sed -e 's/^/\&/' -e 's/ \(.\)/,\&\1/g'` +fi # all_targets is true + +case ${host64}-${target64}-${want64} in + *true*) + wordsize=64 + all_backends='$(BFD64_BACKENDS) $(BFD32_BACKENDS)' + ;; + false-false-false) + wordsize=32 + all_backends='$(BFD32_BACKENDS)' + ;; +esac + +AC_SUBST(wordsize) +AC_SUBST(all_backends) +AC_SUBST(bfd_backends) +AC_SUBST(bfd_machines) + +tdefaults="" +test -n "${defvec}" && tdefaults="${tdefaults} -DDEFAULT_VECTOR=${defvec}" +test -n "${selvecs}" && tdefaults="${tdefaults} -DSELECT_VECS='${selvecs}'" +test -n "${selarchs}" && tdefaults="${tdefaults} -DSELECT_ARCHITECTURES='${selarchs}'" +AC_SUBST(tdefaults) + +dnl AC_CHECK_HEADERS(sys/mman.h) +AC_FUNC_MMAP +AC_CHECK_FUNCS(madvise mprotect) +case ${want_mmap}+${ac_cv_func_mmap} in + true+yes ) AC_DEFINE(USE_MMAP) ;; +esac + +rm -f doc/config.status +AC_OUTPUT(Makefile doc/Makefile, +[case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/contrib/gdb/bfd/corefile.c b/contrib/gdb/bfd/corefile.c new file mode 100644 index 000000000000..212f519ce8a5 --- /dev/null +++ b/contrib/gdb/bfd/corefile.c @@ -0,0 +1,106 @@ +/* Core file generic interface routines for BFD. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Core files + +DESCRIPTION + These are functions pertaining to core files. +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +FUNCTION + bfd_core_file_failing_command + +SYNOPSIS + CONST char *bfd_core_file_failing_command(bfd *abfd); + +DESCRIPTION + Return a read-only string explaining which program was running + when it failed and produced the core file @var{abfd}. + +*/ + +CONST char * +bfd_core_file_failing_command (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_command, (abfd)); +} + +/* +FUNCTION + bfd_core_file_failing_signal + +SYNOPSIS + int bfd_core_file_failing_signal(bfd *abfd); + +DESCRIPTION + Returns the signal number which caused the core dump which + generated the file the BFD @var{abfd} is attached to. +*/ + +int +bfd_core_file_failing_signal (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); +} + + +/* +FUNCTION + core_file_matches_executable_p + +SYNOPSIS + boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +DESCRIPTION + Return <> if the core file attached to @var{core_bfd} + was generated by a run of the executable file attached to + @var{exec_bfd}, <> otherwise. +*/ +boolean +core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { + bfd_set_error (bfd_error_wrong_format); + return false; + } + + return BFD_SEND (core_bfd, _core_file_matches_executable_p, + (core_bfd, exec_bfd)); +} diff --git a/contrib/gdb/bfd/cpu-a29k.c b/contrib/gdb/bfd/cpu-a29k.c new file mode 100644 index 000000000000..5bd25a47720b --- /dev/null +++ b/contrib/gdb/bfd/cpu-a29k.c @@ -0,0 +1,39 @@ +/* BFD support for the AMD 29000 architecture. + Copyright 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_a29k_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_a29k, + 0, /* only 1 machine */ + "a29k", + "a29k", + 4, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-alpha.c b/contrib/gdb/bfd/cpu-alpha.c new file mode 100644 index 000000000000..0d66a8b74e80 --- /dev/null +++ b/contrib/gdb/bfd/cpu-alpha.c @@ -0,0 +1,38 @@ +/* BFD support for the Alpha architecture. + Copyright 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_alpha_arch = + { + 64, /* 32 bits in a word */ + 64, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_alpha, + 0, /* only 1 machine */ + "alpha", + "alpha", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-arm.c b/contrib/gdb/bfd/cpu-arm.c new file mode 100644 index 000000000000..92103e632f0e --- /dev/null +++ b/contrib/gdb/bfd/cpu-arm.c @@ -0,0 +1,39 @@ +/* BFD support for the ARM processor + Copyright 1994 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_arm_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_arm, + 0, /* only 1 machine */ + "arm", + "arm", + 4, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-h8300.c b/contrib/gdb/bfd/cpu-h8300.c new file mode 100644 index 000000000000..380dfb5556e9 --- /dev/null +++ b/contrib/gdb/bfd/cpu-h8300.c @@ -0,0 +1,246 @@ +/* BFD library support routines for the Hitachi H8/300 architecture. + Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#if 0 /* not used currently */ +/* +Relocations for the H8 + +*/ +static bfd_reloc_status_type +howto16_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd * abfd; + arelent * reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection * ignore_input_section; + bfd * ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_16 (abfd, (bfd_byte *) data + addr); + + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_16 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd * abfd; + arelent * reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection * ignore_input_section; + bfd * ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_FFnn_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd * abfd; + arelent * reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection * ignore_input_section; + bfd * ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + abort (); + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +howto8_pcrel_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd * abfd; + arelent * reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection * ignore_input_section; + bfd * ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + abort (); + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + +static reloc_howto_type howto_16 += NEWHOWTO (howto16_callback, "abs16", 1, false, false); +static reloc_howto_type howto_8 += NEWHOWTO (howto8_callback, "abs8", 0, false, false); + +static reloc_howto_type howto_8_FFnn += NEWHOWTO (howto8_FFnn_callback, "ff00+abs8", 0, false, false); + +static reloc_howto_type howto_8_pcrel += NEWHOWTO (howto8_pcrel_callback, "pcrel8", 0, false, true); + +static reloc_howto_type * +local_bfd_reloc_type_lookup (arch, code) + const struct bfd_arch_info *arch; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_16: + return &howto_16; + case BFD_RELOC_8_FFnn: + return &howto_8_FFnn; + case BFD_RELOC_8: + return &howto_8; + case BFD_RELOC_8_PCREL: + return &howto_8_pcrel; + default: + return (reloc_howto_type *) NULL; + } + } +#endif + +int bfd_default_scan_num_mach (); + +static boolean +h8300_scan (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + if (*string != 'h' && *string != 'H') + return false; + + string++; + if (*string != '8') + return false; + + string++; + if (*string == '/') + string++; + + if (*string != '3') + return false; + string++; + if (*string != '0') + return false; + string++; + if (*string != '0') + return false; + string++; + if (*string == '-') + string++; + if (*string == 'h' || *string == 'H') + { + return (info->mach == bfd_mach_h8300h); + } + else + { + return info->mach == bfd_mach_h8300; + } +} + + +/* This routine is provided two arch_infos and works out the + machine which would be compatible with both and returns a pointer + to its info structure */ + +static const bfd_arch_info_type * +compatible (in, out) + const bfd_arch_info_type * in; + const bfd_arch_info_type * out; +{ + /* If the output is non-H and the input is -H, that's bad */ + if (in->mach == bfd_mach_h8300h && + out->mach == bfd_mach_h8300) + return 0; + + /* If either is an -H, the answer is -H */ + if (in->mach == bfd_mach_h8300h) + return in; + return out; +} + +static const bfd_arch_info_type h8300_info_struct = +{ + 16, /* 16 bits in a word */ + 16, /* 16 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_h8300, + bfd_mach_h8300, + "h8300", /* arch_name */ + "h8300", /* printable name */ + 1, + true, /* the default machine */ + compatible, + h8300_scan, +/* local_bfd_reloc_type_lookup, */ + 0, +}; + + +const bfd_arch_info_type bfd_h8300_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_h8300, + bfd_mach_h8300h, + "h8300h", /* arch_name */ + "h8300h", /* printable name */ + 1, + false, /* the default machine */ + compatible, + h8300_scan, +/* local_bfd_reloc_type_lookup, */ + &h8300_info_struct, +}; diff --git a/contrib/gdb/bfd/cpu-h8500.c b/contrib/gdb/bfd/cpu-h8500.c new file mode 100644 index 000000000000..e4abfd178070 --- /dev/null +++ b/contrib/gdb/bfd/cpu-h8500.c @@ -0,0 +1,199 @@ +/* BFD library support routines for the H8/500 architecture. + Copyright (C) 1993 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#if 0 + +/* +Relocations for the Z8K + +*/ +static bfd_reloc_status_type +howto16_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_16(abfd, (bfd_byte *)data + addr); + + HOWTO_PREPARE(relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_16(abfd, x, (bfd_byte *)data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8(abfd, (bfd_byte *)data + addr); + + HOWTO_PREPARE(relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8(abfd, x, (bfd_byte *)data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_FFnn_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + + long x = bfd_get_8(abfd, (bfd_byte *)data + addr); + abort(); + HOWTO_PREPARE(relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8(abfd, x, (bfd_byte *)data + addr); + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +howto8_pcrel_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8(abfd, (bfd_byte *)data + addr); + abort(); + HOWTO_PREPARE(relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8(abfd, x, (bfd_byte *)data + addr); + return bfd_reloc_ok; +} + + + +static reloc_howto_type howto_16 + = NEWHOWTO(howto16_callback,"abs16",1,false,false); +static reloc_howto_type howto_8 + = NEWHOWTO(howto8_callback,"abs8",0,false,false); + +static reloc_howto_type howto_8_FFnn + = NEWHOWTO(howto8_FFnn_callback,"ff00+abs8",0,false,false); + +static reloc_howto_type howto_8_pcrel + = NEWHOWTO(howto8_pcrel_callback,"pcrel8",0,false,true); + + +static reloc_howto_type * +local_bfd_reloc_type_lookup (arch, code) + const struct bfd_arch_info *arch; + bfd_reloc_code_real_type code; +{ + switch (code) { + case BFD_RELOC_16: + return &howto_16; + case BFD_RELOC_8_FFnn: + return &howto_8_FFnn; + case BFD_RELOC_8: + return &howto_8; + case BFD_RELOC_8_PCREL: + return &howto_8_pcrel; + } + return (reloc_howto_type *)NULL; +} +#endif + +int bfd_default_scan_num_mach(); + +static boolean +scan_mach (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + if (strcmp(string,"h8/500") == 0) return true; + if (strcmp(string,"H8/500") == 0) return true; + if (strcmp(string,"h8500") == 0) return true; + if (strcmp(string,"H8500") == 0) return true; + return false; +} + + +#if 0 /* not used currently */ +/* This routine is provided two arch_infos and returns whether + they'd be compatible */ + +static const bfd_arch_info_type * +compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->arch != b->arch || a->mach != b->mach) + return NULL; + return a; +} +#endif + +const bfd_arch_info_type bfd_h8500_arch = +{ + 16, /* 16 bits in a word */ + 24, /* 24 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_h8500, + 0, /* only 1 machine */ + "h8500", /* arch_name */ + "h8500", /* printable name */ + 1, + true, /* the default machine */ + bfd_default_compatible, + scan_mach, + 0, +}; diff --git a/contrib/gdb/bfd/cpu-hppa.c b/contrib/gdb/bfd/cpu-hppa.c new file mode 100644 index 000000000000..5201008dfe1c --- /dev/null +++ b/contrib/gdb/bfd/cpu-hppa.c @@ -0,0 +1,54 @@ +/* BFD support for the HP Precision Architecture architecture. + Copyright 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static const bfd_arch_info_type bfd_hppa10_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_hppa, + 10, /* By convention PA1.0 = 10 */ + "hppa", + "hppa1.0", + 3, + true, /* Unless we use 1.1 specific features */ + bfd_default_compatible, + bfd_default_scan , + 0, +}; + +const bfd_arch_info_type bfd_hppa_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_hppa, + 11, /* By convention PA1.1 = 11 */ + "hppa", + "hppa1.1", + 3, + false, /* 1.1 specific features used */ + bfd_default_compatible, + bfd_default_scan , + &bfd_hppa10_arch, +}; diff --git a/contrib/gdb/bfd/cpu-i386.c b/contrib/gdb/bfd/cpu-i386.c new file mode 100644 index 000000000000..404109033b7f --- /dev/null +++ b/contrib/gdb/bfd/cpu-i386.c @@ -0,0 +1,38 @@ +/* BFD support for the Intel 386 architecture. + Copyright 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_i386_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + 0, /* only 1 machine */ + "i386", + "i386", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-i860.c b/contrib/gdb/bfd/cpu-i860.c new file mode 100644 index 000000000000..57c867cdb2cb --- /dev/null +++ b/contrib/gdb/bfd/cpu-i860.c @@ -0,0 +1,40 @@ +/* BFD support for the Intel 860 architecture. + Copyright 1992, 1995 Free Software Foundation, Inc. + Created mostly by substituting "860" for "386" in cpu-i386.c + Harry Dolan , October 1995 + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_i860_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i860, + 0, /* only 1 machine */ + "i860", + "i860", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-i960.c b/contrib/gdb/bfd/cpu-i960.c new file mode 100644 index 000000000000..6970f89fca5c --- /dev/null +++ b/contrib/gdb/bfd/cpu-i960.c @@ -0,0 +1,162 @@ +/* BFD library support routines for the i960 architecture. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* This routine is provided a string, and tries to work out if it + could possibly refer to the i960 machine pointed at in the + info_struct pointer */ + +static boolean +scan_960_mach (ap, string) + const bfd_arch_info_type *ap; + const char *string; +{ + unsigned long machine; + + /* Look for the string i960, or somesuch at the front of the string */ + + if (strncmp("i960",string,4) == 0) { + string+=4; + } + else { + /* no match, can be us */ + return false; + } + if (string[0] == 0) { + /* i960 on it's own means core to us*/ + if (ap->mach == bfd_mach_i960_core) return true; + return false; + } + + if (string[0] != ':') { + return false; + } + string++; + if (string[0] == '\0') + return false; + if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && + string[3] == 'e' && string[4] == '\0') + machine = bfd_mach_i960_core; + else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char */ + return false; + else if (string[0] == 'k' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 's' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 'm' && string[1] == 'c') + machine = bfd_mach_i960_mc; + else if (string[0] == 'x' && string[1] == 'a') + machine = bfd_mach_i960_xa; + else if (string[0] == 'c' && string[1] == 'a') + machine = bfd_mach_i960_ca; + else if (string[0] == 'k' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else if (string[0] == 's' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else if (string[0] == 'j' && string[1] == 'x') + machine = bfd_mach_i960_jx; + else if (string[0] == 'h' && string[1] == 'x') + machine = bfd_mach_i960_hx; + else + return false; + if (machine == ap->mach) return true; + return false; +} + + + +/* This routine is provided two arch_infos and works out the i960 + machine which would be compatible with both and returns a pointer + to its info structure */ + +static const bfd_arch_info_type * +compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + + /* The i960 has distinct subspecies which may not interbreed: + CORE CA + CORE KA KB MC XA + CORE HX JX + Any architecture on the same line is compatible, the one on + the right is the least restrictive. + + We represent this information in an array, each machine to a side */ + +#define ERROR 0 +#define CORE bfd_mach_i960_core /*1*/ +#define KA bfd_mach_i960_ka_sa /*2*/ +#define KB bfd_mach_i960_kb_sb /*3*/ +#define MC bfd_mach_i960_mc /*4*/ +#define XA bfd_mach_i960_xa /*5*/ +#define CA bfd_mach_i960_ca /*6*/ +#define JX bfd_mach_i960_jx /*7*/ +#define HX bfd_mach_i960_hx /*8*/ +#define MAX_ARCH ((int)HX) + + static CONST unsigned long matrix[MAX_ARCH+1][MAX_ARCH+1] = + { + { ERROR, CORE, KA, KB, MC, XA, CA, JX, HX }, + { CORE, CORE, KA, KB, MC, XA, CA, JX, HX }, + { KA, KA, KA, KB, MC, XA, ERROR, ERROR, ERROR}, + { KB, KB, KB, KB, MC, XA, ERROR, ERROR, ERROR}, + { MC, MC, MC, MC, MC, XA, ERROR, ERROR, ERROR}, + { XA, XA, XA, XA, XA, XA, ERROR, ERROR, ERROR}, + { CA, CA, ERROR, ERROR, ERROR, ERROR, CA, ERROR, ERROR}, + { JX, JX, ERROR, ERROR, ERROR, ERROR, ERROR, JX, HX }, + { HX, HX, ERROR, ERROR, ERROR, ERROR, ERROR, HX, HX }, + }; + + + if (a->arch != b->arch || matrix[a->mach][b->mach] == ERROR) + { + return NULL; + } + else + { + return (a->mach == matrix[a->mach][b->mach]) ? a : b; + } +} + + + +int bfd_default_scan_num_mach(); +#define N(a,b,d,n) \ +{ 32, 32, 8,bfd_arch_i960,a,"i960",b,3,d,compatible,scan_960_mach,n,} + +static const bfd_arch_info_type arch_info_struct[] = +{ + N(bfd_mach_i960_ka_sa,"i960:ka_sa",false, &arch_info_struct[1]), + N(bfd_mach_i960_kb_sb,"i960:kb_sb",false, &arch_info_struct[2]), + N(bfd_mach_i960_mc, "i960:mc", false, &arch_info_struct[3]), + N(bfd_mach_i960_xa, "i960:xa", false, &arch_info_struct[4]), + N(bfd_mach_i960_ca, "i960:ca", false, &arch_info_struct[5]), + N(bfd_mach_i960_jx, "i960:jx", false, &arch_info_struct[6]), + N(bfd_mach_i960_hx, "i960:hx", false, 0), +}; + +const bfd_arch_info_type bfd_i960_arch = + N(bfd_mach_i960_core, "i960:core", true, &arch_info_struct[0]); diff --git a/contrib/gdb/bfd/cpu-m68k.c b/contrib/gdb/bfd/cpu-m68k.c new file mode 100644 index 000000000000..17a373916756 --- /dev/null +++ b/contrib/gdb/bfd/cpu-m68k.c @@ -0,0 +1,42 @@ +/* BFD library support routines for architectures. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +int bfd_default_scan_num_mach(); + + +#define N(name, print,d,next) \ +{ 32, 32, 8, bfd_arch_m68k, name, "m68k",print,2,d,bfd_default_compatible,bfd_default_scan, next, } + +static const bfd_arch_info_type arch_info_struct[] = +{ + N(68008,"m68k:68008",false, &arch_info_struct[1]), + N(68010,"m68k:68010",false, &arch_info_struct[2]), + N(68020,"m68k:68020",true, &arch_info_struct[3]), + N(68030,"m68k:68030",false, &arch_info_struct[4]), + N(68040,"m68k:68040",false, &arch_info_struct[5]), + N(68070,"m68k:68070",false, 0), +}; + +const bfd_arch_info_type bfd_m68k_arch = + N(68000,"m68k:68000",false, &arch_info_struct[0]); diff --git a/contrib/gdb/bfd/cpu-m88k.c b/contrib/gdb/bfd/cpu-m88k.c new file mode 100644 index 000000000000..c3716c5a394c --- /dev/null +++ b/contrib/gdb/bfd/cpu-m88k.c @@ -0,0 +1,42 @@ +/* bfd back-end for m88k support + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + + + +const bfd_arch_info_type bfd_m88k_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_m88k, + 88100, /* only 1 machine */ + "m88k", + "m88k:88100", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-mips.c b/contrib/gdb/bfd/cpu-mips.c new file mode 100644 index 000000000000..5e1934210a29 --- /dev/null +++ b/contrib/gdb/bfd/cpu-mips.c @@ -0,0 +1,85 @@ +/* bfd back-end for mips support + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static const bfd_arch_info_type arch_info_struct[] = +{ + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_mips, + 6000, + "mips", + "mips:6000", + 3, + false, + bfd_default_compatible, + bfd_default_scan, + &arch_info_struct[1], + }, + { + 64, /* 64 bits in a word */ + 64, /* 64 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_mips, + 4000, + "mips", + "mips:4000", + 3, + false, + bfd_default_compatible, + bfd_default_scan , + &arch_info_struct[2], + }, + { + 64, /* 64 bits in a word */ + 64, /* 64 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_mips, + 8000, + "mips", + "mips:8000", + 3, + false, + bfd_default_compatible, + bfd_default_scan , + 0, + } +}; + +const bfd_arch_info_type bfd_mips_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_mips, + 3000, + "mips", + "mips:3000", + 3, + true, + bfd_default_compatible, + bfd_default_scan, + &arch_info_struct[0], +}; diff --git a/contrib/gdb/bfd/cpu-ns32k.c b/contrib/gdb/bfd/cpu-ns32k.c new file mode 100644 index 000000000000..e18e3cfc9ba1 --- /dev/null +++ b/contrib/gdb/bfd/cpu-ns32k.c @@ -0,0 +1,868 @@ +/* BFD support for the ns32k architecture. + Copyright (C) 1990, 1991, 1994, 1995 Free Software Foundation, Inc. + Almost totally rewritten by Ian Dall from initial work + by Andrew Cagney. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +long ns32k_get_displacement PARAMS ((bfd_byte *buffer, long offset, long size)); +int ns32k_put_displacement PARAMS ((long value, bfd_byte *buffer, long offset, long size)); +long ns32k_get_immediate PARAMS ((bfd_byte *buffer, long offset, long size)); +int ns32k_put_immediate PARAMS ((long value, bfd_byte *buffer, long offset, long size)); +bfd_reloc_status_type + ns32k_reloc_disp PARAMS ((bfd *abfd, arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); +bfd_reloc_status_type + ns32k_reloc_imm PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); +bfd_reloc_status_type ns32k_final_link_relocate PARAMS ((reloc_howto_type *howto, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + bfd_vma address, + bfd_vma value, + bfd_vma addend )); +bfd_reloc_status_type ns32k_relocate_contents PARAMS ((reloc_howto_type *howto, + bfd *input_bfd, + bfd_vma relocation, + bfd_byte *location)); + +int bfd_default_scan_num_mach(); + +#define N(machine, printable, d, next) \ +{ 32, 32, 8, bfd_arch_ns32k, machine, "ns32k",printable,3,d,bfd_default_compatible,bfd_default_scan, next, } + +static const bfd_arch_info_type arch_info_struct[] = +{ + N(32532,"ns32k:32532",true, 0), /* the word ns32k will match this too */ +}; + +const bfd_arch_info_type bfd_ns32k_arch = + N(32032,"ns32k:32032",false, &arch_info_struct[0]); + +static long +ns32k_sign_extend(value, bits) + int value; + int bits; +{ + value = value & ((1 << bits) - 1); + return (value & (1 << (bits-1)) + ? value | (~((1 << bits) - 1)) + : value); +} + +long +ns32k_get_displacement(buffer, offset, size) + bfd_byte *buffer; + long offset; + long size; +{ + long value; + buffer += offset; + switch (size) + { + case 1: + value = ns32k_sign_extend (*buffer, 7); + break; + case 2: + value = ns32k_sign_extend(*buffer++, 6); + value = (value << 8) | (0xff & *buffer); + break; + case 4: + value = ns32k_sign_extend(*buffer++, 6); + value = (value << 8) | (0xff & *buffer++); + value = (value << 8) | (0xff & *buffer++); + value = (value << 8) | (0xff & *buffer); + break; + } + return value; +} + +int +ns32k_put_displacement(value, buffer, offset, size) + long value; + bfd_byte *buffer; + long offset; + long size; +{ + buffer += offset; + switch (size) + { + case 1: + if (value < -64 || value > 63) + return -1; + value&=0x7f; + *buffer++=value; + break; + case 2: + if (value < -8192 || value > 8191) + return -1; + value&=0x3fff; + value|=0x8000; + *buffer++=(value>>8); + *buffer++=value; + break; + case 4: + if (value < -0x1f000000 || value >= 0x20000000) + return -1; + value|=0xc0000000; + *buffer++=(value>>24); + *buffer++=(value>>16); + *buffer++=(value>>8); + *buffer++=value; + break; + default: + return -1; + } + return 0; +} + +long +ns32k_get_immediate(buffer, offset, size) + bfd_byte *buffer; + long offset; + long size; +{ + long value = 0; + buffer += offset; + switch (size) + { + case 4: + value = (value << 8) | (*buffer++ & 0xff); + case 3: + value = (value << 8) | (*buffer++ & 0xff); + case 2: + value = (value << 8) | (*buffer++ & 0xff); + case 1: + value = (value << 8) | (*buffer++ & 0xff); + } + return value; +} + +int +ns32k_put_immediate (value, buffer, offset, size) + long value; + bfd_byte *buffer; + long offset; + long size; +{ + buffer += offset + size - 1; + switch (size) + { + case 4: + *buffer-- = (value & 0xff); value >>= 8; + case 3: + *buffer-- = (value & 0xff); value >>= 8; + case 2: + *buffer-- = (value & 0xff); value >>= 8; + case 1: + *buffer-- = (value & 0xff); value >>= 8; + } + return 0; +} + +/* This is just like the standard perform_relocation except we + * use get_data and put_data which know about the ns32k + * storage methods. + * This is probably a lot more complicated than it needs to be! + */ +static bfd_reloc_status_type +do_ns32k_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message, get_data, put_data) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; + long (*get_data)(); + int (*put_data)(); +{ + int overflow = 0; + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type addr = reloc_entry->address; + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + + if ((symbol->section == &bfd_abs_section) + && output_bfd != (bfd *) NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocateable output, return an error if + the symbol is not defined. An undefined weak symbol is + considered to have a value of zero (SVR4 ABI, p. 4-27). */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0 + && output_bfd == (bfd *) NULL) + flag = bfd_reloc_undefined; + + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (output_bfd && howto->partial_inplace == false) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative == true) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is false. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is true. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is false we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is true + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset == true) + relocation -= reloc_entry->address; + } + + if (output_bfd != (bfd *) NULL) + { + if (howto->partial_inplace == false) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour + && strcmp (abfd->xvec->name, "aixcoff-rs6000") != 0) + { +#if 1 + /* For m68k-coff, the addend was being subtracted twice during + relocation with -r. Removing the line below this comment + fixes that problem; see PR 2953. + +However, Ian wrote the following, regarding removing the line below, +which explains why it is still enabled: --djm + +If you put a patch like that into BFD you need to check all the COFF +linkers. I am fairly certain that patch will break coff-i386 (e.g., +SCO); see coff_i386_reloc in coff-i386.c where I worked around the +problem in a different way. There may very well be a reason that the +code works as it does. + +Hmmm. The first obvious point is that bfd_perform_relocation should +not have any tests that depend upon the flavour. It's seem like +entirely the wrong place for such a thing. The second obvious point +is that the current code ignores the reloc addend when producing +relocateable output for COFF. That's peculiar. In fact, I really +have no idea what the point of the line you want to remove is. + +A typical COFF reloc subtracts the old value of the symbol and adds in +the new value to the location in the object file (if it's a pc +relative reloc it adds the difference between the symbol value and the +location). When relocating we need to preserve that property. + +BFD handles this by setting the addend to the negative of the old +value of the symbol. Unfortunately it handles common symbols in a +non-standard way (it doesn't subtract the old value) but that's a +different story (we can't change it without losing backward +compatibility with old object files) (coff-i386 does subtract the old +value, to be compatible with existing coff-i386 targets, like SCO). + +So everything works fine when not producing relocateable output. When +we are producing relocateable output, logically we should do exactly +what we do when not producing relocateable output. Therefore, your +patch is correct. In fact, it should probably always just set +reloc_entry->addend to 0 for all cases, since it is, in fact, going to +add the value into the object file. This won't hurt the COFF code, +which doesn't use the addend; I'm not sure what it will do to other +formats (the thing to check for would be whether any formats both use +the addend and set partial_inplace). + +When I wanted to make coff-i386 produce relocateable output, I ran +into the problem that you are running into: I wanted to remove that +line. Rather than risk it, I made the coff-i386 relocs use a special +function; it's coff_i386_reloc in coff-i386.c. The function +specifically adds the addend field into the object file, knowing that +bfd_perform_relocation is not going to. If you remove that line, then +coff-i386.c will wind up adding the addend field in twice. It's +trivial to fix; it just needs to be done. + +The problem with removing the line is just that it may break some +working code. With BFD it's hard to be sure of anything. The right +way to deal with this is simply to build and test at least all the +supported COFF targets. It should be straightforward if time and disk +space consuming. For each target: + 1) build the linker + 2) generate some executable, and link it using -r (I would + probably use paranoia.o and link against newlib/libc.a, which + for all the supported targets would be available in + /usr/cygnus/progressive/H-host/target/lib/libc.a). + 3) make the change to reloc.c + 4) rebuild the linker + 5) repeat step 2 + 6) if the resulting object files are the same, you have at least + made it no worse + 7) if they are different you have to figure out which version is + right +*/ + relocation -= reloc_entry->addend; +#endif + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + } + else + { + reloc_entry->addend = 0; + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + + /* Get the value that will be used for the relocation, but + starting at bit position zero. */ + if (howto->rightshift > howto->bitpos) + check = relocation >> (howto->rightshift - howto->bitpos); + else + check = relocation << (howto->bitpos - howto->rightshift); + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~reloc_signed_max; + + /* The above right shift is incorrect for a signed value. + Fix it up by forcing on the upper bits. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> (howto->rightshift - howto->bitpos))); + if ((bfd_signed_vma) check > reloc_signed_max + || (bfd_signed_vma) check < reloc_signed_min) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((bfd_vma) check > reloc_unsigned_max) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (((bfd_vma) check & ~reloc_bits) != 0 + && ((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + { + /* The above right shift is incorrect for a signed + value. See if turning on the upper bits fixes the + overflow. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + { + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> (howto->rightshift - howto->bitpos))); + if (((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + flag = bfd_reloc_overflow; + } + else + flag = bfd_reloc_overflow; + } + } + break; + default: + abort (); + } + } + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + + /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler + (OSF version 1.3, compiler version 3.11). It miscompiles the + following program: + + struct str + { + unsigned int i0; + } s = { 0 }; + + int + main () + { + unsigned long x; + + x = 0x100000000; + x <<= (unsigned long) s.i0; + if (x == 0) + printf ("failed\n"); + else + printf ("succeeded (%lx)\n", x); + } + */ + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= (bfd_vma) howto->bitpos; + + /* Wait for the day when all have the mask in them */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + i i i i i o o o o o from bfd_get + and S S S S S to get the size offset we want + + r r r r r r r r r r to get the final value to place + and D D D D D to chop to right size + ----------------------- + A A A A A + And this: + ... i i i i i o o o o o from bfd_get + and N N N N N get instruction + ----------------------- + ... B B B B B + + And then: + B B B B B + or A A A A A + ----------------------- + R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) + { + case 0: + { + char x = get_data (data, addr, 1); + DOIT (x); + overflow = put_data(x, data, addr, 1); + } + break; + + case 1: + if (relocation) + { + short x = get_data (data, addr, 2); + DOIT (x); + overflow = put_data(x, (unsigned char *) data, addr, 2); + } + break; + case 2: + if (relocation) + { + long x = get_data (data, addr, 4); + DOIT (x); + overflow = put_data(x, data, addr, 4); + } + break; + case -2: + { + long x = get_data(data, addr, 4); + relocation = -relocation; + DOIT(x); + overflow = put_data(x, data , addr, 4); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: +#ifdef BFD64 + if (relocation) + { + bfd_vma x = get_data (data, addr, 8); + DOIT (x); + overflow = put_data(x, data, addr, 8); + } +#else + abort (); +#endif + break; + default: + return bfd_reloc_other; + } + if ((howto->complain_on_overflow != complain_overflow_dont) && overflow) + return bfd_reloc_overflow; + + return flag; +} + +/* Relocate a given location using a given value and howto. */ + +bfd_reloc_status_type +do_ns32k_reloc_contents ( howto, input_bfd, relocation, location, get_data, + put_data) + reloc_howto_type *howto; + bfd *input_bfd; + bfd_vma relocation; + bfd_byte *location; + long (*get_data)(); + int (*put_data)(); +{ + int size; + bfd_vma x; + boolean overflow; + + /* If the size is negative, negate RELOCATION. This isn't very + general. */ + if (howto->size < 0) + relocation = -relocation; + + /* Get the value we are going to relocate. */ + size = bfd_get_reloc_size (howto); + switch (size) + { + default: + case 0: + abort (); + case 1: + case 2: + case 4: +#ifdef BFD64 + case 8: +#endif + x = get_data (location, 0, size); + break; + } + + /* Check for overflow. FIXME: We may drop bits during the addition + which we don't check for. We must either check at every single + operation, which would be tedious, or we must do the computations + in a type larger than bfd_vma, which would be inefficient. */ + overflow = false; + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + bfd_signed_vma signed_check; + bfd_vma add; + bfd_signed_vma signed_add; + + if (howto->rightshift == 0) + { + check = relocation; + signed_check = (bfd_signed_vma) relocation; + } + else + { + /* Drop unwanted bits from the value we are relocating to. */ + check = relocation >> howto->rightshift; + + /* If this is a signed value, the rightshift just dropped + leading 1 bits (assuming twos complement). */ + if ((bfd_signed_vma) relocation >= 0) + signed_check = check; + else + signed_check = (check + | ((bfd_vma) - 1 + & ~((bfd_vma) - 1 >> howto->rightshift))); + } + + /* Get the value from the object file. */ + add = x & howto->src_mask; + + /* Get the value from the object file with an appropriate sign. + The expression involving howto->src_mask isolates the upper + bit of src_mask. If that bit is set in the value we are + adding, it is negative, and we subtract out that number times + two. If src_mask includes the highest possible bit, then we + can not get the upper bit, but that does not matter since + signed_add needs no adjustment to become negative in that + case. */ + signed_add = add; + if ((add & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0) + signed_add -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1; + + /* Add the value from the object file, shifted so that it is a + straight number. */ + if (howto->bitpos == 0) + { + check += add; + signed_check += signed_add; + } + else + { + check += add >> howto->bitpos; + + /* For the signed case we use ADD, rather than SIGNED_ADD, + to avoid warnings from SVR4 cc. This is OK since we + explictly handle the sign bits. */ + if (signed_add >= 0) + signed_check += add >> howto->bitpos; + else + signed_check += ((add >> howto->bitpos) + | ((bfd_vma) - 1 + & ~((bfd_vma) - 1 >> howto->bitpos))); + } + + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~reloc_signed_max; + + if (signed_check > reloc_signed_max + || signed_check < reloc_signed_min) + overflow = true; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (check > reloc_unsigned_max) + overflow = true; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((check & ~reloc_bits) != 0 + && (((bfd_vma) signed_check & ~reloc_bits) + != (-1 & ~reloc_bits))) + overflow = true; + } + break; + default: + abort (); + } + } + + /* Put RELOCATION in the right bits. */ + relocation >>= (bfd_vma) howto->rightshift; + relocation <<= (bfd_vma) howto->bitpos; + + /* Add RELOCATION to the right bits of X. */ + x = ((x & ~howto->dst_mask) + | (((x & howto->src_mask) + relocation) & howto->dst_mask)); + + /* Put the relocated value back in the object file. */ + switch (size) + { + default: + case 0: + abort (); + case 1: + case 2: + case 4: +#ifdef BFD64 + case 8: +#endif + put_data(x, location, 0, size); + break; + } + + return overflow ? bfd_reloc_overflow : bfd_reloc_ok; +} + +bfd_reloc_status_type +ns32k_reloc_disp(abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + return do_ns32k_reloc(abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message, ns32k_get_displacement, ns32k_put_displacement); +} + +bfd_reloc_status_type +ns32k_reloc_imm (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + return do_ns32k_reloc(abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message, ns32k_get_immediate, ns32k_put_immediate); +} + +bfd_reloc_status_type +ns32k_final_link_relocate (howto, input_bfd, input_section, contents, address, value, addend ) + reloc_howto_type *howto; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + bfd_vma address; + bfd_vma value; + bfd_vma addend; +{ + bfd_vma relocation; + + /* Sanity check the address. */ + if (address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* This function assumes that we are dealing with a basic relocation + against a symbol. We want to compute the value of the symbol to + relocate to. This is just VALUE, the value of the symbol, plus + ADDEND, any addend associated with the reloc. */ + relocation = value + addend; + + /* If the relocation is PC relative, we want to set RELOCATION to + the distance between the symbol (currently in RELOCATION) and the + location we are relocating. Some targets (e.g., i386-aout) + arrange for the contents of the section to be the negative of the + offset of the location within the section; for such targets + pcrel_offset is false. Other targets (e.g., m88kbcs or ELF) + simply leave the contents of the section as zero; for such + targets pcrel_offset is true. If pcrel_offset is false we do not + need to subtract out the offset of the location within the + section (which is just ADDRESS). */ + if (howto->pc_relative) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset); + if (howto->pcrel_offset) + relocation -= address; + } + + return ns32k_relocate_contents (howto, input_bfd, relocation, + contents + address); +} diff --git a/contrib/gdb/bfd/cpu-powerpc.c b/contrib/gdb/bfd/cpu-powerpc.c new file mode 100644 index 000000000000..11f0f80af5ab --- /dev/null +++ b/contrib/gdb/bfd/cpu-powerpc.c @@ -0,0 +1,124 @@ +/* BFD PowerPC CPU definition + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* The common PowerPC architecture is compatible with the RS/6000. */ + +static const bfd_arch_info_type *powerpc_compatible + PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *)); + +static const bfd_arch_info_type * +powerpc_compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + BFD_ASSERT (a->arch == bfd_arch_powerpc); + switch (b->arch) + { + default: + return NULL; + case bfd_arch_powerpc: + return bfd_default_compatible (a, b); + case bfd_arch_rs6000: + if (a->mach == 0) + return a; + return NULL; + } + /*NOTREACHED*/ +} + +static const bfd_arch_info_type arch_info_struct[] = +{ + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_powerpc, + 603, /* for the mpc603 */ + "powerpc", + "powerpc:603", + 3, + false, /* not the default */ + powerpc_compatible, + bfd_default_scan, + &arch_info_struct[1] + }, + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_powerpc, + 604, /* for the mpc604 */ + "powerpc", + "powerpc:604", + 3, + false, /* not the default */ + powerpc_compatible, + bfd_default_scan, + &arch_info_struct[2] + }, + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_powerpc, + 403, /* for the 403 */ + "powerpc", + "powerpc:403", + 3, + false, /* not the default */ + powerpc_compatible, + bfd_default_scan, + &arch_info_struct[3] + }, + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_powerpc, + 601, /* for the mpc601 */ + "powerpc", + "powerpc:601", + 3, + false, /* not the default */ + powerpc_compatible, + bfd_default_scan, + 0 + } +}; + +const bfd_arch_info_type bfd_powerpc_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_powerpc, + 0, /* for the POWER/PowerPC common architecture */ + "powerpc", + "powerpc:common", + 3, + true, /* the default */ + powerpc_compatible, + bfd_default_scan, + &arch_info_struct[0] + }; diff --git a/contrib/gdb/bfd/cpu-rs6000.c b/contrib/gdb/bfd/cpu-rs6000.c new file mode 100644 index 000000000000..9852ae9a0536 --- /dev/null +++ b/contrib/gdb/bfd/cpu-rs6000.c @@ -0,0 +1,70 @@ +/* BFD back-end for rs6000 support + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM + and John Gilmore of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* The RS/6000 architecture is compatible with the PowerPC common + architecture. */ + +static const bfd_arch_info_type *rs6000_compatible + PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *)); + +static const bfd_arch_info_type * +rs6000_compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + BFD_ASSERT (a->arch == bfd_arch_rs6000); + switch (b->arch) + { + default: + return NULL; + case bfd_arch_rs6000: + return bfd_default_compatible (a, b); + case bfd_arch_powerpc: + if (b->mach == 0) + return b; + return NULL; + } + /*NOTREACHED*/ +} + +const bfd_arch_info_type bfd_rs6000_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_rs6000, + 6000, /* only 1 machine */ + "rs6000", + "rs6000:6000", + 3, + true, /* the one and only */ + rs6000_compatible, + bfd_default_scan, + 0, + }; diff --git a/contrib/gdb/bfd/cpu-sh.c b/contrib/gdb/bfd/cpu-sh.c new file mode 100644 index 000000000000..7f6dd68ba04a --- /dev/null +++ b/contrib/gdb/bfd/cpu-sh.c @@ -0,0 +1,68 @@ +/* BFD library support routines for the Hitachi-SH architecture. + Copyright (C) 1993 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +int bfd_default_scan_num_mach(); + +static boolean +scan_mach (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + if (strcmp(string,"sh") == 0) return true; + if (strcmp(string,"SH") == 0) return true; + return false; +} + + +#if 0 +/* This routine is provided two arch_infos and returns whether + they'd be compatible */ + +static const bfd_arch_info_type * +compatible (a,b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->arch != b->arch || a->mach != b->mach) + return NULL; + return a; +} +#endif + +const bfd_arch_info_type bfd_sh_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_sh, + 0, /* only 1 machine */ + "sh", /* arch_name */ + "sh", /* printable name */ + 1, + true, /* the default machine */ + bfd_default_compatible, + scan_mach, + 0, +}; diff --git a/contrib/gdb/bfd/cpu-sparc.c b/contrib/gdb/bfd/cpu-sparc.c new file mode 100644 index 000000000000..e48aa5e7f2b3 --- /dev/null +++ b/contrib/gdb/bfd/cpu-sparc.c @@ -0,0 +1,111 @@ +/* BFD support for the SPARC architecture. + Copyright (C) 1992, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* Don't mix 32 bit and 64 bit files. */ + +static const bfd_arch_info_type * +sparc_compatible (a, b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->bits_per_word != b->bits_per_word) + return NULL; + + return bfd_default_compatible (a, b); +} + +static const bfd_arch_info_type arch_info_struct[] = +{ + { + 32, /* bits in a word */ + 32, /* bits in an address */ + 8, /* bits in a byte */ + bfd_arch_sparc, + bfd_mach_sparc_v8plus, + "sparc", + "sparc:v8plus", + 3, + false, + sparc_compatible, + bfd_default_scan, + &arch_info_struct[1], + }, + { + 32, /* bits in a word */ + 32, /* bits in an address */ + 8, /* bits in a byte */ + bfd_arch_sparc, + bfd_mach_sparc_v8plusa, + "sparc", + "sparc:v8plusa", + 3, + false, + sparc_compatible, + bfd_default_scan, + &arch_info_struct[2], + }, + { + 64, /* bits in a word */ + 64, /* bits in an address */ + 8, /* bits in a byte */ + bfd_arch_sparc, + bfd_mach_sparc_v9, + "sparc", + "sparc:v9", + 3, + false, + sparc_compatible, + bfd_default_scan, + &arch_info_struct[3], + }, + { + 64, /* bits in a word */ + 64, /* bits in an address */ + 8, /* bits in a byte */ + bfd_arch_sparc, + bfd_mach_sparc_v9a, + "sparc", + "sparc:v9a", + 3, + false, + sparc_compatible, + bfd_default_scan, + 0, + } +}; + +const bfd_arch_info_type bfd_sparc_arch = + { + 32, /* bits in a word */ + 32, /* bits in an address */ + 8, /* bits in a byte */ + bfd_arch_sparc, + bfd_mach_sparc, + "sparc", + "sparc", + 3, + true, /* the default */ + sparc_compatible, + bfd_default_scan, + &arch_info_struct[0], + }; diff --git a/contrib/gdb/bfd/cpu-vax.c b/contrib/gdb/bfd/cpu-vax.c new file mode 100644 index 000000000000..bdc6d39e451f --- /dev/null +++ b/contrib/gdb/bfd/cpu-vax.c @@ -0,0 +1,39 @@ +/* bfd back-end for vax support + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_vax_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_vax, + 0, /* only 1 machine */ + "vax", + "vax", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-w65.c b/contrib/gdb/bfd/cpu-w65.c new file mode 100644 index 000000000000..c0bbf045219c --- /dev/null +++ b/contrib/gdb/bfd/cpu-w65.c @@ -0,0 +1,54 @@ +/* BFD library support routines for the WDC 65816 architecture. + Copyright (C) 1995 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 publiw65ed by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You w65ould 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 "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +int bfd_default_scan_num_mach(); + +static boolean +scan_mach (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + if (strcmp(string,"w65") == 0) return true; + if (strcmp(string,"w65816") == 0) return true; + return false; +} + + + +const bfd_arch_info_type bfd_w65_arch = +{ + 16, /* 16 bits in a word */ + 24, /* 24 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_w65, + 0, /* only 1 machine */ + "w65", /* arch_name */ + "w65", /* printable name */ + 1, + true, /* the default machine */ + bfd_default_compatible, + scan_mach, + 0, +}; diff --git a/contrib/gdb/bfd/cpu-we32k.c b/contrib/gdb/bfd/cpu-we32k.c new file mode 100644 index 000000000000..a38cbc1268b4 --- /dev/null +++ b/contrib/gdb/bfd/cpu-we32k.c @@ -0,0 +1,39 @@ +/* bfd back-end for we32k support + Copyright (C) 1992 Free Software Foundation, Inc. + Contributed by Brendan Kehoe (brendan@cs.widener.edu). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_we32k_arch = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_we32k, + 32000, /* only 1 machine */ + "we32k", + "we32k:32000", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git a/contrib/gdb/bfd/cpu-z8k.c b/contrib/gdb/bfd/cpu-z8k.c new file mode 100644 index 000000000000..5cce8eb0689b --- /dev/null +++ b/contrib/gdb/bfd/cpu-z8k.c @@ -0,0 +1,198 @@ +/* BFD library support routines for the Z800n architecture. + Copyright (C) 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +#if 0 /* not used currently */ +/* +Relocations for the Z8K + +*/ +static bfd_reloc_status_type +howto16_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_16 (abfd, (bfd_byte *) data + addr); + + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_16 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +howto8_FFnn_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + abort (); + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +howto8_pcrel_callback (abfd, reloc_entry, symbol_in, data, + ignore_input_section, ignore_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol_in; + PTR data; + asection *ignore_input_section; + bfd *ignore_bfd; +{ + long relocation = 0; + bfd_vma addr = reloc_entry->address; + long x = bfd_get_8 (abfd, (bfd_byte *) data + addr); + abort (); + HOWTO_PREPARE (relocation, symbol_in); + + x = (x + relocation + reloc_entry->addend); + + bfd_put_8 (abfd, x, (bfd_byte *) data + addr); + return bfd_reloc_ok; +} + + + +static reloc_howto_type howto_16 += NEWHOWTO (howto16_callback, "abs16", 1, false, false); +static reloc_howto_type howto_8 += NEWHOWTO (howto8_callback, "abs8", 0, false, false); + +static reloc_howto_type howto_8_FFnn += NEWHOWTO (howto8_FFnn_callback, "ff00+abs8", 0, false, false); + +static reloc_howto_type howto_8_pcrel += NEWHOWTO (howto8_pcrel_callback, "pcrel8", 0, false, true); + + +static reloc_howto_type * +local_bfd_reloc_type_lookup (arch, code) + const struct bfd_arch_info *arch; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_16: + return &howto_16; + case BFD_RELOC_8_FFnn: + return &howto_8_FFnn; + case BFD_RELOC_8: + return &howto_8; + case BFD_RELOC_8_PCREL: + return &howto_8_pcrel; + default: + return (reloc_howto_type *) NULL; + } +} +#endif + +int bfd_default_scan_num_mach (); + +static boolean +scan_mach (info, string) + const struct bfd_arch_info *info; + const char *string; +{ + if (strcmp (string, "z8001") == 0 || strcmp (string, "z8k") == 0) + { + return bfd_mach_z8001 == info->mach; + } + if (strcmp (string, "z8002") == 0) + { + return bfd_mach_z8002 == info->mach; + } + return false; +} + + +/* This routine is provided two arch_infos and returns whether + they'd be compatible */ + +static const bfd_arch_info_type * +compatible (a, b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->arch != b->arch || a->mach != b->mach) + return NULL; + return a; +} + + +static const bfd_arch_info_type arch_info_struct[] = +{ + {32, 32, 8, bfd_arch_z8k, bfd_mach_z8001, "z8k", "z8001", 1, false, compatible, scan_mach, 0,}, +}; + +const bfd_arch_info_type bfd_z8k_arch = +{ + 32, 16, 8, bfd_arch_z8k, bfd_mach_z8002, "z8k", "z8002", 1, true, compatible, scan_mach, &arch_info_struct[0], +}; diff --git a/contrib/gdb/bfd/demo64.c b/contrib/gdb/bfd/demo64.c new file mode 100644 index 000000000000..c91381d46e93 --- /dev/null +++ b/contrib/gdb/bfd/demo64.c @@ -0,0 +1,24 @@ +/* BFD backend for demonstration 64-bit a.out binaries. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 64 +#define MY(OP) CAT(demo_64_,OP) +#define TARGETNAME "demo64" +#include "aoutf1.h" diff --git a/contrib/gdb/bfd/dep-in.sed b/contrib/gdb/bfd/dep-in.sed new file mode 100644 index 000000000000..1cbd786fb2ee --- /dev/null +++ b/contrib/gdb/bfd/dep-in.sed @@ -0,0 +1,24 @@ +:loop +/\\$/N +/\\$/b loop + +s! @BFD_H@!!g +s!@INCDIR@!$(INCDIR)!g +s!@SRCDIR@/!!g +s!hosts/[^ ]*\.h ! !g +s/ sysdep.h//g +s/ libbfd.h//g +s/ config.h//g +s! \$(INCDIR)/fopen-[^ ]*\.h!!g +s! \$(INCDIR)/ansidecl\.h!!g +s! \$(INCDIR)/obstack\.h!!g + +s/\\\n */ /g + +s/ *$// +s/ */ /g +s/ *:/:/g +/:$/d + +s/\(.\{50\}[^ ]*\) /\1 \\\ + /g diff --git a/contrib/gdb/bfd/doc/ChangeLog b/contrib/gdb/bfd/doc/ChangeLog new file mode 100644 index 000000000000..f076e3777b56 --- /dev/null +++ b/contrib/gdb/bfd/doc/ChangeLog @@ -0,0 +1,268 @@ +Tue Jan 30 14:10:46 1996 Ian Lance Taylor + + From Ronald F. Guilmette : + * Makefile.in (libbfd.h): Depend upon proto.str. + (libcoff.h, bfd.h): Likewise. + +Fri Nov 3 14:46:48 1995 Fred Fish + + * Makefile.in (SRCDOC, SRCPROT, core.texi, bfd.h): Use corefile.c, + renamed from core.c. + +Wed Nov 1 14:28:23 1995 Manfred Hollstein KS/EF4A 60/1F/110 #40283 + + * chew.c: Include . + +Fri Oct 6 16:23:34 1995 Ken Raeburn + + Mon Sep 25 22:49:32 1995 Andreas Schwab + + * Makefile.in (Makefile): Only remake this Makefile. + +Wed Oct 4 15:51:05 1995 Ken Raeburn + + * chew.c: Include . + +Tue Sep 12 18:14:50 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New target. + +Thu Aug 31 12:18:43 1995 Ian Lance Taylor + + * Makefile.in (bfd.h): Add additional #endif at end of bfd.h if + __cplusplus is defined. + +Tue Nov 29 16:13:34 1994 Doug Evans + + * chew.c (write_buffer): New argument `f', all callers changed. + (stdout, stderr, print, drop, idrop): New forth words. + * proto.str (COMMENT): New command. + * doc.str (COMMENT): Likewise. + +Mon Sep 12 11:44:17 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * Makefile.in (DOCFILES): Remove ctor.texi. + (IPROTOS): Remove ctor.ip. + (SRCIPROT): Remove $(srcdir)/../ctor.c. + (ctor.texi): Remove target. + (libbfd.h): Remove dependency on $(srcdir)/../ctor.c. Remove + $(MKDOC) run on $(srcdir)/../ctor.c. + * bfd.texinfo (Constructors): Remove section. + +Fri Sep 2 13:33:44 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * chew.c: Include assert.h. Added prototypes for most functions. + Changed most uses of int to long. Do bounds checking on the + stacks. Added comment at the beginning documenting most of the + intrinsics. Lots of whitespace changes. Re-ordered some + functions. + (die, check_range, icheck_range): New functions. + (strip_trailing_newlines, print_stack_level): New functions. + (translatecomments): Don't insert tab before "/*". + (iscommand): Minimum command length is now 4. + (nextword): Handle some \-sequences. + (push_addr): Deleted. + (main): Add new intrinsics strip_trailing_newlines and + print_stack_level. Complain at end if stack contains more than + one element, or less. + (remchar): Make sure the string is not empty before chopping off a + character. + + * doc.str, proto.str: Handle new commands SENUM, ENUM, ENUMX, + ENUMEQ, ENUMEQX, ENUMDOC. + +Wed Jan 12 18:37:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.texinfo: Added Linker Functions node. + * doc/Makefile.in (DOCFILES): Added linker.texi. + (SRCDOC): Added linker.c. + (linker.texi): New target. + +Tue Jan 4 10:52:56 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * chew.c: Don't rely on a correct declaration of exit. + (chew_exit): New function which just calls exit. + (main): Use it. + +Mon Jan 3 11:40:40 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.texinfo: Added Hash Tables node. + * Makefile.in (DOCFILES): Added hash.texi. + (SRCDOC): Added hash.c. + (hash.texi): New target. + +Thu Dec 30 16:57:04 1993 Ken Raeburn (raeburn@cujo.cygnus.com) + + * Makefile.in: Delete all references to seclet.c, since it's just + been deleted. Don't mention hash.c, linker.c, or genlink.h yet, + since they don't contain documentation yet (hint, hint!). + +Fri Nov 5 10:58:53 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * bfd.texinfo: Small cleanups. + +Fri Nov 19 03:46:11 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (archures.texi): Depends on $(MKDOC). + +Tue Aug 10 14:22:39 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * bfd.texinfo (BFD back end): Don't include elfcode.texi, since + it's empty now and that triggers a makeinfo bug. + +Mon Aug 9 16:27:30 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * bfd.texinfo (BFD back end): New section on ELF, includes + elf.texi and elfcode.texi. + * Makefile.in (DOCFILES): Include elf.texi, elfcode.texi. + (SRCDOC): Include elfcode.h, elf.c. + (elf.texi, elfcode.texi): New intermediate targets. + +Thu Jun 24 13:48:13 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * Makefile.in (.c.o, chew.o): Put CFLAGS last. + * bfdsumm.texi: New file, broken out of bfd.texinfo, to share + with ld.texinfo. + +Mon Jun 14 12:07:07 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) + + * Makefile.in (install-info): remove parentdir cruft, + +Wed Jun 9 16:00:32 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (mostlyclean): Remove chew.o. + +Tue May 25 14:46:58 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (libbfd.h): Use elfcode.h, not elf32.c. + +Mon May 24 15:50:07 1993 Ken Raeburn (raeburn@cygnus.com) + + * chew.c (compile): Add a couple of missing casts. + +Wed May 12 14:45:14 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in (CC_FOR_BUILD): New variable, define to be $(CC). + (chew.o, $(MKDOC)): Build using CC_FOR_BUILD rather than CC, since + it must run on the build machine. + +Tue Apr 6 22:38:10 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (chew): Don't compile from .c to executable in a + single step; it puts a temporary .o filename into the executable, + which makes multi-stage comparisons fail. Compile chew.c to + chew.o, and link that, which makes identical executables every time. + +Wed Mar 24 17:26:29 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: fix typo (bfd.texinfo not bfd.texino) + +Fri Mar 19 01:13:00 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * bfd.texinfo: Since BFD version number has been bumped, do same + to "version number" on title page, and elsewhere. Should be + fixed to extract real version number. + +Tue Mar 16 12:15:13 1993 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in: Add *clean rules. + +Mon Jan 11 18:43:56 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (libbfd.h): Removed duplicate init.c and libbfd.c. + Added seclet.c. + (bfd.h): Added dependency on bfd.c and seclet.c. Added seclet.c + to build. + +Thu Dec 17 19:35:43 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: added dvi target, define and use $(TEXI2DVI) + +Thu Dec 3 17:42:48 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (TEXIDIR): New variable. + (bfd.dvi): Look for bfd.texinfo in $(srcdir). Generate index. + + * bfd.texinfo: Minor doc fixes. + +Thu Nov 5 03:13:55 1992 John Gilmore (gnu@cygnus.com) + + Cleanup: Replace all uses of EXFUN in the BFD sources, with PARAMS. + + * doc/chew.c (exfunstuff): Eliminate. + (paramstuff): Replace exfunstuff with function to generate PARAMS. + * doc/proto.str: Use paramstuff rather than exfunstuff. + +Mon Aug 17 12:40:32 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * chew.c: various patches provided by Howard Chu. + +Fri Jun 19 18:59:54 1992 John Gilmore (gnu at cygnus.com) + + * Makefile.in (libbfd.h): Add elf.c as a source of prototypes. + +Mon May 11 18:55:59 1992 John Gilmore (gnu at cygnus.com) + + * chew.c: exit() should be declared by config files, not by + portable source code. Its type could be int or void function. + +Mon May 4 13:45:57 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * Makefile.in: another CFLAGS correction. + +Tue Apr 28 10:21:32 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * Makefile.in: Do the CFLAGS thing. + +Fri Apr 10 22:34:52 1992 Fred Fish (fnf@cygnus.com) + + * Makefile.in (MINUS_G): Add macro and default to -g. + +Fri Mar 6 18:53:18 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * chew.c: now has -w switch turn on warnings + +Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in: removed traces of namesubdir, + -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced + copyrights to '92, changed some from Cygnus to FSF. + +Tue Dec 10 22:11:05 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: build chew into the current directory. Complete + the MKDOC macro transition. + +Tue Dec 10 08:26:28 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * chew.c: don't core dump when can't open file + * Makefile.in: get proto.str from the right place when built in + odd directories + +Tue Dec 10 04:07:25 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: infodir belongs in datadir. + +Sat Dec 7 17:01:23 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * chew.c: Much modified + * proto.str, doc.str: New files for extracting to product + prototypes and documents respectively. + + +Fri Dec 6 22:57:12 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: added standards.text support, host/site/target + inclusion hooks, install using INSTALL_DATA rather than cp, + don't echo on install. + +Thu Dec 5 22:46:17 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: idestdir and ddestdir go away. Added copyrights + and shift gpl to v2. Added ChangeLog if it didn't exist. docdir + and mandir now keyed off datadir by default. + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/bfd/doc/Makefile.in b/contrib/gdb/bfd/doc/Makefile.in new file mode 100644 index 000000000000..aa3a76c26ae5 --- /dev/null +++ b/contrib/gdb/bfd/doc/Makefile.in @@ -0,0 +1,311 @@ +# +# Makefile +# Copyright (C) 1990, 1991, 1992, 1993 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 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +# + +VPATH = @srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ + +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +MKDOC=./chew +SHELL = /bin/sh + +INSTALL = `cd $(srcdir)/../..;pwd`/install.sh -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +CFLAGS = -g + +CC_FOR_BUILD = $(CC) + +#### Host, target, and site specific Makefile fragments come in here. +### + +.c.o: + $(CC) -c -I.. -I$(srcdir)/.. -I$(srcdir)/../../include $(H_CFLAGS) $(CFLAGS) $< + +DOCFILES = aoutx.texi archive.texi archures.texi \ + bfd.texi cache.texi coffcode.texi \ + core.texi elf.texi elfcode.texi format.texi libbfd.texi \ + opncls.texi reloc.texi section.texi \ + syms.texi targets.texi init.texi hash.texi linker.texi + +PROTOS = archive.p archures.p bfd.p \ + core.p format.p \ + libbfd.p opncls.p reloc.p \ + section.p syms.p targets.p \ + format.p core.p init.p + +IPROTOS = cache.ip libbfd.ip reloc.ip init.ip archures.ip coffcode.ip + +# SRCDOC, SRCPROT, SRCIPROT only used to sidestep Sun Make bug in interaction +# between VPATH and suffix rules. If you use GNU Make, perhaps other Makes, +# you don't need these three: +SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \ + $(srcdir)/../archures.c $(srcdir)/../bfd.c \ + $(srcdir)/../cache.c $(srcdir)/../coffcode.h \ + $(srcdir)/../corefile.c $(srcdir)/../elf.c \ + $(srcdir)/../elfcode.h $(srcdir)/../format.c \ + $(srcdir)/../libbfd.c $(srcdir)/../opncls.c \ + $(srcdir)/../reloc.c $(srcdir)/../section.c \ + $(srcdir)/../syms.c $(srcdir)/../targets.c \ + $(srcdir)/../hash.c $(srcdir)/../linker.c + +SRCPROT = $(srcdir)/../archive.c $(srcdir)/../archures.c \ + $(srcdir)/../bfd.c $(srcdir)/../coffcode.h $(srcdir)/../corefile.c \ + $(srcdir)/../format.c $(srcdir)/../libbfd.c \ + $(srcdir)/../opncls.c $(srcdir)/../reloc.c \ + $(srcdir)/../section.c $(srcdir)/../syms.c \ + $(srcdir)/../targets.c $(srcdir)/../init.c + +SRCIPROT = $(srcdir)/../cache.c $(srcdir)/../libbfd.c \ + $(srcdir)/../reloc.c $(srcdir)/../cpu-h8300.c \ + $(srcdir)/../cpu-i960.c $(srcdir)/../archures.c \ + $(srcdir)/../init.c + +STAGESTUFF = $(DOCFILES) *.info* + +TEXIDIR = $(srcdir)/../../texinfo/fsf + +all install: + +info: bfd.info + +dvi: bfd.dvi + +install-info: info + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +docs: $(MKDOC) protos bfd.info bfd.dvi bfd.ps + +$(MKDOC): chew.o + $(CC_FOR_BUILD) -o $(MKDOC) chew.o $(LOADLIBES) $(LDFLAGS) + +chew.o: chew.c + $(CC_FOR_BUILD) -c -I.. -I$(srcdir)/.. -I$(srcdir)/../../include $(H_CFLAGS) $(CFLAGS) $(srcdir)/chew.c + +protos: libbfd.h libcoff.h bfd.h + + +# We can't replace these rules with an implicit rule, because +# makes without VPATH support couldn't find the .h files in `..'. + +aoutx.texi: $(MKDOC) $(srcdir)/../aoutx.h $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../aoutx.h >aoutx.texi + +archive.texi: $(MKDOC) $(srcdir)/../archive.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../archive.c >archive.texi + +archures.texi: $(MKDOC) $(srcdir)/../archures.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str < $(srcdir)/../archures.c >archures.texi + +bfd.texi: $(MKDOC) $(srcdir)/../bfd.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str < $(srcdir)/../bfd.c >bfd.texi + +cache.texi: $(MKDOC) $(srcdir)/../cache.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str < $(srcdir)/../cache.c >cache.texi + +coffcode.texi: $(MKDOC) $(srcdir)/../coffcode.h $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../coffcode.h >coffcode.texi + +core.texi: $(MKDOC) $(srcdir)/../corefile.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../corefile.c >core.texi + +elf.texi: $(MKDOC) $(srcdir)/../elf.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../elf.c >elf.texi + +elfcode.texi: $(MKDOC) $(srcdir)/../elfcode.h $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../elfcode.h >elfcode.texi + +format.texi: $(MKDOC) $(srcdir)/../format.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../format.c >format.texi + +libbfd.texi: $(MKDOC) $(srcdir)/../libbfd.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str < $(srcdir)/../libbfd.c >libbfd.texi + +opncls.texi: $(MKDOC) $(srcdir)/../opncls.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../opncls.c >opncls.texi + +reloc.texi : $(MKDOC) $(srcdir)/../reloc.c + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../reloc.c >reloc.texi + +section.texi: $(MKDOC) $(srcdir)/../section.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../section.c >section.texi + +syms.texi : $(MKDOC) $(srcdir)/../syms.c + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../syms.c >syms.texi + +targets.texi: $(MKDOC) $(srcdir)/../targets.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../targets.c >targets.texi + +init.texi: $(MKDOC) $(srcdir)/../init.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../init.c >init.texi + +hash.texi: $(MKDOC) $(srcdir)/../hash.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../hash.c >hash.texi + +linker.texi: $(MKDOC) $(srcdir)/../linker.c $(srcdir)/doc.str + $(MKDOC) -f $(srcdir)/doc.str <$(srcdir)/../linker.c >linker.texi + +libbfd.h: $(srcdir)/../libbfd-in.h \ + $(srcdir)/../init.c \ + $(srcdir)/../libbfd.c \ + $(srcdir)/../cache.c \ + $(srcdir)/../reloc.c \ + $(srcdir)/../cpu-h8300.c \ + $(srcdir)/../cpu-i960.c \ + $(srcdir)/../archures.c \ + $(srcdir)/../elfcode.h \ + $(srcdir)/proto.str \ + $(MKDOC) + cat $(srcdir)/../libbfd-in.h >libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../init.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../libbfd.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../cache.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../reloc.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../cpu-h8300.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../cpu-i960.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../archures.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../elf.c >>libbfd.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../elfcode.h >>libbfd.h + +libcoff.h: $(srcdir)/../libcoff-in.h \ + $(srcdir)/../coffcode.h \ + $(srcdir)/proto.str \ + $(MKDOC) + cat $(srcdir)/../libcoff-in.h >libcoff.h + $(MKDOC) -i -f $(srcdir)/proto.str < $(srcdir)/../coffcode.h >>libcoff.h + +bfd.h: $(srcdir)/../bfd-in.h \ + $(srcdir)/../init.c \ + $(srcdir)/../opncls.c \ + $(srcdir)/../libbfd.c \ + $(srcdir)/../section.c \ + $(srcdir)/../archures.c \ + $(srcdir)/../reloc.c \ + $(srcdir)/../syms.c \ + $(srcdir)/../bfd.c \ + $(srcdir)/../archive.c \ + $(srcdir)/../corefile.c \ + $(srcdir)/../targets.c \ + $(srcdir)/../format.c \ + $(srcdir)/proto.str \ + $(MKDOC) + cat $(srcdir)/../bfd-in.h >bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../init.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../opncls.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../libbfd.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../section.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../archures.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../reloc.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../syms.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../bfd.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../archive.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../corefile.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../targets.c >>bfd.h + $(MKDOC) -f $(srcdir)/proto.str<$(srcdir)/../format.c >>bfd.h + echo "#ifdef __cplusplus" >>bfd.h + echo "}" >>bfd.h + echo "#endif" >>bfd.h + echo "#endif" >>bfd.h + + +clean-info: clean + +mostlyclean: + rm -rf *.log *.ps *~* *.dvi *# $(MKDOC) *.o + +clean: mostlyclean + rm -rf $(STAGESTUFF) + rm -f *.p *.ip bfd.?? bfd.??? bfd.h libbfd.h libcoff.h texput.log + +distclean: clean + rm -f Makefile config.status + +maintainer-clean realclean: clean + rm -f Makefile config.status + +bfd.info: $(DOCFILES) bfdsumm.texi bfd.texinfo + $(MAKEINFO) -I$(srcdir) -o bfd.info $(srcdir)/bfd.texinfo + +bfd.dvi: $(DOCFILES) bfdsumm.texi bfd.texinfo + $(TEXI2DVI) $(srcdir)/bfd.texinfo + +bfd.ps: bfd.dvi + dvips bfd -o + +quickdoc: $(DOCFILES) bfdsumm.texi bfd.texinfo + TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex bfd.texinfo + +stage1: force + - mkdir stage1 + - mv -f $(STAGESTUFF) stage1 + +stage2: force + - mkdir stage2 + - mv -f $(STAGESTUFF) stage2 + +stage3: force + - mkdir stage3 + - mv -f $(STAGESTUFF) stage3 + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i || exit 1 ; done + +de-stage1: force + - (cd stage1 ; mv -f $(STAGESTUFF) ..) + - rmdir stage1 + +de-stage2: force + - (cd stage2 ; mv -f $(STAGESTUFF) ..) + - rmdir stage2 + +de-stage3: force + - (cd stage3 ; mv -f $(STAGESTUFF) ..) + - rmdir stage3 + +force: + +Makefile: $(srcdir)/Makefile.in + cd .. && CONFIG_FILES=doc/$@ CONFIG_HEADERS= $(SHELL) ./config.status + diff --git a/contrib/gdb/bfd/doc/bfd.texinfo b/contrib/gdb/bfd/doc/bfd.texinfo new file mode 100644 index 000000000000..af7bc10062d5 --- /dev/null +++ b/contrib/gdb/bfd/doc/bfd.texinfo @@ -0,0 +1,348 @@ +\input texinfo.tex +@setfilename bfd.info +@c $Id: bfd.texinfo,v 1.28 1995/11/10 20:04:12 victoria Exp $ +@tex +% NOTE LOCAL KLUGE TO AVOID TOO MUCH WHITESPACE +\global\long\def\example{% +\begingroup +\let\aboveenvbreak=\par +\let\afterenvbreak=\par +\parskip=0pt +\lisp} +\global\long\def\Eexample{% +\Elisp +\endgroup +\vskip -\parskip% to cancel out effect of following \par +} +@end tex +@synindex fn cp + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Bfd: (bfd). The Binary File Descriptor library. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the BFD library. + +Copyright (C) 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, subject to the terms +of the GNU General Public License, which includes the provision that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo +@iftex +@c@finalout +@setchapternewpage on +@c@setchapternewpage odd +@settitle LIB BFD, the Binary File Descriptor Library +@titlepage +@title{libbfd} +@subtitle{The Binary File Descriptor Library} +@sp 1 +@subtitle First Edition---BFD version < 3.0 +@subtitle April 1991 +@author {Steve Chamberlain} +@author {Cygnus Support} +@page + +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.28 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill sac\@cygnus.com\par +\hfill {\it BFD}, \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +\global\parindent=0pt % Steve likes it this way +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, subject to the terms +of the GNU General Public License, which includes the provision that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage +@end iftex + +@node Top, Overview, (dir), (dir) +@ifinfo +This file documents the binary file descriptor library libbfd. +@end ifinfo + +@menu +* Overview:: Overview of BFD +* BFD front end:: BFD front end +* BFD back ends:: BFD back ends +* Index:: Index +@end menu + +@node Overview, BFD front end, Top, Top +@chapter Introduction +@cindex BFD +@cindex what is it? +BFD is a package which allows applications to use the +same routines to operate on object files whatever the object file +format. A new object file format can be supported simply by +creating a new BFD back end and adding it to the library. + +BFD is split into two parts: the front end, and the back ends (one for +each object file format). +@itemize @bullet +@item The front end of BFD provides the interface to the user. It manages +memory and various canonical data structures. The front end also +decides which back end to use and when to call back end routines. +@item The back ends provide BFD its view of the real world. Each back +end provides a set of calls which the BFD front end can use to maintain +its canonical form. The back ends also may keep around information for +their own use, for greater efficiency. +@end itemize +@menu +* History:: History +* How It Works:: How It Works +* What BFD Version 2 Can Do:: What BFD Version 2 Can Do +@end menu + +@node History, How It Works, Overview, Overview +@section History + +One spur behind BFD was the desire, on the part of the GNU 960 team at +Intel Oregon, for interoperability of applications on their COFF and +b.out file formats. Cygnus was providing GNU support for the team, and +was contracted to provide the required functionality. + +The name came from a conversation David Wallace was having with Richard +Stallman about the library: RMS said that it would be quite hard---David +said ``BFD''. Stallman was right, but the name stuck. + +At the same time, Ready Systems wanted much the same thing, but for +different object file formats: IEEE-695, Oasys, Srecords, a.out and 68k +coff. + +BFD was first implemented by members of Cygnus Support; Steve +Chamberlain (@code{sac@@cygnus.com}), John Gilmore +(@code{gnu@@cygnus.com}), K. Richard Pixley (@code{rich@@cygnus.com}) +and David Henkel-Wallace (@code{gumby@@cygnus.com}). + + + +@node How It Works, What BFD Version 2 Can Do, History, Overview +@section How To Use BFD + +To use the library, include @file{bfd.h} and link with @file{libbfd.a}. + +BFD provides a common interface to the parts of an object file +for a calling application. + +When an application sucessfully opens a target file (object, archive, or +whatever), a pointer to an internal structure is returned. This pointer +points to a structure called @code{bfd}, described in +@file{bfd.h}. Our convention is to call this pointer a BFD, and +instances of it within code @code{abfd}. All operations on +the target object file are applied as methods to the BFD. The mapping is +defined within @code{bfd.h} in a set of macros, all beginning +with @samp{bfd_} to reduce namespace pollution. + +For example, this sequence does what you would probably expect: +return the number of sections in an object file attached to a BFD +@code{abfd}. + +@lisp +@c @cartouche +#include "bfd.h" + +unsigned int number_of_sections(abfd) +bfd *abfd; +@{ + return bfd_count_sections(abfd); +@} +@c @end cartouche +@end lisp + +The abstraction used within BFD is that an object file has: + +@itemize @bullet +@item +a header, +@item +a number of sections containing raw data (@pxref{Sections}), +@item +a set of relocations (@pxref{Relocations}), and +@item +some symbol information (@pxref{Symbols}). +@end itemize +@noindent +Also, BFDs opened for archives have the additional attribute of an index +and contain subordinate BFDs. This approach is fine for a.out and coff, +but loses efficiency when applied to formats such as S-records and +IEEE-695. + +@node What BFD Version 2 Can Do, , How It Works, Overview +@section What BFD Version 2 Can Do +@include bfdsumm.texi + +@node BFD front end, BFD back ends, Overview, Top +@chapter BFD front end +@include bfd.texi + +@menu +* Memory Usage:: +* Initialization:: +* Sections:: +* Symbols:: +* Archives:: +* Formats:: +* Relocations:: +* Core Files:: +* Targets:: +* Architectures:: +* Opening and Closing:: +* Internal:: +* File Caching:: +* Linker Functions:: +* Hash Tables:: +@end menu + +@node Memory Usage, Initialization, BFD front end, BFD front end +@section Memory usage +BFD keeps all of its internal structures in obstacks. There is one obstack +per open BFD file, into which the current state is stored. When a BFD is +closed, the obstack is deleted, and so everything which has been +allocated by BFD for the closing file is thrown away. + +BFD does not free anything created by an application, but pointers into +@code{bfd} structures become invalid on a @code{bfd_close}; for example, +after a @code{bfd_close} the vector passed to +@code{bfd_canonicalize_symtab} is still around, since it has been +allocated by the application, but the data that it pointed to are +lost. + +The general rule is to not close a BFD until all operations dependent +upon data from the BFD have been completed, or all the data from within +the file has been copied. To help with the management of memory, there +is a function (@code{bfd_alloc_size}) which returns the number of bytes +in obstacks associated with the supplied BFD. This could be used to +select the greediest open BFD, close it to reclaim the memory, perform +some operation and reopen the BFD again, to get a fresh copy of the data +structures. + +@node Initialization, Sections, Memory Usage, BFD front end +@include init.texi + +@node Sections, Symbols, Initialization, BFD front end +@include section.texi + +@node Symbols, Archives, Sections, BFD front end +@include syms.texi + +@node Archives, Formats, Symbols, BFD front end +@include archive.texi + +@node Formats, Relocations, Archives, BFD front end +@include format.texi + +@node Relocations, Core Files, Formats, BFD front end +@include reloc.texi + +@node Core Files, Targets, Relocations, BFD front end +@include core.texi + +@node Targets, Architectures, Core Files, BFD front end +@include targets.texi + +@node Architectures, Opening and Closing, Targets, BFD front end +@include archures.texi + +@node Opening and Closing, Internal, Architectures, BFD front end +@include opncls.texi + +@node Internal, File Caching, Opening and Closing, BFD front end +@include libbfd.texi + +@node File Caching, Linker Functions, Internal, BFD front end +@include cache.texi + +@node Linker Functions, Hash Tables, File Caching, BFD front end +@include linker.texi + +@node Hash Tables, , Linker Functions, BFD front end +@include hash.texi + +@node BFD back ends, Index, BFD front end, Top +@chapter BFD back ends +@menu +* What to Put Where:: +* aout :: a.out backends +* coff :: coff backends +* elf :: elf backends +@ignore +* oasys :: oasys backends +* ieee :: ieee backend +* srecord :: s-record backend +@end ignore +@end menu +@node What to Put Where, aout, BFD back ends, BFD back ends +All of BFD lives in one directory. + +@node aout, coff, What to Put Where, BFD back ends +@include aoutx.texi + +@node coff, elf, aout, BFD back ends +@include coffcode.texi + +@node elf, , coff, BFD back ends +@include elf.texi +@c Leave this out until the file has some actual contents... +@c @include elfcode.texi + +@node Index, , BFD back ends , Top +@unnumbered Index +@printindex cp + +@tex +% 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} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/} and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 28mar91. +@end tex + +@contents +@bye diff --git a/contrib/gdb/bfd/doc/bfdsumm.texi b/contrib/gdb/bfd/doc/bfdsumm.texi new file mode 100644 index 000000000000..844531aff8cb --- /dev/null +++ b/contrib/gdb/bfd/doc/bfdsumm.texi @@ -0,0 +1,148 @@ +@c This summary of BFD is shared by the BFD and LD docs. +When an object file is opened, BFD subroutines automatically determine +the format of the input object file. They then build a descriptor in +memory with pointers to routines that will be used to access elements of +the object file's data structures. + +As different information from the the object files is required, +BFD reads from different sections of the file and processes them. +For example, a very common operation for the linker is processing symbol +tables. Each BFD back end provides a routine for converting +between the object file's representation of symbols and an internal +canonical format. When the linker asks for the symbol table of an object +file, it calls through a memory pointer to the routine from the +relevant BFD back end which reads and converts the table into a canonical +form. The linker then operates upon the canonical form. When the link is +finished and the linker writes the output file's symbol table, +another BFD back end routine is called to take the newly +created symbol table and convert it into the chosen output format. + +@menu +* BFD information loss:: Information Loss +* Canonical format:: The BFD canonical object-file format +@end menu + +@node BFD information loss +@subsection Information Loss + +@emph{Information can be lost during output.} The output formats +supported by BFD do not provide identical facilities, and +information which can be described in one form has nowhere to go in +another format. One example of this is alignment information in +@code{b.out}. There is nowhere in an @code{a.out} format file to store +alignment information on the contained data, so when a file is linked +from @code{b.out} and an @code{a.out} image is produced, alignment +information will not propagate to the output file. (The linker will +still use the alignment information internally, so the link is performed +correctly). + +Another example is COFF section names. COFF files may contain an +unlimited number of sections, each one with a textual section name. If +the target of the link is a format which does not have many sections (e.g., +@code{a.out}) or has sections without names (e.g., the Oasys format), the +link cannot be done simply. You can circumvent this problem by +describing the desired input-to-output section mapping with the linker command +language. + +@emph{Information can be lost during canonicalization.} The BFD +internal canonical form of the external formats is not exhaustive; there +are structures in input formats for which there is no direct +representation internally. This means that the BFD back ends +cannot maintain all possible data richness through the transformation +between external to internal and back to external formats. + +This limitation is only a problem when an application reads one +format and writes another. Each BFD back end is responsible for +maintaining as much data as possible, and the internal BFD +canonical form has structures which are opaque to the BFD core, +and exported only to the back ends. When a file is read in one format, +the canonical form is generated for BFD and the application. At the +same time, the back end saves away any information which may otherwise +be lost. If the data is then written back in the same format, the back +end routine will be able to use the canonical form provided by the +BFD core as well as the information it prepared earlier. Since +there is a great deal of commonality between back ends, +there is no information lost when +linking or copying big endian COFF to little endian COFF, or @code{a.out} to +@code{b.out}. When a mixture of formats is linked, the information is +only lost from the files whose format differs from the destination. + +@node Canonical format +@subsection The BFD canonical object-file format + +The greatest potential for loss of information occurs when there is the least +overlap between the information provided by the source format, that +stored by the canonical format, and that needed by the +destination format. A brief description of the canonical form may help +you understand which kinds of data you can count on preserving across +conversions. +@cindex BFD canonical format +@cindex internal object-file format + +@table @emph +@item files +Information stored on a per-file basis includes target machine +architecture, particular implementation format type, a demand pageable +bit, and a write protected bit. Information like Unix magic numbers is +not stored here---only the magic numbers' meaning, so a @code{ZMAGIC} +file would have both the demand pageable bit and the write protected +text bit set. The byte order of the target is stored on a per-file +basis, so that big- and little-endian object files may be used with one +another. + +@item sections +Each section in the input file contains the name of the section, the +section's original address in the object file, size and alignment +information, various flags, and pointers into other BFD data +structures. + +@item symbols +Each symbol contains a pointer to the information for the object file +which originally defined it, its name, its value, and various flag +bits. When a BFD back end reads in a symbol table, it relocates all +symbols to make them relative to the base of the section where they were +defined. Doing this ensures that each symbol points to its containing +section. Each symbol also has a varying amount of hidden private data +for the BFD back end. Since the symbol points to the original file, the +private data format for that symbol is accessible. @code{ld} can +operate on a collection of symbols of wildly different formats without +problems. + +Normal global and simple local symbols are maintained on output, so an +output file (no matter its format) will retain symbols pointing to +functions and to global, static, and common variables. Some symbol +information is not worth retaining; in @code{a.out}, type information is +stored in the symbol table as long symbol names. This information would +be useless to most COFF debuggers; the linker has command line switches +to allow users to throw it away. + +There is one word of type information within the symbol, so if the +format supports symbol type information within symbols (for example, COFF, +IEEE, Oasys) and the type is simple enough to fit within one word +(nearly everything but aggregates), the information will be preserved. + +@item relocation level +Each canonical BFD relocation record contains a pointer to the symbol to +relocate to, the offset of the data to relocate, the section the data +is in, and a pointer to a relocation type descriptor. Relocation is +performed by passing messages through the relocation type +descriptor and the symbol pointer. Therefore, relocations can be performed +on output data using a relocation method that is only available in one of the +input formats. For instance, Oasys provides a byte relocation format. +A relocation record requesting this relocation type would point +indirectly to a routine to perform this, so the relocation may be +performed on a byte being written to a 68k COFF file, even though 68k COFF +has no such relocation type. + +@item line numbers +Object formats can contain, for debugging purposes, some form of mapping +between symbols, source line numbers, and addresses in the output file. +These addresses have to be relocated along with the symbol information. +Each symbol with an associated list of line number records points to the +first record of the list. The head of a line number list consists of a +pointer to the symbol, which allows finding out the address of the +function whose line number is being described. The rest of the list is +made up of pairs: offsets into the section and line numbers. Any format +which can simply derive this information can pass it successfully +between formats (COFF, IEEE and Oasys). +@end table diff --git a/contrib/gdb/bfd/doc/chew.c b/contrib/gdb/bfd/doc/chew.c new file mode 100644 index 000000000000..5c04404f7a64 --- /dev/null +++ b/contrib/gdb/bfd/doc/chew.c @@ -0,0 +1,1551 @@ +/* chew + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Contributed by steve chamberlain @cygnus + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Yet another way of extracting documentation from source. + No, I haven't finished it yet, but I hope you people like it better + than the old way + + sac + + Basically, this is a sort of string forth, maybe we should call it + struth? + + You define new words thus: + : ; + +*/ + +/* Primitives provided by the program: + + Two stacks are provided, a string stack and an integer stack. + + Internal state variables: + internal_wanted - indicates whether `-i' was passed + internal_mode - user-settable + + Commands: + push_text + ! - pop top of integer stack for address, pop next for value; store + @ - treat value on integer stack as the address of an integer; push + that integer on the integer stack after popping the "address" + hello - print "hello\n" to stdout + stdout - put stdout marker on TOS + stderr - put stderr marker on TOS + print - print TOS-1 on TOS (eg: "hello\n" stdout print) + skip_past_newline + catstr - fn icatstr + copy_past_newline - append input, up to and including newline into TOS + dup - fn other_dup + drop - discard TOS + idrop - ditto + remchar - delete last character from TOS + get_stuff_in_command + do_fancy_stuff - translate <> to @code{foo} in TOS + bulletize - if "o" lines found, prepend @itemize @bullet to TOS + and @item to each "o" line; append @end itemize + courierize - put @example around . and | lines, translate {* *} { } + exit - fn chew_exit + swap + outputdots - strip out lines without leading dots + paramstuff - convert full declaration into "PARAMS" form if not already + maybecatstr - do catstr if internal_mode == internal_wanted, discard + value in any case + translatecomments - turn {* and *} into comment delimiters + kill_bogus_lines - get rid of extra newlines + indent + internalmode - pop from integer stack, set `internalmode' to that value + print_stack_level - print current stack depth to stderr + strip_trailing_newlines - go ahead, guess... + [quoted string] - push string onto string stack + [word starting with digit] - push atol(str) onto integer stack + + A command must be all upper-case, and alone on a line. + + Foo. */ + + +#include +#include "sysdep.h" +#include +#include +#include + +#define DEF_SIZE 5000 +#define STACK 50 + +int internal_wanted; +int internal_mode; + +int warning; + +/* Here is a string type ... */ + +typedef struct buffer +{ + char *ptr; + unsigned long write_idx; + unsigned long size; +} string_type; + + +#ifdef __STDC__ +static void init_string_with_size (string_type *, unsigned int); +static void init_string (string_type *); +static int find (string_type *, char *); +static void write_buffer (string_type *, FILE *); +static void delete_string (string_type *); +static char *addr (string_type *, unsigned int); +static char at (string_type *, unsigned int); +static void catchar (string_type *, int); +static void overwrite_string (string_type *, string_type *); +static void catbuf (string_type *, char *, unsigned int); +static void cattext (string_type *, char *); +static void catstr (string_type *, string_type *); +static unsigned int skip_white_and_starts (string_type *, unsigned int); +#endif + + +static void DEFUN(init_string_with_size,(buffer, size), + string_type *buffer AND + unsigned int size ) +{ + buffer->write_idx = 0; + buffer->size = size; + buffer->ptr = malloc(size); +} + +static void DEFUN(init_string,(buffer), + string_type *buffer) +{ + init_string_with_size(buffer, DEF_SIZE); + +} + +static int DEFUN(find, (str, what), + string_type *str AND + char *what) +{ + unsigned int i; + char *p; + p = what; + for (i = 0; i < str->write_idx && *p; i++) + { + if (*p == str->ptr[i]) + p++; + else + p = what; + } + return (*p == 0); + +} + +static void DEFUN(write_buffer,(buffer, f), + string_type *buffer AND + FILE *f) +{ + fwrite(buffer->ptr, buffer->write_idx, 1, f); +} + + +static void DEFUN(delete_string,(buffer), + string_type *buffer) +{ + free(buffer->ptr); +} + + +static char *DEFUN(addr, (buffer, idx), + string_type *buffer AND + unsigned int idx) +{ + return buffer->ptr + idx; +} + +static char DEFUN(at,(buffer, pos), + string_type *buffer AND + unsigned int pos) +{ + if (pos >= buffer->write_idx) + return 0; + return buffer->ptr[pos]; +} + +static void DEFUN(catchar,(buffer, ch), + string_type *buffer AND + int ch) +{ + if (buffer->write_idx == buffer->size) + { + buffer->size *=2; + buffer->ptr = realloc(buffer->ptr, buffer->size); + } + + buffer->ptr[buffer->write_idx ++ ] = ch; +} + + +static void DEFUN(overwrite_string,(dst, src), + string_type *dst AND + string_type *src) +{ + free(dst->ptr); + dst->size = src->size; + dst->write_idx = src->write_idx; + dst->ptr = src->ptr; +} + +static void DEFUN(catbuf,(buffer, buf, len), + string_type *buffer AND + char *buf AND + unsigned int len) +{ + if (buffer->write_idx + len >= buffer->size) + { + while (buffer->write_idx + len >= buffer->size) + buffer->size *= 2; + buffer->ptr = realloc (buffer->ptr, buffer->size); + } + memcpy (buffer->ptr + buffer->write_idx, buf, len); + buffer->write_idx += len; +} + +static void DEFUN(cattext,(buffer, string), + string_type *buffer AND + char *string) +{ + catbuf (buffer, string, (unsigned int) strlen (string)); +} + +static void DEFUN(catstr,(dst, src), + string_type *dst AND + string_type *src) +{ + catbuf (dst, src->ptr, src->write_idx); +} + + +static unsigned int +DEFUN(skip_white_and_stars,(src, idx), + string_type *src AND + unsigned int idx) +{ + char c; + while ((c = at(src,idx)), + isspace (c) + || (c == '*' + /* Don't skip past end-of-comment or star as first + character on its line. */ + && at(src,idx +1) != '/' + && at(src,idx -1) != '\n')) + idx++; + return idx; +} + +/***********************************************************************/ + + +string_type stack[STACK]; +string_type *tos; + +unsigned int idx = 0; /* Pos in input buffer */ +string_type *ptr; /* and the buffer */ +typedef void (*stinst_type)(); +stinst_type *pc; +stinst_type sstack[STACK]; +stinst_type *ssp = &sstack[0]; +long istack[STACK]; +long *isp = &istack[0]; + +typedef int *word_type; + + + +struct dict_struct +{ + char *word; + struct dict_struct *next; + stinst_type *code; + int code_length; + int code_end; + int var; + +}; +typedef struct dict_struct dict_type; +#define WORD(x) static void x() + +static void +die (msg) + char *msg; +{ + fprintf (stderr, "%s\n", msg); + exit (1); +} + +static void +check_range () +{ + if (tos < stack) + die ("underflow in string stack"); + if (tos >= stack + STACK) + die ("overflow in string stack"); +} + +static void +icheck_range () +{ + if (isp < istack) + die ("underflow in integer stack"); + if (isp >= istack + STACK) + die ("overflow in integer stack"); +} + +#ifdef __STDC__ +static void exec (dict_type *); +static void call (void); +static void remchar (void), strip_trailing_newlines (void), push_number (void); +static void push_text (void); +static void remove_noncomments (string_type *, string_type *); +static void print_stack_level (void); +static void paramstuff (void), translatecomments (void), manglecomments (void); +static void outputdots (void), courierize (void), bulletize (void); +static void do_fancy_stuff (void); +static int iscommand (string_type *, unsigned int); +static int copy_past_newline (string_type *, unsigned int, string_type *); +static void icopy_past_newline (void), kill_bogus_lines (void), indent (void); +static void get_stuff_in_command (void), swap (void), other_dup (void); +static void drop (void), idrop (void); +static void icatstr (void), skip_past_newline (void), internalmode (void); +static void maybecatstr (void); +static char *nextword (char *, char **); +dict_type *lookup_word (char *); +static void perform (void); +dict_type *newentry (char *); +unsigned int add_to_definition (dict_type *, stinst_type); +void add_intrinsic (char *, void (*)()); +void add_var (char *); +void compile (char *); +static void bang (void); +static void atsign (void); +static void hello (void); +static void stdout_ (void); +static void stderr_ (void); +static void print (void); +static void read_in (string_type *, FILE *); +static void usage (void); +static void chew_exit (void); +#endif + +static void DEFUN(exec,(word), + dict_type *word) +{ + pc = word->code; + while (*pc) + (*pc)(); +} +WORD(call) +{ + stinst_type *oldpc = pc; + dict_type *e; + e = (dict_type *)(pc [1]); + exec(e); + pc = oldpc + 2; + +} + +WORD(remchar) +{ + if (tos->write_idx) + tos->write_idx--; + pc++; +} + +static void +strip_trailing_newlines () +{ + while ((isspace (at (tos, tos->write_idx - 1)) + || at (tos, tos->write_idx - 1) == '\n') + && tos->write_idx > 0) + tos->write_idx--; + pc++; +} + +WORD(push_number) +{ + isp++; + icheck_range (); + pc++; + *isp = (long)(*pc); + pc++; +} + +WORD(push_text) +{ + tos++; + check_range (); + init_string(tos); + pc++; + cattext(tos,*((char **)pc)); + pc++; + +} + + +/* This function removes everything not inside comments starting on + the first char of the line from the string, also when copying + comments, removes blank space and leading *'s. + Blank lines are turned into one blank line. */ + +static void +DEFUN(remove_noncomments,(src,dst), + string_type *src AND + string_type *dst) +{ + unsigned int idx = 0; + + while (at(src,idx)) + { + /* Now see if we have a comment at the start of the line */ + if (at(src,idx) == '\n' + && at(src,idx+1) == '/' + && at(src,idx+2) == '*') + { + idx+=3; + + idx = skip_white_and_stars(src,idx); + + /* Remove leading dot */ + if (at(src, idx) == '.') + idx++; + + /* Copy to the end of the line, or till the end of the + comment */ + while (at(src, idx)) + { + if (at(src, idx) == '\n') + { + /* end of line, echo and scrape of leading blanks */ + if (at(src,idx +1) == '\n') + catchar(dst,'\n'); + catchar(dst,'\n'); + idx++; + idx = skip_white_and_stars(src, idx); + } + else if (at(src, idx) == '*' && at(src,idx+1) == '/') + { + idx +=2 ; + cattext(dst,"\nENDDD\n"); + break; + } + else + { + catchar(dst, at(src, idx)); + idx++; + } + } + } + else idx++; + } +} + +static void +print_stack_level () +{ + fprintf (stderr, "current string stack depth = %d, ", tos - stack); + fprintf (stderr, "current integer stack depth = %d\n", isp - istack); + pc++; +} + +/* turn: + foobar name(stuff); + into: + foobar + name PARAMS ((stuff)); + and a blank line. + */ + +static void +DEFUN_VOID(paramstuff) +{ + unsigned int openp; + unsigned int fname; + unsigned int idx; + string_type out; + init_string(&out); + + + /* make sure that it's not already param'd or proto'd */ + if(find(tos,"PARAMS") || find(tos,"PROTO") || !find(tos,"(")) { + catstr(&out,tos); + } + else + { + /* Find the open paren */ + for (openp = 0; at(tos, openp) != '(' && at(tos,openp); openp++) + ; + + fname = openp; + /* Step back to the fname */ + fname--; + while (fname && isspace(at(tos, fname))) + fname --; + while (fname && !isspace(at(tos,fname)) && at(tos,fname) != '*') + fname--; + + fname++; + + for (idx = 0; idx < fname; idx++) /* Output type */ + { + catchar(&out, at(tos,idx)); + } + + cattext(&out, "\n"); /* Insert a newline between type and fnname */ + + for (idx = fname; idx < openp; idx++) /* Output fnname */ + { + catchar(&out, at(tos,idx)); + } + + cattext(&out," PARAMS ("); + + while (at(tos,idx) && at(tos,idx) !=';') + { + catchar(&out, at(tos, idx)); + idx++; + } + cattext(&out,");\n\n"); + } + overwrite_string(tos, &out); + pc++; + +} + + + +/* turn {* + and *} into comments */ + +WORD(translatecomments) +{ + unsigned int idx = 0; + string_type out; + init_string(&out); + + while (at(tos, idx)) + { + if (at(tos,idx) == '{' && at(tos,idx+1) =='*') + { + cattext(&out,"/*"); + idx+=2; + } + else if (at(tos,idx) == '*' && at(tos,idx+1) =='}') + { + cattext(&out,"*/"); + idx+=2; + } + else + { + catchar(&out, at(tos, idx)); + idx++; + } + } + + + overwrite_string(tos, &out); + + pc++; + +} + +/* turn everything not starting with a . into a comment */ + +WORD(manglecomments) +{ + unsigned int idx = 0; + string_type out; + init_string(&out); + + while (at(tos, idx)) + { + if (at(tos,idx) == '\n' && at(tos,idx+1) =='*') + { + cattext(&out," /*"); + idx+=2; + } + else if (at(tos,idx) == '*' && at(tos,idx+1) =='}') + { + cattext(&out,"*/"); + idx+=2; + } + else + { + catchar(&out, at(tos, idx)); + idx++; + } + } + + + overwrite_string(tos, &out); + + pc++; + +} + +/* Mod tos so that only lines with leading dots remain */ +static void +DEFUN_VOID(outputdots) +{ + unsigned int idx = 0; + string_type out; + init_string(&out); + + while (at(tos, idx)) + { + if (at(tos, idx) == '\n' && at(tos, idx+1) == '.') + { + char c, c2; + idx += 2; + + while ((c = at(tos, idx)) && c != '\n') + { + if (c == '{' && at(tos,idx+1) =='*') + { + cattext(&out," /*"); + idx+=2; + } + else if (c == '*' && at(tos,idx+1) =='}') + { + cattext(&out,"*/"); + idx+=2; + } + else + { + catchar(&out, c); + idx++; + } + } + catchar(&out,'\n'); + } + else + { + idx++; + } + } + + overwrite_string(tos, &out); + pc++; + +} + +/* Find lines starting with . and | and put example around them on tos */ +WORD(courierize) +{ + string_type out; + unsigned int idx = 0; + int command = 0; + + init_string(&out); + + while (at(tos, idx)) + { + if (at(tos, idx) == '\n' + && (at(tos, idx +1 ) == '.' + || at(tos,idx+1) == '|')) + { + cattext(&out,"\n@example\n"); + do + { + idx += 2; + + while (at(tos, idx) && at(tos, idx)!='\n') + { + if (at(tos,idx)=='{' && at(tos,idx+1) =='*') + { + cattext(&out," /*"); + idx+=2; + } + else if (at(tos,idx)=='*' && at(tos,idx+1) =='}') + { + cattext(&out,"*/"); + idx+=2; + } + else if (at(tos,idx) == '{' && !command) + { + cattext(&out,"@{"); + idx++; + } + else if (at(tos,idx) == '}' && !command) + { + cattext(&out,"@}"); + idx++; + } + else + { + if (at(tos,idx) == '@') + command = 1; + else if (isspace(at(tos,idx)) || at(tos,idx) == '}') + command = 0; + catchar(&out, at(tos, idx)); + idx++; + } + + } + catchar(&out,'\n'); + } + while (at(tos, idx) == '\n' + && (at(tos, idx+1) == '.') + || (at(tos,idx+1) == '|')); + cattext(&out,"@end example"); + } + else + { + catchar(&out, at(tos, idx)); + idx++; + } + } + + overwrite_string(tos, &out); + pc++; + + +} + +/* Finds any lines starting with "o ", if there are any, then turns + on @itemize @bullet, and @items each of them. Then ends with @end + itemize, inplace at TOS*/ + + +WORD(bulletize) +{ + unsigned int idx = 0; + int on = 0; + string_type out; + init_string(&out); + + while (at(tos, idx)) { + if (at(tos, idx) == '@' && + at(tos, idx+1) == '*') + { + cattext(&out,"*"); + idx+=2; + } + +else + if (at(tos, idx) == '\n' && + at(tos, idx+1) == 'o' && + isspace(at(tos, idx +2))) + { + if (!on) + { + cattext(&out,"\n@itemize @bullet\n"); + on = 1; + + } + cattext(&out,"\n@item\n"); + idx+=3; + } + else + { + catchar(&out, at(tos, idx)); + if (on && at(tos, idx) == '\n' && + at(tos, idx+1) == '\n' && + at(tos, idx+2) != 'o') + { + cattext(&out, "@end itemize"); + on = 0; + } + idx++; + + } + } + if (on) + { + cattext(&out,"@end itemize\n"); + } + + delete_string(tos); + *tos = out; + pc++; + +} + +/* Turn <> into @code{foo} in place at TOS*/ + + +WORD(do_fancy_stuff) +{ + unsigned int idx = 0; + string_type out; + init_string(&out); + while (at(tos, idx)) + { + if (at(tos, idx) == '<' + && at(tos, idx+1) == '<' + && !isspace(at(tos,idx + 2))) + { + /* This qualifies as a << startup */ + idx +=2; + cattext(&out,"@code{"); + while(at(tos,idx) && + at(tos,idx) != '>' ) + { + catchar(&out, at(tos, idx)); + idx++; + + } + cattext(&out,"}"); + idx+=2; + } + else + { + catchar(&out, at(tos, idx)); + idx++; + } + } + delete_string(tos); + *tos = out; + pc++; + +} +/* A command is all upper case,and alone on a line */ +static int +DEFUN( iscommand,(ptr, idx), + string_type *ptr AND + unsigned int idx) +{ + unsigned int len = 0; + while (at(ptr,idx)) { + if (isupper(at(ptr,idx)) || at(ptr,idx) == ' ' || + at(ptr,idx) == '_') + { + len++; + idx++; + } + else if(at(ptr,idx) == '\n') + { + if (len > 3) return 1; + return 0; + } + else return 0; + } + return 0; + +} + + +DEFUN(copy_past_newline,(ptr, idx, dst), + string_type *ptr AND + unsigned int idx AND + string_type *dst) +{ + while (at(ptr, idx) && at(ptr, idx) != '\n') + { + catchar(dst, at(ptr, idx)); + idx++; + + } + catchar(dst, at(ptr, idx)); + idx++; + return idx; + +} + +WORD(icopy_past_newline) +{ + tos++; + check_range (); + init_string(tos); + idx = copy_past_newline(ptr, idx, tos); + pc++; +} + +/* indent + Take the string at the top of the stack, do some prettying */ + + +WORD(kill_bogus_lines) +{ + int sl ; + + int nl = 0; + int idx = 0; + int c; + int dot = 0 ; + + string_type out; + init_string(&out); + /* Drop leading nl */ + while (at(tos,idx) == '\n') + { + idx++; + } + c = idx; + + /* Find the last char */ + while (at(tos,idx)) + { + idx++; + } + + /* find the last non white before the nl */ + idx--; + + while (idx && isspace(at(tos,idx))) + idx--; + idx++; + + /* Copy buffer upto last char, but blank lines before and after + dots don't count */ + sl = 1; + + while (c < idx) + { + if (at(tos,c) == '\n' + && at(tos,c+1) == '\n' + && at(tos,c+2) == '.') + { + /* Ignore two newlines before a dot*/ + c++; + } + else if (at(tos,c) == '.' && sl) + { + /* remember that this line started with a dot */ + dot=2; + } + else if (at(tos,c) == '\n' + && at(tos,c+1) == '\n' + && dot) + { + c++; + /* Ignore two newlines when last line was dot */ + } + + catchar(&out, at(tos,c)); + if (at(tos,c) == '\n') + { + sl = 1; + + if (dot == 2)dot=1;else dot = 0; + } + + c++; + + } + + /* Append nl*/ + catchar(&out, '\n'); + pc++; + delete_string(tos); + *tos = out; + + +} + +WORD(indent) +{ + string_type out; + int tab = 0; + int idx = 0; + int ol =0; + init_string(&out); + while (at(tos,idx)) { + switch (at(tos,idx)) + { + case '\n': + cattext(&out,"\n"); + idx++; + if (tab) + { + cattext(&out," "); + } + ol = 0; + break; + case '(': + tab++; + if (ol == 0) + cattext(&out," "); + idx++; + cattext(&out,"("); + ol = 1; + break; + case ')': + tab--; + cattext(&out,")"); + idx++; + ol=1; + + break; + default: + catchar(&out,at(tos,idx)); + ol=1; + + idx++; + break; + } + } + + pc++; + delete_string(tos); + *tos = out; + +} + + +WORD(get_stuff_in_command) +{ + tos++; + check_range (); + init_string(tos); + + while (at(ptr, idx)) { + if (iscommand(ptr, idx)) break; + idx = copy_past_newline(ptr, idx, tos); + } + pc++; +} + +WORD(swap) +{ + string_type t; + + t = tos[0]; + tos[0] = tos[-1]; + tos[-1] =t; + pc++; + +} + +WORD(other_dup) +{ + tos++; + check_range (); + init_string(tos); + catstr(tos, tos-1); + pc++; +} + +WORD(drop) +{ + tos--; + check_range (); + pc++; +} + +WORD(idrop) +{ + isp--; + icheck_range (); + pc++; +} + +WORD(icatstr) +{ + tos--; + check_range (); + catstr(tos, tos+1); + delete_string(tos+1); + pc++; +} + +WORD(skip_past_newline) +{ + while (at(ptr,idx) + && at(ptr,idx) != '\n') + idx++; + idx++; + pc++; +} + + +WORD(internalmode) +{ + internal_mode = *(isp); + isp--; + icheck_range (); + pc++; +} + +WORD(maybecatstr) +{ + if (internal_wanted == internal_mode) + { + catstr(tos-1, tos); + } + delete_string(tos); + tos--; + check_range (); + pc++; +} + +char * +DEFUN(nextword,(string, word), + char *string AND + char **word) +{ + char *word_start; + int idx; + char *dst; + char *src; + + int length = 0; + + while (isspace(*string) || *string == '-') { + if (*string == '-') + { + while (*string && *string != '\n') + string++; + + } + else { + string++; + } + } + if (!*string) return 0; + + word_start = string; + if (*string == '"') + { + do + { + string++; + length++; + if (*string == '\\') + { + string += 2; + length += 2; + } + } + while (*string != '"'); + } + else + { + while (!isspace(*string)) + { + string++; + length++; + + } + } + + *word = malloc(length + 1); + + dst = *word; + src = word_start; + + + for (idx= 0; idx < length; idx++) + { + if (src[idx] == '\\') + switch (src[idx+1]) + { + case 'n': + *dst++ = '\n'; + idx++; + break; + case '"': + case '\\': + *dst++ = src[idx+1]; + idx++; + break; + default: + *dst++ = '\\'; + break; + } + else + *dst++ = src[idx]; + } + *dst++ = 0; + + + + + + if(*string) + return string + 1; + else + return 0; + +} +dict_type *root; +dict_type * +DEFUN(lookup_word,(word), + char *word) +{ + dict_type *ptr = root; + while (ptr) { + if (strcmp(ptr->word, word) == 0) return ptr; + ptr = ptr->next; + + } + if (warning) + fprintf(stderr,"Can't find %s\n",word); + return 0; + + +} + +static void DEFUN_VOID(perform) +{ + tos = stack; + + while (at(ptr, idx)) { + /* It's worth looking through the command list */ + if (iscommand(ptr, idx)) + { + unsigned int i; + int found = 0; + + char *next; + dict_type *word ; + + (void) nextword(addr(ptr, idx), &next); + + + word = lookup_word(next); + + + + + if (word) + { + exec(word); + } + else + { + if (warning) + fprintf(stderr,"warning, %s is not recognised\n", next); + skip_past_newline(); + } + + } + else skip_past_newline(); + + } +} + +dict_type * +DEFUN(newentry,(word), + char *word) +{ + dict_type *new = (dict_type *)malloc(sizeof(dict_type)); + new->word = word; + new->next = root; + root = new; + new->code = (stinst_type *)malloc(sizeof(stinst_type )); + new->code_length = 1; + new->code_end = 0; + return new; + +} + + +unsigned int +DEFUN(add_to_definition,(entry, word), + dict_type *entry AND + stinst_type word) +{ + if (entry->code_end == entry->code_length) + { + entry->code_length += 2; + entry->code = + (stinst_type *) realloc((char *)(entry->code), + entry->code_length *sizeof(word_type)); + } + entry->code[entry->code_end] = word; + +return entry->code_end++; +} + + + + + + + +void +DEFUN(add_intrinsic,(name, func), + char *name AND + void (*func)()) +{ + dict_type *new = newentry(name); + add_to_definition(new, func); + add_to_definition(new, 0); +} + +void +DEFUN(add_var,(name), + char *name) +{ + dict_type *new = newentry(name); + add_to_definition(new, push_number); + add_to_definition(new, (stinst_type)(&(new->var))); + add_to_definition(new,0); +} + + +void +DEFUN(compile, (string), + char *string) +{ + int jstack[STACK]; + int *jptr = jstack; + /* add words to the dictionary */ + char *word; + string = nextword(string, &word); + while (string && *string && word[0]) + { + if (strcmp(word,"var")==0) + { + string=nextword(string, &word); + + add_var(word); + string=nextword(string, &word); + } +else + + if (word[0] == ':') + { + dict_type *ptr; + /* Compile a word and add to dictionary */ + string = nextword(string, &word); + + ptr = newentry(word); + string = nextword(string, &word); + while (word[0] != ';' ) + { + switch (word[0]) + { + case '"': + /* got a string, embed magic push string + function */ + add_to_definition(ptr, push_text); + add_to_definition(ptr, (stinst_type)(word+1)); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Got a number, embedd the magic push number + function */ + add_to_definition(ptr, push_number); + add_to_definition(ptr, (stinst_type)atol(word)); + break; + default: + add_to_definition(ptr, call); + add_to_definition(ptr, (stinst_type)lookup_word(word)); + } + + string = nextword(string, &word); + } + add_to_definition(ptr,0); + string = nextword(string, &word); + } + else + { + fprintf(stderr,"syntax error at %s\n",string-1); + } + } + +} + + +static void DEFUN_VOID(bang) +{ + *(long *)((isp[0])) = isp[-1]; + isp-=2; + icheck_range (); + pc++; +} + +WORD(atsign) +{ + isp[0] = *(long *)(isp[0]); + pc++; +} + +WORD(hello) +{ + printf("hello\n"); + pc++; +} + +WORD(stdout_) +{ + isp++; + icheck_range (); + *isp = 1; + pc++; +} + +WORD(stderr_) +{ + isp++; + icheck_range (); + *isp = 2; + pc++; +} + +WORD(print) +{ + if (*isp == 1) + write_buffer (tos, stdout); + else if (*isp == 2) + write_buffer (tos, stderr); + else + fprintf (stderr, "print: illegal print destination `%d'\n", *isp); + isp--; + tos--; + icheck_range (); + check_range (); + pc++; +} + + +static void DEFUN(read_in, (str, file), + string_type *str AND + FILE *file) +{ + char buff[10000]; + unsigned int r; + do + { + r = fread(buff, 1, sizeof(buff), file); + catbuf(str, buff, r); + } + while (r); + buff[0] = 0; + + catbuf(str, buff,1); +} + + +static void DEFUN_VOID(usage) +{ + fprintf(stderr,"usage: -[d|i|g] file\n"); + exit(33); +} + +/* There is no reliable way to declare exit. Sometimes it returns + int, and sometimes it returns void. Sometimes it changes between + OS releases. Trying to get it declared correctly in the hosts file + is a pointless waste of time. */ + +static void +chew_exit () +{ + exit (0); +} + +int DEFUN(main,(ac,av), +int ac AND +char *av[]) +{ + unsigned int i; + string_type buffer; + string_type pptr; + + init_string(&buffer); + init_string(&pptr); + init_string(stack+0); + tos=stack+1; + ptr = &pptr; + + add_intrinsic("push_text", push_text); + add_intrinsic("!", bang); + add_intrinsic("@", atsign); + add_intrinsic("hello",hello); + add_intrinsic("stdout",stdout_); + add_intrinsic("stderr",stderr_); + add_intrinsic("print",print); + add_intrinsic("skip_past_newline", skip_past_newline ); + add_intrinsic("catstr", icatstr ); + add_intrinsic("copy_past_newline", icopy_past_newline ); + add_intrinsic("dup", other_dup ); + add_intrinsic("drop", drop); + add_intrinsic("idrop", idrop); + add_intrinsic("remchar", remchar ); + add_intrinsic("get_stuff_in_command", get_stuff_in_command ); + add_intrinsic("do_fancy_stuff", do_fancy_stuff ); + add_intrinsic("bulletize", bulletize ); + add_intrinsic("courierize", courierize ); + /* If the following line gives an error, exit() is not declared in the + ../hosts/foo.h file for this host. Fix it there, not here! */ + /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */ + add_intrinsic("exit", chew_exit ); + add_intrinsic("swap", swap ); + add_intrinsic("outputdots", outputdots ); + add_intrinsic("paramstuff", paramstuff ); + add_intrinsic("maybecatstr", maybecatstr ); + add_intrinsic("translatecomments", translatecomments ); + add_intrinsic("kill_bogus_lines", kill_bogus_lines); + add_intrinsic("indent", indent); + add_intrinsic("internalmode", internalmode); + add_intrinsic("print_stack_level", print_stack_level); + add_intrinsic("strip_trailing_newlines", strip_trailing_newlines); + + /* Put a nl at the start */ + catchar(&buffer,'\n'); + + read_in(&buffer, stdin); + remove_noncomments(&buffer, ptr); + for (i= 1; i < ac; i++) + { + if (av[i][0] == '-') + { + if (av[i][1] == 'f') + { + string_type b; + FILE *f; + init_string(&b); + + f = fopen(av[i+1],"r"); + if (!f) + { + fprintf(stderr,"Can't open the input file %s\n",av[i+1]); + return 33; + } + + read_in(&b, f); + compile(b.ptr); + perform(); + } + else if (av[i][1] == 'i') + { + internal_wanted = 1; + } + else if (av[i][1] == 'w') + { + warning = 1; + } + } + } + write_buffer(stack+0, stdout); + if (tos != stack) + { + fprintf (stderr, "finishing with current stack level %d\n", tos - stack); + return 1; + } + return 0; +} diff --git a/contrib/gdb/bfd/doc/doc.str b/contrib/gdb/bfd/doc/doc.str new file mode 100644 index 000000000000..93685996e063 --- /dev/null +++ b/contrib/gdb/bfd/doc/doc.str @@ -0,0 +1,158 @@ +: DOCDD + skip_past_newline + get_stuff_in_command kill_bogus_lines catstr + ; + +: ENDDD + skip_past_newline + ; + +: EXAMPLE + skip_past_newline + get_stuff_in_command kill_bogus_lines do_fancy_stuff translatecomments + courierize catstr + + ; + +: INODE + "@node " catstr skip_past_newline copy_past_newline catstr + ; + +: CODE_FRAGMENT + EXAMPLE + ; + +: COMMENT + skip_past_newline + get_stuff_in_command + drop + ; + +: SYNOPSIS + skip_past_newline + "@strong{Synopsis}\n" catstr + "@example\n" catstr + get_stuff_in_command + kill_bogus_lines + indent + catstr + "@end example\n" catstr + + ; + +: func + "@findex " - a + skip_past_newline + copy_past_newline + dup - a x x + "@subsubsection @code{" - a x x b + swap + remchar + "}\n" - a x b x c + catstr catstr catstr catstr catstr + ; + +: FUNCTION + "@findex " - a + skip_past_newline + copy_past_newline + dup - a x x + "@subsubsection @code{" - a x x b + swap + remchar + "}\n" - a x b x c + catstr catstr catstr catstr catstr + ; + +: bodytext + get_stuff_in_command + bulletize + kill_bogus_lines + do_fancy_stuff + courierize + catstr + "@*\n" catstr + ; + +: asection + skip_past_newline + catstr + copy_past_newline + do_fancy_stuff catstr + bodytext + ; + +: SECTION + "@section " asection ; + +: SUBSECTION + "@subsection " asection ; + +: SUBSUBSECTION + "@subsubsection " asection ; + +: subhead + skip_past_newline + bodytext + ; + + + + +: DESCRIPTION + "@strong{Description}@*\n" catstr subhead ; + +: RETURNS + "@strong{Returns}@*\n" catstr subhead ; + +: INTERNAL_FUNCTION + func ; + + +: INTERNAL_DEFINITION + func ; + + +: INTERNAL + func ; + +: TYPEDEF + FUNCTION ; + +: SENUM + skip_past_newline + "Here are the possible values for @code{enum " + copy_past_newline remchar catstr + "}:\n\n" catstr catstr + ; +: ENUM + skip_past_newline + "@deffn {} " + copy_past_newline catstr catstr + ; +: ENUMX + skip_past_newline + "@deffnx {} " + copy_past_newline catstr + catstr + ; +: ENUMEQ + skip_past_newline + "@deffn {} " + copy_past_newline catstr catstr + skip_past_newline + ; +: ENUMEQX + skip_past_newline + "@deffnx {} " + copy_past_newline catstr + catstr + skip_past_newline + ; +: ENUMDOC + skip_past_newline + get_stuff_in_command + strip_trailing_newlines + catstr + "\n@end deffn\n" catstr + ; diff --git a/contrib/gdb/bfd/doc/proto.str b/contrib/gdb/bfd/doc/proto.str new file mode 100644 index 000000000000..8431c16bd57f --- /dev/null +++ b/contrib/gdb/bfd/doc/proto.str @@ -0,0 +1,135 @@ + +: SYNOPSIS + skip_past_newline + get_stuff_in_command + paramstuff + indent + maybecatstr +; + +: ignore + skip_past_newline + get_stuff_in_command + outputdots + maybecatstr + ; + +: CODE_FRAGMENT + ignore ; + +: external + 0 internalmode ignore ; + +: internal + 1 internalmode ignore ; + +- input stack { a b } output b if internal, a if external +: ifinternal + "" swap 1 internalmode maybecatstr + swap + "" swap 0 internalmode maybecatstr + catstr + ; + +- Put note in output string, regardless of internal mode. +: COMMENT + skip_past_newline + get_stuff_in_command + translatecomments + catstr + ; + +- SENUM enum-type-name +- ENUM enum-name +- ENUMX addl-enum-name +- ENUMDOC doc for preceding enums +- ENDSENUM max-enum-name + +: make_enum_header + dup + "enum " swap catstr + " {\n" catstr + swap " _dummy_first_" swap catstr catstr + ",\n" catstr + ; +: make_string_table_header + dup + "#ifdef _BFD_MAKE_TABLE_" swap catstr swap + "\n\nstatic const char *const " swap catstr catstr + "_names[] = { \"@@uninitialized@@\",\n" catstr + ; +: SENUM + skip_past_newline + copy_past_newline + remchar + dup + make_enum_header + swap + make_string_table_header + ifinternal + catstr + get_stuff_in_command catstr + translatecomments ; +: ENDSENUM + skip_past_newline + copy_past_newline strip_trailing_newlines + dup + " " swap catstr " };\n" catstr swap + " \"@@overflow: " swap catstr "@@\",\n};\n#endif\n\n" catstr + ifinternal + catstr + ; +: make_enumerator + " " swap catstr + ",\n" catstr + ; +: make_enumerator_string + " \"" swap catstr + "\",\n" catstr + ; +: ENUM + skip_past_newline + copy_past_newline + remchar + dup + make_enumerator + swap + make_enumerator_string + ifinternal + ; +: ENUMX ENUM catstr ; +: ENUMEQ + skip_past_newline + "#define " + copy_past_newline remchar + catstr + " " + catstr + copy_past_newline + catstr + "" swap 0 internalmode maybecatstr + ; +: ENUMEQX ENUMEQ catstr ; +: ENUMDOC + skip_past_newline + get_stuff_in_command + strip_trailing_newlines + "\n{* " swap catstr " *}\n" catstr + translatecomments + - discard it if we're doing internal mode + "" swap 0 internalmode maybecatstr + swap + catstr catstr + ; +: ENDDD external ; +: SECTION ignore ; +: SUBSECTION ignore ; +: SUBSUBSECTION ignore ; +: INTERNAL_DEFINITION internal ; +: DESCRIPTION ignore ; +: FUNCTION external ; +: RETURNS ignore ; +: TYPEDEF external ; +: INTERNAL_FUNCTION internal ; +: INTERNAL internal ; +: INODE ignore ; diff --git a/contrib/gdb/bfd/ecoff.c b/contrib/gdb/bfd/ecoff.c new file mode 100644 index 000000000000..e219ff77a230 --- /dev/null +++ b/contrib/gdb/bfd/ecoff.c @@ -0,0 +1,4740 @@ +/* Generic ECOFF (Extended-COFF) routines. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Original version by Per Bothner. + Full support added by Ian Lance Taylor, ian@cygnus.com. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include "aout/stab_gnu.h" + +/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines + some other stuff which we don't want and which conflicts with stuff + we do want. */ +#include "libaout.h" +#include "aout/aout64.h" +#undef N_ABS +#undef exec_hdr +#undef obj_sym_filepos + +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "libcoff.h" +#include "libecoff.h" + +/* Prototypes for static functions. */ + +static int ecoff_get_magic PARAMS ((bfd *abfd)); +static long ecoff_sec_to_styp_flags PARAMS ((const char *name, + flagword flags)); +static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd)); +static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym, + asymbol *asym, int ext, int weak)); +static void ecoff_emit_aggregate PARAMS ((bfd *abfd, FDR *fdr, + char *string, + RNDXR *rndx, long isym, + const char *which)); +static char *ecoff_type_to_string PARAMS ((bfd *abfd, FDR *fdr, + unsigned int indx)); +static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section, + asymbol **symbols)); +static int ecoff_sort_hdrs PARAMS ((const PTR, const PTR)); +static boolean ecoff_compute_section_file_positions PARAMS ((bfd *abfd)); +static bfd_size_type ecoff_compute_reloc_file_positions PARAMS ((bfd *abfd)); +static boolean ecoff_get_extr PARAMS ((asymbol *, EXTR *)); +static void ecoff_set_index PARAMS ((asymbol *, bfd_size_type)); +static unsigned int ecoff_armap_hash PARAMS ((CONST char *s, + unsigned int *rehash, + unsigned int size, + unsigned int hlog)); + +/* This stuff is somewhat copied from coffcode.h. */ + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Create an ECOFF object. */ + +boolean +_bfd_ecoff_mkobject (abfd) + bfd *abfd; +{ + abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *) + bfd_zalloc (abfd, sizeof (ecoff_data_type))); + if (abfd->tdata.ecoff_obj_data == NULL) + return false; + + return true; +} + +/* This is a hook called by coff_real_object_p to create any backend + specific information. */ + +PTR +_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr) + bfd *abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr; + ecoff_data_type *ecoff; + + if (_bfd_ecoff_mkobject (abfd) == false) + return NULL; + + ecoff = ecoff_data (abfd); + ecoff->gp_size = 8; + ecoff->sym_filepos = internal_f->f_symptr; + + if (internal_a != (struct internal_aouthdr *) NULL) + { + int i; + + ecoff->text_start = internal_a->text_start; + ecoff->text_end = internal_a->text_start + internal_a->tsize; + ecoff->gp = internal_a->gp_value; + ecoff->gprmask = internal_a->gprmask; + for (i = 0; i < 4; i++) + ecoff->cprmask[i] = internal_a->cprmask[i]; + ecoff->fprmask = internal_a->fprmask; + if (internal_a->magic == ECOFF_AOUT_ZMAGIC) + abfd->flags |= D_PAGED; + else + abfd->flags &=~ D_PAGED; + } + + /* It turns out that no special action is required by the MIPS or + Alpha ECOFF backends. They have different information in the + a.out header, but we just copy it all (e.g., gprmask, cprmask and + fprmask) and let the swapping routines ensure that only relevant + information is written out. */ + + return (PTR) ecoff; +} + +/* Initialize a new section. */ + +boolean +_bfd_ecoff_new_section_hook (abfd, section) + bfd *abfd; + asection *section; +{ + /* For the .pdata section, which has a special meaning on the Alpha, + we set the alignment power to 3. We correct this later in + ecoff_compute_section_file_positions. We do this hackery because + we need to know the exact unaligned size of the .pdata section in + order to set the lnnoptr field correctly. For every other + section we use an alignment power of 4; this could be made target + dependent by adding a field to ecoff_backend_data, but 4 appears + to be correct for both the MIPS and the Alpha. */ + if (strcmp (section->name, _PDATA) == 0) + section->alignment_power = 3; + else + section->alignment_power = 4; + + if (strcmp (section->name, _TEXT) == 0) + section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _DATA) == 0 + || strcmp (section->name, _SDATA) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _RDATA) == 0 + || strcmp (section->name, _LIT8) == 0 + || strcmp (section->name, _LIT4) == 0 + || strcmp (section->name, _RCONST) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + else if (strcmp (section->name, _BSS) == 0 + || strcmp (section->name, _SBSS) == 0) + section->flags |= SEC_ALLOC; + else if (strcmp (section->name, _LIB) == 0) + { + /* An Irix 4 shared libary. */ + section->flags |= SEC_COFF_SHARED_LIBRARY; + } + + /* Probably any other section name is SEC_NEVER_LOAD, but I'm + uncertain about .init on some systems and I don't know how shared + libraries work. */ + + return true; +} + +/* Determine the machine architecture and type. This is called from + the generic COFF routines. It is the inverse of ecoff_get_magic, + below. This could be an ECOFF backend routine, with one version + for each target, but there aren't all that many ECOFF targets. */ + +boolean +_bfd_ecoff_set_arch_mach_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + enum bfd_architecture arch; + unsigned long mach; + + switch (internal_f->f_magic) + { + case MIPS_MAGIC_1: + case MIPS_MAGIC_LITTLE: + case MIPS_MAGIC_BIG: + arch = bfd_arch_mips; + mach = 3000; + break; + + case MIPS_MAGIC_LITTLE2: + case MIPS_MAGIC_BIG2: + /* MIPS ISA level 2: the r6000 */ + arch = bfd_arch_mips; + mach = 6000; + break; + + case MIPS_MAGIC_LITTLE3: + case MIPS_MAGIC_BIG3: + /* MIPS ISA level 3: the r4000 */ + arch = bfd_arch_mips; + mach = 4000; + break; + + case ALPHA_MAGIC: + arch = bfd_arch_alpha; + mach = 0; + break; + + default: + arch = bfd_arch_obscure; + mach = 0; + break; + } + + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* Get the magic number to use based on the architecture and machine. + This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */ + +static int +ecoff_get_magic (abfd) + bfd *abfd; +{ + int big, little; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_mips: + switch (bfd_get_mach (abfd)) + { + default: + case 0: + case 3000: + big = MIPS_MAGIC_BIG; + little = MIPS_MAGIC_LITTLE; + break; + + case 6000: + big = MIPS_MAGIC_BIG2; + little = MIPS_MAGIC_LITTLE2; + break; + + case 4000: + big = MIPS_MAGIC_BIG3; + little = MIPS_MAGIC_LITTLE3; + break; + } + + return bfd_big_endian (abfd) ? big : little; + + case bfd_arch_alpha: + return ALPHA_MAGIC; + + default: + abort (); + return 0; + } +} + +/* Get the section s_flags to use for a section. */ + +static long +ecoff_sec_to_styp_flags (name, flags) + const char *name; + flagword flags; +{ + long styp; + + styp = 0; + + if (strcmp (name, _TEXT) == 0) + styp = STYP_TEXT; + else if (strcmp (name, _DATA) == 0) + styp = STYP_DATA; + else if (strcmp (name, _SDATA) == 0) + styp = STYP_SDATA; + else if (strcmp (name, _RDATA) == 0) + styp = STYP_RDATA; + else if (strcmp (name, _LITA) == 0) + styp = STYP_LITA; + else if (strcmp (name, _LIT8) == 0) + styp = STYP_LIT8; + else if (strcmp (name, _LIT4) == 0) + styp = STYP_LIT4; + else if (strcmp (name, _BSS) == 0) + styp = STYP_BSS; + else if (strcmp (name, _SBSS) == 0) + styp = STYP_SBSS; + else if (strcmp (name, _INIT) == 0) + styp = STYP_ECOFF_INIT; + else if (strcmp (name, _FINI) == 0) + styp = STYP_ECOFF_FINI; + else if (strcmp (name, _PDATA) == 0) + styp = STYP_PDATA; + else if (strcmp (name, _XDATA) == 0) + styp = STYP_XDATA; + else if (strcmp (name, _LIB) == 0) + styp = STYP_ECOFF_LIB; + else if (strcmp (name, _GOT) == 0) + styp = STYP_GOT; + else if (strcmp (name, _HASH) == 0) + styp = STYP_HASH; + else if (strcmp (name, _DYNAMIC) == 0) + styp = STYP_DYNAMIC; + else if (strcmp (name, _LIBLIST) == 0) + styp = STYP_LIBLIST; + else if (strcmp (name, _RELDYN) == 0) + styp = STYP_RELDYN; + else if (strcmp (name, _CONFLIC) == 0) + styp = STYP_CONFLIC; + else if (strcmp (name, _DYNSTR) == 0) + styp = STYP_DYNSTR; + else if (strcmp (name, _DYNSYM) == 0) + styp = STYP_DYNSYM; + else if (strcmp (name, _COMMENT) == 0) + { + styp = STYP_COMMENT; + flags &=~ SEC_NEVER_LOAD; + } + else if (strcmp (name, _RCONST) == 0) + styp = STYP_RCONST; + else if (flags & SEC_CODE) + styp = STYP_TEXT; + else if (flags & SEC_DATA) + styp = STYP_DATA; + else if (flags & SEC_READONLY) + styp = STYP_RDATA; + else if (flags & SEC_LOAD) + styp = STYP_REG; + else + styp = STYP_BSS; + + if (flags & SEC_NEVER_LOAD) + styp |= STYP_NOLOAD; + + return styp; +} + +/* Get the BFD flags to use for a section. */ + +/*ARGSUSED*/ +flagword +_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name) + bfd *abfd; + PTR hdr; + const char *name; +{ + struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; + long styp_flags = internal_s->s_flags; + flagword sec_flags=0; + + if (styp_flags & STYP_NOLOAD) + sec_flags |= SEC_NEVER_LOAD; + + /* For 386 COFF, at least, an unloadable text or data section is + actually a shared library section. */ + if ((styp_flags & STYP_TEXT) + || (styp_flags & STYP_ECOFF_INIT) + || (styp_flags & STYP_ECOFF_FINI) + || (styp_flags & STYP_DYNAMIC) + || (styp_flags & STYP_LIBLIST) + || (styp_flags & STYP_RELDYN) + || styp_flags == STYP_CONFLIC + || (styp_flags & STYP_DYNSTR) + || (styp_flags & STYP_DYNSYM) + || (styp_flags & STYP_HASH)) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if ((styp_flags & STYP_DATA) + || (styp_flags & STYP_RDATA) + || (styp_flags & STYP_SDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_XDATA + || (styp_flags & STYP_GOT) + || styp_flags == STYP_RCONST) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + if ((styp_flags & STYP_RDATA) + || styp_flags == STYP_PDATA + || styp_flags == STYP_RCONST) + sec_flags |= SEC_READONLY; + } + else if ((styp_flags & STYP_BSS) + || (styp_flags & STYP_SBSS)) + { + sec_flags |= SEC_ALLOC; + } + else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT) + { + sec_flags |= SEC_NEVER_LOAD; + } + else if ((styp_flags & STYP_LITA) + || (styp_flags & STYP_LIT8) + || (styp_flags & STYP_LIT4)) + { + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + } + else if (styp_flags & STYP_ECOFF_LIB) + { + sec_flags |= SEC_COFF_SHARED_LIBRARY; + } + else + { + sec_flags |= SEC_ALLOC | SEC_LOAD; + } + + return sec_flags; +} + +/* Read in the symbolic header for an ECOFF object file. */ + +static boolean +ecoff_slurp_symbolic_header (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + bfd_size_type external_hdr_size; + PTR raw = NULL; + HDRR *internal_symhdr; + + /* See if we've already read it in. */ + if (ecoff_data (abfd)->debug_info.symbolic_header.magic == + backend->debug_swap.sym_magic) + return true; + + /* See whether there is a symbolic header. */ + if (ecoff_data (abfd)->sym_filepos == 0) + { + bfd_get_symcount (abfd) = 0; + return true; + } + + /* At this point bfd_get_symcount (abfd) holds the number of symbols + as read from the file header, but on ECOFF this is always the + size of the symbolic information header. It would be cleaner to + handle this when we first read the file in coffgen.c. */ + external_hdr_size = backend->debug_swap.external_hdr_size; + if (bfd_get_symcount (abfd) != external_hdr_size) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Read the symbolic information header. */ + raw = (PTR) bfd_malloc ((size_t) external_hdr_size); + if (raw == NULL) + goto error_return; + + if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1 + || (bfd_read (raw, external_hdr_size, 1, abfd) + != external_hdr_size)) + goto error_return; + internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + (*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr); + + if (internal_symhdr->magic != backend->debug_swap.sym_magic) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + /* Now we can get the correct number of symbols. */ + bfd_get_symcount (abfd) = (internal_symhdr->isymMax + + internal_symhdr->iextMax); + + if (raw != NULL) + free (raw); + return true; + error_return: + if (raw != NULL) + free (raw); + return false; +} + +/* Read in and swap the important symbolic information for an ECOFF + object file. This is called by gdb via the read_debug_info entry + point in the backend structure. */ + +/*ARGSUSED*/ +boolean +_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug) + bfd *abfd; + asection *ignore; + struct ecoff_debug_info *debug; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + HDRR *internal_symhdr; + bfd_size_type raw_base; + bfd_size_type raw_size; + PTR raw; + bfd_size_type external_fdr_size; + char *fraw_src; + char *fraw_end; + struct fdr *fdr_ptr; + bfd_size_type raw_end; + bfd_size_type cb_end; + + BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info); + + /* Check whether we've already gotten it, and whether there's any to + get. */ + if (ecoff_data (abfd)->raw_syments != (PTR) NULL) + return true; + if (ecoff_data (abfd)->sym_filepos == 0) + { + bfd_get_symcount (abfd) = 0; + return true; + } + + if (! ecoff_slurp_symbolic_header (abfd)) + return false; + + internal_symhdr = &debug->symbolic_header; + + /* Read all the symbolic information at once. */ + raw_base = (ecoff_data (abfd)->sym_filepos + + backend->debug_swap.external_hdr_size); + + /* Alpha ecoff makes the determination of raw_size difficult. It has + an undocumented debug data section between the symhdr and the first + documented section. And the ordering of the sections varies between + statically and dynamically linked executables. + If bfd supports SEEK_END someday, this code could be simplified. */ + + raw_end = 0; + +#define UPDATE_RAW_END(start, count, size) \ + cb_end = internal_symhdr->start + internal_symhdr->count * (size); \ + if (cb_end > raw_end) \ + raw_end = cb_end + + UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char)); + UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size); + UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size); + UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size); + UPDATE_RAW_END (cbOptOffset, ioptMax, backend->debug_swap.external_opt_size); + UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char)); + UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char)); + UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size); + UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size); + UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size); + +#undef UPDATE_RAW_END + + raw_size = raw_end - raw_base; + if (raw_size == 0) + { + ecoff_data (abfd)->sym_filepos = 0; + return true; + } + raw = (PTR) bfd_alloc (abfd, raw_size); + if (raw == NULL) + return false; + if (bfd_seek (abfd, + (ecoff_data (abfd)->sym_filepos + + backend->debug_swap.external_hdr_size), + SEEK_SET) != 0 + || bfd_read (raw, raw_size, 1, abfd) != raw_size) + { + bfd_release (abfd, raw); + return false; + } + + ecoff_data (abfd)->raw_syments = raw; + + /* Get pointers for the numeric offsets in the HDRR structure. */ +#define FIX(off1, off2, type) \ + if (internal_symhdr->off1 == 0) \ + debug->off2 = (type) NULL; \ + else \ + debug->off2 = (type) ((char *) raw \ + + (internal_symhdr->off1 \ + - raw_base)) + FIX (cbLineOffset, line, unsigned char *); + FIX (cbDnOffset, external_dnr, PTR); + FIX (cbPdOffset, external_pdr, PTR); + FIX (cbSymOffset, external_sym, PTR); + FIX (cbOptOffset, external_opt, PTR); + FIX (cbAuxOffset, external_aux, union aux_ext *); + FIX (cbSsOffset, ss, char *); + FIX (cbSsExtOffset, ssext, char *); + FIX (cbFdOffset, external_fdr, PTR); + FIX (cbRfdOffset, external_rfd, PTR); + FIX (cbExtOffset, external_ext, PTR); +#undef FIX + + /* I don't want to always swap all the data, because it will just + waste time and most programs will never look at it. The only + time the linker needs most of the debugging information swapped + is when linking big-endian and little-endian MIPS object files + together, which is not a common occurrence. + + We need to look at the fdr to deal with a lot of information in + the symbols, so we swap them here. */ + debug->fdr = (struct fdr *) bfd_alloc (abfd, + (internal_symhdr->ifdMax * + sizeof (struct fdr))); + if (debug->fdr == NULL) + return false; + external_fdr_size = backend->debug_swap.external_fdr_size; + fdr_ptr = debug->fdr; + fraw_src = (char *) debug->external_fdr; + fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size; + for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) + (*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + + return true; +} + +/* ECOFF symbol table routines. The ECOFF symbol table is described + in gcc/mips-tfile.c. */ + +/* ECOFF uses two common sections. One is the usual one, and the + other is for small objects. All the small objects are kept + together, and then referenced via the gp pointer, which yields + faster assembler code. This is what we use for the small common + section. */ +static asection ecoff_scom_section; +static asymbol ecoff_scom_symbol; +static asymbol *ecoff_scom_symbol_ptr; + +/* Create an empty symbol. */ + +asymbol * +_bfd_ecoff_make_empty_symbol (abfd) + bfd *abfd; +{ + ecoff_symbol_type *new; + + new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type)); + if (new == (ecoff_symbol_type *) NULL) + return (asymbol *) NULL; + memset ((PTR) new, 0, sizeof *new); + new->symbol.section = (asection *) NULL; + new->fdr = (FDR *) NULL; + new->local = false; + new->native = NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Set the BFD flags and section for an ECOFF symbol. */ + +static boolean +ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, weak) + bfd *abfd; + SYMR *ecoff_sym; + asymbol *asym; + int ext; + int weak; +{ + asym->the_bfd = abfd; + asym->value = ecoff_sym->value; + asym->section = &bfd_debug_section; + asym->udata.i = 0; + + /* Most symbol types are just for debugging. */ + switch (ecoff_sym->st) + { + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + break; + case stNil: + if (ECOFF_IS_STAB (ecoff_sym)) + { + asym->flags = BSF_DEBUGGING; + return true; + } + break; + default: + asym->flags = BSF_DEBUGGING; + return true; + } + + if (weak) + asym->flags = BSF_EXPORT | BSF_WEAK; + else if (ext) + asym->flags = BSF_EXPORT | BSF_GLOBAL; + else + { + asym->flags = BSF_LOCAL; + /* Normally, a local stProc symbol will have a corresponding + external symbol. We mark the local symbol as a debugging + symbol, in order to prevent nm from printing both out. + Similarly, we mark stLabel and stabs symbols as debugging + symbols. In both cases, we do want to set the value + correctly based on the symbol class. */ + if (ecoff_sym->st == stProc + || ecoff_sym->st == stLabel + || ECOFF_IS_STAB (ecoff_sym)) + asym->flags |= BSF_DEBUGGING; + } + switch (ecoff_sym->sc) + { + case scNil: + /* Used for compiler generated labels. Leave them in the + debugging section, and mark them as local. If BSF_DEBUGGING + is set, then nm does not display them for some reason. If no + flags are set then the linker whines about them. */ + asym->flags = BSF_LOCAL; + break; + case scText: + asym->section = bfd_make_section_old_way (abfd, ".text"); + asym->value -= asym->section->vma; + break; + case scData: + asym->section = bfd_make_section_old_way (abfd, ".data"); + asym->value -= asym->section->vma; + break; + case scBss: + asym->section = bfd_make_section_old_way (abfd, ".bss"); + asym->value -= asym->section->vma; + break; + case scRegister: + asym->flags = BSF_DEBUGGING; + break; + case scAbs: + asym->section = bfd_abs_section_ptr; + break; + case scUndefined: + asym->section = bfd_und_section_ptr; + asym->flags = 0; + asym->value = 0; + break; + case scCdbLocal: + case scBits: + case scCdbSystem: + case scRegImage: + case scInfo: + case scUserStruct: + asym->flags = BSF_DEBUGGING; + break; + case scSData: + asym->section = bfd_make_section_old_way (abfd, ".sdata"); + asym->value -= asym->section->vma; + break; + case scSBss: + asym->section = bfd_make_section_old_way (abfd, ".sbss"); + asym->value -= asym->section->vma; + break; + case scRData: + asym->section = bfd_make_section_old_way (abfd, ".rdata"); + asym->value -= asym->section->vma; + break; + case scVar: + asym->flags = BSF_DEBUGGING; + break; + case scCommon: + if (asym->value > ecoff_data (abfd)->gp_size) + { + asym->section = bfd_com_section_ptr; + asym->flags = 0; + break; + } + /* Fall through. */ + case scSCommon: + if (ecoff_scom_section.name == NULL) + { + /* Initialize the small common section. */ + ecoff_scom_section.name = SCOMMON; + ecoff_scom_section.flags = SEC_IS_COMMON; + ecoff_scom_section.output_section = &ecoff_scom_section; + ecoff_scom_section.symbol = &ecoff_scom_symbol; + ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; + ecoff_scom_symbol.name = SCOMMON; + ecoff_scom_symbol.flags = BSF_SECTION_SYM; + ecoff_scom_symbol.section = &ecoff_scom_section; + ecoff_scom_symbol_ptr = &ecoff_scom_symbol; + } + asym->section = &ecoff_scom_section; + asym->flags = 0; + break; + case scVarRegister: + case scVariant: + asym->flags = BSF_DEBUGGING; + break; + case scSUndefined: + asym->section = bfd_und_section_ptr; + asym->flags = 0; + asym->value = 0; + break; + case scInit: + asym->section = bfd_make_section_old_way (abfd, ".init"); + asym->value -= asym->section->vma; + break; + case scBasedVar: + case scXData: + case scPData: + asym->flags = BSF_DEBUGGING; + break; + case scFini: + asym->section = bfd_make_section_old_way (abfd, ".fini"); + asym->value -= asym->section->vma; + break; + case scRConst: + asym->section = bfd_make_section_old_way (abfd, ".rconst"); + asym->value -= asym->section->vma; + break; + default: + break; + } + + /* Look for special constructors symbols and make relocation entries + in a special construction section. These are produced by the + -fgnu-linker argument to g++. */ + if (ECOFF_IS_STAB (ecoff_sym)) + { + switch (ECOFF_UNMARK_STAB (ecoff_sym->index)) + { + default: + break; + + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + const char *name; + asection *section; + arelent_chain *reloc_chain; + unsigned int bitsize; + + /* Get a section with the same name as the symbol (usually + __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the + name ___CTOR_LIST (three underscores). We need + __CTOR_LIST (two underscores), since ECOFF doesn't use + a leading underscore. This should be handled by gcc, + but instead we do it here. Actually, this should all + be done differently anyhow. */ + name = bfd_asymbol_name (asym); + if (name[0] == '_' && name[1] == '_' && name[2] == '_') + { + ++name; + asym->name = name; + } + section = bfd_get_section_by_name (abfd, name); + if (section == (asection *) NULL) + { + char *copy; + + copy = (char *) bfd_alloc (abfd, strlen (name) + 1); + if (!copy) + return false; + strcpy (copy, name); + section = bfd_make_section (abfd, copy); + } + + /* Build a reloc pointing to this constructor. */ + reloc_chain = + (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + if (!reloc_chain) + return false; + reloc_chain->relent.sym_ptr_ptr = + bfd_get_section (asym)->symbol_ptr_ptr; + reloc_chain->relent.address = section->_raw_size; + reloc_chain->relent.addend = asym->value; + reloc_chain->relent.howto = + ecoff_backend (abfd)->constructor_reloc; + + /* Set up the constructor section to hold the reloc. */ + section->flags = SEC_CONSTRUCTOR; + ++section->reloc_count; + + /* Constructor sections must be rounded to a boundary + based on the bitsize. These are not real sections-- + they are handled specially by the linker--so the ECOFF + 16 byte alignment restriction does not apply. */ + bitsize = ecoff_backend (abfd)->constructor_bitsize; + section->alignment_power = 1; + while ((1 << section->alignment_power) < bitsize / 8) + ++section->alignment_power; + + reloc_chain->next = section->constructor_chain; + section->constructor_chain = reloc_chain; + section->_raw_size += bitsize / 8; + + /* Mark the symbol as a constructor. */ + asym->flags |= BSF_CONSTRUCTOR; + } + break; + } + } + return true; +} + +/* Read an ECOFF symbol table. */ + +boolean +_bfd_ecoff_slurp_symbol_table (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_size_type external_ext_size + = backend->debug_swap.external_ext_size; + const bfd_size_type external_sym_size + = backend->debug_swap.external_sym_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->debug_swap.swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->debug_swap.swap_sym_in; + bfd_size_type internal_size; + ecoff_symbol_type *internal; + ecoff_symbol_type *internal_ptr; + char *eraw_src; + char *eraw_end; + FDR *fdr_ptr; + FDR *fdr_end; + + /* If we've already read in the symbol table, do nothing. */ + if (ecoff_data (abfd)->canonical_symbols != NULL) + return true; + + /* Get the symbolic information. */ + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, + &ecoff_data (abfd)->debug_info)) + return false; + if (bfd_get_symcount (abfd) == 0) + return true; + + internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type); + internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size); + if (internal == NULL) + return false; + + internal_ptr = internal; + eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext; + eraw_end = (eraw_src + + (ecoff_data (abfd)->debug_info.symbolic_header.iextMax + * external_ext_size)); + for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++) + { + EXTR internal_esym; + + (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym); + internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext + + internal_esym.asym.iss); + if (!ecoff_set_symbol_info (abfd, &internal_esym.asym, + &internal_ptr->symbol, 1, + internal_esym.weakext)) + return false; + /* The alpha uses a negative ifd field for section symbols. */ + if (internal_esym.ifd >= 0) + internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr + + internal_esym.ifd); + else + internal_ptr->fdr = NULL; + internal_ptr->local = false; + internal_ptr->native = (PTR) eraw_src; + } + + /* The local symbols must be accessed via the fdr's, because the + string and aux indices are relative to the fdr information. */ + fdr_ptr = ecoff_data (abfd)->debug_info.fdr; + fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax; + for (; fdr_ptr < fdr_end; fdr_ptr++) + { + char *lraw_src; + char *lraw_end; + + lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym + + fdr_ptr->isymBase * external_sym_size); + lraw_end = lraw_src + fdr_ptr->csym * external_sym_size; + for (; + lraw_src < lraw_end; + lraw_src += external_sym_size, internal_ptr++) + { + SYMR internal_sym; + + (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym); + internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss + + fdr_ptr->issBase + + internal_sym.iss); + if (!ecoff_set_symbol_info (abfd, &internal_sym, + &internal_ptr->symbol, 0, 0)) + return false; + internal_ptr->fdr = fdr_ptr; + internal_ptr->local = true; + internal_ptr->native = (PTR) lraw_src; + } + } + + ecoff_data (abfd)->canonical_symbols = internal; + + return true; +} + +/* Return the amount of space needed for the canonical symbols. */ + +long +_bfd_ecoff_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, + &ecoff_data (abfd)->debug_info)) + return -1; + + if (bfd_get_symcount (abfd) == 0) + return 0; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *)); +} + +/* Get the canonical symbols. */ + +long +_bfd_ecoff_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter = 0; + ecoff_symbol_type *symbase; + ecoff_symbol_type **location = (ecoff_symbol_type **) alocation; + + if (_bfd_ecoff_slurp_symbol_table (abfd) == false) + return -1; + if (bfd_get_symcount (abfd) == 0) + return 0; + + symbase = ecoff_data (abfd)->canonical_symbols; + while (counter < bfd_get_symcount (abfd)) + { + *(location++) = symbase++; + counter++; + } + *location++ = (ecoff_symbol_type *) NULL; + return bfd_get_symcount (abfd); +} + +/* Turn ECOFF type information into a printable string. + ecoff_emit_aggregate and ecoff_type_to_string are from + gcc/mips-tdump.c, with swapping added and used_ptr removed. */ + +/* Write aggregate information to a string. */ + +static void +ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which) + bfd *abfd; + FDR *fdr; + char *string; + RNDXR *rndx; + long isym; + const char *which; +{ + const struct ecoff_debug_swap * const debug_swap = + &ecoff_backend (abfd)->debug_swap; + struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; + unsigned int ifd = rndx->rfd; + unsigned int indx = rndx->index; + const char *name; + + if (ifd == 0xfff) + ifd = isym; + + /* An ifd of -1 is an opaque type. An escaped index of 0 is a + struct return type of a procedure compiled without -g. */ + if (ifd == 0xffffffff + || (rndx->rfd == 0xfff && indx == 0)) + name = ""; + else if (indx == indexNil) + name = ""; + else + { + SYMR sym; + + if (debug_info->external_rfd == NULL) + fdr = debug_info->fdr + ifd; + else + { + RFDT rfd; + + (*debug_swap->swap_rfd_in) (abfd, + ((char *) debug_info->external_rfd + + ((fdr->rfdBase + ifd) + * debug_swap->external_rfd_size)), + &rfd); + fdr = debug_info->fdr + rfd; + } + + indx += fdr->isymBase; + + (*debug_swap->swap_sym_in) (abfd, + ((char *) debug_info->external_sym + + indx * debug_swap->external_sym_size), + &sym); + + name = debug_info->ss + fdr->issBase + sym.iss; + } + + sprintf (string, + "%s %s { ifd = %u, index = %lu }", + which, name, ifd, + ((long) indx + + debug_info->symbolic_header.iextMax)); +} + +/* Convert the type information to string format. */ + +static char * +ecoff_type_to_string (abfd, fdr, indx) + bfd *abfd; + FDR *fdr; + unsigned int indx; +{ + union aux_ext *aux_ptr; + int bigendian; + AUXU u; + struct qual { + unsigned int type; + int low_bound; + int high_bound; + int stride; + } qualifiers[7]; + unsigned int basic_type; + int i; + char buffer1[1024]; + static char buffer2[1024]; + char *p1 = buffer1; + char *p2 = buffer2; + RNDXR rndx; + + aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase; + bigendian = fdr->fBigendian; + + for (i = 0; i < 7; i++) + { + qualifiers[i].low_bound = 0; + qualifiers[i].high_bound = 0; + qualifiers[i].stride = 0; + } + + if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == (bfd_vma) -1) + return "-1 (no type)"; + _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); + + basic_type = u.ti.bt; + qualifiers[0].type = u.ti.tq0; + qualifiers[1].type = u.ti.tq1; + qualifiers[2].type = u.ti.tq2; + qualifiers[3].type = u.ti.tq3; + qualifiers[4].type = u.ti.tq4; + qualifiers[5].type = u.ti.tq5; + qualifiers[6].type = tqNil; + + /* + * Go get the basic type. + */ + switch (basic_type) + { + case btNil: /* undefined */ + strcpy (p1, "nil"); + break; + + case btAdr: /* address - integer same size as pointer */ + strcpy (p1, "address"); + break; + + case btChar: /* character */ + strcpy (p1, "char"); + break; + + case btUChar: /* unsigned character */ + strcpy (p1, "unsigned char"); + break; + + case btShort: /* short */ + strcpy (p1, "short"); + break; + + case btUShort: /* unsigned short */ + strcpy (p1, "unsigned short"); + break; + + case btInt: /* int */ + strcpy (p1, "int"); + break; + + case btUInt: /* unsigned int */ + strcpy (p1, "unsigned int"); + break; + + case btLong: /* long */ + strcpy (p1, "long"); + break; + + case btULong: /* unsigned long */ + strcpy (p1, "unsigned long"); + break; + + case btFloat: /* float (real) */ + strcpy (p1, "float"); + break; + + case btDouble: /* Double (real) */ + strcpy (p1, "double"); + break; + + /* Structures add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to struct def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btStruct: /* Structure (Record) */ + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "struct"); + indx++; /* skip aux words */ + break; + + /* Unions add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to union def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btUnion: /* Union */ + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "union"); + indx++; /* skip aux words */ + break; + + /* Enumerations add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to enum def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btEnum: /* Enumeration */ + _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, fdr, p1, &rndx, + (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "enum"); + indx++; /* skip aux words */ + break; + + case btTypedef: /* defined via a typedef, isymRef points */ + strcpy (p1, "typedef"); + break; + + case btRange: /* subrange of int */ + strcpy (p1, "subrange"); + break; + + case btSet: /* pascal sets */ + strcpy (p1, "set"); + break; + + case btComplex: /* fortran complex */ + strcpy (p1, "complex"); + break; + + case btDComplex: /* fortran double complex */ + strcpy (p1, "double complex"); + break; + + case btIndirect: /* forward or unnamed typedef */ + strcpy (p1, "forward/unamed typedef"); + break; + + case btFixedDec: /* Fixed Decimal */ + strcpy (p1, "fixed decimal"); + break; + + case btFloatDec: /* Float Decimal */ + strcpy (p1, "float decimal"); + break; + + case btString: /* Varying Length Character String */ + strcpy (p1, "string"); + break; + + case btBit: /* Aligned Bit String */ + strcpy (p1, "bit"); + break; + + case btPicture: /* Picture */ + strcpy (p1, "picture"); + break; + + case btVoid: /* Void */ + strcpy (p1, "void"); + break; + + default: + sprintf (p1, "Unknown basic type %d", (int) basic_type); + break; + } + + p1 += strlen (buffer1); + + /* + * If this is a bitfield, get the bitsize. + */ + if (u.ti.fBitfield) + { + int bitsize; + + bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]); + sprintf (p1, " : %d", bitsize); + p1 += strlen (buffer1); + } + + + /* + * Deal with any qualifiers. + */ + if (qualifiers[0].type != tqNil) + { + /* + * Snarf up any array bounds in the correct order. Arrays + * store 5 successive words in the aux. table: + * word 0 RNDXR to type of the bounds (ie, int) + * word 1 Current file descriptor index + * word 2 low bound + * word 3 high bound (or -1 if []) + * word 4 stride size in bits + */ + for (i = 0; i < 7; i++) + { + if (qualifiers[i].type == tqArray) + { + qualifiers[i].low_bound = + AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]); + qualifiers[i].high_bound = + AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]); + qualifiers[i].stride = + AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]); + indx += 5; + } + } + + /* + * Now print out the qualifiers. + */ + for (i = 0; i < 6; i++) + { + switch (qualifiers[i].type) + { + case tqNil: + case tqMax: + break; + + case tqPtr: + strcpy (p2, "ptr to "); + p2 += sizeof ("ptr to ")-1; + break; + + case tqVol: + strcpy (p2, "volatile "); + p2 += sizeof ("volatile ")-1; + break; + + case tqFar: + strcpy (p2, "far "); + p2 += sizeof ("far ")-1; + break; + + case tqProc: + strcpy (p2, "func. ret. "); + p2 += sizeof ("func. ret. "); + break; + + case tqArray: + { + int first_array = i; + int j; + + /* Print array bounds reversed (ie, in the order the C + programmer writes them). C is such a fun language.... */ + + while (i < 5 && qualifiers[i+1].type == tqArray) + i++; + + for (j = i; j >= first_array; j--) + { + strcpy (p2, "array ["); + p2 += sizeof ("array [")-1; + if (qualifiers[j].low_bound != 0) + sprintf (p2, + "%ld:%ld {%ld bits}", + (long) qualifiers[j].low_bound, + (long) qualifiers[j].high_bound, + (long) qualifiers[j].stride); + + else if (qualifiers[j].high_bound != -1) + sprintf (p2, + "%ld {%ld bits}", + (long) (qualifiers[j].high_bound + 1), + (long) (qualifiers[j].stride)); + + else + sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); + + p2 += strlen (p2); + strcpy (p2, "] of "); + p2 += sizeof ("] of ")-1; + } + } + break; + } + } + } + + strcpy (p2, buffer1); + return buffer2; +} + +/* Return information about ECOFF symbol SYMBOL in RET. */ + +/*ARGSUSED*/ +void +_bfd_ecoff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; /* Ignored. */ + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Return whether this is a local label. */ + +/*ARGSUSED*/ +boolean +_bfd_ecoff_bfd_is_local_label (abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ + return symbol->name[0] == '$'; +} + +/* Print information about an ECOFF symbol. */ + +void +_bfd_ecoff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (abfd)->debug_swap; + FILE *file = (FILE *)filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + if (ecoffsymbol (symbol)->local) + { + SYMR ecoff_sym; + + (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_sym); + fprintf (file, "ecoff local "); + fprintf_vma (file, (bfd_vma) ecoff_sym.value); + fprintf (file, " %x %x", (unsigned) ecoff_sym.st, + (unsigned) ecoff_sym.sc); + } + else + { + EXTR ecoff_ext; + + (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + fprintf (file, "ecoff extern "); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc); + } + break; + case bfd_print_symbol_all: + /* Print out the symbols in a reasonable way */ + { + char type; + int pos; + EXTR ecoff_ext; + char jmptbl; + char cobol_main; + char weakext; + + if (ecoffsymbol (symbol)->local) + { + (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext.asym); + type = 'l'; + pos = ((((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->debug_info.external_sym) + / debug_swap->external_sym_size) + + ecoff_data (abfd)->debug_info.symbolic_header.iextMax); + jmptbl = ' '; + cobol_main = ' '; + weakext = ' '; + } + else + { + (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + type = 'e'; + pos = (((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->debug_info.external_ext) + / debug_swap->external_ext_size); + jmptbl = ecoff_ext.jmptbl ? 'j' : ' '; + cobol_main = ecoff_ext.cobol_main ? 'c' : ' '; + weakext = ecoff_ext.weakext ? 'w' : ' '; + } + + fprintf (file, "[%3d] %c ", + pos, type); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " st %x sc %x indx %x %c%c%c %s", + (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc, + (unsigned) ecoff_ext.asym.index, + jmptbl, cobol_main, weakext, + symbol->name); + + if (ecoffsymbol (symbol)->fdr != NULL + && ecoff_ext.asym.index != indexNil) + { + FDR *fdr; + unsigned int indx; + int bigendian; + bfd_size_type sym_base; + union aux_ext *aux_base; + + fdr = ecoffsymbol (symbol)->fdr; + indx = ecoff_ext.asym.index; + + /* sym_base is used to map the fdr relative indices which + appear in the file to the position number which we are + using. */ + sym_base = fdr->isymBase; + if (ecoffsymbol (symbol)->local) + sym_base += + ecoff_data (abfd)->debug_info.symbolic_header.iextMax; + + /* aux_base is the start of the aux entries for this file; + asym.index is an offset from this. */ + aux_base = (ecoff_data (abfd)->debug_info.external_aux + + fdr->iauxBase); + + /* The aux entries are stored in host byte order; the + order is indicated by a bit in the fdr. */ + bigendian = fdr->fBigendian; + + /* This switch is basically from gcc/mips-tdump.c */ + switch (ecoff_ext.asym.st) + { + case stNil: + case stLabel: + break; + + case stFile: + case stBlock: + fprintf (file, "\n End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + case stEnd: + if (ecoff_ext.asym.sc == scText + || ecoff_ext.asym.sc == scInfo) + fprintf (file, "\n First symbol: %ld", + (long) (indx + sym_base)); + else + fprintf (file, "\n First symbol: %ld", + ((long) + (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base))); + break; + + case stProc: + case stStaticProc: + if (ECOFF_IS_STAB (&ecoff_ext.asym)) + ; + else if (ecoffsymbol (symbol)->local) + fprintf (file, "\n End+1 symbol: %-7ld Type: %s", + ((long) + (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base)), + ecoff_type_to_string (abfd, fdr, indx + 1)); + else + fprintf (file, "\n Local symbol: %ld", + ((long) indx + + (long) sym_base + + (ecoff_data (abfd) + ->debug_info.symbolic_header.iextMax))); + break; + + case stStruct: + fprintf (file, "\n struct; End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + case stUnion: + fprintf (file, "\n union; End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + case stEnum: + fprintf (file, "\n enum; End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + default: + if (! ECOFF_IS_STAB (&ecoff_ext.asym)) + fprintf (file, "\n Type: %s", + ecoff_type_to_string (abfd, fdr, indx)); + break; + } + } + } + break; + } +} + +/* Read in the relocs for a section. */ + +static boolean +ecoff_slurp_reloc_table (abfd, section, symbols) + bfd *abfd; + asection *section; + asymbol **symbols; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + arelent *internal_relocs; + bfd_size_type external_reloc_size; + bfd_size_type external_relocs_size; + char *external_relocs; + arelent *rptr; + unsigned int i; + + if (section->relocation != (arelent *) NULL + || section->reloc_count == 0 + || (section->flags & SEC_CONSTRUCTOR) != 0) + return true; + + if (_bfd_ecoff_slurp_symbol_table (abfd) == false) + return false; + + internal_relocs = (arelent *) bfd_alloc (abfd, + (sizeof (arelent) + * section->reloc_count)); + external_reloc_size = backend->external_reloc_size; + external_relocs_size = external_reloc_size * section->reloc_count; + external_relocs = (char *) bfd_alloc (abfd, external_relocs_size); + if (internal_relocs == (arelent *) NULL + || external_relocs == (char *) NULL) + return false; + if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0) + return false; + if (bfd_read (external_relocs, 1, external_relocs_size, abfd) + != external_relocs_size) + return false; + + for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++) + { + struct internal_reloc intern; + + (*backend->swap_reloc_in) (abfd, + external_relocs + i * external_reloc_size, + &intern); + + if (intern.r_extern) + { + /* r_symndx is an index into the external symbols. */ + BFD_ASSERT (intern.r_symndx >= 0 + && (intern.r_symndx + < (ecoff_data (abfd) + ->debug_info.symbolic_header.iextMax))); + rptr->sym_ptr_ptr = symbols + intern.r_symndx; + rptr->addend = 0; + } + else if (intern.r_symndx == RELOC_SECTION_NONE + || intern.r_symndx == RELOC_SECTION_ABS) + { + rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + rptr->addend = 0; + } + else + { + CONST char *sec_name; + asection *sec; + + /* r_symndx is a section key. */ + switch (intern.r_symndx) + { + case RELOC_SECTION_TEXT: sec_name = ".text"; break; + case RELOC_SECTION_RDATA: sec_name = ".rdata"; break; + case RELOC_SECTION_DATA: sec_name = ".data"; break; + case RELOC_SECTION_SDATA: sec_name = ".sdata"; break; + case RELOC_SECTION_SBSS: sec_name = ".sbss"; break; + case RELOC_SECTION_BSS: sec_name = ".bss"; break; + case RELOC_SECTION_INIT: sec_name = ".init"; break; + case RELOC_SECTION_LIT8: sec_name = ".lit8"; break; + case RELOC_SECTION_LIT4: sec_name = ".lit4"; break; + case RELOC_SECTION_XDATA: sec_name = ".xdata"; break; + case RELOC_SECTION_PDATA: sec_name = ".pdata"; break; + case RELOC_SECTION_FINI: sec_name = ".fini"; break; + case RELOC_SECTION_LITA: sec_name = ".lita"; break; + case RELOC_SECTION_RCONST: sec_name = ".rconst"; break; + default: abort (); + } + + sec = bfd_get_section_by_name (abfd, sec_name); + if (sec == (asection *) NULL) + abort (); + rptr->sym_ptr_ptr = sec->symbol_ptr_ptr; + + rptr->addend = - bfd_get_section_vma (abfd, sec); + } + + rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section); + + /* Let the backend select the howto field and do any other + required processing. */ + (*backend->adjust_reloc_in) (abfd, &intern, rptr); + } + + bfd_release (abfd, external_relocs); + + section->relocation = internal_relocs; + + return true; +} + +/* Get a canonical list of relocs. */ + +long +_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + asection *section; + arelent **relptr; + asymbol **symbols; +{ + unsigned int count; + + if (section->flags & SEC_CONSTRUCTOR) + { + arelent_chain *chain; + + /* This section has relocs made up by us, not the file, so take + them out of their chain and place them into the data area + provided. */ + for (count = 0, chain = section->constructor_chain; + count < section->reloc_count; + count++, chain = chain->next) + *relptr++ = &chain->relent; + } + else + { + arelent *tblptr; + + if (ecoff_slurp_reloc_table (abfd, section, symbols) == false) + return -1; + + tblptr = section->relocation; + + for (count = 0; count < section->reloc_count; count++) + *relptr++ = tblptr++; + } + + *relptr = (arelent *) NULL; + + return section->reloc_count; +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +/*ARGSUSED*/ +boolean +_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset, + filename_ptr, functionname_ptr, retline_ptr) + bfd *abfd; + asection *section; + asymbol **ignore_symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *retline_ptr; +{ + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (abfd)->debug_swap; + struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; + struct ecoff_find_line *line_info; + + /* Make sure we have the FDR's. */ + if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info) + || bfd_get_symcount (abfd) == 0) + return false; + + if (ecoff_data (abfd)->find_line_info == NULL) + { + ecoff_data (abfd)->find_line_info = + ((struct ecoff_find_line *) + bfd_alloc (abfd, sizeof (struct ecoff_find_line))); + if (ecoff_data (abfd)->find_line_info == NULL) + return false; + ecoff_data (abfd)->find_line_info->find_buffer = NULL; + ecoff_data (abfd)->find_line_info->fdrtab_len = 0; + ecoff_data (abfd)->find_line_info->fdrtab = NULL; + } + line_info = ecoff_data (abfd)->find_line_info; + + return _bfd_ecoff_locate_line (abfd, section, offset, debug_info, + debug_swap, line_info, filename_ptr, + functionname_ptr, retline_ptr); +} + +/* Copy private BFD data. This is called by objcopy and strip. We + use it to copy the ECOFF debugging information from one BFD to the + other. It would be theoretically possible to represent the ECOFF + debugging information in the symbol table. However, it would be a + lot of work, and there would be little gain (gas, gdb, and ld + already access the ECOFF debugging information via the + ecoff_debug_info structure, and that structure would have to be + retained in order to support ECOFF debugging in MIPS ELF). + + The debugging information for the ECOFF external symbols comes from + the symbol table, so this function only handles the other debugging + information. */ + +boolean +_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info; + struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info; + register int i; + asymbol **sym_ptr_ptr; + size_t c; + boolean local; + + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses ECOFF + format. */ + if (bfd_get_flavour (obfd) != bfd_target_ecoff_flavour) + return true; + + /* Copy the GP value and the register masks. */ + ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp; + ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask; + ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask; + for (i = 0; i < 3; i++) + ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i]; + + /* Copy the version stamp. */ + oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp; + + /* If there are no symbols, don't copy any debugging information. */ + c = bfd_get_symcount (obfd); + sym_ptr_ptr = bfd_get_outsymbols (obfd); + if (c == 0 || sym_ptr_ptr == (asymbol **) NULL) + return true; + + /* See if there are any local symbols. */ + local = false; + for (; c > 0; c--, sym_ptr_ptr++) + { + if (ecoffsymbol (*sym_ptr_ptr)->local) + { + local = true; + break; + } + } + + if (local) + { + /* There are some local symbols. We just bring over all the + debugging information. FIXME: This is not quite the right + thing to do. If the user has asked us to discard all + debugging information, then we are probably going to wind up + keeping it because there will probably be some local symbol + which objcopy did not discard. We should actually break + apart the debugging information and only keep that which + applies to the symbols we want to keep. */ + oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax; + oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine; + oinfo->line = iinfo->line; + + oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax; + oinfo->external_dnr = iinfo->external_dnr; + + oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax; + oinfo->external_pdr = iinfo->external_pdr; + + oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax; + oinfo->external_sym = iinfo->external_sym; + + oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax; + oinfo->external_opt = iinfo->external_opt; + + oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax; + oinfo->external_aux = iinfo->external_aux; + + oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax; + oinfo->ss = iinfo->ss; + + oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax; + oinfo->external_fdr = iinfo->external_fdr; + + oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd; + oinfo->external_rfd = iinfo->external_rfd; + } + else + { + /* We are discarding all the local symbol information. Look + through the external symbols and remove all references to FDR + or aux information. */ + c = bfd_get_symcount (obfd); + sym_ptr_ptr = bfd_get_outsymbols (obfd); + for (; c > 0; c--, sym_ptr_ptr++) + { + EXTR esym; + + (*(ecoff_backend (obfd)->debug_swap.swap_ext_in)) + (obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym); + esym.ifd = ifdNil; + esym.asym.index = indexNil; + (*(ecoff_backend (obfd)->debug_swap.swap_ext_out)) + (obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native); + } + } + + return true; +} + +/* Set the architecture. The supported architecture is stored in the + backend pointer. We always set the architecture anyhow, since many + callers ignore the return value. */ + +boolean +_bfd_ecoff_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach (abfd, arch, machine); + return arch == ecoff_backend (abfd)->arch; +} + +/* Get the size of the section headers. */ + +/*ARGSUSED*/ +int +_bfd_ecoff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + asection *current; + int c; + int ret; + + c = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + ++c; + + ret = (bfd_coff_filhsz (abfd) + + bfd_coff_aoutsz (abfd) + + c * bfd_coff_scnhsz (abfd)); + return BFD_ALIGN (ret, 16); +} + +/* Get the contents of a section. */ + +boolean +_bfd_ecoff_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + return _bfd_generic_get_section_contents (abfd, section, location, + offset, count); +} + +/* Sort sections by VMA, but put SEC_ALLOC sections first. This is + called via qsort. */ + +static int +ecoff_sort_hdrs (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + const asection *hdr1 = *(const asection **) arg1; + const asection *hdr2 = *(const asection **) arg2; + + if ((hdr1->flags & SEC_ALLOC) != 0) + { + if ((hdr2->flags & SEC_ALLOC) == 0) + return -1; + } + else + { + if ((hdr2->flags & SEC_ALLOC) != 0) + return 1; + } + if (hdr1->vma < hdr2->vma) + return -1; + else if (hdr1->vma > hdr2->vma) + return 1; + else + return 0; +} + +/* Calculate the file position for each section, and set + reloc_filepos. */ + +static boolean +ecoff_compute_section_file_positions (abfd) + bfd *abfd; +{ + file_ptr sofar; + asection **sorted_hdrs; + asection *current; + unsigned int i; + file_ptr old_sofar; + boolean first_data, first_nonalloc; + const bfd_vma round = ecoff_backend (abfd)->round; + + sofar = _bfd_ecoff_sizeof_headers (abfd, false); + + /* Sort the sections by VMA. */ + sorted_hdrs = (asection **) bfd_malloc (abfd->section_count + * sizeof (asection *)); + if (sorted_hdrs == NULL) + return false; + for (current = abfd->sections, i = 0; + current != NULL; + current = current->next, i++) + sorted_hdrs[i] = current; + BFD_ASSERT (i == abfd->section_count); + + qsort (sorted_hdrs, abfd->section_count, sizeof (asection *), + ecoff_sort_hdrs); + + first_data = true; + first_nonalloc = true; + for (i = 0; i < abfd->section_count; i++) + { + unsigned int alignment_power; + + current = sorted_hdrs[i]; + + /* For the Alpha ECOFF .pdata section the lnnoptr field is + supposed to indicate the number of .pdata entries that are + really in the section. Each entry is 8 bytes. We store this + away in line_filepos before increasing the section size. */ + if (strcmp (current->name, _PDATA) != 0) + alignment_power = current->alignment_power; + else + { + current->line_filepos = current->_raw_size / 8; + alignment_power = 4; + } + + /* On Ultrix, the data sections in an executable file must be + aligned to a page boundary within the file. This does not + affect the section size, though. FIXME: Does this work for + other platforms? It requires some modification for the + Alpha, because .rdata on the Alpha goes with the text, not + the data. */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0 + && ! first_data + && (current->flags & SEC_CODE) == 0 + && (! ecoff_backend (abfd)->rdata_in_text + || strcmp (current->name, _RDATA) != 0) + && strcmp (current->name, _PDATA) != 0 + && strcmp (current->name, _RCONST) != 0) + { + sofar = (sofar + round - 1) &~ (round - 1); + first_data = false; + } + else if (strcmp (current->name, _LIB) == 0) + { + /* On Irix 4, the location of contents of the .lib section + from a shared library section is also rounded up to a + page boundary. */ + + sofar = (sofar + round - 1) &~ (round - 1); + } + else if (first_nonalloc + && (current->flags & SEC_ALLOC) == 0 + && (abfd->flags & D_PAGED) != 0) + { + /* Skip up to the next page for an unallocated section, such + as the .comment section on the Alpha. This leaves room + for the .bss section. */ + first_nonalloc = false; + sofar = (sofar + round - 1) &~ (round - 1); + } + + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << alignment_power); + + if ((abfd->flags & D_PAGED) != 0 + && (current->flags & SEC_ALLOC) != 0) + sofar += (current->vma - sofar) % round; + + if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) != 0) + current->filepos = sofar; + + sofar += current->_raw_size; + + /* make sure that this section is of the right size too */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << alignment_power); + current->_raw_size += sofar - old_sofar; + } + + free (sorted_hdrs); + sorted_hdrs = NULL; + + ecoff_data (abfd)->reloc_filepos = sofar; + + return true; +} + +/* Determine the location of the relocs for all the sections in the + output file, as well as the location of the symbolic debugging + information. */ + +static bfd_size_type +ecoff_compute_reloc_file_positions (abfd) + bfd *abfd; +{ + const bfd_size_type external_reloc_size = + ecoff_backend (abfd)->external_reloc_size; + file_ptr reloc_base; + bfd_size_type reloc_size; + asection *current; + file_ptr sym_base; + + if (! abfd->output_has_begun) + { + if (! ecoff_compute_section_file_positions (abfd)) + abort (); + abfd->output_has_begun = true; + } + + reloc_base = ecoff_data (abfd)->reloc_filepos; + + reloc_size = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + { + if (current->reloc_count == 0) + current->rel_filepos = 0; + else + { + bfd_size_type relsize; + + current->rel_filepos = reloc_base; + relsize = current->reloc_count * external_reloc_size; + reloc_size += relsize; + reloc_base += relsize; + } + } + + sym_base = ecoff_data (abfd)->reloc_filepos + reloc_size; + + /* At least on Ultrix, the symbol table of an executable file must + be aligned to a page boundary. FIXME: Is this true on other + platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + sym_base = ((sym_base + ecoff_backend (abfd)->round - 1) + &~ (ecoff_backend (abfd)->round - 1)); + + ecoff_data (abfd)->sym_filepos = sym_base; + + return reloc_size; +} + +/* Set the contents of a section. */ + +boolean +_bfd_ecoff_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + /* This must be done first, because bfd_set_section_contents is + going to set output_has_begun to true. */ + if (abfd->output_has_begun == false) + { + if (! ecoff_compute_section_file_positions (abfd)) + return false; + } + + /* If this is a .lib section, bump the vma address so that it winds + up being the number of .lib sections output. This is right for + Irix 4. Ian Taylor . */ + if (strcmp (section->name, _LIB) == 0) + ++section->vma; + + if (count == 0) + return true; + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0 + || bfd_write (location, 1, count, abfd) != count) + return false; + + return true; +} + +/* Get the GP value for an ECOFF file. This is a hook used by + nlmconv. */ + +bfd_vma +bfd_ecoff_get_gp_value (abfd) + bfd *abfd; +{ + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + + return ecoff_data (abfd)->gp; +} + +/* Set the GP value for an ECOFF file. This is a hook used by the + assembler. */ + +boolean +bfd_ecoff_set_gp_value (abfd, gp_value) + bfd *abfd; + bfd_vma gp_value; +{ + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + ecoff_data (abfd)->gp = gp_value; + + return true; +} + +/* Set the register masks for an ECOFF file. This is a hook used by + the assembler. */ + +boolean +bfd_ecoff_set_regmasks (abfd, gprmask, fprmask, cprmask) + bfd *abfd; + unsigned long gprmask; + unsigned long fprmask; + unsigned long *cprmask; +{ + ecoff_data_type *tdata; + + if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour + || bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + tdata = ecoff_data (abfd); + tdata->gprmask = gprmask; + tdata->fprmask = fprmask; + if (cprmask != (unsigned long *) NULL) + { + register int i; + + for (i = 0; i < 3; i++) + tdata->cprmask[i] = cprmask[i]; + } + + return true; +} + +/* Get ECOFF EXTR information for an external symbol. This function + is passed to bfd_ecoff_debug_externals. */ + +static boolean +ecoff_get_extr (sym, esym) + asymbol *sym; + EXTR *esym; +{ + ecoff_symbol_type *ecoff_sym_ptr; + bfd *input_bfd; + + if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour + || ecoffsymbol (sym)->native == NULL) + { + /* Don't include debugging, local, or section symbols. */ + if ((sym->flags & BSF_DEBUGGING) != 0 + || (sym->flags & BSF_LOCAL) != 0 + || (sym->flags & BSF_SECTION_SYM) != 0) + return false; + + esym->jmptbl = 0; + esym->cobol_main = 0; + esym->weakext = (sym->flags & BSF_WEAK) != 0; + esym->reserved = 0; + esym->ifd = ifdNil; + /* FIXME: we can do better than this for st and sc. */ + esym->asym.st = stGlobal; + esym->asym.sc = scAbs; + esym->asym.reserved = 0; + esym->asym.index = indexNil; + return true; + } + + ecoff_sym_ptr = ecoffsymbol (sym); + + if (ecoff_sym_ptr->local) + return false; + + input_bfd = bfd_asymbol_bfd (sym); + (*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in)) + (input_bfd, ecoff_sym_ptr->native, esym); + + /* If the symbol was defined by the linker, then esym will be + undefined but sym will not be. Get a better class for such a + symbol. */ + if ((esym->asym.sc == scUndefined + || esym->asym.sc == scSUndefined) + && ! bfd_is_und_section (bfd_get_section (sym))) + esym->asym.sc = scAbs; + + /* Adjust the FDR index for the symbol by that used for the input + BFD. */ + if (esym->ifd != -1) + { + struct ecoff_debug_info *input_debug; + + input_debug = &ecoff_data (input_bfd)->debug_info; + BFD_ASSERT (esym->ifd < input_debug->symbolic_header.ifdMax); + if (input_debug->ifdmap != (RFDT *) NULL) + esym->ifd = input_debug->ifdmap[esym->ifd]; + } + + return true; +} + +/* Set the external symbol index. This routine is passed to + bfd_ecoff_debug_externals. */ + +static void +ecoff_set_index (sym, indx) + asymbol *sym; + bfd_size_type indx; +{ + ecoff_set_sym_index (sym, indx); +} + +/* Write out an ECOFF file. */ + +boolean +_bfd_ecoff_write_object_contents (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_vma round = backend->round; + const bfd_size_type filhsz = bfd_coff_filhsz (abfd); + const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd); + const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd); + const bfd_size_type external_hdr_size + = backend->debug_swap.external_hdr_size; + const bfd_size_type external_reloc_size = backend->external_reloc_size; + void (* const adjust_reloc_out) PARAMS ((bfd *, + const arelent *, + struct internal_reloc *)) + = backend->adjust_reloc_out; + void (* const swap_reloc_out) PARAMS ((bfd *, + const struct internal_reloc *, + PTR)) + = backend->swap_reloc_out; + struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; + HDRR * const symhdr = &debug->symbolic_header; + asection *current; + unsigned int count; + bfd_size_type reloc_size; + bfd_size_type text_size; + bfd_vma text_start; + boolean set_text_start; + bfd_size_type data_size; + bfd_vma data_start; + boolean set_data_start; + bfd_size_type bss_size; + PTR buff = NULL; + PTR reloc_buff = NULL; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + int i; + + /* Determine where the sections and relocs will go in the output + file. */ + reloc_size = ecoff_compute_reloc_file_positions (abfd); + + count = 1; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + { + current->target_index = count; + ++count; + } + + if ((abfd->flags & D_PAGED) != 0) + text_size = _bfd_ecoff_sizeof_headers (abfd, false); + else + text_size = 0; + text_start = 0; + set_text_start = false; + data_size = 0; + data_start = 0; + set_data_start = false; + bss_size = 0; + + /* Write section headers to the file. */ + + /* Allocate buff big enough to hold a section header, + file header, or a.out header. */ + { + bfd_size_type siz; + siz = scnhsz; + if (siz < filhsz) + siz = filhsz; + if (siz < aoutsz) + siz = aoutsz; + buff = (PTR) bfd_malloc ((size_t) siz); + if (buff == NULL) + goto error_return; + } + + internal_f.f_nscns = 0; + if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0) + goto error_return; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + struct internal_scnhdr section; + bfd_vma vma; + + ++internal_f.f_nscns; + + strncpy (section.s_name, current->name, sizeof section.s_name); + + /* This seems to be correct for Irix 4 shared libraries. */ + vma = bfd_get_section_vma (abfd, current); + if (strcmp (current->name, _LIB) == 0) + section.s_vaddr = 0; + else + section.s_vaddr = vma; + + section.s_paddr = current->lma; + section.s_size = bfd_get_section_size_before_reloc (current); + + /* If this section is unloadable then the scnptr will be 0. */ + if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + section.s_scnptr = 0; + else + section.s_scnptr = current->filepos; + section.s_relptr = current->rel_filepos; + + /* FIXME: the lnnoptr of the .sbss or .sdata section of an + object file produced by the assembler is supposed to point to + information about how much room is required by objects of + various different sizes. I think this only matters if we + want the linker to compute the best size to use, or + something. I don't know what happens if the information is + not present. */ + if (strcmp (current->name, _PDATA) != 0) + section.s_lnnoptr = 0; + else + { + /* The Alpha ECOFF .pdata section uses the lnnoptr field to + hold the number of entries in the section (each entry is + 8 bytes). We stored this in the line_filepos field in + ecoff_compute_section_file_positions. */ + section.s_lnnoptr = current->line_filepos; + } + + section.s_nreloc = current->reloc_count; + section.s_nlnno = 0; + section.s_flags = ecoff_sec_to_styp_flags (current->name, + current->flags); + + if (bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff) == 0 + || bfd_write (buff, 1, scnhsz, abfd) != scnhsz) + goto error_return; + + if ((section.s_flags & STYP_TEXT) != 0 + || ((section.s_flags & STYP_RDATA) != 0 + && backend->rdata_in_text) + || section.s_flags == STYP_PDATA + || (section.s_flags & STYP_DYNAMIC) != 0 + || (section.s_flags & STYP_LIBLIST) != 0 + || (section.s_flags & STYP_RELDYN) != 0 + || section.s_flags == STYP_CONFLIC + || (section.s_flags & STYP_DYNSTR) != 0 + || (section.s_flags & STYP_DYNSYM) != 0 + || (section.s_flags & STYP_HASH) != 0 + || (section.s_flags & STYP_ECOFF_INIT) != 0 + || (section.s_flags & STYP_ECOFF_FINI) != 0 + || section.s_flags == STYP_RCONST) + { + text_size += bfd_get_section_size_before_reloc (current); + if (! set_text_start || text_start > vma) + { + text_start = vma; + set_text_start = true; + } + } + else if ((section.s_flags & STYP_RDATA) != 0 + || (section.s_flags & STYP_DATA) != 0 + || (section.s_flags & STYP_LITA) != 0 + || (section.s_flags & STYP_LIT8) != 0 + || (section.s_flags & STYP_LIT4) != 0 + || (section.s_flags & STYP_SDATA) != 0 + || section.s_flags == STYP_XDATA + || (section.s_flags & STYP_GOT) != 0) + { + data_size += bfd_get_section_size_before_reloc (current); + if (! set_data_start || data_start > vma) + { + data_start = vma; + set_data_start = true; + } + } + else if ((section.s_flags & STYP_BSS) != 0 + || (section.s_flags & STYP_SBSS) != 0) + bss_size += bfd_get_section_size_before_reloc (current); + else if (section.s_flags == 0 + || (section.s_flags & STYP_ECOFF_LIB) != 0 + || section.s_flags == STYP_COMMENT) + /* Do nothing */ ; + else + abort (); + } + + /* Set up the file header. */ + + internal_f.f_magic = ecoff_get_magic (abfd); + + /* We will NOT put a fucking timestamp in the header here. Every + time you put it back, I will come in and take it out again. I'm + sorry. This field does not belong here. We fill it with a 0 so + it compares the same but is not a reasonable time. -- + gnu@cygnus.com. */ + internal_f.f_timdat = 0; + + if (bfd_get_symcount (abfd) != 0) + { + /* The ECOFF f_nsyms field is not actually the number of + symbols, it's the size of symbolic information header. */ + internal_f.f_nsyms = external_hdr_size; + internal_f.f_symptr = ecoff_data (abfd)->sym_filepos; + } + else + { + internal_f.f_nsyms = 0; + internal_f.f_symptr = 0; + } + + internal_f.f_opthdr = aoutsz; + + internal_f.f_flags = F_LNNO; + if (reloc_size == 0) + internal_f.f_flags |= F_RELFLG; + if (bfd_get_symcount (abfd) == 0) + internal_f.f_flags |= F_LSYMS; + if (abfd->flags & EXEC_P) + internal_f.f_flags |= F_EXEC; + + if (bfd_little_endian (abfd)) + internal_f.f_flags |= F_AR32WR; + else + internal_f.f_flags |= F_AR32W; + + /* Set up the ``optional'' header. */ + if ((abfd->flags & D_PAGED) != 0) + internal_a.magic = ECOFF_AOUT_ZMAGIC; + else + internal_a.magic = ECOFF_AOUT_OMAGIC; + + /* FIXME: Is this really correct? */ + internal_a.vstamp = symhdr->vstamp; + + /* At least on Ultrix, these have to be rounded to page boundaries. + FIXME: Is this true on other platforms? */ + if ((abfd->flags & D_PAGED) != 0) + { + internal_a.tsize = (text_size + round - 1) &~ (round - 1); + internal_a.text_start = text_start &~ (round - 1); + internal_a.dsize = (data_size + round - 1) &~ (round - 1); + internal_a.data_start = data_start &~ (round - 1); + } + else + { + internal_a.tsize = text_size; + internal_a.text_start = text_start; + internal_a.dsize = data_size; + internal_a.data_start = data_start; + } + + /* On Ultrix, the initial portions of the .sbss and .bss segments + are at the end of the data section. The bsize field in the + optional header records how many bss bytes are required beyond + those in the data section. The value is not rounded to a page + boundary. */ + if (bss_size < internal_a.dsize - data_size) + bss_size = 0; + else + bss_size -= internal_a.dsize - data_size; + internal_a.bsize = bss_size; + internal_a.bss_start = internal_a.data_start + internal_a.dsize; + + internal_a.entry = bfd_get_start_address (abfd); + + internal_a.gp_value = ecoff_data (abfd)->gp; + + internal_a.gprmask = ecoff_data (abfd)->gprmask; + internal_a.fprmask = ecoff_data (abfd)->fprmask; + for (i = 0; i < 4; i++) + internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i]; + + /* Let the backend adjust the headers if necessary. */ + if (backend->adjust_headers) + { + if (! (*backend->adjust_headers) (abfd, &internal_f, &internal_a)) + goto error_return; + } + + /* Write out the file header and the optional header. */ + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto error_return; + + bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff); + if (bfd_write (buff, 1, filhsz, abfd) != filhsz) + goto error_return; + + bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff); + if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz) + goto error_return; + + /* Build the external symbol information. This must be done before + writing out the relocs so that we know the symbol indices. We + don't do this if this BFD was created by the backend linker, + since it will have already handled the symbols and relocs. */ + if (! ecoff_data (abfd)->linker) + { + symhdr->iextMax = 0; + symhdr->issExtMax = 0; + debug->external_ext = debug->external_ext_end = NULL; + debug->ssext = debug->ssext_end = NULL; + if (bfd_ecoff_debug_externals (abfd, debug, &backend->debug_swap, + (((abfd->flags & EXEC_P) == 0) + ? true : false), + ecoff_get_extr, ecoff_set_index) + == false) + goto error_return; + + /* Write out the relocs. */ + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + arelent **reloc_ptr_ptr; + arelent **reloc_end; + char *out_ptr; + + if (current->reloc_count == 0) + continue; + + reloc_buff = + bfd_alloc (abfd, current->reloc_count * external_reloc_size); + if (reloc_buff == NULL) + goto error_return; + + reloc_ptr_ptr = current->orelocation; + reloc_end = reloc_ptr_ptr + current->reloc_count; + out_ptr = (char *) reloc_buff; + for (; + reloc_ptr_ptr < reloc_end; + reloc_ptr_ptr++, out_ptr += external_reloc_size) + { + arelent *reloc; + asymbol *sym; + struct internal_reloc in; + + memset ((PTR) &in, 0, sizeof in); + + reloc = *reloc_ptr_ptr; + sym = *reloc->sym_ptr_ptr; + + in.r_vaddr = (reloc->address + + bfd_get_section_vma (abfd, current)); + in.r_type = reloc->howto->type; + + if ((sym->flags & BSF_SECTION_SYM) == 0) + { + in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); + in.r_extern = 1; + } + else + { + CONST char *name; + + name = bfd_get_section_name (abfd, bfd_get_section (sym)); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else if (strcmp (name, ".xdata") == 0) + in.r_symndx = RELOC_SECTION_XDATA; + else if (strcmp (name, ".pdata") == 0) + in.r_symndx = RELOC_SECTION_PDATA; + else if (strcmp (name, ".fini") == 0) + in.r_symndx = RELOC_SECTION_FINI; + else if (strcmp (name, ".lita") == 0) + in.r_symndx = RELOC_SECTION_LITA; + else if (strcmp (name, "*ABS*") == 0) + in.r_symndx = RELOC_SECTION_ABS; + else if (strcmp (name, ".rconst") == 0) + in.r_symndx = RELOC_SECTION_RCONST; + else + abort (); + in.r_extern = 0; + } + + (*adjust_reloc_out) (abfd, reloc, &in); + + (*swap_reloc_out) (abfd, &in, (PTR) out_ptr); + } + + if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) + goto error_return; + if (bfd_write (reloc_buff, + external_reloc_size, current->reloc_count, abfd) + != external_reloc_size * current->reloc_count) + goto error_return; + bfd_release (abfd, reloc_buff); + reloc_buff = NULL; + } + + /* Write out the symbolic debugging information. */ + if (bfd_get_symcount (abfd) > 0) + { + /* Write out the debugging information. */ + if (bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap, + ecoff_data (abfd)->sym_filepos) + == false) + goto error_return; + } + } + + /* The .bss section of a demand paged executable must receive an + entire page. If there are symbols, the symbols will start on the + next page. If there are no symbols, we must fill out the page by + hand. */ + if (bfd_get_symcount (abfd) == 0 + && (abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + { + char c; + + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + goto error_return; + if (bfd_read (&c, 1, 1, abfd) == 0) + c = 0; + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + goto error_return; + if (bfd_write (&c, 1, 1, abfd) != 1) + goto error_return; + } + + if (reloc_buff != NULL) + bfd_release (abfd, reloc_buff); + if (buff != NULL) + free (buff); + return true; + error_return: + if (reloc_buff != NULL) + bfd_release (abfd, reloc_buff); + if (buff != NULL) + free (buff); + return false; +} + +/* Archive handling. ECOFF uses what appears to be a unique type of + archive header (armap). The byte ordering of the armap and the + contents are encoded in the name of the armap itself. At least for + now, we only support archives with the same byte ordering in the + armap and the contents. + + The first four bytes in the armap are the number of symbol + definitions. This is always a power of two. + + This is followed by the symbol definitions. Each symbol definition + occupies 8 bytes. The first four bytes are the offset from the + start of the armap strings to the null-terminated string naming + this symbol. The second four bytes are the file offset to the + archive member which defines this symbol. If the second four bytes + are 0, then this is not actually a symbol definition, and it should + be ignored. + + The symbols are hashed into the armap with a closed hashing scheme. + See the functions below for the details of the algorithm. + + After the symbol definitions comes four bytes holding the size of + the string table, followed by the string table itself. */ + +/* The name of an archive headers looks like this: + __________E[BL]E[BL]_ (with a trailing space). + The trailing space is changed to an X if the archive is changed to + indicate that the armap is out of date. + + The Alpha seems to use ________64E[BL]E[BL]_. */ + +#define ARMAP_BIG_ENDIAN 'B' +#define ARMAP_LITTLE_ENDIAN 'L' +#define ARMAP_MARKER 'E' +#define ARMAP_START_LENGTH 10 +#define ARMAP_HEADER_MARKER_INDEX 10 +#define ARMAP_HEADER_ENDIAN_INDEX 11 +#define ARMAP_OBJECT_MARKER_INDEX 12 +#define ARMAP_OBJECT_ENDIAN_INDEX 13 +#define ARMAP_END_INDEX 14 +#define ARMAP_END "_ " + +/* This is a magic number used in the hashing algorithm. */ +#define ARMAP_HASH_MAGIC 0x9dd68ab5 + +/* This returns the hash value to use for a string. It also sets + *REHASH to the rehash adjustment if the first slot is taken. SIZE + is the number of entries in the hash table, and HLOG is the log + base 2 of SIZE. */ + +static unsigned int +ecoff_armap_hash (s, rehash, size, hlog) + CONST char *s; + unsigned int *rehash; + unsigned int size; + unsigned int hlog; +{ + unsigned int hash; + + hash = *s++; + while (*s != '\0') + hash = ((hash >> 27) | (hash << 5)) + *s++; + hash *= ARMAP_HASH_MAGIC; + *rehash = (hash & (size - 1)) | 1; + return hash >> (32 - hlog); +} + +/* Read in the armap. */ + +boolean +_bfd_ecoff_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + unsigned int i; + struct areltdata *mapdata; + bfd_size_type parsed_size; + char *raw_armap; + struct artdata *ardata; + unsigned int count; + char *raw_ptr; + struct symdef *symdef_ptr; + char *stringbase; + + /* Get the name of the first element. */ + i = bfd_read ((PTR) nextname, 1, 16, abfd); + if (i == 0) + return true; + if (i != 16) + return false; + + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) + return false; + + /* Irix 4.0.5F apparently can use either an ECOFF armap or a + standard COFF armap. We could move the ECOFF armap stuff into + bfd_slurp_armap, but that seems inappropriate since no other + target uses this format. Instead, we check directly for a COFF + armap. */ + if (strncmp (nextname, "/ ", 16) == 0) + return bfd_slurp_armap (abfd); + + /* See if the first element is an armap. */ + if (strncmp (nextname, ecoff_backend (abfd)->armap_start, + ARMAP_START_LENGTH) != 0 + || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || strncmp (nextname + ARMAP_END_INDEX, + ARMAP_END, sizeof ARMAP_END - 1) != 0) + { + bfd_has_map (abfd) = false; + return true; + } + + /* Make sure we have the right byte ordering. */ + if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (bfd_header_big_endian (abfd))) + || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (bfd_big_endian (abfd)))) + { + bfd_set_error (bfd_error_wrong_format); + return false; + } + + /* Read in the armap. */ + ardata = bfd_ardata (abfd); + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == (struct areltdata *) NULL) + return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); + + raw_armap = (char *) bfd_alloc (abfd, parsed_size); + if (raw_armap == (char *) NULL) + return false; + + if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + bfd_release (abfd, (PTR) raw_armap); + return false; + } + + ardata->tdata = (PTR) raw_armap; + + count = bfd_h_get_32 (abfd, (PTR) raw_armap); + + ardata->symdef_count = 0; + ardata->cache = (struct ar_cache *) NULL; + + /* This code used to overlay the symdefs over the raw archive data, + but that doesn't work on a 64 bit host. */ + + stringbase = raw_armap + count * 8 + 8; + +#ifdef CHECK_ARMAP_HASH + { + unsigned int hlog; + + /* Double check that I have the hashing algorithm right by making + sure that every symbol can be looked up successfully. */ + hlog = 0; + for (i = 1; i < count; i <<= 1) + hlog++; + BFD_ASSERT (i == count); + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + unsigned int hash, rehash, srch; + + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count, + hlog); + if (hash == i) + continue; + + /* See if we can rehash to this location. */ + for (srch = (hash + rehash) & (count - 1); + srch != hash && srch != i; + srch = (srch + rehash) & (count - 1)) + BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8)) + != 0); + BFD_ASSERT (srch == i); + } + } + +#endif /* CHECK_ARMAP_HASH */ + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0) + ++ardata->symdef_count; + + symdef_ptr = ((struct symdef *) + bfd_alloc (abfd, + ardata->symdef_count * sizeof (struct symdef))); + if (!symdef_ptr) + return false; + + ardata->symdefs = (carsym *) symdef_ptr; + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + symdef_ptr->s.name = stringbase + name_offset; + symdef_ptr->file_offset = file_offset; + ++symdef_ptr; + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary. */ + ardata->first_file_filepos += ardata->first_file_filepos % 2; + + bfd_has_map (abfd) = true; + + return true; +} + +/* Write out an armap. */ + +boolean +_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + unsigned int hashsize, hashlog; + unsigned int symdefsize; + int padit; + unsigned int stringsize; + unsigned int mapsize; + file_ptr firstreal; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + bfd_byte temp[4]; + bfd_byte *hashtable; + bfd *current; + bfd *last_elt; + + /* Ultrix appears to use as a hash table size the least power of two + greater than twice the number of entries. */ + for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++) + ; + hashsize = 1 << hashlog; + + symdefsize = hashsize * 8; + padit = stridx % 2; + stringsize = stridx + padit; + + /* Include 8 bytes to store symdefsize and stringsize in output. */ + mapsize = symdefsize + stringsize + 8; + + firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength; + + memset ((PTR) &hdr, 0, sizeof hdr); + + /* Work out the ECOFF armap name. */ + strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start); + hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] = + (bfd_header_big_endian (abfd) + ? ARMAP_BIG_ENDIAN + : ARMAP_LITTLE_ENDIAN); + hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] = + bfd_big_endian (abfd) ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; + memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1); + + /* Write the timestamp of the archive header to be just a little bit + later than the timestamp of the file, otherwise the linker will + complain that the index is out of date. Actually, the Ultrix + linker just checks the archive name; the GNU linker may check the + date. */ + stat (abfd->filename, &statbuf); + sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60)); + + /* The DECstation uses zeroes for the uid, gid and mode of the + armap. */ + hdr.ar_uid[0] = '0'; + hdr.ar_gid[0] = '0'; + hdr.ar_mode[0] = '0'; + + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + + hdr.ar_fmag[0] = '`'; + hdr.ar_fmag[1] = '\012'; + + /* Turn all null bytes in the header into spaces. */ + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') + (((char *)(&hdr))[i]) = ' '; + + if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + return false; + + bfd_h_put_32 (abfd, (bfd_vma) hashsize, temp); + if (bfd_write ((PTR) temp, 1, 4, abfd) != 4) + return false; + + hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize); + if (!hashtable) + return false; + + current = abfd->archive_head; + last_elt = current; + for (i = 0; i < orl_count; i++) + { + unsigned int hash, rehash; + + /* Advance firstreal to the file position of this archive + element. */ + if (((bfd *) map[i].pos) != last_elt) + { + do + { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } + while (current != (bfd *) map[i].pos); + } + + last_elt = current; + + hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog); + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0) + { + unsigned int srch; + + /* The desired slot is already taken. */ + for (srch = (hash + rehash) & (hashsize - 1); + srch != hash; + srch = (srch + rehash) & (hashsize - 1)) + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0) + break; + + BFD_ASSERT (srch != hash); + + hash = srch; + } + + bfd_h_put_32 (abfd, (bfd_vma) map[i].namidx, + (PTR) (hashtable + hash * 8)); + bfd_h_put_32 (abfd, (bfd_vma) firstreal, + (PTR) (hashtable + hash * 8 + 4)); + } + + if (bfd_write ((PTR) hashtable, 1, symdefsize, abfd) != symdefsize) + return false; + + bfd_release (abfd, hashtable); + + /* Now write the strings. */ + bfd_h_put_32 (abfd, (bfd_vma) stringsize, temp); + if (bfd_write ((PTR) temp, 1, 4, abfd) != 4) + return false; + for (i = 0; i < orl_count; i++) + { + bfd_size_type len; + + len = strlen (*map[i].name) + 1; + if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len) + return false; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for DECstation ar we use a null. */ + if (padit) + { + if (bfd_write ("", 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* See whether this BFD is an archive. If it is, read in the armap + and the extended name table. */ + +const bfd_target * +_bfd_ecoff_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG + 1]; + + if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG + || strncmp (armag, ARMAG, SARMAG) != 0) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return (const bfd_target *) NULL; + } + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of + assignment. */ + abfd->tdata.aout_ar_data = + (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); + + if (bfd_ardata (abfd) == (struct artdata *) NULL) + return (const bfd_target *) NULL; + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + if (_bfd_ecoff_slurp_armap (abfd) == false + || _bfd_ecoff_slurp_extended_name_table (abfd) == false) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = (struct artdata *) NULL; + return (const bfd_target *) NULL; + } + + return abfd->xvec; +} + +/* ECOFF linker code. */ + +static struct bfd_hash_entry *ecoff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string)); +static boolean ecoff_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean ecoff_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean ecoff_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean ecoff_link_add_externals + PARAMS ((bfd *, struct bfd_link_info *, PTR, char *)); + +/* Routine to create an entry in an ECOFF link hash table. */ + +static struct bfd_hash_entry * +ecoff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ecoff_link_hash_entry *ret = (struct ecoff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct ecoff_link_hash_entry *) NULL) + ret = ((struct ecoff_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct ecoff_link_hash_entry))); + if (ret == (struct ecoff_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ecoff_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Set local fields. */ + ret->indx = -1; + ret->abfd = NULL; + ret->written = 0; + ret->small = 0; + } + memset ((PTR) &ret->esym, 0, sizeof ret->esym); + + return (struct bfd_hash_entry *) ret; +} + +/* Create an ECOFF link hash table. */ + +struct bfd_link_hash_table * +_bfd_ecoff_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ + struct ecoff_link_hash_table *ret; + + ret = ((struct ecoff_link_hash_table *) + bfd_alloc (abfd, sizeof (struct ecoff_link_hash_table))); + if (ret == NULL) + return NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, + ecoff_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Look up an entry in an ECOFF link hash table. */ + +#define ecoff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct ecoff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an ECOFF link hash table. */ + +#define ecoff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the ECOFF link hash table from the info structure. This is + just a cast. */ + +#define ecoff_hash_table(p) ((struct ecoff_link_hash_table *) ((p)->hash)) + +/* Given an ECOFF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +_bfd_ecoff_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return ecoff_link_add_object_symbols (abfd, info); + case bfd_archive: + return ecoff_link_add_archive_symbols (abfd, info); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add the symbols from an archive file to the global hash table. + This looks through the undefined symbols, looks each one up in the + archive hash table, and adds any associated object file. We do not + use _bfd_generic_link_add_archive_symbols because ECOFF archives + already have a hash table, so there is no reason to construct + another one. */ + +static boolean +ecoff_link_add_archive_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_byte *raw_armap; + struct bfd_link_hash_entry **pundef; + unsigned int armap_count; + unsigned int armap_log; + unsigned int i; + const bfd_byte *hashtable; + const char *stringbase; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return true; + bfd_set_error (bfd_error_no_armap); + return false; + } + + /* If we don't have any raw data for this archive, as can happen on + Irix 4.0.5F, we call the generic routine. + FIXME: We should be more clever about this, since someday tdata + may get to something for a generic archive. */ + raw_armap = (const bfd_byte *) bfd_ardata (abfd)->tdata; + if (raw_armap == (bfd_byte *) NULL) + return (_bfd_generic_link_add_archive_symbols + (abfd, info, ecoff_link_check_archive_element)); + + armap_count = bfd_h_get_32 (abfd, raw_armap); + + armap_log = 0; + for (i = 1; i < armap_count; i <<= 1) + armap_log++; + BFD_ASSERT (i == armap_count); + + hashtable = raw_armap + 4; + stringbase = (const char *) raw_armap + armap_count * 8 + 8; + + /* Look through the list of undefined symbols. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + unsigned int hash, rehash; + unsigned int file_offset; + const char *name; + bfd *element; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on. */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Native ECOFF linkers do not pull in archive elements merely + to satisfy common definitions, so neither do we. We leave + them on the list, though, in case we are linking against some + other object format. */ + if (h->type != bfd_link_hash_undefined) + { + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive hash table. */ + hash = ecoff_armap_hash (h->root.string, &rehash, armap_count, + armap_log); + + file_offset = bfd_h_get_32 (abfd, hashtable + (hash * 8) + 4); + if (file_offset == 0) + { + /* Nothing in this slot. */ + pundef = &(*pundef)->next; + continue; + } + + name = stringbase + bfd_h_get_32 (abfd, hashtable + (hash * 8)); + if (name[0] != h->root.string[0] + || strcmp (name, h->root.string) != 0) + { + unsigned int srch; + boolean found; + + /* That was the wrong symbol. Try rehashing. */ + found = false; + for (srch = (hash + rehash) & (armap_count - 1); + srch != hash; + srch = (srch + rehash) & (armap_count - 1)) + { + file_offset = bfd_h_get_32 (abfd, hashtable + (srch * 8) + 4); + if (file_offset == 0) + break; + name = stringbase + bfd_h_get_32 (abfd, hashtable + (srch * 8)); + if (name[0] == h->root.string[0] + && strcmp (name, h->root.string) == 0) + { + found = true; + break; + } + } + + if (! found) + { + pundef = &(*pundef)->next; + continue; + } + + hash = srch; + } + + element = (*backend->get_elt_at_filepos) (abfd, file_offset); + if (element == (bfd *) NULL) + return false; + + if (! bfd_check_format (element, bfd_object)) + return false; + + /* Unlike the generic linker, we know that this element provides + a definition for an undefined symbol and we know that we want + to include it. We don't need to check anything. */ + if (! (*info->callbacks->add_archive_element) (info, element, name)) + return false; + if (! ecoff_link_add_object_symbols (element, info)) + return false; + + pundef = &(*pundef)->next; + } + + return true; +} + +/* This is called if we used _bfd_generic_link_add_archive_symbols + because we were not dealing with an ECOFF archive. */ + +static boolean +ecoff_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->debug_swap.swap_ext_in; + HDRR *symhdr; + bfd_size_type external_ext_size; + PTR external_ext = NULL; + size_t esize; + char *ssext = NULL; + char *ext_ptr; + char *ext_end; + + *pneeded = false; + + if (! ecoff_slurp_symbolic_header (abfd)) + goto error_return; + + /* If there are no symbols, we don't want it. */ + if (bfd_get_symcount (abfd) == 0) + goto successful_return; + + symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + + /* Read in the external symbols and external strings. */ + external_ext_size = backend->debug_swap.external_ext_size; + esize = symhdr->iextMax * external_ext_size; + external_ext = (PTR) bfd_malloc (esize); + if (external_ext == NULL && esize != 0) + goto error_return; + + if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0 + || bfd_read (external_ext, 1, esize, abfd) != esize) + goto error_return; + + ssext = (char *) bfd_malloc (symhdr->issExtMax); + if (ssext == NULL && symhdr->issExtMax != 0) + goto error_return; + + if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0 + || (bfd_read (ssext, 1, symhdr->issExtMax, abfd) != + (bfd_size_type) symhdr->issExtMax)) + goto error_return; + + /* Look through the external symbols to see if they define some + symbol that is currently undefined. */ + ext_ptr = (char *) external_ext; + ext_end = ext_ptr + esize; + for (; ext_ptr < ext_end; ext_ptr += external_ext_size) + { + EXTR esym; + boolean def; + const char *name; + struct bfd_link_hash_entry *h; + + (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym); + + /* See if this symbol defines something. */ + if (esym.asym.st != stGlobal + && esym.asym.st != stLabel + && esym.asym.st != stProc) + continue; + + switch (esym.asym.sc) + { + case scText: + case scData: + case scBss: + case scAbs: + case scSData: + case scSBss: + case scRData: + case scCommon: + case scSCommon: + case scInit: + case scFini: + case scRConst: + def = true; + break; + default: + def = false; + break; + } + + if (! def) + continue; + + name = ssext + esym.asym.iss; + h = bfd_link_hash_lookup (info->hash, name, false, false, true); + + /* Unlike the generic linker, we do not pull in elements because + of common symbols. */ + if (h == (struct bfd_link_hash_entry *) NULL + || h->type != bfd_link_hash_undefined) + continue; + + /* Include this element. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + goto error_return; + if (! ecoff_link_add_externals (abfd, info, external_ext, ssext)) + goto error_return; + + *pneeded = true; + goto successful_return; + } + + successful_return: + if (external_ext != NULL) + free (external_ext); + if (ssext != NULL) + free (ssext); + return true; + error_return: + if (external_ext != NULL) + free (external_ext); + if (ssext != NULL) + free (ssext); + return false; +} + +/* Add symbols from an ECOFF object file to the global linker hash + table. */ + +static boolean +ecoff_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + HDRR *symhdr; + bfd_size_type external_ext_size; + PTR external_ext = NULL; + size_t esize; + char *ssext = NULL; + boolean result; + + if (! ecoff_slurp_symbolic_header (abfd)) + return false; + + /* If there are no symbols, we don't want it. */ + if (bfd_get_symcount (abfd) == 0) + return true; + + symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; + + /* Read in the external symbols and external strings. */ + external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size; + esize = symhdr->iextMax * external_ext_size; + external_ext = (PTR) bfd_malloc (esize); + if (external_ext == NULL && esize != 0) + goto error_return; + + if (bfd_seek (abfd, symhdr->cbExtOffset, SEEK_SET) != 0 + || bfd_read (external_ext, 1, esize, abfd) != esize) + goto error_return; + + ssext = (char *) bfd_malloc (symhdr->issExtMax); + if (ssext == NULL && symhdr->issExtMax != 0) + goto error_return; + + if (bfd_seek (abfd, symhdr->cbSsExtOffset, SEEK_SET) != 0 + || (bfd_read (ssext, 1, symhdr->issExtMax, abfd) + != (bfd_size_type) symhdr->issExtMax)) + goto error_return; + + result = ecoff_link_add_externals (abfd, info, external_ext, ssext); + + if (ssext != NULL) + free (ssext); + if (external_ext != NULL) + free (external_ext); + return result; + + error_return: + if (ssext != NULL) + free (ssext); + if (external_ext != NULL) + free (external_ext); + return false; +} + +/* Add the external symbols of an object file to the global linker + hash table. The external symbols and strings we are passed are + just allocated on the stack, and will be discarded. We must + explicitly save any information we may need later on in the link. + We do not want to read the external symbol information again. */ + +static boolean +ecoff_link_add_externals (abfd, info, external_ext, ssext) + bfd *abfd; + struct bfd_link_info *info; + PTR external_ext; + char *ssext; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->debug_swap.swap_ext_in; + bfd_size_type external_ext_size = backend->debug_swap.external_ext_size; + unsigned long ext_count; + struct ecoff_link_hash_entry **sym_hash; + char *ext_ptr; + char *ext_end; + + ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax; + + sym_hash = ((struct ecoff_link_hash_entry **) + bfd_alloc (abfd, + ext_count * sizeof (struct bfd_link_hash_entry *))); + if (!sym_hash) + return false; + ecoff_data (abfd)->sym_hashes = sym_hash; + + ext_ptr = (char *) external_ext; + ext_end = ext_ptr + ext_count * external_ext_size; + for (; ext_ptr < ext_end; ext_ptr += external_ext_size, sym_hash++) + { + EXTR esym; + boolean skip; + bfd_vma value; + asection *section; + const char *name; + struct ecoff_link_hash_entry *h; + + *sym_hash = NULL; + + (*swap_ext_in) (abfd, (PTR) ext_ptr, &esym); + + /* Skip debugging symbols. */ + skip = false; + switch (esym.asym.st) + { + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + break; + default: + skip = true; + break; + } + + if (skip) + continue; + + /* Get the information for this symbol. */ + value = esym.asym.value; + switch (esym.asym.sc) + { + default: + case scNil: + case scRegister: + case scCdbLocal: + case scBits: + case scCdbSystem: + case scRegImage: + case scInfo: + case scUserStruct: + case scVar: + case scVarRegister: + case scVariant: + case scBasedVar: + case scXData: + case scPData: + section = NULL; + break; + case scText: + section = bfd_make_section_old_way (abfd, ".text"); + value -= section->vma; + break; + case scData: + section = bfd_make_section_old_way (abfd, ".data"); + value -= section->vma; + break; + case scBss: + section = bfd_make_section_old_way (abfd, ".bss"); + value -= section->vma; + break; + case scAbs: + section = bfd_abs_section_ptr; + break; + case scUndefined: + section = bfd_und_section_ptr; + break; + case scSData: + section = bfd_make_section_old_way (abfd, ".sdata"); + value -= section->vma; + break; + case scSBss: + section = bfd_make_section_old_way (abfd, ".sbss"); + value -= section->vma; + break; + case scRData: + section = bfd_make_section_old_way (abfd, ".rdata"); + value -= section->vma; + break; + case scCommon: + if (value > ecoff_data (abfd)->gp_size) + { + section = bfd_com_section_ptr; + break; + } + /* Fall through. */ + case scSCommon: + if (ecoff_scom_section.name == NULL) + { + /* Initialize the small common section. */ + ecoff_scom_section.name = SCOMMON; + ecoff_scom_section.flags = SEC_IS_COMMON; + ecoff_scom_section.output_section = &ecoff_scom_section; + ecoff_scom_section.symbol = &ecoff_scom_symbol; + ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; + ecoff_scom_symbol.name = SCOMMON; + ecoff_scom_symbol.flags = BSF_SECTION_SYM; + ecoff_scom_symbol.section = &ecoff_scom_section; + ecoff_scom_symbol_ptr = &ecoff_scom_symbol; + } + section = &ecoff_scom_section; + break; + case scSUndefined: + section = bfd_und_section_ptr; + break; + case scInit: + section = bfd_make_section_old_way (abfd, ".init"); + value -= section->vma; + break; + case scFini: + section = bfd_make_section_old_way (abfd, ".fini"); + value -= section->vma; + break; + case scRConst: + section = bfd_make_section_old_way (abfd, ".rconst"); + value -= section->vma; + break; + } + + if (section == (asection *) NULL) + continue; + + name = ssext + esym.asym.iss; + + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, + esym.weakext ? BSF_WEAK : BSF_GLOBAL, + section, value, (const char *) NULL, true, true, + (struct bfd_link_hash_entry **) &h))) + return false; + + *sym_hash = h; + + /* If we are building an ECOFF hash table, save the external + symbol information. */ + if (info->hash->creator->flavour == bfd_get_flavour (abfd)) + { + if (h->abfd == (bfd *) NULL + || (! bfd_is_und_section (section) + && (! bfd_is_com_section (section) + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)))) + { + h->abfd = abfd; + h->esym = esym; + } + + /* Remember whether this symbol was small undefined. */ + if (esym.asym.sc == scSUndefined) + h->small = 1; + + /* If this symbol was ever small undefined, it needs to wind + up in a GP relative section. We can't control the + section of a defined symbol, but we can control the + section of a common symbol. This case is actually needed + on Ultrix 4.2 to handle the symbol cred in -lckrb. */ + if (h->small + && h->root.type == bfd_link_hash_common + && strcmp (h->root.u.c.p->section->name, SCOMMON) != 0) + { + h->root.u.c.p->section = bfd_make_section_old_way (abfd, + SCOMMON); + h->root.u.c.p->section->flags = SEC_ALLOC; + if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scSCommon; + } + } + } + + return true; +} + +/* ECOFF final link routines. */ + +static boolean ecoff_final_link_debug_accumulate + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + PTR handle)); +static boolean ecoff_link_write_external + PARAMS ((struct ecoff_link_hash_entry *, PTR)); +static boolean ecoff_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); +static boolean ecoff_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Structure used to pass information to ecoff_link_write_external. */ + +struct extsym_info +{ + bfd *abfd; + struct bfd_link_info *info; +}; + +/* ECOFF final link routine. This looks through all the input BFDs + and gathers together all the debugging information, and then + processes all the link order information. This may cause it to + close and reopen some input BFDs; I'll see how bad this is. */ + +boolean +_bfd_ecoff_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; + HDRR *symhdr; + PTR handle; + register bfd *input_bfd; + asection *o; + struct bfd_link_order *p; + struct extsym_info einfo; + + /* We accumulate the debugging information counts in the symbolic + header. */ + symhdr = &debug->symbolic_header; + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We accumulate the debugging information itself in the debug_info + structure. */ + debug->line = NULL; + debug->external_dnr = NULL; + debug->external_pdr = NULL; + debug->external_sym = NULL; + debug->external_opt = NULL; + debug->external_aux = NULL; + debug->ss = NULL; + debug->ssext = debug->ssext_end = NULL; + debug->external_fdr = NULL; + debug->external_rfd = NULL; + debug->external_ext = debug->external_ext_end = NULL; + + handle = bfd_ecoff_debug_init (abfd, debug, &backend->debug_swap, info); + if (handle == (PTR) NULL) + return false; + + /* Accumulate the debugging symbols from each input BFD. */ + for (input_bfd = info->input_bfds; + input_bfd != (bfd *) NULL; + input_bfd = input_bfd->link_next) + { + boolean ret; + + if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour) + { + /* Abitrarily set the symbolic header vstamp to the vstamp + of the first object file in the link. */ + if (symhdr->vstamp == 0) + symhdr->vstamp + = ecoff_data (input_bfd)->debug_info.symbolic_header.vstamp; + ret = ecoff_final_link_debug_accumulate (abfd, input_bfd, info, + handle); + } + else + ret = bfd_ecoff_debug_accumulate_other (handle, abfd, + debug, &backend->debug_swap, + input_bfd, info); + if (! ret) + return false; + + /* Combine the register masks. */ + ecoff_data (abfd)->gprmask |= ecoff_data (input_bfd)->gprmask; + ecoff_data (abfd)->fprmask |= ecoff_data (input_bfd)->fprmask; + ecoff_data (abfd)->cprmask[0] |= ecoff_data (input_bfd)->cprmask[0]; + ecoff_data (abfd)->cprmask[1] |= ecoff_data (input_bfd)->cprmask[1]; + ecoff_data (abfd)->cprmask[2] |= ecoff_data (input_bfd)->cprmask[2]; + ecoff_data (abfd)->cprmask[3] |= ecoff_data (input_bfd)->cprmask[3]; + } + + /* Write out the external symbols. */ + einfo.abfd = abfd; + einfo.info = info; + ecoff_link_hash_traverse (ecoff_hash_table (info), + ecoff_link_write_external, + (PTR) &einfo); + + if (info->relocateable) + { + /* We need to make a pass over the link_orders to count up the + number of relocations we will need to output, so that we know + how much space they will take up. */ + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + o->reloc_count = 0; + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + if (p->type == bfd_indirect_link_order) + o->reloc_count += p->u.indirect.section->reloc_count; + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + } + } + + /* Compute the reloc and symbol file positions. */ + ecoff_compute_reloc_file_positions (abfd); + + /* Write out the debugging information. */ + if (! bfd_ecoff_write_accumulated_debug (handle, abfd, debug, + &backend->debug_swap, info, + ecoff_data (abfd)->sym_filepos)) + return false; + + bfd_ecoff_debug_free (handle, abfd, debug, &backend->debug_swap, info); + + if (info->relocateable) + { + /* Now reset the reloc_count field of the sections in the output + BFD to 0, so that we can use them to keep track of how many + relocs we have output thus far. */ + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + o->reloc_count = 0; + } + + /* Get a value for the GP register. */ + if (ecoff_data (abfd)->gp == 0) + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (info->hash, "_gp", false, false, true); + if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_defined) + ecoff_data (abfd)->gp = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + else if (info->relocateable) + { + bfd_vma lo; + + /* Make up a value. */ + lo = (bfd_vma) -1; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (o->vma < lo + && (strcmp (o->name, _SBSS) == 0 + || strcmp (o->name, _SDATA) == 0 + || strcmp (o->name, _LIT4) == 0 + || strcmp (o->name, _LIT8) == 0 + || strcmp (o->name, _LITA) == 0)) + lo = o->vma; + } + ecoff_data (abfd)->gp = lo + 0x8000; + } + else + { + /* If the relocate_section function needs to do a reloc + involving the GP value, it should make a reloc_dangerous + callback to warn that GP is not defined. */ + } + } + + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_ecoff_flavour)) + { + if (! ecoff_indirect_link_order (abfd, info, o, p)) + return false; + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! ecoff_reloc_link_order (abfd, info, o, p)) + return false; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + } + } + } + + bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax; + + ecoff_data (abfd)->linker = true; + + return true; +} + +/* Accumulate the debugging information for an input BFD into the + output BFD. This must read in the symbolic information of the + input BFD. */ + +static boolean +ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + PTR handle; +{ + struct ecoff_debug_info * const debug = &ecoff_data (input_bfd)->debug_info; + const struct ecoff_debug_swap * const swap = + &ecoff_backend (input_bfd)->debug_swap; + HDRR *symhdr = &debug->symbolic_header; + boolean ret; + +#define READ(ptr, offset, count, size, type) \ + if (symhdr->count == 0) \ + debug->ptr = NULL; \ + else \ + { \ + debug->ptr = (type) bfd_malloc ((size_t) (size * symhdr->count)); \ + if (debug->ptr == NULL) \ + { \ + ret = false; \ + goto return_something; \ + } \ + if ((bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET) \ + != 0) \ + || (bfd_read (debug->ptr, size, symhdr->count, \ + input_bfd) != size * symhdr->count)) \ + { \ + ret = false; \ + goto return_something; \ + } \ + } + + /* If raw_syments is not NULL, then the data was already by read by + _bfd_ecoff_slurp_symbolic_info. */ + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + READ (line, cbLineOffset, cbLine, sizeof (unsigned char), + unsigned char *); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), + union aux_ext *); + READ (ss, cbSsOffset, issMax, sizeof (char), char *); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + } +#undef READ + + /* We do not read the external strings or the external symbols. */ + + ret = (bfd_ecoff_debug_accumulate + (handle, output_bfd, &ecoff_data (output_bfd)->debug_info, + &ecoff_backend (output_bfd)->debug_swap, + input_bfd, debug, swap, info)); + + return_something: + if (ecoff_data (input_bfd)->raw_syments == NULL) + { + if (debug->line != NULL) + free (debug->line); + if (debug->external_dnr != NULL) + free (debug->external_dnr); + if (debug->external_pdr != NULL) + free (debug->external_pdr); + if (debug->external_sym != NULL) + free (debug->external_sym); + if (debug->external_opt != NULL) + free (debug->external_opt); + if (debug->external_aux != NULL) + free (debug->external_aux); + if (debug->ss != NULL) + free (debug->ss); + if (debug->external_fdr != NULL) + free (debug->external_fdr); + if (debug->external_rfd != NULL) + free (debug->external_rfd); + + /* Make sure we don't accidentally follow one of these pointers + into freed memory. */ + debug->line = NULL; + debug->external_dnr = NULL; + debug->external_pdr = NULL; + debug->external_sym = NULL; + debug->external_opt = NULL; + debug->external_aux = NULL; + debug->ss = NULL; + debug->external_fdr = NULL; + debug->external_rfd = NULL; + } + + return ret; +} + +/* Put out information for an external symbol. These come only from + the hash table. */ + +static boolean +ecoff_link_write_external (h, data) + struct ecoff_link_hash_entry *h; + PTR data; +{ + struct extsym_info *einfo = (struct extsym_info *) data; + bfd *output_bfd = einfo->abfd; + boolean strip; + + /* We need to check if this symbol is being stripped. */ + if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + strip = false; + else if (einfo->info->strip == strip_all + || (einfo->info->strip == strip_some + && bfd_hash_lookup (einfo->info->keep_hash, + h->root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + if (strip || h->written) + return true; + + if (h->abfd == (bfd *) NULL) + { + h->esym.jmptbl = 0; + h->esym.cobol_main = 0; + h->esym.weakext = 0; + h->esym.reserved = 0; + h->esym.ifd = ifdNil; + h->esym.asym.value = 0; + h->esym.asym.st = stGlobal; + + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + h->esym.asym.sc = scAbs; + else + { + asection *output_section; + const char *name; + + output_section = h->root.u.def.section->output_section; + name = bfd_section_name (output_section->owner, output_section); + + if (strcmp (name, _TEXT) == 0) + h->esym.asym.sc = scText; + else if (strcmp (name, _DATA) == 0) + h->esym.asym.sc = scData; + else if (strcmp (name, _SDATA) == 0) + h->esym.asym.sc = scSData; + else if (strcmp (name, _RDATA) == 0) + h->esym.asym.sc = scRData; + else if (strcmp (name, _BSS) == 0) + h->esym.asym.sc = scBss; + else if (strcmp (name, _SBSS) == 0) + h->esym.asym.sc = scSBss; + else if (strcmp (name, _INIT) == 0) + h->esym.asym.sc = scInit; + else if (strcmp (name, _FINI) == 0) + h->esym.asym.sc = scFini; + else if (strcmp (name, _PDATA) == 0) + h->esym.asym.sc = scPData; + else if (strcmp (name, _XDATA) == 0) + h->esym.asym.sc = scXData; + else if (strcmp (name, _RCONST) == 0) + h->esym.asym.sc = scRConst; + else + h->esym.asym.sc = scAbs; + } + + h->esym.asym.reserved = 0; + h->esym.asym.index = indexNil; + } + else if (h->esym.ifd != -1) + { + struct ecoff_debug_info *debug; + + /* Adjust the FDR index for the symbol by that used for the + input BFD. */ + debug = &ecoff_data (h->abfd)->debug_info; + BFD_ASSERT (h->esym.ifd >= 0 + && h->esym.ifd < debug->symbolic_header.ifdMax); + h->esym.ifd = debug->ifdmap[h->esym.ifd]; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + if (h->esym.asym.sc != scUndefined + && h->esym.asym.sc != scSUndefined) + h->esym.asym.sc = scUndefined; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + if (h->esym.asym.sc == scUndefined + || h->esym.asym.sc == scSUndefined) + h->esym.asym.sc = scAbs; + else if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scBss; + else if (h->esym.asym.sc == scSCommon) + h->esym.asym.sc = scSBss; + h->esym.asym.value = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + break; + case bfd_link_hash_common: + if (h->esym.asym.sc != scCommon + && h->esym.asym.sc != scSCommon) + h->esym.asym.sc = scCommon; + h->esym.asym.value = h->root.u.c.size; + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: Ignore these for now. The circumstances under which + they should be written out are not clear to me. */ + return true; + } + + /* bfd_ecoff_debug_one_external uses iextMax to keep track of the + symbol number. */ + h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax; + h->written = 1; + + return (bfd_ecoff_debug_one_external + (output_bfd, &ecoff_data (output_bfd)->debug_info, + &ecoff_backend (output_bfd)->debug_swap, h->root.root.string, + &h->esym)); +} + +/* Relocate and write an ECOFF section into an ECOFF output file. */ + +static boolean +ecoff_indirect_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + asection *input_section; + bfd *input_bfd; + struct ecoff_section_tdata *section_tdata; + bfd_size_type raw_size; + bfd_size_type cooked_size; + bfd_byte *contents = NULL; + bfd_size_type external_reloc_size; + bfd_size_type external_relocs_size; + PTR external_relocs = NULL; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return true; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + section_tdata = ecoff_section_data (input_bfd, input_section); + + raw_size = input_section->_raw_size; + cooked_size = input_section->_cooked_size; + if (cooked_size == 0) + cooked_size = raw_size; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (cooked_size == link_order->size); + + /* Get the section contents. We allocate memory for the larger of + the size before relocating and the size after relocating. */ + contents = (bfd_byte *) bfd_malloc (raw_size >= cooked_size + ? (size_t) raw_size + : (size_t) cooked_size); + if (contents == NULL && raw_size != 0) + goto error_return; + + /* If we are relaxing, the contents may have already been read into + memory, in which case we copy them into our new buffer. We don't + simply reuse the old buffer in case cooked_size > raw_size. */ + if (section_tdata != (struct ecoff_section_tdata *) NULL + && section_tdata->contents != (bfd_byte *) NULL) + memcpy (contents, section_tdata->contents, (size_t) raw_size); + else + { + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) contents, + (file_ptr) 0, raw_size)) + goto error_return; + } + + /* Get the relocs. If we are relaxing MIPS code, they will already + have been read in. Otherwise, we read them in now. */ + external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size; + external_relocs_size = external_reloc_size * input_section->reloc_count; + + if (section_tdata != (struct ecoff_section_tdata *) NULL + && section_tdata->external_relocs != NULL) + external_relocs = section_tdata->external_relocs; + else + { + external_relocs = (PTR) bfd_malloc ((size_t) external_relocs_size); + if (external_relocs == NULL && external_relocs_size != 0) + goto error_return; + + if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 + || (bfd_read (external_relocs, 1, external_relocs_size, input_bfd) + != external_relocs_size)) + goto error_return; + } + + /* Relocate the section contents. */ + if (! ((*ecoff_backend (input_bfd)->relocate_section) + (output_bfd, info, input_bfd, input_section, contents, + external_relocs))) + goto error_return; + + /* Write out the relocated section. */ + if (! bfd_set_section_contents (output_bfd, + output_section, + (PTR) contents, + input_section->output_offset, + cooked_size)) + goto error_return; + + /* If we are producing relocateable output, the relocs were + modified, and we write them out now. We use the reloc_count + field of output_section to keep track of the number of relocs we + have output so far. */ + if (info->relocateable) + { + if (bfd_seek (output_bfd, + (output_section->rel_filepos + + output_section->reloc_count * external_reloc_size), + SEEK_SET) != 0 + || (bfd_write (external_relocs, 1, external_relocs_size, output_bfd) + != external_relocs_size)) + goto error_return; + output_section->reloc_count += input_section->reloc_count; + } + + if (contents != NULL) + free (contents); + if (external_relocs != NULL && section_tdata == NULL) + free (external_relocs); + return true; + + error_return: + if (contents != NULL) + free (contents); + if (external_relocs != NULL && section_tdata == NULL) + free (external_relocs); + return false; +} + +/* Generate a reloc when linking an ECOFF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static boolean +ecoff_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + enum bfd_link_order_type type; + asection *section; + bfd_vma addend; + arelent rel; + struct internal_reloc in; + bfd_size_type external_reloc_size; + bfd_byte *rbuf; + boolean ok; + + type = link_order->type; + section = NULL; + addend = link_order->u.reloc.p->addend; + + /* We set up an arelent to pass to the backend adjust_reloc_out + routine. */ + rel.address = link_order->offset; + + rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (rel.howto == 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (type == bfd_section_reloc_link_order) + { + section = link_order->u.reloc.p->u.section; + rel.sym_ptr_ptr = section->symbol_ptr_ptr; + } + else + { + struct bfd_link_hash_entry *h; + + /* Treat a reloc against a defined symbol as though it were + actually against the section. */ + h = bfd_wrapped_link_hash_lookup (output_bfd, info, + link_order->u.reloc.p->u.name, + false, false, false); + if (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + { + type = bfd_section_reloc_link_order; + section = h->u.def.section->output_section; + /* It seems that we ought to add the symbol value to the + addend here, but in practice it has already been added + because it was passed to constructor_callback. */ + addend += section->vma + h->u.def.section->output_offset; + } + else + { + /* We can't set up a reloc against a symbol correctly, + because we have no asymbol structure. Currently no + adjust_reloc_out routine cares. */ + rel.sym_ptr_ptr = (asymbol **) NULL; + } + } + + /* All ECOFF relocs are in-place. Put the addend into the object + file. */ + + BFD_ASSERT (rel.howto->partial_inplace); + if (addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (rel.howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return false; + rstat = _bfd_relocate_contents (rel.howto, output_bfd, addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, section) + : link_order->u.reloc.p->u.name), + rel.howto->name, addend, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + rel.addend = 0; + + /* Move the information into a internal_reloc structure. */ + in.r_vaddr = (rel.address + + bfd_get_section_vma (output_bfd, output_section)); + in.r_type = rel.howto->type; + + if (type == bfd_symbol_reloc_link_order) + { + struct ecoff_link_hash_entry *h; + + h = ((struct ecoff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h != (struct ecoff_link_hash_entry *) NULL + && h->indx != -1) + in.r_symndx = h->indx; + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + in.r_symndx = 0; + } + in.r_extern = 1; + } + else + { + CONST char *name; + + name = bfd_get_section_name (output_bfd, section); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else if (strcmp (name, ".xdata") == 0) + in.r_symndx = RELOC_SECTION_XDATA; + else if (strcmp (name, ".pdata") == 0) + in.r_symndx = RELOC_SECTION_PDATA; + else if (strcmp (name, ".fini") == 0) + in.r_symndx = RELOC_SECTION_FINI; + else if (strcmp (name, ".lita") == 0) + in.r_symndx = RELOC_SECTION_LITA; + else if (strcmp (name, "*ABS*") == 0) + in.r_symndx = RELOC_SECTION_ABS; + else if (strcmp (name, ".rconst") == 0) + in.r_symndx = RELOC_SECTION_RCONST; + else + abort (); + in.r_extern = 0; + } + + /* Let the BFD backend adjust the reloc. */ + (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in); + + /* Get some memory and swap out the reloc. */ + external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size; + rbuf = (bfd_byte *) bfd_malloc ((size_t) external_reloc_size); + if (rbuf == (bfd_byte *) NULL) + return false; + + (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf); + + ok = (bfd_seek (output_bfd, + (output_section->rel_filepos + + output_section->reloc_count * external_reloc_size), + SEEK_SET) == 0 + && (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd) + == external_reloc_size)); + + if (ok) + ++output_section->reloc_count; + + free (rbuf); + + return ok; +} diff --git a/contrib/gdb/bfd/ecofflink.c b/contrib/gdb/bfd/ecofflink.c new file mode 100644 index 000000000000..03d6e00ad188 --- /dev/null +++ b/contrib/gdb/bfd/ecofflink.c @@ -0,0 +1,2452 @@ +/* Routines to link ECOFF debugging information. + Copyright 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "obstack.h" +#include "aout/stab_gnu.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" + +static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend, + size_t need)); +static struct bfd_hash_entry *string_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +static void ecoff_align_debug PARAMS ((bfd *abfd, + struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *, + const struct ecoff_debug_swap *, + file_ptr where)); +static int cmp_fdrtab_entry PARAMS ((const PTR, const PTR)); +static boolean mk_fdrtab PARAMS ((bfd *, + struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, + struct ecoff_find_line *)); +static long fdrtab_lookup PARAMS ((struct ecoff_find_line *, bfd_vma)); + +/* Obstack allocation and deallocation routines. */ +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* Routines to swap auxiliary information in and out. I am assuming + that the auxiliary information format is always going to be target + independent. */ + +/* Swap in a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern) + int bigend; + const struct tir_ext *ext_copy; + TIR *intern; +{ + struct tir_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) + >> TIR_BITS1_BT_SH_BIG; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) + >> TIR_BITS_TQ4_SH_BIG; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) + >> TIR_BITS_TQ5_SH_BIG; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) + >> TIR_BITS_TQ0_SH_BIG; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) + >> TIR_BITS_TQ1_SH_BIG; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) + >> TIR_BITS_TQ2_SH_BIG; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) + >> TIR_BITS_TQ3_SH_BIG; + } else { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) + >> TIR_BITS1_BT_SH_LITTLE; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) + >> TIR_BITS_TQ4_SH_LITTLE; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) + >> TIR_BITS_TQ5_SH_LITTLE; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) + >> TIR_BITS_TQ0_SH_LITTLE; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) + >> TIR_BITS_TQ1_SH_LITTLE; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) + >> TIR_BITS_TQ2_SH_LITTLE; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) + >> TIR_BITS_TQ3_SH_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext) + int bigend; + const TIR *intern_copy; + struct tir_ext *ext; +{ + TIR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) + | ((intern->bt << TIR_BITS1_BT_SH_BIG) + & TIR_BITS1_BT_BIG)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) + & TIR_BITS_TQ4_BIG) + | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) + & TIR_BITS_TQ5_BIG)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) + & TIR_BITS_TQ0_BIG) + | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) + & TIR_BITS_TQ1_BIG)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) + & TIR_BITS_TQ2_BIG) + | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) + & TIR_BITS_TQ3_BIG)); + } else { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) + | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) + & TIR_BITS1_BT_LITTLE)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) + & TIR_BITS_TQ4_LITTLE) + | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) + & TIR_BITS_TQ5_LITTLE)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) + & TIR_BITS_TQ0_LITTLE) + | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) + & TIR_BITS_TQ1_LITTLE)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) + & TIR_BITS_TQ2_LITTLE) + | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) + & TIR_BITS_TQ3_LITTLE)); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern) + int bigend; + const struct rndx_ext *ext_copy; + RNDXR *intern; +{ + struct rndx_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) + >> RNDX_BITS1_RFD_SH_BIG); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) + << RNDX_BITS1_INDEX_SH_LEFT_BIG) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); + } else { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) + << RNDX_BITS1_RFD_SH_LEFT_LITTLE); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) + >> RNDX_BITS1_INDEX_SH_LITTLE) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) + | ((unsigned int) ext->r_bits[3] + << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext) + int bigend; + const RNDXR *intern_copy; + struct rndx_ext *ext; +{ + RNDXR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; + ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) + & RNDX_BITS1_RFD_BIG) + | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) + & RNDX_BITS1_INDEX_BIG)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; + } else { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; + ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) + & RNDX_BITS1_RFD_LITTLE) + | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) + & RNDX_BITS1_INDEX_LITTLE)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* The minimum amount of data to allocate. */ +#define ALLOC_SIZE (4064) + +/* Add bytes to a buffer. Return success. */ + +static boolean +ecoff_add_bytes (buf, bufend, need) + char **buf; + char **bufend; + size_t need; +{ + size_t have; + size_t want; + char *newbuf; + + have = *bufend - *buf; + if (have > need) + want = ALLOC_SIZE; + else + { + want = need - have; + if (want < ALLOC_SIZE) + want = ALLOC_SIZE; + } + newbuf = (char *) bfd_realloc (*buf, have + want); + if (newbuf == NULL) + return false; + *buf = newbuf; + *bufend = *buf + have + want; + return true; +} + +/* We keep a hash table which maps strings to numbers. We use it to + map FDR names to indices in the output file, and to map local + strings when combining stabs debugging information. */ + +struct string_hash_entry +{ + struct bfd_hash_entry root; + /* FDR index or string table offset. */ + long val; + /* Next entry in string table. */ + struct string_hash_entry *next; +}; + +struct string_hash_table +{ + struct bfd_hash_table table; +}; + +/* Routine to create an entry in a string hash table. */ + +static struct bfd_hash_entry * +string_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct string_hash_entry *ret = (struct string_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct string_hash_entry *) NULL) + ret = ((struct string_hash_entry *) + bfd_hash_allocate (table, sizeof (struct string_hash_entry))); + if (ret == (struct string_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct string_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->val = -1; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in an string hash table. */ + +#define string_hash_lookup(t, string, create, copy) \ + ((struct string_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* We can't afford to read in all the debugging information when we do + a link. Instead, we build a list of these structures to show how + different parts of the input file map to the output file. */ + +struct shuffle +{ + /* The next entry in this linked list. */ + struct shuffle *next; + /* The length of the information. */ + unsigned long size; + /* Whether this information comes from a file or not. */ + boolean filep; + union + { + struct + { + /* The BFD the data comes from. */ + bfd *input_bfd; + /* The offset within input_bfd. */ + file_ptr offset; + } file; + /* The data to be written out. */ + PTR memory; + } u; +}; + +/* This structure holds information across calls to + bfd_ecoff_debug_accumulate. */ + +struct accumulate +{ + /* The FDR hash table. */ + struct string_hash_table fdr_hash; + /* The strings hash table. */ + struct string_hash_table str_hash; + /* Linked lists describing how to shuffle the input debug + information into the output file. We keep a pointer to both the + head and the tail. */ + struct shuffle *line; + struct shuffle *line_end; + struct shuffle *pdr; + struct shuffle *pdr_end; + struct shuffle *sym; + struct shuffle *sym_end; + struct shuffle *opt; + struct shuffle *opt_end; + struct shuffle *aux; + struct shuffle *aux_end; + struct shuffle *ss; + struct shuffle *ss_end; + struct string_hash_entry *ss_hash; + struct string_hash_entry *ss_hash_end; + struct shuffle *fdr; + struct shuffle *fdr_end; + struct shuffle *rfd; + struct shuffle *rfd_end; + /* The size of the largest file shuffle. */ + unsigned long largest_file_shuffle; + /* An obstack for debugging information. */ + struct obstack memory; +}; + +/* Add a file entry to a shuffle list. */ + +static boolean add_file_shuffle PARAMS ((struct accumulate *, + struct shuffle **, + struct shuffle **, bfd *, file_ptr, + unsigned long)); + +static boolean +add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) + struct accumulate *ainfo; + struct shuffle **head; + struct shuffle **tail; + bfd *input_bfd; + file_ptr offset; + unsigned long size; +{ + struct shuffle *n; + + if (*tail != (struct shuffle *) NULL + && (*tail)->filep + && (*tail)->u.file.input_bfd == input_bfd + && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset) + { + /* Just merge this entry onto the existing one. */ + (*tail)->size += size; + if ((*tail)->size > ainfo->largest_file_shuffle) + ainfo->largest_file_shuffle = (*tail)->size; + return true; + } + + n = (struct shuffle *) obstack_alloc (&ainfo->memory, + sizeof (struct shuffle)); + if (!n) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + n->next = NULL; + n->size = size; + n->filep = true; + n->u.file.input_bfd = input_bfd; + n->u.file.offset = offset; + if (*head == (struct shuffle *) NULL) + *head = n; + if (*tail != (struct shuffle *) NULL) + (*tail)->next = n; + *tail = n; + if (size > ainfo->largest_file_shuffle) + ainfo->largest_file_shuffle = size; + return true; +} + +/* Add a memory entry to a shuffle list. */ + +static boolean add_memory_shuffle PARAMS ((struct accumulate *, + struct shuffle **head, + struct shuffle **tail, + bfd_byte *data, unsigned long size)); + +static boolean +add_memory_shuffle (ainfo, head, tail, data, size) + struct accumulate *ainfo; + struct shuffle **head; + struct shuffle **tail; + bfd_byte *data; + unsigned long size; +{ + struct shuffle *n; + + n = (struct shuffle *) obstack_alloc (&ainfo->memory, + sizeof (struct shuffle)); + if (!n) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + n->next = NULL; + n->size = size; + n->filep = false; + n->u.memory = (PTR) data; + if (*head == (struct shuffle *) NULL) + *head = n; + if (*tail != (struct shuffle *) NULL) + (*tail)->next = n; + *tail = n; + return true; +} + +/* Initialize the FDR hash table. This returns a handle which is then + passed in to bfd_ecoff_debug_accumulate, et. al. */ + +/*ARGSUSED*/ +PTR +bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo; + + ainfo = (struct accumulate *) bfd_malloc (sizeof (struct accumulate)); + if (!ainfo) + return NULL; + if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, + 1021)) + return NULL; + + ainfo->line = NULL; + ainfo->line_end = NULL; + ainfo->pdr = NULL; + ainfo->pdr_end = NULL; + ainfo->sym = NULL; + ainfo->sym_end = NULL; + ainfo->opt = NULL; + ainfo->opt_end = NULL; + ainfo->aux = NULL; + ainfo->aux_end = NULL; + ainfo->ss = NULL; + ainfo->ss_end = NULL; + ainfo->ss_hash = NULL; + ainfo->ss_hash_end = NULL; + ainfo->fdr = NULL; + ainfo->fdr_end = NULL; + ainfo->rfd = NULL; + ainfo->rfd_end = NULL; + + ainfo->largest_file_shuffle = 0; + + if (! info->relocateable) + { + if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc)) + return NULL; + + /* The first entry in the string table is the empty string. */ + output_debug->symbolic_header.issMax = 1; + } + + if (!obstack_begin (&ainfo->memory, 4050)) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + return (PTR) ainfo; +} + +/* Free the accumulated debugging information. */ + +/*ARGSUSED*/ +void +bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + bfd_hash_table_free (&ainfo->fdr_hash.table); + + if (! info->relocateable) + bfd_hash_table_free (&ainfo->str_hash.table); + + obstack_free (&ainfo->memory, (PTR) NULL); + + free (ainfo); +} + +/* Accumulate the debugging information from INPUT_BFD into + OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF + debugging information which we want to link into the information + pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and + INPUT_SWAP point to the swapping information needed. INFO is the + linker information structure. HANDLE is returned by + bfd_ecoff_debug_init. */ + +/*ARGSUSED*/ +boolean +bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, + input_bfd, input_debug, input_swap, + info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + bfd *input_bfd; + struct ecoff_debug_info *input_debug; + const struct ecoff_debug_swap *input_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = input_swap->swap_sym_in; + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = input_swap->swap_rfd_in; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = output_swap->swap_sym_out; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = output_swap->swap_fdr_out; + void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) + = output_swap->swap_rfd_out; + bfd_size_type external_pdr_size = output_swap->external_pdr_size; + bfd_size_type external_sym_size = output_swap->external_sym_size; + bfd_size_type external_opt_size = output_swap->external_opt_size; + bfd_size_type external_fdr_size = output_swap->external_fdr_size; + bfd_size_type external_rfd_size = output_swap->external_rfd_size; + HDRR * const output_symhdr = &output_debug->symbolic_header; + HDRR * const input_symhdr = &input_debug->symbolic_header; + bfd_vma section_adjust[scMax]; + asection *sec; + bfd_byte *fdr_start; + bfd_byte *fdr_ptr; + bfd_byte *fdr_end; + bfd_size_type fdr_add; + unsigned int copied; + RFDT i; + unsigned long sz; + bfd_byte *rfd_out; + bfd_byte *rfd_in; + bfd_byte *rfd_end; + long newrfdbase = 0; + long oldrfdbase = 0; + bfd_byte *fdr_out; + + /* Use section_adjust to hold the value to add to a symbol in a + particular section. */ + memset ((PTR) section_adjust, 0, sizeof section_adjust); + +#define SET(name, indx) \ + sec = bfd_get_section_by_name (input_bfd, name); \ + if (sec != NULL) \ + section_adjust[indx] = (sec->output_section->vma \ + + sec->output_offset \ + - sec->vma); + + SET (".text", scText); + SET (".data", scData); + SET (".bss", scBss); + SET (".sdata", scSData); + SET (".sbss", scSBss); + /* scRdata section may be either .rdata or .rodata. */ + SET (".rdata", scRData); + SET (".rodata", scRData); + SET (".init", scInit); + SET (".fini", scFini); + SET (".rconst", scRConst); + +#undef SET + + /* Find all the debugging information based on the FDR's. We need + to handle them whether they are swapped or not. */ + if (input_debug->fdr != (FDR *) NULL) + { + fdr_start = (bfd_byte *) input_debug->fdr; + fdr_add = sizeof (FDR); + } + else + { + fdr_start = (bfd_byte *) input_debug->external_fdr; + fdr_add = input_swap->external_fdr_size; + } + fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add; + + input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, + (input_symhdr->ifdMax + * sizeof (RFDT))); + + sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size; + rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!input_debug->ifdmap || !rfd_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz)) + return false; + + copied = 0; + + /* Look through the FDR's to see which ones we are going to include + in the final output. We do not want duplicate FDR information + for header files, because ECOFF debugging is often very large. + When we find an FDR with no line information which can be merged, + we look it up in a hash table to ensure that we only include it + once. We keep a table mapping FDR numbers to the final number + they get with the BFD, so that we can refer to it when we write + out the external symbols. */ + for (fdr_ptr = fdr_start, i = 0; + fdr_ptr < fdr_end; + fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size) + { + FDR fdr; + + if (input_debug->fdr != (FDR *) NULL) + fdr = *(FDR *) fdr_ptr; + else + (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); + + /* See if this FDR can be merged with an existing one. */ + if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge) + { + const char *name; + char *lookup; + struct string_hash_entry *fh; + + /* We look up a string formed from the file name and the + number of symbols. Sometimes an include file will + conditionally define a typedef or something based on the + order of include files. Using the number of symbols as a + hash reduces the chance that we will merge symbol + information that should not be merged. */ + name = input_debug->ss + fdr.issBase + fdr.rss; + + lookup = (char *) bfd_malloc (strlen (name) + 20); + if (lookup == NULL) + return false; + sprintf (lookup, "%s %lx", name, fdr.csym); + + fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true); + free (lookup); + if (fh == (struct string_hash_entry *) NULL) + return false; + + if (fh->val != -1) + { + input_debug->ifdmap[i] = fh->val; + (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, + (PTR) rfd_out); + + /* Don't copy this FDR. */ + continue; + } + + fh->val = output_symhdr->ifdMax + copied; + } + + input_debug->ifdmap[i] = output_symhdr->ifdMax + copied; + (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out); + ++copied; + } + + newrfdbase = output_symhdr->crfd; + output_symhdr->crfd += input_symhdr->ifdMax; + + /* Copy over any existing RFD's. RFD's are only created by the + linker, so this will only happen for input files which are the + result of a partial link. */ + rfd_in = (bfd_byte *) input_debug->external_rfd; + rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size; + for (; + rfd_in < rfd_end; + rfd_in += input_swap->external_rfd_size) + { + RFDT rfd; + + (*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd); + BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax); + rfd = input_debug->ifdmap[rfd]; + (*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out); + rfd_out += external_rfd_size; + } + + oldrfdbase = output_symhdr->crfd; + output_symhdr->crfd += input_symhdr->crfd; + + /* Look through the FDR's and copy over all associated debugging + information. */ + sz = copied * external_fdr_size; + fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!fdr_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz)) + return false; + for (fdr_ptr = fdr_start, i = 0; + fdr_ptr < fdr_end; + fdr_ptr += fdr_add, i++) + { + FDR fdr; + bfd_vma fdr_adr; + bfd_byte *sym_out; + bfd_byte *lraw_src; + bfd_byte *lraw_end; + boolean fgotfilename; + + if (input_debug->ifdmap[i] < output_symhdr->ifdMax) + { + /* We are not copying this FDR. */ + continue; + } + + if (input_debug->fdr != (FDR *) NULL) + fdr = *(FDR *) fdr_ptr; + else + (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); + + fdr_adr = fdr.adr; + + /* Adjust the FDR address for any changes that may have been + made by relaxing. */ + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + struct ecoff_value_adjust *adjust; + + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (fdr_adr >= adjust->start + && fdr_adr < adjust->end) + fdr.adr += adjust->adjust; + } + + /* FIXME: It is conceivable that this FDR points to the .init or + .fini section, in which case this will not do the right + thing. */ + fdr.adr += section_adjust[scText]; + + /* Swap in the local symbols, adjust their values, and swap them + out again. */ + fgotfilename = false; + sz = fdr.csym * external_sym_size; + sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!sym_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, + sz)) + return false; + lraw_src = ((bfd_byte *) input_debug->external_sym + + fdr.isymBase * input_swap->external_sym_size); + lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size; + for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size) + { + SYMR internal_sym; + + (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym); + + BFD_ASSERT (internal_sym.sc != scCommon + && internal_sym.sc != scSCommon); + + /* Adjust the symbol value if appropriate. */ + switch (internal_sym.st) + { + case stNil: + if (ECOFF_IS_STAB (&internal_sym)) + break; + /* Fall through. */ + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + bfd_vma value; + struct ecoff_value_adjust *adjust; + + value = internal_sym.value; + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (value >= adjust->start + && value < adjust->end) + internal_sym.value += adjust->adjust; + } + internal_sym.value += section_adjust[internal_sym.sc]; + break; + + default: + break; + } + + /* If we are doing a final link, we hash all the strings in + the local symbol table together. This reduces the amount + of space required by debugging information. We don't do + this when performing a relocateable link because it would + prevent us from easily merging different FDR's. */ + if (! info->relocateable) + { + boolean ffilename; + const char *name; + + if (! fgotfilename && internal_sym.iss == fdr.rss) + ffilename = true; + else + ffilename = false; + + /* Hash the name into the string table. */ + name = input_debug->ss + fdr.issBase + internal_sym.iss; + if (*name == '\0') + internal_sym.iss = 0; + else + { + struct string_hash_entry *sh; + + sh = string_hash_lookup (&ainfo->str_hash, name, true, true); + if (sh == (struct string_hash_entry *) NULL) + return false; + if (sh->val == -1) + { + sh->val = output_symhdr->issMax; + output_symhdr->issMax += strlen (name) + 1; + if (ainfo->ss_hash == (struct string_hash_entry *) NULL) + ainfo->ss_hash = sh; + if (ainfo->ss_hash_end + != (struct string_hash_entry *) NULL) + ainfo->ss_hash_end->next = sh; + ainfo->ss_hash_end = sh; + } + internal_sym.iss = sh->val; + } + + if (ffilename) + { + fdr.rss = internal_sym.iss; + fgotfilename = true; + } + } + + (*swap_sym_out) (output_bfd, &internal_sym, sym_out); + sym_out += external_sym_size; + } + + fdr.isymBase = output_symhdr->isymMax; + output_symhdr->isymMax += fdr.csym; + + /* Copy the information that does not need swapping. */ + + /* FIXME: If we are relaxing, we need to adjust the line + numbers. Frankly, forget it. Anybody using stabs debugging + information will not use this line number information, and + stabs are adjusted correctly. */ + if (fdr.cbLine > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end, + input_bfd, + input_symhdr->cbLineOffset + fdr.cbLineOffset, + fdr.cbLine)) + return false; + fdr.ilineBase = output_symhdr->ilineMax; + fdr.cbLineOffset = output_symhdr->cbLine; + output_symhdr->ilineMax += fdr.cline; + output_symhdr->cbLine += fdr.cbLine; + } + if (fdr.caux > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end, + input_bfd, + (input_symhdr->cbAuxOffset + + fdr.iauxBase * sizeof (union aux_ext)), + fdr.caux * sizeof (union aux_ext))) + return false; + fdr.iauxBase = output_symhdr->iauxMax; + output_symhdr->iauxMax += fdr.caux; + } + if (! info->relocateable) + { + + /* When are are hashing strings, we lie about the number of + strings attached to each FDR. We need to set cbSs + because some versions of dbx apparently use it to decide + how much of the string table to read in. */ + fdr.issBase = 0; + fdr.cbSs = output_symhdr->issMax; + } + else if (fdr.cbSs > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, + input_bfd, + input_symhdr->cbSsOffset + fdr.issBase, + fdr.cbSs)) + return false; + fdr.issBase = output_symhdr->issMax; + output_symhdr->issMax += fdr.cbSs; + } + + if ((output_bfd->xvec->header_byteorder + == input_bfd->xvec->header_byteorder) + && input_debug->adjust == (struct ecoff_value_adjust *) NULL) + { + /* The two BFD's have the same endianness, and we don't have + to adjust the PDR addresses, so simply copying the + information will suffice. */ + BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size); + if (fdr.cpd > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, + input_bfd, + (input_symhdr->cbPdOffset + + fdr.ipdFirst * external_pdr_size), + fdr.cpd * external_pdr_size)) + return false; + } + BFD_ASSERT (external_opt_size == input_swap->external_opt_size); + if (fdr.copt > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, + input_bfd, + (input_symhdr->cbOptOffset + + fdr.ioptBase * external_opt_size), + fdr.copt * external_opt_size)) + return false; + } + } + else + { + bfd_size_type outsz, insz; + bfd_byte *in; + bfd_byte *end; + bfd_byte *out; + + /* The two BFD's have different endianness, so we must swap + everything in and out. This code would always work, but + it would be unnecessarily slow in the normal case. */ + outsz = external_pdr_size; + insz = input_swap->external_pdr_size; + in = ((bfd_byte *) input_debug->external_pdr + + fdr.ipdFirst * insz); + end = in + fdr.cpd * insz; + sz = fdr.cpd * outsz; + out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, + sz)) + return false; + for (; in < end; in += insz, out += outsz) + { + PDR pdr; + + (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr); + + /* If we have been relaxing, we may have to adjust the + address. */ + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + bfd_vma adr; + struct ecoff_value_adjust *adjust; + + adr = fdr_adr + pdr.adr; + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (adr >= adjust->start + && adr < adjust->end) + pdr.adr += adjust->adjust; + } + + (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out); + } + + /* Swap over the optimization information. */ + outsz = external_opt_size; + insz = input_swap->external_opt_size; + in = ((bfd_byte *) input_debug->external_opt + + fdr.ioptBase * insz); + end = in + fdr.copt * insz; + sz = fdr.copt * outsz; + out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, + sz)) + return false; + for (; in < end; in += insz, out += outsz) + { + OPTR opt; + + (*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt); + (*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out); + } + } + + fdr.ipdFirst = output_symhdr->ipdMax; + output_symhdr->ipdMax += fdr.cpd; + fdr.ioptBase = output_symhdr->ioptMax; + output_symhdr->ioptMax += fdr.copt; + + if (fdr.crfd <= 0) + { + /* Point this FDR at the table of RFD's we created. */ + fdr.rfdBase = newrfdbase; + fdr.crfd = input_symhdr->ifdMax; + } + else + { + /* Point this FDR at the remapped RFD's. */ + fdr.rfdBase += oldrfdbase; + } + + (*swap_fdr_out) (output_bfd, &fdr, fdr_out); + fdr_out += external_fdr_size; + ++output_symhdr->ifdMax; + } + + return true; +} + +/* Add a string to the debugging information we are accumulating. + Return the offset from the fdr string base. */ + +static long ecoff_add_string PARAMS ((struct accumulate *, + struct bfd_link_info *, + struct ecoff_debug_info *, + FDR *fdr, const char *string)); + +static long +ecoff_add_string (ainfo, info, debug, fdr, string) + struct accumulate *ainfo; + struct bfd_link_info *info; + struct ecoff_debug_info *debug; + FDR *fdr; + const char *string; +{ + HDRR *symhdr; + size_t len; + bfd_size_type ret; + + symhdr = &debug->symbolic_header; + len = strlen (string); + if (info->relocateable) + { + if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string, + len + 1)) + return -1; + ret = symhdr->issMax; + symhdr->issMax += len + 1; + fdr->cbSs += len + 1; + } + else + { + struct string_hash_entry *sh; + + sh = string_hash_lookup (&ainfo->str_hash, string, true, true); + if (sh == (struct string_hash_entry *) NULL) + return -1; + if (sh->val == -1) + { + sh->val = symhdr->issMax; + symhdr->issMax += len + 1; + if (ainfo->ss_hash == (struct string_hash_entry *) NULL) + ainfo->ss_hash = sh; + if (ainfo->ss_hash_end + != (struct string_hash_entry *) NULL) + ainfo->ss_hash_end->next = sh; + ainfo->ss_hash_end = sh; + } + ret = sh->val; + } + + return ret; +} + +/* Add debugging information from a non-ECOFF file. */ + +boolean +bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, + output_swap, input_bfd, info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + bfd *input_bfd; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = output_swap->swap_sym_out; + HDRR *output_symhdr = &output_debug->symbolic_header; + FDR fdr; + asection *sec; + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + long symsize; + long symcount; + PTR external_fdr; + + memset ((PTR) &fdr, 0, sizeof fdr); + + sec = bfd_get_section_by_name (input_bfd, ".text"); + if (sec != NULL) + fdr.adr = sec->output_section->vma + sec->output_offset; + else + { + /* FIXME: What about .init or .fini? */ + fdr.adr = 0; + } + + fdr.issBase = output_symhdr->issMax; + fdr.cbSs = 0; + fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr, + bfd_get_filename (input_bfd)); + if (fdr.rss == -1) + return false; + fdr.isymBase = output_symhdr->isymMax; + + /* Get the local symbols from the input BFD. */ + symsize = bfd_get_symtab_upper_bound (input_bfd); + if (symsize < 0) + return false; + symbols = (asymbol **) bfd_alloc (output_bfd, symsize); + if (symbols == (asymbol **) NULL) + return false; + symcount = bfd_canonicalize_symtab (input_bfd, symbols); + if (symcount < 0) + return false; + sym_end = symbols + symcount; + + /* Handle the local symbols. Any external symbols are handled + separately. */ + fdr.csym = 0; + for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) + { + SYMR internal_sym; + PTR external_sym; + + if (((*sym_ptr)->flags & BSF_EXPORT) != 0) + continue; + memset ((PTR) &internal_sym, 0, sizeof internal_sym); + internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr, + (*sym_ptr)->name); + + if (internal_sym.iss == -1) + return false; + if (bfd_is_com_section ((*sym_ptr)->section) + || bfd_is_und_section ((*sym_ptr)->section)) + internal_sym.value = (*sym_ptr)->value; + else + internal_sym.value = ((*sym_ptr)->value + + (*sym_ptr)->section->output_offset + + (*sym_ptr)->section->output_section->vma); + internal_sym.st = stNil; + internal_sym.sc = scUndefined; + internal_sym.index = indexNil; + + external_sym = (PTR) obstack_alloc (&ainfo->memory, + output_swap->external_sym_size); + if (!external_sym) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + (*swap_sym_out) (output_bfd, &internal_sym, external_sym); + add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, + external_sym, output_swap->external_sym_size); + ++fdr.csym; + ++output_symhdr->isymMax; + } + + bfd_release (output_bfd, (PTR) symbols); + + /* Leave everything else in the FDR zeroed out. This will cause + the lang field to be langC. The fBigendian field will + indicate little endian format, but it doesn't matter because + it only applies to aux fields and there are none. */ + external_fdr = (PTR) obstack_alloc (&ainfo->memory, + output_swap->external_fdr_size); + if (!external_fdr) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr); + add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, + external_fdr, output_swap->external_fdr_size); + + ++output_symhdr->ifdMax; + + return true; +} + +/* Set up ECOFF debugging information for the external symbols. + FIXME: This is done using a memory buffer, but it should be + probably be changed to use a shuffle structure. The assembler uses + this interface, so that must be changed to do something else. */ + +boolean +bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, + set_index) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + boolean relocateable; + boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); + void (*set_index) PARAMS ((asymbol *, bfd_size_type)); +{ + HDRR * const symhdr = &debug->symbolic_header; + asymbol **sym_ptr_ptr; + size_t c; + + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr == NULL) + return true; + + for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++) + { + asymbol *sym_ptr; + EXTR esym; + + sym_ptr = *sym_ptr_ptr; + + /* Get the external symbol information. */ + if ((*get_extr) (sym_ptr, &esym) == false) + continue; + + /* If we're producing an executable, move common symbols into + bss. */ + if (relocateable == false) + { + if (esym.asym.sc == scCommon) + esym.asym.sc = scBss; + else if (esym.asym.sc == scSCommon) + esym.asym.sc = scSBss; + } + + if (bfd_is_com_section (sym_ptr->section) + || bfd_is_und_section (sym_ptr->section) + || sym_ptr->section->output_section == (asection *) NULL) + { + /* FIXME: gas does not keep the value of a small undefined + symbol in the symbol itself, because of relocation + problems. */ + if (esym.asym.sc != scSUndefined + || esym.asym.value == 0 + || sym_ptr->value != 0) + esym.asym.value = sym_ptr->value; + } + else + esym.asym.value = (sym_ptr->value + + sym_ptr->section->output_offset + + sym_ptr->section->output_section->vma); + + if (set_index) + (*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax); + + if (! bfd_ecoff_debug_one_external (abfd, debug, swap, + sym_ptr->name, &esym)) + return false; + } + + return true; +} + +/* Add a single external symbol to the debugging information. */ + +boolean +bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + const char *name; + EXTR *esym; +{ + const bfd_size_type external_ext_size = swap->external_ext_size; + void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) + = swap->swap_ext_out; + HDRR * const symhdr = &debug->symbolic_header; + size_t namelen; + + namelen = strlen (name); + + if ((size_t) (debug->ssext_end - debug->ssext) + < symhdr->issExtMax + namelen + 1) + { + if (ecoff_add_bytes ((char **) &debug->ssext, + (char **) &debug->ssext_end, + symhdr->issExtMax + namelen + 1) + == false) + return false; + } + if ((size_t) ((char *) debug->external_ext_end + - (char *) debug->external_ext) + < (symhdr->iextMax + 1) * external_ext_size) + { + if (ecoff_add_bytes ((char **) &debug->external_ext, + (char **) &debug->external_ext_end, + (symhdr->iextMax + 1) * external_ext_size) + == false) + return false; + } + + esym->asym.iss = symhdr->issExtMax; + + (*swap_ext_out) (abfd, esym, + ((char *) debug->external_ext + + symhdr->iextMax * swap->external_ext_size)); + + ++symhdr->iextMax; + + strcpy (debug->ssext + symhdr->issExtMax, name); + symhdr->issExtMax += namelen + 1; + + return true; +} + +/* Align the ECOFF debugging information. */ + +/*ARGSUSED*/ +static void +ecoff_align_debug (abfd, debug, swap) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; +{ + HDRR * const symhdr = &debug->symbolic_header; + bfd_size_type debug_align, aux_align, rfd_align; + size_t add; + + /* Adjust the counts so that structures are aligned. */ + debug_align = swap->debug_align; + aux_align = debug_align / sizeof (union aux_ext); + rfd_align = debug_align / swap->external_rfd_size; + + add = debug_align - (symhdr->cbLine & (debug_align - 1)); + if (add != debug_align) + { + if (debug->line != (unsigned char *) NULL) + memset ((PTR) (debug->line + symhdr->cbLine), 0, add); + symhdr->cbLine += add; + } + + add = debug_align - (symhdr->issMax & (debug_align - 1)); + if (add != debug_align) + { + if (debug->ss != (char *) NULL) + memset ((PTR) (debug->ss + symhdr->issMax), 0, add); + symhdr->issMax += add; + } + + add = debug_align - (symhdr->issExtMax & (debug_align - 1)); + if (add != debug_align) + { + if (debug->ssext != (char *) NULL) + memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add); + symhdr->issExtMax += add; + } + + add = aux_align - (symhdr->iauxMax & (aux_align - 1)); + if (add != aux_align) + { + if (debug->external_aux != (union aux_ext *) NULL) + memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0, + add * sizeof (union aux_ext)); + symhdr->iauxMax += add; + } + + add = rfd_align - (symhdr->crfd & (rfd_align - 1)); + if (add != rfd_align) + { + if (debug->external_rfd != (PTR) NULL) + memset ((PTR) ((char *) debug->external_rfd + + symhdr->crfd * swap->external_rfd_size), + 0, (size_t) (add * swap->external_rfd_size)); + symhdr->crfd += add; + } +} + +/* Return the size required by the ECOFF debugging information. */ + +bfd_size_type +bfd_ecoff_debug_size (abfd, debug, swap) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; +{ + bfd_size_type tot; + + ecoff_align_debug (abfd, debug, swap); + tot = swap->external_hdr_size; + +#define ADD(count, size) \ + tot += debug->symbolic_header.count * size + + ADD (cbLine, sizeof (unsigned char)); + ADD (idnMax, swap->external_dnr_size); + ADD (ipdMax, swap->external_pdr_size); + ADD (isymMax, swap->external_sym_size); + ADD (ioptMax, swap->external_opt_size); + ADD (iauxMax, sizeof (union aux_ext)); + ADD (issMax, sizeof (char)); + ADD (issExtMax, sizeof (char)); + ADD (ifdMax, swap->external_fdr_size); + ADD (crfd, swap->external_rfd_size); + ADD (iextMax, swap->external_ext_size); + +#undef ADD + + return tot; +} + +/* Write out the ECOFF symbolic header, given the file position it is + going to be placed at. This assumes that the counts are set + correctly. */ + +static boolean +ecoff_write_symhdr (abfd, debug, swap, where) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + file_ptr where; +{ + HDRR * const symhdr = &debug->symbolic_header; + char *buff = NULL; + + ecoff_align_debug (abfd, debug, swap); + + /* Go to the right location in the file. */ + if (bfd_seek (abfd, where, SEEK_SET) != 0) + return false; + + where += swap->external_hdr_size; + + symhdr->magic = swap->sym_magic; + + /* Fill in the file offsets. */ +#define SET(offset, count, size) \ + if (symhdr->count == 0) \ + symhdr->offset = 0; \ + else \ + { \ + symhdr->offset = where; \ + where += symhdr->count * size; \ + } + + SET (cbLineOffset, cbLine, sizeof (unsigned char)); + SET (cbDnOffset, idnMax, swap->external_dnr_size); + SET (cbPdOffset, ipdMax, swap->external_pdr_size); + SET (cbSymOffset, isymMax, swap->external_sym_size); + SET (cbOptOffset, ioptMax, swap->external_opt_size); + SET (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + SET (cbSsOffset, issMax, sizeof (char)); + SET (cbSsExtOffset, issExtMax, sizeof (char)); + SET (cbFdOffset, ifdMax, swap->external_fdr_size); + SET (cbRfdOffset, crfd, swap->external_rfd_size); + SET (cbExtOffset, iextMax, swap->external_ext_size); +#undef SET + + buff = (PTR) bfd_malloc ((size_t) swap->external_hdr_size); + if (buff == NULL && swap->external_hdr_size != 0) + goto error_return; + + (*swap->swap_hdr_out) (abfd, symhdr, buff); + if (bfd_write (buff, 1, swap->external_hdr_size, abfd) + != swap->external_hdr_size) + goto error_return; + + if (buff != NULL) + free (buff); + return true; + error_return: + if (buff != NULL) + free (buff); + return false; +} + +/* Write out the ECOFF debugging information. This function assumes + that the information (the pointers and counts) in *DEBUG have been + set correctly. WHERE is the position in the file to write the + information to. This function fills in the file offsets in the + symbolic header. */ + +boolean +bfd_ecoff_write_debug (abfd, debug, swap, where) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + file_ptr where; +{ + HDRR * const symhdr = &debug->symbolic_header; + + if (! ecoff_write_symhdr (abfd, debug, swap, where)) + return false; + +#define WRITE(ptr, count, size, offset) \ + BFD_ASSERT (symhdr->offset == 0 \ + || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \ + if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \ + != size * symhdr->count) \ + return false; + + WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); + WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); + WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); + WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); + WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); + WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset); + WRITE (ss, issMax, sizeof (char), cbSsOffset); + WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset); + WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset); + WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset); + WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset); +#undef WRITE + + return true; +} + +/* Write out a shuffle list. */ + +static boolean ecoff_write_shuffle PARAMS ((bfd *, + const struct ecoff_debug_swap *, + struct shuffle *, PTR space)); + +static boolean +ecoff_write_shuffle (abfd, swap, shuffle, space) + bfd *abfd; + const struct ecoff_debug_swap *swap; + struct shuffle *shuffle; + PTR space; +{ + register struct shuffle *l; + unsigned long total; + + total = 0; + for (l = shuffle; l != (struct shuffle *) NULL; l = l->next) + { + if (! l->filep) + { + if (bfd_write (l->u.memory, 1, l->size, abfd) != l->size) + return false; + } + else + { + if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 + || bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size + || bfd_write (space, 1, l->size, abfd) != l->size) + return false; + } + total += l->size; + } + + if ((total & (swap->debug_align - 1)) != 0) + { + unsigned int i; + bfd_byte *s; + + i = swap->debug_align - (total & (swap->debug_align - 1)); + s = (bfd_byte *) bfd_malloc (i); + if (s == NULL && i != 0) + return false; + + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + return false; + } + free (s); + } + + return true; +} + +/* Write out debugging information using accumulated linker + information. */ + +boolean +bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) + PTR handle; + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + struct bfd_link_info *info; + file_ptr where; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + PTR space = NULL; + + if (! ecoff_write_symhdr (abfd, debug, swap, where)) + goto error_return; + + space = (PTR) bfd_malloc (ainfo->largest_file_shuffle); + if (space == NULL && ainfo->largest_file_shuffle != 0) + goto error_return; + + if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space)) + goto error_return; + + /* The string table is written out from the hash table if this is a + final link. */ + if (info->relocateable) + { + BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL); + if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space)) + goto error_return; + } + else + { + unsigned long total; + bfd_byte null; + struct string_hash_entry *sh; + + BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); + null = 0; + if (bfd_write ((PTR) &null, 1, 1, abfd) != 1) + goto error_return; + total = 1; + BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); + for (sh = ainfo->ss_hash; + sh != (struct string_hash_entry *) NULL; + sh = sh->next) + { + size_t len; + + len = strlen (sh->root.string); + if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1) + goto error_return; + total += len + 1; + } + + if ((total & (swap->debug_align - 1)) != 0) + { + unsigned int i; + bfd_byte *s; + + i = swap->debug_align - (total & (swap->debug_align - 1)); + s = (bfd_byte *) bfd_malloc (i); + if (s == NULL && i != 0) + goto error_return; + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + goto error_return; + } + free (s); + } + } + + /* The external strings and symbol are not converted over to using + shuffles. FIXME: They probably should be. */ + if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd) + != (bfd_size_type) debug->symbolic_header.issExtMax) + goto error_return; + if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0) + { + unsigned int i; + bfd_byte *s; + + i = (swap->debug_align + - (debug->symbolic_header.issExtMax & (swap->debug_align - 1))); + s = (bfd_byte *) bfd_malloc (i); + if (s == NULL && i != 0) + goto error_return; + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + goto error_return; + } + free (s); + } + + if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space)) + goto error_return; + + BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0 + || (debug->symbolic_header.cbExtOffset + == (bfd_vma) bfd_tell (abfd))); + + if (bfd_write (debug->external_ext, swap->external_ext_size, + debug->symbolic_header.iextMax, abfd) + != debug->symbolic_header.iextMax * swap->external_ext_size) + goto error_return; + + if (space != NULL) + free (space); + return true; + + error_return: + if (space != NULL) + free (space); + return false; +} + +/* Handle the find_nearest_line function for both ECOFF and MIPS ELF + files. */ + +/* Compare FDR entries. This is called via qsort. */ + +static int +cmp_fdrtab_entry (leftp, rightp) + const PTR leftp; + const PTR rightp; +{ + const struct ecoff_fdrtab_entry *lp = + (const struct ecoff_fdrtab_entry *) leftp; + const struct ecoff_fdrtab_entry *rp = + (const struct ecoff_fdrtab_entry *) rightp; + + if (lp->base_addr < rp->base_addr) + return -1; + if (lp->base_addr > rp->base_addr) + return 1; + return 0; +} + +/* Each file descriptor (FDR) has a memory address, to simplify + looking up an FDR by address, we build a table covering all FDRs + that have a least one procedure descriptor in them. The final + table will be sorted by address so we can look it up via binary + search. */ + +static boolean +mk_fdrtab (abfd, debug_info, debug_swap, line_info) + bfd *abfd; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; +{ + struct ecoff_fdrtab_entry *tab; + FDR *fdr_ptr; + FDR *fdr_start; + FDR *fdr_end; + boolean stabs; + long len; + + fdr_start = debug_info->fdr; + fdr_end = fdr_start + debug_info->symbolic_header.ifdMax; + + /* First, let's see how long the table needs to be: */ + for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) /* skip FDRs that have no PDRs */ + continue; + ++len; + } + + /* Now, create and fill in the table: */ + + line_info->fdrtab = ((struct ecoff_fdrtab_entry*) + bfd_zalloc (abfd, + len * sizeof (struct ecoff_fdrtab_entry))); + if (line_info->fdrtab == NULL) + return false; + line_info->fdrtab_len = len; + + tab = line_info->fdrtab; + for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) + continue; + + /* Check whether this file has stabs debugging information. In + a file with stabs debugging information, the second local + symbol is named @stabs. */ + stabs = false; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1)*debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = true; + } + + if (!stabs) + { + bfd_size_type external_pdr_size; + char *pdr_ptr; + PDR pdr; + + external_pdr_size = debug_swap->external_pdr_size; + + pdr_ptr = ((char *) debug_info->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* The address of the first PDR is the offset of that + procedure relative to the beginning of file FDR. */ + tab->base_addr = fdr_ptr->adr - pdr.adr; + } + else + { + /* XXX I don't know about stabs, so this is a guess + (davidm@cs.arizona.edu): */ + tab->base_addr = fdr_ptr->adr; + } + tab->fdr = fdr_ptr; + ++tab; + } + + /* Finally, the table is sorted in increasing memory-address order. + The table is mostly sorted already, but there are cases (e.g., + static functions in include files), where this does not hold. + Use "odump -PFv" to verify... */ + qsort ((PTR) line_info->fdrtab, len, + sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry); + + return true; +} + +/* Return index of first FDR that covers to OFFSET. */ + +static long +fdrtab_lookup (line_info, offset) + struct ecoff_find_line *line_info; + bfd_vma offset; +{ + long low, high, len; + long mid = -1; + struct ecoff_fdrtab_entry *tab; + + len = line_info->fdrtab_len; + if (len == 0) + return -1; + + tab = line_info->fdrtab; + for (low = 0, high = len - 1 ; low != high ;) + { + mid = (high + low) / 2; + if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr) + goto find_min; + + if (tab[mid].base_addr > offset) + high = mid; + else + low = mid + 1; + } + ++mid; + + /* last entry is catch-all for all higher addresses: */ + if (offset < tab[mid].base_addr) + return -1; + + find_min: + + while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr) + --mid; + + return mid; +} + +/* Do the work of find_nearest_line. */ + +boolean +_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap, + line_info, filename_ptr, functionname_ptr, retline_ptr) + bfd *abfd; + asection *section; + bfd_vma offset; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *retline_ptr; +{ + struct ecoff_fdrtab_entry *tab; + boolean stabs; + FDR *fdr_ptr; + int i; + + offset += section->vma; + + /* Build FDR table (sorted by object file's base-address) if we + don't have it already. */ + if (line_info->fdrtab == NULL + && !mk_fdrtab (abfd, debug_info, debug_swap, line_info)) + return false; + + tab = line_info->fdrtab; + + /* find first FDR for address OFFSET */ + i = fdrtab_lookup (line_info, offset); + if (i < 0) + return false; /* no FDR, no fun... */ + fdr_ptr = tab[i].fdr; + + /* Check whether this file has stabs debugging information. In a + file with stabs debugging information, the second local symbol is + named @stabs. */ + stabs = false; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = true; + } + + if (!stabs) + { + bfd_size_type external_pdr_size; + char *pdr_ptr; + char *best_pdr = NULL; + FDR *best_fdr; + bfd_vma best_dist = ~0; + PDR pdr; + unsigned char *line_ptr; + unsigned char *line_end; + int lineno; + /* This file uses ECOFF debugging information. Each FDR has a + list of procedure descriptors (PDR). The address in the FDR + is the absolute address of the first procedure. The address + in the first PDR gives the offset of that procedure relative + to the object file's base-address. The addresses in + subsequent PDRs specify each procedure's address relative to + the object file's base-address. To make things more juicy, + whenever the PROF bit in the PDR is set, the real entry point + of the procedure may be 16 bytes below what would normally be + the procedure's entry point. Instead, DEC came up with a + wicked scheme to create profiled libraries "on the fly": + instead of shipping a regular and a profiled version of each + library, they insert 16 bytes of unused space in front of + each procedure and set the "prof" bit in the PDR to indicate + that there is a gap there (this is done automagically by "as" + when option "-pg" is specified). Thus, normally, you link + against such a library and, except for lots of 16 byte gaps + between functions, things will behave as usual. However, + when invoking "ld" with option "-pg", it will fill those gaps + with code that calls mcount(). It then moves the function's + entry point down by 16 bytes, and out pops a binary that has + all functions profiled. + + NOTE: Neither FDRs nor PDRs are strictly sorted in memory + order. For example, when including header-files that + define functions, the FDRs follow behind the including + file, even though their code may have been generated at + a lower address. File coff-alpha.c from libbfd + illustrates this (use "odump -PFv" to look at a file's + FDR/PDR). Similarly, PDRs are sometimes out of order + as well. An example of this is OSF/1 v3.0 libc's + malloc.c. I'm not sure why this happens, but it could + be due to optimizations that reorder a function's + position within an object-file. + + Strategy: + + On the first call to this function, we build a table of FDRs + that is sorted by the base-address of the object-file the FDR + is referring to. Notice that each object-file may contain + code from multiple source files (e.g., due to code defined in + include files). Thus, for any given base-address, there may + be multiple FDRs (but this case is, fortunately, uncommon). + lookup(addr) guarantees to return the first FDR that applies + to address ADDR. Thus, after invoking lookup(), we have a + list of FDRs that may contain the PDR for ADDR. Next, we + walk through the PDRs of these FDRs and locate the one that + is closest to ADDR (i.e., for which the difference between + ADDR and the PDR's entry point is positive and minimal). + Once, the right FDR and PDR are located, we simply walk + through the line-number table to lookup the line-number that + best matches ADDR. Obviously, things could be sped up by + keeping a sorted list of PDRs instead of a sorted list of + FDRs. However, this would increase space requirements + considerably, which is undesirable. */ + external_pdr_size = debug_swap->external_pdr_size; + + /* Make offset relative to object file's start-address: */ + offset -= tab[i].base_addr; + /* Search FDR list starting at tab[i] for the PDR that best matches + OFFSET. Normally, the FDR list is only one entry long. */ + best_fdr = NULL; + do + { + bfd_vma dist, min_dist = 0; + char *pdr_hold; + char *pdr_end; + + fdr_ptr = tab[i].fdr; + + pdr_ptr = ((char *) debug_info->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Find PDR that is closest to OFFSET. If pdr.prof is set, + the procedure entry-point *may* be 0x10 below pdr.adr. We + simply pretend that pdr.prof *implies* a lower entry-point. + This is safe because it just means that may identify 4 NOPs + in front of the function as belonging to the function. */ + for (pdr_hold = NULL; + pdr_ptr < pdr_end; + (pdr_ptr += external_pdr_size, + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr))) + { + if (offset >= (pdr.adr - 0x10 * pdr.prof)) + { + dist = offset - (pdr.adr - 0x10 * pdr.prof); + if (!pdr_hold || dist < min_dist) + { + min_dist = dist; + pdr_hold = pdr_ptr; + } + } + } + + if (!best_pdr || min_dist < best_dist) + { + best_dist = min_dist; + best_fdr = fdr_ptr; + best_pdr = pdr_hold; + } + /* continue looping until base_addr of next entry is different: */ + } + while (++i < line_info->fdrtab_len + && tab[i].base_addr == tab[i - 1].base_addr); + + if (!best_fdr || !best_pdr) + return false; /* shouldn't happen... */ + + /* phew, finally we got something that we can hold onto: */ + fdr_ptr = best_fdr; + pdr_ptr = best_pdr; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Now we can look for the actual line number. The line numbers + are stored in a very funky format, which I won't try to + describe. The search is bounded by the end of the FDRs line + number entries. */ + line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine; + + /* Make offset relative to procedure entry: */ + offset -= pdr.adr - 0x10 * pdr.prof; + lineno = pdr.lnLow; + line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset; + while (line_ptr < line_end) + { + int delta; + unsigned int count; + + delta = *line_ptr >> 4; + if (delta >= 0x8) + delta -= 0x10; + count = (*line_ptr & 0xf) + 1; + ++line_ptr; + if (delta == -8) + { + delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); + if (delta >= 0x8000) + delta -= 0x10000; + line_ptr += 2; + } + lineno += delta; + if (offset < count * 4) + break; + offset -= count * 4; + } + + /* If fdr_ptr->rss is -1, then this file does not have full + symbols, at least according to gdb/mipsread.c. */ + if (fdr_ptr->rss == -1) + { + *filename_ptr = NULL; + if (pdr.isym == -1) + *functionname_ptr = NULL; + else + { + EXTR proc_ext; + + (*debug_swap->swap_ext_in) + (abfd, + ((char *) debug_info->external_ext + + pdr.isym * debug_swap->external_ext_size), + &proc_ext); + *functionname_ptr = debug_info->ssext + proc_ext.asym.iss; + } + } + else + { + SYMR proc_sym; + + *filename_ptr = debug_info->ss + fdr_ptr->issBase + fdr_ptr->rss; + (*debug_swap->swap_sym_in) + (abfd, + ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size), + &proc_sym); + *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss; + } + if (lineno == ilineNil) + lineno = 0; + *retline_ptr = lineno; + } + else + { + bfd_size_type external_sym_size; + const char *directory_name; + const char *main_file_name; + const char *current_file_name; + const char *function_name; + const char *line_file_name; + bfd_vma low_func_vma; + bfd_vma low_line_vma; + boolean past_line; + boolean past_fn; + char *sym_ptr, *sym_ptr_end; + size_t len, funclen; + char *buffer = NULL; + + /* This file uses stabs debugging information. When gcc is not + optimizing, it will put the line number information before + the function name stabs entry. When gcc is optimizing, it + will put the stabs entry for all the function first, followed + by the line number information. (This appears to happen + because of the two output files used by the -mgpopt switch, + which is implied by -O). This means that we must keep + looking through the symbols until we find both a line number + and a function name which are beyond the address we want. */ + + *filename_ptr = NULL; + *functionname_ptr = NULL; + *retline_ptr = 0; + + directory_name = NULL; + main_file_name = NULL; + current_file_name = NULL; + function_name = NULL; + line_file_name = NULL; + low_func_vma = 0; + low_line_vma = 0; + past_line = false; + past_fn = false; + + external_sym_size = debug_swap->external_sym_size; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 2) * external_sym_size); + sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size; + for (; + sym_ptr < sym_ptr_end && (! past_line || ! past_fn); + sym_ptr += external_sym_size) + { + SYMR sym; + + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + + if (ECOFF_IS_STAB (&sym)) + { + switch (ECOFF_UNMARK_STAB (sym.index)) + { + case N_SO: + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + + /* Check the next symbol to see if it is also an + N_SO symbol. */ + if (sym_ptr + external_sym_size < sym_ptr_end) + { + SYMR nextsym; + + (*debug_swap->swap_sym_in) (abfd, + sym_ptr + external_sym_size, + &nextsym); + if (ECOFF_IS_STAB (&nextsym) + && ECOFF_UNMARK_STAB (nextsym.index) == N_SO) + { + directory_name = current_file_name; + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + nextsym.iss; + sym_ptr += external_sym_size; + } + } + break; + + case N_SOL: + current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + break; + + case N_FUN: + if (sym.value > offset) + past_fn = true; + else if (sym.value >= low_func_vma) + { + low_func_vma = sym.value; + function_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + } + break; + } + } + else if (sym.st == stLabel && sym.index != indexNil) + { + if (sym.value > offset) + past_line = true; + else if (sym.value >= low_line_vma) + { + low_line_vma = sym.value; + line_file_name = current_file_name; + *retline_ptr = sym.index; + } + } + } + + if (*retline_ptr != 0) + main_file_name = line_file_name; + + /* We need to remove the stuff after the colon in the function + name. We also need to put the directory name and the file + name together. */ + if (function_name == NULL) + len = funclen = 0; + else + len = funclen = strlen (function_name) + 1; + + if (main_file_name != NULL + && directory_name != NULL + && main_file_name[0] != '/') + len += strlen (directory_name) + strlen (main_file_name) + 1; + + if (len != 0) + { + if (line_info->find_buffer != NULL) + free (line_info->find_buffer); + buffer = (char *) bfd_malloc (len); + if (buffer == NULL) + return false; + line_info->find_buffer = buffer; + } + + if (function_name != NULL) + { + char *colon; + + strcpy (buffer, function_name); + colon = strchr (buffer, ':'); + if (colon != NULL) + *colon = '\0'; + *functionname_ptr = buffer; + } + + if (main_file_name != NULL) + { + if (directory_name == NULL || main_file_name[0] == '/') + *filename_ptr = main_file_name; + else + { + sprintf (buffer + funclen, "%s%s", directory_name, + main_file_name); + *filename_ptr = buffer + funclen; + } + } + } + + return true; +} + +/* These routines copy symbolic information into a memory buffer. + + FIXME: The whole point of the shuffle code is to avoid storing + everything in memory, since the linker is such a memory hog. This + code makes that effort useless. It is only called by the MIPS ELF + code when generating a shared library, so it is not that big a + deal, but it should be fixed eventually. */ + +/* Collect a shuffle into a memory buffer. */ + +static boolean ecoff_collect_shuffle PARAMS ((struct shuffle *, bfd_byte *)); + +static boolean +ecoff_collect_shuffle (l, buff) + struct shuffle *l; + bfd_byte *buff; +{ + unsigned long total; + + total = 0; + for (; l != (struct shuffle *) NULL; l = l->next) + { + if (! l->filep) + memcpy (buff, l->u.memory, l->size); + else + { + if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 + || bfd_read (buff, 1, l->size, l->u.file.input_bfd) != l->size) + return false; + } + total += l->size; + buff += l->size; + } + + return true; +} + +/* Copy PDR information into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_pdr (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->pdr, buff); +} + +/* Copy symbol information into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_sym (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->sym, buff); +} + +/* Copy the string table into a memory buffer. */ + +boolean +_bfd_ecoff_get_accumulated_ss (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + struct string_hash_entry *sh; + unsigned long total; + + /* The string table is written out from the hash table if this is a + final link. */ + BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); + *buff++ = '\0'; + total = 1; + BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); + for (sh = ainfo->ss_hash; + sh != (struct string_hash_entry *) NULL; + sh = sh->next) + { + size_t len; + + len = strlen (sh->root.string); + memcpy (buff, (PTR) sh->root.string, len + 1); + total += len + 1; + buff += len + 1; + } + + return true; +} diff --git a/contrib/gdb/bfd/ecoffswap.h b/contrib/gdb/bfd/ecoffswap.h new file mode 100644 index 000000000000..0d28d16883e1 --- /dev/null +++ b/contrib/gdb/bfd/ecoffswap.h @@ -0,0 +1,853 @@ +/* Generic ECOFF swapping routines, for BFD. + Copyright 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* NOTE: This is a header file, but it contains executable routines. + This is done this way because these routines are substantially + similar, but are not identical, for all ECOFF targets. + + These are routines to swap the ECOFF symbolic information in and + out. The routines are defined statically. You can set breakpoints + on them in gdb by naming the including source file; e.g., + 'coff-mips.c':ecoff_swap_hdr_in. + + Before including this header file, one of ECOFF_32 or ECOFF_64 must + be defined. These are checked when swapping information that + depends upon the target size. This code works for 32 bit and 64 + bit ECOFF, but may need to be generalized in the future. + + Some header file which defines the external forms of these + structures must also be included before including this header file. + Currently this is either coff/mips.h or coff/alpha.h. + + If the symbol TEST is defined when this file is compiled, a + comparison is made to ensure that, in fact, the output is + bit-for-bit the same as the input. Of course, this symbol should + only be defined when deliberately testing the code on a machine + with the proper byte sex and such. */ + +#ifdef ECOFF_32 +#define ecoff_get_off bfd_h_get_32 +#define ecoff_put_off bfd_h_put_32 +#endif +#ifdef ECOFF_64 +#define ecoff_get_off bfd_h_get_64 +#define ecoff_put_off bfd_h_put_64 +#endif + +/* ECOFF auxiliary information swapping routines. These are the same + for all ECOFF targets, so they are defined in ecofflink.c. */ + +extern void _bfd_ecoff_swap_tir_in + PARAMS ((int, const struct tir_ext *, TIR *)); +extern void _bfd_ecoff_swap_tir_out + PARAMS ((int, const TIR *, struct tir_ext *)); +extern void _bfd_ecoff_swap_rndx_in + PARAMS ((int, const struct rndx_ext *, RNDXR *)); +extern void _bfd_ecoff_swap_rndx_out + PARAMS ((int, const RNDXR *, struct rndx_ext *)); + +/* Prototypes for functions defined in this file. */ + +static void ecoff_swap_hdr_in PARAMS ((bfd *, PTR, HDRR *)); +static void ecoff_swap_hdr_out PARAMS ((bfd *, const HDRR *, PTR)); +static void ecoff_swap_fdr_in PARAMS ((bfd *, PTR, FDR *)); +static void ecoff_swap_fdr_out PARAMS ((bfd *, const FDR *, PTR)); +static void ecoff_swap_pdr_in PARAMS ((bfd *, PTR, PDR *)); +static void ecoff_swap_pdr_out PARAMS ((bfd *, const PDR *, PTR)); +static void ecoff_swap_sym_in PARAMS ((bfd *, PTR, SYMR *)); +static void ecoff_swap_sym_out PARAMS ((bfd *, const SYMR *, PTR)); +static void ecoff_swap_ext_in PARAMS ((bfd *, PTR, EXTR *)); +static void ecoff_swap_ext_out PARAMS ((bfd *, const EXTR *, PTR)); +static void ecoff_swap_rfd_in PARAMS ((bfd *, PTR, RFDT *)); +static void ecoff_swap_rfd_out PARAMS ((bfd *, const RFDT *, PTR)); +static void ecoff_swap_opt_in PARAMS ((bfd *, PTR, OPTR *)); +static void ecoff_swap_opt_out PARAMS ((bfd *, const OPTR *, PTR)); +static void ecoff_swap_dnr_in PARAMS ((bfd *, PTR, DNR *)); +static void ecoff_swap_dnr_out PARAMS ((bfd *, const DNR *, PTR)); + +/* Swap in the symbolic header. */ + +static void +ecoff_swap_hdr_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + HDRR *intern; +{ + struct hdr_ext ext[1]; + + *ext = *(struct hdr_ext *) ext_copy; + + intern->magic = bfd_h_get_signed_16 (abfd, (bfd_byte *)ext->h_magic); + intern->vstamp = bfd_h_get_signed_16 (abfd, (bfd_byte *)ext->h_vstamp); + intern->ilineMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_ilineMax); + intern->cbLine = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbLine); + intern->cbLineOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbLineOffset); + intern->idnMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_idnMax); + intern->cbDnOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbDnOffset); + intern->ipdMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_ipdMax); + intern->cbPdOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbPdOffset); + intern->isymMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_isymMax); + intern->cbSymOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbSymOffset); + intern->ioptMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_ioptMax); + intern->cbOptOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbOptOffset); + intern->iauxMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_iauxMax); + intern->cbAuxOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbAuxOffset); + intern->issMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_issMax); + intern->cbSsOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbSsOffset); + intern->issExtMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_issExtMax); + intern->cbSsExtOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbSsExtOffset); + intern->ifdMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_ifdMax); + intern->cbFdOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbFdOffset); + intern->crfd = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_crfd); + intern->cbRfdOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbRfdOffset); + intern->iextMax = bfd_h_get_32 (abfd, (bfd_byte *)ext->h_iextMax); + intern->cbExtOffset = ecoff_get_off (abfd, (bfd_byte *)ext->h_cbExtOffset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out the symbolic header. */ + +static void +ecoff_swap_hdr_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const HDRR *intern_copy; + PTR ext_ptr; +{ + struct hdr_ext *ext = (struct hdr_ext *) ext_ptr; + HDRR intern[1]; + + *intern = *intern_copy; + + bfd_h_put_signed_16 (abfd, intern->magic, (bfd_byte *)ext->h_magic); + bfd_h_put_signed_16 (abfd, intern->vstamp, (bfd_byte *)ext->h_vstamp); + bfd_h_put_32 (abfd, intern->ilineMax, (bfd_byte *)ext->h_ilineMax); + ecoff_put_off (abfd, intern->cbLine, (bfd_byte *)ext->h_cbLine); + ecoff_put_off (abfd, intern->cbLineOffset, (bfd_byte *)ext->h_cbLineOffset); + bfd_h_put_32 (abfd, intern->idnMax, (bfd_byte *)ext->h_idnMax); + ecoff_put_off (abfd, intern->cbDnOffset, (bfd_byte *)ext->h_cbDnOffset); + bfd_h_put_32 (abfd, intern->ipdMax, (bfd_byte *)ext->h_ipdMax); + ecoff_put_off (abfd, intern->cbPdOffset, (bfd_byte *)ext->h_cbPdOffset); + bfd_h_put_32 (abfd, intern->isymMax, (bfd_byte *)ext->h_isymMax); + ecoff_put_off (abfd, intern->cbSymOffset, (bfd_byte *)ext->h_cbSymOffset); + bfd_h_put_32 (abfd, intern->ioptMax, (bfd_byte *)ext->h_ioptMax); + ecoff_put_off (abfd, intern->cbOptOffset, (bfd_byte *)ext->h_cbOptOffset); + bfd_h_put_32 (abfd, intern->iauxMax, (bfd_byte *)ext->h_iauxMax); + ecoff_put_off (abfd, intern->cbAuxOffset, (bfd_byte *)ext->h_cbAuxOffset); + bfd_h_put_32 (abfd, intern->issMax, (bfd_byte *)ext->h_issMax); + ecoff_put_off (abfd, intern->cbSsOffset, (bfd_byte *)ext->h_cbSsOffset); + bfd_h_put_32 (abfd, intern->issExtMax, (bfd_byte *)ext->h_issExtMax); + ecoff_put_off (abfd, intern->cbSsExtOffset, (bfd_byte *)ext->h_cbSsExtOffset); + bfd_h_put_32 (abfd, intern->ifdMax, (bfd_byte *)ext->h_ifdMax); + ecoff_put_off (abfd, intern->cbFdOffset, (bfd_byte *)ext->h_cbFdOffset); + bfd_h_put_32 (abfd, intern->crfd, (bfd_byte *)ext->h_crfd); + ecoff_put_off (abfd, intern->cbRfdOffset, (bfd_byte *)ext->h_cbRfdOffset); + bfd_h_put_32 (abfd, intern->iextMax, (bfd_byte *)ext->h_iextMax); + ecoff_put_off (abfd, intern->cbExtOffset, (bfd_byte *)ext->h_cbExtOffset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in the file descriptor record. */ + +static void +ecoff_swap_fdr_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + FDR *intern; +{ + struct fdr_ext ext[1]; + + *ext = *(struct fdr_ext *) ext_copy; + + intern->adr = ecoff_get_off (abfd, (bfd_byte *)ext->f_adr); + intern->rss = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_rss); +#ifdef ECOFF_64 + if (intern->rss == 0xffffffff) + intern->rss = -1; +#endif + intern->issBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_issBase); + intern->cbSs = ecoff_get_off (abfd, (bfd_byte *)ext->f_cbSs); + intern->isymBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_isymBase); + intern->csym = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_csym); + intern->ilineBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_ilineBase); + intern->cline = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_cline); + intern->ioptBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_ioptBase); + intern->copt = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_copt); +#ifdef ECOFF_32 + intern->ipdFirst = bfd_h_get_16 (abfd, (bfd_byte *)ext->f_ipdFirst); + intern->cpd = bfd_h_get_16 (abfd, (bfd_byte *)ext->f_cpd); +#endif +#ifdef ECOFF_64 + intern->ipdFirst = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_ipdFirst); + intern->cpd = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_cpd); +#endif + intern->iauxBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_iauxBase); + intern->caux = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_caux); + intern->rfdBase = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_rfdBase); + intern->crfd = bfd_h_get_32 (abfd, (bfd_byte *)ext->f_crfd); + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + intern->lang = (ext->f_bits1[0] & FDR_BITS1_LANG_BIG) + >> FDR_BITS1_LANG_SH_BIG; + intern->fMerge = 0 != (ext->f_bits1[0] & FDR_BITS1_FMERGE_BIG); + intern->fReadin = 0 != (ext->f_bits1[0] & FDR_BITS1_FREADIN_BIG); + intern->fBigendian = 0 != (ext->f_bits1[0] & FDR_BITS1_FBIGENDIAN_BIG); + intern->glevel = (ext->f_bits2[0] & FDR_BITS2_GLEVEL_BIG) + >> FDR_BITS2_GLEVEL_SH_BIG; + } else { + intern->lang = (ext->f_bits1[0] & FDR_BITS1_LANG_LITTLE) + >> FDR_BITS1_LANG_SH_LITTLE; + intern->fMerge = 0 != (ext->f_bits1[0] & FDR_BITS1_FMERGE_LITTLE); + intern->fReadin = 0 != (ext->f_bits1[0] & FDR_BITS1_FREADIN_LITTLE); + intern->fBigendian = 0 != (ext->f_bits1[0] & FDR_BITS1_FBIGENDIAN_LITTLE); + intern->glevel = (ext->f_bits2[0] & FDR_BITS2_GLEVEL_LITTLE) + >> FDR_BITS2_GLEVEL_SH_LITTLE; + } + intern->reserved = 0; + + intern->cbLineOffset = ecoff_get_off (abfd, (bfd_byte *)ext->f_cbLineOffset); + intern->cbLine = ecoff_get_off (abfd, (bfd_byte *)ext->f_cbLine); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out the file descriptor record. */ + +static void +ecoff_swap_fdr_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const FDR *intern_copy; + PTR ext_ptr; +{ + struct fdr_ext *ext = (struct fdr_ext *) ext_ptr; + FDR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + ecoff_put_off (abfd, intern->adr, (bfd_byte *)ext->f_adr); + bfd_h_put_32 (abfd, intern->rss, (bfd_byte *)ext->f_rss); + bfd_h_put_32 (abfd, intern->issBase, (bfd_byte *)ext->f_issBase); + ecoff_put_off (abfd, intern->cbSs, (bfd_byte *)ext->f_cbSs); + bfd_h_put_32 (abfd, intern->isymBase, (bfd_byte *)ext->f_isymBase); + bfd_h_put_32 (abfd, intern->csym, (bfd_byte *)ext->f_csym); + bfd_h_put_32 (abfd, intern->ilineBase, (bfd_byte *)ext->f_ilineBase); + bfd_h_put_32 (abfd, intern->cline, (bfd_byte *)ext->f_cline); + bfd_h_put_32 (abfd, intern->ioptBase, (bfd_byte *)ext->f_ioptBase); + bfd_h_put_32 (abfd, intern->copt, (bfd_byte *)ext->f_copt); +#ifdef ECOFF_32 + bfd_h_put_16 (abfd, intern->ipdFirst, (bfd_byte *)ext->f_ipdFirst); + bfd_h_put_16 (abfd, intern->cpd, (bfd_byte *)ext->f_cpd); +#endif +#ifdef ECOFF_64 + bfd_h_put_32 (abfd, intern->ipdFirst, (bfd_byte *)ext->f_ipdFirst); + bfd_h_put_32 (abfd, intern->cpd, (bfd_byte *)ext->f_cpd); +#endif + bfd_h_put_32 (abfd, intern->iauxBase, (bfd_byte *)ext->f_iauxBase); + bfd_h_put_32 (abfd, intern->caux, (bfd_byte *)ext->f_caux); + bfd_h_put_32 (abfd, intern->rfdBase, (bfd_byte *)ext->f_rfdBase); + bfd_h_put_32 (abfd, intern->crfd, (bfd_byte *)ext->f_crfd); + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_BIG) + & FDR_BITS1_LANG_BIG) + | (intern->fMerge ? FDR_BITS1_FMERGE_BIG : 0) + | (intern->fReadin ? FDR_BITS1_FREADIN_BIG : 0) + | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_BIG : 0)); + ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_BIG) + & FDR_BITS2_GLEVEL_BIG); + ext->f_bits2[1] = 0; + ext->f_bits2[2] = 0; + } else { + ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_LITTLE) + & FDR_BITS1_LANG_LITTLE) + | (intern->fMerge ? FDR_BITS1_FMERGE_LITTLE : 0) + | (intern->fReadin ? FDR_BITS1_FREADIN_LITTLE : 0) + | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_LITTLE : 0)); + ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_LITTLE) + & FDR_BITS2_GLEVEL_LITTLE); + ext->f_bits2[1] = 0; + ext->f_bits2[2] = 0; + } + + ecoff_put_off (abfd, intern->cbLineOffset, (bfd_byte *)ext->f_cbLineOffset); + ecoff_put_off (abfd, intern->cbLine, (bfd_byte *)ext->f_cbLine); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +#ifndef MPW_C + +/* Swap in the procedure descriptor record. */ + +static void +ecoff_swap_pdr_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + PDR *intern; +{ + struct pdr_ext ext[1]; + + *ext = *(struct pdr_ext *) ext_copy; + + memset ((PTR) intern, 0, sizeof (*intern)); + + intern->adr = ecoff_get_off (abfd, (bfd_byte *)ext->p_adr); + intern->isym = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_isym); + intern->iline = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_iline); + intern->regmask = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_regmask); + intern->regoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_regoffset); + intern->iopt = bfd_h_get_signed_32 (abfd, (bfd_byte *)ext->p_iopt); + intern->fregmask = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_fregmask); + intern->fregoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_fregoffset); + intern->frameoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_frameoffset); + intern->framereg = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_framereg); + intern->pcreg = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_pcreg); + intern->lnLow = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnLow); + intern->lnHigh = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnHigh); + intern->cbLineOffset = ecoff_get_off (abfd, (bfd_byte *)ext->p_cbLineOffset); + +#ifdef ECOFF_64 + intern->gp_prologue = bfd_h_get_8 (abfd, (bfd_byte *) ext->p_gp_prologue); + if (bfd_header_big_endian (abfd)) + { + intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_BIG); + intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_BIG); + intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_BIG); + intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_BIG) + << PDR_BITS1_RESERVED_SH_LEFT_BIG) + | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_BIG) + >> PDR_BITS2_RESERVED_SH_BIG)); + } + else + { + intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_LITTLE); + intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_LITTLE); + intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_LITTLE); + intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_LITTLE) + >> PDR_BITS1_RESERVED_SH_LITTLE) + | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_LITTLE) + << PDR_BITS2_RESERVED_SH_LEFT_LITTLE)); + } + intern->localoff = bfd_h_get_8 (abfd, (bfd_byte *) ext->p_localoff); +#endif + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out the procedure descriptor record. */ + +static void +ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const PDR *intern_copy; + PTR ext_ptr; +{ + struct pdr_ext *ext = (struct pdr_ext *) ext_ptr; + PDR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + ecoff_put_off (abfd, intern->adr, (bfd_byte *)ext->p_adr); + bfd_h_put_32 (abfd, intern->isym, (bfd_byte *)ext->p_isym); + bfd_h_put_32 (abfd, intern->iline, (bfd_byte *)ext->p_iline); + bfd_h_put_32 (abfd, intern->regmask, (bfd_byte *)ext->p_regmask); + bfd_h_put_32 (abfd, intern->regoffset, (bfd_byte *)ext->p_regoffset); + bfd_h_put_32 (abfd, intern->iopt, (bfd_byte *)ext->p_iopt); + bfd_h_put_32 (abfd, intern->fregmask, (bfd_byte *)ext->p_fregmask); + bfd_h_put_32 (abfd, intern->fregoffset, (bfd_byte *)ext->p_fregoffset); + bfd_h_put_32 (abfd, intern->frameoffset, (bfd_byte *)ext->p_frameoffset); + bfd_h_put_16 (abfd, intern->framereg, (bfd_byte *)ext->p_framereg); + bfd_h_put_16 (abfd, intern->pcreg, (bfd_byte *)ext->p_pcreg); + bfd_h_put_32 (abfd, intern->lnLow, (bfd_byte *)ext->p_lnLow); + bfd_h_put_32 (abfd, intern->lnHigh, (bfd_byte *)ext->p_lnHigh); + ecoff_put_off (abfd, intern->cbLineOffset, (bfd_byte *)ext->p_cbLineOffset); + +#ifdef ECOFF_64 + bfd_h_put_8 (abfd, intern->gp_prologue, (bfd_byte *) ext->p_gp_prologue); + if (bfd_header_big_endian (abfd)) + { + ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_BIG : 0) + | (intern->reg_frame ? PDR_BITS1_REG_FRAME_BIG : 0) + | (intern->prof ? PDR_BITS1_PROF_BIG : 0) + | ((intern->reserved + >> PDR_BITS1_RESERVED_SH_LEFT_BIG) + & PDR_BITS1_RESERVED_BIG)); + ext->p_bits2[0] = ((intern->reserved << PDR_BITS2_RESERVED_SH_BIG) + & PDR_BITS2_RESERVED_BIG); + } + else + { + ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_LITTLE : 0) + | (intern->reg_frame ? PDR_BITS1_REG_FRAME_LITTLE : 0) + | (intern->prof ? PDR_BITS1_PROF_LITTLE : 0) + | ((intern->reserved << PDR_BITS1_RESERVED_SH_LITTLE) + & PDR_BITS1_RESERVED_LITTLE)); + ext->p_bits2[0] = ((intern->reserved >> + PDR_BITS2_RESERVED_SH_LEFT_LITTLE) + & PDR_BITS2_RESERVED_LITTLE); + } + bfd_h_put_8 (abfd, intern->localoff, (bfd_byte *) ext->p_localoff); +#endif + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +#else /* MPW_C */ +/* Same routines, but with ECOFF_64 code removed, so ^&%$#&! MPW C doesn't + corrupt itself and then freak out. */ +/* Swap in the procedure descriptor record. */ + +static void +ecoff_swap_pdr_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + PDR *intern; +{ + struct pdr_ext ext[1]; + + *ext = *(struct pdr_ext *) ext_copy; + + intern->adr = ecoff_get_off (abfd, (bfd_byte *)ext->p_adr); + intern->isym = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_isym); + intern->iline = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_iline); + intern->regmask = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_regmask); + intern->regoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_regoffset); + intern->iopt = bfd_h_get_signed_32 (abfd, (bfd_byte *)ext->p_iopt); + intern->fregmask = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_fregmask); + intern->fregoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_fregoffset); + intern->frameoffset = bfd_h_get_signed_32 (abfd, + (bfd_byte *)ext->p_frameoffset); + intern->framereg = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_framereg); + intern->pcreg = bfd_h_get_16 (abfd, (bfd_byte *)ext->p_pcreg); + intern->lnLow = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnLow); + intern->lnHigh = bfd_h_get_32 (abfd, (bfd_byte *)ext->p_lnHigh); + intern->cbLineOffset = ecoff_get_off (abfd, (bfd_byte *)ext->p_cbLineOffset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out the procedure descriptor record. */ + +static void +ecoff_swap_pdr_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const PDR *intern_copy; + PTR ext_ptr; +{ + struct pdr_ext *ext = (struct pdr_ext *) ext_ptr; + PDR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + ecoff_put_off (abfd, intern->adr, (bfd_byte *)ext->p_adr); + bfd_h_put_32 (abfd, intern->isym, (bfd_byte *)ext->p_isym); + bfd_h_put_32 (abfd, intern->iline, (bfd_byte *)ext->p_iline); + bfd_h_put_32 (abfd, intern->regmask, (bfd_byte *)ext->p_regmask); + bfd_h_put_32 (abfd, intern->regoffset, (bfd_byte *)ext->p_regoffset); + bfd_h_put_32 (abfd, intern->iopt, (bfd_byte *)ext->p_iopt); + bfd_h_put_32 (abfd, intern->fregmask, (bfd_byte *)ext->p_fregmask); + bfd_h_put_32 (abfd, intern->fregoffset, (bfd_byte *)ext->p_fregoffset); + bfd_h_put_32 (abfd, intern->frameoffset, (bfd_byte *)ext->p_frameoffset); + bfd_h_put_16 (abfd, intern->framereg, (bfd_byte *)ext->p_framereg); + bfd_h_put_16 (abfd, intern->pcreg, (bfd_byte *)ext->p_pcreg); + bfd_h_put_32 (abfd, intern->lnLow, (bfd_byte *)ext->p_lnLow); + bfd_h_put_32 (abfd, intern->lnHigh, (bfd_byte *)ext->p_lnHigh); + ecoff_put_off (abfd, intern->cbLineOffset, (bfd_byte *)ext->p_cbLineOffset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} +#endif /* MPW_C */ + +/* Swap in a symbol record. */ + +static void +ecoff_swap_sym_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + SYMR *intern; +{ + struct sym_ext ext[1]; + + *ext = *(struct sym_ext *) ext_copy; + + intern->iss = bfd_h_get_32 (abfd, (bfd_byte *)ext->s_iss); + intern->value = ecoff_get_off (abfd, (bfd_byte *)ext->s_value); + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + intern->st = (ext->s_bits1[0] & SYM_BITS1_ST_BIG) + >> SYM_BITS1_ST_SH_BIG; + intern->sc = ((ext->s_bits1[0] & SYM_BITS1_SC_BIG) + << SYM_BITS1_SC_SH_LEFT_BIG) + | ((ext->s_bits2[0] & SYM_BITS2_SC_BIG) + >> SYM_BITS2_SC_SH_BIG); + intern->reserved = 0 != (ext->s_bits2[0] & SYM_BITS2_RESERVED_BIG); + intern->index = ((ext->s_bits2[0] & SYM_BITS2_INDEX_BIG) + << SYM_BITS2_INDEX_SH_LEFT_BIG) + | (ext->s_bits3[0] << SYM_BITS3_INDEX_SH_LEFT_BIG) + | (ext->s_bits4[0] << SYM_BITS4_INDEX_SH_LEFT_BIG); + } else { + intern->st = (ext->s_bits1[0] & SYM_BITS1_ST_LITTLE) + >> SYM_BITS1_ST_SH_LITTLE; + intern->sc = ((ext->s_bits1[0] & SYM_BITS1_SC_LITTLE) + >> SYM_BITS1_SC_SH_LITTLE) + | ((ext->s_bits2[0] & SYM_BITS2_SC_LITTLE) + << SYM_BITS2_SC_SH_LEFT_LITTLE); + intern->reserved = 0 != (ext->s_bits2[0] & SYM_BITS2_RESERVED_LITTLE); + intern->index = ((ext->s_bits2[0] & SYM_BITS2_INDEX_LITTLE) + >> SYM_BITS2_INDEX_SH_LITTLE) + | (ext->s_bits3[0] << SYM_BITS3_INDEX_SH_LEFT_LITTLE) + | ((unsigned int) ext->s_bits4[0] + << SYM_BITS4_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a symbol record. */ + +static void +ecoff_swap_sym_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const SYMR *intern_copy; + PTR ext_ptr; +{ + struct sym_ext *ext = (struct sym_ext *) ext_ptr; + SYMR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + bfd_h_put_32 (abfd, intern->iss, (bfd_byte *)ext->s_iss); + ecoff_put_off (abfd, intern->value, (bfd_byte *)ext->s_value); + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_BIG) + & SYM_BITS1_ST_BIG) + | ((intern->sc >> SYM_BITS1_SC_SH_LEFT_BIG) + & SYM_BITS1_SC_BIG)); + ext->s_bits2[0] = (((intern->sc << SYM_BITS2_SC_SH_BIG) + & SYM_BITS2_SC_BIG) + | (intern->reserved ? SYM_BITS2_RESERVED_BIG : 0) + | ((intern->index >> SYM_BITS2_INDEX_SH_LEFT_BIG) + & SYM_BITS2_INDEX_BIG)); + ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_BIG) & 0xff; + ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_BIG) & 0xff; + } else { + ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_LITTLE) + & SYM_BITS1_ST_LITTLE) + | ((intern->sc << SYM_BITS1_SC_SH_LITTLE) + & SYM_BITS1_SC_LITTLE)); + ext->s_bits2[0] = (((intern->sc >> SYM_BITS2_SC_SH_LEFT_LITTLE) + & SYM_BITS2_SC_LITTLE) + | (intern->reserved ? SYM_BITS2_RESERVED_LITTLE : 0) + | ((intern->index << SYM_BITS2_INDEX_SH_LITTLE) + & SYM_BITS2_INDEX_LITTLE)); + ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_LITTLE) & 0xff; + ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_LITTLE) & 0xff; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in an external symbol record. */ + +static void +ecoff_swap_ext_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + EXTR *intern; +{ + struct ext_ext ext[1]; + + *ext = *(struct ext_ext *) ext_copy; + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + intern->jmptbl = 0 != (ext->es_bits1[0] & EXT_BITS1_JMPTBL_BIG); + intern->cobol_main = 0 != (ext->es_bits1[0] & EXT_BITS1_COBOL_MAIN_BIG); + intern->weakext = 0 != (ext->es_bits1[0] & EXT_BITS1_WEAKEXT_BIG); + } else { + intern->jmptbl = 0 != (ext->es_bits1[0] & EXT_BITS1_JMPTBL_LITTLE); + intern->cobol_main = 0 != (ext->es_bits1[0] & EXT_BITS1_COBOL_MAIN_LITTLE); + intern->weakext = 0 != (ext->es_bits1[0] & EXT_BITS1_WEAKEXT_LITTLE); + } + intern->reserved = 0; + +#ifdef ECOFF_32 + intern->ifd = bfd_h_get_signed_16 (abfd, (bfd_byte *)ext->es_ifd); +#endif +#ifdef ECOFF_64 + intern->ifd = bfd_h_get_signed_32 (abfd, (bfd_byte *)ext->es_ifd); +#endif + + ecoff_swap_sym_in (abfd, &ext->es_asym, &intern->asym); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out an external symbol record. */ + +static void +ecoff_swap_ext_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const EXTR *intern_copy; + PTR ext_ptr; +{ + struct ext_ext *ext = (struct ext_ext *) ext_ptr; + EXTR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bfd_header_big_endian (abfd)) { + ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_BIG : 0) + | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_BIG : 0) + | (intern->weakext ? EXT_BITS1_WEAKEXT_BIG : 0)); + ext->es_bits2[0] = 0; +#ifdef ECOFF_64 + ext->es_bits2[1] = 0; + ext->es_bits2[2] = 0; +#endif + } else { + ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_LITTLE : 0) + | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_LITTLE : 0) + | (intern->weakext ? EXT_BITS1_WEAKEXT_LITTLE : 0)); + ext->es_bits2[0] = 0; +#ifdef ECOFF_64 + ext->es_bits2[1] = 0; + ext->es_bits2[2] = 0; +#endif + } + +#ifdef ECOFF_32 + bfd_h_put_signed_16 (abfd, intern->ifd, (bfd_byte *)ext->es_ifd); +#endif +#ifdef ECOFF_64 + bfd_h_put_signed_32 (abfd, intern->ifd, (bfd_byte *)ext->es_ifd); +#endif + + ecoff_swap_sym_out (abfd, &intern->asym, &ext->es_asym); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a relative file descriptor. */ + +static void +ecoff_swap_rfd_in (abfd, ext_ptr, intern) + bfd *abfd; + PTR ext_ptr; + RFDT *intern; +{ + struct rfd_ext *ext = (struct rfd_ext *) ext_ptr; + + *intern = bfd_h_get_32 (abfd, (bfd_byte *)ext->rfd); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a relative file descriptor. */ + +static void +ecoff_swap_rfd_out (abfd, intern, ext_ptr) + bfd *abfd; + const RFDT *intern; + PTR ext_ptr; +{ + struct rfd_ext *ext = (struct rfd_ext *) ext_ptr; + + bfd_h_put_32 (abfd, *intern, (bfd_byte *)ext->rfd); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in an optimization symbol. */ + +static void +ecoff_swap_opt_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + OPTR *intern; +{ + struct opt_ext ext[1]; + + *ext = *(struct opt_ext *) ext_copy; + + if (bfd_header_big_endian (abfd)) + { + intern->ot = ext->o_bits1[0]; + intern->value = (((unsigned int) ext->o_bits2[0] + << OPT_BITS2_VALUE_SH_LEFT_BIG) + | ((unsigned int) ext->o_bits3[0] + << OPT_BITS2_VALUE_SH_LEFT_BIG) + | ((unsigned int) ext->o_bits4[0] + << OPT_BITS2_VALUE_SH_LEFT_BIG)); + } + else + { + intern->ot = ext->o_bits1[0]; + intern->value = ((ext->o_bits2[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE) + | (ext->o_bits3[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE) + | (ext->o_bits4[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE)); + } + + _bfd_ecoff_swap_rndx_in (bfd_header_big_endian (abfd), + &ext->o_rndx, &intern->rndx); + + intern->offset = bfd_h_get_32 (abfd, (bfd_byte *) ext->o_offset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out an optimization symbol. */ + +static void +ecoff_swap_opt_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const OPTR *intern_copy; + PTR ext_ptr; +{ + struct opt_ext *ext = (struct opt_ext *) ext_ptr; + OPTR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + if (bfd_header_big_endian (abfd)) + { + ext->o_bits1[0] = intern->ot; + ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_BIG; + ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_BIG; + ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_BIG; + } + else + { + ext->o_bits1[0] = intern->ot; + ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_LITTLE; + ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_LITTLE; + ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_LITTLE; + } + + _bfd_ecoff_swap_rndx_out (bfd_header_big_endian (abfd), + &intern->rndx, &ext->o_rndx); + + bfd_h_put_32 (abfd, intern->value, (bfd_byte *) ext->o_offset); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a dense number. */ + +static void +ecoff_swap_dnr_in (abfd, ext_copy, intern) + bfd *abfd; + PTR ext_copy; + DNR *intern; +{ + struct dnr_ext ext[1]; + + *ext = *(struct dnr_ext *) ext_copy; + + intern->rfd = bfd_h_get_32 (abfd, (bfd_byte *) ext->d_rfd); + intern->index = bfd_h_get_32 (abfd, (bfd_byte *) ext->d_index); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a dense number. */ + +static void +ecoff_swap_dnr_out (abfd, intern_copy, ext_ptr) + bfd *abfd; + const DNR *intern_copy; + PTR ext_ptr; +{ + struct dnr_ext *ext = (struct dnr_ext *) ext_ptr; + DNR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + bfd_h_put_32 (abfd, intern->rfd, (bfd_byte *) ext->d_rfd); + bfd_h_put_32 (abfd, intern->index, (bfd_byte *) ext->d_index); + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} diff --git a/contrib/gdb/bfd/elf-bfd.h b/contrib/gdb/bfd/elf-bfd.h new file mode 100644 index 000000000000..ee38e5b12f4c --- /dev/null +++ b/contrib/gdb/bfd/elf-bfd.h @@ -0,0 +1,858 @@ +/* BFD back-end data structures for ELF files. + Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ 1 + +#include "elf/common.h" +#include "elf/internal.h" +#include "elf/external.h" +#include "bfdlink.h" + +/* If size isn't specified as 64 or 32, NAME macro should fail. */ +#ifndef NAME +#if ARCH_SIZE==64 +#define NAME(x,y) CAT4(x,64,_,y) +#endif +#if ARCH_SIZE==32 +#define NAME(x,y) CAT4(x,32,_,y) +#endif +#endif + +#ifndef NAME +#define NAME(x,y) CAT4(x,NOSIZE,_,y) +#endif + +#define ElfNAME(X) NAME(Elf,X) +#define elfNAME(X) NAME(elf,X) + +/* Information held for an ELF symbol. The first field is the + corresponding asymbol. Every symbol is an ELF file is actually a + pointer to this structure, although it is often handled as a + pointer to an asymbol. */ + +typedef struct +{ + /* The BFD symbol. */ + asymbol symbol; + /* ELF symbol information. */ + Elf_Internal_Sym internal_elf_sym; + /* Backend specific information. */ + union + { + unsigned int hppa_arg_reloc; + PTR mips_extr; + PTR any; + } + tc_data; +} elf_symbol_type; + +/* ELF linker hash table entries. */ + +struct elf_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. This is initialized to -1. It is + set to -2 if the symbol is used by a reloc. */ + long indx; + + /* Symbol size. */ + bfd_size_type size; + + /* Symbol index as a dynamic symbol. Initialized to -1, and remains + -1 if this is not a dynamic symbol. */ + long dynindx; + + /* String table index in .dynstr if this is a dynamic symbol. */ + unsigned long dynstr_index; + + /* If this is a weak defined symbol from a dynamic object, this + field points to a defined symbol with the same value, if there is + one. Otherwise it is NULL. */ + struct elf_link_hash_entry *weakdef; + + /* If this symbol requires an entry in the global offset table, the + processor specific backend uses this field to hold the offset + into the .got section. If this field is -1, then the symbol does + not require a global offset table entry. */ + bfd_vma got_offset; + + /* If this symbol requires an entry in the procedure linkage table, + the processor specific backend uses these two fields to hold the + offset into the procedure linkage section and the offset into the + .got section. If plt_offset is -1, then the symbol does not + require an entry in the procedure linkage table. */ + bfd_vma plt_offset; + + /* If this symbol is used in the linker created sections, the processor + specific backend uses this field to map the field into the offset + from the beginning of the section. */ + struct elf_linker_section_pointers *linker_section_pointer; + + /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ + char type; + + /* Some flags; legal values follow. */ + unsigned char elf_link_hash_flags; + /* Symbol is referenced by a non-shared object. */ +#define ELF_LINK_HASH_REF_REGULAR 01 + /* Symbol is defined by a non-shared object. */ +#define ELF_LINK_HASH_DEF_REGULAR 02 + /* Symbol is referenced by a shared object. */ +#define ELF_LINK_HASH_REF_DYNAMIC 04 + /* Symbol is defined by a shared object. */ +#define ELF_LINK_HASH_DEF_DYNAMIC 010 + /* Dynamic symbol has been adjustd. */ +#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 020 + /* Symbol needs a copy reloc. */ +#define ELF_LINK_HASH_NEEDS_COPY 040 + /* Symbol needs a procedure linkage table entry. */ +#define ELF_LINK_HASH_NEEDS_PLT 0100 + /* Symbol appears in a non-ELF input file. */ +#define ELF_LINK_NON_ELF 0200 + /* Note: If you add more flags, you must change the type of + elf_link_hash_flags. */ +}; + +/* ELF linker hash table. */ + +struct elf_link_hash_table +{ + struct bfd_link_hash_table root; + /* Whether we have created the special dynamic sections required + when linking against or generating a shared object. */ + boolean dynamic_sections_created; + /* The BFD used to hold special sections created by the linker. + This will be the first BFD found which requires these sections to + be created. */ + bfd *dynobj; + /* The number of symbols found in the link which must be put into + the .dynsym section. */ + bfd_size_type dynsymcount; + /* The string table of dynamic symbols, which becomes the .dynstr + section. */ + struct bfd_strtab_hash *dynstr; + /* The number of buckets in the hash table in the .hash section. + This is based on the number of dynamic symbols. */ + bfd_size_type bucketcount; + /* A linked list of DT_NEEDED names found in dynamic objects + included in the link. */ + struct bfd_link_needed_list *needed; +}; + +/* Look up an entry in an ELF linker hash table. */ + +#define elf_link_hash_lookup(table, string, create, copy, follow) \ + ((struct elf_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse an ELF linker hash table. */ + +#define elf_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the ELF linker hash table from a link_info structure. */ + +#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) + +/* Constant information held for an ELF backend. */ + +struct elf_size_info { + unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; + unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; + + unsigned char arch_size, file_align; + unsigned char elfclass, ev_current; + int (*write_out_phdrs) PARAMS ((bfd *, Elf_Internal_Phdr *, int)); + boolean (*write_shdrs_and_ehdr) PARAMS ((bfd *)); + void (*write_relocs) PARAMS ((bfd *, asection *, PTR)); + void (*swap_symbol_out) PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); + boolean (*slurp_reloc_table) PARAMS ((bfd *, asection *, asymbol **)); + long (*slurp_symbol_table) PARAMS ((bfd *, asymbol **, boolean)); + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); +}; + +#define elf_symbol_from(ABFD,S) \ + (((S)->the_bfd->xvec->flavour == bfd_target_elf_flavour \ + && (S)->the_bfd->tdata.elf_obj_data != 0) \ + ? (elf_symbol_type *) (S) \ + : 0) + +struct elf_backend_data +{ + /* Whether the backend uses REL or RELA relocations. FIXME: some + ELF backends use both. When we need to support one, this whole + approach will need to be changed. */ + int use_rela_p; + + /* The architecture for this backend. */ + enum bfd_architecture arch; + + /* The ELF machine code (EM_xxxx) for this backend. */ + int elf_machine_code; + + /* The maximum page size for this backend. */ + bfd_vma maxpagesize; + + /* 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 + section. */ + boolean collect; + + /* This is true if the linker should ignore changes to the type of a + symbol. This is true for MIPS ELF because some Irix 5 objects + record undefined functions as STT_OBJECT although the definitions + are STT_FUNC. */ + boolean type_change_ok; + + /* A function to translate an ELF RELA relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto) PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + + /* A function to translate an ELF REL relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *, + Elf_Internal_Rel *)); + + /* A function to determine whether a symbol is global when + partitioning the symbol table into local and global symbols. + This should be NULL for most targets, in which case the correct + thing will be done. MIPS ELF, at least on the Irix 5, has + special requirements. */ + boolean (*elf_backend_sym_is_global) PARAMS ((bfd *, asymbol *)); + + /* The remaining functions are hooks which are called only if they + are not NULL. */ + + /* A function to permit a backend specific check on whether a + particular BFD format is relevant for an object file, and to + permit the backend to set any global information it wishes. When + this is called elf_elfheader is set, but anything else should be + used with caution. If this returns false, the check_format + routine will return a bfd_error_wrong_format error. */ + boolean (*elf_backend_object_p) PARAMS ((bfd *)); + + /* A function to do additional symbol processing when reading the + ELF symbol table. This is where any processor-specific special + section indices are handled. */ + void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *)); + + /* A function to do additional symbol processing after reading the + entire ELF symbol table. */ + boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, + elf_symbol_type *, + unsigned int)); + + /* A function to do additional processing on the ELF section header + just before writing it out. This is used to set the flags and + type fields for some sections, or to actually write out data for + unusual sections. */ + boolean (*elf_backend_section_processing) PARAMS ((bfd *, + Elf32_Internal_Shdr *)); + + /* A function to handle unusual section types when creating BFD + sections from ELF sections. */ + boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, + Elf32_Internal_Shdr *, + char *)); + + /* A function to set up the ELF section header for a BFD section in + preparation for writing it out. This is where the flags and type + fields are set for unusual sections. */ + boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, + asection *)); + + /* A function to get the ELF section index for a BFD section. If + this returns true, the section was found. If it is a normal ELF + section, *RETVAL should be left unchanged. If it is not a normal + ELF section *RETVAL should be set to the SHN_xxxx index. */ + boolean (*elf_backend_section_from_bfd_section) + PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *retval)); + + /* If this field is not NULL, it is called by the add_symbols phase + of a link just before adding a symbol to the global linker hash + table. It may modify any of the fields as it wishes. If *NAME + is set to NULL, the symbol will be skipped rather than being + added to the hash table. This function is responsible for + handling all processor dependent symbol bindings and section + indices, and must set at least *FLAGS and *SEC for each processor + dependent case; failure to do so will cause a link error. */ + boolean (*elf_add_symbol_hook) + PARAMS ((bfd *abfd, struct bfd_link_info *info, + const Elf_Internal_Sym *, const char **name, + flagword *flags, asection **sec, bfd_vma *value)); + + /* If this field is not NULL, it is called by the elf_link_output_sym + phase of a link for each symbol which will appear in the object file. */ + boolean (*elf_backend_link_output_symbol_hook) + PARAMS ((bfd *, struct bfd_link_info *info, const char *, + Elf_Internal_Sym *, asection *)); + + /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend + linker the first time it encounters a dynamic object in the link. + This function must create any sections required for dynamic + linking. The ABFD argument is a dynamic object. The .interp, + .dynamic, .dynsym, .dynstr, and .hash functions have already been + created, and this function may modify the section flags if + desired. This function will normally create the .got and .plt + sections, but different backends have different requirements. */ + boolean (*elf_backend_create_dynamic_sections) + PARAMS ((bfd *abfd, struct bfd_link_info *info)); + + /* The CHECK_RELOCS function is called by the add_symbols phase of + the ELF backend linker. It is called once for each section with + relocs of an object file, just after the symbols for the object + file have been added to the global linker hash table. The + function must look through the relocs and do any special handling + required. This generally means allocating space in the global + offset table, and perhaps allocating space for a reloc. The + relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. */ + boolean (*check_relocs) + PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs)); + + /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend + linker for every symbol which is defined by a dynamic object and + referenced by a regular object. This is called after all the + input files have been seen, but before the SIZE_DYNAMIC_SECTIONS + function has been called. The hash table entry should be + bfd_link_hash_defined ore bfd_link_hash_defweak, and it should be + defined in a section from a dynamic object. Dynamic object + sections are not included in the final link, and this function is + responsible for changing the value to something which the rest of + the link can deal with. This will normally involve adding an + entry to the .plt or .got or some such section, and setting the + symbol to point to that. */ + boolean (*elf_backend_adjust_dynamic_symbol) + PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h)); + + /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend + linker after all the linker input files have been seen but before + the sections sizes have been set. This is called after + ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols. + It is only called when linking against a dynamic object. It must + set the sizes of the dynamic sections, and may fill in their + contents as well. The generic ELF linker can handle the .dynsym, + .dynstr and .hash sections. This function must handle the + .interp section and any sections created by the + CREATE_DYNAMIC_SECTIONS entry point. */ + boolean (*elf_backend_size_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* The RELOCATE_SECTION function is called by the ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjust the section contents as + necessary, and (if using Rela relocs and generating a + relocateable output file) adjusting the reloc addend as + necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocateable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + boolean (*elf_backend_relocate_section) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info, + bfd *input_bfd, asection *input_section, bfd_byte *contents, + Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms, + asection **local_sections)); + + /* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend + linker just before it writes a symbol out to the .dynsym section. + The processor backend may make any required adjustment to the + symbol. It may also take the opportunity to set contents of the + dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on + all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called + on those symbols which are defined by a dynamic object. */ + boolean (*elf_backend_finish_dynamic_symbol) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)); + + /* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend + linker just before it writes all the dynamic sections out to the + output file. The FINISH_DYNAMIC_SYMBOL will have been called on + all dynamic symbols. */ + boolean (*elf_backend_finish_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* A function to do any beginning processing needed for the ELF file + before building the ELF headers and computing file positions. */ + void (*elf_backend_begin_write_processing) + PARAMS ((bfd *, struct bfd_link_info *)); + + /* A function to do any final processing needed for the ELF file + before writing it out. The LINKER argument is true if this BFD + was created by the ELF backend linker. */ + void (*elf_backend_final_write_processing) + PARAMS ((bfd *, boolean linker)); + + /* This function is called by get_program_header_size. It should + return the number of additional program segments which this BFD + will need. It should return -1 on error. */ + int (*elf_backend_additional_program_headers) PARAMS ((bfd *)); + + /* This function is called to modify an existing segment map in a + backend specific fashion. */ + boolean (*elf_backend_modify_segment_map) PARAMS ((bfd *)); + + /* The swapping table to use when dealing with ECOFF information. + Used for the MIPS ELF .mdebug section. */ + const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; + + /* Alternate EM_xxxx machine codes for this backend. */ + int elf_machine_alt1; + int elf_machine_alt2; + + const struct elf_size_info *s; + + unsigned want_got_plt : 1; + unsigned plt_readonly : 1; + unsigned want_plt_sym : 1; +}; + +/* Information stored for each BFD section in an ELF file. This + structure is allocated by elf_new_section_hook. */ + +struct bfd_elf_section_data +{ + /* The ELF header for this section. */ + Elf_Internal_Shdr this_hdr; + /* The ELF header for the reloc section associated with this + section, if any. */ + Elf_Internal_Shdr rel_hdr; + /* The ELF section number of this section. Only used for an output + file. */ + int this_idx; + /* The ELF section number of the reloc section associated with this + section, if any. Only used for an output file. */ + int rel_idx; + /* Used by the backend linker to store the symbol hash table entries + associated with relocs against global symbols. */ + struct elf_link_hash_entry **rel_hashes; + /* A pointer to the swapped relocs. If the section uses REL relocs, + rather than RELA, all the r_addend fields will be zero. This + pointer may be NULL. It is used by the backend linker. */ + Elf_Internal_Rela *relocs; + /* Used by the backend linker when generating a shared library to + record the dynamic symbol index for a section symbol + corresponding to this section. */ + long dynindx; + /* A pointer available for the processor specific ELF backend. */ + PTR tdata; +}; + +#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) + +#define get_elf_backend_data(abfd) \ + ((struct elf_backend_data *) (abfd)->xvec->backend_data) + +/* Enumeration to specify the special section. */ +typedef enum elf_linker_section_enum +{ + LINKER_SECTION_UNKNOWN, /* not used */ + LINKER_SECTION_GOT, /* .got section for global offset pointers */ + LINKER_SECTION_PLT, /* .plt section for generated procedure stubs */ + LINKER_SECTION_SDATA, /* .sdata/.sbss section for PowerPC */ + LINKER_SECTION_SDATA2, /* .sdata2/.sbss2 section for PowerPC */ + LINKER_SECTION_MAX /* # of linker sections */ +} elf_linker_section_enum_t; + +/* Sections created by the linker. */ + +typedef struct elf_linker_section +{ + char *name; /* name of the section */ + char *rel_name; /* name of the associated .rel{,a}. section */ + char *bss_name; /* name of a related .bss section */ + char *sym_name; /* name of symbol to reference this section */ + asection *section; /* pointer to the section */ + asection *bss_section; /* pointer to the bss section associated with this */ + asection *rel_section; /* pointer to the relocations needed for this section */ + struct elf_link_hash_entry *sym_hash; /* pointer to the created symbol hash value */ + bfd_vma initial_size; /* initial size before any linker generated allocations */ + bfd_vma sym_offset; /* offset of symbol from beginning of section */ + bfd_vma hole_size; /* size of reserved address hole in allocation */ + bfd_vma hole_offset; /* current offset for the hole */ + bfd_vma max_hole_offset; /* maximum offset for the hole */ + elf_linker_section_enum_t which; /* which section this is */ + boolean hole_written_p; /* whether the hole has been initialized */ + int alignment; /* alignment for the section */ + flagword flags; /* flags to use to create the section */ +} elf_linker_section_t; + +/* Linked list of allocated pointer entries. This hangs off of the symbol lists, and + provides allows us to return different pointers, based on different addend's. */ + +typedef struct elf_linker_section_pointers +{ + struct elf_linker_section_pointers *next; /* next allocated pointer for this symbol */ + bfd_vma offset; /* offset of pointer from beginning of section */ + bfd_signed_vma addend; /* addend used */ + elf_linker_section_enum_t which; /* which linker section this is */ + boolean written_address_p; /* whether address was written yet */ +} elf_linker_section_pointers_t; + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +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 bfd_strtab_hash *strtab_ptr; + int num_locals; + int num_globals; + asymbol **section_syms; /* STT_SECTION symbols for each section */ + Elf_Internal_Shdr symtab_hdr; + Elf_Internal_Shdr shstrtab_hdr; + Elf_Internal_Shdr strtab_hdr; + Elf_Internal_Shdr dynsymtab_hdr; + Elf_Internal_Shdr dynstrtab_hdr; + unsigned int symtab_section, shstrtab_section; + unsigned int strtab_section, dynsymtab_section; + file_ptr next_file_pos; + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ + bfd_vma gp; /* The gp value (MIPS only, for now) */ + unsigned int gp_size; /* The gp size (MIPS only, for now) */ + + /* This is set to true if the object was created by the backend + linker. */ + boolean linker; + + /* A mapping from external symbols to entries in the linker hash + table, used when linking. This is indexed by the symbol index + minus the sh_info field of the symbol table header. */ + struct elf_link_hash_entry **sym_hashes; + + /* A mapping from local symbols to offsets into the global offset + table, used when linking. This is indexed by the symbol index. */ + bfd_vma *local_got_offsets; + + /* A mapping from local symbols to offsets into the various linker + sections added. This is index by the symbol index. */ + elf_linker_section_pointers_t **linker_section_pointers; + + /* The linker ELF emulation code needs to let the backend ELF linker + know what filename should be used for a dynamic object if the + dynamic object is found using a search. The emulation code then + sometimes needs to know what name was actually used. Until the + file has been added to the linker symbol table, this field holds + the name the linker wants. After it has been added, it holds the + name actually used, which will be the DT_SONAME entry if there is + one. */ + const char *dt_name; + + /* 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. */ + boolean bad_symtab; + + /* Records the result of `get_program_header_size'. */ + bfd_size_type program_header_size; + + /* Used by find_nearest_line entry point. */ + PTR 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; + + /* Used to determine if the e_flags field has been initialized */ + boolean flags_init; + + /* Linker sections that we are interested in. */ + struct elf_linker_section *linker_section[ (int)LINKER_SECTION_MAX ]; +}; + +#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) +#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) +#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_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 core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) +#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) +#define elf_gp(bfd) (elf_tdata(bfd) -> gp) +#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) +#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) +#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got_offsets) +#define elf_local_ptr_offsets(bfd) (elf_tdata(bfd) -> linker_section_pointers) +#define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name) +#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) +#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) +#define elf_linker_section(bfd,n) (elf_tdata(bfd) -> linker_section[(int)n]) + +extern int _bfd_elf_section_from_bfd_section PARAMS ((bfd *, asection *)); +extern char *bfd_elf_string_from_elf_section + PARAMS ((bfd *, unsigned, unsigned)); +extern char *bfd_elf_get_str_section PARAMS ((bfd *, unsigned)); + +extern boolean _bfd_elf_print_private_bfd_data PARAMS ((bfd *, PTR)); +extern void bfd_elf_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +#define elf_string_from_elf_strtab(abfd,strindex) \ + bfd_elf_string_from_elf_section(abfd,elf_elfheader(abfd)->e_shstrndx,strindex) + +#define bfd_elf32_print_symbol bfd_elf_print_symbol +#define bfd_elf64_print_symbol bfd_elf_print_symbol +#define bfd_elf32_mkobject bfd_elf_mkobject +#define bfd_elf64_mkobject bfd_elf_mkobject +#define elf_mkobject bfd_elf_mkobject + +extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *)); + +extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *, + arelent *, + asymbol *, + PTR, + asection *, + bfd *, + char **)); +extern boolean bfd_elf_mkobject PARAMS ((bfd *)); +extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *)); +extern boolean _bfd_elf_make_section_from_shdr + PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, const char *name)); +extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create + PARAMS ((bfd *)); +extern boolean _bfd_elf_link_hash_table_init + PARAMS ((struct elf_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +extern boolean _bfd_elf_copy_private_symbol_data + PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); +extern boolean _bfd_elf_copy_private_section_data + PARAMS ((bfd *, asection *, bfd *, asection *)); +extern boolean _bfd_elf_write_object_contents PARAMS ((bfd *)); +extern boolean _bfd_elf_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); +extern long _bfd_elf_get_symtab_upper_bound PARAMS ((bfd *)); +extern long _bfd_elf_get_symtab PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_dynamic_symtab_upper_bound PARAMS ((bfd *)); +extern long _bfd_elf_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern long _bfd_elf_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, asymbol **)); +extern asymbol *_bfd_elf_make_empty_symbol PARAMS ((bfd *)); +extern void _bfd_elf_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *_bfd_elf_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean _bfd_elf_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean _bfd_elf_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +#define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols +#define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +extern int _bfd_elf_sizeof_headers PARAMS ((bfd *, boolean)); +extern boolean _bfd_elf_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void _bfd_elf_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + +asection *bfd_section_from_elf_index PARAMS ((bfd *, unsigned int)); +boolean _bfd_elf_create_dynamic_sections PARAMS ((bfd *, + struct bfd_link_info *)); +struct bfd_strtab_hash *_bfd_elf_stringtab_init PARAMS ((void)); +boolean +_bfd_elf_link_record_dynamic_symbol PARAMS ((struct bfd_link_info *, + struct elf_link_hash_entry *)); +boolean +_bfd_elf_compute_section_file_positions PARAMS ((bfd *, + struct bfd_link_info *)); +void _bfd_elf_assign_file_positions_for_relocs PARAMS ((bfd *)); +file_ptr _bfd_elf_assign_file_position_for_section PARAMS ((Elf_Internal_Shdr *, + file_ptr, + boolean)); + +boolean _bfd_elf_create_dynamic_sections PARAMS ((bfd *, + struct bfd_link_info *)); +boolean _bfd_elf_create_got_section PARAMS ((bfd *, + struct bfd_link_info *)); + +elf_linker_section_t *_bfd_elf_create_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + enum elf_linker_section_enum, + elf_linker_section_t *defaults)); + +elf_linker_section_pointers_t *_bfd_elf_find_pointer_linker_section + PARAMS ((elf_linker_section_pointers_t *linker_pointers, + bfd_signed_vma addend, + elf_linker_section_enum_t which)); + +boolean bfd_elf32_create_pointer_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + const Elf32_Internal_Rela *rel)); + +bfd_vma bfd_elf32_finish_pointer_linker_section + PARAMS ((bfd *output_abfd, + bfd *input_bfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + bfd_vma relocation, + const Elf32_Internal_Rela *rel, + int relative_reloc)); + +boolean bfd_elf64_create_pointer_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + const Elf64_Internal_Rela *rel)); + +bfd_vma bfd_elf64_finish_pointer_linker_section + PARAMS ((bfd *output_abfd, + bfd *input_bfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + bfd_vma relocation, + const Elf64_Internal_Rela *rel, + int relative_reloc)); + +boolean _bfd_elf_make_linker_section_rela + PARAMS ((bfd *dynobj, + elf_linker_section_t *lsect, + int alignment)); + +extern const bfd_target *bfd_elf32_object_p PARAMS ((bfd *)); +extern const bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); + +extern boolean bfd_elf32_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf32_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf32_swap_symbol_in + PARAMS ((bfd *, Elf32_External_Sym *, Elf_Internal_Sym *)); +extern void bfd_elf32_swap_symbol_out + PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); +extern void bfd_elf32_swap_reloc_in + PARAMS ((bfd *, Elf32_External_Rel *, Elf_Internal_Rel *)); +extern void bfd_elf32_swap_reloc_out + PARAMS ((bfd *, Elf_Internal_Rel *, Elf32_External_Rel *)); +extern void bfd_elf32_swap_reloca_in + PARAMS ((bfd *, Elf32_External_Rela *, Elf_Internal_Rela *)); +extern void bfd_elf32_swap_reloca_out + PARAMS ((bfd *, Elf_Internal_Rela *, Elf32_External_Rela *)); +extern void bfd_elf32_swap_phdr_in + PARAMS ((bfd *, Elf32_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf32_swap_phdr_out + PARAMS ((bfd *, Elf_Internal_Phdr *, Elf32_External_Phdr *)); +extern void bfd_elf32_swap_dyn_in + PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); +extern void bfd_elf32_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf32_External_Dyn *)); +extern boolean bfd_elf32_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern boolean bfd_elf32_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +extern const bfd_target *bfd_elf64_object_p PARAMS ((bfd *)); +extern const bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf64_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf64_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf64_swap_symbol_in + PARAMS ((bfd *, Elf64_External_Sym *, Elf_Internal_Sym *)); +extern void bfd_elf64_swap_symbol_out + PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); +extern void bfd_elf64_swap_reloc_in + PARAMS ((bfd *, Elf64_External_Rel *, Elf_Internal_Rel *)); +extern void bfd_elf64_swap_reloc_out + PARAMS ((bfd *, Elf_Internal_Rel *, Elf64_External_Rel *)); +extern void bfd_elf64_swap_reloca_in + PARAMS ((bfd *, Elf64_External_Rela *, Elf_Internal_Rela *)); +extern void bfd_elf64_swap_reloca_out + PARAMS ((bfd *, Elf_Internal_Rela *, Elf64_External_Rela *)); +extern void bfd_elf64_swap_phdr_in + PARAMS ((bfd *, Elf64_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf64_swap_phdr_out + PARAMS ((bfd *, Elf_Internal_Phdr *, Elf64_External_Phdr *)); +extern void bfd_elf64_swap_dyn_in + PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); +extern void bfd_elf64_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf64_External_Dyn *)); +extern boolean bfd_elf64_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern boolean bfd_elf64_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +#define bfd_elf32_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#define bfd_elf64_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol + +#endif /* _LIBELF_H_ */ diff --git a/contrib/gdb/bfd/elf.c b/contrib/gdb/bfd/elf.c new file mode 100644 index 000000000000..981d3ee23091 --- /dev/null +++ b/contrib/gdb/bfd/elf.c @@ -0,0 +1,3318 @@ +/* ELF executable support for BFD. + Copyright 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + +SECTION + ELF backends + + BFD support for ELF formats is being worked on. + Currently, the best supported back ends are for sparc and i386 + (running svr4 or Solaris 2). + + Documentation of the internals of the support code still needs + to be written. The code is changing quickly enough that we + haven't bothered yet. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" + +static INLINE struct elf_segment_map *make_mapping + PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean)); +static int elf_sort_sections PARAMS ((const PTR, const PTR)); +static boolean assign_file_positions_for_segments PARAMS ((bfd *)); +static boolean assign_file_positions_except_relocs PARAMS ((bfd *)); +static boolean prep_headers PARAMS ((bfd *)); +static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **)); +static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *)); + +/* Standard ELF hash function. Do not change this function; you will + cause invalid hash tables to be generated. (Well, you would if this + were being used yet.) */ +unsigned long +bfd_elf_hash (name) + CONST unsigned char *name; +{ + unsigned long h = 0; + unsigned long g; + int ch; + + while ((ch = *name++) != '\0') + { + h = (h << 4) + ch; + if ((g = (h & 0xf0000000)) != 0) + { + h ^= g >> 24; + h &= ~g; + } + } + return h; +} + +/* Read a specified number of bytes at a specified offset in an ELF + file, into a newly allocated buffer, and return a pointer to the + buffer. */ + +static char * +elf_read (abfd, offset, size) + bfd * abfd; + long offset; + unsigned int size; +{ + char *buf; + + if ((buf = bfd_alloc (abfd, size)) == NULL) + return NULL; + if (bfd_seek (abfd, offset, SEEK_SET) == -1) + return NULL; + if (bfd_read ((PTR) buf, size, 1, abfd) != size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + return buf; +} + +boolean +elf_mkobject (abfd) + bfd * abfd; +{ + /* this just does initialization */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + elf_tdata (abfd) = (struct elf_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (elf_tdata (abfd) == 0) + return false; + /* since everything is done at close time, do we need any + initialization? */ + + return true; +} + +char * +bfd_elf_get_str_section (abfd, shindex) + bfd * abfd; + unsigned int shindex; +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab = NULL; + unsigned int offset; + unsigned int shstrtabsize; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp == 0 || i_shdrp[shindex] == 0) + return 0; + + shstrtab = (char *) i_shdrp[shindex]->contents; + if (shstrtab == NULL) + { + /* No cached one, attempt to read, and cache what we read. */ + offset = i_shdrp[shindex]->sh_offset; + shstrtabsize = i_shdrp[shindex]->sh_size; + shstrtab = elf_read (abfd, offset, shstrtabsize); + i_shdrp[shindex]->contents = (PTR) shstrtab; + } + return shstrtab; +} + +char * +bfd_elf_string_from_elf_section (abfd, shindex, strindex) + bfd * abfd; + unsigned int shindex; + unsigned int strindex; +{ + Elf_Internal_Shdr *hdr; + + if (strindex == 0) + return ""; + + hdr = elf_elfsections (abfd)[shindex]; + + if (hdr->contents == NULL + && bfd_elf_get_str_section (abfd, shindex) == NULL) + return NULL; + + return ((char *) hdr->contents) + strindex; +} + +/* Make a BFD section from an ELF section. We store a pointer to the + BFD section in the bfd_section field of the header. */ + +boolean +_bfd_elf_make_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf_Internal_Shdr *hdr; + const char *name; +{ + asection *newsect; + flagword flags; + + if (hdr->bfd_section != NULL) + { + BFD_ASSERT (strcmp (name, + bfd_get_section_name (abfd, hdr->bfd_section)) == 0); + return true; + } + + newsect = bfd_make_section_anyway (abfd, name); + if (newsect == NULL) + return false; + + newsect->filepos = hdr->sh_offset; + + if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) + || ! bfd_set_section_size (abfd, newsect, hdr->sh_size) + || ! bfd_set_section_alignment (abfd, newsect, + bfd_log2 (hdr->sh_addralign))) + return false; + + flags = SEC_NO_FLAGS; + if (hdr->sh_type != SHT_NOBITS) + flags |= SEC_HAS_CONTENTS; + if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + flags |= SEC_ALLOC; + if (hdr->sh_type != SHT_NOBITS) + flags |= SEC_LOAD; + } + if ((hdr->sh_flags & SHF_WRITE) == 0) + flags |= SEC_READONLY; + if ((hdr->sh_flags & SHF_EXECINSTR) != 0) + flags |= SEC_CODE; + else if ((flags & SEC_LOAD) != 0) + flags |= SEC_DATA; + + /* The debugging sections appear to be recognized only by name, not + any sort of flag. */ + if (strncmp (name, ".debug", sizeof ".debug" - 1) == 0 + || strncmp (name, ".line", sizeof ".line" - 1) == 0 + || strncmp (name, ".stab", sizeof ".stab" - 1) == 0) + flags |= SEC_DEBUGGING; + + if (! bfd_set_section_flags (abfd, newsect, flags)) + return false; + + if ((flags & SEC_ALLOC) != 0) + { + Elf_Internal_Phdr *phdr; + unsigned int i; + + /* Look through the phdrs to see if we need to adjust the lma. */ + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) + { + if (phdr->p_type == PT_LOAD + && phdr->p_paddr != 0 + && phdr->p_vaddr != phdr->p_paddr + && phdr->p_vaddr <= hdr->sh_addr + && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size) + { + newsect->lma += phdr->p_paddr - phdr->p_vaddr; + break; + } + } + } + + hdr->bfd_section = newsect; + elf_section_data (newsect)->this_hdr = *hdr; + + return true; +} + +/* +INTERNAL_FUNCTION + bfd_elf_find_section + +SYNOPSIS + struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); + +DESCRIPTION + Helper functions for GDB to locate the string tables. + Since BFD hides string tables from callers, GDB needs to use an + internal hook to find them. Sun's .stabstr, in particular, + isn't even pointed to by the .stab section, so ordinary + mechanisms wouldn't work to find it, even if we had some. +*/ + +struct elf_internal_shdr * +bfd_elf_find_section (abfd, name) + bfd * abfd; + char *name; +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab; + unsigned int max; + unsigned int i; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp != NULL) + { + shstrtab = bfd_elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx); + if (shstrtab != NULL) + { + max = elf_elfheader (abfd)->e_shnum; + for (i = 1; i < max; i++) + if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name)) + return i_shdrp[i]; + } + } + return 0; +} + +const char *const bfd_elf_section_type_names[] = { + "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", + "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", + "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", +}; + +/* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, and nothing + has given us any additional addend, the resulting reloc will also + be against the same symbol. In such a case, we don't want to + change anything about the way the reloc is handled, since it will + all be done at final link time. Rather than put special case code + into bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +/*ARGSUSED*/ +bfd_reloc_status_type +bfd_elf_generic_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} + +/* Print out the program headers. */ + +boolean +_bfd_elf_print_private_bfd_data (abfd, farg) + bfd *abfd; + PTR farg; +{ + FILE *f = (FILE *) farg; + Elf_Internal_Phdr *p; + asection *s; + bfd_byte *dynbuf = NULL; + + p = elf_tdata (abfd)->phdr; + if (p != NULL) + { + unsigned int i, c; + + fprintf (f, "\nProgram Header:\n"); + c = elf_elfheader (abfd)->e_phnum; + for (i = 0; i < c; i++, p++) + { + const char *s; + char buf[20]; + + switch (p->p_type) + { + case PT_NULL: s = "NULL"; break; + case PT_LOAD: s = "LOAD"; break; + case PT_DYNAMIC: s = "DYNAMIC"; break; + case PT_INTERP: s = "INTERP"; break; + case PT_NOTE: s = "NOTE"; break; + case PT_SHLIB: s = "SHLIB"; break; + case PT_PHDR: s = "PHDR"; break; + default: sprintf (buf, "0x%lx", p->p_type); s = buf; break; + } + fprintf (f, "%8s off 0x", s); + fprintf_vma (f, p->p_offset); + fprintf (f, " vaddr 0x"); + fprintf_vma (f, p->p_vaddr); + fprintf (f, " paddr 0x"); + fprintf_vma (f, p->p_paddr); + fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align)); + fprintf (f, " filesz 0x"); + fprintf_vma (f, p->p_filesz); + fprintf (f, " memsz 0x"); + fprintf_vma (f, p->p_memsz); + fprintf (f, " flags %c%c%c", + (p->p_flags & PF_R) != 0 ? 'r' : '-', + (p->p_flags & PF_W) != 0 ? 'w' : '-', + (p->p_flags & PF_X) != 0 ? 'x' : '-'); + if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0) + fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X)); + fprintf (f, "\n"); + } + } + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + int elfsec; + unsigned long link; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); + + fprintf (f, "\nDynamic Section:\n"); + + dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size); + if (dynbuf == NULL) + goto error_return; + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0, + s->_raw_size)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + link = elf_elfsections (abfd)[elfsec]->sh_link; + + extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; + swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + const char *name; + char ab[20]; + boolean stringp; + + (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + stringp = false; + switch (dyn.d_tag) + { + default: + sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag); + name = ab; + break; + + case DT_NEEDED: name = "NEEDED"; stringp = true; break; + case DT_PLTRELSZ: name = "PLTRELSZ"; break; + case DT_PLTGOT: name = "PLTGOT"; break; + case DT_HASH: name = "HASH"; break; + case DT_STRTAB: name = "STRTAB"; break; + case DT_SYMTAB: name = "SYMTAB"; break; + case DT_RELA: name = "RELA"; break; + case DT_RELASZ: name = "RELASZ"; break; + case DT_RELAENT: name = "RELAENT"; break; + case DT_STRSZ: name = "STRSZ"; break; + case DT_SYMENT: name = "SYMENT"; break; + case DT_INIT: name = "INIT"; break; + case DT_FINI: name = "FINI"; break; + case DT_SONAME: name = "SONAME"; stringp = true; break; + case DT_RPATH: name = "RPATH"; stringp = true; break; + case DT_SYMBOLIC: name = "SYMBOLIC"; break; + case DT_REL: name = "REL"; break; + case DT_RELSZ: name = "RELSZ"; break; + case DT_RELENT: name = "RELENT"; break; + case DT_PLTREL: name = "PLTREL"; break; + case DT_DEBUG: name = "DEBUG"; break; + case DT_TEXTREL: name = "TEXTREL"; break; + case DT_JMPREL: name = "JMPREL"; break; + } + + fprintf (f, " %-11s ", name); + if (! stringp) + fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val); + else + { + const char *string; + + string = bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (string == NULL) + goto error_return; + fprintf (f, "%s", string); + } + fprintf (f, "\n"); + } + + free (dynbuf); + dynbuf = NULL; + } + + return true; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return false; +} + +/* Display ELF-specific fields of a symbol. */ +void +bfd_elf_print_symbol (ignore_abfd, filep, symbol, how) + bfd *ignore_abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf (file, "elf "); + fprintf_vma (file, symbol->value); + fprintf (file, " %lx", (long) symbol->flags); + break; + case bfd_print_symbol_all: + { + CONST char *section_name; + section_name = symbol->section ? symbol->section->name : "(*none*)"; + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %s\t", section_name); + /* Print the "other" value for a symbol. For common symbols, + we've already printed the size; now print the alignment. + For other symbols, we have no specified alignment, and + we've printed the address; now print the size. */ + fprintf_vma (file, + (bfd_is_com_section (symbol->section) + ? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value + : ((elf_symbol_type *) symbol)->internal_elf_sym.st_size)); + fprintf (file, " %s", symbol->name); + } + break; + } +} + +/* Create an entry in an ELF linker hash table. */ + +struct bfd_hash_entry * +_bfd_elf_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct elf_link_hash_entry *) NULL) + ret = ((struct elf_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry))); + if (ret == (struct elf_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct elf_link_hash_entry *) NULL) + { + /* Set local fields. */ + ret->indx = -1; + ret->size = 0; + ret->dynindx = -1; + ret->dynstr_index = 0; + ret->weakdef = NULL; + ret->got_offset = (bfd_vma) -1; + ret->plt_offset = (bfd_vma) -1; + ret->linker_section_pointer = (elf_linker_section_pointers_t *)0; + ret->type = STT_NOTYPE; + /* Assume that we have been called by a non-ELF symbol reader. + This flag is then reset by the code which reads an ELF input + file. This ensures that a symbol created by a non-ELF symbol + reader will have the flag set correctly. */ + ret->elf_link_hash_flags = ELF_LINK_NON_ELF; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an ELF linker hash table. */ + +boolean +_bfd_elf_link_hash_table_init (table, abfd, newfunc) + struct elf_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->dynamic_sections_created = false; + table->dynobj = NULL; + /* The first dynamic symbol is a dummy. */ + table->dynsymcount = 1; + table->dynstr = NULL; + table->bucketcount = 0; + table->needed = NULL; + return _bfd_link_hash_table_init (&table->root, abfd, newfunc); +} + +/* Create an ELF linker hash table. */ + +struct bfd_link_hash_table * +_bfd_elf_link_hash_table_create (abfd) + bfd *abfd; +{ + struct elf_link_hash_table *ret; + + ret = ((struct elf_link_hash_table *) + bfd_alloc (abfd, sizeof (struct elf_link_hash_table))); + if (ret == (struct elf_link_hash_table *) NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } + + return &ret->root; +} + +/* 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. The generic linker passes name as an + empty string to indicate that no DT_NEEDED entry should be made. */ + +void +bfd_elf_set_dt_needed_name (abfd, name) + bfd *abfd; + const char *name; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_name (abfd) = name; +} + +/* Get the list of DT_NEEDED entries for a link. This is a hook for + the ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_needed_list (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return NULL; + return elf_hash_table (info)->needed; +} + +/* Get the name actually used for a dynamic object for a link. This + is the SONAME entry if there is one. Otherwise, it is the string + passed to bfd_elf_set_dt_needed_name, or it is the filename. */ + +const char * +bfd_elf_get_dt_soname (abfd) + bfd *abfd; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + return elf_dt_name (abfd); + return NULL; +} + +/* Allocate an ELF string table--force the first byte to be zero. */ + +struct bfd_strtab_hash * +_bfd_elf_stringtab_init () +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + { + bfd_size_type loc; + + loc = _bfd_stringtab_add (ret, "", true, false); + BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1); + if (loc == (bfd_size_type) -1) + { + _bfd_stringtab_free (ret); + ret = NULL; + } + } + return ret; +} + +/* ELF .o/exec file reading */ + +/* Create a new bfd section from an ELF section header. */ + +boolean +bfd_section_from_shdr (abfd, shindex) + bfd *abfd; + unsigned int shindex; +{ + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex]; + Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); + struct elf_backend_data *bed = get_elf_backend_data (abfd); + char *name; + + name = elf_string_from_elf_strtab (abfd, hdr->sh_name); + + switch (hdr->sh_type) + { + case SHT_NULL: + /* Inactive section. Throw it away. */ + return true; + + case SHT_PROGBITS: /* Normal section with contents. */ + case SHT_DYNAMIC: /* Dynamic linking information. */ + case SHT_NOBITS: /* .bss section. */ + case SHT_HASH: /* .hash section. */ + case SHT_NOTE: /* .note section. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_SYMTAB: /* A symbol table */ + if (elf_onesymtab (abfd) == shindex) + return true; + + BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + BFD_ASSERT (elf_onesymtab (abfd) == 0); + elf_onesymtab (abfd) = shindex; + elf_tdata (abfd)->symtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr; + abfd->flags |= HAS_SYMS; + + /* Sometimes a shared object will map in the symbol table. If + SHF_ALLOC is set, and this is a shared object, then we also + treat this section as a BFD section. We can not base the + decision purely on SHF_ALLOC, because that flag is sometimes + set in a relocateable object file, which would confuse the + linker. */ + if ((hdr->sh_flags & SHF_ALLOC) != 0 + && (abfd->flags & DYNAMIC) != 0 + && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + + return true; + + case SHT_DYNSYM: /* A dynamic symbol table */ + if (elf_dynsymtab (abfd) == shindex) + return true; + + BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + BFD_ASSERT (elf_dynsymtab (abfd) == 0); + elf_dynsymtab (abfd) = shindex; + elf_tdata (abfd)->dynsymtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr; + abfd->flags |= HAS_SYMS; + + /* Besides being a symbol table, we also treat this as a regular + section, so that objcopy can handle it. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_STRTAB: /* A string table */ + if (hdr->bfd_section != NULL) + return true; + if (ehdr->e_shstrndx == shindex) + { + elf_tdata (abfd)->shstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; + return true; + } + { + unsigned int i; + + for (i = 1; i < ehdr->e_shnum; i++) + { + Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; + if (hdr2->sh_link == shindex) + { + if (! bfd_section_from_shdr (abfd, i)) + return false; + if (elf_onesymtab (abfd) == i) + { + elf_tdata (abfd)->strtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = + &elf_tdata (abfd)->strtab_hdr; + return true; + } + if (elf_dynsymtab (abfd) == i) + { + elf_tdata (abfd)->dynstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = + &elf_tdata (abfd)->dynstrtab_hdr; + /* We also treat this as a regular section, so + that objcopy can handle it. */ + break; + } +#if 0 /* Not handling other string tables specially right now. */ + hdr2 = elf_elfsections (abfd)[i]; /* in case it moved */ + /* We have a strtab for some random other section. */ + newsect = (asection *) hdr2->bfd_section; + if (!newsect) + break; + hdr->bfd_section = newsect; + hdr2 = &elf_section_data (newsect)->str_hdr; + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; +#endif + } + } + } + + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_REL: + case SHT_RELA: + /* *These* do a lot of work -- but build no sections! */ + { + asection *target_sect; + Elf_Internal_Shdr *hdr2; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + + /* For some incomprehensible reason Oracle distributes + libraries for Solaris in which some of the objects have + bogus sh_link fields. It would be nice if we could just + reject them, but, unfortunately, some people need to use + them. We scan through the section headers; if we find only + one suitable symbol table, we clobber the sh_link to point + to it. I hope this doesn't break anything. */ + if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB + && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM) + { + int scan; + int found; + + found = 0; + for (scan = 1; scan < ehdr->e_shnum; scan++) + { + if (elf_elfsections (abfd)[scan]->sh_type == SHT_SYMTAB + || elf_elfsections (abfd)[scan]->sh_type == SHT_DYNSYM) + { + if (found != 0) + { + found = 0; + break; + } + found = scan; + } + } + if (found != 0) + hdr->sh_link = found; + } + + /* Get the symbol table. */ + if (elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB + && ! bfd_section_from_shdr (abfd, hdr->sh_link)) + return false; + + /* If this reloc section does not use the main symbol table we + don't treat it as a reloc section. BFD can't adequately + represent such a section, so at least for now, we don't + try. We just present it as a normal section. */ + if (hdr->sh_link != elf_onesymtab (abfd)) + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + /* Don't allow REL relocations on a machine that uses RELA and + vice versa. */ + /* @@ Actually, the generic ABI does suggest that both might be + used in one file. But the four ABI Processor Supplements I + have access to right now all specify that only one is used on + each of those architectures. It's conceivable that, e.g., a + bunch of absolute 32-bit relocs might be more compact in REL + form even on a RELA machine... */ + BFD_ASSERT (use_rela_p + ? (hdr->sh_type == SHT_RELA + && hdr->sh_entsize == bed->s->sizeof_rela) + : (hdr->sh_type == SHT_REL + && hdr->sh_entsize == bed->s->sizeof_rel)); + + if (! bfd_section_from_shdr (abfd, hdr->sh_info)) + return false; + target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); + if (target_sect == NULL) + return false; + + hdr2 = &elf_section_data (target_sect)->rel_hdr; + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; + target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize; + target_sect->flags |= SEC_RELOC; + target_sect->relocation = NULL; + target_sect->rel_filepos = hdr->sh_offset; + abfd->flags |= HAS_RELOC; + return true; + } + break; + + case SHT_SHLIB: + return true; + + default: + /* Check for any processor-specific section types. */ + { + if (bed->elf_backend_section_from_shdr) + (*bed->elf_backend_section_from_shdr) (abfd, hdr, name); + } + break; + } + + return true; +} + +/* Given an ELF section number, retrieve the corresponding BFD + section. */ + +asection * +bfd_section_from_elf_index (abfd, index) + bfd *abfd; + unsigned int index; +{ + BFD_ASSERT (index > 0 && index < SHN_LORESERVE); + if (index >= elf_elfheader (abfd)->e_shnum) + return NULL; + return elf_elfsections (abfd)[index]->bfd_section; +} + +boolean +_bfd_elf_new_section_hook (abfd, sec) + bfd *abfd; + asection *sec; +{ + struct bfd_elf_section_data *sdata; + + sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata)); + if (!sdata) + return false; + sec->used_by_bfd = (PTR) sdata; + memset (sdata, 0, sizeof (*sdata)); + return true; +} + +/* Create a new bfd section from an ELF program header. + + Since program segments have no names, we generate a synthetic name + of the form segment, where NUM is generally the index in the + program header table. For segments that are split (see below) we + generate the names segmenta and segmentb. + + Note that some program segments may have a file size that is different than + (less than) the memory size. All this means is that at execution the + system must allocate the amount of memory specified by the memory size, + but only initialize it with the first "file size" bytes read from the + file. This would occur for example, with program segments consisting + of combined data+bss. + + To handle the above situation, this routine generates TWO bfd sections + for the single program segment. The first has the length specified by + the file size of the segment, and the second has the length specified + by the difference between the two sizes. In effect, the segment is split + into it's initialized and uninitialized parts. + + */ + +boolean +bfd_section_from_phdr (abfd, hdr, index) + bfd *abfd; + Elf_Internal_Phdr *hdr; + int index; +{ + asection *newsect; + char *name; + char namebuf[64]; + int split; + + split = ((hdr->p_memsz > 0) && + (hdr->p_filesz > 0) && + (hdr->p_memsz > hdr->p_filesz)); + sprintf (namebuf, split ? "segment%da" : "segment%d", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + if (!name) + return false; + strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return false; + newsect->vma = hdr->p_vaddr; + newsect->lma = hdr->p_paddr; + newsect->_raw_size = hdr->p_filesz; + newsect->filepos = hdr->p_offset; + newsect->flags |= SEC_HAS_CONTENTS; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + newsect->flags |= SEC_LOAD; + if (hdr->p_flags & PF_X) + { + /* FIXME: all we known is that it has execute PERMISSION, + may be data. */ + newsect->flags |= SEC_CODE; + } + } + if (!(hdr->p_flags & PF_W)) + { + newsect->flags |= SEC_READONLY; + } + + if (split) + { + sprintf (namebuf, "segment%db", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + if (!name) + return false; + strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return false; + newsect->vma = hdr->p_vaddr + hdr->p_filesz; + newsect->lma = hdr->p_paddr + hdr->p_filesz; + newsect->_raw_size = hdr->p_memsz - hdr->p_filesz; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + if (hdr->p_flags & PF_X) + newsect->flags |= SEC_CODE; + } + if (!(hdr->p_flags & PF_W)) + newsect->flags |= SEC_READONLY; + } + + return true; +} + +/* Set up an ELF internal section header for a section. */ + +/*ARGSUSED*/ +static void +elf_fake_sections (abfd, asect, failedptrarg) + bfd *abfd; + asection *asect; + PTR failedptrarg; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + boolean *failedptr = (boolean *) failedptrarg; + Elf_Internal_Shdr *this_hdr; + + if (*failedptr) + { + /* We already failed; just get out of the bfd_map_over_sections + loop. */ + return; + } + + this_hdr = &elf_section_data (asect)->this_hdr; + + this_hdr->sh_name = (unsigned long) _bfd_stringtab_add (elf_shstrtab (abfd), + asect->name, + true, false); + if (this_hdr->sh_name == (unsigned long) -1) + { + *failedptr = true; + return; + } + + this_hdr->sh_flags = 0; + + if ((asect->flags & SEC_ALLOC) != 0) + this_hdr->sh_addr = asect->vma; + else + this_hdr->sh_addr = 0; + + this_hdr->sh_offset = 0; + this_hdr->sh_size = asect->_raw_size; + this_hdr->sh_link = 0; + this_hdr->sh_addralign = 1 << asect->alignment_power; + /* The sh_entsize and sh_info fields may have been set already by + copy_private_section_data. */ + + this_hdr->bfd_section = asect; + this_hdr->contents = NULL; + + /* FIXME: This should not be based on section names. */ + if (strcmp (asect->name, ".dynstr") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if (strcmp (asect->name, ".hash") == 0) + { + this_hdr->sh_type = SHT_HASH; + this_hdr->sh_entsize = bed->s->arch_size / 8; + } + else if (strcmp (asect->name, ".dynsym") == 0) + { + this_hdr->sh_type = SHT_DYNSYM; + this_hdr->sh_entsize = bed->s->sizeof_sym; + } + else if (strcmp (asect->name, ".dynamic") == 0) + { + this_hdr->sh_type = SHT_DYNAMIC; + this_hdr->sh_entsize = bed->s->sizeof_dyn; + } + else if (strncmp (asect->name, ".rela", 5) == 0 + && get_elf_backend_data (abfd)->use_rela_p) + { + this_hdr->sh_type = SHT_RELA; + this_hdr->sh_entsize = bed->s->sizeof_rela; + } + else if (strncmp (asect->name, ".rel", 4) == 0 + && ! get_elf_backend_data (abfd)->use_rela_p) + { + this_hdr->sh_type = SHT_REL; + this_hdr->sh_entsize = bed->s->sizeof_rel; + } + else if (strcmp (asect->name, ".note") == 0) + this_hdr->sh_type = SHT_NOTE; + else if (strncmp (asect->name, ".stab", 5) == 0 + && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if ((asect->flags & SEC_ALLOC) != 0 + && (asect->flags & SEC_LOAD) != 0) + this_hdr->sh_type = SHT_PROGBITS; + else if ((asect->flags & SEC_ALLOC) != 0 + && ((asect->flags & SEC_LOAD) == 0)) + this_hdr->sh_type = SHT_NOBITS; + else + { + /* Who knows? */ + this_hdr->sh_type = SHT_PROGBITS; + } + + if ((asect->flags & SEC_ALLOC) != 0) + this_hdr->sh_flags |= SHF_ALLOC; + if ((asect->flags & SEC_READONLY) == 0) + this_hdr->sh_flags |= SHF_WRITE; + if ((asect->flags & SEC_CODE) != 0) + this_hdr->sh_flags |= SHF_EXECINSTR; + + /* Check for processor-specific section types. */ + { + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_fake_sections) + (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect); + } + + /* If the section has relocs, set up a section header for the + SHT_REL[A] section. */ + if ((asect->flags & SEC_RELOC) != 0) + { + Elf_Internal_Shdr *rela_hdr; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + char *name; + + rela_hdr = &elf_section_data (asect)->rel_hdr; + name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); + if (name == NULL) + { + *failedptr = true; + return; + } + sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); + rela_hdr->sh_name = + (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name, + true, false); + if (rela_hdr->sh_name == (unsigned int) -1) + { + *failedptr = true; + return; + } + rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; + rela_hdr->sh_entsize = (use_rela_p + ? bed->s->sizeof_rela + : bed->s->sizeof_rel); + rela_hdr->sh_addralign = bed->s->file_align; + rela_hdr->sh_flags = 0; + rela_hdr->sh_addr = 0; + rela_hdr->sh_size = 0; + rela_hdr->sh_offset = 0; + } +} + +/* Assign all ELF section numbers. The dummy first section is handled here + too. The link/info pointers for the standard section types are filled + in here too, while we're at it. */ + +static boolean +assign_section_numbers (abfd) + bfd *abfd; +{ + struct elf_obj_tdata *t = elf_tdata (abfd); + asection *sec; + unsigned int section_number; + Elf_Internal_Shdr **i_shdrp; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + section_number = 1; + + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + + d->this_idx = section_number++; + if ((sec->flags & SEC_RELOC) == 0) + d->rel_idx = 0; + else + d->rel_idx = section_number++; + } + + t->shstrtab_section = section_number++; + elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; + t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd)); + + if (abfd->symcount > 0) + { + t->symtab_section = section_number++; + t->strtab_section = section_number++; + } + + elf_elfheader (abfd)->e_shnum = section_number; + + /* Set up the list of section header pointers, in agreement with the + indices. */ + i_shdrp = ((Elf_Internal_Shdr **) + bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *))); + if (i_shdrp == NULL) + return false; + + i_shdrp[0] = ((Elf_Internal_Shdr *) + bfd_alloc (abfd, sizeof (Elf_Internal_Shdr))); + if (i_shdrp[0] == NULL) + { + bfd_release (abfd, i_shdrp); + return false; + } + memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr)); + + elf_elfsections (abfd) = i_shdrp; + + i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; + if (abfd->symcount > 0) + { + i_shdrp[t->symtab_section] = &t->symtab_hdr; + i_shdrp[t->strtab_section] = &t->strtab_hdr; + t->symtab_hdr.sh_link = t->strtab_section; + } + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + asection *s; + const char *name; + + i_shdrp[d->this_idx] = &d->this_hdr; + if (d->rel_idx != 0) + i_shdrp[d->rel_idx] = &d->rel_hdr; + + /* Fill in the sh_link and sh_info fields while we're at it. */ + + /* sh_link of a reloc section is the section index of the symbol + table. sh_info is the section index of the section to which + the relocation entries apply. */ + if (d->rel_idx != 0) + { + d->rel_hdr.sh_link = t->symtab_section; + d->rel_hdr.sh_info = d->this_idx; + } + + switch (d->this_hdr.sh_type) + { + case SHT_REL: + case SHT_RELA: + /* A reloc section which we are treating as a normal BFD + section. sh_link is the section index of the symbol + table. sh_info is the section index of the section to + which the relocation entries apply. We assume that an + allocated reloc section uses the dynamic symbol table. + FIXME: How can we be sure? */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + + /* We look up the section the relocs apply to by name. */ + name = sec->name; + if (d->this_hdr.sh_type == SHT_REL) + name += 4; + else + name += 5; + s = bfd_get_section_by_name (abfd, name); + if (s != NULL) + d->this_hdr.sh_info = elf_section_data (s)->this_idx; + break; + + case SHT_STRTAB: + /* We assume that a section named .stab*str is a stabs + string section. We look for a section with the same name + but without the trailing ``str'', and set its sh_link + field to point to this section. */ + if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0 + && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) + { + size_t len; + char *alc; + + len = strlen (sec->name); + alc = (char *) bfd_malloc (len - 2); + if (alc == NULL) + return false; + strncpy (alc, sec->name, len - 3); + alc[len - 3] = '\0'; + s = bfd_get_section_by_name (abfd, alc); + free (alc); + if (s != NULL) + { + elf_section_data (s)->this_hdr.sh_link = d->this_idx; + + /* This is a .stab section. */ + elf_section_data (s)->this_hdr.sh_entsize = + 4 + 2 * (bed->s->arch_size / 8); + } + } + break; + + case SHT_DYNAMIC: + case SHT_DYNSYM: + /* sh_link is the section header index of the string table + used for the dynamic entries or symbol table. */ + s = bfd_get_section_by_name (abfd, ".dynstr"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + + case SHT_HASH: + /* sh_link is the section header index of the symbol table + this hash table is for. */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + } + } + + 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 INLINE int +sym_is_global (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + /* If the backend has a special mapping, use it. */ + if (get_elf_backend_data (abfd)->elf_backend_sym_is_global) + return ((*get_elf_backend_data (abfd)->elf_backend_sym_is_global) + (abfd, sym)); + + return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym))); +} + +static boolean +elf_map_symbols (abfd) + bfd *abfd; +{ + int symcount = bfd_get_symcount (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + asymbol **sect_syms; + int num_locals = 0; + int num_globals = 0; + int num_locals2 = 0; + int num_globals2 = 0; + int max_index = 0; + int num_sections = 0; + int idx; + asection *asect; + asymbol **new_syms; + +#ifdef DEBUG + fprintf (stderr, "elf_map_symbols\n"); + fflush (stderr); +#endif + + /* Add a section symbol for each BFD section. FIXME: Is this really + necessary? */ + for (asect = abfd->sections; asect; asect = asect->next) + { + if (max_index < asect->index) + max_index = asect->index; + } + + max_index++; + sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *)); + if (sect_syms == NULL) + return false; + elf_section_syms (abfd) = sect_syms; + + for (idx = 0; idx < symcount; idx++) + { + if ((syms[idx]->flags & BSF_SECTION_SYM) != 0 + && (syms[idx]->value + syms[idx]->section->vma) == 0) + { + asection *sec; + + sec = syms[idx]->section; + if (sec->owner != NULL) + { + if (sec->owner != abfd) + { + if (sec->output_offset != 0) + continue; + sec = sec->output_section; + BFD_ASSERT (sec->owner == abfd); + } + sect_syms[sec->index] = syms[idx]; + } + } + } + + for (asect = abfd->sections; asect; asect = asect->next) + { + asymbol *sym; + + if (sect_syms[asect->index] != NULL) + continue; + + sym = bfd_make_empty_symbol (abfd); + if (sym == NULL) + return false; + sym->the_bfd = abfd; + sym->name = asect->name; + sym->value = 0; + /* Set the flags to 0 to indicate that this one was newly added. */ + sym->flags = 0; + sym->section = asect; + sect_syms[asect->index] = sym; + num_sections++; +#ifdef DEBUG + fprintf (stderr, + "creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n", + asect->name, (long) asect->vma, asect->index, (long) asect); +#endif + } + + /* Classify all of the symbols. */ + for (idx = 0; idx < symcount; idx++) + { + if (!sym_is_global (abfd, syms[idx])) + num_locals++; + else + num_globals++; + } + for (asect = abfd->sections; asect; asect = asect->next) + { + if (sect_syms[asect->index] != NULL + && sect_syms[asect->index]->flags == 0) + { + sect_syms[asect->index]->flags = BSF_SECTION_SYM; + if (!sym_is_global (abfd, sect_syms[asect->index])) + num_locals++; + else + num_globals++; + sect_syms[asect->index]->flags = 0; + } + } + + /* Now sort the symbols so the local symbols are first. */ + new_syms = ((asymbol **) + bfd_alloc (abfd, + (num_locals + num_globals) * sizeof (asymbol *))); + if (new_syms == NULL) + return false; + + for (idx = 0; idx < symcount; idx++) + { + asymbol *sym = syms[idx]; + int i; + + if (!sym_is_global (abfd, sym)) + i = num_locals2++; + else + i = num_locals + num_globals2++; + new_syms[i] = sym; + sym->udata.i = i + 1; + } + for (asect = abfd->sections; asect; asect = asect->next) + { + if (sect_syms[asect->index] != NULL + && sect_syms[asect->index]->flags == 0) + { + asymbol *sym = sect_syms[asect->index]; + int i; + + sym->flags = BSF_SECTION_SYM; + if (!sym_is_global (abfd, sym)) + i = num_locals2++; + else + i = num_locals + num_globals2++; + new_syms[i] = sym; + sym->udata.i = i + 1; + } + } + + bfd_set_symtab (abfd, new_syms, num_locals + num_globals); + + elf_num_locals (abfd) = num_locals; + elf_num_globals (abfd) = num_globals; + return true; +} + +/* Align to the maximum file alignment that could be required for any + ELF data structure. */ + +static INLINE file_ptr align_file_position PARAMS ((file_ptr, int)); +static INLINE file_ptr +align_file_position (off, align) + file_ptr off; + int align; +{ + return (off + align - 1) & ~(align - 1); +} + +/* Assign a file position to a section, optionally aligning to the + required section alignment. */ + +INLINE file_ptr +_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align) + Elf_Internal_Shdr *i_shdrp; + file_ptr offset; + boolean align; +{ + if (align) + { + unsigned int al; + + al = i_shdrp->sh_addralign; + if (al > 1) + offset = BFD_ALIGN (offset, al); + } + i_shdrp->sh_offset = offset; + if (i_shdrp->bfd_section != NULL) + i_shdrp->bfd_section->filepos = offset; + if (i_shdrp->sh_type != SHT_NOBITS) + offset += i_shdrp->sh_size; + return offset; +} + +/* Compute the file positions we are going to put the sections at, and + otherwise prepare to begin writing out the ELF file. If LINK_INFO + is not NULL, this is being called by the ELF backend linker. */ + +boolean +_bfd_elf_compute_section_file_positions (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + boolean failed; + struct bfd_strtab_hash *strtab; + Elf_Internal_Shdr *shstrtab_hdr; + + if (abfd->output_has_begun) + return true; + + /* Do any elf backend specific processing first. */ + if (bed->elf_backend_begin_write_processing) + (*bed->elf_backend_begin_write_processing) (abfd, link_info); + + if (! prep_headers (abfd)) + return false; + + failed = false; + bfd_map_over_sections (abfd, elf_fake_sections, &failed); + if (failed) + return false; + + if (!assign_section_numbers (abfd)) + return false; + + /* The backend linker builds symbol table information itself. */ + if (link_info == NULL && abfd->symcount > 0) + { + if (! swap_out_syms (abfd, &strtab)) + return false; + } + + shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; + /* sh_name was set in prep_headers. */ + shstrtab_hdr->sh_type = SHT_STRTAB; + shstrtab_hdr->sh_flags = 0; + shstrtab_hdr->sh_addr = 0; + shstrtab_hdr->sh_size = _bfd_stringtab_size (elf_shstrtab (abfd)); + shstrtab_hdr->sh_entsize = 0; + shstrtab_hdr->sh_link = 0; + shstrtab_hdr->sh_info = 0; + /* sh_offset is set in assign_file_positions_except_relocs. */ + shstrtab_hdr->sh_addralign = 1; + + if (!assign_file_positions_except_relocs (abfd)) + return false; + + if (link_info == NULL && abfd->symcount > 0) + { + file_ptr off; + Elf_Internal_Shdr *hdr; + + off = elf_tdata (abfd)->next_file_pos; + + hdr = &elf_tdata (abfd)->symtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + + hdr = &elf_tdata (abfd)->strtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + + elf_tdata (abfd)->next_file_pos = off; + + /* Now that we know where the .strtab section goes, write it + out. */ + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || ! _bfd_stringtab_emit (abfd, strtab)) + return false; + _bfd_stringtab_free (strtab); + } + + abfd->output_has_begun = true; + + return true; +} + +/* Create a mapping from a set of sections to a program segment. */ + +static INLINE struct elf_segment_map * +make_mapping (abfd, sections, from, to, phdr) + bfd *abfd; + asection **sections; + unsigned int from; + unsigned int to; + boolean phdr; +{ + struct elf_segment_map *m; + unsigned int i; + asection **hdrpp; + + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, + (sizeof (struct elf_segment_map) + + (to - from - 1) * sizeof (asection *)))); + if (m == NULL) + return NULL; + m->next = NULL; + m->p_type = PT_LOAD; + for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++) + m->sections[i - from] = *hdrpp; + m->count = to - from; + + if (from == 0 && phdr) + { + /* Include the headers in the first PT_LOAD segment. */ + m->includes_filehdr = 1; + m->includes_phdrs = 1; + } + + return m; +} + +/* Set up a mapping from BFD sections to program segments. */ + +static boolean +map_sections_to_segments (abfd) + bfd *abfd; +{ + asection **sections = NULL; + asection *s; + unsigned int i; + unsigned int count; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + struct elf_segment_map *m; + asection *last_hdr; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + boolean phdr_in_section = true; + boolean writable; + asection *dynsec; + + if (elf_tdata (abfd)->segment_map != NULL) + return true; + + if (bfd_count_sections (abfd) == 0) + return true; + + /* Select the allocated sections, and sort them. */ + + sections = (asection **) bfd_malloc (bfd_count_sections (abfd) + * sizeof (asection *)); + if (sections == NULL) + goto error_return; + + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_ALLOC) != 0) + { + sections[i] = s; + ++i; + } + } + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; + + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + + /* Build the mapping. */ + + mfirst = NULL; + pm = &mfirst; + + /* If we have a .interp section, then create a PT_PHDR segment for + the program headers and a PT_INTERP segment for the .interp + section. */ + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_PHDR; + /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ + m->p_flags = PF_R | PF_X; + m->p_flags_valid = 1; + m->includes_phdrs = 1; + + *pm = m; + pm = &m->next; + + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; + } + + /* Look through the sections. We put sections in the same program + segment when the start of the second section can be placed within + a few bytes of the end of the first section. */ + last_hdr = NULL; + phdr_index = 0; + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + writable = false; + dynsec = bfd_get_section_by_name (abfd, ".dynamic"); + if (dynsec != NULL + && (dynsec->flags & SEC_LOAD) == 0) + dynsec = NULL; + + /* Deal with -Ttext or something similar such that the + first section is not adjacent to the program headers. */ + if (count + && ((sections[0]->lma % maxpagesize) < + (elf_tdata (abfd)->program_header_size % maxpagesize))) + phdr_in_section = false; + + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) + { + asection *hdr; + + hdr = *hdrpp; + + /* See if this section and the last one will fit in the same + segment. Don't put a loadable section after a non-loadable + section. If we are building a dynamic executable, don't put + a writable section in a read only segment (we don't do this + for a non-dynamic executable because some people prefer to + have only one program segment; anybody can use PHDRS in their + linker script to control what happens anyhow). */ + if (last_hdr == NULL + || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) + >= hdr->lma) + && ((last_hdr->flags & SEC_LOAD) != 0 + || (hdr->flags & SEC_LOAD) == 0) + && (dynsec == NULL + || writable + || (hdr->flags & SEC_READONLY) != 0))) + { + last_hdr = hdr; + continue; + } + + /* This section won't fit in the program segment. We must + create a new program header holding all the sections from + phdr_index until hdr. */ + + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + + if ((hdr->flags & SEC_READONLY) == 0) + writable = true; + + last_hdr = hdr; + phdr_index = i; + phdr_in_section = false; + } + + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) + { + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + } + + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + if (dynsec != NULL) + { + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = dynsec; + + *pm = m; + pm = &m->next; + } + + free (sections); + sections = NULL; + + elf_tdata (abfd)->segment_map = mfirst; + return true; + + error_return: + if (sections != NULL) + free (sections); + return false; +} + +/* Sort sections by VMA. */ + +static int +elf_sort_sections (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + const asection *sec1 = *(const asection **) arg1; + const asection *sec2 = *(const asection **) arg2; + + if (sec1->vma < sec2->vma) + return -1; + else if (sec1->vma > sec2->vma) + return 1; + + /* Put !SEC_LOAD sections after SEC_LOAD ones. */ + +#define TOEND(x) (((x)->flags & SEC_LOAD) == 0) + + if (TOEND (sec1)) + if (TOEND (sec2)) + return sec1->target_index - sec2->target_index; + else + return 1; + + if (TOEND (sec2)) + return -1; + +#undef TOEND + + /* Sort by size, to put zero sized sections before others at the + same address. */ + + if (sec1->_raw_size < sec2->_raw_size) + return -1; + if (sec1->_raw_size > sec2->_raw_size) + return 1; + + return sec1->target_index - sec2->target_index; +} + +/* Assign file positions to the sections based on the mapping from + sections to segments. This function also sets up some fields in + the file header, and writes out the program headers. */ + +static boolean +assign_file_positions_for_segments (abfd) + bfd *abfd; +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int count; + struct elf_segment_map *m; + unsigned int alloc; + Elf_Internal_Phdr *phdrs; + file_ptr off; + bfd_vma filehdr_vaddr, filehdr_paddr; + bfd_vma phdrs_vaddr, phdrs_paddr; + Elf_Internal_Phdr *p; + + if (elf_tdata (abfd)->segment_map == NULL) + { + if (! map_sections_to_segments (abfd)) + return false; + } + + if (bed->elf_backend_modify_segment_map) + { + if (! (*bed->elf_backend_modify_segment_map) (abfd)) + return false; + } + + count = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; + + elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; + elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; + elf_elfheader (abfd)->e_phnum = count; + + if (count == 0) + return true; + + /* If we already counted the number of program segments, make sure + that we allocated enough space. This happens when SIZEOF_HEADERS + is used in a linker script. */ + alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr; + if (alloc != 0 && count > alloc) + { + ((*_bfd_error_handler) + ("%s: Not enough room for program headers (allocated %u, need %u)", + bfd_get_filename (abfd), alloc, count)); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (alloc == 0) + alloc = count; + + phdrs = ((Elf_Internal_Phdr *) + bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr))); + if (phdrs == NULL) + return false; + + off = bed->s->sizeof_ehdr; + off += alloc * bed->s->sizeof_phdr; + + filehdr_vaddr = 0; + filehdr_paddr = 0; + phdrs_vaddr = 0; + phdrs_paddr = 0; + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + unsigned int i; + asection **secpp; + + /* If elf_segment_map is not from map_sections_to_segments, the + sections may not be correctly ordered. */ + if (m->count > 0) + qsort (m->sections, (size_t) m->count, sizeof (asection *), + elf_sort_sections); + + p->p_type = m->p_type; + + if (m->p_flags_valid) + p->p_flags = m->p_flags; + else + p->p_flags = 0; + + if (p->p_type == PT_LOAD + && m->count > 0 + && (m->sections[0]->flags & SEC_LOAD) != 0) + off += (m->sections[0]->vma - off) % bed->maxpagesize; + + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma; + + if (m->p_paddr_valid) + p->p_paddr = m->p_paddr; + else if (m->count == 0) + p->p_paddr = 0; + else + p->p_paddr = m->sections[0]->lma; + + if (p->p_type == PT_LOAD) + p->p_align = bed->maxpagesize; + else if (m->count == 0) + p->p_align = bed->s->file_align; + else + p->p_align = 0; + + p->p_offset = 0; + p->p_filesz = 0; + p->p_memsz = 0; + + if (m->includes_filehdr) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + p->p_offset = 0; + p->p_filesz = bed->s->sizeof_ehdr; + p->p_memsz = bed->s->sizeof_ehdr; + if (m->count > 0) + { + BFD_ASSERT (p->p_type == PT_LOAD); + p->p_vaddr -= off; + if (! m->p_paddr_valid) + p->p_paddr -= off; + } + if (p->p_type == PT_LOAD) + { + filehdr_vaddr = p->p_vaddr; + filehdr_paddr = p->p_paddr; + } + } + + if (m->includes_phdrs) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + if (m->includes_filehdr) + { + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; + phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; + } + } + else + { + p->p_offset = bed->s->sizeof_ehdr; + 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; + } + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr; + phdrs_paddr = p->p_paddr; + } + } + p->p_filesz += alloc * bed->s->sizeof_phdr; + p->p_memsz += alloc * bed->s->sizeof_phdr; + } + + if (p->p_type == PT_LOAD) + { + if (! m->includes_filehdr && ! m->includes_phdrs) + p->p_offset = off; + else + { + file_ptr adjust; + + adjust = off - (p->p_offset + p->p_filesz); + p->p_filesz += adjust; + p->p_memsz += adjust; + } + } + + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + asection *sec; + flagword flags; + bfd_size_type align; + + sec = *secpp; + flags = sec->flags; + + if (p->p_type == PT_LOAD) + { + bfd_vma adjust; + + /* The section VMA must equal the file position modulo + the page size. */ + if ((flags & SEC_ALLOC) != 0) + { + adjust = (sec->vma - off) % bed->maxpagesize; + if (adjust != 0) + { + if (i == 0) + abort (); + p->p_memsz += adjust; + off += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; + } + } + + sec->filepos = off; + + if ((flags & SEC_LOAD) != 0) + off += sec->_raw_size; + } + + p->p_memsz += sec->_raw_size; + + if ((flags & SEC_LOAD) != 0) + p->p_filesz += sec->_raw_size; + + align = 1 << bfd_get_section_alignment (abfd, sec); + if (align > p->p_align) + p->p_align = align; + + if (! m->p_flags_valid) + { + p->p_flags |= PF_R; + if ((flags & SEC_CODE) != 0) + p->p_flags |= PF_X; + if ((flags & SEC_READONLY) == 0) + p->p_flags |= PF_W; + } + } + } + + /* Now that we have set the section file positions, we can set up + the file positions for the non PT_LOAD segments. */ + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + if (p->p_type != PT_LOAD && m->count > 0) + { + BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs); + p->p_offset = m->sections[0]->filepos; + } + if (m->count == 0) + { + if (m->includes_filehdr) + { + p->p_vaddr = filehdr_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = filehdr_paddr; + } + else if (m->includes_phdrs) + { + p->p_vaddr = phdrs_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = phdrs_paddr; + } + } + } + + /* Clear out any program headers we allocated but did not use. */ + for (; count < alloc; count++, p++) + { + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; + } + + elf_tdata (abfd)->phdr = phdrs; + + elf_tdata (abfd)->next_file_pos = off; + + /* Write out the program headers. */ + if (bfd_seek (abfd, bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) + return false; + + return true; +} + +/* Get the size of the program header. + + If this is called by the linker before any of the section VMA's are set, it + can't calculate the correct value for a strange memory layout. This only + happens when SIZEOF_HEADERS is used in a linker script. In this case, + SORTED_HDRS is NULL and we assume the normal scenario of one text and one + data segment (exclusive of .interp and .dynamic). + + ??? User written scripts must either not use SIZEOF_HEADERS, or assume there + will be two segments. */ + +static bfd_size_type +get_program_header_size (abfd) + bfd *abfd; +{ + size_t segs; + asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We can't return a different result each time we're called. */ + if (elf_tdata (abfd)->program_header_size != 0) + return elf_tdata (abfd)->program_header_size; + + if (elf_tdata (abfd)->segment_map != NULL) + { + struct elf_segment_map *m; + + segs = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++segs; + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; + } + + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; + + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + { + /* We need a PT_DYNAMIC segment. */ + ++segs; + } + + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_additional_program_headers) + { + int a; + + a = (*bed->elf_backend_additional_program_headers) (abfd); + if (a == -1) + abort (); + segs += a; + } + + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; +} + +/* Work out the file positions of all the sections. This is called by + _bfd_elf_compute_section_file_positions. All the section sizes and + VMAs must be known before this is called. + + We do not consider reloc sections at this point, unless they form + part of the loadable image. Reloc sections are assigned file + positions in assign_file_positions_for_relocs, which is called by + write_object_contents and final_link. + + We also don't set the positions of the .symtab and .strtab here. */ + +static boolean +assign_file_positions_except_relocs (abfd) + bfd *abfd; +{ + struct elf_obj_tdata * const tdata = elf_tdata (abfd); + Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + file_ptr off; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + { + Elf_Internal_Shdr **hdrpp; + unsigned int i; + + /* Start after the ELF header. */ + off = i_ehdrp->e_ehsize; + + /* We are not creating an executable, which means that we are + not creating a program header, and that the actual order of + the sections in the file is unimportant. */ + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + { + hdr->sh_offset = -1; + continue; + } + if (i == tdata->symtab_section + || i == tdata->strtab_section) + { + hdr->sh_offset = -1; + continue; + } + + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + } + } + else + { + unsigned int i; + Elf_Internal_Shdr **hdrpp; + + /* Assign file positions for the loaded sections based on the + assignment of sections to segments. */ + if (! assign_file_positions_for_segments (abfd)) + return false; + + /* Assign file positions for the other sections. */ + + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->bfd_section != NULL + && hdr->bfd_section->filepos != 0) + hdr->sh_offset = hdr->bfd_section->filepos; + else if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + ((*_bfd_error_handler) + ("%s: warning: allocated section `%s' not in segment", + bfd_get_filename (abfd), + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + off += (hdr->sh_addr - off) % bed->maxpagesize; + off = _bfd_elf_assign_file_position_for_section (hdr, off, + false); + } + else if (hdr->sh_type == SHT_REL + || hdr->sh_type == SHT_RELA + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + } + } + + /* Place the section headers. */ + off = align_file_position (off, bed->s->file_align); + i_ehdrp->e_shoff = off; + off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; + + elf_tdata (abfd)->next_file_pos = off; + + return true; +} + +static boolean +prep_headers (abfd) + bfd *abfd; +{ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + int count; + struct bfd_strtab_hash *shstrtab; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + + shstrtab = _bfd_elf_stringtab_init (); + if (shstrtab == NULL) + return false; + + elf_shstrtab (abfd) = shstrtab; + + i_ehdrp->e_ident[EI_MAG0] = ELFMAG0; + i_ehdrp->e_ident[EI_MAG1] = ELFMAG1; + i_ehdrp->e_ident[EI_MAG2] = ELFMAG2; + i_ehdrp->e_ident[EI_MAG3] = ELFMAG3; + + i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass; + i_ehdrp->e_ident[EI_DATA] = + bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB; + i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current; + + for (count = EI_PAD; count < EI_NIDENT; count++) + i_ehdrp->e_ident[count] = 0; + + if ((abfd->flags & DYNAMIC) != 0) + i_ehdrp->e_type = ET_DYN; + else if ((abfd->flags & EXEC_P) != 0) + i_ehdrp->e_type = ET_EXEC; + else + i_ehdrp->e_type = ET_REL; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_unknown: + i_ehdrp->e_machine = EM_NONE; + break; + case bfd_arch_sparc: + if (bed->s->arch_size == 64) + i_ehdrp->e_machine = EM_SPARC64; + else + i_ehdrp->e_machine = EM_SPARC; + break; + case bfd_arch_i386: + i_ehdrp->e_machine = EM_386; + break; + case bfd_arch_m68k: + i_ehdrp->e_machine = EM_68K; + break; + case bfd_arch_m88k: + i_ehdrp->e_machine = EM_88K; + break; + case bfd_arch_i860: + i_ehdrp->e_machine = EM_860; + break; + case bfd_arch_mips: /* MIPS Rxxxx */ + i_ehdrp->e_machine = EM_MIPS; /* only MIPS R3000 */ + break; + case bfd_arch_hppa: + i_ehdrp->e_machine = EM_PARISC; + break; + case bfd_arch_powerpc: + i_ehdrp->e_machine = EM_PPC; + break; + /* also note that EM_M32, AT&T WE32100 is unknown to bfd */ + default: + i_ehdrp->e_machine = EM_NONE; + } + i_ehdrp->e_version = bed->s->ev_current; + i_ehdrp->e_ehsize = bed->s->sizeof_ehdr; + + /* no program header, for now. */ + i_ehdrp->e_phoff = 0; + i_ehdrp->e_phentsize = 0; + i_ehdrp->e_phnum = 0; + + /* each bfd section is section header entry */ + i_ehdrp->e_entry = bfd_get_start_address (abfd); + i_ehdrp->e_shentsize = bed->s->sizeof_shdr; + + /* if we're building an executable, we'll need a program header table */ + if (abfd->flags & EXEC_P) + { + /* it all happens later */ +#if 0 + i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); + + /* elf_build_phdrs() returns a (NULL-terminated) array of + Elf_Internal_Phdrs */ + i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum); + i_ehdrp->e_phoff = outbase; + outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum; +#endif + } + else + { + i_ehdrp->e_phentsize = 0; + i_phdrp = 0; + i_ehdrp->e_phoff = 0; + } + + elf_tdata (abfd)->symtab_hdr.sh_name = + (unsigned int) _bfd_stringtab_add (shstrtab, ".symtab", true, false); + elf_tdata (abfd)->strtab_hdr.sh_name = + (unsigned int) _bfd_stringtab_add (shstrtab, ".strtab", true, false); + elf_tdata (abfd)->shstrtab_hdr.sh_name = + (unsigned int) _bfd_stringtab_add (shstrtab, ".shstrtab", true, false); + if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 + || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 + || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1) + return false; + + return true; +} + +/* Assign file positions for all the reloc sections which are not part + of the loadable file image. */ + +void +_bfd_elf_assign_file_positions_for_relocs (abfd) + bfd *abfd; +{ + file_ptr off; + unsigned int i; + Elf_Internal_Shdr **shdrpp; + + off = elf_tdata (abfd)->next_file_pos; + + for (i = 1, shdrpp = elf_elfsections (abfd) + 1; + i < elf_elfheader (abfd)->e_shnum; + i++, shdrpp++) + { + Elf_Internal_Shdr *shdrp; + + shdrp = *shdrpp; + if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA) + && shdrp->sh_offset == -1) + off = _bfd_elf_assign_file_position_for_section (shdrp, off, true); + } + + elf_tdata (abfd)->next_file_pos = off; +} + +boolean +_bfd_elf_write_object_contents (abfd) + bfd *abfd; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Ehdr *i_ehdrp; + Elf_Internal_Shdr **i_shdrp; + boolean failed; + unsigned int count; + + if (! abfd->output_has_begun + && ! _bfd_elf_compute_section_file_positions (abfd, + (struct bfd_link_info *) NULL)) + return false; + + i_shdrp = elf_elfsections (abfd); + i_ehdrp = elf_elfheader (abfd); + + failed = false; + bfd_map_over_sections (abfd, bed->s->write_relocs, &failed); + if (failed) + return false; + _bfd_elf_assign_file_positions_for_relocs (abfd); + + /* After writing the headers, we need to write the sections too... */ + for (count = 1; count < i_ehdrp->e_shnum; count++) + { + if (bed->elf_backend_section_processing) + (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); + if (i_shdrp[count]->contents) + { + if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0 + || (bfd_write (i_shdrp[count]->contents, i_shdrp[count]->sh_size, + 1, abfd) + != i_shdrp[count]->sh_size)) + return false; + } + } + + /* Write out the section header names. */ + if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 + || ! _bfd_stringtab_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); + + return bed->s->write_shdrs_and_ehdr (abfd); +} + +/* given a section, search the header to find them... */ +int +_bfd_elf_section_from_bfd_section (abfd, asect) + bfd *abfd; + struct sec *asect; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd); + int index; + Elf_Internal_Shdr *hdr; + int maxindex = elf_elfheader (abfd)->e_shnum; + + for (index = 0; index < maxindex; index++) + { + hdr = i_shdrp[index]; + if (hdr->bfd_section == asect) + return index; + } + + if (bed->elf_backend_section_from_bfd_section) + { + for (index = 0; index < maxindex; index++) + { + int retval; + + hdr = i_shdrp[index]; + retval = index; + if ((*bed->elf_backend_section_from_bfd_section) + (abfd, hdr, asect, &retval)) + return retval; + } + } + + if (bfd_is_abs_section (asect)) + return SHN_ABS; + if (bfd_is_com_section (asect)) + return SHN_COMMON; + if (bfd_is_und_section (asect)) + return SHN_UNDEF; + + return -1; +} + +/* Given a BFD symbol, return the index in the ELF symbol table, or -1 + on error. */ + +int +_bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) + bfd *abfd; + struct symbol_cache_entry **asym_ptr_ptr; +{ + struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr; + int idx; + flagword flags = asym_ptr->flags; + + /* When gas creates relocations against local labels, it creates its + own symbol for the section, but does put the symbol into the + symbol chain, so udata is 0. When the linker is generating + relocatable output, this section symbol may be for one of the + input sections rather than the output section. */ + if (asym_ptr->udata.i == 0 + && (flags & BSF_SECTION_SYM) + && asym_ptr->section) + { + int indx; + + if (asym_ptr->section->output_section != NULL) + indx = asym_ptr->section->output_section->index; + else + indx = asym_ptr->section->index; + if (elf_section_syms (abfd)[indx]) + asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; + } + + idx = asym_ptr->udata.i; + + if (idx == 0) + { + /* This case can occur when using --strip-symbol on a symbol + which is used in a relocation entry. */ + (*_bfd_error_handler) + ("%s: symbol `%s' required but not present", + bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr)); + bfd_set_error (bfd_error_no_symbols); + return -1; + } + +#if DEBUG & 4 + { + fprintf (stderr, + "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n", + (long) asym_ptr, asym_ptr->name, idx, flags, + elf_symbol_flags (flags)); + fflush (stderr); + } +#endif + + return idx; +} + +/* Copy private BFD data. This copies any program header information. */ + +static boolean +copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + Elf_Internal_Ehdr *iehdr; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + Elf_Internal_Phdr *p; + unsigned int i, c; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + if (elf_tdata (ibfd)->phdr == NULL) + return true; + + iehdr = elf_elfheader (ibfd); + + mfirst = NULL; + pm = &mfirst; + + c = elf_elfheader (ibfd)->e_phnum; + for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++) + { + unsigned int csecs; + asection *s; + struct elf_segment_map *m; + unsigned int isec; + + csecs = 0; + + /* The complicated case when p_vaddr is 0 is to handle the + Solaris linker, which generates a PT_INTERP section with + p_vaddr and p_memsz set to 0. */ + for (s = ibfd->sections; s != NULL; s = s->next) + if (((s->vma >= p->p_vaddr + && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz + || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) + || (p->p_vaddr == 0 + && p->p_filesz > 0 + && (s->flags & SEC_HAS_CONTENTS) != 0 + && (bfd_vma) s->filepos >= p->p_offset + && ((bfd_vma) s->filepos + s->_raw_size + <= p->p_offset + p->p_filesz))) + && (s->flags & SEC_ALLOC) != 0 + && s->output_section != NULL) + ++csecs; + + m = ((struct elf_segment_map *) + bfd_alloc (obfd, + (sizeof (struct elf_segment_map) + + (csecs - 1) * sizeof (asection *)))); + if (m == NULL) + return false; + + m->next = NULL; + m->p_type = p->p_type; + m->p_flags = p->p_flags; + m->p_flags_valid = 1; + m->p_paddr = p->p_paddr; + m->p_paddr_valid = 1; + + m->includes_filehdr = (p->p_offset == 0 + && p->p_filesz >= iehdr->e_ehsize); + + m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff + && (p->p_offset + p->p_filesz + >= ((bfd_vma) iehdr->e_phoff + + iehdr->e_phnum * iehdr->e_phentsize))); + + isec = 0; + for (s = ibfd->sections; s != NULL; s = s->next) + { + if (((s->vma >= p->p_vaddr + && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz + || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) + || (p->p_vaddr == 0 + && p->p_filesz > 0 + && (s->flags & SEC_HAS_CONTENTS) != 0 + && (bfd_vma) s->filepos >= p->p_offset + && ((bfd_vma) s->filepos + s->_raw_size + <= p->p_offset + p->p_filesz))) + && (s->flags & SEC_ALLOC) != 0 + && s->output_section != NULL) + { + m->sections[isec] = s->output_section; + ++isec; + } + } + BFD_ASSERT (isec == csecs); + m->count = csecs; + + *pm = m; + pm = &m->next; + } + + elf_tdata (obfd)->segment_map = mfirst; + + return true; +} + +/* Copy private section information. This copies over the entsize + field, and sometimes the info field. */ + +boolean +_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) + bfd *ibfd; + asection *isec; + bfd *obfd; + asection *osec; +{ + Elf_Internal_Shdr *ihdr, *ohdr; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return true; + + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + 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) + { + asection *s; + + /* Only set up the segments when all the sections have been set + up. */ + for (s = ibfd->sections; s != NULL; s = s->next) + if (s->output_section == NULL) + break; + if (s == NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return false; + } + } + + ihdr = &elf_section_data (isec)->this_hdr; + ohdr = &elf_section_data (osec)->this_hdr; + + ohdr->sh_entsize = ihdr->sh_entsize; + + if (ihdr->sh_type == SHT_SYMTAB + || ihdr->sh_type == SHT_DYNSYM) + ohdr->sh_info = ihdr->sh_info; + + return true; +} + +/* Copy private symbol information. If this symbol is in a section + which we did not map into a BFD section, try to map the section + index correctly. We use special macro definitions for the mapped + section indices; these definitions are interpreted by the + swap_out_syms function. */ + +#define MAP_ONESYMTAB (SHN_LORESERVE - 1) +#define MAP_DYNSYMTAB (SHN_LORESERVE - 2) +#define MAP_STRTAB (SHN_LORESERVE - 3) +#define MAP_SHSTRTAB (SHN_LORESERVE - 4) + +boolean +_bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) + bfd *ibfd; + asymbol *isymarg; + bfd *obfd; + asymbol *osymarg; +{ + elf_symbol_type *isym, *osym; + + isym = elf_symbol_from (ibfd, isymarg); + osym = elf_symbol_from (obfd, osymarg); + + if (isym != NULL + && osym != NULL + && bfd_is_abs_section (isym->symbol.section)) + { + unsigned int shndx; + + shndx = isym->internal_elf_sym.st_shndx; + if (shndx == elf_onesymtab (ibfd)) + shndx = MAP_ONESYMTAB; + else if (shndx == elf_dynsymtab (ibfd)) + shndx = MAP_DYNSYMTAB; + else if (shndx == elf_tdata (ibfd)->strtab_section) + shndx = MAP_STRTAB; + else if (shndx == elf_tdata (ibfd)->shstrtab_section) + shndx = MAP_SHSTRTAB; + osym->internal_elf_sym.st_shndx = shndx; + } + + return true; +} + +/* Swap out the symbols. */ + +static boolean +swap_out_syms (abfd, sttp) + bfd *abfd; + struct bfd_strtab_hash **sttp; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (!elf_map_symbols (abfd)) + return false; + + /* Dump out the symtabs. */ + { + int symcount = bfd_get_symcount (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + struct bfd_strtab_hash *stt; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symstrtab_hdr; + char *outbound_syms; + int idx; + + stt = _bfd_elf_stringtab_init (); + if (stt == NULL) + return false; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + 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_addralign = bed->s->file_align; + + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + symstrtab_hdr->sh_type = SHT_STRTAB; + + outbound_syms = bfd_alloc (abfd, + (1 + symcount) * bed->s->sizeof_sym); + if (outbound_syms == NULL) + return false; + symtab_hdr->contents = (PTR) outbound_syms; + + /* now generate the data (for "contents") */ + { + /* Fill in zeroth symbol and swap it out. */ + Elf_Internal_Sym sym; + sym.st_name = 0; + sym.st_value = 0; + sym.st_size = 0; + sym.st_info = 0; + sym.st_other = 0; + sym.st_shndx = SHN_UNDEF; + bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms); + outbound_syms += bed->s->sizeof_sym; + } + for (idx = 0; idx < symcount; idx++) + { + Elf_Internal_Sym sym; + bfd_vma value = syms[idx]->value; + elf_symbol_type *type_ptr; + flagword flags = syms[idx]->flags; + int type; + + if (flags & BSF_SECTION_SYM) + /* Section symbols have no names. */ + sym.st_name = 0; + else + { + sym.st_name = (unsigned long) _bfd_stringtab_add (stt, + syms[idx]->name, + true, false); + if (sym.st_name == (unsigned long) -1) + return false; + } + + type_ptr = elf_symbol_from (abfd, syms[idx]); + + if (bfd_is_com_section (syms[idx]->section)) + { + /* ELF common symbols put the alignment into the `value' field, + and the size into the `size' field. This is backwards from + how BFD handles it, so reverse it here. */ + sym.st_size = value; + if (type_ptr == NULL + || type_ptr->internal_elf_sym.st_value == 0) + sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value)); + else + sym.st_value = type_ptr->internal_elf_sym.st_value; + sym.st_shndx = _bfd_elf_section_from_bfd_section (abfd, + syms[idx]->section); + } + else + { + asection *sec = syms[idx]->section; + int shndx; + + if (sec->output_section) + { + value += sec->output_offset; + sec = sec->output_section; + } + value += sec->vma; + sym.st_value = value; + sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; + + if (bfd_is_abs_section (sec) + && type_ptr != NULL + && type_ptr->internal_elf_sym.st_shndx != 0) + { + /* This symbol is in a real ELF section which we did + not create as a BFD section. Undo the mapping done + by copy_private_symbol_data. */ + shndx = type_ptr->internal_elf_sym.st_shndx; + switch (shndx) + { + case MAP_ONESYMTAB: + shndx = elf_onesymtab (abfd); + break; + case MAP_DYNSYMTAB: + shndx = elf_dynsymtab (abfd); + break; + case MAP_STRTAB: + shndx = elf_tdata (abfd)->strtab_section; + break; + case MAP_SHSTRTAB: + shndx = elf_tdata (abfd)->shstrtab_section; + break; + default: + break; + } + } + else + { + shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + if (shndx == -1) + { + asection *sec2; + + /* Writing this would be a hell of a lot easier if + we had some decent documentation on bfd, and + knew what to expect of the library, and what to + demand of applications. For example, it + appears that `objcopy' might not set the + section of a symbol to be a section that is + actually in the output file. */ + sec2 = bfd_get_section_by_name (abfd, sec->name); + BFD_ASSERT (sec2 != 0); + shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); + BFD_ASSERT (shndx != -1); + } + } + + sym.st_shndx = shndx; + } + + if ((flags & BSF_FUNCTION) != 0) + type = STT_FUNC; + else if ((flags & BSF_OBJECT) != 0) + type = STT_OBJECT; + else + type = STT_NOTYPE; + + if (bfd_is_com_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); + else if (bfd_is_und_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) + ? STB_WEAK + : STB_GLOBAL), + type); + else if (flags & BSF_SECTION_SYM) + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + else if (flags & BSF_FILE) + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + else + { + int bind = STB_LOCAL; + + if (flags & BSF_LOCAL) + bind = STB_LOCAL; + else if (flags & BSF_WEAK) + bind = STB_WEAK; + else if (flags & BSF_GLOBAL) + bind = STB_GLOBAL; + + sym.st_info = ELF_ST_INFO (bind, type); + } + + sym.st_other = 0; + bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms); + outbound_syms += bed->s->sizeof_sym; + } + + *sttp = stt; + symstrtab_hdr->sh_size = _bfd_stringtab_size (stt); + symstrtab_hdr->sh_type = SHT_STRTAB; + + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + symstrtab_hdr->sh_addralign = 1; + } + + return true; +} + +/* Return the number of bytes required to hold the symtab vector. + + Note that we base it on the count plus 1, since we will null terminate + the vector allocated based on this size. However, the ELF symbol table + always has a dummy entry as symbol #0, so it ends up even. */ + +long +_bfd_elf_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr; + + symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *)); + + return symtab_size; +} + +long +_bfd_elf_get_dynamic_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *)); + + return symtab_size; +} + +long +_bfd_elf_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +/* Canonicalize the relocs. */ + +long +_bfd_elf_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr; + unsigned int i; + + if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd, section, symbols)) + return -1; + + tblptr = section->relocation; + for (i = 0; i < section->reloc_count; i++) + *relptr++ = tblptr++; + + *relptr = NULL; + + return section->reloc_count; +} + +long +_bfd_elf_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, false); + + if (symcount >= 0) + bfd_get_symcount (abfd) = symcount; + return symcount; +} + +long +_bfd_elf_canonicalize_dynamic_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true); +} + +asymbol * +_bfd_elf_make_empty_symbol (abfd) + bfd *abfd; +{ + elf_symbol_type *newsym; + + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type)); + if (!newsym) + return NULL; + else + { + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; + } +} + +void +_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +alent * +_bfd_elf_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + abort (); + return NULL; +} + +boolean +_bfd_elf_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + /* If this isn't the right architecture for this backend, and this + isn't the generic backend, fail. */ + if (arch != get_elf_backend_data (abfd)->arch + && arch != bfd_arch_unknown + && get_elf_backend_data (abfd)->arch != bfd_arch_unknown) + return false; + + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +/* Find the nearest line to a particular section and offset, for error + reporting. */ + +boolean +_bfd_elf_find_nearest_line (abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *line_ptr; +{ + boolean found; + const char *filename; + asymbol *func; + bfd_vma low_func; + asymbol **p; + + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &elf_tdata (abfd)->line_info)) + return false; + if (found) + return true; + + if (symbols == NULL) + return false; + + filename = NULL; + func = NULL; + low_func = 0; + + for (p = symbols; *p != NULL; p++) + { + elf_symbol_type *q; + + q = (elf_symbol_type *) *p; + + if (bfd_get_section (&q->symbol) != section) + continue; + + switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) + { + default: + break; + case STT_FILE: + filename = bfd_asymbol_name (&q->symbol); + break; + case STT_FUNC: + if (q->symbol.section == section + && q->symbol.value >= low_func + && q->symbol.value <= offset) + { + func = (asymbol *) q; + low_func = q->symbol.value; + } + break; + } + } + + if (func == NULL) + return false; + + *filename_ptr = filename; + *functionname_ptr = bfd_asymbol_name (func); + *line_ptr = 0; + return true; +} + +int +_bfd_elf_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + int ret; + + ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; + if (! reloc) + ret += get_program_header_size (abfd); + return ret; +} + +boolean +_bfd_elf_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + Elf_Internal_Shdr *hdr; + + if (! abfd->output_has_begun + && ! _bfd_elf_compute_section_file_positions (abfd, + (struct bfd_link_info *) NULL)) + return false; + + hdr = &elf_section_data (section)->this_hdr; + + if (bfd_seek (abfd, hdr->sh_offset + offset, SEEK_SET) == -1) + return false; + if (bfd_write (location, 1, count, abfd) != count) + return false; + + return true; +} + +void +_bfd_elf_no_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + abort (); +} + +#if 0 +void +_bfd_elf_no_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rel *dst; +{ + abort (); +} +#endif diff --git a/contrib/gdb/bfd/elf32-gen.c b/contrib/gdb/bfd/elf32-gen.c new file mode 100644 index 000000000000..385fda208602 --- /dev/null +++ b/contrib/gdb/bfd/elf32-gen.c @@ -0,0 +1,37 @@ +/* Generic support for 32-bit ELF + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* This does not include any relocations, but should be good enough + for GDB to read the file. */ + +#define TARGET_LITTLE_SYM bfd_elf32_little_generic_vec +#define TARGET_LITTLE_NAME "elf32-little" +#define TARGET_BIG_SYM bfd_elf32_big_generic_vec +#define TARGET_BIG_NAME "elf32-big" +#define ELF_ARCH bfd_arch_unknown +#define ELF_MACHINE_CODE EM_NONE +#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define elf_info_to_howto _bfd_elf_no_info_to_howto + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-hppa.c b/contrib/gdb/bfd/elf32-hppa.c new file mode 100644 index 000000000000..238673170322 --- /dev/null +++ b/contrib/gdb/bfd/elf32-hppa.c @@ -0,0 +1,2984 @@ +/* BFD back-end for HP PA-RISC ELF files. + Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + + Written by + + Center for Software Science + Department of Computer Science + University of Utah + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "obstack.h" +#include "elf-bfd.h" + +/* The internal type of a symbol table extension entry. */ +typedef unsigned long symext_entryS; + +/* The external type of a symbol table extension entry. */ +#define ELF32_PARISC_SX_SIZE (4) +#define ELF32_PARISC_SX_GET(bfd, addr) bfd_h_get_32 ((bfd), (addr)) +#define ELF32_PARISC_SX_PUT(bfd, val, addr) \ + bfd_h_put_32 ((bfd), (val), (addr)) + +/* HPPA symbol table extension entry types */ +enum elf32_hppa_symextn_types +{ + PARISC_SXT_NULL, + PARISC_SXT_SYMNDX, + PARISC_SXT_ARG_RELOC, +}; + +/* These macros compose and decompose the value of a symextn entry: + + entry_type = ELF32_PARISC_SX_TYPE(word); + entry_value = ELF32_PARISC_SX_VAL(word); + word = ELF32_PARISC_SX_WORD(type,val); */ + +#define ELF32_PARISC_SX_TYPE(p) ((p) >> 24) +#define ELF32_PARISC_SX_VAL(p) ((p) & 0xFFFFFF) +#define ELF32_PARISC_SX_WORD(type,val) (((type) << 24) + (val & 0xFFFFFF)) + +/* The following was added facilitate implementation of the .hppa_symextn + section. This section is built after the symbol table is built in the + elf_write_object_contents routine (called from bfd_close). It is built + so late because it requires information that is not known until + the symbol and string table sections have been allocated, and + the symbol table has been built. */ + +#define SYMEXTN_SECTION_NAME ".PARISC.symext" + +struct symext_chain + { + symext_entryS entry; + struct symext_chain *next; + }; + +typedef struct symext_chain symext_chainS; + +/* We use three different hash tables to hold information for + linking PA ELF objects. + + The first is the elf32_hppa_link_hash_table which is derived + from the standard ELF linker hash table. We use this as a place to + attach other hash tables and static information. + + The second is the stub hash table which is derived from the + base BFD hash table. The stub hash table holds the information + necessary to build the linker stubs during a link. + + The last hash table keeps track of argument location information needed + to build hash tables. Each function with nonzero argument location + bits will have an entry in this table. */ + +/* Hash table for linker stubs. */ + +struct elf32_hppa_stub_hash_entry +{ + /* Base hash table entry structure, we can get the name of the stub + (and thus know exactly what actions it performs) from the base + hash table entry. */ + struct bfd_hash_entry root; + + /* Offset of the beginning of this stub. */ + bfd_vma offset; + + /* Given the symbol's value and its section we can determine its final + value when building the stubs (so the stub knows where to jump. */ + symvalue target_value; + asection *target_section; +}; + +struct elf32_hppa_stub_hash_table +{ + /* The hash table itself. */ + struct bfd_hash_table root; + + /* The stub BFD. */ + bfd *stub_bfd; + + /* Where to place the next stub. */ + bfd_byte *location; + + /* Current offset in the stub section. */ + unsigned int offset; + +}; + +/* Hash table for argument location information. */ + +struct elf32_hppa_args_hash_entry +{ + /* Base hash table entry structure. */ + struct bfd_hash_entry root; + + /* The argument location bits for this entry. */ + int arg_bits; +}; + +struct elf32_hppa_args_hash_table +{ + /* The hash table itself. */ + struct bfd_hash_table root; +}; + +struct elf32_hppa_link_hash_entry +{ + struct elf_link_hash_entry root; +}; + +struct elf32_hppa_link_hash_table +{ + /* The main hash table. */ + struct elf_link_hash_table root; + + /* The stub hash table. */ + struct elf32_hppa_stub_hash_table *stub_hash_table; + + /* The argument relocation bits hash table. */ + struct elf32_hppa_args_hash_table *args_hash_table; + + /* A count of the number of output symbols. */ + unsigned int output_symbol_count; + + /* Stuff so we can handle DP relative relocations. */ + long global_value; + int global_sym_defined; +}; + +/* FIXME. */ +#define ARGUMENTS 0 +#define RETURN_VALUE 1 + +/* The various argument relocations that may be performed. */ +typedef enum +{ + /* No relocation. */ + NO, + /* Relocate 32 bits from GR to FP register. */ + GF, + /* Relocate 64 bits from a GR pair to FP pair. */ + GD, + /* Relocate 32 bits from FP to GR. */ + FG, + /* Relocate 64 bits from FP pair to GR pair. */ + DG, +} arg_reloc_type; + +/* What is being relocated (eg which argument or the return value). */ +typedef enum +{ + ARG0, ARG1, ARG2, ARG3, RET, +} arg_reloc_location; + + +/* ELF32/HPPA relocation support + + This file contains ELF32/HPPA relocation support as specified + in the Stratus FTX/Golf Object File Format (SED-1762) dated + February 1994. */ + +#include "elf32-hppa.h" +#include "hppa_stubs.h" + +static bfd_reloc_status_type hppa_elf_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + +static unsigned long hppa_elf_relocate_insn + PARAMS ((bfd *, asection *, unsigned long, unsigned long, long, + long, unsigned long, unsigned long, unsigned long)); + +static bfd_reloc_status_type hppa_elf_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd*, char **)); + +static reloc_howto_type * elf_hppa_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); + +static boolean elf32_hppa_set_section_contents + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + +static void elf_info_to_howto + PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); + +static boolean elf32_hppa_backend_symbol_table_processing + PARAMS ((bfd *, elf_symbol_type *, unsigned int)); + +static void elf32_hppa_backend_begin_write_processing + PARAMS ((bfd *, struct bfd_link_info *)); + +static void elf32_hppa_backend_final_write_processing + PARAMS ((bfd *, boolean)); + +static void add_entry_to_symext_chain + PARAMS ((bfd *, unsigned int, unsigned int, symext_chainS **, + symext_chainS **)); + +static void +elf_hppa_tc_make_sections PARAMS ((bfd *, symext_chainS *)); + +static boolean hppa_elf_is_local_label PARAMS ((bfd *, asymbol *)); + +static boolean elf32_hppa_add_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); + +static bfd_reloc_status_type elf32_hppa_bfd_final_link_relocate + PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma, struct bfd_link_info *, + asection *, const char *, int)); + +static struct bfd_link_hash_table *elf32_hppa_link_hash_table_create + PARAMS ((bfd *)); + +static struct bfd_hash_entry * +elf32_hppa_stub_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +static struct bfd_hash_entry * +elf32_hppa_args_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +static boolean +elf32_hppa_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, + bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); + +static boolean +elf32_hppa_stub_hash_table_init + PARAMS ((struct elf32_hppa_stub_hash_table *, bfd *, + struct bfd_hash_entry *(*) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)))); + +static boolean +elf32_hppa_build_one_stub PARAMS ((struct bfd_hash_entry *, PTR)); + +static boolean +elf32_hppa_read_symext_info + PARAMS ((bfd *, Elf_Internal_Shdr *, struct elf32_hppa_args_hash_table *, + Elf_Internal_Sym *)); + +static unsigned int elf32_hppa_size_of_stub + PARAMS ((unsigned int, unsigned int, bfd_vma, bfd_vma, const char *)); + +static boolean elf32_hppa_arg_reloc_needed + PARAMS ((unsigned int, unsigned int, arg_reloc_type [])); + +static void elf32_hppa_name_of_stub + PARAMS ((unsigned int, unsigned int, bfd_vma, bfd_vma, char *)); + +static boolean elf32_hppa_size_symext PARAMS ((struct bfd_hash_entry *, PTR)); + +static boolean elf32_hppa_link_output_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const char *, + Elf_Internal_Sym *, asection *)); + +/* ELF/PA relocation howto entries. */ + +static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] = +{ + {R_PARISC_NONE, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_NONE"}, + {R_PARISC_DIR32, 0, 0, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DIR32"}, + {R_PARISC_DIR21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DIR21L"}, + {R_PARISC_DIR17R, 0, 0, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DIR17R"}, + {R_PARISC_DIR17F, 0, 0, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DIR17F"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DIR14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DIR14R"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_PCREL21L, 0, 0, 21, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL21L"}, + {R_PARISC_PCREL17R, 0, 0, 17, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL17R"}, + {R_PARISC_PCREL17F, 0, 0, 17, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL17F"}, + {R_PARISC_PCREL17C, 0, 0, 17, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL17C"}, + {R_PARISC_PCREL14R, 0, 0, 14, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL14R"}, + {R_PARISC_PCREL14F, 0, 0, 14, true, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PCREL14F"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DPREL21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DPREL21L"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DPREL14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DPREL14R"}, + {R_PARISC_DPREL14F, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DPREL14F"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DLTREL21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTREL21L"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DLTREL14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTREL14R"}, + {R_PARISC_DLTREL14F, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTREL14F"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DLTIND21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTIND21L"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DLTIND14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTIND14R"}, + {R_PARISC_DLTIND14F, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_DLTIND14F"}, + + {R_PARISC_SETBASE, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_SETBASE"}, + {R_PARISC_BASEREL32, 0, 0, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL32"}, + {R_PARISC_BASEREL21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL21L"}, + {R_PARISC_BASEREL17R, 0, 0, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL17R"}, + {R_PARISC_BASEREL17F, 0, 0, 17, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL17F"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_BASEREL14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL14R"}, + {R_PARISC_BASEREL14F, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_BASEREL14F"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_TEXTREL32, 0, 0, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_TEXTREL32"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_DATAREL32, 0, 0, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_PLABEL32, 0, 0, 32, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLABEL32"}, + {R_PARISC_PLABEL21L, 0, 0, 21, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLABEL21L"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_PLABEL14R, 0, 0, 14, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLABEL14R"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_PLTIND21L, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLTIND21L"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_UNIMPLEMENTED"}, + {R_PARISC_PLTIND14R, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLTIND14R"}, + {R_PARISC_PLTIND14F, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_PLTIND14F"}, + + + {R_PARISC_COPY, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_COPY"}, + {R_PARISC_GLOB_DAT, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_GLOB_DAT"}, + {R_PARISC_JMP_SLOT, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_JMP_SLOT"}, + {R_PARISC_RELATIVE, 0, 0, 0, false, 0, complain_overflow_bitfield, hppa_elf_reloc, "R_PARISC_RELATIVE"}, + + {R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_dont, NULL, "R_PARISC_UNIMPLEMENTED"}, +}; + +/* Where (what register type) is an argument comming from? */ +typedef enum +{ + AR_NO, + AR_GR, + AR_FR, + AR_FU, + AR_FPDBL1, + AR_FPDBL2, +} arg_location; + +/* Horizontal represents the callee's argument location information, + vertical represents caller's argument location information. Value at a + particular X,Y location represents what (if any) argument relocation + needs to be performed to make caller and callee agree. */ + +static CONST arg_reloc_type arg_mismatches[6][6] = +{ + {NO, NO, NO, NO, NO, NO}, + {NO, NO, GF, NO, GD, NO}, + {NO, FG, NO, NO, NO, NO}, + {NO, NO, NO, NO, NO, NO}, + {NO, DG, NO, NO, NO, NO}, + {NO, DG, NO, NO, NO, NO}, +}; + +/* Likewise, but reversed for the return value. */ +static CONST arg_reloc_type ret_mismatches[6][6] = +{ + {NO, NO, NO, NO, NO, NO}, + {NO, NO, FG, NO, DG, NO}, + {NO, GF, NO, NO, NO, NO}, + {NO, NO, NO, NO, NO, NO}, + {NO, GD, NO, NO, NO, NO}, + {NO, GD, NO, NO, NO, NO}, +}; + +/* Misc static crud for symbol extension records. */ +static symext_chainS *symext_rootP; +static symext_chainS *symext_lastP; +static bfd_size_type symext_chain_size; + +/* FIXME: We should be able to try this static variable! */ +static bfd_byte *symextn_contents; + + +/* For linker stub hash tables. */ +#define elf32_hppa_stub_hash_lookup(table, string, create, copy) \ + ((struct elf32_hppa_stub_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +#define elf32_hppa_stub_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ + (info))) + +/* For linker args hash tables. */ +#define elf32_hppa_args_hash_lookup(table, string, create, copy) \ + ((struct elf32_hppa_args_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +#define elf32_hppa_args_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ + (info))) + +#define elf32_hppa_args_hash_table_init(table, newfunc) \ + (bfd_hash_table_init \ + (&(table)->root, \ + (struct bfd_hash_entry *(*) PARAMS ((struct bfd_hash_entry *, \ + struct bfd_hash_table *, \ + const char *))) (newfunc))) + +/* For HPPA linker hash table. */ + +#define elf32_hppa_link_hash_lookup(table, string, create, copy, follow)\ + ((struct elf32_hppa_link_hash_entry *) \ + elf_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +#define elf32_hppa_link_hash_traverse(table, func, info) \ + (elf_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the PA ELF linker hash table from a link_info structure. */ + +#define elf32_hppa_hash_table(p) \ + ((struct elf32_hppa_link_hash_table *) ((p)->hash)) + + +/* Extract specific argument location bits for WHICH from + the full argument location in AR. */ +#define EXTRACT_ARBITS(ar, which) ((ar) >> (8 - ((which) * 2))) & 3 + +/* Assorted hash table functions. */ + +/* Initialize an entry in the stub hash table. */ + +static struct bfd_hash_entry * +elf32_hppa_stub_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct elf32_hppa_stub_hash_entry *ret; + + ret = (struct elf32_hppa_stub_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct elf32_hppa_stub_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf32_hppa_stub_hash_entry))); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf32_hppa_stub_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->offset = 0; + ret->target_value = 0; + ret->target_section = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a stub hash table. */ + +static boolean +elf32_hppa_stub_hash_table_init (table, stub_bfd, newfunc) + struct elf32_hppa_stub_hash_table *table; + bfd *stub_bfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->offset = 0; + table->location = 0; + table->stub_bfd = stub_bfd; + return (bfd_hash_table_init (&table->root, newfunc)); +} + +/* Initialize an entry in the argument location hash table. */ + +static struct bfd_hash_entry * +elf32_hppa_args_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct elf32_hppa_args_hash_entry *ret; + + ret = (struct elf32_hppa_args_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct elf32_hppa_args_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf32_hppa_args_hash_entry))); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf32_hppa_args_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + /* Initialize the local fields. */ + if (ret) + ret->arg_bits = 0; + + return (struct bfd_hash_entry *) ret; +} + +/* Create the derived linker hash table. The PA ELF port uses the derived + hash table to keep information specific to the PA ELF linker (without + using static variables). */ + +static struct bfd_link_hash_table * +elf32_hppa_link_hash_table_create (abfd) + bfd *abfd; +{ + struct elf32_hppa_link_hash_table *ret; + + ret = ((struct elf32_hppa_link_hash_table *) + bfd_alloc (abfd, sizeof (struct elf32_hppa_link_hash_table))); + if (ret == NULL) + return NULL; + if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, + _bfd_elf_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } + ret->stub_hash_table = NULL; + ret->args_hash_table = NULL; + ret->output_symbol_count = 0; + ret->global_value = 0; + ret->global_sym_defined = 0; + + return &ret->root.root; +} + +/* Relocate the given INSN given the various input parameters. + + FIXME: endianness and sizeof (long) issues abound here. */ + +static unsigned long +hppa_elf_relocate_insn (abfd, input_sect, insn, address, sym_value, + r_addend, r_format, r_field, pcrel) + bfd *abfd; + asection *input_sect; + unsigned long insn; + unsigned long address; + long sym_value; + long r_addend; + unsigned long r_format; + unsigned long r_field; + unsigned long pcrel; +{ + unsigned char opcode = get_opcode (insn); + long constant_value; + + switch (opcode) + { + case LDO: + case LDB: + case LDH: + case LDW: + case LDWM: + case STB: + case STH: + case STW: + case STWM: + case COMICLR: + case SUBI: + case ADDIT: + case ADDI: + case LDIL: + case ADDIL: + constant_value = HPPA_R_CONSTANT (r_addend); + + if (pcrel) + sym_value -= address; + + sym_value = hppa_field_adjust (sym_value, constant_value, r_field); + return hppa_rebuild_insn (abfd, insn, sym_value, r_format); + + case BL: + case BE: + case BLE: + /* XXX computing constant_value is not needed??? */ + constant_value = assemble_17 ((insn & 0x001f0000) >> 16, + (insn & 0x00001ffc) >> 2, + insn & 1); + + constant_value = (constant_value << 15) >> 15; + if (pcrel) + { + sym_value -= + address + input_sect->output_offset + + input_sect->output_section->vma; + sym_value = hppa_field_adjust (sym_value, -8, r_field); + } + else + sym_value = hppa_field_adjust (sym_value, constant_value, r_field); + + return hppa_rebuild_insn (abfd, insn, sym_value >> 2, r_format); + + default: + if (opcode == 0) + { + constant_value = HPPA_R_CONSTANT (r_addend); + + if (pcrel) + sym_value -= address; + + return hppa_field_adjust (sym_value, constant_value, r_field); + } + else + abort (); + } +} + +/* Relocate an HPPA ELF section. */ + +static boolean +elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sym_sec; + bfd_vma relocation; + bfd_reloc_status_type r; + const char *sym_name; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_PARISC_UNIMPLEMENTED) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = elf_hppa_howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sym_sec = local_sections[r_symndx]; + rel->r_addend += sym_sec->output_offset; + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sym_sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sym_sec = local_sections[r_symndx]; + relocation = ((ELF_ST_TYPE (sym->st_info) == STT_SECTION + ? 0 : sym->st_value) + + sym_sec->output_offset + + sym_sec->output_section->vma); + } + else + { + long indx; + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (input_bfd)[indx]; + 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; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sym_sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sym_sec->output_offset + + sym_sec->output_section->vma); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else + { + if (!((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + break; + } + } + + if (h != NULL) + sym_name = h->root.root.string; + else + { + sym_name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (sym_name == NULL) + return false; + if (*sym_name == '\0') + sym_name = bfd_section_name (input_bfd, sym_sec); + } + + /* If args_hash_table is NULL, then we have encountered some + kind of link error (ex. undefined symbols). Do not try to + apply any relocations, continue the loop so we can notify + the user of several errors in a single attempted link. */ + if (elf32_hppa_hash_table (info)->args_hash_table == NULL) + continue; + + r = elf32_hppa_bfd_final_link_relocate (howto, input_bfd, output_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend, info, sym_sec, + sym_name, h == NULL); + + if (r != bfd_reloc_ok) + { + switch (r) + { + /* This can happen for DP relative relocs if $global$ is + undefined. This is a panic situation so we don't try + to continue. */ + case bfd_reloc_undefined: + case bfd_reloc_notsupported: + if (!((*info->callbacks->undefined_symbol) + (info, "$global$", input_bfd, + input_section, rel->r_offset))) + return false; + return false; + case bfd_reloc_dangerous: + { + /* We use this return value to indicate that we performed + a "dangerous" relocation. This doesn't mean we did + the wrong thing, it just means there may be some cleanup + that needs to be done here. + + In particular we had to swap the last call insn and its + delay slot. If the delay slot insn needed a relocation, + then we'll need to adjust the next relocation entry's + offset to account for the fact that the insn moved. + + This hair wouldn't be necessary if we inserted stubs + between procedures and used a "bl" to get to the stub. */ + if (rel != relend) + { + Elf_Internal_Rela *next_rel = rel + 1; + + if (rel->r_offset + 4 == next_rel->r_offset) + next_rel->r_offset -= 4; + } + break; + } + default: + case bfd_reloc_outofrange: + case bfd_reloc_overflow: + { + if (!((*info->callbacks->reloc_overflow) + (info, sym_name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Return one (or more) BFD relocations which implement the base + relocation with modifications based on format and field. */ + +elf32_hppa_reloc_type ** +hppa_elf_gen_reloc_type (abfd, base_type, format, field, ignore) + bfd *abfd; + elf32_hppa_reloc_type base_type; + int format; + int field; + int ignore; +{ + elf32_hppa_reloc_type *finaltype; + elf32_hppa_reloc_type **final_types; + + /* Allocate slots for the BFD relocation. */ + final_types = (elf32_hppa_reloc_type **) + bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type *) * 2); + if (final_types == NULL) + return NULL; + + /* Allocate space for the relocation itself. */ + finaltype = (elf32_hppa_reloc_type *) + bfd_alloc_by_size_t (abfd, sizeof (elf32_hppa_reloc_type)); + if (finaltype == NULL) + return NULL; + + /* Some reasonable defaults. */ + final_types[0] = finaltype; + final_types[1] = NULL; + +#define final_type finaltype[0] + + final_type = base_type; + + /* Just a tangle of nested switch statements to deal with the braindamage + that a different field selector means a completely different relocation + for PA ELF. */ + switch (base_type) + { + case R_HPPA: + case R_HPPA_ABS_CALL: + switch (format) + { + case 14: + switch (field) + { + case e_rsel: + case e_rrsel: + final_type = R_PARISC_DIR14R; + break; + case e_rtsel: + final_type = R_PARISC_DLTREL14R; + break; + case e_tsel: + final_type = R_PARISC_DLTREL14F; + break; + case e_rpsel: + final_type = R_PARISC_PLABEL14R; + break; + default: + return NULL; + } + break; + + case 17: + switch (field) + { + case e_fsel: + final_type = R_PARISC_DIR17F; + break; + case e_rsel: + case e_rrsel: + final_type = R_PARISC_DIR17R; + break; + default: + return NULL; + } + break; + + case 21: + switch (field) + { + case e_lsel: + case e_lrsel: + final_type = R_PARISC_DIR21L; + break; + case e_ltsel: + final_type = R_PARISC_DLTREL21L; + break; + case e_lpsel: + final_type = R_PARISC_PLABEL21L; + break; + default: + return NULL; + } + break; + + case 32: + switch (field) + { + case e_fsel: + final_type = R_PARISC_DIR32; + break; + case e_psel: + final_type = R_PARISC_PLABEL32; + break; + default: + return NULL; + } + break; + + default: + return NULL; + } + break; + + + case R_HPPA_GOTOFF: + switch (format) + { + case 14: + switch (field) + { + case e_rsel: + case e_rrsel: + final_type = R_PARISC_DPREL14R; + break; + case e_fsel: + final_type = R_PARISC_DPREL14F; + break; + default: + return NULL; + } + break; + + case 21: + switch (field) + { + case e_lrsel: + case e_lsel: + final_type = R_PARISC_DPREL21L; + break; + default: + return NULL; + } + break; + + default: + return NULL; + } + break; + + + case R_HPPA_PCREL_CALL: + switch (format) + { + case 14: + switch (field) + { + case e_rsel: + case e_rrsel: + final_type = R_PARISC_PCREL14R; + break; + case e_fsel: + final_type = R_PARISC_PCREL14F; + break; + default: + return NULL; + } + break; + + case 17: + switch (field) + { + case e_rsel: + case e_rrsel: + final_type = R_PARISC_PCREL17R; + break; + case e_fsel: + final_type = R_PARISC_PCREL17F; + break; + default: + return NULL; + } + break; + + case 21: + switch (field) + { + case e_lsel: + case e_lrsel: + final_type = R_PARISC_PCREL21L; + break; + default: + return NULL; + } + break; + + default: + return NULL; + } + break; + + default: + return NULL; + } + + return final_types; +} + +#undef final_type + +/* Set the contents of a particular section at a particular location. */ + +static boolean +elf32_hppa_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + /* Ignore write requests for the symbol extension section until we've + had the chance to rebuild it ourselves. */ + if (!strcmp (section->name, ".PARISC.symextn") && !symext_chain_size) + return true; + else + return _bfd_elf_set_section_contents (abfd, section, location, + offset, count); +} + +/* Translate from an elf into field into a howto relocation pointer. */ + +static void +elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_PARISC_UNIMPLEMENTED); + cache_ptr->howto = &elf_hppa_howto_table[ELF32_R_TYPE (dst->r_info)]; +} + + +/* Actually perform a relocation. NOTE this is (mostly) superceeded + by elf32_hppa_bfd_final_link_relocate which is called by the new + fast linker. */ + +static bfd_reloc_status_type +hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* It is no longer valid to call hppa_elf_reloc when creating + a final executable. */ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + + /* Work around lossage in generic elf code to write relocations. + (maps different section symbols into the same symbol index). */ + if ((symbol_in->flags & BSF_SECTION_SYM) + && symbol_in->section) + reloc_entry->addend += symbol_in->section->output_offset; + return bfd_reloc_ok; + } + else + { + *error_message = (char *) "Unsupported call to hppa_elf_reloc"; + return bfd_reloc_notsupported; + } +} + +/* Actually perform a relocation as part of a final link. This can get + rather hairy when linker stubs are needed. */ + +static bfd_reloc_status_type +elf32_hppa_bfd_final_link_relocate (howto, input_bfd, output_bfd, + input_section, contents, offset, value, + addend, info, sym_sec, sym_name, is_local) + reloc_howto_type *howto; + bfd *input_bfd; + bfd *output_bfd; + asection *input_section; + bfd_byte *contents; + bfd_vma offset; + bfd_vma value; + bfd_vma addend; + struct bfd_link_info *info; + asection *sym_sec; + const char *sym_name; + int is_local; +{ + unsigned long insn; + unsigned long r_type = howto->type; + unsigned long r_format = howto->bitsize; + unsigned long r_field = e_fsel; + bfd_byte *hit_data = contents + offset; + boolean r_pcrel = howto->pc_relative; + + insn = bfd_get_32 (input_bfd, hit_data); + + /* Make sure we have a value for $global$. FIXME isn't this effectively + just like the gp pointer on MIPS? Can we use those routines for this + purpose? */ + if (!elf32_hppa_hash_table (info)->global_sym_defined) + { + struct elf_link_hash_entry *h; + asection *sec; + + h = elf_link_hash_lookup (elf_hash_table (info), "$global$", false, + false, false); + + /* If there isn't a $global$, then we're in deep trouble. */ + if (h == NULL) + return bfd_reloc_notsupported; + + /* If $global$ isn't a defined symbol, then we're still in deep + trouble. */ + if (h->root.type != bfd_link_hash_defined) + return bfd_reloc_undefined; + + sec = h->root.u.def.section; + elf32_hppa_hash_table (info)->global_value = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + elf32_hppa_hash_table (info)->global_sym_defined = 1; + } + + switch (r_type) + { + case R_PARISC_NONE: + break; + + case R_PARISC_DIR32: + case R_PARISC_DIR17F: + case R_PARISC_PCREL17C: + r_field = e_fsel; + goto do_basic_type_1; + case R_PARISC_DIR21L: + case R_PARISC_PCREL21L: + r_field = e_lrsel; + goto do_basic_type_1; + case R_PARISC_DIR17R: + case R_PARISC_PCREL17R: + case R_PARISC_DIR14R: + case R_PARISC_PCREL14R: + r_field = e_rrsel; + goto do_basic_type_1; + + /* For all the DP relative relocations, we need to examine the symbol's + section. If it's a code section, then "data pointer relative" makes + no sense. In that case we don't adjust the "value", and for 21 bit + addil instructions, we change the source addend register from %dp to + %r0. */ + case R_PARISC_DPREL21L: + r_field = e_lrsel; + if (sym_sec->flags & SEC_CODE) + { + if ((insn & 0xfc000000) >> 26 == 0xa + && (insn & 0x03e00000) >> 21 == 0x1b) + insn &= ~0x03e00000; + } + else + value -= elf32_hppa_hash_table (info)->global_value; + goto do_basic_type_1; + case R_PARISC_DPREL14R: + r_field = e_rrsel; + if ((sym_sec->flags & SEC_CODE) == 0) + value -= elf32_hppa_hash_table (info)->global_value; + goto do_basic_type_1; + case R_PARISC_DPREL14F: + r_field = e_fsel; + if ((sym_sec->flags & SEC_CODE) == 0) + value -= elf32_hppa_hash_table (info)->global_value; + goto do_basic_type_1; + + /* These cases are separate as they may involve a lot more work + to deal with linker stubs. */ + case R_PARISC_PLABEL32: + case R_PARISC_PLABEL21L: + case R_PARISC_PLABEL14R: + case R_PARISC_PCREL17F: + { + bfd_vma location; + unsigned int len, caller_args, callee_args; + arg_reloc_type arg_reloc_types[5]; + struct elf32_hppa_args_hash_table *args_hash_table; + struct elf32_hppa_args_hash_entry *args_hash; + char *new_name, *stub_name; + + /* Get the field selector right. We'll need it in a minute. */ + if (r_type == R_PARISC_PCREL17F + || r_type == R_PARISC_PLABEL32) + r_field = e_fsel; + else if (r_type == R_PARISC_PLABEL21L) + r_field = e_lrsel; + else if (r_type == R_PARISC_PLABEL14R) + r_field = e_rrsel; + + /* Find out where we are and where we're going. */ + location = (offset + + input_section->output_offset + + input_section->output_section->vma); + + /* Now look for the argument relocation bits associated with the + target. */ + len = strlen (sym_name) + 1; + if (is_local) + len += 9; + new_name = bfd_malloc (len); + if (!new_name) + return bfd_reloc_notsupported; + strcpy (new_name, sym_name); + + /* Local symbols have unique IDs. */ + if (is_local) + sprintf (new_name + len - 10, "_%08x", (int)sym_sec); + + args_hash_table = elf32_hppa_hash_table (info)->args_hash_table; + + args_hash = elf32_hppa_args_hash_lookup (args_hash_table, + new_name, false, false); + if (args_hash == NULL) + callee_args = 0; + else + callee_args = args_hash->arg_bits; + + /* If this is a CALL relocation, then get the caller's bits + from the addend. Else use the magic 0x155 value for PLABELS. + + Also we don't care about the destination (value) for PLABELS. */ + if (r_type == R_PARISC_PCREL17F) + caller_args = HPPA_R_ARG_RELOC (addend); + else + { + caller_args = 0x155; + location = value; + } + + /* Any kind of linker stub needed? */ + if (((int)(value - location) > 0x3ffff) + || ((int)(value - location) < (int)0xfffc0000) + || elf32_hppa_arg_reloc_needed (caller_args, callee_args, + arg_reloc_types)) + { + struct elf32_hppa_stub_hash_table *stub_hash_table; + struct elf32_hppa_stub_hash_entry *stub_hash; + asection *stub_section; + + /* Build a name for the stub. */ + + len = strlen (new_name); + len += 23; + stub_name = bfd_malloc (len); + if (!stub_name) + return bfd_reloc_notsupported; + elf32_hppa_name_of_stub (caller_args, callee_args, + location, value, stub_name); + strcat (stub_name, new_name); + free (new_name); + + stub_hash_table = elf32_hppa_hash_table (info)->stub_hash_table; + + stub_hash + = elf32_hppa_stub_hash_lookup (stub_hash_table, stub_name, + false, false); + + /* We're done with that name. */ + free (stub_name); + + /* The stub BFD only has one section. */ + stub_section = stub_hash_table->stub_bfd->sections; + + if (stub_hash != NULL) + { + + if (r_type == R_PARISC_PCREL17F) + { + unsigned long delay_insn; + unsigned int opcode, rtn_reg, ldo_target_reg, ldo_src_reg; + + /* We'll need to peek at the next insn. */ + delay_insn = bfd_get_32 (input_bfd, hit_data + 4); + opcode = get_opcode (delay_insn); + + /* We also need to know the return register for this + call. */ + rtn_reg = (insn & 0x03e00000) >> 21; + + ldo_src_reg = (delay_insn & 0x03e00000) >> 21; + ldo_target_reg = (delay_insn & 0x001f0000) >> 16; + + /* Munge up the value and other parameters for + hppa_elf_relocate_insn. */ + + value = (stub_hash->offset + + stub_section->output_offset + + stub_section->output_section->vma); + + r_format = 17; + r_field = e_fsel; + r_pcrel = 0; + addend = 0; + + /* We need to peek at the delay insn and determine if + we'll need to swap the branch and its delay insn. */ + if ((insn & 2) + || (opcode == LDO + && ldo_target_reg == rtn_reg) + || (delay_insn == 0x08000240)) + { + /* No need to swap the branch and its delay slot, but + we do need to make sure to jump past the return + pointer update in the stub. */ + value += 4; + + /* If the delay insn does a return pointer adjustment, + then we have to make sure it stays valid. */ + if (opcode == LDO + && ldo_target_reg == rtn_reg) + { + delay_insn &= 0xfc00ffff; + delay_insn |= ((31 << 21) | (31 << 16)); + bfd_put_32 (input_bfd, delay_insn, hit_data + 4); + } + /* Use a BLE to reach the stub. */ + insn = BLE_SR4_R0; + } + else + { + /* Wonderful, we have to swap the call insn and its + delay slot. */ + bfd_put_32 (input_bfd, delay_insn, hit_data); + /* Use a BLE,n to reach the stub. */ + insn = (BLE_SR4_R0 | 0x2); + bfd_put_32 (input_bfd, insn, hit_data + 4); + insn = hppa_elf_relocate_insn (input_bfd, + input_section, + insn, offset + 4, + value, addend, + r_format, r_field, + r_pcrel); + /* Update the instruction word. */ + bfd_put_32 (input_bfd, insn, hit_data + 4); + return bfd_reloc_dangerous; + } + } + else + { + /* PLABEL stuff is easy. */ + + value = (stub_hash->offset + + stub_section->output_offset + + stub_section->output_section->vma); + /* We don't need the RP adjustment for PLABELs. */ + value += 4; + if (r_type == R_PARISC_PLABEL32) + r_format = 32; + else if (r_type == R_PARISC_PLABEL21L) + r_format = 21; + else if (r_type == R_PARISC_PLABEL14R) + r_format = 14; + + r_pcrel = 0; + addend = 0; + } + } + else + return bfd_reloc_notsupported; + } + goto do_basic_type_1; + } + +do_basic_type_1: + insn = hppa_elf_relocate_insn (input_bfd, input_section, insn, + offset, value, addend, r_format, + r_field, r_pcrel); + break; + + /* Something we don't know how to handle. */ + default: + return bfd_reloc_notsupported; + } + + /* Update the instruction word. */ + bfd_put_32 (input_bfd, insn, hit_data); + return (bfd_reloc_ok); +} + +/* Return the address of the howto table entry to perform the CODE + relocation for an ARCH machine. */ + +static reloc_howto_type * +elf_hppa_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + if ((int) code < (int) R_PARISC_UNIMPLEMENTED) + { + BFD_ASSERT ((int) elf_hppa_howto_table[(int) code].type == (int) code); + return &elf_hppa_howto_table[(int) code]; + } + return NULL; +} + +/* Return true if SYM represents a local label symbol. */ + +static boolean +hppa_elf_is_local_label (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + return (sym->name[0] == 'L' && sym->name[1] == '$'); +} + +/* Do any backend specific processing when beginning to write an object + file. For PA ELF we need to determine the size of the symbol extension + section *before* any other output processing happens. */ + +static void +elf32_hppa_backend_begin_write_processing (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + unsigned int i; + asection *symextn_sec; + + /* Size up the symbol extension section. */ + if ((abfd->outsymbols == NULL + && info == NULL) + || symext_chain_size != 0) + return; + + if (info == NULL) + { + /* We were not called from the BFD ELF linker code, so we need + to examine the output BFD's outsymbols. + + Note we can not build the symbol extensions now as the symbol + map hasn't been set up. */ + for (i = 0; i < abfd->symcount; i++) + { + elf_symbol_type *symbol = (elf_symbol_type *)abfd->outsymbols[i]; + + /* Only functions ever need an entry in the symbol extension + section. */ + if (!(symbol->symbol.flags & BSF_FUNCTION)) + continue; + + /* And only if they specify the locations of their arguments. */ + if (symbol->tc_data.hppa_arg_reloc == 0) + continue; + + /* Yup. This function symbol needs an entry. */ + symext_chain_size += 2 * ELF32_PARISC_SX_SIZE; + } + } + else if (info->relocateable == true) + { + struct elf32_hppa_args_hash_table *table; + table = elf32_hppa_hash_table (info)->args_hash_table; + + /* Determine the size of the symbol extension section. */ + elf32_hppa_args_hash_traverse (table, + elf32_hppa_size_symext, + &symext_chain_size); + } + + /* Now create the section and set its size. We'll fill in the + contents later. */ + symextn_sec = bfd_get_section_by_name (abfd, SYMEXTN_SECTION_NAME); + if (symextn_sec == NULL) + symextn_sec = bfd_make_section (abfd, SYMEXTN_SECTION_NAME); + + bfd_set_section_flags (abfd, symextn_sec, + SEC_LOAD | SEC_HAS_CONTENTS | SEC_DATA); + symextn_sec->output_section = symextn_sec; + symextn_sec->output_offset = 0; + bfd_set_section_alignment (abfd, symextn_sec, 2); + bfd_set_section_size (abfd, symextn_sec, symext_chain_size); +} + +/* Called for each entry in the args location hash table. For each + entry we bump the size pointer by 2 records (16 bytes). */ + +static boolean +elf32_hppa_size_symext (gen_entry, in_args) + struct bfd_hash_entry *gen_entry; + PTR in_args; +{ + bfd_size_type *sizep = (bfd_size_type *)in_args; + + *sizep += 2 * ELF32_PARISC_SX_SIZE; + return true; +} + +/* Backend routine called by the linker for each output symbol. + + For PA ELF we use this opportunity to add an appropriate entry + to the symbol extension chain for function symbols. */ + +static boolean +elf32_hppa_link_output_symbol_hook (abfd, info, name, sym, section) + bfd *abfd; + struct bfd_link_info *info; + const char *name; + Elf_Internal_Sym *sym; + asection *section; +{ + char *new_name; + unsigned int len, index; + struct elf32_hppa_args_hash_table *args_hash_table; + struct elf32_hppa_args_hash_entry *args_hash; + + /* If the args hash table is NULL, then we've encountered an error + of some sorts (for example, an undefined symbol). In that case + we've got nothing else to do. + + NOTE: elf_link_output_symbol will abort if we return false here! */ + if (elf32_hppa_hash_table (info)->args_hash_table == NULL) + return true; + + index = elf32_hppa_hash_table (info)->output_symbol_count++; + + /* We need to look up this symbol in the args hash table to see if + it has argument relocation bits. */ + if (ELF_ST_TYPE (sym->st_info) != STT_FUNC) + return true; + + /* We know it's a function symbol of some kind. */ + len = strlen (name) + 1; + if (ELF_ST_BIND (sym->st_info) == STB_LOCAL) + len += 9; + + new_name = bfd_malloc (len); + if (new_name == NULL) + return false; + + strcpy (new_name, name); + if (ELF_ST_BIND (sym->st_info) == STB_LOCAL) + sprintf (new_name + len - 10, "_%08x", (int)section); + + /* Now that we have the unique name, we can look it up in the + args hash table. */ + args_hash_table = elf32_hppa_hash_table (info)->args_hash_table; + args_hash = elf32_hppa_args_hash_lookup (args_hash_table, new_name, + false, false); + free (new_name); + if (args_hash == NULL) + return true; + + /* We know this symbol has arg reloc bits. */ + add_entry_to_symext_chain (abfd, args_hash->arg_bits, + index, &symext_rootP, &symext_lastP); + return true; +} + +/* Perform any processing needed late in the object file writing process. + For PA ELF we build and set the contents of the symbol extension + section. */ + +static void +elf32_hppa_backend_final_write_processing (abfd, linker) + bfd *abfd; + boolean linker; +{ + asection *symextn_sec; + unsigned int i; + + /* Now build the symbol extension section. */ + if (symext_chain_size == 0) + return; + + if (! linker) + { + /* We were not called from the backend linker, so we still need + to build the symbol extension chain. + + Look at each symbol, adding the appropriate information to the + symbol extension section list as necessary. */ + for (i = 0; i < abfd->symcount; i++) + { + elf_symbol_type *symbol = (elf_symbol_type *) abfd->outsymbols[i]; + + /* Only functions ever need an entry in the symbol extension + section. */ + if (!(symbol->symbol.flags & BSF_FUNCTION)) + continue; + + /* And only if they specify the locations of their arguments. */ + if (symbol->tc_data.hppa_arg_reloc == 0) + continue; + + /* Add this symbol's information to the chain. */ + add_entry_to_symext_chain (abfd, symbol->tc_data.hppa_arg_reloc, + symbol->symbol.udata.i, &symext_rootP, + &symext_lastP); + } + } + + /* Now fill in the contents of the symbol extension section. */ + elf_hppa_tc_make_sections (abfd, symext_rootP); + + /* And attach that as the section's contents. */ + symextn_sec = bfd_get_section_by_name (abfd, SYMEXTN_SECTION_NAME); + if (symextn_sec == (asection *) 0) + abort(); + + symextn_sec->contents = (void *)symextn_contents; + + bfd_set_section_contents (abfd, symextn_sec, symextn_sec->contents, + symextn_sec->output_offset, symextn_sec->_raw_size); +} + +/* Update the symbol extention chain to include the symbol pointed to + by SYMBOLP if SYMBOLP is a function symbol. Used internally and by GAS. */ + +static void +add_entry_to_symext_chain (abfd, arg_reloc, sym_idx, symext_root, symext_last) + bfd *abfd; + unsigned int arg_reloc; + unsigned int sym_idx; + symext_chainS **symext_root; + symext_chainS **symext_last; +{ + symext_chainS *symextP; + + /* Allocate memory and initialize this entry. */ + symextP = (symext_chainS *) bfd_alloc (abfd, sizeof (symext_chainS) * 2); + if (!symextP) + abort(); /* FIXME */ + + symextP[0].entry = ELF32_PARISC_SX_WORD (PARISC_SXT_SYMNDX, sym_idx); + symextP[0].next = &symextP[1]; + + symextP[1].entry = ELF32_PARISC_SX_WORD (PARISC_SXT_ARG_RELOC, arg_reloc); + symextP[1].next = NULL; + + /* Now update the chain itself so it can be walked later to build + the symbol extension section. */ + if (*symext_root == NULL) + { + *symext_root = &symextP[0]; + *symext_last = &symextP[1]; + } + else + { + (*symext_last)->next = &symextP[0]; + *symext_last = &symextP[1]; + } +} + +/* Build the symbol extension section. */ + +static void +elf_hppa_tc_make_sections (abfd, symext_root) + bfd *abfd; + symext_chainS *symext_root; +{ + symext_chainS *symextP; + unsigned int i; + asection *symextn_sec; + + symextn_sec = bfd_get_section_by_name (abfd, SYMEXTN_SECTION_NAME); + + /* Grab some memory for the contents of the symbol extension section + itself. */ + symextn_contents = (bfd_byte *) bfd_zalloc (abfd, + symextn_sec->_raw_size); + if (!symextn_contents) + abort(); /* FIXME */ + + /* Fill in the contents of the symbol extension chain. */ + for (i = 0, symextP = symext_root; symextP; symextP = symextP->next, ++i) + ELF32_PARISC_SX_PUT (abfd, (bfd_vma) symextP->entry, + symextn_contents + i * ELF32_PARISC_SX_SIZE); + + return; +} + +/* Do some PA ELF specific work after reading in the symbol table. + In particular attach the argument relocation from the + symbol extension section to the appropriate symbols. */ + +static boolean +elf32_hppa_backend_symbol_table_processing (abfd, esyms,symcnt) + bfd *abfd; + elf_symbol_type *esyms; + unsigned int symcnt; +{ + Elf32_Internal_Shdr *symextn_hdr = + bfd_elf_find_section (abfd, SYMEXTN_SECTION_NAME); + unsigned int i, current_sym_idx = 0; + + /* If no symbol extension existed, then all symbol extension information + is assumed to be zero. */ + if (symextn_hdr == NULL) + { + for (i = 0; i < symcnt; i++) + esyms[i].tc_data.hppa_arg_reloc = 0; + return (true); + } + + /* FIXME: Why not use bfd_get_section_contents here? Also should give + memory back when we're done. */ + /* Allocate a buffer of the appropriate size for the symextn section. */ + symextn_hdr->contents = bfd_zalloc(abfd,symextn_hdr->sh_size); + if (!symextn_hdr->contents) + return false; + + /* Read in the symextn section. */ + if (bfd_seek (abfd, symextn_hdr->sh_offset, SEEK_SET) == -1) + return false; + if (bfd_read ((PTR) symextn_hdr->contents, 1, symextn_hdr->sh_size, abfd) + != symextn_hdr->sh_size) + return false; + + /* Parse entries in the symbol extension section, updating the symtab + entries as we go */ + for (i = 0; i < symextn_hdr->sh_size / ELF32_PARISC_SX_SIZE; i++) + { + symext_entryS se = + ELF32_PARISC_SX_GET (abfd, + ((unsigned char *)symextn_hdr->contents + + i * ELF32_PARISC_SX_SIZE)); + unsigned int se_value = ELF32_PARISC_SX_VAL (se); + unsigned int se_type = ELF32_PARISC_SX_TYPE (se); + + switch (se_type) + { + case PARISC_SXT_NULL: + break; + + case PARISC_SXT_SYMNDX: + if (se_value >= symcnt) + { + bfd_set_error (bfd_error_bad_value); + return (false); + } + current_sym_idx = se_value - 1; + break; + + case PARISC_SXT_ARG_RELOC: + esyms[current_sym_idx].tc_data.hppa_arg_reloc = se_value; + break; + + default: + bfd_set_error (bfd_error_bad_value); + return (false); + } + } + return (true); +} + +/* Read and attach the symbol extension information for the symbols + in INPUT_BFD to the argument location hash table. Handle locals + if DO_LOCALS is true; likewise for globals when DO_GLOBALS is true. */ + +static boolean +elf32_hppa_read_symext_info (input_bfd, symtab_hdr, args_hash_table, local_syms) + bfd *input_bfd; + Elf_Internal_Shdr *symtab_hdr; + struct elf32_hppa_args_hash_table *args_hash_table; + Elf_Internal_Sym *local_syms; +{ + asection *symextn_sec; + bfd_byte *contents; + unsigned int i, n_entries, current_index = 0; + + /* Get the symbol extension section for this BFD. If no section exists + then there's nothing to do. Likewise if the section exists, but + has no contents. */ + symextn_sec = bfd_get_section_by_name (input_bfd, SYMEXTN_SECTION_NAME); + if (symextn_sec == NULL) + return true; + + /* Done separately so we can turn off SEC_HAS_CONTENTS (see below). */ + if (symextn_sec->_raw_size == 0) + { + symextn_sec->flags &= ~SEC_HAS_CONTENTS; + return true; + } + + contents = (bfd_byte *) bfd_malloc ((size_t) symextn_sec->_raw_size); + if (contents == NULL) + return false; + + /* How gross. We turn off SEC_HAS_CONTENTS for the input symbol extension + sections to keep the generic ELF/BFD code from trying to do anything + with them. We have to undo that hack temporarily so that we can read + in the contents with the generic code. */ + symextn_sec->flags |= SEC_HAS_CONTENTS; + if (bfd_get_section_contents (input_bfd, symextn_sec, contents, + 0, symextn_sec->_raw_size) == false) + { + symextn_sec->flags &= ~SEC_HAS_CONTENTS; + free (contents); + return false; + } + + /* Gross. Turn off SEC_HAS_CONTENTS for the input symbol extension + sections (see above). */ + symextn_sec->flags &= ~SEC_HAS_CONTENTS; + + n_entries = symextn_sec->_raw_size / ELF32_PARISC_SX_SIZE; + for (i = 0; i < n_entries; i++) + { + symext_entryS entry = + ELF32_PARISC_SX_GET (input_bfd, contents + i * ELF32_PARISC_SX_SIZE); + unsigned int value = ELF32_PARISC_SX_VAL (entry); + unsigned int type = ELF32_PARISC_SX_TYPE (entry); + struct elf32_hppa_args_hash_entry *args_hash; + + switch (type) + { + case PARISC_SXT_NULL: + break; + + case PARISC_SXT_SYMNDX: + if (value >= symtab_hdr->sh_size / sizeof (Elf32_External_Sym)) + { + bfd_set_error (bfd_error_bad_value); + free (contents); + return false; + } + current_index = value; + break; + + case PARISC_SXT_ARG_RELOC: + if (current_index < symtab_hdr->sh_info) + { + Elf_Internal_Shdr *hdr; + char *new_name; + const char *sym_name; + asection *sym_sec; + unsigned int len; + + hdr = elf_elfsections (input_bfd)[local_syms[current_index].st_shndx]; + sym_sec = hdr->bfd_section; + sym_name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + local_syms[current_index].st_name); + len = strlen (sym_name) + 10; + new_name = bfd_malloc (len); + if (new_name == NULL) + { + free (contents); + return false; + } + strcpy (new_name, sym_name); + sprintf (new_name + len - 10, "_%08x", (int)sym_sec); + + /* This is a global symbol with argument location info. + We need to enter it into the hash table. */ + args_hash = elf32_hppa_args_hash_lookup (args_hash_table, + new_name, true, + true); + free (new_name); + if (args_hash == NULL) + { + free (contents); + return false; + } + args_hash->arg_bits = value; + break; + } + else if (current_index >= symtab_hdr->sh_info) + { + struct elf_link_hash_entry *h; + + current_index -= symtab_hdr->sh_info; + h = elf_sym_hashes(input_bfd)[current_index]; + /* This is a global symbol with argument location + information. We need to enter it into the hash table. */ + args_hash = elf32_hppa_args_hash_lookup (args_hash_table, + h->root.root.string, + true, true); + if (args_hash == NULL) + { + bfd_set_error (bfd_error_bad_value); + free (contents); + return false; + } + args_hash->arg_bits = value; + break; + } + else + break; + + default: + bfd_set_error (bfd_error_bad_value); + free (contents); + return false; + } + } + free (contents); + return true; +} + +/* Undo the generic ELF code's subtraction of section->vma from the + value of each external symbol. */ + +static boolean +elf32_hppa_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp; + asection **secp; + bfd_vma *valp; +{ + *valp += (*secp)->vma; + return true; +} + +/* Determine the name of the stub needed to perform a call assuming the + argument relocation bits for caller and callee are in CALLER and CALLEE + for a call from LOCATION to DESTINATION. Copy the name into STUB_NAME. */ + +static void +elf32_hppa_name_of_stub (caller, callee, location, destination, stub_name) + unsigned int caller, callee; + bfd_vma location, destination; + char *stub_name; +{ + arg_reloc_type arg_reloc_types[5]; + + if (elf32_hppa_arg_reloc_needed (caller, callee, arg_reloc_types)) + { + arg_reloc_location i; + /* Fill in the basic template. */ + strcpy (stub_name, "__XX_XX_XX_XX_XX_stub_"); + + /* Now fix the specifics. */ + for (i = ARG0; i <= RET; i++) + switch (arg_reloc_types[i]) + { + case NO: + stub_name[3 * i + 2] = 'N'; + stub_name[3 * i + 3] = 'O'; + break; + case GF: + stub_name[3 * i + 2] = 'G'; + stub_name[3 * i + 3] = 'F'; + break; + case FG: + stub_name[3 * i + 2] = 'F'; + stub_name[3 * i + 3] = 'G'; + break; + case GD: + stub_name[3 * i + 2] = 'G'; + stub_name[3 * i + 3] = 'D'; + break; + case DG: + stub_name[3 * i + 2] = 'D'; + stub_name[3 * i + 3] = 'G'; + break; + } + } + else + strcpy (stub_name, "_____long_branch_stub_"); +} + +/* Determine if an argument relocation stub is needed to perform a + call assuming the argument relocation bits for caller and callee + are in CALLER and CALLEE. Place the type of relocations (if any) + into stub_types_p. */ + +static boolean +elf32_hppa_arg_reloc_needed (caller, callee, stub_types) + unsigned int caller, callee; + arg_reloc_type stub_types[5]; +{ + /* Special case for no relocations. */ + if (caller == 0 || callee == 0) + return 0; + else + { + arg_location caller_loc[5]; + arg_location callee_loc[5]; + + /* Extract the location information for the argument and return + value on both the caller and callee sides. */ + caller_loc[ARG0] = EXTRACT_ARBITS (caller, ARG0); + callee_loc[ARG0] = EXTRACT_ARBITS (callee, ARG0); + caller_loc[ARG1] = EXTRACT_ARBITS (caller, ARG1); + callee_loc[ARG1] = EXTRACT_ARBITS (callee, ARG1); + caller_loc[ARG2] = EXTRACT_ARBITS (caller, ARG2); + callee_loc[ARG2] = EXTRACT_ARBITS (callee, ARG2); + caller_loc[ARG3] = EXTRACT_ARBITS (caller, ARG3); + callee_loc[ARG3] = EXTRACT_ARBITS (callee, ARG3); + caller_loc[RET] = EXTRACT_ARBITS (caller, RET); + callee_loc[RET] = EXTRACT_ARBITS (callee, RET); + + /* Check some special combinations. This is necessary to + deal with double precision FP arguments. */ + if (caller_loc[ARG0] == AR_FU || caller_loc[ARG1] == AR_FU) + { + caller_loc[ARG0] = AR_FPDBL1; + caller_loc[ARG1] = AR_NO; + } + if (caller_loc[ARG2] == AR_FU || caller_loc[ARG3] == AR_FU) + { + caller_loc[ARG2] = AR_FPDBL2; + caller_loc[ARG3] = AR_NO; + } + if (callee_loc[ARG0] == AR_FU || callee_loc[ARG1] == AR_FU) + { + callee_loc[ARG0] = AR_FPDBL1; + callee_loc[ARG1] = AR_NO; + } + if (callee_loc[ARG2] == AR_FU || callee_loc[ARG3] == AR_FU) + { + callee_loc[ARG2] = AR_FPDBL2; + callee_loc[ARG3] = AR_NO; + } + + /* Now look up any relocation needed for each argument and the + return value. */ + stub_types[ARG0] = arg_mismatches[caller_loc[ARG0]][callee_loc[ARG0]]; + stub_types[ARG1] = arg_mismatches[caller_loc[ARG1]][callee_loc[ARG1]]; + stub_types[ARG2] = arg_mismatches[caller_loc[ARG2]][callee_loc[ARG2]]; + stub_types[ARG3] = arg_mismatches[caller_loc[ARG3]][callee_loc[ARG3]]; + stub_types[RET] = ret_mismatches[caller_loc[RET]][callee_loc[RET]]; + + return (stub_types[ARG0] != NO + || stub_types[ARG1] != NO + || stub_types[ARG2] != NO + || stub_types[ARG3] != NO + || stub_types[RET] != NO); + } +} + +/* Compute the size of the stub needed to call from LOCATION to DESTINATION + (a function named SYM_NAME), with argument relocation bits CALLER and + CALLEE. Return zero if no stub is needed to perform such a call. */ + +static unsigned int +elf32_hppa_size_of_stub (callee, caller, location, destination, sym_name) + unsigned int callee, caller; + bfd_vma location, destination; + const char *sym_name; +{ + arg_reloc_type arg_reloc_types[5]; + + /* Determine if a long branch or argument relocation stub is needed. + If an argument relocation stub is needed, the relocation will be + stored into arg_reloc_types. */ + if (!(((int)(location - destination) > 0x3ffff) + || ((int)(location - destination) < (int)0xfffc0000) + || elf32_hppa_arg_reloc_needed (caller, callee, arg_reloc_types))) + return 0; + + /* Some kind of stub is needed. Determine how big it needs to be. + First check for argument relocation stubs as they also handle + long calls. Then check for long calls to millicode and finally + the normal long calls. */ + if (arg_reloc_types[ARG0] != NO + || arg_reloc_types[ARG1] != NO + || arg_reloc_types[ARG2] != NO + || arg_reloc_types[ARG3] != NO + || arg_reloc_types[RET] != NO) + { + /* Some kind of argument relocation stub is needed. */ + unsigned int len = 16; + arg_reloc_location i; + + /* Each GR or FG relocation takes 2 insns, each GD or DG + relocation takes 3 insns. Plus 4 more insns for the + RP adjustment, ldil & (be | ble) and copy. */ + for (i = ARG0; i <= RET; i++) + switch (arg_reloc_types[i]) + { + case GF: + case FG: + len += 8; + break; + + case GD: + case DG: + len += 12; + break; + + default: + break; + } + + /* Extra instructions are needed if we're relocating a return value. */ + if (arg_reloc_types[RET] != NO) + len += 12; + + return len; + } + else if (!strncmp ("$$", sym_name, 2) + && strcmp ("$$dyncall", sym_name)) + return 12; + else + return 16; +} + +/* Build one linker stub as defined by the stub hash table entry GEN_ENTRY. + IN_ARGS contains the stub BFD and link info pointers. */ + +static boolean +elf32_hppa_build_one_stub (gen_entry, in_args) + struct bfd_hash_entry *gen_entry; + PTR in_args; +{ + void **args = (void **)in_args; + bfd *stub_bfd = (bfd *)args[0]; + struct bfd_link_info *info = (struct bfd_link_info *)args[1]; + struct elf32_hppa_stub_hash_entry *entry; + struct elf32_hppa_stub_hash_table *stub_hash_table; + bfd_byte *loc; + symvalue sym_value; + const char *sym_name; + + /* Initialize pointers to the stub hash table, the particular entry we + are building a stub for, and where (in memory) we should place the stub + instructions. */ + entry = (struct elf32_hppa_stub_hash_entry *)gen_entry; + stub_hash_table = elf32_hppa_hash_table(info)->stub_hash_table; + loc = stub_hash_table->location; + + /* Make a note of the offset within the stubs for this entry. */ + entry->offset = stub_hash_table->offset; + + /* The symbol's name starts at offset 22. */ + sym_name = entry->root.string + 22; + + sym_value = (entry->target_value + + entry->target_section->output_offset + + entry->target_section->output_section->vma); + + if (strncmp ("_____long_branch_stub_", entry->root.string, 22)) + { + /* This must be an argument or return value relocation stub. */ + unsigned long insn; + arg_reloc_location i; + bfd_byte *begin_loc = loc; + + /* First the return pointer adjustment. Depending on exact calling + sequence this instruction may be skipped. */ + bfd_put_32 (stub_bfd, LDO_M4_R31_R31, loc); + loc += 4; + + /* If we are relocating a return value, then we're going to have + to return into the stub. So we have to save off the user's + return pointer into the stack at RP'. */ + if (strncmp (entry->root.string + 14, "NO", 2)) + { + bfd_put_32 (stub_bfd, STW_R31_M8R30, loc); + loc += 4; + } + + /* Iterate over the argument relocations, emitting instructions + to move them around as necessary. */ + for (i = ARG0; i <= ARG3; i++) + { + if (!strncmp (entry->root.string + 3 * i + 2, "GF", 2)) + { + bfd_put_32 (stub_bfd, STW_ARG_M16R30 | ((26 - i) << 16), loc); + bfd_put_32 (stub_bfd, FLDW_M16R30_FARG | (4 + i), loc + 4); + loc += 8; + } + else if (!strncmp (entry->root.string + 3 * i + 2, "FG", 2)) + { + bfd_put_32 (stub_bfd, FSTW_FARG_M16R30 | (4 + i), loc); + bfd_put_32 (stub_bfd, LDW_M16R30_ARG | ((26 - i) << 16), loc + 4); + loc += 8; + } + else if (!strncmp (entry->root.string + 3 * i + 2, "GD", 2)) + { + bfd_put_32 (stub_bfd, STW_ARG_M12R30 | ((26 - i) << 16), loc); + bfd_put_32 (stub_bfd, STW_ARG_M16R30 | ((25 - i) << 16), loc + 4); + bfd_put_32 (stub_bfd, FLDD_M16R30_FARG | (5 + i), loc + 8); + loc += 12; + } + else if (!strncmp (entry->root.string + 3 * i + 2, "DG", 2)) + { + bfd_put_32 (stub_bfd, FSTD_FARG_M16R30 | (5 + i), loc); + bfd_put_32 (stub_bfd, LDW_M12R30_ARG | ((26 - i) << 16), loc + 4); + bfd_put_32 (stub_bfd, LDW_M16R30_ARG | ((25 - i) << 16), loc + 8); + loc += 12; + } + } + + /* Load the high bits of the target address into %r1. */ + insn = hppa_rebuild_insn (stub_bfd, LDIL_R1, + hppa_field_adjust (sym_value, 0, e_lrsel), 21); + bfd_put_32 (stub_bfd, insn, loc); + loc += 4; + + /* If we are relocating a return value, then we're going to have + to return into the stub, then perform the return value relocation. */ + if (strncmp (entry->root.string + 14, "NO", 2)) + { + /* To return to the stub we "ble" to the target and copy the return + pointer from %r31 into %r2. */ + insn = hppa_rebuild_insn (stub_bfd, + BLE_SR4_R1, + hppa_field_adjust (sym_value, 0, + e_rrsel) >> 2, + 17); + bfd_put_32 (stub_bfd, insn, loc); + bfd_put_32 (stub_bfd, COPY_R31_R2, loc + 4); + + /* Reload the return pointer for our caller from the stack. */ + bfd_put_32 (stub_bfd, LDW_M8R30_R31, loc + 8); + loc += 12; + + /* Perform the return value relocation. */ + if (!strncmp (entry->root.string + 14, "GF", 2)) + { + bfd_put_32 (stub_bfd, STW_ARG_M16R30 | (28 << 16), loc); + bfd_put_32 (stub_bfd, FLDW_M16R30_FARG | 4, loc + 4); + loc += 8; + } + else if (!strncmp (entry->root.string + 14, "FG", 2)) + { + bfd_put_32 (stub_bfd, FSTW_FARG_M16R30 | 4, loc); + bfd_put_32 (stub_bfd, LDW_M16R30_ARG | (28 << 16), loc + 4); + loc += 8; + } + else if (!strncmp (entry->root.string + 2, "GD", 2)) + { + bfd_put_32 (stub_bfd, STW_ARG_M12R30 | (28 << 16), loc); + bfd_put_32 (stub_bfd, STW_ARG_M16R30 | (29 << 16), loc + 4); + bfd_put_32 (stub_bfd, FLDD_M16R30_FARG | 4, loc + 8); + loc += 12; + } + else if (!strncmp (entry->root.string + 2, "DG", 2)) + { + bfd_put_32 (stub_bfd, FSTD_FARG_M16R30 | 4, loc); + bfd_put_32 (stub_bfd, LDW_M12R30_ARG | (28 << 16), loc + 4); + bfd_put_32 (stub_bfd, LDW_M16R30_ARG | (29 << 16), loc + 8); + loc += 12; + } + /* Branch back to the user's code now. */ + bfd_put_32 (stub_bfd, BV_N_0_R31, loc); + loc += 4; + } + else + { + /* No return value relocation, so we can simply "be" to the + target and copy out return pointer into %r2. */ + insn = hppa_rebuild_insn (stub_bfd, BE_SR4_R1, + hppa_field_adjust (sym_value, 0, + e_rrsel) >> 2, 17); + bfd_put_32 (stub_bfd, insn, loc); + bfd_put_32 (stub_bfd, COPY_R31_R2, loc + 4); + loc += 8; + } + + /* Update the location and offsets. */ + stub_hash_table->location += (loc - begin_loc); + stub_hash_table->offset += (loc - begin_loc); + } + else + { + /* Create one of two variant long branch stubs. One for $$dyncall and + normal calls, the other for calls to millicode. */ + unsigned long insn; + int millicode_call = 0; + + if (!strncmp ("$$", sym_name, 2) && strcmp ("$$dyncall", sym_name)) + millicode_call = 1; + + /* First the return pointer adjustment. Depending on exact calling + sequence this instruction may be skipped. */ + bfd_put_32 (stub_bfd, LDO_M4_R31_R31, loc); + + /* The next two instructions are the long branch itself. A long branch + is formed with "ldil" loading the upper bits of the target address + into a register, then branching with "be" which adds in the lower bits. + Long branches to millicode nullify the delay slot of the "be". */ + insn = hppa_rebuild_insn (stub_bfd, LDIL_R1, + hppa_field_adjust (sym_value, 0, e_lrsel), 21); + bfd_put_32 (stub_bfd, insn, loc + 4); + insn = hppa_rebuild_insn (stub_bfd, BE_SR4_R1 | (millicode_call ? 2 : 0), + hppa_field_adjust (sym_value, 0, e_rrsel) >> 2, + 17); + bfd_put_32 (stub_bfd, insn, loc + 8); + + if (!millicode_call) + { + /* The sequence to call this stub places the return pointer into %r31, + the final target expects the return pointer in %r2, so copy the + return pointer into the proper register. */ + bfd_put_32 (stub_bfd, COPY_R31_R2, loc + 12); + + /* Update the location and offsets. */ + stub_hash_table->location += 16; + stub_hash_table->offset += 16; + } + else + { + /* Update the location and offsets. */ + stub_hash_table->location += 12; + stub_hash_table->offset += 12; + } + + } + return true; +} + +/* External entry points for sizing and building linker stubs. */ + +/* Build all the stubs associated with the current output file. The + stubs are kept in a hash table attached to the main linker hash + table. This is called via hppaelf_finish in the linker. */ + +boolean +elf32_hppa_build_stubs (stub_bfd, info) + bfd *stub_bfd; + struct bfd_link_info *info; +{ + /* The stub BFD only has one section. */ + asection *stub_sec = stub_bfd->sections; + struct elf32_hppa_stub_hash_table *table; + unsigned int size; + void *args[2]; + + /* So we can pass both the BFD for the stubs and the link info + structure to the routine which actually builds stubs. */ + args[0] = stub_bfd; + args[1] = info; + + /* Allocate memory to hold the linker stubs. */ + size = bfd_section_size (stub_bfd, stub_sec); + stub_sec->contents = (unsigned char *) bfd_zalloc (stub_bfd, size); + if (stub_sec->contents == NULL) + return false; + table = elf32_hppa_hash_table(info)->stub_hash_table; + table->location = stub_sec->contents; + + /* Build the stubs as directed by the stub hash table. */ + elf32_hppa_stub_hash_traverse (table, elf32_hppa_build_one_stub, args); + + return true; +} + +/* Determine and set the size of the stub section for a final link. + + The basic idea here is to examine all the relocations looking for + PC-relative calls to a target that is unreachable with a "bl" + instruction or calls where the caller and callee disagree on the + location of their arguments or return value. */ + +boolean +elf32_hppa_size_stubs (stub_bfd, output_bfd, link_info) + bfd *stub_bfd; + bfd *output_bfd; + struct bfd_link_info *link_info; +{ + bfd *input_bfd; + asection *section, *stub_sec = 0; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *local_syms, *isym, **all_local_syms; + Elf32_External_Sym *ext_syms, *esym; + unsigned int i, index, bfd_count = 0; + struct elf32_hppa_stub_hash_table *stub_hash_table = 0; + struct elf32_hppa_args_hash_table *args_hash_table = 0; + + /* Create and initialize the stub hash table. */ + stub_hash_table = ((struct elf32_hppa_stub_hash_table *) + bfd_malloc (sizeof (struct elf32_hppa_stub_hash_table))); + if (!stub_hash_table) + goto error_return; + + if (!elf32_hppa_stub_hash_table_init (stub_hash_table, stub_bfd, + elf32_hppa_stub_hash_newfunc)) + goto error_return; + + /* Likewise for the argument location hash table. */ + args_hash_table = ((struct elf32_hppa_args_hash_table *) + bfd_malloc (sizeof (struct elf32_hppa_args_hash_table))); + if (!args_hash_table) + goto error_return; + + if (!elf32_hppa_args_hash_table_init (args_hash_table, + elf32_hppa_args_hash_newfunc)) + goto error_return; + + /* Attach the hash tables to the main hash table. */ + elf32_hppa_hash_table(link_info)->stub_hash_table = stub_hash_table; + elf32_hppa_hash_table(link_info)->args_hash_table = args_hash_table; + + /* Count the number of input BFDs. */ + for (input_bfd = link_info->input_bfds; + input_bfd != NULL; + input_bfd = input_bfd->link_next) + bfd_count++; + + /* We want to read in symbol extension records only once. To do this + we need to read in the local symbols in parallel and save them for + later use; so hold pointers to the local symbols in an array. */ + all_local_syms + = (Elf_Internal_Sym **) bfd_malloc (sizeof (Elf_Internal_Sym *) + * bfd_count); + if (all_local_syms == NULL) + goto error_return; + memset (all_local_syms, 0, sizeof (Elf_Internal_Sym *) * bfd_count); + + /* Walk over all the input BFDs adding entries to the args hash table + for all the external functions. */ + for (input_bfd = link_info->input_bfds, index = 0; + input_bfd != NULL; + input_bfd = input_bfd->link_next, index++) + { + /* We'll need the symbol table in a second. */ + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (symtab_hdr->sh_info == 0) + continue; + + /* We need an array of the local symbols attached to the input bfd. + Unfortunately, we're going to have to read & swap them in. */ + local_syms + = (Elf_Internal_Sym *) bfd_malloc (symtab_hdr->sh_info + * sizeof (Elf_Internal_Sym)); + if (local_syms == NULL) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + all_local_syms[index] = local_syms; + + ext_syms + = (Elf32_External_Sym *) bfd_malloc (symtab_hdr->sh_info + * sizeof (Elf32_External_Sym)); + if (ext_syms == NULL) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 + || bfd_read (ext_syms, 1, + (symtab_hdr->sh_info + * sizeof (Elf32_External_Sym)), input_bfd) + != (symtab_hdr->sh_info * sizeof (Elf32_External_Sym))) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + free (ext_syms); + goto error_return; + } + + /* Swap the local symbols in. */ + isym = local_syms; + esym = ext_syms; + for (i = 0; i < symtab_hdr->sh_info; i++, esym++, isym++) + bfd_elf32_swap_symbol_in (input_bfd, esym, isym); + + /* Now we can free the external symbols. */ + free (ext_syms); + + if (elf32_hppa_read_symext_info (input_bfd, symtab_hdr, args_hash_table, + local_syms) == false) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + } + + /* Magic as we know the stub bfd only has one section. */ + stub_sec = stub_bfd->sections; + + /* If generating a relocateable output file, then we don't + have to examine the relocs. */ + if (link_info->relocateable) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + return true; + } + + /* Now that we have argument location information for all the global + functions we can start looking for stubs. */ + for (input_bfd = link_info->input_bfds, index = 0; + input_bfd != NULL; + input_bfd = input_bfd->link_next, index++) + { + /* We'll need the symbol table in a second. */ + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (symtab_hdr->sh_info == 0) + continue; + + local_syms = all_local_syms[index]; + + /* Walk over each section attached to the input bfd. */ + for (section = input_bfd->sections; + section != NULL; + section = section->next) + { + Elf_Internal_Shdr *input_rel_hdr; + Elf32_External_Rela *external_relocs, *erelaend, *erela; + Elf_Internal_Rela *internal_relocs, *irelaend, *irela; + + /* If there aren't any relocs, then there's nothing to do. */ + if ((section->flags & SEC_RELOC) == 0 + || section->reloc_count == 0) + continue; + + /* Allocate space for the external relocations. */ + external_relocs + = ((Elf32_External_Rela *) + bfd_malloc (section->reloc_count + * sizeof (Elf32_External_Rela))); + if (external_relocs == NULL) + { + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + /* Likewise for the internal relocations. */ + internal_relocs + = ((Elf_Internal_Rela *) + bfd_malloc (section->reloc_count * sizeof (Elf_Internal_Rela))); + if (internal_relocs == NULL) + { + free (external_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + /* Read in the external relocs. */ + input_rel_hdr = &elf_section_data (section)->rel_hdr; + if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0 + || bfd_read (external_relocs, 1, input_rel_hdr->sh_size, + input_bfd) != input_rel_hdr->sh_size) + { + free (external_relocs); + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + /* Swap in the relocs. */ + erela = external_relocs; + erelaend = erela + section->reloc_count; + irela = internal_relocs; + for (; erela < erelaend; erela++, irela++) + bfd_elf32_swap_reloca_in (input_bfd, erela, irela); + + /* We're done with the external relocs, free them. */ + free (external_relocs); + + /* Now examine each relocation. */ + irela = internal_relocs; + irelaend = irela + section->reloc_count; + for (; irela < irelaend; irela++) + { + long r_type, callee_args, caller_args, size_of_stub; + unsigned long r_index; + struct elf_link_hash_entry *hash; + struct elf32_hppa_stub_hash_entry *stub_hash; + struct elf32_hppa_args_hash_entry *args_hash; + Elf_Internal_Sym *sym; + asection *sym_sec; + const char *sym_name; + symvalue sym_value; + bfd_vma location, destination; + char *new_name = NULL; + + r_type = ELF32_R_TYPE (irela->r_info); + r_index = ELF32_R_SYM (irela->r_info); + + if (r_type < 0 || r_type >= (int) R_PARISC_UNIMPLEMENTED) + { + bfd_set_error (bfd_error_bad_value); + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + /* Only look for stubs on call instructions or plabel + references. */ + if (r_type != R_PARISC_PCREL17F + && r_type != R_PARISC_PLABEL32 + && r_type != R_PARISC_PLABEL21L + && r_type != R_PARISC_PLABEL14R) + continue; + + /* Now determine the call target, its name, value, section + and argument relocation bits. */ + hash = NULL; + sym = NULL; + sym_sec = NULL; + if (r_index < symtab_hdr->sh_info) + { + /* It's a local symbol. */ + Elf_Internal_Shdr *hdr; + + sym = local_syms + r_index; + hdr = elf_elfsections (input_bfd)[sym->st_shndx]; + sym_sec = hdr->bfd_section; + sym_name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + sym_value = (ELF_ST_TYPE (sym->st_info) == STT_SECTION + ? 0 : sym->st_value); + destination = (sym_value + + sym_sec->output_offset + + sym_sec->output_section->vma); + + /* Tack on an ID so we can uniquely identify this local + symbol in the stub or arg info hash tables. */ + new_name = bfd_malloc (strlen (sym_name) + 10); + if (new_name == 0) + { + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + sprintf (new_name, "%s_%08x", sym_name, (int)sym_sec); + sym_name = new_name; + } + else + { + /* It's an external symbol. */ + long index; + + index = r_index - symtab_hdr->sh_info; + hash = elf_sym_hashes (input_bfd)[index]; + if (hash->root.type == bfd_link_hash_defined + || hash->root.type == bfd_link_hash_defweak) + { + sym_sec = hash->root.u.def.section; + sym_name = hash->root.root.string; + sym_value = hash->root.u.def.value; + destination = (sym_value + + sym_sec->output_offset + + sym_sec->output_section->vma); + } + else + { + bfd_set_error (bfd_error_bad_value); + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + } + + args_hash = elf32_hppa_args_hash_lookup (args_hash_table, + sym_name, false, false); + + /* Get both caller and callee argument information. */ + if (args_hash == NULL) + callee_args = 0; + else + callee_args = args_hash->arg_bits; + + /* For calls get the caller's bits from the addend of + the call relocation. For PLABELS the caller's bits + are assumed to have all args & return values in general + registers (0x155). */ + if (r_type == R_PARISC_PCREL17F) + caller_args = HPPA_R_ARG_RELOC (irela->r_addend); + else + caller_args = 0x155; + + /* Now determine where the call point is. */ + location = (section->output_offset + + section->output_section->vma + + irela->r_offset); + + /* We only care about the destination for PCREL function + calls (eg. we don't care for PLABELS). */ + if (r_type != R_PARISC_PCREL17F) + location = destination; + + /* Determine what (if any) linker stub is needed and its + size (in bytes). */ + size_of_stub = elf32_hppa_size_of_stub (callee_args, + caller_args, + location, + destination, + sym_name); + if (size_of_stub != 0) + { + char *stub_name; + unsigned int len; + + /* Get the name of this stub. */ + len = strlen (sym_name); + len += 23; + + stub_name = bfd_malloc (len); + if (!stub_name) + { + /* Because sym_name was mallocd above for local + symbols. */ + if (r_index < symtab_hdr->sh_info) + free (new_name); + + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + elf32_hppa_name_of_stub (caller_args, callee_args, + location, destination, stub_name); + strcat (stub_name + 22, sym_name); + + /* Because sym_name was malloced above for local symbols. */ + if (r_index < symtab_hdr->sh_info) + free (new_name); + + stub_hash + = elf32_hppa_stub_hash_lookup (stub_hash_table, stub_name, + false, false); + if (stub_hash != NULL) + { + /* The proper stub has already been created, nothing + else to do. */ + free (stub_name); + } + else + { + bfd_set_section_size (stub_bfd, stub_sec, + (bfd_section_size (stub_bfd, + stub_sec) + + size_of_stub)); + + /* Enter this entry into the linker stub hash table. */ + stub_hash + = elf32_hppa_stub_hash_lookup (stub_hash_table, + stub_name, true, true); + if (stub_hash == NULL) + { + free (stub_name); + free (internal_relocs); + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + goto error_return; + } + + /* We'll need these to determine the address that the + stub will branch to. */ + stub_hash->target_value = sym_value; + stub_hash->target_section = sym_sec; + } + free (stub_name); + } + } + /* We're done with the internal relocs, free them. */ + free (internal_relocs); + } + } + /* We're done with the local symbols, free them. */ + for (i = 0; i < bfd_count; i++) + if (all_local_syms[i]) + free (all_local_syms[i]); + free (all_local_syms); + return true; + +error_return: + /* Return gracefully, avoiding dangling references to the hash tables. */ + if (stub_hash_table) + { + elf32_hppa_hash_table(link_info)->stub_hash_table = NULL; + free (stub_hash_table); + } + if (args_hash_table) + { + elf32_hppa_hash_table(link_info)->args_hash_table = NULL; + free (args_hash_table); + } + /* Set the size of the stub section to zero since we're never going + to create them. Avoids losing when we try to get its contents + too. */ + bfd_set_section_size (stub_bfd, stub_sec, 0); + return false; +} + +/* Misc BFD support code. */ +#define bfd_elf32_bfd_reloc_type_lookup elf_hppa_reloc_type_lookup +#define bfd_elf32_bfd_is_local_label hppa_elf_is_local_label + +/* Symbol extension stuff. */ +#define bfd_elf32_set_section_contents elf32_hppa_set_section_contents +#define elf_backend_symbol_table_processing \ + elf32_hppa_backend_symbol_table_processing +#define elf_backend_begin_write_processing \ + elf32_hppa_backend_begin_write_processing +#define elf_backend_final_write_processing \ + elf32_hppa_backend_final_write_processing + +/* Stuff for the BFD linker. */ +#define elf_backend_relocate_section elf32_hppa_relocate_section +#define elf_backend_add_symbol_hook elf32_hppa_add_symbol_hook +#define elf_backend_link_output_symbol_hook \ + elf32_hppa_link_output_symbol_hook +#define bfd_elf32_bfd_link_hash_table_create \ + elf32_hppa_link_hash_table_create + +#define TARGET_BIG_SYM bfd_elf32_hppa_vec +#define TARGET_BIG_NAME "elf32-hppa" +#define ELF_ARCH bfd_arch_hppa +#define ELF_MACHINE_CODE EM_PARISC +#define ELF_MAXPAGESIZE 0x1000 + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-hppa.h b/contrib/gdb/bfd/elf32-hppa.h new file mode 100644 index 000000000000..63ee52200e0d --- /dev/null +++ b/contrib/gdb/bfd/elf32-hppa.h @@ -0,0 +1,152 @@ +/* ELF32/HPPA support + + This file contains ELF32/HPPA relocation support as specified + in the Stratus FTX/Golf Object File Format (SED-1762) dated + February 1994. + + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + + Written by: + + Center for Software Science + Department of Computer Science + University of Utah + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF32_HPPA_H +#define _ELF32_HPPA_H + +#include "elf-bfd.h" +#include "libhppa.h" +#include "elf/hppa.h" + +/* ELF/HPPA relocation types */ + +typedef enum + { + /* Address relocation types + These relocation types do simple base + offset relocations. */ + + R_PARISC_NONE = 0x00, + R_PARISC_DIR32 = 0x01, + R_PARISC_DIR21L = 0x02, + R_PARISC_DIR17R = 0x03, + R_PARISC_DIR17F = 0x04, + R_PARISC_DIR14R = 0x06, + + /* PC-relative relocation types + Typically used for calls. + Note PCREL17C and PCREL17F differ only in overflow handling. + PCREL17C never reports a relocation error. + + When supporting argument relocations, function calls must be + accompanied by parameter relocation information. This information is + carried in the ten high-order bits of the addend field. The remaining + 22 bits of of the addend field are sign-extended to form the Addend. + + Note the code to build argument relocations depends on the + addend being zero. A consequence of this limitation is GAS + can not perform relocation reductions for function symbols. */ + R_PARISC_PCREL21L = 0x0a, + R_PARISC_PCREL17R = 0x0b, + R_PARISC_PCREL17F = 0x0c, + R_PARISC_PCREL17C = 0x0d, + R_PARISC_PCREL14R = 0x0e, + R_PARISC_PCREL14F = 0x0f, + + /* DP-relative relocation types. */ + R_PARISC_DPREL21L = 0x12, + R_PARISC_DPREL14R = 0x16, + R_PARISC_DPREL14F = 0x17, + + /* Data linkage table (DLT) relocation types + + SOM DLT_REL fixup requests are used to for static data references + from position-independent code within shared libraries. They are + similar to the GOT relocation types in some SVR4 implementations. */ + + R_PARISC_DLTREL21L = 0x1a, + R_PARISC_DLTREL14R = 0x1e, + R_PARISC_DLTREL14F = 0x1f, + + /* DLT indirect relocation types */ + R_PARISC_DLTIND21L = 0x22, + R_PARISC_DLTIND14R = 0x26, + R_PARISC_DLTIND14F = 0x27, + + /* Base relative relocation types. Ugh. These imply lots of state */ + R_PARISC_SETBASE = 0x28, + R_PARISC_BASEREL32 = 0x29, + R_PARISC_BASEREL21L = 0x2a, + R_PARISC_BASEREL17R = 0x2b, + R_PARISC_BASEREL17F = 0x2c, + R_PARISC_BASEREL14R = 0x2e, + R_PARISC_BASEREL14F = 0x2f, + + /* Segment relative relocation types. */ + R_PARISC_TEXTREL32 = 0x31, + R_PARISC_DATAREL32 = 0x39, + + /* Plabel relocation types. */ + R_PARISC_PLABEL32 = 0x41, + R_PARISC_PLABEL21L = 0x42, + R_PARISC_PLABEL14R = 0x46, + + /* PLT relocations. */ + R_PARISC_PLTIND21L = 0x82, + R_PARISC_PLTIND14R = 0x86, + R_PARISC_PLTIND14F = 0x87, + + /* Misc relocation types. */ + R_PARISC_COPY = 0x88, + R_PARISC_GLOB_DAT = 0x89, + R_PARISC_JMP_SLOT = 0x8a, + R_PARISC_RELATIVE = 0x8b, + R_PARISC_UNIMPLEMENTED, + } +elf32_hppa_reloc_type; + +#define ELF_HOWTO_TABLE_SIZE R_PARISC_UNIMPLEMENTED + 1 +#define N_PARISC_RELOCS R_PARISC_UNIMPLEMENTED + 1 + +/* Define groups of basic relocations. FIXME: These should + be the only basic relocations created by GAS. The rest + should be internal to the BFD backend. + + The idea is both SOM and ELF define these basic relocation + types so they map into a SOM or ELF specific relocation + as appropriate. This allows GAS to share much more code + between the two target object formats. */ + +#define R_HPPA_NONE R_PARISC_NONE +#define R_HPPA R_PARISC_DIR32 +#define R_HPPA_GOTOFF R_PARISC_DPREL21L +#define R_HPPA_PCREL_CALL R_PARISC_PCREL21L +#define R_HPPA_ABS_CALL R_PARISC_DIR17F +#define R_HPPA_COMPLEX R_PARISC_UNIMPLEMENTED + +elf32_hppa_reloc_type **hppa_elf_gen_reloc_type + PARAMS ((bfd *, elf32_hppa_reloc_type, int, int, int)); + +boolean elf32_hppa_size_stubs + PARAMS ((bfd *, bfd *, struct bfd_link_info *)); + +boolean elf32_hppa_build_stubs + PARAMS ((bfd *, struct bfd_link_info *)); + +#endif /* _ELF32_HPPA_H */ diff --git a/contrib/gdb/bfd/elf32-i386.c b/contrib/gdb/bfd/elf32-i386.c new file mode 100644 index 000000000000..3b39aac91913 --- /dev/null +++ b/contrib/gdb/bfd/elf32-i386.c @@ -0,0 +1,1546 @@ +/* Intel 80386/80486-specific support for 32-bit ELF + Copyright 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +static reloc_howto_type *elf_i386_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf_i386_info_to_howto + PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); +static void elf_i386_info_to_howto_rel + PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); +static boolean elf_i386_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static boolean elf_i386_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf_i386_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_i386_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean elf_i386_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean elf_i386_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +#define USE_REL 1 /* 386 uses REL relocations instead of RELA */ + +enum reloc_type + { + R_386_NONE = 0, + R_386_32, + R_386_PC32, + R_386_GOT32, + R_386_PLT32, + R_386_COPY, + R_386_GLOB_DAT, + R_386_JUMP_SLOT, + R_386_RELATIVE, + R_386_GOTOFF, + R_386_GOTPC, + R_386_max + }; + +#if 0 +static CONST char *CONST reloc_type_names[] = +{ + "R_386_NONE", + "R_386_32", + "R_386_PC32", + "R_386_GOT32", + "R_386_PLT32", + "R_386_COPY", + "R_386_GLOB_DAT", + "R_386_JUMP_SLOT", + "R_386_RELATIVE", + "R_386_GOTOFF", + "R_386_GOTPC", +}; +#endif + +static reloc_howto_type elf_howto_table[]= +{ + HOWTO(R_386_NONE, 0,0, 0,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_NONE", true,0x00000000,0x00000000,false), + HOWTO(R_386_32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_32", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_PC32, 0,2,32,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC32", true,0xffffffff,0xffffffff,true), + HOWTO(R_386_GOT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOT32", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_PLT32, 0,2,32,true,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PLT32", true,0xffffffff,0xffffffff,true), + HOWTO(R_386_COPY, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_COPY", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GLOB_DAT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GLOB_DAT", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_JUMP_SLOT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_JUMP_SLOT",true,0xffffffff,0xffffffff,false), + HOWTO(R_386_RELATIVE, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_RELATIVE", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GOTOFF, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTOFF", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GOTPC, 0,2,32,true,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTPC", true,0xffffffff,0xffffffff,true), +}; + +#ifdef DEBUG_GEN_RELOC +#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) +#else +#define TRACE(str) +#endif + +static reloc_howto_type * +elf_i386_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_NONE: + TRACE ("BFD_RELOC_NONE"); + return &elf_howto_table[ (int)R_386_NONE ]; + + case BFD_RELOC_32: + TRACE ("BFD_RELOC_32"); + return &elf_howto_table[ (int)R_386_32 ]; + + case BFD_RELOC_32_PCREL: + TRACE ("BFD_RELOC_PC32"); + return &elf_howto_table[ (int)R_386_PC32 ]; + + case BFD_RELOC_386_GOT32: + TRACE ("BFD_RELOC_386_GOT32"); + return &elf_howto_table[ (int)R_386_GOT32 ]; + + case BFD_RELOC_386_PLT32: + TRACE ("BFD_RELOC_386_PLT32"); + return &elf_howto_table[ (int)R_386_PLT32 ]; + + case BFD_RELOC_386_COPY: + TRACE ("BFD_RELOC_386_COPY"); + return &elf_howto_table[ (int)R_386_COPY ]; + + case BFD_RELOC_386_GLOB_DAT: + TRACE ("BFD_RELOC_386_GLOB_DAT"); + return &elf_howto_table[ (int)R_386_GLOB_DAT ]; + + case BFD_RELOC_386_JUMP_SLOT: + TRACE ("BFD_RELOC_386_JUMP_SLOT"); + return &elf_howto_table[ (int)R_386_JUMP_SLOT ]; + + case BFD_RELOC_386_RELATIVE: + TRACE ("BFD_RELOC_386_RELATIVE"); + return &elf_howto_table[ (int)R_386_RELATIVE ]; + + case BFD_RELOC_386_GOTOFF: + TRACE ("BFD_RELOC_386_GOTOFF"); + return &elf_howto_table[ (int)R_386_GOTOFF ]; + + case BFD_RELOC_386_GOTPC: + TRACE ("BFD_RELOC_386_GOTPC"); + return &elf_howto_table[ (int)R_386_GOTPC ]; + + default: + break; + } + + TRACE ("Unknown"); + return 0; +} + +static void +elf_i386_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); + + cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +static void +elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rel *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); + + cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +/* Functions for the i386 ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 16 + +/* The first entry in an absolute procedure linkage table looks like + this. See the SVR4 ABI i386 supplement to see how this works. */ + +static const bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, /* pushl contents of address */ + 0, 0, 0, 0, /* replaced with address of .got + 4. */ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of .got + 8. */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Subsequent entries in an absolute procedure linkage table look like + this. */ + +static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* The first entry in a PIC procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Subsequent entries in a PIC procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xa3, /* jmp *offset(%ebx) */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table or procedure linkage + table. */ + +static boolean +elf_i386_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sgot; + asection *srelgot; + asection *sreloc; + + if (info->relocateable) + return true; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_offsets = elf_local_got_offsets (abfd); + + sgot = NULL; + srelgot = NULL; + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + /* Some relocs require a global offset table. */ + if (dynobj == NULL) + { + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_GOT32: + case R_386_GOTOFF: + case R_386_GOTPC: + elf_hash_table (info)->dynobj = dynobj = abfd; + if (! _bfd_elf_create_got_section (dynobj, info)) + return false; + break; + + default: + break; + } + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_GOT32: + /* This symbol requires a global offset table entry. */ + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (srelgot == NULL + && (h != NULL || info->shared)) + { + srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); + if (srelgot == NULL) + { + srelgot = bfd_make_section (dynobj, ".rel.got"); + if (srelgot == NULL + || ! bfd_set_section_flags (dynobj, srelgot, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, srelgot, 2)) + return false; + } + } + + if (h != NULL) + { + if (h->got_offset != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + h->got_offset = sgot->_raw_size; + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + else + { + /* This is a global offset table entry for a local + symbol. */ + if (local_got_offsets == NULL) + { + size_t size; + register unsigned int i; + + size = symtab_hdr->sh_info * sizeof (bfd_vma); + local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); + if (local_got_offsets == NULL) + return false; + elf_local_got_offsets (abfd) = local_got_offsets; + for (i = 0; i < symtab_hdr->sh_info; i++) + local_got_offsets[i] = (bfd_vma) -1; + } + if (local_got_offsets[r_symndx] != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + local_got_offsets[r_symndx] = sgot->_raw_size; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_386_RELATIVE reloc so that the dynamic + linker can adjust this GOT entry. */ + srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + } + + sgot->_raw_size += 4; + + break; + + case R_386_PLT32: + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code which is + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + + break; + + case R_386_32: + case R_386_PC32: + if (info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 || h != NULL)) + { + /* When creating a shared object, we must copy these + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rel", 4) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name + 4) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || ! bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, sreloc, 2)) + return false; + } + } + + sreloc->_raw_size += sizeof (Elf32_External_Rel); + } + + break; + + default: + break; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +elf_i386_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + unsigned int power_of_two; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) + || h->weakdef != NULL + || ((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC + || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0) + { + /* This case can occur if we saw a PLT32 reloc in an input + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a PC32 + reloc instead. */ + BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0); + return true; + } + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } + + h->plt_offset = s->_raw_size; + + /* Make room for this entry. */ + s->_raw_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. */ + + s = bfd_get_section_by_name (dynobj, ".got.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + + s = bfd_get_section_by_name (dynobj, ".rel.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += sizeof (Elf32_External_Rel); + + return true; + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + 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 + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + s = bfd_get_section_by_name (dynobj, ".dynbss"); + BFD_ASSERT (s != NULL); + + /* If the symbol is currently defined in the .bss section of the + dynamic object, then it is OK to simply initialize it to zero. + If the symbol is in some other section, 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. We need to remember the offset into the .rel.bss section + we are going to use. */ + if ((h->root.u.def.section->flags & SEC_LOAD) != 0) + { + asection *srel; + + srel = bfd_get_section_by_name (dynobj, ".rel.bss"); + BFD_ASSERT (srel != NULL); + srel->_raw_size += sizeof (Elf32_External_Rel); + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 3) + power_of_two = 3; + + /* Apply the required alignment. */ + s->_raw_size = BFD_ALIGN (s->_raw_size, + (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (dynobj, s)) + { + if (! bfd_set_section_alignment (dynobj, s, power_of_two)) + return false; + } + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +elf_i386_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean plt; + boolean relocs; + boolean reltext; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + else + { + /* We may have created entries in the .rel.got section. + However, if we are not creating the dynamic sections, we will + not actually use these entries. Reset the size of .rel.got, + which will cause it to get stripped from the output file + below. */ + s = bfd_get_section_by_name (dynobj, ".rel.got"); + if (s != NULL) + s->_raw_size = 0; + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + plt = false; + relocs = false; + reltext = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + if ((s->flags & SEC_IN_MEMORY) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + strip = false; + + if (strcmp (name, ".plt") == 0) + { + if (s->_raw_size == 0) + { + /* Strip this section if we don't need it; see the + comment below. */ + strip = true; + } + else + { + /* Remember whether there is a PLT. */ + plt = true; + } + } + else if (strncmp (name, ".rel", 4) == 0) + { + if (s->_raw_size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rel.bss and + .rel.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + strip = true; + } + else + { + asection *target; + + /* Remember whether there are any reloc sections other + than .rel.plt. */ + if (strcmp (name, ".rel.plt") != 0) + { + relocs = true; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL + entry. The entries in the .rel.plt section + really apply to the .got section, which we + created ourselves and so know is not readonly. */ + target = bfd_get_section_by_name (output_bfd, name + 4); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + } + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else if (strncmp (name, ".got", 4) != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_i386_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (! info->shared) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (plt) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL) + || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + if (relocs) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELENT, + sizeof (Elf32_External_Rel))) + return false; + } + + if (reltext) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + } + + return true; +} + +/* Relocate an i386 ELF section. */ + +static boolean +elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + asection *sgot; + asection *splt; + asection *sreloc; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); + + sgot = NULL; + splt = NULL; + sreloc = NULL; + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_386_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = elf_howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + bfd_vma val; + + sec = local_sections[r_symndx]; + val = bfd_get_32 (input_bfd, contents + rel->r_offset); + val += sec->output_offset + sym->st_value; + bfd_put_32 (input_bfd, val, contents + rel->r_offset); + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if (r_type == R_386_GOTPC + || (r_type == R_386_PLT32 + && h->plt_offset != (bfd_vma) -1) + || (r_type == R_386_GOT32 + && elf_hash_table (info)->dynamic_sections_created + && (! info->shared + || ! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || (info->shared + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0) + && (r_type == R_386_32 + || r_type == R_386_PC32) + && (input_section->flags & SEC_ALLOC) != 0)) + { + /* In these cases, we don't need the relocation + value. We check specially because in some + obscure cases sec->output_section will be NULL. */ + relocation = 0; + } + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared && !info->symbolic) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + switch (r_type) + { + case R_386_GOT32: + /* Relocation is to the entry for this symbol in the global + offset table. */ + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (h != NULL) + { + bfd_vma off; + + off = h->got_offset; + BFD_ASSERT (off != (bfd_vma) -1); + + if (! elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global offset table. Since the offset must + always be a multiple of 4, we use the least + significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rel.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got_offset |= 1; + } + } + + relocation = sgot->output_offset + off; + } + else + { + bfd_vma off; + + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) -1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rel outrel; + + srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, + (((Elf32_External_Rel *) + srelgot->contents) + + srelgot->reloc_count)); + ++srelgot->reloc_count; + } + + local_got_offsets[r_symndx] |= 1; + } + + relocation = sgot->output_offset + off; + } + + break; + + case R_386_GOTOFF: + /* Relocation is relative to the start of the global offset + table. */ + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + /* Note that sgot->output_offset is not involved in this + calculation. We always want the start of .got. If we + defined _GLOBAL_OFFSET_TABLE in a different way, as is + permitted by the ABI, we might have to change this + calculation. */ + relocation -= sgot->output_section->vma; + + break; + + case R_386_GOTPC: + /* Use global offset table as symbol value. */ + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + relocation = sgot->output_section->vma; + + break; + + case R_386_PLT32: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* Resolve a PLT32 reloc again a local symbol directly, + without using the procedure linkage table. */ + if (h == NULL) + break; + + if (h->plt_offset == (bfd_vma) -1) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + } + + if (splt == NULL) + { + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL); + } + + relocation = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + + break; + + case R_386_32: + case R_386_PC32: + if (info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + { + Elf_Internal_Rel outrel; + boolean relocate; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (input_bfd, + elf_elfheader (input_bfd)->e_shstrndx, + elf_section_data (input_section)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rel", 4) == 0 + && strcmp (bfd_get_section_name (input_bfd, + input_section), + name + 4) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + BFD_ASSERT (sreloc != NULL); + } + + outrel.r_offset = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + if (r_type == R_386_PC32) + { + BFD_ASSERT (h != NULL && h->dynindx != -1); + relocate = false; + outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32); + } + else + { + if (h == NULL + || (info->symbolic + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) != 0)) + { + relocate = true; + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + } + else + { + BFD_ASSERT (h->dynindx != -1); + relocate = false; + outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_32); + } + } + + bfd_elf32_swap_reloc_out (output_bfd, &outrel, + (((Elf32_External_Rel *) + sreloc->contents) + + sreloc->reloc_count)); + ++sreloc->reloc_count; + + /* 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. */ + if (! relocate) + continue; + } + + break; + + default: + break; + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, (bfd_vma) 0); + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj; + + dynobj = elf_hash_table (info)->dynobj; + + if (h->plt_offset != (bfd_vma) -1) + { + asection *splt; + asection *sgot; + asection *srel; + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rel rel; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = bfd_get_section_by_name (dynobj, ".plt"); + sgot = bfd_get_section_by_name (dynobj, ".got.plt"); + srel = bfd_get_section_by_name (dynobj, ".rel.plt"); + BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->plt_offset / PLT_ENTRY_SIZE - 1; + + /* Get the offset into the .got table of the entry that + corresponds to this function. Each .got entry is 4 bytes. + The first three are reserved. */ + got_offset = (plt_index + 3) * 4; + + /* Fill in the entry in the procedure linkage table. */ + if (! info->shared) + { + memcpy (splt->contents + h->plt_offset, elf_i386_plt_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + (sgot->output_section->vma + + sgot->output_offset + + got_offset), + splt->contents + h->plt_offset + 2); + } + else + { + memcpy (splt->contents + h->plt_offset, elf_i386_pic_plt_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, got_offset, + splt->contents + h->plt_offset + 2); + } + + bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), + splt->contents + h->plt_offset + 7); + bfd_put_32 (output_bfd, - (h->plt_offset + PLT_ENTRY_SIZE), + splt->contents + h->plt_offset + 12); + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + (splt->output_section->vma + + splt->output_offset + + h->plt_offset + + 6), + sgot->contents + got_offset); + + /* Fill in the entry in the .rel.plt section. */ + rel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + ((Elf32_External_Rel *) srel->contents + + plt_index)); + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got_offset != (bfd_vma) -1) + { + asection *sgot; + asection *srel; + Elf_Internal_Rel rel; + + /* This symbol has an entry in the global offset table. Set it + up. */ + + BFD_ASSERT (h->dynindx != -1); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + srel = bfd_get_section_by_name (dynobj, ".rel.got"); + BFD_ASSERT (sgot != NULL && srel != NULL); + + rel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + (h->got_offset &~ 1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. The entry in + the global offset table will already have been initialized in + the relocate_section function. */ + if (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + else + { + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); + } + + bfd_elf32_swap_reloc_out (output_bfd, &rel, + ((Elf32_External_Rel *) srel->contents + + srel->reloc_count)); + ++srel->reloc_count; + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + asection *s; + Elf_Internal_Rel rel; + + /* This symbol needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rel.bss"); + BFD_ASSERT (s != NULL); + + rel.r_offset = (h->root.u.def.value + + 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); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + ((Elf32_External_Rel *) s->contents + + s->reloc_count)); + ++s->reloc_count; + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +elf_i386_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sgot; + asection *sdyn; + + dynobj = elf_hash_table (info)->dynobj; + + sgot = bfd_get_section_by_name (dynobj, ".got.plt"); + BFD_ASSERT (sgot != NULL); + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_PLTGOT: + name = ".got"; + goto get_vma; + case DT_JMPREL: + name = ".rel.plt"; + get_vma: + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTRELSZ: + s = bfd_get_section_by_name (output_bfd, ".rel.plt"); + BFD_ASSERT (s != NULL); + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_RELSZ: + /* My reading of the SVR4 ABI indicates that the + procedure linkage table relocs (DT_JMPREL) should be + included in the overall relocs (DT_REL). This is + what Solaris does. However, UnixWare can not handle + that case. Therefore, we override the DT_RELSZ entry + here to make it not include the JMPREL relocs. Since + the linker script arranges for .rel.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_REL entry. */ + s = bfd_get_section_by_name (output_bfd, ".rel.plt"); + if (s != NULL) + { + if (s->_cooked_size != 0) + dyn.d_un.d_val -= s->_cooked_size; + else + dyn.d_un.d_val -= s->_raw_size; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } + } + + /* Fill in the first entry in the procedure linkage table. */ + if (splt->_raw_size > 0) + { + if (info->shared) + memcpy (splt->contents, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); + else + { + memcpy (splt->contents, elf_i386_plt0_entry, PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + sgot->output_section->vma + sgot->output_offset + 4, + splt->contents + 2); + bfd_put_32 (output_bfd, + sgot->output_section->vma + sgot->output_offset + 8, + splt->contents + 8); + } + } + + /* UnixWare sets the entsize of .plt to 4, although that doesn't + really seem like the right value. */ + elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; + } + + /* Fill in the first three entries in the global offset table. */ + if (sgot->_raw_size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); + } + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + + return true; +} + +#define TARGET_LITTLE_SYM bfd_elf32_i386_vec +#define TARGET_LITTLE_NAME "elf32-i386" +#define ELF_ARCH bfd_arch_i386 +#define ELF_MACHINE_CODE EM_386 +#define elf_info_to_howto elf_i386_info_to_howto +#define elf_info_to_howto_rel elf_i386_info_to_howto_rel +#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup +#define ELF_MAXPAGESIZE 0x1000 +#define elf_backend_create_dynamic_sections \ + _bfd_elf_create_dynamic_sections +#define elf_backend_check_relocs elf_i386_check_relocs +#define elf_backend_adjust_dynamic_symbol \ + elf_i386_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + elf_i386_size_dynamic_sections +#define elf_backend_relocate_section elf_i386_relocate_section +#define elf_backend_finish_dynamic_symbol \ + elf_i386_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + elf_i386_finish_dynamic_sections +#define elf_backend_want_got_plt 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_want_plt_sym 0 + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-i860.c b/contrib/gdb/bfd/elf32-i860.c new file mode 100644 index 000000000000..a8537a75508f --- /dev/null +++ b/contrib/gdb/bfd/elf32-i860.c @@ -0,0 +1,33 @@ +/* Intel 860 specific support for 32-bit ELF + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define elf_info_to_howto _bfd_elf_no_info_to_howto + +#define TARGET_BIG_SYM bfd_elf32_i860_vec +#define TARGET_BIG_NAME "elf32-i860" +#define ELF_ARCH bfd_arch_i860 +#define ELF_MACHINE_CODE EM_860 + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-m68k.c b/contrib/gdb/bfd/elf32-m68k.c new file mode 100644 index 000000000000..752dfaed2270 --- /dev/null +++ b/contrib/gdb/bfd/elf32-m68k.c @@ -0,0 +1,1600 @@ +/* Motorola 68k series support for 32-bit ELF + Copyright 1993, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +static reloc_howto_type *reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void rtype_to_howto + PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); +static void rtype_to_howto_rel + PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); +static boolean elf_m68k_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static boolean elf_m68k_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf_m68k_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_m68k_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean elf_m68k_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean elf_m68k_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* elf32 m68k code, generated by elf.el */ +enum reloc_type { + R_68K_NONE = 0, + R_68K_32 = 1, + R_68K_16 = 2, + R_68K_8 = 3, + R_68K_PC32 = 4, + R_68K_PC16 = 5, + R_68K_PC8 = 6, + R_68K_GOT32 = 7, + R_68K_GOT16 = 8, + R_68K_GOT8 = 9, + R_68K_GOT32O = 10, + R_68K_GOT16O = 11, + R_68K_GOT8O = 12, + R_68K_PLT32 = 13, + R_68K_PLT16 = 14, + R_68K_PLT8 = 15, + R_68K_PLT32O = 16, + R_68K_PLT16O = 17, + R_68K_PLT8O = 18, + R_68K_COPY = 19, + R_68K_GLOB_DAT = 20, + R_68K_JMP_SLOT = 21, + R_68K_RELATIVE = 22, + R_68K__max +}; + +static reloc_howto_type howto_table[] = { + HOWTO(R_68K_NONE, 0, 0, 0, false,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_NONE", false, 0, 0x00000000,false), + HOWTO(R_68K_32, 0, 2,32, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_32", false, 0, 0xffffffff,false), + HOWTO(R_68K_16, 0, 1,16, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_16", false, 0, 0x0000ffff,false), + HOWTO(R_68K_8, 0, 0, 8, false,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_8", false, 0, 0x000000ff,false), + HOWTO(R_68K_PC32, 0, 2,32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PC32", false, 0, 0xffffffff,true), + HOWTO(R_68K_PC16, 0, 1,16, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PC16", false, 0, 0x0000ffff,true), + HOWTO(R_68K_PC8, 0, 0, 8, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PC8", false, 0, 0x000000ff,true), + HOWTO(R_68K_GOT32, 0, 2,32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT32", false, 0, 0xffffffff,true), + HOWTO(R_68K_GOT16, 0, 1,16, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT16", false, 0, 0x0000ffff,true), + HOWTO(R_68K_GOT8, 0, 0, 8, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT8", false, 0, 0x000000ff,true), + HOWTO(R_68K_GOT32O, 0, 2,32, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT32O", false, 0, 0xffffffff,false), + HOWTO(R_68K_GOT16O, 0, 1,16, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT16O", false, 0, 0x0000ffff,false), + HOWTO(R_68K_GOT8O, 0, 0, 8, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT8O", false, 0, 0x000000ff,false), + HOWTO(R_68K_PLT32, 0, 2,32, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT32", false, 0, 0xffffffff,true), + HOWTO(R_68K_PLT16, 0, 1,16, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT16", false, 0, 0x0000ffff,true), + HOWTO(R_68K_PLT8, 0, 0, 8, true, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT8", false, 0, 0x000000ff,true), + HOWTO(R_68K_PLT32O, 0, 2,32, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT32O", false, 0, 0xffffffff,false), + HOWTO(R_68K_PLT16O, 0, 1,16, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT16O", false, 0, 0x0000ffff,false), + HOWTO(R_68K_PLT8O, 0, 0, 8, false,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT8O", false, 0, 0x000000ff,false), + HOWTO(R_68K_COPY, 0, 0, 0, false,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_COPY", false, 0, 0xffffffff,false), + HOWTO(R_68K_GLOB_DAT, 0, 2,32, false,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_GLOB_DAT", false, 0, 0xffffffff,false), + HOWTO(R_68K_JMP_SLOT, 0, 2,32, false,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_JMP_SLOT", false, 0, 0xffffffff,false), + HOWTO(R_68K_RELATIVE, 0, 2,32, false,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_RELATIVE", false, 0, 0xffffffff,false), +}; + +static void +rtype_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_68K__max); + cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +static void +rtype_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rel *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_68K__max); + cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +#define elf_info_to_howto rtype_to_howto +#define elf_info_to_howto_rel rtype_to_howto_rel + +static const struct { unsigned char bfd_val, elf_val; } reloc_map[] = { + { BFD_RELOC_NONE, R_68K_NONE }, + { BFD_RELOC_32, R_68K_32 }, + { BFD_RELOC_16, R_68K_16 }, + { BFD_RELOC_8, R_68K_8 }, + { BFD_RELOC_32_PCREL, R_68K_PC32 }, + { BFD_RELOC_16_PCREL, R_68K_PC16 }, + { BFD_RELOC_8_PCREL, R_68K_PC8 }, + { BFD_RELOC_32_GOT_PCREL, R_68K_GOT32 }, + { BFD_RELOC_16_GOT_PCREL, R_68K_GOT16 }, + { BFD_RELOC_8_GOT_PCREL, R_68K_GOT8 }, + { BFD_RELOC_32_GOTOFF, R_68K_GOT32O }, + { BFD_RELOC_16_GOTOFF, R_68K_GOT16O }, + { BFD_RELOC_8_GOTOFF, R_68K_GOT8O }, + { BFD_RELOC_32_PLT_PCREL, R_68K_PLT32 }, + { BFD_RELOC_16_PLT_PCREL, R_68K_PLT16 }, + { BFD_RELOC_8_PLT_PCREL, R_68K_PLT8 }, + { BFD_RELOC_32_PLTOFF, R_68K_PLT32O }, + { BFD_RELOC_16_PLTOFF, R_68K_PLT16O }, + { BFD_RELOC_8_PLTOFF, R_68K_PLT8O }, + { BFD_RELOC_NONE, R_68K_COPY }, + { BFD_RELOC_68K_GLOB_DAT, R_68K_GLOB_DAT }, + { BFD_RELOC_68K_JMP_SLOT, R_68K_JMP_SLOT }, + { BFD_RELOC_68K_RELATIVE, R_68K_RELATIVE }, + { BFD_RELOC_CTOR, R_68K_32 }, +}; + +static reloc_howto_type * +reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++) + { + if (reloc_map[i].bfd_val == code) + return &howto_table[(int) reloc_map[i].elf_val]; + } + return 0; +} + +#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup +#define ELF_ARCH bfd_arch_m68k +/* end code generated by elf.el */ + +#define USE_RELA + + +/* Functions for the m68k ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 20 + +/* The first entry in a procedure linkage table looks like this. See + the SVR4 ABI m68k supplement to see how this works. */ + +static const bfd_byte elf_m68k_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0x2f, 0x3b, 0x01, 0x70, /* move.l (%pc,addr),-(%sp) */ + 0, 0, 0, 0, /* replaced with offset to .got + 4. */ + 0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,addr]) */ + 0, 0, 0, 0, /* replaced with offset to .got + 8. */ + 0, 0, 0, 0 /* pad out to 20 bytes. */ +}; + +/* Subsequent entries in a procedure linkage table look like this. */ + +static const bfd_byte elf_m68k_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,symbol@GOTPC]) */ + 0, 0, 0, 0, /* replaced with offset to symbol's .got entry. */ + 0x2f, 0x3c, /* move.l #offset,-(%sp) */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0x60, 0xff, /* bra.l .plt */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table or procedure linkage + table. */ + +static boolean +elf_m68k_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sgot; + asection *srelgot; + asection *sreloc; + + if (info->relocateable) + return true; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_offsets = elf_local_got_offsets (abfd); + + sgot = NULL; + srelgot = NULL; + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_68K_GOT8: + case R_68K_GOT16: + case R_68K_GOT32: + if (h != NULL + && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ + case R_68K_GOT8O: + case R_68K_GOT16O: + case R_68K_GOT32O: + /* This symbol requires a global offset table entry. */ + + if (dynobj == NULL) + { + /* Create the .got section. */ + elf_hash_table (info)->dynobj = dynobj = abfd; + if (!_bfd_elf_create_got_section (dynobj, info)) + return false; + } + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (srelgot == NULL + && (h != NULL || info->shared)) + { + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (srelgot == NULL) + { + srelgot = bfd_make_section (dynobj, ".rela.got"); + if (srelgot == NULL + || !bfd_set_section_flags (dynobj, srelgot, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || !bfd_set_section_alignment (dynobj, srelgot, 2)) + return false; + } + } + + if (h != NULL) + { + if (h->got_offset != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + h->got_offset = sgot->_raw_size; + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (!bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + srelgot->_raw_size += sizeof (Elf32_External_Rela); + } + else + { + /* This is a global offset table entry for a local + symbol. */ + if (local_got_offsets == NULL) + { + size_t size; + register unsigned int i; + + size = symtab_hdr->sh_info * sizeof (bfd_vma); + local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); + if (local_got_offsets == NULL) + return false; + elf_local_got_offsets (abfd) = local_got_offsets; + for (i = 0; i < symtab_hdr->sh_info; i++) + local_got_offsets[i] = (bfd_vma) -1; + } + if (local_got_offsets[r_symndx] != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + local_got_offsets[r_symndx] = sgot->_raw_size; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_68K_RELATIVE reloc so that the dynamic + linker can adjust this GOT entry. */ + srelgot->_raw_size += sizeof (Elf32_External_Rela); + } + } + + sgot->_raw_size += 4; + break; + + case R_68K_PLT8: + case R_68K_PLT16: + case R_68K_PLT32: + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code which is + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + break; + + case R_68K_PLT8O: + case R_68K_PLT16O: + case R_68K_PLT32O: + /* This symbol requires a procedure linkage table entry. */ + + if (h == NULL) + { + /* It does not make sense to have this relocation for a + local symbol. FIXME: does it? How to handle it if + it does make sense? */ + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (!bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + break; + + case R_68K_PC8: + case R_68K_PC16: + case R_68K_PC32: + if (h == NULL) + break; + /* Fall through. */ + case R_68K_8: + case R_68K_16: + case R_68K_32: + if (info->shared + && (sec->flags & SEC_ALLOC) != 0 + && ((ELF32_R_TYPE (rel->r_info) != R_68K_PC8 + && ELF32_R_TYPE (rel->r_info) != R_68K_PC16 + && ELF32_R_TYPE (rel->r_info) != R_68K_PC32) + || (!info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) + { + /* When creating a shared object, we must copy these + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || !bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || !bfd_set_section_alignment (dynobj, sreloc, 2)) + return false; + } + } + + sreloc->_raw_size += sizeof (Elf32_External_Rela); + } + + break; + + default: + break; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +elf_m68k_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + unsigned int power_of_two; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) + || h->weakdef != NULL + || ((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC + || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0 + /* We must always create the plt entry if it was referenced + by a PLTxxO relocation. In this case we already recorded + it as a dynamic symbol. */ + && h->dynindx == -1) + { + /* This case can occur if we saw a PLTxx reloc in an input + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a PCxx + reloc instead. */ + BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0); + return true; + } + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (!info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } + + h->plt_offset = s->_raw_size; + + /* Make room for this entry. */ + s->_raw_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. */ + + s = bfd_get_section_by_name (dynobj, ".got.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += 4; + + /* We also need to make an entry in the .rela.plt section. */ + + s = bfd_get_section_by_name (dynobj, ".rela.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += sizeof (Elf32_External_Rela); + + return true; + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + 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 + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + s = bfd_get_section_by_name (dynobj, ".dynbss"); + BFD_ASSERT (s != NULL); + + /* If the symbol is currently defined in the .bss section of the + dynamic object, then it is OK to simply initialize it to zero. + If the symbol is in some other section, we must generate a + R_68K_COPY reloc to tell the dynamic linker to copy the initial + value out of the dynamic object and into the runtime process + image. We need to remember the offset into the .rela.bss section + we are going to use. */ + if ((h->root.u.def.section->flags & SEC_LOAD) != 0) + { + asection *srel; + + srel = bfd_get_section_by_name (dynobj, ".rela.bss"); + BFD_ASSERT (srel != NULL); + srel->_raw_size += sizeof (Elf32_External_Rela); + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 3) + power_of_two = 3; + + /* Apply the required alignment. */ + s->_raw_size = BFD_ALIGN (s->_raw_size, + (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (dynobj, s)) + { + if (!bfd_set_section_alignment (dynobj, s, power_of_two)) + return false; + } + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +elf_m68k_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean plt; + boolean relocs; + boolean reltext; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (!info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + else + { + /* We may have created entries in the .rela.got section. + However, if we are not creating the dynamic sections, we will + not actually use these entries. Reset the size of .rela.got, + which will cause it to get stripped from the output file + below. */ + s = bfd_get_section_by_name (dynobj, ".rela.got"); + if (s != NULL) + s->_raw_size = 0; + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + plt = false; + relocs = false; + reltext = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + if ((s->flags & SEC_IN_MEMORY) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + strip = false; + + if (strcmp (name, ".plt") == 0) + { + if (s->_raw_size == 0) + { + /* Strip this section if we don't need it; see the + comment below. */ + strip = true; + } + else + { + /* Remember whether there is a PLT. */ + plt = true; + } + } + else if (strncmp (name, ".rela", 5) == 0) + { + if (s->_raw_size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + strip = true; + } + else + { + asection *target; + + /* Remember whether there are any reloc sections other + than .rela.plt. */ + if (strcmp (name, ".rela.plt") != 0) + { + relocs = true; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL + entry. .rela.plt is actually associated with + .got.plt, which is never readonly. */ + target = bfd_get_section_by_name (output_bfd, name + 5); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + } + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else if (strncmp (name, ".got", 4) != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_m68k_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (!info->shared) + { + if (!bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (plt) + { + if (!bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0) + || !bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || !bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA) + || !bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + if (relocs) + { + if (!bfd_elf32_add_dynamic_entry (info, DT_RELA, 0) + || !bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0) + || !bfd_elf32_add_dynamic_entry (info, DT_RELAENT, + sizeof (Elf32_External_Rela))) + return false; + } + + if (reltext) + { + if (!bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + } + + return true; +} + +/* Relocate an M68K ELF section. */ + +static boolean +elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + asection *sgot; + asection *splt; + asection *sreloc; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); + + sgot = NULL; + splt = NULL; + sreloc = NULL; + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_68K__max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if (((r_type == R_68K_PLT8 + || r_type == R_68K_PLT16 + || r_type == R_68K_PLT32 + || r_type == R_68K_PLT8O + || r_type == R_68K_PLT16O + || r_type == R_68K_PLT32O) + && h->plt_offset != (bfd_vma) -1) + || ((r_type == R_68K_GOT8O + || r_type == R_68K_GOT16O + || r_type == R_68K_GOT32O + || ((r_type == R_68K_GOT8 + || r_type == R_68K_GOT16 + || r_type == R_68K_GOT32) + && strcmp (h->root.root.string, + "_GLOBAL_OFFSET_TABLE_") != 0)) + && elf_hash_table (info)->dynamic_sections_created + && (! info->shared + || ! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || (info->shared + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0) + && (input_section->flags & SEC_ALLOC) != 0 + && (r_type == R_68K_8 + || r_type == R_68K_16 + || r_type == R_68K_32 + || r_type == R_68K_PC8 + || r_type == R_68K_PC16 + || r_type == R_68K_PC32))) + { + /* In these cases, we don't need the relocation + value. We check specially because in some + obscure cases sec->output_section will be NULL. */ + relocation = 0; + } + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared && !info->symbolic) + relocation = 0; + else + { + if (!(info->callbacks->undefined_symbol + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + switch (r_type) + { + case R_68K_GOT8: + case R_68K_GOT16: + case R_68K_GOT32: + /* Relocation is to the address of the entry for this symbol + in the global offset table. */ + if (h != NULL + && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ + case R_68K_GOT8O: + case R_68K_GOT16O: + case R_68K_GOT32O: + /* Relocation is the offset of the entry for this symbol in + the global offset table. */ + + { + bfd_vma off; + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (h != NULL) + { + off = h->got_offset; + BFD_ASSERT (off != (bfd_vma) -1); + + if (!elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global offset table. Since the offset must + always be a multiple of 4, we use the least + significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got_offset |= 1; + } + } + } + else + { + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) -1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); + outrel.r_addend = relocation; + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (((Elf32_External_Rela *) + srelgot->contents) + + srelgot->reloc_count)); + ++srelgot->reloc_count; + } + + local_got_offsets[r_symndx] |= 1; + } + } + + relocation = sgot->output_offset + off; + if (r_type == R_68K_GOT8O + || r_type == R_68K_GOT16O + || r_type == R_68K_GOT32O) + { + /* This relocation does not use the addend. */ + rel->r_addend = 0; + } + else + relocation += sgot->output_section->vma; + } + break; + + case R_68K_PLT8: + case R_68K_PLT16: + case R_68K_PLT32: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* Resolve a PLTxx reloc against a local symbol directly, + without using the procedure linkage table. */ + if (h == NULL) + break; + + if (h->plt_offset == (bfd_vma) -1) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + } + + if (splt == NULL) + { + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL); + } + + relocation = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + break; + + case R_68K_PLT8O: + case R_68K_PLT16O: + case R_68K_PLT32O: + /* Relocation is the offset of the entry for this symbol in + the procedure linkage table. */ + BFD_ASSERT (h != NULL && h->plt_offset == (bfd_vma) -1); + + if (splt == NULL) + { + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL); + } + + relocation = h->plt_offset; + + /* This relocation does not use the addend. */ + rel->r_addend = 0; + + break; + + case R_68K_PC8: + case R_68K_PC16: + case R_68K_PC32: + if (h == NULL) + break; + /* Fall through. */ + case R_68K_8: + case R_68K_16: + case R_68K_32: + if (info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && ((r_type != R_68K_PC8 + && r_type != R_68K_PC16 + && r_type != R_68K_PC32) + || (!info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) + { + Elf_Internal_Rela outrel; + int relocate; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (input_bfd, + elf_elfheader (input_bfd)->e_shstrndx, + elf_section_data (input_section)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (input_bfd, + input_section), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + BFD_ASSERT (sreloc != NULL); + } + + outrel.r_offset = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + if (h != NULL + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + { + BFD_ASSERT (h->dynindx != -1); + relocate = false; + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + if (r_type == R_68K_32) + { + relocate = true; + outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + long indx; + + if (h == NULL) + sec = local_sections[r_symndx]; + else + { + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || (h->root.type + == bfd_link_hash_defweak)); + sec = h->root.u.def.section; + } + if (sec != NULL && bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + asection *osec; + + osec = sec->output_section; + indx = elf_section_data (osec)->dynindx; + if (indx == 0) + abort (); + } + + relocate = false; + outrel.r_info = ELF32_R_INFO (indx, r_type); + outrel.r_addend = relocation + rel->r_addend; + } + } + + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (((Elf32_External_Rela *) + sreloc->contents) + + sreloc->reloc_count)); + ++sreloc->reloc_count; + + /* This reloc will be computed at runtime, so there's no + need to do anything now, except for R_68K_32 + relocations that have been turned into + R_68K_RELATIVE. */ + if (!relocate) + continue; + } + + break; + + default: + break; + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (!(info->callbacks->reloc_overflow + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj; + + dynobj = elf_hash_table (info)->dynobj; + + if (h->plt_offset != (bfd_vma) -1) + { + asection *splt; + asection *sgot; + asection *srela; + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = bfd_get_section_by_name (dynobj, ".plt"); + sgot = bfd_get_section_by_name (dynobj, ".got.plt"); + srela = bfd_get_section_by_name (dynobj, ".rela.plt"); + BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->plt_offset / PLT_ENTRY_SIZE - 1; + + /* Get the offset into the .got table of the entry that + corresponds to this function. Each .got entry is 4 bytes. + The first three are reserved. */ + got_offset = (plt_index + 3) * 4; + + /* Fill in the entry in the procedure linkage table. */ + memcpy (splt->contents + h->plt_offset, elf_m68k_plt_entry, + PLT_ENTRY_SIZE); + /* The offset is relative to the first extension word. */ + bfd_put_32 (output_bfd, + (sgot->output_section->vma + + sgot->output_offset + + got_offset + - (splt->output_section->vma + + h->plt_offset + 2)), + splt->contents + h->plt_offset + 4); + + bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela), + splt->contents + h->plt_offset + 10); + bfd_put_32 (output_bfd, - (h->plt_offset + 16), + splt->contents + h->plt_offset + 16); + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + (splt->output_section->vma + + splt->output_offset + + h->plt_offset + + 8), + sgot->contents + got_offset); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_JMP_SLOT); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) srela->contents + + plt_index)); + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got_offset != (bfd_vma) -1) + { + asection *sgot; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the global offset table. Set it + up. */ + + BFD_ASSERT (h->dynindx != -1); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + srela = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (sgot != NULL && srela != NULL); + + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + (h->got_offset &~ 1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. The entry in + the global offset table will already have been initialized in + the relocate_section function. */ + if (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + { + rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); + rela.r_addend = bfd_get_32 (output_bfd, + sgot->contents + (h->got_offset & ~1)); + } + else + { + bfd_put_32 (output_bfd, (bfd_vma) 0, + sgot->contents + (h->got_offset & ~1)); + rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT); + rela.r_addend = 0; + } + + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) srela->contents + + srela->reloc_count)); + ++srela->reloc_count; + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + asection *s; + Elf_Internal_Rela rela; + + /* This symbol needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rela.bss"); + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_COPY); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) s->contents + + s->reloc_count)); + ++s->reloc_count; + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +elf_m68k_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sgot; + asection *sdyn; + + dynobj = elf_hash_table (info)->dynobj; + + sgot = bfd_get_section_by_name (dynobj, ".got.plt"); + BFD_ASSERT (sgot != NULL); + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_PLTGOT: + name = ".got"; + goto get_vma; + case DT_JMPREL: + name = ".rela.plt"; + get_vma: + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTRELSZ: + s = bfd_get_section_by_name (output_bfd, ".rela.plt"); + BFD_ASSERT (s != NULL); + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_RELASZ: + /* The procedure linkage table relocs (DT_JMPREL) should + not be included in the overall relocs (DT_RELA). + Therefore, we override the DT_RELASZ entry here to + make it not include the JMPREL relocs. Since the + linker script arranges for .rela.plt to follow all + other relocation sections, we don't have to worry + about changing the DT_RELA entry. */ + s = bfd_get_section_by_name (output_bfd, ".rela.plt"); + if (s != NULL) + { + if (s->_cooked_size != 0) + dyn.d_un.d_val -= s->_cooked_size; + else + dyn.d_un.d_val -= s->_raw_size; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } + } + + /* Fill in the first entry in the procedure linkage table. */ + if (splt->_raw_size > 0) + { + memcpy (splt->contents, elf_m68k_plt0_entry, PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + (sgot->output_section->vma + + sgot->output_offset + 4 + - (splt->output_section->vma + 2)), + splt->contents + 4); + bfd_put_32 (output_bfd, + (sgot->output_section->vma + + sgot->output_offset + 8 + - (splt->output_section->vma + 10)), + splt->contents + 12); + } + + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = PLT_ENTRY_SIZE; + } + + /* Fill in the first three entries in the global offset table. */ + if (sgot->_raw_size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); + } + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + + return true; +} + +#define TARGET_BIG_SYM bfd_elf32_m68k_vec +#define TARGET_BIG_NAME "elf32-m68k" +#define ELF_MACHINE_CODE EM_68K +#define ELF_MAXPAGESIZE 0x2000 +#define elf_backend_create_dynamic_sections \ + _bfd_elf_create_dynamic_sections +#define elf_backend_check_relocs elf_m68k_check_relocs +#define elf_backend_adjust_dynamic_symbol \ + elf_m68k_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + elf_m68k_size_dynamic_sections +#define elf_backend_relocate_section elf_m68k_relocate_section +#define elf_backend_finish_dynamic_symbol \ + elf_m68k_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + elf_m68k_finish_dynamic_sections +#define elf_backend_want_got_plt 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_want_plt_sym 0 + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-m88k.c b/contrib/gdb/bfd/elf32-m88k.c new file mode 100644 index 000000000000..f3c535e07764 --- /dev/null +++ b/contrib/gdb/bfd/elf32-m88k.c @@ -0,0 +1,35 @@ +/* Motorola 88k-specific support for 32-bit ELF + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* This does not include any relocations, but should be good enough + for GDB. */ + +#define TARGET_BIG_SYM bfd_elf32_m88k_vec +#define TARGET_BIG_NAME "elf32-m88k" +#define ELF_ARCH bfd_arch_m88k +#define ELF_MACHINE_CODE EM_88K +#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define elf_info_to_howto _bfd_elf_no_info_to_howto + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-mips.c b/contrib/gdb/bfd/elf32-mips.c new file mode 100644 index 000000000000..ced0000e2c51 --- /dev/null +++ b/contrib/gdb/bfd/elf32-mips.c @@ -0,0 +1,5867 @@ +/* MIPS-specific support for 32-bit ELF + Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Most of the information added by Ian Lance Taylor, Cygnus Support, + . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file handles MIPS ELF targets. SGI Irix 5 uses a slightly + different MIPS ELF from other targets. This matters when linking. + This file supports both, switching at runtime. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "elf-bfd.h" +#include "elf/mips.h" + +/* Get the ECOFF swapping routines. */ +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/internal.h" +#include "coff/ecoff.h" +#include "coff/mips.h" +#define ECOFF_32 +#include "ecoffswap.h" + +static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static bfd_reloc_status_type mips_elf_gprel32_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd, + char **error)); +static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void mips_info_to_howto_rel + PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); +static void bfd_mips_elf32_swap_gptab_in + PARAMS ((bfd *, const Elf32_External_gptab *, Elf32_gptab *)); +static void bfd_mips_elf32_swap_gptab_out + PARAMS ((bfd *, const Elf32_gptab *, Elf32_External_gptab *)); +static boolean mips_elf_sym_is_global PARAMS ((bfd *, asymbol *)); +static boolean mips_elf_object_p PARAMS ((bfd *)); +static boolean mips_elf_create_procedure_table + PARAMS ((PTR, bfd *, struct bfd_link_info *, asection *, + struct ecoff_debug_info *)); +static int mips_elf_additional_program_headers PARAMS ((bfd *)); +static boolean mips_elf_modify_segment_map PARAMS ((bfd *)); +static void mips_elf_final_write_processing + PARAMS ((bfd *, boolean)); +static boolean mips_elf_set_private_flags PARAMS ((bfd *, flagword)); +static boolean mips_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +static boolean mips_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); +static boolean mips_elf_section_from_shdr + PARAMS ((bfd *, Elf32_Internal_Shdr *, char *)); +static boolean mips_elf_fake_sections + PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); +static boolean mips_elf_section_from_bfd_section + PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *)); +static boolean mips_elf_section_processing + PARAMS ((bfd *, Elf32_Internal_Shdr *)); +static void mips_elf_symbol_processing PARAMS ((bfd *, asymbol *)); +static boolean mips_elf_read_ecoff_info + PARAMS ((bfd *, asection *, struct ecoff_debug_info *)); +static boolean mips_elf_is_local_label + PARAMS ((bfd *, asymbol *)); +static boolean mips_elf_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); +static struct bfd_hash_entry *mips_elf_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table *mips_elf_link_hash_table_create + PARAMS ((bfd *)); +static int gptab_compare PARAMS ((const void *, const void *)); +static boolean mips_elf_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +static void mips_elf_relocate_hi16 + PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *, + bfd_vma)); +static void mips_elf_relocate_got_local + PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *, + Elf_Internal_Rela *, bfd_byte *, bfd_vma)); +static void mips_elf_relocate_global_got + PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma)); +static boolean mips_elf_adjust_dynindx + PARAMS ((struct elf_link_hash_entry *, PTR)); +static boolean mips_elf_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean mips_elf_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean mips_elf_create_compact_rel_section + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean mips_elf_create_got_section + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean mips_elf_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static boolean mips_elf_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean mips_elf_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean mips_elf_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean mips_elf_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean mips_elf_add_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); +static bfd_reloc_status_type mips_elf_final_gp + PARAMS ((bfd *, asymbol *, boolean, char **, bfd_vma *)); +static bfd_byte *elf32_mips_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean, asymbol **)); + +/* This is true for Irix 5 executables, false for normal MIPS ELF ABI + executables. FIXME: At the moment, we default to always generating + Irix 5 executables. */ + +#define SGI_COMPAT(abfd) (1) + +/* This structure is used to hold .got information when linking. It + is stored in the tdata field of the bfd_elf_section_data structure. */ + +struct mips_got_info +{ + /* The symbol index of the first global .got symbol. */ + unsigned long global_gotsym; + /* The number of local .got entries. */ + unsigned int local_gotno; +}; + +/* The number of local .got entries we reserve. */ +#define MIPS_RESERVED_GOTNO (2) + +/* Instructions which appear in a stub. For some reason the stub is + slightly different on an SGI system. */ +#define ELF_MIPS_GP_OFFSET(abfd) (SGI_COMPAT (abfd) ? 0x7ff0 : 0x8000) +#define STUB_LW(abfd) \ + (SGI_COMPAT (abfd) \ + ? 0x8f998010 /* lw t9,0x8010(gp) */ \ + : 0x8f998000) /* lw t9,0x8000(gp) */ +#define STUB_MOVE 0x03e07825 /* move t7,ra */ +#define STUB_JALR 0x0320f809 /* jal t9 */ +#define STUB_LI16 0x34180000 /* ori t8,zero,0 */ +#define MIPS_FUNCTION_STUB_SIZE (16) + +/* Names of sections which appear in the .dynsym section in an Irix 5 + executable. */ + +static const char * const mips_elf_dynsym_sec_names[] = +{ + ".text", + ".init", + ".fini", + ".data", + ".rodata", + ".sdata", + ".sbss", + ".bss", + NULL +}; + +#define SIZEOF_MIPS_DYNSYM_SECNAMES \ + (sizeof mips_elf_dynsym_sec_names / sizeof mips_elf_dynsym_sec_names[0]) + +/* The number of entries in mips_elf_dynsym_sec_names which go in the + text segment. */ + +#define MIPS_TEXT_DYNSYM_SECNO (3) + +/* The names of the runtime procedure table symbols used on Irix 5. */ + +static const char * const mips_elf_dynsym_rtproc_names[] = +{ + "_procedure_table", + "_procedure_string_table", + "_procedure_table_size", + NULL +}; + +/* These structures are used to generate the .compact_rel section on + Irix 5. */ + +typedef struct +{ + unsigned long id1; /* Always one? */ + unsigned long num; /* Number of compact relocation entries. */ + unsigned long id2; /* Always two? */ + unsigned long offset; /* The file offset of the first relocation. */ + unsigned long reserved0; /* Zero? */ + unsigned long reserved1; /* Zero? */ +} Elf32_compact_rel; + +typedef struct +{ + bfd_byte id1[4]; + bfd_byte num[4]; + bfd_byte id2[4]; + bfd_byte offset[4]; + bfd_byte reserved0[4]; + bfd_byte reserved1[4]; +} Elf32_External_compact_rel; + +typedef struct +{ + unsigned int ctype : 1; /* 1: long 0: short format. See below. */ + unsigned int rtype : 4; /* Relocation types. See below. */ + unsigned int dist2to : 8; + unsigned int relvaddr : 19; /* (VADDR - vaddr of the previous entry)/ 4 */ + unsigned long konst; /* KONST field. See below. */ + unsigned long vaddr; /* VADDR to be relocated. */ +} Elf32_crinfo; + +typedef struct +{ + unsigned int ctype : 1; /* 1: long 0: short format. See below. */ + unsigned int rtype : 4; /* Relocation types. See below. */ + unsigned int dist2to : 8; + unsigned int relvaddr : 19; /* (VADDR - vaddr of the previous entry)/ 4 */ + unsigned long konst; /* KONST field. See below. */ +} Elf32_crinfo2; + +typedef struct +{ + bfd_byte info[4]; + bfd_byte konst[4]; + bfd_byte vaddr[4]; +} Elf32_External_crinfo; + +typedef struct +{ + bfd_byte info[4]; + bfd_byte konst[4]; +} Elf32_External_crinfo2; + +/* These are the constants used to swap the bitfields in a crinfo. */ + +#define CRINFO_CTYPE (0x1) +#define CRINFO_CTYPE_SH (31) +#define CRINFO_RTYPE (0xf) +#define CRINFO_RTYPE_SH (27) +#define CRINFO_DIST2TO (0xff) +#define CRINFO_DIST2TO_SH (19) +#define CRINFO_RELVADDR (0x7ffff) +#define CRINFO_RELVADDR_SH (0) + +/* A compact relocation info has long (3 words) or short (2 words) + formats. A short format doesn't have VADDR field and relvaddr + fields contains ((VADDR - vaddr of the previous entry) >> 2). */ +#define CRF_MIPS_LONG 1 +#define CRF_MIPS_SHORT 0 + +/* There are 4 types of compact relocation at least. The value KONST + has different meaning for each type: + + (type) (konst) + CT_MIPS_REL32 Address in data + CT_MIPS_WORD Address in word (XXX) + CT_MIPS_GPHI_LO GP - vaddr + CT_MIPS_JMPAD Address to jump + */ + +#define CRT_MIPS_REL32 0xa +#define CRT_MIPS_WORD 0xb +#define CRT_MIPS_GPHI_LO 0xc +#define CRT_MIPS_JMPAD 0xd + +#define mips_elf_set_cr_format(x,format) ((x).ctype = (format)) +#define mips_elf_set_cr_type(x,type) ((x).rtype = (type)) +#define mips_elf_set_cr_dist2to(x,v) ((x).dist2to = (v)) +#define mips_elf_set_cr_relvaddr(x,d) ((x).relvaddr = (d)<<2) + +static void bfd_elf32_swap_compact_rel_out + PARAMS ((bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *)); +static void bfd_elf32_swap_crinfo_out + PARAMS ((bfd *, const Elf32_crinfo *, Elf32_External_crinfo *)); + +#define USE_REL 1 /* MIPS uses REL relocations instead of RELA */ + +enum reloc_type +{ + R_MIPS_NONE = 0, + R_MIPS_16, R_MIPS_32, + R_MIPS_REL32, R_MIPS_26, + R_MIPS_HI16, R_MIPS_LO16, + R_MIPS_GPREL16, R_MIPS_LITERAL, + R_MIPS_GOT16, R_MIPS_PC16, + R_MIPS_CALL16, R_MIPS_GPREL32, + /* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ + R_MIPS_UNUSED1, R_MIPS_UNUSED2, + R_MIPS_UNUSED3, + R_MIPS_SHIFT5, R_MIPS_SHIFT6, + R_MIPS_64, R_MIPS_GOT_DISP, + R_MIPS_GOT_PAGE, R_MIPS_GOT_OFST, + R_MIPS_GOT_HI16, R_MIPS_GOT_LO16, + R_MIPS_SUB, R_MIPS_INSERT_A, + R_MIPS_INSERT_B, R_MIPS_DELETE, + R_MIPS_HIGHER, R_MIPS_HIGHEST, + R_MIPS_CALL_HI16, R_MIPS_CALL_LO16, + R_MIPS_max +}; + +static reloc_howto_type elf_mips_howto_table[] = +{ + /* No relocation. */ + HOWTO (R_MIPS_NONE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit relocation. */ + HOWTO (R_MIPS_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit relocation. */ + HOWTO (R_MIPS_32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit symbol relative relocation. */ + HOWTO (R_MIPS_REL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_REL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 26 bit branch address. */ + HOWTO (R_MIPS_26, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + /* This needs complex overflow + detection, because the upper four + bits must match the PC. */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_26", /* name */ + true, /* partial_inplace */ + 0x3ffffff, /* src_mask */ + 0x3ffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* High 16 bits of symbol value. */ + HOWTO (R_MIPS_HI16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + mips_elf_hi16_reloc, /* special_function */ + "R_MIPS_HI16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Low 16 bits of symbol value. */ + HOWTO (R_MIPS_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + mips_elf_lo16_reloc, /* special_function */ + "R_MIPS_LO16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* GP relative reference. */ + HOWTO (R_MIPS_GPREL16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_elf_gprel16_reloc, /* special_function */ + "R_MIPS_GPREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Reference to literal section. */ + HOWTO (R_MIPS_LITERAL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_elf_gprel16_reloc, /* special_function */ + "R_MIPS_LITERAL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Reference to global offset table. */ + HOWTO (R_MIPS_GOT16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + mips_elf_got16_reloc, /* special_function */ + "R_MIPS_GOT16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit PC relative reference. */ + HOWTO (R_MIPS_PC16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_PC16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit call through global offset table. */ + /* FIXME: This is not handled correctly. */ + HOWTO (R_MIPS_CALL16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_CALL16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit GP relative reference. */ + HOWTO (R_MIPS_GPREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + mips_elf_gprel32_reloc, /* special_function */ + "R_MIPS_GPREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The remaining relocs are defined on Irix 5, although they are + not defined by the ABI. */ + { 13 }, + { 14 }, + { 15 }, + + /* A 5 bit shift field. */ + HOWTO (R_MIPS_SHIFT5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 5, /* bitsize */ + false, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_SHIFT5", /* name */ + true, /* partial_inplace */ + 0x000007c0, /* src_mask */ + 0x000007c0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 6 bit shift field. */ + /* FIXME: This is not handled correctly; a special function is + needed to put the most significant bit in the right place. */ + HOWTO (R_MIPS_SHIFT6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 6, /* bitsize */ + false, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_SHIFT6", /* name */ + true, /* partial_inplace */ + 0x000007c4, /* src_mask */ + 0x000007c4, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit relocation. Presumably not used in 32 bit ELF. */ + { R_MIPS_64 }, + + /* Displacement in the global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_GOT_DISP, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GOT_DISP", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Displacement to page pointer in the global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_GOT_PAGE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GOT_PAGE", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Offset from page pointer in the global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_GOT_OFST, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GOT_OFST", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* High 16 bits of displacement in global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_GOT_HI16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GOT_HI16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Low 16 bits of displacement in global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_GOT_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GOT_LO16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 64 bit subtraction. Presumably not used in 32 bit ELF. */ + { R_MIPS_SUB }, + + /* Used to cause the linker to insert and delete instructions? */ + { R_MIPS_INSERT_A }, + { R_MIPS_INSERT_B }, + { R_MIPS_DELETE }, + + /* Get the higher values of a 64 bit addend. Presumably not used in + 32 bit ELF. */ + { R_MIPS_HIGHER }, + { R_MIPS_HIGHEST }, + + /* High 16 bits of displacement in global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_CALL_HI16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_CALL_HI16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Low 16 bits of displacement in global offset table. */ + /* FIXME: Not handled correctly. */ + HOWTO (R_MIPS_CALL_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_CALL_LO16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false) /* pcrel_offset */ +}; + +/* Do a R_MIPS_HI16 relocation. This has to be done in combination + with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to + the HI16. Here we just save the information we need; we do the + actual relocation when we see the LO16. MIPS ELF requires that the + LO16 immediately follow the HI16, so this ought to work. */ + +static bfd_byte *mips_hi16_addr; +static bfd_vma mips_hi16_addend; + +static bfd_reloc_status_type +mips_elf_hi16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_reloc_status_type ret; + bfd_vma relocation; + + /* If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + ret = bfd_reloc_ok; + + if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0) + { + boolean relocateable; + bfd_vma gp; + + if (ret == bfd_reloc_undefined) + abort (); + + if (output_bfd != NULL) + relocateable = true; + else + { + relocateable = false; + output_bfd = symbol->section->output_section->owner; + } + + ret = mips_elf_final_gp (output_bfd, symbol, relocateable, + error_message, &gp); + if (ret != bfd_reloc_ok) + return ret; + + relocation = gp - reloc_entry->address; + } + else + { + if (bfd_is_und_section (symbol->section) + && output_bfd == (bfd *) NULL) + ret = bfd_reloc_undefined; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + } + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Save the information, and let LO16 do the actual relocation. */ + mips_hi16_addr = (bfd_byte *) data + reloc_entry->address; + mips_hi16_addend = relocation; + + if (output_bfd != (bfd *) NULL) + reloc_entry->address += input_section->output_offset; + + return ret; +} + +/* Do a R_MIPS_LO16 relocation. This is a straightforward 16 bit + inplace relocation; this function exists in order to do the + R_MIPS_HI16 relocation described above. */ + +static bfd_reloc_status_type +mips_elf_lo16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + arelent gp_disp_relent; + + if (mips_hi16_addr != (bfd_byte *) NULL) + { + unsigned long insn; + unsigned long val; + unsigned long vallo; + + /* Do the HI16 relocation. Note that we actually don't need to + know anything about the LO16 itself, except where to find the + low 16 bits of the addend needed by the LO16. */ + insn = bfd_get_32 (abfd, mips_hi16_addr); + vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) + & 0xffff); + val = ((insn & 0xffff) << 16) + vallo; + val += mips_hi16_addend; + + /* The low order 16 bits are always treated as a signed value. + Therefore, a negative value in the low order bits requires an + adjustment in the high order bits. We need to make this + adjustment in two ways: once for the bits we took from the + data, and once for the bits we are putting back in to the + data. */ + if ((vallo & 0x8000) != 0) + val -= 0x10000; + if ((val & 0x8000) != 0) + val += 0x10000; + + insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); + bfd_put_32 (abfd, insn, mips_hi16_addr); + + mips_hi16_addr = (bfd_byte *) NULL; + + if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0) + { + gp_disp_relent = *reloc_entry; + reloc_entry = &gp_disp_relent; + reloc_entry->addend = mips_hi16_addend; + } + } + else if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0) + { + bfd_reloc_status_type ret; + bfd_vma gp, relocation; + + /* FIXME: Does this case ever occur? */ + + ret = mips_elf_final_gp (output_bfd, symbol, true, error_message, &gp); + if (ret != bfd_reloc_ok) + return ret; + + relocation = gp - reloc_entry->address; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + gp_disp_relent = *reloc_entry; + reloc_entry = &gp_disp_relent; + reloc_entry->addend = relocation - 4; + } + + /* Now do the LO16 reloc in the usual way. */ + return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} + +/* Do a R_MIPS_GOT16 reloc. This is a reloc against the global offset + table used for PIC code. If the symbol is an external symbol, the + instruction is modified to contain the offset of the appropriate + entry in the global offset table. If the symbol is a section + symbol, the next reloc is a R_MIPS_LO16 reloc. The two 16 bit + addends are combined to form the real addend against the section + symbol; the GOT16 is modified to contain the offset of an entry in + the global offset table, and the LO16 is modified to offset it + appropriately. Thus an offset larger than 16 bits requires a + modified value in the global offset table. + + This implementation suffices for the assembler, but the linker does + not yet know how to create global offset tables. */ + +static bfd_reloc_status_type +mips_elf_got16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* If we're relocating, and this an external symbol, we don't want + to change anything. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we're relocating, and this is a local symbol, we can handle it + just like HI16. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) != 0) + return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); + + abort (); +} + +/* We have to figure out the gp value, so that we can adjust the + symbol value correctly. We look up the symbol _gp in the output + BFD. If we can't find it, we're stuck. We cache it in the ELF + target data. We don't need to adjust the symbol value for an + external symbol if we are producing relocateable output. */ + +static bfd_reloc_status_type +mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, pgp) + bfd *output_bfd; + asymbol *symbol; + boolean relocateable; + char **error_message; + bfd_vma *pgp; +{ + if (bfd_is_und_section (symbol->section) + && ! relocateable) + { + *pgp = 0; + return bfd_reloc_undefined; + } + + *pgp = _bfd_get_gp_value (output_bfd); + if (*pgp == 0 + && (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0)) + { + if (relocateable) + { + /* Make up a value. */ + *pgp = symbol->section->output_section->vma + 0x4000; + _bfd_set_gp_value (output_bfd, *pgp); + } + else + { + unsigned int count; + asymbol **sym; + unsigned int i; + + count = bfd_get_symcount (output_bfd); + sym = bfd_get_outsymbols (output_bfd); + + if (sym == (asymbol **) NULL) + i = count; + else + { + for (i = 0; i < count; i++, sym++) + { + register CONST char *name; + + name = bfd_asymbol_name (*sym); + if (*name == '_' && strcmp (name, "_gp") == 0) + { + *pgp = bfd_asymbol_value (*sym); + _bfd_set_gp_value (output_bfd, *pgp); + break; + } + } + } + + if (i >= count) + { + /* Only get the error once. */ + *pgp = 4; + _bfd_set_gp_value (output_bfd, *pgp); + *error_message = + (char *) "GP relative relocation when _gp not defined"; + return bfd_reloc_dangerous; + } + } + } + + return bfd_reloc_ok; +} + +/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must + become the offset from the gp register. This function also handles + R_MIPS_LITERAL relocations, although those can be handled more + cleverly because the entries in the .lit8 and .lit4 sections can be + merged. */ + +static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *, + arelent *, asection *, + boolean, PTR, bfd_vma)); + +static bfd_reloc_status_type +mips_elf_gprel16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + boolean relocateable; + bfd_reloc_status_type ret; + bfd_vma gp; + + /* If we're relocating, and this is an external symbol with no + addend, we don't want to change anything. We will only have an + addend if this is a newly created reloc, not read from an ELF + file. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != (bfd *) NULL) + relocateable = true; + else + { + relocateable = false; + output_bfd = symbol->section->output_section->owner; + } + + ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, + &gp); + if (ret != bfd_reloc_ok) + return ret; + + return gprel16_with_gp (abfd, symbol, reloc_entry, input_section, + relocateable, data, gp); +} + +static bfd_reloc_status_type +gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, + gp) + bfd *abfd; + asymbol *symbol; + arelent *reloc_entry; + asection *input_section; + boolean relocateable; + PTR data; + bfd_vma gp; +{ + bfd_vma relocation; + unsigned long insn; + unsigned long val; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + + /* Set val to the offset into the section or symbol. */ + val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; + if (val & 0x8000) + val -= 0x10000; + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + insn = (insn &~ 0xffff) | (val & 0xffff); + bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); + + if (relocateable) + reloc_entry->address += input_section->output_offset; + + /* Make sure it fit in 16 bits. */ + if (val >= 0x8000 && val < 0xffff8000) + return bfd_reloc_overflow; + + return bfd_reloc_ok; +} + +/* Do a R_MIPS_GPREL32 relocation. Is this 32 bit value the offset + from the gp register? XXX */ + +static bfd_reloc_status_type gprel32_with_gp PARAMS ((bfd *, asymbol *, + arelent *, asection *, + boolean, PTR, bfd_vma)); + +static bfd_reloc_status_type +mips_elf_gprel32_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + boolean relocateable; + bfd_reloc_status_type ret; + bfd_vma gp; + + /* If we're relocating, and this is an external symbol with no + addend, we don't want to change anything. We will only have an + addend if this is a newly created reloc, not read from an ELF + file. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + *error_message = (char *) + "32bits gp relative relocation occurs for an external symbol"; + return bfd_reloc_outofrange; + } + + if (output_bfd != (bfd *) NULL) + { + relocateable = true; + gp = _bfd_get_gp_value (output_bfd); + } + else + { + relocateable = false; + output_bfd = symbol->section->output_section->owner; + + ret = mips_elf_final_gp (output_bfd, symbol, relocateable, + error_message, &gp); + if (ret != bfd_reloc_ok) + return ret; + } + + return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, + relocateable, data, gp); +} + +static bfd_reloc_status_type +gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data, + gp) + bfd *abfd; + asymbol *symbol; + arelent *reloc_entry; + asection *input_section; + boolean relocateable; + PTR data; + bfd_vma gp; +{ + bfd_vma relocation; + unsigned long val; + + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + + /* Set val to the offset into the section or symbol. */ + val += reloc_entry->addend; + + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (! relocateable + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - gp; + + bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); + + if (relocateable) + reloc_entry->address += input_section->output_offset; + + return bfd_reloc_ok; +} + +/* A mapping from BFD reloc types to MIPS ELF reloc types. */ + +struct elf_reloc_map { + bfd_reloc_code_real_type bfd_reloc_val; + enum reloc_type elf_reloc_val; +}; + +static CONST struct elf_reloc_map mips_reloc_map[] = +{ + { BFD_RELOC_NONE, R_MIPS_NONE, }, + { BFD_RELOC_16, R_MIPS_16 }, + { BFD_RELOC_32, R_MIPS_32 }, + { BFD_RELOC_CTOR, R_MIPS_32 }, + { BFD_RELOC_32_PCREL, R_MIPS_REL32 }, + { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, + { BFD_RELOC_HI16_S, R_MIPS_HI16 }, + { BFD_RELOC_LO16, R_MIPS_LO16 }, + { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 }, + { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, + { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, + { BFD_RELOC_16_PCREL, R_MIPS_PC16 }, + { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, + { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 }, + { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, + { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, + { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, + { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 } +}; + +/* Given a BFD reloc type, return a howto structure. */ + +static reloc_howto_type * +bfd_elf32_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + + for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++) + { + if (mips_reloc_map[i].bfd_reloc_val == code) + return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val]; + } + return NULL; +} + +/* Given a MIPS reloc type, fill in an arelent structure. */ + +static void +mips_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rel *dst; +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + BFD_ASSERT (r_type < (unsigned int) R_MIPS_max); + cache_ptr->howto = &elf_mips_howto_table[r_type]; + + /* The addend for a GPREL16 or LITERAL relocation comes from the GP + value for the object file. We get the addend now, rather than + when we do the relocation, because the symbol manipulations done + by the linker may cause us to lose track of the input BFD. */ + if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 + && (r_type == (unsigned int) R_MIPS_GPREL16 + || r_type == (unsigned int) R_MIPS_LITERAL)) + cache_ptr->addend = elf_gp (abfd); +} + +/* A .reginfo section holds a single Elf32_RegInfo structure. These + routines swap this structure in and out. They are used outside of + BFD, so they are globally visible. */ + +void +bfd_mips_elf32_swap_reginfo_in (abfd, ex, in) + bfd *abfd; + const Elf32_External_RegInfo *ex; + Elf32_RegInfo *in; +{ + in->ri_gprmask = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gprmask); + in->ri_cprmask[0] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[0]); + in->ri_cprmask[1] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[1]); + in->ri_cprmask[2] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[2]); + in->ri_cprmask[3] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[3]); + in->ri_gp_value = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gp_value); +} + +void +bfd_mips_elf32_swap_reginfo_out (abfd, in, ex) + bfd *abfd; + const Elf32_RegInfo *in; + Elf32_External_RegInfo *ex; +{ + bfd_h_put_32 (abfd, (bfd_vma) in->ri_gprmask, + (bfd_byte *) ex->ri_gprmask); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[0], + (bfd_byte *) ex->ri_cprmask[0]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[1], + (bfd_byte *) ex->ri_cprmask[1]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[2], + (bfd_byte *) ex->ri_cprmask[2]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[3], + (bfd_byte *) ex->ri_cprmask[3]); + bfd_h_put_32 (abfd, (bfd_vma) in->ri_gp_value, + (bfd_byte *) ex->ri_gp_value); +} + +/* Swap an entry in a .gptab section. Note that these routines rely + on the equivalence of the two elements of the union. */ + +static void +bfd_mips_elf32_swap_gptab_in (abfd, ex, in) + bfd *abfd; + const Elf32_External_gptab *ex; + Elf32_gptab *in; +{ + in->gt_entry.gt_g_value = bfd_h_get_32 (abfd, ex->gt_entry.gt_g_value); + in->gt_entry.gt_bytes = bfd_h_get_32 (abfd, ex->gt_entry.gt_bytes); +} + +static void +bfd_mips_elf32_swap_gptab_out (abfd, in, ex) + bfd *abfd; + const Elf32_gptab *in; + Elf32_External_gptab *ex; +{ + bfd_h_put_32 (abfd, (bfd_vma) in->gt_entry.gt_g_value, + ex->gt_entry.gt_g_value); + bfd_h_put_32 (abfd, (bfd_vma) in->gt_entry.gt_bytes, + ex->gt_entry.gt_bytes); +} + +static void +bfd_elf32_swap_compact_rel_out (abfd, in, ex) + bfd *abfd; + const Elf32_compact_rel *in; + Elf32_External_compact_rel *ex; +{ + bfd_h_put_32 (abfd, (bfd_vma) in->id1, ex->id1); + bfd_h_put_32 (abfd, (bfd_vma) in->num, ex->num); + bfd_h_put_32 (abfd, (bfd_vma) in->id2, ex->id2); + bfd_h_put_32 (abfd, (bfd_vma) in->offset, ex->offset); + bfd_h_put_32 (abfd, (bfd_vma) in->reserved0, ex->reserved0); + bfd_h_put_32 (abfd, (bfd_vma) in->reserved1, ex->reserved1); +} + +static void +bfd_elf32_swap_crinfo_out (abfd, in, ex) + bfd *abfd; + const Elf32_crinfo *in; + Elf32_External_crinfo *ex; +{ + unsigned long l; + + l = (((in->ctype & CRINFO_CTYPE) << CRINFO_CTYPE_SH) + | ((in->rtype & CRINFO_RTYPE) << CRINFO_RTYPE_SH) + | ((in->dist2to & CRINFO_DIST2TO) << CRINFO_DIST2TO_SH) + | ((in->relvaddr & CRINFO_RELVADDR) << CRINFO_RELVADDR_SH)); + bfd_h_put_32 (abfd, (bfd_vma) l, ex->info); + bfd_h_put_32 (abfd, (bfd_vma) in->konst, ex->konst); + bfd_h_put_32 (abfd, (bfd_vma) in->vaddr, ex->vaddr); +} + +/* Determine whether a symbol is global for the purposes of splitting + the symbol table into global symbols and local symbols. At least + on Irix 5, this split must be between section symbols and all other + symbols. On most ELF targets the split is between static symbols + and externally visible symbols. */ + +/*ARGSUSED*/ +static boolean +mips_elf_sym_is_global (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false; +} + +/* Set the right machine number for a MIPS ELF file. */ + +static boolean +mips_elf_object_p (abfd) + bfd *abfd; +{ + switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) + { + default: + case E_MIPS_ARCH_1: + /* Just use the default, which was set in elfcode.h. */ + break; + + case E_MIPS_ARCH_2: + (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 6000); + break; + + case E_MIPS_ARCH_3: + (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 4000); + break; + } + + /* Irix 5 is broken. Object file symbol tables are not always + sorted correctly such that local symbols precede global symbols, + and the sh_info field in the symbol table is not always right. */ + elf_bad_symtab (abfd) = true; + + return true; +} + +/* The final processing done just before writing out a MIPS ELF object + file. This gets the MIPS architecture right based on the machine + number. */ + +/*ARGSUSED*/ +static void +mips_elf_final_write_processing (abfd, linker) + bfd *abfd; + boolean linker; +{ + unsigned long val; + unsigned int i; + Elf_Internal_Shdr **hdrpp; + + switch (bfd_get_mach (abfd)) + { + case 3000: + val = E_MIPS_ARCH_1; + break; + + case 6000: + val = E_MIPS_ARCH_2; + break; + + case 4000: + val = E_MIPS_ARCH_3; + break; + + default: + val = 0; + break; + } + + elf_elfheader (abfd)->e_flags &=~ EF_MIPS_ARCH; + elf_elfheader (abfd)->e_flags |= val; + + /* Set the sh_info field for .gptab sections. */ + for (i = 1, hdrpp = elf_elfsections (abfd) + 1; + i < elf_elfheader (abfd)->e_shnum; + i++, hdrpp++) + { + if ((*hdrpp)->sh_type == SHT_MIPS_GPTAB) + { + const char *name; + asection *sec; + + BFD_ASSERT ((*hdrpp)->bfd_section != NULL); + name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section); + BFD_ASSERT (name != NULL + && strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0); + sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1); + BFD_ASSERT (sec != NULL); + (*hdrpp)->sh_info = elf_section_data (sec)->this_idx; + } + } +} + +/* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */ + +static boolean +mips_elf_set_private_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + BFD_ASSERT (!elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = true; + return true; +} + +/* Copy backend specific data from one object module to another */ + +static boolean +mips_elf_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + BFD_ASSERT (!elf_flags_init (obfd) + || (elf_elfheader (obfd)->e_flags + == elf_elfheader (ibfd)->e_flags)); + + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_flags_init (obfd) = true; + return true; +} + +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static boolean +mips_elf_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + flagword old_flags; + flagword new_flags; + + /* Check if we have the same endianess */ + if (ibfd->xvec->byteorder != obfd->xvec->byteorder + && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) + { + (*_bfd_error_handler) + ("%s: compiled for a %s endian system and target is %s endian", + bfd_get_filename (ibfd), + bfd_big_endian (ibfd) ? "big" : "little", + bfd_big_endian (obfd) ? "big" : "little"); + + bfd_set_error (bfd_error_wrong_format); + return false; + } + + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + new_flags = elf_elfheader (ibfd)->e_flags; + elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; + old_flags = elf_elfheader (obfd)->e_flags; + + if (!elf_flags_init (obfd)) /* First call, no flags set */ + { + elf_flags_init (obfd) = true; + elf_elfheader (obfd)->e_flags = new_flags; + } + else if (((new_flags ^ old_flags) & ~EF_MIPS_NOREORDER) + == 0) /* Compatible flags are ok */ + ; + else /* Incompatible flags */ + { + /* Warn about -fPIC mismatch */ + if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC)) + { + new_flags &= ~EF_MIPS_PIC; + (*_bfd_error_handler) + ("%s: needs all files compiled with -fPIC", + bfd_get_filename (ibfd)); + } + + if ((new_flags & EF_MIPS_CPIC) != (old_flags & EF_MIPS_CPIC)) + { + new_flags &= ~EF_MIPS_CPIC; + (*_bfd_error_handler) + ("%s: needs all files compiled with -mabicalls", + bfd_get_filename (ibfd)); + } + + /* Warn about any other mismatches */ + if (new_flags != old_flags) + (*_bfd_error_handler) + ("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)", + bfd_get_filename (ibfd), (unsigned long) new_flags, + (unsigned long) old_flags); + + bfd_set_error (bfd_error_bad_value); + return false; + } + + return true; +} + +/* Handle a MIPS specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. + FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure + how to. */ + +static boolean +mips_elf_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf32_Internal_Shdr *hdr; + char *name; +{ + asection *newsect; + + /* There ought to be a place to keep ELF backend specific flags, but + at the moment there isn't one. We just keep track of the + sections by their name, instead. Fortunately, the ABI gives + suggested names for all the MIPS specific sections, so we will + probably get away with this. */ + switch (hdr->sh_type) + { + case SHT_MIPS_LIBLIST: + if (strcmp (name, ".liblist") != 0) + return false; + break; + case SHT_MIPS_MSYM: + if (strcmp (name, ".msym") != 0) + return false; + break; + case SHT_MIPS_CONFLICT: + if (strcmp (name, ".conflict") != 0) + return false; + break; + case SHT_MIPS_GPTAB: + if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) != 0) + return false; + break; + case SHT_MIPS_UCODE: + if (strcmp (name, ".ucode") != 0) + return false; + break; + case SHT_MIPS_DEBUG: + if (strcmp (name, ".mdebug") != 0) + return false; + break; + case SHT_MIPS_REGINFO: + if (strcmp (name, ".reginfo") != 0 + || hdr->sh_size != sizeof (Elf32_External_RegInfo)) + return false; + break; + case SHT_MIPS_OPTIONS: + if (strcmp (name, ".options") != 0) + return false; + break; + case SHT_MIPS_DWARF: + if (strncmp (name, ".debug_", sizeof ".debug_" - 1) != 0) + return false; + break; + case SHT_MIPS_EVENTS: + if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) != 0) + return false; + break; + default: + return false; + } + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + newsect = hdr->bfd_section; + + if (hdr->sh_type == SHT_MIPS_DEBUG) + { + if (! bfd_set_section_flags (abfd, newsect, + (bfd_get_section_flags (abfd, newsect) + | SEC_DEBUGGING))) + return false; + } + + /* FIXME: We should record sh_info for a .gptab section. */ + + /* For a .reginfo section, set the gp value in the tdata information + from the contents of this section. We need the gp value while + processing relocs, so we just get it now. */ + if (hdr->sh_type == SHT_MIPS_REGINFO) + { + Elf32_External_RegInfo ext; + Elf32_RegInfo s; + + if (! bfd_get_section_contents (abfd, newsect, (PTR) &ext, + (file_ptr) 0, sizeof ext)) + return false; + bfd_mips_elf32_swap_reginfo_in (abfd, &ext, &s); + elf_gp (abfd) = s.ri_gp_value; + } + + return true; +} + +/* Set the correct type for a MIPS ELF section. We do this by the + section name, which is a hack, but ought to work. */ + +static boolean +mips_elf_fake_sections (abfd, hdr, sec) + bfd *abfd; + Elf32_Internal_Shdr *hdr; + asection *sec; +{ + register const char *name; + + name = bfd_get_section_name (abfd, sec); + + if (strcmp (name, ".liblist") == 0) + { + hdr->sh_type = SHT_MIPS_LIBLIST; + hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib); + /* FIXME: Set the sh_link field. */ + } + else if (strcmp (name, ".msym") == 0) + { + hdr->sh_type = SHT_MIPS_MSYM; + hdr->sh_entsize = 8; + /* FIXME: Set the sh_info field. */ + } + else if (strcmp (name, ".conflict") == 0) + hdr->sh_type = SHT_MIPS_CONFLICT; + else if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0) + { + hdr->sh_type = SHT_MIPS_GPTAB; + hdr->sh_entsize = sizeof (Elf32_External_gptab); + /* The sh_info field is set in mips_elf_final_write_processing. */ + } + else if (strcmp (name, ".ucode") == 0) + hdr->sh_type = SHT_MIPS_UCODE; + else if (strcmp (name, ".mdebug") == 0) + { + hdr->sh_type = SHT_MIPS_DEBUG; + /* In a shared object on Irix 5.3, the .mdebug section has an + entsize of 0. FIXME: Does this matter? */ + if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0) + hdr->sh_entsize = 0; + else + hdr->sh_entsize = 1; + } + else if (strcmp (name, ".reginfo") == 0) + { + hdr->sh_type = SHT_MIPS_REGINFO; + /* In a shared object on Irix 5.3, the .reginfo section has an + entsize of 0x18. FIXME: Does this matter? */ + if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0) + hdr->sh_entsize = sizeof (Elf32_External_RegInfo); + else + hdr->sh_entsize = 1; + + /* Force the section size to the correct value, even if the + linker thinks it is larger. The link routine below will only + write out this much data for .reginfo. */ + hdr->sh_size = sec->_raw_size = sizeof (Elf32_External_RegInfo); + } + else if (SGI_COMPAT (abfd) + && (strcmp (name, ".hash") == 0 + || strcmp (name, ".dynamic") == 0 + || strcmp (name, ".dynstr") == 0)) + { + hdr->sh_entsize = 0; + hdr->sh_info = SIZEOF_MIPS_DYNSYM_SECNAMES; + } + else if (strcmp (name, ".got") == 0 + || strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0 + || strcmp (name, ".lit4") == 0 + || strcmp (name, ".lit8") == 0) + hdr->sh_flags |= SHF_MIPS_GPREL; + else if (strcmp (name, ".options") == 0) + { + hdr->sh_type = SHT_MIPS_OPTIONS; + hdr->sh_entsize = 1; + } + else if (strncmp (name, ".debug_", sizeof ".debug_" - 1) == 0) + hdr->sh_type = SHT_MIPS_DWARF; + else if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) == 0) + hdr->sh_type = SHT_MIPS_EVENTS; + + return true; +} + +/* Given a BFD section, try to locate the corresponding ELF section + index. */ + +static boolean +mips_elf_section_from_bfd_section (abfd, hdr, sec, retval) + bfd *abfd; + Elf32_Internal_Shdr *hdr; + asection *sec; + int *retval; +{ + if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) + { + *retval = SHN_MIPS_SCOMMON; + return true; + } + if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0) + { + *retval = SHN_MIPS_ACOMMON; + return true; + } + return false; +} + +/* Work over a section just before writing it out. We update the GP + value in the .reginfo section based on the value we are using. + FIXME: We recognize sections that need the SHF_MIPS_GPREL flag by + name; there has to be a better way. */ + +static boolean +mips_elf_section_processing (abfd, hdr) + bfd *abfd; + Elf32_Internal_Shdr *hdr; +{ + if (hdr->sh_type == SHT_MIPS_REGINFO) + { + bfd_byte buf[4]; + + BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo)); + BFD_ASSERT (hdr->contents == NULL); + + if (bfd_seek (abfd, + hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4, + SEEK_SET) == -1) + return false; + bfd_h_put_32 (abfd, (bfd_vma) elf_gp (abfd), buf); + if (bfd_write (buf, (bfd_size_type) 1, (bfd_size_type) 4, abfd) != 4) + return false; + } + + if (hdr->bfd_section != NULL) + { + const char *name = bfd_get_section_name (abfd, hdr->bfd_section); + + if (strcmp (name, ".sdata") == 0) + { + hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; + hdr->sh_type = SHT_PROGBITS; + } + else if (strcmp (name, ".sbss") == 0) + { + hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; + hdr->sh_type = SHT_NOBITS; + } + else if (strcmp (name, ".lit8") == 0 + || strcmp (name, ".lit4") == 0) + { + hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL; + hdr->sh_type = SHT_PROGBITS; + } + else if (strcmp (name, ".compact_rel") == 0) + { + hdr->sh_flags = 0; + hdr->sh_type = SHT_PROGBITS; + } + else if (strcmp (name, ".rtproc") == 0) + { + if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0) + { + unsigned int adjust; + + adjust = hdr->sh_size % hdr->sh_addralign; + if (adjust != 0) + hdr->sh_size += hdr->sh_addralign - adjust; + } + } + } + + return true; +} + +/* MIPS ELF uses two common sections. One is the usual one, and the + other is for small objects. All the small objects are kept + together, and then referenced via the gp pointer, which yields + faster assembler code. This is what we use for the small common + section. This approach is copied from ecoff.c. */ +static asection mips_elf_scom_section; +static asymbol mips_elf_scom_symbol; +static asymbol *mips_elf_scom_symbol_ptr; + +/* MIPS ELF also uses an acommon section, which represents an + allocated common symbol which may be overridden by a + definition in a shared library. */ +static asection mips_elf_acom_section; +static asymbol mips_elf_acom_symbol; +static asymbol *mips_elf_acom_symbol_ptr; + +/* The Irix 5 support uses two virtual sections, which represent + text/data symbols defined in dynamic objects. */ +static asection mips_elf_text_section; +static asection *mips_elf_text_section_ptr; +static asymbol mips_elf_text_symbol; +static asymbol *mips_elf_text_symbol_ptr; + +static asection mips_elf_data_section; +static asection *mips_elf_data_section_ptr; +static asymbol mips_elf_data_symbol; +static asymbol *mips_elf_data_symbol_ptr; + +/* Handle the special MIPS section numbers that a symbol may use. */ + +static void +mips_elf_symbol_processing (abfd, asym) + bfd *abfd; + asymbol *asym; +{ + elf_symbol_type *elfsym; + + elfsym = (elf_symbol_type *) asym; + switch (elfsym->internal_elf_sym.st_shndx) + { + case SHN_MIPS_ACOMMON: + /* This section is used in a dynamically linked executable file. + It is an allocated common section. The dynamic linker can + either resolve these symbols to something in a shared + library, or it can just leave them here. For our purposes, + we can consider these symbols to be in a new section. */ + if (mips_elf_acom_section.name == NULL) + { + /* Initialize the acommon section. */ + mips_elf_acom_section.name = ".acommon"; + mips_elf_acom_section.flags = SEC_ALLOC; + mips_elf_acom_section.output_section = &mips_elf_acom_section; + mips_elf_acom_section.symbol = &mips_elf_acom_symbol; + mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr; + mips_elf_acom_symbol.name = ".acommon"; + mips_elf_acom_symbol.flags = BSF_SECTION_SYM; + mips_elf_acom_symbol.section = &mips_elf_acom_section; + mips_elf_acom_symbol_ptr = &mips_elf_acom_symbol; + } + asym->section = &mips_elf_acom_section; + break; + + case SHN_COMMON: + /* Common symbols less than the GP size are automatically + treated as SHN_MIPS_SCOMMON symbols. */ + if (asym->value > elf_gp_size (abfd)) + break; + /* Fall through. */ + case SHN_MIPS_SCOMMON: + if (mips_elf_scom_section.name == NULL) + { + /* Initialize the small common section. */ + mips_elf_scom_section.name = ".scommon"; + mips_elf_scom_section.flags = SEC_IS_COMMON; + mips_elf_scom_section.output_section = &mips_elf_scom_section; + mips_elf_scom_section.symbol = &mips_elf_scom_symbol; + mips_elf_scom_section.symbol_ptr_ptr = &mips_elf_scom_symbol_ptr; + mips_elf_scom_symbol.name = ".scommon"; + mips_elf_scom_symbol.flags = BSF_SECTION_SYM; + mips_elf_scom_symbol.section = &mips_elf_scom_section; + mips_elf_scom_symbol_ptr = &mips_elf_scom_symbol; + } + asym->section = &mips_elf_scom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + + case SHN_MIPS_SUNDEFINED: + asym->section = bfd_und_section_ptr; + break; + +#if 0 /* for SGI_COMPAT */ + case SHN_MIPS_TEXT: + asym->section = mips_elf_text_section_ptr; + break; + + case SHN_MIPS_DATA: + asym->section = mips_elf_data_section_ptr; + break; +#endif + } +} + +/* When creating an Irix 5 executable, we need REGINFO and RTPROC + segments. */ + +static int +mips_elf_additional_program_headers (abfd) + bfd *abfd; +{ + asection *s; + int ret; + + ret = 0; + + if (! SGI_COMPAT (abfd)) + return ret; + + s = bfd_get_section_by_name (abfd, ".reginfo"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + /* We need a PT_MIPS_REGINFO segment. */ + ++ret; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL + && bfd_get_section_by_name (abfd, ".mdebug") != NULL) + { + /* We need a PT_MIPS_RTPROC segment. */ + ++ret; + } + + return ret; +} + +/* Modify the segment map for an Irix 5 executable. */ + +static boolean +mips_elf_modify_segment_map (abfd) + bfd *abfd; +{ + asection *s; + struct elf_segment_map *m, **pm; + + if (! SGI_COMPAT (abfd)) + return true; + + /* If there is a .reginfo section, we need a PT_MIPS_REGINFO + segment. */ + s = bfd_get_section_by_name (abfd, ".reginfo"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + if (m->p_type == PT_MIPS_REGINFO) + break; + if (m == NULL) + { + m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m); + if (m == NULL) + return false; + + m->p_type = PT_MIPS_REGINFO; + m->count = 1; + m->sections[0] = s; + + /* We want to put it after the PHDR and INTERP segments. */ + pm = &elf_tdata (abfd)->segment_map; + while (*pm != NULL + && ((*pm)->p_type == PT_PHDR + || (*pm)->p_type == PT_INTERP)) + pm = &(*pm)->next; + + m->next = *pm; + *pm = m; + } + } + + /* If there are .dynamic and .mdebug sections, we make a room for + the RTPROC header. FIXME: Rewrite without section names. */ + if (bfd_get_section_by_name (abfd, ".interp") == NULL + && bfd_get_section_by_name (abfd, ".dynamic") != NULL + && bfd_get_section_by_name (abfd, ".mdebug") != NULL) + { + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + if (m->p_type == PT_MIPS_RTPROC) + break; + if (m == NULL) + { + m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m); + if (m == NULL) + return false; + + m->p_type = PT_MIPS_RTPROC; + + s = bfd_get_section_by_name (abfd, ".rtproc"); + if (s == NULL) + { + m->count = 0; + m->p_flags = 0; + m->p_flags_valid = 1; + } + else + { + m->count = 1; + m->sections[0] = s; + } + + /* We want to put it after the DYNAMIC segment. */ + pm = &elf_tdata (abfd)->segment_map; + while (*pm != NULL && (*pm)->p_type != PT_DYNAMIC) + pm = &(*pm)->next; + if (*pm != NULL) + pm = &(*pm)->next; + + m->next = *pm; + *pm = m; + } + } + + /* On Irix 5, the PT_DYNAMIC segment includes the .dynamic, .dynstr, + .dynsym, and .hash sections, and everything in between. */ + for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + if ((*pm)->p_type == PT_DYNAMIC) + break; + m = *pm; + if (m != NULL + && m->count == 1 + && strcmp (m->sections[0]->name, ".dynamic") == 0) + { + static const char *sec_names[] = + { ".dynamic", ".dynstr", ".dynsym", ".hash" }; + bfd_vma low, high; + unsigned int i, c; + struct elf_segment_map *n; + + low = 0xffffffff; + high = 0; + for (i = 0; i < sizeof sec_names / sizeof sec_names[0]; i++) + { + s = bfd_get_section_by_name (abfd, sec_names[i]); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + bfd_size_type sz; + + if (low > s->vma) + low = s->vma; + sz = s->_cooked_size; + if (sz == 0) + sz = s->_raw_size; + if (high < s->vma + sz) + high = s->vma + sz; + } + } + + c = 0; + for (s = abfd->sections; s != NULL; s = s->next) + if ((s->flags & SEC_LOAD) != 0 + && s->vma >= low + && ((s->vma + + (s->_cooked_size != 0 ? s->_cooked_size : s->_raw_size)) + <= high)) + ++c; + + n = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof *n + (c - 1) * sizeof (asection *))); + if (n == NULL) + return false; + *n = *m; + n->count = c; + + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && s->vma >= low + && ((s->vma + + (s->_cooked_size != 0 ? s->_cooked_size : s->_raw_size)) + <= high)) + { + n->sections[i] = s; + ++i; + } + } + + *pm = n; + } + + return true; +} + +/* The structure of the runtime procedure descriptor created by the + loader for use by the static exception system. */ + +typedef struct runtime_pdr { + bfd_vma adr; /* memory address of start of procedure */ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long irpss; /* index into the runtime string table */ + long reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) + +/* Swap RPDR (runtime procedure table entry) for output. */ + +static void ecoff_swap_rpdr_out + PARAMS ((bfd *, const RPDR *, struct rpdr_ext *)); + +static void +ecoff_swap_rpdr_out (abfd, in, ex) + bfd *abfd; + const RPDR *in; + struct rpdr_ext *ex; +{ + /* ecoff_put_off was defined in ecoffswap.h. */ + ecoff_put_off (abfd, in->adr, (bfd_byte *) ex->p_adr); + bfd_h_put_32 (abfd, in->regmask, (bfd_byte *) ex->p_regmask); + bfd_h_put_32 (abfd, in->regoffset, (bfd_byte *) ex->p_regoffset); + bfd_h_put_32 (abfd, in->fregmask, (bfd_byte *) ex->p_fregmask); + bfd_h_put_32 (abfd, in->fregoffset, (bfd_byte *) ex->p_fregoffset); + bfd_h_put_32 (abfd, in->frameoffset, (bfd_byte *) ex->p_frameoffset); + + bfd_h_put_16 (abfd, in->framereg, (bfd_byte *) ex->p_framereg); + bfd_h_put_16 (abfd, in->pcreg, (bfd_byte *) ex->p_pcreg); + + bfd_h_put_32 (abfd, in->irpss, (bfd_byte *) ex->p_irpss); +#if 0 /* FIXME */ + ecoff_put_off (abfd, in->exception_info, (bfd_byte *) ex->p_exception_info); +#endif +} + +/* Read ECOFF debugging information from a .mdebug section into a + ecoff_debug_info structure. */ + +static boolean +mips_elf_read_ecoff_info (abfd, section, debug) + bfd *abfd; + asection *section; + struct ecoff_debug_info *debug; +{ + HDRR *symhdr; + const struct ecoff_debug_swap *swap; + char *ext_hdr = NULL; + + swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + + ext_hdr = (char *) bfd_malloc ((size_t) swap->external_hdr_size); + if (ext_hdr == NULL && swap->external_hdr_size != 0) + goto error_return; + + if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0, + swap->external_hdr_size) + == false) + goto error_return; + + symhdr = &debug->symbolic_header; + (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr); + + /* The symbolic header contains absolute file offsets and sizes to + read. */ +#define READ(ptr, offset, count, size, type) \ + if (symhdr->count == 0) \ + debug->ptr = NULL; \ + else \ + { \ + debug->ptr = (type) bfd_malloc ((size_t) (size * symhdr->count)); \ + if (debug->ptr == NULL) \ + goto error_return; \ + if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ + || (bfd_read (debug->ptr, size, symhdr->count, \ + abfd) != size * symhdr->count)) \ + goto error_return; \ + } + + READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), + union aux_ext *); + READ (ss, cbSsOffset, issMax, sizeof (char), char *); + READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); + READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR); +#undef READ + + debug->fdr = NULL; + debug->adjust = NULL; + + return true; + + error_return: + if (ext_hdr != NULL) + free (ext_hdr); + if (debug->line != NULL) + free (debug->line); + if (debug->external_dnr != NULL) + free (debug->external_dnr); + if (debug->external_pdr != NULL) + free (debug->external_pdr); + if (debug->external_sym != NULL) + free (debug->external_sym); + if (debug->external_opt != NULL) + free (debug->external_opt); + if (debug->external_aux != NULL) + free (debug->external_aux); + if (debug->ss != NULL) + free (debug->ss); + if (debug->ssext != NULL) + free (debug->ssext); + if (debug->external_fdr != NULL) + free (debug->external_fdr); + if (debug->external_rfd != NULL) + free (debug->external_rfd); + if (debug->external_ext != NULL) + free (debug->external_ext); + return false; +} + +/* MIPS ELF local labels start with '$', not 'L'. */ + +/*ARGSUSED*/ +static boolean +mips_elf_is_local_label (abfd, symbol) + bfd *abfd; + asymbol *symbol; +{ + return symbol->name[0] == '$'; +} + +/* MIPS ELF uses a special find_nearest_line routine in order the + handle the ECOFF debugging information. */ + +struct mips_elf_find_line +{ + struct ecoff_debug_info d; + struct ecoff_find_line i; +}; + +static boolean +mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *line_ptr; +{ + asection *msec; + + msec = bfd_get_section_by_name (abfd, ".mdebug"); + if (msec != NULL) + { + flagword origflags; + struct mips_elf_find_line *fi; + const struct ecoff_debug_swap * const swap = + get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + + /* If we are called during a link, mips_elf_final_link may have + cleared the SEC_HAS_CONTENTS field. We force it back on here + if appropriate (which it normally will be). */ + origflags = msec->flags; + if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS) + msec->flags |= SEC_HAS_CONTENTS; + + fi = elf_tdata (abfd)->find_line_info; + if (fi == NULL) + { + bfd_size_type external_fdr_size; + char *fraw_src; + char *fraw_end; + struct fdr *fdr_ptr; + + fi = ((struct mips_elf_find_line *) + bfd_alloc (abfd, sizeof (struct mips_elf_find_line))); + if (fi == NULL) + { + msec->flags = origflags; + return false; + } + + memset (fi, 0, sizeof (struct mips_elf_find_line)); + + if (! mips_elf_read_ecoff_info (abfd, msec, &fi->d)) + { + msec->flags = origflags; + return false; + } + + /* Swap in the FDR information. */ + fi->d.fdr = ((struct fdr *) + bfd_alloc (abfd, + (fi->d.symbolic_header.ifdMax * + sizeof (struct fdr)))); + if (fi->d.fdr == NULL) + { + msec->flags = origflags; + return false; + } + external_fdr_size = swap->external_fdr_size; + fdr_ptr = fi->d.fdr; + fraw_src = (char *) fi->d.external_fdr; + fraw_end = (fraw_src + + fi->d.symbolic_header.ifdMax * external_fdr_size); + for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) + (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + + elf_tdata (abfd)->find_line_info = fi; + + /* Note that we don't bother to ever free this information. + find_nearest_line is either called all the time, as in + objdump -l, so the information should be saved, or it is + rarely called, as in ld error messages, so the memory + wasted is unimportant. Still, it would probably be a + good idea for free_cached_info to throw it away. */ + } + + if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap, + &fi->i, filename_ptr, functionname_ptr, + line_ptr)) + { + msec->flags = origflags; + return true; + } + + msec->flags = origflags; + } + + /* Fall back on the generic ELF find_nearest_line routine. */ + + return _bfd_elf_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr); +} + +/* The MIPS ELF linker needs additional information for each symbol in + the global hash table. */ + +struct mips_elf_link_hash_entry +{ + struct elf_link_hash_entry root; + + /* External symbol information. */ + EXTR esym; +}; + +/* MIPS ELF linker hash table. */ + +struct mips_elf_link_hash_table +{ + struct elf_link_hash_table root; + /* String section indices for the dynamic section symbols. */ + bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES]; + /* The number of .rtproc entries. */ + bfd_size_type procedure_count; + /* The size of the .compact_rel section (if SGI_COMPAT). */ + bfd_size_type compact_rel_size; +}; + +/* Look up an entry in a MIPS ELF linker hash table. */ + +#define mips_elf_link_hash_lookup(table, string, create, copy, follow) \ + ((struct mips_elf_link_hash_entry *) \ + elf_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse a MIPS ELF linker hash table. */ + +#define mips_elf_link_hash_traverse(table, func, info) \ + (elf_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the MIPS ELF linker hash table from a link_info structure. */ + +#define mips_elf_hash_table(p) \ + ((struct mips_elf_link_hash_table *) ((p)->hash)) + +static boolean mips_elf_output_extsym + PARAMS ((struct mips_elf_link_hash_entry *, PTR)); + +/* Create an entry in a MIPS ELF linker hash table. */ + +static struct bfd_hash_entry * +mips_elf_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct mips_elf_link_hash_entry *ret = + (struct mips_elf_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct mips_elf_link_hash_entry *) NULL) + ret = ((struct mips_elf_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct mips_elf_link_hash_entry))); + if (ret == (struct mips_elf_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct mips_elf_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct mips_elf_link_hash_entry *) NULL) + { + /* Set local fields. */ + memset (&ret->esym, 0, sizeof (EXTR)); + /* We use -2 as a marker to indicate that the information has + not been set. -1 means there is no associated ifd. */ + ret->esym.ifd = -2; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a MIPS ELF linker hash table. */ + +static struct bfd_link_hash_table * +mips_elf_link_hash_table_create (abfd) + bfd *abfd; +{ + struct mips_elf_link_hash_table *ret; + unsigned int i; + + ret = ((struct mips_elf_link_hash_table *) + bfd_alloc (abfd, sizeof (struct mips_elf_link_hash_table))); + if (ret == (struct mips_elf_link_hash_table *) NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, + mips_elf_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } + + for (i = 0; i < SIZEOF_MIPS_DYNSYM_SECNAMES; i++) + ret->dynsym_sec_strindex[i] = (bfd_size_type) -1; + ret->procedure_count = 0; + ret->compact_rel_size = 0; + + return &ret->root.root; +} + +/* Hook called by the linker routine which adds symbols from an object + file. We must handle the special MIPS section numbers here. */ + +/*ARGSUSED*/ +static boolean +mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp; + asection **secp; + bfd_vma *valp; +{ + if (SGI_COMPAT (abfd) + && (abfd->flags & DYNAMIC) != 0 + && strcmp (*namep, "_rld_new_interface") == 0) + { + /* Skip Irix 5 rld entry name. */ + *namep = NULL; + return true; + } + + switch (sym->st_shndx) + { + case SHN_COMMON: + /* Common symbols less than the GP size are automatically + treated as SHN_MIPS_SCOMMON symbols. */ + if (sym->st_size > elf_gp_size (abfd)) + break; + /* Fall through. */ + case SHN_MIPS_SCOMMON: + *secp = bfd_make_section_old_way (abfd, ".scommon"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + + case SHN_MIPS_TEXT: + /* This section is used in a shared object. */ + if (mips_elf_text_section_ptr == NULL) + { + /* Initialize the section. */ + mips_elf_text_section.name = ".text"; + mips_elf_text_section.flags = SEC_NO_FLAGS; + mips_elf_text_section.output_section = NULL; + mips_elf_text_section.owner = abfd; + mips_elf_text_section.symbol = &mips_elf_text_symbol; + mips_elf_text_section.symbol_ptr_ptr = &mips_elf_text_symbol_ptr; + mips_elf_text_symbol.name = ".text"; + mips_elf_text_symbol.flags = BSF_SECTION_SYM; + mips_elf_text_symbol.section = &mips_elf_text_section; + mips_elf_text_symbol_ptr = &mips_elf_text_symbol; + mips_elf_text_section_ptr = &mips_elf_text_section; + } + if (info->shared) + *secp = bfd_und_section_ptr; + else + *secp = mips_elf_text_section_ptr; + break; + + case SHN_MIPS_ACOMMON: + /* Fall through. XXX Can we treat this as allocated data? */ + case SHN_MIPS_DATA: + /* This section is used in a shared object. */ + if (mips_elf_data_section_ptr == NULL) + { + /* Initialize the section. */ + mips_elf_data_section.name = ".data"; + mips_elf_data_section.flags = SEC_NO_FLAGS; + mips_elf_data_section.output_section = NULL; + mips_elf_data_section.owner = abfd; + mips_elf_data_section.symbol = &mips_elf_data_symbol; + mips_elf_data_section.symbol_ptr_ptr = &mips_elf_data_symbol_ptr; + mips_elf_data_symbol.name = ".data"; + mips_elf_data_symbol.flags = BSF_SECTION_SYM; + mips_elf_data_symbol.section = &mips_elf_data_section; + mips_elf_data_symbol_ptr = &mips_elf_data_symbol; + mips_elf_data_section_ptr = &mips_elf_data_section; + } + if (info->shared) + *secp = bfd_und_section_ptr; + else + *secp = mips_elf_data_section_ptr; + break; + + case SHN_MIPS_SUNDEFINED: + *secp = bfd_und_section_ptr; + break; + } + + return true; +} + +/* Structure used to pass information to mips_elf_output_extsym. */ + +struct extsym_info +{ + bfd *abfd; + struct bfd_link_info *info; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + boolean failed; +}; + +/* This routine is used to write out ECOFF debugging external symbol + information. It is called via mips_elf_link_hash_traverse. The + ECOFF external symbol information must match the ELF external + symbol information. Unfortunately, at this point we don't know + whether a symbol is required by reloc information, so the two + tables may wind up being different. We must sort out the external + symbol information before we can set the final size of the .mdebug + section, and we must set the size of the .mdebug section before we + can relocate any sections, and we can't know which symbols are + required by relocation until we relocate the sections. + Fortunately, it is relatively unlikely that any symbol will be + stripped but required by a reloc. In particular, it can not happen + when generating a final executable. */ + +static boolean +mips_elf_output_extsym (h, data) + struct mips_elf_link_hash_entry *h; + PTR data; +{ + struct extsym_info *einfo = (struct extsym_info *) data; + boolean strip; + asection *sec, *output_section; + + if (h->root.indx == -2) + strip = false; + else if (((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + strip = true; + else if (einfo->info->strip == strip_all + || (einfo->info->strip == strip_some + && bfd_hash_lookup (einfo->info->keep_hash, + h->root.root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + if (strip) + return true; + + if (h->esym.ifd == -2) + { + h->esym.jmptbl = 0; + h->esym.cobol_main = 0; + h->esym.weakext = 0; + h->esym.reserved = 0; + h->esym.ifd = ifdNil; + h->esym.asym.value = 0; + h->esym.asym.st = stGlobal; + + if (SGI_COMPAT (einfo->abfd) + && (h->root.root.type == bfd_link_hash_undefined + || h->root.root.type == bfd_link_hash_undefweak)) + { + const char *name; + + /* Use undefined class. Also, set class and type for some + special symbols. */ + name = h->root.root.root.string; + if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0 + || strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0) + { + h->esym.asym.sc = scData; + h->esym.asym.st = stLabel; + h->esym.asym.value = 0; + } + else if (strcmp (name, mips_elf_dynsym_rtproc_names[2]) == 0) + { + h->esym.asym.sc = scAbs; + h->esym.asym.st = stLabel; + h->esym.asym.value = + mips_elf_hash_table (einfo->info)->procedure_count; + } + else if (strcmp (name, "_gp_disp") == 0) + { + h->esym.asym.sc = scAbs; + h->esym.asym.st = stLabel; + h->esym.asym.value = elf_gp (einfo->abfd); + } + else + h->esym.asym.sc = scUndefined; + } + else if (h->root.root.type != bfd_link_hash_defined + && h->root.root.type != bfd_link_hash_defweak) + h->esym.asym.sc = scAbs; + else + { + const char *name; + + sec = h->root.root.u.def.section; + output_section = sec->output_section; + + /* When making a shared library and symbol h is the one from + the another shared library, OUTPUT_SECTION may be null. */ + if (output_section == NULL) + h->esym.asym.sc = scUndefined; + else + { + name = bfd_section_name (output_section->owner, output_section); + + if (strcmp (name, ".text") == 0) + h->esym.asym.sc = scText; + else if (strcmp (name, ".data") == 0) + h->esym.asym.sc = scData; + else if (strcmp (name, ".sdata") == 0) + h->esym.asym.sc = scSData; + else if (strcmp (name, ".rodata") == 0 + || strcmp (name, ".rdata") == 0) + h->esym.asym.sc = scRData; + else if (strcmp (name, ".bss") == 0) + h->esym.asym.sc = scBss; + else if (strcmp (name, ".sbss") == 0) + h->esym.asym.sc = scSBss; + else if (strcmp (name, ".init") == 0) + h->esym.asym.sc = scInit; + else if (strcmp (name, ".fini") == 0) + h->esym.asym.sc = scFini; + else + h->esym.asym.sc = scAbs; + } + } + + h->esym.asym.reserved = 0; + h->esym.asym.index = indexNil; + } + + if (h->root.root.type == bfd_link_hash_common) + h->esym.asym.value = h->root.root.u.c.size; + else if (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + { + if (h->esym.asym.sc == scCommon) + h->esym.asym.sc = scBss; + else if (h->esym.asym.sc == scSCommon) + h->esym.asym.sc = scSBss; + + sec = h->root.root.u.def.section; + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (h->root.root.u.def.value + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } + else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + /* Set type and value for a symbol with a function stub. */ + h->esym.asym.st = stProc; + sec = h->root.root.u.def.section; + if (sec == NULL) + h->esym.asym.value = 0; + else + { + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (h->root.plt_offset + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } +#if 0 /* FIXME? */ + h->esym.ifd = 0; +#endif + } + + if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, + h->root.root.root.string, + &h->esym)) + { + einfo->failed = true; + return false; + } + + return true; +} + +/* Create a runtime procedure table from the .mdebug section. */ + +static boolean +mips_elf_create_procedure_table (handle, abfd, info, s, debug) + PTR handle; + bfd *abfd; + struct bfd_link_info *info; + asection *s; + struct ecoff_debug_info *debug; +{ + const struct ecoff_debug_swap *swap; + HDRR *hdr = &debug->symbolic_header; + RPDR *rpdr, *rp; + struct rpdr_ext *erp; + PTR rtproc; + struct pdr_ext *epdr; + struct sym_ext *esym; + char *ss, **sv; + char *str; + unsigned long size, count; + unsigned long sindex; + unsigned long i; + PDR pdr; + SYMR sym; + const char *no_name_func = "static procedure (no name)"; + + epdr = NULL; + rpdr = NULL; + esym = NULL; + ss = NULL; + sv = NULL; + + swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + + sindex = strlen (no_name_func) + 1; + count = hdr->ipdMax; + if (count > 0) + { + size = swap->external_pdr_size; + + epdr = (struct pdr_ext *) bfd_malloc (size * count); + if (epdr == NULL) + goto error_return; + + if (! _bfd_ecoff_get_accumulated_pdr (handle, (PTR) epdr)) + goto error_return; + + size = sizeof (RPDR); + rp = rpdr = (RPDR *) bfd_malloc (size * count); + if (rpdr == NULL) + goto error_return; + + sv = (char **) bfd_malloc (sizeof (char *) * count); + if (sv == NULL) + goto error_return; + + count = hdr->isymMax; + size = swap->external_sym_size; + esym = (struct sym_ext *) bfd_malloc (size * count); + if (esym == NULL) + goto error_return; + + if (! _bfd_ecoff_get_accumulated_sym (handle, (PTR) esym)) + goto error_return; + + count = hdr->issMax; + ss = (char *) bfd_malloc (count); + if (ss == NULL) + goto error_return; + if (! _bfd_ecoff_get_accumulated_ss (handle, (PTR) ss)) + goto error_return; + + count = hdr->ipdMax; + for (i = 0; i < count; i++, rp++) + { + (*swap->swap_pdr_in) (abfd, (PTR) (epdr + i), &pdr); + (*swap->swap_sym_in) (abfd, (PTR) &esym[pdr.isym], &sym); + rp->adr = sym.value; + rp->regmask = pdr.regmask; + rp->regoffset = pdr.regoffset; + rp->fregmask = pdr.fregmask; + rp->fregoffset = pdr.fregoffset; + rp->frameoffset = pdr.frameoffset; + rp->framereg = pdr.framereg; + rp->pcreg = pdr.pcreg; + rp->irpss = sindex; + sv[i] = ss + sym.iss; + sindex += strlen (sv[i]) + 1; + } + } + + size = sizeof (struct rpdr_ext) * (count + 2) + sindex; + size = BFD_ALIGN (size, 16); + rtproc = (PTR) bfd_alloc (abfd, size); + if (rtproc == NULL) + { + mips_elf_hash_table (info)->procedure_count = 0; + goto error_return; + } + + mips_elf_hash_table (info)->procedure_count = count + 2; + + erp = (struct rpdr_ext *) rtproc; + memset (erp, 0, sizeof (struct rpdr_ext)); + erp++; + str = (char *) rtproc + sizeof (struct rpdr_ext) * (count + 2); + strcpy (str, no_name_func); + str += strlen (no_name_func) + 1; + for (i = 0; i < count; i++) + { + ecoff_swap_rpdr_out (abfd, rpdr + i, erp + i); + strcpy (str, sv[i]); + str += strlen (sv[i]) + 1; + } + ecoff_put_off (abfd, (bfd_vma) -1, (bfd_byte *) (erp + count)->p_adr); + + /* Set the size and contents of .rtproc section. */ + s->_raw_size = size; + s->contents = rtproc; + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + s->link_order_head = (struct bfd_link_order *) NULL; + + if (epdr != NULL) + free (epdr); + if (rpdr != NULL) + free (rpdr); + if (esym != NULL) + free (esym); + if (ss != NULL) + free (ss); + if (sv != NULL) + free (sv); + + return true; + + error_return: + if (epdr != NULL) + free (epdr); + if (rpdr != NULL) + free (rpdr); + if (esym != NULL) + free (esym); + if (ss != NULL) + free (ss); + if (sv != NULL) + free (sv); + return false; +} + +/* A comparison routine used to sort .gptab entries. */ + +static int +gptab_compare (p1, p2) + const PTR p1; + const PTR p2; +{ + const Elf32_gptab *a1 = (const Elf32_gptab *) p1; + const Elf32_gptab *a2 = (const Elf32_gptab *) p2; + + return a1->gt_entry.gt_g_value - a2->gt_entry.gt_g_value; +} + +/* We need to use a special link routine to handle the .reginfo and + the .mdebug sections. We need to merge all instances of these + sections together, not write them all out sequentially. */ + +static boolean +mips_elf_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection **secpp; + asection *o; + struct bfd_link_order *p; + asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; + asection *rtproc_sec; + Elf32_RegInfo reginfo; + struct ecoff_debug_info debug; + const struct ecoff_debug_swap *swap + = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + HDRR *symhdr = &debug.symbolic_header; + PTR mdebug_handle = NULL; + + /* Drop the .options section, since it has special semantics which I + haven't bothered to figure out. */ + for (secpp = &abfd->sections; *secpp != NULL; secpp = &(*secpp)->next) + { + if (strcmp ((*secpp)->name, ".options") == 0) + { + for (p = (*secpp)->link_order_head; p != NULL; p = p->next) + if (p->type == bfd_indirect_link_order) + p->u.indirect.section->flags &=~ SEC_HAS_CONTENTS; + (*secpp)->link_order_head = NULL; + *secpp = (*secpp)->next; + --abfd->section_count; + break; + } + } + + /* Get a value for the GP register. */ + if (elf_gp (abfd) == 0) + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (info->hash, "_gp", false, false, true); + if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_defined) + elf_gp (abfd) = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + else if (info->relocateable) + { + bfd_vma lo; + + /* Make up a value. */ + lo = (bfd_vma) -1; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (o->vma < lo + && (strcmp (o->name, ".sbss") == 0 + || strcmp (o->name, ".sdata") == 0 + || strcmp (o->name, ".lit4") == 0 + || strcmp (o->name, ".lit8") == 0)) + lo = o->vma; + } + elf_gp (abfd) = lo + ELF_MIPS_GP_OFFSET (abfd); + } + else + { + /* If the relocate_section function needs to do a reloc + involving the GP value, it should make a reloc_dangerous + callback to warn that GP is not defined. */ + } + } + + /* Go through the sections and collect the .reginfo and .mdebug + information. */ + reginfo_sec = NULL; + mdebug_sec = NULL; + gptab_data_sec = NULL; + gptab_bss_sec = NULL; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (strcmp (o->name, ".reginfo") == 0) + { + memset (®info, 0, sizeof reginfo); + + /* We have found the .reginfo section in the output file. + Look through all the link_orders comprising it and merge + the information together. */ + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + Elf32_External_RegInfo ext; + Elf32_RegInfo sub; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + /* The linker emulation code has probably clobbered the + size to be zero bytes. */ + if (input_section->_raw_size == 0) + input_section->_raw_size = sizeof (Elf32_External_RegInfo); + + if (! bfd_get_section_contents (input_bfd, input_section, + (PTR) &ext, + (file_ptr) 0, + sizeof ext)) + return false; + + bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub); + + reginfo.ri_gprmask |= sub.ri_gprmask; + reginfo.ri_cprmask[0] |= sub.ri_cprmask[0]; + reginfo.ri_cprmask[1] |= sub.ri_cprmask[1]; + reginfo.ri_cprmask[2] |= sub.ri_cprmask[2]; + reginfo.ri_cprmask[3] |= sub.ri_cprmask[3]; + + /* ri_gp_value is set by the function + mips_elf_section_processing when the section is + finally written out. */ + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* Force the section size to the value we want. */ + o->_raw_size = sizeof (Elf32_External_RegInfo); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + reginfo_sec = o; + } + + if (strcmp (o->name, ".mdebug") == 0) + { + struct extsym_info einfo; + + /* We have found the .mdebug section in the output file. + Look through all the link_orders comprising it and merge + the information together. */ + symhdr->magic = swap->sym_magic; + /* FIXME: What should the version stamp be? */ + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We accumulate the debugging information itself in the + debug_info structure. */ + debug.line = NULL; + debug.external_dnr = NULL; + debug.external_pdr = NULL; + debug.external_sym = NULL; + debug.external_opt = NULL; + debug.external_aux = NULL; + debug.ss = NULL; + debug.ssext = debug.ssext_end = NULL; + debug.external_fdr = NULL; + debug.external_rfd = NULL; + debug.external_ext = debug.external_ext_end = NULL; + + mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info); + if (mdebug_handle == (PTR) NULL) + return false; + + if (SGI_COMPAT (abfd)) + { + asection *s; + EXTR esym; + bfd_vma last; + unsigned int i; + static const char * const name[] = + { ".text", ".init", ".fini", ".data", + ".rodata", ".sdata", ".sbss", ".bss" }; + static const int sc[] = { scText, scInit, scFini, scData, + scRData, scSData, scSBss, scBss }; + + esym.jmptbl = 0; + esym.cobol_main = 0; + esym.weakext = 0; + esym.reserved = 0; + esym.ifd = ifdNil; + esym.asym.iss = issNil; + esym.asym.st = stLocal; + esym.asym.reserved = 0; + esym.asym.index = indexNil; + for (i = 0; i < 8; i++) + { + esym.asym.sc = sc[i]; + s = bfd_get_section_by_name (abfd, name[i]); + if (s != NULL) + { + esym.asym.value = s->vma; + last = s->vma + s->_raw_size; + } + else + esym.asym.value = last; + + if (! bfd_ecoff_debug_one_external (abfd, &debug, swap, + name[i], &esym)) + return false; + } + } + + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + const struct ecoff_debug_swap *input_swap; + struct ecoff_debug_info input_debug; + char *eraw_src; + char *eraw_end; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour + || (get_elf_backend_data (input_bfd) + ->elf_backend_ecoff_debug_swap) == NULL) + { + /* I don't know what a non MIPS ELF bfd would be + doing with a .mdebug section, but I don't really + want to deal with it. */ + continue; + } + + input_swap = (get_elf_backend_data (input_bfd) + ->elf_backend_ecoff_debug_swap); + + BFD_ASSERT (p->size == input_section->_raw_size); + + /* The ECOFF linking code expects that we have already + read in the debugging information and set up an + ecoff_debug_info structure, so we do that now. */ + if (! mips_elf_read_ecoff_info (input_bfd, input_section, + &input_debug)) + return false; + + if (! (bfd_ecoff_debug_accumulate + (mdebug_handle, abfd, &debug, swap, input_bfd, + &input_debug, input_swap, info))) + return false; + + /* Loop through the external symbols. For each one with + interesting information, try to find the symbol in + the linker global hash table and save the information + for the output external symbols. */ + eraw_src = input_debug.external_ext; + eraw_end = (eraw_src + + (input_debug.symbolic_header.iextMax + * input_swap->external_ext_size)); + for (; + eraw_src < eraw_end; + eraw_src += input_swap->external_ext_size) + { + EXTR ext; + const char *name; + struct mips_elf_link_hash_entry *h; + + (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext); + if (ext.asym.sc == scNil + || ext.asym.sc == scUndefined + || ext.asym.sc == scSUndefined) + continue; + + name = input_debug.ssext + ext.asym.iss; + h = mips_elf_link_hash_lookup (mips_elf_hash_table (info), + name, false, false, true); + if (h == NULL || h->esym.ifd != -2) + continue; + + if (ext.ifd != -1) + { + BFD_ASSERT (ext.ifd + < input_debug.symbolic_header.ifdMax); + ext.ifd = input_debug.ifdmap[ext.ifd]; + } + + h->esym = ext; + } + + /* Free up the information we just read. */ + free (input_debug.line); + free (input_debug.external_dnr); + free (input_debug.external_pdr); + free (input_debug.external_sym); + free (input_debug.external_opt); + free (input_debug.external_aux); + free (input_debug.ss); + free (input_debug.ssext); + free (input_debug.external_fdr); + free (input_debug.external_rfd); + free (input_debug.external_ext); + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + if (SGI_COMPAT (abfd) && info->shared) + { + /* Create .rtproc section. */ + rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc"); + if (rtproc_sec == NULL) + { + flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY); + + rtproc_sec = bfd_make_section (abfd, ".rtproc"); + if (rtproc_sec == NULL + || ! bfd_set_section_flags (abfd, rtproc_sec, flags) + || ! bfd_set_section_alignment (abfd, rtproc_sec, 12)) + return false; + } + + if (! mips_elf_create_procedure_table (mdebug_handle, abfd, + info, rtproc_sec, &debug)) + return false; + } + + /* Build the external symbol information. */ + einfo.abfd = abfd; + einfo.info = info; + einfo.debug = &debug; + einfo.swap = swap; + einfo.failed = false; + mips_elf_link_hash_traverse (mips_elf_hash_table (info), + mips_elf_output_extsym, + (PTR) &einfo); + if (einfo.failed) + return false; + + /* Set the size of the .mdebug section. */ + o->_raw_size = bfd_ecoff_debug_size (abfd, &debug, swap); + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + mdebug_sec = o; + } + + if (strncmp (o->name, ".gptab.", sizeof ".gptab." - 1) == 0) + { + const char *subname; + unsigned int c; + Elf32_gptab *tab; + Elf32_External_gptab *ext_tab; + unsigned int i; + + /* The .gptab.sdata and .gptab.sbss sections hold + information describing how the small data area would + change depending upon the -G switch. These sections + not used in executables files. */ + if (! info->relocateable) + { + asection **secpp; + + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* Skip this section later on (I don't think this + currently matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + + /* Really remove the section. */ + for (secpp = &abfd->sections; + *secpp != o; + secpp = &(*secpp)->next) + ; + *secpp = (*secpp)->next; + --abfd->section_count; + + continue; + } + + /* There is one gptab for initialized data, and one for + uninitialized data. */ + if (strcmp (o->name, ".gptab.sdata") == 0) + gptab_data_sec = o; + else if (strcmp (o->name, ".gptab.sbss") == 0) + gptab_bss_sec = o; + else + { + (*_bfd_error_handler) + ("%s: illegal section name `%s'", + bfd_get_filename (abfd), o->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + + /* The linker script always combines .gptab.data and + .gptab.sdata into .gptab.sdata, and likewise for + .gptab.bss and .gptab.sbss. It is possible that there is + no .sdata or .sbss section in the output file, in which + case we must change the name of the output section. */ + subname = o->name + sizeof ".gptab" - 1; + if (bfd_get_section_by_name (abfd, subname) == NULL) + { + if (o == gptab_data_sec) + o->name = ".gptab.data"; + else + o->name = ".gptab.bss"; + subname = o->name + sizeof ".gptab" - 1; + BFD_ASSERT (bfd_get_section_by_name (abfd, subname) != NULL); + } + + /* Set up the first entry. */ + c = 1; + tab = (Elf32_gptab *) bfd_malloc (c * sizeof (Elf32_gptab)); + if (tab == NULL) + return false; + tab[0].gt_header.gt_current_g_value = elf_gp_size (abfd); + tab[0].gt_header.gt_unused = 0; + + /* Combine the input sections. */ + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + asection *input_section; + bfd *input_bfd; + bfd_size_type size; + unsigned long last; + bfd_size_type gpentry; + + if (p->type != bfd_indirect_link_order) + { + if (p->type == bfd_fill_link_order) + continue; + abort (); + } + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + + /* Combine the gptab entries for this input section one + by one. We know that the input gptab entries are + sorted by ascending -G value. */ + size = bfd_section_size (input_bfd, input_section); + last = 0; + for (gpentry = sizeof (Elf32_External_gptab); + gpentry < size; + gpentry += sizeof (Elf32_External_gptab)) + { + Elf32_External_gptab ext_gptab; + Elf32_gptab int_gptab; + unsigned long val; + unsigned long add; + boolean exact; + unsigned int look; + + if (! (bfd_get_section_contents + (input_bfd, input_section, (PTR) &ext_gptab, + gpentry, sizeof (Elf32_External_gptab)))) + { + free (tab); + return false; + } + + bfd_mips_elf32_swap_gptab_in (input_bfd, &ext_gptab, + &int_gptab); + val = int_gptab.gt_entry.gt_g_value; + add = int_gptab.gt_entry.gt_bytes - last; + + exact = false; + for (look = 1; look < c; look++) + { + if (tab[look].gt_entry.gt_g_value >= val) + tab[look].gt_entry.gt_bytes += add; + + if (tab[look].gt_entry.gt_g_value == val) + exact = true; + } + + if (! exact) + { + Elf32_gptab *new_tab; + unsigned int max; + + /* We need a new table entry. */ + new_tab = ((Elf32_gptab *) + bfd_realloc ((PTR) tab, + (c + 1) * sizeof (Elf32_gptab))); + if (new_tab == NULL) + { + free (tab); + return false; + } + tab = new_tab; + tab[c].gt_entry.gt_g_value = val; + tab[c].gt_entry.gt_bytes = add; + + /* Merge in the size for the next smallest -G + value, since that will be implied by this new + value. */ + max = 0; + for (look = 1; look < c; look++) + { + if (tab[look].gt_entry.gt_g_value < val + && (max == 0 + || (tab[look].gt_entry.gt_g_value + > tab[max].gt_entry.gt_g_value))) + max = look; + } + if (max != 0) + tab[c].gt_entry.gt_bytes += + tab[max].gt_entry.gt_bytes; + + ++c; + } + + last = int_gptab.gt_entry.gt_bytes; + } + + /* Hack: reset the SEC_HAS_CONTENTS flag so that + elf_link_input_bfd ignores this section. */ + input_section->flags &=~ SEC_HAS_CONTENTS; + } + + /* The table must be sorted by -G value. */ + if (c > 2) + qsort (tab + 1, c - 1, sizeof (tab[0]), gptab_compare); + + /* Swap out the table. */ + ext_tab = ((Elf32_External_gptab *) + bfd_alloc (abfd, c * sizeof (Elf32_External_gptab))); + if (ext_tab == NULL) + { + free (tab); + return false; + } + + for (i = 0; i < c; i++) + bfd_mips_elf32_swap_gptab_out (abfd, tab + i, ext_tab + i); + free (tab); + + o->_raw_size = c * sizeof (Elf32_External_gptab); + o->contents = (bfd_byte *) ext_tab; + + /* Skip this section later on (I don't think this currently + matters, but someday it might). */ + o->link_order_head = (struct bfd_link_order *) NULL; + } + } + + /* Invoke the regular ELF backend linker to do all the work. */ + if (! bfd_elf32_bfd_final_link (abfd, info)) + return false; + + /* Now write out the computed sections. */ + + if (reginfo_sec != (asection *) NULL) + { + Elf32_External_RegInfo ext; + + bfd_mips_elf32_swap_reginfo_out (abfd, ®info, &ext); + if (! bfd_set_section_contents (abfd, reginfo_sec, (PTR) &ext, + (file_ptr) 0, sizeof ext)) + return false; + } + + if (mdebug_sec != (asection *) NULL) + { + BFD_ASSERT (abfd->output_has_begun); + if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug, + swap, info, + mdebug_sec->filepos)) + return false; + + bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); + } + + if (gptab_data_sec != (asection *) NULL) + { + if (! bfd_set_section_contents (abfd, gptab_data_sec, + gptab_data_sec->contents, + (file_ptr) 0, + gptab_data_sec->_raw_size)) + return false; + } + + if (gptab_bss_sec != (asection *) NULL) + { + if (! bfd_set_section_contents (abfd, gptab_bss_sec, + gptab_bss_sec->contents, + (file_ptr) 0, + gptab_bss_sec->_raw_size)) + return false; + } + + if (SGI_COMPAT (abfd)) + { + rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc"); + if (rtproc_sec != NULL) + { + if (! bfd_set_section_contents (abfd, rtproc_sec, + rtproc_sec->contents, + (file_ptr) 0, + rtproc_sec->_raw_size)) + return false; + } + } + + return true; +} + +/* Handle a MIPS ELF HI16 reloc. */ + +static void +mips_elf_relocate_hi16 (input_bfd, relhi, rello, contents, addend) + bfd *input_bfd; + Elf_Internal_Rela *relhi; + Elf_Internal_Rela *rello; + bfd_byte *contents; + bfd_vma addend; +{ + bfd_vma insn; + bfd_vma addlo; + + insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); + + addlo = bfd_get_32 (input_bfd, contents + rello->r_offset); + addlo &= 0xffff; + + addend += ((insn & 0xffff) << 16) + addlo; + + if ((addlo & 0x8000) != 0) + addend -= 0x10000; + if ((addend & 0x8000) != 0) + addend += 0x10000; + + bfd_put_32 (input_bfd, + (insn & 0xffff0000) | ((addend >> 16) & 0xffff), + contents + relhi->r_offset); +} + +/* Handle a MIPS ELF local GOT16 reloc. */ + +static void +mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello, + contents, addend) + bfd *output_bfd; + bfd *input_bfd; + asection *sgot; + Elf_Internal_Rela *relhi; + Elf_Internal_Rela *rello; + bfd_byte *contents; + bfd_vma addend; +{ + int local_gotno; + int i; + bfd_vma insn; + bfd_vma addlo; + bfd_vma address; + bfd_vma hipage; + bfd_byte *got_contents; + struct mips_got_info *g; + + insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); + + addlo = bfd_get_32 (input_bfd, contents + rello->r_offset); + addlo &= 0xffff; + + addend += ((insn & 0xffff) << 16) + addlo; + + if ((addlo & 0x8000) != 0) + addend -= 0x10000; + if ((addend & 0x8000) != 0) + addend += 0x10000; + + /* Get a got entry representing requested hipage. */ + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + + local_gotno = g->local_gotno; + got_contents = sgot->contents; + hipage = addend & 0xffff0000; + + for (i = MIPS_RESERVED_GOTNO; i < local_gotno; i++) + { + address = bfd_get_32 (input_bfd, got_contents + i * 4); + if (hipage == (address & 0xffff0000)) + break; + if (address == (bfd_vma) 0) + { + bfd_put_32 (input_bfd, hipage, got_contents + i * 4); + break; + } + } + + BFD_ASSERT (i < local_gotno); +#if 1 + if (i == local_gotno) + (*_bfd_error_handler) + ("ELF MIPS linker: more got entries are needed for hipage: %x", + hipage); +#endif + + i = - ELF_MIPS_GP_OFFSET (output_bfd) + i * 4; + bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff), + contents + relhi->r_offset); +} + +/* Handle MIPS ELF CALL16 reloc and global GOT16 reloc. */ + +static void +mips_elf_relocate_global_got (input_bfd, rel, contents, offset) + bfd *input_bfd; + Elf_Internal_Rela *rel; + bfd_byte *contents; + bfd_vma offset; +{ + bfd_vma insn; + + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + bfd_put_32 (input_bfd, + (insn & 0xffff0000) | (offset & 0xffff), + contents + rel->r_offset); +} + +/* Relocate a MIPS ELF section. */ + +static boolean +mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + size_t locsymcount; + size_t extsymoff; + asection *sgot, *sreloc, *scpt; + bfd *dynobj; + bfd_vma gp; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + struct mips_got_info *g; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + + sgot = NULL; + sreloc = NULL; + if (dynobj == NULL || ! SGI_COMPAT (output_bfd)) + scpt = NULL; + else + scpt = bfd_get_section_by_name (dynobj, ".compact_rel"); + g = NULL; + + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym); + extsymoff = 0; + } + else + { + locsymcount = symtab_hdr->sh_info; + extsymoff = symtab_hdr->sh_info; + } + + gp = _bfd_get_gp_value (output_bfd); + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + bfd_vma addend; + struct elf_link_hash_entry *h; + asection *sec; + Elf_Internal_Sym *sym; + bfd_reloc_status_type r; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_MIPS_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = elf_mips_howto_table + r_type; + + if (dynobj != NULL + && (r_type == R_MIPS_CALL16 + || r_type == R_MIPS_GOT16 + || r_type == R_MIPS_CALL_HI16 + || r_type == R_MIPS_CALL_LO16 + || r_type == R_MIPS_GOT_HI16 + || r_type == R_MIPS_GOT_LO16)) + { + /* We need the .got section. */ + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + } + } + + r_symndx = ELF32_R_SYM (rel->r_info); + + /* Mix in the change in GP address for a GP relative reloc. */ + if (r_type != R_MIPS_GPREL16 + && r_type != R_MIPS_LITERAL + && r_type != R_MIPS_GPREL32) + addend = 0; + else + { + if (gp == 0) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, + "GP relative relocation when GP not defined", + input_bfd, input_section, + rel->r_offset))) + return false; + /* Only give the error once per link. */ + gp = 4; + _bfd_set_gp_value (output_bfd, gp); + } + + if (r_symndx < extsymoff + || (elf_bad_symtab (input_bfd) + && local_sections[r_symndx] != NULL)) + { + /* This is a relocation against a section. The current + addend in the instruction is the difference between + INPUT_SECTION->vma and the GP value of INPUT_BFD. We + must change this to be the difference between the + final definition (which will end up in RELOCATION) + and the GP value of OUTPUT_BFD (which is in GP). */ + addend = elf_gp (input_bfd) - gp; + } + else if (! info->relocateable) + { + /* We are doing a final link. The current addend in the + instruction is simply the desired offset into the + symbol (normally zero). We want the instruction to + hold the difference between the final definition of + the symbol (which will end up in RELOCATION) and the + GP value of OUTPUT_BFD (which is in GP). */ + addend = - gp; + } + else + { + /* We are generating relocateable output, and we aren't + going to define this symbol, so we just leave the + instruction alone. */ + addend = 0; + } + } + + h = NULL; + sym = NULL; + sec = NULL; + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && local_sections[r_symndx] == NULL)) + r = bfd_reloc_ok; + else + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) + r = bfd_reloc_ok; + else + { + sec = local_sections[r_symndx]; + + /* It would be logical to add sym->st_value here, + but Irix 5 sometimes generates a garbage symbol + value. */ + addend += sec->output_offset; + + /* If this is HI16 or GOT16 with an associated LO16, + adjust the addend accordingly. Otherwise, just + relocate. */ + if ((r_type != R_MIPS_HI16 && r_type != R_MIPS_GOT16) + || (rel + 1) >= relend + || ELF32_R_TYPE ((rel + 1)->r_info) != R_MIPS_LO16) + r = _bfd_relocate_contents (howto, input_bfd, + addend, + contents + rel->r_offset); + else + { + mips_elf_relocate_hi16 (input_bfd, rel, rel + 1, + contents, addend); + r = bfd_reloc_ok; + } + } + } + } + else + { + bfd_vma relocation; + boolean local; + + /* This is a final link. */ + sym = NULL; + if (r_symndx < extsymoff + || (elf_bad_symtab (input_bfd) + && local_sections[r_symndx] != NULL)) + { + local = true; + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset); + + /* It would be logical to always add sym->st_value here, + but Irix 5 sometimes generates a garbage symbol + value. */ + if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) + relocation += sym->st_value; + } + else + { + long indx; + + local = false; + indx = r_symndx - extsymoff; + h = elf_sym_hashes (input_bfd)[indx]; + 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; + if (strcmp (h->root.root.string, "_gp_disp") == 0) + { + if (gp == 0) + { + if (! ((*info->callbacks->reloc_dangerous) + (info, + "_gp_disp used when GP not defined", + input_bfd, input_section, + rel->r_offset))) + return false; + /* Only give the error once per link. */ + gp = 4; + _bfd_set_gp_value (output_bfd, gp); + relocation = 0; + } + else + { + sec = input_section; + if (sec->output_section != NULL) + relocation = (gp + - (rel->r_offset + + sec->output_section->vma + + sec->output_offset)); + else + relocation = gp - rel->r_offset; + if (r_type == R_MIPS_LO16) + relocation += 4; + } + } + else if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if (sec->output_section == NULL) + relocation = 0; + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared && ! info->symbolic) + relocation = 0; + else if (strcmp (h->root.root.string, "_DYNAMIC_LINK") == 0) + { + /* If this is a dynamic link, we should have created + a _DYNAMIC_LINK symbol in + mips_elf_create_dynamic_sections. Otherwise, we + should define the symbol with a value of 0. + FIXME: It should probably get into the symbol + table somehow as well. */ + BFD_ASSERT (! info->shared); + BFD_ASSERT (bfd_get_section_by_name (output_bfd, + ".dynamic") == NULL); + relocation = 0; + } + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + if (r_type == R_MIPS_HI16 + && (rel + 1) < relend + && ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16) + { + mips_elf_relocate_hi16 (input_bfd, rel, rel + 1, + contents, relocation + addend); + r = bfd_reloc_ok; + } + else if (r_type == R_MIPS_GOT16 && local) + { + /* GOT16 must be also with associated LO16 in the local + case. In this case, the addend is extracted and the + section in which the referenced object is determined. + Then the final address of the object is computed and + the GOT entry for the hipage (an aligned 64kb chunk) + is added to .got section if needed. The offset field + of the GOT16-relocated instruction is replaced by the + index of this GOT entry for the hipage. */ + if ((rel + 1) < relend + && ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16) + { + mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, + rel, rel + 1, + contents, + relocation + addend); + r = bfd_reloc_ok; + } + else + r = bfd_reloc_outofrange; + } + else if (r_type == R_MIPS_CALL16 + || r_type == R_MIPS_GOT16 + || r_type == R_MIPS_CALL_LO16 + || r_type == R_MIPS_GOT_LO16) + { + bfd_vma offset; + + /* This symbol must be registered as a global symbol + having the corresponding got entry. */ + BFD_ASSERT (h->got_offset != (bfd_vma) -1); + + offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4; + BFD_ASSERT (g->local_gotno <= offset + && offset < sgot->_raw_size); + bfd_put_32 (output_bfd, relocation + addend, + sgot->contents + offset); + offset = (sgot->output_section->vma + sgot->output_offset + + offset - gp); + mips_elf_relocate_global_got (input_bfd, rel, contents, + offset); + r = bfd_reloc_ok; + } + else if (r_type == R_MIPS_CALL_HI16 + || r_type == R_MIPS_GOT_HI16) + { + bfd_vma offset; + + /* This must be a global symbol with a got entry. The + next reloc must be the corresponding LO16 reloc. */ + BFD_ASSERT (h != NULL && h->got_offset != (bfd_vma) -1); + BFD_ASSERT ((rel + 1) < relend); + BFD_ASSERT (ELF32_R_TYPE ((rel + 1)->r_info) + == (r_type == R_MIPS_CALL_HI16 + ? R_MIPS_CALL_LO16 + : R_MIPS_GOT_LO16)); + + offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4; + BFD_ASSERT (g->local_gotno <= offset + && offset < sgot->_raw_size); + bfd_put_32 (output_bfd, relocation + addend, + sgot->contents + offset); + offset = (sgot->output_section->vma + sgot->output_offset + + offset - gp); + mips_elf_relocate_hi16 (input_bfd, rel, rel + 1, contents, + offset); + r = bfd_reloc_ok; + } + else if (r_type == R_MIPS_REL32 + || r_type == R_MIPS_32) + { + Elf_Internal_Rel outrel; + Elf32_crinfo cptrel; + bfd_byte *cr; + + if (info->shared + && (input_section->flags & SEC_ALLOC) != 0) + { + /* When generating a shared object, these + relocations are copied into the output file to be + resolved at run time. */ + if (sreloc == NULL) + { + sreloc = bfd_get_section_by_name (dynobj, ".rel.dyn"); + BFD_ASSERT (sreloc != NULL); + } + + outrel.r_offset = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + + addend = bfd_get_32 (input_bfd, contents + rel->r_offset); + + if (h != NULL + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + { + BFD_ASSERT (h->dynindx != -1); + outrel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_REL32); + sec = input_section; + } + else + { + long indx; + + if (h == NULL) + sec = local_sections[r_symndx]; + else + { + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || (h->root.type + == bfd_link_hash_defweak)); + sec = h->root.u.def.section; + } + if (sec != NULL && bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + asection *osec; + + osec = sec->output_section; + indx = elf_section_data (osec)->dynindx; + if (indx == 0) + abort (); + } + + outrel.r_info = ELF32_R_INFO (indx, R_MIPS_REL32); + addend += relocation; + } + + bfd_put_32 (output_bfd, addend, contents + rel->r_offset); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, + (((Elf32_External_Rel *) + sreloc->contents) + + sreloc->reloc_count)); + ++sreloc->reloc_count; + + if (SGI_COMPAT (output_bfd)) + { + if (scpt == NULL) + continue; + + /* Make an entry of compact relocation info. */ + mips_elf_set_cr_format (cptrel, CRF_MIPS_LONG); + cptrel.vaddr = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + if (r_type == R_MIPS_REL32) + mips_elf_set_cr_type (cptrel, CRT_MIPS_REL32); + else + mips_elf_set_cr_type (cptrel, CRT_MIPS_WORD); + mips_elf_set_cr_dist2to (cptrel, 0); + cptrel.konst = addend; + + cr = (scpt->contents + + sizeof (Elf32_External_compact_rel)); + bfd_elf32_swap_crinfo_out (output_bfd, &cptrel, + ((Elf32_External_crinfo *) cr + + scpt->reloc_count)); + ++scpt->reloc_count; + } + + /* This reloc will be computed at runtime, so + there's no need to do anything now. */ + continue; + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, addend); + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, addend); + + if (SGI_COMPAT (abfd) + && scpt != NULL + && (input_section->flags & SEC_ALLOC) != 0) + { + Elf32_crinfo cptrel; + bfd_byte *cr; + + /* Make an entry of compact relocation info. */ + mips_elf_set_cr_format (cptrel, CRF_MIPS_LONG); + cptrel.vaddr = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + + switch (r_type) + { + case R_MIPS_26: + mips_elf_set_cr_type (cptrel, CRT_MIPS_JMPAD); + /* XXX How should we set dist2to in this case. */ + mips_elf_set_cr_dist2to (cptrel, 8); + cptrel.konst = addend + relocation; + cr = scpt->contents + sizeof (Elf32_External_compact_rel); + bfd_elf32_swap_crinfo_out (output_bfd, &cptrel, + ((Elf32_External_crinfo *) cr + + scpt->reloc_count)); + ++scpt->reloc_count; + break; + + case R_MIPS_GPREL16: + case R_MIPS_LITERAL: + case R_MIPS_GPREL32: + mips_elf_set_cr_type (cptrel, CRT_MIPS_GPHI_LO); + cptrel.konst = gp - cptrel.vaddr; + mips_elf_set_cr_dist2to (cptrel, 4); + cr = scpt->contents + sizeof (Elf32_External_compact_rel); + bfd_elf32_swap_crinfo_out (output_bfd, &cptrel, + ((Elf32_External_crinfo *) cr + + scpt->reloc_count)); + ++scpt->reloc_count; + break; + + default: + break; + } + } + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Functions for the dynamic linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" + +/* Create dynamic sections when linking against a dynamic object. */ + +static boolean +mips_elf_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + struct elf_link_hash_entry *h; + flagword flags; + register asection *s; + const char * const *namep; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_READONLY); + + /* Mips ABI requests the .dynamic section to be read only. */ + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + if (! bfd_set_section_flags (abfd, s, flags)) + return false; + } + + /* We need to create .got section. */ + if (! mips_elf_create_got_section (abfd, info)) + return false; + + /* Create .stub section. */ + if (bfd_get_section_by_name (abfd, ".stub") == NULL) + { + s = bfd_make_section (abfd, ".stub"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + } + + if (SGI_COMPAT (abfd)) + { + for (namep = mips_elf_dynsym_rtproc_names; *namep != NULL; namep++) + { + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, *namep, BSF_GLOBAL, bfd_und_section_ptr, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_SECTION; + + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + /* We need to create a .compact_rel section. */ + if (! mips_elf_create_compact_rel_section (abfd, info)) + return false; + + /* Change aligments of some sections. */ + s = bfd_get_section_by_name (abfd, ".hash"); + if (s != NULL) + bfd_set_section_alignment (abfd, s, 4); + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + bfd_set_section_alignment (abfd, s, 4); + s = bfd_get_section_by_name (abfd, ".dynstr"); + if (s != NULL) + bfd_set_section_alignment (abfd, s, 4); + s = bfd_get_section_by_name (abfd, ".reginfo"); + if (s != NULL) + bfd_set_section_alignment (abfd, s, 4); + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + bfd_set_section_alignment (abfd, s, 4); + } + + if (!info->shared) + { + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_DYNAMIC_LINK", BSF_GLOBAL, bfd_abs_section_ptr, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags ^=~ ELF_LINK_NON_ELF; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_SECTION; + + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + return true; +} + +/* Create the .compact_rel section. */ + +static boolean +mips_elf_create_compact_rel_section (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + + if (bfd_get_section_by_name (abfd, ".compact_rel") == NULL) + { + flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY; + + s = bfd_make_section (abfd, ".compact_rel"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + s->_raw_size = sizeof (Elf32_External_compact_rel); + } + + return true; +} + +/* Create the .got section to hold the global offset table. */ + +static boolean +mips_elf_create_got_section (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct mips_got_info *g; + + /* This function may be called more than once. */ + if (bfd_get_section_by_name (abfd, ".got") != NULL) + return true; + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 4)) + return false; + + /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the + linker script because we don't want to define the symbol if we + are not creating a global offset table. */ + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + + /* The first several global offset table entries are reserved. */ + s->_raw_size = MIPS_RESERVED_GOTNO * 4; + + g = (struct mips_got_info *) bfd_alloc (abfd, + sizeof (struct mips_got_info)); + if (g == NULL) + return false; + g->global_gotsym = 0; + g->local_gotno = MIPS_RESERVED_GOTNO; + if (elf_section_data (s) == NULL) + { + s->used_by_bfd = + (PTR) bfd_zalloc (abfd, sizeof (struct bfd_elf_section_data)); + if (elf_section_data (s) == NULL) + return false; + } + elf_section_data (s)->tdata = (PTR) g; + + return true; +} + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table. */ + +static boolean +mips_elf_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + struct mips_got_info *g; + size_t extsymoff; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sgot; + asection *sreloc; + + if (info->relocateable) + return true; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; + + sgot = NULL; + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_symndx < extsymoff) + h = NULL; + else + h = sym_hashes[r_symndx - extsymoff]; + + /* Some relocs require a global offset table. */ + if (dynobj == NULL) + { + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_MIPS_GOT16: + case R_MIPS_CALL16: + case R_MIPS_CALL_HI16: + case R_MIPS_CALL_LO16: + case R_MIPS_GOT_HI16: + case R_MIPS_GOT_LO16: + elf_hash_table (info)->dynobj = dynobj = abfd; + if (! mips_elf_create_got_section (dynobj, info)) + return false; + break; + + default: + break; + } + } + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_MIPS_CALL16: + case R_MIPS_CALL_HI16: + case R_MIPS_CALL_LO16: + /* This symbol requires a global offset table entry. */ + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + } + + BFD_ASSERT (h != NULL); + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + if (h->got_offset != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + + /* Note the index of the first global got symbol in .dynsym. */ + if (g->global_gotsym == 0 + || g->global_gotsym > (unsigned long) h->dynindx) + g->global_gotsym = h->dynindx; + + /* Make this symbol to have the corresponding got entry. */ + h->got_offset = 0; + + /* We need a stub, not a plt entry for the undefined + function. But we record it as if it needs plt. See + elf_adjust_dynamic_symbol in elflink.h. */ + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->type = STT_FUNC; + + break; + + case R_MIPS_GOT16: + case R_MIPS_GOT_HI16: + case R_MIPS_GOT_LO16: + /* This symbol requires a global offset table entry. */ + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + } + + if (h != NULL) + { + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + if (h->got_offset != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + /* Note the index of the first global got symbol in + .dynsym. */ + if (g->global_gotsym == 0 + || g->global_gotsym > (unsigned long) h->dynindx) + g->global_gotsym = h->dynindx; + + /* Make this symbol to be the global got symbol. */ + h->got_offset = 0; + } + + break; + + case R_MIPS_32: + case R_MIPS_REL32: + if (info->shared + && (sec->flags & SEC_ALLOC) != 0) + { + /* When creating a shared object, we must copy these + reloc types into the output file as R_MIPS_REL32 + relocs. We create the .rel.dyn reloc section in + dynobj and make room for this reloc. */ + if (sreloc == NULL) + { + const char *name = ".rel.dyn"; + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || ! bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, sreloc, 4)) + return false; + + /* Add a null element. */ + sreloc->_raw_size += sizeof (Elf32_External_Rel); + ++sreloc->reloc_count; + } + } + + sreloc->_raw_size += sizeof (Elf32_External_Rel); + } + + if (SGI_COMPAT (abfd)) + mips_elf_hash_table (info)->compact_rel_size += + sizeof (Elf32_External_crinfo); + + break; + + case R_MIPS_26: + case R_MIPS_GPREL16: + case R_MIPS_LITERAL: + case R_MIPS_GPREL32: + if (SGI_COMPAT (abfd)) + mips_elf_hash_table (info)->compact_rel_size += + sizeof (Elf32_External_crinfo); + break; + + default: + break; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +mips_elf_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) + || h->weakdef != NULL + || ((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))); + + /* For a function, create a stub, if needed. */ + if (h->type == STT_FUNC + || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (! elf_hash_table (info)->dynamic_sections_created) + return true; + + /* If this symbol is not defined in a regular file, then set + the symbol to the stub location. This is required to make + function pointers compare as equal between the normal + executable and the shared library. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* We need .stub section. */ + s = bfd_get_section_by_name (dynobj, ".stub"); + BFD_ASSERT (s != NULL); + + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* XXX Write this stub address somewhere. */ + h->plt_offset = s->_raw_size; + + /* Make room for this stub code. */ + s->_raw_size += MIPS_FUNCTION_STUB_SIZE; + + /* The last half word of the stub will be filled with the index + of this symbol in .dynsym section. */ + return true; + } + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +mips_elf_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean reltext; + asection *sgot; + struct mips_got_info *g; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + } + + /* Recompute the size of .got for local entires (reserved and + hipages) if needed. To estimate it, get the upper bound of total + size of loadable sections. */ + sgot = bfd_get_section_by_name (dynobj, ".got"); + + if (sgot != NULL) + { + bfd_size_type loadable_size = 0; + bfd_size_type local_gotno; + struct _bfd *sub; + + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + + for (sub = info->input_bfds; sub; sub = sub->link_next) + for (s = sub->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_ALLOC) == 0) + continue; + loadable_size += (s->_raw_size + 0xf) & ~0xf; + } + + loadable_size += MIPS_FUNCTION_STUB_SIZE; + + /* Assume there are two loadable segments consisting of + contiguous sections. Is 5 enough? */ + local_gotno = (loadable_size >> 16) + 5 + MIPS_RESERVED_GOTNO; + g->local_gotno = local_gotno; + sgot->_raw_size += local_gotno * 4; + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + reltext = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + if ((s->flags & SEC_IN_MEMORY) == 0) + continue; + + strip = false; + + if (strncmp (name, ".rel", 4) == 0) + { + if (s->_raw_size == 0) + strip = true; + else + { + asection *target; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL entry. + If the relocation section is .rel.dyn, we always + assert a DT_TEXTREL entry rather than testing whether + there exists a relocation to a read only section or + not. */ + target = bfd_get_section_by_name (output_bfd, name + 4); + if ((target != NULL && (target->flags & SEC_READONLY) != 0) + || strcmp (name, ".rel.dyn") == 0) + reltext = true; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + if (strcmp (name, ".rel.dyn") != 0) + s->reloc_count = 0; + } + } + else if (strncmp (name, ".got", 4) == 0) + { + int i; + + BFD_ASSERT (elf_section_data (s) != NULL); + g = (struct mips_got_info *) elf_section_data (s)->tdata; + BFD_ASSERT (g != NULL); + + /* Fix the size of .got section for the correspondence of + global symbols and got entries. This adds some useless + got entries. Is this required by ABI really? */ + i = elf_hash_table (info)->dynsymcount - g->global_gotsym; + s->_raw_size += i * 4; + } + else if (strncmp (name, ".stub", 5) == 0) + { + /* Irix rld assumes that the function stub isn't at the end + of .text section. So put a dummy. XXX */ + s->_raw_size += MIPS_FUNCTION_STUB_SIZE; + } + else if (SGI_COMPAT (output_bfd) + && strncmp (name, ".compact_rel", 12) == 0) + s->_raw_size += mips_elf_hash_table (info)->compact_rel_size; + else if (strncmp (name, ".init", 5) != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset (s->contents, 0, s->_raw_size); + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_mips_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (! info->shared) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (reltext) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)) + return false; + + if (bfd_get_section_by_name (dynobj, ".rel.dyn")) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_RELENT, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_CONFLICTNO, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LIBLISTNO, 0)) + return false; + + if (bfd_get_section_by_name (dynobj, ".conflict") != NULL) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_CONFLICT, 0)) + return false; + + s = bfd_get_section_by_name (dynobj, ".liblist"); + BFD_ASSERT (s != NULL); + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LIBLIST, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_RLD_VERSION, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_FLAGS, 0)) + return false; + +#if 0 + /* Time stamps in executable files are a bad idea. */ + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_TIME_STAMP, 0)) + return false; +#endif + +#if 0 /* FIXME */ + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_ICHECKSUM, 0)) + return false; +#endif + +#if 0 /* FIXME */ + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_IVERSION, 0)) + return false; +#endif + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_BASE_ADDRESS, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_LOCAL_GOTNO, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_SYMTABNO, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_UNREFEXTNO, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_GOTSYM, 0)) + return false; + + if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_HIPAGENO, 0)) + return false; + +#if 0 /* (SGI_COMPAT) */ + if (! bfd_get_section_by_name (dynobj, ".init")) + if (! bfd_elf32_add_dynamic_entry (info, DT_INIT, 0)) + return false; + + if (! bfd_get_section_by_name (dynobj, ".fini")) + if (! bfd_elf32_add_dynamic_entry (info, DT_FINI, 0)) + return false; +#endif + } + + /* If we use dynamic linking, we generate a section symbol for each + output section. These are local symbols, which means that they + must come first in the dynamic symbol table. + That means we must increment the dynamic symbol index of every + other dynamic symbol. */ + { + const char * const *namep; + unsigned int c, i; + bfd_size_type strindex; + struct bfd_strtab_hash *dynstr; + struct mips_got_info *g; + + if (elf_hash_table (info)->dynamic_sections_created) + { + if (SGI_COMPAT (output_bfd)) + { + c = SIZEOF_MIPS_DYNSYM_SECNAMES - 1; + elf_link_hash_traverse (elf_hash_table (info), + mips_elf_adjust_dynindx, + (PTR) &c); + elf_hash_table (info)->dynsymcount += c; + + dynstr = elf_hash_table (info)->dynstr; + BFD_ASSERT (dynstr != NULL); + + for (i = 1, namep = mips_elf_dynsym_sec_names; + *namep != NULL; + i++, namep++) + { + s = bfd_get_section_by_name (output_bfd, *namep); + if (s != NULL) + elf_section_data (s)->dynindx = i; + + strindex = _bfd_stringtab_add (dynstr, *namep, true, false); + if (strindex == (bfd_size_type) -1) + return false; + + mips_elf_hash_table (info)->dynsym_sec_strindex[i] = strindex; + } + } + else + { + c = bfd_count_sections (output_bfd); + elf_link_hash_traverse (elf_hash_table (info), + mips_elf_adjust_dynindx, + (PTR) &c); + elf_hash_table (info)->dynsymcount += c; + + for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++) + { + elf_section_data (s)->dynindx = i; + /* These symbols will have no names, so we don't need to + fiddle with dynstr_index. */ + } + } + } + + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + BFD_ASSERT (elf_section_data (s) != NULL); + g = (struct mips_got_info *) elf_section_data (s)->tdata; + BFD_ASSERT (g != NULL); + + /* If there are no global got symbols, fake the last symbol so for + safety. */ + if (g->global_gotsym) + g->global_gotsym += c; + else + g->global_gotsym = elf_hash_table (info)->dynsymcount - 1; + } + + return true; +} + +/* Increment the index of a dynamic symbol by a given amount. Called + via elf_link_hash_traverse. */ + +static boolean +mips_elf_adjust_dynindx (h, cparg) + struct elf_link_hash_entry *h; + PTR cparg; +{ + unsigned int *cp = (unsigned int *) cparg; + + if (h->dynindx != -1) + h->dynindx += *cp; + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj; + bfd_vma gval; + asection *sgot; + struct mips_got_info *g; + const char *name; + + dynobj = elf_hash_table (info)->dynobj; + gval = sym->st_value; + + if (h->plt_offset != (bfd_vma) -1) + { + asection *s; + bfd_byte *p; + bfd_byte stub[MIPS_FUNCTION_STUB_SIZE]; + + /* This symbol has a stub. Set it up. */ + + BFD_ASSERT (h->dynindx != -1); + + s = bfd_get_section_by_name (dynobj, ".stub"); + BFD_ASSERT (s != NULL); + + /* Fill the stub. */ + p = stub; + bfd_put_32 (output_bfd, STUB_LW(output_bfd), p); + p += 4; + bfd_put_32 (output_bfd, STUB_MOVE, p); + p += 4; + + /* FIXME: Can h->dynindex be more than 64K? */ + if (h->dynindx & 0xffff0000) + return false; + + bfd_put_32 (output_bfd, STUB_JALR, p); + p += 4; + bfd_put_32 (output_bfd, STUB_LI16 + h->dynindx, p); + + BFD_ASSERT (h->plt_offset <= s->_raw_size); + memcpy (s->contents + h->plt_offset, stub, MIPS_FUNCTION_STUB_SIZE); + + /* Mark the symbol as undefined. plt_offset != -1 occurs + only for the referenced symbol. */ + sym->st_shndx = SHN_UNDEF; + + /* The run-time linker uses the st_value field of the symbol + to reset the global offset table entry for this external + to its stub address when unlinking a shared object. */ + gval = s->output_section->vma + s->output_offset + h->plt_offset; + sym->st_value = gval; + } + + BFD_ASSERT (h->dynindx != -1); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + + if ((unsigned long) h->dynindx >= g->global_gotsym) + { + bfd_size_type offset; + + /* This symbol has an entry in the global offset table. Set its + value to the corresponding got entry, if needed. */ + if (h->got_offset == (bfd_vma) -1) + { + offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4; + BFD_ASSERT (g->local_gotno * 4 <= offset + && offset < sgot->_raw_size); + bfd_put_32 (output_bfd, gval, sgot->contents + offset); + } + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + name = h->root.root.string; + if (strcmp (name, "_DYNAMIC") == 0 + || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + else if (strcmp (name, "_DYNAMIC_LINK") == 0) + { + sym->st_shndx = SHN_ABS; + sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + sym->st_value = 1; + } + else if (SGI_COMPAT (output_bfd)) + { + if (strcmp (name, "_gp_disp") == 0) + { + sym->st_shndx = SHN_ABS; + sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + sym->st_value = elf_gp (output_bfd); + } + else if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0 + || strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0) + { + sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + sym->st_other = STO_PROTECTED; + sym->st_value = 0; + sym->st_shndx = SHN_MIPS_DATA; + } + else if (strcmp (name, mips_elf_dynsym_rtproc_names[2]) == 0) + { + sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + sym->st_other = STO_PROTECTED; + sym->st_value = mips_elf_hash_table (info)->procedure_count; + sym->st_shndx = SHN_ABS; + } + else if (sym->st_shndx != SHN_UNDEF) + { + if (h->type == STT_FUNC) + sym->st_shndx = SHN_MIPS_TEXT; + else if (h->type == STT_OBJECT) + sym->st_shndx = SHN_MIPS_DATA; + } + } + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +mips_elf_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sdyn; + asection *sgot; + struct mips_got_info *g; + + dynobj = elf_hash_table (info)->dynobj; + + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + + BFD_ASSERT (elf_section_data (sgot) != NULL); + g = (struct mips_got_info *) elf_section_data (sgot)->tdata; + BFD_ASSERT (g != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + Elf32_External_Dyn *dyncon, *dynconend; + + BFD_ASSERT (sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + size_t elemsize; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_RELENT: + s = bfd_get_section_by_name (dynobj, ".rel.dyn"); + BFD_ASSERT (s != NULL); + dyn.d_un.d_val = sizeof (Elf32_External_Rel); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_STRSZ: + /* Rewrite DT_STRSZ. */ + dyn.d_un.d_val = + _bfd_stringtab_size (elf_hash_table (info)->dynstr); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTGOT: + name = ".got"; + goto get_vma; + case DT_MIPS_CONFLICT: + name = ".conflict"; + goto get_vma; + case DT_MIPS_LIBLIST: + name = ".liblist"; + get_vma: + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_RLD_VERSION: + dyn.d_un.d_val = 1; /* XXX */ + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_FLAGS: + dyn.d_un.d_val = RHF_NOTPOT; /* XXX */ + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_CONFLICTNO: + name = ".conflict"; + elemsize = sizeof (Elf32_Conflict); + goto set_elemno; + + case DT_MIPS_LIBLISTNO: + name = ".liblist"; + elemsize = sizeof (Elf32_Lib); + set_elemno: + s = bfd_get_section_by_name (output_bfd, name); + if (s != NULL) + { + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size / elemsize; + else + dyn.d_un.d_val = s->_raw_size / elemsize; + } + else + dyn.d_un.d_val = 0; + + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_TIME_STAMP: + time ((time_t *) &dyn.d_un.d_val); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_ICHECKSUM: + /* XXX FIXME: */ + break; + + case DT_MIPS_IVERSION: + /* XXX FIXME: */ + break; + + case DT_MIPS_BASE_ADDRESS: + s = output_bfd->sections; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma & ~(0xffff); + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_LOCAL_GOTNO: + dyn.d_un.d_val = g->local_gotno; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_SYMTABNO: + name = ".dynsym"; + elemsize = sizeof (Elf32_External_Sym); + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s != NULL); + + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size / elemsize; + else + dyn.d_un.d_val = s->_raw_size / elemsize; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_UNREFEXTNO: + /* XXX FIXME: */ + dyn.d_un.d_val = SIZEOF_MIPS_DYNSYM_SECNAMES; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_GOTSYM: + dyn.d_un.d_val = g->global_gotsym; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_MIPS_HIPAGENO: + dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + } + } + } + + /* The first entry of the global offset table will be filled at + runtime. The second entry will be used by some runtime loaders. + This isn't the case of Irix rld. */ + if (sgot->_raw_size > 0) + { + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0x80000000, sgot->contents + 4); + } + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + + { + asection *sdynsym; + asection *s; + unsigned int i; + bfd_vma last; + Elf_Internal_Sym sym; + long dindx; + const char *name; + const char * const * namep = mips_elf_dynsym_sec_names; + Elf32_compact_rel cpt; + + /* Set up the section symbols for the output sections. SGI sets + the STT_NOTYPE attribute for these symbols. Should we do so? */ + + sdynsym = bfd_get_section_by_name (dynobj, ".dynsym"); + if (sdynsym != NULL) + { + if (SGI_COMPAT (output_bfd)) + { + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); + sym.st_other = 0; + + i = 0; + while ((name = *namep++) != NULL) + { + s = bfd_get_section_by_name (output_bfd, name); + if (s != NULL) + { + sym.st_value = s->vma; + dindx = elf_section_data (s)->dynindx; + last = s->vma + s->_raw_size; + } + else + { + sym.st_value = last; + dindx++; + } + + sym.st_shndx = (i < MIPS_TEXT_DYNSYM_SECNO + ? SHN_MIPS_TEXT + : SHN_MIPS_DATA); + ++i; + sym.st_name = + mips_elf_hash_table (info)->dynsym_sec_strindex[dindx]; + + bfd_elf32_swap_symbol_out (output_bfd, &sym, + (((Elf32_External_Sym *) + sdynsym->contents) + + dindx)); + } + + /* Set the sh_info field of the output .dynsym section to + the index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + SIZEOF_MIPS_DYNSYM_SECNAMES; + } + else + { + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + int indx; + + sym.st_value = s->vma; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + + bfd_elf32_swap_symbol_out (output_bfd, &sym, + (((Elf32_External_Sym *) + sdynsym->contents) + + elf_section_data (s)->dynindx)); + } + + /* Set the sh_info field of the output .dynsym section to + the index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + bfd_count_sections (output_bfd) + 1; + } + } + + if (SGI_COMPAT (output_bfd)) + { + /* Write .compact_rel section out. */ + s = bfd_get_section_by_name (dynobj, ".compact_rel"); + if (s != NULL) + { + cpt.id1 = 1; + cpt.num = s->reloc_count; + cpt.id2 = 2; + cpt.offset = (s->output_section->filepos + + sizeof (Elf32_External_compact_rel)); + cpt.reserved0 = 0; + cpt.reserved1 = 0; + bfd_elf32_swap_compact_rel_out (output_bfd, &cpt, + ((Elf32_External_compact_rel *) + s->contents)); + + /* Clean up a dummy stub function entry in .text. */ + s = bfd_get_section_by_name (dynobj, ".stub"); + if (s != NULL) + { + file_ptr dummy_offset; + + BFD_ASSERT (s->_raw_size >= MIPS_FUNCTION_STUB_SIZE); + dummy_offset = s->_raw_size - MIPS_FUNCTION_STUB_SIZE; + memset (s->contents + dummy_offset, 0, + MIPS_FUNCTION_STUB_SIZE); + } + } + } + + /* Clean up a first relocation in .rel.dyn. */ + s = bfd_get_section_by_name (dynobj, ".rel.dyn"); + if (s != NULL) + memset (s->contents, 0, sizeof (Elf32_External_Rel)); + } + + return true; +} + +/* This is almost identical to bfd_generic_get_... except that some + MIPS relocations need to be handled specially. Sigh. */ + +static bfd_byte * +elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + if (reloc_size < 0) + goto error_return; + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + /* read in the section */ + if (!bfd_get_section_contents (input_bfd, + input_section, + (PTR) data, + 0, + input_section->_raw_size)) + goto error_return; + + /* We're not relaxing the section, so just copy the size info */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = true; + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + goto error_return; + + if (reloc_count > 0) + { + arelent **parent; + /* for mips */ + int gp_found; + bfd_vma gp = 0x12345678; /* initialize just to shut gcc up */ + + { + struct bfd_hash_entry *h; + struct bfd_link_hash_entry *lh; + /* Skip all this stuff if we aren't mixing formats. */ + if (abfd && input_bfd + && abfd->xvec == input_bfd->xvec) + lh = 0; + else + { + h = bfd_hash_lookup (&link_info->hash->table, "_gp", false, false); + lh = (struct bfd_link_hash_entry *) h; + } + lookup: + if (lh) + { + switch (lh->type) + { + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + case bfd_link_hash_common: + gp_found = 0; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + gp_found = 1; + gp = lh->u.def.value; + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + lh = lh->u.i.link; + /* @@FIXME ignoring warning for now */ + goto lookup; + case bfd_link_hash_new: + default: + abort (); + } + } + else + gp_found = 0; + } + /* end mips */ + for (parent = reloc_vector; *parent != (arelent *) NULL; + parent++) + { + char *error_message = (char *) NULL; + bfd_reloc_status_type r; + + /* Specific to MIPS: Deal with relocation types that require + knowing the gp of the output bfd. */ + asymbol *sym = *(*parent)->sym_ptr_ptr; + if (bfd_is_abs_section (sym->section) && abfd) + { + /* The special_function wouldn't get called anyways. */ + } + else if (!gp_found) + { + /* The gp isn't there; let the special function code + fall over on its own. */ + } + else if ((*parent)->howto->special_function + == mips_elf_gprel16_reloc) + { + /* bypass special_function call */ + r = gprel16_with_gp (input_bfd, sym, *parent, input_section, + relocateable, (PTR) data, gp); + goto skip_bfd_perform_relocation; + } + /* end mips specific stuff */ + + r = bfd_perform_relocation (input_bfd, + *parent, + (PTR) data, + input_section, + relocateable ? abfd : (bfd *) NULL, + &error_message); + skip_bfd_perform_relocation: + + if (relocateable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_dangerous: + BFD_ASSERT (error_message != (char *) NULL); + if (!((*link_info->callbacks->reloc_dangerous) + (link_info, error_message, input_bfd, input_section, + (*parent)->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (!((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (*parent)->howto->name, (*parent)->addend, + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + default: + abort (); + break; + } + + } + } + } + if (reloc_vector != NULL) + free (reloc_vector); + return data; + +error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return NULL; +} +#define bfd_elf32_bfd_get_relocated_section_contents \ + elf32_mips_get_relocated_section_contents + +/* ECOFF swapping routines. These are used when dealing with the + .mdebug section, which is in the ECOFF debugging format. */ +static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap = +{ + /* Symbol table magic number. */ + magicSym, + /* Alignment of debugging information. E.g., 4. */ + 4, + /* Sizes of external symbolic information. */ + sizeof (struct hdr_ext), + sizeof (struct dnr_ext), + sizeof (struct pdr_ext), + sizeof (struct sym_ext), + sizeof (struct opt_ext), + sizeof (struct fdr_ext), + sizeof (struct rfd_ext), + sizeof (struct ext_ext), + /* Functions to swap in external symbolic data. */ + ecoff_swap_hdr_in, + ecoff_swap_dnr_in, + ecoff_swap_pdr_in, + ecoff_swap_sym_in, + ecoff_swap_opt_in, + ecoff_swap_fdr_in, + ecoff_swap_rfd_in, + ecoff_swap_ext_in, + _bfd_ecoff_swap_tir_in, + _bfd_ecoff_swap_rndx_in, + /* Functions to swap out external symbolic data. */ + ecoff_swap_hdr_out, + ecoff_swap_dnr_out, + ecoff_swap_pdr_out, + ecoff_swap_sym_out, + ecoff_swap_opt_out, + ecoff_swap_fdr_out, + ecoff_swap_rfd_out, + ecoff_swap_ext_out, + _bfd_ecoff_swap_tir_out, + _bfd_ecoff_swap_rndx_out, + /* Function to read in symbolic data. */ + mips_elf_read_ecoff_info +}; + +#define TARGET_LITTLE_SYM bfd_elf32_littlemips_vec +#define TARGET_LITTLE_NAME "elf32-littlemips" +#define TARGET_BIG_SYM bfd_elf32_bigmips_vec +#define TARGET_BIG_NAME "elf32-bigmips" +#define ELF_ARCH bfd_arch_mips +#define ELF_MACHINE_CODE EM_MIPS +#define ELF_MAXPAGESIZE 0x10000 +#define elf_backend_collect true +#define elf_backend_type_change_ok true +#define elf_info_to_howto 0 +#define elf_info_to_howto_rel mips_info_to_howto_rel +#define elf_backend_sym_is_global mips_elf_sym_is_global +#define elf_backend_object_p mips_elf_object_p +#define elf_backend_section_from_shdr mips_elf_section_from_shdr +#define elf_backend_fake_sections mips_elf_fake_sections +#define elf_backend_section_from_bfd_section \ + mips_elf_section_from_bfd_section +#define elf_backend_section_processing mips_elf_section_processing +#define elf_backend_symbol_processing mips_elf_symbol_processing +#define elf_backend_additional_program_headers \ + mips_elf_additional_program_headers +#define elf_backend_modify_segment_map mips_elf_modify_segment_map +#define elf_backend_final_write_processing \ + mips_elf_final_write_processing +#define elf_backend_ecoff_debug_swap &mips_elf_ecoff_debug_swap + +#define bfd_elf32_bfd_is_local_label mips_elf_is_local_label +#define bfd_elf32_find_nearest_line mips_elf_find_nearest_line + +#define bfd_elf32_bfd_link_hash_table_create \ + mips_elf_link_hash_table_create +#define bfd_elf32_bfd_final_link mips_elf_final_link +#define bfd_elf32_bfd_copy_private_bfd_data \ + mips_elf_copy_private_bfd_data +#define bfd_elf32_bfd_merge_private_bfd_data \ + mips_elf_merge_private_bfd_data +#define bfd_elf32_bfd_set_private_flags mips_elf_set_private_flags +#define elf_backend_add_symbol_hook mips_elf_add_symbol_hook +#define elf_backend_create_dynamic_sections \ + mips_elf_create_dynamic_sections +#define elf_backend_check_relocs mips_elf_check_relocs +#define elf_backend_adjust_dynamic_symbol \ + mips_elf_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + mips_elf_size_dynamic_sections +#define elf_backend_relocate_section mips_elf_relocate_section +#define elf_backend_finish_dynamic_symbol \ + mips_elf_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + mips_elf_finish_dynamic_sections + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-ppc.c b/contrib/gdb/bfd/elf32-ppc.c new file mode 100644 index 000000000000..a8e5ad3fdb19 --- /dev/null +++ b/contrib/gdb/bfd/elf32-ppc.c @@ -0,0 +1,2554 @@ +/* PowerPC-specific support for 32-bit ELF + Copyright 1994, 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is based on a preliminary PowerPC ELF ABI. The + information may not match the final PowerPC ELF ABI. It includes + suggestions from the in-progress Embedded PowerPC ABI, and that + information may also not match. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/ppc.h" + +#define USE_RELA /* we want RELA relocations, not REL */ + +/* PowerPC relocations defined by the ABIs */ +enum ppc_reloc_type +{ + R_PPC_NONE = 0, + R_PPC_ADDR32 = 1, + R_PPC_ADDR24 = 2, + R_PPC_ADDR16 = 3, + R_PPC_ADDR16_LO = 4, + R_PPC_ADDR16_HI = 5, + R_PPC_ADDR16_HA = 6, + R_PPC_ADDR14 = 7, + R_PPC_ADDR14_BRTAKEN = 8, + R_PPC_ADDR14_BRNTAKEN = 9, + R_PPC_REL24 = 10, + R_PPC_REL14 = 11, + R_PPC_REL14_BRTAKEN = 12, + R_PPC_REL14_BRNTAKEN = 13, + R_PPC_GOT16 = 14, + R_PPC_GOT16_LO = 15, + R_PPC_GOT16_HI = 16, + R_PPC_GOT16_HA = 17, + R_PPC_PLTREL24 = 18, + R_PPC_COPY = 19, + R_PPC_GLOB_DAT = 20, + R_PPC_JMP_SLOT = 21, + R_PPC_RELATIVE = 22, + R_PPC_LOCAL24PC = 23, + R_PPC_UADDR32 = 24, + R_PPC_UADDR16 = 25, + R_PPC_REL32 = 26, + R_PPC_PLT32 = 27, + R_PPC_PLTREL32 = 28, + R_PPC_PLT16_LO = 29, + R_PPC_PLT16_HI = 30, + R_PPC_PLT16_HA = 31, + R_PPC_SDAREL16 = 32, + R_PPC_SECTOFF = 33, + R_PPC_SECTOFF_LO = 34, + R_PPC_SECTOFF_HI = 35, + R_PPC_SECTOFF_HA = 36, + + /* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ + R_PPC_EMB_NADDR32 = 101, + R_PPC_EMB_NADDR16 = 102, + R_PPC_EMB_NADDR16_LO = 103, + R_PPC_EMB_NADDR16_HI = 104, + R_PPC_EMB_NADDR16_HA = 105, + R_PPC_EMB_SDAI16 = 106, + R_PPC_EMB_SDA2I16 = 107, + R_PPC_EMB_SDA2REL = 108, + R_PPC_EMB_SDA21 = 109, + R_PPC_EMB_MRKREF = 110, + R_PPC_EMB_RELSEC16 = 111, + R_PPC_EMB_RELST_LO = 112, + R_PPC_EMB_RELST_HI = 113, + R_PPC_EMB_RELST_HA = 114, + R_PPC_EMB_BIT_FLD = 115, + R_PPC_EMB_RELSDA = 116, + + /* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ + R_PPC_TOC16 = 255, + + R_PPC_max +}; + +static reloc_howto_type *ppc_elf_reloc_type_lookup + PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); +static void ppc_elf_info_to_howto + PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst)); +static void ppc_elf_howto_init PARAMS ((void)); +static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword)); +static boolean ppc_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); + +static int ppc_elf_additional_program_headers PARAMS ((bfd *)); +static boolean ppc_elf_modify_segment_map PARAMS ((bfd *)); + +static boolean ppc_elf_section_from_shdr PARAMS ((bfd *, + Elf32_Internal_Shdr *, + char *)); + +static elf_linker_section_t *ppc_elf_create_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + enum elf_linker_section_enum)); + +static boolean ppc_elf_check_relocs PARAMS ((bfd *, + struct bfd_link_info *, + asection *, + const Elf_Internal_Rela *)); + +static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, + struct elf_link_hash_entry *)); + +static boolean ppc_elf_adjust_dynindx PARAMS ((struct elf_link_hash_entry *, PTR)); + +static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); + +static boolean ppc_elf_relocate_section PARAMS ((bfd *, + struct bfd_link_info *info, + bfd *, + asection *, + bfd_byte *, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **)); + +static boolean ppc_elf_add_symbol_hook PARAMS ((bfd *, + struct bfd_link_info *, + const Elf_Internal_Sym *, + const char **, + flagword *, + asection **, + bfd_vma *)); + +static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *, + struct bfd_link_info *, + struct elf_link_hash_entry *, + Elf_Internal_Sym *)); + +static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); + +#define BRANCH_PREDICT_BIT 0x200000 /* branch prediction bit for branch taken relocs */ +#define RA_REGISTER_MASK 0x001f0000 /* mask to set RA in memory instructions */ +#define RA_REGISTER_SHIFT 16 /* value to shift register by to insert RA */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" + + +static reloc_howto_type *ppc_elf_howto_table[ (int)R_PPC_max ]; + +static reloc_howto_type ppc_elf_howto_raw[] = +{ + /* This reloc does nothing. */ + HOWTO (R_PPC_NONE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A standard 32 bit relocation. */ + HOWTO (R_PPC_ADDR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* An absolute 26 bit branch; the lower two bits must be zero. + FIXME: we don't check that, we just clear them. */ + HOWTO (R_PPC_ADDR24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR24", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* A standard 16 bit relocation. */ + HOWTO (R_PPC_ADDR16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 16 bit relocation without overflow. */ + HOWTO (R_PPC_ADDR16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR16_LO", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high order 16 bits of an address. */ + HOWTO (R_PPC_ADDR16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR16_HI", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high order 16 bits of an address, plus 1 if the contents of + the low 16 bits, treated as a signed number, is negative. */ + HOWTO (R_PPC_ADDR16_HA, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR16_HA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* An absolute 16 bit branch; the lower two bits must be zero. + FIXME: we don't check that, we just clear them. */ + HOWTO (R_PPC_ADDR14, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR14", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* An absolute 16 bit branch, for which bit 10 should be set to + indicate that the branch is expected to be taken. The lower two + bits must be zero. */ + HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR14_BRTAKEN",/* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* An absolute 16 bit branch, for which bit 10 should be set to + indicate that the branch is not expected to be taken. The lower + two bits must be zero. */ + HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_ADDR14_BRNTAKEN",/* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + false), /* pcrel_offset */ + + /* A relative 26 bit branch; the lower two bits must be zero. */ + HOWTO (R_PPC_REL24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL24", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0x3fffffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* A relative 16 bit branch; the lower two bits must be zero. */ + HOWTO (R_PPC_REL14, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL14", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* A relative 16 bit branch. Bit 10 should be set to indicate that + the branch is expected to be taken. The lower two bits must be + zero. */ + HOWTO (R_PPC_REL14_BRTAKEN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL14_BRTAKEN", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* A relative 16 bit branch. Bit 10 should be set to indicate that + the branch is not expected to be taken. The lower two bits must + be zero. */ + HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL14_BRNTAKEN",/* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xfffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* Like R_PPC_ADDR16, but referring to the GOT table entry for the + symbol. */ + HOWTO (R_PPC_GOT16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_GOT16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_PPC_GOT16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_GOT16_LO", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_PPC_GOT16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_GOT16_HI", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for + the symbol. */ + HOWTO (R_PPC_GOT16_HA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_GOT16_HA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_REL24, but referring to the procedure linkage table + entry for the symbol. FIXME: Not supported. */ + HOWTO (R_PPC_PLTREL24, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLTREL24", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0x3fffffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* This is used only by the dynamic linker. The symbol should exist + both in the object being run and in some shared library. The + dynamic linker copies the data addressed by the symbol from the + shared library into the object. I have no idea what the purpose + of this is. */ + HOWTO (R_PPC_COPY, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_COPY", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR32, but used when setting global offset table + entries. */ + HOWTO (R_PPC_GLOB_DAT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_GLOB_DAT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Marks a procedure linkage table entry for a symbol. */ + HOWTO (R_PPC_JMP_SLOT, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_JMP_SLOT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Used only by the dynamic linker. When the object is run, this + longword is set to the load address of the object, plus the + addend. */ + HOWTO (R_PPC_RELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_RELATIVE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_REL24, but uses the value of the symbol within the + object rather than the final value. Normally used for + _GLOBAL_OFFSET_TABLE_. FIXME: Not supported. */ + HOWTO (R_PPC_LOCAL24PC, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_LOCAL24PC", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0x3fffffc, /* dst_mask */ + true), /* pcrel_offset */ + + /* Like R_PPC_ADDR32, but may be unaligned. */ + HOWTO (R_PPC_UADDR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_UADDR32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16, but may be unaligned. */ + HOWTO (R_PPC_UADDR16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_UADDR16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32-bit PC relative */ + HOWTO (R_PPC_REL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* 32-bit relocation to the symbol's procedure linkage table. + FIXEME: not supported. */ + HOWTO (R_PPC_PLT32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLT32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32-bit PC relative relocation to the symbol's procedure linkage table. + FIXEME: not supported. */ + HOWTO (R_PPC_PLTREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLTREL32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for + the symbol. */ + HOWTO (R_PPC_PLT16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLT16_LO", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for + the symbol. */ + HOWTO (R_PPC_PLT16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLT16_HI", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for + the symbol. FIXME: Not supported. */ + HOWTO (R_PPC_PLT16_HA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_PLT16_HA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with + small data items. */ + HOWTO (R_PPC_SDAREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_SDAREL16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32-bit section relative relocation. */ + HOWTO (R_PPC_SECTOFF, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_SECTOFF", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + true), /* pcrel_offset */ + + /* 16-bit lower half section relative relocation. */ + HOWTO (R_PPC_SECTOFF_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_SECTOFF_LO", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16-bit upper half section relative relocation. */ + HOWTO (R_PPC_SECTOFF_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_SECTOFF_HI", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16-bit upper half adjusted section relative relocation. */ + HOWTO (R_PPC_SECTOFF_HA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_SECTOFF_HA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ + + /* 32 bit value resulting from the addend minus the symbol */ + HOWTO (R_PPC_EMB_NADDR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_NADDR32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit value resulting from the addend minus the symbol */ + HOWTO (R_PPC_EMB_NADDR16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_NADDR16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit value resulting from the addend minus the symbol */ + HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_ADDR16_LO", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high order 16 bits of the addend minus the symbol */ + HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_NADDR16_HI", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high order 16 bits of the result of the addend minus the address, + plus 1 if the contents of the low 16 bits, treated as a signed number, + is negative. */ + HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_NADDR16_HA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit value resulting from allocating a 4 byte word to hold an + address in the .sdata section, and returning the offset from + _SDA_BASE_ for that relocation */ + HOWTO (R_PPC_EMB_SDAI16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_SDAI16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit value resulting from allocating a 4 byte word to hold an + address in the .sdata2 section, and returning the offset from + _SDA2_BASE_ for that relocation */ + HOWTO (R_PPC_EMB_SDA2I16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_SDA2I16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with + small data items. */ + HOWTO (R_PPC_EMB_SDA2REL, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_SDA2REL", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit + signed offset from the appropriate base, and filling in the register + field with the appropriate register (0, 2, or 13). */ + HOWTO (R_PPC_EMB_SDA21, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_SDA21", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Relocation not handled: R_PPC_EMB_MRKREF */ + /* Relocation not handled: R_PPC_EMB_RELSEC16 */ + /* Relocation not handled: R_PPC_EMB_RELST_LO */ + /* Relocation not handled: R_PPC_EMB_RELST_HI */ + /* Relocation not handled: R_PPC_EMB_RELST_HA */ + /* Relocation not handled: R_PPC_EMB_BIT_FLD */ + + /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling + in the 16 bit signed offset from the appropriate base, and filling in the + register field with the appropriate register (0, 2, or 13). */ + HOWTO (R_PPC_EMB_RELSDA, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_EMB_RELSDA", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Phony reloc to handle AIX style TOC entries */ + HOWTO (R_PPC_TOC16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_TOC16", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ +}; + + +/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ + +static void +ppc_elf_howto_init () +{ + unsigned int i, type; + + for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++) + { + type = ppc_elf_howto_raw[i].type; + BFD_ASSERT (type < sizeof(ppc_elf_howto_table) / sizeof(ppc_elf_howto_table[0])); + ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; + } +} + + +static reloc_howto_type * +ppc_elf_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + enum ppc_reloc_type ppc_reloc = R_PPC_NONE; + + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); + + switch ((int)code) + { + default: + return (reloc_howto_type *)NULL; + + case BFD_RELOC_NONE: ppc_reloc = R_PPC_NONE; break; + case BFD_RELOC_32: ppc_reloc = R_PPC_ADDR32; break; + case BFD_RELOC_PPC_BA26: ppc_reloc = R_PPC_ADDR24; break; + case BFD_RELOC_16: ppc_reloc = R_PPC_ADDR16; break; + case BFD_RELOC_LO16: ppc_reloc = R_PPC_ADDR16_LO; break; + case BFD_RELOC_HI16: ppc_reloc = R_PPC_ADDR16_HI; break; + case BFD_RELOC_HI16_S: ppc_reloc = R_PPC_ADDR16_HA; break; + case BFD_RELOC_PPC_BA16: ppc_reloc = R_PPC_ADDR14; break; + case BFD_RELOC_PPC_BA16_BRTAKEN: ppc_reloc = R_PPC_ADDR14_BRTAKEN; break; + case BFD_RELOC_PPC_BA16_BRNTAKEN: ppc_reloc = R_PPC_ADDR14_BRNTAKEN; break; + case BFD_RELOC_PPC_B26: ppc_reloc = R_PPC_REL24; break; + case BFD_RELOC_PPC_B16: ppc_reloc = R_PPC_REL14; break; + case BFD_RELOC_PPC_B16_BRTAKEN: ppc_reloc = R_PPC_REL14_BRTAKEN; break; + case BFD_RELOC_PPC_B16_BRNTAKEN: ppc_reloc = R_PPC_REL14_BRNTAKEN; break; + case BFD_RELOC_16_GOTOFF: ppc_reloc = R_PPC_GOT16; break; + case BFD_RELOC_LO16_GOTOFF: ppc_reloc = R_PPC_GOT16_LO; break; + case BFD_RELOC_HI16_GOTOFF: ppc_reloc = R_PPC_GOT16_HI; break; + case BFD_RELOC_HI16_S_GOTOFF: ppc_reloc = R_PPC_GOT16_HA; break; + case BFD_RELOC_24_PLT_PCREL: ppc_reloc = R_PPC_PLTREL24; break; + case BFD_RELOC_PPC_COPY: ppc_reloc = R_PPC_COPY; break; + case BFD_RELOC_PPC_GLOB_DAT: ppc_reloc = R_PPC_GLOB_DAT; break; + case BFD_RELOC_PPC_LOCAL24PC: ppc_reloc = R_PPC_LOCAL24PC; break; + case BFD_RELOC_32_PCREL: ppc_reloc = R_PPC_REL32; break; + case BFD_RELOC_32_PLTOFF: ppc_reloc = R_PPC_PLT32; break; + case BFD_RELOC_32_PLT_PCREL: ppc_reloc = R_PPC_PLTREL32; break; + case BFD_RELOC_LO16_PLTOFF: ppc_reloc = R_PPC_PLT16_LO; break; + case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break; + case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break; + case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break; + case BFD_RELOC_32_BASEREL: ppc_reloc = R_PPC_SECTOFF; break; + case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break; + case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break; + case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break; + case BFD_RELOC_CTOR: ppc_reloc = R_PPC_ADDR32; break; + case BFD_RELOC_PPC_TOC16: ppc_reloc = R_PPC_TOC16; break; + case BFD_RELOC_PPC_EMB_NADDR32: ppc_reloc = R_PPC_EMB_NADDR32; break; + case BFD_RELOC_PPC_EMB_NADDR16: ppc_reloc = R_PPC_EMB_NADDR16; break; + case BFD_RELOC_PPC_EMB_NADDR16_LO: ppc_reloc = R_PPC_EMB_NADDR16_LO; break; + case BFD_RELOC_PPC_EMB_NADDR16_HI: ppc_reloc = R_PPC_EMB_NADDR16_HI; break; + case BFD_RELOC_PPC_EMB_NADDR16_HA: ppc_reloc = R_PPC_EMB_NADDR16_HA; break; + case BFD_RELOC_PPC_EMB_SDAI16: ppc_reloc = R_PPC_EMB_SDAI16; break; + case BFD_RELOC_PPC_EMB_SDA2I16: ppc_reloc = R_PPC_EMB_SDA2I16; break; + case BFD_RELOC_PPC_EMB_SDA2REL: ppc_reloc = R_PPC_EMB_SDA2REL; break; + case BFD_RELOC_PPC_EMB_SDA21: ppc_reloc = R_PPC_EMB_SDA21; break; + case BFD_RELOC_PPC_EMB_MRKREF: ppc_reloc = R_PPC_EMB_MRKREF; break; + case BFD_RELOC_PPC_EMB_RELSEC16: ppc_reloc = R_PPC_EMB_RELSEC16; break; + case BFD_RELOC_PPC_EMB_RELST_LO: ppc_reloc = R_PPC_EMB_RELST_LO; break; + case BFD_RELOC_PPC_EMB_RELST_HI: ppc_reloc = R_PPC_EMB_RELST_HI; break; + case BFD_RELOC_PPC_EMB_RELST_HA: ppc_reloc = R_PPC_EMB_RELST_HA; break; + case BFD_RELOC_PPC_EMB_BIT_FLD: ppc_reloc = R_PPC_EMB_BIT_FLD; break; + case BFD_RELOC_PPC_EMB_RELSDA: ppc_reloc = R_PPC_EMB_RELSDA; break; + } + + return ppc_elf_howto_table[ (int)ppc_reloc ]; +}; + +/* Set the howto pointer for a PowerPC ELF reloc. */ + +static void +ppc_elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; +{ + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); + + BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); + cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; +} + +/* Function to set whether a module needs the -mrelocatable bit set. */ + +static boolean +ppc_elf_set_private_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + BFD_ASSERT (!elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags = flags; + elf_flags_init (abfd) = true; + return true; +} + +/* Copy backend specific data from one object module to another */ +static boolean +ppc_elf_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + BFD_ASSERT (!elf_flags_init (obfd) + || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags); + + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_flags_init (obfd) = true; + return true; +} + +/* Merge backend specific data from an object file to the output + object file when linking */ +static boolean +ppc_elf_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + flagword old_flags; + flagword new_flags; + boolean error; + + /* Check if we have the same endianess */ + if (ibfd->xvec->byteorder != obfd->xvec->byteorder + && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) + { + (*_bfd_error_handler) + ("%s: compiled for a %s endian system and target is %s endian", + bfd_get_filename (ibfd), + bfd_big_endian (ibfd) ? "big" : "little", + bfd_big_endian (obfd) ? "big" : "little"); + + bfd_set_error (bfd_error_wrong_format); + return false; + } + + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + new_flags = elf_elfheader (ibfd)->e_flags; + old_flags = elf_elfheader (obfd)->e_flags; + if (!elf_flags_init (obfd)) /* First call, no flags set */ + { + elf_flags_init (obfd) = true; + elf_elfheader (obfd)->e_flags = new_flags; + } + + else if (new_flags == old_flags) /* Compatible flags are ok */ + ; + + else /* Incompatible flags */ + { + /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib to be linked + with either. */ + error = false; + if ((new_flags & EF_PPC_RELOCATABLE) != 0 + && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) + { + error = true; + (*_bfd_error_handler) + ("%s: compiled with -mrelocatable and linked with modules compiled normally", + bfd_get_filename (ibfd)); + } + else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 + && (old_flags & EF_PPC_RELOCATABLE) != 0) + { + error = true; + (*_bfd_error_handler) + ("%s: compiled normally and linked with modules compiled with -mrelocatable", + bfd_get_filename (ibfd)); + } + else if ((new_flags & EF_PPC_RELOCATABLE_LIB) != 0) + elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE_LIB; + + + /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */ + elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); + + new_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); + old_flags &= ~ (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); + + /* Warn about any other mismatches */ + if (new_flags != old_flags) + { + error = true; + (*_bfd_error_handler) + ("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)", + bfd_get_filename (ibfd), (long)new_flags, (long)old_flags); + } + + if (error) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + return true; +} + + +/* Handle a PowerPC specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. */ + +static boolean +ppc_elf_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf32_Internal_Shdr *hdr; + char *name; +{ + asection *newsect; + flagword flags; + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + + newsect = hdr->bfd_section; + flags = bfd_get_section_flags (abfd, newsect); + if (hdr->sh_flags & SHF_EXCLUDE) + flags |= SEC_EXCLUDE; + + if (hdr->sh_type == SHT_ORDERED) + flags |= SEC_SORT_ENTRIES; + + bfd_set_section_flags (abfd, newsect, flags); + return true; +} + + +/* Set up any other section flags and such that may be necessary. */ + +boolean +ppc_elf_fake_sections (abfd, shdr, asect) + bfd *abfd; + Elf32_Internal_Shdr *shdr; + asection *asect; +{ + if ((asect->flags & SEC_EXCLUDE) != 0) + shdr->sh_flags |= SHF_EXCLUDE; + + if ((asect->flags & SEC_SORT_ENTRIES) != 0) + shdr->sh_type = SHT_ORDERED; +} + + +/* Create a special linker section */ +static elf_linker_section_t * +ppc_elf_create_linker_section (abfd, info, which) + bfd *abfd; + struct bfd_link_info *info; + enum elf_linker_section_enum which; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; + + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; + + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) + { + elf_linker_section_t defaults; + static elf_linker_section_t zero_section; + + defaults = zero_section; + defaults.which = which; + defaults.hole_written_p = false; + defaults.alignment = 2; + defaults.flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + switch (which) + { + default: + (*_bfd_error_handler) ("%s: Unknown special linker type %d", + bfd_get_filename (abfd), + (int)which); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + + case LINKER_SECTION_GOT: /* .got section */ + defaults.name = ".got"; + defaults.rel_name = ".rela.got"; + defaults.sym_name = "_GLOBAL_OFFSET_TABLE_"; + defaults.max_hole_offset = 32764; + defaults.hole_size = 16; + defaults.sym_offset = 4; + break; + + case LINKER_SECTION_SDATA: /* .sdata/.sbss section */ + defaults.name = ".sdata"; + defaults.rel_name = ".rela.sdata"; + defaults.bss_name = ".sbss"; + defaults.sym_name = "_SDA_BASE_"; + defaults.sym_offset = 32768; + break; + + case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ + defaults.name = ".sdata2"; + defaults.rel_name = ".rela.sdata2"; + defaults.bss_name = ".sbss2"; + defaults.sym_name = "_SDA2_BASE_"; + defaults.sym_offset = 32768; + defaults.flags |= SEC_READONLY; + break; + } + + lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults); + } + + return lsect; +} + + +/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we need to bump up + the number of section headers. */ + +static int +ppc_elf_additional_program_headers (abfd) + bfd *abfd; +{ + asection *s; + int ret; + + ret = 0; + + s = bfd_get_section_by_name (abfd, ".sbss2"); + if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) + ++ret; + + s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); + if (s != NULL && (s->flags & SEC_LOAD) != 0 && s->_raw_size > 0) + ++ret; + + return ret; +} + +/* Modify the segment map if needed */ + +static boolean +ppc_elf_modify_segment_map (abfd) + bfd *abfd; +{ + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +ppc_elf_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ +#ifdef DEBUG + fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called\n"); +#endif + return true; +} + + +/* Increment the index of a dynamic symbol by a given amount. Called + via elf_link_hash_traverse. */ + +static boolean +ppc_elf_adjust_dynindx (h, cparg) + struct elf_link_hash_entry *h; + PTR cparg; +{ + int *cp = (int *) cparg; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_adjust_dynindx called, h->dynindx = %d, *cp = %d\n", h->dynindx, *cp); +#endif + + if (h->dynindx != -1) + h->dynindx += *cp; + + return true; +} + + +/* Set the sizes of the dynamic sections. */ + +static boolean +ppc_elf_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean reltext; + boolean relplt; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); +#endif + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + + /* Make space for the trailing nop in .plt. */ + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + if (s->_raw_size > 0) + s->_raw_size += 4; + } + else + { + /* We may have created entries in the .rela.got, .rela.sdata, and + .rela.sdata2 section2. However, if we are not creating the + dynamic sections, we will not actually use these entries. Reset + the size of .rela.got, et al, which will cause it to get + stripped from the output file below. */ + static char *rela_sections[] = { ".rela.got", ".rela.sdata", ".rela.sdata", (char *)0 }; + char **p; + + for (p = rela_sections; *p != (char *)0; p++) + { + s = bfd_get_section_by_name (dynobj, *p); + if (s != NULL) + s->_raw_size = 0; + } + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + reltext = false; + relplt = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + if ((s->flags & SEC_IN_MEMORY) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + strip = false; + +#if 0 + if (strncmp (name, ".rela", 5) == 0) + { + if (s->_raw_size == 0) + { + /* If we don't need this section, strip it from the + output file. This is to handle .rela.bss and + .rel.plt. We must create it in + create_dynamic_sections, because it must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + strip = true; + } + else + { + asection *target; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL entry. */ + target = bfd_get_section_by_name (output_bfd, name + 5); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + + if (strcmp (name, ".rela.plt") == 0) + relplt = true; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else +#endif + if (strcmp (name, ".plt") != 0 + && strcmp (name, ".got") != 0 + && strcmp (name, ".sdata") != 0 + && strcmp (name, ".sdata2") != 0 + && strcmp (name, ".rela.sdata") != 0 + && strcmp (name, ".rela.sdata2") != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in ppc_elf_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (! info->shared) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)) + return false; + + if (relplt) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA) + || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT, + sizeof (Elf32_External_Rela))) + return false; + + if (reltext) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + } + + /* If we are generating a shared library, we generate a section + symbol for each output section. These are local symbols, which + means that they must come first in the dynamic symbol table. + That means we must increment the dynamic symbol index of every + other dynamic symbol. */ + if (info->shared) + { + int c, i; + + c = bfd_count_sections (output_bfd); + elf_link_hash_traverse (elf_hash_table (info), + ppc_elf_adjust_dynindx, + (PTR) &c); + elf_hash_table (info)->dynsymcount += c; + + for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++) + { + elf_section_data (s)->dynindx = i; + /* These symbols will have no names, so we don't need to + fiddle with dynstr_index. */ + } + } + + return true; +} + + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table or procedure linkage + table. */ + +static boolean +ppc_elf_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + elf_linker_section_t *got; + elf_linker_section_t *sdata; + elf_linker_section_t *sdata2; + asection *sreloc; + + if (info->relocateable) + return true; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_check_relocs called for section %s\n", + bfd_get_section_name (abfd, sec)); +#endif + + /* Create the linker generated sections all the time so that the special + symbols are created. */ + if ((got = elf_linker_section (abfd, LINKER_SECTION_GOT)) == NULL) + { + got = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_GOT); + if (!got) + return false; + } + + if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL) + { + sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); + if (!sdata) + return false; + } + + + if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL) + { + sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2); + if (!sdata2) + return false; + } + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + default: + break; + + /* GOT16 relocations */ + case R_PPC_GOT16: + case R_PPC_GOT16_LO: + case R_PPC_GOT16_HI: + case R_PPC_GOT16_HA: + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; + + if (!bfd_elf32_create_pointer_linker_section (abfd, info, got, h, rel)) + return false; + + break; + + /* Indirect .sdata relocation */ + case R_PPC_EMB_SDAI16: + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; + + if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel)) + return false; + + break; + + /* Indirect .sdata2 relocation */ + case R_PPC_EMB_SDA2I16: + if (got->rel_section == NULL + && (h != NULL || info->shared) + && !_bfd_elf_make_linker_section_rela (dynobj, got, 2)) + return false; + + if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel)) + return false; + + break; + +#if 0 + case R_PPC_PLT32: + case R_PPC_PLTREL24: + case R_PPC_PLT16_LO: + case R_PPC_PLT16_HI: + case R_PPC_PLT16_HA: +#ifdef DEBUG + fprintf (stderr, "Reloc requires a PLT entry\n"); +#endif + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code without + linking in any dynamic objects, in which case we don't + need to generate a procedure linkage table after all. */ + + if (h == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a local symbol. */ + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + break; + + case R_SPARC_PC10: + case R_SPARC_PC22: + if (h != NULL + && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ + case R_SPARC_DISP8: + case R_SPARC_DISP16: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: + case R_SPARC_WDISP22: + if (h == NULL) + break; + /* Fall through. */ + case R_SPARC_8: + case R_SPARC_16: + case R_SPARC_32: + case R_SPARC_HI22: + case R_SPARC_22: + case R_SPARC_13: + case R_SPARC_LO10: + case R_SPARC_UA32: + if (info->shared + && (sec->flags & SEC_ALLOC) != 0) + { + /* When creating a shared object, we must copy these + relocs into the output file. We create a reloc + section in dynobj and make room for the reloc. */ + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || ! bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, sreloc, 2)) + return false; + } + } + + sreloc->_raw_size += sizeof (Elf32_External_Rela); + } + + break; +#endif + } + } + + return true; +} + + +/* Hook called by the linker routine which adds symbols from an object + file. We use it to put .comm items in .sbss, and not .bss. */ + +/*ARGSUSED*/ +static boolean +ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp; + asection **secp; + bfd_vma *valp; +{ + if (sym->st_shndx == SHN_COMMON && sym->st_size <= bfd_get_gp_size (abfd)) + { + /* Common symbols less than or equal to -G nn bytes are automatically + put into .sdata. */ + elf_linker_section_t *sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA); + if (!sdata->bss_section) + { + sdata->bss_section = bfd_make_section (elf_hash_table (info)->dynobj, sdata->bss_name); + sdata->bss_section->flags = (sdata->bss_section->flags & ~SEC_LOAD) | SEC_IS_COMMON; + } + + *secp = sdata->bss_section; + *valp = sym->st_size; + } + + return true; +} + + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s\n", h->root.root.string); +#endif + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (h->plt_offset != (bfd_vma) -1) + { + asection *splt; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = bfd_get_section_by_name (dynobj, ".plt"); + srela = bfd_get_section_by_name (dynobj, ".rela.plt"); + BFD_ASSERT (splt != NULL && srela != NULL); + + /* Fill in the entry in the procedure linkage table. */ +#if 0 + bfd_put_32 (output_bfd, + PLT_ENTRY_WORD0 + h->plt_offset, + splt->contents + h->plt_offset); + bfd_put_32 (output_bfd, + (PLT_ENTRY_WORD1 + + (((- (h->plt_offset + 4)) >> 2) & 0x3fffff)), + splt->contents + h->plt_offset + 4); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD2, + splt->contents + h->plt_offset + 8); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_JMP_SLOT); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) srela->contents + + h->plt_offset / PLT_ENTRY_SIZE - 4)); +#endif + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + asection *s; + Elf_Internal_Rela rela; + + /* This symbols needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rela.bss"); + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) s->contents + + s->reloc_count)); + ++s->reloc_count; + } + + /* Mark some specially defined symbols as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 + || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return true; +} + + +/* Finish up the dynamic sections. */ + +static boolean +ppc_elf_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + asection *sdyn; + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *got = elf_linker_section (dynobj, LINKER_SECTION_GOT); + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); +#endif + + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + boolean size; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + case DT_PLTGOT: name = ".plt"; size = false; break; + case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; + case DT_JMPREL: name = ".rela.plt"; size = false; break; + default: name = NULL; size = false; break; + } + + if (name != NULL) + { + asection *s; + + s = bfd_get_section_by_name (output_bfd, name); + if (s == NULL) + dyn.d_un.d_val = 0; + else + { + if (! size) + dyn.d_un.d_ptr = s->vma; + else + { + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + } + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + } + + /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can + easily find the address of the _GLOBAL_OFFSET_TABLE_. */ + if (got) + { + unsigned char *contents = got->section->contents + got->hole_offset; + bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, contents); + + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + contents+4); + + elf_section_data (got->section->output_section)->this_hdr.sh_entsize = 4; + } + + if (info->shared) + { + asection *sdynsym; + asection *s; + Elf_Internal_Sym sym; + + /* Set up the section symbols for the output sections. */ + + sdynsym = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (sdynsym != NULL); + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + int indx; + + sym.st_value = s->vma; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + + bfd_elf32_swap_symbol_out (output_bfd, &sym, + (PTR) (((Elf32_External_Sym *) + sdynsym->contents) + + elf_section_data (s)->dynindx)); + } + + /* Set the sh_info field of the output .dynsym section to the + index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + bfd_count_sections (output_bfd) + 1; + } + + return true; +} + + +/* The RELOCATE_SECTION function is called by the ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjust the section contents as + necessary, and (if using Rela relocs and generating a + relocateable output file) adjusting the reloc addend as + necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocateable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + +static boolean +ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *got = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_GOT) : NULL; + elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL; + elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL; + Elf_Internal_Rela *rel = relocs; + Elf_Internal_Rela *relend = relocs + input_section->reloc_count; + boolean ret = true; + long insn; + +#ifdef DEBUG + fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n", + bfd_get_filename (input_bfd), + bfd_section_name(input_bfd, input_section), + (long)input_section->reloc_count, + (info->relocateable) ? " (relocatable)" : ""); +#endif + + if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */ + ppc_elf_howto_init (); + + for (; rel < relend; rel++) + { + enum ppc_reloc_type r_type = (enum ppc_reloc_type)ELF32_R_TYPE (rel->r_info); + bfd_vma offset = rel->r_offset; + bfd_vma addend = rel->r_addend; + bfd_reloc_status_type r = bfd_reloc_other; + Elf_Internal_Sym *sym = (Elf_Internal_Sym *)0; + asection *sec = (asection *)0; + struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)0; + const char *sym_name = (const char *)0; + reloc_howto_type *howto; + unsigned long r_symndx; + bfd_vma relocation; + + /* Unknown relocation handling */ + if ((unsigned)r_type >= (unsigned)R_PPC_max || !ppc_elf_howto_table[(int)r_type]) + { + (*_bfd_error_handler) ("%s: unknown relocation type %d", + bfd_get_filename (input_bfd), + (int)r_type); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + + howto = ppc_elf_howto_table[(int)r_type]; + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if ((unsigned)ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + addend = rel->r_addend += sec->output_offset + sym->st_value; + } + } + +#ifdef DEBUG + fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n", + howto->name, + (int)r_type, + r_symndx, + (long)offset, + (long)addend); +#endif + continue; + } + + /* This is a final link. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + sym_name = ""; + + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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_name = h->root.root.string; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared) + relocation = 0; + else + { + (*info->callbacks->undefined_symbol)(info, + h->root.root.string, + input_bfd, + input_section, + rel->r_offset); + ret = false; + continue; + } + } + + switch ((int)r_type) + { + default: + (*_bfd_error_handler) ("%s: unknown relocation type %d for symbol %s", + bfd_get_filename (input_bfd), + (int)r_type, sym_name); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + + /* relocations that need no special processing */ + case (int)R_PPC_NONE: + case (int)R_PPC_ADDR32: + case (int)R_PPC_ADDR24: + case (int)R_PPC_ADDR16: + case (int)R_PPC_ADDR16_LO: + case (int)R_PPC_ADDR16_HI: + case (int)R_PPC_ADDR14: + case (int)R_PPC_REL24: + case (int)R_PPC_REL14: + case (int)R_PPC_UADDR32: + case (int)R_PPC_UADDR16: + case (int)R_PPC_REL32: + break; + + /* branch taken prediction relocations */ + case (int)R_PPC_ADDR14_BRTAKEN: + case (int)R_PPC_REL14_BRTAKEN: + insn = bfd_get_32 (output_bfd, contents + offset); + if ((relocation - offset) & 0x8000) + insn &= ~BRANCH_PREDICT_BIT; + else + insn |= BRANCH_PREDICT_BIT; + bfd_put_32 (output_bfd, insn, contents + offset); + break; + + /* branch not taken predicition relocations */ + case (int)R_PPC_ADDR14_BRNTAKEN: + case (int)R_PPC_REL14_BRNTAKEN: + insn = bfd_get_32 (output_bfd, contents + offset); + if ((relocation - offset) & 0x8000) + insn |= BRANCH_PREDICT_BIT; + else + insn &= ~BRANCH_PREDICT_BIT; + bfd_put_32 (output_bfd, insn, contents + offset); + break; + + /* GOT16 relocations */ + case (int)R_PPC_GOT16: + case (int)R_PPC_GOT16_LO: + case (int)R_PPC_GOT16_HI: + case (int)R_PPC_GOT16_HA: + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + got, h, relocation, rel, + R_PPC_RELATIVE); + break; + + /* Indirect .sdata relocation */ + case (int)R_PPC_EMB_SDAI16: + BFD_ASSERT (sdata != NULL); + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + sdata, h, relocation, rel, + R_PPC_RELATIVE); + break; + + /* Indirect .sdata2 relocation */ + case (int)R_PPC_EMB_SDA2I16: + BFD_ASSERT (sdata2 != NULL); + relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info, + sdata2, h, relocation, rel, + R_PPC_RELATIVE); + break; + + /* Handle the TOC16 reloc. We want to use the offset within the .got + section, not the actual VMA. This is appropriate when generating + an embedded ELF object, for which the .got section acts like the + AIX .toc section. */ + case (int)R_PPC_TOC16: /* phony GOT16 relocations */ + BFD_ASSERT (sec != (asection *)0); + BFD_ASSERT (bfd_is_und_section (sec) + || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 + || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0) + + addend -= sec->output_section->vma + sec->output_offset + 0x8000; + break; + + /* arithmetic adjust relocations */ + case (int)R_PPC_ADDR16_HA: + BFD_ASSERT (sec != (asection *)0); + addend += ((relocation + addend) & 0x8000) << 1; + break; + + /* relocate against _SDA_BASE_ */ + case (int)R_PPC_SDAREL16: + BFD_ASSERT (sec != (asection *)0); + if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0 + && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0) + { + (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", + bfd_get_filename (input_bfd), + sym_name, + ppc_elf_howto_table[ (int)r_type ]->name, + bfd_get_section_name (abfd, sec)); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + addend -= (sdata->sym_hash->root.u.def.value + + sdata->sym_hash->root.u.def.section->output_section->vma + + sdata->sym_hash->root.u.def.section->output_offset); + break; + + + /* relocate against _SDA2_BASE_ */ + case (int)R_PPC_EMB_SDA2REL: + BFD_ASSERT (sec != (asection *)0); + if (strcmp (bfd_get_section_name (abfd, sec), ".sdata2") != 0 + && strcmp (bfd_get_section_name (abfd, sec), ".sbss2") != 0) + { + (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", + bfd_get_filename (input_bfd), + sym_name, + ppc_elf_howto_table[ (int)r_type ]->name, + bfd_get_section_name (abfd, sec)); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + addend -= (sdata2->sym_hash->root.u.def.value + + sdata2->sym_hash->root.u.def.section->output_section->vma + + sdata2->sym_hash->root.u.def.section->output_offset); + break; + + + /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */ + case (int)R_PPC_EMB_SDA21: + case (int)R_PPC_EMB_RELSDA: + { + const char *name = bfd_get_section_name (abfd, sec); + int reg; + + BFD_ASSERT (sec != (asection *)0); + if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0) + { + reg = 13; + addend -= (sdata->sym_hash->root.u.def.value + + sdata->sym_hash->root.u.def.section->output_section->vma + + sdata->sym_hash->root.u.def.section->output_offset); + } + + else if (strcmp (name, ".sdata2") == 0 || strcmp (name, ".sbss2") == 0) + { + reg = 2; + addend -= (sdata2->sym_hash->root.u.def.value + + sdata2->sym_hash->root.u.def.section->output_section->vma + + sdata2->sym_hash->root.u.def.section->output_offset); + } + + else if (strcmp (name, ".PPC.EMB.sdata0") == 0 || strcmp (name, ".PPC.EMB.sbss0") == 0) + { + reg = 0; + } + + else + { + (*_bfd_error_handler) ("%s: The target (%s) of a %s relocation is in the wrong section (%s)", + bfd_get_filename (input_bfd), + sym_name, + ppc_elf_howto_table[ (int)r_type ]->name, + bfd_get_section_name (abfd, sec)); + + bfd_set_error (bfd_error_bad_value); + ret = false; + continue; + } + + if (r_type == R_PPC_EMB_SDA21) + { /* fill in register field */ + insn = bfd_get_32 (output_bfd, contents + offset); + insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); + bfd_put_32 (output_bfd, insn, contents + offset); + } + } + break; + + /* Relocate against the beginning of the section */ + case (int)R_PPC_SECTOFF: + case (int)R_PPC_SECTOFF_LO: + case (int)R_PPC_SECTOFF_HI: + BFD_ASSERT (sec != (asection *)0); + addend -= sec->output_section->vma; + break; + + case (int)R_PPC_SECTOFF_HA: + BFD_ASSERT (sec != (asection *)0); + addend -= sec->output_section->vma; + addend += ((relocation + addend) & 0x8000) << 1; + break; + + /* Negative relocations */ + case (int)R_PPC_EMB_NADDR32: + case (int)R_PPC_EMB_NADDR16: + case (int)R_PPC_EMB_NADDR16_LO: + case (int)R_PPC_EMB_NADDR16_HI: + addend -= 2*relocation; + break; + + case (int)R_PPC_EMB_NADDR16_HA: + addend -= 2*relocation; + addend += ((relocation + addend) & 0x8000) << 1; + break; + + /* NOP relocation that prevents garbage collecting linkers from omitting a + reference. */ + case (int)R_PPC_EMB_MRKREF: + continue; + + case (int)R_PPC_PLTREL24: + case (int)R_PPC_COPY: + case (int)R_PPC_GLOB_DAT: + case (int)R_PPC_JMP_SLOT: + case (int)R_PPC_RELATIVE: + case (int)R_PPC_LOCAL24PC: + case (int)R_PPC_PLT32: + case (int)R_PPC_PLTREL32: + case (int)R_PPC_PLT16_LO: + case (int)R_PPC_PLT16_HI: + case (int)R_PPC_PLT16_HA: + case (int)R_PPC_EMB_RELSEC16: + case (int)R_PPC_EMB_RELST_LO: + case (int)R_PPC_EMB_RELST_HI: + case (int)R_PPC_EMB_RELST_HA: + case (int)R_PPC_EMB_BIT_FLD: + (*_bfd_error_handler) ("%s: Relocation %s is not yet supported for symbol %s.", + bfd_get_filename (input_bfd), + ppc_elf_howto_table[ (int)r_type ]->name, + sym_name); + + bfd_set_error (bfd_error_invalid_operation); + ret = false; + continue; + } + + +#ifdef DEBUG + fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", + howto->name, + (int)r_type, + sym_name, + r_symndx, + (long)offset, + (long)addend); +#endif + + r = _bfd_final_link_relocate (howto, + input_bfd, + input_section, + contents, + offset, + relocation, + addend); + + if (r != bfd_reloc_ok) + { + ret = false; + switch (r) + { + default: + break; + + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + break; + + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + (*info->callbacks->reloc_overflow)(info, + name, + howto->name, + (bfd_vma) 0, + input_bfd, + input_section, + offset); + } + break; + + } + } + } + + +#ifdef DEBUG + fprintf (stderr, "\n"); +#endif + + return ret; +} + + +#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec +#define TARGET_LITTLE_NAME "elf32-powerpcle" +#define TARGET_BIG_SYM bfd_elf32_powerpc_vec +#define TARGET_BIG_NAME "elf32-powerpc" +#define ELF_ARCH bfd_arch_powerpc +#define ELF_MACHINE_CODE EM_PPC +#define ELF_MAXPAGESIZE 0x10000 +#define elf_info_to_howto ppc_elf_info_to_howto + +#ifdef EM_CYGNUS_POWERPC +#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC +#endif + +#ifdef EM_PPC_OLD +#define ELF_MACHINE_ALT2 EM_PPC_OLD +#endif + +#define bfd_elf32_bfd_copy_private_bfd_data ppc_elf_copy_private_bfd_data +#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data +#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags +#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup +#define elf_backend_section_from_shdr ppc_elf_section_from_shdr +#define elf_backend_relocate_section ppc_elf_relocate_section +#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections +#define elf_backend_check_relocs ppc_elf_check_relocs +#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol +#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook +#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections +#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections +#define elf_backend_fake_sections ppc_elf_fake_sections +#define elf_backend_additional_program_headers ppc_elf_additional_program_headers +#define elf_backend_modify_segment_map ppc_elf_modify_segment_map + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32-sparc.c b/contrib/gdb/bfd/elf32-sparc.c new file mode 100644 index 000000000000..918eb00e2a0b --- /dev/null +++ b/contrib/gdb/bfd/elf32-sparc.c @@ -0,0 +1,1795 @@ +/* SPARC-specific support for 32-bit ELF + Copyright (C) 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/sparc.h" + +static reloc_howto_type *elf32_sparc_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static boolean elf32_sparc_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static boolean elf32_sparc_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf32_sparc_adjust_dynindx + PARAMS ((struct elf_link_hash_entry *, PTR)); +static boolean elf32_sparc_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf32_sparc_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean elf32_sparc_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean elf32_sparc_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf32_sparc_merge_private_bfd_data PARAMS ((bfd *, bfd *)); +static boolean elf32_sparc_object_p + PARAMS ((bfd *)); +static void elf32_sparc_final_write_processing + PARAMS ((bfd *, boolean)); + +/* The howto table and associated functions. + ??? elf64-sparc.c has its own copy for the moment to ease transition + since some of the relocation values have changed. At some point we'll + want elf64-sparc.c to switch over and use this table. + ??? Do we want to recognize (or flag as errors) some of the 64 bit entries + if the target is elf32-sparc. +*/ + +static bfd_reloc_status_type sparc_elf_notsupported_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static bfd_reloc_status_type sparc_elf_wdisp16_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + +reloc_howto_type _bfd_sparc_elf_howto_table[] = +{ + HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), + HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_8", false,0,0x000000ff,true), + HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_32", false,0,0xffffffff,true), + HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP8", false,0,0x000000ff,true), + HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP32", false,0,0x00ffffff,true), + HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HI22", false,0,0x003fffff,true), + HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_22", false,0,0x003fffff,true), + HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_13", false,0,0x00001fff,true), + HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_GOT13", false,0,0x00001fff,true), + HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC10, 0,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_PC10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC22, 10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_PC22", false,0,0x003fffff,true), + HOWTO(R_SPARC_WPLT30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WPLT30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_COPY", false,0,0x00000000,true), + HOWTO(R_SPARC_GLOB_DAT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_JMP_SLOT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_SLOT",false,0,0x00000000,true), + HOWTO(R_SPARC_RELATIVE, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_RELATIVE",false,0,0x00000000,true), + HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_UA32", false,0,0x00000000,true), + HOWTO(R_SPARC_PLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PLT32", false,0,0x00000000,true), + HOWTO(R_SPARC_HIPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HIPLT22", false,0,0x00000000,true), + HOWTO(R_SPARC_LOPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_LOPLT10", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT32", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT22", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT10", false,0,0x00000000,true), + HOWTO(R_SPARC_10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_10", false,0,0x000003ff,true), + HOWTO(R_SPARC_11, 0,2,11,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_11", false,0,0x000007ff,true), + /* ??? If we need to handle R_SPARC_64 then we need (figuratively) + --enable-64-bit-bfd. That causes objdump to print address as 64 bits + which we really don't want on an elf32-sparc system. There may be other + consequences which we may not want (at least not until it's proven they're + necessary) so for now these are only enabled ifdef BFD64. */ +#ifdef BFD64 + HOWTO(R_SPARC_64, 0,4,00,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_64", false,0,~ (bfd_vma) 0, true), + /* ??? These don't make sense except in 64 bit systems so they're disabled + ifndef BFD64 too (for now). */ + HOWTO(R_SPARC_OLO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_OLO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_HH22, 42,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HM10, 32,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true), + HOWTO(R_SPARC_LM22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC_HH22, 42,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC_HM10, 32,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC_LM22, 10,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true), +#else + HOWTO(R_SPARC_64, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_64", false,0,0x00000000,true), + HOWTO(R_SPARC_OLO10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_OLO10", false,0,0x00000000,true), + HOWTO(R_SPARC_HH22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HH22", false,0,0x00000000,true), + HOWTO(R_SPARC_HM10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HM10", false,0,0x00000000,true), + HOWTO(R_SPARC_LM22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_LM22", false,0,0x00000000,true), + HOWTO(R_SPARC_PC_HH22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PC_HH22", false,0,0x00000000,true), + HOWTO(R_SPARC_PC_HM10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PC_HM10", false,0,0x00000000,true), + HOWTO(R_SPARC_PC_LM22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PC_LM22", false,0,0x00000000,true), +#endif + HOWTO(R_SPARC_WDISP16, 2,2,16,true, 0,complain_overflow_signed, sparc_elf_wdisp16_reloc,"R_SPARC_WDISP16", false,0,0x00000000,true), + HOWTO(R_SPARC_WDISP19, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP19", false,0,0x0007ffff,true), + HOWTO(R_SPARC_GLOB_JMP, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_7, 0,2, 7,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_7", false,0,0x0000007f,true), + HOWTO(R_SPARC_5, 0,2, 5,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_5", false,0,0x0000001f,true), + HOWTO(R_SPARC_6, 0,2, 6,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_6", false,0,0x0000003f,true), +}; + +struct elf_reloc_map { + unsigned char bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +static CONST struct elf_reloc_map sparc_reloc_map[] = +{ + { BFD_RELOC_NONE, R_SPARC_NONE, }, + { BFD_RELOC_16, R_SPARC_16, }, + { BFD_RELOC_8, R_SPARC_8 }, + { BFD_RELOC_8_PCREL, R_SPARC_DISP8 }, + /* ??? This might cause us to need separate functions in elf{32,64}-sparc.c + (we could still have just one table), but is this reloc ever used? */ + { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits. */ + { BFD_RELOC_32, R_SPARC_32 }, + { BFD_RELOC_32_PCREL, R_SPARC_DISP32 }, + { BFD_RELOC_HI22, R_SPARC_HI22 }, + { BFD_RELOC_LO10, R_SPARC_LO10, }, + { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 }, + { BFD_RELOC_SPARC22, R_SPARC_22 }, + { BFD_RELOC_SPARC13, R_SPARC_13 }, + { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 }, + { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 }, + { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 }, + { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 }, + { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 }, + { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 }, + { BFD_RELOC_SPARC_COPY, R_SPARC_COPY }, + { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT }, + { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, + { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, + { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, + /* ??? Doesn't dwarf use this? */ +/*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */ + {BFD_RELOC_SPARC_10, R_SPARC_10}, + {BFD_RELOC_SPARC_11, R_SPARC_11}, + {BFD_RELOC_SPARC_64, R_SPARC_64}, + {BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10}, + {BFD_RELOC_SPARC_HH22, R_SPARC_HH22}, + {BFD_RELOC_SPARC_HM10, R_SPARC_HM10}, + {BFD_RELOC_SPARC_LM22, R_SPARC_LM22}, + {BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22}, + {BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10}, + {BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22}, + {BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16}, + {BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19}, + {BFD_RELOC_SPARC_GLOB_JMP, R_SPARC_GLOB_JMP}, + {BFD_RELOC_SPARC_7, R_SPARC_7}, + {BFD_RELOC_SPARC_5, R_SPARC_5}, + {BFD_RELOC_SPARC_6, R_SPARC_6}, +}; + +static reloc_howto_type * +elf32_sparc_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct elf_reloc_map); i++) + { + if (sparc_reloc_map[i].bfd_reloc_val == code) + return &_bfd_sparc_elf_howto_table[(int) sparc_reloc_map[i].elf_reloc_val]; + } + return 0; +} + +/* We need to use ELF32_R_TYPE so we have our own copy of this function, + and elf64-sparc.c has its own copy. */ + +static void +elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_SPARC_max); + cache_ptr->howto = &_bfd_sparc_elf_howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +/* For unsupported relocs. */ + +static bfd_reloc_status_type +sparc_elf_notsupported_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + return bfd_reloc_notsupported; +} + +/* Handle the WDISP16 reloc. */ + +static bfd_reloc_status_type +sparc_elf_wdisp16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_vma x; + + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + return bfd_reloc_continue; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + relocation = (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset); + relocation += reloc_entry->addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset); + relocation -= reloc_entry->address; + + x = bfd_get_32 (abfd, (char *) data + reloc_entry->address); + x |= ((((relocation >> 2) & 0xc000) << 6) + | ((relocation >> 2) & 0x3fff)); + bfd_put_32 (abfd, x, (char *) data + reloc_entry->address); + + if ((bfd_signed_vma) relocation < - 0x40000 + || (bfd_signed_vma) relocation > 0x3ffff) + return bfd_reloc_overflow; + else + return bfd_reloc_ok; +} + +/* Functions for the SPARC ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" + +/* The nop opcode we use. */ + +#define SPARC_NOP 0x01000000 + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 12 + +/* The first four entries in a procedure linkage table are reserved, + and the initial contents are unimportant (we zero them out). + Subsequent entries look like this. See the SVR4 ABI SPARC + supplement to see how this works. */ + +/* sethi %hi(.-.plt0),%g1. We fill in the address later. */ +#define PLT_ENTRY_WORD0 0x03000000 +/* b,a .plt0. We fill in the offset later. */ +#define PLT_ENTRY_WORD1 0x30800000 +/* nop. */ +#define PLT_ENTRY_WORD2 SPARC_NOP + +/* Look through the relocs for a section during the first phase, and + allocate space in the global offset table or procedure linkage + table. */ + +static boolean +elf32_sparc_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sgot; + asection *srelgot; + asection *sreloc; + + if (info->relocateable) + return true; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_offsets = elf_local_got_offsets (abfd); + + sgot = NULL; + srelgot = NULL; + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_SPARC_GOT10: + case R_SPARC_GOT13: + case R_SPARC_GOT22: + /* This symbol requires a global offset table entry. */ + + if (dynobj == NULL) + { + /* Create the .got section. */ + elf_hash_table (info)->dynobj = dynobj = abfd; + if (! _bfd_elf_create_got_section (dynobj, info)) + return false; + } + + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (srelgot == NULL + && (h != NULL || info->shared)) + { + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (srelgot == NULL) + { + srelgot = bfd_make_section (dynobj, ".rela.got"); + if (srelgot == NULL + || ! bfd_set_section_flags (dynobj, srelgot, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, srelgot, 2)) + return false; + } + } + + if (h != NULL) + { + if (h->got_offset != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + h->got_offset = sgot->_raw_size; + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + srelgot->_raw_size += sizeof (Elf32_External_Rela); + } + else + { + /* This is a global offset table entry for a local + symbol. */ + if (local_got_offsets == NULL) + { + size_t size; + register unsigned int i; + + size = symtab_hdr->sh_info * sizeof (bfd_vma); + local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); + if (local_got_offsets == NULL) + return false; + elf_local_got_offsets (abfd) = local_got_offsets; + for (i = 0; i < symtab_hdr->sh_info; i++) + local_got_offsets[i] = (bfd_vma) -1; + } + if (local_got_offsets[r_symndx] != (bfd_vma) -1) + { + /* We have already allocated space in the .got. */ + break; + } + local_got_offsets[r_symndx] = sgot->_raw_size; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R_SPARC_RELATIVE reloc so that the + dynamic linker can adjust this GOT entry. */ + srelgot->_raw_size += sizeof (Elf32_External_Rela); + } + } + + sgot->_raw_size += 4; + + break; + + case R_SPARC_WPLT30: + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code without + linking in any dynamic objects, in which case we don't + need to generate a procedure linkage table after all. */ + + if (h == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a local symbol. */ + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + + break; + + case R_SPARC_PC10: + case R_SPARC_PC22: + if (h != NULL + && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ + case R_SPARC_DISP8: + case R_SPARC_DISP16: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: + case R_SPARC_WDISP22: + case R_SPARC_WDISP19: + case R_SPARC_WDISP16: + if (h == NULL) + break; + /* Fall through. */ + case R_SPARC_8: + case R_SPARC_16: + case R_SPARC_32: + case R_SPARC_HI22: + case R_SPARC_22: + case R_SPARC_13: + case R_SPARC_LO10: + case R_SPARC_UA32: + if (info->shared + && (sec->flags & SEC_ALLOC) != 0) + { + /* When creating a shared object, we must copy these + relocs into the output file. We create a reloc + section in dynobj and make room for the reloc. */ + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (abfd, sec), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + if (sreloc == NULL) + { + sreloc = bfd_make_section (dynobj, name); + if (sreloc == NULL + || ! bfd_set_section_flags (dynobj, sreloc, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, sreloc, 2)) + return false; + } + } + + sreloc->_raw_size += sizeof (Elf32_External_Rela); + } + + break; + + default: + break; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +elf32_sparc_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + unsigned int power_of_two; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) + || h->weakdef != NULL + || ((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later + (although we could actually do it here). */ + if (h->type == STT_FUNC + || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (! elf_hash_table (info)->dynamic_sections_created) + { + /* This case can occur if we saw a WPLT30 reloc in an input + file, but none of the input files were dynamic objects. + In such a case, we don't actually need to build a + procedure linkage table, and we can just do a WDISP30 + reloc instead. */ + BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0); + return true; + } + + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + + /* The first four entries in .plt are reserved. */ + if (s->_raw_size == 0) + s->_raw_size = 4 * PLT_ENTRY_SIZE; + + /* The procedure linkage table has a maximum size. */ + if (s->_raw_size >= 0x400000) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } + + h->plt_offset = s->_raw_size; + + /* Make room for this entry. */ + s->_raw_size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .rela.plt section. */ + + s = bfd_get_section_by_name (dynobj, ".rela.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += sizeof (Elf32_External_Rela); + + return true; + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (info->shared) + 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 + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + s = bfd_get_section_by_name (dynobj, ".dynbss"); + BFD_ASSERT (s != NULL); + + /* If the symbol is currently defined in the .bss section of the + dynamic object, then it is OK to simply initialize it to zero. + If the symbol is in some other section, we must generate a + R_SPARC_COPY reloc to tell the dynamic linker to copy the initial + value out of the dynamic object and into the runtime process + image. We need to remember the offset into the .rel.bss section + we are going to use. */ + if ((h->root.u.def.section->flags & SEC_LOAD) != 0) + { + asection *srel; + + srel = bfd_get_section_by_name (dynobj, ".rela.bss"); + BFD_ASSERT (srel != NULL); + srel->_raw_size += sizeof (Elf32_External_Rela); + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 3) + power_of_two = 3; + + /* Apply the required alignment. */ + s->_raw_size = BFD_ALIGN (s->_raw_size, + (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (dynobj, s)) + { + if (! bfd_set_section_alignment (dynobj, s, power_of_two)) + return false; + } + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +elf32_sparc_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + boolean reltext; + boolean relplt; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + + /* Make space for the trailing nop in .plt. */ + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + if (s->_raw_size > 0) + s->_raw_size += 4; + } + else + { + /* We may have created entries in the .rela.got section. + However, if we are not creating the dynamic sections, we will + not actually use these entries. Reset the size of .rela.got, + which will cause it to get stripped from the output file + below. */ + s = bfd_get_section_by_name (dynobj, ".rela.got"); + if (s != NULL) + s->_raw_size = 0; + } + + /* The check_relocs and adjust_dynamic_symbol entry points have + determined the sizes of the various dynamic sections. Allocate + memory for them. */ + reltext = false; + relplt = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + boolean strip; + + if ((s->flags & SEC_IN_MEMORY) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + strip = false; + + if (strncmp (name, ".rela", 5) == 0) + { + if (s->_raw_size == 0) + { + /* If we don't need this section, strip it from the + output file. This is to handle .rela.bss and + .rel.plt. We must create it in + create_dynamic_sections, because it must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + strip = true; + } + else + { + asection *target; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL entry. */ + target = bfd_get_section_by_name (output_bfd, name + 5); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + + if (strcmp (name, ".rela.plt") == 0) + relplt = true; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + } + else if (strcmp (name, ".plt") != 0 + && strcmp (name, ".got") != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + + continue; + } + + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf32_sparc_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ + if (! info->shared) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)) + return false; + + if (relplt) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA) + || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT, + sizeof (Elf32_External_Rela))) + return false; + + if (reltext) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) + return false; + } + } + + /* If we are generating a shared library, we generate a section + symbol for each output section. These are local symbols, which + means that they must come first in the dynamic symbol table. + That means we must increment the dynamic symbol index of every + other dynamic symbol. */ + if (info->shared) + { + int c, i; + + c = bfd_count_sections (output_bfd); + elf_link_hash_traverse (elf_hash_table (info), + elf32_sparc_adjust_dynindx, + (PTR) &c); + elf_hash_table (info)->dynsymcount += c; + + for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++) + { + elf_section_data (s)->dynindx = i; + /* These symbols will have no names, so we don't need to + fiddle with dynstr_index. */ + } + } + + return true; +} + +/* Increment the index of a dynamic symbol by a given amount. Called + via elf_link_hash_traverse. */ + +static boolean +elf32_sparc_adjust_dynindx (h, cparg) + struct elf_link_hash_entry *h; + PTR cparg; +{ + int *cp = (int *) cparg; + + if (h->dynindx != -1) + h->dynindx += *cp; + return true; +} + +/* Relocate a SPARC ELF section. */ + +static boolean +elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + bfd *dynobj; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + asection *sgot; + asection *splt; + asection *sreloc; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); + + sgot = NULL; + splt = NULL; + sreloc = NULL; + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_SPARC_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = _bfd_sparc_elf_howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if ((r_type == R_SPARC_WPLT30 + && h->plt_offset != (bfd_vma) -1) + || ((r_type == R_SPARC_GOT10 + || r_type == R_SPARC_GOT13 + || r_type == R_SPARC_GOT22) + && elf_hash_table (info)->dynamic_sections_created + && (! info->shared + || ! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || (info->shared + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0) + && (input_section->flags & SEC_ALLOC) != 0 + && (r_type == R_SPARC_8 + || r_type == R_SPARC_16 + || r_type == R_SPARC_32 + || r_type == R_SPARC_DISP8 + || r_type == R_SPARC_DISP16 + || r_type == R_SPARC_DISP32 + || r_type == R_SPARC_WDISP30 + || r_type == R_SPARC_WDISP22 + || r_type == R_SPARC_WDISP19 + || r_type == R_SPARC_WDISP16 + || r_type == R_SPARC_HI22 + || r_type == R_SPARC_22 + || r_type == R_SPARC_13 + || r_type == R_SPARC_LO10 + || r_type == R_SPARC_UA32 + || ((r_type == R_SPARC_PC10 + || r_type == R_SPARC_PC22) + && strcmp (h->root.root.string, + "_GLOBAL_OFFSET_TABLE_") != 0)))) + { + /* In these cases, we don't need the relocation + value. We check specially because in some + obscure cases sec->output_section will be NULL. */ + relocation = 0; + } + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared && !info->symbolic) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + switch (r_type) + { + case R_SPARC_GOT10: + case R_SPARC_GOT13: + case R_SPARC_GOT22: + /* Relocation is to the entry for this symbol in the global + offset table. */ + if (sgot == NULL) + { + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + } + + if (h != NULL) + { + bfd_vma off; + + off = h->got_offset; + BFD_ASSERT (off != (bfd_vma) -1); + + if (! elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global offset table. Since the offset must + always be a multiple of 4, we use the least + significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got_offset |= 1; + } + } + + relocation = sgot->output_offset + off; + } + else + { + bfd_vma off; + + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != (bfd_vma) -1); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already processed this entry. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (info->shared) + { + asection *srelgot; + Elf_Internal_Rela outrel; + + /* We need to generate a R_SPARC_RELATIVE reloc + for the dynamic linker. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE); + outrel.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (((Elf32_External_Rela *) + srelgot->contents) + + srelgot->reloc_count)); + ++srelgot->reloc_count; + } + + local_got_offsets[r_symndx] |= 1; + } + + relocation = sgot->output_offset + off; + } + + break; + + case R_SPARC_WPLT30: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + BFD_ASSERT (h != NULL); + + if (h->plt_offset == (bfd_vma) -1) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + } + + if (splt == NULL) + { + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL); + } + + relocation = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + break; + + case R_SPARC_PC10: + case R_SPARC_PC22: + if (h != NULL + && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + break; + /* Fall through. */ + case R_SPARC_DISP8: + case R_SPARC_DISP16: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: + case R_SPARC_WDISP22: + case R_SPARC_WDISP19: + case R_SPARC_WDISP16: + if (h == NULL) + break; + /* Fall through. */ + case R_SPARC_8: + case R_SPARC_16: + case R_SPARC_32: + case R_SPARC_HI22: + case R_SPARC_22: + case R_SPARC_13: + case R_SPARC_LO10: + case R_SPARC_UA32: + if (info->shared + && (input_section->flags & SEC_ALLOC) != 0) + { + Elf_Internal_Rela outrel; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + if (sreloc == NULL) + { + const char *name; + + name = (bfd_elf_string_from_elf_section + (input_bfd, + elf_elfheader (input_bfd)->e_shstrndx, + elf_section_data (input_section)->rel_hdr.sh_name)); + if (name == NULL) + return false; + + BFD_ASSERT (strncmp (name, ".rela", 5) == 0 + && strcmp (bfd_get_section_name (input_bfd, + input_section), + name + 5) == 0); + + sreloc = bfd_get_section_by_name (dynobj, name); + BFD_ASSERT (sreloc != NULL); + } + + outrel.r_offset = (rel->r_offset + + input_section->output_section->vma + + input_section->output_offset); + if (h != NULL + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + { + BFD_ASSERT (h->dynindx != -1); + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + else + { + if (r_type == R_SPARC_32) + { + outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + long indx; + + if (h == NULL) + sec = local_sections[r_symndx]; + else + { + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || (h->root.type + == bfd_link_hash_defweak)); + sec = h->root.u.def.section; + } + if (sec != NULL && bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + asection *osec; + + osec = sec->output_section; + indx = elf_section_data (osec)->dynindx; + if (indx == 0) + abort (); + } + + outrel.r_info = ELF32_R_INFO (indx, r_type); + outrel.r_addend = relocation + rel->r_addend; + } + } + + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (((Elf32_External_Rela *) + sreloc->contents) + + sreloc->reloc_count)); + ++sreloc->reloc_count; + + /* This reloc will be computed at runtime, so there's no + need to do anything now. */ + continue; + } + + default: + break; + } + + if (r_type != R_SPARC_WDISP16) + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + else + { + bfd_vma x; + + relocation += rel->r_addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset); + relocation -= rel->r_offset; + + x = bfd_get_32 (input_bfd, contents + rel->r_offset); + x |= ((((relocation >> 2) & 0xc000) << 6) + | ((relocation >> 2) & 0x3fff)); + bfd_put_32 (input_bfd, x, contents + rel->r_offset); + + if ((bfd_signed_vma) relocation < - 0x40000 + || (bfd_signed_vma) relocation > 0x3ffff) + r = bfd_reloc_overflow; + else + r = bfd_reloc_ok; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +elf32_sparc_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + bfd *dynobj; + + dynobj = elf_hash_table (info)->dynobj; + + if (h->plt_offset != (bfd_vma) -1) + { + asection *splt; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = bfd_get_section_by_name (dynobj, ".plt"); + srela = bfd_get_section_by_name (dynobj, ".rela.plt"); + BFD_ASSERT (splt != NULL && srela != NULL); + + /* Fill in the entry in the procedure linkage table. */ + bfd_put_32 (output_bfd, + PLT_ENTRY_WORD0 + h->plt_offset, + splt->contents + h->plt_offset); + bfd_put_32 (output_bfd, + (PLT_ENTRY_WORD1 + + (((- (h->plt_offset + 4)) >> 2) & 0x3fffff)), + splt->contents + h->plt_offset + 4); + bfd_put_32 (output_bfd, PLT_ENTRY_WORD2, + splt->contents + h->plt_offset + 8); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_JMP_SLOT); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) srela->contents + + h->plt_offset / PLT_ENTRY_SIZE - 4)); + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got_offset != (bfd_vma) -1) + { + asection *sgot; + asection *srela; + Elf_Internal_Rela rela; + + /* This symbol has an entry in the global offset table. Set it + up. */ + + BFD_ASSERT (h->dynindx != -1); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + srela = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (sgot != NULL && srela != NULL); + + rela.r_offset = (sgot->output_section->vma + + sgot->output_offset + + (h->got_offset &~ 1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. The entry in + the global offset table will already have been initialized in + the relocate_section function. */ + if (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + rela.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE); + else + { + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_GLOB_DAT); + } + + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) srela->contents + + srela->reloc_count)); + ++srela->reloc_count; + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + asection *s; + Elf_Internal_Rela rela; + + /* This symbols needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1); + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rela.bss"); + BFD_ASSERT (s != NULL); + + rela.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rela.r_info = ELF32_R_INFO (h->dynindx, R_SPARC_COPY); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, + ((Elf32_External_Rela *) s->contents + + s->reloc_count)); + ++s->reloc_count; + } + + /* Mark some specially defined symbols as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 + || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +elf32_sparc_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sdyn; + asection *sgot; + + dynobj = elf_hash_table (info)->dynobj; + + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (elf_hash_table (info)->dynamic_sections_created) + { + asection *splt; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (splt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + boolean size; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + case DT_PLTGOT: name = ".plt"; size = false; break; + case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; + case DT_JMPREL: name = ".rela.plt"; size = false; break; + default: name = NULL; size = false; break; + } + + if (name != NULL) + { + asection *s; + + s = bfd_get_section_by_name (output_bfd, name); + if (s == NULL) + dyn.d_un.d_val = 0; + else + { + if (! size) + dyn.d_un.d_ptr = s->vma; + else + { + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + } + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + + /* Clear the first four entries in the procedure linkage table, + and put a nop in the last four bytes. */ + if (splt->_raw_size > 0) + { + memset (splt->contents, 0, 4 * PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, SPARC_NOP, + splt->contents + splt->_raw_size - 4); + } + + elf_section_data (splt->output_section)->this_hdr.sh_entsize = + PLT_ENTRY_SIZE; + } + + /* Set the first entry in the global offset table to the address of + the dynamic section. */ + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + if (sgot->_raw_size > 0) + { + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + } + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + + if (info->shared) + { + asection *sdynsym; + asection *s; + Elf_Internal_Sym sym; + + /* Set up the section symbols for the output sections. */ + + sdynsym = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (sdynsym != NULL); + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + int indx; + + sym.st_value = s->vma; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + + bfd_elf32_swap_symbol_out (output_bfd, &sym, + (PTR) (((Elf32_External_Sym *) + sdynsym->contents) + + elf_section_data (s)->dynindx)); + } + + /* Set the sh_info field of the output .dynsym section to the + index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + bfd_count_sections (output_bfd) + 1; + } + + return true; +} + +/* Functions for dealing with the e_flags field. + + We don't define set_private_flags or copy_private_bfd_data because + the only currently defined values are based on the bfd mach number, + so we use the latter instead and defer setting e_flags until the + file is written out. */ + +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static boolean +elf32_sparc_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + boolean error; + + /* This function is selected based on the input vector. We only + want to copy information over if the output BFD also uses Elf + format. */ + if (bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + error = false; + +#if 0 + /* ??? The native linker doesn't do this so we can't (otherwise gcc would + have to know which linker is being used). Instead, the native linker + bumps up the architecture level when it has to. However, I still think + warnings like these are good, so it would be nice to have them turned on + by some option. */ + + /* If the output machine is normal sparc, we can't allow v9 input files. */ + if (bfd_get_mach (obfd) == bfd_mach_sparc + && (bfd_get_mach (ibfd) == bfd_mach_sparc_v8plus + || bfd_get_mach (ibfd) == bfd_mach_sparc_v8plusa)) + { + error = true; + (*_bfd_error_handler) + ("%s: compiled for a v8plus system and target is v8", + bfd_get_filename (ibfd)); + } + /* If the output machine is v9, we can't allow v9+vis input files. */ + if (bfd_get_mach (obfd) == bfd_mach_sparc_v8plus + && bfd_get_mach (ibfd) == bfd_mach_sparc_v8plusa) + { + error = true; + (*_bfd_error_handler) + ("%s: compiled for a v8plusa system and target is v8plus", + bfd_get_filename (ibfd)); + } +#else + if (bfd_get_mach (ibfd) >= bfd_mach_sparc_v9) + { + error = true; + (*_bfd_error_handler) + ("%s: compiled for a 64 bit system and target is 32 bit", + bfd_get_filename (ibfd)); + } + else if (bfd_get_mach (obfd) < bfd_get_mach (ibfd)) + bfd_set_arch_mach (obfd, bfd_arch_sparc, bfd_get_mach (ibfd)); +#endif + + if (error) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + return true; +} + +/* Set the right machine number. */ + +static boolean +elf32_sparc_object_p (abfd) + bfd *abfd; +{ + if (elf_elfheader (abfd)->e_machine == EM_SPARC32PLUS) + { + if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusa); + else if (elf_elfheader (abfd)->e_flags & EF_SPARC_32PLUS) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plus); + else + return false; + } + else + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc); +} + +/* The final processing done just before writing out the object file. + We need to set the e_machine field appropriately. */ + +static void +elf32_sparc_final_write_processing (abfd, linker) + bfd *abfd; + boolean linker; +{ + switch (bfd_get_mach (abfd)) + { + case bfd_mach_sparc : + break; /* nothing to do */ + case bfd_mach_sparc_v8plus : + elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; + elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; + elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS; + break; + case bfd_mach_sparc_v8plusa : + elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; + elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; + elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS | EF_SPARC_SUN_US1; + break; + default : + abort (); + } +} + +#define TARGET_BIG_SYM bfd_elf32_sparc_vec +#define TARGET_BIG_NAME "elf32-sparc" +#define ELF_ARCH bfd_arch_sparc +#define ELF_MACHINE_CODE EM_SPARC +#define ELF_MACHINE_ALT1 EM_SPARC32PLUS +#define ELF_MAXPAGESIZE 0x10000 + +#define bfd_elf32_bfd_reloc_type_lookup elf32_sparc_reloc_type_lookup +#define elf_backend_create_dynamic_sections \ + _bfd_elf_create_dynamic_sections +#define elf_backend_check_relocs elf32_sparc_check_relocs +#define elf_backend_adjust_dynamic_symbol \ + elf32_sparc_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + elf32_sparc_size_dynamic_sections +#define elf_backend_relocate_section elf32_sparc_relocate_section +#define elf_backend_finish_dynamic_symbol \ + elf32_sparc_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + elf32_sparc_finish_dynamic_sections +#define bfd_elf32_bfd_merge_private_bfd_data \ + elf32_sparc_merge_private_bfd_data +#define elf_backend_object_p elf32_sparc_object_p +#define elf_backend_final_write_processing \ + elf32_sparc_final_write_processing +#define elf_backend_want_got_plt 0 +#define elf_backend_plt_readonly 0 +#define elf_backend_want_plt_sym 1 + +#include "elf32-target.h" diff --git a/contrib/gdb/bfd/elf32.c b/contrib/gdb/bfd/elf32.c new file mode 100644 index 000000000000..f2229694406d --- /dev/null +++ b/contrib/gdb/bfd/elf32.c @@ -0,0 +1,23 @@ +/* ELF 32-bit executable support for BFD. + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 32 + + +#include "elfcode.h" diff --git a/contrib/gdb/bfd/elf64-gen.c b/contrib/gdb/bfd/elf64-gen.c new file mode 100644 index 000000000000..5daf4ee9f17d --- /dev/null +++ b/contrib/gdb/bfd/elf64-gen.c @@ -0,0 +1,37 @@ +/* Generic support for 64-bit ELF + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* This does not include any relocations, but should be good enough + for GDB to read the file. */ + +#define TARGET_LITTLE_SYM bfd_elf64_little_generic_vec +#define TARGET_LITTLE_NAME "elf64-little" +#define TARGET_BIG_SYM bfd_elf64_big_generic_vec +#define TARGET_BIG_NAME "elf64-big" +#define ELF_ARCH bfd_arch_unknown +#define ELF_MACHINE_CODE EM_NONE +#define bfd_elf64_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define elf_info_to_howto _bfd_elf_no_info_to_howto + +#include "elf64-target.h" diff --git a/contrib/gdb/bfd/elf64-sparc.c b/contrib/gdb/bfd/elf64-sparc.c new file mode 100644 index 000000000000..5059b803c62e --- /dev/null +++ b/contrib/gdb/bfd/elf64-sparc.c @@ -0,0 +1,421 @@ +/* SPARC-specific support for 64-bit ELF + Copyright (C) 1993, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* We need a published ABI spec for this. Until one comes out, don't + assume this'll remain unchanged forever. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#define SPARC64_OLD_RELOCS +#include "elf/sparc.h" + +static reloc_howto_type *sparc64_elf_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); + +static boolean sparc64_elf_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static boolean sparc64_elf_object_p PARAMS ((bfd *)); + +/* The howto table and associated functions. + ??? Some of the relocation values have changed. Until we're ready + to upgrade, we have our own copy. At some point a non upward compatible + change will be made at which point this table can be deleted and we'll + use the one in elf32-sparc.c. */ + +static bfd_reloc_status_type sparc_elf_wdisp16_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); + +static reloc_howto_type sparc64_elf_howto_table[] = +{ + HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", false,0,0x00000000,true), + HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_8", false,0,0x000000ff,true), + HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_32", false,0,0xffffffff,true), + HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP8", false,0,0x000000ff,true), + HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_DISP32", false,0,0x00ffffff,true), + HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HI22", false,0,0x003fffff,true), + HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_22", false,0,0x003fffff,true), + HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_13", false,0,0x00001fff,true), + HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_GOT13", false,0,0x00001fff,true), + HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOT22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC10, 0,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_PC10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC22, 10,2,22,true, 0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_PC22", false,0,0x003fffff,true), + HOWTO(R_SPARC_WPLT30, 2,2,30,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WPLT30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_COPY", false,0,0x00000000,true), + HOWTO(R_SPARC_GLOB_DAT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_JMP_SLOT, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_SLOT",false,0,0x00000000,true), + HOWTO(R_SPARC_RELATIVE, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_RELATIVE",false,0,0x00000000,true), + HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_UA32", false,0,0x00000000,true), +#if 0 /* not used yet */ + HOWTO(R_SPARC_PLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PLT32", false,0,0x00000000,true), + HOWTO(R_SPARC_HIPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_HIPLT22", false,0,0x00000000,true), + HOWTO(R_SPARC_LOPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_LOPLT10", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT32, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT32", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT22, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT22", false,0,0x00000000,true), + HOWTO(R_SPARC_PCPLT10, 0,0,00,false,0,complain_overflow_dont, sparc_elf_notsupported_reloc, "R_SPARC_PCPLT10", false,0,0x00000000,true), +#endif + HOWTO(R_SPARC_10, 0,2,10,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_10", false,0,0x000003ff,true), + HOWTO(R_SPARC_11, 0,2,11,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_11", false,0,0x000007ff,true), + HOWTO(R_SPARC_64, 0,4,00,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_64", false,0,~ (bfd_vma) 0, true), + HOWTO(R_SPARC_OLO10, 0,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_OLO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_HH22, 42,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HM10, 32,2,10,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true), + HOWTO(R_SPARC_LM22, 10,2,22,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC_HH22, 42,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HH22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC_HM10, 32,2,10,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_HM10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC_LM22, 10,2,22,true, 0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_LM22", false,0,0x003fffff,true), + HOWTO(R_SPARC_WDISP16, 2,2,16,true, 0,complain_overflow_signed, sparc_elf_wdisp16_reloc,"R_SPARC_WDISP16", false,0,0x00000000,true), + HOWTO(R_SPARC_WDISP19, 2,2,22,true, 0,complain_overflow_signed, bfd_elf_generic_reloc, "R_SPARC_WDISP19", false,0,0x0007ffff,true), + HOWTO(R_SPARC_GLOB_JMP, 0,0,00,false,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_7, 0,2, 7,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_7", false,0,0x0000007f,true), +#if 0 /* not used yet */ + HOWTO(R_SPARC_5, 0,2, 5,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_5", false,0,0x0000001f,true), + HOWTO(R_SPARC_6, 0,2, 6,false,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_6", false,0,0x0000003f,true), +#endif +}; + +struct elf_reloc_map { + unsigned char bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +static CONST struct elf_reloc_map sparc_reloc_map[] = +{ + { BFD_RELOC_NONE, R_SPARC_NONE, }, + { BFD_RELOC_16, R_SPARC_16, }, + { BFD_RELOC_8, R_SPARC_8 }, + { BFD_RELOC_8_PCREL, R_SPARC_DISP8 }, + /* ??? This might cause us to need separate functions in elf{32,64}-sparc.c + (we could still have just one table), but is this reloc ever used? */ + { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits. */ + { BFD_RELOC_32, R_SPARC_32 }, + { BFD_RELOC_32_PCREL, R_SPARC_DISP32 }, + { BFD_RELOC_HI22, R_SPARC_HI22 }, + { BFD_RELOC_LO10, R_SPARC_LO10, }, + { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 }, + { BFD_RELOC_SPARC22, R_SPARC_22 }, + { BFD_RELOC_SPARC13, R_SPARC_13 }, + { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 }, + { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 }, + { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 }, + { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 }, + { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 }, + { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 }, + { BFD_RELOC_SPARC_COPY, R_SPARC_COPY }, + { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT }, + { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, + { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, + { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, + /* ??? Doesn't dwarf use this? */ +/*{ BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */ + {BFD_RELOC_SPARC_10, R_SPARC_10}, + {BFD_RELOC_SPARC_11, R_SPARC_11}, + {BFD_RELOC_SPARC_64, R_SPARC_64}, + {BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10}, + {BFD_RELOC_SPARC_HH22, R_SPARC_HH22}, + {BFD_RELOC_SPARC_HM10, R_SPARC_HM10}, + {BFD_RELOC_SPARC_LM22, R_SPARC_LM22}, + {BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22}, + {BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10}, + {BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22}, + {BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16}, + {BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19}, + {BFD_RELOC_SPARC_GLOB_JMP, R_SPARC_GLOB_JMP}, + {BFD_RELOC_SPARC_7, R_SPARC_7}, +#if 0 /* unused */ + {BFD_RELOC_SPARC_5, R_SPARC_5}, + {BFD_RELOC_SPARC_6, R_SPARC_6}, +#endif +}; + +static reloc_howto_type * +sparc64_elf_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + unsigned int i; + for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct elf_reloc_map); i++) + { + if (sparc_reloc_map[i].bfd_reloc_val == code) + return &sparc64_elf_howto_table[(int) sparc_reloc_map[i].elf_reloc_val]; + } + return 0; +} + +static void +elf_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf64_Internal_Rela *dst; +{ + BFD_ASSERT (ELF64_R_TYPE (dst->r_info) < (unsigned int) R_SPARC_max); + cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE (dst->r_info)]; +} + +/* Handle the WDISP16 reloc. */ + +static bfd_reloc_status_type +sparc_elf_wdisp16_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_vma x; + + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (! reloc_entry->howto->partial_inplace + || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + return bfd_reloc_continue; + + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + relocation = (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset); + relocation += reloc_entry->addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset); + relocation -= reloc_entry->address; + + x = bfd_get_32 (abfd, (char *) data + reloc_entry->address); + x |= ((((relocation >> 2) & 0xc000) << 6) + | ((relocation >> 2) & 0x3fff)); + bfd_put_32 (abfd, x, (char *) data + reloc_entry->address); + + if ((bfd_signed_vma) relocation < - 0x40000 + || (bfd_signed_vma) relocation > 0x3ffff) + return bfd_reloc_overflow; + else + return bfd_reloc_ok; +} + +/* Relocate a SPARC64 ELF section. */ + +static boolean +sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_type = ELF64_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_SPARC_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = sparc64_elf_howto_table + r_type; + + r_symndx = ELF64_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + if (r_type != R_SPARC_WDISP16) + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + else + { + bfd_vma x; + + relocation += rel->r_addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset); + relocation -= rel->r_offset; + + x = bfd_get_32 (input_bfd, contents + rel->r_offset); + x |= ((((relocation >> 2) & 0xc000) << 6) + | ((relocation >> 2) & 0x3fff)); + bfd_put_32 (input_bfd, x, contents + rel->r_offset); + + if ((bfd_signed_vma) relocation < - 0x40000 + || (bfd_signed_vma) relocation > 0x3ffff) + r = bfd_reloc_overflow; + else + r = bfd_reloc_ok; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = (bfd_elf_string_from_elf_section + (input_bfd, + symtab_hdr->sh_link, + sym->st_name)); + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Set the right machine number for a SPARC64 ELF file. */ + +static boolean +sparc64_elf_object_p (abfd) + bfd *abfd; +{ + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc_v9); +} + +#define TARGET_BIG_SYM bfd_elf64_sparc_vec +#define TARGET_BIG_NAME "elf64-sparc" +#define ELF_ARCH bfd_arch_sparc +#define ELF_MACHINE_CODE EM_SPARC64 +#define ELF_MAXPAGESIZE 0x100000 + +#define bfd_elf64_bfd_reloc_type_lookup sparc64_elf_reloc_type_lookup +#define elf_backend_relocate_section sparc64_elf_relocate_section +#define elf_backend_object_p sparc64_elf_object_p + +#include "elf64-target.h" diff --git a/contrib/gdb/bfd/elf64.c b/contrib/gdb/bfd/elf64.c new file mode 100644 index 000000000000..69fb5b5e6e1d --- /dev/null +++ b/contrib/gdb/bfd/elf64.c @@ -0,0 +1,22 @@ +/* ELF 64-bit executable support for BFD. + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 64 + +#include "elfcode.h" diff --git a/contrib/gdb/bfd/elfcode.h b/contrib/gdb/bfd/elfcode.h new file mode 100644 index 000000000000..a6199f0b0f48 --- /dev/null +++ b/contrib/gdb/bfd/elfcode.h @@ -0,0 +1,1406 @@ +/* ELF executable support for BFD. + Copyright 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". Sufficient support for gdb. + + Rewritten by Mark Eichin @ Cygnus Support, from information + published in "System V Application Binary Interface", chapters 4 + and 5, as well as the various "Processor Supplement" documents + derived from it. Added support for assembler and other object file + utilities. Further work done by Ken Raeburn (Cygnus Support), Michael + Meissner (Open Software Foundation), and Peter Hoogenboom (University + of Utah) to finish and extend this. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Problems and other issues to resolve. + + (1) BFD expects there to be some fixed number of "sections" in + the object file. I.E. there is a "section_count" variable in the + bfd structure which contains the number of sections. However, ELF + supports multiple "views" of a file. In particular, with current + implementations, executable files typically have two tables, a + program header table and a section header table, both of which + partition the executable. + + In ELF-speak, the "linking view" of the file uses the section header + table to access "sections" within the file, and the "execution view" + uses the program header table to access "segments" within the file. + "Segments" typically may contain all the data from one or more + "sections". + + Note that the section header table is optional in ELF executables, + but it is this information that is most useful to gdb. If the + section header table is missing, then gdb should probably try + to make do with the program header table. (FIXME) + + (2) The code in this file is compiled twice, once in 32-bit mode and + once in 64-bit mode. More of it should be made size-independent + and moved into elf.c. + + (3) ELF section symbols are handled rather sloppily now. This should + be cleaned up, and ELF section symbols reconciled with BFD section + symbols. + + (4) We need a published spec for 64-bit ELF. We've got some stuff here + that we're using for SPARC V9 64-bit chips, but don't assume that + it's cast in stone. + */ + +#include /* For strrchr and friends */ +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* Renaming structures, typedefs, macros and functions to be size-specific. */ +#define Elf_External_Ehdr NAME(Elf,External_Ehdr) +#define Elf_External_Sym NAME(Elf,External_Sym) +#define Elf_External_Shdr NAME(Elf,External_Shdr) +#define Elf_External_Phdr NAME(Elf,External_Phdr) +#define Elf_External_Rel NAME(Elf,External_Rel) +#define Elf_External_Rela NAME(Elf,External_Rela) +#define Elf_External_Dyn NAME(Elf,External_Dyn) + +#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) +#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) +#define elf_core_file_matches_executable_p \ + NAME(bfd_elf,core_file_matches_executable_p) +#define elf_object_p NAME(bfd_elf,object_p) +#define elf_core_file_p NAME(bfd_elf,core_file_p) +#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) +#define elf_get_dynamic_symtab_upper_bound \ + NAME(bfd_elf,get_dynamic_symtab_upper_bound) +#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) +#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) +#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) +#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) +#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) +#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) +#define elf_swap_phdr_in NAME(bfd_elf,swap_phdr_in) +#define elf_swap_phdr_out NAME(bfd_elf,swap_phdr_out) +#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) +#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) +#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) +#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) +#define elf_get_symtab NAME(bfd_elf,get_symtab) +#define elf_canonicalize_dynamic_symtab \ + NAME(bfd_elf,canonicalize_dynamic_symtab) +#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) +#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) +#define elf_get_lineno NAME(bfd_elf,get_lineno) +#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) +#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) +#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) +#define elf_set_section_contents NAME(bfd_elf,set_section_contents) +#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) +#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) +#define elf_find_section NAME(bfd_elf,find_section) +#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) +#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) +#define elf_link_create_dynamic_sections \ + NAME(bfd_elf,link_create_dynamic_sections) +#define elf_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) +#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section) +#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section) + +#if ARCH_SIZE == 64 +#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF64_R_SYM(X) +#define ELF_R_TYPE(X) ELF64_R_TYPE(X) +#define ELFCLASS ELFCLASS64 +#define FILE_ALIGN 8 +#define LOG_FILE_ALIGN 3 +#endif +#if ARCH_SIZE == 32 +#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF32_R_SYM(X) +#define ELF_R_TYPE(X) ELF32_R_TYPE(X) +#define ELFCLASS ELFCLASS32 +#define FILE_ALIGN 4 +#define LOG_FILE_ALIGN 2 +#endif + +/* Forward declarations of static functions */ + +#define elf_stringtab_init _bfd_elf_stringtab_init + +extern struct bfd_strtab_hash *_bfd_elf_stringtab_init PARAMS ((void)); +#define section_from_elf_index bfd_section_from_elf_index +extern boolean bfd_section_from_phdr PARAMS ((bfd *, Elf_Internal_Phdr *, + int)); + +static long elf_slurp_symbol_table PARAMS ((bfd *, asymbol **, boolean)); + +static boolean elf_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **)); + + int _bfd_elf_symbol_from_bfd_symbol PARAMS ((bfd *, + struct symbol_cache_entry **)); + +static boolean validate_reloc PARAMS ((bfd *, arelent *)); +static void write_relocs PARAMS ((bfd *, asection *, PTR)); + + boolean bfd_section_from_shdr PARAMS ((bfd *, unsigned int shindex)); + +#ifdef DEBUG +static void elf_debug_section PARAMS ((int, Elf_Internal_Shdr *)); +static void elf_debug_file PARAMS ((Elf_Internal_Ehdr *)); +static char *elf_symbol_flags PARAMS ((flagword)); +#endif + +/* Structure swapping routines */ + +/* Should perhaps use put_offset, put_word, etc. For now, the two versions + can be handled by explicitly specifying 32 bits or "the long type". */ +#if ARCH_SIZE == 64 +#define put_word bfd_h_put_64 +#define get_word bfd_h_get_64 +#endif +#if ARCH_SIZE == 32 +#define put_word bfd_h_put_32 +#define get_word bfd_h_get_32 +#endif + +/* Translate an ELF symbol in external format into an ELF symbol in internal + format. */ + +void +elf_swap_symbol_in (abfd, src, dst) + bfd *abfd; + Elf_External_Sym *src; + Elf_Internal_Sym *dst; +{ + dst->st_name = bfd_h_get_32 (abfd, (bfd_byte *) src->st_name); + dst->st_value = get_word (abfd, (bfd_byte *) src->st_value); + dst->st_size = get_word (abfd, (bfd_byte *) src->st_size); + dst->st_info = bfd_h_get_8 (abfd, (bfd_byte *) src->st_info); + dst->st_other = bfd_h_get_8 (abfd, (bfd_byte *) src->st_other); + dst->st_shndx = bfd_h_get_16 (abfd, (bfd_byte *) src->st_shndx); +} + +/* Translate an ELF symbol in internal format into an ELF symbol in external + format. */ + +void +elf_swap_symbol_out (abfd, src, cdst) + bfd *abfd; + Elf_Internal_Sym *src; + PTR cdst; +{ + Elf_External_Sym *dst = (Elf_External_Sym *) cdst; + bfd_h_put_32 (abfd, src->st_name, dst->st_name); + put_word (abfd, src->st_value, dst->st_value); + put_word (abfd, src->st_size, dst->st_size); + bfd_h_put_8 (abfd, src->st_info, dst->st_info); + bfd_h_put_8 (abfd, src->st_other, dst->st_other); + bfd_h_put_16 (abfd, src->st_shndx, dst->st_shndx); +} + + +/* Translate an ELF file header in external format into an ELF file header in + internal format. */ + +static void +elf_swap_ehdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Ehdr *src; + Elf_Internal_Ehdr *dst; +{ + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + dst->e_type = bfd_h_get_16 (abfd, (bfd_byte *) src->e_type); + dst->e_machine = bfd_h_get_16 (abfd, (bfd_byte *) src->e_machine); + dst->e_version = bfd_h_get_32 (abfd, (bfd_byte *) src->e_version); + dst->e_entry = get_word (abfd, (bfd_byte *) src->e_entry); + dst->e_phoff = get_word (abfd, (bfd_byte *) src->e_phoff); + dst->e_shoff = get_word (abfd, (bfd_byte *) src->e_shoff); + dst->e_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->e_flags); + dst->e_ehsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_ehsize); + dst->e_phentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phentsize); + dst->e_phnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phnum); + dst->e_shentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shentsize); + dst->e_shnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shnum); + dst->e_shstrndx = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shstrndx); +} + +/* Translate an ELF file header in internal format into an ELF file header in + external format. */ + +static void +elf_swap_ehdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Ehdr *src; + Elf_External_Ehdr *dst; +{ + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_16 (abfd, src->e_type, dst->e_type); + bfd_h_put_16 (abfd, src->e_machine, dst->e_machine); + bfd_h_put_32 (abfd, src->e_version, dst->e_version); + put_word (abfd, src->e_entry, dst->e_entry); + put_word (abfd, src->e_phoff, dst->e_phoff); + put_word (abfd, src->e_shoff, dst->e_shoff); + bfd_h_put_32 (abfd, src->e_flags, dst->e_flags); + bfd_h_put_16 (abfd, src->e_ehsize, dst->e_ehsize); + bfd_h_put_16 (abfd, src->e_phentsize, dst->e_phentsize); + bfd_h_put_16 (abfd, src->e_phnum, dst->e_phnum); + bfd_h_put_16 (abfd, src->e_shentsize, dst->e_shentsize); + bfd_h_put_16 (abfd, src->e_shnum, dst->e_shnum); + bfd_h_put_16 (abfd, src->e_shstrndx, dst->e_shstrndx); +} + + +/* Translate an ELF section header table entry in external format into an + ELF section header table entry in internal format. */ + +static void +elf_swap_shdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Shdr *src; + Elf_Internal_Shdr *dst; +{ + dst->sh_name = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_name); + dst->sh_type = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_type); + dst->sh_flags = get_word (abfd, (bfd_byte *) src->sh_flags); + dst->sh_addr = get_word (abfd, (bfd_byte *) src->sh_addr); + dst->sh_offset = get_word (abfd, (bfd_byte *) src->sh_offset); + dst->sh_size = get_word (abfd, (bfd_byte *) src->sh_size); + dst->sh_link = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_link); + dst->sh_info = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_info); + dst->sh_addralign = get_word (abfd, (bfd_byte *) src->sh_addralign); + dst->sh_entsize = get_word (abfd, (bfd_byte *) src->sh_entsize); + dst->bfd_section = NULL; + dst->contents = NULL; +} + +/* Translate an ELF section header table entry in internal format into an + ELF section header table entry in external format. */ + +static void +elf_swap_shdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Shdr *src; + Elf_External_Shdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_32 (abfd, src->sh_name, dst->sh_name); + bfd_h_put_32 (abfd, src->sh_type, dst->sh_type); + put_word (abfd, src->sh_flags, dst->sh_flags); + put_word (abfd, src->sh_addr, dst->sh_addr); + put_word (abfd, src->sh_offset, dst->sh_offset); + put_word (abfd, src->sh_size, dst->sh_size); + bfd_h_put_32 (abfd, src->sh_link, dst->sh_link); + bfd_h_put_32 (abfd, src->sh_info, dst->sh_info); + put_word (abfd, src->sh_addralign, dst->sh_addralign); + put_word (abfd, src->sh_entsize, dst->sh_entsize); +} + + +/* Translate an ELF program header table entry in external format into an + ELF program header table entry in internal format. */ + +void +elf_swap_phdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Phdr *src; + Elf_Internal_Phdr *dst; +{ + dst->p_type = bfd_h_get_32 (abfd, (bfd_byte *) src->p_type); + dst->p_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->p_flags); + dst->p_offset = get_word (abfd, (bfd_byte *) src->p_offset); + dst->p_vaddr = get_word (abfd, (bfd_byte *) src->p_vaddr); + dst->p_paddr = get_word (abfd, (bfd_byte *) src->p_paddr); + dst->p_filesz = get_word (abfd, (bfd_byte *) src->p_filesz); + dst->p_memsz = get_word (abfd, (bfd_byte *) src->p_memsz); + dst->p_align = get_word (abfd, (bfd_byte *) src->p_align); +} + +void +elf_swap_phdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Phdr *src; + Elf_External_Phdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_32 (abfd, src->p_type, dst->p_type); + put_word (abfd, src->p_offset, dst->p_offset); + put_word (abfd, src->p_vaddr, dst->p_vaddr); + put_word (abfd, src->p_paddr, dst->p_paddr); + put_word (abfd, src->p_filesz, dst->p_filesz); + put_word (abfd, src->p_memsz, dst->p_memsz); + bfd_h_put_32 (abfd, src->p_flags, dst->p_flags); + put_word (abfd, src->p_align, dst->p_align); +} + +/* Translate an ELF reloc from external format to internal format. */ +INLINE void +elf_swap_reloc_in (abfd, src, dst) + bfd *abfd; + Elf_External_Rel *src; + Elf_Internal_Rel *dst; +{ + dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset); + dst->r_info = get_word (abfd, (bfd_byte *) src->r_info); +} + +INLINE void +elf_swap_reloca_in (abfd, src, dst) + bfd *abfd; + Elf_External_Rela *src; + Elf_Internal_Rela *dst; +{ + dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset); + dst->r_info = get_word (abfd, (bfd_byte *) src->r_info); + dst->r_addend = get_word (abfd, (bfd_byte *) src->r_addend); +} + +/* Translate an ELF reloc from internal format to external format. */ +INLINE void +elf_swap_reloc_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Rel *src; + Elf_External_Rel *dst; +{ + put_word (abfd, src->r_offset, dst->r_offset); + put_word (abfd, src->r_info, dst->r_info); +} + +INLINE void +elf_swap_reloca_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Rela *src; + Elf_External_Rela *dst; +{ + put_word (abfd, src->r_offset, dst->r_offset); + put_word (abfd, src->r_info, dst->r_info); + put_word (abfd, src->r_addend, dst->r_addend); +} + +INLINE void +elf_swap_dyn_in (abfd, p, dst) + bfd *abfd; + const PTR p; + Elf_Internal_Dyn *dst; +{ + const Elf_External_Dyn *src = (const Elf_External_Dyn *) p; + + dst->d_tag = get_word (abfd, src->d_tag); + dst->d_un.d_val = get_word (abfd, src->d_un.d_val); +} + +INLINE void +elf_swap_dyn_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Dyn *src; + Elf_External_Dyn *dst; +{ + put_word (abfd, src->d_tag, dst->d_tag); + put_word (abfd, src->d_un.d_val, dst->d_un.d_val); +} + +/* ELF .o/exec file reading */ + + +/* Begin processing a given object. + + First we validate the file by reading in the ELF header and checking + the magic number. */ + +static INLINE boolean +elf_file_p (x_ehdrp) + Elf_External_Ehdr *x_ehdrp; +{ + return ((x_ehdrp->e_ident[EI_MAG0] == ELFMAG0) + && (x_ehdrp->e_ident[EI_MAG1] == ELFMAG1) + && (x_ehdrp->e_ident[EI_MAG2] == ELFMAG2) + && (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3)); +} + +/* Check to see if the file associated with ABFD matches the target vector + that ABFD points to. + + Note that we may be called several times with the same ABFD, but different + target vectors, most of which will not match. We have to avoid leaving + any side effects in ABFD, or any data it points to (like tdata), if the + file does not match the target vector. */ + +const bfd_target * +elf_object_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr x_shdr; /* Section header table entry, external form */ + Elf_Internal_Shdr *i_shdrp = NULL; /* Section header table, internal form */ + unsigned int shindex; + char *shstrtab; /* Internal copy of section header stringtab */ + struct elf_backend_data *ebd; + struct elf_obj_tdata *preserved_tdata = elf_tdata (abfd); + struct elf_obj_tdata *new_tdata = NULL; + + /* Read in the ELF header in external format. */ + + if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + goto got_wrong_format_error; + else + goto got_no_match; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + section header table (FIXME: See comments re sections at top of this + file). */ + + if ((elf_file_p (&x_ehdr) == false) || + (x_ehdr.e_ident[EI_VERSION] != EV_CURRENT) || + (x_ehdr.e_ident[EI_CLASS] != ELFCLASS)) + goto got_wrong_format_error; + + /* Check that file's byte order matches xvec's */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (! bfd_header_big_endian (abfd)) + goto got_wrong_format_error; + break; + case ELFDATA2LSB: /* Little-endian */ + if (! bfd_header_little_endian (abfd)) + goto got_wrong_format_error; + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto got_wrong_format_error; + } + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + new_tdata = ((struct elf_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct elf_obj_tdata))); + if (new_tdata == NULL) + goto got_no_match; + elf_tdata (abfd) = new_tdata; + + /* Now that we know the byte order, swap in the rest of the header */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + /* If there is no section header table, we're hosed. */ + if (i_ehdrp->e_shoff == 0) + goto got_wrong_format_error; + + /* As a simple sanity check, verify that the what BFD thinks is the + size of each section header table entry actually matches the size + recorded in the file. */ + if (i_ehdrp->e_shentsize != sizeof (x_shdr)) + goto got_wrong_format_error; + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + if (ebd->elf_machine_code != i_ehdrp->e_machine + && (ebd->elf_machine_alt1 == 0 || i_ehdrp->e_machine != ebd->elf_machine_alt1) + && (ebd->elf_machine_alt2 == 0 || i_ehdrp->e_machine != ebd->elf_machine_alt2)) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto got_wrong_format_error; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto got_wrong_format_error; + } + } + } + + if (i_ehdrp->e_type == ET_EXEC) + abfd->flags |= EXEC_P; + else if (i_ehdrp->e_type == ET_DYN) + abfd->flags |= DYNAMIC; + + if (i_ehdrp->e_phnum > 0) + abfd->flags |= D_PAGED; + + if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0)) + goto got_no_match; + + /* Remember the entry point specified in the ELF file header. */ + bfd_get_start_address (abfd) = i_ehdrp->e_entry; + + /* Allocate space for a copy of the section header table in + internal form, seek to the section header table in the file, + read it in, and convert it to internal form. */ + i_shdrp = ((Elf_Internal_Shdr *) + bfd_alloc (abfd, sizeof (*i_shdrp) * i_ehdrp->e_shnum)); + elf_elfsections (abfd) = ((Elf_Internal_Shdr **) + bfd_alloc (abfd, + sizeof (i_shdrp) * i_ehdrp->e_shnum)); + if (!i_shdrp || !elf_elfsections (abfd)) + goto got_no_match; + if (bfd_seek (abfd, i_ehdrp->e_shoff, SEEK_SET) != 0) + goto got_no_match; + for (shindex = 0; shindex < i_ehdrp->e_shnum; shindex++) + { + if (bfd_read ((PTR) & x_shdr, sizeof x_shdr, 1, abfd) != sizeof (x_shdr)) + goto got_no_match; + elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex); + elf_elfsections (abfd)[shindex] = i_shdrp + shindex; + } + if (i_ehdrp->e_shstrndx) + { + if (! bfd_section_from_shdr (abfd, i_ehdrp->e_shstrndx)) + goto got_no_match; + } + + /* Read in the program headers. */ + if (i_ehdrp->e_phnum == 0) + elf_tdata (abfd)->phdr = NULL; + else + { + Elf_Internal_Phdr *i_phdr; + unsigned int i; + + elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *) + bfd_alloc (abfd, + (i_ehdrp->e_phnum + * sizeof (Elf_Internal_Phdr)))); + if (elf_tdata (abfd)->phdr == NULL) + goto got_no_match; + if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0) + goto got_no_match; + i_phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++) + { + Elf_External_Phdr x_phdr; + + if (bfd_read ((PTR) &x_phdr, sizeof x_phdr, 1, abfd) + != sizeof x_phdr) + goto got_no_match; + elf_swap_phdr_in (abfd, &x_phdr, i_phdr); + } + } + + /* Read in the string table containing the names of the sections. We + will need the base pointer to this table later. */ + /* We read this inline now, so that we don't have to go through + bfd_section_from_shdr with it (since this particular strtab is + used to find all of the ELF section names.) */ + + shstrtab = bfd_elf_get_str_section (abfd, i_ehdrp->e_shstrndx); + if (!shstrtab) + goto got_no_match; + + /* Once all of the section headers have been read and converted, we + can start processing them. Note that the first section header is + a dummy placeholder entry, so we ignore it. */ + + for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++) + { + if (! bfd_section_from_shdr (abfd, shindex)) + goto got_no_match; + } + + /* Let the backend double check the format and override global + information. */ + if (ebd->elf_backend_object_p) + { + if ((*ebd->elf_backend_object_p) (abfd) == false) + goto got_wrong_format_error; + } + + return (abfd->xvec); + +got_wrong_format_error: + bfd_set_error (bfd_error_wrong_format); + goto got_no_match; +got_no_match: + if (new_tdata != NULL + && new_tdata->elf_sect_ptr != NULL) + bfd_release (abfd, new_tdata->elf_sect_ptr); + if (i_shdrp != NULL) + bfd_release (abfd, i_shdrp); + if (new_tdata != NULL) + bfd_release (abfd, new_tdata); + elf_tdata (abfd) = preserved_tdata; + return (NULL); +} + +/* ELF .o/exec file writing */ + +/* Try to convert a non-ELF reloc into an ELF one. */ + +static boolean +validate_reloc (abfd, areloc) + bfd *abfd; + arelent *areloc; +{ + /* Check whether we really have an ELF howto. */ + + if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) + { + bfd_reloc_code_real_type code; + reloc_howto_type *howto; + + /* Alien reloc: Try to determine its type to replace it with an + equivalent ELF reloc. */ + + if (areloc->howto->pc_relative) + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8_PCREL; + break; + case 12: + code = BFD_RELOC_12_PCREL; + break; + case 16: + code = BFD_RELOC_16_PCREL; + break; + case 24: + code = BFD_RELOC_24_PCREL; + break; + case 32: + code = BFD_RELOC_32_PCREL; + break; + case 64: + code = BFD_RELOC_64_PCREL; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + + if (areloc->howto->pcrel_offset != howto->pcrel_offset) + { + if (howto->pcrel_offset) + areloc->addend += areloc->address; + else + areloc->addend -= areloc->address; /* addend is unsigned!! */ + } + } + else + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8; + break; + case 14: + code = BFD_RELOC_14; + break; + case 16: + code = BFD_RELOC_16; + break; + case 26: + code = BFD_RELOC_26; + break; + case 32: + code = BFD_RELOC_32; + break; + case 64: + code = BFD_RELOC_64; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + } + + if (howto) + areloc->howto = howto; + else + goto fail; + } + + return true; + + fail: + (*_bfd_error_handler) + ("%s: unsupported relocation type %s", + bfd_get_filename (abfd), areloc->howto->name); + bfd_set_error (bfd_error_bad_value); + return false; +} + +/* Write out the relocs. */ + +static void +write_relocs (abfd, sec, data) + bfd *abfd; + asection *sec; + PTR data; +{ + boolean *failedp = (boolean *) data; + Elf_Internal_Shdr *rela_hdr; + Elf_External_Rela *outbound_relocas; + Elf_External_Rel *outbound_relocs; + unsigned int idx; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + asymbol *last_sym = 0; + int last_sym_idx = 0; + + /* If we have already failed, don't do anything. */ + if (*failedp) + return; + + if ((sec->flags & SEC_RELOC) == 0) + return; + + /* The linker backend writes the relocs out itself, and sets the + reloc_count field to zero to inhibit writing them here. Also, + sometimes the SEC_RELOC flag gets set even when there aren't any + relocs. */ + if (sec->reloc_count == 0) + return; + + rela_hdr = &elf_section_data (sec)->rel_hdr; + + rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; + rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size); + if (rela_hdr->contents == NULL) + { + *failedp = true; + return; + } + + /* orelocation has the data, reloc_count has the count... */ + if (use_rela_p) + { + outbound_relocas = (Elf_External_Rela *) rela_hdr->contents; + + for (idx = 0; idx < sec->reloc_count; idx++) + { + Elf_Internal_Rela dst_rela; + Elf_External_Rela *src_rela; + arelent *ptr; + asymbol *sym; + int n; + + ptr = sec->orelocation[idx]; + src_rela = outbound_relocas + idx; + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + dst_rela.r_offset = ptr->address; + else + dst_rela.r_offset = ptr->address + sec->vma; + + sym = *ptr->sym_ptr_ptr; + if (sym == last_sym) + n = last_sym_idx; + else + { + last_sym = sym; + n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); + if (n < 0) + { + *failedp = true; + return; + } + last_sym_idx = n; + } + + if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec + && ! validate_reloc (abfd, ptr)) + { + *failedp = true; + return; + } + + dst_rela.r_info = ELF_R_INFO (n, ptr->howto->type); + + dst_rela.r_addend = ptr->addend; + elf_swap_reloca_out (abfd, &dst_rela, src_rela); + } + } + else + /* REL relocations */ + { + outbound_relocs = (Elf_External_Rel *) rela_hdr->contents; + + for (idx = 0; idx < sec->reloc_count; idx++) + { + Elf_Internal_Rel dst_rel; + Elf_External_Rel *src_rel; + arelent *ptr; + int n; + asymbol *sym; + + ptr = sec->orelocation[idx]; + sym = *ptr->sym_ptr_ptr; + src_rel = outbound_relocs + idx; + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + dst_rel.r_offset = ptr->address; + else + dst_rel.r_offset = ptr->address + sec->vma; + + if (sym == last_sym) + n = last_sym_idx; + else + { + last_sym = sym; + n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); + if (n < 0) + { + *failedp = true; + return; + } + last_sym_idx = n; + } + + if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec + && ! validate_reloc (abfd, ptr)) + { + *failedp = true; + return; + } + + dst_rel.r_info = ELF_R_INFO (n, ptr->howto->type); + + elf_swap_reloc_out (abfd, &dst_rel, src_rel); + } + } +} + +static int +write_out_phdrs (abfd, phdr, count) + bfd *abfd; + Elf_Internal_Phdr *phdr; + int count; +{ + while (count--) + { + Elf_External_Phdr extphdr; + elf_swap_phdr_out (abfd, phdr, &extphdr); + if (bfd_write (&extphdr, sizeof (Elf_External_Phdr), 1, abfd) + != sizeof (Elf_External_Phdr)) + return -1; + phdr++; + } + return 0; +} + +static boolean +write_shdrs_and_ehdr (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr *x_shdrp; /* Section header table, external form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + unsigned int count; + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + + /* swap the header before spitting it out... */ + +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + elf_swap_ehdr_out (abfd, i_ehdrp, &x_ehdr); + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) + != sizeof (x_ehdr))) + return false; + + /* at this point we've concocted all the ELF sections... */ + x_shdrp = (Elf_External_Shdr *) + bfd_alloc (abfd, sizeof (*x_shdrp) * (i_ehdrp->e_shnum)); + if (!x_shdrp) + return false; + + for (count = 0; count < i_ehdrp->e_shnum; count++) + { +#if DEBUG & 2 + elf_debug_section (count, i_shdrp[count]); +#endif + elf_swap_shdr_out (abfd, i_shdrp[count], x_shdrp + count); + } + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0 + || (bfd_write ((PTR) x_shdrp, sizeof (*x_shdrp), i_ehdrp->e_shnum, abfd) + != sizeof (*x_shdrp) * i_ehdrp->e_shnum)) + return false; + + /* need to dump the string table too... */ + + return true; +} + +static long +elf_slurp_symbol_table (abfd, symptrs, dynamic) + bfd *abfd; + asymbol **symptrs; /* Buffer for generated bfd symbols */ + boolean dynamic; +{ + Elf_Internal_Shdr *hdr; + long symcount; /* Number of external ELF symbols */ + elf_symbol_type *sym; /* Pointer to current bfd symbol */ + elf_symbol_type *symbase; /* Buffer for generated bfd symbols */ + Elf_Internal_Sym i_sym; + Elf_External_Sym *x_symp = NULL; + + /* Read each raw ELF symbol, converting from external ELF form to + internal ELF form, and then using the information to create a + canonical bfd symbol table entry. + + Note that we allocate the initial bfd canonical symbol buffer + based on a one-to-one mapping of the ELF symbols to canonical + symbols. We actually use all the ELF symbols, so there will be no + space left over at the end. When we have all the symbols, we + build the caller's pointer vector. */ + + if (dynamic) + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + else + hdr = &elf_tdata (abfd)->symtab_hdr; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1) + return -1; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + if (symcount == 0) + sym = symbase = NULL; + else + { + long i; + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1) + return -1; + + symbase = ((elf_symbol_type *) + bfd_zalloc (abfd, symcount * sizeof (elf_symbol_type))); + if (symbase == (elf_symbol_type *) NULL) + return -1; + sym = symbase; + + /* Temporarily allocate room for the raw ELF symbols. */ + x_symp = ((Elf_External_Sym *) + bfd_malloc (symcount * sizeof (Elf_External_Sym))); + if (x_symp == NULL && symcount != 0) + goto error_return; + + if (bfd_read ((PTR) x_symp, sizeof (Elf_External_Sym), symcount, abfd) + != symcount * sizeof (Elf_External_Sym)) + goto error_return; + /* Skip first symbol, which is a null dummy. */ + for (i = 1; i < symcount; i++) + { + elf_swap_symbol_in (abfd, x_symp + i, &i_sym); + memcpy (&sym->internal_elf_sym, &i_sym, sizeof (Elf_Internal_Sym)); +#ifdef ELF_KEEP_EXTSYM + memcpy (&sym->native_elf_sym, x_symp + i, sizeof (Elf_External_Sym)); +#endif + sym->symbol.the_bfd = abfd; + + sym->symbol.name = bfd_elf_string_from_elf_section (abfd, + hdr->sh_link, + i_sym.st_name); + + sym->symbol.value = i_sym.st_value; + + if (i_sym.st_shndx > 0 && i_sym.st_shndx < SHN_LORESERVE) + { + sym->symbol.section = section_from_elf_index (abfd, + i_sym.st_shndx); + if (sym->symbol.section == NULL) + { + /* This symbol is in a section for which we did not + create a BFD section. Just use bfd_abs_section, + although it is wrong. FIXME. */ + sym->symbol.section = bfd_abs_section_ptr; + } + } + else if (i_sym.st_shndx == SHN_ABS) + { + sym->symbol.section = bfd_abs_section_ptr; + } + else if (i_sym.st_shndx == SHN_COMMON) + { + sym->symbol.section = bfd_com_section_ptr; + /* Elf puts the alignment into the `value' field, and + the size into the `size' field. BFD wants to see the + size in the value field, and doesn't care (at the + moment) about the alignment. */ + sym->symbol.value = i_sym.st_size; + } + else if (i_sym.st_shndx == SHN_UNDEF) + { + sym->symbol.section = bfd_und_section_ptr; + } + else + sym->symbol.section = bfd_abs_section_ptr; + + sym->symbol.value -= sym->symbol.section->vma; + + switch (ELF_ST_BIND (i_sym.st_info)) + { + case STB_LOCAL: + sym->symbol.flags |= BSF_LOCAL; + break; + case STB_GLOBAL: + if (i_sym.st_shndx != SHN_UNDEF + && i_sym.st_shndx != SHN_COMMON) + sym->symbol.flags |= BSF_GLOBAL; + break; + case STB_WEAK: + sym->symbol.flags |= BSF_WEAK; + break; + } + + switch (ELF_ST_TYPE (i_sym.st_info)) + { + case STT_SECTION: + sym->symbol.flags |= BSF_SECTION_SYM | BSF_DEBUGGING; + break; + case STT_FILE: + sym->symbol.flags |= BSF_FILE | BSF_DEBUGGING; + break; + case STT_FUNC: + sym->symbol.flags |= BSF_FUNCTION; + break; + case STT_OBJECT: + sym->symbol.flags |= BSF_OBJECT; + break; + } + + if (dynamic) + sym->symbol.flags |= BSF_DYNAMIC; + + /* Do some backend-specific processing on this symbol. */ + { + struct elf_backend_data *ebd = get_elf_backend_data (abfd); + if (ebd->elf_backend_symbol_processing) + (*ebd->elf_backend_symbol_processing) (abfd, &sym->symbol); + } + + sym++; + } + } + + /* Do some backend-specific processing on this symbol table. */ + { + struct elf_backend_data *ebd = get_elf_backend_data (abfd); + if (ebd->elf_backend_symbol_table_processing) + (*ebd->elf_backend_symbol_table_processing) (abfd, symbase, symcount); + } + + /* We rely on the zalloc to clear out the final symbol entry. */ + + symcount = sym - symbase; + + /* Fill in the user's symbol pointer vector if needed. */ + if (symptrs) + { + long l = symcount; + + sym = symbase; + while (l-- > 0) + { + *symptrs++ = &sym->symbol; + sym++; + } + *symptrs = 0; /* Final null pointer */ + } + + if (x_symp != NULL) + free (x_symp); + return symcount; +error_return: + if (x_symp != NULL) + free (x_symp); + return -1; +} + +/* Read in and swap the external relocs. */ + +static boolean +elf_slurp_reloc_table (abfd, asect, symbols) + bfd *abfd; + asection *asect; + asymbol **symbols; +{ + struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + struct bfd_elf_section_data * const d = elf_section_data (asect); + PTR allocated = NULL; + bfd_byte *native_relocs; + arelent *relents; + arelent *relent; + unsigned int i; + int entsize; + + if (asect->relocation != NULL + || (asect->flags & SEC_RELOC) == 0 + || asect->reloc_count == 0) + return true; + + BFD_ASSERT (asect->rel_filepos == d->rel_hdr.sh_offset + && (asect->reloc_count + == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize)); + + allocated = (PTR) bfd_malloc ((size_t) d->rel_hdr.sh_size); + if (allocated == NULL) + goto error_return; + + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0 + || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd) + != d->rel_hdr.sh_size)) + goto error_return; + + native_relocs = (bfd_byte *) allocated; + + relents = ((arelent *) + bfd_alloc (abfd, asect->reloc_count * sizeof (arelent))); + if (relents == NULL) + goto error_return; + + entsize = d->rel_hdr.sh_entsize; + BFD_ASSERT (entsize == sizeof (Elf_External_Rel) + || entsize == sizeof (Elf_External_Rela)); + + for (i = 0, relent = relents; + i < asect->reloc_count; + i++, relent++, native_relocs += entsize) + { + Elf_Internal_Rela rela; + Elf_Internal_Rel rel; + + if (entsize == sizeof (Elf_External_Rela)) + elf_swap_reloca_in (abfd, (Elf_External_Rela *) native_relocs, &rela); + else + { + elf_swap_reloc_in (abfd, (Elf_External_Rel *) native_relocs, &rel); + rela.r_offset = rel.r_offset; + rela.r_info = rel.r_info; + rela.r_addend = 0; + } + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + relent->address = rela.r_offset; + else + relent->address = rela.r_offset - asect->vma; + + if (ELF_R_SYM (rela.r_info) == 0) + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + else + { + asymbol **ps, *s; + + ps = symbols + ELF_R_SYM (rela.r_info) - 1; + s = *ps; + + /* Canonicalize ELF section symbols. FIXME: Why? */ + if ((s->flags & BSF_SECTION_SYM) == 0) + relent->sym_ptr_ptr = ps; + else + relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; + } + + relent->addend = rela.r_addend; + + if (entsize == sizeof (Elf_External_Rela)) + (*ebd->elf_info_to_howto) (abfd, relent, &rela); + else + (*ebd->elf_info_to_howto_rel) (abfd, relent, &rel); + } + + asect->relocation = relents; + + if (allocated != NULL) + free (allocated); + + return true; + + error_return: + if (allocated != NULL) + free (allocated); + return false; +} + +#ifdef DEBUG +static void +elf_debug_section (num, hdr) + int num; + Elf_Internal_Shdr *hdr; +{ + fprintf (stderr, "\nSection#%d '%s' 0x%.8lx\n", num, + hdr->bfd_section != NULL ? hdr->bfd_section->name : "", + (long) hdr); + fprintf (stderr, + "sh_name = %ld\tsh_type = %ld\tsh_flags = %ld\n", + (long) hdr->sh_name, + (long) hdr->sh_type, + (long) hdr->sh_flags); + fprintf (stderr, + "sh_addr = %ld\tsh_offset = %ld\tsh_size = %ld\n", + (long) hdr->sh_addr, + (long) hdr->sh_offset, + (long) hdr->sh_size); + fprintf (stderr, + "sh_link = %ld\tsh_info = %ld\tsh_addralign = %ld\n", + (long) hdr->sh_link, + (long) hdr->sh_info, + (long) hdr->sh_addralign); + fprintf (stderr, "sh_entsize = %ld\n", + (long) hdr->sh_entsize); + fflush (stderr); +} + +static void +elf_debug_file (ehdrp) + Elf_Internal_Ehdr *ehdrp; +{ + fprintf (stderr, "e_entry = 0x%.8lx\n", (long) ehdrp->e_entry); + fprintf (stderr, "e_phoff = %ld\n", (long) ehdrp->e_phoff); + fprintf (stderr, "e_phnum = %ld\n", (long) ehdrp->e_phnum); + fprintf (stderr, "e_phentsize = %ld\n", (long) ehdrp->e_phentsize); + fprintf (stderr, "e_shoff = %ld\n", (long) ehdrp->e_shoff); + fprintf (stderr, "e_shnum = %ld\n", (long) ehdrp->e_shnum); + fprintf (stderr, "e_shentsize = %ld\n", (long) ehdrp->e_shentsize); +} + +static char * +elf_symbol_flags (flags) + flagword flags; +{ + static char buffer[1024]; + + buffer[0] = '\0'; + if (flags & BSF_LOCAL) + strcat (buffer, " local"); + + if (flags & BSF_GLOBAL) + strcat (buffer, " global"); + + if (flags & BSF_DEBUGGING) + strcat (buffer, " debug"); + + if (flags & BSF_FUNCTION) + strcat (buffer, " function"); + + if (flags & BSF_KEEP) + strcat (buffer, " keep"); + + if (flags & BSF_KEEP_G) + strcat (buffer, " keep_g"); + + if (flags & BSF_WEAK) + strcat (buffer, " weak"); + + if (flags & BSF_SECTION_SYM) + strcat (buffer, " section-sym"); + + if (flags & BSF_OLD_COMMON) + strcat (buffer, " old-common"); + + if (flags & BSF_NOT_AT_END) + strcat (buffer, " not-at-end"); + + if (flags & BSF_CONSTRUCTOR) + strcat (buffer, " constructor"); + + if (flags & BSF_WARNING) + strcat (buffer, " warning"); + + if (flags & BSF_INDIRECT) + strcat (buffer, " indirect"); + + if (flags & BSF_FILE) + strcat (buffer, " file"); + + if (flags & DYNAMIC) + strcat (buffer, " dynamic"); + + if (flags & ~(BSF_LOCAL + | BSF_GLOBAL + | BSF_DEBUGGING + | BSF_FUNCTION + | BSF_KEEP + | BSF_KEEP_G + | BSF_WEAK + | BSF_SECTION_SYM + | BSF_OLD_COMMON + | BSF_NOT_AT_END + | BSF_CONSTRUCTOR + | BSF_WARNING + | BSF_INDIRECT + | BSF_FILE + | BSF_DYNAMIC)) + strcat (buffer, " unknown-bits"); + + return buffer; +} +#endif + +#include "elfcore.h" +#include "elflink.h" + +/* Size-dependent data and functions. */ +const struct elf_size_info NAME(_bfd_elf,size_info) = { + sizeof (Elf_External_Ehdr), + sizeof (Elf_External_Phdr), + sizeof (Elf_External_Shdr), + sizeof (Elf_External_Rel), + sizeof (Elf_External_Rela), + sizeof (Elf_External_Sym), + sizeof (Elf_External_Dyn), + sizeof (Elf_External_Note), + + ARCH_SIZE, FILE_ALIGN, + ELFCLASS, EV_CURRENT, + write_out_phdrs, + write_shdrs_and_ehdr, + write_relocs, + elf_swap_symbol_out, + elf_slurp_reloc_table, + elf_slurp_symbol_table, + elf_swap_dyn_in +}; diff --git a/contrib/gdb/bfd/elfcore.h b/contrib/gdb/bfd/elfcore.h new file mode 100644 index 000000000000..8100627c9ade --- /dev/null +++ b/contrib/gdb/bfd/elfcore.h @@ -0,0 +1,475 @@ +/* ELF core file support for BFD. + Copyright (C) 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* Core file support */ + +#ifdef HAVE_SYS_PROCFS_H /* Some core file support requires host /proc files */ +#include +#include +#else +#define bfd_prstatus(abfd, descdata, descsz, filepos) true +#define bfd_fpregset(abfd, descdata, descsz, filepos) true +#define bfd_prpsinfo(abfd, descdata, descsz, filepos) true +#endif + +#ifdef HAVE_SYS_PROCFS_H + +static boolean +bfd_prstatus (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + asection *newsect; + prstatus_t *status = (prstatus_t *) 0; + + if (descsz == sizeof (prstatus_t)) + { + newsect = bfd_make_section (abfd, ".reg"); + if (newsect == NULL) + return false; + newsect->_raw_size = sizeof (status->pr_reg); + newsect->filepos = filepos + (long) &status->pr_reg; + newsect->flags = SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + if ((core_prstatus (abfd) = bfd_alloc (abfd, descsz)) != NULL) + { + memcpy (core_prstatus (abfd), descdata, descsz); + } + } + return true; +} + +/* Stash a copy of the prpsinfo structure away for future use. */ + +static boolean +bfd_prpsinfo (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + if (descsz == sizeof (prpsinfo_t)) + { + if ((core_prpsinfo (abfd) = bfd_alloc (abfd, descsz)) == NULL) + return false; + memcpy (core_prpsinfo (abfd), descdata, descsz); + } + return true; +} + +static boolean +bfd_fpregset (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + asection *newsect; + + newsect = bfd_make_section (abfd, ".reg2"); + if (newsect == NULL) + return false; + newsect->_raw_size = descsz; + newsect->filepos = filepos; + newsect->flags = SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + return true; +} + +#endif /* HAVE_SYS_PROCFS_H */ + +/* Return a pointer to the args (including the command name) that were + seen by the program that generated the core dump. Note that for + some reason, a spurious space is tacked onto the end of the args + in some (at least one anyway) implementations, so strip it off if + it exists. */ + +char * +elf_core_file_failing_command (abfd) + bfd *abfd; +{ +#ifdef HAVE_SYS_PROCFS_H + if (core_prpsinfo (abfd)) + { + prpsinfo_t *p = core_prpsinfo (abfd); + char *scan = p->pr_psargs; + while (*scan++) + {; + } + scan -= 2; + if ((scan > p->pr_psargs) && (*scan == ' ')) + { + *scan = '\000'; + } + return p->pr_psargs; + } +#endif + return NULL; +} + +/* Return the number of the signal that caused the core dump. Presumably, + since we have a core file, we got a signal of some kind, so don't bother + checking the other process status fields, just return the signal number. + */ + +int +elf_core_file_failing_signal (abfd) + bfd *abfd; +{ +#ifdef HAVE_SYS_PROCFS_H + if (core_prstatus (abfd)) + { + return ((prstatus_t *) (core_prstatus (abfd)))->pr_cursig; + } +#endif + return -1; +} + +/* Check to see if the core file could reasonably be expected to have + come for the current executable file. Note that by default we return + true unless we find something that indicates that there might be a + problem. + */ + +boolean +elf_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ +#ifdef HAVE_SYS_PROCFS_H + char *corename; + char *execname; +#endif + + /* First, xvecs must match since both are ELF files for the same target. */ + + if (core_bfd->xvec != exec_bfd->xvec) + { + bfd_set_error (bfd_error_system_call); + return false; + } + +#ifdef HAVE_SYS_PROCFS_H + + /* If no prpsinfo, just return true. Otherwise, grab the last component + of the exec'd pathname from the prpsinfo. */ + + if (core_prpsinfo (core_bfd)) + { + corename = (((prpsinfo_t *) core_prpsinfo (core_bfd))->pr_fname); + } + else + { + return true; + } + + /* Find the last component of the executable pathname. */ + + if ((execname = strrchr (exec_bfd->filename, '/')) != NULL) + { + execname++; + } + else + { + execname = (char *) exec_bfd->filename; + } + + /* See if they match */ + + return strcmp (execname, corename) ? false : true; + +#else + + return true; + +#endif /* HAVE_SYS_PROCFS_H */ +} + +/* ELF core files contain a segment of type PT_NOTE, that holds much of + the information that would normally be available from the /proc interface + for the process, at the time the process dumped core. Currently this + includes copies of the prstatus, prpsinfo, and fpregset structures. + + Since these structures are potentially machine dependent in size and + ordering, bfd provides two levels of support for them. The first level, + available on all machines since it does not require that the host + have /proc support or the relevant include files, is to create a bfd + section for each of the prstatus, prpsinfo, and fpregset structures, + without any interpretation of their contents. With just this support, + the bfd client will have to interpret the structures itself. Even with + /proc support, it might want these full structures for it's own reasons. + + In the second level of support, where HAVE_SYS_PROCFS_H is defined, + bfd will pick apart the structures to gather some additional + information that clients may want, such as the general register + set, the name of the exec'ed file and its arguments, the signal (if + any) that caused the core dump, etc. + + */ + +static boolean +elf_corefile_note (abfd, hdr) + bfd *abfd; + Elf_Internal_Phdr *hdr; +{ + Elf_External_Note *x_note_p; /* Elf note, external form */ + Elf_Internal_Note i_note; /* Elf note, internal form */ + char *buf = NULL; /* Entire note segment contents */ + char *namedata; /* Name portion of the note */ + char *descdata; /* Descriptor portion of the note */ + char *sectname; /* Name to use for new section */ + long filepos; /* File offset to descriptor data */ + asection *newsect; + + if (hdr->p_filesz > 0 + && (buf = (char *) bfd_malloc ((size_t) hdr->p_filesz)) != NULL + && bfd_seek (abfd, hdr->p_offset, SEEK_SET) != -1 + && bfd_read ((PTR) buf, hdr->p_filesz, 1, abfd) == hdr->p_filesz) + { + x_note_p = (Elf_External_Note *) buf; + while ((char *) x_note_p < (buf + hdr->p_filesz)) + { + i_note.namesz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->namesz); + i_note.descsz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->descsz); + i_note.type = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->type); + namedata = x_note_p->name; + descdata = namedata + BFD_ALIGN (i_note.namesz, 4); + filepos = hdr->p_offset + (descdata - buf); + switch (i_note.type) + { + case NT_PRSTATUS: + /* process descdata as prstatus info */ + if (! bfd_prstatus (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".prstatus"; + break; + case NT_FPREGSET: + /* process descdata as fpregset info */ + if (! bfd_fpregset (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".fpregset"; + break; + case NT_PRPSINFO: + /* process descdata as prpsinfo */ + if (! bfd_prpsinfo (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".prpsinfo"; + break; + default: + /* Unknown descriptor, just ignore it. */ + sectname = NULL; + break; + } + if (sectname != NULL) + { + newsect = bfd_make_section (abfd, sectname); + if (newsect == NULL) + return false; + newsect->_raw_size = i_note.descsz; + newsect->filepos = filepos; + newsect->flags = SEC_ALLOC | SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + } + x_note_p = (Elf_External_Note *) + (descdata + BFD_ALIGN (i_note.descsz, 4)); + } + } + if (buf != NULL) + { + free (buf); + } + else if (hdr->p_filesz > 0) + { + return false; + } + return true; + +} + +/* Core files are simply standard ELF formatted files that partition + the file using the execution view of the file (program header table) + rather than the linking view. In fact, there is no section header + table in a core file. + + The process status information (including the contents of the general + register set) and the floating point register set are stored in a + segment of type PT_NOTE. We handcraft a couple of extra bfd sections + that allow standard bfd access to the general registers (.reg) and the + floating point registers (.reg2). + + */ + +const bfd_target * +elf_core_file_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Phdr x_phdr; /* Program header table entry, external form */ + Elf_Internal_Phdr *i_phdrp; /* Program header table, internal form */ + unsigned int phindex; + struct elf_backend_data *ebd; + + /* Read in the ELF header in external format. */ + + if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + program header table (FIXME: See comments re segments at top of this + file). */ + + if (elf_file_p (&x_ehdr) == false) + { + wrong: + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* FIXME, Check EI_VERSION here ! */ + + { +#if ARCH_SIZE == 32 + int desired_address_size = ELFCLASS32; +#endif +#if ARCH_SIZE == 64 + int desired_address_size = ELFCLASS64; +#endif + + if (x_ehdr.e_ident[EI_CLASS] != desired_address_size) + goto wrong; + } + + /* Switch xvec to match the specified byte order. */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (! bfd_big_endian (abfd)) + goto wrong; + break; + case ELFDATA2LSB: /* Little-endian */ + if (! bfd_little_endian (abfd)) + goto wrong; + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto wrong; + } + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + elf_tdata (abfd) = + (struct elf_obj_tdata *) bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (elf_tdata (abfd) == NULL) + return NULL; + + /* FIXME, `wrong' returns from this point onward, leak memory. */ + + /* Now that we know the byte order, swap in the rest of the header */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + if (ebd->elf_machine_code != i_ehdrp->e_machine + && (ebd->elf_machine_alt1 == 0 || i_ehdrp->e_machine != ebd->elf_machine_alt1) + && (ebd->elf_machine_alt2 == 0 || i_ehdrp->e_machine != ebd->elf_machine_alt2)) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto wrong; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto wrong; + } + } + } + + /* If there is no program header, or the type is not a core file, then + we are hosed. */ + if (i_ehdrp->e_phoff == 0 || i_ehdrp->e_type != ET_CORE) + goto wrong; + + /* Allocate space for a copy of the program header table in + internal form, seek to the program header table in the file, + read it in, and convert it to internal form. As a simple sanity + check, verify that the what BFD thinks is the size of each program + header table entry actually matches the size recorded in the file. */ + + if (i_ehdrp->e_phentsize != sizeof (x_phdr)) + goto wrong; + i_phdrp = (Elf_Internal_Phdr *) + bfd_alloc (abfd, sizeof (*i_phdrp) * i_ehdrp->e_phnum); + if (!i_phdrp) + return NULL; + if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1) + return NULL; + for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++) + { + if (bfd_read ((PTR) & x_phdr, sizeof (x_phdr), 1, abfd) + != sizeof (x_phdr)) + return NULL; + elf_swap_phdr_in (abfd, &x_phdr, i_phdrp + phindex); + } + + /* Once all of the program headers have been read and converted, we + can start processing them. */ + + for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++) + { + bfd_section_from_phdr (abfd, i_phdrp + phindex, phindex); + if ((i_phdrp + phindex)->p_type == PT_NOTE) + { + if (! elf_corefile_note (abfd, i_phdrp + phindex)) + return NULL; + } + } + + /* Remember the entry point specified in the ELF file header. */ + + bfd_get_start_address (abfd) = i_ehdrp->e_entry; + + return abfd->xvec; +} diff --git a/contrib/gdb/bfd/elflink.c b/contrib/gdb/bfd/elflink.c new file mode 100644 index 000000000000..7b204f763e09 --- /dev/null +++ b/contrib/gdb/bfd/elflink.c @@ -0,0 +1,372 @@ +/* ELF linking support for BFD. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" + +boolean +_bfd_elf_create_got_section (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* This function may be called more than once. */ + if (bfd_get_section_by_name (abfd, ".got") != NULL) + return true; + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, 2)) + return false; + + if (bed->want_got_plt) + { + s = bfd_make_section (abfd, ".got.plt"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, 2)) + return false; + } + + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got + (or .got.plt) section. We don't do this in the linker script + because we don't want to define the symbol if we are not creating + a global offset table. */ + h = NULL; + if (!(_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) NULL, false, get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + /* The first three global offset table entries are reserved. */ + s->_raw_size += 3 * 4; + + return true; +} + + +/* Create dynamic sections when linking against a dynamic object. */ + +boolean +_bfd_elf_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + s = bfd_make_section (abfd, ".plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, + (flags | SEC_CODE + | (bed->plt_readonly ? SEC_READONLY : 0))) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + if (bed->want_plt_sym) + { + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + struct elf_link_hash_entry *h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + s = bfd_make_section (abfd, bed->use_rela_p ? ".rela.plt" : ".rel.plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + if (! _bfd_elf_create_got_section (abfd, info)) + return false; + + /* The .dynbss section is a place to put symbols which are defined + by dynamic objects, are referenced by regular objects, and are + not functions. We must allocate space for them in the process + image and use a R_*_COPY reloc to tell the dynamic linker to + initialize them at run time. The linker script puts the .dynbss + section into the .bss section of the final image. */ + s = bfd_make_section (abfd, ".dynbss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) + return false; + + /* The .rel[a].bss section holds copy relocs. This section is not + normally needed. We need to create it here, though, so that the + linker will map it to an output section. We can't just create it + only if we need it, because we will not know whether we need it + until we have seen all the input files, and the first time the + main linker code calls BFD after examining all the input files + (size_dynamic_sections) the input sections have already been + mapped to the output sections. If the section turns out not to + be needed, we can discard it later. We will never need this + section when generating a shared object, since they do not use + copy relocs. */ + if (! info->shared) + { + s = bfd_make_section (abfd, bed->use_rela_p ? ".rela.bss" : ".rel.bss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + } + + return true; +} + + +/* Record a new dynamic symbol. We record the dynamic symbols as we + read the input files, since we need to have a list of all of them + before we can determine the final sizes of the output sections. + Note that we may actually call this function even though we are not + going to output any dynamic symbols; in some cases we know that a + symbol should be in the dynamic symbol table, but only if there is + one. */ + +boolean +_bfd_elf_link_record_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (h->dynindx == -1) + { + struct bfd_strtab_hash *dynstr; + + h->dynindx = elf_hash_table (info)->dynsymcount; + ++elf_hash_table (info)->dynsymcount; + + dynstr = elf_hash_table (info)->dynstr; + if (dynstr == NULL) + { + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init (); + if (dynstr == NULL) + return false; + } + + h->dynstr_index = ((unsigned long) + _bfd_stringtab_add (dynstr, h->root.root.string, + true, false)); + if (h->dynstr_index == (unsigned long) -1) + return false; + } + + return true; +} + +/* Create a special linker section, or return a pointer to a linker section already created */ + +elf_linker_section_t * +_bfd_elf_create_linker_section (abfd, info, which, defaults) + bfd *abfd; + struct bfd_link_info *info; + enum elf_linker_section_enum which; + elf_linker_section_t *defaults; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; + + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; + + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) + { + asection *s; + + lsect = (elf_linker_section_t *) + bfd_alloc (dynobj, sizeof (elf_linker_section_t)); + + *lsect = *defaults; + elf_linker_section (dynobj, which) = lsect; + lsect->which = which; + lsect->hole_written_p = false; + + /* See if the sections already exist */ + lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name); + if (!s) + { + lsect->section = s = bfd_make_section (dynobj, lsect->name); + + if (s == NULL) + return (elf_linker_section_t *)0; + + bfd_set_section_flags (dynobj, s, defaults->flags); + bfd_set_section_alignment (dynobj, s, lsect->alignment); + } + else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment) + bfd_set_section_alignment (dynobj, s, lsect->alignment); + + s->_raw_size = align_power (s->_raw_size, lsect->alignment); + + /* Is there a hole we have to provide? If so check whether the segment is + too big already */ + if (lsect->hole_size) + { + lsect->hole_offset = s->_raw_size; + s->_raw_size += lsect->hole_size; + if (lsect->hole_offset > lsect->max_hole_offset) + { + (*_bfd_error_handler) ("%s: Section %s is already to large to put hole of %ld bytes in", + bfd_get_filename (abfd), + lsect->name, + (long)lsect->hole_size); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + } + } + +#ifdef DEBUG + fprintf (stderr, "Creating section %s, current size = %ld\n", + lsect->name, (long)s->_raw_size); +#endif + + if (lsect->sym_name) + { + struct elf_link_hash_entry *h = NULL; +#ifdef DEBUG + fprintf (stderr, "Adding %s to section %s\n", + lsect->sym_name, + lsect->name); +#endif + h = (struct elf_link_hash_entry *) + bfd_link_hash_lookup (info->hash, lsect->sym_name, false, false, false); + + if ((h == NULL || h->root.type == bfd_link_hash_undefined) + && !(_bfd_generic_link_add_one_symbol (info, + abfd, + lsect->sym_name, + BSF_GLOBAL, + s, + ((lsect->hole_size) + ? s->_raw_size - lsect->hole_size + lsect->sym_offset + : lsect->sym_offset), + (const char *) NULL, + false, + get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return (elf_linker_section_t *)0; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; + h->type = STT_OBJECT; + lsect->sym_hash = h; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return (elf_linker_section_t *)0; + } + } + + /* Find the related sections if they have been created */ + if (lsect->bss_name && !lsect->bss_section) + lsect->bss_section = bfd_get_section_by_name (dynobj, lsect->bss_name); + + if (lsect->rel_name && !lsect->rel_section) + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + + return lsect; +} + + +/* Find a linker generated pointer with a given addend and type. */ + +elf_linker_section_pointers_t * +_bfd_elf_find_pointer_linker_section (linker_pointers, addend, which) + elf_linker_section_pointers_t *linker_pointers; + bfd_signed_vma addend; + elf_linker_section_enum_t which; +{ + for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) + { + if (which == linker_pointers->which && addend == linker_pointers->addend) + return linker_pointers; + } + + return (elf_linker_section_pointers_t *)0; +} + + +/* Make the .rela section corresponding to the generated linker section. */ + +boolean +_bfd_elf_make_linker_section_rela (dynobj, lsect, alignment) + bfd *dynobj; + elf_linker_section_t *lsect; + int alignment; +{ + if (lsect->rel_section) + return true; + + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL) + { + lsect->rel_section = bfd_make_section (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL + || ! bfd_set_section_flags (dynobj, + lsect->rel_section, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, lsect->rel_section, alignment)) + return false; + } + + return true; +} + diff --git a/contrib/gdb/bfd/elflink.h b/contrib/gdb/bfd/elflink.h new file mode 100644 index 000000000000..4ef3c8b3c49b --- /dev/null +++ b/contrib/gdb/bfd/elflink.h @@ -0,0 +1,3424 @@ +/* ELF linker support. + Copyright 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ELF linker code. */ + +static boolean elf_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static Elf_Internal_Rela *elf_link_read_relocs + PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, boolean)); +static boolean elf_export_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); +static boolean elf_adjust_dynamic_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); + +/* This struct is used to pass information to routines called via + elf_link_hash_traverse which must return failure. */ + +struct elf_info_failed +{ + boolean failed; + struct bfd_link_info *info; +}; + +/* Given an ELF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +elf_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return elf_link_add_object_symbols (abfd, info); + case bfd_archive: + return elf_link_add_archive_symbols (abfd, info); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + + +/* Add symbols from an ELF archive file to the linker hash table. We + don't use _bfd_generic_link_add_archive_symbols because of a + problem which arises on UnixWare. The UnixWare libc.so is an + archive which includes an entry libc.so.1 which defines a bunch of + symbols. The libc.so archive also includes a number of other + object files, which also define symbols, some of which are the same + as those defined in libc.so.1. Correct linking requires that we + consider each object file in turn, and include it if it defines any + symbols we need. _bfd_generic_link_add_archive_symbols does not do + this; it looks through the list of undefined symbols, and includes + any object file which defines them. When this algorithm is used on + UnixWare, it winds up pulling in libc.so.1 early and defining a + bunch of symbols. This means that some of the other objects in the + archive are not included in the link, which is incorrect since they + precede libc.so.1 in the archive. + + Fortunately, ELF archive handling is simpler than that done by + _bfd_generic_link_add_archive_symbols, which has to allow for a.out + oddities. In ELF, if we find a symbol in the archive map, and the + symbol is currently undefined, we know that we must pull in that + object file. + + Unfortunately, we do have to make multiple passes over the symbol + table until nothing further is resolved. */ + +static boolean +elf_link_add_archive_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + symindex c; + boolean *defined = NULL; + boolean *included = NULL; + carsym *symdefs; + boolean loop; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return true; + bfd_set_error (bfd_error_no_armap); + return false; + } + + /* Keep track of all symbols we know to be already defined, and all + files we know to be already included. This is to speed up the + second and subsequent passes. */ + c = bfd_ardata (abfd)->symdef_count; + if (c == 0) + return true; + defined = (boolean *) bfd_malloc (c * sizeof (boolean)); + included = (boolean *) bfd_malloc (c * sizeof (boolean)); + if (defined == (boolean *) NULL || included == (boolean *) NULL) + goto error_return; + memset (defined, 0, c * sizeof (boolean)); + memset (included, 0, c * sizeof (boolean)); + + symdefs = bfd_ardata (abfd)->symdefs; + + do + { + file_ptr last; + symindex i; + carsym *symdef; + carsym *symdefend; + + loop = false; + last = -1; + + symdef = symdefs; + symdefend = symdef + c; + for (i = 0; symdef < symdefend; symdef++, i++) + { + struct elf_link_hash_entry *h; + bfd *element; + struct bfd_link_hash_entry *undefs_tail; + symindex mark; + + if (defined[i] || included[i]) + continue; + if (symdef->file_offset == last) + { + included[i] = true; + continue; + } + + h = elf_link_hash_lookup (elf_hash_table (info), symdef->name, + false, false, false); + if (h == (struct elf_link_hash_entry *) NULL) + continue; + if (h->root.type != bfd_link_hash_undefined) + { + if (h->root.type != bfd_link_hash_undefweak) + defined[i] = true; + continue; + } + + /* We need to include this archive member. */ + + element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); + if (element == (bfd *) NULL) + goto error_return; + + if (! bfd_check_format (element, bfd_object)) + goto error_return; + + /* Doublecheck that we have not included this object + already--it should be impossible, but there may be + something wrong with the archive. */ + if (element->archive_pass != 0) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + element->archive_pass = 1; + + undefs_tail = info->hash->undefs_tail; + + if (! (*info->callbacks->add_archive_element) (info, element, + symdef->name)) + goto error_return; + if (! elf_link_add_object_symbols (element, info)) + goto error_return; + + /* If there are any new undefined symbols, we need to make + another pass through the archive in order to see whether + they can be defined. FIXME: This isn't perfect, because + common symbols wind up on undefs_tail and because an + undefined symbol which is defined later on in this pass + does not require another pass. This isn't a bug, but it + does make the code less efficient than it could be. */ + if (undefs_tail != info->hash->undefs_tail) + loop = true; + + /* Look backward to mark all symbols from this object file + which we have already seen in this pass. */ + mark = i; + do + { + included[mark] = true; + if (mark == 0) + break; + --mark; + } + while (symdefs[mark].file_offset == symdef->file_offset); + + /* We mark subsequent symbols from this object file as we go + on through the loop. */ + last = symdef->file_offset; + } + } + while (loop); + + free (defined); + free (included); + + return true; + + error_return: + if (defined != (boolean *) NULL) + free (defined); + if (included != (boolean *) NULL) + free (included); + return false; +} + +/* Add symbols from an ELF object file to the linker hash table. */ + +static boolean +elf_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean (*add_symbol_hook) PARAMS ((bfd *, struct bfd_link_info *, + const Elf_Internal_Sym *, + const char **, flagword *, + asection **, bfd_vma *)); + boolean (*check_relocs) PARAMS ((bfd *, struct bfd_link_info *, + asection *, const Elf_Internal_Rela *)); + boolean collect; + Elf_Internal_Shdr *hdr; + size_t symcount; + size_t extsymcount; + size_t extsymoff; + Elf_External_Sym *buf = NULL; + struct elf_link_hash_entry **sym_hash; + boolean dynamic; + Elf_External_Dyn *dynbuf = NULL; + struct elf_link_hash_entry *weaks; + Elf_External_Sym *esym; + Elf_External_Sym *esymend; + + add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook; + collect = get_elf_backend_data (abfd)->collect; + + /* As a GNU extension, any input sections which are named + .gnu.warning.SYMBOL are treated as warning symbols for the given + symbol. This differs from .gnu.warning sections, which generate + warnings when they are included in an output file. */ + if (! info->shared) + { + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) + { + const char *name; + + name = bfd_get_section_name (abfd, s); + if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0) + { + char *msg; + bfd_size_type sz; + + sz = bfd_section_size (abfd, s); + msg = (char *) bfd_alloc (abfd, sz); + if (msg == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, msg, (file_ptr) 0, sz)) + goto error_return; + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, + name + sizeof ".gnu.warning." - 1, + BSF_WARNING, s, (bfd_vma) 0, msg, false, collect, + (struct bfd_link_hash_entry **) NULL))) + goto error_return; + + if (! info->relocateable) + { + /* Clobber the section size so that the warning does + not get copied into the output file. */ + s->_raw_size = 0; + } + } + } + } + + /* A stripped shared library might only have a dynamic symbol table, + not a regular symbol table. In that case we can still go ahead + and link using the dynamic symbol table. */ + if (elf_onesymtab (abfd) == 0 + && elf_dynsymtab (abfd) != 0) + { + elf_onesymtab (abfd) = elf_dynsymtab (abfd); + elf_tdata (abfd)->symtab_hdr = elf_tdata (abfd)->dynsymtab_hdr; + } + + hdr = &elf_tdata (abfd)->symtab_hdr; + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols at + this point. */ + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + buf = ((Elf_External_Sym *) + bfd_malloc (extsymcount * sizeof (Elf_External_Sym))); + if (buf == NULL && extsymcount != 0) + goto error_return; + + /* We store a pointer to the hash table entry for each external + symbol. */ + sym_hash = ((struct elf_link_hash_entry **) + bfd_alloc (abfd, + extsymcount * sizeof (struct elf_link_hash_entry *))); + if (sym_hash == NULL) + goto error_return; + elf_sym_hashes (abfd) = sym_hash; + + if (elf_elfheader (abfd)->e_type != ET_DYN) + { + dynamic = false; + + /* If we are creating a shared library, create all the dynamic + sections immediately. We need to attach them to something, + so we attach them to this BFD, provided it is the right + format. FIXME: If there are no input BFD's of the same + format as the output, we can't make a shared library. */ + if (info->shared + && ! elf_hash_table (info)->dynamic_sections_created + && abfd->xvec == info->hash->creator) + { + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + } + } + else + { + asection *s; + boolean add_needed; + const char *name; + bfd_size_type oldsize; + bfd_size_type strindex; + + dynamic = true; + + /* You can't use -r against a dynamic object. Also, there's no + hope of using a dynamic object which does not exactly match + the format of the output file. */ + if (info->relocateable + || info->hash->creator != abfd->xvec) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + /* Find the name to use in a DT_NEEDED entry that refers to this + object. If the object has a DT_SONAME entry, we use it. + Otherwise, if the generic linker stuck something in + elf_dt_name, we use that. Otherwise, we just use the file + name. If the generic linker put a null string into + elf_dt_name, we don't make a DT_NEEDED entry at all, even if + there is a DT_SONAME entry. */ + add_needed = true; + name = bfd_get_filename (abfd); + if (elf_dt_name (abfd) != NULL) + { + name = elf_dt_name (abfd); + if (*name == '\0') + add_needed = false; + } + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + Elf_External_Dyn *extdyn; + Elf_External_Dyn *extdynend; + int elfsec; + unsigned long link; + + dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size); + if (dynbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, + (file_ptr) 0, s->_raw_size)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + link = elf_elfsections (abfd)[elfsec]->sh_link; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); + for (; extdyn < extdynend; extdyn++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (abfd, extdyn, &dyn); + if (dyn.d_tag == DT_SONAME) + { + name = bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (name == NULL) + goto error_return; + } + if (dyn.d_tag == DT_NEEDED) + { + struct bfd_link_needed_list *n, **pn; + char *fnm, *anm; + + n = ((struct bfd_link_needed_list *) + bfd_alloc (abfd, sizeof (struct bfd_link_needed_list))); + fnm = bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (n == NULL || fnm == NULL) + goto error_return; + anm = bfd_alloc (abfd, strlen (fnm) + 1); + if (anm == NULL) + goto error_return; + strcpy (anm, fnm); + n->name = anm; + n->by = abfd; + n->next = NULL; + for (pn = &elf_hash_table (info)->needed; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = n; + } + } + + free (dynbuf); + dynbuf = NULL; + } + + /* We do not want to include any of the sections in a dynamic + object in the output file. We hack by simply clobbering the + list of sections in the BFD. This could be handled more + cleanly by, say, a new section flag; the existing + SEC_NEVER_LOAD flag is not the one we want, because that one + still implies that the section takes up space in the output + file. */ + abfd->sections = NULL; + abfd->section_count = 0; + + /* If this is the first dynamic object found in the link, create + the special sections required for dynamic linking. */ + if (! elf_hash_table (info)->dynamic_sections_created) + { + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + } + + if (add_needed) + { + /* Add a DT_NEEDED entry for this dynamic object. */ + oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr); + strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr, name, + true, false); + if (strindex == (bfd_size_type) -1) + goto error_return; + + if (oldsize == _bfd_stringtab_size (elf_hash_table (info)->dynstr)) + { + asection *sdyn; + Elf_External_Dyn *dyncon, *dynconend; + + /* The hash table size did not change, which means that + the dynamic object name was already entered. If we + have already included this dynamic object in the + link, just ignore it. There is no reason to include + a particular dynamic object more than once. */ + sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, + ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + dyncon = (Elf_External_Dyn *) sdyn->contents; + dynconend = (Elf_External_Dyn *) (sdyn->contents + + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, + &dyn); + if (dyn.d_tag == DT_NEEDED + && dyn.d_un.d_val == strindex) + { + if (buf != NULL) + free (buf); + return true; + } + } + } + + if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex)) + goto error_return; + } + + /* Save the SONAME, if there is one, because sometimes the + linker emulation code will need to know it. */ + if (*name == '\0') + name = bfd_get_filename (abfd); + elf_dt_name (abfd) = name; + } + + if (bfd_seek (abfd, + hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym), + SEEK_SET) != 0 + || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd) + != extsymcount * sizeof (Elf_External_Sym))) + goto error_return; + + weaks = NULL; + + esymend = buf + extsymcount; + for (esym = buf; esym < esymend; esym++, sym_hash++) + { + Elf_Internal_Sym sym; + int bind; + bfd_vma value; + asection *sec; + flagword flags; + const char *name; + struct elf_link_hash_entry *h; + boolean definition; + boolean size_change_ok, type_change_ok; + boolean new_weakdef; + + elf_swap_symbol_in (abfd, esym, &sym); + + flags = BSF_NO_FLAGS; + sec = NULL; + value = sym.st_value; + *sym_hash = NULL; + + bind = ELF_ST_BIND (sym.st_info); + if (bind == STB_LOCAL) + { + /* This should be impossible, since ELF requires that all + global symbols follow all local symbols, and that sh_info + point to the first global symbol. Unfortunatealy, Irix 5 + screws this up. */ + continue; + } + else if (bind == STB_GLOBAL) + { + if (sym.st_shndx != SHN_UNDEF + && sym.st_shndx != SHN_COMMON) + flags = BSF_GLOBAL; + else + flags = 0; + } + else if (bind == STB_WEAK) + flags = BSF_WEAK; + else + { + /* Leave it up to the processor backend. */ + } + + if (sym.st_shndx == SHN_UNDEF) + sec = bfd_und_section_ptr; + else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE) + { + sec = section_from_elf_index (abfd, sym.st_shndx); + if (sec != NULL) + value -= sec->vma; + else + sec = bfd_abs_section_ptr; + } + else if (sym.st_shndx == SHN_ABS) + sec = bfd_abs_section_ptr; + else if (sym.st_shndx == SHN_COMMON) + { + sec = bfd_com_section_ptr; + /* What ELF calls the size we call the value. What ELF + calls the value we call the alignment. */ + value = sym.st_size; + } + else + { + /* Leave it up to the processor backend. */ + } + + name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name); + if (name == (const char *) NULL) + goto error_return; + + if (add_symbol_hook) + { + if (! (*add_symbol_hook) (abfd, info, &sym, &name, &flags, &sec, + &value)) + goto error_return; + + /* The hook function sets the name to NULL if this symbol + should be skipped for some reason. */ + if (name == (const char *) NULL) + continue; + } + + /* Sanity check that all possibilities were handled. */ + if (sec == (asection *) NULL) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (bfd_is_und_section (sec) + || bfd_is_com_section (sec)) + definition = false; + else + definition = true; + + size_change_ok = false; + type_change_ok = get_elf_backend_data (abfd)->type_change_ok; + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + /* We need to look up the symbol now in order to get some of + the dynamic object handling right. We pass the hash + table entry in to _bfd_generic_link_add_one_symbol so + that it does not have to look it up again. */ + if (! bfd_is_und_section (sec)) + h = elf_link_hash_lookup (elf_hash_table (info), name, + true, false, false); + else + h = ((struct elf_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, name, true, + false, false)); + if (h == NULL) + goto error_return; + *sym_hash = h; + + if (h->root.type == bfd_link_hash_new) + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + + 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; + + /* It's OK to change the type if it used to be a weak + definition. */ + if (h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_undefweak) + type_change_ok = true; + + /* It's OK to change the size if it used to be a weak + definition, or if it used to be undefined, or if we will + be overriding an old definition. */ + if (type_change_ok + || h->root.type == bfd_link_hash_undefined) + size_change_ok = true; + + /* If we are looking at a dynamic object, and this is a + definition, we need to see if it has already been defined + by some other object. If it has, we want to use the + existing definition, and we do not want to report a + multiple symbol definition error; we do this by + clobbering sec to be bfd_und_section_ptr. */ + if (dynamic && definition) + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || (h->root.type == bfd_link_hash_common + && bind == STB_WEAK)) + { + sec = bfd_und_section_ptr; + definition = false; + size_change_ok = true; + } + } + + /* Similarly, if we are not looking at a dynamic object, and + we have a definition, we want to override any definition + we may have from a dynamic object. Symbols from regular + files always take precedence over symbols from dynamic + objects, even if they are defined after the dynamic + object in the link. */ + if (! dynamic + && definition + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour) + && (elf_elfheader (h->root.u.def.section->owner)->e_type + == ET_DYN)) + { + /* Change the hash table entry to undefined, and let + _bfd_generic_link_add_one_symbol do the right thing + with the new definition. */ + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + size_change_ok = true; + } + } + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, flags, sec, value, (const char *) NULL, + false, collect, (struct bfd_link_hash_entry **) sym_hash))) + goto error_return; + + h = *sym_hash; + 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; + + new_weakdef = false; + if (dynamic + && definition + && (flags & BSF_WEAK) != 0 + && ELF_ST_TYPE (sym.st_info) != STT_FUNC + && info->hash->creator->flavour == bfd_target_elf_flavour + && h->weakdef == NULL) + { + /* Keep a list of all weak defined non function symbols from + a dynamic object, using the weakdef field. Later in this + function we will set the weakdef field to the correct + value. We only put non-function symbols from dynamic + objects on this list, because that happens to be the only + time we need to know the normal symbol corresponding to a + weak symbol, and the information is time consuming to + figure out. If the weakdef field is not already NULL, + then this symbol was already defined by some previous + dynamic object, and we will be using that previous + definition anyhow. */ + + h->weakdef = weaks; + weaks = h; + new_weakdef = true; + } + + /* Get the alignment of a common symbol. */ + if (sym.st_shndx == SHN_COMMON + && h->root.type == bfd_link_hash_common) + h->root.u.c.p->alignment_power = bfd_log2 (sym.st_value); + + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + int old_flags; + boolean dynsym; + int new_flag; + + /* Remember the symbol size and type. */ + if (sym.st_size != 0 + && (definition || h->size == 0)) + { + if (h->size != 0 && h->size != sym.st_size && ! size_change_ok) + (*_bfd_error_handler) + ("Warning: size of symbol `%s' changed from %lu to %lu in %s", + name, (unsigned long) h->size, (unsigned long) sym.st_size, + bfd_get_filename (abfd)); + + h->size = sym.st_size; + } + if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE + && (definition || h->type == STT_NOTYPE)) + { + if (h->type != STT_NOTYPE + && h->type != ELF_ST_TYPE (sym.st_info) + && ! type_change_ok) + (*_bfd_error_handler) + ("Warning: type of symbol `%s' changed from %d to %d in %s", + name, h->type, ELF_ST_TYPE (sym.st_info), + bfd_get_filename (abfd)); + + h->type = ELF_ST_TYPE (sym.st_info); + } + + /* Set a flag in the hash table entry indicating the type of + reference or definition we just found. Keep a count of + the number of dynamic symbols we find. A dynamic symbol + is one which is referenced or defined by both a regular + object and a shared object, or one which is referenced or + defined by more than one shared object. */ + old_flags = h->elf_link_hash_flags; + dynsym = false; + if (! dynamic) + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_REGULAR; + else + new_flag = ELF_LINK_HASH_DEF_REGULAR; + if (info->shared + || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0) + dynsym = true; + } + else + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_DYNAMIC; + else + new_flag = ELF_LINK_HASH_DEF_DYNAMIC; + if ((old_flags & new_flag) != 0 + || (old_flags & (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_REF_REGULAR)) != 0 + || (h->weakdef != NULL + && (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0)) + dynsym = true; + } + + h->elf_link_hash_flags |= new_flag; + if (dynsym && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + goto error_return; + if (h->weakdef != NULL + && ! new_weakdef + && h->weakdef->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, + h->weakdef)) + goto error_return; + } + } + } + } + + /* Now set the weakdefs field correctly for all the weak defined + symbols we found. The only way to do this is to search all the + symbols. Since we only need the information for non functions in + dynamic objects, that's the only time we actually put anything on + the list WEAKS. We need this information so that if a regular + object refers to a symbol defined weakly in a dynamic object, the + real symbol in the dynamic object is also put in the dynamic + symbols; we also must arrange for both symbols to point to the + same memory location. We could handle the general case of symbol + aliasing, but a general symbol alias can only be generated in + assembler code, handling it correctly would be very time + consuming, and other ELF linkers don't handle general aliasing + either. */ + while (weaks != NULL) + { + struct elf_link_hash_entry *hlook; + asection *slook; + bfd_vma vlook; + struct elf_link_hash_entry **hpp; + struct elf_link_hash_entry **hppend; + + hlook = weaks; + weaks = hlook->weakdef; + hlook->weakdef = NULL; + + BFD_ASSERT (hlook->root.type == bfd_link_hash_defined + || hlook->root.type == bfd_link_hash_defweak + || hlook->root.type == bfd_link_hash_common + || hlook->root.type == bfd_link_hash_indirect); + slook = hlook->root.u.def.section; + vlook = hlook->root.u.def.value; + + hpp = elf_sym_hashes (abfd); + hppend = hpp + extsymcount; + for (; hpp < hppend; hpp++) + { + struct elf_link_hash_entry *h; + + h = *hpp; + if (h != NULL && h != hlook + && h->root.type == bfd_link_hash_defined + && h->root.u.def.section == slook + && h->root.u.def.value == vlook) + { + hlook->weakdef = h; + + /* If the weak definition is in the list of dynamic + symbols, make sure the real definition is put there + as well. */ + if (hlook->dynindx != -1 + && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + goto error_return; + } + + break; + } + } + } + + if (buf != NULL) + { + free (buf); + buf = NULL; + } + + /* If this object is the same format as the output object, and it is + not a shared library, then let the backend look through the + relocs. + + This is required to build global offset table entries and to + arrange for dynamic relocs. It is not required for the + particular common case of linking non PIC code, even when linking + against shared libraries, but unfortunately there is no way of + knowing whether an object file has been compiled PIC or not. + Looking through the relocs is not particularly time consuming. + The problem is that we must either (1) keep the relocs in memory, + which causes the linker to require additional runtime memory or + (2) read the relocs twice from the input file, which wastes time. + This would be a good case for using mmap. + + I have no idea how to handle linking PIC code into a file of a + different format. It probably can't be done. */ + check_relocs = get_elf_backend_data (abfd)->check_relocs; + if (! dynamic + && abfd->xvec == info->hash->creator + && check_relocs != NULL) + { + asection *o; + + for (o = abfd->sections; o != NULL; o = o->next) + { + Elf_Internal_Rela *internal_relocs; + boolean ok; + + if ((o->flags & SEC_RELOC) == 0 + || o->reloc_count == 0) + continue; + + /* I believe we can ignore the relocs for any section which + does not form part of the final process image, such as a + debugging section. */ + if ((o->flags & SEC_ALLOC) == 0) + continue; + + internal_relocs = elf_link_read_relocs (abfd, o, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + info->keep_memory); + if (internal_relocs == NULL) + goto error_return; + + ok = (*check_relocs) (abfd, info, o, internal_relocs); + + if (! info->keep_memory) + free (internal_relocs); + + if (! ok) + goto error_return; + } + } + + return true; + + error_return: + if (buf != NULL) + free (buf); + if (dynbuf != NULL) + free (dynbuf); + return false; +} + +/* Create some sections which will be filled in with dynamic linking + information. ABFD is an input file which requires dynamic sections + to be created. The dynamic sections take up virtual memory space + when the final executable is run, so we need to create them before + addresses are assigned to the output sections. We work out the + actual contents and size of these sections later. */ + +boolean +elf_link_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct elf_backend_data *bed; + + if (elf_hash_table (info)->dynamic_sections_created) + return true; + + /* Make sure that all dynamic sections use the same input BFD. */ + if (elf_hash_table (info)->dynobj == NULL) + elf_hash_table (info)->dynobj = abfd; + else + abfd = elf_hash_table (info)->dynobj; + + /* Note that we set the SEC_IN_MEMORY flag for all of these + sections. */ + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + /* A dynamically linked executable has a .interp section, but a + shared library does not. */ + if (! info->shared) + { + s = bfd_make_section (abfd, ".interp"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return false; + } + + s = bfd_make_section (abfd, ".dynsym"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + s = bfd_make_section (abfd, ".dynstr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return false; + + /* Create a strtab to hold the dynamic symbol names. */ + if (elf_hash_table (info)->dynstr == NULL) + { + elf_hash_table (info)->dynstr = elf_stringtab_init (); + if (elf_hash_table (info)->dynstr == NULL) + return false; + } + + s = bfd_make_section (abfd, ".dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* The special symbol _DYNAMIC is always set to the start of the + .dynamic section. This call occurs before we have processed the + symbols for any dynamic object, so we don't have to worry about + overriding a dynamic definition. We could set _DYNAMIC in a + linker script, but we only want to define it if we are, in fact, + creating a .dynamic 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. */ + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) NULL, false, get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + s = bfd_make_section (abfd, ".hash"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* Let the backend create the rest of the sections. This lets the + backend set the right flags. The backend will normally create + the .got and .plt sections. */ + bed = get_elf_backend_data (abfd); + if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info)) + return false; + + elf_hash_table (info)->dynamic_sections_created = true; + + return true; +} + +/* Add an entry to the .dynamic table. */ + +boolean +elf_add_dynamic_entry (info, tag, val) + struct bfd_link_info *info; + bfd_vma tag; + bfd_vma val; +{ + Elf_Internal_Dyn dyn; + bfd *dynobj; + asection *s; + size_t newsize; + bfd_byte *newcontents; + + dynobj = elf_hash_table (info)->dynobj; + + s = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (s != NULL); + + newsize = s->_raw_size + sizeof (Elf_External_Dyn); + newcontents = (bfd_byte *) bfd_realloc (s->contents, newsize); + if (newcontents == NULL) + return false; + + dyn.d_tag = tag; + dyn.d_un.d_val = val; + elf_swap_dyn_out (dynobj, &dyn, + (Elf_External_Dyn *) (newcontents + s->_raw_size)); + + s->_raw_size = newsize; + s->contents = newcontents; + + return true; +} + + +/* Read and swap the relocs for a section. They may have been cached. + If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL, + they are used as buffers to read into. They are known to be large + enough. If the INTERNAL_RELOCS relocs argument is NULL, the return + value is allocated using either malloc or bfd_alloc, according to + the KEEP_MEMORY argument. */ + +static Elf_Internal_Rela * +elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory) + bfd *abfd; + asection *o; + PTR external_relocs; + Elf_Internal_Rela *internal_relocs; + boolean keep_memory; +{ + Elf_Internal_Shdr *rel_hdr; + PTR alloc1 = NULL; + Elf_Internal_Rela *alloc2 = NULL; + + if (elf_section_data (o)->relocs != NULL) + return elf_section_data (o)->relocs; + + if (o->reloc_count == 0) + return NULL; + + rel_hdr = &elf_section_data (o)->rel_hdr; + + if (internal_relocs == NULL) + { + size_t size; + + size = o->reloc_count * sizeof (Elf_Internal_Rela); + if (keep_memory) + internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size); + else + internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size); + if (internal_relocs == NULL) + goto error_return; + } + + if (external_relocs == NULL) + { + alloc1 = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size); + if (alloc1 == NULL) + goto error_return; + external_relocs = alloc1; + } + + if ((bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0) + || (bfd_read (external_relocs, 1, rel_hdr->sh_size, abfd) + != rel_hdr->sh_size)) + goto error_return; + + /* Swap in the relocs. For convenience, we always produce an + Elf_Internal_Rela array; if the relocs are Rel, we set the addend + to 0. */ + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_External_Rel *erelend; + Elf_Internal_Rela *irela; + + erel = (Elf_External_Rel *) external_relocs; + erelend = erel + o->reloc_count; + irela = internal_relocs; + for (; erel < erelend; erel++, irela++) + { + Elf_Internal_Rel irel; + + elf_swap_reloc_in (abfd, erel, &irel); + irela->r_offset = irel.r_offset; + irela->r_info = irel.r_info; + irela->r_addend = 0; + } + } + else + { + Elf_External_Rela *erela; + Elf_External_Rela *erelaend; + Elf_Internal_Rela *irela; + + BFD_ASSERT (rel_hdr->sh_entsize == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) external_relocs; + erelaend = erela + o->reloc_count; + irela = internal_relocs; + for (; erela < erelaend; erela++, irela++) + elf_swap_reloca_in (abfd, erela, irela); + } + + /* Cache the results for next time, if we can. */ + if (keep_memory) + elf_section_data (o)->relocs = internal_relocs; + + if (alloc1 != NULL) + free (alloc1); + + /* Don't free alloc2, since if it was allocated we are passing it + back (under the name of internal_relocs). */ + + return internal_relocs; + + error_return: + if (alloc1 != NULL) + free (alloc1); + if (alloc2 != NULL) + free (alloc2); + return NULL; +} + + +/* Record an assignment to a symbol made by a linker script. We need + this in case some dynamic object refers to this symbol. */ + +/*ARGSUSED*/ +boolean +NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; + boolean provide; +{ + struct elf_link_hash_entry *h; + + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return true; + + h = elf_link_hash_lookup (elf_hash_table (info), name, true, true, false); + if (h == NULL) + return false; + + if (h->root.type == bfd_link_hash_new) + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + + /* If this symbol is being provided by the linker script, and it is + currently defined by a dynamic object, but not by a regular + object, then mark it as undefined so that the generic linker will + force the correct value. */ + if (provide + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + h->root.type = bfd_link_hash_undefined; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + || info->shared) + && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + + /* If this is a weak defined symbol, and we know a corresponding + real symbol from the same dynamic object, make sure the real + symbol is also made into a dynamic symbol. */ + if (h->weakdef != NULL + && h->weakdef->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef)) + return false; + } + } + + return true; +} + + +/* Array used to determine the number of hash table buckets to use + based on the number of symbols there are. If there are fewer than + 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, + fewer than 37 we use 17 buckets, and so forth. We never use more + than 521 buckets. */ + +static const size_t elf_buckets[] = +{ + 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 0 +}; + +/* 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 + addresses of the various sections. */ + +boolean +NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, + export_dynamic, info, sinterpptr) + bfd *output_bfd; + const char *soname; + const char *rpath; + boolean export_dynamic; + struct bfd_link_info *info; + asection **sinterpptr; +{ + bfd *dynobj; + struct elf_backend_data *bed; + + *sinterpptr = NULL; + + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return true; + + 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 we are supposed to export all symbols into the dynamic symbol + table (this is not the normal case), then do so. */ + if (export_dynamic) + { + struct elf_info_failed eif; + + eif.failed = false; + eif.info = info; + elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol, + (PTR) &eif); + if (eif.failed) + return false; + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + struct elf_info_failed eif; + struct elf_link_hash_entry *h; + bfd_size_type strsize; + + *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (*sinterpptr != NULL || info->shared); + + if (soname != NULL) + { + bfd_size_type indx; + + indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, soname, + true, true); + if (indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, DT_SONAME, indx)) + return false; + } + + if (info->symbolic) + { + if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0)) + return false; + } + + if (rpath != NULL) + { + bfd_size_type indx; + + indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath, + true, true); + if (indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, DT_RPATH, indx)) + return false; + } + + /* Find all symbols which were defined in a dynamic object and make + the backend pick a reasonable value for them. */ + eif.failed = false; + eif.info = info; + elf_link_hash_traverse (elf_hash_table (info), + elf_adjust_dynamic_symbol, + (PTR) &eif); + if (eif.failed) + return false; + + /* Add some entries to the .dynamic section. We fill in some of the + values later, in elf_bfd_final_link, but we must add the entries + now so that we know the final size of the .dynamic section. */ + h = elf_link_hash_lookup (elf_hash_table (info), "_init", false, + false, false); + if (h != NULL + && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR)) != 0) + { + if (! elf_add_dynamic_entry (info, DT_INIT, 0)) + return false; + } + h = elf_link_hash_lookup (elf_hash_table (info), "_fini", false, + false, false); + if (h != NULL + && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR)) != 0) + { + if (! elf_add_dynamic_entry (info, DT_FINI, 0)) + return false; + } + strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr); + if (! elf_add_dynamic_entry (info, DT_HASH, 0) + || ! elf_add_dynamic_entry (info, DT_STRTAB, 0) + || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0) + || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize) + || ! elf_add_dynamic_entry (info, DT_SYMENT, + sizeof (Elf_External_Sym))) + return false; + } + + /* The backend must work out the sizes of all the other dynamic + sections. */ + bed = get_elf_backend_data (output_bfd); + if (! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) + return false; + + if (elf_hash_table (info)->dynamic_sections_created) + { + size_t dynsymcount; + asection *s; + size_t i; + size_t bucketcount = 0; + Elf_Internal_Sym isym; + + /* Set the size of the .dynsym and .hash sections. We counted + the number of dynamic symbols in elf_link_add_object_symbols. + We will build the contents of .dynsym and .hash when we build + 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. */ + dynsymcount = elf_hash_table (info)->dynsymcount; + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (Elf_External_Sym); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + + /* The first entry in .dynsym is a dummy symbol. */ + isym.st_value = 0; + isym.st_size = 0; + isym.st_name = 0; + isym.st_info = 0; + isym.st_other = 0; + isym.st_shndx = 0; + elf_swap_symbol_out (output_bfd, &isym, + (PTR) (Elf_External_Sym *) s->contents); + + for (i = 0; elf_buckets[i] != 0; i++) + { + bucketcount = elf_buckets[i]; + if (dynsymcount < elf_buckets[i + 1]) + break; + } + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + return false; + memset (s->contents, 0, (size_t) s->_raw_size); + + put_word (output_bfd, bucketcount, s->contents); + put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8)); + + elf_hash_table (info)->bucketcount = bucketcount; + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr); + + if (! elf_add_dynamic_entry (info, DT_NULL, 0)) + return false; + } + + return true; +} + + +/* This routine is used to export all defined symbols into the dynamic + symbol table. It is called via elf_link_hash_traverse. */ + +static boolean +elf_export_symbol (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_info_failed *eif = (struct elf_info_failed *) data; + + if (h->dynindx == -1 + && (h->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0) + { + if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h)) + { + eif->failed = true; + return false; + } + } + + return true; +} + + +/* Make the backend pick a good value for a dynamic symbol. This is + called via elf_link_hash_traverse, and also calls itself + recursively. */ + +static boolean +elf_adjust_dynamic_symbol (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_info_failed *eif = (struct elf_info_failed *) data; + bfd *dynobj; + struct elf_backend_data *bed; + + /* If this symbol was mentioned in a non-ELF file, try to set + DEF_REGULAR and REF_REGULAR correctly. This is the only way to + permit a non-ELF file to correctly refer to a symbol defined in + an ELF dynamic object. */ + if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0) + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + else + { + if (h->root.u.def.section->owner != NULL + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour)) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + else + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + { + if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h)) + { + eif->failed = true; + return false; + } + } + } + + /* If -Bsymbolic was used (which means to bind references to global + symbols to the definition within the shared object), and this + symbol was defined in a regular object, then it actually doesn't + need a PLT entry. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0 + && eif->info->shared + && eif->info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT; + + /* If this symbol does not require a PLT entry, and it is not + defined by a dynamic object, or is not referenced by a regular + object, ignore it. We do have to handle a weak defined symbol, + even if no regular object refers to it, if we decided to add it + to the dynamic symbol table. FIXME: Do we normally need to worry + about symbols which are defined by one dynamic object and + referenced by another one? */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0 + && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + || ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 + && (h->weakdef == NULL || h->weakdef->dynindx == -1)))) + return true; + + /* If we've already adjusted this symbol, don't do it again. This + can happen via a recursive call. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + return true; + + /* Don't look at this symbol again. Note that we must set this + after checking the above conditions, because we may look at a + symbol once, decide not to do anything, and then get called + recursively later after REF_REGULAR is set below. */ + h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + + /* If this is a weak definition, and we know a real definition, and + the real symbol is not itself defined by a regular object file, + then get a good value for the real definition. We handle the + real symbol first, for the convenience of the backend routine. + + Note that there is a confusing case here. If the real definition + is defined by a regular object file, we don't get the real symbol + from the dynamic object, but we do get the weak symbol. If the + processor backend uses a COPY reloc, then if some routine in the + dynamic object changes the real symbol, we will not see that + change in the corresponding weak symbol. This is the way other + ELF linkers work as well, and seems to be a result of the shared + library model. + + I will clarify this issue. Most SVR4 shared libraries define the + variable _timezone and define timezone as a weak synonym. The + tzset call changes _timezone. If you write + extern int timezone; + int _timezone = 5; + int main () { tzset (); printf ("%d %d\n", timezone, _timezone); } + you might expect that, since timezone is a synonym for _timezone, + the same number will print both times. However, if the processor + backend uses a COPY reloc, then actually timezone will be copied + into your process image, and, since you define _timezone + yourself, _timezone will not. Thus timezone and _timezone will + wind up at different memory locations. The tzset call will set + _timezone, leaving timezone unchanged. */ + + if (h->weakdef != NULL) + { + struct elf_link_hash_entry *weakdef; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + weakdef = h->weakdef; + BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined + || weakdef->root.type == bfd_link_hash_defweak); + BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); + if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + { + /* This symbol is defined by a regular object file, so we + will not do anything special. Clear weakdef for the + convenience of the processor backend. */ + h->weakdef = NULL; + } + else + { + /* There is an implicit reference by a regular object file + via the weak symbol. */ + weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif)) + return false; + } + } + + dynobj = elf_hash_table (eif->info)->dynobj; + bed = get_elf_backend_data (dynobj); + if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h)) + { + eif->failed = true; + return false; + } + + return true; +} + +/* Final phase of ELF linker. */ + +/* A structure we use to avoid passing large numbers of arguments. */ + +struct elf_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Symbol string table. */ + struct bfd_strtab_hash *symstrtab; + /* .dynsym section. */ + asection *dynsym_sec; + /* .hash section. */ + asection *hash_sec; + /* Buffer large enough to hold contents of any section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any section. */ + PTR external_relocs; + /* Buffer large enough to hold internal relocs of any section. */ + Elf_Internal_Rela *internal_relocs; + /* Buffer large enough to hold external local symbols of any input + BFD. */ + Elf_External_Sym *external_syms; + /* Buffer large enough to hold internal local symbols of any input + BFD. */ + Elf_Internal_Sym *internal_syms; + /* Array large enough to hold a symbol index for each local symbol + of any input BFD. */ + long *indices; + /* Array large enough to hold a section pointer for each local + symbol of any input BFD. */ + asection **sections; + /* Buffer to hold swapped out symbols. */ + Elf_External_Sym *symbuf; + /* Number of swapped out symbols in buffer. */ + size_t symbuf_count; + /* Number of symbols which fit in symbuf. */ + size_t symbuf_size; +}; + +static boolean elf_link_output_sym + PARAMS ((struct elf_final_link_info *, const char *, + Elf_Internal_Sym *, asection *)); +static boolean elf_link_flush_output_syms + PARAMS ((struct elf_final_link_info *)); +static boolean elf_link_output_extsym + PARAMS ((struct elf_link_hash_entry *, PTR)); +static boolean elf_link_input_bfd + PARAMS ((struct elf_final_link_info *, bfd *)); +static boolean elf_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* This struct is used to pass information to routines called via + elf_link_hash_traverse which must return failure. */ + +struct elf_finfo_failed +{ + boolean failed; + struct elf_final_link_info *finfo; +}; + +/* Do the final step of an ELF link. */ + +boolean +elf_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean dynamic; + bfd *dynobj; + struct elf_final_link_info finfo; + register asection *o; + register struct bfd_link_order *p; + register bfd *sub; + size_t max_contents_size; + size_t max_external_reloc_size; + size_t max_internal_reloc_count; + size_t max_sym_count; + file_ptr off; + Elf_Internal_Sym elfsym; + unsigned int i; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symstrtab_hdr; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_finfo_failed eif; + + if (info->shared) + abfd->flags |= DYNAMIC; + + dynamic = elf_hash_table (info)->dynamic_sections_created; + dynobj = elf_hash_table (info)->dynobj; + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.symstrtab = elf_stringtab_init (); + if (finfo.symstrtab == NULL) + return false; + if (! dynamic) + { + finfo.dynsym_sec = NULL; + finfo.hash_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.hash_sec != NULL); + } + finfo.contents = NULL; + finfo.external_relocs = NULL; + finfo.internal_relocs = NULL; + finfo.external_syms = NULL; + finfo.internal_syms = NULL; + finfo.indices = NULL; + finfo.sections = NULL; + finfo.symbuf = NULL; + finfo.symbuf_count = 0; + + /* Count up the number of relocations we will output for each output + section, so that we know the sizes of the reloc sections. We + also figure out some maximum sizes. */ + max_contents_size = 0; + max_external_reloc_size = 0; + max_internal_reloc_count = 0; + max_sym_count = 0; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + o->reloc_count = 0; + + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + + if (info->relocateable) + o->reloc_count += sec->reloc_count; + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->_cooked_size > max_contents_size) + max_contents_size = sec->_cooked_size; + + /* We are interested in just local symbols, not all + symbols. */ + if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour) + { + size_t sym_count; + + if (elf_bad_symtab (sec->owner)) + sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size + / sizeof (Elf_External_Sym)); + else + sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; + + if (sym_count > max_sym_count) + max_sym_count = sym_count; + + if ((sec->flags & SEC_RELOC) != 0) + { + size_t ext_size; + + ext_size = elf_section_data (sec)->rel_hdr.sh_size; + if (ext_size > max_external_reloc_size) + max_external_reloc_size = ext_size; + if (sec->reloc_count > max_internal_reloc_count) + max_internal_reloc_count = sec->reloc_count; + } + } + } + } + + if (o->reloc_count > 0) + o->flags |= SEC_RELOC; + else + { + /* Explicitly clear the SEC_RELOC flag. The linker tends to + set it (this is probably a bug) and if it is set + assign_section_numbers will create a reloc section. */ + o->flags &=~ SEC_RELOC; + } + + /* If the SEC_ALLOC flag is not set, force the section VMA to + zero. This is done in elf_fake_sections as well, but forcing + the VMA to 0 here will ensure that relocs against these + sections are handled correctly. */ + if ((o->flags & SEC_ALLOC) == 0) + o->vma = 0; + } + + /* Figure out the file positions for everything but the symbol table + and the relocs. We set symcount to force assign_section_numbers + to create a symbol table. */ + abfd->symcount = info->strip == strip_all ? 0 : 1; + BFD_ASSERT (! abfd->output_has_begun); + if (! _bfd_elf_compute_section_file_positions (abfd, info)) + goto error_return; + + /* That created the reloc sections. Set their sizes, and assign + them file positions, and allocate some buffers. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Shdr *rel_hdr; + register struct elf_link_hash_entry **p, **pend; + + rel_hdr = &elf_section_data (o)->rel_hdr; + + rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count; + + /* The contents field must last into write_object_contents, + so we allocate it with bfd_alloc rather than malloc. */ + rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size); + if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) + goto error_return; + + p = ((struct elf_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct elf_link_hash_entry *))); + if (p == NULL && o->reloc_count != 0) + goto error_return; + elf_section_data (o)->rel_hashes = p; + pend = p + o->reloc_count; + for (; p < pend; p++) + *p = NULL; + + /* Use the reloc_count field as an index when outputting the + relocs. */ + o->reloc_count = 0; + } + } + + _bfd_elf_assign_file_positions_for_relocs (abfd); + + /* We have now assigned file positions for all the sections except + .symtab and .strtab. We start the .symtab section at the current + file position, and write directly to it. We build the .strtab + section in memory. */ + abfd->symcount = 0; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + /* sh_name is set in prep_headers. */ + symtab_hdr->sh_type = SHT_SYMTAB; + symtab_hdr->sh_flags = 0; + symtab_hdr->sh_addr = 0; + symtab_hdr->sh_size = 0; + symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); + /* sh_link is set in assign_section_numbers. */ + /* sh_info is set below. */ + /* sh_offset is set just below. */ + symtab_hdr->sh_addralign = 4; /* FIXME: system dependent? */ + + off = elf_tdata (abfd)->next_file_pos; + off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true); + + /* Note that at this point elf_tdata (abfd)->next_file_pos 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; + else + finfo.symbuf_size = max_sym_count; + finfo.symbuf = ((Elf_External_Sym *) + bfd_malloc (finfo.symbuf_size * sizeof (Elf_External_Sym))); + if (finfo.symbuf == NULL) + goto error_return; + + /* Start writing out the symbol table. The first symbol is always a + dummy symbol. */ + if (info->strip != strip_all || info->relocateable) + { + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = 0; + elfsym.st_other = 0; + elfsym.st_shndx = SHN_UNDEF; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, bfd_und_section_ptr)) + goto error_return; + } + +#if 0 + /* Some standard ELF linkers do this, but we don't because it causes + bootstrap comparison failures. */ + /* Output a file symbol for the output file as the second symbol. + We output this even if we are discarding local symbols, although + I'm not sure if this is correct. */ + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + elfsym.st_other = 0; + elfsym.st_shndx = SHN_ABS; + if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd), + &elfsym, bfd_abs_section_ptr)) + goto error_return; +#endif + + /* Output a symbol for each section. We output these even if we are + discarding local symbols, since they are used for relocs. These + symbols have no names. We store the index of each one in the + index field of the section, so that we can find it again when + outputting relocs. */ + if (info->strip != strip_all || info->relocateable) + { + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + elfsym.st_other = 0; + for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++) + { + o = section_from_elf_index (abfd, i); + if (o != NULL) + o->target_index = abfd->symcount; + elfsym.st_shndx = i; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, o)) + goto error_return; + } + } + + /* Allocate some memory to hold information read in from the input + files. */ + finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size); + finfo.internal_relocs = ((Elf_Internal_Rela *) + bfd_malloc (max_internal_reloc_count + * sizeof (Elf_Internal_Rela))); + finfo.external_syms = ((Elf_External_Sym *) + bfd_malloc (max_sym_count + * sizeof (Elf_External_Sym))); + finfo.internal_syms = ((Elf_Internal_Sym *) + bfd_malloc (max_sym_count + * sizeof (Elf_Internal_Sym))); + finfo.indices = (long *) bfd_malloc (max_sym_count * sizeof (long)); + finfo.sections = ((asection **) + bfd_malloc (max_sym_count * sizeof (asection *))); + if ((finfo.contents == NULL && max_contents_size != 0) + || (finfo.external_relocs == NULL && max_external_reloc_size != 0) + || (finfo.internal_relocs == NULL && max_internal_reloc_count != 0) + || (finfo.external_syms == NULL && max_sym_count != 0) + || (finfo.internal_syms == NULL && max_sym_count != 0) + || (finfo.indices == NULL && max_sym_count != 0) + || (finfo.sections == NULL && max_sym_count != 0)) + goto error_return; + + /* Since ELF permits relocations to be against local symbols, we + must have the local symbols available when we do the relocations. + Since we would rather only read the local symbols once, and we + would rather not keep them in memory, we handle all the + relocations for a single input file at the same time. + + Unfortunately, there is no way to know the total number of local + symbols until we have seen all of them, and the local symbol + indices precede the global symbol indices. This means that when + we are generating relocateable output, and we see a reloc against + a global symbol, we can not know the symbol index until we have + finished examining all the local symbols to see which ones we are + going to output. To deal with this, we keep the relocations in + memory, and don't output them until the end of the link. This is + an unfortunate waste of memory, but I don't see a good way around + it. Fortunately, it only happens when performing a relocateable + link, which is not the common case. FIXME: If keep_memory is set + we could write the relocs out and then read them again; I don't + know how bad the memory loss will be. */ + + for (sub = info->input_bfds; sub != NULL; sub = sub->next) + sub->output_has_begun = false; + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_elf_flavour)) + { + sub = p->u.indirect.section->owner; + if (! sub->output_has_begun) + { + if (! elf_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! elf_reloc_link_order (abfd, info, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* That wrote out all the local symbols. Finish up the symbol table + with the global symbols. */ + + /* The sh_info field records the index of the first non local + symbol. */ + symtab_hdr->sh_info = abfd->symcount; + if (dynamic) + elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1; + + /* We get the global symbols from the hash table. */ + eif.failed = false; + eif.finfo = &finfo; + elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, + (PTR) &eif); + if (eif.failed) + return false; + + /* Flush all symbols to the file. */ + if (! elf_link_flush_output_syms (&finfo)) + return false; + + /* Now we know the size of the symtab section. */ + off += symtab_hdr->sh_size; + + /* Finish up and write out the symbol string table (.strtab) + section. */ + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + /* sh_name was set in prep_headers. */ + 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_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + /* sh_offset is set just below. */ + symstrtab_hdr->sh_addralign = 1; + + off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, true); + elf_tdata (abfd)->next_file_pos = off; + + if (abfd->symcount > 0) + { + if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 + || ! _bfd_stringtab_emit (abfd, finfo.symstrtab)) + return false; + } + + /* Adjust the relocs to have the correct symbol indices. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *rel_hdr; + + if ((o->flags & SEC_RELOC) == 0) + continue; + + rel_hash = elf_section_data (o)->rel_hashes; + rel_hdr = &elf_section_data (o)->rel_hdr; + for (i = 0; i < o->reloc_count; i++, rel_hash++) + { + if (*rel_hash == NULL) + continue; + + BFD_ASSERT ((*rel_hash)->indx >= 0); + + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_Internal_Rel irel; + + erel = (Elf_External_Rel *) rel_hdr->contents + i; + elf_swap_reloc_in (abfd, erel, &irel); + irel.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irel.r_info)); + elf_swap_reloc_out (abfd, &irel, erel); + } + else + { + Elf_External_Rela *erela; + Elf_Internal_Rela irela; + + BFD_ASSERT (rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) rel_hdr->contents + i; + elf_swap_reloca_in (abfd, erela, &irela); + irela.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irela.r_info)); + elf_swap_reloca_out (abfd, &irela, erela); + } + } + + /* Set the reloc_count field to 0 to prevent write_relocs from + trying to swap the relocs out itself. */ + o->reloc_count = 0; + } + + /* If we are linking against a dynamic object, or generating a + shared library, finish up the dynamic linking information. */ + if (dynamic) + { + Elf_External_Dyn *dyncon, *dynconend; + + /* Fix up .dynamic entries. */ + o = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (o != NULL); + + dyncon = (Elf_External_Dyn *) o->contents; + dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + unsigned int type; + + elf_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + /* SVR4 linkers seem to set DT_INIT and DT_FINI based on + magic _init and _fini symbols. This is pretty ugly, + but we are compatible. */ + case DT_INIT: + name = "_init"; + goto get_sym; + case DT_FINI: + name = "_fini"; + get_sym: + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (elf_hash_table (info), name, + false, false, true); + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + dyn.d_un.d_val = h->root.u.def.value; + o = h->root.u.def.section; + if (o->output_section != NULL) + dyn.d_un.d_val += (o->output_section->vma + + o->output_offset); + else + { + /* The symbol is imported from another shared + library and does not apply to this one. */ + dyn.d_un.d_val = 0; + } + + elf_swap_dyn_out (dynobj, &dyn, dyncon); + } + } + break; + + case DT_HASH: + name = ".hash"; + goto get_vma; + case DT_STRTAB: + name = ".dynstr"; + goto get_vma; + case DT_SYMTAB: + name = ".dynsym"; + get_vma: + o = bfd_get_section_by_name (abfd, name); + BFD_ASSERT (o != NULL); + dyn.d_un.d_ptr = o->vma; + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + + case DT_REL: + case DT_RELA: + case DT_RELSZ: + case DT_RELASZ: + if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) + type = SHT_REL; + else + type = SHT_RELA; + dyn.d_un.d_val = 0; + for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++) + { + Elf_Internal_Shdr *hdr; + + hdr = elf_elfsections (abfd)[i]; + if (hdr->sh_type == type + && (hdr->sh_flags & SHF_ALLOC) != 0) + { + if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) + dyn.d_un.d_val += hdr->sh_size; + else + { + if (dyn.d_un.d_val == 0 + || hdr->sh_addr < dyn.d_un.d_val) + dyn.d_un.d_val = hdr->sh_addr; + } + } + } + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + } + } + } + + /* If we have created any dynamic sections, then output them. */ + if (dynobj != NULL) + { + if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) + goto error_return; + + for (o = dynobj->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || o->_raw_size == 0) + continue; + if ((o->flags & SEC_IN_MEMORY) == 0) + { + /* At this point, we are only interested in sections + created by elf_link_create_dynamic_sections. FIXME: + This test is fragile. */ + continue; + } + if ((elf_section_data (o->output_section)->this_hdr.sh_type + != SHT_STRTAB) + || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0) + { + if (! bfd_set_section_contents (abfd, o->output_section, + o->contents, o->output_offset, + o->_raw_size)) + goto error_return; + } + else + { + file_ptr off; + + /* The contents of the .dynstr section are actually in a + stringtab. */ + off = elf_section_data (o->output_section)->this_hdr.sh_offset; + if (bfd_seek (abfd, off, SEEK_SET) != 0 + || ! _bfd_stringtab_emit (abfd, + elf_hash_table (info)->dynstr)) + 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.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); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + elf_tdata (abfd)->linker = true; + + 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.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); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + return false; +} + +/* Add a symbol to the output symbol table. */ + +static boolean +elf_link_output_sym (finfo, name, elfsym, input_sec) + struct elf_final_link_info *finfo; + const char *name; + Elf_Internal_Sym *elfsym; + asection *input_sec; +{ + boolean (*output_symbol_hook) PARAMS ((bfd *, + struct bfd_link_info *info, + const char *, + Elf_Internal_Sym *, + asection *)); + + output_symbol_hook = get_elf_backend_data (finfo->output_bfd)-> + elf_backend_link_output_symbol_hook; + if (output_symbol_hook != NULL) + { + if (! ((*output_symbol_hook) + (finfo->output_bfd, finfo->info, name, elfsym, input_sec))) + return false; + } + + if (name == (const char *) NULL || *name == '\0') + elfsym->st_name = 0; + else + { + elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab, + name, true, + false); + if (elfsym->st_name == (unsigned long) -1) + return false; + } + + if (finfo->symbuf_count >= finfo->symbuf_size) + { + if (! elf_link_flush_output_syms (finfo)) + return false; + } + + elf_swap_symbol_out (finfo->output_bfd, elfsym, + (PTR) (finfo->symbuf + finfo->symbuf_count)); + ++finfo->symbuf_count; + + ++finfo->output_bfd->symcount; + + return true; +} + +/* Flush the output symbols to the file. */ + +static boolean +elf_link_flush_output_syms (finfo) + struct elf_final_link_info *finfo; +{ + if (finfo->symbuf_count > 0) + { + Elf_Internal_Shdr *symtab; + + symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr; + + if (bfd_seek (finfo->output_bfd, symtab->sh_offset + symtab->sh_size, + SEEK_SET) != 0 + || (bfd_write ((PTR) finfo->symbuf, finfo->symbuf_count, + sizeof (Elf_External_Sym), finfo->output_bfd) + != finfo->symbuf_count * sizeof (Elf_External_Sym))) + return false; + + symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym); + + finfo->symbuf_count = 0; + } + + return true; +} + +/* Add an external symbol to the symbol table. This is called from + the hash table traversal routine. */ + +static boolean +elf_link_output_extsym (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_finfo_failed *eif = (struct elf_finfo_failed *) data; + struct elf_final_link_info *finfo = eif->finfo; + boolean strip; + Elf_Internal_Sym sym; + asection *input_sec; + + /* If we are not creating a shared library, and this symbol is + referenced by a shared library but is not defined anywhere, then + warn that it is undefined. If we do not do this, the runtime + linker will complain that the symbol is undefined when the + program is run. We don't have to worry about symbols that are + referenced by regular files, because we will already have issued + warnings for them. */ + if (! finfo->info->relocateable + && ! finfo->info->shared + && h->root.type == bfd_link_hash_undefined + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + { + if (! ((*finfo->info->callbacks->undefined_symbol) + (finfo->info, h->root.root.string, h->root.u.undef.abfd, + (asection *) NULL, 0))) + { + eif->failed = true; + return false; + } + } + + /* We don't want to output symbols that have never been mentioned by + a regular file, or that we have been told to strip. However, if + h->indx is set to -2, the symbol is used by a reloc and we must + output it. */ + if (h->indx == -2) + strip = false; + else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + strip = true; + else if (finfo->info->strip == strip_all + || (finfo->info->strip == strip_some + && bfd_hash_lookup (finfo->info->keep_hash, + h->root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + /* If we're stripping it, and it's not a dynamic symbol, there's + nothing else to do. */ + if (strip && h->dynindx == -1) + return true; + + sym.st_value = 0; + sym.st_size = h->size; + sym.st_other = 0; + if (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_defweak) + sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + else + sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + return false; + + case bfd_link_hash_undefined: + input_sec = bfd_und_section_ptr; + sym.st_shndx = SHN_UNDEF; + break; + + case bfd_link_hash_undefweak: + input_sec = bfd_und_section_ptr; + sym.st_shndx = SHN_UNDEF; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + { + input_sec = h->root.u.def.section; + if (input_sec->output_section != NULL) + { + sym.st_shndx = + _bfd_elf_section_from_bfd_section (finfo->output_bfd, + input_sec->output_section); + if (sym.st_shndx == (unsigned short) -1) + { + eif->failed = true; + return false; + } + + /* ELF symbols in relocateable files are section relative, + but in nonrelocateable files they are virtual + addresses. */ + sym.st_value = h->root.u.def.value + input_sec->output_offset; + if (! finfo->info->relocateable) + sym.st_value += input_sec->output_section->vma; + } + else + { + BFD_ASSERT ((bfd_get_flavour (input_sec->owner) + == bfd_target_elf_flavour) + && elf_elfheader (input_sec->owner)->e_type == ET_DYN); + sym.st_shndx = SHN_UNDEF; + input_sec = bfd_und_section_ptr; + } + } + break; + + case bfd_link_hash_common: + input_sec = bfd_com_section_ptr; + sym.st_shndx = SHN_COMMON; + sym.st_value = 1 << h->root.u.c.p->alignment_power; + break; + + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* We can't represent these symbols in ELF. A warning symbol + may have come from a .gnu.warning.SYMBOL section anyhow. We + just put the target symbol in the hash table. If the target + symbol does not really exist, don't do anything. */ + if (h->root.u.i.link->type == bfd_link_hash_new) + return true; + return (elf_link_output_extsym + ((struct elf_link_hash_entry *) h->root.u.i.link, data)); + } + + /* If this symbol should be put in the .dynsym section, then put it + there now. We have 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) + { + struct elf_backend_data *bed; + size_t bucketcount; + size_t bucket; + bfd_byte *bucketpos; + bfd_vma chain; + + sym.st_name = h->dynstr_index; + + /* Give the processor backend a chance to tweak the symbol + value, and also to finish up anything that needs to be done + for this symbol. */ + bed = get_elf_backend_data (finfo->output_bfd); + if (! ((*bed->elf_backend_finish_dynamic_symbol) + (finfo->output_bfd, finfo->info, h, &sym))) + { + eif->failed = true; + return false; + } + + elf_swap_symbol_out (finfo->output_bfd, &sym, + (PTR) (((Elf_External_Sym *) + finfo->dynsym_sec->contents) + + h->dynindx)); + + bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucket = (bfd_elf_hash ((const unsigned char *) h->root.root.string) + % bucketcount); + bucketpos = ((bfd_byte *) finfo->hash_sec->contents + + (bucket + 2) * (ARCH_SIZE / 8)); + chain = get_word (finfo->output_bfd, bucketpos); + put_word (finfo->output_bfd, h->dynindx, bucketpos); + put_word (finfo->output_bfd, chain, + ((bfd_byte *) finfo->hash_sec->contents + + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8))); + } + + /* If we're stripping it, then it was just a dynamic symbol, and + there's nothing else to do. */ + if (strip) + return true; + + h->indx = finfo->output_bfd->symcount; + + if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) + { + eif->failed = true; + return false; + } + + return true; +} + +/* Link an input file into the linker output file. This function + handles all the sections and relocations of the input file at once. + This is so that we only have to read the local symbols once, and + don't have to keep them in memory. */ + +static boolean +elf_link_input_bfd (finfo, input_bfd) + struct elf_final_link_info *finfo; + bfd *input_bfd; +{ + boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *, + bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, + Elf_Internal_Sym *, asection **)); + bfd *output_bfd; + Elf_Internal_Shdr *symtab_hdr; + size_t locsymcount; + size_t extsymoff; + Elf_External_Sym *esym; + Elf_External_Sym *esymend; + Elf_Internal_Sym *isym; + long *pindex; + asection **ppsection; + asection *o; + + output_bfd = finfo->output_bfd; + relocate_section = + get_elf_backend_data (output_bfd)->elf_backend_relocate_section; + + /* If this is a dynamic object, we don't want to do anything here: + we don't want the local symbols, and we don't want the section + contents. */ + if (elf_elfheader (input_bfd)->e_type == ET_DYN) + return true; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + extsymoff = 0; + } + else + { + locsymcount = symtab_hdr->sh_info; + extsymoff = symtab_hdr->sh_info; + } + + /* Read the local symbols. */ + if (locsymcount > 0 + && (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym), + locsymcount, input_bfd) + != locsymcount * sizeof (Elf_External_Sym)))) + return false; + + /* Swap in the local symbols and write out the ones which we know + are going into the output file. */ + esym = finfo->external_syms; + esymend = esym + locsymcount; + isym = finfo->internal_syms; + pindex = finfo->indices; + ppsection = finfo->sections; + for (; esym < esymend; esym++, isym++, pindex++, ppsection++) + { + asection *isec; + const char *name; + Elf_Internal_Sym osym; + + elf_swap_symbol_in (input_bfd, esym, isym); + *pindex = -1; + + if (elf_bad_symtab (input_bfd)) + { + if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) + { + *ppsection = NULL; + continue; + } + } + + if (isym->st_shndx == SHN_UNDEF) + isec = bfd_und_section_ptr; + else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE) + isec = section_from_elf_index (input_bfd, isym->st_shndx); + else if (isym->st_shndx == SHN_ABS) + isec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + isec = bfd_com_section_ptr; + else + { + /* Who knows? */ + isec = NULL; + } + + *ppsection = isec; + + /* Don't output the first, undefined, symbol. */ + if (esym == finfo->external_syms) + continue; + + /* If we are stripping all symbols, we don't want to output this + one. */ + if (finfo->info->strip == strip_all) + continue; + + /* We never output section symbols. Instead, we use the section + symbol of the corresponding section in the output file. */ + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + continue; + + /* If we are discarding all local symbols, we don't want to + output this one. If we are generating a relocateable output + 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) + continue; + + /* Get the name of the symbol. */ + name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, + isym->st_name); + if (name == NULL) + 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) + == NULL)) + || (finfo->info->discard == discard_l + && strncmp (name, finfo->info->lprefix, + finfo->info->lprefix_len) == 0)) + continue; + + /* If we get here, we are going to output this symbol. */ + + osym = *isym; + + /* Adjust the section index for the output file. */ + osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, + isec->output_section); + if (osym.st_shndx == (unsigned short) -1) + return false; + + *pindex = output_bfd->symcount; + + /* ELF symbols in relocateable files are section relative, but + in executable files they are virtual addresses. Note that + this code assumes that all ELF sections have an associated + BFD section with a reasonable value for output_offset; below + we assume that they also have a reasonable value for + output_section. Any special sections must be set up to meet + these requirements. */ + osym.st_value += isec->output_offset; + if (! finfo->info->relocateable) + osym.st_value += isec->output_section->vma; + + if (! elf_link_output_sym (finfo, name, &osym, isec)) + return false; + } + + /* Relocate the contents of each section. */ + for (o = input_bfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) == 0) + continue; + + if ((o->flags & SEC_IN_MEMORY) != 0 + && input_bfd == elf_hash_table (finfo->info)->dynobj) + { + /* Section was created by elf_link_create_dynamic_sections. + FIXME: This test is fragile. */ + continue; + } + + /* Read the contents of the section. */ + if (! bfd_get_section_contents (input_bfd, o, finfo->contents, + (file_ptr) 0, o->_raw_size)) + return false; + + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Rela *internal_relocs; + + /* Get the swapped relocs. */ + internal_relocs = elf_link_read_relocs (input_bfd, o, + finfo->external_relocs, + finfo->internal_relocs, + false); + if (internal_relocs == NULL + && o->reloc_count > 0) + return false; + + /* Relocate the section by invoking a back end routine. + + The back end routine is responsible for adjusting the + section contents as necessary, and (if using Rela relocs + and generating a relocateable output file) adjusting the + reloc addend as necessary. + + The back end routine does not have to worry about setting + the reloc address or the reloc symbol index. + + The back end routine is given a pointer to the swapped in + internal symbols, and can access the hash table entries + for the external symbols via elf_sym_hashes (input_bfd). + + When generating relocateable output, the back end routine + must handle STB_LOCAL/STT_SECTION symbols specially. The + output symbol is going to be a section symbol + corresponding to the output section, which will require + the addend to be adjusted. */ + + if (! (*relocate_section) (output_bfd, finfo->info, + input_bfd, o, + finfo->contents, + internal_relocs, + finfo->internal_syms, + finfo->sections)) + return false; + + if (finfo->info->relocateable) + { + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *input_rel_hdr; + Elf_Internal_Shdr *output_rel_hdr; + + /* Adjust the reloc addresses and symbol indices. */ + + irela = internal_relocs; + irelaend = irela + o->reloc_count; + rel_hash = (elf_section_data (o->output_section)->rel_hashes + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, rel_hash++) + { + unsigned long r_symndx; + Elf_Internal_Sym *isym; + asection *sec; + + irela->r_offset += o->output_offset; + + r_symndx = ELF_R_SYM (irela->r_info); + + if (r_symndx == 0) + continue; + + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) + { + long indx; + + /* This is a reloc against a global symbol. We + have not yet output all the local symbols, so + we do not know the symbol index of any global + symbol. We set the rel_hash entry for this + reloc to point to the global hash table entry + for this symbol. The symbol index is then + set at the end of elf_bfd_final_link. */ + indx = r_symndx - extsymoff; + *rel_hash = elf_sym_hashes (input_bfd)[indx]; + + /* Setting the index to -2 tells + elf_link_output_extsym that this symbol is + used by a reloc. */ + BFD_ASSERT ((*rel_hash)->indx < 0); + (*rel_hash)->indx = -2; + + continue; + } + + /* This is a reloc against a local symbol. */ + + *rel_hash = NULL; + isym = finfo->internal_syms + r_symndx; + sec = finfo->sections[r_symndx]; + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + { + /* I suppose the backend ought to fill in the + section of any STT_SECTION symbol against a + processor specific section. */ + if (sec != NULL && bfd_is_abs_section (sec)) + r_symndx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + r_symndx = sec->output_section->target_index; + BFD_ASSERT (r_symndx != 0); + } + } + else + { + if (finfo->indices[r_symndx] == -1) + { + unsigned long link; + const char *name; + asection *osec; + + if (finfo->info->strip == strip_all) + { + /* You can't do ld -r -s. */ + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* This symbol was skipped earlier, but + since it is needed by a reloc, we + must output it now. */ + link = symtab_hdr->sh_link; + name = bfd_elf_string_from_elf_section (input_bfd, + link, + isym->st_name); + if (name == NULL) + return false; + + osec = sec->output_section; + isym->st_shndx = + _bfd_elf_section_from_bfd_section (output_bfd, + osec); + if (isym->st_shndx == (unsigned short) -1) + return false; + + isym->st_value += sec->output_offset; + if (! finfo->info->relocateable) + isym->st_value += osec->vma; + + finfo->indices[r_symndx] = output_bfd->symcount; + + if (! elf_link_output_sym (finfo, name, isym, sec)) + return false; + } + + r_symndx = finfo->indices[r_symndx]; + } + + irela->r_info = ELF_R_INFO (r_symndx, + ELF_R_TYPE (irela->r_info)); + } + + /* Swap out the relocs. */ + input_rel_hdr = &elf_section_data (o)->rel_hdr; + output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr; + BFD_ASSERT (output_rel_hdr->sh_entsize + == input_rel_hdr->sh_entsize); + irela = internal_relocs; + irelaend = irela + o->reloc_count; + if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + + erel = ((Elf_External_Rel *) output_rel_hdr->contents + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, erel++) + { + Elf_Internal_Rel irel; + + irel.r_offset = irela->r_offset; + irel.r_info = irela->r_info; + BFD_ASSERT (irela->r_addend == 0); + elf_swap_reloc_out (output_bfd, &irel, erel); + } + } + else + { + Elf_External_Rela *erela; + + BFD_ASSERT (input_rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + erela = ((Elf_External_Rela *) output_rel_hdr->contents + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, erela++) + elf_swap_reloca_out (output_bfd, irela, erela); + } + + o->output_section->reloc_count += o->reloc_count; + } + } + + /* Write out the modified section contents. */ + if (! bfd_set_section_contents (output_bfd, o->output_section, + finfo->contents, o->output_offset, + (o->_cooked_size != 0 + ? o->_cooked_size + : o->_raw_size))) + return false; + } + + return true; +} + +/* Generate a reloc when linking an ELF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static boolean +elf_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + reloc_howto_type *howto; + long indx; + bfd_vma offset; + bfd_vma addend; + struct elf_link_hash_entry **rel_hash_ptr; + Elf_Internal_Shdr *rel_hdr; + + howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + addend = link_order->u.reloc.p->addend; + + /* Figure out the symbol index. */ + rel_hash_ptr = (elf_section_data (output_section)->rel_hashes + + output_section->reloc_count); + if (link_order->type == bfd_section_reloc_link_order) + { + indx = link_order->u.reloc.p->u.section->target_index; + BFD_ASSERT (indx != 0); + *rel_hash_ptr = NULL; + } + else + { + struct elf_link_hash_entry *h; + + /* Treat a reloc against a defined symbol as though it were + actually against the section. */ + h = ((struct elf_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + asection *section; + + section = h->root.u.def.section; + indx = section->output_section->target_index; + *rel_hash_ptr = NULL; + /* It seems that we ought to add the symbol value to the + addend here, but in practice it has already been added + because it was passed to constructor_callback. */ + addend += section->output_section->vma + section->output_offset; + } + else if (h != NULL) + { + /* Setting the index to -2 tells elf_link_output_extsym that + this symbol is used by a reloc. */ + h->indx = -2; + *rel_hash_ptr = h; + indx = 0; + } + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + indx = 0; + } + } + + /* If this is an inplace reloc, we must write the addend into the + object file. */ + if (howto->partial_inplace && addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return false; + rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, + link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + howto->name, addend, (bfd *) NULL, (asection *) NULL, + (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + /* The address of a reloc is relative to the section in a + relocateable file, and is a virtual address in an executable + file. */ + offset = link_order->offset; + if (! info->relocateable) + offset += output_section->vma; + + rel_hdr = &elf_section_data (output_section)->rel_hdr; + + if (rel_hdr->sh_type == SHT_REL) + { + Elf_Internal_Rel irel; + Elf_External_Rel *erel; + + irel.r_offset = offset; + irel.r_info = ELF_R_INFO (indx, howto->type); + erel = ((Elf_External_Rel *) rel_hdr->contents + + output_section->reloc_count); + elf_swap_reloc_out (output_bfd, &irel, erel); + } + else + { + Elf_Internal_Rela irela; + Elf_External_Rela *erela; + + irela.r_offset = offset; + irela.r_info = ELF_R_INFO (indx, howto->type); + irela.r_addend = addend; + erela = ((Elf_External_Rela *) rel_hdr->contents + + output_section->reloc_count); + elf_swap_reloca_out (output_bfd, &irela, erela); + } + + ++output_section->reloc_count; + + return true; +} + + +/* Allocate a pointer to live in a linker created section. */ + +boolean +elf_create_pointer_linker_section (abfd, info, lsect, h, rel) + bfd *abfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + const Elf_Internal_Rela *rel; +{ + elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; + elf_linker_section_pointers_t *linker_section_ptr; + unsigned long r_symndx = ELF_R_SYM (rel->r_info);; + + BFD_ASSERT (lsect != NULL); + + /* Is this a global symbol? */ + if (h != NULL) + { + /* Has this symbol already been allocated, if so, our work is done */ + if (_bfd_elf_find_pointer_linker_section (h->linker_section_pointer, + rel->r_addend, + lsect->which)) + return true; + + ptr_linker_section_ptr = &h->linker_section_pointer; + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + return false; + } + + if (lsect->rel_section) + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + + else /* Allocation of a pointer to a local symbol */ + { + elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); + + /* Allocate a table to hold the local symbols if first time */ + if (!ptr) + { + int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info; + register unsigned int i; + + ptr = (elf_linker_section_pointers_t **) + bfd_alloc (abfd, num_symbols * sizeof (elf_linker_section_pointers_t *)); + + if (!ptr) + return false; + + elf_local_ptr_offsets (abfd) = ptr; + for (i = 0; i < num_symbols; i++) + ptr[i] = (elf_linker_section_pointers_t *)0; + } + + /* Has this symbol already been allocated, if so, our work is done */ + if (_bfd_elf_find_pointer_linker_section (ptr[r_symndx], + rel->r_addend, + lsect->which)) + return true; + + ptr_linker_section_ptr = &ptr[r_symndx]; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R__RELATIVE reloc so that the + dynamic linker can adjust this GOT entry. */ + BFD_ASSERT (lsect->rel_section != NULL); + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + } + + /* Allocate space for a pointer in the linker section, and allocate a new pointer record + from internal memory. */ + BFD_ASSERT (ptr_linker_section_ptr != NULL); + linker_section_ptr = (elf_linker_section_pointers_t *) + bfd_alloc (abfd, sizeof (elf_linker_section_pointers_t)); + + if (!linker_section_ptr) + return false; + + linker_section_ptr->next = *ptr_linker_section_ptr; + linker_section_ptr->addend = rel->r_addend; + linker_section_ptr->which = lsect->which; + linker_section_ptr->written_address_p = false; + *ptr_linker_section_ptr = linker_section_ptr; + + if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset) + { + linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size; + lsect->hole_offset += ARCH_SIZE / 8; + lsect->sym_offset += ARCH_SIZE / 8; + if (lsect->sym_hash) /* Bump up symbol value if needed */ + lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8; + } + else + linker_section_ptr->offset = lsect->section->_raw_size; + + lsect->section->_raw_size += ARCH_SIZE / 8; + +#ifdef DEBUG + fprintf (stderr, "Create pointer in linker section %s, offset = %ld, section size = %ld\n", + lsect->name, (long)linker_section_ptr->offset, (long)lsect->section->_raw_size); +#endif + + return true; +} + + +#if ARCH_SIZE==64 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR) +#endif +#if ARCH_SIZE==32 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_32 (BFD, VAL, ADDR) +#endif + +/* Fill in the address for a pointer generated in alinker section. */ + +bfd_vma +elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, relocation, rel, relative_reloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + bfd_vma relocation; + const Elf_Internal_Rela *rel; + int relative_reloc; +{ + elf_linker_section_pointers_t *linker_section_ptr; + + BFD_ASSERT (lsect != NULL); + + if (h != NULL) /* global symbol */ + { + linker_section_ptr = _bfd_elf_find_pointer_linker_section (h->linker_section_pointer, + rel->r_addend, + lsect->which); + + BFD_ASSERT (linker_section_ptr != NULL); + + if (! elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global section. + + When doing a dynamic link, we create a .rela. + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = true; + bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend, + lsect->section->contents + linker_section_ptr->offset); + } + } + } + else /* local symbol */ + { + unsigned long r_symndx = ELF_R_SYM (rel->r_info); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL); + linker_section_ptr = _bfd_elf_find_pointer_linker_section (elf_local_ptr_offsets (input_bfd)[r_symndx], + rel->r_addend, + lsect->which); + + BFD_ASSERT (linker_section_ptr != NULL); + + /* Write out pointer if it hasn't been rewritten out before */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = true; + bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend, + lsect->section->contents + linker_section_ptr->offset); + + if (info->shared) + { + asection *srel = lsect->rel_section; + Elf_Internal_Rela outrel; + + /* We need to generate a relative reloc for the dynamic linker. */ + if (!srel) + lsect->rel_section = srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj, + lsect->rel_name); + + BFD_ASSERT (srel != NULL); + + outrel.r_offset = (lsect->section->output_section->vma + + lsect->section->output_offset + + linker_section_ptr->offset); + outrel.r_info = ELF_R_INFO (0, relative_reloc); + outrel.r_addend = 0; + elf_swap_reloca_out (output_bfd, &outrel, + (((Elf_External_Rela *) + lsect->section->contents) + + lsect->section->reloc_count)); + ++lsect->section->reloc_count; + } + } + } + + relocation = (lsect->section->output_offset + + linker_section_ptr->offset + - lsect->hole_offset + - lsect->sym_offset); + +#ifdef DEBUG + fprintf (stderr, "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", + lsect->name, (long)relocation, (long)relocation); +#endif + + /* Subtract out the addend, because it will get added back in by the normal + processing. */ + return relocation - linker_section_ptr->addend; +} diff --git a/contrib/gdb/bfd/elfxx-target.h b/contrib/gdb/bfd/elfxx-target.h new file mode 100644 index 000000000000..f2c0c32cf62e --- /dev/null +++ b/contrib/gdb/bfd/elfxx-target.h @@ -0,0 +1,450 @@ +/* Target definitions for NN-bit ELF + Copyright 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This structure contains everything that BFD knows about a target. + It includes things like its byte order, name, what routines to call + to do various operations, etc. Every BFD points to a target structure + with its "xvec" member. + + There are two such structures here: one for big-endian machines and + one for little-endian machines. */ + +#define bfd_elfNN_close_and_cleanup _bfd_generic_close_and_cleanup +#define bfd_elfNN_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#ifndef bfd_elfNN_get_section_contents +#define bfd_elfNN_get_section_contents _bfd_generic_get_section_contents +#endif + +#define bfd_elfNN_canonicalize_dynamic_symtab _bfd_elf_canonicalize_dynamic_symtab +#define bfd_elfNN_canonicalize_reloc _bfd_elf_canonicalize_reloc +#ifndef bfd_elfNN_find_nearest_line +#define bfd_elfNN_find_nearest_line _bfd_elf_find_nearest_line +#endif +#define bfd_elfNN_read_minisymbols _bfd_elf_read_minisymbols +#define bfd_elfNN_minisymbol_to_symbol _bfd_elf_minisymbol_to_symbol +#define bfd_elfNN_get_dynamic_symtab_upper_bound _bfd_elf_get_dynamic_symtab_upper_bound +#define bfd_elfNN_get_lineno _bfd_elf_get_lineno +#define bfd_elfNN_get_reloc_upper_bound _bfd_elf_get_reloc_upper_bound +#define bfd_elfNN_get_symbol_info _bfd_elf_get_symbol_info +#define bfd_elfNN_get_symtab _bfd_elf_get_symtab +#define bfd_elfNN_get_symtab_upper_bound _bfd_elf_get_symtab_upper_bound +#if 0 /* done in elf-bfd.h */ +#define bfd_elfNN_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#endif +#define bfd_elfNN_make_empty_symbol _bfd_elf_make_empty_symbol +#define bfd_elfNN_new_section_hook _bfd_elf_new_section_hook +#define bfd_elfNN_set_arch_mach _bfd_elf_set_arch_mach +#ifndef bfd_elfNN_set_section_contents +#define bfd_elfNN_set_section_contents _bfd_elf_set_section_contents +#endif +#define bfd_elfNN_sizeof_headers _bfd_elf_sizeof_headers +#define bfd_elfNN_write_object_contents _bfd_elf_write_object_contents + +#define bfd_elfNN_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#ifndef elf_backend_want_got_plt +#define elf_backend_want_got_plt 0 +#endif +#ifndef elf_backend_plt_readonly +#define elf_backend_plt_readonly 0 +#endif +#ifndef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 +#endif + +#define bfd_elfNN_bfd_debug_info_start bfd_void +#define bfd_elfNN_bfd_debug_info_end bfd_void +#define bfd_elfNN_bfd_debug_info_accumulate (PROTO(void,(*),(bfd*, struct sec *))) bfd_void + +#ifndef bfd_elfNN_bfd_get_relocated_section_contents +#define bfd_elfNN_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#endif + +#define bfd_elfNN_bfd_relax_section bfd_generic_relax_section +#define bfd_elfNN_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +#ifndef bfd_elfNN_bfd_copy_private_symbol_data +#define bfd_elfNN_bfd_copy_private_symbol_data \ + _bfd_elf_copy_private_symbol_data +#endif + +#ifndef bfd_elfNN_bfd_copy_private_section_data +#define bfd_elfNN_bfd_copy_private_section_data \ + _bfd_elf_copy_private_section_data +#endif +#ifndef bfd_elfNN_bfd_copy_private_bfd_data +#define bfd_elfNN_bfd_copy_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_print_private_bfd_data +#define bfd_elfNN_bfd_print_private_bfd_data \ + _bfd_elf_print_private_bfd_data +#endif +#ifndef bfd_elfNN_bfd_merge_private_bfd_data +#define bfd_elfNN_bfd_merge_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_set_private_flags +#define bfd_elfNN_bfd_set_private_flags \ + ((boolean (*) PARAMS ((bfd *, flagword))) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_is_local_label +#define bfd_elfNN_bfd_is_local_label bfd_generic_is_local_label +#endif + +#ifndef bfd_elfNN_get_dynamic_reloc_upper_bound +#define bfd_elfNN_get_dynamic_reloc_upper_bound \ + _bfd_nodynamic_get_dynamic_reloc_upper_bound +#endif +#ifndef bfd_elfNN_canonicalize_dynamic_reloc +#define bfd_elfNN_canonicalize_dynamic_reloc \ + _bfd_nodynamic_canonicalize_dynamic_reloc +#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 +#else /* ! defined (elf_backend_relocate_section) */ +/* If no backend relocate_section routine, use the generic linker. */ +#ifndef bfd_elfNN_bfd_link_hash_table_create +#define bfd_elfNN_bfd_link_hash_table_create \ + _bfd_generic_link_hash_table_create +#endif +#ifndef bfd_elfNN_bfd_link_add_symbols +#define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols +#endif +#ifndef bfd_elfNN_bfd_final_link +#define bfd_elfNN_bfd_final_link _bfd_generic_final_link +#endif +#endif /* ! defined (elf_backend_relocate_section) */ +#ifndef bfd_elfNN_bfd_link_split_section +#define bfd_elfNN_bfd_link_split_section _bfd_generic_link_split_section +#endif + +#ifndef elf_symbol_leading_char +#define elf_symbol_leading_char 0 +#endif + +#ifndef elf_info_to_howto_rel +#define elf_info_to_howto_rel 0 +#endif + +#ifndef ELF_MAXPAGESIZE +#define ELF_MAXPAGESIZE 1 +#endif + +#ifndef elf_backend_collect +#define elf_backend_collect false +#endif +#ifndef elf_backend_type_change_ok +#define elf_backend_type_change_ok false +#endif + +#ifndef elf_backend_sym_is_global +#define elf_backend_sym_is_global 0 +#endif +#ifndef elf_backend_object_p +#define elf_backend_object_p 0 +#endif +#ifndef elf_backend_symbol_processing +#define elf_backend_symbol_processing 0 +#endif +#ifndef elf_backend_symbol_table_processing +#define elf_backend_symbol_table_processing 0 +#endif +#ifndef elf_backend_section_processing +#define elf_backend_section_processing 0 +#endif +#ifndef elf_backend_section_from_shdr +#define elf_backend_section_from_shdr 0 +#endif +#ifndef elf_backend_fake_sections +#define elf_backend_fake_sections 0 +#endif +#ifndef elf_backend_section_from_bfd_section +#define elf_backend_section_from_bfd_section 0 +#endif +#ifndef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook 0 +#endif +#ifndef elf_backend_link_output_symbol_hook +#define elf_backend_link_output_symbol_hook 0 +#endif +#ifndef elf_backend_create_dynamic_sections +#define elf_backend_create_dynamic_sections 0 +#endif +#ifndef elf_backend_check_relocs +#define elf_backend_check_relocs 0 +#endif +#ifndef elf_backend_adjust_dynamic_symbol +#define elf_backend_adjust_dynamic_symbol 0 +#endif +#ifndef elf_backend_size_dynamic_sections +#define elf_backend_size_dynamic_sections 0 +#endif +#ifndef elf_backend_relocate_section +#define elf_backend_relocate_section 0 +#endif +#ifndef elf_backend_finish_dynamic_symbol +#define elf_backend_finish_dynamic_symbol 0 +#endif +#ifndef elf_backend_finish_dynamic_sections +#define elf_backend_finish_dynamic_sections 0 +#endif +#ifndef elf_backend_begin_write_processing +#define elf_backend_begin_write_processing 0 +#endif +#ifndef elf_backend_final_write_processing +#define elf_backend_final_write_processing 0 +#endif +#ifndef elf_backend_additional_program_headers +#define elf_backend_additional_program_headers 0 +#endif +#ifndef elf_backend_modify_segment_map +#define elf_backend_modify_segment_map 0 +#endif +#ifndef elf_backend_ecoff_debug_swap +#define elf_backend_ecoff_debug_swap 0 +#endif + +#ifndef ELF_MACHINE_ALT1 +#define ELF_MACHINE_ALT1 0 +#endif + +#ifndef ELF_MACHINE_ALT2 +#define ELF_MACHINE_ALT2 0 +#endif + +extern const struct elf_size_info _bfd_elfNN_size_info; + +static CONST struct elf_backend_data elfNN_bed = +{ +#ifdef USE_REL + 0, /* use_rela_p */ +#else + 1, /* use_rela_p */ +#endif + ELF_ARCH, /* arch */ + ELF_MACHINE_CODE, /* elf_machine_code */ + ELF_MAXPAGESIZE, /* maxpagesize */ + elf_backend_collect, + elf_backend_type_change_ok, + elf_info_to_howto, + elf_info_to_howto_rel, + elf_backend_sym_is_global, + elf_backend_object_p, + elf_backend_symbol_processing, + elf_backend_symbol_table_processing, + elf_backend_section_processing, + elf_backend_section_from_shdr, + elf_backend_fake_sections, + elf_backend_section_from_bfd_section, + elf_backend_add_symbol_hook, + elf_backend_link_output_symbol_hook, + elf_backend_create_dynamic_sections, + elf_backend_check_relocs, + elf_backend_adjust_dynamic_symbol, + elf_backend_size_dynamic_sections, + elf_backend_relocate_section, + elf_backend_finish_dynamic_symbol, + elf_backend_finish_dynamic_sections, + elf_backend_begin_write_processing, + elf_backend_final_write_processing, + elf_backend_additional_program_headers, + elf_backend_modify_segment_map, + elf_backend_ecoff_debug_swap, + ELF_MACHINE_ALT1, + ELF_MACHINE_ALT2, + &_bfd_elfNN_size_info, + elf_backend_want_got_plt, + elf_backend_plt_readonly, + elf_backend_want_plt_sym +}; + +#ifdef TARGET_BIG_SYM +const bfd_target TARGET_BIG_SYM = +{ + /* name: identify kind of target */ + TARGET_BIG_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder: data is big endian */ + BFD_ENDIAN_BIG, + + /* header_byteorder: header is also big endian */ + BFD_ENDIAN_BIG, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | + DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + elf_symbol_leading_char, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 14, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elfNN_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + bfd_elfNN_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elf_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elfNN_write_object_contents, + _bfd_write_archive_contents, + bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elfNN), + BFD_JUMP_TABLE_COPY (bfd_elfNN), + BFD_JUMP_TABLE_CORE (bfd_elfNN), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (bfd_elfNN), + BFD_JUMP_TABLE_RELOCS (bfd_elfNN), + BFD_JUMP_TABLE_WRITE (bfd_elfNN), + BFD_JUMP_TABLE_LINK (bfd_elfNN), + BFD_JUMP_TABLE_DYNAMIC (bfd_elfNN), + + /* backend_data: */ + (PTR) &elfNN_bed, +}; +#endif + +#ifdef TARGET_LITTLE_SYM +const bfd_target TARGET_LITTLE_SYM = +{ + /* name: identify kind of target */ + TARGET_LITTLE_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder: data is little endian */ + BFD_ENDIAN_LITTLE, + + /* header_byteorder: header is also little endian */ + BFD_ENDIAN_LITTLE, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | + DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + elf_symbol_leading_char, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 14, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elfNN_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + bfd_elfNN_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elf_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elfNN_write_object_contents, + _bfd_write_archive_contents, + bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elfNN), + BFD_JUMP_TABLE_COPY (bfd_elfNN), + BFD_JUMP_TABLE_CORE (bfd_elfNN), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (bfd_elfNN), + BFD_JUMP_TABLE_RELOCS (bfd_elfNN), + BFD_JUMP_TABLE_WRITE (bfd_elfNN), + BFD_JUMP_TABLE_LINK (bfd_elfNN), + BFD_JUMP_TABLE_DYNAMIC (bfd_elfNN), + + /* backend_data: */ + (PTR) &elfNN_bed, +}; +#endif diff --git a/contrib/gdb/bfd/filemode.c b/contrib/gdb/bfd/filemode.c new file mode 100644 index 000000000000..fd790b367867 --- /dev/null +++ b/contrib/gdb/bfd/filemode.c @@ -0,0 +1,193 @@ +/* filemode.c -- make a string describing file modes + Copyright (C) 1985, 1990 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include + +void mode_string (); +static char ftypelet (); +static void rwx (); +static void setst (); + +/* filemodestring - fill in string STR with an ls-style ASCII + representation of the st_mode field of file stats block STATP. + 10 characters are stored in STR; no terminating null is added. + The characters stored in STR are: + + 0 File type. 'd' for directory, 'c' for character + special, 'b' for block special, 'm' for multiplex, + 'l' for symbolic link, 's' for socket, 'p' for fifo, + '-' for any other file type + + 1 'r' if the owner may read, '-' otherwise. + + 2 'w' if the owner may write, '-' otherwise. + + 3 'x' if the owner may execute, 's' if the file is + set-user-id, '-' otherwise. + 'S' if the file is set-user-id, but the execute + bit isn't set. + + 4 'r' if group members may read, '-' otherwise. + + 5 'w' if group members may write, '-' otherwise. + + 6 'x' if group members may execute, 's' if the file is + set-group-id, '-' otherwise. + 'S' if it is set-group-id but not executable. + + 7 'r' if any user may read, '-' otherwise. + + 8 'w' if any user may write, '-' otherwise. + + 9 'x' if any user may execute, 't' if the file is "sticky" + (will be retained in swap space after execution), '-' + otherwise. + 'T' if the file is sticky but not executable. */ + +void +filemodestring (statp, str) + struct stat *statp; + char *str; +{ + mode_string (statp->st_mode, str); +} + +/* Like filemodestring, but only the relevant part of the `struct stat' + is given as an argument. */ + +void +mode_string (mode, str) + unsigned short mode; + char *str; +{ + str[0] = ftypelet (mode); + rwx ((mode & 0700) << 0, &str[1]); + rwx ((mode & 0070) << 3, &str[4]); + rwx ((mode & 0007) << 6, &str[7]); + setst (mode, str); +} + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for any other file type. */ + +static char +ftypelet (bits) + unsigned short bits; +{ + switch (bits & S_IFMT) + { + default: + return '-'; + case S_IFDIR: + return 'd'; +#ifdef S_IFLNK + case S_IFLNK: + return 'l'; +#endif +#ifdef S_IFCHR + case S_IFCHR: + return 'c'; +#endif +#ifdef S_IFBLK + case S_IFBLK: + return 'b'; +#endif +#ifdef S_IFMPC + case S_IFMPC: + case S_IFMPB: + return 'm'; +#endif +#ifdef S_IFSOCK + case S_IFSOCK: + return 's'; +#endif +#ifdef S_IFIFO +#if S_IFIFO != S_IFSOCK + case S_IFIFO: + return 'p'; +#endif +#endif +#ifdef S_IFNWK /* HP-UX */ + case S_IFNWK: + return 'n'; +#endif + } +} + +/* Look at read, write, and execute bits in BITS and set + flags in CHARS accordingly. */ + +static void +rwx (bits, chars) + unsigned short bits; + char *chars; +{ + chars[0] = (bits & S_IREAD) ? 'r' : '-'; + chars[1] = (bits & S_IWRITE) ? 'w' : '-'; + chars[2] = (bits & S_IEXEC) ? 'x' : '-'; +} + +/* Set the 's' and 't' flags in file attributes string CHARS, + according to the file mode BITS. */ + +static void +setst (bits, chars) + unsigned short bits; + char *chars; +{ +#ifdef S_ISUID + if (bits & S_ISUID) + { + if (chars[3] != 'x') + /* Set-uid, but not executable by owner. */ + chars[3] = 'S'; + else + chars[3] = 's'; + } +#endif +#ifdef S_ISGID + if (bits & S_ISGID) + { + if (chars[6] != 'x') + /* Set-gid, but not executable by group. */ + chars[6] = 'S'; + else + chars[6] = 's'; + } +#endif +#ifdef S_ISVTX + if (bits & S_ISVTX) + { + if (chars[9] != 'x') + /* Sticky, but not executable by others. */ + chars[9] = 'T'; + else + chars[9] = 't'; + } +#endif +} + + diff --git a/contrib/gdb/bfd/format.c b/contrib/gdb/bfd/format.c new file mode 100644 index 000000000000..7a303424df65 --- /dev/null +++ b/contrib/gdb/bfd/format.c @@ -0,0 +1,319 @@ +/* Generic BFD support for file formats. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + File formats + + A format is a BFD concept of high level file contents type. The + formats supported by BFD are: + + o <> + + The BFD may contain data, symbols, relocations and debug info. + + o <> + + The BFD contains other BFDs and an optional index. + + o <> + + The BFD contains the result of an executable core dump. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* IMPORT from targets.c. */ +extern const size_t _bfd_target_vector_entries; + +/* +FUNCTION + bfd_check_format + +SYNOPSIS + boolean bfd_check_format(bfd *abfd, bfd_format format); + +DESCRIPTION + Verify if the file attached to the BFD @var{abfd} is compatible + with the format @var{format} (i.e., one of <>, + <> or <>). + + If the BFD has been set to a specific target before the + call, only the named target and format combination is + checked. If the target has not been set, or has been set to + <>, then all the known target backends is + interrogated to determine a match. If the default target + matches, it is used. If not, exactly one target must recognize + the file, or an error results. + + The function returns <> on success, otherwise <> + with one of the following error codes: + + o <> - + if <> is not one of <>, <> or + <>. + + o <> - + if an error occured during a read - even some file mismatches + can cause bfd_error_system_calls. + + o <> - + none of the backends recognised the file format. + + o <> - + more than one backend recognised the file format. +*/ + +boolean +bfd_check_format (abfd, format) + bfd *abfd; + bfd_format format; +{ + return bfd_check_format_matches (abfd, format, NULL); +} + +/* +FUNCTION + bfd_check_format_matches + +SYNOPSIS + boolean bfd_check_format_matches(bfd *abfd, bfd_format format, char ***matching); + +DESCRIPTION + Like <>, except when it returns false with + <> set to <>. In that + case, if @var{matching} is not NULL, it will be filled in with + a NULL-terminated list of the names of the formats that matched, + allocated with <>. + Then the user may choose a format and try again. + + When done with the list that @var{matching} points to, the caller + should free it. +*/ + +boolean +bfd_check_format_matches (abfd, format, matching) + bfd *abfd; + bfd_format format; + char ***matching; +{ + const bfd_target * const *target, *save_targ, *right_targ; + char **matching_vector = NULL; + int match_count; + + if (!bfd_read_p (abfd) || + ((int)(abfd->format) < (int)bfd_unknown) || + ((int)(abfd->format) >= (int)bfd_type_end)) { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format)? true: false; + + + /* 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; + if (matching) + { + matching_vector = + (char **) bfd_malloc (sizeof (char *) * + (_bfd_target_vector_entries + 1)); + if (!matching_vector) + return false; + matching_vector[0] = NULL; + *matching = matching_vector; + } + right_targ = 0; + + + /* presume the answer is yes */ + abfd->format = format; + + /* If the target type was explicitly specified, just check that target. */ + + if (!abfd->target_defaulted) { + if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0) /* rewind! */ + return false; + right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (right_targ) { + abfd->xvec = right_targ; /* Set the target as returned */ + if (matching) + free (matching_vector); + return true; /* File position has moved, BTW */ + } + } + + for (target = bfd_target_vector; *target != NULL; target++) { + extern const bfd_target binary_vec; + const bfd_target *temp; + + if (*target == &binary_vec) + continue; + + abfd->xvec = *target; /* Change BFD's target temporarily */ + if (bfd_seek (abfd, (file_ptr)0, SEEK_SET) != 0) + return false; + /* If _bfd_check_format neglects to set bfd_error, assume bfd_error_wrong_format. + We didn't used to even pay any attention to bfd_error, so I suspect + that some _bfd_check_format might have this problem. */ + bfd_set_error (bfd_error_wrong_format); + temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (temp) { /* This format checks out as ok! */ + right_targ = temp; + if (matching) + { + matching_vector[match_count] = temp->name; + matching_vector[match_count + 1] = NULL; + } + match_count++; + /* 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]) + { + if (matching) + { + matching_vector[0] = temp->name; + matching_vector[1] = NULL; + } + match_count = 1; + break; + } +#ifdef GNU960 + /* Big- and little-endian b.out archives look the same, but it doesn't + * matter: there is no difference in their headers, and member file byte + * orders will (I hope) be handled appropriately by bfd. Ditto for big + * and little coff archives. And the 4 coff/b.out object formats are + * unambiguous. So accept the first match we find. + */ + break; +#endif + } else if (bfd_get_error () != bfd_error_wrong_format) { + abfd->xvec = save_targ; + abfd->format = bfd_unknown; + if (matching && bfd_get_error () != bfd_error_file_ambiguously_recognized) + free (matching_vector); + return false; + } + } + + if (match_count == 1) { + abfd->xvec = right_targ; /* Change BFD's target permanently */ + if (matching) + free (matching_vector); + return true; /* File position has moved, BTW */ + } + + abfd->xvec = save_targ; /* Restore original target type */ + abfd->format = bfd_unknown; /* Restore original format */ + if (match_count == 0) + { + bfd_set_error (bfd_error_file_not_recognized); + if (matching) + free (matching_vector); + } + else + bfd_set_error (bfd_error_file_ambiguously_recognized); + return false; +} + +/* +FUNCTION + bfd_set_format + +SYNOPSIS + boolean bfd_set_format(bfd *abfd, bfd_format format); + +DESCRIPTION + This function sets the file format of the BFD @var{abfd} to the + format @var{format}. If the target set in the BFD does not + support the format requested, the format is invalid, or the BFD + is not open for writing, then an error occurs. + +*/ + +boolean +bfd_set_format (abfd, format) + bfd *abfd; + bfd_format format; +{ + + if (bfd_read_p (abfd) || + ((int)abfd->format < (int)bfd_unknown) || + ((int)abfd->format >= (int)bfd_type_end)) { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format) ? true:false; + + /* presume the answer is yes */ + abfd->format = format; + + if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) { + abfd->format = bfd_unknown; + return false; + } + + return true; +} + + +/* +FUNCTION + bfd_format_string + +SYNOPSIS + CONST char *bfd_format_string(bfd_format format); + +DESCRIPTION + Return a pointer to a const string + <>, <>, <>, <>, or <>, + depending upon the value of @var{format}. +*/ + +CONST char * +bfd_format_string (format) + bfd_format format; +{ + if (((int)format <(int) bfd_unknown) + || ((int)format >=(int) bfd_type_end)) + return "invalid"; + + switch (format) { + case bfd_object: + return "object"; /* linker/assember/compiler output */ + case bfd_archive: + return "archive"; /* object archive file */ + case bfd_core: + return "core"; /* core dump */ + default: + return "unknown"; + } +} diff --git a/contrib/gdb/bfd/freebsd.h b/contrib/gdb/bfd/freebsd.h new file mode 100644 index 000000000000..7e1d69d0df74 --- /dev/null +++ b/contrib/gdb/bfd/freebsd.h @@ -0,0 +1,109 @@ +/* BFD back-end definitions used by all FreeBSD targets. + Copyright (C) 1990, 1991, 1992, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* FreeBSD ZMAGIC files never have the header in the text. */ +#define N_HEADER_IN_TEXT(x) 0 + +/* ZMAGIC files start at offset 0. Does not apply to QMAGIC files. */ +#define TEXT_START_ADDR 0 + +#define N_GETMAGIC_NET(exec) \ + (ntohl ((exec).a_info) & 0xffff) +#define N_GETMID_NET(exec) \ + ((ntohl ((exec).a_info) >> 16) & 0x3ff) +#define N_GETFLAG_NET(ex) \ + ((ntohl ((exec).a_info) >> 26) & 0x3f) + +#define N_MACHTYPE(exec) \ + ((enum machine_type) \ + ((N_GETMAGIC_NET (exec) == ZMAGIC) ? N_GETMID_NET (exec) : \ + ((exec).a_info >> 16) & 0x3ff)) +#define N_FLAGS(exec) \ + ((N_GETMAGIC_NET (exec) == ZMAGIC) ? N_GETFLAG_NET (exec) : \ + ((exec).a_info >> 26) & 0x3f) + +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0x3ff) << 16) \ + | (((flags) & 0x3f) << 26)) +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info & 0xfb00ffff) | ((((int)(machtype))&0x3ff) << 16)) +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info & 0x03ffffff) | ((flags & 0x03f) << 26)) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +/* On FreeBSD, the magic number is always in correct endian format */ +#define NO_SWAP_MAGIC + + +#define MY_write_object_contents MY(write_object_contents) +static boolean MY(write_object_contents) PARAMS ((bfd *abfd)); + +#include "aout-target.h" + +/* Write an object file. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +static boolean +MY(write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + /* Magic number, maestro, please! */ + switch (bfd_get_arch(abfd)) { + case bfd_arch_m68k: + if (strcmp (abfd->xvec->name, "a.out-m68k4k-netbsd") == 0) + N_SET_MACHTYPE(*execp, M_68K4K_NETBSD); + else + N_SET_MACHTYPE(*execp, M_68K_NETBSD); + break; + case bfd_arch_sparc: + N_SET_MACHTYPE(*execp, M_SPARC_NETBSD); + break; + case bfd_arch_i386: + N_SET_MACHTYPE(*execp, M_386_NETBSD); + break; + case bfd_arch_ns32k: + N_SET_MACHTYPE(*execp, M_532_NETBSD); + break; + default: + N_SET_MACHTYPE(*execp, M_UNKNOWN); + break; + } + + WRITE_HEADERS(abfd, execp); + + return true; +} diff --git a/contrib/gdb/bfd/gen-aout.c b/contrib/gdb/bfd/gen-aout.c new file mode 100644 index 000000000000..d2224f762d35 --- /dev/null +++ b/contrib/gdb/bfd/gen-aout.c @@ -0,0 +1,101 @@ +/* Generate parameters for an a.out system. + Copyright (C) 1990, 91, 92, 93, 94 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "/usr/include/a.out.h" +#include + +int +main (argc, argv) + int argc; char** argv; +{ + struct exec my_exec; + int page_size; + char *target = "unknown", *arch = "unknown"; + FILE *file = fopen("gen-aout", "r"); + + if (file == NULL) { + fprintf(stderr, "Cannot open gen-aout!\n"); + return -1; + } + if (fread(&my_exec, sizeof(struct exec), 1, file) != 1) { + fprintf(stderr, "Cannot read gen-aout!\n"); + return -1; + } + + target = argv[1]; + if (target == NULL) { + fprintf(stderr, "Usage: gen-aout target_name\n"); + exit (1); + } + +#ifdef N_TXTOFF + page_size = N_TXTOFF(my_exec); + if (page_size == 0) + printf("#define N_HEADER_IN_TEXT(x) 1\n"); + else + printf("#define N_HEADER_IN_TEXT(x) 0\n"); +#endif + + printf("#define BYTES_IN_WORD %d\n", sizeof (int)); + if (my_exec.a_entry == 0) { + printf("#define ENTRY_CAN_BE_ZERO\n"); + printf("#define N_SHARED_LIB(x) 0 /* Avoids warning */\n"); + } + else { + printf("/*#define ENTRY_CAN_BE_ZERO*/\n"); + printf("/*#define N_SHARED_LIB(x) 0*/\n"); + } + + printf("#define TEXT_START_ADDR %d\n", my_exec.a_entry); + +#ifdef PAGSIZ + if (page_size == 0) + page_size = PAGSIZ; +#endif + if (page_size != 0) + printf("#define TARGET_PAGE_SIZE %d\n", page_size); + else + printf("/* #define TARGET_PAGE_SIZE ??? */\n"); + printf("#define SEGMENT_SIZE TARGET_PAGE_SIZE\n"); + +#ifdef vax + arch = "vax"; +#endif +#ifdef m68k + arch = "m68k"; +#endif + if (arch[0] == '1') + { + fprintf (stderr, "warning: preprocessor substituted architecture name inside string;"); + fprintf (stderr, " fix DEFAULT_ARCH in the output file yourself\n"); + arch = "unknown"; + } + printf("#define DEFAULT_ARCH bfd_arch_%s\n", arch); + + printf("\n#define MY(OP) CAT(%s_,OP)\n", target); + printf("#define TARGETNAME \"a.out-%s\"\n\n", target); + + printf("#include \"bfd.h\"\n"); + printf("#include \"sysdep.h\"\n"); + printf("#include \"libbfd.h\"\n"); + printf("#include \"libaout.h\"\n"); + printf("\n#include \"aout-target.h\"\n"); + + return 0; +} diff --git a/contrib/gdb/bfd/genlink.h b/contrib/gdb/bfd/genlink.h new file mode 100644 index 000000000000..5f0809485747 --- /dev/null +++ b/contrib/gdb/bfd/genlink.h @@ -0,0 +1,106 @@ +/* genlink.h -- interface to the BFD generic linker + Copyright 1993, 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GENLINK_H +#define GENLINK_H + +/* This header file is internal to BFD. It describes the internal + structures and functions used by the BFD generic linker, in case + any of the more specific linkers want to use or call them. Note + that some functions, such as _bfd_generic_link_hash_table_create, + are declared in libbfd.h, because they are expected to be widely + used. The functions and structures in this file will probably only + be used by a few files besides linker.c itself. In fact, this file + is not particularly complete; I have only put in the interfaces I + actually needed. */ + +/* The generic linker uses a hash table which is a derived class of + the standard linker hash table, just as the other backend specific + linkers do. Do not confuse the generic linker hash table with the + standard BFD linker hash table it is built upon. */ + +/* Generic linker hash table entries. */ + +struct generic_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Whether this symbol has been written out. */ + boolean written; + /* Symbol from input BFD. */ + asymbol *sym; +}; + +/* Generic linker hash table. */ + +struct generic_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in an generic link hash table. */ + +#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \ + ((struct generic_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an generic link hash table. */ + +#define _bfd_generic_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the generic link hash table from the info structure. This is + just a cast. */ + +#define _bfd_generic_hash_table(p) \ + ((struct generic_link_hash_table *) ((p)->hash)) + +/* The generic linker reads in the asymbol structures for an input BFD + and keeps them in the outsymbol and symcount fields. */ + +#define _bfd_generic_link_get_symbols(abfd) ((abfd)->outsymbols) +#define _bfd_generic_link_get_symcount(abfd) ((abfd)->symcount) + +/* Add the symbols of input_bfd to the symbols being built for + output_bfd. */ +extern boolean _bfd_generic_link_output_symbols + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + size_t *psymalloc)); + +/* This structure is used to pass information to + _bfd_generic_link_write_global_symbol, which may be called via + _bfd_generic_link_hash_traverse. */ + +struct generic_write_global_symbol_info +{ + struct bfd_link_info *info; + bfd *output_bfd; + size_t *psymalloc; +}; + +/* Write out a single global symbol. This is expected to be called + via _bfd_generic_link_hash_traverse. The second argument must + actually be a struct generic_write_global_symbol_info *. */ +extern boolean _bfd_generic_link_write_global_symbol + PARAMS ((struct generic_link_hash_entry *, PTR)); + +#endif diff --git a/contrib/gdb/bfd/hash.c b/contrib/gdb/bfd/hash.c new file mode 100644 index 000000000000..35913fcfccc9 --- /dev/null +++ b/contrib/gdb/bfd/hash.c @@ -0,0 +1,734 @@ +/* hash.c -- hash table routines for BFD + Copyright (C) 1993, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +/* +SECTION + Hash Tables + +@cindex Hash tables + BFD provides a simple set of hash table functions. Routines + are provided to initialize a hash table, to free a hash table, + to look up a string in a hash table and optionally create an + entry for it, and to traverse a hash table. There is + currently no routine to delete an string from a hash table. + + The basic hash table does not permit any data to be stored + with a string. However, a hash table is designed to present a + base class from which other types of hash tables may be + derived. These derived types may store additional information + with the string. Hash tables were implemented in this way, + rather than simply providing a data pointer in a hash table + entry, because they were designed for use by the linker back + ends. The linker may create thousands of hash table entries, + and the overhead of allocating private data and storing and + following pointers becomes noticeable. + + The basic hash table code is in <>. + +@menu +@* Creating and Freeing a Hash Table:: +@* Looking Up or Entering a String:: +@* Traversing a Hash Table:: +@* Deriving a New Hash Table Type:: +@end menu + +INODE +Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables +SUBSECTION + Creating and freeing a hash table + +@findex bfd_hash_table_init +@findex bfd_hash_table_init_n + To create a hash table, create an instance of a <> (defined in <>) and call + <> (if you know approximately how many + entries you will need, the function <>, + which takes a @var{size} argument, may be used). + <> returns <> if some sort of + error occurs. + +@findex bfd_hash_newfunc + The function <> take as an argument a + function to use to create new entries. For a basic hash + table, use the function <>. @xref{Deriving + a New Hash Table Type} for why you would want to use a + different value for this argument. + +@findex bfd_hash_allocate + <> will create an obstack which will be + used to allocate new entries. You may allocate memory on this + obstack using <>. + +@findex bfd_hash_table_free + Use <> to free up all the memory that has + been allocated for a hash table. This will not free up the + <> itself, which you must provide. + +INODE +Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables +SUBSECTION + Looking up or entering a string + +@findex bfd_hash_lookup + The function <> is used both to look up a + string in the hash table and to create a new entry. + + If the @var{create} argument is <>, <> + will look up a string. If the string is found, it will + returns a pointer to a <>. If the + string is not found in the table <> will + return <>. You should not modify any of the fields in + the returns <>. + + If the @var{create} argument is <>, the string will be + entered into the hash table if it is not already there. + Either way a pointer to a <> will be + returned, either to the existing structure or to a newly + created one. In this case, a <> return means that an + error occurred. + + If the @var{create} argument is <>, and a new entry is + created, the @var{copy} argument is used to decide whether to + copy the string onto the hash table obstack or not. If + @var{copy} is passed as <>, you must be careful not to + deallocate or modify the string as long as the hash table + exists. + +INODE +Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables +SUBSECTION + Traversing a hash table + +@findex bfd_hash_traverse + The function <> may be used to traverse a + hash table, calling a function on each element. The traversal + is done in a random order. + + <> takes as arguments a function and a + generic <> pointer. The function is called with a + hash table entry (a <>) and the + generic pointer passed to <>. The function + must return a <> value, which indicates whether to + continue traversing the hash table. If the function returns + <>, <> will stop the traversal and + return immediately. + +INODE +Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables +SUBSECTION + Deriving a new hash table type + + Many uses of hash tables want to store additional information + which each entry in the hash table. Some also find it + convenient to store additional information with the hash table + itself. This may be done using a derived hash table. + + Since C is not an object oriented language, creating a derived + hash table requires sticking together some boilerplate + routines with a few differences specific to the type of hash + table you want to create. + + An example of a derived hash table is the linker hash table. + The structures for this are defined in <>. The + functions are in <>. + + You may also derive a hash table from an already derived hash + table. For example, the a.out linker backend code uses a hash + table derived from the linker hash table. + +@menu +@* Define the Derived Structures:: +@* Write the Derived Creation Routine:: +@* Write Other Derived Routines:: +@end menu + +INODE +Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type +SUBSUBSECTION + Define the derived structures + + You must define a structure for an entry in the hash table, + and a structure for the hash table itself. + + The first field in the structure for an entry in the hash + table must be of the type used for an entry in the hash table + you are deriving from. If you are deriving from a basic hash + table this is <>, which is defined in + <>. The first field in the structure for the hash + table itself must be of the type of the hash table you are + deriving from itself. If you are deriving from a basic hash + table, this is <>. + + For example, the linker hash table defines <> (in <>). The first field, + <>, is of type <>. Similarly, + the first field in <>, <>, + is of type <>. + +INODE +Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type +SUBSUBSECTION + Write the derived creation routine + + You must write a routine which will create and initialize an + entry in the hash table. This routine is passed as the + function argument to <>. + + In order to permit other hash tables to be derived from the + hash table you are creating, this routine must be written in a + standard way. + + The first argument to the creation routine is a pointer to a + hash table entry. This may be <>, in which case the + routine should allocate the right amount of space. Otherwise + the space has already been allocated by a hash table type + derived from this one. + + After allocating space, the creation routine must call the + creation routine of the hash table type it is derived from, + passing in a pointer to the space it just allocated. This + will initialize any fields used by the base hash table. + + Finally the creation routine must initialize any local fields + for the new hash table type. + + Here is a boilerplate example of a creation routine. + @var{function_name} is the name of the routine. + @var{entry_type} is the type of an entry in the hash table you + are creating. @var{base_newfunc} is the name of the creation + routine of the hash table type your hash table is derived + from. + +EXAMPLE + +.struct bfd_hash_entry * +.@var{function_name} (entry, table, string) +. struct bfd_hash_entry *entry; +. struct bfd_hash_table *table; +. const char *string; +.{ +. struct @var{entry_type} *ret = (@var{entry_type} *) entry; +. +. {* Allocate the structure if it has not already been allocated by a +. derived class. *} +. if (ret == (@var{entry_type} *) NULL) +. { +. ret = ((@var{entry_type} *) +. bfd_hash_allocate (table, sizeof (@var{entry_type}))); +. if (ret == (@var{entry_type} *) NULL) +. return NULL; +. } +. +. {* Call the allocation method of the base class. *} +. ret = ((@var{entry_type} *) +. @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string)); +. +. {* Initialize the local fields here. *} +. +. return (struct bfd_hash_entry *) ret; +.} + +DESCRIPTION + The creation routine for the linker hash table, which is in + <>, looks just like this example. + @var{function_name} is <<_bfd_link_hash_newfunc>>. + @var{entry_type} is <>. + @var{base_newfunc} is <>, the creation + routine for a basic hash table. + + <<_bfd_link_hash_newfunc>> also initializes the local fields + in a linker hash table entry: <>, <> and + <>. + +INODE +Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type +SUBSUBSECTION + Write other derived routines + + You will want to write other routines for your new hash table, + as well. + + You will want an initialization routine which calls the + initialization routine of the hash table you are deriving from + and initializes any other local fields. For the linker hash + table, this is <<_bfd_link_hash_table_init>> in <>. + + You will want a lookup routine which calls the lookup routine + of the hash table you are deriving from and casts the result. + The linker hash table uses <> in + <> (this actually takes an additional argument which + it uses to decide how to return the looked up value). + + You may want a traversal routine. This should just call the + traversal routine of the hash table you are deriving from with + appropriate casts. The linker hash table uses + <> in <>. + + These routines may simply be defined as macros. For example, + the a.out backend linker hash table, which is derived from the + linker hash table, uses macros for the lookup and traversal + routines. These are <> and + <> in aoutx.h. +*/ + +/* Obstack allocation and deallocation routines. */ +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* The default number of entries to use when creating a hash table. */ +#define DEFAULT_SIZE (4051) + +/* Create a new hash table, given a number of entries. */ + +boolean +bfd_hash_table_init_n (table, newfunc, size) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + unsigned int size; +{ + unsigned int alloc; + + alloc = size * sizeof (struct bfd_hash_entry *); + if (!obstack_begin (&table->memory, alloc)) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + table->table = ((struct bfd_hash_entry **) + obstack_alloc (&table->memory, alloc)); + if (!table->table) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset ((PTR) table->table, 0, alloc); + table->size = size; + table->newfunc = newfunc; + return true; +} + +/* Create a new hash table with the default number of entries. */ + +boolean +bfd_hash_table_init (table, newfunc) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE); +} + +/* Free a hash table. */ + +void +bfd_hash_table_free (table) + struct bfd_hash_table *table; +{ + obstack_free (&table->memory, (PTR) NULL); +} + +/* Look up a string in a hash table. */ + +struct bfd_hash_entry * +bfd_hash_lookup (table, string, create, copy) + struct bfd_hash_table *table; + const char *string; + boolean create; + boolean copy; +{ + register const unsigned char *s; + register unsigned long hash; + register unsigned int c; + struct bfd_hash_entry *hashp; + unsigned int len; + unsigned int index; + + hash = 0; + len = 0; + s = (const unsigned char *) string; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + index = hash % table->size; + for (hashp = table->table[index]; + hashp != (struct bfd_hash_entry *) NULL; + hashp = hashp->next) + { + if (hashp->hash == hash + && strcmp (hashp->string, string) == 0) + return hashp; + } + + if (! create) + return (struct bfd_hash_entry *) NULL; + + hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string); + if (hashp == (struct bfd_hash_entry *) NULL) + return (struct bfd_hash_entry *) NULL; + if (copy) + { + char *new; + + new = (char *) obstack_alloc (&table->memory, len + 1); + if (!new) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_hash_entry *) NULL; + } + strcpy (new, string); + string = new; + } + hashp->string = string; + hashp->hash = hash; + hashp->next = table->table[index]; + table->table[index] = hashp; + + return hashp; +} + +/* Replace an entry in a hash table. */ + +void +bfd_hash_replace (table, old, nw) + struct bfd_hash_table *table; + struct bfd_hash_entry *old; + struct bfd_hash_entry *nw; +{ + unsigned int index; + struct bfd_hash_entry **pph; + + index = old->hash % table->size; + for (pph = &table->table[index]; + (*pph) != (struct bfd_hash_entry *) NULL; + pph = &(*pph)->next) + { + if (*pph == old) + { + *pph = nw; + return; + } + } + + abort (); +} + +/* Base method for creating a new hash table entry. */ + +/*ARGSUSED*/ +struct bfd_hash_entry * +bfd_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + if (entry == (struct bfd_hash_entry *) NULL) + entry = ((struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_hash_entry))); + return entry; +} + +/* Allocate space in a hash table. */ + +PTR +bfd_hash_allocate (table, size) + struct bfd_hash_table *table; + unsigned int size; +{ + PTR ret; + + ret = obstack_alloc (&table->memory, size); + if (ret == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +/* Traverse a hash table. */ + +void +bfd_hash_traverse (table, func, info) + struct bfd_hash_table *table; + boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR)); + PTR info; +{ + unsigned int i; + + for (i = 0; i < table->size; i++) + { + struct bfd_hash_entry *p; + + for (p = table->table[i]; p != NULL; p = p->next) + { + if (! (*func) (p, info)) + return; + } + } +} + +/* A few different object file formats (a.out, COFF, ELF) use a string + table. These functions support adding strings to a string table, + returning the byte offset, and writing out the table. + + Possible improvements: + + look for strings matching trailing substrings of other strings + + better data structures? balanced trees? + + look at reducing memory use elsewhere -- maybe if we didn't have + to construct the entire symbol table at once, we could get by + with smaller amounts of VM? (What effect does that have on the + string table reductions?) */ + +/* An entry in the strtab hash table. */ + +struct strtab_hash_entry +{ + struct bfd_hash_entry root; + /* Index in string table. */ + bfd_size_type index; + /* Next string in strtab. */ + struct strtab_hash_entry *next; +}; + +/* The strtab hash table. */ + +struct bfd_strtab_hash +{ + struct bfd_hash_table table; + /* Size of strtab--also next available index. */ + bfd_size_type size; + /* First string in strtab. */ + struct strtab_hash_entry *first; + /* Last string in strtab. */ + struct strtab_hash_entry *last; + /* Whether to precede strings with a two byte length, as in the + XCOFF .debug section. */ + boolean xcoff; +}; + +static struct bfd_hash_entry *strtab_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +/* Routine to create an entry in a strtab. */ + +static struct bfd_hash_entry * +strtab_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct strtab_hash_entry *) NULL) + ret = ((struct strtab_hash_entry *) + bfd_hash_allocate (table, sizeof (struct strtab_hash_entry))); + if (ret == (struct strtab_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct strtab_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->index = (bfd_size_type) -1; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in an strtab. */ + +#define strtab_hash_lookup(t, string, create, copy) \ + ((struct strtab_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Create a new strtab. */ + +struct bfd_strtab_hash * +_bfd_stringtab_init () +{ + struct bfd_strtab_hash *table; + + table = ((struct bfd_strtab_hash *) + bfd_malloc (sizeof (struct bfd_strtab_hash))); + if (table == NULL) + return NULL; + + if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc)) + { + free (table); + return NULL; + } + + table->size = 0; + table->first = NULL; + table->last = NULL; + table->xcoff = false; + + return table; +} + +/* Create a new strtab in which the strings are output in the format + used in the XCOFF .debug section: a two byte length precedes each + string. */ + +struct bfd_strtab_hash * +_bfd_xcoff_stringtab_init () +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + ret->xcoff = true; + return ret; +} + +/* Free a strtab. */ + +void +_bfd_stringtab_free (table) + struct bfd_strtab_hash *table; +{ + bfd_hash_table_free (&table->table); + free (table); +} + +/* Get the index of a string in a strtab, adding it if it is not + already present. If HASH is false, we don't really use the hash + table, and we don't eliminate duplicate strings. */ + +bfd_size_type +_bfd_stringtab_add (tab, str, hash, copy) + struct bfd_strtab_hash *tab; + const char *str; + boolean hash; + boolean copy; +{ + register struct strtab_hash_entry *entry; + + if (hash) + { + entry = strtab_hash_lookup (tab, str, true, copy); + if (entry == NULL) + return (bfd_size_type) -1; + } + else + { + entry = ((struct strtab_hash_entry *) + bfd_hash_allocate (&tab->table, + sizeof (struct strtab_hash_entry))); + if (entry == NULL) + return (bfd_size_type) -1; + if (! copy) + entry->root.string = str; + else + { + char *n; + + n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1); + if (n == NULL) + return (bfd_size_type) -1; + entry->root.string = n; + } + entry->index = (bfd_size_type) -1; + entry->next = NULL; + } + + if (entry->index == (bfd_size_type) -1) + { + entry->index = tab->size; + tab->size += strlen (str) + 1; + if (tab->xcoff) + { + entry->index += 2; + tab->size += 2; + } + if (tab->first == NULL) + tab->first = entry; + else + tab->last->next = entry; + tab->last = entry; + } + + return entry->index; +} + +/* Get the number of bytes in a strtab. */ + +bfd_size_type +_bfd_stringtab_size (tab) + struct bfd_strtab_hash *tab; +{ + return tab->size; +} + +/* Write out a strtab. ABFD must already be at the right location in + the file. */ + +boolean +_bfd_stringtab_emit (abfd, tab) + register bfd *abfd; + struct bfd_strtab_hash *tab; +{ + register boolean xcoff; + register struct strtab_hash_entry *entry; + + xcoff = tab->xcoff; + + for (entry = tab->first; entry != NULL; entry = entry->next) + { + register const char *str; + register size_t len; + + str = entry->root.string; + len = strlen (str) + 1; + + if (xcoff) + { + bfd_byte buf[2]; + + /* The output length includes the null byte. */ + bfd_put_16 (abfd, len, buf); + if (bfd_write ((PTR) buf, 1, 2, abfd) != 2) + return false; + } + + if (bfd_write ((PTR) str, 1, len, abfd) != len) + return false; + } + + return true; +} diff --git a/contrib/gdb/bfd/host-aout.c b/contrib/gdb/bfd/host-aout.c new file mode 100644 index 000000000000..99643dcc24ef --- /dev/null +++ b/contrib/gdb/bfd/host-aout.c @@ -0,0 +1,83 @@ +/* BFD backend for local host's a.out binaries + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. Probably John Gilmore's fault. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#define ARCH_SIZE 32 + +/* When porting to a new system, you must supply: + + HOST_PAGE_SIZE (optional) + HOST_SEGMENT_SIZE (optional -- defaults to page size) + HOST_MACHINE_ARCH (optional) + HOST_MACHINE_MACHINE (optional) + HOST_TEXT_START_ADDR (optional) + HOST_STACK_END_ADDR (not used, except by trad-core ???) + HOST_BIG_ENDIAN_P (required -- define if big-endian) + + in the ./hosts/h-systemname.h file. */ + +#ifdef TRAD_HEADER +#include TRAD_HEADER +#endif + +#ifdef HOST_PAGE_SIZE +#define TARGET_PAGE_SIZE HOST_PAGE_SIZE +#endif + +#ifdef HOST_SEGMENT_SIZE +#define SEGMENT_SIZE HOST_SEGMENT_SIZE +#else +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#endif + +#ifdef HOST_TEXT_START_ADDR +#define TEXT_START_ADDR HOST_TEXT_START_ADDR +#endif + +#ifdef HOST_STACK_END_ADDR +#define STACK_END_ADDR HOST_STACK_END_ADDR +#endif + +#ifdef HOST_BIG_ENDIAN_P +#define TARGET_IS_BIG_ENDIAN_P +#else +#undef TARGET_IS_BIG_ENDIAN_P +#endif + +#include "libaout.h" /* BFD a.out internal data structures */ +#include "aout/aout64.h" + +#ifdef HOST_MACHINE_ARCH +#ifdef HOST_MACHINE_MACHINE +#define SET_ARCH_MACH(abfd, execp) \ + bfd_default_set_arch_mach(abfd, HOST_MACHINE_ARCH, HOST_MACHINE_MACHINE) +#else +#define SET_ARCH_MACH(abfd, execp) \ + bfd_default_set_arch_mach(abfd, HOST_MACHINE_ARCH, 0) +#endif +#endif /* HOST_MACHINE_ARCH */ + +#define MY(OP) CAT(host_aout_,OP) +#define TARGETNAME "a.out" + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/hosts/alphalinux.h b/contrib/gdb/bfd/hosts/alphalinux.h new file mode 100644 index 000000000000..d9ba1b7ec6be --- /dev/null +++ b/contrib/gdb/bfd/hosts/alphalinux.h @@ -0,0 +1,6 @@ +/* Linux dumps "struct task_struct" at the end of the core-file. This + structure is currently 920 bytes long, but we allow up to 1024 + bytes to allow for some future growth. */ +#define TRAD_CORE_EXTRA_SIZE_ALLOWED 1024 +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(abfd) \ + ((abfd)->tdata.trad_core_data->u.signal) diff --git a/contrib/gdb/bfd/hosts/decstation.h b/contrib/gdb/bfd/hosts/decstation.h new file mode 100644 index 000000000000..a80c143d525e --- /dev/null +++ b/contrib/gdb/bfd/hosts/decstation.h @@ -0,0 +1,17 @@ +/* Hopefully this should include either machine/param.h (Ultrix) or + machine/machparam.h (Mach), whichever is its name on this system. */ +#include + +#include + +#define HOST_PAGE_SIZE NBPG +/* #define HOST_SEGMENT_SIZE NBPG -- we use HOST_DATA_START_ADDR */ +#define HOST_MACHINE_ARCH bfd_arch_mips +/* #define HOST_MACHINE_MACHINE */ + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_DATA_START_ADDR USRDATA +#define HOST_STACK_END_ADDR USRSTACK + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_arg[0]) diff --git a/contrib/gdb/bfd/hosts/delta68.h b/contrib/gdb/bfd/hosts/delta68.h new file mode 100644 index 000000000000..1a6a6e6f197e --- /dev/null +++ b/contrib/gdb/bfd/hosts/delta68.h @@ -0,0 +1,18 @@ +/* Definitions for a Motorola Delta 3300 box running System V R3.0. + Contributed by manfred@lts.sel.alcatel.de. */ + +#include + +/* Definitions used by trad-core.c. */ +#define NBPG NBPC +#define HOST_DATA_START_ADDR u.u_exdata.ux_datorg +#define HOST_TEXT_START_ADDR u.u_exdata.ux_txtorg +#if 0 +#define HOST_STACK_END_ADDR 0x40000000 +#else +/* User's stack, copied from sys/param.h */ +#define HOST_STACK_END_ADDR USRSTACK +#endif +#define UPAGES USIZE +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(abfd) \ + abfd->tdata.trad_core_data->u.u_abort diff --git a/contrib/gdb/bfd/hosts/dpx2.h b/contrib/gdb/bfd/hosts/dpx2.h new file mode 100644 index 000000000000..ea6395f2e5d7 --- /dev/null +++ b/contrib/gdb/bfd/hosts/dpx2.h @@ -0,0 +1,8 @@ +/* Definitions that are needed for core files. Core section sizes for + the DPX2 are in bytes. */ + +#include +#define NBPG 1 +#define UPAGES (USIZE * NBPP) +#define HOST_DATA_START_ADDR (u.u_exdata.ux_datorg) +#define HOST_STACK_END_ADDR (USERSTACK) diff --git a/contrib/gdb/bfd/hosts/hp300bsd.h b/contrib/gdb/bfd/hosts/hp300bsd.h new file mode 100644 index 000000000000..982871782073 --- /dev/null +++ b/contrib/gdb/bfd/hosts/hp300bsd.h @@ -0,0 +1,13 @@ +#include +#ifdef BSD4_4 +#define NO_CORE_COMMAND +#endif + +#define HOST_PAGE_SIZE NBPG +#define HOST_SEGMENT_SIZE NBPG /* Data seg start addr rounds to NBPG */ +#define HOST_MACHINE_ARCH bfd_arch_m68k +/* #define HOST_MACHINE_MACHINE */ + +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR 0xfff00000 +#define HOST_BIG_ENDIAN_P diff --git a/contrib/gdb/bfd/hosts/i386bsd.h b/contrib/gdb/bfd/hosts/i386bsd.h new file mode 100644 index 000000000000..ac0d8402edbf --- /dev/null +++ b/contrib/gdb/bfd/hosts/i386bsd.h @@ -0,0 +1,25 @@ +/* Intel 386 running any BSD Unix */ + +#include +#include + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_i386 +#define HOST_TEXT_START_ADDR USRTEXT + +/* Jolitz suggested defining HOST_STACK_END_ADDR to + (u.u_kproc.kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ), which should work on + both BSDI and 386BSD, but that is believed not to work for BSD 4.4. */ + +#ifdef __bsdi__ +/* This seems to be the right thing for BSDI. */ +#define HOST_STACK_END_ADDR USRSTACK +#define HOST_DATA_START_ADDR ((bfd_vma)u.u_kproc.kp_eproc.e_vm.vm_daddr) +#else +/* This seems to be the right thing for 386BSD release 0.1. */ +#define HOST_STACK_END_ADDR (USRSTACK - MAXSSIZ) +#endif + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm diff --git a/contrib/gdb/bfd/hosts/i386linux.h b/contrib/gdb/bfd/hosts/i386linux.h new file mode 100644 index 000000000000..13a51f1bd14c --- /dev/null +++ b/contrib/gdb/bfd/hosts/i386linux.h @@ -0,0 +1,8 @@ +/* Linux writes the task structure at the end of the core file. Currently it + is 2912 bytes. It is possible that this should be a pickier check, but + we should probably not be too picky (the size of the task structure might + vary, and if it's not the length we expect it to be, it doesn't affect + our ability to process the core file). So allow 0-4096 extra bytes at + the end. */ + +#define TRAD_CORE_EXTRA_SIZE_ALLOWED 4096 diff --git a/contrib/gdb/bfd/hosts/i386mach3.h b/contrib/gdb/bfd/hosts/i386mach3.h new file mode 100644 index 000000000000..dcc61e3c8e89 --- /dev/null +++ b/contrib/gdb/bfd/hosts/i386mach3.h @@ -0,0 +1,25 @@ +#include +#include + +/* This is an ugly way to hack around the incorrect + * definition of UPAGES in i386/machparam.h. + * + * The definition should specify the size reserved + * for "struct user" in core files in PAGES, + * but instead it gives it in 512-byte core-clicks + * for i386 and i860. UPAGES is used only in trad-core.c. + */ +#if UPAGES == 16 +#undef UPAGES +#define UPAGES 2 +#endif + +#if UPAGES != 2 +FIXME!! UPAGES is neither 2 nor 16 +#endif + +#define HOST_PAGE_SIZE 1 +#define HOST_SEGMENT_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_i386 +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/i386sco.h b/contrib/gdb/bfd/hosts/i386sco.h new file mode 100644 index 000000000000..ec8608c61dd5 --- /dev/null +++ b/contrib/gdb/bfd/hosts/i386sco.h @@ -0,0 +1,19 @@ +/* Core file stuff. At least some, perhaps all, of the following + defines work on many more systems than just SCO. */ + +#define NBPG NBPC +#define UPAGES USIZE +#define HOST_DATA_START_ADDR u.u_exdata.ux_datorg +#define HOST_STACK_START_ADDR u.u_sub +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(abfd) \ + ((core_upage(abfd)->u_sysabort != 0) \ + ? core_upage(abfd)->u_sysabort \ + : -1) + +/* According to the manpage, a version 2 SCO corefile can contain + various additional sections (it is cleverly arranged so the u area, + data, and stack are first where we can find them). So without + writing lots of code to parse all their headers and stuff, we can't + know whether a corefile is bigger than it should be. */ + +#define TRAD_CORE_ALLOW_ANY_EXTRA_SIZE 1 diff --git a/contrib/gdb/bfd/hosts/i860mach3.h b/contrib/gdb/bfd/hosts/i860mach3.h new file mode 100644 index 000000000000..edd2aa10a7bb --- /dev/null +++ b/contrib/gdb/bfd/hosts/i860mach3.h @@ -0,0 +1,27 @@ +/* This file was hacked from i386mach3.h [dolan@ssd.intel.com] */ + +#include +#include + +/* This is an ugly way to hack around the incorrect + * definition of UPAGES in i386/machparam.h. + * + * The definition should specify the size reserved + * for "struct user" in core files in PAGES, + * but instead it gives it in 512-byte core-clicks + * for i386 and i860. UPAGES is used only in trad-core.c. + */ +#if UPAGES == 16 +#undef UPAGES +#define UPAGES 2 +#endif + +#if UPAGES != 2 +FIXME!! UPAGES is neither 2 nor 16 +#endif + +#define HOST_PAGE_SIZE 1 +#define HOST_SEGMENT_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_i860 +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/m68kaux.h b/contrib/gdb/bfd/hosts/m68kaux.h new file mode 100644 index 000000000000..6237755dba55 --- /dev/null +++ b/contrib/gdb/bfd/hosts/m68kaux.h @@ -0,0 +1,16 @@ +/* Definitions for an Apple Macintosh running A/UX 3.x. */ + +#include +#include + +/* Definitions used by trad-core.c. */ +#define NBPG NBPP + +#define HOST_DATA_START_ADDR u.u_exdata.ux_datorg +#define HOST_TEXT_START_ADDR u.u_exdata.ux_txtorg +#define HOST_STACK_END_ADDR 0x100000000 + +#define UPAGES USIZE + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(abfd) \ + (abfd->tdata.trad_core_data->u.u_arg[0]) diff --git a/contrib/gdb/bfd/hosts/m68klinux.h b/contrib/gdb/bfd/hosts/m68klinux.h new file mode 100644 index 000000000000..0067dfa6fda3 --- /dev/null +++ b/contrib/gdb/bfd/hosts/m68klinux.h @@ -0,0 +1,6 @@ +/* Linux dumps "struct task_struct" at the end of the core-file. This + structure is currently 2512 bytes long, but we allow up to 4096 + bytes to allow for some future growth. */ +#define TRAD_CORE_EXTRA_SIZE_ALLOWED 4096 +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(abfd) \ + ((abfd)->tdata.trad_core_data->u.signal) diff --git a/contrib/gdb/bfd/hosts/m88kmach3.h b/contrib/gdb/bfd/hosts/m88kmach3.h new file mode 100644 index 000000000000..421553893ec9 --- /dev/null +++ b/contrib/gdb/bfd/hosts/m88kmach3.h @@ -0,0 +1,11 @@ +#include +#include + +#undef UPAGES +#define UPAGES 3 + +#define HOST_PAGE_SIZE NBPG +#define HOST_SEGMENT_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_m88k +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/mipsbsd.h b/contrib/gdb/bfd/hosts/mipsbsd.h new file mode 100644 index 000000000000..a2fad21fcf7a --- /dev/null +++ b/contrib/gdb/bfd/hosts/mipsbsd.h @@ -0,0 +1,12 @@ +#include +#include +#undef ALIGN + +#define HOST_PAGE_SIZE NBPG +/* #define HOST_SEGMENT_SIZE NBPG -- we use HOST_DATA_START_ADDR */ +#define HOST_MACHINE_ARCH bfd_arch_mips +/* #define HOST_MACHINE_MACHINE */ + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK +#define NO_CORE_COMMAND diff --git a/contrib/gdb/bfd/hosts/mipsmach3.h b/contrib/gdb/bfd/hosts/mipsmach3.h new file mode 100644 index 000000000000..c5c468d37426 --- /dev/null +++ b/contrib/gdb/bfd/hosts/mipsmach3.h @@ -0,0 +1,10 @@ +#include +#include +#include + +#define HOST_PAGE_SIZE NBPG +/* #define HOST_SEGMENT_SIZE NBPG */ +#define HOST_MACHINE_ARCH bfd_arch_mips +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_DATA_START_ADDR USRDATA +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/news-mips.h b/contrib/gdb/bfd/hosts/news-mips.h new file mode 100644 index 000000000000..9e799bed9047 --- /dev/null +++ b/contrib/gdb/bfd/hosts/news-mips.h @@ -0,0 +1,12 @@ +/* Sony News running NewsOS 3.2. */ + +#include +#include + +#define HOST_PAGE_SIZE NBPG + +#define HOST_MACHINE_ARCH bfd_arch_mips + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_DATA_START_ADDR USRDATA +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/news.h b/contrib/gdb/bfd/hosts/news.h new file mode 100644 index 000000000000..bf7946cdb999 --- /dev/null +++ b/contrib/gdb/bfd/hosts/news.h @@ -0,0 +1,9 @@ +/* Sony News running NewsOS 3.2. */ + +#include + +#define HOST_PAGE_SIZE NBPG +#define HOST_SEGMENT_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_m68k +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR (KERNBASE - (UPAGES * NBPG)) diff --git a/contrib/gdb/bfd/hosts/pc532mach.h b/contrib/gdb/bfd/hosts/pc532mach.h new file mode 100644 index 000000000000..ab96f597edd2 --- /dev/null +++ b/contrib/gdb/bfd/hosts/pc532mach.h @@ -0,0 +1,24 @@ +#include +#include + +/* This is an ugly way to hack around the incorrect + * definition of UPAGES in ns532/machparam.h. + * + * The definition should specify the size reserved + * for "struct user" in core files in PAGES, + * but instead it gives it in 512-byte core-clicks + * for ns532, i386 and i860. UPAGES is used only in trad-core.c. + */ +#if UPAGES == 16 +#undef UPAGES +#define UPAGES 2 +#endif + +#if UPAGES != 2 +#error UPAGES is neither 2 nor 16 +#endif + +#define HOST_PAGE_SIZE 1 +#define HOST_SEGMENT_SIZE NBPG +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK diff --git a/contrib/gdb/bfd/hosts/riscos.h b/contrib/gdb/bfd/hosts/riscos.h new file mode 100644 index 000000000000..8ffa826bdcf5 --- /dev/null +++ b/contrib/gdb/bfd/hosts/riscos.h @@ -0,0 +1,10 @@ +/* RISC/os 4.52C, and presumably other versions. */ + +#include +#include + +#define NBPG BSD43_NBPG +#define UPAGES BSD43_UPAGES +#define HOST_TEXT_START_ADDR BSD43_USRTEXT +#define HOST_DATA_START_ADDR BSD43_USRDATA +#define HOST_STACK_END_ADDR BSD43_USRSTACK diff --git a/contrib/gdb/bfd/hosts/symmetry.h b/contrib/gdb/bfd/hosts/symmetry.h new file mode 100644 index 000000000000..75717b31eb22 --- /dev/null +++ b/contrib/gdb/bfd/hosts/symmetry.h @@ -0,0 +1,20 @@ +/* Symmetry running either dynix 3.1 (bsd) or ptx (sysv). */ + +#define NBPG 4096 +#define UPAGES 1 + +#ifdef _SEQUENT_ +/* ptx */ +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR 0x3fffe000 +#define TRAD_CORE_USER_OFFSET ((UPAGES * NBPG) - sizeof (struct user)) +#else +/* dynix */ +#define HOST_TEXT_START_ADDR 0x1000 +#define HOST_DATA_START_ADDR (NBPG * u.u_tsize) +#define HOST_STACK_END_ADDR 0x3ffff000 +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_arg[0]) +#endif + +#define TRAD_CORE_DSIZE_INCLUDES_TSIZE diff --git a/contrib/gdb/bfd/hosts/tahoe.h b/contrib/gdb/bfd/hosts/tahoe.h new file mode 100644 index 000000000000..716cee2a171d --- /dev/null +++ b/contrib/gdb/bfd/hosts/tahoe.h @@ -0,0 +1,12 @@ +#define NO_CORE_COMMAND + +#undef ALIGN /* They use it, we use it too */ +#include +#undef ALIGN /* They use it, we use it too */ + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_tahoe + +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR (KERNBASE - (UPAGES * NBPG)) +#define HOST_BIG_ENDIAN_P diff --git a/contrib/gdb/bfd/hosts/vaxbsd.h b/contrib/gdb/bfd/hosts/vaxbsd.h new file mode 100644 index 000000000000..ceb9ccedfaf1 --- /dev/null +++ b/contrib/gdb/bfd/hosts/vaxbsd.h @@ -0,0 +1,19 @@ +#define NO_CORE_COMMAND /* No command name in core file */ + +#if 0 +#undef ALIGN /* They use it, we use it too */ +/* Does not exist on BSD 4.3, it uses machine/machparam.h. + Whatever it is, it's included by , which trad-core.c, + the only place that uses this (I think), already includes. */ +#include +#endif +#undef ALIGN /* They use it, we use it too */ + +/* Note that HOST_PAGE_SIZE -- the page size as far as executable files + are concerned -- is not the same as NBPG, because of page clustering. */ +#define HOST_PAGE_SIZE 1024 +#define HOST_MACHINE_ARCH bfd_arch_vax + +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR (0x80000000 - (UPAGES * NBPG)) +#undef HOST_BIG_ENDIAN_P diff --git a/contrib/gdb/bfd/hosts/vaxult.h b/contrib/gdb/bfd/hosts/vaxult.h new file mode 100644 index 000000000000..13731b7479f6 --- /dev/null +++ b/contrib/gdb/bfd/hosts/vaxult.h @@ -0,0 +1,8 @@ +#include +#include +#define HOST_PAGE_SIZE (NBPG*CLSIZE) +#define HOST_MACHINE_ARCH bfd_arch_vax + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK +#undef HOST_BIG_ENDIAN_P diff --git a/contrib/gdb/bfd/hosts/vaxult2.h b/contrib/gdb/bfd/hosts/vaxult2.h new file mode 100644 index 000000000000..13731b7479f6 --- /dev/null +++ b/contrib/gdb/bfd/hosts/vaxult2.h @@ -0,0 +1,8 @@ +#include +#include +#define HOST_PAGE_SIZE (NBPG*CLSIZE) +#define HOST_MACHINE_ARCH bfd_arch_vax + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK +#undef HOST_BIG_ENDIAN_P diff --git a/contrib/gdb/bfd/hp300bsd.c b/contrib/gdb/bfd/hp300bsd.c new file mode 100644 index 000000000000..5767b18c179a --- /dev/null +++ b/contrib/gdb/bfd/hp300bsd.c @@ -0,0 +1,38 @@ +/* BFD back-end for HP 9000/300 (68000-based) machines running BSD Unix. + Copyright 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_IS_BIG_ENDIAN_P +#define N_HEADER_IN_TEXT(x) 0 +#define BYTES_IN_WORD 4 +#define ENTRY_CAN_BE_ZERO +#define N_SHARED_LIB(x) 0 /* Avoids warning */ +#define TEXT_START_ADDR 0 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_m68k + +#define MY(OP) CAT(hp300bsd_,OP) +#define TARGETNAME "a.out-hp300bsd" + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/hp300hpux.c b/contrib/gdb/bfd/hp300hpux.c new file mode 100644 index 000000000000..1d1acab8ae4e --- /dev/null +++ b/contrib/gdb/bfd/hp300hpux.c @@ -0,0 +1,865 @@ +/* BFD backend for hp-ux 9000/300 + Copyright (C) 1990, 1991, 1994, 1995 Free Software Foundation, Inc. + Written by Glenn Engel. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + + hpux native ------------> | | + | hp300hpux bfd | ----------> hpux w/gnu ext + hpux w/gnu extension ----> | | + + + Support for the 9000/[34]00 has several limitations. + 1. Shared libraries are not supported. + 2. The output format from this bfd is not usable by native tools. + + The primary motivation for writing this bfd was to allow use of + gdb and gcc for host based debugging and not to mimic the hp-ux tools + in every detail. This leads to a significant simplification of the + code and a leap in performance. The decision to not output hp native + compatible objects was further strengthened by the fact that the richness + of the gcc compiled objects could not be represented without loss of + information. For example, while the hp format supports the concept of + secondary symbols, it does not support indirect symbols. Another + reason is to maintain backwards compatibility with older implementations + of gcc on hpux which used 'hpxt' to translate .a and .o files into a + format which could be readily understood by the gnu linker and gdb. + This allows reading hp secondary symbols and converting them into + indirect symbols but the reverse it not always possible. + + Another example of differences is that the hp format stores symbol offsets + in the object code while the gnu utilities use a field in the + relocation record for this. To support the hp native format, the object + code would need to be patched with the offsets when producing .o files. + + The basic technique taken in this implementation is to #include the code + from aoutx.h and aout-target.h with appropriate #defines to override + code where a unique implementation is needed: + + { + #define a bunch of stuff + #include + + implement a bunch of functions + + #include "aout-target.h" + } + + The hp symbol table is a bit different than other a.out targets. Instead + of having an array of nlist items and an array of strings, hp's format + has them mixed together in one structure. In addition, the strings are + not null terminated. It looks something like this: + + nlist element 1 + string1 + nlist element 2 + string2 + ... + + The whole symbol table is read as one chunk and then we march thru it + and convert it to canonical form. As we march thru the table, we copy + the nlist data into the internal form and we compact the strings and null + terminate them, using storage from the already allocated symbol table: + + string1 + null + string2 + null + */ + +/* @@ Is this really so different from normal a.out that it needs to include + aoutx.h? We should go through this file sometime and see what can be made + more dependent on aout32.o and what might need to be broken off and accessed + through the backend_data field. Or, maybe we really do need such a + completely separate implementation. I don't have time to investigate this + much further right now. [raeburn:19930428.2124EST] */ +/* @@ Also, note that there wind up being two versions of some routines, with + different names, only one of which actually gets used. For example: + slurp_symbol_table + swap_std_reloc_in + slurp_reloc_table + get_symtab + get_symtab_upper_bound + canonicalize_reloc + mkobject + This should also be fixed. */ + +#define TARGETNAME "a.out-hp300hpux" +#define MY(OP) CAT(hp300hpux_,OP) + +#define external_exec hp300hpux_exec_bytes +#define external_nlist hp300hpux_nlist_bytes + +#include "aout/hp300hpux.h" + +/* define these so we can compile unused routines in aoutx.h */ +#define e_strx e_shlib +#define e_other e_length +#define e_desc e_almod + +#define AR_PAD_CHAR '/' +#define TARGET_IS_BIG_ENDIAN_P +#define DEFAULT_ARCH bfd_arch_m68k + +#define MY_get_section_contents aout_32_get_section_contents +#define MY_slurp_armap bfd_slurp_bsd_armap_f2 + +/***********************************************/ +/* provide overrides for routines in this file */ +/***********************************************/ +/* these don't use MY because that causes problems within JUMP_TABLE + (CAT winds up being expanded recursively, which ANSI C compilers + will not do). */ +#define MY_get_symtab hp300hpux_get_symtab +#define MY_get_symtab_upper_bound hp300hpux_get_symtab_upper_bound +#define MY_canonicalize_reloc hp300hpux_canonicalize_reloc +#define MY_write_object_contents hp300hpux_write_object_contents + +#define MY_read_minisymbols _bfd_generic_read_minisymbols +#define MY_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define MY_final_link_callback unused +#define MY_bfd_final_link _bfd_generic_final_link + +/* Until and unless we convert the slurp_reloc and slurp_symtab + routines in this file, we can not use the default aout + free_cached_info routine which assumes that the relocs and symtabs + were allocated using malloc. */ +#define MY_bfd_free_cached_info bfd_true + +#define hp300hpux_write_syms aout_32_write_syms + +#define MY_callback MY(callback) + +#define MY_exec_hdr_flags 0x2 + +#define NAME_swap_exec_header_in NAME(hp300hpux_32_,swap_exec_header_in) + +#define HP_SYMTYPE_UNDEFINED 0x00 +#define HP_SYMTYPE_ABSOLUTE 0x01 +#define HP_SYMTYPE_TEXT 0x02 +#define HP_SYMTYPE_DATA 0x03 +#define HP_SYMTYPE_BSS 0x04 +#define HP_SYMTYPE_COMMON 0x05 + +#define HP_SYMTYPE_TYPE 0x0F +#define HP_SYMTYPE_FILENAME 0x1F + +#define HP_SYMTYPE_ALIGN 0x10 +#define HP_SYMTYPE_EXTERNAL 0x20 +#define HP_SECONDARY_SYMBOL 0x40 + +/* RELOCATION DEFINITIONS */ +#define HP_RSEGMENT_TEXT 0x00 +#define HP_RSEGMENT_DATA 0x01 +#define HP_RSEGMENT_BSS 0x02 +#define HP_RSEGMENT_EXTERNAL 0x03 +#define HP_RSEGMENT_PCREL 0x04 +#define HP_RSEGMENT_RDLT 0x05 +#define HP_RSEGMENT_RPLT 0x06 +#define HP_RSEGMENT_NOOP 0x3F + +#define HP_RLENGTH_BYTE 0x00 +#define HP_RLENGTH_WORD 0x01 +#define HP_RLENGTH_LONG 0x02 +#define HP_RLENGTH_ALIGN 0x03 + +#define NAME(x,y) CAT3(hp300hpux,_32_,y) +#define ARCH_SIZE 32 + +/* aoutx.h requires definitions for BMAGIC and QMAGIC. */ +#define BMAGIC HPUX_DOT_O_MAGIC +#define QMAGIC 0314 + +#include "aoutx.h" + +/* Since the hpux symbol table has nlist elements interspersed with + strings and we need to insert som strings for secondary symbols, we + give ourselves a little extra padding up front to account for + this. Note that for each non-secondary symbol we process, we gain + 9 bytes of space for the discarded nlist element (one byte used for + null). SYM_EXTRA_BYTES is the extra space. */ +#define SYM_EXTRA_BYTES 1024 + +/* Set parameters about this a.out file that are machine-dependent. + This routine is called from some_aout_object_p just before it returns. */ +static const bfd_target * +MY (callback) (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + + /* Calculate the file positions of the parts of a newly read aout header */ + obj_textsec (abfd)->_raw_size = N_TXTSIZE (*execp); + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR (*execp); + obj_datasec (abfd)->vma = N_DATADDR (*execp); + obj_bsssec (abfd)->vma = N_BSSADDR (*execp); + + obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; + obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; + obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF (*execp); + obj_datasec (abfd)->filepos = N_DATOFF (*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp); + + /* The file offsets of the string table and symbol table. */ + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + obj_str_filepos (abfd) = N_STROFF (*execp); + + /* Determine the architecture and machine type of the object file. */ +#ifdef SET_ARCH_MACH + SET_ARCH_MACH (abfd, *execp); +#else + bfd_default_set_arch_mach (abfd, DEFAULT_ARCH, 0); +#endif + + + if (obj_aout_subformat (abfd) == gnu_encap_format) + { + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_GNU_TRELOFF (*execp); + obj_datasec (abfd)->rel_filepos = N_GNU_DRELOFF (*execp); + + /* The file offsets of the string table and symbol table. */ + obj_sym_filepos (abfd) = N_GNU_SYMOFF (*execp); + obj_str_filepos (abfd) = (obj_sym_filepos (abfd) + execp->a_syms); + + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + bfd_get_symcount (abfd) = execp->a_syms / 12; + obj_symbol_entry_size (abfd) = 12; + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + } + + return abfd->xvec; +} + +extern boolean aout_32_write_syms PARAMS ((bfd * abfd)); + +static boolean +MY (write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + bfd_size_type text_size; /* dummy vars */ + file_ptr text_end; + + memset (&exec_bytes, 0, sizeof (exec_bytes)); +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE (abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + if (adata (abfd).magic == undecided_magic) + NAME (aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); + execp->a_syms = 0; + + execp->a_entry = bfd_get_start_address (abfd); + + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * + obj_reloc_entry_size (abfd)); + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * + obj_reloc_entry_size (abfd)); + + N_SET_MACHTYPE (*execp, 0xc); + N_SET_FLAGS (*execp, aout_backend_info (abfd)->exec_hdr_flags); + + NAME (aout,swap_exec_header_out) (abfd, execp, &exec_bytes); + + /* update fields not covered by default swap_exec_header_out */ + + /* this is really the sym table size but we store it in drelocs */ + bfd_h_put_32 (abfd, bfd_get_symcount (abfd) * 12, exec_bytes.e_drelocs); + + if (bfd_seek (abfd, 0L, false) != 0 + || (bfd_write ((PTR) & exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE)) + return false; + + /* Write out the symbols, and then the relocs. We must write out + the symbols first so that we know the symbol indices. */ + + if (bfd_get_symcount (abfd) != 0) + { + /* Skip the relocs to where we want to put the symbols. */ + if (bfd_seek (abfd, (file_ptr) N_DRELOFF (*execp) + execp->a_drsize, + SEEK_SET) != 0) + return false; + } + + if (!MY (write_syms) (abfd)) + return false; + + if (bfd_get_symcount (abfd) != 0) + { + if (bfd_seek (abfd, (long) (N_TRELOFF (*execp)), false) != 0) + return false; + if (!NAME (aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) + return false; + if (bfd_seek (abfd, (long) (N_DRELOFF (*execp)), false) != 0) + return false; + if (!NAME (aout,squirt_out_relocs) (abfd, obj_datasec (abfd))) + return false; + } + + return true; +} + +/* convert the hp symbol type to be the same as aout64.h usage so we */ +/* can piggyback routines in aoutx.h. */ + +static void +convert_sym_type (sym_pointer, cache_ptr, abfd) + struct external_nlist *sym_pointer; + aout_symbol_type *cache_ptr; + bfd *abfd; +{ + int name_type; + int new_type; + + name_type = (cache_ptr->type); + new_type = 0; + + if ((name_type & HP_SYMTYPE_ALIGN) != 0) + { + /* iou_error ("aligned symbol encountered: %s", name);*/ + name_type = 0; + } + + if (name_type == HP_SYMTYPE_FILENAME) + new_type = N_FN; + else + { + switch (name_type & HP_SYMTYPE_TYPE) + { + case HP_SYMTYPE_UNDEFINED: + new_type = N_UNDF; + break; + + case HP_SYMTYPE_ABSOLUTE: + new_type = N_ABS; + break; + + case HP_SYMTYPE_TEXT: + new_type = N_TEXT; + break; + + case HP_SYMTYPE_DATA: + new_type = N_DATA; + break; + + case HP_SYMTYPE_BSS: + new_type = N_BSS; + break; + + case HP_SYMTYPE_COMMON: + new_type = N_COMM; + break; + + default: + abort (); + break; + } + if (name_type & HP_SYMTYPE_EXTERNAL) + new_type |= N_EXT; + + if (name_type & HP_SECONDARY_SYMBOL) + { + switch (new_type) + { + default: + abort (); + case N_UNDF | N_EXT: + new_type = N_WEAKU; + break; + case N_ABS | N_EXT: + new_type = N_WEAKA; + break; + case N_TEXT | N_EXT: + new_type = N_WEAKT; + break; + case N_DATA | N_EXT: + new_type = N_WEAKD; + break; + case N_BSS | N_EXT: + new_type = N_WEAKB; + break; + } + } + } + cache_ptr->type = new_type; + +} + + +/* +DESCRIPTION + Swaps the information in an executable header taken from a raw + byte stream memory image, into the internal exec_header + structure. +*/ + +void +NAME (aout,swap_exec_header_in) (abfd, raw_bytes, execp) + bfd *abfd; + struct external_exec *raw_bytes; + struct internal_exec *execp; +{ + struct external_exec *bytes = (struct external_exec *) raw_bytes; + + /* The internal_exec structure has some fields that are unused in this + configuration (IE for i960), so ensure that all such uninitialized + fields are zero'd out. There are places where two of these structs + are memcmp'd, and thus the contents do matter. */ + memset (execp, 0, sizeof (struct internal_exec)); + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); + + /***************************************************************/ + /* check the header to see if it was generated by a bfd output */ + /* this is detected rather bizarely by requiring a bunch of */ + /* header fields to be zero and an old unused field (now used) */ + /* to be set. */ + /***************************************************************/ + do + { + long syms; + struct aout_data_struct *rawptr; + if (bfd_h_get_32 (abfd, bytes->e_passize) != 0) + break; + if (bfd_h_get_32 (abfd, bytes->e_syms) != 0) + break; + if (bfd_h_get_32 (abfd, bytes->e_supsize) != 0) + break; + + syms = bfd_h_get_32 (abfd, bytes->e_drelocs); + if (syms == 0) + break; + + /* OK, we've passed the test as best as we can determine */ + execp->a_syms = syms; + + /* allocate storage for where we will store this result */ + rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (*rawptr)); + + if (rawptr == NULL) + return; + abfd->tdata.aout_data = rawptr; + obj_aout_subformat (abfd) = gnu_encap_format; + } + while (0); +} + + +/* The hp symbol table is a bit different than other a.out targets. Instead + of having an array of nlist items and an array of strings, hp's format + has them mixed together in one structure. In addition, the strings are + not null terminated. It looks something like this: + + nlist element 1 + string1 + nlist element 2 + string2 + ... + + The whole symbol table is read as one chunk and then we march thru it + and convert it to canonical form. As we march thru the table, we copy + the nlist data into the internal form and we compact the strings and null + terminate them, using storage from the already allocated symbol table: + + string1 + null + string2 + null + ... +*/ + +boolean +MY (slurp_symbol_table) (abfd) + bfd *abfd; +{ + bfd_size_type symbol_bytes; + struct external_nlist *syms; + struct external_nlist *sym_pointer; + struct external_nlist *sym_end; + char *strings; + aout_symbol_type *cached; + unsigned num_syms = 0; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL) + return true; + symbol_bytes = exec_hdr (abfd)->a_syms; + + strings = (char *) bfd_alloc (abfd, + symbol_bytes + SYM_EXTRA_BYTES); + if (!strings) + return false; + syms = (struct external_nlist *) (strings + SYM_EXTRA_BYTES); + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || bfd_read ((PTR) syms, symbol_bytes, 1, abfd) != symbol_bytes) + { + bfd_release (abfd, syms); + return false; + } + + + sym_end = (struct external_nlist *) (((char *) syms) + symbol_bytes); + + /* first, march thru the table and figure out how many symbols there are */ + for (sym_pointer = syms; sym_pointer < sym_end; sym_pointer++, num_syms++) + { + /* skip over the embedded symbol. */ + sym_pointer = (struct external_nlist *) (((char *) sym_pointer) + + sym_pointer->e_length[0]); + } + + /* now that we know the symbol count, update the bfd header */ + bfd_get_symcount (abfd) = num_syms; + + cached = ((aout_symbol_type *) + bfd_zalloc (abfd, + bfd_get_symcount (abfd) * sizeof (aout_symbol_type))); + if (cached == NULL && bfd_get_symcount (abfd) != 0) + return false; + + /* as we march thru the hp symbol table, convert it into a list of + null terminated strings to hold the symbol names. Make sure any + assignment to the strings pointer is done after we're thru using + the nlist so we don't overwrite anything important. */ + + /* OK, now walk the new symtable, cacheing symbol properties */ + { + aout_symbol_type *cache_ptr = cached; + aout_symbol_type cache_save; + /* Run through table and copy values */ + for (sym_pointer = syms, cache_ptr = cached; + sym_pointer < sym_end; sym_pointer++, cache_ptr++) + { + unsigned int length; + cache_ptr->symbol.the_bfd = abfd; + cache_ptr->symbol.value = GET_SWORD (abfd, sym_pointer->e_value); + cache_ptr->desc = bfd_get_16 (abfd, sym_pointer->e_almod); + cache_ptr->type = bfd_get_8 (abfd, sym_pointer->e_type); + cache_ptr->symbol.udata.p = NULL; + length = bfd_get_8 (abfd, sym_pointer->e_length); + cache_ptr->other = length; /* other not used, save length here */ + + cache_save = *cache_ptr; + convert_sym_type (sym_pointer, cache_ptr, abfd); + if (!translate_from_native_sym_flags (abfd, cache_ptr)) + return false; + + /********************************************************/ + /* for hpux, the 'lenght' value indicates the length of */ + /* the symbol name which follows the nlist entry. */ + /********************************************************/ + if (length) + { + /**************************************************************/ + /* the hp string is not null terminated so we create a new one*/ + /* by copying the string to overlap the just vacated nlist */ + /* structure before it in memory. */ + /**************************************************************/ + cache_ptr->symbol.name = strings; + memcpy (strings, sym_pointer + 1, length); + strings[length] = '\0'; + strings += length + 1; + } + else + cache_ptr->symbol.name = (char *) NULL; + + /* skip over the embedded symbol. */ + sym_pointer = (struct external_nlist *) (((char *) sym_pointer) + + length); + } + } + + obj_aout_symbols (abfd) = cached; + + return true; +} + + + +void +MY (swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct hp300hpux_reloc *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + int r_index; + int r_extern = 0; + unsigned int r_length; + int r_pcrel = 0; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + r_index = bfd_h_get_16 (abfd, bytes->r_index); + + switch (bytes->r_type[0]) + { + case HP_RSEGMENT_TEXT: + r_index = N_TEXT; + break; + case HP_RSEGMENT_DATA: + r_index = N_DATA; + break; + case HP_RSEGMENT_BSS: + r_index = N_BSS; + break; + case HP_RSEGMENT_EXTERNAL: + r_extern = 1; + break; + case HP_RSEGMENT_PCREL: + r_extern = 1; + r_pcrel = 1; + break; + case HP_RSEGMENT_RDLT: + break; + case HP_RSEGMENT_RPLT: + break; + case HP_RSEGMENT_NOOP: + break; + default: + abort (); + break; + } + + switch (bytes->r_length[0]) + { + case HP_RLENGTH_BYTE: + r_length = 0; + break; + case HP_RLENGTH_WORD: + r_length = 1; + break; + case HP_RLENGTH_LONG: + r_length = 2; + break; + default: + abort (); + break; + } + + cache_ptr->howto = howto_table_std + r_length + 4 * r_pcrel; + /* FIXME-soon: Roll baserel, jmptable, relative bits into howto setting */ + + /* This macro uses the r_index value computed above */ + if (r_pcrel && r_extern) + { + /* The GNU linker assumes any offset from beginning of section */ + /* is already incorporated into the image while the HP linker */ + /* adds this in later. Add it in now... */ + MOVE_ADDRESS (-cache_ptr->address); + } + else + { + MOVE_ADDRESS (0); + } +} + +boolean +MY (slurp_reloc_table) (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + unsigned int count; + bfd_size_type reloc_size; + PTR relocs; + arelent *reloc_cache; + size_t each_size; + struct hp300hpux_reloc *rptr; + unsigned int counter; + arelent *cache_ptr; + + if (asect->relocation) + return true; + + if (asect->flags & SEC_CONSTRUCTOR) + return true; + + if (asect == obj_datasec (abfd)) + { + reloc_size = exec_hdr (abfd)->a_drsize; + goto doit; + } + + if (asect == obj_textsec (abfd)) + { + reloc_size = exec_hdr (abfd)->a_trsize; + goto doit; + } + + bfd_set_error (bfd_error_invalid_operation); + return false; + +doit: + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) + return false; + each_size = obj_reloc_entry_size (abfd); + + count = reloc_size / each_size; + + + reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t) (count * sizeof + (arelent))); + if (!reloc_cache && count != 0) + return false; + + relocs = (PTR) bfd_alloc (abfd, reloc_size); + if (!relocs && reloc_size != 0) + { + bfd_release (abfd, reloc_cache); + return false; + } + + if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) + { + bfd_release (abfd, relocs); + bfd_release (abfd, reloc_cache); + return false; + } + + rptr = (struct hp300hpux_reloc *) relocs; + counter = 0; + cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) + { + MY (swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols, + bfd_get_symcount (abfd)); + } + + + bfd_release (abfd, relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + + +/************************************************************************/ +/* The following functions are identical to functions in aoutx.h except */ +/* they refer to MY(func) rather than NAME(aout,func) and they also */ +/* call aout_32 versions if the input file was generated by gcc */ +/************************************************************************/ + +long aout_32_get_symtab PARAMS ((bfd * abfd, asymbol ** location)); +long aout_32_get_symtab_upper_bound PARAMS ((bfd * abfd)); + +long aout_32_canonicalize_reloc PARAMS ((bfd * abfd, sec_ptr section, + arelent ** relptr, + asymbol ** symbols)); + +long +MY (get_symtab) (abfd, location) + bfd *abfd; + asymbol **location; +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (obj_aout_subformat (abfd) == gnu_encap_format) + return aout_32_get_symtab (abfd, location); + + if (!MY (slurp_symbol_table) (abfd)) + return -1; + + for (symbase = obj_aout_symbols (abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *) (symbase++); + *location++ = 0; + return bfd_get_symcount (abfd); +} + +long +MY (get_symtab_upper_bound) (abfd) + bfd *abfd; +{ + if (obj_aout_subformat (abfd) == gnu_encap_format) + return aout_32_get_symtab_upper_bound (abfd); + if (!MY (slurp_symbol_table) (abfd)) + return -1; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (aout_symbol_type *)); +} + + + + +long +MY (canonicalize_reloc) (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count; + if (obj_aout_subformat (abfd) == gnu_encap_format) + return aout_32_canonicalize_reloc (abfd, section, relptr, symbols); + + if (!(tblptr || MY (slurp_reloc_table) (abfd, section, symbols))) + return -1; + + if (section->flags & SEC_CONSTRUCTOR) + { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = &chain->relent; + chain = chain->next; + } + } + else + { + tblptr = section->relocation; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/hppa_stubs.h b/contrib/gdb/bfd/hppa_stubs.h new file mode 100644 index 000000000000..ee893e8a57bb --- /dev/null +++ b/contrib/gdb/bfd/hppa_stubs.h @@ -0,0 +1,23 @@ +/* HPPA linker stub instructions */ + +/* These are the instructions which the linker may insert into the + code stream when building final executables to handle out-of-range + calls and argument relocations. */ + +#define LDO_M4_R31_R31 0x37ff3ff9 /* ldo -4(%r31),%r31 */ +#define LDIL_R1 0x20200000 /* ldil XXX,%r1 */ +#define BE_SR4_R1 0xe0202000 /* be XXX(%sr4,%r1) */ +#define COPY_R31_R2 0x081f0242 /* copy %r31,%r2 */ +#define BLE_SR4_R0 0xe4002000 /* ble XXX(%sr4,%r0) */ +#define BLE_SR4_R1 0xe4202000 /* ble XXX(%sr4,%r1) */ +#define BV_N_0_R31 0xebe0c002 /* bv,n 0(%r31) */ +#define STW_R31_M8R30 0x6bdf3ff1 /* stw %r31,-8(%r30) */ +#define LDW_M8R30_R31 0x4bdf3ff1 /* ldw -8(%r30),%r31 */ +#define STW_ARG_M16R30 0x6bc03fe1 /* stw %argX,-16(%r30) */ +#define LDW_M16R30_ARG 0x4bc03fe1 /* ldw -12(%r30),%argX */ +#define STW_ARG_M12R30 0x6bc03fe9 /* stw %argX,-16(%r30) */ +#define LDW_M12R30_ARG 0x4bc03fe9 /* ldw -12(%r30),%argX */ +#define FSTW_FARG_M16R30 0x27c11200 /* fstws %fargX,-16(%r30) */ +#define FLDW_M16R30_FARG 0x27c11000 /* fldws -16(%r30),%fargX */ +#define FSTD_FARG_M16R30 0x2fc11200 /* fstds %fargX,-16(%r30) */ +#define FLDD_M16R30_FARG 0x2fc11000 /* fldds -16(%r30),%fargX */ diff --git a/contrib/gdb/bfd/hppabsd-core.c b/contrib/gdb/bfd/hppabsd-core.c new file mode 100644 index 000000000000..a76ecc5aad15 --- /dev/null +++ b/contrib/gdb/bfd/hppabsd-core.c @@ -0,0 +1,305 @@ +/* BFD back-end for HPPA BSD core files. + Copyright 1993, 1994 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by the Center for Software Science at the University of Utah + and by Cygnus Support. + + The core file structure for the Utah 4.3BSD and OSF1 ports on the + PA is a mix between traditional cores and hpux cores -- just + different enough that supporting this format would tend to add + gross hacks to trad-core.c or hpux-core.c. So instead we keep any + gross hacks isolated to this file. */ + + +/* This file can only be compiled on systems which use HPPA-BSD style + core files. + + I would not expect this to be of use to any other host/target, but + you never know. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#if defined (HOST_HPPABSD) + +#include "machine/vmparam.h" + +#include +#include +#include +#include +#include +#include +#include /* After a.out.h */ +#include +#include + +static asection *make_bfd_asection PARAMS ((bfd *, CONST char *, + flagword, bfd_size_type, + file_ptr, unsigned int)); +static asymbol *hppabsd_core_make_empty_symbol PARAMS ((bfd *)); +static const bfd_target *hppabsd_core_core_file_p PARAMS ((bfd *)); +static char *hppabsd_core_core_file_failing_command PARAMS ((bfd *)); +static int hppabsd_core_core_file_failing_signal PARAMS ((bfd *)); +static boolean hppabsd_core_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); +static void swap_abort PARAMS ((void)); + +/* These are stored in the bfd's tdata. */ + +struct hppabsd_core_struct + { + int sig; + char cmd[MAXCOMLEN + 1]; + asection *data_section; + asection *stack_section; + asection *reg_section; + }; + +#define core_hdr(bfd) ((bfd)->tdata.hppabsd_core_data) +#define core_signal(bfd) (core_hdr(bfd)->sig) +#define core_command(bfd) (core_hdr(bfd)->cmd) +#define core_datasec(bfd) (core_hdr(bfd)->data_section) +#define core_stacksec(bfd) (core_hdr(bfd)->stack_section) +#define core_regsec(bfd) (core_hdr(bfd)->reg_section) + +static asection * +make_bfd_asection (abfd, name, flags, _raw_size, offset, alignment_power) + bfd *abfd; + CONST char *name; + flagword flags; + bfd_size_type _raw_size; + file_ptr offset; + unsigned int alignment_power; +{ + asection *asect; + + asect = bfd_make_section (abfd, name); + if (!asect) + return NULL; + + asect->flags = flags; + asect->_raw_size = _raw_size; + asect->filepos = offset; + asect->alignment_power = alignment_power; + + return asect; +} + +static asymbol * +hppabsd_core_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +static const bfd_target * +hppabsd_core_core_file_p (abfd) + bfd *abfd; +{ + int val; + struct user u; + struct hppabsd_core_struct *coredata; + int clicksz; + + /* Try to read in the u-area. We will need information from this + to know how to grok the rest of the core structures. */ + val = bfd_read ((void *) &u, 1, sizeof u, abfd); + if (val != sizeof u) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Get the page size out of the u structure. This will be different + for PA 1.0 machines and PA 1.1 machines. Yuk! */ + clicksz = u.u_pcb.pcb_pgsz; + + /* clicksz must be a power of two >= 2k. */ + if (clicksz < 0x800 + || clicksz != (clicksz & -clicksz)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + + /* Sanity checks. Make sure the size of the core file matches the + the size computed from information within the core itself. */ + { + FILE *stream = bfd_cache_lookup (abfd); + struct stat statbuf; + if (stream == NULL || fstat (fileno (stream), &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) > statbuf.st_size) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + if (clicksz * (UPAGES + u.u_dsize + u.u_ssize) < statbuf.st_size) + { + /* The file is too big. Maybe it's not a core file + or we otherwise have bad values for u_dsize and u_ssize). */ + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + coredata = (struct hppabsd_core_struct *) + bfd_zalloc (abfd, sizeof (struct hppabsd_core_struct)); + if (!coredata) + return NULL; + + /* Make the core data and available via the tdata part of the BFD. */ + abfd->tdata.hppabsd_core_data = coredata; + + /* Create the sections. */ + core_stacksec (abfd) = make_bfd_asection (abfd, ".stack", + SEC_ALLOC + SEC_HAS_CONTENTS, + clicksz * u.u_ssize, + NBPG * (USIZE + KSTAKSIZE) + + clicksz * u.u_dsize, 2); + core_stacksec (abfd)->vma = USRSTACK; + + core_datasec (abfd) = make_bfd_asection (abfd, ".data", + SEC_ALLOC + SEC_LOAD + + SEC_HAS_CONTENTS, + clicksz * u.u_dsize, + NBPG * (USIZE + KSTAKSIZE), 2); + core_datasec (abfd)->vma = UDATASEG; + + core_regsec (abfd) = make_bfd_asection (abfd, ".reg", + SEC_HAS_CONTENTS, + KSTAKSIZE * NBPG, + NBPG * USIZE, 2); + core_regsec (abfd)->vma = 0; + + strncpy (core_command (abfd), u.u_comm, MAXCOMLEN + 1); + core_signal (abfd) = u.u_code; + return abfd->xvec; +} + +static char * +hppabsd_core_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_command (abfd); +} + +/* ARGSUSED */ +static int +hppabsd_core_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_signal (abfd); +} + +/* ARGSUSED */ +static boolean +hppabsd_core_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + /* There's no way to know this... */ + return true; +} + + +#define hppabsd_core_get_symtab_upper_bound \ + _bfd_nosymbols_get_symtab_upper_bound +#define hppabsd_core_get_symtab _bfd_nosymbols_get_symtab +#define hppabsd_core_print_symbol _bfd_nosymbols_print_symbol +#define hppabsd_core_get_symbol_info _bfd_nosymbols_get_symbol_info +#define hppabsd_core_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define hppabsd_core_get_lineno _bfd_nosymbols_get_lineno +#define hppabsd_core_find_nearest_line _bfd_nosymbols_find_nearest_line +#define hppabsd_core_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define hppabsd_core_read_minisymbols _bfd_nosymbols_read_minisymbols +#define hppabsd_core_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +/* If somebody calls any byte-swapping routines, shoot them. */ +static void +swap_abort () +{ + /* This way doesn't require any declaration for ANSI to fuck up. */ + abort (); +} + +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target hppabsd_core_vec = + { + "hppabsd-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + hppabsd_core_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (hppabsd_core), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (hppabsd_core), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; +#endif diff --git a/contrib/gdb/bfd/hpux-core.c b/contrib/gdb/bfd/hpux-core.c new file mode 100644 index 000000000000..675a5f8d0bd2 --- /dev/null +++ b/contrib/gdb/bfd/hpux-core.c @@ -0,0 +1,270 @@ +/* BFD back-end for HP/UX core files. + Copyright 1993, 1994 Free Software Foundation, Inc. + Written by Stu Grossman, Cygnus Support. + Converted to back-end form by Ian Lance Taylor, Cygnus SUpport + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file can only be compiled on systems which use HP/UX style + core files. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#if defined (HOST_HPPAHPUX) || defined (HOST_HP300HPUX) + +/* FIXME: sys/core.h doesn't exist for HPUX version 7. HPUX version + 5, 6, and 7 core files seem to be standard trad-core.c type core + files; can we just use trad-core.c in addition to this file? */ + +#include +#include + +#endif /* HOST_HPPAHPUX */ + +#ifdef HOST_HPPABSD + +/* Not a very swift place to put it, but that's where the BSD port + puts them. */ +#include "/hpux/usr/include/sys/core.h" + +#endif /* HOST_HPPABSD */ + +#include +#include +#include +#include +#include +#include +#include /* After a.out.h */ +#include +#include + +/* These are stored in the bfd's tdata */ + +struct hpux_core_struct +{ + int sig; + char cmd[MAXCOMLEN + 1]; +}; + +#define core_hdr(bfd) ((bfd)->tdata.hpux_core_data) +#define core_signal(bfd) (core_hdr(bfd)->sig) +#define core_command(bfd) (core_hdr(bfd)->cmd) + +static asection * +make_bfd_asection (abfd, name, flags, _raw_size, vma, alignment_power) + bfd *abfd; + CONST char *name; + flagword flags; + bfd_size_type _raw_size; + bfd_vma vma; + unsigned int alignment_power; +{ + asection *asect; + + asect = bfd_make_section_anyway (abfd, name); + if (!asect) + return NULL; + + asect->flags = flags; + asect->_raw_size = _raw_size; + asect->vma = vma; + asect->filepos = bfd_tell (abfd); + asect->alignment_power = alignment_power; + + return asect; +} + +static asymbol * +hpux_core_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +static const bfd_target * +hpux_core_core_file_p (abfd) + bfd *abfd; +{ + core_hdr (abfd) = (struct hpux_core_struct *) + bfd_zalloc (abfd, sizeof (struct hpux_core_struct)); + if (!core_hdr (abfd)) + return NULL; + + while (1) + { + int val; + struct corehead core_header; + + val = bfd_read ((void *) &core_header, 1, sizeof core_header, abfd); + if (val <= 0) + break; + switch (core_header.type) + { + case CORE_KERNEL: + case CORE_FORMAT: + bfd_seek (abfd, core_header.len, SEEK_CUR); /* Just skip this */ + break; + case CORE_EXEC: + { + struct proc_exec proc_exec; + if (bfd_read ((void *) &proc_exec, 1, core_header.len, abfd) + != core_header.len) + break; + strncpy (core_command (abfd), proc_exec.cmd, MAXCOMLEN + 1); + } + break; + case CORE_PROC: + { + struct proc_info proc_info; + if (!make_bfd_asection (abfd, ".reg", + SEC_HAS_CONTENTS, + core_header.len, + (int) &proc_info - (int) & proc_info.hw_regs, + 2)) + return NULL; + + if (bfd_read (&proc_info, 1, core_header.len, abfd) + != core_header.len) + break; + core_signal (abfd) = proc_info.sig; + } + break; + + case CORE_DATA: + case CORE_STACK: + case CORE_TEXT: + case CORE_MMF: + case CORE_SHM: + if (!make_bfd_asection (abfd, ".data", + SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS, + core_header.len, core_header.addr, 2)) + return NULL; + + bfd_seek (abfd, core_header.len, SEEK_CUR); + break; + + default: + /* Falling into here is an error and should prevent this + target from matching. That way systems which use hpux + cores along with other formats can still work. */ + return 0; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + return abfd->xvec; +} + +static char * +hpux_core_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_command (abfd); +} + +/* ARGSUSED */ +static int +hpux_core_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_signal (abfd); +} + +/* ARGSUSED */ +static boolean +hpux_core_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +#define hpux_core_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound +#define hpux_core_get_symtab _bfd_nosymbols_get_symtab +#define hpux_core_print_symbol _bfd_nosymbols_print_symbol +#define hpux_core_get_symbol_info _bfd_nosymbols_get_symbol_info +#define hpux_core_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define hpux_core_get_lineno _bfd_nosymbols_get_lineno +#define hpux_core_find_nearest_line _bfd_nosymbols_find_nearest_line +#define hpux_core_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define hpux_core_read_minisymbols _bfd_nosymbols_read_minisymbols +#define hpux_core_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target hpux_core_vec = + { + "hpux-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + hpux_core_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (hpux_core), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (hpux_core), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; diff --git a/contrib/gdb/bfd/i386aout.c b/contrib/gdb/bfd/i386aout.c new file mode 100644 index 000000000000..0801832d16d7 --- /dev/null +++ b/contrib/gdb/bfd/i386aout.c @@ -0,0 +1,68 @@ +/* BFD back-end for i386 a.out binaries. + Copyright 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* The only 386 aout system we have here is GO32 from DJ. + These numbers make BFD work with that. If your aout 386 system + doesn't work with these, we'll have to split them into different + files. Send me (sac@cygnus.com) the runes to make it work on your + system, and I'll stick it in for the next release. */ + +#define N_HEADER_IN_TEXT(x) 0 +#define BYTES_IN_WORD 4 + +#define N_TXTOFF(x) 0x20 +#define N_TXTADDR(x) (N_MAGIC(x)==ZMAGIC ? 0x1020 : 0) + +#define N_TXTSIZE(x) ((x).a_text) +#if 0 +#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) : (SEGMENT_SIZE + ((0x1020+(x).a_text-1) & ~(SEGMENT_SIZE-1)))) +#define NOSUBEXECB + +#endif +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE 0x400000 +#define DEFAULT_ARCH bfd_arch_i386 + +#define MY(OP) CAT(i386aout_,OP) +#define TARGETNAME "a.out-i386" +#define NO_WRITE_HEADER_KLUDGE 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" +static boolean MY(set_sizes)(); +#define MY_backend_data &MY(backend_data) +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 1, /* text incl header */ + 0, /* exec_hdr_flags */ + 0, /* text vma? */ + MY(set_sizes), + 1, /* exec header not counted */ + 0, /* add_dynamic_symbols */ + 0, /* add_one_symbol */ + 0, /* link_dynamic_object */ + 0, /* write_dynamic_symbol */ + 0, /* check_dynamic_reloc */ + 0 /* finish_dynamic_link */ +}; + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386bsd.c b/contrib/gdb/bfd/i386bsd.c new file mode 100644 index 000000000000..2328fe3e9e8c --- /dev/null +++ b/contrib/gdb/bfd/i386bsd.c @@ -0,0 +1,46 @@ +/* BFD back-end for i386 a.out binaries under BSD. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This data should be correct for the format used under all the various + BSD ports for 386 machines. */ + +#define BYTES_IN_WORD 4 + +/* ZMAGIC files never have the header in the text. */ +#define N_HEADER_IN_TEXT(x) 0 + +/* ZMAGIC files start at address 0. This does not apply to QMAGIC. */ +#define TEXT_START_ADDR 0 +#define N_SHARED_LIB(x) 0 + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(i386bsd_,OP) +#define TARGETNAME "a.out-i386-bsd" + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386dynix.c b/contrib/gdb/bfd/i386dynix.c new file mode 100644 index 000000000000..ff50a1450a1c --- /dev/null +++ b/contrib/gdb/bfd/i386dynix.c @@ -0,0 +1,80 @@ +/* BFD back-end for i386 a.out binaries under dynix. + Copyright (C) 1994, 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This BFD is currently only tested with gdb, writing object files + may not work. */ + +#define BYTES_IN_WORD 4 + +#define TEXT_START_ADDR 4096 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE + +#include "aout/dynix3.h" + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(i386dynix_,OP) +#define TARGETNAME "a.out-i386-dynix" +#define NAME(x,y) CAT3(i386dynix,_32_,y) +#define ARCH_SIZE 32 +#define NAME_swap_exec_header_in NAME(i386dynix_32_,swap_exec_header_in) +#define MY_get_section_contents aout_32_get_section_contents + +/* aoutx.h requires definitions for NMAGIC, BMAGIC and QMAGIC. */ +#define NMAGIC 0 +#define BMAGIC OMAGIC +#define QMAGIC XMAGIC + +#include "aoutx.h" + +/* (Ab)use some fields in the internal exec header to be able to read + executables that contain shared data. */ + +#define a_shdata a_tload +#define a_shdrsize a_dload + +void +i386dynix_32_swap_exec_header_in (abfd, raw_bytes, execp) + bfd *abfd; + struct external_exec *raw_bytes; + struct internal_exec *execp; +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* The internal_exec structure has some fields that are unused in this + configuration (IE for i960), so ensure that all such uninitialized + fields are zero'd out. There are places where two of these structs + are memcmp'd, and thus the contents do matter. */ + memset ((PTR) execp, 0, sizeof (struct internal_exec)); + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); + execp->a_shdata = GET_WORD (abfd, bytes->e_shdata); + execp->a_shdrsize = GET_WORD (abfd, bytes->e_shdrsize); +} + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386freebsd.c b/contrib/gdb/bfd/i386freebsd.c new file mode 100644 index 000000000000..7a6371b5df69 --- /dev/null +++ b/contrib/gdb/bfd/i386freebsd.c @@ -0,0 +1,33 @@ +/* BFD back-end for FreeBSD/386 a.out-ish binaries. + Copyright (C) 1990, 1991, 1992, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#undef TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(i386freebsd_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-i386-freebsd" + +#include "freebsd.h" diff --git a/contrib/gdb/bfd/i386linux.c b/contrib/gdb/bfd/i386linux.c new file mode 100644 index 000000000000..a45f97c42f80 --- /dev/null +++ b/contrib/gdb/bfd/i386linux.c @@ -0,0 +1,762 @@ +/* BFD back-end for linux flavored i386 a.out binaries. + Copyright (C) 1992, 93, 94, 95, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_PAGE_SIZE 4096 +#define ZMAGIC_DISK_BLOCK_SIZE 1024 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define TEXT_START_ADDR 0x0 +#define N_SHARED_LIB(x) 0 +#define BYTES_IN_WORD 4 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#define DEFAULT_ARCH bfd_arch_i386 +#define MY(OP) CAT(i386linux_,OP) +#define TARGETNAME "a.out-i386-linux" + +extern const bfd_target MY(vec); + +/* We always generate QMAGIC files in preference to ZMAGIC files. It + would be possible to make this a linker option, if that ever + becomes important. */ + +static void MY_final_link_callback + PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); + +static boolean +i386linux_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + obj_aout_subformat (abfd) = q_magic_format; + return NAME(aout,final_link) (abfd, info, MY_final_link_callback); +} + +#define MY_bfd_final_link i386linux_bfd_final_link + +/* Set the machine type correctly. */ + +static boolean +i386linux_write_object_contents (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + + N_SET_MACHTYPE (*execp, M_386); + + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + WRITE_HEADERS(abfd, execp); + + return true; +} + +#define MY_write_object_contents i386linux_write_object_contents + +/* Code to link against Linux a.out shared libraries. */ + +/* See if a symbol name is a reference to the global offset table. */ + +#ifndef GOT_REF_PREFIX +#define GOT_REF_PREFIX "__GOT_" +#endif + +#define IS_GOT_SYM(name) \ + (strncmp (name, GOT_REF_PREFIX, sizeof GOT_REF_PREFIX - 1) == 0) + +/* See if a symbol name is a reference to the procedure linkage table. */ + +#ifndef PLT_REF_PREFIX +#define PLT_REF_PREFIX "__PLT_" +#endif + +#define IS_PLT_SYM(name) \ + (strncmp (name, PLT_REF_PREFIX, sizeof PLT_REF_PREFIX - 1) == 0) + +/* This string is used to generate specialized error messages. */ + +#ifndef NEEDS_SHRLIB +#define NEEDS_SHRLIB "__NEEDS_SHRLIB_" +#endif + +/* This special symbol is a set vector that contains a list of + pointers to fixup tables. It will be present in any dynamicly + linked file. The linker generated fixup table should also be added + to the list, and it should always appear in the second slot (the + first one is a dummy with a magic number that is defined in + crt0.o). */ + +#ifndef SHARABLE_CONFLICTS +#define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__" +#endif + +/* We keep a list of fixups. The terminology is a bit strange, but + each fixup contains two 32 bit numbers. A regular fixup contains + an address and a pointer, and at runtime we should store the + address at the location pointed to by the pointer. A builtin fixup + contains two pointers, and we should read the address using one + pointer and store it at the location pointed to by the other + pointer. Builtin fixups come into play when we have duplicate + __GOT__ symbols for the same variable. The builtin fixup will copy + the GOT pointer from one over into the other. */ + +struct fixup +{ + struct fixup *next; + struct linux_link_hash_entry *h; + bfd_vma value; + + /* Nonzero if this is a jump instruction that needs to be fixed, + zero if this is just a pointer */ + char jump; + + char builtin; +}; + +/* We don't need a special hash table entry structure, but we do need + to keep some information between linker passes, so we use a special + hash table. */ + +struct linux_link_hash_entry +{ + struct aout_link_hash_entry root; +}; + +struct linux_link_hash_table +{ + struct aout_link_hash_table root; + + /* First dynamic object found in link. */ + bfd *dynobj; + + /* Number of fixups. */ + size_t fixup_count; + + /* Number of builtin fixups. */ + size_t local_builtins; + + /* List of fixups. */ + struct fixup *fixup_list; +}; + +static struct bfd_hash_entry *linux_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table *linux_link_hash_table_create + PARAMS ((bfd *)); +static struct fixup *new_fixup + PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *, + bfd_vma, int)); +static boolean linux_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean linux_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, + bfd_vma, const char *, boolean, boolean, + struct bfd_link_hash_entry **)); +static boolean linux_tally_symbols + PARAMS ((struct linux_link_hash_entry *, PTR)); +static boolean linux_finish_dynamic_link + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Routine to create an entry in an Linux link hash table. */ + +static struct bfd_hash_entry * +linux_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct linux_link_hash_entry *) NULL) + ret = ((struct linux_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); + if (ret == NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct linux_link_hash_entry *) + NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != NULL) + { + /* Set local fields; there aren't any. */ + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a Linux link hash table. */ + +static struct bfd_link_hash_table * +linux_link_hash_table_create (abfd) + bfd *abfd; +{ + struct linux_link_hash_table *ret; + + ret = ((struct linux_link_hash_table *) + bfd_alloc (abfd, sizeof (struct linux_link_hash_table))); + if (ret == (struct linux_link_hash_table *) NULL) + return (struct bfd_link_hash_table *) NULL; + if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, + linux_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + + ret->dynobj = NULL; + ret->fixup_count = 0; + ret->local_builtins = 0; + ret->fixup_list = NULL; + + return &ret->root.root; +} + +/* Look up an entry in a Linux link hash table. */ + +#define linux_link_hash_lookup(table, string, create, copy, follow) \ + ((struct linux_link_hash_entry *) \ + aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ + (follow))) + +/* Traverse a Linux link hash table. */ + +#define linux_link_hash_traverse(table, func, info) \ + (aout_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the Linux link hash table from the info structure. This is + just a cast. */ + +#define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash)) + +/* Store the information for a new fixup. */ + +static struct fixup * +new_fixup (info, h, value, builtin) + struct bfd_link_info *info; + struct linux_link_hash_entry *h; + bfd_vma value; + int builtin; +{ + struct fixup *f; + + f = (struct fixup *) bfd_hash_allocate (&info->hash->table, + sizeof (struct fixup)); + if (f == NULL) + return f; + f->next = linux_hash_table (info)->fixup_list; + linux_hash_table (info)->fixup_list = f; + f->h = h; + f->value = value; + f->builtin = builtin; + f->jump = 0; + ++linux_hash_table (info)->fixup_count; + return f; +} + +/* We come here once we realize that we are going to link to a shared + library. We need to create a special section that contains the + fixup table, and we ultimately need to add a pointer to this into + the set vector for SHARABLE_CONFLICTS. At this point we do not + know the size of the section, but that's OK - we just need to + create it for now. */ + +static boolean +linux_link_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + + /* Note that we set the SEC_IN_MEMORY flag. */ + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + /* We choose to use the name ".linux-dynamic" for the fixup table. + Why not? */ + s = bfd_make_section (abfd, ".linux-dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + s->_raw_size = 0; + s->contents = 0; + + return true; +} + +/* Function to add a single symbol to the linker hash table. This is + a wrapper around _bfd_generic_link_add_one_symbol which handles the + tweaking needed for dynamic linking support. */ + +static boolean +linux_add_one_symbol (info, abfd, name, flags, section, value, string, + copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + struct linux_link_hash_entry *h; + boolean insert; + + /* Look up and see if we already have this symbol in the hash table. + If we do, and the defining entry is from a shared library, we + need to create the dynamic sections. + + FIXME: What if abfd->xvec != info->hash->creator? We may want to + be able to link Linux a.out and ELF objects together, but serious + confusion is possible. */ + + insert = false; + + if (! info->relocateable + && linux_hash_table (info)->dynobj == NULL + && strcmp (name, SHARABLE_CONFLICTS) == 0 + && (flags & BSF_CONSTRUCTOR) != 0 + && abfd->xvec == info->hash->creator) + { + if (! linux_link_create_dynamic_sections (abfd, info)) + return false; + linux_hash_table (info)->dynobj = abfd; + insert = true; + } + + if (bfd_is_abs_section (section) + && abfd->xvec == info->hash->creator) + { + h = linux_link_hash_lookup (linux_hash_table (info), name, false, + false, false); + if (h != NULL + && (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak)) + { + struct fixup *f; + + if (hashp != NULL) + *hashp = (struct bfd_link_hash_entry *) h; + + f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); + if (f == NULL) + return false; + f->jump = IS_PLT_SYM (name); + + return true; + } + } + + /* Do the usual procedure for adding a symbol. */ + if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, + value, string, copy, collect, + hashp)) + return false; + + /* Insert a pointer to our table in the set vector. The dynamic + linker requires this information */ + if (insert) + { + asection *s; + + /* Here we do our special thing to add the pointer to the + dynamic section in the SHARABLE_CONFLICTS set vector. */ + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + BFD_ASSERT (s != NULL); + + if (! (_bfd_generic_link_add_one_symbol + (info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS, + BSF_GLOBAL | BSF_CONSTRUCTOR, s, 0, NULL, false, false, NULL))) + return false; + } + + return true; +} + +/* We will crawl the hash table and come here for every global symbol. + We will examine each entry and see if there are indications that we + need to add a fixup. There are two possible cases - one is where + you have duplicate definitions of PLT or GOT symbols - these will + have already been caught and added as "builtin" fixups. If we find + that the corresponding non PLT/GOT symbol is also present, we + convert it to a regular fixup instead. + + This function is called via linux_link_hash_traverse. */ + +static boolean +linux_tally_symbols (h, data) + struct linux_link_hash_entry *h; + PTR data; +{ + struct bfd_link_info *info = (struct bfd_link_info *) data; + struct fixup *f, *f1; + int is_plt; + struct linux_link_hash_entry *h1, *h2; + boolean exists; + + if (h->root.root.type == bfd_link_hash_undefined + && strncmp (h->root.root.root.string, NEEDS_SHRLIB, + sizeof NEEDS_SHRLIB - 1) == 0) + { + const char *name; + char *p; + char *alloc = NULL; + + name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1; + p = strrchr (name, '_'); + if (p != NULL) + alloc = (char *) bfd_malloc (strlen (name) + 1); + + if (p == NULL || alloc == NULL) + (*_bfd_error_handler) ("Output file requires shared library `%s'\n", + name); + else + { + strcpy (alloc, name); + p = strrchr (alloc, '_'); + *p++ = '\0'; + (*_bfd_error_handler) + ("Output file requires shared library `%s.so.%s'\n", + alloc, p); + free (alloc); + } + + abort (); + } + + /* If this symbol is not a PLT/GOT, we do not even need to look at it */ + is_plt = IS_PLT_SYM (h->root.root.root.string); + + if (is_plt || IS_GOT_SYM (h->root.root.root.string)) + { + /* Look up this symbol twice. Once just as a regular lookup, + and then again following all of the indirect links until we + reach a real symbol. */ + h1 = linux_link_hash_lookup (linux_hash_table (info), + (h->root.root.root.string + + sizeof PLT_REF_PREFIX - 1), + false, false, true); + /* h2 does not follow indirect symbols. */ + h2 = linux_link_hash_lookup (linux_hash_table (info), + (h->root.root.root.string + + sizeof PLT_REF_PREFIX - 1), + false, false, false); + + /* The real symbol must exist but if it is also an ABS symbol, + there is no need to have a fixup. This is because they both + came from the same library. If on the other hand, we had to + use an indirect symbol to get to the real symbol, we add the + fixup anyway, since there are cases where these symbols come + from different shared libraries */ + if (h1 != NULL + && (((h1->root.root.type == bfd_link_hash_defined + || h1->root.root.type == bfd_link_hash_defweak) + && ! bfd_is_abs_section (h1->root.root.u.def.section)) + || h2->root.root.type == bfd_link_hash_indirect)) + { + /* See if there is a "builtin" fixup already present + involving this symbol. If so, convert it to a regular + fixup. In the end, this relaxes some of the requirements + about the order of performing fixups. */ + exists = false; + for (f1 = linux_hash_table (info)->fixup_list; + f1 != NULL; + f1 = f1->next) + { + if ((f1->h != h && f1->h != h1) + || (! f1->builtin && ! f1->jump)) + continue; + if (f1->h == h1) + exists = true; + if (! exists + && bfd_is_abs_section (h->root.root.u.def.section)) + { + f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); + f->jump = is_plt; + } + f1->h = h1; + f1->jump = is_plt; + f1->builtin = 0; + exists = true; + } + if (! exists + && bfd_is_abs_section (h->root.root.u.def.section)) + { + f = new_fixup (info, h1, h->root.root.u.def.value, 0); + if (f == NULL) + { + /* FIXME: No way to return error. */ + abort (); + } + f->jump = is_plt; + } + } + + /* Quick and dirty way of stripping these symbols from the + symtab. */ + if (bfd_is_abs_section (h->root.root.u.def.section)) + h->root.written = true; + } + + return true; +} + +/* This is called to set the size of the .linux-dynamic section is. + It is called by the Linux linker emulation before_allocation + routine. We have finished reading all of the input files, and now + we just scan the hash tables to find out how many additional fixups + are required. */ + +boolean +bfd_i386linux_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct fixup *f; + asection *s; + + if (output_bfd->xvec != &MY(vec)) + return true; + + /* First find the fixups... */ + linux_link_hash_traverse (linux_hash_table (info), + linux_tally_symbols, + (PTR) info); + + /* If there are builtin fixups, leave room for a marker. This is + used by the dynamic linker so that it knows that all that follow + are builtin fixups instead of regular fixups. */ + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (f->builtin) + { + ++linux_hash_table (info)->fixup_count; + ++linux_hash_table (info)->local_builtins; + break; + } + } + + if (linux_hash_table (info)->dynobj == NULL) + { + if (linux_hash_table (info)->fixup_count > 0) + abort (); + return true; + } + + /* Allocate memory for our fixup table. We will fill it in later. */ + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + if (s != NULL) + { + s->_raw_size = 8 + linux_hash_table (info)->fixup_count * 8; + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + return false; + memset (s->contents, 0, (size_t) s->_raw_size); + } + + return true; +} + +/* We come here once we are ready to actually write the fixup table to + the output file. Scan the fixup tables and so forth and generate + the stuff we need. */ + +static boolean +linux_finish_dynamic_link (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + asection *s, *os, *is; + bfd_byte *fixup_table; + struct linux_link_hash_entry *h; + struct fixup *f; + unsigned int new_addr; + int section_offset; + unsigned int fixups_written; + + if (linux_hash_table (info)->dynobj == NULL) + return true; + + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + BFD_ASSERT (s != NULL); + os = s->output_section; + fixups_written = 0; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup table file offset: %x VMA: %x\n", + os->filepos + s->output_offset, + os->vma + s->output_offset); +#endif + + fixup_table = s->contents; + bfd_put_32 (output_bfd, linux_hash_table (info)->fixup_count, fixup_table); + fixup_table += 4; + + /* Fill in fixup table. */ + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (f->builtin) + continue; + + if (f->h->root.root.type != bfd_link_hash_defined + && f->h->root.root.type != bfd_link_hash_defweak) + { + (*_bfd_error_handler) + ("Symbol %s not defined for fixups\n", + f->h->root.root.root.string); + continue; + } + + is = f->h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = f->h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, + new_addr, f->value); +#endif + + if (f->jump) + { + /* Relative address */ + new_addr = new_addr - (f->value + 5); + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value + 1, fixup_table); + fixup_table += 4; + } + else + { + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value, fixup_table); + fixup_table += 4; + } + ++fixups_written; + } + + if (linux_hash_table (info)->local_builtins != 0) + { + /* Special marker so we know to switch to the other type of fixup */ + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + ++fixups_written; + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (! f->builtin) + continue; + + if (f->h->root.root.type != bfd_link_hash_defined + && f->h->root.root.type != bfd_link_hash_defweak) + { + (*_bfd_error_handler) + ("Symbol %s not defined for fixups\n", + f->h->root.root.root.string); + continue; + } + + is = f->h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = f->h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, + new_addr, f->value); +#endif + + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value, fixup_table); + fixup_table += 4; + ++fixups_written; + } + } + + if (linux_hash_table (info)->fixup_count != fixups_written) + { + (*_bfd_error_handler) ("Warning: fixup count mismatch\n"); + while (linux_hash_table (info)->fixup_count > fixups_written) + { + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + ++fixups_written; + } + } + + h = linux_link_hash_lookup (linux_hash_table (info), + "__BUILTIN_FIXUPS__", + false, false, false); + + if (h != NULL + && (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak)) + { + is = h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Builtin fixup table at %x\n", new_addr); +#endif + + bfd_put_32 (output_bfd, new_addr, fixup_table); + } + else + bfd_put_32 (output_bfd, 0, fixup_table); + + if (bfd_seek (output_bfd, os->filepos + s->output_offset, SEEK_SET) != 0) + return false; + + if (bfd_write ((PTR) s->contents, 1, s->_raw_size, output_bfd) + != s->_raw_size) + return false; + + return true; +} + +#define MY_bfd_link_hash_table_create linux_link_hash_table_create +#define MY_add_one_symbol linux_add_one_symbol +#define MY_finish_dynamic_link linux_finish_dynamic_link + +#define MY_zmagic_contiguous 1 + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386lynx.c b/contrib/gdb/bfd/i386lynx.c new file mode 100644 index 000000000000..2381cff02b1a --- /dev/null +++ b/contrib/gdb/bfd/i386lynx.c @@ -0,0 +1,563 @@ +/* BFD back-end for i386 a.out binaries under LynxOS. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#define N_SHARED_LIB(x) 0 + +#define TEXT_START_ADDR 0 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_i386 + +#define MY(OP) CAT(i386lynx_aout_,OP) +#define TARGETNAME "a.out-i386-lynx" + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifndef WRITE_HEADERS +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false; \ + if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) \ + != EXEC_BYTES_SIZE) \ + return false; \ + /* Now write out reloc info, followed by syms and strings */ \ + \ + if (bfd_get_symcount (abfd) != 0) \ + { \ + if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET) \ + != 0) \ + return false; \ + \ + if (! NAME(aout,write_syms)(abfd)) return false; \ + \ + if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET) \ + != 0) \ + return false; \ + \ + if (!NAME(lynx,squirt_out_relocs) (abfd, obj_textsec (abfd))) \ + return false; \ + if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET) \ + != 0) \ + return 0; \ + \ + if (!NAME(lynx,squirt_out_relocs)(abfd, obj_datasec (abfd))) \ + return false; \ + } \ + } +#endif + +#include "libaout.h" +#include "aout/aout64.h" + +#ifdef LYNX_CORE + +char *lynx_core_file_failing_command (); +int lynx_core_file_failing_signal (); +boolean lynx_core_file_matches_executable_p (); +const bfd_target *lynx_core_file_p (); + +#define MY_core_file_failing_command lynx_core_file_failing_command +#define MY_core_file_failing_signal lynx_core_file_failing_signal +#define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p +#define MY_core_file_p lynx_core_file_p + +#endif /* LYNX_CORE */ + + +#define KEEPIT flags + +extern reloc_howto_type aout_32_ext_howto_table[]; +extern reloc_howto_type aout_32_std_howto_table[]; + +/* Standard reloc stuff */ +/* Output standard relocation information to a file in target byte order. */ + +void +NAME(lynx,swap_std_reloc_out) (abfd, g, natptr) + bfd *abfd; + arelent *g; + struct reloc_std_external *natptr; +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + unsigned int r_addend; + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_length = g->howto->size; /* Size as a power of two */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + /* r_baserel, r_jmptable, r_relative??? FIXME-soon */ + r_baserel = 0; + r_jmptable = 0; + r_relative = 0; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + + if (bfd_is_com_section (output_section) + || bfd_is_abs_section (output_section) + || bfd_is_und_section (output_section)) + { + if (bfd_abs_section_ptr->symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = stoi ((*(g->sym_ptr_ptr))->KEEPIT); + + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) + { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + (r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) + | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0) + | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0) + | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); + } + else + { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) + | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0) + | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0) + | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); + } +} + + +/* Extended stuff */ +/* Output extended relocation information to a file in target byte order. */ + +void +NAME(lynx,swap_ext_reloc_out) (abfd, g, natptr) + bfd *abfd; + arelent *g; + register struct reloc_ext_external *natptr; +{ + int r_index; + int r_extern; + unsigned int r_type; + unsigned int r_addend; + asymbol *sym = *(g->sym_ptr_ptr); + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_type = (unsigned int) g->howto->type; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + if (bfd_is_com_section (output_section) + || bfd_is_abs_section (output_section) + || bfd_is_und_section (output_section)) + { + if (bfd_abs_section_ptr->symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + r_extern = 1; + r_index = stoi ((*(g->sym_ptr_ptr))->KEEPIT); + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) + { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + (r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG); + } + else + { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + PUT_WORD (abfd, r_addend, natptr->r_addend); +} + +/* BFD deals internally with all things based from the section they're + in. so, something in 10 bytes into a text section with a base of + 50 would have a symbol (.text+10) and know .text vma was 50. + + Aout keeps all it's symbols based from zero, so the symbol would + contain 60. This macro subs the base of each section from the value + to give the true offset from the section */ + + +#define MOVE_ADDRESS(ad) \ + if (r_extern) { \ + /* undefined symbol */ \ + cache_ptr->sym_ptr_ptr = symbols + r_index; \ + cache_ptr->addend = ad; \ + } else { \ + /* defined, section relative. replace symbol with pointer to \ + symbol which points to section */ \ + switch (r_index) { \ + case N_TEXT: \ + case N_TEXT | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->textsec->vma; \ + break; \ + case N_DATA: \ + case N_DATA | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->datasec->vma; \ + break; \ + case N_BSS: \ + case N_BSS | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->bsssec->vma; \ + break; \ + default: \ + case N_ABS: \ + case N_ABS | N_EXT: \ + cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \ + cache_ptr->addend = ad; \ + break; \ + } \ + } \ + +void +NAME(lynx,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_ext_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + int r_index; + int r_extern; + unsigned int r_type; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); + + r_index = bytes->r_index[1]; + r_extern = (0 != (bytes->r_index[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = (bytes->r_index[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG; + + cache_ptr->howto = aout_32_ext_howto_table + r_type; + MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend)); +} + +void +NAME(lynx,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount) + bfd *abfd; + struct reloc_std_external *bytes; + arelent *cache_ptr; + asymbol **symbols; + bfd_size_type symcount; +{ + int r_index; + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + r_index = bytes->r_index[1]; + r_extern = (0 != (bytes->r_index[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_PCREL_BIG)); + r_baserel = (0 != (bytes->r_index[0] & RELOC_STD_BITS_BASEREL_BIG)); + r_jmptable = (0 != (bytes->r_index[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + r_relative = (0 != (bytes->r_index[0] & RELOC_STD_BITS_RELATIVE_BIG)); + r_length = (bytes->r_index[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG; + + cache_ptr->howto = aout_32_std_howto_table + r_length + 4 * r_pcrel; + /* FIXME-soon: Roll baserel, jmptable, relative bits into howto setting */ + + MOVE_ADDRESS (0); +} + +/* Reloc hackery */ + +boolean +NAME(lynx,slurp_reloc_table) (abfd, asect, symbols) + bfd *abfd; + sec_ptr asect; + asymbol **symbols; +{ + unsigned int count; + bfd_size_type reloc_size; + PTR relocs; + arelent *reloc_cache; + size_t each_size; + + if (asect->relocation) + return true; + + if (asect->flags & SEC_CONSTRUCTOR) + return true; + + if (asect == obj_datasec (abfd)) + { + reloc_size = exec_hdr (abfd)->a_drsize; + goto doit; + } + + if (asect == obj_textsec (abfd)) + { + reloc_size = exec_hdr (abfd)->a_trsize; + goto doit; + } + + bfd_set_error (bfd_error_invalid_operation); + return false; + +doit: + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) + return false; + each_size = obj_reloc_entry_size (abfd); + + count = reloc_size / each_size; + + + reloc_cache = (arelent *) bfd_malloc (count * sizeof (arelent)); + if (!reloc_cache && count != 0) + return false; + memset (reloc_cache, 0, count * sizeof (arelent)); + + relocs = (PTR) bfd_alloc (abfd, reloc_size); + if (!relocs && reloc_size != 0) + { + free (reloc_cache); + return false; + } + + if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) + { + bfd_release (abfd, relocs); + free (reloc_cache); + return false; + } + + if (each_size == RELOC_EXT_SIZE) + { + register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) + { + NAME(lynx,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols, + bfd_get_symcount (abfd)); + } + } + else + { + register struct reloc_std_external *rptr = (struct reloc_std_external *) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) + { + NAME(lynx,swap_std_reloc_in) (abfd, rptr, cache_ptr, symbols, + bfd_get_symcount (abfd)); + } + + } + + bfd_release (abfd, relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + + + +/* Write out a relocation section into an object file. */ + +boolean +NAME(lynx,squirt_out_relocs) (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + unsigned char *native, *natptr; + size_t each_size; + + unsigned int count = section->reloc_count; + size_t natsize; + + if (count == 0) + return true; + + each_size = obj_reloc_entry_size (abfd); + natsize = each_size * count; + native = (unsigned char *) bfd_zalloc (abfd, natsize); + if (!native) + return false; + + generic = section->orelocation; + + if (each_size == RELOC_EXT_SIZE) + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(lynx,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *) natptr); + } + else + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(lynx,swap_std_reloc_out) (abfd, *generic, (struct reloc_std_external *) natptr); + } + + if (bfd_write ((PTR) native, 1, natsize, abfd) != natsize) + { + bfd_release (abfd, native); + return false; + } + bfd_release (abfd, native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +long +NAME(lynx,canonicalize_reloc) (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (!(tblptr || NAME(lynx,slurp_reloc_table) (abfd, section, symbols))) + return -1; + + if (section->flags & SEC_CONSTRUCTOR) + { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = &chain->relent; + chain = chain->next; + } + } + else + { + tblptr = section->relocation; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +#define MY_canonicalize_reloc NAME(lynx,canonicalize_reloc) + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386mach3.c b/contrib/gdb/bfd/i386mach3.c new file mode 100644 index 000000000000..72a28f33bf0d --- /dev/null +++ b/contrib/gdb/bfd/i386mach3.c @@ -0,0 +1,65 @@ +/* BFD back-end for i386 a.out binaries. + Copyright (C) 1990, 1991 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is for Mach 3, which uses a.out, not Mach-O. */ + +/* There is no magic number or anything which lets us distinguish this target + from i386aout or i386bsd. So this target is only useful if it is the + default target. */ + +#define TARGET_PAGE_SIZE 1 +#define SEGMENT_SIZE 0x1000 +#define TEXT_START_ADDR 0x10000 +#define ARCH 32 +#define BYTES_IN_WORD 4 +/* This macro is only relevant when N_MAGIC(x) == ZMAGIC. */ +#define N_HEADER_IN_TEXT(x) 1 + +#define N_TXTSIZE(x) ((x).a_text) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#define DEFAULT_ARCH bfd_arch_i386 +#define MY(OP) CAT(i386mach3_,OP) +#define TARGETNAME "a.out-mach3" + +static boolean MY(set_sizes)(); +#define MY_backend_data &MY(backend_data) +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 1, /* text incl header */ + 0, /* exec_hdr_flags */ + 0, /* text vma? */ + MY(set_sizes), + 1, /* exec header not counted */ + 0, /* add_dynamic_symbols */ + 0, /* add_one_symbol */ + 0, /* link_dynamic_object */ + 0, /* write_dynamic_symbol */ + 0, /* check_dynamic_reloc */ + 0 /* finish_dynamic_link */ +}; + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/i386msdos.c b/contrib/gdb/bfd/i386msdos.c new file mode 100644 index 000000000000..24a456bea23d --- /dev/null +++ b/contrib/gdb/bfd/i386msdos.c @@ -0,0 +1,243 @@ +/* BFD back-end for MS-DOS executables. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Bryan Ford of the University of Utah. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#if 0 +struct exe_header +{ + unsigned short magic; + unsigned short bytes_in_last_page; + unsigned short npages; /* number of 512-byte "pages" including this header */ + unsigned short nrelocs; + unsigned short header_paras; /* number of 16-byte paragraphs in header */ + unsigned short reserved; + unsigned short load_switch; + unsigned short ss_ofs; + unsigned short sp; + unsigned short checksum; + unsigned short ip; + unsigned short cs_ofs; + unsigned short reloc_ofs; + unsigned short reserved2; + unsigned short something1; + unsigned short something2; + unsigned short something3; +}; +#endif + +#define EXE_MAGIC 0x5a4d +#define EXE_LOAD_HIGH 0x0000 +#define EXE_LOAD_LOW 0xffff +#define EXE_PAGE_SIZE 512 + + +static int +msdos_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +static boolean +msdos_write_object_contents (abfd) + bfd *abfd; +{ + static char hdr[EXE_PAGE_SIZE]; + file_ptr outfile_size = sizeof(hdr); + bfd_vma high_vma = 0; + asection *sec; + + /* Find the total size of the program on disk and in memory. */ + for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) + { + if (bfd_get_section_size_before_reloc (sec) == 0) + continue; + if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) + { + bfd_vma sec_vma = bfd_get_section_vma (abfd, sec) + + bfd_get_section_size_before_reloc (sec); + if (sec_vma > high_vma) + high_vma = sec_vma; + } + if (bfd_get_section_flags (abfd, sec) & SEC_LOAD) + { + file_ptr sec_end = sizeof(hdr) + + bfd_get_section_vma (abfd, sec) + + bfd_get_section_size_before_reloc (sec); + if (sec_end > outfile_size) + outfile_size = sec_end; + } + } + + /* Make sure the program isn't too big. */ + if (high_vma > (bfd_vma)0xffff) + { + bfd_set_error(bfd_error_file_too_big); + return false; + } + + /* constants */ + bfd_h_put_16(abfd, EXE_MAGIC, &hdr[0]); + bfd_h_put_16(abfd, EXE_PAGE_SIZE / 16, &hdr[8]); + bfd_h_put_16(abfd, EXE_LOAD_LOW, &hdr[12]); + bfd_h_put_16(abfd, 0x3e, &hdr[24]); + bfd_h_put_16(abfd, 0x0001, &hdr[28]); /* XXX??? */ + bfd_h_put_16(abfd, 0x30fb, &hdr[30]); /* XXX??? */ + bfd_h_put_16(abfd, 0x726a, &hdr[32]); /* XXX??? */ + + /* bytes in last page (0 = full page) */ + bfd_h_put_16(abfd, outfile_size & (EXE_PAGE_SIZE - 1), &hdr[2]); + + /* number of pages */ + bfd_h_put_16(abfd, (outfile_size + EXE_PAGE_SIZE - 1) / EXE_PAGE_SIZE, + &hdr[4]); + + /* Set the initial stack pointer to the end of the bss. + The program's crt0 code must relocate it to a real stack. */ + bfd_h_put_16(abfd, high_vma, &hdr[16]); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_write (hdr, 1, sizeof(hdr), abfd) != sizeof(hdr)) + return false; + + return true; +} + +static boolean +msdos_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + + if (count == 0) + return true; + + section->filepos = EXE_PAGE_SIZE + bfd_get_section_vma (abfd, section); + + if (bfd_get_section_flags (abfd, section) & SEC_LOAD) + { + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0 + || bfd_write (location, 1, count, abfd) != count) + return false; + } + + return true; +} + + + +#define msdos_mkobject aout_32_mkobject +#define msdos_make_empty_symbol aout_32_make_empty_symbol +#define msdos_bfd_reloc_type_lookup aout_32_reloc_type_lookup + +#define msdos_close_and_cleanup _bfd_generic_close_and_cleanup +#define msdos_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define msdos_new_section_hook _bfd_generic_new_section_hook +#define msdos_get_section_contents _bfd_generic_get_section_contents +#define msdos_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window +#define msdos_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define msdos_bfd_relax_section bfd_generic_relax_section +#define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define msdos_bfd_final_link _bfd_generic_final_link +#define msdos_bfd_link_split_section _bfd_generic_link_split_section +#define msdos_set_arch_mach _bfd_generic_set_arch_mach + +#define msdos_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound +#define msdos_get_symtab _bfd_nosymbols_get_symtab +#define msdos_print_symbol _bfd_nosymbols_print_symbol +#define msdos_get_symbol_info _bfd_nosymbols_get_symbol_info +#define msdos_find_nearest_line _bfd_nosymbols_find_nearest_line +#define msdos_get_lineno _bfd_nosymbols_get_lineno +#define msdos_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define msdos_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define msdos_read_minisymbols _bfd_nosymbols_read_minisymbols +#define msdos_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +#define msdos_canonicalize_reloc _bfd_norelocs_canonicalize_reloc +#define msdos_get_reloc_upper_bound _bfd_norelocs_get_reloc_upper_bound +#define msdos_32_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target i386msdos_vec = +{ + "msdos", /* name */ + bfd_target_msdos_flavour, + BFD_ENDIAN_LITTLE, /* target byte order */ + BFD_ENDIAN_LITTLE, /* target headers byte order */ + (EXEC_P), /* object flags */ + (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + + { + _bfd_dummy_target, + _bfd_dummy_target, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + msdos_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + msdos_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (msdos), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (msdos), + BFD_JUMP_TABLE_RELOCS (msdos), + BFD_JUMP_TABLE_WRITE (msdos), + BFD_JUMP_TABLE_LINK (msdos), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; + + diff --git a/contrib/gdb/bfd/i386netbsd.c b/contrib/gdb/bfd/i386netbsd.c new file mode 100644 index 000000000000..32feaa70c94e --- /dev/null +++ b/contrib/gdb/bfd/i386netbsd.c @@ -0,0 +1,33 @@ +/* BFD back-end for NetBSD/386 a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#undef TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(i386netbsd_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-i386-netbsd" + +#include "netbsd.h" diff --git a/contrib/gdb/bfd/i386os9k.c b/contrib/gdb/bfd/i386os9k.c new file mode 100644 index 000000000000..fe1a021691bc --- /dev/null +++ b/contrib/gdb/bfd/i386os9k.c @@ -0,0 +1,370 @@ +/* BFD back-end for os9000 i386 binaries. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "libaout.h" /* BFD a.out internal data structures */ +#include "os9k.h" + +static const bfd_target *os9k_callback PARAMS ((bfd *)); + +/* Swaps the information in an executable header taken from a raw byte + stream memory image, into the internal exec_header structure. */ +boolean +os9k_swap_exec_header_in (abfd, raw_bytes, execp) + bfd *abfd; + mh_com *raw_bytes; + struct internal_exec *execp; +{ + mh_com *bytes = (mh_com *) raw_bytes; + unsigned int dload, dmemsize, dmemstart; + + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_16 (abfd, bytes->m_sync); + execp->a_syms = 0; + execp->a_entry = bfd_h_get_32 (abfd, bytes->m_exec); + execp->a_talign = 2; + execp->a_dalign = 2; + execp->a_balign = 2; + + dload = bfd_h_get_32 (abfd, bytes->m_idata); + execp->a_data = dload + 8; + + if (bfd_seek (abfd, (file_ptr) dload, SEEK_SET) != 0 + || (bfd_read (&dmemstart, sizeof (dmemstart), 1, abfd) + != sizeof (dmemstart)) + || (bfd_read (&dmemsize, sizeof (dmemsize), 1, abfd) + != sizeof (dmemsize))) + return false; + + execp->a_tload = 0; + execp->a_dload = bfd_h_get_32 (abfd, (unsigned char *) &dmemstart); + execp->a_text = dload - execp->a_tload; + execp->a_data = bfd_h_get_32 (abfd, (unsigned char *) &dmemsize); + execp->a_bss = bfd_h_get_32 (abfd, bytes->m_data) - execp->a_data; + + execp->a_trsize = 0; + execp->a_drsize = 0; + + return true; +} + +#if 0 +/* Swaps the information in an internal exec header structure into the + supplied buffer ready for writing to disk. */ + +PROTO (void, os9k_swap_exec_header_out, + (bfd * abfd, + struct internal_exec * execp, + struct mh_com * raw_bytes)); +void +os9k_swap_exec_header_out (abfd, execp, raw_bytes) + bfd *abfd; + struct internal_exec *execp; + mh_com *raw_bytes; +{ + mh_com *bytes = (mh_com *) raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info, bytes->e_info); + bfd_h_put_32 (abfd, execp->a_text, bytes->e_text); + bfd_h_put_32 (abfd, execp->a_data, bytes->e_data); + bfd_h_put_32 (abfd, execp->a_bss, bytes->e_bss); + bfd_h_put_32 (abfd, execp->a_syms, bytes->e_syms); + bfd_h_put_32 (abfd, execp->a_entry, bytes->e_entry); + bfd_h_put_32 (abfd, execp->a_trsize, bytes->e_trsize); + bfd_h_put_32 (abfd, execp->a_drsize, bytes->e_drsize); + bfd_h_put_32 (abfd, execp->a_tload, bytes->e_tload); + bfd_h_put_32 (abfd, execp->a_dload, bytes->e_dload); + bytes->e_talign[0] = execp->a_talign; + bytes->e_dalign[0] = execp->a_dalign; + bytes->e_balign[0] = execp->a_balign; + bytes->e_relaxable[0] = execp->a_relaxable; +} + +#endif /* 0 */ + +static const bfd_target * +os9k_object_p (abfd) + bfd *abfd; +{ + struct internal_exec anexec; + mh_com exec_bytes; + + if (bfd_read ((PTR) & exec_bytes, MHCOM_BYTES_SIZE, 1, abfd) + != MHCOM_BYTES_SIZE) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + anexec.a_info = bfd_h_get_16 (abfd, exec_bytes.m_sync); + if (N_BADMAG (anexec)) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if (! os9k_swap_exec_header_in (abfd, &exec_bytes, &anexec)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + return aout_32_some_aout_object_p (abfd, &anexec, os9k_callback); +} + + +/* Finish up the opening of a b.out file for reading. Fill in all the + fields that are not handled by common code. */ + +static const bfd_target * +os9k_callback (abfd) + bfd *abfd; +{ + struct internal_exec *execp = exec_hdr (abfd); + unsigned long bss_start; + + /* Architecture and machine type */ + bfd_set_arch_mach (abfd, bfd_arch_i386, 0); + + /* The positions of the string table and symbol table. */ + obj_str_filepos (abfd) = 0; + obj_sym_filepos (abfd) = 0; + + /* The alignments of the sections */ + obj_textsec (abfd)->alignment_power = execp->a_talign; + obj_datasec (abfd)->alignment_power = execp->a_dalign; + obj_bsssec (abfd)->alignment_power = execp->a_balign; + + /* The starting addresses of the sections. */ + obj_textsec (abfd)->vma = execp->a_tload; + obj_datasec (abfd)->vma = execp->a_dload; + + /* And reload the sizes, since the aout module zaps them */ + obj_textsec (abfd)->_raw_size = execp->a_text; + + bss_start = execp->a_dload + execp->a_data; /* BSS = end of data section */ + obj_bsssec (abfd)->vma = align_power (bss_start, execp->a_balign); + + /* The file positions of the sections */ + obj_textsec (abfd)->filepos = execp->a_entry; + obj_datasec (abfd)->filepos = execp->a_dload; + + /* The file positions of the relocation info *** + obj_textsec (abfd)->rel_filepos = N_TROFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DROFF(*execp); + */ + + adata (abfd).page_size = 1; /* Not applicable. */ + adata (abfd).segment_size = 1;/* Not applicable. */ + adata (abfd).exec_bytes_size = MHCOM_BYTES_SIZE; + + return abfd->xvec; +} + +#if 0 +struct bout_data_struct +{ + struct aoutdata a; + struct internal_exec e; +}; + +static boolean +os9k_mkobject (abfd) + bfd *abfd; +{ + struct bout_data_struct *rawptr; + + rawptr = (struct bout_data_struct *) bfd_zalloc (abfd, sizeof (struct bout_data_struct)); + if (rawptr == NULL) + return false; + + abfd->tdata.bout_data = rawptr; + exec_hdr (abfd) = &rawptr->e; + + obj_textsec (abfd) = (asection *) NULL; + obj_datasec (abfd) = (asection *) NULL; + obj_bsssec (abfd) = (asection *) NULL; + + return true; +} + +static boolean +os9k_write_object_contents (abfd) + bfd *abfd; +{ + struct external_exec swapped_hdr; + + if (! aout_32_make_sections (abfd)) + return false; + + exec_hdr (abfd)->a_info = BMAGIC; + + exec_hdr (abfd)->a_text = obj_textsec (abfd)->_raw_size; + exec_hdr (abfd)->a_data = obj_datasec (abfd)->_raw_size; + exec_hdr (abfd)->a_bss = obj_bsssec (abfd)->_raw_size; + exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) * sizeof (struct nlist); + exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); + exec_hdr (abfd)->a_trsize = ((obj_textsec (abfd)->reloc_count) * + sizeof (struct relocation_info)); + exec_hdr (abfd)->a_drsize = ((obj_datasec (abfd)->reloc_count) * + sizeof (struct relocation_info)); + + exec_hdr (abfd)->a_talign = obj_textsec (abfd)->alignment_power; + exec_hdr (abfd)->a_dalign = obj_datasec (abfd)->alignment_power; + exec_hdr (abfd)->a_balign = obj_bsssec (abfd)->alignment_power; + + exec_hdr (abfd)->a_tload = obj_textsec (abfd)->vma; + exec_hdr (abfd)->a_dload = obj_datasec (abfd)->vma; + + bout_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) & swapped_hdr, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE)) + return false; + + /* Now write out reloc info, followed by syms and strings */ + if (bfd_get_symcount (abfd) != 0) + { + if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (*exec_hdr (abfd))), SEEK_SET) + != 0) + return false; + + if (!aout_32_write_syms (abfd)) + return false; + + if (bfd_seek (abfd, (file_ptr) (N_TROFF (*exec_hdr (abfd))), SEEK_SET) + != 0) + return false; + + if (!b_out_squirt_out_relocs (abfd, obj_textsec (abfd))) + return false; + if (bfd_seek (abfd, (file_ptr) (N_DROFF (*exec_hdr (abfd))), SEEK_SET) + != 0) + return false; + + if (!b_out_squirt_out_relocs (abfd, obj_datasec (abfd))) + return false; + } + return true; +} + +static boolean +os9k_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + unsigned char *location; + file_ptr offset; + int count; +{ + + if (abfd->output_has_begun == false) + { /* set by bfd.c handler */ + if (! aout_32_make_sections (abfd)) + return false; + + obj_textsec (abfd)->filepos = sizeof (struct internal_exec); + obj_datasec (abfd)->filepos = obj_textsec (abfd)->filepos + + obj_textsec (abfd)->_raw_size; + + } + /* regardless, once we know what we're doing, we might as well get going */ + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) + return false; + + if (count != 0) + { + return (bfd_write ((PTR) location, 1, count, abfd) == count) ? true : false; + } + return true; +} +#endif /* 0 */ + +static int +os9k_sizeof_headers (ignore_abfd, ignore) + bfd *ignore_abfd; + boolean ignore; +{ + return sizeof (struct internal_exec); +} + + +/***********************************************************************/ + +#define aout_32_close_and_cleanup aout_32_bfd_free_cached_info + +#define aout_32_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol + +#define aout_32_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define aout_32_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define os9k_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define os9k_bfd_relax_section bfd_generic_relax_section +#define os9k_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define os9k_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define os9k_bfd_final_link _bfd_generic_final_link +#define os9k_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target i386os9k_vec = +{ + "i386os9k", /* name */ + bfd_target_os9k_flavour, + BFD_ENDIAN_LITTLE, /* data byte order is little */ + BFD_ENDIAN_LITTLE, /* hdr byte order is little */ + (HAS_RELOC | EXEC_P | WP_TEXT), /* object flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD), /* section flags */ + 0, /* symbol leading char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + {_bfd_dummy_target, os9k_object_p, /* bfd_check_format */ + bfd_generic_archive_p, _bfd_dummy_target}, + {bfd_false, bfd_false, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, bfd_false, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (aout_32), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), + BFD_JUMP_TABLE_SYMBOLS (aout_32), + BFD_JUMP_TABLE_RELOCS (aout_32), + BFD_JUMP_TABLE_WRITE (aout_32), + BFD_JUMP_TABLE_LINK (os9k), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0, +}; diff --git a/contrib/gdb/bfd/ieee.c b/contrib/gdb/bfd/ieee.c new file mode 100644 index 000000000000..201f22515b3f --- /dev/null +++ b/contrib/gdb/bfd/ieee.c @@ -0,0 +1,3738 @@ +/* BFD back-end for ieee-695 objects. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define KEEPMINUSPCININST 0 + +/* IEEE 695 format is a stream of records, which we parse using a simple one- + token (which is one byte in this lexicon) lookahead recursive decent + parser. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "ieee.h" +#include "libieee.h" + +static boolean ieee_write_byte PARAMS ((bfd *, bfd_byte)); +static boolean ieee_write_2bytes PARAMS ((bfd *, int)); +static boolean ieee_write_int PARAMS ((bfd *, bfd_vma)); +static boolean ieee_write_id PARAMS ((bfd *, const char *)); +static boolean ieee_write_expression + PARAMS ((bfd *, bfd_vma, asymbol *, boolean, unsigned int)); +static void ieee_write_int5 PARAMS ((bfd_byte *, bfd_vma)); +static boolean ieee_write_int5_out PARAMS ((bfd *, bfd_vma)); +static boolean ieee_write_section_part PARAMS ((bfd *)); +static boolean do_with_relocs PARAMS ((bfd *, asection *)); +static boolean do_as_repeat PARAMS ((bfd *, asection *)); +static boolean do_without_relocs PARAMS ((bfd *, asection *)); +static boolean ieee_write_external_part PARAMS ((bfd *)); +static boolean ieee_write_data_part PARAMS ((bfd *)); +static boolean ieee_write_debug_part PARAMS ((bfd *)); +static boolean ieee_write_me_part PARAMS ((bfd *)); +static boolean ieee_write_processor PARAMS ((bfd *)); + +static boolean ieee_slurp_debug PARAMS ((bfd *)); +static boolean ieee_slurp_section_data PARAMS ((bfd *)); + +/* Functions for writing to ieee files in the strange way that the + standard requires. */ + +static boolean +ieee_write_byte (abfd, byte) + bfd *abfd; + bfd_byte byte; +{ + if (bfd_write ((PTR) &byte, 1, 1, abfd) != 1) + return false; + return true; +} + +static boolean +ieee_write_2bytes (abfd, bytes) + bfd *abfd; + int bytes; +{ + bfd_byte buffer[2]; + + buffer[0] = bytes >> 8; + buffer[1] = bytes & 0xff; + if (bfd_write ((PTR) buffer, 1, 2, abfd) != 2) + return false; + return true; +} + +static boolean +ieee_write_int (abfd, value) + bfd *abfd; + bfd_vma value; +{ + if (value <= 127) + { + if (! ieee_write_byte (abfd, (bfd_byte) value)) + return false; + } + else + { + unsigned int length; + + /* How many significant bytes ? */ + /* FIXME FOR LONGER INTS */ + if (value & 0xff000000) + length = 4; + else if (value & 0x00ff0000) + length = 3; + else if (value & 0x0000ff00) + length = 2; + else + length = 1; + + if (! ieee_write_byte (abfd, + (bfd_byte) ((int) ieee_number_repeat_start_enum + + length))) + return false; + switch (length) + { + case 4: + if (! ieee_write_byte (abfd, (bfd_byte) (value >> 24))) + return false; + /* Fall through. */ + case 3: + if (! ieee_write_byte (abfd, (bfd_byte) (value >> 16))) + return false; + /* Fall through. */ + case 2: + if (! ieee_write_byte (abfd, (bfd_byte) (value >> 8))) + return false; + /* Fall through. */ + case 1: + if (! ieee_write_byte (abfd, (bfd_byte) (value))) + return false; + } + } + + return true; +} + +static boolean +ieee_write_id (abfd, id) + bfd *abfd; + const char *id; +{ + size_t length = strlen (id); + + if (length <= 127) + { + if (! ieee_write_byte (abfd, (bfd_byte) length)) + return false; + } + else if (length < 255) + { + if (! ieee_write_byte (abfd, ieee_extension_length_1_enum) + || ! ieee_write_byte (abfd, (bfd_byte) length)) + return false; + } + else if (length < 65535) + { + if (! ieee_write_byte (abfd, ieee_extension_length_2_enum) + || ! ieee_write_2bytes (abfd, (int) length)) + return false; + } + else + { + (*_bfd_error_handler) + ("%s: string too long (%d chars, max 65535)", + bfd_get_filename (abfd), length); + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + if (bfd_write ((PTR) id, 1, length, abfd) != length) + return false; + return true; +} + +/*************************************************************************** +Functions for reading from ieee files in the strange way that the +standard requires: +*/ + +#define this_byte(ieee) *((ieee)->input_p) +#define next_byte(ieee) ((ieee)->input_p++) +#define this_byte_and_next(ieee) (*((ieee)->input_p++)) + +static unsigned short +read_2bytes (ieee) + common_header_type *ieee; +{ + unsigned char c1 = this_byte_and_next (ieee); + unsigned char c2 = this_byte_and_next (ieee); + return (c1 << 8) | c2; +} + +static void +bfd_get_string (ieee, string, length) + common_header_type *ieee; + char *string; + size_t length; +{ + size_t i; + for (i = 0; i < length; i++) + { + string[i] = this_byte_and_next (ieee); + } +} + +static char * +read_id (ieee) + common_header_type *ieee; +{ + size_t length; + char *string; + length = this_byte_and_next (ieee); + if (length <= 0x7f) + { + /* Simple string of length 0 to 127 */ + } + else if (length == 0xde) + { + /* Length is next byte, allowing 0..255 */ + length = this_byte_and_next (ieee); + } + else if (length == 0xdf) + { + /* Length is next two bytes, allowing 0..65535 */ + length = this_byte_and_next (ieee); + length = (length * 256) + this_byte_and_next (ieee); + } + /* Buy memory and read string */ + string = bfd_alloc (ieee->abfd, length + 1); + if (!string) + return NULL; + bfd_get_string (ieee, string, length); + string[length] = 0; + return string; +} + +static boolean +ieee_write_expression (abfd, value, symbol, pcrel, index) + bfd *abfd; + bfd_vma value; + asymbol *symbol; + boolean pcrel; + unsigned int index; +{ + unsigned int term_count = 0; + + if (value != 0) + { + if (! ieee_write_int (abfd, value)) + return false; + term_count++; + } + + if (bfd_is_com_section (symbol->section) + || bfd_is_und_section (symbol->section)) + { + /* Def of a common symbol */ + if (! ieee_write_byte (abfd, ieee_variable_X_enum) + || ! ieee_write_int (abfd, symbol->value)) + return false; + term_count++; + } + else if (! bfd_is_abs_section (symbol->section)) + { + /* Ref to defined symbol - */ + + if (symbol->flags & BSF_GLOBAL) + { + if (! ieee_write_byte (abfd, ieee_variable_I_enum) + || ! ieee_write_int (abfd, symbol->value)) + return false; + term_count++; + } + else if (symbol->flags & (BSF_LOCAL | BSF_SECTION_SYM)) + { + /* This is a reference to a defined local symbol. We can + easily do a local as a section+offset. */ + if (! ieee_write_byte (abfd, ieee_variable_R_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (symbol->section->index + + IEEE_SECTION_NUMBER_BASE))) + return false; + term_count++; + if (symbol->value != 0) + { + if (! ieee_write_int (abfd, symbol->value)) + return false; + term_count++; + } + } + else + { + (*_bfd_error_handler) + ("%s: unrecognized symbol `%s' flags 0x%x", + bfd_get_filename (abfd), bfd_asymbol_name (symbol), + symbol->flags); + bfd_set_error (bfd_error_invalid_operation); + return false; + } + } + + if (pcrel) + { + /* subtract the pc from here by asking for PC of this section*/ + if (! ieee_write_byte (abfd, ieee_variable_P_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (index + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_byte (abfd, ieee_function_minus_enum)) + return false; + } + + /* Handle the degenerate case of a 0 address. */ + if (term_count == 0) + { + if (! ieee_write_int (abfd, 0)) + return false; + } + + while (term_count > 1) + { + if (! ieee_write_byte (abfd, ieee_function_plus_enum)) + return false; + term_count--; + } + + return true; +} + +/*****************************************************************************/ + +/* +writes any integer into the buffer supplied and always takes 5 bytes +*/ +static void +ieee_write_int5 (buffer, value) + bfd_byte *buffer; + bfd_vma value; +{ + buffer[0] = (bfd_byte) ieee_number_repeat_4_enum; + buffer[1] = (value >> 24) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[3] = (value >> 8) & 0xff; + buffer[4] = (value >> 0) & 0xff; +} + +static boolean +ieee_write_int5_out (abfd, value) + bfd *abfd; + bfd_vma value; +{ + bfd_byte b[5]; + + ieee_write_int5 (b, value); + if (bfd_write ((PTR) b, 1, 5, abfd) != 5) + return false; + return true; +} + +static boolean +parse_int (ieee, value_ptr) + common_header_type *ieee; + bfd_vma *value_ptr; +{ + int value = this_byte (ieee); + int result; + if (value >= 0 && value <= 127) + { + *value_ptr = value; + next_byte (ieee); + return true; + } + else if (value >= 0x80 && value <= 0x88) + { + unsigned int count = value & 0xf; + result = 0; + next_byte (ieee); + while (count) + { + result = (result << 8) | this_byte_and_next (ieee); + count--; + } + *value_ptr = result; + return true; + } + return false; +} + +static int +parse_i (ieee, ok) + common_header_type *ieee; + boolean *ok; +{ + bfd_vma x; + *ok = parse_int (ieee, &x); + return x; +} + +static bfd_vma +must_parse_int (ieee) + common_header_type *ieee; +{ + bfd_vma result; + BFD_ASSERT (parse_int (ieee, &result) == true); + return result; +} + +typedef struct +{ + bfd_vma value; + asection *section; + ieee_symbol_index_type symbol; +} ieee_value_type; + + +#ifdef KEEPMINUSPCININST + +#define SRC_MASK(arg) arg +#define PCREL_OFFSET false + +#else + +#define SRC_MASK(arg) 0 +#define PCREL_OFFSET true + +#endif + +static reloc_howto_type abs32_howto = + HOWTO (1, + 0, + 2, + 32, + false, + 0, + complain_overflow_bitfield, + 0, + "abs32", + true, + 0xffffffff, + 0xffffffff, + false); + +static reloc_howto_type abs16_howto = + HOWTO (1, + 0, + 1, + 16, + false, + 0, + complain_overflow_bitfield, + 0, + "abs16", + true, + 0x0000ffff, + 0x0000ffff, + false); + +static reloc_howto_type abs8_howto = + HOWTO (1, + 0, + 0, + 8, + false, + 0, + complain_overflow_bitfield, + 0, + "abs8", + true, + 0x000000ff, + 0x000000ff, + false); + +static reloc_howto_type rel32_howto = + HOWTO (1, + 0, + 2, + 32, + true, + 0, + complain_overflow_signed, + 0, + "rel32", + true, + SRC_MASK (0xffffffff), + 0xffffffff, + PCREL_OFFSET); + +static reloc_howto_type rel16_howto = + HOWTO (1, + 0, + 1, + 16, + true, + 0, + complain_overflow_signed, + 0, + "rel16", + true, + SRC_MASK (0x0000ffff), + 0x0000ffff, + PCREL_OFFSET); + +static reloc_howto_type rel8_howto = + HOWTO (1, + 0, + 0, + 8, + true, + 0, + complain_overflow_signed, + 0, + "rel8", + true, + SRC_MASK (0x000000ff), + 0x000000ff, + PCREL_OFFSET); + +static ieee_symbol_index_type NOSYMBOL = {0, 0}; + +static void +parse_expression (ieee, value, symbol, pcrel, extra, section) + ieee_data_type *ieee; + bfd_vma *value; + ieee_symbol_index_type *symbol; + boolean *pcrel; + unsigned int *extra; + asection **section; + +{ +#define POS sp[1] +#define TOS sp[0] +#define NOS sp[-1] +#define INC sp++; +#define DEC sp--; + + boolean loop = true; + ieee_value_type stack[10]; + + /* The stack pointer always points to the next unused location */ +#define PUSH(x,y,z) TOS.symbol=x;TOS.section=y;TOS.value=z;INC; +#define POP(x,y,z) DEC;x=TOS.symbol;y=TOS.section;z=TOS.value; + ieee_value_type *sp = stack; + + while (loop) + { + switch (this_byte (&(ieee->h))) + { + case ieee_variable_P_enum: + /* P variable, current program counter for section n */ + { + int section_n; + next_byte (&(ieee->h)); + *pcrel = true; + section_n = must_parse_int (&(ieee->h)); + PUSH (NOSYMBOL, bfd_abs_section_ptr, 0); + break; + } + case ieee_variable_L_enum: + /* L variable address of section N */ + next_byte (&(ieee->h)); + PUSH (NOSYMBOL, ieee->section_table[must_parse_int (&(ieee->h))], 0); + break; + case ieee_variable_R_enum: + /* R variable, logical address of section module */ + /* FIXME, this should be different to L */ + next_byte (&(ieee->h)); + PUSH (NOSYMBOL, ieee->section_table[must_parse_int (&(ieee->h))], 0); + break; + case ieee_variable_S_enum: + /* S variable, size in MAUS of section module */ + next_byte (&(ieee->h)); + PUSH (NOSYMBOL, + 0, + ieee->section_table[must_parse_int (&(ieee->h))]->_raw_size); + break; + case ieee_variable_I_enum: + /* Push the address of variable n */ + { + ieee_symbol_index_type sy; + next_byte (&(ieee->h)); + sy.index = (int) must_parse_int (&(ieee->h)); + sy.letter = 'I'; + + PUSH (sy, bfd_abs_section_ptr, 0); + } + break; + case ieee_variable_X_enum: + /* Push the address of external variable n */ + { + ieee_symbol_index_type sy; + next_byte (&(ieee->h)); + sy.index = (int) (must_parse_int (&(ieee->h))); + sy.letter = 'X'; + + PUSH (sy, bfd_und_section_ptr, 0); + } + break; + case ieee_function_minus_enum: + { + bfd_vma value1, value2; + asection *section1, *section_dummy; + ieee_symbol_index_type sy; + next_byte (&(ieee->h)); + + POP (sy, section1, value1); + POP (sy, section_dummy, value2); + PUSH (sy, section1 ? section1 : section_dummy, value2 - value1); + } + break; + case ieee_function_plus_enum: + { + bfd_vma value1, value2; + asection *section1; + asection *section2; + ieee_symbol_index_type sy1; + ieee_symbol_index_type sy2; + next_byte (&(ieee->h)); + + POP (sy1, section1, value1); + POP (sy2, section2, value2); + PUSH (sy1.letter ? sy1 : sy2, + bfd_is_abs_section (section1) ? section2 : section1, + value1 + value2); + } + break; + default: + { + bfd_vma va; + BFD_ASSERT (this_byte (&(ieee->h)) < (int) ieee_variable_A_enum + || this_byte (&(ieee->h)) > (int) ieee_variable_Z_enum); + if (parse_int (&(ieee->h), &va)) + { + PUSH (NOSYMBOL, bfd_abs_section_ptr, va); + } + else + { + /* + Thats all that we can understand. As far as I can see + there is a bug in the Microtec IEEE output which I'm + using to scan, whereby the comma operator is omitted + sometimes in an expression, giving expressions with too + many terms. We can tell if that's the case by ensuring + that sp == stack here. If not, then we've pushed + something too far, so we keep adding. */ + + while (sp != stack + 1) + { + asection *section1; + ieee_symbol_index_type sy1; + POP (sy1, section1, *extra); + } + { + asection *dummy; + + POP (*symbol, dummy, *value); + if (section) + *section = dummy; + } + + loop = false; + } + } + } + } +} + + +#define ieee_seek(abfd, offset) \ + IEEE_DATA(abfd)->h.input_p = IEEE_DATA(abfd)->h.first_byte + offset + +#define ieee_pos(abfd) \ + (IEEE_DATA(abfd)->h.input_p - IEEE_DATA(abfd)->h.first_byte) + +static unsigned int last_index; +static char last_type; /* is the index for an X or a D */ + +static ieee_symbol_type * +get_symbol (abfd, + ieee, + last_symbol, + symbol_count, + pptr, + max_index, + this_type +) + bfd *abfd; + ieee_data_type *ieee; + ieee_symbol_type *last_symbol; + unsigned int *symbol_count; + ieee_symbol_type ***pptr; + unsigned int *max_index; + char this_type + ; +{ + /* Need a new symbol */ + unsigned int new_index = must_parse_int (&(ieee->h)); + if (new_index != last_index || this_type != last_type) + { + ieee_symbol_type *new_symbol = (ieee_symbol_type *) bfd_alloc (ieee->h.abfd, + sizeof (ieee_symbol_type)); + if (!new_symbol) + return NULL; + + new_symbol->index = new_index; + last_index = new_index; + (*symbol_count)++; + **pptr = new_symbol; + *pptr = &new_symbol->next; + if (new_index > *max_index) + { + *max_index = new_index; + } + last_type = this_type; + new_symbol->symbol.section = bfd_abs_section_ptr; + return new_symbol; + } + return last_symbol; +} + +static boolean +ieee_slurp_external_symbols (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + file_ptr offset = ieee->w.r.external_part; + + ieee_symbol_type **prev_symbols_ptr = &ieee->external_symbols; + ieee_symbol_type **prev_reference_ptr = &ieee->external_reference; + ieee_symbol_type *symbol = (ieee_symbol_type *) NULL; + unsigned int symbol_count = 0; + boolean loop = true; + last_index = 0xffffff; + ieee->symbol_table_full = true; + + ieee_seek (abfd, offset); + + while (loop) + { + switch (this_byte (&(ieee->h))) + { + case ieee_nn_record: + next_byte (&(ieee->h)); + + symbol = get_symbol (abfd, ieee, symbol, &symbol_count, + &prev_symbols_ptr, + &ieee->external_symbol_max_index, 'I'); + if (symbol == NULL) + return false; + + symbol->symbol.the_bfd = abfd; + symbol->symbol.name = read_id (&(ieee->h)); + symbol->symbol.udata.p = (PTR) NULL; + symbol->symbol.flags = BSF_NO_FLAGS; + break; + case ieee_external_symbol_enum: + next_byte (&(ieee->h)); + + symbol = get_symbol (abfd, ieee, symbol, &symbol_count, + &prev_symbols_ptr, + &ieee->external_symbol_max_index, 'D'); + if (symbol == NULL) + return false; + + BFD_ASSERT (symbol->index >= ieee->external_symbol_min_index); + + symbol->symbol.the_bfd = abfd; + symbol->symbol.name = read_id (&(ieee->h)); + symbol->symbol.udata.p = (PTR) NULL; + symbol->symbol.flags = BSF_NO_FLAGS; + break; + case ieee_attribute_record_enum >> 8: + { + unsigned int symbol_name_index; + unsigned int symbol_type_index; + unsigned int symbol_attribute_def; + bfd_vma value; + switch (read_2bytes (ieee)) + { + case ieee_attribute_record_enum: + symbol_name_index = must_parse_int (&(ieee->h)); + symbol_type_index = must_parse_int (&(ieee->h)); + symbol_attribute_def = must_parse_int (&(ieee->h)); + switch (symbol_attribute_def) + { + case 8: + case 19: + parse_int (&ieee->h, &value); + break; + default: + (*_bfd_error_handler) + ("%s: unimplemented ATI record %u for symbol %u", + bfd_get_filename (abfd), symbol_attribute_def, + symbol_name_index); + bfd_set_error (bfd_error_bad_value); + return false; + break; + } + break; + case ieee_external_reference_info_record_enum: + /* Skip over ATX record. */ + parse_int (&(ieee->h), &value); + parse_int (&(ieee->h), &value); + parse_int (&(ieee->h), &value); + parse_int (&(ieee->h), &value); + break; + } + } + break; + case ieee_value_record_enum >> 8: + { + unsigned int symbol_name_index; + ieee_symbol_index_type symbol_ignore; + boolean pcrel_ignore; + unsigned int extra; + next_byte (&(ieee->h)); + next_byte (&(ieee->h)); + + symbol_name_index = must_parse_int (&(ieee->h)); + parse_expression (ieee, + &symbol->symbol.value, + &symbol_ignore, + &pcrel_ignore, + &extra, + &symbol->symbol.section); + + symbol->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + + } + break; + case ieee_weak_external_reference_enum: + { + bfd_vma size; + bfd_vma value; + next_byte (&(ieee->h)); + /* Throw away the external reference index */ + (void) must_parse_int (&(ieee->h)); + /* Fetch the default size if not resolved */ + size = must_parse_int (&(ieee->h)); + /* Fetch the defautlt value if available */ + if (parse_int (&(ieee->h), &value) == false) + { + value = 0; + } + /* This turns into a common */ + symbol->symbol.section = bfd_com_section_ptr; + symbol->symbol.value = size; + } + break; + + case ieee_external_reference_enum: + next_byte (&(ieee->h)); + + symbol = get_symbol (abfd, ieee, symbol, &symbol_count, + &prev_reference_ptr, + &ieee->external_reference_max_index, 'X'); + if (symbol == NULL) + return false; + + symbol->symbol.the_bfd = abfd; + symbol->symbol.name = read_id (&(ieee->h)); + symbol->symbol.udata.p = (PTR) NULL; + symbol->symbol.section = bfd_und_section_ptr; + symbol->symbol.value = (bfd_vma) 0; + symbol->symbol.flags = 0; + + BFD_ASSERT (symbol->index >= ieee->external_reference_min_index); + break; + + default: + loop = false; + } + } + + if (ieee->external_symbol_max_index != 0) + { + ieee->external_symbol_count = + ieee->external_symbol_max_index - + ieee->external_symbol_min_index + 1; + } + else + { + ieee->external_symbol_count = 0; + } + + if (ieee->external_reference_max_index != 0) + { + ieee->external_reference_count = + ieee->external_reference_max_index - + ieee->external_reference_min_index + 1; + } + else + { + ieee->external_reference_count = 0; + } + + abfd->symcount = + ieee->external_reference_count + ieee->external_symbol_count; + + if (symbol_count != abfd->symcount) + { + /* There are gaps in the table -- */ + ieee->symbol_table_full = false; + } + + *prev_symbols_ptr = (ieee_symbol_type *) NULL; + *prev_reference_ptr = (ieee_symbol_type *) NULL; + + return true; +} + +static boolean +ieee_slurp_symbol_table (abfd) + bfd *abfd; +{ + if (IEEE_DATA (abfd)->read_symbols == false) + { + if (! ieee_slurp_external_symbols (abfd)) + return false; + IEEE_DATA (abfd)->read_symbols = true; + } + return true; +} + +long +ieee_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (! ieee_slurp_symbol_table (abfd)) + return -1; + + return (abfd->symcount != 0) ? + (abfd->symcount + 1) * (sizeof (ieee_symbol_type *)) : 0; +} + +/* +Move from our internal lists to the canon table, and insert in +symbol index order +*/ + +extern const bfd_target ieee_vec; + +long +ieee_get_symtab (abfd, location) + bfd *abfd; + asymbol **location; +{ + ieee_symbol_type *symp; + static bfd dummy_bfd; + static asymbol empty_symbol = + /* the_bfd, name, value, attr, section */ + {&dummy_bfd, " ieee empty", (symvalue) 0, BSF_DEBUGGING, bfd_abs_section_ptr}; + + if (abfd->symcount) + { + ieee_data_type *ieee = IEEE_DATA (abfd); + dummy_bfd.xvec = &ieee_vec; + if (! ieee_slurp_symbol_table (abfd)) + return -1; + + if (ieee->symbol_table_full == false) + { + /* Arrgh - there are gaps in the table, run through and fill them */ + /* up with pointers to a null place */ + unsigned int i; + for (i = 0; i < abfd->symcount; i++) + { + location[i] = &empty_symbol; + } + } + + ieee->external_symbol_base_offset = -ieee->external_symbol_min_index; + for (symp = IEEE_DATA (abfd)->external_symbols; + symp != (ieee_symbol_type *) NULL; + symp = symp->next) + { + /* Place into table at correct index locations */ + location[symp->index + ieee->external_symbol_base_offset] = &symp->symbol; + } + + /* The external refs are indexed in a bit */ + ieee->external_reference_base_offset = + -ieee->external_reference_min_index + ieee->external_symbol_count; + + for (symp = IEEE_DATA (abfd)->external_reference; + symp != (ieee_symbol_type *) NULL; + symp = symp->next) + { + location[symp->index + ieee->external_reference_base_offset] = + &symp->symbol; + + } + } + if (abfd->symcount) + { + location[abfd->symcount] = (asymbol *) NULL; + } + return abfd->symcount; +} + +static asection * +get_section_entry (abfd, ieee, index) + bfd *abfd; + ieee_data_type *ieee; + unsigned int index; +{ + if (ieee->section_table[index] == (asection *) NULL) + { + char *tmp = bfd_alloc (abfd, 11); + asection *section; + + if (!tmp) + return NULL; + sprintf (tmp, " fsec%4d", index); + section = bfd_make_section (abfd, tmp); + ieee->section_table[index] = section; + section->flags = SEC_NO_FLAGS; + section->target_index = index; + ieee->section_table[index] = section; + } + return ieee->section_table[index]; +} + +static void +ieee_slurp_sections (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + file_ptr offset = ieee->w.r.section_part; + asection *section = (asection *) NULL; + char *name; + + if (offset != 0) + { + bfd_byte section_type[3]; + ieee_seek (abfd, offset); + while (true) + { + switch (this_byte (&(ieee->h))) + { + case ieee_section_type_enum: + { + unsigned int section_index; + next_byte (&(ieee->h)); + section_index = must_parse_int (&(ieee->h)); + /* Fixme to be nice about a silly number of sections */ + BFD_ASSERT (section_index < NSECTIONS); + + section = get_section_entry (abfd, ieee, section_index); + + section_type[0] = this_byte_and_next (&(ieee->h)); + + /* Set minimal section attributes. Attributes are + extended later, based on section contents. */ + + switch (section_type[0]) + { + case 0xC1: + /* Normal attributes for absolute sections */ + section_type[1] = this_byte (&(ieee->h)); + section->flags = SEC_ALLOC; + switch (section_type[1]) + { + case 0xD3: /* AS Absolute section attributes */ + next_byte (&(ieee->h)); + section_type[2] = this_byte (&(ieee->h)); + switch (section_type[2]) + { + case 0xD0: + /* Normal code */ + next_byte (&(ieee->h)); + section->flags |= SEC_CODE; + break; + case 0xC4: + /* Normal data */ + next_byte (&(ieee->h)); + section->flags |= SEC_DATA; + break; + case 0xD2: + next_byte (&(ieee->h)); + /* Normal rom data */ + section->flags |= SEC_ROM | SEC_DATA; + break; + default: + break; + } + } + break; + case 0xC3: /* Named relocatable sections (type C) */ + section_type[1] = this_byte (&(ieee->h)); + section->flags = SEC_ALLOC; + switch (section_type[1]) + { + case 0xD0: /* Normal code (CP) */ + next_byte (&(ieee->h)); + section->flags |= SEC_CODE; + break; + case 0xC4: /* Normal data (CD) */ + next_byte (&(ieee->h)); + section->flags |= SEC_DATA; + break; + case 0xD2: /* Normal rom data (CR) */ + next_byte (&(ieee->h)); + section->flags |= SEC_ROM | SEC_DATA; + break; + default: + break; + } + } + + /* Read section name, use it if non empty. */ + name = read_id (&ieee->h); + if (name[0]) + section->name = name; + + /* Skip these fields, which we don't care about */ + { + bfd_vma parent, brother, context; + parse_int (&(ieee->h), &parent); + parse_int (&(ieee->h), &brother); + parse_int (&(ieee->h), &context); + } + } + break; + case ieee_section_alignment_enum: + { + unsigned int section_index; + bfd_vma value; + asection *section; + next_byte (&(ieee->h)); + section_index = must_parse_int (&ieee->h); + section = get_section_entry (abfd, ieee, section_index); + if (section_index > ieee->section_count) + { + ieee->section_count = section_index; + } + section->alignment_power = + bfd_log2 (must_parse_int (&ieee->h)); + (void) parse_int (&(ieee->h), &value); + } + break; + case ieee_e2_first_byte_enum: + { + ieee_record_enum_type t = (ieee_record_enum_type) (read_2bytes (&(ieee->h))); + + switch (t) + { + case ieee_section_size_enum: + section = ieee->section_table[must_parse_int (&(ieee->h))]; + section->_raw_size = must_parse_int (&(ieee->h)); + break; + case ieee_physical_region_size_enum: + section = ieee->section_table[must_parse_int (&(ieee->h))]; + section->_raw_size = must_parse_int (&(ieee->h)); + break; + case ieee_region_base_address_enum: + section = ieee->section_table[must_parse_int (&(ieee->h))]; + section->vma = must_parse_int (&(ieee->h)); + section->lma = section->vma; + break; + case ieee_mau_size_enum: + must_parse_int (&(ieee->h)); + must_parse_int (&(ieee->h)); + break; + case ieee_m_value_enum: + must_parse_int (&(ieee->h)); + must_parse_int (&(ieee->h)); + break; + case ieee_section_base_address_enum: + section = ieee->section_table[must_parse_int (&(ieee->h))]; + section->vma = must_parse_int (&(ieee->h)); + section->lma = section->vma; + break; + case ieee_section_offset_enum: + (void) must_parse_int (&(ieee->h)); + (void) must_parse_int (&(ieee->h)); + break; + default: + return; + } + } + break; + default: + return; + } + } + } +} + +/* Make a section for the debugging information, if any. We don't try + to interpret the debugging information; we just point the section + at the area in the file so that program which understand can dig it + out. */ + +static boolean +ieee_slurp_debug (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + asection *sec; + + if (ieee->w.r.debug_information_part == 0) + return true; + + sec = bfd_make_section (abfd, ".debug"); + if (sec == NULL) + return false; + sec->flags |= SEC_DEBUGGING | SEC_HAS_CONTENTS; + sec->filepos = ieee->w.r.debug_information_part; + sec->_raw_size = ieee->w.r.data_part - ieee->w.r.debug_information_part; + + return true; +} + +/*********************************************************************** +* archive stuff +*/ + +const bfd_target * +ieee_archive_p (abfd) + bfd *abfd; +{ + char *library; + boolean loop; + unsigned int i; + unsigned char buffer[512]; + file_ptr buffer_offset = 0; + ieee_ar_data_type *save = abfd->tdata.ieee_ar_data; + ieee_ar_data_type *ieee; + abfd->tdata.ieee_ar_data = (ieee_ar_data_type *) bfd_alloc (abfd, sizeof (ieee_ar_data_type)); + if (!abfd->tdata.ieee_ar_data) + return NULL; + ieee = IEEE_AR_DATA (abfd); + + /* FIXME: Check return value. I'm not sure whether it needs to read + the entire buffer or not. */ + bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd); + + ieee->h.first_byte = buffer; + ieee->h.input_p = buffer; + + ieee->h.abfd = abfd; + + if (this_byte (&(ieee->h)) != Module_Beginning) + { + abfd->tdata.ieee_ar_data = save; + return (const bfd_target *) NULL; + } + + next_byte (&(ieee->h)); + library = read_id (&(ieee->h)); + if (strcmp (library, "LIBRARY") != 0) + { + bfd_release (abfd, ieee); + abfd->tdata.ieee_ar_data = save; + return (const bfd_target *) NULL; + } + /* Throw away the filename */ + read_id (&(ieee->h)); + + ieee->element_count = 0; + ieee->element_index = 0; + + next_byte (&(ieee->h)); /* Drop the ad part */ + must_parse_int (&(ieee->h)); /* And the two dummy numbers */ + must_parse_int (&(ieee->h)); + + loop = true; + /* Read the index of the BB table */ + while (loop) + { + ieee_ar_obstack_type t; + int rec = read_2bytes (&(ieee->h)); + if (rec == (int) ieee_assign_value_to_variable_enum) + { + must_parse_int (&(ieee->h)); + t.file_offset = must_parse_int (&(ieee->h)); + t.abfd = (bfd *) NULL; + ieee->element_count++; + + bfd_alloc_grow (abfd, (PTR) &t, sizeof t); + + /* Make sure that we don't go over the end of the buffer */ + + if ((size_t) ieee_pos (abfd) > sizeof (buffer) / 2) + { + /* Past half way, reseek and reprime */ + buffer_offset += ieee_pos (abfd); + if (bfd_seek (abfd, buffer_offset, SEEK_SET) != 0) + return NULL; + /* FIXME: Check return value. I'm not sure whether it + needs to read the entire buffer or not. */ + bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd); + ieee->h.first_byte = buffer; + ieee->h.input_p = buffer; + } + } + else + loop = false; + } + + ieee->elements = (ieee_ar_obstack_type *) bfd_alloc_finish (abfd); + if (!ieee->elements) + return (const bfd_target *) NULL; + + /* Now scan the area again, and replace BB offsets with file */ + /* offsets */ + + for (i = 2; i < ieee->element_count; i++) + { + if (bfd_seek (abfd, ieee->elements[i].file_offset, SEEK_SET) != 0) + return NULL; + /* FIXME: Check return value. I'm not sure whether it needs to + read the entire buffer or not. */ + bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd); + ieee->h.first_byte = buffer; + ieee->h.input_p = buffer; + + next_byte (&(ieee->h)); /* Drop F8 */ + next_byte (&(ieee->h)); /* Drop 14 */ + must_parse_int (&(ieee->h)); /* Drop size of block */ + if (must_parse_int (&(ieee->h)) != 0) + { + /* This object has been deleted */ + ieee->elements[i].file_offset = 0; + } + else + { + ieee->elements[i].file_offset = must_parse_int (&(ieee->h)); + } + } + +/* abfd->has_armap = ;*/ + return abfd->xvec; +} + +static boolean +ieee_mkobject (abfd) + bfd *abfd; +{ + abfd->tdata.ieee_data = (ieee_data_type *) bfd_zalloc (abfd, sizeof (ieee_data_type)); + return abfd->tdata.ieee_data ? true : false; +} + +const bfd_target * +ieee_object_p (abfd) + bfd *abfd; +{ + char *processor; + unsigned int part; + ieee_data_type *ieee; + unsigned char buffer[300]; + ieee_data_type *save = IEEE_DATA (abfd); + + abfd->tdata.ieee_data = 0; + ieee_mkobject (abfd); + + ieee = IEEE_DATA (abfd); + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto fail; + /* Read the first few bytes in to see if it makes sense */ + /* FIXME: Check return value. I'm not sure whether it needs to read + the entire buffer or not. */ + bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd); + + ieee->h.input_p = buffer; + if (this_byte_and_next (&(ieee->h)) != Module_Beginning) + goto got_wrong_format; + + ieee->read_symbols = false; + ieee->read_data = false; + ieee->section_count = 0; + ieee->external_symbol_max_index = 0; + ieee->external_symbol_min_index = IEEE_PUBLIC_BASE; + ieee->external_reference_min_index = IEEE_REFERENCE_BASE; + ieee->external_reference_max_index = 0; + ieee->h.abfd = abfd; + memset ((PTR) ieee->section_table, 0, sizeof (ieee->section_table)); + + processor = ieee->mb.processor = read_id (&(ieee->h)); + if (strcmp (processor, "LIBRARY") == 0) + goto got_wrong_format; + ieee->mb.module_name = read_id (&(ieee->h)); + if (abfd->filename == (CONST char *) NULL) + { + abfd->filename = ieee->mb.module_name; + } + /* Determine the architecture and machine type of the object file. + */ + { + const bfd_arch_info_type *arch = bfd_scan_arch (processor); + if (arch == 0) + goto got_wrong_format; + abfd->arch_info = arch; + } + + if (this_byte (&(ieee->h)) != (int) ieee_address_descriptor_enum) + { + goto fail; + } + next_byte (&(ieee->h)); + + if (parse_int (&(ieee->h), &ieee->ad.number_of_bits_mau) == false) + { + goto fail; + } + if (parse_int (&(ieee->h), &ieee->ad.number_of_maus_in_address) == false) + { + goto fail; + } + + /* If there is a byte order info, take it */ + if (this_byte (&(ieee->h)) == (int) ieee_variable_L_enum || + this_byte (&(ieee->h)) == (int) ieee_variable_M_enum) + next_byte (&(ieee->h)); + + for (part = 0; part < N_W_VARIABLES; part++) + { + boolean ok; + if (read_2bytes (&(ieee->h)) != (int) ieee_assign_value_to_variable_enum) + { + goto fail; + } + if (this_byte_and_next (&(ieee->h)) != part) + { + goto fail; + } + + ieee->w.offset[part] = parse_i (&(ieee->h), &ok); + if (ok == false) + { + goto fail; + } + + } + + if (ieee->w.r.external_part != 0) + abfd->flags = HAS_SYMS; + + /* By now we know that this is a real IEEE file, we're going to read + the whole thing into memory so that we can run up and down it + quickly. We can work out how big the file is from the trailer + record */ + + IEEE_DATA (abfd)->h.first_byte = + (unsigned char *) bfd_alloc (ieee->h.abfd, ieee->w.r.me_record + 1); + if (!IEEE_DATA (abfd)->h.first_byte) + goto fail; + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto fail; + /* FIXME: Check return value. I'm not sure whether it needs to read + the entire buffer or not. */ + bfd_read ((PTR) (IEEE_DATA (abfd)->h.first_byte), 1, + ieee->w.r.me_record + 1, abfd); + + ieee_slurp_sections (abfd); + + if (! ieee_slurp_debug (abfd)) + goto fail; + + /* Parse section data to activate file and section flags implied by + section contents. */ + + if (! ieee_slurp_section_data (abfd)) + goto fail; + + return abfd->xvec; +got_wrong_format: + bfd_set_error (bfd_error_wrong_format); +fail: + (void) bfd_release (abfd, ieee); + abfd->tdata.ieee_data = save; + return (const bfd_target *) NULL; +} + +void +ieee_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); + if (symbol->name[0] == ' ') + ret->name = "* empty table entry "; + if (!symbol->section) + ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A'; +} + +void +ieee_print_symbol (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: +#if 0 + fprintf (file, "%4x %2x", aout_symbol (symbol)->desc & 0xffff, + aout_symbol (symbol)->other & 0xff); +#endif + BFD_FAIL (); + break; + case bfd_print_symbol_all: + { + const char *section_name = + (symbol->section == (asection *) NULL + ? "*abs" + : symbol->section->name); + if (symbol->name[0] == ' ') + { + fprintf (file, "* empty table entry "); + } + else + { + bfd_print_symbol_vandf ((PTR) file, symbol); + + fprintf (file, " %-5s %04x %02x %s", + section_name, + (unsigned) ieee_symbol (symbol)->index, + (unsigned) 0, + symbol->name); + } + } + break; + } +} + +static boolean +do_one (ieee, current_map, location_ptr, s, iterations) + ieee_data_type *ieee; + ieee_per_section_type *current_map; + unsigned char *location_ptr; + asection *s; + int iterations; +{ + switch (this_byte (&(ieee->h))) + { + case ieee_load_constant_bytes_enum: + { + unsigned int number_of_maus; + unsigned int i; + next_byte (&(ieee->h)); + number_of_maus = must_parse_int (&(ieee->h)); + + for (i = 0; i < number_of_maus; i++) + { + location_ptr[current_map->pc++] = this_byte (&(ieee->h)); + next_byte (&(ieee->h)); + } + } + break; + + case ieee_load_with_relocation_enum: + { + boolean loop = true; + next_byte (&(ieee->h)); + while (loop) + { + switch (this_byte (&(ieee->h))) + { + case ieee_variable_R_enum: + + case ieee_function_signed_open_b_enum: + case ieee_function_unsigned_open_b_enum: + case ieee_function_either_open_b_enum: + { + unsigned int extra = 4; + boolean pcrel = false; + asection *section; + ieee_reloc_type *r = + (ieee_reloc_type *) bfd_alloc (ieee->h.abfd, + sizeof (ieee_reloc_type)); + if (!r) + return false; + + *(current_map->reloc_tail_ptr) = r; + current_map->reloc_tail_ptr = &r->next; + r->next = (ieee_reloc_type *) NULL; + next_byte (&(ieee->h)); +/* abort();*/ + r->relent.sym_ptr_ptr = 0; + parse_expression (ieee, + &r->relent.addend, + &r->symbol, + &pcrel, &extra, §ion); + r->relent.address = current_map->pc; + s->flags |= SEC_RELOC; + s->owner->flags |= HAS_RELOC; + s->reloc_count++; + if (r->relent.sym_ptr_ptr == 0) + { + r->relent.sym_ptr_ptr = section->symbol_ptr_ptr; + } + + if (this_byte (&(ieee->h)) == (int) ieee_comma) + { + next_byte (&(ieee->h)); + /* Fetch number of bytes to pad */ + extra = must_parse_int (&(ieee->h)); + }; + + switch (this_byte (&(ieee->h))) + { + case ieee_function_signed_close_b_enum: + next_byte (&(ieee->h)); + break; + case ieee_function_unsigned_close_b_enum: + next_byte (&(ieee->h)); + break; + case ieee_function_either_close_b_enum: + next_byte (&(ieee->h)); + break; + default: + break; + } + /* Build a relocation entry for this type */ + /* If pc rel then stick -ve pc into instruction + and take out of reloc .. + + I've changed this. It's all too complicated. I + keep 0 in the instruction now. */ + + switch (extra) + { + case 0: + case 4: + + if (pcrel == true) + { +#if KEEPMINUSPCININST + bfd_put_32 (ieee->h.abfd, -current_map->pc, location_ptr + + current_map->pc); + r->relent.howto = &rel32_howto; + r->relent.addend -= + current_map->pc; +#else + bfd_put_32 (ieee->h.abfd, 0, location_ptr + + current_map->pc); + r->relent.howto = &rel32_howto; +#endif + } + else + { + bfd_put_32 (ieee->h.abfd, 0, location_ptr + + current_map->pc); + r->relent.howto = &abs32_howto; + } + current_map->pc += 4; + break; + case 2: + if (pcrel == true) + { +#if KEEPMINUSPCININST + bfd_put_16 (ieee->h.abfd, (int) (-current_map->pc), location_ptr + current_map->pc); + r->relent.addend -= current_map->pc; + r->relent.howto = &rel16_howto; +#else + + bfd_put_16 (ieee->h.abfd, 0, location_ptr + current_map->pc); + r->relent.howto = &rel16_howto; +#endif + } + + else + { + bfd_put_16 (ieee->h.abfd, 0, location_ptr + current_map->pc); + r->relent.howto = &abs16_howto; + } + current_map->pc += 2; + break; + case 1: + if (pcrel == true) + { +#if KEEPMINUSPCININST + bfd_put_8 (ieee->h.abfd, (int) (-current_map->pc), location_ptr + current_map->pc); + r->relent.addend -= current_map->pc; + r->relent.howto = &rel8_howto; +#else + bfd_put_8 (ieee->h.abfd, 0, location_ptr + current_map->pc); + r->relent.howto = &rel8_howto; +#endif + } + else + { + bfd_put_8 (ieee->h.abfd, 0, location_ptr + current_map->pc); + r->relent.howto = &abs8_howto; + } + current_map->pc += 1; + break; + + default: + BFD_FAIL (); + return false; + } + } + break; + default: + { + bfd_vma this_size; + if (parse_int (&(ieee->h), &this_size) == true) + { + unsigned int i; + for (i = 0; i < this_size; i++) + { + location_ptr[current_map->pc++] = this_byte (&(ieee->h)); + next_byte (&(ieee->h)); + } + } + else + { + loop = false; + } + } + } + + /* Prevent more than the first load-item of an LR record + from being repeated (MRI convention). */ + if (iterations != 1) + loop = false; + } + } + } + return true; +} + +/* Read in all the section data and relocation stuff too */ +static boolean +ieee_slurp_section_data (abfd) + bfd *abfd; +{ + bfd_byte *location_ptr = (bfd_byte *) NULL; + ieee_data_type *ieee = IEEE_DATA (abfd); + unsigned int section_number; + + ieee_per_section_type *current_map = (ieee_per_section_type *) NULL; + asection *s; + /* Seek to the start of the data area */ + if (ieee->read_data == true) + return true; + ieee->read_data = true; + ieee_seek (abfd, ieee->w.r.data_part); + + /* Allocate enough space for all the section contents */ + + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + ieee_per_section_type *per = (ieee_per_section_type *) s->used_by_bfd; + if ((s->flags & SEC_DEBUGGING) != 0) + continue; + per->data = (bfd_byte *) bfd_alloc (ieee->h.abfd, s->_raw_size); + if (!per->data) + return false; + /*SUPPRESS 68*/ + per->reloc_tail_ptr = + (ieee_reloc_type **) & (s->relocation); + } + + while (true) + { + switch (this_byte (&(ieee->h))) + { + /* IF we see anything strange then quit */ + default: + return true; + + case ieee_set_current_section_enum: + next_byte (&(ieee->h)); + section_number = must_parse_int (&(ieee->h)); + s = ieee->section_table[section_number]; + s->flags |= SEC_LOAD | SEC_HAS_CONTENTS; + current_map = (ieee_per_section_type *) s->used_by_bfd; + location_ptr = current_map->data - s->vma; + /* The document I have says that Microtec's compilers reset */ + /* this after a sec section, even though the standard says not */ + /* to. SO .. */ + current_map->pc = s->vma; + break; + + case ieee_e2_first_byte_enum: + next_byte (&(ieee->h)); + switch (this_byte (&(ieee->h))) + { + case ieee_set_current_pc_enum & 0xff: + { + bfd_vma value; + ieee_symbol_index_type symbol; + unsigned int extra; + boolean pcrel; + next_byte (&(ieee->h)); + must_parse_int (&(ieee->h)); /* Thow away section #*/ + parse_expression (ieee, &value, + &symbol, + &pcrel, &extra, + 0); + current_map->pc = value; + BFD_ASSERT ((unsigned) (value - s->vma) <= s->_raw_size); + } + break; + + case ieee_value_starting_address_enum & 0xff: + /* We've got to the end of the data now - */ + return true; + default: + BFD_FAIL (); + return false; + } + break; + case ieee_repeat_data_enum: + { + /* Repeat the following LD or LR n times - we do this by + remembering the stream pointer before running it and + resetting it and running it n times. We special case + the repetition of a repeat_data/load_constant + */ + + unsigned int iterations; + unsigned char *start; + next_byte (&(ieee->h)); + iterations = must_parse_int (&(ieee->h)); + start = ieee->h.input_p; + if (start[0] == (int) ieee_load_constant_bytes_enum && + start[1] == 1) + { + while (iterations != 0) + { + location_ptr[current_map->pc++] = start[2]; + iterations--; + } + next_byte (&(ieee->h)); + next_byte (&(ieee->h)); + next_byte (&(ieee->h)); + } + else + { + while (iterations != 0) + { + ieee->h.input_p = start; + if (!do_one (ieee, current_map, location_ptr, s, + iterations)) + return false; + iterations--; + } + } + } + break; + case ieee_load_constant_bytes_enum: + case ieee_load_with_relocation_enum: + { + if (!do_one (ieee, current_map, location_ptr, s, 1)) + return false; + } + } + } +} + +boolean +ieee_new_section_hook (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + newsect->used_by_bfd = (PTR) + bfd_alloc (abfd, sizeof (ieee_per_section_type)); + if (!newsect->used_by_bfd) + return false; + ieee_per_section (newsect)->data = (bfd_byte *) NULL; + ieee_per_section (newsect)->section = newsect; + return true; +} + +long +ieee_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if ((asect->flags & SEC_DEBUGGING) != 0) + return 0; + if (! ieee_slurp_section_data (abfd)) + return -1; + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +static boolean +ieee_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + ieee_per_section_type *p = (ieee_per_section_type *) section->used_by_bfd; + if ((section->flags & SEC_DEBUGGING) != 0) + return _bfd_generic_get_section_contents (abfd, section, location, + offset, count); + ieee_slurp_section_data (abfd); + (void) memcpy ((PTR) location, (PTR) (p->data + offset), (unsigned) count); + return true; +} + +long +ieee_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ +/* ieee_per_section_type *p = (ieee_per_section_type *) section->used_by_bfd;*/ + ieee_reloc_type *src = (ieee_reloc_type *) (section->relocation); + ieee_data_type *ieee = IEEE_DATA (abfd); + + if ((section->flags & SEC_DEBUGGING) != 0) + return 0; + + while (src != (ieee_reloc_type *) NULL) + { + /* Work out which symbol to attach it this reloc to */ + switch (src->symbol.letter) + { + case 'I': + src->relent.sym_ptr_ptr = + symbols + src->symbol.index + ieee->external_symbol_base_offset; + break; + case 'X': + src->relent.sym_ptr_ptr = + symbols + src->symbol.index + ieee->external_reference_base_offset; + break; + case 0: + src->relent.sym_ptr_ptr = + src->relent.sym_ptr_ptr[0]->section->symbol_ptr_ptr; + break; + default: + + BFD_FAIL (); + } + *relptr++ = &src->relent; + src = src->next; + } + *relptr = (arelent *) NULL; + return section->reloc_count; +} + +static int +comp (ap, bp) + CONST PTR ap; + CONST PTR bp; +{ + arelent *a = *((arelent **) ap); + arelent *b = *((arelent **) bp); + return a->address - b->address; +} + +/* Write the section headers. */ + +static boolean +ieee_write_section_part (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + asection *s; + ieee->w.r.section_part = bfd_tell (abfd); + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if (! bfd_is_abs_section (s) + && (s->flags & SEC_DEBUGGING) == 0) + { + if (! ieee_write_byte (abfd, ieee_section_type_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + + IEEE_SECTION_NUMBER_BASE))) + return false; + + if (abfd->flags & EXEC_P) + { + /* This image is executable, so output absolute sections */ + if (! ieee_write_byte (abfd, ieee_variable_A_enum) + || ! ieee_write_byte (abfd, ieee_variable_S_enum)) + return false; + } + else + { + if (! ieee_write_byte (abfd, ieee_variable_C_enum)) + return false; + } + + switch (s->flags & (SEC_CODE | SEC_DATA | SEC_ROM)) + { + case SEC_CODE | SEC_LOAD: + case SEC_CODE: + if (! ieee_write_byte (abfd, ieee_variable_P_enum)) + return false; + break; + case SEC_DATA: + default: + if (! ieee_write_byte (abfd, ieee_variable_D_enum)) + return false; + break; + case SEC_ROM: + case SEC_ROM | SEC_DATA: + case SEC_ROM | SEC_LOAD: + case SEC_ROM | SEC_DATA | SEC_LOAD: + if (! ieee_write_byte (abfd, ieee_variable_R_enum)) + return false; + } + + + if (! ieee_write_id (abfd, s->name)) + return false; +#if 0 + ieee_write_int (abfd, 0); /* Parent */ + ieee_write_int (abfd, 0); /* Brother */ + ieee_write_int (abfd, 0); /* Context */ +#endif + /* Alignment */ + if (! ieee_write_byte (abfd, ieee_section_alignment_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_int (abfd, 1 << s->alignment_power)) + return false; + + /* Size */ + if (! ieee_write_2bytes (abfd, ieee_section_size_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_int (abfd, s->_raw_size)) + return false; + if (abfd->flags & EXEC_P) + { + /* Relocateable sections don't have asl records */ + /* Vma */ + if (! ieee_write_2bytes (abfd, ieee_section_base_address_enum) + || ! ieee_write_byte (abfd, + ((bfd_byte) + (s->index + + IEEE_SECTION_NUMBER_BASE))) + || ! ieee_write_int (abfd, s->vma)) + return false; + } + } + } + + return true; +} + + +static boolean +do_with_relocs (abfd, s) + bfd *abfd; + asection *s; +{ + unsigned int number_of_maus_in_address = + bfd_arch_bits_per_address (abfd) / bfd_arch_bits_per_byte (abfd); + unsigned int relocs_to_go = s->reloc_count; + bfd_byte *stream = ieee_per_section (s)->data; + arelent **p = s->orelocation; + bfd_size_type current_byte_index = 0; + + qsort (s->orelocation, + relocs_to_go, + sizeof (arelent **), + comp); + + /* Output the section preheader */ + if (! ieee_write_byte (abfd, ieee_set_current_section_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_2bytes (abfd, ieee_set_current_pc_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + IEEE_SECTION_NUMBER_BASE))) + return false; + if ((abfd->flags & EXEC_P) != 0 && relocs_to_go == 0) + { + if (! ieee_write_int (abfd, s->vma)) + return false; + } + else + { + if (! ieee_write_expression (abfd, 0, s->symbol, 0, 0)) + return false; + } + + if (relocs_to_go == 0) + { + /* If there aren't any relocations then output the load constant + byte opcode rather than the load with relocation opcode */ + + while (current_byte_index < s->_raw_size) + { + bfd_size_type run; + unsigned int MAXRUN = 127; + run = MAXRUN; + if (run > s->_raw_size - current_byte_index) + { + run = s->_raw_size - current_byte_index; + } + + if (run != 0) + { + if (! ieee_write_byte (abfd, ieee_load_constant_bytes_enum)) + return false; + /* Output a stream of bytes */ + if (! ieee_write_int (abfd, run)) + return false; + if (bfd_write ((PTR) (stream + current_byte_index), + 1, + run, + abfd) + != run) + return false; + current_byte_index += run; + } + } + } + else + { + if (! ieee_write_byte (abfd, ieee_load_with_relocation_enum)) + return false; + + /* Output the data stream as the longest sequence of bytes + possible, allowing for the a reasonable packet size and + relocation stuffs. */ + + if ((PTR) stream == (PTR) NULL) + { + /* Outputting a section without data, fill it up */ + stream = (unsigned char *) (bfd_alloc (abfd, s->_raw_size)); + if (!stream) + return false; + memset ((PTR) stream, 0, (size_t) s->_raw_size); + } + while (current_byte_index < s->_raw_size) + { + bfd_size_type run; + unsigned int MAXRUN = 127; + if (relocs_to_go) + { + run = (*p)->address - current_byte_index; + if (run > MAXRUN) + run = MAXRUN; + } + else + { + run = MAXRUN; + } + if (run > s->_raw_size - current_byte_index) + { + run = s->_raw_size - current_byte_index; + } + + if (run != 0) + { + /* Output a stream of bytes */ + if (! ieee_write_int (abfd, run)) + return false; + if (bfd_write ((PTR) (stream + current_byte_index), + 1, + run, + abfd) + != run) + return false; + current_byte_index += run; + } + /* Output any relocations here */ + if (relocs_to_go && (*p) && (*p)->address == current_byte_index) + { + while (relocs_to_go + && (*p) && (*p)->address == current_byte_index) + { + arelent *r = *p; + bfd_signed_vma ov; + +#if 0 + if (r->howto->pc_relative) + { + r->addend += current_byte_index; + } +#endif + + switch (r->howto->size) + { + case 2: + + ov = bfd_get_signed_32 (abfd, + stream + current_byte_index); + current_byte_index += 4; + break; + case 1: + ov = bfd_get_signed_16 (abfd, + stream + current_byte_index); + current_byte_index += 2; + break; + case 0: + ov = bfd_get_signed_8 (abfd, + stream + current_byte_index); + current_byte_index++; + break; + default: + ov = 0; + BFD_FAIL (); + return false; + } + + ov &= r->howto->src_mask; + + if (r->howto->pc_relative + && ! r->howto->pcrel_offset) + ov += r->address; + + if (! ieee_write_byte (abfd, + ieee_function_either_open_b_enum)) + return false; + +/* abort();*/ + + if (r->sym_ptr_ptr != (asymbol **) NULL) + { + if (! ieee_write_expression (abfd, r->addend + ov, + *(r->sym_ptr_ptr), + r->howto->pc_relative, + s->index)) + return false; + } + else + { + if (! ieee_write_expression (abfd, r->addend + ov, + (asymbol *) NULL, + r->howto->pc_relative, + s->index)) + return false; + } + + if (number_of_maus_in_address + != bfd_get_reloc_size (r->howto)) + { + if (! ieee_write_int (abfd, + bfd_get_reloc_size (r->howto))) + return false; + } + if (! ieee_write_byte (abfd, + ieee_function_either_close_b_enum)) + return false; + + relocs_to_go--; + p++; + } + + } + } + } + + return true; +} + +/* If there are no relocations in the output section then we can be + clever about how we write. We block items up into a max of 127 + bytes. */ + +static boolean +do_as_repeat (abfd, s) + bfd *abfd; + asection *s; +{ + if (s->_raw_size) + { + if (! ieee_write_byte (abfd, ieee_set_current_section_enum) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_byte (abfd, ieee_set_current_pc_enum >> 8) + || ! ieee_write_byte (abfd, ieee_set_current_pc_enum & 0xff) + || ! ieee_write_byte (abfd, + (bfd_byte) (s->index + + IEEE_SECTION_NUMBER_BASE)) + || ! ieee_write_int (abfd, s->vma) + || ! ieee_write_byte (abfd, ieee_repeat_data_enum) + || ! ieee_write_int (abfd, s->_raw_size) + || ! ieee_write_byte (abfd, ieee_load_constant_bytes_enum) + || ! ieee_write_byte (abfd, 1) + || ! ieee_write_byte (abfd, 0)) + return false; + } + + return true; +} + +static boolean +do_without_relocs (abfd, s) + bfd *abfd; + asection *s; +{ + bfd_byte *stream = ieee_per_section (s)->data; + + if (stream == 0 || ((s->flags & SEC_LOAD) == 0)) + { + if (! do_as_repeat (abfd, s)) + return false; + } + else + { + unsigned int i; + for (i = 0; i < s->_raw_size; i++) + { + if (stream[i] != 0) + { + if (! do_with_relocs (abfd, s)) + return false; + return true; + } + } + if (! do_as_repeat (abfd, s)) + return false; + } + + return true; +} + + +static unsigned char *output_ptr_start; +static unsigned char *output_ptr; +static unsigned char *output_ptr_end; +static unsigned char *input_ptr_start; +static unsigned char *input_ptr; +static unsigned char *input_ptr_end; +static bfd *input_bfd; +static bfd *output_bfd; +static int output_buffer; + +static void +fill () +{ + /* FIXME: Check return value. I'm not sure whether it needs to read + the entire buffer or not. */ + bfd_read ((PTR) input_ptr_start, 1, input_ptr_end - input_ptr_start, input_bfd); + input_ptr = input_ptr_start; +} +static void +flush () +{ + if (bfd_write ((PTR) (output_ptr_start), 1, output_ptr - output_ptr_start, + output_bfd) + != (bfd_size_type) (output_ptr - output_ptr_start)) + abort (); + output_ptr = output_ptr_start; + output_buffer++; +} + +#define THIS() ( *input_ptr ) +#define NEXT() { input_ptr++; if (input_ptr == input_ptr_end) fill(); } +#define OUT(x) { *output_ptr++ = (x); if(output_ptr == output_ptr_end) flush(); } + +static void +write_int (value) + int value; +{ + if (value >= 0 && value <= 127) + { + OUT (value); + } + else + { + unsigned int length; + /* How many significant bytes ? */ + /* FIXME FOR LONGER INTS */ + if (value & 0xff000000) + { + length = 4; + } + else if (value & 0x00ff0000) + { + length = 3; + } + else if (value & 0x0000ff00) + { + length = 2; + } + else + length = 1; + + OUT ((int) ieee_number_repeat_start_enum + length); + switch (length) + { + case 4: + OUT (value >> 24); + case 3: + OUT (value >> 16); + case 2: + OUT (value >> 8); + case 1: + OUT (value); + } + + } +} + +static void +copy_id () +{ + int length = THIS (); + char ch; + OUT (length); + NEXT (); + while (length--) + { + ch = THIS (); + OUT (ch); + NEXT (); + } +} + +#define VAR(x) ((x | 0x80)) +static void +copy_expression () +{ + int stack[10]; + int *tos = stack; + int value = 0; + while (1) + { + switch (THIS ()) + { + case 0x84: + NEXT (); + value = THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + *tos++ = value; + break; + case 0x83: + NEXT (); + value = THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + *tos++ = value; + break; + case 0x82: + NEXT (); + value = THIS (); + NEXT (); + value = (value << 8) | THIS (); + NEXT (); + *tos++ = value; + break; + case 0x81: + NEXT (); + value = THIS (); + NEXT (); + *tos++ = value; + break; + case 0x80: + NEXT (); + *tos++ = 0; + break; + default: + if (THIS () > 0x84) + { + /* Not a number, just bug out with the answer */ + write_int (*(--tos)); + return; + } + *tos++ = THIS (); + NEXT (); + value = 0; + break; + case 0xa5: + /* PLUS anything */ + { + int value = *(--tos); + value += *(--tos); + *tos++ = value; + NEXT (); + } + break; + case VAR ('R'): + { + int section_number; + ieee_data_type *ieee; + asection *s; + NEXT (); + section_number = THIS (); + + NEXT (); + ieee = IEEE_DATA (input_bfd); + s = ieee->section_table[section_number]; + if (s->output_section) + { + value = s->output_section->vma; + } + else + { + value = 0; + } + value += s->output_offset; + *tos++ = value; + value = 0; + } + break; + case 0x90: + { + NEXT (); + write_int (*(--tos)); + OUT (0x90); + return; + + } + } + } + +} + +/* Drop the int in the buffer, and copy a null into the gap, which we + will overwrite later */ + +struct output_buffer_struct +{ + unsigned char *ptrp; + int buffer; +}; + +static void +fill_int (buf) + struct output_buffer_struct *buf; +{ + if (buf->buffer == output_buffer) + { + /* Still a chance to output the size */ + int value = output_ptr - buf->ptrp + 3; + buf->ptrp[0] = value >> 24; + buf->ptrp[1] = value >> 16; + buf->ptrp[2] = value >> 8; + buf->ptrp[3] = value >> 0; + } +} + +static void +drop_int (buf) + struct output_buffer_struct *buf; +{ + int type = THIS (); + int ch; + if (type <= 0x84) + { + NEXT (); + switch (type) + { + case 0x84: + ch = THIS (); + NEXT (); + case 0x83: + ch = THIS (); + NEXT (); + case 0x82: + ch = THIS (); + NEXT (); + case 0x81: + ch = THIS (); + NEXT (); + case 0x80: + break; + } + } + OUT (0x84); + buf->ptrp = output_ptr; + buf->buffer = output_buffer; + OUT (0); + OUT (0); + OUT (0); + OUT (0); +} + +static void +copy_int () +{ + int type = THIS (); + int ch; + if (type <= 0x84) + { + OUT (type); + NEXT (); + switch (type) + { + case 0x84: + ch = THIS (); + NEXT (); + OUT (ch); + case 0x83: + ch = THIS (); + NEXT (); + OUT (ch); + case 0x82: + ch = THIS (); + NEXT (); + OUT (ch); + case 0x81: + ch = THIS (); + NEXT (); + OUT (ch); + case 0x80: + break; + } + } +} + +#define ID copy_id() +#define INT copy_int() +#define EXP copy_expression() +static void copy_till_end (); +#define INTn(q) copy_int() +#define EXPn(q) copy_expression() + +static void +f1_record () +{ + int ch; + /* ATN record */ + NEXT (); + ch = THIS (); + switch (ch) + { + default: + OUT (0xf1); + OUT (ch); + break; + case 0xc9: + NEXT (); + OUT (0xf1); + OUT (0xc9); + INT; + INT; + ch = THIS (); + switch (ch) + { + case 0x16: + NEXT (); + break; + case 0x01: + NEXT (); + break; + case 0x00: + NEXT (); + INT; + break; + case 0x03: + NEXT (); + INT; + break; + case 0x13: + EXPn (instruction address); + break; + default: + break; + } + break; + case 0xd8: + /* EXternal ref */ + NEXT (); + OUT (0xf1); + OUT (0xd8); + EXP; + EXP; + EXP; + EXP; + break; + case 0xce: + NEXT (); + OUT (0xf1); + OUT (0xce); + INT; + INT; + ch = THIS (); + INT; + switch (ch) + { + case 0x01: + INT; + INT; + break; + case 0x02: + INT; + break; + case 0x04: + EXPn (external function); + break; + case 0x05: + break; + case 0x07: + INTn (line number); + INT; + case 0x08: + break; + case 0x0a: + INTn (locked register); + INT; + break; + case 0x3f: + copy_till_end (); + break; + case 0x3e: + copy_till_end (); + break; + case 0x40: + copy_till_end (); + break; + case 0x41: + ID; + break; + } + } + +} + +static void +f0_record () +{ + /* Attribute record */ + NEXT (); + OUT (0xf0); + INTn (Symbol name); + ID; +} + +static void +copy_till_end () +{ + int ch = THIS (); + while (1) + { + while (ch <= 0x80) + { + OUT (ch); + NEXT (); + ch = THIS (); + } + switch (ch) + { + case 0x84: + OUT (THIS ()); + NEXT (); + case 0x83: + OUT (THIS ()); + NEXT (); + case 0x82: + OUT (THIS ()); + NEXT (); + case 0x81: + OUT (THIS ()); + NEXT (); + OUT (THIS ()); + NEXT (); + + ch = THIS (); + break; + default: + return; + } + } + +} + +static void +f2_record () +{ + NEXT (); + OUT (0xf2); + INT; + NEXT (); + OUT (0xce); + INT; + copy_till_end (); +} + + +static void block (); +static void +f8_record () +{ + int ch; + NEXT (); + ch = THIS (); + switch (ch) + { + case 0x01: + case 0x02: + case 0x03: + /* Unique typedefs for module */ + /* GLobal typedefs */ + /* High level module scope beginning */ + { + struct output_buffer_struct ob; + NEXT (); + OUT (0xf8); + OUT (ch); + drop_int (&ob); + ID; + + block (); + + NEXT (); + fill_int (&ob); + OUT (0xf9); + } + break; + case 0x04: + /* Global function */ + { + struct output_buffer_struct ob; + NEXT (); + OUT (0xf8); + OUT (0x04); + drop_int (&ob); + ID; + INTn (stack size); + INTn (ret val); + EXPn (offset); + + block (); + + NEXT (); + OUT (0xf9); + EXPn (size of block); + fill_int (&ob); + } + break; + + case 0x05: + /* File name for source line numbers */ + { + struct output_buffer_struct ob; + NEXT (); + OUT (0xf8); + OUT (0x05); + drop_int (&ob); + ID; + INTn (year); + INTn (month); + INTn (day); + INTn (hour); + INTn (monute); + INTn (second); + block (); + NEXT (); + OUT (0xf9); + fill_int (&ob); + } + break; + + case 0x06: + /* Local function */ + { + struct output_buffer_struct ob; + NEXT (); + OUT (0xf8); + OUT (0x06); + drop_int (&ob); + ID; + INTn (stack size); + INTn (type return); + EXPn (offset); + block (); + NEXT (); + OUT (0xf9); + EXPn (size); + fill_int (&ob); + } + break; + + case 0x0a: + /* Assembler module scope beginning -*/ + { + struct output_buffer_struct ob; + + NEXT (); + OUT (0xf8); + OUT (0x0a); + drop_int (&ob); + ID; + ID; + INT; + ID; + INT; + INT; + INT; + INT; + INT; + INT; + + block (); + + NEXT (); + OUT (0xf9); + fill_int (&ob); + } + break; + case 0x0b: + { + struct output_buffer_struct ob; + NEXT (); + OUT (0xf8); + OUT (0x0b); + drop_int (&ob); + ID; + INT; + INTn (section index); + EXPn (offset); + INTn (stuff); + + block (); + + OUT (0xf9); + NEXT (); + EXPn (Size in Maus); + fill_int (&ob); + } + break; + } +} + +static void +e2_record () +{ + OUT (0xe2); + NEXT (); + OUT (0xce); + NEXT (); + INT; + EXP; +} + +static void +block () +{ + int ch; + while (1) + { + ch = THIS (); + switch (ch) + { + case 0xe1: + case 0xe5: + return; + case 0xf9: + return; + case 0xf0: + f0_record (); + break; + case 0xf1: + f1_record (); + break; + case 0xf2: + f2_record (); + break; + case 0xf8: + f8_record (); + break; + case 0xe2: + e2_record (); + break; + + } + } +} + + + +/* relocate_debug, + moves all the debug information from the source bfd to the output + bfd, and relocates any expressions it finds +*/ + +static void +relocate_debug (output, input) + bfd *output; + bfd *input; +{ +#define IBS 400 +#define OBS 400 + unsigned char input_buffer[IBS]; + + input_ptr_start = input_ptr = input_buffer; + input_ptr_end = input_buffer + IBS; + input_bfd = input; + /* FIXME: Check return value. I'm not sure whether it needs to read + the entire buffer or not. */ + bfd_read ((PTR) input_ptr_start, 1, IBS, input); + block (); +} + +/* + During linking, we we told about the bfds which made up our + contents, we have a list of them. They will still be open, so go to + the debug info in each, and copy it out, relocating it as we go. +*/ + +static boolean +ieee_write_debug_part (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + bfd_chain_type *chain = ieee->chain_root; + unsigned char output_buffer[OBS]; + boolean some_debug = false; + file_ptr here = bfd_tell (abfd); + + output_ptr_start = output_ptr = output_buffer; + output_ptr_end = output_buffer + OBS; + output_ptr = output_buffer; + output_bfd = abfd; + + if (chain == (bfd_chain_type *) NULL) + { + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) + if ((s->flags & SEC_DEBUGGING) != 0) + break; + if (s == NULL) + { + ieee->w.r.debug_information_part = 0; + return true; + } + + ieee->w.r.debug_information_part = here; + if (bfd_write (s->contents, 1, s->_raw_size, abfd) != s->_raw_size) + return false; + } + else + { + while (chain != (bfd_chain_type *) NULL) + { + bfd *entry = chain->this; + ieee_data_type *entry_ieee = IEEE_DATA (entry); + if (entry_ieee->w.r.debug_information_part) + { + if (bfd_seek (entry, entry_ieee->w.r.debug_information_part, + SEEK_SET) + != 0) + return false; + relocate_debug (abfd, entry); + } + + chain = chain->next; + } + if (some_debug) + { + ieee->w.r.debug_information_part = here; + } + else + { + ieee->w.r.debug_information_part = 0; + } + + flush (); + } + + return true; +} + +/* Write the data in an ieee way. */ + +static boolean +ieee_write_data_part (abfd) + bfd *abfd; +{ + asection *s; + ieee_data_type *ieee = IEEE_DATA (abfd); + ieee->w.r.data_part = bfd_tell (abfd); + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + /* Skip sections that have no loadable contents (.bss, + debugging, etc.) */ + if ((s->flags & SEC_LOAD) == 0) + continue; + + /* Sort the reloc records so we can insert them in the correct + places */ + if (s->reloc_count != 0) + { + if (! do_with_relocs (abfd, s)) + return false; + } + else + { + if (! do_without_relocs (abfd, s)) + return false; + } + } + + return true; +} + + +static boolean +init_for_output (abfd) + bfd *abfd; +{ + asection *s; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if ((s->flags & SEC_DEBUGGING) != 0) + continue; + if (s->_raw_size != 0) + { + ieee_per_section (s)->data = (bfd_byte *) (bfd_alloc (abfd, s->_raw_size)); + if (!ieee_per_section (s)->data) + return false; + } + } + return true; +} + +/** exec and core file sections */ + +/* set section contents is complicated with IEEE since the format is +* not a byte image, but a record stream. +*/ +boolean +ieee_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if ((section->flags & SEC_DEBUGGING) != 0) + { + if (section->contents == NULL) + { + section->contents = bfd_alloc (abfd, section->_raw_size); + if (section->contents == NULL) + return false; + } + /* bfd_set_section_contents has already checked that everything + is within range. */ + memcpy (section->contents + offset, location, count); + return true; + } + + if (ieee_per_section (section)->data == (bfd_byte *) NULL) + { + if (!init_for_output (abfd)) + return false; + } + memcpy ((PTR) (ieee_per_section (section)->data + offset), + (PTR) location, + (unsigned int) count); + return true; +} + +/* Write the external symbols of a file. IEEE considers two sorts of + external symbols, public, and referenced. It uses to internal + forms to index them as well. When we write them out we turn their + symbol values into indexes from the right base. */ + +static boolean +ieee_write_external_part (abfd) + bfd *abfd; +{ + asymbol **q; + ieee_data_type *ieee = IEEE_DATA (abfd); + + unsigned int reference_index = IEEE_REFERENCE_BASE; + unsigned int public_index = IEEE_PUBLIC_BASE + 2; + file_ptr here = bfd_tell (abfd); + boolean hadone = false; + if (abfd->outsymbols != (asymbol **) NULL) + { + + for (q = abfd->outsymbols; *q != (asymbol *) NULL; q++) + { + asymbol *p = *q; + hadone = true; + if (bfd_is_und_section (p->section)) + { + /* This must be a symbol reference .. */ + if (! ieee_write_byte (abfd, ieee_external_reference_enum) + || ! ieee_write_int (abfd, reference_index) + || ! ieee_write_id (abfd, p->name)) + return false; + p->value = reference_index; + reference_index++; + } + else if (bfd_is_com_section (p->section)) + { + /* This is a weak reference */ + if (! ieee_write_byte (abfd, ieee_external_reference_enum) + || ! ieee_write_int (abfd, reference_index) + || ! ieee_write_id (abfd, p->name) + || ! ieee_write_byte (abfd, + ieee_weak_external_reference_enum) + || ! ieee_write_int (abfd, reference_index) + || ! ieee_write_int (abfd, p->value)) + return false; + p->value = reference_index; + reference_index++; + } + else if (p->flags & BSF_GLOBAL) + { + /* This must be a symbol definition */ + + if (! ieee_write_byte (abfd, ieee_external_symbol_enum) + || ! ieee_write_int (abfd, public_index) + || ! ieee_write_id (abfd, p->name) + || ! ieee_write_2bytes (abfd, ieee_attribute_record_enum) + || ! ieee_write_int (abfd, public_index) + || ! ieee_write_byte (abfd, 15) /* instruction address */ + || ! ieee_write_byte (abfd, 19) /* static symbol */ + || ! ieee_write_byte (abfd, 1)) /* one of them */ + return false; + + /* Write out the value */ + if (! ieee_write_2bytes (abfd, ieee_value_record_enum) + || ! ieee_write_int (abfd, public_index)) + return false; + if (! bfd_is_abs_section (p->section)) + { + if (abfd->flags & EXEC_P) + { + /* If fully linked, then output all symbols + relocated */ + if (! (ieee_write_int + (abfd, + (p->value + + p->section->output_offset + + p->section->output_section->vma)))) + return false; + } + else + { + if (! (ieee_write_expression + (abfd, + p->value + p->section->output_offset, + p->section->output_section->symbol, + false, 0))) + return false; + } + } + else + { + if (! ieee_write_expression (abfd, + p->value, + bfd_abs_section_ptr->symbol, + false, 0)) + return false; + } + p->value = public_index; + public_index++; + } + else + { + /* This can happen - when there are gaps in the symbols read */ + /* from an input ieee file */ + } + } + } + if (hadone) + ieee->w.r.external_part = here; + + return true; +} + + +static CONST unsigned char exten[] = +{ + 0xf0, 0x20, 0x00, + 0xf1, 0xce, 0x20, 0x00, 37, 3, 3, /* Set version 3 rev 3 */ + 0xf1, 0xce, 0x20, 0x00, 39, 2,/* keep symbol in original case */ + 0xf1, 0xce, 0x20, 0x00, 38 /* set object type relocateable to x */ +}; + +static CONST unsigned char envi[] = +{ + 0xf0, 0x21, 0x00, + +/* 0xf1, 0xce, 0x21, 00, 50, 0x82, 0x07, 0xc7, 0x09, 0x11, 0x11, + 0x19, 0x2c, +*/ + 0xf1, 0xce, 0x21, 00, 52, 0x00, /* exec ok */ + + 0xf1, 0xce, 0x21, 0, 53, 0x03,/* host unix */ +/* 0xf1, 0xce, 0x21, 0, 54, 2,1,1 tool & version # */ +}; + +static boolean +ieee_write_me_part (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + ieee->w.r.trailer_part = bfd_tell (abfd); + if (abfd->start_address) + { + if (! ieee_write_2bytes (abfd, ieee_value_starting_address_enum) + || ! ieee_write_byte (abfd, ieee_function_either_open_b_enum) + || ! ieee_write_int (abfd, abfd->start_address) + || ! ieee_write_byte (abfd, ieee_function_either_close_b_enum)) + return false; + } + ieee->w.r.me_record = bfd_tell (abfd); + if (! ieee_write_byte (abfd, ieee_module_end_enum)) + return false; + return true; +} + +/* Write out the IEEE processor ID. */ + +static boolean +ieee_write_processor (abfd) + bfd *abfd; +{ + const bfd_arch_info_type *arch; + + arch = bfd_get_arch_info (abfd); + switch (arch->arch) + { + default: + if (! ieee_write_id (abfd, bfd_printable_name (abfd))) + return false; + break; + + case bfd_arch_a29k: + if (! ieee_write_id (abfd, "29000")) + return false; + break; + + case bfd_arch_h8300: + if (! ieee_write_id (abfd, "H8/300")) + return false; + break; + + case bfd_arch_h8500: + if (! ieee_write_id (abfd, "H8/500")) + return false; + break; + + case bfd_arch_i960: + switch (arch->mach) + { + default: + case bfd_mach_i960_core: + case bfd_mach_i960_ka_sa: + if (! ieee_write_id (abfd, "80960KA")) + return false; + break; + + case bfd_mach_i960_kb_sb: + if (! ieee_write_id (abfd, "80960KB")) + return false; + break; + + case bfd_mach_i960_ca: + if (! ieee_write_id (abfd, "80960CA")) + return false; + break; + + case bfd_mach_i960_mc: + case bfd_mach_i960_xa: + if (! ieee_write_id (abfd, "80960MC")) + return false; + break; + } + break; + + case bfd_arch_m68k: + { + char ab[20]; + + sprintf (ab, "%lu", arch->mach); + if (! ieee_write_id (abfd, ab)) + return false; + } + break; + } + + return true; +} + +boolean +ieee_write_object_contents (abfd) + bfd *abfd; +{ + ieee_data_type *ieee = IEEE_DATA (abfd); + unsigned int i; + file_ptr old; + + /* Fast forward over the header area */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + + if (! ieee_write_byte (abfd, ieee_module_beginning_enum) + || ! ieee_write_processor (abfd) + || ! ieee_write_id (abfd, abfd->filename)) + return false; + + /* Fast forward over the variable bits */ + if (! ieee_write_byte (abfd, ieee_address_descriptor_enum)) + return false; + + /* Bits per MAU */ + if (! ieee_write_byte (abfd, (bfd_byte) (bfd_arch_bits_per_byte (abfd)))) + return false; + /* MAU's per address */ + if (! ieee_write_byte (abfd, + (bfd_byte) (bfd_arch_bits_per_address (abfd) + / bfd_arch_bits_per_byte (abfd)))) + return false; + + old = bfd_tell (abfd); + if (bfd_seek (abfd, (file_ptr) (8 * N_W_VARIABLES), SEEK_CUR) != 0) + return false; + + ieee->w.r.extension_record = bfd_tell (abfd); + if (bfd_write ((char *) exten, 1, sizeof (exten), abfd) != sizeof (exten)) + return false; + if (abfd->flags & EXEC_P) + { + if (! ieee_write_byte (abfd, 0x1)) /* Absolute */ + return false; + } + else + { + if (! ieee_write_byte (abfd, 0x2)) /* Relocateable */ + return false; + } + + ieee->w.r.environmental_record = bfd_tell (abfd); + if (bfd_write ((char *) envi, 1, sizeof (envi), abfd) != sizeof (envi)) + return false; + output_bfd = abfd; + + flush (); + + if (! ieee_write_section_part (abfd)) + return false; + /* First write the symbols. This changes their values into table + indeces so we cant use it after this point. */ + if (! ieee_write_external_part (abfd)) + return false; + + /* ieee_write_byte(abfd, ieee_record_seperator_enum);*/ + + /* ieee_write_byte(abfd, ieee_record_seperator_enum);*/ + + + /* Write any debugs we have been told about. */ + if (! ieee_write_debug_part (abfd)) + return false; + + /* Can only write the data once the symbols have been written, since + the data contains relocation information which points to the + symbols. */ + if (! ieee_write_data_part (abfd)) + return false; + + /* At the end we put the end! */ + if (! ieee_write_me_part (abfd)) + return false; + + /* Generate the header */ + if (bfd_seek (abfd, old, SEEK_SET) != 0) + return false; + + for (i = 0; i < N_W_VARIABLES; i++) + { + if (! ieee_write_2bytes (abfd, ieee_assign_value_to_variable_enum) + || ! ieee_write_byte (abfd, (bfd_byte) i) + || ! ieee_write_int5_out (abfd, ieee->w.offset[i])) + return false; + } + + return true; +} + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this + function exits. We read the strings into a buffer large enough to + hold them all plus all the cached symbol entries. */ + +asymbol * +ieee_make_empty_symbol (abfd) + bfd *abfd; +{ + ieee_symbol_type *new = + (ieee_symbol_type *) bfd_zmalloc (sizeof (ieee_symbol_type)); + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +static bfd * +ieee_openr_next_archived_file (arch, prev) + bfd *arch; + bfd *prev; +{ + ieee_ar_data_type *ar = IEEE_AR_DATA (arch); + /* take the next one from the arch state, or reset */ + if (prev == (bfd *) NULL) + { + /* Reset the index - the first two entries are bogus*/ + ar->element_index = 2; + } + while (true) + { + ieee_ar_obstack_type *p = ar->elements + ar->element_index; + ar->element_index++; + if (ar->element_index <= ar->element_count) + { + if (p->file_offset != (file_ptr) 0) + { + if (p->abfd == (bfd *) NULL) + { + p->abfd = _bfd_create_empty_archive_element_shell (arch); + p->abfd->origin = p->file_offset; + } + return p->abfd; + } + } + else + { + bfd_set_error (bfd_error_no_more_archived_files); + return (bfd *) NULL; + } + + } +} + +static boolean +ieee_find_nearest_line (abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + char **filename_ptr; + char **functionname_ptr; + int *line_ptr; +{ + return false; +} + +static int +ieee_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + ieee_ar_data_type *ar = abfd->my_archive->tdata.ieee_ar_data; + if (ar == (ieee_ar_data_type *) NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + else if (ieee_object_p (abfd)) + { + ieee_data_type *ieee = IEEE_DATA (abfd); + + buf->st_size = ieee->w.r.me_record + 1; + buf->st_mode = 0644; + return 0; + } + else + return -1; +} + +static int +ieee_sizeof_headers (abfd, x) + bfd *abfd; + boolean x; +{ + return 0; +} + + +/* The debug info routines are never used. */ +#if 0 + +static void +ieee_bfd_debug_info_start (abfd) + bfd *abfd; +{ + +} + +static void +ieee_bfd_debug_info_end (abfd) + bfd *abfd; +{ + +} + + +/* Add this section to the list of sections we have debug info for, to + be ready to output it at close time + */ +static void +ieee_bfd_debug_info_accumulate (abfd, section) + bfd *abfd; + asection *section; +{ + ieee_data_type *ieee = IEEE_DATA (section->owner); + ieee_data_type *output_ieee = IEEE_DATA (abfd); + /* can only accumulate data from other ieee bfds */ + if (section->owner->xvec != abfd->xvec) + return; + /* Only bother once per bfd */ + if (ieee->done_debug == true) + return; + ieee->done_debug = true; + + /* Don't bother if there is no debug info */ + if (ieee->w.r.debug_information_part == 0) + return; + + + /* Add to chain */ + { + bfd_chain_type *n = (bfd_chain_type *) bfd_alloc (abfd, sizeof (bfd_chain_type)); + if (!n) + abort (); /* FIXME */ + n->this = section->owner; + n->next = (bfd_chain_type *) NULL; + + if (output_ieee->chain_head) + { + output_ieee->chain_head->next = n; + } + else + { + output_ieee->chain_root = n; + + } + output_ieee->chain_head = n; + } +} + +#endif + +#define ieee_close_and_cleanup _bfd_generic_close_and_cleanup +#define ieee_bfd_free_cached_info _bfd_generic_bfd_free_cached_info + +#define ieee_slurp_armap bfd_true +#define ieee_slurp_extended_name_table bfd_true +#define ieee_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_true) +#define ieee_truncate_arname bfd_dont_truncate_arname +#define ieee_write_armap \ + ((boolean (*) \ + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ + bfd_true) +#define ieee_read_ar_hdr bfd_nullvoidptr +#define ieee_update_armap_timestamp bfd_true +#define ieee_get_elt_at_index _bfd_generic_get_elt_at_index + +#define ieee_bfd_is_local_label bfd_generic_is_local_label +#define ieee_get_lineno _bfd_nosymbols_get_lineno +#define ieee_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define ieee_read_minisymbols _bfd_generic_read_minisymbols +#define ieee_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define ieee_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define ieee_set_arch_mach _bfd_generic_set_arch_mach + +#define ieee_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window +#define ieee_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define ieee_bfd_relax_section bfd_generic_relax_section +#define ieee_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define ieee_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define ieee_bfd_final_link _bfd_generic_final_link +#define ieee_bfd_link_split_section _bfd_generic_link_split_section + +/*SUPPRESS 460 */ +const bfd_target ieee_vec = +{ + "ieee", /* name */ + bfd_target_ieee_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, + ieee_object_p, /* bfd_check_format */ + ieee_archive_p, + _bfd_dummy_target, + }, + { + bfd_false, + ieee_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + { + bfd_false, + ieee_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (ieee), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (ieee), + BFD_JUMP_TABLE_SYMBOLS (ieee), + BFD_JUMP_TABLE_RELOCS (ieee), + BFD_JUMP_TABLE_WRITE (ieee), + BFD_JUMP_TABLE_LINK (ieee), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/ihex.c b/contrib/gdb/bfd/ihex.c new file mode 100644 index 000000000000..80140da5976b --- /dev/null +++ b/contrib/gdb/bfd/ihex.c @@ -0,0 +1,1005 @@ +/* BFD back-end for Intel Hex objects. + Copyright 1995 Free Software Foundation, Inc. + Written by Ian Lance Taylor of Cygnus Support . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is what Intel Hex files look like: + +1. INTEL FORMATS + +A. Intel 1 + + 16-bit address-field format, for files 64k bytes in length or less. + + DATA RECORD + Byte 1 Header = colon(:) + 2..3 The number of data bytes in hex notation + 4..5 High byte of the record load address + 6..7 Low byte of the record load address + 8..9 Record type, must be "00" + 10..x Data bytes in hex notation: + x = (number of bytes - 1) * 2 + 11 + x+1..x+2 Checksum in hex notation + x+3..x+4 Carriage return, line feed + + END RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "00" + 4..7 Transfer-address (usually "0000") + the jump-to address, execution start address + 8..9 Record type, must be "01" + 10..11 Checksum, in hex notation + 12..13 Carriage return, line feed + +B. INTEL 2 + + MCS-86 format, using a 20-bit address for files larger than 64K bytes. + + DATA RECORD + Byte 1 Header = colon (:) + 2..3 The byte count of this record, hex notation + 4..5 High byte of the record load address + 6..7 Low byte of the record load address + 8..9 Record type, must be "00" + 10..x The data bytes in hex notation: + x = (number of data bytes - 1) * 2 + 11 + x+1..x+2 Checksum in hex notation + x+3..x+4 Carriage return, line feed + + EXTENDED ADDRESS RECORD + Byte 1 Header = colon(:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "02" + 10..11 High byte of the offset address + 12..13 Low byte of the offset address + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed + + The checksums are the two's complement of the 8-bit sum + without carry of the byte count, offset address, and the + record type. + + START ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "04" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "03" + 10..13 8086 CS value + 14..17 8086 IP value + 18..19 Checksum in hex notation + 20..21 Carriage return, line feed + +Another document reports these additional types: + + EXTENDED LINEAR ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "04" + 10..13 Upper 16 bits of address of subsequent records + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed + + START LINEAR ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "05" + 10..13 Upper 16 bits of start address + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" + +#include + +static void ihex_init PARAMS ((void)); +static boolean ihex_mkobject PARAMS ((bfd *)); +static INLINE int ihex_get_byte PARAMS ((bfd *, boolean *)); +static void ihex_bad_byte PARAMS ((bfd *, unsigned int, int, boolean)); +static boolean ihex_scan PARAMS ((bfd *)); +static const bfd_target *ihex_object_p PARAMS ((bfd *)); +static boolean ihex_read_section PARAMS ((bfd *, asection *, bfd_byte *)); +static boolean ihex_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static boolean ihex_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static boolean ihex_write_record + PARAMS ((bfd *, bfd_size_type, bfd_vma, unsigned int, bfd_byte *)); +static boolean ihex_write_object_contents PARAMS ((bfd *)); +static asymbol *ihex_make_empty_symbol PARAMS ((bfd *)); +static boolean ihex_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); + +/* The number of bytes we put on one line during output. */ + +#define CHUNK (21) + +/* Macros for converting between hex and binary. */ + +#define NIBBLE(x) (hex_value (x)) +#define HEX2(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) +#define HEX4(buffer) ((HEX2 (buffer) << 8) + HEX2 ((buffer) + 2)) +#define ISHEX(x) (hex_p (x)) + +/* When we write out an ihex value, the values can not be output as + they are seen. Instead, we hold them in memory in this structure. */ + +struct ihex_data_list +{ + struct ihex_data_list *next; + bfd_byte *data; + bfd_vma where; + bfd_size_type size; +}; + +/* The ihex tdata information. */ + +struct ihex_data_struct +{ + struct ihex_data_list *head; + struct ihex_data_list *tail; +}; + +/* Initialize by filling in the hex conversion array. */ + +static void +ihex_init () +{ + static boolean inited; + + if (! inited) + { + inited = true; + hex_init (); + } +} + +/* Create an ihex object. */ + +static boolean +ihex_mkobject (abfd) + bfd *abfd; +{ + if (abfd->tdata.ihex_data == NULL) + { + struct ihex_data_struct *tdata; + + tdata = ((struct ihex_data_struct *) + bfd_alloc (abfd, sizeof (struct ihex_data_struct))); + if (tdata == NULL) + return false; + abfd->tdata.ihex_data = tdata; + tdata->head = NULL; + tdata->tail = NULL; + } + + return true; +} + +/* Read a byte from a BFD. Set *ERRORPTR if an error occurred. + Return EOF on error or end of file. */ + +static INLINE int +ihex_get_byte (abfd, errorptr) + bfd *abfd; + boolean *errorptr; +{ + bfd_byte c; + + if (bfd_read (&c, 1, 1, abfd) != 1) + { + if (bfd_get_error () != bfd_error_file_truncated) + *errorptr = true; + return EOF; + } + + return (int) (c & 0xff); +} + +/* Report a problem in an Intel Hex file. */ + +static void +ihex_bad_byte (abfd, lineno, c, error) + bfd *abfd; + unsigned int lineno; + int c; + boolean error; +{ + if (c == EOF) + { + if (! error) + bfd_set_error (bfd_error_file_truncated); + } + else + { + char buf[10]; + + if (! isprint (c)) + sprintf (buf, "\\%03o", (unsigned int) c); + else + { + buf[0] = c; + buf[1] = '\0'; + } + (*_bfd_error_handler) + ("%s:%d: unexpected character `%s' in Intel Hex file\n", + bfd_get_filename (abfd), lineno, buf); + bfd_set_error (bfd_error_bad_value); + } +} + +/* Read an Intel hex file and turn it into sections. We create a new + section for each contiguous set of bytes. */ + +static boolean +ihex_scan (abfd) + bfd *abfd; +{ + bfd_vma segbase; + bfd_vma extbase; + asection *sec; + int lineno; + boolean error; + bfd_byte *buf; + size_t bufsize; + int c; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto error_return; + + abfd->start_address = 0; + + extbase = 0; + segbase = 0; + sec = NULL; + lineno = 1; + error = false; + buf = NULL; + bufsize = 0; + while ((c = ihex_get_byte (abfd, &error)) != EOF) + { + if (c == '\r') + continue; + else if (c == '\n') + { + ++lineno; + continue; + } + else if (c != ':') + { + ihex_bad_byte (abfd, lineno, c, error); + goto error_return; + } + else + { + file_ptr pos; + char hdr[8]; + unsigned int i; + unsigned int len; + bfd_vma addr; + unsigned int type; + unsigned int chars; + unsigned int chksum; + + /* This is a data record. */ + + pos = bfd_tell (abfd) - 1; + + /* Read the header bytes. */ + + if (bfd_read (hdr, 1, 8, abfd) != 8) + goto error_return; + + for (i = 0; i < 8; i++) + { + if (! ISHEX (hdr[i])) + { + ihex_bad_byte (abfd, lineno, hdr[i], error); + goto error_return; + } + } + + len = HEX2 (hdr); + addr = HEX4 (hdr + 2); + type = HEX2 (hdr + 6); + + /* Read the data bytes. */ + + chars = len * 2 + 2; + if (chars >= bufsize) + { + buf = (bfd_byte *) bfd_realloc (buf, chars); + if (buf == NULL) + goto error_return; + bufsize = chars; + } + + if (bfd_read (buf, 1, chars, abfd) != chars) + goto error_return; + + for (i = 0; i < chars; i++) + { + if (! ISHEX (buf[i])) + { + ihex_bad_byte (abfd, lineno, hdr[i], error); + goto error_return; + } + } + + /* Check the checksum. */ + chksum = len + addr + (addr >> 8) + type; + for (i = 0; i < len; i++) + chksum += HEX2 (buf + 2 * i); + if (((- chksum) & 0xff) != (unsigned int) HEX2 (buf + 2 * i)) + { + (*_bfd_error_handler) + ("%s:%d: bad checksum in Intel Hex file (expected %u, found %u)", + bfd_get_filename (abfd), lineno, + (- chksum) & 0xff, (unsigned int) HEX2 (buf + 2 * i)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + switch (type) + { + case 0: + /* This is a data record. */ + if (sec != NULL + && sec->vma + sec->_raw_size == extbase + segbase + addr) + { + /* This data goes at the end of the section we are + currently building. */ + sec->_raw_size += len; + } + else if (len > 0) + { + char secbuf[20]; + char *secname; + + sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); + secname = (char *) bfd_alloc (abfd, strlen (secbuf) + 1); + if (secname == NULL) + goto error_return; + strcpy (secname, secbuf); + sec = bfd_make_section (abfd, secname); + if (sec == NULL) + goto error_return; + sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + sec->vma = extbase + segbase + addr; + sec->lma = extbase + segbase + addr; + sec->_raw_size = len; + sec->filepos = pos; + } + break; + + case 1: + /* An end record. */ + if (abfd->start_address == 0) + abfd->start_address = addr; + if (buf != NULL) + free (buf); + return true; + + case 2: + /* An extended address record. */ + if (len != 2) + { + (*_bfd_error_handler) + ("%s:%d: bad extended address record length in Intel Hex file", + bfd_get_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + segbase = HEX4 (buf) << 4; + + sec = NULL; + + break; + + case 3: + /* An extended start address record. */ + if (len != 4) + { + (*_bfd_error_handler) + ("%s:%d: bad extended start address length in Intel Hex file", + bfd_get_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + abfd->start_address += (HEX4 (buf) << 4) + HEX4 (buf + 4); + + sec = NULL; + + break; + + case 4: + /* An extended linear address record. */ + if (len != 2) + { + (*_bfd_error_handler) + ("%s:%d: bad extended linear address record length in Intel Hex file", + bfd_get_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + segbase = HEX4 (buf) << 16; + + sec = NULL; + + break; + + case 5: + /* An extended linear start address record. */ + if (len != 2) + { + (*_bfd_error_handler) + ("%s:%d: bad extended linear start address length in Intel Hex file", + bfd_get_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + abfd->start_address += HEX4 (buf) << 16; + + sec = NULL; + + break; + + default: + (*_bfd_error_handler) + ("%s:%d: unrecognized ihex type %u in Intel Hex file\n", + bfd_get_filename (abfd), lineno, type); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + } + } + + if (error) + goto error_return; + + if (buf != NULL) + free (buf); + + return true; + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Try to recognize an Intel Hex file. */ + +static const bfd_target * +ihex_object_p (abfd) + bfd *abfd; +{ + bfd_byte b[9]; + unsigned int i; + unsigned int type; + + ihex_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return NULL; + if (bfd_read (b, 1, 9, abfd) != 9) + { + if (bfd_get_error () == bfd_error_file_truncated) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (b[0] != ':') + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + for (i = 1; i < 9; i++) + { + if (! ISHEX (b[i])) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + } + + type = HEX2 (b + 7); + if (type > 5) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* OK, it looks like it really is an Intel Hex file. */ + + if (! ihex_mkobject (abfd) + || ! ihex_scan (abfd)) + return NULL; + + return abfd->xvec; +} + +/* Read the contents of a section in an Intel Hex file. */ + +static boolean +ihex_read_section (abfd, section, contents) + bfd *abfd; + asection *section; + bfd_byte *contents; +{ + int c; + bfd_byte *p; + bfd_byte *buf; + size_t bufsize; + boolean error; + + if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) + goto error_return; + + p = contents; + buf = NULL; + bufsize = 0; + error = false; + while ((c = ihex_get_byte (abfd, &error)) != EOF) + { + char hdr[8]; + unsigned int len; + bfd_vma addr; + unsigned int type; + unsigned int i; + + if (c == '\r' || c == '\n') + continue; + + /* This is called after ihex_scan has succeeded, so we ought to + know the exact format. */ + BFD_ASSERT (c == ':'); + + if (bfd_read (hdr, 1, 8, abfd) != 8) + goto error_return; + + len = HEX2 (hdr); + addr = HEX4 (hdr + 2); + type = HEX2 (hdr + 6); + + /* We should only see type 0 records here. */ + if (type != 0) + { + (*_bfd_error_handler) + ("%s: internal error in ihex_read_section", + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (len * 2 > bufsize) + { + buf = (bfd_byte *) bfd_realloc (buf, len * 2); + if (buf == NULL) + goto error_return; + bufsize = len * 2; + } + + if (bfd_read (buf, 1, len * 2, abfd) != len * 2) + goto error_return; + + for (i = 0; i < len; i++) + *p++ = HEX2 (buf + 2 * i); + if ((bfd_size_type) (p - contents) >= section->_raw_size) + { + /* We've read everything in the section. */ + if (buf != NULL) + free (buf); + return true; + } + + /* Skip the checksum. */ + if (bfd_read (buf, 1, 2, abfd) != 2) + goto error_return; + } + + if ((bfd_size_type) (p - contents) < section->_raw_size) + { + (*_bfd_error_handler) + ("%s: bad section length in ihex_read_section", + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (buf != NULL) + free (buf); + + return true; + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Get the contents of a section in an Intel Hex file. */ + +static boolean +ihex_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->_raw_size); + if (section->used_by_bfd == NULL) + return false; + if (! ihex_read_section (abfd, section, section->used_by_bfd)) + return false; + } + + memcpy (location, (bfd_byte *) section->used_by_bfd + offset, + (size_t) count); + + return true; +} + +/* Set the contents of a section in an Intel Hex file. */ + +static boolean +ihex_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + struct ihex_data_list *n; + bfd_byte *data; + struct ihex_data_struct *tdata; + + if (count == 0 + || (section->flags & SEC_ALLOC) == 0 + || (section->flags & SEC_LOAD) == 0) + return true; + + n = ((struct ihex_data_list *) + bfd_alloc (abfd, sizeof (struct ihex_data_list))); + if (n == NULL) + return false; + + data = (bfd_byte *) bfd_alloc (abfd, count); + if (data == NULL) + return false; + memcpy (data, location, (size_t) count); + + n->data = data; + n->where = section->lma + offset; + n->size = count; + + /* Sort the records by address. Optimize for the common case of + adding a record to the end of the list. */ + tdata = abfd->tdata.ihex_data; + if (tdata->tail != NULL + && n->where >= tdata->tail->where) + { + tdata->tail->next = n; + n->next = NULL; + tdata->tail = n; + } + else + { + register struct ihex_data_list **pp; + + for (pp = &tdata->head; + *pp != NULL && (*pp)->where < n->where; + pp = &(*pp)->next) + ; + n->next = *pp; + *pp = n; + if (n->next == NULL) + tdata->tail = n; + } + + return true; +} + +/* Write a record out to an Intel Hex file. */ + +static boolean +ihex_write_record (abfd, count, addr, type, data) + bfd *abfd; + bfd_size_type count; + bfd_vma addr; + unsigned int type; + bfd_byte *data; +{ + static const char digs[] = "0123456789ABCDEF"; + char buf[9 + CHUNK * 2 + 4]; + char *p; + unsigned int chksum; + unsigned int i; + +#define TOHEX(buf, v) \ + ((buf)[0] = digs[((v) >> 4) & 0xf], (buf)[1] = digs[(v) & 0xf]) + + buf[0] = ':'; + TOHEX (buf + 1, count); + TOHEX (buf + 3, (addr >> 8) & 0xff); + TOHEX (buf + 5, addr & 0xff); + TOHEX (buf + 7, type); + + chksum = count + addr + (addr >> 8) + type; + + for (i = 0, p = buf + 9; i < count; i++, p += 2, data++) + { + TOHEX (p, *data); + chksum += *data; + } + + TOHEX (p, (- chksum) & 0xff); + p[2] = '\r'; + p[3] = '\n'; + + if (bfd_write (buf, 1, 9 + count * 2 + 4, abfd) != 9 + count * 2 + 4) + return false; + + return true; +} + +/* Write out an Intel Hex file. */ + +static boolean +ihex_write_object_contents (abfd) + bfd *abfd; +{ + bfd_vma extbase; + bfd_vma segbase; + struct ihex_data_list *l; + + extbase = 0; + segbase = 0; + for (l = abfd->tdata.ihex_data->head; l != NULL; l = l->next) + { + bfd_vma where; + bfd_byte *p; + bfd_size_type count; + + where = l->where; + p = l->data; + count = l->size; + while (count > 0) + { + bfd_size_type now; + + now = count; + if (now > CHUNK) + now = CHUNK; + + if (where > extbase + segbase + 0xffff) + { + bfd_byte addr[2]; + + /* We need a new base address. */ + if (where <= 0xfffff) + { + segbase = where & 0xf0000; + addr[0] = (segbase >> 12) & 0xff; + addr[1] = (segbase >> 4) & 0xff; + if (! ihex_write_record (abfd, 2, 0, 2, addr)) + return false; + } + else + { + extbase = where & 0xffff0000; + if (where > extbase + 0xffff) + { + char buf[20]; + + sprintf_vma (buf, where); + (*_bfd_error_handler) + ("%s: address 0x%s out of range for Intex Hex file", + bfd_get_filename (abfd), buf); + bfd_set_error (bfd_error_bad_value); + return false; + } + addr[0] = (extbase >> 24) & 0xff; + addr[1] = (extbase >> 16) & 0xff; + if (! ihex_write_record (abfd, 2, 0, 4, addr)) + return false; + } + } + + if (! ihex_write_record (abfd, now, where - (extbase + segbase), + 0, p)) + return false; + + where += now; + p += now; + count -= now; + } + } + + if (abfd->start_address != 0) + { + bfd_vma start; + bfd_byte startbuf[4]; + + start = abfd->start_address; + + if (start > 0xfffff) + { + startbuf[0] = (start >> 24) & 0xff; + startbuf[1] = (start >> 16) & 0xff; + if (! ihex_write_record (abfd, 2, 0, 5, startbuf)) + return false; + start &= 0xffff; + } + + startbuf[0] = ((start & 0xf0000) >> 12) & 0xff; + startbuf[1] = 0; + startbuf[2] = (start >> 8) & 0xff; + startbuf[3] = start & 0xff; + if (! ihex_write_record (abfd, 4, 0, 3, startbuf)) + return false; + } + + if (! ihex_write_record (abfd, 0, 0, 1, NULL)) + return false; + + return true; +} + +/* Make an empty symbol. This is required only because + bfd_make_section_anyway wants to create a symbol for the section. */ + +static asymbol * +ihex_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new; + + new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new != NULL) + new->the_bfd = abfd; + return new; +} + +/* Set the architecture for the output file. The architecture is + irrelevant, so we ignore errors about unknown architectures. */ + +static boolean +ihex_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ + if (! bfd_default_set_arch_mach (abfd, arch, mach)) + { + if (arch != bfd_arch_unknown) + return false; + } + return true; +} + +/* Get the size of the headers, for the linker. */ + +/*ARGSUSED*/ +static int +ihex_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +/* Some random definitions for the target vector. */ + +#define ihex_close_and_cleanup _bfd_generic_close_and_cleanup +#define ihex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define ihex_new_section_hook _bfd_generic_new_section_hook +#define ihex_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define ihex_get_symtab_upper_bound bfd_0l +#define ihex_get_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) bfd_0l) +#define ihex_print_symbol _bfd_nosymbols_print_symbol +#define ihex_get_symbol_info _bfd_nosymbols_get_symbol_info +#define ihex_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define ihex_get_lineno _bfd_nosymbols_get_lineno +#define ihex_find_nearest_line _bfd_nosymbols_find_nearest_line +#define ihex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define ihex_read_minisymbols _bfd_nosymbols_read_minisymbols +#define ihex_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +#define ihex_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define ihex_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define ihex_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define ihex_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define ihex_bfd_relax_section bfd_generic_relax_section +#define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define ihex_bfd_final_link _bfd_generic_final_link +#define ihex_bfd_link_split_section _bfd_generic_link_split_section + +/* The Intel Hex target vector. */ + +const bfd_target ihex_vec = +{ + "ihex", /* name */ + bfd_target_ihex_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + 0, /* object flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + ihex_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + ihex_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + ihex_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (ihex), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (ihex), + BFD_JUMP_TABLE_RELOCS (ihex), + BFD_JUMP_TABLE_WRITE (ihex), + BFD_JUMP_TABLE_LINK (ihex), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/init.c b/contrib/gdb/bfd/init.c new file mode 100644 index 000000000000..1fa1d505bee6 --- /dev/null +++ b/contrib/gdb/bfd/init.c @@ -0,0 +1,50 @@ +/* bfd initialization stuff + Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Initialization + + These are the functions that handle initializing a BFD. +*/ + +/* +FUNCTION + bfd_init + +SYNOPSIS + void bfd_init(void); + +DESCRIPTION + This routine must be called before any other BFD function to + initialize magical internal data structures. +*/ + +/* Actually, there is currently nothing for this function to do. + However, someday it may be needed, so keep it around. */ + +void +bfd_init () +{ +} diff --git a/contrib/gdb/bfd/irix-core.c b/contrib/gdb/bfd/irix-core.c new file mode 100644 index 000000000000..3fd39772ce84 --- /dev/null +++ b/contrib/gdb/bfd/irix-core.c @@ -0,0 +1,263 @@ +/* BFD back-end for Irix core files. + Copyright 1993, 1994 Free Software Foundation, Inc. + Written by Stu Grossman, Cygnus Support. + Converted to back-end form by Ian Lance Taylor, Cygnus Support + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file can only be compiled on systems which use Irix style core + files (namely, Irix 4 and Irix 5, so far). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifdef IRIX_CORE + +#include + +struct sgi_core_struct +{ + int sig; + char cmd[CORE_NAMESIZE]; +}; + +#define core_hdr(bfd) ((bfd)->tdata.sgi_core_data) +#define core_signal(bfd) (core_hdr(bfd)->sig) +#define core_command(bfd) (core_hdr(bfd)->cmd) + +static asection * +make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos) + bfd *abfd; + CONST char *name; + flagword flags; + bfd_size_type _raw_size; + bfd_vma vma; + file_ptr filepos; +{ + asection *asect; + + asect = bfd_make_section_anyway (abfd, name); + if (!asect) + return NULL; + + asect->flags = flags; + asect->_raw_size = _raw_size; + asect->vma = vma; + asect->filepos = filepos; + asect->alignment_power = 4; + + return asect; +} + +static const bfd_target * +irix_core_core_file_p (abfd) + bfd *abfd; +{ + int val; + int i; + char *secname; + struct coreout coreout; + struct idesc *idg, *idf, *ids; + + val = bfd_read ((PTR)&coreout, 1, sizeof coreout, abfd); + if (val != sizeof coreout) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if (coreout.c_magic != CORE_MAGIC + || coreout.c_version != CORE_VERSION1) + return 0; + + core_hdr (abfd) = (struct sgi_core_struct *) bfd_zalloc (abfd, sizeof (struct sgi_core_struct)); + if (!core_hdr (abfd)) + return NULL; + + strncpy (core_command (abfd), coreout.c_name, CORE_NAMESIZE); + core_signal (abfd) = coreout.c_sigcause; + + if (bfd_seek (abfd, coreout.c_vmapoffset, SEEK_SET) != 0) + return NULL; + + for (i = 0; i < coreout.c_nvmap; i++) + { + struct vmap vmap; + + val = bfd_read ((PTR)&vmap, 1, sizeof vmap, abfd); + if (val != sizeof vmap) + break; + + switch (vmap.v_type) + { + case VDATA: + secname = ".data"; + break; + case VSTACK: + secname = ".stack"; + break; +#ifdef VMAPFILE + case VMAPFILE: + secname = ".mapfile"; + break; +#endif + default: + continue; + } + + /* A file offset of zero means that the section is not contained + in the corefile. */ + if (vmap.v_offset == 0) + continue; + + if (!make_bfd_asection (abfd, secname, + SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS, + vmap.v_len, + vmap.v_vaddr, + vmap.v_offset, + 2)) + return NULL; + } + + /* Make sure that the regs are contiguous within the core file. */ + + idg = &coreout.c_idesc[I_GPREGS]; + idf = &coreout.c_idesc[I_FPREGS]; + ids = &coreout.c_idesc[I_SPECREGS]; + + if (idg->i_offset + idg->i_len != idf->i_offset + || idf->i_offset + idf->i_len != ids->i_offset) + return 0; /* Can't deal with non-contig regs */ + + if (bfd_seek (abfd, idg->i_offset, SEEK_SET) != 0) + return NULL; + + make_bfd_asection (abfd, ".reg", + SEC_HAS_CONTENTS, + idg->i_len + idf->i_len + ids->i_len, + 0, + idg->i_offset); + + /* OK, we believe you. You're a core file (sure, sure). */ + + return abfd->xvec; +} + +static char * +irix_core_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_command (abfd); +} + +static int +irix_core_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_signal (abfd); +} + +static boolean +irix_core_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* XXX - FIXME */ +} + +static asymbol * +irix_core_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +#define irix_core_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound +#define irix_core_get_symtab _bfd_nosymbols_get_symtab +#define irix_core_print_symbol _bfd_nosymbols_print_symbol +#define irix_core_get_symbol_info _bfd_nosymbols_get_symbol_info +#define irix_core_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define irix_core_get_lineno _bfd_nosymbols_get_lineno +#define irix_core_find_nearest_line _bfd_nosymbols_find_nearest_line +#define irix_core_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define irix_core_read_minisymbols _bfd_nosymbols_read_minisymbols +#define irix_core_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target irix_core_vec = + { + "irix-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + irix_core_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (irix_core), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (irix_core), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; + +#endif /* IRIX_CORE */ diff --git a/contrib/gdb/bfd/libaout.h b/contrib/gdb/bfd/libaout.h new file mode 100644 index 000000000000..76c1dff7cdbd --- /dev/null +++ b/contrib/gdb/bfd/libaout.h @@ -0,0 +1,608 @@ +/* BFD back-end data structures for a.out (and similar) files. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef LIBAOUT_H +#define LIBAOUT_H + +/* We try to encapsulate the differences in the various a.out file + variants in a few routines, and otherwise share large masses of code. + This means we only have to fix bugs in one place, most of the time. */ + +#include "bfdlink.h" + +/* Parameterize the a.out code based on whether it is being built + for a 32-bit architecture or a 64-bit architecture. */ +#if ARCH_SIZE==64 +#define GET_WORD bfd_h_get_64 +#define GET_SWORD bfd_h_get_signed_64 +#define PUT_WORD bfd_h_put_64 +#ifndef NAME +#define NAME(x,y) CAT3(x,_64_,y) +#endif +#define JNAME(x) CAT(x,_64) +#define BYTES_IN_WORD 8 +#else /* ARCH_SIZE == 32 */ +#define GET_WORD bfd_h_get_32 +#define GET_SWORD bfd_h_get_signed_32 +#define PUT_WORD bfd_h_put_32 +#ifndef NAME +#define NAME(x,y) CAT3(x,_32_,y) +#endif +#define JNAME(x) CAT(x,_32) +#define BYTES_IN_WORD 4 +#endif /* ARCH_SIZE==32 */ + +/* Declare at file level, since used in parameter lists, which have + weird scope. */ +struct external_exec; +struct external_nlist; +struct reloc_ext_external; +struct reloc_std_external; + +/* a.out backend linker hash table entries. */ + +struct aout_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Whether this symbol has been written out. */ + boolean written; + /* Symbol index in output file. */ + int indx; +}; + +/* a.out backend linker hash table. */ + +struct aout_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in an a.out link hash table. */ + +#define aout_link_hash_lookup(table, string, create, copy, follow) \ + ((struct aout_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an a.out link hash table. */ + +#define aout_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the a.out link hash table from the info structure. This is + just a cast. */ + +#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash)) + +/* Back-end information for various a.out targets. */ +struct aout_backend_data +{ + /* Are ZMAGIC files mapped contiguously? If so, the text section may + need more padding, if the segment size (granularity for memory access + control) is larger than the page size. */ + unsigned char zmagic_mapped_contiguous; + /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the + text section, which starts immediately after the file header. + If not, the text section starts on the next page. */ + unsigned char text_includes_header; + + /* The value to pass to N_SET_FLAGS. */ + unsigned char exec_hdr_flags; + + /* If the text section VMA isn't specified, and we need an absolute + address, use this as the default. If we're producing a relocatable + file, zero is always used. */ + /* ?? Perhaps a callback would be a better choice? Will this do anything + reasonable for a format that handles multiple CPUs with different + load addresses for each? */ + bfd_vma default_text_vma; + + /* Callback for setting the page and segment sizes, if they can't be + trivially determined from the architecture. */ + boolean (*set_sizes) PARAMS ((bfd *)); + + /* zmagic files only. For go32, the length of the exec header contributes + to the size of the text section in the file for alignment purposes but + does *not* get counted in the length of the text section. */ + unsigned char exec_header_not_counted; + + /* Callback from the add symbols phase of the linker code to handle + a dynamic object. */ + boolean (*add_dynamic_symbols) PARAMS ((bfd *, struct bfd_link_info *, + struct external_nlist **, + bfd_size_type *, char **)); + + /* Callback from the add symbols phase of the linker code to handle + adding a single symbol to the global linker hash table. */ + boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *, + const char *, flagword, asection *, + bfd_vma, const char *, boolean, + boolean, + struct bfd_link_hash_entry **)); + + /* Called to handle linking a dynamic object. */ + boolean (*link_dynamic_object) PARAMS ((struct bfd_link_info *, bfd *)); + + /* Called for each global symbol being written out by the linker. + This should write out the dynamic symbol information. */ + boolean (*write_dynamic_symbol) PARAMS ((bfd *, struct bfd_link_info *, + struct aout_link_hash_entry *)); + + /* If this callback is not NULL, the linker calls it for each reloc. + RELOC is a pointer to the unswapped reloc. If *SKIP is set to + true, the reloc will be skipped. *RELOCATION may be changed to + change the effects of the relocation. */ + boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + struct aout_link_hash_entry *h, + PTR reloc, bfd_byte *contents, + boolean *skip, + bfd_vma *relocation)); + + /* Called at the end of a link to finish up any dynamic linking + information. */ + boolean (*finish_dynamic_link) PARAMS ((bfd *, struct bfd_link_info *)); +}; +#define aout_backend_info(abfd) \ + ((CONST struct aout_backend_data *)((abfd)->xvec->backend_data)) + +/* This is the layout in memory of a "struct exec" while we process it. + All 'lengths' are given as a number of bytes. + All 'alignments' are for relinkable files only; an alignment of + 'n' indicates the corresponding segment must begin at an + address that is a multiple of (2**n). */ + +struct internal_exec +{ + long a_info; /* Magic number and flags, packed */ + bfd_vma a_text; /* length of text, in bytes */ + bfd_vma a_data; /* length of data, in bytes */ + bfd_vma a_bss; /* length of uninitialized data area in mem */ + bfd_vma a_syms; /* length of symbol table data in file */ + bfd_vma a_entry; /* start address */ + bfd_vma a_trsize; /* length of text's relocation info, in bytes */ + bfd_vma a_drsize; /* length of data's relocation info, in bytes */ + /* Added for i960 */ + bfd_vma a_tload; /* Text runtime load address */ + bfd_vma a_dload; /* Data runtime load address */ + unsigned char a_talign; /* Alignment of text segment */ + unsigned char a_dalign; /* Alignment of data segment */ + unsigned char a_balign; /* Alignment of bss segment */ + char a_relaxable; /* Enough info for linker relax */ +}; + +/* Magic number is written +< MSB > +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > +*/ +/* Magic number for NetBSD is + +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< >< MAGIC NUMBER > +*/ + +enum machine_type { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of suns numbers */ + /* make these up for the ns32k*/ + M_NS32032 = (64), /* ns32032 running ? */ + M_NS32532 = (64 + 5), /* ns32532 running mach */ + + M_386 = 100, + M_29K = 101, /* AMD 29000 */ + M_386_DYNIX = 102, /* Sequent running dynix */ + M_ARM = 103, /* Advanced Risc Machines ARM */ + M_386_NETBSD = 134, /* NetBSD/i386 binary */ + M_68K_NETBSD = 135, /* NetBSD/m68k binary */ + M_68K4K_NETBSD = 136, /* NetBSD/m68k4k binary */ + M_532_NETBSD = 137, /* NetBSD/ns32k binary */ + M_SPARC_NETBSD = 138, /* NetBSD/sparc binary */ + M_MIPS1 = 151, /* MIPS R2000/R3000 binary */ + M_MIPS2 = 152, /* MIPS R4000/R6000 binary */ + M_HP200 = 200, /* HP 200 (68010) BSD binary */ + M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */ + M_HPUX = (0x20c % 256)/* HP 200/300 HPUX binary */ +}; + +#define N_DYNAMIC(exec) ((exec).a_info & 0x80000000) + +#ifndef N_MAGIC +# define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif + +#ifndef N_MACHTYPE +# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#endif + +#ifndef N_FLAGS +# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#endif + +#ifndef N_SET_INFO +# define N_SET_INFO(exec, magic, type, flags) \ +((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#endif + +#ifndef N_SET_DYNAMIC +# define N_SET_DYNAMIC(exec, dynamic) \ +((exec).a_info = (dynamic) ? ((exec).a_info | 0x80000000) : \ +((exec).a_info & 0x7fffffff)) +#endif + +#ifndef N_SET_MAGIC +# define N_SET_MAGIC(exec, magic) \ +((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +#endif + +#ifndef N_SET_MACHTYPE +# define N_SET_MACHTYPE(exec, machtype) \ +((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +#endif + +#ifndef N_SET_FLAGS +# define N_SET_FLAGS(exec, flags) \ +((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +#endif + +typedef struct aout_symbol { + asymbol symbol; + short desc; + char other; + unsigned char type; +} aout_symbol_type; + +/* The `tdata' struct for all a.out-like object file formats. + Various things depend on this struct being around any time an a.out + file is being handled. An example is dbxread.c in GDB. */ + +struct aoutdata { + struct internal_exec *hdr; /* exec file header */ + aout_symbol_type *symbols; /* symtab for input bfd */ + + /* For ease, we do this */ + asection *textsec; + asection *datasec; + asection *bsssec; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. */ + file_ptr sym_filepos; + file_ptr str_filepos; + + /* Size of a relocation entry in external form */ + unsigned reloc_entry_size; + + /* Size of a symbol table entry in external form */ + unsigned symbol_entry_size; + + /* Page size - needed for alignment of demand paged files. */ + unsigned long page_size; + + /* Segment size - needed for alignment of demand paged files. */ + unsigned long segment_size; + + /* Zmagic disk block size - need to align the start of the text + section in ZMAGIC binaries. Normally the same as page_size. */ + unsigned long zmagic_disk_block_size; + + unsigned exec_bytes_size; + unsigned vma_adjusted : 1; + + /* used when a bfd supports several highly similar formats */ + enum + { + default_format = 0, + /* Used on HP 9000/300 running HP/UX. See hp300hpux.c. */ + gnu_encap_format, + /* Used on Linux, 386BSD, etc. See include/aout/aout64.h. */ + q_magic_format + } subformat; + + enum + { + undecided_magic = 0, + z_magic, + o_magic, + n_magic + } magic; + + /* A buffer for find_nearest_line. */ + char *line_buf; + + /* The external symbol information. */ + struct external_nlist *external_syms; + bfd_size_type external_sym_count; + bfd_window sym_window; + char *external_strings; + bfd_size_type external_string_size; + bfd_window string_window; + struct aout_link_hash_entry **sym_hashes; + + /* A pointer for shared library information. */ + PTR dynamic_info; + + /* A mapping from local symbols to offsets into the global offset + table, used when linking on SunOS. This is indexed by the symbol + index. */ + bfd_vma *local_got_offsets; +}; + +struct aout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +#define adata(bfd) ((bfd)->tdata.aout_data->a) +#define exec_hdr(bfd) (adata(bfd).hdr) +#define obj_aout_symbols(bfd) (adata(bfd).symbols) +#define obj_textsec(bfd) (adata(bfd).textsec) +#define obj_datasec(bfd) (adata(bfd).datasec) +#define obj_bsssec(bfd) (adata(bfd).bsssec) +#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos) +#define obj_str_filepos(bfd) (adata(bfd).str_filepos) +#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size) +#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size) +#define obj_aout_subformat(bfd) (adata(bfd).subformat) +#define obj_aout_external_syms(bfd) (adata(bfd).external_syms) +#define obj_aout_external_sym_count(bfd) (adata(bfd).external_sym_count) +#define obj_aout_sym_window(bfd) (adata(bfd).sym_window) +#define obj_aout_external_strings(bfd) (adata(bfd).external_strings) +#define obj_aout_external_string_size(bfd) (adata(bfd).external_string_size) +#define obj_aout_string_window(bfd) (adata(bfd).string_window) +#define obj_aout_sym_hashes(bfd) (adata(bfd).sym_hashes) +#define obj_aout_dynamic_info(bfd) (adata(bfd).dynamic_info) + +/* We take the address of the first element of an asymbol to ensure that the + macro is only ever applied to an asymbol */ +#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) + +/* Information we keep for each a.out section. This is currently only + used by the a.out backend linker. */ + +struct aout_section_data_struct +{ + /* The unswapped relocation entries for this section. */ + PTR relocs; +}; + +#define aout_section_data(s) \ + ((struct aout_section_data_struct *) (s)->used_by_bfd) + +#define set_aout_section_data(s,v) \ + ((s)->used_by_bfd = (PTR)&(v)->relocs) + +/* Prototype declarations for functions defined in aoutx.h */ + +boolean +NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section)); + +boolean +NAME(aout,make_sections) PARAMS ((bfd *)); + +const bfd_target * +NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd, + struct internal_exec *execp, + const bfd_target *(*callback)(bfd *))); + +boolean +NAME(aout,mkobject) PARAMS ((bfd *abfd)); + +enum machine_type +NAME(aout,machine_type) PARAMS ((enum bfd_architecture arch, + unsigned long machine, + boolean *unknown)); + +boolean +NAME(aout,set_arch_mach) PARAMS ((bfd *abfd, enum bfd_architecture arch, + unsigned long machine)); + +boolean +NAME(aout,new_section_hook) PARAMS ((bfd *abfd, asection *newsect)); + +boolean +NAME(aout,set_section_contents) PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, bfd_size_type count)); + +asymbol * +NAME(aout,make_empty_symbol) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,translate_symbol_table) PARAMS ((bfd *, aout_symbol_type *, + struct external_nlist *, + bfd_size_type, char *, + bfd_size_type, + boolean dynamic)); + +boolean +NAME(aout,slurp_symbol_table) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,write_syms) PARAMS ((bfd *abfd)); + +void +NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd)); + +long +NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd)); + +long +NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location)); + +void +NAME(aout,swap_ext_reloc_in) PARAMS ((bfd *, struct reloc_ext_external *, + arelent *, asymbol **, bfd_size_type)); +void +NAME(aout,swap_std_reloc_in) PARAMS ((bfd *, struct reloc_std_external *, + arelent *, asymbol **, bfd_size_type)); + +reloc_howto_type * +NAME(aout,reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + +boolean +NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect, + asymbol **symbols)); + +long +NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section, + arelent **relptr, asymbol **symbols)); + +long +NAME(aout,get_reloc_upper_bound) PARAMS ((bfd *abfd, sec_ptr asect)); + +void +NAME(aout,reclaim_reloc) PARAMS ((bfd *ignore_abfd, sec_ptr ignore)); + +alent * +NAME(aout,get_lineno) PARAMS ((bfd *ignore_abfd, asymbol *ignore_symbol)); + +void +NAME(aout,print_symbol) PARAMS ((bfd *ignore_abfd, PTR file, + asymbol *symbol, bfd_print_symbol_type how)); + +void +NAME(aout,get_symbol_info) PARAMS ((bfd *ignore_abfd, + asymbol *symbol, symbol_info *ret)); + +boolean +NAME(aout,find_nearest_line) PARAMS ((bfd *abfd, asection *section, + asymbol **symbols, bfd_vma offset, CONST char **filename_ptr, + CONST char **functionname_ptr, unsigned int *line_ptr)); + +long +NAME(aout,read_minisymbols) PARAMS ((bfd *, boolean, PTR *, unsigned int *)); + +asymbol * +NAME(aout,minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR, + asymbol *)); + +int +NAME(aout,sizeof_headers) PARAMS ((bfd *abfd, boolean exec)); + +boolean +NAME(aout,adjust_sizes_and_vmas) PARAMS ((bfd *abfd, + bfd_size_type *text_size, file_ptr *text_end)); + +void +NAME(aout,swap_exec_header_in) PARAMS ((bfd *abfd, + struct external_exec *raw_bytes, struct internal_exec *execp)); + +void +NAME(aout,swap_exec_header_out) PARAMS ((bfd *abfd, + struct internal_exec *execp, struct external_exec *raw_bytes)); + +struct bfd_hash_entry * +NAME(aout,link_hash_newfunc) + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +boolean +NAME(aout,link_hash_table_init) + PARAMS ((struct aout_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +struct bfd_link_hash_table * +NAME(aout,link_hash_table_create) PARAMS ((bfd *)); + +boolean +NAME(aout,link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); + +boolean +NAME(aout,final_link) PARAMS ((bfd *, struct bfd_link_info *, + void (*) (bfd *, file_ptr *, file_ptr *, + file_ptr *))); + +boolean +NAME(aout,bfd_free_cached_info) PARAMS ((bfd *)); + +/* A.out uses the generic versions of these routines... */ + +#define aout_32_get_section_contents _bfd_generic_get_section_contents + +#define aout_64_get_section_contents _bfd_generic_get_section_contents +#ifndef NO_WRITE_HEADER_KLUDGE +#define NO_WRITE_HEADER_KLUDGE 0 +#endif + +#ifndef aout_32_bfd_is_local_label +#define aout_32_bfd_is_local_label bfd_generic_is_local_label +#endif + +#ifndef WRITE_HEADERS +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false; \ + if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) \ + != EXEC_BYTES_SIZE) \ + return false; \ + /* Now write out reloc info, followed by syms and strings */ \ + \ + if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \ + && bfd_get_symcount (abfd) != 0) \ + { \ + if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET) \ + != 0) \ + return false; \ + \ + if (! NAME(aout,write_syms)(abfd)) return false; \ + \ + if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET) \ + != 0) \ + return false; \ + \ + if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) \ + return false; \ + if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET) \ + != 0) \ + return false; \ + \ + if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) \ + return false; \ + } \ + } +#endif + +#endif /* ! defined (LIBAOUT_H) */ diff --git a/contrib/gdb/bfd/libbfd-in.h b/contrib/gdb/bfd/libbfd-in.h new file mode 100644 index 000000000000..14935ebbeabc --- /dev/null +++ b/contrib/gdb/bfd/libbfd-in.h @@ -0,0 +1,503 @@ +/* libbfd.h -- Declarations used by bfd library *implementation*. + (This include file is not for users of the library.) + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +** NOTE: libbfd.h is a GENERATED file. Don't change it; instead, +** change libbfd-in.h or the other BFD source files processed to +** generate this file. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. */ +#define BFD_ALIGN(this, boundary) \ + ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* Set a tdata field. Can't use the other macros for this, since they + do casts, and casting to the left of assignment isn't portable. */ +#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v)) + +/* If BFD_IN_MEMORY is set for a BFD, then the iostream fields points + to an instance of this structure. */ + +struct bfd_in_memory +{ + /* Size of buffer. */ + bfd_size_type size; + /* Buffer holding contents of BFD. */ + bfd_byte *buffer; +}; + +/* tdata for an archive. For an input archive, cache + needs to be free()'d. For an output archive, symdefs do. */ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *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 */ + /* 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 + for the BSD linker to not complain, + just before we finish writing an + archive. */ + file_ptr armap_datepos; /* Position within archive to seek to + rewrite the date field. */ + PTR tdata; /* Backend specific information. */ +}; + +#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 */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +extern PTR bfd_malloc PARAMS ((size_t)); +extern PTR bfd_realloc PARAMS ((PTR, size_t)); +extern PTR bfd_zmalloc PARAMS ((size_t)); + +extern bfd_error_handler_type _bfd_error_handler; + +/* These routines allocate and free things on the BFD's obstack. */ + +PTR bfd_alloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size)); +void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size)); +PTR bfd_alloc_finish PARAMS ((bfd *abfd)); +PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted)); + +#define bfd_release(x,y) (void) obstack_free(&(x->memory),y) + +bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd)); +bfd * _bfd_look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index)); +boolean _bfd_add_bfd_to_archive_cache PARAMS ((bfd *, file_ptr, bfd *)); +boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd)); +const bfd_target *bfd_generic_archive_p PARAMS ((bfd *abfd)); +boolean bfd_slurp_armap PARAMS ((bfd *abfd)); +boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd)); +#define bfd_slurp_bsd_armap bfd_slurp_armap +#define bfd_slurp_coff_armap bfd_slurp_armap +boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd)); +extern boolean _bfd_construct_extended_name_table + PARAMS ((bfd *, boolean, char **, bfd_size_type *)); +boolean _bfd_write_archive_contents PARAMS ((bfd *abfd)); +boolean _bfd_compute_and_write_armap PARAMS ((bfd *, unsigned int elength)); +bfd *_bfd_get_elt_at_filepos PARAMS ((bfd *archive, file_ptr filepos)); +extern bfd *_bfd_generic_get_elt_at_index PARAMS ((bfd *, symindex)); +bfd * _bfd_new_bfd PARAMS ((void)); + +boolean bfd_false PARAMS ((bfd *ignore)); +boolean bfd_true PARAMS ((bfd *ignore)); +PTR bfd_nullvoidptr PARAMS ((bfd *ignore)); +int bfd_0 PARAMS ((bfd *ignore)); +unsigned int bfd_0u PARAMS ((bfd *ignore)); +long bfd_0l PARAMS ((bfd *ignore)); +long _bfd_n1 PARAMS ((bfd *ignore)); +void bfd_void PARAMS ((bfd *ignore)); + +bfd *_bfd_new_bfd_contained_in PARAMS ((bfd *)); +const bfd_target *_bfd_dummy_target PARAMS ((bfd *abfd)); + +void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); + +boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +extern PTR _bfd_generic_read_ar_hdr PARAMS ((bfd *)); + +extern PTR _bfd_generic_read_ar_hdr_mag PARAMS ((bfd *, const char *)); + +bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive, + bfd *last_file)); + +int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); + +#define _bfd_read_ar_hdr(abfd) \ + BFD_SEND (abfd, _bfd_read_ar_hdr_fn, (abfd)) + +/* 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_bfd_free_cached_info bfd_true +#define _bfd_generic_new_section_hook \ + ((boolean (*) PARAMS ((bfd *, asection *))) bfd_true) +extern boolean _bfd_generic_get_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr offset, + bfd_size_type count)); +extern boolean _bfd_generic_get_section_contents_in_window + PARAMS ((bfd *, asection *, bfd_window *, file_ptr, bfd_size_type)); + +/* Generic routines to use for BFD_JUMP_TABLE_COPY. Use + BFD_JUMP_TABLE_COPY (_bfd_generic). */ + +#define _bfd_generic_bfd_copy_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_merge_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_set_private_flags \ + ((boolean (*) PARAMS ((bfd *, flagword))) bfd_true) +#define _bfd_generic_bfd_copy_private_section_data \ + ((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true) +#define _bfd_generic_bfd_copy_private_symbol_data \ + ((boolean (*) PARAMS ((bfd *, asymbol *, bfd *, asymbol *))) bfd_true) +#define _bfd_generic_bfd_print_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, PTR))) bfd_true) + +/* Routines to use for BFD_JUMP_TABLE_CORE when there is no core file + support. Use BFD_JUMP_TABLE_CORE (_bfd_nocore). */ + +extern char *_bfd_nocore_core_file_failing_command PARAMS ((bfd *)); +extern int _bfd_nocore_core_file_failing_signal PARAMS ((bfd *)); +extern boolean _bfd_nocore_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE when there is no archive + file support. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive). */ + +#define _bfd_noarchive_slurp_armap bfd_false +#define _bfd_noarchive_slurp_extended_name_table bfd_false +#define _bfd_noarchive_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_false) +#define _bfd_noarchive_truncate_arname \ + ((void (*) PARAMS ((bfd *, const char *, char *))) bfd_void) +#define _bfd_noarchive_write_armap \ + ((boolean (*) \ + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ + bfd_false) +#define _bfd_noarchive_read_ar_hdr bfd_nullvoidptr +#define _bfd_noarchive_openr_next_archived_file \ + ((bfd *(*) PARAMS ((bfd *, bfd *))) bfd_nullvoidptr) +#define _bfd_noarchive_get_elt_at_index \ + ((bfd *(*) PARAMS ((bfd *, symindex))) bfd_nullvoidptr) +#define _bfd_noarchive_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define _bfd_noarchive_update_armap_timestamp bfd_false + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd). */ + +#define _bfd_archive_bsd_slurp_armap bfd_slurp_bsd_armap +#define _bfd_archive_bsd_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern boolean _bfd_archive_bsd_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_bsd_truncate_arname bfd_bsd_truncate_arname +#define _bfd_archive_bsd_write_armap bsd_write_armap +#define _bfd_archive_bsd_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_bsd_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_bsd_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_bsd_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +extern boolean _bfd_archive_bsd_update_armap_timestamp PARAMS ((bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get COFF style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff). */ + +#define _bfd_archive_coff_slurp_armap bfd_slurp_coff_armap +#define _bfd_archive_coff_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern boolean _bfd_archive_coff_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_coff_truncate_arname bfd_dont_truncate_arname +#define _bfd_archive_coff_write_armap coff_write_armap +#define _bfd_archive_coff_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_coff_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_coff_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_coff_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +#define _bfd_archive_coff_update_armap_timestamp bfd_true + +/* Routines to use for BFD_JUMP_TABLE_SYMBOLS where there is no symbol + support. Use BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols). */ + +#define _bfd_nosymbols_get_symtab_upper_bound _bfd_n1 +#define _bfd_nosymbols_get_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nosymbols_make_empty_symbol \ + ((asymbol *(*) PARAMS ((bfd *))) bfd_nullvoidptr) +#define _bfd_nosymbols_print_symbol \ + ((void (*) PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void) +#define _bfd_nosymbols_get_symbol_info \ + ((void (*) PARAMS ((bfd *, asymbol *, symbol_info *))) bfd_void) +#define _bfd_nosymbols_bfd_is_local_label \ + ((boolean (*) PARAMS ((bfd *, asymbol *))) bfd_false) +#define _bfd_nosymbols_get_lineno \ + ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr) +#define _bfd_nosymbols_find_nearest_line \ + ((boolean (*) \ + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, \ + const char **, unsigned int *))) \ + bfd_false) +#define _bfd_nosymbols_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, PTR, unsigned long))) bfd_nullvoidptr) +#define _bfd_nosymbols_read_minisymbols \ + ((long (*) PARAMS ((bfd *, boolean, PTR *, unsigned int *))) _bfd_n1) +#define _bfd_nosymbols_minisymbol_to_symbol \ + ((asymbol *(*) PARAMS ((bfd *, boolean, const PTR, asymbol *))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_RELOCS when there is no reloc + support. Use BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */ + +#define _bfd_norelocs_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) _bfd_n1) +#define _bfd_norelocs_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) _bfd_n1) +#define _bfd_norelocs_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_WRITE for targets which may not + be written. Use BFD_JUMP_TABLE_WRITE (_bfd_nowrite). */ + +#define _bfd_nowrite_set_arch_mach \ + ((boolean (*) PARAMS ((bfd *, enum bfd_architecture, unsigned long))) \ + bfd_false) +#define _bfd_nowrite_set_section_contents \ + ((boolean (*) PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type))) \ + bfd_false) + +/* Generic routines to use for BFD_JUMP_TABLE_WRITE. Use + BFD_JUMP_TABLE_WRITE (_bfd_generic). */ + +#define _bfd_generic_set_arch_mach bfd_default_set_arch_mach +extern boolean _bfd_generic_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); + +/* Routines to use for BFD_JUMP_TABLE_LINK for targets which do not + support linking. Use BFD_JUMP_TABLE_LINK (_bfd_nolink). */ + +#define _bfd_nolink_sizeof_headers ((int (*) PARAMS ((bfd *, boolean))) bfd_0) +#define _bfd_nolink_bfd_get_relocated_section_contents \ + ((bfd_byte *(*) \ + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, \ + bfd_byte *, boolean, asymbol **))) \ + bfd_nullvoidptr) +#define _bfd_nolink_bfd_relax_section \ + ((boolean (*) \ + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *))) \ + bfd_false) +#define _bfd_nolink_bfd_link_hash_table_create \ + ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr) +#define _bfd_nolink_bfd_link_add_symbols \ + ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_final_link \ + ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_link_split_section \ + ((boolean (*) PARAMS ((bfd *, struct sec *))) bfd_false) + +/* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not + have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC + (_bfd_nodynamic). */ + +#define _bfd_nodynamic_get_dynamic_symtab_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_reloc \ + ((long (*) PARAMS ((bfd *, arelent **, asymbol **))) _bfd_n1) + +/* Generic routine to determine of the given symbol is a local + label. */ +extern boolean bfd_generic_is_local_label PARAMS ((bfd *, asymbol *)); + +/* Generic minisymbol routines. */ +extern long _bfd_generic_read_minisymbols + PARAMS ((bfd *, boolean, PTR *, unsigned int *)); +extern asymbol *_bfd_generic_minisymbol_to_symbol + PARAMS ((bfd *, boolean, const PTR, asymbol *)); + +/* Find the nearest line using .stab/.stabstr sections. */ +extern boolean _bfd_stab_section_find_nearest_line + PARAMS ((bfd *, asymbol **, asection *, bfd_vma, boolean *, const char **, + const char **, unsigned int *, PTR *)); + +/* A routine to create entries for a bfd_link_hash_table. */ +extern struct bfd_hash_entry *_bfd_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string)); + +/* Initialize a bfd_link_hash_table. */ +extern boolean _bfd_link_hash_table_init + PARAMS ((struct bfd_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Generic link hash table creation routine. */ +extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create + PARAMS ((bfd *)); + +/* Generic add symbol routine. */ +extern boolean _bfd_generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic add symbol routine. This version is used by targets for + which the linker must collect constructors and destructors by name, + as the collect2 program does. */ +extern boolean _bfd_generic_link_add_symbols_collect + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic archive add symbol routine. */ +extern boolean _bfd_generic_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *, + boolean (*checkfn) (bfd *, struct bfd_link_info *, boolean *))); + +/* Forward declaration to avoid prototype errors. */ +typedef struct bfd_link_hash_entry _bfd_link_hash_entry; + +/* Generic routine to add a single symbol. */ +extern boolean _bfd_generic_link_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword, + asection *, bfd_vma, const char *, boolean copy, + boolean constructor, struct bfd_link_hash_entry **)); + +/* Generic link routine. */ +extern boolean _bfd_generic_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern boolean _bfd_generic_link_split_section + PARAMS ((bfd *, struct sec *)); + +/* Generic reloc_link_order processing routine. */ +extern boolean _bfd_generic_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Default link order processing routine. */ +extern boolean _bfd_default_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Count the number of reloc entries in a link order list. */ +extern unsigned int _bfd_count_link_order_relocs + PARAMS ((struct bfd_link_order *)); + +/* Final link relocation routine. */ +extern bfd_reloc_status_type _bfd_final_link_relocate + PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, + bfd_vma address, bfd_vma value, bfd_vma addend)); + +/* Relocate a particular location by a howto and a value. */ +extern bfd_reloc_status_type _bfd_relocate_contents + PARAMS ((reloc_howto_type *, bfd *, bfd_vma, bfd_byte *)); + +/* Create a string table. */ +extern struct bfd_strtab_hash *_bfd_stringtab_init PARAMS ((void)); + +/* Create an XCOFF .debug section style string table. */ +extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init PARAMS ((void)); + +/* Free a string table. */ +extern void _bfd_stringtab_free PARAMS ((struct bfd_strtab_hash *)); + +/* Get the size of a string table. */ +extern bfd_size_type _bfd_stringtab_size PARAMS ((struct bfd_strtab_hash *)); + +/* Add a string to a string table. */ +extern bfd_size_type _bfd_stringtab_add + PARAMS ((struct bfd_strtab_hash *, const char *, boolean hash, + boolean copy)); + +/* Write out a string table. */ +extern boolean _bfd_stringtab_emit PARAMS ((bfd *, struct bfd_strtab_hash *)); + +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +void bfd_assert PARAMS ((const char*,int)); + +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +FILE * bfd_cache_lookup_worker PARAMS ((bfd *)); + +extern bfd *bfd_last_cache; + +/* Now Steve, what's the story here? */ +#ifdef lint +#define itos(x) "l" +#define stoi(x) 1 +#else +#define itos(x) ((char*)(x)) +#define stoi(x) ((int)(x)) +#endif + +/* List of supported target vectors, and the default vector (if + bfd_default_vector[0] is NULL, there is no default). */ +extern const bfd_target * const bfd_target_vector[]; +extern const bfd_target * const bfd_default_vector[]; + +/* Functions shared by the ECOFF and MIPS ELF backends, which have no + other common header files. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_find_line; +#endif + +extern boolean _bfd_ecoff_locate_line + PARAMS ((bfd *, asection *, bfd_vma, struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, struct ecoff_find_line *, + const char **, const char **, unsigned int *)); +extern boolean _bfd_ecoff_get_accumulated_pdr PARAMS ((PTR, bfd_byte *)); +extern boolean _bfd_ecoff_get_accumulated_sym PARAMS ((PTR, bfd_byte *)); +extern boolean _bfd_ecoff_get_accumulated_ss PARAMS ((PTR, bfd_byte *)); + +extern bfd_vma _bfd_get_gp_value PARAMS ((bfd *)); +extern void _bfd_set_gp_value PARAMS ((bfd *, bfd_vma)); + +/* And more follows */ + diff --git a/contrib/gdb/bfd/libbfd.c b/contrib/gdb/bfd/libbfd.c new file mode 100644 index 000000000000..1052a3a17be5 --- /dev/null +++ b/contrib/gdb/bfd/libbfd.c @@ -0,0 +1,1197 @@ +/* Assorted BFD support routines, only used internally. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static int real_read PARAMS ((PTR, size_t, size_t, FILE *)); + +/* +SECTION + Internal functions + +DESCRIPTION + These routines are used within BFD. + They are not intended for export, but are documented here for + completeness. +*/ + +/* A routine which is used in target vectors for unsupported + operations. */ + +/*ARGSUSED*/ +boolean +bfd_false (ignore) + bfd *ignore; +{ + bfd_set_error (bfd_error_invalid_operation); + return false; +} + +/* A routine which is used in target vectors for supported operations + which do not actually do anything. */ + +/*ARGSUSED*/ +boolean +bfd_true (ignore) + bfd *ignore; +{ + return true; +} + +/* A routine which is used in target vectors for unsupported + operations which return a pointer value. */ + +/*ARGSUSED*/ +PTR +bfd_nullvoidptr (ignore) + bfd *ignore; +{ + bfd_set_error (bfd_error_invalid_operation); + return NULL; +} + +/*ARGSUSED*/ +int +bfd_0 (ignore) + bfd *ignore; +{ + return 0; +} + +/*ARGSUSED*/ +unsigned int +bfd_0u (ignore) + bfd *ignore; +{ + return 0; +} + +/*ARGUSED*/ +long +bfd_0l (ignore) + bfd *ignore; +{ + return 0; +} + +/* A routine which is used in target vectors for unsupported + operations which return -1 on error. */ + +/*ARGSUSED*/ +long +_bfd_n1 (ignore_abfd) + bfd *ignore_abfd; +{ + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + +/*ARGSUSED*/ +void +bfd_void (ignore) + bfd *ignore; +{ +} + +/*ARGSUSED*/ +boolean +_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd) + bfd *ignore_core_bfd; + bfd *ignore_exec_bfd; +{ + bfd_set_error (bfd_error_invalid_operation); + return false; +} + +/* Routine to handle core_file_failing_command entry point for targets + without core file support. */ + +/*ARGSUSED*/ +char * +_bfd_nocore_core_file_failing_command (ignore_abfd) + bfd *ignore_abfd; +{ + bfd_set_error (bfd_error_invalid_operation); + return (char *)NULL; +} + +/* Routine to handle core_file_failing_signal entry point for targets + without core file support. */ + +/*ARGSUSED*/ +int +_bfd_nocore_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd; +{ + bfd_set_error (bfd_error_invalid_operation); + return 0; +} + +/*ARGSUSED*/ +const bfd_target * +_bfd_dummy_target (ignore_abfd) + bfd *ignore_abfd; +{ + bfd_set_error (bfd_error_wrong_format); + return 0; +} + +/* Allocate memory using malloc. */ + +PTR +bfd_malloc (size) + size_t size; +{ + PTR ptr; + + ptr = (PTR) malloc (size); + if (ptr == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); + return ptr; +} + +/* Reallocate memory using realloc. */ + +PTR +bfd_realloc (ptr, size) + PTR ptr; + size_t size; +{ + PTR ret; + + if (ptr == NULL) + ret = malloc (size); + else + ret = realloc (ptr, size); + + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); + + return ret; +} + +/* Allocate memory using malloc and clear it. */ + +PTR +bfd_zmalloc (size) + size_t size; +{ + PTR ptr; + + ptr = (PTR) malloc (size); + + if (size != 0) + { + if (ptr == NULL) + bfd_set_error (bfd_error_no_memory); + else + memset (ptr, 0, size); + } + + return ptr; +} + +/* Some IO code */ + + +/* Note that archive entries don't have streams; they share their parent's. + This allows someone to play with the iostream behind BFD's back. + + Also, note that the origin pointer points to the beginning of a file's + contents (0 for non-archive elements). For archive entries this is the + first octet in the file, NOT the beginning of the archive header. */ + +static int +real_read (where, a,b, file) + PTR where; + size_t a; + size_t b; + FILE *file; +{ + return fread (where, a, b, file); +} + +/* Return value is amount read (FIXME: how are errors and end of file dealt + with? We never call bfd_set_error, which is probably a mistake). */ + +bfd_size_type +bfd_read (ptr, size, nitems, abfd) + PTR ptr; + bfd_size_type size; + bfd_size_type nitems; + bfd *abfd; +{ + int nread; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim; + bfd_size_type get; + + bim = (struct bfd_in_memory *) abfd->iostream; + get = size * nitems; + if (abfd->where + get > bim->size) + { + get = bim->size - abfd->where; + bfd_set_error (bfd_error_file_truncated); + } + memcpy (ptr, bim->buffer + abfd->where, get); + abfd->where += get; + return get; + } + + nread = real_read (ptr, 1, (size_t)(size*nitems), bfd_cache_lookup(abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nread > 0) + abfd->where += nread; +#endif + + /* Set bfd_error if we did not read as much data as we expected. + + If the read failed due to an error set the bfd_error_system_call, + else set bfd_error_file_truncated. + + A BFD backend may wish to override bfd_error_file_truncated to + provide something more useful (eg. no_symbols or wrong_format). */ + if (nread < (int)(size * nitems)) + { + if (ferror (bfd_cache_lookup (abfd))) + bfd_set_error (bfd_error_system_call); + else + bfd_set_error (bfd_error_file_truncated); + } + + return nread; +} + +/* The window support stuff should probably be broken out into + another file.... */ +/* The idea behind the next and refcount fields is that one mapped + region can suffice for multiple read-only windows or multiple + non-overlapping read-write windows. It's not implemented yet + though. */ +struct _bfd_window_internal { + struct _bfd_window_internal *next; + PTR data; + bfd_size_type size; + int refcount : 31; /* should be enough... */ + unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ +}; + +void +bfd_init_window (windowp) + bfd_window *windowp; +{ + windowp->data = 0; + windowp->i = 0; + windowp->size = 0; +} + +#undef HAVE_MPROTECT /* code's not tested yet */ + +#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE +#include +#include +#endif + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +static int debug_windows; + +/* Currently, if USE_MMAP is undefined, none if the window stuff is + used. Okay, so it's mis-named. At least the command-line option + "--without-mmap" is more obvious than "--without-windows" or some + such. */ +#ifdef USE_MMAP + +void +bfd_free_window (windowp) + bfd_window *windowp; +{ + bfd_window_internal *i = windowp->i; + windowp->i = 0; + windowp->data = 0; + if (i == 0) + return; + i->refcount--; + if (debug_windows) + fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n", + windowp, windowp->data, windowp->size, windowp->i); + if (i->refcount != 0) + return; + + if (i->mapped) + { +#ifdef HAVE_MMAP + munmap (i->data, i->size); + goto no_free; +#else + abort (); +#endif + } +#ifdef HAVE_MPROTECT + mprotect (i->data, i->size, PROT_READ | PROT_WRITE); +#endif + free (i->data); +#ifdef HAVE_MMAP + no_free: +#endif + i->data = 0; + /* There should be no more references to i at this point. */ + free (i); +} +#endif + +static int ok_to_map = 1; + +boolean +bfd_get_file_window (abfd, offset, size, windowp, writable) + bfd *abfd; + file_ptr offset; + bfd_size_type size; + bfd_window *windowp; + boolean writable; +{ + static size_t pagesize; + bfd_window_internal *i = windowp->i; + size_t size_to_alloc = size; + +#ifndef USE_MMAP + abort (); +#endif + + if (debug_windows) + fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", + abfd, (long) offset, (long) size, + windowp, windowp->data, windowp->size, windowp->i, + writable); + + /* Make sure we know the page size, so we can be friendly to mmap. */ + if (pagesize == 0) + pagesize = getpagesize (); + if (pagesize == 0) + abort (); + + if (i == 0) + { + windowp->i = i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (i == 0) + return false; + i->data = 0; + } +#ifdef HAVE_MMAP + if (ok_to_map + && (i->data == 0 || i->mapped == 1) + && (abfd->flags & BFD_IN_MEMORY) == 0) + { + file_ptr file_offset, offset2; + size_t real_size; + int fd; + FILE *f; + + /* Find the real file and the real offset into it. */ + while (abfd->my_archive != NULL) + { + offset += abfd->origin; + abfd = abfd->my_archive; + } + f = bfd_cache_lookup (abfd); + fd = fileno (f); + + /* Compute offsets and size for mmap and for the user's data. */ + offset2 = offset % pagesize; + if (offset2 < 0) + abort (); + file_offset = offset - offset2; + real_size = offset + size - file_offset; + real_size = real_size + pagesize - 1; + real_size -= real_size % pagesize; + + /* If we're re-using a memory region, make sure it's big enough. */ + if (i->data && i->size < size) + { + munmap (i->data, i->size); + i->data = 0; + } + i->data = mmap (i->data, real_size, + writable ? PROT_WRITE | PROT_READ : PROT_READ, + (writable + ? MAP_FILE | MAP_PRIVATE + : MAP_FILE | MAP_SHARED), + fd, file_offset); + if (i->data == (PTR) -1) + { + /* An error happened. Report it, or try using malloc, or + something. */ + bfd_set_error (bfd_error_system_call); + i->data = 0; + windowp->data = 0; + if (debug_windows) + fprintf (stderr, "\t\tmmap failed!\n"); + return false; + } + if (debug_windows) + fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n", + (long) real_size, i->data, (long) offset2); + i->size = real_size; + windowp->data = (PTR) ((bfd_byte *) i->data + offset2); + windowp->size = size; + i->mapped = 1; + return true; + } + else if (debug_windows) + { + if (ok_to_map) + fprintf (stderr, "not mapping: data=%lx mapped=%d\n", + (unsigned long) i->data, (int) i->mapped); + else + fprintf (stderr, "not mapping: env var not set\n"); + } +#else + ok_to_map = 0; +#endif + +#ifdef HAVE_MPROTECT + if (!writable) + { + size_to_alloc += pagesize - 1; + size_to_alloc -= size_to_alloc % pagesize; + } +#endif + if (debug_windows) + fprintf (stderr, "\n\t%s(%6ld)", + i->data ? "realloc" : " malloc", (long) size_to_alloc); + i->data = (PTR) bfd_realloc (i->data, size_to_alloc); + if (debug_windows) + fprintf (stderr, "\t-> %p\n", i->data); + i->refcount = 1; + if (i->data == NULL) + { + if (size_to_alloc == 0) + return true; + bfd_set_error (bfd_error_no_memory); + return false; + } + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return false; + i->size = bfd_read (i->data, size, 1, abfd); + if (i->size != size) + return false; + i->mapped = 0; +#ifdef HAVE_MPROTECT + if (!writable) + { + if (debug_windows) + fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, + (long) i->size); + mprotect (i->data, i->size, PROT_READ); + } +#endif + windowp->data = i->data; + windowp->size = i->size; + return true; +} + +bfd_size_type +bfd_write (ptr, size, nitems, abfd) + CONST PTR ptr; + bfd_size_type size; + bfd_size_type nitems; + bfd *abfd; +{ + long nwrote; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + nwrote = fwrite (ptr, 1, (size_t) (size * nitems), + bfd_cache_lookup (abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nwrote > 0) + abfd->where += nwrote; +#endif + if ((bfd_size_type) nwrote != size * nitems) + { +#ifdef ENOSPC + if (nwrote >= 0) + errno = ENOSPC; +#endif + bfd_set_error (bfd_error_system_call); + } + return nwrote; +} + +/* +INTERNAL_FUNCTION + bfd_write_bigendian_4byte_int + +SYNOPSIS + void bfd_write_bigendian_4byte_int(bfd *abfd, int i); + +DESCRIPTION + Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big + endian order regardless of what else is going on. This is useful in + archives. + +*/ +void +bfd_write_bigendian_4byte_int (abfd, i) + bfd *abfd; + int i; +{ + bfd_byte buffer[4]; + bfd_putb32(i, buffer); + if (bfd_write((PTR)buffer, 4, 1, abfd) != 4) + abort (); +} + +long +bfd_tell (abfd) + bfd *abfd; +{ + file_ptr ptr; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return abfd->where; + + ptr = ftell (bfd_cache_lookup(abfd)); + + if (abfd->my_archive) + ptr -= abfd->origin; + abfd->where = ptr; + return ptr; +} + +int +bfd_flush (abfd) + bfd *abfd; +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return 0; + return fflush (bfd_cache_lookup(abfd)); +} + +/* Returns 0 for success, negative value for failure (in which case + bfd_get_error can retrieve the error code). */ +int +bfd_stat (abfd, statbuf) + bfd *abfd; + struct stat *statbuf; +{ + FILE *f; + int result; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + f = bfd_cache_lookup (abfd); + if (f == NULL) + { + bfd_set_error (bfd_error_system_call); + return -1; + } + result = fstat (fileno (f), statbuf); + if (result < 0) + bfd_set_error (bfd_error_system_call); + return result; +} + +/* Returns 0 for success, nonzero for failure (in which case bfd_get_error + can retrieve the error code). */ + +int +bfd_seek (abfd, position, direction) + bfd *abfd; + file_ptr position; + int direction; +{ + int result; + FILE *f; + file_ptr file_position; + /* For the time being, a BFD may not seek to it's end. The problem + is that we don't easily have a way to recognize the end of an + element in an archive. */ + + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); + + if (direction == SEEK_CUR && position == 0) + return 0; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; + return 0; + } + +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (abfd->format != bfd_archive && abfd->my_archive == 0) + { +#if 0 + /* Explanation for this code: I'm only about 95+% sure that the above + conditions are sufficient and that all i/o calls are properly + adjusting the `where' field. So this is sort of an `assert' + that the `where' field is correct. If we can go a while without + tripping the abort, we can probably safely disable this code, + so that the real optimizations happen. */ + file_ptr where_am_i_now; + where_am_i_now = ftell (bfd_cache_lookup (abfd)); + if (abfd->my_archive) + where_am_i_now -= abfd->origin; + if (where_am_i_now != abfd->where) + abort (); +#endif + if (direction == SEEK_SET && position == abfd->where) + return 0; + } + else + { + /* We need something smarter to optimize access to archives. + Currently, anything inside an archive is read via the file + handle for the archive. Which means that a bfd_seek on one + component affects the `current position' in the archive, as + well as in any other component. + + It might be sufficient to put a spike through the cache + abstraction, and look to the archive for the file position, + but I think we should try for something cleaner. + + In the meantime, no optimization for archives. */ + } +#endif + + f = bfd_cache_lookup (abfd); + file_position = position; + if (direction == SEEK_SET && abfd->my_archive != NULL) + file_position += abfd->origin; + + result = fseek (f, file_position, direction); + + if (result != 0) + { + /* Force redetermination of `where' field. */ + bfd_tell (abfd); + bfd_set_error (bfd_error_system_call); + } + else + { +#ifdef FILE_OFFSET_IS_CHAR_INDEX + /* Adjust `where' field. */ + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; +#endif + } + return result; +} + +/** The do-it-yourself (byte) sex-change kit */ + +/* The middle letter e.g. getshort indicates Big or Little endian + target machine. It doesn't matter what the byte order of the host + machine is; these routines work for either. */ + +/* FIXME: Should these take a count argument? + Answer (gnu@cygnus.com): No, but perhaps they should be inline + functions in swap.h #ifdef __GNUC__. + Gprof them later and find out. */ + +/* +FUNCTION + bfd_put_size +FUNCTION + bfd_get_size + +DESCRIPTION + These macros as used for reading and writing raw data in + sections; each access (except for bytes) is vectored through + the target format of the BFD and mangled accordingly. The + mangling performs any necessary endian translations and + removes alignment restrictions. Note that types accepted and + returned by these macros are identical so they can be swapped + around in macros---for example, @file{libaout.h} defines <> + to either <> or <>. + + In the put routines, @var{val} must be a <>. If we are on a + system without prototypes, the caller is responsible for making + sure that is true, with a cast if necessary. We don't cast + them in the macro definitions because that would prevent <> + or <> from detecting sins such as passing a pointer. + To detect calling these with less than a <>, use + <> on a host with 64 bit <>'s. + +. +.{* Byte swapping macros for user section data. *} +. +.#define bfd_put_8(abfd, val, ptr) \ +. (*((unsigned char *)(ptr)) = (unsigned char)(val)) +.#define bfd_put_signed_8 \ +. bfd_put_8 +.#define bfd_get_8(abfd, ptr) \ +. (*(unsigned char *)(ptr)) +.#define bfd_get_signed_8(abfd, ptr) \ +. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) +. +.#define bfd_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +.#define bfd_put_signed_16 \ +. bfd_put_16 +.#define bfd_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx16, (ptr)) +.#define bfd_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) +. +.#define bfd_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +.#define bfd_put_signed_32 \ +. bfd_put_32 +.#define bfd_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx32, (ptr)) +.#define bfd_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) +. +.#define bfd_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +.#define bfd_put_signed_64 \ +. bfd_put_64 +.#define bfd_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx64, (ptr)) +.#define bfd_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) +. +*/ + +/* +FUNCTION + bfd_h_put_size + bfd_h_get_size + +DESCRIPTION + These macros have the same function as their <> + bretheren, except that they are used for removing information + for the header records of object files. Believe it or not, + some object files keep their header records in big endian + order and their data in little endian order. +. +.{* Byte swapping macros for file header data. *} +. +.#define bfd_h_put_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_put_signed_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_get_8(abfd, ptr) \ +. bfd_get_8 (abfd, ptr) +.#define bfd_h_get_signed_8(abfd, ptr) \ +. bfd_get_signed_8 (abfd, ptr) +. +.#define bfd_h_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +.#define bfd_h_put_signed_16 \ +. bfd_h_put_16 +.#define bfd_h_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx16,(ptr)) +.#define bfd_h_get_signed_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) +. +.#define bfd_h_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +.#define bfd_h_put_signed_32 \ +. bfd_h_put_32 +.#define bfd_h_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx32,(ptr)) +.#define bfd_h_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) +. +.#define bfd_h_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +.#define bfd_h_put_signed_64 \ +. bfd_h_put_64 +.#define bfd_h_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx64,(ptr)) +.#define bfd_h_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) +. +*/ + +/* Sign extension to bfd_signed_vma. */ +#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000) +#define EIGHT_GAZILLION (((BFD_HOST_64_BIT)0x80000000) << 32) +#define COERCE64(x) \ + (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + +bfd_vma +bfd_getb16 (addr) + register const bfd_byte *addr; +{ + return (addr[0] << 8) | addr[1]; +} + +bfd_vma +bfd_getl16 (addr) + register const bfd_byte *addr; +{ + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +bfd_getl_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[1] << 8) | addr[0]); +} + +void +bfd_putb16 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)(data >> 8); + addr[1] = (bfd_byte )data; +} + +void +bfd_putl16 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte )data; + addr[1] = (bfd_byte)(data >> 8); +} + +bfd_vma +bfd_getb32 (addr) + register const bfd_byte *addr; +{ + return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]; +} + +bfd_vma +bfd_getl32 (addr) + register const bfd_byte *addr; +{ + return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_32 (addr) + register const bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]); +} + +bfd_signed_vma +bfd_getl_signed_32 (addr) + register const bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]); +} + +bfd_vma +bfd_getb64 (addr) + register const bfd_byte *addr; +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_vma +bfd_getl64 (addr) + register const bfd_byte *addr; +{ +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +bfd_getb_signed_64 (addr) + register const bfd_byte *addr; +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_signed_vma +bfd_getl_signed_64 (addr) + register const bfd_byte *addr; +{ +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + +void +bfd_putb32 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)(data >> 24); + addr[1] = (bfd_byte)(data >> 16); + addr[2] = (bfd_byte)(data >> 8); + addr[3] = (bfd_byte)data; +} + +void +bfd_putl32 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte)data; + addr[1] = (bfd_byte)(data >> 8); + addr[2] = (bfd_byte)(data >> 16); + addr[3] = (bfd_byte)(data >> 24); +} + +void +bfd_putb64 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ +#ifdef BFD64 + addr[0] = (bfd_byte)(data >> (7*8)); + addr[1] = (bfd_byte)(data >> (6*8)); + addr[2] = (bfd_byte)(data >> (5*8)); + addr[3] = (bfd_byte)(data >> (4*8)); + addr[4] = (bfd_byte)(data >> (3*8)); + addr[5] = (bfd_byte)(data >> (2*8)); + addr[6] = (bfd_byte)(data >> (1*8)); + addr[7] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif +} + +void +bfd_putl64 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ +#ifdef BFD64 + addr[7] = (bfd_byte)(data >> (7*8)); + addr[6] = (bfd_byte)(data >> (6*8)); + addr[5] = (bfd_byte)(data >> (5*8)); + addr[4] = (bfd_byte)(data >> (4*8)); + addr[3] = (bfd_byte)(data >> (3*8)); + addr[2] = (bfd_byte)(data >> (2*8)); + addr[1] = (bfd_byte)(data >> (1*8)); + addr[0] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif +} + +/* Default implementation */ + +boolean +_bfd_generic_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return true; + if ((bfd_size_type)(offset+count) > section->_raw_size + || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_read(location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +boolean +_bfd_generic_get_section_contents_in_window (abfd, section, w, offset, count) + bfd *abfd; + sec_ptr section; + bfd_window *w; + file_ptr offset; + bfd_size_type count; +{ +#ifdef USE_MMAP + if (count == 0) + return true; + if (abfd->xvec->_bfd_get_section_contents != _bfd_generic_get_section_contents) + { + /* We don't know what changes the bfd's get_section_contents + method may have to make. So punt trying to map the file + window, and let get_section_contents do its thing. */ + /* @@ FIXME : If the internal window has a refcount of 1 and was + allocated with malloc instead of mmap, just reuse it. */ + bfd_free_window (w); + w->i = (bfd_window_internal *) bfd_zmalloc (sizeof (bfd_window_internal)); + if (w->i == NULL) + return false; + w->i->data = (PTR) bfd_malloc ((size_t) count); + if (w->i->data == NULL) + { + free (w->i); + w->i = NULL; + return false; + } + w->i->mapped = 0; + w->i->refcount = 1; + w->size = w->i->size = count; + w->data = w->i->data; + return bfd_get_section_contents (abfd, section, w->data, offset, count); + } + if ((bfd_size_type) (offset+count) > section->_raw_size + || (bfd_get_file_window (abfd, section->filepos + offset, count, w, true) + == false)) + return false; + return true; +#else + abort (); +#endif +} + +/* This generic function can only be used in implementations where creating + NEW sections is disallowed. It is useful in patching existing sections + in read-write files, though. See other set_section_contents functions + to see why it doesn't work for new sections. */ +boolean +_bfd_generic_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return true; + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) == -1 + || bfd_write (location, (bfd_size_type) 1, count, abfd) != count) + return false; + + return true; +} + +/* +INTERNAL_FUNCTION + bfd_log2 + +SYNOPSIS + unsigned int bfd_log2(bfd_vma x); + +DESCRIPTION + Return the log base 2 of the value supplied, rounded up. E.g., an + @var{x} of 1025 returns 11. +*/ + +unsigned +bfd_log2(x) + bfd_vma x; +{ + unsigned result = 0; + while ( (bfd_vma)(1<< result) < x) + result++; + return result; +} + +boolean +bfd_generic_is_local_label (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.'; + + return (sym->name[0] == locals_prefix); +} + diff --git a/contrib/gdb/bfd/libbfd.h b/contrib/gdb/bfd/libbfd.h new file mode 100644 index 000000000000..5cf504cdc751 --- /dev/null +++ b/contrib/gdb/bfd/libbfd.h @@ -0,0 +1,735 @@ +/* libbfd.h -- Declarations used by bfd library *implementation*. + (This include file is not for users of the library.) + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +** NOTE: libbfd.h is a GENERATED file. Don't change it; instead, +** change libbfd-in.h or the other BFD source files processed to +** generate this file. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. */ +#define BFD_ALIGN(this, boundary) \ + ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* Set a tdata field. Can't use the other macros for this, since they + do casts, and casting to the left of assignment isn't portable. */ +#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v)) + +/* If BFD_IN_MEMORY is set for a BFD, then the iostream fields points + to an instance of this structure. */ + +struct bfd_in_memory +{ + /* Size of buffer. */ + bfd_size_type size; + /* Buffer holding contents of BFD. */ + bfd_byte *buffer; +}; + +/* tdata for an archive. For an input archive, cache + needs to be free()'d. For an output archive, symdefs do. */ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *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 */ + /* 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 + for the BSD linker to not complain, + just before we finish writing an + archive. */ + file_ptr armap_datepos; /* Position within archive to seek to + rewrite the date field. */ + PTR tdata; /* Backend specific information. */ +}; + +#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 */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +extern PTR bfd_malloc PARAMS ((size_t)); +extern PTR bfd_realloc PARAMS ((PTR, size_t)); +extern PTR bfd_zmalloc PARAMS ((size_t)); + +extern bfd_error_handler_type _bfd_error_handler; + +/* These routines allocate and free things on the BFD's obstack. */ + +PTR bfd_alloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size)); +void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size)); +PTR bfd_alloc_finish PARAMS ((bfd *abfd)); +PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted)); + +#define bfd_release(x,y) (void) obstack_free(&(x->memory),y) + +bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd)); +bfd * _bfd_look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index)); +boolean _bfd_add_bfd_to_archive_cache PARAMS ((bfd *, file_ptr, bfd *)); +boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd)); +const bfd_target *bfd_generic_archive_p PARAMS ((bfd *abfd)); +boolean bfd_slurp_armap PARAMS ((bfd *abfd)); +boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd)); +#define bfd_slurp_bsd_armap bfd_slurp_armap +#define bfd_slurp_coff_armap bfd_slurp_armap +boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd)); +extern boolean _bfd_construct_extended_name_table + PARAMS ((bfd *, boolean, char **, bfd_size_type *)); +boolean _bfd_write_archive_contents PARAMS ((bfd *abfd)); +boolean _bfd_compute_and_write_armap PARAMS ((bfd *, unsigned int elength)); +bfd *_bfd_get_elt_at_filepos PARAMS ((bfd *archive, file_ptr filepos)); +extern bfd *_bfd_generic_get_elt_at_index PARAMS ((bfd *, symindex)); +bfd * _bfd_new_bfd PARAMS ((void)); + +boolean bfd_false PARAMS ((bfd *ignore)); +boolean bfd_true PARAMS ((bfd *ignore)); +PTR bfd_nullvoidptr PARAMS ((bfd *ignore)); +int bfd_0 PARAMS ((bfd *ignore)); +unsigned int bfd_0u PARAMS ((bfd *ignore)); +long bfd_0l PARAMS ((bfd *ignore)); +long _bfd_n1 PARAMS ((bfd *ignore)); +void bfd_void PARAMS ((bfd *ignore)); + +bfd *_bfd_new_bfd_contained_in PARAMS ((bfd *)); +const bfd_target *_bfd_dummy_target PARAMS ((bfd *abfd)); + +void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); + +boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +extern PTR _bfd_generic_read_ar_hdr PARAMS ((bfd *)); + +extern PTR _bfd_generic_read_ar_hdr_mag PARAMS ((bfd *, const char *)); + +bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive, + bfd *last_file)); + +int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); + +#define _bfd_read_ar_hdr(abfd) \ + BFD_SEND (abfd, _bfd_read_ar_hdr_fn, (abfd)) + +/* 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_bfd_free_cached_info bfd_true +#define _bfd_generic_new_section_hook \ + ((boolean (*) PARAMS ((bfd *, asection *))) bfd_true) +extern boolean _bfd_generic_get_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr offset, + bfd_size_type count)); +extern boolean _bfd_generic_get_section_contents_in_window + PARAMS ((bfd *, asection *, bfd_window *, file_ptr, bfd_size_type)); + +/* Generic routines to use for BFD_JUMP_TABLE_COPY. Use + BFD_JUMP_TABLE_COPY (_bfd_generic). */ + +#define _bfd_generic_bfd_copy_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_merge_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_set_private_flags \ + ((boolean (*) PARAMS ((bfd *, flagword))) bfd_true) +#define _bfd_generic_bfd_copy_private_section_data \ + ((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true) +#define _bfd_generic_bfd_copy_private_symbol_data \ + ((boolean (*) PARAMS ((bfd *, asymbol *, bfd *, asymbol *))) bfd_true) +#define _bfd_generic_bfd_print_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, PTR))) bfd_true) + +/* Routines to use for BFD_JUMP_TABLE_CORE when there is no core file + support. Use BFD_JUMP_TABLE_CORE (_bfd_nocore). */ + +extern char *_bfd_nocore_core_file_failing_command PARAMS ((bfd *)); +extern int _bfd_nocore_core_file_failing_signal PARAMS ((bfd *)); +extern boolean _bfd_nocore_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE when there is no archive + file support. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive). */ + +#define _bfd_noarchive_slurp_armap bfd_false +#define _bfd_noarchive_slurp_extended_name_table bfd_false +#define _bfd_noarchive_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_false) +#define _bfd_noarchive_truncate_arname \ + ((void (*) PARAMS ((bfd *, const char *, char *))) bfd_void) +#define _bfd_noarchive_write_armap \ + ((boolean (*) \ + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ + bfd_false) +#define _bfd_noarchive_read_ar_hdr bfd_nullvoidptr +#define _bfd_noarchive_openr_next_archived_file \ + ((bfd *(*) PARAMS ((bfd *, bfd *))) bfd_nullvoidptr) +#define _bfd_noarchive_get_elt_at_index \ + ((bfd *(*) PARAMS ((bfd *, symindex))) bfd_nullvoidptr) +#define _bfd_noarchive_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define _bfd_noarchive_update_armap_timestamp bfd_false + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd). */ + +#define _bfd_archive_bsd_slurp_armap bfd_slurp_bsd_armap +#define _bfd_archive_bsd_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern boolean _bfd_archive_bsd_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_bsd_truncate_arname bfd_bsd_truncate_arname +#define _bfd_archive_bsd_write_armap bsd_write_armap +#define _bfd_archive_bsd_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_bsd_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_bsd_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_bsd_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +extern boolean _bfd_archive_bsd_update_armap_timestamp PARAMS ((bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get COFF style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff). */ + +#define _bfd_archive_coff_slurp_armap bfd_slurp_coff_armap +#define _bfd_archive_coff_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern boolean _bfd_archive_coff_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_coff_truncate_arname bfd_dont_truncate_arname +#define _bfd_archive_coff_write_armap coff_write_armap +#define _bfd_archive_coff_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_coff_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_coff_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_coff_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +#define _bfd_archive_coff_update_armap_timestamp bfd_true + +/* Routines to use for BFD_JUMP_TABLE_SYMBOLS where there is no symbol + support. Use BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols). */ + +#define _bfd_nosymbols_get_symtab_upper_bound _bfd_n1 +#define _bfd_nosymbols_get_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nosymbols_make_empty_symbol \ + ((asymbol *(*) PARAMS ((bfd *))) bfd_nullvoidptr) +#define _bfd_nosymbols_print_symbol \ + ((void (*) PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void) +#define _bfd_nosymbols_get_symbol_info \ + ((void (*) PARAMS ((bfd *, asymbol *, symbol_info *))) bfd_void) +#define _bfd_nosymbols_bfd_is_local_label \ + ((boolean (*) PARAMS ((bfd *, asymbol *))) bfd_false) +#define _bfd_nosymbols_get_lineno \ + ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr) +#define _bfd_nosymbols_find_nearest_line \ + ((boolean (*) \ + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, \ + const char **, unsigned int *))) \ + bfd_false) +#define _bfd_nosymbols_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, PTR, unsigned long))) bfd_nullvoidptr) +#define _bfd_nosymbols_read_minisymbols \ + ((long (*) PARAMS ((bfd *, boolean, PTR *, unsigned int *))) _bfd_n1) +#define _bfd_nosymbols_minisymbol_to_symbol \ + ((asymbol *(*) PARAMS ((bfd *, boolean, const PTR, asymbol *))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_RELOCS when there is no reloc + support. Use BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */ + +#define _bfd_norelocs_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) _bfd_n1) +#define _bfd_norelocs_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) _bfd_n1) +#define _bfd_norelocs_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_WRITE for targets which may not + be written. Use BFD_JUMP_TABLE_WRITE (_bfd_nowrite). */ + +#define _bfd_nowrite_set_arch_mach \ + ((boolean (*) PARAMS ((bfd *, enum bfd_architecture, unsigned long))) \ + bfd_false) +#define _bfd_nowrite_set_section_contents \ + ((boolean (*) PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type))) \ + bfd_false) + +/* Generic routines to use for BFD_JUMP_TABLE_WRITE. Use + BFD_JUMP_TABLE_WRITE (_bfd_generic). */ + +#define _bfd_generic_set_arch_mach bfd_default_set_arch_mach +extern boolean _bfd_generic_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); + +/* Routines to use for BFD_JUMP_TABLE_LINK for targets which do not + support linking. Use BFD_JUMP_TABLE_LINK (_bfd_nolink). */ + +#define _bfd_nolink_sizeof_headers ((int (*) PARAMS ((bfd *, boolean))) bfd_0) +#define _bfd_nolink_bfd_get_relocated_section_contents \ + ((bfd_byte *(*) \ + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, \ + bfd_byte *, boolean, asymbol **))) \ + bfd_nullvoidptr) +#define _bfd_nolink_bfd_relax_section \ + ((boolean (*) \ + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *))) \ + bfd_false) +#define _bfd_nolink_bfd_link_hash_table_create \ + ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr) +#define _bfd_nolink_bfd_link_add_symbols \ + ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_final_link \ + ((boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_link_split_section \ + ((boolean (*) PARAMS ((bfd *, struct sec *))) bfd_false) + +/* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not + have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC + (_bfd_nodynamic). */ + +#define _bfd_nodynamic_get_dynamic_symtab_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_reloc \ + ((long (*) PARAMS ((bfd *, arelent **, asymbol **))) _bfd_n1) + +/* Generic routine to determine of the given symbol is a local + label. */ +extern boolean bfd_generic_is_local_label PARAMS ((bfd *, asymbol *)); + +/* Generic minisymbol routines. */ +extern long _bfd_generic_read_minisymbols + PARAMS ((bfd *, boolean, PTR *, unsigned int *)); +extern asymbol *_bfd_generic_minisymbol_to_symbol + PARAMS ((bfd *, boolean, const PTR, asymbol *)); + +/* Find the nearest line using .stab/.stabstr sections. */ +extern boolean _bfd_stab_section_find_nearest_line + PARAMS ((bfd *, asymbol **, asection *, bfd_vma, boolean *, const char **, + const char **, unsigned int *, PTR *)); + +/* A routine to create entries for a bfd_link_hash_table. */ +extern struct bfd_hash_entry *_bfd_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string)); + +/* Initialize a bfd_link_hash_table. */ +extern boolean _bfd_link_hash_table_init + PARAMS ((struct bfd_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Generic link hash table creation routine. */ +extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create + PARAMS ((bfd *)); + +/* Generic add symbol routine. */ +extern boolean _bfd_generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic add symbol routine. This version is used by targets for + which the linker must collect constructors and destructors by name, + as the collect2 program does. */ +extern boolean _bfd_generic_link_add_symbols_collect + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic archive add symbol routine. */ +extern boolean _bfd_generic_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *, + boolean (*checkfn) (bfd *, struct bfd_link_info *, boolean *))); + +/* Forward declaration to avoid prototype errors. */ +typedef struct bfd_link_hash_entry _bfd_link_hash_entry; + +/* Generic routine to add a single symbol. */ +extern boolean _bfd_generic_link_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword, + asection *, bfd_vma, const char *, boolean copy, + boolean constructor, struct bfd_link_hash_entry **)); + +/* Generic link routine. */ +extern boolean _bfd_generic_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern boolean _bfd_generic_link_split_section + PARAMS ((bfd *, struct sec *)); + +/* Generic reloc_link_order processing routine. */ +extern boolean _bfd_generic_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Default link order processing routine. */ +extern boolean _bfd_default_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Count the number of reloc entries in a link order list. */ +extern unsigned int _bfd_count_link_order_relocs + PARAMS ((struct bfd_link_order *)); + +/* Final link relocation routine. */ +extern bfd_reloc_status_type _bfd_final_link_relocate + PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, + bfd_vma address, bfd_vma value, bfd_vma addend)); + +/* Relocate a particular location by a howto and a value. */ +extern bfd_reloc_status_type _bfd_relocate_contents + PARAMS ((reloc_howto_type *, bfd *, bfd_vma, bfd_byte *)); + +/* Create a string table. */ +extern struct bfd_strtab_hash *_bfd_stringtab_init PARAMS ((void)); + +/* Create an XCOFF .debug section style string table. */ +extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init PARAMS ((void)); + +/* Free a string table. */ +extern void _bfd_stringtab_free PARAMS ((struct bfd_strtab_hash *)); + +/* Get the size of a string table. */ +extern bfd_size_type _bfd_stringtab_size PARAMS ((struct bfd_strtab_hash *)); + +/* Add a string to a string table. */ +extern bfd_size_type _bfd_stringtab_add + PARAMS ((struct bfd_strtab_hash *, const char *, boolean hash, + boolean copy)); + +/* Write out a string table. */ +extern boolean _bfd_stringtab_emit PARAMS ((bfd *, struct bfd_strtab_hash *)); + +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +void bfd_assert PARAMS ((const char*,int)); + +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +FILE * bfd_cache_lookup_worker PARAMS ((bfd *)); + +extern bfd *bfd_last_cache; + +/* Now Steve, what's the story here? */ +#ifdef lint +#define itos(x) "l" +#define stoi(x) 1 +#else +#define itos(x) ((char*)(x)) +#define stoi(x) ((int)(x)) +#endif + +/* List of supported target vectors, and the default vector (if + bfd_default_vector[0] is NULL, there is no default). */ +extern const bfd_target * const bfd_target_vector[]; +extern const bfd_target * const bfd_default_vector[]; + +/* Functions shared by the ECOFF and MIPS ELF backends, which have no + other common header files. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_find_line; +#endif + +extern boolean _bfd_ecoff_locate_line + PARAMS ((bfd *, asection *, bfd_vma, struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, struct ecoff_find_line *, + const char **, const char **, unsigned int *)); +extern boolean _bfd_ecoff_get_accumulated_pdr PARAMS ((PTR, bfd_byte *)); +extern boolean _bfd_ecoff_get_accumulated_sym PARAMS ((PTR, bfd_byte *)); +extern boolean _bfd_ecoff_get_accumulated_ss PARAMS ((PTR, bfd_byte *)); + +extern bfd_vma _bfd_get_gp_value PARAMS ((bfd *)); +extern void _bfd_set_gp_value PARAMS ((bfd *, bfd_vma)); + +/* And more follows */ + +void +bfd_write_bigendian_4byte_int PARAMS ((bfd *abfd, int i)); + +unsigned int +bfd_log2 PARAMS ((bfd_vma x)); + +#define BFD_CACHE_MAX_OPEN 10 +extern bfd *bfd_last_cache; + +#define bfd_cache_lookup(x) \ + ((x)==bfd_last_cache? \ + (FILE*)(bfd_last_cache->iostream): \ + bfd_cache_lookup_worker(x)) +boolean +bfd_cache_init PARAMS ((bfd *abfd)); + +boolean +bfd_cache_close PARAMS ((bfd *abfd)); + +FILE* +bfd_open_file PARAMS ((bfd *abfd)); + +FILE * +bfd_cache_lookup_worker PARAMS ((bfd *abfd)); + +#ifdef _BFD_MAKE_TABLE_bfd_reloc_code_real + +static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + + "BFD_RELOC_64", + "BFD_RELOC_32", + "BFD_RELOC_26", + "BFD_RELOC_16", + "BFD_RELOC_14", + "BFD_RELOC_8", + "BFD_RELOC_64_PCREL", + "BFD_RELOC_32_PCREL", + "BFD_RELOC_24_PCREL", + "BFD_RELOC_16_PCREL", + "BFD_RELOC_12_PCREL", + "BFD_RELOC_8_PCREL", + "BFD_RELOC_32_GOT_PCREL", + "BFD_RELOC_16_GOT_PCREL", + "BFD_RELOC_8_GOT_PCREL", + "BFD_RELOC_32_GOTOFF", + "BFD_RELOC_16_GOTOFF", + "BFD_RELOC_LO16_GOTOFF", + "BFD_RELOC_HI16_GOTOFF", + "BFD_RELOC_HI16_S_GOTOFF", + "BFD_RELOC_8_GOTOFF", + "BFD_RELOC_32_PLT_PCREL", + "BFD_RELOC_24_PLT_PCREL", + "BFD_RELOC_16_PLT_PCREL", + "BFD_RELOC_8_PLT_PCREL", + "BFD_RELOC_32_PLTOFF", + "BFD_RELOC_16_PLTOFF", + "BFD_RELOC_LO16_PLTOFF", + "BFD_RELOC_HI16_PLTOFF", + "BFD_RELOC_HI16_S_PLTOFF", + "BFD_RELOC_8_PLTOFF", + "BFD_RELOC_68K_GLOB_DAT", + "BFD_RELOC_68K_JMP_SLOT", + "BFD_RELOC_68K_RELATIVE", + "BFD_RELOC_32_BASEREL", + "BFD_RELOC_16_BASEREL", + "BFD_RELOC_LO16_BASEREL", + "BFD_RELOC_HI16_BASEREL", + "BFD_RELOC_HI16_S_BASEREL", + "BFD_RELOC_8_BASEREL", + "BFD_RELOC_RVA", + "BFD_RELOC_8_FFnn", + "BFD_RELOC_32_PCREL_S2", + "BFD_RELOC_16_PCREL_S2", + "BFD_RELOC_23_PCREL_S2", + "BFD_RELOC_HI22", + "BFD_RELOC_LO10", + "BFD_RELOC_GPREL16", + "BFD_RELOC_GPREL32", + "BFD_RELOC_I960_CALLJ", + "BFD_RELOC_NONE", + "BFD_RELOC_SPARC_WDISP22", + "BFD_RELOC_SPARC22", + "BFD_RELOC_SPARC13", + "BFD_RELOC_SPARC_GOT10", + "BFD_RELOC_SPARC_GOT13", + "BFD_RELOC_SPARC_GOT22", + "BFD_RELOC_SPARC_PC10", + "BFD_RELOC_SPARC_PC22", + "BFD_RELOC_SPARC_WPLT30", + "BFD_RELOC_SPARC_COPY", + "BFD_RELOC_SPARC_GLOB_DAT", + "BFD_RELOC_SPARC_JMP_SLOT", + "BFD_RELOC_SPARC_RELATIVE", + "BFD_RELOC_SPARC_UA32", + "BFD_RELOC_SPARC_BASE13", + "BFD_RELOC_SPARC_BASE22", + "BFD_RELOC_SPARC_10", + "BFD_RELOC_SPARC_11", + "BFD_RELOC_SPARC_OLO10", + "BFD_RELOC_SPARC_HH22", + "BFD_RELOC_SPARC_HM10", + "BFD_RELOC_SPARC_LM22", + "BFD_RELOC_SPARC_PC_HH22", + "BFD_RELOC_SPARC_PC_HM10", + "BFD_RELOC_SPARC_PC_LM22", + "BFD_RELOC_SPARC_WDISP16", + "BFD_RELOC_SPARC_WDISP19", + "BFD_RELOC_SPARC_GLOB_JMP", + "BFD_RELOC_SPARC_7", + "BFD_RELOC_SPARC_6", + "BFD_RELOC_SPARC_5", + "BFD_RELOC_ALPHA_GPDISP_HI16", + "BFD_RELOC_ALPHA_GPDISP_LO16", + "BFD_RELOC_ALPHA_LITERAL", + "BFD_RELOC_ALPHA_LITUSE", + "BFD_RELOC_ALPHA_HINT", + "BFD_RELOC_MIPS_JMP", + "BFD_RELOC_HI16", + "BFD_RELOC_HI16_S", + "BFD_RELOC_LO16", + "BFD_RELOC_PCREL_HI16_S", + "BFD_RELOC_PCREL_LO16", + "BFD_RELOC_MIPS_LITERAL", + "BFD_RELOC_MIPS_GOT16", + "BFD_RELOC_MIPS_CALL16", + "BFD_RELOC_MIPS_GOT_HI16", + "BFD_RELOC_MIPS_GOT_LO16", + "BFD_RELOC_MIPS_CALL_HI16", + "BFD_RELOC_MIPS_CALL_LO16", + "BFD_RELOC_386_GOT32", + "BFD_RELOC_386_PLT32", + "BFD_RELOC_386_COPY", + "BFD_RELOC_386_GLOB_DAT", + "BFD_RELOC_386_JUMP_SLOT", + "BFD_RELOC_386_RELATIVE", + "BFD_RELOC_386_GOTOFF", + "BFD_RELOC_386_GOTPC", + "BFD_RELOC_NS32K_IMM_8", + "BFD_RELOC_NS32K_IMM_16", + "BFD_RELOC_NS32K_IMM_32", + "BFD_RELOC_NS32K_IMM_8_PCREL", + "BFD_RELOC_NS32K_IMM_16_PCREL", + "BFD_RELOC_NS32K_IMM_32_PCREL", + "BFD_RELOC_NS32K_DISP_8", + "BFD_RELOC_NS32K_DISP_16", + "BFD_RELOC_NS32K_DISP_32", + "BFD_RELOC_NS32K_DISP_8_PCREL", + "BFD_RELOC_NS32K_DISP_16_PCREL", + "BFD_RELOC_NS32K_DISP_32_PCREL", + "BFD_RELOC_PPC_B26", + "BFD_RELOC_PPC_BA26", + "BFD_RELOC_PPC_TOC16", + "BFD_RELOC_PPC_B16", + "BFD_RELOC_PPC_B16_BRTAKEN", + "BFD_RELOC_PPC_B16_BRNTAKEN", + "BFD_RELOC_PPC_BA16", + "BFD_RELOC_PPC_BA16_BRTAKEN", + "BFD_RELOC_PPC_BA16_BRNTAKEN", + "BFD_RELOC_PPC_COPY", + "BFD_RELOC_PPC_GLOB_DAT", + "BFD_RELOC_PPC_JMP_SLOT", + "BFD_RELOC_PPC_RELATIVE", + "BFD_RELOC_PPC_LOCAL24PC", + "BFD_RELOC_PPC_EMB_NADDR32", + "BFD_RELOC_PPC_EMB_NADDR16", + "BFD_RELOC_PPC_EMB_NADDR16_LO", + "BFD_RELOC_PPC_EMB_NADDR16_HI", + "BFD_RELOC_PPC_EMB_NADDR16_HA", + "BFD_RELOC_PPC_EMB_SDAI16", + "BFD_RELOC_PPC_EMB_SDA2I16", + "BFD_RELOC_PPC_EMB_SDA2REL", + "BFD_RELOC_PPC_EMB_SDA21", + "BFD_RELOC_PPC_EMB_MRKREF", + "BFD_RELOC_PPC_EMB_RELSEC16", + "BFD_RELOC_PPC_EMB_RELST_LO", + "BFD_RELOC_PPC_EMB_RELST_HI", + "BFD_RELOC_PPC_EMB_RELST_HA", + "BFD_RELOC_PPC_EMB_BIT_FLD", + "BFD_RELOC_PPC_EMB_RELSDA", + "BFD_RELOC_CTOR", + "BFD_RELOC_ARM_PCREL_BRANCH", + "BFD_RELOC_ARM_IMMEDIATE", + "BFD_RELOC_ARM_OFFSET_IMM", + "BFD_RELOC_ARM_SHIFT_IMM", + "BFD_RELOC_ARM_SWI", + "BFD_RELOC_ARM_MULTI", + "BFD_RELOC_ARM_CP_OFF_IMM", + "BFD_RELOC_ARM_ADR_IMM", + "BFD_RELOC_ARM_LDR_IMM", + "BFD_RELOC_ARM_LITERAL", + "BFD_RELOC_ARM_IN_POOL", + "@@overflow: BFD_RELOC_UNUSED@@", +}; +#endif + +reloc_howto_type * +bfd_default_reloc_type_lookup + PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +boolean +bfd_generic_relax_section + PARAMS ((bfd *abfd, + asection *section, + struct bfd_link_info *, + boolean *)); + +bfd_byte * + +bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + boolean relocateable, + asymbol **symbols)); + +extern const bfd_arch_info_type bfd_default_arch_struct; +boolean +bfd_default_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long mach)); + +const bfd_arch_info_type * +bfd_default_compatible + PARAMS ((const bfd_arch_info_type *a, + const bfd_arch_info_type *b)); + +boolean +bfd_default_scan PARAMS ((const struct bfd_arch_info *info, const char *string)); + +struct elf_internal_shdr * +bfd_elf_find_section PARAMS ((bfd *abfd, char *name)); + diff --git a/contrib/gdb/bfd/libcoff-in.h b/contrib/gdb/bfd/libcoff-in.h new file mode 100644 index 000000000000..648ed8066386 --- /dev/null +++ b/contrib/gdb/bfd/libcoff-in.h @@ -0,0 +1,482 @@ +/* BFD COFF object file private structure. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +** NOTE: libcoff.h is a GENERATED file. Don't change it; instead, +** change libcoff-in.h or coffcode.h. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfdlink.h" + +/* Object file tdata; access macros */ + +#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) +#define exec_hdr(bfd) (coff_data(bfd)->hdr) +#define obj_pe(bfd) (coff_data(bfd)->pe) +#define obj_symbols(bfd) (coff_data(bfd)->symbols) +#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (coff_data(bfd)->relocbase) +#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments) +#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count) +#define obj_convert(bfd) (coff_data(bfd)->conversion_table) +#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size) + +#define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) +#define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) +#define obj_coff_strings(bfd) (coff_data (bfd)->strings) +#define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) +#define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) + +#define obj_coff_local_toc_table(bfd) (coff_data(bfd)->local_toc_sym_map) + +/* `Tdata' information kept for COFF files. */ + +typedef struct coff_tdata +{ + struct coff_symbol_struct *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + int conv_table_size; + file_ptr sym_filepos; + + struct coff_ptr_struct *raw_syments; + unsigned int raw_syment_count; + + /* These are only valid once writing has begun */ + long int relocbase; + + /* These members communicate important constants about the symbol table + to GDB's symbol-reading code. These `constants' unfortunately vary + from coff implementation to implementation... */ + unsigned local_n_btmask; + unsigned local_n_btshft; + unsigned local_n_tmask; + unsigned local_n_tshift; + unsigned local_symesz; + unsigned local_auxesz; + unsigned local_linesz; + + /* The unswapped external symbols. May be NULL. Read by + _bfd_coff_get_external_symbols. */ + PTR external_syms; + /* If this is true, the external_syms may not be freed. */ + boolean keep_syms; + + /* The string table. May be NULL. Read by + _bfd_coff_read_string_table. */ + char *strings; + /* If this is true, the strings may not be freed. */ + boolean keep_strings; + + /* is this a PE format coff file */ + int pe; + /* Used by the COFF backend linker. */ + struct coff_link_hash_entry **sym_hashes; + + /* used by the pe linker for PowerPC */ + int *local_toc_sym_map; + + struct bfd_link_info *link_info; + + /* Used by coff_find_nearest_line. */ + PTR line_info; +} coff_data_type; + +/* Tdata for pe image files. */ +typedef struct pe_tdata +{ + coff_data_type coff; + struct internal_extra_pe_aouthdr pe_opthdr; + int dll; + int has_reloc_section; + boolean (*in_reloc_p) PARAMS((bfd *, reloc_howto_type *)); + flagword real_flags; +} pe_data_type; + +#define pe_data(bfd) ((bfd)->tdata.pe_obj_data) + +/* Tdata for XCOFF files. */ + +struct xcoff_tdata +{ + /* Basic COFF information. */ + coff_data_type coff; + + /* True if a large a.out header should be generated. */ + boolean full_aouthdr; + + /* TOC value. */ + bfd_vma toc; + + /* Index of section holding TOC. */ + int sntoc; + + /* Index of section holding entry point. */ + int snentry; + + /* .text alignment from optional header. */ + int text_align_power; + + /* .data alignment from optional header. */ + int data_align_power; + + /* modtype from optional header. */ + short modtype; + + /* cputype from optional header. */ + short cputype; + + /* maxdata from optional header. */ + bfd_size_type maxdata; + + /* maxstack from optional header. */ + bfd_size_type maxstack; + + /* Used by the XCOFF backend linker. */ + asection **csects; + unsigned long *debug_indices; + unsigned int import_file_id; +}; + +#define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data) + +/* We take the address of the first element of a asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) + +/* The used_by_bfd field of a section may be set to a pointer to this + structure. */ + +struct coff_section_tdata +{ + /* The relocs, swapped into COFF internal form. This may be NULL. */ + struct internal_reloc *relocs; + /* If this is true, the relocs entry may not be freed. */ + boolean keep_relocs; + /* The section contents. This may be NULL. */ + bfd_byte *contents; + /* If this is true, the contents entry may not be freed. */ + boolean keep_contents; + /* Information cached by coff_find_nearest_line. */ + bfd_vma offset; + unsigned int i; + const char *function; + int line_base; + /* Available for individual backends. */ + PTR tdata; +}; + +/* An accessor macro for the coff_section_tdata structure. */ +#define coff_section_data(abfd, sec) \ + ((struct coff_section_tdata *) (sec)->used_by_bfd) + +/* Tdata for sections in XCOFF files. This is used by the linker. */ + +struct xcoff_section_tdata +{ + /* Used for XCOFF csects created by the linker; points to the real + XCOFF section which contains this csect. */ + asection *enclosing; + /* The lineno_count field for the enclosing section, because we are + going to clobber it there. */ + unsigned int lineno_count; + /* The first and one past the last symbol indices for symbols used + by this csect. */ + unsigned long first_symndx; + unsigned long last_symndx; +}; + +/* An accessor macro the xcoff_section_tdata structure. */ +#define xcoff_section_data(abfd, sec) \ + ((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata) + +/* COFF linker hash table entries. */ + +struct coff_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. Set to -1 initially. Set to -2 if + there is a reloc against this symbol. */ + long indx; + + /* Symbol type. */ + unsigned short type; + + /* Symbol class. */ + unsigned char class; + + /* Number of auxiliary entries. */ + char numaux; + + /* BFD to take auxiliary entries from. */ + bfd *auxbfd; + + /* Pointer to array of auxiliary entries, if any. */ + union internal_auxent *aux; +}; + +/* COFF linker hash table. */ + +struct coff_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in a COFF linker hash table. */ + +#define coff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct coff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse a COFF linker hash table. */ + +#define coff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the COFF linker hash table from a link_info structure. */ + +#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash)) + +/* Functions in coffgen.c. */ +extern const bfd_target *coff_object_p PARAMS ((bfd *)); +extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int)); +extern long coff_get_symtab_upper_bound PARAMS ((bfd *)); +extern long coff_get_symtab PARAMS ((bfd *, asymbol **)); +extern int coff_count_linenumbers PARAMS ((bfd *)); +extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *)); +extern boolean coff_renumber_symbols PARAMS ((bfd *, int *)); +extern void coff_mangle_symbols PARAMS ((bfd *)); +extern boolean coff_write_symbols PARAMS ((bfd *)); +extern boolean coff_write_linenumbers PARAMS ((bfd *)); +extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *)); +extern asymbol *coff_section_symbol PARAMS ((bfd *, char *)); +extern boolean _bfd_coff_get_external_symbols PARAMS ((bfd *)); +extern const char *_bfd_coff_read_string_table PARAMS ((bfd *)); +extern boolean _bfd_coff_free_symbols PARAMS ((bfd *)); +extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *)); +extern long coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern asymbol *coff_make_empty_symbol PARAMS ((bfd *)); +extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *, + bfd_print_symbol_type how)); +extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *ret)); +extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR, + unsigned long)); +extern boolean coff_find_nearest_line PARAMS ((bfd *, + asection *, + asymbol **, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **functionname_ptr, + unsigned int *line_ptr)); +extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc)); +extern boolean bfd_coff_reloc16_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean relocateable, asymbol **)); +extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *, + struct bfd_link_info *, + asection *)); +extern void bfd_perform_slip PARAMS ((bfd *abfd, unsigned int slip, + asection *input_section, + bfd_vma val)); + +/* Functions and types in cofflink.c. */ + +#define STRING_SIZE_SIZE (4) + +/* We use a hash table to merge identical enum, struct, and union + definitions in the linker. */ + +/* Information we keep for a single element (an enum value, a + structure or union field) in the debug merge hash table. */ + +struct coff_debug_merge_element +{ + /* Next element. */ + struct coff_debug_merge_element *next; + + /* Name. */ + const char *name; + + /* Type. */ + unsigned int type; + + /* Symbol index for complex type. */ + long tagndx; +}; + +/* A linked list of debug merge entries for a given name. */ + +struct coff_debug_merge_type +{ + /* Next type with the same name. */ + struct coff_debug_merge_type *next; + + /* Class of type. */ + int class; + + /* Symbol index where this type is defined. */ + long indx; + + /* List of elements. */ + struct coff_debug_merge_element *elements; +}; + +/* Information we store in the debug merge hash table. */ + +struct coff_debug_merge_hash_entry +{ + struct bfd_hash_entry root; + + /* A list of types with this name. */ + struct coff_debug_merge_type *types; +}; + +/* The debug merge hash table. */ + +struct coff_debug_merge_hash_table +{ + struct bfd_hash_table root; +}; + +/* Initialize a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_init(table) \ + (bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc)) + +/* Free a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_free(table) \ + (bfd_hash_table_free (&(table)->root)) + +/* Look up an entry in a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_lookup(table, string, create, copy) \ + ((struct coff_debug_merge_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Information we keep for each section in the output file when doing + a relocateable link. */ + +struct coff_link_section_info +{ + /* The relocs to be output. */ + struct internal_reloc *relocs; + /* For each reloc against a global symbol whose index was not known + when the reloc was handled, the global hash table entry. */ + struct coff_link_hash_entry **rel_hashes; +}; + +/* Information that we pass around while doing the final link step. */ + +struct coff_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Used to indicate failure in traversal routine. */ + boolean failed; + /* Hash table for long symbol names. */ + struct bfd_strtab_hash *strtab; + /* When doing a relocateable link, an array of information kept for + each output section, indexed by the target_index field. */ + struct coff_link_section_info *section_info; + /* Symbol index of last C_FILE symbol (-1 if none). */ + long last_file_index; + /* Contents of last C_FILE symbol. */ + struct internal_syment last_file; + /* Hash table used to merge debug information. */ + struct coff_debug_merge_hash_table debug_merge; + /* Buffer large enough to hold swapped symbols of any input file. */ + struct internal_syment *internal_syms; + /* Buffer large enough to hold sections of symbols of any input file. */ + asection **sec_ptrs; + /* Buffer large enough to hold output indices of symbols of any + input file. */ + long *sym_indices; + /* Buffer large enough to hold output symbols for any input file. */ + bfd_byte *outsyms; + /* Buffer large enough to hold external line numbers for any input + section. */ + bfd_byte *linenos; + /* Buffer large enough to hold any input section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any input section. */ + bfd_byte *external_relocs; + /* Buffer large enough to hold swapped relocs of any input section. */ + struct internal_reloc *internal_relocs; +}; + +extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern boolean _bfd_coff_link_hash_table_init + PARAMS ((struct coff_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); +extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create + PARAMS ((bfd *)); +extern const char *_bfd_coff_internal_syment_name + PARAMS ((bfd *, const struct internal_syment *, char *)); +extern boolean _bfd_coff_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_coff_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern struct internal_reloc *_bfd_coff_read_internal_relocs + PARAMS ((bfd *, asection *, boolean, bfd_byte *, boolean, + struct internal_reloc *)); +extern boolean _bfd_coff_generic_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern boolean _bfd_coff_write_global_sym + PARAMS ((struct coff_link_hash_entry *, PTR)); +extern boolean _bfd_coff_link_input_bfd + PARAMS ((struct coff_final_link_info *, bfd *)); +extern boolean _bfd_coff_reloc_link_order + PARAMS ((bfd *, struct coff_final_link_info *, asection *, + struct bfd_link_order *)); + + +#define coff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +/* Functions in xcofflink.c. */ + +extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create + PARAMS ((bfd *)); +extern boolean _bfd_xcoff_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_xcoff_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_ppc_xcoff_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +/* And more taken from the source .. */ + diff --git a/contrib/gdb/bfd/libcoff.h b/contrib/gdb/bfd/libcoff.h new file mode 100644 index 000000000000..daa39b52bd4e --- /dev/null +++ b/contrib/gdb/bfd/libcoff.h @@ -0,0 +1,823 @@ +/* BFD COFF object file private structure. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +** NOTE: libcoff.h is a GENERATED file. Don't change it; instead, +** change libcoff-in.h or coffcode.h. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfdlink.h" + +/* Object file tdata; access macros */ + +#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) +#define exec_hdr(bfd) (coff_data(bfd)->hdr) +#define obj_pe(bfd) (coff_data(bfd)->pe) +#define obj_symbols(bfd) (coff_data(bfd)->symbols) +#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (coff_data(bfd)->relocbase) +#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments) +#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count) +#define obj_convert(bfd) (coff_data(bfd)->conversion_table) +#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size) + +#define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) +#define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) +#define obj_coff_strings(bfd) (coff_data (bfd)->strings) +#define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) +#define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) + +#define obj_coff_local_toc_table(bfd) (coff_data(bfd)->local_toc_sym_map) + +/* `Tdata' information kept for COFF files. */ + +typedef struct coff_tdata +{ + struct coff_symbol_struct *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + int conv_table_size; + file_ptr sym_filepos; + + struct coff_ptr_struct *raw_syments; + unsigned int raw_syment_count; + + /* These are only valid once writing has begun */ + long int relocbase; + + /* These members communicate important constants about the symbol table + to GDB's symbol-reading code. These `constants' unfortunately vary + from coff implementation to implementation... */ + unsigned local_n_btmask; + unsigned local_n_btshft; + unsigned local_n_tmask; + unsigned local_n_tshift; + unsigned local_symesz; + unsigned local_auxesz; + unsigned local_linesz; + + /* The unswapped external symbols. May be NULL. Read by + _bfd_coff_get_external_symbols. */ + PTR external_syms; + /* If this is true, the external_syms may not be freed. */ + boolean keep_syms; + + /* The string table. May be NULL. Read by + _bfd_coff_read_string_table. */ + char *strings; + /* If this is true, the strings may not be freed. */ + boolean keep_strings; + + /* is this a PE format coff file */ + int pe; + /* Used by the COFF backend linker. */ + struct coff_link_hash_entry **sym_hashes; + + /* used by the pe linker for PowerPC */ + int *local_toc_sym_map; + + struct bfd_link_info *link_info; + + /* Used by coff_find_nearest_line. */ + PTR line_info; +} coff_data_type; + +/* Tdata for pe image files. */ +typedef struct pe_tdata +{ + coff_data_type coff; + struct internal_extra_pe_aouthdr pe_opthdr; + int dll; + int has_reloc_section; + boolean (*in_reloc_p) PARAMS((bfd *, reloc_howto_type *)); + flagword real_flags; +} pe_data_type; + +#define pe_data(bfd) ((bfd)->tdata.pe_obj_data) + +/* Tdata for XCOFF files. */ + +struct xcoff_tdata +{ + /* Basic COFF information. */ + coff_data_type coff; + + /* True if a large a.out header should be generated. */ + boolean full_aouthdr; + + /* TOC value. */ + bfd_vma toc; + + /* Index of section holding TOC. */ + int sntoc; + + /* Index of section holding entry point. */ + int snentry; + + /* .text alignment from optional header. */ + int text_align_power; + + /* .data alignment from optional header. */ + int data_align_power; + + /* modtype from optional header. */ + short modtype; + + /* cputype from optional header. */ + short cputype; + + /* maxdata from optional header. */ + bfd_size_type maxdata; + + /* maxstack from optional header. */ + bfd_size_type maxstack; + + /* Used by the XCOFF backend linker. */ + asection **csects; + unsigned long *debug_indices; + unsigned int import_file_id; +}; + +#define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data) + +/* We take the address of the first element of a asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) + +/* The used_by_bfd field of a section may be set to a pointer to this + structure. */ + +struct coff_section_tdata +{ + /* The relocs, swapped into COFF internal form. This may be NULL. */ + struct internal_reloc *relocs; + /* If this is true, the relocs entry may not be freed. */ + boolean keep_relocs; + /* The section contents. This may be NULL. */ + bfd_byte *contents; + /* If this is true, the contents entry may not be freed. */ + boolean keep_contents; + /* Information cached by coff_find_nearest_line. */ + bfd_vma offset; + unsigned int i; + const char *function; + int line_base; + /* Available for individual backends. */ + PTR tdata; +}; + +/* An accessor macro for the coff_section_tdata structure. */ +#define coff_section_data(abfd, sec) \ + ((struct coff_section_tdata *) (sec)->used_by_bfd) + +/* Tdata for sections in XCOFF files. This is used by the linker. */ + +struct xcoff_section_tdata +{ + /* Used for XCOFF csects created by the linker; points to the real + XCOFF section which contains this csect. */ + asection *enclosing; + /* The lineno_count field for the enclosing section, because we are + going to clobber it there. */ + unsigned int lineno_count; + /* The first and one past the last symbol indices for symbols used + by this csect. */ + unsigned long first_symndx; + unsigned long last_symndx; +}; + +/* An accessor macro the xcoff_section_tdata structure. */ +#define xcoff_section_data(abfd, sec) \ + ((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata) + +/* COFF linker hash table entries. */ + +struct coff_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. Set to -1 initially. Set to -2 if + there is a reloc against this symbol. */ + long indx; + + /* Symbol type. */ + unsigned short type; + + /* Symbol class. */ + unsigned char class; + + /* Number of auxiliary entries. */ + char numaux; + + /* BFD to take auxiliary entries from. */ + bfd *auxbfd; + + /* Pointer to array of auxiliary entries, if any. */ + union internal_auxent *aux; +}; + +/* COFF linker hash table. */ + +struct coff_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in a COFF linker hash table. */ + +#define coff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct coff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse a COFF linker hash table. */ + +#define coff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the COFF linker hash table from a link_info structure. */ + +#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash)) + +/* Functions in coffgen.c. */ +extern const bfd_target *coff_object_p PARAMS ((bfd *)); +extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int)); +extern long coff_get_symtab_upper_bound PARAMS ((bfd *)); +extern long coff_get_symtab PARAMS ((bfd *, asymbol **)); +extern int coff_count_linenumbers PARAMS ((bfd *)); +extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *)); +extern boolean coff_renumber_symbols PARAMS ((bfd *, int *)); +extern void coff_mangle_symbols PARAMS ((bfd *)); +extern boolean coff_write_symbols PARAMS ((bfd *)); +extern boolean coff_write_linenumbers PARAMS ((bfd *)); +extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *)); +extern asymbol *coff_section_symbol PARAMS ((bfd *, char *)); +extern boolean _bfd_coff_get_external_symbols PARAMS ((bfd *)); +extern const char *_bfd_coff_read_string_table PARAMS ((bfd *)); +extern boolean _bfd_coff_free_symbols PARAMS ((bfd *)); +extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *)); +extern long coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern asymbol *coff_make_empty_symbol PARAMS ((bfd *)); +extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *, + bfd_print_symbol_type how)); +extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *ret)); +extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR, + unsigned long)); +extern boolean coff_find_nearest_line PARAMS ((bfd *, + asection *, + asymbol **, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **functionname_ptr, + unsigned int *line_ptr)); +extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc)); +extern boolean bfd_coff_reloc16_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *)); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, boolean relocateable, asymbol **)); +extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *, + struct bfd_link_info *, + asection *)); +extern void bfd_perform_slip PARAMS ((bfd *abfd, unsigned int slip, + asection *input_section, + bfd_vma val)); + +/* Functions and types in cofflink.c. */ + +#define STRING_SIZE_SIZE (4) + +/* We use a hash table to merge identical enum, struct, and union + definitions in the linker. */ + +/* Information we keep for a single element (an enum value, a + structure or union field) in the debug merge hash table. */ + +struct coff_debug_merge_element +{ + /* Next element. */ + struct coff_debug_merge_element *next; + + /* Name. */ + const char *name; + + /* Type. */ + unsigned int type; + + /* Symbol index for complex type. */ + long tagndx; +}; + +/* A linked list of debug merge entries for a given name. */ + +struct coff_debug_merge_type +{ + /* Next type with the same name. */ + struct coff_debug_merge_type *next; + + /* Class of type. */ + int class; + + /* Symbol index where this type is defined. */ + long indx; + + /* List of elements. */ + struct coff_debug_merge_element *elements; +}; + +/* Information we store in the debug merge hash table. */ + +struct coff_debug_merge_hash_entry +{ + struct bfd_hash_entry root; + + /* A list of types with this name. */ + struct coff_debug_merge_type *types; +}; + +/* The debug merge hash table. */ + +struct coff_debug_merge_hash_table +{ + struct bfd_hash_table root; +}; + +/* Initialize a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_init(table) \ + (bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc)) + +/* Free a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_free(table) \ + (bfd_hash_table_free (&(table)->root)) + +/* Look up an entry in a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_lookup(table, string, create, copy) \ + ((struct coff_debug_merge_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Information we keep for each section in the output file when doing + a relocateable link. */ + +struct coff_link_section_info +{ + /* The relocs to be output. */ + struct internal_reloc *relocs; + /* For each reloc against a global symbol whose index was not known + when the reloc was handled, the global hash table entry. */ + struct coff_link_hash_entry **rel_hashes; +}; + +/* Information that we pass around while doing the final link step. */ + +struct coff_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Used to indicate failure in traversal routine. */ + boolean failed; + /* Hash table for long symbol names. */ + struct bfd_strtab_hash *strtab; + /* When doing a relocateable link, an array of information kept for + each output section, indexed by the target_index field. */ + struct coff_link_section_info *section_info; + /* Symbol index of last C_FILE symbol (-1 if none). */ + long last_file_index; + /* Contents of last C_FILE symbol. */ + struct internal_syment last_file; + /* Hash table used to merge debug information. */ + struct coff_debug_merge_hash_table debug_merge; + /* Buffer large enough to hold swapped symbols of any input file. */ + struct internal_syment *internal_syms; + /* Buffer large enough to hold sections of symbols of any input file. */ + asection **sec_ptrs; + /* Buffer large enough to hold output indices of symbols of any + input file. */ + long *sym_indices; + /* Buffer large enough to hold output symbols for any input file. */ + bfd_byte *outsyms; + /* Buffer large enough to hold external line numbers for any input + section. */ + bfd_byte *linenos; + /* Buffer large enough to hold any input section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any input section. */ + bfd_byte *external_relocs; + /* Buffer large enough to hold swapped relocs of any input section. */ + struct internal_reloc *internal_relocs; +}; + +extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern boolean _bfd_coff_link_hash_table_init + PARAMS ((struct coff_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); +extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create + PARAMS ((bfd *)); +extern const char *_bfd_coff_internal_syment_name + PARAMS ((bfd *, const struct internal_syment *, char *)); +extern boolean _bfd_coff_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_coff_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern struct internal_reloc *_bfd_coff_read_internal_relocs + PARAMS ((bfd *, asection *, boolean, bfd_byte *, boolean, + struct internal_reloc *)); +extern boolean _bfd_coff_generic_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern boolean _bfd_coff_write_global_sym + PARAMS ((struct coff_link_hash_entry *, PTR)); +extern boolean _bfd_coff_link_input_bfd + PARAMS ((struct coff_final_link_info *, bfd *)); +extern boolean _bfd_coff_reloc_link_order + PARAMS ((bfd *, struct coff_final_link_info *, asection *, + struct bfd_link_order *)); + + +#define coff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +/* Functions in xcofflink.c. */ + +extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create + PARAMS ((bfd *)); +extern boolean _bfd_xcoff_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_xcoff_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_ppc_xcoff_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +/* And more taken from the source .. */ + +typedef struct coff_ptr_struct +{ + + /* Remembers the offset from the first symbol in the file for + this symbol. Generated by coff_renumber_symbols. */ +unsigned int offset; + + /* Should the value of this symbol be renumbered. Used for + XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */ +unsigned int fix_value : 1; + + /* Should the tag field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +unsigned int fix_tag : 1; + + /* Should the endidx field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +unsigned int fix_end : 1; + + /* Should the x_csect.x_scnlen field be renumbered. + Created by coff_pointerize_aux. */ +unsigned int fix_scnlen : 1; + + /* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the + index into the line number entries. Set by + coff_slurp_symbol_table. */ +unsigned int fix_line : 1; + + /* The container for the symbol structure as read and translated + from the file. */ + +union { + union internal_auxent auxent; + struct internal_syment syment; + } u; +} combined_entry_type; + + + /* Each canonical asymbol really looks like this: */ + +typedef struct coff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ +asymbol symbol; + + /* A pointer to the hidden information for this symbol */ +combined_entry_type *native; + + /* A pointer to the linenumber information for this symbol */ +struct lineno_cache_entry *lineno; + + /* Have the line numbers been relocated yet ? */ +boolean done_lineno; +} coff_symbol_type; +typedef struct +{ + void (*_bfd_coff_swap_aux_in) PARAMS (( + bfd *abfd, + PTR ext, + int type, + int class, + int indaux, + int numaux, + PTR in)); + + void (*_bfd_coff_swap_sym_in) PARAMS (( + bfd *abfd , + PTR ext, + PTR in)); + + void (*_bfd_coff_swap_lineno_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + + unsigned int (*_bfd_coff_swap_aux_out) PARAMS (( + bfd *abfd, + PTR in, + int type, + int class, + int indaux, + int numaux, + PTR ext)); + + unsigned int (*_bfd_coff_swap_sym_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_lineno_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_reloc_out) PARAMS (( + bfd *abfd, + PTR src, + PTR dst)); + + unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int _bfd_filhsz; + unsigned int _bfd_aoutsz; + unsigned int _bfd_scnhsz; + unsigned int _bfd_symesz; + unsigned int _bfd_auxesz; + unsigned int _bfd_relsz; + unsigned int _bfd_linesz; + boolean _bfd_coff_long_filenames; + void (*_bfd_coff_swap_filehdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_aouthdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_scnhdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_reloc_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + boolean (*_bfd_coff_bad_format_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + boolean (*_bfd_coff_set_arch_mach_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + PTR (*_bfd_coff_mkobject_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr, + PTR internal_aouthdr)); + flagword (*_bfd_styp_to_sec_flags_hook) PARAMS (( + bfd *abfd, + PTR internal_scnhdr, + const char *name)); + void (*_bfd_set_alignment_hook) PARAMS (( + bfd *abfd, + asection *sec, + PTR internal_scnhdr)); + boolean (*_bfd_coff_slurp_symbol_table) PARAMS (( + bfd *abfd)); + boolean (*_bfd_coff_symname_in_debug) PARAMS (( + bfd *abfd, + struct internal_syment *sym)); + boolean (*_bfd_coff_pointerize_aux_hook) PARAMS (( + bfd *abfd, + combined_entry_type *table_base, + combined_entry_type *symbol, + unsigned int indaux, + combined_entry_type *aux)); + boolean (*_bfd_coff_print_aux) PARAMS (( + bfd *abfd, + FILE *file, + combined_entry_type *table_base, + combined_entry_type *symbol, + combined_entry_type *aux, + unsigned int indaux)); + void (*_bfd_coff_reloc16_extra_cases) PARAMS (( + bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + arelent *reloc, + bfd_byte *data, + unsigned int *src_ptr, + unsigned int *dst_ptr)); + int (*_bfd_coff_reloc16_estimate) PARAMS (( + bfd *abfd, + asection *input_section, + arelent *r, + unsigned int shrink, + struct bfd_link_info *link_info)); + boolean (*_bfd_coff_sym_is_global) PARAMS (( + bfd *abfd, + struct internal_syment *)); + void (*_bfd_coff_compute_section_file_positions) PARAMS (( + bfd *abfd)); + boolean (*_bfd_coff_start_final_link) PARAMS (( + bfd *output_bfd, + struct bfd_link_info *info)); + boolean (*_bfd_coff_relocate_section) PARAMS (( + bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + struct internal_reloc *relocs, + struct internal_syment *syms, + asection **sections)); + reloc_howto_type *(*_bfd_coff_rtype_to_howto) PARAMS (( + bfd *abfd, + asection *sec, + struct internal_reloc *rel, + struct coff_link_hash_entry *h, + struct internal_syment *sym, + bfd_vma *addendp)); + boolean (*_bfd_coff_adjust_symndx) PARAMS (( + bfd *obfd, + struct bfd_link_info *info, + bfd *ibfd, + asection *sec, + struct internal_reloc *reloc, + boolean *adjustedp)); + boolean (*_bfd_coff_link_add_one_symbol) PARAMS (( + struct bfd_link_info *info, + bfd *abfd, + const char *name, + flagword flags, + asection *section, + bfd_vma value, + const char *string, + boolean copy, + boolean collect, + struct bfd_link_hash_entry **hashp)); + +} bfd_coff_backend_data; + +#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) + +#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) + +#define bfd_coff_swap_sym_in(a,e,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) + +#define bfd_coff_swap_lineno_in(a,e,i) \ + ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) + +#define bfd_coff_swap_reloc_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) + +#define bfd_coff_swap_lineno_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) + +#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) + +#define bfd_coff_swap_sym_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) + +#define bfd_coff_swap_filehdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) + +#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) +#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) +#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) +#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) +#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) +#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) +#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) +#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames) +#define bfd_coff_swap_filehdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) + +#define bfd_coff_swap_reloc_in(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) + +#define bfd_coff_bad_format_hook(abfd, filehdr) \ + ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) + +#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ + ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) +#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ + ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr)) + +#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name)\ + ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr, name)) + +#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) + +#define bfd_coff_slurp_symbol_table(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) + +#define bfd_coff_symname_in_debug(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) + +#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ + ((coff_backend_info (abfd)->_bfd_coff_print_aux)\ + (abfd, file, base, symbol, aux, indaux)) + +#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ + (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) + +#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ + (abfd, section, reloc, shrink, link_info)) + +#define bfd_coff_sym_is_global(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_sym_is_global)\ + (abfd, sym)) + +#define bfd_coff_compute_section_file_positions(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ + (abfd)) + +#define bfd_coff_start_final_link(obfd, info)\ + ((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ + (obfd, info)) +#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ + ((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ + (obfd, info, ibfd, o, con, rel, isyms, secs)) +#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ + ((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ + (abfd, sec, rel, h, sym, addendp)) +#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ + ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ + (obfd, info, ibfd, sec, rel, adjustedp)) +#define bfd_coff_link_add_one_symbol(info,abfd,name,flags,section,value,string,cp,coll,hashp)\ + ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ + (info, abfd, name, flags, section, value, string, cp, coll, hashp)) + diff --git a/contrib/gdb/bfd/libecoff.h b/contrib/gdb/bfd/libecoff.h new file mode 100644 index 000000000000..169610d00509 --- /dev/null +++ b/contrib/gdb/bfd/libecoff.h @@ -0,0 +1,352 @@ +/* BFD ECOFF object file private structure. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfdlink.h" + +#ifndef ECOFF_H +#include "coff/ecoff.h" +#endif + +/* This is the backend information kept for ECOFF files. This + structure is constant for a particular backend. The first element + is the COFF backend data structure, so that ECOFF targets can use + the generic COFF code. */ + +#define ecoff_backend(abfd) \ + ((struct ecoff_backend_data *) (abfd)->xvec->backend_data) + +struct ecoff_backend_data +{ + /* COFF backend information. This must be the first field. */ + bfd_coff_backend_data coff; + /* Supported architecture. */ + enum bfd_architecture arch; + /* Initial portion of armap string. */ + const char *armap_start; + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + bfd_vma round; + /* True if the .rdata section is part of the text segment, as on the + Alpha. False if .rdata is part of the data segment, as on the + MIPS. */ + boolean rdata_in_text; + /* Bitsize of constructor entries. */ + unsigned int constructor_bitsize; + /* Reloc to use for constructor entries. */ + reloc_howto_type *constructor_reloc; + /* How to swap debugging information. */ + struct ecoff_debug_swap debug_swap; + /* External reloc size. */ + bfd_size_type external_reloc_size; + /* Reloc swapping functions. */ + void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *)); + void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR)); + /* Backend reloc tweaking. */ + void (*adjust_reloc_in) PARAMS ((bfd *, const struct internal_reloc *, + arelent *)); + void (*adjust_reloc_out) PARAMS ((bfd *, const arelent *, + struct internal_reloc *)); + /* Relocate section contents while linking. */ + boolean (*relocate_section) PARAMS ((bfd *output_bfd, struct bfd_link_info *, + bfd *input_bfd, asection *input_section, + bfd_byte *contents, + PTR external_relocs)); + /* Do final adjustments to filehdr and aouthdr. */ + boolean (*adjust_headers) PARAMS ((bfd *, struct internal_filehdr *, + struct internal_aouthdr *)); + /* Read an element from an archive at a given file position. This + is needed because OSF/1 3.2 uses a weird archive format. */ + bfd *(*get_elt_at_filepos) PARAMS ((bfd *, file_ptr)); +}; + +/* This is the target specific information kept for ECOFF files. */ + +#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data) + +typedef struct ecoff_tdata +{ + /* The reloc file position, set by + ecoff_compute_section_file_positions. */ + file_ptr reloc_filepos; + + /* The symbol table file position, set by _bfd_ecoff_mkobject_hook. */ + file_ptr sym_filepos; + + /* The start and end of the text segment. Only valid for an + existing file, not for one we are creating. */ + unsigned long text_start; + unsigned long text_end; + + /* The cached gp value. This is used when relocating. */ + bfd_vma gp; + + /* The maximum size of objects to optimize using gp. This is + typically set by the -G option to the compiler, assembler or + linker. */ + unsigned int gp_size; + + /* The register masks. When linking, all the masks found in the + input files are combined into the masks of the output file. + These are not all used for all targets, but that's OK, because + the relevant ones are the only ones swapped in and out. */ + unsigned long gprmask; + unsigned long fprmask; + unsigned long cprmask[4]; + + /* The ECOFF symbolic debugging information. */ + struct ecoff_debug_info debug_info; + + /* The unswapped ECOFF symbolic information. */ + PTR raw_syments; + + /* The canonical BFD symbols. */ + struct ecoff_symbol_struct *canonical_symbols; + + /* A mapping from external symbol numbers to entries in the linker + hash table, used when linking. */ + struct ecoff_link_hash_entry **sym_hashes; + + /* A mapping from reloc symbol indices to sections, used when + linking. */ + asection **symndx_to_section; + + /* True if this BFD was written by the backend linker. */ + boolean linker; + + /* True if a warning that multiple global pointer values are + needed in the output binary was issued already. */ + boolean issued_multiple_gp_warning; + + /* Used by 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 ecoff_find_line *find_line_info; + +} ecoff_data_type; + +/* Each canonical asymbol really looks like this. */ + +typedef struct ecoff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ + asymbol symbol; + + /* The fdr for this symbol. */ + FDR *fdr; + + /* true if this is a local symbol rather than an external one. */ + boolean local; + + /* A pointer to the unswapped hidden information for this symbol. + This is either a struct sym_ext or a struct ext_ext, depending on + the value of the local field above. */ + PTR native; +} ecoff_symbol_type; + +/* We take the address of the first element of a asymbol to ensure that the + macro is only ever applied to an asymbol. */ +#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) + +/* We need to save the index of an external symbol when we write it + out so that can set the symbol index correctly when we write out + the relocs. */ +#define ecoff_get_sym_index(symbol) ((symbol)->udata.i) +#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata.i = (idx)) + +/* When generating MIPS embedded PIC code, the linker relaxes the code + to turn PC relative branches into longer code sequences when the PC + relative branch is out of range. This involves reading the relocs + in bfd_relax_section as well as in bfd_final_link, and requires the + code to keep track of which relocs have been expanded. A pointer + to this structure is put in the used_by_bfd pointer of a section to + keep track of this information. The user_by_bfd pointer will be + NULL if the information was not needed. */ + +struct ecoff_section_tdata +{ + /* The unswapped relocs for this section. These are stored in + memory so the input file does not have to be read twice. */ + PTR external_relocs; + + /* The contents of the section. These bytes may or may not be saved + in memory, but if it is this is a pointer to them. */ + bfd_byte *contents; + + /* Offset adjustments for PC relative branches. A number other than + 1 is an addend for a PC relative branch, or a switch table entry + which is the difference of two .text locations; this addend + arises because the branch or difference crosses one or more + branches which were expanded into a larger code sequence. A 1 + means that this branch was itself expanded into a larger code + sequence. 1 is not a possible offset, since all offsets must be + multiples of the instruction size, which is 4; also, the only + relocs with non-zero offsets will be PC relative branches or + switch table entries within the same object file. If this field + is NULL, no branches were expanded and no offsets are required. + Otherwise there are as many entries as there are relocs in the + section, and the entry for any reloc that is not PC relative is + zero. */ + long *offsets; + + /* When producing an executable (i.e., final, non-relocatable link) + on the Alpha, we may need to use multiple global pointer values + to span the entire .lita section. In essence, we allow each + input .lita section to have its own gp value. To support this, + we need to keep track of the gp values that we picked for each + input .lita section . */ + bfd_vma gp; +}; + +/* An accessor macro for the ecoff_section_tdata structure. */ +#define ecoff_section_data(abfd, sec) \ + ((struct ecoff_section_tdata *) (sec)->used_by_bfd) + +/* ECOFF linker hash table entries. */ + +struct ecoff_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Symbol index in output file. */ + long indx; + /* BFD that ext field value came from. */ + bfd *abfd; + /* ECOFF external symbol information. */ + EXTR esym; + /* Nonzero if this symbol has been written out. */ + char written; + /* Nonzero if this symbol was referred to as small undefined. */ + char small; +}; + +/* ECOFF linker hash table. */ + +struct ecoff_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Make an ECOFF object. */ +extern boolean _bfd_ecoff_mkobject PARAMS ((bfd *)); + +/* Read in the ECOFF symbolic debugging information. */ +extern boolean _bfd_ecoff_slurp_symbolic_info + PARAMS ((bfd *, asection *, struct ecoff_debug_info *)); + +/* Generic ECOFF BFD backend vectors. */ + +extern boolean _bfd_ecoff_write_object_contents PARAMS ((bfd *abfd)); +extern const bfd_target *_bfd_ecoff_archive_p PARAMS ((bfd *abfd)); + +#define _bfd_ecoff_close_and_cleanup _bfd_generic_close_and_cleanup +#define _bfd_ecoff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +extern boolean _bfd_ecoff_new_section_hook + PARAMS ((bfd *, asection *)); +extern boolean _bfd_ecoff_get_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type)); + +#define _bfd_ecoff_bfd_link_split_section _bfd_generic_link_split_section + +extern boolean _bfd_ecoff_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +#define _bfd_ecoff_bfd_copy_private_section_data \ + _bfd_generic_bfd_copy_private_section_data + +#define _bfd_ecoff_bfd_copy_private_symbol_data \ + _bfd_generic_bfd_copy_private_symbol_data + +#define _bfd_ecoff_bfd_print_private_bfd_data \ + _bfd_generic_bfd_print_private_bfd_data + +#define _bfd_ecoff_bfd_merge_private_bfd_data \ + _bfd_generic_bfd_merge_private_bfd_data + +#define _bfd_ecoff_bfd_set_private_flags _bfd_generic_bfd_set_private_flags +extern boolean _bfd_ecoff_slurp_armap PARAMS ((bfd *abfd)); +#define _bfd_ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table +#define _bfd_ecoff_construct_extended_name_table \ + _bfd_archive_bsd_construct_extended_name_table +#define _bfd_ecoff_truncate_arname bfd_dont_truncate_arname +extern boolean _bfd_ecoff_write_armap + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); +#define _bfd_ecoff_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_ecoff_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_ecoff_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define _bfd_ecoff_update_armap_timestamp bfd_true + +extern long _bfd_ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd)); +extern long _bfd_ecoff_get_symtab PARAMS ((bfd *abfd, asymbol **alocation)); +extern asymbol *_bfd_ecoff_make_empty_symbol PARAMS ((bfd *abfd)); +extern void _bfd_ecoff_print_symbol + PARAMS ((bfd *, PTR filep, asymbol *, bfd_print_symbol_type)); +extern void _bfd_ecoff_get_symbol_info + PARAMS ((bfd *, asymbol *, symbol_info *)); +extern boolean _bfd_ecoff_bfd_is_local_label + PARAMS ((bfd *, asymbol *)); +#define _bfd_ecoff_get_lineno _bfd_nosymbols_get_lineno +extern boolean _bfd_ecoff_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma offset, + const char **filename_ptr, const char **fnname_ptr, + unsigned int *retline_ptr)); +#define _bfd_ecoff_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define _bfd_ecoff_read_minisymbols _bfd_generic_read_minisymbols +#define _bfd_ecoff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define _bfd_ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound +extern long _bfd_ecoff_canonicalize_reloc + PARAMS ((bfd *, asection *, arelent **, asymbol **symbols)); +/* ecoff_bfd_reloc_type_lookup defined by backend. */ + +extern boolean _bfd_ecoff_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long machine)); +extern boolean _bfd_ecoff_set_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type)); + +extern int _bfd_ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc)); +/* ecoff_bfd_get_relocated_section_contents defined by backend. */ +/* ecoff_bfd_relax_section defined by backend. */ +extern struct bfd_link_hash_table *_bfd_ecoff_bfd_link_hash_table_create + PARAMS ((bfd *)); +extern boolean _bfd_ecoff_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean _bfd_ecoff_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Hook functions for the generic COFF section reading code. */ + +extern PTR _bfd_ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr)); +#define _bfd_ecoff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) +extern boolean _bfd_ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr)); +extern flagword _bfd_ecoff_styp_to_sec_flags + PARAMS ((bfd *abfd, PTR hdr, const char *name)); +extern boolean _bfd_ecoff_slurp_symbol_table PARAMS ((bfd *abfd)); + +/* ECOFF auxiliary information swapping routines. These are the same + for all ECOFF targets, so they are defined in ecofflink.c. */ + +extern void _bfd_ecoff_swap_tir_in + PARAMS ((int, const struct tir_ext *, TIR *)); +extern void _bfd_ecoff_swap_tir_out + PARAMS ((int, const TIR *, struct tir_ext *)); +extern void _bfd_ecoff_swap_rndx_in + PARAMS ((int, const struct rndx_ext *, RNDXR *)); +extern void _bfd_ecoff_swap_rndx_out + PARAMS ((int, const RNDXR *, struct rndx_ext *)); diff --git a/contrib/gdb/bfd/libhppa.h b/contrib/gdb/bfd/libhppa.h new file mode 100644 index 000000000000..fa97b68821fd --- /dev/null +++ b/contrib/gdb/bfd/libhppa.h @@ -0,0 +1,549 @@ +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _HPPA_H +#define _HPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE inline +#else +#define INLINE +#endif /* GNU C? */ +#endif /* INLINE */ + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) (((a) >> 22) & 0x3FF) +#define HPPA_R_CONSTANT(a) ((((int)(a)) << 10) >> 10) +#define HPPA_R_ADDEND(r,c) (((r) << 22) + ((c) & 0x3FFFFF)) + +/* Some functions to manipulate PA instructions. */ +static INLINE unsigned int +assemble_3 (x) + unsigned int x; +{ + return (((x & 1) << 2) | ((x & 6) >> 1)) & 7; +} + +static INLINE void +dis_assemble_3 (x, r) + unsigned int x; + unsigned int *r; +{ + *r = (((x & 4) >> 2) | ((x & 3) << 1)) & 7; +} + +static INLINE unsigned int +assemble_12 (x, y) + unsigned int x, y; +{ + return (((y & 1) << 11) | ((x & 1) << 10) | ((x & 0x7fe) >> 1)) & 0xfff; +} + +static INLINE void +dis_assemble_12 (as12, x, y) + unsigned int as12; + unsigned int *x, *y; +{ + *y = (as12 & 0x800) >> 11; + *x = ((as12 & 0x3ff) << 1) | ((as12 & 0x400) >> 10); +} + +static INLINE unsigned long +assemble_17 (x, y, z) + unsigned int x, y, z; +{ + unsigned long temp; + + temp = ((z & 1) << 16) | + ((x & 0x1f) << 11) | + ((y & 1) << 10) | + ((y & 0x7fe) >> 1); + return temp & 0x1ffff; +} + +static INLINE void +dis_assemble_17 (as17, x, y, z) + unsigned int as17; + unsigned int *x, *y, *z; +{ + + *z = (as17 & 0x10000) >> 16; + *x = (as17 & 0x0f800) >> 11; + *y = (((as17 & 0x00400) >> 10) | ((as17 & 0x3ff) << 1)) & 0x7ff; +} + +static INLINE unsigned long +assemble_21 (x) + unsigned int x; +{ + unsigned long temp; + + temp = ((x & 1) << 20) | + ((x & 0xffe) << 8) | + ((x & 0xc000) >> 7) | + ((x & 0x1f0000) >> 14) | + ((x & 0x003000) >> 12); + return temp & 0x1fffff; +} + +static INLINE void +dis_assemble_21 (as21, x) + unsigned int as21, *x; +{ + unsigned long temp; + + + temp = (as21 & 0x100000) >> 20; + temp |= (as21 & 0x0ffe00) >> 8; + temp |= (as21 & 0x000180) << 7; + temp |= (as21 & 0x00007c) << 14; + temp |= (as21 & 0x000003) << 12; + *x = temp; +} + +static INLINE unsigned long +sign_extend (x, len) + unsigned int x, len; +{ + return (int)(x >> (len - 1) ? (-1 << len) | x : x); +} + +static INLINE unsigned int +ones (n) + int n; +{ + unsigned int len_ones; + int i; + + i = 0; + len_ones = 0; + while (i < n) + { + len_ones = (len_ones << 1) | 1; + i++; + } + + return len_ones; +} + +static INLINE void +sign_unext (x, len, result) + unsigned int x, len; + unsigned int *result; +{ + unsigned int len_ones; + + len_ones = ones (len); + + *result = x & len_ones; +} + +static INLINE unsigned long +low_sign_extend (x, len) + unsigned int x, len; +{ + return (int)((x & 0x1 ? (-1 << (len - 1)) : 0) | x >> 1); +} + +static INLINE void +low_sign_unext (x, len, result) + unsigned int x, len; + unsigned int *result; +{ + unsigned int temp; + unsigned int sign; + unsigned int rest; + unsigned int one_bit_at_len; + unsigned int len_ones; + + len_ones = ones (len); + one_bit_at_len = 1 << (len - 1); + + sign_unext (x, len, &temp); + sign = temp & one_bit_at_len; + sign >>= (len - 1); + + rest = temp & (len_ones ^ one_bit_at_len); + rest <<= 1; + + *result = rest | sign; +} + +/* Handle field selectors for PA instructions. */ + +static INLINE unsigned long +hppa_field_adjust (value, constant_value, r_field) + unsigned long value; + unsigned long constant_value; + unsigned short r_field; +{ + switch (r_field) + { + case e_fsel: /* F : no change */ + case e_nsel: /* N : no change */ + value += constant_value; + break; + + case e_lssel: /* LS : if (bit 21) then add 0x800 + arithmetic shift right 11 bits */ + value += constant_value; + if (value & 0x00000400) + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rssel: /* RS : Sign extend from bit 21 */ + value += constant_value; + if (value & 0x00000400) + value |= 0xfffff800; + else + value &= 0x7ff; + break; + + case e_lsel: /* L : Arithmetic shift right 11 bits */ + case e_nlsel: /* NL : Arithmetic shift right 11 bits */ + value += constant_value; + value = (value & 0xfffff800) >> 11; + break; + + case e_rsel: /* R : Set bits 0-20 to zero */ + value += constant_value; + value = value & 0x7ff; + break; + + case e_ldsel: /* LD : Add 0x800, arithmetic shift + right 11 bits */ + value += constant_value; + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rdsel: /* RD : Set bits 0-20 to one */ + value += constant_value; + value |= 0xfffff800; + break; + + case e_lrsel: /* LR : L with "rounded" constant */ + case e_nlrsel: /* NLR : NL with "rounded" constant */ + value = value + ((constant_value + 0x1000) & 0xffffe000); + value = (value & 0xfffff800) >> 11; + break; + + case e_rrsel: /* RR : R with "rounded" constant */ + value = value + ((constant_value + 0x1000) & 0xffffe000); + value = (value & 0x7ff) + constant_value - ((constant_value + 0x1000) & 0xffffe000); + break; + + default: + abort (); + } + return value; + +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) ((insn) & 0xfc000000) >> 26 + +/* FIXME: this list is incomplete. It should also be an enumerated + type rather than #defines. */ + +#define LDO 0x0d +#define LDB 0x10 +#define LDH 0x11 +#define LDW 0x12 +#define LDWM 0x13 +#define STB 0x18 +#define STH 0x19 +#define STW 0x1a +#define STWM 0x1b +#define COMICLR 0x24 +#define SUBI 0x25 +#define SUBIO 0x25 +#define ADDIT 0x2c +#define ADDITO 0x2c +#define ADDI 0x2d +#define ADDIO 0x2d +#define LDIL 0x08 +#define ADDIL 0x0a + +#define MOVB 0x32 +#define MOVIB 0x33 +#define COMBT 0x20 +#define COMBF 0x22 +#define COMIBT 0x21 +#define COMIBF 0x23 +#define ADDBT 0x28 +#define ADDBF 0x2a +#define ADDIBT 0x29 +#define ADDIBF 0x2b +#define BVB 0x30 +#define BB 0x31 + +#define BL 0x3a +#define BLE 0x39 +#define BE 0x38 + + +/* Given a machine instruction, return its format. + + FIXME: opcodes which do not map to a known format + should return an error of some sort. */ + +static INLINE char +bfd_hppa_insn2fmt (insn) + unsigned long insn; +{ + char fmt = -1; + unsigned char op = get_opcode (insn); + + switch (op) + { + case ADDI: + case ADDIT: + case SUBI: + fmt = 11; + break; + case MOVB: + case MOVIB: + case COMBT: + case COMBF: + case COMIBT: + case COMIBF: + case ADDBT: + case ADDBF: + case ADDIBT: + case ADDIBF: + case BVB: + case BB: + fmt = 12; + break; + case LDO: + case LDB: + case LDH: + case LDW: + case LDWM: + case STB: + case STH: + case STW: + case STWM: + fmt = 14; + break; + case BL: + case BE: + case BLE: + fmt = 17; + break; + case LDIL: + case ADDIL: + fmt = 21; + break; + default: + fmt = 32; + break; + } + return fmt; +} + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static INLINE unsigned long +hppa_rebuild_insn (abfd, insn, value, r_format) + bfd *abfd; + unsigned long insn; + unsigned long value; + unsigned long r_format; +{ + unsigned long const_part; + unsigned long rebuilt_part; + + switch (r_format) + { + case 11: + { + unsigned w1, w; + + const_part = insn & 0xffffe002; + dis_assemble_12 (value, &w1, &w); + rebuilt_part = (w1 << 2) | w; + return const_part | rebuilt_part; + } + + case 12: + { + unsigned w1, w; + + const_part = insn & 0xffffe002; + dis_assemble_12 (value, &w1, &w); + rebuilt_part = (w1 << 2) | w; + return const_part | rebuilt_part; + } + + case 14: + const_part = insn & 0xffffc000; + low_sign_unext (value, 14, &rebuilt_part); + return const_part | rebuilt_part; + + case 17: + { + unsigned w1, w2, w; + + const_part = insn & 0xffe0e002; + dis_assemble_17 (value, &w1, &w2, &w); + rebuilt_part = (w2 << 2) | (w1 << 16) | w; + return const_part | rebuilt_part; + } + + case 21: + const_part = insn & 0xffe00000; + dis_assemble_21 (value, &rebuilt_part); + return const_part | rebuilt_part; + + case 32: + const_part = 0; + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _HPPA_H */ diff --git a/contrib/gdb/bfd/libieee.h b/contrib/gdb/bfd/libieee.h new file mode 100644 index 000000000000..c3729cbf5177 --- /dev/null +++ b/contrib/gdb/bfd/libieee.h @@ -0,0 +1,135 @@ +/* IEEE-695 object file formats: definitions internal to BFD. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Written by Cygnus Support. Mostly Steve Chamberlain's fault. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +typedef struct { + unsigned int index:24; + char letter; +} ieee_symbol_index_type; + +typedef struct ct { + bfd *this; + struct ct *next; +} bfd_chain_type; + +typedef struct ieee_symbol +{ + asymbol symbol; + struct ieee_symbol *next; + + unsigned int index; +} ieee_symbol_type; + + +typedef struct ieee_reloc { + arelent relent; + struct ieee_reloc *next; + ieee_symbol_index_type symbol; + +} ieee_reloc_type; + +#define ieee_symbol(x) ((ieee_symbol_type *)(x)) + +typedef struct ieee_per_section +{ + asection *section; + bfd_byte *data; + bfd_vma offset; + bfd_vma pc; + /* For output */ + file_ptr current_pos; + unsigned int current_byte; + boolean initialized; + ieee_reloc_type **reloc_tail_ptr; +} ieee_per_section_type; + +#define ieee_per_section(x) ((ieee_per_section_type *)((x)->used_by_bfd)) +/* FIXME! There should be no limit to the number of sections! */ +#define NSECTIONS 20 + + +typedef struct { + unsigned char *input_p; + unsigned char *first_byte; + bfd *abfd; +} common_header_type ; + +typedef struct ieee_data_struct +{ + common_header_type h; + boolean read_symbols; + boolean read_data; + file_ptr output_cursor; + /* Map of section indexes to section ptrs */ + asection * section_table[NSECTIONS]; + ieee_address_descriptor_type ad; + ieee_module_begin_type mb; + ieee_w_variable_type w; + + unsigned int section_count; + + unsigned int map_idx; + /* List of GLOBAL EXPORT symbols */ + ieee_symbol_type *external_symbols; + /* List of UNDEFINED symbols */ + ieee_symbol_type *external_reference; + + /* When the symbols have been canonicalized, they are in a + * special order, we remember various bases here.. */ + unsigned int external_symbol_max_index; + unsigned int external_symbol_min_index; + unsigned int external_symbol_count; + int external_symbol_base_offset; + + unsigned int external_reference_max_index; + unsigned int external_reference_min_index; + unsigned int external_reference_count; + int external_reference_base_offset; + + + boolean symbol_table_full; + + +boolean done_debug; + + +bfd_chain_type *chain_head; +bfd_chain_type *chain_root; + +} ieee_data_type; + +typedef struct { + file_ptr file_offset; + bfd *abfd; +} ieee_ar_obstack_type; + +typedef struct ieee_ar_data_struct +{ + common_header_type h; + ieee_ar_obstack_type *elements; + + unsigned int element_index ; + unsigned int element_count; + +} ieee_ar_data_type; + +#define IEEE_DATA(abfd) ((abfd)->tdata.ieee_data) +#define IEEE_AR_DATA(abfd) ((abfd)->tdata.ieee_ar_data) + +#define ptr(abfd) (ieee_data(abfd)->input_p) diff --git a/contrib/gdb/bfd/libnlm.h b/contrib/gdb/bfd/libnlm.h new file mode 100644 index 000000000000..12d2e4e0cf8a --- /dev/null +++ b/contrib/gdb/bfd/libnlm.h @@ -0,0 +1,264 @@ +/* BFD back-end data structures for NLM (NetWare Loadable Modules) files. + Copyright (C) 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBNLM_H_ +#define _LIBNLM_H_ 1 + +#ifdef ARCH_SIZE +# define NLM_ARCH_SIZE ARCH_SIZE +#endif +#include "nlm/common.h" +#include "nlm/internal.h" +#include "nlm/external.h" + +/* A reloc for an imported NLM symbol. Normal relocs are associated + with sections, and include a symbol. These relocs are associated + with (undefined) symbols, and include a section. */ + +struct nlm_relent +{ + /* Section of reloc. */ + asection *section; + /* Reloc info (sym_ptr_ptr field set only when canonicalized). */ + arelent reloc; +}; + +/* Information we keep for an NLM symbol. */ + +typedef struct +{ + /* BFD symbol. */ + asymbol symbol; + /* Number of reloc entries for imported symbol. */ + bfd_size_type rcnt; + /* Array of reloc information for imported symbol. */ + struct nlm_relent *relocs; +} nlmNAME(symbol_type); + +extern boolean nlm_mkobject PARAMS ((bfd *)); +extern boolean nlm_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + +extern void nlmNAME(get_symbol_info) + PARAMS ((bfd *, asymbol *, symbol_info *)); +extern long nlmNAME(get_symtab_upper_bound) + PARAMS ((bfd *)); +extern long nlmNAME(get_symtab) + PARAMS ((bfd *, asymbol **)); +extern asymbol *nlmNAME(make_empty_symbol) + PARAMS ((bfd *)); +extern void nlmNAME(print_symbol) + PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type)); +extern long nlmNAME(get_reloc_upper_bound) + PARAMS ((bfd *, asection *)); +extern long nlmNAME(canonicalize_reloc) + PARAMS ((bfd *, asection *, arelent **, asymbol **)); +extern const bfd_target *nlmNAME(object_p) + PARAMS ((bfd *)); +extern boolean nlmNAME(set_arch_mach) + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +extern boolean nlmNAME(set_section_contents) + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +extern boolean nlmNAME(write_object_contents) + PARAMS ((bfd *)); + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +struct nlm_obj_tdata +{ + /* Actual data, but ref like ptr */ + Nlm_Internal_Fixed_Header nlm_fixed_hdr[1]; + Nlm_Internal_Variable_Header nlm_variable_hdr[1]; + Nlm_Internal_Version_Header nlm_version_hdr[1]; + Nlm_Internal_Copyright_Header nlm_copyright_hdr[1]; + Nlm_Internal_Extended_Header nlm_extended_hdr[1]; + Nlm_Internal_Custom_Header nlm_custom_hdr[1]; + Nlm_Internal_Cygnus_Ext_Header nlm_cygnus_ext_hdr[1]; + /* BFD NLM symbols. */ + nlmNAME(symbol_type) *nlm_symbols; + /* Lowest text and data VMA values. */ + bfd_vma nlm_text_low; + bfd_vma nlm_data_low; + /* Caches for data read from object file. */ + arelent * nlm_reloc_fixups; + asection ** nlm_reloc_fixup_secs; + /* Backend specific information. This should probably be a pointer, + but that would require yet another entry point to initialize the + structure. */ + union + { + struct /* Alpha backend information. */ + { + bfd_vma gp; /* GP value. */ + bfd_vma lita_address; /* .lita section address. */ + bfd_size_type lita_size; /* .lita section size. */ + } + alpha_backend_data; + } + backend_data; +}; + +#define nlm_tdata(bfd) ((bfd) -> tdata.nlm_obj_data) +#define nlm_fixed_header(bfd) (nlm_tdata(bfd) -> nlm_fixed_hdr) +#define nlm_variable_header(bfd) (nlm_tdata(bfd) -> nlm_variable_hdr) +#define nlm_version_header(bfd) (nlm_tdata(bfd) -> nlm_version_hdr) +#define nlm_copyright_header(bfd) (nlm_tdata(bfd) -> nlm_copyright_hdr) +#define nlm_extended_header(bfd) (nlm_tdata(bfd) -> nlm_extended_hdr) +#define nlm_custom_header(bfd) (nlm_tdata(bfd) -> nlm_custom_hdr) +#define nlm_cygnus_ext_header(bfd) (nlm_tdata(bfd) -> nlm_cygnus_ext_hdr) +#define nlm_get_symbols(bfd) (nlm_tdata(bfd) -> nlm_symbols) +#define nlm_set_symbols(bfd, p) (nlm_tdata(bfd) -> nlm_symbols = (p)) +#define nlm_set_text_low(bfd, i) (nlm_tdata(bfd) -> nlm_text_low = (i)) +#define nlm_get_text_low(bfd) (nlm_tdata(bfd) -> nlm_text_low) +#define nlm_set_data_low(bfd, i) (nlm_tdata(bfd) -> nlm_data_low = (i)) +#define nlm_get_data_low(bfd) (nlm_tdata(bfd) -> nlm_data_low) +#define nlm_relocation_fixups(bfd) (nlm_tdata(bfd) -> nlm_reloc_fixups) +#define nlm_relocation_fixup_secs(bfd) (nlm_tdata(bfd)->nlm_reloc_fixup_secs) + +#define nlm_alpha_backend_data(bfd) \ + (&nlm_tdata (bfd)->backend_data.alpha_backend_data) + +/* This is used when writing out the external relocs. */ + +struct reloc_and_sec +{ + arelent *rel; + asection *sec; +}; + +/* We store some function pointer in the backend structure. This lets + different NLM targets share most of the same code, while providing + slightly different code where necessary. */ + +struct nlm_backend_data +{ + /* Signature for this backend. */ + char signature[NLM_SIGNATURE_SIZE]; + /* Size of the fixed header. */ + bfd_size_type fixed_header_size; + /* Size of optional prefix for this backend. Some backend may + require this to be a function, but so far a constant is OK. This + is for a prefix which precedes the standard NLM fixed header. */ + bfd_size_type optional_prefix_size; + /* Architecture. */ + enum bfd_architecture arch; + /* Machine. */ + long mach; + /* Some NLM formats do not use the uninitialized data section, so + all uninitialized data must be put into the regular data section + instead. */ + boolean no_uninitialized_data; + /* Some NLM formats have a prefix on the file. If this function is + not NULL, it will be called by nlm_object_p. It should return + true if this file could match this format, and it should leave + the BFD such that a bfd_read will pick up the fixed header. */ + boolean (*nlm_backend_object_p) PARAMS ((bfd *)); + /* Write out the prefix. This function may be NULL. This must + write out the same number of bytes as is in the field + optional_prefix_size. */ + boolean (*nlm_write_prefix) PARAMS ((bfd *)); + /* Read a relocation fixup from abfd. The reloc information is + machine specific. The second argument is the symbol if this is + an import, or NULL if this is a reloc fixup. This function + should set the third argument to the section which the reloc + belongs in, and the fourth argument to the reloc itself; it does + not need to fill in the sym_ptr_ptr field for a reloc against an + import symbol. */ + boolean (*nlm_read_reloc) PARAMS ((bfd *, nlmNAME(symbol_type) *, + asection **, arelent *)); + /* To make objcopy to an i386 NLM work, the i386 backend needs a + chance to work over the relocs. This is a bit icky. */ + boolean (*nlm_mangle_relocs) PARAMS ((bfd *, asection *, PTR data, + bfd_vma offset, + bfd_size_type count)); + /* Read an import record from abfd. It would be nice if this + were in a machine-dependent format, but it doesn't seem to be. */ + boolean (*nlm_read_import) PARAMS ((bfd *, nlmNAME(symbol_type) *)); + /* Write an import record to abfd. */ + boolean (*nlm_write_import) PARAMS ((bfd *, asection *, arelent *)); + /* Set the section for a public symbol. This may be NULL, in which + case a default method will be used. */ + boolean (*nlm_set_public_section) PARAMS ((bfd *, nlmNAME(symbol_type) *)); + /* Get the offset to write out for a public symbol. This may be + NULL, in which case a default method will be used. */ + bfd_vma (*nlm_get_public_offset) PARAMS ((bfd *, asymbol *)); + /* Swap the fixed header in and out */ + void (*nlm_swap_fhdr_in) PARAMS ((bfd *, + PTR, + Nlm_Internal_Fixed_Header *)); + void (*nlm_swap_fhdr_out) PARAMS ((bfd *, + struct nlm_internal_fixed_header *, + PTR)); + /* Write out an external reference. */ + boolean (*nlm_write_external) PARAMS ((bfd *, bfd_size_type, + asymbol *, + struct reloc_and_sec *)); + boolean (*nlm_write_export) PARAMS ((bfd *, asymbol *, bfd_vma)); +}; + +#define nlm_backend(bfd) \ + ((struct nlm_backend_data *)((bfd) -> xvec -> backend_data)) +#define nlm_signature(bfd) \ + (nlm_backend(bfd) -> signature) +#define nlm_fixed_header_size(bfd) \ + (nlm_backend(bfd) -> fixed_header_size) +#define nlm_optional_prefix_size(bfd) \ + (nlm_backend(bfd) -> optional_prefix_size) +#define nlm_architecture(bfd) \ + (nlm_backend(bfd) -> arch) +#define nlm_machine(bfd) \ + (nlm_backend(bfd) -> mach) +#define nlm_no_uninitialized_data(bfd) \ + (nlm_backend(bfd) -> no_uninitialized_data) +#define nlm_backend_object_p_func(bfd) \ + (nlm_backend(bfd) -> nlm_backend_object_p) +#define nlm_write_prefix_func(bfd) \ + (nlm_backend(bfd) -> nlm_write_prefix) +#define nlm_read_reloc_func(bfd) \ + (nlm_backend(bfd) -> nlm_read_reloc) +#define nlm_mangle_relocs_func(bfd) \ + (nlm_backend(bfd) -> nlm_mangle_relocs) +#define nlm_read_import_func(bfd) \ + (nlm_backend(bfd) -> nlm_read_import) +#define nlm_write_import_func(bfd) \ + (nlm_backend(bfd) -> nlm_write_import) +#define nlm_set_public_section_func(bfd) \ + (nlm_backend(bfd) -> nlm_set_public_section) +#define nlm_get_public_offset_func(bfd) \ + (nlm_backend(bfd) -> nlm_get_public_offset) +#define nlm_swap_fixed_header_in_func(bfd) \ + (nlm_backend(bfd) -> nlm_swap_fhdr_in) +#define nlm_swap_fixed_header_out_func(bfd) \ + (nlm_backend(bfd) -> nlm_swap_fhdr_out) +#define nlm_write_external_func(bfd) \ + (nlm_backend(bfd) -> nlm_write_external) +#define nlm_write_export_func(bfd) \ + (nlm_backend(bfd) -> nlm_write_export) + +/* The NLM code, data, and uninitialized sections have no names defined + in the NLM, but bfd wants to give them names, so use the traditional + UNIX names. */ + +#define NLM_CODE_NAME ".text" +#define NLM_INITIALIZED_DATA_NAME ".data" +#define NLM_UNINITIALIZED_DATA_NAME ".bss" + +#endif /* _LIBNLM_H_ */ diff --git a/contrib/gdb/bfd/liboasys.h b/contrib/gdb/bfd/liboasys.h new file mode 100644 index 000000000000..2d1581376565 --- /dev/null +++ b/contrib/gdb/bfd/liboasys.h @@ -0,0 +1,83 @@ +/* BFD internal declarations for Oasys file format handling. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + Scrawled by Steve Chamberlain of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +typedef struct _oasys_symbol +{ + asymbol symbol; +} oasys_symbol_type; + +typedef struct _oasys_reloc { + arelent relent; + struct _oasys_reloc *next; + unsigned int symbol; +} oasys_reloc_type; + + +#define oasys_symbol(x) ((oasys_symbol_type *)(x)) +#define oasys_per_section(x) ((oasys_per_section_type *)(x->used_by_bfd)) + +typedef struct _oasys_per_section +{ + asection *section; + bfd_byte *data; + bfd_vma offset; + boolean had_vma; + oasys_reloc_type **reloc_tail_ptr; + bfd_vma pc; + + + file_ptr current_pos; + unsigned int current_byte; + boolean initialized; +} oasys_per_section_type; + +#define NSECTIONS 10 + +typedef struct _oasys_ar_obstack { + file_ptr file_offset; + bfd *abfd; +} oasys_ar_obstack_type; + + +typedef struct _oasys_module_info { + file_ptr pos; + unsigned int size; + bfd *abfd; + char *name; +} oasys_module_info_type; + +typedef struct _oasys_ar_data { + oasys_module_info_type *module; + unsigned int module_count; + unsigned int module_index; +} oasys_ar_data_type; + +typedef struct _oasys_data { + struct obstack oasys_obstack; + char *strings; + asymbol *symbols; + unsigned int symbol_string_length; + asection *sections[OASYS_MAX_SEC_COUNT]; + file_ptr first_data_record; +} oasys_data_type; + +#define OASYS_DATA(abfd) ((abfd)->tdata.oasys_obj_data) +#define OASYS_AR_DATA(abfd) ((abfd)->tdata.oasys_ar_data) + diff --git a/contrib/gdb/bfd/linker.c b/contrib/gdb/bfd/linker.c new file mode 100644 index 000000000000..4decc88cafae --- /dev/null +++ b/contrib/gdb/bfd/linker.c @@ -0,0 +1,2781 @@ +/* linker.c -- BFD linker routines + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" + +/* +SECTION + Linker Functions + +@cindex Linker + The linker uses three special entry points in the BFD target + vector. It is not necessary to write special routines for + these entry points when creating a new BFD back end, since + generic versions are provided. However, writing them can + speed up linking and make it use significantly less runtime + memory. + + The first routine creates a hash table used by the other + routines. The second routine adds the symbols from an object + file to the hash table. The third routine takes all the + object files and links them together to create the output + file. These routines are designed so that the linker proper + does not need to know anything about the symbols in the object + files that it is linking. The linker merely arranges the + sections as directed by the linker script and lets BFD handle + the details of symbols and relocs. + + The second routine and third routines are passed a pointer to + a <> structure (defined in + <>) which holds information relevant to the link, + including the linker hash table (which was created by the + first routine) and a set of callback functions to the linker + proper. + + The generic linker routines are in <>, and use the + header file <>. As of this writing, the only back + ends which have implemented versions of these routines are + a.out (in <>) and ECOFF (in <>). The a.out + routines are used as examples throughout this section. + +@menu +@* Creating a Linker Hash Table:: +@* Adding Symbols to the Hash Table:: +@* Performing the Final Link:: +@end menu + +INODE +Creating a Linker Hash Table, Adding Symbols to the Hash Table, Linker Functions, Linker Functions +SUBSECTION + Creating a linker hash table + +@cindex _bfd_link_hash_table_create in target vector +@cindex target vector (_bfd_link_hash_table_create) + The linker routines must create a hash table, which must be + derived from <> described in + <>. @xref{Hash Tables} for information on how to + create a derived hash table. This entry point is called using + the target vector of the linker output file. + + The <<_bfd_link_hash_table_create>> entry point must allocate + and initialize an instance of the desired hash table. If the + back end does not require any additional information to be + stored with the entries in the hash table, the entry point may + simply create a <>. Most likely, + however, some additional information will be needed. + + For example, with each entry in the hash table the a.out + linker keeps the index the symbol has in the final output file + (this index number is used so that when doing a relocateable + link the symbol index used in the output file can be quickly + filled in when copying over a reloc). The a.out linker code + defines the required structures and functions for a hash table + derived from <>. The a.out linker + hash table is created by the function + <>; it simply allocates + space for the hash table, initializes it, and returns a + pointer to it. + + When writing the linker routines for a new back end, you will + generally not know exactly which fields will be required until + you have finished. You should simply create a new hash table + which defines no additional fields, and then simply add fields + as they become necessary. + +INODE +Adding Symbols to the Hash Table, Performing the Final Link, Creating a Linker Hash Table, Linker Functions +SUBSECTION + Adding symbols to the hash table + +@cindex _bfd_link_add_symbols in target vector +@cindex target vector (_bfd_link_add_symbols) + The linker proper will call the <<_bfd_link_add_symbols>> + entry point for each object file or archive which is to be + linked (typically these are the files named on the command + line, but some may also come from the linker script). The + entry point is responsible for examining the file. For an + object file, BFD must add any relevant symbol information to + the hash table. For an archive, BFD must determine which + elements of the archive should be used and adding them to the + link. + + The a.out version of this entry point is + <>. + +@menu +@* Differing file formats:: +@* Adding symbols from an object file:: +@* Adding symbols from an archive:: +@end menu + +INODE +Differing file formats, Adding symbols from an object file, Adding Symbols to the Hash Table, Adding Symbols to the Hash Table +SUBSUBSECTION + Differing file formats + + Normally all the files involved in a link will be of the same + format, but it is also possible to link together different + format object files, and the back end must support that. The + <<_bfd_link_add_symbols>> entry point is called via the target + vector of the file to be added. This has an important + consequence: the function may not assume that the hash table + is the type created by the corresponding + <<_bfd_link_hash_table_create>> vector. All the + <<_bfd_link_add_symbols>> function can assume about the hash + table is that it is derived from <>. + + Sometimes the <<_bfd_link_add_symbols>> function must store + some information in the hash table entry to be used by the + <<_bfd_final_link>> function. In such a case the <> + field of the hash table must be checked to make sure that the + hash table was created by an object file of the same format. + + The <<_bfd_final_link>> routine must be prepared to handle a + hash entry without any extra information added by the + <<_bfd_link_add_symbols>> function. A hash entry without + extra information will also occur when the linker script + directs the linker to create a symbol. Note that, regardless + of how a hash table entry is added, all the fields will be + initialized to some sort of null value by the hash table entry + initialization function. + + See <> for an example of how to + check the <> field before saving information (in this + case, the ECOFF external symbol debugging information) in a + hash table entry. + +INODE +Adding symbols from an object file, Adding symbols from an archive, Differing file formats, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an object file + + When the <<_bfd_link_add_symbols>> routine is passed an object + file, it must add all externally visible symbols in that + object file to the hash table. The actual work of adding the + symbol to the hash table is normally handled by the function + <<_bfd_generic_link_add_one_symbol>>. The + <<_bfd_link_add_symbols>> routine is responsible for reading + all the symbols from the object file and passing the correct + information to <<_bfd_generic_link_add_one_symbol>>. + + The <<_bfd_link_add_symbols>> routine should not use + <> to read the symbols. The point of + providing this routine is to avoid the overhead of converting + the symbols into generic <> structures. + +@findex _bfd_generic_link_add_one_symbol + <<_bfd_generic_link_add_one_symbol>> handles the details of + combining common symbols, warning about multiple definitions, + and so forth. It takes arguments which describe the symbol to + add, notably symbol flags, a section, and an offset. The + symbol flags include such things as <> or + <>. The section is a section in the object + file, or something like <> for an undefined + symbol or <> for a common symbol. + + If the <<_bfd_final_link>> routine is also going to need to + read the symbol information, the <<_bfd_link_add_symbols>> + routine should save it somewhere attached to the object file + BFD. However, the information should only be saved if the + <> field of the <> argument is true, so + that the <<-no-keep-memory>> linker switch is effective. + + The a.out function which adds symbols from an object file is + <>, and most of the interesting + work is in <>. The latter saves + pointers to the hash tables entries created by + <<_bfd_generic_link_add_one_symbol>> indexed by symbol number, + so that the <<_bfd_final_link>> routine does not have to call + the hash table lookup routine to locate the entry. + +INODE +Adding symbols from an archive, , Adding symbols from an object file, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an archive + + When the <<_bfd_link_add_symbols>> routine is passed an + archive, it must look through the symbols defined by the + archive and decide which elements of the archive should be + included in the link. For each such element it must call the + <> linker callback, and it must add the + symbols from the object file to the linker hash table. + +@findex _bfd_generic_link_add_archive_symbols + In most cases the work of looking through the symbols in the + archive should be done by the + <<_bfd_generic_link_add_archive_symbols>> function. This + function builds a hash table from the archive symbol table and + looks through the list of undefined symbols to see which + elements should be included. + <<_bfd_generic_link_add_archive_symbols>> is passed a function + to call to make the final decision about adding an archive + element to the link and to do the actual work of adding the + symbols to the linker hash table. + + The function passed to + <<_bfd_generic_link_add_archive_symbols>> must read the + symbols of the archive element and decide whether the archive + element should be included in the link. If the element is to + be included, the <> linker callback + routine must be called with the element as an argument, and + the elements symbols must be added to the linker hash table + just as though the element had itself been passed to the + <<_bfd_link_add_symbols>> function. + + When the a.out <<_bfd_link_add_symbols>> function receives an + archive, it calls <<_bfd_generic_link_add_archive_symbols>> + passing <> as the function + argument. <> calls + <>. If the latter decides to add + the element (an element is only added if it provides a real, + non-common, definition for a previously undefined or common + symbol) it calls the <> callback and then + <> calls + <> to actually add the symbols to the + linker hash table. + + The ECOFF back end is unusual in that it does not normally + call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF + archives already contain a hash table of symbols. The ECOFF + back end searches the archive itself to avoid the overhead of + creating a new hash table. + +INODE +Performing the Final Link, , Adding Symbols to the Hash Table, Linker Functions +SUBSECTION + Performing the final link + +@cindex _bfd_link_final_link in target vector +@cindex target vector (_bfd_final_link) + When all the input files have been processed, the linker calls + the <<_bfd_final_link>> entry point of the output BFD. This + routine is responsible for producing the final output file, + which has several aspects. It must relocate the contents of + the input sections and copy the data into the output sections. + It must build an output symbol table including any local + symbols from the input files and the global symbols from the + hash table. When producing relocateable output, it must + modify the input relocs and write them into the output file. + There may also be object format dependent work to be done. + + The linker will also call the <> entry + point when the BFD is closed. The two entry points must work + together in order to produce the correct output file. + + The details of how this works are inevitably dependent upon + the specific object file format. The a.out + <<_bfd_final_link>> routine is <>. + +@menu +@* Information provided by the linker:: +@* Relocating the section contents:: +@* Writing the symbol table:: +@end menu + +INODE +Information provided by the linker, Relocating the section contents, Performing the Final Link, Performing the Final Link +SUBSUBSECTION + Information provided by the linker + + Before the linker calls the <<_bfd_final_link>> entry point, + it sets up some data structures for the function to use. + + The <> field of the <> structure + will point to a list of all the input files included in the + link. These files are linked through the <> field + of the <> structure. + + Each section in the output file will have a list of + <> structures attached to the <> + field (the <> structure is defined in + <>). These structures describe how to create the + contents of the output section in terms of the contents of + various input sections, fill constants, and, eventually, other + types of information. They also describe relocs that must be + created by the BFD backend, but do not correspond to any input + file; this is used to support -Ur, which builds constructors + while generating a relocateable object file. + +INODE +Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link +SUBSUBSECTION + Relocating the section contents + + The <<_bfd_final_link>> function should look through the + <> structures attached to each section of the + output file. Each <> structure should either be + handled specially, or it should be passed to the function + <<_bfd_default_link_order>> which will do the right thing + (<<_bfd_default_link_order>> is defined in <>). + + For efficiency, a <> of type + <> whose associated section belongs + to a BFD of the same format as the output BFD must be handled + specially. This type of <> describes part of an + output section in terms of a section belonging to one of the + input files. The <<_bfd_final_link>> function should read the + contents of the section and any associated relocs, apply the + relocs to the section contents, and write out the modified + section contents. If performing a relocateable link, the + relocs themselves must also be modified and written out. + +@findex _bfd_relocate_contents +@findex _bfd_final_link_relocate + The functions <<_bfd_relocate_contents>> and + <<_bfd_final_link_relocate>> provide some general support for + performing the actual relocations, notably overflow checking. + Their arguments include information about the symbol the + relocation is against and a <> argument + which describes the relocation to perform. These functions + are defined in <>. + + The a.out function which handles reading, relocating, and + writing section contents is <>. The + actual relocation is done in <> + and <>. + +INODE +Writing the symbol table, , Relocating the section contents, Performing the Final Link +SUBSUBSECTION + Writing the symbol table + + The <<_bfd_final_link>> function must gather all the symbols + in the input files and write them out. It must also write out + all the symbols in the global hash table. This must be + controlled by the <> and <> fields of the + <> structure. + + The local symbols of the input files will not have been + entered into the linker hash table. The <<_bfd_final_link>> + routine must consider each input file and include the symbols + in the output file. It may be convenient to do this when + looking through the <> structures, or it may be + done by stepping through the <> list. + + The <<_bfd_final_link>> routine must also traverse the global + hash table to gather all the externally visible symbols. It + is possible that most of the externally visible symbols may be + written out when considering the symbols of each input file, + but it is still necessary to traverse the hash table since the + linker script may have defined some symbols that are not in + any of the input files. + + The <> field of the <> structure + controls which symbols are written out. The possible values + are listed in <>. If the value is <>, + then the <> field of the <> + structure is a hash table of symbols to keep; each symbol + should be looked up in this hash table, and only symbols which + are present should be included in the output file. + + If the <> field of the <> structure + permits local symbols to be written out, the <> field + is used to further controls which local symbols are included + in the output file. If the value is <>, then all + local symbols which begin with a certain prefix are discarded; + this prefix is described by the <> and + <> fields of the <> structure. + + The a.out backend handles symbols by calling + <> on each input BFD and then + traversing the global hash table with the function + <>. It builds a string table + while writing out the symbols, which is written to the output + file at the end of <>. +*/ + +static struct bfd_hash_entry *generic_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +static boolean generic_link_read_symbols + PARAMS ((bfd *)); +static boolean generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean collect)); +static boolean generic_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean collect)); +static boolean generic_link_check_archive_element_no_collect + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean generic_link_check_archive_element_collect + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean generic_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded, boolean collect)); +static boolean generic_link_add_symbol_list + PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + boolean collect)); +static bfd *hash_entry_bfd PARAMS ((struct bfd_link_hash_entry *)); +static void set_symbol_from_hash + PARAMS ((asymbol *, struct bfd_link_hash_entry *)); +static boolean generic_add_output_symbol + PARAMS ((bfd *, size_t *psymalloc, asymbol *)); +static boolean default_fill_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); +static boolean default_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *, boolean)); + +/* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ + +/* Routine to create an entry in the link hash table. */ + +struct bfd_hash_entry * +_bfd_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct bfd_link_hash_entry *ret = (struct bfd_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct bfd_link_hash_entry *) NULL) + ret = ((struct bfd_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry))); + if (ret == (struct bfd_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct bfd_link_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->type = bfd_link_hash_new; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a link hash table. The BFD argument is the one + responsible for creating this table. */ + +boolean +_bfd_link_hash_table_init (table, abfd, newfunc) + struct bfd_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->creator = abfd->xvec; + table->undefs = NULL; + table->undefs_tail = NULL; + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up a symbol in a link hash table. If follow is true, we + follow bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ + +struct bfd_link_hash_entry * +bfd_link_hash_lookup (table, string, create, copy, follow) + struct bfd_link_hash_table *table; + const char *string; + boolean create; + boolean copy; + boolean follow; +{ + struct bfd_link_hash_entry *ret; + + ret = ((struct bfd_link_hash_entry *) + bfd_hash_lookup (&table->table, string, create, copy)); + + if (follow && ret != (struct bfd_link_hash_entry *) NULL) + { + while (ret->type == bfd_link_hash_indirect + || ret->type == bfd_link_hash_warning) + ret = ret->u.i.link; + } + + return ret; +} + +/* Look up a symbol in the main linker hash table if the symbol might + be wrapped. This should only be used for references to an + undefined symbol, not for definitions of a symbol. */ + +struct bfd_link_hash_entry * +bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow) + bfd *abfd; + struct bfd_link_info *info; + const char *string; + boolean create; + boolean copy; + boolean follow; +{ + if (info->wrap_hash != NULL) + { + const char *l; + + l = string; + if (*l == bfd_get_symbol_leading_char (abfd)) + ++l; + +#undef WRAP +#define WRAP "__wrap_" + + if (bfd_hash_lookup (info->wrap_hash, l, false, false) != NULL) + { + char *n; + struct bfd_link_hash_entry *h; + + /* This symbol is being wrapped. We want to replace all + references to SYM with references to __wrap_SYM. */ + + n = (char *) bfd_malloc (strlen (l) + sizeof WRAP + 1); + if (n == NULL) + return NULL; + + /* Note that symbol_leading_char may be '\0'. */ + n[0] = bfd_get_symbol_leading_char (abfd); + n[1] = '\0'; + strcat (n, WRAP); + strcat (n, l); + h = bfd_link_hash_lookup (info->hash, n, create, true, follow); + free (n); + return h; + } + +#undef WRAP + +#undef REAL +#define REAL "__real_" + + if (*l == '_' + && strncmp (l, REAL, sizeof REAL - 1) == 0 + && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1, + false, false) != NULL) + { + char *n; + struct bfd_link_hash_entry *h; + + /* This is a reference to __real_SYM, where SYM is being + wrapped. We want to replace all references to __real_SYM + with references to SYM. */ + + n = (char *) bfd_malloc (strlen (l + sizeof REAL - 1) + 2); + if (n == NULL) + return NULL; + + /* Note that symbol_leading_char may be '\0'. */ + n[0] = bfd_get_symbol_leading_char (abfd); + n[1] = '\0'; + strcat (n, l + sizeof REAL - 1); + h = bfd_link_hash_lookup (info->hash, n, create, true, follow); + free (n); + return h; + } + +#undef REAL + } + + return bfd_link_hash_lookup (info->hash, string, create, copy, follow); +} + +/* Traverse a generic link hash table. The only reason this is not a + macro is to do better type checking. This code presumes that an + argument passed as a struct bfd_hash_entry * may be caught as a + struct bfd_link_hash_entry * with no explicit cast required on the + call. */ + +void +bfd_link_hash_traverse (table, func, info) + struct bfd_link_hash_table *table; + boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR)); + PTR info; +{ + bfd_hash_traverse (&table->table, + ((boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) + func), + info); +} + +/* Add a symbol to the linker hash table undefs list. */ + +INLINE void +bfd_link_add_undef (table, h) + struct bfd_link_hash_table *table; + struct bfd_link_hash_entry *h; +{ + BFD_ASSERT (h->next == NULL); + if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL) + table->undefs_tail->next = h; + if (table->undefs == (struct bfd_link_hash_entry *) NULL) + table->undefs = h; + table->undefs_tail = h; +} + +/* Routine to create an entry in an generic link hash table. */ + +static struct bfd_hash_entry * +generic_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct generic_link_hash_entry *ret = + (struct generic_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct generic_link_hash_entry *) NULL) + ret = ((struct generic_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry))); + if (ret == (struct generic_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct generic_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Set local fields. */ + ret->written = false; + ret->sym = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create an generic link hash table. */ + +struct bfd_link_hash_table * +_bfd_generic_link_hash_table_create (abfd) + bfd *abfd; +{ + struct generic_link_hash_table *ret; + + ret = ((struct generic_link_hash_table *) + bfd_alloc (abfd, sizeof (struct generic_link_hash_table))); + if (ret == NULL) + return (struct bfd_link_hash_table *) NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, + generic_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Grab the symbols for an object file when doing a generic link. We + store the symbols in the outsymbols field. We need to keep them + around for the entire link to ensure that we only read them once. + If we read them multiple times, we might wind up with relocs and + the hash table pointing to different instances of the symbol + structure. */ + +static boolean +generic_link_read_symbols (abfd) + bfd *abfd; +{ + if (abfd->outsymbols == (asymbol **) NULL) + { + long symsize; + long symcount; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + return false; + abfd->outsymbols = (asymbol **) bfd_alloc (abfd, symsize); + if (abfd->outsymbols == NULL && symsize != 0) + return false; + symcount = bfd_canonicalize_symtab (abfd, abfd->outsymbols); + if (symcount < 0) + return false; + abfd->symcount = symcount; + } + + return true; +} + +/* Generic function to add symbols to from an object file to the + global hash table. This version does not automatically collect + constructors by name. */ + +boolean +_bfd_generic_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, false); +} + +/* Generic function to add symbols from an object file to the global + hash table. This version automatically collects constructors by + name, as the collect2 program does. It should be used for any + target which does not provide some other mechanism for setting up + constructors and destructors; these are approximately those targets + for which gcc uses collect2 and do not support stabs. */ + +boolean +_bfd_generic_link_add_symbols_collect (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, true); +} + +/* Add symbols from an object file to the global hash table. */ + +static boolean +generic_link_add_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean collect; +{ + boolean ret; + + switch (bfd_get_format (abfd)) + { + case bfd_object: + ret = generic_link_add_object_symbols (abfd, info, collect); + break; + case bfd_archive: + ret = (_bfd_generic_link_add_archive_symbols + (abfd, info, + (collect + ? generic_link_check_archive_element_collect + : generic_link_check_archive_element_no_collect))); + break; + default: + bfd_set_error (bfd_error_wrong_format); + ret = false; + } + + return ret; +} + +/* Add symbols from an object file to the global hash table. */ + +static boolean +generic_link_add_object_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean collect; +{ + if (! generic_link_read_symbols (abfd)) + return false; + return generic_link_add_symbol_list (abfd, info, + _bfd_generic_link_get_symcount (abfd), + _bfd_generic_link_get_symbols (abfd), + collect); +} + +/* We build a hash table of all symbols defined in an archive. */ + +/* An archive symbol may be defined by multiple archive elements. + This linked list is used to hold the elements. */ + +struct archive_list +{ + struct archive_list *next; + int indx; +}; + +/* An entry in an archive hash table. */ + +struct archive_hash_entry +{ + struct bfd_hash_entry root; + /* Where the symbol is defined. */ + struct archive_list *defs; +}; + +/* An archive hash table itself. */ + +struct archive_hash_table +{ + struct bfd_hash_table table; +}; + +static struct bfd_hash_entry *archive_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean archive_hash_table_init + PARAMS ((struct archive_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Create a new entry for an archive hash table. */ + +static struct bfd_hash_entry * +archive_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct archive_hash_entry *ret = (struct archive_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct archive_hash_entry *) NULL) + ret = ((struct archive_hash_entry *) + bfd_hash_allocate (table, sizeof (struct archive_hash_entry))); + if (ret == (struct archive_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct archive_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->defs = (struct archive_list *) NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an archive hash table. */ + +static boolean +archive_hash_table_init (table, newfunc) + struct archive_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up an entry in an archive hash table. */ + +#define archive_hash_lookup(t, string, create, copy) \ + ((struct archive_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Allocate space in an archive hash table. */ + +#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size)) + +/* Free an archive hash table. */ + +#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table) + +/* Generic function to add symbols from an archive file to the global + hash file. This function presumes that the archive symbol table + has already been read in (this is normally done by the + bfd_check_format entry point). It looks through the undefined and + common symbols and searches the archive symbol table for them. If + it finds an entry, it includes the associated object file in the + link. + + The old linker looked through the archive symbol table for + undefined symbols. We do it the other way around, looking through + undefined symbols for symbols defined in the archive. The + advantage of the newer scheme is that we only have to look through + the list of undefined symbols once, whereas the old method had to + re-search the symbol table each time a new object file was added. + + The CHECKFN argument is used to see if an object file should be + included. CHECKFN should set *PNEEDED to true if the object file + should be included, and must also call the bfd_link_info + add_archive_element callback function and handle adding the symbols + to the global hash table. CHECKFN should only return false if some + sort of error occurs. + + For some formats, such as a.out, it is possible to look through an + object file but not actually include it in the link. The + archive_pass field in a BFD is used to avoid checking the symbols + of an object files too many times. When an object is included in + the link, archive_pass is set to -1. If an object is scanned but + not included, archive_pass is set to the pass number. The pass + number is incremented each time a new object file is included. The + pass number is used because when a new object file is included it + may create new undefined symbols which cause a previously examined + object file to be included. */ + +boolean +_bfd_generic_link_add_archive_symbols (abfd, info, checkfn) + bfd *abfd; + struct bfd_link_info *info; + boolean (*checkfn) PARAMS ((bfd *, struct bfd_link_info *, + boolean *pneeded)); +{ + carsym *arsyms; + carsym *arsym_end; + register carsym *arsym; + int pass; + struct archive_hash_table arsym_hash; + int indx; + struct bfd_link_hash_entry **pundef; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return true; + bfd_set_error (bfd_error_no_armap); + return false; + } + + arsyms = bfd_ardata (abfd)->symdefs; + arsym_end = arsyms + bfd_ardata (abfd)->symdef_count; + + /* In order to quickly determine whether an symbol is defined in + this archive, we build a hash table of the symbols. */ + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc)) + return false; + for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) + { + struct archive_hash_entry *arh; + struct archive_list *l, **pp; + + arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false); + if (arh == (struct archive_hash_entry *) NULL) + goto error_return; + l = ((struct archive_list *) + archive_hash_allocate (&arsym_hash, sizeof (struct archive_list))); + if (l == NULL) + goto error_return; + l->indx = indx; + for (pp = &arh->defs; + *pp != (struct archive_list *) NULL; + pp = &(*pp)->next) + ; + *pp = l; + l->next = NULL; + } + + /* The archive_pass field in the archive itself is used to + initialize PASS, sine we may search the same archive multiple + times. */ + pass = abfd->archive_pass + 1; + + /* New undefined symbols are added to the end of the list, so we + only need to look through it once. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + struct archive_hash_entry *arh; + struct archive_list *l; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on (it would also cause + us to lose track of whether the symbol has been + referenced). */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive symbol map. */ + arh = archive_hash_lookup (&arsym_hash, h->root.string, false, false); + if (arh == (struct archive_hash_entry *) NULL) + { + pundef = &(*pundef)->next; + continue; + } + + /* Look at all the objects which define this symbol. */ + for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next) + { + bfd *element; + boolean needed; + + /* If the symbol has gotten defined along the way, quit. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + break; + + element = bfd_get_elt_at_index (abfd, l->indx); + if (element == (bfd *) NULL) + goto error_return; + + /* If we've already included this element, or if we've + already checked it on this pass, continue. */ + if (element->archive_pass == -1 + || element->archive_pass == pass) + continue; + + /* If we can't figure this element out, just ignore it. */ + if (! bfd_check_format (element, bfd_object)) + { + element->archive_pass = -1; + continue; + } + + /* CHECKFN will see if this element should be included, and + go ahead and include it if appropriate. */ + if (! (*checkfn) (element, info, &needed)) + goto error_return; + + if (! needed) + element->archive_pass = pass; + else + { + element->archive_pass = -1; + + /* Increment the pass count to show that we may need to + recheck object files which were already checked. */ + ++pass; + } + } + + pundef = &(*pundef)->next; + } + + archive_hash_table_free (&arsym_hash); + + /* Save PASS in case we are called again. */ + abfd->archive_pass = pass; + + return true; + + error_return: + archive_hash_table_free (&arsym_hash); + return false; +} + +/* See if we should include an archive element. This version is used + when we do not want to automatically collect constructors based on + the symbol name, presumably because we have some other mechanism + for finding them. */ + +static boolean +generic_link_check_archive_element_no_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, false); +} + +/* See if we should include an archive element. This version is used + when we want to automatically collect constructors based on the + symbol name, as collect2 does. */ + +static boolean +generic_link_check_archive_element_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, true); +} + +/* See if we should include an archive element. Optionally collect + constructors. */ + +static boolean +generic_link_check_archive_element (abfd, info, pneeded, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; + boolean collect; +{ + asymbol **pp, **ppend; + + *pneeded = false; + + if (! generic_link_read_symbols (abfd)) + return false; + + pp = _bfd_generic_link_get_symbols (abfd); + ppend = pp + _bfd_generic_link_get_symcount (abfd); + for (; pp < ppend; pp++) + { + asymbol *p; + struct bfd_link_hash_entry *h; + + p = *pp; + + /* We are only interested in globally visible symbols. */ + if (! bfd_is_com_section (p->section) + && (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0) + continue; + + /* We are only interested if we know something about this + symbol, and it is undefined or common. An undefined weak + symbol (type bfd_link_hash_undefweak) is not considered to be + a reference when pulling files out of an archive. See the + SVR4 ABI, p. 4-27. */ + h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), false, + false, true); + if (h == (struct bfd_link_hash_entry *) NULL + || (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common)) + continue; + + /* P is a symbol we are looking for. */ + + if (! bfd_is_com_section (p->section)) + { + bfd_size_type symcount; + asymbol **symbols; + + /* This object file defines this symbol, so pull it in. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, + bfd_asymbol_name (p))) + return false; + symcount = _bfd_generic_link_get_symcount (abfd); + symbols = _bfd_generic_link_get_symbols (abfd); + if (! generic_link_add_symbol_list (abfd, info, symcount, + symbols, collect)) + return false; + *pneeded = true; + return true; + } + + /* P is a common symbol. */ + + if (h->type == bfd_link_hash_undefined) + { + bfd *symbfd; + bfd_vma size; + unsigned int power; + + symbfd = h->u.undef.abfd; + if (symbfd == (bfd *) NULL) + { + /* This symbol was created as undefined from outside + BFD. We assume that we should link in the object + file. This is for the -u option in the linker. */ + if (! (*info->callbacks->add_archive_element) + (info, abfd, bfd_asymbol_name (p))) + return false; + *pneeded = true; + return true; + } + + /* Turn the symbol into a common symbol but do not link in + the object file. This is how a.out works. Object + formats that require different semantics must implement + this function differently. This symbol is already on the + undefs list. We add the section to a common section + attached to symbfd to ensure that it is in a BFD which + will be linked in. */ + h->type = bfd_link_hash_common; + h->u.c.p = + ((struct bfd_link_hash_common_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_common_entry))); + if (h->u.c.p == NULL) + return false; + + size = bfd_asymbol_value (p); + h->u.c.size = size; + + power = bfd_log2 (size); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + if (p->section == bfd_com_section_ptr) + h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON"); + else + h->u.c.p->section = bfd_make_section_old_way (symbfd, + p->section->name); + h->u.c.p->section->flags = SEC_ALLOC; + } + else + { + /* Adjust the size of the common symbol if necessary. This + is how a.out works. Object formats that require + different semantics must implement this function + differently. */ + if (bfd_asymbol_value (p) > h->u.c.size) + h->u.c.size = bfd_asymbol_value (p); + } + } + + /* This archive element is not needed. */ + return true; +} + +/* Add the symbols from an object file to the global hash table. ABFD + is the object file. INFO is the linker information. SYMBOL_COUNT + is the number of symbols. SYMBOLS is the list of symbols. COLLECT + is true if constructors should be automatically collected by name + as is done by collect2. */ + +static boolean +generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_size_type symbol_count; + asymbol **symbols; + boolean collect; +{ + asymbol **pp, **ppend; + + pp = symbols; + ppend = symbols + symbol_count; + for (; pp < ppend; pp++) + { + asymbol *p; + + p = *pp; + + if ((p->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (p)) + || bfd_is_com_section (bfd_get_section (p)) + || bfd_is_ind_section (bfd_get_section (p))) + { + const char *name; + const char *string; + struct generic_link_hash_entry *h; + + name = bfd_asymbol_name (p); + if (((p->flags & BSF_INDIRECT) != 0 + || bfd_is_ind_section (p->section)) + && pp + 1 < ppend) + { + pp++; + string = bfd_asymbol_name (*pp); + } + else if ((p->flags & BSF_WARNING) != 0 + && pp + 1 < ppend) + { + /* The name of P is actually the warning string, and the + next symbol is the one to warn about. */ + string = name; + pp++; + name = bfd_asymbol_name (*pp); + } + else + string = NULL; + + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, p->flags, bfd_get_section (p), + p->value, string, false, collect, + (struct bfd_link_hash_entry **) &h))) + return false; + + /* If this is a constructor symbol, and the linker didn't do + anything with it, then we want to just pass the symbol + through to the output file. This will happen when + linking with -r. */ + if ((p->flags & BSF_CONSTRUCTOR) != 0 + && (h == NULL || h->root.type == bfd_link_hash_new)) + { + p->udata.p = NULL; + continue; + } + + /* Save the BFD symbol so that we don't lose any backend + specific information that may be attached to it. We only + want this one if it gives more information than the + existing one; we don't want to replace a defined symbol + with an undefined one. This routine may be called with a + hash table other than the generic hash table, so we only + do this if we are certain that the hash table is a + generic one. */ + if (info->hash->creator == abfd->xvec) + { + if (h->sym == (asymbol *) NULL + || (! bfd_is_und_section (bfd_get_section (p)) + && (! bfd_is_com_section (bfd_get_section (p)) + || bfd_is_und_section (bfd_get_section (h->sym))))) + { + h->sym = p; + /* BSF_OLD_COMMON is a hack to support COFF reloc + reading, and it should go away when the COFF + linker is switched to the new version. */ + if (bfd_is_com_section (bfd_get_section (p))) + p->flags |= BSF_OLD_COMMON; + } + + /* Store a back pointer from the symbol to the hash + table entry for the benefit of relaxation code until + it gets rewritten to not use asymbol structures. + Setting this is also used to check whether these + symbols were set up by the generic linker. */ + p->udata.p = (PTR) h; + } + } + } + + return true; +} + +/* We use a state table to deal with adding symbols from an object + file. The first index into the state table describes the symbol + from the object file. The second index into the state table is the + type of the symbol in the hash table. */ + +/* The symbol from the object file is turned into one of these row + values. */ + +enum link_row +{ + UNDEF_ROW, /* Undefined. */ + UNDEFW_ROW, /* Weak undefined. */ + DEF_ROW, /* Defined. */ + DEFW_ROW, /* Weak defined. */ + COMMON_ROW, /* Common. */ + INDR_ROW, /* Indirect. */ + WARN_ROW, /* Warning. */ + SET_ROW /* Member of set. */ +}; + +/* apparently needed for Hitachi 3050R(HI-UX/WE2)? */ +#undef FAIL + +/* The actions to take in the state table. */ + +enum link_action +{ + FAIL, /* Abort. */ + UND, /* Mark symbol undefined. */ + WEAK, /* Mark symbol weak undefined. */ + DEF, /* Mark symbol defined. */ + DEFW, /* Mark symbol weak defined. */ + COM, /* Mark symbol common. */ + REF, /* Mark defined symbol referenced. */ + CREF, /* Possibly warn about common reference to defined symbol. */ + CDEF, /* Define existing common symbol. */ + NOACT, /* No action. */ + BIG, /* Mark symbol common using largest size. */ + MDEF, /* Multiple definition error. */ + MIND, /* Multiple indirect symbols. */ + IND, /* Make indirect symbol. */ + CIND, /* Make indirect symbol from existing common symbol. */ + SET, /* Add value to set. */ + MWARN, /* Make warning symbol. */ + WARN, /* Issue warning. */ + CWARN, /* Warn if referenced, else MWARN. */ + CYCLE, /* Repeat with symbol pointed to. */ + REFC, /* Mark indirect symbol referenced and then CYCLE. */ + WARNC /* Issue warning and then CYCLE. */ +}; + +/* The state table itself. The first index is a link_row and the + second index is a bfd_link_hash_type. */ + +static const enum link_action link_action[8][8] = +{ + /* current\prev new undef undefw def defw com indr warn */ + /* UNDEF_ROW */ {UND, NOACT, UND, REF, REF, NOACT, REFC, WARNC }, + /* UNDEFW_ROW */ {WEAK, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC }, + /* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MDEF, CYCLE }, + /* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE }, + /* COMMON_ROW */ {COM, COM, COM, CREF, CREF, BIG, CREF, WARNC }, + /* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE }, + /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, CYCLE }, + /* SET_ROW */ {SET, SET, SET, SET, SET, SET, CYCLE, CYCLE } +}; + +/* Most of the entries in the LINK_ACTION table are straightforward, + but a few are somewhat subtle. + + A reference to an indirect symbol (UNDEF_ROW/indr or + UNDEFW_ROW/indr) is counted as a reference both to the indirect + symbol and to the symbol the indirect symbol points to. + + A reference to a warning symbol (UNDEF_ROW/warn or UNDEFW_ROW/warn) + causes the warning to be issued. + + A common definition of an indirect symbol (COMMON_ROW/indr) is + treated as a multiple definition error. Likewise for an indirect + definition of a common symbol (INDR_ROW/com). + + An indirect definition of a warning (INDR_ROW/warn) does not cause + the warning to be issued. + + If a warning is created for an indirect symbol (WARN_ROW/indr) no + warning is created for the symbol the indirect symbol points to. + + Adding an entry to a set does not count as a reference to a set, + and no warning is issued (SET_ROW/warn). */ + +/* Return the BFD in which a hash entry has been defined, if known. */ + +static bfd * +hash_entry_bfd (h) + struct bfd_link_hash_entry *h; +{ + while (h->type == bfd_link_hash_warning) + h = h->u.i.link; + switch (h->type) + { + default: + return NULL; + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + return h->u.undef.abfd; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->u.def.section->owner; + case bfd_link_hash_common: + return h->u.c.p->section->owner; + } + /*NOTREACHED*/ +} + +/* Add a symbol to the global hash table. + ABFD is the BFD the symbol comes from. + NAME is the name of the symbol. + FLAGS is the BSF_* bits associated with the symbol. + SECTION is the section in which the symbol is defined; this may be + bfd_und_section_ptr or bfd_com_section_ptr. + VALUE is the value of the symbol, relative to the section. + STRING is used for either an indirect symbol, in which case it is + the name of the symbol to indirect to, or a warning symbol, in + which case it is the warning string. + COPY is true if NAME or STRING must be copied into locally + allocated memory if they need to be saved. + COLLECT is true if we should automatically collect gcc constructor + or destructor names as collect2 does. + HASHP, if not NULL, is a place to store the created hash table + entry; if *HASHP is not NULL, the caller has already looked up + the hash table entry, and stored it in *HASHP. */ + +boolean +_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, + string, copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + enum link_row row; + struct bfd_link_hash_entry *h; + boolean cycle; + + if (bfd_is_ind_section (section) + || (flags & BSF_INDIRECT) != 0) + row = INDR_ROW; + else if ((flags & BSF_WARNING) != 0) + row = WARN_ROW; + else if ((flags & BSF_CONSTRUCTOR) != 0) + row = SET_ROW; + else if (bfd_is_und_section (section)) + { + if ((flags & BSF_WEAK) != 0) + row = UNDEFW_ROW; + else + row = UNDEF_ROW; + } + else if ((flags & BSF_WEAK) != 0) + row = DEFW_ROW; + else if (bfd_is_com_section (section)) + row = COMMON_ROW; + else + row = DEF_ROW; + + if (hashp != NULL && *hashp != NULL) + h = *hashp; + else + { + if (row == UNDEF_ROW || row == UNDEFW_ROW) + h = bfd_wrapped_link_hash_lookup (abfd, info, name, true, copy, false); + else + h = bfd_link_hash_lookup (info->hash, name, true, copy, false); + if (h == NULL) + { + if (hashp != NULL) + *hashp = NULL; + return false; + } + } + + if (info->notice_hash != (struct bfd_hash_table *) NULL + && (bfd_hash_lookup (info->notice_hash, name, false, false) + != (struct bfd_hash_entry *) NULL)) + { + if (! (*info->callbacks->notice) (info, name, abfd, section, value)) + return false; + } + + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = h; + + do + { + enum link_action action; + + cycle = false; + action = link_action[(int) row][(int) h->type]; + switch (action) + { + case FAIL: + abort (); + + case NOACT: + /* Do nothing. */ + break; + + case UND: + /* Make a new undefined symbol. */ + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, h); + break; + + case WEAK: + /* Make a new weak undefined symbol. */ + h->type = bfd_link_hash_undefweak; + h->u.undef.abfd = abfd; + break; + + case CDEF: + /* We have found a definition for a symbol which was + previously common. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_defined, (bfd_vma) 0))) + return false; + /* Fall through. */ + case DEF: + case DEFW: + { + enum bfd_link_hash_type oldtype; + + /* Define a symbol. */ + oldtype = h->type; + if (action == DEFW) + h->type = bfd_link_hash_defweak; + else + h->type = bfd_link_hash_defined; + h->u.def.section = section; + h->u.def.value = value; + + /* If we have been asked to, we act like collect2 and + identify all functions that might be global + constructors and destructors and pass them up in a + callback. We only do this for certain object file + types, since many object file types can handle this + automatically. */ + if (collect && name[0] == '_') + { + const char *s; + + /* A constructor or destructor name starts like this: + _+GLOBAL_[_.$][ID][_.$] where the first [_.$] and + the second are the same character (we accept any + character there, in case a new object file format + comes along with even worse naming restrictions). */ + +#define CONS_PREFIX "GLOBAL_" +#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1) + + s = name + 1; + while (*s == '_') + ++s; + if (s[0] == 'G' + && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0) + { + char c; + + c = s[CONS_PREFIX_LEN + 1]; + if ((c == 'I' || c == 'D') + && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2]) + { + /* If this is a definition of a symbol which + was previously weakly defined, we are in + trouble. We have already added a + constructor entry for the weak defined + symbol, and now we are trying to add one + for the new symbol. Fortunately, this case + should never arise in practice. */ + if (oldtype == bfd_link_hash_defweak) + abort (); + + if (! ((*info->callbacks->constructor) + (info, + c == 'I' ? true : false, + name, abfd, section, value))) + return false; + } + } + } + } + + break; + + case COM: + /* We have found a common definition for a symbol. */ + if (h->type == bfd_link_hash_new) + bfd_link_add_undef (info->hash, h); + h->type = bfd_link_hash_common; + h->u.c.p = + ((struct bfd_link_hash_common_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_common_entry))); + if (h->u.c.p == NULL) + return false; + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + { + unsigned int power; + + power = bfd_log2 (value); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + } + + /* The section of a common symbol is only used if the common + symbol is actually allocated. It basically provides a + hook for the linker script to decide which output section + the common symbols should be put in. In most cases, the + section of a common symbol will be bfd_com_section_ptr, + the code here will choose a common symbol section named + "COMMON", and the linker script will contain *(COMMON) in + the appropriate place. A few targets use separate common + sections for small symbols, and they require special + handling. */ + if (section == bfd_com_section_ptr) + { + h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); + h->u.c.p->section->flags = SEC_ALLOC; + } + else if (section->owner != abfd) + { + h->u.c.p->section = bfd_make_section_old_way (abfd, + section->name); + h->u.c.p->section->flags = SEC_ALLOC; + } + else + h->u.c.p->section = section; + break; + + case REF: + /* A reference to a defined symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + break; + + case BIG: + /* We have found a common definition for a symbol which + already had a common definition. Use the maximum of the + two sizes. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_common, value))) + return false; + if (value > h->u.c.size) + { + unsigned int power; + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + power = bfd_log2 (value); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + } + break; + + case CREF: + { + bfd *obfd; + + /* We have found a common definition for a symbol which + was already defined. FIXME: It would nice if we could + report the BFD which defined an indirect symbol, but we + don't have anywhere to store the information. */ + if (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + obfd = h->u.def.section->owner; + else + obfd = NULL; + if (! ((*info->callbacks->multiple_common) + (info, name, obfd, h->type, (bfd_vma) 0, + abfd, bfd_link_hash_common, value))) + return false; + } + break; + + case MIND: + /* Multiple indirect symbols. This is OK if they both point + to the same symbol. */ + if (strcmp (h->u.i.link->root.string, string) == 0) + break; + /* Fall through. */ + case MDEF: + /* Handle a multiple definition. */ + { + asection *msec; + bfd_vma mval; + + switch (h->type) + { + case bfd_link_hash_defined: + msec = h->u.def.section; + mval = h->u.def.value; + break; + case bfd_link_hash_indirect: + msec = bfd_ind_section_ptr; + mval = 0; + break; + default: + abort (); + } + + /* Ignore a redefinition of an absolute symbol to the same + value; it's harmless. */ + if (h->type == bfd_link_hash_defined + && bfd_is_abs_section (msec) + && bfd_is_abs_section (section) + && value == mval) + break; + + if (! ((*info->callbacks->multiple_definition) + (info, name, msec->owner, msec, mval, abfd, section, + value))) + return false; + } + break; + + case CIND: + /* Create an indirect symbol from an existing common symbol. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_indirect, (bfd_vma) 0))) + return false; + /* Fall through. */ + case IND: + /* Create an indirect symbol. */ + { + struct bfd_link_hash_entry *inh; + + /* STRING is the name of the symbol we want to indirect + to. */ + inh = bfd_wrapped_link_hash_lookup (abfd, info, string, true, + copy, false); + if (inh == (struct bfd_link_hash_entry *) NULL) + return false; + if (inh->type == bfd_link_hash_new) + { + inh->type = bfd_link_hash_undefined; + inh->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, inh); + } + + /* If the indirect symbol has been referenced, we need to + push the reference down to the symbol we are + referencing. */ + if (h->type != bfd_link_hash_new) + { + row = UNDEF_ROW; + cycle = true; + } + + h->type = bfd_link_hash_indirect; + h->u.i.link = inh; + } + break; + + case SET: + /* Add an entry to a set. */ + if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, + abfd, section, value)) + return false; + break; + + case WARNC: + /* Issue a warning and cycle. */ + if (h->u.i.warning != NULL) + { + if (! (*info->callbacks->warning) (info, h->u.i.warning, name, + abfd, (asection *) NULL, + (bfd_vma) 0)) + return false; + /* Only issue a warning once. */ + h->u.i.warning = NULL; + } + /* Fall through. */ + case CYCLE: + /* Try again with the referenced symbol. */ + h = h->u.i.link; + cycle = true; + break; + + case REFC: + /* A reference to an indirect symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + h = h->u.i.link; + cycle = true; + break; + + case WARN: + /* Issue a warning. */ + if (! (*info->callbacks->warning) (info, string, name, + hash_entry_bfd (h), + (asection *) NULL, (bfd_vma) 0)) + return false; + break; + + case CWARN: + /* Warn if this symbol has been referenced already, + otherwise add a warning. A symbol has been referenced if + the next field is not NULL, or it is the tail of the + undefined symbol list. The REF case above helps to + ensure this. */ + if (h->next != NULL || info->hash->undefs_tail == h) + { + if (! (*info->callbacks->warning) (info, string, name, + hash_entry_bfd (h), + (asection *) NULL, + (bfd_vma) 0)) + return false; + break; + } + /* Fall through. */ + case MWARN: + /* Make a warning symbol. */ + { + struct bfd_link_hash_entry *sub; + + /* STRING is the warning to give. */ + sub = ((struct bfd_link_hash_entry *) + ((*info->hash->table.newfunc) + ((struct bfd_hash_entry *) NULL, &info->hash->table, + h->root.string))); + if (sub == NULL) + return false; + *sub = *h; + sub->type = bfd_link_hash_warning; + sub->u.i.link = h; + if (! copy) + sub->u.i.warning = string; + else + { + char *w; + + w = bfd_hash_allocate (&info->hash->table, + strlen (string) + 1); + if (w == NULL) + return false; + strcpy (w, string); + sub->u.i.warning = w; + } + + bfd_hash_replace (&info->hash->table, + (struct bfd_hash_entry *) h, + (struct bfd_hash_entry *) sub); + if (hashp != NULL) + *hashp = sub; + } + break; + } + } + while (cycle); + + return true; +} + +/* Generic final link routine. */ + +boolean +_bfd_generic_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *sub; + asection *o; + struct bfd_link_order *p; + size_t outsymalloc; + struct generic_write_global_symbol_info wginfo; + + abfd->outsymbols = (asymbol **) NULL; + abfd->symcount = 0; + outsymalloc = 0; + + /* Build the output symbol table. */ + for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) + if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) + return false; + + /* Accumulate the global symbols. */ + wginfo.info = info; + wginfo.output_bfd = abfd; + wginfo.psymalloc = &outsymalloc; + _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), + _bfd_generic_link_write_global_symbol, + (PTR) &wginfo); + + if (info->relocateable) + { + /* Allocate space for the output relocs for each section. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + o->reloc_count = 0; + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) + { + asection *input_section; + bfd *input_bfd; + long relsize; + arelent **relocs; + asymbol **symbols; + long reloc_count; + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + relsize = bfd_get_reloc_upper_bound (input_bfd, + input_section); + if (relsize < 0) + return false; + relocs = (arelent **) bfd_malloc ((size_t) relsize); + if (!relocs && relsize != 0) + return false; + symbols = _bfd_generic_link_get_symbols (input_bfd); + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + relocs, + symbols); + if (reloc_count < 0) + return false; + BFD_ASSERT ((unsigned long) reloc_count + == input_section->reloc_count); + o->reloc_count += reloc_count; + free (relocs); + } + } + if (o->reloc_count > 0) + { + o->orelocation = ((arelent **) + bfd_alloc (abfd, + (o->reloc_count + * sizeof (arelent *)))); + if (!o->orelocation) + return false; + o->flags |= SEC_RELOC; + /* Reset the count so that it can be used as an index + when putting in the output relocs. */ + o->reloc_count = 0; + } + } + } + + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) + return false; + break; + case bfd_indirect_link_order: + if (! default_indirect_link_order (abfd, info, o, p, true)) + return false; + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + break; + } + } + } + + return true; +} + +/* Add an output symbol to the output BFD. */ + +static boolean +generic_add_output_symbol (output_bfd, psymalloc, sym) + bfd *output_bfd; + size_t *psymalloc; + asymbol *sym; +{ + if (output_bfd->symcount >= *psymalloc) + { + asymbol **newsyms; + + if (*psymalloc == 0) + *psymalloc = 124; + else + *psymalloc *= 2; + newsyms = (asymbol **) bfd_realloc (output_bfd->outsymbols, + *psymalloc * sizeof (asymbol *)); + if (newsyms == (asymbol **) NULL) + return false; + output_bfd->outsymbols = newsyms; + } + + output_bfd->outsymbols[output_bfd->symcount] = sym; + ++output_bfd->symcount; + + return true; +} + +/* Handle the symbols for an input BFD. */ + +boolean +_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + size_t *psymalloc; +{ + asymbol **sym_ptr; + asymbol **sym_end; + + if (! generic_link_read_symbols (input_bfd)) + return false; + + /* Create a filename symbol if we are supposed to. */ + if (info->create_object_symbols_section != (asection *) NULL) + { + asection *sec; + + for (sec = input_bfd->sections; + sec != (asection *) NULL; + sec = sec->next) + { + if (sec->output_section == info->create_object_symbols_section) + { + asymbol *newsym; + + newsym = bfd_make_empty_symbol (input_bfd); + if (!newsym) + return false; + newsym->name = input_bfd->filename; + newsym->value = 0; + newsym->flags = BSF_LOCAL | BSF_FILE; + newsym->section = sec; + + if (! generic_add_output_symbol (output_bfd, psymalloc, + newsym)) + return false; + + break; + } + } + } + + /* Adjust the values of the globally visible symbols, and write out + local symbols. */ + sym_ptr = _bfd_generic_link_get_symbols (input_bfd); + sym_end = sym_ptr + _bfd_generic_link_get_symcount (input_bfd); + for (; sym_ptr < sym_end; sym_ptr++) + { + asymbol *sym; + struct generic_link_hash_entry *h; + boolean output; + + h = (struct generic_link_hash_entry *) NULL; + sym = *sym_ptr; + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_is_ind_section (bfd_get_section (sym))) + { + if (sym->udata.p != NULL) + h = (struct generic_link_hash_entry *) sym->udata.p; + else if ((sym->flags & BSF_CONSTRUCTOR) != 0) + { + /* This case normally means that the main linker code + deliberately ignored this constructor symbol. We + should just pass it through. This will screw up if + the constructor symbol is from a different, + non-generic, object file format, but the case will + only arise when linking with -r, which will probably + fail anyhow, since there will be no way to represent + the relocs in the output format being used. */ + h = NULL; + } + else if (bfd_is_und_section (bfd_get_section (sym))) + h = ((struct generic_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + bfd_asymbol_name (sym), + false, false, true)); + else + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + bfd_asymbol_name (sym), + false, false, true); + + if (h != (struct generic_link_hash_entry *) NULL) + { + /* Force all references to this symbol to point to + the same area in memory. It is possible that + this routine will be called with a hash table + other than a generic hash table, so we double + check that. */ + if (info->hash->creator == input_bfd->xvec) + { + if (h->sym != (asymbol *) NULL) + *sym_ptr = sym = h->sym; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + break; + case bfd_link_hash_undefweak: + sym->flags |= BSF_WEAK; + break; + case bfd_link_hash_indirect: + h = (struct generic_link_hash_entry *) h->root.u.i.link; + /* fall through */ + case bfd_link_hash_defined: + sym->flags |= BSF_GLOBAL; + sym->flags &=~ BSF_CONSTRUCTOR; + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + break; + case bfd_link_hash_defweak: + sym->flags |= BSF_WEAK; + sym->flags &=~ BSF_CONSTRUCTOR; + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + sym->flags |= BSF_GLOBAL; + if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* We do not set the section of the symbol to + h->root.u.c.p->section. That value was saved so + that we would know where to allocate the symbol + if it was defined. In this case the type is + still bfd_link_hash_common, so we did not define + it, so we do not want to use that section. */ + break; + } + } + } + + /* This switch is straight from the old code in + write_file_locals in ldsym.c. */ + if (info->strip == strip_some + && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym), + false, false) + == (struct bfd_hash_entry *) NULL)) + output = false; + else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + { + /* If this symbol is marked as occurring now, rather + than at the end, output it now. This is used for + COFF C_EXT FCN symbols. FIXME: There must be a + better way. */ + if (bfd_asymbol_bfd (sym) == input_bfd + && (sym->flags & BSF_NOT_AT_END) != 0) + output = true; + else + output = false; + } + else if (bfd_is_ind_section (sym->section)) + output = false; + else if ((sym->flags & BSF_DEBUGGING) != 0) + { + if (info->strip == strip_none) + output = true; + else + output = false; + } + else if (bfd_is_und_section (sym->section) + || bfd_is_com_section (sym->section)) + output = false; + else if ((sym->flags & BSF_LOCAL) != 0) + { + if ((sym->flags & BSF_WARNING) != 0) + output = false; + else + { + switch (info->discard) + { + default: + case discard_all: + output = false; + break; + case discard_l: + if (bfd_asymbol_name (sym)[0] == info->lprefix[0] + && (info->lprefix_len == 1 + || strncmp (bfd_asymbol_name (sym), info->lprefix, + info->lprefix_len) == 0)) + output = false; + else + output = true; + break; + case discard_none: + output = true; + break; + } + } + } + else if ((sym->flags & BSF_CONSTRUCTOR)) + { + if (info->strip != strip_all) + output = true; + else + output = false; + } + else + abort (); + + if (output) + { + if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) + return false; + if (h != (struct generic_link_hash_entry *) NULL) + h->written = true; + } + } + + return true; +} + +/* Set the section and value of a generic BFD symbol based on a linker + hash table entry. */ + +static void +set_symbol_from_hash (sym, h) + asymbol *sym; + struct bfd_link_hash_entry *h; +{ + switch (h->type) + { + default: + abort (); + break; + case bfd_link_hash_new: + /* This can happen when a constructor symbol is seen but we are + not building constructors. */ + if (sym->section != NULL) + { + BFD_ASSERT ((sym->flags & BSF_CONSTRUCTOR) != 0); + } + else + { + sym->flags |= BSF_CONSTRUCTOR; + sym->section = bfd_abs_section_ptr; + sym->value = 0; + } + break; + case bfd_link_hash_undefined: + sym->section = bfd_und_section_ptr; + sym->value = 0; + break; + case bfd_link_hash_undefweak: + sym->section = bfd_und_section_ptr; + sym->value = 0; + sym->flags |= BSF_WEAK; + break; + case bfd_link_hash_defined: + sym->section = h->u.def.section; + sym->value = h->u.def.value; + break; + case bfd_link_hash_defweak: + sym->flags |= BSF_WEAK; + sym->section = h->u.def.section; + sym->value = h->u.def.value; + break; + case bfd_link_hash_common: + sym->value = h->u.c.size; + if (sym->section == NULL) + sym->section = bfd_com_section_ptr; + else if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* Do not set the section; see _bfd_generic_link_output_symbols. */ + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: What should we do here? */ + break; + } +} + +/* Write out a global symbol, if it hasn't already been written out. + This is called for each symbol in the hash table. */ + +boolean +_bfd_generic_link_write_global_symbol (h, data) + struct generic_link_hash_entry *h; + PTR data; +{ + struct generic_write_global_symbol_info *wginfo = + (struct generic_write_global_symbol_info *) data; + asymbol *sym; + + if (h->written) + return true; + + h->written = true; + + if (wginfo->info->strip == strip_all + || (wginfo->info->strip == strip_some + && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string, + false, false) == NULL)) + return true; + + if (h->sym != (asymbol *) NULL) + sym = h->sym; + else + { + sym = bfd_make_empty_symbol (wginfo->output_bfd); + if (!sym) + return false; + sym->name = h->root.root.string; + sym->flags = 0; + } + + set_symbol_from_hash (sym, &h->root); + + sym->flags |= BSF_GLOBAL; + + if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc, + sym)) + { + /* FIXME: No way to return failure. */ + abort (); + } + + return true; +} + +/* Create a relocation. */ + +boolean +_bfd_generic_reloc_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + arelent *r; + + if (! info->relocateable) + abort (); + if (sec->orelocation == (arelent **) NULL) + abort (); + + r = (arelent *) bfd_alloc (abfd, sizeof (arelent)); + if (r == (arelent *) NULL) + return false; + + r->address = link_order->offset; + r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); + if (r->howto == 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Get the symbol to use for the relocation. */ + if (link_order->type == bfd_section_reloc_link_order) + r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + else + { + struct generic_link_hash_entry *h; + + h = ((struct generic_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h == (struct generic_link_hash_entry *) NULL + || ! h->written) + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + return false; + bfd_set_error (bfd_error_bad_value); + return false; + } + r->sym_ptr_ptr = &h->sym; + } + + /* If this is an inplace reloc, write the addend to the object file. + Otherwise, store it in the reloc addend. */ + if (! r->howto->partial_inplace) + r->addend = link_order->u.reloc.p->addend; + else + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (r->howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return false; + rstat = _bfd_relocate_contents (r->howto, abfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (abfd, link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + r->howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (abfd, sec, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + + r->addend = 0; + } + + sec->orelocation[sec->reloc_count] = r; + ++sec->reloc_count; + + return true; +} + +/* Allocate a new link_order for a section. */ + +struct bfd_link_order * +bfd_new_link_order (abfd, section) + bfd *abfd; + asection *section; +{ + struct bfd_link_order *new; + + new = ((struct bfd_link_order *) + bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order))); + if (!new) + return NULL; + + new->type = bfd_undefined_link_order; + new->offset = 0; + new->size = 0; + new->next = (struct bfd_link_order *) NULL; + + if (section->link_order_tail != (struct bfd_link_order *) NULL) + section->link_order_tail->next = new; + else + section->link_order_head = new; + section->link_order_tail = new; + + return new; +} + +/* Default link order processing routine. Note that we can not handle + the reloc_link_order types here, since they depend upon the details + of how the particular backends generates relocs. */ + +boolean +_bfd_default_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + switch (link_order->type) + { + case bfd_undefined_link_order: + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + default: + abort (); + case bfd_indirect_link_order: + return default_indirect_link_order (abfd, info, sec, link_order, + false); + case bfd_fill_link_order: + return default_fill_link_order (abfd, info, sec, link_order); + case bfd_data_link_order: + return bfd_set_section_contents (abfd, sec, + (PTR) link_order->u.data.contents, + (file_ptr) link_order->offset, + link_order->size); + } +} + +/* Default routine to handle a bfd_fill_link_order. */ + +/*ARGSUSED*/ +static boolean +default_fill_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + size_t size; + char *space; + size_t i; + int fill; + boolean result; + + BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); + + size = (size_t) link_order->size; + space = (char *) bfd_malloc (size); + if (space == NULL && size != 0) + return false; + + fill = link_order->u.fill.value; + for (i = 0; i < size; i += 2) + space[i] = fill >> 8; + for (i = 1; i < size; i += 2) + space[i] = fill; + result = bfd_set_section_contents (abfd, sec, space, + (file_ptr) link_order->offset, + link_order->size); + free (space); + return result; +} + +/* Default routine to handle a bfd_indirect_link_order. */ + +static boolean +default_indirect_link_order (output_bfd, info, output_section, link_order, + generic_linker) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; + boolean generic_linker; +{ + asection *input_section; + bfd *input_bfd; + bfd_byte *contents = NULL; + bfd_byte *new_contents; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return true; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (input_section->_cooked_size == link_order->size); + + if (info->relocateable + && input_section->reloc_count > 0 + && output_section->orelocation == (arelent **) NULL) + { + /* Space has not been allocated for the output relocations. + This can happen when we are called by a specific backend + because somebody is attempting to link together different + types of object files. Handling this case correctly is + difficult, and sometimes impossible. */ + abort (); + } + + if (! generic_linker) + { + asymbol **sympp; + asymbol **symppend; + + /* Get the canonical symbols. The generic linker will always + have retrieved them by this point, but we are being called by + a specific linker, presumably because we are linking + different types of object files together. */ + if (! generic_link_read_symbols (input_bfd)) + return false; + + /* Since we have been called by a specific linker, rather than + the generic linker, the values of the symbols will not be + right. They will be the values as seen in the input file, + not the values of the final link. We need to fix them up + before we can relocate the section. */ + sympp = _bfd_generic_link_get_symbols (input_bfd); + symppend = sympp + _bfd_generic_link_get_symcount (input_bfd); + for (; sympp < symppend; sympp++) + { + asymbol *sym; + struct bfd_link_hash_entry *h; + + sym = *sympp; + + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_is_ind_section (bfd_get_section (sym))) + { + /* sym->udata may have been set by + generic_link_add_symbol_list. */ + if (sym->udata.p != NULL) + h = (struct bfd_link_hash_entry *) sym->udata.p; + else if (bfd_is_und_section (bfd_get_section (sym))) + h = bfd_wrapped_link_hash_lookup (output_bfd, info, + bfd_asymbol_name (sym), + false, false, true); + else + h = bfd_link_hash_lookup (info->hash, + bfd_asymbol_name (sym), + false, false, true); + if (h != NULL) + set_symbol_from_hash (sym, h); + } + } + } + + /* Get and relocate the section contents. */ + contents = ((bfd_byte *) + bfd_malloc (bfd_section_size (input_bfd, input_section))); + if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0) + goto error_return; + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, info->relocateable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + + /* Output the section contents. */ + if (! bfd_set_section_contents (output_bfd, output_section, + (PTR) new_contents, + link_order->offset, link_order->size)) + goto error_return; + + if (contents != NULL) + free (contents); + return true; + + error_return: + if (contents != NULL) + free (contents); + return false; +} + +/* A little routine to count the number of relocs in a link_order + list. */ + +unsigned int +_bfd_count_link_order_relocs (link_order) + struct bfd_link_order *link_order; +{ + register unsigned int c; + register struct bfd_link_order *l; + + c = 0; + for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next) + { + if (l->type == bfd_section_reloc_link_order + || l->type == bfd_symbol_reloc_link_order) + ++c; + } + + return c; +} + +/* +FUNCTION + bfd_link_split_section + +SYNOPSIS + boolean bfd_link_split_section(bfd *abfd, asection *sec); + +DESCRIPTION + Return nonzero if @var{sec} should be split during a + reloceatable or final link. + +.#define bfd_link_split_section(abfd, sec) \ +. BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) +. + +*/ + + + +boolean +_bfd_generic_link_split_section (abfd, sec) + bfd *abfd; + asection *sec; +{ + return false; +} diff --git a/contrib/gdb/bfd/lynx-core.c b/contrib/gdb/bfd/lynx-core.c new file mode 100644 index 000000000000..2358177dbc62 --- /dev/null +++ b/contrib/gdb/bfd/lynx-core.c @@ -0,0 +1,233 @@ +/* BFD back end for Lynx core files + Copyright 1993 Free Software Foundation, Inc. + Written by Stu Grossman of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifdef LYNX_CORE + +#include +#include +/* sys/kernel.h should define this, but doesn't always, sigh. */ +#ifndef __LYNXOS +#define __LYNXOS +#endif +#include +#include +#include +#include +#include +#include +#include + +/* These are stored in the bfd's tdata */ + +struct lynx_core_struct +{ + int sig; + char cmd[PNMLEN + 1]; +}; + +#define core_hdr(bfd) ((bfd)->tdata.lynx_core_data) +#define core_signal(bfd) (core_hdr(bfd)->sig) +#define core_command(bfd) (core_hdr(bfd)->cmd) + +/* Handle Lynx core dump file. */ + +static asection * +make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos) + bfd *abfd; + CONST char *name; + flagword flags; + bfd_size_type _raw_size; + bfd_vma vma; + file_ptr filepos; +{ + asection *asect; + char *newname; + + newname = bfd_alloc (abfd, strlen (name) + 1); + if (!newname) + return NULL; + + strcpy (newname, name); + + asect = bfd_make_section (abfd, newname); + if (!asect) + return NULL; + + asect->flags = flags; + asect->_raw_size = _raw_size; + asect->vma = vma; + asect->filepos = filepos; + asect->alignment_power = 2; + + return asect; +} + +/* ARGSUSED */ +const bfd_target * +lynx_core_file_p (abfd) + bfd *abfd; +{ + int val; + int secnum; + struct pssentry pss; + size_t tcontext_size; + core_st_t *threadp; + int pagesize; + asection *newsect; + + pagesize = getpagesize (); /* Serious cross-target issue here... This + really needs to come from a system-specific + header file. */ + + /* Get the pss entry from the core file */ + + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + return NULL; + + val = bfd_read ((void *)&pss, 1, sizeof pss, abfd); + if (val != sizeof pss) + { + /* Too small to be a core file */ + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + core_hdr (abfd) = (struct lynx_core_struct *) + bfd_zalloc (abfd, sizeof (struct lynx_core_struct)); + + if (!core_hdr (abfd)) + return NULL; + + strncpy (core_command (abfd), pss.pname, PNMLEN + 1); + + /* Compute the size of the thread contexts */ + + tcontext_size = pss.threadcnt * sizeof (core_st_t); + + /* Allocate space for the thread contexts */ + + threadp = (core_st_t *)bfd_alloc (abfd, tcontext_size); + if (!threadp) + return NULL; + + /* Save thread contexts */ + + if (bfd_seek (abfd, pagesize, SEEK_SET) != 0) + return NULL; + + val = bfd_read ((void *)threadp, pss.threadcnt, sizeof (core_st_t), abfd); + + if (val != tcontext_size) + { + /* Probably too small to be a core file */ + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + core_signal (abfd) = threadp->currsig; + + newsect = make_bfd_asection (abfd, ".stack", + SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS, + pss.ssize, + pss.slimit, + pagesize + tcontext_size); + if (!newsect) + return NULL; + + newsect = make_bfd_asection (abfd, ".data", + SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS, + pss.data_len + pss.bss_len, + pss.data_start, + pagesize + tcontext_size + pss.ssize +#if defined (SPARC) || defined (__SPARC__) + /* SPARC Lynx seems to start dumping + the .data section at a page + boundary. It's OK to check a + #define like SPARC here because this + file can only be compiled on a Lynx + host. */ + + pss.data_start % pagesize +#endif + ); + if (!newsect) + return NULL; + +/* And, now for the .reg/XXX pseudo sections. Each thread has it's own + .reg/XXX section, where XXX is the thread id (without leading zeros). The + currently running thread (at the time of the core dump) also has an alias + called `.reg' (just to keep GDB happy). Note that we use `.reg/XXX' as + opposed to `.regXXX' because GDB expects that .reg2 will be the floating- + point registers. */ + + newsect = make_bfd_asection (abfd, ".reg", + SEC_HAS_CONTENTS, + sizeof (core_st_t), + 0, + pagesize); + if (!newsect) + return NULL; + + for (secnum = 0; secnum < pss.threadcnt; secnum++) + { + char secname[100]; + + sprintf (secname, ".reg/%d", BUILDPID (0, threadp[secnum].tid)); + newsect = make_bfd_asection (abfd, secname, + SEC_HAS_CONTENTS, + sizeof (core_st_t), + 0, + pagesize + secnum * sizeof (core_st_t)); + if (!newsect) + return NULL; + } + + return abfd->xvec; +} + +char * +lynx_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_command (abfd); +} + +/* ARGSUSED */ +int +lynx_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_signal (abfd); +} + +/* ARGSUSED */ +boolean +lynx_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +#endif /* LYNX_CORE */ diff --git a/contrib/gdb/bfd/m68k4knetbsd.c b/contrib/gdb/bfd/m68k4knetbsd.c new file mode 100644 index 000000000000..c1ecb434425b --- /dev/null +++ b/contrib/gdb/bfd/m68k4knetbsd.c @@ -0,0 +1,35 @@ +/* BFD back-end for NetBSD/m68k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#define TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE 4096 + +#define DEFAULT_ARCH bfd_arch_m68k +#define MACHTYPE_OK(mtype) \ + ((mtype) == M_68020 || (mtype) == M_68K_NETBSD || (mtype) == M_68K4K_NETBSD \ + || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(m68k4knetbsd_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-m68k4k-netbsd" + +#include "netbsd.h" diff --git a/contrib/gdb/bfd/m68klinux.c b/contrib/gdb/bfd/m68klinux.c new file mode 100644 index 000000000000..062165b399b8 --- /dev/null +++ b/contrib/gdb/bfd/m68klinux.c @@ -0,0 +1,767 @@ +/* BFD back-end for linux flavored m68k a.out binaries. + Copyright (C) 1992, 93, 94, 95, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_PAGE_SIZE 4096 +#define ZMAGIC_DISK_BLOCK_SIZE 1024 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define TEXT_START_ADDR 0x0 +#define N_SHARED_LIB(x) 0 +#define BYTES_IN_WORD 4 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#define TARGET_IS_BIG_ENDIAN_P +#define DEFAULT_ARCH bfd_arch_m68k +#define MY(OP) CAT(m68klinux_,OP) +#define TARGETNAME "a.out-m68k-linux" + +extern const bfd_target MY(vec); + +/* We always generate QMAGIC files in preference to ZMAGIC files. It + would be possible to make this a linker option, if that ever + becomes important. */ + +static void MY_final_link_callback + PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *)); + +static boolean +m68klinux_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + obj_aout_subformat (abfd) = q_magic_format; + return NAME(aout,final_link) (abfd, info, MY_final_link_callback); +} + +#define MY_bfd_final_link m68klinux_bfd_final_link + +/* Set the machine type correctly. */ + +static boolean +m68klinux_write_object_contents (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + + N_SET_MACHTYPE (*execp, M_68020); + + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + WRITE_HEADERS(abfd, execp); + + return true; +} + +#define MY_write_object_contents m68klinux_write_object_contents + +/* Code to link against Linux a.out shared libraries. */ + +/* See if a symbol name is a reference to the global offset table. */ + +#ifndef GOT_REF_PREFIX +#define GOT_REF_PREFIX "__GOT_" +#endif + +#define IS_GOT_SYM(name) \ + (strncmp (name, GOT_REF_PREFIX, sizeof GOT_REF_PREFIX - 1) == 0) + +/* See if a symbol name is a reference to the procedure linkage table. */ + +#ifndef PLT_REF_PREFIX +#define PLT_REF_PREFIX "__PLT_" +#endif + +#define IS_PLT_SYM(name) \ + (strncmp (name, PLT_REF_PREFIX, sizeof PLT_REF_PREFIX - 1) == 0) + +/* This string is used to generate specialized error messages. */ + +#ifndef NEEDS_SHRLIB +#define NEEDS_SHRLIB "__NEEDS_SHRLIB_" +#endif + +/* This special symbol is a set vector that contains a list of + pointers to fixup tables. It will be present in any dynamicly + linked file. The linker generated fixup table should also be added + to the list, and it should always appear in the second slot (the + first one is a dummy with a magic number that is defined in + crt0.o). */ + +#ifndef SHARABLE_CONFLICTS +#define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__" +#endif + +/* We keep a list of fixups. The terminology is a bit strange, but + each fixup contains two 32 bit numbers. A regular fixup contains + an address and a pointer, and at runtime we should store the + address at the location pointed to by the pointer. A builtin fixup + contains two pointers, and we should read the address using one + pointer and store it at the location pointed to by the other + pointer. Builtin fixups come into play when we have duplicate + __GOT__ symbols for the same variable. The builtin fixup will copy + the GOT pointer from one over into the other. */ + +struct fixup +{ + struct fixup *next; + struct linux_link_hash_entry *h; + bfd_vma value; + + /* Nonzero if this is a jump instruction that needs to be fixed, + zero if this is just a pointer */ + char jump; + + char builtin; +}; + +/* We don't need a special hash table entry structure, but we do need + to keep some information between linker passes, so we use a special + hash table. */ + +struct linux_link_hash_entry +{ + struct aout_link_hash_entry root; +}; + +struct linux_link_hash_table +{ + struct aout_link_hash_table root; + + /* First dynamic object found in link. */ + bfd *dynobj; + + /* Number of fixups. */ + size_t fixup_count; + + /* Number of builtin fixups. */ + size_t local_builtins; + + /* List of fixups. */ + struct fixup *fixup_list; +}; + +static struct bfd_hash_entry *linux_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table *linux_link_hash_table_create + PARAMS ((bfd *)); +static struct fixup *new_fixup + PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *, + bfd_vma, int)); +static boolean linux_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean linux_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, + bfd_vma, const char *, boolean, boolean, + struct bfd_link_hash_entry **)); +static boolean linux_tally_symbols + PARAMS ((struct linux_link_hash_entry *, PTR)); +static boolean linux_finish_dynamic_link + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Routine to create an entry in an Linux link hash table. */ + +static struct bfd_hash_entry * +linux_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct linux_link_hash_entry *) NULL) + ret = ((struct linux_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); + if (ret == NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct linux_link_hash_entry *) + NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != NULL) + { + /* Set local fields; there aren't any. */ + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a Linux link hash table. */ + +static struct bfd_link_hash_table * +linux_link_hash_table_create (abfd) + bfd *abfd; +{ + struct linux_link_hash_table *ret; + + ret = ((struct linux_link_hash_table *) + bfd_alloc (abfd, sizeof (struct linux_link_hash_table))); + if (ret == (struct linux_link_hash_table *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_link_hash_table *) NULL; + } + if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, + linux_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + + ret->dynobj = NULL; + ret->fixup_count = 0; + ret->local_builtins = 0; + ret->fixup_list = NULL; + + return &ret->root.root; +} + +/* Look up an entry in a Linux link hash table. */ + +#define linux_link_hash_lookup(table, string, create, copy, follow) \ + ((struct linux_link_hash_entry *) \ + aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ + (follow))) + +/* Traverse a Linux link hash table. */ + +#define linux_link_hash_traverse(table, func, info) \ + (aout_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the Linux link hash table from the info structure. This is + just a cast. */ + +#define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash)) + +/* Store the information for a new fixup. */ + +static struct fixup * +new_fixup (info, h, value, builtin) + struct bfd_link_info *info; + struct linux_link_hash_entry *h; + bfd_vma value; + int builtin; +{ + struct fixup *f; + + f = (struct fixup *) bfd_hash_allocate (&info->hash->table, + sizeof (struct fixup)); + if (f == NULL) + return f; + f->next = linux_hash_table (info)->fixup_list; + linux_hash_table (info)->fixup_list = f; + f->h = h; + f->value = value; + f->builtin = builtin; + f->jump = 0; + ++linux_hash_table (info)->fixup_count; + return f; +} + +/* We come here once we realize that we are going to link to a shared + library. We need to create a special section that contains the + fixup table, and we ultimately need to add a pointer to this into + the set vector for SHARABLE_CONFLICTS. At this point we do not + know the size of the section, but that's OK - we just need to + create it for now. */ + +static boolean +linux_link_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + + /* Note that we set the SEC_IN_MEMORY flag. */ + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + /* We choose to use the name ".linux-dynamic" for the fixup table. + Why not? */ + s = bfd_make_section (abfd, ".linux-dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + s->_raw_size = 0; + s->contents = 0; + + return true; +} + +/* Function to add a single symbol to the linker hash table. This is + a wrapper around _bfd_generic_link_add_one_symbol which handles the + tweaking needed for dynamic linking support. */ + +static boolean +linux_add_one_symbol (info, abfd, name, flags, section, value, string, + copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + struct linux_link_hash_entry *h; + boolean insert; + + /* Look up and see if we already have this symbol in the hash table. + If we do, and the defining entry is from a shared library, we + need to create the dynamic sections. + + FIXME: What if abfd->xvec != info->hash->creator? We may want to + be able to link Linux a.out and ELF objects together, but serious + confusion is possible. */ + + insert = false; + + if (! info->relocateable + && linux_hash_table (info)->dynobj == NULL + && strcmp (name, SHARABLE_CONFLICTS) == 0 + && (flags & BSF_CONSTRUCTOR) != 0 + && abfd->xvec == info->hash->creator) + { + if (! linux_link_create_dynamic_sections (abfd, info)) + return false; + linux_hash_table (info)->dynobj = abfd; + insert = true; + } + + if (bfd_is_abs_section (section) + && abfd->xvec == info->hash->creator) + { + h = linux_link_hash_lookup (linux_hash_table (info), name, false, + false, false); + if (h != NULL + && (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak)) + { + struct fixup *f; + + if (hashp != NULL) + *hashp = (struct bfd_link_hash_entry *) h; + + f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); + if (f == NULL) + return false; + f->jump = IS_PLT_SYM (name); + + return true; + } + } + + /* Do the usual procedure for adding a symbol. */ + if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, + value, string, copy, collect, + hashp)) + return false; + + /* Insert a pointer to our table in the set vector. The dynamic + linker requires this information */ + if (insert) + { + asection *s; + + /* Here we do our special thing to add the pointer to the + dynamic section in the SHARABLE_CONFLICTS set vector. */ + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + BFD_ASSERT (s != NULL); + + if (! (_bfd_generic_link_add_one_symbol + (info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS, + BSF_GLOBAL | BSF_CONSTRUCTOR, s, 0, NULL, false, false, NULL))) + return false; + } + + return true; +} + +/* We will crawl the hash table and come here for every global symbol. + We will examine each entry and see if there are indications that we + need to add a fixup. There are two possible cases - one is where + you have duplicate definitions of PLT or GOT symbols - these will + have already been caught and added as "builtin" fixups. If we find + that the corresponding non PLT/GOT symbol is also present, we + convert it to a regular fixup instead. + + This function is called via linux_link_hash_traverse. */ + +static boolean +linux_tally_symbols (h, data) + struct linux_link_hash_entry *h; + PTR data; +{ + struct bfd_link_info *info = (struct bfd_link_info *) data; + struct fixup *f, *f1; + int is_plt; + struct linux_link_hash_entry *h1, *h2; + boolean exists; + + if (h->root.root.type == bfd_link_hash_undefined + && strncmp (h->root.root.root.string, NEEDS_SHRLIB, + sizeof NEEDS_SHRLIB - 1) == 0) + { + const char *name; + char *p; + char *alloc = NULL; + + name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1; + p = strrchr (name, '_'); + if (p != NULL) + alloc = (char *) bfd_malloc (strlen (name) + 1); + + if (p == NULL || alloc == NULL) + (*_bfd_error_handler) ("Output file requires shared library `%s'\n", + name); + else + { + strcpy (alloc, name); + p = strrchr (alloc, '_'); + *p++ = '\0'; + (*_bfd_error_handler) + ("Output file requires shared library `%s.so.%s'\n", + alloc, p); + free (alloc); + } + + abort (); + } + + /* If this symbol is not a PLT/GOT, we do not even need to look at it */ + is_plt = IS_PLT_SYM (h->root.root.root.string); + + if (is_plt || IS_GOT_SYM (h->root.root.root.string)) + { + /* Look up this symbol twice. Once just as a regular lookup, + and then again following all of the indirect links until we + reach a real symbol. */ + h1 = linux_link_hash_lookup (linux_hash_table (info), + (h->root.root.root.string + + sizeof PLT_REF_PREFIX - 1), + false, false, true); + /* h2 does not follow indirect symbols. */ + h2 = linux_link_hash_lookup (linux_hash_table (info), + (h->root.root.root.string + + sizeof PLT_REF_PREFIX - 1), + false, false, false); + + /* The real symbol must exist but if it is also an ABS symbol, + there is no need to have a fixup. This is because they both + came from the same library. If on the other hand, we had to + use an indirect symbol to get to the real symbol, we add the + fixup anyway, since there are cases where these symbols come + from different shared libraries */ + if (h1 != NULL + && (((h1->root.root.type == bfd_link_hash_defined + || h1->root.root.type == bfd_link_hash_defweak) + && ! bfd_is_abs_section (h1->root.root.u.def.section)) + || h2->root.root.type == bfd_link_hash_indirect)) + { + /* See if there is a "builtin" fixup already present + involving this symbol. If so, convert it to a regular + fixup. In the end, this relaxes some of the requirements + about the order of performing fixups. */ + exists = false; + for (f1 = linux_hash_table (info)->fixup_list; + f1 != NULL; + f1 = f1->next) + { + if ((f1->h != h && f1->h != h1) + || (! f1->builtin && ! f1->jump)) + continue; + if (f1->h == h1) + exists = true; + if (! exists + && bfd_is_abs_section (h->root.root.u.def.section)) + { + f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); + f->jump = is_plt; + } + f1->h = h1; + f1->jump = is_plt; + f1->builtin = 0; + exists = true; + } + if (! exists + && bfd_is_abs_section (h->root.root.u.def.section)) + { + f = new_fixup (info, h1, h->root.root.u.def.value, 0); + if (f == NULL) + { + /* FIXME: No way to return error. */ + abort (); + } + f->jump = is_plt; + } + } + + /* Quick and dirty way of stripping these symbols from the + symtab. */ + if (bfd_is_abs_section (h->root.root.u.def.section)) + h->root.written = true; + } + + return true; +} + +/* This is called to set the size of the .linux-dynamic section is. + It is called by the Linux linker emulation before_allocation + routine. We have finished reading all of the input files, and now + we just scan the hash tables to find out how many additional fixups + are required. */ + +boolean +bfd_m68klinux_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct fixup *f; + asection *s; + + if (output_bfd->xvec != &MY(vec)) + return true; + + /* First find the fixups... */ + linux_link_hash_traverse (linux_hash_table (info), + linux_tally_symbols, + (PTR) info); + + /* If there are builtin fixups, leave room for a marker. This is + used by the dynamic linker so that it knows that all that follow + are builtin fixups instead of regular fixups. */ + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (f->builtin) + { + ++linux_hash_table (info)->fixup_count; + ++linux_hash_table (info)->local_builtins; + break; + } + } + + if (linux_hash_table (info)->dynobj == NULL) + { + if (linux_hash_table (info)->fixup_count > 0) + abort (); + return true; + } + + /* Allocate memory for our fixup table. We will fill it in later. */ + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + if (s != NULL) + { + s->_raw_size = 8 + linux_hash_table (info)->fixup_count * 8; + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset (s->contents, 0, (size_t) s->_raw_size); + } + + return true; +} + +/* We come here once we are ready to actually write the fixup table to + the output file. Scan the fixup tables and so forth and generate + the stuff we need. */ + +static boolean +linux_finish_dynamic_link (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + asection *s, *os, *is; + bfd_byte *fixup_table; + struct linux_link_hash_entry *h; + struct fixup *f; + unsigned int new_addr; + int section_offset; + unsigned int fixups_written; + + if (linux_hash_table (info)->dynobj == NULL) + return true; + + s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, + ".linux-dynamic"); + BFD_ASSERT (s != NULL); + os = s->output_section; + fixups_written = 0; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup table file offset: %x VMA: %x\n", + os->filepos + s->output_offset, + os->vma + s->output_offset); +#endif + + fixup_table = s->contents; + bfd_put_32 (output_bfd, linux_hash_table (info)->fixup_count, fixup_table); + fixup_table += 4; + + /* Fill in fixup table. */ + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (f->builtin) + continue; + + if (f->h->root.root.type != bfd_link_hash_defined + && f->h->root.root.type != bfd_link_hash_defweak) + { + (*_bfd_error_handler) + ("Symbol %s not defined for fixups\n", + f->h->root.root.root.string); + continue; + } + + is = f->h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = f->h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, + new_addr, f->value); +#endif + + if (f->jump) + { + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value + 2, fixup_table); + fixup_table += 4; + } + else + { + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value, fixup_table); + fixup_table += 4; + } + ++fixups_written; + } + + if (linux_hash_table (info)->local_builtins != 0) + { + /* Special marker so we know to switch to the other type of fixup */ + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + ++fixups_written; + for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) + { + if (! f->builtin) + continue; + + if (f->h->root.root.type != bfd_link_hash_defined + && f->h->root.root.type != bfd_link_hash_defweak) + { + (*_bfd_error_handler) + ("Symbol %s not defined for fixups\n", + f->h->root.root.root.string); + continue; + } + + is = f->h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = f->h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, + new_addr, f->value); +#endif + + bfd_put_32 (output_bfd, new_addr, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, f->value, fixup_table); + fixup_table += 4; + ++fixups_written; + } + } + + if (linux_hash_table (info)->fixup_count != fixups_written) + { + (*_bfd_error_handler) ("Warning: fixup count mismatch\n"); + while (linux_hash_table (info)->fixup_count > fixups_written) + { + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + bfd_put_32 (output_bfd, 0, fixup_table); + fixup_table += 4; + ++fixups_written; + } + } + + h = linux_link_hash_lookup (linux_hash_table (info), + "__BUILTIN_FIXUPS__", + false, false, false); + + if (h != NULL + && (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak)) + { + is = h->root.root.u.def.section; + section_offset = is->output_section->vma + is->output_offset; + new_addr = h->root.root.u.def.value + section_offset; + +#ifdef LINUX_LINK_DEBUG + printf ("Builtin fixup table at %x\n", new_addr); +#endif + + bfd_put_32 (output_bfd, new_addr, fixup_table); + } + else + bfd_put_32 (output_bfd, 0, fixup_table); + + if (bfd_seek (output_bfd, os->filepos + s->output_offset, SEEK_SET) != 0) + return false; + + if (bfd_write ((PTR) s->contents, 1, s->_raw_size, output_bfd) + != s->_raw_size) + return false; + + return true; +} + +#define MY_bfd_link_hash_table_create linux_link_hash_table_create +#define MY_add_one_symbol linux_add_one_symbol +#define MY_finish_dynamic_link linux_finish_dynamic_link + +#define MY_zmagic_contiguous 1 + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/m68klynx.c b/contrib/gdb/bfd/m68klynx.c new file mode 100644 index 000000000000..7acdfbcad21d --- /dev/null +++ b/contrib/gdb/bfd/m68klynx.c @@ -0,0 +1,54 @@ +/* BFD back-end for m68k binaries under LynxOS. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#define N_SHARED_LIB(x) 0 + +#define TEXT_START_ADDR 0 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_m68k + +#define MY(OP) CAT(m68klynx_aout_,OP) +#define TARGETNAME "a.out-m68k-lynx" + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include "libaout.h" +#include "aout/aout64.h" + +#define TARGET_IS_BIG_ENDIAN_P + +#ifdef LYNX_CORE + +char *lynx_core_file_failing_command(); +int lynx_core_file_failing_signal(); +boolean lynx_core_file_matches_executable_p(); +const bfd_target *lynx_core_file_p(); + +#define MY_core_file_failing_command lynx_core_file_failing_command +#define MY_core_file_failing_signal lynx_core_file_failing_signal +#define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p +#define MY_core_file_p lynx_core_file_p + +#endif /* LYNX_CORE */ + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/m68knetbsd.c b/contrib/gdb/bfd/m68knetbsd.c new file mode 100644 index 000000000000..3bff530fbc72 --- /dev/null +++ b/contrib/gdb/bfd/m68knetbsd.c @@ -0,0 +1,35 @@ +/* BFD back-end for NetBSD/m68k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#define TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 8192 +#define SEGMENT_SIZE 8192 + +#define DEFAULT_ARCH bfd_arch_m68k +#define MACHTYPE_OK(mtype) \ + ((mtype) == M_68020 || (mtype) == M_68K_NETBSD || (mtype) == M_68K4K_NETBSD \ + || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(m68knetbsd_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-m68k-netbsd" + +#include "netbsd.h" diff --git a/contrib/gdb/bfd/m88kmach3.c b/contrib/gdb/bfd/m88kmach3.c new file mode 100644 index 000000000000..7a5640873008 --- /dev/null +++ b/contrib/gdb/bfd/m88kmach3.c @@ -0,0 +1,38 @@ +/* BFD back-end for Motorola m88k a.out (Mach 3) binaries. + Copyright (C) 1990, 1991, 1993, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_PAGE_SIZE (4096*2) +#define SEGMENT_SIZE 0x20000 +#define TEXT_START_ADDR 0 +#define BYTES_IN_WORD 4 +#define N_HEADER_IN_TEXT(x) 1 /* (N_MAGIG(x) == ZMAGIC) */ +#define N_SHARED_LIB(x) 0 + +#define N_TXTSIZE(x) ((x).a_text) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#define DEFAULT_ARCH bfd_arch_m88k +#define MY(OP) CAT(m88kmach3_,OP) +#define TARGETNAME "a.out-m88k-mach3" + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/makefile.dos b/contrib/gdb/bfd/makefile.dos new file mode 100644 index 000000000000..8a22c6af201f --- /dev/null +++ b/contrib/gdb/bfd/makefile.dos @@ -0,0 +1,49 @@ +CFLAGS=-O2 + +.c.o : + gcc $(CFLAGS) -I. -I../include -c $< + +all : libbfd.a + +targets.o : targets.c + gcc $(CFLAGS) -I. -I../include -DSELECT_VECS=&go32coff_vec,&i386aout_vec -DDEFAULT_VECTOR=go32coff_vec -c $*.c + +archures.o : archures.c + gcc $(CFLAGS) -I. -I../include -DSELECT_ARCHITECTURES=bfd_i386_arch -c $*.c + +OBJS = \ + libbfd.o \ + opncls.o \ + bfd.o \ + archive.o \ + targets.o \ + cache.o \ + archures.o \ + corefile.o \ + section.o \ + format.o \ + syms.o \ + reloc.o \ + init.o \ + coffgen.o \ + srec.o \ + hash.o \ + linker.o \ + ecoff.o \ + ecofflink.o \ + elf.o \ + aout32.o \ + stab-sym.o \ + i386aout.o \ + cpu-i386.o \ + coff-go32.o \ + cofflink.o \ + elf32.o \ + binary.o \ + tekhex.o \ + $E + +libbfd.a : $(OBJS) + -rm libbfd.a + ar rvs libbfd.a $(OBJS) + ranlib libbfd.a diff --git a/contrib/gdb/bfd/mipsbsd.c b/contrib/gdb/bfd/mipsbsd.c new file mode 100644 index 000000000000..801f3604338e --- /dev/null +++ b/contrib/gdb/bfd/mipsbsd.c @@ -0,0 +1,467 @@ +/* BFD backend for MIPS BSD (a.out) binaries. + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Ralph Campbell. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +/* #define ENTRY_CAN_BE_ZERO */ +#define N_HEADER_IN_TEXT(x) 1 +#define N_SHARED_LIB(x) 0 +#define N_TXTADDR(x) \ + (N_MAGIC(x) != ZMAGIC ? (x).a_entry : /* object file or NMAGIC */\ + TEXT_START_ADDR + EXEC_BYTES_SIZE /* no padding */\ + ) +#define N_DATADDR(x) (N_TXTADDR(x)+N_TXTSIZE(x)) +#define TEXT_START_ADDR 4096 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_mips +#define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \ + || (mtype) == M_MIPS1 || (mtype) == M_MIPS2) +#define MY_symbol_leading_char '\0' + +#define MY(OP) CAT(mipsbsd_,OP) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#define SET_ARCH_MACH(ABFD, EXEC) \ + MY(set_arch_mach)(ABFD, N_MACHTYPE (EXEC)); \ + MY(choose_reloc_size)(ABFD); +void MY(set_arch_mach) PARAMS ((bfd *abfd, int machtype)); +static void MY(choose_reloc_size) PARAMS ((bfd *abfd)); + +#define MY_write_object_contents MY(write_object_contents) +static boolean MY(write_object_contents) PARAMS ((bfd *abfd)); + +/* We can't use MY(x) here because it leads to a recursive call to CAT + when expanded inside JUMP_TABLE. */ +#define MY_bfd_reloc_type_lookup mipsbsd_reloc_howto_type_lookup +#define MY_canonicalize_reloc mipsbsd_canonicalize_reloc + +#define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define MY_final_link_callback unused +#define MY_bfd_final_link _bfd_generic_final_link + +#define MY_backend_data &MY(backend_data) +#define MY_BFD_TARGET + +#include "aout-target.h" + +void +MY(set_arch_mach) (abfd, machtype) + bfd *abfd; + int machtype; +{ + enum bfd_architecture arch; + long machine; + + /* Determine the architecture and machine type of the object file. */ + switch (machtype) { + + case M_MIPS1: + arch = bfd_arch_mips; + machine = 3000; + break; + + case M_MIPS2: + arch = bfd_arch_mips; + machine = 4000; + break; + + default: + arch = bfd_arch_obscure; + machine = 0; + break; + } + bfd_set_arch_mach(abfd, arch, machine); +} + +/* Determine the size of a relocation entry, based on the architecture */ +static void +MY(choose_reloc_size) (abfd) + bfd *abfd; +{ + switch (bfd_get_arch(abfd)) { + case bfd_arch_sparc: + case bfd_arch_a29k: + case bfd_arch_mips: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } +} + +/* Write an object file in BSD a.out format. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +static boolean +MY(write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + + /* Magic number, maestro, please! */ + switch (bfd_get_arch(abfd)) { + case bfd_arch_m68k: + switch (bfd_get_mach(abfd)) { + case 68010: + N_SET_MACHTYPE(*execp, M_68010); + break; + default: + case 68020: + N_SET_MACHTYPE(*execp, M_68020); + break; + } + break; + case bfd_arch_sparc: + N_SET_MACHTYPE(*execp, M_SPARC); + break; + case bfd_arch_i386: + N_SET_MACHTYPE(*execp, M_386); + break; + case bfd_arch_a29k: + N_SET_MACHTYPE(*execp, M_29K); + break; + case bfd_arch_mips: + switch (bfd_get_mach(abfd)) { + case 4000: + case 6000: + N_SET_MACHTYPE(*execp, M_MIPS2); + break; + default: + N_SET_MACHTYPE(*execp, M_MIPS1); + break; + } + break; + default: + N_SET_MACHTYPE(*execp, M_UNKNOWN); + } + + MY(choose_reloc_size)(abfd); + + WRITE_HEADERS(abfd, execp); + + return true; +} + +/* + * MIPS relocation types. + */ +#define MIPS_RELOC_32 0 +#define MIPS_RELOC_JMP 1 +#define MIPS_RELOC_WDISP16 2 +#define MIPS_RELOC_HI16 3 +#define MIPS_RELOC_HI16_S 4 +#define MIPS_RELOC_LO16 5 + +/* + * This is only called when performing a BFD_RELOC_MIPS_JMP relocation. + * The jump destination address is formed from the upper 4 bits of the + * "current" program counter concatenated with the jump instruction's + * 26 bit field and two trailing zeros. + * If the destination address is not in the same segment as the "current" + * program counter, then we need to signal an error. + */ +static bfd_reloc_status_type +mips_fix_jmp_addr (abfd,reloc_entry,symbol,data,input_section,output_bfd) + bfd *abfd; + arelent *reloc_entry; + struct symbol_cache_entry *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; +{ + bfd_vma relocation, pc; + + /* If this is a partial relocation, just continue. */ + if (output_bfd != (bfd *)NULL) + return bfd_reloc_continue; + + /* If this is an undefined symbol, return error */ + if (bfd_is_und_section (symbol->section) + && (symbol->flags & BSF_WEAK) == 0) + return bfd_reloc_undefined; + + /* + * Work out which section the relocation is targetted at and the + * initial relocation command value. + */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + pc = input_section->output_section->vma + input_section->output_offset + + reloc_entry->address + 4; + + if ((relocation & 0xF0000000) != (pc & 0xF0000000)) + return bfd_reloc_overflow; + + return bfd_reloc_continue; +} + +/* + * This is only called when performing a BFD_RELOC_HI16_S relocation. + * We need to see if bit 15 is set in the result. If it is, we add + * 0x10000 and continue normally. This will compensate for the sign extension + * when the low bits are added at run time. + */ +static bfd_reloc_status_type +mips_fix_hi16_s PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +mips_fix_hi16_s (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + + /* If this is a partial relocation, just continue. */ + if (output_bfd != (bfd *)NULL) + return bfd_reloc_continue; + + /* If this is an undefined symbol, return error */ + if (bfd_is_und_section (symbol->section) + && (symbol->flags & BSF_WEAK) == 0) + return bfd_reloc_undefined; + + /* + * Work out which section the relocation is targetted at and the + * initial relocation command value. + */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + + if (relocation & 0x8000) + reloc_entry->addend += 0x10000; + + return bfd_reloc_continue; +} + +static reloc_howto_type mips_howto_table_ext[] = { + {MIPS_RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, + "32", false, 0, 0xffffffff, false}, + {MIPS_RELOC_JMP, 2, 2, 26, false, 0, complain_overflow_dont, + mips_fix_jmp_addr, + "MIPS_JMP", false, 0, 0x03ffffff, false}, + {MIPS_RELOC_WDISP16, 2, 2, 16, true, 0, complain_overflow_signed, 0, + "WDISP16", false, 0, 0x0000ffff, false}, + {MIPS_RELOC_HI16, 16, 2, 16, false, 0, complain_overflow_bitfield, 0, + "HI16", false, 0, 0x0000ffff, false}, + {MIPS_RELOC_HI16_S, 16, 2, 16, false, 0, complain_overflow_bitfield, + mips_fix_hi16_s, + "HI16_S", false, 0, 0x0000ffff, false}, + {MIPS_RELOC_LO16, 0, 2, 16, false, 0, complain_overflow_dont, 0, + "LO16", false, 0, 0x0000ffff, false}, +}; + +static reloc_howto_type * +MY(reloc_howto_type_lookup) (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + + if (bfd_get_arch (abfd) != bfd_arch_mips) + return 0; + + switch (code) + { + case BFD_RELOC_CTOR: + case BFD_RELOC_32: + return (&mips_howto_table_ext[MIPS_RELOC_32]); + case BFD_RELOC_MIPS_JMP: + return (&mips_howto_table_ext[MIPS_RELOC_JMP]); + case BFD_RELOC_16_PCREL_S2: + return (&mips_howto_table_ext[MIPS_RELOC_WDISP16]); + case BFD_RELOC_HI16: + return (&mips_howto_table_ext[MIPS_RELOC_HI16]); + case BFD_RELOC_HI16_S: + return (&mips_howto_table_ext[MIPS_RELOC_HI16_S]); + case BFD_RELOC_LO16: + return (&mips_howto_table_ext[MIPS_RELOC_LO16]); + default: + return 0; + } +} + +/* + * This is just like the standard aoutx.h version but we need to do our + * own mapping of external reloc type values to howto entries. + */ +long +MY(canonicalize_reloc)(abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count, c; + extern reloc_howto_type NAME(aout,ext_howto_table)[]; + + /* If we have already read in the relocation table, return the values. */ + if (section->flags & SEC_CONSTRUCTOR) { + arelent_chain *chain = section->constructor_chain; + + for (count = 0; count < section->reloc_count; count++) { + *relptr++ = &chain->relent; + chain = chain->next; + } + *relptr = 0; + return section->reloc_count; + } + if (tblptr && section->reloc_count) { + for (count = 0; count++ < section->reloc_count;) + *relptr++ = tblptr++; + *relptr = 0; + return section->reloc_count; + } + + if (!NAME(aout,slurp_reloc_table)(abfd, section, symbols)) + return -1; + tblptr = section->relocation; + + /* fix up howto entries */ + for (count = 0; count++ < section->reloc_count;) + { + c = tblptr->howto - NAME(aout,ext_howto_table); + tblptr->howto = &mips_howto_table_ext[c]; + + *relptr++ = tblptr++; + } + *relptr = 0; + return section->reloc_count; +} + +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 1, /* text incl header */ + 0, /* exec_hdr_flags */ + TARGET_PAGE_SIZE, /* text vma */ + MY_set_sizes, + 0, /* text size includes exec header */ + 0, /* add_dynamic_symbols */ + 0, /* add_one_symbol */ + 0, /* link_dynamic_object */ + 0, /* write_dynamic_symbol */ + 0, /* check_dynamic_reloc */ + 0 /* finish_dynamic_link */ +}; + +const bfd_target aout_mips_little_vec = +{ + "a.out-mips-little", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_LITTLE, /* target byte order (little) */ + BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (MY), + BFD_JUMP_TABLE_COPY (MY), + BFD_JUMP_TABLE_CORE (MY), + BFD_JUMP_TABLE_ARCHIVE (MY), + BFD_JUMP_TABLE_SYMBOLS (MY), + BFD_JUMP_TABLE_RELOCS (MY), + BFD_JUMP_TABLE_WRITE (MY), + BFD_JUMP_TABLE_LINK (MY), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) MY_backend_data, +}; + +const bfd_target aout_mips_big_vec = +{ + "a.out-mips-big", /* name */ + bfd_target_aout_flavour, + BFD_ENDIAN_BIG, /* target byte order (big) */ + BFD_ENDIAN_BIG, /* target headers byte order (big) */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + ' ', /* ar_pad_char */ + 15, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (MY), + BFD_JUMP_TABLE_COPY (MY), + BFD_JUMP_TABLE_CORE (MY), + BFD_JUMP_TABLE_ARCHIVE (MY), + BFD_JUMP_TABLE_SYMBOLS (MY), + BFD_JUMP_TABLE_RELOCS (MY), + BFD_JUMP_TABLE_WRITE (MY), + BFD_JUMP_TABLE_LINK (MY), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) MY_backend_data, +}; diff --git a/contrib/gdb/bfd/mpw-config.in b/contrib/gdb/bfd/mpw-config.in new file mode 100644 index 000000000000..9195d0e64547 --- /dev/null +++ b/contrib/gdb/bfd/mpw-config.in @@ -0,0 +1,73 @@ +# Configuration fragment for BFD. + +# This is almost always correct. + +Set selarchs "&bfd_{target_cpu}_arch" +Set defvec "" +Set selvecs "" + +If "{target_canonical}" =~ /m68k-apple-macos/ + Set BFD_BACKENDS '"{o}"coff-m68k.c.o "{o}"cofflink.c.o' + Set defvec m68kcoff_vec + Set selvecs '&m68kcoff_vec' + +Else If "{target_canonical}" =~ /powerpc-apple-macos/ + Set BFD_BACKENDS '"{o}"coff-pmac.c.o "{o}"xcofflink.c.o' + Set defvec pmac_xcoff_vec + Set selvecs '&pmac_xcoff_vec' + Set selarchs "&bfd_powerpc_arch" + +Else If "{target_canonical}" =~ /i386-unknown-go32/ + Set BFD_BACKENDS '"{o}"coff-i386.c.o' + Set defvec i386coff_vec + Set selvecs '&i386coff_vec' + +Else If "{target_canonical}" =~ /mips-\Option-x-\Option-x/ + Set BFD_BACKENDS '"{o}"coff-mips.c.o "{o}"ecoff.c.o "{o}"ecofflink.c.o' + Set defvec ecoff_big_vec + Set selvecs '&ecoff_big_vec,&ecoff_little_vec' + +Else If "{target_canonical}" =~ /sh-hitachi-hms/ + Set BFD_BACKENDS '"{o}"coff-sh.c.o "{o}"cofflink.c.o' + Set defvec shcoff_vec + Set selvecs '&shcoff_vec,&shlcoff_vec' +End If + +Set ta `echo {selarchs} | sed -e 's/&bfd_/{o}cpu-/g' -e 's/_arch/.c.o/g'` + +Set tdefaults "-d DEFAULT_VECTOR={defvec} -d SELECT_VECS={selvecs} -d SELECT_ARCHITECTURES={selarchs}" + +Echo '# From mpw-config.in' > "{o}"mk.tmp +Echo 'WORDSIZE = 32' >> "{o}"mk.tmp +Echo 'BFD_MACHINES = ' {ta} >> "{o}"mk.tmp +Echo 'BFD_BACKENDS = ' {BFD_BACKENDS} >> "{o}"mk.tmp +Echo 'TDEFAULTS = ' {tdefaults} >> "{o}"mk.tmp +Echo 'HDEPFILES = ' >> "{o}"mk.tmp +Echo 'TDEPFILES = ' >> "{o}"mk.tmp +Echo '# End from mpw-config.in' >> "{o}"mk.tmp + +Echo '/* config.h. Generated by mpw-configure. */' > "{o}"config.new +Echo '#include "mpw.h"' >> "{o}"config.new + +MoveIfChange "{o}"config.new "{o}"config.h + +# We can only handle 32-bit targets right now. + +sed -e 's/@WORDSIZE@/32/' \Option-d + -e "s/@VERSION@/`Catenate {srcdir}VERSION`/" \Option-d + -e 's/@BFD_HOST_64BIT_LONG@/0/' \Option-d + "{srcdir}"bfd-in2.h >"{o}"bfd.h-new + +MoveIfChange "{o}"bfd.h-new "{o}"bfd.h + +# Pre-expand some macros in coffswap.h, so MPW C doesn't choke. + +sed -e 's/^ PUT_AOUTHDR_TSIZE (/ bfd_h_put_32 (/' \Option-d + -e 's/^ PUT_AOUTHDR_DSIZE (/ bfd_h_put_32 (/' \Option-d + -e 's/^ PUT_AOUTHDR_BSIZE (/ bfd_h_put_32 (/' \Option-d + -e 's/^ PUT_AOUTHDR_ENTRY (/ bfd_h_put_32 (/' \Option-d + -e 's/^ PUT_AOUTHDR_TEXT_START (/ bfd_h_put_32 (/' \Option-d + -e 's/^ PUT_AOUTHDR_DATA_START (/ bfd_h_put_32 (/' \Option-d + "{srcdir}"coffswap.h >"{o}"coffswap.h-new + +MoveIfChange "{o}"coffswap.h-new "{o}"coffswap.h diff --git a/contrib/gdb/bfd/mpw-make.sed b/contrib/gdb/bfd/mpw-make.sed new file mode 100644 index 000000000000..a989ef005ff2 --- /dev/null +++ b/contrib/gdb/bfd/mpw-make.sed @@ -0,0 +1,70 @@ +# Sed commands to finish translating the Unix BFD Makefile into MPW syntax. + +# Whack out unused host and target define bits. +/HDEFINES/s/@HDEFINES@// +/TDEFINES/s/@TDEFINES@// + +/INCDIR=/s/"{srcdir}":/"{topsrcdir}"/ +/^CSEARCH = .*$/s/$/ -i "{INCDIR}":mpw: -i ::extra-include:/ + +/WORDSIZE/s/^WORDSIZE = /#WORDSIZE = / +/BFD_MACHINES/s/^BFD_MACHINES = /#BFD_MACHINES = / +/BFD_BACKENDS/s/^BFD_BACKENDS = /#BFD_BACKENDS = / +/TDEFAULTS/s/^TDEFAULTS = /#TDEFAULTS = / + +# Remove extra, useless, "all". +/^all \\Option-f _oldest/,/^$/d + +# Remove the Makefile rebuild rule. +/^Makefile /,/--recheck/d + +# Don't do any recursive subdir stuff. +/ subdir_do/s/{MAKE}/null-command/ + +/BFD_H/s/^{BFD_H}/#{BFD_H}/ + +# Point at include files that are always in the objdir. +/bfd/s/"{s}"bfd\.h/"{o}"bfd.h/g +/config/s/"{s}"config\.h/"{o}"config.h/g +/elf32-target/s/"{s}"elf32-target\.h/"{o}"elf32-target.h/g +/elf64-target/s/"{s}"elf64-target\.h/"{o}"elf64-target.h/g + +/"{s}"{INCDIR}/s/"{s}"{INCDIR}/"{INCDIR}"/g + +/dep/s/\.dep/__dep/g + +# Removing duplicates is cool but presently unnecessary, +# so whack this out. +/^ofiles \\Option-f/,/^$/d +/ofiles/s/{OFILES} ofiles/{OFILES}/ +/echo ofiles = /d +/cat ofiles/s/`cat ofiles`/{OFILES}/ + +# No corefile support. +/COREFILE/s/@COREFILE@// +/COREFLAG/s/@COREFLAG@// + +# No PIC foolery in this environment. +/@ALLLIBS@/s/@ALLLIBS@/{TARGETLIB}/ +/@PICLIST@/s/@PICLIST@// +/@PICFLAG@/s/@PICFLAG@// +/^{OFILES} \\Option-f stamp-picdir/,/^$/d + +# Remove the pic trickery from the default build rule. +/^\.c\.o \\Option-f /,/End If/c\ +.c.o \\Option-f .c + +# MPW Make doesn't know about $<. +/"{o}"targets.c.o \\Option-f "{s}"targets.c Makefile/,/^$/c\ +"{o}"targets.c.o \\Option-f "{s}"targets.c Makefile\ + {CC} {ALL_CFLAGS} {TDEFAULTS} "{s}"targets.c -o "{o}"targets.c.o + +/"{o}"archures.c.o \\Option-f "{s}"archures.c Makefile/,/^$/c\ +"{o}"archures.c.o \\Option-f "{s}"archures.c Makefile\ + {CC} {ALL_CFLAGS} {TDEFAULTS} "{s}"archures.c -o "{o}"archures.c.o + +# Remove the .h rebuilding rules, we don't currently have a doc subdir, +# or a way to build the prototype-hacking tool that's in it. +/^"{srcdir}"bfd-in2.h \\Option-f /,/^$/d +/^"{srcdir}"libbfd.h \\Option-f /,/^$/d +/^"{srcdir}"libcoff.h \\Option-f /,/^$/d diff --git a/contrib/gdb/bfd/netbsd-core.c b/contrib/gdb/bfd/netbsd-core.c new file mode 100644 index 000000000000..4e8286797963 --- /dev/null +++ b/contrib/gdb/bfd/netbsd-core.c @@ -0,0 +1,310 @@ +/* BFD back end for NetBSD style core files + Copyright 1988, 1989, 1991, 1992, 1993, 1996 Free Software Foundation, Inc. + Written by Paul Kranenburg, EUR + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * FIXME: On NetBSD/sparc CORE_FPU_OFFSET should be (sizeof(struct trapframe)) + */ + +struct netbsd_core_struct { + struct core core; +} *rawptr; + +/* forward declarations */ + +static const bfd_target * netbsd_core_core_file_p PARAMS ((bfd *abfd)); +static char * netbsd_core_core_file_failing_command PARAMS ((bfd *abfd)); +static int netbsd_core_core_file_failing_signal PARAMS ((bfd *abfd)); +static boolean netbsd_core_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Handle NetBSD-style core dump file. */ + +/* ARGSUSED */ +static const bfd_target * +netbsd_core_core_file_p (abfd) + bfd *abfd; + +{ + int i, val, offset; + asection *asect, *asect2; + struct core core; + struct coreseg coreseg; + + val = bfd_read ((void *)&core, 1, sizeof core, abfd); + if (val != sizeof core) { + /* Too small to be a core file */ + bfd_set_error(bfd_error_wrong_format); + return 0; + } + + if (CORE_GETMAGIC(core) != COREMAGIC) { + bfd_set_error(bfd_error_wrong_format); + return 0; + } + + rawptr = (struct netbsd_core_struct *) + bfd_zalloc (abfd, sizeof (struct netbsd_core_struct)); + if (rawptr == NULL) { + bfd_set_error(bfd_error_no_memory); + return 0; + } + + rawptr->core = core; + abfd->tdata.netbsd_core_data = rawptr; + + offset = core.c_hdrsize; + for (i = 0; i < core.c_nseg; i++) { + + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + goto punt; + + val = bfd_read ((void *)&coreseg, 1, sizeof coreseg, abfd); + if (val != sizeof coreseg) { + bfd_set_error(bfd_error_file_truncated); + goto punt; + } + if (CORE_GETMAGIC(coreseg) != CORESEGMAGIC) { + bfd_set_error(bfd_error_wrong_format); + goto punt; + } + + offset += core.c_seghdrsize; + + asect = (asection *) bfd_zalloc (abfd, sizeof(asection)); + if (asect == NULL) { + bfd_set_error(bfd_error_no_memory); + } + + asect->_raw_size = coreseg.c_size; + asect->vma = coreseg.c_addr; + asect->filepos = offset; + asect->alignment_power = 2; + asect->next = abfd->sections; + abfd->sections = asect; + abfd->section_count++; + offset += coreseg.c_size; + + switch (CORE_GETFLAG(coreseg)) { + case CORE_CPU: + asect->name = ".reg"; + asect->flags = SEC_ALLOC + SEC_HAS_CONTENTS; +#ifdef CORE_FPU_OFFSET + /* Hackish... */ + asect->_raw_size = CORE_FPU_OFFSET; + asect2 = (asection *)bfd_zalloc (abfd, + sizeof (asection)); + if (asect2 == NULL) { + bfd_set_error(bfd_error_no_memory); + goto punt; + } + asect2->_raw_size = coreseg.c_size - CORE_FPU_OFFSET; + asect2->vma = 0; + asect2->filepos = asect->filepos + CORE_FPU_OFFSET; + asect2->alignment_power = 2; + asect2->next = abfd->sections; + asect2->name = ".reg2"; + asect2->flags = SEC_ALLOC + SEC_HAS_CONTENTS; + abfd->sections = asect2; + abfd->section_count++; +#endif + + break; + case CORE_DATA: + asect->name = ".data"; + asect->flags = SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS; + break; + case CORE_STACK: + asect->name = ".stack"; + asect->flags = SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS; + break; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + return abfd->xvec; + +punt: { + asection *anext; + for (asect = abfd->sections; asect; asect = anext) { + anext = asect->next; + free((void *)asect); + } + } + free ((void *)rawptr); + abfd->tdata.netbsd_core_data = NULL; + abfd->sections = NULL; + abfd->section_count = 0; + return 0; +} + +static char* +netbsd_core_core_file_failing_command (abfd) + bfd *abfd; +{ + /*return core_command (abfd);*/ + return abfd->tdata.netbsd_core_data->core.c_name; +} + +/* ARGSUSED */ +static int +netbsd_core_core_file_failing_signal (abfd) + bfd *abfd; +{ + /*return core_signal (abfd);*/ + return abfd->tdata.netbsd_core_data->core.c_signo; +} + +/* ARGSUSED */ +static boolean +netbsd_core_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +/* No archive file support via this BFD */ +#define netbsd_openr_next_archived_file bfd_generic_openr_next_archived_file +#define netbsd_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define netbsd_slurp_armap bfd_false +#define netbsd_slurp_extended_name_table bfd_true +#define netbsd_write_armap (boolean (*) PARAMS \ + ((bfd *arch, unsigned int elength, struct orl *map, \ + unsigned int orl_count, int stridx))) bfd_false +#define netbsd_truncate_arname bfd_dont_truncate_arname +#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file + +#define netbsd_close_and_cleanup bfd_generic_close_and_cleanup +#define netbsd_set_section_contents (boolean (*) PARAMS \ + ((bfd *abfd, asection *section, PTR data, file_ptr offset, \ + bfd_size_type count))) bfd_false +#define netbsd_get_section_contents bfd_generic_get_section_contents +#define netbsd_new_section_hook (boolean (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_true +#define netbsd_get_symtab_upper_bound bfd_0u +#define netbsd_get_symtab (unsigned int (*) PARAMS \ + ((bfd *, struct symbol_cache_entry **))) bfd_0u +#define netbsd_get_reloc_upper_bound (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_0u +#define netbsd_canonicalize_reloc (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u +#define netbsd_make_empty_symbol (struct symbol_cache_entry * \ + (*) PARAMS ((bfd *))) bfd_false +#define netbsd_print_symbol (void (*) PARAMS \ + ((bfd *, PTR, struct symbol_cache_entry *, \ + bfd_print_symbol_type))) bfd_false +#define netbsd_get_symbol_info (void (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *, \ + symbol_info *))) bfd_false +#define netbsd_get_lineno (alent * (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr +#define netbsd_set_arch_mach (boolean (*) PARAMS \ + ((bfd *, enum bfd_architecture, unsigned long))) bfd_false +#define netbsd_find_nearest_line (boolean (*) PARAMS \ + ((bfd *abfd, struct sec *section, \ + struct symbol_cache_entry **symbols,bfd_vma offset, \ + CONST char **file, CONST char **func, unsigned int *line))) bfd_false +#define netbsd_sizeof_headers (int (*) PARAMS \ + ((bfd *, boolean))) bfd_0 + +#define netbsd_bfd_debug_info_start bfd_void +#define netbsd_bfd_debug_info_end bfd_void +#define netbsd_bfd_debug_info_accumulate (void (*) PARAMS \ + ((bfd *, struct sec *))) bfd_void +#define netbsd_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define netbsd_bfd_relax_section bfd_generic_relax_section +#define netbsd_bfd_seclet_link \ + ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false) +#define netbsd_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define netbsd_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* If somebody calls any byte-swapping routines, shoot them. */ +static void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) + +const bfd_target netbsd_core_vec = + { + "netbsd-core", + bfd_target_unknown_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 3, /* minimum alignment power */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + netbsd_core_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (netbsd_core), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; diff --git a/contrib/gdb/bfd/netbsd.h b/contrib/gdb/bfd/netbsd.h new file mode 100644 index 000000000000..dd73d37e789b --- /dev/null +++ b/contrib/gdb/bfd/netbsd.h @@ -0,0 +1,108 @@ +/* BFD back-end definitions used by all NetBSD targets. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* NetBSD fits its header into the start of its text segment */ +#define N_HEADER_IN_TEXT(x) 1 +#define TEXT_START_ADDR TARGET_PAGE_SIZE + +#define N_MACHTYPE(exec) \ + ((enum machine_type)(((exec).a_info >> 16) & 0x03ff)) +#define N_FLAGS(exec) \ + (((exec).a_info >> 26) & 0x3f) + +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0x3ff) << 16) \ + | (((flags) & 0x3f) << 24)) +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info & 0xfb00ffff) | ((((int)(machtype))&0x3ff) << 16)) +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info & 0x03ffffff) | ((flags & 0x03f) << 26)) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +/* On NetBSD, the magic number is always in ntohl's "network" (big-endian) + format. */ +#define SWAP_MAGIC(ext) bfd_getb32 (ext) + + +#define MY_write_object_contents MY(write_object_contents) +static boolean MY(write_object_contents) PARAMS ((bfd *abfd)); +#define MY_text_includes_header 1 + +#include "aout-target.h" + +/* Write an object file. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +static boolean +MY(write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + /* Magic number, maestro, please! */ + switch (bfd_get_arch(abfd)) { + case bfd_arch_m68k: + if (strcmp (abfd->xvec->name, "a.out-m68k4k-netbsd") == 0) + N_SET_MACHTYPE(*execp, M_68K4K_NETBSD); + else + N_SET_MACHTYPE(*execp, M_68K_NETBSD); + break; + case bfd_arch_sparc: + N_SET_MACHTYPE(*execp, M_SPARC_NETBSD); + break; + case bfd_arch_i386: + N_SET_MACHTYPE(*execp, M_386_NETBSD); + break; + case bfd_arch_ns32k: + N_SET_MACHTYPE(*execp, M_532_NETBSD); + break; + default: + N_SET_MACHTYPE(*execp, M_UNKNOWN); + break; + } + + /* The NetBSD magic number is always big-endian */ +#ifndef TARGET_IS_BIG_ENDIAN_P + /* XXX aren't there any macro to change byteorder of a word independent of + the host's or target's endianesses? */ + execp->a_info + = (execp->a_info & 0xff) << 24 | (execp->a_info & 0xff00) << 8 + | (execp->a_info & 0xff0000) >> 8 | (execp->a_info & 0xff000000) >> 24; +#endif + + WRITE_HEADERS(abfd, execp); + + return true; +} diff --git a/contrib/gdb/bfd/newsos3.c b/contrib/gdb/bfd/newsos3.c new file mode 100644 index 000000000000..7ec7a75a87c0 --- /dev/null +++ b/contrib/gdb/bfd/newsos3.c @@ -0,0 +1,40 @@ +/* BFD back-end for NewsOS3 (Sony, 68k) binaries. + Copyright (C) 1990, 91, 92, 93, 94 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define TEXT_START_ADDR 0 +#define BYTES_IN_WORD 4 +#define MY(OP) CAT(newsos3_,OP) +#define TARGETNAME "a.out-newsos3" +#define ENTRY_CAN_BE_ZERO +#define N_SHARED_LIB(x) 0 /* Avoids warning when compiled with -Wall. */ +#define DEFAULT_ARCH bfd_arch_m68k +#define TARGET_IS_BIG_ENDIAN_P +#define N_HEADER_IN_TEXT(x) 0 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/nlm-target.h b/contrib/gdb/bfd/nlm-target.h new file mode 100644 index 000000000000..cdd3fa8b22e6 --- /dev/null +++ b/contrib/gdb/bfd/nlm-target.h @@ -0,0 +1,228 @@ +/* Target definitions for 32/64-bit NLM (NetWare Loadable Module) + Copyright (C) 1993, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define nlm_core_file_p _bfd_dummy_target + +#define nlm_get_symtab_upper_bound nlmNAME(get_symtab_upper_bound) +#define nlm_get_symtab nlmNAME(get_symtab) +#define nlm_make_empty_symbol nlmNAME(make_empty_symbol) +#define nlm_print_symbol nlmNAME(print_symbol) +#define nlm_get_symbol_info nlmNAME(get_symbol_info) +#define nlm_bfd_is_local_label bfd_generic_is_local_label +#define nlm_get_lineno _bfd_nosymbols_get_lineno +#define nlm_find_nearest_line _bfd_nosymbols_find_nearest_line +#define nlm_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define nlm_read_minisymbols _bfd_generic_read_minisymbols +#define nlm_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define nlm_get_reloc_upper_bound nlmNAME(get_reloc_upper_bound) +#define nlm_canonicalize_reloc nlmNAME(canonicalize_reloc) +#define nlm_bfd_reloc_type_lookup bfd_default_reloc_type_lookup + +#define nlm_set_section_contents nlmNAME(set_section_contents) + +#define nlm_sizeof_headers _bfd_nolink_sizeof_headers +#define nlm_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define nlm_bfd_relax_section bfd_generic_relax_section +#define nlm_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define nlm_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define nlm_bfd_final_link _bfd_generic_final_link +#define nlm_bfd_link_split_section _bfd_generic_link_split_section + +/* This structure contains everything that BFD knows about a target. + It includes things like its byte order, name, what routines to call + to do various operations, etc. Every BFD points to a target structure + with its "xvec" member. + + There are two such structures here: one for big-endian machines and + one for little-endian machines. */ + + +#ifdef TARGET_BIG_SYM +const bfd_target TARGET_BIG_SYM = +{ + /* name: identify kind of target */ + TARGET_BIG_NAME, + + /* flavour: general indication about file */ + bfd_target_nlm_flavour, + + /* byteorder: data is big endian */ + BFD_ENDIAN_BIG, + + /* header_byteorder: header is also big endian */ + BFD_ENDIAN_BIG, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS + | WP_TEXT), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_CODE | SEC_DATA), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + 0, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with NLM, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with NLM, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 15, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + nlmNAME(object_p), /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + nlm_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + nlm_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + nlmNAME(write_object_contents), + _bfd_write_archive_contents, + bfd_false + }, + + /* Initialize a jump table with the standard macro. All names start with + "nlm" */ + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (nlm), + BFD_JUMP_TABLE_RELOCS (nlm), + BFD_JUMP_TABLE_WRITE (nlm), + BFD_JUMP_TABLE_LINK (nlm), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + /* backend_data: */ + (PTR) TARGET_BACKEND_DATA +}; +#endif + +#ifdef TARGET_LITTLE_SYM +const bfd_target TARGET_LITTLE_SYM = +{ + /* name: identify kind of target */ + TARGET_LITTLE_NAME, + + /* flavour: general indication about file */ + bfd_target_nlm_flavour, + + /* byteorder: data is little endian */ + BFD_ENDIAN_LITTLE, + + /* header_byteorder: header is also little endian */ + BFD_ENDIAN_LITTLE, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS + | WP_TEXT), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_DATA), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + 0, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with NLM, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with NLM, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 15, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + nlmNAME(object_p), /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + nlm_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + nlm_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + nlmNAME(write_object_contents), + _bfd_write_archive_contents, + bfd_false + }, + + /* Initialize a jump table with the standard macro. All names start with + "nlm" */ + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (nlm), + BFD_JUMP_TABLE_RELOCS (nlm), + BFD_JUMP_TABLE_WRITE (nlm), + BFD_JUMP_TABLE_LINK (nlm), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + /* backend_data: */ + (PTR) TARGET_BACKEND_DATA +}; +#endif diff --git a/contrib/gdb/bfd/nlm.c b/contrib/gdb/bfd/nlm.c new file mode 100644 index 000000000000..89c6baa64ef7 --- /dev/null +++ b/contrib/gdb/bfd/nlm.c @@ -0,0 +1,55 @@ +/* NLM (NetWare Loadable Module) executable support for BFD. + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libnlm.h" + +/* Make an NLM object. We just need to allocate the backend + information. */ + +boolean +nlm_mkobject (abfd) + bfd * abfd; +{ + nlm_tdata (abfd) = + (struct nlm_obj_tdata *) bfd_zalloc (abfd, sizeof (struct nlm_obj_tdata)); + if (nlm_tdata (abfd) == NULL) + return (false); + + if (nlm_architecture (abfd) != bfd_arch_unknown) + bfd_default_set_arch_mach (abfd, nlm_architecture (abfd), + nlm_machine (abfd)); + + /* since everything is done at close time, do we need any initialization? */ + return (true); +} + +/* Set the architecture and machine for an NLM object. */ + +boolean +nlm_set_arch_mach (abfd, arch, machine) + bfd * abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach (abfd, arch, machine); + return arch == nlm_architecture (abfd); +} diff --git a/contrib/gdb/bfd/nlm32-alpha.c b/contrib/gdb/bfd/nlm32-alpha.c new file mode 100644 index 000000000000..24c8e5167628 --- /dev/null +++ b/contrib/gdb/bfd/nlm32-alpha.c @@ -0,0 +1,892 @@ +/* Support for 32-bit Alpha NLM (NetWare Loadable Module) + Copyright (C) 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file describes the 32 bit Alpha NLM format. You might think + that an Alpha chip would use a 64 bit format, but, for some reason, + it doesn't. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#define ARCH_SIZE 32 + +#include "nlm/alpha-ext.h" +#define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header + +#include "libnlm.h" + +static boolean nlm_alpha_backend_object_p + PARAMS ((bfd *)); +static boolean nlm_alpha_write_prefix + PARAMS ((bfd *)); +static boolean nlm_alpha_read_reloc + PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); +static boolean nlm_alpha_mangle_relocs + PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); +static boolean nlm_alpha_read_import + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static boolean nlm_alpha_write_import + PARAMS ((bfd *, asection *, arelent *)); +static boolean nlm_alpha_set_public_section + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static bfd_vma nlm_alpha_get_public_offset + PARAMS ((bfd *, asymbol *)); +static boolean nlm_alpha_write_external + PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); + +/* Alpha NLM's have a prefix header before the standard NLM. This + function reads it in, verifies the version, and seeks the bfd to + the location before the regular NLM header. */ + +static boolean +nlm_alpha_backend_object_p (abfd) + bfd *abfd; +{ + struct nlm32_alpha_external_prefix_header s; + bfd_size_type size; + + if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s) + return false; + + if (bfd_h_get_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC) + return false; + + /* FIXME: Should we check the format number? */ + + /* Skip to the end of the header. */ + size = bfd_h_get_32 (abfd, s.size); + if (bfd_seek (abfd, size, SEEK_SET) != 0) + return false; + + return true; +} + +/* Write out the prefix. */ + +static boolean +nlm_alpha_write_prefix (abfd) + bfd *abfd; +{ + struct nlm32_alpha_external_prefix_header s; + + memset (&s, 0, sizeof s); + bfd_h_put_32 (abfd, (bfd_vma) NLM32_ALPHA_MAGIC, s.magic); + bfd_h_put_32 (abfd, (bfd_vma) 2, s.format); + bfd_h_put_32 (abfd, (bfd_vma) sizeof s, s.size); + if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s) + return false; + return true; +} + +/* How to process the various reloc types. */ + +static reloc_howto_type nlm32_alpha_howto_table[] = +{ + /* Reloc type 0 is ignored by itself. However, it appears after a + GPDISP reloc to identify the location where the low order 16 bits + of the gp register are loaded. */ + HOWTO (ALPHA_R_IGNORE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "IGNORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "REFLONG", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFQUAD, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "REFQUAD", /* name */ + true, /* partial_inplace */ + 0xffffffffffffffff, /* src_mask */ + 0xffffffffffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 32 bit GP relative offset. This is just like REFLONG except + that when the value is used the value of the gp register will be + added in. */ + HOWTO (ALPHA_R_GPREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "GPREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Used for an instruction that refers to memory off the GP + register. The offset is 16 bits of the 32 bit instruction. This + reloc always seems to be against the .lita section. */ + HOWTO (ALPHA_R_LITERAL, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "LITERAL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* This reloc only appears immediately following a LITERAL reloc. + It identifies a use of the literal. It seems that the linker can + use this to eliminate a portion of the .lita section. The symbol + index is special: 1 means the literal address is in the base + register of a memory format instruction; 2 means the literal + address is in the byte offset register of a byte-manipulation + instruction; 3 means the literal address is in the target + register of a jsr instruction. This does not actually do any + relocation. */ + HOWTO (ALPHA_R_LITUSE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "LITUSE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Load the gp register. This is always used for a ldah instruction + which loads the upper 16 bits of the gp register. The next reloc + will be an IGNORE reloc which identifies the location of the lda + instruction which loads the lower 16 bits. The symbol index of + the GPDISP instruction appears to actually be the number of bytes + between the ldah and lda instructions. This gives two different + ways to determine where the lda instruction is; I don't know why + both are used. The value to use for the relocation is the + difference between the GP value and the current location; the + load will always be done against a register holding the current + address. */ + HOWTO (ALPHA_R_GPDISP, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "GPDISP", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true), /* pcrel_offset */ + + /* A 21 bit branch. The native assembler generates these for + branches within the text segment, and also fills in the PC + relative offset in the instruction. It seems to me that this + reloc, unlike the others, is not partial_inplace. */ + HOWTO (ALPHA_R_BRADDR, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 21, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "BRADDR", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A hint for a jump to a register. */ + HOWTO (ALPHA_R_HINT, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 14, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "HINT", /* name */ + true, /* partial_inplace */ + 0x3fff, /* src_mask */ + 0x3fff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 64 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "SREL64", /* name */ + true, /* partial_inplace */ + 0xffffffffffffffff, /* src_mask */ + 0xffffffffffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Push a value on the reloc evaluation stack. */ + HOWTO (ALPHA_R_OP_PUSH, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PUSH", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Store the value from the stack at the given address. Store it in + a bitfield of size r_size starting at bit position r_offset. */ + HOWTO (ALPHA_R_OP_STORE, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_STORE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffffffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Subtract the reloc address from the value on the top of the + relocation stack. */ + HOWTO (ALPHA_R_OP_PSUB, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PSUB", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Shift the value on the top of the relocation stack right by the + given value. */ + HOWTO (ALPHA_R_OP_PRSHIFT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "OP_PRSHIFT", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* Adjust the GP value for a new range in the object file. */ + HOWTO (ALPHA_R_GPVALUE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "GPVALUE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false) /* pcrel_offset */ +}; + +static reloc_howto_type nlm32_alpha_nw_howto = + HOWTO (ALPHA_R_NW_RELOC, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "NW_RELOC", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false); /* pcrel_offset */ + +/* Read an Alpha NLM reloc. This routine keeps some static data which + it uses when handling local relocs. This only works correctly + because all the local relocs are read at once. */ + +static boolean +nlm_alpha_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + static bfd_vma gp_value; + static bfd_vma lita_address; + struct nlm32_alpha_external_reloc ext; + bfd_vma r_vaddr; + long r_symndx; + int r_type, r_extern, r_offset, r_size; + asection *code_sec, *data_sec; + + /* Read the reloc from the file. */ + if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext) + return false; + + /* Swap in the reloc information. */ + r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext.r_vaddr); + r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext.r_symndx); + + BFD_ASSERT (bfd_little_endian (abfd)); + + r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE) + >> RELOC_BITS0_TYPE_SH_LITTLE); + r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; + r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) + >> RELOC_BITS1_OFFSET_SH_LITTLE); + /* Ignore the reserved bits. */ + r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE) + >> RELOC_BITS3_SIZE_SH_LITTLE); + + /* Fill in the BFD arelent structure. */ + code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + if (r_extern) + { + /* External relocations are only used for imports. */ + BFD_ASSERT (sym != NULL); + /* We don't need to set sym_ptr_ptr for this case. It is set in + nlm_canonicalize_reloc. */ + rel->sym_ptr_ptr = NULL; + rel->addend = 0; + } + else + { + /* Internal relocations are only used for local relocation + fixups. If they are not NW_RELOC or GPDISP or IGNORE, they + must be against .text or .data. */ + BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL); + if (r_type == ALPHA_R_NW_RELOC + || r_type == ALPHA_R_GPDISP + || r_type == ALPHA_R_IGNORE) + { + rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + rel->addend = 0; + } + else if (r_symndx == ALPHA_RELOC_SECTION_TEXT) + { + rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr; + BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0); + rel->addend = 0; + } + else if (r_symndx == ALPHA_RELOC_SECTION_DATA) + { + rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr; + rel->addend = - bfd_get_section_vma (abfd, data_sec); + } + else + { + BFD_ASSERT (0); + rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + rel->addend = 0; + } + } + + /* We use the address to determine whether the reloc is in the .text + or .data section. R_NW_RELOC relocs don't really have a section, + so we put them in .text. */ + if (r_type == ALPHA_R_NW_RELOC + || r_vaddr < bfd_section_size (abfd, code_sec)) + { + *secp = code_sec; + rel->address = r_vaddr; + } + else + { + *secp = data_sec; + rel->address = r_vaddr - bfd_section_size (abfd, code_sec); + } + + /* We must adjust the addend based on the type. */ + BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE) + || r_type == ALPHA_R_NW_RELOC); + + switch (r_type) + { + case ALPHA_R_BRADDR: + case ALPHA_R_SREL16: + case ALPHA_R_SREL32: + case ALPHA_R_SREL64: + /* The PC relative relocs do not seem to use the section VMA as + a negative addend. */ + rel->addend = 0; + break; + + case ALPHA_R_GPREL32: + /* Copy the gp value for this object file into the addend, to + ensure that we are not confused by the linker. */ + if (! r_extern) + rel->addend += gp_value; + break; + + case ALPHA_R_LITERAL: + BFD_ASSERT (! r_extern); + rel->addend += lita_address; + break; + + case ALPHA_R_LITUSE: + case ALPHA_R_GPDISP: + /* The LITUSE and GPDISP relocs do not use a symbol, or an + addend, but they do use a special code. Put this code in the + addend field. */ + rel->addend = r_symndx; + rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + break; + + case ALPHA_R_OP_STORE: + /* The STORE reloc needs the size and offset fields. We store + them in the addend. */ + BFD_ASSERT (r_offset < 256 && r_size < 256); + rel->addend = (r_offset << 8) + r_size; + break; + + case ALPHA_R_OP_PUSH: + case ALPHA_R_OP_PSUB: + case ALPHA_R_OP_PRSHIFT: + /* The PUSH, PSUB and PRSHIFT relocs do not actually use an + address. I believe that the address supplied is really an + addend. */ + rel->addend = r_vaddr; + break; + + case ALPHA_R_GPVALUE: + /* Record the new gp value. */ + gp_value += r_symndx; + rel->addend = gp_value; + break; + + case ALPHA_R_IGNORE: + /* If the type is ALPHA_R_IGNORE, make sure this is a reference + to the absolute section so that the reloc is ignored. For + some reason the address of this reloc type is not adjusted by + the section vma. We record the gp value for this object file + here, for convenience when doing the GPDISP relocation. */ + rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + rel->address = r_vaddr; + rel->addend = gp_value; + break; + + case ALPHA_R_NW_RELOC: + /* If this is SETGP, we set the addend to 0. Otherwise we set + the addend to the size of the .lita section (this is + r_symndx) plus 1. We have already set the address of the + reloc to r_vaddr. */ + if (r_size == ALPHA_R_NW_RELOC_SETGP) + { + gp_value = r_vaddr; + rel->addend = 0; + } + else if (r_size == ALPHA_R_NW_RELOC_LITA) + { + lita_address = r_vaddr; + rel->addend = r_symndx + 1; + } + else + BFD_ASSERT (0); + rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + break; + + default: + break; + } + + if (r_type == ALPHA_R_NW_RELOC) + rel->howto = &nlm32_alpha_nw_howto; + else + rel->howto = &nlm32_alpha_howto_table[r_type]; + + return true; +} + +/* Mangle Alpha NLM relocs for output. */ + +static boolean +nlm_alpha_mangle_relocs (abfd, sec, data, offset, count) + bfd *abfd; + asection *sec; + PTR data; + bfd_vma offset; + bfd_size_type count; +{ + return true; +} + +/* Read an ALPHA NLM import record */ + +static boolean +nlm_alpha_read_import (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + struct nlm_relent *nlm_relocs; /* relocation records for symbol */ + bfd_size_type rcount; /* number of relocs */ + bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ + unsigned char symlength; /* length of symbol name */ + char *name; + + if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength)) + return false; + sym -> symbol.the_bfd = abfd; + name = bfd_alloc (abfd, symlength + 1); + if (name == NULL) + return false; + if (bfd_read (name, symlength, 1, abfd) != symlength) + return false; + name[symlength] = '\0'; + sym -> symbol.name = name; + sym -> symbol.flags = 0; + sym -> symbol.value = 0; + sym -> symbol.section = bfd_und_section_ptr; + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + rcount = bfd_h_get_32 (abfd, temp); + nlm_relocs = ((struct nlm_relent *) + bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); + if (!nlm_relocs) + return false; + sym -> relocs = nlm_relocs; + sym -> rcnt = 0; + while (sym -> rcnt < rcount) + { + asection *section; + + if (nlm_alpha_read_reloc (abfd, sym, §ion, + &nlm_relocs -> reloc) + == false) + return false; + nlm_relocs -> section = section; + nlm_relocs++; + sym -> rcnt++; + } + + return true; +} + +/* Write an Alpha NLM reloc. */ + +static boolean +nlm_alpha_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + asymbol *sym; + bfd_vma r_vaddr; + long r_symndx; + int r_type, r_extern, r_offset, r_size; + struct nlm32_alpha_external_reloc ext; + + sym = *rel->sym_ptr_ptr; + + /* Get values for the relocation fields. */ + r_type = rel->howto->type; + if (r_type != ALPHA_R_NW_RELOC) + { + r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address; + if ((sec->flags & SEC_CODE) == 0) + r_vaddr += bfd_section_size (abfd, + bfd_get_section_by_name (abfd, + NLM_CODE_NAME)); + if (bfd_is_und_section (bfd_get_section (sym))) + { + r_extern = 1; + r_symndx = 0; + } + else + { + r_extern = 0; + if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) + r_symndx = ALPHA_RELOC_SECTION_TEXT; + else + r_symndx = ALPHA_RELOC_SECTION_DATA; + } + r_offset = 0; + r_size = 0; + + switch (r_type) + { + case ALPHA_R_LITUSE: + case ALPHA_R_GPDISP: + r_symndx = rel->addend; + break; + + case ALPHA_R_OP_STORE: + r_size = rel->addend & 0xff; + r_offset = (rel->addend >> 8) & 0xff; + break; + + case ALPHA_R_OP_PUSH: + case ALPHA_R_OP_PSUB: + case ALPHA_R_OP_PRSHIFT: + r_vaddr = rel->addend; + break; + + case ALPHA_R_IGNORE: + r_vaddr = rel->address; + break; + + default: + break; + } + } + else + { + /* r_type == ALPHA_R_NW_RELOC */ + r_vaddr = rel->address; + if (rel->addend == 0) + { + r_symndx = 0; + r_size = ALPHA_R_NW_RELOC_SETGP; + } + else + { + r_symndx = rel->addend - 1; + r_size = ALPHA_R_NW_RELOC_LITA; + } + r_extern = 0; + r_offset = 0; + } + + /* Swap out the relocation fields. */ + bfd_h_put_64 (abfd, r_vaddr, (bfd_byte *) ext.r_vaddr); + bfd_h_put_32 (abfd, r_symndx, (bfd_byte *) ext.r_symndx); + + BFD_ASSERT (bfd_little_endian (abfd)); + + ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE) + & RELOC_BITS0_TYPE_LITTLE); + ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0) + | ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE) + & RELOC_BITS1_OFFSET_LITTLE)); + ext.r_bits[2] = 0; + ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE) + & RELOC_BITS3_SIZE_LITTLE); + + /* Write out the relocation. */ + if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext) + return false; + + return true; +} + +/* Alpha NetWare does not use the high bit to determine whether a + public symbol is in the code segment or the data segment. Instead, + it just uses the address. The set_public_section and + get_public_offset routines override the default code which uses the + high bit. */ + +/* Set the section for a public symbol. */ + +static boolean +nlm_alpha_set_public_section (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + asection *code_sec, *data_sec; + + code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + if (sym->symbol.value < bfd_section_size (abfd, code_sec)) + { + sym->symbol.section = code_sec; + sym->symbol.flags |= BSF_FUNCTION; + } + else + { + sym->symbol.section = data_sec; + sym->symbol.value -= bfd_section_size (abfd, code_sec); + /* The data segment had better be aligned. */ + BFD_ASSERT ((bfd_section_size (abfd, code_sec) & 0xf) == 0); + } + return true; +} + +/* Get the offset to write out for a public symbol. */ + +static bfd_vma +nlm_alpha_get_public_offset (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + return bfd_asymbol_value (sym); +} + +/* Write an Alpha NLM external symbol. */ + +static boolean +nlm_alpha_write_external (abfd, count, sym, relocs) + bfd *abfd; + bfd_size_type count; + asymbol *sym; + struct reloc_and_sec *relocs; +{ + int i; + bfd_byte len; + unsigned char temp[NLM_TARGET_LONG_SIZE]; + arelent r; + + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + return false; + + bfd_put_32 (abfd, count + 2, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + /* The first two relocs for each external symbol are the .lita + address and the GP value. */ + r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + r.howto = &nlm32_alpha_nw_howto; + + r.address = nlm_alpha_backend_data (abfd)->lita_address; + r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1; + if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false) + return false; + + r.address = nlm_alpha_backend_data (abfd)->gp; + r.addend = 0; + if (nlm_alpha_write_import (abfd, (asection *) NULL, &r) == false) + return false; + + for (i = 0; i < count; i++) + { + if (nlm_alpha_write_import (abfd, relocs[i].sec, + relocs[i].rel) == false) + return false; + } + + return true; +} + +#include "nlmswap.h" + +static const struct nlm_backend_data nlm32_alpha_backend = +{ + "NetWare Alpha Module \032", + sizeof (Nlm32_alpha_External_Fixed_Header), + sizeof (struct nlm32_alpha_external_prefix_header), + bfd_arch_alpha, + 0, + true, /* no uninitialized data permitted by Alpha NetWare. */ + nlm_alpha_backend_object_p, + nlm_alpha_write_prefix, + nlm_alpha_read_reloc, + nlm_alpha_mangle_relocs, + nlm_alpha_read_import, + nlm_alpha_write_import, + nlm_alpha_set_public_section, + nlm_alpha_get_public_offset, + nlm_swap_fixed_header_in, + nlm_swap_fixed_header_out, + nlm_alpha_write_external, + 0, /* write_export */ +}; + +#define TARGET_LITTLE_NAME "nlm32-alpha" +#define TARGET_LITTLE_SYM nlmNAME(alpha_vec) +#define TARGET_BACKEND_DATA &nlm32_alpha_backend + +#include "nlm-target.h" diff --git a/contrib/gdb/bfd/nlm32-i386.c b/contrib/gdb/bfd/nlm32-i386.c new file mode 100644 index 000000000000..f16c74d985eb --- /dev/null +++ b/contrib/gdb/bfd/nlm32-i386.c @@ -0,0 +1,451 @@ +/* Support for 32-bit i386 NLM (NetWare Loadable Module) + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#define ARCH_SIZE 32 + +#include "nlm/i386-ext.h" +#define Nlm_External_Fixed_Header Nlm32_i386_External_Fixed_Header + +#include "libnlm.h" + +static boolean nlm_i386_read_reloc + PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); +static boolean nlm_i386_write_import + PARAMS ((bfd *, asection *, arelent *)); +static boolean nlm_i386_mangle_relocs + PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); +static boolean nlm_i386_read_import + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static boolean nlm_i386_write_external + PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); + +/* Adjust the reloc location by an absolute value. */ + +static reloc_howto_type nlm_i386_abs_howto = + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false); /* pcrel_offset */ + +/* Adjust the reloc location by a PC relative displacement. */ + +static reloc_howto_type nlm_i386_pcrel_howto = + HOWTO (1, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "DISP32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true); /* pcrel_offset */ + +/* Read a NetWare i386 reloc. */ + +static boolean +nlm_i386_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + bfd_byte temp[4]; + bfd_vma val; + const char *name; + + if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + val = bfd_get_32 (abfd, temp); + + /* The value is an offset into either the code or data segment. + This is the location which needs to be adjusted. + + If this is a relocation fixup rather than an imported symbol (the + sym argument is NULL) then the high bit is 0 if the location + needs to be adjusted by the address of the data segment, or 1 if + the location needs to be adjusted by the address of the code + segment. If this is an imported symbol, then the high bit is 0 + if the location is 0 if the location should be adjusted by the + offset to the symbol, or 1 if the location should adjusted by the + absolute value of the symbol. + + The second most significant bit is 0 if the value is an offset + into the data segment, or 1 if the value is an offset into the + code segment. + + All this translates fairly easily into a BFD reloc. */ + + if (sym == NULL) + { + if ((val & NLM_HIBIT) == 0) + name = NLM_INITIALIZED_DATA_NAME; + else + { + name = NLM_CODE_NAME; + val &=~ NLM_HIBIT; + } + rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr; + rel->howto = &nlm_i386_abs_howto; + } + else + { + /* In this case we do not need to set the sym_ptr_ptr field. */ + rel->sym_ptr_ptr = NULL; + if ((val & NLM_HIBIT) == 0) + rel->howto = &nlm_i386_pcrel_howto; + else + { + rel->howto = &nlm_i386_abs_howto; + val &=~ NLM_HIBIT; + } + } + + if ((val & (NLM_HIBIT >> 1)) == 0) + *secp = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + else + { + *secp = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + val &=~ (NLM_HIBIT >> 1); + } + + rel->address = val; + rel->addend = 0; + + return true; +} + +/* Write a NetWare i386 reloc. */ + +static boolean +nlm_i386_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + asymbol *sym; + bfd_vma val; + bfd_byte temp[4]; + + /* NetWare only supports two kinds of relocs. We should check + special_function here, as well, but at the moment coff-i386 + relocs uses a special_function which does not affect what we do + here. */ + if (rel->addend != 0 + || rel->howto == NULL + || rel->howto->rightshift != 0 + || rel->howto->size != 2 + || rel->howto->bitsize != 32 + || rel->howto->bitpos != 0 + || rel->howto->src_mask != 0xffffffff + || rel->howto->dst_mask != 0xffffffff) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + sym = *rel->sym_ptr_ptr; + + /* The value we write out is the offset into the appropriate + segment. This offset is the section vma, adjusted by the vma of + the lowest section in that segment, plus the address of the + relocation. */ + val = bfd_get_section_vma (abfd, sec) + rel->address; + + /* The second most significant bit is 0 if the value is an offset + into the data segment, or 1 if the value is an offset into the + code segment. */ + if (bfd_get_section_flags (abfd, sec) & SEC_CODE) + { + val -= nlm_get_text_low (abfd); + val |= NLM_HIBIT >> 1; + } + else + val -= nlm_get_data_low (abfd); + + if (! bfd_is_und_section (bfd_get_section (sym))) + { + /* NetWare only supports absolute internal relocs. */ + if (rel->howto->pc_relative) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* The high bit is 1 if the reloc is against the code section, 0 + if against the data section. */ + if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) + val |= NLM_HIBIT; + } + else + { + /* The high bit is 1 if this is an absolute reloc, 0 if it is PC + relative. */ + if (! rel->howto->pc_relative) + val |= NLM_HIBIT; + else + { + /* PC relative relocs on NetWare must be pcrel_offset. */ + if (! rel->howto->pcrel_offset) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + } + } + + bfd_put_32 (abfd, val, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + return true; +} + +/* I want to be able to use objcopy to turn a i386 a.out or COFF file + into a NetWare i386 module. That means that the relocs from the + source file have to be mapped into relocs that apply to the target + file. This function is called by nlm_set_section_contents to give + it a chance to rework the relocs. + + This is actually a fairly general concept. However, this is not a + general implementation. */ + +static boolean +nlm_i386_mangle_relocs (abfd, sec, data, offset, count) + bfd *abfd; + asection *sec; + PTR data; + bfd_vma offset; + bfd_size_type count; +{ + arelent **rel_ptr_ptr, **rel_end; + + rel_ptr_ptr = sec->orelocation; + rel_end = rel_ptr_ptr + sec->reloc_count; + for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++) + { + arelent *rel; + asymbol *sym; + bfd_vma addend; + + rel = *rel_ptr_ptr; + sym = *rel->sym_ptr_ptr; + + /* Note that no serious harm will ensue if we fail to change a + reloc. We will wind up failing in nlm_i386_write_import. */ + + /* Make sure this reloc is within the data we have. We only 4 + byte relocs here, so we insist on having 4 bytes. */ + if (rel->address < offset + || rel->address + 4 > offset + count) + continue; + + /* NetWare doesn't support reloc addends, so we get rid of them + here by simply adding them into the object data. We handle + the symbol value, if any, the same way. */ + addend = rel->addend + sym->value; + + /* The value of a symbol is the offset into the section. If the + symbol is in the .bss segment, we need to include the size of + the data segment in the offset as well. Fortunately, we know + that at this point the size of the data section is in the NLM + header. */ + if (((bfd_get_section_flags (abfd, bfd_get_section (sym)) + & SEC_LOAD) == 0) + && ((bfd_get_section_flags (abfd, bfd_get_section (sym)) + & SEC_ALLOC) != 0)) + addend += nlm_fixed_header (abfd)->dataImageSize; + + if (addend != 0 + && rel->howto != NULL + && rel->howto->rightshift == 0 + && rel->howto->size == 2 + && rel->howto->bitsize == 32 + && rel->howto->bitpos == 0 + && rel->howto->src_mask == 0xffffffff + && rel->howto->dst_mask == 0xffffffff) + { + bfd_vma val; + + val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset); + val += addend; + bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset); + rel->addend = 0; + } + + /* NetWare uses a reloc with pcrel_offset set. We adjust + pc_relative relocs accordingly. We are going to change the + howto field, so we can only do this if the current one is + compatible. We should check special_function here, but at + the moment coff-i386 uses a special_function which does not + affect what we are doing here. */ + if (rel->howto != NULL + && rel->howto->pc_relative + && ! rel->howto->pcrel_offset + && rel->howto->rightshift == 0 + && rel->howto->size == 2 + && rel->howto->bitsize == 32 + && rel->howto->bitpos == 0 + && rel->howto->src_mask == 0xffffffff + && rel->howto->dst_mask == 0xffffffff) + { + bfd_vma val; + + /* When pcrel_offset is not set, it means that the negative + of the address of the memory location is stored in the + memory location. We must add it back in. */ + val = bfd_get_32 (abfd, (bfd_byte *) data + rel->address - offset); + val += rel->address; + bfd_put_32 (abfd, val, (bfd_byte *) data + rel->address - offset); + + rel->howto = &nlm_i386_pcrel_howto; + } + } + + return true; +} + +/* Read a NetWare i386 import record */ +static boolean +nlm_i386_read_import (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + struct nlm_relent *nlm_relocs; /* relocation records for symbol */ + bfd_size_type rcount; /* number of relocs */ + bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ + unsigned char symlength; /* length of symbol name */ + char *name; + + if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength)) + return false; + sym -> symbol.the_bfd = abfd; + name = bfd_alloc (abfd, symlength + 1); + if (name == NULL) + return false; + if (bfd_read (name, symlength, 1, abfd) != symlength) + return false; + name[symlength] = '\0'; + sym -> symbol.name = name; + sym -> symbol.flags = 0; + sym -> symbol.value = 0; + sym -> symbol.section = bfd_und_section_ptr; + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + rcount = bfd_h_get_32 (abfd, temp); + nlm_relocs = ((struct nlm_relent *) + bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); + if (!nlm_relocs) + return false; + sym -> relocs = nlm_relocs; + sym -> rcnt = 0; + while (sym -> rcnt < rcount) + { + asection *section; + + if (nlm_i386_read_reloc (abfd, sym, §ion, + &nlm_relocs -> reloc) + == false) + return false; + nlm_relocs -> section = section; + nlm_relocs++; + sym -> rcnt++; + } + return true; +} + +/* Write out an external reference. */ + +static boolean +nlm_i386_write_external (abfd, count, sym, relocs) + bfd *abfd; + bfd_size_type count; + asymbol *sym; + struct reloc_and_sec *relocs; +{ + unsigned int i; + bfd_byte len; + unsigned char temp[NLM_TARGET_LONG_SIZE]; + + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + return false; + + bfd_put_32 (abfd, count, temp); + if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp)) + return false; + + for (i = 0; i < count; i++) + { + if (nlm_i386_write_import (abfd, relocs[i].sec, + relocs[i].rel) == false) + return false; + } + + return true; +} + +#include "nlmswap.h" + +static const struct nlm_backend_data nlm32_i386_backend = +{ + "NetWare Loadable Module\032", + sizeof (Nlm32_i386_External_Fixed_Header), + 0, /* optional_prefix_size */ + bfd_arch_i386, + 0, + false, + 0, /* backend_object_p */ + 0, /* write_prefix_func */ + nlm_i386_read_reloc, + nlm_i386_mangle_relocs, + nlm_i386_read_import, + nlm_i386_write_import, + 0, /* set_public_section */ + 0, /* get_public_offset */ + nlm_swap_fixed_header_in, + nlm_swap_fixed_header_out, + nlm_i386_write_external, + 0, /* write_export */ +}; + +#define TARGET_LITTLE_NAME "nlm32-i386" +#define TARGET_LITTLE_SYM nlmNAME(i386_vec) +#define TARGET_BACKEND_DATA &nlm32_i386_backend + +#include "nlm-target.h" diff --git a/contrib/gdb/bfd/nlm32-ppc.c b/contrib/gdb/bfd/nlm32-ppc.c new file mode 100644 index 000000000000..ecf2de8f10bf --- /dev/null +++ b/contrib/gdb/bfd/nlm32-ppc.c @@ -0,0 +1,1045 @@ +/* Support for 32-bit PowerPC NLM (NetWare Loadable Module) + Copyright (C) 1994, 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* The format of a PowerPC NLM changed. Define OLDFORMAT to get the + old format. */ + +#define ARCH_SIZE 32 + +#include "nlm/ppc-ext.h" +#define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header + +#include "libnlm.h" + +#ifdef OLDFORMAT +static boolean nlm_powerpc_backend_object_p + PARAMS ((bfd *)); +static boolean nlm_powerpc_write_prefix + PARAMS ((bfd *)); +#endif + +static boolean nlm_powerpc_read_reloc + PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); +static boolean nlm_powerpc_mangle_relocs + PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); +static boolean nlm_powerpc_read_import + PARAMS ((bfd *, nlmNAME(symbol_type) *)); + +#ifdef OLDFORMAT +static boolean nlm_powerpc_write_reloc + PARAMS ((bfd *, asection *, arelent *, int)); +#endif + +static boolean nlm_powerpc_write_import + PARAMS ((bfd *, asection *, arelent *)); +static boolean nlm_powerpc_write_external + PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); + +#ifndef OLDFORMAT +static boolean nlm_powerpc_set_public_section + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static bfd_vma nlm_powerpc_get_public_offset + PARAMS ((bfd *, asymbol *)); +#endif + +#ifdef OLDFORMAT + +/* The prefix header is only used in the old format. */ + +/* PowerPC NLM's have a prefix header before the standard NLM. This + function reads it in, verifies the version, and seeks the bfd to + the location before the regular NLM header. */ + +static boolean +nlm_powerpc_backend_object_p (abfd) + bfd *abfd; +{ + struct nlm32_powerpc_external_prefix_header s; + + if (bfd_read ((PTR) &s, sizeof s, 1, abfd) != sizeof s) + return false; + + if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0 + || bfd_h_get_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION) + return false; + + return true; +} + +/* Write out the prefix. */ + +static boolean +nlm_powerpc_write_prefix (abfd) + bfd *abfd; +{ + struct nlm32_powerpc_external_prefix_header s; + + memset (&s, 0, sizeof s); + memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature); + bfd_h_put_32 (abfd, (bfd_vma) NLM32_POWERPC_HEADER_VERSION, s.headerVersion); + bfd_h_put_32 (abfd, (bfd_vma) 0, s.origins); + + /* FIXME: What should we do about the date? */ + + if (bfd_write ((PTR) &s, sizeof s, 1, abfd) != sizeof s) + return false; + + return true; +} + +#endif /* OLDFORMAT */ + +#ifndef OLDFORMAT + +/* There is only one type of reloc in a PowerPC NLM. */ + +static reloc_howto_type nlm_powerpc_howto = + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false); /* pcrel_offset */ + +/* Read a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + bfd_byte temp[4]; + bfd_vma val; + const char *name; + + if (bfd_read (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + val = bfd_get_32 (abfd, temp); + + /* The value is a word offset into either the code or data segment. + This is the location which needs to be adjusted. + + The high bit is 0 if the value is an offset into the data + segment, or 1 if the value is an offset into the text segment. + + If this is a relocation fixup rather than an imported symbol (the + sym argument is NULL), then the second most significant bit is 0 + if the address of the data segment should be added to the + location addressed by the value, or 1 if the address of the text + segment should be added. + + If this is an imported symbol, the second most significant bit is + not used and must be 0. */ + + if ((val & NLM_HIBIT) == 0) + name = NLM_INITIALIZED_DATA_NAME; + else + { + name = NLM_CODE_NAME; + val &=~ NLM_HIBIT; + } + *secp = bfd_get_section_by_name (abfd, name); + + if (sym == NULL) + { + if ((val & (NLM_HIBIT >> 1)) == 0) + name = NLM_INITIALIZED_DATA_NAME; + else + { + name = NLM_CODE_NAME; + val &=~ (NLM_HIBIT >> 1); + } + rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr; + } + + rel->howto = &nlm_powerpc_howto; + + rel->address = val << 2; + rel->addend = 0; + + return true; +} + +#else /* OLDFORMAT */ + +/* This reloc handling is only applicable to the old format. */ + +/* How to process the various reloc types. PowerPC NLMs use XCOFF + reloc types, and I have just copied the XCOFF reloc table here. */ + +static reloc_howto_type nlm_powerpc_howto_table[] = +{ + /* Standard 32 bit relocation. */ + HOWTO (0, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_POS", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit relocation, but store negative value. */ + HOWTO (1, /* type */ + 0, /* rightshift */ + -2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_NEG", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 32 bit PC relative relocation. */ + HOWTO (2, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* 16 bit TOC relative relocation. */ + HOWTO (3, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_TOC", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* I don't really know what this is. */ + HOWTO (4, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RTB", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* External TOC relative symbol. */ + HOWTO (5, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_GL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Local TOC relative symbol. */ + HOWTO (6, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TCL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 7 }, + + /* Non modifiable absolute branch. */ + HOWTO (8, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_BA", /* name */ + true, /* partial_inplace */ + 0x3fffffc, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + { 9 }, + + /* Non modifiable relative branch. */ + HOWTO (0xa, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_BR", /* name */ + true, /* partial_inplace */ + 0x3fffffc, /* src_mask */ + 0x3fffffc, /* dst_mask */ + false), /* pcrel_offset */ + + { 0xb }, + + /* Indirect load. */ + HOWTO (0xc, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Load address. */ + HOWTO (0xd, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RLA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + { 0xe }, + + /* Non-relocating reference. */ + HOWTO (0xf, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_REF", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + { 0x10 }, + { 0x11 }, + + /* TOC relative indirect load. */ + HOWTO (0x12, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TRL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* TOC relative load address. */ + HOWTO (0x13, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_TRLA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable relative branch. */ + HOWTO (0x14, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RRTBI", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable absolute branch. */ + HOWTO (0x15, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RRTBA", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable call absolute indirect. */ + HOWTO (0x16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_CAI", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable call relative. */ + HOWTO (0x17, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x18, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBA", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x19, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_RBAC", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch relative. */ + HOWTO (0x1a, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Modifiable branch absolute. */ + HOWTO (0x1b, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "R_REL", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false) /* pcrel_offset */ +}; + +#define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \ + / sizeof nlm_powerpc_howto_table[0]) + +/* Read a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + struct nlm32_powerpc_external_reloc ext; + bfd_vma l_vaddr; + unsigned long l_symndx; + int l_rtype; + int l_rsecnm; + asection *code_sec, *data_sec, *bss_sec; + + /* Read the reloc from the file. */ + if (bfd_read (&ext, sizeof ext, 1, abfd) != sizeof ext) + return false; + + /* Swap in the fields. */ + l_vaddr = bfd_h_get_32 (abfd, ext.l_vaddr); + l_symndx = bfd_h_get_32 (abfd, ext.l_symndx); + l_rtype = bfd_h_get_16 (abfd, ext.l_rtype); + l_rsecnm = bfd_h_get_16 (abfd, ext.l_rsecnm); + + /* Get the sections now, for convenience. */ + code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); + + /* Work out the arelent fields. */ + if (sym != NULL) + { + /* This is an import. sym_ptr_ptr is filled in by + nlm_canonicalize_reloc. */ + rel->sym_ptr_ptr = NULL; + } + else + { + asection *sec; + + if (l_symndx == 0) + sec = code_sec; + else if (l_symndx == 1) + sec = data_sec; + else if (l_symndx == 2) + sec = bss_sec; + else + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + rel->sym_ptr_ptr = sec->symbol_ptr_ptr; + } + + rel->addend = 0; + + BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT); + + rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff); + + BFD_ASSERT (rel->howto->name != NULL + && ((l_rtype & 0x8000) != 0 + ? (rel->howto->complain_on_overflow + == complain_overflow_signed) + : (rel->howto->complain_on_overflow + == complain_overflow_bitfield)) + && ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1); + + if (l_rsecnm == 0) + *secp = code_sec; + else if (l_rsecnm == 1) + { + *secp = data_sec; + l_vaddr -= bfd_section_size (abfd, code_sec); + } + else + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + rel->address = l_vaddr; + + return true; +} + +#endif /* OLDFORMAT */ + +/* Mangle PowerPC NLM relocs for output. */ + +static boolean +nlm_powerpc_mangle_relocs (abfd, sec, data, offset, count) + bfd *abfd; + asection *sec; + PTR data; + bfd_vma offset; + bfd_size_type count; +{ + return true; +} + +/* Read a PowerPC NLM import record */ + +static boolean +nlm_powerpc_read_import (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + struct nlm_relent *nlm_relocs; /* relocation records for symbol */ + bfd_size_type rcount; /* number of relocs */ + bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ + unsigned char symlength; /* length of symbol name */ + char *name; + + if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength)) + return (false); + sym -> symbol.the_bfd = abfd; + name = bfd_alloc (abfd, symlength + 1); + if (name == NULL) + return false; + if (bfd_read (name, symlength, 1, abfd) != symlength) + return (false); + name[symlength] = '\0'; + sym -> symbol.name = name; + sym -> symbol.flags = 0; + sym -> symbol.value = 0; + sym -> symbol.section = bfd_und_section_ptr; + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + rcount = bfd_h_get_32 (abfd, temp); + nlm_relocs = ((struct nlm_relent *) + bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); + if (nlm_relocs == (struct nlm_relent *) NULL) + return false; + sym -> relocs = nlm_relocs; + sym -> rcnt = 0; + while (sym -> rcnt < rcount) + { + asection *section; + + if (nlm_powerpc_read_reloc (abfd, sym, §ion, + &nlm_relocs -> reloc) + == false) + return false; + nlm_relocs -> section = section; + nlm_relocs++; + sym -> rcnt++; + } + return true; +} + +#ifndef OLDFORMAT + +/* Write a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + asymbol *sym; + bfd_vma val; + bfd_byte temp[4]; + + /* PowerPC NetWare only supports one kind of reloc. */ + if (rel->addend != 0 + || rel->howto == NULL + || rel->howto->rightshift != 0 + || rel->howto->size != 2 + || rel->howto->bitsize != 32 + || rel->howto->bitpos != 0 + || rel->howto->pc_relative + || (rel->howto->src_mask != 0xffffffff && rel->addend != 0) + || rel->howto->dst_mask != 0xffffffff) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + sym = *rel->sym_ptr_ptr; + + /* The value we write out is the offset into the appropriate + segment, rightshifted by two. This offset is the section vma, + adjusted by the vma of the lowest section in that segment, plus + the address of the relocation. */ + val = bfd_get_section_vma (abfd, sec) + rel->address; + if ((val & 3) != 0) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + val >>= 2; + + /* The high bit is 0 if the reloc is in the data section, or 1 if + the reloc is in the code section. */ + if (bfd_get_section_flags (abfd, sec) & SEC_DATA) + val -= nlm_get_data_low (abfd); + else + { + val -= nlm_get_text_low (abfd); + val |= NLM_HIBIT; + } + + if (! bfd_is_und_section (bfd_get_section (sym))) + { + /* This is an internal relocation fixup. The second most + significant bit is 0 if this is a reloc against the data + segment, or 1 if it is a reloc against the text segment. */ + if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE) + val |= NLM_HIBIT >> 1; + } + + bfd_put_32 (abfd, val, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return false; + + return true; +} + +#else /* OLDFORMAT */ + +/* This is used for the reloc handling in the old format. */ + +/* Write a PowerPC NLM reloc. */ + +static boolean +nlm_powerpc_write_reloc (abfd, sec, rel, indx) + bfd *abfd; + asection *sec; + arelent *rel; + int indx; +{ + struct nlm32_powerpc_external_reloc ext; + asection *code_sec, *data_sec, *bss_sec; + asymbol *sym; + asection *symsec; + unsigned long l_symndx; + int l_rtype; + int l_rsecnm; + reloc_howto_type *howto; + bfd_size_type address; + + /* Get the sections now, for convenience. */ + code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); + + sym = *rel->sym_ptr_ptr; + symsec = bfd_get_section (sym); + if (indx != -1) + { + BFD_ASSERT (bfd_is_und_section (symsec)); + l_symndx = indx + 3; + } + else + { + if (symsec == code_sec) + l_symndx = 0; + else if (symsec == data_sec) + l_symndx = 1; + else if (symsec == bss_sec) + l_symndx = 2; + else + { + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + bfd_h_put_32 (abfd, (bfd_vma) l_symndx, ext.l_symndx); + + for (howto = nlm_powerpc_howto_table; + howto < nlm_powerpc_howto_table + HOWTO_COUNT; + howto++) + { + if (howto->rightshift == rel->howto->rightshift + && howto->size == rel->howto->size + && howto->bitsize == rel->howto->bitsize + && howto->pc_relative == rel->howto->pc_relative + && howto->bitpos == rel->howto->bitpos + && (howto->partial_inplace == rel->howto->partial_inplace + || (! rel->howto->partial_inplace + && rel->addend == 0)) + && (howto->src_mask == rel->howto->src_mask + || (rel->howto->src_mask == 0 + && rel->addend == 0)) + && howto->dst_mask == rel->howto->dst_mask + && howto->pcrel_offset == rel->howto->pcrel_offset) + break; + } + if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + l_rtype = howto->type; + if (howto->complain_on_overflow == complain_overflow_signed) + l_rtype |= 0x8000; + l_rtype |= (howto->bitsize - 1) << 8; + bfd_h_put_16 (abfd, (bfd_vma) l_rtype, ext.l_rtype); + + address = rel->address; + + if (sec == code_sec) + l_rsecnm = 0; + else if (sec == data_sec) + { + l_rsecnm = 1; + address += bfd_section_size (abfd, code_sec); + } + else + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_h_put_16 (abfd, (bfd_vma) l_rsecnm, ext.l_rsecnm); + bfd_h_put_32 (abfd, (bfd_vma) address, ext.l_vaddr); + + if (bfd_write (&ext, sizeof ext, 1, abfd) != sizeof ext) + return false; + + return true; +} + +/* Write a PowerPC NLM import. */ + +static boolean +nlm_powerpc_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + return nlm_powerpc_write_reloc (abfd, sec, rel, -1); +} + +#endif /* OLDFORMAT */ + +/* Write a PowerPC NLM external symbol. This routine keeps a static + count of the symbol index. FIXME: I don't know if this is + necessary, and the index never gets reset. */ + +static boolean +nlm_powerpc_write_external (abfd, count, sym, relocs) + bfd *abfd; + bfd_size_type count; + asymbol *sym; + struct reloc_and_sec *relocs; +{ + unsigned int i; + bfd_byte len; + unsigned char temp[NLM_TARGET_LONG_SIZE]; +#ifdef OLDFORMAT + static int indx; +#endif + + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + return false; + + bfd_put_32 (abfd, count, temp); + if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp)) + return false; + + for (i = 0; i < count; i++) + { +#ifndef OLDFORMAT + if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel)) + return false; +#else + if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec, + relocs[i].rel, indx)) + return false; +#endif + } + +#ifdef OLDFORMAT + ++indx; +#endif + + return true; +} + +#ifndef OLDFORMAT + +/* PowerPC Netware uses a word offset, not a byte offset, for public + symbols. */ + +/* Set the section for a public symbol. */ + +static boolean +nlm_powerpc_set_public_section (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + if (sym->symbol.value & NLM_HIBIT) + { + sym->symbol.value &= ~NLM_HIBIT; + sym->symbol.flags |= BSF_FUNCTION; + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_CODE_NAME); + } + else + { + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + } + + sym->symbol.value <<= 2; + + return true; +} + +/* Get the offset to write out for a public symbol. */ + +static bfd_vma +nlm_powerpc_get_public_offset (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + bfd_vma offset; + asection *sec; + + offset = bfd_asymbol_value (sym); + sec = bfd_get_section (sym); + if (sec->flags & SEC_CODE) + { + offset -= nlm_get_text_low (abfd); + offset |= NLM_HIBIT; + } + else if (sec->flags & (SEC_DATA | SEC_ALLOC)) + { + /* SEC_ALLOC is for the .bss section. */ + offset -= nlm_get_data_low (abfd); + } + else + { + /* We can't handle an exported symbol that is not in the code or + data segment. */ + bfd_set_error (bfd_error_invalid_operation); + /* FIXME: No way to return error. */ + abort (); + } + + return offset; +} + +#endif /* ! defined (OLDFORMAT) */ + +#include "nlmswap.h" + +static const struct nlm_backend_data nlm32_powerpc_backend = +{ + "NetWare PowerPC Module \032", + sizeof (Nlm32_powerpc_External_Fixed_Header), +#ifndef OLDFORMAT + 0, /* optional_prefix_size */ +#else + sizeof (struct nlm32_powerpc_external_prefix_header), +#endif + bfd_arch_powerpc, + 0, + false, +#ifndef OLDFORMAT + 0, /* backend_object_p */ + 0, /* write_prefix */ +#else + nlm_powerpc_backend_object_p, + nlm_powerpc_write_prefix, +#endif + nlm_powerpc_read_reloc, + nlm_powerpc_mangle_relocs, + nlm_powerpc_read_import, + nlm_powerpc_write_import, +#ifndef OLDFORMAT + nlm_powerpc_set_public_section, + nlm_powerpc_get_public_offset, +#else + 0, /* set_public_section */ + 0, /* get_public_offset */ +#endif + nlm_swap_fixed_header_in, + nlm_swap_fixed_header_out, + nlm_powerpc_write_external, + 0, /* write_export */ +}; + +#define TARGET_BIG_NAME "nlm32-powerpc" +#define TARGET_BIG_SYM nlmNAME(powerpc_vec) +#define TARGET_BACKEND_DATA &nlm32_powerpc_backend + +#include "nlm-target.h" diff --git a/contrib/gdb/bfd/nlm32-sparc.c b/contrib/gdb/bfd/nlm32-sparc.c new file mode 100644 index 000000000000..5963adbc70bf --- /dev/null +++ b/contrib/gdb/bfd/nlm32-sparc.c @@ -0,0 +1,440 @@ +/* Support for 32-bit SPARC NLM (NetWare Loadable Module) + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#define ARCH_SIZE 32 + +#include "nlm/sparc32-ext.h" +#define Nlm_External_Fixed_Header Nlm32_sparc_External_Fixed_Header + +#include "libnlm.h" + +static boolean nlm_sparc_read_reloc + PARAMS ((bfd *, nlmNAME(symbol_type) *, asection **, arelent *)); +static boolean nlm_sparc_write_reloc + PARAMS ((bfd *, asection *, arelent *)); +static boolean nlm_sparc_mangle_relocs + PARAMS ((bfd *, asection *, PTR, bfd_vma, bfd_size_type)); +static boolean nlm_sparc_read_import + PARAMS ((bfd *, nlmNAME(symbol_type) *)); +static boolean nlm_sparc_write_import + PARAMS ((bfd *, asection *, arelent *)); +static boolean nlm_sparc_write_external + PARAMS ((bfd *, bfd_size_type, asymbol *, struct reloc_and_sec *)); + +enum reloc_type + { + R_SPARC_NONE = 0, + R_SPARC_8, R_SPARC_16, R_SPARC_32, + R_SPARC_DISP8, R_SPARC_DISP16, R_SPARC_DISP32, + R_SPARC_WDISP30, R_SPARC_WDISP22, + R_SPARC_HI22, R_SPARC_22, + R_SPARC_13, R_SPARC_LO10, + R_SPARC_GOT10, R_SPARC_GOT13, R_SPARC_GOT22, + R_SPARC_PC10, R_SPARC_PC22, + R_SPARC_WPLT30, + R_SPARC_COPY, + R_SPARC_GLOB_DAT, R_SPARC_JMP_SLOT, + R_SPARC_RELATIVE, + R_SPARC_UA32, + R_SPARC_max + }; + +#if 0 +static CONST char *CONST reloc_type_names[] = +{ + "R_SPARC_NONE", + "R_SPARC_8", "R_SPARC_16", "R_SPARC_32", + "R_SPARC_DISP8", "R_SPARC_DISP16", "R_SPARC_DISP32", + "R_SPARC_WDISP30", "R_SPARC_WDISP22", + "R_SPARC_HI22", "R_SPARC_22", + "R_SPARC_13", "R_SPARC_LO10", + "R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", + "R_SPARC_PC10", "R_SPARC_PC22", + "R_SPARC_WPLT30", + "R_SPARC_COPY", + "R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", + "R_SPARC_RELATIVE", + "R_SPARC_UA32", +}; +#endif + +static reloc_howto_type nlm32_sparc_howto_table[] = +{ + HOWTO(R_SPARC_NONE, 0,0, 0,false,0,complain_overflow_dont, 0,"R_SPARC_NONE", false,0,0x00000000,true), + HOWTO(R_SPARC_8, 0,0, 8,false,0,complain_overflow_bitfield,0,"R_SPARC_8", false,0,0x000000ff,true), + HOWTO(R_SPARC_16, 0,1,16,false,0,complain_overflow_bitfield,0,"R_SPARC_16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_32, 0,2,32,false,0,complain_overflow_bitfield,0,"R_SPARC_32", false,0,0xffffffff,true), + HOWTO(R_SPARC_DISP8, 0,0, 8,true, 0,complain_overflow_signed, 0,"R_SPARC_DISP8", false,0,0x000000ff,true), + HOWTO(R_SPARC_DISP16, 0,1,16,true, 0,complain_overflow_signed, 0,"R_SPARC_DISP16", false,0,0x0000ffff,true), + HOWTO(R_SPARC_DISP32, 0,2,32,true, 0,complain_overflow_signed, 0,"R_SPARC_DISP32", false,0,0x00ffffff,true), + HOWTO(R_SPARC_WDISP30, 2,2,30,true, 0,complain_overflow_signed, 0,"R_SPARC_WDISP30", false,0,0x3fffffff,true), + HOWTO(R_SPARC_WDISP22, 2,2,22,true, 0,complain_overflow_signed, 0,"R_SPARC_WDISP22", false,0,0x003fffff,true), + HOWTO(R_SPARC_HI22, 10,2,22,false,0,complain_overflow_dont, 0,"R_SPARC_HI22", false,0,0x003fffff,true), + HOWTO(R_SPARC_22, 0,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_22", false,0,0x003fffff,true), + HOWTO(R_SPARC_13, 0,2,13,false,0,complain_overflow_bitfield,0,"R_SPARC_13", false,0,0x00001fff,true), + HOWTO(R_SPARC_LO10, 0,2,10,false,0,complain_overflow_dont, 0,"R_SPARC_LO10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT10, 0,2,10,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT10", false,0,0x000003ff,true), + HOWTO(R_SPARC_GOT13, 0,2,13,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT13", false,0,0x00001fff,true), + HOWTO(R_SPARC_GOT22, 10,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_GOT22", false,0,0x003fffff,true), + HOWTO(R_SPARC_PC10, 0,2,10,false,0,complain_overflow_bitfield,0,"R_SPARC_PC10", false,0,0x000003ff,true), + HOWTO(R_SPARC_PC22, 0,2,22,false,0,complain_overflow_bitfield,0,"R_SPARC_PC22", false,0,0x003fffff,true), + HOWTO(R_SPARC_WPLT30, 0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_WPLT30", false,0,0x00000000,true), + HOWTO(R_SPARC_COPY, 0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_COPY", false,0,0x00000000,true), + HOWTO(R_SPARC_GLOB_DAT,0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_GLOB_DAT",false,0,0x00000000,true), + HOWTO(R_SPARC_JMP_SLOT,0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_JMP_SLOT",false,0,0x00000000,true), + HOWTO(R_SPARC_RELATIVE,0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_RELATIVE",false,0,0x00000000,true), + HOWTO(R_SPARC_UA32, 0,0,00,false,0,complain_overflow_dont, 0,"R_SPARC_UA32", false,0,0x00000000,true), +}; + +/* Read a NetWare sparc reloc. */ + +struct nlm32_sparc_reloc_ext { + unsigned char offset[4]; + unsigned char addend[4]; + unsigned char type[1]; + unsigned char pad1[3]; +}; + +static boolean +nlm_sparc_read_reloc (abfd, sym, secp, rel) + bfd *abfd; + nlmNAME(symbol_type) *sym; + asection **secp; + arelent *rel; +{ + bfd_vma val, addend; + unsigned int index; + unsigned int type; + struct nlm32_sparc_reloc_ext tmp_reloc; + asection *code_sec, *data_sec; + + if (bfd_read (&tmp_reloc, 12, 1, abfd) != 12) + return false; + + code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + + *secp = code_sec; + + val = bfd_get_32 (abfd, tmp_reloc.offset); + addend = bfd_get_32 (abfd, tmp_reloc.addend); + type = bfd_get_8 (abfd, tmp_reloc.type); + + rel->address = val; + rel->addend = addend; + rel->howto = NULL; + + for (index = 0; + index < sizeof(nlm32_sparc_howto_table) / sizeof(reloc_howto_type); + index++) + if (nlm32_sparc_howto_table[index].type == type) { + rel->howto = &nlm32_sparc_howto_table[index]; + break; + } + +#ifdef DEBUG + fprintf (stderr, "%s: address = %08lx, addend = %08lx, type = %d, howto = %08lx\n", + __FUNCTION__, rel->address, rel->addend, type, rel->howto); +#endif + return true; + +} + +/* Write a NetWare sparc reloc. */ + +static boolean +nlm_sparc_write_reloc (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + bfd_vma val; + struct nlm32_sparc_reloc_ext tmp_reloc; + unsigned int index; + int type = -1; + reloc_howto_type *tmp; + + + for (index = 0; + index < sizeof (nlm32_sparc_howto_table) / sizeof(reloc_howto_type); + index++) { + tmp = &nlm32_sparc_howto_table[index]; + + if (tmp->rightshift == rel->howto->rightshift + && tmp->size == rel->howto->size + && tmp->bitsize == rel->howto->bitsize + && tmp->pc_relative == rel->howto->pc_relative + && tmp->bitpos == rel->howto->bitpos + && tmp->src_mask == rel->howto->src_mask + && tmp->dst_mask == rel->howto->dst_mask) { + type = tmp->type; + break; + } + } + if (type == -1) + abort(); + + /* + * Netware wants a list of relocs for each address. + * Format is: + * long offset + * long addend + * char type + * That should be it. + */ + + /* The value we write out is the offset into the appropriate + segment. This offset is the section vma, adjusted by the vma of + the lowest section in that segment, plus the address of the + relocation. */ +#if 0 + val = bfd_get_section_vma (abfd, (*rel->sym_ptr_ptr)->section) + rel->address; +#else + val = bfd_get_section_vma (abfd, sec) + rel->address; +#endif + +#ifdef DEBUG + fprintf (stderr, "%s: val = %08lx, addend = %08lx, type = %d\n", + __FUNCTION__, val, rel->addend, rel->howto->type); +#endif + bfd_put_32 (abfd, val, tmp_reloc.offset); + bfd_put_32 (abfd, rel->addend, tmp_reloc.addend); + bfd_put_8 (abfd, (short)(rel->howto->type), tmp_reloc.type); + + if (bfd_write (&tmp_reloc, 12, 1, abfd) != 12) + return false; + + return true; +} + +/* Mangle relocs for SPARC NetWare. We can just use the standard + SPARC relocs. */ + +static boolean +nlm_sparc_mangle_relocs (abfd, sec, data, offset, count) + bfd *abfd; + asection *sec; + PTR data; + bfd_vma offset; + bfd_size_type count; +{ + return true; +} + +/* Read a NetWare sparc import record */ +static boolean +nlm_sparc_read_import (abfd, sym) + bfd *abfd; + nlmNAME(symbol_type) *sym; +{ + struct nlm_relent *nlm_relocs; /* relocation records for symbol */ + bfd_size_type rcount; /* number of relocs */ + bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* temporary 32-bit value */ + unsigned char symlength; /* length of symbol name */ + char *name; + + /* + * First, read in the number of relocation + * entries for this symbol + */ + if (bfd_read ((PTR) temp, 4, 1, abfd) != 4) + return false; + + rcount = bfd_get_32 (abfd, temp); + + /* + * Next, read in the length of the symbol + */ + + if (bfd_read ((PTR) &symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength)) + return false; + sym -> symbol.the_bfd = abfd; + name = bfd_alloc (abfd, symlength + 1); + if (name == NULL) + return false; + + /* + * Then read in the symbol + */ + + if (bfd_read (name, symlength, 1, abfd) != symlength) + return false; + name[symlength] = '\0'; + sym -> symbol.name = name; + sym -> symbol.flags = 0; + sym -> symbol.value = 0; + sym -> symbol.section = bfd_und_section_ptr; + + /* + * Next, start reading in the relocs. + */ + + nlm_relocs = ((struct nlm_relent *) + bfd_alloc (abfd, rcount * sizeof (struct nlm_relent))); + if (!nlm_relocs) + return false; + sym -> relocs = nlm_relocs; + sym -> rcnt = 0; + while (sym -> rcnt < rcount) + { + asection *section; + + if (nlm_sparc_read_reloc (abfd, sym, §ion, + &nlm_relocs -> reloc) + == false) + return false; + nlm_relocs -> section = section; + nlm_relocs++; + sym -> rcnt++; + } + return true; +} + +static boolean +nlm_sparc_write_import (abfd, sec, rel) + bfd *abfd; + asection *sec; + arelent *rel; +{ + char temp[4]; + asection *code, *data, *bss, *symsec; + bfd_vma base; + + code = bfd_get_section_by_name (abfd, NLM_CODE_NAME); + data = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + bss = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); + symsec = (*rel->sym_ptr_ptr)->section; + + if (symsec == code) { + base = 0; + } else if (symsec == data) { + base = bfd_section_size (abfd, code); + } else if (symsec == bss) { + base = bfd_section_size (abfd, code) + bfd_section_size (abfd, data); + } else + base = 0; + +#ifdef DEBUG + fprintf (stderr, "%s: <%x, 1>\n\t", + __FUNCTION__, base + (*rel->sym_ptr_ptr)->value); +#endif + bfd_put_32 (abfd, base + (*rel->sym_ptr_ptr)->value, temp); + if (bfd_write ((PTR)temp, 4, 1, abfd) != 4) + return false; + bfd_put_32 (abfd, 1, temp); + if (bfd_write ((PTR)temp, 4, 1, abfd) != 4) + return false; + if (nlm_sparc_write_reloc (abfd, sec, rel) == false) + return false; + return true; +} + +/* Write out an external reference. */ + +static boolean +nlm_sparc_write_external (abfd, count, sym, relocs) + bfd *abfd; + bfd_size_type count; + asymbol *sym; + struct reloc_and_sec *relocs; +{ + unsigned int i; + bfd_byte len; + unsigned char temp[NLM_TARGET_LONG_SIZE]; + + bfd_put_32 (abfd, count, temp); + if (bfd_write (temp, sizeof(temp), 1, abfd) != sizeof (temp)) + return false; + + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) != sizeof(bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + return false; + + for (i = 0; i < count; i++) + { + if (nlm_sparc_write_reloc (abfd, relocs[i].sec, + relocs[i].rel) == false) + return false; + } + + return true; +} + +static boolean +nlm_sparc_write_export (abfd, sym, value) + bfd *abfd; + asymbol *sym; + bfd_vma value; +{ + bfd_byte len; + bfd_byte temp[4]; + +#ifdef DEBUG + fprintf (stderr, "%s: <%x, %d, %s>\n", + __FUNCTION__, value, strlen (sym->name), sym->name); +#endif + bfd_put_32 (abfd, value, temp); + len = strlen (sym->name); + + if (bfd_write (temp, 4, 1, abfd) != 4 + || bfd_write (&len, 1, 1, abfd) != 1 + || bfd_write (sym->name, len, 1, abfd) != len) + return false; + + return true; +} + +#undef nlm_swap_fixed_header_in +#undef nlm_swap_fixed_header_out + +#include "nlmswap.h" + +static const struct nlm_backend_data nlm32_sparc_backend = +{ + "NetWare SPARC Module \032", + sizeof (Nlm32_sparc_External_Fixed_Header), + 0, /* optional_prefix_size */ + bfd_arch_sparc, + 0, + false, + 0, /* backend_object_p */ + 0, /* write_prefix_func */ + nlm_sparc_read_reloc, + nlm_sparc_mangle_relocs, + nlm_sparc_read_import, + nlm_sparc_write_import, + 0, /* set_public_section */ + 0, /* get_public_offset */ + nlm_swap_fixed_header_in, + nlm_swap_fixed_header_out, + nlm_sparc_write_external, + nlm_sparc_write_export +}; + +#define TARGET_BIG_NAME "nlm32-sparc" +#define TARGET_BIG_SYM nlmNAME(sparc_vec) +#define TARGET_BACKEND_DATA &nlm32_sparc_backend + +#include "nlm-target.h" diff --git a/contrib/gdb/bfd/nlm32.c b/contrib/gdb/bfd/nlm32.c new file mode 100644 index 000000000000..4730e4fd3499 --- /dev/null +++ b/contrib/gdb/bfd/nlm32.c @@ -0,0 +1,21 @@ +/* NLM (NetWare Loadable Module) 32-bit executable support for BFD. + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 32 +#include "nlmcode.h" diff --git a/contrib/gdb/bfd/nlm64.c b/contrib/gdb/bfd/nlm64.c new file mode 100644 index 000000000000..5dcd96a2b3c6 --- /dev/null +++ b/contrib/gdb/bfd/nlm64.c @@ -0,0 +1,21 @@ +/* NLM (NetWare Loadable Module) 64-bit executable support for BFD. + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 64 +#include "nlmcode.h" diff --git a/contrib/gdb/bfd/nlmcode.h b/contrib/gdb/bfd/nlmcode.h new file mode 100644 index 000000000000..7f828b46b60f --- /dev/null +++ b/contrib/gdb/bfd/nlmcode.h @@ -0,0 +1,2057 @@ +/* NLM (NetWare Loadable Module) executable support for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, using ELF support as the + template. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include /* For strrchr and friends */ +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libnlm.h" + +/* The functions in this file do not use the names they appear to use. + This file is actually compiled multiple times, once for each size + of NLM target we are using. At each size we use a different name, + constructed by the macro nlmNAME. For example, the function which + is named nlm_symbol_type below is actually named nlm32_symbol_type + in the final executable. */ + +#define Nlm_External_Fixed_Header NlmNAME(External_Fixed_Header) +#define Nlm_External_Version_Header NlmNAME(External_Version_Header) +#define Nlm_External_Copyright_Header NlmNAME(External_Copyright_Header) +#define Nlm_External_Extended_Header NlmNAME(External_Extended_Header) +#define Nlm_External_Custom_Header NlmNAME(External_Custom_Header) +#define Nlm_External_Cygnus_Ext_Header NlmNAME(External_Cygnus_Ext_Header) + +#define nlm_symbol_type nlmNAME(symbol_type) +#define nlm_get_symtab_upper_bound nlmNAME(get_symtab_upper_bound) +#define nlm_get_symtab nlmNAME(get_symtab) +#define nlm_make_empty_symbol nlmNAME(make_empty_symbol) +#define nlm_print_symbol nlmNAME(print_symbol) +#define nlm_get_symbol_info nlmNAME(get_symbol_info) +#define nlm_get_reloc_upper_bound nlmNAME(get_reloc_upper_bound) +#define nlm_canonicalize_reloc nlmNAME(canonicalize_reloc) +#define nlm_object_p nlmNAME(object_p) +#define nlm_set_section_contents nlmNAME(set_section_contents) +#define nlm_write_object_contents nlmNAME(write_object_contents) + +#define nlm_swap_fixed_header_in(abfd,src,dst) \ + (nlm_swap_fixed_header_in_func(abfd))(abfd,src,dst) +#define nlm_swap_fixed_header_out(abfd,src,dst) \ + (nlm_swap_fixed_header_out_func(abfd))(abfd,src,dst) + +/* Forward declarations of static functions */ + +static boolean add_bfd_section + PARAMS ((bfd *, char *, file_ptr, bfd_size_type, flagword)); +static boolean nlm_swap_variable_header_in + PARAMS ((bfd *)); +static boolean nlm_swap_variable_header_out + PARAMS ((bfd *)); +static boolean find_nonzero + PARAMS ((PTR, size_t)); +static boolean nlm_swap_auxiliary_headers_in + PARAMS ((bfd *)); +static boolean nlm_swap_auxiliary_headers_out + PARAMS ((bfd *)); +static boolean nlm_slurp_symbol_table + PARAMS ((bfd *)); +static boolean nlm_slurp_reloc_fixups + PARAMS ((bfd *)); +static boolean nlm_compute_section_file_positions + PARAMS ((bfd *)); +static int nlm_external_reloc_compare + PARAMS ((const void *, const void *)); + +/* Should perhaps use put_offset, put_word, etc. For now, the two versions + can be handled by explicitly specifying 32 bits or "the long type". */ +#if ARCH_SIZE == 64 +#define put_word bfd_h_put_64 +#define get_word bfd_h_get_64 +#endif +#if ARCH_SIZE == 32 +#define put_word bfd_h_put_32 +#define get_word bfd_h_get_32 +#endif + +const bfd_target * +nlm_object_p (abfd) + bfd *abfd; +{ + struct nlm_obj_tdata *preserved_tdata = nlm_tdata (abfd); + boolean (*backend_object_p) PARAMS ((bfd *)); + PTR x_fxdhdr = NULL; + Nlm_Internal_Fixed_Header *i_fxdhdrp; + struct nlm_obj_tdata *new_tdata = NULL; + const char *signature; + enum bfd_architecture arch; + + /* Some NLM formats have a prefix before the standard NLM fixed + header. */ + backend_object_p = nlm_backend_object_p_func (abfd); + if (backend_object_p) + { + if (!(*backend_object_p) (abfd)) + goto got_wrong_format_error; + } + + /* Read in the fixed length portion of the NLM header in external format. */ + + x_fxdhdr = (PTR) bfd_malloc ((size_t) nlm_fixed_header_size (abfd)); + if (x_fxdhdr == NULL) + goto got_no_match; + + if (bfd_read ((PTR) x_fxdhdr, nlm_fixed_header_size (abfd), 1, abfd) != + nlm_fixed_header_size (abfd)) + { + if (bfd_get_error () != bfd_error_system_call) + goto got_wrong_format_error; + else + goto got_no_match; + } + + /* Allocate an instance of the nlm_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + new_tdata = ((struct nlm_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct nlm_obj_tdata))); + if (new_tdata == NULL) + goto got_no_match; + + nlm_tdata (abfd) = new_tdata; + + i_fxdhdrp = nlm_fixed_header (abfd); + nlm_swap_fixed_header_in (abfd, x_fxdhdr, i_fxdhdrp); + free (x_fxdhdr); + x_fxdhdr = NULL; + + /* Check to see if we have an NLM file for this backend by matching + the NLM signature. */ + + signature = nlm_signature (abfd); + if (signature != NULL + && *signature != '\0' + && strncmp ((char *) i_fxdhdrp->signature, signature, + NLM_SIGNATURE_SIZE) != 0) + goto got_wrong_format_error; + + /* There's no supported way to discover the endianess of an NLM, so test for + a sane version number after doing byte swapping appropriate for this + XVEC. (Hack alert!) */ + + if (i_fxdhdrp->version > 0xFFFF) + goto got_wrong_format_error; + + /* There's no supported way to check for 32 bit versus 64 bit addresses, + so ignore this distinction for now. (FIXME) */ + + /* Swap in the rest of the required header. */ + if (!nlm_swap_variable_header_in (abfd)) + { + if (bfd_get_error () != bfd_error_system_call) + goto got_wrong_format_error; + else + goto got_no_match; + } + + /* Add the sections supplied by all NLM's, and then read in the + auxiliary headers. Reading the auxiliary headers may create + additional sections described in the cygnus_ext header. + From this point on we assume that we have an NLM, and do not + treat errors as indicating the wrong format. */ + + if (!add_bfd_section (abfd, NLM_CODE_NAME, + i_fxdhdrp->codeImageOffset, + i_fxdhdrp->codeImageSize, + (SEC_CODE | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_RELOC)) + || !add_bfd_section (abfd, NLM_INITIALIZED_DATA_NAME, + i_fxdhdrp->dataImageOffset, + i_fxdhdrp->dataImageSize, + (SEC_DATA | SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_RELOC)) + || !add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME, + (file_ptr) 0, + i_fxdhdrp->uninitializedDataSize, + SEC_ALLOC)) + goto got_no_match; + + if (!nlm_swap_auxiliary_headers_in (abfd)) + goto got_no_match; + + if (nlm_fixed_header (abfd)->numberOfRelocationFixups != 0 + || nlm_fixed_header (abfd)->numberOfExternalReferences != 0) + abfd->flags |= HAS_RELOC; + if (nlm_fixed_header (abfd)->numberOfPublics != 0 + || nlm_fixed_header (abfd)->numberOfDebugRecords != 0 + || nlm_fixed_header (abfd)->numberOfExternalReferences != 0) + abfd->flags |= HAS_SYMS; + + arch = nlm_architecture (abfd); + if (arch != bfd_arch_unknown) + bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0); + + abfd->flags |= EXEC_P; + bfd_get_start_address (abfd) = nlm_fixed_header (abfd)->codeStartOffset; + + return (abfd->xvec); + +got_wrong_format_error: + bfd_set_error (bfd_error_wrong_format); +got_no_match: + nlm_tdata (abfd) = preserved_tdata; + if (new_tdata != NULL) + bfd_release (abfd, new_tdata); + if (x_fxdhdr != NULL) + free (x_fxdhdr); + return (NULL); +} + +/* Add a section to the bfd. */ + +static boolean +add_bfd_section (abfd, name, offset, size, flags) + bfd *abfd; + char *name; + file_ptr offset; + bfd_size_type size; + flagword flags; +{ + asection *newsect; + + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + { + return (false); + } + newsect->vma = 0; /* NLM's are relocatable. */ + newsect->_raw_size = size; + newsect->filepos = offset; + newsect->flags = flags; + newsect->alignment_power = bfd_log2 (0); /* FIXME */ + return (true); +} + +/* Read and swap in the variable length header. All the fields must + exist in the NLM, and must exist in the order they are read here. */ + +static boolean +nlm_swap_variable_header_in (abfd) + bfd *abfd; +{ + unsigned char temp[NLM_TARGET_LONG_SIZE]; + + /* Read the description length and text members. */ + + if (bfd_read ((PTR) & nlm_variable_header (abfd)->descriptionLength, + sizeof (nlm_variable_header (abfd)->descriptionLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->descriptionLength)) + return (false); + if (bfd_read ((PTR) nlm_variable_header (abfd)->descriptionText, + nlm_variable_header (abfd)->descriptionLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->descriptionLength + 1) + return (false); + + /* Read and convert the stackSize field. */ + + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + nlm_variable_header (abfd)->stackSize = get_word (abfd, (bfd_byte *) temp); + + /* Read and convert the reserved field. */ + + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + nlm_variable_header (abfd)->reserved = get_word (abfd, (bfd_byte *) temp); + + /* Read the oldThreadName field. This field is a fixed length string. */ + + if (bfd_read ((PTR) nlm_variable_header (abfd)->oldThreadName, + sizeof (nlm_variable_header (abfd)->oldThreadName), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->oldThreadName)) + return (false); + + /* Read the screen name length and text members. */ + + if (bfd_read ((PTR) & nlm_variable_header (abfd)->screenNameLength, + sizeof (nlm_variable_header (abfd)->screenNameLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->screenNameLength)) + return (false); + if (bfd_read ((PTR) nlm_variable_header (abfd)->screenName, + nlm_variable_header (abfd)->screenNameLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->screenNameLength + 1) + return (false); + + /* Read the thread name length and text members. */ + + if (bfd_read ((PTR) & nlm_variable_header (abfd)->threadNameLength, + sizeof (nlm_variable_header (abfd)->threadNameLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->threadNameLength)) + return (false); + if (bfd_read ((PTR) nlm_variable_header (abfd)->threadName, + nlm_variable_header (abfd)->threadNameLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->threadNameLength + 1) + return (false); + return (true); +} + +/* Swap and write out the variable length header. All the fields must + exist in the NLM, and must exist in this order. */ + +static boolean +nlm_swap_variable_header_out (abfd) + bfd *abfd; +{ + unsigned char temp[NLM_TARGET_LONG_SIZE]; + + /* Write the description length and text members. */ + + if (bfd_write ((PTR) & nlm_variable_header (abfd)->descriptionLength, + sizeof (nlm_variable_header (abfd)->descriptionLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->descriptionLength)) + return (false); + if (bfd_write ((PTR) nlm_variable_header (abfd)->descriptionText, + nlm_variable_header (abfd)->descriptionLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->descriptionLength + 1) + return (false); + + /* Convert and write the stackSize field. */ + + put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->stackSize, + (bfd_byte *) temp); + if (bfd_write ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + + /* Convert and write the reserved field. */ + + put_word (abfd, (bfd_vma) nlm_variable_header (abfd)->reserved, + (bfd_byte *) temp); + if (bfd_write ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + + /* Write the oldThreadName field. This field is a fixed length string. */ + + if (bfd_write ((PTR) nlm_variable_header (abfd)->oldThreadName, + sizeof (nlm_variable_header (abfd)->oldThreadName), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->oldThreadName)) + return (false); + + /* Write the screen name length and text members. */ + + if (bfd_write ((PTR) & nlm_variable_header (abfd)->screenNameLength, + sizeof (nlm_variable_header (abfd)->screenNameLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->screenNameLength)) + return (false); + if (bfd_write ((PTR) nlm_variable_header (abfd)->screenName, + nlm_variable_header (abfd)->screenNameLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->screenNameLength + 1) + return (false); + + /* Write the thread name length and text members. */ + + if (bfd_write ((PTR) & nlm_variable_header (abfd)->threadNameLength, + sizeof (nlm_variable_header (abfd)->threadNameLength), + 1, abfd) != + sizeof (nlm_variable_header (abfd)->threadNameLength)) + return (false); + if (bfd_write ((PTR) nlm_variable_header (abfd)->threadName, + nlm_variable_header (abfd)->threadNameLength + 1, + 1, abfd) != + (bfd_size_type) nlm_variable_header (abfd)->threadNameLength + 1) + return (false); + return (true); +} + +/* Read and swap in the contents of all the auxiliary headers. Because of + the braindead design, we have to do strcmps on strings of indeterminate + length to figure out what each auxiliary header is. Even worse, we have + no way of knowing how many auxiliary headers there are or where the end + of the auxiliary headers are, except by finding something that doesn't + look like a known auxiliary header. This means that the first new type + of auxiliary header added will break all existing tools that don't + recognize it. */ + +static boolean +nlm_swap_auxiliary_headers_in (abfd) + bfd *abfd; +{ + char tempstr[16]; + long position; + + for (;;) + { + position = bfd_tell (abfd); + if (bfd_read ((PTR) tempstr, sizeof (tempstr), 1, abfd) != + sizeof (tempstr)) + return (false); + if (bfd_seek (abfd, position, SEEK_SET) == -1) + return (false); + if (strncmp (tempstr, "VeRsIoN#", 8) == 0) + { + Nlm_External_Version_Header thdr; + if (bfd_read ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return (false); + memcpy (nlm_version_header (abfd)->stamp, thdr.stamp, + sizeof (thdr.stamp)); + nlm_version_header (abfd)->majorVersion = + get_word (abfd, (bfd_byte *) thdr.majorVersion); + nlm_version_header (abfd)->minorVersion = + get_word (abfd, (bfd_byte *) thdr.minorVersion); + nlm_version_header (abfd)->revision = + get_word (abfd, (bfd_byte *) thdr.revision); + nlm_version_header (abfd)->year = + get_word (abfd, (bfd_byte *) thdr.year); + nlm_version_header (abfd)->month = + get_word (abfd, (bfd_byte *) thdr.month); + nlm_version_header (abfd)->day = + get_word (abfd, (bfd_byte *) thdr.day); + } + else if (strncmp (tempstr, "MeSsAgEs", 8) == 0) + { + Nlm_External_Extended_Header thdr; + if (bfd_read ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return (false); + memcpy (nlm_extended_header (abfd)->stamp, thdr.stamp, + sizeof (thdr.stamp)); + nlm_extended_header (abfd)->languageID = + get_word (abfd, (bfd_byte *) thdr.languageID); + nlm_extended_header (abfd)->messageFileOffset = + get_word (abfd, (bfd_byte *) thdr.messageFileOffset); + nlm_extended_header (abfd)->messageFileLength = + get_word (abfd, (bfd_byte *) thdr.messageFileLength); + nlm_extended_header (abfd)->messageCount = + get_word (abfd, (bfd_byte *) thdr.messageCount); + nlm_extended_header (abfd)->helpFileOffset = + get_word (abfd, (bfd_byte *) thdr.helpFileOffset); + nlm_extended_header (abfd)->helpFileLength = + get_word (abfd, (bfd_byte *) thdr.helpFileLength); + nlm_extended_header (abfd)->RPCDataOffset = + get_word (abfd, (bfd_byte *) thdr.RPCDataOffset); + nlm_extended_header (abfd)->RPCDataLength = + get_word (abfd, (bfd_byte *) thdr.RPCDataLength); + nlm_extended_header (abfd)->sharedCodeOffset = + get_word (abfd, (bfd_byte *) thdr.sharedCodeOffset); + nlm_extended_header (abfd)->sharedCodeLength = + get_word (abfd, (bfd_byte *) thdr.sharedCodeLength); + nlm_extended_header (abfd)->sharedDataOffset = + get_word (abfd, (bfd_byte *) thdr.sharedDataOffset); + nlm_extended_header (abfd)->sharedDataLength = + get_word (abfd, (bfd_byte *) thdr.sharedDataLength); + nlm_extended_header (abfd)->sharedRelocationFixupOffset = + get_word (abfd, (bfd_byte *) thdr.sharedRelocationFixupOffset); + nlm_extended_header (abfd)->sharedRelocationFixupCount = + get_word (abfd, (bfd_byte *) thdr.sharedRelocationFixupCount); + nlm_extended_header (abfd)->sharedExternalReferenceOffset = + get_word (abfd, (bfd_byte *) thdr.sharedExternalReferenceOffset); + nlm_extended_header (abfd)->sharedExternalReferenceCount = + get_word (abfd, (bfd_byte *) thdr.sharedExternalReferenceCount); + nlm_extended_header (abfd)->sharedPublicsOffset = + get_word (abfd, (bfd_byte *) thdr.sharedPublicsOffset); + nlm_extended_header (abfd)->sharedPublicsCount = + get_word (abfd, (bfd_byte *) thdr.sharedPublicsCount); + nlm_extended_header (abfd)->sharedDebugRecordOffset = + get_word (abfd, (bfd_byte *) thdr.sharedDebugRecordOffset); + nlm_extended_header (abfd)->sharedDebugRecordCount = + get_word (abfd, (bfd_byte *) thdr.sharedDebugRecordCount); + nlm_extended_header (abfd)->SharedInitializationOffset = + get_word (abfd, (bfd_byte *) thdr.sharedInitializationOffset); + nlm_extended_header (abfd)->SharedExitProcedureOffset = + get_word (abfd, (bfd_byte *) thdr.SharedExitProcedureOffset); + nlm_extended_header (abfd)->productID = + get_word (abfd, (bfd_byte *) thdr.productID); + nlm_extended_header (abfd)->reserved0 = + get_word (abfd, (bfd_byte *) thdr.reserved0); + nlm_extended_header (abfd)->reserved1 = + get_word (abfd, (bfd_byte *) thdr.reserved1); + nlm_extended_header (abfd)->reserved2 = + get_word (abfd, (bfd_byte *) thdr.reserved2); + nlm_extended_header (abfd)->reserved3 = + get_word (abfd, (bfd_byte *) thdr.reserved3); + nlm_extended_header (abfd)->reserved4 = + get_word (abfd, (bfd_byte *) thdr.reserved4); + nlm_extended_header (abfd)->reserved5 = + get_word (abfd, (bfd_byte *) thdr.reserved5); + } + else if (strncmp (tempstr, "CoPyRiGhT=", 10) == 0) + { + if (bfd_read ((PTR) nlm_copyright_header (abfd)->stamp, + sizeof (nlm_copyright_header (abfd)->stamp), + 1, abfd) + != sizeof (nlm_copyright_header (abfd)->stamp)) + return (false); + if (bfd_read ((PTR) & (nlm_copyright_header (abfd) + ->copyrightMessageLength), + 1, 1, abfd) != 1) + return (false); + /* The copyright message is a variable length string. */ + if (bfd_read ((PTR) nlm_copyright_header (abfd)->copyrightMessage, + nlm_copyright_header (abfd)->copyrightMessageLength + 1, + 1, abfd) != + ((bfd_size_type) + nlm_copyright_header (abfd)->copyrightMessageLength + 1)) + return (false); + } + else if (strncmp (tempstr, "CuStHeAd", 8) == 0) + { + Nlm_External_Custom_Header thdr; + bfd_size_type hdrLength; + file_ptr dataOffset; + bfd_size_type dataLength; + char dataStamp[8]; + PTR hdr; + + /* Read the stamp ("CuStHeAd"). */ + if (bfd_read ((PTR) thdr.stamp, 1, sizeof (thdr.stamp), abfd) + != sizeof (thdr.stamp)) + return false; + /* Read the length of this custom header. */ + if (bfd_read ((PTR) thdr.length, 1, sizeof (thdr.length), abfd) + != sizeof (thdr.length)) + return false; + hdrLength = get_word (abfd, (bfd_byte *) thdr.length); + /* Read further fields if we have them. */ + if (hdrLength < NLM_TARGET_LONG_SIZE) + dataOffset = 0; + else + { + if (bfd_read ((PTR) thdr.dataOffset, 1, + sizeof (thdr.dataOffset), abfd) + != sizeof (thdr.dataOffset)) + return false; + dataOffset = get_word (abfd, (bfd_byte *) thdr.dataOffset); + } + if (hdrLength < 2 * NLM_TARGET_LONG_SIZE) + dataLength = 0; + else + { + if (bfd_read ((PTR) thdr.dataLength, 1, + sizeof (thdr.dataLength), abfd) + != sizeof (thdr.dataLength)) + return false; + dataLength = get_word (abfd, (bfd_byte *) thdr.dataLength); + } + if (hdrLength < 2 * NLM_TARGET_LONG_SIZE + 8) + memset (dataStamp, 0, sizeof (dataStamp)); + else + { + if (bfd_read ((PTR) dataStamp, 1, sizeof (dataStamp), abfd) + != sizeof (dataStamp)) + return false; + } + + /* Read the rest of the header, if any. */ + if (hdrLength <= 2 * NLM_TARGET_LONG_SIZE + 8) + { + hdr = NULL; + hdrLength = 0; + } + else + { + hdrLength -= 2 * NLM_TARGET_LONG_SIZE + 8; + hdr = bfd_alloc (abfd, hdrLength); + if (hdr == NULL) + return false; + if (bfd_read (hdr, 1, hdrLength, abfd) != hdrLength) + return false; + } + + /* If we have found a Cygnus header, process it. Otherwise, + just save the associated data without trying to interpret + it. */ + if (strncmp (dataStamp, "CyGnUsEx", 8) == 0) + { + file_ptr pos; + bfd_byte *contents; + bfd_byte *p, *pend; + + BFD_ASSERT (hdrLength == 0 && hdr == NULL); + + pos = bfd_tell (abfd); + if (bfd_seek (abfd, dataOffset, SEEK_SET) != 0) + return false; + contents = (bfd_byte *) bfd_alloc (abfd, dataLength); + if (contents == NULL) + return false; + if (bfd_read (contents, 1, dataLength, abfd) != dataLength) + return false; + if (bfd_seek (abfd, pos, SEEK_SET) != 0) + return false; + + memcpy (nlm_cygnus_ext_header (abfd), "CyGnUsEx", 8); + nlm_cygnus_ext_header (abfd)->offset = dataOffset; + nlm_cygnus_ext_header (abfd)->length = dataLength; + + /* This data this header points to provides a list of + the sections which were in the original object file + which was converted to become an NLM. We locate + those sections and add them to the BFD. Note that + this is likely to create a second .text, .data and + .bss section; retrieving the sections by name will + get the actual NLM sections, which is what we want to + happen. The sections from the original file, which + may be subsets of the NLM section, can only be found + using bfd_map_over_sections. */ + p = contents; + pend = p + dataLength; + while (p < pend) + { + char *name; + size_t l; + file_ptr filepos; + bfd_size_type size; + asection *newsec; + + /* The format of this information is + null terminated section name + zeroes to adjust to 4 byte boundary + 4 byte section data file pointer + 4 byte section size + */ + + name = (char *) p; + l = strlen (name) + 1; + l = (l + 3) &~ 3; + p += l; + filepos = bfd_h_get_32 (abfd, p); + p += 4; + size = bfd_h_get_32 (abfd, p); + p += 4; + + newsec = bfd_make_section_anyway (abfd, name); + if (newsec == (asection *) NULL) + return false; + newsec->_raw_size = size; + if (filepos != 0) + { + newsec->filepos = filepos; + newsec->flags |= SEC_HAS_CONTENTS; + } + } + } + else + { + memcpy (nlm_custom_header (abfd)->stamp, thdr.stamp, + sizeof (thdr.stamp)); + nlm_custom_header (abfd)->hdrLength = hdrLength; + nlm_custom_header (abfd)->dataOffset = dataOffset; + nlm_custom_header (abfd)->dataLength = dataLength; + memcpy (nlm_custom_header (abfd)->dataStamp, dataStamp, + sizeof (dataStamp)); + nlm_custom_header (abfd)->hdr = hdr; + } + } + else + { + break; + } + } + return (true); +} + +/* Return whether there is a non-zero byte in a memory block. */ + +static boolean +find_nonzero (buf, size) + PTR buf; + size_t size; +{ + char *p = (char *) buf; + + while (size-- != 0) + if (*p++ != 0) + return true; + return false; +} + +/* Swap out the contents of the auxiliary headers. We create those + auxiliary headers which have been set non-zero. We do not require + the caller to set up the stamp fields. */ + +static boolean +nlm_swap_auxiliary_headers_out (abfd) + bfd *abfd; +{ + /* Write out the version header if there is one. */ + if (find_nonzero ((PTR) nlm_version_header (abfd), + sizeof (Nlm_Internal_Version_Header))) + { + Nlm_External_Version_Header thdr; + + memcpy (thdr.stamp, "VeRsIoN#", 8); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->majorVersion, + (bfd_byte *) thdr.majorVersion); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->minorVersion, + (bfd_byte *) thdr.minorVersion); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->revision, + (bfd_byte *) thdr.revision); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->year, + (bfd_byte *) thdr.year); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->month, + (bfd_byte *) thdr.month); + put_word (abfd, (bfd_vma) nlm_version_header (abfd)->day, + (bfd_byte *) thdr.day); + if (bfd_write ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; + } + + /* Write out the extended header if there is one. */ + if (find_nonzero ((PTR) nlm_extended_header (abfd), + sizeof (Nlm_Internal_Extended_Header))) + { + Nlm_External_Extended_Header thdr; + + memcpy (thdr.stamp, "MeSsAgEs", 8); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->languageID, + (bfd_byte *) thdr.languageID); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->messageFileOffset, + (bfd_byte *) thdr.messageFileOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->messageFileLength, + (bfd_byte *) thdr.messageFileLength); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->messageCount, + (bfd_byte *) thdr.messageCount); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->helpFileOffset, + (bfd_byte *) thdr.helpFileOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->helpFileLength, + (bfd_byte *) thdr.helpFileLength); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->RPCDataOffset, + (bfd_byte *) thdr.RPCDataOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->RPCDataLength, + (bfd_byte *) thdr.RPCDataLength); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedCodeOffset, + (bfd_byte *) thdr.sharedCodeOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedCodeLength, + (bfd_byte *) thdr.sharedCodeLength); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedDataOffset, + (bfd_byte *) thdr.sharedDataOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedDataLength, + (bfd_byte *) thdr.sharedDataLength); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupOffset, + (bfd_byte *) thdr.sharedRelocationFixupOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedRelocationFixupCount, + (bfd_byte *) thdr.sharedRelocationFixupCount); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceOffset, + (bfd_byte *) thdr.sharedExternalReferenceOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedExternalReferenceCount, + (bfd_byte *) thdr.sharedExternalReferenceCount); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedPublicsOffset, + (bfd_byte *) thdr.sharedPublicsOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedPublicsCount, + (bfd_byte *) thdr.sharedPublicsCount); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordOffset, + (bfd_byte *) thdr.sharedDebugRecordOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->sharedDebugRecordCount, + (bfd_byte *) thdr.sharedDebugRecordCount); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->SharedInitializationOffset, + (bfd_byte *) thdr.sharedInitializationOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->SharedExitProcedureOffset, + (bfd_byte *) thdr.SharedExitProcedureOffset); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->productID, + (bfd_byte *) thdr.productID); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved0, + (bfd_byte *) thdr.reserved0); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved1, + (bfd_byte *) thdr.reserved1); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved2, + (bfd_byte *) thdr.reserved2); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved3, + (bfd_byte *) thdr.reserved3); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved4, + (bfd_byte *) thdr.reserved4); + put_word (abfd, + (bfd_vma) nlm_extended_header (abfd)->reserved5, + (bfd_byte *) thdr.reserved5); + if (bfd_write ((PTR) & thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; + } + + + /* Write out the copyright header if there is one. */ + if (find_nonzero ((PTR) nlm_copyright_header (abfd), + sizeof (Nlm_Internal_Copyright_Header))) + { + Nlm_External_Copyright_Header thdr; + + memcpy (thdr.stamp, "CoPyRiGhT=", 10); + if (bfd_write ((PTR) thdr.stamp, sizeof (thdr.stamp), 1, abfd) + != sizeof (thdr.stamp)) + return false; + thdr.copyrightMessageLength[0] = + nlm_copyright_header (abfd)->copyrightMessageLength; + if (bfd_write ((PTR) thdr.copyrightMessageLength, 1, 1, abfd) != 1) + return false; + /* The copyright message is a variable length string. */ + if (bfd_write ((PTR) nlm_copyright_header (abfd)->copyrightMessage, + nlm_copyright_header (abfd)->copyrightMessageLength + 1, + 1, abfd) != + ((bfd_size_type) + nlm_copyright_header (abfd)->copyrightMessageLength + 1)) + return false; + } + + /* Write out the custom header if there is one. */ + if (find_nonzero ((PTR) nlm_custom_header (abfd), + sizeof (Nlm_Internal_Custom_Header))) + { + Nlm_External_Custom_Header thdr; + boolean ds; + bfd_size_type hdrLength; + + ds = find_nonzero ((PTR) nlm_custom_header (abfd)->dataStamp, + sizeof (nlm_custom_header (abfd)->dataStamp)); + memcpy (thdr.stamp, "CuStHeAd", 8); + hdrLength = (2 * NLM_TARGET_LONG_SIZE + (ds ? 8 : 0) + + nlm_custom_header (abfd)->hdrLength); + put_word (abfd, hdrLength, thdr.length); + put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataOffset, + thdr.dataOffset); + put_word (abfd, (bfd_vma) nlm_custom_header (abfd)->dataLength, + thdr.dataLength); + if (! ds) + { + BFD_ASSERT (nlm_custom_header (abfd)->hdrLength == 0); + if (bfd_write ((PTR) &thdr, 1, + sizeof (thdr) - sizeof (thdr.dataStamp), abfd) + != sizeof (thdr) - sizeof (thdr.dataStamp)) + return false; + } + else + { + memcpy (thdr.dataStamp, nlm_custom_header (abfd)->dataStamp, + sizeof (thdr.dataStamp)); + if (bfd_write ((PTR) &thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; + if (bfd_write (nlm_custom_header (abfd)->hdr, 1, + nlm_custom_header (abfd)->hdrLength, abfd) + != nlm_custom_header (abfd)->hdrLength) + return false; + } + } + + /* Write out the Cygnus debugging header if there is one. */ + if (find_nonzero ((PTR) nlm_cygnus_ext_header (abfd), + sizeof (Nlm_Internal_Cygnus_Ext_Header))) + { + Nlm_External_Custom_Header thdr; + + memcpy (thdr.stamp, "CuStHeAd", 8); + put_word (abfd, (bfd_vma) 2 * NLM_TARGET_LONG_SIZE + 8, + (bfd_byte *) thdr.length); + put_word (abfd, (bfd_vma) nlm_cygnus_ext_header (abfd)->offset, + (bfd_byte *) thdr.dataOffset); + put_word (abfd, (bfd_vma) nlm_cygnus_ext_header (abfd)->length, + (bfd_byte *) thdr.dataLength); + memcpy (thdr.dataStamp, "CyGnUsEx", 8); + if (bfd_write ((PTR) &thdr, sizeof (thdr), 1, abfd) != sizeof (thdr)) + return false; + } + + return true; +} + +/* We read the NLM's public symbols and use it to generate a bfd symbol + table (hey, it's better than nothing) on a one-for-one basis. Thus + use the number of public symbols as the number of bfd symbols we will + have once we actually get around to reading them in. + + Return the number of bytes required to hold the symtab vector, based on + the count plus 1, since we will NULL terminate the vector allocated based + on this size. */ + +long +nlm_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + Nlm_Internal_Fixed_Header *i_fxdhdrp; /* Nlm file header, internal form */ + long symcount; + long symtab_size = 0; + + i_fxdhdrp = nlm_fixed_header (abfd); + symcount = (i_fxdhdrp->numberOfPublics + + i_fxdhdrp->numberOfDebugRecords + + i_fxdhdrp->numberOfExternalReferences); + symtab_size = (symcount + 1) * (sizeof (asymbol)); + return (symtab_size); +} + +/* Note that bfd_get_symcount is guaranteed to be zero if slurping the + symbol table fails. */ + +long +nlm_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + nlm_symbol_type *symbase; + bfd_size_type counter = 0; + + if (nlm_slurp_symbol_table (abfd) == false) + return -1; + symbase = nlm_get_symbols (abfd); + while (counter < bfd_get_symcount (abfd)) + { + *alocation++ = &symbase->symbol; + symbase++; + counter++; + } + *alocation = (asymbol *) NULL; + return bfd_get_symcount (abfd); +} + +/* Make an NLM symbol. There is nothing special to do here. */ + +asymbol * +nlm_make_empty_symbol (abfd) + bfd *abfd; +{ + nlm_symbol_type *new; + + new = (nlm_symbol_type *) bfd_zalloc (abfd, sizeof (nlm_symbol_type)); + if (new) + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Get symbol information. */ + +void +nlm_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Print symbol information. */ + +void +nlm_print_symbol (abfd, afile, symbol, how) + bfd *abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + + switch (how) + { + case bfd_print_symbol_name: + case bfd_print_symbol_more: + if (symbol->name) + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_all: + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s", symbol->section->name); + if (symbol->name) + fprintf (file, " %s", symbol->name); + break; + } +} + +/* Slurp in nlm symbol table. + + In the external (in-file) form, NLM export records are variable length, + with the following form: + + 1 byte length of the symbol name (N) + N bytes the symbol name + 4 bytes the symbol offset from start of it's section + + We also read in the debugging symbols and import records. Import + records are treated as undefined symbols. As we read the import + records we also read in the associated reloc information, which is + attached to the symbol. + + The bfd symbols are copied to SYMPTRS. + + When we return, the bfd symcount is either zero or contains the correct + number of symbols. +*/ + +static boolean +nlm_slurp_symbol_table (abfd) + bfd *abfd; +{ + Nlm_Internal_Fixed_Header *i_fxdhdrp; /* Nlm file header, internal form */ + bfd_size_type totsymcount; /* Number of NLM symbols */ + bfd_size_type symcount; /* Counter of NLM symbols */ + nlm_symbol_type *sym; /* Pointer to current bfd symbol */ + unsigned char symlength; /* Symbol length read into here */ + unsigned char symtype; /* Type of debugging symbol */ + bfd_byte temp[NLM_TARGET_LONG_SIZE]; /* Symbol offsets read into here */ + boolean (*read_import_func) PARAMS ((bfd *, nlm_symbol_type *)); + boolean (*set_public_section_func) PARAMS ((bfd *, nlm_symbol_type *)); + + if (nlm_get_symbols (abfd) != NULL) + return (true); + + /* Read each raw NLM symbol, using the information to create a canonical bfd + symbol table entry. + + Note that we allocate the initial bfd canonical symbol buffer based on a + one-to-one mapping of the NLM symbols to canonical symbols. We actually + use all the NLM symbols, so there will be no space left over at the end. + When we have all the symbols, we build the caller's pointer vector. */ + + abfd->symcount = 0; + i_fxdhdrp = nlm_fixed_header (abfd); + totsymcount = (i_fxdhdrp->numberOfPublics + + i_fxdhdrp->numberOfDebugRecords + + i_fxdhdrp->numberOfExternalReferences); + if (totsymcount == 0) + { + return (true); + } + + if (bfd_seek (abfd, i_fxdhdrp->publicsOffset, SEEK_SET) == -1) + return (false); + + sym = ((nlm_symbol_type *) + bfd_zalloc (abfd, totsymcount * sizeof (nlm_symbol_type))); + if (!sym) + return false; + nlm_set_symbols (abfd, sym); + + /* We use the bfd's symcount directly as the control count, so that early + termination of the loop leaves the symcount correct for the symbols that + were read. */ + + set_public_section_func = nlm_set_public_section_func (abfd); + symcount = i_fxdhdrp->numberOfPublics; + while (abfd->symcount < symcount) + { + if (bfd_read ((PTR) & symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength)) + return (false); + sym->symbol.the_bfd = abfd; + sym->symbol.name = bfd_alloc (abfd, symlength + 1); + if (!sym->symbol.name) + return false; + if (bfd_read ((PTR) sym->symbol.name, symlength, 1, abfd) + != symlength) + return (false); + /* Cast away const. */ + ((char *) (sym->symbol.name))[symlength] = '\0'; + if (bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp)) + return (false); + sym->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + sym->symbol.value = get_word (abfd, temp); + if (set_public_section_func) + { + /* Most backends can use the code below, but unfortunately + some use a different scheme. */ + if ((*set_public_section_func) (abfd, sym) == false) + return false; + } + else + { + if (sym->symbol.value & NLM_HIBIT) + { + sym->symbol.value &= ~NLM_HIBIT; + sym->symbol.flags |= BSF_FUNCTION; + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_CODE_NAME); + } + else + { + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + } + } + sym->rcnt = 0; + abfd->symcount++; + sym++; + } + + /* Read the debugging records. */ + + if (i_fxdhdrp->numberOfDebugRecords > 0) + { + if (bfd_seek (abfd, i_fxdhdrp->debugInfoOffset, SEEK_SET) == -1) + return (false); + + symcount += i_fxdhdrp->numberOfDebugRecords; + while (abfd->symcount < symcount) + { + if ((bfd_read ((PTR) & symtype, sizeof (symtype), 1, abfd) + != sizeof (symtype)) + || bfd_read ((PTR) temp, sizeof (temp), 1, abfd) != sizeof (temp) + || (bfd_read ((PTR) & symlength, sizeof (symlength), 1, abfd) + != sizeof (symlength))) + return false; + sym->symbol.the_bfd = abfd; + sym->symbol.name = bfd_alloc (abfd, symlength + 1); + if (!sym->symbol.name) + return false; + if (bfd_read ((PTR) sym->symbol.name, symlength, 1, abfd) + != symlength) + return (false); + /* Cast away const. */ + ((char *) (sym->symbol.name))[symlength] = '\0'; + sym->symbol.flags = BSF_LOCAL; + sym->symbol.value = get_word (abfd, temp); + if (symtype == 0) + { + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME); + } + else if (symtype == 1) + { + sym->symbol.flags |= BSF_FUNCTION; + sym->symbol.section = + bfd_get_section_by_name (abfd, NLM_CODE_NAME); + } + else + { + sym->symbol.section = bfd_abs_section_ptr; + } + sym->rcnt = 0; + abfd->symcount++; + sym++; + } + } + + /* Read in the import records. We can only do this if we know how + to read relocs for this target. */ + + read_import_func = nlm_read_import_func (abfd); + if (read_import_func != NULL) + { + if (bfd_seek (abfd, i_fxdhdrp->externalReferencesOffset, SEEK_SET) + == -1) + return (false); + + symcount += i_fxdhdrp->numberOfExternalReferences; + while (abfd->symcount < symcount) + { + if ((*read_import_func) (abfd, sym) == false) + return false; + sym++; + abfd->symcount++; + } + } + + return (true); +} + +/* Get the relocs for an NLM file. There are two types of relocs. + Imports are relocs against symbols defined in other NLM files. We + treat these as relocs against global symbols. Relocation fixups + are internal relocs. + + The actual format used to store the relocs is machine specific. */ + +/* Read in the relocation fixup information. This is stored in + nlm_relocation_fixups, an array of arelent structures, and + nlm_relocation_fixup_secs, an array of section pointers. The + section pointers are needed because the relocs are not sorted by + section. */ + +static boolean +nlm_slurp_reloc_fixups (abfd) + bfd *abfd; +{ + boolean (*read_func) PARAMS ((bfd *, nlm_symbol_type *, asection **, + arelent *)); + bfd_size_type count; + arelent *rels; + asection **secs; + + if (nlm_relocation_fixups (abfd) != NULL) + return true; + read_func = nlm_read_reloc_func (abfd); + if (read_func == NULL) + return true; + + if (bfd_seek (abfd, nlm_fixed_header (abfd)->relocationFixupOffset, + SEEK_SET) != 0) + return false; + + count = nlm_fixed_header (abfd)->numberOfRelocationFixups; + rels = (arelent *) bfd_alloc (abfd, count * sizeof (arelent)); + secs = (asection **) bfd_alloc (abfd, count * sizeof (asection *)); + if ((rels == NULL || secs == NULL) && count != 0) + return false; + nlm_relocation_fixups (abfd) = rels; + nlm_relocation_fixup_secs (abfd) = secs; + + /* We have to read piece by piece, because we don't know how large + the machine specific reloc information is. */ + while (count-- != 0) + { + if ((*read_func) (abfd, (nlm_symbol_type *) NULL, secs, rels) == false) + { + nlm_relocation_fixups (abfd) = NULL; + nlm_relocation_fixup_secs (abfd) = NULL; + return false; + } + ++secs; + ++rels; + } + + return true; +} + +/* Get the number of relocs. This really just returns an upper bound, + since it does not attempt to distinguish them based on the section. + That will be handled when they are actually read. */ + +long +nlm_get_reloc_upper_bound (abfd, sec) + bfd *abfd; + asection *sec; +{ + nlm_symbol_type *syms; + bfd_size_type count; + unsigned int ret; + + /* If we don't know how to read relocs, just return 0. */ + if (nlm_read_reloc_func (abfd) == NULL) + return -1; + /* Make sure we have either the code or the data section. */ + if ((bfd_get_section_flags (abfd, sec) & (SEC_CODE | SEC_DATA)) == 0) + return 0; + + syms = nlm_get_symbols (abfd); + if (syms == NULL) + { + if (nlm_slurp_symbol_table (abfd) == false) + return -1; + syms = nlm_get_symbols (abfd); + } + + ret = nlm_fixed_header (abfd)->numberOfRelocationFixups; + + count = bfd_get_symcount (abfd); + while (count-- != 0) + { + ret += syms->rcnt; + ++syms; + } + + return (ret + 1) * sizeof (arelent *); +} + +/* Get the relocs themselves. */ + +long +nlm_canonicalize_reloc (abfd, sec, relptr, symbols) + bfd *abfd; + asection *sec; + arelent **relptr; + asymbol **symbols; +{ + arelent *rels; + asection **secs; + bfd_size_type count, i; + unsigned int ret; + + /* Get the relocation fixups. */ + rels = nlm_relocation_fixups (abfd); + if (rels == NULL) + { + if (nlm_slurp_reloc_fixups (abfd) == false) + return -1; + rels = nlm_relocation_fixups (abfd); + } + secs = nlm_relocation_fixup_secs (abfd); + + ret = 0; + count = nlm_fixed_header (abfd)->numberOfRelocationFixups; + for (i = 0; i < count; i++, rels++, secs++) + { + if (*secs == sec) + { + *relptr++ = rels; + ++ret; + } + } + + /* Get the import symbols. */ + count = bfd_get_symcount (abfd); + for (i = 0; i < count; i++, symbols++) + { + asymbol *sym; + + sym = *symbols; + if (bfd_asymbol_flavour (sym) == bfd_target_nlm_flavour) + { + nlm_symbol_type *nlm_sym; + bfd_size_type j; + + nlm_sym = (nlm_symbol_type *) sym; + for (j = 0; j < nlm_sym->rcnt; j++) + { + if (nlm_sym->relocs[j].section == sec) + { + *relptr = &nlm_sym->relocs[j].reloc; + (*relptr)->sym_ptr_ptr = symbols; + ++relptr; + ++ret; + } + } + } + } + + *relptr = NULL; + + return ret; +} + +/* Compute the section file positions for an NLM file. All variable + length data in the file headers must be set before this function is + called. If the variable length data is changed later, the + resulting object file will be incorrect. Unfortunately, there is + no way to check this. + + This routine also sets the Size and Offset fields in the fixed + header. + + It also looks over the symbols and moves any common symbols into + the .bss section; NLM has no way to represent a common symbol. + This approach means that either the symbols must already have been + set at this point, or there must be no common symbols. We need to + move the symbols at this point so that mangle_relocs can see the + final values. */ + +static boolean +nlm_compute_section_file_positions (abfd) + bfd *abfd; +{ + file_ptr sofar; + asection *sec; + bfd_vma text, data, bss; + bfd_vma text_low, data_low; + unsigned int text_align, data_align, other_align; + file_ptr text_ptr, data_ptr, other_ptr; + asection *bss_sec; + asymbol **sym_ptr_ptr; + + if (abfd->output_has_begun == true) + return true; + + /* Make sure we have a section to hold uninitialized data. */ + bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); + if (bss_sec == NULL) + { + if (!add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME, + (file_ptr) 0, (bfd_size_type) 0, + SEC_ALLOC)) + return false; + bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME); + } + + abfd->output_has_begun = true; + + /* The fixed header. */ + sofar = nlm_optional_prefix_size (abfd) + nlm_fixed_header_size (abfd); + + /* The variable header. */ + sofar += (sizeof (nlm_variable_header (abfd)->descriptionLength) + + nlm_variable_header (abfd)->descriptionLength + 1 + + NLM_TARGET_LONG_SIZE /* stackSize */ + + NLM_TARGET_LONG_SIZE /* reserved */ + + sizeof (nlm_variable_header (abfd)->oldThreadName) + + sizeof (nlm_variable_header (abfd)->screenNameLength) + + nlm_variable_header (abfd)->screenNameLength + 1 + + sizeof (nlm_variable_header (abfd)->threadNameLength) + + nlm_variable_header (abfd)->threadNameLength + 1); + + /* The auxiliary headers. */ + if (find_nonzero ((PTR) nlm_version_header (abfd), + sizeof (Nlm_Internal_Version_Header))) + sofar += sizeof (Nlm_External_Version_Header); + if (find_nonzero ((PTR) nlm_extended_header (abfd), + sizeof (Nlm_Internal_Extended_Header))) + sofar += sizeof (Nlm_External_Extended_Header); + if (find_nonzero ((PTR) nlm_copyright_header (abfd), + sizeof (Nlm_Internal_Copyright_Header))) + sofar += (sizeof (Nlm_External_Copyright_Header) + + nlm_copyright_header (abfd)->copyrightMessageLength + 1); + if (find_nonzero ((PTR) nlm_custom_header (abfd), + sizeof (Nlm_Internal_Custom_Header))) + sofar += (sizeof (Nlm_External_Custom_Header) + + nlm_custom_header (abfd)->hdrLength); + if (find_nonzero ((PTR) nlm_cygnus_ext_header (abfd), + sizeof (Nlm_Internal_Cygnus_Ext_Header))) + sofar += sizeof (Nlm_External_Custom_Header); + + /* Compute the section file positions in two passes. First get the + sizes of the text and data sections, and then set the file + positions. This code aligns the sections in the file using the + same alignment restrictions that apply to the sections in memory; + this may not be necessary. */ + text = 0; + text_low = (bfd_vma) - 1; + text_align = 0; + data = 0; + data_low = (bfd_vma) - 1; + data_align = 0; + bss = 0; + other_align = 0; + for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) + { + flagword f; + + sec->_raw_size = BFD_ALIGN (sec->_raw_size, 1 << sec->alignment_power); + + f = bfd_get_section_flags (abfd, sec); + if (f & SEC_CODE) + { + text += sec->_raw_size; + if (bfd_get_section_vma (abfd, sec) < text_low) + text_low = bfd_get_section_vma (abfd, sec); + if (sec->alignment_power > text_align) + text_align = sec->alignment_power; + } + else if (f & SEC_DATA) + { + data += sec->_raw_size; + if (bfd_get_section_vma (abfd, sec) < data_low) + data_low = bfd_get_section_vma (abfd, sec); + if (sec->alignment_power > data_align) + data_align = sec->alignment_power; + } + else if (f & SEC_HAS_CONTENTS) + { + if (sec->alignment_power > other_align) + other_align = sec->alignment_power; + } + else if (f & SEC_ALLOC) + bss += sec->_raw_size; + } + + nlm_set_text_low (abfd, text_low); + nlm_set_data_low (abfd, data_low); + + if (nlm_no_uninitialized_data (abfd)) + { + /* This NetWare format does not use uninitialized data. We must + increase the size of the data section. We will never wind up + writing those file locations, so they will remain zero. */ + data += bss; + bss = 0; + } + + text_ptr = BFD_ALIGN (sofar, 1 << text_align); + data_ptr = BFD_ALIGN (text_ptr + text, 1 << data_align); + other_ptr = BFD_ALIGN (data_ptr + data, 1 << other_align); + + /* Fill in some fields in the header for which we now have the + information. */ + nlm_fixed_header (abfd)->codeImageOffset = text_ptr; + nlm_fixed_header (abfd)->codeImageSize = text; + nlm_fixed_header (abfd)->dataImageOffset = data_ptr; + nlm_fixed_header (abfd)->dataImageSize = data; + nlm_fixed_header (abfd)->uninitializedDataSize = bss; + + for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) + { + flagword f; + + f = bfd_get_section_flags (abfd, sec); + + if (f & SEC_CODE) + { + sec->filepos = text_ptr; + text_ptr += sec->_raw_size; + } + else if (f & SEC_DATA) + { + sec->filepos = data_ptr; + data_ptr += sec->_raw_size; + } + else if (f & SEC_HAS_CONTENTS) + { + sec->filepos = other_ptr; + other_ptr += sec->_raw_size; + } + } + + nlm_fixed_header (abfd)->relocationFixupOffset = other_ptr; + + /* Move all common symbols into the .bss section. */ + + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != NULL) + { + asymbol **sym_end; + bfd_vma add; + + sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); + add = 0; + for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) + { + asymbol *sym; + bfd_vma size; + + sym = *sym_ptr_ptr; + + if (!bfd_is_com_section (bfd_get_section (sym))) + continue; + + /* Put the common symbol in the .bss section, and increase + the size of the .bss section by the size of the common + symbol (which is the old value of the symbol). */ + sym->section = bss_sec; + size = sym->value; + sym->value = bss_sec->_raw_size + add; + add += size; + add = BFD_ALIGN (add, 1 << bss_sec->alignment_power); + } + if (add != 0) + { + if (nlm_no_uninitialized_data (abfd)) + { + /* We could handle this case, but so far it hasn't been + necessary. */ + abort (); + } + nlm_fixed_header (abfd)->uninitializedDataSize += add; + bss_sec->_raw_size += add; + } + } + + return true; +} + +/* Set the contents of a section. To do this we need to know where + the section is going to be located in the output file. That means + that the sizes of all the sections must be set, and all the + variable size header information must be known. */ + +boolean +nlm_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false + && nlm_compute_section_file_positions (abfd) == false) + return false; + + if (count == 0) + return true; + + /* i386 NetWare has a very restricted set of relocs. In order for + objcopy to work, the NLM i386 backend needs a chance to rework + the section contents so that its set of relocs will work. If all + the relocs are already acceptable, this will not do anything. */ + if (section->reloc_count != 0) + { + boolean (*mangle_relocs_func) PARAMS ((bfd *, asection *, PTR, + bfd_vma, bfd_size_type)); + + mangle_relocs_func = nlm_mangle_relocs_func (abfd); + if (mangle_relocs_func != NULL) + { + if (!(*mangle_relocs_func) (abfd, section, location, + (bfd_vma) offset, count)) + return false; + } + } + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0 + || bfd_write (location, 1, count, abfd) != count) + return false; + + return true; +} + +/* We need to sort a list of relocs associated with sections when we + write out the external relocs. */ + +static int +nlm_external_reloc_compare (p1, p2) + const void *p1; + const void *p2; +{ + const struct reloc_and_sec *r1 = (const struct reloc_and_sec *) p1; + const struct reloc_and_sec *r2 = (const struct reloc_and_sec *) p2; + int cmp; + + cmp = strcmp ((*r1->rel->sym_ptr_ptr)->name, + (*r2->rel->sym_ptr_ptr)->name); + if (cmp != 0) + return cmp; + + /* We sort by address within symbol to make the sort more stable and + increase the chances that different hosts will generate bit for + bit equivalent results. */ + return (int) (r1->rel->address - r2->rel->address); +} + +/* Write out an NLM file. We write out the information in this order: + fixed header + variable header + auxiliary headers + code sections + data sections + other sections (custom data, messages, help, shared NLM, RPC, + module dependencies) + relocation fixups + external references (imports) + public symbols (exports) + debugging records + This is similar to the order used by the NetWare tools; the + difference is that NetWare puts the sections other than code, data + and custom data at the end of the NLM. It is convenient for us to + know where the sections are going to be before worrying about the + size of the other information. + + By the time this function is called, all the section data should + have been output using set_section_contents. Note that custom + data, the message file, the help file, the shared NLM file, the RPC + data, and the module dependencies are all considered to be + sections; the caller is responsible for filling in the offset and + length fields in the NLM headers. The relocation fixups and + imports are both obtained from the list of relocs attached to each + section. The exports and debugging records are obtained from the + list of outsymbols. */ + +boolean +nlm_write_object_contents (abfd) + bfd *abfd; +{ + asection *sec; + boolean (*write_import_func) PARAMS ((bfd *, asection *, arelent *)); + bfd_size_type external_reloc_count, internal_reloc_count, i, c; + struct reloc_and_sec *external_relocs; + asymbol **sym_ptr_ptr; + file_ptr last; + boolean (*write_prefix_func) PARAMS ((bfd *)); + unsigned char *fixed_header = NULL; + + fixed_header = ((unsigned char *) + bfd_malloc ((size_t) nlm_fixed_header_size (abfd))); + if (fixed_header == NULL) + goto error_return; + + if (abfd->output_has_begun == false + && nlm_compute_section_file_positions (abfd) == false) + goto error_return; + + /* Write out the variable length headers. */ + if (bfd_seek (abfd, + nlm_optional_prefix_size (abfd) + nlm_fixed_header_size (abfd), + SEEK_SET) != 0) + goto error_return; + if (nlm_swap_variable_header_out (abfd) == false + || nlm_swap_auxiliary_headers_out (abfd) == false) + { + bfd_set_error (bfd_error_system_call); + goto error_return; + } + + /* A weak check on whether the section file positions were + reasonable. */ + if (bfd_tell (abfd) > nlm_fixed_header (abfd)->codeImageOffset) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + /* Advance to the relocs. */ + if (bfd_seek (abfd, nlm_fixed_header (abfd)->relocationFixupOffset, + SEEK_SET) != 0) + goto error_return; + + /* The format of the relocation entries is dependent upon the + particular target. We use an external routine to write the reloc + out. */ + write_import_func = nlm_write_import_func (abfd); + + /* Write out the internal relocation fixups. While we're looping + over the relocs, we also count the external relocs, which is + needed when they are written out below. */ + internal_reloc_count = 0; + external_reloc_count = 0; + for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) + { + arelent **rel_ptr_ptr, **rel_end; + + if (sec->reloc_count == 0) + continue; + + /* We can only represent relocs within a code or data + section. We ignore them for a debugging section. */ + if ((bfd_get_section_flags (abfd, sec) & (SEC_CODE | SEC_DATA)) == 0) + continue; + + /* We need to know how to write out imports */ + if (write_import_func == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + rel_ptr_ptr = sec->orelocation; + rel_end = rel_ptr_ptr + sec->reloc_count; + for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++) + { + arelent *rel; + asymbol *sym; + + rel = *rel_ptr_ptr; + sym = *rel->sym_ptr_ptr; + + if (! bfd_is_und_section (bfd_get_section (sym))) + { + ++internal_reloc_count; + if ((*write_import_func) (abfd, sec, rel) == false) + goto error_return; + } + else + ++external_reloc_count; + } + } + nlm_fixed_header (abfd)->numberOfRelocationFixups = internal_reloc_count; + + /* Write out the imports (relocs against external symbols). These + are output as a symbol name followed by all the relocs for that + symbol, so we must first gather together all the relocs against + external symbols and sort them. */ + external_relocs = + (struct reloc_and_sec *) bfd_alloc (abfd, + (external_reloc_count + * sizeof (struct reloc_and_sec))); + if (external_relocs == (struct reloc_and_sec *) NULL) + goto error_return; + i = 0; + for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next) + { + arelent **rel_ptr_ptr, **rel_end; + + if (sec->reloc_count == 0) + continue; + + rel_ptr_ptr = sec->orelocation; + rel_end = rel_ptr_ptr + sec->reloc_count; + for (; rel_ptr_ptr < rel_end; rel_ptr_ptr++) + { + arelent *rel; + asymbol *sym; + + rel = *rel_ptr_ptr; + sym = *rel->sym_ptr_ptr; + + if (! bfd_is_und_section (bfd_get_section (sym))) + continue; + + external_relocs[i].rel = rel; + external_relocs[i].sec = sec; + ++i; + } + } + + BFD_ASSERT (i == external_reloc_count); + + /* Sort the external relocs by name. */ + qsort ((PTR) external_relocs, (size_t) external_reloc_count, + sizeof (struct reloc_and_sec), nlm_external_reloc_compare); + + /* Write out the external relocs. */ + nlm_fixed_header (abfd)->externalReferencesOffset = bfd_tell (abfd); + c = 0; + i = 0; + while (i < external_reloc_count) + { + arelent *rel; + asymbol *sym; + bfd_size_type j, cnt; + + ++c; + + rel = external_relocs[i].rel; + sym = *rel->sym_ptr_ptr; + + cnt = 0; + for (j = i; + (j < external_reloc_count + && *external_relocs[j].rel->sym_ptr_ptr == sym); + j++) + ++cnt; + + if ((*nlm_write_external_func (abfd)) (abfd, cnt, sym, + &external_relocs[i]) + == false) + goto error_return; + + i += cnt; + } + + nlm_fixed_header (abfd)->numberOfExternalReferences = c; + + /* Write out the public symbols (exports). */ + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != (asymbol **) NULL) + { + bfd_vma (*get_public_offset_func) PARAMS ((bfd *, asymbol *)); + boolean (*write_export_func) PARAMS ((bfd *, asymbol *, bfd_vma)); + + asymbol **sym_end; + + nlm_fixed_header (abfd)->publicsOffset = bfd_tell (abfd); + get_public_offset_func = nlm_get_public_offset_func (abfd); + write_export_func = nlm_write_export_func (abfd); + c = 0; + sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); + for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) + { + asymbol *sym; + bfd_byte len; + bfd_vma offset; + bfd_byte temp[NLM_TARGET_LONG_SIZE]; + + sym = *sym_ptr_ptr; + + if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) == 0 + || bfd_is_und_section (bfd_get_section (sym))) + continue; + + ++c; + + if (get_public_offset_func) + { + /* Most backends can use the code below, but + unfortunately some use a different scheme. */ + offset = (*get_public_offset_func) (abfd, sym); + } + else + { + offset = bfd_asymbol_value (sym); + sec = sym->section; + if (sec->flags & SEC_CODE) + { + offset -= nlm_get_text_low (abfd); + offset |= NLM_HIBIT; + } + else if (sec->flags & (SEC_DATA | SEC_ALLOC)) + { + /* SEC_ALLOC is for the .bss section. */ + offset -= nlm_get_data_low (abfd); + } + else + { + /* We can't handle an exported symbol that is not in + the code or data segment. */ + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + } + + if (write_export_func) + { + if ((*write_export_func) (abfd, sym, offset) == false) + goto error_return; + } + else + { + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) + != sizeof (bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + goto error_return; + + put_word (abfd, offset, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + goto error_return; + } + } + nlm_fixed_header (abfd)->numberOfPublics = c; + + /* Write out the debugging records. The NLM conversion program + wants to be able to inhibit this, so as a special hack if + debugInfoOffset is set to -1 we don't write any debugging + information. This can not be handled by fiddling with the + symbol table, because exported symbols appear in both the + exported symbol list and the debugging information. */ + if (nlm_fixed_header (abfd)->debugInfoOffset == (file_ptr) - 1) + { + nlm_fixed_header (abfd)->debugInfoOffset = 0; + nlm_fixed_header (abfd)->numberOfDebugRecords = 0; + } + else + { + nlm_fixed_header (abfd)->debugInfoOffset = bfd_tell (abfd); + c = 0; + sym_ptr_ptr = bfd_get_outsymbols (abfd); + sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); + for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) + { + asymbol *sym; + bfd_byte type, len; + bfd_vma offset; + bfd_byte temp[NLM_TARGET_LONG_SIZE]; + + sym = *sym_ptr_ptr; + + /* The NLM notion of a debugging symbol is actually what + BFD calls a local or global symbol. What BFD calls a + debugging symbol NLM does not understand at all. */ + if ((sym->flags & (BSF_LOCAL | BSF_GLOBAL | BSF_EXPORT)) == 0 + || (sym->flags & BSF_DEBUGGING) != 0 + || bfd_is_und_section (bfd_get_section (sym))) + continue; + + ++c; + + offset = bfd_asymbol_value (sym); + sec = sym->section; + if (sec->flags & SEC_CODE) + { + offset -= nlm_get_text_low (abfd); + type = 1; + } + else if (sec->flags & (SEC_DATA | SEC_ALLOC)) + { + /* SEC_ALLOC is for the .bss section. */ + offset -= nlm_get_data_low (abfd); + type = 0; + } + else + type = 2; + + /* The type is 0 for data, 1 for code, 2 for absolute. */ + if (bfd_write (&type, sizeof (bfd_byte), 1, abfd) + != sizeof (bfd_byte)) + goto error_return; + + put_word (abfd, offset, temp); + if (bfd_write (temp, sizeof (temp), 1, abfd) != sizeof (temp)) + goto error_return; + + len = strlen (sym->name); + if ((bfd_write (&len, sizeof (bfd_byte), 1, abfd) + != sizeof (bfd_byte)) + || bfd_write (sym->name, len, 1, abfd) != len) + goto error_return; + } + nlm_fixed_header (abfd)->numberOfDebugRecords = c; + } + } + + /* NLMLINK fills in offset values even if there is no data, so we do + the same. */ + last = bfd_tell (abfd); + if (nlm_fixed_header (abfd)->codeImageOffset == 0) + nlm_fixed_header (abfd)->codeImageOffset = last; + if (nlm_fixed_header (abfd)->dataImageOffset == 0) + nlm_fixed_header (abfd)->dataImageOffset = last; + if (nlm_fixed_header (abfd)->customDataOffset == 0) + nlm_fixed_header (abfd)->customDataOffset = last; + if (nlm_fixed_header (abfd)->moduleDependencyOffset == 0) + nlm_fixed_header (abfd)->moduleDependencyOffset = last; + if (nlm_fixed_header (abfd)->relocationFixupOffset == 0) + nlm_fixed_header (abfd)->relocationFixupOffset = last; + if (nlm_fixed_header (abfd)->externalReferencesOffset == 0) + nlm_fixed_header (abfd)->externalReferencesOffset = last; + if (nlm_fixed_header (abfd)->publicsOffset == 0) + nlm_fixed_header (abfd)->publicsOffset = last; + if (nlm_fixed_header (abfd)->debugInfoOffset == 0) + nlm_fixed_header (abfd)->debugInfoOffset = last; + + /* At this point everything has been written out except the fixed + header. */ + memcpy (nlm_fixed_header (abfd)->signature, nlm_signature (abfd), + NLM_SIGNATURE_SIZE); + nlm_fixed_header (abfd)->version = NLM_HEADER_VERSION; + nlm_fixed_header (abfd)->codeStartOffset = + (bfd_get_start_address (abfd) + - nlm_get_text_low (abfd)); + + /* We have no convenient way for the caller to pass in the exit + procedure or the check unload procedure, so the caller must set + the values in the header to the values of the symbols. */ + nlm_fixed_header (abfd)->exitProcedureOffset -= nlm_get_text_low (abfd); + if (nlm_fixed_header (abfd)->checkUnloadProcedureOffset != 0) + nlm_fixed_header (abfd)->checkUnloadProcedureOffset -= + nlm_get_text_low (abfd); + + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + goto error_return; + + write_prefix_func = nlm_write_prefix_func (abfd); + if (write_prefix_func) + { + if ((*write_prefix_func) (abfd) == false) + goto error_return; + } + + BFD_ASSERT ((bfd_size_type) bfd_tell (abfd) + == nlm_optional_prefix_size (abfd)); + + nlm_swap_fixed_header_out (abfd, nlm_fixed_header (abfd), fixed_header); + if (bfd_write (fixed_header, nlm_fixed_header_size (abfd), 1, abfd) + != nlm_fixed_header_size (abfd)) + goto error_return; + + if (fixed_header != NULL) + free (fixed_header); + return true; + +error_return: + if (fixed_header != NULL) + free (fixed_header); + return false; +} diff --git a/contrib/gdb/bfd/nlmswap.h b/contrib/gdb/bfd/nlmswap.h new file mode 100644 index 000000000000..5a9ce7268d00 --- /dev/null +++ b/contrib/gdb/bfd/nlmswap.h @@ -0,0 +1,157 @@ +/* NLM (NetWare Loadable Module) swapping routines for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, using ELF support as the + template. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Although this is a header file, it defines functions. It is + included by NLM backends to define swapping functions that vary + from one NLM to another. The backend code must arrange for + Nlm_External_xxxx to be defined appropriately, and can then include + this file to get the swapping routines. + + At the moment this is only needed for one structure, the fixed NLM + file header. */ + +static void nlm_swap_fixed_header_in PARAMS ((bfd *, PTR, + Nlm_Internal_Fixed_Header *)); +static void nlm_swap_fixed_header_out PARAMS ((bfd *, + Nlm_Internal_Fixed_Header *, + PTR)); + +/* Translate an NLM fixed length file header in external format into an NLM + file header in internal format. */ + +static void +nlm_swap_fixed_header_in (abfd, realsrc, dst) + bfd *abfd; + PTR realsrc; + Nlm_Internal_Fixed_Header *dst; +{ + Nlm_External_Fixed_Header *src = (Nlm_External_Fixed_Header *) realsrc; + memcpy (dst->signature, src->signature, NLM_SIGNATURE_SIZE); + memcpy (dst->moduleName, src->moduleName, NLM_MODULE_NAME_SIZE); + dst->version = + bfd_h_get_32 (abfd, (bfd_byte *) src->version); + dst->codeImageOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->codeImageOffset); + dst->codeImageSize = + bfd_h_get_32 (abfd, (bfd_byte *) src->codeImageSize); + dst->dataImageOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->dataImageOffset); + dst->dataImageSize = + bfd_h_get_32 (abfd, (bfd_byte *) src->dataImageSize); + dst->uninitializedDataSize = + bfd_h_get_32 (abfd, (bfd_byte *) src->uninitializedDataSize); + dst->customDataOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->customDataOffset); + dst->customDataSize = + bfd_h_get_32 (abfd, (bfd_byte *) src->customDataSize); + dst->moduleDependencyOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->moduleDependencyOffset); + dst->numberOfModuleDependencies = + bfd_h_get_32 (abfd, (bfd_byte *) src->numberOfModuleDependencies); + dst->relocationFixupOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->relocationFixupOffset); + dst->numberOfRelocationFixups = + bfd_h_get_32 (abfd, (bfd_byte *) src->numberOfRelocationFixups); + dst->externalReferencesOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->externalReferencesOffset); + dst->numberOfExternalReferences = + bfd_h_get_32 (abfd, (bfd_byte *) src->numberOfExternalReferences); + dst->publicsOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->publicsOffset); + dst->numberOfPublics = + bfd_h_get_32 (abfd, (bfd_byte *) src->numberOfPublics); + dst->debugInfoOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->debugInfoOffset); + dst->numberOfDebugRecords = + bfd_h_get_32 (abfd, (bfd_byte *) src->numberOfDebugRecords); + dst->codeStartOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->codeStartOffset); + dst->exitProcedureOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->exitProcedureOffset); + dst->checkUnloadProcedureOffset = + bfd_h_get_32 (abfd, (bfd_byte *) src->checkUnloadProcedureOffset); + dst->moduleType = + bfd_h_get_32 (abfd, (bfd_byte *) src->moduleType); + dst->flags = + bfd_h_get_32 (abfd, (bfd_byte *) src->flags); +} + +/* Translate an NLM fixed length file header in internal format into + an NLM file header in external format. */ + +static void +nlm_swap_fixed_header_out (abfd, src, realdst) + bfd *abfd; + Nlm_Internal_Fixed_Header *src; + PTR realdst; +{ + Nlm_External_Fixed_Header *dst = (Nlm_External_Fixed_Header *) realdst; + memset (dst, 0, sizeof *dst); + memcpy (dst->signature, src->signature, NLM_SIGNATURE_SIZE); + memcpy (dst->moduleName, src->moduleName, NLM_MODULE_NAME_SIZE); + bfd_h_put_32 (abfd, (bfd_vma) src->version, + (bfd_byte *) dst->version); + bfd_h_put_32 (abfd, (bfd_vma) src->codeImageOffset, + (bfd_byte *) dst->codeImageOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->codeImageSize, + (bfd_byte *) dst->codeImageSize); + bfd_h_put_32 (abfd, (bfd_vma) src->dataImageOffset, + (bfd_byte *) dst->dataImageOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->dataImageSize, + (bfd_byte *) dst->dataImageSize); + bfd_h_put_32 (abfd, (bfd_vma) src->uninitializedDataSize, + (bfd_byte *) dst->uninitializedDataSize); + bfd_h_put_32 (abfd, (bfd_vma) src->customDataOffset, + (bfd_byte *) dst->customDataOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->customDataSize, + (bfd_byte *) dst->customDataSize); + bfd_h_put_32 (abfd, (bfd_vma) src->moduleDependencyOffset, + (bfd_byte *) dst->moduleDependencyOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->numberOfModuleDependencies, + (bfd_byte *) dst->numberOfModuleDependencies); + bfd_h_put_32 (abfd, (bfd_vma) src->relocationFixupOffset, + (bfd_byte *) dst->relocationFixupOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->numberOfRelocationFixups, + (bfd_byte *) dst->numberOfRelocationFixups); + bfd_h_put_32 (abfd, (bfd_vma) src->externalReferencesOffset, + (bfd_byte *) dst->externalReferencesOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->numberOfExternalReferences, + (bfd_byte *) dst->numberOfExternalReferences); + bfd_h_put_32 (abfd, (bfd_vma) src->publicsOffset, + (bfd_byte *) dst->publicsOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->numberOfPublics, + (bfd_byte *) dst->numberOfPublics); + bfd_h_put_32 (abfd, (bfd_vma) src->debugInfoOffset, + (bfd_byte *) dst->debugInfoOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->numberOfDebugRecords, + (bfd_byte *) dst->numberOfDebugRecords); + bfd_h_put_32 (abfd, (bfd_vma) src->codeStartOffset, + (bfd_byte *) dst->codeStartOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->exitProcedureOffset, + (bfd_byte *) dst->exitProcedureOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->checkUnloadProcedureOffset, + (bfd_byte *) dst->checkUnloadProcedureOffset); + bfd_h_put_32 (abfd, (bfd_vma) src->moduleType, + (bfd_byte *) dst->moduleType); + bfd_h_put_32 (abfd, (bfd_vma) src->flags, + (bfd_byte *) dst->flags); +} diff --git a/contrib/gdb/bfd/ns32knetbsd.c b/contrib/gdb/bfd/ns32knetbsd.c new file mode 100644 index 000000000000..3e3f08a9e58d --- /dev/null +++ b/contrib/gdb/bfd/ns32knetbsd.c @@ -0,0 +1,53 @@ +/* BFD back-end for NetBSD/ns32k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#undef TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE 4096 + +#define DEFAULT_ARCH bfd_arch_ns32k +#define MACHTYPE_OK(mtype) ((mtype) == M_532_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(pc532netbsd_,OP) + +#define NAME(x,y) CAT3(ns32kaout,_32_,y) + +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-ns32k-netbsd" + +#define ns32kaout_32_get_section_contents aout_32_get_section_contents + +#define MY_text_includes_header 1 + +/* We can`t use the MYNS macro here for cpp reasons too subtle + * for me -- IWD + */ +#define MY_bfd_reloc_type_lookup ns32kaout_bfd_reloc_type_lookup + +#include "bfd.h" /* To ensure following declaration is OK */ + +CONST struct reloc_howto_struct * +MY_bfd_reloc_type_lookup + PARAMS((bfd *abfd AND + bfd_reloc_code_real_type code)); + + +#include "netbsd.h" diff --git a/contrib/gdb/bfd/oasys.c b/contrib/gdb/bfd/oasys.c new file mode 100644 index 000000000000..c72147288af5 --- /dev/null +++ b/contrib/gdb/bfd/oasys.c @@ -0,0 +1,1533 @@ +/* BFD back-end for oasys objects. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define UNDERSCORE_HACK 1 +#include "bfd.h" +#include "sysdep.h" +#include +#include "libbfd.h" +#include "oasys.h" +#include "liboasys.h" + +/* XXX - FIXME. offsetof belongs in the system-specific files in + ../include/sys. */ +/* Define offsetof for those systems which lack it */ + +#ifndef offsetof +#define offsetof(type, identifier) (size_t) &(((type *) 0)->identifier) +#endif + +static boolean oasys_read_record PARAMS ((bfd *, + oasys_record_union_type *)); +static boolean oasys_write_sections PARAMS ((bfd *)); +static boolean oasys_write_record PARAMS ((bfd *, + oasys_record_enum_type, + oasys_record_union_type *, + size_t)); +static boolean oasys_write_syms PARAMS ((bfd *)); +static boolean oasys_write_header PARAMS ((bfd *)); +static boolean oasys_write_end PARAMS ((bfd *)); +static boolean oasys_write_data PARAMS ((bfd *)); + +/* Read in all the section data and relocation stuff too */ +PROTO (static boolean, oasys_slurp_section_data, (bfd * CONST abfd)); + +static boolean +oasys_read_record (abfd, record) + bfd *abfd; + oasys_record_union_type *record; +{ + if (bfd_read ((PTR) record, 1, sizeof (record->header), abfd) + != sizeof (record->header)) + return false; + + if ((size_t) record->header.length <= (size_t) sizeof (record->header)) + return true; + if (bfd_read ((PTR) (((char *) record) + sizeof (record->header)), + 1, record->header.length - sizeof (record->header), + abfd) + != record->header.length - sizeof (record->header)) + return false; + return true; +} +static size_t +oasys_string_length (record) + oasys_record_union_type *record; +{ + return record->header.length + - ((char *) record->symbol.name - (char *) record); +} + +/*****************************************************************************/ + +/* + +Slurp the symbol table by reading in all the records at the start file +till we get to the first section record. + +We'll sort the symbolss into two lists, defined and undefined. The +undefined symbols will be placed into the table according to their +refno. + +We do this by placing all undefined symbols at the front of the table +moving in, and the defined symbols at the end of the table moving back. + +*/ + +static boolean +oasys_slurp_symbol_table (abfd) + bfd *CONST abfd; +{ + oasys_record_union_type record; + oasys_data_type *data = OASYS_DATA (abfd); + boolean loop = true; + asymbol *dest_defined; + asymbol *dest; + char *string_ptr; + + + if (data->symbols != (asymbol *) NULL) + { + return true; + } + /* Buy enough memory for all the symbols and all the names */ + data->symbols = + (asymbol *) bfd_alloc (abfd, sizeof (asymbol) * abfd->symcount); +#ifdef UNDERSCORE_HACK + /* buy 1 more char for each symbol to keep the underscore in*/ + data->strings = bfd_alloc (abfd, data->symbol_string_length + + abfd->symcount); +#else + data->strings = bfd_alloc (abfd, data->symbol_string_length); +#endif + if (!data->symbols || !data->strings) + return false; + + dest_defined = data->symbols + abfd->symcount - 1; + + string_ptr = data->strings; + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + while (loop) + { + + if (! oasys_read_record (abfd, &record)) + return false; + switch (record.header.type) + { + case oasys_record_is_header_enum: + break; + case oasys_record_is_local_enum: + case oasys_record_is_symbol_enum: + { + int flag = record.header.type == (int) oasys_record_is_local_enum ? + (BSF_LOCAL) : (BSF_GLOBAL | BSF_EXPORT); + + + size_t length = oasys_string_length (&record); + switch (record.symbol.relb & RELOCATION_TYPE_BITS) + { + case RELOCATION_TYPE_ABS: + dest = dest_defined--; + dest->section = bfd_abs_section_ptr; + dest->flags = 0; + + break; + case RELOCATION_TYPE_REL: + dest = dest_defined--; + dest->section = + OASYS_DATA (abfd)->sections[record.symbol.relb & + RELOCATION_SECT_BITS]; + if (record.header.type == (int) oasys_record_is_local_enum) + { + dest->flags = BSF_LOCAL; + if (dest->section == (asection *) (~0)) + { + /* It seems that sometimes internal symbols are tied up, but + still get output, even though there is no + section */ + dest->section = 0; + } + } + else + { + + dest->flags = flag; + } + break; + case RELOCATION_TYPE_UND: + dest = data->symbols + bfd_h_get_16 (abfd, record.symbol.refno); + dest->section = bfd_und_section_ptr; + break; + case RELOCATION_TYPE_COM: + dest = dest_defined--; + dest->name = string_ptr; + dest->the_bfd = abfd; + + dest->section = bfd_com_section_ptr; + + break; + default: + dest = dest_defined--; + BFD_ASSERT (0); + break; + } + dest->name = string_ptr; + dest->the_bfd = abfd; + dest->udata.p = (PTR) NULL; + dest->value = bfd_h_get_32 (abfd, record.symbol.value); + +#ifdef UNDERSCORE_HACK + if (record.symbol.name[0] != '_') + { + string_ptr[0] = '_'; + string_ptr++; + } +#endif + memcpy (string_ptr, record.symbol.name, length); + + + string_ptr[length] = 0; + string_ptr += length + 1; + } + break; + default: + loop = false; + } + } + return true; +} + +static long +oasys_get_symtab_upper_bound (abfd) + bfd *CONST abfd; +{ + if (! oasys_slurp_symbol_table (abfd)) + return -1; + + return (abfd->symcount + 1) * (sizeof (oasys_symbol_type *)); +} + +/* +*/ + +extern const bfd_target oasys_vec; + +long +oasys_get_symtab (abfd, location) + bfd *abfd; + asymbol **location; +{ + asymbol *symbase; + unsigned int counter; + if (oasys_slurp_symbol_table (abfd) == false) + { + return -1; + } + symbase = OASYS_DATA (abfd)->symbols; + for (counter = 0; counter < abfd->symcount; counter++) + { + *(location++) = symbase++; + } + *location = 0; + return abfd->symcount; +} + +/*********************************************************************** +* archive stuff +*/ + +static const bfd_target * +oasys_archive_p (abfd) + bfd *abfd; +{ + oasys_archive_header_type header; + oasys_extarchive_header_type header_ext; + unsigned int i; + file_ptr filepos; + + if (bfd_seek (abfd, (file_ptr) 0, false) != 0 + || (bfd_read ((PTR) & header_ext, 1, sizeof (header_ext), abfd) + != sizeof (header_ext))) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + header.version = bfd_h_get_32 (abfd, header_ext.version); + header.mod_count = bfd_h_get_32 (abfd, header_ext.mod_count); + header.mod_tbl_offset = bfd_h_get_32 (abfd, header_ext.mod_tbl_offset); + header.sym_tbl_size = bfd_h_get_32 (abfd, header_ext.sym_tbl_size); + header.sym_count = bfd_h_get_32 (abfd, header_ext.sym_count); + header.sym_tbl_offset = bfd_h_get_32 (abfd, header_ext.sym_tbl_offset); + header.xref_count = bfd_h_get_32 (abfd, header_ext.xref_count); + header.xref_lst_offset = bfd_h_get_32 (abfd, header_ext.xref_lst_offset); + + /* + There isn't a magic number in an Oasys archive, so the best we + can do to verify reasnableness is to make sure that the values in + the header are too weird + */ + + if (header.version > 10000 || + header.mod_count > 10000 || + header.sym_count > 100000 || + header.xref_count > 100000) + return (const bfd_target *) NULL; + + /* + That all worked, let's buy the space for the header and read in + the headers. + */ + { + oasys_ar_data_type *ar = + (oasys_ar_data_type *) bfd_alloc (abfd, sizeof (oasys_ar_data_type)); + + oasys_module_info_type *module = + (oasys_module_info_type *) + bfd_alloc (abfd, sizeof (oasys_module_info_type) * header.mod_count); + oasys_module_table_type record; + + if (!ar || !module) + return NULL; + + abfd->tdata.oasys_ar_data = ar; + ar->module = module; + ar->module_count = header.mod_count; + + filepos = header.mod_tbl_offset; + for (i = 0; i < header.mod_count; i++) + { + if (bfd_seek (abfd, filepos, SEEK_SET) != 0) + return NULL; + + /* There are two ways of specifying the archive header */ + + if (0) + { + oasys_extmodule_table_type_a_type record_ext; + if (bfd_read ((PTR) & record_ext, 1, sizeof (record_ext), abfd) + != sizeof (record_ext)) + return NULL; + + record.mod_size = bfd_h_get_32 (abfd, record_ext.mod_size); + record.file_offset = bfd_h_get_32 (abfd, record_ext.file_offset); + + record.dep_count = bfd_h_get_32 (abfd, record_ext.dep_count); + record.depee_count = bfd_h_get_32 (abfd, record_ext.depee_count); + record.sect_count = bfd_h_get_32 (abfd, record_ext.sect_count); + + module[i].name = bfd_alloc (abfd, 33); + if (!module[i].name) + return NULL; + + memcpy (module[i].name, record_ext.mod_name, 33); + filepos += + sizeof (record_ext) + + record.dep_count * 4 + + record.depee_count * 4 + + record.sect_count * 8 + 187; + } + else + { + oasys_extmodule_table_type_b_type record_ext; + if (bfd_read ((PTR) & record_ext, 1, sizeof (record_ext), abfd) + != sizeof (record_ext)) + return NULL; + + record.mod_size = bfd_h_get_32 (abfd, record_ext.mod_size); + record.file_offset = bfd_h_get_32 (abfd, record_ext.file_offset); + + record.dep_count = bfd_h_get_32 (abfd, record_ext.dep_count); + record.depee_count = bfd_h_get_32 (abfd, record_ext.depee_count); + record.sect_count = bfd_h_get_32 (abfd, record_ext.sect_count); + record.module_name_size = bfd_h_get_32 (abfd, record_ext.mod_name_length); + + module[i].name = bfd_alloc (abfd, record.module_name_size + 1); + if (!module[i].name) + return NULL; + if (bfd_read ((PTR) module[i].name, 1, record.module_name_size, + abfd) + != record.module_name_size) + return NULL; + module[i].name[record.module_name_size] = 0; + filepos += + sizeof (record_ext) + + record.dep_count * 4 + + record.module_name_size + 1; + + } + + + module[i].size = record.mod_size; + module[i].pos = record.file_offset; + module[i].abfd = 0; + } + + } + return abfd->xvec; +} + +static boolean +oasys_mkobject (abfd) + bfd *abfd; +{ + + abfd->tdata.oasys_obj_data = (oasys_data_type *) bfd_alloc (abfd, sizeof (oasys_data_type)); + return abfd->tdata.oasys_obj_data ? true : false; +} + +#define MAX_SECS 16 +static const bfd_target * +oasys_object_p (abfd) + bfd *abfd; +{ + oasys_data_type *oasys; + oasys_data_type *save = OASYS_DATA (abfd); + boolean loop = true; + boolean had_usefull = false; + + abfd->tdata.oasys_obj_data = 0; + oasys_mkobject (abfd); + oasys = OASYS_DATA (abfd); + memset ((PTR) oasys->sections, 0xff, sizeof (oasys->sections)); + + /* Point to the start of the file */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto fail; + oasys->symbol_string_length = 0; + /* Inspect the records, but only keep the section info - + remember the size of the symbols + */ + oasys->first_data_record = 0; + while (loop) + { + oasys_record_union_type record; + if (! oasys_read_record (abfd, &record)) + goto fail; + if ((size_t) record.header.length < (size_t) sizeof (record.header)) + goto fail; + + + switch ((oasys_record_enum_type) (record.header.type)) + { + case oasys_record_is_header_enum: + had_usefull = true; + break; + case oasys_record_is_symbol_enum: + case oasys_record_is_local_enum: + /* Count symbols and remember their size for a future malloc */ + abfd->symcount++; + oasys->symbol_string_length += 1 + oasys_string_length (&record); + had_usefull = true; + break; + case oasys_record_is_section_enum: + { + asection *s; + char *buffer; + unsigned int section_number; + if (record.section.header.length != sizeof (record.section)) + { + goto fail; + } + buffer = bfd_alloc (abfd, 3); + if (!buffer) + goto fail; + section_number = record.section.relb & RELOCATION_SECT_BITS; + sprintf (buffer, "%u", section_number); + s = bfd_make_section (abfd, buffer); + oasys->sections[section_number] = s; + switch (record.section.relb & RELOCATION_TYPE_BITS) + { + case RELOCATION_TYPE_ABS: + case RELOCATION_TYPE_REL: + break; + case RELOCATION_TYPE_UND: + case RELOCATION_TYPE_COM: + BFD_FAIL (); + } + + s->_raw_size = bfd_h_get_32 (abfd, record.section.value); + s->vma = bfd_h_get_32 (abfd, record.section.vma); + s->flags = 0; + had_usefull = true; + } + break; + case oasys_record_is_data_enum: + oasys->first_data_record = bfd_tell (abfd) - record.header.length; + case oasys_record_is_debug_enum: + case oasys_record_is_module_enum: + case oasys_record_is_named_section_enum: + case oasys_record_is_end_enum: + if (had_usefull == false) + goto fail; + loop = false; + break; + default: + goto fail; + } + } + oasys->symbols = (asymbol *) NULL; + /* + Oasys support several architectures, but I can't see a simple way + to discover which one is in a particular file - we'll guess + */ + bfd_default_set_arch_mach (abfd, bfd_arch_m68k, 0); + if (abfd->symcount != 0) + { + abfd->flags |= HAS_SYMS; + } + + /* + We don't know if a section has data until we've read it.. + */ + + oasys_slurp_section_data (abfd); + + + return abfd->xvec; + +fail: + (void) bfd_release (abfd, oasys); + abfd->tdata.oasys_obj_data = save; + return (const bfd_target *) NULL; +} + + +static void +oasys_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); + if (!symbol->section) + ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A'; +} + +static void +oasys_print_symbol (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + + switch (how) + { + case bfd_print_symbol_name: + case bfd_print_symbol_more: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section == (asection *) NULL ? + (CONST char *) "*abs" : symbol->section->name; + + bfd_print_symbol_vandf ((PTR) file, symbol); + + fprintf (file, " %-5s %s", + section_name, + symbol->name); + } + break; + } +} +/* + The howto table is build using the top two bits of a reloc byte to + index into it. The bits are PCREL,WORD/LONG +*/ +static reloc_howto_type howto_table[] = +{ + + HOWTO (0, 0, 1, 16, false, 0, complain_overflow_bitfield, 0, "abs16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (0, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "abs32", true, 0xffffffff, 0xffffffff, false), + HOWTO (0, 0, 1, 16, true, 0, complain_overflow_signed, 0, "pcrel16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (0, 0, 2, 32, true, 0, complain_overflow_signed, 0, "pcrel32", true, 0xffffffff, 0xffffffff, false) +}; + +/* Read in all the section data and relocation stuff too */ +static boolean +oasys_slurp_section_data (abfd) + bfd *CONST abfd; +{ + oasys_record_union_type record; + oasys_data_type *data = OASYS_DATA (abfd); + boolean loop = true; + + oasys_per_section_type *per; + + asection *s; + + /* See if the data has been slurped already .. */ + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + per = oasys_per_section (s); + if (per->initialized == true) + return true; + } + + if (data->first_data_record == 0) + return true; + + if (bfd_seek (abfd, data->first_data_record, SEEK_SET) != 0) + return false; + while (loop) + { + if (! oasys_read_record (abfd, &record)) + return false; + switch (record.header.type) + { + case oasys_record_is_header_enum: + break; + case oasys_record_is_data_enum: + { + + bfd_byte *src = record.data.data; + bfd_byte *end_src = ((bfd_byte *) & record) + record.header.length; + bfd_byte *dst_ptr; + bfd_byte *dst_base_ptr; + unsigned int relbit; + unsigned int count; + asection *section = + data->sections[record.data.relb & RELOCATION_SECT_BITS]; + bfd_vma dst_offset; + + per = oasys_per_section (section); + + if (per->initialized == false) + { + per->data = (bfd_byte *) bfd_zalloc (abfd, section->_raw_size); + if (!per->data) + return false; + per->reloc_tail_ptr = (oasys_reloc_type **) & (section->relocation); + per->had_vma = false; + per->initialized = true; + section->reloc_count = 0; + section->flags = SEC_ALLOC; + } + + dst_offset = bfd_h_get_32 (abfd, record.data.addr); + if (per->had_vma == false) + { + /* Take the first vma we see as the base */ + section->vma = dst_offset; + per->had_vma = true; + } + + dst_offset -= section->vma; + + dst_base_ptr = oasys_per_section (section)->data; + dst_ptr = oasys_per_section (section)->data + + dst_offset; + + if (src < end_src) + { + section->flags |= SEC_LOAD | SEC_HAS_CONTENTS; + } + while (src < end_src) + { + unsigned char mod_byte = *src++; + size_t gap = end_src - src; + + count = 8; + if (mod_byte == 0 && gap >= 8) + { + dst_ptr[0] = src[0]; + dst_ptr[1] = src[1]; + dst_ptr[2] = src[2]; + dst_ptr[3] = src[3]; + dst_ptr[4] = src[4]; + dst_ptr[5] = src[5]; + dst_ptr[6] = src[6]; + dst_ptr[7] = src[7]; + dst_ptr += 8; + src += 8; + } + else + { + for (relbit = 1; count-- != 0 && src < end_src; relbit <<= 1) + { + if (relbit & mod_byte) + { + unsigned char reloc = *src; + /* This item needs to be relocated */ + switch (reloc & RELOCATION_TYPE_BITS) + { + case RELOCATION_TYPE_ABS: + + break; + + case RELOCATION_TYPE_REL: + { + /* Relocate the item relative to the section */ + oasys_reloc_type *r = + (oasys_reloc_type *) + bfd_alloc (abfd, + sizeof (oasys_reloc_type)); + if (!r) + return false; + *(per->reloc_tail_ptr) = r; + per->reloc_tail_ptr = &r->next; + r->next = (oasys_reloc_type *) NULL; + /* Reference to undefined symbol */ + src++; + /* There is no symbol */ + r->symbol = 0; + /* Work out the howto */ + abort (); +#if 0 + r->relent.section = + data->sections[reloc & + RELOCATION_SECT_BITS]; + + r->relent.addend = - + r->relent.section->vma; +#endif + r->relent.address = dst_ptr - dst_base_ptr; + r->relent.howto = &howto_table[reloc >> 6]; + r->relent.sym_ptr_ptr = (asymbol **) NULL; + section->reloc_count++; + + /* Fake up the data to look like it's got the -ve pc in it, this makes + it much easier to convert into other formats. This is done by + hitting the addend. + */ + if (r->relent.howto->pc_relative == true) + { + r->relent.addend -= dst_ptr - dst_base_ptr; + } + + + } + break; + + + case RELOCATION_TYPE_UND: + { + oasys_reloc_type *r = + (oasys_reloc_type *) + bfd_alloc (abfd, + sizeof (oasys_reloc_type)); + if (!r) + return false; + *(per->reloc_tail_ptr) = r; + per->reloc_tail_ptr = &r->next; + r->next = (oasys_reloc_type *) NULL; + /* Reference to undefined symbol */ + src++; + /* Get symbol number */ + r->symbol = (src[0] << 8) | src[1]; + /* Work out the howto */ + abort (); + +#if 0 + r->relent.section = (asection + *) NULL; +#endif + r->relent.addend = 0; + r->relent.address = dst_ptr - dst_base_ptr; + r->relent.howto = &howto_table[reloc >> 6]; + r->relent.sym_ptr_ptr = (asymbol **) NULL; + section->reloc_count++; + + src += 2; + /* Fake up the data to look like it's got the -ve pc in it, this makes + it much easier to convert into other formats. This is done by + hitting the addend. + */ + if (r->relent.howto->pc_relative == true) + { + r->relent.addend -= dst_ptr - dst_base_ptr; + } + + + + } + break; + case RELOCATION_TYPE_COM: + BFD_FAIL (); + } + } + *dst_ptr++ = *src++; + } + } + } + } + break; + case oasys_record_is_local_enum: + case oasys_record_is_symbol_enum: + case oasys_record_is_section_enum: + break; + default: + loop = false; + } + } + + return true; + +} + +static boolean +oasys_new_section_hook (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + newsect->used_by_bfd = (PTR) + bfd_alloc (abfd, sizeof (oasys_per_section_type)); + if (!newsect->used_by_bfd) + return false; + oasys_per_section (newsect)->data = (bfd_byte *) NULL; + oasys_per_section (newsect)->section = newsect; + oasys_per_section (newsect)->offset = 0; + oasys_per_section (newsect)->initialized = false; + newsect->alignment_power = 1; + /* Turn the section string into an index */ + + sscanf (newsect->name, "%u", &newsect->target_index); + + return true; +} + + +static long +oasys_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (! oasys_slurp_section_data (abfd)) + return -1; + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +static boolean +oasys_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + oasys_per_section_type *p = (oasys_per_section_type *) section->used_by_bfd; + oasys_slurp_section_data (abfd); + if (p->initialized == false) + { + (void) memset (location, 0, (int) count); + } + else + { + (void) memcpy (location, (PTR) (p->data + offset), (int) count); + } + return true; +} + + +long +oasys_canonicalize_reloc (ignore_abfd, section, relptr, symbols) + bfd *ignore_abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + unsigned int reloc_count = 0; + oasys_reloc_type *src = (oasys_reloc_type *) (section->relocation); + while (src != (oasys_reloc_type *) NULL) + { + abort (); + +#if 0 + if (src->relent.section == (asection *) NULL) + { + src->relent.sym_ptr_ptr = symbols + src->symbol; + } +#endif + + *relptr++ = &src->relent; + src = src->next; + reloc_count++; + } + *relptr = (arelent *) NULL; + return section->reloc_count = reloc_count; +} + + + + +/* Writing */ + + +/* Calculate the checksum and write one record */ +static boolean +oasys_write_record (abfd, type, record, size) + bfd *abfd; + oasys_record_enum_type type; + oasys_record_union_type *record; + size_t size; +{ + int checksum; + size_t i; + unsigned char *ptr; + + record->header.length = size; + record->header.type = (int) type; + record->header.check_sum = 0; + record->header.fill = 0; + ptr = (unsigned char *) &record->pad[0]; + checksum = 0; + for (i = 0; i < size; i++) + { + checksum += *ptr++; + } + record->header.check_sum = 0xff & (-checksum); + if (bfd_write ((PTR) record, 1, size, abfd) != size) + return false; + return true; +} + + +/* Write out all the symbols */ +static boolean +oasys_write_syms (abfd) + bfd *abfd; +{ + unsigned int count; + asymbol **generic = bfd_get_outsymbols (abfd); + unsigned int index = 0; + for (count = 0; count < bfd_get_symcount (abfd); count++) + { + + oasys_symbol_record_type symbol; + asymbol *CONST g = generic[count]; + + CONST char *src = g->name; + char *dst = symbol.name; + unsigned int l = 0; + + if (bfd_is_com_section (g->section)) + { + symbol.relb = RELOCATION_TYPE_COM; + bfd_h_put_16 (abfd, index, symbol.refno); + index++; + } + else if (bfd_is_abs_section (g->section)) + { + symbol.relb = RELOCATION_TYPE_ABS; + bfd_h_put_16 (abfd, 0, symbol.refno); + + } + else if (bfd_is_und_section (g->section)) + { + symbol.relb = RELOCATION_TYPE_UND; + bfd_h_put_16 (abfd, index, symbol.refno); + /* Overload the value field with the output index number */ + index++; + } + else if (g->flags & BSF_DEBUGGING) + { + /* throw it away */ + continue; + } + else + { + if (g->section == (asection *) NULL) + { + /* Sometime, the oasys tools give out a symbol with illegal + bits in it, we'll output it in the same broken way */ + + symbol.relb = RELOCATION_TYPE_REL | 0; + } + else + { + symbol.relb = RELOCATION_TYPE_REL | g->section->output_section->target_index; + } + bfd_h_put_16 (abfd, 0, symbol.refno); + } +#ifdef UNDERSCORE_HACK + if (src[l] == '_') + dst[l++] = '.'; +#endif + while (src[l]) + { + dst[l] = src[l]; + l++; + } + + bfd_h_put_32 (abfd, g->value, symbol.value); + + + if (g->flags & BSF_LOCAL) + { + if (! oasys_write_record (abfd, + oasys_record_is_local_enum, + (oasys_record_union_type *) & symbol, + offsetof (oasys_symbol_record_type, + name[0]) + l)) + return false; + } + else + { + if (! oasys_write_record (abfd, + oasys_record_is_symbol_enum, + (oasys_record_union_type *) & symbol, + offsetof (oasys_symbol_record_type, + name[0]) + l)) + return false; + } + g->value = index - 1; + } + + return true; +} + + + /* Write a section header for each section */ +static boolean +oasys_write_sections (abfd) + bfd *abfd; +{ + asection *s; + static oasys_section_record_type out; + + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if (!isdigit (s->name[0])) + { + (*_bfd_error_handler) + ("%s: can not represent section `%s' in oasys", + bfd_get_filename (abfd), s->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + out.relb = RELOCATION_TYPE_REL | s->target_index; + bfd_h_put_32 (abfd, s->_cooked_size, out.value); + bfd_h_put_32 (abfd, s->vma, out.vma); + + if (! oasys_write_record (abfd, + oasys_record_is_section_enum, + (oasys_record_union_type *) & out, + sizeof (out))) + return false; + } + return true; +} + +static boolean +oasys_write_header (abfd) + bfd *abfd; +{ + /* Create and write the header */ + oasys_header_record_type r; + size_t length = strlen (abfd->filename); + if (length > (size_t) sizeof (r.module_name)) + { + length = sizeof (r.module_name); + } + + (void) memcpy (r.module_name, + abfd->filename, + length); + (void) memset (r.module_name + length, + ' ', + sizeof (r.module_name) - length); + + r.version_number = OASYS_VERSION_NUMBER; + r.rev_number = OASYS_REV_NUMBER; + if (! oasys_write_record (abfd, + oasys_record_is_header_enum, + (oasys_record_union_type *) & r, + offsetof (oasys_header_record_type, + description[0]))) + return false; + + return true; +} + +static boolean +oasys_write_end (abfd) + bfd *abfd; +{ + oasys_end_record_type end; + unsigned char null = 0; + end.relb = RELOCATION_TYPE_ABS; + bfd_h_put_32 (abfd, abfd->start_address, end.entry); + bfd_h_put_16 (abfd, 0, end.fill); + end.zero = 0; + if (! oasys_write_record (abfd, + oasys_record_is_end_enum, + (oasys_record_union_type *) & end, + sizeof (end))) + return false; + if (bfd_write ((PTR) & null, 1, 1, abfd) != 1) + return false; + return true; +} + +static int +comp (ap, bp) + CONST PTR ap; + CONST PTR bp; +{ + arelent *a = *((arelent **) ap); + arelent *b = *((arelent **) bp); + return a->address - b->address; +} + +/* + Writing data.. + +*/ +static boolean +oasys_write_data (abfd) + bfd *abfd; +{ + asection *s; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if (s->flags & SEC_LOAD) + { + bfd_byte *raw_data = oasys_per_section (s)->data; + oasys_data_record_type processed_data; + bfd_size_type current_byte_index = 0; + unsigned int relocs_to_go = s->reloc_count; + arelent **p = s->orelocation; + if (s->reloc_count != 0) + { +/* Sort the reloc records so it's easy to insert the relocs into the + data */ + + qsort (s->orelocation, + s->reloc_count, + sizeof (arelent **), + comp); + } + current_byte_index = 0; + processed_data.relb = s->target_index | RELOCATION_TYPE_REL; + + while (current_byte_index < s->_cooked_size) + { + /* Scan forwards by eight bytes or however much is left and see if + there are any relocations going on */ + bfd_byte *mod = &processed_data.data[0]; + bfd_byte *dst = &processed_data.data[1]; + + unsigned int i = 0; + *mod = 0; + + + bfd_h_put_32 (abfd, s->vma + current_byte_index, + processed_data.addr); + + /* Don't start a relocation unless you're sure you can finish it + within the same data record. The worst case relocation is a + 4-byte relocatable value which is split across two modification + bytes (1 relocation byte + 2 symbol reference bytes + 2 data + + 1 modification byte + 2 data = 8 bytes total). That's where + the magic number 8 comes from. + */ + while (current_byte_index < s->_raw_size && dst <= + &processed_data.data[sizeof (processed_data.data) - 8]) + { + + + if (relocs_to_go != 0) + { + arelent *r = *p; + reloc_howto_type *const how = r->howto; + /* There is a relocation, is it for this byte ? */ + if (r->address == current_byte_index) + { + unsigned char rel_byte; + + p++; + relocs_to_go--; + + *mod |= (1 << i); + if (how->pc_relative) + { + rel_byte = RELOCATION_PCREL_BIT; + + /* Also patch the raw data so that it doesn't have + the -ve stuff any more */ + if (how->size != 2) + { + bfd_put_16 (abfd, + bfd_get_16 (abfd, raw_data) + + current_byte_index, raw_data); + } + + else + { + bfd_put_32 (abfd, + bfd_get_32 (abfd, raw_data) + + current_byte_index, raw_data); + } + } + else + { + rel_byte = 0; + } + if (how->size == 2) + { + rel_byte |= RELOCATION_32BIT_BIT; + } + + /* Is this a section relative relocation, or a symbol + relative relocation ? */ + abort (); + +#if 0 + if (r->section != (asection *) NULL) + { + /* The relent has a section attached, so it must be section + relative */ + rel_byte |= RELOCATION_TYPE_REL; + rel_byte |= r->section->output_section->target_index; + *dst++ = rel_byte; + } + else +#endif + { + asymbol *p = *(r->sym_ptr_ptr); + + /* If this symbol has a section attached, then it + has already been resolved. Change from a symbol + ref to a section ref */ + if (p->section != (asection *) NULL) + { + rel_byte |= RELOCATION_TYPE_REL; + rel_byte |= + p->section->output_section->target_index; + *dst++ = rel_byte; + } + else + { + rel_byte |= RELOCATION_TYPE_UND; + *dst++ = rel_byte; + /* Next two bytes are a symbol index - we can get + this from the symbol value which has been zapped + into the symbol index in the table when the + symbol table was written + */ + *dst++ = p->value >> 8; + *dst++ = p->value; + } + } +#define ADVANCE { if (++i >= 8) { i = 0; mod = dst++; *mod = 0; } current_byte_index++; } + /* relocations never occur from an unloadable section, + so we can assume that raw_data is not NULL + */ + *dst++ = *raw_data++; + ADVANCE + * dst++ = *raw_data++; + ADVANCE + if (how->size == 2) + { + *dst++ = *raw_data++; + ADVANCE + * dst++ = *raw_data++; + ADVANCE + } + continue; + } + } + /* If this is coming from an unloadable section then copy + zeros */ + if (raw_data == NULL) + { + *dst++ = 0; + } + else + { + *dst++ = *raw_data++; + } + ADVANCE + } + + /* Don't write a useless null modification byte */ + if (dst == mod + 1) + { + --dst; + } + + if (! oasys_write_record (abfd, + oasys_record_is_data_enum, + ((oasys_record_union_type *) + & processed_data), + dst - (bfd_byte *) & processed_data)) + return false; + } + } + } + + return true; +} + +static boolean +oasys_write_object_contents (abfd) + bfd *abfd; +{ + if (! oasys_write_header (abfd)) + return false; + if (! oasys_write_syms (abfd)) + return false; + if (! oasys_write_sections (abfd)) + return false; + if (! oasys_write_data (abfd)) + return false; + if (! oasys_write_end (abfd)) + return false; + return true; +} + + + + +/** exec and core file sections */ + +/* set section contents is complicated with OASYS since the format is +* not a byte image, but a record stream. +*/ +static boolean +oasys_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count != 0) + { + if (oasys_per_section (section)->data == (bfd_byte *) NULL) + { + oasys_per_section (section)->data = + (bfd_byte *) (bfd_alloc (abfd, section->_cooked_size)); + if (!oasys_per_section (section)->data) + return false; + } + (void) memcpy ((PTR) (oasys_per_section (section)->data + offset), + location, + (size_t) count); + } + return true; +} + + + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this +function exits. We read the strings into a buffer large enough to +hold them all plus all the cached symbol entries. */ + +static asymbol * +oasys_make_empty_symbol (abfd) + bfd *abfd; +{ + + oasys_symbol_type *new = + (oasys_symbol_type *) bfd_zalloc (abfd, sizeof (oasys_symbol_type)); + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + + + + +/* User should have checked the file flags; perhaps we should return +BFD_NO_MORE_SYMBOLS if there are none? */ + +static bfd * +oasys_openr_next_archived_file (arch, prev) + bfd *arch; + bfd *prev; +{ + oasys_ar_data_type *ar = OASYS_AR_DATA (arch); + oasys_module_info_type *p; + /* take the next one from the arch state, or reset */ + if (prev == (bfd *) NULL) + { + /* Reset the index - the first two entries are bogus*/ + ar->module_index = 0; + } + + p = ar->module + ar->module_index; + ar->module_index++; + + if (ar->module_index <= ar->module_count) + { + if (p->abfd == (bfd *) NULL) + { + p->abfd = _bfd_create_empty_archive_element_shell (arch); + p->abfd->origin = p->pos; + p->abfd->filename = p->name; + + /* Fixup a pointer to this element for the member */ + p->abfd->arelt_data = (PTR) p; + } + return p->abfd; + } + else + { + bfd_set_error (bfd_error_no_more_archived_files); + return (bfd *) NULL; + } +} + +static boolean +oasys_find_nearest_line (abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + char **filename_ptr; + char **functionname_ptr; + unsigned int *line_ptr; +{ + return false; + +} + +static int +oasys_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + oasys_module_info_type *mod = (oasys_module_info_type *) abfd->arelt_data; + if (mod == (oasys_module_info_type *) NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + else + { + buf->st_size = mod->size; + buf->st_mode = 0666; + return 0; + } +} + +static int +oasys_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +#define oasys_close_and_cleanup _bfd_generic_close_and_cleanup +#define oasys_bfd_free_cached_info _bfd_generic_bfd_free_cached_info + +#define oasys_slurp_armap bfd_true +#define oasys_slurp_extended_name_table bfd_true +#define oasys_construct_extended_name_table \ + ((boolean (*) PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_true) +#define oasys_truncate_arname bfd_dont_truncate_arname +#define oasys_write_armap \ + ((boolean (*) \ + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ + bfd_true) +#define oasys_read_ar_hdr bfd_nullvoidptr +#define oasys_get_elt_at_index _bfd_generic_get_elt_at_index +#define oasys_update_armap_timestamp bfd_true + +#define oasys_bfd_is_local_label bfd_generic_is_local_label +#define oasys_get_lineno _bfd_nosymbols_get_lineno +#define oasys_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define oasys_read_minisymbols _bfd_generic_read_minisymbols +#define oasys_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define oasys_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define oasys_set_arch_mach bfd_default_set_arch_mach + +#define oasys_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define oasys_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define oasys_bfd_relax_section bfd_generic_relax_section +#define oasys_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define oasys_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define oasys_bfd_final_link _bfd_generic_final_link +#define oasys_bfd_link_split_section _bfd_generic_link_split_section + +/*SUPPRESS 460 */ +const bfd_target oasys_vec = +{ + "oasys", /* name */ + bfd_target_oasys_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + {_bfd_dummy_target, + oasys_object_p, /* bfd_check_format */ + oasys_archive_p, + _bfd_dummy_target, + }, + { /* bfd_set_format */ + bfd_false, + oasys_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + { /* bfd_write_contents */ + bfd_false, + oasys_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (oasys), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (oasys), + BFD_JUMP_TABLE_SYMBOLS (oasys), + BFD_JUMP_TABLE_RELOCS (oasys), + BFD_JUMP_TABLE_WRITE (oasys), + BFD_JUMP_TABLE_LINK (oasys), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/opncls.c b/contrib/gdb/bfd/opncls.c new file mode 100644 index 000000000000..54528dbf48f6 --- /dev/null +++ b/contrib/gdb/bfd/opncls.c @@ -0,0 +1,604 @@ +/* opncls.c -- open and close a BFD. + Copyright (C) 1990 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + +/* fdopen is a loser -- we should use stdio exclusively. Unfortunately + if we do that we can't use fcntl. */ + + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +#ifndef HAVE_GETPAGESIZE +#define getpagesize() 2048 +#endif + +long _bfd_chunksize = -1; + +/* Return a new BFD. All BFD's are allocated through this routine. */ + +bfd * +_bfd_new_bfd () +{ + bfd *nbfd; + + nbfd = (bfd *)bfd_zmalloc (sizeof (bfd)); + if (!nbfd) + return 0; + + if (_bfd_chunksize <= 0) + { + _bfd_chunksize = getpagesize (); + if (_bfd_chunksize <= 0) + _bfd_chunksize = 2048; + /* Leave some slush space, since many malloc implementations + prepend a header, and may wind up wasting another page + because of it. */ + _bfd_chunksize -= 32; + } + + if (!obstack_begin(&nbfd->memory, _bfd_chunksize)) + { + bfd_set_error (bfd_error_no_memory); + return 0; + } + + nbfd->arch_info = &bfd_default_arch_struct; + + nbfd->direction = no_direction; + nbfd->iostream = NULL; + nbfd->where = 0; + nbfd->sections = (asection *)NULL; + nbfd->format = bfd_unknown; + nbfd->my_archive = (bfd *)NULL; + nbfd->origin = 0; + nbfd->opened_once = false; + nbfd->output_has_begun = false; + nbfd->section_count = 0; + nbfd->usrdata = (PTR)NULL; + nbfd->cacheable = false; + nbfd->flags = NO_FLAGS; + nbfd->mtime_set = false; + + return nbfd; +} + +/* Allocate a new BFD as a member of archive OBFD. */ + +bfd * +_bfd_new_bfd_contained_in (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = _bfd_new_bfd(); + nbfd->xvec = obfd->xvec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + nbfd->target_defaulted = obfd->target_defaulted; + return nbfd; +} + +/* +SECTION + Opening and closing BFDs + +*/ + +/* +FUNCTION + bfd_openr + +SYNOPSIS + bfd *bfd_openr(CONST char *filename, CONST char *target); + +DESCRIPTION + Open the file @var{filename} (using <>) with the target + @var{target}. Return a pointer to the created BFD. + + Calls <>, so @var{target} is interpreted as by + that function. + + If <> is returned then an error has occured. Possible errors + are <>, <> or <> error. +*/ + +bfd * +bfd_openr (filename, target) + CONST char *filename; + CONST char *target; +{ + bfd *nbfd; + const bfd_target *target_vec; + + nbfd = _bfd_new_bfd(); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_set_error (bfd_error_invalid_target); + return NULL; + } + + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_set_error (bfd_error_system_call); /* File didn't exist, or some such */ + bfd_release(nbfd,0); + return NULL; + } + return nbfd; +} + + +/* Don't try to `optimize' this function: + + o - We lock using stack space so that interrupting the locking + won't cause a storage leak. + o - We open the file stream last, since we don't want to have to + close it if anything goes wrong. Closing the stream means closing + the file descriptor too, even though we didn't open it. + */ +/* +FUNCTION + bfd_fdopenr + +SYNOPSIS + bfd *bfd_fdopenr(CONST char *filename, CONST char *target, int fd); + +DESCRIPTION + <> is to <> much like <> is to <>. + It opens a BFD on a file already described by the @var{fd} + supplied. + + When the file is later <>d, the file descriptor will be closed. + + If the caller desires that this file descriptor be cached by BFD + (opened as needed, closed as needed to free descriptors for + other opens), with the supplied @var{fd} used as an initial + file descriptor (but subject to closure at any time), call + bfd_set_cacheable(bfd, 1) on the returned BFD. The default is to + assume no cacheing; the file descriptor will remain open until + <>, and will not be affected by BFD operations on other + files. + + Possible errors are <>, <> and <>. +*/ + +bfd * +bfd_fdopenr (filename, target, fd) + CONST char *filename; + CONST char *target; + int fd; +{ + bfd *nbfd; + const bfd_target *target_vec; + int fdflags; + + bfd_set_error (bfd_error_system_call); +#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL) + fdflags = O_RDWR; /* Assume full access */ +#else + fdflags = fcntl (fd, F_GETFL, NULL); +#endif + if (fdflags == -1) return NULL; + + nbfd = _bfd_new_bfd(); + + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_set_error (bfd_error_invalid_target); + return NULL; + } +#if defined(VMS) || defined(__GO32__) || defined (WINGDB) + nbfd->iostream = (PTR)fopen(filename, FOPEN_RB); +#else + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RB); break; + case O_WRONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; + case O_RDWR: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; + default: abort (); + } +#endif + if (nbfd->iostream == NULL) { + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + + /* OK, put everything where it belongs */ + + nbfd->filename = filename; + + /* As a special case we allow a FD open for read/write to + be written through, although doing so requires that we end + the previous clause with a preposition. */ + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->direction = read_direction; break; + case O_WRONLY: nbfd->direction = write_direction; break; + case O_RDWR: nbfd->direction = both_direction; break; + default: abort (); + } + + if (! bfd_cache_init (nbfd)) + return NULL; + + return nbfd; +} + +/* +FUNCTION + bfd_openstreamr + +SYNOPSIS + bfd *bfd_openstreamr(); + +DESCRIPTION + + Open a BFD for read access on an existing stdio stream. When + the BFD is passed to <>, the stream will be closed. +*/ + +bfd * +bfd_openstreamr (filename, target, stream) + const char *filename; + const char *target; + FILE *stream; +{ + bfd *nbfd; + const bfd_target *target_vec; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) + { + bfd_set_error (bfd_error_invalid_target); + return NULL; + } + + nbfd->iostream = (PTR) stream; + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (! bfd_cache_init (nbfd)) + return NULL; + + return nbfd; +} + +/** bfd_openw -- open for writing. + Returns a pointer to a freshly-allocated BFD on success, or NULL. + + See comment by bfd_fdopenr before you try to modify this function. */ + +/* +FUNCTION + bfd_openw + +SYNOPSIS + bfd *bfd_openw(CONST char *filename, CONST char *target); + +DESCRIPTION + Create a BFD, associated with file @var{filename}, using the + file format @var{target}, and return a pointer to it. + + Possible errors are <>, <>, + <>. +*/ + +bfd * +bfd_openw (filename, target) + CONST char *filename; + CONST char *target; +{ + bfd *nbfd; + const bfd_target *target_vec; + + bfd_set_error (bfd_error_system_call); + + /* nbfd has to point to head of malloc'ed block so that bfd_close may + reclaim it correctly. */ + + nbfd = _bfd_new_bfd(); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) return NULL; + + nbfd->filename = filename; + nbfd->direction = write_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_set_error (bfd_error_system_call); /* File not writeable, etc */ + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + return nbfd; +} + +/* + +FUNCTION + bfd_close + +SYNOPSIS + boolean bfd_close(bfd *abfd); + +DESCRIPTION + + Close a BFD. If the BFD was open for writing, + then pending operations are completed and the file written out + and closed. If the created file is executable, then + <> is called to mark it as such. + + All memory attached to the BFD's obstacks is released. + + The file descriptor associated with the BFD is closed (even + if it was passed in to BFD by <>). + +RETURNS + <> is returned if all is ok, otherwise <>. +*/ + + +boolean +bfd_close (abfd) + bfd *abfd; +{ + boolean ret; + + if (!bfd_read_p (abfd)) + { + if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd))) + return false; + } + + if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) + return false; + + ret = bfd_cache_close (abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret + && abfd->direction == write_direction + && abfd->flags & EXEC_P) + { + struct stat buf; + + if (stat (abfd->filename, &buf) == 0) + { + int mask = umask (0); + umask (mask); + chmod (abfd->filename, + (0777 + & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask)))); + } + } + + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free (abfd); + + return ret; +} + +/* +FUNCTION + bfd_close_all_done + +SYNOPSIS + boolean bfd_close_all_done(bfd *); + +DESCRIPTION + Close a BFD. Differs from <> + since it does not complete any pending operations. This + routine would be used if the application had just used BFD for + swapping and didn't want to use any of the writing code. + + If the created file is executable, then <> is called + to mark it as such. + + All memory attached to the BFD's obstacks is released. + +RETURNS + <> is returned if all is ok, otherwise <>. + +*/ + +boolean +bfd_close_all_done (abfd) + bfd *abfd; +{ + boolean ret; + + ret = bfd_cache_close (abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret + && abfd->direction == write_direction + && abfd->flags & EXEC_P) + { + struct stat buf; + + if (stat (abfd->filename, &buf) == 0) + { + int mask = umask (0); + umask (mask); + chmod (abfd->filename, + (0x777 + & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask)))); + } + } + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free(abfd); + return ret; +} + + +/* +FUNCTION + bfd_alloc_size + +SYNOPSIS + bfd_size_type bfd_alloc_size(bfd *abfd); + +DESCRIPTION + Return the number of bytes in the obstacks connected to @var{abfd}. + +*/ + +bfd_size_type +bfd_alloc_size (abfd) + bfd *abfd; +{ + struct _obstack_chunk *chunk = abfd->memory.chunk; + size_t size = 0; + while (chunk) { + size += chunk->limit - &(chunk->contents[0]); + chunk = chunk->prev; + } + return size; +} + + + +/* +FUNCTION + bfd_create + +SYNOPSIS + bfd *bfd_create(CONST char *filename, bfd *templ); + +DESCRIPTION + Create a new BFD in the manner of + <>, but without opening a file. The new BFD + takes the target from the target used by @var{template}. The + format is always set to <>. + +*/ + +bfd * +bfd_create (filename, templ) + CONST char *filename; + bfd *templ; +{ + bfd *nbfd = _bfd_new_bfd(); + if (nbfd == (bfd *)NULL) + return (bfd *)NULL; + nbfd->filename = filename; + if(templ) { + nbfd->xvec = templ->xvec; + } + nbfd->direction = no_direction; + bfd_set_format(nbfd, bfd_object); + return nbfd; +} + +/* +INTERNAL_FUNCTION + bfd_alloc_by_size_t + +SYNOPSIS + PTR bfd_alloc_by_size_t(bfd *abfd, size_t wanted); + +DESCRIPTION + Allocate a block of @var{wanted} bytes of memory in the obstack + attatched to <> and return a pointer to it. +*/ + + +PTR +bfd_alloc_by_size_t (abfd, size) + bfd *abfd; + size_t size; +{ + PTR ret; + + ret = obstack_alloc (&(abfd->memory), size); + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +void +bfd_alloc_grow (abfd, ptr, size) + bfd *abfd; + PTR ptr; + size_t size; +{ + (void) obstack_grow(&(abfd->memory), ptr, size); +} + +PTR +bfd_alloc_finish (abfd) + bfd *abfd; +{ + PTR ret; + + ret = obstack_finish (&(abfd->memory)); + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +PTR +bfd_alloc (abfd, size) + bfd *abfd; + size_t size; +{ + return bfd_alloc_by_size_t(abfd, (size_t)size); +} + +PTR +bfd_zalloc (abfd, size) + bfd *abfd; + size_t size; +{ + PTR res; + res = bfd_alloc(abfd, size); + if (res) + memset(res, 0, (size_t)size); + return res; +} diff --git a/contrib/gdb/bfd/osf-core.c b/contrib/gdb/bfd/osf-core.c new file mode 100644 index 000000000000..6d1df9b37094 --- /dev/null +++ b/contrib/gdb/bfd/osf-core.c @@ -0,0 +1,256 @@ +/* BFD back-end for OSF/1 core files. + Copyright 1993, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file can only be compiled on systems which use OSF/1 style + core files. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include +#include +#include +#include + +/* forward declarations */ + +static asection * +make_bfd_asection PARAMS ((bfd *, CONST char *, flagword, bfd_size_type, + bfd_vma, file_ptr)); +static asymbol * +osf_core_make_empty_symbol PARAMS ((bfd *)); +static const bfd_target * +osf_core_core_file_p PARAMS ((bfd *)); +static char * +osf_core_core_file_failing_command PARAMS ((bfd *)); +static int +osf_core_core_file_failing_signal PARAMS ((bfd *)); +static boolean +osf_core_core_file_matches_executable_p PARAMS ((bfd *, bfd *)); +static void +swap_abort PARAMS ((void)); + +/* These are stored in the bfd's tdata */ + +struct osf_core_struct +{ + int sig; + char cmd[MAXCOMLEN + 1]; +}; + +#define core_hdr(bfd) ((bfd)->tdata.osf_core_data) +#define core_signal(bfd) (core_hdr(bfd)->sig) +#define core_command(bfd) (core_hdr(bfd)->cmd) + +static asection * +make_bfd_asection (abfd, name, flags, _raw_size, vma, filepos) + bfd *abfd; + CONST char *name; + flagword flags; + bfd_size_type _raw_size; + bfd_vma vma; + file_ptr filepos; +{ + asection *asect; + + asect = bfd_make_section_anyway (abfd, name); + if (!asect) + return NULL; + + asect->flags = flags; + asect->_raw_size = _raw_size; + asect->vma = vma; + asect->filepos = filepos; + asect->alignment_power = 8; + + return asect; +} + +static asymbol * +osf_core_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +static const bfd_target * +osf_core_core_file_p (abfd) + bfd *abfd; +{ + int val; + int i; + char *secname; + struct core_filehdr core_header; + + val = bfd_read ((PTR)&core_header, 1, sizeof core_header, abfd); + if (val != sizeof core_header) + return NULL; + + if (strncmp (core_header.magic, "Core", 4) != 0) + return NULL; + + core_hdr (abfd) = (struct osf_core_struct *) + bfd_zalloc (abfd, sizeof (struct osf_core_struct)); + if (!core_hdr (abfd)) + return NULL; + + strncpy (core_command (abfd), core_header.name, MAXCOMLEN + 1); + core_signal (abfd) = core_header.signo; + + for (i = 0; i < core_header.nscns; i++) + { + struct core_scnhdr core_scnhdr; + flagword flags; + + val = bfd_read ((PTR)&core_scnhdr, 1, sizeof core_scnhdr, abfd); + if (val != sizeof core_scnhdr) + break; + + /* Skip empty sections. */ + if (core_scnhdr.size == 0 || core_scnhdr.scnptr == 0) + continue; + + switch (core_scnhdr.scntype) + { + case SCNRGN: + secname = ".data"; + flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + break; + case SCNSTACK: + secname = ".stack"; + flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + break; + case SCNREGS: + secname = ".reg"; + flags = SEC_HAS_CONTENTS; + break; + default: + (*_bfd_error_handler) ("Unhandled OSF/1 core file section type %d\n", + core_scnhdr.scntype); + continue; + } + + if (!make_bfd_asection (abfd, secname, flags, + (bfd_size_type) core_scnhdr.size, + (bfd_vma) core_scnhdr.vaddr, + (file_ptr) core_scnhdr.scnptr)) + return NULL; + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + return abfd->xvec; +} + +static char * +osf_core_core_file_failing_command (abfd) + bfd *abfd; +{ + return core_command (abfd); +} + +/* ARGSUSED */ +static int +osf_core_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_signal (abfd); +} + +/* ARGSUSED */ +static boolean +osf_core_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +#define osf_core_get_symtab_upper_bound _bfd_nosymbols_get_symtab_upper_bound +#define osf_core_get_symtab _bfd_nosymbols_get_symtab +#define osf_core_print_symbol _bfd_nosymbols_print_symbol +#define osf_core_get_symbol_info _bfd_nosymbols_get_symbol_info +#define osf_core_bfd_is_local_label _bfd_nosymbols_bfd_is_local_label +#define osf_core_get_lineno _bfd_nosymbols_get_lineno +#define osf_core_find_nearest_line _bfd_nosymbols_find_nearest_line +#define osf_core_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define osf_core_read_minisymbols _bfd_nosymbols_read_minisymbols +#define osf_core_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +/* If somebody calls any byte-swapping routines, shoot them. */ +static void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target osf_core_vec = + { + "osf-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + osf_core_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (osf_core), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (osf_core), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; diff --git a/contrib/gdb/bfd/pc532-mach.c b/contrib/gdb/bfd/pc532-mach.c new file mode 100644 index 000000000000..73f4ac49e827 --- /dev/null +++ b/contrib/gdb/bfd/pc532-mach.c @@ -0,0 +1,121 @@ +/* BFD back-end for Mach3/532 a.out-ish binaries. + Copyright (C) 1990, 1991, 1992, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Ian Dall + * 19-Apr-94 + * + * Formerly part of aout-pc532-mach.c. Split out to allow more + * flexibility with multiple formats. + * + */ +/* This architecture has N_TXTOFF and N_TXTADDR defined as if + * N_HEADER_IN_TEXT, but the a_text entry (text size) does not include the + * space for the header. So we have N_HEADER_IN_TEXT defined to + * 1 and specially define our own N_TXTSIZE + */ + +#define N_HEADER_IN_TEXT(x) 1 +#define N_TXTSIZE(x) ((x).a_text) + + +#define TEXT_START_ADDR 0x10000 /* from old ld */ +#define TARGET_PAGE_SIZE 0x1000 /* from old ld, 032 & 532 are really 512/4k */ + +/* Use a_entry of 0 to distinguish object files from OMAGIC executables */ +#define N_TXTADDR(x) \ + (N_MAGIC(x) == OMAGIC ? \ + ((x).a_entry < TEXT_START_ADDR? 0: TEXT_START_ADDR): \ + (N_MAGIC(x) == NMAGIC? TEXT_START_ADDR: \ + TEXT_START_ADDR + EXEC_BYTES_SIZE)) + +#define SEGMENT_SIZE TARGET_PAGE_SIZE + +#define N_SHARED_LIB(x) 0 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_ns32k + +#define MY(OP) CAT(pc532machaout_,OP) + +/* Must be the same as aout-ns32k.c */ +#define NAME(x,y) CAT3(ns32kaout,_32_,y) + +#define TARGETNAME "a.out-pc532-mach" + +#include "bfd.h" +#include "sysdep.h" +#include "libaout.h" +#include "libbfd.h" +#include "aout/aout64.h" + +/* We can`t use the MYNS macro here for cpp reasons too subtle for me -- IWD */ + +#define MY_bfd_reloc_type_lookup ns32kaout_bfd_reloc_type_lookup + +/* libaout doesn't use NAME for these ... */ + +#define MY_get_section_contents aout_32_get_section_contents + +#define MY_text_includes_header 1 + +#define MY_exec_header_not_counted 1 + +#define MYNSX(OP) CAT(ns32kaout_,OP) +reloc_howto_type * +MYNSX(bfd_reloc_type_lookup) + PARAMS((bfd *abfd AND + bfd_reloc_code_real_type code)); + +boolean +MYNSX(write_object_contents) + PARAMS((bfd *abfd)); + +static boolean +MY(write_object_contents) (abfd) +bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + BFD_ASSERT (bfd_get_arch (abfd) == bfd_arch_ns32k); + switch (bfd_get_mach (abfd)) + { + case 32032: + N_SET_MACHTYPE (*execp, M_NS32032); + break; + case 32532: + default: + N_SET_MACHTYPE (*execp, M_NS32532); + break; + } + N_SET_FLAGS (*execp, aout_backend_info (abfd)->exec_hdr_flags); + + WRITE_HEADERS(abfd, execp); + + return true; +} + +#define MY_write_object_contents MY(write_object_contents) + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/pe-arm.c b/contrib/gdb/bfd/pe-arm.c new file mode 100644 index 000000000000..fa97e2e8413d --- /dev/null +++ b/contrib/gdb/bfd/pe-arm.c @@ -0,0 +1,32 @@ +/* BFD back-end for ARM PECOFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_LITTLE_SYM armpe_little_vec +#define TARGET_LITTLE_NAME "pe-arm-little" +#define TARGET_BIG_SYM armpe_big_vec +#define TARGET_BIG_NAME "pe-arm-big" + +#define COFF_OBJ_WITH_PE +#define COFF_WITH_PE +#define PCRELOFFSET true + +#include "coff-arm.c" diff --git a/contrib/gdb/bfd/pe-i386.c b/contrib/gdb/bfd/pe-i386.c new file mode 100644 index 000000000000..878993e510cc --- /dev/null +++ b/contrib/gdb/bfd/pe-i386.c @@ -0,0 +1,30 @@ +/* BFD back-end for Intel 386 PECOFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + + +#define TARGET_SYM i386pe_vec +#define TARGET_NAME "pe-i386" +#define COFF_OBJ_WITH_PE +#define COFF_WITH_PE +#define PCRELOFFSET true +#define TARGET_UNDERSCORE '_' +#include "coff-i386.c" diff --git a/contrib/gdb/bfd/pe-ppc.c b/contrib/gdb/bfd/pe-ppc.c new file mode 100644 index 000000000000..67fdda04e6c8 --- /dev/null +++ b/contrib/gdb/bfd/pe-ppc.c @@ -0,0 +1,39 @@ +/* BFD back-end for Intel 386 PECOFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bfd.h" +#include "sysdep.h" + + +#define E_FILENMLEN 18 + +#define PPC + +#define TARGET_LITTLE_SYM bfd_powerpcle_pe_vec +#define TARGET_LITTLE_NAME "pe-powerpcle" + +#define TARGET_BIG_SYM bfd_powerpc_pe_vec +#define TARGET_BIG_NAME "pe-powerpc" + +#define COFF_OBJ_WITH_PE +#define COFF_WITH_PE + +/* FIXME: verify PCRELOFFSET is always false */ + +#include "coff-ppc.c" diff --git a/contrib/gdb/bfd/pei-arm.c b/contrib/gdb/bfd/pei-arm.c new file mode 100644 index 000000000000..fd9d398432d0 --- /dev/null +++ b/contrib/gdb/bfd/pei-arm.c @@ -0,0 +1,33 @@ +/* BFD back-end for arm PE IMAGE COFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_LITTLE_SYM armpei_little_vec +#define TARGET_LITTLE_NAME "pei-arm-little" +#define TARGET_BIG_SYM armpei_big_vec +#define TARGET_BIG_NAME "pei-arm-big" + +#define IMAGE_BASE NT_IMAGE_BASE +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define PCRELOFFSET true + +#include "coff-arm.c" diff --git a/contrib/gdb/bfd/pei-i386.c b/contrib/gdb/bfd/pei-i386.c new file mode 100644 index 000000000000..8754e7c55e36 --- /dev/null +++ b/contrib/gdb/bfd/pei-i386.c @@ -0,0 +1,33 @@ +/* BFD back-end for Intel 386 PE IMAGE COFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#define TARGET_SYM i386pei_vec +#define TARGET_NAME "pei-i386" +#define IMAGE_BASE NT_IMAGE_BASE +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE +#define PCRELOFFSET true +#define TARGET_UNDERSCORE '_' +#include "coff-i386.c" + + + diff --git a/contrib/gdb/bfd/pei-ppc.c b/contrib/gdb/bfd/pei-ppc.c new file mode 100644 index 000000000000..fc8f89fddb6d --- /dev/null +++ b/contrib/gdb/bfd/pei-ppc.c @@ -0,0 +1,44 @@ +/* BFD back-end for Intel 386 PE IMAGE COFF files. + Copyright 1995 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +/* setting up for a PE environment stolen directly from the i386 structure */ +#define E_FILNMLEN 18 /* # characters in a file name */ + +#define PPC + +#define TARGET_LITTLE_SYM bfd_powerpcle_pei_vec +#define TARGET_LITTLE_NAME "pei-powerpcle" + +#define TARGET_BIG_SYM bfd_powerpc_pei_vec +#define TARGET_BIG_NAME "pei-powerpc" + +#define IMAGE_BASE NT_IMAGE_BASE + +#define COFF_IMAGE_WITH_PE +#define COFF_WITH_PE + +/* FIXME: Verify PCRELOFFSET is always false */ + +#include "coff-ppc.c" + + + diff --git a/contrib/gdb/bfd/peicode.h b/contrib/gdb/bfd/peicode.h new file mode 100644 index 000000000000..a7a47469e3d0 --- /dev/null +++ b/contrib/gdb/bfd/peicode.h @@ -0,0 +1,1861 @@ +/* Support for the generic parts of most COFF variants, for BFD. + Copyright 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +Most of this hacked by Steve Chamberlain, + sac@cygnus.com +*/ + + + +#define coff_bfd_print_private_bfd_data pe_print_private_bfd_data +#define coff_mkobject pe_mkobject +#define coff_mkobject_hook pe_mkobject_hook + +#ifndef GET_FCN_LNNOPTR +#define GET_FCN_LNNOPTR(abfd, ext) \ + bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif + +#ifndef GET_FCN_ENDNDX +#define GET_FCN_ENDNDX(abfd, ext) \ + bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif + +#ifndef PUT_FCN_LNNOPTR +#define PUT_FCN_LNNOPTR(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif +#ifndef PUT_FCN_ENDNDX +#define PUT_FCN_ENDNDX(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif +#ifndef GET_LNSZ_LNNO +#define GET_LNSZ_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef GET_LNSZ_SIZE +#define GET_LNSZ_SIZE(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef PUT_LNSZ_LNNO +#define PUT_LNSZ_LNNO(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef PUT_LNSZ_SIZE +#define PUT_LNSZ_SIZE(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte*) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef GET_SCN_SCNLEN +#define GET_SCN_SCNLEN(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef GET_SCN_NRELOC +#define GET_SCN_NRELOC(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef GET_SCN_NLINNO +#define GET_SCN_NLINNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nlinno) +#endif +#ifndef PUT_SCN_SCNLEN +#define PUT_SCN_SCNLEN(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef PUT_SCN_NRELOC +#define PUT_SCN_NRELOC(abfd,in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef PUT_SCN_NLINNO +#define PUT_SCN_NLINNO(abfd,in, ext) bfd_h_put_16(abfd,in, (bfd_byte *) ext->x_scn.x_nlinno) +#endif +#ifndef GET_LINENO_LNNO +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) (ext->l_lnno)); +#endif +#ifndef PUT_LINENO_LNNO +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_16(abfd,val, (bfd_byte *) (ext->l_lnno)); +#endif + +/* The f_symptr field in the filehdr is sometimes 64 bits. */ +#ifndef GET_FILEHDR_SYMPTR +#define GET_FILEHDR_SYMPTR bfd_h_get_32 +#endif +#ifndef PUT_FILEHDR_SYMPTR +#define PUT_FILEHDR_SYMPTR bfd_h_put_32 +#endif + +/* Some fields in the aouthdr are sometimes 64 bits. */ +#ifndef GET_AOUTHDR_TSIZE +#define GET_AOUTHDR_TSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TSIZE +#define PUT_AOUTHDR_TSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DSIZE +#define GET_AOUTHDR_DSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DSIZE +#define PUT_AOUTHDR_DSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_BSIZE +#define GET_AOUTHDR_BSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_BSIZE +#define PUT_AOUTHDR_BSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_ENTRY +#define GET_AOUTHDR_ENTRY bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_ENTRY +#define PUT_AOUTHDR_ENTRY bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_TEXT_START +#define GET_AOUTHDR_TEXT_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TEXT_START +#define PUT_AOUTHDR_TEXT_START bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DATA_START +#define GET_AOUTHDR_DATA_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DATA_START +#define PUT_AOUTHDR_DATA_START bfd_h_put_32 +#endif + +/* Some fields in the scnhdr are sometimes 64 bits. */ +#ifndef GET_SCNHDR_PADDR +#define GET_SCNHDR_PADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_PADDR +#define PUT_SCNHDR_PADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_VADDR +#define GET_SCNHDR_VADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_VADDR +#define PUT_SCNHDR_VADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SIZE +#define GET_SCNHDR_SIZE bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SIZE +#define PUT_SCNHDR_SIZE bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SCNPTR +#define GET_SCNHDR_SCNPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SCNPTR +#define PUT_SCNHDR_SCNPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_RELPTR +#define GET_SCNHDR_RELPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_RELPTR +#define PUT_SCNHDR_RELPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_LNNOPTR +#define GET_SCNHDR_LNNOPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_LNNOPTR +#define PUT_SCNHDR_LNNOPTR bfd_h_put_32 +#endif + + + +/**********************************************************************/ + +static void +coff_swap_reloc_in (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + RELOC *reloc_src = (RELOC *) src; + struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; + + reloc_dst->r_vaddr = bfd_h_get_32(abfd, (bfd_byte *)reloc_src->r_vaddr); + reloc_dst->r_symndx = bfd_h_get_signed_32(abfd, (bfd_byte *) reloc_src->r_symndx); + + reloc_dst->r_type = bfd_h_get_16(abfd, (bfd_byte *) reloc_src->r_type); + +#ifdef SWAP_IN_RELOC_OFFSET + reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET(abfd, + (bfd_byte *) reloc_src->r_offset); +#endif +} + + +static unsigned int +coff_swap_reloc_out (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + struct internal_reloc *reloc_src = (struct internal_reloc *)src; + struct external_reloc *reloc_dst = (struct external_reloc *)dst; + bfd_h_put_32(abfd, reloc_src->r_vaddr, (bfd_byte *) reloc_dst->r_vaddr); + bfd_h_put_32(abfd, reloc_src->r_symndx, (bfd_byte *) reloc_dst->r_symndx); + + bfd_h_put_16(abfd, reloc_src->r_type, (bfd_byte *) + reloc_dst->r_type); + +#ifdef SWAP_OUT_RELOC_OFFSET + SWAP_OUT_RELOC_OFFSET(abfd, + reloc_src->r_offset, + (bfd_byte *) reloc_dst->r_offset); +#endif +#ifdef SWAP_OUT_RELOC_EXTRA + SWAP_OUT_RELOC_EXTRA(abfd,reloc_src, reloc_dst); +#endif + return sizeof(struct external_reloc); +} + + +static void +coff_swap_filehdr_in (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + FILHDR *filehdr_src = (FILHDR *) src; + struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; + filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *) filehdr_src->f_magic); + filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_nscns); + filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_timdat); + + filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_nsyms); + filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_flags); + filehdr_dst->f_symptr = bfd_h_get_32 (abfd, (bfd_byte *) filehdr_src->f_symptr); + + /* Other people's tools sometimes generate headers + with an nsyms but a zero symptr. */ + if (filehdr_dst->f_nsyms && filehdr_dst->f_symptr) + { + filehdr_dst->f_flags |= HAS_SYMS; + } + else + { + filehdr_dst->f_symptr = 0; + filehdr_dst->f_nsyms = 0; + filehdr_dst->f_flags &= ~HAS_SYMS; + } + + filehdr_dst->f_opthdr = bfd_h_get_16(abfd, + (bfd_byte *)filehdr_src-> f_opthdr); +} + +#ifdef COFF_IMAGE_WITH_PE + +static unsigned int +coff_swap_filehdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + int idx; + struct internal_filehdr *filehdr_in = (struct internal_filehdr *)in; + FILHDR *filehdr_out = (FILHDR *)out; + + if (pe_data (abfd)->has_reloc_section) + filehdr_in->f_flags &= ~F_RELFLG; + + if (pe_data (abfd)->dll) + filehdr_in->f_flags |= F_DLL; + + filehdr_in->pe.e_magic = DOSMAGIC; + filehdr_in->pe.e_cblp = 0x90; + filehdr_in->pe.e_cp = 0x3; + filehdr_in->pe.e_crlc = 0x0; + filehdr_in->pe.e_cparhdr = 0x4; + filehdr_in->pe.e_minalloc = 0x0; + filehdr_in->pe.e_maxalloc = 0xffff; + filehdr_in->pe.e_ss = 0x0; + filehdr_in->pe.e_sp = 0xb8; + filehdr_in->pe.e_csum = 0x0; + filehdr_in->pe.e_ip = 0x0; + filehdr_in->pe.e_cs = 0x0; + filehdr_in->pe.e_lfarlc = 0x40; + filehdr_in->pe.e_ovno = 0x0; + + for (idx=0; idx < 4; idx++) + filehdr_in->pe.e_res[idx] = 0x0; + + filehdr_in->pe.e_oemid = 0x0; + filehdr_in->pe.e_oeminfo = 0x0; + + for (idx=0; idx < 10; idx++) + filehdr_in->pe.e_res2[idx] = 0x0; + + filehdr_in->pe.e_lfanew = 0x80; + + /* this next collection of data are mostly just characters. It appears + to be constant within the headers put on NT exes */ + filehdr_in->pe.dos_message[0] = 0x0eba1f0e; + filehdr_in->pe.dos_message[1] = 0xcd09b400; + filehdr_in->pe.dos_message[2] = 0x4c01b821; + filehdr_in->pe.dos_message[3] = 0x685421cd; + filehdr_in->pe.dos_message[4] = 0x70207369; + filehdr_in->pe.dos_message[5] = 0x72676f72; + filehdr_in->pe.dos_message[6] = 0x63206d61; + filehdr_in->pe.dos_message[7] = 0x6f6e6e61; + filehdr_in->pe.dos_message[8] = 0x65622074; + filehdr_in->pe.dos_message[9] = 0x6e757220; + filehdr_in->pe.dos_message[10] = 0x206e6920; + filehdr_in->pe.dos_message[11] = 0x20534f44; + filehdr_in->pe.dos_message[12] = 0x65646f6d; + filehdr_in->pe.dos_message[13] = 0x0a0d0d2e; + filehdr_in->pe.dos_message[14] = 0x24; + filehdr_in->pe.dos_message[15] = 0x0; + filehdr_in->pe.nt_signature = NT_SIGNATURE; + + + + bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic); + bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns); + + bfd_h_put_32(abfd, time (0), (bfd_byte *) filehdr_out->f_timdat); + PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr, + (bfd_byte *) filehdr_out->f_symptr); + bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms); + bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr); + bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags); + + /* put in extra dos header stuff. This data remains essentially + constant, it just has to be tacked on to the beginning of all exes + for NT */ + bfd_h_put_16(abfd, filehdr_in->pe.e_magic, (bfd_byte *) filehdr_out->e_magic); + bfd_h_put_16(abfd, filehdr_in->pe.e_cblp, (bfd_byte *) filehdr_out->e_cblp); + bfd_h_put_16(abfd, filehdr_in->pe.e_cp, (bfd_byte *) filehdr_out->e_cp); + bfd_h_put_16(abfd, filehdr_in->pe.e_crlc, (bfd_byte *) filehdr_out->e_crlc); + bfd_h_put_16(abfd, filehdr_in->pe.e_cparhdr, + (bfd_byte *) filehdr_out->e_cparhdr); + bfd_h_put_16(abfd, filehdr_in->pe.e_minalloc, + (bfd_byte *) filehdr_out->e_minalloc); + bfd_h_put_16(abfd, filehdr_in->pe.e_maxalloc, + (bfd_byte *) filehdr_out->e_maxalloc); + bfd_h_put_16(abfd, filehdr_in->pe.e_ss, (bfd_byte *) filehdr_out->e_ss); + bfd_h_put_16(abfd, filehdr_in->pe.e_sp, (bfd_byte *) filehdr_out->e_sp); + bfd_h_put_16(abfd, filehdr_in->pe.e_csum, (bfd_byte *) filehdr_out->e_csum); + bfd_h_put_16(abfd, filehdr_in->pe.e_ip, (bfd_byte *) filehdr_out->e_ip); + bfd_h_put_16(abfd, filehdr_in->pe.e_cs, (bfd_byte *) filehdr_out->e_cs); + bfd_h_put_16(abfd, filehdr_in->pe.e_lfarlc, (bfd_byte *) filehdr_out->e_lfarlc); + bfd_h_put_16(abfd, filehdr_in->pe.e_ovno, (bfd_byte *) filehdr_out->e_ovno); + { + int idx; + for (idx=0; idx < 4; idx++) + bfd_h_put_16(abfd, filehdr_in->pe.e_res[idx], + (bfd_byte *) filehdr_out->e_res[idx]); + } + bfd_h_put_16(abfd, filehdr_in->pe.e_oemid, (bfd_byte *) filehdr_out->e_oemid); + bfd_h_put_16(abfd, filehdr_in->pe.e_oeminfo, + (bfd_byte *) filehdr_out->e_oeminfo); + { + int idx; + for (idx=0; idx < 10; idx++) + bfd_h_put_16(abfd, filehdr_in->pe.e_res2[idx], + (bfd_byte *) filehdr_out->e_res2[idx]); + } + bfd_h_put_32(abfd, filehdr_in->pe.e_lfanew, (bfd_byte *) filehdr_out->e_lfanew); + + { + int idx; + for (idx=0; idx < 16; idx++) + bfd_h_put_32(abfd, filehdr_in->pe.dos_message[idx], + (bfd_byte *) filehdr_out->dos_message[idx]); + } + + /* also put in the NT signature */ + bfd_h_put_32(abfd, filehdr_in->pe.nt_signature, + (bfd_byte *) filehdr_out->nt_signature); + + + + + return sizeof(FILHDR); +} +#else + +static unsigned int +coff_swap_filehdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_filehdr *filehdr_in = (struct internal_filehdr *)in; + FILHDR *filehdr_out = (FILHDR *)out; + + bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic); + bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns); + bfd_h_put_32(abfd, filehdr_in->f_timdat, (bfd_byte *) filehdr_out->f_timdat); + PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr, + (bfd_byte *) filehdr_out->f_symptr); + bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms); + bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr); + bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags); + + return sizeof(FILHDR); +} + +#endif + + +static void +coff_swap_sym_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + SYMENT *ext = (SYMENT *)ext1; + struct internal_syment *in = (struct internal_syment *)in1; + + if( ext->e.e_name[0] == 0) { + in->_n._n_n._n_zeroes = 0; + in->_n._n_n._n_offset = bfd_h_get_32(abfd, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(in->_n._n_name, ext->e.e_name, SYMNMLEN); +#endif + } + + in->n_value = bfd_h_get_32(abfd, (bfd_byte *) ext->e_value); + in->n_scnum = bfd_h_get_16(abfd, (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2){ + in->n_type = bfd_h_get_16(abfd, (bfd_byte *) ext->e_type); + } + else { + in->n_type = bfd_h_get_32(abfd, (bfd_byte *) ext->e_type); + } + in->n_sclass = bfd_h_get_8(abfd, ext->e_sclass); + in->n_numaux = bfd_h_get_8(abfd, ext->e_numaux); + + /* The section symbols for the .idata$ sections have class 68, which MS + documentation indicates is a section symbol. The problem is that the + value field in the symbol is simply a copy of the .idata section's flags + rather than something useful. When these symbols are encountered, change + the value to 0 and the section number to 1 so that they will be handled + somewhat correctly in the bfd code. */ + if (in->n_sclass == 0x68) { + in->n_value = 0x0; + in->n_scnum = 1; + /* I have tried setting the class to 3 and using the following to set + the section number. This will put the address of the pointer to the + string kernel32.dll at addresses 0 and 0x10 off start of idata section + which is not correct */ + /* if (strcmp (in->_n._n_name, ".idata$4") == 0) */ + /* in->n_scnum = 3; */ + /* else */ + /* in->n_scnum = 2; */ + } + +#ifdef coff_swap_sym_in_hook + coff_swap_sym_in_hook(abfd, ext1, in1); +#endif +} + +static unsigned int +coff_swap_sym_out (abfd, inp, extp) + bfd *abfd; + PTR inp; + PTR extp; +{ + struct internal_syment *in = (struct internal_syment *)inp; + SYMENT *ext =(SYMENT *)extp; + if(in->_n._n_name[0] == 0) { + bfd_h_put_32(abfd, 0, (bfd_byte *) ext->e.e.e_zeroes); + bfd_h_put_32(abfd, in->_n._n_n._n_offset, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(ext->e.e_name, in->_n._n_name, SYMNMLEN); +#endif + } + + bfd_h_put_32(abfd, in->n_value , (bfd_byte *) ext->e_value); + bfd_h_put_16(abfd, in->n_scnum , (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2) + { + bfd_h_put_16(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + else + { + bfd_h_put_32(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + bfd_h_put_8(abfd, in->n_sclass , ext->e_sclass); + bfd_h_put_8(abfd, in->n_numaux , ext->e_numaux); + + return sizeof(SYMENT); +} + +static void +coff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1) + bfd *abfd; + PTR ext1; + int type; + int class; + int indx; + int numaux; + PTR in1; +{ + AUXENT *ext = (AUXENT *)ext1; + union internal_auxent *in = (union internal_auxent *)in1; + + switch (class) { + case C_FILE: + if (ext->x_file.x_fname[0] == 0) { + in->x_file.x_n.x_zeroes = 0; + in->x_file.x_n.x_offset = + bfd_h_get_32(abfd, (bfd_byte *) ext->x_file.x_n.x_offset); + } else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN); +#endif + } + return; + + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + in->x_scn.x_scnlen = GET_SCN_SCNLEN(abfd, ext); + in->x_scn.x_nreloc = GET_SCN_NRELOC(abfd, ext); + in->x_scn.x_nlinno = GET_SCN_NLINNO(abfd, ext); + return; + } + break; + } + + in->x_sym.x_tagndx.l = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + in->x_sym.x_tvndx = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (class == C_BLOCK || ISFCN (type) || ISTAG (class)) + { + in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext); + in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext); + } + else + { +#if DIMNUM != E_DIMNUM + #error we need to cope with truncating or extending DIMNUM +#endif + in->x_sym.x_fcnary.x_ary.x_dimen[0] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + in->x_sym.x_fcnary.x_ary.x_dimen[1] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + in->x_sym.x_fcnary.x_ary.x_dimen[2] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + in->x_sym.x_fcnary.x_ary.x_dimen[3] = + bfd_h_get_16 (abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]); + } + + if (ISFCN(type)) { + in->x_sym.x_misc.x_fsize = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_fsize); + } + else { + in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO(abfd, ext); + in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE(abfd, ext); + } +} + +static unsigned int +coff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp) + bfd *abfd; + PTR inp; + int type; + int class; + int indx; + int numaux; + PTR extp; +{ + union internal_auxent *in = (union internal_auxent *)inp; + AUXENT *ext = (AUXENT *)extp; + + memset((PTR)ext, 0, AUXESZ); + switch (class) { + case C_FILE: + if (in->x_file.x_fname[0] == 0) { + bfd_h_put_32(abfd, 0, (bfd_byte *) ext->x_file.x_n.x_zeroes); + bfd_h_put_32(abfd, + in->x_file.x_n.x_offset, + (bfd_byte *) ext->x_file.x_n.x_offset); + } + else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN); +#endif + } + return sizeof (AUXENT); + + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + PUT_SCN_SCNLEN(abfd, in->x_scn.x_scnlen, ext); + PUT_SCN_NRELOC(abfd, in->x_scn.x_nreloc, ext); + PUT_SCN_NLINNO(abfd, in->x_scn.x_nlinno, ext); + return sizeof (AUXENT); + } + break; + } + + bfd_h_put_32(abfd, in->x_sym.x_tagndx.l, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + bfd_h_put_16(abfd, in->x_sym.x_tvndx , (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (class == C_BLOCK || ISFCN (type) || ISTAG (class)) + { + PUT_FCN_LNNOPTR(abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext); + PUT_FCN_ENDNDX(abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext); + } + else + { +#if DIMNUM != E_DIMNUM + #error we need to cope with truncating or extending DIMNUM +#endif + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + bfd_h_put_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], + (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]); + } + + if (ISFCN (type)) + bfd_h_put_32 (abfd, in->x_sym.x_misc.x_fsize, + (bfd_byte *) ext->x_sym.x_misc.x_fsize); + else + { + PUT_LNSZ_LNNO (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext); + PUT_LNSZ_SIZE (abfd, in->x_sym.x_misc.x_lnsz.x_size, ext); + } + + return sizeof(AUXENT); +} + + +static void +coff_swap_lineno_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + LINENO *ext = (LINENO *)ext1; + struct internal_lineno *in = (struct internal_lineno *)in1; + + in->l_addr.l_symndx = bfd_h_get_32(abfd, (bfd_byte *) ext->l_addr.l_symndx); + in->l_lnno = GET_LINENO_LNNO(abfd, ext); +} + +static unsigned int +coff_swap_lineno_out (abfd, inp, outp) + bfd *abfd; + PTR inp; + PTR outp; +{ + struct internal_lineno *in = (struct internal_lineno *)inp; + struct external_lineno *ext = (struct external_lineno *)outp; + bfd_h_put_32(abfd, in->l_addr.l_symndx, (bfd_byte *) + ext->l_addr.l_symndx); + + PUT_LINENO_LNNO (abfd, in->l_lnno, ext); + return sizeof(struct external_lineno); +} + + + +static void +coff_swap_aouthdr_in (abfd, aouthdr_ext1, aouthdr_int1) + bfd *abfd; + PTR aouthdr_ext1; + PTR aouthdr_int1; +{ + struct internal_extra_pe_aouthdr *a; + PEAOUTHDR *src = (PEAOUTHDR *)(aouthdr_ext1); + AOUTHDR *aouthdr_ext = (AOUTHDR *) aouthdr_ext1; + struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1; + + aouthdr_int->magic = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->magic); + aouthdr_int->vstamp = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->vstamp); + aouthdr_int->tsize = + GET_AOUTHDR_TSIZE (abfd, (bfd_byte *) aouthdr_ext->tsize); + aouthdr_int->dsize = + GET_AOUTHDR_DSIZE (abfd, (bfd_byte *) aouthdr_ext->dsize); + aouthdr_int->bsize = + GET_AOUTHDR_BSIZE (abfd, (bfd_byte *) aouthdr_ext->bsize); + aouthdr_int->entry = + GET_AOUTHDR_ENTRY (abfd, (bfd_byte *) aouthdr_ext->entry); + aouthdr_int->text_start = + GET_AOUTHDR_TEXT_START (abfd, (bfd_byte *) aouthdr_ext->text_start); + aouthdr_int->data_start = + GET_AOUTHDR_DATA_START (abfd, (bfd_byte *) aouthdr_ext->data_start); + + a = &aouthdr_int->pe; + a->ImageBase = bfd_h_get_32 (abfd, src->ImageBase); + a->SectionAlignment = bfd_h_get_32 (abfd, src->SectionAlignment); + a->FileAlignment = bfd_h_get_32 (abfd, src->FileAlignment); + a->MajorOperatingSystemVersion = + bfd_h_get_16 (abfd, src->MajorOperatingSystemVersion); + a->MinorOperatingSystemVersion = + bfd_h_get_16 (abfd, src->MinorOperatingSystemVersion); + a->MajorImageVersion = bfd_h_get_16 (abfd, src->MajorImageVersion); + a->MinorImageVersion = bfd_h_get_16 (abfd, src->MinorImageVersion); + a->MajorSubsystemVersion = bfd_h_get_16 (abfd, src->MajorSubsystemVersion); + a->MinorSubsystemVersion = bfd_h_get_16 (abfd, src->MinorSubsystemVersion); + a->Reserved1 = bfd_h_get_32 (abfd, src->Reserved1); + a->SizeOfImage = bfd_h_get_32 (abfd, src->SizeOfImage); + a->SizeOfHeaders = bfd_h_get_32 (abfd, src->SizeOfHeaders); + a->CheckSum = bfd_h_get_32 (abfd, src->CheckSum); + a->Subsystem = bfd_h_get_16 (abfd, src->Subsystem); + a->DllCharacteristics = bfd_h_get_16 (abfd, src->DllCharacteristics); + a->SizeOfStackReserve = bfd_h_get_32 (abfd, src->SizeOfStackReserve); + a->SizeOfStackCommit = bfd_h_get_32 (abfd, src->SizeOfStackCommit); + a->SizeOfHeapReserve = bfd_h_get_32 (abfd, src->SizeOfHeapReserve); + a->SizeOfHeapCommit = bfd_h_get_32 (abfd, src->SizeOfHeapCommit); + a->LoaderFlags = bfd_h_get_32 (abfd, src->LoaderFlags); + a->NumberOfRvaAndSizes = bfd_h_get_32 (abfd, src->NumberOfRvaAndSizes); + + { + int idx; + for (idx=0; idx < 16; idx++) + { + a->DataDirectory[idx].VirtualAddress = + bfd_h_get_32 (abfd, src->DataDirectory[idx][0]); + a->DataDirectory[idx].Size = + bfd_h_get_32 (abfd, src->DataDirectory[idx][1]); + } + } + + if (aouthdr_int->entry) + aouthdr_int->entry += a->ImageBase; + if (aouthdr_int->tsize) + aouthdr_int->text_start += a->ImageBase; + if (aouthdr_int->dsize) + aouthdr_int->data_start += a->ImageBase; +} + + +static void add_data_entry (abfd, aout, idx, name, base) + bfd *abfd; + struct internal_extra_pe_aouthdr *aout; + int idx; + char *name; + bfd_vma base; +{ + asection *sec = bfd_get_section_by_name (abfd, name); + + /* add import directory information if it exists */ + if (sec != NULL) + { + aout->DataDirectory[idx].VirtualAddress = sec->vma - base; + aout->DataDirectory[idx].Size = sec->_cooked_size; + sec->flags |= SEC_DATA; + } +} + +static unsigned int +coff_swap_aouthdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *)in; + struct internal_extra_pe_aouthdr *extra = &pe_data (abfd)->pe_opthdr; + PEAOUTHDR *aouthdr_out = (PEAOUTHDR *)out; + + bfd_vma sa = extra->SectionAlignment; + bfd_vma fa = extra->FileAlignment; + bfd_vma ib = extra->ImageBase ; + + if (aouthdr_in->tsize) + aouthdr_in->text_start -= ib; + if (aouthdr_in->dsize) + aouthdr_in->data_start -= ib; + if (aouthdr_in->entry) + aouthdr_in->entry -= ib; + +#define FA(x) (((x) + fa -1 ) & (- fa)) +#define SA(x) (((x) + sa -1 ) & (- sa)) + + /* We like to have the sizes aligned */ + + aouthdr_in->bsize = FA (aouthdr_in->bsize); + + + extra->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + + /* first null out all data directory entries .. */ + memset (extra->DataDirectory, sizeof (extra->DataDirectory), 0); + + add_data_entry (abfd, extra, 0, ".edata", ib); + add_data_entry (abfd, extra, 1, ".idata", ib); + add_data_entry (abfd, extra, 2, ".rsrc" ,ib); + +#ifdef POWERPC_LE_PE + /* FIXME: do other PE platforms use this? */ + add_data_entry (abfd, extra, 3, ".pdata" ,ib); +#endif + + add_data_entry (abfd, extra, 5, ".reloc", ib); + +#ifdef POWERPC_LE_PE + /* On the PPC NT system, this field is set up as follows. It is + not an "officially" reserved field, so it currently has no title. + first_thunk_address is idata$5, and the thunk_size is the size + of the idata$5 chunk of the idata section. + */ + extra->DataDirectory[12].VirtualAddress = first_thunk_address; + extra->DataDirectory[12].Size = thunk_size; + + /* On the PPC NT system, the size of the directory entry is not the + size of the entire section. It's actually offset to the end of + the idata$3 component of the idata section. This is the size of + the entire import table. (also known as the start of idata$4) + */ + extra->DataDirectory[1].Size = import_table_size; +#endif + + { + asection *sec; + bfd_vma dsize= 0; + bfd_vma isize = SA(abfd->sections->filepos); + bfd_vma tsize= 0; + + for (sec = abfd->sections; sec; sec = sec->next) + { + int rounded = FA(sec->_raw_size); + + if (strcmp(sec->name,".junk") == 0) + { + continue; + } + + if (sec->flags & SEC_DATA) + dsize += rounded; + if (sec->flags & SEC_CODE) + tsize += rounded; + isize += SA(rounded); + } + + aouthdr_in->dsize = dsize; + aouthdr_in->tsize = tsize; + extra->SizeOfImage = isize; + } + + extra->SizeOfHeaders = abfd->sections->filepos; + bfd_h_put_16(abfd, aouthdr_in->magic, (bfd_byte *) aouthdr_out->standard.magic); + +#ifdef POWERPC_LE_PE + /* this little piece of magic sets the "linker version" field to 2.60 */ + bfd_h_put_16(abfd, 2 + 60 * 256, (bfd_byte *) aouthdr_out->standard.vstamp); +#else + /* this little piece of magic sets the "linker version" field to 2.55 */ + bfd_h_put_16(abfd, 2 + 55 * 256, (bfd_byte *) aouthdr_out->standard.vstamp); +#endif + + PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, (bfd_byte *) aouthdr_out->standard.tsize); + PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, (bfd_byte *) aouthdr_out->standard.dsize); + PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, (bfd_byte *) aouthdr_out->standard.bsize); + PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, (bfd_byte *) aouthdr_out->standard.entry); + PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, + (bfd_byte *) aouthdr_out->standard.text_start); + + PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, + (bfd_byte *) aouthdr_out->standard.data_start); + + + bfd_h_put_32 (abfd, extra->ImageBase, + (bfd_byte *) aouthdr_out->ImageBase); + bfd_h_put_32 (abfd, extra->SectionAlignment, + (bfd_byte *) aouthdr_out->SectionAlignment); + bfd_h_put_32 (abfd, extra->FileAlignment, + (bfd_byte *) aouthdr_out->FileAlignment); + bfd_h_put_16 (abfd, extra->MajorOperatingSystemVersion, + (bfd_byte *) aouthdr_out->MajorOperatingSystemVersion); + bfd_h_put_16 (abfd, extra->MinorOperatingSystemVersion, + (bfd_byte *) aouthdr_out->MinorOperatingSystemVersion); + bfd_h_put_16 (abfd, extra->MajorImageVersion, + (bfd_byte *) aouthdr_out->MajorImageVersion); + bfd_h_put_16 (abfd, extra->MinorImageVersion, + (bfd_byte *) aouthdr_out->MinorImageVersion); + bfd_h_put_16 (abfd, extra->MajorSubsystemVersion, + (bfd_byte *) aouthdr_out->MajorSubsystemVersion); + bfd_h_put_16 (abfd, extra->MinorSubsystemVersion, + (bfd_byte *) aouthdr_out->MinorSubsystemVersion); + bfd_h_put_32 (abfd, extra->Reserved1, + (bfd_byte *) aouthdr_out->Reserved1); + bfd_h_put_32 (abfd, extra->SizeOfImage, + (bfd_byte *) aouthdr_out->SizeOfImage); + bfd_h_put_32 (abfd, extra->SizeOfHeaders, + (bfd_byte *) aouthdr_out->SizeOfHeaders); + bfd_h_put_32 (abfd, extra->CheckSum, + (bfd_byte *) aouthdr_out->CheckSum); + bfd_h_put_16 (abfd, extra->Subsystem, + (bfd_byte *) aouthdr_out->Subsystem); + bfd_h_put_16 (abfd, extra->DllCharacteristics, + (bfd_byte *) aouthdr_out->DllCharacteristics); + bfd_h_put_32 (abfd, extra->SizeOfStackReserve, + (bfd_byte *) aouthdr_out->SizeOfStackReserve); + bfd_h_put_32 (abfd, extra->SizeOfStackCommit, + (bfd_byte *) aouthdr_out->SizeOfStackCommit); + bfd_h_put_32 (abfd, extra->SizeOfHeapReserve, + (bfd_byte *) aouthdr_out->SizeOfHeapReserve); + bfd_h_put_32 (abfd, extra->SizeOfHeapCommit, + (bfd_byte *) aouthdr_out->SizeOfHeapCommit); + bfd_h_put_32 (abfd, extra->LoaderFlags, + (bfd_byte *) aouthdr_out->LoaderFlags); + bfd_h_put_32 (abfd, extra->NumberOfRvaAndSizes, + (bfd_byte *) aouthdr_out->NumberOfRvaAndSizes); + { + int idx; + for (idx=0; idx < 16; idx++) + { + bfd_h_put_32 (abfd, extra->DataDirectory[idx].VirtualAddress, + (bfd_byte *) aouthdr_out->DataDirectory[idx][0]); + bfd_h_put_32 (abfd, extra->DataDirectory[idx].Size, + (bfd_byte *) aouthdr_out->DataDirectory[idx][1]); + } + } + + return sizeof(AOUTHDR); +} + +static void + coff_swap_scnhdr_in (abfd, ext, in) + bfd *abfd; + PTR ext; + PTR in; +{ + SCNHDR *scnhdr_ext = (SCNHDR *) ext; + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + memcpy(scnhdr_int->s_name, scnhdr_ext->s_name, sizeof(scnhdr_int->s_name)); + scnhdr_int->s_vaddr = + GET_SCNHDR_VADDR (abfd, (bfd_byte *) scnhdr_ext->s_vaddr); + scnhdr_int->s_paddr = + GET_SCNHDR_PADDR (abfd, (bfd_byte *) scnhdr_ext->s_paddr); + scnhdr_int->s_size = + GET_SCNHDR_SIZE (abfd, (bfd_byte *) scnhdr_ext->s_size); + scnhdr_int->s_scnptr = + GET_SCNHDR_SCNPTR (abfd, (bfd_byte *) scnhdr_ext->s_scnptr); + scnhdr_int->s_relptr = + GET_SCNHDR_RELPTR (abfd, (bfd_byte *) scnhdr_ext->s_relptr); + scnhdr_int->s_lnnoptr = + GET_SCNHDR_LNNOPTR (abfd, (bfd_byte *) scnhdr_ext->s_lnnoptr); + scnhdr_int->s_flags = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_flags); + + scnhdr_int->s_nreloc = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nlnno); + + if (scnhdr_int->s_vaddr != 0) + { + scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase; + } + if (strcmp (scnhdr_int->s_name, _BSS) == 0) + { + scnhdr_int->s_size = scnhdr_int->s_paddr; + scnhdr_int->s_paddr = 0; + } +} + +static unsigned int +coff_swap_scnhdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *)in; + SCNHDR *scnhdr_ext = (SCNHDR *)out; + unsigned int ret = sizeof (SCNHDR); + bfd_vma ps; + bfd_vma ss; + + memcpy(scnhdr_ext->s_name, scnhdr_int->s_name, sizeof(scnhdr_int->s_name)); + + PUT_SCNHDR_VADDR (abfd, + (scnhdr_int->s_vaddr + - pe_data(abfd)->pe_opthdr.ImageBase), + (bfd_byte *) scnhdr_ext->s_vaddr); + + /* NT wants the size data to be rounded up to the next NT_FILE_ALIGNMENT + value except for the BSS section, its s_size should be 0 */ + + + if (strcmp (scnhdr_int->s_name, _BSS) == 0) + { + ps = scnhdr_int->s_size; + ss = 0; + } + else + { + ps = scnhdr_int->s_paddr; + ss = scnhdr_int->s_size; + } + + PUT_SCNHDR_SIZE (abfd, ss, + (bfd_byte *) scnhdr_ext->s_size); + + + PUT_SCNHDR_PADDR (abfd, ps, (bfd_byte *) scnhdr_ext->s_paddr); + + PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, + (bfd_byte *) scnhdr_ext->s_scnptr); + PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, + (bfd_byte *) scnhdr_ext->s_relptr); + PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, + (bfd_byte *) scnhdr_ext->s_lnnoptr); + + /* Extra flags must be set when dealing with NT. All sections should also + have the IMAGE_SCN_MEM_READ (0x40000000) flag set. In addition, the + .text section must have IMAGE_SCN_MEM_EXECUTE (0x20000000) and the data + sections (.idata, .data, .bss, .CRT) must have IMAGE_SCN_MEM_WRITE set + (this is especially important when dealing with the .idata section since + the addresses for routines from .dlls must be overwritten). If .reloc + section data is ever generated, we must add IMAGE_SCN_MEM_DISCARDABLE + (0x02000000). Also, the resource data should also be read and + writable. */ + + /* FIXME: alignment is also encoded in this field, at least on ppc (krk) */ + /* FIXME: even worse, I don't see how to get the original alignment field*/ + /* back... */ + + { + int flags = scnhdr_int->s_flags; + if (strcmp (scnhdr_int->s_name, ".data") == 0 || + strcmp (scnhdr_int->s_name, ".CRT") == 0 || + strcmp (scnhdr_int->s_name, ".rsrc") == 0 || + strcmp (scnhdr_int->s_name, ".bss") == 0) + flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + else if (strcmp (scnhdr_int->s_name, ".text") == 0) + flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; + else if (strcmp (scnhdr_int->s_name, ".reloc") == 0) + flags = SEC_DATA| IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE; + else if (strcmp (scnhdr_int->s_name, ".idata") == 0) + flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | SEC_DATA; + else if (strcmp (scnhdr_int->s_name, ".rdata") == 0 + || strcmp (scnhdr_int->s_name, ".edata") == 0) + flags = IMAGE_SCN_MEM_READ | SEC_DATA; + /* ppc-nt additions */ + else if (strcmp (scnhdr_int->s_name, ".pdata") == 0) + flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | + IMAGE_SCN_MEM_READ ; + /* Remember this field is a max of 8 chars, so the null is _not_ there + for an 8 character name like ".reldata". (yep. Stupid bug) */ + else if (strncmp (scnhdr_int->s_name, ".reldata", strlen(".reldata")) == 0) + flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_8BYTES | + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE ; + else if (strcmp (scnhdr_int->s_name, ".ydata") == 0) + flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_8BYTES | + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE ; + else if (strcmp (scnhdr_int->s_name, ".drectve") == 0) + flags = IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE ; + /* end of ppc-nt additions */ +#ifdef POWERPC_LE_PE + else if (strncmp (scnhdr_int->s_name, ".stabstr", strlen(".stabstr")) == 0) + { + flags = IMAGE_SCN_LNK_INFO; + } + else if (strcmp (scnhdr_int->s_name, ".stab") == 0) + { + flags = IMAGE_SCN_LNK_INFO; + } +#endif + + bfd_h_put_32(abfd, flags, (bfd_byte *) scnhdr_ext->s_flags); + } + + if (scnhdr_int->s_nlnno <= 0xffff) + bfd_h_put_16(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno); + else + { + (*_bfd_error_handler) ("%s: line number overflow: 0x%lx > 0xffff", + bfd_get_filename (abfd), + scnhdr_int->s_nlnno); + bfd_set_error (bfd_error_file_truncated); + bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nlnno); + ret = 0; + } + if (scnhdr_int->s_nreloc <= 0xffff) + bfd_h_put_16(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc); + else + { + (*_bfd_error_handler) ("%s: reloc overflow: 0x%lx > 0xffff", + bfd_get_filename (abfd), + scnhdr_int->s_nreloc); + bfd_set_error (bfd_error_file_truncated); + bfd_h_put_16 (abfd, 0xffff, (bfd_byte *) scnhdr_ext->s_nreloc); + ret = 0; + } + return ret; +} + +static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = +{ + "Export Directory [.edata]", + "Import Directory [parts of .idata]", + "Resource Directory [.rsrc]", + "Exception Directory [.pdata]", + "Security Directory", + "Base Relocation Directory [.reloc]", + "Debug Directory", + "Description Directory", + "Special Directory", + "Thread Storage Directory [.tls]", + "Load Configuration Directory", + "Bound Import Directory", + "Import Address Table Directory", + "Reserved", + "Reserved", + "Reserved" +}; + +/**********************************************************************/ +static boolean +pe_print_idata(abfd, vfile) + bfd*abfd; + void *vfile; +{ + FILE *file = vfile; + bfd_byte *data = 0; + asection *section = bfd_get_section_by_name (abfd, ".idata"); + +#ifdef POWERPC_LE_PE + asection *rel_section = bfd_get_section_by_name (abfd, ".reldata"); +#endif + + bfd_size_type datasize = 0; + bfd_size_type i; + bfd_size_type start, stop; + int onaline = 20; + bfd_vma addr_value; + bfd_vma loadable_toc_address; + bfd_vma toc_address; + bfd_vma start_address; + + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + + if (section == 0) + return true; + +#ifdef POWERPC_LE_PE + if (rel_section != 0 && bfd_section_size (abfd, rel_section) != 0) + { + /* The toc address can be found by taking the starting address, + which on the PPC locates a function descriptor. The descriptor + consists of the function code starting address followed by the + address of the toc. The starting address we get from the bfd, + and the descriptor is supposed to be in the .reldata section. + */ + + bfd_byte *data = 0; + int offset; + data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, + rel_section)); + if (data == NULL && bfd_section_size (abfd, rel_section) != 0) + return false; + + datasize = bfd_section_size (abfd, rel_section); + + bfd_get_section_contents (abfd, + rel_section, + (PTR) data, 0, + bfd_section_size (abfd, rel_section)); + + offset = abfd->start_address - rel_section->vma; + + start_address = bfd_get_32(abfd, data+offset); + loadable_toc_address = bfd_get_32(abfd, data+offset+4); + toc_address = loadable_toc_address - 32768; + + fprintf(file, + "\nFunction descriptor located at the start address: %04lx\n", + (unsigned long int) (abfd->start_address)); + fprintf (file, + "\tcode-base %08lx toc (loadable/actual) %08lx/%08lx\n", + start_address, loadable_toc_address, toc_address); + } + else + { + loadable_toc_address = 0; + toc_address = 0; + start_address = 0; + } +#endif + + fprintf(file, + "\nThe Import Tables (interpreted .idata section contents)\n"); + fprintf(file, + " vma: Hint Time Forward DLL First\n"); + fprintf(file, + " Table Stamp Chain Name Thunk\n"); + + if (bfd_section_size (abfd, section) == 0) + return true; + + data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, section)); + datasize = bfd_section_size (abfd, section); + if (data == NULL && datasize != 0) + return false; + + bfd_get_section_contents (abfd, + section, + (PTR) data, 0, + bfd_section_size (abfd, section)); + + start = 0; + + stop = bfd_section_size (abfd, section); + + for (i = start; i < stop; i += onaline) + { + bfd_vma hint_addr; + bfd_vma time_stamp; + bfd_vma forward_chain; + bfd_vma dll_name; + bfd_vma first_thunk; + int idx; + int j; + char *dll; + int adj = extra->ImageBase - section->vma; + + fprintf (file, + " %04lx\t", + (unsigned long int) (i + section->vma)); + + if (i+20 > stop) + { + /* check stuff */ + ; + } + + hint_addr = bfd_get_32(abfd, data+i); + time_stamp = bfd_get_32(abfd, data+i+4); + forward_chain = bfd_get_32(abfd, data+i+8); + dll_name = bfd_get_32(abfd, data+i+12); + first_thunk = bfd_get_32(abfd, data+i+16); + + fprintf(file, "%08lx %08lx %08lx %08lx %08lx\n", + hint_addr, + time_stamp, + forward_chain, + dll_name, + first_thunk); + + if (hint_addr ==0) + { + break; + } + + /* the image base is present in the section->vma */ + dll = data + dll_name + adj; + fprintf(file, "\n\tDLL Name: %s\n", dll); + fprintf(file, "\tvma: Ordinal Member-Name\n"); + + idx = hint_addr + adj; + + for (j=0;j>> Ran out of IAT members!\n"); + } + else + { + ordinal = bfd_get_16(abfd, + data + iat_member + adj); + member_name = data + iat_member + adj + 2; + fprintf(file, "\t%04lx\t %4d %s\n", + iat_member, ordinal, member_name); + } + break; + } + if (hint_member == 0) + break; + } + if (differ == 0) + { + fprintf(file, + "\tThe Import Address Table is identical\n"); + } + } + + fprintf(file, "\n"); + + } + + free (data); +} + +static boolean +pe_print_edata(abfd, vfile) + bfd*abfd; + void *vfile; +{ + FILE *file = vfile; + bfd_byte *data = 0; + asection *section = bfd_get_section_by_name (abfd, ".edata"); + + bfd_size_type datasize = 0; + bfd_size_type i; + + int adj; + struct EDT_type + { + long export_flags; /* reserved - should be zero */ + long time_stamp; + short major_ver; + short minor_ver; + bfd_vma name; /* rva - relative to image base */ + long base; /* ordinal base */ + long num_functions; /* Number in the export address table */ + long num_names; /* Number in the name pointer table */ + bfd_vma eat_addr; /* rva to the export address table */ + bfd_vma npt_addr; /* rva to the Export Name Pointer Table */ + bfd_vma ot_addr; /* rva to the Ordinal Table */ + } edt; + + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + + if (section == 0) + return true; + + data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, + section)); + datasize = bfd_section_size (abfd, section); + + if (data == NULL && datasize != 0) + return false; + + bfd_get_section_contents (abfd, + section, + (PTR) data, 0, + bfd_section_size (abfd, section)); + + /* Go get Export Directory Table */ + edt.export_flags = bfd_get_32(abfd, data+0); + edt.time_stamp = bfd_get_32(abfd, data+4); + edt.major_ver = bfd_get_16(abfd, data+8); + edt.minor_ver = bfd_get_16(abfd, data+10); + edt.name = bfd_get_32(abfd, data+12); + edt.base = bfd_get_32(abfd, data+16); + edt.num_functions = bfd_get_32(abfd, data+20); + edt.num_names = bfd_get_32(abfd, data+24); + edt.eat_addr = bfd_get_32(abfd, data+28); + edt.npt_addr = bfd_get_32(abfd, data+32); + edt.ot_addr = bfd_get_32(abfd, data+36); + + adj = extra->ImageBase - section->vma; + + + /* Dump the EDT first first */ + fprintf(file, + "\nThe Export Tables (interpreted .edata section contents)\n\n"); + + fprintf(file, + "Export Flags \t\t\t%x\n",edt.export_flags); + + fprintf(file, + "Time/Date stamp \t\t%x\n",edt.time_stamp); + + fprintf(file, + "Major/Minor \t\t\t%d/%d\n", edt.major_ver, edt.minor_ver); + + fprintf(file, + "Name \t\t\t\t%x %s\n", edt.name, data + edt.name + adj); + + fprintf(file, + "Ordinal Base \t\t\t%d\n", edt.base); + + fprintf(file, + "Number in:\n"); + + fprintf(file, + "\tExport Address Table \t\t%x\n", edt.num_functions); + + fprintf(file, + "\t[Name Pointer/Ordinal] Table\t%d\n", edt.num_names); + + fprintf(file, + "Table Addresses\n"); + + fprintf(file, + "\tExport Address Table \t\t%x\n", + edt.eat_addr); + + fprintf(file, + "\tName Pointer Table \t\t%x\n", + edt.npt_addr); + + fprintf(file, + "\tOrdinal Table \t\t\t%x\n", + edt.ot_addr); + + + /* The next table to find si the Export Address Table. It's basically + a list of pointers that either locate a function in this dll, or + forward the call to another dll. Something like: + typedef union + { + long export_rva; + long forwarder_rva; + } export_address_table_entry; + */ + + fprintf(file, + "\nExport Address Table -- Ordinal Base %d\n", + edt.base); + + for (i = 0; i < edt.num_functions; ++i) + { + bfd_vma eat_member = bfd_get_32(abfd, + data + edt.eat_addr + (i*4) + adj); + bfd_vma eat_actual = extra->ImageBase + eat_member; + bfd_vma edata_start = bfd_get_section_vma(abfd,section); + bfd_vma edata_end = edata_start + bfd_section_size (abfd, section); + + + if (eat_member == 0) + continue; + + if (edata_start < eat_actual && eat_actual < edata_end) + { + /* this rva is to a name (forwarding function) in our section */ + /* Should locate a function descriptor */ + fprintf(file, + "\t[%4d] +base[%4d] %04lx %s -- %s\n", + i, i+edt.base, eat_member, "Forwarder RVA", + data + eat_member + adj); + } + else + { + /* Should locate a function descriptor in the reldata section */ + fprintf(file, + "\t[%4d] +base[%4d] %04lx %s\n", + i, i+edt.base, eat_member, "Export RVA"); + } + } + + /* The Export Name Pointer Table is paired with the Export Ordinal Table */ + /* Dump them in parallel for clarity */ + fprintf(file, + "\n[Ordinal/Name Pointer] Table\n"); + + for (i = 0; i < edt.num_names; ++i) + { + bfd_vma name_ptr = bfd_get_32(abfd, + data + + edt.npt_addr + + (i*4) + adj); + + char *name = data + name_ptr + adj; + + bfd_vma ord = bfd_get_16(abfd, + data + + edt.ot_addr + + (i*2) + adj); + fprintf(file, + "\t[%4d] %s\n", ord, name); + + } + + free (data); +} + +static boolean +pe_print_pdata(abfd, vfile) + bfd*abfd; + void *vfile; +{ + FILE *file = vfile; + bfd_byte *data = 0; + asection *section = bfd_get_section_by_name (abfd, ".pdata"); + bfd_size_type datasize = 0; + bfd_size_type i; + bfd_size_type start, stop; + int onaline = 20; + bfd_vma addr_value; + + if (section == 0) + return true; + + fprintf(file, + "\nThe Function Table (interpreted .pdata section contents)\n"); + fprintf(file, + " vma:\t\tBegin End EH EH PrologEnd\n"); + fprintf(file, + " \t\tAddress Address Handler Data Address\n"); + + if (bfd_section_size (abfd, section) == 0) + return true; + + data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, section)); + datasize = bfd_section_size (abfd, section); + if (data == NULL && datasize != 0) + return false; + + bfd_get_section_contents (abfd, + section, + (PTR) data, 0, + bfd_section_size (abfd, section)); + + start = 0; + + stop = bfd_section_size (abfd, section); + + for (i = start; i < stop; i += onaline) + { + bfd_vma begin_addr; + bfd_vma end_addr; + bfd_vma eh_handler; + bfd_vma eh_data; + bfd_vma prolog_end_addr; + + if (i+20 > stop) + break; + + begin_addr = bfd_get_32(abfd, data+i); + end_addr = bfd_get_32(abfd, data+i+4); + eh_handler = bfd_get_32(abfd, data+i+8); + eh_data = bfd_get_32(abfd, data+i+12); + prolog_end_addr = bfd_get_32(abfd, data+i+16); + + if (begin_addr == 0 && end_addr == 0 && eh_handler == 0 + && eh_data == 0 && prolog_end_addr == 0) + { + /* We are probably into the padding of the + section now */ + break; + } + + fprintf (file, + " %08lx\t", + (unsigned long int) (i + section->vma)); + + fprintf(file, "%08lx %08lx %08lx %08lx %08lx", + begin_addr, + end_addr, + eh_handler, + eh_data, + prolog_end_addr); + +#ifdef POWERPC_LE_PE + if (eh_handler == 0 && eh_data != 0) + { + /* Special bits here, although the meaning may */ + /* be a little mysterious. The only one I know */ + /* for sure is 0x03. */ + /* Code Significance */ + /* 0x00 None */ + /* 0x01 Register Save Millicode */ + /* 0x02 Register Restore Millicode */ + /* 0x03 Glue Code Sequence */ + switch (eh_data) + { + case 0x01: + fprintf(file, " Register save millicode"); + break; + case 0x02: + fprintf(file, " Register restore millicode"); + break; + case 0x03: + fprintf(file, " Glue code sequence"); + break; + default: + break; + } + } +#endif + fprintf(file, "\n"); + } + + free (data); +} + +static const char *tbl[6] = +{ +"ABSOLUTE", +"HIGH", +"LOW", +"HIGHLOW", +"HIGHADJ", +"unknown" +}; + +static boolean +pe_print_reloc(abfd, vfile) + bfd*abfd; + void *vfile; +{ + FILE *file = vfile; + bfd_byte *data = 0; + asection *section = bfd_get_section_by_name (abfd, ".reloc"); + bfd_size_type datasize = 0; + bfd_size_type i; + bfd_size_type start, stop; + int onaline = 20; + bfd_vma addr_value; + + if (section == 0) + return true; + + if (bfd_section_size (abfd, section) == 0) + return true; + + fprintf(file, + "\n\nPE File Base Relocations (interpreted .reloc" + " section contents)\n"); + + data = (bfd_byte *) bfd_malloc ((size_t) bfd_section_size (abfd, section)); + datasize = bfd_section_size (abfd, section); + if (data == NULL && datasize != 0) + return false; + + bfd_get_section_contents (abfd, + section, + (PTR) data, 0, + bfd_section_size (abfd, section)); + + start = 0; + + stop = bfd_section_size (abfd, section); + + for (i = start; i < stop;) + { + int j; + bfd_vma virtual_address; + long number, size; + + /* The .reloc section is a sequence of blocks, with a header consisting + of two 32 bit quantities, followed by a number of 16 bit entries */ + + virtual_address = bfd_get_32(abfd, data+i); + size = bfd_get_32(abfd, data+i+4); + number = (size - 8) / 2; + + if (size == 0) + { + break; + } + + fprintf (file, + "\nVirtual Address: %08lx Chunk size %d (0x%x) " + "Number of fixups %d\n", + virtual_address, size, size, number); + + for (j = 0; j < number; ++j) + { + unsigned short e = bfd_get_16(abfd, data + i + 8 + j*2); + int t = (e & 0xF000) >> 12; + int off = e & 0x0FFF; + + if (t > 5) + abort(); + + fprintf(file, + "\treloc %4d offset %4x [%4x] %s\n", + j, off, off+virtual_address, tbl[t]); + + } + i += size; + } + + free (data); +} + +static boolean +pe_print_private_bfd_data (abfd, vfile) + bfd *abfd; + PTR vfile; +{ + FILE *file = (FILE *) vfile; + int j; + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr; + + fprintf (file,"\nImageBase\t\t"); + fprintf_vma (file, i->ImageBase); + fprintf (file,"\nSectionAlignment\t"); + fprintf_vma (file, i->SectionAlignment); + fprintf (file,"\nFileAlignment\t\t"); + fprintf_vma (file, i->FileAlignment); + fprintf (file,"\nMajorOSystemVersion\t%d\n", i->MajorOperatingSystemVersion); + fprintf (file,"MinorOSystemVersion\t%d\n", i->MinorOperatingSystemVersion); + fprintf (file,"MajorImageVersion\t%d\n", i->MajorImageVersion); + fprintf (file,"MinorImageVersion\t%d\n", i->MinorImageVersion); + fprintf (file,"MajorSubsystemVersion\t%d\n", i->MajorSubsystemVersion); + fprintf (file,"MinorSubsystemVersion\t%d\n", i->MinorSubsystemVersion); + fprintf (file,"Reserved1\t\t%08lx\n", i->Reserved1); + fprintf (file,"SizeOfImage\t\t%08lx\n", i->SizeOfImage); + fprintf (file,"SizeOfHeaders\t\t%08lx\n", i->SizeOfHeaders); + fprintf (file,"CheckSum\t\t%08lx\n", i->CheckSum); + fprintf (file,"Subsystem\t\t%08x\n", i->Subsystem); + fprintf (file,"DllCharacteristics\t%08x\n", i->DllCharacteristics); + fprintf (file,"SizeOfStackReserve\t"); + fprintf_vma (file, i->SizeOfStackReserve); + fprintf (file,"\nSizeOfStackCommit\t"); + fprintf_vma (file, i->SizeOfStackCommit); + fprintf (file,"\nSizeOfHeapReserve\t"); + fprintf_vma (file, i->SizeOfHeapReserve); + fprintf (file,"\nSizeOfHeapCommit\t"); + fprintf_vma (file, i->SizeOfHeapCommit); + fprintf (file,"\nLoaderFlags\t\t%08lx\n", i->LoaderFlags); + fprintf (file,"NumberOfRvaAndSizes\t%08lx\n", i->NumberOfRvaAndSizes); + + fprintf (file,"\nThe Data Directory\n"); + for (j = 0; j < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; j++) + { + fprintf (file, "Entry %1x ", j); + fprintf_vma (file, i->DataDirectory[j].VirtualAddress); + fprintf (file, " %08lx ", i->DataDirectory[j].Size); + fprintf (file, "%s\n", dir_names[j]); + } + + pe_print_idata(abfd, vfile); + pe_print_edata(abfd, vfile); + pe_print_pdata(abfd, vfile); + pe_print_reloc(abfd, vfile); + + return true; +} + +static boolean +pe_mkobject (abfd) + bfd * abfd; +{ + pe_data_type *pe; + abfd->tdata.pe_obj_data = + (struct pe_tdata *) bfd_zalloc (abfd, sizeof (pe_data_type)); + + if (abfd->tdata.pe_obj_data == 0) + return false; + + pe = pe_data (abfd); + + pe->coff.pe = 1; + pe->in_reloc_p = in_reloc_p; + return true; +} + +/* Create the COFF backend specific information. */ +static PTR +pe_mkobject_hook (abfd, filehdr, aouthdr) + bfd * abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + pe_data_type *pe; + + if (pe_mkobject (abfd) == false) + return NULL; + + pe = pe_data (abfd); + pe->coff.sym_filepos = internal_f->f_symptr; + /* These members communicate important constants about the symbol + table to GDB's symbol-reading code. These `constants' + unfortunately vary among coff implementations... */ + pe->coff.local_n_btmask = N_BTMASK; + pe->coff.local_n_btshft = N_BTSHFT; + pe->coff.local_n_tmask = N_TMASK; + pe->coff.local_n_tshift = N_TSHIFT; + pe->coff.local_symesz = SYMESZ; + pe->coff.local_auxesz = AUXESZ; + pe->coff.local_linesz = LINESZ; + + obj_raw_syment_count (abfd) = + obj_conv_table_size (abfd) = + internal_f->f_nsyms; + + pe->real_flags = internal_f->f_flags; + +#ifdef COFF_IMAGE_WITH_PE + if (aouthdr) + { + pe->pe_opthdr = ((struct internal_aouthdr *)aouthdr)->pe; + } +#endif + + return (PTR) pe; +} + + + +/* Copy any private info we understand from the input bfd + to the output bfd. */ + +#define coff_bfd_copy_private_bfd_data pe_bfd_copy_private_bfd_data + +static boolean +pe_bfd_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd, *obfd; +{ + /* One day we may try to grok other private data. */ + if (ibfd->xvec->flavour != bfd_target_coff_flavour + || obfd->xvec->flavour != bfd_target_coff_flavour) + return true; + + pe_data(obfd)->pe_opthdr = pe_data (ibfd)->pe_opthdr; + + return true; +} diff --git a/contrib/gdb/bfd/ptrace-core.c b/contrib/gdb/bfd/ptrace-core.c new file mode 100644 index 000000000000..e356457e8fbc --- /dev/null +++ b/contrib/gdb/bfd/ptrace-core.c @@ -0,0 +1,233 @@ +/* BFD backend for core files which use the ptrace_user structure + Copyright 1993, 1994 Free Software Foundation, Inc. + The structure of this file is based on trad-core.c written by John Gilmore + of Cygnus Support. + Modified to work with the ptrace_user structure by Kevin A. Buettner. + (Longterm it may be better to merge this file with trad-core.c) + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef PTRACE_CORE + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +struct trad_core_struct + { + asection *data_section; + asection *stack_section; + asection *reg_section; + struct ptrace_user u; + }; + +#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) +#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) +#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) +#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) + +/* forward declarations */ + +const bfd_target *ptrace_unix_core_file_p PARAMS ((bfd *abfd)); +char * ptrace_unix_core_file_failing_command PARAMS ((bfd *abfd)); +int ptrace_unix_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean ptrace_unix_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* ARGSUSED */ +const bfd_target * +ptrace_unix_core_file_p (abfd) + bfd *abfd; + +{ + int val; + struct ptrace_user u; + struct trad_core_struct *rawptr; + + val = bfd_read ((void *)&u, 1, sizeof u, abfd); + if (val != sizeof u || u.pt_magic != _BCS_PTRACE_MAGIC + || u.pt_rev != _BCS_PTRACE_REV) + { + /* Too small to be a core file */ + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + /* Allocate both the upage and the struct core_data at once, so + a single free() will free them both. */ + rawptr = (struct trad_core_struct *) + bfd_zalloc (abfd, sizeof (struct trad_core_struct)); + + if (rawptr == NULL) + return 0; + + abfd->tdata.trad_core_data = rawptr; + + rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ + + /* Create the sections. This is raunchy, but bfd_close wants to free + them separately. */ + + core_stacksec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_stacksec (abfd) == NULL) + return NULL; + core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_datasec (abfd) == NULL) + return NULL; + core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_regsec (abfd) == NULL) + return NULL; + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + + /* FIXME: Need to worry about shared memory, library data, and library + text. I don't think that any of these things are supported on the + system on which I am developing this for though. */ + + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_regsec (abfd)->flags = SEC_HAS_CONTENTS; + + core_datasec (abfd)->_raw_size = u.pt_dsize; + core_stacksec (abfd)->_raw_size = u.pt_ssize; + core_regsec (abfd)->_raw_size = sizeof(u); + + core_datasec (abfd)->vma = u.pt_o_data_start; + core_stacksec (abfd)->vma = USRSTACK - u.pt_ssize; + core_regsec (abfd)->vma = 0 - sizeof(u); /* see trad-core.c */ + + core_datasec (abfd)->filepos = (int) u.pt_dataptr; + core_stacksec (abfd)->filepos = (int) (u.pt_dataptr + u.pt_dsize); + core_regsec (abfd)->filepos = 0; /* Register segment is ptrace_user */ + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + abfd->section_count = 3; + + return abfd->xvec; +} + +char * +ptrace_unix_core_file_failing_command (abfd) + bfd *abfd; +{ + char *com = abfd->tdata.trad_core_data->u.pt_comm; + if (*com) + return com; + else + return 0; +} + +/* ARGSUSED */ +int +ptrace_unix_core_file_failing_signal (abfd) + bfd *abfd; +{ + return abfd->tdata.trad_core_data->u.pt_sigframe.sig_num; +} + +/* ARGSUSED */ +boolean +ptrace_unix_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + /* FIXME: Use pt_timdat field of the ptrace_user structure to match + the date of the executable */ + return true; +} + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target ptrace_core_vec = + { + "trad-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + ptrace_unix_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (ptrace_unix), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; + +#endif /* PTRACE_CORE */ diff --git a/contrib/gdb/bfd/reloc.c b/contrib/gdb/bfd/reloc.c new file mode 100644 index 000000000000..46ed5c2d9228 --- /dev/null +++ b/contrib/gdb/bfd/reloc.c @@ -0,0 +1,2391 @@ +/* BFD support for handling relocation entries. + Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Relocations + + BFD maintains relocations in much the same way it maintains + symbols: they are left alone until required, then read in + en-mass and translated into an internal form. A common + routine <> acts upon the + canonical form to do the fixup. + + Relocations are maintained on a per section basis, + while symbols are maintained on a per BFD basis. + + All that a back end has to do to fit the BFD interface is to create + a <> for each relocation + in a particular section, and fill in the right bits of the structures. + +@menu +@* typedef arelent:: +@* howto manager:: +@end menu + +*/ + +/* DO compile in the reloc_code name table from libbfd.h. */ +#define _BFD_MAKE_TABLE_bfd_reloc_code_real + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +/* +DOCDD +INODE + typedef arelent, howto manager, Relocations, Relocations + +SUBSECTION + typedef arelent + + This is the structure of a relocation entry: + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_status +.{ +. {* No errors detected *} +. bfd_reloc_ok, +. +. {* The relocation was performed, but there was an overflow. *} +. bfd_reloc_overflow, +. +. {* The address to relocate was not within the section supplied. *} +. bfd_reloc_outofrange, +. +. {* Used by special functions *} +. bfd_reloc_continue, +. +. {* Unsupported relocation size requested. *} +. bfd_reloc_notsupported, +. +. {* Unused *} +. bfd_reloc_other, +. +. {* The symbol to relocate against was undefined. *} +. bfd_reloc_undefined, +. +. {* The relocation was performed, but may not be ok - presently +. generated only when linking i960 coff files with i960 b.out +. symbols. If this type is returned, the error_message argument +. to bfd_perform_relocation will be set. *} +. bfd_reloc_dangerous +. } +. bfd_reloc_status_type; +. +. +.typedef struct reloc_cache_entry +.{ +. {* A pointer into the canonical table of pointers *} +. struct symbol_cache_entry **sym_ptr_ptr; +. +. {* offset in section *} +. bfd_size_type address; +. +. {* addend for relocation value *} +. bfd_vma addend; +. +. {* Pointer to how to perform the required relocation *} +. reloc_howto_type *howto; +. +.} arelent; + +*/ + +/* +DESCRIPTION + + Here is a description of each of the fields within an <>: + + o <> + + The symbol table pointer points to a pointer to the symbol + associated with the relocation request. It is + the pointer into the table returned by the back end's + <> action. @xref{Symbols}. The symbol is referenced + through a pointer to a pointer so that tools like the linker + can fix up all the symbols of the same name by modifying only + one pointer. The relocation routine looks in the symbol and + uses the base of the section the symbol is attached to and the + value of the symbol as the initial relocation offset. If the + symbol pointer is zero, then the section provided is looked up. + + o <
> + + The <
> field gives the offset in bytes from the base of + the section data which owns the relocation record to the first + byte of relocatable information. The actual data relocated + will be relative to this point; for example, a relocation + type which modifies the bottom two bytes of a four byte word + would not touch the first byte pointed to in a big endian + world. + + o <> + + The <> is a value provided by the back end to be added (!) + to the relocation offset. Its interpretation is dependent upon + the howto. For example, on the 68k the code: + + +| char foo[]; +| main() +| { +| return foo[0x12345678]; +| } + + Could be compiled into: + +| linkw fp,#-4 +| moveb @@#12345678,d0 +| extbl d0 +| unlk fp +| rts + + + This could create a reloc pointing to <>, but leave the + offset in the data, something like: + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000006 32 _foo +| +|00000000 4e56 fffc ; linkw fp,#-4 +|00000004 1039 1234 5678 ; moveb @@#12345678,d0 +|0000000a 49c0 ; extbl d0 +|0000000c 4e5e ; unlk fp +|0000000e 4e75 ; rts + + + Using coff and an 88k, some instructions don't have enough + space in them to represent the full address range, and + pointers have to be loaded in two parts. So you'd get something like: + + +| or.u r13,r0,hi16(_foo+0x12345678) +| ld.b r2,r13,lo16(_foo+0x12345678) +| jmp r1 + + + This should create two relocs, both pointing to <<_foo>>, and with + 0x12340000 in their addend field. The data would consist of: + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000002 HVRT16 _foo+0x12340000 +|00000006 LVRT16 _foo+0x12340000 +| +|00000000 5da05678 ; or.u r13,r0,0x5678 +|00000004 1c4d5678 ; ld.b r2,r13,0x5678 +|00000008 f400c001 ; jmp r1 + + + The relocation routine digs out the value from the data, adds + it to the addend to get the original offset, and then adds the + value of <<_foo>>. Note that all 32 bits have to be kept around + somewhere, to cope with carry from bit 15 to bit 16. + + One further example is the sparc and the a.out format. The + sparc has a similar problem to the 88k, in that some + instructions don't have room for an entire offset, but on the + sparc the parts are created in odd sized lumps. The designers of + the a.out format chose to not use the data within the section + for storing part of the offset; all the offset is kept within + the reloc. Anything in the data should be ignored. + +| save %sp,-112,%sp +| sethi %hi(_foo+0x12345678),%g2 +| ldsb [%g2+%lo(_foo+0x12345678)],%i0 +| ret +| restore + + Both relocs contain a pointer to <>, and the offsets + contain junk. + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000004 HI22 _foo+0x12345678 +|00000008 LO10 _foo+0x12345678 +| +|00000000 9de3bf90 ; save %sp,-112,%sp +|00000004 05000000 ; sethi %hi(_foo+0),%g2 +|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 +|0000000c 81c7e008 ; ret +|00000010 81e80000 ; restore + + + o <> + + The <> field can be imagined as a + relocation instruction. It is a pointer to a structure which + contains information on what to do with all of the other + information in the reloc record and data section. A back end + would normally have a relocation instruction set and turn + relocations into pointers to the correct structure on input - + but it would be possible to create each howto field on demand. + +*/ + +/* +SUBSUBSECTION + <> + + Indicates what sort of overflow checking should be done when + performing a relocation. + +CODE_FRAGMENT +. +.enum complain_overflow +.{ +. {* Do not complain on overflow. *} +. complain_overflow_dont, +. +. {* Complain if the bitfield overflows, whether it is considered +. as signed or unsigned. *} +. complain_overflow_bitfield, +. +. {* Complain if the value overflows when considered as signed +. number. *} +. complain_overflow_signed, +. +. {* Complain if the value overflows when considered as an +. unsigned number. *} +. complain_overflow_unsigned +.}; + +*/ + +/* +SUBSUBSECTION + <> + + The <> is a structure which contains all the + information that libbfd needs to know to tie up a back end's data. + +CODE_FRAGMENT +.struct symbol_cache_entry; {* Forward declaration *} +. +.struct reloc_howto_struct +.{ +. {* The type field has mainly a documetary use - the back end can +. do what it wants with it, though normally the back end's +. external idea of what a reloc number is stored +. in this field. For example, a PC relative word relocation +. in a coff environment has the type 023 - because that's +. what the outside world calls a R_PCRWORD reloc. *} +. unsigned int type; +. +. {* The value the final relocation is shifted right by. This drops +. unwanted data from the relocation. *} +. unsigned int rightshift; +. +. {* The size of the item to be relocated. This is *not* a +. power-of-two measure. To get the number of bytes operated +. on by a type of relocation, use bfd_get_reloc_size. *} +. int size; +. +. {* The number of bits in the item to be relocated. This is used +. when doing overflow checking. *} +. unsigned int bitsize; +. +. {* Notes that the relocation is relative to the location in the +. data section of the addend. The relocation function will +. subtract from the relocation value the address of the location +. being relocated. *} +. boolean pc_relative; +. +. {* The bit position of the reloc value in the destination. +. The relocated value is left shifted by this amount. *} +. unsigned int bitpos; +. +. {* What type of overflow error should be checked for when +. relocating. *} +. enum complain_overflow complain_on_overflow; +. +. {* If this field is non null, then the supplied function is +. called rather than the normal function. This allows really +. strange relocation methods to be accomodated (e.g., i960 callj +. instructions). *} +. bfd_reloc_status_type (*special_function) +. PARAMS ((bfd *abfd, +. arelent *reloc_entry, +. struct symbol_cache_entry *symbol, +. PTR data, +. asection *input_section, +. bfd *output_bfd, +. char **error_message)); +. +. {* The textual name of the relocation type. *} +. char *name; +. +. {* When performing a partial link, some formats must modify the +. relocations rather than the data - this flag signals this.*} +. boolean partial_inplace; +. +. {* The src_mask selects which parts of the read in data +. are to be used in the relocation sum. E.g., if this was an 8 bit +. bit of data which we read and relocated, this would be +. 0x000000ff. When we have relocs which have an addend, such as +. sun4 extended relocs, the value in the offset part of a +. relocating field is garbage so we never use it. In this case +. the mask would be 0x00000000. *} +. bfd_vma src_mask; +. +. {* The dst_mask selects which parts of the instruction are replaced +. into the instruction. In most cases src_mask == dst_mask, +. except in the above special case, where dst_mask would be +. 0x000000ff, and src_mask would be 0x00000000. *} +. bfd_vma dst_mask; +. +. {* When some formats create PC relative instructions, they leave +. the value of the pc of the place being relocated in the offset +. slot of the instruction, so that a PC relative relocation can +. be made just by adding in an ordinary offset (e.g., sun3 a.out). +. Some formats leave the displacement part of an instruction +. empty (e.g., m88k bcs); this flag signals the fact.*} +. boolean pcrel_offset; +. +.}; + +*/ + +/* +FUNCTION + The HOWTO Macro + +DESCRIPTION + The HOWTO define is horrible and will go away. + + +.#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ +. {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} + +DESCRIPTION + And will be replaced with the totally magic way. But for the + moment, we are compatible, so do it this way. + + +.#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) +. +DESCRIPTION + Helper routine to turn a symbol into a relocation value. + +.#define HOWTO_PREPARE(relocation, symbol) \ +. { \ +. if (symbol != (asymbol *)NULL) { \ +. if (bfd_is_com_section (symbol->section)) { \ +. relocation = 0; \ +. } \ +. else { \ +. relocation = symbol->value; \ +. } \ +. } \ +.} + +*/ + +/* +FUNCTION + bfd_get_reloc_size + +SYNOPSIS + int bfd_get_reloc_size (reloc_howto_type *); + +DESCRIPTION + For a reloc_howto_type that operates on a fixed number of bytes, + this returns the number of bytes operated on. + */ + +int +bfd_get_reloc_size (howto) + reloc_howto_type *howto; +{ + switch (howto->size) + { + case 0: return 1; + case 1: return 2; + case 2: return 4; + case 3: return 0; + case 4: return 8; + case -2: return 4; + default: abort (); + } +} + +/* +TYPEDEF + arelent_chain + +DESCRIPTION + + How relocs are tied together in an <>: + +.typedef struct relent_chain { +. arelent relent; +. struct relent_chain *next; +.} arelent_chain; + +*/ + + + +/* +FUNCTION + bfd_perform_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_perform_relocation + (bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message); + +DESCRIPTION + If @var{output_bfd} is supplied to this function, the + generated image will be relocatable; the relocations are + copied to the output file after they have been changed to + reflect the new state of the world. There are two ways of + reflecting the results of partial linkage in an output file: + by modifying the output data in place, and by modifying the + relocation record. Some native formats (e.g., basic a.out and + basic coff) have no way of specifying an addend in the + relocation type, so the addend has to go in the output data. + This is no big deal since in these formats the output data + slot will always be big enough for the addend. Complex reloc + types with addends were invented to solve just this problem. + The @var{error_message} argument is set to an error message if + this return @code{bfd_reloc_dangerous}. + +*/ + + +bfd_reloc_status_type +bfd_perform_relocation (abfd, reloc_entry, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type addr = reloc_entry->address; + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + asymbol *symbol; + + symbol = *(reloc_entry->sym_ptr_ptr); + if (bfd_is_abs_section (symbol->section) + && output_bfd != (bfd *) NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocateable output, return an error if + the symbol is not defined. An undefined weak symbol is + considered to have a value of zero (SVR4 ABI, p. 4-27). */ + if (bfd_is_und_section (symbol->section) + && (symbol->flags & BSF_WEAK) == 0 + && output_bfd == (bfd *) NULL) + flag = bfd_reloc_undefined; + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + cont = howto->special_function (abfd, reloc_entry, symbol, data, + input_section, output_bfd, + error_message); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (output_bfd && howto->partial_inplace == false) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative == true) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is false. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is true. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is false we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is true + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset == true) + relocation -= reloc_entry->address; + } + + if (output_bfd != (bfd *) NULL) + { + if (howto->partial_inplace == false) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour + && strcmp (abfd->xvec->name, "aixcoff-rs6000") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-little") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-big") != 0) + { +#if 1 + /* For m68k-coff, the addend was being subtracted twice during + relocation with -r. Removing the line below this comment + fixes that problem; see PR 2953. + +However, Ian wrote the following, regarding removing the line below, +which explains why it is still enabled: --djm + +If you put a patch like that into BFD you need to check all the COFF +linkers. I am fairly certain that patch will break coff-i386 (e.g., +SCO); see coff_i386_reloc in coff-i386.c where I worked around the +problem in a different way. There may very well be a reason that the +code works as it does. + +Hmmm. The first obvious point is that bfd_perform_relocation should +not have any tests that depend upon the flavour. It's seem like +entirely the wrong place for such a thing. The second obvious point +is that the current code ignores the reloc addend when producing +relocateable output for COFF. That's peculiar. In fact, I really +have no idea what the point of the line you want to remove is. + +A typical COFF reloc subtracts the old value of the symbol and adds in +the new value to the location in the object file (if it's a pc +relative reloc it adds the difference between the symbol value and the +location). When relocating we need to preserve that property. + +BFD handles this by setting the addend to the negative of the old +value of the symbol. Unfortunately it handles common symbols in a +non-standard way (it doesn't subtract the old value) but that's a +different story (we can't change it without losing backward +compatibility with old object files) (coff-i386 does subtract the old +value, to be compatible with existing coff-i386 targets, like SCO). + +So everything works fine when not producing relocateable output. When +we are producing relocateable output, logically we should do exactly +what we do when not producing relocateable output. Therefore, your +patch is correct. In fact, it should probably always just set +reloc_entry->addend to 0 for all cases, since it is, in fact, going to +add the value into the object file. This won't hurt the COFF code, +which doesn't use the addend; I'm not sure what it will do to other +formats (the thing to check for would be whether any formats both use +the addend and set partial_inplace). + +When I wanted to make coff-i386 produce relocateable output, I ran +into the problem that you are running into: I wanted to remove that +line. Rather than risk it, I made the coff-i386 relocs use a special +function; it's coff_i386_reloc in coff-i386.c. The function +specifically adds the addend field into the object file, knowing that +bfd_perform_relocation is not going to. If you remove that line, then +coff-i386.c will wind up adding the addend field in twice. It's +trivial to fix; it just needs to be done. + +The problem with removing the line is just that it may break some +working code. With BFD it's hard to be sure of anything. The right +way to deal with this is simply to build and test at least all the +supported COFF targets. It should be straightforward if time and disk +space consuming. For each target: + 1) build the linker + 2) generate some executable, and link it using -r (I would + probably use paranoia.o and link against newlib/libc.a, which + for all the supported targets would be available in + /usr/cygnus/progressive/H-host/target/lib/libc.a). + 3) make the change to reloc.c + 4) rebuild the linker + 5) repeat step 2 + 6) if the resulting object files are the same, you have at least + made it no worse + 7) if they are different you have to figure out which version is + right +*/ + relocation -= reloc_entry->addend; +#endif + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + } + else + { + reloc_entry->addend = 0; + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont + && flag == bfd_reloc_ok) + { + bfd_vma check; + + /* Get the value that will be used for the relocation, but + starting at bit position zero. */ + check = relocation >> howto->rightshift; + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~reloc_signed_max; + + /* The above right shift is incorrect for a signed value. + Fix it up by forcing on the upper bits. */ + if (howto->rightshift > 0 + && (bfd_signed_vma) relocation < 0) + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> howto->rightshift)); + if ((bfd_signed_vma) check > reloc_signed_max + || (bfd_signed_vma) check < reloc_signed_min) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((bfd_vma) check > reloc_unsigned_max) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (((bfd_vma) check & ~reloc_bits) != 0 + && ((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + { + /* The above right shift is incorrect for a signed + value. See if turning on the upper bits fixes the + overflow. */ + if (howto->rightshift > 0 + && (bfd_signed_vma) relocation < 0) + { + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> howto->rightshift)); + if (((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + flag = bfd_reloc_overflow; + } + else + flag = bfd_reloc_overflow; + } + } + break; + default: + abort (); + } + } + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + + /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler + (OSF version 1.3, compiler version 3.11). It miscompiles the + following program: + + struct str + { + unsigned int i0; + } s = { 0 }; + + int + main () + { + unsigned long x; + + x = 0x100000000; + x <<= (unsigned long) s.i0; + if (x == 0) + printf ("failed\n"); + else + printf ("succeeded (%lx)\n", x); + } + */ + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= (bfd_vma) howto->bitpos; + + /* Wait for the day when all have the mask in them */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + i i i i i o o o o o from bfd_get + and S S S S S to get the size offset we want + + r r r r r r r r r r to get the final value to place + and D D D D D to chop to right size + ----------------------- + A A A A A + And this: + ... i i i i i o o o o o from bfd_get + and N N N N N get instruction + ----------------------- + ... B B B B B + + And then: + B B B B B + or A A A A A + ----------------------- + R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, (char *) data + addr); + DOIT (x); + bfd_put_8 (abfd, x, (unsigned char *) data + addr); + } + break; + + case 1: + if (relocation) + { + short x = bfd_get_16 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_16 (abfd, x, (unsigned char *) data + addr); + } + break; + case 2: + if (relocation) + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *) data + addr); + } + break; + case -2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + addr); + relocation = -relocation; + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *) data + addr); + } + break; + + case -1: + { + long x = bfd_get_16 (abfd, (bfd_byte *) data + addr); + relocation = -relocation; + DOIT (x); + bfd_put_16 (abfd, x, (bfd_byte *) data + addr); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: +#ifdef BFD64 + if (relocation) + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data + addr); + } +#else + abort (); +#endif + break; + default: + return bfd_reloc_other; + } + + return flag; +} + +/* +FUNCTION + bfd_install_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_install_relocation + (bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message); + +DESCRIPTION + This looks remarkably like <>, except it + does not expect that the section contents have been filled in. + I.e., it's suitable for use when creating, rather than applying + a relocation. + + For now, this function should be considered reserved for the + assembler. + +*/ + + +bfd_reloc_status_type +bfd_install_relocation (abfd, reloc_entry, data_start, data_start_offset, + input_section, error_message) + bfd *abfd; + arelent *reloc_entry; + PTR data_start; + bfd_vma data_start_offset; + asection *input_section; + char **error_message; +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type addr = reloc_entry->address; + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + asymbol *symbol; + bfd_byte *data; + + symbol = *(reloc_entry->sym_ptr_ptr); + if (bfd_is_abs_section (symbol->section)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + /* XXX - The special_function calls haven't been fixed up to deal + with creating new relocations and section contents. */ + cont = howto->special_function (abfd, reloc_entry, symbol, + /* XXX - Non-portable! */ + ((bfd_byte *) data_start + - data_start_offset), + input_section, abfd, error_message); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (howto->partial_inplace == false) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative == true) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is false. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is true. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is false we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is true + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset == true && howto->partial_inplace == true) + relocation -= reloc_entry->address; + } + + if (howto->partial_inplace == false) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour + && strcmp (abfd->xvec->name, "aixcoff-rs6000") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-little") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-big") != 0) + { +#if 1 +/* For m68k-coff, the addend was being subtracted twice during + relocation with -r. Removing the line below this comment + fixes that problem; see PR 2953. + +However, Ian wrote the following, regarding removing the line below, +which explains why it is still enabled: --djm + +If you put a patch like that into BFD you need to check all the COFF +linkers. I am fairly certain that patch will break coff-i386 (e.g., +SCO); see coff_i386_reloc in coff-i386.c where I worked around the +problem in a different way. There may very well be a reason that the +code works as it does. + +Hmmm. The first obvious point is that bfd_install_relocation should +not have any tests that depend upon the flavour. It's seem like +entirely the wrong place for such a thing. The second obvious point +is that the current code ignores the reloc addend when producing +relocateable output for COFF. That's peculiar. In fact, I really +have no idea what the point of the line you want to remove is. + +A typical COFF reloc subtracts the old value of the symbol and adds in +the new value to the location in the object file (if it's a pc +relative reloc it adds the difference between the symbol value and the +location). When relocating we need to preserve that property. + +BFD handles this by setting the addend to the negative of the old +value of the symbol. Unfortunately it handles common symbols in a +non-standard way (it doesn't subtract the old value) but that's a +different story (we can't change it without losing backward +compatibility with old object files) (coff-i386 does subtract the old +value, to be compatible with existing coff-i386 targets, like SCO). + +So everything works fine when not producing relocateable output. When +we are producing relocateable output, logically we should do exactly +what we do when not producing relocateable output. Therefore, your +patch is correct. In fact, it should probably always just set +reloc_entry->addend to 0 for all cases, since it is, in fact, going to +add the value into the object file. This won't hurt the COFF code, +which doesn't use the addend; I'm not sure what it will do to other +formats (the thing to check for would be whether any formats both use +the addend and set partial_inplace). + +When I wanted to make coff-i386 produce relocateable output, I ran +into the problem that you are running into: I wanted to remove that +line. Rather than risk it, I made the coff-i386 relocs use a special +function; it's coff_i386_reloc in coff-i386.c. The function +specifically adds the addend field into the object file, knowing that +bfd_install_relocation is not going to. If you remove that line, then +coff-i386.c will wind up adding the addend field in twice. It's +trivial to fix; it just needs to be done. + +The problem with removing the line is just that it may break some +working code. With BFD it's hard to be sure of anything. The right +way to deal with this is simply to build and test at least all the +supported COFF targets. It should be straightforward if time and disk +space consuming. For each target: + 1) build the linker + 2) generate some executable, and link it using -r (I would + probably use paranoia.o and link against newlib/libc.a, which + for all the supported targets would be available in + /usr/cygnus/progressive/H-host/target/lib/libc.a). + 3) make the change to reloc.c + 4) rebuild the linker + 5) repeat step 2 + 6) if the resulting object files are the same, you have at least + made it no worse + 7) if they are different you have to figure out which version is + right +*/ + relocation -= reloc_entry->addend; +#endif + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + + /* Get the value that will be used for the relocation, but + starting at bit position zero. */ + check = relocation >> howto->rightshift; + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~reloc_signed_max; + + /* The above right shift is incorrect for a signed value. + Fix it up by forcing on the upper bits. */ + if (howto->rightshift > 0 + && (bfd_signed_vma) relocation < 0) + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> howto->rightshift)); + if ((bfd_signed_vma) check > reloc_signed_max + || (bfd_signed_vma) check < reloc_signed_min) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((bfd_vma) check > reloc_unsigned_max) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (((bfd_vma) check & ~reloc_bits) != 0 + && ((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + { + /* The above right shift is incorrect for a signed + value. See if turning on the upper bits fixes the + overflow. */ + if (howto->rightshift > 0 + && (bfd_signed_vma) relocation < 0) + { + check |= ((bfd_vma) - 1 + & ~((bfd_vma) - 1 + >> howto->rightshift)); + if (((bfd_vma) check & ~reloc_bits) != (-1 & ~reloc_bits)) + flag = bfd_reloc_overflow; + } + else + flag = bfd_reloc_overflow; + } + } + break; + default: + abort (); + } + } + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + + /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler + (OSF version 1.3, compiler version 3.11). It miscompiles the + following program: + + struct str + { + unsigned int i0; + } s = { 0 }; + + int + main () + { + unsigned long x; + + x = 0x100000000; + x <<= (unsigned long) s.i0; + if (x == 0) + printf ("failed\n"); + else + printf ("succeeded (%lx)\n", x); + } + */ + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= (bfd_vma) howto->bitpos; + + /* Wait for the day when all have the mask in them */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + i i i i i o o o o o from bfd_get + and S S S S S to get the size offset we want + + r r r r r r r r r r to get the final value to place + and D D D D D to chop to right size + ----------------------- + A A A A A + And this: + ... i i i i i o o o o o from bfd_get + and N N N N N get instruction + ----------------------- + ... B B B B B + + And then: + B B B B B + or A A A A A + ----------------------- + R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + data = (bfd_byte *) data_start + (addr - data_start_offset); + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, (char *) data); + DOIT (x); + bfd_put_8 (abfd, x, (unsigned char *) data); + } + break; + + case 1: + if (relocation) + { + short x = bfd_get_16 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_16 (abfd, x, (unsigned char *) data); + } + break; + case 2: + if (relocation) + { + long x = bfd_get_32 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *) data); + } + break; + case -2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data); + relocation = -relocation; + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *) data); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: + if (relocation) + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data); + } + break; + default: + return bfd_reloc_other; + } + + return flag; +} + +/* This relocation routine is used by some of the backend linkers. + They do not construct asymbol or arelent structures, so there is no + reason for them to use bfd_perform_relocation. Also, + bfd_perform_relocation is so hacked up it is easier to write a new + function than to try to deal with it. + + This routine does a final relocation. It should not be used when + generating relocateable output. + + FIXME: This routine ignores any special_function in the HOWTO, + since the existing special_function values have been written for + bfd_perform_relocation. + + HOWTO is the reloc howto information. + INPUT_BFD is the BFD which the reloc applies to. + INPUT_SECTION is the section which the reloc applies to. + CONTENTS is the contents of the section. + ADDRESS is the address of the reloc within INPUT_SECTION. + VALUE is the value of the symbol the reloc refers to. + ADDEND is the addend of the reloc. */ + +bfd_reloc_status_type +_bfd_final_link_relocate (howto, input_bfd, input_section, contents, address, + value, addend) + reloc_howto_type *howto; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + bfd_vma address; + bfd_vma value; + bfd_vma addend; +{ + bfd_vma relocation; + + /* Sanity check the address. */ + if (address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* This function assumes that we are dealing with a basic relocation + against a symbol. We want to compute the value of the symbol to + relocate to. This is just VALUE, the value of the symbol, plus + ADDEND, any addend associated with the reloc. */ + relocation = value + addend; + + /* If the relocation is PC relative, we want to set RELOCATION to + the distance between the symbol (currently in RELOCATION) and the + location we are relocating. Some targets (e.g., i386-aout) + arrange for the contents of the section to be the negative of the + offset of the location within the section; for such targets + pcrel_offset is false. Other targets (e.g., m88kbcs or ELF) + simply leave the contents of the section as zero; for such + targets pcrel_offset is true. If pcrel_offset is false we do not + need to subtract out the offset of the location within the + section (which is just ADDRESS). */ + if (howto->pc_relative) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset); + if (howto->pcrel_offset) + relocation -= address; + } + + return _bfd_relocate_contents (howto, input_bfd, relocation, + contents + address); +} + +/* Relocate a given location using a given value and howto. */ + +bfd_reloc_status_type +_bfd_relocate_contents (howto, input_bfd, relocation, location) + reloc_howto_type *howto; + bfd *input_bfd; + bfd_vma relocation; + bfd_byte *location; +{ + int size; + bfd_vma x; + boolean overflow; + + /* If the size is negative, negate RELOCATION. This isn't very + general. */ + if (howto->size < 0) + relocation = -relocation; + + /* Get the value we are going to relocate. */ + size = bfd_get_reloc_size (howto); + switch (size) + { + default: + case 0: + abort (); + case 1: + x = bfd_get_8 (input_bfd, location); + break; + case 2: + x = bfd_get_16 (input_bfd, location); + break; + case 4: + x = bfd_get_32 (input_bfd, location); + break; + case 8: +#ifdef BFD64 + x = bfd_get_64 (input_bfd, location); +#else + abort (); +#endif + break; + } + + /* Check for overflow. FIXME: We may drop bits during the addition + which we don't check for. We must either check at every single + operation, which would be tedious, or we must do the computations + in a type larger than bfd_vma, which would be inefficient. */ + overflow = false; + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + bfd_signed_vma signed_check; + bfd_vma add; + bfd_signed_vma signed_add; + + if (howto->rightshift == 0) + { + check = relocation; + signed_check = (bfd_signed_vma) relocation; + } + else + { + /* Drop unwanted bits from the value we are relocating to. */ + check = relocation >> howto->rightshift; + + /* If this is a signed value, the rightshift just dropped + leading 1 bits (assuming twos complement). */ + if ((bfd_signed_vma) relocation >= 0) + signed_check = check; + else + signed_check = (check + | ((bfd_vma) - 1 + & ~((bfd_vma) - 1 >> howto->rightshift))); + } + + /* Get the value from the object file. */ + add = x & howto->src_mask; + + /* Get the value from the object file with an appropriate sign. + The expression involving howto->src_mask isolates the upper + bit of src_mask. If that bit is set in the value we are + adding, it is negative, and we subtract out that number times + two. If src_mask includes the highest possible bit, then we + can not get the upper bit, but that does not matter since + signed_add needs no adjustment to become negative in that + case. */ + signed_add = add; + if ((add & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0) + signed_add -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1; + + /* Add the value from the object file, shifted so that it is a + straight number. */ + if (howto->bitpos == 0) + { + check += add; + signed_check += signed_add; + } + else + { + check += add >> howto->bitpos; + + /* For the signed case we use ADD, rather than SIGNED_ADD, + to avoid warnings from SVR4 cc. This is OK since we + explictly handle the sign bits. */ + if (signed_add >= 0) + signed_check += add >> howto->bitpos; + else + signed_check += ((add >> howto->bitpos) + | ((bfd_vma) - 1 + & ~((bfd_vma) - 1 >> howto->bitpos))); + } + + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~reloc_signed_max; + + if (signed_check > reloc_signed_max + || signed_check < reloc_signed_min) + overflow = true; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (check > reloc_unsigned_max) + overflow = true; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((check & ~reloc_bits) != 0 + && (((bfd_vma) signed_check & ~reloc_bits) + != (-1 & ~reloc_bits))) + overflow = true; + } + break; + default: + abort (); + } + } + + /* Put RELOCATION in the right bits. */ + relocation >>= (bfd_vma) howto->rightshift; + relocation <<= (bfd_vma) howto->bitpos; + + /* Add RELOCATION to the right bits of X. */ + x = ((x & ~howto->dst_mask) + | (((x & howto->src_mask) + relocation) & howto->dst_mask)); + + /* Put the relocated value back in the object file. */ + switch (size) + { + default: + case 0: + abort (); + case 1: + bfd_put_8 (input_bfd, x, location); + break; + case 2: + bfd_put_16 (input_bfd, x, location); + break; + case 4: + bfd_put_32 (input_bfd, x, location); + break; + case 8: +#ifdef BFD64 + bfd_put_64 (input_bfd, x, location); +#else + abort (); +#endif + break; + } + + return overflow ? bfd_reloc_overflow : bfd_reloc_ok; +} + +/* +DOCDD +INODE + howto manager, , typedef arelent, Relocations + +SECTION + The howto manager + + When an application wants to create a relocation, but doesn't + know what the target machine might call it, it can find out by + using this bit of code. + +*/ + +/* +TYPEDEF + bfd_reloc_code_type + +DESCRIPTION + The insides of a reloc code. The idea is that, eventually, there + will be one enumerator for every type of relocation we ever do. + Pass one of these values to <>, and it'll + return a howto pointer. + + This does mean that the application must determine the correct + enumerator value; you can't get a howto pointer from a random set + of attributes. + +SENUM + bfd_reloc_code_real + +ENUM + BFD_RELOC_64 +ENUMX + BFD_RELOC_32 +ENUMX + BFD_RELOC_26 +ENUMX + BFD_RELOC_16 +ENUMX + BFD_RELOC_14 +ENUMX + BFD_RELOC_8 +ENUMDOC + Basic absolute relocations of N bits. + +ENUM + BFD_RELOC_64_PCREL +ENUMX + BFD_RELOC_32_PCREL +ENUMX + BFD_RELOC_24_PCREL +ENUMX + BFD_RELOC_16_PCREL +ENUMX + BFD_RELOC_12_PCREL +ENUMX + BFD_RELOC_8_PCREL +ENUMDOC + PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. + +ENUM + BFD_RELOC_32_GOT_PCREL +ENUMX + BFD_RELOC_16_GOT_PCREL +ENUMX + BFD_RELOC_8_GOT_PCREL +ENUMX + BFD_RELOC_32_GOTOFF +ENUMX + BFD_RELOC_16_GOTOFF +ENUMX + BFD_RELOC_LO16_GOTOFF +ENUMX + BFD_RELOC_HI16_GOTOFF +ENUMX + BFD_RELOC_HI16_S_GOTOFF +ENUMX + BFD_RELOC_8_GOTOFF +ENUMX + BFD_RELOC_32_PLT_PCREL +ENUMX + BFD_RELOC_24_PLT_PCREL +ENUMX + BFD_RELOC_16_PLT_PCREL +ENUMX + BFD_RELOC_8_PLT_PCREL +ENUMX + BFD_RELOC_32_PLTOFF +ENUMX + BFD_RELOC_16_PLTOFF +ENUMX + BFD_RELOC_LO16_PLTOFF +ENUMX + BFD_RELOC_HI16_PLTOFF +ENUMX + BFD_RELOC_HI16_S_PLTOFF +ENUMX + BFD_RELOC_8_PLTOFF +ENUMDOC + For ELF. + +ENUM + BFD_RELOC_68K_GLOB_DAT +ENUMX + BFD_RELOC_68K_JMP_SLOT +ENUMX + BFD_RELOC_68K_RELATIVE +ENUMDOC + Relocations used by 68K ELF. + +ENUM + BFD_RELOC_32_BASEREL +ENUMX + BFD_RELOC_16_BASEREL +ENUMX + BFD_RELOC_LO16_BASEREL +ENUMX + BFD_RELOC_HI16_BASEREL +ENUMX + BFD_RELOC_HI16_S_BASEREL +ENUMX + BFD_RELOC_8_BASEREL +ENUMX + BFD_RELOC_RVA +ENUMDOC + Linkage-table relative. + +ENUM + BFD_RELOC_8_FFnn +ENUMDOC + Absolute 8-bit relocation, but used to form an address like 0xFFnn. + +ENUM + BFD_RELOC_32_PCREL_S2 +ENUMX + BFD_RELOC_16_PCREL_S2 +ENUMX + BFD_RELOC_23_PCREL_S2 +ENUMDOC + These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. + +ENUM + BFD_RELOC_HI22 +ENUMX + BFD_RELOC_LO10 +ENUMDOC + High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. + +ENUM + BFD_RELOC_GPREL16 +ENUMX + BFD_RELOC_GPREL32 +ENUMDOC + For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. + + +ENUM + BFD_RELOC_I960_CALLJ +ENUMDOC + Reloc types used for i960/b.out. + +ENUM + BFD_RELOC_NONE +ENUMX + BFD_RELOC_SPARC_WDISP22 +ENUMX + BFD_RELOC_SPARC22 +ENUMX + BFD_RELOC_SPARC13 +ENUMX + BFD_RELOC_SPARC_GOT10 +ENUMX + BFD_RELOC_SPARC_GOT13 +ENUMX + BFD_RELOC_SPARC_GOT22 +ENUMX + BFD_RELOC_SPARC_PC10 +ENUMX + BFD_RELOC_SPARC_PC22 +ENUMX + BFD_RELOC_SPARC_WPLT30 +ENUMX + BFD_RELOC_SPARC_COPY +ENUMX + BFD_RELOC_SPARC_GLOB_DAT +ENUMX + BFD_RELOC_SPARC_JMP_SLOT +ENUMX + BFD_RELOC_SPARC_RELATIVE +ENUMX + BFD_RELOC_SPARC_UA32 +ENUMDOC + SPARC ELF relocations. There is probably some overlap with other + relocation types already defined. + +ENUM + BFD_RELOC_SPARC_BASE13 +ENUMX + BFD_RELOC_SPARC_BASE22 +ENUMDOC + I think these are specific to SPARC a.out (e.g., Sun 4). + +ENUMEQ + BFD_RELOC_SPARC_64 + BFD_RELOC_64 +ENUMX + BFD_RELOC_SPARC_10 +ENUMX + BFD_RELOC_SPARC_11 +ENUMX + BFD_RELOC_SPARC_OLO10 +ENUMX + BFD_RELOC_SPARC_HH22 +ENUMX + BFD_RELOC_SPARC_HM10 +ENUMX + BFD_RELOC_SPARC_LM22 +ENUMX + BFD_RELOC_SPARC_PC_HH22 +ENUMX + BFD_RELOC_SPARC_PC_HM10 +ENUMX + BFD_RELOC_SPARC_PC_LM22 +ENUMX + BFD_RELOC_SPARC_WDISP16 +ENUMX + BFD_RELOC_SPARC_WDISP19 +ENUMX + BFD_RELOC_SPARC_GLOB_JMP +ENUMX + BFD_RELOC_SPARC_7 +ENUMX + BFD_RELOC_SPARC_6 +ENUMX + BFD_RELOC_SPARC_5 +ENUMDOC + Some relocations we're using for SPARC V9 -- subject to change. + +ENUM + BFD_RELOC_ALPHA_GPDISP_HI16 +ENUMDOC + Alpha ECOFF relocations. Some of these treat the symbol or "addend" + in some special way. + For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when + writing; when reading, it will be the absolute section symbol. The + addend is the displacement in bytes of the "lda" instruction from + the "ldah" instruction (which is at the address of this reloc). +ENUM + BFD_RELOC_ALPHA_GPDISP_LO16 +ENUMDOC + For GPDISP_LO16 ("ignore") relocations, the symbol is handled as + with GPDISP_HI16 relocs. The addend is ignored when writing the + relocations out, and is filled in with the file's GP value on + reading, for convenience. + +ENUM + BFD_RELOC_ALPHA_LITERAL +ENUMX + BFD_RELOC_ALPHA_LITUSE +ENUMDOC + The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; + the assembler turns it into a LDQ instruction to load the address of + the symbol, and then fills in a register in the real instruction. + + The LITERAL reloc, at the LDQ instruction, refers to the .lita + section symbol. The addend is ignored when writing, but is filled + in with the file's GP value on reading, for convenience, as with the + GPDISP_LO16 reloc. + + The LITUSE reloc, on the instruction using the loaded address, gives + information to the linker that it might be able to use to optimize + away some literal section references. The symbol is ignored (read + as the absolute section symbol), and the "addend" indicates the type + of instruction using the register: + 1 - "memory" fmt insn + 2 - byte-manipulation (byte offset reg) + 3 - jsr (target of branch) + + The GNU linker currently doesn't do any of this optimizing. + +ENUM + BFD_RELOC_ALPHA_HINT +ENUMDOC + The HINT relocation indicates a value that should be filled into the + "hint" field of a jmp/jsr/ret instruction, for possible branch- + prediction logic which may be provided on some processors. + +ENUM + BFD_RELOC_MIPS_JMP +ENUMDOC + Bits 27..2 of the relocation address shifted right 2 bits; + simple reloc otherwise. + +ENUM + BFD_RELOC_HI16 +ENUMDOC + High 16 bits of 32-bit value; simple reloc. +ENUM + BFD_RELOC_HI16_S +ENUMDOC + High 16 bits of 32-bit value but the low 16 bits will be sign + extended and added to form the final result. If the low 16 + bits form a negative number, we need to add one to the high value + to compensate for the borrow when the low bits are added. +ENUM + BFD_RELOC_LO16 +ENUMDOC + Low 16 bits. +ENUM + BFD_RELOC_PCREL_HI16_S +ENUMDOC + Like BFD_RELOC_HI16_S, but PC relative. +ENUM + BFD_RELOC_PCREL_LO16 +ENUMDOC + Like BFD_RELOC_LO16, but PC relative. + +ENUMEQ + BFD_RELOC_MIPS_GPREL + BFD_RELOC_GPREL16 +ENUMDOC + Relocation relative to the global pointer. + +ENUM + BFD_RELOC_MIPS_LITERAL +ENUMDOC + Relocation against a MIPS literal section. + +ENUM + BFD_RELOC_MIPS_GOT16 +ENUMX + BFD_RELOC_MIPS_CALL16 +ENUMEQX + BFD_RELOC_MIPS_GPREL32 + BFD_RELOC_GPREL32 +ENUMX + BFD_RELOC_MIPS_GOT_HI16 +ENUMX + BFD_RELOC_MIPS_GOT_LO16 +ENUMX + BFD_RELOC_MIPS_CALL_HI16 +ENUMX + BFD_RELOC_MIPS_CALL_LO16 +ENUMDOC + MIPS ELF relocations. + +ENUM + BFD_RELOC_386_GOT32 +ENUMX + BFD_RELOC_386_PLT32 +ENUMX + BFD_RELOC_386_COPY +ENUMX + BFD_RELOC_386_GLOB_DAT +ENUMX + BFD_RELOC_386_JUMP_SLOT +ENUMX + BFD_RELOC_386_RELATIVE +ENUMX + BFD_RELOC_386_GOTOFF +ENUMX + BFD_RELOC_386_GOTPC +ENUMDOC + i386/elf relocations + +ENUM + BFD_RELOC_NS32K_IMM_8 +ENUMX + BFD_RELOC_NS32K_IMM_16 +ENUMX + BFD_RELOC_NS32K_IMM_32 +ENUMX + BFD_RELOC_NS32K_IMM_8_PCREL +ENUMX + BFD_RELOC_NS32K_IMM_16_PCREL +ENUMX + BFD_RELOC_NS32K_IMM_32_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_8 +ENUMX + BFD_RELOC_NS32K_DISP_16 +ENUMX + BFD_RELOC_NS32K_DISP_32 +ENUMX + BFD_RELOC_NS32K_DISP_8_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_16_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_32_PCREL +ENUMDOC + ns32k relocations + +ENUM + BFD_RELOC_PPC_B26 +ENUMX + BFD_RELOC_PPC_BA26 +ENUMX + BFD_RELOC_PPC_TOC16 +ENUMX + BFD_RELOC_PPC_B16 +ENUMX + BFD_RELOC_PPC_B16_BRTAKEN +ENUMX + BFD_RELOC_PPC_B16_BRNTAKEN +ENUMX + BFD_RELOC_PPC_BA16 +ENUMX + BFD_RELOC_PPC_BA16_BRTAKEN +ENUMX + BFD_RELOC_PPC_BA16_BRNTAKEN +ENUMX + BFD_RELOC_PPC_COPY +ENUMX + BFD_RELOC_PPC_GLOB_DAT +ENUMX + BFD_RELOC_PPC_JMP_SLOT +ENUMX + BFD_RELOC_PPC_RELATIVE +ENUMX + BFD_RELOC_PPC_LOCAL24PC +ENUMX + BFD_RELOC_PPC_EMB_NADDR32 +ENUMX + BFD_RELOC_PPC_EMB_NADDR16 +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_LO +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_HI +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_HA +ENUMX + BFD_RELOC_PPC_EMB_SDAI16 +ENUMX + BFD_RELOC_PPC_EMB_SDA2I16 +ENUMX + BFD_RELOC_PPC_EMB_SDA2REL +ENUMX + BFD_RELOC_PPC_EMB_SDA21 +ENUMX + BFD_RELOC_PPC_EMB_MRKREF +ENUMX + BFD_RELOC_PPC_EMB_RELSEC16 +ENUMX + BFD_RELOC_PPC_EMB_RELST_LO +ENUMX + BFD_RELOC_PPC_EMB_RELST_HI +ENUMX + BFD_RELOC_PPC_EMB_RELST_HA +ENUMX + BFD_RELOC_PPC_EMB_BIT_FLD +ENUMX + BFD_RELOC_PPC_EMB_RELSDA +ENUMDOC + Power(rs6000) and PowerPC relocations. + +ENUM + BFD_RELOC_CTOR +ENUMDOC + The type of reloc used to build a contructor table - at the moment + probably a 32 bit wide absolute relocation, but the target can choose. + It generally does map to one of the other relocation types. + +ENUM + BFD_RELOC_ARM_PCREL_BRANCH +ENUMDOC + ARM 26 bit pc-relative branch. The lowest two bits must be zero and are + not stored in the instruction. +ENUM + BFD_RELOC_ARM_IMMEDIATE +ENUMX + BFD_RELOC_ARM_OFFSET_IMM +ENUMX + BFD_RELOC_ARM_SHIFT_IMM +ENUMX + BFD_RELOC_ARM_SWI +ENUMX + BFD_RELOC_ARM_MULTI +ENUMX + BFD_RELOC_ARM_CP_OFF_IMM +ENUMX + BFD_RELOC_ARM_ADR_IMM +ENUMX + BFD_RELOC_ARM_LDR_IMM +ENUMX + BFD_RELOC_ARM_LITERAL +ENUMX + BFD_RELOC_ARM_IN_POOL +ENUMDOC + These relocs are only used within the ARM assembler. They are not + (at present) written to any object files. + +COMMENT +ENDSENUM + BFD_RELOC_UNUSED +CODE_FRAGMENT +. +.typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +*/ + + +/* +FUNCTION + bfd_reloc_type_lookup + +SYNOPSIS + reloc_howto_type * + bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + Return a pointer to a howto structure which, when + invoked, will perform the relocation @var{code} on data from the + architecture noted. + +*/ + + +reloc_howto_type * +bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + return BFD_SEND (abfd, reloc_type_lookup, (abfd, code)); +} + +static reloc_howto_type bfd_howto_32 = +HOWTO (0, 00, 2, 32, false, 0, complain_overflow_bitfield, 0, "VRT32", false, 0xffffffff, 0xffffffff, true); + + +/* +INTERNAL_FUNCTION + bfd_default_reloc_type_lookup + +SYNOPSIS + reloc_howto_type *bfd_default_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a default relocation lookup routine for any architecture. + + +*/ + +reloc_howto_type * +bfd_default_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_CTOR: + /* The type of reloc used in a ctor, which will be as wide as the + address - so either a 64, 32, or 16 bitter. */ + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 64: + BFD_FAIL (); + case 32: + return &bfd_howto_32; + case 16: + BFD_FAIL (); + default: + BFD_FAIL (); + } + default: + BFD_FAIL (); + } + return (reloc_howto_type *) NULL; +} + +/* +FUNCTION + bfd_get_reloc_code_name + +SYNOPSIS + const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a printable name for the supplied relocation code. + Useful mainly for printing error messages. +*/ + +const char * +bfd_get_reloc_code_name (code) + bfd_reloc_code_real_type code; +{ + if (code > BFD_RELOC_UNUSED) + return 0; + return bfd_reloc_code_real_names[(int)code]; +} + +/* +INTERNAL_FUNCTION + bfd_generic_relax_section + +SYNOPSIS + boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + struct bfd_link_info *, + boolean *); + +DESCRIPTION + Provides default handling for relaxing for back ends which + don't do relaxing -- i.e., does nothing. +*/ + +/*ARGSUSED*/ +boolean +bfd_generic_relax_section (abfd, section, link_info, again) + bfd *abfd; + asection *section; + struct bfd_link_info *link_info; + boolean *again; +{ + *again = false; + return true; +} + +/* +INTERNAL_FUNCTION + bfd_generic_get_relocated_section_contents + +SYNOPSIS + bfd_byte * + bfd_generic_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + boolean relocateable, + asymbol **symbols); + +DESCRIPTION + Provides default handling of relocation effort for back ends + which can't be bothered to do it efficiently. + +*/ + +bfd_byte * +bfd_generic_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + if (reloc_size < 0) + goto error_return; + + reloc_vector = (arelent **) bfd_malloc ((size_t) reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + /* read in the section */ + if (!bfd_get_section_contents (input_bfd, + input_section, + (PTR) data, + 0, + input_section->_raw_size)) + goto error_return; + + /* We're not relaxing the section, so just copy the size info */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = true; + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + goto error_return; + + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent != (arelent *) NULL; + parent++) + { + char *error_message = (char *) NULL; + bfd_reloc_status_type r = + bfd_perform_relocation (input_bfd, + *parent, + (PTR) data, + input_section, + relocateable ? abfd : (bfd *) NULL, + &error_message); + + if (relocateable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + if (!((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_dangerous: + BFD_ASSERT (error_message != (char *) NULL); + if (!((*link_info->callbacks->reloc_dangerous) + (link_info, error_message, input_bfd, input_section, + (*parent)->address))) + goto error_return; + break; + case bfd_reloc_overflow: + if (!((*link_info->callbacks->reloc_overflow) + (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (*parent)->howto->name, (*parent)->addend, + input_bfd, input_section, (*parent)->address))) + goto error_return; + break; + case bfd_reloc_outofrange: + default: + abort (); + break; + } + + } + } + } + if (reloc_vector != NULL) + free (reloc_vector); + return data; + +error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return NULL; +} diff --git a/contrib/gdb/bfd/reloc16.c b/contrib/gdb/bfd/reloc16.c new file mode 100644 index 000000000000..e88d50fb9035 --- /dev/null +++ b/contrib/gdb/bfd/reloc16.c @@ -0,0 +1,289 @@ +/* 8 and 16 bit COFF relocation functions, for BFD. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +Most of this hacked by Steve Chamberlain, + sac@cygnus.com +*/ + +/* These routines are used by coff-h8300 and coff-z8k to do + relocation. + + FIXME: This code should be rewritten to support the new COFF + linker. Basically, they need to deal with COFF relocs rather than + BFD generic relocs. They should store the relocs in some location + where coff_link_input_bfd can find them (and coff_link_input_bfd + should be changed to use this location rather than rereading the + file) (unless info->keep_memory is false, in which case they should + free up the relocs after dealing with them). */ + +#include "bfd.h" +#include "sysdep.h" +#include "obstack.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "coff/internal.h" +#include "libcoff.h" + +bfd_vma +bfd_coff_reloc16_get_value (reloc, link_info, input_section) + arelent *reloc; + struct bfd_link_info *link_info; + asection *input_section; +{ + bfd_vma value; + asymbol *symbol = *(reloc->sym_ptr_ptr); + /* A symbol holds a pointer to a section, and an offset from the + base of the section. To relocate, we find where the section will + live in the output and add that in */ + + if (bfd_is_und_section (symbol->section)) + { + struct bfd_link_hash_entry *h; + + /* The symbol is undefined in this BFD. Look it up in the + global linker hash table. FIXME: This should be changed when + we convert this stuff to use a specific final_link function + and change the interface to bfd_relax_section to not require + the generic symbols. */ + h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info, + bfd_asymbol_name (symbol), + false, false, true); + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + value = (h->u.def.value + + h->u.def.section->output_section->vma + + h->u.def.section->output_offset); + else if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_common) + value = h->u.c.size; + else + { + if (! ((*link_info->callbacks->undefined_symbol) + (link_info, bfd_asymbol_name (symbol), + input_section->owner, input_section, reloc->address))) + abort (); + value = 0; + } + } + else + { + value = symbol->value + + symbol->section->output_offset + + symbol->section->output_section->vma; + } + + /* Add the value contained in the relocation */ + value += reloc->addend; + + return value; +} + +void +bfd_perform_slip(abfd, slip, input_section, value) + bfd *abfd; + unsigned int slip; + asection *input_section; + bfd_vma value; +{ + asymbol **s; + + s = _bfd_generic_link_get_symbols (abfd); + BFD_ASSERT (s != (asymbol **) NULL); + + /* Find all symbols past this point, and make them know + what's happened */ + while (*s) + { + asymbol *p = *s; + if (p->section == input_section) + { + /* This was pointing into this section, so mangle it */ + if (p->value > value) + { + p->value -= slip; + if (p->udata.p != NULL) + { + struct generic_link_hash_entry *h; + + h = (struct generic_link_hash_entry *) p->udata.p; + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + h->root.u.def.value -= slip; + BFD_ASSERT (h->root.u.def.value == p->value); + } + } + } + s++; + } +} + +boolean +bfd_coff_reloc16_relax_section (abfd, i, link_info, again) + bfd *abfd; + asection *i; + struct bfd_link_info *link_info; + boolean *again; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = i->owner; + asection *input_section = i; + int shrink = 0 ; + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + /* We only run this relaxation once. It might work to run it more + often, but it hasn't been tested. */ + *again = false; + + if (reloc_size < 0) + return false; + + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (!reloc_vector && reloc_size > 0) + return false; + + /* Get the relocs and think about them */ + reloc_count = + bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, + _bfd_generic_link_get_symbols (input_bfd)); + if (reloc_count < 0) + { + free (reloc_vector); + return false; + } + + if (reloc_count > 0) + { + arelent **parent; + for (parent = reloc_vector; *parent; parent++) + { + shrink = bfd_coff_reloc16_estimate (abfd, input_section, + *parent, shrink, link_info); + } + } + + input_section->_cooked_size -= shrink; + free((char *)reloc_vector); + return true; +} + +bfd_byte * +bfd_coff_reloc16_get_relocated_section_contents(in_abfd, + link_info, + link_order, + data, + relocateable, + symbols) + bfd *in_abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + boolean relocateable; + asymbol **symbols; +{ + /* Get enough memory to hold the stuff */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector; + long reloc_count; + + if (reloc_size < 0) + return NULL; + + /* If producing relocateable output, don't bother to relax. */ + if (relocateable) + return bfd_generic_get_relocated_section_contents (in_abfd, link_info, + link_order, + data, relocateable, + symbols); + + /* read in the section */ + if (! bfd_get_section_contents(input_bfd, + input_section, + data, + 0, + input_section->_raw_size)) + return NULL; + + + reloc_vector = (arelent **) bfd_malloc((size_t) reloc_size); + if (!reloc_vector && reloc_size != 0) + return NULL; + + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + reloc_vector, + symbols); + if (reloc_count < 0) + { + free (reloc_vector); + return NULL; + } + + if (reloc_count > 0) + { + arelent **parent = reloc_vector; + arelent *reloc ; + unsigned int dst_address = 0; + unsigned int src_address = 0; + unsigned int run; + unsigned int idx; + + /* Find how long a run we can do */ + while (dst_address < link_order->size) + { + reloc = *parent; + if (reloc) + { + /* Note that the relaxing didn't tie up the addresses in the + relocation, so we use the original address to work out the + run of non-relocated data */ + run = reloc->address - src_address; + parent++; + } + else + { + run = link_order->size - dst_address; + } + /* Copy the bytes */ + for (idx = 0; idx < run; idx++) + { + data[dst_address++] = data[src_address++]; + } + + /* Now do the relocation */ + + if (reloc) + { + bfd_coff_reloc16_extra_cases (input_bfd, link_info, link_order, + reloc, data, &src_address, + &dst_address); + } + } + } + free((char *)reloc_vector); + return data; +} + diff --git a/contrib/gdb/bfd/riscix.c b/contrib/gdb/bfd/riscix.c new file mode 100644 index 000000000000..21a86d5e1024 --- /dev/null +++ b/contrib/gdb/bfd/riscix.c @@ -0,0 +1,644 @@ +/* BFD back-end for RISC iX (Acorn, arm) binaries. + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* RISC iX overloads the MAGIC field to indicate more than just the usual + [ZNO]MAGIC values. Also included are squeezing information and + shared library usage. */ + +/* The following come from the man page. */ +#define SHLIBLEN 60 + +#define MF_IMPURE 00200 +#define MF_SQUEEZED 01000 +#define MF_USES_SL 02000 +#define MF_IS_SL 04000 + +/* Common combinations. */ +#define IMAGIC (MF_IMPURE|ZMAGIC) /* Demand load (impure text) */ +#define SPOMAGIC (MF_USES_SL|OMAGIC) /* OMAGIC with large header */ + /* -- may contain a ref to a */ + /* shared lib required by the */ + /* object. */ +#define SLOMAGIC (MF_IS_SL|OMAGIC) /* A reference to a shared library */ + /* The text portion of the object */ + /* contains "overflow text" from */ + /* the shared library to be linked */ + /* in with an object */ +#define QMAGIC (MF_SQUEEZED|ZMAGIC) /* Sqeezed demand paged. */ + /* NOTE: This interpretation of */ + /* QMAGIC seems to be at variance */ + /* With that used on other */ + /* architectures. */ +#define SPZMAGIC (MF_USES_SL|ZMAGIC) /* program which uses sl */ +#define SPQMAGIC (MF_USES_SL|QMAGIC) /* sqeezed ditto */ +#define SLZMAGIC (MF_IS_SL|ZMAGIC) /* shared lib part of prog */ +#define SLPZMAGIC (MF_USES_SL|SLZMAGIC) /* sl which uses another */ + +#define N_SHARED_LIB(x) ((x).a_info & MF_USES_SL) + +/* Only a pure OMAGIC file has the minimal header */ +#define N_TXTOFF(x) \ + ((x).a_info == OMAGIC ? 32 \ + : (N_MAGIC(x) == ZMAGIC) ? TARGET_PAGE_SIZE \ + : 999) + +#define N_TXTADDR(x) \ + (N_MAGIC(x) != ZMAGIC ? 0 /* object file or NMAGIC */ \ + /* Programs with shared libs are loaded at the first page after all the \ + text segments of the shared library programs. Without looking this \ + up we can't know exactly what the address will be. A reasonable guess \ + is that a_entry will be in the first page of the executable. */ \ + : N_SHARED_LIB(x) ? ((x).a_entry & ~(TARGET_PAGE_SIZE - 1)) \ + : TEXT_START_ADDR) + +#define N_SYMOFF(x) \ + (N_TXTOFF (x) + (x).a_text + (x).a_data + (x).a_trsize + (x).a_drsize) + +#define N_STROFF(x) (N_SYMOFF (x) + (x).a_syms) + +#define TEXT_START_ADDR 32768 +#define TARGET_PAGE_SIZE 32768 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_arm + +#define MY(OP) CAT(riscix_,OP) +#define TARGETNAME "a.out-riscix" +#define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) && \ + (((x).a_info & ~006000) != OMAGIC) && \ + ((x).a_info != NMAGIC)) +#define N_MAGIC(x) ((x).a_info & ~07200) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "assert.h" + +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false; \ + if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) \ + != EXEC_BYTES_SIZE) \ + return false; \ + /* Now write out reloc info, followed by syms and strings */ \ + \ + if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \ + && bfd_get_symcount (abfd) != 0) \ + { \ + if (bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET) != 0) \ + return false; \ + \ + if (! NAME(aout,write_syms)(abfd)) return false; \ + \ + if (bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET) != 0) \ + return false; \ + \ + if (! riscix_squirt_out_relocs (abfd, obj_textsec (abfd))) \ + return false; \ + if (bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET) != 0) \ + return false; \ + \ + if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) \ + return false; \ + } \ + } + +#include "libaout.h" +#include "aout/aout64.h" + +static bfd_reloc_status_type +riscix_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static bfd_reloc_status_type +riscix_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR, + asection *, bfd *, char **)); + +static reloc_howto_type riscix_std_reloc_howto[] = { + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ + HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false), + HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false), + HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false), + HOWTO( 3, 2, 3, 26, true, 0, complain_overflow_signed, riscix_fix_pcrel_26 , "ARM26", true, 0x00ffffff,0x00ffffff, false), + HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, true), + HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, true), + HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, true), + HOWTO( 7, 2, 3, 26, false, 0, complain_overflow_signed, riscix_fix_pcrel_26_done, "ARM26D",true,0x00ffffff,0x00ffffff, false), + {-1}, + HOWTO( 9, 0, -1, 16, false, 0, complain_overflow_bitfield,0,"NEG16", true, 0x0000ffff,0x0000ffff, false), + HOWTO( 10, 0, -2, 32, false, 0, complain_overflow_bitfield,0,"NEG32", true, 0xffffffff,0xffffffff, false) +}; + +#define RISCIX_TABLE_SIZE \ + (sizeof (riscix_std_reloc_howto) / sizeof (reloc_howto_type)) + + +static bfd_reloc_status_type +riscix_fix_pcrel_26_done (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + /* This is dead simple at present. */ + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +riscix_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_size_type addr = reloc_entry->address; + long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); + bfd_reloc_status_type flag = bfd_reloc_ok; + + /* If this is an undefined symbol, return error */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0) + return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; + + /* If the sections are different, and we are doing a partial relocation, + just ignore it for now. */ + if (symbol->section->name != input_section->name + && output_bfd != (bfd *)NULL) + return bfd_reloc_continue; + + relocation = (target & 0x00ffffff) << 2; + relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */ + relocation += symbol->value; + relocation += symbol->section->output_section->vma; + relocation += symbol->section->output_offset; + relocation += reloc_entry->addend; + relocation -= input_section->output_section->vma; + relocation -= input_section->output_offset; + relocation -= addr; + if (relocation & 3) + return bfd_reloc_overflow; + + /* Check for overflow */ + if (relocation & 0x02000000) + { + if ((relocation & ~0x03ffffff) != ~0x03ffffff) + flag = bfd_reloc_overflow; + } + else if (relocation & ~0x03ffffff) + flag = bfd_reloc_overflow; + + target &= ~0x00ffffff; + target |= (relocation >> 2) & 0x00ffffff; + bfd_put_32 (abfd, target, (bfd_byte *) data + addr); + + /* Now the ARM magic... Change the reloc type so that it is marked as done. + Strictly this is only necessary if we are doing a partial relocation. */ + reloc_entry->howto = &riscix_std_reloc_howto[7]; + + return flag; +} + +reloc_howto_type * +DEFUN(riscix_reloc_type_lookup,(abfd,code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ +#define ASTD(i,j) case i: return &riscix_std_reloc_howto[j] + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + default: return (reloc_howto_type *) NULL; + } + + switch (code) + { + ASTD (BFD_RELOC_16, 1); + ASTD (BFD_RELOC_32, 2); + ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3); + ASTD (BFD_RELOC_8_PCREL, 4); + ASTD (BFD_RELOC_16_PCREL, 5); + ASTD (BFD_RELOC_32_PCREL, 6); + default: return (reloc_howto_type *) NULL; + } +} + +#define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define MY_bfd_final_link _bfd_generic_final_link + +#define MY_bfd_reloc_type_lookup riscix_reloc_type_lookup +#define MY_canonicalize_reloc riscix_canonicalize_reloc +#define MY_object_p riscix_object_p + +static const bfd_target *riscix_callback PARAMS ((bfd *)); + +void +riscix_swap_std_reloc_out (abfd, g, natptr) + bfd *abfd; + arelent *g; + struct reloc_std_external *natptr; +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + int r_length; + int r_pcrel; + int r_neg = 0; /* Negative relocs use the BASEREL bit. */ + asection *output_section = sym->section->output_section; + + PUT_WORD(abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two */ + if (r_length < 0) + { + r_length = -r_length; + r_neg = 1; + } + + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + + /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the + relocation has been done already (Only for the 26-bit one I think)???!!! + */ + + if (r_length == 3) + r_pcrel = r_pcrel ? 0 : 1; + + +#if 0 + /* For a standard reloc, the addend is in the object file. */ + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; +#endif + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = stoi((*(g->sym_ptr_ptr))->flags); + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (bfd_header_big_endian (abfd)) + { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + ( (r_extern ? RELOC_STD_BITS_EXTERN_BIG: 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG: 0) + | (r_neg ? RELOC_STD_BITS_BASEREL_BIG: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); + } + else + { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + ( (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_neg ? RELOC_STD_BITS_BASEREL_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); + } +} + +boolean +riscix_squirt_out_relocs (abfd, section) + bfd *abfd; + asection *section; +{ + arelent **generic; + unsigned char *native, *natptr; + size_t each_size; + + unsigned int count = section->reloc_count; + size_t natsize; + + if (count == 0) return true; + + each_size = obj_reloc_entry_size (abfd); + natsize = each_size * count; + native = (unsigned char *) bfd_zalloc (abfd, natsize); + if (!native) + return false; + + generic = section->orelocation; + + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + riscix_swap_std_reloc_out (abfd, *generic, + (struct reloc_std_external *) natptr); + + if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) + { + bfd_release(abfd, native); + return false; + } + + bfd_release (abfd, native); + return true; +} + + +/* + * This is just like the standard aoutx.h version but we need to do our + * own mapping of external reloc type values to howto entries. + */ +long +MY(canonicalize_reloc)(abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count, c; + extern reloc_howto_type NAME(aout,std_howto_table)[]; + + /* If we have already read in the relocation table, return the values. */ + if (section->flags & SEC_CONSTRUCTOR) { + arelent_chain *chain = section->constructor_chain; + + for (count = 0; count < section->reloc_count; count++) { + *relptr++ = &chain->relent; + chain = chain->next; + } + *relptr = 0; + return section->reloc_count; + } + if (tblptr && section->reloc_count) { + for (count = 0; count++ < section->reloc_count;) + *relptr++ = tblptr++; + *relptr = 0; + return section->reloc_count; + } + + if (!NAME(aout,slurp_reloc_table)(abfd, section, symbols)) + return -1; + tblptr = section->relocation; + + /* fix up howto entries */ + for (count = 0; count++ < section->reloc_count;) + { + c = tblptr->howto - NAME(aout,std_howto_table); + assert (c < RISCIX_TABLE_SIZE); + tblptr->howto = &riscix_std_reloc_howto[c]; + + *relptr++ = tblptr++; + } + *relptr = 0; + return section->reloc_count; +} + +/* This is the same as NAME(aout,some_aout_object_p), but has different + expansions of the macro definitions. */ + +const bfd_target * +riscix_some_aout_object_p (abfd, execp, callback_to_real_object_p) + bfd *abfd; + struct internal_exec *execp; + const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *)); +{ + struct aout_data_struct *rawptr, *oldrawptr; + const bfd_target *result; + + rawptr = ((struct aout_data_struct *) + bfd_zalloc (abfd, sizeof (struct aout_data_struct ))); + + if (rawptr == NULL) + return 0; + + oldrawptr = abfd->tdata.aout_data; + abfd->tdata.aout_data = rawptr; + + /* Copy the contents of the old tdata struct. + In particular, we want the subformat, since for hpux it was set in + hp300hpux.c:swap_exec_header_in and will be used in + hp300hpux.c:callback. */ + if (oldrawptr != NULL) + *abfd->tdata.aout_data = *oldrawptr; + + abfd->tdata.aout_data->a.hdr = &rawptr->e; + *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec + struct */ + execp = abfd->tdata.aout_data->a.hdr; + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + /* Setting of EXEC_P has been deferred to the bottom of this function */ + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + if (N_DYNAMIC(*execp)) + abfd->flags |= DYNAMIC; + + + if ((execp->a_info & MF_SQUEEZED) != 0) /* Squeezed files aren't supported + (yet)! */ + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + else if ((execp->a_info & MF_IS_SL) != 0) /* Nor are shared libraries */ + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + else if (N_MAGIC (*execp) == ZMAGIC) + { + abfd->flags |= D_PAGED | WP_TEXT; + adata (abfd).magic = z_magic; + } + else if (N_MAGIC (*execp) == NMAGIC) + { + abfd->flags |= WP_TEXT; + adata (abfd).magic = n_magic; + } + else if (N_MAGIC (*execp) == OMAGIC) + adata (abfd).magic = o_magic; + else + { + /* Should have been checked with N_BADMAG before this routine + was called. */ + abort (); + } + + bfd_get_start_address (abfd) = execp->a_entry; + + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; + bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist); + + /* The default relocation entry size is that of traditional V7 Unix. */ + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + /* The default symbol entry size is that of traditional Unix. */ + obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE; + + obj_aout_external_syms (abfd) = NULL; + obj_aout_external_strings (abfd) = NULL; + obj_aout_sym_hashes (abfd) = NULL; + + if (! NAME(aout,make_sections) (abfd)) + return NULL; + + obj_datasec (abfd)->_raw_size = execp->a_data; + obj_bsssec (abfd)->_raw_size = execp->a_bss; + + obj_textsec (abfd)->flags = + (execp->a_trsize != 0 + ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) + : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = + (execp->a_drsize != 0 + ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) + : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + + result = (*callback_to_real_object_p)(abfd); + +#if defined(MACH) || defined(STAT_FOR_EXEC) + /* The original heuristic doesn't work in some important cases. The + * a.out file has no information about the text start address. For + * files (like kernels) linked to non-standard addresses (ld -Ttext + * nnn) the entry point may not be between the default text start + * (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size + * This is not just a mach issue. Many kernels are loaded at non + * standard addresses. + */ + { + struct stat stat_buf; + if (abfd->iostream != NULL + && (abfd->flags & BFD_IN_MEMORY) == 0 + && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0) + && ((stat_buf.st_mode & 0111) != 0)) + abfd->flags |= EXEC_P; + } +#else /* ! MACH */ + /* Now that the segment addresses have been worked out, take a better + guess at whether the file is executable. If the entry point + is within the text segment, assume it is. (This makes files + executable even if their entry point address is 0, as long as + their text starts at zero.) + + At some point we should probably break down and stat the file and + declare it executable if (one of) its 'x' bits are on... */ + if ((execp->a_entry >= obj_textsec(abfd)->vma) && + (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size)) + abfd->flags |= EXEC_P; +#endif /* MACH */ + if (result) + { + } + else + { + free (rawptr); + abfd->tdata.aout_data = oldrawptr; + } + return result; +} + + +static const bfd_target * +MY(object_p) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; /* Raw exec header from file */ + struct internal_exec exec; /* Cleaned-up exec header */ + const bfd_target *target; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); + + if (N_BADMAG (exec)) return 0; +#ifdef MACHTYPE_OK + if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0; +#endif + + NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec); + + target = riscix_some_aout_object_p (abfd, &exec, MY(callback)); + + return target; +} + + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/rs6000-core.c b/contrib/gdb/bfd/rs6000-core.c new file mode 100644 index 000000000000..4889f72f6dda --- /dev/null +++ b/contrib/gdb/bfd/rs6000-core.c @@ -0,0 +1,396 @@ +/* IBM RS/6000 "XCOFF" back-end for BFD. + Copyright (C) 1990, 1991, 1995 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Metin G. Ozisik, Mimi Ph\373\364ng-Th\345o V\365, + and John Gilmore. + Archive support from Damon A. Permezel. + Contributed by IBM Corporation and Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This port currently only handles reading object files, except when + compiled on an RS/6000 host. -- no archive support, no core files. + In all cases, it does not support writing. + + FIXMEmgo comments are left from Metin Ozisik's original port. + + This is in a separate file from coff-rs6000.c, because it includes + system include files that conflict with coff/rs6000.h. + */ + +/* Internalcoff.h and coffcode.h modify themselves based on this flag. */ +#define RS6000COFF_C 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifdef AIX_CORE + +/* AOUTHDR is defined by the above. We need another defn of it, from the + system include files. Punt the old one and get us a new name for the + typedef in the system include files. */ +#ifdef AOUTHDR +#undef AOUTHDR +#endif +#define AOUTHDR second_AOUTHDR + +#undef SCNHDR + + +/* ------------------------------------------------------------------------ */ +/* Support for core file stuff.. */ +/* ------------------------------------------------------------------------ */ + +#include +#include +#include + + +/* Number of special purpose registers supported by gdb. This value + should match `tm.h' in gdb directory. Clean this mess up and use + the macros in sys/reg.h. FIXMEmgo. */ + +#define NUM_OF_SPEC_REGS 7 + +#define core_hdr(bfd) (((Rs6kCorData*)(bfd->tdata.any))->hdr) +#define core_datasec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->data_section) +#define core_stacksec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->stack_section) +#define core_regsec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg_section) +#define core_reg2sec(bfd) (((Rs6kCorData*)(bfd->tdata.any))->reg2_section) + +/* AIX 4.1 Changed the names and locations of a few items in the core file, + this seems to be the quickest easiet way to deal with it. + + Note however that encoding magic addresses (STACK_END_ADDR) is going + to be _very_ fragile. But I don't see any easy way to get that info + right now. */ +#ifdef CORE_VERSION_1 +#define CORE_DATA_SIZE_FIELD c_u.U_dsize +#define CORE_COMM_FIELD c_u.U_comm +#define SAVE_FIELD c_mst +#define STACK_END_ADDR 0x2ff23000 +#else +#define CORE_DATA_SIZE_FIELD c_u.u_dsize +#define CORE_COMM_FIELD c_u.u_comm +#define SAVE_FIELD c_u.u_save +#define STACK_END_ADDR 0x2ff80000 +#endif + +/* These are stored in the bfd's tdata */ +typedef struct { + struct core_dump hdr; /* core file header */ + asection *data_section, + *stack_section, + *reg_section, /* section for GPRs and special registers. */ + *reg2_section; /* section for FPRs. */ + + /* This tells us where everything is mapped (shared libraries and so on). + GDB needs it. */ + asection *ldinfo_section; +#define core_ldinfosec(bfd) (((Rs6kCorData *)(bfd->tdata.any))->ldinfo_section) +} Rs6kCorData; + + +/* Decide if a given bfd represents a `core' file or not. There really is no + magic number or anything like, in rs6000coff. */ + +const bfd_target * +rs6000coff_core_p (abfd) + bfd *abfd; +{ + int fd; + struct core_dump coredata; + struct stat statbuf; + char *tmpptr; + + /* Use bfd_xxx routines, rather than O/S primitives to read coredata. FIXMEmgo */ + fd = open (abfd->filename, O_RDONLY); + if (fd < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + if (fstat (fd, &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + close (fd); + return NULL; + } + if (read (fd, &coredata, sizeof (struct core_dump)) + != sizeof (struct core_dump)) + { + bfd_set_error (bfd_error_wrong_format); + close (fd); + return NULL; + } + + if (close (fd) < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + /* If the core file ulimit is too small, the system will first + omit the data segment, then omit the stack, then decline to + dump core altogether (as far as I know UBLOCK_VALID and LE_VALID + are always set) (this is based on experimentation on AIX 3.2). + Now, the thing is that GDB users will be surprised + if segments just silently don't appear (well, maybe they would + think to check "info files", I don't know), but we have no way of + returning warnings (as opposed to errors). + + For the data segment, we have no choice but to keep going if it's + not there, since the default behavior is not to dump it (regardless + of the ulimit, it's based on SA_FULLDUMP). But for the stack segment, + if it's not there, we refuse to have anything to do with this core + file. The usefulness of a core dump without a stack segment is pretty + limited anyway. */ + + if (!(coredata.c_flag & UBLOCK_VALID) + || !(coredata.c_flag & LE_VALID)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if ((coredata.c_flag & CORE_TRUNC) + || !(coredata.c_flag & USTACK_VALID)) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + + /* Don't check the core file size for a full core, AIX 4.1 includes + additional shared library sections in a full core. */ + if (!(coredata.c_flag & FULL_CORE) + && ((bfd_vma)coredata.c_stack + coredata.c_size) != statbuf.st_size) + { + /* If the size is wrong, it means we're misinterpreting something. */ + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Sanity check on the c_tab field. */ + if ((u_long) coredata.c_tab < sizeof coredata || + (u_long) coredata.c_tab >= statbuf.st_size || + (long) coredata.c_tab >= (long)coredata.c_stack) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* maybe you should alloc space for the whole core chunk over here!! FIXMEmgo */ + tmpptr = (char*)bfd_zalloc (abfd, sizeof (Rs6kCorData)); + if (!tmpptr) + return NULL; + + set_tdata (abfd, tmpptr); + + /* Copy core file header. */ + core_hdr (abfd) = coredata; + + /* .stack section. */ + if ((core_stacksec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) + return NULL; + core_stacksec (abfd)->name = ".stack"; + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_stacksec (abfd)->_raw_size = coredata.c_size; + core_stacksec (abfd)->vma = STACK_END_ADDR - coredata.c_size; + core_stacksec (abfd)->filepos = (int)coredata.c_stack; /*???? */ + + /* .reg section for GPRs and special registers. */ + if ((core_regsec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) + return NULL; + core_regsec (abfd)->name = ".reg"; + core_regsec (abfd)->flags = SEC_HAS_CONTENTS; + core_regsec (abfd)->_raw_size = (32 + NUM_OF_SPEC_REGS) * 4; + core_regsec (abfd)->vma = 0; /* not used?? */ + core_regsec (abfd)->filepos = + (char*)&coredata.SAVE_FIELD - (char*)&coredata; + + /* .reg2 section for FPRs (floating point registers). */ + if ((core_reg2sec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) + return NULL; + core_reg2sec (abfd)->name = ".reg2"; + core_reg2sec (abfd)->flags = SEC_HAS_CONTENTS; + core_reg2sec (abfd)->_raw_size = 8 * 32; /* 32 FPRs. */ + core_reg2sec (abfd)->vma = 0; /* not used?? */ + core_reg2sec (abfd)->filepos = + (char*)&coredata.SAVE_FIELD.fpr[0] - (char*)&coredata; + + if ((core_ldinfosec (abfd) = (asection*) bfd_zalloc (abfd, sizeof (asection))) + == NULL) + return NULL; + core_ldinfosec (abfd)->name = ".ldinfo"; + core_ldinfosec (abfd)->flags = SEC_HAS_CONTENTS; + /* To actually find out how long this section is in this particular + core dump would require going down the whole list of struct ld_info's. + See if we can just fake it. */ + core_ldinfosec (abfd)->_raw_size = 0x7fffffff; + /* Not relevant for ldinfo section. */ + core_ldinfosec (abfd)->vma = 0; + core_ldinfosec (abfd)->filepos = (file_ptr) coredata.c_tab; + + /* set up section chain here. */ + abfd->section_count = 4; + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_regsec(abfd); + core_regsec (abfd)->next = core_reg2sec (abfd); + core_reg2sec (abfd)->next = core_ldinfosec (abfd); + core_ldinfosec (abfd)->next = NULL; + + if (coredata.c_flag & FULL_CORE) + { + asection *sec = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (sec == NULL) + return NULL; + sec->name = ".data"; + sec->flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; + sec->_raw_size = coredata.CORE_DATA_SIZE_FIELD; + sec->vma = CDATA_ADDR (coredata.CORE_DATA_SIZE_FIELD); + sec->filepos = (int)coredata.c_stack + coredata.c_size; + + sec->next = abfd->sections; + abfd->sections = sec; + ++abfd->section_count; + } + + return abfd->xvec; /* this is garbage for now. */ +} + + + +/* return `true' if given core is from the given executable.. */ +boolean +rs6000coff_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + FILE *fd; + struct core_dump coredata; + struct ld_info ldinfo; + char pathname [1024]; + const char *str1, *str2; + + /* Use bfd_xxx routines, rather than O/S primitives, do error checking!! + FIXMEmgo */ + /* Actually should be able to use bfd_get_section_contents now that + we have a .ldinfo section. */ + fd = fopen (core_bfd->filename, FOPEN_RB); + + fread (&coredata, sizeof (struct core_dump), 1, fd); + fseek (fd, (long)coredata.c_tab, 0); + fread (&ldinfo, (char*)&ldinfo.ldinfo_filename[0] - (char*)&ldinfo.ldinfo_next, + 1, fd); + fscanf (fd, "%s", pathname); + + str1 = strrchr (pathname, '/'); + str2 = strrchr (exec_bfd->filename, '/'); + + /* step over character '/' */ + str1 = str1 ? str1+1 : &pathname[0]; + str2 = str2 ? str2+1 : exec_bfd->filename; + + fclose (fd); + return strcmp (str1, str2) == 0; +} + +char * +rs6000coff_core_file_failing_command (abfd) + bfd *abfd; +{ + char *com = core_hdr (abfd).CORE_COMM_FIELD; + if (*com) + return com; + else + return 0; +} + +int +rs6000coff_core_file_failing_signal (abfd) + bfd *abfd; +{ + return core_hdr (abfd).c_signo; +} + + +boolean +rs6000coff_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + int count; +{ + if (count == 0) + return true; + + /* Reading a core file's sections will be slightly different. For the + rest of them we can use bfd_generic_get_section_contents () I suppose. */ + /* Make sure this routine works for any bfd and any section. FIXMEmgo. */ + + if (abfd->format == bfd_core && strcmp (section->name, ".reg") == 0) { + + struct mstsave mstatus; + int regoffset = (char*)&mstatus.gpr[0] - (char*)&mstatus; + + /* Assert that the only way this code will be executed is reading the + whole section. */ + if (offset || count != (sizeof(mstatus.gpr) + (4 * NUM_OF_SPEC_REGS))) + (*_bfd_error_handler) + ("ERROR! in rs6000coff_get_section_contents()\n"); + + /* for `.reg' section, `filepos' is a pointer to the `mstsave' structure + in the core file. */ + + /* read GPR's into the location. */ + if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 + || bfd_read(location, sizeof (mstatus.gpr), 1, abfd) != sizeof (mstatus.gpr)) + return (false); /* on error */ + + /* increment location to the beginning of special registers in the section, + reset register offset value to the beginning of first special register + in mstsave structure, and read special registers. */ + + location = (PTR) ((char*)location + sizeof (mstatus.gpr)); + regoffset = (char*)&mstatus.iar - (char*)&mstatus; + + if ( bfd_seek(abfd, section->filepos + regoffset, SEEK_SET) == -1 + || bfd_read(location, 4 * NUM_OF_SPEC_REGS, 1, abfd) != + 4 * NUM_OF_SPEC_REGS) + return (false); /* on error */ + + /* increment location address, and read the special registers.. */ + /* FIXMEmgo */ + return (true); + } + + /* else, use default bfd section content transfer. */ + else + return _bfd_generic_get_section_contents + (abfd, section, location, offset, count); +} + +#endif /* AIX_CORE */ diff --git a/contrib/gdb/bfd/section.c b/contrib/gdb/bfd/section.c new file mode 100644 index 000000000000..ac9a44912100 --- /dev/null +++ b/contrib/gdb/bfd/section.c @@ -0,0 +1,976 @@ +/* Object file "section" support for the BFD library. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Sections + + The raw data contained within a BFD is maintained through the + section abstraction. A single BFD may have any number of + sections. It keeps hold of them by pointing to the first; + each one points to the next in the list. + + Sections are supported in BFD in <>. + +@menu +@* Section Input:: +@* Section Output:: +@* typedef asection:: +@* section prototypes:: +@end menu + +INODE +Section Input, Section Output, Sections, Sections +SUBSECTION + Section input + + When a BFD is opened for reading, the section structures are + created and attached to the BFD. + + Each section has a name which describes the section in the + outside world---for example, <> would contain at least + three sections, called <<.text>>, <<.data>> and <<.bss>>. + + Names need not be unique; for example a COFF file may have several + sections named <<.data>>. + + Sometimes a BFD will contain more than the ``natural'' number of + sections. A back end may attach other sections containing + constructor data, or an application may add a section (using + <>) to the sections attached to an already open + BFD. For example, the linker creates an extra section + <> for each input file's BFD to hold information about + common storage. + + The raw data is not necessarily read in when + the section descriptor is created. Some targets may leave the + data in place until a <> call is + made. Other back ends may read in all the data at once. For + example, an S-record file has to be read once to determine the + size of the data. An IEEE-695 file doesn't contain raw data in + sections, but data and relocation expressions intermixed, so + the data area has to be parsed to get out the data and + relocations. + +INODE +Section Output, typedef asection, Section Input, Sections + +SUBSECTION + Section output + + To write a new object style BFD, the various sections to be + written have to be created. They are attached to the BFD in + the same way as input sections; data is written to the + sections using <>. + + Any program that creates or combines sections (e.g., the assembler + and linker) must use the <> fields <> and + <> to indicate the file sections to which each + section must be written. (If the section is being created from + scratch, <> should probably point to the section + itself and <> should probably be zero.) + + The data to be written comes from input sections attached + (via <> pointers) to + the output sections. The output section structure can be + considered a filter for the input section: the output section + determines the vma of the output data and the name, but the + input section determines the offset into the output section of + the data to be written. + + E.g., to create a section "O", starting at 0x100, 0x123 long, + containing two subsections, "A" at offset 0x0 (i.e., at vma + 0x100) and "B" at offset 0x20 (i.e., at vma 0x120) the <> + structures would look like: + +| section name "A" +| output_offset 0x00 +| size 0x20 +| output_section -----------> section name "O" +| | vma 0x100 +| section name "B" | size 0x123 +| output_offset 0x20 | +| size 0x103 | +| output_section --------| + + +SUBSECTION + Link orders + + The data within a section is stored in a @dfn{link_order}. + These are much like the fixups in <>. The link_order + abstraction allows a section to grow and shrink within itself. + + A link_order knows how big it is, and which is the next + link_order and where the raw data for it is; it also points to + a list of relocations which apply to it. + + The link_order is used by the linker to perform relaxing on + final code. The compiler creates code which is as big as + necessary to make it work without relaxing, and the user can + select whether to relax. Sometimes relaxing takes a lot of + time. The linker runs around the relocations to see if any + are attached to data which can be shrunk, if so it does it on + a link_order by link_order basis. + +*/ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +DOCDD +INODE +typedef asection, section prototypes, Section Output, Sections +SUBSECTION + typedef asection + + Here is the section structure: + +CODE_FRAGMENT +. +.typedef struct sec +.{ +. {* The name of the section; the name isn't a copy, the pointer is +. the same as that passed to bfd_make_section. *} +. +. CONST char *name; +. +. {* Which section is it; 0..nth. *} +. +. int index; +. +. {* The next section in the list belonging to the BFD, or NULL. *} +. +. struct sec *next; +. +. {* The field flags contains attributes of the section. Some +. flags are read in from the object file, and some are +. synthesized from other information. *} +. +. flagword flags; +. +.#define SEC_NO_FLAGS 0x000 +. +. {* Tells the OS to allocate space for this section when loading. +. This is clear for a section containing debug information +. only. *} +.#define SEC_ALLOC 0x001 +. +. {* Tells the OS to load the section from the file when loading. +. This is clear for a .bss section. *} +.#define SEC_LOAD 0x002 +. +. {* The section contains data still to be relocated, so there is +. some relocation information too. *} +.#define SEC_RELOC 0x004 +. +.#if 0 {* Obsolete ? *} +.#define SEC_BALIGN 0x008 +.#endif +. +. {* A signal to the OS that the section contains read only +. data. *} +.#define SEC_READONLY 0x010 +. +. {* The section contains code only. *} +.#define SEC_CODE 0x020 +. +. {* The section contains data only. *} +.#define SEC_DATA 0x040 +. +. {* The section will reside in ROM. *} +.#define SEC_ROM 0x080 +. +. {* The section contains constructor information. This section +. type is used by the linker to create lists of constructors and +. destructors used by <>. When a back end sees a symbol +. which should be used in a constructor list, it creates a new +. section for the type of name (e.g., <<__CTOR_LIST__>>), attaches +. the symbol to it, and builds a relocation. To build the lists +. of constructors, all the linker has to do is catenate all the +. sections called <<__CTOR_LIST__>> and relocate the data +. contained within - exactly the operations it would peform on +. standard data. *} +.#define SEC_CONSTRUCTOR 0x100 +. +. {* The section is a constuctor, and should be placed at the +. end of the text, data, or bss section(?). *} +.#define SEC_CONSTRUCTOR_TEXT 0x1100 +.#define SEC_CONSTRUCTOR_DATA 0x2100 +.#define SEC_CONSTRUCTOR_BSS 0x3100 +. +. {* The section has contents - a data section could be +. <> | <>; a debug section could be +. <> *} +.#define SEC_HAS_CONTENTS 0x200 +. +. {* An instruction to the linker to not output the section +. even if it has information which would normally be written. *} +.#define SEC_NEVER_LOAD 0x400 +. +. {* The section is a COFF shared library section. This flag is +. only for the linker. If this type of section appears in +. the input file, the linker must copy it to the output file +. without changing the vma or size. FIXME: Although this +. was originally intended to be general, it really is COFF +. specific (and the flag was renamed to indicate this). It +. might be cleaner to have some more general mechanism to +. allow the back end to control what the linker does with +. sections. *} +.#define SEC_COFF_SHARED_LIBRARY 0x800 +. +. {* The section is a common section (symbols may be defined +. multiple times, the value of a symbol is the amount of +. space it requires, and the largest symbol value is the one +. used). Most targets have exactly one of these (which we +. translate to bfd_com_section_ptr), but ECOFF has two. *} +.#define SEC_IS_COMMON 0x8000 +. +. {* The section contains only debugging information. For +. example, this is set for ELF .debug and .stab sections. +. strip tests this flag to see if a section can be +. discarded. *} +.#define SEC_DEBUGGING 0x10000 +. +. {* The contents of this section are held in memory pointed to +. by the contents field. This is checked by +. bfd_get_section_contents, and the data is retrieved from +. memory if appropriate. *} +.#define SEC_IN_MEMORY 0x20000 +. +. {* The contents of this section are to be excluded by the +. linker for executable and shared objects unless those +. objects are to be further relocated. *} +.#define SEC_EXCLUDE 0x40000 +. +. {* The contents of this section are to be sorted by the +. based on the address specified in the associated symbol +. table. *} +.#define SEC_SORT_ENTRIES 0x80000 +. +. {* End of section flags. *} +. +. {* The virtual memory address of the section - where it will be +. at run time. The symbols are relocated against this. The +. user_set_vma flag is maintained by bfd; if it's not set, the +. backend can assign addresses (for example, in <>, where +. the default address for <<.data>> is dependent on the specific +. target and various flags). *} +. +. bfd_vma vma; +. boolean user_set_vma; +. +. {* The load address of the section - where it would be in a +. rom image; really only used for writing section header +. information. *} +. +. bfd_vma lma; +. +. {* The size of the section in bytes, as it will be output. +. contains a value even if the section has no contents (e.g., the +. size of <<.bss>>). This will be filled in after relocation *} +. +. bfd_size_type _cooked_size; +. +. {* The original size on disk of the section, in bytes. Normally this +. value is the same as the size, but if some relaxing has +. been done, then this value will be bigger. *} +. +. bfd_size_type _raw_size; +. +. {* If this section is going to be output, then this value is the +. offset into the output section of the first byte in the input +. section. E.g., if this was going to start at the 100th byte in +. the output section, this value would be 100. *} +. +. bfd_vma output_offset; +. +. {* The output section through which to map on output. *} +. +. struct sec *output_section; +. +. {* The alignment requirement of the section, as an exponent of 2 - +. e.g., 3 aligns to 2^3 (or 8). *} +. +. unsigned int alignment_power; +. +. {* If an input section, a pointer to a vector of relocation +. records for the data in this section. *} +. +. struct reloc_cache_entry *relocation; +. +. {* If an output section, a pointer to a vector of pointers to +. relocation records for the data in this section. *} +. +. struct reloc_cache_entry **orelocation; +. +. {* The number of relocation records in one of the above *} +. +. unsigned reloc_count; +. +. {* Information below is back end specific - and not always used +. or updated. *} +. +. {* File position of section data *} +. +. file_ptr filepos; +. +. {* File position of relocation info *} +. +. file_ptr rel_filepos; +. +. {* File position of line data *} +. +. file_ptr line_filepos; +. +. {* Pointer to data for applications *} +. +. PTR userdata; +. +. {* If the SEC_IN_MEMORY flag is set, this points to the actual +. contents. *} +. unsigned char *contents; +. +. {* Attached line number information *} +. +. alent *lineno; +. +. {* Number of line number records *} +. +. unsigned int lineno_count; +. +. {* When a section is being output, this value changes as more +. linenumbers are written out *} +. +. file_ptr moving_line_filepos; +. +. {* What the section number is in the target world *} +. +. int target_index; +. +. PTR used_by_bfd; +. +. {* If this is a constructor section then here is a list of the +. relocations created to relocate items within it. *} +. +. struct relent_chain *constructor_chain; +. +. {* The BFD which owns the section. *} +. +. bfd *owner; +. +. boolean reloc_done; +. {* A symbol which points at this section only *} +. struct symbol_cache_entry *symbol; +. struct symbol_cache_entry **symbol_ptr_ptr; +. +. struct bfd_link_order *link_order_head; +. struct bfd_link_order *link_order_tail; +.} asection ; +. +. {* 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. *} +.#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 const 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 const 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 const asection bfd_com_section; +.#define bfd_com_section_ptr ((asection *) &bfd_com_section) +. {* Pointer to the indirect section *} +.extern const asection bfd_ind_section; +.#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +.#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) +. +.extern const struct symbol_cache_entry * const bfd_abs_symbol; +.extern const struct symbol_cache_entry * const bfd_com_symbol; +.extern const struct symbol_cache_entry * const bfd_und_symbol; +.extern const struct symbol_cache_entry * const bfd_ind_symbol; +.#define bfd_get_section_size_before_reloc(section) \ +. (section->reloc_done ? (abort(),1): (section)->_raw_size) +.#define bfd_get_section_size_after_reloc(section) \ +. ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +*/ + +/* These symbols are global, not specific to any BFD. Therefore, anything + that tries to change them is broken, and should be repaired. */ +static const asymbol global_syms[] = +{ + /* the_bfd, name, value, attr, section [, udata] */ + {0, BFD_COM_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_com_section}, + {0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_und_section}, + {0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_abs_section}, + {0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, (asection *) &bfd_ind_section}, +}; + +#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ + const asymbol * const SYM = (asymbol *) &global_syms[IDX]; \ + const asection SEC = \ + { NAME, 0, 0, FLAGS, 0, false, 0, 0, 0, 0, (asection *) &SEC, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \ + (asymbol *) &global_syms[IDX], (asymbol **) &SYM, } + +STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol, + BFD_COM_SECTION_NAME, 0); +STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1); +STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2); +STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3); +#undef STD_SECTION + +/* +DOCDD +INODE +section prototypes, , typedef asection, Sections +SUBSECTION + Section prototypes + +These are the functions exported by the section handling part of BFD. +*/ + +/* +FUNCTION + bfd_get_section_by_name + +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. +*/ + +asection * +bfd_get_section_by_name (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *sect; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + if (!strcmp (sect->name, name)) + return sect; + return NULL; +} + + +/* +FUNCTION + bfd_make_section_old_way + +SYNOPSIS + asection *bfd_make_section_old_way(bfd *abfd, CONST char *name); + +DESCRIPTION + Create a new empty section called @var{name} + and attach it to the end of the chain of sections for the + BFD @var{abfd}. An attempt to create a section with a name which + is already in use returns its pointer without changing the + section chain. + + It has the funny name since this is the way it used to be + before it was rewritten.... + + Possible errors are: + o <> - + If output has already started for this BFD. + o <> - + If obstack alloc fails. + +*/ + + +asection * +bfd_make_section_old_way (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *sec = bfd_get_section_by_name (abfd, name); + if (sec == (asection *) NULL) + { + sec = bfd_make_section (abfd, name); + } + return sec; +} + +/* +FUNCTION + bfd_make_section_anyway + +SYNOPSIS + asection *bfd_make_section_anyway(bfd *abfd, CONST char *name); + +DESCRIPTION + Create a new empty section called @var{name} and attach it to the end of + the chain of sections for @var{abfd}. Create a new section even if there + is already a section with that name. + + Return <> and set <> on error; possible errors are: + o <> - If output has already started for @var{abfd}. + o <> - If obstack alloc fails. +*/ + +sec_ptr +bfd_make_section_anyway (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *newsect; + asection **prev = &abfd->sections; + asection *sect = abfd->sections; + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + while (sect) + { + prev = §->next; + sect = sect->next; + } + + newsect = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (newsect == NULL) + return NULL; + + newsect->name = name; + newsect->index = abfd->section_count++; + newsect->flags = SEC_NO_FLAGS; + + newsect->userdata = NULL; + newsect->contents = NULL; + newsect->next = (asection *) NULL; + newsect->relocation = (arelent *) NULL; + newsect->reloc_count = 0; + newsect->line_filepos = 0; + newsect->owner = abfd; + + /* Create a symbol whos only job is to point to this section. This is + useful for things like relocs which are relative to the base of a + section. */ + newsect->symbol = bfd_make_empty_symbol (abfd); + if (newsect->symbol == NULL) + return NULL; + newsect->symbol->name = name; + newsect->symbol->value = 0; + newsect->symbol->section = newsect; + newsect->symbol->flags = BSF_SECTION_SYM; + + newsect->symbol_ptr_ptr = &newsect->symbol; + + if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) + { + free (newsect); + return NULL; + } + + *prev = newsect; + return newsect; +} + +/* +FUNCTION + bfd_make_section + +SYNOPSIS + asection *bfd_make_section(bfd *, CONST char *name); + +DESCRIPTION + Like <>, but return <> (without calling + bfd_set_error ()) without changing the section chain if there is already a + section named @var{name}. If there is an error, return <> and set + <>. +*/ + +asection * +bfd_make_section (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *sect = abfd->sections; + + if (strcmp (name, BFD_ABS_SECTION_NAME) == 0) + { + return bfd_abs_section_ptr; + } + if (strcmp (name, BFD_COM_SECTION_NAME) == 0) + { + return bfd_com_section_ptr; + } + if (strcmp (name, BFD_UND_SECTION_NAME) == 0) + { + return bfd_und_section_ptr; + } + + if (strcmp (name, BFD_IND_SECTION_NAME) == 0) + { + return bfd_ind_section_ptr; + } + + while (sect) + { + if (!strcmp (sect->name, name)) + return NULL; + sect = sect->next; + } + + /* The name is not already used; go ahead and make a new section. */ + return bfd_make_section_anyway (abfd, name); +} + + +/* +FUNCTION + bfd_set_section_flags + +SYNOPSIS + boolean bfd_set_section_flags(bfd *abfd, asection *sec, flagword flags); + +DESCRIPTION + Set the attributes of the section @var{sec} in the BFD + @var{abfd} to the value @var{flags}. Return <> on success, + <> on error. Possible error returns are: + + o <> - + The section cannot have one or more of the attributes + requested. For example, a .bss section in <> may not + have the <> field set. + +*/ + +/*ARGSUSED*/ +boolean +bfd_set_section_flags (abfd, section, flags) + bfd *abfd; + sec_ptr section; + flagword flags; +{ +#if 0 + /* If you try to copy a text section from an input file (where it + has the SEC_CODE flag set) to an output file, this loses big if + the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE + set - which it doesn't, at least not for a.out. FIXME */ + + if ((flags & bfd_applicable_section_flags (abfd)) != flags) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } +#endif + + section->flags = flags; + return true; +} + + +/* +FUNCTION + bfd_map_over_sections + +SYNOPSIS + void bfd_map_over_sections(bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj); + +DESCRIPTION + Call the provided function @var{func} for each section + attached to the BFD @var{abfd}, passing @var{obj} as an + argument. The function will be called as if by + +| func(abfd, the_section, obj); + + This is the prefered method for iterating over sections; an + alternative would be to use a loop: + +| section *p; +| for (p = abfd->sections; p != NULL; p = p->next) +| func(abfd, p, ...) + + +*/ + +/*VARARGS2*/ +void +bfd_map_over_sections (abfd, operation, user_storage) + bfd *abfd; + void (*operation) PARAMS ((bfd * abfd, asection * sect, PTR obj)); + PTR user_storage; +{ + asection *sect; + unsigned int i = 0; + + for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) + (*operation) (abfd, sect, user_storage); + + if (i != abfd->section_count) /* Debugging */ + abort (); +} + + +/* +FUNCTION + bfd_set_section_size + +SYNOPSIS + boolean bfd_set_section_size(bfd *abfd, asection *sec, bfd_size_type val); + +DESCRIPTION + Set @var{sec} to the size @var{val}. If the operation is + ok, then <> is returned, else <>. + + Possible error returns: + o <> - + Writing has started to the BFD, so setting the size is invalid. + +*/ + +boolean +bfd_set_section_size (abfd, ptr, val) + bfd *abfd; + sec_ptr ptr; + bfd_size_type val; +{ + /* Once you've started writing to any section you cannot create or change + the size of any others. */ + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + ptr->_cooked_size = val; + ptr->_raw_size = val; + + return true; +} + +/* +FUNCTION + bfd_set_section_contents + +SYNOPSIS + boolean bfd_set_section_contents + (bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count); + + +DESCRIPTION + Sets the contents of the section @var{section} in BFD + @var{abfd} to the data starting in memory at @var{data}. The + data is written to the output section starting at offset + @var{offset} for @var{count} bytes. + + + + Normally <> is returned, else <>. Possible error + returns are: + o <> - + The output section does not have the <> + attribute, so nothing can be written to it. + o and some more too + + This routine is front end to the back end function + <<_bfd_set_section_contents>>. + + +*/ + +#define bfd_get_section_size_now(abfd,sec) \ +(sec->reloc_done \ + ? bfd_get_section_size_after_reloc (sec) \ + : bfd_get_section_size_before_reloc (sec)) + +boolean +bfd_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + bfd_size_type sz; + + if (!(bfd_get_section_flags (abfd, section) & SEC_HAS_CONTENTS)) + { + bfd_set_error (bfd_error_no_contents); + return (false); + } + + if (offset < 0) + { + bad_val: + bfd_set_error (bfd_error_bad_value); + return false; + } + sz = bfd_get_section_size_now (abfd, section); + if ((bfd_size_type) offset > sz + || count > sz + || offset + count > sz) + goto bad_val; + + switch (abfd->direction) + { + case read_direction: + case no_direction: + bfd_set_error (bfd_error_invalid_operation); + return false; + + case write_direction: + break; + + case both_direction: + /* File is opened for update. `output_has_begun' some time ago when + the file was created. Do not recompute sections sizes or alignments + in _bfd_set_section_content. */ + abfd->output_has_begun = true; + break; + } + + if (BFD_SEND (abfd, _bfd_set_section_contents, + (abfd, section, location, offset, count))) + { + abfd->output_has_begun = true; + return true; + } + + return false; +} + +/* +FUNCTION + bfd_get_section_contents + +SYNOPSIS + boolean bfd_get_section_contents + (bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count); + +DESCRIPTION + Read data from @var{section} in BFD @var{abfd} + into memory starting at @var{location}. The data is read at an + offset of @var{offset} from the start of the input section, + and is read for @var{count} bytes. + + If the contents of a constructor with the <> + flag set are requested or if the section does not have the + <> flag set, then the @var{location} is filled + with zeroes. If no errors occur, <> is returned, else + <>. + + + +*/ +boolean +bfd_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + bfd_size_type sz; + + if (section->flags & SEC_CONSTRUCTOR) + { + memset (location, 0, (unsigned) count); + return true; + } + + if (offset < 0) + { + bad_val: + bfd_set_error (bfd_error_bad_value); + return false; + } + /* Even if reloc_done is true, this function reads unrelocated + contents, so we want the raw size. */ + sz = section->_raw_size; + if ((bfd_size_type) offset > sz || count > sz || offset + count > sz) + goto bad_val; + + if (count == 0) + /* Don't bother. */ + return true; + + if ((section->flags & SEC_HAS_CONTENTS) == 0) + { + memset (location, 0, (unsigned) count); + return true; + } + + if ((section->flags & SEC_IN_MEMORY) != 0) + { + memcpy (location, section->contents + offset, (size_t) count); + return true; + } + + return BFD_SEND (abfd, _bfd_get_section_contents, + (abfd, section, location, offset, count)); +} + +/* +FUNCTION + bfd_copy_private_section_data + +SYNOPSIS + boolean bfd_copy_private_section_data(bfd *ibfd, asection *isec, bfd *obfd, asection *osec); + +DESCRIPTION + Copy private section information from @var{isec} in the BFD + @var{ibfd} to the section @var{osec} in the BFD @var{obfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{osec}. + +.#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ +. BFD_SEND (ibfd, _bfd_copy_private_section_data, \ +. (ibfd, isection, obfd, osection)) +*/ diff --git a/contrib/gdb/bfd/som.c b/contrib/gdb/bfd/som.c new file mode 100644 index 000000000000..dd03d99ee199 --- /dev/null +++ b/contrib/gdb/bfd/som.c @@ -0,0 +1,5999 @@ +/* bfd back-end for HP PA-RISC SOM objects. + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) + +#include "libbfd.h" +#include "som.h" + +#include +#include +#include +#include +#include +#include +#include + +/* Magic not defined in standard HP-UX header files until 8.0 */ + +#ifndef CPU_PA_RISC1_0 +#define CPU_PA_RISC1_0 0x20B +#endif /* CPU_PA_RISC1_0 */ + +#ifndef CPU_PA_RISC1_1 +#define CPU_PA_RISC1_1 0x210 +#endif /* CPU_PA_RISC1_1 */ + +#ifndef _PA_RISC1_0_ID +#define _PA_RISC1_0_ID CPU_PA_RISC1_0 +#endif /* _PA_RISC1_0_ID */ + +#ifndef _PA_RISC1_1_ID +#define _PA_RISC1_1_ID CPU_PA_RISC1_1 +#endif /* _PA_RISC1_1_ID */ + +#ifndef _PA_RISC_MAXID +#define _PA_RISC_MAXID 0x2FF +#endif /* _PA_RISC_MAXID */ + +#ifndef _PA_RISC_ID +#define _PA_RISC_ID(__m_num) \ + (((__m_num) == _PA_RISC1_0_ID) || \ + ((__m_num) >= _PA_RISC1_1_ID && (__m_num) <= _PA_RISC_MAXID)) +#endif /* _PA_RISC_ID */ + + +/* HIUX in it's infinite stupidity changed the names for several "well + known" constants. Work around such braindamage. Try the HPUX version + first, then the HIUX version, and finally provide a default. */ +#ifdef HPUX_AUX_ID +#define EXEC_AUX_ID HPUX_AUX_ID +#endif + +#if !defined (EXEC_AUX_ID) && defined (HIUX_AUX_ID) +#define EXEC_AUX_ID HIUX_AUX_ID +#endif + +#ifndef EXEC_AUX_ID +#define EXEC_AUX_ID 0 +#endif + +/* Size (in chars) of the temporary buffers used during fixup and string + table writes. */ + +#define SOM_TMP_BUFSIZE 8192 + +/* Size of the hash table in archives. */ +#define SOM_LST_HASH_SIZE 31 + +/* Max number of SOMs to be found in an archive. */ +#define SOM_LST_MODULE_LIMIT 1024 + +/* Generic alignment macro. */ +#define SOM_ALIGN(val, alignment) \ + (((val) + (alignment) - 1) & ~((alignment) - 1)) + +/* SOM allows any one of the four previous relocations to be reused + with a "R_PREV_FIXUP" relocation entry. Since R_PREV_FIXUP + relocations are always a single byte, using a R_PREV_FIXUP instead + of some multi-byte relocation makes object files smaller. + + Note one side effect of using a R_PREV_FIXUP is the relocation that + is being repeated moves to the front of the queue. */ +struct reloc_queue + { + unsigned char *reloc; + unsigned int size; + } reloc_queue[4]; + +/* This fully describes the symbol types which may be attached to + an EXPORT or IMPORT directive. Only SOM uses this formation + (ELF has no need for it). */ +typedef enum +{ + SYMBOL_TYPE_UNKNOWN, + SYMBOL_TYPE_ABSOLUTE, + SYMBOL_TYPE_CODE, + SYMBOL_TYPE_DATA, + SYMBOL_TYPE_ENTRY, + SYMBOL_TYPE_MILLICODE, + SYMBOL_TYPE_PLABEL, + SYMBOL_TYPE_PRI_PROG, + SYMBOL_TYPE_SEC_PROG, +} pa_symbol_type; + +struct section_to_type +{ + char *section; + char type; +}; + +/* Assorted symbol information that needs to be derived from the BFD symbol + and/or the BFD backend private symbol data. */ +struct som_misc_symbol_info +{ + unsigned int symbol_type; + unsigned int symbol_scope; + unsigned int arg_reloc; + unsigned int symbol_info; + unsigned int symbol_value; +}; + +/* Forward declarations */ + +static boolean som_mkobject PARAMS ((bfd *)); +static const bfd_target * som_object_setup PARAMS ((bfd *, + struct header *, + struct som_exec_auxhdr *)); +static boolean setup_sections PARAMS ((bfd *, struct header *)); +static const bfd_target * som_object_p PARAMS ((bfd *)); +static boolean som_write_object_contents PARAMS ((bfd *)); +static boolean som_slurp_string_table PARAMS ((bfd *)); +static unsigned int som_slurp_symbol_table PARAMS ((bfd *)); +static long som_get_symtab_upper_bound PARAMS ((bfd *)); +static long som_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, asymbol **)); +static long som_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +static unsigned int som_set_reloc_info PARAMS ((unsigned char *, unsigned int, + arelent *, asection *, + asymbol **, boolean)); +static boolean som_slurp_reloc_table PARAMS ((bfd *, asection *, + asymbol **, boolean)); +static long som_get_symtab PARAMS ((bfd *, asymbol **)); +static asymbol * som_make_empty_symbol PARAMS ((bfd *)); +static void som_print_symbol PARAMS ((bfd *, PTR, + asymbol *, bfd_print_symbol_type)); +static boolean som_new_section_hook PARAMS ((bfd *, asection *)); +static boolean som_bfd_copy_private_symbol_data PARAMS ((bfd *, asymbol *, + bfd *, asymbol *)); +static boolean som_bfd_copy_private_section_data PARAMS ((bfd *, asection *, + bfd *, asection *)); +static boolean som_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *)); +#define som_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data +#define som_bfd_set_private_flags _bfd_generic_bfd_set_private_flags +static boolean som_bfd_is_local_label PARAMS ((bfd *, asymbol *)); +static boolean som_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); +static boolean som_get_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); +static boolean som_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +static boolean som_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, bfd_vma, + CONST char **, + CONST char **, + unsigned int *)); +static void som_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); +static asection * bfd_section_from_som_symbol PARAMS ((bfd *, + struct symbol_dictionary_record *)); +static int log2 PARAMS ((unsigned int)); +static bfd_reloc_status_type hppa_som_reloc PARAMS ((bfd *, arelent *, + asymbol *, PTR, + asection *, bfd *, + char **)); +static void som_initialize_reloc_queue PARAMS ((struct reloc_queue *)); +static void som_reloc_queue_insert PARAMS ((unsigned char *, unsigned int, + struct reloc_queue *)); +static void som_reloc_queue_fix PARAMS ((struct reloc_queue *, unsigned int)); +static int som_reloc_queue_find PARAMS ((unsigned char *, unsigned int, + struct reloc_queue *)); +static unsigned char * try_prev_fixup PARAMS ((bfd *, int *, unsigned char *, + unsigned int, + struct reloc_queue *)); + +static unsigned char * som_reloc_skip PARAMS ((bfd *, unsigned int, + unsigned char *, unsigned int *, + struct reloc_queue *)); +static unsigned char * som_reloc_addend PARAMS ((bfd *, int, unsigned char *, + unsigned int *, + struct reloc_queue *)); +static unsigned char * som_reloc_call PARAMS ((bfd *, unsigned char *, + unsigned int *, + arelent *, int, + struct reloc_queue *)); +static unsigned long som_count_spaces PARAMS ((bfd *)); +static unsigned long som_count_subspaces PARAMS ((bfd *)); +static int compare_syms PARAMS ((const void *, const void *)); +static int compare_subspaces PARAMS ((const void *, const void *)); +static unsigned long som_compute_checksum PARAMS ((bfd *)); +static boolean som_prep_headers PARAMS ((bfd *)); +static int som_sizeof_headers PARAMS ((bfd *, boolean)); +static boolean som_finish_writing PARAMS ((bfd *)); +static boolean som_build_and_write_symbol_table PARAMS ((bfd *)); +static void som_prep_for_fixups PARAMS ((bfd *, asymbol **, unsigned long)); +static boolean som_write_fixups PARAMS ((bfd *, unsigned long, unsigned int *)); +static boolean som_write_space_strings PARAMS ((bfd *, unsigned long, + unsigned int *)); +static boolean som_write_symbol_strings PARAMS ((bfd *, unsigned long, + asymbol **, unsigned int, + unsigned *)); +static boolean som_begin_writing PARAMS ((bfd *)); +static reloc_howto_type * som_bfd_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static char som_section_type PARAMS ((const char *)); +static int som_decode_symclass PARAMS ((asymbol *)); +static boolean som_bfd_count_ar_symbols PARAMS ((bfd *, struct lst_header *, + symindex *)); + +static boolean som_bfd_fill_in_ar_symbols PARAMS ((bfd *, struct lst_header *, + carsym **syms)); +static boolean som_slurp_armap PARAMS ((bfd *)); +static boolean som_write_armap PARAMS ((bfd *, unsigned int, struct orl *, + unsigned int, int)); +static void som_bfd_derive_misc_symbol_info PARAMS ((bfd *, asymbol *, + struct som_misc_symbol_info *)); +static boolean som_bfd_prep_for_ar_write PARAMS ((bfd *, unsigned int *, + unsigned int *)); +static unsigned int som_bfd_ar_symbol_hash PARAMS ((asymbol *)); +static boolean som_bfd_ar_write_symbol_stuff PARAMS ((bfd *, unsigned int, + unsigned int, + struct lst_header)); +static CONST char *normalize PARAMS ((CONST char *file)); +static boolean som_is_space PARAMS ((asection *)); +static boolean som_is_subspace PARAMS ((asection *)); +static boolean som_is_container PARAMS ((asection *, asection *)); +static boolean som_bfd_free_cached_info PARAMS ((bfd *)); +static boolean som_bfd_link_split_section PARAMS ((bfd *, asection *)); + +/* Map SOM section names to POSIX/BSD single-character symbol types. + + This table includes all the standard subspaces as defined in the + current "PRO ABI for PA-RISC Systems", $UNWIND$ which for + some reason was left out, and sections specific to embedded stabs. */ + +static const struct section_to_type stt[] = { + {"$TEXT$", 't'}, + {"$SHLIB_INFO$", 't'}, + {"$MILLICODE$", 't'}, + {"$LIT$", 't'}, + {"$CODE$", 't'}, + {"$UNWIND_START$", 't'}, + {"$UNWIND$", 't'}, + {"$PRIVATE$", 'd'}, + {"$PLT$", 'd'}, + {"$SHLIB_DATA$", 'd'}, + {"$DATA$", 'd'}, + {"$SHORTDATA$", 'g'}, + {"$DLT$", 'd'}, + {"$GLOBAL$", 'g'}, + {"$SHORTBSS$", 's'}, + {"$BSS$", 'b'}, + {"$GDB_STRINGS$", 'N'}, + {"$GDB_SYMBOLS$", 'N'}, + {0, 0} +}; + +/* About the relocation formatting table... + + There are 256 entries in the table, one for each possible + relocation opcode available in SOM. We index the table by + the relocation opcode. The names and operations are those + defined by a.out_800 (4). + + Right now this table is only used to count and perform minimal + processing on relocation streams so that they can be internalized + into BFD and symbolically printed by utilities. To make actual use + of them would be much more difficult, BFD's concept of relocations + is far too simple to handle SOM relocations. The basic assumption + that a relocation can be completely processed independent of other + relocations before an object file is written is invalid for SOM. + + The SOM relocations are meant to be processed as a stream, they + specify copying of data from the input section to the output section + while possibly modifying the data in some manner. They also can + specify that a variable number of zeros or uninitialized data be + inserted on in the output segment at the current offset. Some + relocations specify that some previous relocation be re-applied at + the current location in the input/output sections. And finally a number + of relocations have effects on other sections (R_ENTRY, R_EXIT, + R_UNWIND_AUX and a variety of others). There isn't even enough room + in the BFD relocation data structure to store enough information to + perform all the relocations. + + Each entry in the table has three fields. + + The first entry is an index into this "class" of relocations. This + index can then be used as a variable within the relocation itself. + + The second field is a format string which actually controls processing + of the relocation. It uses a simple postfix machine to do calculations + based on variables/constants found in the string and the relocation + stream. + + The third field specifys whether or not this relocation may use + a constant (V) from the previous R_DATA_OVERRIDE rather than a constant + stored in the instruction. + + Variables: + + L = input space byte count + D = index into class of relocations + M = output space byte count + N = statement number (unused?) + O = stack operation + R = parameter relocation bits + S = symbol index + T = first 32 bits of stack unwind information + U = second 32 bits of stack unwind information + V = a literal constant (usually used in the next relocation) + P = a previous relocation + + Lower case letters (starting with 'b') refer to following + bytes in the relocation stream. 'b' is the next 1 byte, + c is the next 2 bytes, d is the next 3 bytes, etc... + This is the variable part of the relocation entries that + makes our life a living hell. + + numerical constants are also used in the format string. Note + the constants are represented in decimal. + + '+', "*" and "=" represents the obvious postfix operators. + '<' represents a left shift. + + Stack Operations: + + Parameter Relocation Bits: + + Unwind Entries: + + Previous Relocations: The index field represents which in the queue + of 4 previous fixups should be re-applied. + + Literal Constants: These are generally used to represent addend + parts of relocations when these constants are not stored in the + fields of the instructions themselves. For example the instruction + addil foo-$global$-0x1234 would use an override for "0x1234" rather + than storing it into the addil itself. */ + +struct fixup_format +{ + int D; + char *format; +}; + +static const struct fixup_format som_fixup_formats[256] = +{ + /* R_NO_RELOCATION */ + 0, "LD1+4*=", /* 0x00 */ + 1, "LD1+4*=", /* 0x01 */ + 2, "LD1+4*=", /* 0x02 */ + 3, "LD1+4*=", /* 0x03 */ + 4, "LD1+4*=", /* 0x04 */ + 5, "LD1+4*=", /* 0x05 */ + 6, "LD1+4*=", /* 0x06 */ + 7, "LD1+4*=", /* 0x07 */ + 8, "LD1+4*=", /* 0x08 */ + 9, "LD1+4*=", /* 0x09 */ + 10, "LD1+4*=", /* 0x0a */ + 11, "LD1+4*=", /* 0x0b */ + 12, "LD1+4*=", /* 0x0c */ + 13, "LD1+4*=", /* 0x0d */ + 14, "LD1+4*=", /* 0x0e */ + 15, "LD1+4*=", /* 0x0f */ + 16, "LD1+4*=", /* 0x10 */ + 17, "LD1+4*=", /* 0x11 */ + 18, "LD1+4*=", /* 0x12 */ + 19, "LD1+4*=", /* 0x13 */ + 20, "LD1+4*=", /* 0x14 */ + 21, "LD1+4*=", /* 0x15 */ + 22, "LD1+4*=", /* 0x16 */ + 23, "LD1+4*=", /* 0x17 */ + 0, "LD8= 0x1000000) + { + skip -= 0x1000000; + bfd_put_8 (abfd, R_NO_RELOCATION + 31, p); + bfd_put_8 (abfd, 0xff, p + 1); + bfd_put_16 (abfd, 0xffff, p + 2); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue); + while (skip >= 0x1000000) + { + skip -= 0x1000000; + bfd_put_8 (abfd, R_PREV_FIXUP, p); + p++; + *subspace_reloc_sizep += 1; + /* No need to adjust queue here since we are repeating the + most recent fixup. */ + } + } + + /* The difference must be less than 0x1000000. Use one + more R_NO_RELOCATION entry to get to the right difference. */ + if ((skip & 3) == 0 && skip <= 0xc0000 && skip > 0) + { + /* Difference can be handled in a simple single-byte + R_NO_RELOCATION entry. */ + if (skip <= 0x60) + { + bfd_put_8 (abfd, R_NO_RELOCATION + (skip >> 2) - 1, p); + *subspace_reloc_sizep += 1; + p++; + } + /* Handle it with a two byte R_NO_RELOCATION entry. */ + else if (skip <= 0x1000) + { + bfd_put_8 (abfd, R_NO_RELOCATION + 24 + (((skip >> 2) - 1) >> 8), p); + bfd_put_8 (abfd, (skip >> 2) - 1, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue); + } + /* Handle it with a three byte R_NO_RELOCATION entry. */ + else + { + bfd_put_8 (abfd, R_NO_RELOCATION + 28 + (((skip >> 2) - 1) >> 16), p); + bfd_put_16 (abfd, (skip >> 2) - 1, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue); + } + } + /* Ugh. Punt and use a 4 byte entry. */ + else if (skip > 0) + { + bfd_put_8 (abfd, R_NO_RELOCATION + 31, p); + bfd_put_8 (abfd, (skip - 1) >> 16, p + 1); + bfd_put_16 (abfd, skip - 1, p + 2); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue); + } + return p; +} + +/* Emit the proper R_DATA_OVERRIDE fixups to handle a nonzero addend + from a BFD relocation. Update the size of the subspace relocation + stream via SUBSPACE_RELOC_SIZE_P; also return the current pointer + into the relocation stream. */ + +static unsigned char * +som_reloc_addend (abfd, addend, p, subspace_reloc_sizep, queue) + bfd *abfd; + int addend; + unsigned char *p; + unsigned int *subspace_reloc_sizep; + struct reloc_queue *queue; +{ + if ((unsigned)(addend) + 0x80 < 0x100) + { + bfd_put_8 (abfd, R_DATA_OVERRIDE + 1, p); + bfd_put_8 (abfd, addend, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue); + } + else if ((unsigned) (addend) + 0x8000 < 0x10000) + { + bfd_put_8 (abfd, R_DATA_OVERRIDE + 2, p); + bfd_put_16 (abfd, addend, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue); + } + else if ((unsigned) (addend) + 0x800000 < 0x1000000) + { + bfd_put_8 (abfd, R_DATA_OVERRIDE + 3, p); + bfd_put_8 (abfd, addend >> 16, p + 1); + bfd_put_16 (abfd, addend, p + 2); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 4, queue); + } + else + { + bfd_put_8 (abfd, R_DATA_OVERRIDE + 4, p); + bfd_put_32 (abfd, addend, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 5, queue); + } + return p; +} + +/* Handle a single function call relocation. */ + +static unsigned char * +som_reloc_call (abfd, p, subspace_reloc_sizep, bfd_reloc, sym_num, queue) + bfd *abfd; + unsigned char *p; + unsigned int *subspace_reloc_sizep; + arelent *bfd_reloc; + int sym_num; + struct reloc_queue *queue; +{ + int arg_bits = HPPA_R_ARG_RELOC (bfd_reloc->addend); + int rtn_bits = arg_bits & 0x3; + int type, done = 0; + + /* You'll never believe all this is necessary to handle relocations + for function calls. Having to compute and pack the argument + relocation bits is the real nightmare. + + If you're interested in how this works, just forget it. You really + do not want to know about this braindamage. */ + + /* First see if this can be done with a "simple" relocation. Simple + relocations have a symbol number < 0x100 and have simple encodings + of argument relocations. */ + + if (sym_num < 0x100) + { + switch (arg_bits) + { + case 0: + case 1: + type = 0; + break; + case 1 << 8: + case 1 << 8 | 1: + type = 1; + break; + case 1 << 8 | 1 << 6: + case 1 << 8 | 1 << 6 | 1: + type = 2; + break; + case 1 << 8 | 1 << 6 | 1 << 4: + case 1 << 8 | 1 << 6 | 1 << 4 | 1: + type = 3; + break; + case 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2: + case 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2 | 1: + type = 4; + break; + default: + /* Not one of the easy encodings. This will have to be + handled by the more complex code below. */ + type = -1; + break; + } + if (type != -1) + { + /* Account for the return value too. */ + if (rtn_bits) + type += 5; + + /* Emit a 2 byte relocation. Then see if it can be handled + with a relocation which is already in the relocation queue. */ + bfd_put_8 (abfd, bfd_reloc->howto->type + type, p); + bfd_put_8 (abfd, sym_num, p + 1); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 2, queue); + done = 1; + } + } + + /* If this could not be handled with a simple relocation, then do a hard + one. Hard relocations occur if the symbol number was too high or if + the encoding of argument relocation bits is too complex. */ + if (! done) + { + /* Don't ask about these magic sequences. I took them straight + from gas-1.36 which took them from the a.out man page. */ + type = rtn_bits; + if ((arg_bits >> 6 & 0xf) == 0xe) + type += 9 * 40; + else + type += (3 * (arg_bits >> 8 & 3) + (arg_bits >> 6 & 3)) * 40; + if ((arg_bits >> 2 & 0xf) == 0xe) + type += 9 * 4; + else + type += (3 * (arg_bits >> 4 & 3) + (arg_bits >> 2 & 3)) * 4; + + /* Output the first two bytes of the relocation. These describe + the length of the relocation and encoding style. */ + bfd_put_8 (abfd, bfd_reloc->howto->type + 10 + + 2 * (sym_num >= 0x100) + (type >= 0x100), + p); + bfd_put_8 (abfd, type, p + 1); + + /* Now output the symbol index and see if this bizarre relocation + just happened to be in the relocation queue. */ + if (sym_num < 0x100) + { + bfd_put_8 (abfd, sym_num, p + 2); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 3, queue); + } + else + { + bfd_put_8 (abfd, sym_num >> 16, p + 2); + bfd_put_16 (abfd, sym_num, p + 3); + p = try_prev_fixup (abfd, subspace_reloc_sizep, p, 5, queue); + } + } + return p; +} + + +/* Return the logarithm of X, base 2, considering X unsigned. + Abort -1 if X is not a power or two or is zero. */ + +static int +log2 (x) + unsigned int x; +{ + int log = 0; + + /* Test for 0 or a power of 2. */ + if (x == 0 || x != (x & -x)) + return -1; + + while ((x >>= 1) != 0) + log++; + return log; +} + +static bfd_reloc_status_type +hppa_som_reloc (abfd, reloc_entry, symbol_in, data, + input_section, output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + if (output_bfd) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + return bfd_reloc_ok; +} + +/* Given a generic HPPA relocation type, the instruction format, + and a field selector, return one or more appropriate SOM relocations. */ + +int ** +hppa_som_gen_reloc_type (abfd, base_type, format, field, sym_diff) + bfd *abfd; + int base_type; + int format; + enum hppa_reloc_field_selector_type_alt field; + int sym_diff; +{ + int *final_type, **final_types; + + final_types = (int **) bfd_alloc_by_size_t (abfd, sizeof (int *) * 6); + final_type = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types || !final_type) + return NULL; + + /* The field selector may require additional relocations to be + generated. It's impossible to know at this moment if additional + relocations will be needed, so we make them. The code to actually + write the relocation/fixup stream is responsible for removing + any redundant relocations. */ + switch (field) + { + case e_fsel: + case e_psel: + case e_lpsel: + case e_rpsel: + final_types[0] = final_type; + final_types[1] = NULL; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_tsel: + case e_ltsel: + case e_rtsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + if (field == e_tsel) + *final_types[0] = R_FSEL; + else if (field == e_ltsel) + *final_types[0] = R_LSEL; + else + *final_types[0] = R_RSEL; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_lssel: + case e_rssel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_S_MODE; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_lsel: + case e_rsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_N_MODE; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_ldsel: + case e_rdsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_D_MODE; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_lrsel: + case e_rrsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_R_MODE; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_nsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_N1SEL; + final_types[1] = final_type; + final_types[2] = NULL; + *final_type = base_type; + break; + + case e_nlsel: + case e_nlrsel: + final_types[0] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0]) + return NULL; + *final_types[0] = R_N0SEL; + final_types[1] = (int *) bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[1]) + return NULL; + if (field == e_nlsel) + *final_types[1] = R_N_MODE; + else + *final_types[1] = R_R_MODE; + final_types[2] = final_type; + final_types[3] = NULL; + *final_type = base_type; + break; + } + + switch (base_type) + { + case R_HPPA: + /* The difference of two symbols needs *very* special handling. */ + if (sym_diff) + { + final_types[0] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[1] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[2] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[3] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0] || !final_types[1] || !final_types[2]) + return NULL; + if (field == e_fsel) + *final_types[0] = R_FSEL; + else if (field == e_rsel) + *final_types[0] = R_RSEL; + else if (field == e_lsel) + *final_types[0] = R_LSEL; + *final_types[1] = R_COMP2; + *final_types[2] = R_COMP2; + *final_types[3] = R_COMP1; + final_types[4] = final_type; + *final_types[4] = R_CODE_EXPR; + final_types[5] = NULL; + break; + } + /* PLABELs get their own relocation type. */ + else if (field == e_psel + || field == e_lpsel + || field == e_rpsel) + { + /* A PLABEL relocation that has a size of 32 bits must + be a R_DATA_PLABEL. All others are R_CODE_PLABELs. */ + if (format == 32) + *final_type = R_DATA_PLABEL; + else + *final_type = R_CODE_PLABEL; + } + /* PIC stuff. */ + else if (field == e_tsel + || field == e_ltsel + || field == e_rtsel) + *final_type = R_DLT_REL; + /* A relocation in the data space is always a full 32bits. */ + else if (format == 32) + *final_type = R_DATA_ONE_SYMBOL; + + break; + + case R_HPPA_GOTOFF: + /* More PLABEL special cases. */ + if (field == e_psel + || field == e_lpsel + || field == e_rpsel) + *final_type = R_DATA_PLABEL; + break; + + case R_HPPA_COMPLEX: + /* The difference of two symbols needs *very* special handling. */ + if (sym_diff) + { + final_types[0] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[1] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[2] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + final_types[3] = (int *)bfd_alloc_by_size_t (abfd, sizeof (int)); + if (!final_types[0] || !final_types[1] || !final_types[2]) + return NULL; + if (field == e_fsel) + *final_types[0] = R_FSEL; + else if (field == e_rsel) + *final_types[0] = R_RSEL; + else if (field == e_lsel) + *final_types[0] = R_LSEL; + *final_types[1] = R_COMP2; + *final_types[2] = R_COMP2; + *final_types[3] = R_COMP1; + final_types[4] = final_type; + *final_types[4] = R_CODE_EXPR; + final_types[5] = NULL; + break; + } + else + break; + + case R_HPPA_NONE: + case R_HPPA_ABS_CALL: + case R_HPPA_PCREL_CALL: + /* Right now we can default all these. */ + break; + } + return final_types; +} + +/* Return the address of the correct entry in the PA SOM relocation + howto table. */ + +/*ARGSUSED*/ +static reloc_howto_type * +som_bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + if ((int) code < (int) R_NO_RELOCATION + 255) + { + BFD_ASSERT ((int) som_hppa_howto_table[(int) code].type == (int) code); + return &som_hppa_howto_table[(int) code]; + } + + return (reloc_howto_type *) 0; +} + +/* Perform some initialization for an object. Save results of this + initialization in the BFD. */ + +static const bfd_target * +som_object_setup (abfd, file_hdrp, aux_hdrp) + bfd *abfd; + struct header *file_hdrp; + struct som_exec_auxhdr *aux_hdrp; +{ + asection *section; + int found; + + /* som_mkobject will set bfd_error if som_mkobject fails. */ + if (som_mkobject (abfd) != true) + return 0; + + /* Set BFD flags based on what information is available in the SOM. */ + abfd->flags = NO_FLAGS; + if (file_hdrp->symbol_total) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + + switch (file_hdrp->a_magic) + { + case DEMAND_MAGIC: + abfd->flags |= (D_PAGED | WP_TEXT | EXEC_P); + break; + case SHARE_MAGIC: + abfd->flags |= (WP_TEXT | EXEC_P); + break; + case EXEC_MAGIC: + abfd->flags |= (EXEC_P); + break; + case RELOC_MAGIC: + abfd->flags |= HAS_RELOC; + break; +#ifdef SHL_MAGIC + case SHL_MAGIC: +#endif +#ifdef DL_MAGIC + case DL_MAGIC: +#endif + abfd->flags |= DYNAMIC; + break; + + default: + break; + } + + /* Allocate space to hold the saved exec header information. */ + obj_som_exec_data (abfd) = (struct som_exec_data *) + bfd_zalloc (abfd, sizeof (struct som_exec_data )); + if (obj_som_exec_data (abfd) == NULL) + return NULL; + + /* The braindamaged OSF1 linker switched exec_flags and exec_entry! + + We used to identify OSF1 binaries based on NEW_VERSION_ID, but + apparently the latest HPUX linker is using NEW_VERSION_ID now. + + It's about time, OSF has used the new id since at least 1992; + HPUX didn't start till nearly 1995!. + + The new approach examines the entry field. If it's zero or not 4 + byte aligned then it's not a proper code address and we guess it's + really the executable flags. */ + found = 0; + for (section = abfd->sections; section; section = section->next) + { + if ((section->flags & SEC_CODE) == 0) + continue; + if (aux_hdrp->exec_entry >= section->vma + && aux_hdrp->exec_entry < section->vma + section->_cooked_size) + found = 1; + } + if (aux_hdrp->exec_entry == 0 + || (aux_hdrp->exec_entry & 0x3) != 0 + || ! found) + { + bfd_get_start_address (abfd) = aux_hdrp->exec_flags; + obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_entry; + } + else + { + bfd_get_start_address (abfd) = aux_hdrp->exec_entry; + obj_som_exec_data (abfd)->exec_flags = aux_hdrp->exec_flags; + } + + bfd_default_set_arch_mach (abfd, bfd_arch_hppa, pa10); + bfd_get_symcount (abfd) = file_hdrp->symbol_total; + + /* Initialize the saved symbol table and string table to NULL. + Save important offsets and sizes from the SOM header into + the BFD. */ + obj_som_stringtab (abfd) = (char *) NULL; + obj_som_symtab (abfd) = (som_symbol_type *) NULL; + obj_som_sorted_syms (abfd) = NULL; + obj_som_stringtab_size (abfd) = file_hdrp->symbol_strings_size; + obj_som_sym_filepos (abfd) = file_hdrp->symbol_location; + obj_som_str_filepos (abfd) = file_hdrp->symbol_strings_location; + obj_som_reloc_filepos (abfd) = file_hdrp->fixup_request_location; + obj_som_exec_data (abfd)->system_id = file_hdrp->system_id; + + return abfd->xvec; +} + +/* Convert all of the space and subspace info into BFD sections. Each space + contains a number of subspaces, which in turn describe the mapping between + regions of the exec file, and the address space that the program runs in. + BFD sections which correspond to spaces will overlap the sections for the + associated subspaces. */ + +static boolean +setup_sections (abfd, file_hdr) + bfd *abfd; + struct header *file_hdr; +{ + char *space_strings; + unsigned int space_index, i; + unsigned int total_subspaces = 0; + asection **subspace_sections, *section; + + /* First, read in space names */ + + space_strings = bfd_malloc (file_hdr->space_strings_size); + if (!space_strings && file_hdr->space_strings_size != 0) + goto error_return; + + if (bfd_seek (abfd, file_hdr->space_strings_location, SEEK_SET) < 0) + goto error_return; + if (bfd_read (space_strings, 1, file_hdr->space_strings_size, abfd) + != file_hdr->space_strings_size) + goto error_return; + + /* Loop over all of the space dictionaries, building up sections */ + for (space_index = 0; space_index < file_hdr->space_total; space_index++) + { + struct space_dictionary_record space; + struct subspace_dictionary_record subspace, save_subspace; + int subspace_index; + asection *space_asect; + char *newname; + + /* Read the space dictionary element */ + if (bfd_seek (abfd, file_hdr->space_location + + space_index * sizeof space, SEEK_SET) < 0) + goto error_return; + if (bfd_read (&space, 1, sizeof space, abfd) != sizeof space) + goto error_return; + + /* Setup the space name string */ + space.name.n_name = space.name.n_strx + space_strings; + + /* Make a section out of it */ + newname = bfd_alloc (abfd, strlen (space.name.n_name) + 1); + if (!newname) + goto error_return; + strcpy (newname, space.name.n_name); + + space_asect = bfd_make_section_anyway (abfd, newname); + if (!space_asect) + goto error_return; + + if (space.is_loadable == 0) + space_asect->flags |= SEC_DEBUGGING; + + /* Set up all the attributes for the space. */ + if (bfd_som_set_section_attributes (space_asect, space.is_defined, + space.is_private, space.sort_key, + space.space_number) == false) + goto error_return; + + /* If the space has no subspaces, then we're done. */ + if (space.subspace_quantity == 0) + continue; + + /* Now, read in the first subspace for this space */ + if (bfd_seek (abfd, file_hdr->subspace_location + + space.subspace_index * sizeof subspace, + SEEK_SET) < 0) + goto error_return; + if (bfd_read (&subspace, 1, sizeof subspace, abfd) != sizeof subspace) + goto error_return; + /* Seek back to the start of the subspaces for loop below */ + if (bfd_seek (abfd, file_hdr->subspace_location + + space.subspace_index * sizeof subspace, + SEEK_SET) < 0) + goto error_return; + + /* Setup the start address and file loc from the first subspace record */ + space_asect->vma = subspace.subspace_start; + space_asect->filepos = subspace.file_loc_init_value; + space_asect->alignment_power = log2 (subspace.alignment); + if (space_asect->alignment_power == -1) + goto error_return; + + /* Initialize save_subspace so we can reliably determine if this + loop placed any useful values into it. */ + memset (&save_subspace, 0, sizeof (struct subspace_dictionary_record)); + + /* Loop over the rest of the subspaces, building up more sections */ + for (subspace_index = 0; subspace_index < space.subspace_quantity; + subspace_index++) + { + asection *subspace_asect; + + /* Read in the next subspace */ + if (bfd_read (&subspace, 1, sizeof subspace, abfd) + != sizeof subspace) + goto error_return; + + /* Setup the subspace name string */ + subspace.name.n_name = subspace.name.n_strx + space_strings; + + newname = bfd_alloc (abfd, strlen (subspace.name.n_name) + 1); + if (!newname) + goto error_return; + strcpy (newname, subspace.name.n_name); + + /* Make a section out of this subspace */ + subspace_asect = bfd_make_section_anyway (abfd, newname); + if (!subspace_asect) + goto error_return; + + /* Store private information about the section. */ + if (bfd_som_set_subsection_attributes (subspace_asect, space_asect, + subspace.access_control_bits, + subspace.sort_key, + subspace.quadrant) == false) + goto error_return; + + /* Keep an easy mapping between subspaces and sections. + Note we do not necessarily read the subspaces in the + same order in which they appear in the object file. + + So to make the target index come out correctly, we + store the location of the subspace header in target + index, then sort using the location of the subspace + header as the key. Then we can assign correct + subspace indices. */ + total_subspaces++; + subspace_asect->target_index = bfd_tell (abfd) - sizeof (subspace); + + /* Set SEC_READONLY and SEC_CODE/SEC_DATA as specified + by the access_control_bits in the subspace header. */ + switch (subspace.access_control_bits >> 4) + { + /* Readonly data. */ + case 0x0: + subspace_asect->flags |= SEC_DATA | SEC_READONLY; + break; + + /* Normal data. */ + case 0x1: + subspace_asect->flags |= SEC_DATA; + break; + + /* Readonly code and the gateways. + Gateways have other attributes which do not map + into anything BFD knows about. */ + case 0x2: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + subspace_asect->flags |= SEC_CODE | SEC_READONLY; + break; + + /* dynamic (writable) code. */ + case 0x3: + subspace_asect->flags |= SEC_CODE; + break; + } + + if (subspace.dup_common || subspace.is_common) + subspace_asect->flags |= SEC_IS_COMMON; + else if (subspace.subspace_length > 0) + subspace_asect->flags |= SEC_HAS_CONTENTS; + + if (subspace.is_loadable) + subspace_asect->flags |= SEC_ALLOC | SEC_LOAD; + else + subspace_asect->flags |= SEC_DEBUGGING; + + if (subspace.code_only) + subspace_asect->flags |= SEC_CODE; + + /* Both file_loc_init_value and initialization_length will + be zero for a BSS like subspace. */ + if (subspace.file_loc_init_value == 0 + && subspace.initialization_length == 0) + subspace_asect->flags &= ~(SEC_DATA | SEC_LOAD | SEC_HAS_CONTENTS); + + /* This subspace has relocations. + The fixup_request_quantity is a byte count for the number of + entries in the relocation stream; it is not the actual number + of relocations in the subspace. */ + if (subspace.fixup_request_quantity != 0) + { + subspace_asect->flags |= SEC_RELOC; + subspace_asect->rel_filepos = subspace.fixup_request_index; + som_section_data (subspace_asect)->reloc_size + = subspace.fixup_request_quantity; + /* We can not determine this yet. When we read in the + relocation table the correct value will be filled in. */ + subspace_asect->reloc_count = -1; + } + + /* Update save_subspace if appropriate. */ + if (subspace.file_loc_init_value > save_subspace.file_loc_init_value) + save_subspace = subspace; + + subspace_asect->vma = subspace.subspace_start; + subspace_asect->_cooked_size = subspace.subspace_length; + subspace_asect->_raw_size = subspace.subspace_length; + subspace_asect->filepos = subspace.file_loc_init_value; + subspace_asect->alignment_power = log2 (subspace.alignment); + if (subspace_asect->alignment_power == -1) + goto error_return; + } + + /* Yow! there is no subspace within the space which actually + has initialized information in it; this should never happen + as far as I know. */ + if (!save_subspace.file_loc_init_value) + goto error_return; + + /* Setup the sizes for the space section based upon the info in the + last subspace of the space. */ + space_asect->_cooked_size = save_subspace.subspace_start + - space_asect->vma + save_subspace.subspace_length; + space_asect->_raw_size = save_subspace.file_loc_init_value + - space_asect->filepos + save_subspace.initialization_length; + } + /* Now that we've read in all the subspace records, we need to assign + a target index to each subspace. */ + subspace_sections = (asection **) bfd_malloc (total_subspaces + * sizeof (asection *)); + if (subspace_sections == NULL) + goto error_return; + + for (i = 0, section = abfd->sections; section; section = section->next) + { + if (!som_is_subspace (section)) + continue; + + subspace_sections[i] = section; + i++; + } + qsort (subspace_sections, total_subspaces, + sizeof (asection *), compare_subspaces); + + /* subspace_sections is now sorted in the order in which the subspaces + appear in the object file. Assign an index to each one now. */ + for (i = 0; i < total_subspaces; i++) + subspace_sections[i]->target_index = i; + + if (space_strings != NULL) + free (space_strings); + + if (subspace_sections != NULL) + free (subspace_sections); + + return true; + + error_return: + if (space_strings != NULL) + free (space_strings); + + if (subspace_sections != NULL) + free (subspace_sections); + return false; +} + +/* Read in a SOM object and make it into a BFD. */ + +static const bfd_target * +som_object_p (abfd) + bfd *abfd; +{ + struct header file_hdr; + struct som_exec_auxhdr aux_hdr; + + if (bfd_read ((PTR) & file_hdr, 1, FILE_HDR_SIZE, abfd) != FILE_HDR_SIZE) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if (!_PA_RISC_ID (file_hdr.system_id)) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + switch (file_hdr.a_magic) + { + case RELOC_MAGIC: + case EXEC_MAGIC: + case SHARE_MAGIC: + case DEMAND_MAGIC: +#ifdef DL_MAGIC + case DL_MAGIC: +#endif +#ifdef SHL_MAGIC + case SHL_MAGIC: +#endif +#ifdef EXECLIBMAGIC + case EXECLIBMAGIC: +#endif +#ifdef SHARED_MAGIC_CNX + case SHARED_MAGIC_CNX: +#endif + break; + default: + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + if (file_hdr.version_id != VERSION_ID + && file_hdr.version_id != NEW_VERSION_ID) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + /* If the aux_header_size field in the file header is zero, then this + object is an incomplete executable (a .o file). Do not try to read + a non-existant auxiliary header. */ + memset (&aux_hdr, 0, sizeof (struct som_exec_auxhdr)); + if (file_hdr.aux_header_size != 0) + { + if (bfd_read ((PTR) & aux_hdr, 1, AUX_HDR_SIZE, abfd) != AUX_HDR_SIZE) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + } + + if (!setup_sections (abfd, &file_hdr)) + { + /* setup_sections does not bubble up a bfd error code. */ + bfd_set_error (bfd_error_bad_value); + return 0; + } + + /* This appears to be a valid SOM object. Do some initialization. */ + return som_object_setup (abfd, &file_hdr, &aux_hdr); +} + +/* Create a SOM object. */ + +static boolean +som_mkobject (abfd) + bfd *abfd; +{ + /* Allocate memory to hold backend information. */ + abfd->tdata.som_data = (struct som_data_struct *) + bfd_zalloc (abfd, sizeof (struct som_data_struct)); + if (abfd->tdata.som_data == NULL) + return false; + return true; +} + +/* Initialize some information in the file header. This routine makes + not attempt at doing the right thing for a full executable; it + is only meant to handle relocatable objects. */ + +static boolean +som_prep_headers (abfd) + bfd *abfd; +{ + struct header *file_hdr; + asection *section; + + /* Make and attach a file header to the BFD. */ + file_hdr = (struct header *) bfd_zalloc (abfd, sizeof (struct header)); + if (file_hdr == NULL) + return false; + obj_som_file_hdr (abfd) = file_hdr; + + if (abfd->flags & (EXEC_P | DYNAMIC)) + { + + /* Make and attach an exec header to the BFD. */ + obj_som_exec_hdr (abfd) = (struct som_exec_auxhdr *) + bfd_zalloc (abfd, sizeof (struct som_exec_auxhdr)); + if (obj_som_exec_hdr (abfd) == NULL) + return false; + + if (abfd->flags & D_PAGED) + file_hdr->a_magic = DEMAND_MAGIC; + else if (abfd->flags & WP_TEXT) + file_hdr->a_magic = SHARE_MAGIC; +#ifdef SHL_MAGIC + else if (abfd->flags & DYNAMIC) + file_hdr->a_magic = SHL_MAGIC; +#endif + else + file_hdr->a_magic = EXEC_MAGIC; + } + else + file_hdr->a_magic = RELOC_MAGIC; + + /* Only new format SOM is supported. */ + file_hdr->version_id = NEW_VERSION_ID; + + /* These fields are optional, and embedding timestamps is not always + a wise thing to do, it makes comparing objects during a multi-stage + bootstrap difficult. */ + file_hdr->file_time.secs = 0; + file_hdr->file_time.nanosecs = 0; + + file_hdr->entry_space = 0; + file_hdr->entry_subspace = 0; + file_hdr->entry_offset = 0; + file_hdr->presumed_dp = 0; + + /* Now iterate over the sections translating information from + BFD sections to SOM spaces/subspaces. */ + + for (section = abfd->sections; section != NULL; section = section->next) + { + /* Ignore anything which has not been marked as a space or + subspace. */ + if (!som_is_space (section) && !som_is_subspace (section)) + continue; + + if (som_is_space (section)) + { + /* Allocate space for the space dictionary. */ + som_section_data (section)->space_dict + = (struct space_dictionary_record *) + bfd_zalloc (abfd, sizeof (struct space_dictionary_record)); + if (som_section_data (section)->space_dict == NULL) + return false; + /* Set space attributes. Note most attributes of SOM spaces + are set based on the subspaces it contains. */ + som_section_data (section)->space_dict->loader_fix_index = -1; + som_section_data (section)->space_dict->init_pointer_index = -1; + + /* Set more attributes that were stuffed away in private data. */ + som_section_data (section)->space_dict->sort_key = + som_section_data (section)->copy_data->sort_key; + som_section_data (section)->space_dict->is_defined = + som_section_data (section)->copy_data->is_defined; + som_section_data (section)->space_dict->is_private = + som_section_data (section)->copy_data->is_private; + som_section_data (section)->space_dict->space_number = + som_section_data (section)->copy_data->space_number; + } + else + { + /* Allocate space for the subspace dictionary. */ + som_section_data (section)->subspace_dict + = (struct subspace_dictionary_record *) + bfd_zalloc (abfd, sizeof (struct subspace_dictionary_record)); + if (som_section_data (section)->subspace_dict == NULL) + return false; + + /* Set subspace attributes. Basic stuff is done here, additional + attributes are filled in later as more information becomes + available. */ + if (section->flags & SEC_IS_COMMON) + { + som_section_data (section)->subspace_dict->dup_common = 1; + som_section_data (section)->subspace_dict->is_common = 1; + } + + if (section->flags & SEC_ALLOC) + som_section_data (section)->subspace_dict->is_loadable = 1; + + if (section->flags & SEC_CODE) + som_section_data (section)->subspace_dict->code_only = 1; + + som_section_data (section)->subspace_dict->subspace_start = + section->vma; + som_section_data (section)->subspace_dict->subspace_length = + bfd_section_size (abfd, section); + som_section_data (section)->subspace_dict->initialization_length = + bfd_section_size (abfd, section); + som_section_data (section)->subspace_dict->alignment = + 1 << section->alignment_power; + + /* Set more attributes that were stuffed away in private data. */ + som_section_data (section)->subspace_dict->sort_key = + som_section_data (section)->copy_data->sort_key; + som_section_data (section)->subspace_dict->access_control_bits = + som_section_data (section)->copy_data->access_control_bits; + som_section_data (section)->subspace_dict->quadrant = + som_section_data (section)->copy_data->quadrant; + } + } + return true; +} + +/* Return true if the given section is a SOM space, false otherwise. */ + +static boolean +som_is_space (section) + asection *section; +{ + /* If no copy data is available, then it's neither a space nor a + subspace. */ + if (som_section_data (section)->copy_data == NULL) + return false; + + /* If the containing space isn't the same as the given section, + then this isn't a space. */ + if (som_section_data (section)->copy_data->container != section + && (som_section_data (section)->copy_data->container->output_section + != section)) + return false; + + /* OK. Must be a space. */ + return true; +} + +/* Return true if the given section is a SOM subspace, false otherwise. */ + +static boolean +som_is_subspace (section) + asection *section; +{ + /* If no copy data is available, then it's neither a space nor a + subspace. */ + if (som_section_data (section)->copy_data == NULL) + return false; + + /* If the containing space is the same as the given section, + then this isn't a subspace. */ + if (som_section_data (section)->copy_data->container == section + || (som_section_data (section)->copy_data->container->output_section + == section)) + return false; + + /* OK. Must be a subspace. */ + return true; +} + +/* Return true if the given space containins the given subspace. It + is safe to assume space really is a space, and subspace really + is a subspace. */ + +static boolean +som_is_container (space, subspace) + asection *space, *subspace; +{ + return (som_section_data (subspace)->copy_data->container == space + || (som_section_data (subspace)->copy_data->container->output_section + == space)); +} + +/* Count and return the number of spaces attached to the given BFD. */ + +static unsigned long +som_count_spaces (abfd) + bfd *abfd; +{ + int count = 0; + asection *section; + + for (section = abfd->sections; section != NULL; section = section->next) + count += som_is_space (section); + + return count; +} + +/* Count the number of subspaces attached to the given BFD. */ + +static unsigned long +som_count_subspaces (abfd) + bfd *abfd; +{ + int count = 0; + asection *section; + + for (section = abfd->sections; section != NULL; section = section->next) + count += som_is_subspace (section); + + return count; +} + +/* Return -1, 0, 1 indicating the relative ordering of sym1 and sym2. + + We desire symbols to be ordered starting with the symbol with the + highest relocation count down to the symbol with the lowest relocation + count. Doing so compacts the relocation stream. */ + +static int +compare_syms (arg1, arg2) + const PTR arg1; + const PTR arg2; + +{ + asymbol **sym1 = (asymbol **) arg1; + asymbol **sym2 = (asymbol **) arg2; + unsigned int count1, count2; + + /* Get relocation count for each symbol. Note that the count + is stored in the udata pointer for section symbols! */ + if ((*sym1)->flags & BSF_SECTION_SYM) + count1 = (*sym1)->udata.i; + else + count1 = som_symbol_data (*sym1)->reloc_count; + + if ((*sym2)->flags & BSF_SECTION_SYM) + count2 = (*sym2)->udata.i; + else + count2 = som_symbol_data (*sym2)->reloc_count; + + /* Return the appropriate value. */ + if (count1 < count2) + return 1; + else if (count1 > count2) + return -1; + return 0; +} + +/* Return -1, 0, 1 indicating the relative ordering of subspace1 + and subspace. */ + +static int +compare_subspaces (arg1, arg2) + const PTR arg1; + const PTR arg2; + +{ + asection **subspace1 = (asection **) arg1; + asection **subspace2 = (asection **) arg2; + unsigned int count1, count2; + + if ((*subspace1)->target_index < (*subspace2)->target_index) + return -1; + else if ((*subspace2)->target_index < (*subspace1)->target_index) + return 1; + else + return 0; +} + +/* Perform various work in preparation for emitting the fixup stream. */ + +static void +som_prep_for_fixups (abfd, syms, num_syms) + bfd *abfd; + asymbol **syms; + unsigned long num_syms; +{ + int i; + asection *section; + asymbol **sorted_syms; + + /* Most SOM relocations involving a symbol have a length which is + dependent on the index of the symbol. So symbols which are + used often in relocations should have a small index. */ + + /* First initialize the counters for each symbol. */ + for (i = 0; i < num_syms; i++) + { + /* Handle a section symbol; these have no pointers back to the + SOM symbol info. So we just use the udata field to hold the + relocation count. */ + if (som_symbol_data (syms[i]) == NULL + || syms[i]->flags & BSF_SECTION_SYM) + { + syms[i]->flags |= BSF_SECTION_SYM; + syms[i]->udata.i = 0; + } + else + som_symbol_data (syms[i])->reloc_count = 0; + } + + /* Now that the counters are initialized, make a weighted count + of how often a given symbol is used in a relocation. */ + for (section = abfd->sections; section != NULL; section = section->next) + { + int i; + + /* Does this section have any relocations? */ + if (section->reloc_count <= 0) + continue; + + /* Walk through each relocation for this section. */ + for (i = 1; i < section->reloc_count; i++) + { + arelent *reloc = section->orelocation[i]; + int scale; + + /* A relocation against a symbol in the *ABS* section really + does not have a symbol. Likewise if the symbol isn't associated + with any section. */ + if (reloc->sym_ptr_ptr == NULL + || bfd_is_abs_section ((*reloc->sym_ptr_ptr)->section)) + continue; + + /* Scaling to encourage symbols involved in R_DP_RELATIVE + and R_CODE_ONE_SYMBOL relocations to come first. These + two relocations have single byte versions if the symbol + index is very small. */ + if (reloc->howto->type == R_DP_RELATIVE + || reloc->howto->type == R_CODE_ONE_SYMBOL) + scale = 2; + else + scale = 1; + + /* Handle section symbols by storing the count in the udata + field. It will not be used and the count is very important + for these symbols. */ + if ((*reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM) + { + (*reloc->sym_ptr_ptr)->udata.i = + (*reloc->sym_ptr_ptr)->udata.i + scale; + continue; + } + + /* A normal symbol. Increment the count. */ + som_symbol_data (*reloc->sym_ptr_ptr)->reloc_count += scale; + } + } + + /* Sort a copy of the symbol table, rather than the canonical + output symbol table. */ + sorted_syms = (asymbol **) bfd_zalloc (abfd, num_syms * sizeof (asymbol *)); + memcpy (sorted_syms, syms, num_syms * sizeof (asymbol *)); + qsort (sorted_syms, num_syms, sizeof (asymbol *), compare_syms); + obj_som_sorted_syms (abfd) = sorted_syms; + + /* Compute the symbol indexes, they will be needed by the relocation + code. */ + for (i = 0; i < num_syms; i++) + { + /* A section symbol. Again, there is no pointer to backend symbol + information, so we reuse the udata field again. */ + if (sorted_syms[i]->flags & BSF_SECTION_SYM) + sorted_syms[i]->udata.i = i; + else + som_symbol_data (sorted_syms[i])->index = i; + } +} + +static boolean +som_write_fixups (abfd, current_offset, total_reloc_sizep) + bfd *abfd; + unsigned long current_offset; + unsigned int *total_reloc_sizep; +{ + unsigned int i, j; + /* Chunk of memory that we can use as buffer space, then throw + away. */ + unsigned char tmp_space[SOM_TMP_BUFSIZE]; + unsigned char *p; + unsigned int total_reloc_size = 0; + unsigned int subspace_reloc_size = 0; + unsigned int num_spaces = obj_som_file_hdr (abfd)->space_total; + asection *section = abfd->sections; + + memset (tmp_space, 0, SOM_TMP_BUFSIZE); + p = tmp_space; + + /* All the fixups for a particular subspace are emitted in a single + stream. All the subspaces for a particular space are emitted + as a single stream. + + So, to get all the locations correct one must iterate through all the + spaces, for each space iterate through its subspaces and output a + fixups stream. */ + for (i = 0; i < num_spaces; i++) + { + asection *subsection; + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + /* Now iterate through each of its subspaces. */ + for (subsection = abfd->sections; + subsection != NULL; + subsection = subsection->next) + { + int reloc_offset, current_rounding_mode; + + /* Find a subspace of this space. */ + if (!som_is_subspace (subsection) + || !som_is_container (section, subsection)) + continue; + + /* If this subspace does not have real data, then we are + finised with it. */ + if ((subsection->flags & SEC_HAS_CONTENTS) == 0) + { + som_section_data (subsection)->subspace_dict->fixup_request_index + = -1; + continue; + } + + /* This subspace has some relocations. Put the relocation stream + index into the subspace record. */ + som_section_data (subsection)->subspace_dict->fixup_request_index + = total_reloc_size; + + /* To make life easier start over with a clean slate for + each subspace. Seek to the start of the relocation stream + for this subspace in preparation for writing out its fixup + stream. */ + if (bfd_seek (abfd, current_offset + total_reloc_size, SEEK_SET) < 0) + return false; + + /* Buffer space has already been allocated. Just perform some + initialization here. */ + p = tmp_space; + subspace_reloc_size = 0; + reloc_offset = 0; + som_initialize_reloc_queue (reloc_queue); + current_rounding_mode = R_N_MODE; + + /* Translate each BFD relocation into one or more SOM + relocations. */ + for (j = 0; j < subsection->reloc_count; j++) + { + arelent *bfd_reloc = subsection->orelocation[j]; + unsigned int skip; + int sym_num; + + /* Get the symbol number. Remember it's stored in a + special place for section symbols. */ + if ((*bfd_reloc->sym_ptr_ptr)->flags & BSF_SECTION_SYM) + sym_num = (*bfd_reloc->sym_ptr_ptr)->udata.i; + else + sym_num = som_symbol_data (*bfd_reloc->sym_ptr_ptr)->index; + + /* If there is not enough room for the next couple relocations, + then dump the current buffer contents now. Also reinitialize + the relocation queue. + + No single BFD relocation could ever translate into more + than 100 bytes of SOM relocations (20bytes is probably the + upper limit, but leave lots of space for growth). */ + if (p - tmp_space + 100 > SOM_TMP_BUFSIZE) + { + if (bfd_write ((PTR) tmp_space, p - tmp_space, 1, abfd) + != p - tmp_space) + return false; + + p = tmp_space; + som_initialize_reloc_queue (reloc_queue); + } + + /* Emit R_NO_RELOCATION fixups to map any bytes which were + skipped. */ + skip = bfd_reloc->address - reloc_offset; + p = som_reloc_skip (abfd, skip, p, + &subspace_reloc_size, reloc_queue); + + /* Update reloc_offset for the next iteration. + + Many relocations do not consume input bytes. They + are markers, or set state necessary to perform some + later relocation. */ + switch (bfd_reloc->howto->type) + { + /* This only needs to handle relocations that may be + made by hppa_som_gen_reloc. */ + case R_ENTRY: + case R_ALT_ENTRY: + case R_EXIT: + case R_N_MODE: + case R_S_MODE: + case R_D_MODE: + case R_R_MODE: + case R_FSEL: + case R_LSEL: + case R_RSEL: + case R_COMP1: + case R_COMP2: + case R_BEGIN_BRTAB: + case R_END_BRTAB: + case R_N0SEL: + case R_N1SEL: + reloc_offset = bfd_reloc->address; + break; + + default: + reloc_offset = bfd_reloc->address + 4; + break; + } + + /* Now the actual relocation we care about. */ + switch (bfd_reloc->howto->type) + { + case R_PCREL_CALL: + case R_ABS_CALL: + p = som_reloc_call (abfd, p, &subspace_reloc_size, + bfd_reloc, sym_num, reloc_queue); + break; + + case R_CODE_ONE_SYMBOL: + case R_DP_RELATIVE: + /* Account for any addend. */ + if (bfd_reloc->addend) + p = som_reloc_addend (abfd, bfd_reloc->addend, p, + &subspace_reloc_size, reloc_queue); + + if (sym_num < 0x20) + { + bfd_put_8 (abfd, bfd_reloc->howto->type + sym_num, p); + subspace_reloc_size += 1; + p += 1; + } + else if (sym_num < 0x100) + { + bfd_put_8 (abfd, bfd_reloc->howto->type + 32, p); + bfd_put_8 (abfd, sym_num, p + 1); + p = try_prev_fixup (abfd, &subspace_reloc_size, p, + 2, reloc_queue); + } + else if (sym_num < 0x10000000) + { + bfd_put_8 (abfd, bfd_reloc->howto->type + 33, p); + bfd_put_8 (abfd, sym_num >> 16, p + 1); + bfd_put_16 (abfd, sym_num, p + 2); + p = try_prev_fixup (abfd, &subspace_reloc_size, + p, 4, reloc_queue); + } + else + abort (); + break; + + case R_DATA_ONE_SYMBOL: + case R_DATA_PLABEL: + case R_CODE_PLABEL: + case R_DLT_REL: + /* Account for any addend using R_DATA_OVERRIDE. */ + if (bfd_reloc->howto->type != R_DATA_ONE_SYMBOL + && bfd_reloc->addend) + p = som_reloc_addend (abfd, bfd_reloc->addend, p, + &subspace_reloc_size, reloc_queue); + + if (sym_num < 0x100) + { + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + bfd_put_8 (abfd, sym_num, p + 1); + p = try_prev_fixup (abfd, &subspace_reloc_size, p, + 2, reloc_queue); + } + else if (sym_num < 0x10000000) + { + bfd_put_8 (abfd, bfd_reloc->howto->type + 1, p); + bfd_put_8 (abfd, sym_num >> 16, p + 1); + bfd_put_16 (abfd, sym_num, p + 2); + p = try_prev_fixup (abfd, &subspace_reloc_size, + p, 4, reloc_queue); + } + else + abort (); + break; + + case R_ENTRY: + { + int tmp; + arelent *tmp_reloc = NULL; + bfd_put_8 (abfd, R_ENTRY, p); + + /* R_ENTRY relocations have 64 bits of associated + data. Unfortunately the addend field of a bfd + relocation is only 32 bits. So, we split up + the 64bit unwind information and store part in + the R_ENTRY relocation, and the rest in the R_EXIT + relocation. */ + bfd_put_32 (abfd, bfd_reloc->addend, p + 1); + + /* Find the next R_EXIT relocation. */ + for (tmp = j; tmp < subsection->reloc_count; tmp++) + { + tmp_reloc = subsection->orelocation[tmp]; + if (tmp_reloc->howto->type == R_EXIT) + break; + } + + if (tmp == subsection->reloc_count) + abort (); + + bfd_put_32 (abfd, tmp_reloc->addend, p + 5); + p = try_prev_fixup (abfd, &subspace_reloc_size, + p, 9, reloc_queue); + break; + } + + case R_N_MODE: + case R_S_MODE: + case R_D_MODE: + case R_R_MODE: + /* If this relocation requests the current rounding + mode, then it is redundant. */ + if (bfd_reloc->howto->type != current_rounding_mode) + { + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + subspace_reloc_size += 1; + p += 1; + current_rounding_mode = bfd_reloc->howto->type; + } + break; + + case R_EXIT: + case R_ALT_ENTRY: + case R_FSEL: + case R_LSEL: + case R_RSEL: + case R_BEGIN_BRTAB: + case R_END_BRTAB: + case R_N0SEL: + case R_N1SEL: + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + subspace_reloc_size += 1; + p += 1; + break; + + case R_COMP1: + /* The only time we generate R_COMP1, R_COMP2 and + R_CODE_EXPR relocs is for the difference of two + symbols. Hence we can cheat here. */ + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + bfd_put_8 (abfd, 0x44, p + 1); + p = try_prev_fixup (abfd, &subspace_reloc_size, + p, 2, reloc_queue); + break; + + case R_COMP2: + /* The only time we generate R_COMP1, R_COMP2 and + R_CODE_EXPR relocs is for the difference of two + symbols. Hence we can cheat here. */ + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + bfd_put_8 (abfd, 0x80, p + 1); + bfd_put_8 (abfd, sym_num >> 16, p + 2); + bfd_put_16 (abfd, sym_num, p + 3); + p = try_prev_fixup (abfd, &subspace_reloc_size, + p, 5, reloc_queue); + break; + + case R_CODE_EXPR: + /* The only time we generate R_COMP1, R_COMP2 and + R_CODE_EXPR relocs is for the difference of two + symbols. Hence we can cheat here. */ + bfd_put_8 (abfd, bfd_reloc->howto->type, p); + subspace_reloc_size += 1; + p += 1; + break; + + /* Put a "R_RESERVED" relocation in the stream if + we hit something we do not understand. The linker + will complain loudly if this ever happens. */ + default: + bfd_put_8 (abfd, 0xff, p); + subspace_reloc_size += 1; + p += 1; + break; + } + } + + /* Last BFD relocation for a subspace has been processed. + Map the rest of the subspace with R_NO_RELOCATION fixups. */ + p = som_reloc_skip (abfd, bfd_section_size (abfd, subsection) + - reloc_offset, + p, &subspace_reloc_size, reloc_queue); + + /* Scribble out the relocations. */ + if (bfd_write ((PTR) tmp_space, p - tmp_space, 1, abfd) + != p - tmp_space) + return false; + p = tmp_space; + + total_reloc_size += subspace_reloc_size; + som_section_data (subsection)->subspace_dict->fixup_request_quantity + = subspace_reloc_size; + } + section = section->next; + } + *total_reloc_sizep = total_reloc_size; + return true; +} + +/* Write out the space/subspace string table. */ + +static boolean +som_write_space_strings (abfd, current_offset, string_sizep) + bfd *abfd; + unsigned long current_offset; + unsigned int *string_sizep; +{ + /* Chunk of memory that we can use as buffer space, then throw + away. */ + unsigned char tmp_space[SOM_TMP_BUFSIZE]; + unsigned char *p; + unsigned int strings_size = 0; + asection *section; + + memset (tmp_space, 0, SOM_TMP_BUFSIZE); + p = tmp_space; + + /* Seek to the start of the space strings in preparation for writing + them out. */ + if (bfd_seek (abfd, current_offset, SEEK_SET) < 0) + return false; + + /* Walk through all the spaces and subspaces (order is not important) + building up and writing string table entries for their names. */ + for (section = abfd->sections; section != NULL; section = section->next) + { + int length; + + /* Only work with space/subspaces; avoid any other sections + which might have been made (.text for example). */ + if (!som_is_space (section) && !som_is_subspace (section)) + continue; + + /* Get the length of the space/subspace name. */ + length = strlen (section->name); + + /* If there is not enough room for the next entry, then dump the + current buffer contents now. Each entry will take 4 bytes to + hold the string length + the string itself + null terminator. */ + if (p - tmp_space + 5 + length > SOM_TMP_BUFSIZE) + { + if (bfd_write ((PTR) &tmp_space[0], p - tmp_space, 1, abfd) + != p - tmp_space) + return false; + /* Reset to beginning of the buffer space. */ + p = tmp_space; + } + + /* First element in a string table entry is the length of the + string. Alignment issues are already handled. */ + bfd_put_32 (abfd, length, p); + p += 4; + strings_size += 4; + + /* Record the index in the space/subspace records. */ + if (som_is_space (section)) + som_section_data (section)->space_dict->name.n_strx = strings_size; + else + som_section_data (section)->subspace_dict->name.n_strx = strings_size; + + /* Next comes the string itself + a null terminator. */ + strcpy (p, section->name); + p += length + 1; + strings_size += length + 1; + + /* Always align up to the next word boundary. */ + while (strings_size % 4) + { + bfd_put_8 (abfd, 0, p); + p++; + strings_size++; + } + } + + /* Done with the space/subspace strings. Write out any information + contained in a partial block. */ + if (bfd_write ((PTR) &tmp_space[0], p - tmp_space, 1, abfd) != p - tmp_space) + return false; + *string_sizep = strings_size; + return true; +} + +/* Write out the symbol string table. */ + +static boolean +som_write_symbol_strings (abfd, current_offset, syms, num_syms, string_sizep) + bfd *abfd; + unsigned long current_offset; + asymbol **syms; + unsigned int num_syms; + unsigned int *string_sizep; +{ + unsigned int i; + + /* Chunk of memory that we can use as buffer space, then throw + away. */ + unsigned char tmp_space[SOM_TMP_BUFSIZE]; + unsigned char *p; + unsigned int strings_size = 0; + + memset (tmp_space, 0, SOM_TMP_BUFSIZE); + p = tmp_space; + + /* Seek to the start of the space strings in preparation for writing + them out. */ + if (bfd_seek (abfd, current_offset, SEEK_SET) < 0) + return false; + + for (i = 0; i < num_syms; i++) + { + int length = strlen (syms[i]->name); + + /* If there is not enough room for the next entry, then dump the + current buffer contents now. */ + if (p - tmp_space + 5 + length > SOM_TMP_BUFSIZE) + { + if (bfd_write ((PTR) &tmp_space[0], p - tmp_space, 1, abfd) + != p - tmp_space) + return false; + /* Reset to beginning of the buffer space. */ + p = tmp_space; + } + + /* First element in a string table entry is the length of the + string. This must always be 4 byte aligned. This is also + an appropriate time to fill in the string index field in the + symbol table entry. */ + bfd_put_32 (abfd, length, p); + strings_size += 4; + p += 4; + + /* Next comes the string itself + a null terminator. */ + strcpy (p, syms[i]->name); + + som_symbol_data(syms[i])->stringtab_offset = strings_size; + p += length + 1; + strings_size += length + 1; + + /* Always align up to the next word boundary. */ + while (strings_size % 4) + { + bfd_put_8 (abfd, 0, p); + strings_size++; + p++; + } + } + + /* Scribble out any partial block. */ + if (bfd_write ((PTR) &tmp_space[0], p - tmp_space, 1, abfd) != p - tmp_space) + return false; + + *string_sizep = strings_size; + return true; +} + +/* Compute variable information to be placed in the SOM headers, + space/subspace dictionaries, relocation streams, etc. Begin + writing parts of the object file. */ + +static boolean +som_begin_writing (abfd) + bfd *abfd; +{ + unsigned long current_offset = 0; + int strings_size = 0; + unsigned int total_reloc_size = 0; + unsigned long num_spaces, num_subspaces, i; + asection *section; + unsigned int total_subspaces = 0; + struct som_exec_auxhdr *exec_header = NULL; + + /* The file header will always be first in an object file, + everything else can be in random locations. To keep things + "simple" BFD will lay out the object file in the manner suggested + by the PRO ABI for PA-RISC Systems. */ + + /* Before any output can really begin offsets for all the major + portions of the object file must be computed. So, starting + with the initial file header compute (and sometimes write) + each portion of the object file. */ + + /* Make room for the file header, it's contents are not complete + yet, so it can not be written at this time. */ + current_offset += sizeof (struct header); + + /* Any auxiliary headers will follow the file header. Right now + we support only the copyright and version headers. */ + obj_som_file_hdr (abfd)->aux_header_location = current_offset; + obj_som_file_hdr (abfd)->aux_header_size = 0; + if (abfd->flags & (EXEC_P | DYNAMIC)) + { + /* Parts of the exec header will be filled in later, so + delay writing the header itself. Fill in the defaults, + and write it later. */ + current_offset += sizeof (struct som_exec_auxhdr); + obj_som_file_hdr (abfd)->aux_header_size + += sizeof (struct som_exec_auxhdr); + exec_header = obj_som_exec_hdr (abfd); + exec_header->som_auxhdr.type = EXEC_AUX_ID; + exec_header->som_auxhdr.length = 40; + } + if (obj_som_version_hdr (abfd) != NULL) + { + unsigned int len; + + if (bfd_seek (abfd, current_offset, SEEK_SET) < 0) + return false; + + /* Write the aux_id structure and the string length. */ + len = sizeof (struct aux_id) + sizeof (unsigned int); + obj_som_file_hdr (abfd)->aux_header_size += len; + current_offset += len; + if (bfd_write ((PTR) obj_som_version_hdr (abfd), len, 1, abfd) != len) + return false; + + /* Write the version string. */ + len = obj_som_version_hdr (abfd)->header_id.length - sizeof (int); + obj_som_file_hdr (abfd)->aux_header_size += len; + current_offset += len; + if (bfd_write ((PTR) obj_som_version_hdr (abfd)->user_string, + len, 1, abfd) != len) + return false; + } + + if (obj_som_copyright_hdr (abfd) != NULL) + { + unsigned int len; + + if (bfd_seek (abfd, current_offset, SEEK_SET) < 0) + return false; + + /* Write the aux_id structure and the string length. */ + len = sizeof (struct aux_id) + sizeof (unsigned int); + obj_som_file_hdr (abfd)->aux_header_size += len; + current_offset += len; + if (bfd_write ((PTR) obj_som_copyright_hdr (abfd), len, 1, abfd) != len) + return false; + + /* Write the copyright string. */ + len = obj_som_copyright_hdr (abfd)->header_id.length - sizeof (int); + obj_som_file_hdr (abfd)->aux_header_size += len; + current_offset += len; + if (bfd_write ((PTR) obj_som_copyright_hdr (abfd)->copyright, + len, 1, abfd) != len) + return false; + } + + /* Next comes the initialization pointers; we have no initialization + pointers, so current offset does not change. */ + obj_som_file_hdr (abfd)->init_array_location = current_offset; + obj_som_file_hdr (abfd)->init_array_total = 0; + + /* Next are the space records. These are fixed length records. + + Count the number of spaces to determine how much room is needed + in the object file for the space records. + + The names of the spaces are stored in a separate string table, + and the index for each space into the string table is computed + below. Therefore, it is not possible to write the space headers + at this time. */ + num_spaces = som_count_spaces (abfd); + obj_som_file_hdr (abfd)->space_location = current_offset; + obj_som_file_hdr (abfd)->space_total = num_spaces; + current_offset += num_spaces * sizeof (struct space_dictionary_record); + + /* Next are the subspace records. These are fixed length records. + + Count the number of subspaes to determine how much room is needed + in the object file for the subspace records. + + A variety if fields in the subspace record are still unknown at + this time (index into string table, fixup stream location/size, etc). */ + num_subspaces = som_count_subspaces (abfd); + obj_som_file_hdr (abfd)->subspace_location = current_offset; + obj_som_file_hdr (abfd)->subspace_total = num_subspaces; + current_offset += num_subspaces * sizeof (struct subspace_dictionary_record); + + /* Next is the string table for the space/subspace names. We will + build and write the string table on the fly. At the same time + we will fill in the space/subspace name index fields. */ + + /* The string table needs to be aligned on a word boundary. */ + if (current_offset % 4) + current_offset += (4 - (current_offset % 4)); + + /* Mark the offset of the space/subspace string table in the + file header. */ + obj_som_file_hdr (abfd)->space_strings_location = current_offset; + + /* Scribble out the space strings. */ + if (som_write_space_strings (abfd, current_offset, &strings_size) == false) + return false; + + /* Record total string table size in the header and update the + current offset. */ + obj_som_file_hdr (abfd)->space_strings_size = strings_size; + current_offset += strings_size; + + /* Next is the compiler records. We do not use these. */ + obj_som_file_hdr (abfd)->compiler_location = current_offset; + obj_som_file_hdr (abfd)->compiler_total = 0; + + /* Now compute the file positions for the loadable subspaces, taking + care to make sure everything stays properly aligned. */ + + section = abfd->sections; + for (i = 0; i < num_spaces; i++) + { + asection *subsection; + int first_subspace; + unsigned int subspace_offset = 0; + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + first_subspace = 1; + /* Now look for all its subspaces. */ + for (subsection = abfd->sections; + subsection != NULL; + subsection = subsection->next) + { + + if (!som_is_subspace (subsection) + || !som_is_container (section, subsection) + || (subsection->flags & SEC_ALLOC) == 0) + continue; + + /* If this is the first subspace in the space, and we are + building an executable, then take care to make sure all + the alignments are correct and update the exec header. */ + if (first_subspace + && (abfd->flags & (EXEC_P | DYNAMIC))) + { + /* Demand paged executables have each space aligned to a + page boundary. Sharable executables (write-protected + text) have just the private (aka data & bss) space aligned + to a page boundary. Ugh. Not true for HPUX. + + The HPUX kernel requires the text to always be page aligned + within the file regardless of the executable's type. */ + if (abfd->flags & (D_PAGED | DYNAMIC) + || (subsection->flags & SEC_CODE) + || ((abfd->flags & WP_TEXT) + && (subsection->flags & SEC_DATA))) + current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE); + + /* Update the exec header. */ + if (subsection->flags & SEC_CODE && exec_header->exec_tfile == 0) + { + exec_header->exec_tmem = section->vma; + exec_header->exec_tfile = current_offset; + } + if (subsection->flags & SEC_DATA && exec_header->exec_dfile == 0) + { + exec_header->exec_dmem = section->vma; + exec_header->exec_dfile = current_offset; + } + + /* Keep track of exactly where we are within a particular + space. This is necessary as the braindamaged HPUX + loader will create holes between subspaces *and* + subspace alignments are *NOT* preserved. What a crock. */ + subspace_offset = subsection->vma; + + /* Only do this for the first subspace within each space. */ + first_subspace = 0; + } + else if (abfd->flags & (EXEC_P | DYNAMIC)) + { + /* The braindamaged HPUX loader may have created a hole + between two subspaces. It is *not* sufficient to use + the alignment specifications within the subspaces to + account for these holes -- I've run into at least one + case where the loader left one code subspace unaligned + in a final executable. + + To combat this we keep a current offset within each space, + and use the subspace vma fields to detect and preserve + holes. What a crock! + + ps. This is not necessary for unloadable space/subspaces. */ + current_offset += subsection->vma - subspace_offset; + if (subsection->flags & SEC_CODE) + exec_header->exec_tsize += subsection->vma - subspace_offset; + else + exec_header->exec_dsize += subsection->vma - subspace_offset; + subspace_offset += subsection->vma - subspace_offset; + } + + + subsection->target_index = total_subspaces++; + /* This is real data to be loaded from the file. */ + if (subsection->flags & SEC_LOAD) + { + /* Update the size of the code & data. */ + if (abfd->flags & (EXEC_P | DYNAMIC) + && subsection->flags & SEC_CODE) + exec_header->exec_tsize += subsection->_cooked_size; + else if (abfd->flags & (EXEC_P | DYNAMIC) + && subsection->flags & SEC_DATA) + exec_header->exec_dsize += subsection->_cooked_size; + som_section_data (subsection)->subspace_dict->file_loc_init_value + = current_offset; + subsection->filepos = current_offset; + current_offset += bfd_section_size (abfd, subsection); + subspace_offset += bfd_section_size (abfd, subsection); + } + /* Looks like uninitialized data. */ + else + { + /* Update the size of the bss section. */ + if (abfd->flags & (EXEC_P | DYNAMIC)) + exec_header->exec_bsize += subsection->_cooked_size; + + som_section_data (subsection)->subspace_dict->file_loc_init_value + = 0; + som_section_data (subsection)->subspace_dict-> + initialization_length = 0; + } + } + /* Goto the next section. */ + section = section->next; + } + + /* Finally compute the file positions for unloadable subspaces. + If building an executable, start the unloadable stuff on its + own page. */ + + if (abfd->flags & (EXEC_P | DYNAMIC)) + current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE); + + obj_som_file_hdr (abfd)->unloadable_sp_location = current_offset; + section = abfd->sections; + for (i = 0; i < num_spaces; i++) + { + asection *subsection; + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + if (abfd->flags & (EXEC_P | DYNAMIC)) + current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE); + + /* Now look for all its subspaces. */ + for (subsection = abfd->sections; + subsection != NULL; + subsection = subsection->next) + { + + if (!som_is_subspace (subsection) + || !som_is_container (section, subsection) + || (subsection->flags & SEC_ALLOC) != 0) + continue; + + subsection->target_index = total_subspaces++; + /* This is real data to be loaded from the file. */ + if ((subsection->flags & SEC_LOAD) == 0) + { + som_section_data (subsection)->subspace_dict->file_loc_init_value + = current_offset; + subsection->filepos = current_offset; + current_offset += bfd_section_size (abfd, subsection); + } + /* Looks like uninitialized data. */ + else + { + som_section_data (subsection)->subspace_dict->file_loc_init_value + = 0; + som_section_data (subsection)->subspace_dict-> + initialization_length = bfd_section_size (abfd, subsection); + } + } + /* Goto the next section. */ + section = section->next; + } + + /* If building an executable, then make sure to seek to and write + one byte at the end of the file to make sure any necessary + zeros are filled in. Ugh. */ + if (abfd->flags & (EXEC_P | DYNAMIC)) + current_offset = SOM_ALIGN (current_offset, PA_PAGESIZE); + if (bfd_seek (abfd, current_offset - 1, SEEK_SET) < 0) + return false; + if (bfd_write ((PTR) "", 1, 1, abfd) != 1) + return false; + + obj_som_file_hdr (abfd)->unloadable_sp_size + = current_offset - obj_som_file_hdr (abfd)->unloadable_sp_location; + + /* Loader fixups are not supported in any way shape or form. */ + obj_som_file_hdr (abfd)->loader_fixup_location = 0; + obj_som_file_hdr (abfd)->loader_fixup_total = 0; + + /* Done. Store the total size of the SOM so far. */ + obj_som_file_hdr (abfd)->som_length = current_offset; + + return true; +} + +/* Finally, scribble out the various headers to the disk. */ + +static boolean +som_finish_writing (abfd) + bfd *abfd; +{ + int num_spaces = som_count_spaces (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + int i, num_syms, strings_size; + int subspace_index = 0; + file_ptr location; + asection *section; + unsigned long current_offset; + unsigned int total_reloc_size; + + /* Next is the symbol table. These are fixed length records. + + Count the number of symbols to determine how much room is needed + in the object file for the symbol table. + + The names of the symbols are stored in a separate string table, + and the index for each symbol name into the string table is computed + below. Therefore, it is not possible to write the symbol table + at this time. + + These used to be output before the subspace contents, but they + were moved here to work around a stupid bug in the hpux linker + (fixed in hpux10). */ + current_offset = obj_som_file_hdr (abfd)->som_length; + + /* Make sure we're on a word boundary. */ + if (current_offset % 4) + current_offset += (4 - (current_offset % 4)); + + num_syms = bfd_get_symcount (abfd); + obj_som_file_hdr (abfd)->symbol_location = current_offset; + obj_som_file_hdr (abfd)->symbol_total = num_syms; + current_offset += num_syms * sizeof (struct symbol_dictionary_record); + + /* Next are the symbol strings. + Align them to a word boundary. */ + if (current_offset % 4) + current_offset += (4 - (current_offset % 4)); + obj_som_file_hdr (abfd)->symbol_strings_location = current_offset; + + /* Scribble out the symbol strings. */ + if (som_write_symbol_strings (abfd, current_offset, syms, + num_syms, &strings_size) + == false) + return false; + + /* Record total string table size in header and update the + current offset. */ + obj_som_file_hdr (abfd)->symbol_strings_size = strings_size; + current_offset += strings_size; + + /* Do prep work before handling fixups. */ + som_prep_for_fixups (abfd, + bfd_get_outsymbols (abfd), + bfd_get_symcount (abfd)); + + /* At the end of the file is the fixup stream which starts on a + word boundary. */ + if (current_offset % 4) + current_offset += (4 - (current_offset % 4)); + obj_som_file_hdr (abfd)->fixup_request_location = current_offset; + + /* Write the fixups and update fields in subspace headers which + relate to the fixup stream. */ + if (som_write_fixups (abfd, current_offset, &total_reloc_size) == false) + return false; + + /* Record the total size of the fixup stream in the file header. */ + obj_som_file_hdr (abfd)->fixup_request_total = total_reloc_size; + + /* Done. Store the total size of the SOM. */ + obj_som_file_hdr (abfd)->som_length = current_offset + total_reloc_size; + + /* Now that the symbol table information is complete, build and + write the symbol table. */ + if (som_build_and_write_symbol_table (abfd) == false) + return false; + + /* Subspaces are written first so that we can set up information + about them in their containing spaces as the subspace is written. */ + + /* Seek to the start of the subspace dictionary records. */ + location = obj_som_file_hdr (abfd)->subspace_location; + if (bfd_seek (abfd, location, SEEK_SET) < 0) + return false; + + section = abfd->sections; + /* Now for each loadable space write out records for its subspaces. */ + for (i = 0; i < num_spaces; i++) + { + asection *subsection; + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + /* Now look for all its subspaces. */ + for (subsection = abfd->sections; + subsection != NULL; + subsection = subsection->next) + { + + /* Skip any section which does not correspond to a space + or subspace. Or does not have SEC_ALLOC set (and therefore + has no real bits on the disk). */ + if (!som_is_subspace (subsection) + || !som_is_container (section, subsection) + || (subsection->flags & SEC_ALLOC) == 0) + continue; + + /* If this is the first subspace for this space, then save + the index of the subspace in its containing space. Also + set "is_loadable" in the containing space. */ + + if (som_section_data (section)->space_dict->subspace_quantity == 0) + { + som_section_data (section)->space_dict->is_loadable = 1; + som_section_data (section)->space_dict->subspace_index + = subspace_index; + } + + /* Increment the number of subspaces seen and the number of + subspaces contained within the current space. */ + subspace_index++; + som_section_data (section)->space_dict->subspace_quantity++; + + /* Mark the index of the current space within the subspace's + dictionary record. */ + som_section_data (subsection)->subspace_dict->space_index = i; + + /* Dump the current subspace header. */ + if (bfd_write ((PTR) som_section_data (subsection)->subspace_dict, + sizeof (struct subspace_dictionary_record), 1, abfd) + != sizeof (struct subspace_dictionary_record)) + return false; + } + /* Goto the next section. */ + section = section->next; + } + + /* Now repeat the process for unloadable subspaces. */ + section = abfd->sections; + /* Now for each space write out records for its subspaces. */ + for (i = 0; i < num_spaces; i++) + { + asection *subsection; + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + /* Now look for all its subspaces. */ + for (subsection = abfd->sections; + subsection != NULL; + subsection = subsection->next) + { + + /* Skip any section which does not correspond to a space or + subspace, or which SEC_ALLOC set (and therefore handled + in the loadable spaces/subspaces code above). */ + + if (!som_is_subspace (subsection) + || !som_is_container (section, subsection) + || (subsection->flags & SEC_ALLOC) != 0) + continue; + + /* If this is the first subspace for this space, then save + the index of the subspace in its containing space. Clear + "is_loadable". */ + + if (som_section_data (section)->space_dict->subspace_quantity == 0) + { + som_section_data (section)->space_dict->is_loadable = 0; + som_section_data (section)->space_dict->subspace_index + = subspace_index; + } + + /* Increment the number of subspaces seen and the number of + subspaces contained within the current space. */ + som_section_data (section)->space_dict->subspace_quantity++; + subspace_index++; + + /* Mark the index of the current space within the subspace's + dictionary record. */ + som_section_data (subsection)->subspace_dict->space_index = i; + + /* Dump this subspace header. */ + if (bfd_write ((PTR) som_section_data (subsection)->subspace_dict, + sizeof (struct subspace_dictionary_record), 1, abfd) + != sizeof (struct subspace_dictionary_record)) + return false; + } + /* Goto the next section. */ + section = section->next; + } + + /* All the subspace dictiondary records are written, and all the + fields are set up in the space dictionary records. + + Seek to the right location and start writing the space + dictionary records. */ + location = obj_som_file_hdr (abfd)->space_location; + if (bfd_seek (abfd, location, SEEK_SET) < 0) + return false; + + section = abfd->sections; + for (i = 0; i < num_spaces; i++) + { + + /* Find a space. */ + while (!som_is_space (section)) + section = section->next; + + /* Dump its header */ + if (bfd_write ((PTR) som_section_data (section)->space_dict, + sizeof (struct space_dictionary_record), 1, abfd) + != sizeof (struct space_dictionary_record)) + return false; + + /* Goto the next section. */ + section = section->next; + } + + /* Setting of the system_id has to happen very late now that copying of + BFD private data happens *after* section contents are set. */ + if (abfd->flags & (EXEC_P | DYNAMIC)) + obj_som_file_hdr(abfd)->system_id = obj_som_exec_data (abfd)->system_id; + else if (bfd_get_mach (abfd) == pa11) + obj_som_file_hdr(abfd)->system_id = CPU_PA_RISC1_1; + else + obj_som_file_hdr(abfd)->system_id = CPU_PA_RISC1_0; + + /* Compute the checksum for the file header just before writing + the header to disk. */ + obj_som_file_hdr (abfd)->checksum = som_compute_checksum (abfd); + + /* Only thing left to do is write out the file header. It is always + at location zero. Seek there and write it. */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) < 0) + return false; + if (bfd_write ((PTR) obj_som_file_hdr (abfd), + sizeof (struct header), 1, abfd) + != sizeof (struct header)) + return false; + + /* Now write the exec header. */ + if (abfd->flags & (EXEC_P | DYNAMIC)) + { + long tmp; + struct som_exec_auxhdr *exec_header; + + exec_header = obj_som_exec_hdr (abfd); + exec_header->exec_entry = bfd_get_start_address (abfd); + exec_header->exec_flags = obj_som_exec_data (abfd)->exec_flags; + + /* Oh joys. Ram some of the BSS data into the DATA section + to be compatable with how the hp linker makes objects + (saves memory space). */ + tmp = exec_header->exec_dsize; + tmp = SOM_ALIGN (tmp, PA_PAGESIZE); + exec_header->exec_bsize -= (tmp - exec_header->exec_dsize); + if (exec_header->exec_bsize < 0) + exec_header->exec_bsize = 0; + exec_header->exec_dsize = tmp; + + if (bfd_seek (abfd, obj_som_file_hdr (abfd)->aux_header_location, + SEEK_SET) < 0) + return false; + + if (bfd_write ((PTR) exec_header, AUX_HDR_SIZE, 1, abfd) + != AUX_HDR_SIZE) + return false; + } + return true; +} + +/* Compute and return the checksum for a SOM file header. */ + +static unsigned long +som_compute_checksum (abfd) + bfd *abfd; +{ + unsigned long checksum, count, i; + unsigned long *buffer = (unsigned long *) obj_som_file_hdr (abfd); + + checksum = 0; + count = sizeof (struct header) / sizeof (unsigned long); + for (i = 0; i < count; i++) + checksum ^= *(buffer + i); + + return checksum; +} + +static void +som_bfd_derive_misc_symbol_info (abfd, sym, info) + bfd *abfd; + asymbol *sym; + struct som_misc_symbol_info *info; +{ + /* Initialize. */ + memset (info, 0, sizeof (struct som_misc_symbol_info)); + + /* The HP SOM linker requires detailed type information about + all symbols (including undefined symbols!). Unfortunately, + the type specified in an import/export statement does not + always match what the linker wants. Severe braindamage. */ + + /* Section symbols will not have a SOM symbol type assigned to + them yet. Assign all section symbols type ST_DATA. */ + if (sym->flags & BSF_SECTION_SYM) + info->symbol_type = ST_DATA; + else + { + /* Common symbols must have scope SS_UNSAT and type + ST_STORAGE or the linker will choke. */ + if (bfd_is_com_section (sym->section)) + { + info->symbol_scope = SS_UNSAT; + info->symbol_type = ST_STORAGE; + } + + /* It is possible to have a symbol without an associated + type. This happens if the user imported the symbol + without a type and the symbol was never defined + locally. If BSF_FUNCTION is set for this symbol, then + assign it type ST_CODE (the HP linker requires undefined + external functions to have type ST_CODE rather than ST_ENTRY). */ + else if ((som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN + || som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE) + && bfd_is_und_section (sym->section) + && sym->flags & BSF_FUNCTION) + info->symbol_type = ST_CODE; + + /* Handle function symbols which were defined in this file. + They should have type ST_ENTRY. Also retrieve the argument + relocation bits from the SOM backend information. */ + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_ENTRY + || (som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE + && (sym->flags & BSF_FUNCTION)) + || (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN + && (sym->flags & BSF_FUNCTION))) + { + info->symbol_type = ST_ENTRY; + info->arg_reloc = som_symbol_data (sym)->tc_data.hppa_arg_reloc; + } + + /* If the type is unknown at this point, it should be ST_DATA or + ST_CODE (function/ST_ENTRY symbols were handled as special + cases above). */ + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_UNKNOWN) + { + if (sym->section->flags & SEC_CODE) + info->symbol_type = ST_CODE; + else + info->symbol_type = ST_DATA; + } + + /* From now on it's a very simple mapping. */ + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_ABSOLUTE) + info->symbol_type = ST_ABSOLUTE; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_CODE) + info->symbol_type = ST_CODE; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_DATA) + info->symbol_type = ST_DATA; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_MILLICODE) + info->symbol_type = ST_MILLICODE; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_PLABEL) + info->symbol_type = ST_PLABEL; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_PRI_PROG) + info->symbol_type = ST_PRI_PROG; + else if (som_symbol_data (sym)->som_type == SYMBOL_TYPE_SEC_PROG) + info->symbol_type = ST_SEC_PROG; + } + + /* Now handle the symbol's scope. Exported data which is not + in the common section has scope SS_UNIVERSAL. Note scope + of common symbols was handled earlier! */ + if (bfd_is_und_section (sym->section)) + info->symbol_scope = SS_UNSAT; + else if (sym->flags & BSF_EXPORT && ! bfd_is_com_section (sym->section)) + info->symbol_scope = SS_UNIVERSAL; + /* Anything else which is not in the common section has scope + SS_LOCAL. */ + else if (! bfd_is_com_section (sym->section)) + info->symbol_scope = SS_LOCAL; + + /* Now set the symbol_info field. It has no real meaning + for undefined or common symbols, but the HP linker will + choke if it's not set to some "reasonable" value. We + use zero as a reasonable value. */ + if (bfd_is_com_section (sym->section) + || bfd_is_und_section (sym->section) + || bfd_is_abs_section (sym->section)) + info->symbol_info = 0; + /* For all other symbols, the symbol_info field contains the + subspace index of the space this symbol is contained in. */ + else + info->symbol_info = sym->section->target_index; + + /* Set the symbol's value. */ + info->symbol_value = sym->value + sym->section->vma; +} + +/* Build and write, in one big chunk, the entire symbol table for + this BFD. */ + +static boolean +som_build_and_write_symbol_table (abfd) + bfd *abfd; +{ + unsigned int num_syms = bfd_get_symcount (abfd); + file_ptr symtab_location = obj_som_file_hdr (abfd)->symbol_location; + asymbol **bfd_syms = obj_som_sorted_syms (abfd); + struct symbol_dictionary_record *som_symtab = NULL; + int i, symtab_size; + + /* Compute total symbol table size and allocate a chunk of memory + to hold the symbol table as we build it. */ + symtab_size = num_syms * sizeof (struct symbol_dictionary_record); + som_symtab = (struct symbol_dictionary_record *) bfd_malloc (symtab_size); + if (som_symtab == NULL && symtab_size != 0) + goto error_return; + memset (som_symtab, 0, symtab_size); + + /* Walk over each symbol. */ + for (i = 0; i < num_syms; i++) + { + struct som_misc_symbol_info info; + + /* This is really an index into the symbol strings table. + By the time we get here, the index has already been + computed and stored into the name field in the BFD symbol. */ + som_symtab[i].name.n_strx = som_symbol_data(bfd_syms[i])->stringtab_offset; + + /* Derive SOM information from the BFD symbol. */ + som_bfd_derive_misc_symbol_info (abfd, bfd_syms[i], &info); + + /* Now use it. */ + som_symtab[i].symbol_type = info.symbol_type; + som_symtab[i].symbol_scope = info.symbol_scope; + som_symtab[i].arg_reloc = info.arg_reloc; + som_symtab[i].symbol_info = info.symbol_info; + som_symtab[i].symbol_value = info.symbol_value; + } + + /* Everything is ready, seek to the right location and + scribble out the symbol table. */ + if (bfd_seek (abfd, symtab_location, SEEK_SET) != 0) + return false; + + if (bfd_write ((PTR) som_symtab, symtab_size, 1, abfd) != symtab_size) + goto error_return; + + if (som_symtab != NULL) + free (som_symtab); + return true; + error_return: + if (som_symtab != NULL) + free (som_symtab); + return false; +} + +/* Write an object in SOM format. */ + +static boolean +som_write_object_contents (abfd) + bfd *abfd; +{ + if (abfd->output_has_begun == false) + { + /* Set up fixed parts of the file, space, and subspace headers. + Notify the world that output has begun. */ + som_prep_headers (abfd); + abfd->output_has_begun = true; + /* Start writing the object file. This include all the string + tables, fixup streams, and other portions of the object file. */ + som_begin_writing (abfd); + } + + return (som_finish_writing (abfd)); +} + + +/* Read and save the string table associated with the given BFD. */ + +static boolean +som_slurp_string_table (abfd) + bfd *abfd; +{ + char *stringtab; + + /* Use the saved version if its available. */ + if (obj_som_stringtab (abfd) != NULL) + return true; + + /* I don't think this can currently happen, and I'm not sure it should + really be an error, but it's better than getting unpredictable results + from the host's malloc when passed a size of zero. */ + if (obj_som_stringtab_size (abfd) == 0) + { + bfd_set_error (bfd_error_no_symbols); + return false; + } + + /* Allocate and read in the string table. */ + stringtab = bfd_malloc (obj_som_stringtab_size (abfd)); + if (stringtab == NULL) + return false; + memset (stringtab, 0, obj_som_stringtab_size (abfd)); + + if (bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET) < 0) + return false; + + if (bfd_read (stringtab, obj_som_stringtab_size (abfd), 1, abfd) + != obj_som_stringtab_size (abfd)) + return false; + + /* Save our results and return success. */ + obj_som_stringtab (abfd) = stringtab; + return true; +} + +/* Return the amount of data (in bytes) required to hold the symbol + table for this object. */ + +static long +som_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (!som_slurp_symbol_table (abfd)) + return -1; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (asymbol *)); +} + +/* Convert from a SOM subspace index to a BFD section. */ + +static asection * +bfd_section_from_som_symbol (abfd, symbol) + bfd *abfd; + struct symbol_dictionary_record *symbol; +{ + asection *section; + + /* The meaning of the symbol_info field changes for functions + within executables. So only use the quick symbol_info mapping for + incomplete objects and non-function symbols in executables. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 + || (symbol->symbol_type != ST_ENTRY + && symbol->symbol_type != ST_PRI_PROG + && symbol->symbol_type != ST_SEC_PROG + && symbol->symbol_type != ST_MILLICODE)) + { + unsigned int index = symbol->symbol_info; + for (section = abfd->sections; section != NULL; section = section->next) + if (section->target_index == index && som_is_subspace (section)) + return section; + + /* Could be a symbol from an external library (such as an OMOS + shared library). Don't abort. */ + return bfd_abs_section_ptr; + + } + else + { + unsigned int value = symbol->symbol_value; + + /* For executables we will have to use the symbol's address and + find out what section would contain that address. Yuk. */ + for (section = abfd->sections; section; section = section->next) + { + if (value >= section->vma + && value <= section->vma + section->_cooked_size + && som_is_subspace (section)) + return section; + } + + /* Could be a symbol from an external library (such as an OMOS + shared library). Don't abort. */ + return bfd_abs_section_ptr; + + } +} + +/* Read and save the symbol table associated with the given BFD. */ + +static unsigned int +som_slurp_symbol_table (abfd) + bfd *abfd; +{ + int symbol_count = bfd_get_symcount (abfd); + int symsize = sizeof (struct symbol_dictionary_record); + char *stringtab; + struct symbol_dictionary_record *buf = NULL, *bufp, *endbufp; + som_symbol_type *sym, *symbase; + + /* Return saved value if it exists. */ + if (obj_som_symtab (abfd) != NULL) + goto successful_return; + + /* Special case. This is *not* an error. */ + if (symbol_count == 0) + goto successful_return; + + if (!som_slurp_string_table (abfd)) + goto error_return; + + stringtab = obj_som_stringtab (abfd); + + symbase = ((som_symbol_type *) + bfd_malloc (symbol_count * sizeof (som_symbol_type))); + if (symbase == NULL) + goto error_return; + memset (symbase, 0, symbol_count * sizeof (som_symbol_type)); + + /* Read in the external SOM representation. */ + buf = bfd_malloc (symbol_count * symsize); + if (buf == NULL && symbol_count * symsize != 0) + goto error_return; + if (bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET) < 0) + goto error_return; + if (bfd_read (buf, symbol_count * symsize, 1, abfd) + != symbol_count * symsize) + goto error_return; + + /* Iterate over all the symbols and internalize them. */ + endbufp = buf + symbol_count; + for (bufp = buf, sym = symbase; bufp < endbufp; ++bufp) + { + + /* I don't think we care about these. */ + if (bufp->symbol_type == ST_SYM_EXT + || bufp->symbol_type == ST_ARG_EXT) + continue; + + /* Set some private data we care about. */ + if (bufp->symbol_type == ST_NULL) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_UNKNOWN; + else if (bufp->symbol_type == ST_ABSOLUTE) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_ABSOLUTE; + else if (bufp->symbol_type == ST_DATA) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_DATA; + else if (bufp->symbol_type == ST_CODE) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_CODE; + else if (bufp->symbol_type == ST_PRI_PROG) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_PRI_PROG; + else if (bufp->symbol_type == ST_SEC_PROG) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_SEC_PROG; + else if (bufp->symbol_type == ST_ENTRY) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_ENTRY; + else if (bufp->symbol_type == ST_MILLICODE) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_MILLICODE; + else if (bufp->symbol_type == ST_PLABEL) + som_symbol_data (sym)->som_type = SYMBOL_TYPE_PLABEL; + else + som_symbol_data (sym)->som_type = SYMBOL_TYPE_UNKNOWN; + som_symbol_data (sym)->tc_data.hppa_arg_reloc = bufp->arg_reloc; + + /* Some reasonable defaults. */ + sym->symbol.the_bfd = abfd; + sym->symbol.name = bufp->name.n_strx + stringtab; + sym->symbol.value = bufp->symbol_value; + sym->symbol.section = 0; + sym->symbol.flags = 0; + + switch (bufp->symbol_type) + { + case ST_ENTRY: + case ST_MILLICODE: + sym->symbol.flags |= BSF_FUNCTION; + sym->symbol.value &= ~0x3; + break; + + case ST_STUB: + case ST_CODE: + case ST_PRI_PROG: + case ST_SEC_PROG: + sym->symbol.value &= ~0x3; + /* If the symbol's scope is ST_UNSAT, then these are + undefined function symbols. */ + if (bufp->symbol_scope == SS_UNSAT) + sym->symbol.flags |= BSF_FUNCTION; + + + default: + break; + } + + /* Handle scoping and section information. */ + switch (bufp->symbol_scope) + { + /* symbol_info field is undefined for SS_EXTERNAL and SS_UNSAT symbols, + so the section associated with this symbol can't be known. */ + case SS_EXTERNAL: + if (bufp->symbol_type != ST_STORAGE) + sym->symbol.section = bfd_und_section_ptr; + else + sym->symbol.section = bfd_com_section_ptr; + sym->symbol.flags |= (BSF_EXPORT | BSF_GLOBAL); + break; + + case SS_UNSAT: + if (bufp->symbol_type != ST_STORAGE) + sym->symbol.section = bfd_und_section_ptr; + else + sym->symbol.section = bfd_com_section_ptr; + break; + + case SS_UNIVERSAL: + sym->symbol.flags |= (BSF_EXPORT | BSF_GLOBAL); + sym->symbol.section = bfd_section_from_som_symbol (abfd, bufp); + sym->symbol.value -= sym->symbol.section->vma; + break; + +#if 0 + /* SS_GLOBAL and SS_LOCAL are two names for the same thing. + Sound dumb? It is. */ + case SS_GLOBAL: +#endif + case SS_LOCAL: + sym->symbol.flags |= BSF_LOCAL; + sym->symbol.section = bfd_section_from_som_symbol (abfd, bufp); + sym->symbol.value -= sym->symbol.section->vma; + break; + } + + /* Mark section symbols and symbols used by the debugger. + Note $START$ is a magic code symbol, NOT a section symbol. */ + if (sym->symbol.name[0] == '$' + && sym->symbol.name[strlen (sym->symbol.name) - 1] == '$' + && !strcmp (sym->symbol.name, sym->symbol.section->name)) + sym->symbol.flags |= BSF_SECTION_SYM; + else if (!strncmp (sym->symbol.name, "L$0\002", 4)) + { + sym->symbol.flags |= BSF_SECTION_SYM; + sym->symbol.name = sym->symbol.section->name; + } + else if (!strncmp (sym->symbol.name, "L$0\001", 4)) + sym->symbol.flags |= BSF_DEBUGGING; + + /* Note increment at bottom of loop, since we skip some symbols + we can not include it as part of the for statement. */ + sym++; + } + + /* Save our results and return success. */ + obj_som_symtab (abfd) = symbase; + successful_return: + if (buf != NULL) + free (buf); + return (true); + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Canonicalize a SOM symbol table. Return the number of entries + in the symbol table. */ + +static long +som_get_symtab (abfd, location) + bfd *abfd; + asymbol **location; +{ + int i; + som_symbol_type *symbase; + + if (!som_slurp_symbol_table (abfd)) + return -1; + + i = bfd_get_symcount (abfd); + symbase = obj_som_symtab (abfd); + + for (; i > 0; i--, location++, symbase++) + *location = &symbase->symbol; + + /* Final null pointer. */ + *location = 0; + return (bfd_get_symcount (abfd)); +} + +/* Make a SOM symbol. There is nothing special to do here. */ + +static asymbol * +som_make_empty_symbol (abfd) + bfd *abfd; +{ + som_symbol_type *new = + (som_symbol_type *) bfd_zalloc (abfd, sizeof (som_symbol_type)); + if (new == NULL) + return 0; + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +/* Print symbol information. */ + +static void +som_print_symbol (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf (file, "som "); + fprintf_vma (file, symbol->value); + fprintf (file, " %lx", (long) symbol->flags); + break; + case bfd_print_symbol_all: + { + CONST char *section_name; + section_name = symbol->section ? symbol->section->name : "(*none*)"; + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %s\t%s", section_name, symbol->name); + break; + } + } +} + +static boolean +som_bfd_is_local_label (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + return (sym->name[0] == 'L' && sym->name[1] == '$'); +} + +/* Count or process variable-length SOM fixup records. + + To avoid code duplication we use this code both to compute the number + of relocations requested by a stream, and to internalize the stream. + + When computing the number of relocations requested by a stream the + variables rptr, section, and symbols have no meaning. + + Return the number of relocations requested by the fixup stream. When + not just counting + + This needs at least two or three more passes to get it cleaned up. */ + +static unsigned int +som_set_reloc_info (fixup, end, internal_relocs, section, symbols, just_count) + unsigned char *fixup; + unsigned int end; + arelent *internal_relocs; + asection *section; + asymbol **symbols; + boolean just_count; +{ + unsigned int op, varname, deallocate_contents = 0; + unsigned char *end_fixups = &fixup[end]; + const struct fixup_format *fp; + char *cp; + unsigned char *save_fixup; + int variables[26], stack[20], c, v, count, prev_fixup, *sp, saved_unwind_bits; + const int *subop; + arelent *rptr= internal_relocs; + unsigned int offset = 0; + +#define var(c) variables[(c) - 'A'] +#define push(v) (*sp++ = (v)) +#define pop() (*--sp) +#define emptystack() (sp == stack) + + som_initialize_reloc_queue (reloc_queue); + memset (variables, 0, sizeof (variables)); + memset (stack, 0, sizeof (stack)); + count = 0; + prev_fixup = 0; + saved_unwind_bits = 0; + sp = stack; + + while (fixup < end_fixups) + { + + /* Save pointer to the start of this fixup. We'll use + it later to determine if it is necessary to put this fixup + on the queue. */ + save_fixup = fixup; + + /* Get the fixup code and its associated format. */ + op = *fixup++; + fp = &som_fixup_formats[op]; + + /* Handle a request for a previous fixup. */ + if (*fp->format == 'P') + { + /* Get pointer to the beginning of the prev fixup, move + the repeated fixup to the head of the queue. */ + fixup = reloc_queue[fp->D].reloc; + som_reloc_queue_fix (reloc_queue, fp->D); + prev_fixup = 1; + + /* Get the fixup code and its associated format. */ + op = *fixup++; + fp = &som_fixup_formats[op]; + } + + /* If this fixup will be passed to BFD, set some reasonable defaults. */ + if (! just_count + && som_hppa_howto_table[op].type != R_NO_RELOCATION + && som_hppa_howto_table[op].type != R_DATA_OVERRIDE) + { + rptr->address = offset; + rptr->howto = &som_hppa_howto_table[op]; + rptr->addend = 0; + rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + + /* Set default input length to 0. Get the opcode class index + into D. */ + var ('L') = 0; + var ('D') = fp->D; + var ('U') = saved_unwind_bits; + + /* Get the opcode format. */ + cp = fp->format; + + /* Process the format string. Parsing happens in two phases, + parse RHS, then assign to LHS. Repeat until no more + characters in the format string. */ + while (*cp) + { + /* The variable this pass is going to compute a value for. */ + varname = *cp++; + + /* Start processing RHS. Continue until a NULL or '=' is found. */ + do + { + c = *cp++; + + /* If this is a variable, push it on the stack. */ + if (isupper (c)) + push (var (c)); + + /* If this is a lower case letter, then it represents + additional data from the fixup stream to be pushed onto + the stack. */ + else if (islower (c)) + { + int bits = (c - 'a') * 8; + for (v = 0; c > 'a'; --c) + v = (v << 8) | *fixup++; + if (varname == 'V') + v = sign_extend (v, bits); + push (v); + } + + /* A decimal constant. Push it on the stack. */ + else if (isdigit (c)) + { + v = c - '0'; + while (isdigit (*cp)) + v = (v * 10) + (*cp++ - '0'); + push (v); + } + else + + /* An operator. Pop two two values from the stack and + use them as operands to the given operation. Push + the result of the operation back on the stack. */ + switch (c) + { + case '+': + v = pop (); + v += pop (); + push (v); + break; + case '*': + v = pop (); + v *= pop (); + push (v); + break; + case '<': + v = pop (); + v = pop () << v; + push (v); + break; + default: + abort (); + } + } + while (*cp && *cp != '='); + + /* Move over the equal operator. */ + cp++; + + /* Pop the RHS off the stack. */ + c = pop (); + + /* Perform the assignment. */ + var (varname) = c; + + /* Handle side effects. and special 'O' stack cases. */ + switch (varname) + { + /* Consume some bytes from the input space. */ + case 'L': + offset += c; + break; + /* A symbol to use in the relocation. Make a note + of this if we are not just counting. */ + case 'S': + if (! just_count) + rptr->sym_ptr_ptr = &symbols[c]; + break; + /* Argument relocation bits for a function call. */ + case 'R': + if (! just_count) + { + unsigned int tmp = var ('R'); + rptr->addend = 0; + + if ((som_hppa_howto_table[op].type == R_PCREL_CALL + && R_PCREL_CALL + 10 > op) + || (som_hppa_howto_table[op].type == R_ABS_CALL + && R_ABS_CALL + 10 > op)) + { + /* Simple encoding. */ + if (tmp > 4) + { + tmp -= 5; + rptr->addend |= 1; + } + if (tmp == 4) + rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4 | 1 << 2; + else if (tmp == 3) + rptr->addend |= 1 << 8 | 1 << 6 | 1 << 4; + else if (tmp == 2) + rptr->addend |= 1 << 8 | 1 << 6; + else if (tmp == 1) + rptr->addend |= 1 << 8; + } + else + { + unsigned int tmp1, tmp2; + + /* First part is easy -- low order two bits are + directly copied, then shifted away. */ + rptr->addend = tmp & 0x3; + tmp >>= 2; + + /* Diving the result by 10 gives us the second + part. If it is 9, then the first two words + are a double precision paramater, else it is + 3 * the first arg bits + the 2nd arg bits. */ + tmp1 = tmp / 10; + tmp -= tmp1 * 10; + if (tmp1 == 9) + rptr->addend += (0xe << 6); + else + { + /* Get the two pieces. */ + tmp2 = tmp1 / 3; + tmp1 -= tmp2 * 3; + /* Put them in the addend. */ + rptr->addend += (tmp2 << 8) + (tmp1 << 6); + } + + /* What's left is the third part. It's unpacked + just like the second. */ + if (tmp == 9) + rptr->addend += (0xe << 2); + else + { + tmp2 = tmp / 3; + tmp -= tmp2 * 3; + rptr->addend += (tmp2 << 4) + (tmp << 2); + } + } + rptr->addend = HPPA_R_ADDEND (rptr->addend, 0); + } + break; + /* Handle the linker expression stack. */ + case 'O': + switch (op) + { + case R_COMP1: + subop = comp1_opcodes; + break; + case R_COMP2: + subop = comp2_opcodes; + break; + case R_COMP3: + subop = comp3_opcodes; + break; + default: + abort (); + } + while (*subop <= (unsigned char) c) + ++subop; + --subop; + break; + /* The lower 32unwind bits must be persistent. */ + case 'U': + saved_unwind_bits = var ('U'); + break; + + default: + break; + } + } + + /* If we used a previous fixup, clean up after it. */ + if (prev_fixup) + { + fixup = save_fixup + 1; + prev_fixup = 0; + } + /* Queue it. */ + else if (fixup > save_fixup + 1) + som_reloc_queue_insert (save_fixup, fixup - save_fixup, reloc_queue); + + /* We do not pass R_DATA_OVERRIDE or R_NO_RELOCATION + fixups to BFD. */ + if (som_hppa_howto_table[op].type != R_DATA_OVERRIDE + && som_hppa_howto_table[op].type != R_NO_RELOCATION) + { + /* Done with a single reloction. Loop back to the top. */ + if (! just_count) + { + if (som_hppa_howto_table[op].type == R_ENTRY) + rptr->addend = var ('T'); + else if (som_hppa_howto_table[op].type == R_EXIT) + rptr->addend = var ('U'); + else if (som_hppa_howto_table[op].type == R_PCREL_CALL + || som_hppa_howto_table[op].type == R_ABS_CALL) + ; + else if (som_hppa_howto_table[op].type == R_DATA_ONE_SYMBOL) + { + unsigned addend = var ('V'); + + /* Try what was specified in R_DATA_OVERRIDE first + (if anything). Then the hard way using the + section contents. */ + rptr->addend = var ('V'); + + if (rptr->addend == 0 && !section->contents) + { + /* Got to read the damn contents first. We don't + bother saving the contents (yet). Add it one + day if the need arises. */ + section->contents = bfd_malloc (section->_raw_size); + if (section->contents == NULL) + return -1; + + deallocate_contents = 1; + bfd_get_section_contents (section->owner, + section, + section->contents, + 0, + section->_raw_size); + } + else if (rptr->addend == 0) + rptr->addend = bfd_get_32 (section->owner, + (section->contents + + offset - var ('L'))); + + } + else + rptr->addend = var ('V'); + rptr++; + } + count++; + /* Now that we've handled a "full" relocation, reset + some state. */ + memset (variables, 0, sizeof (variables)); + memset (stack, 0, sizeof (stack)); + } + } + if (deallocate_contents) + free (section->contents); + + return count; + +#undef var +#undef push +#undef pop +#undef emptystack +} + +/* Read in the relocs (aka fixups in SOM terms) for a section. + + som_get_reloc_upper_bound calls this routine with JUST_COUNT + set to true to indicate it only needs a count of the number + of actual relocations. */ + +static boolean +som_slurp_reloc_table (abfd, section, symbols, just_count) + bfd *abfd; + asection *section; + asymbol **symbols; + boolean just_count; +{ + char *external_relocs; + unsigned int fixup_stream_size; + arelent *internal_relocs; + unsigned int num_relocs; + + fixup_stream_size = som_section_data (section)->reloc_size; + /* If there were no relocations, then there is nothing to do. */ + if (section->reloc_count == 0) + return true; + + /* If reloc_count is -1, then the relocation stream has not been + parsed. We must do so now to know how many relocations exist. */ + if (section->reloc_count == -1) + { + external_relocs = (char *) bfd_malloc (fixup_stream_size); + if (external_relocs == (char *) NULL) + return false; + /* Read in the external forms. */ + if (bfd_seek (abfd, + obj_som_reloc_filepos (abfd) + section->rel_filepos, + SEEK_SET) + != 0) + return false; + if (bfd_read (external_relocs, 1, fixup_stream_size, abfd) + != fixup_stream_size) + return false; + + /* Let callers know how many relocations found. + also save the relocation stream as we will + need it again. */ + section->reloc_count = som_set_reloc_info (external_relocs, + fixup_stream_size, + NULL, NULL, NULL, true); + + som_section_data (section)->reloc_stream = external_relocs; + } + + /* If the caller only wanted a count, then return now. */ + if (just_count) + return true; + + num_relocs = section->reloc_count; + external_relocs = som_section_data (section)->reloc_stream; + /* Return saved information about the relocations if it is available. */ + if (section->relocation != (arelent *) NULL) + return true; + + internal_relocs = (arelent *) + bfd_zalloc (abfd, (num_relocs * sizeof (arelent))); + if (internal_relocs == (arelent *) NULL) + return false; + + /* Process and internalize the relocations. */ + som_set_reloc_info (external_relocs, fixup_stream_size, + internal_relocs, section, symbols, false); + + /* We're done with the external relocations. Free them. */ + free (external_relocs); + + /* Save our results and return success. */ + section->relocation = internal_relocs; + return (true); +} + +/* Return the number of bytes required to store the relocation + information associated with the given section. */ + +static long +som_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + /* If section has relocations, then read in the relocation stream + and parse it to determine how many relocations exist. */ + if (asect->flags & SEC_RELOC) + { + if (! som_slurp_reloc_table (abfd, asect, NULL, true)) + return -1; + return (asect->reloc_count + 1) * sizeof (arelent *); + } + /* There are no relocations. */ + return 0; +} + +/* Convert relocations from SOM (external) form into BFD internal + form. Return the number of relocations. */ + +static long +som_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr; + int count; + + if (som_slurp_reloc_table (abfd, section, symbols, false) == false) + return -1; + + count = section->reloc_count; + tblptr = section->relocation; + + while (count--) + *relptr++ = tblptr++; + + *relptr = (arelent *) NULL; + return section->reloc_count; +} + +extern const bfd_target som_vec; + +/* A hook to set up object file dependent section information. */ + +static boolean +som_new_section_hook (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + newsect->used_by_bfd = + (PTR) bfd_zalloc (abfd, sizeof (struct som_section_data_struct)); + if (!newsect->used_by_bfd) + return false; + newsect->alignment_power = 3; + + /* We allow more than three sections internally */ + return true; +} + +/* Copy any private info we understand from the input symbol + to the output symbol. */ + +static boolean +som_bfd_copy_private_symbol_data (ibfd, isymbol, obfd, osymbol) + bfd *ibfd; + asymbol *isymbol; + bfd *obfd; + asymbol *osymbol; +{ + struct som_symbol *input_symbol = (struct som_symbol *) isymbol; + struct som_symbol *output_symbol = (struct som_symbol *) osymbol; + + /* One day we may try to grok other private data. */ + if (ibfd->xvec->flavour != bfd_target_som_flavour + || obfd->xvec->flavour != bfd_target_som_flavour) + return false; + + /* The only private information we need to copy is the argument relocation + bits. */ + output_symbol->tc_data.hppa_arg_reloc = input_symbol->tc_data.hppa_arg_reloc; + + return true; +} + +/* Copy any private info we understand from the input section + to the output section. */ +static boolean +som_bfd_copy_private_section_data (ibfd, isection, obfd, osection) + bfd *ibfd; + asection *isection; + bfd *obfd; + asection *osection; +{ + /* One day we may try to grok other private data. */ + if (ibfd->xvec->flavour != bfd_target_som_flavour + || obfd->xvec->flavour != bfd_target_som_flavour + || (!som_is_space (isection) && !som_is_subspace (isection))) + return true; + + som_section_data (osection)->copy_data + = (struct som_copyable_section_data_struct *) + bfd_zalloc (obfd, sizeof (struct som_copyable_section_data_struct)); + if (som_section_data (osection)->copy_data == NULL) + return false; + + memcpy (som_section_data (osection)->copy_data, + som_section_data (isection)->copy_data, + sizeof (struct som_copyable_section_data_struct)); + + /* Reparent if necessary. */ + if (som_section_data (osection)->copy_data->container) + som_section_data (osection)->copy_data->container = + som_section_data (osection)->copy_data->container->output_section; + + return true; +} + +/* Copy any private info we understand from the input bfd + to the output bfd. */ + +static boolean +som_bfd_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd, *obfd; +{ + /* One day we may try to grok other private data. */ + if (ibfd->xvec->flavour != bfd_target_som_flavour + || obfd->xvec->flavour != bfd_target_som_flavour) + return true; + + /* Allocate some memory to hold the data we need. */ + obj_som_exec_data (obfd) = (struct som_exec_data *) + bfd_zalloc (obfd, sizeof (struct som_exec_data)); + if (obj_som_exec_data (obfd) == NULL) + return false; + + /* Now copy the data. */ + memcpy (obj_som_exec_data (obfd), obj_som_exec_data (ibfd), + sizeof (struct som_exec_data)); + + return true; +} + +/* Set backend info for sections which can not be described + in the BFD data structures. */ + +boolean +bfd_som_set_section_attributes (section, defined, private, sort_key, spnum) + asection *section; + int defined; + int private; + unsigned int sort_key; + int spnum; +{ + /* Allocate memory to hold the magic information. */ + if (som_section_data (section)->copy_data == NULL) + { + som_section_data (section)->copy_data + = (struct som_copyable_section_data_struct *) + bfd_zalloc (section->owner, + sizeof (struct som_copyable_section_data_struct)); + if (som_section_data (section)->copy_data == NULL) + return false; + } + som_section_data (section)->copy_data->sort_key = sort_key; + som_section_data (section)->copy_data->is_defined = defined; + som_section_data (section)->copy_data->is_private = private; + som_section_data (section)->copy_data->container = section; + som_section_data (section)->copy_data->space_number = spnum; + return true; +} + +/* Set backend info for subsections which can not be described + in the BFD data structures. */ + +boolean +bfd_som_set_subsection_attributes (section, container, access, + sort_key, quadrant) + asection *section; + asection *container; + int access; + unsigned int sort_key; + int quadrant; +{ + /* Allocate memory to hold the magic information. */ + if (som_section_data (section)->copy_data == NULL) + { + som_section_data (section)->copy_data + = (struct som_copyable_section_data_struct *) + bfd_zalloc (section->owner, + sizeof (struct som_copyable_section_data_struct)); + if (som_section_data (section)->copy_data == NULL) + return false; + } + som_section_data (section)->copy_data->sort_key = sort_key; + som_section_data (section)->copy_data->access_control_bits = access; + som_section_data (section)->copy_data->quadrant = quadrant; + som_section_data (section)->copy_data->container = container; + return true; +} + +/* Set the full SOM symbol type. SOM needs far more symbol information + than any other object file format I'm aware of. It is mandatory + to be able to know if a symbol is an entry point, millicode, data, + code, absolute, storage request, or procedure label. If you get + the symbol type wrong your program will not link. */ + +void +bfd_som_set_symbol_type (symbol, type) + asymbol *symbol; + unsigned int type; +{ + som_symbol_data (symbol)->som_type = type; +} + +/* Attach an auxiliary header to the BFD backend so that it may be + written into the object file. */ +boolean +bfd_som_attach_aux_hdr (abfd, type, string) + bfd *abfd; + int type; + char *string; +{ + if (type == VERSION_AUX_ID) + { + int len = strlen (string); + int pad = 0; + + if (len % 4) + pad = (4 - (len % 4)); + obj_som_version_hdr (abfd) = (struct user_string_aux_hdr *) + bfd_zalloc (abfd, sizeof (struct aux_id) + + sizeof (unsigned int) + len + pad); + if (!obj_som_version_hdr (abfd)) + return false; + obj_som_version_hdr (abfd)->header_id.type = VERSION_AUX_ID; + obj_som_version_hdr (abfd)->header_id.length = len + pad; + obj_som_version_hdr (abfd)->header_id.length += sizeof (int); + obj_som_version_hdr (abfd)->string_length = len; + strncpy (obj_som_version_hdr (abfd)->user_string, string, len); + } + else if (type == COPYRIGHT_AUX_ID) + { + int len = strlen (string); + int pad = 0; + + if (len % 4) + pad = (4 - (len % 4)); + obj_som_copyright_hdr (abfd) = (struct copyright_aux_hdr *) + bfd_zalloc (abfd, sizeof (struct aux_id) + + sizeof (unsigned int) + len + pad); + if (!obj_som_copyright_hdr (abfd)) + return false; + obj_som_copyright_hdr (abfd)->header_id.type = COPYRIGHT_AUX_ID; + obj_som_copyright_hdr (abfd)->header_id.length = len + pad; + obj_som_copyright_hdr (abfd)->header_id.length += sizeof (int); + obj_som_copyright_hdr (abfd)->string_length = len; + strcpy (obj_som_copyright_hdr (abfd)->copyright, string); + } + return true; +} + +static boolean +som_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0 || ((section->flags & SEC_HAS_CONTENTS) == 0)) + return true; + if ((bfd_size_type)(offset+count) > section->_raw_size + || bfd_seek (abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_read (location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +static boolean +som_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false) + { + /* Set up fixed parts of the file, space, and subspace headers. + Notify the world that output has begun. */ + som_prep_headers (abfd); + abfd->output_has_begun = true; + /* Start writing the object file. This include all the string + tables, fixup streams, and other portions of the object file. */ + som_begin_writing (abfd); + } + + /* Only write subspaces which have "real" contents (eg. the contents + are not generated at run time by the OS). */ + if (!som_is_subspace (section) + || ((section->flags & SEC_HAS_CONTENTS) == 0)) + return true; + + /* Seek to the proper offset within the object file and write the + data. */ + offset += som_section_data (section)->subspace_dict->file_loc_init_value; + if (bfd_seek (abfd, offset, SEEK_SET) == -1) + return false; + + if (bfd_write ((PTR) location, 1, count, abfd) != count) + return false; + return true; +} + +static boolean +som_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + /* Allow any architecture to be supported by the SOM backend */ + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +static boolean +som_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *line_ptr; +{ + return (false); +} + +static int +som_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + (*_bfd_error_handler) ("som_sizeof_headers unimplemented"); + fflush (stderr); + abort (); + return (0); +} + +/* Return the single-character symbol type corresponding to + SOM section S, or '?' for an unknown SOM section. */ + +static char +som_section_type (s) + const char *s; +{ + const struct section_to_type *t; + + for (t = &stt[0]; t->section; t++) + if (!strcmp (s, t->section)) + return t->type; + return '?'; +} + +static int +som_decode_symclass (symbol) + asymbol *symbol; +{ + char c; + + if (bfd_is_com_section (symbol->section)) + return 'C'; + if (bfd_is_und_section (symbol->section)) + return 'U'; + if (bfd_is_ind_section (symbol->section)) + return 'I'; + if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL))) + return '?'; + + if (bfd_is_abs_section (symbol->section) + || (som_symbol_data (symbol) != NULL + && som_symbol_data (symbol)->som_type == SYMBOL_TYPE_ABSOLUTE)) + c = 'a'; + else if (symbol->section) + c = som_section_type (symbol->section->name); + else + return '?'; + if (symbol->flags & BSF_GLOBAL) + c = toupper (c); + return c; +} + +/* Return information about SOM symbol SYMBOL in RET. */ + +static void +som_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + ret->type = som_decode_symclass (symbol); + if (ret->type != 'U') + ret->value = symbol->value+symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; +} + +/* Count the number of symbols in the archive symbol table. Necessary + so that we can allocate space for all the carsyms at once. */ + +static boolean +som_bfd_count_ar_symbols (abfd, lst_header, count) + bfd *abfd; + struct lst_header *lst_header; + symindex *count; +{ + unsigned int i; + unsigned int *hash_table = NULL; + file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header); + + hash_table = + (unsigned int *) bfd_malloc (lst_header->hash_size + * sizeof (unsigned int)); + if (hash_table == NULL && lst_header->hash_size != 0) + goto error_return; + + /* Don't forget to initialize the counter! */ + *count = 0; + + /* Read in the hash table. The has table is an array of 32bit file offsets + which point to the hash chains. */ + if (bfd_read ((PTR) hash_table, lst_header->hash_size, 4, abfd) + != lst_header->hash_size * 4) + goto error_return; + + /* Walk each chain counting the number of symbols found on that particular + chain. */ + for (i = 0; i < lst_header->hash_size; i++) + { + struct lst_symbol_record lst_symbol; + + /* An empty chain has zero as it's file offset. */ + if (hash_table[i] == 0) + continue; + + /* Seek to the first symbol in this hash chain. */ + if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) < 0) + goto error_return; + + /* Read in this symbol and update the counter. */ + if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd) + != sizeof (lst_symbol)) + goto error_return; + + (*count)++; + + /* Now iterate through the rest of the symbols on this chain. */ + while (lst_symbol.next_entry) + { + + /* Seek to the next symbol. */ + if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET) + < 0) + goto error_return; + + /* Read the symbol in and update the counter. */ + if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd) + != sizeof (lst_symbol)) + goto error_return; + + (*count)++; + } + } + if (hash_table != NULL) + free (hash_table); + return true; + + error_return: + if (hash_table != NULL) + free (hash_table); + return false; +} + +/* Fill in the canonical archive symbols (SYMS) from the archive described + by ABFD and LST_HEADER. */ + +static boolean +som_bfd_fill_in_ar_symbols (abfd, lst_header, syms) + bfd *abfd; + struct lst_header *lst_header; + carsym **syms; +{ + unsigned int i, len; + carsym *set = syms[0]; + unsigned int *hash_table = NULL; + struct som_entry *som_dict = NULL; + file_ptr lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header); + + hash_table = + (unsigned int *) bfd_malloc (lst_header->hash_size + * sizeof (unsigned int)); + if (hash_table == NULL && lst_header->hash_size != 0) + goto error_return; + + som_dict = + (struct som_entry *) bfd_malloc (lst_header->module_count + * sizeof (struct som_entry)); + if (som_dict == NULL && lst_header->module_count != 0) + goto error_return; + + /* Read in the hash table. The has table is an array of 32bit file offsets + which point to the hash chains. */ + if (bfd_read ((PTR) hash_table, lst_header->hash_size, 4, abfd) + != lst_header->hash_size * 4) + goto error_return; + + /* Seek to and read in the SOM dictionary. We will need this to fill + in the carsym's filepos field. */ + if (bfd_seek (abfd, lst_filepos + lst_header->dir_loc, SEEK_SET) < 0) + goto error_return; + + if (bfd_read ((PTR) som_dict, lst_header->module_count, + sizeof (struct som_entry), abfd) + != lst_header->module_count * sizeof (struct som_entry)) + goto error_return; + + /* Walk each chain filling in the carsyms as we go along. */ + for (i = 0; i < lst_header->hash_size; i++) + { + struct lst_symbol_record lst_symbol; + + /* An empty chain has zero as it's file offset. */ + if (hash_table[i] == 0) + continue; + + /* Seek to and read the first symbol on the chain. */ + if (bfd_seek (abfd, lst_filepos + hash_table[i], SEEK_SET) < 0) + goto error_return; + + if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd) + != sizeof (lst_symbol)) + goto error_return; + + /* Get the name of the symbol, first get the length which is stored + as a 32bit integer just before the symbol. + + One might ask why we don't just read in the entire string table + and index into it. Well, according to the SOM ABI the string + index can point *anywhere* in the archive to save space, so just + using the string table would not be safe. */ + if (bfd_seek (abfd, lst_filepos + lst_header->string_loc + + lst_symbol.name.n_strx - 4, SEEK_SET) < 0) + goto error_return; + + if (bfd_read (&len, 1, 4, abfd) != 4) + goto error_return; + + /* Allocate space for the name and null terminate it too. */ + set->name = bfd_zalloc (abfd, len + 1); + if (!set->name) + goto error_return; + if (bfd_read (set->name, 1, len, abfd) != len) + goto error_return; + + set->name[len] = 0; + + /* Fill in the file offset. Note that the "location" field points + to the SOM itself, not the ar_hdr in front of it. */ + set->file_offset = som_dict[lst_symbol.som_index].location + - sizeof (struct ar_hdr); + + /* Go to the next symbol. */ + set++; + + /* Iterate through the rest of the chain. */ + while (lst_symbol.next_entry) + { + /* Seek to the next symbol and read it in. */ + if (bfd_seek (abfd, lst_filepos + lst_symbol.next_entry, SEEK_SET) <0) + goto error_return; + + if (bfd_read ((PTR) & lst_symbol, 1, sizeof (lst_symbol), abfd) + != sizeof (lst_symbol)) + goto error_return; + + /* Seek to the name length & string and read them in. */ + if (bfd_seek (abfd, lst_filepos + lst_header->string_loc + + lst_symbol.name.n_strx - 4, SEEK_SET) < 0) + goto error_return; + + if (bfd_read (&len, 1, 4, abfd) != 4) + goto error_return; + + /* Allocate space for the name and null terminate it too. */ + set->name = bfd_zalloc (abfd, len + 1); + if (!set->name) + goto error_return; + + if (bfd_read (set->name, 1, len, abfd) != len) + goto error_return; + set->name[len] = 0; + + /* Fill in the file offset. Note that the "location" field points + to the SOM itself, not the ar_hdr in front of it. */ + set->file_offset = som_dict[lst_symbol.som_index].location + - sizeof (struct ar_hdr); + + /* Go on to the next symbol. */ + set++; + } + } + /* If we haven't died by now, then we successfully read the entire + archive symbol table. */ + if (hash_table != NULL) + free (hash_table); + if (som_dict != NULL) + free (som_dict); + return true; + + error_return: + if (hash_table != NULL) + free (hash_table); + if (som_dict != NULL) + free (som_dict); + return false; +} + +/* Read in the LST from the archive. */ +static boolean +som_slurp_armap (abfd) + bfd *abfd; +{ + struct lst_header lst_header; + struct ar_hdr ar_header; + unsigned int parsed_size; + struct artdata *ardata = bfd_ardata (abfd); + char nextname[17]; + int i = bfd_read ((PTR) nextname, 1, 16, abfd); + + /* Special cases. */ + if (i == 0) + return true; + if (i != 16) + return false; + + if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) < 0) + return false; + + /* For archives without .o files there is no symbol table. */ + if (strncmp (nextname, "/ ", 16)) + { + bfd_has_map (abfd) = false; + return true; + } + + /* Read in and sanity check the archive header. */ + if (bfd_read ((PTR) &ar_header, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + return false; + + if (strncmp (ar_header.ar_fmag, ARFMAG, 2)) + { + bfd_set_error (bfd_error_malformed_archive); + return false; + } + + /* How big is the archive symbol table entry? */ + errno = 0; + parsed_size = strtol (ar_header.ar_size, NULL, 10); + if (errno != 0) + { + bfd_set_error (bfd_error_malformed_archive); + return false; + } + + /* Save off the file offset of the first real user data. */ + ardata->first_file_filepos = bfd_tell (abfd) + parsed_size; + + /* Read in the library symbol table. We'll make heavy use of this + in just a minute. */ + if (bfd_read ((PTR) & lst_header, 1, sizeof (struct lst_header), abfd) + != sizeof (struct lst_header)) + return false; + + /* Sanity check. */ + if (lst_header.a_magic != LIBMAGIC) + { + bfd_set_error (bfd_error_malformed_archive); + return false; + } + + /* Count the number of symbols in the library symbol table. */ + if (som_bfd_count_ar_symbols (abfd, &lst_header, &ardata->symdef_count) + == false) + return false; + + /* Get back to the start of the library symbol table. */ + if (bfd_seek (abfd, ardata->first_file_filepos - parsed_size + + sizeof (struct lst_header), SEEK_SET) < 0) + return false; + + /* Initializae the cache and allocate space for the library symbols. */ + ardata->cache = 0; + ardata->symdefs = (carsym *) bfd_alloc (abfd, + (ardata->symdef_count + * sizeof (carsym))); + if (!ardata->symdefs) + return false; + + /* Now fill in the canonical archive symbols. */ + if (som_bfd_fill_in_ar_symbols (abfd, &lst_header, &ardata->symdefs) + == false) + return false; + + /* Seek back to the "first" file in the archive. Note the "first" + file may be the extended name table. */ + if (bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET) < 0) + return false; + + /* Notify the generic archive code that we have a symbol map. */ + bfd_has_map (abfd) = true; + return true; +} + +/* Begin preparing to write a SOM library symbol table. + + As part of the prep work we need to determine the number of symbols + and the size of the associated string section. */ + +static boolean +som_bfd_prep_for_ar_write (abfd, num_syms, stringsize) + bfd *abfd; + unsigned int *num_syms, *stringsize; +{ + bfd *curr_bfd = abfd->archive_head; + + /* Some initialization. */ + *num_syms = 0; + *stringsize = 0; + + /* Iterate over each BFD within this archive. */ + while (curr_bfd != NULL) + { + unsigned int curr_count, i; + som_symbol_type *sym; + + /* Don't bother for non-SOM objects. */ + if (curr_bfd->format != bfd_object + || curr_bfd->xvec->flavour != bfd_target_som_flavour) + { + curr_bfd = curr_bfd->next; + continue; + } + + /* Make sure the symbol table has been read, then snag a pointer + to it. It's a little slimey to grab the symbols via obj_som_symtab, + but doing so avoids allocating lots of extra memory. */ + if (som_slurp_symbol_table (curr_bfd) == false) + return false; + + sym = obj_som_symtab (curr_bfd); + curr_count = bfd_get_symcount (curr_bfd); + + /* Examine each symbol to determine if it belongs in the + library symbol table. */ + for (i = 0; i < curr_count; i++, sym++) + { + struct som_misc_symbol_info info; + + /* Derive SOM information from the BFD symbol. */ + som_bfd_derive_misc_symbol_info (curr_bfd, &sym->symbol, &info); + + /* Should we include this symbol? */ + if (info.symbol_type == ST_NULL + || info.symbol_type == ST_SYM_EXT + || info.symbol_type == ST_ARG_EXT) + continue; + + /* Only global symbols and unsatisfied commons. */ + if (info.symbol_scope != SS_UNIVERSAL + && info.symbol_type != ST_STORAGE) + continue; + + /* Do no include undefined symbols. */ + if (bfd_is_und_section (sym->symbol.section)) + continue; + + /* Bump the various counters, being careful to honor + alignment considerations in the string table. */ + (*num_syms)++; + *stringsize = *stringsize + strlen (sym->symbol.name) + 5; + while (*stringsize % 4) + (*stringsize)++; + } + + curr_bfd = curr_bfd->next; + } + return true; +} + +/* Hash a symbol name based on the hashing algorithm presented in the + SOM ABI. */ +static unsigned int +som_bfd_ar_symbol_hash (symbol) + asymbol *symbol; +{ + unsigned int len = strlen (symbol->name); + + /* Names with length 1 are special. */ + if (len == 1) + return 0x1000100 | (symbol->name[0] << 16) | symbol->name[0]; + + return ((len & 0x7f) << 24) | (symbol->name[1] << 16) + | (symbol->name[len-2] << 8) | symbol->name[len-1]; +} + +static CONST char * +normalize (file) + CONST char *file; +{ + CONST char *filename = strrchr (file, '/'); + + if (filename != NULL) + filename++; + else + filename = file; + return filename; +} + +/* Do the bulk of the work required to write the SOM library + symbol table. */ + +static boolean +som_bfd_ar_write_symbol_stuff (abfd, nsyms, string_size, lst) + bfd *abfd; + unsigned int nsyms, string_size; + struct lst_header lst; +{ + file_ptr lst_filepos; + char *strings = NULL, *p; + struct lst_symbol_record *lst_syms = NULL, *curr_lst_sym; + bfd *curr_bfd; + unsigned int *hash_table = NULL; + struct som_entry *som_dict = NULL; + struct lst_symbol_record **last_hash_entry = NULL; + unsigned int curr_som_offset, som_index, extended_name_length = 0; + unsigned int maxname = abfd->xvec->ar_max_namelen; + + hash_table = + (unsigned int *) bfd_malloc (lst.hash_size * sizeof (unsigned int)); + if (hash_table == NULL && lst.hash_size != 0) + goto error_return; + som_dict = + (struct som_entry *) bfd_malloc (lst.module_count + * sizeof (struct som_entry)); + if (som_dict == NULL && lst.module_count != 0) + goto error_return; + + last_hash_entry = + ((struct lst_symbol_record **) + bfd_malloc (lst.hash_size * sizeof (struct lst_symbol_record *))); + if (last_hash_entry == NULL && lst.hash_size != 0) + goto error_return; + + /* Lots of fields are file positions relative to the start + of the lst record. So save its location. */ + lst_filepos = bfd_tell (abfd) - sizeof (struct lst_header); + + /* Some initialization. */ + memset (hash_table, 0, 4 * lst.hash_size); + memset (som_dict, 0, lst.module_count * sizeof (struct som_entry)); + memset (last_hash_entry, 0, + lst.hash_size * sizeof (struct lst_symbol_record *)); + + /* Symbols have som_index fields, so we have to keep track of the + index of each SOM in the archive. + + The SOM dictionary has (among other things) the absolute file + position for the SOM which a particular dictionary entry + describes. We have to compute that information as we iterate + through the SOMs/symbols. */ + som_index = 0; + curr_som_offset = 8 + 2 * sizeof (struct ar_hdr) + lst.file_end; + + /* Yow! We have to know the size of the extended name table + too. */ + for (curr_bfd = abfd->archive_head; + curr_bfd != NULL; + curr_bfd = curr_bfd->next) + { + CONST char *normal = normalize (curr_bfd->filename); + unsigned int thislen; + + if (!normal) + return false; + thislen = strlen (normal); + if (thislen > maxname) + extended_name_length += thislen + 1; + } + + /* Make room for the archive header and the contents of the + extended string table. */ + if (extended_name_length) + curr_som_offset += extended_name_length + sizeof (struct ar_hdr); + + /* Make sure we're properly aligned. */ + curr_som_offset = (curr_som_offset + 0x1) & ~0x1; + + /* FIXME should be done with buffers just like everything else... */ + lst_syms = bfd_malloc (nsyms * sizeof (struct lst_symbol_record)); + if (lst_syms == NULL && nsyms != 0) + goto error_return; + strings = bfd_malloc (string_size); + if (strings == NULL && string_size != 0) + goto error_return; + + p = strings; + curr_lst_sym = lst_syms; + + curr_bfd = abfd->archive_head; + while (curr_bfd != NULL) + { + unsigned int curr_count, i; + som_symbol_type *sym; + + /* Don't bother for non-SOM objects. */ + if (curr_bfd->format != bfd_object + || curr_bfd->xvec->flavour != bfd_target_som_flavour) + { + curr_bfd = curr_bfd->next; + continue; + } + + /* Make sure the symbol table has been read, then snag a pointer + to it. It's a little slimey to grab the symbols via obj_som_symtab, + but doing so avoids allocating lots of extra memory. */ + if (som_slurp_symbol_table (curr_bfd) == false) + goto error_return; + + sym = obj_som_symtab (curr_bfd); + curr_count = bfd_get_symcount (curr_bfd); + + for (i = 0; i < curr_count; i++, sym++) + { + struct som_misc_symbol_info info; + + /* Derive SOM information from the BFD symbol. */ + som_bfd_derive_misc_symbol_info (curr_bfd, &sym->symbol, &info); + + /* Should we include this symbol? */ + if (info.symbol_type == ST_NULL + || info.symbol_type == ST_SYM_EXT + || info.symbol_type == ST_ARG_EXT) + continue; + + /* Only global symbols and unsatisfied commons. */ + if (info.symbol_scope != SS_UNIVERSAL + && info.symbol_type != ST_STORAGE) + continue; + + /* Do no include undefined symbols. */ + if (bfd_is_und_section (sym->symbol.section)) + continue; + + /* If this is the first symbol from this SOM, then update + the SOM dictionary too. */ + if (som_dict[som_index].location == 0) + { + som_dict[som_index].location = curr_som_offset; + som_dict[som_index].length = arelt_size (curr_bfd); + } + + /* Fill in the lst symbol record. */ + curr_lst_sym->hidden = 0; + curr_lst_sym->secondary_def = 0; + curr_lst_sym->symbol_type = info.symbol_type; + curr_lst_sym->symbol_scope = info.symbol_scope; + curr_lst_sym->check_level = 0; + curr_lst_sym->must_qualify = 0; + curr_lst_sym->initially_frozen = 0; + curr_lst_sym->memory_resident = 0; + curr_lst_sym->is_common = bfd_is_com_section (sym->symbol.section); + curr_lst_sym->dup_common = 0; + curr_lst_sym->xleast = 0; + curr_lst_sym->arg_reloc = info.arg_reloc; + curr_lst_sym->name.n_strx = p - strings + 4; + curr_lst_sym->qualifier_name.n_strx = 0; + curr_lst_sym->symbol_info = info.symbol_info; + curr_lst_sym->symbol_value = info.symbol_value; + curr_lst_sym->symbol_descriptor = 0; + curr_lst_sym->reserved = 0; + curr_lst_sym->som_index = som_index; + curr_lst_sym->symbol_key = som_bfd_ar_symbol_hash (&sym->symbol); + curr_lst_sym->next_entry = 0; + + /* Insert into the hash table. */ + if (hash_table[curr_lst_sym->symbol_key % lst.hash_size]) + { + struct lst_symbol_record *tmp; + + /* There is already something at the head of this hash chain, + so tack this symbol onto the end of the chain. */ + tmp = last_hash_entry[curr_lst_sym->symbol_key % lst.hash_size]; + tmp->next_entry + = (curr_lst_sym - lst_syms) * sizeof (struct lst_symbol_record) + + lst.hash_size * 4 + + lst.module_count * sizeof (struct som_entry) + + sizeof (struct lst_header); + } + else + { + /* First entry in this hash chain. */ + hash_table[curr_lst_sym->symbol_key % lst.hash_size] + = (curr_lst_sym - lst_syms) * sizeof (struct lst_symbol_record) + + lst.hash_size * 4 + + lst.module_count * sizeof (struct som_entry) + + sizeof (struct lst_header); + } + + /* Keep track of the last symbol we added to this chain so we can + easily update its next_entry pointer. */ + last_hash_entry[curr_lst_sym->symbol_key % lst.hash_size] + = curr_lst_sym; + + + /* Update the string table. */ + bfd_put_32 (abfd, strlen (sym->symbol.name), p); + p += 4; + strcpy (p, sym->symbol.name); + p += strlen (sym->symbol.name) + 1; + while ((int)p % 4) + { + bfd_put_8 (abfd, 0, p); + p++; + } + + /* Head to the next symbol. */ + curr_lst_sym++; + } + + /* Keep track of where each SOM will finally reside; then look + at the next BFD. */ + curr_som_offset += arelt_size (curr_bfd) + sizeof (struct ar_hdr); + + /* A particular object in the archive may have an odd length; the + linker requires objects begin on an even boundary. So round + up the current offset as necessary. */ + curr_som_offset = (curr_som_offset + 0x1) & ~0x1; + curr_bfd = curr_bfd->next; + som_index++; + } + + /* Now scribble out the hash table. */ + if (bfd_write ((PTR) hash_table, lst.hash_size, 4, abfd) + != lst.hash_size * 4) + goto error_return; + + /* Then the SOM dictionary. */ + if (bfd_write ((PTR) som_dict, lst.module_count, + sizeof (struct som_entry), abfd) + != lst.module_count * sizeof (struct som_entry)) + goto error_return; + + /* The library symbols. */ + if (bfd_write ((PTR) lst_syms, nsyms, sizeof (struct lst_symbol_record), abfd) + != nsyms * sizeof (struct lst_symbol_record)) + goto error_return; + + /* And finally the strings. */ + if (bfd_write ((PTR) strings, string_size, 1, abfd) != string_size) + goto error_return; + + if (hash_table != NULL) + free (hash_table); + if (som_dict != NULL) + free (som_dict); + if (last_hash_entry != NULL) + free (last_hash_entry); + if (lst_syms != NULL) + free (lst_syms); + if (strings != NULL) + free (strings); + return true; + + error_return: + if (hash_table != NULL) + free (hash_table); + if (som_dict != NULL) + free (som_dict); + if (last_hash_entry != NULL) + free (last_hash_entry); + if (lst_syms != NULL) + free (lst_syms); + if (strings != NULL) + free (strings); + + return false; +} + +/* SOM almost uses the SVR4 style extended name support, but not + quite. */ + +static boolean +som_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ + *name = "//"; + return _bfd_construct_extended_name_table (abfd, false, tabloc, tablen); +} + +/* Write out the LST for the archive. + + You'll never believe this is really how armaps are handled in SOM... */ + +/*ARGSUSED*/ +static boolean +som_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + bfd *curr_bfd; + struct stat statbuf; + unsigned int i, lst_size, nsyms, stringsize; + struct ar_hdr hdr; + struct lst_header lst; + int *p; + + /* We'll use this for the archive's date and mode later. */ + if (stat (abfd->filename, &statbuf) != 0) + { + bfd_set_error (bfd_error_system_call); + return false; + } + /* Fudge factor. */ + bfd_ardata (abfd)->armap_timestamp = statbuf.st_mtime + 60; + + /* Account for the lst header first. */ + lst_size = sizeof (struct lst_header); + + /* Start building the LST header. */ + /* FIXME: Do we need to examine each element to determine the + largest id number? */ + lst.system_id = CPU_PA_RISC1_0; + lst.a_magic = LIBMAGIC; + lst.version_id = VERSION_ID; + lst.file_time.secs = 0; + lst.file_time.nanosecs = 0; + + lst.hash_loc = lst_size; + lst.hash_size = SOM_LST_HASH_SIZE; + + /* Hash table is a SOM_LST_HASH_SIZE 32bit offsets. */ + lst_size += 4 * SOM_LST_HASH_SIZE; + + /* We need to count the number of SOMs in this archive. */ + curr_bfd = abfd->archive_head; + lst.module_count = 0; + while (curr_bfd != NULL) + { + /* Only true SOM objects count. */ + if (curr_bfd->format == bfd_object + && curr_bfd->xvec->flavour == bfd_target_som_flavour) + lst.module_count++; + curr_bfd = curr_bfd->next; + } + lst.module_limit = lst.module_count; + lst.dir_loc = lst_size; + lst_size += sizeof (struct som_entry) * lst.module_count; + + /* We don't support import/export tables, auxiliary headers, + or free lists yet. Make the linker work a little harder + to make our life easier. */ + + lst.export_loc = 0; + lst.export_count = 0; + lst.import_loc = 0; + lst.aux_loc = 0; + lst.aux_size = 0; + + /* Count how many symbols we will have on the hash chains and the + size of the associated string table. */ + if (som_bfd_prep_for_ar_write (abfd, &nsyms, &stringsize) == false) + return false; + + lst_size += sizeof (struct lst_symbol_record) * nsyms; + + /* For the string table. One day we might actually use this info + to avoid small seeks/reads when reading archives. */ + lst.string_loc = lst_size; + lst.string_size = stringsize; + lst_size += stringsize; + + /* SOM ABI says this must be zero. */ + lst.free_list = 0; + lst.file_end = lst_size; + + /* Compute the checksum. Must happen after the entire lst header + has filled in. */ + p = (int *)&lst; + lst.checksum = 0; + for (i = 0; i < sizeof (struct lst_header)/sizeof (int) - 1; i++) + lst.checksum ^= *p++; + + sprintf (hdr.ar_name, "/ "); + sprintf (hdr.ar_date, "%ld", bfd_ardata (abfd)->armap_timestamp); + sprintf (hdr.ar_uid, "%ld", (long) getuid ()); + sprintf (hdr.ar_gid, "%ld", (long) getgid ()); + sprintf (hdr.ar_mode, "%-8o", (unsigned int) statbuf.st_mode); + sprintf (hdr.ar_size, "%-10d", (int) lst_size); + hdr.ar_fmag[0] = '`'; + hdr.ar_fmag[1] = '\012'; + + /* Turn any nulls into spaces. */ + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + + /* Scribble out the ar header. */ + if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + return false; + + /* Now scribble out the lst header. */ + if (bfd_write ((PTR) &lst, 1, sizeof (struct lst_header), abfd) + != sizeof (struct lst_header)) + return false; + + /* Build and write the armap. */ + if (som_bfd_ar_write_symbol_stuff (abfd, nsyms, stringsize, lst) == false) + return false; + + /* Done. */ + return true; +} + +/* Free all information we have cached for this BFD. We can always + read it again later if we need it. */ + +static boolean +som_bfd_free_cached_info (abfd) + bfd *abfd; +{ + asection *o; + + if (bfd_get_format (abfd) != bfd_object) + return true; + +#define FREE(x) if (x != NULL) { free (x); x = NULL; } + /* Free the native string and symbol tables. */ + FREE (obj_som_symtab (abfd)); + FREE (obj_som_stringtab (abfd)); + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + /* Free the native relocations. */ + o->reloc_count = -1; + FREE (som_section_data (o)->reloc_stream); + /* Free the generic relocations. */ + FREE (o->relocation); + } +#undef FREE + + return true; +} + +/* End of miscellaneous support functions. */ + +/* Linker support functions. */ +static boolean +som_bfd_link_split_section (abfd, sec) + bfd *abfd; + asection *sec; +{ + return (som_is_subspace (sec) && sec->_raw_size > 240000); +} + +#define som_close_and_cleanup som_bfd_free_cached_info + +#define som_read_ar_hdr _bfd_generic_read_ar_hdr +#define som_openr_next_archived_file bfd_generic_openr_next_archived_file +#define som_get_elt_at_index _bfd_generic_get_elt_at_index +#define som_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define som_truncate_arname bfd_bsd_truncate_arname +#define som_slurp_extended_name_table _bfd_slurp_extended_name_table +#define som_update_armap_timestamp bfd_true +#define som_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data + +#define som_get_lineno _bfd_nosymbols_get_lineno +#define som_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define som_read_minisymbols _bfd_generic_read_minisymbols +#define som_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +#define som_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define som_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define som_bfd_relax_section bfd_generic_relax_section +#define som_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define som_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define som_bfd_final_link _bfd_generic_final_link + + +const bfd_target som_vec = +{ + "som", /* name */ + bfd_target_som_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | DYNAMIC), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + +/* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + 0, + '/', /* ar_pad_char */ + 14, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + {_bfd_dummy_target, + som_object_p, /* bfd_check_format */ + bfd_generic_archive_p, + _bfd_dummy_target + }, + { + bfd_false, + som_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + { + bfd_false, + som_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, +#undef som + + BFD_JUMP_TABLE_GENERIC (som), + BFD_JUMP_TABLE_COPY (som), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (som), + BFD_JUMP_TABLE_SYMBOLS (som), + BFD_JUMP_TABLE_RELOCS (som), + BFD_JUMP_TABLE_WRITE (som), + BFD_JUMP_TABLE_LINK (som), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; + +#endif /* HOST_HPPAHPUX || HOST_HPPABSD || HOST_HPPAOSF */ diff --git a/contrib/gdb/bfd/som.h b/contrib/gdb/bfd/som.h new file mode 100644 index 000000000000..6290e88f948c --- /dev/null +++ b/contrib/gdb/bfd/som.h @@ -0,0 +1,224 @@ +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SOM_H +#define _SOM_H + +#include "../bfd/sysdep.h" +#include "libhppa.h" + +#include +#include +#include + +/* The SOM BFD backend doesn't currently use anything from these + two include files, but it's likely to need them in the future. */ +#ifdef R_DLT_REL +#include +#include +#endif + +#if defined(HOST_HPPABSD) || defined (HOST_HPPAOSF) +/* BSD uses a completely different scheme for object file identification. + so for now, define _PA_RISC_ID to accept any random value for a model + number. */ +#undef _PA_RISC_ID +#define _PA_RISC_ID(__m_num) 1 +#endif /* HOST_HPPABSD */ + +#define FILE_HDR_SIZE sizeof(struct header) +#define AUX_HDR_SIZE sizeof(struct som_exec_auxhdr) + +typedef struct som_symbol + { + asymbol symbol; + unsigned int som_type; + + /* Structured like the ELF tc_data union. Allows more code sharing + in GAS this way. */ + union + { + unsigned int hppa_arg_reloc; + PTR any; + } + tc_data; + + /* Index of this symbol in the symbol table. Only used when + building relocation streams for incomplete objects. */ + int index; + + /* How many times this symbol is used in a relocation. By sorting + the symbols from most used to least used we can significantly + reduce the size of the relocation stream for incomplete objects. */ + int reloc_count; + + /* During object file writing, the offset of the name of this symbol + in the SOM string table. */ + int stringtab_offset; + } +som_symbol_type; + +/* A structure containing all the magic information stored in a BFD's + private data which needs to be copied during an objcopy/strip run. */ +struct som_exec_data + { + /* Sort-of a magic number. BSD uses it to distinguish between + native executables and hpux executables. */ + short system_id; + + /* Magic exec flags. These control things like whether or not + null pointer dereferencing is allowed and the like. */ + long exec_flags; + + /* Add more stuff here as needed. Good examples of information + we might want to pass would be presumed_dp, entry_* and maybe + others from the file header. */ + }; + +struct somdata + { + /* All the magic information about an executable which lives + in the private BFD structure and needs to be copied from + the input bfd to the output bfd during a objcopy/strip. */ + struct som_exec_data *exec_data; + + /* These three fields are only used when writing files and are + generated from scratch. They need not be copied for objcopy + or strip to work. */ + struct header *file_hdr; + struct copyright_aux_hdr *copyright_aux_hdr; + struct user_string_aux_hdr *version_aux_hdr; + struct som_exec_auxhdr *exec_hdr; + + /* Pointers to a saved copy of the symbol and string tables. These + need not be copied for objcopy or strip to work. */ + som_symbol_type *symtab; + char *stringtab; + asymbol **sorted_syms; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. + These offsets need not be copied for objcopy or strip to work. */ + + file_ptr sym_filepos; + file_ptr str_filepos; + file_ptr reloc_filepos; + unsigned stringtab_size; + }; + +struct som_data_struct + { + struct somdata a; + }; + +/* Substructure of som_section_data_struct used to hold information + which can't be represented by the generic BFD section structure, + but which must be copied during objcopy or strip. */ +struct som_copyable_section_data_struct + { + /* Various fields in space and subspace headers that we need + to pass around. */ + unsigned int sort_key : 8; + unsigned int access_control_bits : 7; + unsigned int is_defined : 1; + unsigned int is_private : 1; + unsigned int quadrant : 2; + + /* For subspaces, this points to the section which represents the + space in which the subspace is contained. For spaces it points + back to the section for this space. */ + asection *container; + + /* The user-specified space number. It is wrong to use this as + an index since duplicates and holes are allowed. */ + int space_number; + + /* Add more stuff here as needed. Good examples of information + we might want to pass would be initialization pointers, + and the many subspace flags we do not represent yet. */ + }; + +/* Used to keep extra SOM specific information for a given section. + + reloc_size holds the size of the relocation stream, note this + is very different from the number of relocations as SOM relocations + are variable length. + + reloc_stream is the actual stream of relocation entries. */ + +struct som_section_data_struct + { + struct som_copyable_section_data_struct *copy_data; + unsigned int reloc_size; + char *reloc_stream; + struct space_dictionary_record *space_dict; + struct subspace_dictionary_record *subspace_dict; + }; + +#define somdata(bfd) ((bfd)->tdata.som_data->a) +#define obj_som_exec_data(bfd) (somdata(bfd).exec_data) +#define obj_som_file_hdr(bfd) (somdata(bfd).file_hdr) +#define obj_som_exec_hdr(bfd) (somdata(bfd).exec_hdr) +#define obj_som_copyright_hdr(bfd) (somdata(bfd).copyright_aux_hdr) +#define obj_som_version_hdr(bfd) (somdata(bfd).version_aux_hdr) +#define obj_som_symtab(bfd) (somdata(bfd).symtab) +#define obj_som_stringtab(bfd) (somdata(bfd).stringtab) +#define obj_som_sym_filepos(bfd) (somdata(bfd).sym_filepos) +#define obj_som_str_filepos(bfd) (somdata(bfd).str_filepos) +#define obj_som_stringtab_size(bfd) (somdata(bfd).stringtab_size) +#define obj_som_reloc_filepos(bfd) (somdata(bfd).reloc_filepos) +#define obj_som_sorted_syms(bfd) (somdata(bfd).sorted_syms) +#define som_section_data(sec) \ + ((struct som_section_data_struct *)sec->used_by_bfd) +#define som_symbol_data(symbol) ((som_symbol_type *) symbol) + + +/* Defines groups of basic relocations. FIXME: These should + be the only basic relocations created by GAS. The rest + should be internal to the BFD backend. + + The idea is both SOM and ELF define these basic relocation + types so they map into a SOM or ELF specific reloation as + appropriate. This allows GAS to share much more code + between the two object formats. */ + +#define R_HPPA_NONE R_NO_RELOCATION +#define R_HPPA R_CODE_ONE_SYMBOL +#define R_HPPA_PCREL_CALL R_PCREL_CALL +#define R_HPPA_ABS_CALL R_ABS_CALL +#define R_HPPA_GOTOFF R_DP_RELATIVE +#define R_HPPA_ENTRY R_ENTRY +#define R_HPPA_EXIT R_EXIT +#define R_HPPA_COMPLEX R_COMP1 +#define R_HPPA_BEGIN_BRTAB R_BEGIN_BRTAB +#define R_HPPA_END_BRTAB R_END_BRTAB + +/* Exported functions, mostly for use by GAS. */ +boolean bfd_som_set_section_attributes PARAMS ((asection *, int, int, + unsigned int, int)); +boolean bfd_som_set_subsection_attributes PARAMS ((asection *, asection *, + int, unsigned int, int)); +void bfd_som_set_symbol_type PARAMS ((asymbol *, unsigned int)); +boolean bfd_som_attach_aux_hdr PARAMS ((bfd *, int, char *)); +int ** hppa_som_gen_reloc_type + PARAMS ((bfd *, int, int, enum hppa_reloc_field_selector_type_alt, int)); +#endif /* _SOM_H */ diff --git a/contrib/gdb/bfd/sparclynx.c b/contrib/gdb/bfd/sparclynx.c new file mode 100644 index 000000000000..0885620283ec --- /dev/null +++ b/contrib/gdb/bfd/sparclynx.c @@ -0,0 +1,265 @@ +/* BFD support for Sparc binaries under LynxOS. + Copyright (C) 1990, 1991, 1992, 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if 0 +#define BYTES_IN_WORD 4 +#define N_SHARED_LIB(x) 0 + +#define TEXT_START_ADDR 0 +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#define DEFAULT_ARCH bfd_arch_sparc + +#endif + +#define MY(OP) CAT(sparclynx_aout_,OP) +#define TARGETNAME "a.out-sparc-lynx" + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#include "aout/sun4.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" + +/* This is needed to reject a NewsOS file, e.g. in + gdb/testsuite/gdb.t10/crossload.exp. + I needed to add M_UNKNOWN to recognize a 68000 object, so this will + probably no longer reject a NewsOS object. . */ +#define MACHTYPE_OK(mtype) ((mtype) == M_UNKNOWN \ + || (mtype) == M_68010 \ + || (mtype) == M_68020 \ + || (mtype) == M_SPARC) + +/* +The file @code{aoutf1.h} contains the code for BFD's +a.out back end. Control over the generated back end is given by these +two preprocessor names: +@table @code +@item ARCH_SIZE +This value should be either 32 or 64, depending upon the size of an +int in the target format. It changes the sizes of the structs which +perform the memory/disk mapping of structures. + +The 64 bit backend may only be used if the host compiler supports 64 +ints (eg long long with gcc), by defining the name @code{BFD_HOST_64_BIT} in @code{bfd.h}. +With this name defined, @emph{all} bfd operations are performed with 64bit +arithmetic, not just those to a 64bit target. + +@item TARGETNAME +The name put into the target vector. +@item +@end table + +*/ + +/*SUPPRESS558*/ +/*SUPPRESS529*/ + +void +NAME(lynx,set_arch_mach) (abfd, machtype) + bfd *abfd; + int machtype; +{ + /* Determine the architecture and machine type of the object file. */ + enum bfd_architecture arch; + long machine; + switch (machtype) + { + + case M_UNKNOWN: + /* Some Sun3s make magic numbers without cpu types in them, so + we'll default to the 68000. */ + arch = bfd_arch_m68k; + machine = 68000; + break; + + case M_68010: + case M_HP200: + arch = bfd_arch_m68k; + machine = 68010; + break; + + case M_68020: + case M_HP300: + arch = bfd_arch_m68k; + machine = 68020; + break; + + case M_SPARC: + arch = bfd_arch_sparc; + machine = 0; + break; + + case M_386: + case M_386_DYNIX: + arch = bfd_arch_i386; + machine = 0; + break; + + case M_29K: + arch = bfd_arch_a29k; + machine = 0; + break; + + case M_HPUX: + arch = bfd_arch_m68k; + machine = 0; + break; + + default: + arch = bfd_arch_obscure; + machine = 0; + break; + } + bfd_set_arch_mach (abfd, arch, machine); +} + +#define SET_ARCH_MACH(ABFD, EXEC) \ + NAME(lynx,set_arch_mach)(ABFD, N_MACHTYPE (EXEC)); \ + choose_reloc_size(ABFD); + +/* Determine the size of a relocation entry, based on the architecture */ +static void +choose_reloc_size (abfd) + bfd *abfd; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_sparc: + case bfd_arch_a29k: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } +} + +/* Write an object file in LynxOS format. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +static boolean +NAME(aout,sparclynx_write_object_contents) (abfd) + bfd *abfd; +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + + /* Magic number, maestro, please! */ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + switch (bfd_get_mach (abfd)) + { + case 68010: + N_SET_MACHTYPE (*execp, M_68010); + break; + default: + case 68020: + N_SET_MACHTYPE (*execp, M_68020); + break; + } + break; + case bfd_arch_sparc: + N_SET_MACHTYPE (*execp, M_SPARC); + break; + case bfd_arch_i386: + N_SET_MACHTYPE (*execp, M_386); + break; + case bfd_arch_a29k: + N_SET_MACHTYPE (*execp, M_29K); + break; + default: + N_SET_MACHTYPE (*execp, M_UNKNOWN); + } + + choose_reloc_size (abfd); + + N_SET_FLAGS (*execp, aout_backend_info (abfd)->exec_hdr_flags); + + WRITE_HEADERS (abfd, execp); + + return true; +} + +#define MY_set_sizes sparclynx_set_sizes +static boolean +sparclynx_set_sizes (abfd) + bfd *abfd; +{ + switch (bfd_get_arch (abfd)) + { + default: + return false; + case bfd_arch_sparc: + adata (abfd).page_size = 0x2000; + adata (abfd).segment_size = 0x2000; + adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; + case bfd_arch_m68k: + adata (abfd).page_size = 0x2000; + adata (abfd).segment_size = 0x20000; + adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; + } +} + +static CONST struct aout_backend_data sparclynx_aout_backend = +{ + 0, 1, 1, 0, sparclynx_set_sizes, 0, + 0, /* add_dynamic_symbols */ + 0, /* add_one_symbol */ + 0, /* link_dynamic_object */ + 0, /* write_dynamic_symbol */ + 0, /* check_dynamic_reloc */ + 0 /* finish_dynamic_link */ +}; + + +#define MY_bfd_debug_info_start bfd_void +#define MY_bfd_debug_info_end bfd_void +#define MY_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd *, struct sec *))) bfd_void + +#define MY_write_object_contents NAME(aout,sparclynx_write_object_contents) +#define MY_backend_data &sparclynx_aout_backend + +#define TARGET_IS_BIG_ENDIAN_P + +#ifdef LYNX_CORE + +char *lynx_core_file_failing_command (); +int lynx_core_file_failing_signal (); +boolean lynx_core_file_matches_executable_p (); +const bfd_target *lynx_core_file_p (); + +#define MY_core_file_failing_command lynx_core_file_failing_command +#define MY_core_file_failing_signal lynx_core_file_failing_signal +#define MY_core_file_matches_executable_p lynx_core_file_matches_executable_p +#define MY_core_file_p lynx_core_file_p + +#endif /* LYNX_CORE */ + +#include "aout-target.h" diff --git a/contrib/gdb/bfd/sparcnetbsd.c b/contrib/gdb/bfd/sparcnetbsd.c new file mode 100644 index 000000000000..69240f5d1587 --- /dev/null +++ b/contrib/gdb/bfd/sparcnetbsd.c @@ -0,0 +1,33 @@ +/* BFD back-end for NetBSD/sparc a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BYTES_IN_WORD 4 +#define TARGET_IS_BIG_ENDIAN_P + +#define TARGET_PAGE_SIZE 4096 +#define SEGMENT_SIZE 4096 + +#define DEFAULT_ARCH bfd_arch_sparc +#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(sparcnetbsd_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-sparc-netbsd" + +#include "netbsd.h" diff --git a/contrib/gdb/bfd/srec.c b/contrib/gdb/bfd/srec.c new file mode 100644 index 000000000000..33d28d5eab81 --- /dev/null +++ b/contrib/gdb/bfd/srec.c @@ -0,0 +1,1324 @@ +/* BFD back-end for s-record objects. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SUBSECTION + S-Record handling + +DESCRIPTION + + Ordinary S-Records cannot hold anything but addresses and + data, so that's all that we implement. + + The only interesting thing is that S-Records may come out of + order and there is no header, so an initial scan is required + to discover the minimum and maximum addresses used to create + the vma and size of the only section we create. We + arbitrarily call this section ".text". + + When bfd_get_section_contents is called the file is read + again, and this time the data is placed into a bfd_alloc'd + area. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + An s record looks like: + +EXAMPLE + S
+ +DESCRIPTION + Where + o length + is the number of bytes following upto the checksum. Note that + this is not the number of chars following, since it takes two + chars to represent a byte. + o type + is one of: + 0) header record + 1) two byte address data record + 2) three byte address data record + 3) four byte address data record + 7) four byte address termination record + 8) three byte address termination record + 9) two byte address termination record + + o address + is the start address of the data following, or in the case of + a termination record, the start address of the image + o data + is the data. + o checksum + is the sum of all the raw byte data in the record, from the length + upwards, modulo 256 and subtracted from 255. + + +SUBSECTION + Symbol S-Record handling + +DESCRIPTION + Some ICE equipment understands an addition to the standard + S-Record format; symbols and their addresses can be sent + before the data. + + The format of this is: + ($$ + (
)*) + $$ + + so a short symbol table could look like: + +EXAMPLE + $$ flash.x + $$ flash.c + _port6 $0 + _delay $4 + _start $14 + _etext $8036 + _edata $8036 + _end $8036 + $$ + +DESCRIPTION + We allow symbols to be anywhere in the data stream - the module names + are always ignored. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" +#include + +static void srec_init PARAMS ((void)); +static boolean srec_mkobject PARAMS ((bfd *)); +static int srec_get_byte PARAMS ((bfd *, boolean *)); +static void srec_bad_byte PARAMS ((bfd *, unsigned int, int, boolean)); +static boolean srec_scan PARAMS ((bfd *)); +static const bfd_target *srec_object_p PARAMS ((bfd *)); +static const bfd_target *symbolsrec_object_p PARAMS ((bfd *)); +static boolean srec_read_section PARAMS ((bfd *, asection *, bfd_byte *)); + +static boolean srec_write_record PARAMS ((bfd *, int, bfd_vma, + const bfd_byte *, + const bfd_byte *)); +static boolean srec_write_header PARAMS ((bfd *)); +static boolean srec_write_symbols PARAMS ((bfd *)); + +/* Macros for converting between hex and binary. */ + +static CONST char digs[] = "0123456789ABCDEF"; + +#define NIBBLE(x) hex_value(x) +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d, x, ch) \ + d[1] = digs[(x) & 0xf]; \ + d[0] = digs[((x)>>4)&0xf]; \ + ch += ((x) & 0xff); +#define ISHEX(x) hex_p(x) + +/* Initialize by filling in the hex conversion array. */ + +static void +srec_init () +{ + static boolean inited = false; + + if (inited == false) + { + inited = true; + hex_init (); + } +} + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 21 + +/* When writing an S-record file, the S-records can not be output as + they are seen. This structure is used to hold them in memory. */ + +struct srec_data_list_struct +{ + struct srec_data_list_struct *next; + bfd_byte *data; + bfd_vma where; + bfd_size_type size; +}; + +typedef struct srec_data_list_struct srec_data_list_type; + +/* When scanning the S-record file, a linked list of srec_symbol + structures is built to represent the symbol table (if there is + one). */ + +struct srec_symbol +{ + struct srec_symbol *next; + const char *name; + bfd_vma val; +}; + +/* The S-record tdata information. */ + +typedef struct srec_data_struct + { + srec_data_list_type *head; + srec_data_list_type *tail; + unsigned int type; + struct srec_symbol *symbols; + struct srec_symbol *symtail; + asymbol *csymbols; + } +tdata_type; + +static boolean srec_write_section PARAMS ((bfd *, tdata_type *, + srec_data_list_type *)); +static boolean srec_write_terminator PARAMS ((bfd *, tdata_type *)); + +/* Set up the S-record tdata information. */ + +static boolean +srec_mkobject (abfd) + bfd *abfd; +{ + srec_init (); + + if (abfd->tdata.srec_data == NULL) + { + tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); + if (tdata == NULL) + return false; + abfd->tdata.srec_data = tdata; + tdata->type = 1; + tdata->head = NULL; + tdata->tail = NULL; + tdata->symbols = NULL; + tdata->symtail = NULL; + tdata->csymbols = NULL; + } + + return true; +} + +/* Read a byte from an S record file. Set *ERRORPTR if an error + occurred. Return EOF on error or end of file. */ + +static int +srec_get_byte (abfd, errorptr) + bfd *abfd; + boolean *errorptr; +{ + bfd_byte c; + + if (bfd_read (&c, 1, 1, abfd) != 1) + { + if (bfd_get_error () != bfd_error_file_truncated) + *errorptr = true; + return EOF; + } + + return (int) (c & 0xff); +} + +/* Report a problem in an S record file. FIXME: This probably should + not call fprintf, but we really do need some mechanism for printing + error messages. */ + +static void +srec_bad_byte (abfd, lineno, c, error) + bfd *abfd; + unsigned int lineno; + int c; + boolean error; +{ + if (c == EOF) + { + if (! error) + bfd_set_error (bfd_error_file_truncated); + } + else + { + char buf[10]; + + if (! isprint (c)) + sprintf (buf, "\\%03o", (unsigned int) c); + else + { + buf[0] = c; + buf[1] = '\0'; + } + (*_bfd_error_handler) + ("%s:%d: Unexpected character `%s' in S-record file\n", + bfd_get_filename (abfd), lineno, buf); + bfd_set_error (bfd_error_bad_value); + } +} + +/* Add a new symbol found in an S-record file. */ + +static boolean +srec_new_symbol (abfd, name, val) + bfd *abfd; + const char *name; + bfd_vma val; +{ + struct srec_symbol *n; + + n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (struct srec_symbol)); + if (n == NULL) + return false; + + n->name = name; + n->val = val; + + if (abfd->tdata.srec_data->symbols == NULL) + abfd->tdata.srec_data->symbols = n; + else + abfd->tdata.srec_data->symtail->next = n; + abfd->tdata.srec_data->symtail = n; + n->next = NULL; + + ++abfd->symcount; + + return true; +} + +/* Read the S record file and turn it into sections. We create a new + section for each contiguous set of bytes. */ + +static boolean +srec_scan (abfd) + bfd *abfd; +{ + int c; + unsigned int lineno = 1; + boolean error = false; + bfd_byte *buf = NULL; + size_t bufsize = 0; + asection *sec = NULL; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto error_return; + + while ((c = srec_get_byte (abfd, &error)) != EOF) + { + /* We only build sections from contiguous S-records, so if this + is not an S-record, then stop building a section. */ + if (c != 'S' && c != '\r' && c != '\n') + sec = NULL; + + switch (c) + { + default: + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + + case '\n': + ++lineno; + break; + + case '\r': + break; + + case '$': + /* Starting a module name, which we ignore. */ + while ((c = srec_get_byte (abfd, &error)) != '\n' + && c != EOF) + ; + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + ++lineno; + + break; + + case ' ': + { + char *symname; + bfd_vma symval; + + /* Starting a symbol definition. */ + while ((c = srec_get_byte (abfd, &error)) != EOF + && (c == ' ' || c == '\t')) + ; + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + obstack_1grow (&abfd->memory, c); + while ((c = srec_get_byte (abfd, &error)) != EOF + && ! isspace (c)) + obstack_1grow (&abfd->memory, c); + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + symname = obstack_finish (&abfd->memory); + if (symname == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + while ((c = srec_get_byte (abfd, &error)) != EOF + && (c == ' ' || c == '\t')) + ; + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + /* Skip a dollar sign before the hex value. */ + if (c == '$') + { + c = srec_get_byte (abfd, &error); + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + } + + symval = 0; + while (ISHEX (c)) + { + symval <<= 4; + symval += NIBBLE (c); + c = srec_get_byte (abfd, &error); + } + + if (c == EOF || ! isspace (c)) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + if (! srec_new_symbol (abfd, symname, symval)) + goto error_return; + + if (c == '\n') + ++lineno; + + } + break; + + case 'S': + { + file_ptr pos; + char hdr[3]; + unsigned int bytes; + bfd_vma address; + bfd_byte *data; + + /* Starting an S-record. */ + + pos = bfd_tell (abfd) - 1; + + if (bfd_read (hdr, 1, 3, abfd) != 3) + goto error_return; + + if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2])) + { + if (! ISHEX (hdr[1])) + c = hdr[1]; + else + c = hdr[2]; + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + bytes = HEX (hdr + 1); + if (bytes * 2 > bufsize) + { + if (buf != NULL) + free (buf); + buf = (bfd_byte *) bfd_malloc (bytes * 2); + if (buf == NULL) + goto error_return; + bufsize = bytes * 2; + } + + if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2) + goto error_return; + + /* Ignore the checksum byte. */ + --bytes; + + address = 0; + data = buf; + switch (hdr[0]) + { + case '0': + case '5': + /* Prologue--ignore the file name, but stop building a + section at this point. */ + sec = NULL; + break; + + case '3': + address = HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '2': + address = (address << 8) | HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '1': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + bytes -= 2; + + if (sec != NULL + && sec->vma + sec->_raw_size == address) + { + /* This data goes at the end of the section we are + currently building. */ + sec->_raw_size += bytes; + } + else + { + char secbuf[20]; + char *secname; + + sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); + secname = (char *) bfd_alloc (abfd, strlen (secbuf) + 1); + strcpy (secname, secbuf); + sec = bfd_make_section (abfd, secname); + if (sec == NULL) + goto error_return; + sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + sec->vma = address; + sec->lma = address; + sec->_raw_size = bytes; + sec->filepos = pos; + } + + break; + + case '7': + address = HEX (data); + data += 2; + /* Fall through. */ + case '8': + address = (address << 8) | HEX (data); + data += 2; + /* Fall through. */ + case '9': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + + /* This is a termination record. */ + abfd->start_address = address; + + if (buf != NULL) + free (buf); + + return true; + } + } + break; + } + } + + if (error) + goto error_return; + + if (buf != NULL) + free (buf); + + return true; + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Check whether an existing file is an S-record file. */ + +static const bfd_target * +srec_object_p (abfd) + bfd *abfd; +{ + bfd_byte b[4]; + + srec_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_read (b, 1, 4, abfd) != 4) + return NULL; + + if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (! srec_mkobject (abfd) + || ! srec_scan (abfd)) + return NULL; + + return abfd->xvec; +} + +/* Check whether an existing file is an S-record file with symbols. */ + +static const bfd_target * +symbolsrec_object_p (abfd) + bfd *abfd; +{ + char b[2]; + + srec_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_read (b, 1, 2, abfd) != 2) + return NULL; + + if (b[0] != '$' || b[1] != '$') + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (! srec_mkobject (abfd) + || ! srec_scan (abfd)) + return NULL; + + return abfd->xvec; +} + +/* Read in the contents of a section in an S-record file. */ + +static boolean +srec_read_section (abfd, section, contents) + bfd *abfd; + asection *section; + bfd_byte *contents; +{ + int c; + bfd_size_type sofar = 0; + boolean error = false; + bfd_byte *buf = NULL; + size_t bufsize = 0; + + if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) + goto error_return; + + while ((c = srec_get_byte (abfd, &error)) != EOF) + { + bfd_byte hdr[3]; + unsigned int bytes; + bfd_vma address; + bfd_byte *data; + + if (c == '\r' || c == '\n') + continue; + + /* This is called after srec_scan has already been called, so we + ought to know the exact format. */ + BFD_ASSERT (c == 'S'); + + if (bfd_read (hdr, 1, 3, abfd) != 3) + goto error_return; + + BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2])); + + bytes = HEX (hdr + 1); + + if (bytes * 2 > bufsize) + { + if (buf != NULL) + free (buf); + buf = (bfd_byte *) bfd_malloc (bytes * 2); + if (buf == NULL) + goto error_return; + bufsize = bytes * 2; + } + + if (bfd_read (buf, 1, bytes * 2, abfd) != bytes * 2) + goto error_return; + + address = 0; + data = buf; + switch (hdr[0]) + { + default: + BFD_ASSERT (sofar == section->_raw_size); + if (buf != NULL) + free (buf); + return true; + + case '3': + address = HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '2': + address = (address << 8) | HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '1': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + bytes -= 2; + + if (address != section->vma + sofar) + { + /* We've come to the end of this section. */ + BFD_ASSERT (sofar == section->_raw_size); + if (buf != NULL) + free (buf); + return true; + } + + /* Don't consider checksum. */ + --bytes; + + while (bytes-- != 0) + { + contents[sofar] = HEX (data); + data += 2; + ++sofar; + } + + break; + } + } + + if (error) + goto error_return; + + BFD_ASSERT (sofar == section->_raw_size); + + if (buf != NULL) + free (buf); + + return true; + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Get the contents of a section in an S-record file. */ + +static boolean +srec_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->_raw_size); + if (section->used_by_bfd == NULL + && section->_raw_size != 0) + return false; + + if (! srec_read_section (abfd, section, section->used_by_bfd)) + return false; + } + + memcpy (location, (bfd_byte *) section->used_by_bfd + offset, + (size_t) count); + + return true; +} + +/* we have to save up all the Srecords for a splurge before output */ + +static boolean +srec_set_section_contents (abfd, section, location, offset, bytes_to_do) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type bytes_to_do; +{ + tdata_type *tdata = abfd->tdata.srec_data; + register srec_data_list_type *entry; + + entry = ((srec_data_list_type *) + bfd_alloc (abfd, sizeof (srec_data_list_type))); + if (entry == NULL) + return false; + + if (bytes_to_do + && (section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + bfd_byte *data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); + if (data == NULL) + return false; + memcpy ((PTR) data, location, (size_t) bytes_to_do); + + if ((section->lma + offset + bytes_to_do - 1) <= 0xffff) + { + + } + else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff + && tdata->type < 2) + { + tdata->type = 2; + } + else + { + tdata->type = 3; + } + + entry->data = data; + entry->where = section->lma + offset; + entry->size = bytes_to_do; + + /* Sort the records by address. Optimize for the common case of + adding a record to the end of the list. */ + if (tdata->tail != NULL + && entry->where >= tdata->tail->where) + { + tdata->tail->next = entry; + entry->next = NULL; + tdata->tail = entry; + } + else + { + register srec_data_list_type **look; + + for (look = &tdata->head; + *look != NULL && (*look)->where < entry->where; + look = &(*look)->next) + ; + entry->next = *look; + *look = entry; + if (entry->next == NULL) + tdata->tail = entry; + } + } + return true; +} + +/* Write a record of type, of the supplied number of bytes. The + supplied bytes and length don't have a checksum. That's worked out + here +*/ +static boolean +srec_write_record (abfd, type, address, data, end) + bfd *abfd; + int type; + bfd_vma address; + const bfd_byte *data; + const bfd_byte *end; +{ + char buffer[MAXCHUNK]; + unsigned int check_sum = 0; + CONST bfd_byte *src = data; + char *dst = buffer; + char *length; + bfd_size_type wrlen; + + *dst++ = 'S'; + *dst++ = '0' + type; + + length = dst; + dst += 2; /* leave room for dst*/ + + switch (type) + { + case 3: + case 7: + TOHEX (dst, (address >> 24), check_sum); + dst += 2; + case 8: + case 2: + TOHEX (dst, (address >> 16), check_sum); + dst += 2; + case 9: + case 1: + case 0: + TOHEX (dst, (address >> 8), check_sum); + dst += 2; + TOHEX (dst, (address), check_sum); + dst += 2; + break; + + } + for (src = data; src < end; src++) + { + TOHEX (dst, *src, check_sum); + dst += 2; + } + + /* Fill in the length */ + TOHEX (length, (dst - length) / 2, check_sum); + check_sum &= 0xff; + check_sum = 255 - check_sum; + TOHEX (dst, check_sum, check_sum); + dst += 2; + + *dst++ = '\r'; + *dst++ = '\n'; + wrlen = dst - buffer; + if (bfd_write ((PTR) buffer, 1, wrlen, abfd) != wrlen) + return false; + return true; +} + + + +static boolean +srec_write_header (abfd) + bfd *abfd; +{ + bfd_byte buffer[MAXCHUNK]; + bfd_byte *dst = buffer; + unsigned int i; + + /* I'll put an arbitary 40 char limit on header size */ + for (i = 0; i < 40 && abfd->filename[i]; i++) + { + *dst++ = abfd->filename[i]; + } + return srec_write_record (abfd, 0, 0, buffer, dst); +} + +static boolean +srec_write_section (abfd, tdata, list) + bfd *abfd; + tdata_type *tdata; + srec_data_list_type *list; +{ + unsigned int bytes_written = 0; + bfd_byte *location = list->data; + + while (bytes_written < list->size) + { + bfd_vma address; + + unsigned int bytes_this_chunk = list->size - bytes_written; + + if (bytes_this_chunk > CHUNK) + { + bytes_this_chunk = CHUNK; + } + + address = list->where + bytes_written; + + if (! srec_write_record (abfd, + tdata->type, + address, + location, + location + bytes_this_chunk)) + return false; + + bytes_written += bytes_this_chunk; + location += bytes_this_chunk; + } + + return true; +} + +static boolean +srec_write_terminator (abfd, tdata) + bfd *abfd; + tdata_type *tdata; +{ + bfd_byte buffer[2]; + + return srec_write_record (abfd, 10 - tdata->type, + abfd->start_address, buffer, buffer); +} + + + +static boolean +srec_write_symbols (abfd) + bfd *abfd; +{ + char buffer[MAXCHUNK]; + /* Dump out the symbols of a bfd */ + int i; + int count = bfd_get_symcount (abfd); + + if (count) + { + size_t len; + asymbol **table = bfd_get_outsymbols (abfd); + sprintf (buffer, "$$ %s\r\n", abfd->filename); + + len = strlen (buffer); + if (bfd_write (buffer, len, 1, abfd) != len) + return false; + + for (i = 0; i < count; i++) + { + asymbol *s = table[i]; +#if 0 + int len = strlen (s->name); + + /* If this symbol has a .[ocs] in it, it's probably a file name + and we'll output that as the module name */ + + if (len > 3 && s->name[len - 2] == '.') + { + int l; + sprintf (buffer, "$$ %s\r\n", s->name); + l = strlen (buffer); + if (bfd_write (buffer, l, 1, abfd) != l) + return false; + } + else +#endif + if (s->flags & (BSF_GLOBAL | BSF_LOCAL) + && (s->flags & BSF_DEBUGGING) == 0 + && s->name[0] != '.' + && s->name[0] != 't') + { + /* Just dump out non debug symbols */ + bfd_size_type l; + char buf2[40], *p; + + sprintf_vma (buf2, + s->value + s->section->output_section->lma + + s->section->output_offset); + p = buf2; + while (p[0] == '0' && p[1] != 0) + p++; + sprintf (buffer, " %s $%s\r\n", s->name, p); + l = strlen (buffer); + if (bfd_write (buffer, l, 1, abfd) != l) + return false; + } + } + sprintf (buffer, "$$ \r\n"); + len = strlen (buffer); + if (bfd_write (buffer, len, 1, abfd) != len) + return false; + } + + return true; +} + +static boolean +internal_srec_write_object_contents (abfd, symbols) + bfd *abfd; + int symbols; +{ + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *list; + + if (symbols) + { + if (! srec_write_symbols (abfd)) + return false; + } + + if (! srec_write_header (abfd)) + return false; + + /* Now wander though all the sections provided and output them */ + list = tdata->head; + + while (list != (srec_data_list_type *) NULL) + { + if (! srec_write_section (abfd, tdata, list)) + return false; + list = list->next; + } + return srec_write_terminator (abfd, tdata); +} + +static boolean +srec_write_object_contents (abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents (abfd, 0); +} + +static boolean +symbolsrec_write_object_contents (abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents (abfd, 1); +} + +/*ARGSUSED*/ +static int +srec_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +static asymbol * +srec_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +/* Return the amount of memory needed to read the symbol table. */ + +static long +srec_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); +} + +/* Return the symbol table. */ + +static long +srec_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int symcount = bfd_get_symcount (abfd); + asymbol *csymbols; + unsigned int i; + + csymbols = abfd->tdata.srec_data->csymbols; + if (csymbols == NULL) + { + asymbol *c; + struct srec_symbol *s; + + csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol)); + if (csymbols == NULL && symcount != 0) + return false; + abfd->tdata.srec_data->csymbols = csymbols; + + for (s = abfd->tdata.srec_data->symbols, c = csymbols; + s != NULL; + s = s->next, ++c) + { + c->the_bfd = abfd; + c->name = s->name; + c->value = s->val; + c->flags = BSF_GLOBAL; + c->section = bfd_abs_section_ptr; + c->udata.p = NULL; + } + } + + for (i = 0; i < symcount; i++) + *alocation++ = csymbols++; + *alocation = NULL; + + return symcount; +} + +/*ARGSUSED*/ +void +srec_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/*ARGSUSED*/ +void +srec_print_symbol (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + default: + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s", + symbol->section->name, + symbol->name); + + } +} + +#define srec_close_and_cleanup _bfd_generic_close_and_cleanup +#define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define srec_new_section_hook _bfd_generic_new_section_hook + +#define srec_bfd_is_local_label bfd_generic_is_local_label +#define srec_get_lineno _bfd_nosymbols_get_lineno +#define srec_find_nearest_line _bfd_nosymbols_find_nearest_line +#define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define srec_read_minisymbols _bfd_generic_read_minisymbols +#define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define srec_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define srec_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define srec_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define srec_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define srec_set_arch_mach bfd_default_set_arch_mach + +#define srec_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define srec_bfd_relax_section bfd_generic_relax_section +#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define srec_bfd_final_link _bfd_generic_final_link +#define srec_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target srec_vec = +{ + "srec", /* name */ + bfd_target_srec_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + srec_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + srec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (srec), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (srec), + BFD_JUMP_TABLE_RELOCS (srec), + BFD_JUMP_TABLE_WRITE (srec), + BFD_JUMP_TABLE_LINK (srec), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; + + + +const bfd_target symbolsrec_vec = +{ + "symbolsrec", /* name */ + bfd_target_srec_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + symbolsrec_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + symbolsrec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (srec), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (srec), + BFD_JUMP_TABLE_RELOCS (srec), + BFD_JUMP_TABLE_WRITE (srec), + BFD_JUMP_TABLE_LINK (srec), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/stab-syms.c b/contrib/gdb/bfd/stab-syms.c new file mode 100644 index 000000000000..f4fe6c8ba3cf --- /dev/null +++ b/contrib/gdb/bfd/stab-syms.c @@ -0,0 +1,57 @@ +/* Table of stab names for the BFD library. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" + +#define ARCH_SIZE 32 /* Value doesn't matter. */ +#include "libaout.h" +#include "aout/aout64.h" + +/* Ignore duplicate stab codes; just return the string for the first + one. */ +#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING) +#define __define_stab_duplicate(NAME, CODE, STRING) + +/* These are not really stab symbols, but it is + convenient to have them here for the sake of nm. + For completeness, we could also add N_TEXT etc, but those + are never needed, since nm treats those specially. */ +#define EXTRA_SYMBOLS \ + __define_name (N_SETA, "SETA")/* Absolute set element symbol */ \ + __define_name (N_SETT, "SETT")/* Text set element symbol */ \ + __define_name (N_SETD, "SETD")/* Data set element symbol */ \ + __define_name (N_SETB, "SETB")/* Bss set element symbol */ \ + __define_name (N_SETV, "SETV")/* Pointer to set vector in data area. */ \ + __define_name (N_INDR, "INDR") \ + __define_name (N_WARNING, "WARNING") + +const char * +bfd_get_stab_name (code) + int code; +{ + switch (code) + { +#define __define_name(val, str) case val: return str; +#include "aout/stab.def" + EXTRA_SYMBOLS + } + + return (const char *) 0; +} diff --git a/contrib/gdb/bfd/sunos.c b/contrib/gdb/bfd/sunos.c new file mode 100644 index 000000000000..77bf319bcd60 --- /dev/null +++ b/contrib/gdb/bfd/sunos.c @@ -0,0 +1,2767 @@ +/* BFD backend for SunOS binaries. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGETNAME "a.out-sunos-big" +#define MY(OP) CAT(sunos_big_,OP) + +#include "bfd.h" +#include "bfdlink.h" +#include "libaout.h" + +/* Static routines defined in this file. */ + +static boolean sunos_read_dynamic_info PARAMS ((bfd *)); +static long sunos_get_dynamic_symtab_upper_bound PARAMS ((bfd *)); +static boolean sunos_slurp_dynamic_symtab PARAMS ((bfd *)); +static long sunos_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **)); +static long sunos_get_dynamic_reloc_upper_bound PARAMS ((bfd *)); +static long sunos_canonicalize_dynamic_reloc + PARAMS ((bfd *, arelent **, asymbol **)); +static struct bfd_hash_entry *sunos_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table *sunos_link_hash_table_create + PARAMS ((bfd *)); +static boolean sunos_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, boolean)); +static boolean sunos_add_dynamic_symbols + PARAMS ((bfd *, struct bfd_link_info *, struct external_nlist **, + bfd_size_type *, char **)); +static boolean sunos_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, + bfd_vma, const char *, boolean, boolean, + struct bfd_link_hash_entry **)); +static boolean sunos_scan_relocs + PARAMS ((struct bfd_link_info *, bfd *, asection *, bfd_size_type)); +static boolean sunos_scan_std_relocs + PARAMS ((struct bfd_link_info *, bfd *, asection *, + const struct reloc_std_external *, bfd_size_type)); +static boolean sunos_scan_ext_relocs + PARAMS ((struct bfd_link_info *, bfd *, asection *, + const struct reloc_ext_external *, bfd_size_type)); +static boolean sunos_link_dynamic_object + PARAMS ((struct bfd_link_info *, bfd *)); +static boolean sunos_write_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct aout_link_hash_entry *)); +static boolean sunos_check_dynamic_reloc + PARAMS ((struct bfd_link_info *, bfd *, asection *, + struct aout_link_hash_entry *, PTR, bfd_byte *, boolean *, + bfd_vma *)); +static boolean sunos_finish_dynamic_link + PARAMS ((bfd *, struct bfd_link_info *)); + +#define MY_get_dynamic_symtab_upper_bound sunos_get_dynamic_symtab_upper_bound +#define MY_canonicalize_dynamic_symtab sunos_canonicalize_dynamic_symtab +#define MY_get_dynamic_reloc_upper_bound sunos_get_dynamic_reloc_upper_bound +#define MY_canonicalize_dynamic_reloc sunos_canonicalize_dynamic_reloc +#define MY_bfd_link_hash_table_create sunos_link_hash_table_create +#define MY_add_dynamic_symbols sunos_add_dynamic_symbols +#define MY_add_one_symbol sunos_add_one_symbol +#define MY_link_dynamic_object sunos_link_dynamic_object +#define MY_write_dynamic_symbol sunos_write_dynamic_symbol +#define MY_check_dynamic_reloc sunos_check_dynamic_reloc +#define MY_finish_dynamic_link sunos_finish_dynamic_link + +/* Include the usual a.out support. */ +#include "aoutf1.h" + +/* SunOS shared library support. We store a pointer to this structure + in obj_aout_dynamic_info (abfd). */ + +struct sunos_dynamic_info +{ + /* Whether we found any dynamic information. */ + boolean valid; + /* Dynamic information. */ + struct internal_sun4_dynamic_link dyninfo; + /* Number of dynamic symbols. */ + unsigned long dynsym_count; + /* Read in nlists for dynamic symbols. */ + struct external_nlist *dynsym; + /* asymbol structures for dynamic symbols. */ + aout_symbol_type *canonical_dynsym; + /* Read in dynamic string table. */ + char *dynstr; + /* Number of dynamic relocs. */ + unsigned long dynrel_count; + /* Read in dynamic relocs. This may be reloc_std_external or + reloc_ext_external. */ + PTR dynrel; + /* arelent structures for dynamic relocs. */ + arelent *canonical_dynrel; +}; + +/* The hash table of dynamic symbols is composed of two word entries. + See include/aout/sun4.h for details. */ + +#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD) + +/* Read in the basic dynamic information. This locates the __DYNAMIC + structure and uses it to find the dynamic_link structure. It + creates and saves a sunos_dynamic_info structure. If it can't find + __DYNAMIC, it sets the valid field of the sunos_dynamic_info + structure to false to avoid doing this work again. */ + +static boolean +sunos_read_dynamic_info (abfd) + bfd *abfd; +{ + struct sunos_dynamic_info *info; + asection *dynsec; + bfd_vma dynoff; + struct external_sun4_dynamic dyninfo; + unsigned long dynver; + struct external_sun4_dynamic_link linkinfo; + + if (obj_aout_dynamic_info (abfd) != (PTR) NULL) + return true; + + if ((abfd->flags & DYNAMIC) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + info = ((struct sunos_dynamic_info *) + bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info))); + if (!info) + return false; + info->valid = false; + info->dynsym = NULL; + info->dynstr = NULL; + info->canonical_dynsym = NULL; + info->dynrel = NULL; + info->canonical_dynrel = NULL; + obj_aout_dynamic_info (abfd) = (PTR) info; + + /* This code used to look for the __DYNAMIC symbol to locate the dynamic + linking information. + However this inhibits recovering the dynamic symbols from a + stripped object file, so blindly assume that the dynamic linking + information is located at the start of the data section. + We could verify this assumption later by looking through the dynamic + symbols for the __DYNAMIC symbol. */ + if ((abfd->flags & DYNAMIC) == 0) + return true; + if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo, + (file_ptr) 0, sizeof dyninfo)) + return true; + + dynver = GET_WORD (abfd, dyninfo.ld_version); + if (dynver != 2 && dynver != 3) + return true; + + dynoff = GET_WORD (abfd, dyninfo.ld); + + /* dynoff is a virtual address. It is probably always in the .data + section, but this code should work even if it moves. */ + if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd))) + dynsec = obj_textsec (abfd); + else + dynsec = obj_datasec (abfd); + dynoff -= bfd_get_section_vma (abfd, dynsec); + if (dynoff > bfd_section_size (abfd, dynsec)) + return true; + + /* This executable appears to be dynamically linked in a way that we + can understand. */ + if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff, + (bfd_size_type) sizeof linkinfo)) + return true; + + /* Swap in the dynamic link information. */ + info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded); + info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need); + info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules); + info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got); + info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt); + info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel); + info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash); + info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab); + info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash); + info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets); + info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols); + info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size); + info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text); + info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz); + + /* Reportedly the addresses need to be offset by the size of the + exec header in an NMAGIC file. */ + if (adata (abfd).magic == n_magic) + { + unsigned long exec_bytes_size = adata (abfd).exec_bytes_size; + + info->dyninfo.ld_need += exec_bytes_size; + info->dyninfo.ld_rules += exec_bytes_size; + info->dyninfo.ld_rel += exec_bytes_size; + info->dyninfo.ld_hash += exec_bytes_size; + info->dyninfo.ld_stab += exec_bytes_size; + info->dyninfo.ld_symbols += exec_bytes_size; + } + + /* The only way to get the size of the symbol information appears to + be to determine the distance between it and the string table. */ + info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab) + / EXTERNAL_NLIST_SIZE); + BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE + == (unsigned long) (info->dyninfo.ld_symbols + - info->dyninfo.ld_stab)); + + /* Similarly, the relocs end at the hash table. */ + info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel) + / obj_reloc_entry_size (abfd)); + BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd) + == (unsigned long) (info->dyninfo.ld_hash + - info->dyninfo.ld_rel)); + + info->valid = true; + + return true; +} + +/* Return the amount of memory required for the dynamic symbols. */ + +static long +sunos_get_dynamic_symtab_upper_bound (abfd) + bfd *abfd; +{ + struct sunos_dynamic_info *info; + + if (! sunos_read_dynamic_info (abfd)) + return -1; + + info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + if (! info->valid) + { + bfd_set_error (bfd_error_no_symbols); + return -1; + } + + return (info->dynsym_count + 1) * sizeof (asymbol *); +} + +/* Read the external dynamic symbols. */ + +static boolean +sunos_slurp_dynamic_symtab (abfd) + bfd *abfd; +{ + struct sunos_dynamic_info *info; + + /* Get the general dynamic information. */ + if (obj_aout_dynamic_info (abfd) == NULL) + { + if (! sunos_read_dynamic_info (abfd)) + return false; + } + + info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + if (! info->valid) + { + bfd_set_error (bfd_error_no_symbols); + return false; + } + + /* Get the dynamic nlist structures. */ + if (info->dynsym == (struct external_nlist *) NULL) + { + info->dynsym = ((struct external_nlist *) + bfd_alloc (abfd, + (info->dynsym_count + * EXTERNAL_NLIST_SIZE))); + if (info->dynsym == NULL && info->dynsym_count != 0) + return false; + if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0 + || (bfd_read ((PTR) info->dynsym, info->dynsym_count, + EXTERNAL_NLIST_SIZE, abfd) + != info->dynsym_count * EXTERNAL_NLIST_SIZE)) + { + if (info->dynsym != NULL) + { + bfd_release (abfd, info->dynsym); + info->dynsym = NULL; + } + return false; + } + } + + /* Get the dynamic strings. */ + if (info->dynstr == (char *) NULL) + { + info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size); + if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0) + return false; + if (bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0 + || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size, + abfd) + != info->dyninfo.ld_symb_size)) + { + if (info->dynstr != NULL) + { + bfd_release (abfd, info->dynstr); + info->dynstr = NULL; + } + return false; + } + } + + return true; +} + +/* Read in the dynamic symbols. */ + +static long +sunos_canonicalize_dynamic_symtab (abfd, storage) + bfd *abfd; + asymbol **storage; +{ + struct sunos_dynamic_info *info; + unsigned long i; + + if (! sunos_slurp_dynamic_symtab (abfd)) + return -1; + + info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + +#ifdef CHECK_DYNAMIC_HASH + /* Check my understanding of the dynamic hash table by making sure + that each symbol can be located in the hash table. */ + { + bfd_size_type table_size; + bfd_byte *table; + bfd_size_type i; + + if (info->dyninfo.ld_buckets > info->dynsym_count) + abort (); + table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash; + table = (bfd_byte *) bfd_malloc (table_size); + if (table == NULL && table_size != 0) + abort (); + if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0 + || bfd_read ((PTR) table, 1, table_size, abfd) != table_size) + abort (); + for (i = 0; i < info->dynsym_count; i++) + { + unsigned char *name; + unsigned long hash; + + name = ((unsigned char *) info->dynstr + + GET_WORD (abfd, info->dynsym[i].e_strx)); + hash = 0; + while (*name != '\0') + hash = (hash << 1) + *name++; + hash &= 0x7fffffff; + hash %= info->dyninfo.ld_buckets; + while (GET_WORD (abfd, table + hash * HASH_ENTRY_SIZE) != i) + { + hash = GET_WORD (abfd, + table + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD); + if (hash == 0 || hash >= table_size / HASH_ENTRY_SIZE) + abort (); + } + } + free (table); + } +#endif /* CHECK_DYNAMIC_HASH */ + + /* Get the asymbol structures corresponding to the dynamic nlist + structures. */ + if (info->canonical_dynsym == (aout_symbol_type *) NULL) + { + info->canonical_dynsym = ((aout_symbol_type *) + bfd_alloc (abfd, + (info->dynsym_count + * sizeof (aout_symbol_type)))); + if (info->canonical_dynsym == NULL && info->dynsym_count != 0) + return -1; + + if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym, + info->dynsym, info->dynsym_count, + info->dynstr, + info->dyninfo.ld_symb_size, + true)) + { + if (info->canonical_dynsym != NULL) + { + bfd_release (abfd, info->canonical_dynsym); + info->canonical_dynsym = NULL; + } + return -1; + } + } + + /* Return pointers to the dynamic asymbol structures. */ + for (i = 0; i < info->dynsym_count; i++) + *storage++ = (asymbol *) (info->canonical_dynsym + i); + *storage = NULL; + + return info->dynsym_count; +} + +/* Return the amount of memory required for the dynamic relocs. */ + +static long +sunos_get_dynamic_reloc_upper_bound (abfd) + bfd *abfd; +{ + struct sunos_dynamic_info *info; + + if (! sunos_read_dynamic_info (abfd)) + return -1; + + info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + if (! info->valid) + { + bfd_set_error (bfd_error_no_symbols); + return -1; + } + + return (info->dynrel_count + 1) * sizeof (arelent *); +} + +/* Read in the dynamic relocs. */ + +static long +sunos_canonicalize_dynamic_reloc (abfd, storage, syms) + bfd *abfd; + arelent **storage; + asymbol **syms; +{ + struct sunos_dynamic_info *info; + unsigned long i; + + /* Get the general dynamic information. */ + if (obj_aout_dynamic_info (abfd) == (PTR) NULL) + { + if (! sunos_read_dynamic_info (abfd)) + return -1; + } + + info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + if (! info->valid) + { + bfd_set_error (bfd_error_no_symbols); + return -1; + } + + /* Get the dynamic reloc information. */ + if (info->dynrel == NULL) + { + info->dynrel = (PTR) bfd_alloc (abfd, + (info->dynrel_count + * obj_reloc_entry_size (abfd))); + if (info->dynrel == NULL && info->dynrel_count != 0) + return -1; + if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0 + || (bfd_read ((PTR) info->dynrel, info->dynrel_count, + obj_reloc_entry_size (abfd), abfd) + != info->dynrel_count * obj_reloc_entry_size (abfd))) + { + if (info->dynrel != NULL) + { + bfd_release (abfd, info->dynrel); + info->dynrel = NULL; + } + return -1; + } + } + + /* Get the arelent structures corresponding to the dynamic reloc + information. */ + if (info->canonical_dynrel == (arelent *) NULL) + { + arelent *to; + + info->canonical_dynrel = ((arelent *) + bfd_alloc (abfd, + (info->dynrel_count + * sizeof (arelent)))); + if (info->canonical_dynrel == NULL && info->dynrel_count != 0) + return -1; + + to = info->canonical_dynrel; + + if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE) + { + register struct reloc_ext_external *p; + struct reloc_ext_external *pend; + + p = (struct reloc_ext_external *) info->dynrel; + pend = p + info->dynrel_count; + for (; p < pend; p++, to++) + NAME(aout,swap_ext_reloc_in) (abfd, p, to, syms, + info->dynsym_count); + } + else + { + register struct reloc_std_external *p; + struct reloc_std_external *pend; + + p = (struct reloc_std_external *) info->dynrel; + pend = p + info->dynrel_count; + for (; p < pend; p++, to++) + NAME(aout,swap_std_reloc_in) (abfd, p, to, syms, + info->dynsym_count); + } + } + + /* Return pointers to the dynamic arelent structures. */ + for (i = 0; i < info->dynrel_count; i++) + *storage++ = info->canonical_dynrel + i; + *storage = NULL; + + return info->dynrel_count; +} + +/* Code to handle linking of SunOS shared libraries. */ + +/* A SPARC procedure linkage table entry is 12 bytes. The first entry + in the table is a jump which is filled in by the runtime linker. + The remaining entries are branches back to the first entry, + followed by an index into the relocation table encoded to look like + a sethi of %g0. */ + +#define SPARC_PLT_ENTRY_SIZE (12) + +static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] = +{ + /* sethi %hi(0),%g1; address filled in by runtime linker. */ + 0x3, 0, 0, 0, + /* jmp %g1; offset filled in by runtime linker. */ + 0x81, 0xc0, 0x60, 0, + /* nop */ + 0x1, 0, 0, 0 +}; + +/* save %sp, -96, %sp */ +#define SPARC_PLT_ENTRY_WORD0 0x9de3bfa0 +/* call; address filled in later. */ +#define SPARC_PLT_ENTRY_WORD1 0x40000000 +/* sethi; reloc index filled in later. */ +#define SPARC_PLT_ENTRY_WORD2 0x01000000 + +/* This sequence is used when for the jump table entry to a defined + symbol in a complete executable. It is used when linking PIC + compiled code which is not being put into a shared library. */ +/* sethi
, %g1 */ +#define SPARC_PLT_PIC_WORD0 0x03000000 +/* jmp %g1 +
*/ +#define SPARC_PLT_PIC_WORD1 0x81c06000 +/* nop */ +#define SPARC_PLT_PIC_WORD2 0x01000000 + +/* An m68k procedure linkage table entry is 8 bytes. The first entry + in the table is a jump which is filled in the by the runtime + linker. The remaining entries are branches back to the first + entry, followed by a two byte index into the relocation table. */ + +#define M68K_PLT_ENTRY_SIZE (8) + +static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] = +{ + /* jmps @# */ + 0x4e, 0xf9, + /* Filled in by runtime linker with a magic address. */ + 0, 0, 0, 0, + /* Not used? */ + 0, 0 +}; + +/* bsrl */ +#define M68K_PLT_ENTRY_WORD0 (0x61ff) +/* Remaining words filled in later. */ + +/* An entry in the SunOS linker hash table. */ + +struct sunos_link_hash_entry +{ + struct aout_link_hash_entry root; + + /* If this is a dynamic symbol, this is its index into the dynamic + symbol table. This is initialized to -1. As the linker looks at + the input files, it changes this to -2 if it will be added to the + dynamic symbol table. After all the input files have been seen, + the linker will know whether to build a dynamic symbol table; if + it does build one, this becomes the index into the table. */ + long dynindx; + + /* If this is a dynamic symbol, this is the index of the name in the + dynamic symbol string table. */ + long dynstr_index; + + /* The offset into the global offset table used for this symbol. If + the symbol does not require a GOT entry, this is 0. */ + bfd_vma got_offset; + + /* The offset into the procedure linkage table used for this symbol. + If the symbol does not require a PLT entry, this is 0. */ + bfd_vma plt_offset; + + /* Some linker flags. */ + unsigned char flags; + /* Symbol is referenced by a regular object. */ +#define SUNOS_REF_REGULAR 01 + /* Symbol is defined by a regular object. */ +#define SUNOS_DEF_REGULAR 02 + /* Symbol is referenced by a dynamic object. */ +#define SUNOS_REF_DYNAMIC 04 + /* Symbol is defined by a dynamic object. */ +#define SUNOS_DEF_DYNAMIC 010 + /* Symbol is a constructor symbol in a regular object. */ +#define SUNOS_CONSTRUCTOR 020 +}; + +/* The SunOS linker hash table. */ + +struct sunos_link_hash_table +{ + struct aout_link_hash_table root; + + /* The object which holds the dynamic sections. */ + bfd *dynobj; + + /* Whether we have created the dynamic sections. */ + boolean dynamic_sections_created; + + /* Whether we need the dynamic sections. */ + boolean dynamic_sections_needed; + + /* The number of dynamic symbols. */ + size_t dynsymcount; + + /* The number of buckets in the hash table. */ + size_t bucketcount; + + /* The list of dynamic objects needed by dynamic objects included in + the link. */ + struct bfd_link_needed_list *needed; +}; + +/* Routine to create an entry in an SunOS link hash table. */ + +static struct bfd_hash_entry * +sunos_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct sunos_link_hash_entry *ret = (struct sunos_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct sunos_link_hash_entry *) NULL) + ret = ((struct sunos_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct sunos_link_hash_entry))); + if (ret == (struct sunos_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct sunos_link_hash_entry *) + NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != NULL) + { + /* Set local fields. */ + ret->dynindx = -1; + ret->dynstr_index = -1; + ret->got_offset = 0; + ret->plt_offset = 0; + ret->flags = 0; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a SunOS link hash table. */ + +static struct bfd_link_hash_table * +sunos_link_hash_table_create (abfd) + bfd *abfd; +{ + struct sunos_link_hash_table *ret; + + ret = ((struct sunos_link_hash_table *) + bfd_alloc (abfd, sizeof (struct sunos_link_hash_table))); + if (ret == (struct sunos_link_hash_table *) NULL) + return (struct bfd_link_hash_table *) NULL; + if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, + sunos_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return (struct bfd_link_hash_table *) NULL; + } + + ret->dynobj = NULL; + ret->dynamic_sections_created = false; + ret->dynamic_sections_needed = false; + ret->dynsymcount = 0; + ret->bucketcount = 0; + ret->needed = NULL; + + return &ret->root.root; +} + +/* Look up an entry in an SunOS link hash table. */ + +#define sunos_link_hash_lookup(table, string, create, copy, follow) \ + ((struct sunos_link_hash_entry *) \ + aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ + (follow))) + +/* Traverse a SunOS link hash table. */ + +#define sunos_link_hash_traverse(table, func, info) \ + (aout_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the SunOS link hash table from the info structure. This is + just a cast. */ + +#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash)) + +static boolean sunos_scan_dynamic_symbol + PARAMS ((struct sunos_link_hash_entry *, PTR)); + +/* Create the dynamic sections needed if we are linking against a + dynamic object, or if we are linking PIC compiled code. ABFD is a + bfd we can attach the dynamic sections to. The linker script will + look for these special sections names and put them in the right + place in the output file. See include/aout/sun4.h for more details + of the dynamic linking information. */ + +static boolean +sunos_create_dynamic_sections (abfd, info, needed) + bfd *abfd; + struct bfd_link_info *info; + boolean needed; +{ + asection *s; + + if (! sunos_hash_table (info)->dynamic_sections_created) + { + flagword flags; + + sunos_hash_table (info)->dynobj = abfd; + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + /* The .dynamic section holds the basic dynamic information: the + sun4_dynamic structure, the dynamic debugger information, and + the sun4_dynamic_link structure. */ + s = bfd_make_section (abfd, ".dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .got section holds the global offset table. The address + is put in the ld_got field. */ + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .plt section holds the procedure linkage table. The + address is put in the ld_plt field. */ + s = bfd_make_section (abfd, ".plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_CODE) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .dynrel section holds the dynamic relocs. The address is + put in the ld_rel field. */ + s = bfd_make_section (abfd, ".dynrel"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .hash section holds the dynamic hash table. The address + is put in the ld_hash field. */ + s = bfd_make_section (abfd, ".hash"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .dynsym section holds the dynamic symbols. The address + is put in the ld_stab field. */ + s = bfd_make_section (abfd, ".dynsym"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* The .dynstr section holds the dynamic symbol string table. + The address is put in the ld_symbols field. */ + s = bfd_make_section (abfd, ".dynstr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + sunos_hash_table (info)->dynamic_sections_created = true; + } + + if (needed && ! sunos_hash_table (info)->dynamic_sections_needed) + { + bfd *dynobj; + + dynobj = sunos_hash_table (info)->dynobj; + + s = bfd_get_section_by_name (dynobj, ".got"); + s->_raw_size = BYTES_IN_WORD; + + sunos_hash_table (info)->dynamic_sections_needed = true; + } + + return true; +} + +/* Add dynamic symbols during a link. This is called by the a.out + backend linker when it encounters an object with the DYNAMIC flag + set. */ + +static boolean +sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) + bfd *abfd; + struct bfd_link_info *info; + struct external_nlist **symsp; + bfd_size_type *sym_countp; + char **stringsp; +{ + asection *s; + bfd *dynobj; + struct sunos_dynamic_info *dinfo; + unsigned long need; + + /* We do not want to include the sections in a dynamic object in the + output file. We hack by simply clobbering the list of sections + in the BFD. This could be handled more cleanly by, say, a new + section flag; the existing SEC_NEVER_LOAD flag is not the one we + want, because that one still implies that the section takes up + space in the output file. */ + abfd->sections = NULL; + + /* The native linker seems to just ignore dynamic objects when -r is + used. */ + if (info->relocateable) + return true; + + /* There's no hope of using a dynamic object which does not exactly + match the format of the output file. */ + if (info->hash->creator != abfd->xvec) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* Make sure we have all the required information. */ + if (! sunos_create_dynamic_sections (abfd, info, true)) + return false; + + /* Make sure we have a .need and a .rules sections. These are only + needed if there really is a dynamic object in the link, so they + are not added by sunos_create_dynamic_sections. */ + dynobj = sunos_hash_table (info)->dynobj; + if (bfd_get_section_by_name (dynobj, ".need") == NULL) + { + /* The .need section holds the list of names of shared objets + which must be included at runtime. The address of this + section is put in the ld_need field. */ + s = bfd_make_section (dynobj, ".need"); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return false; + } + + if (bfd_get_section_by_name (dynobj, ".rules") == NULL) + { + /* The .rules section holds the path to search for shared + objects. The address of this section is put in the ld_rules + field. */ + s = bfd_make_section (dynobj, ".rules"); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return false; + } + + /* Pick up the dynamic symbols and return them to the caller. */ + if (! sunos_slurp_dynamic_symtab (abfd)) + return false; + + dinfo = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); + *symsp = dinfo->dynsym; + *sym_countp = dinfo->dynsym_count; + *stringsp = dinfo->dynstr; + + /* Record information about any other objects needed by this one. */ + need = dinfo->dyninfo.ld_need; + while (need != 0) + { + bfd_byte buf[16]; + unsigned long name, flags; + unsigned short major_vno, minor_vno; + struct bfd_link_needed_list *needed, **pp; + bfd_byte b; + + if (bfd_seek (abfd, need, SEEK_SET) != 0 + || bfd_read (buf, 1, 16, abfd) != 16) + return false; + + /* For the format of an ld_need entry, see aout/sun4.h. We + should probably define structs for this manipulation. */ + + name = bfd_get_32 (abfd, buf); + flags = bfd_get_32 (abfd, buf + 4); + major_vno = bfd_get_16 (abfd, buf + 8); + minor_vno = bfd_get_16 (abfd, buf + 10); + need = bfd_get_32 (abfd, buf + 12); + + needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)); + if (needed == NULL) + return false; + needed->by = abfd; + + /* We return the name as [-l]name[.maj][.min]. */ + + if ((flags & 0x80000000) != 0) + bfd_alloc_grow (abfd, "-l", 2); + if (bfd_seek (abfd, name, SEEK_SET) != 0) + return false; + do + { + if (bfd_read (&b, 1, 1, abfd) != 1) + return false; + bfd_alloc_grow (abfd, &b, 1); + } + while (b != '\0'); + if (major_vno != 0) + { + char verbuf[30]; + + sprintf (verbuf, ".%d", major_vno); + bfd_alloc_grow (abfd, verbuf, strlen (verbuf)); + if (minor_vno != 0) + { + sprintf (verbuf, ".%d", minor_vno); + bfd_alloc_grow (abfd, verbuf, strlen (verbuf)); + } + } + needed->name = bfd_alloc_finish (abfd); + if (needed->name == NULL) + return false; + + needed->next = NULL; + + for (pp = &sunos_hash_table (info)->needed; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = needed; + } + + return true; +} + +/* Function to add a single symbol to the linker hash table. This is + a wrapper around _bfd_generic_link_add_one_symbol which handles the + tweaking needed for dynamic linking support. */ + +static boolean +sunos_add_one_symbol (info, abfd, name, flags, section, value, string, + copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + struct sunos_link_hash_entry *h; + int new_flag; + + if (! sunos_hash_table (info)->dynamic_sections_created) + { + /* We must create the dynamic sections while reading the input + files, even though at this point we don't know if any of the + sections will be needed. This will ensure that the dynamic + sections are mapped to the right output section. It does no + harm to create these sections if they are not needed. */ + if (! sunos_create_dynamic_sections (abfd, info, false)) + return false; + } + + if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0 + || ! bfd_is_und_section (section)) + h = sunos_link_hash_lookup (sunos_hash_table (info), name, true, copy, + false); + else + h = ((struct sunos_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, name, true, copy, false)); + if (h == NULL) + return false; + + if (hashp != NULL) + *hashp = (struct bfd_link_hash_entry *) h; + + /* Treat a common symbol in a dynamic object as defined in the .bss + section of the dynamic object. We don't want to allocate space + for it in our process image. */ + if ((abfd->flags & DYNAMIC) != 0 + && bfd_is_com_section (section)) + section = obj_bsssec (abfd); + + if (! bfd_is_und_section (section) + && h->root.root.type != bfd_link_hash_new + && h->root.root.type != bfd_link_hash_undefined + && h->root.root.type != bfd_link_hash_defweak) + { + /* We are defining the symbol, and it is already defined. This + is a potential multiple definition error. */ + if ((abfd->flags & DYNAMIC) != 0) + { + /* The definition we are adding is from a dynamic object. + We do not want this new definition to override the + existing definition, so we pretend it is just a + reference. */ + section = bfd_und_section_ptr; + } + else if (h->root.root.type == bfd_link_hash_defined + && h->root.root.u.def.section->owner != NULL + && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) + { + /* The existing definition is from a dynamic object. We + want to override it with the definition we just found. + Clobber the existing definition. */ + h->root.root.type = bfd_link_hash_new; + } + else if (h->root.root.type == bfd_link_hash_common + && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0) + { + /* The existing definition is from a dynamic object. We + want to override it with the definition we just found. + Clobber the existing definition. We can't set it to new, + because it is on the undefined list. */ + h->root.root.type = bfd_link_hash_undefined; + h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner; + } + } + + if ((abfd->flags & DYNAMIC) != 0 + && abfd->xvec == info->hash->creator + && (h->flags & SUNOS_CONSTRUCTOR) != 0) + { + /* The existing symbol is a constructor symbol, and this symbol + is from a dynamic object. A constructor symbol is actually a + definition, although the type will be bfd_link_hash_undefined + at this point. We want to ignore the definition from the + dynamic object. */ + section = bfd_und_section_ptr; + } + else if ((flags & BSF_CONSTRUCTOR) != 0 + && (abfd->flags & DYNAMIC) == 0 + && h->root.root.type == bfd_link_hash_defined + && h->root.root.u.def.section->owner != NULL + && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) + { + /* The existing symbol is defined by a dynamic object, and this + is a constructor symbol. As above, we want to force the use + of the constructor symbol from the regular object. */ + h->root.root.type = bfd_link_hash_new; + } + + /* Do the usual procedure for adding a symbol. */ + if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, + value, string, copy, collect, + hashp)) + return false; + + if (abfd->xvec == info->hash->creator) + { + /* Set a flag in the hash table entry indicating the type of + reference or definition we just found. Keep a count of the + number of dynamic symbols we find. A dynamic symbol is one + which is referenced or defined by both a regular object and a + shared object. */ + if ((abfd->flags & DYNAMIC) == 0) + { + if (bfd_is_und_section (section)) + new_flag = SUNOS_REF_REGULAR; + else + new_flag = SUNOS_DEF_REGULAR; + } + else + { + if (bfd_is_und_section (section)) + new_flag = SUNOS_REF_DYNAMIC; + else + new_flag = SUNOS_DEF_DYNAMIC; + } + h->flags |= new_flag; + + if (h->dynindx == -1 + && (h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0) + { + ++sunos_hash_table (info)->dynsymcount; + h->dynindx = -2; + } + + if ((flags & BSF_CONSTRUCTOR) != 0 + && (abfd->flags & DYNAMIC) == 0) + h->flags |= SUNOS_CONSTRUCTOR; + } + + return true; +} + +/* Return the list of objects needed by BFD. */ + +/*ARGSUSED*/ +struct bfd_link_needed_list * +bfd_sunos_get_needed_list (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (info->hash->creator != &MY(vec)) + return NULL; + return sunos_hash_table (info)->needed; +} + +/* Record an assignment made to a symbol by a linker script. We need + this in case some dynamic object refers to this symbol. */ + +boolean +bfd_sunos_record_link_assignment (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct sunos_link_hash_entry *h; + + if (output_bfd->xvec != &MY(vec)) + return true; + + /* This is called after we have examined all the input objects. If + the symbol does not exist, it merely means that no object refers + to it, and we can just ignore it at this point. */ + h = sunos_link_hash_lookup (sunos_hash_table (info), name, + false, false, false); + if (h == NULL) + return true; + + /* In a shared library, the __DYNAMIC symbol does not appear in the + dynamic symbol table. */ + if (! info->shared || strcmp (name, "__DYNAMIC") != 0) + { + h->flags |= SUNOS_DEF_REGULAR; + + if (h->dynindx == -1) + { + ++sunos_hash_table (info)->dynsymcount; + h->dynindx = -2; + } + } + + return true; +} + +/* Set up the sizes and contents of the dynamic sections created in + sunos_add_dynamic_symbols. This is called by the SunOS linker + emulation before_allocation routine. We must set the sizes of the + sections before the linker sets the addresses of the various + sections. This unfortunately requires reading all the relocs so + that we can work out which ones need to become dynamic relocs. If + info->keep_memory is true, we keep the relocs in memory; otherwise, + we discard them, and will read them again later. */ + +boolean +bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, + srulesptr) + bfd *output_bfd; + struct bfd_link_info *info; + asection **sdynptr; + asection **sneedptr; + asection **srulesptr; +{ + bfd *dynobj; + size_t dynsymcount; + struct sunos_link_hash_entry *h; + asection *s; + size_t bucketcount; + size_t hashalloc; + size_t i; + bfd *sub; + + *sdynptr = NULL; + *sneedptr = NULL; + *srulesptr = NULL; + + if (output_bfd->xvec != &MY(vec)) + return true; + + /* Look through all the input BFD's and read their relocs. It would + be better if we didn't have to do this, but there is no other way + to determine the number of dynamic relocs we need, and, more + importantly, there is no other way to know which symbols should + get an entry in the procedure linkage table. */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + if ((sub->flags & DYNAMIC) == 0 + && sub->xvec == output_bfd->xvec) + { + if (! sunos_scan_relocs (info, sub, obj_textsec (sub), + exec_hdr (sub)->a_trsize) + || ! sunos_scan_relocs (info, sub, obj_datasec (sub), + exec_hdr (sub)->a_drsize)) + return false; + } + } + + dynobj = sunos_hash_table (info)->dynobj; + dynsymcount = sunos_hash_table (info)->dynsymcount; + + /* If there were no dynamic objects in the link, and we don't need + to build a global offset table, there is nothing to do here. */ + if (! sunos_hash_table (info)->dynamic_sections_needed) + return true; + + /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it. */ + h = sunos_link_hash_lookup (sunos_hash_table (info), + "__GLOBAL_OFFSET_TABLE_", false, false, false); + if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0) + { + h->flags |= SUNOS_DEF_REGULAR; + if (h->dynindx == -1) + { + ++sunos_hash_table (info)->dynsymcount; + h->dynindx = -2; + } + h->root.root.type = bfd_link_hash_defined; + h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got"); + h->root.root.u.def.value = 0; + } + + /* The .dynamic section is always the same size. */ + s = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (s != NULL); + s->_raw_size = (sizeof (struct external_sun4_dynamic) + + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE + + sizeof (struct external_sun4_dynamic_link)); + + /* Set the size of the .dynsym and .hash sections. We counted the + number of dynamic symbols as we read the input files. We will + build the dynamic symbol table (.dynsym) and the hash table + (.hash) when we build the final symbol table, because until then + we do not know the correct value to give the symbols. We build + the dynamic symbol string table (.dynstr) in a traversal of the + symbol table using sunos_scan_dynamic_symbol. */ + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (struct external_nlist); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return false; + + /* The number of buckets is just the number of symbols divided by + four. To compute the final size of the hash table, we must + actually compute the hash table. Normally we need exactly as + many entries in the hash table as there are dynamic symbols, but + if some of the buckets are not used we will need additional + entries. In the worst case, every symbol will hash to the same + bucket, and we will need BUCKETCOUNT - 1 extra entries. */ + if (dynsymcount >= 4) + bucketcount = dynsymcount / 4; + else if (dynsymcount > 0) + bucketcount = dynsymcount; + else + bucketcount = 1; + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE; + s->contents = (bfd_byte *) bfd_alloc (dynobj, hashalloc); + if (s->contents == NULL && dynsymcount > 0) + return false; + memset (s->contents, 0, hashalloc); + for (i = 0; i < bucketcount; i++) + PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE); + s->_raw_size = bucketcount * HASH_ENTRY_SIZE; + + sunos_hash_table (info)->bucketcount = bucketcount; + + /* Scan all the symbols, place them in the dynamic symbol table, and + build the dynamic hash table. We reuse dynsymcount as a counter + for the number of symbols we have added so far. */ + sunos_hash_table (info)->dynsymcount = 0; + sunos_link_hash_traverse (sunos_hash_table (info), + sunos_scan_dynamic_symbol, + (PTR) info); + BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount); + + /* The SunOS native linker seems to align the total size of the + symbol strings to a multiple of 8. I don't know if this is + important, but it can't hurt much. */ + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + if ((s->_raw_size & 7) != 0) + { + bfd_size_type add; + bfd_byte *contents; + + add = 8 - (s->_raw_size & 7); + contents = (bfd_byte *) bfd_realloc (s->contents, + (size_t) (s->_raw_size + add)); + if (contents == NULL) + return false; + memset (contents + s->_raw_size, 0, (size_t) add); + s->contents = contents; + s->_raw_size += add; + } + + /* Now that we have worked out the sizes of the procedure linkage + table and the dynamic relocs, allocate storage for them. */ + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + if (s->_raw_size != 0) + { + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL) + return false; + + /* Fill in the first entry in the table. */ + switch (bfd_get_arch (dynobj)) + { + case bfd_arch_sparc: + memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE); + break; + + case bfd_arch_m68k: + memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE); + break; + + default: + abort (); + } + } + + s = bfd_get_section_by_name (dynobj, ".dynrel"); + if (s->_raw_size != 0) + { + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL) + return false; + } + /* We use the reloc_count field to keep track of how many of the + relocs we have output so far. */ + s->reloc_count = 0; + + /* Make space for the global offset table. */ + s = bfd_get_section_by_name (dynobj, ".got"); + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL) + return false; + + *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic"); + *sneedptr = bfd_get_section_by_name (dynobj, ".need"); + *srulesptr = bfd_get_section_by_name (dynobj, ".rules"); + + return true; +} + +/* Scan the relocs for an input section. */ + +static boolean +sunos_scan_relocs (info, abfd, sec, rel_size) + struct bfd_link_info *info; + bfd *abfd; + asection *sec; + bfd_size_type rel_size; +{ + PTR relocs; + PTR free_relocs = NULL; + + if (rel_size == 0) + return true; + + if (! info->keep_memory) + relocs = free_relocs = bfd_malloc ((size_t) rel_size); + else + { + struct aout_section_data_struct *n; + + n = ((struct aout_section_data_struct *) + bfd_alloc (abfd, sizeof (struct aout_section_data_struct))); + if (n == NULL) + relocs = NULL; + else + { + set_aout_section_data (sec, n); + relocs = bfd_malloc ((size_t) rel_size); + aout_section_data (sec)->relocs = relocs; + } + } + if (relocs == NULL) + return false; + + if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 + || bfd_read (relocs, 1, rel_size, abfd) != rel_size) + goto error_return; + + if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE) + { + if (! sunos_scan_std_relocs (info, abfd, sec, + (struct reloc_std_external *) relocs, + rel_size)) + goto error_return; + } + else + { + if (! sunos_scan_ext_relocs (info, abfd, sec, + (struct reloc_ext_external *) relocs, + rel_size)) + goto error_return; + } + + if (free_relocs != NULL) + free (free_relocs); + + return true; + + error_return: + if (free_relocs != NULL) + free (free_relocs); + return false; +} + +/* Scan the relocs for an input section using standard relocs. We + need to figure out what to do for each reloc against a dynamic + symbol. If the symbol is in the .text section, an entry is made in + the procedure linkage table. Note that this will do the wrong + thing if the symbol is actually data; I don't think the Sun 3 + native linker handles this case correctly either. If the symbol is + not in the .text section, we must preserve the reloc as a dynamic + reloc. FIXME: We should also handle the PIC relocs here by + building global offset table entries. */ + +static boolean +sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size) + struct bfd_link_info *info; + bfd *abfd; + asection *sec; + const struct reloc_std_external *relocs; + bfd_size_type rel_size; +{ + bfd *dynobj; + asection *splt = NULL; + asection *srel = NULL; + struct sunos_link_hash_entry **sym_hashes; + const struct reloc_std_external *rel, *relend; + + /* We only know how to handle m68k plt entries. */ + if (bfd_get_arch (abfd) != bfd_arch_m68k) + { + bfd_set_error (bfd_error_invalid_target); + return false; + } + + dynobj = NULL; + + sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd); + + relend = relocs + rel_size / RELOC_STD_SIZE; + for (rel = relocs; rel < relend; rel++) + { + int r_index; + struct sunos_link_hash_entry *h; + + /* We only want relocs against external symbols. */ + if (bfd_header_big_endian (abfd)) + { + if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0) + continue; + } + else + { + if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE) == 0) + continue; + } + + /* Get the symbol index. */ + if (bfd_header_big_endian (abfd)) + r_index = ((rel->r_index[0] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[2]); + else + r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0]); + + /* Get the hash table entry. */ + h = sym_hashes[r_index]; + if (h == NULL) + { + /* This should not normally happen, but it will in any case + be caught in the relocation phase. */ + continue; + } + + /* At this point common symbols have already been allocated, so + we don't have to worry about them. We need to consider that + we may have already seen this symbol and marked it undefined; + if the symbol is really undefined, then SUNOS_DEF_DYNAMIC + will be zero. */ + if (h->root.root.type != bfd_link_hash_defined + && h->root.root.type != bfd_link_hash_defweak + && h->root.root.type != bfd_link_hash_undefined) + continue; + + if ((h->flags & SUNOS_DEF_DYNAMIC) == 0 + || (h->flags & SUNOS_DEF_REGULAR) != 0) + continue; + + if (dynobj == NULL) + { + if (! sunos_create_dynamic_sections (abfd, info, true)) + return false; + dynobj = sunos_hash_table (info)->dynobj; + splt = bfd_get_section_by_name (dynobj, ".plt"); + srel = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (splt != NULL && srel != NULL); + } + + BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0); + BFD_ASSERT (h->plt_offset != 0 + || ((h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + ? (h->root.root.u.def.section->owner->flags + & DYNAMIC) != 0 + : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0)); + + /* This reloc is against a symbol defined only by a dynamic + object. */ + + if (h->root.root.type == bfd_link_hash_undefined) + { + /* Presumably this symbol was marked as being undefined by + an earlier reloc. */ + srel->_raw_size += RELOC_STD_SIZE; + } + else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0) + { + bfd *sub; + + /* This reloc is not in the .text section. It must be + copied into the dynamic relocs. We mark the symbol as + being undefined. */ + srel->_raw_size += RELOC_STD_SIZE; + sub = h->root.root.u.def.section->owner; + h->root.root.type = bfd_link_hash_undefined; + h->root.root.u.undef.abfd = sub; + } + else + { + /* This symbol is in the .text section. We must give it an + entry in the procedure linkage table, if we have not + already done so. We change the definition of the symbol + to the .plt section; this will cause relocs against it to + be handled correctly. */ + if (h->plt_offset == 0) + { + if (splt->_raw_size == 0) + splt->_raw_size = M68K_PLT_ENTRY_SIZE; + h->plt_offset = splt->_raw_size; + + if ((h->flags & SUNOS_DEF_REGULAR) == 0) + { + h->root.root.u.def.section = splt; + h->root.root.u.def.value = splt->_raw_size; + } + + splt->_raw_size += M68K_PLT_ENTRY_SIZE; + + /* We may also need a dynamic reloc entry. */ + if ((h->flags & SUNOS_DEF_REGULAR) == 0) + srel->_raw_size += RELOC_STD_SIZE; + } + } + } + + return true; +} + +/* Scan the relocs for an input section using extended relocs. We + need to figure out what to do for each reloc against a dynamic + symbol. If the reloc is a WDISP30, and the symbol is in the .text + section, an entry is made in the procedure linkage table. + Otherwise, we must preserve the reloc as a dynamic reloc. */ + +static boolean +sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) + struct bfd_link_info *info; + bfd *abfd; + asection *sec; + const struct reloc_ext_external *relocs; + bfd_size_type rel_size; +{ + bfd *dynobj; + struct sunos_link_hash_entry **sym_hashes; + const struct reloc_ext_external *rel, *relend; + asection *splt = NULL; + asection *sgot = NULL; + asection *srel = NULL; + + /* We only know how to handle SPARC plt entries. */ + if (bfd_get_arch (abfd) != bfd_arch_sparc) + { + bfd_set_error (bfd_error_invalid_target); + return false; + } + + dynobj = NULL; + + sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd); + + relend = relocs + rel_size / RELOC_EXT_SIZE; + for (rel = relocs; rel < relend; rel++) + { + unsigned int r_index; + int r_extern; + int r_type; + struct sunos_link_hash_entry *h = NULL; + + /* Swap in the reloc information. */ + if (bfd_header_big_endian (abfd)) + { + r_index = ((rel->r_index[0] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[2]); + r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG); + } + else + { + r_index = ((rel->r_index[2] << 16) + | (rel->r_index[1] << 8) + | rel->r_index[0]); + r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); + r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + if (r_extern) + { + h = sym_hashes[r_index]; + if (h == NULL) + { + /* This should not normally happen, but it will in any + case be caught in the relocation phase. */ + continue; + } + } + + /* If this is a base relative reloc, we need to make an entry in + the .got section. */ + if (r_type == RELOC_BASE10 + || r_type == RELOC_BASE13 + || r_type == RELOC_BASE22) + { + if (dynobj == NULL) + { + if (! sunos_create_dynamic_sections (abfd, info, true)) + return false; + dynobj = sunos_hash_table (info)->dynobj; + splt = bfd_get_section_by_name (dynobj, ".plt"); + sgot = bfd_get_section_by_name (dynobj, ".got"); + srel = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + } + + if (r_extern) + { + if (h->got_offset != 0) + continue; + + h->got_offset = sgot->_raw_size; + } + else + { + if (r_index >= bfd_get_symcount (abfd)) + { + /* This is abnormal, but should be caught in the + relocation phase. */ + continue; + } + + if (adata (abfd).local_got_offsets == NULL) + { + adata (abfd).local_got_offsets = + (bfd_vma *) bfd_zalloc (abfd, + (bfd_get_symcount (abfd) + * sizeof (bfd_vma))); + if (adata (abfd).local_got_offsets == NULL) + return false; + } + + if (adata (abfd).local_got_offsets[r_index] != 0) + continue; + + adata (abfd).local_got_offsets[r_index] = sgot->_raw_size; + } + + sgot->_raw_size += BYTES_IN_WORD; + + /* If we are making a shared library, or if the symbol is + defined by a dynamic object, we will need a dynamic reloc + entry. */ + if (info->shared + || (h != NULL + && (h->flags & SUNOS_DEF_DYNAMIC) != 0 + && (h->flags & SUNOS_DEF_REGULAR) == 0)) + srel->_raw_size += RELOC_EXT_SIZE; + + continue; + } + + /* Otherwise, we are only interested in relocs against symbols + defined in dynamic objects but not in regular objects. We + only need to consider relocs against external symbols. */ + if (! r_extern) + { + /* But, if we are creating a shared library, we need to + generate an absolute reloc. */ + if (info->shared) + { + if (dynobj == NULL) + { + if (! sunos_create_dynamic_sections (abfd, info, true)) + return false; + dynobj = sunos_hash_table (info)->dynobj; + splt = bfd_get_section_by_name (dynobj, ".plt"); + sgot = bfd_get_section_by_name (dynobj, ".got"); + srel = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + } + + srel->_raw_size += RELOC_EXT_SIZE; + } + + continue; + } + + /* At this point common symbols have already been allocated, so + we don't have to worry about them. We need to consider that + we may have already seen this symbol and marked it undefined; + if the symbol is really undefined, then SUNOS_DEF_DYNAMIC + will be zero. */ + if (h->root.root.type != bfd_link_hash_defined + && h->root.root.type != bfd_link_hash_defweak + && h->root.root.type != bfd_link_hash_undefined) + continue; + + if (r_type != RELOC_JMP_TBL + && ! info->shared + && ((h->flags & SUNOS_DEF_DYNAMIC) == 0 + || (h->flags & SUNOS_DEF_REGULAR) != 0)) + continue; + + if (r_type == RELOC_JMP_TBL + && ! info->shared + && (h->flags & SUNOS_DEF_DYNAMIC) == 0 + && (h->flags & SUNOS_DEF_REGULAR) == 0) + { + /* This symbol is apparently undefined. Don't do anything + here; just let the relocation routine report an undefined + symbol. */ + continue; + } + + if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) + continue; + + if (dynobj == NULL) + { + if (! sunos_create_dynamic_sections (abfd, info, true)) + return false; + dynobj = sunos_hash_table (info)->dynobj; + splt = bfd_get_section_by_name (dynobj, ".plt"); + sgot = bfd_get_section_by_name (dynobj, ".got"); + srel = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + } + + BFD_ASSERT (r_type == RELOC_JMP_TBL + || info->shared + || (h->flags & SUNOS_REF_REGULAR) != 0); + BFD_ASSERT (r_type == RELOC_JMP_TBL + || info->shared + || h->plt_offset != 0 + || ((h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + ? (h->root.root.u.def.section->owner->flags + & DYNAMIC) != 0 + : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0)); + + /* This reloc is against a symbol defined only by a dynamic + object, or it is a jump table reloc from PIC compiled code. */ + + if (r_type != RELOC_JMP_TBL + && h->root.root.type == bfd_link_hash_undefined) + { + /* Presumably this symbol was marked as being undefined by + an earlier reloc. */ + srel->_raw_size += RELOC_EXT_SIZE; + } + else if (r_type != RELOC_JMP_TBL + && (h->root.root.u.def.section->flags & SEC_CODE) == 0) + { + bfd *sub; + + /* This reloc is not in the .text section. It must be + copied into the dynamic relocs. We mark the symbol as + being undefined. */ + srel->_raw_size += RELOC_EXT_SIZE; + if ((h->flags & SUNOS_DEF_REGULAR) == 0) + { + sub = h->root.root.u.def.section->owner; + h->root.root.type = bfd_link_hash_undefined; + h->root.root.u.undef.abfd = sub; + } + } + else + { + /* This symbol is in the .text section. We must give it an + entry in the procedure linkage table, if we have not + already done so. We change the definition of the symbol + to the .plt section; this will cause relocs against it to + be handled correctly. */ + if (h->plt_offset == 0) + { + if (splt->_raw_size == 0) + splt->_raw_size = SPARC_PLT_ENTRY_SIZE; + h->plt_offset = splt->_raw_size; + + if ((h->flags & SUNOS_DEF_REGULAR) == 0) + { + if (h->root.root.type == bfd_link_hash_undefined) + h->root.root.type = bfd_link_hash_defined; + h->root.root.u.def.section = splt; + h->root.root.u.def.value = splt->_raw_size; + } + + splt->_raw_size += SPARC_PLT_ENTRY_SIZE; + + /* We will also need a dynamic reloc entry, unless this + is a JMP_TBL reloc produced by linking PIC compiled + code, and we are not making a shared library. */ + if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) + srel->_raw_size += RELOC_EXT_SIZE; + } + + /* If we are creating a shared library, we need to copy over + any reloc other than a jump table reloc. */ + if (info->shared && r_type != RELOC_JMP_TBL) + srel->_raw_size += RELOC_EXT_SIZE; + } + } + + return true; +} + +/* Build the hash table of dynamic symbols, and to mark as written all + symbols from dynamic objects which we do not plan to write out. */ + +static boolean +sunos_scan_dynamic_symbol (h, data) + struct sunos_link_hash_entry *h; + PTR data; +{ + struct bfd_link_info *info = (struct bfd_link_info *) data; + + /* Set the written flag for symbols we do not want to write out as + part of the regular symbol table. This is all symbols which are + not defined in a regular object file. For some reason symbols + which are referenced by a regular object and defined by a dynamic + object do not seem to show up in the regular symbol table. It is + possible for a symbol to have only SUNOS_REF_REGULAR set here, it + is an undefined symbol which was turned into a common symbol + because it was found in an archive object which was not included + in the link. */ + if ((h->flags & SUNOS_DEF_REGULAR) == 0 + && (h->flags & SUNOS_DEF_DYNAMIC) != 0 + && strcmp (h->root.root.root.string, "__DYNAMIC") != 0) + h->root.written = true; + + /* If this symbol is defined by a dynamic object and referenced by a + regular object, see whether we gave it a reasonable value while + scanning the relocs. */ + + if ((h->flags & SUNOS_DEF_REGULAR) == 0 + && (h->flags & SUNOS_DEF_DYNAMIC) != 0 + && (h->flags & SUNOS_REF_REGULAR) != 0) + { + if ((h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) + && h->root.root.u.def.section->output_section == NULL) + { + bfd *sub; + + /* This symbol is currently defined in a dynamic section + which is not being put into the output file. This + implies that there is no reloc against the symbol. I'm + not sure why this case would ever occur. In any case, we + change the symbol to be undefined. */ + sub = h->root.root.u.def.section->owner; + h->root.root.type = bfd_link_hash_undefined; + h->root.root.u.undef.abfd = sub; + } + } + + /* If this symbol is defined or referenced by a regular file, add it + to the dynamic symbols. */ + if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0) + { + asection *s; + size_t len; + bfd_byte *contents; + unsigned char *name; + unsigned long hash; + bfd *dynobj; + + BFD_ASSERT (h->dynindx == -2); + + dynobj = sunos_hash_table (info)->dynobj; + + h->dynindx = sunos_hash_table (info)->dynsymcount; + ++sunos_hash_table (info)->dynsymcount; + + len = strlen (h->root.root.root.string); + + /* We don't bother to construct a BFD hash table for the strings + which are the names of the dynamic symbols. Using a hash + table for the regular symbols is beneficial, because the + regular symbols includes the debugging symbols, which have + long names and are often duplicated in several object files. + There are no debugging symbols in the dynamic symbols. */ + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + contents = (bfd_byte *) bfd_realloc (s->contents, + s->_raw_size + len + 1); + if (contents == NULL) + return false; + s->contents = contents; + + h->dynstr_index = s->_raw_size; + strcpy (contents + s->_raw_size, h->root.root.root.string); + s->_raw_size += len + 1; + + /* Add it to the dynamic hash table. */ + name = (unsigned char *) h->root.root.root.string; + hash = 0; + while (*name != '\0') + hash = (hash << 1) + *name++; + hash &= 0x7fffffff; + hash %= sunos_hash_table (info)->bucketcount; + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + + if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1) + PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE); + else + { + bfd_vma next; + + next = GET_WORD (dynobj, + (s->contents + + hash * HASH_ENTRY_SIZE + + BYTES_IN_WORD)); + PUT_WORD (dynobj, s->_raw_size / HASH_ENTRY_SIZE, + s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD); + PUT_WORD (dynobj, h->dynindx, s->contents + s->_raw_size); + PUT_WORD (dynobj, next, s->contents + s->_raw_size + BYTES_IN_WORD); + s->_raw_size += HASH_ENTRY_SIZE; + } + } + + return true; +} + +/* Link a dynamic object. We actually don't have anything to do at + this point. This entry point exists to prevent the regular linker + code from doing anything with the object. */ + +/*ARGSUSED*/ +static boolean +sunos_link_dynamic_object (info, abfd) + struct bfd_link_info *info; + bfd *abfd; +{ + return true; +} + +/* Write out a dynamic symbol. This is called by the final traversal + over the symbol table. */ + +static boolean +sunos_write_dynamic_symbol (output_bfd, info, harg) + bfd *output_bfd; + struct bfd_link_info *info; + struct aout_link_hash_entry *harg; +{ + struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; + int type; + bfd_vma val; + asection *s; + struct external_nlist *outsym; + + if (h->dynindx < 0) + return true; + + switch (h->root.root.type) + { + default: + case bfd_link_hash_new: + abort (); + /* Avoid variable not initialized warnings. */ + return true; + case bfd_link_hash_undefined: + type = N_UNDF | N_EXT; + val = 0; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + { + asection *sec; + asection *output_section; + + sec = h->root.root.u.def.section; + output_section = sec->output_section; + BFD_ASSERT (bfd_is_abs_section (output_section) + || output_section->owner == output_bfd); + if (h->plt_offset != 0 + && (h->flags & SUNOS_DEF_REGULAR) == 0) + { + type = N_UNDF | N_EXT; + val = 0; + } + else + { + if (output_section == obj_textsec (output_bfd)) + type = (h->root.root.type == bfd_link_hash_defined + ? N_TEXT + : N_WEAKT); + else if (output_section == obj_datasec (output_bfd)) + type = (h->root.root.type == bfd_link_hash_defined + ? N_DATA + : N_WEAKD); + else if (output_section == obj_bsssec (output_bfd)) + type = (h->root.root.type == bfd_link_hash_defined + ? N_BSS + : N_WEAKB); + else + type = (h->root.root.type == bfd_link_hash_defined + ? N_ABS + : N_WEAKA); + type |= N_EXT; + val = (h->root.root.u.def.value + + output_section->vma + + sec->output_offset); + } + } + break; + case bfd_link_hash_common: + type = N_UNDF | N_EXT; + val = h->root.root.u.c.size; + break; + case bfd_link_hash_undefweak: + type = N_WEAKU; + val = 0; + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: Ignore these for now. The circumstances under which + they should be written out are not clear to me. */ + return true; + } + + s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + outsym = ((struct external_nlist *) + (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE)); + + bfd_h_put_8 (output_bfd, type, outsym->e_type); + bfd_h_put_8 (output_bfd, 0, outsym->e_other); + + /* FIXME: The native linker doesn't use 0 for desc. It seems to use + one less than the desc value in the shared library, although that + seems unlikely. */ + bfd_h_put_16 (output_bfd, 0, outsym->e_desc); + + PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx); + PUT_WORD (output_bfd, val, outsym->e_value); + + /* If this symbol is in the procedure linkage table, fill in the + table entry. */ + if (h->plt_offset != 0) + { + bfd *dynobj; + asection *splt; + bfd_byte *p; + asection *s; + bfd_vma r_address; + + dynobj = sunos_hash_table (info)->dynobj; + splt = bfd_get_section_by_name (dynobj, ".plt"); + p = splt->contents + h->plt_offset; + + s = bfd_get_section_by_name (dynobj, ".dynrel"); + + r_address = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + + switch (bfd_get_arch (output_bfd)) + { + case bfd_arch_sparc: + if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) + { + bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p); + bfd_put_32 (output_bfd, + (SPARC_PLT_ENTRY_WORD1 + + (((- (h->plt_offset + 4) >> 2) + & 0x3fffffff))), + p + 4); + bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count, + p + 8); + } + else + { + bfd_vma val; + + val = (h->root.root.u.def.section->output_section->vma + + h->root.root.u.def.section->output_offset + + h->root.root.u.def.value); + bfd_put_32 (output_bfd, + SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff), + p); + bfd_put_32 (output_bfd, + SPARC_PLT_PIC_WORD1 + (val & 0x3ff), + p + 4); + bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8); + } + break; + + case bfd_arch_m68k: + if (! info->shared && (h->flags & SUNOS_DEF_REGULAR) != 0) + abort (); + bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p); + bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2); + bfd_put_16 (output_bfd, s->reloc_count, p + 6); + r_address += 2; + break; + + default: + abort (); + } + + /* We also need to add a jump table reloc, unless this is the + result of a JMP_TBL reloc from PIC compiled code. */ + if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) + { + BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) + < s->_raw_size); + p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd); + if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE) + { + struct reloc_std_external *srel; + + srel = (struct reloc_std_external *) p; + PUT_WORD (output_bfd, r_address, srel->r_address); + if (bfd_header_big_endian (output_bfd)) + { + srel->r_index[0] = h->dynindx >> 16; + srel->r_index[1] = h->dynindx >> 8; + srel->r_index[2] = h->dynindx; + srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG + | RELOC_STD_BITS_JMPTABLE_BIG); + } + else + { + srel->r_index[2] = h->dynindx >> 16; + srel->r_index[1] = h->dynindx >> 8; + srel->r_index[0] = h->dynindx; + srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE + | RELOC_STD_BITS_JMPTABLE_LITTLE); + } + } + else + { + struct reloc_ext_external *erel; + + erel = (struct reloc_ext_external *) p; + PUT_WORD (output_bfd, r_address, erel->r_address); + if (bfd_header_big_endian (output_bfd)) + { + erel->r_index[0] = h->dynindx >> 16; + erel->r_index[1] = h->dynindx >> 8; + erel->r_index[2] = h->dynindx; + erel->r_type[0] = + (RELOC_EXT_BITS_EXTERN_BIG + | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG)); + } + else + { + erel->r_index[2] = h->dynindx >> 16; + erel->r_index[1] = h->dynindx >> 8; + erel->r_index[0] = h->dynindx; + erel->r_type[0] = + (RELOC_EXT_BITS_EXTERN_LITTLE + | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE)); + } + PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend); + } + + ++s->reloc_count; + } + } + + return true; +} + +/* This is called for each reloc against an external symbol. If this + is a reloc which are are going to copy as a dynamic reloc, then + copy it over, and tell the caller to not bother processing this + reloc. */ + +/*ARGSUSED*/ +static boolean +sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, + contents, skip, relocationp) + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + struct aout_link_hash_entry *harg; + PTR reloc; + bfd_byte *contents; + boolean *skip; + bfd_vma *relocationp; +{ + struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; + bfd *dynobj; + boolean baserel; + boolean jmptbl; + asection *s; + bfd_byte *p; + long indx; + + *skip = false; + + dynobj = sunos_hash_table (info)->dynobj; + + if (h != NULL && h->plt_offset != 0) + { + asection *splt; + + /* Redirect the relocation to the PLT entry. */ + splt = bfd_get_section_by_name (dynobj, ".plt"); + *relocationp = (splt->output_section->vma + + splt->output_offset + + h->plt_offset); + } + + if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) + { + struct reloc_std_external *srel; + + srel = (struct reloc_std_external *) reloc; + if (bfd_header_big_endian (input_bfd)) + { + baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); + jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + } + else + { + baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); + jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); + } + } + else + { + struct reloc_ext_external *erel; + int r_type; + + erel = (struct reloc_ext_external *) reloc; + if (bfd_header_big_endian (input_bfd)) + r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG); + else + r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE); + baserel = (r_type == RELOC_BASE10 + || r_type == RELOC_BASE13 + || r_type == RELOC_BASE22); + jmptbl = r_type == RELOC_JMP_TBL; + } + + if (baserel) + { + bfd_vma *got_offsetp; + asection *sgot; + + if (h != NULL) + got_offsetp = &h->got_offset; + else if (adata (input_bfd).local_got_offsets == NULL) + got_offsetp = NULL; + else + { + struct reloc_std_external *srel; + int r_index; + + srel = (struct reloc_std_external *) reloc; + if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) + { + if (bfd_header_big_endian (input_bfd)) + r_index = ((srel->r_index[0] << 16) + | (srel->r_index[1] << 8) + | srel->r_index[2]); + else + r_index = ((srel->r_index[2] << 16) + | (srel->r_index[1] << 8) + | srel->r_index[0]); + } + else + { + struct reloc_ext_external *erel; + + erel = (struct reloc_ext_external *) reloc; + if (bfd_header_big_endian (input_bfd)) + r_index = ((erel->r_index[0] << 16) + | (erel->r_index[1] << 8) + | erel->r_index[2]); + else + r_index = ((erel->r_index[2] << 16) + | (erel->r_index[1] << 8) + | erel->r_index[0]); + } + + got_offsetp = adata (input_bfd).local_got_offsets + r_index; + } + + BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + + /* We set the least significant bit to indicate whether we have + already initialized the GOT entry. */ + if ((*got_offsetp & 1) == 0) + { + if (h == NULL + || (! info->shared + && ((h->flags & SUNOS_DEF_DYNAMIC) == 0 + || (h->flags & SUNOS_DEF_REGULAR) != 0))) + PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp); + else + PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp); + + if (info->shared + || (h != NULL + && (h->flags & SUNOS_DEF_DYNAMIC) != 0 + && (h->flags & SUNOS_DEF_REGULAR) == 0)) + { + /* We need to create a GLOB_DAT or 32 reloc to tell the + dynamic linker to fill in this entry in the table. */ + + s = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) + < s->_raw_size); + + p = (s->contents + + s->reloc_count * obj_reloc_entry_size (dynobj)); + + if (h != NULL) + indx = h->dynindx; + else + indx = 0; + + if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) + { + struct reloc_std_external *srel; + + srel = (struct reloc_std_external *) p; + PUT_WORD (dynobj, + (*got_offsetp + + sgot->output_section->vma + + sgot->output_offset), + srel->r_address); + if (bfd_header_big_endian (dynobj)) + { + srel->r_index[0] = indx >> 16; + srel->r_index[1] = indx >> 8; + srel->r_index[2] = indx; + if (h == NULL) + srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG; + else + srel->r_type[0] = + (RELOC_STD_BITS_EXTERN_BIG + | RELOC_STD_BITS_BASEREL_BIG + | RELOC_STD_BITS_RELATIVE_BIG + | (2 << RELOC_STD_BITS_LENGTH_SH_BIG)); + } + else + { + srel->r_index[2] = indx >> 16; + srel->r_index[1] = indx >> 8; + srel->r_index[0] = indx; + if (h == NULL) + srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE; + else + srel->r_type[0] = + (RELOC_STD_BITS_EXTERN_LITTLE + | RELOC_STD_BITS_BASEREL_LITTLE + | RELOC_STD_BITS_RELATIVE_LITTLE + | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE)); + } + } + else + { + struct reloc_ext_external *erel; + + erel = (struct reloc_ext_external *) p; + PUT_WORD (dynobj, + (*got_offsetp + + sgot->output_section->vma + + sgot->output_offset), + erel->r_address); + if (bfd_header_big_endian (dynobj)) + { + erel->r_index[0] = indx >> 16; + erel->r_index[1] = indx >> 8; + erel->r_index[2] = indx; + if (h == NULL) + erel->r_type[0] = + RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG; + else + erel->r_type[0] = + (RELOC_EXT_BITS_EXTERN_BIG + | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG)); + } + else + { + erel->r_index[2] = indx >> 16; + erel->r_index[1] = indx >> 8; + erel->r_index[0] = indx; + if (h == NULL) + erel->r_type[0] = + RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE; + else + erel->r_type[0] = + (RELOC_EXT_BITS_EXTERN_LITTLE + | (RELOC_GLOB_DAT + << RELOC_EXT_BITS_TYPE_SH_LITTLE)); + } + PUT_WORD (dynobj, 0, erel->r_addend); + } + + ++s->reloc_count; + } + + *got_offsetp |= 1; + } + + *relocationp = sgot->vma + (*got_offsetp &~ 1); + + /* There is nothing else to do for a base relative reloc. */ + return true; + } + + if (! sunos_hash_table (info)->dynamic_sections_needed) + return true; + if (! info->shared) + { + if (h == NULL + || h->dynindx == -1 + || h->root.root.type != bfd_link_hash_undefined + || (h->flags & SUNOS_DEF_REGULAR) != 0 + || (h->flags & SUNOS_DEF_DYNAMIC) == 0 + || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0) + return true; + } + else + { + if (h != NULL + && (h->dynindx == -1 + || jmptbl + || strcmp (h->root.root.root.string, + "__GLOBAL_OFFSET_TABLE_") == 0)) + return true; + } + + /* It looks like this is a reloc we are supposed to copy. */ + + s = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->_raw_size); + + p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj); + + /* Copy the reloc over. */ + memcpy (p, reloc, obj_reloc_entry_size (dynobj)); + + if (h != NULL) + indx = h->dynindx; + else + indx = 0; + + /* Adjust the address and symbol index. */ + if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) + { + struct reloc_std_external *srel; + + srel = (struct reloc_std_external *) p; + PUT_WORD (dynobj, + (GET_WORD (dynobj, srel->r_address) + + input_section->output_section->vma + + input_section->output_offset), + srel->r_address); + if (bfd_header_big_endian (dynobj)) + { + srel->r_index[0] = indx >> 16; + srel->r_index[1] = indx >> 8; + srel->r_index[2] = indx; + } + else + { + srel->r_index[2] = indx >> 16; + srel->r_index[1] = indx >> 8; + srel->r_index[0] = indx; + } + } + else + { + struct reloc_ext_external *erel; + + erel = (struct reloc_ext_external *) p; + PUT_WORD (dynobj, + (GET_WORD (dynobj, erel->r_address) + + input_section->output_section->vma + + input_section->output_offset), + erel->r_address); + if (bfd_header_big_endian (dynobj)) + { + erel->r_index[0] = indx >> 16; + erel->r_index[1] = indx >> 8; + erel->r_index[2] = indx; + } + else + { + erel->r_index[2] = indx >> 16; + erel->r_index[1] = indx >> 8; + erel->r_index[0] = indx; + } + } + + ++s->reloc_count; + + if (h != NULL) + *skip = true; + + return true; +} + +/* Finish up the dynamic linking information. */ + +static boolean +sunos_finish_dynamic_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *o; + asection *s; + asection *sdyn; + struct external_sun4_dynamic esd; + struct external_sun4_dynamic_link esdl; + + if (! sunos_hash_table (info)->dynamic_sections_needed) + return true; + + dynobj = sunos_hash_table (info)->dynobj; + + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + /* Finish up the .need section. The linker emulation code filled it + in, but with offsets from the start of the section instead of + real addresses. Now that we know the section location, we can + fill in the final values. */ + s = bfd_get_section_by_name (dynobj, ".need"); + if (s != NULL && s->_raw_size != 0) + { + file_ptr filepos; + bfd_byte *p; + + filepos = s->output_section->filepos + s->output_offset; + p = s->contents; + while (1) + { + bfd_vma val; + + PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p); + val = GET_WORD (dynobj, p + 12); + if (val == 0) + break; + PUT_WORD (dynobj, val + filepos, p + 12); + p += 16; + } + } + + /* The first entry in the .got section is the address of the + dynamic information, unless this is a shared library. */ + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + if (info->shared) + PUT_WORD (dynobj, 0, s->contents); + else + PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset, + s->contents); + + for (o = dynobj->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) != 0 + && o->contents != NULL) + { + BFD_ASSERT (o->output_section != NULL + && o->output_section->owner == abfd); + if (! bfd_set_section_contents (abfd, o->output_section, + o->contents, o->output_offset, + o->_raw_size)) + return false; + } + } + + /* Finish up the dynamic link information. */ + PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version); + PUT_WORD (dynobj, + sdyn->output_section->vma + sdyn->output_offset + sizeof esd, + esd.ldd); + PUT_WORD (dynobj, + (sdyn->output_section->vma + + sdyn->output_offset + + sizeof esd + + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE), + esd.ld); + + if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd, + sdyn->output_offset, sizeof esd)) + return false; + + + PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded); + + s = bfd_get_section_by_name (dynobj, ".need"); + if (s == NULL || s->_raw_size == 0) + PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need); + else + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_need); + + s = bfd_get_section_by_name (dynobj, ".rules"); + if (s == NULL || s->_raw_size == 0) + PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules); + else + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_rules); + + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_got); + + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_plt); + PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz); + + s = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) == s->_raw_size); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_rel); + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_hash); + + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_stab); + + PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash); + + PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount, + esdl.ld_buckets); + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_symbols); + PUT_WORD (dynobj, s->_raw_size, esdl.ld_symb_size); + + /* The size of the text area is the size of the .text section + rounded up to a page boundary. FIXME: Should the page size be + conditional on something? */ + PUT_WORD (dynobj, + BFD_ALIGN (obj_textsec (abfd)->_raw_size, 0x2000), + esdl.ld_text); + + if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl, + (sdyn->output_offset + + sizeof esd + + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE), + sizeof esdl)) + return false; + + abfd->flags |= DYNAMIC; + + return true; +} diff --git a/contrib/gdb/bfd/syms.c b/contrib/gdb/bfd/syms.c new file mode 100644 index 000000000000..e3007e4c5f01 --- /dev/null +++ b/contrib/gdb/bfd/syms.c @@ -0,0 +1,1084 @@ +/* Generic symbol-table support for the BFD library. + Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Symbols + + BFD tries to maintain as much symbol information as it can when + it moves information from file to file. BFD passes information + to applications though the <> structure. When the + application requests the symbol table, BFD reads the table in + the native form and translates parts of it into the internal + format. To maintain more than the information passed to + applications, some targets keep some information ``behind the + scenes'' in a structure only the particular back end knows + about. For example, the coff back end keeps the original + symbol table structure as well as the canonical structure when + a BFD is read in. On output, the coff back end can reconstruct + the output symbol table so that no information is lost, even + information unique to coff which BFD doesn't know or + understand. If a coff symbol table were read, but were written + through an a.out back end, all the coff specific information + would be lost. The symbol table of a BFD + is not necessarily read in until a canonicalize request is + made. Then the BFD back end fills in a table provided by the + application with pointers to the canonical information. To + output symbols, the application provides BFD with a table of + pointers to pointers to <>s. This allows applications + like the linker to output a symbol as it was read, since the ``behind + the scenes'' information will be still available. +@menu +@* Reading Symbols:: +@* Writing Symbols:: +@* Mini Symbols:: +@* typedef asymbol:: +@* symbol handling functions:: +@end menu + +INODE +Reading Symbols, Writing Symbols, Symbols, Symbols +SUBSECTION + Reading symbols + + There are two stages to reading a symbol table from a BFD: + allocating storage, and the actual reading process. This is an + excerpt from an application which reads the symbol table: + +| long storage_needed; +| asymbol **symbol_table; +| long number_of_symbols; +| long i; +| +| storage_needed = bfd_get_symtab_upper_bound (abfd); +| +| if (storage_needed < 0) +| FAIL +| +| if (storage_needed == 0) { +| return ; +| } +| symbol_table = (asymbol **) xmalloc (storage_needed); +| ... +| number_of_symbols = +| bfd_canonicalize_symtab (abfd, symbol_table); +| +| if (number_of_symbols < 0) +| FAIL +| +| for (i = 0; i < number_of_symbols; i++) { +| process_symbol (symbol_table[i]); +| } + + All storage for the symbols themselves is in an obstack + connected to the BFD; it is freed when the BFD is closed. + + +INODE +Writing Symbols, Mini Symbols, Reading Symbols, Symbols +SUBSECTION + Writing symbols + + Writing of a symbol table is automatic when a BFD open for + writing is closed. The application attaches a vector of + pointers to pointers to symbols to the BFD being written, and + fills in the symbol count. The close and cleanup code reads + through the table provided and performs all the necessary + operations. The BFD output code must always be provided with an + ``owned'' symbol: one which has come from another BFD, or one + which has been created using <>. Here is an + example showing the creation of a symbol table with only one element: + +| #include "bfd.h" +| main() +| { +| bfd *abfd; +| asymbol *ptrs[2]; +| asymbol *new; +| +| abfd = bfd_openw("foo","a.out-sunos-big"); +| bfd_set_format(abfd, bfd_object); +| new = bfd_make_empty_symbol(abfd); +| new->name = "dummy_symbol"; +| new->section = bfd_make_section_old_way(abfd, ".text"); +| new->flags = BSF_GLOBAL; +| new->value = 0x12345; +| +| ptrs[0] = new; +| ptrs[1] = (asymbol *)0; +| +| bfd_set_symtab(abfd, ptrs, 1); +| bfd_close(abfd); +| } +| +| ./makesym +| nm foo +| 00012345 A dummy_symbol + + Many formats cannot represent arbitary symbol information; for + instance, the <> object format does not allow an + arbitary number of sections. A symbol pointing to a section + which is not one of <<.text>>, <<.data>> or <<.bss>> cannot + be described. + +INODE +Mini Symbols, typedef asymbol, Writing Symbols, Symbols +SUBSECTION + Mini Symbols + + Mini symbols provide read-only access to the symbol table. + They use less memory space, but require more time to access. + They can be useful for tools like nm or objdump, which may + have to handle symbol tables of extremely large executables. + + The <> function will read the symbols + into memory in an internal form. It will return a <> + pointer to a block of memory, a symbol count, and the size of + each symbol. The pointer is allocated using <>, and + should be freed by the caller when it is no longer needed. + + The function <> will take a pointer + to a minisymbol, and a pointer to a structure returned by + <>, and return a <> structure. + The return value may or may not be the same as the value from + <> which was passed in. + +*/ + + + +/* +DOCDD +INODE +typedef asymbol, symbol handling functions, Mini Symbols, Symbols + +*/ +/* +SUBSECTION + typedef asymbol + + An <> has the form: + +*/ + +/* +CODE_FRAGMENT + +. +.typedef struct symbol_cache_entry +.{ +. {* A pointer to the BFD which owns the symbol. This information +. is necessary so that a back end can work out what additional +. information (invisible to the application writer) is carried +. with the symbol. +. +. This field is *almost* redundant, since you can use section->owner +. instead, except that some symbols point to the global sections +. bfd_{abs,com,und}_section. This could be fixed by making +. these globals be per-bfd (or per-target-flavor). FIXME. *} +. +. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} +. +. {* The text of the symbol. The name is left alone, and not copied; the +. application may not alter it. *} +. CONST char *name; +. +. {* The value of the symbol. This really should be a union of a +. numeric value with a pointer, since some flags indicate that +. a pointer to another symbol is stored here. *} +. symvalue value; +. +. {* Attributes of a symbol: *} +. +.#define BSF_NO_FLAGS 0x00 +. +. {* The symbol has local scope; <> in <>. The value +. is the offset into the section of the data. *} +.#define BSF_LOCAL 0x01 +. +. {* The symbol has global scope; initialized data in <>. The +. value is the offset into the section of the data. *} +.#define BSF_GLOBAL 0x02 +. +. {* The symbol has global scope and is exported. The value is +. the offset into the section of the data. *} +.#define BSF_EXPORT BSF_GLOBAL {* no real difference *} +. +. {* A normal C symbol would be one of: +. <>, <>, <> or +. <> *} +. +. {* The symbol is a debugging record. The value has an arbitary +. meaning. *} +.#define BSF_DEBUGGING 0x08 +. +. {* The symbol denotes a function entry point. Used in ELF, +. perhaps others someday. *} +.#define BSF_FUNCTION 0x10 +. +. {* Used by the linker. *} +.#define BSF_KEEP 0x20 +.#define BSF_KEEP_G 0x40 +. +. {* A weak global symbol, overridable without warnings by +. a regular global symbol of the same name. *} +.#define BSF_WEAK 0x80 +. +. {* This symbol was created to point to a section, e.g. ELF's +. STT_SECTION symbols. *} +.#define BSF_SECTION_SYM 0x100 +. +. {* The symbol used to be a common symbol, but now it is +. allocated. *} +.#define BSF_OLD_COMMON 0x200 +. +. {* The default value for common data. *} +.#define BFD_FORT_COMM_DEFAULT_VALUE 0 +. +. {* In some files the type of a symbol sometimes alters its +. location in an output file - ie in coff a <> symbol +. which is also <> symbol appears where it was +. declared and not at the end of a section. This bit is set +. by the target BFD part to convey this information. *} +. +.#define BSF_NOT_AT_END 0x400 +. +. {* Signal that the symbol is the label of constructor section. *} +.#define BSF_CONSTRUCTOR 0x800 +. +. {* Signal that the symbol is a warning symbol. The name is a +. warning. The name of the next symbol is the one to warn about; +. if a reference is made to a symbol with the same name as the next +. symbol, a warning is issued by the linker. *} +.#define BSF_WARNING 0x1000 +. +. {* Signal that the symbol is indirect. This symbol is an indirect +. pointer to the symbol with the same name as the next symbol. *} +.#define BSF_INDIRECT 0x2000 +. +. {* BSF_FILE marks symbols that contain a file name. This is used +. for ELF STT_FILE symbols. *} +.#define BSF_FILE 0x4000 +. +. {* Symbol is from dynamic linking information. *} +.#define BSF_DYNAMIC 0x8000 +. +. {* The symbol denotes a data object. Used in ELF, and perhaps +. others someday. *} +.#define BSF_OBJECT 0x10000 +. +. flagword flags; +. +. {* A pointer to the section to which this symbol is +. relative. This will always be non NULL, there are special +. sections for undefined and absolute symbols. *} +. struct sec *section; +. +. {* Back end special data. *} +. union +. { +. PTR p; +. bfd_vma i; +. } udata; +. +.} asymbol; +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "aout/stab_gnu.h" + +/* +DOCDD +INODE +symbol handling functions, , typedef asymbol, Symbols +SUBSECTION + Symbol handling functions +*/ + +/* +FUNCTION + bfd_get_symtab_upper_bound + +DESCRIPTION + Return the number of bytes required to store a vector of pointers + to <> for all the symbols in the BFD @var{abfd}, + including a terminal NULL pointer. If there are no symbols in + the BFD, then return 0. If an error occurs, return -1. + +.#define bfd_get_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) + +*/ + +/* +FUNCTION + bfd_is_local_label + +SYNOPSIS + boolean bfd_is_local_label(bfd *abfd, asymbol *sym); + +DESCRIPTION + Return true if the given symbol @var{sym} in the BFD @var{abfd} is + a compiler generated local label, else return false. +.#define bfd_is_local_label(abfd, sym) \ +. BFD_SEND (abfd, _bfd_is_local_label,(abfd, sym)) +*/ + +/* +FUNCTION + bfd_canonicalize_symtab + +DESCRIPTION + Read the symbols from the BFD @var{abfd}, and fills in + the vector @var{location} with pointers to the symbols and + a trailing NULL. + Return the actual number of symbol pointers, not + including the NULL. + + +.#define bfd_canonicalize_symtab(abfd, location) \ +. BFD_SEND (abfd, _bfd_canonicalize_symtab,\ +. (abfd, location)) + +*/ + + +/* +FUNCTION + bfd_set_symtab + +SYNOPSIS + boolean bfd_set_symtab (bfd *abfd, asymbol **location, unsigned int count); + +DESCRIPTION + Arrange that when the output BFD @var{abfd} is closed, + the table @var{location} of @var{count} pointers to symbols + will be written. +*/ + +boolean +bfd_set_symtab (abfd, location, symcount) + bfd *abfd; + asymbol **location; + unsigned int symcount; +{ + if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + bfd_get_outsymbols (abfd) = location; + bfd_get_symcount (abfd) = symcount; + return true; +} + +/* +FUNCTION + bfd_print_symbol_vandf + +SYNOPSIS + void bfd_print_symbol_vandf(PTR file, asymbol *symbol); + +DESCRIPTION + Print the value and flags of the @var{symbol} supplied to the + stream @var{file}. +*/ +void +bfd_print_symbol_vandf (arg, symbol) + PTR arg; + asymbol *symbol; +{ + FILE *file = (FILE *) arg; + flagword type = symbol->flags; + if (symbol->section != (asection *) NULL) + { + fprintf_vma (file, symbol->value + symbol->section->vma); + } + else + { + fprintf_vma (file, symbol->value); + } + + /* This presumes that a symbol can not be both BSF_DEBUGGING and + BSF_DYNAMIC, nor more than one of BSF_FUNCTION, BSF_FILE, and + BSF_OBJECT. */ + fprintf (file, " %c%c%c%c%c%c%c", + ((type & BSF_LOCAL) + ? (type & BSF_GLOBAL) ? '!' : 'l' + : (type & BSF_GLOBAL) ? 'g' : ' '), + (type & BSF_WEAK) ? 'w' : ' ', + (type & BSF_CONSTRUCTOR) ? 'C' : ' ', + (type & BSF_WARNING) ? 'W' : ' ', + (type & BSF_INDIRECT) ? 'I' : ' ', + (type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ', + ((type & BSF_FUNCTION) + ? 'F' + : ((type & BSF_FILE) + ? 'f' + : ((type & BSF_OBJECT) ? 'O' : ' ')))); +} + + +/* +FUNCTION + bfd_make_empty_symbol + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd} + and return a pointer to it. + + This routine is necessary because each back end has private + information surrounding the <>. Building your own + <> and pointing to it will not create the private + information, and will cause problems later on. + +.#define bfd_make_empty_symbol(abfd) \ +. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +*/ + +/* +FUNCTION + bfd_make_debug_symbol + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd}, + to be used as a debugging symbol. Further details of its use have + yet to be worked out. + +.#define bfd_make_debug_symbol(abfd,ptr,size) \ +. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +*/ + +struct section_to_type +{ + CONST char *section; + char type; +}; + +/* Map section names to POSIX/BSD single-character symbol types. + This table is probably incomplete. It is sorted for convenience of + adding entries. Since it is so short, a linear search is used. */ +static CONST struct section_to_type stt[] = +{ + {"*DEBUG*", 'N'}, + {".bss", 'b'}, + {"zerovars", 'b'}, /* MRI .bss */ + {".data", 'd'}, + {"vars", 'd'}, /* MRI .data */ + {".rdata", 'r'}, /* Read only data. */ + {".rodata", 'r'}, /* Read only data. */ + {".sbss", 's'}, /* Small BSS (uninitialized data). */ + {".scommon", 'c'}, /* Small common. */ + {".sdata", 'g'}, /* Small initialized data. */ + {".text", 't'}, + {"code", 't'}, /* MRI .text */ + {0, 0} +}; + +/* Return the single-character symbol type corresponding to + section S, or '?' for an unknown COFF section. + + Check for any leading string which matches, so .text5 returns + 't' as well as .text */ + +static char +coff_section_type (s) + char *s; +{ + CONST struct section_to_type *t; + + for (t = &stt[0]; t->section; t++) + if (!strncmp (s, t->section, strlen (t->section))) + return t->type; + + return '?'; +} + +#ifndef islower +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#endif +#ifndef toupper +#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c)) +#endif + +/* +FUNCTION + bfd_decode_symclass + +DESCRIPTION + Return a character corresponding to the symbol + class of @var{symbol}, or '?' for an unknown class. + +SYNOPSIS + int bfd_decode_symclass(asymbol *symbol); +*/ +int +bfd_decode_symclass (symbol) + asymbol *symbol; +{ + char c; + + if (bfd_is_com_section (symbol->section)) + return 'C'; + if (bfd_is_und_section (symbol->section)) + return 'U'; + if (bfd_is_ind_section (symbol->section)) + return 'I'; + if (symbol->flags & BSF_WEAK) + return 'W'; + if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL))) + return '?'; + + if (bfd_is_abs_section (symbol->section)) + c = 'a'; + else if (symbol->section) + c = coff_section_type (symbol->section->name); + else + return '?'; + if (symbol->flags & BSF_GLOBAL) + c = toupper (c); + return c; + + /* We don't have to handle these cases just yet, but we will soon: + N_SETV: 'v'; + N_SETA: 'l'; + N_SETT: 'x'; + N_SETD: 'z'; + N_SETB: 's'; + N_INDR: 'i'; + */ +} + +/* +FUNCTION + bfd_symbol_info + +DESCRIPTION + Fill in the basic info about symbol that nm needs. + Additional info may be added by the back-ends after + calling this function. + +SYNOPSIS + void bfd_symbol_info(asymbol *symbol, symbol_info *ret); +*/ + +void +bfd_symbol_info (symbol, ret) + asymbol *symbol; + symbol_info *ret; +{ + ret->type = bfd_decode_symclass (symbol); + if (ret->type != 'U') + ret->value = symbol->value + symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; +} + +void +bfd_symbol_is_absolute () +{ + abort (); +} + +/* +FUNCTION + bfd_copy_private_symbol_data + +SYNOPSIS + boolean bfd_copy_private_symbol_data(bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); + +DESCRIPTION + Copy private symbol information from @var{isym} in the BFD + @var{ibfd} to the symbol @var{osym} in the BFD @var{obfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{osec}. + +.#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ +. BFD_SEND (ibfd, _bfd_copy_private_symbol_data, \ +. (ibfd, isymbol, obfd, osymbol)) + +*/ + +/* The generic version of the function which returns mini symbols. + This is used when the backend does not provide a more efficient + version. It just uses BFD asymbol structures as mini symbols. */ + +long +_bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep) + bfd *abfd; + boolean dynamic; + PTR *minisymsp; + unsigned int *sizep; +{ + long storage; + asymbol **syms = NULL; + long symcount; + + if (dynamic) + storage = bfd_get_dynamic_symtab_upper_bound (abfd); + else + storage = bfd_get_symtab_upper_bound (abfd); + if (storage < 0) + goto error_return; + + syms = (asymbol **) bfd_malloc ((size_t) storage); + if (syms == NULL) + goto error_return; + + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); + else + symcount = bfd_canonicalize_symtab (abfd, syms); + if (symcount < 0) + goto error_return; + + *minisymsp = (PTR) syms; + *sizep = sizeof (asymbol *); + return symcount; + + error_return: + if (syms != NULL) + free (syms); + return -1; +} + +/* The generic version of the function which converts a minisymbol to + an asymbol. We don't worry about the sym argument we are passed; + we just return the asymbol the minisymbol points to. */ + +/*ARGSUSED*/ +asymbol * +_bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym) + bfd *abfd; + boolean dynamic; + const PTR minisym; + asymbol *sym; +{ + return *(asymbol **) minisym; +} + +/* Look through stabs debugging information in .stab and .stabstr + sections to find the source file and line closest to a desired + location. This is used by COFF and ELF targets. It sets *pfound + to true if it finds some information. The *pinfo field is used to + pass cached information in and out of this routine; this first time + the routine is called for a BFD, *pinfo should be NULL. The value + placed in *pinfo should be saved with the BFD, and passed back each + time this function is called. */ + +/* A pointer to this structure is stored in *pinfo. */ + +struct stab_find_info +{ + /* The .stab section. */ + asection *stabsec; + /* The .stabstr section. */ + asection *strsec; + /* The contents of the .stab section. */ + bfd_byte *stabs; + /* The contents of the .stabstr section. */ + bfd_byte *strs; + /* An malloc buffer to hold the file name. */ + char *filename; + /* Cached values to restart quickly. */ + bfd_vma cached_offset; + bfd_byte *cached_stab; + bfd_byte *cached_str; + bfd_size_type cached_stroff; +}; + +boolean +_bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, pfound, + pfilename, pfnname, pline, pinfo) + bfd *abfd; + asymbol **symbols; + asection *section; + bfd_vma offset; + boolean *pfound; + const char **pfilename; + const char **pfnname; + unsigned int *pline; + PTR *pinfo; +{ + struct stab_find_info *info; + bfd_size_type stabsize, strsize; + bfd_byte *stab, *stabend, *str; + bfd_size_type stroff; + bfd_vma fnaddr; + char *directory_name, *main_file_name, *current_file_name, *line_file_name; + char *fnname; + bfd_vma low_func_vma, low_line_vma; + + *pfound = false; + *pfilename = bfd_get_filename (abfd); + *pfnname = NULL; + *pline = 0; + + info = (struct stab_find_info *) *pinfo; + if (info != NULL) + { + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. */ + return true; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + } + else + { + long reloc_size, reloc_count; + arelent **reloc_vector; + + info = (struct stab_find_info *) bfd_zalloc (abfd, sizeof *info); + if (info == NULL) + return false; + + /* FIXME: When using the linker --split-by-file or + --split-by-reloc options, it is possible for the .stab and + .stabstr sections to be split. We should handle that. */ + + info->stabsec = bfd_get_section_by_name (abfd, ".stab"); + info->strsec = bfd_get_section_by_name (abfd, ".stabstr"); + + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. Set *pinfo so that we + can return quickly in the info != NULL case above. */ + *pinfo = (PTR) info; + return true; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + + info->stabs = (bfd_byte *) bfd_alloc (abfd, stabsize); + info->strs = (bfd_byte *) bfd_alloc (abfd, strsize); + if (info->stabs == NULL || info->strs == NULL) + return false; + + if (! bfd_get_section_contents (abfd, info->stabsec, info->stabs, 0, + stabsize) + || ! bfd_get_section_contents (abfd, info->strsec, info->strs, 0, + strsize)) + return false; + + /* If this is a relocateable object file, we have to relocate + the entries in .stab. This should always be simple 32 bit + relocations against symbols defined in this object file, so + this should be no big deal. */ + reloc_size = bfd_get_reloc_upper_bound (abfd, info->stabsec); + if (reloc_size < 0) + return false; + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + return false; + reloc_count = bfd_canonicalize_reloc (abfd, info->stabsec, reloc_vector, + symbols); + if (reloc_count < 0) + { + if (reloc_vector != NULL) + free (reloc_vector); + return false; + } + if (reloc_count > 0) + { + arelent **pr; + + for (pr = reloc_vector; *pr != NULL; pr++) + { + arelent *r; + unsigned long val; + asymbol *sym; + + r = *pr; + if (r->howto->rightshift != 0 + || r->howto->size != 2 + || r->howto->bitsize != 32 + || r->howto->pc_relative + || r->howto->bitpos != 0 + || r->howto->dst_mask != 0xffffffff) + { + (*_bfd_error_handler) + ("Unsupported .stab relocation"); + bfd_set_error (bfd_error_invalid_operation); + if (reloc_vector != NULL) + free (reloc_vector); + return false; + } + + val = bfd_get_32 (abfd, info->stabs + r->address); + val &= r->howto->src_mask; + sym = *r->sym_ptr_ptr; + val += sym->value + sym->section->vma + r->addend; + bfd_put_32 (abfd, val, info->stabs + r->address); + } + } + + if (reloc_vector != NULL) + free (reloc_vector); + + *pinfo = (PTR) info; + } + + /* We are passed a section relative offset. The offsets in the + stabs information are absolute. */ + offset += bfd_get_section_vma (abfd, section); + + /* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. + + The stabs symbols are divided into compilation units. For the + first entry in each unit, the type of 0, the value is the length + of the string table for this unit, and the desc field is the + number of stabs symbols for this unit. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + + /* It would be nice if we could skip ahead to the stabs symbols for + the next compilation unit to quickly scan through the compilation + units. Unfortunately, since each line number gets a separate + stabs entry, it is entirely plausible that a large source file + will overflow the 16 bit count of stabs entries. */ + fnaddr = 0; + directory_name = NULL; + main_file_name = NULL; + current_file_name = NULL; + line_file_name = NULL; + fnname = NULL; + low_func_vma = 0; + low_line_vma = 0; + + stabend = info->stabs + stabsize; + + if (info->cached_stab == NULL || offset < info->cached_offset) + { + stab = info->stabs; + str = info->strs; + stroff = 0; + } + else + { + stab = info->cached_stab; + str = info->cached_str; + stroff = info->cached_stroff; + } + + info->cached_offset = offset; + + for (; stab < stabend; stab += STABSIZE) + { + boolean done; + bfd_vma val; + char *name; + + done = false; + + switch (stab[TYPEOFF]) + { + case 0: + /* This is the first entry in a compilation unit. */ + if ((bfd_size_type) ((info->strs + strsize) - str) < stroff) + { + done = true; + break; + } + str += stroff; + stroff = bfd_get_32 (abfd, stab + VALOFF); + break; + + case N_SO: + /* The main file name. */ + + val = bfd_get_32 (abfd, stab + VALOFF); + if (val > offset) + { + done = true; + break; + } + + name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + + /* An empty string indicates the end of the compilation + unit. */ + if (*name == '\0') + { + /* If there are functions in different sections, they + may have addresses larger than val, but we don't want + to forget the file name. When there are functions in + different cases, there is supposed to be an N_FUN at + the end of the function indicating where it ends. */ + if (low_func_vma < val || fnname == NULL) + main_file_name = NULL; + break; + } + + /* We know that we have to get to at least this point in the + stabs entries for this offset. */ + info->cached_stab = stab; + info->cached_str = str; + info->cached_stroff = stroff; + + current_file_name = name; + + /* Look ahead to the next symbol. Two consecutive N_SO + symbols are a directory and a file name. */ + if (stab + STABSIZE >= stabend + || *(stab + STABSIZE + TYPEOFF) != N_SO) + directory_name = NULL; + else + { + stab += STABSIZE; + directory_name = current_file_name; + current_file_name = ((char *) str + + bfd_get_32 (abfd, stab + STRDXOFF)); + } + + main_file_name = current_file_name; + + break; + + case N_SOL: + /* The name of an include file. */ + current_file_name = ((char *) str + + bfd_get_32 (abfd, stab + STRDXOFF)); + break; + + case N_SLINE: + case N_DSLINE: + case N_BSLINE: + /* A line number. The value is relative to the start of the + current function. */ + val = fnaddr + bfd_get_32 (abfd, stab + VALOFF); + if (val >= low_line_vma && val <= offset) + { + *pline = bfd_get_16 (abfd, stab + DESCOFF); + low_line_vma = val; + line_file_name = current_file_name; + } + break; + + case N_FUN: + /* A function name. */ + val = bfd_get_32 (abfd, stab + VALOFF); + name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + + /* An empty string here indicates the end of a function, and + the value is relative to fnaddr. */ + + if (*name == '\0') + { + val += fnaddr; + if (val >= low_func_vma && val < offset) + fnname = NULL; + } + else + { + if (val >= low_func_vma && val <= offset) + { + fnname = name; + low_func_vma = val; + } + + fnaddr = val; + } + + break; + } + + if (done) + break; + } + + if (main_file_name == NULL) + { + /* No information found. */ + return true; + } + + *pfound = true; + + if (*pline != 0) + main_file_name = line_file_name; + + if (main_file_name != NULL) + { + if (main_file_name[0] == '/' || directory_name == NULL) + *pfilename = main_file_name; + else + { + size_t dirlen; + + dirlen = strlen (directory_name); + if (info->filename == NULL + || strncmp (info->filename, directory_name, dirlen) != 0 + || strcmp (info->filename + dirlen, main_file_name) != 0) + { + if (info->filename != NULL) + free (info->filename); + info->filename = (char *) bfd_malloc (dirlen + + strlen (main_file_name) + + 1); + if (info->filename == NULL) + return false; + strcpy (info->filename, directory_name); + strcpy (info->filename + dirlen, main_file_name); + } + + *pfilename = info->filename; + } + } + + if (fnname != NULL) + { + char *s; + + /* This will typically be something like main:F(0,1), so we want + to clobber the colon. It's OK to change the name, since the + string is in our own local storage anyhow. */ + + s = strchr (fnname, ':'); + if (s != NULL) + *s = '\0'; + + *pfnname = fnname; + } + + return true; +} diff --git a/contrib/gdb/bfd/sysdep.h b/contrib/gdb/bfd/sysdep.h new file mode 100644 index 000000000000..dd8146a961a8 --- /dev/null +++ b/contrib/gdb/bfd/sysdep.h @@ -0,0 +1,114 @@ +/* sysdep.h -- handle host dependencies for the BFD library + Copyright 1995 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BFD_SYSDEP_H +#define BFD_SYSDEP_H + +#include "ansidecl.h" + +#include "config.h" + +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#include +#include + +#include +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#else +extern char *strchr (); +extern char *strrchr (); +extern char *strstr (); +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef USE_BINARY_FOPEN +#include "fopen-bin.h" +#else +#include "fopen-same.h" +#endif + +#ifdef HAVE_FCNTL_H +#include +#else +#ifdef HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_WRONLY +#define O_WRONLY 1 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +#endif + +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif + +#endif /* ! defined (BFD_SYSDEP_H) */ diff --git a/contrib/gdb/bfd/targets.c b/contrib/gdb/bfd/targets.c new file mode 100644 index 000000000000..e1e6468a18ee --- /dev/null +++ b/contrib/gdb/bfd/targets.c @@ -0,0 +1,886 @@ +/* Generic target-file-type support for the BFD library. + Copyright 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Written by Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Targets + +DESCRIPTION + Each port of BFD to a different machine requries the creation + of a target back end. All the back end provides to the root + part of BFD is a structure containing pointers to functions + which perform certain low level operations on files. BFD + translates the applications's requests through a pointer into + calls to the back end routines. + + When a file is opened with <>, its format and + target are unknown. BFD uses various mechanisms to determine + how to interpret the file. The operations performed are: + + o Create a BFD by calling the internal routine + <<_bfd_new_bfd>>, then call <> with the + target string supplied to <> and the new BFD pointer. + + o If a null target string was provided to <>, + look up the environment variable <> and use + that as the target string. + + o If the target string is still <>, or the target string is + <>, then use the first item in the target vector + as the target type, and set <> in the BFD to + cause <> to loop through all the targets. + @xref{bfd_target}. @xref{Formats}. + + o Otherwise, inspect the elements in the target vector + one by one, until a match on target name is found. When found, + use it. + + o Otherwise return the error <> to + <>. + + o <> attempts to open the file using + <>, and returns the BFD. + + Once the BFD has been opened and the target selected, the file + format may be determined. This is done by calling + <> on the BFD with a suggested format. + If <> has been set, each possible target + type is tried to see if it recognizes the specified format. + <> returns <> when the caller guesses right. +@menu +@* bfd_target:: +@end menu +*/ + + +/* + +INODE + bfd_target, , Targets, Targets +DOCDD +SUBSECTION + bfd_target + +DESCRIPTION + This structure contains everything that BFD knows about a + target. It includes things like its byte order, name, and which + routines to call to do various operations. + + Every BFD points to a target structure with its <> + member. + + The macros below are used to dispatch to functions through the + <> vector. They are used in a number of macros further + down in @file{bfd.h}, and are also used when calling various + routines by hand inside the BFD implementation. The @var{arglist} + argument must be parenthesized; it contains all the arguments + to the called function. + + They make the documentation (more) unpleasant to read, so if + someone wants to fix this and not break the above, please do. + +.#define BFD_SEND(bfd, message, arglist) \ +. ((*((bfd)->xvec->message)) arglist) +. +.#ifdef DEBUG_BFD_SEND +.#undef BFD_SEND +.#define BFD_SEND(bfd, message, arglist) \ +. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ +. ((*((bfd)->xvec->message)) arglist) : \ +. (bfd_assert (__FILE__,__LINE__), NULL)) +.#endif + + For operations which index on the BFD format: + +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) +. +.#ifdef DEBUG_BFD_SEND +.#undef BFD_SEND_FMT +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ +. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) : \ +. (bfd_assert (__FILE__,__LINE__), NULL)) +.#endif + + This is the structure which defines the type of BFD this is. The + <> member of the struct <> itself points here. Each + module that implements access to a different target under BFD, + defines one of these. + + + FIXME, these names should be rationalised with the names of + the entry points which call them. Too bad we can't have one + macro to define them both! + +.enum bfd_flavour { +. bfd_target_unknown_flavour, +. bfd_target_aout_flavour, +. bfd_target_coff_flavour, +. bfd_target_ecoff_flavour, +. bfd_target_elf_flavour, +. bfd_target_ieee_flavour, +. bfd_target_nlm_flavour, +. bfd_target_oasys_flavour, +. bfd_target_tekhex_flavour, +. bfd_target_srec_flavour, +. bfd_target_ihex_flavour, +. bfd_target_som_flavour, +. bfd_target_os9k_flavour, +. bfd_target_versados_flavour, +. bfd_target_msdos_flavour +.}; +. +.enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; +. +.{* Forward declaration. *} +.typedef struct bfd_link_info _bfd_link_info; +. +.typedef struct bfd_target +.{ + +Identifies the kind of target, e.g., SunOS4, Ultrix, etc. + +. char *name; + +The "flavour" of a back end is a general indication about the contents +of a file. + +. enum bfd_flavour flavour; + +The order of bytes within the data area of a file. + +. enum bfd_endian byteorder; + +The order of bytes within the header parts of a file. + +. enum bfd_endian header_byteorder; + +A mask of all the flags which an executable may have set - +from the set <>, <>, ...<>. + +. flagword object_flags; + +A mask of all the flags which a section may have set - from +the set <>, <>, ...<>. + +. flagword section_flags; + +The character normally found at the front of a symbol +(if any), perhaps `_'. + +. char symbol_leading_char; + +The pad character for file names within an archive header. + +. char ar_pad_char; + +The maximum number of characters in an archive header. + +. unsigned short ar_max_namelen; + +Entries for byte swapping for data. These are different from the other +entry points, since they don't take a BFD asthe first argument. +Certain other handlers could do the same. + +. bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); +. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); +. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); +. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Byte swapping for the headers + +. bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Format dependent routines: these are vectors of entry points +within the target vector structure, one for each format to check. + +Check the format of a file being read. Return a <> or zero. + +. const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + +Set the format of a file being written. + +. boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + +Write cached information into a file being written, at <>. + +. boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + +The general target vector. + +. +. {* Generic entry points. *} +.#define BFD_JUMP_TABLE_GENERIC(NAME)\ +.CAT(NAME,_close_and_cleanup),\ +.CAT(NAME,_bfd_free_cached_info),\ +.CAT(NAME,_new_section_hook),\ +.CAT(NAME,_get_section_contents),\ +.CAT(NAME,_get_section_contents_in_window) +. +. {* Called when the BFD is being closed to do any necessary cleanup. *} +. boolean (*_close_and_cleanup) PARAMS ((bfd *)); +. {* Ask the BFD to free all cached information. *} +. boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); +. {* Called when a new section is created. *} +. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); +. {* Read the contents of a section. *} +. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. boolean (*_bfd_get_section_contents_in_window) +. PARAMS ((bfd *, sec_ptr, bfd_window *, +. file_ptr, bfd_size_type)); +. +. {* Entry points to copy private data. *} +.#define BFD_JUMP_TABLE_COPY(NAME)\ +.CAT(NAME,_bfd_copy_private_bfd_data),\ +.CAT(NAME,_bfd_merge_private_bfd_data),\ +.CAT(NAME,_bfd_copy_private_section_data),\ +.CAT(NAME,_bfd_copy_private_symbol_data),\ +.CAT(NAME,_bfd_set_private_flags),\ +.CAT(NAME,_bfd_print_private_bfd_data)\ +. {* Called to copy BFD general private data from one object file +. to another. *} +. boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); +. {* Called to merge BFD general private data from one object file +. to a common output file when linking. *} +. boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); +. {* Called to copy BFD private section data from one object file +. to another. *} +. boolean (*_bfd_copy_private_section_data) PARAMS ((bfd *, sec_ptr, +. bfd *, sec_ptr)); +. {* Called to copy BFD private symbol data from one symbol +. to another. *} +. boolean (*_bfd_copy_private_symbol_data) PARAMS ((bfd *, asymbol *, +. bfd *, asymbol *)); +. {* Called to set private backend flags *} +. boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); +. +. {* Called to print private BFD data *} +. boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); +. +. {* Core file entry points. *} +.#define BFD_JUMP_TABLE_CORE(NAME)\ +.CAT(NAME,_core_file_failing_command),\ +.CAT(NAME,_core_file_failing_signal),\ +.CAT(NAME,_core_file_matches_executable_p) +. char * (*_core_file_failing_command) PARAMS ((bfd *)); +. int (*_core_file_failing_signal) PARAMS ((bfd *)); +. boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); +. +. {* Archive entry points. *} +.#define BFD_JUMP_TABLE_ARCHIVE(NAME)\ +.CAT(NAME,_slurp_armap),\ +.CAT(NAME,_slurp_extended_name_table),\ +.CAT(NAME,_construct_extended_name_table),\ +.CAT(NAME,_truncate_arname),\ +.CAT(NAME,_write_armap),\ +.CAT(NAME,_read_ar_hdr),\ +.CAT(NAME,_openr_next_archived_file),\ +.CAT(NAME,_get_elt_at_index),\ +.CAT(NAME,_generic_stat_arch_elt),\ +.CAT(NAME,_update_armap_timestamp) +. boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); +. boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); +. boolean (*_bfd_construct_extended_name_table) +. PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +. void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); +. boolean (*write_armap) PARAMS ((bfd *arch, +. unsigned int elength, +. struct orl *map, +. unsigned int orl_count, +. int stridx)); +. PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); +. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +.#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) +. bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); +. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); +. boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); +. +. {* Entry points used for symbols. *} +.#define BFD_JUMP_TABLE_SYMBOLS(NAME)\ +.CAT(NAME,_get_symtab_upper_bound),\ +.CAT(NAME,_get_symtab),\ +.CAT(NAME,_make_empty_symbol),\ +.CAT(NAME,_print_symbol),\ +.CAT(NAME,_get_symbol_info),\ +.CAT(NAME,_bfd_is_local_label),\ +.CAT(NAME,_get_lineno),\ +.CAT(NAME,_find_nearest_line),\ +.CAT(NAME,_bfd_make_debug_symbol),\ +.CAT(NAME,_read_minisymbols),\ +.CAT(NAME,_minisymbol_to_symbol) +. long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); +. long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, +. struct symbol_cache_entry **)); +. struct symbol_cache_entry * +. (*_bfd_make_empty_symbol) PARAMS ((bfd *)); +. void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, +. struct symbol_cache_entry *, +. bfd_print_symbol_type)); +.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) +. void (*_bfd_get_symbol_info) PARAMS ((bfd *, +. struct symbol_cache_entry *, +. symbol_info *)); +.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) +. boolean (*_bfd_is_local_label) PARAMS ((bfd *, asymbol *)); +. +. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); +. boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, +. struct sec *section, struct symbol_cache_entry **symbols, +. bfd_vma offset, CONST char **file, CONST char **func, +. unsigned int *line)); +. {* Back-door to allow format-aware applications to create debug symbols +. while using BFD for everything else. Currently used by the assembler +. when creating COFF files. *} +. asymbol * (*_bfd_make_debug_symbol) PARAMS (( +. bfd *abfd, +. void *ptr, +. unsigned long size)); +.#define bfd_read_minisymbols(b, d, m, s) \ +. BFD_SEND (b, _read_minisymbols, (b, d, m, s)) +. long (*_read_minisymbols) PARAMS ((bfd *, boolean, PTR *, +. unsigned int *)); +.#define bfd_minisymbol_to_symbol(b, d, m, f) \ +. BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) +. asymbol *(*_minisymbol_to_symbol) PARAMS ((bfd *, boolean, const PTR, +. asymbol *)); +. +. {* Routines for relocs. *} +.#define BFD_JUMP_TABLE_RELOCS(NAME)\ +.CAT(NAME,_get_reloc_upper_bound),\ +.CAT(NAME,_canonicalize_reloc),\ +.CAT(NAME,_bfd_reloc_type_lookup) +. long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); +. long (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, +. struct symbol_cache_entry **)); +. {* See documentation on reloc types. *} +. reloc_howto_type * +. (*reloc_type_lookup) PARAMS ((bfd *abfd, +. bfd_reloc_code_real_type code)); +. +. {* Routines used when writing an object file. *} +.#define BFD_JUMP_TABLE_WRITE(NAME)\ +.CAT(NAME,_set_arch_mach),\ +.CAT(NAME,_set_section_contents) +. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, +. unsigned long)); +. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. +. {* Routines used by the linker. *} +.#define BFD_JUMP_TABLE_LINK(NAME)\ +.CAT(NAME,_sizeof_headers),\ +.CAT(NAME,_bfd_get_relocated_section_contents),\ +.CAT(NAME,_bfd_relax_section),\ +.CAT(NAME,_bfd_link_hash_table_create),\ +.CAT(NAME,_bfd_link_add_symbols),\ +.CAT(NAME,_bfd_final_link),\ +.CAT(NAME,_bfd_link_split_section) +. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); +. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, +. struct bfd_link_info *, struct bfd_link_order *, +. bfd_byte *data, boolean relocateable, +. struct symbol_cache_entry **)); +. +. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, +. struct bfd_link_info *, boolean *again)); +. +. {* Create a hash table for the linker. Different backends store +. different information in this table. *} +. struct bfd_link_hash_table *(*_bfd_link_hash_table_create) PARAMS ((bfd *)); +. +. {* Add symbols from this object file into the hash table. *} +. boolean (*_bfd_link_add_symbols) PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Do a link based on the link_order structures attached to each +. section of the BFD. *} +. boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Should this section be split up into smaller pieces during linking. *} +. boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); +. +. {* Routines to handle dynamic symbols and relocs. *} +.#define BFD_JUMP_TABLE_DYNAMIC(NAME)\ +.CAT(NAME,_get_dynamic_symtab_upper_bound),\ +.CAT(NAME,_canonicalize_dynamic_symtab),\ +.CAT(NAME,_get_dynamic_reloc_upper_bound),\ +.CAT(NAME,_canonicalize_dynamic_reloc) +. {* Get the amount of memory required to hold the dynamic symbols. *} +. long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); +. {* Read in the dynamic symbols. *} +. long (*_bfd_canonicalize_dynamic_symtab) +. PARAMS ((bfd *, struct symbol_cache_entry **)); +. {* Get the amount of memory required to hold the dynamic relocs. *} +. long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); +. {* Read in the dynamic relocs. *} +. long (*_bfd_canonicalize_dynamic_reloc) +. PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); +. + +Data for use by back-end routines, which isn't generic enough to belong +in this structure. + +. PTR backend_data; +.} bfd_target; + +*/ + +/* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ +extern const bfd_target a29kcoff_big_vec; +extern const bfd_target a_out_adobe_vec; +extern const bfd_target aout_arm_big_vec; +extern const bfd_target aout_arm_little_vec; +extern const bfd_target aout_mips_big_vec; +extern const bfd_target aout_mips_little_vec; +extern const bfd_target aout0_big_vec; +extern const bfd_target apollocoff_vec; +extern const bfd_target armcoff_little_vec; +extern const bfd_target armcoff_big_vec; +extern const bfd_target armpe_little_vec; +extern const bfd_target armpe_big_vec; +extern const bfd_target armpei_little_vec; +extern const bfd_target armpei_big_vec; +extern const bfd_target b_out_vec_big_host; +extern const bfd_target b_out_vec_little_host; +extern const bfd_target bfd_elf32_big_generic_vec; +extern const bfd_target bfd_elf32_bigmips_vec; +extern const bfd_target bfd_elf32_hppa_vec; +extern const bfd_target bfd_elf32_i386_vec; +extern const bfd_target bfd_elf32_i860_vec; +extern const bfd_target bfd_elf32_little_generic_vec; +extern const bfd_target bfd_elf32_littlemips_vec; +extern const bfd_target bfd_elf32_m68k_vec; +extern const bfd_target bfd_elf32_m88k_vec; +extern const bfd_target bfd_elf32_powerpc_vec; +extern const bfd_target bfd_elf32_powerpcle_vec; +extern const bfd_target bfd_elf32_sparc_vec; +extern const bfd_target bfd_elf64_big_generic_vec; +extern const bfd_target bfd_elf64_little_generic_vec; +extern const bfd_target bfd_elf64_sparc_vec; +extern const bfd_target demo_64_vec; +extern const bfd_target ecoff_big_vec; +extern const bfd_target ecoff_little_vec; +extern const bfd_target ecoffalpha_little_vec; +extern const bfd_target h8300coff_vec; +extern const bfd_target h8500coff_vec; +extern const bfd_target host_aout_vec; +extern const bfd_target hp300bsd_vec; +extern const bfd_target hp300hpux_vec; +extern const bfd_target som_vec; +extern const bfd_target i386aout_vec; +extern const bfd_target i386bsd_vec; +extern const bfd_target i386dynix_vec; +extern const bfd_target i386freebsd_vec; +extern const bfd_target i386os9k_vec; +extern const bfd_target i386coff_vec; +extern const bfd_target bfd_powerpc_pe_vec; +extern const bfd_target bfd_powerpcle_pe_vec; +extern const bfd_target bfd_powerpc_pei_vec; +extern const bfd_target bfd_powerpcle_pei_vec; +extern const bfd_target i386pe_vec; +extern const bfd_target i386pei_vec; +extern const bfd_target go32coff_vec; +extern const bfd_target i386linux_vec; +extern const bfd_target i386lynx_aout_vec; +extern const bfd_target i386lynx_coff_vec; +extern const bfd_target i386mach3_vec; +extern const bfd_target i386msdos_vec; +extern const bfd_target i386netbsd_vec; +extern const bfd_target i860coff_vec; +extern const bfd_target icoff_big_vec; +extern const bfd_target icoff_little_vec; +extern const bfd_target ieee_vec; +extern const bfd_target m68kaux_coff_vec; +extern const bfd_target m68kcoff_vec; +extern const bfd_target m68kcoffun_vec; +extern const bfd_target m68klinux_vec; +extern const bfd_target m68klynx_aout_vec; +extern const bfd_target m68klynx_coff_vec; +extern const bfd_target m68knetbsd_vec; +extern const bfd_target m68k4knetbsd_vec; +extern const bfd_target m88kbcs_vec; +extern const bfd_target m88kmach3_vec; +extern const bfd_target newsos3_vec; +extern const bfd_target nlm32_i386_vec; +extern const bfd_target nlm32_sparc_vec; +extern const bfd_target nlm32_alpha_vec; +extern const bfd_target nlm32_powerpc_vec; +extern const bfd_target pc532netbsd_vec; +extern const bfd_target oasys_vec; +extern const bfd_target pc532machaout_vec; +extern const bfd_target riscix_vec; +extern const bfd_target pmac_xcoff_vec; +extern const bfd_target rs6000coff_vec; +extern const bfd_target shcoff_vec; +extern const bfd_target shlcoff_vec; +extern const bfd_target sparclynx_aout_vec; +extern const bfd_target sparclynx_coff_vec; +extern const bfd_target sparcnetbsd_vec; +extern const bfd_target sparccoff_vec; +extern const bfd_target sunos_big_vec; +extern const bfd_target tekhex_vec; +extern const bfd_target versados_vec; +extern const bfd_target we32kcoff_vec; +extern const bfd_target w65_vec; +extern const bfd_target z8kcoff_vec; + +/* srec is always included. */ +extern const bfd_target srec_vec; +extern const bfd_target symbolsrec_vec; + +/* binary is always included. */ +extern const bfd_target binary_vec; + +/* ihex is always included. */ +extern const bfd_target ihex_vec; + +/* All of the xvecs for core files. */ +extern const bfd_target aix386_core_vec; +extern const bfd_target cisco_core_vec; +extern const bfd_target hpux_core_vec; +extern const bfd_target hppabsd_core_vec; +extern const bfd_target irix_core_vec; +extern const bfd_target osf_core_vec; +extern const bfd_target sco_core_vec; +extern const bfd_target trad_core_vec; +extern const bfd_target ptrace_core_vec; + +const bfd_target * const bfd_target_vector[] = { + +#ifdef SELECT_VECS + + SELECT_VECS, + +#else /* not SELECT_VECS */ + +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + /* This list is alphabetized to make it easy to compare + with other vector lists -- the decls above and + the case statement in configure.in. + Vectors that don't compile on all systems, or aren't finished, + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a29kcoff_big_vec, + &a_out_adobe_vec, +#if 0 /* No one seems to use this. */ + &aout_mips_big_vec, +#endif + &aout_mips_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, + + /* This, and other vectors, may not be used in any *.mt configuration. + But that does not mean they are unnecessary. If configured with + --enable-targets=all, objdump or gdb should be able to examine + the file even if we don't recognize the machine type. */ + &bfd_elf32_big_generic_vec, + &bfd_elf32_bigmips_vec, + &bfd_elf32_hppa_vec, + &bfd_elf32_i386_vec, + &bfd_elf32_i860_vec, + &bfd_elf32_little_generic_vec, + &bfd_elf32_littlemips_vec, + &bfd_elf32_m68k_vec, + &bfd_elf32_m88k_vec, + &bfd_elf32_sparc_vec, + &bfd_elf32_powerpc_vec, +#ifdef BFD64 /* No one seems to use this. */ + &bfd_elf64_big_generic_vec, + &bfd_elf64_little_generic_vec, +#endif +#if 0 + &bfd_elf64_sparc_vec, +#endif + /* We don't include cisco_core_vec. Although it has a magic number, + the magic number isn't at the beginning of the file, and thus + might spuriously match other kinds of files. */ +#ifdef BFD64 + &demo_64_vec, /* Only compiled if host has long-long support */ +#endif + &ecoff_big_vec, + &ecoff_little_vec, +#if 0 + &ecoffalpha_little_vec, +#endif + &h8300coff_vec, + &h8500coff_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &host_aout_vec, +#endif +#if 0 /* Clashes with sunos_big_vec magic no. */ + &hp300bsd_vec, +#endif + &hp300hpux_vec, +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) + &som_vec, +#endif + &i386aout_vec, + &i386bsd_vec, + &i386coff_vec, + &i386freebsd_vec, + &i860coff_vec, + &bfd_powerpc_pe_vec, + &bfd_powerpcle_pe_vec, + &bfd_powerpc_pei_vec, + &bfd_powerpcle_pei_vec, + &go32coff_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &i386linux_vec, +#endif + &i386lynx_aout_vec, + &i386lynx_coff_vec, +#if 0 + /* No distinguishing features for Mach 3 executables. */ + &i386mach3_vec, +#endif + &i386msdos_vec, + &i386netbsd_vec, + &i386os9k_vec, + &i386pe_vec, + &i386pei_vec, + &armcoff_little_vec, + &armcoff_big_vec, + &armpe_little_vec, + &armpe_big_vec, + &armpei_little_vec, + &armpei_big_vec, + &icoff_big_vec, + &icoff_little_vec, + &ieee_vec, + &m68kcoff_vec, + &m68kcoffun_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &m68klinux_vec, +#endif + &m68klynx_aout_vec, + &m68klynx_coff_vec, + &m68knetbsd_vec, + &m88kbcs_vec, + &m88kmach3_vec, + &newsos3_vec, + &nlm32_i386_vec, + &nlm32_sparc_vec, +#ifdef BFD64 + &nlm32_alpha_vec, +#endif + &pc532netbsd_vec, +#if 0 + /* We have no oasys tools anymore, so we can't test any of this + anymore. If you want to test the stuff yourself, go ahead... + steve@cygnus.com + Worse, since there is no magic number for archives, there + can be annoying target mis-matches. */ + &oasys_vec, +#endif + &pc532machaout_vec, +#if 0 + /* We have no way of distinguishing these from other a.out variants */ + &aout_arm_big_vec, + &aout_arm_little_vec, + &riscix_vec, +#endif +#if 0 + /* This has the same magic number as RS/6000. */ + &pmac_xcoff_vec, +#endif + &rs6000coff_vec, + &shcoff_vec, + &shlcoff_vec, + &sparclynx_aout_vec, + &sparclynx_coff_vec, + &sparcnetbsd_vec, + &sunos_big_vec, + &aout0_big_vec, + &tekhex_vec, + &we32kcoff_vec, + &versados_vec, + &z8kcoff_vec, + +#endif /* not SELECT_VECS */ + +/* Always support S-records, for convenience. */ + &srec_vec, + &symbolsrec_vec, +/* And tekhex */ + &tekhex_vec, +/* Likewise for binary output. */ + &binary_vec, +/* Likewise for ihex. */ + &ihex_vec, + +/* Add any required traditional-core-file-handler. */ + +#ifdef AIX386_CORE + &aix386_core_vec, +#endif +#ifdef HPUX_CORE + &hpux_core_vec, +#endif +#ifdef HPPABSD_CORE + &hppabsd_core_vec, +#endif +#ifdef IRIX_CORE + &irix_core_vec, +#endif +#ifdef OSF_CORE + &osf_core_vec, +#endif +#ifdef TRAD_CORE + &trad_core_vec, +#endif + +#ifdef PTRACE_CORE + &ptrace_core_vec, +#endif + + NULL /* end of list marker */ +}; + +/* bfd_default_vector[0] contains either the address of the default vector, + if there is one, or zero if there isn't. */ + +const bfd_target * const bfd_default_vector[] = { +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + NULL +}; + +/* When there is an ambiguous match, bfd_check_format_matches puts the + names of the matching targets in an array. This variable is the maximum + number of entries that the array could possibly need. */ +const size_t _bfd_target_vector_entries = sizeof(bfd_target_vector)/sizeof(*bfd_target_vector); + +/* +FUNCTION + bfd_find_target + +SYNOPSIS + const bfd_target *bfd_find_target(CONST char *target_name, bfd *abfd); + +DESCRIPTION + Return a pointer to the transfer vector for the object target + named @var{target_name}. If @var{target_name} is <>, choose the + one in the environment variable <>; if that is null or not + defined, then choose the first entry in the target list. + Passing in the string "default" or setting the environment + variable to "default" will cause the first entry in the target + list to be returned, and "target_defaulted" will be set in the + BFD. This causes <> to loop over all the + targets to find the one that matches the file being read. +*/ + +const bfd_target * +bfd_find_target (target_name, abfd) + CONST char *target_name; + bfd *abfd; +{ + const bfd_target * const *target; + extern char *getenv (); + CONST char *targname = (target_name ? target_name : + (CONST char *) getenv ("GNUTARGET")); + + /* This is safe; the vector cannot be null */ + if (targname == NULL || !strcmp (targname, "default")) { + abfd->target_defaulted = true; + return abfd->xvec = bfd_target_vector[0]; + } + + abfd->target_defaulted = false; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) { + if (!strcmp (targname, (*target)->name)) + return abfd->xvec = *target; + } + + bfd_set_error (bfd_error_invalid_target); + return NULL; +} + + +/* +FUNCTION + bfd_target_list + +SYNOPSIS + const char **bfd_target_list(void); + +DESCRIPTION + Return a freshly malloced NULL-terminated + vector of the names of all the valid BFD targets. Do not + modify the names. + +*/ + +const char ** +bfd_target_list () +{ + int vec_length= 0; +#if defined (HOST_HPPAHPUX) && ! defined (__STDC__) + /* The native compiler on the HP9000/700 has a bug which causes it + to loop endlessly when compiling this file. This avoids it. */ + volatile +#endif + const bfd_target * const *target; + CONST char **name_list, **name_ptr; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) + vec_length++; + + name_ptr = name_list = (CONST char **) + bfd_zmalloc ((vec_length + 1) * sizeof (char **)); + + if (name_list == NULL) + return NULL; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) + *(name_ptr++) = (*target)->name; + + return name_list; +} diff --git a/contrib/gdb/bfd/tekhex.c b/contrib/gdb/bfd/tekhex.c new file mode 100644 index 000000000000..bf7957e673ab --- /dev/null +++ b/contrib/gdb/bfd/tekhex.c @@ -0,0 +1,1031 @@ +/* BFD backend for Extended Tektronix Hex Format objects. + Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + + Written by Steve Chamberlain of Cygnus Support . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SUBSECTION + Tektronix Hex Format handling + +DESCRIPTION + + Tek Hex records can hold symbols and data, but not + relocations. Their main application is communication with + devices like PROM programmers and ICE equipment. + + It seems that the sections are descibed as being really big, + the example I have says that the text section is 0..ffffffff. + BFD would barf with this, many apps would try to alloc 4GB to + read in the file. + + Tex Hex may contain many sections, but the data which comes in + has no tag saying which section it belongs to, so we create + one section for each block of data, called "blknnnn" which we + stick all the data into. + + TekHex may come out of order and there is no header, so an + initial scan is required to discover the minimum and maximum + addresses used to create the vma and size of the sections we + create. + We read in the data into pages of CHUNK_MASK+1 size and read + them out from that whenever we need to. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + + A TekHex record looks like: +EXAMPLE + % + +DESCRIPTION + Where + o length + is the number of bytes in the record not including the % sign. + o type + is one of: + 3) symbol record + 6) data record + 8) termination record + + +The data can come out of order, and may be discontigous. This is a +serial protocol, so big files are unlikely, so we keep a list of 8k chunks +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" + +typedef struct + { + bfd_vma low; + bfd_vma high; + } addr_range_type; + +typedef struct tekhex_symbol_struct + { + + asymbol symbol; + struct tekhex_symbol_struct *prev; + + } tekhex_symbol_type; + +static const char digs[] = "0123456789ABCDEF"; + +static char sum_block[256]; + +#define NOT_HEX 20 +#define NIBBLE(x) hex_value(x) +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d,x) \ +(d)[1] = digs[(x) & 0xf]; \ +(d)[0] = digs[((x)>>4)&0xf]; +#define ISHEX(x) hex_p(x) + +/* +Here's an example +%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 +%1B3709T_SEGMENT1108FFFFFFFF +%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 +%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 +%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 +%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 +%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 +%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 +%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 +%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 +%2734D9T_SEGMENT8Bvoid$t15$151035_main10 +%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 +%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 +%07 8 10 10 + +explanation: +%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 + ^ ^^ ^ ^-data + | || +------ 4 char integer 0x8000 + | |+-------- checksum + | +--------- type 6 (data record) + +----------- length 3a chars + <---------------------- 3a (58 chars) -------------------> + +%1B3709T_SEGMENT1108FFFFFFFF + ^ ^^ ^- 8 character integer 0xffffffff + | |+- 1 character integer 0 + | +-- type 1 symbol (section definition) + +------------ 9 char symbol T_SEGMENT + +%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 +%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 +%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 +%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 +%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 +%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 +%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 +%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 +%2734D9T_SEGMENT8Bvoid$t15$151035_main10 +%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 +%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 +%0781010 + +Turns into +sac@thepub$ ./objdump -dx -m m68k f + +f: file format tekhex +-----x--- 9/55728 -134219416 Sep 29 15:13 1995 f +architecture: UNKNOWN!, flags 0x00000010: +HAS_SYMS +start address 0x00000000 +SECTION 0 [D00000000] : size 00020000 vma 00000000 align 2**0 + ALLOC, LOAD +SECTION 1 [D00008000] : size 00002001 vma 00008000 align 2**0 + +SECTION 2 [T_SEGMENT] : size ffffffff vma 00000000 align 2**0 + +SYMBOL TABLE: +00000000 g T_SEGMENT gcc_compiled$ +00000000 g T_SEGMENT hello$c +00000000 g T_SEGMENT int$t1$r1$$21474 +00000000 g T_SEGMENT char$t2$r2$0$127 +00000000 g T_SEGMENT long$int$t3$r1$$ +00000000 g T_SEGMENT unsigned$int$t4$ +00000000 g T_SEGMENT long$unsigned$in +00000000 g T_SEGMENT short$int$t6$r1$ +00000000 g T_SEGMENT long$long$int$t7 +00000000 g T_SEGMENT short$unsigned$i +00000000 g T_SEGMENT long$long$unsign +00000000 g T_SEGMENT signed$char$t10$ +00000000 g T_SEGMENT unsigned$char$t1 +00000000 g T_SEGMENT float$t12$r1$4$0 +00000000 g T_SEGMENT double$t13$r1$8$ +00000000 g T_SEGMENT long$double$t14$ +00000000 g T_SEGMENT void$t15$15 +00000000 g T_SEGMENT _main +00000000 g T_SEGMENT $ +00000000 g T_SEGMENT $ +00000000 g T_SEGMENT $ +00000010 g T_SEGMENT $ +00000000 g T_SEGMENT main$F1 +fcffffff g T_SEGMENT i$1 +00000000 g T_SEGMENT $ +00000010 g T_SEGMENT $ + + +RELOCATION RECORDS FOR [D00000000]: (none) + +RELOCATION RECORDS FOR [D00008000]: (none) + +RELOCATION RECORDS FOR [T_SEGMENT]: (none) + +Disassembly of section D00000000: +... +00008000 ($+)7ff0 linkw fp,#-4 +00008004 ($+)7ff4 nop +00008006 ($+)7ff6 movel #99,d0 +00008008 ($+)7ff8 cmpl fp@(-4),d0 +0000800c ($+)7ffc blts 00008014 ($+)8004 +0000800e ($+)7ffe addql #1,fp@(-4) +00008012 ($+)8002 bras 00008006 ($+)7ff6 +00008014 ($+)8004 unlk fp +00008016 ($+)8006 rts +... + +*/ + +static void +tekhex_init () +{ + unsigned int i; + static boolean inited = false; + int val; + + if (inited == false) + { + inited = true; + hex_init (); + val = 0; + for (i = 0; i < 10; i++) + { + sum_block[i + '0'] = val++; + } + for (i = 'A'; i <= 'Z'; i++) + { + sum_block[i] = val++; + } + sum_block['$'] = val++; + sum_block['%'] = val++; + sum_block['.'] = val++; + sum_block['_'] = val++; + for (i = 'a'; i <= 'z'; i++) + { + sum_block[i] = val++; + } + } +} + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 21 + +/* We cannot output our tekhexords as we see them, we have to glue them + together, this is done in this structure : */ + +struct tekhex_data_list_struct +{ + unsigned char *data; + bfd_vma where; + bfd_size_type size; + struct tekhex_data_list_struct *next; + +}; +typedef struct tekhex_data_list_struct tekhex_data_list_type; + +#define CHUNK_MASK 0x1fff + +struct data_struct + { + char chunk_data[CHUNK_MASK + 1]; + char chunk_init[CHUNK_MASK + 1]; + bfd_vma vma; + struct data_struct *next; + }; + +typedef struct tekhex_data_struct +{ + tekhex_data_list_type *head; + unsigned int type; + struct tekhex_symbol_struct *symbols; + struct data_struct *data; +} tdata_type; + +#define enda(x) (x->vma + x->size) + +static bfd_vma +getvalue (srcp) + char **srcp; +{ + char *src = *srcp; + bfd_vma value = 0; + unsigned int len = hex_value(*src++); + + if (len == 0) + len = 16; + while (len--) + { + value = value << 4 | hex_value(*src++); + } + *srcp = src; + return value; +} + +static unsigned int +getsym (dstp, srcp) + char *dstp; + char **srcp; +{ + char *src = *srcp; + unsigned int i; + unsigned int len = hex_value(*src++); + + if (len == 0) + len = 16; + for (i = 0; i < len; i++) + dstp[i] = src[i]; + dstp[i] = 0; + *srcp = src + i; + return len; +} + +struct data_struct * +find_chunk (abfd, vma) + bfd *abfd; + bfd_vma vma; +{ + struct data_struct *d = abfd->tdata.tekhex_data->data; + + vma &= ~CHUNK_MASK; + while (d && (d->vma) != vma) + { + d = d->next; + } + if (!d) + { + char *sname = bfd_alloc (abfd, 12); + + /* No chunk for this address, so make one up */ + d = (struct data_struct *) + bfd_alloc (abfd, sizeof (struct data_struct)); + + if (!sname || !d) + return NULL; + + memset (d->chunk_init, 0, CHUNK_MASK + 1); + memset (d->chunk_data, 0, CHUNK_MASK + 1); + d->next = abfd->tdata.tekhex_data->data; + d->vma = vma; + abfd->tdata.tekhex_data->data = d; + } + return d; +} + +static void +insert_byte (abfd, value, addr) + bfd *abfd; + int value; + bfd_vma addr; +{ + /* Find the chunk that this byte needs and put it in */ + struct data_struct *d = find_chunk (abfd, addr); + + d->chunk_data[addr & CHUNK_MASK] = value; + d->chunk_init[addr & CHUNK_MASK] = 1; +} + +/* The first pass is to find the names of all the sections, and see + how big the data is */ +static void +first_phase (abfd, type, src) + bfd *abfd; + char type; + char *src; +{ + asection *section = bfd_abs_section_ptr; + int len; + char sym[17]; /* A symbol can only be 16chars long */ + + switch (type) + { + case '6': + /* Data record - read it and store it */ + { + bfd_vma addr = getvalue (&src); + + while (*src) + { + insert_byte (abfd, HEX (src), addr); + src += 2; + addr++; + } + } + + return; + case '3': + /* Symbol record, read the segment */ + len = getsym (sym, &src); + section = bfd_get_section_by_name (abfd, sym); + if (section == (asection *) NULL) + { + char *n = bfd_alloc (abfd, len + 1); + + if (!n) + abort(); /* FIXME */ + memcpy (n, sym, len + 1); + section = bfd_make_section (abfd, n); + } + while (*src) + { + switch (*src) + { + case '1': /* section range */ + src++; + section->vma = getvalue (&src); + section->_raw_size = getvalue (&src) - section->vma; + section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + break; + case '0': + case '2': + case '3': + case '4': + case '6': + case '7': + case '8': + /* Symbols, add to section */ + { + tekhex_symbol_type *new = + (tekhex_symbol_type *) bfd_alloc (abfd, + sizeof (tekhex_symbol_type)); + char type = (*src); + + if (!new) + abort(); /* FIXME */ + new->symbol.the_bfd = abfd; + src++; + abfd->symcount++; + abfd->flags |= HAS_SYMS; + new->prev = abfd->tdata.tekhex_data->symbols; + abfd->tdata.tekhex_data->symbols = new; + len = getsym (sym, &src); + new->symbol.name = bfd_alloc (abfd, len + 1); + if (!new->symbol.name) + abort(); /* FIXME */ + memcpy ((char *) (new->symbol.name), sym, len + 1); + new->symbol.section = section; + if (type <= '4') + new->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); + else + new->symbol.flags = BSF_LOCAL; + new->symbol.value = getvalue (&src) - section->vma; + } + } + } + } +} + +/* Pass over an tekhex, calling one of the above functions on each + record. */ + +static void + pass_over (abfd, func) + bfd *abfd; + void (*func) (); +{ + unsigned int chars_on_line; + boolean eof = false; + + /* To the front of the file */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + abort (); + while (eof == false) + { + char buffer[MAXCHUNK]; + char *src = buffer; + char type; + + /* Find first '%' */ + eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1); + while (*src != '%' && !eof) + { + eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1); + } + if (eof) + break; + src++; + + /* Fetch the type and the length and the checksum */ + if (bfd_read (src, 1, 5, abfd) != 5) + abort (); /* FIXME */ + + type = src[2]; + + if (!ISHEX (src[0]) || !ISHEX (src[1])) + break; + + chars_on_line = HEX (src) - 5; /* Already read five char */ + + if (bfd_read (src, 1, chars_on_line, abfd) != chars_on_line) + abort (); /* FIXME */ + src[chars_on_line] = 0; /* put a null at the end */ + + func (abfd, type, src); + } + +} + +long +tekhex_get_symtab (abfd, table) + bfd *abfd; + asymbol **table; + +{ + tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; + unsigned int c = bfd_get_symcount (abfd); + + table[c] = 0; + while (p) + { + table[--c] = &(p->symbol); + p = p->prev; + } + + return bfd_get_symcount (abfd); +} + +long +tekhex_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); + +} + +static boolean +tekhex_mkobject (abfd) + bfd *abfd; +{ + tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); + + if (!tdata) + return false; + abfd->tdata.tekhex_data = tdata; + tdata->type = 1; + tdata->head = (tekhex_data_list_type *) NULL; + tdata->symbols = (struct tekhex_symbol_struct *) NULL; + tdata->data = (struct data_struct *) NULL; + return true; +} + +/* + Return true if the file looks like it's in TekHex format. Just look + for a percent sign and some hex digits */ + +static const bfd_target * +tekhex_object_p (abfd) + bfd *abfd; +{ + char b[4]; + + tekhex_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_read (b, 1, 4, abfd) != 4) + return NULL; + + if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) + return (const bfd_target *) NULL; + + tekhex_mkobject (abfd); + + pass_over (abfd, first_phase); + return abfd->xvec; +} + +static void +move_section_contents (abfd, section, locationp, offset, count, get) + bfd *abfd; + asection *section; + PTR locationp; + file_ptr offset; + bfd_size_type count; + boolean get; +{ + bfd_vma addr; + char *location = (char *) locationp; + bfd_vma prev_number = 1; /* Nothing can have this as a high bit*/ + struct data_struct *d = (struct data_struct *) NULL; + + for (addr = section->vma; count != 0; count--, addr++) + { + + bfd_vma chunk_number = addr & ~CHUNK_MASK; /* Get high bits of address */ + bfd_vma low_bits = addr & CHUNK_MASK; + + if (chunk_number != prev_number) + { + /* Different chunk, so move pointer */ + d = find_chunk (abfd, chunk_number); + } + + if (get) + { + if (d->chunk_init[low_bits]) + { + *location = d->chunk_data[low_bits]; + } + else + { + *location = 0; + } + } + else + { + d->chunk_data[low_bits] = *location; + d->chunk_init[low_bits] = (*location != 0); + } + + location++; + + } + +} +static boolean +tekhex_get_section_contents (abfd, section, locationp, offset, count) + bfd *abfd; + asection *section; + PTR locationp; + file_ptr offset; + bfd_size_type count; +{ + if (section->flags & (SEC_LOAD | SEC_ALLOC)) + { + move_section_contents (abfd, section, locationp, offset, count, true); + return true; + } + else + return false; +} + +boolean +tekhex_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +/* we have to save up all the Tekhexords for a splurge before output, + */ + +static boolean +tekhex_set_section_contents (abfd, section, locationp, offset, bytes_to_do) + bfd *abfd; + sec_ptr section; + PTR locationp; + file_ptr offset; + bfd_size_type bytes_to_do; +{ + + if (abfd->output_has_begun == false) + { + /* The first time around, allocate enough sections to hold all the chunks */ + asection *s = abfd->sections; + bfd_vma vma; + + for (s = abfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + for (vma = s->vma & ~CHUNK_MASK; + vma < s->vma + s->_raw_size; + vma += CHUNK_MASK) + find_chunk (abfd, vma); + } + } + + } + if (section->flags & (SEC_LOAD | SEC_ALLOC)) + { + move_section_contents (abfd, section, locationp, offset, bytes_to_do, false); + return true; + } + else + return false; + +} + +static void +writevalue (dst, value) + char **dst; + bfd_vma value; +{ + char *p = *dst; + int len; + int shift; + + for (len = 8, shift = 28; shift; shift -= 4, len--) + { + if ((value >> shift) & 0xf) + { + *p++ = len + '0'; + while (len) + { + *p++ = digs[(value >> shift) & 0xf]; + shift -= 4; + len--; + } + *dst = p; + return; + + } + } + *p++ = '1'; + *p++ = '0'; + *dst = p; +} + +static void +writesym (dst, sym) + char **dst; + CONST char *sym; +{ + char *p = *dst; + int len = (sym ? strlen (sym) : 0); + + if (len >= 16) + { + *p++ = '0'; + len = 16; + } + + else + { + if (len == 0) + { + *p++ = '1'; + sym = "$"; + len = 1; + } + else + { + *p++ = digs[len]; + } + } + + while (len--) + { + *p++ = *sym++; + } + *dst = p; +} + +static void +out (abfd, type, start, end) + bfd *abfd; + char type; + char *start; + char *end; +{ + int sum = 0; + char *s; + char front[6]; + bfd_size_type wrlen; + + front[0] = '%'; + TOHEX (front + 1, end - start + 5); + front[3] = type; + + for (s = start; s < end; s++) + { + sum += sum_block[(unsigned char) *s]; + } + + sum += sum_block[(unsigned char) front[1]]; /* length */ + sum += sum_block[(unsigned char) front[2]]; + sum += sum_block[(unsigned char) front[3]]; /* type */ + TOHEX (front + 4, sum); + if (bfd_write (front, 1, 6, abfd) != 6) + abort (); + end[0] = '\n'; + wrlen = end - start + 1; + if (bfd_write (start, 1, wrlen, abfd) != wrlen) + abort (); +} + +static boolean +tekhex_write_object_contents (abfd) + bfd *abfd; +{ + int bytes_written; + char buffer[100]; + asymbol **p; + asection *s; + struct data_struct *d; + + bytes_written = 0; + + /* And the raw data */ + for (d = abfd->tdata.tekhex_data->data; + d != (struct data_struct *) NULL; + d = d->next) + { + int low; + + CONST int span = 32; + int addr; + + /* Write it in blocks of 32 bytes */ + + for (addr = 0; addr < CHUNK_MASK + 1; addr += span) + { + int need = 0; + + /* Check to see if necessary */ + for (low = 0; !need && low < span; low++) + { + if (d->chunk_init[addr + low]) + need = 1; + } + if (need) + { + char *dst = buffer; + + writevalue (&dst, addr + d->vma); + for (low = 0; low < span; low++) + { + TOHEX (dst, d->chunk_data[addr + low]); + dst += 2; + } + out (abfd, '6', buffer, dst); + } + } + } + /* write all the section headers for the sections */ + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + char *dst = buffer; + + writesym (&dst, s->name); + *dst++ = '1'; + writevalue (&dst, s->vma); + writevalue (&dst, s->vma + s->_raw_size); + out (abfd, '3', buffer, dst); + } + + /* And the symbols */ + for (p = abfd->outsymbols; *p; p++) + { + int section_code = bfd_decode_symclass (*p); + + if (section_code != '?') + { /* do not include debug symbols */ + asymbol *s = *p; + char *dst = buffer; + + writesym (&dst, s->section->name); + + switch (section_code) + { + case 'A': + *dst++ = '2'; + break; + case 'a': + *dst++ = '6'; + break; + case 'D': + case 'B': + case 'O': + *dst++ = '4'; + break; + case 'd': + case 'b': + case 'o': + *dst++ = '8'; + break; + case 'T': + *dst++ = '3'; + break; + case 't': + *dst++ = '7'; + break; + case 'C': + case 'U': + bfd_set_error (bfd_error_wrong_format); + return false; + } + + writesym (&dst, s->name); + writevalue (&dst, s->value + s->section->vma); + out (abfd, '3', buffer, dst); + } + } + + /* And the terminator */ + if (bfd_write ("%0781010\n", 1, 9, abfd) != 9) + abort (); + return true; +} + +static int + tekhex_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; + +{ + return 0; +} + +static asymbol * +tekhex_make_empty_symbol (abfd) + bfd *abfd; +{ + tekhex_symbol_type *new = + (tekhex_symbol_type *) bfd_zalloc (abfd, sizeof (struct tekhex_symbol_struct)); + + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + new->prev = (struct tekhex_symbol_struct *) NULL; + return &(new->symbol); +} + +static void +tekhex_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +static void +tekhex_print_symbol (ignore_abfd, filep, symbol, how) + bfd *ignore_abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + break; + + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section->name; + + bfd_print_symbol_vandf ((PTR) file, symbol); + + fprintf (file, " %-5s %s", + section_name, + symbol->name); + } + } +} + +#define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup +#define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define tekhex_new_section_hook _bfd_generic_new_section_hook + +#define tekhex_bfd_is_local_label bfd_generic_is_local_label +#define tekhex_get_lineno _bfd_nosymbols_get_lineno +#define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line +#define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define tekhex_read_minisymbols _bfd_generic_read_minisymbols +#define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define tekhex_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define tekhex_bfd_relax_section bfd_generic_relax_section +#define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define tekhex_bfd_final_link _bfd_generic_final_link +#define tekhex_bfd_link_split_section _bfd_generic_link_split_section + +#define tekhex_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +const bfd_target tekhex_vec = +{ + "tekhex", /* name */ + bfd_target_tekhex_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (EXEC_P | /* object flags */ + HAS_SYMS | HAS_LINENO | HAS_DEBUG | HAS_RELOC | HAS_LOCALS | + WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + tekhex_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + tekhex_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + tekhex_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (tekhex), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (tekhex), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (tekhex), + BFD_JUMP_TABLE_LINK (tekhex), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/trad-core.c b/contrib/gdb/bfd/trad-core.c new file mode 100644 index 000000000000..09c74ae481cd --- /dev/null +++ b/contrib/gdb/bfd/trad-core.c @@ -0,0 +1,316 @@ +/* BFD back end for traditional Unix core files (U-area and raw sections) + Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by John Gilmore of Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include +#include +#include +#include +#include + +#include /* After a.out.h */ + +#ifdef TRAD_HEADER +#include TRAD_HEADER +#endif + + struct trad_core_struct + { + asection *data_section; + asection *stack_section; + asection *reg_section; + struct user u; + }; + +#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) +#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) +#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) +#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) + +/* forward declarations */ + +const bfd_target *trad_unix_core_file_p PARAMS ((bfd *abfd)); +char * trad_unix_core_file_failing_command PARAMS ((bfd *abfd)); +int trad_unix_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean trad_unix_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */ + +/* ARGSUSED */ +const bfd_target * +trad_unix_core_file_p (abfd) + bfd *abfd; + +{ + int val; + struct user u; + struct trad_core_struct *rawptr; + +#ifdef TRAD_CORE_USER_OFFSET + /* If defined, this macro is the file position of the user struct. */ + if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) != 0) + return 0; +#endif + + val = bfd_read ((void *)&u, 1, sizeof u, abfd); + if (val != sizeof u) + { + /* Too small to be a core file */ + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + /* Sanity check perhaps??? */ + if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */ + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + if (u.u_ssize > 0x1000000) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + + /* Check that the size claimed is no greater than the file size. */ + { + FILE *stream = bfd_cache_lookup (abfd); + struct stat statbuf; + if (stream == NULL) + return 0; + if (fstat (fileno (stream), &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + return 0; + } + if (NBPG * (UPAGES + u.u_dsize +#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE + - u.u_tsize +#endif + + u.u_ssize) > statbuf.st_size) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } +#ifndef TRAD_CORE_ALLOW_ANY_EXTRA_SIZE + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) +#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED + /* Some systems write the file too big. */ + + TRAD_CORE_EXTRA_SIZE_ALLOWED +#endif + < statbuf.st_size) + { + /* The file is too big. Maybe it's not a core file + or we otherwise have bad values for u_dsize and u_ssize). */ + bfd_set_error (bfd_error_wrong_format); + return 0; + } +#endif + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + /* Allocate both the upage and the struct core_data at once, so + a single free() will free them both. */ + rawptr = (struct trad_core_struct *) + bfd_zmalloc (sizeof (struct trad_core_struct)); + if (rawptr == NULL) + return 0; + + abfd->tdata.trad_core_data = rawptr; + + rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ + + /* Create the sections. This is raunchy, but bfd_close wants to free + them separately. */ + + core_stacksec(abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_stacksec (abfd) == NULL) + return NULL; + core_datasec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_datasec (abfd) == NULL) + return NULL; + core_regsec (abfd) = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (core_regsec (abfd) == NULL) + return NULL; + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_regsec (abfd)->flags = SEC_HAS_CONTENTS; + + core_datasec (abfd)->_raw_size = NBPG * u.u_dsize +#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE + - NBPG * u.u_tsize +#endif + ; + core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize; + core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */ + + /* What a hack... we'd like to steal it from the exec file, + since the upage does not seem to provide it. FIXME. */ +#ifdef HOST_DATA_START_ADDR + core_datasec (abfd)->vma = HOST_DATA_START_ADDR; +#else + core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize); +#endif + +#ifdef HOST_STACK_START_ADDR + core_stacksec (abfd)->vma = HOST_STACK_START_ADDR; +#else + core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize); +#endif + + /* This is tricky. As the "register section", we give them the entire + upage and stack. u.u_ar0 points to where "register 0" is stored. + There are two tricks with this, though. One is that the rest of the + registers might be at positive or negative (or both) displacements + from *u_ar0. The other is that u_ar0 is sometimes an absolute address + in kernel memory, and on other systems it is an offset from the beginning + of the `struct user'. + + As a practical matter, we don't know where the registers actually are, + so we have to pass the whole area to GDB. We encode the value of u_ar0 + by setting the .regs section up so that its virtual memory address + 0 is at the place pointed to by u_ar0 (by setting the vma of the start + of the section to -u_ar0). GDB uses this info to locate the regs, + using minor trickery to get around the offset-or-absolute-addr problem. */ + core_regsec (abfd)->vma = 0 - (bfd_vma) u.u_ar0; + + core_datasec (abfd)->filepos = NBPG * UPAGES; + core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize +#ifdef TRAD_CORE_DSIZE_INCLUDES_TSIZE + - NBPG * u.u_tsize +#endif + ; + core_regsec (abfd)->filepos = 0; /* Register segment is the upage */ + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + abfd->section_count = 3; + + return abfd->xvec; +} + +char * +trad_unix_core_file_failing_command (abfd) + bfd *abfd; +{ +#ifndef NO_CORE_COMMAND + char *com = abfd->tdata.trad_core_data->u.u_comm; + if (*com) + return com; + else +#endif + return 0; +} + +/* ARGSUSED */ +int +trad_unix_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd; +{ +#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL + return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd); +#else + return -1; /* FIXME, where is it? */ +#endif +} + +/* ARGSUSED */ +boolean +trad_unix_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( const bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET \ + ((bfd_signed_vma (*) PARAMS ((const bfd_byte *))) swap_abort ) + +const bfd_target trad_core_vec = + { + "trad-core", + bfd_target_unknown_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + trad_unix_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (_bfd_generic), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (trad_unix), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (_bfd_generic), + BFD_JUMP_TABLE_LINK (_bfd_nolink), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 /* backend_data */ +}; diff --git a/contrib/gdb/bfd/versados.c b/contrib/gdb/bfd/versados.c new file mode 100644 index 000000000000..84ad114e90a2 --- /dev/null +++ b/contrib/gdb/bfd/versados.c @@ -0,0 +1,906 @@ +/* BFD back-end for VERSAdos-E objects. + + Versados is a Motorola trademark. + + Copyright 1995 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + SUBSECTION + VERSAdos-E relocateable object file format + + DESCRIPTION + + This module supports reading of VERSAdos relocateable + object files. + + A VERSAdos file looks like contains + + o Indentification Record + o External Symbol Definition Record + o Object Text Recrod + o End Record + + + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" + + +static boolean versados_mkobject PARAMS ((bfd *)); +static boolean versados_scan PARAMS ((bfd *)); +static const bfd_target *versados_object_p PARAMS ((bfd *)); + + +#define VHEADER '1' +#define VESTDEF '2' +#define VOTR '3' +#define VEND '4' + + +#define ES_BASE 17 /* first symbol has esdid 17 */ + +/* Per file target dependent information */ + +/* one for each section */ +struct esdid + { + asection *section; /* ptr to bfd version */ + unsigned char *contents; /* used to build image */ + int pc; + int relocs; /* reloc count, valid end of pass 1 */ + int donerel; /* have relocs been translated */ + }; + +typedef struct versados_data_struct + { + int es_done; /* count of symbol index, starts at ES_BASE */ + asymbol *symbols; /* pointer to local symbols */ + char *strings; /* strings of all the above */ + int stringlen; /* len of string table (valid end of pass1) */ + int nsecsyms; /* number of sections */ + + int ndefs; /* number of exported symbols (they dont get esdids) */ + int nrefs; /* number of imported symbols (valid end of pass1) */ + + int ref_idx; /* current processed value of the above */ + int def_idx; + + int pass_2_done; + + struct esdid e[16]; /* per section info */ + int alert; /* to see if we're trampling */ + asymbol *rest[256 - 16]; /* per symbol info */ + + } +tdata_type; + +#define VDATA(abfd) (abfd->tdata.versados_data) +#define EDATA(abfd, n) (abfd->tdata.versados_data->e[n]) +#define RDATA(abfd, n) (abfd->tdata.versados_data->rest[n]) + +struct ext_otr + { + unsigned char size; + char type; + unsigned char map[4]; + unsigned char esdid; + unsigned char data[200]; + }; + +struct ext_vheader + { + unsigned char size; + char type; /* record type */ + char name[10]; /* module name */ + char rev; /* module rev number */ + char lang; + char vol[4]; + char user[2]; + char cat[8]; + char fname[8]; + char ext[2]; + char time[3]; + char date[3]; + char rest[211]; + }; + +struct ext_esd + { + unsigned char size; + char type; + unsigned char esd_entries[1]; + }; +#define ESD_ABS 0 +#define ESD_COMMON 1 +#define ESD_STD_REL_SEC 2 +#define ESD_SHRT_REL_SEC 3 +#define ESD_XDEF_IN_SEC 4 +#define ESD_XREF_SYM 7 +#define ESD_XREF_SEC 6 +#define ESD_XDEF_IN_ABS 5 +union ext_any + { + unsigned char size; + struct ext_vheader header; + struct ext_esd esd; + struct ext_otr otr; + }; + +/* Initialize by filling in the hex conversion array. */ + + + + + +/* Set up the tdata information. */ + +static boolean +versados_mkobject (abfd) + bfd *abfd; +{ + if (abfd->tdata.versados_data == NULL) + { + tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); + if (tdata == NULL) + return false; + abfd->tdata.versados_data = tdata; + tdata->symbols = NULL; + VDATA (abfd)->alert = 0x12345678; + } + + bfd_default_set_arch_mach (abfd, bfd_arch_m68k, 0); + return true; +} + + +/* Report a problem in an S record file. FIXME: This probably should + not call fprintf, but we really do need some mechanism for printing + error messages. */ + + + +static asymbol * +versados_new_symbol (abfd, snum, name, val, sec) + bfd *abfd; + int snum; + const char *name; + bfd_vma val; + asection *sec; +{ + asymbol *n = VDATA (abfd)->symbols + snum; + n->name = name; + n->value = val; + n->section = sec; + n->the_bfd = abfd; + n->flags = 0; + return n; +} + + +static int +get_record (abfd, ptr) + bfd *abfd; + union ext_any *ptr; +{ + bfd_read (&ptr->size, 1, 1, abfd); + if (bfd_read ((char *) ptr + 1, 1, ptr->size, abfd) != ptr->size) + return 0; + return 1; +} + +int +get_4 (pp) + unsigned char **pp; +{ + unsigned char *p = *pp; + *pp += 4; + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); +} + +void +get_10 (pp, name) + unsigned char **pp; + char *name; +{ + char *p = (char *) *pp; + int len = 10; + *pp += len; + while (*p != ' ' + && len) + { + *name++ = *p++; + len--; + } + *name = 0; +} + +static char * +new_symbol_string (abfd, name) + bfd *abfd; + char *name; +{ + char *n = VDATA (abfd)->strings; + strcpy (VDATA (abfd)->strings, name); + VDATA (abfd)->strings += strlen (VDATA (abfd)->strings) + 1; + return n; +} + + +static void +process_esd (abfd, esd, pass) + bfd *abfd; + struct ext_esd *esd; + int pass; +{ + /* Read through the ext def for the est entries */ + int togo = esd->size - 2; + bfd_vma size; + bfd_vma start; + asection *sec; + char name[11]; + unsigned char *ptr = esd->esd_entries; + unsigned char *end = ptr + togo; + while (ptr < end) + { + int scn = *ptr & 0xf; + int typ = (*ptr >> 4) & 0xf; + + /* Declare this section */ + sprintf (name, "%d", scn); + sec = bfd_make_section_old_way (abfd, strdup (name)); + sec->target_index = scn; + EDATA (abfd, scn).section = sec; + ptr++; + switch (typ) + { + default: + abort (); + case ESD_XREF_SEC: + case ESD_XREF_SYM: + { + int snum = VDATA (abfd)->ref_idx++; + get_10 (&ptr, name); + if (pass == 1) + { + VDATA (abfd)->stringlen += strlen (name) + 1; + } + else + { + int esidx; + asymbol *s; + char *n = new_symbol_string (abfd, name); + s = versados_new_symbol (abfd, snum, n, 0, + &bfd_und_section, scn); + esidx = VDATA (abfd)->es_done++; + RDATA (abfd, esidx - ES_BASE) = s; + } + } + break; + + + case ESD_ABS: + size = get_4 (&ptr); + start = get_4 (&ptr); + break; + case ESD_STD_REL_SEC: + case ESD_SHRT_REL_SEC: + { + sec->_raw_size = get_4 (&ptr); + sec->flags |= SEC_ALLOC; + } + break; + case ESD_XDEF_IN_ABS: + sec = (asection *) & bfd_abs_section; + case ESD_XDEF_IN_SEC: + { + int snum = VDATA (abfd)->def_idx++; + long val; + get_10 (&ptr, name); + val = get_4 (&ptr); + if (pass == 1) + { + /* Just remember the symbol */ + VDATA (abfd)->stringlen += strlen (name) + 1; + } + else + { + asymbol *s; + char *n = new_symbol_string (abfd, name); + s = versados_new_symbol (abfd, snum + VDATA (abfd)->nrefs, n, val, sec, scn); + s->flags |= BSF_GLOBAL; + } + } + break; + } + } +} + +#define R_RELWORD 1 +#define R_RELLONG 2 +#define R_RELWORD_NEG 3 +#define R_RELLONG_NEG 4 + +reloc_howto_type versados_howto_table[] = +{ + HOWTO (R_RELWORD, 0, 1, 16, false, + 0, complain_overflow_dont, 0, + "+v16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_RELLONG, 0, 2, 32, false, + 0, complain_overflow_dont, 0, + "+v32", true, 0xffffffff, 0xffffffff, false), + + HOWTO (R_RELWORD_NEG, 0, -1, 16, false, + 0, complain_overflow_dont, 0, + "-v16", true, 0x0000ffff, 0x0000ffff, false), + HOWTO (R_RELLONG_NEG, 0, -2, 32, false, + 0, complain_overflow_dont, 0, + "-v32", true, 0xffffffff, 0xffffffff, false), +}; + + +static int +get_offset (len, ptr) + int len; + unsigned char *ptr; +{ + int val = 0; + if (len) + { + int i; + val = *ptr++; + if (val & 0x80) + val |= ~0xff; + for (i = 1; i < len; i++) + val = (val << 8) | *ptr++; + } + + return val; +} + +static void +process_otr (abfd, otr, pass) + bfd *abfd; + struct ext_otr *otr; + int pass; +{ + unsigned long shift; + unsigned char *srcp = otr->data; + unsigned char *endp = (unsigned char *) otr + otr->size; + unsigned int bits = (otr->map[0] << 24) + | (otr->map[1] << 16) + | (otr->map[2] << 8) + | (otr->map[3] << 0); + + struct esdid *esdid = &EDATA (abfd, otr->esdid - 1); + unsigned char *contents = esdid->contents; + int need_contents = 0; + unsigned int dst_idx = esdid->pc; + + for (shift = (1 << 31); shift && srcp < endp; shift >>= 1) + { + if (bits & shift) + { + int flag = *srcp++; + int esdids = (flag >> 5) & 0x7; + int sizeinwords = ((flag >> 3) & 1) ? 2 : 1; + int offsetlen = flag & 0x7; + int j; + + + if (esdids == 0) + { + /* A zero esdid means the new pc is the offset given */ + dst_idx += get_offset (offsetlen, srcp); + srcp += offsetlen; + } + else + { + int val = get_offset (offsetlen, srcp + esdids); + if (pass == 1) + need_contents = 1; + else + for (j = 0; j < sizeinwords * 2; j++) + { + contents[dst_idx + (sizeinwords * 2) - j - 1] = val; + val >>= 8; + } + + for (j = 0; j < esdids; j++) + { + int esdid = *srcp++; + + if (esdid) + { + int rn = EDATA (abfd, otr->esdid - 1).relocs++; + if (pass == 1) + { + /* this is the first pass over the data, + just remember that we need a reloc */ + } + else + { + arelent *n = + EDATA (abfd, otr->esdid - 1).section->relocation + rn; + n->address = dst_idx; + + n->sym_ptr_ptr = (asymbol **) esdid; + n->addend = 0; + n->howto = versados_howto_table + ((j & 1) * 2) + (sizeinwords - 1); + } + } + } + srcp += offsetlen; + dst_idx += sizeinwords * 2; + } + } + else + { + need_contents = 1; + if (dst_idx < esdid->section->_raw_size) + if (pass == 2) + { + /* absolute code, comes in 16 bit lumps */ + contents[dst_idx] = srcp[0]; + contents[dst_idx + 1] = srcp[1]; + } + dst_idx += 2; + srcp += 2; + } + } + EDATA (abfd, otr->esdid - 1).pc = dst_idx; + + if (!contents && need_contents) + esdid->contents = (unsigned char *) bfd_alloc (abfd, esdid->section->_raw_size); + + +} + +static boolean +versados_scan (abfd) + bfd *abfd; +{ + int loop = 1; + int i; + int j; + int nsecs = 0; + + VDATA (abfd)->nrefs = 0; + VDATA (abfd)->ndefs = 0; + VDATA (abfd)->ref_idx = 0; + VDATA (abfd)->def_idx = 0; + + while (loop) + { + union ext_any any; + if (!get_record (abfd, &any)) + return true; + switch (any.header.type) + { + case VHEADER: + break; + case VEND: + loop = 0; + break; + case VESTDEF: + process_esd (abfd, &any.esd, 1); + break; + case VOTR: + process_otr (abfd, &any.otr, 1); + break; + } + } + + /* Now allocate space for the relocs and sections */ + + VDATA (abfd)->nrefs = VDATA (abfd)->ref_idx; + VDATA (abfd)->ndefs = VDATA (abfd)->def_idx; + VDATA (abfd)->ref_idx = 0; + VDATA (abfd)->def_idx = 0; + + abfd->symcount = VDATA (abfd)->nrefs + VDATA (abfd)->ndefs; + + for (i = 0; i < 16; i++) + { + struct esdid *esdid = &EDATA (abfd, i); + if (esdid->section) + { + esdid->section->relocation + = (arelent *) bfd_alloc (abfd, sizeof (arelent) * esdid->relocs); + + esdid->pc = 0; + + if (esdid->contents) + esdid->section->flags |= SEC_HAS_CONTENTS | SEC_LOAD; + + esdid->section->reloc_count = esdid->relocs; + if (esdid->relocs) + esdid->section->flags |= SEC_RELOC; + + esdid->relocs = 0; + + /* Add an entry into the symbol table for it */ + nsecs++; + VDATA (abfd)->stringlen += strlen (esdid->section->name) + 1; + } + } + + abfd->symcount += nsecs; + + VDATA (abfd)->symbols = (asymbol *) bfd_alloc (abfd, + sizeof (asymbol) * (abfd->symcount)); + + VDATA (abfd)->strings = bfd_alloc (abfd, VDATA (abfd)->stringlen); + + + /* Actually fill in the section symbols, + we stick them at the end of the table */ + + for (j = VDATA (abfd)->nrefs + VDATA (abfd)->ndefs, i = 0; i < 16; i++) + { + struct esdid *esdid = &EDATA (abfd, i); + asection *sec = esdid->section; + if (sec) + { + asymbol *s = VDATA (abfd)->symbols + j; + s->name = new_symbol_string (abfd, sec->name); + s->section = sec; + s->flags = BSF_LOCAL; + s->value = 0; + s->the_bfd = abfd; + j++; + } + } + if (abfd->symcount) + abfd->flags |= HAS_SYMS; + + /* Set this to nsecs - since we've already planted the section + symbols */ + VDATA (abfd)->nsecsyms = nsecs; + + VDATA (abfd)->ref_idx = 0; + + return 1; +} + + + +/* Check whether an existing file is a versados file. */ + +static const bfd_target * +versados_object_p (abfd) + bfd *abfd; +{ + struct ext_vheader ext; + unsigned char len; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET)) + return NULL; + + + bfd_read (&len, 1, 1, abfd); + if (bfd_read (&ext.type, 1, len, abfd) != len + || ext.type != '1') + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* ok, looks like a record, build the tdata and read + in.. */ + + if (!versados_mkobject (abfd) + || !versados_scan (abfd)) + return NULL; + + return abfd->xvec; +} + + +static boolean +versados_pass_2 (abfd) + bfd *abfd; +{ + union ext_any any; + + if (VDATA (abfd)->pass_2_done) + return 1; + + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + return 0; + + VDATA (abfd)->es_done = ES_BASE; + + + /* read records till we get to where we want to be */ + + while (1) + { + get_record (abfd, &any); + switch (any.header.type) + { + case VEND: + VDATA (abfd)->pass_2_done = 1; + return 1; + case VESTDEF: + process_esd (abfd, &any.esd, 2); + break; + case VOTR: + process_otr (abfd, &any.otr, 2); + break; + } + } +} + +static boolean +versados_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (!versados_pass_2 (abfd)) + return false; + + memcpy (location, + EDATA (abfd, section->target_index).contents + offset, + (size_t) count); + + return true; +} + +#define versados_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +static boolean +versados_set_section_contents (abfd, section, location, offset, bytes_to_do) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type bytes_to_do; +{ + return false; +} + + +/*ARGSUSED */ +static int +versados_sizeof_headers (abfd, exec) + bfd *abfd; + boolean exec; +{ + return 0; +} + +static asymbol * +versados_make_empty_symbol (abfd) + bfd *abfd; +{ + asymbol *new = (asymbol *) bfd_zalloc (abfd, sizeof (asymbol)); + if (new) + new->the_bfd = abfd; + return new; +} + +/* Return the amount of memory needed to read the symbol table. */ + +static long +versados_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); +} + +/* Return the symbol table. */ + +static long +versados_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int symcount = bfd_get_symcount (abfd); + unsigned int i; + asymbol *s; + + versados_pass_2 (abfd); + + for (i = 0, s = VDATA (abfd)->symbols; + i < symcount; + s++, i++) + { + *alocation++ = s; + } + + *alocation = NULL; + + return symcount; +} + +/*ARGSUSED */ +void +versados_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/*ARGSUSED */ +void +versados_print_symbol (ignore_abfd, afile, symbol, how) + bfd *ignore_abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + default: + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s", + symbol->section->name, + symbol->name); + + } +} + +long +versados_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + return (asect->reloc_count + 1) * sizeof (arelent *); +} + + +long +versados_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + unsigned int count; + arelent *src; + + versados_pass_2 (abfd); + src = section->relocation; + if (!EDATA (abfd, section->target_index).donerel) + { + EDATA (abfd, section->target_index).donerel = 1; + /* translate from indexes to symptr ptrs */ + for (count = 0; count < section->reloc_count; count++) + { + int esdid = (int) src[count].sym_ptr_ptr; + + if (esdid == 0) + { + src[count].sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + } + else if (esdid < ES_BASE) /* Section relative thing */ + { + struct esdid *e = &EDATA (abfd, esdid - 1); + if (!section) + { + /** relocation relative to section which was + never declared ! */ + } + src[count].sym_ptr_ptr = e->section->symbol_ptr_ptr; + } + else + { + src[count].sym_ptr_ptr = symbols + esdid - ES_BASE; + } + + } + } + + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = src++; + } + *relptr = 0; + return section->reloc_count; +} + +#define versados_close_and_cleanup _bfd_generic_close_and_cleanup +#define versados_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define versados_new_section_hook _bfd_generic_new_section_hook + +#define versados_bfd_is_local_label bfd_generic_is_local_label +#define versados_get_lineno _bfd_nosymbols_get_lineno +#define versados_find_nearest_line _bfd_nosymbols_find_nearest_line +#define versados_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define versados_read_minisymbols _bfd_generic_read_minisymbols +#define versados_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define versados_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define versados_set_arch_mach bfd_default_set_arch_mach + +#define versados_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define versados_bfd_relax_section bfd_generic_relax_section +#define versados_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define versados_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define versados_bfd_final_link _bfd_generic_final_link +#define versados_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target versados_vec = +{ + "versados", /* name */ + bfd_target_versados_flavour, + BFD_ENDIAN_BIG, /* target byte order */ + BFD_ENDIAN_BIG, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + versados_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + versados_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + bfd_false, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (versados), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (versados), + BFD_JUMP_TABLE_RELOCS (versados), + BFD_JUMP_TABLE_WRITE (versados), + BFD_JUMP_TABLE_LINK (versados), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + (PTR) 0 +}; diff --git a/contrib/gdb/bfd/xcofflink.c b/contrib/gdb/bfd/xcofflink.c new file mode 100644 index 000000000000..16a76cc7ca55 --- /dev/null +++ b/contrib/gdb/bfd/xcofflink.c @@ -0,0 +1,5798 @@ +/* POWER/PowerPC XCOFF linker support. + Copyright 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor , Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +/* This file holds the XCOFF linker code. */ + +#define STRING_SIZE_SIZE (4) + +/* In order to support linking different object file formats into an + XCOFF format, we need to be able to determine whether a particular + bfd_target is an XCOFF vector. FIXME: We need to rethink this + whole approach. */ +#define XCOFF_XVECP(xv) \ + (strcmp ((xv)->name, "aixcoff-rs6000") == 0 \ + || strcmp ((xv)->name, "xcoff-powermac") == 0) + +/* Get the XCOFF hash table entries for a BFD. */ +#define obj_xcoff_sym_hashes(bfd) \ + ((struct xcoff_link_hash_entry **) obj_coff_sym_hashes (bfd)) + +/* XCOFF relocation types. These probably belong in a header file + somewhere. The relocations are described in the function + _bfd_ppc_xcoff_relocate_section in this file. */ + +#define R_POS (0x00) +#define R_NEG (0x01) +#define R_REL (0x02) +#define R_TOC (0x03) +#define R_RTB (0x04) +#define R_GL (0x05) +#define R_TCL (0x06) +#define R_BA (0x08) +#define R_BR (0x0a) +#define R_RL (0x0c) +#define R_RLA (0x0d) +#define R_REF (0x0f) +#define R_TRL (0x12) +#define R_TRLA (0x13) +#define R_RRTBI (0x14) +#define R_RRTBA (0x15) +#define R_CAI (0x16) +#define R_CREL (0x17) +#define R_RBA (0x18) +#define R_RBAC (0x19) +#define R_RBR (0x1a) +#define R_RBRC (0x1b) + +/* The first word of global linkage code. This must be modified by + filling in the correct TOC offset. */ + +#define XCOFF_GLINK_FIRST (0x81820000) /* lwz r12,0(r2) */ + +/* The remaining words of global linkage code. */ + +static unsigned long xcoff_glink_code[] = +{ + 0x90410014, /* stw r2,20(r1) */ + 0x800c0000, /* lwz r0,0(r12) */ + 0x804c0004, /* lwz r2,4(r12) */ + 0x7c0903a6, /* mtctr r0 */ + 0x4e800420, /* bctr */ + 0x0, /* start of traceback table */ + 0x000c8000, /* traceback table */ + 0x0 /* traceback table */ +}; + +#define XCOFF_GLINK_SIZE \ + (((sizeof xcoff_glink_code / sizeof xcoff_glink_code[0]) * 4) + 4) + +/* We reuse the SEC_ROM flag as a mark flag for garbage collection. + This flag will only be used on input sections. */ + +#define SEC_MARK (SEC_ROM) + +/* The ldhdr structure. This appears at the start of the .loader + section. */ + +struct internal_ldhdr +{ + /* The version number: currently always 1. */ + unsigned long l_version; + /* The number of symbol table entries. */ + bfd_size_type l_nsyms; + /* The number of relocation table entries. */ + bfd_size_type l_nreloc; + /* The length of the import file string table. */ + bfd_size_type l_istlen; + /* The number of import files. */ + bfd_size_type l_nimpid; + /* The offset from the start of the .loader section to the first + entry in the import file table. */ + bfd_size_type l_impoff; + /* The length of the string table. */ + bfd_size_type l_stlen; + /* The offset from the start of the .loader section to the first + entry in the string table. */ + bfd_size_type l_stoff; +}; + +struct external_ldhdr +{ + bfd_byte l_version[4]; + bfd_byte l_nsyms[4]; + bfd_byte l_nreloc[4]; + bfd_byte l_istlen[4]; + bfd_byte l_nimpid[4]; + bfd_byte l_impoff[4]; + bfd_byte l_stlen[4]; + bfd_byte l_stoff[4]; +}; + +#define LDHDRSZ (8 * 4) + +/* The ldsym structure. This is used to represent a symbol in the + .loader section. */ + +struct internal_ldsym +{ + union + { + /* The symbol name if <= SYMNMLEN characters. */ + char _l_name[SYMNMLEN]; + struct + { + /* Zero if the symbol name is more than SYMNMLEN characters. */ + long _l_zeroes; + /* The offset in the string table if the symbol name is more + than SYMNMLEN characters. */ + long _l_offset; + } _l_l; + } _l; + /* The symbol value. */ + bfd_vma l_value; + /* The symbol section number. */ + short l_scnum; + /* The symbol type and flags. */ + char l_smtype; + /* The symbol storage class. */ + char l_smclas; + /* The import file ID. */ + bfd_size_type l_ifile; + /* Offset to the parameter type check string. */ + bfd_size_type l_parm; +}; + +struct external_ldsym +{ + union + { + bfd_byte _l_name[SYMNMLEN]; + struct + { + bfd_byte _l_zeroes[4]; + bfd_byte _l_offset[4]; + } _l_l; + } _l; + bfd_byte l_value[4]; + bfd_byte l_scnum[2]; + bfd_byte l_smtype[1]; + bfd_byte l_smclas[1]; + bfd_byte l_ifile[4]; + bfd_byte l_parm[4]; +}; + +#define LDSYMSZ (8 + 3 * 4 + 2 + 2) + +/* These flags are for the l_smtype field (the lower three bits are an + XTY_* value). */ + +/* Imported symbol. */ +#define L_IMPORT (0x40) +/* Entry point. */ +#define L_ENTRY (0x20) +/* Exported symbol. */ +#define L_EXPORT (0x10) + +/* The ldrel structure. This is used to represent a reloc in the + .loader section. */ + +struct internal_ldrel +{ + /* The reloc address. */ + bfd_vma l_vaddr; + /* The symbol table index in the .loader section symbol table. */ + bfd_size_type l_symndx; + /* The relocation type and size. */ + short l_rtype; + /* The section number this relocation applies to. */ + short l_rsecnm; +}; + +struct external_ldrel +{ + bfd_byte l_vaddr[4]; + bfd_byte l_symndx[4]; + bfd_byte l_rtype[2]; + bfd_byte l_rsecnm[2]; +}; + +#define LDRELSZ (2 * 4 + 2 * 2) + +/* The list of import files. */ + +struct xcoff_import_file +{ + /* The next entry in the list. */ + struct xcoff_import_file *next; + /* The path. */ + const char *path; + /* The file name. */ + const char *file; + /* The member name. */ + const char *member; +}; + +/* An entry in the XCOFF linker hash table. */ + +struct xcoff_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. Set to -1 initially. Set to -2 if + there is a reloc against this symbol. */ + long indx; + + /* If we have created a TOC entry for this symbol, this is the .tc + section which holds it. */ + asection *toc_section; + + union + { + /* If we have created a TOC entry (the XCOFF_SET_TOC flag is + set), this is the offset in toc_section. */ + bfd_vma toc_offset; + /* If the TOC entry comes from an input file, this is set to the + symbo lindex of the C_HIDEXT XMC_TC symbol. */ + long toc_indx; + } u; + + /* If this symbol is a function entry point which is called, this + field holds a pointer to the function descriptor. If this symbol + is a function descriptor, this field holds a pointer to the + function entry point. */ + struct xcoff_link_hash_entry *descriptor; + + /* The .loader symbol table entry, if there is one. */ + struct internal_ldsym *ldsym; + + /* The .loader symbol table index. */ + long ldindx; + + /* Some linker flags. */ + unsigned short flags; + /* Symbol is referenced by a regular object. */ +#define XCOFF_REF_REGULAR (01) + /* Symbol is defined by a regular object. */ +#define XCOFF_DEF_REGULAR (02) + /* Symbol is defined by a dynamic object. */ +#define XCOFF_DEF_DYNAMIC (04) + /* Symbol is used in a reloc being copied into the .loader section. */ +#define XCOFF_LDREL (010) + /* Symbol is the entry point. */ +#define XCOFF_ENTRY (020) + /* Symbol is called; this is, it appears in a R_BR reloc. */ +#define XCOFF_CALLED (040) + /* Symbol needs the TOC entry filled in. */ +#define XCOFF_SET_TOC (0100) + /* Symbol is explicitly imported. */ +#define XCOFF_IMPORT (0200) + /* Symbol is explicitly exported. */ +#define XCOFF_EXPORT (0400) + /* Symbol has been processed by xcoff_build_ldsyms. */ +#define XCOFF_BUILT_LDSYM (01000) + /* Symbol is mentioned by a section which was not garbage collected. */ +#define XCOFF_MARK (02000) + /* Symbol size is recorded in size_list list from hash table. */ +#define XCOFF_HAS_SIZE (04000) + /* Symbol is a function descriptor. */ +#define XCOFF_DESCRIPTOR (010000) + + /* The storage mapping class. */ + unsigned char smclas; +}; + +/* The XCOFF linker hash table. */ + +struct xcoff_link_hash_table +{ + struct bfd_link_hash_table root; + + /* The .debug string hash table. We need to compute this while + reading the input files, so that we know how large the .debug + section will be before we assign section positions. */ + struct bfd_strtab_hash *debug_strtab; + + /* The .debug section we will use for the final output. */ + asection *debug_section; + + /* The .loader section we will use for the final output. */ + asection *loader_section; + + /* A count of non TOC relative relocs which will need to be + allocated in the .loader section. */ + size_t ldrel_count; + + /* The .loader section header. */ + struct internal_ldhdr ldhdr; + + /* The .gl section we use to hold global linkage code. */ + asection *linkage_section; + + /* The .tc section we use to hold toc entries we build for global + linkage code. */ + asection *toc_section; + + /* The .ds section we use to hold function descriptors which we + create for exported symbols. */ + asection *descriptor_section; + + /* The list of import files. */ + struct xcoff_import_file *imports; + + /* Required alignment of sections within the output file. */ + unsigned long file_align; + + /* Whether the .text section must be read-only. */ + boolean textro; + + /* Whether garbage collection was done. */ + boolean gc; + + /* A linked list of symbols for which we have size information. */ + struct xcoff_link_size_list + { + struct xcoff_link_size_list *next; + struct xcoff_link_hash_entry *h; + bfd_size_type size; + } *size_list; + + /* Magic sections: _text, _etext, _data, _edata, _end, end. */ + asection *special_sections[6]; +}; + +/* Information we keep for each section in the output file during the + final link phase. */ + +struct xcoff_link_section_info +{ + /* The relocs to be output. */ + struct internal_reloc *relocs; + /* For each reloc against a global symbol whose index was not known + when the reloc was handled, the global hash table entry. */ + struct xcoff_link_hash_entry **rel_hashes; + /* If there is a TOC relative reloc against a global symbol, and the + index of the TOC symbol is not known when the reloc was handled, + an entry is added to this linked list. This is not an array, + like rel_hashes, because this case is quite uncommon. */ + struct xcoff_toc_rel_hash + { + struct xcoff_toc_rel_hash *next; + struct xcoff_link_hash_entry *h; + struct internal_reloc *rel; + } *toc_rel_hashes; +}; + +/* Information that we pass around while doing the final link step. */ + +struct xcoff_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Hash table for long symbol names. */ + struct bfd_strtab_hash *strtab; + /* Array of information kept for each output section, indexed by the + target_index field. */ + struct xcoff_link_section_info *section_info; + /* Symbol index of last C_FILE symbol (-1 if none). */ + long last_file_index; + /* Contents of last C_FILE symbol. */ + struct internal_syment last_file; + /* Symbol index of TOC symbol. */ + long toc_symindx; + /* Start of .loader symbols. */ + struct external_ldsym *ldsym; + /* Next .loader reloc to swap out. */ + struct external_ldrel *ldrel; + /* File position of start of line numbers. */ + file_ptr line_filepos; + /* Buffer large enough to hold swapped symbols of any input file. */ + struct internal_syment *internal_syms; + /* Buffer large enough to hold output indices of symbols of any + input file. */ + long *sym_indices; + /* Buffer large enough to hold output symbols for any input file. */ + bfd_byte *outsyms; + /* Buffer large enough to hold external line numbers for any input + section. */ + bfd_byte *linenos; + /* Buffer large enough to hold any input section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any input section. */ + bfd_byte *external_relocs; +}; + +static void xcoff_swap_ldhdr_in + PARAMS ((bfd *, const struct external_ldhdr *, struct internal_ldhdr *)); +static void xcoff_swap_ldhdr_out + PARAMS ((bfd *, const struct internal_ldhdr *, struct external_ldhdr *)); +static void xcoff_swap_ldsym_in + PARAMS ((bfd *, const struct external_ldsym *, struct internal_ldsym *)); +static void xcoff_swap_ldsym_out + PARAMS ((bfd *, const struct internal_ldsym *, struct external_ldsym *)); +static void xcoff_swap_ldrel_out + PARAMS ((bfd *, const struct internal_ldrel *, struct external_ldrel *)); +static struct bfd_hash_entry *xcoff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct internal_reloc *xcoff_read_internal_relocs + PARAMS ((bfd *, asection *, boolean, bfd_byte *, boolean, + struct internal_reloc *)); +static boolean xcoff_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean xcoff_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *)); +static boolean xcoff_link_check_ar_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean *)); +static bfd_size_type xcoff_find_reloc + PARAMS ((struct internal_reloc *, bfd_size_type, bfd_vma)); +static boolean xcoff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *)); +static boolean xcoff_link_add_dynamic_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean xcoff_mark PARAMS ((struct bfd_link_info *, asection *)); +static void xcoff_sweep PARAMS ((struct bfd_link_info *)); +static boolean xcoff_build_ldsyms + PARAMS ((struct xcoff_link_hash_entry *, PTR)); +static boolean xcoff_link_input_bfd + PARAMS ((struct xcoff_final_link_info *, bfd *)); +static boolean xcoff_write_global_symbol + PARAMS ((struct xcoff_link_hash_entry *, PTR)); +static boolean xcoff_reloc_link_order + PARAMS ((bfd *, struct xcoff_final_link_info *, asection *, + struct bfd_link_order *)); +static int xcoff_sort_relocs PARAMS ((const PTR, const PTR)); + +/* Routines to swap information in the XCOFF .loader section. If we + ever need to write an XCOFF loader, this stuff will need to be + moved to another file shared by the linker (which XCOFF calls the + ``binder'') and the loader. */ + +/* Swap in the ldhdr structure. */ + +static void +xcoff_swap_ldhdr_in (abfd, src, dst) + bfd *abfd; + const struct external_ldhdr *src; + struct internal_ldhdr *dst; +{ + dst->l_version = bfd_get_32 (abfd, src->l_version); + dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms); + dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc); + dst->l_istlen = bfd_get_32 (abfd, src->l_istlen); + dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid); + dst->l_impoff = bfd_get_32 (abfd, src->l_impoff); + dst->l_stlen = bfd_get_32 (abfd, src->l_stlen); + dst->l_stoff = bfd_get_32 (abfd, src->l_stoff); +} + +/* Swap out the ldhdr structure. */ + +static void +xcoff_swap_ldhdr_out (abfd, src, dst) + bfd *abfd; + const struct internal_ldhdr *src; + struct external_ldhdr *dst; +{ + bfd_put_32 (abfd, src->l_version, dst->l_version); + bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms); + bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc); + bfd_put_32 (abfd, src->l_istlen, dst->l_istlen); + bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid); + bfd_put_32 (abfd, src->l_impoff, dst->l_impoff); + bfd_put_32 (abfd, src->l_stlen, dst->l_stlen); + bfd_put_32 (abfd, src->l_stoff, dst->l_stoff); +} + +/* Swap in the ldsym structure. */ + +static void +xcoff_swap_ldsym_in (abfd, src, dst) + bfd *abfd; + const struct external_ldsym *src; + struct internal_ldsym *dst; +{ + if (bfd_get_32 (abfd, src->_l._l_l._l_zeroes) != 0) + memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN); + else + { + dst->_l._l_l._l_zeroes = 0; + dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->_l._l_l._l_offset); + } + dst->l_value = bfd_get_32 (abfd, src->l_value); + dst->l_scnum = bfd_get_16 (abfd, src->l_scnum); + dst->l_smtype = bfd_get_8 (abfd, src->l_smtype); + dst->l_smclas = bfd_get_8 (abfd, src->l_smclas); + dst->l_ifile = bfd_get_32 (abfd, src->l_ifile); + dst->l_parm = bfd_get_32 (abfd, src->l_parm); +} + +/* Swap out the ldsym structure. */ + +static void +xcoff_swap_ldsym_out (abfd, src, dst) + bfd *abfd; + const struct internal_ldsym *src; + struct external_ldsym *dst; +{ + if (src->_l._l_l._l_zeroes != 0) + memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN); + else + { + bfd_put_32 (abfd, 0, dst->_l._l_l._l_zeroes); + bfd_put_32 (abfd, src->_l._l_l._l_offset, dst->_l._l_l._l_offset); + } + bfd_put_32 (abfd, src->l_value, dst->l_value); + bfd_put_16 (abfd, src->l_scnum, dst->l_scnum); + bfd_put_8 (abfd, src->l_smtype, dst->l_smtype); + bfd_put_8 (abfd, src->l_smclas, dst->l_smclas); + bfd_put_32 (abfd, src->l_ifile, dst->l_ifile); + bfd_put_32 (abfd, src->l_parm, dst->l_parm); +} + +/* As it happens, we never need to swap in the ldrel structure. */ + +/* Swap out the ldrel structure. */ + +static void +xcoff_swap_ldrel_out (abfd, src, dst) + bfd *abfd; + const struct internal_ldrel *src; + struct external_ldrel *dst; +{ + bfd_put_32 (abfd, src->l_vaddr, dst->l_vaddr); + bfd_put_32 (abfd, src->l_symndx, dst->l_symndx); + bfd_put_16 (abfd, src->l_rtype, dst->l_rtype); + bfd_put_16 (abfd, src->l_rsecnm, dst->l_rsecnm); +} + +/* Routine to create an entry in an XCOFF link hash table. */ + +static struct bfd_hash_entry * +xcoff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct xcoff_link_hash_entry *ret = (struct xcoff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct xcoff_link_hash_entry *) NULL) + ret = ((struct xcoff_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct xcoff_link_hash_entry))); + if (ret == (struct xcoff_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct xcoff_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != NULL) + { + /* Set local fields. */ + ret->indx = -1; + ret->toc_section = NULL; + ret->u.toc_indx = -1; + ret->descriptor = NULL; + ret->ldsym = NULL; + ret->ldindx = -1; + ret->flags = 0; + ret->smclas = XMC_UA; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create a XCOFF link hash table. */ + +struct bfd_link_hash_table * +_bfd_xcoff_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ + struct xcoff_link_hash_table *ret; + + ret = ((struct xcoff_link_hash_table *) + bfd_alloc (abfd, sizeof (struct xcoff_link_hash_table))); + if (ret == (struct xcoff_link_hash_table *) NULL) + return (struct bfd_link_hash_table *) NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, xcoff_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return (struct bfd_link_hash_table *) NULL; + } + + ret->debug_strtab = _bfd_xcoff_stringtab_init (); + ret->debug_section = NULL; + ret->loader_section = NULL; + ret->ldrel_count = 0; + memset (&ret->ldhdr, 0, sizeof (struct internal_ldhdr)); + ret->linkage_section = NULL; + ret->toc_section = NULL; + ret->descriptor_section = NULL; + ret->imports = NULL; + ret->file_align = 0; + ret->textro = false; + ret->gc = false; + memset (ret->special_sections, 0, sizeof ret->special_sections); + + /* The linker will always generate a full a.out header. We need to + record that fact now, before the sizeof_headers routine could be + called. */ + xcoff_data (abfd)->full_aouthdr = true; + + return &ret->root; +} + +/* Look up an entry in an XCOFF link hash table. */ + +#define xcoff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct xcoff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy),\ + (follow))) + +/* Traverse an XCOFF link hash table. */ + +#define xcoff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the XCOFF link hash table from the info structure. This is + just a cast. */ + +#define xcoff_hash_table(p) ((struct xcoff_link_hash_table *) ((p)->hash)) + +/* Read internal relocs for an XCOFF csect. This is a wrapper around + _bfd_coff_read_internal_relocs which tries to take advantage of any + relocs which may have been cached for the enclosing section. */ + +static struct internal_reloc * +xcoff_read_internal_relocs (abfd, sec, cache, external_relocs, + require_internal, internal_relocs) + bfd *abfd; + asection *sec; + boolean cache; + bfd_byte *external_relocs; + boolean require_internal; + struct internal_reloc *internal_relocs; +{ + if (coff_section_data (abfd, sec) != NULL + && coff_section_data (abfd, sec)->relocs == NULL + && xcoff_section_data (abfd, sec) != NULL) + { + asection *enclosing; + + enclosing = xcoff_section_data (abfd, sec)->enclosing; + + if (enclosing != NULL + && (coff_section_data (abfd, enclosing) == NULL + || coff_section_data (abfd, enclosing)->relocs == NULL) + && cache + && enclosing->reloc_count > 0) + { + if (_bfd_coff_read_internal_relocs (abfd, enclosing, true, + external_relocs, false, + (struct internal_reloc *) NULL) + == NULL) + return NULL; + } + + if (enclosing != NULL + && coff_section_data (abfd, enclosing) != NULL + && coff_section_data (abfd, enclosing)->relocs != NULL) + { + size_t off; + + off = ((sec->rel_filepos - enclosing->rel_filepos) + / bfd_coff_relsz (abfd)); + if (! require_internal) + return coff_section_data (abfd, enclosing)->relocs + off; + memcpy (internal_relocs, + coff_section_data (abfd, enclosing)->relocs + off, + sec->reloc_count * sizeof (struct internal_reloc)); + return internal_relocs; + } + } + + return _bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs, + require_internal, internal_relocs); +} + +/* Given an XCOFF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +_bfd_xcoff_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return xcoff_link_add_object_symbols (abfd, info); + case bfd_archive: + return (_bfd_generic_link_add_archive_symbols + (abfd, info, xcoff_link_check_archive_element)); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add symbols from an XCOFF object file. */ + +static boolean +xcoff_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (! _bfd_coff_get_external_symbols (abfd)) + return false; + if (! xcoff_link_add_symbols (abfd, info)) + return false; + if (! info->keep_memory) + { + if (! _bfd_coff_free_symbols (abfd)) + return false; + } + return true; +} + +/* Check a single archive element to see if we need to include it in + the link. *PNEEDED is set according to whether this element is + needed in the link or not. This is called via + _bfd_generic_link_add_archive_symbols. */ + +static boolean +xcoff_link_check_archive_element (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + if (! _bfd_coff_get_external_symbols (abfd)) + return false; + + if (! xcoff_link_check_ar_symbols (abfd, info, pneeded)) + return false; + + if (*pneeded) + { + if (! xcoff_link_add_symbols (abfd, info)) + return false; + } + + if (! info->keep_memory || ! *pneeded) + { + if (! _bfd_coff_free_symbols (abfd)) + return false; + } + + return true; +} + +/* Look through the symbols to see if this object file should be + included in the link. */ + +static boolean +xcoff_link_check_ar_symbols (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + bfd_size_type symesz; + bfd_byte *esym; + bfd_byte *esym_end; + + *pneeded = false; + + symesz = bfd_coff_symesz (abfd); + esym = (bfd_byte *) obj_coff_external_syms (abfd); + esym_end = esym + obj_raw_syment_count (abfd) * symesz; + while (esym < esym_end) + { + struct internal_syment sym; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); + + if (sym.n_sclass == C_EXT && sym.n_scnum != N_UNDEF) + { + const char *name; + char buf[SYMNMLEN + 1]; + struct bfd_link_hash_entry *h; + + /* This symbol is externally visible, and is defined by this + object file. */ + + name = _bfd_coff_internal_syment_name (abfd, &sym, buf); + if (name == NULL) + return false; + h = bfd_link_hash_lookup (info->hash, name, false, false, true); + + /* We are only interested in symbols that are currently + undefined. If a symbol is currently known to be common, + XCOFF linkers do not bring in an object file which + defines it. We also don't bring in symbols to satisfy + undefined references in shared objects. */ + if (h != (struct bfd_link_hash_entry *) NULL + && h->type == bfd_link_hash_undefined) + { + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + return false; + *pneeded = true; + return true; + } + } + + esym += (sym.n_numaux + 1) * symesz; + } + + /* We do not need this object file. */ + return true; +} + +/* Returns the index of reloc in RELOCS with the least address greater + than or equal to ADDRESS. The relocs are sorted by address. */ + +static bfd_size_type +xcoff_find_reloc (relocs, count, address) + struct internal_reloc *relocs; + bfd_size_type count; + bfd_vma address; +{ + bfd_size_type min, max, this; + + if (count < 2) + { + if (count == 1 && relocs[0].r_vaddr < address) + return 1; + else + return 0; + } + + min = 0; + max = count; + + /* Do a binary search over (min,max]. */ + while (min + 1 < max) + { + bfd_vma raddr; + + this = (max + min) / 2; + raddr = relocs[this].r_vaddr; + if (raddr > address) + max = this; + else if (raddr < address) + min = this; + else + { + min = this; + break; + } + } + + if (relocs[min].r_vaddr < address) + return min + 1; + + while (min > 0 + && relocs[min - 1].r_vaddr == address) + --min; + + return min; +} + +/* Add all the symbols from an object file to the hash table. + + XCOFF is a weird format. A normal XCOFF .o files will have three + COFF sections--.text, .data, and .bss--but each COFF section will + contain many csects. These csects are described in the symbol + table. From the linker's point of view, each csect must be + considered a section in its own right. For example, a TOC entry is + handled as a small XMC_TC csect. The linker must be able to merge + different TOC entries together, which means that it must be able to + extract the XMC_TC csects from the .data section of the input .o + file. + + From the point of view of our linker, this is, of course, a hideous + nightmare. We cope by actually creating sections for each csect, + and discarding the original sections. We then have to handle the + relocation entries carefully, since the only way to tell which + csect they belong to is to examine the address. */ + +static boolean +xcoff_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + unsigned int n_tmask; + unsigned int n_btshft; + boolean default_copy; + bfd_size_type symcount; + struct xcoff_link_hash_entry **sym_hash; + asection **csect_cache; + bfd_size_type linesz; + asection *o; + asection *last_real; + boolean keep_syms; + asection *csect; + unsigned int csect_index; + asection *first_csect; + bfd_size_type symesz; + bfd_byte *esym; + bfd_byte *esym_end; + struct reloc_info_struct + { + struct internal_reloc *relocs; + asection **csects; + bfd_byte *linenos; + } *reloc_info = NULL; + + if ((abfd->flags & DYNAMIC) != 0 + && ! info->static_link) + { + if (! xcoff_link_add_dynamic_symbols (abfd, info)) + return false; + } + + /* We need to build a .loader section, so we do it here. This won't + work if we're producing an XCOFF output file with no XCOFF input + files. FIXME. */ + if (xcoff_hash_table (info)->loader_section == NULL) + { + asection *lsec; + + lsec = bfd_make_section_anyway (abfd, ".loader"); + if (lsec == NULL) + goto error_return; + xcoff_hash_table (info)->loader_section = lsec; + lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY; + } + /* Likewise for the linkage section. */ + if (xcoff_hash_table (info)->linkage_section == NULL) + { + asection *lsec; + + lsec = bfd_make_section_anyway (abfd, ".gl"); + if (lsec == NULL) + goto error_return; + xcoff_hash_table (info)->linkage_section = lsec; + lsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + lsec->alignment_power = 2; + } + /* Likewise for the TOC section. */ + if (xcoff_hash_table (info)->toc_section == NULL) + { + asection *tsec; + + tsec = bfd_make_section_anyway (abfd, ".tc"); + if (tsec == NULL) + goto error_return; + xcoff_hash_table (info)->toc_section = tsec; + tsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + tsec->alignment_power = 2; + } + /* Likewise for the descriptor section. */ + if (xcoff_hash_table (info)->descriptor_section == NULL) + { + asection *dsec; + + dsec = bfd_make_section_anyway (abfd, ".ds"); + if (dsec == NULL) + goto error_return; + xcoff_hash_table (info)->descriptor_section = dsec; + dsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + dsec->alignment_power = 2; + } + /* Likewise for the .debug section. */ + if (xcoff_hash_table (info)->debug_section == NULL) + { + asection *dsec; + + dsec = bfd_make_section_anyway (abfd, ".debug"); + if (dsec == NULL) + goto error_return; + xcoff_hash_table (info)->debug_section = dsec; + dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY; + } + + if ((abfd->flags & DYNAMIC) != 0 + && ! info->static_link) + return true; + + n_tmask = coff_data (abfd)->local_n_tmask; + n_btshft = coff_data (abfd)->local_n_btshft; + + /* Define macros so that ISFCN, et. al., macros work correctly. */ +#define N_TMASK n_tmask +#define N_BTSHFT n_btshft + + if (info->keep_memory) + default_copy = false; + else + default_copy = true; + + symcount = obj_raw_syment_count (abfd); + + /* We keep a list of the linker hash table entries that correspond + to each external symbol. */ + sym_hash = ((struct xcoff_link_hash_entry **) + bfd_alloc (abfd, + (symcount + * sizeof (struct xcoff_link_hash_entry *)))); + if (sym_hash == NULL && symcount != 0) + goto error_return; + coff_data (abfd)->sym_hashes = (struct coff_link_hash_entry **) sym_hash; + memset (sym_hash, 0, + (size_t) symcount * sizeof (struct xcoff_link_hash_entry *)); + + /* Because of the weird stuff we are doing with XCOFF csects, we can + not easily determine which section a symbol is in, so we store + the information in the tdata for the input file. */ + csect_cache = ((asection **) + bfd_alloc (abfd, symcount * sizeof (asection *))); + if (csect_cache == NULL && symcount != 0) + goto error_return; + xcoff_data (abfd)->csects = csect_cache; + memset (csect_cache, 0, (size_t) symcount * sizeof (asection *)); + + /* While splitting sections into csects, we need to assign the + relocs correctly. The relocs and the csects must both be in + order by VMA within a given section, so we handle this by + scanning along the relocs as we process the csects. We index + into reloc_info using the section target_index. */ + reloc_info = ((struct reloc_info_struct *) + bfd_malloc ((abfd->section_count + 1) + * sizeof (struct reloc_info_struct))); + if (reloc_info == NULL) + goto error_return; + memset ((PTR) reloc_info, 0, + (abfd->section_count + 1) * sizeof (struct reloc_info_struct)); + + /* Read in the relocs and line numbers for each section. */ + linesz = bfd_coff_linesz (abfd); + last_real = NULL; + for (o = abfd->sections; o != NULL; o = o->next) + { + last_real = o; + if ((o->flags & SEC_RELOC) != 0) + { + reloc_info[o->target_index].relocs = + xcoff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL, + false, (struct internal_reloc *) NULL); + reloc_info[o->target_index].csects = + (asection **) bfd_malloc (o->reloc_count * sizeof (asection *)); + if (reloc_info[o->target_index].csects == NULL) + goto error_return; + memset (reloc_info[o->target_index].csects, 0, + o->reloc_count * sizeof (asection *)); + } + + if ((info->strip == strip_none || info->strip == strip_some) + && o->lineno_count > 0) + { + bfd_byte *linenos; + + linenos = (bfd_byte *) bfd_malloc (o->lineno_count * linesz); + if (linenos == NULL) + goto error_return; + reloc_info[o->target_index].linenos = linenos; + if (bfd_seek (abfd, o->line_filepos, SEEK_SET) != 0 + || (bfd_read (linenos, linesz, o->lineno_count, abfd) + != linesz * o->lineno_count)) + goto error_return; + } + } + + /* Don't let the linker relocation routines discard the symbols. */ + keep_syms = obj_coff_keep_syms (abfd); + obj_coff_keep_syms (abfd) = true; + + csect = NULL; + csect_index = 0; + first_csect = NULL; + + symesz = bfd_coff_symesz (abfd); + BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); + esym = (bfd_byte *) obj_coff_external_syms (abfd); + esym_end = esym + symcount * symesz; + while (esym < esym_end) + { + struct internal_syment sym; + union internal_auxent aux; + const char *name; + char buf[SYMNMLEN + 1]; + int smtyp; + flagword flags; + asection *section; + bfd_vma value; + struct xcoff_link_hash_entry *set_toc; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); + + /* In this pass we are only interested in symbols with csect + information. */ + if (sym.n_sclass != C_EXT && sym.n_sclass != C_HIDEXT) + { + if (sym.n_sclass == C_FILE && csect != NULL) + { + xcoff_section_data (abfd, csect)->last_symndx = + ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz); + csect = NULL; + } + + if (csect != NULL) + *csect_cache = csect; + else if (first_csect == NULL || sym.n_sclass == C_FILE) + *csect_cache = coff_section_from_bfd_index (abfd, sym.n_scnum); + else + *csect_cache = NULL; + esym += (sym.n_numaux + 1) * symesz; + sym_hash += sym.n_numaux + 1; + csect_cache += sym.n_numaux + 1; + continue; + } + + name = _bfd_coff_internal_syment_name (abfd, &sym, buf); + if (name == NULL) + goto error_return; + + /* If this symbol has line number information attached to it, + and we're not stripping it, count the number of entries and + add them to the count for this csect. In the final link pass + we are going to attach line number information by symbol, + rather than by section, in order to more easily handle + garbage collection. */ + if ((info->strip == strip_none || info->strip == strip_some) + && sym.n_numaux > 1 + && csect != NULL + && ISFCN (sym.n_type)) + { + union internal_auxent auxlin; + + bfd_coff_swap_aux_in (abfd, (PTR) (esym + symesz), + sym.n_type, sym.n_sclass, + 0, sym.n_numaux, (PTR) &auxlin); + if (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0) + { + asection *enclosing; + bfd_size_type linoff; + + enclosing = xcoff_section_data (abfd, csect)->enclosing; + if (enclosing == NULL) + { + (*_bfd_error_handler) + ("%s: `%s' has line numbers but no enclosing section", + bfd_get_filename (abfd), name); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + linoff = (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr + - enclosing->line_filepos); + if (linoff < enclosing->lineno_count * linesz) + { + struct internal_lineno lin; + bfd_byte *linpstart; + + linpstart = (reloc_info[enclosing->target_index].linenos + + linoff); + bfd_coff_swap_lineno_in (abfd, (PTR) linpstart, (PTR) &lin); + if (lin.l_lnno == 0 + && ((bfd_size_type) lin.l_addr.l_symndx + == ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz))) + { + bfd_byte *linpend, *linp; + + linpend = (reloc_info[enclosing->target_index].linenos + + enclosing->lineno_count * linesz); + for (linp = linpstart + linesz; + linp < linpend; + linp += linesz) + { + bfd_coff_swap_lineno_in (abfd, (PTR) linp, + (PTR) &lin); + if (lin.l_lnno == 0) + break; + } + csect->lineno_count += (linp - linpstart) / linesz; + /* The setting of line_filepos will only be + useful if all the line number entries for a + csect are contiguous; this only matters for + error reporting. */ + if (csect->line_filepos == 0) + csect->line_filepos = + auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr; + } + } + } + } + + /* Pick up the csect auxiliary information. */ + + if (sym.n_numaux == 0) + { + (*_bfd_error_handler) + ("%s: class %d symbol `%s' has no aux entries", + bfd_get_filename (abfd), sym.n_sclass, name); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + bfd_coff_swap_aux_in (abfd, + (PTR) (esym + symesz * sym.n_numaux), + sym.n_type, sym.n_sclass, + sym.n_numaux - 1, sym.n_numaux, + (PTR) &aux); + + smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); + + flags = BSF_GLOBAL; + section = NULL; + value = 0; + set_toc = NULL; + + switch (smtyp) + { + default: + (*_bfd_error_handler) + ("%s: symbol `%s' has unrecognized csect type %d", + bfd_get_filename (abfd), name, smtyp); + bfd_set_error (bfd_error_bad_value); + goto error_return; + + case XTY_ER: + /* This is an external reference. */ + if (sym.n_sclass == C_HIDEXT + || sym.n_scnum != N_UNDEF + || aux.x_csect.x_scnlen.l != 0) + { + (*_bfd_error_handler) + ("%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d", + bfd_get_filename (abfd), name, sym.n_sclass, sym.n_scnum, + aux.x_csect.x_scnlen.l); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + /* An XMC_XO external reference is actually a reference to + an absolute location. */ + if (aux.x_csect.x_smclas != XMC_XO) + section = bfd_und_section_ptr; + else + { + section = bfd_abs_section_ptr; + value = sym.n_value; + } + break; + + case XTY_SD: + /* This is a csect definition. */ + + if (csect != NULL) + { + xcoff_section_data (abfd, csect)->last_symndx = + ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz); + } + + csect = NULL; + csect_index = -1; + + /* When we see a TOC anchor, we record the TOC value. */ + if (aux.x_csect.x_smclas == XMC_TC0) + { + if (sym.n_sclass != C_HIDEXT + || aux.x_csect.x_scnlen.l != 0) + { + (*_bfd_error_handler) + ("%s: XMC_TC0 symbol `%s' is class %d scnlen %d", + bfd_get_filename (abfd), name, sym.n_sclass, + aux.x_csect.x_scnlen.l); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + xcoff_data (abfd)->toc = sym.n_value; + } + + /* We must merge TOC entries for the same symbol. We can + merge two TOC entries if they are both C_HIDEXT, they + both have the same name, they are both 4 bytes long, and + they both have a relocation table entry for an external + symbol with the same name. Unfortunately, this means + that we must look through the relocations. Ick. */ + if (aux.x_csect.x_smclas == XMC_TC + && sym.n_sclass == C_HIDEXT + && aux.x_csect.x_scnlen.l == 4 + && info->hash->creator == abfd->xvec) + { + asection *enclosing; + struct internal_reloc *relocs; + bfd_size_type relindx; + struct internal_reloc *rel; + + enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum); + if (enclosing == NULL) + goto error_return; + + relocs = reloc_info[enclosing->target_index].relocs; + relindx = xcoff_find_reloc (relocs, enclosing->reloc_count, + sym.n_value); + rel = relocs + relindx; + if (relindx < enclosing->reloc_count + && rel->r_vaddr == (bfd_vma) sym.n_value + && rel->r_size == 31 + && rel->r_type == R_POS) + { + bfd_byte *erelsym; + struct internal_syment relsym; + + erelsym = ((bfd_byte *) obj_coff_external_syms (abfd) + + rel->r_symndx * symesz); + bfd_coff_swap_sym_in (abfd, (PTR) erelsym, (PTR) &relsym); + if (relsym.n_sclass == C_EXT) + { + const char *relname; + char relbuf[SYMNMLEN + 1]; + boolean copy; + struct xcoff_link_hash_entry *h; + + /* At this point we know that the TOC entry is + for an externally visible symbol. */ + relname = _bfd_coff_internal_syment_name (abfd, &relsym, + relbuf); + if (relname == NULL) + goto error_return; + + /* We only merge TOC entries if the TC name is + the same as the symbol name. This handles + the normal case, but not common cases like + SYM.P4 which gcc generates to store SYM + 4 + in the TOC. FIXME. */ + if (strcmp (name, relname) == 0) + { + copy = (! info->keep_memory + || relsym._n._n_n._n_zeroes != 0 + || relsym._n._n_n._n_offset == 0); + h = xcoff_link_hash_lookup (xcoff_hash_table (info), + relname, true, copy, + false); + if (h == NULL) + goto error_return; + + /* At this point h->root.type could be + bfd_link_hash_new. That should be OK, + since we know for sure that we will come + across this symbol as we step through the + file. */ + + /* We store h in *sym_hash for the + convenience of the relocate_section + function. */ + *sym_hash = h; + + if (h->toc_section != NULL) + { + asection **rel_csects; + + /* We already have a TOC entry for this + symbol, so we can just ignore this + one. */ + rel_csects = + reloc_info[enclosing->target_index].csects; + rel_csects[relindx] = bfd_und_section_ptr; + break; + } + + /* We are about to create a TOC entry for + this symbol. */ + set_toc = h; + } + } + } + } + + /* We need to create a new section. We get the name from + the csect storage mapping class, so that the linker can + accumulate similar csects together. */ + { + static const char *csect_name_by_class[] = + { + ".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo", + ".sv", ".bs", ".ds", ".uc", ".ti", ".tb", NULL, ".tc0", + ".td" + }; + const char *csect_name; + asection *enclosing; + + if ((aux.x_csect.x_smclas >= + sizeof csect_name_by_class / sizeof csect_name_by_class[0]) + || csect_name_by_class[aux.x_csect.x_smclas] == NULL) + { + (*_bfd_error_handler) + ("%s: symbol `%s' has unrecognized smclas %d", + bfd_get_filename (abfd), name, aux.x_csect.x_smclas); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + csect_name = csect_name_by_class[aux.x_csect.x_smclas]; + csect = bfd_make_section_anyway (abfd, csect_name); + if (csect == NULL) + goto error_return; + enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum); + if (enclosing == NULL) + goto error_return; + if (! bfd_is_abs_section (enclosing) + && ((bfd_vma) sym.n_value < enclosing->vma + || ((bfd_vma) sym.n_value + aux.x_csect.x_scnlen.l + > enclosing->vma + enclosing->_raw_size))) + { + (*_bfd_error_handler) + ("%s: csect `%s' not in enclosing section", + bfd_get_filename (abfd), name); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + csect->vma = sym.n_value; + csect->filepos = (enclosing->filepos + + sym.n_value + - enclosing->vma); + csect->_raw_size = aux.x_csect.x_scnlen.l; + csect->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; + csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); + + /* Record the enclosing section in the tdata for this new + section. */ + csect->used_by_bfd = + ((struct coff_section_tdata *) + bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); + if (csect->used_by_bfd == NULL) + goto error_return; + coff_section_data (abfd, csect)->tdata = + bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata)); + if (coff_section_data (abfd, csect)->tdata == NULL) + goto error_return; + xcoff_section_data (abfd, csect)->enclosing = enclosing; + xcoff_section_data (abfd, csect)->lineno_count = + enclosing->lineno_count; + + if (enclosing->owner == abfd) + { + struct internal_reloc *relocs; + bfd_size_type relindx; + struct internal_reloc *rel; + asection **rel_csect; + + relocs = reloc_info[enclosing->target_index].relocs; + relindx = xcoff_find_reloc (relocs, enclosing->reloc_count, + csect->vma); + rel = relocs + relindx; + rel_csect = (reloc_info[enclosing->target_index].csects + + relindx); + csect->rel_filepos = (enclosing->rel_filepos + + relindx * bfd_coff_relsz (abfd)); + while (relindx < enclosing->reloc_count + && *rel_csect == NULL + && rel->r_vaddr < csect->vma + csect->_raw_size) + { + *rel_csect = csect; + csect->flags |= SEC_RELOC; + ++csect->reloc_count; + ++relindx; + ++rel; + ++rel_csect; + } + } + + /* There are a number of other fields and section flags + which we do not bother to set. */ + + csect_index = ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz); + + xcoff_section_data (abfd, csect)->first_symndx = csect_index; + + if (first_csect == NULL) + first_csect = csect; + + /* If this symbol is C_EXT, we treat it as starting at the + beginning of the newly created section. */ + if (sym.n_sclass == C_EXT) + { + section = csect; + value = 0; + } + + /* If this is a TOC section for a symbol, record it. */ + if (set_toc != NULL) + set_toc->toc_section = csect; + } + break; + + case XTY_LD: + /* This is a label definition. The x_scnlen field is the + symbol index of the csect. I believe that this must + always follow the appropriate XTY_SD symbol, so I will + insist on it. */ + { + boolean bad; + + bad = false; + if (aux.x_csect.x_scnlen.l < 0 + || (aux.x_csect.x_scnlen.l + >= esym - (bfd_byte *) obj_coff_external_syms (abfd))) + bad = true; + if (! bad) + { + section = xcoff_data (abfd)->csects[aux.x_csect.x_scnlen.l]; + if (section == NULL + || (section->flags & SEC_HAS_CONTENTS) == 0) + bad = true; + } + if (bad) + { + (*_bfd_error_handler) + ("%s: misplaced XTY_LD `%s'", + bfd_get_filename (abfd), name); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + value = sym.n_value - csect->vma; + } + break; + + case XTY_CM: + /* This is an unitialized csect. We could base the name on + the storage mapping class, but we don't bother. If this + csect is externally visible, it is a common symbol. */ + + if (csect != NULL) + { + xcoff_section_data (abfd, csect)->last_symndx = + ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz); + } + + csect = bfd_make_section_anyway (abfd, ".bss"); + if (csect == NULL) + goto error_return; + csect->vma = sym.n_value; + csect->_raw_size = aux.x_csect.x_scnlen.l; + csect->flags |= SEC_ALLOC; + csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); + /* There are a number of other fields and section flags + which we do not bother to set. */ + + csect_index = ((esym + - (bfd_byte *) obj_coff_external_syms (abfd)) + / symesz); + + csect->used_by_bfd = + ((struct coff_section_tdata *) + bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); + if (csect->used_by_bfd == NULL) + goto error_return; + coff_section_data (abfd, csect)->tdata = + bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata)); + if (coff_section_data (abfd, csect)->tdata == NULL) + goto error_return; + xcoff_section_data (abfd, csect)->first_symndx = csect_index; + + if (first_csect == NULL) + first_csect = csect; + + if (sym.n_sclass == C_EXT) + { + csect->flags |= SEC_IS_COMMON; + csect->_raw_size = 0; + section = csect; + value = aux.x_csect.x_scnlen.l; + } + + break; + } + + /* Check for magic symbol names. */ + if ((smtyp == XTY_SD || smtyp == XTY_CM) + && aux.x_csect.x_smclas != XMC_TC) + { + int i; + + i = -1; + if (name[0] == '_') + { + if (strcmp (name, "_text") == 0) + i = 0; + else if (strcmp (name, "_etext") == 0) + i = 1; + else if (strcmp (name, "_data") == 0) + i = 2; + else if (strcmp (name, "_edata") == 0) + i = 3; + else if (strcmp (name, "_end") == 0) + i = 4; + } + else if (name[0] == 'e' && strcmp (name, "end") == 0) + i = 5; + + if (i != -1) + xcoff_hash_table (info)->special_sections[i] = csect; + } + + /* Now we have enough information to add the symbol to the + linker hash table. */ + + if (sym.n_sclass == C_EXT) + { + boolean copy; + + BFD_ASSERT (section != NULL); + + /* We must copy the name into memory if we got it from the + syment itself, rather than the string table. */ + copy = default_copy; + if (sym._n._n_n._n_zeroes != 0 + || sym._n._n_n._n_offset == 0) + copy = true; + + if (info->hash->creator == abfd->xvec) + { + /* If we are statically linking a shared object, it is + OK for symbol redefinitions to occur. I can't figure + out just what the XCOFF linker is doing, but + something like this is required for -bnso to work. */ + if (! bfd_is_und_section (section)) + *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info), + name, true, copy, false); + else + *sym_hash = ((struct xcoff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, name, + true, copy, false)); + if (*sym_hash == NULL) + goto error_return; + if (((*sym_hash)->root.type == bfd_link_hash_defined + || (*sym_hash)->root.type == bfd_link_hash_defweak) + && ! bfd_is_und_section (section) + && ! bfd_is_com_section (section)) + { + if ((abfd->flags & DYNAMIC) != 0) + { + section = bfd_und_section_ptr; + value = 0; + } + else if (((*sym_hash)->root.u.def.section->owner->flags + & DYNAMIC) != 0) + { + (*sym_hash)->root.type = bfd_link_hash_undefined; + (*sym_hash)->root.u.undef.abfd = + (*sym_hash)->root.u.def.section->owner; + } + } + } + + /* _bfd_generic_link_add_one_symbol may call the linker to + generate an error message, and the linker may try to read + the symbol table to give a good error. Right now, the + line numbers are in an inconsistent state, since they are + counted both in the real sections and in the new csects. + We need to leave the count in the real sections so that + the linker can report the line number of the error + correctly, so temporarily clobber the link to the csects + so that the linker will not try to read the line numbers + a second time from the csects. */ + BFD_ASSERT (last_real->next == first_csect); + last_real->next = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, flags, section, value, + (const char *) NULL, copy, true, + (struct bfd_link_hash_entry **) sym_hash))) + goto error_return; + last_real->next = first_csect; + + if (smtyp == XTY_CM) + { + if ((*sym_hash)->root.type != bfd_link_hash_common + || (*sym_hash)->root.u.c.p->section != csect) + { + /* We don't need the common csect we just created. */ + csect->_raw_size = 0; + } + else + { + (*sym_hash)->root.u.c.p->alignment_power + = csect->alignment_power; + } + } + + if (info->hash->creator == abfd->xvec) + { + int flag; + + if (smtyp == XTY_ER || smtyp == XTY_CM) + flag = XCOFF_REF_REGULAR; + else + flag = XCOFF_DEF_REGULAR; + (*sym_hash)->flags |= flag; + + if ((*sym_hash)->smclas == XMC_UA + || flag == XCOFF_DEF_REGULAR) + (*sym_hash)->smclas = aux.x_csect.x_smclas; + } + } + + *csect_cache = csect; + + esym += (sym.n_numaux + 1) * symesz; + sym_hash += sym.n_numaux + 1; + csect_cache += sym.n_numaux + 1; + } + + BFD_ASSERT (last_real == NULL || last_real->next == first_csect); + + /* Make sure that we have seen all the relocs. */ + for (o = abfd->sections; o != first_csect; o = o->next) + { + /* Reset the section size and the line numebr count, since the + data is now attached to the csects. Don't reset the size of + the .debug section, since we need to read it below in + bfd_xcoff_size_dynamic_sections. */ + if (strcmp (bfd_get_section_name (abfd, o), ".debug") != 0) + o->_raw_size = 0; + o->lineno_count = 0; + + if ((o->flags & SEC_RELOC) != 0) + { + bfd_size_type i; + struct internal_reloc *rel; + asection **rel_csect; + + rel = reloc_info[o->target_index].relocs; + rel_csect = reloc_info[o->target_index].csects; + for (i = 0; i < o->reloc_count; i++, rel++, rel_csect++) + { + if (*rel_csect == NULL) + { + (*_bfd_error_handler) + ("%s: reloc %s:%d not in csect", + bfd_get_filename (abfd), o->name, i); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + /* We identify all symbols which are called, so that we + can create glue code for calls to functions imported + from dynamic objects. */ + if (info->hash->creator == abfd->xvec + && *rel_csect != bfd_und_section_ptr + && (rel->r_type == R_BR + || rel->r_type == R_RBR) + && obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL) + { + struct xcoff_link_hash_entry *h; + + h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx]; + h->flags |= XCOFF_CALLED; + /* If the symbol name starts with a period, it is + the code of a function. If the symbol is + currently undefined, then add an undefined symbol + for the function descriptor. This should do no + harm, because any regular object that defines the + function should also define the function + descriptor. It helps, because it means that we + will identify the function descriptor with a + dynamic object if a dynamic object defines it. */ + if (h->root.root.string[0] == '.' + && h->descriptor == NULL) + { + struct xcoff_link_hash_entry *hds; + + hds = xcoff_link_hash_lookup (xcoff_hash_table (info), + h->root.root.string + 1, + true, false, true); + if (hds == NULL) + goto error_return; + if (hds->root.type == bfd_link_hash_new) + { + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, hds->root.root.string, + (flagword) 0, bfd_und_section_ptr, + (bfd_vma) 0, (const char *) NULL, false, + true, + (struct bfd_link_hash_entry **) &hds))) + goto error_return; + } + hds->flags |= XCOFF_DESCRIPTOR; + BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0 + && (h->flags & XCOFF_DESCRIPTOR) == 0); + hds->descriptor = h; + h->descriptor = hds; + } + } + } + + free (reloc_info[o->target_index].csects); + reloc_info[o->target_index].csects = NULL; + + /* Reset SEC_RELOC and the reloc_count, since the reloc + information is now attached to the csects. */ + o->flags &=~ SEC_RELOC; + o->reloc_count = 0; + + /* If we are not keeping memory, free the reloc information. */ + if (! info->keep_memory + && coff_section_data (abfd, o) != NULL + && coff_section_data (abfd, o)->relocs != NULL + && ! coff_section_data (abfd, o)->keep_relocs) + { + free (coff_section_data (abfd, o)->relocs); + coff_section_data (abfd, o)->relocs = NULL; + } + } + + /* Free up the line numbers. FIXME: We could cache these + somewhere for the final link, to avoid reading them again. */ + if (reloc_info[o->target_index].linenos != NULL) + { + free (reloc_info[o->target_index].linenos); + reloc_info[o->target_index].linenos = NULL; + } + } + + free (reloc_info); + + obj_coff_keep_syms (abfd) = keep_syms; + + return true; + + error_return: + if (reloc_info != NULL) + { + for (o = abfd->sections; o != NULL; o = o->next) + { + if (reloc_info[o->target_index].csects != NULL) + free (reloc_info[o->target_index].csects); + if (reloc_info[o->target_index].linenos != NULL) + free (reloc_info[o->target_index].linenos); + } + free (reloc_info); + } + obj_coff_keep_syms (abfd) = keep_syms; + return false; +} + +#undef N_TMASK +#undef N_BTSHFT + +/* This function is used to add symbols from a dynamic object to the + global symbol table. */ + +static boolean +xcoff_link_add_dynamic_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *lsec; + bfd_byte *buf = NULL; + struct internal_ldhdr ldhdr; + const char *strings; + struct external_ldsym *elsym, *elsymend; + struct xcoff_import_file *n; + const char *bname; + const char *mname; + const char *s; + unsigned int c; + struct xcoff_import_file **pp; + + /* We can only handle a dynamic object if we are generating an XCOFF + output file. */ + if (info->hash->creator != abfd->xvec) + { + (*_bfd_error_handler) + ("%s: XCOFF shared object when not producing XCOFF output", + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + /* The symbols we use from a dynamic object are not the symbols in + the normal symbol table, but, rather, the symbols in the export + table. If there is a global symbol in a dynamic object which is + not in the export table, the loader will not be able to find it, + so we don't want to find it either. Also, on AIX 4.1.3, shr.o in + libc.a has symbols in the export table which are not in the + symbol table. */ + + /* Read in the .loader section. FIXME: We should really use the + o_snloader field in the a.out header, rather than grabbing the + section by name. */ + lsec = bfd_get_section_by_name (abfd, ".loader"); + if (lsec == NULL) + { + (*_bfd_error_handler) + ("%s: dynamic object with no .loader section", + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_no_symbols); + goto error_return; + } + + buf = (bfd_byte *) bfd_malloc (lsec->_raw_size); + if (buf == NULL && lsec->_raw_size > 0) + goto error_return; + + if (! bfd_get_section_contents (abfd, lsec, (PTR) buf, (file_ptr) 0, + lsec->_raw_size)) + goto error_return; + + /* Remove the sections from this object, so that they do not get + included in the link. */ + abfd->sections = NULL; + + xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr); + + strings = (char *) buf + ldhdr.l_stoff; + + elsym = (struct external_ldsym *) (buf + LDHDRSZ); + elsymend = elsym + ldhdr.l_nsyms; + BFD_ASSERT (sizeof (struct external_ldsym) == LDSYMSZ); + for (; elsym < elsymend; elsym++) + { + struct internal_ldsym ldsym; + char nambuf[SYMNMLEN + 1]; + const char *name; + struct xcoff_link_hash_entry *h; + + xcoff_swap_ldsym_in (abfd, elsym, &ldsym); + + /* We are only interested in exported symbols. */ + if ((ldsym.l_smtype & L_EXPORT) == 0) + continue; + + if (ldsym._l._l_l._l_zeroes == 0) + name = strings + ldsym._l._l_l._l_offset; + else + { + memcpy (nambuf, ldsym._l._l_name, SYMNMLEN); + nambuf[SYMNMLEN] = '\0'; + name = nambuf; + } + + /* Normally we could not call xcoff_link_hash_lookup in an add + symbols routine, since we might not be using an XCOFF hash + table. However, we verified above that we are using an XCOFF + hash table. */ + + h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, + true, true); + if (h == NULL) + goto error_return; + + h->flags |= XCOFF_DEF_DYNAMIC; + + /* If the symbol is undefined, and the BFD it was found in is + not a dynamic object, change the BFD to this dynamic object, + so that we can get the correct import file ID. */ + if ((h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + && (h->root.u.undef.abfd == NULL + || (h->root.u.undef.abfd->flags & DYNAMIC) == 0)) + h->root.u.undef.abfd = abfd; + + if (h->root.type == bfd_link_hash_new) + { + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = abfd; + /* We do not want to add this to the undefined symbol list. */ + } + + if (h->smclas == XMC_UA + || h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + h->smclas = ldsym.l_smclas; + + /* Unless this is an XMC_XO symbol, we don't bother to actually + define it, since we don't have a section to put it in anyhow. + Instead, the relocation routines handle the DEF_DYNAMIC flag + correctly. */ + + if (h->smclas == XMC_XO + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + { + /* This symbol has an absolute value. */ + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = bfd_abs_section_ptr; + h->root.u.def.value = ldsym.l_value; + } + } + + if (buf != NULL) + { + free (buf); + buf = NULL; + } + + /* Record this file in the import files. */ + + n = ((struct xcoff_import_file *) + bfd_alloc (abfd, sizeof (struct xcoff_import_file))); + if (n == NULL) + goto error_return; + n->next = NULL; + + /* For some reason, the path entry in the import file list for a + shared object appears to always be empty. The file name is the + base name. */ + n->path = ""; + if (abfd->my_archive == NULL) + { + bname = bfd_get_filename (abfd); + mname = ""; + } + else + { + bname = bfd_get_filename (abfd->my_archive); + mname = bfd_get_filename (abfd); + } + s = strrchr (bname, '/'); + if (s != NULL) + bname = s + 1; + n->file = bname; + n->member = mname; + + /* We start c at 1 because the first import file number is reserved + for LIBPATH. */ + for (pp = &xcoff_hash_table (info)->imports, c = 1; + *pp != NULL; + pp = &(*pp)->next, ++c) + ; + *pp = n; + + xcoff_data (abfd)->import_file_id = c; + + return true; + + error_return: + if (buf != NULL) + free (buf); + return false; +} + +/* Routines that are called after all the input files have been + handled, but before the sections are laid out in memory. */ + +/* Mark a symbol as not being garbage, including the section in which + it is defined. */ + +static INLINE boolean +xcoff_mark_symbol (info, h) + struct bfd_link_info *info; + struct xcoff_link_hash_entry *h; +{ + if ((h->flags & XCOFF_MARK) != 0) + return true; + + h->flags |= XCOFF_MARK; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *hsec; + + hsec = h->root.u.def.section; + if ((hsec->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, hsec)) + return false; + } + } + + if (h->toc_section != NULL + && (h->toc_section->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, h->toc_section)) + return false; + } + + return true; +} + +/* The mark phase of garbage collection. For a given section, mark + it, and all the sections which define symbols to which it refers. + Because this function needs to look at the relocs, we also count + the number of relocs which need to be copied into the .loader + section. */ + +static boolean +xcoff_mark (info, sec) + struct bfd_link_info *info; + asection *sec; +{ + if ((sec->flags & SEC_MARK) != 0) + return true; + + sec->flags |= SEC_MARK; + + if (sec->owner->xvec == info->hash->creator + && coff_section_data (sec->owner, sec) != NULL + && xcoff_section_data (sec->owner, sec) != NULL) + { + register struct xcoff_link_hash_entry **hp, **hpend; + struct internal_reloc *rel, *relend; + + /* Mark all the symbols in this section. */ + + hp = (obj_xcoff_sym_hashes (sec->owner) + + xcoff_section_data (sec->owner, sec)->first_symndx); + hpend = (obj_xcoff_sym_hashes (sec->owner) + + xcoff_section_data (sec->owner, sec)->last_symndx); + for (; hp < hpend; hp++) + { + register struct xcoff_link_hash_entry *h; + + h = *hp; + if (h != NULL + && (h->flags & XCOFF_MARK) == 0) + { + if (! xcoff_mark_symbol (info, h)) + return false; + } + } + + /* Look through the section relocs. */ + + if ((sec->flags & SEC_RELOC) != 0 + && sec->reloc_count > 0) + { + rel = xcoff_read_internal_relocs (sec->owner, sec, true, + (bfd_byte *) NULL, false, + (struct internal_reloc *) NULL); + if (rel == NULL) + return false; + relend = rel + sec->reloc_count; + for (; rel < relend; rel++) + { + asection *rsec; + struct xcoff_link_hash_entry *h; + + if ((unsigned int) rel->r_symndx + > obj_raw_syment_count (sec->owner)) + continue; + + h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx]; + if (h != NULL + && (h->flags & XCOFF_MARK) == 0) + { + if (! xcoff_mark_symbol (info, h)) + return false; + } + + rsec = xcoff_data (sec->owner)->csects[rel->r_symndx]; + if (rsec != NULL + && (rsec->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, rsec)) + return false; + } + + /* See if this reloc needs to be copied into the .loader + section. */ + switch (rel->r_type) + { + default: + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common + || ((h->flags & XCOFF_CALLED) != 0 + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + && h->root.root.string[0] == '.' + && h->descriptor != NULL + && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0 + || info->shared + || ((h->descriptor->flags & XCOFF_IMPORT) != 0 + && (h->descriptor->flags + & XCOFF_DEF_REGULAR) == 0)))) + break; + /* Fall through. */ + case R_POS: + case R_NEG: + case R_RL: + case R_RLA: + ++xcoff_hash_table (info)->ldrel_count; + if (h != NULL) + h->flags |= XCOFF_LDREL; + break; + case R_TOC: + case R_GL: + case R_TCL: + case R_TRL: + case R_TRLA: + /* We should never need a .loader reloc for a TOC + relative reloc. */ + break; + } + } + + if (! info->keep_memory + && coff_section_data (sec->owner, sec) != NULL + && coff_section_data (sec->owner, sec)->relocs != NULL + && ! coff_section_data (sec->owner, sec)->keep_relocs) + { + free (coff_section_data (sec->owner, sec)->relocs); + coff_section_data (sec->owner, sec)->relocs = NULL; + } + } + } + + return true; +} + +/* The sweep phase of garbage collection. Remove all garbage + sections. */ + +static void +xcoff_sweep (info) + struct bfd_link_info *info; +{ + bfd *sub; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + for (o = sub->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_MARK) == 0) + { + /* Keep all sections from non-XCOFF input files. Keep + special sections. Keep .debug sections for the + moment. */ + if (sub->xvec != info->hash->creator + || o == xcoff_hash_table (info)->debug_section + || o == xcoff_hash_table (info)->loader_section + || o == xcoff_hash_table (info)->linkage_section + || o == xcoff_hash_table (info)->toc_section + || o == xcoff_hash_table (info)->descriptor_section + || strcmp (o->name, ".debug") == 0) + o->flags |= SEC_MARK; + else + { + o->_raw_size = 0; + o->reloc_count = 0; + o->lineno_count = 0; + } + } + } + } +} + +/* Record the number of elements in a set. This is used to output the + correct csect length. */ + +boolean +bfd_xcoff_link_record_set (output_bfd, info, harg, size) + bfd *output_bfd; + struct bfd_link_info *info; + struct bfd_link_hash_entry *harg; + bfd_size_type size; +{ + struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg; + struct xcoff_link_size_list *n; + + if (! XCOFF_XVECP (output_bfd->xvec)) + return true; + + /* This will hardly ever be called. I don't want to burn four bytes + per global symbol, so instead the size is kept on a linked list + attached to the hash table. */ + + n = ((struct xcoff_link_size_list *) + bfd_alloc (output_bfd, sizeof (struct xcoff_link_size_list))); + if (n == NULL) + return false; + n->next = xcoff_hash_table (info)->size_list; + n->h = h; + n->size = size; + xcoff_hash_table (info)->size_list = n; + + h->flags |= XCOFF_HAS_SIZE; + + return true; +} + +/* Import a symbol. */ + +boolean +bfd_xcoff_import_symbol (output_bfd, info, harg, val, imppath, impfile, + impmember) + bfd *output_bfd; + struct bfd_link_info *info; + struct bfd_link_hash_entry *harg; + bfd_vma val; + const char *imppath; + const char *impfile; + const char *impmember; +{ + struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg; + + if (! XCOFF_XVECP (output_bfd->xvec)) + return true; + + h->flags |= XCOFF_IMPORT; + + if (val != (bfd_vma) -1) + { + if (h->root.type == bfd_link_hash_defined + && (! bfd_is_abs_section (h->root.u.def.section) + || h->root.u.def.value != val)) + { + if (! ((*info->callbacks->multiple_definition) + (info, h->root.root.string, h->root.u.def.section->owner, + h->root.u.def.section, h->root.u.def.value, + output_bfd, bfd_abs_section_ptr, val))) + return false; + } + + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = bfd_abs_section_ptr; + h->root.u.def.value = val; + } + + if (h->ldsym == NULL) + { + h->ldsym = ((struct internal_ldsym *) + bfd_zalloc (output_bfd, sizeof (struct internal_ldsym))); + if (h->ldsym == NULL) + return false; + } + + if (imppath == NULL) + h->ldsym->l_ifile = (bfd_size_type) -1; + else + { + unsigned int c; + struct xcoff_import_file **pp; + + /* We start c at 1 because the first entry in the import list is + reserved for the library search path. */ + for (pp = &xcoff_hash_table (info)->imports, c = 1; + *pp != NULL; + pp = &(*pp)->next, ++c) + { + if (strcmp ((*pp)->path, imppath) == 0 + && strcmp ((*pp)->file, impfile) == 0 + && strcmp ((*pp)->member, impmember) == 0) + break; + } + + if (*pp == NULL) + { + struct xcoff_import_file *n; + + n = ((struct xcoff_import_file *) + bfd_alloc (output_bfd, sizeof (struct xcoff_import_file))); + if (n == NULL) + return false; + n->next = NULL; + n->path = imppath; + n->file = impfile; + n->member = impmember; + *pp = n; + } + + h->ldsym->l_ifile = c; + } + + return true; +} + +/* Export a symbol. */ + +boolean +bfd_xcoff_export_symbol (output_bfd, info, harg, syscall) + bfd *output_bfd; + struct bfd_link_info *info; + struct bfd_link_hash_entry *harg; + boolean syscall; +{ + struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg; + + if (! XCOFF_XVECP (output_bfd->xvec)) + return true; + + h->flags |= XCOFF_EXPORT; + + /* FIXME: I'm not at all sure what syscall is supposed to mean, so + I'm just going to ignore it until somebody explains it. */ + + /* See if this is a function descriptor. It may be one even though + it is not so marked. */ + if ((h->flags & XCOFF_DESCRIPTOR) == 0 + && h->root.root.string[0] != '.') + { + char *fnname; + struct xcoff_link_hash_entry *hfn; + + fnname = (char *) bfd_malloc (strlen (h->root.root.string) + 2); + if (fnname == NULL) + return false; + fnname[0] = '.'; + strcpy (fnname + 1, h->root.root.string); + hfn = xcoff_link_hash_lookup (xcoff_hash_table (info), + fnname, false, false, true); + free (fnname); + if (hfn != NULL + && hfn->smclas == XMC_PR + && (hfn->root.type == bfd_link_hash_defined + || hfn->root.type == bfd_link_hash_defweak)) + { + h->flags |= XCOFF_DESCRIPTOR; + h->descriptor = hfn; + hfn->descriptor = h; + } + } + + /* Make sure we don't garbage collect this symbol. */ + if (! xcoff_mark_symbol (info, h)) + return false; + + /* If this is a function descriptor, make sure we don't garbage + collect the associated function code. We normally don't have to + worry about this, because the descriptor will be attached to a + section with relocs, but if we are creating the descriptor + ourselves those relocs will not be visible to the mark code. */ + if ((h->flags & XCOFF_DESCRIPTOR) != 0) + { + if (! xcoff_mark_symbol (info, h->descriptor)) + return false; + } + + return true; +} + +/* Count a reloc against a symbol. This is called for relocs + generated by the linker script, typically for global constructors + and destructors. */ + +boolean +bfd_xcoff_link_count_reloc (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct xcoff_link_hash_entry *h; + + if (! XCOFF_XVECP (output_bfd->xvec)) + return true; + + h = ((struct xcoff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, name, false, false, + false)); + if (h == NULL) + { + (*_bfd_error_handler) ("%s: no such symbol", name); + bfd_set_error (bfd_error_no_symbols); + return false; + } + + h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL; + ++xcoff_hash_table (info)->ldrel_count; + + /* Mark the symbol to avoid garbage collection. */ + if (! xcoff_mark_symbol (info, h)) + return false; + + return true; +} + +/* This function is called for each symbol to which the linker script + assigns a value. */ + +boolean +bfd_xcoff_record_link_assignment (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct xcoff_link_hash_entry *h; + + if (! XCOFF_XVECP (output_bfd->xvec)) + return true; + + h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, true, + false); + if (h == NULL) + return false; + + h->flags |= XCOFF_DEF_REGULAR; + + return true; +} + +/* This structure is used to pass information through + xcoff_link_hash_traverse. */ + +struct xcoff_loader_info +{ + /* Set if a problem occurred. */ + boolean failed; + /* Output BFD. */ + bfd *output_bfd; + /* Link information structure. */ + struct bfd_link_info *info; + /* Whether all defined symbols should be exported. */ + boolean export_defineds; + /* Number of ldsym structures. */ + size_t ldsym_count; + /* Size of string table. */ + size_t string_size; + /* String table. */ + bfd_byte *strings; + /* Allocated size of string table. */ + size_t string_alc; +}; + +/* Build the .loader section. This is called by the XCOFF linker + emulation before_allocation routine. We must set the size of the + .loader section before the linker lays out the output file. + LIBPATH is the library path to search for shared objects; this is + normally built from the -L arguments passed to the linker. ENTRY + is the name of the entry point symbol (the -e linker option). + FILE_ALIGN is the alignment to use for sections within the file + (the -H linker option). MAXSTACK is the maximum stack size (the + -bmaxstack linker option). MAXDATA is the maximum data size (the + -bmaxdata linker option). GC is whether to do garbage collection + (the -bgc linker option). MODTYPE is the module type (the + -bmodtype linker option). TEXTRO is whether the text section must + be read only (the -btextro linker option). EXPORT_DEFINEDS is + whether all defined symbols should be exported (the -unix linker + option). SPECIAL_SECTIONS is set by this routine to csects with + magic names like _end. */ + +boolean +bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry, + file_align, maxstack, maxdata, gc, + modtype, textro, export_defineds, + special_sections) + bfd *output_bfd; + struct bfd_link_info *info; + const char *libpath; + const char *entry; + unsigned long file_align; + unsigned long maxstack; + unsigned long maxdata; + boolean gc; + int modtype; + boolean textro; + boolean export_defineds; + asection **special_sections; +{ + struct xcoff_link_hash_entry *hentry; + asection *lsec; + struct xcoff_loader_info ldinfo; + int i; + size_t impsize, impcount; + struct xcoff_import_file *fl; + struct internal_ldhdr *ldhdr; + bfd_size_type stoff; + register char *out; + asection *sec; + bfd *sub; + struct bfd_strtab_hash *debug_strtab; + bfd_byte *debug_contents = NULL; + + if (! XCOFF_XVECP (output_bfd->xvec)) + { + for (i = 0; i < 6; i++) + special_sections[i] = NULL; + return true; + } + + ldinfo.failed = false; + ldinfo.output_bfd = output_bfd; + ldinfo.info = info; + ldinfo.export_defineds = export_defineds; + ldinfo.ldsym_count = 0; + ldinfo.string_size = 0; + ldinfo.strings = NULL; + ldinfo.string_alc = 0; + + xcoff_data (output_bfd)->maxstack = maxstack; + xcoff_data (output_bfd)->maxdata = maxdata; + xcoff_data (output_bfd)->modtype = modtype; + + xcoff_hash_table (info)->file_align = file_align; + xcoff_hash_table (info)->textro = textro; + + hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry, + false, false, true); + if (hentry != NULL) + hentry->flags |= XCOFF_ENTRY; + + /* Garbage collect unused sections. */ + if (info->relocateable + || ! gc + || hentry == NULL + || (hentry->root.type != bfd_link_hash_defined + && hentry->root.type != bfd_link_hash_defweak)) + { + gc = false; + xcoff_hash_table (info)->gc = false; + + /* We still need to call xcoff_mark, in order to set ldrel_count + correctly. */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + for (o = sub->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, o)) + goto error_return; + } + } + } + } + else + { + if (! xcoff_mark (info, hentry->root.u.def.section)) + goto error_return; + xcoff_sweep (info); + xcoff_hash_table (info)->gc = true; + } + + /* Return special sections to the caller. */ + for (i = 0; i < 6; i++) + { + asection *sec; + + sec = xcoff_hash_table (info)->special_sections[i]; + if (sec != NULL + && gc + && (sec->flags & SEC_MARK) == 0) + sec = NULL; + special_sections[i] = sec; + } + + if (info->input_bfds == NULL) + { + /* I'm not sure what to do in this bizarre case. */ + return true; + } + + xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_build_ldsyms, + (PTR) &ldinfo); + if (ldinfo.failed) + goto error_return; + + /* Work out the size of the import file names. Each import file ID + consists of three null terminated strings: the path, the file + name, and the archive member name. The first entry in the list + of names is the path to use to find objects, which the linker has + passed in as the libpath argument. For some reason, the path + entry in the other import file names appears to always be empty. */ + impsize = strlen (libpath) + 3; + impcount = 1; + for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next) + { + ++impcount; + impsize += (strlen (fl->path) + + strlen (fl->file) + + strlen (fl->member) + + 3); + } + + /* Set up the .loader section header. */ + ldhdr = &xcoff_hash_table (info)->ldhdr; + ldhdr->l_version = 1; + ldhdr->l_nsyms = ldinfo.ldsym_count; + ldhdr->l_nreloc = xcoff_hash_table (info)->ldrel_count; + ldhdr->l_istlen = impsize; + ldhdr->l_nimpid = impcount; + ldhdr->l_impoff = (LDHDRSZ + + ldhdr->l_nsyms * LDSYMSZ + + ldhdr->l_nreloc * LDRELSZ); + ldhdr->l_stlen = ldinfo.string_size; + stoff = ldhdr->l_impoff + impsize; + if (ldinfo.string_size == 0) + ldhdr->l_stoff = 0; + else + ldhdr->l_stoff = stoff; + + /* We now know the final size of the .loader section. Allocate + space for it. */ + lsec = xcoff_hash_table (info)->loader_section; + lsec->_raw_size = stoff + ldhdr->l_stlen; + lsec->contents = (bfd_byte *) bfd_zalloc (output_bfd, lsec->_raw_size); + if (lsec->contents == NULL) + goto error_return; + + /* Set up the header. */ + xcoff_swap_ldhdr_out (output_bfd, ldhdr, + (struct external_ldhdr *) lsec->contents); + + /* Set up the import file names. */ + out = (char *) lsec->contents + ldhdr->l_impoff; + strcpy (out, libpath); + out += strlen (libpath) + 1; + *out++ = '\0'; + *out++ = '\0'; + for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next) + { + register const char *s; + + s = fl->path; + while ((*out++ = *s++) != '\0') + ; + s = fl->file; + while ((*out++ = *s++) != '\0') + ; + s = fl->member; + while ((*out++ = *s++) != '\0') + ; + } + + BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff); + + /* Set up the symbol string table. */ + if (ldinfo.string_size > 0) + { + memcpy (out, ldinfo.strings, ldinfo.string_size); + free (ldinfo.strings); + ldinfo.strings = NULL; + } + + /* We can't set up the symbol table or the relocs yet, because we + don't yet know the final position of the various sections. The + .loader symbols are written out when the corresponding normal + symbols are written out in xcoff_link_input_bfd or + xcoff_write_global_symbol. The .loader relocs are written out + when the corresponding normal relocs are handled in + xcoff_link_input_bfd. */ + + /* Allocate space for the magic sections. */ + sec = xcoff_hash_table (info)->linkage_section; + if (sec->_raw_size > 0) + { + sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size); + if (sec->contents == NULL) + goto error_return; + } + sec = xcoff_hash_table (info)->toc_section; + if (sec->_raw_size > 0) + { + sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size); + if (sec->contents == NULL) + goto error_return; + } + sec = xcoff_hash_table (info)->descriptor_section; + if (sec->_raw_size > 0) + { + sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size); + if (sec->contents == NULL) + goto error_return; + } + + /* Now that we've done garbage collection, figure out the contents + of the .debug section. */ + debug_strtab = xcoff_hash_table (info)->debug_strtab; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *subdeb; + bfd_size_type symcount; + unsigned long *debug_index; + asection **csectpp; + bfd_byte *esym, *esymend; + bfd_size_type symesz; + + if (sub->xvec != info->hash->creator) + continue; + subdeb = bfd_get_section_by_name (sub, ".debug"); + if (subdeb == NULL || subdeb->_raw_size == 0) + continue; + + if (info->strip == strip_all + || info->strip == strip_debugger + || info->discard == discard_all) + { + subdeb->_raw_size = 0; + continue; + } + + if (! _bfd_coff_get_external_symbols (sub)) + goto error_return; + + symcount = obj_raw_syment_count (sub); + debug_index = ((unsigned long *) + bfd_zalloc (sub, symcount * sizeof (unsigned long))); + if (debug_index == NULL) + goto error_return; + xcoff_data (sub)->debug_indices = debug_index; + + /* Grab the contents of the .debug section. We use malloc and + copy the neams into the debug stringtab, rather than + bfd_alloc, because I expect that, when linking many files + together, many of the strings will be the same. Storing the + strings in the hash table should save space in this case. */ + debug_contents = (bfd_byte *) bfd_malloc (subdeb->_raw_size); + if (debug_contents == NULL) + goto error_return; + if (! bfd_get_section_contents (sub, subdeb, (PTR) debug_contents, + (file_ptr) 0, subdeb->_raw_size)) + goto error_return; + + csectpp = xcoff_data (sub)->csects; + + symesz = bfd_coff_symesz (sub); + esym = (bfd_byte *) obj_coff_external_syms (sub); + esymend = esym + symcount * symesz; + while (esym < esymend) + { + struct internal_syment sym; + + bfd_coff_swap_sym_in (sub, (PTR) esym, (PTR) &sym); + + *debug_index = (unsigned long) -1; + + if (sym._n._n_n._n_zeroes == 0 + && *csectpp != NULL + && (! gc + || ((*csectpp)->flags & SEC_MARK) != 0 + || *csectpp == bfd_abs_section_ptr) + && bfd_coff_symname_in_debug (sub, &sym)) + { + char *name; + bfd_size_type indx; + + name = (char *) debug_contents + sym._n._n_n._n_offset; + indx = _bfd_stringtab_add (debug_strtab, name, true, true); + if (indx == (bfd_size_type) -1) + goto error_return; + *debug_index = indx; + } + + esym += (sym.n_numaux + 1) * symesz; + csectpp += sym.n_numaux + 1; + debug_index += sym.n_numaux + 1; + } + + free (debug_contents); + debug_contents = NULL; + + /* Clear the size of subdeb, so that it is not included directly + in the output file. */ + subdeb->_raw_size = 0; + + if (! info->keep_memory) + { + if (! _bfd_coff_free_symbols (sub)) + goto error_return; + } + } + + xcoff_hash_table (info)->debug_section->_raw_size = + _bfd_stringtab_size (debug_strtab); + + return true; + + error_return: + if (ldinfo.strings != NULL) + free (ldinfo.strings); + if (debug_contents != NULL) + free (debug_contents); + return false; +} + +/* Add a symbol to the .loader symbols, if necessary. */ + +static boolean +xcoff_build_ldsyms (h, p) + struct xcoff_link_hash_entry *h; + PTR p; +{ + struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p; + size_t len; + + /* If all defined symbols should be exported, mark them now. */ + if (ldinfo->export_defineds + && (h->flags & XCOFF_DEF_REGULAR) != 0) + h->flags |= XCOFF_EXPORT; + + /* We don't want to garbage collect symbols which are not defined in + XCOFF files. This is a convenient place to mark them. */ + if (xcoff_hash_table (ldinfo->info)->gc + && (h->flags & XCOFF_MARK) == 0 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section->owner == NULL + || (h->root.u.def.section->owner->xvec + != ldinfo->info->hash->creator))) + h->flags |= XCOFF_MARK; + + /* If this symbol is called and defined in a dynamic object, or not + defined at all when building a shared object, or imported, then + we need to set up global linkage code for it. (Unless we did + garbage collection and we didn't need this symbol.) */ + if ((h->flags & XCOFF_CALLED) != 0 + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + && h->root.root.string[0] == '.' + && h->descriptor != NULL + && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0 + || ldinfo->info->shared + || ((h->descriptor->flags & XCOFF_IMPORT) != 0 + && (h->descriptor->flags & XCOFF_DEF_REGULAR) == 0)) + && (! xcoff_hash_table (ldinfo->info)->gc + || (h->flags & XCOFF_MARK) != 0)) + { + asection *sec; + struct xcoff_link_hash_entry *hds; + + sec = xcoff_hash_table (ldinfo->info)->linkage_section; + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = sec; + h->root.u.def.value = sec->_raw_size; + h->smclas = XMC_GL; + h->flags |= XCOFF_DEF_REGULAR; + sec->_raw_size += XCOFF_GLINK_SIZE; + + /* The global linkage code requires a TOC entry for the + descriptor. */ + hds = h->descriptor; + BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined + || hds->root.type == bfd_link_hash_undefweak) + && (hds->flags & XCOFF_DEF_REGULAR) == 0); + hds->flags |= XCOFF_MARK; + if (hds->toc_section == NULL) + { + hds->toc_section = xcoff_hash_table (ldinfo->info)->toc_section; + hds->u.toc_offset = hds->toc_section->_raw_size; + hds->toc_section->_raw_size += 4; + ++xcoff_hash_table (ldinfo->info)->ldrel_count; + ++hds->toc_section->reloc_count; + hds->indx = -2; + hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL; + + /* We need to call xcoff_build_ldsyms recursively here, + because we may already have passed hds on the traversal. */ + xcoff_build_ldsyms (hds, p); + } + } + + /* If this symbol is exported, but not defined, we need to try to + define it. */ + if ((h->flags & XCOFF_EXPORT) != 0 + && (h->flags & XCOFF_IMPORT) == 0 + && (h->flags & XCOFF_DEF_REGULAR) == 0 + && (h->flags & XCOFF_DEF_DYNAMIC) == 0 + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + { + if ((h->flags & XCOFF_DESCRIPTOR) != 0 + && (h->descriptor->root.type == bfd_link_hash_defined + || h->descriptor->root.type == bfd_link_hash_defweak)) + { + asection *sec; + + /* This is an undefined function descriptor associated with + a defined entry point. We can build up a function + descriptor ourselves. Believe it or not, the AIX linker + actually does this, and there are cases where we need to + do it as well. */ + sec = xcoff_hash_table (ldinfo->info)->descriptor_section; + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = sec; + h->root.u.def.value = sec->_raw_size; + h->smclas = XMC_DS; + h->flags |= XCOFF_DEF_REGULAR; + sec->_raw_size += 12; + + /* A function descriptor uses two relocs: one for the + associated code, and one for the TOC address. */ + xcoff_hash_table (ldinfo->info)->ldrel_count += 2; + sec->reloc_count += 2; + + /* We handle writing out the contents of the descriptor in + xcoff_write_global_symbol. */ + } + else + { + (*_bfd_error_handler) + ("attempt to export undefined symbol `%s'", + h->root.root.string); + ldinfo->failed = true; + bfd_set_error (bfd_error_invalid_operation); + return false; + } + } + + /* If this is still a common symbol, and it wasn't garbage + collected, we need to actually allocate space for it in the .bss + section. */ + if (h->root.type == bfd_link_hash_common + && (! xcoff_hash_table (ldinfo->info)->gc + || (h->flags & XCOFF_MARK) != 0) + && h->root.u.c.p->section->_raw_size == 0) + { + BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section)); + h->root.u.c.p->section->_raw_size = h->root.u.c.size; + } + + /* We need to add a symbol to the .loader section if it is mentioned + in a reloc which we are copying to the .loader section and it was + not defined or common, or if it is the entry point, or if it is + being exported. */ + + if (((h->flags & XCOFF_LDREL) == 0 + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) + && (h->flags & XCOFF_ENTRY) == 0 + && (h->flags & XCOFF_EXPORT) == 0) + { + h->ldsym = NULL; + return true; + } + + /* We don't need to add this symbol if we did garbage collection and + we did not mark this symbol. */ + if (xcoff_hash_table (ldinfo->info)->gc + && (h->flags & XCOFF_MARK) == 0) + { + h->ldsym = NULL; + return true; + } + + /* We may have already processed this symbol due to the recursive + call above. */ + if ((h->flags & XCOFF_BUILT_LDSYM) != 0) + return true; + + /* We need to add this symbol to the .loader symbols. */ + + /* h->ldsym will already have been allocated for an explicitly + imported symbol. */ + if (h->ldsym == NULL) + { + h->ldsym = ((struct internal_ldsym *) + bfd_zalloc (ldinfo->output_bfd, + sizeof (struct internal_ldsym))); + if (h->ldsym == NULL) + { + ldinfo->failed = true; + return false; + } + } + + /* The first 3 symbol table indices are reserved to indicate the + sections. */ + h->ldindx = ldinfo->ldsym_count + 3; + + ++ldinfo->ldsym_count; + + len = strlen (h->root.root.string); + if (len <= SYMNMLEN) + strncpy (h->ldsym->_l._l_name, h->root.root.string, SYMNMLEN); + else + { + if (ldinfo->string_size + len + 3 > ldinfo->string_alc) + { + size_t newalc; + bfd_byte *newstrings; + + newalc = ldinfo->string_alc * 2; + if (newalc == 0) + newalc = 32; + while (ldinfo->string_size + len + 3 > newalc) + newalc *= 2; + + newstrings = ((bfd_byte *) + bfd_realloc ((PTR) ldinfo->strings, newalc)); + if (newstrings == NULL) + { + ldinfo->failed = true; + return false; + } + ldinfo->string_alc = newalc; + ldinfo->strings = newstrings; + } + + bfd_put_16 (ldinfo->output_bfd, len + 1, + ldinfo->strings + ldinfo->string_size); + strcpy (ldinfo->strings + ldinfo->string_size + 2, h->root.root.string); + h->ldsym->_l._l_l._l_zeroes = 0; + h->ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; + ldinfo->string_size += len + 3; + } + + h->flags |= XCOFF_BUILT_LDSYM; + + return true; +} + +/* Do the final link step. */ + +boolean +_bfd_xcoff_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_size_type symesz; + struct xcoff_final_link_info finfo; + asection *o; + struct bfd_link_order *p; + size_t max_contents_size; + size_t max_sym_count; + size_t max_lineno_count; + size_t max_reloc_count; + size_t max_output_reloc_count; + file_ptr rel_filepos; + unsigned int relsz; + file_ptr line_filepos; + unsigned int linesz; + bfd *sub; + bfd_byte *external_relocs = NULL; + char strbuf[STRING_SIZE_SIZE]; + + if (info->shared) + abfd->flags |= DYNAMIC; + + symesz = bfd_coff_symesz (abfd); + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.strtab = NULL; + finfo.section_info = NULL; + finfo.last_file_index = -1; + finfo.toc_symindx = -1; + finfo.internal_syms = NULL; + finfo.sym_indices = NULL; + finfo.outsyms = NULL; + finfo.linenos = NULL; + finfo.contents = NULL; + finfo.external_relocs = NULL; + + finfo.ldsym = ((struct external_ldsym *) + (xcoff_hash_table (info)->loader_section->contents + + LDHDRSZ)); + finfo.ldrel = ((struct external_ldrel *) + (xcoff_hash_table (info)->loader_section->contents + + LDHDRSZ + + xcoff_hash_table (info)->ldhdr.l_nsyms * LDSYMSZ)); + + xcoff_data (abfd)->coff.link_info = info; + + finfo.strtab = _bfd_stringtab_init (); + if (finfo.strtab == NULL) + goto error_return; + + /* Count the line number and relocation entries required for the + output file. Determine a few maximum sizes. */ + max_contents_size = 0; + max_lineno_count = 0; + max_reloc_count = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + o->reloc_count = 0; + o->lineno_count = 0; + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + + if (info->strip == strip_none + || info->strip == strip_some) + o->lineno_count += sec->lineno_count; + + o->reloc_count += sec->reloc_count; + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->lineno_count > max_lineno_count) + max_lineno_count = sec->lineno_count; + if (coff_section_data (sec->owner, sec) != NULL + && xcoff_section_data (sec->owner, sec) != NULL + && (xcoff_section_data (sec->owner, sec)->lineno_count + > max_lineno_count)) + max_lineno_count = + xcoff_section_data (sec->owner, sec)->lineno_count; + if (sec->reloc_count > max_reloc_count) + max_reloc_count = sec->reloc_count; + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + } + } + + /* Compute the file positions for all the sections. */ + if (abfd->output_has_begun) + { + if (xcoff_hash_table (info)->file_align != 0) + abort (); + } + else + { + bfd_vma file_align; + + file_align = xcoff_hash_table (info)->file_align; + if (file_align != 0) + { + boolean saw_contents; + int indx; + asection **op; + file_ptr sofar; + + /* Insert .pad sections before every section which has + contents and is loaded, if it is preceded by some other + section which has contents and is loaded. */ + saw_contents = true; + for (op = &abfd->sections; *op != NULL; op = &(*op)->next) + { + (*op)->target_index = indx; + if (strcmp ((*op)->name, ".pad") == 0) + saw_contents = false; + else if (((*op)->flags & SEC_HAS_CONTENTS) != 0 + && ((*op)->flags & SEC_LOAD) != 0) + { + if (! saw_contents) + saw_contents = true; + else + { + asection *n, *hold; + + hold = *op; + *op = NULL; + n = bfd_make_section_anyway (abfd, ".pad"); + BFD_ASSERT (*op == n); + n->next = hold; + n->flags = SEC_HAS_CONTENTS; + n->alignment_power = 0; + saw_contents = false; + } + } + } + + /* Reset the section indices after inserting the new + sections. */ + indx = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + ++indx; + o->target_index = indx; + } + BFD_ASSERT ((unsigned int) indx == abfd->section_count); + + /* Work out appropriate sizes for the .pad sections to force + each section to land on a page boundary. This bit of + code knows what compute_section_file_positions is going + to do. */ + sofar = bfd_coff_filhsz (abfd); + sofar += bfd_coff_aoutsz (abfd); + sofar += abfd->section_count * bfd_coff_scnhsz (abfd); + for (o = abfd->sections; o != NULL; o = o->next) + if (o->reloc_count >= 0xffff || o->lineno_count >= 0xffff) + sofar += bfd_coff_scnhsz (abfd); + + for (o = abfd->sections; o != NULL; o = o->next) + { + if (strcmp (o->name, ".pad") == 0) + { + bfd_vma pageoff; + + BFD_ASSERT (o->_raw_size == 0); + pageoff = sofar & (file_align - 1); + if (pageoff != 0) + { + o->_raw_size = file_align - pageoff; + sofar += file_align - pageoff; + o->flags |= SEC_HAS_CONTENTS; + } + } + else + { + if ((o->flags & SEC_HAS_CONTENTS) != 0) + sofar += BFD_ALIGN (o->_raw_size, + 1 << o->alignment_power); + } + } + } + + bfd_coff_compute_section_file_positions (abfd); + } + + /* Allocate space for the pointers we need to keep for the relocs. */ + { + unsigned int i; + + /* We use section_count + 1, rather than section_count, because + the target_index fields are 1 based. */ + finfo.section_info = + ((struct xcoff_link_section_info *) + bfd_malloc ((abfd->section_count + 1) + * sizeof (struct xcoff_link_section_info))); + if (finfo.section_info == NULL) + goto error_return; + for (i = 0; i <= abfd->section_count; i++) + { + finfo.section_info[i].relocs = NULL; + finfo.section_info[i].rel_hashes = NULL; + finfo.section_info[i].toc_rel_hashes = NULL; + } + } + + /* Set the file positions for the relocs. */ + rel_filepos = obj_relocbase (abfd); + relsz = bfd_coff_relsz (abfd); + max_output_reloc_count = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + if (o->reloc_count == 0) + o->rel_filepos = 0; + else + { + o->flags |= SEC_RELOC; + o->rel_filepos = rel_filepos; + rel_filepos += o->reloc_count * relsz; + + /* We don't know the indices of global symbols until we have + written out all the local symbols. For each section in + the output file, we keep an array of pointers to hash + table entries. Each entry in the array corresponds to a + reloc. When we find a reloc against a global symbol, we + set the corresponding entry in this array so that we can + fix up the symbol index after we have written out all the + local symbols. + + Because of this problem, we also keep the relocs in + memory until the end of the link. This wastes memory. + We could backpatch the file later, I suppose, although it + would be slow. */ + finfo.section_info[o->target_index].relocs = + ((struct internal_reloc *) + bfd_malloc (o->reloc_count * sizeof (struct internal_reloc))); + finfo.section_info[o->target_index].rel_hashes = + ((struct xcoff_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct xcoff_link_hash_entry *))); + if (finfo.section_info[o->target_index].relocs == NULL + || finfo.section_info[o->target_index].rel_hashes == NULL) + goto error_return; + + if (o->reloc_count > max_output_reloc_count) + max_output_reloc_count = o->reloc_count; + } + } + + /* We now know the size of the relocs, so we can determine the file + positions of the line numbers. */ + line_filepos = rel_filepos; + finfo.line_filepos = line_filepos; + linesz = bfd_coff_linesz (abfd); + for (o = abfd->sections; o != NULL; o = o->next) + { + if (o->lineno_count == 0) + o->line_filepos = 0; + else + { + o->line_filepos = line_filepos; + line_filepos += o->lineno_count * linesz; + } + + /* Reset the reloc and lineno counts, so that we can use them to + count the number of entries we have output so far. */ + o->reloc_count = 0; + o->lineno_count = 0; + } + + obj_sym_filepos (abfd) = line_filepos; + + /* Figure out the largest number of symbols in an input BFD. Take + the opportunity to clear the output_has_begun fields of all the + input BFD's. We want at least 4 symbols, since that is the + number which xcoff_write_global_symbol may need. */ + max_sym_count = 4; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + size_t sz; + + sub->output_has_begun = false; + sz = obj_raw_syment_count (sub); + if (sz > max_sym_count) + max_sym_count = sz; + } + + /* Allocate some buffers used while linking. */ + finfo.internal_syms = ((struct internal_syment *) + bfd_malloc (max_sym_count + * sizeof (struct internal_syment))); + finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long)); + finfo.outsyms = ((bfd_byte *) + bfd_malloc ((size_t) ((max_sym_count + 1) * symesz))); + finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count + * bfd_coff_linesz (abfd)); + finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz); + if ((finfo.internal_syms == NULL && max_sym_count > 0) + || (finfo.sym_indices == NULL && max_sym_count > 0) + || finfo.outsyms == NULL + || (finfo.linenos == NULL && max_lineno_count > 0) + || (finfo.contents == NULL && max_contents_size > 0) + || (finfo.external_relocs == NULL && max_reloc_count > 0)) + goto error_return; + + obj_raw_syment_count (abfd) = 0; + xcoff_data (abfd)->toc = (bfd_vma) -1; + + /* We now know the position of everything in the file, except that + we don't know the size of the symbol table and therefore we don't + know where the string table starts. We just build the string + table in memory as we go along. We process all the relocations + for a single input file at once. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && p->u.indirect.section->owner->xvec == abfd->xvec) + { + sub = p->u.indirect.section->owner; + if (! sub->output_has_begun) + { + if (! xcoff_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! xcoff_reloc_link_order (abfd, &finfo, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* Free up the buffers used by xcoff_link_input_bfd. */ + + if (finfo.internal_syms != NULL) + { + free (finfo.internal_syms); + finfo.internal_syms = NULL; + } + if (finfo.sym_indices != NULL) + { + free (finfo.sym_indices); + finfo.sym_indices = NULL; + } + if (finfo.linenos != NULL) + { + free (finfo.linenos); + finfo.linenos = NULL; + } + if (finfo.contents != NULL) + { + free (finfo.contents); + finfo.contents = NULL; + } + if (finfo.external_relocs != NULL) + { + free (finfo.external_relocs); + finfo.external_relocs = NULL; + } + + /* The value of the last C_FILE symbol is supposed to be -1. Write + it out again. */ + if (finfo.last_file_index != -1) + { + finfo.last_file.n_value = -1; + bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file, + (PTR) finfo.outsyms); + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + finfo.last_file_index * symesz), + SEEK_SET) != 0 + || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz) + goto error_return; + } + + /* Write out all the global symbols which do not come from XCOFF + input files. */ + xcoff_link_hash_traverse (xcoff_hash_table (info), + xcoff_write_global_symbol, + (PTR) &finfo); + + if (finfo.outsyms != NULL) + { + free (finfo.outsyms); + finfo.outsyms = NULL; + } + + /* Now that we have written out all the global symbols, we know the + symbol indices to use for relocs against them, and we can finally + write out the relocs. */ + external_relocs = (bfd_byte *) malloc (max_output_reloc_count * relsz); + if (external_relocs == NULL && max_output_reloc_count != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + for (o = abfd->sections; o != NULL; o = o->next) + { + struct internal_reloc *irel; + struct internal_reloc *irelend; + struct xcoff_link_hash_entry **rel_hash; + struct xcoff_toc_rel_hash *toc_rel_hash; + bfd_byte *erel; + + if (o->reloc_count == 0) + continue; + + irel = finfo.section_info[o->target_index].relocs; + irelend = irel + o->reloc_count; + rel_hash = finfo.section_info[o->target_index].rel_hashes; + for (; irel < irelend; irel++, rel_hash++, erel += relsz) + { + if (*rel_hash != NULL) + { + if ((*rel_hash)->indx < 0) + { + if (! ((*info->callbacks->unattached_reloc) + (info, (*rel_hash)->root.root.string, + (bfd *) NULL, o, irel->r_vaddr))) + goto error_return; + (*rel_hash)->indx = 0; + } + irel->r_symndx = (*rel_hash)->indx; + } + } + + for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes; + toc_rel_hash != NULL; + toc_rel_hash = toc_rel_hash->next) + { + if (toc_rel_hash->h->u.toc_indx < 0) + { + if (! ((*info->callbacks->unattached_reloc) + (info, toc_rel_hash->h->root.root.string, + (bfd *) NULL, o, toc_rel_hash->rel->r_vaddr))) + goto error_return; + toc_rel_hash->h->u.toc_indx = 0; + } + toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx; + } + + /* XCOFF requires that the relocs be sorted by address. We tend + to produce them in the order in which their containing csects + appear in the symbol table, which is not necessarily by + address. So we sort them here. There may be a better way to + do this. */ + qsort ((PTR) finfo.section_info[o->target_index].relocs, + o->reloc_count, sizeof (struct internal_reloc), + xcoff_sort_relocs); + + irel = finfo.section_info[o->target_index].relocs; + irelend = irel + o->reloc_count; + erel = external_relocs; + for (; irel < irelend; irel++, rel_hash++, erel += relsz) + bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel); + + if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0 + || bfd_write ((PTR) external_relocs, relsz, o->reloc_count, + abfd) != relsz * o->reloc_count) + goto error_return; + } + + if (external_relocs != NULL) + { + free (external_relocs); + external_relocs = NULL; + } + + /* Free up the section information. */ + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + finfo.section_info = NULL; + } + + /* Write out the loader section contents. */ + BFD_ASSERT ((bfd_byte *) finfo.ldrel + == (xcoff_hash_table (info)->loader_section->contents + + xcoff_hash_table (info)->ldhdr.l_impoff)); + o = xcoff_hash_table (info)->loader_section; + if (! bfd_set_section_contents (abfd, o->output_section, + o->contents, o->output_offset, + o->_raw_size)) + goto error_return; + + /* Write out the magic sections. */ + o = xcoff_hash_table (info)->linkage_section; + if (o->_raw_size > 0 + && ! bfd_set_section_contents (abfd, o->output_section, o->contents, + o->output_offset, o->_raw_size)) + goto error_return; + o = xcoff_hash_table (info)->toc_section; + if (o->_raw_size > 0 + && ! bfd_set_section_contents (abfd, o->output_section, o->contents, + o->output_offset, o->_raw_size)) + goto error_return; + o = xcoff_hash_table (info)->descriptor_section; + if (o->_raw_size > 0 + && ! bfd_set_section_contents (abfd, o->output_section, o->contents, + o->output_offset, o->_raw_size)) + goto error_return; + + /* Write out the string table. */ + if (bfd_seek (abfd, + (obj_sym_filepos (abfd) + + obj_raw_syment_count (abfd) * symesz), + SEEK_SET) != 0) + goto error_return; + bfd_h_put_32 (abfd, + _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE, + (bfd_byte *) strbuf); + if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE) + goto error_return; + if (! _bfd_stringtab_emit (abfd, finfo.strtab)) + goto error_return; + + _bfd_stringtab_free (finfo.strtab); + + /* Write out the debugging string table. */ + o = xcoff_hash_table (info)->debug_section; + if (o != NULL) + { + struct bfd_strtab_hash *debug_strtab; + + debug_strtab = xcoff_hash_table (info)->debug_strtab; + BFD_ASSERT (o->output_section->_raw_size - o->output_offset + >= _bfd_stringtab_size (debug_strtab)); + if (bfd_seek (abfd, + o->output_section->filepos + o->output_offset, + SEEK_SET) != 0) + goto error_return; + if (! _bfd_stringtab_emit (abfd, debug_strtab)) + goto error_return; + } + + /* Setting bfd_get_symcount to 0 will cause write_object_contents to + not try to write out the symbols. */ + bfd_get_symcount (abfd) = 0; + + return true; + + error_return: + if (finfo.strtab != NULL) + _bfd_stringtab_free (finfo.strtab); + if (finfo.section_info != NULL) + { + unsigned int i; + + for (i = 0; i < abfd->section_count; i++) + { + if (finfo.section_info[i].relocs != NULL) + free (finfo.section_info[i].relocs); + if (finfo.section_info[i].rel_hashes != NULL) + free (finfo.section_info[i].rel_hashes); + } + free (finfo.section_info); + } + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.sym_indices != NULL) + free (finfo.sym_indices); + if (finfo.outsyms != NULL) + free (finfo.outsyms); + if (finfo.linenos != NULL) + free (finfo.linenos); + if (finfo.contents != NULL) + free (finfo.contents); + if (finfo.external_relocs != NULL) + free (finfo.external_relocs); + if (external_relocs != NULL) + free (external_relocs); + return false; +} + +/* Link an input file into the linker output file. This function + handles all the sections and relocations of the input file at once. */ + +static boolean +xcoff_link_input_bfd (finfo, input_bfd) + struct xcoff_final_link_info *finfo; + bfd *input_bfd; +{ + bfd *output_bfd; + const char *strings; + bfd_size_type syment_base; + unsigned int n_tmask; + unsigned int n_btshft; + boolean copy, hash; + bfd_size_type isymesz; + bfd_size_type osymesz; + bfd_size_type linesz; + bfd_byte *esym; + bfd_byte *esym_end; + struct xcoff_link_hash_entry **sym_hash; + struct internal_syment *isymp; + asection **csectpp; + unsigned long *debug_index; + long *indexp; + unsigned long output_index; + bfd_byte *outsym; + unsigned int incls; + asection *oline; + boolean keep_syms; + asection *o; + + /* We can just skip DYNAMIC files, unless this is a static link. */ + if ((input_bfd->flags & DYNAMIC) != 0 + && ! finfo->info->static_link) + return true; + + /* Move all the symbols to the output file. */ + + output_bfd = finfo->output_bfd; + strings = NULL; + syment_base = obj_raw_syment_count (output_bfd); + isymesz = bfd_coff_symesz (input_bfd); + osymesz = bfd_coff_symesz (output_bfd); + linesz = bfd_coff_linesz (input_bfd); + BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd)); + + n_tmask = coff_data (input_bfd)->local_n_tmask; + n_btshft = coff_data (input_bfd)->local_n_btshft; + + /* Define macros so that ISFCN, et. al., macros work correctly. */ +#define N_TMASK n_tmask +#define N_BTSHFT n_btshft + + copy = false; + if (! finfo->info->keep_memory) + copy = true; + hash = true; + if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) + hash = false; + + if (! _bfd_coff_get_external_symbols (input_bfd)) + return false; + + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; + sym_hash = obj_xcoff_sym_hashes (input_bfd); + csectpp = xcoff_data (input_bfd)->csects; + debug_index = xcoff_data (input_bfd)->debug_indices; + isymp = finfo->internal_syms; + indexp = finfo->sym_indices; + output_index = syment_base; + outsym = finfo->outsyms; + incls = 0; + oline = NULL; + + while (esym < esym_end) + { + struct internal_syment isym; + union internal_auxent aux; + int smtyp = 0; + boolean skip; + boolean require; + int add; + + bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp); + + /* If this is a C_EXT or C_HIDEXT symbol, we need the csect + information. */ + if (isymp->n_sclass == C_EXT || isymp->n_sclass == C_HIDEXT) + { + BFD_ASSERT (isymp->n_numaux > 0); + bfd_coff_swap_aux_in (input_bfd, + (PTR) (esym + isymesz * isymp->n_numaux), + isymp->n_type, isymp->n_sclass, + isymp->n_numaux - 1, isymp->n_numaux, + (PTR) &aux); + smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); + } + + /* Make a copy of *isymp so that the relocate_section function + always sees the original values. This is more reliable than + always recomputing the symbol value even if we are stripping + the symbol. */ + isym = *isymp; + + /* If this symbol is in the .loader section, swap out the + .loader symbol information. If this is an external symbol + reference to a defined symbol, though, then wait until we get + to the definition. */ + if (isym.n_sclass == C_EXT + && *sym_hash != NULL + && (*sym_hash)->ldsym != NULL + && (smtyp != XTY_ER + || (*sym_hash)->root.type == bfd_link_hash_undefined)) + { + struct xcoff_link_hash_entry *h; + struct internal_ldsym *ldsym; + + h = *sym_hash; + ldsym = h->ldsym; + if (isym.n_scnum > 0) + { + ldsym->l_scnum = (*csectpp)->output_section->target_index; + ldsym->l_value = (isym.n_value + + (*csectpp)->output_section->vma + + (*csectpp)->output_offset + - (*csectpp)->vma); + } + else + { + ldsym->l_scnum = isym.n_scnum; + ldsym->l_value = isym.n_value; + } + + ldsym->l_smtype = smtyp; + if (((h->flags & XCOFF_DEF_REGULAR) == 0 + && (h->flags & XCOFF_DEF_DYNAMIC) != 0) + || (h->flags & XCOFF_IMPORT) != 0) + ldsym->l_smtype |= L_IMPORT; + if (((h->flags & XCOFF_DEF_REGULAR) != 0 + && (h->flags & XCOFF_DEF_DYNAMIC) != 0) + || (h->flags & XCOFF_EXPORT) != 0) + ldsym->l_smtype |= L_EXPORT; + if ((h->flags & XCOFF_ENTRY) != 0) + ldsym->l_smtype |= L_ENTRY; + + ldsym->l_smclas = aux.x_csect.x_smclas; + + if (ldsym->l_ifile == (bfd_size_type) -1) + ldsym->l_ifile = 0; + else if (ldsym->l_ifile == 0) + { + if ((ldsym->l_smtype & L_IMPORT) == 0) + ldsym->l_ifile = 0; + else + { + bfd *impbfd; + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + impbfd = h->root.u.def.section->owner; + else if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + impbfd = h->root.u.undef.abfd; + else + impbfd = NULL; + + if (impbfd == NULL) + ldsym->l_ifile = 0; + else + { + BFD_ASSERT (impbfd->xvec == finfo->output_bfd->xvec); + ldsym->l_ifile = xcoff_data (impbfd)->import_file_id; + } + } + } + + ldsym->l_parm = 0; + + BFD_ASSERT (h->ldindx >= 0); + BFD_ASSERT (LDSYMSZ == sizeof (struct external_ldsym)); + xcoff_swap_ldsym_out (finfo->output_bfd, ldsym, + finfo->ldsym + h->ldindx - 3); + h->ldsym = NULL; + + /* Fill in snentry now that we know the target_index. */ + if ((h->flags & XCOFF_ENTRY) != 0 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + xcoff_data (output_bfd)->snentry = + h->root.u.def.section->output_section->target_index; + } + + *indexp = -1; + + skip = false; + require = false; + add = 1 + isym.n_numaux; + + /* If we are skipping this csect, we want to skip this symbol. */ + if (*csectpp == NULL) + skip = true; + + /* If we garbage collected this csect, we want to skip this + symbol. */ + if (! skip + && xcoff_hash_table (finfo->info)->gc + && ((*csectpp)->flags & SEC_MARK) == 0 + && *csectpp != bfd_abs_section_ptr) + skip = true; + + /* An XCOFF linker always skips C_STAT symbols. */ + if (! skip + && isymp->n_sclass == C_STAT) + skip = true; + + /* We skip all but the first TOC anchor. */ + if (! skip + && isymp->n_sclass == C_HIDEXT + && aux.x_csect.x_smclas == XMC_TC0) + { + if (finfo->toc_symindx != -1) + skip = true; + else + { + bfd_vma tocval, tocend; + + tocval = ((*csectpp)->output_section->vma + + (*csectpp)->output_offset + + isym.n_value + - (*csectpp)->vma); + /* We want to find out if tocval is a good value to use + as the TOC anchor--that is, whether we can access all + of the TOC using a 16 bit offset from tocval. This + test assumes that the TOC comes at the end of the + output section, as it does in the default linker + script. If the TOC anchor is too far into the .toc + section, the relocation routine will report + overflows. */ + tocend = ((*csectpp)->output_section->vma + + (*csectpp)->output_section->_raw_size); + if (tocval + 0x8000 < tocend) + { + bfd_vma tocadd; + + tocadd = tocend - (tocval + 0x8000); + tocval += tocadd; + isym.n_value += tocadd; + } + + finfo->toc_symindx = output_index; + xcoff_data (finfo->output_bfd)->toc = tocval; + xcoff_data (finfo->output_bfd)->sntoc = + (*csectpp)->output_section->target_index; + require = true; + } + } + + /* If we are stripping all symbols, we want to skip this one. */ + if (! skip + && finfo->info->strip == strip_all) + skip = true; + + /* We can skip resolved external references. */ + if (! skip + && isym.n_sclass == C_EXT + && smtyp == XTY_ER + && (*sym_hash)->root.type != bfd_link_hash_undefined) + skip = true; + + /* We can skip common symbols if they got defined somewhere + else. */ + if (! skip + && isym.n_sclass == C_EXT + && smtyp == XTY_CM + && ((*sym_hash)->root.type != bfd_link_hash_common + || (*sym_hash)->root.u.c.p->section != *csectpp) + && ((*sym_hash)->root.type != bfd_link_hash_defined + || (*sym_hash)->root.u.def.section != *csectpp)) + skip = true; + + /* Skip local symbols if we are discarding them. */ + if (! skip + && finfo->info->discard == discard_all + && isym.n_sclass != C_EXT + && (isym.n_sclass != C_HIDEXT + || smtyp != XTY_SD)) + skip = true; + + /* If we stripping debugging symbols, and this is a debugging + symbol, then skip it. */ + if (! skip + && finfo->info->strip == strip_debugger + && isym.n_scnum == N_DEBUG) + skip = true; + + /* If some symbols are stripped based on the name, work out the + name and decide whether to skip this symbol. We don't handle + this correctly for symbols whose names are in the .debug + section; to get it right we would need a new bfd_strtab_hash + function to return the string given the index. */ + if (! skip + && (finfo->info->strip == strip_some + || finfo->info->discard == discard_l) + && (debug_index == NULL || *debug_index == (unsigned long) -1)) + { + const char *name; + char buf[SYMNMLEN + 1]; + + name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); + if (name == NULL) + return false; + + if ((finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, name, false, + false) == NULL)) + || (finfo->info->discard == discard_l + && (isym.n_sclass != C_EXT + && (isym.n_sclass != C_HIDEXT + || smtyp != XTY_SD)) + && strncmp (name, finfo->info->lprefix, + finfo->info->lprefix_len) == 0)) + skip = true; + } + + /* We can not skip the first TOC anchor. */ + if (skip + && require + && finfo->info->strip != strip_all) + skip = false; + + /* We now know whether we are to skip this symbol or not. */ + if (! skip) + { + /* Adjust the symbol in order to output it. */ + + if (isym._n._n_n._n_zeroes == 0 + && isym._n._n_n._n_offset != 0) + { + /* This symbol has a long name. Enter it in the string + table we are building. If *debug_index != -1, the + name has already been entered in the .debug section. */ + if (debug_index != NULL && *debug_index != (unsigned long) -1) + isym._n._n_n._n_offset = *debug_index; + else + { + const char *name; + bfd_size_type indx; + + name = _bfd_coff_internal_syment_name (input_bfd, &isym, + (char *) NULL); + if (name == NULL) + return false; + indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy); + if (indx == (bfd_size_type) -1) + return false; + isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; + } + } + + if (isym.n_sclass != C_BSTAT + && isym.n_sclass != C_ESTAT + && isym.n_sclass != C_DECL + && isym.n_scnum > 0) + { + isym.n_scnum = (*csectpp)->output_section->target_index; + isym.n_value += ((*csectpp)->output_section->vma + + (*csectpp)->output_offset + - (*csectpp)->vma); + } + + /* The value of a C_FILE symbol is the symbol index of the + next C_FILE symbol. The value of the last C_FILE symbol + is -1. We try to get this right, below, just before we + write the symbols out, but in the general case we may + have to write the symbol out twice. */ + if (isym.n_sclass == C_FILE) + { + if (finfo->last_file_index != -1 + && finfo->last_file.n_value != (long) output_index) + { + /* We must correct the value of the last C_FILE entry. */ + finfo->last_file.n_value = output_index; + if ((bfd_size_type) finfo->last_file_index >= syment_base) + { + /* The last C_FILE symbol is in this input file. */ + bfd_coff_swap_sym_out (output_bfd, + (PTR) &finfo->last_file, + (PTR) (finfo->outsyms + + ((finfo->last_file_index + - syment_base) + * osymesz))); + } + else + { + /* We have already written out the last C_FILE + symbol. We need to write it out again. We + borrow *outsym temporarily. */ + bfd_coff_swap_sym_out (output_bfd, + (PTR) &finfo->last_file, + (PTR) outsym); + if (bfd_seek (output_bfd, + (obj_sym_filepos (output_bfd) + + finfo->last_file_index * osymesz), + SEEK_SET) != 0 + || (bfd_write (outsym, osymesz, 1, output_bfd) + != osymesz)) + return false; + } + } + + finfo->last_file_index = output_index; + finfo->last_file = isym; + } + + /* The value of a C_BINCL or C_EINCL symbol is a file offset + into the line numbers. We update the symbol values when + we handle the line numbers. */ + if (isym.n_sclass == C_BINCL + || isym.n_sclass == C_EINCL) + { + isym.n_value = finfo->line_filepos; + ++incls; + } + + /* Output the symbol. */ + + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym); + + *indexp = output_index; + + if (isym.n_sclass == C_EXT) + { + long indx; + struct xcoff_link_hash_entry *h; + + indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) + / isymesz); + h = obj_xcoff_sym_hashes (input_bfd)[indx]; + BFD_ASSERT (h != NULL); + h->indx = output_index; + } + + /* If this is a symbol in the TOC which we may have merged + (class XMC_TC), remember the symbol index of the TOC + symbol. */ + if (isym.n_sclass == C_HIDEXT + && aux.x_csect.x_smclas == XMC_TC + && *sym_hash != NULL) + { + BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0); + BFD_ASSERT ((*sym_hash)->toc_section != NULL); + (*sym_hash)->u.toc_indx = output_index; + } + + output_index += add; + outsym += add * osymesz; + } + + esym += add * isymesz; + isymp += add; + csectpp += add; + sym_hash += add; + if (debug_index != NULL) + debug_index += add; + ++indexp; + for (--add; add > 0; --add) + *indexp++ = -1; + } + + /* Fix up the aux entries and the C_BSTAT symbols. This must be + done in a separate pass, because we don't know the correct symbol + indices until we have already decided which symbols we are going + to keep. */ + + esym = (bfd_byte *) obj_coff_external_syms (input_bfd); + esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; + isymp = finfo->internal_syms; + indexp = finfo->sym_indices; + csectpp = xcoff_data (input_bfd)->csects; + outsym = finfo->outsyms; + while (esym < esym_end) + { + int add; + + add = 1 + isymp->n_numaux; + + if (*indexp < 0) + esym += add * isymesz; + else + { + int i; + + if (isymp->n_sclass == C_BSTAT) + { + struct internal_syment isym; + unsigned long indx; + + /* The value of a C_BSTAT symbol is the symbol table + index of the containing csect. */ + bfd_coff_swap_sym_in (output_bfd, (PTR) outsym, (PTR) &isym); + indx = isym.n_value; + if (indx < obj_raw_syment_count (input_bfd)) + { + long symindx; + + symindx = finfo->sym_indices[indx]; + if (symindx < 0) + isym.n_value = 0; + else + isym.n_value = symindx; + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, + (PTR) outsym); + } + } + + esym += isymesz; + outsym += osymesz; + + for (i = 0; i < isymp->n_numaux && esym < esym_end; i++) + { + union internal_auxent aux; + + bfd_coff_swap_aux_in (input_bfd, (PTR) esym, isymp->n_type, + isymp->n_sclass, i, isymp->n_numaux, + (PTR) &aux); + + if (isymp->n_sclass == C_FILE) + { + /* This is the file name (or some comment put in by + the compiler). If it is long, we must put it in + the string table. */ + if (aux.x_file.x_n.x_zeroes == 0 + && aux.x_file.x_n.x_offset != 0) + { + const char *filename; + bfd_size_type indx; + + BFD_ASSERT (aux.x_file.x_n.x_offset + >= STRING_SIZE_SIZE); + if (strings == NULL) + { + strings = _bfd_coff_read_string_table (input_bfd); + if (strings == NULL) + return false; + } + filename = strings + aux.x_file.x_n.x_offset; + indx = _bfd_stringtab_add (finfo->strtab, filename, + hash, copy); + if (indx == (bfd_size_type) -1) + return false; + aux.x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; + } + } + else if ((isymp->n_sclass == C_EXT + || isymp->n_sclass == C_HIDEXT) + && i + 1 == isymp->n_numaux) + { + /* We don't support type checking. I don't know if + anybody does. */ + aux.x_csect.x_parmhash = 0; + /* I don't think anybody uses these fields, but we'd + better clobber them just in case. */ + aux.x_csect.x_stab = 0; + aux.x_csect.x_snstab = 0; + if (SMTYP_SMTYP (aux.x_csect.x_smtyp) == XTY_LD) + { + unsigned long indx; + + indx = aux.x_csect.x_scnlen.l; + if (indx < obj_raw_syment_count (input_bfd)) + { + long symindx; + + symindx = finfo->sym_indices[indx]; + if (symindx < 0) + aux.x_sym.x_tagndx.l = 0; + else + aux.x_sym.x_tagndx.l = symindx; + } + } + } + else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) + { + unsigned long indx; + + if (ISFCN (isymp->n_type) + || ISTAG (isymp->n_sclass) + || isymp->n_sclass == C_BLOCK) + { + indx = aux.x_sym.x_fcnary.x_fcn.x_endndx.l; + if (indx > 0 + && indx < obj_raw_syment_count (input_bfd)) + { + /* We look forward through the symbol for + the index of the next symbol we are going + to include. I don't know if this is + entirely right. */ + while (finfo->sym_indices[indx] < 0 + && indx < obj_raw_syment_count (input_bfd)) + ++indx; + if (indx >= obj_raw_syment_count (input_bfd)) + indx = output_index; + else + indx = finfo->sym_indices[indx]; + aux.x_sym.x_fcnary.x_fcn.x_endndx.l = indx; + } + } + + indx = aux.x_sym.x_tagndx.l; + if (indx > 0 && indx < obj_raw_syment_count (input_bfd)) + { + long symindx; + + symindx = finfo->sym_indices[indx]; + if (symindx < 0) + aux.x_sym.x_tagndx.l = 0; + else + aux.x_sym.x_tagndx.l = symindx; + } + } + + /* Copy over the line numbers, unless we are stripping + them. We do this on a symbol by symbol basis in + order to more easily handle garbage collection. */ + if ((isymp->n_sclass == C_EXT + || isymp->n_sclass == C_HIDEXT) + && i == 0 + && isymp->n_numaux > 1 + && ISFCN (isymp->n_type) + && aux.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0) + { + if (finfo->info->strip != strip_none + && finfo->info->strip != strip_some) + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0; + else + { + asection *enclosing; + unsigned int enc_count; + bfd_size_type linoff; + struct internal_lineno lin; + + o = *csectpp; + enclosing = xcoff_section_data (abfd, o)->enclosing; + enc_count = xcoff_section_data (abfd, o)->lineno_count; + if (oline != enclosing) + { + if (bfd_seek (input_bfd, + enclosing->line_filepos, + SEEK_SET) != 0 + || (bfd_read (finfo->linenos, linesz, + enc_count, input_bfd) + != linesz * enc_count)) + return false; + oline = enclosing; + } + + linoff = (aux.x_sym.x_fcnary.x_fcn.x_lnnoptr + - enclosing->line_filepos); + + bfd_coff_swap_lineno_in (input_bfd, + (PTR) (finfo->linenos + linoff), + (PTR) &lin); + if (lin.l_lnno != 0 + || ((bfd_size_type) lin.l_addr.l_symndx + != ((esym + - isymesz + - ((bfd_byte *) + obj_coff_external_syms (input_bfd))) + / isymesz))) + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0; + else + { + bfd_byte *linpend, *linp; + bfd_vma offset; + bfd_size_type count; + + lin.l_addr.l_symndx = *indexp; + bfd_coff_swap_lineno_out (output_bfd, (PTR) &lin, + (PTR) (finfo->linenos + + linoff)); + + linpend = (finfo->linenos + + enc_count * linesz); + offset = (o->output_section->vma + + o->output_offset + - o->vma); + for (linp = finfo->linenos + linoff + linesz; + linp < linpend; + linp += linesz) + { + bfd_coff_swap_lineno_in (input_bfd, (PTR) linp, + (PTR) &lin); + if (lin.l_lnno == 0) + break; + lin.l_addr.l_paddr += offset; + bfd_coff_swap_lineno_out (output_bfd, + (PTR) &lin, + (PTR) linp); + } + + count = (linp - (finfo->linenos + linoff)) / linesz; + + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = + (o->output_section->line_filepos + + o->output_section->lineno_count * linesz); + + if (bfd_seek (output_bfd, + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr, + SEEK_SET) != 0 + || (bfd_write (finfo->linenos + linoff, + linesz, count, output_bfd) + != linesz * count)) + return false; + + o->output_section->lineno_count += count; + + if (incls > 0) + { + struct internal_syment *iisp, *iispend; + long *iindp; + bfd_byte *oos; + + /* Update any C_BINCL or C_EINCL symbols + that refer to a line number in the + range we just output. */ + iisp = finfo->internal_syms; + iispend = (iisp + + obj_raw_syment_count (input_bfd)); + iindp = finfo->sym_indices; + oos = finfo->outsyms; + while (iisp < iispend) + { + if ((iisp->n_sclass == C_BINCL + || iisp->n_sclass == C_EINCL) + && ((bfd_size_type) iisp->n_value + >= enclosing->line_filepos + linoff) + && ((bfd_size_type) iisp->n_value + < (enclosing->line_filepos + + enc_count * linesz))) + { + struct internal_syment iis; + + bfd_coff_swap_sym_in (output_bfd, + (PTR) oos, + (PTR) &iis); + iis.n_value = + (iisp->n_value + - enclosing->line_filepos + - linoff + + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr); + bfd_coff_swap_sym_out (output_bfd, + (PTR) &iis, + (PTR) oos); + --incls; + } + + iisp += iisp->n_numaux + 1; + iindp += iisp->n_numaux + 1; + oos += (iisp->n_numaux + 1) * osymesz; + } + } + } + } + } + + bfd_coff_swap_aux_out (output_bfd, (PTR) &aux, isymp->n_type, + isymp->n_sclass, i, isymp->n_numaux, + (PTR) outsym); + outsym += osymesz; + esym += isymesz; + } + } + + indexp += add; + isymp += add; + csectpp += add; + } + + /* If we swapped out a C_FILE symbol, guess that the next C_FILE + symbol will be the first symbol in the next input file. In the + normal case, this will save us from writing out the C_FILE symbol + again. */ + if (finfo->last_file_index != -1 + && (bfd_size_type) finfo->last_file_index >= syment_base) + { + finfo->last_file.n_value = output_index; + bfd_coff_swap_sym_out (output_bfd, (PTR) &finfo->last_file, + (PTR) (finfo->outsyms + + ((finfo->last_file_index - syment_base) + * osymesz))); + } + + /* Write the modified symbols to the output file. */ + if (outsym > finfo->outsyms) + { + if (bfd_seek (output_bfd, + obj_sym_filepos (output_bfd) + syment_base * osymesz, + SEEK_SET) != 0 + || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1, + output_bfd) + != (bfd_size_type) (outsym - finfo->outsyms))) + return false; + + BFD_ASSERT ((obj_raw_syment_count (output_bfd) + + (outsym - finfo->outsyms) / osymesz) + == output_index); + + obj_raw_syment_count (output_bfd) = output_index; + } + + /* Don't let the linker relocation routines discard the symbols. */ + keep_syms = obj_coff_keep_syms (input_bfd); + obj_coff_keep_syms (input_bfd) = true; + + /* Relocate the contents of each section. */ + for (o = input_bfd->sections; o != NULL; o = o->next) + { + bfd_byte *contents; + + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || o->_raw_size == 0 + || (o->flags & SEC_IN_MEMORY) != 0) + continue; + + /* We have set filepos correctly for the sections we created to + represent csects, so bfd_get_section_contents should work. */ + if (coff_section_data (input_bfd, o) != NULL + && coff_section_data (input_bfd, o)->contents != NULL) + contents = coff_section_data (input_bfd, o)->contents; + else + { + if (! bfd_get_section_contents (input_bfd, o, finfo->contents, + (file_ptr) 0, o->_raw_size)) + return false; + contents = finfo->contents; + } + + if ((o->flags & SEC_RELOC) != 0) + { + int target_index; + struct internal_reloc *internal_relocs; + struct internal_reloc *irel; + bfd_vma offset; + struct internal_reloc *irelend; + struct xcoff_link_hash_entry **rel_hash; + long r_symndx; + + /* Read in the relocs. */ + target_index = o->output_section->target_index; + internal_relocs = (xcoff_read_internal_relocs + (input_bfd, o, false, finfo->external_relocs, + true, + (finfo->section_info[target_index].relocs + + o->output_section->reloc_count))); + if (internal_relocs == NULL) + return false; + + /* Call processor specific code to relocate the section + contents. */ + if (! bfd_coff_relocate_section (output_bfd, finfo->info, + input_bfd, o, + contents, + internal_relocs, + finfo->internal_syms, + xcoff_data (input_bfd)->csects)) + return false; + + offset = o->output_section->vma + o->output_offset - o->vma; + irel = internal_relocs; + irelend = irel + o->reloc_count; + rel_hash = (finfo->section_info[target_index].rel_hashes + + o->output_section->reloc_count); + for (; irel < irelend; irel++, rel_hash++) + { + struct xcoff_link_hash_entry *h = NULL; + struct internal_ldrel ldrel; + + *rel_hash = NULL; + + /* Adjust the reloc address and symbol index. */ + + irel->r_vaddr += offset; + + r_symndx = irel->r_symndx; + + if (r_symndx != -1) + { + h = obj_xcoff_sym_hashes (input_bfd)[r_symndx]; + if (h != NULL + && (irel->r_type == R_TOC + || irel->r_type == R_GL + || irel->r_type == R_TCL + || irel->r_type == R_TRL + || irel->r_type == R_TRLA)) + { + /* This is a TOC relative reloc with a symbol + attached. The symbol should be the one which + this reloc is for. We want to make this + reloc against the TOC address of the symbol, + not the symbol itself. */ + BFD_ASSERT (h->toc_section != NULL); + BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0); + if (h->u.toc_indx != -1) + irel->r_symndx = h->u.toc_indx; + else + { + struct xcoff_toc_rel_hash *n; + struct xcoff_link_section_info *si; + + n = ((struct xcoff_toc_rel_hash *) + bfd_alloc (finfo->output_bfd, + sizeof (struct xcoff_toc_rel_hash))); + if (n == NULL) + return false; + si = finfo->section_info + target_index; + n->next = si->toc_rel_hashes; + n->h = h; + n->rel = irel; + si->toc_rel_hashes = n; + } + } + else if (h != NULL) + { + /* This is a global symbol. */ + if (h->indx >= 0) + irel->r_symndx = h->indx; + else + { + /* This symbol is being written at the end + of the file, and we do not yet know the + symbol index. We save the pointer to the + hash table entry in the rel_hash list. + We set the indx field to -2 to indicate + that this symbol must not be stripped. */ + *rel_hash = h; + h->indx = -2; + } + } + else + { + long indx; + + indx = finfo->sym_indices[r_symndx]; + + if (indx == -1) + { + struct internal_syment *is; + + /* Relocations against a TC0 TOC anchor are + automatically transformed to be against + the TOC anchor in the output file. */ + is = finfo->internal_syms + r_symndx; + if (is->n_sclass == C_HIDEXT + && is->n_numaux > 0) + { + PTR auxptr; + union internal_auxent aux; + + auxptr = ((PTR) + (((bfd_byte *) + obj_coff_external_syms (input_bfd)) + + ((r_symndx + is->n_numaux) + * isymesz))); + bfd_coff_swap_aux_in (input_bfd, auxptr, + is->n_type, is->n_sclass, + is->n_numaux - 1, + is->n_numaux, + (PTR) &aux); + if (SMTYP_SMTYP (aux.x_csect.x_smtyp) == XTY_SD + && aux.x_csect.x_smclas == XMC_TC0) + indx = finfo->toc_symindx; + } + } + + if (indx != -1) + irel->r_symndx = indx; + else + { + struct internal_syment *is; + const char *name; + char buf[SYMNMLEN + 1]; + + /* This reloc is against a symbol we are + stripping. It would be possible to handle + this case, but I don't think it's worth it. */ + is = finfo->internal_syms + r_symndx; + + name = (_bfd_coff_internal_syment_name + (input_bfd, is, buf)); + if (name == NULL) + return false; + + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, name, input_bfd, o, + irel->r_vaddr))) + return false; + } + } + } + + switch (irel->r_type) + { + default: + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) + break; + /* Fall through. */ + case R_POS: + case R_NEG: + case R_RL: + case R_RLA: + /* This reloc needs to be copied into the .loader + section. */ + ldrel.l_vaddr = irel->r_vaddr; + if (r_symndx == -1) + ldrel.l_symndx = -1; + else if (h == NULL + || (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common)) + { + asection *sec; + + if (h == NULL) + sec = xcoff_data (input_bfd)->csects[r_symndx]; + else if (h->root.type == bfd_link_hash_common) + sec = h->root.u.c.p->section; + else + sec = h->root.u.def.section; + sec = sec->output_section; + + if (strcmp (sec->name, ".text") == 0) + ldrel.l_symndx = 0; + else if (strcmp (sec->name, ".data") == 0) + ldrel.l_symndx = 1; + else if (strcmp (sec->name, ".bss") == 0) + ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + ("%s: loader reloc in unrecognized section `%s'", + bfd_get_filename (input_bfd), + sec->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + } + else + { + if (h->ldindx < 0) + { + (*_bfd_error_handler) + ("%s: `%s' in loader reloc but not loader sym", + bfd_get_filename (input_bfd), + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return false; + } + ldrel.l_symndx = h->ldindx; + } + ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; + ldrel.l_rsecnm = o->output_section->target_index; + if (xcoff_hash_table (finfo->info)->textro + && strcmp (o->output_section->name, ".text") == 0) + { + (*_bfd_error_handler) + ("%s: loader reloc in read-only section %s", + bfd_get_filename (input_bfd), + bfd_get_section_name (finfo->output_bfd, + o->output_section)); + bfd_set_error (bfd_error_invalid_operation); + return false; + } + xcoff_swap_ldrel_out (output_bfd, &ldrel, + finfo->ldrel); + BFD_ASSERT (sizeof (struct external_ldrel) == LDRELSZ); + ++finfo->ldrel; + break; + + case R_TOC: + case R_GL: + case R_TCL: + case R_TRL: + case R_TRLA: + /* We should never need a .loader reloc for a TOC + relative reloc. */ + break; + } + } + + o->output_section->reloc_count += o->reloc_count; + } + + /* Write out the modified section contents. */ + if (! bfd_set_section_contents (output_bfd, o->output_section, + contents, o->output_offset, + (o->_cooked_size != 0 + ? o->_cooked_size + : o->_raw_size))) + return false; + } + + obj_coff_keep_syms (input_bfd) = keep_syms; + + if (! finfo->info->keep_memory) + { + if (! _bfd_coff_free_symbols (input_bfd)) + return false; + } + + return true; +} + +#undef N_TMASK +#undef N_BTSHFT + +/* Write out a non-XCOFF global symbol. */ + +static boolean +xcoff_write_global_symbol (h, p) + struct xcoff_link_hash_entry *h; + PTR p; +{ + struct xcoff_final_link_info *finfo = (struct xcoff_final_link_info *) p; + bfd *output_bfd; + bfd_byte *outsym; + struct internal_syment isym; + union internal_auxent aux; + + output_bfd = finfo->output_bfd; + + /* If this symbol was garbage collected, just skip it. */ + if (xcoff_hash_table (finfo->info)->gc + && (h->flags & XCOFF_MARK) == 0) + return true; + + /* If we need a .loader section entry, write it out. */ + if (h->ldsym != NULL) + { + struct internal_ldsym *ldsym; + bfd *impbfd; + + ldsym = h->ldsym; + + if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + { + ldsym->l_value = 0; + ldsym->l_scnum = N_UNDEF; + ldsym->l_smtype = XTY_ER; + impbfd = h->root.u.undef.abfd; + } + else if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *sec; + + sec = h->root.u.def.section; + ldsym->l_value = (sec->output_section->vma + + sec->output_offset + + h->root.u.def.value); + ldsym->l_scnum = sec->output_section->target_index; + ldsym->l_smtype = XTY_SD; + impbfd = sec->owner; + } + else + abort (); + + if (((h->flags & XCOFF_DEF_REGULAR) == 0 + && (h->flags & XCOFF_DEF_DYNAMIC) != 0) + || (h->flags & XCOFF_IMPORT) != 0) + ldsym->l_smtype |= L_IMPORT; + if (((h->flags & XCOFF_DEF_REGULAR) != 0 + && (h->flags & XCOFF_DEF_DYNAMIC) != 0) + || (h->flags & XCOFF_EXPORT) != 0) + ldsym->l_smtype |= L_EXPORT; + if ((h->flags & XCOFF_ENTRY) != 0) + ldsym->l_smtype |= L_ENTRY; + + ldsym->l_smclas = h->smclas; + + if (ldsym->l_ifile == (bfd_size_type) -1) + ldsym->l_ifile = 0; + else if (ldsym->l_ifile == 0) + { + if ((ldsym->l_smtype & L_IMPORT) == 0) + ldsym->l_ifile = 0; + else if (impbfd == NULL) + ldsym->l_ifile = 0; + else + { + BFD_ASSERT (impbfd->xvec == output_bfd->xvec); + ldsym->l_ifile = xcoff_data (impbfd)->import_file_id; + } + } + + ldsym->l_parm = 0; + + BFD_ASSERT (h->ldindx >= 0); + BFD_ASSERT (LDSYMSZ == sizeof (struct external_ldsym)); + xcoff_swap_ldsym_out (output_bfd, ldsym, finfo->ldsym + h->ldindx - 3); + h->ldsym = NULL; + } + + /* If this symbol needs global linkage code, write it out. */ + if (h->root.type == bfd_link_hash_defined + && (h->root.u.def.section + == xcoff_hash_table (finfo->info)->linkage_section)) + { + bfd_byte *p; + bfd_vma tocoff; + unsigned int i; + + p = h->root.u.def.section->contents + h->root.u.def.value; + + /* The first instruction in the global linkage code loads a + specific TOC element. */ + tocoff = (h->descriptor->toc_section->output_section->vma + + h->descriptor->toc_section->output_offset + - xcoff_data (output_bfd)->toc); + if ((h->descriptor->flags & XCOFF_SET_TOC) != 0) + tocoff += h->descriptor->u.toc_offset; + bfd_put_32 (output_bfd, XCOFF_GLINK_FIRST | (tocoff & 0xffff), p); + for (i = 0, p += 4; + i < sizeof xcoff_glink_code / sizeof xcoff_glink_code[0]; + i++, p += 4) + bfd_put_32 (output_bfd, xcoff_glink_code[i], p); + } + + /* If we created a TOC entry for this symbol, write out the required + relocs. */ + if ((h->flags & XCOFF_SET_TOC) != 0) + { + asection *tocsec; + asection *osec; + int oindx; + struct internal_reloc *irel; + struct internal_ldrel ldrel; + + tocsec = h->toc_section; + osec = tocsec->output_section; + oindx = osec->target_index; + irel = finfo->section_info[oindx].relocs + osec->reloc_count; + irel->r_vaddr = (osec->vma + + tocsec->output_offset + + h->u.toc_offset); + if (h->indx >= 0) + irel->r_symndx = h->indx; + else + { + h->indx = -2; + irel->r_symndx = obj_raw_syment_count (output_bfd); + } + irel->r_type = R_POS; + irel->r_size = 31; + finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; + ++osec->reloc_count; + + BFD_ASSERT (h->ldindx >= 0); + ldrel.l_vaddr = irel->r_vaddr; + ldrel.l_symndx = h->ldindx; + ldrel.l_rtype = (31 << 8) | R_POS; + ldrel.l_rsecnm = oindx; + xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + ++finfo->ldrel; + } + + /* If this symbol is a specially defined function descriptor, write + it out. The first word is the address of the function code + itself, the second word is the address of the TOC, and the third + word is zero. */ + if ((h->flags & XCOFF_DESCRIPTOR) != 0 + && h->root.type == bfd_link_hash_defined + && (h->root.u.def.section + == xcoff_hash_table (finfo->info)->descriptor_section)) + { + asection *sec; + asection *osec; + int oindx; + bfd_byte *p; + struct xcoff_link_hash_entry *hentry; + asection *esec; + struct internal_reloc *irel; + struct internal_ldrel ldrel; + asection *tsec; + + sec = h->root.u.def.section; + osec = sec->output_section; + oindx = osec->target_index; + p = sec->contents + h->root.u.def.value; + + hentry = h->descriptor; + BFD_ASSERT (hentry != NULL + && (hentry->root.type == bfd_link_hash_defined + || hentry->root.type == bfd_link_hash_defweak)); + esec = hentry->root.u.def.section; + bfd_put_32 (output_bfd, + (esec->output_section->vma + + esec->output_offset + + hentry->root.u.def.value), + p); + + irel = finfo->section_info[oindx].relocs + osec->reloc_count; + irel->r_vaddr = (osec->vma + + sec->output_offset + + h->root.u.def.value); + irel->r_symndx = esec->output_section->target_index; + irel->r_type = R_POS; + irel->r_size = 31; + finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; + ++osec->reloc_count; + + ldrel.l_vaddr = irel->r_vaddr; + if (strcmp (esec->output_section->name, ".text") == 0) + ldrel.l_symndx = 0; + else if (strcmp (esec->output_section->name, ".data") == 0) + ldrel.l_symndx = 1; + else if (strcmp (esec->output_section->name, ".bss") == 0) + ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + ("%s: loader reloc in unrecognized section `%s'", + bfd_get_filename (output_bfd), + esec->output_section->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + ldrel.l_rtype = (31 << 8) | R_POS; + ldrel.l_rsecnm = oindx; + xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + ++finfo->ldrel; + + bfd_put_32 (output_bfd, xcoff_data (output_bfd)->toc, p + 4); + + tsec = coff_section_from_bfd_index (output_bfd, + xcoff_data (output_bfd)->sntoc); + + ++irel; + irel->r_vaddr = (osec->vma + + sec->output_offset + + h->root.u.def.value + + 4); + irel->r_symndx = tsec->output_section->target_index; + irel->r_type = R_POS; + irel->r_size = 31; + finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL; + ++osec->reloc_count; + + ldrel.l_vaddr = irel->r_vaddr; + if (strcmp (tsec->output_section->name, ".text") == 0) + ldrel.l_symndx = 0; + else if (strcmp (tsec->output_section->name, ".data") == 0) + ldrel.l_symndx = 1; + else if (strcmp (tsec->output_section->name, ".bss") == 0) + ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + ("%s: loader reloc in unrecognized section `%s'", + bfd_get_filename (output_bfd), + tsec->output_section->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + ldrel.l_rtype = (31 << 8) | R_POS; + ldrel.l_rsecnm = oindx; + xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + ++finfo->ldrel; + } + + if (h->indx >= 0) + return true; + + if (h->indx != -2 + && (finfo->info->strip == strip_all + || (finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, + h->root.root.string, false, false) + == NULL)))) + return true; + + if (h->indx != -2 + && (h->flags & (XCOFF_REF_REGULAR | XCOFF_DEF_REGULAR)) == 0) + return true; + + outsym = finfo->outsyms; + + memset (&aux, 0, sizeof aux); + + h->indx = obj_raw_syment_count (output_bfd); + + if (strlen (h->root.root.string) <= SYMNMLEN) + strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN); + else + { + boolean hash; + bfd_size_type indx; + + hash = true; + if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0) + hash = false; + indx = _bfd_stringtab_add (finfo->strtab, h->root.root.string, hash, + false); + if (indx == (bfd_size_type) -1) + return false; + isym._n._n_n._n_zeroes = 0; + isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; + } + + if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + { + isym.n_value = 0; + isym.n_scnum = N_UNDEF; + isym.n_sclass = C_EXT; + aux.x_csect.x_smtyp = XTY_ER; + } + else if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + struct xcoff_link_size_list *l; + + isym.n_value = (h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset + + h->root.u.def.value); + isym.n_scnum = h->root.u.def.section->output_section->target_index; + isym.n_sclass = C_HIDEXT; + aux.x_csect.x_smtyp = XTY_SD; + + if ((h->flags & XCOFF_HAS_SIZE) != 0) + { + for (l = xcoff_hash_table (finfo->info)->size_list; + l != NULL; + l = l->next) + { + if (l->h == h) + { + aux.x_csect.x_scnlen.l = l->size; + break; + } + } + } + } + else if (h->root.type == bfd_link_hash_common) + { + isym.n_value = (h->root.u.c.p->section->output_section->vma + + h->root.u.c.p->section->output_offset); + isym.n_scnum = h->root.u.c.p->section->output_section->target_index; + isym.n_sclass = C_EXT; + aux.x_csect.x_smtyp = XTY_CM; + aux.x_csect.x_scnlen.l = h->root.u.c.size; + } + else + abort (); + + isym.n_type = T_NULL; + isym.n_numaux = 1; + + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym); + outsym += bfd_coff_symesz (output_bfd); + + aux.x_csect.x_smclas = h->smclas; + + bfd_coff_swap_aux_out (output_bfd, (PTR) &aux, T_NULL, isym.n_sclass, 0, 1, + (PTR) outsym); + outsym += bfd_coff_auxesz (output_bfd); + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + /* We just output an SD symbol. Now output an LD symbol. */ + + h->indx += 2; + + isym.n_sclass = C_EXT; + bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym); + outsym += bfd_coff_symesz (output_bfd); + + aux.x_csect.x_smtyp = XTY_LD; + aux.x_csect.x_scnlen.l = obj_raw_syment_count (output_bfd); + + bfd_coff_swap_aux_out (output_bfd, (PTR) &aux, T_NULL, C_EXT, 0, 1, + (PTR) outsym); + outsym += bfd_coff_auxesz (output_bfd); + } + + if (bfd_seek (output_bfd, + (obj_sym_filepos (output_bfd) + + (obj_raw_syment_count (output_bfd) + * bfd_coff_symesz (output_bfd))), + SEEK_SET) != 0 + || (bfd_write (finfo->outsyms, outsym - finfo->outsyms, 1, output_bfd) + != (bfd_size_type) (outsym - finfo->outsyms))) + return false; + obj_raw_syment_count (output_bfd) += + (outsym - finfo->outsyms) / bfd_coff_symesz (output_bfd); + + return true; +} + +/* Handle a link order which is supposed to generate a reloc. */ + +static boolean +xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order) + bfd *output_bfd; + struct xcoff_final_link_info *finfo; + asection *output_section; + struct bfd_link_order *link_order; +{ + reloc_howto_type *howto; + struct xcoff_link_hash_entry *h; + asection *hsec; + bfd_vma hval; + bfd_vma addend; + struct internal_reloc *irel; + struct xcoff_link_hash_entry **rel_hash_ptr; + struct internal_ldrel ldrel; + + if (link_order->type == bfd_section_reloc_link_order) + { + /* We need to somehow locate a symbol in the right section. The + symbol must either have a value of zero, or we must adjust + the addend by the value of the symbol. FIXME: Write this + when we need it. The old linker couldn't handle this anyhow. */ + abort (); + } + + howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + h = ((struct xcoff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, finfo->info, + link_order->u.reloc.p->u.name, + false, false, true)); + if (h == NULL) + { + if (! ((*finfo->info->callbacks->unattached_reloc) + (finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + return true; + } + + if (h->root.type == bfd_link_hash_common) + { + hsec = h->root.u.c.p->section; + hval = 0; + } + else if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + hsec = h->root.u.def.section; + hval = h->root.u.def.value; + } + else + { + hsec = NULL; + hval = 0; + } + + addend = link_order->u.reloc.p->addend; + if (hsec != NULL) + addend += (hsec->output_section->vma + + hsec->output_offset + + hval); + + if (addend != 0) + { + bfd_size_type size; + bfd_byte *buf; + bfd_reloc_status_type rstat; + boolean ok; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == NULL) + return false; + + rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*finfo->info->callbacks->reloc_overflow) + (finfo->info, link_order->u.reloc.p->u.name, + howto->name, addend, (bfd *) NULL, (asection *) NULL, + (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + /* Store the reloc information in the right place. It will get + swapped and written out at the end of the final_link routine. */ + + irel = (finfo->section_info[output_section->target_index].relocs + + output_section->reloc_count); + rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes + + output_section->reloc_count); + + memset (irel, 0, sizeof (struct internal_reloc)); + *rel_hash_ptr = NULL; + + irel->r_vaddr = output_section->vma + link_order->offset; + + if (h->indx >= 0) + irel->r_symndx = h->indx; + else + { + /* Set the index to -2 to force this symbol to get written out. */ + h->indx = -2; + *rel_hash_ptr = h; + irel->r_symndx = 0; + } + + irel->r_type = howto->type; + irel->r_size = howto->bitsize - 1; + if (howto->complain_on_overflow == complain_overflow_signed) + irel->r_size |= 0x80; + + ++output_section->reloc_count; + + /* Now output the reloc to the .loader section. */ + + ldrel.l_vaddr = irel->r_vaddr; + + if (hsec != NULL) + { + const char *secname; + + secname = hsec->output_section->name; + + if (strcmp (secname, ".text") == 0) + ldrel.l_symndx = 0; + else if (strcmp (secname, ".data") == 0) + ldrel.l_symndx = 1; + else if (strcmp (secname, ".bss") == 0) + ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + ("%s: loader reloc in unrecognized section `%s'", + bfd_get_filename (output_bfd), secname); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + } + else + { + if (h->ldindx < 0) + { + (*_bfd_error_handler) + ("%s: `%s' in loader reloc but not loader sym", + bfd_get_filename (output_bfd), + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return false; + } + ldrel.l_symndx = h->ldindx; + } + + ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; + ldrel.l_rsecnm = output_section->target_index; + xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel); + ++finfo->ldrel; + + return true; +} + +/* Sort relocs by VMA. This is called via qsort. */ + +static int +xcoff_sort_relocs (p1, p2) + const PTR p1; + const PTR p2; +{ + const struct internal_reloc *r1 = (const struct internal_reloc *) p1; + const struct internal_reloc *r2 = (const struct internal_reloc *) p2; + + if (r1->r_vaddr > r2->r_vaddr) + return 1; + else if (r1->r_vaddr < r2->r_vaddr) + return -1; + else + return 0; +} + +/* This is the relocation function for the RS/6000/POWER/PowerPC. + This is currently the only processor which uses XCOFF; I hope that + will never change. */ + +boolean +_bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd, + input_section, contents, relocs, syms, + sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + struct internal_reloc *relocs; + struct internal_syment *syms; + asection **sections; +{ + struct internal_reloc *rel; + struct internal_reloc *relend; + + rel = relocs; + relend = rel + input_section->reloc_count; + for (; rel < relend; rel++) + { + long symndx; + struct xcoff_link_hash_entry *h; + struct internal_syment *sym; + bfd_vma addend; + bfd_vma val; + struct reloc_howto_struct howto; + bfd_reloc_status_type rstat; + + /* Relocation type R_REF is a special relocation type which is + merely used to prevent garbage collection from occurring for + the csect including the symbol which it references. */ + if (rel->r_type == R_REF) + continue; + + symndx = rel->r_symndx; + + if (symndx == -1) + { + h = NULL; + sym = NULL; + addend = 0; + } + else + { + h = obj_xcoff_sym_hashes (input_bfd)[symndx]; + sym = syms + symndx; + addend = - sym->n_value; + } + + /* We build the howto information on the fly. */ + + howto.type = rel->r_type; + howto.rightshift = 0; + howto.size = 2; + howto.bitsize = (rel->r_size & 0x1f) + 1; + howto.pc_relative = false; + howto.bitpos = 0; + if ((rel->r_size & 0x80) != 0) + howto.complain_on_overflow = complain_overflow_signed; + else + howto.complain_on_overflow = complain_overflow_bitfield; + howto.special_function = NULL; + howto.name = "internal"; + howto.partial_inplace = true; + if (howto.bitsize == 32) + howto.src_mask = howto.dst_mask = 0xffffffff; + else + { + howto.src_mask = howto.dst_mask = (1 << howto.bitsize) - 1; + if (howto.bitsize == 16) + howto.size = 1; + } + howto.pcrel_offset = false; + + val = 0; + + if (h == NULL) + { + asection *sec; + + if (symndx == -1) + { + sec = bfd_abs_section_ptr; + val = 0; + } + else + { + sec = sections[symndx]; + /* Hack to make sure we use the right TOC anchor value + if this reloc is against the TOC anchor. */ + if (sec->name[3] == '0' + && strcmp (sec->name, ".tc0") == 0) + val = xcoff_data (output_bfd)->toc; + else + val = (sec->output_section->vma + + sec->output_offset + + sym->n_value + - sec->vma); + } + } + else + { + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + asection *sec; + + sec = h->root.u.def.section; + val = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_common) + { + asection *sec; + + sec = h->root.u.c.p->section; + val = (sec->output_section->vma + + sec->output_offset); + } + else if ((h->flags & XCOFF_DEF_DYNAMIC) != 0 + || (h->flags & XCOFF_IMPORT) != 0) + { + /* Every symbol in a shared object is defined somewhere. */ + val = 0; + } + else if (! info->relocateable + && ! info->shared) + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, input_section, + rel->r_vaddr - input_section->vma))) + return false; + } + } + + /* I took the relocation type definitions from two documents: + the PowerPC AIX Version 4 Application Binary Interface, First + Edition (April 1992), and the PowerOpen ABI, Big-Endian + 32-Bit Hardware Implementation (June 30, 1994). Differences + between the documents are noted below. */ + + switch (rel->r_type) + { + case R_RTB: + case R_RRTBI: + case R_RRTBA: + /* These relocs are defined by the PowerPC ABI to be + relative branches which use half of the difference + between the symbol and the program counter. I can't + quite figure out when this is useful. These relocs are + not defined by the PowerOpen ABI. */ + default: + (*_bfd_error_handler) + ("%s: unsupported relocation type 0x%02x", + bfd_get_filename (input_bfd), (unsigned int) rel->r_type); + bfd_set_error (bfd_error_bad_value); + return false; + case R_POS: + /* Simple positive relocation. */ + break; + case R_NEG: + /* Simple negative relocation. */ + val = - val; + break; + case R_REL: + /* Simple PC relative relocation. */ + howto.pc_relative = true; + break; + case R_TOC: + /* TOC relative relocation. The value in the instruction in + the input file is the offset from the input file TOC to + the desired location. We want the offset from the final + TOC to the desired location. We have: + isym = iTOC + in + iinsn = in + o + osym = oTOC + on + oinsn = on + o + so we must change insn by on - in. + */ + case R_GL: + /* Global linkage relocation. The value of this relocation + is the address of the entry in the TOC section. */ + case R_TCL: + /* Local object TOC address. I can't figure out the + difference between this and case R_GL. */ + case R_TRL: + /* TOC relative relocation. A TOC relative load instruction + which may be changed to a load address instruction. + FIXME: We don't currently implement this optimization. */ + case R_TRLA: + /* TOC relative relocation. This is a TOC relative load + address instruction which may be changed to a load + instruction. FIXME: I don't know if this is the correct + implementation. */ + if (h != NULL && h->toc_section == NULL) + { + (*_bfd_error_handler) + ("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry", + bfd_get_filename (input_bfd), rel->r_vaddr, + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return false; + } + if (h != NULL) + { + BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0); + val = (h->toc_section->output_section->vma + + h->toc_section->output_offset); + } + val = ((val - xcoff_data (output_bfd)->toc) + - (sym->n_value - xcoff_data (input_bfd)->toc)); + addend = 0; + break; + case R_BA: + /* Absolute branch. We don't want to mess with the lower + two bits of the instruction. */ + case R_CAI: + /* The PowerPC ABI defines this as an absolute call which + may be modified to become a relative call. The PowerOpen + ABI does not define this relocation type. */ + case R_RBA: + /* Absolute branch which may be modified to become a + relative branch. */ + case R_RBAC: + /* The PowerPC ABI defines this as an absolute branch to a + fixed address which may be modified to an absolute branch + to a symbol. The PowerOpen ABI does not define this + relocation type. */ + case R_RBRC: + /* The PowerPC ABI defines this as an absolute branch to a + fixed address which may be modified to a relative branch. + The PowerOpen ABI does not define this relocation type. */ + howto.src_mask &= ~3; + howto.dst_mask = howto.src_mask; + break; + case R_BR: + /* Relative branch. We don't want to mess with the lower + two bits of the instruction. */ + case R_CREL: + /* The PowerPC ABI defines this as a relative call which may + be modified to become an absolute call. The PowerOpen + ABI does not define this relocation type. */ + case R_RBR: + /* A relative branch which may be modified to become an + absolute branch. FIXME: We don't implement this, + although we should for symbols of storage mapping class + XMC_XO. */ + howto.pc_relative = true; + howto.src_mask &= ~3; + howto.dst_mask = howto.src_mask; + break; + case R_RL: + /* The PowerPC AIX ABI describes this as a load which may be + changed to a load address. The PowerOpen ABI says this + is the same as case R_POS. */ + break; + case R_RLA: + /* The PowerPC AIX ABI describes this as a load address + which may be changed to a load. The PowerOpen ABI says + this is the same as R_POS. */ + break; + } + + /* If we see an R_BR or R_RBR reloc which is jumping to global + linkage code, and it is followed by an appropriate cror nop + instruction, we replace the cror with lwz r2,20(r1). This + restores the TOC after the glink code. Contrariwise, if the + call is followed by a lwz r2,20(r1), but the call is not + going to global linkage code, we can replace the load with a + cror. */ + if ((rel->r_type == R_BR || rel->r_type == R_RBR) + && h != NULL + && h->root.type == bfd_link_hash_defined + && (rel->r_vaddr - input_section->vma + 8 + <= input_section->_cooked_size)) + { + bfd_byte *pnext; + unsigned long next; + + pnext = contents + (rel->r_vaddr - input_section->vma) + 4; + next = bfd_get_32 (input_bfd, pnext); + if (h->smclas == XMC_GL) + { + if (next == 0x4def7b82 /* cror 15,15,15 */ + || next == 0x4ffffb82) /* cror 31,31,31 */ + bfd_put_32 (input_bfd, 0x80410014, pnext); /* lwz r1,20(r1) */ + } + else + { + if (next == 0x80410014) /* lwz r1,20(r1) */ + bfd_put_32 (input_bfd, 0x4ffffb82, pnext); /* cror 31,31,31 */ + } + } + + /* A PC relative reloc includes the section address. */ + if (howto.pc_relative) + addend += input_section->vma; + + rstat = _bfd_final_link_relocate (&howto, input_bfd, input_section, + contents, + rel->r_vaddr - input_section->vma, + val, addend); + + switch (rstat) + { + default: + abort (); + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + { + const char *name; + char buf[SYMNMLEN + 1]; + char howto_name[10]; + + if (symndx == -1) + name = "*ABS*"; + else if (h != NULL) + name = h->root.root.string; + else + { + name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); + if (name == NULL) + return false; + } + sprintf (howto_name, "0x%02x", rel->r_type); + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto_name, (bfd_vma) 0, input_bfd, + input_section, rel->r_vaddr - input_section->vma))) + return false; + } + } + } + + return true; +} diff --git a/contrib/gdb/gdb/.gdbinit b/contrib/gdb/gdb/.gdbinit new file mode 100644 index 000000000000..f60802e50093 --- /dev/null +++ b/contrib/gdb/gdb/.gdbinit @@ -0,0 +1,16 @@ +echo Setting up the environment for debugging gdb.\n + +set complaints 1 + +b fatal + +b info_command +commands + silent + return +end + +dir ../mmalloc +dir ../libiberty +dir ../bfd +set prompt (top-gdb) diff --git a/contrib/gdb/gdb/COPYING b/contrib/gdb/gdb/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/contrib/gdb/gdb/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/gdb/gdb/ChangeLog b/contrib/gdb/gdb/ChangeLog new file mode 100644 index 000000000000..0ee1d9cad322 --- /dev/null +++ b/contrib/gdb/gdb/ChangeLog @@ -0,0 +1,1415 @@ +Mon Apr 22 20:17:01 1996 Fred Fish + + * Makefile.in (VERSION): Bump version number to 4.16 + * NEWS: Update for 4.16 release. + +Fri Apr 12 21:39:42 1996 Fred Fish + + * Makefile.in (VERSION): Bump version to 4.15.86 + * README: Update for 4.16 release. + * configure.in (AC_CHECK_FUNCS): Also check for sbrk. + * configure: Regenerate with autoconf. + * config.in: Regenerate with autoheader. + * main.c (main): Only use sbrk() when HAVE_SBRK is defined. + * top.c (command_loop): Ditto. + +Thu Apr 11 17:51:58 1996 Fred Fish + + From: Miles Bader + * configure.in (AC_CHECK_HEADERS): check for endian.h. + Use AC_CHECK_TOOL to find AR & RANLIB. Add AC_PROG_AWK. + Add host & target cases for i[345]86-*-gnu*. + * config.in: Regenerate with autoheader. + * configure: Regenerate with autoconf. + * Makefile.in (AR, AWK): Set from corresponding autoconf substs. + (init.c): Don't scan mig-generated files. + * defs.h (endian.h): Include if HAVE_ENDIAN_H defined. + * config/nm-m3.h (ATTACH_NO_WAIT): Define. + * infcmd.c (attach_command): Use "#ifndef ATTACH_NO_WAIT" + rather than "#ifndef MACH". + +Mon Apr 8 12:53:56 1996 Fred Fish + + * Makefile.in (scm-exp.o, scm-lang.o, scm-valprint.o): Add targets and + dependencies. + * scm-lang.c (gdb_string.h): Include. + * objfiles.c (add_to_objfile_sections): Cast second arg of obstack_grow + call to correct type (char *). + * cp-valprint.c (cp_print_static_field): Ditto. + * somsolib.c (som_solib_create_inferior_hook): Add a declaration + for external find_unwind_entry function (from hppa-tdep.c). + * remote-pa.c (remote_write_bytes, remote_read_bytes): Change + type of second arg to "char *" to be type compatible with + dcache. + (remote_wait): Cast second arg to strtol to correct type. + * hppa-tdep.c (compare_unwind_entries): Change argument types to + "const void *" to be type compatible with qsort, and then + assign to local args prior to use. + +Sun Apr 7 22:34:29 1996 Fred Fish + + From: Miles Bader + * gnu-nat.c, gnu-nat.h, msg.defs, exc_request.defs, i386gnu-nat.c, + msg_reply.defs, notify.defs, process_reply.defs, reply_mig_hack.awk, + config/nm-gnu.h, config/i386/{i386gnu.mh, i386gnu.mt, nm-gnu.h, + m-i386gnu.h, xm-i386gnu.h}: New files for GNU hurd. + +Sun Apr 7 13:32:41 1996 Fred Fish + + * configure.in (case host): Add i386sco5 host. + * configure: Regenerate. + + From: Robert Lipe + Add support for SCO OpenServer 5 (a.k.a. 3.2v5*) This + target is an SVR3.2 with COFF, ELF, and shared libes, but + no /proc. + * config/i386/i386sco5.mh: New file. + * config/i386/nm-i386sco5.h: New file. + +Sat Apr 6 08:55:22 1996 Fred Fish + + * bcache.c (bcache): When size of chunk to cache is exactly equal to + BCACHE_MAXLENGTH, stash chunk as unique copy. + +Sat Apr 6 00:46:26 1996 Fred Fish + + * symfile.c (INLINE_ADD_PSYMBOL): Remove ifdef. + (add_psymbol_to_list): Add an arg for passing CORE_ADDR values and + use it, rather than calling add_psymbol_addr_to_list. + (add_psymbol_addr_to_list): Delete. + (add_psymbol_to_list): Make psymbol static to avoid random data in + gaps due to alignment of structure members. + * symfile.h (INLINE_ADD_PSYMBOL, ADD_PSYMBOL_TO_LIST, + ADD_PSYMBOL_ADDR_TO_LIST): Remove. Real world tests show no + performance improvements by inlining via complicated macros and + they just make gdb larger and harder to maintain. + * dwarfread.c (add_enum_psymbol): Replace ADD_PSYMBOL_TO_LIST + and/or ADD_PSYMBOL_ADDR_TO_LIST macro(s) with call to + add_psymbol_to_list with appropriate long or CORE_ADDR args. + (add_partial_symbol): Ditto. + * partial-stab.h: Ditto. + * os9kread.c (read_os9k_psymtab): Ditto + * mdebugread.c (parse_partial_symbols): Ditto. + (handle_psymbol_enumerators): Ditto. + (demangle.h): Include. + * hpread.c (hpread_build_psymtabs): Ditto. + (hpread_build_psymtabs): Ditto. + (demangle.h): Include + +Thu Apr 4 17:59:58 1996 Fred Fish + + * configure.in: Check for setpgid function. + * config.in: Regenerate with autoheader. + * configure: Regenerate with autoconf. + * inflow.c (_initialize_inflow): Only try to use _SC_JOB_CONTROL + if it is actually defined. + (gdb_setpgid): Use HAVE_SETPGID. + * ch-exp.c: Change include of to "gdb_string.h". + * c-exp.y: Ditto. + * f-exp.y: Ditto. + * m2-exp.y: Ditto. + * c-exp.y: Include . + * serial.c: Ditto. + * config/m68k/nm-news.h: Add typedef for pid_t which is + apparently missing from . Enclose entire + file in NM_NEWS_H ifndef and define when included. + * config/mips/nm-news-mips.h: Ditto. + * config/m68k/tm-m68k.h (REGISTER_CONVERT_TO_VIRTUAL, + REGISTER_CONVERT_TO_RAW): Change name of temporary variable. + +Thu Apr 4 17:17:53 1996 Fred Fish + + * symmisc.c (print_objfile_statistics): Print memory used by + psymbol cache obstack. + +Mon Apr 1 16:31:00 1996 Stan Shebs + + * mpw-make.sed: Change references to config.h to be in objdir, + edit out rules to rebuild config.h. + +Mon Apr 1 08:32:23 1996 Fred Fish + + * hppa-tdep.c (hppa_pop_frame): Call clear_proceed_status before + proceeding. + +Sun Mar 31 16:15:43 1996 Fred Fish + + * hppah-nat.c (store_inferior_registers, store_inferior_registers, + fetch_register, child_xfer_memory): Use call_ptrace function supplied + by infptrace.c rather than calling ptrace directly. + +Sat Mar 30 11:00:22 1996 Fred Fish + + * configure.in: Check whether printf family supports printing + long doubles or not and define PRINTF_HAS_LONG_DOUBLE if so. + * acconfig.h: Provide default undef for PRINTF_HAS_LONG_DOUBLE. + * configure: Regenerate. + * valprint.c (print_floating): Use PRINTF_HAS_LONG_DOUBLE. + * c-exp.y (parse_number): Use PRINTF_HAS_LONG_DOUBLE. + * configure.in: Fix have_gregset and have_fpregset autoconf + variable names so that they match the pattern required to + cache them. + +Fri Mar 29 21:53:14 1996 Fred Fish + + * core-aout.c (fetch_core_registers): Cast core_reg_size to int + before testing against reg_ptr. + * eval.c (evaluate_subexp_standard): Cast type of + TYPE_FN_FIELD_VOFFSET to int. + * findvar.c (extract_signed_integer, extract_unsigned_integer, + extract_long_unsigned_integer): Cast type of sizeof to int. + * values.c (unpack_field_as_long, modify_field): Ditto. + * valops.c (value_assign, call_function_by_hand): Ditto. + * infcmd.c (do_registers_info): Ditto. + * ser-tcp.c (tcp_open): Ditto + * remote.c (putpkt): Ditto. + * dcache.c (dcache_peek): Ditto. + * dcache.c (dcache_poke): Ditto. + * m2-exp.y (yylex): Ditto. + * gnu-regex.c (re_match_2): Ditto. + * f-lang.c (ADD_BF_SYMNUM, saved_bf_list_end, tmp_bf_ptr): Ifdef + out unused macro definition and variables. + * inftarg.c (proc_wait): Move from main.c to here, and make static. + * valprint.c (val_print_string): Change bufsize from int to unsigned. + * main.c (wait.h): Include + * top.c (command_line_input): Remove unused variable "c". + * f-typeprint.c (f_type_print_varspec_prefix): Add missing enum + value TYPE_CODE_TYPEDEF to switch statement. + (f_type_print_varspec_suffix): Add missing enum value + TYPE_CODE_TYPEDEF to switch statement. + * ch-exp.c (parse_primval): Add remaining enumeration values to + switch statement, with no specific action. + (ch_lex): Add LOC_UNRESOLVED in switch statement. + (pushback_token): Ifdef out, since code using it is ifdef'd out. + * stabsread.c (cleanup_undefined_types): Remove unused label + "badtype". + * objfiles.h (print_symbol_bcache_statistics): Add prototype. + * maint.c (objfiles.h): Include. + (maintenance_print_statistics): Remove unused variable "temp". + * minsyms.c (lookup_minimal_symbol_solib_trampoline): Remove + unused variable "found_file_symbol". + * m2-exp.y (yylex): Add LOC_UNRESOLVED case to switch. + * language.c (lang_bool_type): Use existing function local type + variable rather than create block local variables. + * solib.c (disable_break): Enclose in ifndef SVR4_SHARED_LIBS. + * infptrace.c (wait.h, command.h): Include. + * ser-tcp.c (gdb_string.h): Include + * i386-tdep.c (codestream_seek): Change "place" to CORE_ADDR. + (i386_get_frame_setup): Change "pc" from int to CORE_ADDR. + * command.c (complete_on_enum): Make assignment used as truth value + explictly check against NULL. + (wait.h): Include. + * infrun.c (wait_for_inferior): Ifdef out prologue_pc since code + that uses it is ifdef'd out. + * parser-defs.h: Add prototype for write_dollar_variable. + * infrun.c: Add prototype for write_pc_pid. + * breakpoint.h: Add prototype for re_enable_breakpoints_in_shlibs. + * symmisc.c (bcache.h): Include. + * bcache.h: Add prototype for print_bcache_statistics. + * symfile.c: Include . + * printcmd.c (print_scalar_formatted): Change len to unsigned int. + * valarith.c (value_equal): Cast result of TYPE_LENGTH to int. + * valarith.c (value_binop): Change result_len, promoted_len1, + and promoted_len2 to unsigned int. + * valarith.c (value_subscripted_rvalue): Change elt_offs and + elt_size to unsigned int. + * valops.c (value_array): Change typelength to unsigned int. + (destructor_name_p): Change len to unsigned int. + * scm-lang.h (scm_parse): Add prototype for scm_unpack. + * symfile.c (decrement_reading_symtab): Change return type to void. + * valarith.c (value_subscript): Remove unused variable "word". + (value_subscript): Remove unused variable "tint". + * valops.c (auto_abandon): Ifdef out, since code using it is also + ifdef'd out. + * eval.c (init_array_element): Remove unused variable "val". + * Makefile.in (values.o): Depends on scm-lang.h. + (command.o): Depends upon wait_h. + (ser-tcp.o): Depends upon gdb_string.h. + (infptrace.o): Depends upon wait_h and command_h. + (maint.o): Depends on objfiles.h and symfile.h. + * values.c (allocate_repeat_value): Remove unused variable + "element_type". + (scm-lang.h): Include. + * breakpoint.c (create_longjmp_breakpoint): Enclose in + GET_LONGJMP_TARGET define, unused otherwise. + * config/i386/nm-linux.h: Add prototypes for i386_insert_watchpoint, + i386_remove_watchpoint and i386_stopped_by_watchpoint. + +Thu Mar 28 06:51:26 1996 Fred Fish + + * valops.c (value_assign): Make copy of internal variable value + before returning it as a new value, since it is owned by the + internal variable and will be freed along with it. + +Wed Mar 27 12:54:55 1996 Fred Fish + + From Peter Schauer + * breakpoint.c (breakpoint_re_set_one): Keep temporary + breakpoints bp_until, bp_finish, bp_watchpoint_cope, bp_call_dummy + and bp_step_resume in case breakpoint_re_set_one is called due + to a step over a dlopen call. + * infrun.c (wait_for_inferior): Always remove breakpoints from + inferior in BPSTAT_WHAT_CHECK_SHLIBS case. + +Tue Mar 26 13:15:32 1996 Fred Fish + + * Makefile.in (VERSION): Bump version to 4.15.85 + + * config/mips/tm-mips.h (COERCE_FLOAT_TO_DOUBLE): Only prefer + non-prototyped case over prototyped case for C. + * config/pa/tm-hppa.h (COERCE_FLOAT_TO_DOUBLE): Ditto. + +Sat Mar 23 15:50:47 1996 Fred Fish + + * os9kread.c (os9k_process_one_symbol): Note nonportable + assumption that an int can hold a char *. + + * bcache.h (struct hashlink): Wrap data[] inside union with + double to force longest alignment. + (BCACHE_DATA): New macro to access data[]. + (BCACHE_ALIGNMENT): New macro to get offset to data[]. + * bcache.c (lookup_cache, bcache): Use BCACHE_DATA to get + address of cached data. Use BCACHE_ALIGNMENT to compute + amount of space to allocate for each hashlink struct. + +Sat Mar 23 12:14:02 1996 Fred Fish + + * ch-lang.c (evaluate_subexp_chill): Fix typo. + +Thu Mar 21 08:27:19 1996 Fred Fish + + * Makefile.in (VERSION): Bump version to 4.15.3 + +Thu Mar 21 10:56:41 1996 Ian Lance Taylor + + * config.in: Rename from config.h.in. + * configure.in: Call AC_CONFIG_HEADER with config.h:config.in. + Change CONFIG_HEADERS test in AC_OUTPUT accordingly. + * configure: Rebuild. + * Makefile.in (stamp-h): Depend upon config.in, not config.h.in. + Set CONFIG_HEADERS to config.h:config.in. + +Tue Mar 19 12:47:51 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * partial-stab.h (case N_ENDM): Finish current partial symbol + table for Solaris 2 cc. + +Tue Mar 19 10:39:15 1996 Jeffrey A Law (law@cygnus.com) + + * rs6000-nat.c (exec_one_dummy_insn): Don't clobber the + PC in the registers array. From Peter Schauer. + +Mon Mar 18 13:47:09 1996 Fred Fish + + * symfile.c (reread_symbols): Reinitialize bcache struct + members to zero using memset. Also use memset to reinit + global_psymbols and static_psymbols, rather than explicitly + resetting each structure member. + +Sat Mar 16 19:47:36 1996 Fred Fish + + * configure.in: Add fragment to create stamp-h. + + From Peter Schauer + * configure.in (AC_CHECK_HEADERS): Check for link.h. + * configure: Regenerate with autoconf. + * config.h.in: Regenerate with autoheader. + * config/i386/nm-linux.h: Include solib.h only if HAVE_LINK_H + is defined. + * solib.c: Exclude most of the code if HAVE_LINK_H is not defined. + * config/i386/linux.mh: Reinstate XM_CLIBS, it is needed for + older a.out based systems. + +Sat Mar 16 16:45:43 1996 Fred Fish + + * config.h.in: New file. + * acconfig.h: New file, for autoheader. + * configure.in (AC_CONFIG_HEADER): Add, generate config.h. + * configure: Regenerate. + * Makefile.in (defs_h): Add config.h + (distclean): Remove config.h and stamp-h during distclean. + (config.h, stamp-h): New targets to remake config.h when necessary. + * defs.h (config.h): Include before any other includes or defines. + * i386-tdep.c (gdb_string.h): Move include after include of defs.h. + * i386v4-nat.c (defs.h): Include before testing HAVE_SYS_PROCFS_H. + +Sat Mar 16 14:55:27 1996 Fred Fish + + From Peter Schauer + * Makefile.in (INSTALLED_LIBS): Make sure that @LIBS@ will not + result in an empty line, to work around a bug in native Ultrix 4.4 + and OSF/1-3.2C make. + +Sat Mar 16 13:33:17 1996 Fred Fish + + * configure.in: Add gdbserver to configdirs under linux. + * configure: Regenerate. + +Fri Mar 15 12:06:58 1996 J.T. Conklin + + * config/i386/nm-nbsd.h (FLOAT_INFO): Comment out. + * config/i386/tm-nbsd.h (NUM_REGS): Define. + +Thu Mar 14 10:31:18 1996 Jeffrey A Law (law@cygnus.com) + + * solib.c (solib_break_names): Add _r_debug_state for + vanilla SVR4 implementations. From Peter Schauer. + +Mon Mar 11 14:24:57 1996 Dawn Perchik + + * mon960-rom.c: New file; support mon960 rom monitor on i960. + * monitor.c (monitor_debug): Change remotedebug to buffer strings. + * monitor.c (monitor_open): Add test for flag MO_NO_ECHO_ON_OPEN before + epecting prompt and echo during open. + * monitor.c (monitor_stop): Add test for flag MO_SEND_BREAK_ON_OPEN to + determine if break should be sent as stop command. + * monitor.h: Add flags MO_NO_ECHO_ON_OPEN and MO_SEND_BREAK_ON_OPEN. + * i960-tdep.c (mon960_frame_chain_valid): New function for getting + stack frame on mon960. + * Makefile.in: Add mon960 files. + * configure.in: Changed i960-*-coff* and i960-*-elf* to target mon960; + added i960-nindy-coff* and i960-nindy-elf* for target nindy. + * configure: Regenerated. + * config/i960/mon960.mt, config/i960/tm-mon960.h: New files; + support mon960 rom monitor on i960. + +Mon Mar 11 11:02:47 1996 Steve Chamberlain + + With Michael Snyder: + * i386-tdep.c (skip_trampoline_code): Fix strncmp length. + * win32-nat.c (CHECK, DEBUG*, debug_*): New. + (handle_load_dll): Don't reload symbols. + (handle_exception): Use the DEBUG_* names. + (child_wait): Add DEBUG_* code. + (_initialize_inftarg): Add new commands to set debug_ names. + +Mon Mar 11 09:19:58 1996 Jeffrey A Law (law@cygnus.com) + + * From Peter Schauer: + * breakpoint.c (insert_breakpoints): Use ALL_BREAKPOINTS_SAFE. + (bpstat_stop_status): Likewise. + (remove_solib_event_breakpoints): Likewise. + (clear_momentary_breakpoints): Likewise. + (re_enable_breakpoints_in_shlibs): Don't reenable a breakpoint + if we still can't read the memory for that breakpoint. + (mention): Add bp_shlib_event case to keep gcc quiet. + +Fri Mar 8 12:08:12 1996 Jeffrey A Law (law@cygnus.com) + + * breakpoint.h (enum enable): New enum shlib_disabled for + shared library breakpoints that have been temporarily disabled. + * breakpoint.c: Handle temporarily disabled shared library + breakpoints like disabled breakpoints in most places. + (insert_breakpoints): Use shlib_disabled to indicate + that an unsettable breakpoint is only temporarily disabled. + (re_enable_breakpoints_in_shlibs): New function. + * corelow.c (solib_add_stub): After adding shared libraries, + try to reenable any temporarily disabled breakpoints. + * infcmd.c (attach_command): Likewise. + * infrun.c (wait_for_inferior): Likewise. + +Fri Mar 8 11:41:25 1996 Ian Lance Taylor + + * defs.h (extract_long_unsigned_integer): Declare. + * findvar.c (extract_long_unsigned_integer): New function. + * printcmd.c (print_scalar_formatted): Use it. + * valprint.c (val_print_type_code_int): Likewise. + +Thu Mar 7 17:40:50 1996 Stan Shebs + + * infcmd.c (do_registers_info): Ignore anonymous registers. + * sh-tdep.c (set processor): New command to set specific + processor type. + (sh_reg_names, sh3_reg_names): Arrays of register names for + SH and SH3 processors. + (sh_set_processor_type): New function. + * sh3-rom.c (sh3_open): Call it. + (sh3_regname): Add names of all the bank registers. + (sh3_supply_register): Clean up formatting. + * config/sh/tm-sh.h (NUM_REGS, NUM_REALREGS): Increase to include + bank registers. + (REGISTER_NAMES): Add names of bank registers. + (FP15_REGNUM): Define. + (REGISTER_VIRTUAL_TYPE): Use it. + * monitor.c: Clean up some comments. + +Thu Mar 7 12:09:51 1996 J.T. Conklin + + * i386b-nat.c: Revert part of Mar 5 change. FreeBSD collapsed the + s* and t* symbols too. + +Thu Mar 7 15:18:51 1996 James G. Smith + + * symfile.c (generic_load): Avoid division by zero. + +Wed Mar 6 17:57:59 1996 Jeffrey A Law (law@cygnus.com) + + * breakpoint.c (bfd_lookup_symbol): Provide for all SVR4 systems, + not just those with HANDLE_SVR4_EXEC_EMULATORS. + + From Peter Schauer: + * breakpoint.c (internal_breakpoint_number): Move to file scope. + (create_solib_event_breakpoint): Use an internal breakpoint number. + +Wed Mar 6 00:32:44 1996 Wilfried Moser (Alcatel) + + * valarith.c (value_in): Change builtin_type_chill_bool to + LA_BOOL_TYPE. + +Tue Mar 5 23:48:36 1996 Wilfried Moser (Alcatel) + + * ch-exp.c (parse_primval): Handle CARD, MAX, MIN. + (match_string_literal): Handle control sequence. + (match_character_literal): Deto. + + * ch-lang.c (chill_printchar): Change formating of nonprintable + characters from C'xx' to ^(num). + (chill_printstr): Deto. + (value_chill_card, value_chill_max_min): New functions to process + Chill's CARD, MAX, MIN. + (evaluate_subexp_chill): Process UNOP_CARD, UNOP_CHMAX, UNOP_CHMIN. + + * expression.h (exp_opcode): Add UNOP_CARD, UNOP_CHMAX, UNOP_CHMIN + for Chill's CARD, MAX, MIN. + + * valarith.c (value_in): Add processing of TYPE_CODE_RANGE + and change return type from builtin_type_int to + builtin_type_chill_bool. + +Tue Mar 5 18:54:04 1996 Stan Shebs + + * config/nm-nbsd.h (link_object, lo_name, etc): Move to here + from config/nm-nbsd.h. + * config/sparc/nm-nbsd.h (regs, fp_status, etc): Move to here + from config/sparc/tm-nbsd.h. + + * config/m68k/nm-hp300hpux.h (FIVE_ARG_PTRACE): Define here + instead of in config/m68k/xm-hp300hpux.h. + +Tue Mar 5 12:05:35 1996 J.T. Conklin + + * i386b-nat.c, m68knbsd-nat.c (fetch_core_registers): Provide + implementation for NetBSD systems. + +Mon Mar 4 23:44:16 1996 Per Bothner + + * valarith.c (binop_user_defined_p): Return 0 for BINOP_CONCAT. + (value_concat): Handle varying strings (add COERCE_VARYING_ARRAY). + + * ch-lang.c (evaluate_subexp_chill case MULTI_SUBSCRIPT): Error + if "function" is pointer to non-function. + +Mon Mar 4 17:47:03 1996 Stan Shebs + + * top.c (print_gdb_version): Update copyright year. + +Mon Mar 4 14:44:54 1996 Jeffrey A Law (law@cygnus.com) + + From Peter Schauer: + * infrun.c (wait_for_inferior): Remove breakpoints and + switch terminal settings before calling SOLIB_ADD. + * solib.c (enable_break, SVR4 variant): Don't map in symbols + for the dynamic linker, the namespace pollution causes real + problems. + +Sun Mar 3 17:18:57 1996 James G. Smith + + * remote-mips.c (common_breakpoint): Explicitly terminate the + returned buffer. + +Wed Feb 28 22:32:18 1996 Stan Shebs + + From Wilfried Moser : + * remote.c (remote_detach): Send a command 'D' to the target + when detaching, update the function's comments. + +Wed Feb 28 15:50:12 1996 Fred Fish + + * Makefile.in (VERSION): Bump version to 4.15.2 to establish + baseline for gdb 4.16 rerelease testing. + +Wed Feb 28 13:32:05 1996 Jeffrey A Law (law@cygnus.com) + + * somsolib.c (som_solib_create_inferior_hook): Before returning + call clear_symtab_users. + +Tue Feb 27 00:04:46 1996 Stu Grossman (grossman@critters.cygnus.com) + + * remote-e7000.c (e7000_open): Delete all breakpoints when + connecting to e7000. Change connect message to allow use of + monitor.exp in test suite. + * (e7000_load): Print transfer rate of download. + * symfile.c (generic_load): Print transfer rate of download. + +Sun Feb 25 13:58:33 1996 Stan Shebs + + * configure.in (mips*-*-vxworks*): New config. + * configure: Regenerated. + + * config/mips/vxmips.mt, config/mips/tm-vxmips.h: New files. + * remote-vxmips.c (vx_convert_to_virtual, vx_convert_from_virtual): + Remove, never used. + +Sat Feb 24 12:30:28 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * partial-stab.h (case N_FUN): Function symbols generated + by SPARCworks cc have a meaningless zero value, do not update + pst->textlow if the function symbol value is zero. + + * stabsread.c (define_symbol): Initialize SYMBOL_TYPE field + for function prototype declaration symbols. + +Fri Feb 23 22:33:04 1996 Stu Grossman (grossman@critters.cygnus.com) + + * remote-e7000.c (e7000_load): New routine to download via the + network. + * (e7000_wait): Don't backup PC when we hit a breakpoint. + Apparantly new sh2 pods get this right... + * (e7000_ops): Add call to e7000_load. + +Thu Feb 22 00:52:42 1996 J.T. Conklin + + * config/m68k/{nbsd.mh,nbsd.mt,nm-nbsd.h,tm-nbsd.h,xm-nbsd.h}, + m68knbsd-nat.c: New files, support for NetBSD/m68k. + + * configure.in (m68k-*-netbsd*): New config. + * configure: Regenerated. + +Wed Feb 21 19:00:21 1996 Fred Fish + + * standalone.c (open, _initialize_standalone): Fix obvious typos + reported by Martin Pool . + +Wed Feb 21 14:24:04 1996 Jeffrey A Law (law@cygnus.com) + + * solib.c (solib_create_inferior_hook): Fix thinko. + +Tue Feb 20 23:59:19 1996 Jeffrey A Law (law@cygnus.com) + + * solib.c (solib_break_names): Define for Solaris and Linux. + (enable_break): For SVR4 systems, first try to use the debugger + interfaces in the dynamic linker to track shared library events + as they happen, then fall back to BKPT_AT_SYMBOL code. Convert + BKPT_AT_SYMBOL code to use shared library event breakpoints. + (solib_create_inferior_hook): Simplify BKPT_AT_SYMBOL code, + it no longer needs to restart/wait on the inferior. + * symfile.c (find_lowest_section): No longer static. + * symfile.h (find_lowest_section): Corresponding changes. + +Tue Feb 20 18:54:08 1996 Fred Fish + + * valops.c (COERCE_FLOAT_TO_DOUBLE): Define default value. + (value_arg_coerce): Use COERCE_FLOAT_TO_DOUBLE. + * config/alpha/tm-alpha.h (COERCE_FLOAT_TO_DOUBLE): Define to 1. + * config/mips/tm-mips.h: Ditto. + * config/pa/tm-hppa.h: Ditto. + * config/rs6000/tm-rs6000.h: Ditto. + * config/sparc/tm-sparc.h: Ditto. + +Tue Feb 20 17:32:05 1996 J.T. Conklin + + * config/{i386,ns32k}/nbsd.mh (NATDEPFILES): Remove core-aout.o. + + * config/nm-nbsd.h (FETCH_INFERIOR_REGISTERS): Defined. + * config/xm-nbsd.h (CC_HAS_LONG_LONG, PRINTF_HAS_LONG_LONG): + #ifdef'd out definitions --- Causes serious gdb failures on + the i386. Need to investigate further before enabling. + + * i386b-nat.c (fetch_inferior_registers, store_inferior_registers, + fetch_core_registers): New functions. These functions are defined + if FETCH_INFERIOR_REGISTERS is set. Registers are fetched/stored + with ptrace PT_GETREGS/PT_SETREGS. + +Tue Feb 20 16:55:06 1996 Stu Grossman (grossman@critters.cygnus.com) + + * findvar.c (extract_floating store_floating): Replace `long + double' with `DOUBLEST'. + +Mon Feb 19 15:25:51 1996 J.T. Conklin + + * config/xm-nbsd.h (CC_HAS_LONG_LONG, PRINTF_HAS_LONG_LONG): + Define. + +Mon Feb 19 10:32:05 1996 Jeffrey A Law (law@cygnus.com) + + * symtab.h (looup_minimal_symbol_solib_trampoline): Declare. + + * breakpoint.h (remove_solib_event_breakpoints): Declare. + * breakpoint.c (remove_solib_event_breakpoints): New function. + * somsolib.c (solib_create_inferior_hook): Remove all solib event + breakpoints before inserting any new ones. Use a solib event + breakpoint for the breakpoint at "_start". + Remove extraneous "\n" from calls to warning. + + * breakpoint.c (breakpoint_1): Add missing "sigtramp" to bptypes + name array. + +Mon Feb 19 01:09:32 1996 Doug Evans + + * dwarfread.c (add_partial_symbol): Use ADD_PSYMBOL_ADDR_TO_LIST + for CORE_ADDR values. + (new_symbol): Use SYMBOL_VALUE_ADDRESS for CORE_ADDR values. + * symfile.h (add_psymbol_{,addr}to_list): Add prototypes. + +Sun Feb 18 14:37:13 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (mipscoff_symfile_read): Unconditionally add + alpha coff dynamic symbols for all symbol files. Makes skipping + over the trampoline code work when stepping from a function in a + shared library into a function in a different shared library. + +Sun Feb 18 09:27:10 1996 Stu Grossman (grossman@cygnus.com) + + * config/sparc/tm-sparc.h: Define PS_FLAG_CARRY. Define + RETURN_VALUE_ON_STACK to return long doubles on the stack. + +Sat Feb 17 16:33:11 1996 Fred Fish + + * Makefile.in (ch-exp.o): Add dependencies. + (various): Add gdb_string.h to dependencies that need it. + +Sat Feb 17 08:57:50 1996 Fred Fish + + * symmisc.c (print_symbol_bcache_statistics): Update description for + printing byte cache statistics. + +Thu Feb 16 16:02:03 1996 Stu Grossman (grossman@cygnus.com) + + * Add native support for long double data type. + * c-exp.y (%union): Change dval to typed_val_float. Use DOUBLEST + to store actual data. Change types of INT and FLOAT tokens to + typed_val_int and typed_val_float respectively. Create new token + DOUBLE_KEYWORD to specify the string `double'. Make production + for FLOAT use type determined by parse_number. Add production for + "long double" data type. + * (parse_number): Use sscanf to parse numbers as float, double or + long double depending upon the type of typed_val_float.dval. Also + allow user to specify `f' or `l' suffix to explicitly specify + float or long double constants. Change typed_val to + typed_val_int. + * (yylex): Change typed_val to typed_val_int. Also, scan for + "double" keyword. + * coffread.c (decode_base_type): Add support for T_LNGDBL basic + type. + * configure, configure.in: Add check for long double support in + the host compiler. + * defs.h: Define DOUBLEST appropriatly depending on whether + HAVE_LONG_DOUBLE (from autoconf) is defined. Also, fix prototypes + for functions that handle this type. + * expression.h (union exp_element): doubleconst is now type + DOUBLEST. + * m2-exp.y f-exp.y (%union): dval becomes type DOUBLEST. + * findvar.c (extract_floating): Make return value be DOUBLEST. + Also, add support for numbers with size of long double. + * (store_floating): Arg `val' is now type DOUBLEST. Handle all + floating types. + * parser-defs.h parse.c (write_exp_elt_dblcst): Arg expelt is now + DOUBLEST. + * valarith.c (value_binop): Change temp variables v1, v2 and v to + type DOUBLEST. Coerce type of result to long double if either op + was of that type. + * valops.c (value_arg_coerce): If argument type is bigger than + double, coerce to long double. + * (call_function_by_hand): If REG_STRUCT_HAS_ADDR is defined, and + arg type is float and > 8 bytes, then use pointer-to-object + calling conventions. + * valprint.c (print_floating): Arg doub is now type DOUBLEST. + Use appropriate format and precision to print out floating point + values. + * value.h: Fixup prototypes for value_as_double, + value_from_double, and unpack_double to use DOUBLEST. + * values.c (record_latest_value): Remove check for invalid + floats. Allow history to store them so that people may examine + them in hex if they want. + * (value_as_double unpack_double): Change return value to DOUBLEST. + * (value_from_double): Arg `num' is now DOUBLEST. + * (using_struct_return): Use RETURN_VALUE_ON_STACK macro (target + specific) to expect certain types to always be returned on the stack. + +Fri Feb 16 14:00:54 1996 Fred Fish + + * bcache.c, bcache.h: New files to implement a byte cache. + * Makefile.in (SFILES): Add bcache.c. + (symtab_h): Add bcache.h. + (HFILES_NO_SRCDIR): add bcache.h + (COMMON_OBJS): Add bcache.o + (bcache.o): New target. + * dbxread.c (start_psymtab): Make global_syms & static_syms + type "partial_symbol **". + * hpread.c (hpread_start_symtab): Ditto. + * os9kread.c (os9k_start_psymtab): Ditto. + * stabsread.h (start_psymtab): Ditto. + * {symfile.c, symfile.h} (start_psymtab_common): Ditto. + * maint.c (maintenance_print_statistics): Call + print_symbol_bcache_statistics. + * objfiles.c (allocate_objfile): Initialize psymbol bcache malloc + and free pointers. + * solib.c (allocate_rt_common_objfile): Ditto. + * symfile.c (reread_symbols): Ditto. + (free_objfile): Free psymbol bcache when objfile is freed. + (objfile_relocate): Use new indirect psymbol pointers. + * objfiles.h (struct objfile): Add psymbol cache. + * symfile.c (compare_psymbols): Now passed pointers to pointers to + psymbols. + (reread_symbols): Free psymbol bcache when freeing other objfile + resources. + (add_psymbol_to_list, add_psymbol_addr_to_list): Initialize new + psymbol using the psymbol bcache. + (init_psymbol_list): Psymbol lists now contain pointers rather than + the actual psymbols. + * symfile.h (psymbol_allocation_list): Psymbol lists now dynamically + grown arrays of pointers. + (ADD_PSYMBOL_VT_TO_LIST): Initialize new symbol using the psymbol + bcache. + * symmisc.c (print_partial_symbols): Now takes pointer to pointer + to partial symbol. + (print_symbol_bcache_statistics): New function to print per objfile + bcache statistics. + (print_partial_symbol, print_partial_symbols, + maintenance_check_symtabs, extend_psymbol_list): + Account for change to pointer to pointer to partial symbol. + * symtab.c (find_pc_psymbol, lookup_partial_symbol, decode_line_2, + make_symbol_completion_list): + Account for change to pointer to pointer to partial symbol. + * symtab.h (bcache.h): Include. + * xcoffread.c (xcoff_start_psymtab): Make global_syms & static_syms + type "partial_symbol **". + +Fri Feb 16 10:02:34 1996 Fred Fish + + * dwarfread.c (free_utypes): New function. + (read_file_scope): Call free_utypes as cleanup, rather than just + freeing the utypes pointer. + +Thu Feb 15 21:40:52 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * demangle.c (is_cplus_marker): New function, checks if a + character is one of the commonly used C++ marker characters. + * defs.h (is_cplus_marker): Add prototype. + * c-typeprint.c (c_type_print_base), ch-lang.c (chill_demangle), + cp-valprint.c (cp_print_class_method), mdebugread.c (parse_symbol), + stabsread.c (define_symbol, read_member_functions, read_struct_fields), + symtab.h (OPNAME_PREFIX_P, VTBL_PREFIX_P, DESTRUCTOR_PREFIX_P), + values.c (vb_match): Use is_cplus_marker instead of comparison + with CPLUS_MARKER. + +Thu Feb 15 18:08:13 1996 Fred Fish + + * symfile.h (INLINE_ADD_PSYMBOL): Default this to 0 and possibly + delete entirely someday. + +Thu Feb 15 15:25:34 1996 Stan Shebs + + * mpw-make.sed: Edit out makefile rebuild rule. + (host_alias, target_alias): Comment out instead of deleting. + (@LIBS@): Edit out references. + +Tue Feb 13 22:56:46 1996 Fred Fish + + * symfile.c (add_psymbol_to_list, add_psymbol_addr_to_list): + Use n_psyms in OBJSTAT, not psyms. + +Mon Feb 12 15:59:31 1996 Doug Evans + + * configure.in (sparclet-*-aout*): New config. + * configure: Regenerated. + +Mon Feb 12 14:17:52 1996 Fred Fish + + * somsolib.c (som_solib_add): Use xmalloc rather than bare + unchecked call to malloc. + * remote-mips.c (pmon_load_fast): ditto. + * remote-mm.c (mm_open): ditto. + * hpread.c (hpread_lookup_type): ditto. + * remote-adapt.c (adapt_open): ditto. + +Mon Feb 12 13:11:32 1996 Fred Fish + + * f-lang.c (allocate_saved_bf_node, allocate_saved_function_node, + allocate_saved_f77_common_node, allocate_common_entry_node, + add_common_block): Use xmalloc rather than malloc, some of which + were unchecked. + * gnu-regex.c: At same point as other gdb specific changes + #undef malloc and then #define it to xmalloc. + * ch-exp.c (growbuf_by_size): Use xmalloc/xrealloc rather than + bare unchecked calls to malloc/realloc. + * stabsread.c (dbx_lookup_type): Use xmalloc rather than bare + unchecked call to malloc. + +Wed Feb 7 11:31:26 1996 Stu Grossman (grossman@cygnus.com) + + * symtab.c (gdb_mangle_name): Change opname var to be const to + match return val of cplus_mangle_name. + * i960-tdep.c: Change arg types of next_insn to match callers. + +Wed Feb 7 07:34:24 1996 Fred Fish + + * config/i386/linux.mh (XM_CLIBS, GDBSERVER_LIBS): Remove. These + apparently aren't needed in any reasonably recent version of + linux. + +Tue Feb 6 21:37:03 1996 Per Bothner + + * stabsread.c (read_range_type): If !self-subrange and language + is Chill, assume a true range. If a true_range is a sub_subrange, + use builtin_type_int for index_type. + +Tue Feb 6 18:38:51 1996 J.T. Conklin + + * nindy-share/nindy.c (say): Use stdarg.h macros when compiling + with an ANSI compiler. + +Mon Feb 5 18:24:28 1996 Steve Chamberlain + + From Michael_Snyder@NeXT.COM (Michael Snyder): + * valops.c (value_arg_coerce): Coerce float to double, unless the + function prototype specifies float. + +Mon Feb 5 09:51:55 1996 Tom Tromey + + * language.c (set_language_command): Use languages table when + printing available languages. + +Sat Feb 3 12:22:05 1996 Fred Fish + + Fix problems reported by Hans Verkuil (hans@wyst.hobby.nl): + * command.c (add_cmd): Add missing initialization for enums member. + Reorder members to match structure declaration to make it easier to + tell when one is missing. + * exec.c (exec_file_command): Fix problem where filename in malloc'd + memory is referenced after being freed. + +Sat Feb 3 03:26:21 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dwarfread.c (read_func_scope): Avoid GDB core dumps if + AT_name tag is missing. + + * procfs.c (procfs_stopped_by_watchpoint): Fix logic when + FLTWATCH and FLTKWATCH are defined. + + * remote.c (remote_read_bytes): Advance memaddr for transfers, + return number of bytes transferred for partial reads. + + * top.c (init_signals): Reset SIGTRAP to SIG_DFL. + +Fri Feb 2 13:40:50 1996 Steve Chamberlain + + * win32-nat.c (mappings): Add ppc registers. + (child_resume): Turn off step for ppc. + +Thu Feb 1 10:29:31 1996 Steve Chamberlain + + * config/powerpc/(cygwin32.mh, cygwin32.mt, tm-cygwin32.h, + xm-cygwin32.h): New. + * config/i386/(*win32*): Becomes *cygwin32*. + * configure.in (i[3456]86-*-win32*): Becomes i[3456]86-*-cygwin32. + (powerpcle-*-cygwin32): New. + * configure: Regenerate. + * win32-nat.c (child_create_inferior): Call CreateProcess + with the right program arg. + +Thu Feb 1 11:01:10 1996 Jeffrey A Law (law@cygnus.com) + + * config/pa/tm-hppa.h (SOFT_FLOAT): Provide a default definition. + +Wed Jan 31 19:01:28 1996 Fred Fish + + * serial.c: Change fputc/fputs/fprintf to _unfiltered forms. + +Wed Jan 31 18:36:27 1996 Stan Shebs + + * config/sparc/xm-sun4os4.h (HAVE_TERMIOS): Remove. + + * config/sparc/xm-sparc.h (HAVE_WAIT_STRUCT): Remove, never used. + + * config/i386/nm-i386mach.h (CHILD_PREPARE_TO_STORE): Move to + here from config/i386/xm-i386mach.h, fix name. + * config/i386/nm-sun386.h: Ditto, from config/i386/xm-sun386.h. + * config/i386/nm-ptx4.h (CHILD_PREPARE_TO_STORE): Move to + here from config/i386/xm-ptx4.h. + * config/i386/nm-ptx4.h: Ditto, from config/i386/xm-ptx.h. + * config/i386/nm-symmetry.h: Ditto, from config/i386/xm-symmetry.h. + * config/m68k/nm-sun3.h: Ditto, from config/m68k/xm-sun3.h. + * config/sparc/nm-nbsd.h: Ditto, from config/sparc/xm-nbsd.h. + * config/sparc/nm-sun4os4: Ditto, from config/sparc/xm-sparc.h. + + * config/sparc/nm-sun4sol2.h: New file, renamed from nm-sysv4.h. + (PRSVADDR_BROKEN): Move here from xm-sun4sol2.h. + * config/sparc/sun4sol2.mh (NAT_FILE): Update. + +Wed Jan 31 17:20:26 1996 Jeffrey A Law (law@cygnus.com) + + * config/pa/tm-hppa.h (EXTRACT_RETURN_VALUE): Handle software + floating point correctly. + (STORE_RETURN_VALUE): Likewise. + * config/pa/tm-pro.h (SOFT_FLOAT): define. + +Wed Jan 31 13:34:52 1996 Fred Fish + + * config/i386/xm-linux.h (MMAP_BASE_ADDRESS, MMAP_INCREMENT): + Define to what should be reasonable values. However, apparently + a bug in linux mmap prevents mapped symbol tables from working. + +Tue Jan 30 18:26:19 1996 Fred Fish + + * defs.h (errno.h>: Move #include closer to head of file to solve + obscure problem with systems that declare perror with const arg, in + both errno.h and stdio.h, and const is defined away by intervening + local include. + +Tue Jan 30 15:41:10 1996 Fred Fish + + From Jon Reeves : + * i386-stub.c (getpacket): Change fprintf stream from "gdb" to stderr. + (mem_fault_routine): Fix misplaced volatile type qualifier in decl. + +Mon Jan 29 19:05:58 1996 Fred Fish + + * Makefile.in (diststuff): Make all-doc; diststuff target does not + exist in doc/Makefile.in. + +Mon Jan 29 18:44:57 1996 Stan Shebs + + * config/m88k/xm-cxux.h (BP_HIT_COUNT): Remove, never used. + +Mon Jan 29 00:10:35 1996 Wilfried Moser (Alcatel) + + * ch-valprint.c (calculate_array_length): New function to + determine the length of an array type. + (chill_val_print (case TYPE_CODE_ARRAY)): If the length of an + array type is zero, call calculate_array_length. + + * gdbtypes.c (get_discrete_bounds (case TYPE_CODE_ENUM)): The + values may not be sorted. Scan all entries and set the real lower + and upper bound. + +Sun Jan 28 15:50:42 1996 Fred Fish + + * config/xm-linux.h: Move include of solib.h and #define of + SVR4_SHARED_LIBS from here ... + * config/nm-linux.h: ...to here. + +Sat Jan 27 10:34:05 1996 Fred Fish + + * configure.in (AC_CHECK_HEADERS): Check for sys/procfs.h. + Also check for gregset_t and fpregset_t types. + * configure: Regenerate. + * core-regset.c (sys/procfs.h): Only include if HAVE_SYS_PROCFS_H + is defined. + (fetch_core_registers): Turn into stub unless both HAVE_GREGSET_T + and HAVE_FPREGSET_T are defined. These changes allow systems + like linux that are migrating to /proc support to use a single + configuration for both new and old versions. + + * config/i386/linux.mt: Note that this is now for both a.out and + ELF systems. + * config/i386/linux.mh (NATDEPFILES): Add solib.o, core-regset.o, + i386v4-nat.o + * config/i386/tm-linux.h (tm-sysv4.h): Include. + * config/i386/xm-linux.h (solib.h): Include + (SVR4_SHARED_LIBS): Define. + * i386v4-nat.c: Only compile if HAVE_SYS_PROCFS_H is defined. + (supply_gregset, fill_gregset): Compile if HAVE_GREGSET_T defined. + (supply_fpregset, fill_fpregset): Compile if HAVE_FPREGSET_T + defined. + +Fri Jan 26 13:48:14 1996 Stan Shebs + + * config/sparc/xm-sparc.h (NEW_SUN_CORE): Remove, never used. + * config/i386/xm-sun386.h: Ditto. + * config/m68k/xm-sun2.h, config/m68k/xm-sun3.h: Ditto. + +Thu Jan 25 16:05:53 1996 Tom Tromey + + * Makefile.in (INSTALLED_LIBS, CLIBS): Include @LIBS@. + +Thu Jan 25 09:22:15 1996 Steve Chamberlain + + From Greg McGary : + * dcache.c (dcache_peek, dcache_poke): Advance addr for + multi-byte I/O. + +Thu Jan 25 13:08:51 1996 Doug Evans (dje@cygnus.com) + + * infrun.c (normal_stop): Fix test for shared library event. + +Thu Jan 25 03:26:38 1996 Doug Evans + + * configure.in (sparc64-*-*): Add default host configuration. + (sparc64-*-solaris2*): Add target configuration. + * configure: Regenerated. + * sparc/sp64sol2.mt: New file. + +Wed Jan 24 22:31:37 1996 Doug Evans + + * Makefile.in (RUNTEST): srcdir renamed to rootsrc. + +Wed Jan 24 15:42:24 1996 Tom Tromey + + * Makefile.in (lint): Close backquotes. + +Wed Jan 24 13:19:10 1996 Fred Fish + + * NEWS: Make note of new record and replay feature for + remote debug sessions. + * serial.c (gdbcmd.h): Include. + (serial_logfile, serial_logfp, serial_reading, serial_writing): + Define here, for remote debug session logging. + (serial_log_command, serial_logchar, serial_write, serial_readchar): + New functions for remote debug session logging. + (serial_open): Open remote debug session log file when needed. + (serial_close): Close remote debug session log file when needed. + (_initialize_serial): Add set/show commands for name of remote + debug session log file. + * serial.h (serial_readchar): Declare + (SERIAL_READCHAR): Call serial_readchar(). + (SERIAL_WRITE): Call serial_write(). + (serial_close): Declare as extern. + (serial_logfile, serial_logfp): Declare. + * top.c (execute_command): Declare serial_logfp. Log user command + in remote debug session log if log file is open. + * remote-array.c (array_wait): #ifdef out echo to gdb_stdout. + (array_read_inferior_memory): Rewrite to fix memory overwrite bug. + * remote-array.c (SREC_SIZE): Remove, duplicates define in + monitor.h. + * remote-array.c (hexchars, hex2mem): Remove, unused. + * gdbserver/low-linux.c (store_inferior_registers): Remove + unnecessary extern declaration of registers[]. + * gdbserver/Makefile.in (all): Add gdbreplay. + * gdbserver/gdbreplay.c: New file. + * gdbserver/README: Give example of recording a remote + debug session with gdb and then replaying it with gdbreplay. + +Tue Jan 23 18:02:35 1996 Per Bothner + + * stabsread.c (rs6000_builtin_type): Make bool type unsigned. + (read_one_struct_field): Support boolean bitfields. + * c-valprint.c (c_val_print): Print booleans properly. + +Tue Jan 23 18:54:09 1996 Stan Shebs + + * remote-vxsparc.c (vx_convert_to_virtual, vx_convert_from_virtual): + Remove, never used. + * config/sparc/vxsparc.mt (TDEPFILES): Add remote-vxsparc.o. + +Tue Jan 23 14:36:05 1996 Per Bothner + + * ch-exp.c (parse_tuple): Error if invalid mode. + + * value.h (COERCE_ARRAY): Don't coerce enums. + (COERCE_ENUM): Don't COERCE_REF. + (COERCE_NUMBER): New macro (same as COERCE_ARRAY then COERCE_ENUM). + * valops.c (value_assign): Only do COERCE_ARRAY if internalvar (let + value_cast handle it otherwise); do *not* COERCE_ENUM either way. + * valarith.c: Use COERCE_NUMBER instead od COEREC_ARRAY. + Add COERCE_REF before COERCE_ENUM. + * values.c (value_as_long): Simplify. + + * valops.c (value_array): Create internalvar if !c_style_arrays. + + * language.c (lang_bool_type): Add Fortran support. + * eval.c (OP_BOOL): Use LA_BOOL_TYPE. + +Tue Jan 23 13:08:26 1996 Jeffrey A Law (law@cygnus.com) + + * symfile.c (auto_solib_add): Renamed from auto_solib_add_at_startup. + All references changed. + * breakpoint.c (bpstat_what): Add shlib_event to the class types. + Update state table. Reformat so that it's still readable. + When we hit the shlib_event breakpoint, set the calss of shlib_event. + (breakpoint_1): Add "shlib events" as a breakpoint type. + Print the shlib_event breakpoint like other breakpoints. + (create_solib_event_breakpoint): New function. + (breakpoint_re_set_one): Handle solib_event breakpoints. + * breakpoint.h (enum bytype): Add bp_shlib_event breakpoint type. + (enum bpstat_what_main_action): Add BPSTAT_WHAT_CHECK_SHLIBS + action. + (create_solib_event_breakpoint): Declare. + * infrun.c (wait_for_inferior): Handle CHECK_SHLIBS bpstat. + (normal_stop): Inform the user when the inferior stoped due + to a shared library event. + (_initialize_infrun): Add new set/show variable "stop-on-solib-events" + to control whether or not gdb continues the inferior or stops it when + a shared library event occurs. + * minsyms.c (lookup_minimal_symbol_solib_trampoline): New function. + * somsolib.c (TODO list): Update. + (som_solib_create_inferior_hook): Arrange for gdb to be notified + when significant shared library events occur. + * hppa-tdep.c (find_unwind_entry): No longer static. + +Tue Jan 23 09:00:48 1996 Doug Evans + + * printcmd.c (print_insn): Pass fprintf_unfiltered to + INIT_DISASSEMBLE_INFO. + +Mon Jan 22 16:59:40 1996 Stan Shebs + + * remote.c (remotebreak): New GDB variable. + (remote_break): New global. + (remote_interrupt): Send a break instead of ^C if remote_break. + * NEWS: Describe the new variable. + +Mon Jan 22 16:24:11 1996 Doug Evans + + * sparc-tdep.c (_initialize_sparc_tdep): Always use print_insn_sparc. + +Fri Jan 19 07:19:38 1996 Fred Fish + + * hp300ux-nat.c (getpagesize): Remove unused function + fetch_core_registers. + (hp300ux_core_fns): Remove, is unused. + (_initialize_core_hp300ux): Remove, is unused. + (gdbcore.h): Remove #include, no longer needed. + +Fri Jan 19 00:59:53 1996 Jeffrey A Law (law@cygnus.com) + + * rs6000-nat.c (exec_one_dummy_insn): Rework to avoid + ptrace bug in aix4.1.3 on the rs6000. + +Wed Jan 17 13:22:27 1996 Stan Shebs + + * remote-hms.c (hms_ops): Add value for to_thread_alive. + * remote-nindy.c (nindy_ops): Ditto. + * remote-udi.c (udi_ops): Ditto. + +Tue Jan 16 18:00:35 1996 James G. Smith + + * remote-mips.c (pmon_opn, pmon_wait, pmon_makeb64, pmon_zeroset, + pmon_checkset, pmon_make_fastrec, pmon_check_ack, + pmon_load_fast): New functions. Support for the PMON monitor world. + (common_open): New function to merge support for different monitors. + (mips_open): Use common_open(). + (mips_send_command): New function. + (mips_send_packet): Scan out-of-sequence packets. + (mips_enter_debug, mips_exit_debug): New functions. + (pmon_ops): New target definition structure. + +Tue Jan 16 11:22:58 1996 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (CLIBS): Add LIBS to allow libraries to be + specified on the make command line (via make LIBS=xxx). + + +Fri Jan 12 21:41:58 1996 Jeffrey A Law (law@cygnus.com) + + * symtab.c (find_pc_symtab): Don't lose if OBJF_REORDERED + is set but there are no psymtabs. + +Fri Jan 12 15:56:12 1996 Steve Chamberlain + + * dsrec.c (load_srec): Remove unused variable. + * monitor.c (monitor_expect): Don't expect a ^C to echo. + * serial.c (serial_open): Add parallel interface. + * sh3-rom.c (parallel, parallel_in_use): New. + (sh3_load): If parallel_in_use, download though the + parallel port. + (sh3_open): Open parallel port if specified. + (sh3_close): New function. + (_inititalize_sh3): Add sh3_close hook and documentation. + * monitor.c (monitor_close): Export. + * monitor.h (monitor_close): Add prototype. + +Fri Jan 12 13:11:42 1996 Stan Shebs + + From Wilfried Moser : + * remote.c (remotetimeout): New GDB variable, use to set the + remote timeout for reading. + + +Fri Jan 12 07:14:27 1996 Fred Fish + + * lynx-nat.c, irix4-nat.c, sparc-nat.c: Include gdbcore.h + to get "struct core_fns" defined. + * Makefile.in (lynx-nat.o, irix4-nat.o, sparc-nat.o): + Are dependent upon gdbcore_h. + +Thu Jan 11 23:13:24 1996 Per Bothner + + * symfile.c (decrement_reading_symtab): New function. + * symfile.c, symtab.h (currently_reading_symtab): New variable. + * symfile.c (psymtab_to_symtab): Adjust currently_reading_symtab. + * gdbtypes.c (check_typedef): Don't call lookup_symbol if + currently_reading_symtab (since that could infinitely recurse). + +Thu Jan 11 17:21:25 1996 Per Bothner + + * stabsread.c (read_struct_type): Trivial simplification. + + * stabsread.c (define-symbol): Use invisible references + for TYPE_CODE_SET and TYPE_CODE_BITSTRING too. + * valops.c (call_function_by_hand): Likewise. + * eval.c (evaluate_subexp_standard): When known, use the formal + parameter type as the expected type when evaluating arg expressions. + * ch-lang.c (evaluate_subexp_chill): Likewise (for MULTI_SUBSCRIPT). + + +Wed Jan 10 16:08:49 1996 Brendan Kehoe + + * configure.in, configure: Recognize rs6000-*-aix4*. + * config/powerpc/xm-aix.h: Reduce to include "xm-aix4.h". + * config/rs6000/aix4.mh (XM_FILE): Point to xm-aix4.h. + * config/rs6000/xm-aix4.h: New file. + * config/xm-aix4.h: New file. + +Wed Jan 10 11:25:37 1996 Fred Fish + + From Wilfried Moser : + * gdbserver/low-linux.c: New file. + * remote.c (remote_read_bytes): Fix aborts on larger packets. + + * config/i386/linux.mh (GDBSERVER_DEPFILES, GDBSERVER_LIBS): + Define. + * stabsread.c (define_symbol): If register value is too large, + tell what it is and what max is. + + +Tue Jan 9 09:33:53 1996 Jeffrey A Law (law@cygnus.com) + + * hpread.c (hpread_build_psymtabs): Finish Jan 4th + enum namespace -> enum_namespace change. + +Tue Jan 9 04:44:47 1996 Wilfried Moser (Alcatel) + + * ch-exp.c (parse_primval): In case ARRAY, add missing + FORWARD_TOKEN (). + +Mon Jan 8 13:29:34 1996 Stan Shebs + + * remote-mips.c (mips_receive_header): Recognize \012 instead + of \n, but write \n when program sends a \012. + * ser-mac.c (mac_input_buffer): Increase size of buffer. + +Mon Jan 8 12:00:40 1996 Jeffrey A Law (law@cygnus.com) + + * infptrace.c (initialize_infptrace): Move function out of + #ifdef conditional; put code within the function inside an + #ifdef conditional. + + * buildsym.c (end_symtab): Remove sort_pending and sort_linevec + arguments. Sorting is now dependent on OBJF_REORDERED. All + callers/references changed. + * dbxread.c (read_ofile_symtab): Correctly determine value for + last_source_start_addr for reordered executables. + (process_one_symbol): Handle N_FUN with no name as an end of + function marker. + * partial-stab.h (case N_FN, N_TEXT): Don't assume CUR_SYMBOL_VALUE + is the high text address for a psymtab. + (case N_SO): Likewise. + (case N_FUN): Handle N_FUN with no name as an end of function + marker. + * minsyms.c (lookup_minimal_symbol_by_pc): Examine all symbols + at the same address rather than a random subset of them. + * coffread.c (coff_symfile_init): Set OBJF_REORDERED. + * elfread.c (elf_symfile_init): Similarly. + * somread.c (som_symfile_init): Similarly. + * xcoffread.c (xcoff_symfile_init): Similarly. + +Fri Jan 5 17:46:01 1996 Stu Grossman (grossman@cygnus.com) + + * stack.c (print_stack_frame print_frame_info) symmisc.c + (dump_symtab): Change RETURN_MASK_ERROR to RETURN_MASK_ALL so + that catch_errors doesn't get blindsided by QUIT and lose the + cleanup chain. This fixes a problem where ^C while in a + user-defined command sometimes leaves instream NULL and causes a + segfault in command_loop. + +Fri Jan 5 13:59:16 1996 Brendan Kehoe + + * configure.in, configure: Add `-ldl -lw' for Solaris linking. + +Fri Jan 5 12:02:00 1996 Steve Chamberlain + + * config/sh/sh.mt, config/powerpc/*.mt, config/pa/hppapro.mt, + config/m68k/monitor.mt, config/h8500/h8500.mt, config/h8300/h8300.mt: + srec.o renamed to dsrec.o. + +Thu Jan 4 16:04:54 1996 Stu Grossman (grossman@cygnus.com) + + * breakpoint.c (remove_breakpoint): Change error to warning so + that hardware watchpoint removal problems won't leave breakpoint + traps in the target. + * remote-e7000.c (e7000_insert_breakpoint, + e7000_remove_breakpoint): Use e7000 based breakpoints, not memory + breakpoints. + * (e7000_wait): Adjust PC back by two when we see a breakpoint to + compensate for e7000 maladjustment. + * sparcl-tdep.c (sparclite_check_watch_resources): Fix logic bug + which prevented hardware watchpoints from working. + +Thu Jan 4 10:44:17 1996 Fred Fish + + * infptrace.c (udot_info): New function. + (PT_*): Define each individually if that one is not defined. + * rs6000-nat.c (kernel_u_size): New function + Include for "struct user" + * alpha-nat.c (kernel_u_size): New function. + Include for "struct user" + * sparc-nat.c (kernel_u_size): New function. + Include for "struct user" + * i386b-nat.c (kernel_u_size): New function. + * i386v-nat.c (kernel_u_size): New function. + * config/i386/nm-fbsd.h (KERNEL_U_SIZE): Define. + (kernel_u_size): Declare. + * config/i386/nm-linux.h (KERNEL_U_SIZE): Define. + (kernel_u_size): Declare. + * config/sparc/nm-sun4os4.h (KERNEL_U_SIZE): Define. + (kernel_u_size): Declare. + * config/alpha/nm-osf2.h (KERNEL_U_SIZE): Define. + (kernel_u_size): Declare. + * config/rs6000/nm-rs6000.h (KERNEL_U_SIZE): Define. + (kernel_u_size): Declare. + +Thu Jan 4 11:00:01 1996 steve chamberlain + + * mdebugread.c (mylookup_symbol): enum namespace becomes + enum_namespace type. + * symfile.c (add_psymbol_to_list) + (add_psymbol_addr_to_list): Ditto. + * symtab.c (lookup_partial_symbol): Ditto. + (lookup_symbol): Ditto. + (lookup_block_symbol): Ditto. + * win32-nat.c (handle_load_dll): Use incoming dll base. + (child_wait): Catch DLL load errors. + (create_child_inferior): Translated between paths correctly. + +Wed Jan 3 23:13:53 1996 Fred Fish + + * i386v4-nat.c (supply_gregset, fill_gregset): Subtract NUM_FREGS + from NUM_REGS to get number of general registers that we care about. + * config/i386/tm-i386.h (REGISTER_BYTES): Define in terms + of number of general regs and number of floating point regs. + +Wed Jan 3 19:49:54 1996 steve chamberlain + + * config/i386/tm-win32.h (IN_SOLIB_CALL_TRAMPOLINE): New. + (SKIP_TRAMPOLINE_CODE): New. + * config/i386/xm-win32.h (CANT_FORK): Deleted. + (SLASH*) Changed to use unix style slash. + * symtab.h (namespace enum): becomes typedef to avoid namespace + collision in C++. + * infcmd.c (path_command): Use empty string if PATH name not set. + * i386-tdep.c (skip_trampoline_code): New function. + * srec.c: Renamed dsrec.c to avoid filename collision. + * Makefile.in: Cope with renaming. + +Wed Jan 3 13:09:04 1996 Fred Fish + + * symmisc.c (print_objfile_statistics): Print memory use statistics + for objfile psymbol, symbol, and type obstacks. + +Tue Jan 2 13:41:14 1996 Stan Shebs + + * config/mips/nm-irix5.h: Restore. + (TARGET_HAS_HARDWARE_WATCHPOINTS, etc): Define as for Irix 4; + from Lee Iverson . + * config/mips/irix5.mh (NAT_FILE): Use nm-irix5.h. + * config/mips/irix[345].mh (MUNCH_DEFINE): Remove. + +For older changes see ChangeLog-95 + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/gdb/ChangeLog-93 b/contrib/gdb/gdb/ChangeLog-93 new file mode 100644 index 000000000000..463154d9ce83 --- /dev/null +++ b/contrib/gdb/gdb/ChangeLog-93 @@ -0,0 +1,7597 @@ +Fri Dec 31 14:33:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * nindy-share/nindy.c: Fix order of arguments to store_unsigned_integer + (second and third arguments were reversed). + (say): Use varargs. + +Fri Dec 31 12:13:47 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote-mips.c: Add timeout parameter to mips_request and + mips_receive_packet. + (callers): pass in mips_receive_wait except mips_initialize (where + we use it to clean up the kludge where we had been changing + mips_receive_wait temporarily) and mips_wait (where we pass in + -1 for no timeout). + +Fri Dec 31 14:33:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stack.c (print_block_frame_locals): Also print LOC_BASEREG variables. + +Fri Dec 31 06:55:38 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.c (find_methods): Call fprintf_symbol_filtered with DMGL_ANSI. + +Thu Dec 30 10:16:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * values.c (unpack_long): Fix garbled error message. + + * remote-mips.c (mips_error): New function. + * remote-mips.c: Use it instead of error() most places. + * remote-mips.c (mips_receive_packet): New arg throw_error. + (mips_initialize): Use it not catch_errors. + * defs.h: Declare error_pre_print and warning_pre_print here... + * main.c: ...not here. + + * breakpoint.c (breakpoint_chain): Make static. + * breakpoint.c, breakpoint.h (frame_in_dummy): New function. + * stack.c (print_frame_info): Use it. + +Thu Dec 30 07:41:36 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * exec.c (add_to_section_table): Check for SEC_ALLOC instead of + SEC_LOAD to handle .bss segments properly. + +Thu Dec 30 10:16:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Enable code which assumes that if + we jump into the prologue from another function, then it was a + subroutine call. #if 0 AT_FUNCTION_START; the above code should + take care of this case. + +Wed Dec 29 12:32:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valprint.c (val_print_string): Change chunksize from 200 + to 8. + + * symfile.c (generic_load): If no arguments, get file name + from get_exec_file. + + * c-exp.y: Revert Kung's change. "..." is not a type, and the + change caused "p (...)0" to dump core. + * gdbtypes.c (check_stub_method): Don't pass "..." to + parse_and_eval_type. This should fix the bug which Kung was + trying to fix. + + * stabsread.c (define_symbol): If we choose not to combine + two symbols, don't just ignore the second (LOC_REGISTER) one. + * printcmd.c (print_frame_args): If we have a LOC_ARG and a + LOC_REGISTER, use the LOC_ARG not the LOC_REGISTER. + +Tue Dec 28 15:08:00 1993 Fred Fish (fnf@deneb.cygnus.com) + + * solib.c (DEBUG_BASE): Remove macro and all references. + * solib.c (debug_base_symbols): Add array of symbols to lookup. + * solib.c (IGNORE_FIRST_LINK_MAP_ENTRY): Add macro. + * solib.c (look_for_base, locate_base): Use debug_base_symbols. + * solib.c (find_solib): Use IGNORE_FIRST_LINK_MAP_ENTRY. + +Tue Dec 28 12:06:57 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * c-exp.y : fix grammar to parse ellipsis (...) + +Mon Dec 27 18:42:14 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * stabsread.c (read_type): fix problem when reading static member + of a class. caused by change to allow :: inside template + instantiated name. + +Mon Dec 27 11:07:05 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbtypes.h: Expand on comments for TYPE_CODE_BITSTRING and + TYPE_CODE_STRING a bit. + + * m68k-tdep.c (m68k_skip_prologue, m68k_find_saved_regs): + Allow pea %fp; move.l %sp, %fp instead of link instruction to + set up the new frame. + + * main.c (init_main): Change "set remotedebug" back to var_zinteger + from var_boolean. + + * c-exp.y (yylex): Don't try to deal with nested types. + + * cp-valprint.c (cplus_print_value): Call check_stub_type on + TYPE_BASECLASS (type, i) before we look at its name. + + * dbxread.c: Move default definition of GCC_COMPILED_FLAG_SYMBOL + from here . . . + * symtab.h: . . . to here. + * dbxread.c (record_minimal_symbol): Move check for gcc{,2}_compiled. + and __gnu_compiled* from here . . . + * minsyms.c (prim_record_minimal_symbol_and_info): . . . to here. + * minsyms.c (prim_record_minimal_symbol): Call + prim_record_minimal_symbol_and_info rather than duplicating code. + * minsyms.c, symtab.h (prim_record_minimal_symbol{,_and_info}), + coffread.c (record_minimal_symbol), + xcoffread.c (RECORD_MINIMAL_SYMBOL), callers: Add objfile parameter. + +Sun Dec 26 20:44:02 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * dbxread.c (process_one_symbol): Handle stabs-in-som just like + stabs-in-elf. + (pastab_build_psymtabs): Likewise. + + * hppa-tdep.c: Change all comments to reference %r3 or frame + pointer rather than %r4. + (frame_chain, skip_prologue, dig_rp_from_stack): Handle %r3 as the + frame pointer. + + * config/pa/tm-hppa.h (FP_REGNUM): Define as %r3. + (FIND_FRAME_SAVED_REGS): Handle %r3 as frame pointer. + (CALL_DUMMY): Likewise. + +Sun Dec 26 16:59:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * exec.c (exec_file_command): If error occurs after we have opened + exec_bfd but before we call push_target, make sure to close exec_bfd. + + * infrun.c (wait_for_inferior): Remove confusing and inaccurate + stuff about subroutine calls, return, etc., from comment which + says "We've wandered out of the step range.". + +Sun Dec 26 09:18:10 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (wait_for_inferior): When checking whether the line has + changed, check the symtab as well. + +Sun Dec 26 09:18:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbtypes.c (force_to_range_type): Use switch statement. + complain() not warning() if the TYPE_CODE isn't one we know how to + deal with gracefully. Use builtin_type_int not + lookup_fundamental_type (the objfile we passed to + lookup_fundamental_type was sometimes NULL). + + * valops.c (call_function_by_hand, push_word), defs.h (push_word), + convex-xdep.c, m88k-nat.c, i386m3-nat.c, mips-tdep.c, mipsm3-nat.c, + ns32km3-nat.c, remote-bug.c, m88k-tdep.c, remote-hms.c, remote-mips.c, + config/gould/tm-np1.h, hppa-tdep.c (hppa_fix_call_dummy), remote-vx.c: + Use REGISTER_SIZE, unsigned LONGEST, and + {store,extract}_unsigned_integer, instead of sizeof + (REGISTER_TYPE) and REGISTER_TYPE. + * All tm.h files: Change REGISTER_TYPE to REGISTER_SIZE. + * hppa-tdep.c (pa_print_fp_reg): Remove unused variable val. + + * Makefile.in (ALLDEPFILES): Remove i386ly-nat.c and m68kly-nat.c. + Add lynx-nat.c. + +Sat Dec 25 20:05:41 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (init_extra_frame_info): Correctly adjust the base + of the current frame when "fromleaf" is true. Do not adjust the + frame base of the innermost frame if it is a leaf function. + +Sat Dec 25 13:39:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (define_symbol): Only combine a p/r pair into a + LOC_REGPARM if REG_STRUCT_HAS_ADDR. + +Sat Dec 25 09:50:29 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valops.c (value_struct_elt): Check for (value)-1 return from + search_struct_method. + +Sat Dec 25 09:50:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * defs.h: Move definitions of TARGET_*_BIT after include of tm.h. + The old way (using #undef in tm.h) was ugly and asking for + trouble, because it makes it possible for some file to use the + wrong definition. Move definition of HOST_CHAR_BIT after definition + of TARGET_CHAR_BIT. + * config/alpha/tm-alpha.h, config/h8300/tm-h8300.h, + config/h8500/tm-h8500.h, config/z8k/tm-z8k.h: Don't undef TARGET_*_BIT + before defining them. + + * mdebugread.c: Change the builtin_type_* in this file to + mdebug_type_* and make them static. Use TYPE_CODE_ERROR for + complex and float decimal. + + * printcmd.c (disassemble_command): Call wrap_here between printing + address and printing instruction. + +Fri Dec 24 14:23:57 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (read_type): Don't fall through 'S' case (the case it + was falling though happened to do the right thing ("break;") but that + is hardly a good thing to assume). + +Tue Dec 21 13:32:02 1993 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-exp.y (match_dollar_tokens): Fix off-by-one bug. + * ch-lang.c (chill_is_varying_struct), ch-lang.h: New function. + * ch-lang.c (chill_printstr): Use double quotes, not single quotes. + * ch-typeprint.c (chill_type_print_base): Handle TYPE_CODE_BITSTRING. + Improve printing of TYPE_CODE_STRING, TYPE_CODE_SET, and + TYPE_CODE_STRUCT (including checking chill_is_varying_struct). + Print TYPE_DUMMY_RANGE by printing its TYPE_TARGET_TYPE. + Handle TYPE_CODE_ENUM. + * ch-valprint.c (chill_val_print): Handle TYPE_CODE_BITSTRING. + For TYPE_CODE_STRING, never print address. Handle VARYING strings. + * gdbtypes.c (force_to_range_type): New. + * gdbtypes.c (create_set_type): Make work, following Chill layout. + * gdbtypes.h (TYPE_LOW_BOUND, TYPE_HIGH_BOUND, TYPE_DUMMY_RANGE): New. + * stabsread.c (read_type): Distinguish string and bitstring from + char-array and set. + * valarith.c (value_subscript), valops.c (value_coerce_array): + Handle STRINGs as well as ARRAYs. + * valarith.c (value_bit_index): Fix think. Use new macros. + + +Fri Dec 17 10:45:32 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * symtab (decode_line_1): fix a bug when position char is not + set correctly. + * c-valprint (c_val_print): handle vtbl printing when vtbl is not + set up yet. + +Thu Dec 16 16:46:01 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-tdep.c (read_next_frame_reg): If SIGFRAME_REG_SIZE is not + defined, define it as 4. + +Thu Dec 16 13:08:01 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * config/m68k/nm-hp300bsd.h: Correctly identify 4.3BSD vs 4.4BSD. + + * config/m68k/tm-hp300bsd.h (REMOTE_BPT_VECTOR): Define. + + * config/m68k/tm-m68k.h (REMOTE_BPT_VECTOR): Allow targets to + override. + (REMOTE_BREAKPOINT): Likewise. + +Thu Dec 16 09:14:58 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hp_function_type): Correctly handle + pass-by-value structures > 64bits in size. + (process_one_debug_symbol): Likewise. + +Mon Dec 13 20:17:39 1993 Per Bothner (bothner@kalessin.cygnus.com) + + Implement support for Chill POWERSETs. + * ch-exp.y (operand_2): Implement 'Element IN PowerSet'. + * ch-typeprint.c (chill_type_print_base): Handle POWERSETs. + * ch-valprint.c (chill_val_print): Handle TYPE_CODE_SET. + * eval.c (evaluate_subexp): Implement BINOP_IN. + * expression.h (enum exp_opcode): Added BINOP_IN. + * gdbtypes.c (create_set_type), gdbtypes.h: New function. + * stabsread.c (read_type): If 'S', create a set type. + * valarith.c (value_bit_index, value_in), value.h: New functions, + for indexing in SETs. + +Mon Dec 13 06:42:37 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (pa_symfile_init): Check for the existance of stabs + after DBX_TEXT_SECT has been initialized. + +Tue Nov 23 17:29:28 1993 Steve Chamberlain (sac@jonny.cygnus.com) + + * config/h8300/tm-h8300.h (BREAKPOINT): Insn changed to sleep. + (DECP_PC_AFTER_BREAK): Now is 0. + * config/h8500/tm-h8500.h (REGISTER_BYTES, REGISTER_BYTE, + REGISTER_NAMES): update to new view. (INIT_EXTRA_FRAME_INFO): No + extra frame info now. + * config/sh/sh.h (NOP): Define NOP insn. + * config/z8k/tm-z8k.h (BIG): is now sim_z8001_mode. + * config/z8k/z8ksim.mt (TDEPFILES): Add remote-sim.o to list. + * ser-go32.c: Lint. (strncasecmp): Removed, now in libiberty. + (go32_readchar): Special handling for faster polling. (async + structure): Volatile. + * h8300-tdep.c (print_register_hook): Allocate and use the right + number bytes for the raw register. + * h8500-tdep.c (regoff, frame_find_saved_reg, examine_prologue): + deleted. (h8500_register_size, h8500_register_virtual_type, ): + Use new way of counting registers. + * remote-e7000.c (echo_index): deleted. (expect): Better handling + of user interrupts. (expect_prompt): Remove never used log file + support. (want, want_nopc): Add support for H8/300H. + (fetch_regs_from_dump): Treat \r and \n as whitespace. + (e7000_drain): Send an "end" command before waiting for output to + stop. (e7000_wait): Cope with H8/300H, better handling of user + interrupts. (why_stop, expect_n, sub2_from_pc): New function. + * remote-utils.c (gr_load_image): call fflush and QUIT more regularly. + * utils.c (notice_quit): New function for polling for user interrupts. + +Fri Dec 10 15:53:56 1993 Per Bothner (bothner@kalessin.cygnus.com) + + * stabsread.c (read_array_type): Allow negative array bounds, + without interpreting that to mean "adjustable." + * ch-valprint.c (chill_val_print): Handle RANGE types. + * ch-typeprint.c (chill_type_print_base): Handle BOOL. + Handle variant records. Handle RANGE types. + +Tue Dec 7 15:41:32 1993 Ian Lance Taylor (ian@cygnus.com) + + * config/mips/idt.mt: Use tm-idt.h instead of tm-bigmips.h. + * config/mips/idtl.mt: Use tm-idtl.h instead of tm-mips.h. + * config/mips/tm-idt.h, config/mips/tm-idtl.h: New files; use + different BREAKPOINT value for IDT. + + * mipsread.c: Include bfd.h and coff/sym.h. + +Mon Dec 6 16:34:10 1993 K. Richard Pixley (rich@cygnus.com) + + * ser-unix.c (set_tty_state): set the rest of the terminal state + pieces. + +Mon Dec 6 12:01:37 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * configure.in: Recognize mips* for all mips targets. + (mips*el-*-elf*, mips*-*-elf*): New targets; use idt and idtl. + + Added Irix 5 support. + * configure.in (mips-sgi-irix5*): New host and target. Use irix5 + for both. + * config/mips/irix5.mh, config/mips/irix5.mt, + config/mips/xm-irix5.h, config/mips/nm-irix5.h, + config/mips/tm-irix5.h, irix5-nat.c: New files for Irix 5 support. + * mdebugread.c: New file, split out of mipsread.c. Added + elfmdebug_build_psymtabs routine. Added some checks on external + symbols. Changed code to keep ecoff_debug_info and + ecoff_debug_swap structs in the psymtab and in global pointers + rather than retrieving them from the bfd. Also changed to keep + the pending list with the psymtab rather than the objfile (each + psymtab for a single objfile points to the same pending list). + * mipsread.c: Bulk of file moved into mdebugread.c, leaving just + the sym_fns. + * Makefile.in (SFILES): Added mdebugread.c. + (OBS): Added mdebugread.o. + (mdebugread.o): New target. + * symfile.h: Declare mdebug_build_psymtabs and + elfmdebug_build_psymtabs. + * elfread.c (struct elfinfo): Added mdebugsect field. + (elf_locate_sections): Remember location of .mdebug section. + (elf_symfile_read): Call elfmdebug_build_psymtabs on .mdebug + section. + * infrun.c (AT_FUNCTION_START): Set to 0 if not already defined. + (wait_for_inferior): Use AT_FUNCTION_START if it is defined to see + if PC is at the start of a function. + * mips-tdep.c (read_next_frame_reg): Use SIGFRAME_REG_SIZE, and + give it a default definition. + (mips_skip_prologue): Skip instructions which initialize $gp + register. + (in_sigtramp): New procedure, moved in from mipsread.c. + * config/mips/tm-mips.h: Declare in_sigtramp. + + * serial.h (serial_fdopen): Make parameter const to match + function definition. + +Fri Dec 3 14:20:43 1993 Stu Grossman (grossman at cygnus.com) + + * config/mips/irix4.mh: Enable ser-tcp.o. + +Tue Nov 30 15:24:24 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (check): Do not use subdir_do, so that + TARGET_FLAGS_TO_PASS is used correctly. + +Mon Nov 29 16:10:38 1993 Stu Grossman (grossman at cygnus.com) + + * i386-nlmstub.c: Undo I/O redirection changes by Tom Lord. + These definitely won't work under Netware. + +Mon Nov 29 15:34:58 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * stabsread.c(read_struct_field): Fix the check when getting to + member functions. + +Mon Nov 29 16:48:16 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + gcc -Wall -O lint: + * mips-tdep.c (heuristic_proc_desc): Initialize reg30 to avoid + warning. Unnest comment. + (init_extra_frame_info): Remove unused variable mask. + (MASK): Fully parenthesize. + (mips_push_dummy_frame): Remove unused variable val. + (mips_skip_prologue): Remove unused variables f and b. + +Mon Nov 29 12:23:25 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_symbol, parse_partial_symbols): Do not create + (partial) symbols for opaque struct definitions. + +Mon Nov 29 11:36:57 1993 Stu Grossman (grossman at cygnus.com) + + * i386ly-tdep.c (i386lynx_saved_pc_after_call): Change call_inst + to unsigned char to avoid domain warning for some values. + +Mon Nov 22 23:42:59 1993 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote-e7000.c (e7000_wait): Cope with H8/300 register dump. + * config/h8300/h8300hms.mt: Add remote-e7000. + +Mon Nov 22 11:03:45 1993 Fred Fish (fnf@cygnus.com) + + Merged changes from kev@spuds.geg.mot.com (Kevin A. Buettner): + * gdb/config/m88k/delta88.mh (NATDEPFILES): Added corelow.o and + coredep.o to this list. + * gdb/m88k-nat.c (m88k_register_u_addr): Avoid error when passed + the number for an M88110 extended register by just returning the + address of r0. + +Sat Nov 20 09:20:51 1993 Fred Fish (fnf@rtl.cygnus.com) + + * go32-xdep.c (re_comp, re_exec): Remove stubs now that gdb + always uses it's own version of regex. + +Fri Nov 19 18:23:19 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * valops.c(value_struct_elt_for_reference): enhance search operator in + c++. + * symtab.c(decode_line_1): same as above. + +Fri Nov 19 15:08:47 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (decode_line_1): Add comment about use of + return_to_top_level directly instead of error. Add comment saying + that the '' should not be needed--that the completer should be fixed. + +Fri Nov 19 11:00:33 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * symtab.c(decode_line_1): fix the inconsistency of setting + breakpoint with '' or without them. The '' is needed when you + want name completion. + +Thu Nov 18 08:25:50 1993 Fred Fish (fnf@cygnus.com) + + * valprint.c (val_print_string): When looking for a null + terminator compare current bufsize to fetchlimit to determine + when to stop, instead of computing buffer+fetchlimit which + may overflow for very large limits (like "unlimited"). + +Wed Nov 17 18:23:09 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * eval.c(evaluate_subexp): to use unified search so type conversion + operator works in calling method. + * valarith.c(value_x_binop, value_x_unop): same as above. + * valops.c(search_struct_method): same as above. + +Wed Nov 17 18:47:34 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mipsread.c: Change use of ECOFF information to correspond to + changes in bfd/libecoff.h. + (mipscoff_symfile_offsets): Made static. + +Wed Nov 17 09:43:31 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * valops.c (typecmp): improve prototype matching when calling + a method. Make 'p (*(ostream *) &cout) << "lll" ' to work. + * eval.c(evalute_subexp): fix operator search problem when call + like p x.'operator+'(i). + +Tue Nov 16 17:15:03 1993 Stu Grossman (grossman at cygnus.com) + + * i386ly-nat.c, i386lynx-nat.c, m68kly-nat.c: Remove. Move + common code into lynx-nat.c. + * lynx-nat.c: New module. Contains portable code for Lynx native + stuff (mostly ptrace related). + * config/i386/i386lynx.mh (NATDEPFILES): i386ly-nat.o -> lynx-nat.o + * config/m68k/m68klynx.mh (NATDEPFILES): i386ly-nat.o -> lynx-nat.o + + * config/nm-lynx.h, config/tm-lynx.h: New files to contain + non-architecture specific native and target defs. + * config/i386/nm-i386lynx.h, config/i386/tm-i386lynx.h, + config/m68k/nm-m68klynx.h, config/m68k/tm-m68klynx.h: Move all + (arch) portable stuff into ../{tm nm}-lynx.h. + +Tue Nov 16 13:33:47 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (gdb_mangle_name): Only assume that the physname is + the entire mangled name if it looks like the mangled name of a + constructor. Needed for testsuite to work with GCC 2.4.5. + + * a68v-nat.c: Replace with new version from Troy Rollo. The + version I am replacing appears to be an old copy of sun3-nat.c. + * dstread.c (dst_symfile_read): Replace sort_all_symtab_syms call + with loop. + + * Makefile.in (TAGS): Depend on TAGFILES_{NO,WITH}_SRCDIR. + + * Makefile.in: (HFILES,TAGFILES): Split into _WITH_SRCDIR and + _NO_SRCDIR versions. + (TAGS): Only add srcdir to TAGFILES_NO_SRCDIR. + (This is part of a long saga involving me putting srcdir on + everything (perhaps for now-obsolete reasons, I forget), Rich + removing the srcdir from everything, Stu putting it back some + places for Sun make, and me just now getting around to fixing + `make TAGS' again). + +Mon Nov 15 12:29:10 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * stack.c(print_frame_info): print demangled function name + ansi style. + +Mon Nov 15 14:32:29 1993 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote-e7000.c: New file to cope with the Hitachi E7000 ICE. + * remote-utils.c, remote-utils.h (gr_load_image): New function to + download to target. + * h8300-tdep.c, h8500-tdep.c, remote-z8k.c, sh-tdep.c z8k-tdep.c + (sim_load): delete. + * remote-sim.c (gdbsim_load): Use gr_load_image, rather than + sim_load. + * config/sh/sh.mt: Add remote-e7000 + +Mon Nov 15 11:38:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/linux.mh: Remove XM_CLIBS, TERMLIB, SYSV_DEFINE, and + REGEX. + * config/i386/xm-linux.h: Don't include xm-i386v.h. Define + HOST_BYTE_ORDER ourselves. Define HAVE_TERMIOS not HAVE_TERMIO. + Define NEED_POSIX_SETPGID. Include unistd.h. + +Mon Nov 15 12:29:10 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * symtab.c(gdb_mangle_name): fix the problem with constructor + name mangling. + +Mon Nov 15 11:38:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbtypes.h: Add TYPE_FLAG_TARGET_STUB. + * gdbtypes.c (check_stub_type): On TYPE_FLAG_TARGET_STUB, do + what cleanup_undefined_types does for arrays, except we clear + TYPE_FLAG_TARGET_STUB if we fix up the type. + * stabsread.c (cleanup_undefined_types): Add comments about how + doing arrays here is no longer the clean way to do it. + (read_array_type): Set TYPE_FLAG_TARGET_STUB as well as calling + add_undefined_type. + * c-typeprint.c, ch-typeprint.c: Move call to check_stub_type + outside switch so it happens for all type codes. + * cp-valprint.c (cp_print_value_fields): Recurse to val_print, + instead of c_val_print, so that check_stub_type gets called. + + * gdbtypes.h, gdbtypes.c, m2-lang.c, ch-lang.c, c-lang.c: Remove + TYPE_FLAG_SIGNED. It was inconsistently set, never checked + (except in recursive_dump_type), and is pointless. + +Mon Nov 15 00:40:38 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (pa_symfile_init): Look for the $TEXT$ section rather + than the .text section. + +Sun Nov 14 00:28:13 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c: Remove #if 0'd dbx_class_complaint. We now handle + this (more or less) gracefully, and complain() was never a good + way of dealing with this. + + * stabsread.c (read_type): Skip the colon when reading a + cross-reference. Only complain, not error_type, on unrecognized + cross-reference types. error_type, not dump core, if the colon is + missing. + +Fri Nov 12 16:23:08 1993 Stu Grossman (grossman at cygnus.com) + + * config/m68k/tm-sun3.h: Disable use of alternate breakpoint insn + when doing remote stuff. + +Fri Nov 12 16:22:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-exp.y (yylex): Call lookup_symtab not lookup_partial_symtab. + + * partial-stab.h: Ignore ':' symbol descriptors. Same case as + Kung's stabsread.c change. + +Fri Nov 12 11:18:02 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * stabsread.c (patch_block_stabs, define_symbol, read_type): in + g++ template instantiation, nested class can be part of the + params, and '::' can gets into symbol or type names. This is + to fix the problem. + + * gdbtypes.c (lookup_struct_elt_type): Handle type ref or pointer + to struct/union case. + +Fri Nov 12 10:39:31 1993 Stu Grossman (grossman at cygnus.com) + + * coff-solib.c (coff_solib_add): Cast result of alloca(). + * m68k-tdep.c (m68k_saved_pc_after_call): Get rid of + GDB_TARGET_IS_SUN3. Use more general SYSCALL_TRAP macro. + * config/m68k/m68klynx.mh (NATDEPFILES): Remove exec.o (it's + already in TDEPFILES). + * config/m68k/tm-m68k.h (SAVED_PC_AFTER_CALL): Use + m68k_saved_pc_after_call. + * Remove all Sun3 specific stuff. + * (FIX_CALL_DUMMY): Cast arg to bfd_putb32 to unsigned char *. + * config/m68k/tm-m68klynx.h: Define SYSCALL_TRAP as trap #10. + Disable REMOTE_BREAKPOINT mechanism. + * config/m68k/tm-sun3.h: Get rid of GDB_TARGET_IS_SUN3. + * Protect from multiple includion. + * Move Sun3 specific stuff from tm-m68k.h to here. + * Define SYSCALL_TRAP as trap #0. + * Remove def of SAVED_PC_AFTER_CALL (now in tm-m68k.h). + * gdbserver/low-lynx.c: Redo all register store/fetch stuff to + make it portable for 386 and 68k. + +Fri Nov 12 09:53:26 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mips-tdep.c (init_extra_frame_info): Check to see whether the + registers mentioned in the proc_desc have been saved. This + generalizes mips_in_lenient_prologue in the sense that we keep + searching until we've found saves for all the registers, not just + look for a "lenient prologue" pattern. + * mips-tdep.c: #if 0 lenient prologue code. + + * mips-tdep.c (heuristic_proc_desc): Don't assume a host short + is 16 bits. + +Thu Nov 11 19:58:05 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/i386sol2.mh: Comment out corelow.o. + + * printcmd.c (address_info): Use filtered, not unfiltered functions. + We should be able to deal with a QUIT here. + +Thu Nov 11 15:22:20 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * printcmd.c (address_info): Use fprintf_symbol_filtered + to print the symbol name. + + * stabsread.c (define_symbol): Handle cfront lossage for + struct/union/enums and typedefs. + + * partial-stab.h (case N_BINCL): Update psymtab_language + as appropriate when changing subfiles. + (case N_SOL): Update psymtab_language as appropriate when + changing subfiles. Add typedef for structs, unions, and enums + when processing C++ files. + +Thu Nov 11 13:18:47 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * README: Remove information on languages and just cite the (newly + updated) information in doc/gdb.texinfo instead. + + * delta68-nat.c: Fix typos (add missing ");" and stuct -> struct). + +Wed Nov 10 09:31:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c (process_one_symbol, N_RBRAC): Don't clear + within_function just because local_symbols is NULL. It appears + that this bug has existed since the 10 Apr 89 change which started + clearing within_function here. + + * config/m68k/tm-m68k.h: Clean up CALL_DUMMY comment. + * config/m68k/{tm-hp300bsd.h,tm-hp300hpux.h,tm-m68k-em.h, + tm-monitor.h,tm-sun3.h,tm-vx68.h}, config/sparc/tm-sparc.h: + Define BELIEVE_PCC_PROMOTION. + * dbxread.c: Remove BELIEVE_PCC_PROMOTION define. The code which + used this was moved to stabsread.c a long time ago. + + * dstread.c (dst_sym_fns): Update for flavours. + * symfile.c (find_sym_fns): Add kludge for apollo like for rs/6000. + * dstread.c (dst_symfile_offsets): Set objfile->num_sections. + + gcc -Wall lint: + * thread.c: Include "gdbcmd.h" and . + * Makefile.in: Update dependency. + * thread.c (thread_command): Remove unused variable p. + * values.c (unpack_double): Use len instead of TYPE_LENGTH (type). + * valprint.c (print_floating): Correctly check sign bit now that + we are using unsigned arithmetic. + * symtab.c (find_pc_line_range): Remove unused variables exact_match, + ind, and l. + +Tue Nov 9 17:42:25 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * valarith.c (value_x_binop): fix search operator in class bug + * valarith.c (value_x_unop): fix search operator in class bug + +Tue Nov 9 19:20:17 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (init.c): Add udi2go32.o to list of files that we + should not try to search for _initialize_* functions. + + * remote-udi.c (udi_wait): Change UDIGdb_StdoutReady back to + UDIStdoutReady. It accidentally got changed on 24 Oct 93 when + stdout was changed to gdb_stdout. Likewise for UDIGetStdout, + UDIStderrReady, and UDIGetStderr. + +Tue Nov 9 12:48:06 1993 Tom Lord (lord@cygnus.com) + + * remote-hms.c (hms_wait): fixed too many arguments to putc_unfiltered. + +Tue Nov 9 12:20:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (quit): Also call gdb_flush on standard output and error. + + * .gdbinit: Remove "source /.gdbinit". It causes a spurious error + if /.gdbinit doesn't exist (and I know of no convention of putting + something in /.gdbinit). + +Mon Nov 8 18:17:11 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cp-valprint.c (cp_print_value_fields): change output from to + +Mon Nov 08 17:05:30 1993 Jeffrey Wheat (cassidy@cygnus.com) + + * Makefile.in: Change RUNTEST_FLAGS back to RUNTESTFLAGS + Change RUNTEST = runtest to test for existance of + a runtest in the source tree first. + +Mon Nov 8 10:42:03 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Remove unused variable GCC. Remove "#CC=cc" line + which doesn't really relate to anything. + + * Makefile.in (CC_FOR_TARGET): Test for existence of gcc/xgcc, not + for existence of gcc/Makefile. + + * inflow.c (terminal_init_inferior), infptrace.c (child_resume): + Add comments about use of Lynx PIDGET and how we will want to + clean it up. + + * stabsread.c: Remove long_kludge_name code (it was already #if 0). + * stabsread.c (read_one_struct_field): Clean up comments to reflect + Kung's change of 5 Nov 93. + * stabsread.c (read_one_struct_field): Don't give up on unknown + visibility character, just shove it in fip->list->visibility. + (read_baseclasses): Don't give up on unknown virtual or visibility + characters, just assume a reasonable default, complain, and keep + going. + (attach_fields_to_type): Complain on unrecognized visibility. + One result of all this is that '9' (VISIBILITY_IGNORE) can be used + in a stab as well as being something which GDB uses internally. + +Mon Nov 8 07:57:30 1993 Doug Evans (dje@canuck.cygnus.com) + + * configure.in: Remove h8300h, we have multilib now. + +Mon Nov 8 06:11:24 1993 D. V. Henkel-Wallace (gumby@cirdan.cygnus.com) + + * configure.in: Add unixware as a configuration alias for x86 + sysv4 + + * config/i386/i386nw.mt: add i387-tdep.o, exec.o to TDEPFILES + +Sun Nov 7 23:49:21 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.c (decode_line_1, decode_line_2): Do not adjust pc by + FUNCTION_START_OFFSET if funfirstline is not set. + +Fri Nov 5 17:19:30 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * gdbtypes.h : add a field 'ignore_field_bits in cplus_specific, + and macros to handle the bits. + * stabsread.c (read_one_struct_field): add VISIBILITY_IGNORE, and + for field of length 0, set this bit on. + * cp-valprint.c (cp_print_value_fields): for VISIBILITY_IGNORE + field, print . + +Fri Nov 5 14:43:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Version 4.11.2. + +Fri Nov 5 09:49:22 1993 Stu Grossman (grossman at cygnus.com) + + * inflow.c (terminal_init_inferior): Temporarily use Lynx PIDGET + macro to set process groups. + * infptrace.c (child_resume): Temporarily use Lynx PIDGET to + specify resumption of all threads. + * infrun.c (wait_for_inferior): Fix handling of thread-specific + breakpoints for systems where DECR_PC_AFTER_BREAK > 0 (ie: backup + PC by the right amount when continuing the thread). + * thread.c (thread_apply_command): Add the `thread apply' + command to apply a given GDB command to a list of threads. + +Fri Nov 5 05:58:03 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (init.c): Don't call sed if filename is empty. + +Thu Nov 4 08:27:24 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c (unknown_symchar_complaint): Make message refer to + "symbol descriptor" not "symbol type character" for consistency + with stabs.texinfo terminology. + + * stabsread.c (read_struct_fields): Accept either '$' or '.' as + the character which introduces a cpp_abbrev or anonymous type. + + * c-lang.c (c_printstr): Print "" to stream (like all the other + output from this function), not gdb_stdout. + + * dbxread.c (process_one_symbol): Do relocate 'S' symbols by + the text offset (revert 12 Oct 93 change). + + * configure.in: Make hppa*-*-hiux* use hppahpux, + not non-existent hppahiux. + +Wed Nov 3 16:24:09 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * values.c (value_fn_field): when physical name not found, do not + error, but return null. + * valops.c (value_struct_elt): when name and args match does not + mean it is the one, some times a typedef class can have the same + member method and args. This probably will not happen with new + version of g++, but it does happen in old g++ and cause gdb error. + +Wed Nov 3 09:20:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + Merge changes for dos x udi: + * Makefile.in (udi2go32.o): add rule to build this file + * 29k-share/udi/udi2go32.c: new file + * config/a29k/a29k-udi.mt: add udi2go32.o + * 29k-share/udi/{udr.c, udip2soc.c}: #ifdef out the entire file + if __GO32__ is defined. What a hack. + +Wed Nov 3 09:20:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c (putpkt, getpkt): Don't call interrupt_query. + + * findvar.c (value_of_register): Rename val to reg_val to avoid + name conflict with some (e.g. tm-m68k.h) REGISTER_CONVERT_TO_VIRTUAL. + + * main.c: Add variables source_line_number, source_file_name, + source_error, source_error_allocated, and source_pre_error. + (command_line_input): If source_file_name set, increment + source_line_number and set error_pre_print with them. + (source_command): Set source_* and make a cleanup so they get + set back. + +Tue Nov 2 16:28:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stack.c (down_silently_command): Add comment about PR 1913. + + * breakpoint.c (insert_breakpoints, delete_breakpoint): Call + target_terminal_ours_for_output before attempting output. + + * fork-child.c (fork_inferior): Fix comment so that it suggests + "set shell" rather than having "set env SHELL" affect GDB's + operation. + +Tue Nov 2 15:03:08 1993 Tom Lord (lord@rtl.cygnus.com) + + * utils.c (vfprintf_unfiltered): don't use maybe_filtered + since it involves a fixed size buffer. + +Tue Nov 2 13:42:30 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * findvar.c (value_of_register, value_from_register), + hppa-tdep.c (pa_print_fp_reg), infcmd.c (do_registers_info), + valops.c (value_assign): Use REGISTER_CONVERT_TO_* only if + REGISTER_CONVERTIBLE is defined, otherwise just copy the content. + Pass desired type to REGISTER_CONVERT_TO_*. + + * config/m68k/tm-m68k.h, config/i960/tm-i960.h (REGISTER_CONVERT_*): + Pass length of desired type to store/extract_floating. + * config/i386/tm-arm.h, config/i386/tm-i386aix.h, + config/i386/tm-sun386.h, config/i386/tm-symmetry.h, + config/m88k/tm-m88k.h config/rs6000/tm-rs6000.h (REGISTER_CONVERT_*): + Use extract_floating and store_floating with length of desired type. + * config/m68k/tm-news.h (STORE,EXTRACT_RETURN_VALUE): Add type + parameter to REGISTER_CONVERT_*. + + * config/a29k/tm-a29k.h, config/convex/tm-convex.h, + config/gould/tm-np1.h, config/gould/tm-pn.h, config/h8300/tm-h8300.h, + config/h8500/tm-h8500.h, config/i386/tm-i386v.h, + config/mips/tm-mips.h, config/ns32k/tm-merlin.h, + config/ns32k/tm-umax.h, config/pa/tm-hppa.h, config/pyr/tm-pyr.h, + config/sh/tm-sh.h, config/sparc/tm-sparc.h, config/tahoe/tm-tahoe.h, + config/vax/tm-vax.h, config/z8k/tm-z8k.h (REGISTER_CONVERTIBLE, + REGISTER_CONVERT_TO_RAW, REGISTER_CONVERT_TO_VIRTUAL): Remove + versions for which REGISTER_CONVERTIBLE is always false. + * z8k-tdep.c (register_convert_to_virtual, register_convert_to_raw): + Remove, no longer used. + + * alpha-tdep.c (alpha_register_convert_to_raw, + alpha_register_convert_to_virtual): New routines to handle + the different raw formats in alpha floating point registers. + * config/alpha/tm-alpha.h (REGISTER_CONVERTIBLE, + REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW): Use them. + +Tue Nov 2 12:45:23 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * gdbserver/configure.in: Recognize *-*-lynxos* instead of + *-*-lynx*, recognize sparc-*-lynxos*. + * gdbserver/Makefile.in (install, install_only): Add. + * gdbserver/gdbserver.1: New file, man page for gdbserver. + +Tue Nov 2 03:01:01 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Include and . Change include + of "libhppa.h" to "som.h". + (BYTES_IN_WORD): Define. + (hppa_sym_fns): "hppa" is 4 characters, not 5. + +Mon Nov 1 09:40:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c, symtab.h, source.c: Change find_line_pc_range to take + a struct symtab_and_line argument, rather than a symtab and a line. + Re-write it to be based on the address rather than bogusly adding + one to the line number and hoping that has something to do with the + end of the line. + + * config/m88k/m88k.mh (NATDEPFILES): Remove exec.o. + + * paread.c (pa_symtab_read): Change comments to say ignoring + labels really should be handled by the assembler/compiler. + + * Makefile.in: Add -O to CXXFLAGS. + + * TODO: Expand comments on fast watchpoints. + +Sun Oct 31 19:45:06 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (pa_symtab_read): Also filter out local symbols + starting with "L$". + +Sun Oct 31 09:28:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symfile.h (sym_fns), symfile.c (find_sym_fns), xcoffread.c, + coffread.c, dbxread.c, elfread.c, mipsread.c, nlmread.c, paread.c: + Change from using bfd target name to using the flavour. + + * objfiles.h, infcmd.c, symfile.c: Add comments about how various + objfiles get created and when we should blow them away. + +Sat Oct 30 08:32:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symfile.c (reread_symbols): When re-reading symbols, do all the + right operations ourself, rather than calling symbol_file_command. + If we re-read something, call clear_symtab_users not just + breakpoint_re_set. + * objfiles.h, objfiles.c (build_objfile_section_table): No longer + static. + * symfile.c (clear_symtab_users): Call clear_pc_function_cache. + * coffread.c, dbxread.c, elfread.c, mipsread.c, nlmread.c, paread.c + (*_symfile_offsets): Set objfile->num_sections. + * remote.c (remote_wait), symfile.c (syms_from_objfile): + Don't muck with objfile->num_sections now that all the symbol + readers set it. + * elfread.c: Clean up obsolete comment about handling only DWARF. + * paread.c: Remove comment about how we should use an "ordinary" + file format with an hppa suffix. There is nothing ordinary about SOM. + + * config/i386/{i386m3.mh,i386mk.mh}, config/mips/mipsm3.mh, + config/ns32k/ns32km3.mh: Change MMALLOC_LIB to MMALLOC. + * TODO: Update Mach stuff. + +Fri Oct 29 16:30:36 1993 Stan Shebs (shebs@rtl.cygnus.com) + + LynxOS support: + * configure.in: Change *-*-lynx* to *-*-lynxos*, add + sparc-*-lynxos*. + * Makefile.in (ALLDEPFILES): Add m68kly-nat.c, sparcly-nat.c. + Rename i386lynx-nat.[co] to i386ly-nat.[co]. + (ALLCONFIG): Add config/{m68k,sparc}/{m68k,sparc}lynx.m[ht]. + (m68kly-nat.o, sparcly-nat.o): Add rules. + * i386ly-tdep.c: Cosmetics. + * i386lynx-nat.c: Removed. + * i386ly-nat.c: New file, was i386lynx-nat.c. + * m68kly-nat.c: New file. + * sparcly-nat.c: New file. + * config/xm-lynx.h: New file, cpu-independent host info. + * config/i386/i386lynx.mh: Changes for consistency. + * config/i386/i386lynx.mt: Ditto. + * config/i386/tm-i386lynx.h: Ditto. + * config/i386/nm-i386lynx.h: Ditto. + * config/i386/xm-i386lynx.h: Include config/xm-lynx.h. + * config/m68k/m68klynx.mh, config/m68k/m68klynx.mt, + config/m68k/tm-m68klynx.h, config/m68k/nm-m68klynx.h, + config/m68k/xm-m68klynx.h: New files, M68K LynxOS support. + * config/sparc/sparclynx.mh, config/sparc/sparclynx.mt, + config/sparc/tm-sparclynx.h, config/sparc/nm-sparclynx.h, + config/sparc/xm-sparclynx.h: New files, Sparc LynxOS support. + +Fri Oct 29 08:11:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * defs.h, findvar.c (extract_floating, store_floating): New functions. + * Move SWAP_TARGET_AND_HOST from defs.h to findvar.c because it is + now used only by extract_floating and store_floating. + * valprint.c (print_floating): Use unsigned arithmetic. Use + extract_unsigned_integer instead of SWAP_TARGET_AND_HOST. + Change sizeof (float) to 4 and sizeof (double) to 8 (those are always + the relevant sizes for this code, which is in #ifdef IEEE_FLOAT). + * values.c (unpack_long, unpack_double, value_from_double), + valarith.c (value_binop), stabsread.c (define_symbol): + Use extract_floating and store_floating instead of + SWAP_TARGET_AND_HOST. + * config/m68k/tm-m68k.h, config/i960/tm-i960.h (REGISTER_CONVERT_*): + Use extract_floating and store_floating. + * config/m88k/tm-m88k.h: Add comments (it should be doing the same). + * i386-tdep.c (i386_extract_return_value), + * remote-nindy.c (nindy_store_registers): Use store_floating. + +Fri Oct 29 09:31:38 1993 Steve Chamberlain (sac@rtl.cygnus.com) + + * remote-sim.c (gdbsim_store_register): Change var name so + it compiles with non-ANSI compilers. + +Fri Oct 29 08:11:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Add idea for "disassemble" with source. + +Fri Oct 29 00:41:01 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.11.1 after release and cvs + tagging. + +Thu Oct 28 09:14:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Add section on Mach. Stop calling it a "bug list". + Remove John's name and email address. Remove item on "always" + ("hook-stop" takes care of this). Remove item on executables with + no symbols (this works on some machines, at least). Remove item + about calling error() during symbol reading (I think all the important + ones have been cleaned up). Revise items about signals and remote + systems. Remove section on ^Z requiring several continues to make + it go (this now works. Perhaps the item is based on confusion over + programs (like GDB itself) which catch SIGTSTP and then re-send + themselves the signal. PR 2575 might contain relevant info). + +Thu Oct 28 16:55:34 1993 Fred Fish (fnf@cygnus.com) + + * NEWS: Note improvements in C++ support, preliminary thread + implementation, and LynxOS native and target support for 386. + +Thu Oct 28 16:55:34 1993 Fred Fish (fnf@cygnus.com) + + * README: Add note from Peter Schauer about OSF/1 shared + libraries. Add note from Pace Willisson about configuring on BSDI + BSD/386 release 1.0. Update gdb references to gdb 4.11. + +Thu Oct 28 09:14:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * NEWS: Add notes about Alpha and "set remotedebug" for UDI. + + * valops.c (value_assign): Change bitfield code to use a buffer of + the correct size, rather than an int. + +Wed Oct 27 13:43:07 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/{i386m3.mt,i386m3.mh}, + config/mips/{mipsm3.mt,mipsm3.mh}, + config/ns32k/{ns32km3.mt,ns32km3.mh}: Use correct names for TM_FILE + and XM_FILE. Replace host files *mach3-xdep.o with native + files *m3-nat.o. Replace host file os-mach3.o with native + file m3-nat.o. + + * remote-udi.c: Remove LOG_FILE stuff; superceded by "set remotedebug". + * remote-mon.c: Remove commented out "set remotedebug" command. + * remote-nindy.c: Clean up comment about wanting alternative to + options specified on the GDB command line. + + * fork-child.c (fork_inferior): Set inferior_pid before calling + init_trace_fun. Move the code which gets us through the shell + to new function startup_inferior. + * inferior.h: Declare startup_inferior. + * procfs.c (procfs_init_inferior), inftarg.c (ptrace_him): + Call startup_inferior. + * m3-nat.c (m3_trace_him): Call intercept_exec_calls. + * config/nm-m3.h: Don't define STARTUP_INFERIOR. + * config/i386/tm-i386m3.h, config/ns32k/tm-ns32k.h, + config/mips/tm-mipsm3.h: Don't define START_INFERIOR_TRAPS_EXPECTED. + + * m68k-stub.c: Change vector 13 from SIGFPE to SIGBUS. + +Tue Oct 26 22:05:03 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * mips-tdep.c (mips_pop_frame): If proc_desc is NULL, don't dump core. + +Tue Oct 26 15:07:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + gcc -Wall lint: + * nlmread.c: Include stabsread.h. + * Makefile.in: Update dependencies. + + * remote.c: Change PBUFSIZ back to 400. John's 28 Feb 1992 change + to increase it broke the ability to write large chunks of memory + with m68k-stub and i386-stub. Now we only use more than 400 on + machines where we need that much to write the registers. + * remote.c (remote_write_bytes): Eliminate possible abort(). The + check for when to abort was off by a few bytes and besides which, + it is handled by MAXBUFBYTES, which the caller uses. + * m68k-stub.c: Add comments about trap #1 and trap #8 instructions. + +Tue Oct 26 08:36:07 1993 Doug Evans (dje@canuck.cygnus.com) + + * remote-sim.h (SIM_ADDR): New type (same as CORE_ADDR). + (sim_set_pc): Update prototype. + (sim_read, sim_write): Ditto, and use unsigned char *buf. + (sim_fetch_register, sim_store_register): Use unsigned char *buf. + (sim_info): Pass printf function as argument, add verbose argument. + (sim_stop_reason): Renamed from sim_stop_signal, fix prototype. + * remote-sim.c (gdbsim_wait): Update call to sim_stop_reason. + (gdbsim_files_info): Update call to sim_info. + +Tue Oct 26 10:41:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (value_assign): Call reinit_frame_cache when assigning + to a register. + +Mon Oct 25 11:08:59 1993 Stu Grossman (grossman at cygnus.com) + + * infrun.c (wait_for_inferior): Fix PC out of objfile bounds + check to just use stop_func_name == 0. + * remote-udi.c (store_register): Invalidate NPC/PC_REGNUM after + changing PC. + +Mon Oct 25 14:57:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/{low-lynx.c,low-sparc.c,low-sun3.c}, standalone.c, + m3-nat.c, i386m3-nat.c, mipsm3-nat.c, ns32km3-nat.c: bcopy -> memcpy. + + gcc -Wall lint: + * breakpoint.c: Include thread.h. + * coffread.c: Include stabsread.h. + * Makefile.in: Update dependencies. + * breakpoint.c (mention): Add bp_call_dummy to switch. + * symmisc.c (dump_symtab): Use %d not %ld for line number. + +Sun Oct 24 18:29:32 1993 Tom Lord (lord@rtl.cygnus.com) + + * every non-obsolete file except utils.c: + Change the stream argument to _filtered to GDB_FILE *. + Change all references to stdout/stderr to gdb_stdout/gdb_stderr. + Replace all calls to stdio output functions with + calls to corresponding _unfiltered functions. + Replaced calls to fopen for output to gdb_fopen. + Added sufficient goo to utils.c and defs.h to make the above + work. + + The net effect is that stdio output functions are only directly + used in utils.c. Elsewhere, the _unfiltered and _filtered + functions and GDB_FILE type are used. + + In the near future, GDB_FILE will stop being equivalant to + FILE. + + The semantics of some commands has changed in a very subtle way: + called in the right context, they may cause new occurences of + prompt_for_continue() behavior. + + Please respect this change by not reintroducing stdio output + dependencies in the main body of gdb code. All output from + commands should go to a GDB_FILE. + +Sun Oct 24 20:16:38 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * parse.c, parser-defs.h (write_exp_msymbol): New function to write + the appropriate expression for a minimal symbol. Taken from c-exp.y + and m2-exp.y but handles mst_file_*. + * c-exp.y, m2-exp.y: Use it. + +Sun Oct 24 09:31:05 1993 Fred Fish (fnf@lisa.cygnus.com) + + * elfread.c (elf_symtab_read): Use bfd convention that both + initialized and uninitialized data sections have the SEC_ALLOC + flag bit set, but only initialized sections have SEC_LOAD set. + SEC_DATA is ignored since it only gets set for initialized + data. + +Sat Oct 23 14:48:18 1993 Doug Evans (dje@canuck.cygnus.com) + + * remote-sim.h (sim_stop): New enum. + (sim_stop_signal): Change prototype, result is enum sim_stop. + * remote-sim.c (gdbsim_wait): Update call to sim_stop_signal. + +Fri Oct 22 07:49:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (define_symbol): Skip the whole thing about "pcc + promotion" on little-endian machines. + + * remote-vx.c (vx_wait): Rename pid parameter to pid_to_wait_for. + Some compilers (legitimately) don't like variables in the + function's outermost block whose name is the the same as the name of + a parameter. + + Merge Apollo patches from Troy Rollo (troy@cbme.unsw.edu.au): + * dst.h, dstread.c, config/m68k/{apollo68b.mt,tm-apollo68b.h}: + New files. + * config/m68k/nm-apollo68b.h: Add more defines. + * configure.in: Recognize apollo target, not just host. + + * configure.in: Add * to end of all OS names. + +Fri Oct 22 06:14:01 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (ALLPARAM): Add config/m88k/xm-delta88v4.h + +Thu Oct 21 12:23:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (init.c): Generate using the source, not munch. This + cleans up all kinds of hassles (which nm to use in munch, etc). The + new formatting conventions (mostly already followed) are that + the name of the _initialize_* routines must start in column zero, + and must not be inside #if. + * munch: Removed. + * Makefile.in: Remove references to munch. + * serial.c, remote.c, infptrace.c, maint.c, convex-tdep.c, + alpha-tdep.c, hp300ux-nat.c, hppab-nat.c, osfsolib.c, remote-es.c, + procfs.c, remote-udi.c, ser-go32.c, ultra3-xdep.c, sh-tdep.c, + i960-tdep.c, hppa-tdep.c, h8500-tdep.c, dpx2-nat.c, delta68-nat.c, + z8k-tdep.c: Make sure the above conventions are followed. Make + sure they are all declared as returning void. Clean up + miscellaneous comments and such. + + * sh-tdep.c (sim_load): Add function. + +Thu Oct 21 15:58:48 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * remote-mips.c (mips_wait): add pid argument. + +Thu Oct 21 12:23:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (c-exp.tab.o): Remove notice about shift/reduce conflicts + which no longer occur. + + gcc -Wall lint: + * findvar.c (symbol_read_needs_frame), corelow.c (ignore), + inflow.c (gdb_has_a_terminal): Make sure to return a value. + * regex.h: Declare re_set_syntax. + * printcmd.c: Include valprint.h. + * infcmd.c, exec.c, maint.c, core.c: Include language.h. + * maint.c: Include expression.h. + * infrun.c, fork-child.c, corelow.c, inflow.c: Include thread.h. + * inftarg.c: Include command.h. + * coredep.c: Include value.h. + * c-exp.y, m2-exp.y, ch-exp.y: Include bfd.h, symfile.h and objfiles.h. + * ch-typeprint.c: Include typeprint.h. + * ch-valprint.c: Include c-lang.h. + * nlmread.c: Include buildsym.h. + * environ.c: Include gdbcore.h. Only include defs.h once. + (set_in_environ): Cast const char * to char * when passing to + set_gnutarget. + * Makefile.in: Update dependencies to reflect all these new includes. + Remove unused variables: + * printcmd.c (printf_command): args_to_vprintf. + * coffread.c (coff_symfile_init): strsection. + Move variables to within the #ifdefs where they are used: + * symtab.c (gdb_mangle_name): opname. + * inftarg.c (child_attach): pid and exec_file. + * inftarg.c (child_detach): siggnal. + * objfiles.c (allocate_objfile): mapto, md, and fd. + * objfiles.c (free_objfile): mmfd. + * infrun.c (wait_for_inferior): Include BPSTAT_WHAT_LAST in switch. + * infrun.c (wait_for_inferior): Remove unused same_pid label. + * inferior.h: Declare set_sigint_trap and clear_sigint_trap. + * parser-defs.h: Declare write_exp_elt_block. + * stabsread.h: Declare elfstab_offset_sections and + coffstab_build_psymtabs. + +Thu Oct 21 12:05:08 1993 Ken Raeburn (raeburn@cygnus.com) + + Patch from Jeff Law: + * paread.c: Fix references to "hppa" that should now be "som". + +Thu Oct 21 12:23:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (decode_line_1): Don't use SYMBOL_LINE for functions. + +Thu Oct 21 02:59:07 1993 Stu Grossman (grossman at cygnus.com) + + * remote-udi.c (udi_store_registers, store_register): Use + UDI29KPC address space when modifying PC. It seems that you can't + modify the PC directly (at least in the isstip simulator). + +Wed Oct 20 11:35:43 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.h: Put remote_debug declaration back here. Add baud_rate. + * remote.c, remote-udi.c, remote-utils.h: Let target.h take care of + declaring these. Those random externs all over are error prone. + * Move "set remotebaud" from remote-utils.c to main.c to it applies + to remote.c as well. + + * xcoffread.c (xcoff_symfile_read), coffread.c (coff_symfile_read): + Sort symtabs for this objfile only, not for all objfiles. + * symfile.c, symfile.h (sort_all_symtab_syms): Remove; no longer used. + + * mipsread.c (parse_symbol): In third-eye, a function has a block + within it which represents the whole function. Create only one + GDB block for both. + +Wed Oct 20 17:47:42 1993 Stu Grossman (grossman at cygnus.com) + + * main.c: Make baud_rate and remote_debug be global variables, + remove #include "remote-utils.h". This makes it possible to build + GDB without remote-utils.c. Also, move setting of remote_debug + into main, so that all remote*.c files can use it (not just the + serial line ones). And, make baud_rate be an int. + * remote-udi.c: Change kiodebug to remote_debug. + * remote-utils.c: Move setting of baud rate and debug into main.c. + * remote-utils.h: Redefine sr_{get set}_debug and sr_{get set}_baud + to use baud_rate and remote_debug globals for compatibility. + * remote.c: Use remote_debug and baud_rate globals directly, + instead of sr_ functions, so that we don't need to load + remote-utils.c. + * config/a29k/a29k-udi.mt: Define REMOTE_O as null so that we don't + get the default remote* modules. + +Wed Oct 20 11:35:43 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (define_symbol): When combining a LOC_ARG and a + LOC_REGISTER, use the type from the LOC_REGISTER, not from the + LOC_ARG. + +Wed Oct 20 14:34:38 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * config/i386/xm-go32.h: define some signals if they aren't + already defined. + +Wed Oct 20 11:35:43 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (INTERNAL_LDFLAGS): New macro. The new part is + that we use CFLAGS and PROFILE_CFLAGS to link. + (gdb, rapp, kdb): Use INTERNAL_LDFLAGS instead of + LDFLAGS and/or GLOBAL_CFLAGS. + +Wed Oct 20 09:29:55 1993 Stu Grossman (grossman at cygnus.com) + + * Makefile.in: Add $(srcdir) to all refs to 29k-share + directories. + +Tue Oct 19 17:23:34 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (ALLCONFIG): Add config/i386/{i386m3.mh, i386m3.mt, + i386/i386mk.mh i386/i386mk.mt}, config/mips/{mipsm3.mh, + mipsm3.mt}, config/ns32k/{ns32km3.mh, ns32m3.mt} + * Makefile.in (remote_utils_h): Add remote-sim.h + * Makefile.in (NONSRC): Add i386-nlmstub.c + * Makefile.in (HFILES): Add coff-solib.h + +Tue Oct 19 14:15:40 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * values.c (value_virtual_fn_field): Fix the offset calculation + when calling virtual functions. (gdb.t22/virtfunc.exp). + * eval.c (evaluate_subexp): same as above. + +Tue Oct 19 10:43:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/rs6000/rs6000.mh (TERMCAP): Define to -lcurses. + + * Makefile.in: Define CXXFLAGS. + +Tue Oct 19 09:28:52 1993 Stu Grossman (grossman@cygnus.com) + + * sparclite/Makefile.in: Fixup so that this works with Sun make + and VPATH. + +Tue Oct 19 10:43:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.h (struct bpstat_what): Don't use bitfields. + + * typeprint.c: Add "class CLASS-NAME" to docstring for ptype. + +Tue Oct 19 06:17:10 1993 Fred Fish (fnf@cirdan.cygnus.com) + + * Makefile.in (ALLPARAM): Add config/m88k/{nm-delta88v4.h, + tm-delta88v4.h, xm-dgux.h}. + * Makefile.in (ALLCONFIG): Add config/m88k/{delta88v4.mh, + delta88v4.mt}. + + * README: Remove comment about SunOS 5.x programs leaving + coredumps. Info from Sun is that this was not in customer + releases. + +Mon Oct 18 10:28:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * hppa-tdep.c (restore_pc_queue): Call target_terminal_ours after + done stepping the inferior. + + * c-exp.y: Remove never-used (because of shift/reduce conflicts) + rules for pointers to members. + * Makefile.in: Remove notice about expected shift/reduce conflicts. + + * buildsym.c (finish_block): If we pop the context stack and it is + not empty, complain () instead of abort (). + +Sun Oct 17 19:42:31 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * parse.c, parser-defs.h (follow_types): New function. + * c-exp.y (ptype : typebase abs_decl): Use it. + * c-exp.y (ptype): Add support for type qualifiers after the + typebase. The typebase rule already has support for them before + the typebase. + * Makefile.in: Change the expected number of shift/reduce + conflicts to 6. This is OK--the 2 new conflicts are basically the + same as one of the old ones. + +Sun Oct 17 13:04:49 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.10.3. + +Sun Oct 17 09:18:57 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Clean up comments which were at + the top of the file, making them more concise and moving them with + the code (Sorry, Randy, but these stream-of-consciousness comments + really have to go). Switch the order of the "&&", which makes + things clearer and turns out to be an improvement with respect to + side effects and speed. + +Sun Oct 17 02:06:01 1993 Stu Grossman (grossman at cygnus.com) + + * procfs.c: Handle process exits more elegantly by trapping on + entry to _exit. Also, cleanup procinfo list when process dies of + it's own accord (as opposed to being killed). + +Sat Oct 16 20:47:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m88k/xm-dgux.h: Define NO_PTRACE_H. + + * corelow.c (add_to_thread_list): Need a cast to go from PTR to + asection *. + + * infrun.c: Add comment about signals. + + * fork-child.c (fork_inferior): Remove CREATE_INFERIOR_HOOK again. + Stu reinstated it (accidently I assume). + +Sat Oct 16 15:27:10 1993 Stu Grossman (grossman at cygnus.com) + + * procfs.c (procfs_wait): Losing Unixware can't do poll on /proc + files. Use PIOCWSTOP instead. + * corelow.c (add_to_thread_list): Fix arg to match prototype. + + * procfs.c (procfs_set_sproc_trap): Don't use this if sproc + isn't available. + * (procfs_notice_signals): Fix prototype. + +Fri Oct 15 22:46:07 1993 Stu Grossman (grossman at cygnus.com) + + * breakpoint.c (breakpoint_thread_match break_command_1): + Thread-specific breakpoint support. + * breakpoint.h (struct breakpoint): Add thread id field. + * fork-child.c (fork_inferior): Move call to init_thread_list() + back a bit so that init_trace_fun can do thread functions. + * hppa-tdep.c (restore_pc_queue): Add pid to call to target_wait. + * hppab-nat.c (child_resume): Handle default pid. + * hppah-nat.c (child_resume): Handle default pid. + * i386lynx-nat.c (child_wait): New arg pid. + * inflow.c (kill_command): Reset thread list. + * infptrace.c (child_resume): Handle default pid. + * infrun.c: Thread-specific breakpoint support. + * inftarg.c (child_wait): Add pid arg. + * osfsolib.c (solib_create_inferior_hook): Add pid to call to + target_resume. + * procfs.c: Multi-thread support. + * remote-bug.c (bug_wait): Add pid arg. + * remote-hms.c (hms_wait): Add pid arg. + * remote-mips.c (mips_wait): Add pid arg. + * remote-mon.c (monitor_wait): Add pid arg. + * remote-nindy.c (nindy_wait): Add pid arg. + * remote-sim.c (gdbsim_wait): Add pid arg. + * remote-udi.c (udi_wait): Add pid arg. + * remote-vx.c (vx_wait): Add pid arg. + * remote-z8k.c (sim_wait): Add pid arg. + * remote.c (remote_wait): Add pid arg. + * solib.c (solib_create_inferior_hook): Add pid to call to + target_resume. + * target.h (struct target_ops): Add pid arg to to_wait and + to_notice_signals. + * thread.c (valid_thread_id): New func to validate thread #s. + * (pid_to_thread_id): New func to do the obvious. + * thread.h: Prototypes for above. + + * coff-solib.c (coff_solib_add): Use nameoffset field to locate + filename. + +Fri Oct 15 21:29:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * h8300-tdep.c, h8500-tdep.c: Define sim_load only, but not + sim_kill, sim_open, or sim_set_args. + + * stack.c (print_stack_frame): Put catch_errors around + print_frame_info so (for example) error printing source doesn't + cause auto-displays to get skipped in normal_stop. + + * findvar.c (value_from_register): When preparing to cast a value + from REGISTER_VIRTUAL_TYPE to type, copy the REGISTER_VIRTUAL_SIZE; + the old code didn't copy the whole thing. + * valops.c (value_assign): Add comment. + +Fri Oct 15 12:57:30 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (upgrade_type): Replace bitsize sanity checks and + complaint by a comment explaining why they were useless. + +Fri Oct 15 14:30:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Move comments on bypassing call dummy breakpoint from stack.c + to breakpoint.h. + +Fri Oct 15 11:52:56 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.c (lookup_partial_symtab): If filename is not found and + contains no slashes, try again and compare without leading path + components. + * symtab.c (lookup_symtab_1): Replace open coded version of + lookup_partial_symtab with a function call. + +Thu Oct 14 20:34:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * fork-child.c (fork_inferior), remote-eb.c (eb_create_inferior), + remote-mon.c (monitor_create_inferior), remote-nindy.c + (nindy_create_inferior), remote-st.c (st2000_create_inferior), + remote-vx.c (vx_create_inferior): Remove CREATE_INFERIOR_HOOK; it + is replaced by init_trace_fun. + * config/convex/xm-convex.h, convex-xdep.c: Add comments explaining + how to do without CREATE_INFERIOR_HOOK for whoever fixes the Convex + port. + + * Makefile.in: Add Mach files to ALLDEPFILES, etc. + * m3-nat.c: Clean up more hair--message(), cprocs. + * configure.in: Recognize Mach targets and hosts. + * config/ns32k/tm-umax.h: Add some #ifndef's so tm-ns32km3.h can + include this file. + * Mach headers in config/*/tm-*.h: Fix includes to match correct + locations of files. + +Thu Oct 14 21:35:55 1993 Rob Savoye (rob@darkstar.cygnus.com) + + * remote-mon.c (general_open): Set dev_name. Minor tweaking to get + it working again. + * config/m68k/tm-monitor.h: Remove floating point register names + as there aren't any on any of the monitors that use this code. + +Wed Oct 13 11:47:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * inflow.c: Pass pointer to process group, not process group itself, + to TIOCSPGRP ioctl. + + * inflow.c (terminal_ours_1): Don't print warning on failure to + set process group. + + * printcmd.c (printf_command): Instead of using makeva* and + calling vprintf, just make the appropriate calls to printf. + * printcmd.c, config/pa/xm-pa.h, config/mips/xm-makeva.h, + config/alpha/xm-alpha.h, config/m88k/xm-m88k.h: Remove all + traces of makeva*. My apologies to everyone (including me!) + who spent so much time getting it to work on various machines, + but look at the bright side, at least you won't have to do it + again in the future. + + * printcmd.c (printf_command): Make a cleanup for val_args (fixes + a memory leak). + +Tue Oct 12 22:54:41 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/xm-mips.h: Remove comment about HAVE_SGTTY vs. usleep. + +Tue Oct 12 12:01:29 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * configure.in: only configure gdbserver for native environments + +Tue Oct 12 08:59:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (read_type): Treat a negative type number at the start + of a type as a type reference, not as a definition of a type with + "50=" omitted. This makes things work on the RS/6000 again (the + 14 Sep 1993 change broke it). + + * inflow.c: Use 0 (standard input) not scb->fd. + (terminal_ours_1): If printing warning, don't claim it happened in + terminal_inferior. + + * blockframe.c (get_prev_frame_info): Don't error() if there are no + frames; just return NULL. + + * xcoffsolib.h, xcoffexec.c: Undo the part of Fred's bfd->abfd + change which involved structure elements. It was unnecessary and + was not consistently done. + + * stabsread.h, stabsread.c, dbxread.c (common_block*, copy_pending): + Move common block handling from dbxread.c to stabsread.c. + Use the name from the BCOMM instead of the ECOMM. + Allocate things on the symbol_obstack. + * xcoffread.c (process_xcoff_symbol): Process C_BCOMM, C_ECOMM, + and C_ECOML. On unrecognized storage classes, go ahead and call + define_symbol (after the complaint). + + * dbxread.c (process_one_symbol): Don't relocate 'S' symbols by + the text offset. + +Tue Oct 12 12:33:09 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * osfsolib.c (solib_create_inferior_hook): Reset stop_soon_quietly + after shared library symbol reading to get rid of warning from + heuristic_proc_start. + +Tue Oct 12 12:01:29 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * remote-sim.c: fix unterminated character string + +Tue Oct 12 08:59:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c: Fix comment about gcc 2.3.3 stab for long long int. + +Mon Oct 11 14:27:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m3-nat.c, config/nm-m3.h: Add a target_ops struct and other + various things to try to get this to work. + + * symtab.h: Fix comments re headers, sharing blockvectors, etc. + +Mon Oct 11 11:46:06 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * config/i960/vxworks960.mt (REMOTE_O): add dcache.o and remote-utils.o + +Mon Oct 11 02:48:57 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_partial_symbols): Do not add undefined + symbols to the partial symbol table. + * alpha-tdep.c (init_extra_frame_info): Remove kludge for gcc, + gcc has to be compatible with the native tools. + * alpha-tdep.c (alpha_push_arguments): Rename NUM_ARG_REGS to + ALPHA_NUM_ARG_REGS and move its definition to tm-alpha.h. + * config/alpha/tm-alpha.h (FRAME_ARGS_ADDRESS): Change it to the + way the native tools define it, update comment. + +Fri Oct 8 15:54:06 1993 Fred Fish (fnf@deneb.cygnus.com) + + * osfsolib.c, remote-sim.c, remote.c, solib.c, xcoffexec.c, + xcoffsolib.h: Use 'abfd' for bfd variables instead of 'bfd'. + Sun cc doesn't like variable names that match their typedef'd type. + +Fri Oct 8 14:56:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * inflow.c: Remove unused includes of sys/param.h and sys/types.h. + + * inflow.c, ser-unix.c, ser-go32.c, ser-tcp.c, serial.h, + terminal.h, fork-child.c, main.c, utils.c: Move all the process + group stuff back to inflow.c and terminal.h; that's a better place + for it and fixes problems with trying to get/set the process group + of a tty we're doing remote debugging on. + * terminal.h: Skip the redefines and includes if HAVE_TERMIOS. + + * findvar.c, value.h (symbol_read_needs_frame): New function. + * c-exp.y, m2-exp.y: Call it instead of having our own switch on + the symbol's class. + * valops.c (value_of_variable): Use symbol_read_needs_frame to + decide whether we care about finding a frame. + +Fri Oct 8 02:34:21 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * blockframe.c (get_frame_block): Do not adjust pc if the frame + function was interrupted by a signal. + +Thu Oct 7 19:20:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/h8300/tm-h8300.h: Don't define sr_get_debug. + * remote-sim.c: Include remote-utils.h. + * target.h: Add comment about target_has_execution. + +Thu Oct 7 16:14:19 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * h8300-tdep.c (sim_load, sim_kill, sim_open, sim_set_args): + New functions. + * infrun.c (normal_stop): Don't try and set the pc in the current + frame coredump if there isn't one. + * remote-sim.c (gdbsim_store_register): Don't + SWAP_TARGET_AND_HOST, sim_store_register takes bytes in raw order. + (gdbsim_wait): Set status with WSETSTOP. + * config/h8300/tm-h8300.h (sr_get_debug): Define + +Thu Oct 7 12:56:57 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + New Mach stuff: + * config/i386/i386mach.c: Explain this is for the old (probably + non-functional and/or obsolete) Mach stuff. + * m3-nat.c, config/nm-m3.h, + i386m3-nat.c, mipsm3-nat.c, ns32km3-nat.c, + config/i386/{i386m3.mh,i386m3.mt,tm-i386m3.h,xm-i386m3.h}, + config/i386/{i386mk.mh,i386mk.mt,tm-i386mk.h,xm-i386mk.h}, + config/mips/{mipsm3.mh,mipsm3.mt,tm-mipsm3.h,xm-mipsm3.h}, + config/ns32k/{ns32km3.mh,ns32km3.mt,tm-ns32km3.h,xm-ns32km3.h}: + New files. + + * blockframe.c (find_pc_partial_function): If we call + PSYMTAB_TO_SYMTAB, call target_terminal_ours_for_output first. + This is needed now that wait_for_inferior passes in endaddr. + * infrun.c: Move call to target_terminal_inferior from proceed + to resume. + +Thu Oct 7 09:22:04 1993 Stu Grossman (grossman at cygnus.com) + + * blockframe.c (find_pc_partial_function): Fix handling for PCs + beyond the end of the last function in an objfile. + * coff-solib.c (coff_solib_add): Use BFD to get fields from .lib + section. + * infrun.c (wait_for_inferior): Modify test for subroutine entry + to include pc out of bounds of the previous function. + * remote.c (remote_wait): Use strtoul for parsing 'N' message. + Add code to relocate symfile_objfile->sections. + +Thu Oct 7 06:22:43 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/sparc/sun4os4.mh: Add comment saying why we don't use + -lresolv. + +Thu Oct 7 09:29:11 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * breakpoint.c, breakpoint.h (breakpoint_init_inferior): New function + that clears the `inserted' flag for all breakpoints and deletes + any breakpoints which should go away between runs of programs. + * inflow.c (generic_mourn_inferior), infrun.c (init_wait_for_inferior), + remote-es.c (es1800_load), comments in exec.c and corelow.c: + Use it instead of mark_breakpoints_out. + * breakpoint.c (mark_breakpoints_out): Update comment, tm-rs6000.h + uses it in a completely different context. + * breakpoint.c (breakpoint_re_set_one): Add bp_call_dummy case. + +Thu Oct 7 09:29:11 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * Makefile.in (REGEX, REGEX1): Always use our own version of + regex.c to be consistent across hosts. + * source.c (_initialize_source): Initialize regex to use grep + style syntax as an approximation to POSIX basic regex syntax. + +Wed Oct 6 12:43:47 1993 Jeffrey A Law (law@snake.cs.utah.edu) + Jim Kingdon (kingdon@lioth.cygnus.com) + + * hppa-tdep.c (frame_chain): Rework so that it correctly + handles boundaries where code with a frame pointer calls code + without a frame pointer. + (dig_fp_from_stack): New function. + +Wed Oct 6 12:43:47 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (delete_breakpoint): Don't insert a disabled breakpoint. + + * README: Add Alpha notes from Schauer. + +Tue Oct 5 15:26:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (install, uninstall): Remove $$n.1 stuff; I don't + understand what it is trying to do, but I suspect it's not doing + it. + + * config/ns32k/merlin.mh: Add comment about M_INSTALL. + * config/m88k/{delta88.mh,delta88v4.mh}: Remove M_INSTALL and + M_UNINSTALL; it tries to install a non-existent file gdb.z. + * Makefile.in: Remove M_INSTALL stuff; the above were the only uses. + + * stabsread.c (read_range_type): Remove comment which recommends + distinguishing float from complex by the name. + +Tue Oct 5 12:17:40 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + Jim Kingdon (kingdon@cygnus.com) + Stu Grossman (grossman@cygnus.com) + + Changes to support alpha OSF/1 in native mode. + * alpha-nat.c, alpha-tdep.c, config/alpha/alpha-osf1.mt, + config/alpha/nm-alpha.h, config/alpha/tm-alpha.h, osfsolib.c: + New files. + * Makefile.in: Add new files and dependencies. + * configure.in: Add alpha target. + * config/alpha/alpha-osf1.mh (NATDEPFILES): Add osfsolib.o + * config/alpha/alpha-osf1.mh (MH_CFLAGS): Remove, we can handle + shared libraries now. + * config/alpha/xm-alpha.h: Cleanup, get MAKEVA_* defines right. + + * defs.h (CORE_ADDR): Make its type overridable via CORE_ADDR_TYPE, + provide `unsigned int' default. + * breakpoint.c (breakpoint_auto_delete): Delete only if we really + stopped for the breakpoint. + * stabsread.c, stabsread.h (define_symbol): Change valu parameter + to a CORE_ADDR. + * stabsread.c (read_range_type): Handle the case where the lower + bound overflows and the upper doesn't and the range is legal. + * infrun.c (resume): Do not step a breakpoint instruction if + CANNOT_STEP_BREAKPOINT is defined. + + * inferior.h (CALL_DUMMY_LOCATION): New variant AT_ENTRY_POINT. + Now that we have the bp_call_dummy breakpoint the call dummy code + is no longer needed. PUSH_DUMMY_FRAME, PUSH_ARGUMENTS and + FIX_CALL_DUMMY can be used to set up everything for the dummy. + The breakpoint for the dummy is set at the entry point and thats it. + * blockframe.c (inside_entry_file, inside_entry_func): Do not stop + backtraces if pc is in the call dummy at the entry point. + * infcmd.c (run_stack_dummy): Handle AT_ENTRY_POINT case. Use + the expected breakpoint pc when setting up the frame for + set_momentary_breakpoint. + * symfile.c (entry_point_address): New function for AT_ENTRY_POINT + support. + * valops.c (call_function_by_hand): Handle AT_ENTRY_POINT case. + +Tue Oct 5 11:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * configure.in: Recognize hppa*-*-hiux* (currently synonym for hpux). + Change other hppa host entries to use -*- not -hp-. + +Mon Oct 4 19:16:14 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i386-nlmstub.c: New file; debugging stub for i386 NetWare. Must + be compiled with NetWare header files and turned into an NLM with + nlmconv. + +Mon Oct 4 11:02:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * minsyms.c (lookup_minimal_symbol_by_pc): Don't use mst_abs symbols. + + * dbxread.c (process_one_symbol): Make n_opt_found static. + + * Rename i386lynx-tdep.c to i386ly-tdep.c for 14 character file names. + * Makefile.in, config/i386/i386lynx.mt: Change accordingly. + + * values.c (record_latest_value): Fetch lazy values and set VALUE_LVAL + to not_lval. + +Sun Oct 3 15:54:51 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * objfiles.h (objfile): New slot sym_stab_info, use by most + stab-reading formats. + * gdb-stabs.h (DBX_SYMFILE_INFO): Access sym_stab_info instead of + sym_private. + * coffread.c (coff_symfile_init): Alloc struct for sym_stab_info. + * dbxread.c, elfread.c, paread.c: Change sym_private references to + sym_stab_info references. + +Sat Oct 2 19:28:35 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mipsread.c, objfiles.c, utils.c: Use PTR not void *. RISC/OS + 4.02 lacks void *. + * elfread.c: Use void * not PTR inside PARAMS. + + * config/mips/news-mips.mh: Remove coredep.o; mips-nat.o does it. + * config/mips/news-mips.mh: Define NAT_FILE not NM_FILE. + * config/mips/nm-news-mips.h: Include mips/nm-mips.h not nm-mips.h. + +Sat Oct 2 16:05:22 1993 Stu Grossman (grossman at cygnus.com) + + * Makefile.in, coff-solib.c, coff-solib.h, i386lynx.mt, + tm-i386lynx.h: Add support for SVR3 COFF shared libraries. + +Sat Oct 2 15:50:41 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m88k-nat.c (store_inferior_registers): When writing all registers, + don't try to write EXIP_REGNUM or ENIP_REGNUM (not needed for this + case, and they cause trouble). + + * TODO: Don't suggest doing fast watchpoints by stepping a line + at a time. That would be really hairy and still not fast enough. + Do suggest debug registers and page table diddling. + +Fri Oct 1 14:54:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (do_examine): Make meaning of 'h', 'w', and 'g' not + depend on builtin_type_*. Instead, it is always 2, 4, and 8 bytes + like the documentation says. + * printcmd.c (decode_format) [CC_HAS_LONG_LONG]: Remove 'l' as + synonym for 'g'. This was never documented, it shouldn't depend on + CC_HAS_LONG_LONG, and I don't see what's wrong with 'g'. + +Fri Oct 1 10:06:35 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * symtab.c: fix a bug in testsuite (virtfunc.exp) + +Thu Sep 30 11:30:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m88k-nat.c (fill_gregset): Fix typo (R_SFIP -> R_FIP). + + * c-typeprint.c (c_type_print_base, TYPE_FN_FIELD_STUB code): + If demangled name lacks a colon, don't dump core. + + * blockframe.c (find_pc_partial_function): If pst->readin is + set, don't try to get symbols from pst. + + * inflow.c (generic_mourn_inferior): Call reinit_frame_cache + instead of doing it ourself. + * blockframe.c (reinit_frame_cache): Use code which was in + generic_mourn_inferior so we can use this function even when + we have switched targets. + * corelow.c (core_detach): Call reinit_frame_cache. + * target.c (target_detach): Don't call generic_mourn_inferior + (revert yesterday's change, now handled by core_detach). + * objfiles.c (free_objfile): Detach any core file if we call + SOLIB_CLEAR. #include target.h. + + * fork-child.c (fork_inferior): Don't call target_terminal_init + and target_terminal_inferior until we are sure that the inferior + has called gdb_setpgid. This fixes PR 2900 (Schauer tracked it + down and was able to reliably reproduce it by putting a sleep() + before the gdb_setpgid()). + +Thu Sep 30 12:00:49 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * c-exp.y, m2-exp.y: Change type of address for msymbol to + builtin_type_long. + * infptrace.c (fetch_register, store_inferior_register, + child_xfer_memory): Use PTRACE_XFER_TYPE for the type of ptrace + transfers. Provide an `int' default for PTRACE_XFER_TYPE. + +Thu Sep 30 11:30:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * defs.h (TARGET_*_BIT): Don't use host information (sizeof) in + picking defaults. + + * cp-valprint.c (cp_is_vtbl_ptr_type): Continue to accept old form. + +Thu Sep 30 11:25:55 1993 Kung Hsu (kung@cygnus.com) + + * cp-valprint.c (cp_is_vtbl_ptr_type): + change vtable field name to __vtbl (pr2695). + + * symtab.c (gdb_mangle_name): fix a bug, to get mangled name right. + +Wed Sep 29 18:34:22 1993 Stu Grossman (grossman at cygnus.com) + + * Makefile.in: Add deps for i386lynx-nat.o and i386lynx-tdep.o to + keep non-gnu makes happy. + +Wed Sep 29 17:20:54 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hpux_symtab): When a K_END is found for a + K_MODULE, clear the have_module and have_name flags. + +Wed Sep 29 10:52:19 1993 Kung Hsu (kung@cygnus.com) + + * c-valprint.c: to fix virtual table print bug (pr2695). + +Wed Sep 29 10:52:19 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.c (target_detach): Call generic_mourn_inferior. + * inflow.c (generic_mourn_inferior): Call flush_cached_frames. + +Tue Sep 28 23:08:59 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c, coffread.c, elfread.c: A few changes to comments. + +Tue Sep 28 18:39:37 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * configure.in: Rename ...-lynx* to ...-lynxos*. + Add m68*-*-lynxos* configuration. + * dbxread.c (coffstab_build_psymtabs): New function, + interfaces coffread.c to dbxread functions. + * coffread.c (coff_symfile_info): Expand to include + dbx_symfile_info slots. + (coff_symfile_init): Init coff_symfile_info struct. + (coff_locate_sections): New functions, finds the stab and stabstr + sections. + (coff_symfile_read): Call coffstab_build_psymtabs if a stab + section is present. + (coff_section_offsets): Replace fake version with real offsets. + +Tue Sep 28 18:00:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infcmd.c (run_stack_dummy): Set the frame in the bp_call_dummy + breakpoint. + +Tue Sep 28 17:53:26 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * config/nm-sysv4.h: Include solib.h. Define SVR4_SHARED_LIBS. + * config/tm-sysv4.h: Don't include solib.h. + * config/xm-sysv4.h: Don't define SVR4_SHARED_LIBS. + * config/i386/i386v4.mt (TDEPFILES): Move solib.o from here... + * config/i386/i386v4.mh (NATDEPFILES): ...to here. + * config/i386/nm-i386v4.h: Include nm-sysv4.h. + * config/m68k/amix.mt (TDEPFILES): Move solib.o from here... + * config/m68k/amix.mh (NATDEPFILES): ...to here. + +Tue Sep 28 09:45:38 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symmisc.c (print_symbol): Use %02x not %2x for LOC_CONST_BYTES. + + Clean up problems with targets and hosts that have 64 bit longs + and pointers and 32 bit ints. + * breakpoint.c, buildsym.c, c-lang.c, c-valprint.c, ch-lang.c, + ch-valprint.c, core.c, cp-valprint.c, dbxread.c, exec.c, + expprint.c, gdbtypes.c, infcmd.c, language.c, language.h, + m2-lang.c, maint.c, mips-tdep.c, mipsread.c, partial-stab.h, + printcmd.c, remote-vx.c, solib.c, source.c, stack.c, symfile.c, + symmisc.c, symtab.c, valops.c, valprint.c, xcoffexec.c: + Change all printf formats from %x to %lx if outputting an address. + Change la_*_format to use long format. + local_hex_string, local_hex_string_custom now take an unsigned long + argument, change all callers. + * coffread.c (read_coff_symtab): Remove superfluous cast for + complaint output. + * dbxread.c (end_psymtab): Cast MSYMBOL_INFO to long, not int. + * findvar.c, value.h (write_register): Change val to LONGEST. + * gdbtypes.h (struct type): Change `bitsize' to long as + TYPE_FIELD_STATIC_PHYSNAME uses this field as a pointer. + * inferior.h (struct inferior_status): Change type of stop_pc to + CORE_ADDR. + * language.h (local_octal_string, local_octal_string_custom): + Remove prototype, the functions are neither defined nor used. + * mipsread.c (parse_symbol): Use temporary variable for bitsize as + f->bitsize is a long now. + * objfiles.c (add_to_objfile_sections, build_objfile_section_table): + Use unsigned long casts instead of int for abusing sections_end + pointer as integer. + * stack.c (parse_frame_specification): Change type of `args' to + CORE_ADDR for SETUP_ARBITRARY_FRAME. + + * printcmd.c (make_vasize): Allow redefinition via MAKEVA_SIZE. + * mipsread.c (parse_type): Alpha cc now supports the t->continued + bit, update algorithm to match the way the compiler uses it. + +Tue Sep 28 12:05:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (fprintfi_filtered): Fix comments. + +Mon Sep 27 18:10:08 1993 Stu Grossman (grossman at cygnus.com) + + * coffread.c (read_coff_symtab): Don't call getfilename if there + are no auxents. + +Mon Sep 27 10:22:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (find_pc_line): Fix comments. + + * remote-udi.c (udi_mourn): Don't pop target. + +Fri Sep 24 17:25:41 1993 Stu Grossman (grossman at cygnus.com) + + * corelow.c: Add multi thread/process support for core files with + .reg/XXX pseudo-sections. + * i386lynx-nat.c thread.h thread.c: Remove unnecessary core file + support. + +Thu Sep 23 10:49:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c (download): Skip zero length sections. + + * valops.c (search_struct_method, value_struct_elt): + Use (value)-1, not -1, for error. + + * infcmd.c (step_1), infrun.c (wait_for_inferior): Add comments + about SHIFT_INST_REGS. + + * exec.c (exec_file_command): Set text_end based on all code readonly + sections, not just ".text". + + * defs.h, infcmd.c, config/z8k/tm-z8k.h, config/m88k/tm-m88k.h, + config/sh/tm-sh.h, config/h8300/tm-h8300.h, config/h8500/tm-h8500.h, + z8k-tdep.c: Remove all references to ADDR_BITS_SET. + * config/m88k/tm-m88k.h: Define TARGET_WRITE_PC. + + * config/m88k/tm-m88k.h, m88k-tdep.c: Add call function stuff. + +Thu Sep 23 00:13:06 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/tm-mips.h (STORE_STRUCT_RETURN): Define as noop as + the pushing of the struct return address is already handled in + mips_push_arguments. + * mips-tdep.c (reinit_frame_cache_sfunc): Fix typo in prototype + declaration. + * mipsread.c (parse_symbol, parse_type, upgrade_type): Add more + sanity checks for corrupt symbol entries to avoid core dumps + reported by benson@odi.com. Obviously Ultrix 4.3A cc now has + the same problems as the OSF/1 alpha cc. + * mipsread.c (parse_lines): Iterate over the range of the compressed + line number entries, the old iteration sometimes failed to stop + and wrote past the end of the LINETABLE. Add sanity check to avoid + the same problem in case the line number info is corrupt. + * mipsread.c (parse_procedure): Adjust pdr for alpha __sigtramp. + * mipsread.c (parse_external, parse_partial_symbols): Ignore stNil + symbols that are produced for statics in .o files and stLocal symbols + that are produced for every section in OSF/1 dynamically linked + executables. + * mipsread.c (psymtab_to_symtab_1): Put out `undefined symbols' + warning only under `verbose on' as there are many undefined symbols + in a dynamically linked executable. + +Wed Sep 22 10:28:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i960/nindy960.mt: Don't define REMOTE_O; REMOTE_O was + intended only for VxWorks. Remove dcache.o from TDEPFILES now + that we pick it up from the default REMOTE_O. + + * breakpoint.c (bpstat_what): Initialize retval.call_dummy and + retval.step_resume. + + * mips-tdep.c (mips_frame_chain): If frame size zero, return zero. + * rs6000-tdep.c: Add comment about framelessness. + + * remote-nindy.c: Declare ninMemGet and ninMemPut. + +Wed Sep 22 08:02:57 1993 Stu Grossman (grossman at cygnus.com) + + * Makefile.in: Add i386lynx-tdep to the right places. + (TARDIRS): Add gdbserver. + + * exec.c (print_section_info): Print entry point. + * i386lynx-nat.c (i386lynx_saved_pc_after_call): Move into + i386lynx-tdep.c. Add core file support. + * i386lynx-tdep.c: New module for Lynx/386 target dependant code. + * maint.c: Add `maint info sections' command to print info about all + sections that BFD knows about for exec and core files. + * sparc-tdep.c (sparc_push_dummy_frame): Update stack pointer + before putting frame on the stack. Consolidate writes to reduce + traffic for remote debugging. + * config/i386/i386lynx.mh (NATDEPFILES): Remove exec.o. + * config/i386/i386lynx.mt (TDEPFILES): Add exec.o, i386lynx-tdep.o. + * config/i386/nm-i386lynx.h: Add target_pid_to_str(). + * config/i386/tm-i386lynx.h: Remove target_pid_to_str(). + * sparclite/Makefile.in: Add deps to keep Sun make happy. + +Tue Sep 21 17:48:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.h, breakpoint.c (bpstat_stop_status): Add new argument + not_a_breakpoint. + * infrun.c (wait_for_inferior): Pass it. Also consolidate the + test of whether we are stepping into a CURRENTLY_STEPPING macro. + +Tue Sep 21 17:22:34 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * breakpoint.c (bpstat_stop_status), + infcmd.c (step_1), + infrun.c (wait_for_inferior): collapse SHIFT_INST_REGS ifdef + and insert macro. + + * m88k-tdep.c: include ieee-float.h. new global target_is_m88110. + new const struct ext_format_m88110 for float format. + (pic_prologue_code): add braces. + (next_insn): remove unused variable buf. + (frame_find_saved_regs): remove unused variables next_addr, + saved_regs, regnum. + (frame_locals_address): remove unused variables frame, ap. + (frame_args_address): remove unused variables frame, ap. + (push_parameters): add some breaks and a default case. + + * remote-bug.c: remove redundant includes of value.h, target.h, + serial.h. + (bug_open): corrected typo, sr_multi_scan -> gr_multi_scan. + (bug_fetch_register): special case sfip register for m88110. + remove flag bit masking of pc registers. This should be handled + by the ADDR_BITS_* macros. + (bug_store_register): special case sfip register for m88110. + Corrected sprint format for extended registers. + + * config/m88k/tm-m88k.h: white space and comment changes. include + ieee-float.h. expanded to cope with m88110 extended registers. + (R0_REGNUM, XFP_REGNUM, X0_REGNUM): new macros. + (SHIFT_INST_REGS): becomes a real macro. + +Tue Sep 21 17:48:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (breakpoint_1): Support bp_call_dummy. + +Tue Sep 21 17:06:19 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * elfread.c (record_minimal_symbol_and_info): Guess the section to + use from the type. + * objfiles.c: Include gdb-stabs.h for SECT_* macros. + (objfile_relocate): Relocate textlow and texthigh in psymtabs. + Relocate partial symbols. Check that minimal SYMBOL_SECTION is + nonnegative before using it. + * symtab.h: Adjust section field comment. + + * remote.c (interrupt_query): New function. + (remote_interrupt_twice): Call interrupt_query. + (putpkt, getpkt): If quit_flag is set, call interrupt_query. + (remote_wait): Don't bother with objfile_relocate if the addresses + haven't changed. + (remote_fetch_registers): If we see a packet that doesn't start + with a hex character, fetch a new one. + +Tue Sep 21 11:44:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c, remote-utils.c: Use SERIAL_FLUSH_INPUT after opening it. + + * printcmd.c (print_scalar_formatted): When truncating value we are + going to print as unsigned, handle it generally for any length + less than sizeof (LONGEST), rather than special-casing sizeof (char), + sizeof (short), and sizeof (long). Clarify comment on what this + is for. + + * symfile.c (deduce_language_from_filename): Accept .cxx for C++. + * buildsym.c (start_subfile): Use deduce_language_from_filename + rather than checking for .C or .cc ourself. + +Mon Sep 20 14:53:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * defs.h: Declare argument of re_comp as const char *. + + * remote.c, remote-mips.c: Use sr_get_debug not remote_debug. + + * README: Say using bfd from another release doesn't generally work. + +Sat Sep 18 10:13:18 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * mipsread.c (parse_type): Don't complain() if we guessed struct + and it was a union, or vice versa. + + * defs.h (make_cleanup): Change PTR to void * when inside PARAMS. + + Some of the following is in #ifdef CALL_DUMMY_BREAKPOINT_OFFSET. + * breakpoint.h (enum bptype): Add bp_call_dummy. + (struct bpstat_what): Add call_dummy field. + * infrun.c (wait_for_inferior): Deal with it. + * breakpoint.c (bpstat_what): Deal with call dummy breakpoint. + * infcmd.c (run_stack_dummy): Set the call dummy breakpoint. + * config/sparc/tm-sparc.h: Define CALL_DUMMY_BREAKPOINT_OFFSET. + + * remote-sim.h: New file. + * remote-sim.c: Add remote debug feature. Rename stuff to distinguish + interface to simulator from gdb-specific stuff. Other changes. + * remote-sp64sim.c: Renamed to remote-sim.c. + Use sr_get_debug instead of our own sim_verbose/simif_snoop. + Use gnutarget in call to bfd_openr. + Rename simif_* to gdbsim_*. + * config/sparc/sp64sim.mt: Change remote-sp64sim.c to remote-sim.c. + +Fri Sep 17 04:41:17 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * findvar.c (extract_signed_integer): Cast *p to LONGEST before doing + the xor and subtract. Otherwise it will not sign extend if the type + of LONGEST is larger than int. + * cp-valprint.c (cp_print_class_method): Inhibit core dump if + domain is an undefined cross reference. + * valops.c (call_function_by_hand): Set real_pc to correct + value if CALL_DUMMY_LOCATION != ON_STACK. + +Thu Sep 16 20:37:06 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * config/a29k/tm-a29k.h (FRAME_CHAIN): If rsize is zero, return zero. + +Thu Sep 16 13:16:22 1993 Stu Grossman (grossman at cygnus.com) + + * infrun.c (wait_for_inferior): Allow user to single step within + a stack dummy. + +Thu Sep 16 12:34:01 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * dbxread.c (copy_pending): Deal with END NULL. + (process_one_symbol): Add comments about what common_block NULL means. + +Wed Sep 15 14:50:26 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * remote-udi.c, remote-adapt.c, remote-mm.c: Move processor_type + to tm-a29k.h and a29k-tdep.c and make it an enum. + * a29k-tdep.c (a29k_get_processor_type): New function. Fix many + aspects of how we detected the processor type. + * remote-udi.c, remote-adapt.c, remote-mm.c (*_open): Call it + rather than figuring out the type ourselves. + +Thu Sep 16 12:12:59 1993 Stu Grossman (grossman at cygnus.com) + + * sparc-stub.c (_trap_low): Do restore/save sequence after + setting sp to ensure that we load the previous window from the + right place on the stack. + +Thu Sep 16 00:36:32 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c: Many changes for alpha ecoff format: + Correct sizeof(int) == sizeof(long) assumptions. + Replace stParsed hack by putting the parsed types on the pending chain. + Replace mips specific ecoff mapping by ECOFF_REG_TO_REGNUM macro, + provide default for cross debugging. + Swapping the symbol back is no longer needed as the symbol is not + modified anymore. + Add new alpha basic types, handle btTypedef, handle stStaticProc + external symbols . + Update and clean up cross_ref for alpha cc cross ref variations. + Allocate types on the type_obstack to inhibit storage leaks. + * config/mips/tm-mips.h (ECOFF_REG_TO_REGNUM): Define. + * gdbtypes.c (recursive_dump_type): Dump TYPE_TAG_NAME if it is set. + +Tue Sep 14 09:12:17 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * stabsread.c (read_type): Process "s" (size) type attribute. + If type is defined to another type, copy the type. + +Tue Sep 14 18:37:17 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * config/i386/i386v4.mh (NATDEPFILES): Move exec.o from here... + * config/i386/i386v4.mt (TDEPFILES): ...to here. + +Tue Sep 14 12:21:49 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * Makefile.in (remote_utils_h): add serial.h and target.h. + (main.o, remote-es.o, remote-nindy.o, remote.o): remove target.h + (already in remote_utils_h). + (remote-utils.o): new rule. + + * remote-utils.h: include serial.h. + + * serial.h: ifdef protect from multiple inclusion. + + * remote.c, remote-nindy.c, remote-mon.c, remote-es.c: include + remote-utils.h. + + * remote.c (remote_open), remote-nindy.c (nindy_open, + nindy_files_info), remote-mon.c (general_open), remote-es.c + (es1800_open): use remote-utils facilities for baud rate. + +Tue Sep 14 09:12:17 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * paread.c, coffread.c, elfread.c, dwarfread.c: + Include and before libbfd.h. + + * paread.c: Define BYTES_IN_WORD before including aout/aout64.h. + + * Makefile.in (a29k-tdep.o): Depend on $(defs_h). + * config/a29k/tm-a29k.h (SAVED_PC_AFTER_CALL): Use gr122 not lr0 + if this is a transparent procedure. + +Mon Sep 13 16:06:43 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * remote.c: Define remote_debug to 0 and #if 0 baud_rate. Temporary + hack so this file compiles again. + + * remote-utils.c (gr_multi_scan): Cast return value from alloca. + (gr_multi_scan): #if 0 never-reached return(-1). + + * remote-udi.c (udi_wait): Return inferior_pid not 0. + +Mon Sep 13 14:14:35 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + Collect some remote things into remote-utils. + * remote-utils.[ch]: new files of functions collected from several + different remote targets. + * Makefile.in (REMOTE_O): add remote-utils.o. + (dcache_h, remote_utils_h): new macros. + (HFILES): add $(remote_utils_h). + (ALLDEPFILES): add $(remote_utils_h). + (dcache.o): new rule. + (main.o, remote-bug.o): also depend on $(remote_utils_h). + * target.h (remote_debug): extern moved to remote-utils.h. + * target.c (find_default_run_target, find_core_target): initialize + runable. + (remote_debug): moved to remote-utils.c. + (_initialize_targets): move declaration of user variable + remotedebug to remote-utils.c. + * remote-bug.c: include remote-utils.h rather than dcache.h. + (bug_close, bug_write, bug_write_cr, desc, bug_dcache, timeout, + dev_name, check_open, is_open, readchar, readchar_nofail, + pollchar, expect, expect_prompt, get_hex_digit, get_hex_byte, + get_hex_word, bug_kill, bug_detach, bug_create_inferior, + multi-scan, bug_prepare_to_store, bug_fetch_word, + bug_store_word, bug_files_info, bug_mourn, bug_com, bug_device, + bug_speed): removed and replaced with facilities from + remote-utils.[ch]. + (bug_read_inferior_memory): renamed to bug_read_memory. + (bug_write_inferior_memory): renamed to bug_write_memory. + (bug_xfer_inferior_memory): renamed to bug_xfer_memory. + (get_word): comment out this unused function for now. + (bug_settings, cpu_check_strings): new statics. + (bug_open): rewritten to use gr_open. + (_initialize_remote_bug): remove declarations of commands bug, + device, speed. + * main.c: include remote-utils.h. + (baud_rate): removed to remote-utils.c. + (main): handle baud rate settings using new facilities from + remote-utils. + * defs.h (baud_rate): removed extern. + + m88110 support via bug-197 monitor. + * remote-bug.c (get_reg_name, bug_fetch_register, + bug_store_register): added m88110 extended register support. + (wait_strings): added bug-197 prompt. + (bug_wait): cope with bug-197 prompt. + (start_load): cope with either bug-197 or bug-187 prompt. + +Mon Sep 13 12:53:09 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * inferior.h, infrun.c, thread.c, infcmd.c: Remove all uses of + pc_changed. If it was ever set to a non-zero value, it was before + GDB 2.8. It doesn't seem to have any useful function. + + * defs.h: Don't define NORETURN (see comment). + +Sat Sep 11 10:46:09 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * m88k-nat.c (fill_gregset): Set r31 and sfip. + +Thu Sep 9 10:18:29 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c (udi_wait, case UDIStdinNeeded): Use a loop calling + getchar() (terminated only on '\n') instead of scanf. Send the + '\n' which terminates it to the remote system. + + More gcc lint: + * exec.c (ignore): Return 0. + * stack.c (return_command): Fetch lazy value directly, not via + VALUE_CONTENTS, to avoid "value computed is not used". + * inflow.c (new_tty): Move osigttou inside #if. + + * remote.c (remote_fetch_registers): If remote reply is short, just + note that fact and keep going (reading extra registers as all bits 0). + (remote_store_registers): Send number of registers that were found + by remote_fetch_registers. + * m68k-tdep.c, config/m68k/tm-m68k.h, config/m68k/tm-*.h: Remove + HAVE_68881. Define CANNOT_STORE_REGISTER if ptrace() can't write + floating registers. + * config/m68k/{tm-m68k-nofp.h,m68k-nofp.mt,tm-m68k-fp.h,m68k-fp.mt}: + Remove, replaced by {tm-m68k-em.h,m68k-em.mt}. + * Makefile.in, configure.in: Change accordingly. + +Thu Sep 9 04:59:03 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (cross_ref): Allow SGI extended symbol types as cross + reference targets. + * symmisc.c (print_symbol): Use TYPE_TAG_NAME not TYPE_NAME to avoid + printing of identities. + +Wed Sep 8 19:18:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (breakpoint_1): Deal with step resume breakpoint. + +Wed Sep 8 13:01:10 1993 K. Richard Pixley (rich@cygnus.com) + + Gcc lint. + * config/m88k/tm-m88k.h (frame_find_saved_regs): prototype. + * config/h8300/tm-h8300.h (NUM_REGS): rewrite to avoid nested comment. + * blockframe.c (get_prev_frame_info): initialize address. + * breakpoint.c (bpstat_copy): initialize retval. + (bpstat_stop_status): initialize value_is_zero. + (bpstat_what): initialize bs_class. + (breakpoint_1, mention): add do-nothing case for bp_step_resume. + (break_command_1): initialize cond_end, addr_end, & + canonical_strings_chain. + (enable_breakpoint): initialize save_selected_frame. + * buildsym.c (end_symtab): initialize symtab & linetablesize. + * c-exp.y (parse_number): initialize i. + * c-typeprint.c (c_type_print_varspec_prefix): include + TYPE_CODE_BITSTRING in switch statements and do nothing. + * c-valprint.c (c_val_print): removed unused variable c. + * ch-valprint.c (chill_val_print): removed unused variable eltlen. + * cp-valprint.c (cp_print_class_method): initialize f & j. + * eval.c (evaluate_subexp): initialize pc2, arg1, arg2. + * expprint.c (print_subexp): initialize myprec, assoc, & tempstr. + * findvar.c (value_from_register): initialize first_addr. + * gdbtypes.c (lookup_struct_elt_type): localize use of temporary + variable typename. + * infcmd.c (run_stack_dummy): return zero rather than simple + return. + * infrun.c (wait_for_inferior): initialize stop_sp, prologue_pc. + remove symtab, appears unused. + (restore_selected_frame): return 1. + * mipsread.c (psymtab_to_symtab_1): initialize first_off. + (fixup_sigtramp): initialize b0. + * printcmd.c (do_examine): initialize val_type. + (print_frame_args): initialize b. + * ser-tcp.c (tcp_restore): comment out declaration. Appears + unused. + * ser-unix.c (hardwire_restore): comment out declaration. Appears + unused. + (hardwire_send_break): moved variable status into ifdef + HAVE_SGTTY. + (wait_for): moved variable numfds into ifdef HAVE_SGTTY. + * serial.h: comment change only. + * stabsread.c (rs6000_builtin_type): initialize rettype. + (read_range_type): initialize nbits. + * stack.c (print_frame_info): remove unused variable numargs. + (parse_frame_specification): remove unused variables arg1, arg2, + arg3. + (return_command): initialize return_value. + * symfile.c (cashier_psymtab): initialize pprev. + * symtab.c (find_pc_psymbol): initialize best. + (lookup_symbol): initialize s. + (make_symbol_completion_list): initialize quote_pos. + * thread.c: include command.h. + (thread_info): static declaration removed; unused. + (info_threads_command): fix == vs = typo. + * typeprint.c (whatis_exp): initialize old_chain. + * valprint.c (val_print_string): remove unused variable + first_addr_err. Initialize old_chain. + (_initialize_valprint): white space comment change. + * values.c (show_values): rewrite if statement to avoid empty + body. + (vb_match): remove unused variable fieldtype_target_type. + +Wed Sep 8 10:21:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (mipsread.o): Depend on $(bfd_h). + +Tue Sep 7 13:06:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/Makefile.in (TAGS): config files are in + $(srcdir)/../config, not $(srcdir)/config. + + * config/pa/tm-hppa.h: Declare target_read_pc and target_write_pc. + (STORE_RETURN_VALUE): Pass the correct offset of the return + register to write_register_bytes. + * hppa-tdep.c: Use target_write_pc if PCOQ_TAIL_REGNUM was not saved. + +Tue Sep 7 14:30:34 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * remote.c (remote_wait): Don't call error. Instead, call warning + inside a loop. User can ^C to get out. + + * config/m68k/tm-m68k.h (FIX_CALL_DUMMY): Changed name of swapping + routine to match BFD name change. + * config/z8k/tm-z8k.h (FIX_CALL_DUMMY): Likewise. + +Mon Sep 6 15:01:57 1993 Jeffrey Wheat (cassidy@cygnus.com) + + * elfread.c: change elf32_symbol_type to elf_symbol_type + +Mon Sep 6 15:43:25 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * remote.c (remote_wait): Added 'W' and 'N' responses. + +Fri Sep 3 08:57:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c, utils.c: Add comments about immediate_quit. + + * elfread.c (elf_symtab_read): Don't add symbols starting with ".L" + to minimal symbols. + + * target.c (pop_target): Don't try to deal with the stack becoming + empty. Shouldn't happen and the code that tried was broken. + + * dcache.c: Cast return value from xmalloc. + + * remote.c: Move setting of immediate_quit from remote_open to + remote_start_dummy and set it back to zero when done. + +Thu Sep 2 00:07:36 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m88k-tdep.c: Remove a bunch of unused #includes. + + * language.h: Add comment about current_language. + + * mips-tdep.c (_initialize_mips_tdep): Change heuristic-fence-post + from var_uinteger to var_zinteger. + + * configure.in: Fix typo (delta88r4 -> delta88v4). + + * config/m88k/xm-delta88.h: Don't include sys/siginfo.h. It was + to make this work on SVR4 before SVR4 had its own configuration, + and it breaks SVR3. + + * config/m88k/tm-delta88v4.h: Define FRAME_CHAIN_VALID_ALTERNATE. + + * config/m88k/delta88v4.h (NATDEPFILES): Remove infptrace.o inftarg.o. + + * config/m88k/xm-dgux.h: Renamed from config/m88k/xm-m88k.h. + * config/m88k/m88k.mh: Use xm-dgux.h. + * config/m88k/xm-m88k.h: New file, with HOST_BYTE_ORDER, + MAKEVA_END and MAKEVA_ARG. + * config/m88k/xm-*.h: Include m88k/xm-m88k.h. + * printcmd.c: Remove __INT_VARARGS_H code; now in xm-m88k.h. + +Wed Sep 1 19:31:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c (udi_wait): Call `warning' not `error'. + + * symtab.c (COMPLETION_LIST_ADD_SYMBOL): If the symbol has a + demangling, don't put the mangled form in the completion list. + + * symtab.c, symfile.c, c-exp.y, ch-exp.y, m2-exp.y, buildsym.c, + symfile.h, stabsread.c, minsyms.c, solib.c, nlmread.c, dwarfread.c + partial-stab.h, symmisc.c, gdbtypes.c: Lint. Remove (or put + inside #if) unused variables and labels. Fix unclosed comment. + Deal with enumeration values unhandled in switch statements. Make + sure non-void functions return values. Include appropriate + headers. + * dbxread.c (elfstab_build_psymtabs): Don't check for unsigned + value < 0. + +Wed Sep 1 14:36:00 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * i960-tdep.c, ns32k-pinsn.c, remote-adapt.c, xcoffread.c: + index -> strchr. + +Wed Sep 1 11:35:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c: Add comment explaining why dcache is disabled. + (remote_fetch_word, remote_store_word): Make static and #if 0. + They are not called from anywhere. + +Wed Sep 1 14:41:28 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * arm-tdep.c, convex-tdep.c, convex-xdep.c, dbxread.c, + h8300-tdep.c, h8500-tdep.c, i960-pinsn.c, i960-tdep.c, + infptrace.c, m88k-tdep.c, mips-tdep.c, regex.c, remote-vx.c, + rs6000-tdep.c, xcoffexec.c, xcoffread.c, z8k-tdep.c, + config/arm/tm-arm.h, config/convex/tm-convex.h, + config/gould/tm-np1.h, config/gould/tm-pn.h, + config/m68k/tm-isi.h, config/ns32k/tm-umax.h, + config/pa/tm-hppa.h, config/pyr/tm-pyr.h, + config/rs6000/tm-rs6000.h, config/tahoe/tm-tahoe.h, + config/vax/tm-vax.h: bzero -> memset. + + * regex.c: bcmp -> memcmp. + +Wed Sep 1 11:35:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (find_pc_line, find_line_common), + symtab.h (struct linetable), xcoffread.c (arrange_linetable): + Revise comments re linetable sorting. + * buildsym.c (compare_line_numbers): Sort by pc, not by line. + * coffread.c: Tell end_symtab to sort the line table. + + * coffread.c: Re-work a lot of the coff-specific stuff to use stuff + in buildsym.c. This includes coff_finish_block, coff_context_stack, + coff_local_symbols, coff_file_symbols, coff_global_symbols, + coff_end_symtab and coff_add_symbol_to_list. + (read_enum_type): Deal with it now that we have a "struct pending" + not a "struct coff_pending". + + * buildsym.c (end_symtab): Don't realloc subfile->linetable. + +Wed Sep 1 13:12:43 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * a68v-nat.c, altos-xdep.c, convex-tdep.c, convex-xdep.c, + findvar.c, hppab-nat.c, hppah-nat.c, i386mach-nat.c, + irix4-nat.c, m68k-tdep.c, m88k-tdep.c, mipsread.c, regex.c, + remote-bug.c, remote-hms.c, rs6000-nat.c, rs6000-tdep.c, + sparc-nat.c, stabsread.c, sun3-nat.c, sun386-nat.c, symfile.c, + umax-xdep.c, xcoffread.c, 29k-share/udi/udip2soc.c, + 29k-share/udi/udr.c, config/a29k/tm-a29k.h, config/arm/tm-arm.h, + config/convex/tm-convex.h, config/gould/tm-np1.h, + config/gould/tm-pn.h, config/h8300/tm-h8300.h, + config/h8500/tm-h8500.h, config/i386/tm-i386aix.h, + config/i386/tm-sun386.h, config/i386/tm-symmetry.h, + config/i960/tm-i960.h, config/m68k/tm-news.h, + config/m88k/tm-m88k.h, config/mips/tm-mips.h, + config/ns32k/tm-merlin.h, config/ns32k/tm-umax.h, + config/pa/tm-hppa.h, config/pyr/tm-pyr.h, + config/rs6000/tm-rs6000.h, config/sh/tm-sh.h, + config/tahoe/tm-tahoe.h, config/vax/tm-vax.h, + config/z8k/tm-z8k.h, nindy-share/nindy.c: bcopy -> memcpy. + +Wed Sep 1 05:05:53 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_partial_symbols): Use language from FDR if it + is unambigous. Patch from ptf@delcam.co.uk (Paul Flinders). + * mipsread.c (ecoff_symfile_info): New struct to hold the global + pending_list. + * mipsread.c (mipscoff_symfile_init, parse_partial_symbols): + Allocate the global pending list and link it to the objfile. + * mipsread.c (is_pending_symbol, add_pending): Use global pending + list from objfile. Allocate pending list entries from the + psymbol_obstack. + * mipsread.c (free_pending): Remove. The pending list is now + freed when the psymbol_obstack is freed. + * mipsread.c (psymtab_to_symtab1): Remove pending list allocation, + the global pending list is used now. + * mipsread.c (parse_partial_symbols): Skip only the first + file indirect entry when building the dependency list. + +Tue Aug 31 15:01:27 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + Break dcache code out of remote.c. + * dcache.h: white space changes only. + * dcache.c: add user settable variable to set whether data caching + is in use. + * remote.c: include dcache.h. removed data caching code which is + now in dcache.c. Compile in data caching again. (data caching + is currently off by default.) + (remote_read_bytes, remote_write_bytes): change second arg to + unsigned char. + (remote_dcache): new static variable. + * Makefile.in (REMOTE_O): add dcache.o. + * config/m88k/m88k.mt (TDEPFILES): removed dcache.o. + + Break dcache code out of remote-nindy.c. + * remote-nindy.c: removed dcache code. Changed callers to use new + conventions. include dcache.h. + (nindy_dcache): new static variable. + * config/i960/nindy960.mt (TDEPFILES): added dcache.o. + + Break dcache code out of remote-bug.c into dcache.[hc]. + * Makefile.in (dcache_h): new macro. + (HFILES): added $(dcache_h). + (ALLDEPFILES): added dcache.c. + (dcache.o): new rule. + (remote-bug.o): now depends on $(dcache_h). + * remote-bug.c: include dcache.h. remove externs for insque and + remque, add extern for bcopy. Prototype bug_close, + bug_clear_breakpoints, bug_write_cr. dcache code moved to + dcache.[hc]. Changed dcache calling convention to include an + initial DCACHE argument. + (bug_dcache): new static variable. + (bug_read_inferior_memory): change second arg to + unsigned char. + * dcache.[ch]: new files. + * config/m88k/m88k.mt (TDEPFILES): add dcache.o. + +Tue Aug 31 10:33:13 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-typeprint.c (c_print_type_base): Treat show = 0 just like + show < 0. The only case where we had been distinguishing is that + show = 0 used to print "struct " or "enum " instead of + "struct {...}" or "enum {...}" which seems clearly wrong. + +Mon Aug 30 17:51:32 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * configure.in: recognize m88110 as an m88k. + +Mon Aug 30 16:07:59 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (call_function_by_hand): If we discard cleanups, call + bpstat_clear (&inf_status.stop_bpstat). + +Mon Aug 30 12:47:46 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * stabsread.h, dbxread.c (end_psymtab): Return NULL if the psymtab + was empty and thrown away. + * mipsread.c (parse_partial_symbols): Do not add empty psymtabs to + dependency list, skip self dependencies. + * mipsread.c (parse_fdr): Removed, obsolete. + * mipsread.c (parse_lines): Check for cbLine being zero, not + cbLineOffset. + * mipsread.c (struct symloc): Add pst_language. + * mipsread.c (parse_partial_symbols): Set up proper language for + header files, save it in pst_language for psymtab_to_symtab_1. + * mipsread.c (psymtab_to_symtab_1): Use pst_language. + +Mon Aug 30 10:48:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * configure.in: Fix typo m88*-motorola-svr4* -> sysv4*. + +Fri Aug 27 17:09:19 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * paread.c: Include som.h instead of libhppa.h. (From Utah.) + +Fri Aug 27 09:30:40 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * symmisc.c (dump_symtab): Use catch_errors around print_symbol. + Change calling sequence of print_symbol to fit catch_errors. + + * mips-tdep.c: Call reinit_frame_cache every time the user does + "set heuristic-fence-post". + + * gdbserver/low-sun3.c: New file. + * gdbserver/Makefile.in, config/m68k/sun3.mh: Change accordingly. + + * Rename files for 14-character limits: + gdbserver/remote-gutils.c -> gdbserver/utils.c + gdbserver/remote-inflow.c -> gdbserver/low-lynx.c + gdbserver/remote-inflow-sparc.c -> gdbserver/low-sparc.c + gdbserver/remote-server.c -> gdbserver/server.c + remote-monitor.c -> remote-mon.c + * Makefile.in, gdbserver/Makefile.in, gdbserver/configure.in, + config/m68k/monitor.mt, config/i386/i386lynx.mh, + config/sparc/sun4os4.mh: Change accordingly. + * gdbserver/Makefile.in: Remove more junk inherited from gdb Makefile. + +Thu Aug 26 14:32:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infcmd.c, inferior.h (run_stack_dummy): If we stop somewhere + besides the dummy, return 1 rather than calling error(). + Let caller print the error message. Remove name argument. + * valops.c (call_function_by_hand): Deal with changes to calling + sequence of run_stack_dummy. Discard restore_inferior_status cleanup + if run_stack_dummy returns 1. + + * Version 4.10.2. + + * config/mips/tm-mips.h (EXTRACT_STRUCT_VALUE_ADDRESS): + Get struct return address from v0, not a0. + + * infrun.c (restore_inferior_status): Use catch_errors when + restoring selected frame. + +Wed Aug 25 21:52:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (save_inferior_status, restore_inferior_status): + Save and restore the registers too. + * inferior.h (struct inferior_status): Add "registers". + +Tue Aug 24 00:36:17 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c (end_psymtab): Clean up comment. + + * frame.h, symtab.h, findvar.c (read_var_value): Change basereg + support to use LOC_BASEREG rather than SYMBOL_BASEREG_VALID. + * dwarfread.c: Use LOC_BASEREG where appropriate. + * Various: Support LOC_BASEREG and LOC_BASEREG_ARG. + + * coffread.c (init_lineno, init_stringtab): Don't check whether + xmalloc returned NULL. + + * config/vax/xm-vaxult.h: Define NO_PTRACE_H. + + * target.c, target.h: Add "set remotedebug" command. + * remote-bug.c, remote.c, remote-mips.c: Remove "set remotedebug" and + "set m88ksnoop" options and use generic "set remotedebug" instead. + * NEWS: Describe this change. + +Mon Aug 23 20:26:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * buildsym.h: Remove declaration of dbxread.c functions. + * stabsread.h: Group together dbxread.c functions. + Move elfstab_build_psymtabs here from symfile.h. + Declare pastab_build_psymtabs. + * elfread.c, paread.c: Include stabsread.h (for stabsread_new_init + declaration, etc). + +Mon Aug 23 17:16:23 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * remote-bug.c: rename quiet to bug88k_snoop. + (double_scan, multi_scan): generalize double_scan into a scan + for multiple patterns. Rename to multi_scan. + (bug_wait, bug_write_inferior_memory): adapt to use the new + multi_scan in order to catch and represent target bus errors. + (bug_scan): currently unused, so comment out. + (bug_quiet): removed. Replaced with a standard user settable boolean. + + * m88k-tdep.c: remove include of sys/dir.h. Appears unnecessary + and isn't available on solaris. + +Mon Aug 23 14:56:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m88k/{delta88v4.mt,delta88v4.mh}: New files + * config/m88k/delta88.mh: Fix comment. + * config/m88k/tm-delta88.h: Remove unused BCS define. + * config/m88k/{tm-delta88v4.h,xm-delta88v4.h,nm-delta88v4.h}: + New files. + * configure.in: Recognize m88*-motorola-sysv4*. + * m88k-nat.c: Always include sys/types.h; don't depend on USG. + +Mon Aug 23 12:57:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_symbol, parse_type, cross_ref): Pass name of + symbol as an argument and use it in complaints. + * symmisc.c (dump_psymtab): Dump filenames of dependencies. + +Mon Aug 23 1993 Sean Fagan (sef@cygnus.com) + and Jim Kingdon (kingdon@cygnus.com) + + Add NetBSD support: + * configure.in: Recognize netbsd. + +Sun Aug 22 22:50:32 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (get_textlow): Don't go past a K_END when looking for a + K_FUNCTION. Avoids losing on source files with no functions. + +Fri Aug 20 14:01:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-nindy.c: Remove unused include of sys/ioctl.h. + + * frame.h, symtab.h: Revise comments regarding baseregs. + +Fri Aug 20 15:07:05 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_partial_symbols, psymtab_to_symtab_1): + Set language for psymtab and symtab. + * mipsread.c (new_symbol): Set language and initialize demangled + name for symbol. + * symmisc.c (print_symbol): Use SYMBOL_SOURCE_NAME when printing + the symbol type. + * symtab.c (decode_line_1): Inhibit coredumps with cfront executables. + +Fri Aug 20 14:01:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Move KERNEL_U_ADDR from xm-hp300bsd.h to nm-hp300bsd.h and make + it conditionalized on 4.3 vs. 4.4. + * config/m68k/nm-hp300bsd.h: Move REGISTER_U_ADDR out of 4.3 and + 4.4 sections; it was identical and now works for 4.4. + + * mips-tdep.c (is_delayed): Use INSN*BRANCH* not ANY_DELAY. + + * printcmd.c (MAKEVA_END): Update this version to use "aligner". + +Thu Aug 19 22:08:09 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/vax/tm-vax.h (BELIEVE_PCC_PROMOTION): Define. + * mipsread.c (parse_symbol, parse_type, cross_ref): Handle corrupt + file indirect entries with complaints instead of core dumps. Remove + complaint for stTypedef within aggregates. + +Thu Aug 19 17:58:39 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * coffread.c (process_coff_symbol): Ignore tagnames like .0fake. + + * coffread.c (coff_read_enum_type): #if 0 out code which changes + enum {FALSE, TRUE} into boolean. + + * config/m68k/delta68.m{t,h}: Use nm-delta68.h, etc. not + non-existent files nm-delta.h, etc. + * config/m68k/tm-delta68.h: Define CANNOT_STORE_REGISTER. + * delta68-nat.c: Add "[0]" in offsetof argument. + * delta68-nat.c (_initialize_kernel_u_addr): Don't try to set up + nl with initializer, just assign to it. Check n_scnum field on + return. + +Wed Aug 18 21:42:52 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hpux_symtab): Call SET_NAMESTRING for K_MODULE + debug symbols. + +Wed Aug 18 12:03:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_address), values.c (value_as_pointer): Don't + use ADDR_BITS_REMOVE. + * defs.h: Try to clarify comment about ADDR_BITS_REMOVE. + + * blockframe.c (block_innermost_frame): Uncomment. + Return NULL if passed NULL. + * frame.h: Declare it. + * expression.h (union exp_element): Add field block. + * parse.c (write_exp_elt_block): New function. + * expression.h (OP_VAR_VALUE): Now takes additional struct block *. + * *-exp.y: Write block for OP_VAR_VALUE. + * eval.c, expprint.c, parse.c: Deal with block for OP_VAR_VALUE. + * valops.c, value.h (value_of_variable), callers: + Add second argument, for block. + + * main.c (gdb_readline): If we read some characters followed by EOF, + return them rather than returning NULL. + +Tue Aug 17 11:14:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mips-tdep.c: Remove unused #ifndef NUMERIC_REG_NAMES and add comment. + +Tue Aug 17 15:10:04 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * config/m88k/tm-m88k.h: Fix typo in comment. + (FP_REGNUM): define in terms of SP_REGNUM + rather than by absolute number. Also clearly comment that this + is a convenient lie in order to decrease future confusion. + (ACTUAL_FP_REGNUM): new macro for FP. + (FRAME_CHAIN_VALID): removed. Standard default works fine. + * m88k-tdep.c (frame_chain_valid): redundant, so removed. + (NEXT_PROLOGUE_INSN): removed unused fourth arg, fixed all + callers. + (read_next_frame_reg): declare static. + (examine_prologue): removed unused variabel insn2, rename insn1 + to insn, rewrote comment about finding fp, sp, etc. set frame_fp + based on ACTUAL_FP_REGNUM rather than FP_REGNUM which is + actually a scammed alias for SP_REGNUM on m88k. + + * frame.h: fixed typo in comment. + +Tue Aug 17 11:14:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * 29k-share/udi/udiphcfg.h: Always include udiphunix.h not udiphdos.h. + + * complaints.c (complain): fflush (stdout) after output. + +Tue Aug 17 01:43:55 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * blockframe.c, frame.h (sigtramp_saved_pc): New routine to fetch + the saved pc from sigcontext on the stack for BSD signal handling. + * config/i386/tm-i386bsd.h (SIGTRAMP_START, SIGTRAMP_END, FRAME_CHAIN, + FRAMELESS_FUNCTION_INVOCATION, FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): + Define to make backtracing through sigtramp work. + * config/vax/tm-vax.h (SIGTRAMP_START, SIGTRAMP_END, TARGET_UPAGES, + FRAME_SAVED_PC, SIGCONTEXT_PC_OFFSET): Ditto. + +Mon Aug 16 13:52:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (cd_command): If current_directory on entry is "/", then + don't append an extra slash. + Don't assume that /../.. means /. + + * target.c (target_xfer_memory): Clear errno before calling + to_xfer_memory. + + * stack.c (frame_info, print_frame_info): Add comment about using + the starting source line number on a line boundary if backtracing + through sigtramp. + +Mon Aug 16 09:52:33 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Add U Utah contribution notice. Add TODO list. + (hp_type_lookup): Use TYPE_NAME and TYPE_TAG_NAME. + (process_one_debug_symbol): Likewise. + +Mon Aug 16 02:56:01 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * blockframe.c (create_new_frame, get_prev_frame_info): + Use the function name when calling IN_SIGTRAMP. + * config/m68k/tm-m68k.h (SIG_PC_FP_OFFSET, SIG_SP_FP_OFFSET): + Define for correct handling of bachtraces through _sigtramp. + * m68k-tdep.c (m68k_find_saved_regs): Adjust saved sp for fake + sigtramp frames. + * mipsread.c (parse_type): Handle corrupt TIR info with complaint + instead of core dump. + * mipsread.c (parse_partial_symbols): Put static symbols into the + mimimal symbol table, use proper mst_types for all minimal symbols. + * stack.c (frame_info, print_frame_info): Use the starting source + line number on a line boundary if backtracing through sigtramp. + +Fri Aug 13 14:37:05 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * remote-bug.c: include gdbcmd.h. + (sleep, remque, insque): forward decls added. + (bug_fetch_registers, bug_store_registers): forward decls + removed. + (bug_read_inferior_memory, bug_write_inferior_memory): forward + decls added. + (srec_frame, srec_max_retries, srec_bytes, srec_echo_pace, + srec_sleep, srec_noise): new static variables for user settable + options. Mostly these are for debugging and tuning. I don't + expect them to stay user settable options for long. + (timeout): change default to 4 seconds. + (check_open): declare funtion static, force return value. + (readchar_nofail): if timeout, then say so if not being quiet. + (pollchar, double_scan, bug_scan, bug_srec_write_cr, + start_load): new functions. + (bug_wait): rewritten to use double scan. + (expect): while (1) -> for (;;) + (get_hex_digit): rewrite if condition to avoid gcc complaints. + (bug_load, bug_create_inferior, bug_open, bug_store_register): + removed unused variables. + (bug_load): replaced DELTA macro with user settable srec_frame + variable. Other minor lint. + (find_end_of_word, is_baudrate_right, set_rate, not_bug_wait, + gethex, timed_read, translate_addr, bug_before_main_loop): + unsused and removed. + (bug_resume): add missing first arg, pid. + (get_reg_name): use ip rather than cr04. + (bug_write, bug_write_cr, but_clear_breakpoints, bug_quiet): + declare type, args, and explicitly return. + (bug_store_register): straighten out the ip vs cr04 confusion. + (bug_write_inferior_memory): rewrite to cope with errors while + downloading s-records. + (bug_read_inferior_memory): declare static. + (bug_clear_breakpoints): expect nobr before prompt. + (_initialize_remote_bug): add initializations for srec-bytes, + srec-max-retries, srec-frame, srec-noise, srec-sleep, + srec-echo-pace. + + * Makefile.in (remote-bug.o): new rule. + (ALLDEPFILES): added remote-bug.c + + * remote-hms.c (hms_wait): use -1 for timeout's which means block + forever rather than 99999. + + * ser-unix.c (get_tty_state): if a descriptor is not a tty, then + simply save encode this fact as the process group and return + success rather than an error. + (set_tty_state): if process group is -1, do not reset the + process group. + (hardwire_reachar): comment change. + + * serial.h: comment change. + + * config/m88k/tm-m88k.h: comment change to remove embedded + comment. + (SKIP_PROLOGUE): skip_prologue returns a value which is expected + to reset the pc argument. So reset it. + +Fri Aug 13 10:15:24 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (VERSION): Bump to 4.10.1 after release and cvs + tagging. + +Thu Aug 12 20:40:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/Makefile.in: Use GDBSERVER_LIBS and + GDBSERVER_DEPFILES. Also remove much (but not all that could be + removed) crud inherited from gdb Makefile.in. + * config/i386/i386lynx.mh, config/sparc/sun4os4.mh: Define GDBSERVER_*. + * gdbserver/README: Say it works on Sun and change configuration + instructions slightly. + +Wed Aug 11 18:56:59 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * config/i386/i386v4.mh: use -lsocket and -lnsl, for remote + targets that use BSD style network connections + +Wed Aug 11 17:54:24 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-{monitor,bug}.c: Make bug_ops not static (forward declaration + of statics doesn't work with SunOS4 /bin/cc). + Rename the occurrence in remote-monitor.c to monitor_bug_ops. + +Tue Aug 10 13:07:14 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * blockframe.c (find_pc_partial_function), + mips-tdep.c (find_proc_desc): Deal with "pathological" case. + +Tue Aug 10 14:50:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (wrap_here): Allow indent to be NULL. + (fputs_filtered): Don't check for null wrap_indent (wrap_here now + guarantees that it isn't, and anyway we were only checking one out + of the two places we dereferenced it). + + * objfiles.h (struct objfile): Clean up comments for + {obj,sym}_private to clarify what they are private to. + +Mon Aug 9 16:45:00 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * stabsread.c, buildsym.c (hashname): Moved function to + buildsym.c, as suggested in the sources. + +Mon Aug 9 09:53:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c: Make udi_ops extern rather than trying forward + declaration of a static variable. + + * hppab-nat.c: Define ptrace to call_ptrace and pass the 5th arg + there, rather than using an ANSI C specific macro. + + * 29k-share/udi/udr.c: Include fcntl.h not sys/fcntl.h. Also put + sys/types.h near the top (just on general principles). + + * environ.c (set_in_environ): Remove G960BASE and G960BIN; they are + no longer used. + + * gdbcore.h: New variable gnutarget. + * core.c: Add commands to set and show it. + * Callers to bfd_*open*: Pass gnutarget instead of NULL as target. + * environ.c (set_in_environ): For GNUTARGET, use set_gnutarget not + putenv. + + * symtab.c (decode_line_1): Give error on unmatched single quote. + +Sun Aug 8 13:59:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ser-unix.c (hardwire_send_break) [HAVE_SGTTY]: Use select not usleep. + + * remote.c: Add comments about 'd', 'r', and unrecognized requests. + + * inflow.c (terminal_init_inferior): Don't muck with tty state if + gdb_has_a_terminal() is false. + +Sun Aug 8 10:07:47 1993 Fred Fish (fnf@cygnus.com) + + * dwarfread.c (record_minimal_symbol): Remove prototype and + function. + * dwarfread.c (add_partial_symbol): Remove code to add minimal + symbols and remove comment about limitations. Experiments show + that now that gdb handles the ELF symtab better for creating + minimal symbols, that no additional information is added by + examining the DWARF information, and in fact, given the + limitations, the DWARF code was actually making things worse. + +Sat Aug 7 10:59:03 1993 Fred Fish (fnf@deneb.cygnus.com) + + * elfread.c (elf_symtab_read): Properly sort out the bss symbols + from the data symbols and give them the correct minimal_symbol_type. + Add file static symbols to the minimal symbol table, not just + global symbols. Add absolute symbols as well (like _edata, _end). + Redo stabs-in-elf special symbol handling now that file static + symbols are entered into the into the minimal symbol table. + * dwarfread.c (add_partial_symbol): Add comment about limitations + of DWARF symbols for distinquishing data from bss when adding + minimal symbols. Add file local symbols to minimal symbols. + +Thu Aug 5 08:58:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ser-go32.c: Define job_control variable. + +Thu Aug 5 15:56:13 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * configure.in: z8k-coff is the same as z8k-sim + +Thu Aug 5 08:58:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * 29k-share/udi/udip2soc.c: Include sys/types.h before sys/file.h. + + * config/i386/tm-i386bsd.h (NUM_REGS): There are only 10, not 11. + + * inflow.c: Put all uses of F_GETFL and F_SETFL in #ifdef F_GETFL. + + * 29k-share/udi/udip2soc.c: Include fcntl.h not sys/fcntl.h. + +Wed Aug 4 18:32:12 1993 Fred Fish (fnf@cygnus.com) + + * inflow.c (pass_signal): Signal handlers take one int arg; + supply an unused one to make it type compatible as an arg to + signal(). + +Tue Aug 3 18:34:14 1993 Ian Lance Taylor (ian@cygnus.com) + + * config/mips/tm-mips.h: Include bfd.h before coff/sym.h. + +Tue Aug 3 15:34:57 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (ALLCONFIG): Add config/i386/i386nw.mt, + config/m68k/delta68.mh, config/m68k/delta68.mt, + config/m68k/dpx2.mh, config/m68k/dpx2.mt, config/mips/riscos.mh, + config/mips/news-mips.mh. + * Makefile.in (ALLPARAM): Add config/i386/nm-symmetry.h, + config/i386/tm-i386nw.h, config/m68k/nm-delta68.h, + config/m68k/tm-delta68.h, config/m68k/xm-delta68.h, + config/m68k/nm-dpx2.h, config/m68k/tm-dpx2.h, + config/m68k/xm-dpx2.h, config/mips/xm-makeva.h. + * Makefile.in (ALLDEPFILES): Add dpx2-nat.c. + +Tue Aug 3 12:02:09 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c: Updated for BFD ECOFF changes. Now gets the + swapping routines and external structure sizes via the + ecoff_backend information. No longer includes coff/mips.h. + +Tue Aug 3 10:58:04 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (SFILES): Add thread.c + +Tue Aug 3 10:21:58 1993 Doug Evans (dje@canuck.cygnus.com) + + * remote-sp64sim.c (simif_create_inferior): Add FIXME regarding + sim_set_args return code. + +Mon Aug 2 16:35:31 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * Makefile.in (VERSION): bumped to 4.9.4. + + * remote-monitor.c: updated copyright. + (bug_ops, monitor_desc): now static. + (monitor_desc): in several places, check and/or set to NULL. + + * remote-hms.c (hms_files_info): Add the appropriate items where + missing in the printf call. + + * remote-bug.c: new file for m88k bug support. + + * config/m88k/m88k.mt (TDEPFILES): added remote-bug.o. + +Mon Aug 2 14:22:09 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * h8300-tdep.c: Use new variable h8300hmode. + +Mon Aug 2 12:06:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (typecmp): If we are passing a non-reference to a function + which takes a reference, pass the address. + (value_arg_coerce): Don't use COERCE_ENUM; we don't want to dereference + references here. + + * thread.c (thread_switch): Define as static. + (add_thread): Cast return value from xmalloc. + + * gdbtypes.c (fill_in_vptr_fieldno): Call check_stub_type. + * gdbtypes.{c,h}: Improve comments on vptr_fieldno. + +Mon Aug 2 11:58:52 1993 Fred Fish (fnf@deneb.cygnus.com) + + * README: Elaborate on gdb C++ support and cfront support. + +Mon Aug 2 11:30:57 1993 Stu Grossman (grossman at cygnus.com) + + * i386lynx-nat.c, thread.c, thread.h: Update copyrights. + +Mon Aug 2 12:06:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (ALLDEPFILES): Add i386lynx-nat.c. + +Mon Aug 2 08:42:50 1993 Stu Grossman (grossman at cygnus.com) + + * gdbserver/remote-inflow.c (create_inferior): Fix comments, and + error msg. Setup seperate process group for child. + * (write_inferior_memory): Sleep for 1 second and retry on ptrace + failure. + +Sun Aug 1 22:58:18 1993 Stu Grossman (grossman at cygnus.com) + + * config/i386/i386lynx.mh (NATDEPFILES): Drop coredep (for now). + * config/i386/nm-i386bsd.h: Protect from multiple inclusion. + * config/i386/nm-i386lynx.h: Lotsa new host porting stuff. + * config/i386/tm-i386lynx.h: Define SAVED_PC_AFTER_CALL and + target_pid_to_str. + + * Makefile.in (CLIBS): Reorder to make Lynx ld happy. + * (HFILES): New file thread.h. + * (OBS): New file thread.c. + * configure.in: Host config for Lynx/386. + * fork-child.c (fork_inferior): Call init_thread_list(). + * infrun.c (resume): Add pid to invocation of target_resume(). + * (wait_for_inferior): Pay attention to pid from target_wait(). + Multi-threading code now uses this to determine what to do. + * inftarg.c (child_wait): Conditionalize based on CHILD_WAIT macro. + Use target_pid_to_str() macro throughout when printing pid. + * inferior.h (child_resume): Add pid to prototype. + * hppab-nat.c hppah-nat.c infptrace.c (child_resume): Pass in pid as + argument, instead of using inferior_pid. + * procfs.c (procfs_resume): Pass in pid as argument. Ignored for + now. Use target_pid_to_str() macro throughout for printing process id. + * remote-adapt.c (adapt_resume): Pass in pid as argument. + * remote-eb.c (eb_resume): Pass in pid as argument. + * remote-es.c (es1800_resume): Pass in pid as argument. + * remote-hms.c (hms_resume): Pass in pid as argument. + * remote-mips.c (mips_resume): Pass in pid as argument. + * remote-mm.c (mm_resume): Pass in pid as argument. + * remote-monitor.c (monitor_resume): Pass in pid as argument. + * remote-nindy.c (nindy_resume): Pass in pid as argument. + * remote-sa.sparc.c (remote_resume): Pass in pid as argument. + * remote-sim.c (rem_resume): Pass in pid as argument. + * remote-sp64sim.c (simif_resume): Pass in pid as argument. + * remote-st.c (st2000_resume): Pass in pid as argument. + * remote-udi.c (udi_resume): Pass in pid as argument. + * remote-vx.c (vx_resume): Pass in pid as argument. + * remote-z8k.c (rem_resume): Pass in pid as argument. + * remote.c (remote_resume): Pass in pid as argument. + * solib.c (solid_create_inferior_hook): Pass inferior_pid to + target_resume(). + * target.c (normal_pid_to_str): New routine to print out process + ID normally. + * target.h (struct target_ops): Add pid to prototype at + to_resume(). (target_resume): Add pid argument. + * (target_pid_to_str): Default definition for normal type pids. + * thread.h, thread.c: New modules for multi thread/process control. + +Sun Aug 1 13:02:42 1993 John Gilmore (gnu@cygnus.com) + + * README: Say that bug-gdb is also the place to send requests + for help with GDB. + +Sun Aug 1 09:42:13 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (make-proto-gdb-1): Use -f opt on rm of Makefile. + * h8500-tdep.c: Add parens around a few macro args. + +Fri Jul 30 15:43:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Remove items about unix-to-unix/rapp debugging (now we + have gdbserver), moving xm files to subdirectory, ptype yylval, + and file-local symbols. + + * gdbtypes.h: Improve comments about C++ methods. + +Fri Jul 30 14:16:32 1993 Fred Fish (fnf@deneb.cygnus.com) + + * c-exp.y: Add missing 5th arg for one call to lookup_symbol, cast + NULL in all other calls to correct pointer types. + +Fri Jul 30 15:43:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + From Jeffrey Law: + * tm-hppa.h (TARGET_WRITE_PC): Define. + * hppa-tdep.c (hppa_fix_call_dummy): If in a syscall, + then return the address of the dummy itself rather than + the address of $$dyncall. + (target_write_pc): New function to store a new PC. + +Fri Jul 30 12:51:27 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + and Jim Kingdon (kingdon@cygnus.com) + + * breakpoint.c (breakpoint_re_set_one): Always reparse breakpoint + conditions, they might contain symbol table references. + +Fri Jul 30 12:51:27 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_symbol): Handle opaque struct definitions and + type naming for stTypedef symbols. + +Fri Jul 30 14:44:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-exp.y (yylex): Detect C++ nested types. + +Fri Jul 30 11:07:37 1993 Doug Evans (dje@canuck.cygnus.com) + + * sp64-tdep.c (sparc64_frame_chain, sparc64_frame_saved_pc): Deleted. + (dump_ccreg, sparc_print_register_hook): New fns. + * remote-sim.h: New file. + * remote-sp64sim.h (sim_*): External fns. (simif_*): Internal fns. + + * config/sparc/sp64.mt: New file. + * config/sparc/tm-sp64.h (FRAME_CHAIN, FRAME_SAVED_PC): Deleted. + (PRINT_REGISTER_HOOK): Call new fn sparc_print_register_hook. + +Fri Jul 30 10:15:01 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (ALLCONFIG): Add config/i386/ptx.mh + +Fri Jul 30 08:58:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + From J. Law: + * infcmd.c (read_pc): Remove PA specific code. + * tm-hppa.h (TARGET_READ_PC): Define. + * hppa-tdep.c (target_read_pc): New function. + + * symtab.c (gdb_mangle_name): Deal with it if type lacks a name. + +Fri Jul 30 07:36:53 1993 Fred Fish (fnf@deneb.cygnus.com) + + * NEWS: Add note that DEC alpha support is host only, not native. + * README: Emphasize that C++ support works best with GNU C++ and + stabs debugging format. + * delta68-nat.c: Add missing FSF copyright. + +Fri Jul 30 08:58:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * paread.c (pa_symtab_read): Put file-local symbols in minimal symbols. + * hppa-tdep.c (frame_chain_valid): Check that our function has the + same address as _start, not that it must be the same symbol. + +Fri Jul 30 00:18:40 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (ALLDEPFILES): Add delta68-nat.c + * Makefile.in (delta68-nat.o): Add dependency. + +Thu Jul 29 12:09:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * value.h (COERCE_ENUM): Use COERCE_REF to coerce refs; value_ind + was adequate in gdb 3.5 but not now. + + * valops.c (typecmp): An array in t2 matches a pointer in t1. + + * valops.c (typecmp): When comparing type1& to type2, compare + type1 and type2 as leniently as if we were comparing type1 to + type2. + + * cp-valprint.c (cplus_print_value): Don't dump core if the + baseclass doesn't have a name. + * values.c (vb_match): New function, which finds the virtual + base class pointer even if the types are nameless. + (baseclass_{addr,offset}): Use it. + + * hppa-tdep.c: Make "maintenance print unwind" command from old + "unwind" command. + + * remote-udi.c: Remove udi_timer, call to siginterrupt, and associated + obsolete junk which apparently had been copied from the + pre-serial.h remote.c, but which is no longer used. + +Thu Jul 29 12:36:20 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (NONSRC): Need 29k-share/README, not + 29k-share/udi/README. + +Thu Jul 29 12:09:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * paread.c (pa_symfile_init): If error reading string table, don't + use errno in cases where it hasn't been set. + + * ser-unix.c (gdb_setpgid): Pass our pid, not 0, to setpgid. + + * remote-monitor.c (_initialize_monitor): Comment out use of + connect_command, since connect_command itself is commented out. + + * remote-monitor.c (generic_open): Parse arguments the same way + as remote.c. + + * hppa-tdep.c (pc_in_linker_stub): Fix unclosed comments. + +Wed Jul 28 13:19:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/xm-mips.h: Define HAVE_TERMIOS. + + * dbxread.c (record_minimal_symbol): Don't put gcc_compiled or + __gnu_compiled* symbols into the minimal symbols. + +Wed Jul 28 08:26:58 1993 Ian Lance Taylor (ian@cygnus.com) + + * remote-mips.c (_initialize_remote_mips): Added "timeout" and + "retransmit-timeout" variables to set mips_receive_wait and + mips_retransmit_wait, respectively. + +Wed Jul 28 03:58:58 1993 (pes@regent.e-technik.tu-muenchen.de) + + * symmisc.c (dump_msymbols): Handle new mst_file_* types. + +Tue Jul 27 12:07:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c: Remove old comment about download not implemented. + + * serial.h, ser-{unix,go32,tcp}.c: Add flush_input and send_break. + * nindy-share/*, remote-nindy.c: Extensive hacking to make it + conform to GDB conventions like using memcpy not bcopy, serial.h, + etc. This is to make it host on Solaris, AIX, etc. + * Makefile.in: Reflect removed nindy-share files. + * config/i960/nindy960.mt (TDEPFILES): Remove ttybreak.o. + + * stack.c (print_frame_info): Revise comment about `pathological' + case (there was a wrong FIXME about text labels; also asm() can + trigger this as well as versions of ar which truncate .o names). + + * buildsym.c (start_subfile): If a .c file includes a .C file, set + the language of both of them to C++. + + * config/sparc/xm-sun4os4.h: Define MEM_FNS_DECLARED and include + . + Include rather than declaring malloc functions ourself. + + * ser-unix.c (set_tty_state): Don't ignore errors setting process + group. + * inflow.c (terminal_inferior): If attach_flag set, ignore errors + from set_tty_state. + + * fork-child.c (fork_inferior): Only quote exec file if needed. + + * mipsread.c (parse_symbol): Remove 21 Jul 93 change with + stTypedef inside an stBlock. + +Tue Jul 27 12:36:49 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * breakpoint.c (breakpoint_1): Walk the breakpoint chain to decide if + we have breakpoints or watchpoints as we might have to ignore internal + breakpoints. + + Fix gdb core dumps after `file newfile' commands. + * symtab.h, symfile.c (clear_symtab_users): New routine which + unconditionally clears symtab users. clear_symtab_users_once + commented out as it was a noop anyway. + * objfiles.c (free_objfile): Don't call clear_symtab_users_once. + * objfiles.c (free_all_objfiles), symfile.c (new_symfile_objfile), + xcoffexec.c (exec_close): Call clear_symtab_users if necessary. + * symfile.c (syms_from_objfile): Install cleanups for errors during + symbol reading. + * coffread.c, dbxread.c, mipsread.c, xcoffread.c (*_symfile_read): + Lint cleanup code, call do_cleanups explicitly. + * symfile.c (symbol_file_add): Call new_symfile_objfile and + reinit_frame_cache _after_ the new symbols are read in. + +Tue Jul 27 01:57:01 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_type): Do not set tag name for compiler + generated fake tag names. + +Mon Jul 26 17:31:49 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * config/m88k/m88k.mt (TDEPFILES): add exec.o. + +Mon Jul 26 13:17:36 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * hppa-tdep.c: Remove all uses of use_unwind and `set use_unwind' + command. Now we use unwind info by default if we can find it. + + * config/sparc: Move VARIABLES_INSIDE_BLOCK and SUN_FIXED_LBRAC_BUG + to tm-sparc.h so they are shared between Solaris and SunOS4. + * dbxread.c (process_one_symbol): Deal with SunOS4 acc N_STSYM and + N_GSYM functions. + + * config/pa/tm-hppa.h (REGISTER_NAMES): Use "fr" rather than "fp" + for floating point registers. + + * mipsread.c (parse_symbol): Put stStaticProc symbols in minimal + symbols as mst_file_text. + + * hppa-tdep.c (pc_in_linker_stub): Return 0 if can't read memory. + + * stabsread.c (rs6000_builtin_type): Make logical types be + TYPE_CODE_BOOL. + +Sun Jul 25 23:41:48 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.{c,h} (struct breakpoint): Replace symtab field with + source_file field. + +Fri Jul 23 09:57:25 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote.c: Don't error() on errors xferring memory. + * target.h: Clean up comments about *xfer_memory. + + * exec.c, corelow.c (target_ops struct): Don't allow + {insert,remove}_breakpoints to be defaulted to + memory_{insert_remove}_breakpoint. + + * demangle.c: Make it so `help set dem' tells you how to get the + list of demangling styles. + +Thu Jul 22 15:41:09 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * Makefile.in: Use REMOTE_O macro not remote.o. + * config/i960/{nindy960,vxworks960}: Don't use remote.o. + +Thu Jul 22 12:43:25 1993 Ian Lance Taylor (ian@cygnus.com) + + * coredep.c: If NEED_SYS_CORE_H defined, include + (can't include it in nm-*.h file because it causes conflicts with + a.out symbol definitions). + * hp300ux-nat.c (fetch_core_registers): Commented out; obsolete. + * config/m68k/hp300hpux.mh (NATDEPFILES): Added coredep.o and + corelow.o. + * config/m68k/nm-hp300hpux.h (NEED_SYS_CORE_H): Defined. + (REGISTER_U_ADDR): Defined. + * config/m68k/xm-hp300hpux.h (HAVE_TERMIOS): Define instead of + HAVE_TERMIO. + * config/pa/xm-hppah.h: Likewise. + +Wed Jul 21 11:37:30 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * mipsread.c (parse_symbol): when stTypedef and friends occur within + an stBlock, skip over the fields of the inner one. + + * mips-tdep.c (init_extra_frame_info): If in lenient prologue, call + heuristic_proc_desc rather than just assuming registers not saved. + + * Makefile.in (regex.o): Add dependency. + + * hppa{b,h}-nat.c: Warning, not error, if can't access registers. + + * config/pa/hppa{b,h}.h: Define ATTACH_DETACH. + +Wed Jul 21 03:07:30 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/xm-makeva.h: New file implements va_list alignment + restrictions for mips hosts. + * config/mips/{xm-irix3.h, xm-mips.h, xm-news-mips.h, xm-riscos.h}: + Use it. + +Wed Jul 21 00:11:05 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-tdep.c (init_extra_frame_info): Do not check for + mips_in_lenient_prologue if it is a dummy frame. + * mipsread.c (fixup_sigtramp): Initialize pdr.adr, it is used by + mips_in_lenient_prologue. + +Tue Jul 20 14:14:59 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hp_array_type): Handle "char foo[]". + +Tue Jul 20 12:53:47 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * mips-tdep.c (heuristic_proc_start): First time we print the + warning, elaborate. + (_initialize_mips_tdep): Improve docstring for `set heur'. + + * config/rs6000/tm-rs6000.h: Remove call to insert_step_breakpoint. + + * symtab.c (find_line_symtab): New function, to deal with multiple + symtabs with the same name. + (find_line_pc{,_range}): Use it. + (find_pc_symtab): Add comment about overlapping symtabs. + +Mon Jul 19 21:29:14 1993 Fred Fish (fnf@deneb.cygnus.com) + + * Makefile.in (SFILES): Add nlmread.c. + * Makefile.in (OBS): Add nlmread.o. + * Makefile.in (nlmread.o): Add new target. + * configure.in (i[34]86-*-netware): New configuration. + * nlmread.c, config/i386/{i386nw.mt, tm-i386nw.h}: New files + for NLM/NetWare support. + +Mon Jul 19 11:48:57 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * symtab.h (enum minimal_symbol_type): Add mst_file_*. + * partial-stab.h [DBXREAD_ONLY]: Record statics in miminal symbols. + * dbxread.c (record_minimal_symbol): Deal with statics. + * minsyms.c (lookup_minimal_symbol): Prefer externals to statics. + + * config/i386/xm-i386sco.h: Define HAVE_TERMIOS. + + * printcmd.c, config/pa/xm-pa.h, config/alpha/xm-alpha.h: Make it so + arg_bytes field of makeva_list is always aligned. + * config/pa/xm-pa.h: Make arglist_address a char *. + + * ser-unix.c: Don't try to use job control with termio. + +Sun Jul 18 23:11:28 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + and Jim Kingdon (kingdon@cygnus.com) + + Make breakpoint_re_set_one work with overloaded member functions, + `b 123' and `b foo' if foo is a static function. + * symtab.c (decode_line_1, decode_line_2): New argument `canonical' + to return canonical line specs if requested by the caller. + * breakpoint.c, source.c, symtab.c, symtab.h: Change prototypes and + callers accordingly. + * symtab.c (build_canonical_line_spec): New helper function which + constructs the canonical line spec. + * breakpoint.c (break_command_1): Use canonical line spec instead + of command string as addr_string if necessary. + * source.c (line_info): Fix storage leak. + +Sun Jul 18 15:22:45 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * infptrace.c: Split out define of PT_KILL; Sequent defines PT_KILL + but not the others. + * symm-tdep.c: Remove exec_file_command. + [_SEQUENT_] (ptx_coff_regno_to_gdb, register_addr): New functions. + A few miscellaneous cleanups. + * symm-nat.c: Renamed from symm-xdep.c. + * All symmetry dependent files: Many changes. + + * mips-tdep.c (mips_skip_prologue): New argument lenient. + Use read_memory_nobpt. + (is_delayed, mips_in_lenient_prologue): New functions. + (init_extra_frame_info): If in the prologue, don't use saved registers. + * config/mips/tm-mips.h: Declare mips_skip_prologue. + + * partial-stab.h (N_SO): Add the text offset to valu before, not after, + passing it to END_PSYMTAB. + +Fri Jul 16 18:48:52 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * symtab.c (find_pc_symtab): Call warning, not printf directly. + + * solib.c (solib_add): Use x{re,m}alloc, not {re,m}alloc. + +Fri Jul 16 09:56:42 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c: No longer need to undefine ZMAGIC. + +Thu Jul 15 18:03:37 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m88k-pinsn.c: Moved code into opcodes/m88k-dis.c. + (print_insn): Now just calls print_insn_m88k. + +Thu Jul 15 14:54:05 1993 Doug Evans (dje@canuck.cygnus.com) + + * h8300-tdep.c (examine_prologue): Make prototype match definition. + +Thu Jul 15 08:34:49 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * NEWS: Mention that remote.c now has a `load' operation. + + * hppa-tdep.c (pc_in_linker_stub): New function. + (find_proc_framesize): Return 0 for linker stubs. + (rp_saved): Tell the caller where rp is saved. + (frame_chain_valid): Return 1 for linker stubs. + (frame_saved_pc): Use return value from rp_saved. + + * stack.c (print_frame_info): When checking PC_IN_CALL_DUMMY, + pass the sp relative to the frame in question, not the sp in the + innermost frame. + +Wed Jul 14 17:37:03 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mipsread.c (parse_procedure): Take as argument the symtab to look + the name up in. Look it up with mylookup_symbol, not lookup_symbol. + (psymtab_to_symtab_1): For stabs, pass the symtab to parse_procedure. + + * mipsread.c (mylookup_symbol): Use strcmp, not STREQ, as we have + already checked the first characters. + + Changes from Jeffrey Law: + * printcmd.c (makeva_list): Use MAKEVA_EXTRA_INFO to define + machine dependent fields in the makeva_list structure. + (makeva_size): Allocate extra space to handle gaps made by + alignment restrictions. + * config/pa/xm-pa.h (MAKEVA_EXTRA_INFO): Define. + (MAKEVA_START): Initialize arglist_address field. + (MAKEVA_ARG): Always store arguments on natural alignment + boundaries. Set arglist_address to the address right after + the args. + (MAKEVA_END): Simply return the value stored in arglist_address. + +Wed Jul 14 13:51:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ch-valprint.c (chill_val_print, case TYPE_CODE_STRING): Print + address, not addr. + + * hppah-nat.c (store_inferior_registers): Don't print i in cases + where we aren't using it. + + * a29k-tdep.c (get_saved_register): Fix typo. + +Wed Jul 14 09:45:52 1993 Doug Evans (dje@canuck.cygnus.com) + + * configure.in: Recognize h8300h (variant of h8300). + +Wed Jul 14 09:45:52 1993 Doug Evans (dje@canuck.cygnus.com) + + * configure.in: Recognize sparc64-*-*. + +Tue Jul 13 14:03:48 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (define_symbol): Make the caddr_t hack apply to `function + returning foo' as well as `pointer to foo'. + + * remote.c [REMOTE_BREAKPOINT]: Use for breakpoint insn if defined. + * config/m68k/tm-m68k.h: Define it. + * mem-break.c, breakpoint.c: Improve comments. + +Tue Jul 13 13:35:31 1993 Frederic Pierresteguy (F.Pierresteguy@frcl.bull.fr) + + * config/m68k/tm-dpx2.h: Replace "tm-68k.h" with "m68k/tm-m68k.h". + * config/m68k/xm-dpx2.h: Define HAVE_TERMIOS not HAVE_TERMIO. + +Tue Jul 13 11:50:38 1993 Doug Evans (dje@canuck.cygnus.com) + + * gdbcore.h (read_memory_integer, read_memory_unsigned_integer): + Make prototype match definition. + +Tue Jul 13 11:15:15 1993 Fred Fish (fnf@cygnus.com) + + * elfread.c: Remove notice about file still being under + construction. + * Makefile.in (ultra3-xdep.o, umax-xdep.o): Add missing ')'. + +Mon Jul 12 17:46:35 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * a29k-tdep.c (read_register_stack): Make val static. + +Mon Jul 12 14:10:48 1993 Doug Evans (dje@canuck.cygnus.com) + + * config/h8300/tm-h8300.h (REGISTER_CONVERTIBLE): Change value to 0. + (REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW): Move def'n to + usual spot. + +Mon Jul 12 11:29:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-valprint.c (c_val_print): Fix thinko with unspecified length + arrays. + + * hppa-tdep.c (find_proc_framesize): If there is a frame pointer, + use it. + +Sun Jul 11 19:35:05 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (decode_line_1): Use end of block to figure out whether + val.end is in the same function, not minimal symbols. + + * source.c (line_info): Add a few more wrap_here's. + + * i386-tdep.c (i386_follow_jump): Do byteswapping where needed and + don't make assumptions about sizes of host data types. + + * blockframe.c, symtab.h (find_pc_partial_function): New arg endaddr. + * infrun.c, breakpoint.c, printcmd.c: Change callers. + * printcmd.c (containing_function_bounds): Remove. + * printcmd.c (disassemble_command): Use find_pc_partial_function, + not containing_function_bounds. + * infcmd.c (step_1): Use find_pc_partial_function rather than + trying to roll our own. Move check for a pc between SIGTRAMP_START and + SIGTRAMP_END in find_pc_partial_function, not step_1. + + * sparc-tdep.c (sparc_frame_chain, frame_saved_pc): + Keep unswapped value in array of char, not REGISTER_TYPE. + Use REGISTER_RAW_SIZE not sizeof (REGISTER_TYPE). + (sparc_extract_struct_value_address): Use TARGET_PTR_BIT not + sizeof (CORE_ADDR). + +Thu Jul 1 15:50:05 1993 Frederic Pierresteguy (F.Pierresteguy@frcl.bull.fr) + + * configure.in (m68*-bull-sysv*): added support for Bull dpx2. + * config/m68k/{t,x,n}m-dpx2.h, dpx2-nat.c: New files. + * config/m68k/dpx2.m{h,t}: New files. + +Thu Jul 1 15:46:10 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Run through gnu-indent. + +Sun Jul 11 12:32:08 1993 Doug Evans (dje@canuck.cygnus.com) + + * config/sparc/tm-sparc.h (PRINT_REGISTER_HOOK): Fix typo, add + more parens around macro arg. + +Sat Jul 10 09:54:17 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c: Remove step_resume_{duplicate,shadow}. Replace + step_resume_break_address with step_resume_breakpoint (now local + to wait_for_inferior). + ({insert,remove}_step_breakpoint): Remove. + (wait_for_inferior): Set step resume break with + set_momentary_breakpoint. Test hitting it with bpstat_stop_status + and bpstat_what (stop_step_resume_break removed). + * breakpoint.{h,c}, infrun.c: Return value from bpstat_what now struct + which includes previous return value as main_action, and a step_resume + bit. + * breakpoint.c (delete_breakpoint): If breakpoint was inserted, and + there is another breakpoint there, insert it. + * infrun.c (wait_for_inferior): Rearrange the spaghetti a bit. Use + a few more gotos. + Various: Clean up and add comments. + + * infrun.c [TDESC]: Remove remaining tdesc code (see ChangeLog + for Wed Nov 13 16:45:13 1991). + +Fri Jul 9 12:36:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * values.c, value.h (modify_field), callers: Make fieldval a LONGEST. + + * h8300-tdep.c (NEXT_PROLOGUE_INSN): Make pword1 an INSN_WORD * + not short *. + + * findvar.c, defs.h + ({extract,store}_{signed_integer,unsigned_integer,address}): + New routines to replace SWAP_TARGET_AND_HOST. + All over: All uses of SWAP_TARGET_AND_HOST on integers replaced. + + * config/sparc/tm-sparc.h: Add comment suggesting that removing + ins and locals from the registers array might clean things up. + + * utils.c: Clean up comments about wrap buffer and wrap_here. + * printcmd.c (printf_command): Call wrap_here before vprintf. + + * mipsread.c (cross_ref): Set the name to unknown for "struct *" case. + Patch from ptf@delcam.co.uk (Paul Flinders). + + * a29k-tdep.c, findvar.c (get_saved_register): Fix byteswapping sins. + +Fri Jul 9 09:47:02 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * defs.h, remote-eb.c (TM_FILE_OVERRIDE): Remove it. + * mips-tdep.c (init_extra_frame_info): Set proper fci->frame if pc + is at the start of the dummy code. + +Thu Jul 8 14:48:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc-tdep.c (sparc_push_dummy_frame): Skip all the do_save_insn + stuff, just write the sp and fp. + (sparc_pop_frame): Skip the do_restore_insn; we already restore + the sp with the other out registers. + + * hppa-tdep.c (hppa_push_arguments): Allocate enough space for + arguments. + + * hppa-tdep.c: Change _initialize_hppab_tdep to _initialize_hppa_tdep. + +Thu Jul 8 14:47:00 1993 Doug Evans (dje@canuck.cygnus.com) + + * sparc-tdep.c (sparc_frame_chain): Handle sizeof (CORE_ADDR) + != sizeof (REGISTER_TYPE). + (frame_saved_pc): Ditto. + +Thu Jul 8 08:22:05 1993 Doug Evans (dje@canuck.cygnus.com) + + * config/h8300/tm-h8300.h: (REGISTER_TYPES): Adjust for h8/300h. + (REGISTER_RAW_SIZE): Ditto. + (REGISTER_VIRTUAL_TYPE): Use builtin_type_unsigned_long for regs + on the h8/300h (ints may still be 16 bits). + (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE, + EXTRACT_STRUCT_VALUE_ADDRESS): Add FIXME's for h8/300h. Some + thought needed here. + + * h8300-tdep.c (print_insn): Call print_insn_h8300h if h8/300h. + (examine_prologue): reg_save_depth is 4 if h8/300h. + + * findvar.c (read_register): Provide some support for 64 bit regs. + (write_register): Ditto. + +Wed Jul 7 14:30:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/nm-riscos.h: machine/machparam.h is always the right + place to look for BSD43_NBPG, not machine/vmparam.h + + * infcmd.c (run_stack_dummy): New argument name. + Change error message in (another) attempt to make it comprehensible. + * valops.c (call_function_by_hand): Pass name to run_stack_dummy. + * symtab.h: Declare demangle and asm_demangle since macros use them. + + * eval.c (evaluate_subexp): Add comment about calling a member + function of a variable in a register. + + * expression.h: Clean up comment about string in STRUCT_STRUCT etc. + + * config/{rs6000/tm-rs6000.h,sparc/tm-sparc.h,pyr/tm-pyr.h}, + inferior.h (PC_IN_CALL_DUMMY) [ON_STACK]: Add comments about stack + frame tops and bottoms. + + * frame.h, blockframe.c, stack.c, a29k-tdep.c, + config/gould/tmp-{pn,np1}.h, + config/{sparc/tm-sparc.h,pyr/tm-pyr.h,vax/tm-vax.h}: Remove field + next_frame from struct frame_info. It has no purpose beyond + ->next->frame and is an artifact from GDB 2.8. + +Tue Jul 6 11:51:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Remove gdb before creating a new one. + Update init.c atomically. + + * Makefile.in (ALLPARAM): Add config/{alpha/xm-alpha.h,pa/xm-pa.h}. + (ALLCONFIG): Add config/alpha/alpha-osf1.mh. + + * infcmd.c (_initialize_infcmd): In docstring for "continue", + describe argument as setting ignore count. + +Sun Jul 4 15:04:47 1993 Doug Evans (dje@cygnus.com) + + * h8300-tdep.c (examine_prologue): Fix call to + read_memory_unsigned_integer. + +Fri Jul 2 18:22:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/{x,n}m-irix{3,4}.h: Make some definitions here + rather than including xm-bigmips.h. + + * eval.c (evaluate_subexp): Improve error messages for OP_TYPE and + default cases. + + * Makefile.in (distclean): Remove y.tab.h. + +Fri Jul 2 14:55:48 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * exec.c (exec_file_command): Remove Mar 28 hack as BFD handles + file updates properly now. + * mipsread.c (mips_coff_new_init): Force reevaluation of sigtramp + addresses if switching to a new symbol file. + * dbxread.c (process_one_symbol): Avoid dereferencing NULL + symbols that might be returned from define_symbol. + +Fri Jul 2 13:33:12 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + New target macros for getting at the pc, sp and fp. + * infcmd.c (read_pc, write_pc): Modify to use new macros. + (read_sp, write_sp, read_fp, write_fp): New functions. + * blockframe.c (reinit_frame_cache, get_prev_frame_info): + Use new functions. + * breakpoint.c (bpstat_alloc): ditto. + * infrun.c (wait_for_inferior): ditto. + * stack.c (print_frame_info): ditto. + * valops (call_function_by_hand): ditto. + * corelow.c (core_open): ditto. + * h8500-tdep.c: (target_read_sp, target_write_sp, target_read_pc, + target_write_pc, target_read_fp, target_write_fp): New functions. + * inferior.h (read_sp, write_sp, read_fp, write_fp): Prototypes. + + * config/alpha/xm-alpha.h: Add MAKEVA_END. + * config/h8500/tm-h8500.h: Define new macros. + +Fri Jul 2 13:51:04 1993 Ian Lance Taylor (ian@cygnus.com) + + * configure.in (mipos-*-riscos*): New host and target; use riscos. + * config/mips/nm-riscos.h: If BSD43_NBPG is not defined by + vmparam.h, include machparam.h. + (KERNEL_U_ADDR): Define to be BSD43_UADDR. + +Fri Jul 2 13:39:48 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-exp.y (yylex): Give error if unmatched single quote. + + * configure.in, config/m68k/*delta68*, delta68-nat.c: New port. + + * Remove unused STACK_END_ADDR in the following files (in other + files it is used for something): tm-mips.h, tm-sun2.h, tm-news.h, + tm-a29k, tm-i386v.h, tm-hppa.h, tm-nindy960.h, tm-amix.h, + tm-hp300hpux.h, tm-isi.h. + +Thu Jul 1 09:51:27 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/mips/nm-riscos.h: Define NBPG and UPAGES. + config/mips/xm-riscos.h: Include . + + * ser-unix.c (hardwire_noflush_set_tty_state): Use an assignment, + not an initializer, to copy the structure. + + * gdbtypes.h (struct type): Add field tag_name. + * gdbtypes.c (type_name_no_tag), c-typeprint.c (c_type_print_base): + Use it. + * {coff,dwarf,mips,stabs}read.c: Set it. + + * xm-sysv4.h: Undefine HAVE_TERMIO. + + * config/mips/nm-riscos.h: Remove unmatched #endif. + Define FETCH_INFERIOR_REGISTERS. + * config/mips/riscos.mh: Don't include coredep.o; mips-nat.o is enough. + Fix misspelling of NAT_FILE. + * mips-nat.c (fetch_core_registers): If KERNEL_U_ADDR is not defined, + we can still process "modern" core files. + + * ser-unix.c (hardwire_print_tty_state) [HAVE_TERMIOS]: Don't + print c_line. + (_initialize_ser_hardwire): Just check whether _POSIX_JOB_CONTROL + is defined; don't care what it is defined to. + +Wed Jun 30 20:06:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/vax/xm-vaxult2.h: Define FD_SET and FD_ZERO. + +Tue Jun 29 11:02:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * inftarg.c: Remove unused include of terminal.h. + * signals.h: Don't undefine signals anymore. + * main.c: Use job_control from serial.h. + * fork-child.c (fork_inferior): Use gdb_setpgid. + * serial.h, ser-unix.c, ser-go32.c: Provide gdb_setpgid. + * utils.c (quit): Use current_target->to_terminal_ours to figure + out whether we care about lack of job control, rather than __GO32__. + * utils.c: Include serial.h not terminal.h + (quit): Use job_control not TIOCGPGRP. + * terminal.h: Don't undefine TIOCGPGRP. + * serial.h, ser-unix.c, ser-go32.c, ser-tcp.c: Add SERIAL_FLUSH_OUTPUT. + * utils.c (quit): Use it. + * serial.h: Add SERIAL_UN_FDOPEN. + * utils.c (quit): Use it. + * ser-unix.c: Add process group to ttystate. + [HAVE_SGTTY]: Add tchars, ltchars, and lmode to ttystate. + * inflow.c: Include serial.h not terminal.h. + Use serial.h stuff to replace most of the maze of #ifdef's. + * inflow.c, main.c, inferior.h: make gdb_has_a_terminal a function. + * serial.h: Document SERIAL_SET_TTY_STATE as being immediate. + * ser-unix.c: Use TIOCSETN not TIOCSETP so it is true. + * serial.h, ser-unix.c, ser-go32.c, ser-tcp.c: + Add SERIAL_PRINT_TTY_STATE, SERIAL_NOFLUSH_SET_TTY_STATE, and + SERIAL_SET_PROCESS_GROUP. + * inflow.c: Use them. + * config/xm-svr4.h, config/rs6000/xm-rs6000.h, config/sparc/sun4os4.h: + Define HAVE_TERMIOS. + * Various: Remove all use of TIOC*_BROKEN. + +Wed Jun 30 12:20:51 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/m68k/tm-sun3.h (BELIEVE_PCC_PROMOTION_TYPE): Define. + +Tue Jun 29 13:44:41 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * target.h (target_detach): Turn macro into function. + * target.c (target_detach): Define it, do deferred register stores + before calling the real target function. + +Tue Jun 29 13:15:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + and Jim Kingdon (kingdon@cygnus.com) + + * symtab.h (BLOCK_SHOULD_SORT): Do not sort blocks corresponding to + a function to avoid printing of function arguments in wrong order + due to sorting. + * symfile.c (compare_symbols): Remove code for sorting arguments + as blocks containing arguments are no longer sorted. + * symtab.c (lookup_block_symbol): Update comment accordingly. + +Tue Jun 29 11:02:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/pa/tm-hppa.h: Remove unused ARGS_GROW_DOC. + (REG_STRUCT_HAS_ADDR): Add comment. + + * infrun.c (wait_for_inferior): Use find_pc_line not find_pc_symtab + to check whether there is line number information. + +Tue Jun 29 08:29:17 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * remote-udi.c: Fix docstring so that it compiles. + + * remote-mips.c, remote-nindy.c: move bfd.h before symfile.h + (for file_ptr). + +Tue Jun 29 09:11:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c (process_one_symbol): If we find a LOC_BLOCK where we + don't expect it, change it to LOC_STATIC so at least we don't coredump. + + * c-typeprint.c (c_type_print_base): Don't error() on invalid type. + + * symtab.h: Add comments about line numbers. + * source.c (identify_source_line): Fix off by one bug with line. + +Mon Jun 28 19:00:21 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Do not include libhppax. Instead include libhppa.h + and hpux-symtab.h. Misc indention fixes. + (find_unwind_entry): Add PARAM prototype. + (read_hpux_symtab): More fixes for names and sizes of structs, + unions, enums, typedefs, and tagdefs. + (read_hp_enum_type, read_hp_struct_type): Likewise. + (read_hp_set_type, read_hp_subrange_type): Likewise. + (hp_type_lookup, process_one_debug_symbol): Likewise. + (process_one_debug_symbol): Search forward from the K_FUNCTION for + the first K_BEGIN when setting the line number associated with a + function. Avoid unnecessary calls to savestring. + (hp_alloc_type): Initialize TYPE_CPLUS_SPECIFIC here. Remove + most cases where we set it elsewhere. + (hppa_sym_fns): Use "hppa" instead of hppax since hpread.c and + paread.c use the same BFD backend now. All references changed. + (hpux_symfile_init): Allocate space to hold the debugging section + contents on the symbol obstack. + +Mon Jun 28 10:09:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (makeva*): New interface, for making a va_list. + (printf_command): Use it. + * config/m88k/xm-delta88.h: Remove VPRINTF define, not needed. + * config/pa/xm-pa.h: New file. + * config/pa/xm-hppa{b,h}.h: Include it. + + * xcoffread.c: Remove obsolete NO_TYPEDEFS comment. + +Sun Jun 27 08:54:55 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valprint.c (val_print_type_code_int): Fix off by one error with + eliminating leading zeroes for large little endian integers. + +Sun Jun 27 08:58:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/riscos.mh (CC): Use -systype sysv. + + * ser-unix.c: Move #include of to HAVE_SGTTY section. + + * Makefile.in (ALLPARAM): Add config/mips/{x,n}-{news-mips,riscos}.h. + +Fri Jun 25 11:22:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/tm-m68k.h: Remove obsolete comment about duplicating + CALL_DUMMY between different 68k machines. + +Fri Jun 25 17:02:45 1993 Stu Grossman (grossman at cygnus.com) + + * gdbserver/Makefile.in: Add dependancies on server.h. + * gdbserver/remote-gutils.c: Remove lots of unused functions and + variables. + * gdbserver/remote-inflow.c: Remove lots of unused variables and + #includes. Also, use PTRACE_* symbols instead of constants. + (mywait): Surround calls to wait() with enable/disable_async_io() + so that we can be interrupted from GDB while waiting for the + child. Also, handle child exit more gracefully. + * gdbserver/remote-server.c: Remove lots of unused variables. + Move all extern defs into server.h. Redo main loop so that + failure from getpkt() causes communications to be re-established. + Fix 'k' command so that it restarts the child. + * gdbserver/remote-utils.c: Remove lots of unloved vars and + subrs. Move many extern decls into server.h. (remote_open): For + tcp, seperate usage of proto fd from connected fd. Close proto + fd after getting connection. (putpkt/getpkt): Pay attention to + errors when reading/writing. Report these to the caller. New + routines input_interrupt/enable_async_io/disable_async_io to make + it possible to get an I/O interrupt when data arrives from the + comm link. + * serial.h: New file to contain common defs for all remote files. + +Fri Jun 25 17:02:45 1993 Stu Grossman (grossman at cygnus.com) + + * remote.c: Add arg names to prototypes, in a modest effort at + clarification. Also add prototypes for some new functions. + * (remote_wait): Better error reporting for 'T' responses. + * ser-go32.c (strncasecmp): Make str1 & str2 be const. + * (dos_async_init): Make usage message reflect requested port #. + * ser-tcp.c (tcp_open): Terminate hostname properly to prevent + random hostname lookup failures. Add nicer message for unknown + host error. (wait_for): Wake up in case of exceptions. Also, + restart select() if we got EINTR. + * ser-unix.c (wait_for): Restart select() if we got EINTR. + * serial.c: (serial_close): Clean up code. + +Fri Jun 25 11:22:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/tm-m68k.h: Remove obsolete comment about duplicating + CALL_DUMMY between different 68k machines. + +Fri Jun 25 11:22:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (*.tab.c): Use ./c-exp.tab.c not just c-exp.tab.c. + Make comment explaining this comprehensible. + (TAGFILES): Include ALLDEPFILES. + (ALLDEPFILES): udi2soc.c and udr.c are in 29k-share/udi, not + 29k-share/udi/udi. + (update-alldeps): Remove; obsolete. + + * remote.c: Move comments regarding packets to top of file with the + rest of the protocol comments. + Fix incorrect description of 'T' response. + + * README (Reporting Bugs): Refer people to the GDB manual. + + * c-valprint.c (c_val_print): Handle TYPE_CODE_BOOLEAN. + * stabsread.c: Type -16 is 4 bytes. + + * remote-udi.c: Improve docstring. + +Fri Jun 25 11:16:31 1993 Fred Fish (fnf@cygnus.com) + + * elfread.c (elf_symfile_read): Call bfd_elf_find_section, not + bfd_elf32_find_section, to track bfd changes. + +Fri Jun 25 11:22:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/riscos.mh (REGEX{,1}, MUNCH_DEFINE, MH_CFLAGS): Define. + * config/mips/xm-riscos.h: Define USG. + +Thu Jun 24 14:52:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (filename_completer): Don't complete to files ending in ~. + + * NEWS: Mention filename completion and "info line" enhancements. + + * main.c (symbol_completion_function): On "info t foo", return NULL, + don't error(). + + * main.c (symbol_completion_function): Don't use readline word + breaking. Use new calling convention for c->completer and + complete_on_cmdlist. + * command.h (struct command): Change arguments; now the text passed + to completer does not have any word breaking done. New arg word. + * symtab.{c,h} (make_symbol_completion_list): Do word breaking. Take + word argument. + * {main.c,gdbcmd.h} ({filename,noop}_completer): Take word argument. + * command.{c,h} (complete_on_cmdlist): Take word argument. + + * command.c (lookup_cmd_1): Doc fix. + +Thu Jun 24 13:26:04 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * Makefile.in (OP_INCLUDE): define. + (OPCODE_CFLAGS): use OP_INCLUDE. + + * config/i386/ncr3000.mh, config/i386/i386v4.mh, + config/i386/i386sol2.mh, config/m68k/hp300hpux.mh, + config/m68k/amix.mh, config/mips/irix[34].mh, + config/m88k/delta88.mh, config/sparc/sun4sol2.mh (ALLOCA, + ALLOCA1): macros removed. + + * config/mips/decstation.mh, config/rs6000/rs6000.mh + (MMALLOC_LIB): renamed to MMALLOC. + +Wed Jun 23 00:25:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * partial-stab.h: Consolidate case statements for N_LSYM and N_FUN. + * dbxread.c: Change comment regarding acc. + +Wed Jun 23 16:33:36 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Document a few functions, misc cleanups. Update + copyright to reflect the first "release" of this file. + (struct hpux_symfile_info): Delete unneeded fields. Keep pointers + to the contents of the debug sections rather than offsets within + the file itself. Corresponding changes to the accessor macros. + (sl_symbol_size, slt_symbuf): Delete unneeded global variables. + (slt_symbuf_start, slt_symbuf_end, lntt_symbuf): Likewise. + (lntt_symbuf_start, lntt_symbuf_end, gntt_symbuf): Likewise. + (gntt_symbuf_start, gntt_symbuf_end): Likewise. + (fill_slt_symbuf, fill_lntt_symbuf): Delete unneeded functions. + (fill_gntt_symbuf): Likewise. + (get_lntt, get_gntt, get_slt): Simplify. + (hpux_symfile_init): Read and store the contents of the debugging + sections. Do error checking on memory allocation and BFD calls. + (read_hpux_symtab): Delete KERNELDEBUG crud. Ignore debug symbols + which are not needed for building partial symbol tables. Handle + K_CONST, K_TYPEDEF, and K_TAGDEF just like K_SVAR and K_DVAR. + (read_ofile_symtab): Delete useless processing_gcc_compilation stuff. + (read_hp_struct_type): Initialize TYPE_CPLUS_SPECIFIC. + (read_hp_set_type, read_hp_array_type): Likewise. + (read_hp_subrange_type, hp_type_lookup): Likewise. + +Wed Jun 23 15:04:54 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + Makefile overhaul dropping autodepend features. + * Makefile.in: many comment changes. forced consistent use of $() + for makefile variables references. dropped leading ./ in file + references. Drop $(srcdir)/ prefix on all dependencies. + Inserted contents of alldeps.mak and depend. + (INCLUDE_CFLAGS): defined as new macro for getting libiberty's + include directory into the compilation line. + (GDB_CFLAGS): new macro to take up the semantic previously held + by INCLUDE_CFLAGS. + (LIBIBERTY): dropped ancient subdir macro. I last removed this + macro in feb of '92. How does it keep coming back? + (MMALLOC_LIB): renamed to MMALLOC. + (BFD_SRC_DIR): renamed to BFD_SRC. + (BFD_OBJ_DIR): renamed to BFD_DIR. + (BFD_LIB): renamed to BFD. + (BFD_INCLUDES): renamed to BFD_CFLAGS. + (READLINE_DIR): now represents object directory. + (RL_LIB): renamed to READLINE. + (READLINE_SRC, READLINE_CFLAGS, OPCODES, OPCODES_CFLAGS): new + macros. + (INTERNAL_CFLAGS): added GDB_CFLAGS, OPCODES_CFLAGS, + READLINE_CFLAGS, BFD_CFLAGS. Dropped USER_CFLAGS. + (LDFLAGS): removed default assignment. + (TEXIDIR, INCLUDE_DEP, MMALLOC_DIR, MMALLOC_DEP, BFD_DEP, + READLINE_DEP, LIBIBERTY_DIR, TESTS, depend, STAGESTUFF): unused, so removed. + (ALLOCA1, ALLOCA): removed all references. alloca is now in + libiberty. + (VERSION): unilaterally and arbitrarily bumped to 4.9.3. + (SFILES, NONSRC, HFILES, ALLDEPFILES, ALLPARAM, ALLCONFIG): + removed all $(srcdir) prefixes. + (getopt_h, ieee-float_h, bfd_h, wait_h, dis-asm_h): new macros + for potential dependencies. commented out by default. + (readline_headers, udiheaders): convenient abbreviations. + (gdbcore_h, frame_h, symtab_h, gdbtypes_h, expression_h, + value_h, breakpoint_h, command_h, gdbcmd_h, defs_h, inferior_h): + new macros used for header file dependencies. + (install-info, clean-info): collapse into the info rule. + (install): now depends on all. + (install-only): new target for installing without depending on + all. + (uninstall): new target. + (config-check, config-check-hosts, config-check-targets): added + fixme comments. + (ch-exp.tab.c, m2-exp.tab.c): added artificial dependencies in + order to force parallel makes into keeping these rules separate. + * configure.in: omit cat'ing depend file onto generated Makefile. + * alldeps.mak, depend: removed. + + * inferior.h: remove redundant include of symtab.h which is + included in value.h via breakpoint.h. + + * alloca.c: removed. alloca is now in libiberty. + + * config/m88k/delta88.mh, config/ns32k/merlin.mh (M_UNINSTALL): + new macro to undo what M_INSTALL does. + +Wed Jun 23 00:25:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/ns32k/{merlin.mh,xm-merlin.h}: Be consistent about name + of gdb-sh. + + * dbxread.c (copy_pending): Change name and function of begi argument + to endi, since that is what the caller needs. + + * Makefile.in (TAGFILES): Don't include YYFILES. + + * Makefile.in (HFILES): Include monitor.h. + + * Makefile.in: Include text that used to be in alldeps.mak. + Remove config/mips/{bigmips.mh,xm-bigmips} from it. + * Makefile.in, configure.in: Remove all traces of alldeps.mak. + + * main.c (main): Print help message on stdout not stderr + per standards.texi. + New option --version per standards.texi. + In help message, show long options with "--" not "-". + Don't try to print help message or version until after we have + called initialize_all_files. + +Tue Jun 22 11:03:13 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Delete useless #if 1 statements. + (hp_type_translate): Use T_LONG, T_UNS_LONG, and T_DOUBLE instead + of magic integers. Fix handling for T_UNS_INT. Abort if the type + passed in is not an "immediate" type. + (read_hp_enum_type): Properly compute the size of the type. + (read_hp_array_type): Likewise. + (hp_type_lookup): Prefix the names of structs, unions and enums + with "struct", "union", and "enum" as appropriate. + +Tue Jun 22 03:15:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * solib.c (solib_add_common_symbols): Don't call lookup_minimal_symbol. + (solib_add): Call special_symbol_handling once, not once per library. + + * procfs.c (procfs_resume): Don't pass a SIGTSTP whose action + is SIG_DFL. + + * procfs.c (procfs_resume): Skip the unnecessary PRSVADDR on all + systems, not just Solaris. + + * stabsread.c: Include . + +Mon Jun 21 16:09:46 1993 Jim Kingdon (kingdon@cygnus.com) + + * fork-child.c (fork_inferior): Quote exec_file so it can contain + funky characters. + +Mon Jun 21 16:56:47 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (INCLUDE_CFLAGS): Add BFD_INCLUDES for now, since + bfd.h is included by target.h, which most of gdb includes. + * depend: Hand remove BFD_INCLUDES from ${CC} lines, now that + it's in INCLUDE_CFLAGS. + +Mon Jun 21 16:09:46 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/i386/*aix*, i386aix-nat.c: New files. + * configure.in: Use them. + * alldeps.mak: List them. + * coffread.c (decode_base_type): Deal with anonymous enum type. + * i387-tdep.c (print_387_status_word): Add comment re "top". + * i386-tdep.c [I386_AIX_TARGET] (i386_extract_return_value): New func. + * dbxread.c: Use SEEK_SET and SEEK_CUR, not L_*. Define them if and + only if not defined by a header file. + * mipsread.c: Don't define L_SET or L_INCR. + +Mon Jun 21 15:10:07 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (BFD_INCLUDES): Bfd.h is now back in bfd build dir. + * depend: Hand updated to match. + +Mon Jun 21 10:13:42 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Include "demangle.h". + (process_one_debug_symbol): Set the SYMBOL_LANGUAGE and + SYMBOL_INIT_DEMANGLED_NAME for the current symbol. Adjust + SYMBOL_VALUE for local variables in the stack by the size of the + current function's stack (found in unwind descriptor). Keep + better track of the current unwind descriptor. + +Sun Jun 20 13:11:11 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabsread.c (read_struct_fields): Don't call read_cpp_abbrev on $_. + (read_cpp_abbrev): Don't complain specially for $_. Also return 0 if + we don't recognize the abbrev. + +Sun Jun 20 00:24:41 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * solib.c (solib_add_common_symbols): Add comment about performance. + +Fri Jun 18 12:37:36 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/{{x,n}m-riscos.h,riscos.mh}: New files. + * configure.in (mips-*-sysv*): Use riscos for host, bigmips for target. + + * config/mips/{{x,n}m-news-mips.h,news-mips.mh}: New files. + * config/mips/{bigmips.mh,xm-bigmips.h}: Remove. + * configure.in (mips-sony-*): Use news-mips for host. + + * buildsym.h: Doc fix for processing_acc_compilation. + +Thu Jun 17 19:57:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_formatted): Don't use tab in wrap_here arg. + +Thu Jun 17 17:29:30 1993 Jim Kingdon (kingdon@lisa.cygnus.com) + + * Makefile.in (INTERNAL_CFLAGS): Include ../include as well as + ${srcdir}/../include. + + * config/m88k/xm-delta88.h: Comment out unused defines which conflict + with system headers. + * printcmd.c (printf_command): Cast second arg to vprintf to PTR. + Use VPRINTF macro if defined. + * config/m88k/xm-delta88.h: Define VPRINTF. Include . + Define TIOC{GETC,GLTC}_BROKEN. + * m88k-nat.c: Uncomment include of . + * main.c: Rename initialize_{main,cmd_lists,history} to init_* to + make things easier on munch (apparently this matters on + the delta88 with svr3). + +Thu Jun 17 16:53:56 1993 david d `zoo' zuhn (zoo@cygnus.com) + + * Makefile.in: canonicalize install.sh; for use within + this directory (and subdirs) + +Tue Jun 15 17:01:23 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: remove parentdir support; use INSTALL_XFORM + +Thu Jun 17 15:08:35 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * configure.in (alpha-*-osf*), config/alpha/alpha-osf.mh: New + host. + * sh-tdep.c (frame_find_saved_regs): Use NUM_REGS rather than hard + wired (and wrong) constant. + * values.c (unpack_long): Add case to unpack when target object is + sizeof(int). + * config/sh/tm-sh.h (REGISTER_NAMES): Know about the news ones the + simulator defines. + +Wed Jun 16 16:08:18 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * NEWS: tracking user visible changes starting with + vxworks-timeout. + + * remote-vx.c (_initialize_vx): rename user settable option from + rpcTimeout to vxworks-timeout. + +Wed Jun 16 14:34:10 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hp_type_translate): Fix promotion bugs from + char to short and short to int. + +Wed Jun 16 12:21:49 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (depend): More makefile diddling. + * alldeps.mak, depend: Update to latest automatically built + versions. + + * Makefile.in (depend): Bfd.h keeps moving, keep up with it. + * alldeps.mak, depend: Update to latest automatically built + versions. + +Tue Jun 15 12:26:05 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * remote-vx.c: include gdbcmd.h for setlist. + (_initialize_vx): make rpcTimeout user settable. + +Mon Jun 14 09:23:51 1993 Jim Kingdon (kingdon@cygnus.com) + + * main.c, gdbcmd.h: Add function filename_completer. + * main.c, symfile.c, source.c, exec.c, core.c: Use it for + "directory", "source", "cd", "symbol-file" "add-symbol-file", + "load", "file", "exec-file", "core-file" commands. + (But '/' is a word break, limiting usefulness; see comments). + + * source.c (mod_path): Warning not error if can't find directory. + + * isi-xdep.c: New file. + * config/m68k/isi.mh (XDEPFILES): Add isi-xdep.o + +Sun Jun 13 09:17:48 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/m68k/xm-news.h: Include . + + * m88k-tdep.c (IEEE_isNAN): Remove. + config/m88k/tm-m88k.h (INVALID_FLOAT): Return 0. This was the same + broken isNAN as on the mips. + + * valprint.c (_initialize_valprint): Use c->function.sfunc not just + c->function. + + * dbxread.c (process_one_symbol): If SUN_FIXED_LBRAC_BUG is not + defined, don't worry about Sun's silly LBRAC bug. + * config/m68k/tm-sun3.h: Define SUN_FIXED_LBRAC_BUG to 0. + + * dbxread.c (process_one_symbol): If there's a symbol before an + N_SO, don't error(). + (case N_BCOMM): complain () not error (). + + * defs.h, main.c (catch_errors): Add return_mask arg. + stack.c (print_frame_info): Pass RETURN_MASK_ERROR. + other callers: Pass RETURN_MASK_ALL. + (return_to_top_level), callers: Add return_reason arg. + * utils.c (quit): + Use return_to_top_level (RETURN_QUIT) instead of error (). + * main.c (main), tm-nindy960.h (ADDITIONAL_OPTION_HANDLER): + Use SET_TOP_LEVEL not setjmp (to_top_level). + * remote-nindy.c: Use catch_errors not setjmp (to_top_level). + +Sat Jun 12 14:40:54 1993 Jim Kingdon (kingdon@cygnus.com) + + * solib.c (solib_create_inferior_hook) [SVR4_SHARED_LIBS]: + Don't try to get the debug base yet. + + * dbxread.c (process_one_symbol): Set n_opt_found based on whether + a non-gcc N_OPT symbol is found. Make SUN_FIXED_LBRAC_BUG a macro + which returns 0 or 1 to say whether to do it. + * config/sparc/sun4{sol2,os4}.h + (SUN_FIXED_LBRAC_BUG,VARIABLES_INSIDE_BLOCK): Use n_opt_found so + the right thing happens for both acc and SunOS4 /bin/cc. + + * valprint.c (print_hex_chars): Use local_hex_format_{pre,suf}fix. + * printcmd.c (print_scalar_formatted): Use val_print_type_code_int. + + * mips-tdep.c: Remove isa_NAN; it assumed sizeof(host int) == 4 and + probably contained byte-order sins too. + config/mips/tm-mips.h (INVALID_FLOAT): Define to 0 like most machines. + The IEEE_FLOAT code in print_floating takes care of it. + +Sat Jun 12 14:47:04 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.9.2. + * c-valprint.c (c_val_print): For array of chars printed with + string syntax, don't print the address of the array. From + bothner@cygnus.com. + * c-exp.y (yylex): Recognize '.' as indicating a floating point + number regardless of the radix. From wilson@cygnus.com. + * valprint.c (set_input_radix_1, set_output_radix_1): New + prototypes and functions that do the actual radix setting work. + * valprint.c (set_radix, set_output_radix, set_input_radix): + Rewrite to use set_input_radix_1 and set_output_radix_1. + * valprint.c (initialize_valprint): Enable commands to + independently set and show input and output radices. + * valprint.c (show_radix): New prototype and function that + handles separate input and output radices. + +Fri Jun 11 18:39:38 1993 Ken Raeburn (raeburn@cygnus.com) + + Patches from Jeff Law, law@cs.utah.edu: + * hppa-pinsn.c: Now uses disassembler from opcode library, + this contains only the stub function print_insn. + +Fri Jun 11 15:19:59 1993 K. Richard Pixley (rich@cygnus.com) + + * main.c (main): back to two periods for elipse. + (print_gdb_version): revised format for configuration info. + +Fri Jun 11 10:24:35 1993 Fred Fish (fnf@cygnus.com) + + * defs.h (INT_MAX): Cast unsigned shift result to int. + +Fri Jun 11 10:17:41 1993 Jim Kingdon (kingdon@cygnus.com) + + * dbxread.c (process_one_symbol): Rather than having + BLOCK_ADDRESS_FUNCTION_RELATIVE a macro, make it a variable which + is true if we are doing stabs-in-elf, false otherwise. + config/sparc/tm-sun4sol2.h: Don't define it. + +Fri Jun 11 13:33:40 1993 Ian Lance Taylor (ian@cygnus.com) + + * remote-mips.c (mips_send_packet): Don't print garbage character + in debugging info. + (mips_request): Don't check that remote pid is 0, because + sometimes it isn't. + (mips_fetch_registers): Pass a pointer to SWAP_TARGET_AND_HOST, + not an integer. + +Fri Jun 11 10:17:41 1993 Jim Kingdon (kingdon@cygnus.com) + + * stack.c (print_frame_info): Use catch_errors around print_frame_args. + + * Makefile.in (install): Don't depend on gdb. + + * Rename remote-es1800.c to remote-es.c + and remote-st2000.c to remote-st.c for 14-char filenames. + config/m68k/{es1800,st2000}: Use the new names. + + * mips-tdep.c (isa_NAN): Don't return true on -0. + +Fri Jun 11 10:24:35 1993 Fred Fish (fnf@cygnus.com) + + * defs.h (INT_MAX): Cast unsigned shift result to int. + +Thu Jun 10 13:26:41 1993 Fred Fish (fnf@cygnus.com) + + * elfread.c (elf_symtab_read): Add bfd section address to bfd + symbols, now that they are section relative. + * solib.c (bfd_lookup_symbol): Ditto. + +Thu Jun 10 11:27:34 1993 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hp_function_type): Adjust SYMBOL_VALUE for + arguments in the stack by the size of the current function's stack + (found in the unwind descriptor). + (process_one_debug_symbol): Likewise. Keep track of the current + function's unwind descriptor. + +Thu Jun 10 10:56:56 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (depend): Add bfd -I's for paread.c and xcoffexec.c + depend: Updated accordingly. + +Wed Jun 9 16:08:44 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (*.tab.c): Use mv for atomic update. + + * Makefile.in ({dist,real}clean): Also remove nm.h. + (realclean): Also remove ${TESTS}, y.output, yacc.{acts,tmp}. + (distclean): Don't rebuild *.tab.c or TAGS. + +Wed Jun 9 12:56:58 1993 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in (version.c): add host and target names to version.c. + * main.c (main): print three periods for the elipse. + (print_gdb_version): also print configuration. + + * udi/udiids.h, udi/udip2soc.c, udi/udiphcfg.h, udi/udiphunix.h, + udi/udiproc.h, udi/udipt29k.h, udi/udiptcfg.h, udi/udisoc.h, + udi/udr.c: Change AMD copyrights to FSF copyleft '93. + + * remote-eb.c (get_hex_regs, eb_fetch_registers), remote-adapt.c + (get_hex_regs, adapt_fetch_registers): cast args to + supply_register to avoid gcc warning. + + * config/a29k/a29k.mt (TDEPFILES): drop minimon support. It + doesn't compile on solaris and is now obsolete. + + * config/sparc/sun4os4.mh (XM_CLIBS): remove -lresolv. This + breaks stock sunos installations. + +Wed Jun 9 06:14:33 1993 Jim Kingdon (kingdon@cygnus.com) + + * m68k-stub.c: Add comment about frame cache. + + * target.h (target_store_registers): Doc fix re error handling. + + * findvar.c (write_register): Call SWAP_TARGET_AND_HOST regardless + of register_valid[regno]. + +Tue Jun 8 14:42:10 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * symtab.h, dwarfread.c: Doc fix re dependencies. + +Tue Jun 8 17:54:09 1993 Rob Savoye (rob@rtl.cygnus.com) + + * serial.c (serial_close): If scb is NULL, don't try to close + it. + * configure.in: Add support for rom68k and bug boot monitors. + +Tue Jun 8 17:39:12 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * coffread.c (init_stringtab): Fix bug where sizeof(long) != 4. + * gdbcore.h, core.c (read_memory_unsigned_integer): New function. + * findvar.c (read_register, write_register): Fix thinko where + sizeof(host long) != sizeof(target int). + * h8300-tdep.c: Use new read_memory_unsigned_integer call. + * sh-tdep.c (_initialize_sh_tdep): Add memory_size command. + +Tue Jun 8 14:42:10 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * Move config/m68k/tm-m68k.h (FRAME_FIND_SAVED_REGS) to + m68k-tdep.c (m68k_find_saved_regs). Don't duplicate code between + 68881 and non-68881 cases. Check for a pair of movel instructions. + +Tue Jun 8 14:52:55 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + First cut at sparc-vxworks targetting. + * config/sparc/tm-vxsparc.h, config/sparc/vxsparc.mt: new files. + * configure.in: sparc-vxworks gdb_target now vxsparc. + + * remote-eb.c, remote.c: symfile.h requires bfd.h so include it. + +Tue Jun 8 14:42:10 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * config/m68k/xm-news.h: add "extern int errno". + +Tue Jun 8 13:45:07 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * remove-vx.c (vx_read_register, vx_write_register): collapse + ifdef I80960 else (assumes) m68k into parameterizable macros + VX_NUM_REGS and VX_SIZE_FPREGS. + * config/m68k/tm-vx68.h, config/i960/tm-vx960.h (VX_NUM_REGS, + VX_SIZE_FPREGS): new definitions. + +Tue Jun 8 11:08:29 1993 Jim Kingdon (kingdon@cygnus.com) + + * symfile.{c,h} (generic_load): New function. + remote{,-nindy,-eb,-mips}.c: Use it. + +Mon Jun 7 20:07:30 1993 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (depend): More sed gubbish to deal with + ../bfd/bfd.h being generated during the build. + * depend: Re-done with corrected makefile. + +Mon Jun 7 16:32:05 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (BFD_SRC_DIR): Renamed def and usages from BFD_DIR. + * Makefile.in (BFD_OBJ_DIR): New definition for the bfd build + directory to find automatically generated header files and library. + * Makefile.in (BFD_LIB): Use BFD_OBJ_DIR. + * Makefile.in (LINTFLAGS): Include BFD_OBJ_DIR. + * Makefile.in (saber_gdb): Include BFD_OBJ_DIR. + * Makefile.in (depend): Include BFD_OBJ_DIR in gcc args. + * Makefile.in (paread.o, xcoffexec.o): Remove, now in depend. + * depend, alldeps.mak: Rebuild after Makefile.in changes. + +Fri Jun 4 10:18:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * configure.in: change lynx support to CPU-*-lynxos* + + * Makefile.in (subdir_do): change test from existence of directory + to existence of Makefile (the directory may exist but not be configured) + +Thu Jun 3 01:18:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * config/sparc/xm-sun4sol2.h: define MEM_FNS_DECLARED + +Fri Jun 4 10:43:33 1993 Ian Lance Taylor (ian@cygnus.com) + + * configure.in (mips-idt-ecoffl*): New target; use idtl. + (mips-idt-ecoff*): Added trailing '*'. + * config/mips/idtl.mt: New file; like idt.mt, but little endian. + +Thu Jun 3 17:36:56 1993 Stu Grossman (grossman@cygnus.com) + + * ser-go32.c: Clean up lots of compilation nits. + +Thu Jun 3 14:44:57 1993 Stu Grossman (grossman@cygnus.com) + + * Patches from Jeffrey Law . + * hppab-nat.c: Eliminate unnecessary ifdefs for + FETCH_INFERIOR_REGISTERS, CANNOT_FETCH_REGISTER, and + CANNOT_STORE_REGISTER. + (fetch_register): Delete code to handle CANNOT_FETCH_REGISTER. + * hppa-pinsn.c: Support 'I', 'J', and 'K' in output + templates for 1.1 FP computational instructions. + +Thu Jun 3 03:34:49 1993 Stu Grossman (grossman@cygnus.com) + + * Makefile.in: Remove ser-tcp.[co]. (Use XDEPFILES instead.) + * alldeps.mak, depend: Rebuild to account for ser-tcp. + * config/sparc/sun4os4.mh: Add ser-tcp to XDEPFILES. + * gdbserver/Makefile.in (gdbserver): Use -lbsd. + * gdbserver/remote-inflow{-sparc}.c (create_inferior): Don't use a + shell when running the child, as args have been expanded by the + time we get here. Simplify calling convention. + * gdbserver/remote-server.c (main): Use new calling convention + for create_inferior, remove defunct code for coalescing argv. + Remove extra calls to mywait(), as we no longer have to wade + through a shell. + + * target.c (target_read_memory_partial): Don't deref errnoptr + when checking for null pointer. + +Wed Jun 2 19:58:46 1993 John Gilmore (gnu@cygnus.com) + + * remote-es1800.c: Fix typo. + +Tue Jun 1 21:22:39 1993 Fred Fish (fnf@cygnus.com) + + * target.c (target_read_memory_partial): Like target_read_memory, + but does partial reads, such as reads that bump into the end of + the address space. + * target.h (target_read_memory_partial): Add prototype. + * valprint.c (PRINT_MAX_DEFAULT): New define, initial value 200. + * valprint.c (val_print_string): Complete rewrite to fix bug with + bumping into end of memory, avoiding unnecessarily long reads, and + fixing bug when print_max is set to 0 (unlimited print length). + * valprint.c (_initialize_valprint): Use PRINT_MAX_DEFAULT to + initialize print_max. + +Tue Jun 1 18:11:35 1993 Rob Savoye (rob at darkstar.cygnus.com) + + * configure.in: Add support for rom68k and bug boot monitors. + +Mon May 31 10:37:04 1993 Jim Kingdon (kingdon@cygnus.com) + + * printcmd.c (print_scalar_formatted): Print integers bigger than + LONGEST in hex no matter how big, and no matter what the format + and size. + + * stabsread.c (read_type): Skip type attributes if present. + + * stabsread.c (read_huge_number): Don't accept '0' + radix as part + of number, just through '0' + radix - 1. + +Sun May 30 15:35:21 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (SER_HARDWIRE): Temporarily comment out ser-tcp.o. + + * {dbxread.c, dwarfread.c} (read_ofile_symtab): Rewrite to take + single parameter, the pointer to the partial symtab, rather than + a bunch of args that are derived from the partial symtab. Change + prototypes and callers to match. + + * dbxread.c (read_ofile_symtab): Remove "#if 1" around code to + set demangling style automatically. + * defs.h (CPLUS_MARKER): Clarify comment that this is only for + GNU C++, not C++ in general. + * symtab.h (general_symbol_info): Simplify by eliminating one + structure level for the language dependent info. + +Sat May 29 15:59:29 1993 Fred Fish (fnf@cygnus.com) + + * c-typeprint.c (c_type_print_base): Avoid dereferencing NULL + names for TYPE_CODE_STRUCT and TYPE_CODE_UNION types. + TYPE_CODE_ENUM was already testing for this. + +Fri May 28 17:18:05 1993 Stu Grossman (grossman@cygnus.com) + + * Makefile.in: Add new file ser-tcp.c. + * defs.h (memcmp): Add decl for memcmp to #ifndef MEM_FNS_DECLARED. + * findvar.c (write_register): See if we are writing back the same + value that's already in the register. If so, don't bother. + * remote.c (putpkt, getpkt): Improve handling of communication + problems. + * ser-go32.c: Prototype it to death. Update serial_ops and add + dummy routines where appropriate. + * ser-tcp.c: New module to implement serial I/O via TCP + connections. + * ser-unix.c: Clean up getting/setting of tty state. Get rid of + SERIAL_RESTORE, add SERIAL_{GET|SET}_TTY_STATE interfaces. + * serial.c: Add start of support for connect command. + (serial_open): Distinguish between tcp and local devices. + * serial.h (struct serial_ops): Get rid of restore, add + get_tty_state and set_tty_state. Define protoypes and macros for + this mess. + * gdbserver/remote-utils.c: Add tcp support. (readchar): Do + some real buffering. Handle error conditions gracefully. + * gdbserver/remote-inflow-sparc.c: Update to remote-inflow.c + (Lynx), remove lots of cruft. + +Fri May 28 17:24:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * printcmd.c (print_address_symbolic): turn this into an assigment + instead of an initialization (many compilers don't accept + structure initialization). + +Thu May 27 16:56:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): If several program csects in one + source file, give them all the name of the source file, rather than + the 2nd and subsequent ones having NULL names. + +Thu May 27 06:16:56 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * printcmd.c (print_address_symbolic): Append source filename and + linenumber of the symbol if print symbol-filename is on. + (initialize_printcmd): `set print symbol-filename'. + +Wed May 26 13:46:16 1993 Stu Grossman (grossman@cygnus.com) + + * configure.in: Add config for Lynx target. Configure gdbserver + only for Lynx. Re-do selective configuration of sparclite. + + * gdbserver/{remote-gutils.c remote-server.c Makefile.in + configure.in remote-inflow.c remote-utils.c}: New files to + support GDB remote server. Currently only works for Lynx. + +Wed May 26 10:28:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (define_symbol, case 't'): Only set the name if it + is not a pointer type. + + * stabsread.c (define_symbol): Clean up logic; move the read_type + calls to inside the switch statement (this improves the error + handling). + + * mipsread.c (parse_symbol, parse_partial_symbols): Deal with Fortran + common blocks. + +Tue May 25 20:44:24 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_formatted, case 'i'): Pass a tab to wrap_here. + + * source.c (line_info): Change "pc" to "address" in messages and + use print_address for addresses. + + * source.c (line_info): If we don't find a symtab, print more useful + output, including the symbolic address. + + * source.c (line_info): If --fullname, display the source. + (identify_source_line), callers: Take pc as argument, rather than + assuming innermost frame (emacs doesn't use this, so no one ever + noticed). + * symtab.h: Declare frame_file_full_name. + * main.c: Don't. + +Tue May 25 15:30:43 1993 Brendan Kehoe (brendan@lisa.cygnus.com) + + * breakpoint.c (catch_command_1): Fix typo in error msg. + +Tue May 25 16:05:55 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * elfread.c (elf_symfile_read): Update ELF structure and routine + names to specify 32-bit versions. + (elf_symtab_read): Retrieve size field directly from symbol, + instead of using old kludge. + + * mips-pinsn.c (print_insn): Cast address to bfd_vma before + calling opcodes library. + * z8k-tdep.c (print_insn): Likewise. + +Tue May 25 13:06:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c: Remove all uses of error(). Make error_type and + read_type_number static. + (define_symbol): Don't try to deal with a missing symbol + descriptor which isn't followed by digit, '(', or '-'. + * stabsread.h: Don't declare read_type_number here. + * gdbtypes.h: Don't declare error_type here. + * xcoffread.c: Remove NO_TYPEDEFS code. + +Tue May 25 09:33:16 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips-tdep.c: Removed #include of many header files, and #define + of MIPSMAGIC; no longer used. + +Tue May 25 09:36:13 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Many places: replace "the inferior" in messages with "the program" + or "the program being debugged". + * inflow.c (try_writing_regs): Remove; it's been #if 0'd forever + and I'm getting sick of maintaining it. + + * config/i386/linux.mh: Don't use \ newline; the awk scripts don't + support it. + + * config/i386/go32.mh: Define SER_HARDWIRE. + * Makefile.in: Define SER_HARDWIRE. + (DEPFILES): Use it. + (alldeps.mak): Add SER_HARDWIRE. + Remove all references to ser-hardwire.{c,o}. + * configure.in: Remove all ser_hardwire and gdb_serial_driver stuff. + +Mon May 24 23:50:05 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-nat.c (store_inferior_registers): Fill in all members of + inferior_fp_registers by reading them from the inferior before + modifying and writing them back. + Fixes unexplainable inferior FP exceptions after calls to the inferior + or setting of floating point registers. + * mips-tdep.c (mips_skip_prologue): Skip move of argument register + to register which is generated by gcc-2.4. + +Tue May 25 00:42:39 1993 Ken Raeburn (raeburn@cygnus.com) + + * hppa-pinsn.c: Define OLD_TABLE before including opcode/hppa.h. + +Mon May 24 13:55:14 1993 Stu Grossman (grossman@cygnus.com) + + * config/i386/{i386lynx.mh i386lynx.mt nm-i386lynx.h tm-i386lynx.h + xm-i386lynx.h}: New configuration for Lynx. + +Mon May 24 10:01:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mipsread.c (parse_symbol): Deal with scVar and scVarRegister. + * symtab.h: Comment that LOC_REGPARM_ADDR can be call by reference. + + * c-typeprint.c (c_type_print_base): Don't print typedef'd names + as struct, union, or enum tags. + +Mon May 24 01:10:01 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symmisc.c (dump_msymbols): Avoid gdb coredump with stripped + executable. + +Sat May 22 10:03:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior), + infcmd.c (program_info, signal_command): Use symbolic signal names. + + * inftarg.c (child_wait): Deal with EINTR and include message from + strerror if printing an error message. + + * main.c (command_line_input): Use STOP_SIGNAL not SIGTSTP. + + * stabsread.c: Remove most uses of lookup_fundamental_type. + (define_symbol): Use read_type for type of enum constant, + not just read_type_number. Also don't call error(). + (define_symbol): For unrecognized constant type, one complaint (the + one from error_type) is enough. Don't make our own in addition. + (define_symbol): Don't treat an N_FUN 'R' as a prototype. + * gdbtypes.h: Doc fixes. + +Sat May 22 03:33:07 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + Fix stack unwinding through _sigtramp on Irix. These patches are from + Paul Flinders . + * mipsread.c (fixup_sigtramp): Find _sigtramp on Irix even when the + executable uses sigvec. + * mips-tdep.c (read_next_frame_reg): Allow tm-file to override + sigcontext offsets. + * config/mips/tm-irix3.h: Add sigcontext offsets for Irix. + +Sat May 22 00:39:01 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (wait_for_inferior): Clear stop_signal if it should not + be passed to the inferior to make "handle nopass nostop" work. + +Sat May 22 00:21:41 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/tm-irix3.h: Clean up, use tm-bigmips.h and redefine + the necessary bits. + * findvar.c (value_from_register): Fix uninitialized first_addr + which caused problems with assignment of doubles to register variables + on some targets. + * mipsread.c: Remove TM_FILE_OVERRIDE, include tm.h and provide the + missing mips definitions if necessary. + + Fix handling of double register variables for mips targets and big + endian hosts. These patches are from Paul Flinders . + * config/mips/tm-mips.h: Increase MAX_REGISTER_{RAW,VIRTUAL}_SIZE to + 8 bytes for doubles. + * config/mips/tm-mips.h (REGISTER_CONVERT_TO_TYPE): New macro for + conversion of type held in multiple registers to host format. + * config/mips/tm-mips.h (REGISTER_CONVERT_FROM_TYPE): New macro, + companion to REGISTER_CONVERT_TO_TYPE. + * config/mips/tm-mips.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE): + Convert to function calls. + * config/mips/tm-mips.h (FIX_CALL_DUMMY): New code for big endian + mips targets. + * mips-tdep.c (mips_print_register): Raw buffer now needs just + MAX_REGISTER_RAW_SIZE bytes. + * mips-tdep.c (mips_print_register): Use REGISTER_CONVERT_TO_TYPE + (if defined) for doubles. + * mips-tdep.c: (mips_extract_return_value, mips_store_return_value): + New functions, take care of REGISTER_CONVERT_TO/FROM_TYPE. + * valops.c (value_assign): Use REGISTER_CONVERT_TO_TYPE if + defined. + * findvar.c (value_from_register): Use REGISTER_CONVERT_TO_TYPE if + defined. + +Fri May 21 09:04:25 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * configure.in: Add i[34]86-*-isc*. + + * stabsread.c: Make sure all complain() pass the address of the struct. + + * xcoffread.c: Make sure all struct complaints are static not auto. + + * Makefile.in: Add rule for xcoffexec.o like that for paread.o. + + * xcoffread.c (process_xcoff_symbol, case C_LSYM): Use define_symbol. + +Wed May 19 12:33:59 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/linux.mh: Re-enable coredumps now that they should work. + +Wed May 19 15:44:20 1993 K. Richard Pixley (rich@cygnus.com) + + * config/m68k/tm-m68k.h (FRAME_CHAIN): add missing close paren. + +Wed May 19 15:33:57 1993 Stu Grossman (grossman@cygnus.com) + + * config/pa/nm-hppab.h: Comment PTRACE_ARG3_TYPE. + +Wed May 19 12:33:59 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (INSTALLED_LIBS): New variable. + +Tue May 18 14:08:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (quit_command): In the "quit anyway?" message, tell the user + whether we are planning to detach or kill the program. + + * config/vax/vaxbsd.mh: Add "NAT_FILE= nm-vax.h". + * config/vax/xm-vaxbsd.h: Use not + + * infcmd.c (read_pc): Doc fix. + + * printcmd.c (print_address_symbolic): Use %u not %d for offset. + + * blockframe.c (get_prev_frame_info): If pc in sigtramp, set + signal_handler_caller. + * tm-68k.h (FRAME_{CHAIN,SAVED_PC}): Deal with sigtramp. + * tm-hp300bsd.h: Define SIGTRAMP_{START,END} not IN_SIGTRAMP. + * inferior.h (IN_SIGTRAMP): Definition moved from infrun.c. + Use SIGTRAMP_START if defined. + * infcmd.c (step_1): Use SIGTRAMP_{START,END} if needed. + * infrun.c (wait_for_inferior): Check IN_SIGTRAMP before SKIP_PROLOGUE. + + * infptrace.c: Remove unused KERNEL_U_ADDR_HPUX code. + + * infcmd.c (step_1): Fix poorly worded error message. + + * config/{i386/linux.mh,m68k/isi.mh} (NATDEPFILES): + Comment out corelow.c because core dumps are broken on these machines. + + * Makefile.in (depend): Put "${srcdir}" in generated dependencies + if srcdir is not ".". + Also put in -I${BFD_DIR} or -I${READLINE_DIR} for files which need it. + (INCLUDE_CFLAGS): Remove BFD_DIR and READLINE_DIR. + * depend: Update to latest automatically built version. + +Tue May 18 08:10:45 1993 Fred Fish (fnf@cygnus.com) + + * ChangeLog, ChangeLog-92: Split ChangeLog at 1993. + * Makefile.in (NONSRC): Add ChangeLog-92 + +Tue May 18 08:03:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * findvar.c ({read,write}_register): Use REGISTER_RAW_SIZE + not typo RAW_REGISTER_SIZE. + + * frame.h, inferior.h: Doc fixes. + +Mon May 17 15:43:03 1993 Stu Grossman (grossman@cygnus.com) + + * findvar.c (write_register): Add sanity check for register size. + (read_register): Fixup sanity check for register size to be + consistent with write_register(). + +Mon May 17 07:36:20 1993 Ian Lance Taylor (ian@cygnus.com) + + * sparclite/Makefile.in: Add dummy info, install and install-info + targets. + +Thu May 13 07:30:22 1993 Ian Lance Taylor (ian@cygnus.com) + + * remote-nindy.c: Removed declaration of coffstrip. + * nindy-share/nindy.c: #if 0 coffstrip routine; no longer used. + +Wed May 12 00:35:19 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.9.1 after release and cvs + tagging. + + * Makefile.in (VERSION): GDB 4.9 release. + +Tue May 11 08:04:41 1993 Fred Fish (fnf@cygnus.com) + + * README: Update known bugs to include the Solaris bug that + leaves core dumps in the current directory when restarting the + inferior with "run". Expand on the testsuite information. + + * Makefile.in (VERSION): Bump to 4.8.96 for what should hopefully + be the last 4.9 prerelease test archive. + +Mon May 10 22:13:23 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/m68k/xm-hp300bsd.h: Include to avoid INT_MAX + redefined warnings. + +Mon May 10 20:00:43 1993 Fred Fish (fnf@cygnus.com) + + * README, NEWS: Update for gdb 4.9 release. + +Mon May 10 19:38:34 1993 John Gilmore (gnu@cygnus.com) + + * ch-exp.y (MAX, MIN): Rename to MAX_TOKEN, MIN_TOKEN. + * target.c (MIN): #undef before defining. + +Mon May 10 16:03:03 1993 Jim Kingdon (kingdon@cygnus.com) + + Patch from Jeffrey Law: + * gdb/config/pa/nm-hppab.h (PTRACE_ARG3_TYPE): Define as caddr_t. + +Mon May 10 15:28:27 1993 Ian Lance Taylor (ian@cygnus.com) + + * hppa-tdep.c (hppa_push_arguments): Allocate correct amount of + memory. + +Mon May 10 13:14:46 1993 Fred Fish (fnf@cygnus.com) + + * ch-exp.y (start): Apply work-around to avoid bison warning. + +Sun May 9 07:25:02 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (BISON): Remove double quotes around BISON + definition when bison is used. + + * configure.in (hppa*-hp-bsd): Change to hppa*-hp-bsd* + * configure.in (hppa*-hp-hpux): Change to hppa*-hp-hpux* + * configure.in (m68*-hp-bsd): Change to m68*-hp-bsd* + * configure.in (m68*-hp-hpux): Change to m68*-hp-hpux* + * configure.in (hppa*-*-bsd): Change to hppa*-*-bsd* + * configure.in (hppa*-*-hpux): Change to hppa*-*-hpux* + * configure.in (m68*-hp-bsd): Change to m68*-hp-bsd* + * configure.in (m68*-hp-hpux): Change to m68*-hp-hpux* + + * Makefile.in (VERSION): Bump to 4.8.6. + +Sat May 8 12:36:03 1993 Fred Fish (fnf@cygnus.com) + + * config/pa/xm-hppah.h (MALLOC_INCOMPATIBLE): Define it, and + include declarations for malloc/realloc/free. Both malloc and + realloc return 'void *' for non-ANSI compilations. + +Sat May 8 01:39:30 1993 (pes@regent.e-technik.tu-muenchen.de) + + * coffread.c (read_coff_symtab): Don't fclose stream as it is no + longer opened twice. + +Thu May 6 21:08:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * solib.c (clear_solib): Don't close bfd if it is NULL. + +Thu May 6 20:55:35 1993 Fred Fish (fnf@cygnus.com) + + * core.c (dis_asm_read_memory): Cast second arg of + target_read_memory to "char *". + * breakpoint.c (watchpoint_check): Change arg type from PTR to + "char *", to match other functions called by catch_errors(). + +Thu May 6 15:47:45 1993 Stu Grossman (grossman@cygnus.com) + + * More patches from Jeffrey Law (law@cs.utah.edu). + * gdb/config/nm-hppab.h (PTRACE_ARG3_TYPE): Define as caddr_t. + * gdb/config/pa/tm-hppah.h (millicode_start, millicode_end): + Delete unnecessary declarations. + +Thu May 6 15:15:46 1993 Stu Grossman (grossman@cygnus.com) + + * ser-unix.c (wait_for): Use VTIME to do timeouts instead of + poll() for termio{s}. + +Thu May 6 10:03:41 1993 Jim Kingdon (kingdon@cygnus.com) + + * i386-tdep.c (i386_frame_num_args): Always return -1. + +Wed May 5 15:16:33 1993 Stu Grossman (grossman@cygnus.com) + + * Patches from Jeffrey Law . + * gdb/hppa-tdep.c: Declare frame_saved_pc. + (frameless_function_invocation): New function. + (frame_saved_pc, init_extra_frame_info): Use + frameless_function_invocation. + * gdb/config/pa/tm-hppa.h (SAVED_PC_AFTER_CALL): Use saved_pc_after + call instead of just grabbing the value currently in %r2. + (FRAMELESS_FUNCTION_INVOCATION): Use frameless_function_invocation. + * gdb/config/pa/tm-hppah.h (SAVED_PC_AFTER_CALL): Delete private + definition and use the common one in tm-hppa.h. + * gdb/hppa-tdep.c (frame_chain_valid): If "use_unwind" is true, then + use unwind descriptors to determine if the frame chain is valid. + * gdb/hppa-tdep.c (find_dummy_frame_regs): Rework so that + it does not assume %r4 is the frame pointer. + * gdb/hppa-pinsn.c (print_insn): Handle 'r' and 'R' for break, rsm, + and ssm instructions. + * gdb/hppa-tdep.c (extract_5r_store, extract_5R_store): New + helper functions for print_insn. + * gdb/hppa-tdep.c (gcc_p, hpux_cc_p): Delete unused functions. + * gdb/config/pa/tm-hppa.h (ABOUT_TO_RETURN): Handle a return + which nullifies the following instruction. + +Tue May 4 12:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * infptrace.c [FIVE_ARG_PTRACE]: Define ptrace to call_ptrace and + pass the 5th arg there, rather than using an ANSI C-specific macro. + + * Makefile.in (depend): Don't include ${CC} command for *.tab.c. + +Tue May 4 19:33:12 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.8.5 + * Makefile.in (INCLUDE_CFLAGS): Add BFD_DIR and READLINE_DIR + directories to include search path. + * Makefile.in (CLIBS, CDEPS, ADD_FILES, ADD_DEPS): Clean up + whitespace. + * Makefile.in (depend): For gcc -MM line, use INTERNAL_CFLAGS + * Makefile.in (main.o, dbxread.o, coffread.o, mipsread.o, + elfread.o, dwarfread.o, stabsread.o, xcoffread.o, xcoffexec.o, + xdr_ld.o, xdr_rdb.o, nindy.o, Onindy.o, ttybreak.o, ttyflush.o, + udr.o, udip2soc.o): Remove explicit rules, use the ones that + are automatically generated in "depend". + * Makefile.in (paread.o): Document why a dependency doesn't get + automatically generated in "depend" and leave this explicit rule + in for now (FIXME). + * depend: Update to latest automatically generated version. + +Tue May 4 12:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c: Doc fix. + + * Makefile.in (depend): Include $(CC) command in generated output. + +Mon May 3 22:51:05 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (NONSRC): Remove ${srcdir}/putenv.c. + * Makefile.in (SFILES): Add ${srcdir}/putenv.c. + * depend: Update to latest automatically built version. + +Mon May 3 19:20:20 1993 Stu Grossman (grossman@cygnus.com) + + * sparclite/Makefile.in: Create default target that does nothing + in order to force user to build by hand. + + * sparclite/Makefile: Remove. It's not necessary anymore. + + * ser-unix.c (wait_for): New routine to handle read timeouts, + etc. Uses poll() if HAVE_TERMIO[S] is defined, select() otherwise. + +Mon May 3 13:52:08 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips-pinsn.c (print_insn): Return value. + +Sun May 2 11:43:57 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (SFILES): Remove ser-hardwire.c; it is a link made + at configuration time and doesn't belong in the distribution archive. + + * Makefile.in (NONSRC): Add 29k-share/README. + * Makefile.in (HFILES): Add 29k-share/udi/udiids.h. + + * defs.h (UINT_MAX, LONG_MAX, INT_MAX, INT_MIN): Replace hex + constants with slightly more portable definitions (still depends + on 2's complement arithmetic though). + * config/i386/nm-linux.h: Define NO_SYS_REG_H for no . + * i386v-nat.c (sys/reg.h): Conditionalize include on + NO_SYS_REG_H. Linux doesn't have . + * ser-unix.c (termio.h): Include like other files that + include termio.h, not which may not exist (on + linux for example). + +Sat May 1 16:05:24 1993 Fred Fish (fnf@cygnus.com) + + * valprint.c (print_longest): Change format parameter from a + 'char' to an 'int'. We can't have 'char' parameters with the + current coding style, where we mix prototypes with pre-ANSI + style declarations. + * value.h (print_longest): Change format parameter in prototype + from a 'char' to an 'int'. + +Sat May 1 02:47:20 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/tm-mips.h (STAB_REG_TO_REGNUM): Match it with the gcc + definition. + * config/mips/tm-irix3.h (STAB_REG_TO_REGNUM): Add. + * irix4-nat.c (fill_fpregset): Fix bug with indexing into fpregsetp. + +Fri Apr 30 17:45:32 1993 Stu Grossman (grossman@cygnus.com) + + * The following patches are from Jeffrey Law . + * config/pa/hppabsd.mh: Add more files to NATDEPFILES. + * config/pa/xm-hppa[bh].h: Define FIVE_ARG_PTRACE. + * hppab-nat.c: Delete WANT_NATIVE_TARGET ifdefs. + ptrace needs 5 arguments, #define ptrace to always + pass zero as the 5th argument. + +Fri Apr 30 15:54:13 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * configure.in: Match z8k-*-sim for z8000. + * config/h8500/tm-h8500.h, h8500-tdep.c: Lint. + * remote-hms.c: Update to use new serial protocol. + +Fri Apr 30 16:50:38 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * mips-tdep.c: remove include of sys/dir.h. Doesn't seem + necessary and Solaris doesn't have it. + + * Makefile.in (clean-info, install, install-info, info, dvi, + check, all): do not echo recursion lines. + + * 29k-share/udip2soc.c (UDIConnect): replace union wait with int. + + * config/sparc/sun4sol2.mh (XM_CLIBS): add -lsocket which is + required target ports which use sockets (like a29k-udi). + + * remote-udi.c (udi_wait): Use SIGURG, as Solaris doesn't have SIGLOST. + +Fri Apr 30 11:05:42 1993 Jim Kingdon (kingdon@cygnus.com) + + * ser-unix.c [USE_{TERMIO,ALARM}_TIMEOUT]: New code to deal with + systems lacking select(). + + * Makefile.in (TAGS): Doc fix. Deal with empty DEPFILES. + +Fri Apr 30 10:06:46 1993 Fred Fish (fnf@cygnus.com) + + * alldeps.mak, depend: Update with latest automatically built + versions. + +Thu Apr 29 12:03:23 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (SFILES): Add ser-unix.c and ser-go32.c. + + * Makefile.in (make-proto-testsuite.dir): New target to make + prototype testsuite tree. + + * Makefile.in (VERSION): Bump to 4.8.4. + +Thu Apr 29 08:46:22 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabsread.c (define_symbol): If unrecognized constant type, + complain() not error(). + +Thu Apr 29 00:03:59 1993 Fred Fish (fnf@cygnus.com) + + * infptrace.c: Add missing close paren to test for + FIVE_ARG_PTRACE defined. + + * defs.h (CC_HAS_LONG_LONG): Set up to define CC_HAS_LONG_LONG + when compiling with gcc, but disable it for now. See comment. + * defs.h (LONGEST): Define as either "long" or "long long" + based on CC_HAS_LONG_LONG. + * defs.h (longest_to_int): Use CC_HAS_LONG_LONG to control + how longest_to_int is defined. + * c-valprint.c (c_val_print): Call print_longest. + * expprint.c (dump_expression): Use PRINTF_HAS_LONG_LONG + instead of LONG_LONG. + * {printcmd.c, gdbtypes.h} (LONG_LONG): Replace usages with + CC_HAS_LONG_LONG. + * printcmd.c (print_scalar_formatted): Call print_longest + and let it figure out what to do for PRINTF_HAS_LONG_LONG. + * typeprint.c (print_type_scalar): Call print_longest and let + it figure out what to do for PRINTF_HAS_LONG_LONG. + * valprint.c (val_print_type_code_int): Call print_longest + and let it figure out what to do for PRINTF_HAS_LONG_LONG. + * stabsread.c (LONG_LONG): Replace usages with CC_HAS_LONG_LONG. + * value.h (struct value): Replace usage of LONG_LONG with + CC_HAS_LONG_LONG. + * value.h (print_longest): Add prototype. + * values.c (LONG_LONG): Replace usages with CC_HAS_LONG_LONG. + * values.c (unpack_double): Collapse code that was unnecessarily + dependent on CC_HAS_LONG_LONG. Use LONGEST instead of direct types. + * values.c (value_from_longest): Remove dependency on + CC_HAS_LONG_LONG and just use LONGEST. + * solib.c (solib_map_sections): Use bfd_get_filename + to access filename field. + * solib.c (clear_solib): Save filename and free it later, after + bfd_close, since bfd_close may reference it. Use bfd_get_filename + to access the field. + * config/convex/xm-convex.h (LONG_LONG): Replace with + CC_HAS_LONG_LONG. Add define for PRINTF_HAS_LONG_LONG. + * doc/gdbint.texinfo (LONG_LONG): Replace with CC_HAS_LONG_LONG. + Add PRINTF_HAS_LONG_LONG references. + +Wed Apr 28 06:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * inflow.c (kill_command), infcmd.c (attach_command), + remote.c (remote_interrupt_twice): In messages for the user, call it + "the program" or "the program being debugged" not "the inferior". + + * hp300ux-nat.c: Cast second arg to supply_register calls. + (_initialize_kernel_u_addr, getpagesize): New functions. + (store_inferior_register_1): Change arg name from value to val. + (fetch_core_registers): Make arg core_reg_size unsigned. + Pass 5 args to ptrace. + * config/m68k/xm-hp300hpux.h: Define FIVE_ARG_PTRACE. + Remove KERNEL_U_ADDR stuff. + * infptrace.c [FIVE_ARG_PTRACE]: Pass 5th arg to ptrace. + * config/m68k/hp300hpux.m{t,h}: + Move exec.o from NATDEPFILES to TDEPFILES + * config/m68k/hp300hpux.mt: Mention GAS requirement. Remove + hp-include stuff. Add m68k-tdep.o to TDEPFILES. + +Wed Apr 28 13:27:54 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * ch-exp.y (yylex): Don't STREQ with simplename if it is NULL. + +Wed Apr 28 06:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/sparc/xm-sun4os4.h [__STDC__]: Don't use MALLOC_INCOMPATIBLE. + +Wed Apr 28 11:39:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * doc/gdb.texinfo: make node "Shell Commands" unconditional; + describe `set demangle-style arm' (not cfront); + mention can type `q' to discard output, when gdb pages + +Wed Apr 28 11:32:39 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valops.c (search_struct_field): Fix gdb core dump with incomplete + stabs info. + +Wed Apr 28 06:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * remote.c: Change timeout to 2. + (remote_open): Use unpush_target not remote_close. + (remote_resume): If siggnal != 0, give warning not error(). + (remote_wait, remote_interrupt, remote_interrupt_twice): + If we get two interrupts, let the user get out if they want. + (remote_{kill,mourn}): New functions. + i386-stub.c (handle_exception, case 'k'): Don't BREAKPOINT. + +Wed Apr 28 09:20:55 1993 Ian Lance Taylor (ian@rtl.cygnus.com) + + * config/sparc/sun4sol2.mh (XM_CLIBS): Define to be -lnsl. + +Wed Apr 28 06:11:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * Remote targets (mourn): Call unpush_target. + + * config/sparc/xm-sun4os4.h: Declare free() to return int. + Remove twisted use of PARAMS. + + * config/rs6000/xm-rs6000.h: Don't define MALLOC_INCOMPATIBLE now + that ansidecl.h assumes ANSI on AIX. + +Tue Apr 27 10:01:33 1993 Jim Kingdon (kingdon@cygnus.com) + + * README: Move most stuff about hacking GDB to doc/gdbint.texinfo. + (Known bugs): Remove AIX bugs, revise SPARC struct bug description. + +Tue Apr 27 13:44:19 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * expprint.c (print_subexp): Fix bug with OP_SCOPE operator output. + +Tue Apr 27 10:01:33 1993 Jim Kingdon (kingdon@cygnus.com) + + * remote-vx.c (net_connect): Allow numeric IP address for host. + +Mon Apr 26 17:59:38 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * config/sh/sh.mt, config/sh/tm-sh.h, sh-tdep.c: New files. + +Mon Apr 26 07:13:32 1993 Jim Kingdon (kingdon@cygnus.com) + + * rs6000-tdep.c (branch_dest): Deal with stepping through system call. + + * symtab.h, xcoffread.c: Revise linetable sorting comments. + +Sun Apr 25 02:32:16 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valops.c (value_cast): A cast might also change the object + representation in C++. + * dbxread.c (end_psymtab): Copy subpst read_symtab function from pst + to get the proper read_symtab function when called from mipsread.c. + * mipsread.c (mipscoff_psymtab_to_symtab, psymtab_to_symtab_1): + Set cur_bfd in psymtab_to_symtab_1 as CURBFD(pst) is invalid + for dummy psymtabs, inhibit processing of dummy psymtabs. + +Sat Apr 24 19:59:54 1993 Jim Kingdon (kingdon@cygnus.com) + + * Changes from (or inspired by) AMD: + * remote-udi.c (udi_attach): Assignments to Space and Offset were + switched, fix it. + (udi_wait): Make error message (UDIGetStdout) match error. + (udi_wait): Handle UDIStdinNeeded. + * command.c [CANT_FORK]: Use system(). + * utils.c (prompt_for_continue): Allow quit with 'q'. + + * solib.c (solib_add): Don't call special_symbol_handling if there + were errors in symbol_add_stub. Also set so->from_tty before + calling symbol_add_stub. + +Fri Apr 23 16:17:00 1993 Stu Grossman (grossman@cygnus.com) + + * Merge in HPPA/BSD patches from Utah: + * defs.h: Add const to 2nd arg of psignal prototype. + * hppah-tdep.c: Renamed to hppa-tdep.c 'cuz it's common code with + BSD now. + * hppab-core.c: Deleted. No longer useful. + * hppab-nat.c: #include more files. Use PT_WUREGS, not + PT_WRITE_U. + * hppab-tdep.c: Deleted. Supplanted by hppa-tdep.c. + * config/pa/hppabsd.mh (NATDEPFILES): Remove hppab-core.o. + * config/pa/hppabsd.mt (TDEPFILES): hppab-tdep.o => hppa-tdep.o + * config/pa/hppahpux.mt (TDEPFILES): hppab-tdep.o => hppa-tdep.o + * config/pa/xm-hppab.h: #define SET_STACK_LIMIT_HUGE. + +Fri Apr 23 10:34:02 1993 Stu Grossman (grossman@cygnus.com) + + * Fix two bugs found by deja-gnu. One is the incorrect reporting + of the PC being in a stack dummy when looking at a core file + without symbols. The other is the incorrect passing of char + arguments during expression evaluation (ie: p foo('a','b') would + mess up the passing of it's args because it wasn't coercing the + char's to ints). + * hppah-tdep.c: Rename global functions to have consistent hppa_ + prefix. Make more functions static. Drop hp_ prefix from static + functions. (hppa_push_arguments): Call value_arg_coerce to cast + char to int args if necessary. (hppa_fix_call_dummy): Create + this routine from FIX_CALL_DUMMY macro in tm-hppa.h. + * inferior.h (PC_IN_CALL_DUMMY): Check for frame_address being + valid (ie: != 0) before doing comparison against PC. + * valops.c (call_function_by_hand): Adjust call to FIX_CALL_DUMMY + to reflect new arguments. + * config/pa/tm-hppa.h (POP_FRAME, PUSH_ARGUMENTS): Use new hppa_ + prefix for func name. (FIX_CALL_DUMMY): Move code into + hppah-tdep.c. + + * testsuite/gdb.t16/gdbme.c, testsuite/gdb.t17/gdbme.c: Add calls + to malloc() so that we can test GDB eval of dynamically created + arrays (like char strings in `print "foo"'). + +Fri Apr 23 01:28:14 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * printcmd.c (print_address_symbolic): Search symtabs as well as the + minimal symbols for a nearby symbol. + +Thu Apr 22 19:44:21 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * coffread.c: Comment changes around minimal symbol recording. + +Thu Apr 22 16:24:36 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * command.c: comment changes only. + + * mips-tdep.c (heuristic_fence_post): new static variable. + (heuristic_proc_start): use heuristic_fence_post, print better + warnings, but only if not stop_soon_quietly. + (_initialize_mips_tdep): add_set_cmd for heuristic-fence-post. + +Thu Apr 22 14:50:05 1993 Jim Kingdon (kingdon@cygnus.com) + + * symtab.h: Fix LOC_REF_ARG comment. + +Wed Apr 22 20:21:30 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + and Jim Kingdon (kingdon@cygnus.com) + + * stabsread.c (define_symbol): Combine a 'p', 'r' arg pair to a + LOC_REGPARM symbol. + * config/sparc/tm-sparc.h (REG_STRUCT_HAS_ADDR): Revise comments. + symfile.c (compare_symbols): Don't check first character; STRCMP + does that. + + * stabsread.c (define_symbol): Generate a LOC_REGPARM_ADDR for + structures that are passed by address in a register. + * symtab.h (enum address_class): Add LOC_REGPARM_ADDR. + * findvar.c (read_var_value), + printcmd.c (address_info, print_frame_args), + stack.c (print_frame_arg_vars), symmisc.c (print_{,partial_}symbol), + * symtab.c (lookup_block_symbol): Deal with it. + +Thu Apr 22 09:07:24 1993 Jim Kingdon (kingdon@cygnus.com) + + * objfiles.h (obj_section), objfiles.c (build_objfile_section_table): + Add objfile field. + * objfiles.c (find_pc_section): Return a struct obj_section *. + * sparc-tdep.c (in_solib_trampoline): Deal with find_pc_section return. + * symfile.c (syms_from_objfile) [IBM6000_TARGET]: + Don't use obj_section hack. + * xcoffexec (vmap_symtab): Relocate obj_sections. + * printcmd.c (containing_function_bounds): Use find_pc_section. + + * symtab.h: Clean up SYMBOL_VALUE comments. + +Wed Apr 21 14:29:57 1993 Jim Kingdon (kingdon@cygnus.com) + + * stack.c (print_frame_arg_vars), printcmd.c (print_frame_args): + Expand comments about LOC_ARG/LOC_LOCAL pairs. + + * coffread.c (read_coff_symtab): Use rewind before fseek. + +Wed Apr 21 14:24:19 1993 Per Bothner (bothner@cygnus.com) + + * ch-exp.y: Removed unused structure_primitive_value and FIXME_23. + * Makefile.in: Add $(YFLAGS) when using $(YACC). + * Makefile.in: Remove message to expect conflicts and unused + rules in ch-exp.y, since there no longer are any such. + +Wed Apr 21 13:27:50 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * stabs.texinfo: fixed bad xrefs (un-initialized statics) + +Tue Apr 20 08:55:11 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffexec.c (xcoff_relocate_core): If no exec file, error() + rather than dumping core. + + * Makefile.in: Add ${srcdir}/ to all source files. + (alldeps.mak): Add "${srcdir}/" to files when generating alldeps.mak. + (TAGS): Deal with srcdir and new config directory scheme. + createtags: Remove. + Makefile.in (NONSRC): Remove createtags. + alldeps.mak: Updated. + + * rs6000-tdep.c: Delete unused function print_frame. + + * frame.h (struct frame_info): Doc fix for next_frame. + New field signal_handler_caller. + blockframe.c (create_new_frame, get_prev_frame_info), + config/rs6000/tm-rs6000.h (INIT_EXTRA_FRAME_INFO): Set it (needs + INIT_FRAME_PC_FIRST). + stack.c (print_frame_info), rs6000-tdep.c (rs6000_frame_chain): + Check it. + +Mon Apr 19 22:52:33 1993 Stu Grossman (grossman@cygnus.com) + + * irix4-nat.c (fetch_core_registers): Special version of this for + Irix 4.x, which stores regs a bit differently from other /proc + based systems. + * procfs.c, core-svr4.c: Move fetch_core_registers from procfs.c + to new file core-svr4.c. + * config/i386/i386sol2.mh, config/i386/i386v4.mh, config/m68k/amix.mh, + config/i386/ncr3000.mh, config/sparc/sun4sol2.mh: Add core-svr4.o + to NATDEPFILES. + * config/mips/irix4.mh: Add corelow.o to NATDEPFILES. + +Mon Apr 19 11:13:34 1993 Jim Kingdon (kingdon@cygnus.com) + + * i387-tdep.c: Remove unused #includes. + + * configure.in: Match i[34]86-*-sysv3.2 not i[34]86-*-sysv32. + + * config/i386/nm-i386v.h: Define NO_PTRACE_H. + +Sun Apr 18 10:39:35 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c: Nuke NO_DEFINE_SYMBOL code. There is no going back. + + * stabsread.c (define_symbol): 'R' is synonym for 'P', not 'r'. + xcoffread.c (process_xcoff_symbol, case C_RPSYM): + Don't muck with SYMBOL_CLASS. + +Fri Apr 16 17:38:33 1993 Stu Grossman (grossman@cygnus.com) + + * munch: Don't use head command. It doesn't exist everywhere. + +Fri Apr 16 15:07:57 1993 Fred Fish (fnf@cygnus.com) + + * inflow.c (new_tty): Remove spurious 'o' character at end + of #endif line. + +Fri Apr 16 12:27:11 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-tdep.c (mips_skip_prologue): Always skip the typical prologue + instructions and nothing more. + * mipsread.c (add_line): Add comment why we have to combine line number + entries for the same line number. + +Fri Apr 16 09:42:03 1993 Jim Kingdon (kingdon@cygnus.com) + + * symtab.{c,h}: Doc fixes (remove symseg references, last relevant + in gdb 2.8!). + +Thu Apr 15 21:16:58 1993 Fred Fish (fnf@cygnus.com) + + * depend, alldeps.mak: Update, now that gcc -MM bug is fixed. + +Thu Apr 15 12:38:39 1993 Jim Kingdon (kingdon@cygnus.com) + + * source.c (select_source_symtab): Clean up comment. Also, if + we have a current_source_symtab, and s is NULL, return without + doing anything. + xcoffread.c (xcoff_symfile_read): Don't call select_source_symtab. + breakpoint.c (breakpoint_re_set): Don't call select_source_symtab. + +Thu Apr 15 02:37:48 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * dbxread.c (unknown_symchar_complaint): Add new complaint. + * stabsread.h: Declare it. + * partial-stab.h: Use it. + + * utils.c (malloc_botch): Don't forward-declare if NO_MMALLOC. + +Wed Apr 14 17:12:51 1993 Jim Kingdon (kingdon@cygnus.com) + + * stack.c (print_frame_info): Print specially if dummy frame. + + * breakpoint.c: Add comments regarding within_scope future direction. + + * Version 4.8.3. + + * xcoffread.c (record_include_{begin,end}): Change fatal to complain. + +Wed Apr 14 14:03:18 1993 Per Bothner (bothner@cygnus.com) + + * ch-exp.y: Fix thinko that broke parsing of FALSE. + +Wed Apr 14 12:49:29 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * stabsread.c (read_member_functions): Initialize domain for stubbed + member functions to avoid gdb core dumps when printing pointers + to member functions. + * cp-valprint.c (cp_print_class_method): Check for stubbed member + functions. + +Tue Apr 13 08:28:26 1993 Jim Kingdon (kingdon@cygnus.com) + + * expprint.c (print_subexp): If opcode not found in op_print_tab, + stop with an error(). + eval.c (evaluate_subexp): Change error message. + + * objfiles.c (build_objfile_section_table): Cast return value + from obstack_finish. + +Mon Apr 12 10:53:50 1993 Jim Kingdon (kingdon@cygnus.com) + + * config/rs6000/tm-rs6000.h, rs6000-tdep.c: Move FRAME_CHAIN + to rs6000_frame_chain and deal with it if we're in a signal handler. + (FRAME_SAVED_PC): Use rs6000_frame_chain. + + * breakpoint.c (within_scope): New function. + (enable_breakpoint, watchpoint_check): Use it. + + * source.c (openp): Handle "exec-file ./ls" correctly. + + * breakpoint.c (breakpoint_1): Use wrap_here before "at". + +Sat Apr 10 01:32:43 1993 Per Bothner (bothner@rtl.cygnus.com) + + * ch-exp.y: Clean up lexing of identifiers and + reserved words. (E.g. don't recognize FALSEXXX as the + keyword FALSE followed by the identifier XXX.) + Also, convert identifiers to lower case. + +Fri Apr 9 15:53:19 1993 Stu Grossman (grossman@cygnus.com) + + * remote-mips.c, remote-monitor.c, remote-st2000.c: Convert to + new serial interface. + +Fri Apr 9 15:01:12 1993 Stu Grossman (grossman@cygnus.com) + + * remote.c (remote_open): Use SERIAL_OPEN instead of serial_open. + (putpkt, getpkt): Use new return codes for SERIAL_READCHAR. + * ser-go32.c: Return -1 on most failures, 0 on most successes, + and use new return codes for go32_readchar(). + * ser-unix.c: Ditto. Also, move error handling up to caller for + SERIAL_SETBAUDRATE(). + * serial.c (serial_open): Internal call, not SERIAL_OPEN to get + to specific routine. + (serial_close): New routine to wrap around device close routine. + serial.h: Clean & document return values more clearly. + +Fri Apr 9 10:20:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * rs6000-pinsn.c (print_operand): Deal with no operand instructions. + + * rs6000-pinsn.c (print_operand, case LI): Print condition register + operand in decimal rather than wrong textual versions. + + * printcmd.c (_initialize_printcmd): Clean up docstring for "x" + (mention 't', remove false thing about 'g' only good with 'f'). + + * breakpoint.h: move "struct breakpoint" and friends to top of + file so that bpstat_find_breakpoint prototype works. + + * solib.c (struct so_list): Add bfd field. + (solib_map_sections): Leave bfd open and scratch_pathname allocated. + Put the bfd in bfd field of the so_list. + (clear_solib): Free bfd name and close_bfd on the bfd. + +Fri Apr 9 00:45:41 1993 Per Bothner (bothner@rtl.cygnus.com) + + * valarith.c (value_subscript): Add COERCE_REF. + * ch-exp.y (operand_5): We can generalize the 2nd operand + of a string repetition ot 'literal' without ambiguity. + +Thu Apr 8 10:15:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.h (struct bpstat): Remove momentary field. + Remove bpstat_momentary_breakpoint. This was always kludgy + and is no longer used. + + * breakpoint.h: Add enum bpstat_what. + breakpoint.h (struct bpstat), breakpoint.c (bpstat_stop_status): + stop and print fields of bpstat now per-breakpoint, not just + one for the whole chain. + breakpoint.{c,h} (bpstat_what): New function. + breakpoint.h: Remove bpstat_stop and bpstat_should_print. + infrun.c: Replace switch (stop_bpstat->breakpoint_at->type) + with call to bpstat_what. + README: Remove watchpoint/breakpoint bug from known bugs. + + * breakpoint.h: Prototype bpstat_find_breakpoint. + +Thu Apr 8 16:01:21 1993 Fred Fish (fnf@cygnus.com) + + * symtab.c (find_methods, gdb_mangle_name): Note that functions + are g++ specific. + * symtab.h (VTBL_FNADDR_OFFSET, OPNAME_PREFIX_P, VTBL_PREFIX_P, + DESTRUCTOR_PREFIX_P): Note that macros are g++ specific. + +Thu Apr 8 12:45:32 1993 Ian Lance Taylor (ian@cygnus.com) + + * i960-pinsn.c (tabent): Copied struct definition from + opcodes/i960-dis.c. + +Thu Apr 8 10:34:37 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.h (DESTRUCTOR_PREFIX_P): New macro to check if physname + is a C++ destructor. + * symtab.c (gdb_mangle_name): Use it. + * symtab.c (find_methods): Do not add destructors to choice list + for constructors. + * symtab.c (decode_line_1): Make breakpoints on destructors work + for gcc-2.x again. + +Wed Apr 7 18:43:09 1993 Stu Grossman (grossman@cygnus.com) + + * ser-go32.c: Make it use serial port name. + * go32-xdep.c: Put in def for strlwr, needed by dir.o in go32 libc. + + * infcmd.c (read_pc): Make sure that we read PC_REGNUM when not + in a system call! + +Wed Apr 7 15:52:11 1993 Stu Grossman (grossman@cygnus.com) + + * configure.in: Only configure sparclite subdir when target_cpu + is sparclite. + +Wed Apr 7 10:11:22 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (struct coff_symbol): Change c_sclass to unsigned char. + Remove FIXME comment regarding this. + + * symfile.h: Change NULL->'\0' in comment (that wasn't a typo). + + * xcoffread.c (read_xcoff_symtab): Use E_SYMNMLEN. + +Tue Apr 6 22:30:58 1993 K. Richard Pixley (rich@cygnus.com) + + Add section table to objfile struct. Use it for find_pc_section. + * objfiles.c (add_to_objfile_sections, + build_objfile_section_table, find_pc_section): new functions. + (allocate_objfile): build section table. + * objfiles.h (struct obj_section): new structure. + (struct objfile): add section table. + (find_pc_section): new prototype. + * solib.[ch] (find_pc_section_from_so_list): removed. + * sparc-tdep.c: include objfiles.h for find_pc_section. include + symfile.h for objfiles.h. + (in_solib_trampoline): adjusted for new find_pc_section + prototype. Removed BAD_RICH_HACK ifdefs. + * symfile.c (syms_from_objfile): offset objfile sections. + (find_pc_section): removed. Also removed BAD_RICH_HACK ifdefs. + * symfile.h (find_pc_section): prototype removed. Also fixed + comment typo NUL -> NULL. + * target.[ch] (find_pc_section_from_targets): removed. + * config/sparc/tm-sun4sol2.h (BAD_RICHH_HACK): removed. + +Tue Apr 6 21:41:13 1993 Stu Grossman (grossman@cygnus.com) + + * ser-go32.c: Format. (go32_open): Use proper return value. + + * configure.in: Undo conditional configdirs hack for sparclite. + +Tue Apr 6 17:07:37 1993 Jim Wilson (wilson@sphagnum.cygnus.com) + + * symtab.c (list_symbols): When call break_command, pass both + filename and function name not just function name. + +Tue Apr 6 15:00:09 1993 Fred Fish (fnf@cygnus.com) + + (Changes and new files to make "none" a full fledged configuration) + * config/none/{nm-none.h, tm-none.h, xm-none.h}: New files. + Currently only tm-none.h has any meaningful contents. + * config/none/none.mh (NAT_FILE): Use nm-none.h + * config/none/none.mh (XM_FILE): Use xm-none.h + * config/none/none.mt (TM_FILE): Use tm-none.h + * Makefile.in (depend): Remove comment about parse errors in + valops.c, it now parses correctly and generates a correct depend + line. Remove line that touches xm.h, tm.h, and nm.h; they are + now linked to config/none/{xm-none.h, tm-none.h, nm-none.h}. + +Tue Apr 6 09:54:29 1993 Jim Kingdon (kingdon@cygnus.com) + + * values.c (USE_STRUCT_RETURN): Only use gcc wierdness for gcc1. + + * xcoffread.c (read_xcoff_symtab): Deal correctly with symbols of + exactly 8 characters. + +Tue Apr 6 10:31:26 1993 Stu Grossman (grossman@cygnus.com) + + * configure.in: Sparclite uses sparc config dir. Also has it's + own tm- & .mt files now. Also add sparclite to configdirs. + * go32-xdep.c: Dummy routines for sigsetmask & strlwr. + * config/i386/go32.mh: Nullify def of TERMCAP. + * config/i386/xm-go32.h: Get rid of redef of EIO. + * config/sparc/{sparclite.mh tm-sparclite.h}: New sparclite + specific configs. Very similar to sun4os4, but without solib. + * sparclite/{Makefile.in configure.in}: First cut at making this + dir configgable. + +Tue Apr 6 03:10:44 1993 Stu Grossman (grossman@cygnus.com) + + * ser-go32.c: First cut at adapting to new serial interface. + +Mon Apr 5 22:29:43 1993 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (SFILES OBS): Add serial.[co] & ser-hardwire.[co]. + These implement a new serial line interface for talking to remote + targets. + * configure.in: Link ser-hardwire.c to ser-unix.c for all hosts, + EXCEPT go32, which gets ser-go32.c. + * remote.c: Use new serial interface. More remote-xxx's to be + converted later. + * ser-bsd.c, ser-termios.c: Removed. + * serial.c: New. Implements common operations for all serial + types. + * ser-unix.c: New. Unix specific serial operations for various + flavors of Unix (Posix, SysV, BSD). + * serial.h: Generic serial interface defs. + * config/i386/go32.mh, config/i386/i386bsd.h, + config/m68k/apollo68b.mh, config/sparc/sun4os4.mh: Remove + ser-bsd.o from XDEPFILES. All the magic is now handled in + configure.in. + +Mon Apr 5 20:48:54 1993 Stu Grossman (grossman@cygnus.com) + + * config/h8500/tm-h8500.h: Clean up brain damage found by GCC. + +Fri Apr 2 08:23:14 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (xcoff_symfile_offsets): Use 0 not addr for offsets. + + * rs6000-tdep.c (frameless_function_invocation): Don't even think + about framelessness except on the innermost frame. + + * xcoffexec.c: Call fatal() not abort(). + + * stabsread.c (patch_block_stabs): If stab & no symbol, make + a LOC_OPTIMIZED_OUT symbol. + symtab.h (enum address_class): Add LOC_OPTIMIZED_OUT. + findvar.c (read_var_value), printcmd.c (address_info), + symmisc.c (print_{,partial_}symbol), c-exp.y (variable), + m2-exp.y (yylex): Deal with it. + ch-exp.y (yylex): Deal with it. + +Thu Apr 1 18:43:02 1993 Stu Grossman (grossman@cygnus.com) + + * findvar.c (value_from_register): H8500 specific, check to see + if we are looking at short pointer. If so, skip crock. + * h8500-tdep.c (h8500_frame_chain): Mask down value from + read_memory_integer() to avoid getting messed up by sign extension. + +Thu Apr 1 16:44:41 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * sparc-tdep.c (in_solib_trampoline), symfile.c (find_pc_section): + ifdef protect using BAD_RICH_HACK. This should be removed soon. + * config/sparc/tm-sun4sol2.h (BAD_RICH_HACK): define. + +Thu Apr 1 09:01:38 1993 Jim Kingdon (kingdon@cygnus.com) + + * i960-pinsn.c, a29k-pinsn.c: Much abridged, just use libopcodes.a. + + * core.c (dis_asm_print_address): New function. + + * core.c (dis_asm_read_memory): Reinstate 4th arg. The prototype + has been fixed. + +Thu Apr 1 09:34:43 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * breakpoint.c (bpstat_print, bpstat_stop_status): Change to walk the + entire breakpoint chain and print only the first entry that needs to + be printed and needs to be stopped for. Fixes problems with printing + of multiple breakpoints with different conditions. + * breakpoint.c (print_it_done): Renamed from print_it_noop as it + effectively stops printing of the breakpoint chain. + * breakpoint.c (print_it_noop): New routine to print nothing + for this breakpoint entry and dont stop printing. + * breakpoint.c (breakpoint_re_set_one): mention the reevaluated + watchpoint only if it is enabled. + * mipsread.c (parse_procedure): Correct incorrect setjmp procedure + descriptor from the library to make backtraces through setjmp work. + * mipsread.c (fixup_sigtramp): Correct pcreg and fregoffset for + sigtramp. + * mips-tdep.c (read_next_frame_reg): Provide correct values for + all registers saved within sigtramp, cleanup. + +Wed Mar 31 12:52:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc-pinsn.c: Much abridged, just calls version in libopcodes.a. + +Wed Mar 31 21:23:41 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * core.c (dis_asm_read_memory): drop fourth arg which conflicts + with prototype in ../include/dis-asm.h. + +Wed Mar 31 12:52:12 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * core.c (dis_asm_{read_memory,memory_error}): New functions. + m68k-pinsn.c, h8500-tdep.c, i386-pinsn.c, mips-pinsn.c, z8k-tdep.c: + Use read_memory_func interface to disassembler. + +Tue Mar 30 15:46:14 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + Teach sparc solaris to next over shared library functions. + * solib.[hc] (find_pc_section_from_so_list): new function and + prototype. + * sparc-tdep.c (in_solib_trampoline): new function. + * symfile.[hc] (find_pc_section): new function and prototypes. + * target.[hc] (find_pc_section_from_targets): new function and + prototypes. + * config/sparc/tm-sun4sol2.h (IN_SOLIB_TRAMPOLINE): redefine to + in_solib_trampoline. + +Tue Mar 30 08:06:24 1993 Jim Kingdon (kingdon@cygnus.com) + + * infrun.c (wait_for_inferior): Revise comment. + + * command.c (do_setshow_command): Use %u with var_{u,z}integer. + + * command.{c,h}: New var_type var_integer. + main.c: Use it for history_size. + + * rs6000-tdep.c, xcoffexec.c, config/rs6000/xm-rs6000.h, breakpoint.c: + Lint and byte-order fixups. + + * breakpoint.c (print_it_normal): Return 0 after hitting watchpoint. + + * breakpoint.h (bpstat): New field print_it. + breakpoint.c (bpstat_print): Use it. + (print_it_normal): New function (from old bpstat_print code). + (bpstat_{alloc,stop_status}): Set print_it field. + + * breakpoint.c (bpstat_stop_status): Use catch_errors when + evaluating watchpoint condition, via new function watchpoint_check. + Also stop if watchpoint disabled due to leaving its block. + + * findvar.c [REG_STRUCT_HAS_ADDR]: Add comment. + +Tue Mar 30 00:14:38 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-pinsn.c: Add missing include of dis-asm.h. + +Mon Mar 29 15:03:25 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (clean, distclean, realclean): Recursively apply + to subdirs first, rather than last. This avoids, for example, + Makefile being removed in a parent directory before the recursive + make is run. + + * alldeps.mak, depend: Update for below changes. + + * config/m68k/tm-m68k.h: Renamed from config/m68k/tm-68k.h. + * m68k/{tm-3b1.h, tm-altos.h, tm-amix.h, tm-es1800.h, + tm-hp300bsd.h, tm-hp300hpux.h, tm-isi.h, tm-news.h, tm-os68k.h, + tm-st2000.h, tm-sun2.h, tm-sun3.h, tm-vx68.h}: Include tm-m68k.h + instead of tm-68k.h. + * Makefile.in (HFILES): tm-68k.h renamed to tm-m68k.h. + * README, a29k-pinsn.c, m68k-pinsn.c, m68k-stub.c, remote-vx.c, + m68k/{altos.mh, altos.mt, apollo68b.mh, nm-apollo68b.h, + nm-hp300bsd.h, config/m68k/xm-apollo68b.h}: Map '68k' to 'm68k'. + * a29k/tm-a29k.h, doc/gdbint.texinfo: Account for renaming of + tm-68k.h to tm-m68k.h. + * m68k/m68k-fp.mt (TM_FILE): tm-68k-fp.h renamed to tm-m68k-fp.h. + * m68k/m68k-nofp.mt (TM_FILE): tm-68k-nofp.h renamed to + tm-m68k-nofp.h. + + * config/a29k/tm-a29k.h: Renamed from config/a29k/tm-29k.h. + * a29k-pinsn.c: Renamed from am29k-pinsn.c. + * a29k-tdep.c: Renamed from am29k-tdep.c. + * remote-eb.c, config/a29k/tm-ultra3.h: Include renamed tm-a29k.h. + * remote-monitor.c, remote-st2000.c, config/a29k/{nm-ultra3.h, + tm-a29k.h, xm-ultra3.h}, config/romp/rtbsd.mh, doc/gdbinv-s.texi, + testsuite/gdb.t15/funcargs.exp, testsuite/gdb.t17/callfuncs.exp: + Map '29k' to 'a29k'. + * config/a29k/{a29k-kern.mt, a29k-udi.mt, a29k.mt, ultra3.mt} + (TDEPFILES): Use renamed a29k-pinsn.o and a29k-tdep.o. + * config/a29k/{a29k-udi.mt, a29k.mt} (TM_FILE): Use renamed + tm-a29k.h. + * config/a29k/a29k-udi.mt (MT_CFLAGS): Remove TARGET_AM29K + define that does not appear anywhere else in the gdb source tree. + * doc/gdbinit.texinfo: Document renaming of tm-29k.h to tm-a29k.h. + +Mon Mar 29 13:55:29 1993 Jim Kingdon (kingdon@cygnus.com) + + * breakpoint.c: Add comments regarding breakpoint_re_set. + + * xcoffread.c (sort_syms, compare_symbols): Remove. + (xcoff_symfile_read): Use sort_all_symtab_syms from symfile.c + not our own sort_syms (it is identical). + + * xcoffread.c: Nuke NAMES_HAVE_DOT define (not used). + +Sun Mar 28 11:24:37 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * breakpoint.c (breakpoint_re_set_one): Fix storage leak. + * breakpoint.c (enable_breakpoint): Don't enable watchpoint if it + went out of scope. + * exec.c (exec_close): Fix storage leak. + * exec.c (exec_file_command): Make sure that bfd doesn't realign the + output sections when patching an executable. + * mips-nat.c (store_inferior_registers): Use REGISTER_PTRACE_ADDR + when writing all registers. + * mips-tdep.c (mips_push_dummy_frame): Save floating point registers + at the right offset in the dummy frame. + * mipsread.c (psymtab_to_symtab_1): Do not complain for stProc, + stStaticProc and stEnd symbols as they are generated by gcc-2.x. + * mipsread.c (mipscoff_new_init): Initialize stabsread and buildsym. + +Fri Mar 26 15:25:05 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (TARFILES): Avoid trailing backslash. + +Fri Mar 26 11:29:30 1993 Jim Kingdon (kingdon@cygnus.com) + + * breakpoint.{c,h}: Add exp_string to struct breakpoint and use + it in breakpoint_re_set. + * breakpoint.c (watch_command, enable_breakpoint): Fetch lazy values. + + * rs6000-tdep.c (single_step): Misc cleanups (CORE_ADDR not int, + don't use sizeof(int) for target stuff, etc). + +Thu Mar 25 15:03:53 1993 Fred Fish (fnf@cygnus.com) + + * alldeps.mak, configure.in, i860-break.h, i860-opcode.h, + i860-pinsn.c, i860-tdep.c, config/i860/*: Remove incomplete i860 + support that can't be integrated anyway due to lack of clear + authorship. + +Thu Mar 25 12:26:50 1993 Stu Grossman (grossman@cygnus.com) + + * findvar.c (read_register, write_register): Make these capable + of reading/writing registers that are shorter than REGISTER_TYPE. + * (value_from_register): Install H8500 specific code to return + proper value when register is being used as a pointer. + * h8500-tdep.c: Remove extra defines of NUM_REGS. + (h8500_skip_prologue): Use correct lengths for LINK instructions. + (FRAME_CHAIN): Change name to h8500_frame_chain. Rewrite code to + chain frames properly by combining frame pointer with T reg. + (init_extra_frame_info): Delete. It's now a macro. + (frame_args_address): Don't add PTR_SIZE. Stack args are already + offset by the correct amount off of the frame pointer. + (register_byte): Delete. It's now a macro. + (register_raw_size, register_virtual_size): Delete. Replaced by + common routine h8500_register_size, cuz there's no difference + between the raw & virtual sizes on this machine. + (register_convert_to_raw, register_convert_to_virtual): Delete, + cuz there's no difference between the raw & virtual forms. + Replaced by memcpy in tm file. + (register_virtual_type): Rename to h8500_register_virtual_type. + Get rid of pointer pseudo-regs, use _REGNUM with all reg names. + (_initialize_h8500_tdep): Get rid of crock to ensure that GDB & + emulator have same reg offsets. This is all handled in the + simulator code now. + (h8500_trapped_internalvar): New routine to detect references to + convenience vars acting as pointer pseudo-regs. + (h8500_value_trapped_internalvar): Conjure up value of pointer + pseudo-regs. + (h8500_set_trapped_internalvar): Convert set value in real + register references. + infcmd.c (read_pc, write_pc): Add h8500 specific code to handle + code segment register. + infrun.c (proceed): Simplify. Call write_pc instead of doing it + by hand. + (wait_for_inferior): Add h8500 specific code to add stack segment + when reading SP register. + remote-sim.c (fetch_register): Spacing. + tm-h8500.h: #define GDB_TARGET_IS_H8500 to make it easier to + detect cruft. Redo all register manipulation stuff. Get rid of + pointer pseudo-regs. (INIT_EXTRA_FRAME_INFO): Adds stack segment + to frame pointer. (IS_TRAPPED_INTERNALVAL, + VALUE_OF_TRAPPED_INTERNALVAR, SET_TRAPPED_INTERNALVAR): Use these + to create internal vars for pointer pseudo-regs. + +Thu Mar 25 10:10:28 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in: Numerous small changes to macro definitions + and rules for building gdb distribution tree. Many macros + eliminated or merged, and rules simplified. + * alldeps.mak: Update. + * depend: Update. + +Wed Mar 24 13:52:29 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: recurse through SUBDIRS for dvi target too + +Wed Mar 24 08:48:30 1993 Jim Kingdon (kingdon@cygnus.com) + + * Clean up xcoff relocation. + objfiles.h (struct objfiles): Add section_offsets, num_sections. + symfile.c (syms_from_objfile), xcoffread.c (xcoff_symfile_offsets): + Set them. + symtab.h (struct general_symbol_info): Add section field. + minsyms.c (prim_record_minimal_symbol{,_and_info}): Set it. + xcoffread.c: Set section for symbols and msymbols. + (struct symtab): Add block_line_section field. + buildsym.c (end_symtab): Set it. + (end_symtab and callers): Add section parameter. + objfiles.c (objfile_relocate): New funciton. + xcoffexec.c (vmap_symtab): Use it. + xcoffsolib.h (struct vmap): Remove unused fields. + config/rs6000/tm-rs6000.h, stack.c, xcoffexec.c: Remove + CORE_NEEDS_RELOCATION, symtab_relocated. + config/rs6000/tm-rs6000.h: Remove use of loadinfotext. + rs6000-tdep.c: Make loadinfotext static. + breakpoint.c (fixup_breakpoints): Doc fix. + symtab.h (struct symtab), config/rs6000/tm-rs6000.h, buildsym.c + (end_symtab): primary field replaces nonreloc. + +Tue Mar 23 00:10:53 1993 John Gilmore (gnu@cygnus.com) + + * symtab.h (struct linetable_entry): Remove confusing comment. + +Tue Mar 23 00:01:23 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: add installcheck target + +Mon Mar 22 16:17:58 1993 Fred Fish (fnf@cygnus.com) + + * config/{a29k, arm, convex, gould, h8300, i386, i860, i960, m68k, + m88k, mips, none, ns32k, pa, pyr, romp, rs6000, sparc, tahoe, vax, + z8k}: New directories to hold cpu specific configuration files. + Naming follows gcc convention. + * config/{*.mt, *.mh}: All target and host makefile fragment + config files moved to an appropriate config/ subdirectory. + * nm-*, xm-*, tm-*: All native, host, and target files, which + get linked to nm.h, xm.h, and tm.h respectively by configure, + moved to appropriate config/ subdirectory. + * nm-sysv4.h, xm-sysv4.h, tm-sysv4.h, tm-sunos.h, nm-trash.h: + Native, host, and target files that are common across more than + one cpu architecture and included by one of the configured + native, host, or target files, get moved to config directory. + * Makefile.in (INCLUDE_CFLAGS): Add -I${srcdir}/config to + pick up native, host, or target include files moved to one of + the config subdirectories, and that are included by other files. + * Makefile.in (alldeps.mak): Modify to account for new config + directory structure. + * alldeps.mak, depend: Update for new config directory structure. + * config/*/[ntx]m-*.h: Modify all files that include other + [ntx]m-*.h files to use path relative to gdb/config. I.E. + "a29k/tm-ultra3.h" includes "a29k/tm-29k.h" rather than just + "tm-29k.h". + * remote-eb.c (tm-29k.h): Include a29k/tm-29k.h. + * mipsread.c (tm-mips.h): Include mips/tm-mips.h. + * i860-pinsn.c (tm-i860.h): Include i860/tm-i860.h. + * configure.in: Default gdb_host_cpu to host_cpu, and remap + the ones where the default is not unique or different than the + config subdirectory name. Similarly, handle gdb_target_cpu. + Modify configure.in as appropriate to make use of gdb_host_cpu + and gdb_target_cpu to find makefile fragments and make links. + +Mon Mar 22 12:36:24 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c (compare_blocks): Sort blocks with the same start + address by decreasing ending address. + +Mon Mar 22 20:36:04 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mipsread.c (parse_procedure): Save cur_fdr accross call to + lookup_symbol as it might get clobbered by the call. + + * mipsread.c (parse_partial_symbols): Use ADD_PSYMBOL_ADDR_TO_LIST. + The previous code did not initialize the language field for the psymtab + entry. + +Sat Mar 20 00:33:39 1993 John Gilmore (gnu@cygnus.com) + + * c-exp.y (parse_number): Avoid shift warning. + * serial.h (struct ttystate): Declare empty one on DOS. + +Fri Mar 19 12:59:50 1993 Stu Grossman (grossman@cygnus.com) + + * xm-sun4os4.h: Return type of free() should be void, not int. + + * vx-share/vxWorks.h: Remove #def of NULL. + +Fri Mar 19 11:28:18 1993 Jim Kingdon (kingdon@cygnus.com) + + * tm-rs6000.h: Nuke no-op STAB_REG_TO_REGNUM. + +Fri Mar 19 07:40:09 1993 Steve Chamberlain (sac@cygnus.com) + + * z8k-tdep.c (print_insn): Include the new dis-asm header file. + +Thu Mar 18 14:26:57 1993 Per Bothner (bothner@rtl.cygnus.com) + + * ieee-float.c: Moved to ../libiberty. + * ieee-float.h: Moved to ../include. + * Makefile.in: Update accordingly. + * i386-pinsn.c (print_insn), m68k-pinsn.c (print_insn): + Convert to stubs that call disassemblers in ../opcodes/*-dis.c. + * m68k-tdep.c: Removed definition of ext_format ext_format_68881; + it is now in ../opcodes/m68881-ext.c. + * mips-tdep.c (mips_skip_prologue): Try to skip more of the + prologue (some callers _do_ care). + * mips-pinsn.c (print_insn), z8k-tdep.c (print_insn): Convert to + new interface of ../opcodes/*-dis.c. + * ch-exp.y: Add #include . + +Thu Mar 18 11:57:49 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffexec.c (exec_close): Don't close exec_bfd twice. + + * xcoffread.c (enter_line_range): endaddr is exclusive, not inclusive. + +Wed Mar 17 09:46:31 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (arrange_linetable): Use x{m,re}alloc not {m,re}alloc. + +Wed Mar 17 11:28:11 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8k-tdep.c (extract_return_value, write_return_value, + store_struct_return): New functions from macros in tm-z8k.h. + +Wed Mar 17 11:23:06 1993 Fred Fish (fnf@cygnus.com) + + * valops.c (value_arg_coerce): Apply temporary patch to + fix problem with coercion of array and function types when + passed as arguments to C functions, pending a more complete + review of when and how coercion should be done, depending + upon context and language. + +Wed Mar 17 09:46:31 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (MIN_TBTABSIZ): Change to 12. + + * xcoffread.c (xcoff_symfile_read): Only read stringtab and + debugsec if there are a non-zero number of symbols. + +Tue Mar 16 18:08:45 1993 John Gilmore (gnu@cygnus.com) + + * command.c (show_user): Avoid fprintf_filtered botch (AGAIN!). + +Tue Mar 16 15:18:17 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffexec.c (add_vmap): Wrap symbol read in catch_errors. + + * xcoffread.c (read_symbol_lineno): Look to end of symbols for .bf, + not just 50 symbols. + (symtbl_num_syms): New variable. + (read_xcoff_symtab): Set it. + (read_symbol_nvalue): Check for bad symno. + (read_symbol_{lineno,nvalue}, callers): Don't pass symtable; it's + always symtbl. + +Tue Mar 16 10:09:05 1993 Stu Grossman (grossman@cygnus.com) + + * config/rs6000.mh: Get rid of -Dfd_set=int crock. + This is defined in defs.h if necessary. + * vx-share/vxWorks.h: Remove #defs of min and max. + * vx-share/xdr_ld.c, vx-share/xdr_ptrace.c, + vx-share/xdr_rdb.c: include defs.h. + +Fri Mar 12 09:33:23 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (retrieve_tracebackinfo): Move assignment out + of while condition. + + * xcoffread.c (enter_line_range): complain() on bad endoffset. + xcoffread.c: Doc fixes. + +Tue Mar 9 09:56:12 1993 Jim Kingdon (kingdon@cygnus.com) + + * tm-rs6000.h (CORE_NEEDS_RELOCATION): Just call xcoff_relocate_core. + xcoffexec.c (xcoff_relocate_core): New function. + (text_adjustment): Removed. + (add_vmap): Return the vmap. + rs6000-tdep.c (add_text_to_loadinfo): No longer static. + +Fri Mar 5 05:22:46 1993 Jim Kingdon (kingdon@cygnus.com) + + * xcoffsolib.h: Add objfile member to struct vmap. + xcoff{exec,solib}.c: Use it, not lookup_objfile_bfd. + xcoffexec.c (add_vmap): Allocate objfiles here. + +Sun Mar 14 02:54:15 1993 John Gilmore (gnu@cygnus.com) + + Support 68000 series without floating point. + + * configure.in (m68000-*-{aout,elf,coff}): New configs. + * tm-68k-nofp.h: New file, lacks 68881 support. + * config/m68k-nofp.mt: New file. + +Sun Mar 14 02:30:08 1993 John Gilmore (gnu@cygnus.com) + + Remove a few remaining underscore/no-underscore remnants from + config files. + + * config/{m68k-un.mt, sparc-un.mt}: Remove. + * config/m68k-noun.mt: Rename to m68k-fp.mt. + * config/sparc-noun.mt: Rename to sparc-em.mt. + * tm-68k-noun.h, tm-spc-noun.h: Remove. + * tm-68k-un.h: Rename to tm-68k-fp.h. + * tm-spc-un.h: Rename to tm-spc-em.h. + * tm-sun4sol2.h: Cleanup. + * configure.in (m68k-*, sparc-* targets): Corresponding changes. + +Sat Mar 13 14:58:22 1993 John Gilmore (gnu@cygnus.com) + + * symmisc.c (std_in, std_out, std_err): Move initializations + to runtime code, in case they aren't constant. + +Fri Mar 12 16:23:54 1993 K. Richard Pixley (rich@cygnus.com) + + * symtab.c (find_pc_symtab): some object file formats, notably + mips, have holes in the address ranges of symtabs. Change + this algorithm from first hit to tightest fit. + + * mips-tdep.c (heuristic_proc_start): if we walk the pc into the + fence post without finding the enclosing function, then print a + warning. + +Thu Mar 11 09:33:01 1993 Fred Fish (fnf@cygnus.com) + + * utils.c (fputs_demangled, fprint_symbol): Remove. + * utils.c (fprintf_symbol_filtered): New function which combines + the functionality of fputs_demangled and fprint_symbol. Uses a + caller provided language parameter to select the appropriate + demangler, and caller provided args to pass to the demangler. + * defs.h (enum language): Move further up in file so enum can + be used in prototypes. + * defs.h (fputs_demangled, fprint_symbol): Remove prototypes. + * defs.h (fprintf_symbol_filtered): Add prototype. + * c-typeprint.c (cp_type_print_method_args): Replace calls to + fputs_demangled with call to fprintf_symbol_filtered. + * cp-valprint.c (demangle.h): Include + * cp-valprint.c (cp_print_value_fields): Replace calls to + fprint_symbol with calls to fprintf_symbol_filtered. + * printcmd.c (print_frame_args): Replace call to fprint_symbol + with call to fprintf_symbol_filtered. + * stack.c (print_frame_info): Remove obsolete code so we don't + have to update fputs_demangled usage in it. + * stack.c (print_frame_info, frame_info): Add language variable + to pass to fprintf_symbol_demangled and initialize it from the + symbol's language. Replace calls to fputs_demangled with calls + to fprintf_symbol_filtered. + * symtab.c (find_methods): Replace call to fputs_demangled with + call to fprintf_symbol_filtered. + * ch-valprint.c (demangle.h): Include. + * ch-valprint.c (chill_print_value_fields): Replace call to + fprint_symbol with call to new fprintf_symbol_filtered. + +Wed Mar 10 17:37:11 1993 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump version to 4.8.2. + + * main.c (source_command): Require an explicit pathname of file + to source, since previous behavior of defaulting to gdb init file + was troublesome and undocumented. + * printcmd.c (disassemble_command): Add missing '{}' pair to + else with two statements. Bug reported by Stephane Tsacas + . + * symtab.c (find_pc_line): Don't complain about zero length or + negative length line numbers for the moment, since we may not own + the terminal when called, such as when single stepping. (FIXME) + * language.h (CAST_IS_CONVERSION): True if current language is + C++ as well as C. Fix from Peter Schauer. + * environ.c (get_in_environ, set_in_environ, unset_in_environ): + Use STREQN macro rather than bare '!strncmp()'. + * environ.c (unset_in_environ): Avoid use of memcpy on + overlapping memory regions, as suggested by Paul Eggert + . + * c-exp.y (%union struct): Remove unused ulval as suggested + by Paul Eggert . + +Mon Mar 8 19:03:06 1993 Fred Fish (fnf@cygnus.com) + + * main.c (gdbinit): Make static. + * main.c (inhibit_gdbinit): Move to file scope. + * main.c (main): Remove local inhibit_gdbinit. + * main.c (source_command): Don't source '.gdbinit' file by + default if gdb has been told to ignore it. + +Sun Mar 7 21:58:53 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in (MAKEOVERRIDES): Define to be empty for GNU Make + 3.63. + +Fri Mar 5 17:39:45 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * printcmd.c (print_address_symbolic): Only print if offset + is shorter than max_symbolic_offset. + (initialize_printcmd): `set print max-symbolic-offset'. + + * am29k-tdep.c (TAGWORD_ZERO_MASK): New #define. + (examine_tag): Use it. + (read_register_stack): Only look in the local registers for a + memory address if it's between rfb and rsp; go to memory otherwise. + (initialize_29k): Fix call_scratch_address doc. Remove reginv_com. + (reginv_com): Remove ancient kludge command. + +Fri Mar 5 17:16:26 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * tm-irix3.h (ZERO_REGNUM): copy this macro from tm-mips.h so that + irix4 will again compile. + + * tm-mips.h (GDB_TARGET_IS_MIPS): no longer used, now removed. + + * configure.in: accept mips-sgi-irix4* for irix4. + +Fri Mar 5 07:49:48 1993 Steve Chamberlain (sac@lisa.cygnus.com) + + * z8k-tdep.c (print_register_hook): Lint. + +Thu Mar 4 17:42:03 1993 John Gilmore (gnu@cygnus.com) + + Lint fixes from Paul Eggert (eggert@twinsun.com): + + * command.c (do_setshow_command): var_uintegers are unsigned. + * sparc-tdep.c (save_insn_opcodes, restore_insn_opcodes): + unsigned, since they use hex values with the high bit set. + +Thu Mar 4 08:22:55 1993 Fred Fish (fnf@cygnus.com) + + Fixes submitted by Karl Berry (karl@nermal.hq.ileaf.com): + * m88k-pinsn.c (sprint_address): Use SYMBOL_NAME macro to + access symbol name. + * m88k-nat-c (SXIP_OFFSET, SNIP_OFFSET, SFIP_OFFSET): Enclose + macro definitions in parenthesis. + + * dbxread.c (dbx_symfile_init): Catch the case where there is + no string table, but the only way we find out is by reading zero + bytes from EOF. + +Wed Mar 3 15:51:28 1993 Fred Fish (fnf@cygnus.com) + + * dbxread.c (dbx_symfile_init): Make size of the string table + size field a define (DBX_STRINGTAB_SIZE_SIZE). Ensure that the + offset to the string table is nonzero and handle the nonexistant + string table case, should it occur. Ensure that the string table + size read from the file is reasonable, with a minimum lower bound + of DBX_STRINGTAB_SIZE_SIZE instead of zero. + +Wed Mar 3 07:23:03 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: Changes to build testsuite correctly. + (FLAGS_TO_PASS): Added CXX and CXXFLAGS. + (CC_FOR_TARGET, CXX, CXX_FOR_TARGET): New variables. + (TARGET_FLAGS_TO_PASS): New variable. + (SUBDIRS): Added testsuite. + (all): Build testsuite using TARGET_FLAGS_TO_PASS, so that + testsuite is compiled with CC_FOR_TARGET rather than CC. + +Tue Mar 2 17:57:56 1993 Fred Fish (fnf@cygnus.com) + + * dbxread.c (dbx_symfile_init): Fix for nonexistant string table, + reported by mycroft@gnu.ai.mit.edu. + + (Ultrix 2.2 support from Michael Rendell ) + * configure.in (vax-*-ultrix2*): New triplet. + * config/vaxult2.mh: New file. + * xm-vaxult2.h: New file. + + * c-exp.y (parse_number): Change high_bit to unsigned. + * demangle.c: Change all references to cfront to ARM, since the + actual algorithm is the one specified in the Annotated Reference + Manual. This was confusing users into thinking that full cfront + support was implemented. + * dwarfread.c (CFRONT_PRODUCER): Remove, was never really used. + * eval.c (evaluate_subexp): For STRUCTOP_PTR pass the arg type + directly to lookup_struct_elt_type, which will do the + dereferencing itself. + * gdbtypes.c (lookup_struct_elt_type): Expand comments. Fix + NULL dereferencing bug for unnamed structs, comment out + questionable code. + +Mon Mar 1 17:54:41 1993 John Gilmore (gnu@cygnus.com) + + * coffread.c (process_coff_symbol): Change PCC argument correction + so that it only happens on big-endian targets; so that it only + happens if the short or char argument is aligned on an int + boundary; and so that it changes the location, rather than the + type, of the argument. These changes tend to parallel similar + (old) changes in stabsread.c. + + * coffread.c (coff_read_enum_type): Use the specified size for + enums, don't assume that they are int-sized. + + * c-valprint.c (c_val_print): Don't assume enums are the same as + ints. + + * coredep.c: Handle NO_PTRACE_H in coredep.c. Fix by Michael + Rendell, . + +Mon Mar 1 09:25:57 1993 Fred Fish (fnf@cygnus.com) + + * language.h (local_decimal_format_custom): Add prototype. + * language.c (local_decimal_format_custom): Add function, bug + reported by Robert R. Henry (rrh@tera.com). + +Fri Feb 26 18:33:18 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * xcoffexec.c (vmap_ldinfo): Fix "/" for '/' typo, reported + by Josef Leherbauer, joe@takeFive.co.at. + +Wed Feb 24 19:17:11 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * symfile.c (syms_from_objfile), tm-29k.h, tm-3b1.h, tm-68k-un.h, + tm-altos.h, tm-arm.h, tm-convex.h, tm-es1800.h, tm-h8300.h, + tm-hp300bsd.h, tm-hp300hpux.h, tm-hppa.h, tm-i386bsd.h, + tm-i386v.h, tm-i960.h, tm-irix3.h, tm-isi.h, tm-linux.h, + tm-m88k.h, tm-merlin.h, tm-mips.h, tm-news.h, tm-np1.h, tm-pn.h, + tm-pyr.h, tm-rs6000.h, tm-spc-un.h, tm-sun386.h, tm-sunos.h, + tm-symmetry.h, tm-sysv4.h, tm-tahoe.h, tm-umax.h, tm-vax.h, + tm-vx68.h, tm-z8k.h: Remove remnants of NAMES_HAVE_UNDERSCORE. + +Wed Feb 24 07:41:15 1993 Fred Fish (fnf@cygnus.com) + + * symtab.h (SYMBOL_INIT_DEMANGLED_NAME): Initialize contents + of demangled name fields to NULL if no demangling exists for + a symbol. SYMBOL_INIT_LANGUAGE_SPECIFIC does this for new + symbols if their language is known at the time they are created, + but sometimes the language is not known until later. + + * ch-typeprint.c (chill_print_type_base): Name changed to + chill_type_print_base to match pattern for C and C++ names. + * ch-typeprint.c (chill_print_type): Change "char" to "CHAR" + to be consistent with other usages. + * ch-typeprint.c (chill_type_print_base): Add support for + printing Chill STRUCT types. + * ch-valprint.c: Include values.h. + * ch-valprint.c (chill_print_value_fields): New function and + prototype for printing Chill STRUCT values. + * ch-valprint.c (chill_val_print): Fix call to val_print_string + that was being called with two args instead of three. + * ch-valprint.c (chill_val_print): Call chill_print_value_fields + to print Chill STRUCT values. + +Tue Feb 23 18:58:11 1993 Mike Werner (mtw@poseidon.cygnus.com) + + * configure.in: added testsuite to configdirs. + +Tue Feb 23 11:46:11 1993 Mike Stump (mrs@cygnus.com) + + * doc/stabs.texi: The `this' pointer is now known by the name + `this' instead of `$t'. + +Tue Feb 23 11:21:33 1993 Fred Fish (fnf@cygnus.com) + + * dwarfread.c (read_tag_string_type): Rewrite to allow forward + references of TAG_string_type DIEs in user defined types. + * ch-lang.c (chill_create_fundamental_type): Track compiler + change that now emits debugging info with the type long for Chill + longs. + +Mon Feb 22 15:21:54 1993 Ian Lance Taylor (ian@cygnus.com) + + * remote-mips.c: New file; implements MIPS remote debugging + protocol. + * config/idt.mt: New file; uses remote-mips.c + * configure.in (mips-idt-ecoff): New target; uses idt.mt. + + * mips-tdep.c (mips_fpu): New variable; controls use of MIPS + floating point coprocessor. + (mips_push_dummy_frame): If not mips_fpu, don't save floating + point registers. + (mips_pop_frame): If not mips_fpu, don't restore floating point + registers. + (_initialize_mips_tdep): New function; let the user reset mips_fpu + variable. + * tm-mips.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE): If not + mips_fpu, don't use fp0 as floating point return register. + (FIX_CALL_DUMMY): If not mips_fpu, don't save floating point + registers. + +Mon Feb 22 07:54:03 1993 Mike Werner (mtw@poseidon.cygnus.com) + + * gdb/testsuite: made modifications to testcases, etc., to allow + them to work properly given the reorganization of deja-gnu and the + relocation of the testcases from deja-gnu to a "tool" subdirectory. + +Sun Feb 21 10:55:55 1993 Mike Werner (mtw@poseidon.cygnus.com) + + * gdb/testsuite: Initial creation of gdb/testsuite. + Migrated dejagnu testcases and support files for testing nm to + gdb/testsuite from deja-gnu. These files were moved "as is" + with no modifications. This migration is part of a major overhaul + of dejagnu. The modifications to these testcases, etc., which + will allow them to work with the new version of dejagnu will be + made in a future update. + +Fri Feb 19 18:36:55 1993 John Gilmore (gnu@cygnus.com) + + * NEWS: Add reminders for next release. + +Fri Feb 19 10:01:39 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c (parse_lines): Correct check for files compiled with + -g1. + +Fri Feb 19 05:56:15 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (VERSION): 4.8.1 to distinguish local versions. + +Fri Feb 19 01:32:58 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (VERSION): GDB-4.8 release! + * README, NEWS: Update for release. + +Thu Feb 18 22:44:40 1993 Stu Grossman (grossman@cygnus.com) + + * am29k-pinsn.c (print_insn): Minor nits with const. + * am29k-tdep.c: More minor nits with arg types for + supply_register, NULL vs. 0, read_register_gen, & reginv_com. + +Thu Feb 18 22:38:03 1993 John Gilmore (gnu@cygnus.com) + + * gcc.patch: Update for a different GCC (G++) bug. + * main.c (print_gdb_version): Update copyright year to 1993. + * nm-hp300bsd.h: Decide whether this is BSD 4.3 or 4.4, + conditionalize this file on it. FIXME, right way is to split + these into two config files. + (ATTACH_DETACH): Define for BSD 4.4 + (PTRACE_ARG_TYPE): caddr_t for BSD 4.4, unset for 4.3. + (U_REGS_OFFSET): Revise for 4.4. + (REGISTER_U_ADDR): Separate for 4.4, but it doesn't work yet. + * xm-hp300bsd.h: Move definitions of UINT_MAX, INT_MAX, INT_MIN, + LONG_MAX into this file to avoid cpp "redefinition" warnings. + +Thu Feb 18 16:13:28 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * nm-hp300bsd.h (PTRACE_ARG3_TYPE): FSF's hp300's have int* not + caddr_t. + +Thu Feb 18 04:10:06 1993 John Gilmore (gnu@cygnus.com) + + * c-lang.c (c_printstr): Bugfix for length==0 case. + + * c-lang.c (c_printstr): If a C string ends in a null, don't + print the null. + +Thu Feb 18 02:39:21 1993 Stu Grossman (grossman at cygnus.com) + + * defs.h (STRCMP): Make it work for unsigned chars. + +Thu Feb 18 01:56:06 1993 John Gilmore (gnu@cygnus.com) + + * nm-hp300bsd.h (ATTACH_DETACH, PTRACE_ATTACH, PTRACE_DETACH): define. + * config/hp300bsd.mh (REGEX, REGEX1): Define. + * m68k-pinsn.c (BREAK_UP_BIG_DECL, AND_OTHER_PART): #if __GNUC__, + define to kludge the large opcode table into two smaller tables, + since GCC take exponential space to build the table. Lint. + (NOPCODES): Remove, use "numopcodes" from opcode/m68k.h instead. + +Wed Feb 17 19:24:40 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (VERSION): Roll to 4.7.9. + * xm-hp300bsd.h: Define PSIGNAL_IN_SIGNAL_H and put a compatible + definition here, to handle both BSD 4.3 and 4.4 systems. + * mipsread.c (ZMAGIC): #undef to avoid duplicate define. + * remote.c (alarm): Move declaration to global level, before + first reference to it. + * tm-i386bsd.h (NUM_REGS): There are only eleven, not twelve. + * dbxread.c (process_one_symbol): Cast to unsigned char, not int. + +Wed Feb 17 13:40:29 1993 K. Richard Pixley (rich@cygnus.com) + + * remote.c (readchar): forward declare alarm which otherwise looks + like an undeclared variable to gcc. + + * dbxread.c (process_one_symbol): cast enum value N_SO into int + when comparing against an int. Avoids superfluous warning from + vax ultrix 4.2 cc. + + * inflow.c (set_sigint_trap): add cast to assignment from signal. + Avoids superfluous warnings from some systems and/or compilers + (like vax ultrix 4.2.) + + * language.c (struct op_print unk_op_print_tab): use the enum + values rather naked zeros as initializers. Avoids warnings from + ultrix type compilers. + +Tue Feb 16 00:53:20 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (VERSION): Roll to 4.7.6. + (SFILES_SUBDIR): Add 29k-share/udi_soc. + (SFILES_SUBSUBDIR): Move 29k-share/udi files to this macro. + (alldeps.mak): Make ALLDEPFILES_SUBSUBDIR for files in sub sub dirs. + (ALLDEPFILES_SUBSUBDIR): Depend on this for deeper dep files. + (HFILES): Remove all nm-* except nm-trash.h. Add ns32k-opcode.h. + (depend): Fix bug where nm-files in config files weren't noticed. + (make-proto-gdb-1): Avoid changing directories while building new + prototype. Build SFILES_SUBSUBDIR with longer symlinks. + +Mon Feb 15 20:48:09 1993 John Gilmore (gnu@cygnus.com) + + * remote.c: Improve error recovery. Allow user to break out + of initial connection attempt with INTERRUPT. Treat a timeout + while waiting for remote packet like a retry, unless the remote + side is actively running user code. Fix a few long printf_filtered's. + + * xcoffread.c (read_xcoff_symtab): Don't use null symbol name for + trampoline symbols. + + * buildsym.c (start_subfile): Allow null file name. + +Fri Feb 12 15:46:49 1993 K. Richard Pixley (rich@cygnus.com) + + * xcoffread.c (process_xcoff_symbol, read_symbol_lineno): complain + expects a pointer to complaint rather than a complaint + structure. + (process_linenos): free the previously allocated subfile name, + then allocate the new one from the heap. + +Fri Feb 12 08:06:05 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * h8300-tdep.c, tm-h8300.h: turn off some experimental features + +Thu Feb 11 00:59:07 1993 John Gilmore (gnu@cygnus.com) + + * stabsread.c (dbx_lookup_type): Handle negative type numbers. + Previously, would bogusly index off the bottom of type_vector. + (rs6000_builtin_type): Accept type number as argument. + (read_type, case '-'): Handle negatives like any other type number. + + * symfile.c (deduce_language_from_filename): Handle null name. + + * mips-tdep.c (isa_NAN): Fix byte order dependency. + Reported by Nobuyuki Hikichi , + fixed by sato@sm.sony.co.jp. + + * xcoffread.c (parmsym): Don't use an initializer to set up + this struct symbol. Set it up in initialize_xcoffread. + (read_xcoff_symtab, xcoff_symfile_read): Surround code that only + works on real rs/6000 target with #ifndef FAKING_RS6000. + +Wed Feb 10 23:42:37 1993 John Gilmore (gnu@cygnus.com) + + * stabsread.c (rs6000_builtin_type): Move function from + xcoffread.c:builtin_type. + * xcoffread.c (builtin_type): Move to stabsread. Remove + IBM6000_HOST dependency. Move misplaced comments. + (various): Change printf's to complaints. + (patch_block_stabs, process_xcoff_symbol case C_DECL): Add + objfile argument to read_type calls under #if 0. + (process_xcoff_symbol case C_RSYM): Fix typo in #ifdef. + * xcoffexec.c (map_vmap): Don't allocate an objfile for the exec_file. + * Makefile.in: xcoffread.o is not built by default. + * xm-rs6000.h (IBM6000_HOST): Remove. + * config/rs6000.mh (NATDEPFILES): xcoffread.o is native only. + * doc/gdbint.texinfo: Eliminate IBM6000_HOST, document + IBM6000_TARGET. + +Wed Feb 10 18:31:20 1993 Stu Grossman (grossman at cygnus.com) + + * findvar.c (read_var_value): If REG_STRUCT_HAS_ADDR, then set + VALUE_LVAL to be lval_memory so that we don't try to modify wild + register numbers when user tries to modify elements in structs + passed as arguments. + * inflow.c (child_terminal_info): Move banner outside of system + specific #ifdefs. + * tm-hppa.h (REG_STRUCT_HAS_ADDR): Define this for HPPA, which + passes struct/union arguments by address. + +Wed Feb 10 15:34:46 1993 Ian Lance Taylor (ian@cygnus.com) + + * Based on patch from Kean Johnston : + * nm-i386sco4.h: New file. Like nm-i386sco.h, but define + ATTACH_DETACH, PTRACE_ATTACH and PTRACE_DETACH. + * config/i386sco4.mh (NAT_FILE): Use nm-i386sco4.h. + +Tue Feb 9 20:07:18 1993 John Gilmore (gnu@cygnus.com) + + * remote-udi.c (FREEZE_MODE): Fix && for & typo. Found and + fixed by Lynn D. Shumaker, shumaker@saifr00.cfsat.honeywell.com. + +Tue Feb 9 08:18:07 1993 Ian Lance Taylor (ian@cygnus.com) + + * config/i386sco4.mh (MUNCH_DEFINE): Pass -p to nm to avoid bug in + cc debugging output. + +Tue Feb 9 00:19:28 1993 John Gilmore (gnu@cygnus.com) + + * stabsread.c (define_symbol): Complain about unrecognized names + that begin with CPLUS_MARKER (often '$'), but don't die. Fix + suggested by gb@cs.purdue.edu (Gerald Baumgartner). + (read_cpp_abbrev): Don't use the class name as part of the + vtable pointer member name (_vptr$) in $vf abbrevs or unrecognized + abbrevs. Inspired by Mike Tiemann. + (read_tilde_fields): Comment. Remove ancient dead code. + Remove erroneous but non-dead code. Simplify. Add complaints. + (in general): Remove extraneous (parentheses) in return + statements. + +Fri Feb 5 14:01:22 1993 John Gilmore (gnu@cygnus.com) + + * coffread.c (coff_lookup_type): Fix fencepost error reported + by Art Berggreen, . + + Fix long file name bug reported on SCO Open Desktop 2.0 by Ulf Lunde + and Dag H. Wanvik : + + * coffread.c (getfilename): Eliminate COFF_NO_LONG_FILE_NAMES + test, which is apparently left over from when we used native + include files and couldn't depend on the member names being there. + * tm-3b1.h, tm-altos.h, tm-i386v.h: Don't set it. + +Thu Feb 4 12:23:15 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c: Major overhaul to use new BFD symbol table reading + routines. Now swaps information as it is needed, rather than + swapping everything when the file is read. + +Thu Feb 4 01:52:36 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (TARDIRS): Add sparclite demo dir. + (*.tab.c): Change dependency on Makefile to depend on + Makefile.in, otherwise it always rebuilds after configuring. + Force output *.tab.c file into current directory even in "make" + versions that rewrite dependent file names used in command lines. + + * TODO: Remove some things we did. + * am29k-opcode.h, convx-opcode: Remove; now in ../include/opcode. + * os68k-xdep.c: Remove; useless file (os68k is a target only). + * convex-pinsn.c: Use ../include/opcode/convex.h. Add CONST. + * symtab.h: Eliminate unnamed unions and structs. + +Wed Feb 3 14:48:08 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (VERSION): Roll to 4.7.5. + +Tue Feb 2 20:47:42 1993 John Gilmore (gnu@cygnus.com) + + * breakpoint.c (breakpoint_re_set_one): Handle watchpoints when + re-evaluating symbol pointers. + +Tue Feb 2 16:10:31 1993 Fred Fish (fnf@cygnus.com) + + * c-exp.y (lcurly, rcurly): New nonterminals. + * c-exp.y (exp): Use lcurly and rcurly for arrays and UNOP_MEMVAL + constructs. + * parse.c (free_funcalls): Moved prototype from parser-defs.h, + made function static. + * parse.c (struct funcall): Moved struct def from parser-defs.h. + * parse.c (funcall_chain): Moved from parser-defs.h, made static. + * parse.c (start_arglist): + * parser-defs.h (free_funcalls): Moved prototype to parse.c. + * parser-defs.h (struct funcall): Moved struct def to parse.c. + * parser-defs.h (funcall_chain): Moved to parse.c. + * printcmd.c (print_frame_nameless_args): Fix prototype. + * tm-mips.h (setup_arbitrary_frame): Fix prototype. + * tm-sparc.h (setup_arbitrary_frame): Fix prototype. + * valops.c (typecmp): Moved prototype from values.h. + * value.h (typecmp): Moved prototype to valops.c, made static. + * ch-exp.y (yylex): Change way control sequences are disabled. + +Tue Feb 2 16:11:43 1993 John Gilmore (gnu@cygnus.com) + + * tm-mips.h, tm-sparc.h: Fix thinko in SETUP_ARBITRARY_FRAME. + +Tue Feb 2 15:30:33 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c (upgrade_type): Build array types correctly, using + create_range_type and create_array_type. + +Tue Feb 2 00:19:08 1993 John Gilmore (gnu@cygnus.com) + + * remote-nindy.c: Cleanup. + + * infrun.c (wait_for_inferior): When rolling back the PC after + a breakpoint, call write_pc so that NPC gets rolled back as well + (for the 29K). + + * blockframe.c (inside_entry_file, inside_main_func, + inside_entry_func): PC of zero is always "bottom of stack". + + * printcmd.c (print_frame_args, print_frame_nameless_args): + Let print_frame_nameless_args decide whether there are any, + laying groundwork for possibly later printing 29K args for + functions where we have tag words but no symbols. + +Mon Feb 1 18:09:58 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * Makefile.in: fix GDB doc targets for new doc subdir structure + +Mon Feb 1 17:56:47 1993 John Gilmore (gnu@cygnus.com) + + * stack.c (parse_frame_specification): Parse as many arguments + as there are (up to MAXARGS). Pass all of them in argc, argv + format to SETUP_ARBITRARY_FRAME. Put the burden of checking how + many there were, onto SETUP_ARBITRARY_FRAME. + * tm-mips.h, tm-sparc.h: Corresponding changes. + * mips-tdep.c, sparc-tdep.c: Ditto. + +Mon Feb 1 17:19:37 1993 John Gilmore (gnu@cygnus.com) + + * hp300ux-nat.c: Update copyrights. + * mipsread.c (parse_partial_symbols): Complain about block + indexes that go backwards. Fix from Peter Schauer. + * symfile.c (syms_from_objfile, symbol_file_add): Allow a + symbol-file that has no linkage symbols to be read. + * tm-rs6000.h, xm-rs6000.h: (SIGWINCH_HANDLER and friends): Move + from tm- file to xm-file, since they're host dependent. + * valarith.c (value_binop): Typo. + +Mon Feb 1 16:16:59 1993 Stu Grossman (grossman at cygnus.com) + + * sparclite/aload.c: Add copyleft. + * sparclite/crt0.s: Add comment at beginning. + +Mon Feb 1 14:36:11 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * remote-z8k.c, z8k-tdep.c: support for the Z8001 and Z8002. + * parse.c (std_regs): Only declare if NO_STD_REGS is defined. + +Sun Jan 31 04:32:48 1993 Michael Tiemann (tiemann@rtl.cygnus.com) + + * values.c (value_headof): Fix typo in which VTBL and ARG were + being confused for one another. + + * valops.c (typecmp): Now static. + + * gdbtypes.c (fill_in_vptr_fieldno): Don't ignore the first + baseclass--we don't always inherit its virtual function table + pointer. + + * eval.c (evaluate_subexp): In OP_FUNCALL case, adjust `this' + pointer correctly in case value_struct_elt moves it around. + + * valops.c (typecmp): Now static. Also, now groks references + better. + + * gdbtypes.c (lookup_struct_elt_type): Pass NOERR instead of + zero on recursive call. If NAME is the name of TYPE, return TYPE. + +Sat Jan 30 19:55:52 1993 John Gilmore (gnu@cygnus.com) + + * hppah-nat.c: Eliminate and other unnecessary stuff, + to avoid "too much defining" error from native C compiler (!). + + * Makefile.in (HFILES): Add typeprint.h. + * typeprint.[ch]: Update copyrights. + +Thu Jan 28 19:09:02 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in: Update to match doc/ subdir changes. + + * config/hp300hpux.mh: No cross-host file needed, just native. + * config/go32.mh: Remove nonexistent "native" support. + + M88K fixes reported by Carl Greco, : + * tm-m88k.h (REGISTER_CONVERT_TO_RAW): Fix typo. + * m88k-tdep.c (next_insn): Lint, cleanup. + (store_parm_word): Lint. + + * README: Fix typo (reported by karl@hq.ileaf.com). + +Wed Jan 27 21:34:21 1993 Fred Fish (fnf@cygnus.com) + + * expression.h (BINOP_CONCAT): Document use for self concatenation + an integral number of times. + * language.c (binop_type_check): Extend BINOP_CONCAT for self + concatenation case. + * valarith.c (value_concat): Rewrite to support self + concatenation an integral number of times. + * Makefile.in (ch-exp.tab.c): Change "expect" message. + * ch-exp.y (FIXME's): Make all FIXME tokens distinct, to + eliminate hundreds of spurious shift/reduce and reduce/reduce + conflicts that mask the 5 real ones. + * ch-exp.y (STRING, CONSTANT, SC): Remove unused tokens. + * ch-exp.y (integer_literal_expression): Remove production, + no longer used. + +Thu Jan 21 09:58:36 1993 Fred Fish (fnf@cygnus.com) + + * eval.c (evaluate_subexp): Fix OP_ARRAY, remove code that + implied that "no side effects" was nonfunctional. + * eval.c (evaluate_subexp): Add BINOP_CONCAT case to deal with + character string and bitstring concatenation. + * expprint.c (dump_expression): Add case for BINOP_CONCAT. + * expression.h (exp_opcode): Add BINOP_CONCAT. + * gdbtypes.h (type_code): Add TYPE_CODE_BITSTRING. + * language.c (string_type): Add function to determine if a type + is a string type. + * language.c (binop_type_check): Add case for BINOP_CONCAT. + * valarith.c (value_concat): New function to concatenate two + values, such as character strings or bitstrings. + * valops.c (value_string): Remove error stub and implement + function body. + * value.h (value_concat): Add prototype. + * ch-exp.y (operand_3): Add actions for SLASH_SLASH (//). + * ch-exp.y (yylex): Recognize SLASH_SLASH. + * ch-lang.c (chill_op_print_tab): Add SLASH_SLASH (//) as + BINOP_CONCAT. + +Tue Jan 19 14:26:15 1993 Fred Fish (fnf@cygnus.com) + + * c-exp.y (exp): Add production to support direct creation + of array constants using the obvious syntax. + * c-valprint.c (c_val_print): Set printed string length. + * dwarfread.c (read_tag_string_type): New prototype and + function that handles TAG_string_type DIEs. + * dwarfread.c (process_dies): Add case for TAG_string_type + that calls new read_tag_string_type function. + * expprint.c (print_subexp): Add support for OP_ARRAY. + * gdbtypes.c (create_range_type, create_array_type): Inherit + objfile from the index type. + * ch-typeprint.c (chill_print_type): Add case for + TYPE_CODE_STRING. + * ch-valprint.c (chill_val_print): Fix case for + TYPE_CODE_STRING. + +Mon Jan 18 11:58:45 1993 Ian Lance Taylor (ian@cygnus.com) + + * mipsread.c (CODE_MASK, MIPS_IS_STAB, MIPS_MARK_STAB, + MIPS_UNMARK_STAB, STABS_SYMBOLS): Removed; now in + include/coff/mips.h. + +Fri Jan 15 20:26:50 1993 Fred Fish (fnf@cygnus.com) + + * c-exp.y (exp:STRING): Convert C strings into array-of-char + constants with an explicit null byte terminator. OP_STRING is + now used for real string types. + * c-lang.c (builtin_type_*): Move declarations to lang.c since + they are used by all languages. + * c-lang.c (_initialize_c_language): Move initializations of + builtin_type_* to lang.c. + * c-typeprint.c (c_type_print_varspec_prefix, + c_type_print_varspec_suffix): TYPE_CODE_PASCAL_ARRAY renamed + to TYPE_CODE_STRING. + * c-valprint.c (c_val_print): Change the way character arrays + are printed as strings to be consistent with the way strings + are printed when pointer-to-char types are dereferenced. + Remove test of print_max before calling val_print_string, which + now does it's own test. + * eval.c (evaluate_subexp): Add case for OP_ARRAY. + * expprint.c (print_subexp, dump_expression): Add case for OP_ARRAY. + * expression.h (enum exp_opcode): Add OP_ARRAY and document. + * gdbtypes.c (builtin_type_*): Add declarations moved from + c-lang.c. + * gdbtypes.c (create_string_type): New function to create real + string types. + * gdbtypes.c (recursive_dump_type): TYPE_CODE_PASCAL_ARRAY + renamed to TYPE_CODE_STRING. + * gdbtypes.c (_initialize_gdbtypes): Add initializations of + builtin_type_* types moved from c-lang.c. + * gdbtypes.h (enum type_code): TYPE_CODE_PASCAL_ARRAY renamed + to TYPE_CODE_STRING. + * gdbtypes.h (builtin_type_string): Add extern declaration. + * gdbtypes.h (create_string_type): Add prototype. + * m2-lang.c (m2_create_fundamental_type): TYPE_CODE_PASCAL_ARRAY + renamed to TYPE_CODE_STRING. + * m88k-tdep.c (pushed_size): TYPE_CODE_PASCAL_ARRAY renamed to + TYPE_CODE_STRING. + * mipsread.c (_initialize_mipsread): TYPE_CODE_PASCAL_ARRAY + renamed to TYPE_CODE_STRING. + * parse.c (length_of_subexp, prefixify_subexp): Add case for + OP_ARRAY. + * printcmd.c (print_formatted): Recognize TYPE_CODE_STRING. + * typeprint.c (print_type_scalar): TYPE_CODE_PASCAL_ARRAY renamed + to TYPE_CODE_STRING. + * valops.c (allocate_space_in_inferior): New function and + prototype, using code ripped out of value_string. + * valops.c (value_string): Rewritten to use new function + allocate_space_in_inferior, but temporarily disabled until some + other support is in place. + * valops.c (value_array): New function to create array constants. + * valprint.c (val_print_string): Add comment to document use, + complete rewrite to fix several small buglets. + * value.h (value_array): Add prototype. + * value.h (val_print_string): Change prototype to match rewrite. + * ch-valprint.c (chill_val_print): Add case for TYPE_CODE_STRING. + * ch-exp.y (match_character_literal): Disable recognition of + control sequence form of character literals and document why. + +Thu Jan 14 15:48:12 1993 Stu Grossman (grossman at cygnus.com) + + * nindy-share/nindy.c: Add comments to #endif's to clarify + grouping. + + * hppa-pinsn.c (print_insn): Use read_memory_integer, instead of + read_memory to get byte order right. + * hppah-tdep.c (find_unwind_info): Don't read in unwind info + anymore. This is done in paread.c now. We expect unwind info + to hang off of objfiles, and search all of the objfiles when until + we find a match. + * (skip_trampoline_code): Cast arg to target_read_memory. + * objfiles.h (struct objfile): Add new field obj_private to hold + per object file private data (unwind info in this case). + * paread.c (read_unwind_info): New routine to read unwind info + for the objfile. This data is hung off of obj_private. + * tm-hppa.h: Define struct obj_unwind_info, to hold pointers to + the unwind info for this objfile. Also define OBJ_UNWIND_INFO to + make this easier to access. + +Wed Jan 13 20:49:59 1993 Fred Fish (fnf@cygnus.com) + + * c-valprint.c (cp_print_class_member): Add extern decl. + * c-valprint.c (c_val_print): Extract code for printing methods + and move it to cp_print_class_method in cp-valprint.c. + * c-valprint.c (c_val_print): Extract code to print strings and + move it to val_print_string in valprint.c. + * cp-valprint.c (cp_print_class_method): New function using + code extracted from c_val_print. + * valprint.c (val_print_string): New function using code + extracted from c_val_print. + * value.h (val_print_string): Add prototype. + * ch-exp.y (CHARACTER_STRING_LITERAL): Set correct token type. + * ch-exp.y (literal): Add action for CHARACTER_STRING_LITERAL. + * ch-exp.y (tempbuf, tempbufsize, tempbufindex, GROWBY_MIN_SIZE, + CHECKBUF, growbuf_by_size): New variables, macros, and support + functions for implementing a dynamically expandable temp buffer. + * ch-exp.y (match_string_literal): New lexer function. + * ch-exp.y (match_bitstring_literal): Dynamic buffer code + removed and replaced with new CHECKBUF macro. + * ch-exp.y (yylex): Call match_string_literal when appropriate. + * ch-valprint.c (ch_val_print): Add code for TYPE_CODE_PTR. + +Sat Jan 9 19:59:33 1993 Stu Grossman (grossman at cygnus.com) + + * Makefile.in: Add info for paread.o. + * config/hppahpux.mh: Add paread.o to NATDEPFILES. + + * blockframe.c (frameless_look_for_prologue): Correct the + comment. + * gdbtypes.h, gdbtypes.c: Use const in decl of + cplus_struct_default, now that pa-gas assembler has been fixed. + * hppah-nat.c: Formatting. + * hppah-tdep.c: Remove lots of useless externs for variables we + don't use. + * (find_unwind_entry): Speed up by using binary search, and a one + entry cache. + * (rp_saved): New routine to see what unwind info says about RP + being saved on the stack frame. + * (frame_saved_pc): Look for prologue to see if we need to + examine the stack for the saved RP or not. + * (init_extra_frame_info): Check for prologue, instead of + framesize to determine if we are frameless or not. + * (frame_chain_valid): Stop backtraces when we run into _start. + * (push_dummy_frame): Reformat to make more readable. + * (find_dummy_frame_regs): ditto. + * (hp_pop_frame): ditto. + * (hp_restore_pc_queue): small cleanup. + * (hp_push_arguments): ditto. + * (pa_do_registers_info): ditto. + * (skip_prologue): New routine created from SKIP_PROLOGUE macro. + * tm-hppa.h: Move contents of SKIP_PROLOGUE into hppah-tdep.c. + * Define FRAME_CHAIN_VALID. + * Turn on BELIEVE_PCC_PROMOTION so that we can access char args + passed to functions. + + * paread.c (pa_symtab_read): Use new bfd conventions for + accessing linker symbol table. + * (pa_symfile_init): Access embedded STAB info via BFD section + mechanism and related macros. + + +Sat Jan 9 19:31:43 1993 Stu Grossman (grossman at cygnus.com) + + * sparc-stub.c: Use a seperate stack for our traps. + * Handle recursive traps. + * Remove all trap init code. This needs to be done by the + environment. + * (set_mem_fault_trap): Call exceptionHandler() to setup this + trap. + * (handle_exception): See if we are at breakinst, if so, then + advance PC sp that users can just step out of breakpoint(). + * (case 'G'): Don't let GDB hack CWP. Also, copy saved regs to + new place if SP has changed. + * (case 's'): Get rid of this, we can't do it yet. + * (case 't'): New command to test any old random feature. + * (case 'r'): New command to reset the system. + * (breakpoint): Add label to breakpoint trap instruction so that + handle_exception() can detect where we are and get past the + breakpoint trivially. + +Thu Jan 7 13:33:06 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips-pinsn.c: Actual work now done by opcodes/mips-dis.c. + +Thu Jan 7 09:21:51 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * configure.in: recognise all sparclite variants + +Wed Jan 6 10:14:51 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * symfile.c: If O_BINARY isn't defined, set it to 0, call openp for + binary files oring in the right bit. + + * main.c, source.c, state.c, symmisc.c: use macros defined in + fopen-{bin|both} when fopening files. + +Wed Jan 6 08:19:11 1993 Fred Fish (fnf@cygnus.com) + + * defs.h (HOST_CHAR_BIT): New macro, defaults to either CHAR_BIT + from a configuration file (typically including ), or to + TARGET_CHAR_BIT if CHAR_BIT is not defined. + * eval.c (evaluate_subexp): Use new BYTES_TO_EXP_ELEM macro. + * eval.c (evaluate_subexp): Add case for OP_BITSTRING. + * expprint.c (print_subexp): Use new BYTES_TO_EXP_ELEM macro. + * exppritn.c (print_subexp, dump_expression): Add case for + OP_BITSTRING. + * expression.h (OP_BITSTRING): New expression element type for + packed bitstrings. + * expression.h (EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): New + macros to convert between number of expression elements and bytes + to store that many elements. + * i960-tdep.c (leafproc_return): Use new macros to access + minimal symbol name and address fields. + * m88k-pinsn.c (sprint_address): Use new macros to access + minimal symbol name and address fields. + * nindy-tdep.c (nindy_frame_chain_valid): Use new macro to access + minimal symbol address field. + * parse.c (write_exp_elt, write_exp_string, prefixify_expression, + parse_exp_1): Use new EXP_ELEM_TO_BYTES macro. + * parse.c (write_exp_string, length_of_subexp, prefixify_expression): + Use new BYTES_TO_EXP_ELEM macro. + * parse.c (write_exp_bitstring): New function to write packed + bitstrings into the expression element vector. + * parse.c (length_of_subexp, prefixify_subexp): Add case for + OP_BITSTRING. + * parser-defs.h (struct stoken): Document that it is used for + OP_BITSTRING as well as OP_STRING. + * parser-defs.h (write_exp_bitstring): Add prototype. + * ch-exp.y (BIT_STRING_LITERAL): Change token type to sval. + * ch-exp.y (NUM, PRED, SUCC, ABS, CARD, MAX, MIN, SIZE, UPPER, + LOWER, LENGTH): New tokens for keywords. + * ch-exp.y (chill_value_built_in_routine_call, mode_argument, + upper_lower_argument, length_argument, array_mode_name, + string_mode_name, variant_structure_mode_name): New non-terminals + and productions. + * ch-exp.y (literal): Useful production for BIT_STRING_LITERAL. + * ch-exp.y (match_bitstring_literal): New lexer support function + to recognize bitstring literals. + * ch-exp.y (tokentab6): New token table for 6 character keywords. + * ch-exp.y (tokentab5): Add LOWER, UPPER. + * ch-exp.y (tokentab4): Add PRED, SUCC, CARD, SIZE. + * ch-exp.y (tokentab3): Add NUM, ABS, MIN, MAX. + * ch-exp.y (yylex): Check tokentab6. + * ch-exp.y (yylex): Call match_bitstring_literal. + +Mon Jan 4 16:54:18 1993 Fred Fish (fnf@cygnus.com) + + * xcoffexec.c (vmap_symtab): Use new macros to access minimal + symbol name and value fields. + + * c-exp.y (yylex): Make static, to match prototype and other + -exp.y files. + + * expression.h (exp_opcode): Add BINOP_MOD. + * eval.c (evaluate_subexp): Handle new BINOP_MOD. + * expprint.c (dump_expression): Handle new BINOP_MOD. + * language.c (binop_type_check): Handle new BINOP_MOD. + * main.c (float_handler): Re-enable float handler when hit. + * valarith.c (language.h): Include, need current_language. + * valarith.c (TRUNCATION_TOWARDS_ZERO): Define default macro + for integer divide truncates towards zero for negative results. + * valarith.c (value_x_binop): Handle BINOP_MOD if seen. + * valarith.c (value_binop): Allow arithmetic operations on + TYPE_CODE_CHAR variables. Add case to handle new BINOP_MOD. + * ch-exp.y (operand_4): Add useful actions for MOD and REM. + * ch-exp.y (tokentab3): Add MOD and REM. + * ch-exp.y (yylex): Set innermost_block for symbols found + in local scopes. Return LOCATION_NAME for local symbols. + * ch-lang.c (chill_op_print_tab): Fix MOD entry to use + BINOP_MOD instead of BINOP_REM. Add REM entry, using BINOP_REM. + +Mon Jan 4 07:35:31 1993 Steve Chamberlain (sac@wahini.cygnus.com) + + * command.c (shell_escape, make_command, _initialize_command): + don't create or use fork if CANT_FORK is defined. + * serial.h, ser-go32.c: now compiles, but "the obvious problems of + code written for the IBM PC" remain. + * xm-go32.h: define CANT_FORK + +Sun Jan 3 14:24:56 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * remote-sim.c: first attempt at general simulator interface + * remote-hms.c: whitespace + * h8300-tdep.c: (h8300_skip_prologue, examine_prologue): + understand new stack layout. (print_register_hook): print ccr + register in a fancy way. + +Sun Jan 3 14:16:10 1993 Fred Fish (fnf@cygnus.com) + + * eval.c (language.h): Include. + * eval.c (evaluate_subexp_with_coercion): Only coerce arrays + to pointer types when the current language is C. It loses for + other languages when the lower index bound is nonzero. + * valarith.c (value_subscript): Take array lower bounds into + account when performing subscripting operations. + * valops.c (value_coerce_array): Add comment describing why + arrays with nonzero lower bounds are dealt with in value_subscript, + rather than in value_coerce_array. + +Sat Jan 2 12:16:41 1993 Fred Fish (fnf@cygnus.com) + + * ch-exp.y (FLOAT_LITERAL): Add token. + * ch-exp.y (literal): Add FLOAT_LITERAL. + * ch-exp.y (match_float_literal): New lexer routine. + * ch-exp.y (convert_float): Remove. + * ch-exp.y (yylex): Call match_float_literal. + * ch-exp.y (yylex): Match single '.' after trying + to match floating point literals. + + * eval.c (evaluate_subexp): Add case MULTI_SUBSCRIPT. + * expprint.c (print_subexp): Rename BINOP_MULTI_SUBSCRIPT to + MULTI_SUBSCRIPT. + * expprint.c (dump_expression): New function for dumping + expression vectors during gdb debugging. + * expression.h (BINOP_MULTI_SUBSCRIPT): Name changed to + MULTI_SUBSCRIPT and moved out of BINOP range. + * expression.h (DUMP_EXPRESSION): New macro that calls + dump_expression if DEBUG_EXPRESSIONS is defined. + * m2-exp.y (BINOP_MULTI_SUBSCRIPT): Changed to MULTI_SUBSCRIPT. + * parse.c (length_of_subexp, prefixify_subexp): Change + BINOP_MULTI_SUBSCRIPT to MULTI_SUBSCRIPT. + * parse.c (parse_exp_1): Call DUMP_EXPRESSION before and after + prefixify'ing the expression. + * printcmd.c (print_command_1): Add comment. + * ch-exp.y (expression_list): Add useful actions. + * ch-exp.y (value_array_element): Add useful actions. + * ch-exp.y (array_primitive_value): Add production. + * ch-exp.y (yylex): Recognize ',' as a token. + +Fri Jan 1 18:22:02 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: pass prefix and exec_prefix via FLAGS_TO_PASS, + POSIXize the recursive makes (make [variable assignments] target{s}) + +Fri Jan 1 11:56:23 1993 Fred Fish (fnf@cygnus.com) + + * tm-sun4sol2.h (CPLUS_MARKER): Remove, now set in tm-sysv4.h. + * tm-sysv4.h (CPLUS_MARKER): By default, g++ uses '.' as the + CPLUS_MARKER for all SVR4 systems, so follow suit. + * defs.h (strdup_demangled): Remove prototype. + * dwarfread.c (enum_type, synthesize_typedef): Use new macro + SYMBOL_INIT_LANGUAGE_SPECIFIC. + * dwarfread.c (new_symbol): Use SYMBOL_INIT_DEMANGLED_NAME. + * minsyms.c (install_minimal_symbols, prim_record_minimal_symbol, + prim_record_minimal_symbol_and_info): Use new macro + SYMBOL_INIT_LANGUAGE_SPECIFIC. + * minsyms.c (install_minimal_symbols): Use new macro + SYMBOL_INIT_DEMANGLED_NAME. + * stabsread.c (define_symbol): Use new macro + SYMBOL_INIT_DEMANGLED_NAME. + * symfile.c (add_psymbol_to_list, add_psymbol_addr_to_list): + Use new macro SYMBOL_INIT_DEMANGLED_NAME. + * symfile.h (ADD_PSYMBOL_VT_TO_LIST): Use new macro + SYMBOL_INIT_DEMANGLED_NAME. + * symmisc.c (dump_msymbols, dump_symtab, print_partial_symbol): + SYMBOL_DEMANGLED_NAME now tests language itself. + * symtab.c (COMPLETION_LIST_ADD_SYMBOL): SYMBOL_DEMANGLED_NAME + now tests language itself. + * symtab.h (SYMBOL_CPLUS_DEMANGLED_NAME): New macro that does + what SYMBOL_DEMANGLED_NAME used to do, directly access the C++ + mangled name member in the language dependent portion of a symbol. + * symtab.h (SYMBOL_DEMANGLED_NAME): New macro that returns the + mangled name member appropriate for a symbol's language. + * symtab.h (SYMBOL_SOURCE_NAME, SYMBOL_LINKAGE_NAME, + SYMBOL_MATCHES_NAME, SYMBOL_MATCHES_REGEXP): + SYMBOL_DEMANGLED_NAME now tests language itself. + * symtab.h (SYMBOL_INIT_LANGUAGE_SPECIFIC): New macro that + initializes language dependent portion of symbol. + * symtab.h (SYMBOL_INIT_DEMANGLED_NAME): New macro that + demangles and caches the demangled form of symbol names. + * utils.c (fputs_demangled, fprint_symbol): Use current language + to select an appropriate demangling algorithm. + * utils.c (strdup_demangled): Remove, no longer used. + * symtab.h (SYMBOL_CHILL_DEMANGLED_NAME): New macro that directly + access the Chill mangled name member in the language dependent + portion of a symbol. + * ch-lang.c (chill_demangle): New function, simple demangler. + * defs.h (chill_demangle): Add prototype. + * symtab.h (language_dependent_info): Add struct for Chill. + +For older changes see ChangeLog-92 + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/gdb/ChangeLog-94 b/contrib/gdb/gdb/ChangeLog-94 new file mode 100644 index 000000000000..a691ace10030 --- /dev/null +++ b/contrib/gdb/gdb/ChangeLog-94 @@ -0,0 +1,5705 @@ +Fri Dec 30 17:58:55 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * config/m68k/tm-est.h: Remove cruft. + + +Thu Dec 29 22:40:00 1994 Jeff Law (law@snake.cs.utah.edu) + + * Allow up to 10 whitespace separated arguments to user defined + commands. + * top.c (struct user_args): Structure for holding arguments to + user defined commands. + (print_command_line): Delete unused "tmp_chain" variable. Clean + up flow control by having cases exit in the same manner. + Before executing a command or evaluating an expression, substitute + the current $arg0..$arg9 values if the command/expression uses them. + (arg_cleanup): New function. + (setup_user_args, locate_arg, insert_args): Likewise. + (execute_user_command): Allow arguments to user defined commands. + + * Allow if/while commands to be used within a breakpoint command + list. + * breakpoint.c (bpstat_do_actions): Call execute_control_command + rather than execute_command (passes entire command structure rather + than just the command line text). + (breakpoint_1): Use "print_command_line" to print a breakpoint + command line (including control structures). + * gdbcmd.h (execute_control_command): Provide extern decl. + (print_command_line): Likewise. + * top.c (execute_control_command): No longer static. + (print_command_line): New function to recursively print a command + line, including control structures. + +Thu Dec 29 18:18:31 1994 Rob Savoye + + * hppa-tdep.c (pa_print_registers): Extract register values stored + in big endian format on big and little endian hosts. + + * array-rom.c: Support for Array Tech LSI33k based RAID disk + controller board. + * configure.in: Recognize "mips*-*-ecoff*" rather than + "mips*-idt-ecoff*" so it'll work for the LSI33k. + + * monitor.[ch], op50-rom.c, rom68k-rom.c, w89k-rom.c: Add support + to monitor config structure for supported baud rates for a target + and variable stop bits. + * monitor.c (monitor_fetch_register): Store register values in big + endian format on any host. + +Wed Dec 28 19:27:22 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (hppa_fix_call_dummy): Prefer import stubs over + export stubs and actual shared library functions so that lazy + binding works correctly. Try both __d_plt_call and __gcc_plt_call + trampolines for calling import stubs. + +Wed Dec 28 15:29:02 1994 Stan Shebs + + * a29k-tdep.c (pop_frame): Fix a variable name. + +Wed Dec 28 12:21:39 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (push_dummy_frame): Refine code to determine what + space ID to place in the stack & inf_status structure. + (hppa_pop_frame): Don't walk through trampoline code if popping a + call dummy frame. + (hppa_fix_call_dummy): Call the stack dummy directly if the + current PC is in a shared library. + + * hppa-tdep.c (push_dummy_frame): Return type is void. Clear + in_syscall bit in flags. Don't depend on the PC queue registers + when in_syscall is set, they're not valid. + * config/pa/tm-hppa.h (PUSH_DUMMY_FRAME): Pass inf_status down to + push_dummy_frame. + (SR4_REGNUM): Define. + + * hppa-tdep.c: Misc. lint changes. + +Tue Dec 27 12:32:43 1994 Jeff Law (law@snake.cs.utah.edu) + + * breakpoint.c (watchpoint_check): Don't bother restoring the + "selected" frame anymore, it's not necessary. Initialize the + frame cache before trying to find the current frame in the frame + chain. + + * somsolib.c (som_solib_add): Return without loading any shared + libraries if symfile_objfile is NULL. + (som_solib_create_inferior_hook): Likewise. + +Fri Dec 23 17:03:13 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote-est.c: New file supports EST-300 CPU32 background + mode ICE. + * remote-utils.c (sr_com): Call registers_changed. + * configure.in (m68*-*-est*): New configuration. + * config/m68k/tm-est.h: New file. + +Fri Dec 23 16:18:50 1994 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (CLIBS): Put LIBIBERTY last. + +Thu Dec 22 09:27:16 1994 Jim Kingdon + + * ser-tcp.c (tcp_open): Cast to struct sockaddr when passing to + function which expects that. + +Thu Dec 22 13:25:33 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * nlm/gdbserve.c, nlm/ppc.c, nlm/ppc.h: Don't try to use + ALTERNATE_MEM_FUNCS. + +Wed Dec 21 14:00:26 1994 Rob Savoye + + * monitor.c: Now supports xmodem as a remoteloadprotocol. + +Tue Dec 20 23:01:17 1994 Stu Grossman (grossman@cygnus.com) + + * config/mips/xm-irix4.h, config/mips/xm-irix5.h: #define + _BSD_COMPAT to get reliable signal handling. + +Tue Dec 20 11:44:28 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc-tdep.c, a29k-tdep.c, findvar.c (get_saved_register): + if !target_has_registers, call error(). + + * value.h: Remove obsolete comments about FRAME vs struct + frame_info *. + + +Sun Dec 18 11:52:58 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-tdep.c (sparc_pop_frame): Remove erroneous extra argument + to write_register. + +Sat Dec 17 13:23:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * tm-sparc.c (EXTRA_FRAME_INFO): New field sp_offset. + * sparc-tdep.c (sparc_init_extra_frame_info): Set it. + (examine_prologue, sparc_init_extra_frame_info): Use ->frame plus + ->sp_offset to compute the address something is saved at, not + ->bottom. + + * sparc-tdep.c (get_saved_register): New function. + * tm-sparc.h: Define GET_SAVED_REGISTER; don't define + FRAME_FIND_SAVED_REGS, HAVE_REGISTER_WINDOWS or REGISTER_IN_WINDOW_P. + * stack.c (frame_info): Add comment about what to do if + FRAME_FIND_SAVED_REGS is not defined. + + * sparc-tdep.c (sparc_init_extra_frame_info): Set ->frame field + here. Get it right for flat frames. + * sparc-tdep.c (sparc_frame_chain): Instead of returning + meaningful value for ->frame field, just return dummy value. + This change is needed because the old code didn't deal with mixed + flat and non-flat frames. + + * sparc-tdep.c (sparc_pop_frame): Write SP_REGNUM from + frame->frame, don't go through saved regs for this. + + * sparc-tdep.c: Move guts of skip_prologue to new function + examine_prologue. Check for flat prologue and set is_flat. + Provide the caller with the information about what is saved where + if desired. + (skip_prologue, sparc_frame_find_saved_regs): Call examine_prologue. + + * sparc-tdep.c: Replace union sparc_insn_layout and anonymous + union in isannulled, which won't work on a little-endian host, + with X_* macros. + + * sparc-tdep.c (sparc_frame_saved_pc): If addr == 0, the saved PC + is still in %o7. + + * config/sparc/tm-sparc.h: Define INIT_FRAME_PC and + INIT_FRAME_PC_FIRST. + * blockframe.c (get_prev_frame_info): Modify comments regarding + INIT_FRAME_PC_FIRST and the sparc. + + * sparc-tdep.c (single_step): Use 4 not sizeof (long) for size of + instruction. + +Sat Dec 17 02:33:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * c-typeprint.c (c_type_print_base): Use `show' of -1 to print + the return type of methods to avoid infinite loops with anonymous + types. + * valops.c (search_struct_field): Handle anonymous unions. + + * sparc-tdep.c (sunos4_skip_trampoline_code): New function + to correctly handle steps into -g compiled PIC objects in the + main executable. + * config/sparc/tm-sun4os4.h (SKIP_TRAMPOLINE_CODE): + Redefine to use sunos4_skip_trampoline_code. + + * dwarfread.c (DWARF_REG_TO_REGNUM): Provide a default mapping + from DWARF to GDB register numbering. + * dwarfread.c (locval): Use DWARF_REG_TO_REGNUM to map the + register value. + * config/mips/tm-mipsv4.h (DWARF_REG_TO_REGNUM): Define. + +Fri Dec 16 10:56:29 1994 J.T. Conklin + + * Makefile.in (uninstall): transform file names. + +Thu Dec 15 16:55:35 1994 Stan Shebs + + * defs.h: Include progress.h. + (QUIT): Call PROGRESS. + * main.c (main): Call START_PROGRESS and END_PROGRESS, break + usage message into shorter strings. + * source.c: Change long command help strings into concats of + shorter ones, for picky ANSI compilers. + + * top.c (command_loop): For space usage display, show both + absolute size and the change from before command execution. + +Thu Dec 15 16:40:10 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h, main.c (gdb_fputs), top.c: Add stream arg to + fputs_unfiltered_hook. + * defs.h, top.c, utils.c (error): Add error_hook. + +Tue Dec 13 15:15:33 1994 Stan Shebs + + * breakpoint.c, infrun.c, printcmd.c: Change long command help + strings into concats of shorter ones, for picky ANSI compilers. + +Mon Dec 12 17:08:02 1994 Stan Shebs + + Sparc flat register window support. + * sparc-tdep.c (sparc_insn_layout): New union, defines layout of + instructions symbolically (used to be local to skip_prologue). + (sparc_init_extra_frame_info): New function. + (sparc_frame_chain): Add flat cases throughout. + (skip_prologue): Add recognition of flat prologues. + (sparc_frame_find_saved_regs): Add flat cases. + (sparc_pop_frame): Ditto. + * config/sparc/tm-sparc.h (EXTRA_FRAME_INFO): New slots. + (INIT_EXTRA_FRAME_INFO): Call sparc_init_extra_frame_info. + (PRINT_EXTRA_FRAME_INFO): Define. + + +Mon Dec 12 13:06:59 1994 Jim Kingdon + + * f-lang.c: Remove duplicate declaration of + builtin_type_f_integer, and only include it in the f_builtin_types + once. + + * somread.c (som_symfile_read): Just assign to objfile->obj_private, + not OBJ_UNWIND_INFO. Assigning to a cast is a GCC-ism which + the HP compiler doesn't like. + + +Fri Dec 9 15:50:05 1994 Stan Shebs + + * remote.c (remote_wait): Pass string instead of char to strcpy. + +Fri Dec 9 04:43:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/low-lynx.c (mywait): Remove debugging printf. + +Thu Dec 8 15:07:29 1994 Jim Kingdon + + * frame.h: Restore pre-Nov 3 comments about FRAME_FP with minor + changes. They are correct, unlike the post-Nov 3 comment + (FRAME_FP doesn't have any machine-independent relationship with + FP_REGNUM or any other such notion of a "frame pointer"). + +Wed Dec 7 14:50:54 1994 Jim Kingdon + + * gdbserver/remote-utils.c (write_ok): Write "OK", not "Ok", to + match stubs and protocol spec. + * gdbserver/remote-utils.c (remote_open): Cast to struct sockaddr + when passing to function which expects that. + + The following changes aren't quite enough to make things work with + LynxOS (apprently kernel problems). + * infrun.c (wait_for_inferior): When resuming new thread, pass pid + not -1 for remote case. + * thread.c (info_threads_command): Give error if !target_has_stack. + * infrun.c (start_remote): Call init_thread_list. + * thread.c (info_threads_command): Don't call kill for remote + debugging target. + * target.c (normal_pid_to_str): Print "thread" not "process" for + remote. + * remote.c, gdbserver/*: Add 'H', 'S', and 'C' requests, 'X' + response, and `thread' part of 'T' response. + * gdbserver/*: If program exits, send packet to GDB before + exiting. Handle termination with a signal the same as exiting + with an exitstatus. + * remote.c: Don't try to kill program after getting an 'X' + response. + * infrun.c (wait_for_inferior): Add comment about kill versus mourn. + +Thu Dec 8 12:37:38 1994 Rob Savoye + + * config/pa/tm-pro.h tm-hppap.h, hppapro.mt: Rename tm-hppap.h to + tm-pro.h. + +Wed Dec 7 18:22:59 1994 Stan Shebs + + * source.c: Various cosmetic changes. + (forward_search_command): Handle very long source lines correctly. + +Wed Dec 7 13:21:47 1994 Rob Savoye + + * hppa-tdep.c: Use GDB_TARGET_IS_PA_ELF so SOM target support will + stop being linked in. + + * config/pa/tm-hppap.h: New file. Set GDB_TARGET_IS_PA_ELF, + otherwise it looks like BSD-ELF. + +Mon Dec 5 21:43:52 1994 Stu Grossman (grossman@cygnus.com) + + * inftarg.c: include to get def of pid_t. + +Fri Dec 2 15:03:07 1994 Stan Shebs + + * solib.c (auto_solib_add_at_startup): New global. + (solib_create_inferior_hook): Call solib_add only if + auto_solib_add_at_startup is nonzero. + (_initialize_solib): New command "set auto-solib-add". + +Fri Dec 2 12:52:04 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * parse.c (msymbol_addr_type): Replaced by + lookup_pointer_type (builtin_type_void). + + * printcmd.c (_initialize_printcmd): Give examine_*_type + a name for `ptype $_'. + +Fri Dec 2 12:52:04 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_formatted): Call val_print_string directly, + rather than via value_print. + +Wed Nov 30 22:27:27 1994 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (som_solib_get_got_by_pc): New function. + * somsolib.h (som_solib_get_got_by_pc): Add extern decl. + * hppa-tdep.c (hppa_fix_call_dummy): Handle case where FUN is the + function's export stub or real address in a shared library. + +Tue Nov 29 13:40:25 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * config/i386/nbsd.mh (REGEX, REGEX1): No longer define. + + * configure.in (i[345]86-*-freebsd*): New configuration. + * config/i386/{fbsd.mh,fbsd.mt,nm-fbsd.h}: New files. + +Tue Nov 29 12:23:25 1994 Stan Shebs (shebs@andros.cygnus.com) + + * top.c (read_next_line): Pass annotation suffix "commands" + instead of "command", matches documentation. + +Mon Nov 28 14:53:21 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/a29k/tm-a29k.h (setup_arbitrary_frame): Replace + FRAME_ADDR with CORE_ADDR in prototype. + + * top.c (command_line_input): If annotation suffix is NULL, + replace it with an empty string. + (read_next_line): Pass "command" as annotation suffix to + command_line_input. + +Mon Nov 28 11:03:14 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * config/rs6000/tm-rs6000.h (setpgrp): move defn from here... + * config/rs6000/xm-rs6000.h: ...to here. + + +Fri Nov 25 21:26:02 1994 Jeff Law (law@snake.cs.utah.edu) + + * tm-hppa.h (skip_trampoline_code): Add extern decl. + * hppa-tdep.c (hppa_pop_frame): Silently restart the inferior and + allow it to execute any return path trampoline code. Stop the + inferior and give the user control when the trampoline has + finished executing. + (in_solib_call_trampoline): Handle export stubs which also perform + parameter relocations. + (in_solib_return_trampoline): Likewise. + +Fri Nov 25 13:37:10 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * coffread.c, symfile.h (coff_getfilename): Make it static again. + * xcoffread.c (coff_getfilename): Use a static copy from + coffread.c, modified for accessing the static xcoff strtbl. + +Fri Nov 25 00:51:05 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (in_solib_call_trampoline): Recognize calls through + _sr4export and $$dyncall as trampolines. Likewise for long-call + stubs and parameter relocation stubs. + (in_solib_return_trampoline): Recognize a return trampoline for + return value relocation stubs. + + * hpread.c: Include hp-symtab.h instead of hpux-symtab.h. + Various name changes to match those used by hp-symtab.h. + +Thu Nov 24 00:39:27 1994 Jeff Law (law@snake.cs.utah.edu) + + * blockframe.c (find_pc_partial_function): Inhibit mst_trampoline + symbol special handling when INHIBIT_SUNSOLIB_TRANSFER_TABLE_HACK + is defined. + * infrun.c (IN_SOLIB_CALL_TRAMPOLINE): Renamed from + IN_SOLIB_TRAMPOLINE. All callers changed. + (IN_SOLIB_RETURN_TRAMPOLINE): Provide default definition. + (wait_for_inferior): Handle single stepping through trampolines on + return paths from shared libraries. + * config/pa/tm-hppa.h (IN_SOLIB_CALL_TRAMPOLINE): Use + in_solib_call_trampoline. + (IN_SOLIB_RETURN_TRAMPOLINE): Use in_solib_return_trampoline. + (INHIBIT_SUNSOLIB_TRANSFER_TABLE_HACK): Define. + * hppa-tdep.c (in_solib_call_trampoline): New function. + (in_solib_return_trampoline): New function. + +Wed Nov 23 21:43:03 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * tm-h8300.h (REMOTE_BREAKPOINT): Define. + * h8300-tdep.c (h8300_pop_frame): Remove redundant call. + + * remote-e7000.c (HARD_BREAKPOINTS): Reenable. + (BC_BREAKPOINTS): Disable. + * sh-tdep.c (print_insn): Cope with big and little endian machines. + * sh/sh.mt: Use libsim.a + * sh/tm-sh.h (TARGET_BYTE_ORDER_SELECTABLE): New + (BREAKPOINT): Changed to be byteorder independent. + +Tue Nov 22 19:13:39 1994 Stan Shebs (shebs@andros.cygnus.com) + + Maintenance commands to report time and space usage. + * main.c (display_time, display_space): New globals. + (main): Add argument --statistics to enable reporting, display + time and space after startup is done. + * maint.c (maintenance_time_display, maintenance_space_display): + New commands. + * top.c (command_loop): Display time and space after command + execution. + + * top.c (pre_init_ui_hook): New global. + (gdb_init): If pre_init_ui_hook set, call before all other init. + +Tue Nov 22 10:25:59 1994 Kung Hsu (kung@mexican.cygnus.com) + + * a29k-tdep.c (examine_tag): Fix a bug in stack frame size. + +Sat Nov 19 03:10:51 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/i386/i386sol2.mh: Reenable core file support. + + * symfile.c (deduce_language_from_filename): Treat .c++ as a + C++ extension. + + * valops.c (destructor_name_p): Do not compare the template + part for template classes. + +Fri Nov 18 14:55:59 1994 Stan Shebs (shebs@andros.cygnus.com) + + * defs.h, infcmd.c (reg_names): Don't declare as constant. + * remote-mips.c (mips_open): Read and set the processor type. + * mips-tdep.c (mips_set_processor_type): Always return an int. + +Fri Nov 18 10:38:12 1994 J.T. Conklin + + * nlm/alpha.c (strtol): Remove, it is provided by NetWare C library. + * nlm/gdbserve.def (strtol): Add to import list. + * nlm/fake_aio.c: Remove file, no longer used. + + * Makefile.in (LD_FOR_TARGET, NLMCONV_FOR_TARGET): Remove. + * nlm/Makefile.in (gdbserve.O): Link with ${CC_FOR_TARGET}. + (LD_FOR_TARGET): Remove. + +Thu Nov 17 22:09:50 1994 Rob Savoye + + * monitor.h, monitor.c, w89k-rom.c, op50n-rom.c, idp-rom.c: Add + support for two variables used to control the load protocol and + conversion type. + +Thu Nov 17 17:51:12 1994 Stan Shebs (shebs@andros.cygnus.com) + + Support for different MIPS IDT processor models. + * mips-tdep.c (mips_processor_type, tmp_mips_processor_type, + mips_generic_reg_names, mips_r3041_reg_names, + mips_r3051_reg_names, mips_r3081_reg_names, + mips_processor_type_table): New globals. + (mips_do_registers_info): Don't display register if name is empty. + (mips_set_processor_type_command): New command. + (mips_show_processor_type_command): New command. + (mips_set_processor_type): New function. + (mips_read_processor_type): New function. + * config/mips/tm-idt.h (DEFAULT_MIPS_TYPE): New macro. + * config/mips/tm-mips.h (DEFAULT_MIPS_TYPE): New macro. + (NUM_REGS): Increase to account for all CP0 registers. + (REGISTER_NAMES): Add empty names for CP0 registers. + (FIRST_EMBED_REGNUM, LAST_EMBED_REGNUM): Adjust. + (PRID_REGNUM): New macro. + +Wed Nov 16 16:41:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + * README: Add warning about termcap in Ultrix and OSF/1. + +Wed Nov 16 15:28:29 1994 Rob Savoye (rob@cygnus.com) + + + * hppa-tdep.c: Remove including sys/dir.h from a target file. + +Wed Nov 16 10:31:27 1994 J.T. Conklin (jtc@cygnus.com) + + * config/powerpc/gdbserve.mt (TDEPFILES): Remove fake_aio.o. + + * nlm/gdbserve.c: Include before other NetWare headers. + * nlm/ppc.c: Likewise. + + * nlm/ppc.c (strtol): Remove, it is provided by NetWare C Library. + (StopBell): New function (stubbed out). + +Wed Nov 16 00:12:21 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (skip_trampoline_code): Handle shared library import + trampolines. + +Tue Nov 15 16:18:52 1994 Kung Hsu (kung@mexican.cygnus.com) + + * c-exp.y (yylex): Fix a bug in template scanning. + +Tue Nov 15 14:25:47 1994 Stan Shebs (shebs@andros.cygnus.com) + + * i386-stub.c, m68k-stub.c, sparc-stub.c, sparcl-stub.c: Mask out + the top bit returned by getDebugChar. + +Tue Nov 15 01:03:56 1994 Rob Savoye (rob@slipknot.cygnus.com) + + * op50-rom.c, w89k-rom.c, monitor.c: Modify to usr two variables + to set remote load type and protocol. + * rom68k-rom.c: Add to_stop in target_ops. + + +Sat Nov 12 21:55:47 1994 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c: Add TODO list. + (som_solib_add): Immediately return if $SHLIB_INFO$ sections does + not exist or has size zero. Slightly simplify error handling. + Keep an internal list of all the loaded shared libraries and + various tidbits of information about the loaded shared libraries. + Build section tables for each loaded shared library and add those + tables to the core target if necessary. + (som_solib_create_inferior_hook): Force re-reading of shared + libraries at exec time. + (som_sharedlibrary_info_command): New function for dumping + information about the currently loaded shared libraries. + (_initialize_som_solib): New function. + +Sat Nov 12 02:26:50 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * Makefile.in (copying.o, f-exp.tab.o, dpx2-nat.o, dstread.o, + i386aix-nat.o, i386m3-nat.o, irix5-nat.o, lynx-nat.o, m3-nat.o, + mipsm3-nat.o, ns32km3-nat.o, remote-e7000.o, remote-os9k.o): + Add dependencies. + (copying.o, os9kread.o, remote.o): Update dependencies. + + * valarith.c (value_sub): When subtracting pointers, only + check for a match of the pointed to element lengths. + Cast element length to LONGEST to obtain a signed result for + pointer subtractions. + +Fri Nov 11 10:51:07 1994 Jeff Law (law@snake.cs.utah.edu) + + * ch-exp.y (yylex): Fix off-by-one error when converting string to + lowercase. Null terminate new string. + + * hppa-tdep.c (rp_saved): Handle IMPORT stubs too. + + * somsolib.c (som_solib_add): Check the value of __dld_flags, if + it indicates __dld_list is not valid return an error. If it + indicates that libraries were not mapped privately, issue a + warning. + +Thu Nov 10 23:17:45 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symfile.c (syms_from_objfile): Only call find_lowest_section if + no ".text" section exists. + +Thu Nov 10 15:16:21 1994 Rob Savoye + + * rom68k-rom.c: New file. Replaces the old remote-mon.c and uses + the new generic ROM interface in monitor.c. + * config/m68k/monitor.mt: Use new ROM support. + * monitor.c: Add support for xmodem download protocol. + +Wed Nov 9 18:46:24 1994 Stan Shebs (shebs@andros.cygnus.com) + + * findvar.c (find_saved_register): Fix a frame variable name. + * infcmd.c (finish_command): Ditto. + +Tue Nov 8 13:20:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Remove "Watchpoints seem not entirely reliable, though + they haven't failed me recently." item--this old (4.6 at least) + item is too vague to be useful (some watchpoint bugs have been + fixed since then). + * TODO: Add explanation of "RPC interface" item. + +Mon Nov 7 22:25:21 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (read_unwind_info): Use "text_offset" for linker + stub unwind descriptors too. + + * Enable backtracing from inside a SOM shared library back into + user code. + * hppa-tdep.c (internalize_unwinds): Accept and use new + "text_offset" argument for dynamic relocation of + region_{start,end} fields in the unwind descriptor. + (read_unwind_info): Pass text_offset to internalize unwinds. + +Mon Nov 7 14:34:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m3-nat.c: Remove comments about arbitrary limit in + printf_filtered; that limit is gone. + +Mon Nov 7 00:27:16 1994 Jeff Law (law@snake.cs.utah.edu) + + * Beginnings of SOM shared library support. Breakpoints and + single frame backtracing within the library only. Only works when + using the HPUX 9 dynamic linker. More functionality to be added + soon. + + * somsolib.c, somsolib.h: New files. + * Makefile.in (HFILES_NO_SRCDIR): Add somsolib.h + (ALLDEPFILES): Add somsolib.c. + (somsolib.o): Add some dependencies. + * somread.c (som_symtab_read): Accept multiple section offsets. + All callers changed. Adjust all text symbols with the first + section offset. + * symfile.c (find_lowest_section): Enable this function. Add some + tie-breaking logic when sections have the same vma. + (syms_from_objfile): Use find_lowest_section rather than looking + for ".text" by name. Relax warning to only warn if the lowest + section is not a code section. + * config/pa/{hppabsd.mh, hppahpux.mh} (NATDEPFILES): Add somsolib.o + * config/pa/{nm-hppab.h, nm-hppah.h}: Include somsolib.h. + +Sun Nov 6 12:54:54 1994 Jeff Law (law@snake.cs.utah.edu) + + * partial-stab.h (N_TEXT): Put back GDB_TARGET_IS_HPPA kludge, + it is still needed for GCC-2.6 compiled code. + * TODO (GDB_TARGET_IS_HPPA): Note this kludge can be nuked + sometime after GCC-2.7 has been released. + + * hppa-tdep.c (frame_saved_pc): Mask off low two bits when + retrieving the PC from a signal handler caller. Fix thinko + in Stan's last change ("frame", should have been "frame->next"). + If the next frame is a signal handler caller and it's a system + call which has entered the kernel ((PSW & 0x2) != 0), then the + saved pc is in %r2 instead of %r31. + +Fri Nov 4 23:47:07 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (hppa_frame_find_saved_regs): Change "frame" to + "frame_info" throughout. + +Fri Nov 4 16:26:59 1994 Kung Hsu (kung@mexican.cygnus.com) + + * sparcl-stub.c: get rid of defs.h. + +Fri Nov 4 13:11:54 1994 Jim Kingdon + + * gdbserver/Makefile.in (MMALLOC_CFLAGS): Add -I${MMALLOC_DIR}. + Correct definition of MMALLOC_DIR to reflect fact this is + gdb/gdbserver/Makefile.in, not gdb/Makefile.in. + + * gdbserver/server.c (main): After we kill the inferior in + response to a 'k' request, exit. + + * remote.c (remote_kill): Use catch_errors when calling putpkt. + (putpkt): Return int, not void, to match catch_errors calling + convention. + +Fri Nov 4 10:52:38 1994 Stan Shebs (shebs@andros.cygnus.com) + + * rs6000-tdep.c (pop_frame): Correct a variable name. + +Fri Nov 4 05:43:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Re-write item about SIGINT handling to reflect the fact + that target_stop now exists. + +Thu Nov 3 15:19:17 1994 Stan Shebs (shebs@andros.cygnus.com) + + Replace useless FRAME, FRAME_ADDR types with struct frame_info * + and CORE_ADDR, respectively. + * frame.h (FRAME, FRAME_INFO_ID, FRAME_ADDR): Remove. + * blockframe.c (get_frame_info): Remove. + * a29k-tdep.c, alpha-tdep.c, blockframe.c, breakpoint.c, + breakpoint.h, energize.c, findvar.c, gould-pinsn.c, + h8300-tdep.c, h8500-tdep.c, hppa-tdep.c, i386-tdep.c, i960-tdep.c, + infcmd.c, inferior.h, infrun.c, m68k-tdep.c, m88k-tdep.c, + mips-tdep.c, nindy-tdep.c, printcmd.c, pyr-tdep.c, rs6000-tdep.c, + sh-tdep.c, sparc-tdep.c, stack.c, valops.c, z8k-tdep.c, + config/a29k/tm-a29k.h, config/alpha/tm-alpha.h, + config/gould/tm-pn.h, config/h8300/tm-h8300.h, + config/h8500/tm-h8500.h, config/mips/tm-mips.h, + config/ns32k/tm-merlin.h, config/ns32k/tm-umax.h, + config/pyr/tm-pyr.h, config/sparc/tm-sparc.h): Replace FRAME with + struct frame_info * everywhere, replace FRAME_ADDR with CORE_ADDR, + rename variables consistently (using `frame' or `fi'), remove + calls to get_frame_info and FRAME_INFO_ID, remove comments about + FRAME and FRAME_ADDR cruftiness. + +Thu Nov 3 14:25:24 1994 Stu Grossman (grossman@cygnus.com) + + * corelow.c, exec.c, inftarg.c, m3-nat.c, op50-rom.c, procfs.c, + remote-adapt.c, remote-e7000.c, remote-eb.c, remote-es.c, + remote-hms.c, remote-mips.c, remote-mm.c, remote-mon.c, + remote-nindy.c, remote-os9k.c, remote-pa.c, remote-sim.c, + remote-st.c, remote-udi.c, remote-vx.c, remote-z8k.c, remote.c, + w89k-rom.c, target.c, target.h: Add support for target_stop(). + +Thu Nov 3 01:23:45 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * osfsolib.c (solib_map_sections, first_link_map_member, + next_link_map_member, xfer_link_map_member): Retrieve and use + shared library relocation offset from runtime loader structures. + Use libxproc.a routines to get a working version if + USE_LDR_ROUTINES is defined. + * README: Remove item about shared library relocation for + Alpha OSF/1. + +Wed Nov 2 15:05:39 1994 Kung Hsu (kung@mexican.cygnus.com) + + * c-exp.y (yylex): scan template names, and scan nested class + names. + +Wed Nov 2 11:01:55 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * nlm/Makefile.in: install gdbserve.nlm. + + +Tue Nov 1 13:00:46 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * c-valprint.c (c_value_print): Check for plain literal `char' + target type when suppressing `(char *)' output for strings. + +Mon Oct 31 19:19:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * coffread.c (coff_symfile_init): Remove unused local abfd. + * utils.c [NO_MMALLOC] (mmalloc, mrealloc): Define and use size_t + instead of long, for compatibility with mmalloc.h. + +Sat Oct 29 02:40:40 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * top.c (line_completion_function): Renamed from + symbol_completion_function, takes the line buffer and the + point in the line buffer as additional arguments. + (readline_line_completion_function): New function, interface + between readline and line_completion_function. + (init_main): Use it. + (complete_command): Use line_completion_function instead of + abusing rl_line_buffer. Free completion strings after printing + them. + * symtab.c (completion_list_add_name): Recheck for duplicates + if we intend to add a modified symbol. + + * gdbtypes.h (cplus_struct_type): nfn_fields_total no longer + includes the number of methods from the baseclasses. + * stabsread.c (attach_fn_fields_to_type): No longer add the + number of methods from the baseclasses to TYPE_NFN_FIELDS_TOTAL, + the baseclass type might not have been completely filled in yet. + * symtab.c (total_number_of_methods): New function to compute + the total number of methods for a type, including the methods + from baseclasses. + (decode_line_1): Use it instead of TYPE_NFN_FIELDS_TOTAL to + allocate the symbol array for find_methods. + + * stabsread.c (scan_file_globals): Add default case to minimal + symbol type switch, to avoid gcc -Wall warnings. + + * config/rs6000/tm-rs6000.h (INIT_EXTRA_FRAME_INFO): + Don't test for zero backchain pointer to recognize a signal + handler frame, if read() gets interrupted by a signal, the + backchain will be non zero. + (SIG_FRAME_FP_OFFSET): Move to here from rs6000-tdep.c, + improve comment. + (SIG_FRAME_PC_OFFSET): New definition. + (FRAME_SAVED_PC): Return saved pc from sigcontext if this + is a signal handler frame. + * rs6000-tdep.c (function_frame_info): Do not error out + if we can't access the instructions. + + * config/rs6000/tm-rs6000.h (CONVERT_FROM_FUNC_PTR_ADDR): + New definition to get the function address from a function pointer. + * valops.c (find_function_addr): Use it when calling a user + function through a function pointer. + +Fri Oct 28 16:16:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (MMALLOC_DIR): New definition. + (MMALLOC): Use MMALLOC_DIR. + (MMALLOC_CFLAGS): Look in MMALLOC_DIR for mmalloc.h. + (OPCODES): Remove gratuitous "./". + * defs.h (mmalloc.h): Include. + (mmalloc, mrealloc, etc): Remove decls. + (cplus_demangle, cplus_demangle_opname): Remove decls. + +Wed Oct 26 15:41:07 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h, main.c, top.c: Change sense and name of + no_windows variable. Now called use_windows, and defaults to off + (for compatibility). + +Wed Oct 26 12:20:53 1994 Jim Kingdon + + * coffread.c (coff_symtab_read): If we get the address from + target_lookup_symbol, set the section to -2 not SECT_OFF_BSS. + (coff_symtab_read): Set value and section of symbol that + process_coff_symbol returns. + +Tue Oct 25 09:53:04 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * config/i386/tm-nbsd.h: Enable longjmp support. + +Sat Oct 22 03:41:13 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valarith.c (value_binop): Take care of ANSI `value preserving' + rule, which was not addressed by the previous change. + + * rs6000-tdep.c (skip_prologue): Handle `mr r31,r1', which is + generated by gcc-2.6, as a synonym for `oril r31,r1,0'. + + * TODO: Remove item about RS/6000 shared libraries. + +Thu Oct 20 17:35:45 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h, infrun.c (wait_for_inferior), top.c: Call + target_wait_hook to allow GUI to handle blocking for inferior. Call + call_command_hook in execute_command to provide means for wrapping + commands with GUI state change updates. + + * infrun.c (wait_for_inferior): Make sure + through_sigtramp_breakpoint is non-null before deleting. + +Thu Oct 20 10:26:43 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * config/powerpc/ppc-nw.mt (TDEPFILES): Removed exec.o. + +Thu Oct 20 06:56:07 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (coffread.o): Depend on target.h. + (remote-vx.o): Depend on gdb-stabs.h objfiles.h symfile.h $(bfd_h). + +Wed Oct 19 22:49:31 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Fix typo. + +Wed Oct 19 11:32:15 1994 Jim Kingdon + + * objfiles.c (objfile_relocate): When relocating ->sections, use + objfile not symfile_objfile. + + * symtab.h, minsyms.c (minsyms_sort): New function. + * objfiles.c (objfile_relocate): Call it. + + * remote-vx.c (vx_add_symbols): Call breakpoint_re_set. + + * objfiles.c, objfiles.h (objfile_to_front): New function. + * remote-vx.c (vx_add_symbols): Call it. + + * coffread.c (coff_symtab_read): Handle common symbols the same + way that partial-stab.h does. + +Wed Oct 19 21:06:12 1994 Rob Savoye (rob@cirdan.cygnus.com) + + * hppa-tdep.c: Remove include files a.out.h, ioctl.h, and + machine/psl.h. These are host files. + +Wed Oct 19 15:13:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * objfiles.h (struct objfile): Fix comment--minimal_symbol_count + does *not* include the terminating NULL msymbol. + +Tue Oct 18 20:53:29 1994 Rob Savoye + + * monitor.c (monitor_load_srec,monitor_make_srec): Add an asrecord + loader that reads files using BFD and converts it on the fly. + +Mon Oct 17 18:52:06 1994 Rob Savoye + + * monitor.c (set_loadtype_command): Fixed so it doesn't core dump. + * monitor.c (monitor_load): check the load type and load the file + accordingly. Default to gr_load_image(). + * monitor.c (monitor_load_ascii_srec): Load an ascii file in + srecord format by downloading to the monitor. + * w89k-rom.c, op50n-rom.c: set supported load types. + +Mon Oct 17 10:29:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (ALLDEPFILES): Remove xcoffexec.c. + * Makefile.in: Remove xcoffexec.o rule. + + * exec.c (exec_file_command): Add comment. + + Fix data and bss relocation for VxWorks 5.1: + * remote-vx.c (vx_add_symbols): New function. + (vx_load_command, add_symbol_stub): Call it instead of + symbol_file_add. + (vx_wait): Remove comment which was wrong to useless. + * remote-vx.c: Reindent much of file. + * coffread.c (cs_to_section, find_targ_sec): New functions. + (process_coff_symbol): Set SYMBOL_SECTION to result + from cs_to_section. + (coff_symtab_read): Call cs_to_section and deal with result + rather than assuming sections are in a certain order. Deal with + BSS. + * coffread.c: Remove text_bfd_scnum variable. + +Sat Oct 15 16:55:48 1994 Stan Shebs (shebs@andros.cygnus.com) + + * corelow.c: Format to standard. + (core_close): Use name instead of bfd_filename. + +Fri Oct 14 10:29:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * exec.c (map_vmap): Cast return from xmalloc to its proper type, + not to PTR. + + * symfile.c (reread_symbols): Include bfd_errmsg string in error + message if bfd_close fails. + * exec.c (exec_close), solib.c (clear_solib), corelow.c + (core_close), objfiles.c (free_objfile), irix5-nat.c + (clear_solib), osfsolib.c (clear_solib), remote-utils.c + (gr_load_image): Check for errors from bfd_close. + * solib.c (look_for_base), remote-utils.c (gr_load_image), + remote-udi.c (download), corelow.c (core_open), symfile.c + (symfile_bfd_open), symfile.c (generic_load): Add comment + regarding error from bfd_close. + * remote-udi.c (download), remote-utils.c (gr_load_image): Add + comment about bogus handling of errors from bfd_openr. + * exec.c (exec_close): Add comment regarding memory leak and + dangling reference to vp->name. + +Sat Oct 15 03:43:00 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * eval.c (evaluate_subexp): Make fnptr a LONGEST instead + of using longest_to_int. + + * infcmd.c (run_stack_dummy): Reinstate set_current_frame call, + mips and alpha targets need the real breakpoint pc for + creating the breakpoint frame. + + * stack.c (return_command): Cast return value to the return + type of the function from which we return. + * values.c (set_return_value): Pass VALUE_CONTENTS unmodified + to STORE_RETURN_VALUE. + + * symtab.c (lookup_symbol): Remove search for `static mangled + symbols', the search for `static symbols' already looks for + mangled and demangled symbols via lookup_block_symbol. + + * valarith.c (value_binop): Use ANSI C arithmetic conversions + when performing integral evaluations, implement BINOP_EQUAL and + BINOP_LESS. + (value_equal, value_less): Use value_binop to perform the + comparison if both operands have TYPE_CODE_INT. + + * rs6000-tdep.c (pop_frame): Make sure all registers are valid, + as they are written back later. Handle sp restore for frameless + functions. Use fdata.nosavedpc instead of fdata.frameless to + determine if the pc has been saved. + (function_frame_info): Handle `mr r31,r1', which is generated by + gcc-2.6, as a synonym for `oril r31,r1,0'. + (skip_trampoline_code): Handle shared library trampolines. + * xcoffread.c (read_xcoff_symtabs): Record XMC_GL symbols with + their real name. Enables setting of breakpoints in shared libraries + before the executable is run. + +Fri Oct 14 19:39:47 1994 Rob Savoye + + * monitor.h, remote-mon.c: Hack up to so the old ROM monitor + interface code still works with the new ROM monitor + structures. Fake out a couple of fields. + +Fri Oct 14 14:54:37 1994 Stan Shebs (shebs@andros.cygnus.com) + + * h8500-tdep.c (target_read_sp, target_write_sp, target_read_pc, + target_write_pc, target_read_fp, target_write_fp): Rename to + h8500_read_sp, etc. + (h8500_read_pc, h8500_write_pc): Add pid argument. + * config/h8500/tm-h8500.h (TARGET_READ_SP, TARGET_WRITE_SP, + TARGET_READ_PC, TARGET_WRITE_PC, TARGET_READ_FP, TARGET_WRITE_FP): + Change to match functions above. + +Thu Oct 13 13:24:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * NEWS: Add item about if and while. + + * .gdbinit: Restore `end'; it was not excess. Reindent + list-objfiles to make this clear. Comment out all of + list-objfiles because old gdb's choke on it. + +Wed Oct 12 23:19:08 1994 Ian Lance Taylor + + * config/mips/tm-bigmips64.h: Just define TARGET_BYTE_ORDER and + include tm-mips64.h. + +Wed Oct 12 18:02:17 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (ANNOTATE_OBS): New definition. + (COMMON_OBS): Add exec.o. + (annotate.o): Remove extra compile rule. + * config/*/*.mh, config/*/*.mt: Remove exec.o from *DEPFILES lists + everywhere. + + * .gdbinit: Remove excess `end'. + + * exec.c: Merge in RS6000 support from xcoffexec.c. + (symfile.h, objfiles.h, xcoffsolib.h): Include. + (vmap): New global variable. + (exec_close): Close and free objects in vmap chain. + (exec_file_command) [IBM6000_TARGET]: Set up initial vmap. + (bfdsec_to_vmap, map_vmap): Moved here from xcoffexec.c. + (exec_files_info): Print vmap information. + * xcoffexec.c: Remove. + * config/rs6000/rs6000.mt, config/rs6000/rs6000lynx.mt + (TDEPFILES): Use exec.o instead of xcoffexec.o. + * TODO: Remove pertinent items. + +Wed Oct 12 10:08:19 1994 Jeff Law (law@snake.cs.utah.edu) + + * partial-stab.h (N_TEXT): Delete GDB_TARGET_IS_HPPA kludge; they + are no longer needed as of gcc-2.6.0. + +Tue Oct 11 15:51:01 1994 Ian Lance Taylor + + * lynx-nat.c (child_wait): Correct handling of byte reversed SPARC + Lynx wait status. + (fetch_core_registers): Don't try to fetch a register if + regmap maps it to -1. + * sparc-tdep.c (sparc_frame_find_saved_regs): Use FRAME_SAVED_I0 + and FRAME_SAVED_L0 when setting saved_regs_addr. SPARC Lynx + stores the registers in a weird order. + +Sat Oct 8 20:59:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * blockframe.c (reinit_frame_cache): Reinstate select_frame call + if inferior_pid is nonzero. + +Sat Oct 8 04:27:21 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + Speed up GDB startup time by not demangling partial symbols. + * symfile.h (ADD_PSYMBOL_VT_TO_LIST), + symfile.c (add_psymbol_to_list, add_psymbol_addr_to_list): + No longer demangle partial symbols. + * symtab.c (lookup_symbol, list_symbols): Handle mangled + variables, e.g. C++ static members, via the minimal symbols. + + Handle reordered functions in an objfile, for Irix 5.2 shared + libraries. + * objfiles.h (OBJF_REORDERED): New bit in the objfile flags, + set if the functions in an objfile are reordered. + * mdebugread.c (parse_partial_symbols): Detect reordered + functions in an objfile. + * symtab.c (find_pc_psymtab, find_pc_symtab): Use expensive + lookup algorithm if the functions in the objfile are reordered. + + * xcoffexec.c (exec_close): If the current target has a copy + of the exec_ops sections, reflect the freeing of the sections + in current_target. + + * valops.c (call_function_by_hand): Use `sizeof dummy1', not + `sizeof dummy', for constructing the call dummy code. + + * config/sparc/tm-sparc.h: Add PARAMS declarations to all + function declarations. + * sparc-tdep.c (sparc_pop_frame): Cast result of + read_memory_integer to CORE_ADDR when passing it to PC_ADJUST. + + * irix5-nat.c (enable_break): Set breakpoint at the entry point + of the executable, to handle the case where main resides in a + shared library. + * irix5-nat.c (solib_create_inferior_hook): Reset stop_soon_quietly + after shared library symbol reading, to get rid of a warning from + heuristic_proc_start if the startup code has no symbolic debug info. + + * breakpoint.h (struct breakpoint): Add new fields language + and input_radix, to enable breakpoint resetting with the + proper language and radix. + * breakpoint.c (set_raw_breakpoint): Initialize them. + (breakpoint_re_set_one): Use them when resetting the breakpoint. + (breakpoint_re_set): Preserve current language and input_radix + across breakpoint_re_set_one calls. + + * symtab.c (decode_line_1): Do not build a canonical line + specification for `*expr' line specifications. + + * breakpoint.h (bpstat_stop_status): Fix prototype declaration. + +Fri Oct 7 08:48:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + The point of these changes is to avoid reading the frame pointer + and stack pointer during stepping, to speed things up. + A. Changes to not select a frame until we need a selected frame: + * blockframe.c (flush_cached_frames): Call select_frame (NULL, -1). + * infrun.c (wait_for_inferior): Move call to select_frame back to + normal_stop. This reverts a change of 13 Apr 94 (it says Jeff + Law, but the change was my idea); the only reason for that change + was so we could save and restore the selected frame in + wait_for_inferior, and now that flush_cached frames clears the + selected frame, that should work OK now. + B. Changes to not create a current_frame until we need one: + * blockframe.c (get_current_frame): If current_frame is NULL, try + to create an innermost frame. + * sparc-tdep.c (sparc_pop_frame), infcmd.c (run-stack_dummy), + infrun.c (wait_for_inferior), thread.c (thread_switch), + convex-tdep.c (set_thread_command), a29k-tdep.c (pop_frame), + alpha-tdep.c (alpha_pop_frame), convex-xdep.c (core_file_command), + h8300-tdep.c (h8300_pop_frame), h8500-tdep.c (h8300_pop_frame), + hppa-tdep.c (hppa_pop_frame), i386-tdep.c (i386_pop_frame), + i960-tdep.c (pop_frame), m68k-tdep.c + (m68k_pop_frame), mips-tdep.c (mips_pop_frame), rs6000-tdep.c + (push_dummy_frame, pop_dummy_frame, pop_frame), sh-tdep.c + (pop_frame), config/arm/tm-arm.h (POP_FRAME), + config/convex/tm-convex.h (POP_FRAME), config/gould/tm-pn.h + (POP_FRAME), config/ns32k/tm-merlin.h (POP_FRAME), + config/ns32k/tm-umax.h (POP_FRAME), config/tahoe/tm-tahoe.h + (POP_FRAME), config/vax/tm-vax.h (POP_FRAME): Don't + call create_new_frame. + * corelow.c (core_open), altos-xdep.c (core_file_command), + arm-xdep.c (core_file_command), gould-xdep.c (core_file_command), + m3-nat.c (select_thread), sun386-nat.c (core_file_command), + umax-xdep.c (core_file_command): Don't call create_new_frame; do + call flush_cached_frames. + * blockframe.c (reinit_frame_cache): Don't call create_new_frame + or select_frame. + C. Changes to get rid of stop_frame_address and instead only + fetch the frame pointer when we need it. + * breakpoint.c (bpstat_stop_status): Remove argument + frame_address; use FRAME_FP (get_current_frame ()). + * infrun.c (wait_for_inferior): Don't pass frame pointer to + bpstat_stop_status. + * infrun.c (wait_for_inferior): Use FRAME_FP (get_current_frame + ()) instead of stop_frame_address. + * infrun.c (save_inferior_status, restore_inferior_status), + inferior.h (struct inferior_status): Don't save and restore + stop_frame_address. + * inferior.h, infcmd.c, thread.c (thread_switch), m3-nat.c + (select_thread): Remove stop_frame_address and uses thereof. + D. Same thing for the stack pointer. + * infrun.c (wait_for_inferior): Remove stop_sp and replace + uses thereof with read_sp (). + E. Change to eliminate one nasty little spot where we were + wanting to know the frame pointer from before the current step + (idea from GDB 3.5, which saved my ass, because my other ideas of + how to fix it were very baroque). + * infrun.c: Remove prev_frame_address. + * infrun.c (wait_for_inferior, step_over_function): Use + step_frame_address instead of prev_frame_address. + F. Same basic idea for the stack pointer. + * inferior.h, infcmd.c: New variable step_sp. + * infcmd.c (step_1, until_next_command): Set it. + * infrun.c: Remove prev_sp and replace uses by step_sp. + * infrun.c (wait_for_inferior): If we get out of the step + range, then set step_sp to the current stack pointer before we + start going again. + +Fri Oct 7 12:17:17 1994 Ian Lance Taylor + + * top.c (target_byte_order_auto): New static variable. + (set_endian): Mention that ``auto'' is permitted. + (set_endian_auto): New static function. + (show_endian): Change message based on target_byte_order_auto. + (set_endian_from_file): New function. + (init_main): Add command ``auto'' to endianlist. + * exec.c (exec_file_command): Call set_endian_from_file. + * defs.h (set_endian_from_file): Declare. + +Thu Oct 6 18:10:41 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * nlm/i386.c (flush_i_cache): New function, does nothing. + (frame_to_registers, registers_to_frame, set_step_traps, + clear_step_traps, do_status): Make non-static. + +Thu Oct 6 12:26:42 1994 Ian Lance Taylor + + * config/mips/tm-mips.h (GDB_TARGET_IS_MIPS64): If not already + defined, define as 0. + (FIX_CALL_DUMMY): Rewrite to remove presumption that host and + target are similar. + * config/mips/tm-idt.h (TARGET_BYTE_ORDER_SELECTABLE): Define. + * config/mips/tm-idtl.h (TARGET_BYTE_ORDER_SELECTABLE): Define. + * config/mips/tm-idt64.h (TARGET_BYTE_ORDER_SELECTABLE): Define. + (BREAKPOINT): Remove definition. + * config/mips/tm-idtl64.h (TARGET_BYTE_ORDER_SELECTABLE): Define. + (BREAKPOINT): Remove definition. + * config/mips/tm-mips64.h (GDB_TARGET_IS_MIPS64): Define with a + value of 1, rather than without a value. + * config/mips/tm-bigmips64.h (GDB_TARGET_IS_MIPS64): Likewise. + * mips-tdep.c: Rewrite uses of GDB_TARGET_IS_MIPS64 to switch at + run time rather than at compile time. + + * remote-mips.c (break_insn): Remove. + (BREAK_INSN, BREAK_INSN_SIZE): Define. + (mips_insert_breakpoint): Use BREAK_INSN, not break_insn. + (mips_remove_breakpoint): Likewise. + + * defs.h: If TARGET_BYTE_ORDER_SELECTABLE is defined by tm.h, + define TARGET_BYTE_ORDER as target_byte_order, and declare + target_byte_order as an extern int, and define BITS_BIG_ENDIAN as + a test of TARGET_BYTE_ORDER. + * top.c: Several additions if TARGET_BYTE_ORDER_SELECTABLE is + defined: + (endianlist, target_byte_order): New variables. + (set_endian, set_endian_big, set_endian_little): New functions. + (show_endian): New function. + (init_cmd_lists): Initialize endianlist. + (init_main): Add commands ``set endian big'', ``set endian + little'', and ``show endian''. + * a29k-pinsn.c: Rewrite uses of TARGET_BYTE_ORDER and + BITS_BIG_ENDIAN to switch at run time rather than at compile time. + * coffread.c, dwarfread.c, findvar.c, mips-tdep.c: Likewise. + * remote-os9k.c, stabsread.c, valarith.c, valprint.c: Likewise. + * values.c: Likewise. + +Wed Oct 5 11:41:24 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * nlm/configure.in: ${gdb_host_cpu} defaults to ${host_cpu}. + + * nlm/Makefile.in: Get rid of NWINCLUDES. + * config/{alpha,powerpc}/gdbserve.mt: Remove NWINCLUDES. + User should now configure with --with-headers. + +Mon Oct 3 07:48:34 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/server.c (main): Silently accept all unrecognized + requests and send back a zero length acknowledge. That is what + *-stub.c do and is what remote.c expects. + +Mon Oct 3 05:11:47 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * corelow.c (core_open): Copy the modified to_sections_end + vector from current_target to core_ops too. + + * gdbserver/server.c (main): Silently accept query requests + and send back a zero length acknowledge. + +Fri Sep 30 17:17:21 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * nlm/Makefile.in: Don't define NWINCLUDES. + * config/{alpha,powerpc}/gdbserve.mt: define NWINCLUDES. + +Fri Sep 30 15:59:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/low-lynx.c (create_inferior): Pass all 4 args to ptrace. + +Fri Sep 30 06:42:42 1994 Ian Lance Taylor (ian@cygnus.com) + + * lynx-nat.c (child_wait): Use status.w_status, not status, in + arithmetic. status is a `union wait'. + + * config/nm-lynx.h (PTRACE_ARG3_TYPE): Define to int, not char *. + + * lynx-nat.c (child_wait): Pass fourth argument to ptrace. + +Thu Sep 29 08:22:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): Fix comment for yesterday's change. + +Wed Sep 28 17:48:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * coffread.c (complete_symtab): If last_source_file is set upon + entry, free it. + +Wed Sep 28 08:59:14 1994 Jim Kingdon (kingdon@cygnus.com) + + * xcoffread.c (read_xcoff_symtab, case C_FILE): + Set main_aux before using it. + + * xcoffexec.c (exec_close): If quitting, don't call clear_symtab_users. + + * xcoffread.c (read_xcoff_symtab): Process XTY_LD symbols we were + ignoring before. But continue to ignore XMC_DS. + +Wed Sep 28 00:35:23 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hpread_read_array_type): Do not change the type code + to TYPE_CODE_PTR for "char foo[]". Just make it a zero length + array type. + + * hpread.c (hpread_type_translate): Handle T_UNS_LONG types with + lengths other than 32bits (HP C 9.69 represents an "unsigned char" + as an T_UNS_LONG with length 8). + + * hpread.c (struct hpread_symfile_info): Delete have_module field + and accessor macro. Minor indentation fix. + (hpread_build_psymtabs, case K_MODULE): Only start a new psymtab + and reset state variables have_name & texthigh if pst is NULL. + (hpread_build_psymtabs, case K_SRCFILE): Only reset the name of a + partial symbol table if pst is non-NULL. If pst is NULL, then + start a new psymtab. + (hpread_process_one_debug_symbol, case K_MODULE): Now empty. + (hpread_process_one_debug_symbol, case K_SRCFILE): Simplify and + correct handling of subfiles. + +Mon Sep 26 02:59:00 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * defs.h (misc_command_type): Remove trailing comma from + enumerator list. + +Sun Sep 25 23:19:58 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (frame_saved_pc): Fix thinko in code to dig saved pc + out of an interrupt frame. + +Sun Sep 25 12:50:17 1994 Stan Shebs (shebs@andros.cygnus.com) + + * infcmd.c (do_registers_info) [INVALID_FLOAT]: Only use if + defined. + * values.c (unpack_double) [INVALID_FLOAT]: Ditto. + * mips-tdep.c (mips_print_register): Don't test float validity. + * config/a29k/tm-a29k.h, config/alpha/tm-alpha.h, + config/arm/tm-arm.h, config/convex/tm-convex.h, + config/h8300/tm-h8300.h, config/h8500/tm-h8500.h, + config/i386/tm-i386v.h, config/i386/tm-sun386.h, + config/i960/tm-i960.h, config/m68k/tm-m68k.h, + config/m88k/tm-m88k.h, config/mips/tm-mips.h, + config/ns32k/tm-merlin.h, config/ns32k/tm-nbsd.h, + config/ns32k/tm-ns32km3.h, config/ns32k/tm-umax.h, + config/pa/tm-hppa.h, config/pyr/tm-pyr.h, + config/rs6000/tm-rs6000.h, config/sh/tm-sh.h, + config/sparc/tm-sparc.h, config/z8k/tm-z8k.h (INVALID_FLOAT): + Remove definition. + +Sun Sep 25 06:07:37 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Remove item about adding general multi-threaded stuff; + this is done. + Remove item about specifying arbitrary locations of stack frames + (this works on some machines). + Remove item about debugging functions without a frame pointer + (this works on some machines). + Remove item about re-writing macros which handle frame chaining and + frameless functions. They have been re-written at least once + since that item was written. + Remove item about gdb catching SIGINT when attached; this is done. + Remove item about having list_command not read symbols--why bother? + +Sat Sep 24 17:40:10 1994 Stan Shebs (shebs@andros.cygnus.com) + + * TODO: Append contents of Projects file. + * Projects: Remove. + +Sat Sep 24 01:47:25 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * corelow.c (add_solib_stub): Remove copying of to_sections, + pass current_target to SOLIB_ADD. The Sep 10 change failed + if SOLIB_ADD errored out, or if SOLIB_ADD was trying to access + target memory. + * corelow.c (core_open): After reading the shared libraries, + copy the modified to_sections vector from current_target to + core_ops, so that core_close can free it later. + * config/rs6000/nm-rs6000.h, rs6000-nat.c (xcoff_relocate_core): + Pass down target parameter from SOLIB_ADD and use it instead of + directly accessing core_ops. + +Fri Sep 23 14:58:49 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * solib.c: *BSD systems need to be included before + . + + * i386b-nat.c: Add i386_float_info(), etc. + * config/i386/nm-nbsd.h: #define FLOAT_INFO. + + * config/nm-nbsd.h: New file, for generic NetBSD native support. + * config/i386/nm-nbsd.h: Use it. + * config/sparc/nm-nbsd.h: Use it. + * config/ns32k/nm-nbsd.h: Use it. + + * configure.in (i386-*-netbsd): Use config/i386/nbsd.m[ht]. + (ns32k-*-netbsd): Use config/ns32k/nbsd.m[ht]. + * config/i386/{nbsd.mh,nbsd.mt,nm-nbsd.h,tm-nbsd.h,xm-nbsd.h}: + New files, support for NetBSD/i386. + * config/ns32k/{nbsd.mh,nbsd.mh,nm-nbsd.h,tm-nbsd.h,xm-nbsd.h}: + New files, support for NetBSD/ns32k. + +Tue Sep 20 11:34:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * .gdbinit: Add list-objfiles command. + + * TODO: Reword item regarding NO_STD_REGS. + + * coffread.c (record_minimal_symbol, coff_read_enum_type, + coff_read_struct_type): Allocate on symbol_obstack, not directly + via malloc/savestring. + +Tue Sep 20 15:42:02 1994 Stan Shebs (shebs@andros.cygnus.com) + + * TODO: Add more items. + * tests: Remove the directory and all of its (obsolete) contents. + +Tue Sep 20 11:34:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * coffread.c (init_stringtab): When copying length to stringtab, + use target format, not host format, since that is what the rest of + the code assumes. + +Mon Sep 19 15:48:10 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * Makefile.in: Removed prelude.o, i386-nlmstub.o, nlmstub.o, + nlmstub.nlm, and nlmstub targets. Removed NWSOURCE and + NWINCLUDES definitions. + * i386-nlmstub.c: Removed. + +Mon Sep 19 07:48:36 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (read_dbx_dynamic_symtab): Cast bfd_asymbol_name to + char * (from const char *) before assigning. Don't save string we + pass to record_minimal_symbol (it already saves it). + + +Sat Sep 17 02:26:58 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cp-valprint.c (static_field_print): New variable, controls + printing of static members. + (_initialize_cp_valprint): New print set subcommand + "static-members". Turn on printing of static members by default. + (cp_print_value_fields): Print static members if necessary. + + * solib.c: Remove inclusion of libelf.h and elf/mips.h. + (elf_locate_base): Use only standard BFD functions to collect + information about the .dynamic section. Check for DT_MIPS_RLD_MAP + tag only if it got defined via the inclusion of . + + * f-exp.y: Write block for OP_VAR_VALUE. + * f-valprint.c (info_common_command): Handle `info common' + without an argument correctly. + + * c-typeprint.c (c_type_print_base): Handle template constructors. + * symtab.c (gdb_mangle_name): Handle template method mangling, + get rid of GCC_MANGLE_BUG code, which only applied to gcc-2.2.2. + +Fri Sep 16 16:06:08 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * gdbtypes.h (TYPE_INDEX_TYPE): New macro. + * ch-typeprint.c, ch-valprint.c: Use TYPE_INDEX_TYPE. + * ch-valprint.c (chill_val_print): Pass index type directly + (instead of its TYPE_TARGET_TYPE) to print_type_scalar. + * stabsread.c (read_type): Don't set TYPE_FLAG_TARGET_STUB + if the index type is a stub. + +Fri Sep 16 17:18:44 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/i386/{i386aix.mh, i386bsd.mh, i386lynx.mh, i386sco.mh, + i386sco4.mh, i386sol2.mh, i386v.mh, i386v32.mh, i386v4.mh, + ncr3000.mh, ptx.mh, ptx4.mh}, config/m68k/{altos.mh, apollo68v.mh, + delta68.mh, dpx2.mh, hp300bsd.mh, hp300hpux.mh, m68klynx.mh, + m68kv4.mh}, config/m88k/{delta88.mh, delta88v4.mh}, + config/mips/riscos.mh, config/pa/hppahpux.mh, + config/rs6000/rs6000lynx.mh, config/sparc/{sparclynx.mh, + sun4sol2.mh}, config/tahoe/tahoe.mh, config/vax/{vaxbsd.mh, + vaxult.mh, vaxult2.mh} (REGEX, REGEX1, SYSV_DEFINE): No longer + define. + * config/i386/i386sco4.mh (MUNCH_DEFINE): No longer define. + +Fri Sep 16 15:40:34 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h (QUIT): Call interactive_hook to allow GUI to interrupt. + Also, add decl for symtab_to_filename. + * source.c (symtab_to_filename): New. Returns the file + associated with a symtab. + * top.c: Define interactive_hook. Called during QUIT to animate + the GUI. + +Fri Sep 16 00:14:40 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * stabsread.c (read_type): Handle stub types for bitstrings. + * stabsread.c (read_array_type): Check for stub domain type + using TYPE_FLAG_STUB, not its length. + * gdbtypes.c (create_set_type): Handle a stub domain type. + + * ch-exp.y: Get rid of some extra non-terminals, and move + their rules into primitive_value. + * parser-defs.h: Add comment about unary postfix operators. + * ch-lang.c (chill_op_print_tab): Add '->', postfix and prefix. + * expprint.c (print_subexp): Recognize unary postfix operator. + +Wed Sep 14 18:27:42 1994 Jason Molenda (crash@phydeaux.cygnus.com) + + * remote-hms.c: use remote_debug instead of hms_silent toggle. + Add warnings about depreciation of `snoop' cmd. + +Wed Sep 14 18:18:58 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote-hms.c (hms_read_inferior_memory): Cope when + target sends both \r and \n. + +Wed Sep 14 17:14:57 1994 Stan Shebs (shebs@andros.cygnus.com) + + * remote-mips.c (mips_error): Place NORETURN macro correctly. + * TODO: Add item about START_INFERIOR_TRAPS_EXPECTED. + +Wed Sep 14 14:26:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): Fix obsolete comment about + mst_solib_trampoline. + + * f-valprint.c (f_val_print): Change cast of valaddr from + CORE_ADDR * to char **, since that is how it is used. + + * dbxread.c (read_dbx_dynamic_symtab): Save copy of symbol names + using obsavestring, and pass that to prim_record_minimal_symbol. + Having the objfile point to bfd_asymbol_name directly doesn't work + if we save and restore a mapped symbol file. + + +Tue Sep 13 18:23:26 1994 Rob Savoye (rob@darkstar.cygnus.com) + + * w89k-rom.c, op50-rom.c, monitor.c, config/pa/hppapro.mt: New files + to add a generic ROM monitor interface, and support file for the + WinBond W89K and the Oki OP50N PA based target boards. + + +Sun Sep 11 22:34:57 1994 Jeff Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (REGISTER_NAMES): Use r26-r23 for arg0-arg3. + +Sun Sep 11 04:36:47 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * irix5-nat.c, osfsolib.c, solib.c (solib_add): Simplify last + change by replacing `symbols_added' with `so_last'. + * mdebugread.c (parse_external, parse_partial_symbols): Ignore + global common symbols, they will be resolved by the runtime loader. + * mdebugread.c (parse_symbol, parse_partial_symbols, cross_ref): + Handle scSCommon like scCommon symbols. + +Sat Sep 10 01:43:28 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * corelow.c (add_solib_stub): Copy to_sections changes from + core_ops to current_target after adding the shared libraries. + * partial-stab.h (N_EXCL), dbxread.c (add_old_header_file, + find_corresponding_bincl_psymtab): Change `repeated header not seen' + error to a complaint, simplify complaint. + * procfs.c (signalname, errnoname): Make `name' const. + * symfile.c (reread_symbols): Use filename from old BFD to + reopen the objfile. + * values.c (record_latest_value): Don't record value in the + history chain until we are sure there won't be an error. + +Fri Sep 9 15:52:09 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * nlm/Makefile.in: remove MMALLOC, READLINE, TERMCAP, and other + cruft. + + * config/i386/gdbserve.mt: New file, defs for i386 nlm stub. + +Thu Sep 8 17:14:43 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote.c (fromhex): Make error more explicit. + (read_frame): Don't print bad checksum information unless + remote_debugging. Don't use repeat count unless it's > 0. + * remote-e7000.c (expect): When echoing, ignore multiple newlines. + (e7000_insert_breakpoint, e7000_remove_breakpoint, target_ops): + Optionally cope with BC style breakpoints. + (e7000_command): After command send directly to the E7000 mark + registers as changed. + (why_stop, e7000_wait: Understand BC style stop condition. + * sh-tdep.c (sh_skip_prologue): Understand more complicated + sequences. (frame_find_saved_regs): Likewise. + * config/h8500/tm-h8500.h (target_write_pc, TARGET_WRITE_PC): + Handle extra arg. + * config/i386/xm-go32.h (GDBINIT_FILENAME): Set to gdb.ini. + (more work here to come) + * config/sh/tm-sh.h (EXTRA_FRAME_INFO): Add f_offset and leaf_function + fields. + +Thu Sep 8 16:15:34 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * sparclite/Makefile.in: Assorted stuff needed for eload. + + * sparclite/eload.c: Merge in command line argument parsing and + error message handling improvements orignally made to aload.c. + +Wed Sep 7 23:24:50 1994 Jeff Law (law@snake.cs.utah.edu) + + * defs.h (enum misc_command_type, command_control_type): Enums + for describing the command and control types. + (struct command_line): Add new fields to keep track of the command + type and body associated with the command. + * top.c: Include value.h. Delete whitespace at the end of lines. + (build_command_line, get_command_line): New functions. + (execute_control_command, while_command, if_command): Likewise. + (realloc_body_list, read_next_line): Likewise. + (recurse_read_control_structure): Likewise. + (execute_user_command): Call execute_control_command. + (read_command_lines): Simplify by calling read_next_line, call + read_control_structure for "if" and "while" commands. + (free_command_lines): Free new fields in the command structure. + (define_command): Reset control_level to zero. + (init_main): Install command handlers for "if" and "while" commands. + +Tue Sep 6 16:24:07 1994 Stan Shebs (shebs@andros.cygnus.com) + + * c-typeprint.c (c_type_print_varspec_prefix, + c_type_print_varspec_suffix): Add cases for Fortran type codes. + * eval.c (evaluate_subexp): For OP_ARRAY expressions in Fortran, + call f77_value_literal_string instead. + * f_exp.y: Include , move include of parser-defs.h. + (parse_number): Translate 'd' floats to 'e' so atof() works. + (yylex): Remove unused variables. + * f-lang.c: Include . + (get_bf_for_fcn): Remove unused variable. + * f-typeprint.c (f_type_print_varspec_prefix, + f_type_print_varspec_suffix): Remove unused + variables, add cases to switch statements. + (f_type_print_base): Remove unused variables. + * f-valprint.c (gdbcore.h, command.h): Include. + (f77_get_dynamic_lowerbound, f77_get_dynamic_upperbound): + Call read_memory_integer with correct number of arguments. + (f77_get_dynamic_upperbound): Call f77_get_dynamic_lowerbound + with correct argument type. + (f77_print_array): Removed unused array array_size_array. + (f_val_print): Don't use a CORE_ADDR as a char *. + * valops.c (value_cast): Handle COMPLEX and BOOL types. + (value_assign): Handle Fortran literal string and complex values. + (f77_cast_into_complex, f77_assign_from_literal_string, + f77_assign_from_literal_complex): New functions. + +Mon Sep 5 14:46:41 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-typeprint.c (chill_type_print_base): Make TYPE_CODE_RANGE + case more robust. + +Sun Sep 4 16:06:34 1994 Stan Shebs (shebs@andros.cygnus.com) + + * i960-tdep.c (signal.h): Don't include. + + * cxux-nat.c (target_is_m88110): Remove definition. + + * configure.in (config/nm-empty.h): If cross only, use instead + of config/nm-trash.h. + * config/nm-trash.h: Remove. + * config/nm-empty.h: New file. + * config/i386/nm-m3.h: New file, includes config/nm-m3.h. + * config/mips/nm-m3.h: New file, includes config/nm-m3.h. + * config/m68k/nm-sysv4.h: New file, includes config/nm-sysv4.h. + * config/mips/nm-sysv4.h: New file, includes config/nm-sysv4.h. + * config/sparc/nm-sysv4.h: New file, includes config/nm-sysv4.h. + + +Fri Sep 2 17:35:55 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * configure.in: No longer look for nm, tm, and xm headers in + config/
; they are always in config//
. + +Fri Sep 2 16:40:03 1994 Stan Shebs (shebs@andros.cygnus.com) + + * objfiles.c (allocate_objfile): Add the newly-created objfile to + the end of the list of objfiles, instead of at the beginning. + + * xcoffread.c (allocate_include_entry): New function, abstracted + from code in record_include_begin. + (record_include_begin, record_include_end): Call it. + + * blockframe.c (reinit_frame_cache): Test inferior_pid instead of + target_has_stack to decide whether to create a real stack frame + for the cache. + + * coffread.c (process_coff_symbol) [CXUX_TARGET]: Ignore vendor + section. + * config/m88k/tm-cxux.h (CXUX_TARGET): Define. + + * h8300-tdep.c: Include "dis-asm.h" instead of . + +Fri Sep 2 09:51:46 1994 J.T. Conklin (jtc@cygnus.com) + + * config/sparc/tm-nbsd.h: Add #defines to map NetBSD struct and + field names into what is expected by sparc-nat.c. + +Thu Sep 1 17:32:54 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * c-typeprint.c (c_typedef_print): Add missing Chill support. + +Thu Sep 1 15:41:21 1994 Stu Grossman (grossman@cygnus.com) + + * rs6000-pinsn.c (print_insn): Use powerpc disassembler when + doing Power PC. + * config/powerpc/tm-ppc-nw.h: Define GDB_TARGET_POWERPC. + + * config/i386/i386lynx.mh, config/m68k/m68klynx.mh, + config/rs6000/rs6000lynx.mh, config/sparc/sparclynx.mh: Enable + ser-tcp. + + * nlm/Makefile.in: Get rid of NWSOURCE. + * nlm/alpha-io.S (inVti, outVti): Remove extraneous ldha's. + * nlm/gdbserve.o: Add dummy __main routine. + * nlm/gdbserve.def: Turn on debug. + +Thu Sep 1 12:36:39 1994 Jim Kingdon (kingdon@cygnus.com) + + * config/xm-nbsd.h: Don't define SET_STACK_LIMIT_HUGE; it is obsolete. + +Thu Sep 1 11:01:40 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * config/tm-nbsd.h: New file, support for all NetBSD targets. + * config/xm-nbsd.h: fix typo. + * config/sparc/{nm,tm,xm}-nbsd.h: New files, renamed from + {nm,tm,xm}-sparcnbsd.h to conform to prefered file naming + conventions. + * configure.in: (sparc-*-netbsd): use config/sparc/nbsd.m[ht]. + +Wed Aug 31 14:40:33 1994 Jason Molenda (crash@phydeaux.cygnus.com) + + * remote-udi.c (udi_read_inferior_memory,udi_write_inferior_memory): + change typeo in error msg (`inferrior' -> `inferior'). + +Wed Aug 31 09:17:02 1994 Jim Kingdon (kingdon@cygnus.com) + + * inflow.c (set_sigint_trap, clear_sigint_trap): Check for + attach_flag (this check was performed by the callers). Also check + inferior_thisrun_terminal. + * inftarg.c (child_wait), lynx-nat.c (child_wait), + procfs.c (wait_fd), symm-nat.c (child_wait): Don't check + attach_flag in deciding whether to call set_sigint_trap and + clear_sigint_trap. + + * value.h (struct value): Change literal_data from PTR to char *, + since that is the way it is used. + +Tue Aug 30 21:56:54 1994 Jeff Law (law@snake.cs.utah.edu) + + * somread.c (som_symfile_read): Force unwinds to be re-read after + reading in a new partial symbol table. + +Tue Aug 30 13:14:16 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/h8500/tm-8500.h (DONT_USE_REMOTE): Remove definition, + an obsolete conditional. + * config/pa/tm-hppa.h (BREAKPOINT) [KERNELDEBUG]: Remove use, + an obsolete conditional. + * config/rs6000/rs6000.mh, config/rs6000/rs6000.mt: Clean up + comments. + +Mon Aug 29 14:39:42 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (ns32k-opcode.h): Remove reference. + (ns32k-pinsn.o): Update dependencies. + * ns32k-opcode.h: Remove file. + * ns32k-pinsn.c (print_insn): Call version in libopcodes, remove + all other code in this file. + +Mon Aug 29 12:04:07 1994 Stu Grossman (grossman@cygnus.com) + + * nlm/configure.in: Stop using cpu.c. Put it in TDEPFILES instead. + * config/alpha/gdbserve.mt (TDEPFILES): Remove alpha-patch.o. + + * nlm/Makefile.in: Add rule for .S.o. + * nlm/aio.h: Protect from multiple inclusions. + * nlm/alpha-io.S: Remove everything we don't need. + * nlm/{alpha-patch.c, alpha-patch.h, alpha-uart.c, alpha-uart.h}: + Remove, no longer needed. + * nlm/alpha.c: Merge in lots of stuff from previous files. + * nlm/alpha.h: Don't #include alpha-patch.h. Make + breakpoint_insn extern. + * Move stuff from alpha-patch.h into here. + + * config/alpha/gdbserve.mt (TDEPFILES): Get rid of alpha-uart.o. + +Mon Aug 29 11:34:34 1994 Jim Kingdon (kingdon@cygnus.com) + + * annotate.c (annotate_starting): Flush output. + +Sat Aug 27 23:32:43 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symfile.c (symbol_file_add): Move reinit_frame_cache call to + the callers of symbol_file_add. Gets rid of heuristic fence-post + warnings on mips and alpha targets when the PC resides in a shared + library which is not yet read in. + * coff-solib.c (coff_solib_add), cxux-nat.c (add_shared_symbol_files), + irix5-nat.c (solib_add), osfsolib.c (solib_add), + remote-vx.c (vx_open), solib.c (solib_add): + Add call to reinit_frame_cache after all shared libraries are read in. + * remote-udi.c (udi_load), remote-vx.c (vx_load_command), + symfile.c (symbol_file_command, add_symbol_file_command): + Add call to reinit_frame_cache after symbol_file_add. + +Wed Aug 24 17:45:14 1994 J.T. Conklin (jtc@cygnus.com) + + * config/xm-nbsd.h: New file, support for all NetBSD ports. + * config/sparc/{nm-sparcnbsd.h,tm-sparcnbsd.h,xm-sparcnbsd.h, + sparcnbsd.mh,sparcnbsd.mt}: New files, support for NetBSD/sparc. + * configure.in: Add sparc-*-netbsd target. + +Wed Aug 24 13:17:34 1994 Stan Shebs (shebs@andros.cygnus.com) + + * remote-vx.c (vx_attach): Interpret the command argument as an + unsigned long. + +Wed Aug 24 13:08:08 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * configure.in: Change i[34]86 to i[345]86. + * nlm/configure.in: Likewise. + * gdbserver/configure.in: Likewise. + +Wed Aug 24 09:41:09 1994 J.T. Conklin (jtc@cygnus.com) + + * configure.in (i386-*-netware): Automatically configure nlm + subdir. + +Tue Aug 23 17:51:13 1994 J.T. Conklin (jtc@cygnus.com) + + * nlm/gdbserve.c: conditionalize header file inclusion for either + NetWare 4.0 or PIN targets. + * nlm/i386.c: include appropriate header files. + * nlm/prelude.c: define TERMINATE_BY_UNLOAD for NetWare 4.0 + targets. + +Tue Aug 23 16:54:16 1994 Stu Grossman (grossman@cygnus.com) + + * nlm/ppc.c (set_step_traps clear_step_traps): Cleanups. + * nlm/gdbserve.def: Autoload clib. + +Tue Aug 23 12:05:19 1994 Jim Kingdon (kingdon@cygnus.com) + + * breakpoint.c (condition_command): Call breakpoints_changed. + + * gdbtypes.h: Declare f77_create_literal_string_type and + f77_create_literal_complex_type. + * valops.c (f77_value_literal_string, f77_value_substring, + f77_value_literal_complex): Use xmalloc not malloc. + * valops.c (f77_value_literal_string, f77_value_substring): + Make addr char * not CORE_ADDR. + * value.h (struct value): Add new field literal_data of aligner union. + (VALUE_LITERAL_DATA): Use it. + * f-lang.h: Declare find_common_for_function. + * value.h, valops.c: Split VALUE_SUBSTRING_START into memaddr and + myaddr fields of a union. Don't overload it with the frame field + (not sure this is necessary; I'm not sure what lval_* codes + VALUE_SUBSTRING_* can be used with). + +Mon Aug 22 11:45:01 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/a29k/{a29k-kern.mt,a29k-udi.mt,a29k.mt,ultra3.mh, + ultra3.mt}: Clean up comments, remove no-longer-used definitions. + + * rs6000-nat.c: Include libbfd.h again, needed until reference + to bfd_cache_lookup is cleaned out. + + * config/i386/linux.mh (XM_CLIBS): Add -lm. + +Mon Aug 22 10:42:15 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + Work to reduce the interrupts-off duration when running in DOS. + * ser-go32.c: (dos_async_ready): See if anything is in the buffer. + (dos_async_rx): rewrite to unpack as many characters from the + asynctsr as possible into a local buffer. + +Fri Aug 19 14:55:45 1994 Stan Shebs (shebs@andros.cygnus.com) + + Initial Fortran language support, adapted from work by Farooq Butt + (fmbutt@engage.sps.mot.com). + * Makefile.in: Add Fortran-related files and dependencies. + * defs.h (language_fortran): New language enum. + * language.h (_LANG_fortran): Define. + (MAX_FORTRAN_DIMS): Define. + * expression.h: Reformat to standard. + (MULTI_F77_SUBSCRIPT, OP_F77_UNDETERMINED_ARGLIST, + OP_F77_LITERAL_COMPLEX, OP_F77_SUBSTR): New expression opcodes. + * gdbtypes.h (TYPE_CODE_COMPLEX, TYPE_CODE_LITERAL_COMPLEX, + TYPE_CODE_LITERAL_STRING): New type codes. + (type): New fields upper_bound_type and lower_bound_type. + (TYPE_ARRAY_UPPER_BOUND_TYPE, TYPE_ARRAY_LOWER_BOUND_TYPE, + TYPE_ARRAY_UPPER_BOUND_VALUE, TYPE_ARRAY_LOWER_BOUND_VALUE): New + macros. + (builtin_type_f_character, etc): Declare. + * value.h (VALUE_LITERAL_DATA, VALUE_SUBSTRING_START): Define. + * f-exp.y: New file, Fortran expression grammar. + * f-lang.c: New file, Fortran language support functions. + * f-lang.h: New file, Fortran language support declarations. + * f-typeprint.c: New file, Fortran type printing. + * f-valprint.c: New file, Fortran value printing. + * eval.c (evaluate_subexp): Add code for new expression opcodes, + fix wording of error message. + * gdbtypes.c (f77_create_literal_complex_type, + f77_create_literal_string_type): New functions. + * language.c (set_language_command): Add Fortran info. + (calc_f77_array_dims): New function. + * parse.c (length_of_subexp, prefixify_subexp): Add cases for new + expression opcodes. + * symfile.c (deduce_language_from_filename): Recognize .f and .F + as Fortran source files. + * valops.c (f77_value_literal_string, f77_value_substring, + f77_value_literal_complex): New functions. + +Fri Aug 19 13:35:01 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * c-typeprint.c (c_print_type): Assume demangled arguments + if a '(' is found in varstring, looking for ')' at the end of + varstring did fail with demangled const member functions, which + have a trailing `const'. + * remote.c (get_offsets, putpkt): Change to `char' buffers, + to avoid errors when compiling with DEC c89. + (remote_wait): Cast to `char *' before passing buffer to + fputs_filtered, to avoid errors when compiling with DEC c89. + (remote_wait): Do not return inferior_pid by default, this + statement is never reached, which causes warnings from some + compilers. + * stabsread.c (scan_file_globals): Ignore static minimal symbols. + * symfile.c (load_command): If called with no argument, try + to get the filename from the executable file. + (generic_load): Remove check for NULL filename, it is done + in load_command now. + +Fri Aug 19 10:36:15 1994 Jeff Law (law@snake.cs.utah.edu) + + * Makefile.in (ALLDEPFILES): Add hpread.c. + (hpread.o): Add dependencies. + + * somread.c: Do not include "aout/aout64.h". SOM has nothing to + do with a.out. + (BYTES_IN_WORD): Delete. + (som_symfile_read): Call hpread_build_psymtabs to build any + minimal symbols based on the HP C native debug symbols. + (som_symfile_finish): Call hpread_symfile_finish. + (som_symfile_init): Call hpread_symfile_init. + * config/pa/tm-hppa.h (HPREAD_ADJUST_STACK_ADDRESS): Define. + * hppa-tdep.c (hpread_adjust_stack_address): New function. + + * config/pa/hppabsd.mh (NATDEPFILES): Add hpread.o + * config/pa/hppahpux.mh (NATDEPFILES): Likewise. + * hpread.c: New file. + +Fri Aug 19 00:40:55 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (skip_trampoline_code): Revert incorrect change + from June 2, 1994 (what was I thinking?!?). Fix it right this + time. + +Thu Aug 18 17:01:35 1994 J.T. Conklin (jtc@rtl.cygnus.com) + + * nlm/i386.c, nlm/i386.h: New files that contain i386 specific code. + +Thu Aug 18 14:39:46 1994 Stan Shebs (shebs@andros.cygnus.com) + + * README: Grammar improvements, clarifications, updates. + +Wed Aug 17 23:08:53 1994 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (TARGET_FLAGS_TO_PASS): Pass down LD_FOR_TARGET and + NLMCONV_FOR_TARGET. (SUBDIRS): Add nlm target. + * configure.in (powerpc-*-netware*): Automatically configure nlm + subdir. + * nlm/Makefile.in: Add {CC NLMCONV LD}_FOR_TARGET. Remove alpha + specific stuff. Make things more configurable. + * nlm/configure.in: Add powerpc-*-netware* target. Use + gdbserve.mt/cpu.c/cpu.h for target stuff. Get rid of tm/xm/nm.h + files. + * nlm/gdbserve.c: Move Alpha specific stuff into other files. + Remove lots of architecture-specific stuff. + * nlm/gdbserve.def: Add new imports. + * nlm/ppc.c, nlm/ppc.h: New files that contain PowerPC specific code. + * nlm/prelude.c: Don't include libhooks.h, get rid of call to + register library. + * nlm/prelude.o: What was this doing here? + * config/alpha/gdbserve.mt: Defs for alpha nlm stub. + * config/powerpc/gdbserve.mt: Defs for PowerPC nlm stub. + * config/powerpc/ppc-nw.mt: Defs for PowerPC target for GDB. + * config/powerpc/tm-ppc-nw.h: Ditto. + + * nlmstub.def: New file, contains imports for 386 nlm stub. + +Wed Aug 17 23:17:33 1994 Rob Savoye (rob@darkstar.cygnus.com) + + * remote-pa.c: New file for HPPA embedded support. Currently it's + a copy of remote.c. + * config/pa/hppabsd.mt,hppahpux.mt,hppaosf.mt: User remote-pa.c. + +Wed Aug 17 13:19:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/m68k/tm-delta68.h (EXTRACT_RETURN_VALUE, + STORE_RETURN_VALUE): Define to use %a0 for pointers. + +Wed Aug 17 07:43:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-mips.c: Remove unused declaration of mips_load. + +Tue Aug 16 16:45:34 1994 Stan Shebs (shebs@andros.cygnus.com) + + * coffread.c: General cleanup, and support for section offsets. + (time.h, sys/types.h, libbfd.h): Don't include. + (cur_src_start_addr, cur_src_end_addr): Rename to + current_source_start_addr, current_source_end_addr. + (nlist_stream_global): Remove. + (nlist_bfd_global): New global variable. + (coff_symfile_read): Remove code that gets and uses fileno() + directly. + (read_coff_symtab, enter_linenos, process_coff_symbol): Add + section_offsets parameter, add text/data section offset to + appropriate symbols' values. + (read_one_sym): Use bfd_read instead of fread. + (init_stringtab, init_lineno): Change first parameter to a bfd, + use bfd routines instead of raw I/O. + +Tue Aug 16 15:24:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.c (decode_line_1): If funfirstline and we get a + non-LOC_BLOCK symbol (e.g. variable or type), then error(). + + * Makefile.in (TARFILES, NONSRC, SFILES_STAND, SFILES_KGDB): + Remove; unused. + (TAGFILES_NO_SRCDIR): Remove ALLPARAM. + (HFILES_NO_SRCDIR): Remove all files in config sub-directory. + (TAGS): Also pass result of find on config sub-directory to etags. + (ALLPARAM): Remove; now unused. + +Sun Aug 14 13:05:26 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.13.1 + * NEWS, README: Update to match gdb 4.13 release version. + +Sat Aug 13 08:22:50 1994 Fred Fish (fnf@cygnus.com) + + Harris CX/UX support, from Bob Rusk (rrusk@mail.csd.harris.com). + * cxux-nat.c: Remove dangling #else block. + (m88k_harris_core_register_addr): New function. + + * environ.c (init_environ): If no environment, do nothing. + +Fri Aug 12 19:30:53 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Delete rest of TODO list. Do not include "libbfd.h", + , , "demangle.h", , + "expression.h", "language.h", "gdbtypes.h", "demangleh". + Move all global variables into the private symbol table structure + and add accessor macros. Update some comments. + (hpread_build_psymtabs): Delete dbsubc_addr, we don't need it. + (hpread_end_psymtab): New function to end a partial symbol table, + all callers changed (no more bogus sharing with dbxread.c). + +Fri Aug 12 15:52:37 1994 Stu Grossman (grossman@cygnus.com) + + * remote.c (remote_wait): Return inferior_pid instead of 0 for + `W` message. + +Fri Aug 12 11:47:10 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * sparclite/aload.c (sys_error, error): Use vfprintf for variable + argument lists. + +Thu Aug 11 04:06:42 1994 Doug Evans (dje@canuck.cygnus.com) + + * defs.h (concat, basename, buildargv, freeargv, strerrno, strsigno, + errno_max, signo_max, strtoerrno, strtosigno): Delete. + Include "libiberty.h" instead. + +Wed Aug 10 13:23:47 1994 Rick Sladkey (jrs@world.std.com) + + * i386v-nat.c (i386_insert_nonaligned_watchpoint): + add additional argument specifying raw address to permit + proper release of debug registers. + (i386_insert_watchpoint, i386_insert_aligned_watchpoint): + change all callers. + +Wed Aug 10 16:13:45 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h, top.c: Use `extern' in declarations of GUI hooks, and + define them in top.c. Add comments to the hooks. + +Wed Aug 10 15:57:43 1994 Doug Evans (dje@canuck.cygnus.com) + + * remote-sim.c (gdbsim_ops): Set `to_insert_breakpoint' and + `to_remove_breakpoint' fields. + +Wed Aug 10 15:46:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infcmd.c (run_command): Remove comment suggesting using + target_has_execution instead of inferior_pid. + +Wed Aug 10 10:33:20 1994 Kung Hsu (kung@mexican.cygnus.com) + + * remote-mips.c (mips_open): add code to handle baud rate. + +Tue Aug 9 09:44:42 1994 Stu Grossman (grossman@cygnus.com) + + * infrun.c (wait_for_inferior): Call target_resume() upon + detection of new processes. + + * procfs.c (create_procinfo): Return pointer to new procinfo + structure. + * (do_detach): Spacing & formatting cleanup. + * (procfs_wait): Move wait_again label to ensure that we really + wait again. On exit from fork, release new child from gdbs' + clutches. + * (procfs_set_sproc_trap): Enable trapping of fork and vfork. + +Mon Aug 08 15:34:13 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hpread_process_one_debug_symbol): Fix block scoping + problem (losing localvars on the close-brace instead of after + the close brace). + +Mon Aug 8 15:09:32 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * i386-nlmstub.c (handle_exception): Wait until the thread has + been started before killing the NLM by pointing the PC at + _exit(). + +Sat Aug 6 22:27:30 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/tm-irix5.h (IN_SIGTRAMP): Redefine for Irix 5, + Irix 5 has a standard _sigtramp signal handler. + * irix5-nat.c (solib_add): Get rid of sigtramp_address handling, + it is not needed for a standard _sigtramp signal handler. + Add shared library sections to the section table of the target + before adding the symbols. + * mips-tdep.c (mips_skip_prologue): Do not skip load immediate + instructions that do not prepare a stack adjustment. + * regex.c (SIGN_EXTEND_CHAR): Update to emacs-19.25 definition, + which does the right thing on machines where `char' is unsigned. + +Fri Aug 5 17:50:59 1994 Stu Grossman (grossman@cygnus.com) + + * remote.c (remote_open): Move setting of inferior_pid prior to + call to remote_start_remote. Also use unique value for pid to + avoid confusion with read_register_pid & friends. + * (remote_wait): Return inferior_pid instead of 0 in all cases. + +Fri Aug 5 12:23:02 1994 Stan Shebs (shebs@andros.cygnus.com) + + * dwarfread.c (bfd.h): Don't include. + +Fri Aug 5 09:08:34 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * i386-nlmstub.c (handle_exception): Point the PC at _exit() to + kill the program being debugged. KillMe(), the undocumented + call intended for this purpose, causes the server to hang. + +Thu Aug 4 16:26:06 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote.c (read_frame): Calculate run length encoded checksum + correctly. + * config/sh/stub.c: New file. + +Thu Aug 4 14:34:12 1994 Stu Grossman (grossman@cygnus.com) + + * target.c (find_default_run_target): Make sure to_can_run is set + before calling it. + +Thu Aug 4 11:46:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * TODO: Remove note about fast watchpoints and remove obsolete + Mach stuff. + +Thu Aug 4 11:08:03 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/i386/xm-i386v4.h, config/m68k/xm-m68kv4.h, + config/sparc/xm-sun4sol2.h (NORETURN): Don't define. + * config/m88k/tm-cxux.h (ARCH_NUM_REGS): Undefine before defining. + +Thu Aug 4 10:26:36 1994 Stu Grossman (grossman@rtl.cygnus.com) + + * target.c (add_target): Don't call clean_target on target + vectors anymore. + * (unpush_target): Test for to_close being set before calling. + * (target_xfer_memory, target_info): Check for to_has_memory + before playing with memory. + + * remote.c (remote_open): Set inferior_pid to make kill command + happy. + * inflow.c (kill_command): Revert change of Aug 2. Use + inferior_pid to determine whether to print out "The program is not + being run." message. + +Thu Aug 4 07:55:04 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/i386m3.mh (NAT_CLIBS): Add -lmachid and -lnetname. + * m3-nat.c, config/nm-m3.h: #if 0 REQUEST_QUIT stuff. + * m3-nat.c: Pass argument to return_to_top_level. + Declare m3_kill_inferior before use. + (port_chain_insert): In "can't happen" case, abort rather than + setting `mid' to large decimal constant (which gcc warns about). + (get_thread_name): Use cast to convert const char * to char *. + (add_mach_specific_commands): #if 0 "thread break" command. + (m3_trace_him): Call push_target. + (mach_really_wait): New argument pid; remove unused + variable pid. + (intercept_exec_calls): Call target_terminal_init and + target_terminal_inferior once the child execs. + * infrun.c (proceed): Pass argument to PREPARE_TO_PROCEED. + +Wed Aug 3 22:41:13 1994 Tom Lord (lord@x1.cygnus.com) + + * procfs.c (procfs_mourn_inferior): don't dereference the + procinfo pointer after it has been freed. + +Wed Aug 3 12:05:13 1994 Stan Shebs (shebs@andros.cygnus.com) + + * breakpoint.c (breakpoint_1): Improve pluralization in display + of breakpoint hit counts. + + * language.h (struct language_defn): Remove unused field + la_longest_float. + (longest_float): Remove, no longer used. + * language.c (unknown_language_defn, auto_language_defn, + local_language_defn): Remove init of la_longest_float field. + * c-lang.c (c_language_defn, cplus_language_defn, + asm_language_defn): Ditto. + * ch-lang.c (chill_language_defn): Ditto. + * m2-lang.c (m2_language_defn): Ditto. + +Tue Aug 2 10:58:34 1994 Stan Shebs (shebs@andros.cygnus.com) + + * defs.h (bfd_read, bfd_seek): Remove declarations. + * os9kread.c, rs6000-nat.c (libbfd.h): Don't include. + +Tue Aug 2 09:50:50 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * inflow.c (kill_command): Fix a bug which prevented target + programs to be killed. + +Mon Aug 1 18:48:47 1994 Stan Shebs (shebs@andros.cygnus.com) + + * defs.h: Change two-line declarations to one-line form. + (NORETURN): Define as "volatile" only for older GCCs. + (ATTR_NORETURN): Define for newer GCCs. + * procfs.c (proc_init_failed): Add ATTR_NORETURN to declaration. + +Mon Aug 1 16:43:24 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (mention), main.c (fputs_unfiltered): Add comments. + * breakpoint.c (delete_breakpoint, enable_breakpoint, + disable_breakpoint): Don't call breakpoints_changed; it is now + called via the *_breakpoint_hook functions. + * annotate.c (_initialize_annotate, breakpoint_changed): New functions. + +Mon Aug 1 13:38:04 1994 Kung Hsu (kung@mexican.cygnus.com) + + * stabsread.c (read_type): Fix a bug in enum size calculation. + +Mon Aug 1 01:36:13 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (compare_unwind_entries): Add "const" to both + argument types to shut up GCC. + + * hppa-tdep.c (saved_pc_after_call): If the saved PC is in a + linker stub, then return the address the stub will return to. + (frame_saved_pc): Correctly restart the search for the saved + pc when a linker stub is encountered. + + * hppa-tdep.c (inst_saves_gr): Handle 16 and 8 bit instruction + register stores emitted by the version 9 HP compilers. + (inst_saves_fr): Relax test for a specific base register (%r1); + this avoids losing with the version 9 HP compilers. + (skip_prologue): Try to skip argument stores emitted by the HP + compilers. It's not perfect, but it's better than before. + +Fri Jul 29 23:20:30 1994 Stu Grossman (grossman@cygnus.com) + + * findvar.c (write_pc write_pc_pid): Remove casts to long when + calling write_register_pid. + * (write_register_pid): Add prototype. + +Fri Jul 29 21:56:23 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * remote.c (read_frame): Split readchar/checksum calculation into + two parts since evaluation order is undefined. + +Fri Jul 29 13:46:08 1994 Fred Fish (fnf@cygnus.com) + + From Kevin A. Buettner (kev@cujo.geg.mot.com). + * Makefile.in (coredep.o): Add inferior.h as dependency. + * inflow.c: Add F_SETOWN to list of defines to check + around code that uses F_SETOWN. + +Fri Jul 29 09:59:05 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * Makefile.in (CC_FOR_TARGET, CXX_FOR_TARGET): If using newlib, + set the -L and -B directory prefixes so we can link with it. + +Thu Jul 28 14:37:36 1994 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (INSTALLED_LIBS, CLIBS, DEPFILES): Add support for + --enable-xxx configure option by adding ENABLE_{CLIBS DEPFILES} + where appropriate. + + * General hackery to support alternate user-interface. + * breakpoint.c (mention, delete_breakpoint, enable_breakpoint, + disable_breakpoint): Call hooks for alternate user-interface. + * defs.h: Add declarations for alternate user-interface hooks. + * main.c (main): Add --nw (and --nowindows) options to disable + the GUI. + * (near call to command_loop): Call command_loop_hook if set. + * (fputs_unfiltered): Call fputs_unfiltered_hook if set. + * stack.c: Call print_frame_info_listing_hook if set. + * top.c (gdb_init): Initialize targets.c and utils.c prior to + other files to make sure that calls to error and warning will + work. Call init_ui_hook after everything else. + * utils.c (query): Call query_hook if set. + * (gdb_flush): Call flush_hook if set. + * Change _initialize_utils to initialize_utils cuz we don't use + automatic initialization of utils.c anymore. + + + * remote.c: Get rid of #ifdef DONT_USE_REMOTE. It's no longer + necessary. + +Thu Jul 28 14:52:01 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * Makefile.in (CC_FOR_TARGET, CXX_FOR_TARGET): Use newlib if it is + there and we are using the gcc from the tree. + (LD_FOR_TARGET): Look for ld in ../ld/ld.new. + +Thu Jul 28 10:43:36 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (annotate.o): Add dependencies. + +Wed Jul 27 14:34:42 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * sparclite/aload.c: Added new -q (quiet) option. + return 0 exit status if file was successfully downloaded. + + * nlm/gdbserve.c: merge in command line argument parsing changes + and bug fixes made to i386-nlmstub.c. + + * i386-nlmstub.c: The returnLength field must be initialized + before portConfig is passed to AIOGetPortConfiguration. + Compare command line arguments with strnicmp(); args are + case insensitive on netware. + +Wed Jul 27 09:24:19 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (DISTSTUFF): Add definition. + (diststuff): Add for new distribution support. + (gdb.tar.Z, make-proto-gdb.dir, setup-to-dist, + gdb-$(VERSION).tar.Z, make-proto-gdb-1, make-proto-testsuite.dir): + Remove old distribution building rules, now uses standard + distribution support in parent directory Makefile.in. + +Tue Jul 26 14:15:53 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.c (push_target): Cast result from xmalloc. + +Tue Jul 26 18:20:46 1994 Paul Flinders (ptf@smee) + + * elfread.c (elf_symtab_read): Discard compiler labels generated + by the Solaris 2.1/Intel SunPro compiler. + +Mon Jul 25 18:19:24 1994 Stu Grossman (grossman@cygnus.com) + + * target.c (nomemory): Fix prototype and routine to take correct + args. + +Mon Jul 25 15:38:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (clean): Remove libgdb-files. + +Mon Jul 25 11:50:57 1994 Stan Shebs (shebs@andros.cygnus.com) + + * coredep.c: Include inferior.h. + +Mon Jul 25 11:36:02 1994 J.T. Conklin (jtc@phishhead.cygnus.com) + + * i386-nlmstub.c: Add support for NODE, PORT and BAUD command + line arguments. + +Sat Jul 23 14:36:09 1994 Stan Shebs (shebs@andros.cygnus.com) + + * symfile.c (deduce_language_from_filename): Recognize .S as asm, + .cp as C++, alphabetize better. + + * breakpoint.c (ignore, condition): Move usage note into body of + help text, so first line can be one-line summary. + +Sat Jul 23 00:58:15 1994 Stu Grossman (grossman@cygnus.com) + + * target.c (unpush_target): Fix handling of removal of top target. + +Fri Jul 22 17:30:39 1994 Stu Grossman (grossman@cygnus.com) + + * Makefile.in: Add stuff to build nlmstub. + * Add rule for annotate.o to keep Sun make happy. + * configure.in: Add config for powerpc/Netware. + + * partial-stab.h (near N_SO): Don't call START_PSYMTAB with null + filename. This speeds up handling of trailing N_SO stabs (they + mark the end of a .o file). + + * target.c, target.h: Change the way pushing and popping of + targets work to support target overlays and inheritance. + * corelow.c, hppa-tdep.c, inflow.c, remote-nindy.c, utils.c: + Fixup references to current_target, due to previous changes. + + * config/i386/tm-i386nw.h: Enable longjmp support. More work is + needed to get the address of longjmp out of the target. + +Tue Jul 19 13:25:06 1994 Stan Shebs (shebs@andros.cygnus.com) + + * main.c: Include . + +Mon Jul 18 15:32:17 1994 Kung Hsu (kung@mexican.cygnus.com) + + * remote-mips.c (mips_readchar): Fix a bug in checking + prompt. + +Mon Jul 18 14:26:35 1994 Stan Shebs (shebs@andros.cygnus.com) + + * solib.c (look_for_base): Don't deref exec_bfd if NULL. + +Sun Jul 17 15:38:36 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.12.4. + +Sun Jul 17 12:20:35 1994 Stan Shebs (shebs@andros.cygnus.com) + + Harris CX/UX support, from Bob Rusk (rrusk@mail.csd.harris.com). + * configure.in (m88*-harris-cxux*): New configuration. + * cxux-nat.c, config/m88k/cxux.mh, config/m88k/cxux.mt, + config/m88k/xm-cxux.h, config/m88k/tm-cxux.h, config/m88k/nm-cxux.h: + New files. + * config/m88k/tm-m88k.h: Add comment about Harris OS. + (TARGET_WRITE_PC): Pass pid through to register writers. + + * configure.in (m68*): Put vendor-only-specified host configs + after vendor-and-os-specified configs. + (m68*-atari-sysv4*, m68*-cbm-sysv4*): Replace with m68*-*-sysv4. + + * config/m88k/delta88.mh (MUNCH_DEFINE): Remove. + * config/m88k/delta88.mt, config/m88k/delta88v4.mh: Format + consistently. + +Sat Jul 16 23:39:17 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * elfread.c (elf_symtab_read): Handle error return from + bfd_get_dynamic_symtab_upper_bound gracefully. + +Sat Jul 16 14:43:17 1994 Stan Shebs (shebs@andros.cygnus.com) + + * inferior.h (ARCH_NUM_REGS): New macro, actual number of + registers in use by the inferior. + * coredep.c (fetch_core_registers, register_addr): Use it. + * findvar.c (registers_changed, registers_fetched, + read_register_bytes): Ditto. + * infcmd.c (do_registers_info, registers_info): Ditto. + * infptrace.c (fetch_inferior_registers, + store_inferior_registers): Ditto. + * stack.c (frame_info): Ditto. + + * coredep.c (CORE_REGISTER_ADDR): New macro. + (fetch_core_registers): Use it. + + * breakpoint.c (ignore, condition): Add usage notes to help strings. + * symfile.c (add-symbol-file): Add usage note to help string. + (add_shared_symbol_files_command): New command. + + gcc -Wall lint. + * inferior.h (read_pc_pid): Declare. + * breakpoint.c (watchpoint_check): Cache breakpoint in local + variable b, remove unused variable other_type_used. + * main.c (inferior.h, call-cmds.h): Include. + (gdb_init): Declare. + * remote.c (remote_wait): Return 0 by default. + +Fri Jul 15 16:43:33 1994 Stan Shebs (shebs@andros.cygnus.com) + + Stop printing at null char option, from Oliver Meyer + (omeyer@i3.informatik.rwth-aachen.de). + * valprint.h, valprint.c (stop_print_at_null): New global. + * valprint.c (_initialize_valprint): New print set subcommand + "null-stop". + * c-valprint.c (c_val_print): If stop_print_at_null is on, and + printing a char array, adjust the number of chars to print. + +Fri Jul 15 14:33:40 1994 Stan Shebs (shebs@andros.cygnus.com) + + From Kevin A. Buettner (kev@cujo.geg.mot.com). + * m88k-tdep.c (examine_prologue): Modified to handle prologues for + pic code in addition to prologues where an instruction from the + prologue gets moved into the delay slot of a branch instruction + immediately following the prologue. A table of potential prologue + instructions (prologue_insn_tbl) is now used for picking apart a + function prologue. + (frame_find_saved_regs): Changed the way in which limit gets set + so that the delay slot of branch instructions immediately + following the prologue gets examined. + (pushed_size, store_parm_word, store_parm, push_parameters, + collect_returned_value): Deleted. + +Fri Jul 15 01:06:00 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (wait_for_inferior): Handle stepping into leaf + functions whose prologue consists of gp loading code only. + +Thu Jul 14 14:22:12 1994 Stan Shebs (shebs@andros.cygnus.com) + + * dbxread.c: Don't include libbfd.h. + * dwarfread.c, elfread.c somread.c: Don't include libbfd.h, + , or . + * elfread.c (elf_symfile_read): Use only standard BFD functions to + collect information about the stab and stab string sections. + +Thu Jul 14 13:17:39 1994 Kung Hsu (kung@x1.cygnus.com) + + * stabsread.c (read_huge_number): handle large unsigned number + for stabs generated by os9k C compiler. + +Wed Jul 13 18:58:15 1994 Stan Shebs (shebs@andros.cygnus.com) + + Breakpoint hit counts, from Bob Rusk (rrusk@mail.csd.harris.com). + * breakpoint.h (hit_count): New breakpoint field. + * breakpoint.c (show_breakpoint_hit_counts): New variable. + (clear_breakpoint_hit_counts): New function. + (bpstat_stop_status): Increment the hit count. + (breakpoint_1): Display the hit count. + * infcmd.c (run_command): Reset breakpoint hit counts. + * target.c (generic_mourn_inferior): Don't clear ignore counts if + displaying hit counts. + +Tue Jul 12 12:23:15 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * elfread.c (elf_symfile_read): Unconditionally add dynamic + symbols for all symbol files. Makes skipping over the + trampoline code work when stepping from a function in a shared + library into a function in a different shared library for Irix 5. + Other ELF targets do not have enough information in their + dynamic symbol tables to make this work. + (elf_symtab_read): Relocate mst_solib_trampoline address. + +Mon Jul 11 16:38:49 1994 Stan Shebs (shebs@andros.cygnus.com) + + Atari support, from Uwe Seimet (seimet@chemie.uni-kl.de). + * configure.in (m68*-atari-sysv4*): New configuration. + (m68*-cbm-sysv4*): Use m68kv4 instead of amix. + * m68k-tdep.c (R_PS): Define as R_SR if necessary. + * config/m68k/m68kv4.mh, config/m68k/m68kv4.mt, + config/m68k/tm-m68kv4.h, config/m68k/xm-m68kv4.h: New files. + * config/m68k/amix.mh, config/m68k/amix.mt, + config/m68k/tm-amix.h, config/m68k/xm-amix.h: Removed, superseded + by m68kv4 files. + +Sat Jul 9 16:28:43 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.c (find_function_start_sal): New function to find + the start of a function from a function symbol. + (decode_line_1, decode_line_2): Use it instead of open coded + partial copies of the code. + (list_symbols): Quote symbol name before passing it to + break_command to enable proper handling of mangled symbols. + +Wed Jul 6 20:22:07 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-exp.y (match_simple_name_string): Don't lower-case here. + * ch-exp.y (yylex): First try name lookup using exact name + typed by user; if that fails, try lower-cased name. + +Wed Jul 06 12:39:07 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: More cleanups. Delete lots of trailing whitespace. + Remove some items from the TODO list and notes throughout code + for things which need fixing. Add more comments. + Document bogus struct symloc sharing with dbxread.c. Delete more + useless variables. Add more PARAM prototypes. Fixup more + indention problems that have crept in. + (SET_NAMESTRING): Accept new namep and objfile arguments so that + it doesn't depend on the variable names on the procedures it's + used from. + (hpread_symfile_init): Delete incorrect checks for bogus sizes of + the debug sections. + +Wed Jul 6 00:48:57 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c, elfread.c, mipsread.c, nlmread.c, os9kread.c: + Move "no debugging symbols found" test to symfile.c. + * symfile.c (syms_from_objfile, reread_symbols): Add + "no debugging symbols found" test. + * coffread.c (init_stringtab): Handle stripped files with a + stringtab offset of zero gracefully. + * osfsolib.c (solib_create_inferior_hook): Use DYNAMIC flag from + BFD instead of stop_pc heuristic to determine if it is a dynamically + linked object file. + * procfs.c (wait_fd): Handle ENOENT error return from PIOCWSTOP + ioctl, it indicates that the process has exited. + +Mon Jul 04 19:48:03 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hpread_symfile_init): Make sure to initialize all the + private data to zero. Not having any HP C debug symbols is not an + error. Just return. + +Mon Jul 4 19:28:56 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (read_unwind_info): ELF unwind information is in the + .PARISC.unwind section now. + +Mon Jul 4 17:06:26 1994 Stan Shebs (shebs@andros.cygnus.com) + + * breakpoint.c (mention): Always show breakpoint address if no + source file. + +Sat Jul 2 01:51:33 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * solib.c (bfd_lookup_symbol, look_for_base): Reinstate to reenable + handling of shared libraries for non-ELF executables, but only if + HANDLE_SVR4_EXEC_EMULATORS is defined. + (locate_base): Try to find debug_base in the dynamic linker + for non-ELF executables if HANDLE_SVR4_EXEC_EMULATORS is defined. + * config/sparc/tm-sun4sol2.h (HANDLE_SVR4_EXEC_EMULATORS): + Define to enable handling of shared libraries for a.out executables, + run under Solaris BCP. + +Fri Jul 01 19:50:21 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c: Change contribution notice to the Cygnus/Utah agreed + upon notice. Delete some stuff from the TODO list. Rework + many comments to be clearer. Major cleanups. Consistently + use "hpread_" prefix. Delete unnecessary macros, structures + variables, fiels, functions and #if 0 code. Mark code which + still needs to be cleaned up. PARAMize and make most functions + static. Fix error checking when reading in the debug section + contents. No more minimal symbol table handling in this code! + +Thu Jun 30 13:59:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Print "Program exited normally" + regardless of batch_mode. + * defs.h, top.c (batch_mode): Removed. + +Wed Jun 29 18:53:36 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (dcache_h): Remove redundant definition. + (init.c): Add a comment. + (top.c): Remove explicit compile action. + * breakpoint.c (mention): Share code indicating location of + break/watchpoints, don't print address if addressprint is off. + * breakpoint.c, c-typeprint.c, c-valprint.c, energize.c, symtab.h + (demangle): Remove redundant declarations. + * eval.c: Remove redundant function declarations. + * objfiles.h: Cosmetic and grammatical improvements. + * TODO: Various updates. + + * remote-mips.c: Replace all \r chars with \015. + (mips_receive_header): Display control characters readably. + (mips_xfer_memory): Add a simple progress display. + +Wed Jun 29 13:11:45 1994 Steve Chamberlain (sac@cirdan.cygnus.com) + + * remote-e7000.c (e7000_open): Don't try a tcp open if we're + using go32. + * remote-hms.c (flush): New function. + (expect): Get edge case right. + (hms_read_inferior_memory): Be more tolerant of line noise. + +Tue Jun 28 14:17:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * configure.in: Use i386m3.mh and i386m3.mt as names of host and + target files, not non-existent mach3.mh and mach3.mt. + +Wed Jun 29 00:26:17 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (dbx_symfile_read): Unconditionally add dynamic + symbols for all symbol files. Makes skipping over the + trampoline code work when stepping from a function in a shared + library into a function in a different shared library. + (read_dbx_dynamic_symtab): Relocate mst_solib_trampoline address. + +Tue Jun 28 15:28:01 1994 Stu Grossman (grossman@cygnus.com) + + * dbxread.c, partial-stab.h (near N_SO): SO stabs with blank + names mean end of .o file. + * infrun.c (wait_for_inferior): Clean up multi-thread logic near + top of routine. Handle new thread notification cleanly. + * lynx-nat.c (child_wait): General cleanups, handle new LynxOS + thread notification scheme. + * (child_resume): General cleanups, handle resumption of all + threads properly. + +Mon Jun 27 09:57:23 1994 Steve Chamberlain (sac@cirdan.cygnus.com) + + * ser-go32.c: Rewrite to run under windows. + * ser-e7kpc.c: New file to support the E7000 with the PC ISA + bus interface. + * serial.c (serial_open): Notice device "pc". + * remote-e7000.c: Fix copyright date. + (expect): Compare \n and \r the same. + (e7000_open): Allow pc as a serial port + * sh/sh.mt: Add ser-e7kpc. + * h8300/h8300hms.mt: Add ser-e7kpc. + * main.c (proc_wait): Don't wait if using go32. + +Mon Jun 27 00:35:51 1994 Jeff Law (law@snake.cs.utah.edu) + + * somread.c: Simplify by using stabsect_build_psymtabs. + * dbxread.c (stabsect_build_psymtabs): New argument "text_name" + corresponding to the name of the text section. All references + changed. + (somstab_build_psymtabs): Delete function, no longer needed. + +Sun Jun 26 23:54:08 1994 Jeff Law (law@snake.cs.utah.edu) + + * somread.c: Renamed from paread.c. Changed function names and + comments to reflect that this file deals with SOM (an object file + format), rather than the PA (a cpu). + (Makefile.in): Chaned appropriately. + (config/pa/hppabsd.mh, config/pa/hppahpux.mh): Likewise. + * dbxread.c (somstab_build_psymtabs): Renamed from + pastab_build_psymtabs. + +Fri Jun 24 08:15:42 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * core-sol2.c: New file to handle ELF and BCP core file flavours. + * config/sparc/sun4sol2.mh (NATDEPFILES): Use it instead of + core-svr4. + * Makefile.in: Updated for core-sol2.c. + * README: Add notes about SPARCworks cc under Solaris 2.x, + from Casper H.S. Dik (casper@fwi.uva.nl). + * config/mips/xm-makeva.h: Removed, no longer necessary. + * Makefile.in, config/mips/xm-irix3.h, config/mips/xm-irix5.h, + config/mips/xm-mips.h, config/mips/xm-news-mips.h, + config/mips/xm-riscos.h: Remove references to xm-makeva.h + +Wed Jun 22 17:48:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdba.el: Put program input and output in a separate buffer. + +Wed Jun 22 16:54:15 1994 Fred Fish (fnf@cygnus.com) + + * energize-patches, main.c (main), top.c (gdb_init, pwd_command), + top.h: Change all occurances of dirbuf to gdb_dirbuf. Collides + with global variable of same name in libnsl.so on UnixWare. + +Wed Jun 22 14:40:52 1994 Kung Hsu (kung@mexican.cygnus.com) + + * symtab.c (decode_line_1): fix a bug in dealing with '<>' + embedded in template name. + +Tue Jun 21 14:06:46 1994 Kung Hsu (kung@mexican.cygnus.com) + + * config/i386/nm-linux.h: change calling convention of + TARGET_CAN_USE_HARDWARE_WATCHPOINT() and + target_insert_watchpoint() and + target_remove_watchpoint(). + + * config/mips/tm-mips64.h: define FORCE_LONG_LONG to force LONGEST + to be long long in gdb. + * config/mips/tm-bigmips.h: ditto. + +Mon Jun 20 23:54:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * c-lang.c (asm_language_defn): New definitions for language_asm, + mostly copied from c_language_defn, to avoid warnings when + switching between c and asm stack frames. + +Mon Jun 20 13:51:55 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mdebugread.c (parse_symbol): Don't call ecoff_swap_tir_in or + ecoff_swap_rndx_in directly; use the debug_swap pointer instead. + (upgrade_type, handle_psymbol_enumerators): Likewise. + (has_opaque_xref, cross_ref): Likewise. + (elfmdebug_build_psymtabs): Call swap->read_debug_info to read + debugging information, rather than doing it here. + * mipsread.c (mipscoff_symfile_read): Call read_debug_info entry + point in ecoff_debug_swap backend structure, rather than calling + ecoff_slurp_symbolic_info directly. + +Fri Jun 17 20:58:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c: Include annotate.h. Call annotate_field rather + than printing annotation directly. + + * main.c: Include string.h. + +Thu Jun 16 14:41:37 1994 Stan Shebs (shebs@andros.cygnus.com) + + * fork-child.c (startup_inferior) [STARTUP_INFERIOR]: If defined, + call it instead of doing normal loop. + * infcmd.c (attach_command): Don't call wait_for_inferior if + running Mach 3. + * infrun.c (proceed) [PREPARE_TO_PROCEED]: If defined, call + hook that can decide whether to step over the next breakpoint. + * utils.c (wrap_here): Abort if wrap_buffer not allocated. + (request_quit) [REQUEST_QUIT]: If defined, call it instead of + doing normal quit. + + * configure.in: Improve sorting/formatting of hosts and targets. + (i[34]86-*-mach3*, i[34]86-*-osf1mk*, mips-*-mach3*, + m88*-*-mach3*, ns32k-*-mach3*): Recognize. + * Makefile.in (stop-gdb): New target. + * stop-gdb.c: New file, utility to get attention of waiting GDBs + in Mach 3. + +Wed Jun 15 00:41:03 1994 Tom Lord (lord@rtl.cygnus.com) + + * top.c (gdb_init): Init current_directory in gdb_init. Probably + the identical initialization can be deleted from main.c, but i + haven't done so just in case. + +Tue Jun 14 17:24:41 1994 Tom Lord (lord@x1.cygnus.com) + + * gdba.el: Added menu windows and slightly improved window + handling to gdba.el. Fixed numerous minor bugs that were causing + emacs and gdb to fall out of sync. + +Tue Jun 14 16:18:44 1994 Kung Hsu (kung@mexican.cygnus.com) + + * breakpoint.c: annotate changes lost at merge, put back in. + +Mon Jun 13 17:28:50 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config/i386/i386sco.mh, i386sco4.mh (XDEPFILES): Remove + i387-tdep.o. + +Sun Jun 12 03:51:52 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/m68k/dpx2.mh (NATDEPFILES): Remove duplicate inclusion + of inftarg.o. + * config/m68k/tm-dpx2.h (CANNOT_STORE_REGISTER): Define to inhibit + writing of floating registers, the dpx2 kernel disallows it. + * irix5-nat.c (LM_ADDR): The loaded address of the shared library + is contained in o_praw. + * irix5-nat.c (solib_map_sections): Adjust sections by the + difference between the loaded address and the prelinked address. + * irix5-nat.c (solib_address): Use LM_ADDR for the loaded start + address. + * mdebugread.c (parse_symbol): Do not relocate stEnd/scText + symbols, their value is absolute. + * mdebugread.c (parse_partial_symbols): Handle Irix 5.2 shared + libraries fh->adr fields of zero. Relocate minimal symbol values + upon readin. Relocate non-stabs symbols upon readin. + * mdebugread.c (psymtab_to_symtab_1): Use pst->textlow for the + start address of the outermost block. + * mdebugread.c (parse_lines, parse_procedure): Pass in pst + instead of section_offsets and use relocated pst->textlow for + line number and procedure address relocations. + + From gmo@MicroUnity.com (Guillermo A. Loyola): + * mdebugread.c (parse_symbol, parse_partial_symbols, cross_ref): + Handle SGI Irix5 stIndirect symbol type. + +Fri Jun 10 14:52:56 1994 Kung Hsu (kung@mexican.cygnus.com) + + * breakpoint.c: fix a syntax error native cc does not like. + + * Makefile.in: change sparclite-tdep.c to sparcl-tdep.c. + * sparclite/Makefile.in: ditto. + * sparcl-tdpe.c: change file name because first 8 chars has to be + unique. + * sparcl-stub.c: ditto. + + * sparclite/Makefile.in: fix INCLUDE_CFLAGS to have {srcdir}/../config. + +Fri Jun 10 10:38:15 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (target_read_pc, target_write_pc): Accept (and + ignore) a PID argument. + (hppa_pop_frame): Pass a PID to target_write_pc. + * config/pa/tm-hppa.h (TARGET_READ_PC, TARGET_WRITE_PC): Accept + and pass through a PID argument. + (target_read_pc, target_write_pc): Update prototypes. + +Thu Jun 9 18:10:44 1994 Kung Hsu (kung@mexican.cygnus.com) + + * Makefile.in: add new file sparclite-tdep.c. + * sparclite/Makefile.in: add new file sparclite-stub.c. + * sparclite/hw_breakpoint.note: note for SPARClite hardware breapoint + support. + * config/sparc/sparclite.mt: add sparclite-tdep.o. + * config/sparc/tm-sparclite.h: add hardware breakpoints support + defiines and code. + * sparclite-tdep.c: new file, contains hardware breakpoint support + code. + * sparclite-stub.c: new file, stub code that add support hardware + breakpoint support. + * breakpoint.c: add hardware breakpoint support. + * breakpoint.h: add new breakpoint type to support hardware + breakpoint. + * config/mips/nm-irix4.h: change interface for target dependent + code supporting watch point. + * config/pa/nm-hppab.h: change interface for target dependent + code supporting watch point. + +Thu Jun 9 14:59:58 1994 Kung Hsu (kung@mexican.cygnus.com) + + * remote-os9k.c (rombuf_command): fix a bug accepting rombug + output. + * stabsread.c (read_struct_fields): os9k nested structure does not + have terminating ';', instead it just get to ',' and bit position + and length. + +Wed Jun 8 23:20:45 1994 Stu Grossman (grossman@cygnus.com) + + * nlmread.c (nlm_symtab_read): Clean up a bit. + * (nlm_symfile_read): Record bounds of main() so that backtrace + command will know where to stop. + * objfiles.c (objfile_relocate): Relocate entry point/func info + for backtrace as well. + * objfiles.h: Define values for invalid PCs for entry point info. + * symfile.c (init_entry_point_info): Initialize invalid values + with aforementioned macros. + * config/alpha/tm-alphanw.h: Turn on FRAME_CHAIN_VALID_ALTERNATE + to cause backtrace to stop when it gets back to main(). + * config/i386/tm-i386nw.h: Ditto. + +Sat Jun 4 18:17:03 1994 Per Bothner (bothner@kalessin.cygnus.com) + + Fix value_print, which used to be ostensibly language-independent, + but would print pointers and arrays in C syntax. Instead, call + a language-specific function. + * language.h (struct language_defn): New functional field + la_value_print. + (LA_VALUE_PRINT): New macro. + * language.c (unk_lang_value_print): New stub/dummy function. + (unknown_language_defn, auto_language_defn, local_language_defn): + Use it. + * c-valprint.c (c_value_print): New function, with code moved from: + * valprint.c (value_print): ... here. Now just invoke + LA_VALUE_PRINT to do language-specific stuff. + * valprint.c (value_print_array_elements): Make non-static. + * c-lang.c (c_language_defn, cplus_language_defn): Add + c_value_print in the la_value_print field. + * m2-lang.c (m2_language_defn): Likewise. + * ch-lang.c (chill_language_defn): But here use chill_value_print. + * ch-valprint.c (chill_val_print): Print null pointer as NULL. + * ch-valprint.c (chill_value_print): New function, based on + c_value_print, but use Chill "look and feel." + * c-lang.h (c_value_print): New prototype. + * ch-lang.h (chill_value_print): New prototype. + * value.h (value_print_array_elements): New prototype. + + * ch-valprint.c (chill_val_print, case TYPE_CODE_BITSTRING + and case TYPE_CODE_SET): Check that the element type isn't a stub. + +Fri Jun 3 09:15:00 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c: Move entire file except for #ifndef MAIN_OVERRIDE code + to new file top.c. Make things extern instead of static and + similar rearrangements to deal with this. + * top.h: New file. + * utils.c: Move fputs_unfiltered to main.c. Remove + FPUTS_UNFILTERED_OVERRIDE ifndef. + * Makefile.in: Change so that gdb uses main.c, utils.c, and top.c, + and libgdb uses utils.c and top.c. + +Thu Jun 2 23:19:10 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (skip_trampoline_code): Fix typo. + +Thu Jun 2 18:09:59 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-valprint.c (chill_val_print_array_elements): New function. + A Chill version of val_print_array_elements, it prints the + array index labels, in additions ot the array element values. + (chill_val_print): Use the new function. + +Thu Jun 2 08:50:00 1994 Stu Grossman (grossman@cygnus.com) + + * configure.in: Add nlm subdir to configdirs for alpha-*-netware + target. + * defs.h (enum language): Add language_asm. + * findvar.c (read_register_bytes read_register_gen + write_register_bytes read_register read_register_pid + write_register write_register_pid supply_register): Move multi- + thread handling down into these routines. Create XXX_pid routines + that allow register references to specify the pid. + * findvar.c infcmd.c (read_pc read_pc_pid write_pc write_pc_pid + read_sp write_sp read_fp write_fp): Move these routines from + infcmd to findvar to centralize the whole mess. + * i386-nlmstub.c: Portability fixes. + * infptrace.c (child_resume): Conditionalize to allow other natives + to override it. Remove PIDGET gubbish, it's no longer necessary. + * infrun.c (wait_for_inferior): Put registers_changed() before + target_wait() to speed up remote debugging. + * Replace code that reads registers from other threads with much + nicer looking new function calls (see changes to findvar.c). + * Don't skip prologues if debugging assembly source. + * lynx-nat.c (child_resume): Lynx now needs it's own version of + child_resume to handle multi-thread debugging properly. + * remote.c: Add O response to get console output from target. + * (readchar): Add timeout parameter. Handle SERIAL_EOF and + SERIAL_ERROR here to simplify callers. + * Change static var timeout to remote_timeout. + * (fromhex): Remove unnecessary return -1 at end of routine. + * (remote_wait): Turn this into a big switch statement. Add + support for O response. + * (putpkt): Remove unnecessary handling of SERIAL_EOF/ERROR. + * (getpkt): Split getpkt into two parts. read_frame deals with + all formatting issues, run-length encoding, and framing. getpkt + now handles error recovery, and frame detection. + * ser-tcp.c (tcp_readchar): Handle EINTR from read(). + * ser-unix.c (hardwire_raw): Set CLOCAL so that we ignore modem + control. (hardwire_readchar): Handle EINTR from read(). + * symfile.c (deduce_language_from_filename): Add support for .s + files. + * config/nm-lynx.h: Define CHILD_WAIT so that lynx-nat.c can + override infptrace's child_wait. + * config/rs6000/rs6000lynx.mh: Use xm-rs6000ly.h & nm-rs6000ly.h + instead of XXXlynx.h. + * config/rs6000/rs6000lynx.mt: Use tm-rs6000ly.h instead of + tm-rs6000lynx.h. + * nlm/gdbserve.c: Portability fixes. + +Tue May 31 20:35:44 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * inftarg.c (child_wait): Call proc_wait, not wait. + (child_mourn_inferior): Call proc_remove_foreign. + * main.c (gdb_init): Call init_proc. + * main.c: Provide dummy versions of init_proc, proc_wait, and + proc_remove_foreign for the gdb case (the libgdb case provides its + own versions of these functions). + * Makefile.in (libgdb-files): Add libproc.a. + +Wed Jun 1 11:08:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + Hardware watchpoints for Linux, from Rick Sladkey + (jrs@world.std.com). + * infrun.c (wait_for_inferior) [HAVE_CONTINUABLE_WATCHPOINT]: Add + new hardware breakpoint recovery method. + * i386v-nat.c (i386_insert_watchpoint, + i386_insert_nonaligned_watchpoint, i386_remove_watchpoint, + i386_stopped_by_watchpoint) [TARGET_CAN_USE_HARWARE_WATCHPOINT]: + New functions to support the 386 hardware debugging registers. + * config/i386/nm-linux.h (TARGET_CAN_USE_HARDWARE_WATCHPOINT, + HAVE_CONTINUABLE_WATCHPOINT, STOPPED_BY_WATCHPOINT, + target_insert_watchpoint, target_remove_watchpoint): Define these + macros to use the hardware debugging functions in i386v-nat.c. + +Wed May 25 17:06:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Replace libgdb.a with libgdb-files. Make "all" + build it. + +Thu May 19 09:56:20 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.c, target.h: New variables target_activity_function and + target_activity_fd. + * inflow.c, inferior.h: New functions set_sigio_trap and + clear_sigio_trap. + * inftarg.c (child_wait), procfs.c (wait_fd): Call them. + +Wed May 18 13:01:55 1994 Doug Evans (dje@canuck.cygnus.com) + + * remote-sim.h (sim_verbose): Delete. + Document callbacks needed. + (sim_*): Change result to void where there isn't one. + (sim_open): Clarify argument and error response. + (sim_close): Declare. + (sim_load): Change bfd_handle argument to file name. Clarify result. + (sim_create_inferior): Renamed from sim_set_args. + (sim_set_pc): Delete. + (sim_info): Delete printf_fn argument. + * remote-sim.c (gdbsim_kill): Add comment describing purpose. + (gdbsim_load): Try sim_load first. + (gdbsim_create_inferior): Call sim_create_inferior. + (gdbsim_open): Handle args == NULL. Update call to sim_open. + (gdbsim_close): Call sim_close. + (gdbsim_files_info): Update call to sim_info. + (gdbsim_ops): Realign comments. + + * printcmd.c (decode_format): Allow TARGET_PTR_BIT to be non-constant. + +Tue May 17 16:45:20 1994 Stan Shebs (shebs@andros.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): For C_FILE symbols, only use + the auxent if the symbol's name is ".file". From David Edelsohn + . + +Tue May 17 11:08:22 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (breakpoint_1): Fix typo. + + * annotate.c (annotate_field_end): Fix typo. + + * Makefile.in: Move annotate.o from COMMON_OBS to OBS. + + * Makefile.in (TSSTART): Remove; no longer used. + + * utils.c (vfprintf_maybe_filtered, vfprintf_unfiltered): Call + fputs_unfiltered and exit directly, rather than fatal. The latter + calls vfprintf_unfiltered! + + * gdbtypes.h, gdbtypes.c (can_dereference): New function. + * value.h, printcmd.c (print_value_flags): Move from here... + * annotate.c: ...to here, and make it use can_dereference. + +Sat May 14 15:13:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + * inflow.c (job_control, attach_flag, generic_mourn_inferior): + Remove, needed for both native and cross. + * target.c (attach_flag, generic_mourn_inferior): Put here. + * utils.c (job_control): Put here. + (terminal.h): Don't include anymore. + +Sat May 14 09:11:44 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * source.c (find_source_lines): Always use code that was #ifdef + BROKEN_LARGE_ALLOCA. Do the cleanup before returning, rather than + leaving it on the chain. Reindent much of this function. + * config/sparc/{xm-sun4sol2.h,xm-sun4os4.h}, + config/i386/{xm-sun386.h,xm-i386m3.h,xm-i386mach.h}, + config/m68k/{sun3os4.h,xm-news.h,xm-hp300hpux.h}, + config/ns32k/xm-ns32km3.h: Remove all references to + BROKEN_LARGE_ALLOCA; with the above change it is no longer needed. + * main.c, fork-child.c, many config files: Remove all + SET_STACK_LIMIT_HUGE code; with the above changes it should no + longer be needed. + + * symtab.c (lookup_partial_symbol): Use if and abort, not assert. + This avoids __eprintf troubles. + +Fri May 13 08:10:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (main): Surround in #ifndef MAIN_OVERRIDE. Move + initialization code which needs to be called even if we bypass the + command line stuff into gdb_init. + * utils.c (fputs_unfiltered): Surround in #ifndef + FPUTS_UNFILTERED_OVERRIDE. + * Makefile.in (libgdb.a): New target. + + * utils.c: Rearrange I/O stuff a bit so that all output goes + through fputs_unfiltered. Use vasprintf; removes arbitrary limit + which made %s not work with arbitrarily large strings. + * printcmd.c (printf_command): Use printf_filtered, not + printf_unfiltered and printf, now that arbitrary limit is gone. + + gcc -Wall lint: + * breakpoint.c (watchpoint_check): Remove unused variable b. + * stack.c (print_frame_info): Move sp and buf inside #if. + * eval.c (evaluate_subexp): Remove unused variables pp, + mangle_ptr, ptr, and mangle_tstr. + * valarith.c (value_x_binop): Remove unused variables mangle_tstr + and mangle_ptr. + * symtab.c (lookup_symtab): Put variable copy inside #if. + (decode_line_1): Put variable q1 inside #if 0. + * target.h: Declare target_link. + * infrun.c (wait_for_inferior): Remove unused variables signame. + * remote.c (remote_resume): Remove unused variable name. + * c-exp.y (parse_number): Parenthesize operand of shift. + * dbxread.c (record_minimal_symbol): Parenthesize operand of && + (this is a semantic change, the warning seems to have detected a bug). + * dbxread.c (end_psymtab): Move variable p1 inside #if. + * coffread.c: Move variable temptype inside #if. + * ch-typeprint.c (chill_type_print_base): Remove unused variable + name. + * ch-valprint.c: #include typeprint.h and ch-lang.h. + (chill_val_print): Remove unused variable in_range. + (chill_val_print): Remove statement "length > TYPE_LENGTH (type);". + (chill_val_print): Add default case for switch. + * stabsread.h: Declare stabsect_build_psymtabs. + * os9kread.c (read_minimal_symbols): Make this return void. + (os9k_symfile_read): Remove unused variables stb_exist and val. + (os9k_symfile_init): Remove unused variable val. + (fill_sym): Remove unused variable id. + (read_os9k_psymtab): Put variable back_to inside #if 0. Remove + unused variable nsl. + Remove unused variable symfile_bfd. + #if 0 unused variables lbrac_unmatched_complaint and + lbrac_mismatch_complaint. + Remove declaration for non-existent function os9k_next_symbol_text. + + * annotate.c, annotate.h: New files, containing a function for + each annotation which outputs it. + * Move breakpoints_changed from breakpoint.c to annotate.c. + * breakpoint.c, blockframe.c, infrun.c, cp-valprint.c, main.c, + printcmd.c, source.c, stack.c, utils.c, valprint.c: + Use annotate.c functions to output annotations. + * Makefile.in (OBS): Add annotate.o. + +Thu May 12 10:46:27 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (read_unwind_info): Make sure elf_unwind_size and + elf_unwind_entries are always initialized. + + * hppa-tdep.c (skip_trampoline_code): Handle argument relocation + stubs which return directly to the caller rather than to the stub + itself. + +Wed May 11 20:11:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * c-exp.y (yyerror): Display a more informative error message. + * ch-exp.y (yyerror): Ditto, don't use global yychar. + * m2-exp.y (yyerror): Ditto. + +Tue May 10 11:57:53 1994 Stan Shebs (shebs@andros.cygnus.com) + + * inflow.c (job_control): Move definition to front of file. + +Tue May 10 14:42:37 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * maint.c (print_section_table): Rename SEC_SHARED_LIBRARY to + SEC_COFF_SHARED_LIBRARY to match corresponding change in bfd. + +Fri May 6 13:30:22 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (kdb): Remove old init.c creation commands. + * configure.in (sparclite): Match on sparclite*. + * sparclite/aload.c (main): Only change section addresses for + a.out format object files. + +Fri May 6 13:24:04 1994 Steve Chamberlain (sac@cygnus.com) + + * config/i386/go32.mh: Define CC. + +Fri May 6 11:56:54 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdbserver/Makefile.in: Remove irrelevant definitions and + comments inherited from the gdb Makefile. + (BFD_DIR, BFD, BFD_SRC, BFD_CFLAGS): Add from gdb Makefile. + (VERSION): Update to 4.12.3. + (gdbserver): Remove any existing executable first. + (distclean, realclean): Remove nm.h. + * gdbserver/low-lynx.c: Add Sparc Lynx support. + * gdbserver/low-sparc.c, gdbserver/low-sun3.c (sys/wait.h): + Don't use absolute pathname. + +Thu May 5 12:00:22 1994 Stan Shebs (shebs@andros.cygnus.com) + + * rs6000-nat.c (vmap_ldinfo): Don't fail if fstat returns an + error. + +Wed May 4 06:56:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (proceed, normal_stop, wait_for_inferior), breakpoint.c + (print_it_normal): Add annotations for the inferior starting and + stopping, and for all the various messages related to how it + stopped. + + * printcmd.c (do_one_display): Annotate. + * stack.c (print_frame_info): Annotate printing of stack frames. + +Wed May 4 18:15:51 1994 Stu Grossman (grossman@cygnus.com) + + * remote.c (get_offsets): Handle case where stub doesn't support + qOffsets message. + +Wed May 4 15:30:39 1994 Per Bothner (bothner@kalessin.cygnus.com) + + Add partial support for g++ code compiled with -fvtable-thunks. + * c-valprint.c (c_val_print): Add vtblprint support + when using thunks. + * cp-valprint.c (cp_is_vtbl_member): A vtable can be an array of + pointers (if using thunks) as well as array of structs (otherwise). + * cp-valprint.c (vtbl_ptr_name_old, vtbl_ptr_name): Move to global + level, and make the latter non-static (so define_symbol can use it). + * stabsread.c (define_symbol): If the type being defined is a + pointer type named "__vtbl_ptr_type", set the TYPE_NAME to that name. + * symtab.h (VTBL_PREFIX_P): Allow "_VT" as well as "_vt". + * values.c (value_virtual_fn_field): Handle thunks. + * values.c (value_headof): Minor efficiency hack. + * values.c (value_headof): Incomplete thunk support. FIXME. + +Wed May 4 06:56:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valprint.c (print_longest): Clarify comment about use_local. + * printcmd.c, defs.h (print_address_numeric), callers in + symmisc.c, symfile.c, stack.c, source.c, remote.c, infcmd.c, + cp-valprint.c, core.c, ch-valprint.c, c-valprint.c, breakpoint.c, + exec.c: New argument use_local. + * source.c (identify_source_line): Use filtered output. Use + print_address_numeric. + + * core.c (memory_error), symtab.c (cplusplus_hint, decode_line_1), + language.c (type_error, range_error): Use filtered output. + * utils.c (error_begin): Update comment to tell people to use + filtered output. + + * Makefile.in (HFILES_WITH_SRCDIR): List bfd.h. + (HFILES_NO_SRCDIR): List gdbcore.h not gdbcore_h, so as not to get + bfd.h. + +Tue May 3 07:41:33 1994 Jim Kingdon (kingdon@cygnus.com) + + * procfs.c (procfs_wait): Reinstate code which deduces the signal + from the fault, #ifndef FAULTED_USE_SIGINFO. + * config/sparc/tm-sun4sol2.h: Define FAULTED_USE_SIGINFO. + +Fri Apr 29 18:15:04 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (breakpoint_1): Annotate each field of the headers. + Explicitly annotate each record. + +Fri Apr 29 15:56:18 1994 Stan Shebs (shebs@andros.cygnus.com) + + * xcoffexec.c: Reformat to standards and lint. + (language.h): Include. + (exec_close): Declare arg "quitting". + (file_command): Declare arg "from_tty". + (map_vmap): Cast xmalloc result to PTR. + * rs6000-nat.c: Reformat to standards and lint. + (exec_one_dummy_insn): Use char array for saved instruction. + (fixup_breakpoints): Declare. + (vmap_ldinfo): Be more informative in fatal error messages. + (xcoff_relocate_symtab): Define to return void. + * xcoffsolib.h: Reformat to standards, improve comments. + * config/rs6000/nm-rs6000.h (xcoff_relocate_symtab): Declare. + +Thu Apr 28 08:40:56 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c, defs.h (error_begin): New function. + (quit): Print annotation before printing the error message. + * main.c (return_to_top_level): Print annotation before doing the + longjmp. + * symtab.c (decode_line_1): Call error not warning and then + return_to_top_level. Call error_begin and printf_unfiltered + rather calling warning (before calls to return_to_top_level). + * core.c (memory_error): Use error_begin, printf_unfiltered, + print_address_numeric and return_to_top_level instead of error. + Cleans up a FIXME-32x64. + * language.c (type_error, range_error): Call error_begin + not just target_terminal_ours. + + * dbxread.c (stabsect_build_psymtabs): Assign to sym_stab_info + directly, rather than via DBX_SYMFILE_INFO. A cast on the left + side of an assignment is non-portable. + + * utils.c (query): Change syntax of query annotations to be + consistent with other input annotations. + (prompt_for_continue): Likewise for prompt-for-continue annotation. + +Thu Apr 28 01:20:39 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (psymtab_to_symtab_1): Do not call sort_blocks + for stabs symtabs. + * mips-tdep.c (mips_skip_prologue): Handle prologues for functions + that have a stack frame size of 32k or larger (from Paul Flinders). + Remove #if 0'd code. + +Wed Apr 27 16:33:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * lynx-nat.c (CANNOT_STORE_REGISTER): Add a fallback definition + for Lynx platforms that need it. + * config/nm-lynx.h (__LYNXOS): Define if not already defined. + +Wed Apr 27 16:01:37 1994 Jim Kingdon (kingdon@cygnus.com) + + * procfs.c (procfs_wait): Use the signal from the pr_info rather + than trying to deduce it from the fault. + +Wed Apr 27 12:22:46 1994 Steve Chamberlain (sac@cygnus.com) + + * printcmd.c (print_address_symbolic): Initialize name to empty + string to avoid core dump if lookup fails. + * remote-e7000.c (printf_e7000debug): Error if target not open. + +Tue Apr 26 22:45:24 1994 Stu Grossman (grossman at cygnus.com) + + * i386-nlmstub.c: Update to be more in line with PIN stub. + * nlm/gdbserve.c (putDebugChar): Install bug fix from i386-nlmstub. + * (hex2mem): Init ptr. + * General cleanups to use ConsolePrintf, standard prologues, etc... + +Tue Apr 26 10:23:04 1994 Stu Grossman (grossman at cygnus.com) + + * i386-nlmstub.c: More changes to be compatible with remote.c. + + * dbxread.c: Move a bunch of strncmps out of process_one_symbol + into (the far less frequently called) dbx_symfile_read. + + * i386-nlmstub.c: An interim version till we get PIN for the x86. + +Tue Apr 26 09:50:45 1994 Stu Grossman (grossman at cygnus.com) + + * dbxread.c (record_minimal_symbol): Record the section + associated with the symbol to make dynmaic relocation work. + * (dbx_symfile_read, process_one_symbol): Fixes to work around + Solaris brain-damage which don't apply to relocatable object + files. + * (stabsect_build_psymtabs): New routine to read stabs out of an + arbitrarily named section. + * nlmread.c (nlm_symtab_read): Read ALL syms from the NLM, not just + globals. + * (nlm_symfile_read): Call stabsect_build_psymtabs to read the + stabs out of the nlm. + * partial-stabs.h (cases 'f' & 'F'): Fixes to work around Solaris + brain-damage which don't apply to relocatable object files. + * remote.c (putpkt): Improve error reporting and error handling. + * (get_offsets): Temporary kludge to force data & bss sections to + have the same relocation. + * stabsread.c (define_symbol, scan_file_globals): Record section + info in sym. + +Sat Apr 23 19:05:52 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (breakpoint_1): Annotate each field of output. Add + FIXME-32x64 comment. + +Fri Apr 22 16:43:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Move call to flush_cached_frames + to after call to target_wait. This means that flush_cached_frames + can call target_terminal_ours if it wants to. + * infrun.c (wait_for_inferior) [HAVE_NONSTEPPABLE_WATCHPOINT]: Add + comment about why the code is dubious. + + * stabsread.c (read_type): Call read_type, not nonexistent + os9k_read_type. + +Fri Apr 22 14:25:36 1994 Kung Hsu (kung@mexican.cygnus.com) + + * remote-os9k.c (rombug_fetch_registers): set trace mode + correctly. + * remote-os9k.c (rombug_read_inferior_memory): cache data in + buffer. + * os9kread,c (read_os9k_psymtab): process file symbol to truncate + extra info. + * os9kread.c (os9k_read_ofile_symtab): proper casting of args + passed to process_one_symbol. + * stabsread.c (read_type): process os9k functio prototype. + +Fri Apr 22 11:27:39 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * solib.c (symbol_add_stub): If so->textsection is NULL, don't + dump core. + +Thu Apr 21 07:45:49 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (prompt_for_continue): Annotate prompt. + (query): Annotate query. + * printcmd.c (print_frame_args): Change syntax of argument + annotation to make name and value part of a single group of + annotations, not two separate groups. + * cp-valprint.c (cp_print_value_fields): Likewise for fields. + * valprint.c (val_print_array_elements): Change syntax of + annotation to be more concise. + * main.c, defs.h (command_line_input): New argument tells what + string to include in the annotations. + * symtab.c (decode_line_2), main.c (read_command_lines, + command_loop): Change callers. + + * breakpoint.c (watch_command): Use (CORE_ADDR)0, not NULL, for + target null pointer. + * blockframe.c (find_frame_addr_in_frame_chain): Likewise. + + * printcmd.c (output_command): Annotate things we print here too. + * printcmd.c (print_command_1): Add "value-history-value" annotation. + * Move declaration of print_value_flags from defs.h to value.h. + * main.c (command_line_input): Call wrap_here as well as gdb_flush. + +Thu Apr 21 09:29:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (read_dbx_dynamic_symtab): Reinstall support for sun3, + BFD handles sun3 dynamic relocations now. + * elfread.c (elf_symtab_read, elf_symfile_read): Handle dynamic + symbol table. + +Wed Apr 20 19:41:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_command_1): Annotate the top-level expressions + that we print. + (print_frame_args): Annotate each argument. + * printcmd.c, defs.h (print_value_flags): New function. + * cp-valprint.c (cp_print_value_fields): Annotate each field. + * valprint.c (val_print_array_elements): Annotate each array element. + +Wed Apr 20 13:18:41 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * findvar.c (read_var_value): Handle LOC_REPARM_ADDR case correctly, + the register contains a pointer to the type, not the type itself. + +Mon Apr 11 10:44:35 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * main.c (main): Accept --annotate=N option and make --fullname + the same as --annotate=1. + (command_line_input): Print annotatation before and after prompt. + * blockframe.c (flush_cached_frames): Print annotation. + * Rename frame_file_full_name to annotation_level and move it from + symtab.h to defs.h. + * source.c (identify_source_line): If annotation_level > 1, + change output format. + * breakpoint.c: Print annotation whenever a breakpoint changes. + * main.c: New variable server_command. + (command_line_input): Parse "server " and set server_command. + (dont_repeat): Check server_command. + +Wed Apr 20 08:37:16 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (xcoff_next_symbol_text): Don't return before + updating raw_symbol and symnum. Return a value in the case where + we complained. + + * dstread.c, coffread.c: Don't define pending_blocks; buildsym.c + takes care of it. + * parse.c: Don't define block_found; it is defined in symtab.c. + * parser-defs.h: Add comment regarding block_found. + +Tue Apr 19 09:46:05 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (internalize_unwind_info): Delete unused indexp + argument. + +Mon Apr 18 13:18:56 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (read_dbx_dynamic_symtab): Relocate BFD symbols by + section vma. Do not read dynamic relocs for sun3 executables to + avoid BFD assertion message. + +Mon Apr 18 10:08:07 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * nm-hppab.h (KERNEL_U_ADDR): Define. + (FIVE_ARG_PTRACE): Likewise. + (CANNOT_STORE_REGISTER): Likewise. + * nm-hppah.h (KERNEL_U_ADDR): Define. + (FIVE_ARG_PTRACE): Likewise. + (CANNOT_STORE_REGISTER): Likewise. + (NEED_TEXT_START_END): Likewise. + + * tm-hppah.h (NEED_TEXT_START_END): Delete definition. + * xm-hppah.h (KERNEL_U_ADDR): Delete definition. + (FIVE_ARG_PTRACE): Likewise. + * xm-hppab.h (KERNEL_U_ADDR): Delete definition. + (FIVE_ARG_PTRACE): Likewise. + + * hppa-tdep.c (read_unwind_info): Make static. + (restore_pc_queue): Indirect through the target vector to + reload the register state. + +Sat Apr 16 22:20:51 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (compare_unwind_entries): Delete function. It's been + moved into hppa-tdep.c. + (read_unwind_info): Likewise. + (pa_symfile_read): No longer call read_unwind_info. The unwind + tables will be read in as they are needed. + + * hppa-tdep.c (compare_unwind_entries): New function. + (read_unwind_info, internalize_unwinds): Likewise. + (find_unwind_entry): Read in unwind information on demand. + +Fri Apr 15 11:53:46 1994 Stan Shebs (shebs@andros.cygnus.com) + + * source.c (DIRNAME_SEPARATOR): New macro, replaces all references + to : in search path processing. + * defs.h (qsort): Rename argument in prototype. + * symtab.h (SAYMBOL_VALUE): Rename value field, avoids bugs in + some compilers. + * breakpoint.c, exec.c, mdebugread.c, mipsread.c, xcoffexec.c + (false): Eliminate usages. + +Fri Apr 15 11:35:19 1994 Steve Chamberlain (sac@cygnus.com) + + * h8500-tdep.c (initialize_h8500_tdep, large_command): + All references to value changed to value_ptrlage_command is now + called big_command. + All references to value changed to value_ptr. + * remote-e7000.c (e7000_wait): Use target_waitstatus and SETSTOP + * remote-hms.c (hms_wait): Timeout after five seconds. + * ser-go32.c (dosasync_read): Poll if timeout < 0. + * config/tm/tm-h8500.h (BEFORE_MAIN_LOOP_HOOK): Deleted. + * config/sh/tm-sh.h (BREAKPOINT): Is now sleep opcode. + +Thu Apr 14 07:01:56 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * procfs.c (procfs_wait): Protect watchpoint code with appropriate + #ifdefs. + (procfs_set_watchpoint, procfs_stopped_by_watchpoint): Likewise. + +Wed Apr 13 14:52:46 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * breakpoint.h (enum bptype): Add bp_hardware_watchpoint and + bp_watchpoint_scope breakpoints. + (struct breakpoint): Add val_chain and related_breakpoint fields + for use by watchpoints. + + * breakpoint.c (within_scope): Delete. No longer used. + (TARGET_CAN_USE_HARDWARE_WATCHPOINT): Provide default definition. + (target_{remove,insert}_watchpoint): Likewise. + (can_use_hardware_watchpoint): New function. + (remove_breakpoint): New function to remove a single breakpoint + or hardware watchpoint. + (insert_breakpoints): Handle insertion of hardware watchpoints. + Store a copy of the value chain derived from the watchpoint + expression. + (remove_breakpoints): Simplify by using remove_breakpoint. + (delete_breakpoint): Likewise. + (watchpoint_check): Delete the watchpoint and watchpoint scope + breakpoints when the watchpoint goes out of scope. Save & restore + the current frame after checking watchpoints. + (breakpoint_init_inferior): Likewise (restarting the program + makes all local watchpoints go out of scope). + (bpstat_stop_status): Handle hardware watchpoints much like normal + watchpoints. Delete the watchpoint and watchpoint scope breakpoint + when the watchpoint goes out of scope. Remove and reinsert all + breakpoints before returning if we stopped when a hardware watchpoint + fired. + (watch_command): Use a hardware watchpoint when possible. If + watching a local expression, build a scope breakpoint too. + (map_breakpoint_numbers): Also call given function for any + related breakpoints. + (disable_breakpoint): Never disable a scope breakpoint. + (enable_breakpoint): Handle hardware breakpoints much like normal + breakpoints, but recompute the watchpoint_scope breakpoint's + frame and address (if we have an associated scope breakpoint). + (read_memory_nobpt): Handle hardware watchpoints like normal + watchpoints. When necessary handle watchpoint_scope breakpoints. + (print_it_normal, bpstat_what, breakpoint_1, mention): Likewise. + (clear_command, breakpoint_re_set_one, enable_command): Likewise. + (disable_command): Likewise. + + * blockframe.c (find_frame_addr_in_frame_chain): New function. + Extern prototype added to frame.h + + * infrun.c (wait_for_inferior): Set current_frame and select + a frame before checking if we stopped due to a hardare watchpoint + firing. Handle stepping over hardware watchpoints. + (normal_stop): Remove unnecessary call to select_frame. + + * value.h (value_release_to_mark): Declare. + * values.c (value_release_to_mark): New function. + + * procfs.c (procfs_wait): Add cases for hardware watchpoints. + (procfs_set_watchpoint, procfs_stopped_by_watchpoint): New functions. + + * hppab-nat.c (hppa_set_watchpoint): New function. + + * config/pa/nm-hppab.h (STOPPED_BY_WATCHPOINT): Define. + (HAVE_STEPPABLE_WATCHPOINT): Define. + (TARGET_CAN_USE_HARDWARE_WATCHPOINT): Define. + (target_{insert,delete}_watchpoint): Define. + + * config/mips/nm-irix4.h (TARGET_CAN_USE_HARDWARE_WATCHPOINT): Define. + (STOPPED_BY_WATCHPOINT, HAVE_NONSTEPPABLE_WATCHPOINT): Likewise. + (target_{insert,remove}_watchpoint): Likewise. + +Mon Apr 11 19:21:27 1994 Stu Grossman (grossman at cygnus.com) + + * xcoffread.c (read_xcoff_symtab): Ignore symbols of class C_EXT, + smtyp XTY_LD, sclass XMC_DS (external data segment label). They + often have the same names as debug symbols for functions, and + confuse lookup_symbol(). + +Mon Apr 11 10:44:35 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote.c: Around redefinition of PBUFSIZE, adjust whitespace. + * config/pa/tm-hppa.h (REGISTER_BYTES): Use 4 rather than + REGISTER_RAW_SIZE (1). + Together these changes work around a bug in HP's compiler. Both + seem to be necessary. + +Mon Apr 11 09:18:24 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (pa_symtab_read): Handle ST_STUB symbols and symbols + with scope SS_EXTERNAL. ST_ENTRY symbols in dynamic executables + are type mst_solib_trampoline. + +Fri Apr 8 17:14:37 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * config/m68k/es1800.mt: Change comments. + +Fri Apr 8 17:14:37 1994 Rob Savoye (rob@darkstar.cygnus.com) + + * config/m68k/monitor.mt (TDEPFILES): Don't include remote-es.o. + +Fri Apr 8 15:35:30 1994 Stu Grossman (grossman at cygnus.com) + + * lynx-nat.c: Restore regmap structure for SPARC. It's needed + for core files. + +Fri Apr 8 14:53:35 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * values.c (unpack_long): Remove obsolete comment about using a + switch statement. + + * symfile.c (symbol_file_command): Add comments about command syntax. + +Thu Apr 7 17:25:21 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + Jim Kingdon (kingdon@cygnus.com) + + * infrun.c (IN_SOLIB_TRAMPOLINE): Correct comment, trampolines + are in the .plt section. + * minsyms.c (lookup_solib_trampoline_symbol_by_pc, + find_solib_trampoline_target): New functions for handling + stepping into -g compiled shared libraries. + * symtab.h (lookup_solib_trampoline_symbol_by_pc, + find_solib_trampoline_target): Add prototypes. + * config/tm-sunos.h (IN_SOLIB_TRAMPOLINE, SKIP_TRAMPOLINE_CODE): + Define to handle stepping into -g compiled shared libraries. + * config/tm-sysv4.h (SKIP_TRAMPOLINE_CODE): Define to handle + stepping into -g compiled shared libraries. + +Thu Apr 7 17:22:54 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * configure.in: Add mips-*-sysv4* support. + * config/mips/mipsv4.mh, config/mips/mipsv4.mt, + config/mips/tm-mipsv4.h, config/mips/xm-mipsv4.h, mipsv4-nat.c: + New files for MIPS SVR4 support. + * Makefile.in: Update for new mipsv4 files. + * alpha-tdep.c (heuristic_proc_desc, find_proc_desc): Use + read_next_frame_reg to obtain the frame relative stack pointer. + * mips-tdep.c (heuristic_proc_desc): Use read_next_frame_reg to + obtain the frame relative stack pointer. + * mdebugread.c (parse_partial_symbols, psymtab_to_symtab1): + Handle stStatic and stStaticProc symbols in stabs-in-ecoff output + by entering them into the minimal symbol table. + * printcmd.c (print_scalar_formatted): Do not try to unpack to + a long for float formats. + * solib.c: Include "elf/mips.h" only if DT_MIPS_RLD_MAP does not + get defined in . + * solib.c (solib_add): Add shared library sections to the section + table of the target before adding the symbols. + * partial-stab.h: Relocate static and global functions. + * dbxread.c (read_dbx_symtab): Remove unused variable + end_of_text_address. Relocate text_addr when passing it + to end_psymtab. + + For Alpha OSF/1 targets, enable gdb to set breakpoints in shared + library functions before the executable is run. Retrieve dynamic + symbols from stripped executables. + * mipsread.c (read_alphacoff_dynamic_symtab): New function. + * mipsread.c (mipscoff_symfile_read): Use it. Issue warning message + if no debugging symbols were found. + * alpha-tdep.c (alpha_skip_prologue): Silently return the unaltered + pc if memory at the pc is not accessible and GDB_TARGET_HAS_SHARED_LIBS + is defined. + * config/alpha/nm-alpha.h (GDB_TARGET_HAS_SHARED_LIBS): Define, + OSF/1 has shared libraries. + +Thu Apr 7 15:11:11 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dbxread.c (read_dbx_dynamic_symtab): Adjust for recent changes + to BFD handling of dynamic symbols. + +Tue Apr 5 15:29:25 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (hppa_fix_call_dummy): If FUN is a procedure label, + then gets its real address into FUN and its GOT/DP value into %r19. + + * tm-hppa.h (CALL_DUMMY): Use %r20, not %r19 as a temporary. + + * hppa-tdep.c (frameless_function_invocation): If no unwind + descriptor was found, then assume this was not a frameless + function invocation. + (frame_saved_pc): If the saved PC is in a linker stub, then + return the return address which the linker stub will return to. + + * xm-hppab.h: Never define USG. + * xm-hppah.h: Always define USG. + +Tue Apr 5 12:58:47 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * values.c (unpack_long, value_from_longest), + valarith.c (value_binop): Allow TYPE_CODE_RANGE. + +Fri Apr 1 14:04:34 1994 Jason Merrill (jason@deneb.cygnus.com) + + * symfile.c (deduce_language_from_filename): .cpp is a C++ extension. + +Fri Apr 1 00:44:00 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + For SVR4 targets, enable gdb to set breakpoints in shared + library functions before the executable is run. + * elfread.c (elf_symtab_read): Handle symbols for shared library + functions. + * sparc-tdep.c (in_solib_trampoline): Renamed to in_plt_section + and moved to objfiles.c. + * objfiles.c (in_plt_section): Moved to here from sparc-tdep. + * config/tm-sysv4.h (IN_SOLIB_TRAMPOLINE): Use new in_plt_section. + * config/sparc/tm-sun4sol2.h (IN_SOLIB_TRAMPOLINE): Removed, + the new generic definition from tm-sysv4.h works for Solaris. + +Wed Mar 30 16:14:27 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * elfread.c (elf_symtab_read): Change storage_needed, + number_of_symbols and i to long. Rename get_symtab_upper_bound to + bfd_get_symtab_upper_bound. Check for errors from + bfd_get_symtab_upper_bound and bfd_canonicalize_symtab. + * nlmread.c (nlm_symtab_read): Same changes. + +Wed Mar 30 11:43:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (xcoff_next_symbol_text): New function. + (read_xcoff_symtab): Set next_symbol_text_func to it. + Move raw_symbol outside of read_xcoff_symtab. + + * remote.c (getpkt): Remove unused "out" label. + +Wed Mar 30 09:15:42 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * breakpoint.c (print_it_normal): Allow GDB to notify the user + about more than one watchpoint being triggered. + +Wed Mar 30 08:24:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/tm-dpx2.h: Include tm-m68k.h not nonexistent tm-68k.h. + +Wed Mar 30 00:31:49 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * blockframe.c (find_pc_partial_function): mst_file_text + symbols do not live in the shared library transfer table. + * ch-exp.y (decode_integer_value, match_character_literal, + match_bitstring_literal): Guard tolower calls with isupper, + tolower on old BSD systems blindly subtracts a constant. + * dbxread.c (read_ofile_symtab): Check for __gnu_compiled_* as + well when determining the producer of the object file. + * mdebugread.c (has_opaque_xref): New function to check for + cross reference to an opaque aggregate. + * mdebugread.c (parse_symbol, parse_partial_symbols): Do not + enter typedefs to opaque aggregates into the symbol tables. + * mdebugread.c (parse_external): Remove skip_procedures argument, + it has always been 1. Remove code that handled stProc symbols, + it was never executed and was wrong, as the index of a + stProc symbol points to the local symbol table and not to the + auxiliary symbol info. Update caller. + * mdebugread.c (parse_partial_symbols): Do not enter external + stProc symbols into the partial symbol table, they are already + entered into the minimal symbol table. + * config/i386/tm-symmetry.h: Clean up, it is now only used for Dynix. + Remove all conditionals and definitions for ptx. + I386_REGNO_TO_SYMMETRY moved to here from symm-tdep.c. + Fix addresses of floating point registers in REGISTER_U_ADDR. + STORE_STRUCT_RETURN now handles cc and gcc conventions. + FRAME_CHAIN, FRAMELESS_FUNCTION_INVOCATION, FRAME_SAVED_PC, + IN_SIGTRAMP, SIGCONTEXT_PC_OFFSET defined to make backtracing through + signal trampoline code work. + * config/i386/xm-symmetry.h: Clean up, it is now only used for Dynix. + Remove all conditionals and definitions for ptx. + Remove KDB definitions. + * symm-nat.c (store_inferior_registers): Fetch registers before + storing them to obtain valid floating point control registers. + Store fpu registers. + * symm-nat.c (print_1167_control_word): Dynix 3.1.1 defines + FPA_PCR_CC_C0 and FPA_PCR_CC_C1, avoid duplicate case value. + * symm-nat.c (fetch_inferior_registers, child_xfer_memory): + Fix typos. + * symm-nat.c (child_resume): Update type of `signal' parameter. + * symm-tdep.c (I386_REGNO_TO_SYMMETRY): Moved to tm-symmetry.h. + +Tue Mar 29 23:01:33 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (hppa_fix_call_dummy): Use an alternate method for + calling import stubs for functions in shared libraries. + +Tue Mar 29 21:14:04 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-exp.y: Implement SIZE(mode_name) and SIZE(expression). + + * ch-lang.c (chill_is_varying_struct): Magic string is + was "" is now "__var_length" (more portable). + +Tue Mar 29 19:41:34 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c (getpkt): If we get a timeout, actually retry rather + than just giving up the first time it happens. + * remote.c: Document sequence numbers. + (remote_store_registers): Change syntax of 'P' request so that it + never looks like a sequence number. + +Tue Mar 29 16:06:01 1994 Kung Hsu (kung@mexican.cygnus.com) + + * os9kread.c (record_minimal_symbol): add section_offset to + relocate minimal symbol table. + * os9kread.c (read_minimal_symbols): ditto. + * os9kread.c (os9k_symfile_init): increase size of dbg and stb + file names. + * os9kread.c (read_os9k_psymtab): if there's no dbg file, just + return. Also if file addr is 0 leave it 0, not to relocate. + * remote-os9k.c (_initialize_remote_os9k): add 'set remotexon', + 'set remotexoff' and 'set remotelog' commands. + +Tue Mar 29 12:38:45 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c (remote_store_registers): Add 'P' request to set an + individual register. + (remote_write_bytes, remote_read_bytes): Use %lx, not %x, to print + a target address. + +Sat Mar 26 07:05:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/sparc/tm-sparc.h: Define USE_REGISTER_NOT_ARG. + * stabsread (define_symbol): If USE_REGISTER_NOT_ARG, go back to + combining all 'p' and 'r' pairs into a LOC_REGPARM. + + * command.c (do_setshow_command, case var_string): Never add a + space to the end of the string. + * NEWS: Document this change. + * .gdbinit: Add a space to the "set prompt" command. + +Fri Mar 25 12:40:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m3-nat.c, i386m3-nat.c, config/i386/i386m3.mh: Many minor + changes to make it compile (it doesn't link yet). + + * buildsym.c (start_subfile, patch_subfile_names), demangle.c + (set_demangling_style, set_demangling_command): Use savestring not + strdup. We were not dealing properly with a NULL return from + strdup, and were not declaring strdup (the system header may or + may not have it). + + * valprint.c (val_print): Remove inaccurate comment about what + types can be stub types. + + * config/i386/ptx.mh (XDEPFILES): Add coredep.o. Delete infptrace.o. + * symm-nat.c (child_wait, _initialize_symm_nat, kill_inferior): + Supply alternate version if ATTACH_DETACH is not defined. + * ptx4-nat.c, config/i386/{nm-ptx4.h, ptx4.mh, ptx.mt, ptx4.mt, + tm-ptx.h, tm-ptx4.h, xm-ptx.h, xm-ptx4.h}: New files. + * configure.in: Recognize i[34]86-sequent-sysv4* host. + +Fri Mar 25 10:14:03 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (skip_prologue): Do nothing if not at the beginning + of a function. + (skip_trampoline_code): Rewrite and add support for argument + relocation stubs stubs, import/export stubs, calls through + "_sr4export" and cascaded trampolines. + + * hppa-tdep.c (skip_prologue): Return "pc" not zero + if no unwind descriptor is found. + + * tm-hppa.h (NUM_REGS): Bump to 128 registers. + (REGISTER_NAMES): Add entries for "right-half" of FP registers. + (REGISTER_RAW_SIZE, MAX_REGISTER_RAW_SIZE): Do not treat FP regs + differently. All registers are four bytes. + (REGISTER_BYTES, REGISTER_BYTE): Simplify now that all registers are + the same size. + (REGISTER_VIRTUAL_TYPE): Use builtin_type_float for all FP regs. + + * hppa-tdep.c (pa_print_fp_reg): Update to print even numbered FP + registers as both single and double values (fetching 2nd 32bit half + as necessary). Annotate each register printed with its precision. + + * paread.c (read_unwind_info): Fix off-by-one error. + +Fri Mar 25 08:33:28 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (complete_command): Deal with it if arg is NULL. + +Thu Mar 24 07:12:09 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/mips/tm-mips.h (SETUP_ARBITRARY_FRAME): Revise comment + regarding using the PC--using the PC is necessary and all the + FIXME comments in the world won't make it go away. + + * valops.c (value_at, value_at_lazy): Give error if we dereference + a pointer to void. + * gdbtypes.h: Fix comments regarding TYPE_CODE_VOID. + * stabsread.c: Use 1, not 0, for TYPE_LENGTH of void types. + + * stabsread.c (patch_block_stabs): Add comment about what happens + if the definition is in another compilation unit from the stab. + + * dbxread.c (end_psymtab): Add comment about empty psymtabs. + +Wed Mar 23 07:50:33 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (complete_command): New command, from Rick Sladkey + . + (symbol_completion_function): Don't declare rl_point and + rl_line_buffer; they are now declared in readline.h. + (show_commands): Don't declare history_base; it is declared in + history.h. + * command.c (lookup_cmd): Don't delete trailing whitespace. + Reverts change of 14 May 1989. + +Wed Mar 23 16:14:52 1994 Stu Grossman (grossman at cygnus.com) + + * minsyms.c (prim_record_minimal_symbol): Move section deduction + code from prim_record_minimal_symbol_and_info() to here. Callers + of the latter can legitimately supply a section number of -1. + +Wed Mar 23 07:50:33 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbtypes.h, gdbtypes.c: Add comments regarding whether static + member functions have an element in args for a (nonexistent) this + pointer. + +Tue Mar 22 20:12:53 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppao.h (NO_PC_SPACE_QUEUE_RESTORE): Define. + + * hppa-tdep.c (hppa_pop_frame): Do not restore the PC space + queue if NO_PC_SPACE_QUEUE_RESTORE is defined. + + * stabsread.c (REG_STRUCT_HAS_ADDR): Accept additional argument + for the structure's type. All callers changed. + + * valops.c (call_function_by_hand): Check REG_STRUCT_HAS_ADDR + for each structure argument rather than assuming it's either + true or false for all structure arguments. + + * config/pa/tm-hppa.h (REG_STRUCT_HAS_ADDR): Depend only + on the length structure passed, not the compiler used. + + * config/sparc/tm-sparc.h (REG_STRUCT_HAS_ADDR): Accept additional + argument for the structure's type. + +Tue Mar 22 15:28:33 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * values.c (set_internalvar): Don't set var->value until we are + sure there won't be an error(). + + * remote.c (get_offsets): Reinstate comment which was in + remote_wait about use of SECT_OFF_TEXT and so on. + +Mon Mar 21 13:11:30 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symmisc.c (maintenance_check_symtabs): New function to check + consistency of psymtabs and symtabs. + * symtab.h (maintenance_check_symtabs): Add prototype. + * maint.c: Add new `maint check-symtabs' command. + * config/i386/tm-i386aix.h, config/i386/tm-sun386.h, + config/i386/tm-symmetry.h (REGISTER_CONVERT_TO_RAW): Fix typo. + * config/i386/tm-symmetry.h: Make comment inside #if 0 a real + comment. + * config/i386/tm-symmetry.h (STORE_STRUCT_RETURN): Cast argument + to write_memory to avoid warnings from gcc. + * config/i386/xm-symmetry.h: Add missing #endif. + * config/i386/nm-symmetry.h (NO_PTRACE_H): Add for Dynix. + * config/i386/symmetry.mt (TDEPFILES): Add i386-tdep.o. + * config/i386/symmetry.mh (NAT_FILE, NATDEPFILES): Add. + +Mon Mar 21 11:50:28 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (hppa_fix_call_dummy): Use value_ptr. + (hppa_push_arguments): Likewise. + +Mon Mar 21 11:02:51 1994 Stu Grossman (grossman at cygnus.com) + + * alpha-tdep.c: Gobs of changes (many imported from mips-tdep) to + improve remote debugging efficiency. Also fixed problems with + doing function calls for programs with no entry points. + * infcmd.c (run_stack_dummy): Use CALL_DUMMY_ADDRESS instead of + entry_point_address. + * inferior.h (PC_IN_CALL_DUMMY): ditto. + * mdebugread.c (parse_symbol, parse_procedure, parse_external, + parse_lines): Pass section_offsets info to these routines so that + we can relocate symbol table entries upon readin. + * (psymtab_to_symtab_1): Set symtab->primary to tell + objfile_relocate to do relocations for our symbols. + * (ecoff_relocate_efi): New routine to relocate adr field of PDRs + (which hang off of the symbol table). + * Use prim_record_minimal_symbols_and_info instead of + prim_record_minimal_symbols to supply section info to make minimal + symbol relocations work. + * minsyms.c (prim_record_minimal_symbols_and_info): If section is + -1, try to deduce it from ms_type. + * objfiles.c (objfile_relocate): Use ALL_OBJFILE_SYMTABS where + appropriate. Handle relocation of MIPS_EFI symbols special. Also, + add code to relocate objfile->sections data structure. + * remote.c (get_offsets): Use new protocol message to acquire + section offsets from the target. + * (remote_wait): Get rid of relocation stuff. That's all handled + by objfile_relocate now. + * config/alpha/alpha-nw.mt (TM_FILE): Use tm-alphanw.h. + * config/alpha/tm-alpha.h: Define CALL_DUMMY_ADDRESS, and + VM_MIN_ADDRESS. + * config/alpha/tm-alphanw.h: DECR_PC_AFTER_BREAK=0, VM_MIN_ADDRESS=0. + +Mon Mar 21 10:09:06 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (_initialize_hpuxread): Don't call add_symtab_fns if + HPREAD is not defined. + +Sun Mar 20 15:21:57 1994 Doug Evans (dje@cygnus.com) + + * sparc-tdep.c (sparc_frame_find_save_regs): Use REGISTER_RAW_SIZE + instead of 4. + * sp64-tdep.c (target_ptr_bit, set_target_ptr_bit): Deleted, + can no longer set this at run time. + * config/sparc/sp64.mt (SIMFILES): Use remote-sim.o now. + (TM_CLIBS): Define to -lm, the simulator uses the sqrt() function. + * config/sparc/tm-sp64.h (FPS_REGNUM, CPS_REGNUM): Define (so + sparc-tdep.c compiles). + (TARGET_PTR_BIT): Must be a constant now, fix at 64. + +Sat Mar 19 08:51:12 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/{cisco.mt,tm-cisco.h}: New files. + * Makefile.in (ALLPARAM, ALLCONFIG): Add them. + * configure.in: Recognize m68*-cisco*-*. + + * Makefile.in (TAGS): Use variables directly, rather than using + find, to locate TM_FILE, XM_FILE, and NAT_FILE. This is faster + and means that these filenames no longer need be unique across all + the config/* directories. + * configure.in: Put the config/*/ into TM_FILE, etc. + + * m68k-stub.c (computeSignal): Return SIGFPE, not SIGURG, for chk + and trapv exceptions. + + * target.h (struct section_table), objfiles.h (struct obj_section): + Change name of field sec_ptr to the_bfd_section. More mnemonic + and avoids the (sort of, for the ptx compiler) name clash with + the name of the typedef. + * exec.c, xcoffexec.c, sparc-tdep.c, rs6000-nat.c, osfsolib.c, + solib.c, irix5-nat.c, objfiles.c, remote.c: Change users. + + * utils.c: Include readline.h. + * Makefile.in (utils.o): Add dependency. + + * remote.c (getpkt): Add support for run-length encoding. + +Fri Mar 18 19:11:15 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * utils.c (prompt_for_continue): Call readline, not gdb_readline. + +Fri Mar 18 10:25:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dstread.c (record_minimal_symbol): New arg objfile. Pass it to + prim_record_minimal_symbol. + Callers: Pass it. + + * regex.c (EXTEND_BUFFER): Adjust pointers within buffer by + computing their offset from the start of the old buffer and adding + to the new buffer, rather than by assuming we can add the + difference between the old buffer and the new buffer (it might not + fit in an int). Merge in cosmetic differences from emacs regex.c + version of this macro. + +Wed Mar 16 15:28:54 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (install-only): Fix use of program_transform_name. + +Wed Mar 16 07:18:43 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c: Remove "set print fast-symbolic-addr off" command. + The bug which it worked around was fixed on 25 Feb 94 in coffread.c, + so I'm nuking the command. + * symtab.c (find_addr_symbol): Comment out, no longer used. + + * main.c (main): Don't init_source_path for the -cd argument. Now + that source_path doesn't contain the current_directory from when + GDB started up, init_source_path is no longer useful (and is + harmful because it clobbers a source_path set in $HOME/.gdbinit). + + * TODO: Remove item about line numbers being off. It is useless + and confusing without a reproducible test case (it mentions + proceed(), but I was able to step through proceed without trouble). + +Tue Mar 15 13:39:23 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + For Sunos 4.x targets, enable gdb to set breakpoints in shared + library functions before the executable is run. Retrieve dynamic + symbols from stripped executables. + * symtab.h (minimal_symbol_type): Add mst_solib_trampoline type. + * parse.c (write_exp_msymbol), symmisc.c (dump_msymbols), + symtab.c (list_symbols): Handle mst_solib_trampoline. + * minsyms.c (lookup_minimal_symbol): Handle mst_solib_trampoline + for all targets, remove IBM6000_TARGET dependencies. + * dbxread.c (read_dbx_dynamic_symtab): New function. + * dbxread.c (dbx_symfile_read): Use it. + * dbxread.c (SET_NAMESTRING): Set namestring to + "" instead of "foo" if the string index is + corrupt. + * xcoffread.c (read_xcoff_symtab): Use mst_solib_trampoline instead + of mst_unknown. + * symtab.c (list_symbols): Take from_tty as parameter and pass it + to break_command. Handle mst_file_* minimal symbol types. + * config/i386/tm-i386bsd.h: Give just macro name, not args, to #undef. + +Tue Mar 15 11:40:43 1994 Kung Hsu (kung@mexican.cygnus.com) + + * c-exp.y(yylex): fix potential memory overflow. + +Tue Mar 15 10:33:28 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * environ.c (set_in_environ): Eliminate special handling of PATH and + GNUTARGET. + * putenv.c: Removed, conflicts with system declaration of + putenv on RS/6000 running AIX 3.2.5, and above change makes it + unnecessary. + * Makefile.in: Change accordingly. + * procfs.c (procfs_create_inferior): Change comment accordingly. + +Tue Mar 15 10:05:27 1994 Jim Kingdon (kingdon@cygnus.com) + + * rs6000-tdep.c: Change value to value_ptr. + +Sun Mar 13 17:19:03 1994 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (read_hpux_symtab: Correctly determine the namespace + and address class of SVAR, DVAR, TYPEDEF, TAGDEF, CONST, and + MEMENUM symbols. Do not include function-scoped variables in + the partial symbol table. + +Sun Mar 13 09:45:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i386m3-nat.c: Include floatformat.h. + (get_i387_state): Use memset not bzero. + + * Version 4.12.3. + + * Makefile.in: Enable commented out getopt_h, bfd_h, etc. Change + ieee-float.h to floatformat.h. + + * valprint.c (val_print_string): Ignore error if the error + happened after a terminating '\0'. + + * c-valprint.c (c_val_print): Never add 1 to return value from + val_print_string; just return what it returns. + + * target.h (enum target_signal): Add TARGET_SIGNAL_FIRST, for + looping through all of the enums. + * infrun.c (signals_info): Use it. + +Fri Mar 11 08:08:50 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * main.c (main): When printing warning about bad baud rate, don't + use warning(); it relies on current_target which isn't set up yet. + + * breakpoint.c (_initialize_breakpoint): Update docstring for + tbreak to match what the code actually does. Don't mention tbreak + in docstrings for "enable once" or "enable breakpoints once". + +Thu Mar 10 08:52:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symfile.h (ADD_PSYMBOL_VT_TO_LIST): Don't put a semicolon after + while (0). That defeats the whole purpose of using do . . . while (0). + * mdebugread.c (parse_partial_symbols): Don't use ?: expression as + list for ADD_PSYMBOL_TO_LIST; the macro takes its address and + using a ?: expression as an lvalue is not portable. + + * stabsread.c (define_symbol): If REG_STRUCT_HAS_ADDR, also + convert a LOC_ARG to a LOC_REF_ARG. Update code which combines + 'p' and 'r' symbol descriptors into a single symbol to look for a + LOC_REF_ARG. + * README, config/sparc/tm-sparc.h: Update comments. + +Wed Mar 9 21:43:24 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_type): Do not complain for types with + an `indexNil' aux index, these are simply undefined types. + Remove indexNil check from caller of parse_type. + * mdebugread.c (parse_partial_symbols): Do not enter + stGlobal, scCommon symbols into the minimal symbol table, their + value is the size of the common, not its address. + Handle scInit, scFini, scPData and scXData sections. + Use minimal symbol type mst_file_* for stLabel symbols, instead of + mst_*. + Enter stProc symbols into the global_psymbols list once, not into + the static_psymbols_list. + Get rid of dummy psymtab if it is empty, to allow proper detection + of stripped executables. + * mdebugread.c (cross_ref): Allow cross references to Fortran + common blocks. + +Wed Mar 9 15:23:19 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (common_block_end, fix_common_block): Stash the + struct pending * in the SYMBOL_TYPE, not the SYMBOL_NAMESPACE, so + as to not assume that a pointer fits in an enum. + +Wed Mar 9 18:56:36 1994 Kung Hsu (kung@mexican.cygnus.com) + + * os9kread.c (fill_sym): check compiler verion number for pre- + UltraC compiler. + * os9kread.c (os9k_process_one_symbol): address of symbol is + relative to section not module. + * stabsread.c (define_symbol): add symbol type 's' as local + symbol for os9k. + * remote-os9k.c: add command 'set monitor_log' to turn on or off + monitor logging. + * remote-os9k.c: fix bug in delete breakpoint, single step trace. + * remote-os9k.c: fix bug in 'set remotebaud' function. + * remote-os9k.c (rombug_link): minimize checking so to improve + speed. + * symfile.c (symbol_file_command): check if failed to link, also make + the command be able to accept more than one filenames. + * target.c (target_link): check if failed to link with rombug. + * config/i386/tm-i386os9k.h : add #define DECR_PC_AFTER_BREAK 0. + +Wed Mar 9 15:23:19 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-es.c (es1800_child_ops): Don't declare it static. + +Tue Mar 8 11:42:39 1994 Jim Kingdon (kingdon@cygnus.com) + + * config/i386/tm-i386v4.h: Give just macro name, not args, to #undef. + +Tue Mar 8 06:56:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c: New variable lowest_text_address. + (record_minimal_symbol, read_dbx_symtab): Set it. + (read_dbx_symtab): Use lowest_text_address + text_size instead of + end_of_text_address. + * config/gould/tm-pn.h: Add comment regarding END_OF_TEXT_DEFAULT. + + * dbxread.c (end_psymtab): Remove old and commented out + capping_global and capping_static. Fix comments regarding + N_SO_ADDRESS_MAYBE_MISSING to match the real name of the macro. + + * parser-defs.h: Add "extern" to start of variable declarations so + we don't end up with commons. + * parse.c: Define these variables. + + * irix5-nat.c (find_solib): Cast o_path to CORE_ADDR when using it + as one. + +Mon Mar 7 13:00:50 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * alpha-tdep.c: Change value to value_ptr. + +Sun Mar 6 17:36:53 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * solib.c (elf_locate_base): New function to locate the address + of the dynamic linker's runtime structure in the dynamic info section. + * solib.c (locate_base): Use it instead of iterating over the list + of mapped address segments. + * solib.c (look_for_base, bfd_lookup_symbol): Removed, no longer + necessary. + +Fri Mar 4 09:50:47 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (pc_in_linker_stub): Move decl to beginning of file. + (pc_in_interrupt_handler): New function. Also add PARAM decl. + (find_proc_framesize): Deal with HPUX setting SAVE_SP bit for + signal trampoline and interrupt routines. + (frame_saved_pc): Handle signal trampolines and interrupt routines. + (frame_chain, frame_chain_valid): Likewise. + (hppa_frame_find_saved_regs): Likewise. Also deal with special + saved regs convention for SP. + + * tm-hppa[bho].h: FRAME_FIND_SAVED_PC_IN_SIGTRAMP): Define. + (FRAME_BASE_BEFORE_SIGTRAMP): Define. + (FRAME_FIND_SAVED_REGS_IN_SIGTRAMP): Define. + + * tm-hppah.h (IN_SIGTRAMP): Define. + +Thu Mar 3 12:41:16 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * ch-exp.y (match_simple_name_string): Accept '_' as well as an + alphabetic character as the start of a name. + + * sparclite/Makefile.in (all install): Build and install aload. + + * configure.in: Accept i[34]86-*-*sysv32 because that is what + config.guess and config.sub produce. + + * mips-tdep.c: Change value to value_ptr. + +Wed Mar 2 09:17:55 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * breakpoint.c, breakpoint.h, c-valprint.c, ch-valprint.c, + cp-valprint.c, eval.c, expprint.c, findvar.c, language.c, + objfiles.h, infcmd.c, printcmd.c, stack.c, typeprint.c, + valarith.c, valops.c, valprint.c, value.h, values.c: Replace + value with value_ptr. This is for the ptx compiler. + * objfiles.h, target.h: Don't declare a "sec_ptr" field using a + "sec_ptr" typedef. + * symm-nat.c: Add a bunch of stuff for symmetry's ptrace stuff. + #if 0 i386_float_info. + * symm-tdep.c (round): Remove. Also remove sgttyb. + * symm-tdep.c: Remove lots of stuff which duplicates stuff from + i386-tdep.c. Remove register_addr and ptx_coff_regno_to_gdb. + * i386-tdep.c (i386_frame_find_saved_regs): Put in + I386_REGNO_TO_SYMMETRY check in case it is needed for Dynix + someday. + * config/i386/nm-symmetry.h: Change KERNEL_U_ADDR. Move + stuff from PTRACE_READ_REGS, PTRACE_WRITE_REGS macros to + symm-nat.c. Define CHILD_WAIT and declare child_wait(). + * config/i386/tm-symmetry.h: Remove call function stuff; stuff in + tm-i386v.h is apparently OK. + * config/i386/xm-symmetry.h [_SEQUENT_]: Define HAVE_TERMIOS not + HAVE_TERMIO. Define MEM_FNS_DECLARED, NEED_POSIX_SETPGID, and + USE_O_NOCTTY. + +Wed Mar 2 11:31:08 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * osfsolib.c (xfer_link_map_member): Update to use new + target_read_string interface. + +Wed Mar 2 09:17:55 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * infrun.c (wait_for_inferior): In checking + remove_breakpoints_on_following_step, check + through_sigtramp_breakpoint as well as step_resume_breakpoint. + +Tue Mar 1 16:22:56 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * os9kread.c (os9k_process_one_symbol): Rename + VARIABLES_INSIDE_BLOCK to OS9K_VARIABLES_INSIDE_BLOCK. + * symfile.c (symbol_file_command): Check for (CORE_ADDR)-1, not + (CORE_ADDR)0, from target_link, since that is what it uses. + Process name at end, not during parsing (like we did before Kung's + change), so that -readnow and -mapped can appear anywhere. + Make text_relocation a local variable. + * config/i386/i386os9k.mt: Fix comment. + * Makefile.in (ALLDEPFILES): Add remote-os9k.c. + * os9kread.c: Put "comments" after #endif inside /* */. + * stabsread.h: Add os9k_stabs variable. + * stabsread.c (start_stabs), os9kread.c (os9k_process_one_symbol): + Set it. + * stabsread.c (define_symbol): If os9k_stabs, put a 'V' symbol + descriptor in global_symbols not local_symbols. + (read_type): If os9k_stabs, accept 'c', 'i', and 'b' type + descriptors. + (read_type): If os9k_stabs, accept function parameters after 'f' + type descriptor. + (read_array_type): If os9k_stabs, don't expect index type and + expect lower and upper to be separated by ',' not ';'. + (read_enum_type): If os9k_stabs, read a number before the first + enumeration constant. + (os9k_init_type_vector): New function. + (dbx_lookup_type): Call it when starting new type vector. + * config/i386/tm-i386os9k.h: Define BELIEVE_PCC_PROMOTION. + * (os9k_process_one_symbol): Call define_symbol not os9k_define_symbol. + * os9kstab.c: Removed. + * Makefile.in: Update accordingly. + * objfiles.c (objfile_relocate_data): Removed. + * remote-os9k.c (rombug_wait): Call objfile_relocate + not objfile_relocate_data. + * objfiles.h, objfiles.c: Remove find_pc_objfile. + * remote-os9k.c (rombug_wait): Call find_pc_section not + find_pc_objfile. + * main.c (quit_command): Check inferior_pid; revert Kung change. + * remote-os9k.c (rombug_create_inferior): Set inferior_pid. + +Tue Mar 1 14:56:14 1994 Kung Hsu (kung@mexican.cygnus.com) + + * os9kread.c: New file to read os9000 style symbo table. + * os9kstab.c: new file to read os9000 style stabs. + * remote-os9k.c: remote protocol talking to os9000 rombug monitor. + * objfiles.c (find_pc_objfile): new function to search objfile + from pc. + * objfiles.c (objfile_relocate_data): new function to relocate + data symbols in symbol table. + * objfiles.h: Add two aux fields in struct objfile to handle + multiple symbol table files situation like in os9000. + * symfile.c: Change so 'symbol-file' command can handle multiple + files. Also call target_link() to get relocation infos. + * target.c (target_link): new function to get relocation info when + a symbol file is requested to load. + * main.c (quit_command): take out 'inferior_pid != 0' condition, + because in cross mode there's no inferior pid, bit they need to + be detached. + Makefile.in: add os9kread.c os9kstab.c and .o's. + configure.in: add i386os9k target. + config/i386/i386os9k.mt: new add. + config/i386/tm-i386os9k.h: new add. + +Tue Mar 1 13:16:10 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/sparc/tm-sun4sol2.h (IN_SIGTRAMP): Handle ucbsigvechandler. + * sparc-tdep.c (sparc_frame_saved_pc): Handle ucbsigvechandler. + +Tue Mar 1 11:54:11 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * target.c, target.h (target_read_string): Provide error detection to + caller. Put string in malloc'd space, so caller need not impose + arbitrary limits. + * solib.c (find_solib): Update to use new interface. + * irix5-nat.c (find_solib): Read o_path from inferior + (clear_solib): Free storage for o_path. + * valprint.c (val_print_string): Add comments. + +Mon Feb 28 23:54:39 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.c (decode_line_1): Handle the case when skip_quoted does not + advance `p'. + +Mon Feb 28 12:40:46 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * value.h (struct value): Add modifiable field. + * values.c (allocate_value, record_latest_value, value_copy): Set it. + (record_latest_value): Don't mess with VALUE_LVAL of value. + * valops.c (value_assign): Check it. Reword existing error + message on not_lval. + + * mips-tdep.c (mips_step_skips_delay), config/mips/tm-mips.h + (STEP_SKIPS_DELAY): Added. + * infrun.c (proceed) [STEP_SKIPS_DELAY]: Check for a breakpoint in + the delay slot. + + * valprint.c (val_print_string): If errcode is set, always print + an error, regardless of force_ellipsis. In the non-EIO case, + just print the error message rather than calling error(). Don't + access *(bufptr-1) if bufptr points to the start of the buffer. + When looking for '\0', don't increment bufptr and addr if bufptr + started out already at limit. If an error happens on fetching the + first character, don't print the string. + +Sun Feb 27 21:05:06 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * config/m68k/tm-apollo68b.h: Remove HAVE_68881 define; it is + obsolete. + + * i387-tdep.c, i386-tdep.c i386v-nat.c, i386aix-nat.c, + i386m3-nat.c, config/m68k/tm-m68k.h, i960-tdep.c + config/i960/tm-i960.h, remote-nindy.c, config/m88k/tm-m88k.h, + m88k-tdep.c: Use floatformat.h instead of ieee-float.h. + * sparc-tdep.c: Remove now-obsolete ieee-float.h stuff + * findvar.c: Update comment regarding ieee-float.h. + +Sun Feb 27 21:39:48 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/i386/tm-i386v4.h (I386V4_SIGTRAMP_SAVED_PC, IN_SIGTRAMP, + FRAME_CHAIN, FRAMELESS_FUNCTION_INVOCATION, FRAME_SAVED_PC): + Define to make backtracing through the various sigtramp handlers + work. + * i386-tdep.c (i386v4_sigtramp_saved_pc): New routine to fetch + the saved pc from ucontext on the stack for SVR4 signal handling. + +Fri Feb 25 09:41:11 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote.c, remote-mon.c, remote-utils.c, remote-utils.h, + target.h, remote-es.c, remote-nindy.c: Don't set baud rate if + baud_rate is -1. Remove sr_get_baud_rate and sr_set_baud_rate; + just use the global variable itself. When printing baud rate, + don't print a baud rate if baud_rate is -1. + + * coffread.c (read_coff_symtab): Pass mst_file_* to + record_minimal_symbol for C_STAT symbols. Put C_EXT and C_STAT + symbols in the minimal symbols regardless of SDB_TYPE. + +Thu Feb 24 08:30:33 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * breakpoint.h (enum bptype): New type bp_through_sigtramp. + (bpstat_what_main_action): New code BPSTAT_WHAT_THROUGH_SIGTRAMP. + * breakpoint.c (bpstat_what): Return BPSTAT_WHAT_THROUGH_SIGTRAMP + if we hit a bp_through_sigtramp breakpoint. Remove kludge which + ignored bs->stop for a bp_step_resume breakpoint. + * infrun.c (wait_for_inferior): Make a through_sigtramp_breakpoint + which performs one (the check_sigtramp2 one) of the functions + which had been handled by the step_resume_breakpoint. For each + use of the step_resume_breakpoint, make it still use the + step_resume_breakpoint, use the through_sigtramp_breakpoint, or + operate on both. + Deal with BPSTAT_WHAT_THROUGH_SIGTRAMP return from bpstat_what. + When setting the frame address of the step resume breakpoint, set + it to the address for frame *before* the call instruction is + executed, not after. + + * mips-tdep.c (mips_print_register): Print integers using + print_scalar_formatted rather than duplicating all the + CC_HAS_LONG_LONG and so on. + (mips_push_dummy_frame): Use read_register_gen rather than using + read_register and then putting it back in target format with + store_unsigned_integer. If registers are more than 4 bytes, give + an error rather than have some registers overwrite other + registers. + #if 0 unused include of opcode/mips.h. + + * symfile.h: Don't declare arguments for coff_getfilename. + + * defs.h: Revert Kung change regarding FORCE_LONG_LONG. + +Thu Feb 24 08:06:52 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * configure.in (hppa*-*-osf*): New configuration. + * config/pa/hppaosf.mt: New target makefile fragment. + * config/pa/tm-hppao.h: New target include file. + +Thu Feb 24 04:29:19 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * exec.c (print_section_info): Print entry point for exec_bfd only. + * ser-unix.c (wait_for): Fix typo in HAVE_TERMIO case. + * dwarfread.c: Remove second inclusion of , which + causes problems if has no multiple inclusion protection. + +Wed Feb 23 16:28:55 1994 Jeffrey A. Law (law@cygnus.com) + + * tm-hppa.h (CALL_DUMMY): Add two NOP instructions to the end of + the call dummy to avoid kernel bugs in HPUX, BSD, and OSF1. + (CALL_DUMMY_LENGTH): Changed accordingly. + +Wed Feb 23 16:21:25 1994 Stu Grossman (grossman at cygnus.com) + + * sparc-stub.c (trap_low): Make trap handler work for arbitrary + numbers of register windows. + + * sparclite/hello.c: Add factorial function for testing. + * salib.c: Use macros instead of constants for I/O addresses to + make 931 support easier. + * sparclite.h: Change constraint for LOC to "rJ" to force use of + register in sta/lda instructions. + +Wed Feb 23 10:39:18 1994 Jim Kingdon (kingdon@rtl.cygnus.com) + + * dbxread.c (process_one_symbol): Set + block_address_function_relative for COFF like we do for ELF and SOM. + +Sat Feb 19 03:17:32 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (new_psymtab): Pass in section_offsets and set + them in the pst. + * mdebugread.c (handle_psymbol_enumerators): New function to enter + the enumerators of an ecoff enum into the partial symbol table. + * mdebugread.c (parse_partial_symbols): Call it. + * symfile.c (reread_symbols): Initialize objfile->*_psymbols.next. + * symmisc.c (dump_psymtab): Fix typo, clean up output of section + offsets. Cast psymtab->read_symtab to PTR before passing it to + gdb_print_address. + * i386-tdep.c (i386_skip_prologue): Skip over instructions that + set up the global offset table pointer in pic compiled code. + * config/mips/tm-mips.h (FIX_CALL_DUMMY): For big endian targets, + error() on TYPE_CODE_FLT arguments whose size is greater than 8, + swap all other TYPE_CODE_FLT arguments as mips_push_arguments + ensures that floats are promoted to doubles before they are pushed + on the stack. + +Fri Feb 18 23:12:59 1994 Stu Grossman (grossman at cygnus.com) + + * sparclite/Makefile.in, sparclite/salib.c, sparclite/sparclite.h: + Fixup cache_on and flush_i_cache so that they work for both the + 930 and 932 processors. Rewrite most low level funcs (uart + access & cache stuff) to use new ASI access macros in sparclite.h. + Also make it easy to access second serial port. + +Fri Feb 18 22:17:33 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * hp300ux-nat.c: Don't incloude , , or + ; not needed. + +Fri Feb 18 08:26:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stack.c (print_frame_info): In "pathological" case, don't + distrust the line number information. + +Fri Feb 18 16:51:14 1994 Kung Hsu (kung@mexican.cygnus.com) + + * mips-tdep.c (mips_print_register): handle 64 bits register. + * valprint.c (print_longest): fix a bug in printing 64 bits value. + +Fri Feb 18 08:26:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Version 4.12.2. + + * Makefile.in (install): Do the sed for program_transform_name + ourselves instead of worrying about INSTALL_XFORM. This enables + users to override INSTALL_PROGRAM in the standard way. + + * Makefile.in (c-exp.tab.o, ch-exp.tab.o, m2-exp.tab.o): Don't + depend on Makefile.in. + + * defs.h, valprint.c: Make longest_to_int a function not a macro. + Only test against INT_MIN if a LONGEST is bigger than an int. + + * README: Change GhostScript to Ghostscript. + +Fri Feb 18 07:30:55 1994 Jim Kingdon (kingdon@cygnus.com) + + * config/rs6000/{tm-rs6000lynx.h,nm-rs6000lynx.h,xm-rs6000lynx.h}: + Rename to tm-rs6000ly.h, nm-rs6000ly.h, xm-rs6000ly.h for 14 + character file names. + * Makefile.in (ALLPARAM): Add these files. + + * config/mips/littlemips64.mt: Rename to mipsel64.mt for 14 + character file names. + * Makefile.in: Add Kung's new mips64 files. + +Thu Feb 17 17:25:47 1994 Kung Hsu (kung@mexican.cygnus.com) + + * configure.in: add mips64-*-elf, mips64-*-ecoff, mips64el-*-elf, + mips64el-*-ecoff and mips64-big-*. + * defs.h: get rid of FORCE_LONG_LONG. + * mips-tdep.c (mips_find_saved_regs): add sd and sdc1 instruction + parsing. Change register size to be MIPS_REGSIZE. + +Thu Feb 17 09:30:22 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * corelow.c, exec.c, irix5-nat.c, mipsread.c, objfiles.c, + osfsolib.c, rs6000-nat.c, solib.c, symfile.c, utils.c, + xcoffexec.c: Use bfd_get_error and bfd_set_error and new error names. + +Fri Feb 11 21:47:24 1994 Steve Chamberlain (sac@sphagnum.cygnus.com) + + * remote-hms.c (readchar, hms_open, hms_fetch_register): Made more robust. + (remove_commands, add_commands): Add/remove hms-drain when target + is connected. + +Fri Feb 11 16:11:38 1994 Stu Grossman (grossman at cygnus.com) + + * configure.in: Add Lynx/rs6000 support. + * lynx-nat.c: Clean up some Sparc stuff. Clean up ptrace error + messages. Add rs6000 support. Don't try to modify unwritable + registers. + * rs6000-nat.c: Move lots of native dependent stuff (like core + file support) from rs6000-tdep.c & xcoffexec.c to here. + * rs6000-tdep.c: Move native dependent stuff to nat.c. + * xcoffexec.c: Move native dependent stuff to nat.c. + * config/rs6000/nm-rs6000.h: Move defs of SOLIB_* macros to here + from tm file. + * config/rs6000/tm-rs6000.h: Remove defs of SOLIB_* funcs, cuz they're + really native. + * config/rs6000/tm-rs6000lynx.h, config/rs6000/xm-rs6000lynx.h: + New files to support Lynx/rs6000. + +Tue Feb 8 00:32:28 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * README: Remove note about gcc warnings on alpha, these should be + gone now. + * c-exp.y, ch-exp.y, core.c, corelow.c, eval.c, fork-child.c, + m2-exp.y, minsyms.c, nlmread.c, parse.c, putenv.c, regex.c + remote-utils.c, stabsread.c: Include . + * regex.c: Include "defs.h", change re_comp argument to const char *. + * infptrace.c (fetch_register, store_inferior_registers): Change + regaddr to type CORE_ADDR. + * config/alpha/alpha-nw.mt, config/alpha/alpha-osf1.mt (MT_CFLAGS): + Remove, no longer necessary now that we use bfd_vma for a CORE_ADDR. + +Mon Feb 7 09:21:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * symtab.h: Always define BYTE_BITFIELD to nothing. + +Mon Feb 7 08:44:17 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * config/m68k/{m68k-em.mt,tm-m68k-em.h}: Remove; no longer used. + * configure.in: Remove comment about m68k-em.mt. + * Makefile.in: Remove references. + +Mon Feb 7 08:22:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * defs.h [BFD64]: Use BFD_HOST_64_BIT, not nonexistent + BFD_HOST_64_TYPE. + +Sun Feb 6 15:56:09 1994 Jeff Law (law@wild.cs.utah.edu) + + * hpread.c (hpux_symfile_init): Use obj_som_* rather than obj_* to + access BFD private data. Search for the "$TEXT$" space rather + than ".text". + (hppa_sym_fns): Add bfd target flavour to initializer. + +Sun Feb 6 06:55:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.c (target_preopen): If target_kill doesn't remove the + target from the stack, use pop_target to do it. + + * coffread.c (process_coff_symbol, case C_TPDEF): Don't set name + of TYPE_CODE_PTR or TYPE_CODE_FUNC types. This parallels similar + changes to stabsread.c from summer 1993. + + * remote-udi.c (udi_files_info): If prog_name is NULL, just skip + printing the program, rather than passing NULL to printf. + (udi_detach): Set udi_session_id to -1 so that udi_close doesn't + try to call UDIDisconnect again. Print better message. + (udi_kill): Just call UDIDisconnect ourselves, rather than doing + it via udi_close. + (udi_create_inferior): If udi_session_id is negative, open a new + TIP rather than giving an error. + + * config/mips/mipsm3.mh, config/i386/i386m3.mh, + config/ns32k/ns32km3.mh: Define NAT_FILE. + * config/nm-m3.h: Change guard from _OS_MACH3_H_ and _OS_MACH3_H + (it was inconsistent and namespace-wrong) to NM_M3_H. + * m3-nat.c (mach_really_wait): Change parameter name to ourstatus. + (m3_open): New function. + (m3_ops): Use it. + * TODO: Update Mach section. + + * Makefile.in: Remove "rapp" stuff; it is superseded by gdbserver. + +Sun Feb 6 13:26:21 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * printcmd.c (printf_command): Add missing single-letter + backslash-escape sequences, and improve error message. + +Sun Feb 6 06:55:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * corelow.c (solib_add_stub, core_open): Pass address of from_tty + rather than trying to shove an int into a pointer and back out + again. This avoids compiler warnings. + + * defs.h (alloca): Declare as void *, not char *, on hpux. + Don't prototype it, just declare the return type. + +Sun Feb 6 03:25:41 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/i386/tm-sun386.h, config/i386/tm-symmetry.h + (REGISTER_CONVERT_TO_RAW): Add missing backslash. + +Sat Feb 5 08:03:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-mips.c (mips_fetch_registers): If regno is FP_REGNUM or + ZERO_REGNUM, just read it as zero without talking to the board. + + * config/i386/tm-i386aix.h (REGISTER_CONVERT_TO_RAW): Add missing + backslash. + * i386-tdep.c (i386_extract_return_value): Pass TYPE_LENGTH (type) + to store_floating, not nonexistent variable len. + + * remote-mips.c (mips_insert_breakpoint, mips_remove_breakpoint): + New functions. + (mips_store_word): Change calling convention to return errors, and + to provide old contents if the caller wants it. + (mips_xfer_memory): Deal with errors from mips_store_word. + * config/mips/tm-idt.h, config/mips/tm-idtl.h: Remove BREAKPOINT + define now that remote-mips.c doesn't use BREAKPOINT. + + * remote-mips.c (mips_create_inferior): Call warning if arguments + specified, and then execute "set args" command. Call error, not + mips_error, if executable file not specified. + + * remote-e7000.c: Replace "snoop" command (e7000_noecho) with + remote_debug. + + * config/rs6000/tm-rs6000.h (STORE_STRUCT_RETURN): Don't cast + to unsigned int. + +Sat Feb 5 05:27:05 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * value.h (print_longest): Rename "value" to "val" in prototype + declaration because some compilers don't like arguments whose + names are the same as types. + * remote.c (remote_xfer_memory): Cast "myaddr" to unsigned char * + before passing it to remote_*_bytes. + +Fri Feb 4 15:53:18 1994 Steve Chamberlain (sac@cygnus.com) + + * h8500-tdep.c (saved_pc_after_call): The size of the + pc is memory model dependent. (segmented_command, + unsegmented_command, _initialize_h8500_tdep): New commands to + change memory model. + * remote-e7000.c (_initialize_remote_e7000): Change name of snoop + command. + * remote-hms.c (hms_load): Remove breakpoints when loaded. + (hms_wait): Use new status structure + (hms_open): Push the target here. (hms_before_main_loop): Not + here. (supply_val, hms_fetch_register, hms_store_register): Cope + with H8/500 names too. (hms_fetch_register): Take out REGISTER_TYPE. + * sh-tdep.c (show_regs, initialize_sh_tdep): New command to print + all registers in a compact way. + +Fri Feb 4 07:41:13 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * config/rs6000/tm-rs6000.h: Declare rs6000_struct_return_address + as CORE_ADDR to match definition in rs6000-tdep.c. + +Fri Feb 4 01:14:20 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dwarfread.c (process_dies): Skip nested TAG_compile_unit DIEs. + * dwarfread.c (add_partial_symbol): Do not enter opaque aggregate + definitions into the psymtab. + +Thu Feb 3 12:38:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m68k-stub.c: Treat mc68332 like mc68020 most places. Provide + a special exceptionSize for the 68332. + + * remote-udi.c (udi_attach): If no arguments, print error. + +Thu Feb 3 17:34:05 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (VERSION): Bump to 4.12.1 + * NEWS, README: Update to match 4.12 release. + +Thu Feb 3 12:38:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * command.c (empty_sfunc): New function. + (add_set_cmd): Use it instead of not_just_help_class_command. + (not_just_help_class_command): Change calling convention back to + what it was before yesterday's change. + + * stabsread.c (read_sun_builtin_type): Skip the semicolon at the end + of the type if present. + +Wed Feb 2 11:16:45 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (decode_format): Don't blithely set the size for + an address to 'w'. Make it 'g' or 'h', depending on TARGET_PTR_BIT. + + * defs.h: Just typedef CORE_ADDR to bfd_vma. Include bfd.h. + If BFD64, make a LONGEST a BFD_HOST_64_BIT. + * defs.h (longest_to_int): Don't depend on CC_HAS_LONG_LONG; instead + always just check against INT_MIN and INT_MAX (this also fixes things + if sizeof (long) > sizeof (int), e.g. Alpha). + * config/pa/tm-hppa.h, config/i386/sun386.h, config/rs6000/tm-rs6000.h: + Don't define LONGEST or BUILTIN_TYPE_LONGEST. + * gdbtypes.h: Remove BUILTIN_TYPE_LONGEST and + BUILTIN_TYPE_UNSIGNED_LONGEST. + * language.h, c-lang.c, ch-lang.c, m2-lang.c, language.c: Remove + longest_int and longest_unsigned_int. + * value.h (struct value): Just align to LONGEST, rather than worrying + about CC_HAS_LONG_LONG. + * valarith.c (value_binop): Figure out type ourself based on + sizeof (LONGEST) rather than relying on BUILTIN_TYPE_LONGEST. The + point is that we don't depend on CC_HAS_LONG_LONG anymore. + * valprint.c (val_print_type_code_int): Just call + extract_unsigned_integer directly, rather than going through + unpack_long. + * printcmd.c (decode_format): Remove code which would sometimes + change 'g' size to 'w' for integers. print_scalar_formatted handles + printing huge integers well enough, thank you. + + * command.c (add_set_cmd, not_just_help_class_command): Change + to make this the sfunc, not cfunc, since that is how we call it. + * command.h: Comment difference between sfunc and cfunc. + * demangle.c (set_demangling_command): Add third arg since that + is how it is called. + (_initialize_demangler): Use sfunc, not cfunc, for + set_demangling_command, since that is how it is called. + Remove show_demangling_command; it has no effect. + + * command.c (shell_escape): Report errors correctly (with error + message from strerror). + +Wed Feb 2 14:35:41 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): Change CSECT_LEN to use + x_scnlen.l rather than x_scnlen to match corresponding change in + coff/internal.h. + +Wed Feb 2 11:16:45 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbtypes.h, ch-typeprint.c, ch-valprint.c: + Change comments regarding TYPE_CODE_BOOL. + * language.c (boolean_type): Always return 1 for TYPE_CODE_BOOL, + regardless of the language. + (value_true): Just call value_logical_not regardless of language. + * coffread.c (coff_read_enum_type), stabsread.c (read_enum_type): + Remove #if 0'd code which makes some enums TYPE_CODE_BOOL. + * language.h: Improve comment for la_builtin_type_vector. + * m2-lang.c (_initialize_m2_language): Don't add any fields to + builtin_type_m2_bool. + +Tue Feb 1 17:13:32 1994 Kevin Buettner (kev@cujo.geg.mot.com) + + * config/m88k/{tm-delta88.h,tm-delta88v4.h}, m88k-tdep.c: + Define IN_SIGTRAMP and backtrace correctly through signal handlers. + +Tue Feb 1 22:13:25 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * procfs.c (wait_fd): Handle EINTR error return from PIOCWSTOP ioctl + by restarting the ioctl. + +Tue Feb 1 16:16:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.h (target_wait): Add comment about calling + return_to_top_level. + +Tue Feb 1 12:21:00 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * coffread.c (read_one_sym): bfd_coff_swap_aux_in now takes + additional arguments. + * xcoffread.c (read_xcoff_symtab, read_symbol_lineno): Likewise. + +Mon Jan 31 16:10:41 1994 Stu Grossman (grossman at cygnus.com) + + * sparc-stub.c: Remove unnecessary #include of memory.h. + +Mon Jan 31 12:12:34 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mips-tdep.c: Remove code which sets saved_regs from + init_extra_frame_info and put it in new function mips_find_saved_regs. + (READ_FRAME_REG): Remove macro and replace uses with the expansion. + * mips-tdep.c, config/mips/tm-mips.h: When examining ->saved_regs, + check if it is NULL and call mips_find_saved_regs if so. + + * remote-mips.c: Use unfiltered, not filtered, output most places. + + * blockframe.c (get_prev_frame_info): Detect and stop an infinite + backtrace. Revise comments. + +Mon Jan 31 09:40:33 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_procedure): Remove _sigtramp kludges for + alpha and irix. The _sigtramp case has to be handled properly + in the tdep files if we have no ecoff debugging info. + * alpha-tdep.c (alpha_frame_saved_pc, alpha_frame_chain), + mips-tdep.c (mips_frame_saved_pc): Handle signal handler frames + without PC_REGNUM kludge. + * mdebugread.c (fixup_sigtramp), mips-tdep.c (read_next_frame_reg): + Clean up handling of mips sigtramp frames, improve comments. + +Sat Jan 29 23:25:57 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * paread.c (read_unwind_info): Fix typo. + + * paread.c (pa_symtab_read): Update the "check_strange_names" + filter to match GCC's current output. Filter out section symbols + (which the HP linker sometimes puts in the wrong place). + +Sat Jan 29 07:44:59 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * serial.h (SERIAL_SET_TTY_STATE): Comment return value. + + * Makefile.in (TAGS): Just echo one line, rather than the whole thing. + + * Makefile.in: Remove all references to sparcly-nat.c. + + * Makefile.in (HFILES_NO_SRCDIR): Include dcache.h remote-utils.h + remote-sim.h directly, rather than via $(remote_utils_h). This avoids + duplicating serial.h and target.h. + + * Makefile.in: Don't set M_INSTALL and M_UNINSTALL. These variables + are not used anywhere (a 5 Oct 1993 change removed the uses). + + * config/m68k/monitor.mt (TDEPFILE): Add remote-es.o. + * config/m68k/es1800.mt: Add comment. + * remote-es.c: Extensive changes to update to current conventions. + + * ser-unix.c (wait_for, hardwire_readchar) [HAVE_TERMIO, HAVE_TERMIOS]: + If the timeout is too big to fit in c_cc[VTIME], then do multiple reads + to achieve the desired timeout. + * serial.h (serial_t): Add field timeout_remaining. + +Fri Jan 28 08:45:02 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * c-exp.y (yylex): Reenable nested type code. + +Fri Jan 28 15:40:33 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * a29k-tdep.c (examine_tag): Add comment regarding argcount. + + * remote-mips.c (mips_ops): Fix docstring. + + * remote-bug.c (bug_ops): Remove spurious newline from docstring. + + * config/m68k/tm-monitor.h: Changes to bring this into accordance + with the old tm-m68k-em.h: + (GDBINIT_FILENAME, DEFAULT_PROMPT): Remove. + (HAVE_68881): Don't undefine; HAVE_68881 is obsolete. + (REGISTER_NAMES): Don't muck with it; what tm-m68k.h has is fine. + Add FIXME regarding GET_LONGJMP_TARGET. + + * remote-udi.c (udi_close, udi_detach, udi_kill): Add comments. + * infptrace.c (kill_inferior): Add comments. + * main.c (quit_command): Call target_close after we kill or + detach. + * remote-udi.c (udi_close): Don't error() if QUITTING. + +Fri Jan 28 11:55:52 1994 Rob Savoye (rob@darkstar.cygnus.com) + + * configure.in: Make m68k-coff and aout add monitor support in + addition to the standard serial support. + +Fri Jan 28 08:45:02 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * mdebugread.c (psymtab_to_symtab_1): Don't complain on stLabel with + index indexNil. + +Fri Jan 28 10:40:34 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/pa/tm-hppa.h: Define macro SMASH_TEXT_ADDRESS. + * elfread.c (record_minimal_symbol_and_info), + dwarfread.c (process_dies), paread.c (pa_symtab_read): Use it. + +Thu Jan 27 15:12:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i386-stub.c: Add ".text" right before "mem_fault:". + + * main.c (baud_rate): Add FIXME comment about printing -1 value. + + * remote-utils.c (usage): Fix message to be accurate and conform + more closely to normal conventions. + + * remote-utils.c (gr_files_info): Have the exec_bfd test control + whether to show information about exec_bfd, and not control whether + to show information about device and speed. + + * remote-utils.c (gr_open): If sr_get_device returns NULL, give + usage message, don't dump core. + + * remote-bug.c (bug_write_memory): Use alloca, not GCC extension + for variable size array. + (bug_fetch_register, bug_store_register): Rename "value" to + "fpreg_buf" because some compilers don't like variables whose + names are the same as types. + (bug_store_register): Use a cast when converting char * to + unsigned char *. + + * symmisc.c (maintenance_print_symbols): Don't refer to the name + of the command in error message (the text was referring to the old + name of the command). + + * symmisc.c (dump_symtab): Fix args to fprintf_filtered. + + * c-typeprint.c (c_type_print_base): Have SHOW == 0 mean to print + full details on structure elements without names. This partially + reverts the changes of 1 Jul 1993 and 31 Aug 1993; I think this aspect + of those changes was accidental. + + * stack.c (parse_frame_specification): If SETUP_ARBITRARY_FRAME is + defined, make it an error to specify a single argument which is not + a frame number. + + * Makefile.in (version.c), main.c (print_gdb_version): Use + host_alias and target_alias, not host_canonical and + target_canonical, to print configuration. + +Wed Jan 26 10:57:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * parse.c (write_exp_msymbol): Use new type msymbol_addr_type instead + of builtin_type_long. It is necessary to get a type which is + TARGET_PTR_BIT bits in size; builtin_type_long might not be big enough. + + Fix many sins which will come up in 32 bit x 64 bit GDB, and + various miscellaneous things discovered in the process: + * printcmd.c, defs.h (print_address_numeric): New function. + * c-valprint.c (c_val_print), ch-valprint.c (chill_val_print) + breakpoint.c (describe_other_breakpoints, breakpoint_1, mention), + cp-valprint.c (cplus_print_value), infcmd.c (jump_command), + printcmd.c, stack.c, symfile.c, symmisc.c, valprint.c: + Use it. + * utils.c, defs.h (gdb_print_address): New function. + * expprint (dump_expression), gdbtypes.h: Use it. + * breakpoint.c (describe_other_breakpoints), + symmisc.c (dump_symtab, print_symbol): + Use filtered not unfiltered I/O. + (remove_breakpoints): Remove BREAKPOINT_DEBUG code. Might as well + just run gdb under a debugger for this (and it had problems with + printing addresses, how to print b->shadow, etc.). + * buildsym.c (make_blockvector), core.c (memory_error), + exec.c (print_section_info), maint.c (print_section_table), + mdebugread.c (parse_procedure), solib.c, source.c, symfile.c, + symmisc.c, symtab.c, valops.c, valprint.c, xcoffexec.c: + Add comments saying code is broken. Marked with "FIXME-32x64". + * dbxread.c (process_one_symbol), partial-stab.h (default), + remote-vx.c (vx_run_files_info): + Don't cast int being passed to local_hex_string. + * symmisc.c (print_symbol): Don't cast long being passed to %lx. + * symtab.h (general_symbol_info): Add comment about SYMBOL_VALUE + only being a long. + * symmisc.c (print_symbol): Print "offset" in message for LOC_ARG + and LOC_LOCAL. + * printcmd.c (print_address): Remove #if 0 code with ADDR_BITS_REMOVE. + * source.c: Include regardless of USG. + +Tue Jan 25 12:58:26 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * valops.c (value_assign): Set `type' after coercing toval. + * c-valprint.c (c_val_print), ch-valprint.c (chill_val_print): + Use extract_unsigned_integer to get the address of a reference. + +Tue Jan 25 11:31:53 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (STABS_CONTINUE, error_type), partial-stab.h: + AIX can use ? instead of \ for continuation. Deal with it. + + * paread.c (read_unwind_info): Just assign to objfile->obj_private, + not OBJ_UNWIND_INFO. Assigning to a cast is a GCC-ism which + the HP compiler in ANSI mode doesn't like. + + * main.c: When defaulting HAVE_SIGSETMASK based on USG, just do it + based on USG, rather than defining HAVE_SIGSETMASK to an + expression containing defined. Having a macro used in #if expand + to an expression containing "defined" is undefined according to + ANSI, and the HP compiler in ANSI mode doesn't do what we wanted + it to. + +Mon Jan 24 20:51:29 1994 John Gilmore (gnu@cygnus.com) + + * sparc-nat.c (fetch_inferior_registers, store_inferior_registers): + Clean up the changes of 11 Jan, as recommended by Peter Schauer. + +Fri Jan 21 19:10:44 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * ch-exp.y (match_string_literal): Allow a zero-length string. + * ch-lang.c (chill_printstr): Don't print zero-length string funny. + +Sat Jan 22 17:08:48 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i386aix-nat.c (i386_float_info): Reverse order of registers before + passing them to print_387_status. + (print_387_status): Don't subtract top from 7 before using it. + * i387-tdep.c: Remove comment about AIX wanting "top" subtracted + from 7; the above explains it. + +Sat Jan 22 20:25:11 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-tdep.c (init_extra_frame_info): Use frame relative stack + pointer value when fixing up the frame at the start of a function. + +Sat Jan 22 12:29:13 1994 Stu Grossman (grossman at cygnus.com) + + * lynx-nat.c (fetch_core_registers): Load the I & L regs for the + Sparc from the stack. + +Sat Jan 22 08:30:42 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote-mips.c (mips_initialize): Clear mips_initializing via + cleanup chain, not directly. + + * ser-unix.c (wait_for) [HAVE_TERMIO, HAVE_TERMIOS]: Make a timeout + of -1 mean forever, like in the HAVE_SGTTY case. Warn if we are + munging the timeout due to the limited range of c_cc[VTIME]. + + * fork-child.c, inferior.h (fork_inferior): New argument shell_file. + * procfs.c (procfs_create_inferior), inftarg.c (child_create_inferior), + m3-nat.c (m3_create_inferior): Pass it. + * procfs.c: Remove ptrace function. It was declared in a way which + conflicted with the prototype in unistd.h on Solaris. + +Sat Jan 22 01:37:40 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-tdep.c (frame_saved_pc): Get the pc from the saved pc + in the sigcontext if it is a signal trampoline frame. + * config/sparc/tm-sun4sol2.h (IN_SIGTRAMP, SIGCONTEXT_PC_OFFSET): + Define for Solaris2. + +Sat Jan 22 00:34:47 1994 Stu Grossman (grossman at cygnus.com) + + * sparc-tdep.c, lynx-nat.c, config/sparc/tm-sparc.h, + config/sparc/tm-sparclynx.h: Move defs of FRAME_SAVED_I0/L0 to + tm-sparc.h so they can be overridden if necessary. + +Fri Jan 21 17:49:28 1994 Stu Grossman (grossman at cygnus.com) + + * lynx-nat.c: Add Sparc support. + * sparcly-nat.c: Remove. It's useless. + * config/sparc/nm-sparclynx.h: Rewrite. + * config/sparc/sparclynx.mh (NATDEPFILES): Replace sparcly-nat.o + with lynx-nat.o + * config/sparc/tm-sparclynx.h: Rewrite. + +Fri Jan 21 19:08:48 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * rs6000-pinsn.c: Use the new disassembler in the opcodes + directory. Old code was discarded, since the new opcode table has + a different format. + +Fri Jan 21 14:28:30 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (realclean): Remove info files per make-stds.texi. + +Fri Jan 21 12:47:53 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c (end_psymtab): Only patch psymtab textlow and texthigh + if N_SO_ADDRESS_MAYBE_MISSING is defined. + * config/sparc/tm-sun4sol2.h: Define it. + +Thu Jan 20 15:04:24 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * printcmd.c (print_address_symbolic): Unconditionally use msymbol + if we did not find a symbol. + +Fri Jan 21 08:20:18 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * infptrace.c (child_xfer_memory): Only use if CHILD_XFER_MEMORY + is not defined. + + * hppab-nat.c (call_ptrace): Delete redundant function. + (kill_inferior, attach, detach, child_resume): Likewise. + (child_xfer_memory): Likewise. + + * hppah-nat.c (call_ptrace): Delete redundant function. + (kill_inferior, attach, detach, child_resume): Likewise. + + * config/pa/hppabsd.mh (NATDEPFILES): Add infptrace.o. + + * config/pa/hppahpux.mh (NATDEPFILES): Add infptrace.o. + + * config/pa/nm-hppab.h (FETCH_INFERIOR_REGISTERS): Define. + + * config/pa/nm-hppah.h (FETCH_INFERIOR_REGISTERS): define. + (CHILD_XFER_MEMORY): Define. + (PT_*): Define so that generic infptrace.c code can be used. + +Fri Jan 21 09:23:33 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (xcoff_symfile_read): Make second parameter a + struct section_offsets *, not a (nonexistent) struct section_offset *. + + * xcoffread.c (read_xcoff_symtab): Make main_aux just a union + internal_xcoff_symtab, not an array of one of them. Change lots of + "main_aux" to "&main_aux" and so on. + + * coffread.c, xcoffread.c: Include + before "symfile.h". + +Thu Jan 20 17:30:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * coffread.c (coff_getfilename): Make it not static. + + * xcoffread.c (read_xcoff_symtab): complain() not abort(). + + * xcoffread.c (struct coff_symbol): Rename c_nsyms to c_naux (removes + a completely gratuitous difference between xcoffread.c and coffread.c). + +Wed Jan 19 15:09:44 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Don't set frame for + step_resume_breakpoint for IN_SIGTRAMP cases. + + * infrun.c (wait_for_inferior), breakpoint.h (struct bpstat_what), + breakpoint.c (bpstat_what): Move step_resume from its own field of + the struct bpstat_what into the main_action. Make it override + other breakpoints. This is a conservative change in the sense + that before the step resume breakpoint was a breakpoint.c + breakpoint, hitting the step resume breakpoint overrode even + calling bpstat_stop_status. + +Wed Jan 19 12:40:25 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (normal_stop): Set stop_pc after popping the dummy frame + in case execution was stopped in the called function. + * stack.c (print_frame_info, frame_info): If backtracing through + a call dummy, handle the starting source line number on a line + boundary like backtracing through sigtramp. + * sparc-tdep.c (sparc_frame_find_saved_regs): Get frame address + for call dummy frame right. Remove old test for dummy frame, + it has been unused at least since gdb-3.5. + * sparc-tdep.c (sparc_push_dummy_frame): Set return address register + of the dummy frame. + +Tue Jan 18 16:16:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infcmd.c (signal_command): Accept 0 as legitimate signal number. + +Tue Jan 18 14:09:25 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (signals_info), target.c (target_signal_from_name): + Use ugly casts to avoid enumvar < enumvar or enumvar++. + +Mon Jan 17 22:00:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ser-unix.c (hardwire_noflush_set_tty_state): Don't muck with ICANON. + * inflow.c (terminal_ours_1): When discussing how to deal with the + tty state, make note of query() as well as readline. + + * infrun.c (_initialize_infrun): Add TARGET_SIGNAL_POLL to list of + signals for which stop and print are cleared by default. + +Mon Jan 17 20:00:51 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (unwind_table_entry): Use one of the + reserved fields to hold a stub unwind entry type. Fix typo. + (stub_unwind_entry): New structure for raw stub unwind entries. + (stub_unwind_types): The types of stubs we may encounter. + (UNWIND_ENTRY_SIZE, STUB_UNWIND_ENTRY_SIZE): New defines. + * hppa-tdep.c (rp_saved): Use additional information provided + by linker stub unwind descriptors. + (frameless_function_invocation): Likewise. + (frame_chain_valid): Likewise. + * paread.c (compare_unwind_entries): New function for sorting + unwind table entries. + (read_unwind_info): Rewrite to remove dependency on host endianness. + Read in data from the $UNWIND_END$ subspace which contains linker + stub unwind descriptors. Merge that data into the basic unwind + table. + + * hppab-nat.c (_initialize_kernel_u_addr): Delete unwanted functions. + +Mon Jan 17 22:00:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (read_xcoff_symtab, case C_FILE): Accept the name + from either the symbol name or the auxent. + * coffread.c, symfile.h (coff_getfilename): Renamed from getfilename, + no longer static. + +Mon Jan 17 13:35:01 1994 Fred Fish (fnf@cygnus.com) + + * Makefile.in (ALLPARAM): Change irix5.h to nm-irix5.h. + +Mon Jan 17 12:35:42 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * README: Update notes for alpha port. + +Mon Jan 17 11:15:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i960-tdep.c (i960_fault_to_signal): Return TARGET_SIGNAL_ILL + for operation fault, constraint fault, and type fault. + +Sun Jan 16 12:46:01 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (init.c): Add comment explaining formatting conventions. + + * c-exp.y (parse_number): Assign to temporary between the right + shifts, to work around a bug in the SCO compiler. + + * Makefile.in (ALLCONFIG, ALLPARAM, ALLDEPFILES, HFILES_NO_SRCDIR): + Add various files which were added to GDB recently. + + * xcoffread.c (process_xcoff_symbol): Only change 'V' to 'S' if not + within_function. + + * Makefile.in: Add mostlyclean target. + +Sat Jan 15 10:20:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Version 4.11.4. + +Sat Jan 15 18:27:34 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * main.c (show_commands): Make return type of extern + history_get be HIST_ENTRY, rather than struct _hist_entry. + (The latter loses with the upcoming merged readline.) + +Sat Jan 15 10:20:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * minsyms.c (prim_record_minimal_symbol_and_info): Make tempstring + const char *, not char *. + + * symtab.h (struct symbol): Make section short, not unsigned short. + + * symtab.c (lookup_symbol): Add comment about QUIT here. + + * utils.c (fputs_unfiltered): Call fputs, not fputs_maybe_filtered. + + * c-exp.y (parse_number): Check for overflow regardless of range + checking. Fix overflow check to use unsigned LONGEST, not + unsigned int. + + * c-exp.y (parse_number): Make it so that integer constants are + builtin_type_long_long if builtin_type_long isn't big enough or if + an "LL" suffix is used. Properly handle "UL" or "LU" suffixes. + + * c-typeprint.c (c_type_print_varspec_suffix, case TYPE_CODE_FUNC): + Print our "()" first, then recurse for the target type. + +Fri Jan 14 21:55:39 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-udi.c (udi_create_inferior): Quote empty execfile argument. + + * gdbserver/low-lynx.c: Include not "/usr/include/wait.h". + +Fri Jan 14 14:17:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (request_quit): Re-establish signal handler regardless + of USG. + + * config/mips/xm-irix4.h: Define HAVE_TERMIOS. + +Fri Jan 14 21:55:39 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i960-tdep.c: Include target.h. + +Fri Jan 14 17:12:28 1994 Stan Shebs (shebs@andros.cygnus.com) + + * lynx-nat.c (sys/wait.h): Don't use absolute pathname. + +Fri Jan 14 11:06:10 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * lynx-nat.c (child_wait): Fix thinkos in struct target_waitstatus + changes (status -> ourstatus; declare status, etc.). + * config/nm-lynx.h: Fix child_wait prototype and include target.h. + +Fri Jan 14 14:17:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (ALLPARAM): Add config/nm-lynx.h. + +Fri Jan 14 11:49:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * remote-mips.c (mips_request, mips_wait): Correct prototypes. + +Fri Jan 14 11:37:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/i386/xm-linux.h: Define HAVE_TERMIOS. + +Fri Jan 14 01:04:36 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/alpha/tm-alpha.h (CALL_DUMMY): Improve comment. + +Thu Jan 13 10:32:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote-vx.c (vx_wait): Only call i960_fault_to_signal if I80960 + is defined. Otherwise just report TARGET_SIGNAL_UNKNOWN. + + * mips-tdep.c (mips_push_arguments): Byteswap struct_addr before + writing it. + + Add search to target vector (#if 0'd until after 4.12): + * target.h (to_search, target_search): Add. + * gdbcore.h, core.c (generic_search): Add. + * remote.c (remote_search): Add. + * a29k-tdep.c (init_frame_info): Use target_search to find traceback + tag. + + * printcmd.c (print_address_symbolic): If set print fast-symbolic-addr + is on, call find_pc_function rather than relying just on the minimal + symbols (probably only matters for symbol readers which don't put + statics in the minimal symbols, but changing this strikes me as + not conservative enough). + Initialize name_location in all cases. + If no symbol and no msymbol, don't print anything symbolic. + + * a29k-tdep.c (push_dummy_frame): Add comment about saving lr0. + +Wed Jan 12 20:53:16 1994 John Gilmore (gnu@cygnus.com) + + * printcmd.c (print_address_symbolic): Make it search the + symtabs for variables as well as functions. Add `set print + fast-symbolic-addr' and default it to fast (the old way). + Print line numbers for data items as well as functions. + + * symtab.c (find_addr_symbol): Return the symtab and the symbol + address, if a symbol is found (take two more args pointing to + where to store these results). + + * symtab.h (find_addr_symbol): Add prototype. + +Wed Jan 12 19:32:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * objfiles.h: Fix comments to reflect the fact that the phrase + "top of stack" always refers to where the pushing and popping takes + place, regardless of whether it is at the highest or lowest address. + +Wed Jan 12 13:23:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_symbol): Do not set TYPE_TAG_NAME for + compiler generated tag names. + * mdebugread.c (parse_type): Handle cross references to qualified + aggregate types. + * valops.c (value_struct_elt): Improve error message if the + address of a method is requested from an object instance. + * valops.c (search_struct_method): Make name_matched non-static + to get it initialized correctly. + * config/i386/nm-i386sco.h (CANNOT_STORE_REGISTER): Define to + exclude segment register which are not writable on newer SCO versions. + +Wed Jan 12 14:44:45 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * go32-xdep.c: Remove unused function uerror. + (sigsetmask): Declare return type. Declare argument (to match the + way it is called). Explicitly return 0. + +Wed Jan 12 01:44:25 1994 John Gilmore (gnu@cygnus.com) + + * symtab.h (struct symbol, general_symbol_info, minimal_symbol, + partial_symbol): Shrink the storage sizes of symbols, by making + enums into 1-byte bitfields when compiled __GNUC__, moving all the + enums and small ints to the end of each struct to improve + alignment, and switching the section number from int to unsigned + short. + +Wed Jan 12 00:16:26 1994 John Gilmore (gnu@cygnus.com) + + * symtab.c (find_addr_symbol): New routine that will find the nearest + symbol associated with an address. It does so by exhaustive + search of the symtabs, so it's slow but complete. + +Tue Jan 11 23:57:30 1994 John Gilmore (gnu@cygnus.com) + + * coffread.c (read_coff_symtab): Set PC bounds of _globals_ symtab + to [0,0] rather than [0, end of first source file]. This avoids + problems with other parts of GDB looking for linetables in the + _globals_ symtab. Eliminate variables num_object_files and + first_object_file_end. + +Tue Jan 11 00:53:46 1994 John Gilmore (gnu@cygnus.com) + + * a29k-tdep.c (init_frame_info): Cast null arg to examine_tag. + (pop_frame): Restore PC2 and LR0 from dummy frames. + (push_dummy_frame): Save PC2 and LR0 into dummy frames. + (setup_arbitrary_frame): Handle 3 args and set up real frames. + * config/a29k/tm-a29k.h (FRAME_NUM_ARGS): Update comments. + (DUMMY_FRAME_RSIZE): Add 2 longwords for PC2 and LR0. + (SETUP_ARBITRARY_FRAME): Define. + +Tue Jan 11 06:59:10 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * infrun.c, config/mips/tm-irix5.h: Remove #if 0'd AT_FUNCTION_START. + +Tue Jan 11 14:27:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * remote-udi.c (udi_resume): Correct prototype. + +Tue Jan 11 11:10:30 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (FRAME_FIND_SAVED_REGS): Call + hppa_frame_find_saved_regs. + * hppa-tdep.c (dig_fp_from_stack): Delete function. + (prologue_inst_adjust_sp): New function. + (is_branch, inst_saves_gr, inst_saves_fr): New functions. + (skip_prologue): Completely rewrite to use unwind information. + (hppa_frame_find_saved_regs): Likewise. + +Tue Jan 11 06:59:10 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * remote-mips.c (mips_wait): Use new function mips_signal_from_protocol + to convert a signal number with appropriate bounds checking. + + * remote-mips.c (mips_wait): Fix typos (0x177 -> 0177, 0x377 -> 0377). + +Tue Jan 11 00:53:46 1994 John Gilmore (gnu@cygnus.com) + + * stack.c (frame_info): If FRAME_FIND_SAVED_REGS isn't defined, + print a newline to end the display anyway. + + * sparc-tdep.c (sparc_pop_frame): Pop the fsr and csr (float and + coprocessor status regs) when popping a frame. This fixes + float exceptions that occur after calling inferior functions. + + * sparc-nat.c (fetch_inferior_registers, store_inferior_registers): + Read and write the fsr (float status register) to/from the child + process along with the float regs. Remove Peter Schauer's change + of May 24 '93, which has higher overhead and doesn't solve the + real problem (which was that FSR wasn't being set). + +Mon Jan 10 23:16:42 1994 John Gilmore (gnu@cygnus.com) + + * a29k-tdep.c (examine_prologue): Don't worry if the ASGEQ + stack overflow check isn't right after the register stack + adjustment instruction. Metaware R2.3u compiler moves other + things in front of it. This fix isn't perfect but is what's + running. + +Mon Jan 10 20:08:23 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * c-valprint.c (c_val_print): Treat TYPE_CODE_RANGE like TYPE_CODE_INT. + + * config/alpha/alpha-netware.mt: Rename to alpha-nw.mt for 14 + character filenames. + * configure.in: Change accordingly. + +Mon Jan 10 15:48:36 1994 Tom Lord (lord@rtl.cygnus.com) + + * m68k-stub.c, sparc-stub.c: removed spurious introduction of + _filtered io routines from these two files. + +Fri Jan 7 12:42:45 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/i386/tm-i386v.h, config/m68k/tm-m68k.h, config/mips/tm-mips.h, + config/vax/tm-vax.h (CALL_DUMMY_BREAKPOINT_OFFSET): Define. + * mdebugread.c (parse_symbol): Handle enum sh.type produced by + DEC c89. + * mdebugread.c (add_line): Handle zero linenos produced by DEC c89. + +Fri Jan 7 12:55:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c (print_sys_errmsg): Call gdb_flush (gdb_stdout) before + printing to gdb_stderr. + + * remote-udi.c (udi_kill): Don't close the connection, just set + inferior_pid to zero. + (udi_mourn): Call remove_breakpoints. + + * remote-udi.c: Remove obsolete need_artificial_traps comment. + + * i386b-nat.c (sregmap): If sEAX, etc., not defined, use tEAX, etc. + +Thu Jan 6 07:17:53 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * symtab.c (lookup_symbol): Don't try adding .c to the name. + + * remote-bug.c: At the start of each section, reset srec_frame + back to 160. + + * target.h: Add TARGET_WAITKIND_LOADED and TARGET_WAITKIND_SPURIOUS. + * target.c (store_waitstatus): Add CHILD_SPECIAL_WAITSTATUS hook. + * infrun.c (wait_for_inferior): Replace SIGTRAP_STOP_AFTER_LOAD with + code which looks for those two waitkinds. Use switch statement. + * config/rs6000/tm-rs6000.h: Replace SIGTRAP_STOP_AFTER_LOAD with + CHILD_SPECIAL_WAITSTATUS. + + * procfs.c (procfs_wait): Fix argument name to match 4 Jan changes. + * Move target_signal_from_host, target_signal_to_host, and + store_waitstatus from inftarg.c to target.c. procfs needs them. + * target.c: Include "wait.h" and . + * target.h, infrun.c (proceed), proceed callers: Pass new code + TARGET_SIGNAL_DEFAULT instead of -1. This avoids problems with + enums being treated as unsigned and is cleaner. + * infrun.c (signals_info): Don't print TARGET_SIGNAL_DEFAULT or + TARGET_SIGNAL_0. + * infcmd.c (signal_command), infrun.c (signals_info): + Don't allow user to specify numeric equivalent of + TARGET_SIGNAL_DEFAULT. + +Tue Jan 4 15:34:36 1994 Stu Grossman (grossman@cygnus.com) + + * config/alpha/alpha-netware.mt: New target support for Alpha + running Netware. + * configure.in: Add alpha-*-netware* target. + +Tue Jan 4 14:51:35 1994 Stan Shebs (shebs@andros.cygnus.com) + + * remote-mips.c (mips_wait): Fix ref to TARGET_WAITKIND_STOPPED. + +Tue Jan 4 09:47:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * target.h: Add enum target_waitkind, enum target_signal, and + struct target_waitstatus. Change status argument to target_wait to + be struct target_waitstatus * instead of int *. + * target.h, infrun.c, all targets: Change type of signal arguments + to resume(), proceed(), and target_resume() from int to enum + target_signal. + * All targets (*_wait, *_resume): Change accordingly. + * infcmd.c (program_info, signal_command), throughout infrun.c, + * fork-child.c, solib.c, hppa-tdep.c, osfsolib.c: Use this stuff. + * convex-xdep.c, convex-tdep.c: Add FIXME's (getting the Convex + signal code stuff right with the new signals would be non-trivial). + * inferior.h (stop_signal): Make it enum target_signal not int. + * target.c, target.h (target_signal_to_string, target_signal_to_name, + target_signal_from_name): New functions. + * inftarg.c, target.h (target_signal_to_host, target_signal_from_host, + store_waitstatus): New functions. + * procfs.c (procfs_notice_signals): Use them. + * i960-tdep.c (i960_fault_to_signal): New function, to replace + print_fault. + * config/i960/tm-i960.h: Don't define PRINT_RANDOM_SIGNAL. + + * objfiles.c (build_objfile_section_table): Don't abort() if + objfile->sections is already set. + + * objfiles.c (add_to_objfile_sections): Check SEC_ALLOC not SEC_LOAD + to match recent change to exec.c. + + * Version 4.11.3. + + * main.c (print_gdb_version): Change year to 1994. + + * ChangeLog, ChangeLog-93: Split ChangeLog at 1994. + * Makefile.in (NONSRC): Add ChangeLog-93. + +Mon Jan 3 11:57:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabsread.c (read_type): Allow defining several type numbers + at once (e.g. "(1,2)=(3,4)="...). + + * stabsread.c (read_enum_type): Use TARGET_INT_BIT not sizeof (int). + + * breakpoint.c (frame_in_dummy): Check PC as well as frame. + +Mon Jan 3 02:47:03 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (psymtab_to_symtab_1): Only pass N_STAB symbols + to process_one_symbol. + * symtab.c (find_pc_psymbol): Search global_psymbols as well to + avoid caching a bad endaddr in find_pc_partial_function. + +Sun Jan 2 21:41:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/tm-sun3.h: Don't define BELIEVE_PCC_PROMOTION. + +Sat Jan 1 04:35:23 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * infrun.c (wait_for_inferior): Do not step or step resume past + the end of a one-line function we just stepped into. + +For older changes see ChangeLog-93 + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/gdb/ChangeLog-95 b/contrib/gdb/gdb/ChangeLog-95 new file mode 100644 index 000000000000..cdf4ddabcc51 --- /dev/null +++ b/contrib/gdb/gdb/ChangeLog-95 @@ -0,0 +1,4882 @@ +Fri Dec 29 16:30:58 1995 Stan Shebs + + * symfile.c (find_sym_fns): Add PowerMac to xcoff file recognition + kludge. + + +Fri Dec 22 11:05:59 1995 Michael Meissner + + * configure.in (gdb_host): Add support for DG/UX running on x86 as + a host. + (all x86 targets and hosts): Add support for pentium-pro machines. + + * configure: Rebuild. + + * config/i386/i386dgux.mh: New file for DG/UX running on x86 host. + +Thu Dec 21 19:09:20 1995 Rob Savoye + + * remote-array.c (array_wait): Poll the keyboard along with the + serial port so users can tpye at the target while their + application is running. + +Thu Dec 21 11:58:52 1995 Michael Meissner + + * Makefile.in (ppcbug-rom.o, srec.o): Add dependencies. + + * monitor.c (monitor_debug): Take prefix, and suffix arguments. + Print trailing newline after the suffix. + (monitor_printf{,_noecho}): Change monitor_debug calls. + (monitor_printf): Call monitor_expect instead of trying to do the + expect processing locally so that if there is extra junk, it + doesn't hang things up. + (readchar): If MO_HANDLE_NL is set, handle \r\n pairs and convert + them to a single \r. Use monitor_debug to print out byte read. + + * monitor.h (MO_HANDLE_NL): Add new flag. + + * ppcbug-rom.c (ppcbug_ops{1,2}): Split into two ops, one that + uses lo 0 to load, and the other that uses lo 1. Set flag + MO_HANDLE_NL. + (ppcbug_open{0,1}): Clone and split to handle ppcbug_ops{1,2}. + (_initialize_ppcbug_rom): Set up both ppcbug_open{0,1}. + +Wed Dec 20 10:54:41 1995 Fred Fish + + * defs.h: Delete extraneous whitespace at end of file. + * symfile.h: Move #include of demangle.h outside conditional. + * objfiles.h (struct objstats, OBJSTAT, OBJSTATS): New struct and + macros to hold per-objfile statistics for internal + instrumentation. + (struct objfile): Add OBJSTATS member, which is optional. + * buildsym.h (next_symbol_text_func): Now takes objfile argument. + Also update copyright to 1995. + * dbxread.c (dbx_next_symbol_text): Now takes objfile argument. + (dbx_symfile_init, coffstab_build_psymtabs, elfstab_build_psymtabs, + stabsect_build_psymtabs): Accumulate string table size. + (dbx_next_symbol_text, read_dbx_symtab, read_ofile_symtab): + Accumulate number of stabs symbols read. + * dwarfread.c (new_symbol, symthesize_typedef): + Accumulate number of full symbols created. + * gdbtypes.c (alloc_type): Accumulate number of types. + * maint.c (maintenance_print_statistics): New function. + * mdebugread.c (mdebug_next_symbol_text): Now takes objfile + argument. + * minsyms.c (prim_record_minimal_symbol_and_info): Accumulate + number of minimal symbols read. + * os9kread.c (read_os9k_psymtab): next_symbol_text takes objfile + arg. + * partial-stab.h: next_symbol_text takes objfile arg. + * stabsread.c (error_type, STABS_CONTINUE): Now takes objfile arg + and uses it to call next_symbol_text. + * symfile.c (add_psymbol_to_list, add_psymbol_addr_to_list): + Accumulate number of partial symbols created. + * symfile.h (ADD_PSYMBOL_VT_TO_LIST): Accumulate number of partial + symbols created. + * symmisc.c (print_objfile_statistics): Print the per-objfile + internal instrumentation statistics gathered. + * xcoffread.c (xcoff_next_symbol_text): Now takes objfile argument. + +Fri Dec 15 16:15:55 1995 Ian Lance Taylor + + * top.c (set_endian_from_file): Use new bfd_big_endian macro. + +Fri Dec 15 12:21:10 1995 Raymond Jou + + * mpw-make.sed: Add quotes to RIncludes reference. + +Fri Dec 15 13:18:55 1995 Rob Savoye + + * remote-array.c: Remove bogus setting of baudrate to 4800. Their + hardware has real UARTS now. + +Mon Dec 11 18:19:16 1995 Stan Shebs + + * configure.in (powerpc-*-macos*): New target configuration. + * configure: Update. + * config/powerpc/macos.mh, config/powerpc/macos.mt, + config/powerpc/nm-macos.h, config/powerpc/tm-macos.h, mac-nat.c: + New files, native PowerMac debugging support. + * Makefile.in (mac-nat.o): Add build rule. + * mpw-config.in (enable_cflags): Add support. + (m68k-apple-macos, powerpc-apple-macos): Fix natdepfiles to + list object file instead of source file. + * mpw-make.sed (@ENABLE_CFLAGS@): Don't edit out, replace with + value of variable. + (install, install-only): Edit MPW-specific installation into + place of Unix shell code. + * mac-gdb.r: Fix version resources to use symbolic version strings. + (cfrg): New resource, code fragment for PowerMac. + + +Mon Dec 11 14:13:03 1995 Fred Fish + + * dbxread.c (process_one_symbol): When looking at the next + minimal symbol, check for end of the minimal symbol array + (symbol with NULL pointer for name) before dereferencing it. + +Mon Dec 11 15:56:55 1995 Per Bothner + + * eval.c (evaluate_struct_tuple): Fix thinko. + +Mon Dec 11 06:52:02 1995 Wilfried Moser (Alcatel) + + * ch-typeprint.c (chill_type_print_base): Slightly change of printing + of variant structures. + +Mon Dec 11 00:36:01 1995 Per Bothner + + * valops.c (value_cast): Handle casts to and from TYPE_CODE_CHAR. + * ch-exp.c (match_integer_literal): Fix long long support. + * gdbtypes.c (get_discrete_bounds): Make TYPE_LENGTH (type) == + sizeof (LONGEST) case work OK. + +Fri Dec 8 21:02:24 1995 Fred Fish + + * coffread.c, dbxread.c, dstread.c, objfiles.c, os9kread.c, + symfile.c, symtab.c: Use "obstack.h" rather than . + +Wed Dec 6 16:16:18 1995 Stu Grossman (grossman@cirdan.cygnus.com) + + * remote-mips.c (mips_receive_header): Allow mips_syn_garbage to be + user-settable (via set syn-garbage-limit). Setting it to -1 makes + it unlimited. + +Tue Dec 5 18:33:43 1995 Brendan Kehoe + + * gdbtypes.c (check_stub_method): Make sure we get back a function + string in the demangled name before we try to use it. + +Tue Dec 5 18:08:29 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c (monitor_expect_regexp): Make static, add prototype. + * (monitor_read_memory_single): Call monitor_expect_regexp with + pointer to getmem_resp_delim_pattern, not entire struct. + +Tue Dec 5 15:51:25 1995 Stan Shebs + + * c-lang.h (c_op_print_tab): Don't declare, some compilers + consider illegal if structure not defined, and only used + in c-lang.c anyway. + +Sun Dec 3 12:31:03 1995 Per Bothner + + * eval.c (evaluate_subexp_standard case): Fix typo. + +Sun Dec 3 11:59:21 1995 Jeffrey A. Law + + * ch-exp.c (parse_named_record_element): Avoid aggregrate + initializations for automatic variables. + + * hppa-tdep.c (hppa_alignof): Fix typo in last change. + +Sat Dec 2 19:32:57 1995 Fred Fish + + * symfile.c (global_psymbols, static_psymbols): Remove, unused. + +Sat Dec 2 03:02:21 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-tdep.c (heuristic_proc_desc): Add heuristic to + determine the return address register, needed for OSF/1-3.2C. + * config/alpha/tm-alpha.h (T7_REGNUM, T9_REGNUM): Define. + +Fri Dec 1 07:23:57 1995 Michael Meissner + + * ppcbug-rom.c (ppcbug_cmds): Turn on MO_GETMEM_READ_SINGLE + because PPCbug displays the memory as characters as well as hex. + Fix getmem/setmem commands. + + * srec.c (load_srec): Fix off by one typo in last submission. + + * rs6000-tdep.c (push_arguments): Fix typo. + +Thu Nov 30 23:54:17 1995 Per Bothner + + * language.c (lang_bool_type), language.h: New function. + * language.h (LA_BOOL_TYPE): New macro. + * eval.c (evaluate_subexp_standard) Use LA_BOOL_TYPE instead + of builtin_type_int where appropriate, + * valarith.c (value_subscript): Likewise. + + * valops.c (value_slice): Implement (value) bitstring slices. + * valprint.c (val_print): If TYPE_LENGTH is zero, don't automatically + print "" - Chill has zero-length (string) types. + + * gdbtypes.c (check_stub_type): Removed; no longes needed. + * ch-exp.c (expect, parse_call): Tweak error messages. + +Wed Nov 29 13:35:18 1995 Per Bothner + + * scm-valprint.c (scm_isymnames): Remove "#@" prefix. + (scm_scmval_print): Do not print "#@" prefix. + + * gdbtypes.h (enum type_code): Added TYPE_CODE_TYPEDEF. + (check_typedef): New prototype. + (CHECK_TYPEDEF): New macro. + (TYPE_DUMMY_RANGE): Removed. + * gdbtypes.c (get_discrete_bounds): Fix paren error; make more robust. + (create_array_type): Don't force_to_range_type; users of the + array are responsible for handling non-range index types. + (create_set_type): Likewise. + (force_to_range_type): Removed. + (check_typedef): New function handles stub types and typedefs. + (check_stub_type): Just call check_typedef. (To be removed.) + (recursive_dump_type): Handle TYPE_CODE_TYPEDEF. + * ch-lang.c (type_lower_upper): Use get_discrete_bounds. + (evaluate_subexp_chill): Handle string repetition. + Re-arrange to handle EVAL_AVOID_SIDE_EFFECTS better. + * ch-typeprint.c (chill_type_print_base): Handle TYPE_CODE_TYPEDEF. + Pass show=0 in recursive calls various places. + (case TYPE_CODE_ARRAY): Don't require index type to have + TYPE_CODE_RANGE. + (case TYPE_CODE_RANGE): Don't need to support TYPE_DUMMY_RANGE. + * gdbtypes.c, ch-lang.c, ch-typeprint.c (numerous places): + Add check_typedef/CHECK_TYPEDEF as needed. + + * ch-exp.y: Replaced by ... + * ch-exp.c: New file. Use recursive-descent. + Recognize labelled array tuples and powerset ranges. + * Makefile.in: Update for no longer using yacc for ch-exp. + + * c-lang.c: Make various functions non-static. + * c-lang.h: Add bunches of prototypes. + * cp-valprint.c (cp_print_value_fields): Also take address. + (cp_print_value): Likewise. Use baselcass_offset. + * stabsread.c (current_symbol): New static variable. + (type_synonym_name): Remove. + (read_type): If copying, make copy be a TYPE_CODE_TYPEDEF. + (read_array_type): Don't need to handle undefined element type here. + (cleanup_undefined_types): Ditto. + (read_range_type): Look for Chill ranges. + * valops.c (value_assign): Fix case lval_internalvar - don't try + to assign into old value (which might be too small!). + (value_coerce_array): No longer need special VALUE_REPEATED handling. + (value_arg_coerce): Cleaner array->pointer decay mechanism. + (search_struct_field): Use baseclass_offset rather than + baseclass_addr. + (value_slice): Use get_discrete_bounds. + * value.h (COERCE_VARYING_ARRAY): Take type argumnt as well. + * values.c (baseclass_offset): Change parameter interface. + (baseclass_addr): Removed. + * c-typeprint.c, c-valprint.c, ch-valprint.c, values.c, valops.c: + Add check_typedef/CHECK_TYPEDEF as needed. + + * alpha-tdep.c, c-exp.y, h8500-tdep.c, f-exp.y, f-valprint.c, + findvar.c, hppa-tdep.c, infcmd.c, language.c, printcmd.c, + rs6000-tdep.c, symmisc.c, symtab.c, mdebugread.c: + Add check_typedef/CHECK_TYPEDEF as needed. + + * f-typeprint.c, valarith.c, valprint.c, typeprint.c, eval.c: + Add check_typedef/CHECK_TYPEDEF as needed. + * f-typeprint.c: Various cleaning up. + * valarith.c (value_subscript): Also subscript bitstrings (for Chill). + * typeprint.c (print_type_scalar): Also support TYPE_CODE_RANGE. + * eval.c (evaluate_subexp_standard case OP_ARRAY): Implement + support for labelled array tuples and ranges in powerset tuples. + (init_array_element): New function. + + * top.c (command_line_input): Only strip out an initial #-comment. + Looking for internal comments is language-specific (breaks Scheme). + + * expression.h (enum exp_opcode): Add BINOP_RANGE. + * expprint.c (dump_expression): Support BINOP_RANGE. + * eval.c (evaluate_subexp_standard): Handle BINOP_RANGE (as error). + (case MULTI_SUBSCRIPT): Fix broken f77 value->int ad hoc conversion. + * ch-lang.c (chill_op_print_tab): Support BINOP_RANGE. + (evaluate_subexp_chill): Error on BINOP_COMMA. + + * Makefile.in: Clean up so doc stuff stays in doc sub-dir. + +Wed Nov 29 16:39:50 1995 Michael Meissner + + * monitor.c (monitor_debug): New function to print monitor debug + output in printable fashion. + (monitor_printf{,_noecho}): Call monitor_debug instead of + fputs_unfiltered. + + * srec.c (load_srec): When printing srec debug information, do not + print the carriage return directly, instead print \\r followed by + a newline. + +Tue Nov 28 15:25:28 1995 Doug Evans + + * Makefile.in (target_subdir): Define. + (CC_FOR_TARGET, CXX_FOR_TARGET): Use it to find target libraries. + * configure.in (X_CFLAGS): Fix typo. + (target_subdir): Set to "${target_alias}/" if cross. + * configure: Regenerated. + + * dbxread.c (dbx_symfile_read): Set block_address_function_relative + for `pe' format files. + +Tue Nov 28 11:17:47 1995 Fred Fish + + * magic.h: Renamed to gmagic.h to avoid conflict. + * magic.c: Renamed to gmagic.c in sympathy. + * eval.c, gmagic.c, config/tm-magic.h: + Include "gmagic.h" rather than "magic.h". + +Sat Nov 25 02:56:38 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (handle_psymbol_enumerators, parse_symbol): + Recognize enums from alpha cc -migrate. + (upgrade_type): Pass correct fd to parse_symbol when parsing + the index type of an array. + (parse_procedure, parse_lines, psymtab_to_symtab_1): Handle + unsorted procedure descriptors from Irix 5.x and Alpha OSF/1-3.x + shared libraries. Use CORE_ADDR instead of `unsigned long' in + procedure descriptor address computations. + + * symtab.c (decode_line_1): Prevent accidental strchr match + of a null character with the terminating null character of + gdb_completer_quote_characters. + (cplusplus_hint): Make sure that only a single quote is printed + in the hint message. + +Fri Nov 24 16:17:01 1995 Jeffrey A Law (law@cygnus.com) + + * top.c (recurse_read_control_structure): Don't make cleanups + here. Callers handle that correctly. + +Tue Nov 21 15:16:34 1995 Fred Fish + + * config/m68k/xm-hp300hpux.h: Define MMAP_BASE_ADDRESS and MMAP_INCREMENT. + Also force HAVE_MMAP to be defined since autoconf is currently broken + for detecting a working mmap under hpux. + * config/pa/xm-hppah.h (MMAP_BASE_ADDRESS): Tweak MMAP_BASE_ADDRESS + to a better value suggested by Jeffrey A Law (law@cygnus.com). + +Tue Nov 21 08:48:58 1995 Fred Fish + + * config/pa/xm-hppah.h: Define MMAP_BASE_ADDRESS and MMAP_INCREMENT. + Also force HAVE_MMAP to be defined since autoconf is currently broken + for detecting a working mmap under hpux. + * objfiles.c (map_to_address): Have gdb print a warning when it + is compiled with HAVE_MMAP but without both MMAP_BASE_ADDRESS and + MMAP_INCREMENT defined (thus making it appear mmap doesn't work). + +Mon Nov 20 14:13:53 1995 Stu Grossman (grossman@cygnus.com) + + * infrun.c (wait_for_inferior): Add support for dynamic function + trampolines. These are pieces of code between the caller and the + callee that figure out the address of the callee's code at run + time. Upon entry, we can't figure out the callee's address, so we + set a breakpoint within the trampoline where the address will be + known, and continue the target. Once we hit the breakpoint, we + break at the callee's address and proceed as usual. + +Mon Nov 20 11:12:34 1995 Fred Fish + + * objfiles.c (allocate_objfile): Change warning message about mapped + symbol tables so that it is obvious that they are not supported on + this particular machine rather than implying they are not supported + at all in this version of gdb. + +Sun Nov 19 05:20:53 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * irix5-nat.c, osfsolib.c (solib_address): Return the name of the + containing solib. + * stack.c (print_frame_info): Use minimal symbol only if + fi->pc is in a known section. + +Sat Nov 18 11:19:35 1995 Roland McGrath + + * solib.c (solib_address): Return the name of the containing solib. + * solib.h (PC_SOLIB): New macro; define using solib_address. + * stack.c (print_frame_info) [PC_SOLIB]: If no function name, try + PC_SOLIB on the PC value. + +Sat Nov 18 04:09:31 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * annotate.c (annotate_source, annotate_frame_begin): Issue + `0x' prefix for the pc value, to remain consistent with previous + GDB versions. + + * blockframe.c (find_pc_partial_function), config/pa/tm-hppa.h: + Remove Sun shared library transfer hack and + INHIBIT_SUNSOLIB_TRANSFER_TABLE_HACK, it is obsoleted by the + mst_solib_trampoline minimal symbols. + + * blockframe.c (inside_main_func): Check main_func_*pc against + INVALID_ENTRY_*PC, not zero. + * symfile.c (init_entry_point_info): Initialize ei.*pc with + INVALID_ENTRY_*PC. + * mipsread.c (mipscoff_symfile_read): If the entry_file bounds + are still unknown after processing the partial symbols, then try + to set them from the minimal symbols. + + * infcmd.c (registers_info): Error out if selected_frame is NULL. + * stack.c (return_command): Select new current frame silently if + not interactive. + + * mipsread.c (read_alphacoff_dynamic_symtab): Ignore additional + DT_MIPS_LOCAL_GOTNO and DT_MIPS_GOTSYM entries. + + * irix5-nat.c (solib_create_inferior_hook): Call solib_add only + if auto_solib_add_at_startup is nonzero. + (_initialize_solib): Add "set auto-solib-add" command. + * osfsolib.c (solib_create_inferior_hook): Call solib_add only + if auto_solib_add_at_startup is nonzero. + (_initialize_solib): Add "set auto-solib-add" command. + +Wed Nov 15 17:12:04 1995 Stan Shebs + + * utils.c: Don't include sys/ioctl.h etc if MPW is host. + +Tue Nov 14 17:16:46 1995 Doug Evans + + * config/arm/tm-arm.h (ADDITIONAL_REGISTER_NAMES): Fix r5. + (FRAME_SAVED_PC): Minor clean up. + +Tue Nov 14 14:51:05 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c (monitor_load_srec monitor_make_srec): Move all + S-record download code into srec.c. + * srec.c srec.h: New files. Contain S-record loading routines + formerly in monitor.c. + * serial.c serial.h: New routine just like fprintf, but uses + serial_t instead of FILE *. + * sh-tdep.c (frame_find_saved_regs init_extra_frame_info): + Don't add four to saved pc (makes things match manual). Also, fix + bug where we didn't get pc from stack frame correctly. + * config/sh/tm-sh.h (SAVED_PC_AFTER_CALL): Don't add four to + saved pc. Real hardware does this for you. + * sh3-rom.c (sh3_load): New routine. Sets up for download then + calls generic S-record loader. + * config/h8300/h8300.mt, config/h8500/h8500.mt, + config/m68k/monitor.mt, config/pa/hppapro.mt, config/sh/sh.mt: + Add srec.o to TDEPFILES. + +Tue Nov 14 15:57:36 1995 Michael Meissner + + * ppcbug-rom.c: New file to support the Motorola PPCBUG monitor + for PowerPC's. + + * config/powerpc/ppc{,le}-{eabi,sim}.mt (TDEPFILES): Include + ppcbug-rom.o, monitor.o, and srec.o + + * config/i386/linux.mt (XDEPFILES): Include ser-tcp.o. + +Mon Nov 13 13:12:46 1995 Jeffrey A Law (law@cygnus.com) + + * partial-stab.h: Remove GDB_TARGET_IS_HPPA kludge. + +Fri Nov 10 13:08:54 1995 Jeff Law (law@kahlua.cs.utah.edu) + + * terminal.h (HAVE_SGTTY): Fix typo. + +Thu Nov 9 17:34:01 1995 Michael Meissner + + * configure.in (gdb_target): Build in the simulator for all + PowerPC eabi targets, not just eabisim, providing + --enable-sim-powerpc is used, or the host compiler is GCC. + +Thu Nov 9 14:04:05 1995 Raymond Jou (rjou@mexican.cygnus.com) + + * mpw-config.in: Add variable with names of SIOW libraries. + * mpw-make.sed: Add an action to build SIOWgdb. + +Wed Nov 8 19:25:22 1995 Stan Shebs + + * mpw-make.sed: Edit @ENABLE_CFLAGS@ out, mpw-configure can + add back in if necessary. + +Wed Nov 8 15:59:52 1995 James G. Smith + + * config/mips/vr4300.mt: Added simulator to default VR4300 build. + +Tue Nov 7 16:02:25 1995 Stu Grossman (grossman@cygnus.com) + + * remote-mips.c (mips_initialize): Fix brain damage found by + Jamie. Basically had case statement in the wrong place... + * (mips_load): Remove unnecessary `db tty0' command. It's all + handled by mips_initialize now. + +Tue Nov 7 12:59:14 1995 Raymond Jou + + * mac-gdb.r: Added #ifdef Macgdb. + +Tue Nov 7 14:59:51 1995 James G. Smith + + * remote-mips.c (mips_initialize): Updated to talk to VR4300 RISQ + monitor board. + +Mon Nov 6 11:44:11 1995 James G. Smith + + * config/mips/{tm-vr4300.h tm-vr4300el.h} (TARGET_MONITOR_PROMPT): + Change into real strings. + + * remote-sim.c (gdbsim_open): Moved sim_open() call to after + callback initialisation. + +Sun Nov 5 00:07:52 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in (AC_CHECK_HEADERS): add stddef.h. + +Fri Nov 3 12:30:43 1995 Fred Fish + + * Makefile.in (COMMON_OBS): Use corefile.o rather than core.o + * core.c: Rename to corefile.c. + * config/pyr/tm-pyr.h, umax-xdep.c, sun386-nat.c, pyr-xdep.c, + Makefile.in (SFILES), gould-xdep.c, coredep.c, armtdep.c, + arm-xdep.c, altos-xdep.c: Change core.c references to corefile.c. + + From Graham Stoney . + * Makefile.in (remote-array.o): Add rule to build. + (ALLDEPFILES): Add remote-array.c + * remote-array.c (baud_rate): Remove unnecessary declaration. + (baudrate): Remove. + (array_files_info): Print global baud_rate not baudrate. + +Sat Nov 4 10:21:58 1995 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (INTERNAL_CFLAGS): Add ENABLE_CFLAGS. + * fork-child.c (fork_inferior): Add call to + TARGET_CREATE_INFERIOR_HOOK to allow target specific code to get + control just before the new process executes it's first instruction. + * remote-mips.c (mips_initialize): Cleanup a bit. Don't try to + receive a packet at first. This speeds up initialization a lot. + Use TARGET_MONITOR_PROMPT instead of "". + (common_breakpoint): Use rresponse instead of rerrflg to inspect + error code. + * symfile.c (syms_from_objfile reread_symbols): Call + TARGET_SYMFILE_POSTREAD to allow target specific code to get + control after reading new symbols. + * target.h: New macros TARGET_SYMFILE_POSTREAD, and + TARGET_CREATE_INFERIOR_HOOK. See above for descriptions. + * config/mips/{irix5.mh nm-irix5.h}: Delete nm-irix5.h. Make + NAT_FILE point directly at ../nm-sysv4.h. + * config/mips/{mipsm3.mh nm-m3.h}: Delete nm-m3.h. Make + NAT_FILE point directly at ../nm-m3.h. + * config/mips/{mipsv4.mh nm-sysv4.h}: Delete nm-sysv4.h. Make + NAT_FILE point directly at ../nm-sysv4.h. + * config/mips/nm-mips.h: Improve comment at top of file. + * config/mips/tm-mips.h (TARGET_MONITOR_PROMPT): Change + definition into a proper string. + +Wed Nov 1 20:18:08 1995 Fred Fish + + * config/i386/tm-i386.h: New file containing generic i*86 target + definitions. + (TARGET_BYTE_ORDER): Moved here from tm-i386v.h. + (IEEE_FLOAT): Moved here from tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Define default as 2. + (FUNCTION_START_OFFSET): Moved here from tm-i386v.h. + (SKIP_PROLOGUE): Moved here from tm-i386v.h. + (SAVED_PC_AFTER_CALL): Moved here from tm-i386v.h. + (INNER_THAN): Moved here from tm-i386v.h. + (BREAKPOINT): Moved here from tm-i386v.h. + (DECR_PC_AFTER_BREAK): Moved here from tm-i386v.h. + (ABOUT_TO_RETURN): Moved here from tm-i386v.h. + (REGISTER_SIZE): Moved here from tm-i386v.h. + (NUM_REGS): Moved here from tm-i386v.h. + (REGISTER_NAMES): Moved here from tm-i386v.h. + (EXTRACT_STRUCT_VALUE_ADDRESS): Moved here from tm-i386v.h. + (FP_REGNUM): Moved here from tm-i386v.h. + (SP_REGNUM): Moved here from tm-i386v.h. + (PC_REGNUM): Moved here from tm-i386v.h. + (PS_REGNUM): Moved here from tm-i386v.h. + (FP0_REGNUM): Moved here from tm-i386aix.h. + (FPC_REGNUM): Moved here from tm-sun386.h. + (REGISTER_BYTES): Moved here from tm-i386aix.h. + (REGISTER_BYTE): Moved here from tm-i386aix.h. + (REGISTER_RAW_SIZE): Moved here from tm-i386aix.h. + (MAX_REGISTER_RAW_SIZE): Moved here from tm-i386aix.h. + (REGISTER_VIRTUAL_SIZE): Moved here from tm-i386aix.h. + (MAX_REGISTER_VIRTUAL_SIZE): Moved here from tm-i386aix.h. + (EXTRACT_RETURN_VALUE): Moved here from tm-i386aix.h. + (STORE_RETURN_VALUE): Moved here from tm-i386aix.h. + (REGISTER_VIRTUAL_TYPE): Moved here from tm-i386v.h. + (STORE_STRUCT_RETURN): Moved here from tm-i386v.h. + (FRAME_CHAIN): Moved here from tm-i386v4.h. + (FRAMELESS_FUNCTION_INVOCATION): Moved here from tm-i386v4.h. + (FRAME_SAVED_PC): Moved here from tm-i386os9k.h + (FRAME_ARGS_ADDRESS): Moved here from tm-i386v.h. + (FRAME_LOCALS_ADDRESS): Moved here from tm-i386v.h. + (FRAME_NUM_ARGS): Moved here from tm-i386sun.h. + (FRAME_ARGS_SKIP): Moved here from tm-i386v.h. + (FRAME_FIND_SAVED_REGS): Moved here from tm-i386v.h. + (PUSH_DUMMY_FRAME): Moved here from tm-i386v.h. + (POP_FRAME): Moved here from tm-i386v.h. + (CALL_DUMMY, CALL_DUMMY_LENGTH, CALL_DUMMY_START_OFFSET, + CALL_DUMMY_BREAKPOINT_OFFSET, FIX_CALL_DUMMY): Moved here from + tm-i386v.h + (print_387_control_word, print_387_status_word): Declare prototypes. + (struct frame_info, struct frame_saved_regs): Forward decls for + prototypes. + (SP_ARG0): Moved here from tm-i386v.h. + + * config/i386/tm-i386v.h: + (i386/tm-i386.h): Include. + (TARGET_BYTE_ORDER): Remove. + (IEEE_FLOAT): Remove. + (START_INFERIOR_TRAPS_EXPECTED): Undef before redefine to 4. + (FUNCTION_START_OFFSET): Remove. + (SKIP_PROLOGUE): Remove. + (i386_skip_prologue): Remove prototype. + (SAVED_PC_AFTER_CALL): Remove. + (INNER_THAN): Remove. + (BREAKPOINT): Remove. + (DECR_PC_AFTER_BREAK): Remove. + (ABOUT_TO_RETURN): Remove. + (REGISTER_SIZE): Remove. + (NUM_REGS): Undef before redefine to 16 (no FP support). + (REGISTER_NAMES): Undef before redefine. + (FP_REGNUM, SP_REGNUM, PC_REGNUM, PS_REGNUM): Remove. + (REGISTER_BYTES): Undef before redefine. + (REGISTER_BYTE): Undef before redefine. + (REGISTER_RAW_SIZE): Undef before redefine. + (REGISTER_VIRTUAL_SIZE): Undef before redefine. + (MAX_REGISTER_RAW_SIZE): Undef before redefine. + (MAX_REGISTER_VIRTUAL_SIZE): Undef before redefine. + (REGISTER_VIRTUAL_TYPE): Undef before redefine. + (STORE_STRUCT_RETURN): Undef before redefine. + (EXTRACT_RETURN_VALUE): Undef before redefine. + (STORE_RETURN_VALUE): Undef before redefine. + (EXTRACT_STRUCT_VALUE_ADDRESS): Remove. + (FRAME_CHAIN): Undef before redefine. + (FRAMELESS_FUNCTION_INVOCATION): Undef before redefine. + (FRAME_SAVED_PC): Undef before redefine. + (FRAME_ARGS_ADDRESS): Remove. + (FRAME_LOCALS_ADDRESS): Remove. + (FRAME_NUM_ARGS): Undef before redefine. + (FRAME_ARGS_SKIP): Remove. + (FRAME_FIND_SAVED_REGS): Remove. + (PUSH_DUMMY_FRAME): Remove. + (POP_FRAME): Remove. + (CALL_DUMMY): Remove. + (CALL_DUMMY_LENGTH): Remove. + (CALL_DUMMY_START_OFFSET): Remove. + (CALL_DUMMY_BREAKPOINT_OFFSET): Remove + (FIX_CALL_DUMMY): Remove. + (print_387_control_word): Remove. + (print_387_status_word): Remove. + (SP_ARG0): Remove. + + * config/i386/tm-symmetry.h: + (TM_SYMMETRY_H): Enclose file in test for define & define if needed. + (START_INFERIOR_TRAPS_EXPECTED): Move to after inclusion of + tm-i386v4.h or tm-i386v.h, #undef, and #define back to 2. + (DECR_PC_AFTER_BREAK): Move to after inclusion of tm-i386v4.h + or tm-i386v.h, #undef, and #define to 0. + (MAX_REGISTER_RAW_SIZE): Remove. + (FRAME_CHAIN): Remove. + (FRAMELESS_FUNCTION_INVOCATION): Remove. + (FRAME_SAVED_PC): Remove. + (print_387_control_word, print_387_status_word): Remove prototypes. + + * config/i386/tm-ptx.h: + (TM_PTX_H): Enclose file in test for define & define if needed. + (START_INFERIOR_TRAPS_EXPECTED): Move to after inclusion of + tm-i386v4.h or tm-i386v.h, #undef, and #define back to 2. + (DECR_PC_AFTER_BREAK): Move to after inclusion of tm-i386v4.h + or tm-i386v.h, #undef, and #define to 0. + (SDB_REG_TO_REGNUM): Remove obsolete commented out define. + (print_387_control_word, print_387_status_word): Remove prototypes. + + * config/i386/tm-linux.h: + (TM_LINUX_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + + * config/i386/tm-i386v4.h: + (TM_I386V4_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + (FRAME_CHAIN): Moved to tm-i386.h. + (FRAMELESS_FUNCTION_INVOCATION): Moved to tm-i386.h. + (FRAME_SAVED_PC): Remove. + (sigtramp_saved_pc): Define as i386v4_sigtramp_saved_pc. + (FRAME_NUM_ARGS): Remove. + + * config/i386/tm-i386os9k.h: + (TM_I386OS9K_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + (NUM_REGS): Undefine before redefining. + (FRAME_CHAIN): Remove. + (FRAMELESS_FUNCTION_INVOCATION): Remove. + (FRAME_SAVED_PC): Move to tm-i386.h. + + * config/i386/tm-i386nw.h: + (TM_I386NW_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + + * config/i386/tm-i386bsd.h: + (TM_I386BSD_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + (FRAMELESS_FUNCTION_INVOCATION): Remove. + (FRAME_SAVED_PC): Remove. + + * config/i386/tm-i386aix.h: + (i386/tm-i386.h): Include instead of tm-i386v.h. + (START_INFERIOR_TRAPS_EXPECTED): Remove. + (FP_REGNUM): Remove. + (SP_REGNUM): Remove. + (PC_REGNUM): Remove. + (PS_REGNUM): Remove. + (FP0_REGNUM): Moved to tm-i386.h. + (NUM_REGS): Remove. + (REGISTER_NAMES): Remove. + (REGISTER_BYTES): Moved to tm-i386.h. + (REGISTER_BYTE): Moved to tm-i386.h. + (REGISTER_RAW_SIZE): Moved to tm-i386.h. + (MAX_REGISTER_RAW_SIZE): Moved to tm-i386.h. + (REGISTER_VIRTUAL_SIZE): Moved to tm-i386.h. + (REGISTER_VIRTUAL_TYPE): Removed. + (EXTRACT_RETURN_VALUE): Moved to tm-i386.h. + (STORE_RETURN_VALUE): Moved to tm-i386.h. + + * config/i386/tm-sun386.h: + (TM_SUN386_H): Enclose file in test for define & define if needed. + (i386/tm-i386.h): Include. + (TARGET_BYTE_ORDER): Remove. + (FUNCTION_START_OFFSET): Remove. + (SKIP_PROLOGUE): Remove. + (SAVED_PC_AFTER_CALL): Remove. + (INNER_THAN): Remove. + (BREAKPOINT): Remove. + (DECR_PC_AFTER_BREAK): Remove. + (ABOUT_TO_RETURN): Remove. + (REGISTER_SIZE): Remove. + (NUM_REGS): Undefine before defining. + (REGISTER_NAMES): Undefine before redefining. + (REGISTER_BYTES): Undefine before redefining. + (REGISTER_BYTE): Undefine before defining. + (FP_REGNUM): Undefine before defining. + (PC_REGNUM): Undefine before defining. + (FPC_REGNUM): Undefine before defining. + (REGISTER_RAW_SIZE): Undefine before defining. + (FRAME_CHAIN): Undefine before defining. + (FRAMELESS_FUNCTION_INVOCATION): Undefine before defining. + (FRAME_SAVED_PC): Undefine before defining. + (FRAME_NUM_ARGS): Moved to tm-i386.h. + (MAX_REGISTER_RAW_SIZE): Remove. + (MAX_REGISTER_VIRTUAL_SIZE): Remove. + (STORE_STRUCT_RETURN): Remove. + (EXTRACT_STRUCT_VALUE_ADDRESS): Remove. + (FRAME_ARGS_ADDRESS): Remove. + (FRAME_LOCALS_ADDRESS): Remove. + (FRAME_NUM_ARGS): Undefine before defining. + (FRAME_ARGS_SKIP): Remove. + (FRAME_FIND_SAVED_REGS): Remove. + (PUSH_DUMMY_FRAME): Remove. + (POP_FRAME): Remove. + (CALL_DUMMY, CALL_DUMMY_LENGTH, CALL_DUMMY_START_OFFSET): Remove. + (struct frame_info, struct frame_saved_regs): Remove forward decls + for prototypes. + + * config/i386/tm-i386lynx.h (i386/tm-i386.h): Include instead of + tm-i386v.h. + * config/i386/tm-i386m3.h (i386/tm-i386.h): Include instead of + tm-i386v.h. + + * i386-tdep.c (i386_extract_return_value): Make function visible + for all i386 targets, but only assume floating point values returned + in floating point registers for I386_AIX_TARGET. + + * i386v-nat.c (i386_register_u_addr): Enable code to locate + floating point regs in user struct. + +Wed Nov 1 15:32:57 1995 Fred Fish + + * breakpoint.c (breakpoint_re_set): Fix typo in comment. + * symtab.c (in_prologue): Document func_start and when it is zero + don't call SKIP_PROLOGUE (which typically leads unconditionally to + an error when we try to access a prologue at address 0). + +Tue Oct 31 13:01:15 1995 Fred Fish + + * elfread.c: Include elf-bfd.h rather than libelf.h. + +Tue Oct 31 10:42:42 1995 steve chamberlain + + * win32-nat.c (xlate_exception): Treat a stack overflow like a SEGV. + +Sun Oct 29 11:22:05 1995 Fred Fish + + * monitor.c: Include gnu-regex.h rather than system regex.h. + +Sat Oct 28 23:51:48 1995 steve chamberlain + + * defs.h: Test on name __WIN32__ rather than WIN32. + * inflow.c (new_tty): Likewise + * terminal.h: Likewise. + * utils.c (initialize_utils): Likewise. + * win32-nat.c (child_create_inferiror): Print error code when failing. + * config/i386/win32.mh (XM_CLIBS): Need -lkernel32. + +Sat Oct 28 04:52:36 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symtab.h (enum address_class): Add LOC_UNRESOLVED for + a location whose address has to be resolved via the minimal + symbol table. + * buildsym.c (finish_block), findvar.c (symbol_read_needs_frame, + read_var_value), printcmd.c (address_info), + symmisc.c (print_symbol, print_partial_symbol): Handle + LOC_UNRESOLVED. + * stabsread.c (scan_file_globals): Change unresolved LOC_STATIC + symbols to LOC_UNRESOLVED. Remove rt_common_objfile lookup + kludge, global common symbols are now handled by LOC_UNRESOLVED. + (scan_file_globals_1): Move code back to scan_file_globals, + delete. + +Fri Oct 27 09:54:07 1995 Stu Grossman (grossman@cygnus.com) + + * breakpoint.c (breakpoint_re_set): #ifdef GET_LONGJMP_TARGET + around calls to create_longjmp_breakpoint. Why install the + breakpoints if we can't find the longjmp target? + * infrun.c (wait_for_inferior): Cleanup comments near call test. + * remote-mips.c: Fixed a bunch of prototypes to avoid char/int + complaint from picky compilers. Add comment to mips_expect. + Replace all instances of sr_get_debug with remote_debug. + * (mips_readchar): Don't jam init string to monitor. + mips_initialize() handles that. + * (mips_receive_header): Print better message when we get too + much garbage. + * (mips_request): Allow caller to pass in buff to allow them to + analyze the returned message. + * (mips_initialize): Re-do initialization to try sending a BREAK, + a ^C, and then a download escape sequence. Cleanup protocol + startup. Eliminate sleeps. Clear breakpoints (if using monitor + breakpoints). Re-init frame. + * (mips_detach): Close down target. + * (mips_wait): Handle return status with registers, or breakpoint stuff. + * (mips_kill): Add ^C handling. + * (mips_insert_breakpoint mips_remove_breakpoint): Call new + breakpoint stuff if enabled. + * (calculate_mask remote_mips_set_watchpoint + remote_mips_remove_watchpoint remote_mips_stopped_by_watchpoint): + Hardware watchpoint/breakpoint stuff. + * (common_breakpoint): Common code for new monitor breakpoint commands. + * (mips_load): Don't use `prompt'. It's a global variable. + * top.c (dont_repeat_command): New command for use in + user-defined commands to suppress auto-repeat (by hittin return key). + * valops.c: Add start of auto function-call abandonment capability. + + +Thu Oct 26 22:02:27 1995 Stan Shebs + + * mpw-config.in: Add support for PowerMac host, add beginnings + of native support. + * mpw-make.sed: Disable subdir recursion, edit out useless rule. + * mac-xdep.c (Values.h): Don't include. + (GestaltEqu.h): Include Gestalt.h instead. + (do_mouse_down): Comment out control tracking, needs to be + updated to use UPP before will work on PowerMac. + * config/xm-mpw.h: New file, all-Mac host support. + * config/m68k/xm-mpw.h: Move most definitions into generic Mac + support. + * config/powerpc/xm-mpw.h: New file, PowerMac host support. + +Thu Oct 26 15:21:32 1995 Brendan Kehoe + + * regex.h: Renamed to gnu-regex.h. + * regex.c: Renamed to gnu-regex.c. + * Makefile.in (POSSLIBS): Refer to gnu-regex.h and gnu-regex.c. + (REGEX, REGEX1): Change to gnu-regex.o instead of regex.o. + (regex.o): Renamed to gnu-regex.o; refer to gnu-regex.c. + (irix5-nat.o, osfsolib.o, gnu-regex.o, solib.o, source.o, symtab.o): + Likewise. + * irix5-nat.c, osfsolib.c, gnu-regex.c, solib.c, source.c, symtab.c): + Include "gnu-regex.h" instead of "regex.h". + * alpha-tdep.c (in_prologue): Rename to alpha_in_prologue, to + avoid conflicts with symtab.h. + +Tue Oct 24 18:30:18 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * config/pa/hppahpux.mh: Remove hardcoding of X locations. + * Makefile.in: Use X11_CFLAGS, X11_LDFLAGS and X11_LIBS. + * configure.in: Link X statically on Solaris, SunOS and HPUX. + +Tue Oct 24 12:26:14 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c (monitor_expect_regexp): Same as monitor_expect, but + with the obvious extension. + (monitor_read_memory_single): Use regexp for getmem.resp_delim + because of parsing ambiguities caused by certain monitors. + (monitor_read_memory): Use new regexp stuff to parse + getmem.resp_delim. + * monitor.h (struct memrw_cmd->resp_delim): Document this as a + regexp. + * sh3-rom.c: Finish off table. Use new regexp capability for + getmem commands. + + * infrun.c (wait_for_inferior): Disable questionable code near + the step range test. Replace call detection test with much + simpler (and more efficient) test that doesn't require prologue + examination (as often). + * symtab.c symtab.h (in_prologue): New function that indicates + whether or not we are in a function prologue. This uses the + symbol table, and then falls back to prologue examination if that + fails. It's much more efficient for remote debugging because it + avoids examining memory, which is very slow. This is used in + wait_for_inferior to determine if we've made a function call that + needs to be skipped over (for next/nexti). + * mips-tdep.c (after_prologue): New function, returns the PC + after the prologue. Uses PDRs and the symbol table. + (mips_find_saved_regs): Use in_prologue() to avoid costly + prologue examination if possible. + (mips_skip_prologue): Use after_prologue() if possible to avoid + costly prologue examination. + +Mon Oct 23 16:03:33 1995 James G. Smith + + * configure.in (configdirs): Added support for the VR4300 default + builds (mips64*vr4300*el-*-elf*, mips64*vr4300*-*-elf*). + + * configure: Regenerated. + + * remote-mips.c (mips_load): Updated the prompt spotting code to + make use of the TARGET_MONITOR_PROMPT manifest. + +Sat Oct 21 06:11:49 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-tdep.c, mips-tdep.c (init_extra_frame_info): + Do not set saved registers from heuristics for a sigtramp frame. + + * dwarfread.c (enum_type): Determine signedness of enum type + from enumerators. + + * mips-tdep.c: Include gdb_string.h, gcc -Wall lint. + + * rs6000-nat.c (xcoff_relocate_core): Fix typo. + + * valops.c (value_repeat): Fix length of memory transfer to + match recent allocate_repeat_value change. + +Thu Oct 19 19:04:35 1995 Per Bothner + + * gdbtypes.c (get_discrete_bounds): Fix typo. + +Thu Oct 19 12:15:37 1995 Stan Shebs + + * defs.h (SEEK_SET, SEEK_CUR): Add default definitions. + * dbxread.c, mdebugread.c, os9kread.c (SEEK_SET, SEEK_CUR): + Remove default definitions. + + * Makefile.in (CC-LD): Rename to CC_LD, so MPW xform works. + (MMALLOC_SRC): Define. + (MMALLOC_CFLAGS): Use. + (ser-mac.o): Add rule. + * dwarfread.c, somread.c, ultra3-nat.c, xcoffread.c: Replace L_SET + with SEEK_SET in all calls to bfd_seek. + * scm-tags.h (scm_tags): Remove excess comma. + + * mpw-config.in: Adapt to work with autoconf'ed configury; + build config.h, add empty definitions to mk.tmp. + (powerpc-apple-macos): Make it work. + * mpw-make.sed: New file, sed commands to translate Unix makefile + into MPW syntax. + * mpw-make.in: Remove. + * mac-gdb.r: New file, was macgdb.r, renamed for consistency + with other tools, now includes cfrg resource. + * macgdb.r: Remove. + * config/m68k/xm-mpw.h: Remove most of contents, replace with + include of include/mpw/mpw.h. + +Tue Oct 17 10:38:53 1995 Jeffrey A Law (law@cygnus.com) + + * hppa-tdep.c (frame_chain): Fix more obscure problems caused + by system calls that core dump processes without saving all + the register state. + + * config/pa/hppahpux.mt (XDEPFILES): Remove bogus definition. + * config/pa/hppapro.mt (XDEPFILES): Likewise. + +Tue Oct 17 08:04:26 1995 Fred Fish + + * NEWS: Fix typo. + +Mon Oct 16 18:24:03 1995 Jim Wilson + + * config/sh/tm-sh.h (REGISTER_VIRTUAL_TYPE): Return builtin_type_float + for FP registers. + (REGISTER_NAMES): Add FP register names. Remove ticks, stalls, cycles, + insts, plr, and tlr. + (NUM_REGS, NUM_REALREGS): Increase from 23 to 41. + (FPUL_REGNUM, FP0_REGNUM): New macros. + +Mon Oct 16 11:27:06 1995 Stu Grossman (grossman@cygnus.com) + + * remote-mips.c: Add support for speedy (about 10x faster) + downloads. + + * remote-array.c: Move baud_rate initialization from + _initialize_array to array_open. It was forcing the baud rate of + all targets to be 4800 baud! Seems like I've fixed this before... + * config/mips/idt.mt (TDEPFILES): Remove remote-array.o. This + has *nothing* to do with IDT!!! + + + * Makefile.in sh3-rom.c config/sh/sh.mt config/sh/tm-sh.h: Add + sh3 monitor support. + * monitor.c: Cleanup regexp compilation stuff to make it easier + to use several regexps. + * monitor.h: Get rid of struct rom_cmd_data. It's no longer used. + * config/m68k/tm-monitor.h: Don't redefine NUM_REGS here. It just + causes GDB to crash. + + * sparcl-tdep.c: Cleanup serial error handling. + +Sun Oct 15 16:19:27 1995 Stan Shebs + + * rs6000-tdep.c: Don't include a.out.h, improve some formatting. + +Fri Oct 13 15:27:49 1995 Stu Grossman (grossman@cygnus.com) + + * dcache.c: Change default value of remotecache to off. It just + screws up too many targets. + * sparcl-stub.c: Add prototypes to many forward decls. + * Create private copies of strlen, strcpy, and memcpy to prevent + chaos when user steps into them. + * (trap_low handle_exception): Clean up DSU support code + (hardware breakpoints). Move lots of stuff from asm-land to + C-land (make it much easier to #ifdef if necessary). Also, use + trap 255 to get into break mode instead of doing a DSU register + write, which may trash the register. + * (putpacket): Don't check return value of putDebugChar. It + returns void... + +Fri Oct 13 14:16:17 1995 steve chamberlain + + * remote-sim.h: Always include callback.h. + (sim_set_callbacks): New declaration. + +Fri Oct 13 10:57:40 1995 Jeffrey A Law (law@cygnus.com) + + * somsolib.c (som_solib_add): Just give a warning if a file + mentioned in the dld_list can't be found. + * config/pa/tm-hppah.h (FRAME_SAVED_PC_IN_SIGTRAMP): Dig out + the PC from the PC queues rather than %r31. + +Thu Oct 12 13:36:15 1995 Jeffrey A Law (law@cygnus.com) + + * corelow.c (core_open): Don't update the to_sections and + to_sections_end fields in core_ops here. It's too late. + * irix5-nat.c (solib_add): Update the to_sections and + to_sections_end fields in core_ops here if needed. + * osfsolib.c (solib_add): Likewise. + * rs6000-nat.c (xcoff_relocate_core): Likewise. + * solib.c (solib_add): Likewise. + * somsolib.c (solib_add): Likewise. + +Wed Oct 11 17:25:59 1995 Fred Fish + + * Makefile.in (VERSION): Bump version to 4.15.1 + +Tue Oct 10 15:26:39 1995 Fred Fish + + * Makefile.in (VERSION): Version 4.15 released. + * README: Updated for version 4.15. + * NEWS: Updated for 4.15 release. + +Tue Oct 10 13:18:50 1995 Fred Fish + + * configure.in: Add AC_PROG_YACC + * configure: Regenerate + * Makefile.in (BISON): Remove macro definition. + (YACC): Set from autoconfig. + (FLAGS_TO_PASS): Remove BISON. + (TARGET_FLAGS_TO_PASS): Remove BISON. + +Tue Oct 10 12:25:11 1995 steve chamberlain + + * win32-nat.c (child_create_inferior): Pass argv correctly. + * Makefile.in (win32-nat.o): Add dependencies. + +Mon Oct 9 14:36:29 1995 steve chamberlain + + * NEWS: Add information about win32 and arm code. + * win32-nat.c: Renamed from win32.c. + * config/i386/win32.mh: Renamed from config/i386/i386win32.mh. + * config/i386/win32.mt: Renamed from config/i386/i386win32.mt. + * config/i386/tm-win32.h: Renamed from config/i386/tm-i386win32.h. + * config/i386/xm-win32.h: Renamed from config/i386/xm-i386win32.h. + * configure.in (i[345]86-*-win32): Updated to cope with filename + changes. + * configure: Regenerated. + +Sun Oct 8 18:01:04 1995 Per Bothner + + * ch-exp.y (yylex): Also look for '$' following '$'. + +Sat Oct 7 22:52:42 1995 Michael Meissner + + * ch-exp.y (yylex): Fix typo. + +Fri Oct 6 11:56:49 1995 Jim Wilson + + * remote-sim.c (gdbsim_open): Put callback initializations here. + (_initalize_remote_sim): Not here. + +Fri Oct 6 17:08:49 1995 Stan Shebs + + * top.c (execute_control_command): Use 0/1 instead of BFD's + true/false. + +Fri Oct 6 14:43:19 1995 Stu Grossman (grossman@cygnus.com) + + * sparcl-stub.c: Include sparclite.h to get access to register + fondling macros. + * (trap_low): Save and restore FP regs if necessary. Also, clean + up save and restore of debug unit regs. + * (hard_trap_info): Add more architecturally defined traps. + * (set_debug_traps): Only set FP disabled trap if FP is disabled. + * (get_in_break_mode): Clean up. Get rid of calls to + set_hw_breakpoint_trap(). Also, use write_asi macro. + * (handle_exception): Clean up `g' and `G' commands. Add `P' + command. + * (hw_breakpoint): Why was this here!? It's gone now... + +Fri Oct 6 11:56:49 1995 Jim Wilson + + * callback.c (fdbad): Fix typo in comment. + (os_close, os_isatty, os_lseek, os_read, os_write): Use if + statements rather than || to get correct return value. + (os_write_stdout): Pass missing first argument to os_write. + * remote-sim.c: Include callback.h. + (_initialize_remote_sim): Call sim_set_callbacks and then + initialize the callbacks. + +Thu Oct 5 17:28:09 1995 Per Bothner + + * values.c (allocate_repeat_value): Allocate an array type, and + a value of that type; use that instead of setting VALUE_REPEATED. + * value.h (struct value): Remove fields repetitions and repeated. + (VALUE_REPEATED, VALUE_REPETITIONS): Removed, no longer used. + * c-valprint.c, ch-valprint.c, eval.c, printcmd.c, valops.c, + value.h, values.c: Simplify, since now VALUE_REPEATED is never + used. + * valprint.c (value_print_array_elemen): Removed never-used + function. + +Thu Oct 5 15:14:36 1995 Per Bothner + + * parse.c (write_dollar_variable): New function. + + * c-exp.y (yylex): Replace code for recognizing '$' + pseudo-variables with a call to write_dollar_variable. + Simplify grammar correspondingly. + * f-exp.y: Likewise. + * m2-exp.y: Likewise. + * ch-exp.y: Likewise. (Remove function match_dollar_tokens.) + * scm-exp.c (scm_lreadr): Call write_dollar_variable to handle '$'. + +Thu Oct 5 13:27:30 1995 steve chamberlain + + * win32.c: New file; support for debugging on windows NT. + * configure.in: (i[345]86-*-win32): New target. + * configure: Regnerated. + * eval.c (evaluate_subexp_standard): Remove unused name. + * serial.c (gdb_string.h): Include. + * source.c (value.h): Include. + * config/i386/i386win32.mh (XDEPFILES): Add win32.o + * config/i386/i386win32.mt: New. + * config/i386/tm-i386win32.h: New. + +Wed Oct 4 18:41:34 1995 Per Bothner + + * expression.h (enum exp_code): Added OP_NAME. + * expprint.c (print_subexp): Add OP_NAME support. + * parse.c (length_of_subexp, prefixify_subexp): Likewise. + * scm-lang.c (scm_unpack, in_eval_c, scm_lookup_name): new function. + * scm-lang.h: Declare builtin_type_scm; other minor tweaks. + * values.c (unpack_long): If type is SCM, call scm_unpack. + * scm-valprint.c (scm_val_print): Use extract_signed_integer, + instead unpack_long + * scm-lang.c: More Scheme expression parsing from here ... + * scm-exp.c: ... to here. New file. + Also, provide for gdb to evaluate simple constants and names.. + * Makefile.in: Note new scm-exp.{c,o}. + +Wed Oct 4 17:23:03 1995 Per Bothner + + * gdbtypes.c (get_discrete_bounds): New function. + (force_to_range_type): Use get_discrete_bounds. + * gdbtypes.h (get_discrete_bounds): Add declaration. + * valarith.c (value_bit_index): Generalize to use get_discrete_bounds. + * ch-valprint.c (chill_val_print): Make (power)sets and bitstring + support use get_discrete_bounds and generally be more robust. + +Tue Oct 3 16:54:56 1995 Stan Shebs + + * remote-nrom.c (nrom_ops): Add value for to_thread_alive, + add comments naming slots. + +Mon Oct 2 21:45:44 1995 Jeff Law (law@hurl) + + * top.c (build_command_line): Demand arguments for if/while + commands. + +Mon Oct 2 13:08:01 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * Makefile.in (X11_CFLAGS): Set only to @X_INCDIR@. + +Sat Sep 30 16:13:36 1995 Per Bothner + + * scm-lang.c: Moved Scheme value printing code to ... + * scm-valprint.c: ... this new file. + Also major improvements in support for printing SCM values. + * scm-lang.h: New file. + * scm-tags.h: New file. + * Makefile.in: Note new scm-valprint.{c,o}. + +Sat Sep 30 09:35:02 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in: X_INCDIR and X_LIBDIR added. + * Makefile.in: @X_INCDIR@ and @X_LIBDIR@ added. + * configure: Regnerated. + +Fri Sep 29 02:10:05 1995 steve chamberlain + + * config/arm/tm-arm.h (FRAME_CHAIN, FRAME_CHAIN_VALID): + Any pc > LOWESTPC is ok. + + * remote-rdp.c (rdp_init): Take out variable baud rate stuff. + (remote_rdp_detatch): Delete. + * breakpoint.c (ctype.h): Don't include twice. + + * Makefile.in (remote-rdp.o): Doesn't need remote-rdp.h + * callback.c (os_printf_filtered): fix protos. + * defs.h (puts_filtered, puts_unfiltered + [v|f|]printf_[un]filtered): Make format arg const. + * remote-rdp.c (rdp_init): Attept to sync at different + baudrates. + * utils.c (puts_filtered, puts_unfiltered + [v|f|]printf_[un]filtered): Define prototypes with + const in the right place. + +Thu Sep 28 17:43:39 1995 Per Bothner + + * defs.h (enum language): Add language_scm. + * expression.h (enum exp_code): Added OP_EXPRSTRING. + * scm-lang.c: Preliminary support for Guile /SCM dialect of Scheme. + * expprint.c (print_subexp): Add OP_EXPRSTRING support. + * parse.c (length_of_subexp, prefixify_subexp): Likewise. + * valops.c (find_function_in_inferior): New function. + (value_allocate_space_in_inferior): New function. + (allocate_space_in_inferior): Redefine using previous function. + * Makefile.in (SFILES): Add scm-lang.c. + (COMMON_OBS): Add scm-lang.o + +Thu Sep 28 14:32:11 1995 steve chamberlain + + * callback.[ch]: New files. + * remote-rdp.c: Support for the ARM RDP monitor. + * Makefile: Update. + * arm-tdep.c (arm_othernames): New. + (_initialize_arm_tdep): install 'othernames' command. + (arm_nullified_insn, shifted_reg_val, arm_get_next_pc): New. + * configure.in: Check for termios.h, termio.h and sgtty.h. + (i[345]86-*-win32*): New host. + * configure: Regenerated. + * inflow.c: Clean up inclusions. + * main.c (main): Check for WINGDB, not WIN32. + * printcmd.c (do_examine): Put QUIT test in loop. + * remote-hms.c (e7000_load): Delete. + (hms_ops): Point to generic_load instead. + * remote-hms.c (hms_ops): Point to generic_load. + * remote-sim.c (sim_callback_write_stdout): Becomes + gdbsim_write_stdout. + (gdbsim_load): Call generic_load. + * remote-utils.c (gr_load_image): Delete. + * ser-unix.c (terminal.h): Include instead of havig + own #if tree. + (hardwire_flush_input): Reset input buffer too. + * source.c (openp): If WIN32 then open file in binary mode. + * terminal.h: Configure IO mechanism using autoconf defines if + available and not overriden. + * utils.c (quit, pollquit, notice_quit): WIN32 check becomes + WINGDB check. + + * config/arm/arm.mt (TDEPFILES): Add remote-rdp.o. + * config/arm/tm-arm.h (TARGET_BYTE_ORDER): becomes + TARGET_BYTE_ORDER_SELECTABLE. + (ADDR_BITS_REMOVE): New. + (ORIGINAL_REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): New. + (INST_xx): New. + (FRAME_FIND_SAVED_REGS): Pass the right argument. + (arm_get_next_pc): Declare. + +Wed Sep 27 10:14:36 1995 Per Bothner + + * valops.c (search_struct_field): Also allow "else" as a variant + name. + * eval.c (evaluate_struct_tuple): New function. Used to evaluate + structure tuples. Now also handles Chill variant records. + (get_label): New function, used by evaluate_struct_tuple. + (evaluate_subexp_standard case OP_ARRAY): Use evaluate_struct_tuple. + (evaluate_labeled_field_init): Removed. + + * valops.c (search_struct_field): Generalize to work with Chill + variant records. + +Sat Sep 23 01:22:23 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_partial_symbols): Reset includes_used + and dependencies_used after finishing the partial symbol table. + + * rs6000-tdep.c (push_dummy_frame): Handle lr_offset of zero + correctly. + + * rs6000-nat.c (xcoff_relocate_core): Don't relocate data + addresses for the main objfile if DONT_RELOCATE_SYMFILE_OBJFILE + is defined. + * xcoffread.c: gcc -Wall lint. Remove traceback table reading + code. The existing code tried to add parameter information for + functions compiled without -g, which cannot be done properly + for optimized code and produced misleading parameter displays. + (ef_complaint, eb_complaint): Make a local static copy to avoid + dependency on coffread.c. + (read_xcoff_symtab, process_xcoff_symbol, scan_xcoff_symtab): + Enter C_EXT/C_HIDEXT symbols into the minimal symbol table only. + (read_xcoff_symtab): Ignore C_STAT section auxiliary entry + symbols. Complain about unmatched .ef and .eb symbols instead of + segfaulting. + (process_xcoff_symbol): Determine value of C_GSYM symbols via + the global_sym_chain mechanism in stabsread.c. + (xcoff_new_init): Call stabsread_new_init and buildsym_new_init. + (init_string_tab): Initialize length field bytes in the strtbl. + (scan_xcoff_symtab): Skip symbols that start with `$' or `.$'. + Set first_fun_line_offset for symbols with two auxents only. + +Wed Sep 20 21:06:35 1995 Jeff Law (law@snake.cs.utah.edu) + + * op50-rom.c (op50n_cmds): Send ".\r" after the interrupt + character. + +Wed Sep 20 13:12:56 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New target, synonym for + realclean. Add GNU standard maintainer-clean echos. + * gdbserver/Makefile.in (maintainer-clean): New target, synonym + for realclean. + * nlm/Makefile.in (maintainer-clean): Likewise. + +Wed Sep 20 08:16:03 1995 steve chamberlain + + * defs.h (xmalloc, xrealloc): Delete, they're declared in libiberty.h. + (GETENV_PROVIDED, FCLOSE_PROVIDED): New. + * doc/gdbint.texinfo (GETENV_PROVIDED, FCLOSE_PROVIDED): Document. + * remote-sim.[ch] (sim_callback_write_stdout): New. + +Tue Sep 19 15:28:58 1995 Per Bothner + + * gdbtypes.c (create_set_type): Set TYPE_LENGTH in bytes, not bits. + * valops.c (value_bitstring): TYPE_LENGTH is bytes, not bits. + + * gdbtypes.c (force_to_range_type): Calculate upper limit of + TYPE_CODE_CHAR depending on TYPE_LENGTH (instead of just using 255). + +Mon Sep 18 01:43:42 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (auto_solib_add_at_startup): Delete definition. No + longer needed. + +Sat Sep 16 13:23:36 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/mips/tm-mips.h (UNUSED_REGNUM): Define. + * mipsv4-nat.c (supply_gregset): Fill UNUSED_REGNUM register + with zero. + +Thu Sep 14 17:35:24 1995 Stu Grossman (grossman@cygnus.com) + + * remote-sim.c (gdbsim_create_inferior): Back out change that + broke all simulator configurations except the rs6000. + +Thu Sep 14 14:44:59 1995 Jeffrey A. Law + + * monitor.c (monitor_expect): Discard NULL characters. + +Thu Sep 14 14:12:30 1995 Kung Hsu + + * infcmd.c: Add extern declaration for auto_solib_add_at_startup. + +Wed Sep 13 13:33:58 1995 Kung Hsu + + * symfile.c: Move global variable auto_solib_add_at_startup from + solib.c to symfile.c. + * solib.c: ditto. + * symfile.h: Add extern declaration of the above mentioned variable. + * infcmd.c: Take out extern declaration, since it's in symfile.h. + +Thu Sep 14 12:39:35 1995 Stu Grossman (grossman@cygnus.com) + + * coffread.c (coff_symtab_read): Complain about unmatched .ef and + .eb symbols instead of segfaulting. + +Wed Sep 13 13:33:58 1995 Kung Hsu + + * stabsread.c (read_one_struct_field): Use subfile language instead of + global language. Improve efficiency. + +Wed Sep 13 08:45:02 1995 Jeff Law (law@fast.cs.utah.edu) + + * somsolib.c (auto_solib_add_at_startup): Define new global variable. + (som_solib_create_inferior_hook): Don't add libraries if + auto_solib_add_at_startup is zero. + (_initialize_som_solib): Add command to toggle + auto_solib_add_at_startup. + +Tue Sep 12 19:37:24 1995 Jeff Law (law@snake.cs.utah.edu) + + * monitor.c (monitor_make_srec): Fix thinkos in computation + of addr_size. + +Tue Sep 12 15:46:18 1995 Kung Hsu + + * stabsread.c (read_one_struct_field): Add a patch to handle cfront + generated stabs that each field is in full mangled name. + + * stabsread.c: To include language.h and expression.h for the reason + above. + + * infcmd.c (attach_command): Add solibs only when + auto_solib_add_at_startup is set. + +Mon Sep 11 17:22:35 1995 Fred Fish + + * NEWS: Add information about remote target caching. + +Sun Sep 10 15:36:21 1995 Fred Fish + + * defs.h: Only include mmalloc.h if NO_MMALLOC is not + defined. + +Sun Sep 10 10:24:48 1995 Michael Tiemann + + * tm-ppc-eabi.h (PC_IN_CALL_DUMMY): Redefine this to work with the + simulator. FIXME. + + * rs6000-tdep.c (push_dummy_frame): Calculate the correct link + register offset from the current frame (don't assume it is always 8). + (push_dummy_frame): Add comment about having only 4096 bytes of + stack space in the simulator (by default). + + * remote-sim.c (gdbsim_create_inferior): Call + `add_text_to_loadinfo' so that gdb can find TOC entries when + calling functions in the inferior. + +Sun Sep 10 09:00:28 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-tdep.c (fill_fpregset): Fix incorrect FP_MAX_REGNUM + substitution. + (supply_fpregset): Use FP_MAX_REGNUM. + +Sat Sep 9 08:21:52 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * stabsread.c (read_enum_type): Exit loop for putting pending + enum symbols into the enum type correctly if we had no pending + symbols on entry to read_enum_type. + +Fri Sep 8 12:57:41 1995 Kung Hsu + + * inferior.h: Add extern declaration of inferior_environ. + * solib.c (solib_map_sections): To get inferior's env instead of + gdb's for LD_LIBRARY_PATH, same for PATH. + + * solib.c (solib_map_sections): Copy full path name into so_list + structure so that symbol_file_add can find it. + +Tue Sep 5 17:47:53 1995 Doug Evans + + * config/sparc/tm-sp64.h (REGISTER_RAW_SIZE): Lower 32 fp regs + have size 4. + (REGISTER_VIRTUAL_SIZE): Likewise. + (REGISTER_VIRTUAL_TYPE): Lower 32 fp regs have type float. + Upper 32 fp regs have type double. + * sparc-tdep.c (NUM_SPARC_FPREGS): Replace with + (FP_REGISTER_BYTES): this, and update all uses. + (FP_MAX_REGNUM): Define if not already. + (get_saved_register): Handle new sparc64 fp regs. + (sparc_frame_find_saved_regs): Likewise. + (sparc_print_register_hook): Only print fp regs < 32 as doubles. + Add code to handle long doubles when gdb does. + (_initialize_sparc_tdep): Use print_insn_sparc64 if sparc64. + +Sat Sep 2 06:41:26 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * configure.in: Explicitly `exit 0' for broken shells. + * configure: Rebuilt. + + * symtab.c (list_symbols): Add missing blank after + `' output. + + * valops.c (value_assign): Handle truncation when assigning + to bitfields. Use value_copy to construct the return value + from toval. + * values.c (value_copy): Copy VALUE_FRAME and VALUE_OPTIMIZED_OUT. + +Fri Sep 1 08:25:50 1995 James G. Smith + + * configure (mips64*vr4300*-*-elf): Support added. + * remote-mips.c (mips_readchar): Change to allow build-time prompt + string. + * config/mips/tm-mips.h: Added TARGET_MONITOR_PROMPT. + * config/mips/{vr4300.mt, vr4300el.mt, tm-vr4300.h, + tm-vr4300el.h}: Added. + +Thu Aug 31 12:48:04 1995 Jim Wilson + + * config/sh/sh.mt (SIM): Add -lm. + +Wed Aug 30 18:10:57 1995 Kung Hsu + + * rmote-nindy.c (non_dle, nidy_resume, nindy_wait): Changes to + conform to GNU coding standards. + + * solib.c (match_main): Modify to follow GNU coding conventions. + +Mon Aug 28 17:07:26 1995 Kung Hsu + + * remote.c (remote_wait): Revert 19 July my change which should be + customer specific. + +Sat Aug 26 00:26:11 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_symbol): Handle sh.value of zero for enums. + Determine signedness of enum type from enumerators. + (parse_type): Handle btIndirect types, handle fBitfield for + some non-member types. + (upgrade_type): Use TYPE_FLAG_TARGET_STUB for arrays with + unknown length. + (cross_ref): Handle stIndirect forward reference to btTypedef. + + * stabsread.c (read_enum_type): Determine signedness of enum + type from enumerators. + + * top.c (execute_command): Remove trailing whitespace from + command arguments, except for `set' and `complete' commands. + (validate_comname): Allow underscores in user defined command + names. + + * values.c (modify_field): Change `Value does not fit in %d bits' + error to a warning. Exclude sign extension bits of negative field + values from fit check. + +Fri Aug 25 11:31:29 1995 Michael Meissner + + * configure.in (powerpc*-*-eabisim*): Only link in the simulator + if the target is powerpc{,le}-*-eabisim*, since the simulator + needs GCC to build. + * config/powerpc/ppc{,le}-sim.mt: Cloned from ppc{,le}-eabi.mt. + * config/powerpc/ppc{,le}-eabi.mt: Remove simulator support. + * config/powerpc/tm-ppc{,le}-sim.mt: Include tm-ppc{,le}-sim.h. + +Wed Aug 23 16:55:35 1995 Michael Meissner + + * config/powerpc/ppc{,le}-eabi.mt (SIM_OBJS, SIM): Link in the + PowerPC simulator. + +Tue Aug 22 02:00:47 1995 Jeff Law (law@snake.cs.utah.edu) + + * tm-hppa.h (EXTRACT_RETURN_VALUE): Fix for FP values. + + * tm-hppa.h (STORE_RETURN_VALUE): Fix to work with -msoft-float + calling conventions too. Use the TYPE of the return value, not + its length to determine if it should also be copied into the + floating point registers. + + * tm-hppa.h (PROLOGUE_FIRSTLINE_OVERLAP): Delete. Causes more + problems than it fixes. + * hppa-tdep.c (skip_prologue): If we exit the main loop without + finding all the register saves, retry again without looking for + the registers we could not find the first time. + +Mon Aug 21 23:39:56 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (frame_chain_valid): Handle systems where "$START$" + calls "main" directly. + (skip_prologue): Always assume arguments were saved into the stack + since GCC will do so without setting the magic Args_Saved bit in + the unwind descriptor. + +Mon Aug 21 11:49:17 1995 Kung Hsu + + * remote-udi.c (udi_wait): Mask off high bits of stop reason. + * remote-udi.c (fetch_register): For unfetchable regs, pretend it's + done. Fix a bug. + +Mon Aug 21 00:45:17 1995 Jeff Law (law@snake.cs.utah.edu) + + * Makefile.in (install): Remove "brokensed" hack, unnecessary now + that we're using autoconf. + (uninstall): Likewise. + + +Sat Aug 19 01:19:34 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdbtypes.c (recursive_dump_type): Add dont_print_type_obstack + to inhibit infinite recursion when printing aggregate types. + +Fri Aug 18 17:48:55 1995 steve chamberlain + + * dcache.c (dcache_write_line): Write dirty lines right. + +Fri Aug 18 06:26:56 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-tdep.c (isbranch): Fix typo which caused wrong + target addresses for annulled branches. + +Wed Aug 16 21:54:39 1995 Jeff Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (PROLOGUE_FIRSTLINE_OVERLAP): Define. + +Tue Aug 15 07:51:21 1995 steve chamberlain + + * remote.c (remote_write_bytes): Chop up large transfers. + +Mon Aug 14 17:56:36 1995 Stan Shebs + + * gcc.patch: Remove, relevant only to long-ago versions of GCC. + +Mon Aug 14 13:43:01 1995 Kung Hsu + + * config/sparc/tm-sparclite.h: Define FRAME_CHAIN_VALID_ALTERNATE. + * blockframe.c (inside_main_func): If main func addr range not set, + try to set it now. + +Sat Aug 12 15:34:54 1995 Jeffrey A. Law + + * config/powerpc/xm-aix.h (FIVE_ARG_PTRACE): Define. + * config/rs6000/xm-rs6000.h (FIVE_ARG_PTRACE): Likewise. + + * configure.in: Recognize aix4 specially as some aspects + of aix4 need different handling than aix3. + * configure: Updated. + * config/powerpc/{aix4.mh,aix4.mt,tm-ppc-aix4.h}: New files + specific to aix4 support on the power pc. + * config/powerpc/tm-ppc-aix.h (DONT_RELOCATE_SYMFILE_OBJFILE): Do + not defined. The aix4 specific target files will do that. + * config/rs6000/{aix4,mh,aix4,mt,tm-rs6000-aix4.h}: New files + specific to aix4 support on the rs6000. + + * config/rs6000/tm-rs6000.h (CONVERT_FROM_FUNC_PTR_ADDR): Don't + do the conversion if the pointer is not a magic aix function + pointer. + * rs6000-tdep.c: Include objfiles.h and symtab.h. + (is_magic_function_pointer): New function. + + * rs6000-tdep.c (skip_prologue): Refine check for frameless + functions. Handle b .+4 emitted by aix4 compilers. Only + allow one load of a minimal toc pointer. Handle aix4 compiler's + code for alloca. + + * rs6000-tdep.c (find_toc_address): Report an error if no toc was + found rather than possibly core dumping. + + * partial-stab.h: Handle extra field generated by the aix4 compiler + for enumerations. + * stabsread.c (read_enum_type): Likewise. + +Sat Aug 12 03:18:04 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * rs6000-tdep.c (extract_return_value): Fix returning of values + whose length is less than the register size for big endian targets. + +Fri Aug 11 13:04:32 1995 Kung Hsu + + * symtab.c (list_symbols): if break command set breakpoint on + matched symbol. + +Wed Aug 9 18:59:05 1995 Fred Fish + + * defs.h (strchr, strrchr, strstr, strtok, strerror): Enclose in + #ifndefs to protect against previous definitions as macros. + +Wed Aug 9 14:51:36 1995 Kung Hsu + + * xcoffread.c (xcoff_symfile_offset): Revert an unwanted change + that got in accidentally with Aug 1 change. + +Sat Aug 5 09:07:28 1995 steve chamberlain + + * remote-hms.c (hms_cmds): Get reg term right. + * monitor.c (monitor_fetch_register): If we see + a non-hex digit, just stop reading. + * remote.c (remote_wait): Change way $O is handled. + +Wed Aug 9 11:42:36 1995 Jeffrey A. Law + + * configure.in (powerpc-*-aix*): Recognize as a new gdb host + and target. + (powerpc-*-eabi*): Don't set configdirs. + (powerpcle-*-eabi*): Likewise. + * configure: Updated. + * rs6000-nat.c (vmap_ldinfo): Don't relocate data addresses + for the main objfile if DONT_RELOCATE_SYMFILE_OBJFILE is + defined. + * config/powerpc/{aix.mh,aix.mh}: Host and target makefile fragments + for powerpc running aix4. + * config/powerpc/{nm-aix.h, tm-ppc-aix.h, xm-aix.h}: Native, target + and host include files for powerpc running aix4. + +Wed Aug 9 08:11:45 1995 Stan Shebs + + * top.c (target_output_hook): Really make it match defs.h (char * + is not the same as unsigned char *). + +Tue Aug 8 15:13:05 1995 J.T. Conklin + + * Makefile.in (CXX_FOR_TARGET): Don't use ${rootme}/../gcc/xgcc + unless it is present. + +Tue Aug 8 10:50:15 1995 Jeffrey A. Law + + * top.c (target_output_hook): Make declaration match the one + in defs.h. + + * symfile.c (add_psymbol_to_list): Initialize SYMBOL_SECTION. + (add_psymbol_addr_to_list): Likewise. + * symfile.h (ADD_PSYMBOL_VT_TO_LIST): Likewise. + +Mon Aug 7 15:34:29 1995 steve chamberlain + + * top.c (target_output_hook): New definition. + * stack.c (gdb_string.h): Include after defs.h + * defs.h (target_output_hook): New declaration. + * source.c (mod_path): Fix Win32 \ handling. + +Sun Aug 6 22:14:25 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (frame_saved_pc): Don't try to dig a return pointer + out of a long branch stub. + +Fri Aug 4 13:37:31 1995 Jeffrey A. Law + + * xcoffread.c (process_linenos): Fix typo in last change. + +Thu Aug 3 22:01:26 1995 Fred Fish + + * ch-exp.y (write_lower_upper_value): Add prototype so bison + generated parser will insert prototype before first func usage. + Bison and byacc order the output sections differently. Also + make function static. + +Thu Aug 3 10:45:37 1995 Fred Fish + + * Update all FSF addresses except those in COPYING* files. + +Thu Aug 3 01:38:45 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/alpha/tm-alpha.h (EXTRA_FRAME_INFO): Add pc_reg field. + (SKIP_TRAMPOLINE_CODE): Define. + * alpha-tdep.c (alpha_frame_saved_pc): Use pc_reg field from + frame to find the saved pc register. + (alpha_saved_pc_after_call): Skip over shared library trampoline + before trying to find the saved pc register. + (find_proc_desc): Copy PROC_PC_REG from found proc_desc + to heuristic proc_desc. + (init_extra_frame_info): Initialize pc_reg field in frame. + +Wed Aug 2 18:00:36 1995 Stan Shebs + + * configure.in (m68*-est-*): Use monitor target config. + * configure: Update. + * config/m68k/est.mt, config/m68k/tm-est.h: Delete. + * config/m68k/monitor.mt, config/m68k/tm-monitor.h: Fix comments. + +Tue Aug 1 22:52:53 1995 Fred Fish + + * Makefile.in (VERSION): Bump to 4.14.2 + +Tue Aug 1 16:04:36 1995 Kung Hsu + + * xcoffread.c (process_linenos): The value in include file symbol + should point to line number table. Currently this value is not + set correctly by AIX ld. A fix to get around this bug. + +Tue Aug 1 11:44:53 1995 J.T. Conklin + + * configure.in: Check for working mmap, ansi headers, string.h, + strings.h, and memory.h. + * configure: Regenerated. + + * gdb_stat.h: New file, "portable" . + * gdb_string.h: New file, "portable" . + + * altos-xdep.c, arm-tdep.c, arm-xdep.c, convex-tdep.c, + convex-xdep.c, coredep.c, cxux-nat.c, dbxread.c, exec.c, + gould-xdep.c, hppa-tdep.c, i386aix-nat.c, i386b-nat.c, + i386mach-nat.c, i386v-nat.c, infptrace.c, m88k-nat.c, main.c, + mdebugread.c, objfiles.c, os9kread.c, procfs.c, pyr-xdep.c, + rs6000-nat.c, source.c, standalone.c, stuff.c, sun386-nat.c, + symfile.c, symm-nat.c, symm-tdep.c, symtab.c, top.c, ultra3-nat.c, + ultra3-xdep.c, umax-xdep.c, xcoffread.c: Include "gdb_stat.h" + instead of . + + * alpha-tdep.c, breakpoint.c, buildsym.c, c-typeprint.c, + ch-typeprint.c, coffread.c, command.c, core-sol2.c, core-svr4.c, + core.c, corelow.c, cp-valprint.c, dbxread.c, dcache.c, demangle.c, + dpx2-nat.c, dstread.c, dwarfread.c, elfread.c, environ.c, eval.c, + exec.c, f-lang.c, f-typeprint.c, f-valprint.c, findvar.c, + fork-child.c, gdbtypes.c, hpread.c, i386-tdep.c, infcmd.c, + inflow.c, infptrace.c, infrun.c, irix5-nat.c, language.c, + m2-typeprint.c, main.c, mdebugread.c, minsyms.c, mipsread.c, + monitor.c, nlmread.c, objfiles.c, os9kread.c, osfsolib.c, parse.c, + printcmd.c, procfs.c, regex.c, remote-adapt.c, remote-arc.c, + remote-array.c, remote-bug.c, remote-e7000.c, remote-eb.c, + remote-es.c, remote-hms.c, remote-mm.c, remote-os9k.c, + remote-pa.c, remote-sim.c, remote-st.c, remote-udi.c, + remote-utils.c, remote-vx.c, remote-vx29k.c, remote-vx68.c, + remote-vx960.c, remote-vxmips.c, remote-vxsparc.c, remote.c, + solib.c, somread.c, source.c, stabsread.c, stack.c, symfile.c, + symmisc.c, symtab.c, target.c, top.c, typeprint.c, utils.c, + valarith.c, valops.c, valprint.c, values.c, xcoffread.c: Include + "gdb_string.h" instead of . + + * config/xm-sysv4.h, i386/xm-ptx.h, m68k/xm-sun3os4.h, + sparc/xm-sun4os4.h (HAVE_MMAP): Removed. + + * config/xm-lynx.h, config/i386/xm-ptx.h, + config/m68k/nm-apollo68b.h, config/m68k/xm-hp300hpux.h, + config/mips/xm-irix3.h, config/mips/xm-mips.h, + config/mips/xm-news-mips.h, config/mips/xm-riscos.h, + config/pa/hppah.h, config/rs6000/xm-rs6000.h, + config/sparc/xm-sun4os4.h, config/sparc/xm-sun4sol2.h, + config/vax/xm-vaxbsd.h, config/vax/xm-vaxult.h, + config/vax/xm-vaxult2.h (MEM_FNS_DECLARED): Removed. + * config/mips/xm-irix3.h, config/mips/xm-mips.h, + config/pa/xm-hppah.h (memcpy, memset): Removed declarations. + +Tue Aug 1 02:08:30 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-tdep.c (mips_extract_return_value): Fix returning of + values whose length is less than the register size for big endian + targets. + * alpha-tdep.c (alpha_extract_return_value, + alpha_store_return_value): Use alpha_convert_register_to_* + to handle functions returning "float" correctly. + +Mon Jul 31 19:12:48 1995 Stan Shebs + + * h8500-tdep.c: General linting and cleanup. + (opcodes/h8500-opc.h): Don't include. + (code_size, data_size): Make static. + (frame_locals_address, frame_args_address): Remove. + (h8300_pop_frame): Rename to h8500_pop_frame. + (big_command, medium_command, compact_command, small_command): + Define as regular functions rather than with macro trickery. + (tm_print_insn): Set to correct disassembler function. + * config/h8500/tm-h8500.h: Minor cleanup, add prototypes. + (ABOUT_TO_RETURN): #if 0 out. + (FRAME_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS): Use usual define. + (GDB_TARGET_IS_H8500): Remove duplicate definition. + (regoff): Remove, never used. + * config/h8500/h8500.mt (TDEPFILES): Add monitor.o. + +Mon Jul 31 14:32:30 1995 J.T. Conklin + + * configure.in: Check for unistd.h. + * configure: Regenerated. + + * command.c, cp-valprint.c, fork-child.c, i386-tdep.c, + i386b-nat.c, inflow.c, main.c, maint.c, objfiles.c, solib.c, + source.c, stack.c, symfile.c, top.c, utils.c: Include strings.h + and/or unistd.h to bring prototypes into scope. + +Sun Jul 30 01:40:11 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * rs6000-tdep.c (frame_saved_pc): Check for signal handler caller + before trying to determine the start of the function. + (skip_prologue): Skip subroutine call which might save the + floating point registers only if it is within the first three + instructions. + Reinstate setting of alloca_reg if setup of a gcc frame pointer + is found. + (frame_get_cache_fsr): Use new fields in rs6000_framedata. + +Sat Jul 29 14:43:35 1995 Stan Shebs + + * sparclite: Removed subdirectory. aload and eload are now in + utils/sparclite, low-level library is in libgloss. + * configure.in (sparclite*): Don't configure sparclite subdir. + * configure: Update. + * Makefile.in (TARDIRS): Remove, no longer used. + +Sat Jul 29 01:45:56 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * procfs.c (unconditionally_kill_inferior): Clear current signal + if PROCFS_NEED_CLEAR_CURSIG_FOR_KILL is defined. + * config/alpha/nm-osf3.h (PROCFS_NEED_CLEAR_CURSIG_FOR_KILL): Define. + + * alpha-tdep.c: Move sigtramp handling of saved registers from + read_next_frame_reg to alpha_find_saved_regs, handle saved + floating point registers. + * mips-tdep.c: Move sigtramp handling of saved registers from + read_next_frame_reg to mips_find_saved_regs, handle saved + floating point registers. + * config/mips/tm-irix3.h, config/mips/tm-irix5.h, + config/mips/tm-mipsv4.h (SIGFRAME_FPREGSAVE_OFF): Define. + + * sparc-tdep.c (sparc_pc_adjust): Fix check for `unimp' + instruction to handle functions returning structures with + large sizes properly. + +Fri Jul 28 11:50:17 1995 steve chamberlain + + * configure, configure.in (z8k-*-sim): deleted. + +Thu Jul 27 12:49:28 1995 Jeffrey A. Law + + * lynx-nat.c (child_wait): Handle threads exiting. + +Thu Jul 27 07:47:50 1995 Michael Meissner + + * rs6000-tdep.c (skip_prologue): Don't assume the update stack + instruction is the last in the prologue, since xlc stores the lr + after the stack update. Make sure offset is correct sign for + large frames. + (frame_saved_pc): Move test for signal before frameless. + + * config/rs6000/tm-rs6000.h (DEFAULT_LR_SAVE): Define. + * config/powerpc/tm-ppc-eabi.h (DEFAULT_LR_SAVE): Redefine. + +Thu Jul 27 01:22:08 1995 Jeffrey A. Law + + * hppa-tdep.c (hppa_fix_call_dummy): Rewrite code for calling + into shared libraries. + +Wed Jul 26 23:33:34 1995 Michael Meissner + + * config/rs6000/tm-rs6000.h (rs6000_framedata): Add offsets the + gprs, fprs, lr, and cr is stored at. + (FRAME_FIND_SAVED_REGS): Use new fields in rs6000_framedata. + (function_frame_info): Delete declaration. + (SKIP_PROLOGUE): Skip_prologue is now passed a rs6000_framedata + structure to fill in. + (FRAMELESS_FUNCTION_INVOCATION): Function now longer takes a + second argument. + (FRAME_SAVED_PC): Call frame_saved_pc. + + * rs6000-tdep.c (skip_prologue): Recognize V.4 prologues as well + as AIX style. Fill in rs6000_framedata structure. Remember where + the gprs, fprs, cr, and lr are saved. + (pop_frame): Use skip_prologue, not function_frame_info, and use + new rs6000_framedata fields. + (function_frame_info): Function deleted. + (frameless_function_invocation): Separate frame_saved_pc support + to new function. Recognize V.4 frames. + (frame_saved_pc): New function. + (frame_get_cache_fsr): Use skip_prologue, not function_frame_info. + (frame_initial_stack_address): Ditto. + +Wed Jul 26 01:00:37 1995 Jeff Law (law@snake.cs.utah.edu) + + * remote.c: Add documentation for extended protocol operations + and for thread_alive change from a couple weeks ago. + (extended_remote_ops): Declare and define a new target vector + for the extended remote protocol. + (extended_remote_restart): New function to restart the remote + server & process. + (remote_open): Just a stub routine. + (extended_remote_open): New function to start a remote session + using the extended gdb remote protocol. + (remote_open_1): New function containing code common to both + remote_open and extended_remote_open. + (remote_mourn, extended_remote_mourn, remote_mourn_1): Similarly. + (extended_remote_create_inferior): New function for the extended + remote target. + (initialize_remote): Add the extended_remote_ops target vector. + * gdbserver/server.c (main, case '!'): Set extended_protocol. + (main, case 'k'): If the extended protocol is in use, kill the + inferior then start a new one. + (main, case 'R'): New command to restart the remote server and + inferior process. Only supported when using the extended + protocol. + (main, server loop): If the inferior terminates while using the + extended protocol then start a new one. If getpkt fails when + using the extended protocol then exit. + +Tue Jul 25 11:43:44 1995 Stan Shebs + + * mdebugread.c (psymtab_to_symtab_1): Relocate encoded stab + line numbers using the psymtab's section offsets. + +Tue Jul 25 10:43:27 1995 Michael Meissner + + * config/rs6000/tm-rs6000.h (rs6000_framedata): Rename from + aix_framedata. Change all uses. + * rs6000-tdep.c: Change all aix_framedata -> rs6000_framedata. + +Sat Jul 22 23:44:18 1995 Jeff Law (law@snake.cs.utah.edu) + + * defs.h (ATTR_FORMAT): Disable if ANSI_PROTOTYPES is not defined. + +Fri Jul 21 16:50:28 1995 Jeffrey A. Law + + * lynx-nat.c (child_thread_alive): New function. Somehow I + forgot to check this in with all the other thread_alive changes. + +Thu Jul 20 22:22:34 1995 Jeff Law (law@snake.cs.utah.edu) + + * somread.c (som_symtab_read): Add unsatisfied common symbols to + the minimal symbol table. All common symbols are "unsatisfied" + when -E is passed to the linker. + +Thu Jul 20 15:04:57 1995 Fred Fish + + * top.c (show_endian): Cast first arg of printf_unfiltered to + correct type of "char *". + +Thu Jul 20 14:18:51 1995 Jeffrey A. Law + + * lynx-nat.c (child_wait): A thread_id of zero from wait apparently + means the process is single threaded, so there's no need to add + it to the thread list. Handle case where multi-threaded process + reverts back to a single-threaded process. + + * gdbserver/low-hppabsd.c: Remove error declaration. + * gdbserver/low-sparc.c: Likewise. + * gdbserver/low-sun3.c: Likewise. + * gdbserver/server.h: Remove error and fatal declaration. + * gdbserver/utils.c (error): Update to be compatable with recent + changes in defs.h. + (fatal): Likewise. + +Wed Jul 19 22:42:43 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/m68k/tm-m68kv4.h (DWARF_REG_TO_REGNUM): Define to + correctly map floating point registers numbers. + + * dwarfread.c (locval, new_symbol): Handle variables that are + optimized out. + + * mdebugread.c: Replace all uses of builtin_type_* with + mdebug_type_*. Define and initialize mdebug_type_*. + + * serial.h (serial_close): Add additional argument `really_close'. + (SERIAL_CLOSE): Update serial_close call accordingly. + (SERIAL_UN_FDOPEN): Use serial_close to handle refcnt properly. + * serial.c (serial_close): Handle `really_close'. + * serial.h (scb_base): Moved to serial.c, made static. + + * valops.c (value_addr): Don't coerce arrays. + (typecmp): Coerce arrays instead of calling value_addr if necessary. + +Wed Jul 19 18:19:28 1995 Stan Shebs + + From Richard Earnshaw (rearnsha@armltd.co.uk): + * infrun.c (wait_for_inferior): Set the convenience variable + $_exitcode to the termination code of the inferior. + * top.c (quit_command): Accept optional expression to use + as parameter to exit(). + +Wed Jul 19 13:15:32 1995 Kung Hsu + + * remote.c (remote_wait): When getting registers, check endianess and + do conversion if necessary. + +Tue Jul 18 00:41:31 1995 Jeff Law (law@snake.cs.utah.edu) + + * gdbserver/low-hppabsd.c: New file. + * gdbserver/Makefile.in (SFILES): Add low-hppabsd.c. + * config/pa/hppabsd.mh (XDEPFILES): Add ser-tcp.o. + (GDBSERVER_DEPFILES): Add low-hppabsd.o. + * config/pa/hppaosf.mh: Likewise. + +Mon Jul 17 21:35:18 1995 Fred Fish + + * dache.c (struct dcache_block): Change data member from unsigned + char to char, since everything passed in and out of dcache is char + or casted to appropriate type anyway. + (dcache_alloc): Move assignment of db out of test and combine + separate tests into if-else. + (dcache_peek_byte): Change ptr from unsigned char* to char*. + (dcache_peek_byte): Remove now unnecessary cast in read_memory call. + (dcache_peek): Change cast of incoming data arg. + (dcache_poke): Change cast of addr of incoming data arg. + (dcache_info): Mask data passed to printf_filtered to lsbyte only. + (dcache_info): Change printf_filtered arg from "% 2x" to " %2x". + * target.c (debug_to_thread_alive): Change return type to int and + return zero, for type compatibility with other *_thread_alive + funcs. + (cleanup_target): Change cast of ignore function to match type of the + to_thread_alive member. + * defs.h (error_hook): Add ATTR_NORETURN. + * defs.h (NORETURN, ATTR_NORETURN): Switch from volatile to + __attribute__ method with gcc 2.7, to avoid gcc 2.6.3 bug. + * remote.c (remote_wait): Cast first arg to strtol, strchr, and + strncmp to "const char *" from "unsigned char *". + (remote_wait): Cast arg to putpkt and strcpy from "unsigned char *" + to "char *". + (remote_wait): Change printf format for long arg from "%d" to "%ld". + (getpkt): Remove unused variable "bp". + (remote_fetch_word, remote_store_word): Ifdef out apparently unused + functions. + * breakpoint.c (watchpoint_check): Removed unused variables + "saved_level" and "saved_frame". + * valops.c (value_arg_coerce): Add other enum TYPE_CODE_* and + default cases to switch for completeness. + * infrun.c (wait_for_inferior): Enclose "have_waited" label + in #ifdef that matches the one in which it is referenced. + * ser-unix.c (hardwire_noflush_set_tty_state): Enclose otherwise + unused variable "state" in #ifdef that matches one in which it is + referenced. + * eval.c (evaluate_subexp_standard): Remove unused variable "var". + * eval.c (evaluate_subexp_standard): Remove unused variable + "tmp_symbol". + * valarith.c (value_subscript): Remove unused variable + "lowerbound", which is redeclared in a nested scope prior to use. + * printcmd.c (print_frame_nameless_args): Use "%ld" to print long + arg, not "%d". + * {mem-break.c, remote-pa.c, remote.c, saber.suppress}: + Remove unused static var "check_break_insn_size". + * buildsym.c (finish_block): Add other enum LOC_* and default + cases to switch for completeness. + ch-lang.c (type_lower_upper): Removed unused label "retry". + Add other enum TYPE_* and default cases to switch for completeness. + * f-typeprint.c (f_type_print_args): Ifdef out unused function + that may be used someday when Fortran support is complete. + * ch-valprint.c (chill_print_type_scalar): Add other enum + TYPE_* and default cases to switch for completeness. + (chill_val_print): Remove unused local var "high_bound" that + is redeclared in a nested scope prior to use. + (chill_var_print): Use "%ld" to print long arg, not "%d". + * regex.c (re_compile_fastmap, re_match_2): Add remaining enum + types and default to switches for completeness. + * minsyms.c (lookup_minimal_symbol_text): Delete unused variable + "trampoline_symbol". + (prim_record_minimal_symbol_and_info): Return NULL rather than + trash. + * elfread.c (elf_symtab_read): Don't dereference NULL returns from + record_minimal_symbol_and_info. + * f-lang.c (saved_function_list_end): Ifdef out unused variable + that may be used someday. + * f-valprint.c (f_val_print): Remove unused local "straddr". + +Mon Jul 17 13:08:00 1995 Ian Lance Taylor + + * stabsread.h (struct stab_section_list): Define. + (coffstab_build_psymtabs): Remove staboff and stabsize parameters. + Add textaddr, textsize, and stabs parameters. + * gdb-stabs.h (struct dbx_symfile_info): Remove text_sect field. + Add text_addr and text_size fields. + (DBX_TEXT_SECT): Don't define. + (DBX_TEXT_ADDR, DBX_TEXT_SIZE): Define. + * coffread.c: Include . + (struct coff_symfile_info): Remove stabsect and stabindexsect + fields. Add textaddr, textsize, and stabsects fields. + (coff_locate_sections): Record the address of the .text section, + and total the sizes of all sections with names beginning with + ".text". Don't bother to record a .stab.index section (COFF + doesn't use them). Make a linked list of all sections with names + beginning with ".stab". + (coff_symfile_read): Adjust call to coffstab_build_psymtabs for + new parameters. + * dbxread.c (dbx_symfile_read): Use DBX_TEXT_ADDR and + DBX_TEXT_SIZE, rather than getting both from DBX_TEXT_SECT. + (dbx_symfile_init): Set DBX_TEXT_ADDR and DBX_TEXT_SIZE, not + DBX_TEXT_SECT. + (elfstab_build_psymtabs): Likewise. + (stabsect_build_psymtabs): Likewise. + (symbuf_sections, symbuf_left, symbuf_read): New static variables. + (fill_symbuf): If symbuf_sections is not NULL, read symbols from + multiple sections. + (coffstab_build_psymtabs): Remove staboffset and stabsize + parameters. Add textaddr, textsize, and stabsects parameters. + Set DBX_TEXT_ADDR and DBX_TEXT_SIZE, not DBX_TEXT_SECT. Handle + multiple stabs sections. + * os9kread.c (os9k_symfile_read): Use DBX_TEXT_ADDR and + DBX_TEXT_SIZE, rather than getting both from DBX_TEXT_SECT. + (os9k_symfile_init): Set DBX_TEXT_ADDR and DBX_TEXT_SIZE, not + DBX_TEXT_SECT. + + * remote-vx.c (vx_ops, vx_run_ops): Initialize new to_thread_alive + field. + +Sat Jul 15 01:02:53 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * config/alpha/alpha-osf3.mh, config/alpha/nm-osf3.h: New files + for OSF/1-3.x procfs support. + * configure.in (alpha-dec-osf): Use them when configuring + for OSF/1-3.x. + * configure: Updated. + * target.c: Include . + +Fri Jul 14 16:16:56 1995 J.T. Conklin + + * Makefile.in, configure.in: Use one variable, frags, to hold + pathnames of makefile fragments. + * configure: regenerated. + +Fri Jul 14 09:49:47 1995 Jeff Law (law@snake.cs.utah.edu) + + * procfs.c (procfs_ops): Fix typo in last change. + +Thu Jul 13 13:42:38 1995 Jeffrey A. Law + + * inftarg.c (child_thread_alive): New function to see if a + particular thread is still running. + (child_ops): Add child_thread_alive entry. + * remote.c (remote_thread_alive): New function to see if a + particular thread is still alive. + (remote_ops): Add remote_thread_alive. + * target.c (dummy_target): Add dummy entry for thread_alive. + (cleanup_target): de_fault thread_alive too. + (update_current_target): INHERIT thread_alive too. + (debug_to_thread_alive): New function. + (setup_target_debug): Add debug_to_thread_alive. + * target.h (struct target_ops): Add to_thread_alive. + (target_thread_alive): Define. + * thread.c (info_threads_command): Don't call kill; use + target_thread_alive instead. + * config/nm-lynx.h (CHILD_THREAD_ALIVE): Define. + * gdbserver/low-lynx.c (mythread_alive): New function. + (mywait): Don't restart any threads after a new thread notification, + let the generic code handle it. + * gdbserver/low-sparc.c (mythread_alive): Dummy version. + * gdbserver/low-sun3.c (mythread_alive): Likewise. + * gdbserver/server.c (main): Handle thread_alive requests. + * gdbserver/server.h (mythread_alive): Declare. + * corelow.c (core_ops): Add dummy entry for thread_alive. + * exec.c (exec_ops): Likewise. + * m3-nat.c (m3_ops): Likewise. + * monitor.c (monitor_ops): Likewise. + * procfs.c (procfs_ops): Likewise. + * remote-arc.c (arc_ops): Likewise. + * remote-array.c (array_ops): Likewise. + * remote-e7000.c (e7000_ops): Likewise. + * remote-es.c (es1800_ops, es1800_child_ops): Likewise. + * remote-mips.c (mips_ops): Likewise. + * remote-pa.c (remote_hppro_ops): Likewise. + * remote-sim.c (gdbsim_ops): Likewise. + * sparcl-tdep.c (sparclite_ops): Likewise. + +Tue Jul 11 11:15:55 1995 Kung Hsu + + * solib.c: Add _DYNAMIC__MGC base symbol for Mentor Graphics Inc. + * solib.c (match_main): New function for checking name of main. + * solib.c (solib_add): Not to add if solib match main. + +Fri Jul 7 14:41:56 1995 Kung Hsu + + * elfread.c (elf_symtab_read): Fix a bug ignoring compiler + generated internal labels ($LM...). + +Wed Jul 5 11:38:36 1995 Kung Hsu + + * defs.h: if __GO32__ or WIN32 the directory separating symbol should + be '\' not '/'. + + * remote-nindy (nindy_wait): Use infinite timeout reading after + esacpe character. + +Tue Jul 4 10:30:22 1995 Jeffrey A. Law + + * infrun.c (wait_for_inferior): When switching from one thread to + another, save infrun's state for the old thread and load infrun's + previous state for the new thread. + * thread.c (struct thread_info): Add new fields for thread specific + state saved/restored in infrun.c. + (add_thread): Initialize new fields. + (load_infrun_state): New function. + (save_infrun_state): New function. + * thread.h (load_infrun_state): Provide external decl. + (save_infrun_state): Likewise. + + * infrun.c (wait_for_inferior): When we hit a breakpoint for the + wrong thread, make sure to write the fixed PC value into the thread + that stopped. Restart all threads after single stepping over a + breakpoint for a different thread. + * breakpoint.c (set_momentary_breakpoint): Make momentary + breakpoints thread specific in a multi-threaded program. + * lynx-nat.c (child_resume): Add some comments. Correctly + choose between the single and multi-threaded step and continue + ptrace calls. + +Fri Jun 30 16:15:36 1995 Stan Shebs + + * config/h8300/h8300.mt: Renamed from h8300hms.mt. + * config/h8500/h8500.mt: Renamed from h8500hms.mt. + * config/z8k/z8k.mt: Renamed from z8ksim.mt. + * configure, configure.in: Update to reflect renamings. + + * remote-sim.c (sim): New command, passes commands to simulator. + (simulator_command): New function. + (gdbsim_ops): Clean up. + * remote-sim.h (sim_do_command): Declare. + * sh-tdep.c (memory_size): Remove command. + + * Makefile.in (SIM, SIM_OBS): New variables. + (CLIBS, CDEPS): Add value of SIM. + (DEPFILES): Add value of SIM_OBS + + * config/arm/arm.mt, config/h8300/h8300.mt, config/h8500/h8500.mt, + config/sh/sh.mt, config/sparc/sp64sim.mt, config/w65/w65.mt, + config/z8k/z8k.mt: Remove simulator files from TDEPFILES, + define in SIM_OBS and SIM. + config/sparc/sp64sim.mt (SIMFILES): Remove. + + * remote-z8k.c: Remove, was superseded by remote-sim.c + * Makefile.in, mpw-make.in: Remove references to remote-z8k.c. + +Sun Jun 25 15:30:43 1995 Stan Shebs + + * remote.c (remote_read_bytes, remote_write_bytes): Second arg + should be char *, not unsigned char *. + * dcache.h (memxferfunc): Ditto. + * monitor.c (monitor_write_memory, monitor_read_memory_single): + Ditto. + (monitor_make_srec): Let compiler figure size of hextab. + +Sat Jun 24 19:27:37 1995 Jeffrey A. Law + + * lynx-nat.c (child_wait): Don't restart new threads and loop + to the top of child_wait; let the machine independent code in + wait_for_inferior deal with new thread notifications. + +Fri Jun 23 11:51:58 1995 Kung Hsu + + * remote-nindy (nindy_load): Put in target specific load, it's + 20 times faster. + +Thu Jun 22 20:21:59 1995 Stan Shebs + + * utils.c (error): Move local `args' outside conditional, + move local `string1' inside, declare function as void if + non-ANSI compiler, dereference error_hook when calling. + + * mac-xdep.c (stdarg.h): Don't include. + +Thu Jun 22 13:12:33 1995 Kung Hsu + + * remote-nindy.c (nindy_wait): Change timeout in SERIAL_READCHAR. + +Wed Jun 21 13:24:41 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppam3-nat.c: Change HP800_THREAD_STATE to TRACE_FLAVOR and + HP800_THREAD_STATE_COUNT to TRACE_FLAVOR_SIZE. + +Wed Jun 21 05:57:56 1995 Steve Chamberlain + + * monitor.c: Turn on caching. + (monitor_printf): If a ^C was sent, don't expect to see its + echo. + (monitor_open): Enable caching. + (monitor_resume, monitor_load): Flush cache. + (monitor_xfer_memory): Call cache routine. + (monitor_dump_regs): New. + (monitor_fetch_registers): If monitor_dump_regs available + then use it. + (monitor_load): Don't ref exec_bfd if it's NULL. + (monitor_load_srec): Use new monitor_make_srec calling convention. + (monitor_make_srec): Rewrite to cope with two, three and four byte + addresses. + * remote-hms.c (hms_cmds): Initialze end-of-command delim. + * dcache.h, dcache.h: Rewritten. + * remote.c: Reenable caching. + (getpkt): Reduce MAX_TRIES to 3. + (remote_xfer_memory): Use dcache_xfer_memory. + * defs.h (error_hook): New. + * top.c (error_hook): New definition. + * utils.c (error): Use error_hook if initialized. + * sparcl-tdep.c (HAVE_SOCKETS): Don't define if GO32 or WIN32. Use + HAVE_SOCKETS in place of #ifndef GO32. + +Tue Jun 20 22:17:44 1995 Jeff Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (PSW_*): Define processor status word masks. + (INSTRUCTION_NULLIFIED): Allow specific targets to override. + * config/pa/tm-hppao.h (INSTRUCTION_NULLIFIED): Define to work + around losing mach kernel behavior. + +Tue Jun 20 12:03:36 1995 Stan Shebs + + * monitor.c (monitor_wait): Don't use the watchdog timeout + if its value is 0. + * w89k-rom.c (w89k_open): Define to be static. + + +Sat Jun 17 10:17:16 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (som_solib_add): Validate regexp argument. + Don't assume the first entry on dld's library list is the main + program. Don't load the same library more than once and don't + consider the main program a shared library. + (som_solib_sharedlibrary_command): New function + (_initialize_som_solib): Add "sharedlibrary" command. + +Thu Jun 15 14:54:58 1995 Stan Shebs + + * array-rom.c: Remove, no longer used. + + * remote-hms.c (hms_open): Make static. + + * mpw-config.in (MacSerial.h): Copy from version in {CIncludes}, + not {MPW}Interfaces:CIncludes. + * ser-mac.c (mac_baud_rate_table): Fix value for 38400 baud. + +Wed Jun 14 14:27:07 1995 Per Bothner + + * ch-exp.y: Remove lots of unsupported productions and names. + Add support for IF-expressions, ORIF, ANDIF, NUM, and ADDR. + +Tue Jun 13 21:40:11 1995 Per Bothner + + * parser-defs.h (enum precedence): Added PREC_BUILTIN_FUNCTION. + * expression.h (enum exp_opcode): Added UNOP_LOWER, UNOP_UPPER, + UNUP_LENGTH. + * expprint.c (dump_expression): Handle the new exp_opcodes. + (print_subexp): Handle PREC_BUILTIN_FUNCTION. + (print_simple_m2_func): Removed. + (print_subexp): Remove support for Modula2 builtin functions. + * m2-lang.c (m2_op_print_tab): Add support for builtin functions. + * ch-exp.y: Parse LOWER, UPPER, and LENGTH builtins. + (write_lower_upper_value): Convenience function for LOWER and UPPER. + (upper_lower_argument, length_argument): Removed non-terminals. + * ch-lang.c (chill_op_print_tab): Entries for UPPER, LOWER, LENGTH. + (type_lower_upper): New function. Calculate LOWER/UPPER of type. + (value_chill_length): New function. Calcalate LENGTH of ARRAY/STRING. + (evaluate_subexp_chill): Handle UNOP_LOWER, UNOP_UPPER, UNOP_LENGTH. + +Mon Jun 12 12:48:13 1995 Stan Shebs + + Windows support bits from Steve Chamberlain . + * defs.h: Don't declare strchr and friends if WIN32. + (DIRNAME_SEPARATOR): Move here from source.c. + (SLASH_P, SLASH_CHAR, SLASH_STRING, ROOTED_P): New macros, + symbolic definitions for filename bits. + * top.c (cd_command): Use these. + * source.c (mod_path, openp): Ditto. + * terminal.h: Disable termio/sgtty definitions if WIN32. + * findvar.c (registers_changed): Call registers_changed_hook + if it is defined. + +Mon Jun 12 12:22:05 1995 J.T. Conklin + + * Makefile.in (distclean, realclean): Remove config.cache and + config.log. + +Mon Jun 12 00:21:59 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c: Include gdb-stabs.h. + (som_solib_section_offsets): Use SECT_OFF_XXX rather than 0, 1, + etc. Initialize offsets for RODATA & BSS too. + +Sat Jun 10 17:59:11 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa-tdep.c (frame_chain): Try to compensate for incomplete + register information in core files when backtracing. + +Fri Jun 9 14:51:38 1995 Stu Grossman (grossman@cygnus.com) + + * remote-nrom.c: Remove everything but download code. More + cleanups. + +Thu Jun 8 15:06:00 1995 Stu Grossman (grossman@cygnus.com) + + * defs.h maint.c monitor.c remote-mips.c remote.c: Add support + for `watchdog' variable. This allows the user to put an upper + limit on the amount of time that GDB will wait for the target to + return from a step or continue operation. This will primarily be + used for the testsuite, where it is difficult to come up with a + reasonable timeout for things like function calls, which can take + as long as three minutes under some circumstances. If the + watchdog timer expires, GDB will generate an error that looks like + `Watchdog has expired.', and will detach from the target. + + * remote-mips.c (mips_open): Setup initial frame from target. + Print it out so that user is told where the program is stopped + when they attach. + + * remote-nrom.c: Loads of cleanups. Use serial code to open + network connections. Use expect() to wait for response to + download command. + + * ser-tcp.c (tcp_open): Retry connection if we get ECONNREFUSED. + + * serial.c serial.h (serial_open serial_fdopen serial_close): + Allow users to open the same device multiple times. They all get + to share the same serial_t. This is about the only way to have + multiple active targets use the same device (for download and + debug). + + * sparcl-tdep.c: Keep #include away from GO32. + + * target.c: Add `targetdebug' variable. If this is non-zero, + then a special target is put at the top of the target stack which + will cause all calls through the target vector to have their args + and results printed out. + +Wed Jun 7 17:40:37 1995 Per Bothner + + * ch-exp.y: Handle "->" . + +Wed Jun 7 17:46:33 1995 Michael Meissner + + * mem-break.c (LITTLE_BREAKPOINT): If BREAKPOINT and + {LITTLE,BIG}_BREAKPOINT are all defined, don't redefine. + (BIG_BREAKPOINT): Ditto. + + * config/rs6000/tm-rs6000.h (BREAKPOINT): Define as either + BIG_BREAKPOINT or LITTLE_BREAKPOINT depending on the target byte + order. + +Wed Jun 7 12:41:42 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (som_solib_section_offsets): Handle relative pathnames. + + * hppa-tdep.c (frame_saved_pc): Handle backtracing through signal + handler in dynamically linked executables. + +Tue Jun 6 10:44:25 1995 Michael Meissner + + From Andrew Cagney + * rs6000-tdep.c (single_step): Handle both little and big endian + breakpoints. + (gdb_print_insn_powerpc): Deal with disassembling both little and + big endian PowerPC systems. + (_initialize_rs6000_tdep): Use gdb_print_insn_powerpc to handle + disassembly, rather that assuming big endian order. + + * config/rs6000/tm-rs6000.h (BREAKPOINT): Delete. + (BIG_BREAKPOINT): Define, big endian breakpoint instruction. + (LITTLE_BREAKPOINT): Define, little endian breakpoint instruction. + +Sat Jun 3 01:54:56 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * README: Add note about Unixware 2.x. + + * dbxread.c (process_one_symbol): Check for exact symbol name + match when fixing up N_GSYM and N_STSYM symbols from Sun acc. + + * valprint.c (value_print_array_elements): Use + fprintf_filtered to put out `', + from schwab@issan.informatik.uni-dortmund.de (Andreas Schwab). + + * value.h (struct value): Change `repetitions' field from + `short' to `int' type. + + +Wed May 31 12:04:01 1995 J.T. Conklin + + * nlm/{configure.in, Makefile.in}: Converted to use autoconf. + * nlm/configure: New file, generated with autoconf 2.3. + + * nlm/configure.in: Use sed instead of awk to get the value of + cpufile. Awk is not a utility required by the GNU coding + standards. This change also fixes the rigid whitespace + requirements that were required for awk. + + * sparclite/aload.c: Use a file descriptor instead of a stdio + stream for i/o with target board. + Use #error if HAVE_TERMIOS is not defined. + + * sparclite/{Makefile.in, configure.in}: Converted to use + autoconf. + * sparclite/configure: New file, generated with autoconf 2.3. + +Sun May 28 23:10:07 1995 Jeff Law (law@snake.cs.utah.edu) + + * defs.h: Include either varargs.h or stdarg.h (for va_list). + Fix stupid thinko in last change ("..." -> "va_list"). + + * defs.h (vprintf_filtered declaration): Add PARAMS prototype; + gcc-2.5 chokes on format attributes for unprototyped functions. + (vfprintf_filtered declaration): Likewise. + (vprintf_unfiltered declaration): Likewise. + (vfprintf_unfiltered). Likewise. + +Sat May 27 23:54:17 1995 J.T. Conklin + + * configure.in: Use sed instead of awk to get the values of + hostfile, targetfile and nativefile. Awk is not a utility + required by the GNU coding standards. This change also + fixes the rigid whitespace requirements that were required + for awk. + * configure: regenerated. + +Sat May 27 16:24:04 1995 Angela Marie Thomas + + * sparclite/{Makefile,configure}.in: Add hooks for building with + -lsocket & -lnsl for solaris2. Don't build aload/eload for DOS. + +Thu May 25 12:46:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbserver/remote-utils.c (prepare_resume_reply): Add FIXME + comment regarding signal numbering. + +Wed May 24 15:49:47 1995 Steve Chamberlain + + * arm-tdep.c (_initialize_arm_tdep): Use print_insn_little_arm + now. + + * arm-tdep.c (convert_from_extended, convert_to_extended): + New. + * coffread.c (enter_linenos): Return if linetab 0. + * config/arm/arm.mt (TDEPFILES): Add simulator support. + * config/arm/tm-arm.h (FRAME_FIND_SAVED_REGS): Fix prototypes. + +Mon May 22 19:37:21 1995 Rob Savoye + + * config/idt.mt: replace monitor and array-rom with the new + remote-array. + +Mon May 22 15:38:25 1995 Stu Grossman (grossman@cygnus.com) + + * remote-nindy.c: Install Kung patch for PR 6820. I have no idea + what this does... + + * breakpoint.c: Move defaults of watchpoint related macros into + target.h. + * target.h: Macros from breakpoint.c. Conditionalize based on + TARGET_HAS_HARDWARE_WATCHPOINTS. + * i386v-nat.c procfs.c: Use TARGET_HAS_HARDWARE_WATCHPOINTS + instead of TARGET_CAN_USE_HARDWARE_WATCHPOINT to enable watchpoint + code. + * config/i386/nm-linux.h, config/mips/nm-irix4.h, + config/pa/nm-hppab.h, config/sparc/tm-sparclite.h: #define + TARGET_HAS_HARDWARE_WATCHPOINTS to enable watchpoint code. + +Mon May 22 06:47:30 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c, target.h: Move defaults of watchpoint related + macros back to breakpoint.c. Required to get GDB compiling + on Solaris again. + +Fri May 19 14:49:37 1995 J.T. Conklin + + * defs.h (ATTR_FORMAT): New macro, expands to gcc's format + attribute when compiled by gcc. + * defs.h, language.h, monitor.h: Changed many function + declarations to use ATTR_FORMAT. + + * breakpoint.c (delete_command); source.c (directory_command); + top.c (define_command): Changed call to query() that had too + many arguments. + * printcmd.c (address_info): Changed call to printf_filtered() + that had too many arguments. + +Fri May 19 09:52:07 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (wait_for_inferior): Move assignments to stop_signal + and stop_pc, and STOPPED_BY_WATCHPOINT code, back where they + were--after the switch statement on w.kind. You can't read the + registers of an inferior which has exited. Use a goto in the + STOPPED_BY_WATCHPOINT code. + * infrun.c (wait_for_inferior): Reinstate + HAVE_STEPPABLE_WATCHPOINT and HAVE_CONTINUABLE_WATCHPOINT code. + +Fri May 19 06:15:40 1995 Jim Kingdon + + * utils.c, complaints.c, language.c, monitor.c, remote-array.c, + remote-mips.c, remote-os9k.c, remote-st.c: Conditionalize use of + stdarg rather than varargs on ANSI_PROTOTYPES not __STDC__; it + must match the definition of PARAMS. + +Thu May 18 15:58:46 1995 J.T. Conklin + + * utils.c (fprintf_filtered, fprintf_unfiltered, fprintfi_filtered, + printf_filtered, printf_unfiltered, printfi_filtered, query, warning, + error, fatal, fatal_dump_core): Use stdarg.h macros when compiling + with an ANSI compiler. + * complaints.c (complain): Likewise. + * language.c (type_error, range_error): Likewise. + * monitor.c (monitor_printf, monitor_printf_noecho): Likewise. + * remote-array.c (printf_monitor, debuglogs): Likewise. + * remote-mips.c (mips_error): Likewise. + * remote-os9k.c (printf_monitor): Likewise. + * remote-st.c (printf_stdebug): Likewise. + + * defs.h, complaints.h, language.h, monitor.h: Add prototypes to + match above changes. + + * printcmd.c: Remove uneeded #include . + * remote-e7000.c: Likewise. + + * f-typeprint.c (f_type_print_base): Fix typo found by above + changes. + +Wed May 17 11:21:32 1995 Jim Kingdon + + * Makefile.in (xcoffread.o): Depend on partial-stab.h. + + * xcoffsolib.c (sharedlibrary_command): New command. + * xcoffsolib.c (solib_info): Call xcoff_relocate_symtab. + * xcoffsolib.c: Miscellaneous cleanups. + + * partial-stab.h: Ignore symbol descriptor '-' (for local + variables with negative type numbers) without complaint. + + * rs6000-nat.c (vmap_ldinfo): Use bfd_stat rather than our own + local emulation thereof. Remove unused variable ostart. + +Wed May 17 15:55:53 1995 J.T. Conklin + + * Makefile.in (config.status): changed target so that + config.status --recheck is executed if configure script changes. + + * monitor.c (monitor_printf): Changed format specification in + error message to work with pre-ansi compilers. + (monitor_load_srec): reduced length of s-records from 128 to 32 + bytes so download is more reliable with the rom68k monitor. + + * rom68k-rom.c: Added trailing space to prompt string. + + * config/i386/xm-i386sco.h (HAVE_STRSTR): Removed. + * config/i386/xm-go32.h, mswin/xm.h (SYS_SIGLIST_MISSING): + Removed. + * defs.h, config/{xm-lynx.h, xm-nbsd.h}, + config/i386/{xm-i386bsd.h, xm-linux.h}, + config/m68k/xm-hp300bsd.h, config/mips/xm-irix4.h, + config/ns32k/xm-ns32km3.h, doc/gdbint.texinfo + (PSIGNAL_IN_SIGNAL_H): Removed. + +Tue May 16 13:16:06 1995 J.T. Conklin + + * Makefile.in (Makefile): Added config.status to dependency list. + + * configure.in: Added INIT-CMDS argument to AC_OUTPUT which sets + gdb_host_cpu, gdb_target_cpu and nativefile. + * configure: regenerated. + +Mon May 15 23:50:51 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_symbol): Do not relocate stBlock/scText + symbols, their value is the displacement from the procedure address. + * top.c (init_main): Add missing newlines to help strings for + `if' and `while' commands, fix help string for `show commands'. + +Mon May 15 18:37:56 1995 Stu Grossman (grossman@cygnus.com) + + * breakpoint.c: Move defaults of watchpoint related macros into + target.h. Use BP_TEMPFLAG and BP_HARDWAREFLAG instead of + constants. + * infrun.c (wait_for_inferior): Enhance comment near + STOPPED_BY_WATCHPOINT. + * target.h: Macros from breakpoint.c. + +Mon May 15 17:11:38 1995 J.T. Conklin + + * config/i386/{i386sol2.mh, i386v4.mh, ncr3000.mh}, + config/m68k/m68kv4.mh, config/mips/{irix4.mh, irix5.mh, + mipsv4.mh}, config/sparc/sun4so2.mh (INSTALL): Removed, figured + out by autoconf. + * config/apollo68v.mh (RANLIB): Removed, figured out by autoconf. + + * Makefile.in, configure.in: Converted to use autoconf + * aclocal.m4: New file, local autoconf macro definitions. + * configure: New file, generated with autoconf 2.3. + +Mon May 15 14:46:41 1995 Stan Shebs + + * remote.c (remote_kill): Add prototype. + * cpu32bug-rom.c (cpu32bug_open): Properly define as static. + * config/h8300/h8300hms.mt (TDEPFILES): Add monitor.o. + +Mon May 15 12:12:34 1995 Stu Grossman (grossman@cygnus.com) + + * sparclite/salib.c (win_ovf win_unf): Make window size constant + into a variable (__WINSIZE) so that it can be controlled via the + .h file. + * sparclite/sparclite.h: Add SL933 #ifdef to set __WINSIZE to 6 + for the 933 board. + + * infrun.c: Add #ifdef HP_OS_BUG to all references to + trap_expected_after_continue. + * (wait_for_inferior): Fix for remote watchpoints. Don't try to + insert breakpoints while target is running (this only works on + *some* native targets). This may also speed up native watchpoints + considerably. + +Sat May 13 13:55:04 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dwarfread.c (struct dwfinfo), dbxread.c (struct symloc), + mdebugread.c (struct symloc), hpread.c (struct symloc), + xcoffread.c (struct symloc): Fix inaccurate comment introduced + 20 Apr 1995. + +Sat May 13 13:34:18 1995 Jim Kingdon + + * rs6000-tdep.c (find_toc_address): Revise comment. + * symfile.c, symfile.h (init_psymbol_list): New function; + consolidate duplicated copies from os9kread.c, dbxread.c + and dwarfread.c. + * defs.h: Declare info_verbose. + * xcoffread.c: Extensive changes to support psymtabs. + +Fri May 12 13:48:41 1995 Stu Grossman (grossman@andros.cygnus.com) + + * cpu32bug-rom.c remote-est.c rom68k-rom.c: Update line_term element. + +Fri May 12 06:39:30 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * partial-stab.h: Expand comments. + +Thu May 11 19:01:37 1995 Jeff Law (law@snake.cs.utah.edu) + + * Support debugging using native MACH primitives on hppa*-*-osf*. + * configure.in: hppa*-*-osf* != hppa*-*-bsd* anymore. + * config/pa/hppaosf.mh: New file. + * config/pa/nm-hppao.h: Likewise. + * hppam3-nat.c: Likewise. + * config/pa/tm-hppao.h (PSW_SS): Define for single-stepping. + (MACHINE_CPROC_*_OFFSET): Define. + (TRACE_*): Define. + (START_INFERIOR_TRAPS_EXPECTED): Delete definition. + +Wed May 10 18:59:26 1995 Stu Grossman (grossman@andros.cygnus.com) + + * hppa-tdep.c (read_unwind_info): Cosmetic cleanup. + * (unwind_command): Clean it up and make it print things out + nicer. + * monitor.c: Add ^C handling capability (mostly ripped off from + remote.c). + * (monitor_printf): Make it check the command echo. + * (monitor_printf_noecho): Similar to above, but doesn't check + for echo. + * (monitor_stop): No longer waits for prompt. That is the job of + the caller. This makes things work much better for monitor_wait, + which waits for the prompt itself. + * (monitor_open): Deal with new monitor_stop semantics. Also, + flush input after sending init strings to get rid of junk that may + be output. Also, don't always send \r to remote. Use + monitor_ops->line_term cuz proper character isn't always \r. + * (monitor_fetch_register): Switch to completely different + algorithm to deal with lame-ass monitors which put spaces in the + middle of numbers, and prompt with a space!!!!! + * (monitor_read_memory_single): New routine to be used with + monitors that can only return one byte/short/long at a time. This + is selected via MO_GETMEM_READ_SINGLE. + * (monitor_load_srec): Use monitor_printf_noecho for sending S + records. Most targets don't echo them. + * (monitor.h): Get rid of cmd_delim. Add line_delim. + * op50n-rom.c (op50n_cmds): Fill it up. Make it work. + * w89k-rom.c: Change all eols from \r to \n. Change load_resp to + ^Q to prevent error message. + * config/pa/tm-hppa.h (CALL_DUMMY (for hppro)): Add special + instruction sequence at end to make restore_pc_queue happy. + +Wed May 10 15:59:00 1995 Torbjorn Granlund + + * remote-est.c (est_open): Make static to match prototype. + +Tue May 9 16:58:50 1995 Michael Meissner + + * configure.in: Add little endian PowerPC support. + * config/powerpc/ppcle-eabi.mt: New file for little endian PowerPC + support. + * config/powerpc/tm-ppcle-eabi.h: ditto. + +Mon May 8 12:11:38 1995 J.T. Conklin + + * nlm/configure.in (gdb_host, gdb_host_cpu, gdb_target): Removed. + These variables not used. + + * config/m68k/monitor.mt (TDEPFILES): Added cpu32bug-rom.o. + +Wed May 3 17:54:47 1995 Stan Shebs + + * monitor.c (monitor_command): Don't use PROMPT until monitor + target is known to be open. + (monitor_make_srec): Don't define size of hextab. + +Tue May 2 18:32:24 1995 Stan Shebs + + * configure.in (--enable-netrom): New configuration option. + * Makefile.in (REMOTE_OBS): Rename from REMOTE_O, append + value of NETROM_OBS. + (NETROM_OBS): New variable. + * remote-nrom.c: New file, NetROM target support. + * config/a29k/a29k-udi.mt, config/i960/vxworks960.mt: Use + REMOTE_OBS instead of REMOTE_O. + +Fri Apr 28 23:30:00 1995 Stu Grossman (grossman@cygnus.com) + + * array-rom.c (_initialize_array array_open): Move baud_rate + initialization from _initxxx to array_open to fix bug with + overriding -b command line option. + +Thu Apr 27 20:29:34 1995 Doug Evans + + * Makefile.in (RUNTEST): Fix reference of `srcdir'. + +Wed Apr 26 19:01:08 1995 Steve Chamberlain + + * remote-hms.c: Rewrite to use new monitor conventions. + +Tue Apr 25 11:27:14 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dbxread.c: Add comment explaining lowest_text_address. + Add comment regarding stringtab_global and psymtabs. + +Sat Apr 22 01:26:29 1995 Jeff Law (law@snake.cs.utah.edu) + + * config/pa/tm-hppa.h (EXTRACT_STRUCT_VALUE_ADDRESS): Fix. + + * config/pa/tm-hppa.h (EXTRACT_RETURN_VALUE): Rewrite to correctly + handle "short", "int" and small structures returned in registers. + +Fri Apr 21 12:57:53 1995 Kung Hsu + + * minsyms.c: add new function lookup_minimal_symbol_text, to look + for text symbol only. + * breakpoint.c (create_longjmp_breakpoint): call + lookup_minimal_symbol_text instead of lookup_minimal_symbol. + * symtab.h: add lookup_minimal_symbol_text prototype. + +Fri Apr 21 12:03:44 1995 Stan Shebs + + * sh-tdep.c (sh-opc.h): Don't include. + (gdbcore.h): Include. + (frame_find_saved_regs): Remove unused local. + +Thu Apr 20 10:12:21 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dwarfread.c (struct dwfinfo), dbxread.c (struct symloc), + mdebugread.c (struct symloc), hpread.c (struct symloc): Clean + up comments. + +Wed Apr 19 16:58:11 1995 Stu Grossman (grossman@andros.cygnus.com) + + * hppa-tdep.c (deposit_17): New routine to deposit 17 bit + constants into PA instructions. + * Put #ifdefs around all signal handling code. Not generally + needed for embedded boards. + * (hppa_fix_call_dummy): Parameterize offsets into call dummy to + allow different dummys to be used by this code. Use + INSTRUCTION_SIZE instead of REGISTER_SIZE for things. + Conditionalize setup of _sr4export fixup. Improve comments. + * config/pa/tm-hppa.h: Define INSTRUCTION_SIZE. Use a different + call dummy if PA_LEVEL_0 is defined. Better comments for call + dummys. Define offsets for LDIL/LDO instructions which load + function addresses. + * config/pa/tm-pro.h: Get rid of signal handling stuff. Define + PA_LEVEL_0 to disable mucking with space regs and such. + +Mon Apr 17 15:37:08 1995 Stu Grossman (grossman@andros.cygnus.com) + + * cpu32bug-rom.c monitor.h op50-rom.c remote-est.c rom68k-rom.c + w89k-rom.c: Remove loadtypes, loadprotos and baudrates. + * op50-rom.c: Fix copyrights and add load routine to op50n_cmds. + * rom68k-rom.c (_initialize_rom68k): Don't set baud rate. + * w89k-rom.c: Fix copyrights. + +Sun Apr 16 14:00:55 1995 Stu Grossman (grossman@andros.cygnus.com) + + * monitor.c: Move all xmodem stuff into xmodem.[ch]. Remove + unnecessary remoteloadprotocol and remoteloadtype support. + * (expect expect_prompt): Change names to monitor_expect and + monitor_expect_prompt. Make them global. + * (printf_monitor): Change name to monitor_printf. Make global. + * (monitor_read_memory): Flush command echo to avoid parsing + ambiguity with CPU32Bug monitor. + * (monitor_load): Remove remoteloadprotocol and remoteloadtype + support. Call target_ops->load_routine, default to + monitor_load_srec. + * (monitor_load_srec): Remove everything but S-record support. + * monitor.h (monitor_ops): Add load_routine to provide monitor + specific download capability. + * remote-est.c: Clean up copyrights and comments. + * w89k-rom.c: Use new xmodem support. + * xmodem.c xmodem.h: New files to support xmodem downloads. + * rom68k-rom.c remote-est.c: Fix copyrights, add load_routine + entry to monitor_ops. + * cpu32bug-rom.c: New file to support Moto BCC debuggers. + * config/m68k/est.mt (TDEPFILES): Add cpu32bug.o. + * config/pa/hppapro.mt (TDEPFILES): Add xmodem.o. + +Sat Apr 15 18:00:15 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * rem-multi.shar: Removed; superceded by gdbserver. + +Fri Apr 14 12:10:24 1995 Jim Kingdon + + * xcoffread.c (xcoff_sym_fns): Revise comment about merging this + with coffread.c. + + * breakpoint.c (fixup_breakpoints): Removed. + * rs6000-nat.c (vmap_symtab): Don't call fixup_breakpoints. + (vmap_ldinfo, xcoff_relocate_core): Call breakpoint_re_set. + + * coffread.c (coff_symfile_offsets): Allocate SECT_OFF_MAX + sections, not just SECT_OFF_MAX-1. + + * rs6000-nat.c (vmap_symtab), xcoffread.c: Re-do section offsets + to be indexed by SECT_OFF_* instead of xcoff section numbers. + * objfiles.c, remote.c: Remove comments regarding SECT_OFF_*. + * symtab.h: Revise comment about block_line_section. + * rs6000-nat.c (vmap_symtab): Don't relocate objfile->sections. + +Sat Apr 15 14:15:14 1995 Stan Shebs + + * mpw-make.in (init.c): Don't try to do symbolic {o} in sed + command, not allowed by some version of MPW Make. + * ser-mac.c (mac-setbaudrate): Make it actually set baud rates. + +Sat Apr 15 14:05:09 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * alpha-tdep.c (alpha_push_arguments): Fix typo (TYPE_VALUE -> + VALUE_TYPE). Do the cast for TYPE_CODE_BOOL, TYPE_CODE_CHAR, + TYPE_CODE_ENUM, and TYPE_CODE_RANGE as well as TYPE_CODE_INT. + +Sat Apr 15 14:04:32 1995 Per Bothner + + * alpha-tdep.c (alpha_push_arguments): Only cast to long for + TYPE_CODE_INT. + + +Thu Apr 13 16:17:04 1995 Rob Savoye + + * remote-array.c: New file for Array Tech LSI33k based controller + board. + +Thu Apr 13 12:23:31 1995 Kung Hsu + + * a29k-tdep.c (get_longjmp_target): Replace SWAP_TARGET_AND_HOST with + extract_address. + * remote-vxsparc.c: New file, preliminary check in, this configuration + not supported yet. + * remote-vxmips.c: ditto. + +Thu Apr 13 12:10:14 1995 Michael Meissner + + * rs6000-tdep.c (xcoff_add_toc_to_loadinfo): Don't use a prototype + to declare the function. + +Wed Apr 12 16:40:20 1995 Stan Shebs + + * monitor.h (init_monitor_ops): Declare. + * rom68k-rom.c: Clarify some comments. + (rom68k_open): Define as static, to match decl. + +Wed Apr 12 16:36:44 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.gdb: New file. + * .gdbinit: Move list-objfiles to gdb.gdb. + + * values.c (set_internalvar): Set modifiable flag of newval. + +Wed Apr 12 14:34:31 1995 Jim Kingdon + + * xcoffread.c: Call complain() rather than error() or printing a + warning. + + +Tue Apr 11 16:42:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * top.c, utils.c, defs.h: Remove error_hook. It is currently + unused and would need to hook into error_begin()/return_to_top_level(), + instead of error(), if it were to be used. + +Tue Apr 11 13:46:25 1995 Jim Kingdon + + * utils.c, defs.h (warning_begin): Renamed from warning_setup, for + consistency with error_begin. Also print warning_pre_print. + Document it better. + * utils.c (warning): Use it. + * utils.c (error_begin): Doc fix. + * rs6000-nat.c (vmap_ldinfo): If we don't find ldinfo for the + symfile_objfile, nuke it. + +Tue Apr 11 09:35:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * printcmd.c (print_address_numeric): Pass use_local to + print_longest, rather than always passing 1. + + * nlm/Makefile.in: Remove comments discussing munch. + + +Mon Apr 10 18:31:57 1995 Stan Shebs + + Merge in support for Mac MPW as a host. + (Old change descriptions retained for informational value.) + + * mpw-config.in (i386-unknown-go32): Change from aout. + (sh-hitachi-hms): New target. + * mpw-make.in (BISON): Use byacc instead of bison. + (VERSION): Bump to 4.14.1. + (*-pinsn.*): Remove mentions everywhere. + (all): Don't build MacGDB. + (gdb, SiowGDB): Depend on Version.r. + (Version.r): Generate from version info. + * main.c (main): Pass program name to START_PROGRESS, END_PROGRESS. + (main) [MPW]: Remove debugging hook. + * mac-xdep.c (debug_openp): New flag. + (mac_init): Set flag if env variable defined. + * ser-mac.c (mac_open): Clarify error message. + (mac_readchar): Call PROGRESS while looping. + (mac_write): Call sleep instead of sec_sleep. + (sec_sleep): Remove. + * source.c (openp) [MPW]: Only print debugging info if debugging. + * utils.c (query) [MPW]: Clarify that behavior is a bug. + + * mpw-make.in (init.c): Use open-brace instead of mpw-open-brace. + + * main.c, source.c: Remove hacks that replace long strings + with shorter ones, now solved portably. + + * config/m68k/xm-mpw.h (spin.h): Include. + (ALMOST_STDC): Only define if MPW_C. + * config/m68k/tm-mac.h: New file, Mac target definitions. + + * mpw-config.in (m68k-apple-macos, ppc-apple-macos, + i386-unknown-aout): New targets. + (mk.tmp): Add *DEPFILES definitions. + * mpw-make.in: Remove gC rules, clean up definitions for other + include files, bump version, fix bogus \ that should be \Option-d. + (init.c): Build correctly. + + * mpw-make.in (HFILES_NO_SRCDIR): Add somsolib.h + (ALLDEPFILES): Add somsolib.c. + (somsolib.o): Add some dependencies. + + * mpw-config.in: Use nm-empty.h if host is not target. + (xdepfiles): Add mac-xdep.c.o. + (xm_file): Remove. + * mpw-make.in: Add Fortran files. + (XDEPFILES): Remove. + + * mpw-config.in (MacSerial.h): Duplicate from standard Serial.h. + * ser-mac.c (MacSerial.h): Include instead of Serial.h. + + * mpw-make.in: Use {s} instead of {srcdir} everywhere. + (bindir, libdir): Remove extra colon. + (source.c): Compile with C instead of gC. + (c-exp.tab.c, ch-exp.tab.c, m2-exp.tab.c): Add {o}. + (install-only): Don't install MacGDB. + * source.c (openp) [MPW]: Add a debugging display. + (open_source_file) [MPW]: Use MPW basename finders. + [MPW_C]: Briefer versions of help for line and list commands. + + * mpw-make.in: Change references from paread.c to somread.c + + * mpw-make.in (VERSION): Update to 4.12.3. + (SiowGDB): New target, GDB using SIOW library. + (init-new.c): New target, attempt to generate init.c from sources. + (main.c.o, top.c.o): Put each in its own segment. + * main.c (main) [MPW]: Always call mac_init. + * utils.c (query) [MPW]: Always return "yes" if in MacGDB, output + an extra newline otherwise. + * mac-xdep.c: More comments in various places, remove junk. + (mac_init): Add tests for MPW and SIOW. + (use_wne, has_color_qd): Renamed. + (use_color_qd): New variable. + (grow_window): Only do console resizing to console window, + call resize_console_window. + (zoom_window): Call resize_console_window. + (resize_console_window, scroll_text): New functions. + (adjust_console_sizes): Always align viewrect to even multiples of + text lines. + (adjust_console_text): Always scroll by whole lines. + (hacked_vfprintf, hacked_puts, hacked_fputc, hacked_putc): Force a + recalculation of scroll positions if a newline was output. + (hacked_fflush): Similarly, for flushing. + (hacked_fgetc): New function, aborts if called in MacGDB. + * ser-mac.c (mac_readchar): Rename starttime to start_time, + remove debugging printf. + (mac_write): Sleep on first 4 writes. + (sec_sleep): New function, works like standard sleep. + * macgdb.r: Adjust positioning and contents of About box. + Set minimum size to 2000K, preferred size to 5000K. + * config/m68k/xm-mpw.h (fgetc): Define as a macro. + + * mpw-make.in (.c.o, .gc.o): Prefix segment names with gdb_. + (top.c.o, annotate.c.o): Add build rules. + * macgdb.r (SysTypes.r): Include. + ('vers'): New resource, version info. + (mFile, mEdit, mDebug): Enable all menu items. + (mDebug): Add key equivalents for continue, step, next. + (wConsole): Add zoom and close boxes to window. + * mac-xdep.c (new_console_window): New function, code taken from + mac_init. + (mac_command_loop): Use GetCaretTime for wait interval, call + do_idle on null events. + (do_idle): New function. + (zoom_window): Implement zooming. + (v_scroll_proc): New function, handles vertical scrolling. + (activate_window): Do activation of console window. + (do_menu_command): Implement items of file, edit, and debug menus. + (do_keyboard_command): Fix command extraction. + (adjust_console_sizes, adjust_console_text): New functions. + (hacked_fprintf, hacked_vfprintf, hacked_fputs, hacked_fputc, + hacked_putc): Don't call draw_console. + * ser-mac.c (mac_open): Add an error message for invalid ports. + (first_mac_write): New global. + (mac_write): Use first_mac_write to sleep on first several writes. + + * mpw-make.in (INCLUDE_CFLAGS): Add readline source dir. + (READLINE_CFLAGS, READLINE_SRC, READLINE_DIR): Uncomment. + (TSOBS): Don't compile inflow.c. + (all, install): Add MacGDB. + * main.c (main): Do Mac-specific init and command loop if a + standalone app, skip full option help message if compiling + with MPW C. + (gdb_readline): If MPW, add a newline after the (gdb) prompt. + * utils.c (_initialize_utils): If MPW, don't try to use termcap to + compute the window size. + * config/m68k/xm-mpw.h (printf, fprintf, fputs, fputc, putc, + fflush): Define as macros that expand into hacked_... versions. + (StandAlone, mac_app): Declare. + * macgdb.r (SIZE): Set the default partition to 4000K. + * mac-xdep.c (readline.h, history.h): Include. + (terminal.h): Don't include. + (mac_app): Define. + (gdb_has_a_terminal): Define Mac-specific version. + (do_keyboard_command): Simplify search for command string. + (readline): Define as gdb_readline. + Add other history/readline stubs to make main gdb link. + (hacked_fprintf, hacked_printf, hacked_vfprintf, hacked_fputs, + hacked_fputc, hacked_fflush): New functions, intercept output to + stdout and stderr, send to console window. + + * mpw-make.in (MacGDB): New target, standalone Mac-hosted gdb. + (XDEPFILES): Define. + (main.c.o): Compile with gC instead of C. + * mac-defs.h: New file, menu etc definitions shared between + C and Rez files. + * macgdb.r: New file, Rez (resource compiler) resource + definitions. + * mac-xdep.c: New file, Mac host interface code. + * config/m68k/xm-mpw.h (PATHNAME_SEPARATOR): Rename to + DIRNAME_SEPARATOR. + (PATHNAME_SEPARATOR_STRING): Remove. + (SIGQUIT, SIGHUP): Define. + (fileno, R_OK): Define. + + * mpw-config.in: New file, MPW configuration fragment. + * mpw-make.in: New file, MPW makefile fragment. + * config/m68k/xm-mpw.h: New file, MPW host definitions. + * ser-mac.c: New file, Mac serial interface. + +Mon Apr 10 16:47:57 1995 Kung Hsu + + * valprint.c (print_longest): Fix a syntax error in #ifdef + PRINTF_HAS_LONG_LONG. + + * config/mips/xm-irix5.h: turn on CC_HAS_LONG_LONG and + PRINTF_HAS_LONG_LONG. + * config/mips/tm-irix5.h: turn on FORCE_LONG_LONG. + +Sat Apr 8 02:47:45 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_symbol): Use new variable + nodebug_var_symbol_type as type of variables which don't have any + ecoff debug info associated with them. + (parse_symbol, parse_procedure): Use heuristics to determine if + functions were compiled without debugging info and change their + type to nodebug_function_symbol_type. + (_initialize_mdebugread): Initialize nodebug_*_symbol_type. + + * source.c (line_info): Clear sal.pc for `info line' without + arguments. + +Fri Apr 7 17:43:01 1995 Stu Grossman (grossman@andros.cygnus.com) + + * monitor.c: make_xmodem_packet and print_xmodem_packet go away. + send_xmodem_packet shows up to do the obvious. Lots of fixes to + xmodem downloads including resetting of block number at start of + new transfers, fix for buffer overrun problem, addition of CRC + generation code. + * (monitor_open): loadtype_str and loadproto_str now default to + first entry in monitor_ops->loadtypes. + * (monitor_wait): Lengthen register dump buf, because of verbose + Winbond monitor. + * (monitor_fetch_register): Report unimplemented registers as 0. + * (monitor_read_memory): Only do 16 byte aligned transfers + because of formatting weirdness with the Winbond monitor. Also, + ignore non-hex, non-whitespace formatting between bytes (same + monitor). + * (monitor_load): Clean up logic. + * (monitor_load_srec): Re-do xmodem support. Move lots of it + into send_xmodem_packet. + * (getacknak): Get rid of polls and timeouts. Handle CRC + requests from receiver. + * (monitor_make_srec): Efficiency improvements. Don't call + sprintf to output two digit hex numbers. + * (crcinit, docrc): New, CRC-16 support routines. + * (send_xmodem_packet): New routine to generate either CRC-16 or + checksummed xmodem packets. + + * remote-est.c (est_loadtypes), rom68k-rom.c (rom68k_loadtypes): + Reduce tables down to only the load types supported by each + monitor. + + * w89k-rom.c (w89k_supply_register): Parses output of Winbond + register dumps. + * (w89k_loadtypes, w89k_loadprotos): Reduce to just srec/xmodem. + * (w89k_cmds): Add clear all breakpoints, memory fill, and dump + registers commands. + + * config/pa/tm-hppa.h: Define lots register offsets needed by + w89k-rom.c. + + +Thu Apr 6 17:00:46 1995 Michael Meissner + + * Makefile.in (X11_INCLUDES): Define as empty. + (X11_CFLAGS): Define as including $(X11_INCLUDES). + (X11_LIB_SWITCHES): Define as empty. + (X11_LIBS): Define as -lX11. + + +Wed Apr 5 19:57:38 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mips-tdep.c (mips_print_register): Remove unused variable + our_type and call to init_type. Fixes memory leak. Reindent function. + + * mips-tdep.c (mips_print_register), findvar.c + (write_register_bytes): Make buffer char[] instead of unsigned + char[]. + +Mon Apr 3 19:28:14 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * top.c, utils.c, main.c, defs.h: Replace error_pre_print with two + variables: error_pre_print (for RETURN_ERROR) and quit_pre_print + (for RETURN_QUIT). Fixes a bug whereby typing ^C (e.g. in "maint + print sym") could output extraneous stuff. + * objfiles.c: Don't declare error_pre_print; defs.h does it. + +Mon Apr 3 13:48:28 1995 Stu Grossman (grossman@andros.cygnus.com) + + * monitor.h: Add MO_GETMEM_NEEDS_RANGE flag. + * monitor.c (monitor_read_memory): Use previously mentioned flag + to send proper format memory examine commands to the w89k monitor. + Also, try to handle bizarre format of memory dump... + + * op50-rom.c w89k-rom.c: Update to new monitor.[ch] conventions. + +Sat Apr 1 03:22:20 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (process_one_symbol) [SOFUN_ADDRESS_MAYBE_MISSING]: + Handle relocated symbol address. + * partial-stab.h, case N_SO, SOFUN_ADDRESS_MAYBE_MISSING: + Do not relocate a zero address. + +Thu Mar 30 19:46:36 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/a29k/tm-a29k.h: Nuke obsolete define CONTROL_END_ADDR; it + is nowhere used. + + * stabsread.c (read_range_type): Remove FIXME comment about + type-id (I presume this meant a number followed by = followed by a + type) versus type number; Per fixed it. + +Wed Mar 29 09:56:04 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in: sparc-*-sunos5* is same as sparc-*-solaris2*. + +Wed Mar 29 18:30:03 1995 Stan Shebs + + * remote-e7000.c (why_stop): Add new kinds of strings to expect + from the emulator. + (e7000_wait): Add interpretations for more stop reasons, + including warnings for write protect and cycle address errors. + +Wed Mar 29 17:09:29 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c monitor.h remote-est.c rom68k-rom.c: Add start of + support for interrupting target. + * monitor.c (monitor_open): Send stop command before doing + anything else. + * (monitor_load_srec): Fix record size calculation to prevent end + of segment from getting trashed. + * rom68k-rom.c: Update to latest version of struct monitor_ops. + * config/sparc/tm-sparc.h (FIX_CALL_DUMMY): Fix byte-order + problems. Makes DOS hosted function calling work. + * sparclite/crt0.s: Define _start to make COFF happy. + +Wed Mar 29 09:11:51 1995 Michael Meissner + + * defs.h (atof): Don't provide an external declaration if atof is + a macro. + +Wed Mar 29 00:01:07 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * rs6000-tdep.c (skip_prologue): Skip saving of LR and CR in + the stack frame, fix typos in `st rx,NUM(r1)' and `stu r1,NUM(r1)' + tests. + +Tue Mar 28 17:04:04 1995 Per Bothner + + * gdbtypes.c (create_range_type): If indextype has TYPE_FLAG_STUB + set, set TYPE_FLAG_TARGET_STUB. + (check_stub_type): Recalculate TYPE_LENGTH for range type. + * stabsread.c (read_range_type): If index type number is followed + by '=', back up, call read_type. and assume we have a true range. + * gdbtypes.h (TYPE_FLAG_TARGET_STUB): Update comment. + +Mon Mar 27 22:51:54 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-nat.c, irix4-nat.c, irix5-nat.c, mipsv4-nat.c, + sparc-tdep.c (supply_gregset, supply_fpregset): Fill inaccessible + registers with zero to handle recent read_register_bytes change. + * irix4-nat.c, irix5-nat.c, mipsv4-nat.c (supply_gregset, + fill_gregset): Fix handling of CAUSE_REGNUM. + * mips-nat.c (store_inferior_registers): Handle unwritable + registers when storing a single register. + * config/mips/tm-irix3.h (CAUSE_REGNUM, BADVADDR_REGNUM): + Fix definitions. + + * mdebugread.c (parse_symbol, psymtab_to_symtab_1): Clear + allocated mips_extra_func_info, if the debug info is corrupt, + the PDR to fill it in might be missing. + +Mon Mar 27 14:43:00 1995 Kung Hsu + + * vx-share/regPacket.h: a new file interfacing with vxworks. + +Sun Mar 26 13:22:47 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (bpstat_do_actions): Once we've executed the + commands, set bs->commands to NULL. + +Sat Mar 25 01:16:10 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * buildsym.c (patch_subfile_name): Update last_source_file + with the real source file name. + * dbxread.c (end_psymtab): Handle static functions in the + SOFUN_ADDRESS_MAYBE_MISSING case by passing pst->filename + to lookup_minimal_symbol. + (process_one_symbol): Ignore extra outermost context from + SunPRO cc and acc. + * stabsread.c (define_symbol): Do not complain for SunPRO + static variable encoding if STATIC_TRANSFORM_NAME is defined. + * sparc-tdep.c, config/sparc/tm-sun4sol2.h + (sunpro_static_transform_name): Renamed from + solaris_static_transform_name. + * config/sparc/tm-sun4os4.h (STATIC_TRANSFORM_NAME): + Define to sunpro_static_transform_name for acc 3.0 compiled + executables. + * procfs.c, config/alpha/nm-osf2.h (PROCFS_DONT_TRACE_FAULTS): + Renamed from PROCFS_DONT_TRACE_IFAULT, don't trace any faults + if defined. + * procfs.c (info_proc_siginfo): Cast sip->si_addr to + `unsigned long' and use `lx' format for printing it. + +Fri Mar 24 15:45:42 1995 Stu Grossman (grossman@cygnus.com) + + * configure.in: Move test for m68*-est-* before m68*-*-coff*. + * findvar.c: Move default def of CANNOT_STORE_REGISTER closer to + the beginning of the code. + * (write_register_gen): New routine. Analogous to + read_register_gen. + * (write_register_bytes): Another rewrite! Make it smarter about + not updating regs with the same value. + * monitor.c (printf_monitor readchar): Use stderr instead of + stdout to output debug info. Also cleanup readchar a little. + * (expect): Make sure that excessive responses are null + terminated. + * (monitor_open): Check for magic number in monitor_ops struct. + Allow multiple commands as init strings. Also, clear all + breakpoints. + * (monitor_resume monitor_wait): Send a command to dump all the + regs for those targets which don't do so when waking up after a + continue command. + * (monitor_wait): Handle excessive response output better. + * (monitor_write_memory): Use block fill, word, and long word + commands (if they exist) to write memory more efficiently. + * General cleanups to use flag bits instead of individual flag + words in monitor_ops struct. + * (monitor_command): Return output from command. + * (monitor_load_srec): Allocate buffer only once. Use alloca. + Wait for load response string instead of using a timeout to start + sending S-records. Fix bug where value of srec_frame shrinks. If + hashmark is set, print `-' for retransmissions. General cleanups. + * (monitor_make_srec): Get rid of S-record default type kludge. + * monitor.h: Use seperate struct for memory and register + read/write commands. Memory commands can come in byte, word, + long, and longlong forms. + * (monitor_ops): Change lots of fields. Generalize some stuff. + Put all flags into flags word. Allow init to be a list of commands. + Add command for clearing all breakpoints, block fill, dumping all + registers. + * remote-est.c: Rewrite to use new monitor conventions. + * config/m68k/est.mt (TDEPFILES): Add monitor.o. + * config/m68k/tm-est.h: Set NUM_REGS to 18. + * testsuite/gdb.base/break.exp: Lots of cleanups. Use gdb_test + more thoroughly. + +Thu Mar 23 23:20:00 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (som_solib_add): Handle case where a shared library + referenced by a core file has sections without the SEC_ALLOC bit + set (eg stabs sections). + +Thu Mar 23 15:07:08 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * breakpoint.c (bpstat_do_actions): For each element in the bpstat + chain, do all the commands regardless of whether they run the + inferior. + +Wed Mar 22 19:17:06 1995 Doug Evans + + * mem-break.c (LITTLE_BREAKPOINT, BIG_BREAKPOINT): Define as + BREAKPOINT if mono-endian. + (break_insn): Deleted. + (big_break_insn, little_break_insn): Define. + (memory_insert_breakpoint): Handle bi-endian cpus. + (BREAKPOINT_LEN): Define. + (memory_remove_breakpoint): Use it. + (memory_breakpoint_size): Likewise. + +Tue Mar 21 17:03:17 1995 Kung Hsu + + * sparc-stub.c: add nop after 'bg good_wim'. + * sparcl-stub.c: ditto. + +Tue Mar 21 13:34:12 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (handle_command): Don't print TARGET_SIGNAL_0, + TARGET_SIGNAL_UNKNOWN, or TARGET_SIGNAL_DEFAULT. + +Mon Mar 20 10:09:59 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppab-nat.c (store_inferior_registers): Sync with HPUX version. + +Mon Mar 20 07:34:48 1995 Stu Grossman (grossman@cygnus.com) + + * hppah-nat.c (store_inferior_registers): Move check for + CANNOT_STORE_REGISTER to a better place. Fixes ptrace I/O errors + found by test suite during function calls, which attempts to write + unwritable registers. + +Sat Mar 18 02:02:24 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mdebugread.c (parse_symbol): If finishing a function without + known parameter type info, set that from parameter symbols. + Remove commented-out add_param_to_type support. + +Thu Mar 16 16:38:03 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (process_linenos): Make sure filename we pass to + start_subfile will cause deduce_language_from_filename to return + the correct thing. Reindent function to GNU standards. + +Thu Mar 16 15:54:00 1995 J.T. Conklin + + * nlm/gdbserve.c (handle_exception): #if out call to StopBell, + as it is not available on NetWare 3 or PIN. + * nlm/ppc.c (StopBell): Removed. + +Thu Mar 16 12:14:41 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (read_xcoff_symtab): When creating a dummy parameter + inferred from the traceback tags, give its type the name + "". + + * stabsread.c (rs6000_builtin_type): Recognize types -31 to -34. + +Wed Mar 15 15:09:29 1995 Stu Grossman (grossman@cygnus.com) + + * findvar.c (read_register_bytes write_register_bytes): Make + these routines much smarter about updating registers from the + target, only doing so when absolutely necessary. This really + speeds up register modification on some remote targets. + + * monitor.c: More cleanups. Get rid of monitor_load_ascii_srec. + BFD makes this unnecessary. Lots of debugging speedups. + * (expect): NULL terminate return string. + * (monitor_open monitor_supply_register parse_register_dump + monitor_wait monitor_fetch_register): Switch to using GNU regexp + library to parse multi-register displays. + * (monitor_read_memory): Read multiple bytes (up to 16) at once. + * (monitor_create_inferior): Call clear_proceed_status to make run + command notice first breakpoint. + * (monitor_load): Clean up. Reset inferior_pid, set pc to start + address and reset symbol table stuff to make loads put things into + a fresh state. + * (monitor_load_srec): Lower sleep time to 1 second. + + * monitor.h (struct monitor_ops): Add register_pattern and + supply_register to monitor_ops. + + * rom68k-rom.c: Add new support for handling register dumps. + * config/m68k/tm-m68k.h: Define D0_REGNUM and A0_REGNUM for register + dump handling. + +Wed Mar 15 15:18:27 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * utils.c, defs.h (putchar_unfiltered, fputc_unfiltered): Make + argument be an int, not a char. Using a prototype followed by an + old-style function definition in a case where an argument is + widened is a GCC-ism not supported by the native AIX compiler. + +Wed Mar 15 12:22:35 1995 J.T. Conklin + + * nlmstub.def: Removed, this was moved to nlm/gdbserve.def + long ago. + + * configure.in (alpha-*-netware*): Removed configuration. + * config/alpha/{alpha-nw.mt, gdbserve.mt, tm-alphanw.h}: Removed. + * nlm/{README-ALPHA-NETWARE, aio.h, alpha-io.S, alpha-regdef.h, + alpha.c, alpha.h, altdebug.h}: Removed. + + * nlm/gdbserve.c (main): Add support for processing BOARD= + argument, deprecate NODE=. + +Wed Mar 15 10:58:26 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * c-exp.y (yylex): Make an empty character constant an error. + +Tue Mar 14 15:00:54 1995 Per Bothner + + * valops.c (value_arg_coerce): Do possible value_coerce_array + before determining type argument to value_cast. + +Tue Mar 14 10:41:41 1995 Kung Hsu + + * remote-es.c: Replace ignore with 0. + +Tue Mar 14 05:52:36 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (value_repeat), eval.c (evaluate_subexp_standard): + If VALUE_REPEATED is already set, just error out. + + * valops.c (value_cast, value_slice), parse.c (follow_types): Add + FIXME-type-allocation comments. + + * gdbtypes.h (struct type): Fix comment about what units the + TYPE_LENGTH is in. + +Mon Mar 13 18:27:25 1995 Stan Shebs + + * ch-valprint.c (annotate.h): Include. + * eval.c (evaluate_subexp_standard): Remove unused variable. + (calc_f77_array_dims): Add parens to expression. + * f-exp.y (yylex): Add parens to expression, remove unused label. + * f-lang.h (calc_f77_array_dims): Declare. + * f-valprint.c (f_val_print): Remove unused variables. + +Mon Mar 13 15:25:47 1995 Jim Kingdon + + * alpha-tdep.c (find_proc_desc): If pdr.framereg field is -1, don't + use the PDR, just examine prologues instead. + + +Fri Mar 10 02:49:40 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + Fix problems with infinite recursion when printing a class + that contains a static instance of the class. + * cp-valprint.c (dont_print_vb_obstack): Renamed from + dont_print_obstack, made static. + (dont_print_statmem_obstack): New obstack, controls printing + of static member classes. + (_initialize_cp_valprint): Initialize it. + (cp_print_static_field): New function, handles printing of + static members. + (cp_print_value_fields): New parameter dont_print_statmem to + handle recursive printing of static member classes, use + cp_print_static_field to handle printing of static members. + * c-valprint.c (cp_print_value_fields): Update prototype and + call to include additional dont_print_statmem parameter. + * c-valprint.c, f-valprint.c (dont_print_obstack): Remove unused + extern declaration. + + * alpha-tdep.c, findvar.c, infptrace.c: Include . + + * config/alpha/tm-alpha.h (FRAME_FIND_SAVED_REGS): Call + alpha_find_saved_regs if fi->saved_regs is still NULL. + + * elfread.c (elf_symtab_read): Ensure that the filename field + of a minsym is nonempty. Ignore solib trampoline symbols from + the main symbol table, they might have a bogus value. + + * procfs.c (set_proc_siginfo), config/alpha/alpha-osf2.mh: + Fix typos in comments. + +Thu Mar 9 17:19:47 1995 Jim Kingdon + + * mdebugread.c (parse_symbol, psymtab_to_symtab_1): Initialize + pdr.framereg field of MIPS_EFI_SYMBOL_NAME symbol to -1. That way + we know whether the PDR ever got set. + * mips-tdep.c (find_proc_desc): If pdr.framereg field is -1, don't + use the PDR, just examine prologues instead. + +Wed Mar 8 23:35:10 1995 Jeff Law (law@snake.cs.utah.edu) + + * somsolib.c (som_solib_section_offsets): Get offset of text + section right. + +Wed Mar 8 16:12:21 1995 Stu Grossman (grossman@cygnus.com) + + + * source.c (forward_search_command reverse_search_command): Set + convenience variable $_ to be the line # of the match. + * symtab.c (decode_line_1): Allow convenience variables to be + used in line specs (for breakpoints and such). + +Wed Mar 8 12:51:00 1995 Stan Shebs + + * Makefile.in (VERSION): Bump to 4.14.1. + * NEWS, README: Update for 4.14. + * i386v-nat.c (i386_insert_aligned_watchpoint): Fix declaration. + (i386_insert_nonaligned_watchpoint): Call aligned instead of + generic watchpoint insertion. + +Tue Mar 7 19:26:10 1995 Per Bothner + + * valops.c (value_slice): Do COERCE_VARYING_ARRAY. + +Tue Mar 7 00:23:47 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c, array-rom.c, monitor.h, rom68k-rom.c: Move target_ops + into monitor.c. + * monitor.c (monitor_create_inferior): Allow run command to start + program. + + * monitor.c (monitor_load): Set PC to start address when done + loading. + + * array-rom.c, monitor.h, rom68k-rom.c: Clean up target_ops. + Remove ref to monitor_create_inferior. + + * monitor.c: More general cleanups. Add prototypes, remove + unused routines. Fix bug with wrong number of args to error(). + + * main.c (main): Don't start up GUI when running under gdb mode + in emacs. + + * Makefile.in: Add rules for monitor.o and rom68k-rom.o to make + Sun make (with VPATH) work... + + * monitor.c, monitor.h, rom68k-rom.c: Serious cleanup to make IDP + (rom68k) target work right. + * array-rom.c, op50-rom.c, w89k-rom.c: Partial updates to new + monitor.c interface. More work needs to be done here. + * config/m68k/tm-monitor.h: Change DECR_PC_AFTER_BREAK to 0 to + match the IDP monitor. Also, set NUM_REGS to 18 cuz there's no + floating-point for this card. + + * serial.h, ser-go32.c, ser-go32-para.c, ser-mac.c, ser-tcp.c, + ser-unix.c: Add SERIAL_SETSTOPBITS to set the number of stopbits + (needed for IDP board?!?!?). + + * defs.h, utils.c, remote-hms.c, remote-pa.c, remote.c: Fix defs + and usage of fputc_unfiltered and putchar_unfiltered. Eliminate + putc_unfiltered (it's superfluous). + + * command.h, command.c, top.c: Add var_enum command type. It's + like var_string but allows only only one of the specified strings. + +Mon Mar 6 15:03:59 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (value_cast): Don't use backslash newline--pre-ANSI + compilers (such as SunOS4 /bin/cc) don't generally support it + except in some contexts. + +Fri Mar 3 17:42:48 1995 Per Bothner + + * valops.c (value_cast): Check for cast to array type *before* + we coerce array to pointer (in case arg2 is already array). + + * valops.c (call_function_by_hand): Set using_gcc to 2 if using + gcc2. Needed for REG_STRUCT_HAS_ADDR to work on sparc. + Also check REG_STRUCT_HAS_ADDR for union, array and string types. + + * valops.c (call_function_by_hand): Re-arrange code for pushing + paramaters on the stack so we can do better STACK_ALIGN. + + * valops.c (call_function_by_hand): Call error if the number + of arguments is fewer than parameter types in function type. + +Fri Mar 3 17:13:05 1995 Doug Evans + + * sparc-tdep.c (sparc_extract_struct_value_address): Move + sparc64 support to here. + (sparc64_extract_struct_value_address): Deleted. + (dump_ccreg): Add a prototype so long long arg -> int. + * sparc/tm-sp64.h (USE_STRUCT_CONVENTION): Define. + (EXTRACT_STRUCT_VALUE_ADDRESS): Delete. + +Fri Mar 3 15:12:12 1995 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hpread_record_lines): New argument "offset". All + callers changed. Use it to handle dynamic address relocation. + (hpread_build_psymtabs): Adjust texthigh as we read each function + debug symbol. Fix computation of texthigh. + (hpread_read_subrange_type): Work around macro bugs in HP's + compilers. + (hpread_process_one_debug_symbol): Correctly map source lines. + + * somread.c (check_strange_names): Filter names emitted by the HP + compiler when generating PIC code. + + * valops.c (value_struct_elt_for_reference): Work around macro + bugs in HP's compilers. + * c-exp.y (block): Likewise. + +Fri Mar 3 12:27:28 1995 Jim Kingdon + + * rs6000-tdep.c (push_dummy_frame): Fix order of arguments to + store_address. + + * utils.c [_AIX]: Include stddef.h instead of #defining size_t. + +Fri Mar 3 12:33:24 1995 Michael Meissner + + * rs6000-tdep.c (skip_prologue): Skip multiple stores of the saved + registers that GCC emits on the PowerPC by default in addition to + the store multiple instruction used on the Power series. + +Fri Mar 3 00:54:58 1995 Doug Evans + + * sparc-tdep.c (decode_asi): New function. + (sparc_print_register_hook): Pretty print more v9 registers. + * sparc/tm-sp64.h (REGISTER_NAMES): Fix some typos. + +Thu Mar 2 22:20:22 1995 Doug Evans + + * dwarfread.c (struct dieinfo): Use CORE_ADDR for at_{low,high}_pc. + (target_to_host): Change result type to CORE_ADDR. + +Thu Mar 2 15:13:04 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * rs6000-tdep.c: Fix byte-swapping sins. + +Thu Mar 2 16:48:45 1995 Michael Meissner + + * rs6000-tdep.c (branch_dest): Minor code cleanup, don't share + code between branch unconditional and branch conditional cases. + +Wed Mar 1 09:41:26 1995 Doug Evans + + Various changes for sparc64. + * sparc-tdep.c (NUM_SPARC_FPREGS): Define. + (SPARC_INTREG_SIZE): Define. + (*): Use SPARC_INTREG_SIZE instead of REGISTER_RAW_SIZE (intreg) + where appropriate. + (enum branch_type): New value `done_retry'. + (isbranch): Renamed from isannulled. All callers changed. + Support new sparc64 branch insns. + (single_step): Handle done_retry. + (sparc_extract_struct_value_address): Don't assume 4 byte regs. + (get_saved_register): Likewise. + (sparc_push_dummy_frame): Likewise. + (sparc_frame_find_saved_regs): Likewise. + (sparc_pop_frame): Likewise. Don't refer to FPS_REGNUM, CPS_REGNUM, + or PS_REGNUM if not sparc64. sparc64 has 64 fp regs. + (sparc64_extract_struct_value_address): New function. + (dump_ccreg, sparc_print_register_hook): Likewise. + * sp64-tdep.c: Deleted. + * sparc/tm-sp64.h (GDB_TARGET_IS_SPARC64): Define. + (NUM_REGS): Reduce by 2, cle/tle are in the pstate reg. + (CC_HAS_LONG_LONG): Define. + (REGISTER_NAMES): Delete cle/tle and reorganize. + (PS_REGNUM, FPS_REGNUM, CPS_REGNUM): Delete, they're ifdef'd out of + sparc-tdep.c now. + (REGISTER_BYTES): Update. + (REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW): Delete. + (EXTRACT_RETURN_VALUE): Delete. Use definition in tm-sparc.h. + (NO_SINGLE_STEP): Likewise. + * sparc/tm-sparc.h (EXTRACT_VALUE_RETURN): Don't assume 4 byte regs. + * sparc/sp64.mt: Move simulator support ... + * sparc/sp64sim.mt: ... to here. + +Wed Mar 1 13:14:42 1995 Kung Hsu + + * remote-vx960.c: new file for target specific register packaging. + * remote-vx68.c: ditto. + * config/i960/vxworks960.mt: add remote-vx960.o. + * config/m68k/vxworks68.mt: add remote-vx68.o. + +Wed Mar 1 13:42:49 1995 Michael Meissner + + * remote.c (remote_wait): Make calls to strtol be type correct by + passing the address of a char * pointer instead of an unsigned + char *. + + * rs6000-tdep.c (push_dummy_frame): Cast sp to char * when calling + write_memory to make things type correct. + +Wed Mar 1 12:17:31 1995 Michael Meissner + + * ch-exp.y, c-exp.y, f-exp.y, m2-exp.y (yy defines): Support the + standard Linux yacc by adding more names to be redefined with a + prefix. + +Tue Feb 28 22:55:47 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * hppa-tdep.c (pa_print_registers), monitor.c: Use + extract_unsigned_integer and friends, not SWAP_TARGET_AND_HOST. + * defs.h, findvar.c: Move SWAP_TARGET_AND_HOST back to findvar.c. + Rename it to SWAP_FLOATING to make it clear it is no longer for + integers. + +Tue Feb 28 14:38:39 1995 Kung Hsu + + * defs.h (SWAP_TARGET_AND_HOST): check endianess at runtime not + compile time. + + + * vx-share/ptrace.h: merge in WRS new ptrace requests. + + * defs.h: fix a syntax error. + + * a29k-tdep.c (get_longjmp_target): add this function, from WRS. + * remote-vx.c: move read_register and write_register out to + target specific files. + * remote-vx29k.c (get_fp_contnets): add this function, from WRS. + + * defs.h: define SWAP_TARGET_AND_HOST macro. + * findvar.c, monitor.c, hppa-tdep.c: remove definition of + SWAP_TARGET_AND_HOST. + +Tue Feb 28 08:31:40 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * alpha-tdep.c (find_proc_desc): Only attempt to set + PROC_LOCALOFF (found_heuristic) if found_heuristic is non-NULL. + +Mon Feb 27 11:56:32 1995 Stan Shebs + + * monitor.c: General gcc -Wall lint cleanup and reformat. + (monitor_command): If no args, send an empty command. + +Thu Feb 23 21:07:25 1995 Stu Grossman (grossman@cygnus.com) + + * monitor.c (monitor_load_ascii_srec): Add a one second sleep + after send LOAD_CMD to prevent loss of first S-record. + +Tue Feb 21 20:48:42 1995 Per Bothner + + * valops.c (call_function_by_hand): Set using_gcc to 2 if gcc-2. + Call error if too few arguments. + If REG_STRUCT_HAS_ADDR (structs passed by invisible reference), + copy and convert to reference *before* we calculate alignment. + Also, make sure structs allocated for return values and invisible + reference don't violate STACK_ALIGN. + +Tue Feb 21 23:29:59 1995 Per Bothner + + * ch-exp.y (expression_conversion): Recognize 'ARRAY () TYPE (EXPR)' + (same as C's '(TYPE[])EXPR') + +Tue Feb 21 11:47:26 1995 Stan Shebs + + * top.c (print_gdb_version): Update the year. + +Sun Feb 19 14:31:57 1995 Jim Kingdon + + * Makefile.in (CC_FOR_TARGET, CXX_FOR_TARGET): Look for newlib in + `..' not in `../..'. + +Sun Feb 19 11:05:28 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * procfs.c (unconditionally_kill_inferior): Don't issue a PIOCKILL + in addition to a PIOCSSIG to kill the inferior. + +Thu Feb 16 15:06:12 1995 Per Bothner + + * parse.c (follow_types): Given (TYPE[]) (i.e. with no length), + create a 0-length array type, and set BOUND_CANNOT_BE_DETERMINED. + * valops.c (value_cast): If a cast like (TYPE[])VALUE (i.e. array + of unknown length) use sizeof(VALUE)/sizeof(TYPE) as the length. + * c-typeprint.c (c_type_print_varspec_suffix): If array length + is 0, print it, but not if upper_bound is BOUND_CANNOT_BE_DETERMINED. + +Thu Feb 16 16:06:50 1995 Michael Meissner + + * dcache.c (insque, remque): Rewrite Linux support. + +Wed Feb 15 12:33:20 1995 Michael Meissner + + * config/powerpc/tm-ppc-eabi.h (TEXT_SEGMENT_BASE): Define as 1. + + * dcache.c (insque, remque): If compiling in standard C on Linux, + protect insque and remque with macros to cast the pointer + arguments to the proper type. + +Tue Feb 14 17:16:41 1995 Stu Grossman (grossman@cygnus.com) + + * annotate.c, breakpoint.c, defs.h, top.c: Replace + enable/disable_breakpoint_hook with modify_breakpoint_hook. + +Tue Feb 14 16:58:07 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * expression.h: Move declaration of evaluate_subexp_with_coercion + from here... + * value.h: ...to here. + * expression.h: Don't include value.h + +Tue Feb 14 11:46:07 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * expression.h: Move include of value.h until after declaration of + enum exp_opcode. + +Sun Feb 12 13:47:30 1995 Stan Shebs + + * remote-e7000.c: Comprehensive cleanup; removal of dead code, + simplify code, declare things, format to standards. + (inferior.h, value.h, command.h, remote-utils.h): Include. + (e7000_login): Rename to e7000_login_command. + (e7000_ftp): Rename to e7000_ftp_command. + (e7000_drain): Rename to e7000_drain_command. + + * irix5-nat.c (string.h): Include near beginning of file. + +Sun Feb 12 12:36:38 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * valops.c (value_arg_coerce): Use VALUE_TYPE not SYMBOL_TYPE on + arg, it is a value not a symbol. + + gcc -Wall lint: + * eval.c: Move declaration of evaluate_subexp_with_coercion from here.. + * expression.h: ..to here. + * expression.h: Include value.h. + * ch-lang.c (evaluate_subexp_chill): Add default case in switch. + +Sun Feb 12 11:03:47 1995 Per Bothner + + * language.h (struct language_defn): New field evaluate_exp. + * c-lang.c (c_language_defn, cplus_language_defn, asm_langauge_defn), + f-lang.c (f_language_defn), language.c (unknown_language_defn, + auto_language_defn, local_language_defn), m2-lang.c (m2_language_defn): + Set evaluate_exp to evaluate_subexp_standard. + * ch-lang.c (evaluate_subexp_chill): New function. Chill-specific + support for MULTI_SUBSCRIPT. + (chill_language_defn): Set evaluate_exp to evaluate_subexp_chill. + * eval.c (enum noside): Move from here .... + * expression.h (enum noside): ... to here. + (evaluate_subexp_standard): New prototype. + * eval.c (evaluate_subexp): Renamed to evaluate_subexp_standard. + Removed lo-longer-needed test for chill_varying_type. + (evaluate_subexp): New. Calls exp->language_defn->evaluate_exp. + + * ch-exp.y (maybe_expression_list): New non-terminal. + (primitive_value): Allow empty parameter list. + +Sun Feb 12 10:02:16 1995 Per Bothner + + * buildsym.c (finish_block): If finishing a function without known + parameter type info, set that from parameter symbols. + * c-typeprint.c (c_type_print_varspec_suffix): For TYPE_CODE_FUNC, + print parameter types, if available. + * ch-typeprint.c (chill_type_print_base): Likewise. + + * gdbtypes.h (struct type): Remove function type field. + (TYPE_FUNCTION_TYPE): Remove macro. We can't as simply re-use + function types now that we're also storing parameter types. + And the payoff is much less. + * gdbtypes.c (make_function_type): Don't use/set TYPE_FUNCTION_TYPE. + (recursive_dump_type): Don't print TYPE_FUNCTION_TYPE. + * dwarfread.c (read_subroutine_type): Don't set TYPE_FUNCTION_TYPE. + + * valops.c (value_arg_coerce): Now takes param_type argument. + (call_function_by_hand): Convert arguments with value_arg_coerce + early, and overwrite original args with converted args. + No longer need multiple calls to value_arg_coerce. + (value_arg_push): Removed. + * hppa-tdep.c (hppa_push_arguments): No longer call value_arg_coerce. + * mips-tdep.c (mips_push_arguments): Likewise. + * alpha-tdep.c (alpha_push_arguments): Likewise. + * rs6000-tdep.c (push_arguments, ran_out_of_registers_for_arguments): + Likewise. + * value.h (value_arg_coerce): Remove declaration. (It's now static.) + + * valops.c (value_cast): Do COERCE_VARYING_ARRAY after COERCE_REF. + + * symtab.c (add_param_to_type): Remove (commented-out) function, + since that functionality has been re-written. + * coffread.c: Remove commented-out add_param_to_type support. + * mdebugread.c (parse_symbol): Likewise. + * stabsread.c (define_symbol): Likewise. + +Sun Feb 12 09:03:47 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * buildsym.c (start_subfile): Set language for f2c like for cfront. + +Thu Feb 9 20:20:11 1995 Rob Savoye + + * op50n-rom.c: Add the control registers. + +Thu Feb 9 15:46:39 1995 Stan Shebs + + * Makefile.in (CLIBS): Add $(LIBIBERTY) before, in addition to + after, any host/target/native libraries. + * dcache.c (insque, remque): Remove declarations. + * gdbtypes.h (type_code): Remove trailing comma. + + From Peter Schauer: + * xcoffread.c (read_xcoff_symtab) [C_HIDEXT]: Move #ifdef + STATIC_NODEBUG_VARS inside case. + +Thu Feb 9 07:43:41 1995 Jim Kingdon + + * config/sparc/tm-sun4sol2.h: Define STATIC_TRANSFORM_NAME. + * partial-stab.h: Call it. + * stabsread.c (define_symbol) [STATIC_TRANSFORM_NAME]: Call + STATIC_TRANSFORM_NAME to get the name and use minimal symbols to + get the address. + * sparc-tdep.c (solaris_static_transform_name): New function. + +Thu Feb 9 12:09:09 1995 Jeff Law (law@snake.cs.utah.edu) + + * somread.c (som_symtab_read): Handle dynamic relocation for both + text and data symbols. + (som_symfile_offsets): If objfile is a shared library, then get + text and data offsets from the shared library structures. + * somsolib.c (som_solib_add): Copy the bfd pointer from the + objfile rather than reopening the file again. + (som_solib_section_offsets): New function. + * somsolib.h (som_solib_section_offsets): Declare. + +Wed Feb 8 20:32:18 1995 Jim Kingdon + + * config/sparc/tm-sun4sol2.h, dbxread.c: Rename + N_SO_ADDRESS_MAYBE_MISSING to SOFUN_ADDRESS_MAYBE_MISSING. + * symtab.h (minimal_symbol) [SOFUN_ADDRESS_MAYBE_MISSING]: Add + filename field. + * elfread.c (record_minimal_symbol_and_info), + minsyms.c, symtab.h (prim_record_minimal_symbol_and_info): Return + newly created symbol. + * elfread.c (elf_symtab_read) [SOFUN_ADDRESS_MAYBE_MISSING]: + Set filename field of minimal symbol. + * symmisc.c (dump_msymbols) [SOFUN_ADDRESS_MAYBE_MISSING]: + Print filename field. + * minsyms.c, symtab.h (lookup_minimal_symbol): New arg sfile. + * symm-tdep.c, somsolib.c, hppa-tdep.c, c-exp.y, f-exp.y, + m2-exp.y, nindy-tdep.c, m3-nat.c, irix5-nat.c, hpread.c, + os9kread.c, breakpoint.c, alpha-tdep.c, valops.c, symtab.c, + printcmd.c, dbxread.c: Change callers to pass NULL for sfile. + * dbxread.c (process_one_symbol) [SOFUN_ADDRESS_MAYBE_MISSING]: + Find address of function from minimal symbols. + * partial-stab.h, case 'f', 'F': Call find_stab_function_addr + instead of getting pst->textlow from the stab. + * minsyms.c (find_stab_function_addr): New function. + +Wed Feb 8 19:19:56 1995 Rob Savoye + + * monitor.c: Fix so all the output shows up in the GUI command + window. + +Mon Feb 6 18:50:59 1995 Stan Shebs + + * i386-tdep.c (_initialize_i386_tdep): Put void decl on separate + line, so init.c generation works correctly. + +Mon Feb 6 14:44:36 1995 Rob Savoye + + * config/mips/idt.mt: Add support for the lsi33k target. + * config/sparc/sun4sol2.mh: Add support for ser-tcp. + * array-rom.c: Finish the rest of the support commands needed by + GDB. + * mips-tdep.c: Add LSI33k register names and processor type. + +Sat Feb 4 13:29:52 1995 Stan Shebs + + * config/m68k/est.mt (TDEPFILES): Remove m68k-pinsn.o. + +Fri Feb 3 16:47:31 1995 Kung Hsu + + * ser-go32-para.c (dos_read): fix syntax errors. + +Fri Feb 3 11:19:20 1995 Stu Grossman (grossman@cygnus.com) + + * core.c (dis_asm_read_memory), defs.h, top.c: Get rid of + dis_asm_read_memory_hook. We can now call the disassemblers + directly and have no need for this hook anymore. + * defs.h, printcmd.c: Make print_insn be static. + + * ser-go32.c (dos_comisr): Make this 8 bit clean. + * (dos_open dos_close): Allow multiple opens to the same device. + Use a ref count to prevent unwanted deallocations. + * sparcl-tdep.c: Put #ifdefs around all socket stuff to make GO32 + happy. + * (sparclite_ops): Switch to download_stratum. + * target.h (enum strata): Move download_stratum before + process_stratum so that executable targets get pushed on top of + download targets. + +Thu Feb 2 19:02:45 1995 Rob Savoye + + * array-rom.c: Remove the non GDB remote protocol config stuff. + + * monitor.c: All reading/writing functions for memory and + registers work. + +Thu Feb 2 16:11:04 1995 Kung Hsu + + * ser-go32-para.c: new file for go32 parallel port communication. + +Thu Feb 2 13:58:40 1995 Stan Shebs + + * Makefile.in (VERSION): Bump to 4.13.2. + +Thu Feb 2 07:27:56 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + Fix compiler warnings: + * remote-e7000.c (printf_e7000debug): Rename to puts_e7000debug + and have the caller do the sprintf. Saves us from varargs hell. + (normal): Define before use. + * remote-e7000.c: Reindent a few things. + +Wed Feb 1 21:16:42 1995 Per Bothner + + * f-typeprint.c (f_type_print_varspec_suffix): Print array index + ranges in reverse order. + * f-valprint.c (f77_create_arrayprint_offset_tbl): Fix calculation. + + * eval.c (evaluate_subscript): Don't call value_subscript, since + it adjusts for lower bound and enforces ranges. + + * expression.h (exp_code): Remove MULTI_F77_SUBSCRIPT, OP_F77_SUBSTR. + * eval.c, parse.c: Removed uses of removed opcodes. + * eval.c (evaluate_subexp): Clean up handling of + OP_UNDETERMINED_ARGLIST (no backtracking, more general). + + * f-valprint.c (f_val_print): Print TYPE_CODE_STRING using + LA_PRINT_STRING, and not val_print_string (which reads from inferior). + + * ch-lang.c (chill_is_varying_struct), ch-lang.h: Remve function + duplicate function made redundant by chill_varying_type. + + Re-write of f77 string and complex number support: + + * language.h (struct language_defn): New fields string_lower_bound + and string_char_type. + * c-lang.c (c_language_defn, cplus_language_defn, asm_language_defn), + language.c (unknown_language_defn, auto_language_defn, + local_language_defn), m2-lang.c (m2_language_defn), f-lang.c + (f_language_defn), ch-lang.c (chill_language_defn): Set new fields. + * gdbtypes.c (create_string_type): Use new string_char_type field. + * valops.c (value_string): Use new string_lower_bound field. + + * defs.h (TARGET_COMPLEX_BIT, TARGET_DOUBLE_COMPLEX_BIT): Removed. + * f-lang.c (f_create_fundamental_type, _initialize_f_language), + m2-lang.c (m2_create_fundamental_type), + gdbtypes.c (_initialize_gdbtypes): Set TYPE_TARGET_TYPE of complex + types. Set their TYPE_CODEs to TYPE_CODE_COMPLEX. + * mdebugread.c (mdebug_type_complex, mdebug_type_double_complex): + Removed. Use builtin_type_complex and builtin_type_double_complex. + + * gdbtypes.h (enum type_code): Removed TYPE_CODE_LITERAL_STRING + and TYPE_CODE_LITERAL_COMPLEX. + * c-typeprint.c, f-typeprint.c, f-valprint.c, eval.c: Removed uses of + TYPE_CODE_LITERAL_STRING and TYPE_CODE_LITERAL_COMPLEX. + * gdbtypes.c, gdbtypes.h (f77_create_literal_complex_type, + f77_create_literal_string_type): Removed. + * value.h (VALUE_LITERAL_DATA, VALUE_SUBSTRING_MEMADDR, + VALUE_SUBSTRING_MYADDR): Removed. + + * expression.h (enum exp_opcode): Rename OP_F77_LITERAL_COMPLEX to + OP_COMPLEX. + * parse.c: Update accordingly. + + * f-valprint.c (f77_print_cmplx): Removed. + (f_val_print case TYPE_CODE_COMPLEX): Re-write to use print_floating. + + * f-exp.y (STRING_LITERAL): Use OP_STRING instead of OP_ARRAY. + * eval.c (evaluate_subexp): For case OP_ARRAY, don't call + f77_value_literal_string. + * valops.c, value.h (f77_value_literal_string, f77_value_substring, + f77_assign_from_literal_string, f77_assign_from_literal_complex): + Removed. + (value_assign): No longer need to handle literal types. + * valops.c (f77_value_literal_complex), value.h: Re-written and + renamed to value_literal_complex. Last arg is now a (complex) type. + * valops.c (f77_cast_into_complex): Re-written and renamed to + cast_into_complex. + * eval.c (evaluate_subexp): Update accordingly. + + * ch-valprint.c (chill_val_print): On TYPE_CODE_STRING, don't + print address for non-'s'-formats. + * ch-typeprint.c, ch-valprint.c: Use chill_varying_type instead + of chill_is_varying_struct. + +Wed Feb 1 13:27:33 1995 Stan Shebs + + gcc -Wall lint. + * alpha-tdep.c (alpha_in_lenient_prologue): Comment out. + (after_prologue): Remove unused local b. + * procfs.c (thread.h): Include. + (pr_flag_table, pr_why_table, faults_table, siginfo_table): Use + nested braces in initializer. + * top.c (initialize_targets, initialize_utils): Declare. + (locate_arg, insert_args): Add parens around tested assignments. + * remote-utils.c (sr_scan_args): Remove decl of strtol. + * remote.c (thread.h): Include. + (remote_wait): Remove unused local p2. + * sparc-tdep.c (fill_gregset, fill_fpregset): Remove decls of + registers array. + + defs.h (stdlib.h): Include. + (exit, perror, atoi, qsort, memcpy, memcmp): Don't declare. + (fclose, atof, malloc, realloc, free, strchr, strrchr, strstr, + strtok, strerror): Don't specify parameter types in declaration. + +Wed Feb 1 12:23:57 1995 Per Bothner + + * ch-exp.y (value_string_element, string_primitive_value, + start_element, left_element, right_element, slice_size, + lower_element, upper_element, first_element): Removed. + (value_string_slice, value_array_slice): Replaced by ... + (slice): New non-terminal, with working slice support. + (primitive_value_lparen, rparen): New non-terminals. + (maybe_tuple_elements): New non-terminal, to allow empty tuples. + (idtokentab): Added "up". + + * value.h (COERCE_VARYING_ARRAY): New macro. + * valarith.c (value_subscript): Use it. + * valops.c (value_cast): Likewise. Also, do nothing if already + correct type, and allow converting from/to range to/from scalar. + + * valops.c, value.h (varying_to_slice, value_slice): New functions. + * eval.c (OP_ARRAY): Add cast for array element. + * expression.h (TERNOP_SLICE, TERNOP_SLICE_COUNT): New exp_opcodes. + * valops.c (chill_varying_type): Moved function frp, here ... + * gdbtypes.c (chill_varying_type), gdbtypes.h: ... to here. + * parse.c (length_of_subexp, prefixify_subexp): Add support + for TERNOP_SLICE, TERNOP_SLICE_COUNT. + * expprint.c (print_subexp, dump_expression): Likewise. + * eval.c (evaluate_subexp): Likewise. + + * eval.c (evaluate_subexp case MULTI_SUBSCRIPT): Don't call + value_x_binop on a Chill varying string. + +Tue Jan 31 13:51:53 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config/m68k/monitor.mt, + config/pa/{hppabsd.mt,hppahpux.mt,hppaosf.mt,hppapro.mt}: Put + depfiles in TDEPFILES not REMOTE_O. + +Tue Jan 31 11:14:44 1995 Steve Chamberlain + + From nigel@algor.co.uk. + * ser-go32.c (dos_close): Don't crash if scb null. + (dos_sendbreak): New function. + (dos_ops): Point to dos_sendbreak. + (dos_info): Calculate COM number correctly. + +Tue Jan 31 09:40:11 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * xcoffread.c (process_xcoff_symbol): Use new variables + func_symbol_type and var_symbol_type as type of functions and + variables which don't have any stabs associated with them. + Reindent most of function. + (_initialize_xcoffread): Initialize *_symbol_type. + + * xcoffread.c (read_xcoff_symtab): Reindent most of function. + Put C_HIDEXT symbols in the minimal symbols, rather than ignoring + them (this part commented out as I didn't quite get it to work). + (cs_to_section, find_targ_sec): New functions, to support above code. + * xcoffread.c (RECORD_MINIMAL_SYMBOL): Only skip '.' if it is + actually present. + +Mon Jan 30 17:34:24 1995 Stu Grossman (grossman@cygnus.com) + * sparcl-tdep.c: Add `sparclite' target for doing serial and udp + downloads to SPARClite demo boards. + +Sun Jan 29 09:43:22 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.c, remote-pa.c: Remove #if 0'd icache code. It has had + no hope of working as is for a long time (in particular, shebs' 27 + Jan 95 change confuses the issue further--target_read_memory and + xfer_core_file do *not* do the same thing in this context). + Revise comment. + +Sat Jan 28 13:40:46 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * elfread.c (elf_symtab_read): Do not test BSF_GLOBAL for + procedure linkage table symbols, it is no longer set due to the + Jan 6 BFD change in bfd/elfcode.h. + +Fri Jan 27 17:08:06 1995 Stan Shebs + + * top.c (use_windows): Clarify comments. + + * convex-tdep.c (xfer_core_file): Comment out. + * config/convex/tm-convex.h (XFER_CORE_FILE): Remove. + * remote.c, remote-pa.c (remote_fetch_word): Change xfer_core_file + references to target_read_memory. + * gdbcore.h (xfer_core_file, core_open, core_detach): Remove + declarations. + * corelow.c (core_open, core_detach): Make static. + + * arm-tdep.c: Make it compile. + (exec_file_command, xfer_core_file): Comment out. + (arm_print_insn): Remove, now in libopcodes. + (skip_prologue): Comment out most of body. + (arm_frame_find_saved_regs): Move here from tm-arm.h. + (_initialize_arm_tdep): Set tm_print_insn. + * config/arm/tm-arm.h: Remove old refs to first_object_file_end. + (XFER_CORE_FILE): Remove. + (FRAME_FIND_SAVED_REGS): Call arm_frame_find_saved_regs. + +Fri Jan 27 08:48:28 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (CHILL_LIB): Define as in testsuite/Makefile.in. + +Thu Jan 26 18:24:41 1995 Jim Kingdon + + * symtab.c (find_pc_line): When subtracting one to get a line + number, make sure not to end up with zero. + + * remote-vx.c: Revert all of Kung's changes of 16 Jan. The + problems with those changes were (a) the file didn't compile, (b) + they changed memset to bzero--memset is correct, (c) they took out + code to deal with boards lacking floating point, (d) who knows + what I didn't discover in a quick read. + +Thu Jan 26 17:32:54 1995 Stu Grossman (grossman@cygnus.com) + + * sparcl-tdep.c: Clean up formatting and indentation. + +Thu Jan 26 10:49:59 1995 Steve Chamberlain + + * remote-hms.c (hms_ops): Change ref of hr_load_image + to gr_load_image. + (dcache_flush, dcache_hit, dcache_value, dcache_fetch, + dcache_poke, dcache_init): Deleted. + (hms_open, hms_resume, hms_fetch_word, hms_store_word): + Use dcache routines provided by remote-util.h + +Thu Jan 26 12:08:31 1995 Michael Meissner + + * configure.in: Add support for powerpc-*-eabi. + + * powerpc/tm-ppc-eabi.h, powerpc/pcc-eabi.mt: New files for + PowerPC support. + +Wed Jan 25 18:13:14 1995 Per Bothner + + * language.h (struct language_defn): New field c_style_arrays. + * language.c (unknown_language_defn, auto_language_defn, + local_language_defn), c-lang.c (c_language_defn, cplus_language_defn, + asm_language_defn): Set c_style_arrays to true. + * m2-lang.c (m2_language_defn), ch-lang.c (chill_language_defn), + f-lang.c (f_language_defn): Set c_style_arrays to false. + * valops.c (value_string): If c_style_array is not set, + allocate string in gdb (not inferior) using allocate_value. + + * value.h (COERCE_ARRAY), valops.c (value_addr, value_arg_coerce): + Only call value_coerce_array if current_language->c_style_arrays. + * values.c: Add #include "language.h". (Needed for COERCE_ARRAY.) + + * valops.c (chill_varying_type): New predicate. + * valops.c (value_cast): Support assigning a fixed string or array + to a variable string/array structure. + + * valarith.c (value_subscripted_rvalue): Extra parameter lowerbound. + Check index>=lowerbound, and then add lowerbound to index here, + instead of in caller. Generalize to arbitrary lval_types. + (value_subscript): Use enhanced value_subscripted_rvalue if + c_style_arrays is false (and index is in range). + + +Wed Jan 25 18:13:14 1995 Per Bothner + + * eval.c (evaluate_subexp case OP_ARRAY): Fix calls to memset: + TYPE_LENGTH is length in bytes, not bits. + +Wed Jan 25 08:19:35 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * infrun.c (proceed): Flush stdout before resuming inferior. + * infcmd.c (step_1), annotate.c (annotate_starting): + Don't bother to flush here. + +Wed Jan 25 01:11:21 1995 Jeff Law (law@snake.cs.utah.edu) + + * hpread.c (hpread_process_one_debug_symbol): Fix lines garbled + by an ill-advised global search and replace. + +Tue Jan 24 12:10:28 1995 Stu Grossman (grossman@cygnus.com) + + * gdbtk.tcl (create_registers_window): Work around a radiobutton + widget bug to make Options|Natural button work. + + * gdbtk.c (gdb_disassemble): Fix problem with source+assembly and + g++ caused by out-of-order pc's. + * gdbtk.tcl (files_command): Remove duplicate file names. Also, + add scrollbar. + +Mon Jan 23 17:21:09 1995 Stu Grossman (grossman@cygnus.com) + + * gdbtk.tcl: Take .gdbtkinit if it exists. Makes gdbtk match the + doc! + +Mon Jan 23 13:11:46 1995 Per Bothner + + Add support for Chill bitstring literals (e.h. H'FF00'). + * ch-exp.y (match_bitstring_literal): Fix for proper endianness. + * expprint.c (print_subexp): Don't call error on OP_BITSTRING, + just print B''. + * gdbtypes.c (create_set_type): Fix bug in length calculation. + * valops.c, value.h (value_bitstring): New function. + * eval.c (evaluate_subexp): Implement support for OP_BITSTRING. + + * ch-typeprint.c (chill_type_print_base): For TYPE_CODE_FUNC, + check that return type is non-void, and print in proper Chill syntax. + +Mon Jan 23 12:20:34 1995 Rob Savoye + + * Makefile.in: Remove references to remote-mon.c. + * remote-mon.c: remove. Replaced by rom68k-rom.c. + * rom68k-rom.c: Support for Rom68k monitor. + +Mon Jan 23 10:50:57 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (CHILL_FOR_TARGET): Update -L argument to point to + gcc/ch/runtime not chillrt, since that is where the chill runtime + lives now. + +Mon Jan 23 00:06:57 1995 Steve Chamberlain + + * remote-hms.c (hms_load): Delete. + (target_ops): Use hr_load_image. + + * remote-e7000.c, remote-z8k.c, remote-nindy.c (target_ops): + Define memory_insert/remove_breakpoint. + * xm-go32.h: Remove redundant SIGs. + +Thu Jan 19 20:26:58 1995 Steve Chamberlain + + * ser-go32.c: Rewritten by nigel@algor.co.uk. + +Fri Jan 20 15:23:55 1995 Per Bothner + + * expression.h (OP_LABELED): New operator, for Chill + labeled structre tuples. + * ch-exp.y (tuple_element, named_record_element, tuple_elements): + New non-terminals, to handle labeled structure tuples. + (tuple): Re-define using tuple_elements. + * eval.c (evaluate_labeled_field_init): New function, to handle + initialization of structure fields, possibly using OP_LABELED. + (evaluate_subexp): Use it. + * expprint.c (print_subexp case): For OP_ARRAY, use Chill syntax + for Chill. Handled OP_LABELED. + * parse.c (length_of_subexp, prefixify_subexp): Handle OP_LABELED. + + * eval.c (evaluate_subexp): Handle Chill Powerset tuples. + * valarith.c (value_bit_index): Just treat bitstring as represented + by an array of bytes. Alignment is handled by compiler. + +Wed Jan 18 19:00:29 1995 Stan Shebs + + * h8300-tdep.c (gdb_print_insn_h8300): Fix typo (&info -> info). + * sh-tdep.c (gdb_print_insn_sh): Ditto. + +Wed Jan 18 11:25:43 1995 Kung Hsu + + * remote-os9k.c (rombug_open): Fix a bug in exception handling + command. + * remote-os9k.c (rombug_write_inferior_memory): reset buffer after + write. + +Tue Jan 17 09:48:38 1995 Jim Kingdon + + * parse.c (_initialize_parse): Improve wording of names of + msym_*_symbol_type. + +Tue Jan 17 14:00:58 1995 Ian Lance Taylor + + * config/mips/tm-mips.h (enum mips_fpu_type): New enum. + (mips_fpu): Change type to enum mips_fpu_type. + (FIX_CALL_DUMMY): Handle mips_fpu == MIPS_FPU_SINGLE. + * mips-tdep.c (mips_fpu): Change type to enum mips_fpu_type. + Don't initialize. + (mips_fpu_string): New static variable. + (mips_push_dummy_frame): Handle mips_fpu == MIPS_FPU_SINGLE. + (mips_pop_frame): Likewise. + (mips_extract_return_value): Likewise. + (mips_store_return_value): Likewise. + (mips_set_fpu_command): New static function. + (mips_show_fpu_command): New static function. + (_initialize_mips_tdep): Change handling of set/show mipsfpu. + +Tue Jan 17 09:48:38 1995 Jim Kingdon + + * a29k-tdep.c (gdb_print_insn_a29k): Fix typo (&info -> info). + + * parse.c (write_exp_msymbol): Use new variables + msym_*_symbol_type as type of msymbol expression. + (_initialize_parse): Initialize them. + +Mon Jan 16 18:11:03 1995 Stan Shebs + + General cleanup and simplication of disassembler interface. + * a29k-pinsn.c, arm-pinsn.c, convex-pinsn.c, gould-pinsn.c, + hppa-pinsn.c, i386-pinsn.c, i960-pinsn.c, m68k-pinsn.c, + m88k-pinsn.c, mips-pinsn.c, ns32k-pinsn.c, pyr-pinsn.c, + rs6000-pinsn.c, sparc-pinsn.c, tahoe-pinsn.c, vax-pinsn.c: Remove. + * gould-tdep.c, ns32k-tdep.c, tahoe-tdep.c, vax-tdep.c: New files, + had been -pinsn.c files. + * Makefile.in (ALLDEPFILES): Remove removed files. + (a29k-pinsn.o, arm-pinsn.o, convex-pinsn.o, gould-pinsn.o, + hppa-pinsn.o, i386-pinsn.o, i960-pinsn.o, m68k-pinsn.o, + m88k-pinsn.o, mips-pinsn.o, ns32k-pinsn.o, pyr-pinsn.o, + rs6000-pinsn.o, sparc-pinsn.o, tahoe-pinsn.o, vax-pinsn.o): + Remove compile actions. + * arm-tdep.o, gould-tdep.o, ns32k-tdep.o, tahoe-tdep.o, + vax-tdep.o: Add compile actions. + * defs.h (tm_print_insn): New global. + * a29k-tdep.c (gdb_print_insn_a29k): New function. + (_initialize_a29k_tdep): Rename from _initialize_29k, + set tm_print_insn. + * alpha-tdep.c (print_insn): Remove. + (_initialize_alpha_tdep): Set tm_print_insn. + * arm-tdep.c (arm_print_insn): New function, was print_insn + in arm-pinsn.c. + * convex-tdep.c (convex_print_insn): New function, was print_insn + in convex-pinsn.c. + * h8300-tdep.c (print_insn): Remove. + (gdb_print_insn_h8300): New function. + (_initialize_h8300_tdep): New function. + * h8500-tdep.c (print_insn): Remove. + (_initialize_h8500_tdep): New function. + * hppa-tdep.c (_initialize_hppa_tdep): Set tm_print_insn. + * i386-tdep.c (_initialize_i386_tdep): New function. + * i960-tdep.c (mem, next_insn): New functions, were in + i960-pinsn.c. + (_initialize_i960_tdep): Set tm_print_insn. + * m68k-tdep.c (_initialize_m68k_tdep): New function. + * m88k-tdep.c (_initialize_m88k_tdep): New function. + * mips-tdep.c (gdb_print_insn_mips): New function. + (_initialize_mips_tdep): Set tm_print_insn. + * pyr-tdep.c (pyr_print_insn): New function, was print_insn + in pyr-pinsn.c. + * rs6000-tdep.c (_initialize_rs6000_tdep): New function. + * sh-tdep.c (print_insn): Remove. + (gdb_print_insn_sh): New function. + (_initialize_sh_tdep): Set tm_print_insn. + * sparc-tdep.c (_initialize_sparc_tdep): New function. + * w65-tdep.c (print_insn): Remove. + (_initialize_w65_tdep): New function. + * z8k-tdep.c (print_insn): Remove. + (gdb_print_insn_z8k): New function. + (_initialize_z8k_tdep): Set tm_print_insn. + * printcmd.c (print_insn): New function, generic disassembler. + * config/*/*.mt (TDEPFILES): Remove refs to *-pinsn.o. + +Mon Jan 16 15:43:29 1995 Kung Hsu + + * Makefile.in: add new files remote-vx29k.c, config/a29k/tm-vx29k.h, + and config/a29k/vx29k.mt. + * configure.in: add new configuration a29k-*-vxworks. + * remote-vx29k.c: new file merged from WRS. + * remote-vx.c: merge changes from WRS. + * config/a29k/vx29k.mt: new file for new configuration. + * config/a29k/tm-vx29k.h: new header file for newconfiguration. + +Sun Jan 15 14:36:19 1995 Steve Chamberlain + + * breakpoint.h (disable_breakpoint, enable_breakpoint): + New declarations. + (enum bpdisp): Change name of 'delete' member to 'del'. + (struct bpstat): Changed name to 'bpstats'. + * breakpoint.c (disable_breakpoint, enable_breakpoint, + breakpoint_chain): Made globally visible. + (bpstat_stop_status): Use new name for bpstat. + (break_command_1, watch_command_1, catch_command_1, + breakpoint_auto_delete, denable_delete_breakpoint): Use 'del' + instead of 'delete'. + (set_breakpoint_sal): New function. + * defs.h (registers_changed_hook): New declaration. + * infcmd.c (run_stack_dummy): 'delete' is now 'del'. + * inflow.c (new_tty): Treat WIN32 in same way as __GO32__ + * main.c (main): Don't scan options when in WIN32 and exit + without entering main loop. + * m2-exp.y (m2_elx): Member 'class' is now 'aclass'. + * symtab.h (struct symbol, struct partial_symbol): Changed name of + member 'class' to 'aclass'. + (SYMBOL_CLASS, PSYMBOL_CLASS): Reflect change. + * top.c (registers_changed_hook): New definition. + * utils.c (quit, notice_quit, initialize_utils): Treate WIN32 + in same way as __GO32__. + * value.h (c_typedef_print): Rename 'new' argument. + + * w65-tdep.c, config/tm-w65.h, config/w65.mt: New files. + * configure.in: Suppprt for w65, + + +Sat Jan 14 11:18:11 1995 Jim Kingdon + + * infcmd.c (signal_command): For "signal 0", pass (CORE_ADDR)-1, + not stop_pc, to proceed. + + * eval.c (evaluate_subexp): Clear expect_type except for C++ and CHILL. + +Fri Jan 13 17:52:57 1995 Jim Kingdon + + * infcmd.c (signal_command): Accept "signal 0"; the change to not + accept it was accidental. "handle 0" and "info signal 0" remain + illegal, though. + +Fri Jan 13 15:19:01 1995 Stan Shebs + + * Makefile.in (all): Don't make libgdb-files. + (libgdb): New action, makes libgdb-files. + +Thu Jan 12 21:23:25 1995 Per Bothner + + * stabsread.c (read_enum_type): When pending enum symbols are + put into the enum type, they must be inserted in "backwards + order, in case we've overflowed a struct pending buffer. + + +Thu Jan 12 09:33:24 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * README: Add note about SPARCworks cc release 3.0 and higher. + + Add procfs support for Alpha OSF/1-2.x. + * config/alpha/nm-osf.h: Renamed from nm-alpha.h, generic + OSF/1 native support. + * config/alpha/alpha-osf1.mh (NAT_FILE): Changed accordingly. + (MUNCH_DEFINE): Removed. + * config/alpha/alpha-osf2.mh, config/alpha/nm-osf2.h: New files + for procfs support. + * configure.in (alpha-dec-osf*): Use alpha-osf2.mh for OSF/1 + release 2.x and higher, else alpha-osf1.mh, as the procfs support + in release 1.x is incomplete. + * Makefile.in (ALLCONFIG): Add config/alpha/alpha-osf2.mh. + * alpha-nat.c (supply_gregset, fill_gregset, supply_fpgregset, + fill_fpgregset): New routines for procfs support. + * inftarg.c (_initialize_inftarg): Don't add ptrace support + if we have an optional procfs and /proc is accessible. + * procfs.c: Include sys/fault.h and sys/syscall.h before + including sys/procfs.h. + (unconditionally_kill_inferior): If PROCFS_NEED_PIOCSSIG_FOR_KILL + is defined, additionally perform a PIOCSSIG to really terminate + the inferior. + (create_procinfo): Always return a result. + (create_procinfo, do_attach): Don't trace T_IFAULT faults if + PROCFS_DONT_TRACE_IFAULT is defined. + (procfs_init_inferior): Use START_INFERIOR_TRAPS_EXPECTED as + argument to startup_inferior if it is defined. + (proc_set_exec_trap): If PIOCSSPCACT is defined, use it instead + of tracing exits from exec system calls. Needed for the user level + loader under Alpha OSF/1. + (do_detach): Clear any pending signal if we want to detach from + a process without a signal. + (set_proc_siginfo): If PROCFS_DONT_PIOCSSIG_CURSIG is defined, + don't issue a PIOCSSIG if pr_cursig already contains the signal we + intend to set. + (info_proc_signals): If PROCFS_SIGPEND_OFFSET is defined, the + pending signals are numbered from 1 instead of 0. + (info_proc_mappings): Increase size of output format for addresses + if BFD_HOST_64_BIT is defined. + (procfs_stop): Renamed from child_stop. + (_initialize_procfs): Don't add procfs support if we have an + optional procfs and /proc is not accessible. + + +Wed Jan 11 17:53:26 1995 Rob Savoye + + * array-rom.c: Add support for most commands. + + * monitor.c: Add GDB remote protocol for the hybrid environment on + the Array board. + +Wed Jan 11 00:44:01 1995 Jeff Law (law@snake.cs.utah.edu) + + * command.c (show_user_1): Use print_command_line to show a user + defined command (including control structures). + + * top.c (init_main): Change documentation for user defined + commands to indicate they may accept up to ten arguments. + +Tue Jan 10 16:22:41 1995 Jim Kingdon + + * mips-tdep.c (mips_skip_prologue): Accept or as well as addu for + `move $s8, $sp' instruction. + +Sun Jan 8 12:45:34 1995 Jim Kingdon + + * target.c, target.h (target_signal_from_command): New function. + * infrun.c (handle_command, signals_info), infcmd.c + (signal_command): Use it. + * infrun.c, infcmd.c: Update docstrings for these commands. + + * target.h (enum target_signal), target.c (signals), target.c + (target_signal_from_host, target_signal_to_host): Add + TARGET_SIGNAL_REALTIME_* and TARGET_SIGNAL_PRIO for lynx. + * config/tm-lynx.h: Define signal numbers for realtime events. + +Sat Jan 7 07:23:53 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dbxread.c (process_one_symbol): Handle N_FUN symbols + for Sun acc 3.0 under SunOS4. + + Changes to improve handling of runtime common symbols + under SunOS4. + * minsyms.c (get_symbol_leading_char): New routine to determine + the leading symbol character for an objfile. + (prim_record_minimal_symbol_and_info, install_minimal_symbols): + Use it. + * objfiles.h (rt_common_objfile): New global, points to objfile + containing the runtime common minimal symbols. + * objfiles.c (free_objfile): Mark rt_common_objfile as + unallocated before freeing it. + * solib.c (allocate_rt_common_objfile): New routine to allocate + an objfile for the runtime common minimal symbols. + (solib_add_common_symbols): Allocate an objfile for the runtime + common symbols if necessary and put common symbols into it. + Clean up code and comments. + (solib_add, special_symbol_handling): Cleanup comments regarding + runtime common symbols. + * stabsread.c (scan_file_globals_1): New routine, contains + old scan_file_globals code. Checks if there are any unresolved + global symbols before starting the expensive minimal symbol table + search. + (scan_file_globals): Now calls scan_file_globals_1 for the passed + objfile and eventually for the runtime common objfile. Complains + about any unresolved global symbols and removes them from the + global symbol chain to avoid dangling pointers into the symbol + table if the symbol table is reread. + +Thu Jan 5 17:38:29 1995 Stu Grossman (grossman@cygnus.com) + + * Makefile.in (install_only uninstall): Indent for clarity. + + * core.c (dis_asm_read_memory): Add call to + dis_asm_read_memory_hook to provide alternate way for disassembler + to read memory. + + * defs.h: Protect from multiple inclusion. Add decl for + dis_asm_read_memory_hook. + + * top.c: Make window startup be the default. + * Add dis_asm_read_memory_hook. + + +Thu Jan 5 01:16:40 1995 Jeff Law (law@snake.cs.utah.edu) + + * stabsread.c (define_symbol): Handle `a' symbol type used for + reference parameter passed in a register. + + +Wed Jan 4 12:27:29 1995 Kung Hsu + + * defs.h: move include tm.h up, so that the type LONGEST can + also based on the target requirement to determine. In this case + target mips64. + + * remote-os9k.c (rombug_open): catch exception e in rombug. + * remote-os9k.c (rombug_wait): print message before register display + from rombug. + +Wed Jan 4 09:18:27 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * top.c (locate_arg): Call strchr not index. + +Tue Jan 3 16:52:03 1995 Per Bothner + + * ch-exp.y (literal): Recognize NULL. + (tuple): Parse simple unlabelled tuples. + * eval.c (evaluate_subexp case OP_ARRAY): Use expect_type to + evaluate brace-initializer-expressions depending on context. + (evaluate_subexp case UNOP_CAST): Pass the target type as + expected type when evaluating the expression. + + * ch-typeprint.c (chill_type_print_base): Get names of PTR and + BOOL from TYPE_NAME. + * ch-valprint.c (chill_print_type_scalar): New function, to handle + TYPE_CODE_RANGE better than print_type_scalar does. + (chill_val_print_array_elements): Use above new function. + +Mon Jan 2 15:02:51 1995 Stan Shebs + + * remote-udi.c (udi_load): Tell symbol_file_add that the + program being loaded is the main program. + +For older changes see ChangeLog-94 + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/gdb/Makefile.in b/contrib/gdb/gdb/Makefile.in new file mode 100644 index 000000000000..77ef7f2e24f3 --- /dev/null +++ b/contrib/gdb/gdb/Makefile.in @@ -0,0 +1,1534 @@ +# Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 +# Free Software Foundation, Inc. + +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(libdir)/$(target_alias) + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +AR = @AR@ +AR_FLAGS = qv +RANLIB = @RANLIB@ +AWK = @AWK@ + +# Flags that describe where you can find the termcap library. +# This can be overridden in the host Makefile fragment file. +TERMCAP = -ltermcap + +# If you are compiling with GCC, make sure that either 1) You have the +# fixed include files where GCC can reach them, or 2) You use the +# -traditional flag. Otherwise the ioctl calls in inflow.c +# will be incorrectly compiled. The "fixincludes" script in the gcc +# distribution will fix your include files up. +CC=@CC@ + +# Directory containing source files. +srcdir = @srcdir@ +VPATH = @srcdir@ + +YACC=@YACC@ + +# where to find makeinfo, preferably one designed for texinfo-2 +MAKEINFO=makeinfo + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefined references. +#CC_LD=gcc -static +CC_LD=$(CC) + +# Where is our "include" directory? Typically $(srcdir)/../include. +# This is essentially the header file directory for the library +# routines in libiberty. +INCLUDE_DIR = $(srcdir)/../include +INCLUDE_CFLAGS = -I$(INCLUDE_DIR) + +# Where is the "-liberty" library? Typically in ../libiberty. +LIBIBERTY = ../libiberty/libiberty.a + +# Where is the MMALLOC library? Typically in ../mmalloc. +# Note that mmalloc can still be used on systems without mmap(). +# To use your system malloc, comment out the following defines. +MMALLOC_DIR = ../mmalloc +MMALLOC_SRC = $(srcdir)/$(MMALLOC_DIR) +MMALLOC = $(MMALLOC_DIR)/libmmalloc.a +# To use your system malloc, uncomment MMALLOC_DISABLE. +#MMALLOC_DISABLE = -DNO_MMALLOC +# To use mmalloc but disable corruption checking, uncomment MMALLOC_CHECK +#MMALLOC_CHECK = -DNO_MMALLOC_CHECK +MMALLOC_CFLAGS = -I$(MMALLOC_SRC) $(MMALLOC_CHECK) $(MMALLOC_DISABLE) + +# Where is the BFD library? Typically in ../bfd. +BFD_DIR = ../bfd +BFD = $(BFD_DIR)/libbfd.a +BFD_SRC = $(srcdir)/$(BFD_DIR) +BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC) + +# Where is the READLINE library? Typically in ../readline. +READLINE_DIR = ../readline +READLINE = $(READLINE_DIR)/libreadline.a +READLINE_SRC = $(srcdir)/$(READLINE_DIR) +READLINE_CFLAGS = -I$(READLINE_SRC) + +# Opcodes currently live in one of two places. Either they are in the +# opcode library, typically ../opcodes, or they are in a header file +# in INCLUDE_DIR. +# Where is the "-lopcodes" library, with (some of) the opcode tables and +# disassemblers? +OPCODES = ../opcodes/libopcodes.a +# Where are the other opcode tables which only have header file +# versions? +OP_INCLUDE = $(INCLUDE_DIR)/opcode +OPCODES_CFLAGS = -I$(OP_INCLUDE) + +# The simulator is usually nonexistent; targets that include one +# should set this to list all the .o or .a files to be linked in. +SIM = + + +ENABLE_CFLAGS= @ENABLE_CFLAGS@ +ENABLE_CLIBS= @ENABLE_CLIBS@ +ENABLE_OBS= @ENABLE_OBS@ + +# -I. for config files. +# -I$(srcdir) for gdb internal headers and possibly for gnu-regex.h also. +# -I$(srcdir)/config for more generic config files. + +# It is also possible that you will need to add -I/usr/include/sys if +# your system doesn't have fcntl.h in /usr/include (which is where it +# should be according to Posix). +DEFS = @DEFS@ +GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config $(DEFS) + +# M{H,T}_CFLAGS, if defined, have host- and target-dependent CFLAGS +# from the config directory. +GLOBAL_CFLAGS = $(MT_CFLAGS) $(MH_CFLAGS) +#PROFILE_CFLAGS = -pg + +# CFLAGS is specifically reserved for setting from the command line +# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". +CFLAGS = -g + +# Need to pass this to testsuite for "make check". Probably should be +# consistent with top-level Makefile.in and gdb/testsuite/Makefile.in +# so "make check" has the same result no matter where it is run. +CXXFLAGS = -g -O + +# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. +INTERNAL_CFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \ + $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \ + $(BFD_CFLAGS) $(MMALLOC_CFLAGS) $(INCLUDE_CFLAGS) $(ENABLE_CFLAGS) + +# LDFLAGS is specifically reserved for setting from the command line +# when running make. + +# Profiling options need to go here to work. +# I think it's perfectly reasonable for a user to set -pg in CFLAGS +# and have it work; that's why CFLAGS is here. +INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) $(LDFLAGS) + +# We are using our own version of REGEX now to be consistent across +# machines. +REGEX = gnu-regex.o +REGEX1 = gnu-regex.o + +# If your system is missing alloca(), or, more likely, it's there but +# it doesn't work, then refer to libiberty. + +# Libraries and corresponding dependencies for compiling gdb. +# {X,T}M_CLIBS, defined in *config files, have host- and target-dependent libs. +# TERMCAP comes after readline, since readline depends on it. +# If you have the Cygnus libraries installed, +# you can use 'CLIBS=$(INSTALLED_LIBS)' 'CDEPS=' +INSTALLED_LIBS=-lbfd -lreadline $(TERMCAP) -lopcodes -lmmalloc -liberty \ + $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(ENABLE_CLIBS) @LIBS@ +CLIBS = $(SIM) $(BFD) $(READLINE) $(OPCODES) $(MMALLOC) $(LIBIBERTY) \ + $(ENABLE_CLIBS) $(TERMCAP) $(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) \ + $(LIBIBERTY) @LIBS@ +CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \ + $(OPCODES) $(MMALLOC) $(LIBIBERTY) + +ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) +ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) + +VERSION = 4.16 +DIST=gdb + +LINT=/usr/5bin/lint +LINTFLAGS= $(BFD_CFLAGS) + +RUNTEST = `if [ -f $${rootsrc}/../dejagnu/runtest ] ; then \ + echo $${rootsrc}/../dejagnu/runtest ; else echo runtest; \ + fi` + +RUNTESTFLAGS= + +# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX +# interface to the serial port. Hopefully if get ported to OS/2, VMS, +# etc., then there will be (as part of the C library or perhaps as +# part of libiberty) a POSIX interface. But at least for now the +# host-dependent makefile fragment might need to use something else +# besides ser-unix.o +SER_HARDWIRE = ser-unix.o + +# The `remote' debugging target is supported for most architectures, +# but not all (e.g. 960) +REMOTE_OBS = remote.o dcache.o remote-utils.o + +# This is remote-sim.o if a simulator is to be linked in. +SIM_OBS = + +ANNOTATE_OBS = annotate.o + +# Host and target-dependent makefile fragments come in here. +@host_makefile_frag@ +@target_makefile_frag@ +# End of host and target-dependent makefile fragments + +FLAGS_TO_PASS = \ + "prefix=$(prefix)" \ + "exec_prefix=$(exec_prefix)" \ + "against=$(against)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "CHILLFLAGS=$(CHILLFLAGS)" \ + "CHILL=$(CHILL)" \ + "CHILL_LIB=$(CHILL_LIB)" \ + "CXX=$(CXX)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "MAKEINFO=$(MAKEINFO)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" + +# Flags that we pass when building the testsuite. + +# empty for native, $(target_alias)/ for cross +target_subdir = @target_subdir@ + +CC_FOR_TARGET = ` \ + if [ -f $${rootme}/../gcc/xgcc ] ; then \ + if [ -f $${rootme}/../$(target_subdir)newlib/Makefile ] ; then \ + echo $${rootme}/../gcc/xgcc -B$${rootme}/../gcc/ -idirafter $${rootme}/$(target_subdir)newlib/targ-include -idirafter $${rootsrc}/../$(target_subdir)newlib/libc/include -nostdinc -B$${rootme}/../$(target_subdir)newlib/; \ + else \ + echo $${rootme}/../gcc/xgcc -B$${rootme}/../gcc/; \ + fi; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(CC); \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e '' $$t; \ + fi; \ + fi` + +CXX = gcc +CXX_FOR_TARGET = ` \ + if [ -f $${rootme}/../gcc/xgcc ] ; then \ + if [ -f $${rootme}/../$(target_subdir)newlib/Makefile ] ; then \ + echo $${rootme}/../gcc/xgcc -B$${rootme}/../gcc/ -idirafter $${rootme}/$(target_subdir)newlib/targ-include -idirafter $${rootsrc}/../$(target_subdir)newlib/libc/include -nostdinc -B$${rootme}/../$(target_subdir)newlib/; \ + else \ + echo $${rootme}/../gcc/xgcc -B$${rootme}/../gcc/; \ + fi; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(CXX); \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e '' $$t; \ + fi; \ + fi` + +CHILLFLAGS = $(CFLAGS) +CHILL = gcc +CHILL_FOR_TARGET = ` \ + if [ -f $${rootme}/../gcc/Makefile ] ; then \ + echo $${rootme}/../gcc/xgcc -B$${rootme}/../gcc/ -L$${rootme}/../gcc/ch/runtime/; \ + else \ + if [ "$(host_canonical)" = "$(target_canonical)" ] ; then \ + echo $(CC); \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e '' $$t; \ + fi; \ + fi` +CHILL_LIB = ` \ + if [ -f $${rootme}/../gcc/ch/runtime/libchill.a ] ; then \ + echo $${rootme}/../gcc/ch/runtime/chillrt0.o \ + $${rootme}/../gcc/ch/runtime/libchill.a; \ + else \ + echo -lchill; \ + fi` + +# The use of $$(x_FOR_TARGET) reduces the command line length by not +# duplicating the lengthy definition. +TARGET_FLAGS_TO_PASS = \ + "prefix=$(prefix)" \ + "exec_prefix=$(exec_prefix)" \ + "against=$(against)" \ + 'CC=$$(CC_FOR_TARGET)' \ + "CC_FOR_TARGET=$(CC_FOR_TARGET)" \ + "CFLAGS=$(CFLAGS)" \ + "CHILLFLAGS=$(CHILLFLAGS)" \ + 'CHILL=$$(CHILL_FOR_TARGET)' \ + "CHILL_FOR_TARGET=$(CHILL_FOR_TARGET)" \ + "CHILL_LIB=$(CHILL_LIB)" \ + 'CXX=$$(CXX_FOR_TARGET)' \ + "CXX_FOR_TARGET=$(CXX_FOR_TARGET)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "MAKEINFO=$(MAKEINFO)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" + +# All source files that go into linking GDB. +# Links made at configuration time should not be specified here, since +# SFILES is used in building the distribution archive. + +SFILES = bcache.c blockframe.c breakpoint.c buildsym.c callback.c c-exp.y \ + c-lang.c c-typeprint.c c-valprint.c ch-exp.c ch-lang.c \ + ch-typeprint.c ch-valprint.c coffread.c command.c complaints.c \ + corefile.c cp-valprint.c dbxread.c demangle.c dwarfread.c \ + elfread.c environ.c eval.c expprint.c \ + f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c \ + gdbtypes.c infcmd.c inflow.c infrun.c language.c \ + m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \ + mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c parse.c \ + printcmd.c remote.c remote-nrom.c scm-exp.c scm-lang.c scm-valprint.c \ + source.c stabsread.c stack.c symfile.c symmisc.c \ + symtab.c target.c thread.c top.c \ + typeprint.c utils.c valarith.c valops.c \ + valprint.c values.c serial.c ser-unix.c mdebugread.c os9kread.c + +LINTFILES = $(SFILES) $(YYFILES) init.c + +# "system" headers. Using these in dependencies is a rather personal +# choice. (-rich, summer 1993) +# (Why would we not want to depend on them? If one of these changes in a +# non-binary-compatible way, it is a real pain to remake the right stuff +# without these dependencies -kingdon, 13 Mar 1994) +getopt_h = $(INCLUDE_DIR)/getopt.h +floatformat_h = $(INCLUDE_DIR)/floatformat.h +bfd_h = $(BFD_DIR)/bfd.h +wait_h = $(INCLUDE_DIR)/wait.h +dis-asm_h = $(INCLUDE_DIR)/dis-asm.h + +dcache_h = dcache.h +remote_utils_h = $(dcache_h) serial.h target.h remote-utils.h remote-sim.h + +readline_headers = \ + $(READLINE_SRC)/chardefs.h \ + $(READLINE_SRC)/history.h \ + $(READLINE_SRC)/keymaps.h \ + $(READLINE_SRC)/readline.h + +udiheaders = \ + $(srcdir)/29k-share/udi/udiproc.h \ + $(srcdir)/29k-share/udi/udiphcfg.h \ + $(srcdir)/29k-share/udi/udiphunix.h \ + $(srcdir)/29k-share/udi/udiptcfg.h \ + $(srcdir)/29k-share/udi/udipt29k.h \ + $(srcdir)/29k-share/udi/udisoc.h + +gdbcore_h = gdbcore.h $(bfd_h) + +frame_h = frame.h +symtab_h = symtab.h bcache.h +gdbtypes_h = gdbtypes.h +expression_h = expression.h +value_h = value.h $(symtab_h) $(gdbtypes_h) $(expression_h) + +breakpoint_h = breakpoint.h $(frame_h) $(value_h) + +command_h = command.h +gdbcmd_h = gdbcmd.h $(command_h) + +defs_h = defs.h xm.h tm.h nm.h config.status config.h + +inferior_h = inferior.h $(breakpoint_h) + +# Header files that need to have srcdir added. Note that in the cases +# where we use a macro like $(gdbcmd_h), things are carefully arranged +# so that each .h file is listed exactly once (M-x tags-search works +# wrong if TAGS has files twice). Because this is tricky to get +# right, it is probably easiest just to list .h files here directly. + +HFILES_NO_SRCDIR = bcache.h buildsym.h call-cmds.h coff-solib.h defs.h \ + dst.h environ.h $(gdbcmd_h) gdbcore.h \ + gdb-stabs.h $(inferior_h) language.h minimon.h monitor.h \ + objfiles.h parser-defs.h partial-stab.h serial.h signals.h solib.h \ + symfile.h stabsread.h target.h terminal.h typeprint.h xcoffsolib.h \ + c-lang.h ch-lang.h f-lang.h m2-lang.h \ + complaints.h valprint.h \ + 29k-share/udi/udiids.h 29k-share/udi_soc nindy-share/b.out.h \ + nindy-share/block_io.h nindy-share/coff.h \ + nindy-share/env.h nindy-share/stop.h \ + vx-share/dbgRpcLib.h vx-share/ptrace.h vx-share/vxTypes.h \ + vx-share/vxWorks.h vx-share/wait.h vx-share/xdr_ld.h \ + vx-share/xdr_ptrace.h vx-share/xdr_rdb.h thread.h \ + dcache.h remote-utils.h remote-sim.h top.h somsolib.h + +# Header files that already have srcdir in them, or which are in objdir. + +HFILES_WITH_SRCDIR = $(udiheaders) ../bfd/bfd.h + + +# GDB "info" files, which should be included in their entirety +INFOFILES = gdb.info* + +REMOTE_EXAMPLES = m68k-stub.c i386-stub.c sparc-stub.c rem-multi.shar + +POSSLIBS = gnu-regex.c gnu-regex.h + +# {X,T,NAT}DEPFILES are something of a pain in that it's hard to +# default their values the way we do for SER_HARDWIRE; in the future +# maybe much of the stuff now in {X,T,NAT}DEPFILES will go into other +# variables analogous to SER_HARDWIRE which get defaulted in this +# Makefile.in + +DEPFILES = $(TDEPFILES) $(XDEPFILES) $(SER_HARDWIRE) $(NATDEPFILES) \ + $(REMOTE_OBS) $(SIM_OBS) $(ENABLE_OBS) + +SOURCES = $(SFILES) $(ALLDEPFILES) $(YYFILES) +# Don't include YYFILES (*.tab.c) because we already include *.y in SFILES, +# and it's more useful to see it in the .y file. +TAGFILES_NO_SRCDIR = $(SFILES) $(HFILES_NO_SRCDIR) $(ALLDEPFILES) \ + $(POSSLIBS) +TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR) + +COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o stack.o thread.o \ + source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \ + symtab.o symfile.o symmisc.o infcmd.o infrun.o command.o \ + expprint.o environ.o gdbtypes.o copying.o $(DEPFILES) \ + mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \ + exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \ + dbxread.o coffread.o elfread.o \ + dwarfread.o mipsread.o stabsread.o corefile.o \ + c-lang.o ch-exp.o ch-lang.o f-lang.o m2-lang.o \ + scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \ + c-typeprint.o ch-typeprint.o f-typeprint.o m2-typeprint.o \ + c-valprint.o cp-valprint.o ch-valprint.o f-valprint.o m2-valprint.o \ + nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o callback.o + +OBS = $(COMMON_OBS) $(ANNOTATE_OBS) main.o + +LIBGDB_OBS = + +TSOBS = inflow.o + +NTSOBS = standalone.o + +NTSSTART = kdb-start.o + +SUBDIRS = doc testsuite nlm + +# For now, shortcut the "configure GDB for fewer languages" stuff. +YYFILES = c-exp.tab.c f-exp.tab.c m2-exp.tab.c +YYOBJ = c-exp.tab.o f-exp.tab.o m2-exp.tab.o + +# Things which need to be built when making a distribution. + +DISTSTUFF = $(YYFILES) + +# Prevent Sun make from putting in the machine type. Setting +# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. +.c.o: + $(CC) -c $(INTERNAL_CFLAGS) $< + +all: gdb + @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do + +installcheck: + +# The check target can not use subdir_do, because subdir_do does not +# use TARGET_FLAGS_TO_PASS. +check: force + @if [ -f testsuite/Makefile ]; then \ + rootme=`pwd`; export rootme; \ + rootsrc=`cd $(srcdir); pwd`; export rootsrc; \ + cd testsuite; \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check; \ + else true; fi + +info dvi install-info clean-info: force + @$(MAKE) $(FLAGS_TO_PASS) DO=$@ "DODIRS=$(SUBDIRS)" subdir_do + +gdb.z:gdb.1 + nroff -man $(srcdir)/gdb.1 | col -b > gdb.t + pack gdb.t ; rm -f gdb.t + mv gdb.t.z gdb.z + +# Traditionally "install" depends on "all". But it may be useful +# not to; for example, if the user has made some trivial change to a +# source file and doesn't care about rebuilding or just wants to save the +# time it takes for make to check that all is up to date. +# install-only is intended to address that need. +install: all install-only +install-only: + transformed_name=`t='$(program_transform_name)'; \ + echo gdb | sed -e $$t` ; \ + if test "x$$transformed_name" = x; then \ + transformed_name=gdb ; \ + else \ + true ; \ + fi ; \ + $(INSTALL_PROGRAM) gdb $(bindir)/$$transformed_name ; \ + $(INSTALL_DATA) $(srcdir)/gdb.1 $(man1dir)/$$transformed_name.1 + @$(MAKE) DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do + +uninstall: force + transformed_name=`t='$(program_transform_name)'; \ + echo gdb | sed -e $$t` ; \ + if test "x$$transformed_name" = x; then \ + transformed_name=gdb ; \ + else \ + true ; \ + fi ; \ + rm -f $(bindir)/$$transformed_name $(man1dir)/$$transformed_name.1 + @$(MAKE) DO=uninstall "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do + +# We do this by grepping through sources. If that turns out to be too slow, +# maybe we could just require every .o file to have an initialization routine +# of a given name (remote-udi.o -> _initialize_remote_udi, etc.). +# +# Formatting conventions: The name of the _initialize_* routines must start +# in column zero, and must not be inside #if. +# +# Note that the set of files with init functions might change, or the names +# of the functions might change, so this files needs to depend on all the +# object files that will be linked into gdb. + +init.c: $(OBS) $(TSOBS) + @echo Making init.c + @rm -f init.c-tmp + @echo '/* Do not modify this file. */' >init.c-tmp + @echo '/* It is created automatically by the Makefile. */'>>init.c-tmp + @echo 'void initialize_all_files () {' >>init.c-tmp + @for i in $(OBS) $(TSOBS); do \ + filename=`echo $$i | sed \ + -e '/^Onindy.o/d' \ + -e '/^nindy.o/d' \ + -e '/ttyflush.o/d' \ + -e '/xdr_ld.o/d' \ + -e '/xdr_ptrace.o/d' \ + -e '/xdr_rdb.o/d' \ + -e '/udr.o/d' \ + -e '/udip2soc.o/d' \ + -e '/udi2go32.o/d' \ + -e '/version.o/d' \ + -e '/^[a-z0-9A-Z_]*_[SU].o/d' \ + -e '/[a-z0-9A-Z_]*-exp.tab.o/d' \ + -e 's/\.o/.c/'` ; \ + case $$filename in \ + "") ;; \ + *) sed <$(srcdir)/$$filename >>init.c-tmp -n \ + -e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (); \1 ();}/p' ; ;; \ + esac ; \ + done + @echo '}' >>init.c-tmp + @mv init.c-tmp init.c + +.PRECIOUS: init.c + +# Removing the old gdb first works better if it is running, at least on SunOS. +gdb: $(OBS) $(TSOBS) $(ADD_DEPS) $(CDEPS) init.o + rm -f gdb + $(CC_LD) $(INTERNAL_LDFLAGS) -o gdb \ + init.o $(OBS) $(TSOBS) $(ADD_FILES) $(CLIBS) $(LOADLIBES) + +nlm: force + rootme=`pwd`; export rootme; $(MAKE) $(TARGET_FLAGS_TO_PASS) DO=all DODIRS=nlm subdir_do + +libgdb: libgdb-files $(LIBGDB_OBS) + +# libproc is not listed here because all-libproc is a dependency of all-gui, +# not all-gdb, and thus might be built after us. +LIBGDBDEPS=$(COMMON_OBS) $(LIBGDB_OBS) $(TSOBS) $(ADD_DEPS) $(CDEPS) init.o +# libproc needs to be before libiberty for alloca. +LIBGDBFILES=$(COMMON_OBS) $(LIBGDB_OBS) $(TSOBS) ../libproc/libproc.a \ + $(ADD_DEPS) $(CDEPS) init.o + +libgdb-files: $(LIBGDBDEPS) Makefile.in + -rm -f libgdb-files + for i in $(LIBGDBFILES); do\ + echo $$i >> libgdb-files;\ + done + +saber_gdb: $(SFILES) $(DEPFILES) copying.c version.c + #setopt load_flags $(CFLAGS) $(BFD_CFLAGS) -DHOST_SYS=SUN4_SYS + #load ./init.c $(SFILES) + #unload $(srcdir)/c-exp.y $(srcdir)/m2-exp.y + #unload vx-share/*.h + #unload nindy-share/[A-Z]* + #load c-exp.tab.c m2-exp.tab.c + #load copying.c version.c + #load ../opcodes/libopcodes.a + #load ../libiberty/libiberty.a + #load ../bfd/libbfd.a + #load ../readline/libreadline.a + #load ../mmalloc/libmmalloc.a + #load -ltermcap + #load `echo " "$(DEPFILES) | sed -e 's/\.o/.c/g' -e 's, , ../,g'` + echo "Load .c corresponding to:" $(DEPFILES) + + +# A Mach 3.0 program to force gdb back to command level + +stop-gdb: stop-gdb.o + ${CC_LD} $(GLOBAL_CFLAGS) $(LDFLAGS) -o stop-gdb \ + stop-gdb.o $(CLIBS) $(LOADLIBES) + +# This is useful when debugging GDB, because some Unix's don't let you run GDB +# on itself without copying the executable. So "make gdb1" will make +# gdb and put a copy in gdb1, and you can run it with "gdb gdb1". +# Removing gdb1 before the copy is the right thing if gdb1 is open +# in another process. +gdb1: gdb + rm -f gdb1 + cp gdb gdb1 + +### fixme - this can't be right. +# This checks the configure.in file versus the config/ directory. +config-check: config-check-hosts config-check-targets +config-check-hosts: + grep gdb_host= $(srcdir)/configure.in | \ + sed -e 's/.*gdb_host=//' -e 's/ ;;$$/.mh/' | sort -u >HOSTconf.o + (cd $(srcdir)/config; ls *.mh) >HOSTdir.o + diff -u HOSTconf.o HOSTdir.o + +### fixme - nor can this. +config-check-targets: + grep gdb_target= $(srcdir)/configure.in | \ + sed -e 's/.*gdb_target=//' -e 's/ ;;$$/.mh/' | sort -u >TARGconf.o + (cd $(srcdir)/config; ls *.mt) >TARGdir.o + diff -u HOSTconf.o HOSTdir.o + +# FIXME. These are not generated by "make depend" because they only are there +# for some machines. +# But these rules don't do what we want; we want to hack the foo.o: tm.h +# dependency to do the right thing. +tm-isi.h tm-sun3.h tm-news.h tm-hp300bsd.h tm-altos.h: tm-m68k.h +tm-hp300hpux.h tm-sun2.h tm-3b1.h: tm-m68k.h +xm-news1000.h: xm-news.h +xm-i386-sv32.h: xm-i386.h +tm-i386gas.h: tm-i386.h +xm-sun4os4.h: xm-sparc.h +tm-sun4os4.h: tm-sparc.h +xm-vaxult.h: xm-vax.h +xm-vaxbsd.h: xm-vax.h + +kdb: $(NTSSTART) $(OBS) $(NTSOBS) $(ADD_DEPS) $(CDEPS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o $(ADD_FILES) \ + -lc $(CLIBS) + +# Put the proper machine-specific files first, so M-. on a machine +# specific routine gets the one for the correct machine. (FIXME: those +# files go in twice; we should be removing them from the main list). + +# TAGS depends on all the files that go into it so you can rebuild TAGS +# with `make TAGS' and not have to say `rm TAGS' first. + +TAGS: $(TAGFILES_NO_SRCDIR) $(TAGFILES_WITH_SRCDIR) + @echo Making TAGS + @etags $(srcdir)/$(TM_FILE) \ + $(srcdir)/$(XM_FILE) \ + $(srcdir)/$(NAT_FILE) \ + `(for i in $(DEPFILES) $(TAGFILES_NO_SRCDIR); do \ + echo $(srcdir)/$$i ; \ + done ; for i in $(TAGFILES_WITH_SRCDIR); do \ + echo $$i ; \ + done) | sed -e 's/\.o$$/\.c/'` \ + `find $(srcdir)/config -name '*.h' -print` + +tags: TAGS + +clean mostlyclean: + @$(MAKE) $(FLAGS_TO_PASS) DO=clean "DODIRS=$(SUBDIRS)" subdir_do + rm -f *.o $(ADD_FILES) *~ init.c-tmp + rm -f init.c version.c + rm -f gdb core make.log libgdb-files + rm -f gdb[0-9] + +# This used to depend on c-exp.tab.c m2-exp.tab.c TAGS +# I believe this is wrong; the makefile standards for distclean just +# describe removing files; the only sort of "re-create a distribution" +# functionality described is if the distributed files are unmodified. +distclean: clean + @$(MAKE) $(FLAGS_TO_PASS) DO=distclean "DODIRS=$(SUBDIRS)" subdir_do + rm -f nm.h tm.h xm.h config.status config.h stamp-h + rm -f y.output yacc.acts yacc.tmp y.tab.h + rm -f config.log config.cache + rm -f Makefile + +maintainer-clean realclean: clean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + @$(MAKE) $(FLAGS_TO_PASS) DO=maintainer-clean "DODIRS=$(SUBDIRS)" subdir_do + rm -f c-exp.tab.c f-exp.tab.c m2-exp.tab.c + rm -f TAGS $(INFOFILES) + rm -f nm.h tm.h xm.h config.status + rm -f y.output yacc.acts yacc.tmp + rm -f config.log config.cache + rm -f Makefile + +diststuff: $(DISTSTUFF) + cd doc; $(MAKE) $(MFLAGS) all-doc + +subdir_do: force + @for i in $(DODIRS); do \ + if [ -f ./$$i/Makefile ] ; then \ + if (cd ./$$i; \ + $(MAKE) $(FLAGS_TO_PASS) $(DO)) ; then true ; \ + else exit 1 ; fi ; \ + else true ; fi ; \ + done + +Makefile: Makefile.in config.status @frags@ + $(SHELL) config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_HEADERS=config.h:config.in $(SHELL) config.status + +config.status: configure + $(SHELL) config.status --recheck + +force: + +# Documentation! +# GDB QUICK REFERENCE (TeX dvi file, CM fonts) +doc/refcard.dvi: + cd doc; $(MAKE) refcard.dvi $(FLAGS_TO_PASS) + +# GDB QUICK REFERENCE (PostScript output, common PS fonts) +doc/refcard.ps: + cd doc; $(MAKE) refcard.ps $(FLAGS_TO_PASS) + +# GDB MANUAL: TeX dvi file +doc/gdb.dvi: + cd doc; $(MAKE) gdb.dvi $(FLAGS_TO_PASS) + +# GDB MANUAL: info file +doc/gdb.info: + cd doc; $(MAKE) gdb.info $(FLAGS_TO_PASS) + +# Make copying.c from COPYING +copying.c: COPYING copying.awk + awk -f $(srcdir)/copying.awk < $(srcdir)/COPYING > copying.c + +version.c: Makefile + echo 'char *version = "$(VERSION)";' >version.c + echo 'char *host_name = "$(host_alias)";' >> version.c + echo 'char *target_name = "$(target_alias)";' >> version.c + +# c-exp.tab.c is generated in objdir from c-exp.y if it doesn't exist +# in srcdir, then compiled in objdir to c-exp.tab.o. + +# If we said c-exp.tab.c rather than ./c-exp.tab.c some makes +# would sometimes re-write it into $(srcdir)/c-exp.tab.c. + +# Remove bogus decls for malloc/realloc/free which conflict with everything +# else. Strictly speaking c-exp.tab.c should therefore depend on +# Makefile.in, but that was a pretty big annoyance. +c-exp.tab.o: c-exp.tab.c +c-exp.tab.c: c-exp.y + $(YACC) $(YFLAGS) $(srcdir)/c-exp.y + -sed -e '/extern.*malloc/d' \ + -e '/extern.*realloc/d' \ + -e '/extern.*free/d' \ + -e '/include.*malloc.h/d' \ + -e 's/malloc/xmalloc/g' \ + -e 's/realloc/xrealloc/g' \ + < y.tab.c > c-exp.new + -rm y.tab.c + mv c-exp.new ./c-exp.tab.c + +f-exp.tab.o: f-exp.tab.c +f-exp.tab.c: f-exp.y c-exp.tab.c + $(YACC) $(YFLAGS) $(srcdir)/f-exp.y + -sed -e '/extern.*malloc/d' \ + -e '/extern.*realloc/d' \ + -e '/extern.*free/d' \ + -e '/include.*malloc.h/d' \ + -e 's/malloc/xmalloc/g' \ + -e 's/realloc/xrealloc/g' \ + < y.tab.c > f-exp.new + -rm y.tab.c + mv f-exp.new ./f-exp.tab.c + +# m2-exp.tab.c is generated in objdir from m2-exp.y if it doesn't exist +# in srcdir, then compiled in objdir to m2-exp.tab.o. +# Remove bogus decls for malloc/realloc/free which conflict with everything +# else. +m2-exp.tab.o: m2-exp.tab.c +m2-exp.tab.c: m2-exp.y + $(YACC) $(YFLAGS) $(srcdir)/m2-exp.y + -sed -e '/extern.*malloc/d' \ + -e '/extern.*realloc/d' \ + -e '/extern.*free/d' \ + -e '/include.*malloc.h/d' \ + -e 's/malloc/xmalloc/g' \ + -e 's/realloc/xrealloc/g' \ + < y.tab.c > m2-exp.new + -rm y.tab.c + mv m2-exp.new ./m2-exp.tab.c + +# These files are updated atomically, so make never has to remove them +.PRECIOUS: m2-exp.tab.c f-exp.tab.c c-exp.tab.c + +lint: $(LINTFILES) + $(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES) \ + `echo $(DEPFILES) | sed 's/\.o /\.c /g'` + +gdb.cxref: $(SFILES) + cxref -I. $(SFILES) >gdb.cxref + +force_update: + +# GNU Make has an annoying habit of putting *all* the Makefile variables +# into the environment, unless you include this target as a circumvention. +# Rumor is that this will be fixed (and this target can be removed) +# in GNU Make 4.0. +.NOEXPORT: + +# GNU Make 3.63 has a different problem: it keeps tacking command line +# overrides onto the definition of $(MAKE). This variable setting +# will remove them. +MAKEOVERRIDES= + +## This is ugly, but I don't want GNU make to put these variables in +## the environment. Older makes will see this as a set of targets +## with no dependencies and no actions. +unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET : + +ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \ + 29k-share/udi/udi2go32.c \ + a29k-tdep.c a68v-nat.c alpha-nat.c alpha-tdep.c \ + altos-xdep.c arm-convert.s \ + arm-tdep.c arm-xdep.c coff-solib.c \ + convex-tdep.c convex-xdep.c \ + core-sol2.c core-regset.c core-aout.c corelow.c \ + dcache.c delta68-nat.c dpx2-nat.c dstread.c exec.c fork-child.c \ + go32-xdep.c gould-tdep.c gould-xdep.c h8300-tdep.c h8500-tdep.c \ + hp300ux-nat.c hppa-tdep.c hppab-nat.c hppah-nat.c \ + hpread.c \ + i386-tdep.c i386b-nat.c i386mach-nat.c i386v-nat.c \ + i386aix-nat.c i386m3-nat.c i386v4-nat.c i386ly-tdep.c \ + i387-tdep.c \ + i960-tdep.c \ + infptrace.c inftarg.c irix4-nat.c irix5-nat.c isi-xdep.c \ + lynx-nat.c m3-nat.c \ + m68k-tdep.c \ + m88k-nat.c m88k-tdep.c mac-nat.c mips-nat.c \ + mips-tdep.c mipsm3-nat.c mipsv4-nat.c news-xdep.c \ + nindy-share/Onindy.c nindy-share/nindy.c \ + nindy-share/ttyflush.c nindy-tdep.c \ + ns32k-tdep.c ns32km3-nat.c osfsolib.c \ + somread.c somsolib.c $(HPREAD_SOURCE) \ + procfs.c pyr-tdep.c pyr-xdep.c \ + remote-adapt.c remote-array.c remote-bug.c remote-e7000.c remote-eb.c \ + remote-es.c remote-hms.c remote-mips.c \ + remote-mm.c remote-nindy.c remote-os9k.c remote-rdp.c remote-sim.c \ + remote-st.c remote-utils.c dcache.c \ + remote-udi.c remote-vx.c remote-vx29k.c \ + rs6000-nat.c rs6000-tdep.c \ + ser-go32.c ser-tcp.c sh-tdep.c solib.c sparc-nat.c \ + sparc-tdep.c sparcl-tdep.c sun3-nat.c sun386-nat.c \ + symm-tdep.c symm-nat.c \ + tahoe-tdep.c ultra3-nat.c ultra3-xdep.c umax-xdep.c \ + vax-tdep.c \ + vx-share/xdr_ld.c vx-share/xdr_ptrace.c vx-share/xdr_rdb.c \ + win32-nat.c \ + xcoffread.c xcoffsolib.c z8k-tdep.c + +ALLCONFIG = config/a29k/a29k-kern.mt config/a29k/a29k-udi.mt config/a29k/vx29k.mt\ + config/a29k/a29k.mt config/a29k/ultra3.mh config/a29k/ultra3.mt \ + config/alpha/alpha-osf1.mh config/alpha/alpha-osf2.mh \ + config/alpha/alpha-osf1.mt config/alpha/alpha-nw.mt \ + config/arm/arm.mh config/arm/arm.mt config/convex/convex.mh \ + config/convex/convex.mt config/gould/np1.mh config/gould/np1.mt \ + config/gould/pn.mh config/gould/pn.mt config/h8300/h8300hms.mt \ + config/h8500/h8500hms.mt config/i386/go32.mh config/i386/i386aix.mh \ + config/i386/i386aix.mt config/i386/i386aout.mt config/i386/i386bsd.mh \ + config/i386/i386bsd.mt config/i386/i386lynx.mh \ + config/i386/i386lynx.mt config/i386/i386m3.mh config/i386/i386m3.mt \ + config/i386/i386mach.mh config/i386/i386mk.mh config/i386/i386mk.mt \ + config/i386/i386nw.mt config/i386/i386sco.mh \ + config/i386/i386sco4.mh \ + config/i386/i386sol2.mh config/i386/i386sol2.mt config/i386/i386v.mh \ + config/i386/i386v.mt config/i386/i386v32.mh config/i386/i386v4.mh \ + config/i386/i386v4.mt config/i386/linux.mh config/i386/linux.mt \ + config/i386/ncr3000.mh config/i386/ncr3000.mt config/i386/ptx.mh \ + config/i386/sun386.mh \ + config/i386/sun386.mt config/i386/symmetry.mh config/i386/symmetry.mt \ + config/i386/win32.mh config/i386/win32.mt \ + config/i960/mon960.mt \ + config/i960/nindy960.mt config/i960/vxworks960.mt config/m68k/3b1.mh \ + config/m68k/3b1.mt config/m68k/altos.mh config/m68k/altos.mt \ + config/m68k/amix.mh config/m68k/amix.mt config/m68k/apollo68b.mh \ + config/m68k/apollo68b.mt \ + config/m68k/apollo68v.mh \ + config/m68k/cisco.mt config/m68k/delta68.mh \ + config/m68k/delta68.mt config/m68k/dpx2.mh config/m68k/dpx2.mt \ + config/m68k/es1800.mt config/m68k/hp300bsd.mh \ + config/m68k/hp300bsd.mt config/m68k/hp300hpux.mh \ + config/m68k/hp300hpux.mt config/m68k/isi.mh config/m68k/isi.mt \ + config/m68k/m68klynx.mh config/m68k/m68klynx.mt \ + config/m68k/monitor.mt \ + config/m68k/news.mh config/m68k/news.mt config/m68k/news1000.mh \ + config/m68k/os68k.mt config/m68k/st2000.mt config/m68k/sun2os3.mh \ + config/m68k/sun2os3.mt config/m68k/sun2os4.mh config/m68k/sun2os4.mt \ + config/m68k/sun3os3.mh config/m68k/sun3os3.mt config/m68k/sun3os4.mh \ + config/m68k/sun3os4.mt config/m68k/vxworks68.mt config/m88k/delta88.mh \ + config/m88k/delta88.mt config/m88k/delta88v4.mh \ + config/m88k/delta88v4.mt config/m88k/m88k.mh config/m88k/m88k.mt \ + config/mips/bigmips.mt config/mips/bigmips64.mt \ + config/mips/decstation.mh \ + config/mips/decstation.mt config/mips/idt.mt config/mips/idtl.mt \ + config/mips/idt64.mt config/mips/idtl64.mt \ + config/mips/irix3.mh config/mips/irix3.mt config/mips/irix4.mh \ + config/mips/irix5.mh config/mips/irix5.mt \ + config/mips/littlemips.mh config/mips/littlemips.mt \ + config/mips/mipsel64.mt \ + config/mips/mipsm3.mh config/mips/mipsm3.mt \ + config/mips/mipsv4.mh config/mips/mipsv4.mt \ + config/mips/news-mips.mh config/mips/riscos.mh \ + config/none/none.mh config/none/none.mt config/ns32k/merlin.mh \ + config/ns32k/merlin.mt config/ns32k/ns32km3.mh config/ns32k/ns32km3.mt \ + config/ns32k/umax.mh config/ns32k/umax.mt \ + config/pa/hppabsd.mh config/pa/hppabsd.mt config/pa/hppahpux.mh \ + config/pa/hppahpux.mt config/pyr/pyramid.mh config/pyr/pyramid.mt \ + config/romp/rtbsd.mh config/rs6000/rs6000.mh config/rs6000/rs6000.mt \ + config/sh/sh.mt config/sparc/sparc-em.mt config/sparc/sparclite.mt \ + config/sparc/sparclynx.mh config/sparc/sparclynx.mt \ + config/sparc/sun4os4.mh config/sparc/sun4os4.mt \ + config/sparc/sun4sol2.mh config/sparc/sun4sol2.mt \ + config/sparc/vxsparc.mt config/tahoe/tahoe.mh config/tahoe/tahoe.mt \ + config/vax/vax.mt config/vax/vaxbsd.mh config/vax/vaxult.mh \ + config/vax/vaxult2.mh config/z8k/z8ksim.mt + + +udip2soc.o: $(srcdir)/29k-share/udi/udip2soc.c $(udiheaders) + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/29k-share/udi/udip2soc.c + +udi2go32.o: $(srcdir)/29k-share/udi/udi2go32.c $(udiheaders) + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/29k-share/udi/udi2go32.c + +udr.o: $(srcdir)/29k-share/udi/udr.c $(udiheaders) + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/29k-share/udi/udr.c + +a29k-tdep.o: a29k-tdep.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) + +a68v-nat.o: a68v-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +alpha-nat.o: alpha-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h + +alpha-tdep.o: alpha-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) $(symtab_h) $(dis-asm.h) gdb_string.h + +altos-xdep.o: altos-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) + +annotate.o: annotate.c $(defs_h) annotate.h $(value_h) target.h $(gdbtypes_h) + +arm-tdep.o: arm-tdep.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) + +bcache.o: bcache.c bcache.h $(defs_h) + +blockframe.o: blockframe.c $(defs_h) $(gdbcore_h) $(inferior_h) \ + objfiles.h symfile.h target.h + +breakpoint.o: breakpoint.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) language.h target.h thread.h gdb_string.h + +buildsym.o: buildsym.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + objfiles.h symfile.h $(symtab_h) gdb_string.h + +callback.o: callback.c $(defs_h) callback.h + +c-lang.o: c-lang.c c-lang.h $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h parser-defs.h $(symtab_h) + +c-typeprint.o: c-typeprint.c c-lang.h $(defs_h) $(expression_h) \ + $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) \ + target.h typeprint.h $(value_h) gdb_string.h + +c-valprint.o: c-valprint.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h $(symtab_h) valprint.h $(value_h) + +f-lang.o: f-lang.c f-lang.h $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h parser-defs.h $(symtab_h) gdb_string.h + +f-typeprint.o: f-typeprint.c f-lang.h $(defs_h) $(expression_h) \ + $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) \ + target.h typeprint.h $(value_h) gdb_string.h + +f-valprint.o: f-valprint.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h $(symtab_h) valprint.h $(value_h) gdb_string.h + +ch-exp.o: ch-exp.c ch-lang.h $(defs_h) language.h parser-defs.h $(bfd_h) symfile.h objfiles.h $(value_h) + +ch-lang.o: ch-lang.c ch-lang.h $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h parser-defs.h $(symtab_h) + +ch-typeprint.o: ch-typeprint.c ch-lang.h $(defs_h) $(expression_h) \ + $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) \ + target.h $(value_h) typeprint.h gdb_string.h + +ch-valprint.o: ch-valprint.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h $(symtab_h) valprint.h $(value_h) c-lang.h + +coff-solib.o: coff-solib.c $(defs_h) + +coffread.o: coffread.c $(bfd_h) $(breakpoint_h) buildsym.h \ + complaints.h $(defs_h) $(expression_h) $(gdbtypes_h) objfiles.h \ + symfile.h $(symtab_h) gdb-stabs.h stabsread.h target.h \ + gdb_string.h + +command.o: command.c $(defs_h) $(expression_h) $(gdbcmd_h) \ + $(gdbtypes_h) $(symtab_h) $(value_h) gdb_string.h $(wait_h) + +complaints.o: complaints.c complaints.h $(defs_h) $(gdbcmd_h) + +convex-tdep.o: convex-tdep.c $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(gdbcore_h) $(inferior_h) + +convex-xdep.o: convex-xdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) + +copying.o: copying.c $(defs_h) $(gdbcmd_h) + +core-aout.o: core-aout.c $(defs_h) $(gdbcore_h) $(value_h) $(inferior_h) + +core-sol2.o: core-sol2.c $(command_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h gdb_string.h + +core-regset.o: core-regset.c $(command_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h gdb_string.h + +corefile.o: corefile.c $(dis-asm_h) $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) target.h language.h gdb_string.h + +corelow.o: corelow.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + target.h thread.h gdb_string.h + +cp-valprint.o: cp-valprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ + $(gdbtypes_h) $(symtab_h) $(value_h) gdb_string.h + +dcache.o: dcache.c $(dcache_h) $(defs_h) $(gdbcmd_h) gdb_string.h + +dbxread.o: dbxread.c $(breakpoint_h) buildsym.h $(command_h) \ + complaints.h $(defs_h) $(expression_h) gdb-stabs.h $(gdbcore_h) \ + $(gdbtypes_h) language.h objfiles.h partial-stab.h stabsread.h \ + symfile.h $(symtab_h) target.h gdb_string.h + +delta68-nat.o: delta68-nat.c $(defs_h) + +demangle.o: demangle.c $(defs_h) $(gdbcmd_h) gdb_string.h + +dpx2-nat.o: dpx2-nat.c $(defs_h) $(gdbcore_h) gdb_string.h + +dstread.o: dstread.c gdb_string.h + +dwarfread.o: dwarfread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + $(expression_h) $(gdbtypes_h) language.h objfiles.h symfile.h \ + $(symtab_h) gdb_string.h + +elfread.o: elfread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + gdb-stabs.h objfiles.h symfile.h $(symtab_h) gdb_string.h + +environ.o: environ.c $(defs_h) environ.h $(gdbcore_h) gdb_string.h + +eval.o: eval.c $(bfd_h) $(defs_h) $(expression_h) $(frame_h) \ + $(gdbtypes_h) language.h $(symtab_h) target.h $(value_h) \ + gdb_string.h + +exec.o: exec.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \ + target.h language.h gdb_string.h + +expprint.o: expprint.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h parser-defs.h $(symtab_h) $(value_h) + +findvar.o: findvar.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \ + gdb_string.h + +fork-child.o: fork-child.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h terminal.h thread.h gdb_string.h + + +gdbtypes.o: gdbtypes.c $(bfd_h) complaints.h $(defs_h) $(expression_h) \ + $(gdbtypes_h) language.h objfiles.h symfile.h $(symtab_h) target.h \ + $(value_h) gdb_string.h + +go32-xdep.o: go32-xdep.c + +gould-tdep.o: gould-tdep.c $(OP_INCLUDE)/np1.h $(defs_h) $(frame_h) \ + $(gdbcore_h) $(symtab_h) + +gould-xdep.o: gould-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) + +h8300-tdep.o: h8300-tdep.c $(defs_h) $(frame_h) $(symtab_h) + +h8500-tdep.o: h8500-tdep.c $(bfd_h) $(dis-asm_h) $(defs_h) \ + $(expression_h) $(frame_h) $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) \ + $(value_h) + +hp300ux-nat.o: hp300ux-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +hppa-tdep.o: hppa-tdep.c $(wait_h) $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) objfiles.h symfile.h target.h + +hppab-nat.o: hppab-nat.c $(bfd_h) $(defs_h) $(inferior_h) target.h +hppah-nat.o: hppah-nat.c $(bfd_h) $(defs_h) $(inferior_h) target.h + +i386-tdep.o: i386-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \ + gdb_string.h + +i386aix-nat.o: i386aix-nat.c $(defs_h) $(frame_h) $(inferior_h) \ + language.h $(gdbcore_h) $(floatformat_h) target.h + +i386b-nat.o: i386b-nat.c $(defs_h) + +i386ly-nat.o: i386ly-nat.c $(defs_h) $(frame_h) $(inferior_h) target.h + +i386ly-tdep.o: i386ly-tdep.c $(defs_h) $(inferior_h) target.h + +i386m3-nat.o: i386m3-nat.c $(defs_h) $(inferior_h) $(floatformat_h) target.h + +i386mach-nat.o: i386mach-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +i386v-nat.o: i386v-nat.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) language.h target.h + +i386v4-nat.o: i386v4-nat.c $(defs_h) + +i387-tdep.o: i387-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) language.h + +i960-tdep.o: i960-tdep.c $(floatformat_h) $(defs_h) $(expression_h) \ + $(frame_h) $(gdbtypes_h) $(symtab_h) $(value_h) + +infcmd.o: infcmd.c $(defs_h) environ.h $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) target.h language.h gdb_string.h + +inflow.o: inflow.c $(bfd_h) $(command_h) $(defs_h) $(inferior_h) \ + signals.h target.h terminal.h thread.h gdb_string.h + +infptrace.o: infptrace.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \ + gdb_string.h $(wait_h) $(command_h) + +infrun.o: infrun.c $(wait_h) $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) target.h thread.h gdb_string.h + +inftarg.o: inftarg.c $(wait_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + target.h terminal.h $(command_h) + +irix4-nat.o: irix4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) +irix5-nat.o: irix5-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) target.h \ + $(symtab_h) symfile.h objfiles.h $(command_h) $(frame_h) gnu-regex.h \ + language.h gdb_string.h + +isi-xdep.o: isi-xdep.c + +language.o: language.c $(bfd_h) $(defs_h) $(expression_h) $(frame_h) \ + $(gdbcmd_h) $(gdbtypes_h) language.h parser-defs.h $(symtab_h) \ + target.h $(value_h) gdb_string.h + +lynx-nat.o: lynx-nat.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcore_h) \ + target.h + +m2-lang.o: m2-lang.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h m2-lang.h parser-defs.h $(symtab_h) + +m2-typeprint.o: m2-typeprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ + $(gdbcore_h) $(gdbtypes_h) language.h m2-lang.h $(symtab_h) target.h \ + $(value_h) gdb_string.h + +m2-valprint.o: m2-valprint.c $(defs_h) $(gdbtypes_h) $(symtab_h) \ + valprint.h + +m3-nat.o: m3-nat.c $(defs_h) $(inferior_h) $(value_h) language.h target.h \ + $(wait_h) $(gdbcmd_h) $(gdbcore_h) + +m68k-tdep.o: m68k-tdep.c $(defs_h) $(frame_h) $(symtab_h) + +m68kly-nat.o: m68kly-nat.c $(defs_h) $(frame_h) $(inferior_h) target.h + +m88k-nat.o: m88k-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +m88k-tdep.o: m88k-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) + +mac-nat.o: mac-nat.c $(defs_h) gdb_string.h + +main.o: main.c top.h $(defs_h) gdb_string.h + +maint.o: maint.c $(defs_h) $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) language.h \ + $(expression_h) objfiles.h symfile.h + +mdebugread.o: mdebugread.c buildsym.h complaints.h $(bfd_h) $(defs_h) \ + $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \ + objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h) \ + gdb_string.h + +mipsm3-nat.o: mipsm3-nat.c $(defs_h) $(inferior_h) + +os9kread.o: os9kread.c buildsym.h complaints.h $(bfd_h) $(defs_h) \ + $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \ + objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h) \ + target.h gdb_string.h + +mem-break.o: mem-break.c $(defs_h) + +minsyms.o: minsyms.c $(bfd_h) $(defs_h) objfiles.h symfile.h \ + $(symtab_h) gdb_string.h + +mips-nat.o: mips-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +mips-tdep.o: mips-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) language.h objfiles.h symfile.h gdb_string.h + +mipsread.o: mipsread.c buildsym.h complaints.h $(bfd_h) $(defs_h) \ + $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \ + objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h) \ + gdb_string.h + +mipsv4-nat.o: mipsv4-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h + +monitor.o: monitor.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h serial.h terminal.h gdb_string.h + +news-xdep.o: news-xdep.c + +Onindy.o: nindy-share/Onindy.c $(wait_h) nindy-share/block_io.h \ + nindy-share/env.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/nindy-share/Onindy.c + +nindy.o: nindy-share/nindy.c $(wait_h) nindy-share/block_io.h \ + nindy-share/env.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/nindy-share/nindy.c + +nlmread.o: nlmread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + gdb-stabs.h objfiles.h symfile.h $(symtab_h) stabsread.h \ + gdb_string.h + +ns32km3-nat.o: ns32km3-nat.c $(defs_h) $(inferior_h) + +ttyflush.o: nindy-share/ttyflush.c + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/nindy-share/ttyflush.c + +nindy-tdep.o: nindy-tdep.c $(defs_h) $(frame_h) $(symtab_h) + +ns32k-tdep.o: ns32k-tdep.c $(bfd_h) $(dis-asm_h) $(defs_h) + +objfiles.o: objfiles.c $(bfd_h) $(defs_h) objfiles.h symfile.h \ + $(symtab_h) gdb_string.h + +osfsolib.o: osfsolib.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + objfiles.h gnu-regex.h symfile.h target.h language.h gdb_string.h + +somread.o: somread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + gdb-stabs.h objfiles.h symfile.h $(symtab_h) gdb_string.h + +somsolib.o: somsolib.c $(defs_h) + +hpread.o: hpread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \ + gdb-stabs.h objfiles.h symfile.h $(symtab_h) gdb_string.h + +parse.o: parse.c $(command_h) $(defs_h) $(expression_h) $(frame_h) \ + $(gdbtypes_h) language.h parser-defs.h $(symtab_h) $(value_h) \ + gdb_string.h + +ppcbug-rom.o: ppcbug-rom.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h serial.h terminal.h + +printcmd.o: printcmd.c $(breakpoint_h) $(defs_h) $(expression_h) \ + $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h objfiles.h \ + symfile.h $(symtab_h) target.h gdb_string.h + +procfs.o: procfs.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + target.h gdb_string.h + +pyr-tdep.o: pyr-tdep.c $(defs_h) + +pyr-xdep.o: pyr-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) + +gnu-regex.o: gnu-regex.c gnu-regex.h $(defs_h) gdb_string.h + +remote-adapt.o: remote-adapt.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h terminal.h gdb_string.h + +remote-arc.o: remote-arc.c gdb_string.h + +remote-array.o: remote-array.c $(wait_h) $(defs_h) $(gdbcore_h) target.h \ + gdb_string.h $(command_h) serial.h monitor.h $(remote_utils_h) + +remote-rdp.o: remote-rdp.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) gdb_string.h + +remote-bug.o: remote-bug.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h terminal.h $(remote_utils_h) gdb_string.h + +remote-e7000.o: remote-e7000.c $(defs_h) $(gdbcore_h) target.h \ + $(wait_h) serial.h gdb_string.h + +remote-eb.o: remote-eb.c $(wait_h) $(srcdir)/config/a29k/tm-a29k.h \ + $(defs_h) $(gdbcore_h) $(inferior_h) symfile.h target.h terminal.h \ + gdb_string.h + +remote-es.o: remote-es.c $(bfd_h) $(wait_h) $(command_h) $(defs_h) \ + $(inferior_h) $(remote_utils_h) terminal.h gdb_string.h + +remote-hms.o: remote-hms.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) serial.h target.h terminal.h gdb_string.h + +remote-mips.o: remote-mips.c $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(gdbcore_h) $(inferior_h) serial.h symfile.h target.h + +remote-mm.o: remote-mm.c $(bfd_h) $(wait_h) $(defs_h) $(inferior_h) \ + minimon.h target.h terminal.h gdb_string.h + +remote-nindy.o: remote-nindy.c $(floatformat_h) $(wait_h) $(command_h) \ + $(defs_h) $(gdbcore_h) $(inferior_h) \ + nindy-share/env.h nindy-share/stop.h $(remote_utils_h) \ + symfile.h + +remote-os9k.o: remote-os9k.c $(defs_h) $(gdbcore_h) $(wait_h) \ + $(command_h) monitor.h $(remote_utils_h) $(symtab_h) symfile.h \ + objfiles.h gdb-stabs.h gdb_string.h + +remote-sim.o: remote-sim.c $(wait_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) target.h terminal.h gdb_string.h + +remote-st.o: remote-st.c $(wait_h) $(defs_h) $(gdbcore_h) serial.h \ + target.h gdb_string.h + +remote-udi.o: remote-udi.c $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h terminal.h $(udiheaders) gdb_string.h + +remote-vx.o: remote-vx.c $(wait_h) complaints.h $(defs_h) $(gdbcmd_h) \ + $(gdbcore_h) $(inferior_h) target.h vx-share/dbgRpcLib.h \ + vx-share/ptrace.h vx-share/xdr_ld.h vx-share/xdr_ptrace.h \ + vx-share/xdr_rdb.h gdb-stabs.h objfiles.h symfile.h $(bfd_h) \ + gdb_string.h + +remote-vx29k.o: remote-vx29k.c $(wait_h) complaints.h $(defs_h) $(gdbcmd_h) \ + $(gdbcore_h) $(inferior_h) target.h vx-share/dbgRpcLib.h \ + vx-share/ptrace.h vx-share/xdr_ld.h vx-share/xdr_ptrace.h \ + vx-share/xdr_rdb.h gdb_string.h + +remote-utils.o: remote-utils.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + $(inferior_h) $(remote_utils_h) gdb_string.h + +remote.o: remote.c $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) $(remote_utils_h) symfile.h terminal.h gdb_string.h + +remote-nrom.o: remote-nrom.c $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) $(remote_utils_h) symfile.h terminal.h + +rom68k-rom.o: rom68k-rom.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h serial.h terminal.h + +rs6000-nat.o: rs6000-nat.c $(bfd_h) $(defs_h) $(inferior_h) target.h + +rs6000-tdep.o: rs6000-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) \ + target.h xcoffsolib.h + +scm-exp.o: $(defs_h) $(value_h) parser-defs.h language.h c-lang.h \ + scm-lang.h scm-tags.h + +scm-lang.o: $(defs_h) $(value_h) parser-defs.h language.h c-lang.h \ + scm-lang.h scm-tags.h gdb_string.h + +scm-valprint.o: $(defs_h) $(value_h) parser-defs.h language.h \ + scm-lang.h valprint.h + +ser-go32.o: ser-go32.c $(defs_h) serial.h + +ser-mac.o: ser-mac.c $(defs_h) serial.h signals.h + +ser-tcp.o: ser-tcp.c $(defs_h) serial.h signals.h gdb_string.h + +ser-unix.o: ser-unix.c $(defs_h) serial.h + +serial.o: serial.c $(defs_h) serial.h gdb_string.h + +sh-tdep.o: sh-tdep.c $(bfd_h) $(dis-asm_h) \ + $(srcdir)/../opcodes/sh-opc.h $(defs_h) $(expression_h) $(frame_h) \ + $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) $(value_h) + +sh3-rom.o: sh3-rom.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h serial.h terminal.h + +mon960-rom.o: mon960-rom.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ + $(inferior_h) target.h serial.h terminal.h + +solib.o: solib.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ + objfiles.h gnu-regex.h symfile.h target.h gdb_string.h + +source.o: source.c $(defs_h) $(expression_h) $(frame_h) $(gdbcmd_h) \ + $(gdbcore_h) language.h objfiles.h gnu-regex.h symfile.h $(symtab_h) \ + gdb_string.h + +sparc-nat.o: sparc-nat.c $(bfd_h) $(defs_h) $(inferior_h) $(gdbcore_h) \ + target.h + +sparc-tdep.o: sparc-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) objfiles.h symfile.h target.h + +sparcl-tdep.o: sparcl-tdep.c $(defs_h) $(gdbcore_h) target.h + +dsrec.o: dsrec.c $(defs_h) srec.h + +stabsread.o: stabsread.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \ + $(INCLUDE_DIR)/aout/stab_gnu.h buildsym.h complaints.h $(defs_h) \ + $(gdbtypes_h) objfiles.h stabsread.h symfile.h $(symtab_h) \ + gdb_string.h + +stack.o: stack.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \ + language.h target.h gdb_string.h + +sun3-nat.o: sun3-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) +sun386-nat.o: sun386-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) + +symfile.o: symfile.c $(breakpoint_h) complaints.h $(defs_h) \ + $(expression_h) $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) \ + language.h objfiles.h symfile.h $(symtab_h) target.h \ + gdb_string.h + +symm-tdep.o: symm-tdep.c $(defs_h) $(gdbcore_h) $(inferior_h) +symm-nat.o: symm-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) + +symmisc.o: symmisc.c $(bfd_h) $(breakpoint_h) $(command_h) $(defs_h) \ + $(expression_h) $(gdbtypes_h) language.h objfiles.h symfile.h \ + $(symtab_h) gdb_string.h + +symtab.o: symtab.c call-cmds.h $(defs_h) $(expression_h) $(frame_h) \ + $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h objfiles.h \ + gnu-regex.h symfile.h $(symtab_h) target.h $(value_h) \ + gdb_string.h + +tahoe-tdep.o: tahoe-tdep.c $(OP_INCLUDE)/tahoe.h $(defs_h) \ + $(symtab_h) + +target.o: target.c $(bfd_h) $(defs_h) $(gdbcmd_h) $(inferior_h) \ + objfiles.h symfile.h target.h gdb_string.h + +thread.o: thread.c $(defs_h) thread.h $(gdbcmd_h) + +top.o: top.c top.h $(bfd_h) $(getopt_h) $(readline_headers) call-cmds.h \ + $(defs_h) $(gdbcmd_h) $(inferior_h) language.h signals.h \ + $(remote_utils_h) gdb_string.h + +typeprint.o: typeprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ + $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) target.h \ + $(value_h) gdb_string.h + +ultra3-nat.o: ultra3-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) +ultra3-xdep.o: ultra3-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) +umax-xdep.o: umax-xdep.c $(defs_h) $(gdbcore_h) $(inferior_h) + +utils.o: utils.c $(bfd_h) $(defs_h) $(expression_h) $(gdbcmd_h) \ + language.h signals.h target.h terminal.h $(readline_headers) \ + gdb_string.h + +valarith.o: valarith.c $(bfd_h) $(defs_h) $(expression_h) \ + $(gdbtypes_h) language.h $(symtab_h) target.h $(value_h) \ + gdb_string.h + +valops.o: valops.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \ + gdb_string.h + +valprint.o: valprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ + $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) target.h \ + $(value_h) gdb_string.h + +values.o: values.c $(defs_h) $(expression_h) $(frame_h) $(gdbcmd_h) \ + $(gdbcore_h) $(gdbtypes_h) $(symtab_h) target.h $(value_h) \ + gdb_string.h scm-lang.h + +vax-tdep.o: vax-tdep.c $(OP_INCLUDE)/vax.h $(defs_h) $(symtab_h) + +w65-tdep.o : w65-tdep.c + +win32-nat.o: win32-nat.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) \ + gdb_string.h + +xdr_ld.o: vx-share/xdr_ld.c $(defs_h) vx-share/vxTypes.h \ + vx-share/vxWorks.h vx-share/xdr_ld.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/vx-share/xdr_ld.c + +xdr_ptrace.o: vx-share/xdr_ptrace.c $(defs_h) vx-share/vxTypes.h \ + vx-share/vxWorks.h vx-share/xdr_ptrace.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/vx-share/xdr_ptrace.c + +xdr_rdb.o: vx-share/xdr_rdb.c $(defs_h) vx-share/vxTypes.h \ + vx-share/vxWorks.h vx-share/xdr_rdb.h + $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/vx-share/xdr_rdb.c + +xcoffread.o: xcoffread.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \ + $(INCLUDE_DIR)/aout/stab_gnu.h $(INCLUDE_DIR)/coff/internal.h \ + $(INCLUDE_DIR)/coff/rs6000.h $(BFD_SRC)/libcoff.h buildsym.h \ + complaints.h $(defs_h) $(gdbtypes_h) objfiles.h stabsread.h symfile.h \ + $(symtab_h) partial-stab.h gdb_string.h + +xcoffsolib.o: xcoffsolib.c $(bfd_h) $(defs_h) xcoffsolib.h + +z8k-tdep.o: z8k-tdep.c $(bfd_h) $(dis-asm_h) $(defs_h) $(frame_h) \ + $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) + +c-exp.tab.o: c-exp.tab.c c-lang.h $(defs_h) $(expression_h) \ + $(gdbtypes_h) language.h parser-defs.h $(symtab_h) $(value_h) \ + $(bfd_h) objfiles.h symfile.h + +f-exp.tab.o: f-exp.tab.c f-lang.h $(defs_h) $(expression_h) \ + language.h parser-defs.h $(value_h) $(bfd_h) objfiles.h symfile.h + +m2-exp.tab.o: m2-exp.tab.c $(defs_h) $(expression_h) $(gdbtypes_h) \ + language.h m2-lang.h parser-defs.h $(symtab_h) $(value_h) \ + $(bfd_h) objfiles.h symfile.h + +### end of the gdb Makefile.in. diff --git a/contrib/gdb/gdb/NEWS b/contrib/gdb/gdb/NEWS new file mode 100644 index 000000000000..979a878e4daa --- /dev/null +++ b/contrib/gdb/gdb/NEWS @@ -0,0 +1,1338 @@ + What has changed in GDB? + (Organized release by release) + +*** Changes in GDB-4.16: + +* New native configurations + +Windows 95, x86 Windows NT i[345]86-*-cygwin32 +M68K NetBSD m68k-*-netbsd* +PowerPC AIX 4.x powerpc-*-aix* +PowerPC MacOS powerpc-*-macos* +PowerPC Windows NT powerpcle-*-cygwin32 +RS/6000 AIX 4.x rs6000-*-aix4* + +* New targets + +ARM with RDP protocol arm-*-* +I960 with MON960 i960-*-coff +MIPS VxWorks mips*-*-vxworks* +MIPS VR4300 with PMON mips64*vr4300{,el}-*-elf* +PowerPC with PPCBUG monitor powerpc{,le}-*-eabi* +Hitachi SH3 sh-*-* +Matra Sparclet sparclet-*-* + +* PowerPC simulator + +The powerpc-eabi configuration now includes the PSIM simulator, +contributed by Andrew Cagney, with assistance from Mike Meissner. +PSIM is a very elaborate model of the PowerPC, including not only +basic instruction set execution, but also details of execution unit +performance and I/O hardware. See sim/ppc/README for more details. + +* Solaris 2.5 + +GDB now works with Solaris 2.5. + +* Windows 95/NT native + +GDB will now work as a native debugger on Windows 95 and Windows NT. +To build it from source, you must use the "gnu-win32" environment, +which uses a DLL to emulate enough of Unix to run the GNU tools. +Further information, binaries, and sources are available at +ftp.cygnus.com, under pub/gnu-win32. + +* dont-repeat command + +If a user-defined command includes the command `dont-repeat', then the +command will not be repeated if the user just types return. This is +useful if the command is time-consuming to run, so that accidental +extra keystrokes don't run the same command many times. + +* Send break instead of ^C + +The standard remote protocol now includes an option to send a break +rather than a ^C to the target in order to interrupt it. By default, +GDB will send ^C; to send a break, set the variable `remotebreak' to 1. + +* Remote protocol timeout + +The standard remote protocol includes a new variable `remotetimeout' +that allows you to set the number of seconds before GDB gives up trying +to read from the target. The default value is 2. + +* Automatic tracking of dynamic object loading (HPUX and Solaris only) + +By default GDB will automatically keep track of objects as they are +loaded and unloaded by the dynamic linker. By using the command `set +stop-on-solib-events 1' you can arrange for GDB to stop the inferior +when shared library events occur, thus allowing you to set breakpoints +in shared libraries which are explicitly loaded by the inferior. + +Note this feature does not work on hpux8. On hpux9 you must link +/usr/lib/end.o into your program. This feature should work +automatically on hpux10. + +* Irix 5.x hardware watchpoint support + +Irix 5 configurations now support the use of hardware watchpoints. + +* Mips protocol "SYN garbage limit" + +When debugging a Mips target using the `target mips' protocol, you +may set the number of characters that GDB will ignore by setting +the `syn-garbage-limit'. A value of -1 means that GDB will ignore +every character. The default value is 1050. + +* Recording and replaying remote debug sessions + +If you set `remotelogfile' to the name of a file, gdb will write to it +a recording of a remote debug session. This recording may then be +replayed back to gdb using "gdbreplay". See gdbserver/README for +details. This is useful when you have a problem with GDB while doing +remote debugging; you can make a recording of the session and send it +to someone else, who can then recreate the problem. + +* Speedups for remote debugging + +GDB includes speedups for downloading and stepping MIPS systems using +the IDT monitor, fast downloads to the Hitachi SH E7000 emulator, +and more efficient S-record downloading. + +* Memory use reductions and statistics collection + +GDB now uses less memory and reports statistics about memory usage. +Try the `maint print statistics' command, for example. + +*** Changes in GDB-4.15: + +* Psymtabs for XCOFF + +The symbol reader for AIX GDB now uses partial symbol tables. This +can greatly improve startup time, especially for large executables. + +* Remote targets use caching + +Remote targets now use a data cache to speed up communication with the +remote side. The data cache could lead to incorrect results because +it doesn't know about volatile variables, thus making it impossible to +debug targets which use memory mapped I/O devices. `set remotecache +off' turns the the data cache off. + +* Remote targets may have threads + +The standard remote protocol now includes support for multiple threads +in the target system, using new protocol commands 'H' and 'T'. See +gdb/remote.c for details. + +* NetROM support + +If GDB is configured with `--enable-netrom', then it will include +support for the NetROM ROM emulator from XLNT Designs. The NetROM +acts as though it is a bank of ROM on the target board, but you can +write into it over the network. GDB's support consists only of +support for fast loading into the emulated ROM; to debug, you must use +another protocol, such as standard remote protocol. The usual +sequence is something like + + target nrom + load + target remote :1235 + +* Macintosh host + +GDB now includes support for the Apple Macintosh, as a host only. It +may be run as either an MPW tool or as a standalone application, and +it can debug through the serial port. All the usual GDB commands are +available, but to the target command, you must supply "serial" as the +device type instead of "/dev/ttyXX". See mpw-README in the main +directory for more information on how to build. The MPW configuration +scripts */mpw-config.in support only a few targets, and only the +mips-idt-ecoff target has been tested. + +* Autoconf + +GDB configuration now uses autoconf. This is not user-visible, +but does simplify configuration and building. + +* hpux10 + +GDB now supports hpux10. + +*** Changes in GDB-4.14: + +* New native configurations + +x86 FreeBSD i[345]86-*-freebsd +x86 NetBSD i[345]86-*-netbsd +NS32k NetBSD ns32k-*-netbsd +Sparc NetBSD sparc-*-netbsd + +* New targets + +A29K VxWorks a29k-*-vxworks +HP PA PRO embedded (WinBond W89K & Oki OP50N) hppa*-*-pro* +CPU32 EST-300 emulator m68*-*-est* +PowerPC ELF powerpc-*-elf +WDC 65816 w65-*-* + +* Alpha OSF/1 support for procfs + +GDB now supports procfs under OSF/1-2.x and higher, which makes it +possible to attach to running processes. As the mounting of the /proc +filesystem is optional on the Alpha, GDB automatically determines +the availability of /proc during startup. This can lead to problems +if /proc is unmounted after GDB has been started. + +* Arguments to user-defined commands + +User commands may accept up to 10 arguments separated by whitespace. +Arguments are accessed within the user command via $arg0..$arg9. A +trivial example: +define adder + print $arg0 + $arg1 + $arg2 + +To execute the command use: +adder 1 2 3 + +Defines the command "adder" which prints the sum of its three arguments. +Note the arguments are text substitutions, so they may reference variables, +use complex expressions, or even perform inferior function calls. + +* New `if' and `while' commands + +This makes it possible to write more sophisticated user-defined +commands. Both commands take a single argument, which is the +expression to evaluate, and must be followed by the commands to +execute, one per line, if the expression is nonzero, the list being +terminated by the word `end'. The `if' command list may include an +`else' word, which causes the following commands to be executed only +if the expression is zero. + +* Fortran source language mode + +GDB now includes partial support for Fortran 77. It will recognize +Fortran programs and can evaluate a subset of Fortran expressions, but +variables and functions may not be handled correctly. GDB will work +with G77, but does not yet know much about symbols emitted by other +Fortran compilers. + +* Better HPUX support + +Most debugging facilities now work on dynamic executables for HPPAs +running hpux9 or later. You can attach to running dynamically linked +processes, but by default the dynamic libraries will be read-only, so +for instance you won't be able to put breakpoints in them. To change +that behavior do the following before running the program: + + adb -w a.out + __dld_flags?W 0x5 + control-d + +This will cause the libraries to be mapped private and read-write. +To revert to the normal behavior, do this: + + adb -w a.out + __dld_flags?W 0x4 + control-d + +You cannot set breakpoints or examine data in the library until after +the library is loaded if the function/data symbols do not have +external linkage. + +GDB can now also read debug symbols produced by the HP C compiler on +HPPAs (sorry, no C++, Fortran or 68k support). + +* Target byte order now dynamically selectable + +You can choose which byte order to use with a target system, via the +commands "set endian big" and "set endian little", and you can see the +current setting by using "show endian". You can also give the command +"set endian auto", in which case GDB will use the byte order +associated with the executable. Currently, only embedded MIPS +configurations support dynamic selection of target byte order. + +* New DOS host serial code + +This version uses DPMI interrupts to handle buffered I/O, so you +no longer need to run asynctsr when debugging boards connected to +a PC's serial port. + +*** Changes in GDB-4.13: + +* New "complete" command + +This lists all the possible completions for the rest of the line, if it +were to be given as a command itself. This is intended for use by emacs. + +* Trailing space optional in prompt + +"set prompt" no longer adds a space for you after the prompt you set. This +allows you to set a prompt which ends in a space or one that does not. + +* Breakpoint hit counts + +"info break" now displays a count of the number of times the breakpoint +has been hit. This is especially useful in conjunction with "ignore"; you +can ignore a large number of breakpoint hits, look at the breakpoint info +to see how many times the breakpoint was hit, then run again, ignoring one +less than that number, and this will get you quickly to the last hit of +that breakpoint. + +* Ability to stop printing at NULL character + +"set print null-stop" will cause GDB to stop printing the characters of +an array when the first NULL is encountered. This is useful when large +arrays actually contain only short strings. + +* Shared library breakpoints + +In SunOS 4.x, SVR4, and Alpha OSF/1 configurations, you can now set +breakpoints in shared libraries before the executable is run. + +* Hardware watchpoints + +There is a new hardware breakpoint for the watch command for sparclite +targets. See gdb/sparclite/hw_breakpoint.note. + +Hardware watchpoints are also now supported under Linux. + +* Annotations + +Annotations have been added. These are for use with graphical interfaces, +and are still experimental. Currently only gdba.el uses these. + +* Improved Irix 5 support + +GDB now works properly with Irix 5.2. + +* Improved HPPA support + +GDB now works properly with the latest GCC and GAS. + +* New native configurations + +Sequent PTX4 i[34]86-sequent-ptx4 +HPPA running OSF/1 hppa*-*-osf* +Atari TT running SVR4 m68*-*-sysv4* +RS/6000 LynxOS rs6000-*-lynxos* + +* New targets + +OS/9000 i[34]86-*-os9k +MIPS R4000 mips64*{,el}-*-{ecoff,elf} +Sparc64 sparc64-*-* + +* Hitachi SH7000 and E7000-PC ICE support + +There is now support for communicating with the Hitachi E7000-PC ICE. +This is available automatically when GDB is configured for the SH. + +* Fixes + +As usual, a variety of small fixes and improvements, both generic +and configuration-specific. See the ChangeLog for more detail. + +*** Changes in GDB-4.12: + +* Irix 5 is now supported + +* HPPA support + +GDB-4.12 on the HPPA has a number of changes which make it unable +to debug the output from the currently released versions of GCC and +GAS (GCC 2.5.8 and GAS-2.2 or PAGAS-1.36). Until the next major release +of GCC and GAS, versions of these tools designed to work with GDB-4.12 +can be retrieved via anonymous ftp from jaguar.cs.utah.edu:/dist. + + +*** Changes in GDB-4.11: + +* User visible changes: + +* Remote Debugging + +The "set remotedebug" option is now consistent between the mips remote +target, remote targets using the gdb-specific protocol, UDI (AMD's +debug protocol for the 29k) and the 88k bug monitor. It is now an +integer specifying a debug level (normally 0 or 1, but 2 means more +debugging info for the mips target). + +* DEC Alpha native support + +GDB now works on the DEC Alpha. GCC 2.4.5 does not produce usable +debug info, but GDB works fairly well with the DEC compiler and should +work with a future GCC release. See the README file for a few +Alpha-specific notes. + +* Preliminary thread implementation + +GDB now has preliminary thread support for both SGI/Irix and LynxOS. + +* LynxOS native and target support for 386 + +This release has been hosted on LynxOS 2.2, and also can be configured +to remotely debug programs running under LynxOS (see gdb/gdbserver/README +for details). + +* Improvements in C++ mangling/demangling. + +This release has much better g++ debugging, specifically in name +mangling/demangling, virtual function calls, print virtual table, +call methods, ...etc. + +*** Changes in GDB-4.10: + + * User visible changes: + +Remote debugging using the GDB-specific (`target remote') protocol now +supports the `load' command. This is only useful if you have some +other way of getting the stub to the target system, and you can put it +somewhere in memory where it won't get clobbered by the download. + +Filename completion now works. + +When run under emacs mode, the "info line" command now causes the +arrow to point to the line specified. Also, "info line" prints +addresses in symbolic form (as well as hex). + +All vxworks based targets now support a user settable option, called +vxworks-timeout. This option represents the number of seconds gdb +should wait for responses to rpc's. You might want to use this if +your vxworks target is, perhaps, a slow software simulator or happens +to be on the far side of a thin network line. + + * DEC alpha support + +This release contains support for using a DEC alpha as a GDB host for +cross debugging. Native alpha debugging is not supported yet. + + +*** Changes in GDB-4.9: + + * Testsuite + +This is the first GDB release which is accompanied by a matching testsuite. +The testsuite requires installation of dejagnu, which should be available +via ftp from most sites that carry GNU software. + + * C++ demangling + +'Cfront' style demangling has had its name changed to 'ARM' style, to +emphasize that it was written from the specifications in the C++ Annotated +Reference Manual, not necessarily to be compatible with AT&T cfront. Despite +disclaimers, it still generated too much confusion with users attempting to +use gdb with AT&T cfront. + + * Simulators + +GDB now uses a standard remote interface to a simulator library. +So far, the library contains simulators for the Zilog Z8001/2, the +Hitachi H8/300, H8/500 and Super-H. + + * New targets supported + +H8/300 simulator h8300-hitachi-hms or h8300hms +H8/500 simulator h8500-hitachi-hms or h8500hms +SH simulator sh-hitachi-hms or sh +Z8000 simulator z8k-zilog-none or z8ksim +IDT MIPS board over serial line mips-idt-ecoff + +Cross-debugging to GO32 targets is supported. It requires a custom +version of the i386-stub.c module which is integrated with the +GO32 memory extender. + + * New remote protocols + +MIPS remote debugging protocol. + + * New source languages supported + +This version includes preliminary support for Chill, a Pascal like language +used by telecommunications companies. Chill support is also being integrated +into the GNU compiler, but we don't know when it will be publically available. + + +*** Changes in GDB-4.8: + + * HP Precision Architecture supported + +GDB now supports HP PA-RISC machines running HPUX. A preliminary +version of this support was available as a set of patches from the +University of Utah. GDB does not support debugging of programs +compiled with the HP compiler, because HP will not document their file +format. Instead, you must use GCC (version 2.3.2 or later) and PA-GAS +(as available from jaguar.cs.utah.edu:/dist/pa-gas.u4.tar.Z). + +Many problems in the preliminary version have been fixed. + + * Faster and better demangling + +We have improved template demangling and fixed numerous bugs in the GNU style +demangler. It can now handle type modifiers such as `static' or `const'. Wide +character types (wchar_t) are now supported. Demangling of each symbol is now +only done once, and is cached when the symbol table for a file is read in. +This results in a small increase in memory usage for C programs, a moderate +increase in memory usage for C++ programs, and a fantastic speedup in +symbol lookups. + +`Cfront' style demangling still doesn't work with AT&T cfront. It was written +from the specifications in the Annotated Reference Manual, which AT&T's +compiler does not actually implement. + + * G++ multiple inheritance compiler problem + +In the 2.3.2 release of gcc/g++, how the compiler resolves multiple +inheritance lattices was reworked to properly discover ambiguities. We +recently found an example which causes this new algorithm to fail in a +very subtle way, producing bad debug information for those classes. +The file 'gcc.patch' (in this directory) can be applied to gcc to +circumvent the problem. A future GCC release will contain a complete +fix. + +The previous G++ debug info problem (mentioned below for the gdb-4.7 +release) is fixed in gcc version 2.3.2. + + * Improved configure script + +The `configure' script will now attempt to guess your system type if +you don't supply a host system type. The old scheme of supplying a +host system triplet is preferable over using this. All the magic is +done in the new `config.guess' script. Examine it for details. + +We have also brought our configure script much more in line with the FSF's +version. It now supports the --with-xxx options. In particular, +`--with-minimal-bfd' can be used to make the GDB binary image smaller. +The resulting GDB will not be able to read arbitrary object file formats -- +only the format ``expected'' to be used on the configured target system. +We hope to make this the default in a future release. + + * Documentation improvements + +There's new internal documentation on how to modify GDB, and how to +produce clean changes to the code. We implore people to read it +before submitting changes. + +The GDB manual uses new, sexy Texinfo conditionals, rather than arcane +M4 macros. The new texinfo.tex is provided in this release. Pre-built +`info' files are also provided. To build `info' files from scratch, +you will need the latest `makeinfo' release, which will be available in +a future texinfo-X.Y release. + +*NOTE* The new texinfo.tex can cause old versions of TeX to hang. +We're not sure exactly which versions have this problem, but it has +been seen in 3.0. We highly recommend upgrading to TeX version 3.141 +or better. If that isn't possible, there is a patch in +`texinfo/tex3patch' that will modify `texinfo/texinfo.tex' to work +around this problem. + + * New features + +GDB now supports array constants that can be used in expressions typed in by +the user. The syntax is `{element, element, ...}'. Ie: you can now type +`print {1, 2, 3}', and it will build up an array in memory malloc'd in +the target program. + +The new directory `gdb/sparclite' contains a program that demonstrates +how the sparc-stub.c remote stub runs on a Fujitsu SPARClite processor. + + * New native hosts supported + +HP/PA-RISC under HPUX using GNU tools hppa1.1-hp-hpux +386 CPUs running SCO Unix 3.2v4 i386-unknown-sco3.2v4 + + * New targets supported + +AMD 29k family via UDI a29k-amd-udi or udi29k + + * New file formats supported + +BFD now supports reading HP/PA-RISC executables (SOM file format?), +HPUX core files, and SCO 3.2v2 core files. + + * Major bug fixes + +Attaching to processes now works again; thanks for the many bug reports. + +We have also stomped on a bunch of core dumps caused by +printf_filtered("%s") problems. + +We eliminated a copyright problem on the rpc and ptrace header files +for VxWorks, which was discovered at the last minute during the 4.7 +release. You should now be able to build a VxWorks GDB. + +You can now interrupt gdb while an attached process is running. This +will cause the attached process to stop, and give control back to GDB. + +We fixed problems caused by using too many file descriptors +for reading symbols from object files and libraries. This was +especially a problem for programs that used many (~100) shared +libraries. + +The `step' command now only enters a subroutine if there is line number +information for the subroutine. Otherwise it acts like the `next' +command. Previously, `step' would enter subroutines if there was +any debugging information about the routine. This avoids problems +when using `cc -g1' on MIPS machines. + + * Internal improvements + +GDB's internal interfaces have been improved to make it easier to support +debugging of multiple languages in the future. + +GDB now uses a common structure for symbol information internally. +Minimal symbols (derived from linkage symbols in object files), partial +symbols (from a quick scan of debug information), and full symbols +contain a common subset of information, making it easier to write +shared code that handles any of them. + + * New command line options + +We now accept --silent as an alias for --quiet. + + * Mmalloc licensing + +The memory-mapped-malloc library is now licensed under the GNU Library +General Public License. + +*** Changes in GDB-4.7: + + * Host/native/target split + +GDB has had some major internal surgery to untangle the support for +hosts and remote targets. Now, when you configure GDB for a remote +target, it will no longer load in all of the support for debugging +local programs on the host. When fully completed and tested, this will +ensure that arbitrary host/target combinations are possible. + +The primary conceptual shift is to separate the non-portable code in +GDB into three categories. Host specific code is required any time GDB +is compiled on that host, regardless of the target. Target specific +code relates to the peculiarities of the target, but can be compiled on +any host. Native specific code is everything else: it can only be +built when the host and target are the same system. Child process +handling and core file support are two common `native' examples. + +GDB's use of /proc for controlling Unix child processes is now cleaner. +It has been split out into a single module under the `target_ops' vector, +plus two native-dependent functions for each system that uses /proc. + + * New hosts supported + +HP/Apollo 68k (under the BSD domain) m68k-apollo-bsd or apollo68bsd +386 CPUs running various BSD ports i386-unknown-bsd or 386bsd +386 CPUs running SCO Unix i386-unknown-scosysv322 or i386sco + + * New targets supported + +Fujitsu SPARClite sparclite-fujitsu-none or sparclite +68030 and CPU32 m68030-*-*, m68332-*-* + + * New native hosts supported + +386 CPUs running various BSD ports i386-unknown-bsd or 386bsd + (386bsd is not well tested yet) +386 CPUs running SCO Unix i386-unknown-scosysv322 or sco + + * New file formats supported + +BFD now supports COFF files for the Zilog Z8000 microprocessor. It +supports reading of `a.out.adobe' object files, which are an a.out +format extended with minimal information about multiple sections. + + * New commands + +`show copying' is the same as the old `info copying'. +`show warranty' is the same as `info warrantee'. +These were renamed for consistency. The old commands continue to work. + +`info handle' is a new alias for `info signals'. + +You can now define pre-command hooks, which attach arbitrary command +scripts to any command. The commands in the hook will be executed +prior to the user's command. You can also create a hook which will be +executed whenever the program stops. See gdb.texinfo. + + * C++ improvements + +We now deal with Cfront style name mangling, and can even extract type +info from mangled symbols. GDB can automatically figure out which +symbol mangling style your C++ compiler uses. + +Calling of methods and virtual functions has been improved as well. + + * Major bug fixes + +The crash that occured when debugging Sun Ansi-C compiled binaries is +fixed. This was due to mishandling of the extra N_SO stabs output +by the compiler. + +We also finally got Ultrix 4.2 running in house, and fixed core file +support, with help from a dozen people on the net. + +John M. Farrell discovered that the reason that single-stepping was so +slow on all of the Mips based platforms (primarily SGI and DEC) was +that we were trying to demangle and lookup a symbol used for internal +purposes on every instruction that was being stepped through. Changing +the name of that symbol so that it couldn't be mistaken for a C++ +mangled symbol sped things up a great deal. + +Rich Pixley sped up symbol lookups in general by getting much smarter +about when C++ symbol mangling is necessary. This should make symbol +completion (TAB on the command line) much faster. It's not as fast as +we'd like, but it's significantly faster than gdb-4.6. + + * AMD 29k support + +A new user controllable variable 'call_scratch_address' can +specify the location of a scratch area to be used when GDB +calls a function in the target. This is necessary because the +usual method of putting the scratch area on the stack does not work +in systems that have separate instruction and data spaces. + +We integrated changes to support the 29k UDI (Universal Debugger +Interface), but discovered at the last minute that we didn't have all +of the appropriate copyright paperwork. We are working with AMD to +resolve this, and hope to have it available soon. + + * Remote interfaces + +We have sped up the remote serial line protocol, especially for targets +with lots of registers. It now supports a new `expedited status' ('T') +message which can be used in place of the existing 'S' status message. +This allows the remote stub to send only the registers that GDB +needs to make a quick decision about single-stepping or conditional +breakpoints, eliminating the need to fetch the entire register set for +each instruction being stepped through. + +The GDB remote serial protocol now implements a write-through cache for +registers, only re-reading the registers if the target has run. + +There is also a new remote serial stub for SPARC processors. You can +find it in gdb-4.7/gdb/sparc-stub.c. This was written to support the +Fujitsu SPARClite processor, but will run on any stand-alone SPARC +processor with a serial port. + + * Configuration + +Configure.in files have become much easier to read and modify. A new +`table driven' format makes it more obvious what configurations are +supported, and what files each one uses. + + * Library changes + +There is a new opcodes library which will eventually contain all of the +disassembly routines and opcode tables. At present, it only contains +Sparc and Z8000 routines. This will allow the assembler, debugger, and +disassembler (binutils/objdump) to share these routines. + +The libiberty library is now copylefted under the GNU Library General +Public License. This allows more liberal use, and was done so libg++ +can use it. This makes no difference to GDB, since the Library License +grants all the rights from the General Public License. + + * Documentation + +The file gdb-4.7/gdb/doc/stabs.texinfo is a (relatively) complete +reference to the stabs symbol info used by the debugger. It is (as far +as we know) the only published document on this fascinating topic. We +encourage you to read it, compare it to the stabs information on your +system, and send improvements on the document in general (to +bug-gdb@prep.ai.mit.edu). + +And, of course, many bugs have been fixed. + + +*** Changes in GDB-4.6: + + * Better support for C++ function names + +GDB now accepts as input the "demangled form" of C++ overloaded function +names and member function names, and can do command completion on such names +(using TAB, TAB-TAB, and ESC-?). The names have to be quoted with a pair of +single quotes. Examples are 'func (int, long)' and 'obj::operator==(obj&)'. +Make use of command completion, it is your friend. + +GDB also now accepts a variety of C++ mangled symbol formats. They are +the GNU g++ style, the Cfront (ARM) style, and the Lucid (lcc) style. +You can tell GDB which format to use by doing a 'set demangle-style {gnu, +lucid, cfront, auto}'. 'gnu' is the default. Do a 'set demangle-style foo' +for the list of formats. + + * G++ symbol mangling problem + +Recent versions of gcc have a bug in how they emit debugging information for +C++ methods (when using dbx-style stabs). The file 'gcc.patch' (in this +directory) can be applied to gcc to fix the problem. Alternatively, if you +can't fix gcc, you can #define GCC_MANGLE_BUG when compling gdb/symtab.c. The +usual symptom is difficulty with setting breakpoints on methods. GDB complains +about the method being non-existent. (We believe that version 2.2.2 of GCC has +this problem.) + + * New 'maintenance' command + +All of the commands related to hacking GDB internals have been moved out of +the main command set, and now live behind the 'maintenance' command. This +can also be abbreviated as 'mt'. The following changes were made: + + dump-me -> maintenance dump-me + info all-breakpoints -> maintenance info breakpoints + printmsyms -> maintenance print msyms + printobjfiles -> maintenance print objfiles + printpsyms -> maintenance print psymbols + printsyms -> maintenance print symbols + +The following commands are new: + + maintenance demangle Call internal GDB demangler routine to + demangle a C++ link name and prints the result. + maintenance print type Print a type chain for a given symbol + + * Change to .gdbinit file processing + +We now read the $HOME/.gdbinit file before processing the argv arguments +(e.g. reading symbol files or core files). This allows global parameters to +be set, which will apply during the symbol reading. The ./.gdbinit is still +read after argv processing. + + * New hosts supported + +Solaris-2.0 !!! sparc-sun-solaris2 or sun4sol2 + +Linux support i386-unknown-linux or linux + +We are also including code to support the HP/PA running BSD and HPUX. This +is almost guaranteed not to work, as we didn't have time to test or build it +for this release. We are including it so that the more adventurous (or +masochistic) of you can play with it. We also had major problems with the +fact that the compiler that we got from HP doesn't support the -g option. +It costs extra. + + * New targets supported + +Hitachi H8/300 h8300-hitachi-hms or h8300hms + + * More smarts about finding #include files + +GDB now remembers the compilation directory for all include files, and for +all files from which C is generated (like yacc and lex sources). This +greatly improves GDB's ability to find yacc/lex sources, and include files, +especially if you are debugging your program from a directory different from +the one that contains your sources. + +We also fixed a bug which caused difficulty with listing and setting +breakpoints in include files which contain C code. (In the past, you had to +try twice in order to list an include file that you hadn't looked at before.) + + * Interesting infernals change + +GDB now deals with arbitrary numbers of sections, where the symbols for each +section must be relocated relative to that section's landing place in the +target's address space. This work was needed to support ELF with embedded +stabs used by Solaris-2.0. + + * Bug fixes (of course!) + +There have been loads of fixes for the following things: + mips, rs6000, 29k/udi, m68k, g++, type handling, elf/dwarf, m88k, + i960, stabs, DOS(GO32), procfs, etc... + +See the ChangeLog for details. + +*** Changes in GDB-4.5: + + * New machines supported (host and target) + +IBM RS6000 running AIX rs6000-ibm-aix or rs6000 + +SGI Irix-4.x mips-sgi-irix4 or iris4 + + * New malloc package + +GDB now uses a new memory manager called mmalloc, based on gmalloc. +Mmalloc is capable of handling mutiple heaps of memory. It is also +capable of saving a heap to a file, and then mapping it back in later. +This can be used to greatly speedup the startup of GDB by using a +pre-parsed symbol table which lives in a mmalloc managed heap. For +more details, please read mmalloc/mmalloc.texi. + + * info proc + +The 'info proc' command (SVR4 only) has been enhanced quite a bit. See +'help info proc' for details. + + * MIPS ecoff symbol table format + +The code that reads MIPS symbol table format is now supported on all hosts. +Thanks to MIPS for releasing the sym.h and symconst.h files to make this +possible. + + * File name changes for MS-DOS + +Many files in the config directories have been renamed to make it easier to +support GDB on MS-DOSe systems (which have very restrictive file name +conventions :-( ). MS-DOSe host support (under DJ Delorie's GO32 +environment) is close to working but has some remaining problems. Note +that debugging of DOS programs is not supported, due to limitations +in the ``operating system'', but it can be used to host cross-debugging. + + * Cross byte order fixes + +Many fixes have been made to support cross debugging of Sparc and MIPS +targets from hosts whose byte order differs. + + * New -mapped and -readnow options + +If memory-mapped files are available on your system through the 'mmap' +system call, you can use the -mapped option on the `file' or +`symbol-file' commands to cause GDB to write the symbols from your +program into a reusable file. If the program you are debugging is +called `/path/fred', the mapped symbol file will be `./fred.syms'. +Future GDB debugging sessions will notice the presence of this file, +and will quickly map in symbol information from it, rather than reading +the symbol table from the executable program. Using the '-mapped' +option in a GDB `file' or `symbol-file' command has the same effect as +starting GDB with the '-mapped' command-line option. + +You can cause GDB to read the entire symbol table immediately by using +the '-readnow' option with any of the commands that load symbol table +information (or on the GDB command line). This makes the command +slower, but makes future operations faster. + +The -mapped and -readnow options are typically combined in order to +build a `fred.syms' file that contains complete symbol information. +A simple GDB invocation to do nothing but build a `.syms' file for future +use is: + + gdb -batch -nx -mapped -readnow programname + +The `.syms' file is specific to the host machine on which GDB is run. +It holds an exact image of GDB's internal symbol table. It cannot be +shared across multiple host platforms. + + * longjmp() handling + +GDB is now capable of stepping and nexting over longjmp(), _longjmp(), and +siglongjmp() without losing control. This feature has not yet been ported to +all systems. It currently works on many 386 platforms, all MIPS-based +platforms (SGI, DECstation, etc), and Sun3/4. + + * Solaris 2.0 + +Preliminary work has been put in to support the new Solaris OS from Sun. At +this time, it can control and debug processes, but it is not capable of +reading symbols. + + * Bug fixes + +As always, many many bug fixes. The major areas were with g++, and mipsread. +People using the MIPS-based platforms should experience fewer mysterious +crashes and trashed symbol tables. + +*** Changes in GDB-4.4: + + * New machines supported (host and target) + +SCO Unix on i386 IBM PC clones i386-sco-sysv or i386sco + (except core files) +BSD Reno on Vax vax-dec-bsd +Ultrix on Vax vax-dec-ultrix + + * New machines supported (target) + +AMD 29000 embedded, using EBMON a29k-none-none + + * C++ support + +GDB continues to improve its handling of C++. `References' work better. +The demangler has also been improved, and now deals with symbols mangled as +per the Annotated C++ Reference Guide. + +GDB also now handles `stabs' symbol information embedded in MIPS +`ecoff' symbol tables. Since the ecoff format was not easily +extensible to handle new languages such as C++, this appeared to be a +good way to put C++ debugging info into MIPS binaries. This option +will be supported in the GNU C compiler, version 2, when it is +released. + + * New features for SVR4 + +GDB now handles SVR4 shared libraries, in the same fashion as SunOS +shared libraries. Debugging dynamically linked programs should present +only minor differences from debugging statically linked programs. + +The `info proc' command will print out information about any process +on an SVR4 system (including the one you are debugging). At the moment, +it prints the address mappings of the process. + +If you bring up GDB on another SVR4 system, please send mail to +bug-gdb@prep.ai.mit.edu to let us know what changes were reqired (if any). + + * Better dynamic linking support in SunOS + +Reading symbols from shared libraries which contain debugging symbols +now works properly. However, there remain issues such as automatic +skipping of `transfer vector' code during function calls, which +make it harder to debug code in a shared library, than to debug the +same code linked statically. + + * New Getopt + +GDB is now using the latest `getopt' routines from the FSF. This +version accepts the -- prefix for options with long names. GDB will +continue to accept the old forms (-option and +option) as well. +Various single letter abbreviations for options have been explicity +added to the option table so that they won't get overshadowed in the +future by other options that begin with the same letter. + + * Bugs fixed + +The `cleanup_undefined_types' bug that many of you noticed has been squashed. +Many assorted bugs have been handled. Many more remain to be handled. +See the various ChangeLog files (primarily in gdb and bfd) for details. + + +*** Changes in GDB-4.3: + + * New machines supported (host and target) + +Amiga 3000 running Amix m68k-cbm-svr4 or amix +NCR 3000 386 running SVR4 i386-ncr-svr4 or ncr3000 +Motorola Delta 88000 running Sys V m88k-motorola-sysv or delta88 + + * Almost SCO Unix support + +We had hoped to support: +SCO Unix on i386 IBM PC clones i386-sco-sysv or i386sco +(except for core file support), but we discovered very late in the release +that it has problems with process groups that render gdb unusable. Sorry +about that. I encourage people to fix it and post the fixes. + + * Preliminary ELF and DWARF support + +GDB can read ELF object files on System V Release 4, and can handle +debugging records for C, in DWARF format, in ELF files. This support +is preliminary. If you bring up GDB on another SVR4 system, please +send mail to bug-gdb@prep.ai.mit.edu to let us know what changes were +reqired (if any). + + * New Readline + +GDB now uses the latest `readline' library. One user-visible change +is that two tabs will list possible command completions, which previously +required typing M-? (meta-question mark, or ESC ?). + + * Bugs fixed + +The `stepi' bug that many of you noticed has been squashed. +Many bugs in C++ have been handled. Many more remain to be handled. +See the various ChangeLog files (primarily in gdb and bfd) for details. + + * State of the MIPS world (in case you wondered): + +GDB can understand the symbol tables emitted by the compilers +supplied by most vendors of MIPS-based machines, including DEC. These +symbol tables are in a format that essentially nobody else uses. + +Some versions of gcc come with an assembler post-processor called +mips-tfile. This program is required if you want to do source-level +debugging of gcc-compiled programs. I believe FSF does not ship +mips-tfile with gcc version 1, but it will eventually come with gcc +version 2. + +Debugging of g++ output remains a problem. g++ version 1.xx does not +really support it at all. (If you're lucky, you should be able to get +line numbers and stack traces to work, but no parameters or local +variables.) With some work it should be possible to improve the +situation somewhat. + +When gcc version 2 is released, you will have somewhat better luck. +However, even then you will get confusing results for inheritance and +methods. + +We will eventually provide full debugging of g++ output on +DECstations. This will probably involve some kind of stabs-in-ecoff +encapulation, but the details have not been worked out yet. + + +*** Changes in GDB-4.2: + + * Improved configuration + +Only one copy of `configure' exists now, and it is not self-modifying. +Porting BFD is simpler. + + * Stepping improved + +The `step' and `next' commands now only stop at the first instruction +of a source line. This prevents the multiple stops that used to occur +in switch statements, for-loops, etc. `Step' continues to stop if a +function that has debugging information is called within the line. + + * Bug fixing + +Lots of small bugs fixed. More remain. + + * New host supported (not target) + +Intel 386 PC clone running Mach i386-none-mach + + +*** Changes in GDB-4.1: + + * Multiple source language support + +GDB now has internal scaffolding to handle several source languages. +It determines the type of each source file from its filename extension, +and will switch expression parsing and number formatting to match the +language of the function in the currently selected stack frame. +You can also specifically set the language to be used, with +`set language c' or `set language modula-2'. + + * GDB and Modula-2 + +GDB now has preliminary support for the GNU Modula-2 compiler, +currently under development at the State University of New York at +Buffalo. Development of both GDB and the GNU Modula-2 compiler will +continue through the fall of 1991 and into 1992. + +Other Modula-2 compilers are currently not supported, and attempting to +debug programs compiled with them will likely result in an error as the +symbol table is read. Feel free to work on it, though! + +There are hooks in GDB for strict type checking and range checking, +in the `Modula-2 philosophy', but they do not currently work. + + * set write on/off + +GDB can now write to executable and core files (e.g. patch +a variable's value). You must turn this switch on, specify +the file ("exec foo" or "core foo"), *then* modify it, e.g. +by assigning a new value to a variable. Modifications take +effect immediately. + + * Automatic SunOS shared library reading + +When you run your program, GDB automatically determines where its +shared libraries (if any) have been loaded, and reads their symbols. +The `share' command is no longer needed. This also works when +examining core files. + + * set listsize + +You can specify the number of lines that the `list' command shows. +The default is 10. + + * New machines supported (host and target) + +SGI Iris (MIPS) running Irix V3: mips-sgi-irix or iris +Sony NEWS (68K) running NEWSOS 3.x: m68k-sony-sysv or news +Ultracomputer (29K) running Sym1: a29k-nyu-sym1 or ultra3 + + * New hosts supported (not targets) + +IBM RT/PC: romp-ibm-aix or rtpc + + * New targets supported (not hosts) + +AMD 29000 embedded with COFF a29k-none-coff +AMD 29000 embedded with a.out a29k-none-aout +Ultracomputer remote kernel debug a29k-nyu-kern + + * New remote interfaces + +AMD 29000 Adapt +AMD 29000 Minimon + + +*** Changes in GDB-4.0: + + * New Facilities + +Wide output is wrapped at good places to make the output more readable. + +Gdb now supports cross-debugging from a host machine of one type to a +target machine of another type. Communication with the target system +is over serial lines. The ``target'' command handles connecting to the +remote system; the ``load'' command will download a program into the +remote system. Serial stubs for the m68k and i386 are provided. Gdb +also supports debugging of realtime processes running under VxWorks, +using SunRPC Remote Procedure Calls over TCP/IP to talk to a debugger +stub on the target system. + +New CPUs supported include the AMD 29000 and Intel 960. + +GDB now reads object files and symbol tables via a ``binary file'' +library, which allows a single copy of GDB to debug programs of multiple +object file types such as a.out and coff. + +There is now a GDB reference card in "doc/refcard.tex". (Make targets +refcard.dvi and refcard.ps are available to format it). + + + * Control-Variable user interface simplified + +All variables that control the operation of the debugger can be set +by the ``set'' command, and displayed by the ``show'' command. + +For example, ``set prompt new-gdb=>'' will change your prompt to new-gdb=>. +``Show prompt'' produces the response: +Gdb's prompt is new-gdb=>. + +What follows are the NEW set commands. The command ``help set'' will +print a complete list of old and new set commands. ``help set FOO'' +will give a longer description of the variable FOO. ``show'' will show +all of the variable descriptions and their current settings. + +confirm on/off: Enables warning questions for operations that are + hard to recover from, e.g. rerunning the program while + it is already running. Default is ON. + +editing on/off: Enables EMACS style command line editing + of input. Previous lines can be recalled with + control-P, the current line can be edited with control-B, + you can search for commands with control-R, etc. + Default is ON. + +history filename NAME: NAME is where the gdb command history + will be stored. The default is .gdb_history, + or the value of the environment variable + GDBHISTFILE. + +history size N: The size, in commands, of the command history. The + default is 256, or the value of the environment variable + HISTSIZE. + +history save on/off: If this value is set to ON, the history file will + be saved after exiting gdb. If set to OFF, the + file will not be saved. The default is OFF. + +history expansion on/off: If this value is set to ON, then csh-like + history expansion will be performed on + command line input. The default is OFF. + +radix N: Sets the default radix for input and output. It can be set + to 8, 10, or 16. Note that the argument to "radix" is interpreted + in the current radix, so "set radix 10" is always a no-op. + +height N: This integer value is the number of lines on a page. Default + is 24, the current `stty rows'' setting, or the ``li#'' + setting from the termcap entry matching the environment + variable TERM. + +width N: This integer value is the number of characters on a line. + Default is 80, the current `stty cols'' setting, or the ``co#'' + setting from the termcap entry matching the environment + variable TERM. + +Note: ``set screensize'' is obsolete. Use ``set height'' and +``set width'' instead. + +print address on/off: Print memory addresses in various command displays, + such as stack traces and structure values. Gdb looks + more ``symbolic'' if you turn this off; it looks more + ``machine level'' with it on. Default is ON. + +print array on/off: Prettyprint arrays. New convenient format! Default + is OFF. + +print demangle on/off: Print C++ symbols in "source" form if on, + "raw" form if off. + +print asm-demangle on/off: Same, for assembler level printouts + like instructions. + +print vtbl on/off: Prettyprint C++ virtual function tables. Default is OFF. + + + * Support for Epoch Environment. + +The epoch environment is a version of Emacs v18 with windowing. One +new command, ``inspect'', is identical to ``print'', except that if you +are running in the epoch environment, the value is printed in its own +window. + + + * Support for Shared Libraries + +GDB can now debug programs and core files that use SunOS shared libraries. +Symbols from a shared library cannot be referenced +before the shared library has been linked with the program (this +happens after you type ``run'' and before the function main() is entered). +At any time after this linking (including when examining core files +from dynamically linked programs), gdb reads the symbols from each +shared library when you type the ``sharedlibrary'' command. +It can be abbreviated ``share''. + +sharedlibrary REGEXP: Load shared object library symbols for files + matching a unix regular expression. No argument + indicates to load symbols for all shared libraries. + +info sharedlibrary: Status of loaded shared libraries. + + + * Watchpoints + +A watchpoint stops execution of a program whenever the value of an +expression changes. Checking for this slows down execution +tremendously whenever you are in the scope of the expression, but is +quite useful for catching tough ``bit-spreader'' or pointer misuse +problems. Some machines such as the 386 have hardware for doing this +more quickly, and future versions of gdb will use this hardware. + +watch EXP: Set a watchpoint (breakpoint) for an expression. + +info watchpoints: Information about your watchpoints. + +delete N: Deletes watchpoint number N (same as breakpoints). +disable N: Temporarily turns off watchpoint number N (same as breakpoints). +enable N: Re-enables watchpoint number N (same as breakpoints). + + + * C++ multiple inheritance + +When used with a GCC version 2 compiler, GDB supports multiple inheritance +for C++ programs. + + * C++ exception handling + +Gdb now supports limited C++ exception handling. Besides the existing +ability to breakpoint on an exception handler, gdb can breakpoint on +the raising of an exception (before the stack is peeled back to the +handler's context). + +catch FOO: If there is a FOO exception handler in the dynamic scope, + set a breakpoint to catch exceptions which may be raised there. + Multiple exceptions (``catch foo bar baz'') may be caught. + +info catch: Lists all exceptions which may be caught in the + current stack frame. + + + * Minor command changes + +The command ``call func (arg, arg, ...)'' now acts like the print +command, except it does not print or save a value if the function's result +is void. This is similar to dbx usage. + +The ``up'' and ``down'' commands now always print the frame they end up +at; ``up-silently'' and `down-silently'' can be used in scripts to change +frames without printing. + + * New directory command + +'dir' now adds directories to the FRONT of the source search path. +The path starts off empty. Source files that contain debug information +about the directory in which they were compiled can be found even +with an empty path; Sun CC and GCC include this information. If GDB can't +find your source file in the current directory, type "dir .". + + * Configuring GDB for compilation + +For normal use, type ``./configure host''. See README or gdb.texinfo +for more details. + +GDB now handles cross debugging. If you are remotely debugging between +two different machines, type ``./configure host -target=targ''. +Host is the machine where GDB will run; targ is the machine +where the program that you are debugging will run. diff --git a/contrib/gdb/gdb/README b/contrib/gdb/gdb/README new file mode 100644 index 000000000000..c58bcb778b47 --- /dev/null +++ b/contrib/gdb/gdb/README @@ -0,0 +1,583 @@ + README for gdb-4.16 release + Updated 10-Apr-96 by Fred Fish + +This is GDB, the GNU source-level debugger. +A summary of new features is in the file `NEWS'. + + +Unpacking and Installation -- quick overview +========================== + +In this release, the GDB debugger sources, the generic GNU include +files, the BFD ("binary file description") library, the readline +library, and other libraries all have directories of their own +underneath the gdb-4.16 directory. The idea is that a variety of GNU +tools can share a common copy of these things. Be aware of variation +over time--for example don't try to build gdb with a copy of bfd from +a release other than the gdb release (such as a binutils or gas +release), especially if the releases are more than a few weeks apart. +Configuration scripts and makefiles exist to cruise up and down this +directory tree and automatically build all the pieces in the right +order. + +When you unpack the gdb-4.16.tar.gz file, you'll find a directory +called `gdb-4.16', which contains: + + COPYING config.sub* libiberty/ opcodes/ + COPYING.LIB configure* mmalloc/ readline/ + Makefile.in configure.in move-if-change* sim/ + README etc/ mpw-README texinfo/ + bfd/ gdb/ mpw-build.in utils/ + config/ include/ mpw-config.in + config.guess* install.sh* mpw-configure + +To build GDB, you can just do: + + cd gdb-4.16 + ./configure + make + cp gdb/gdb /usr/local/bin/gdb (or wherever you want) + +This will configure and build all the libraries as well as GDB. +If `configure' can't determine your system type, specify one as its +argument, e.g., sun4 or decstation. + +If you get compiler warnings during this stage, see the `Reporting Bugs' +section below; there are a few known problems. + +GDB can be used as a cross-debugger, running on a machine of one type +while debugging a program running on a machine of another type. See below. + + +More Documentation +****************** + + The GDB 4 release includes an already-formatted reference card, +ready for printing with PostScript or Ghostscript, in the `gdb' +subdirectory of the main source directory. (In `gdb-4.16/gdb/refcard.ps'.) +If you can use PostScript or Ghostscript with your printer, you can +print the reference card immediately with `refcard.ps'. + + The release also includes the source for the reference card. You +can format it, using TeX, by typing: + + make refcard.dvi + + The GDB reference card is designed to print in landscape mode on US +"letter" size paper; that is, on a sheet 11 inches wide by 8.5 inches +high. You will need to specify this form of printing as an option to +your DVI output program. + + All the documentation for GDB comes as part of the machine-readable +distribution. The documentation is written in Texinfo format, which is +a documentation system that uses a single source file to produce both +on-line information and a printed manual. You can use one of the Info +formatting commands to create the on-line version of the documentation +and TeX (or `texi2roff') to typeset the printed version. + + GDB includes an already formatted copy of the on-line Info version of +this manual in the `gdb' subdirectory. The main Info file is +`gdb-VERSION-NUMBER/gdb/gdb.info', and it refers to subordinate files +matching `gdb.info*' in the same directory. If necessary, you can +print out these files, or read them with any editor; but they are +easier to read using the `info' subsystem in GNU Emacs or the +standalone `info' program, available as part of the GNU Texinfo +distribution. + + If you want to format these Info files yourself, you need one of the +Info formatting programs, such as `texinfo-format-buffer' or `makeinfo'. + + If you have `makeinfo' installed, and are in the top level GDB +source directory (`gdb-4.16', in the case of version 4.16), you can make +the Info file by typing: + + cd gdb + make gdb.info + + If you want to typeset and print copies of this manual, you need TeX, +a program to print its DVI output files, and `texinfo.tex', the Texinfo +definitions file. + + TeX is a typesetting program; it does not print files directly, but +produces output files called DVI files. To print a typeset document, +you need a program to print DVI files. If your system has TeX +installed, chances are it has such a program. The precise command to +use depends on your system; `lpr -d' is common; another (for PostScript +devices) is `dvips'. The DVI print command may require a file name +without any extension or a `.dvi' extension. + + TeX also requires a macro definitions file called `texinfo.tex'. +This file tells TeX how to typeset a document written in Texinfo +format. On its own, TeX cannot read, much less typeset a Texinfo file. + `texinfo.tex' is distributed with GDB and is located in the +`gdb-VERSION-NUMBER/texinfo' directory. + + If you have TeX and a DVI printer program installed, you can typeset +and print this manual. First switch to the the `gdb' subdirectory of +the main source directory (for example, to `gdb-4.16/gdb') and then type: + + make gdb.dvi + + +Installing GDB +************** + + GDB comes with a `configure' script that automates the process of +preparing GDB for installation; you can then use `make' to build the +`gdb' program. + + The GDB distribution includes all the source code you need for GDB in +a single directory, whose name is usually composed by appending the +version number to `gdb'. + + For example, the GDB version 4.16 distribution is in the `gdb-4.16' +directory. That directory contains: + +`gdb-4.16/{COPYING,COPYING.LIB}' + Standard GNU license files. Please read them. + +`gdb-4.16/bfd' + source for the Binary File Descriptor library + +`gdb-4.16/config*' + script for configuring GDB, along with other support files + +`gdb-4.16/gdb' + the source specific to GDB itself + +`gdb-4.16/include' + GNU include files + +`gdb-4.16/libiberty' + source for the `-liberty' free software library + +`gdb-4.16/mmalloc' + source for the GNU memory-mapped malloc package + +`gdb-4.16/opcodes' + source for the library of opcode tables and disassemblers + +`gdb-4.16/readline' + source for the GNU command-line interface + +'gdb-4.16/sim' + source for some simulators (z8000, H8/300, H8/500, etc) + + The simplest way to configure and build GDB is to run `configure' +from the `gdb-VERSION-NUMBER' source directory, which in this example +is the `gdb-4.16' directory. + + First switch to the `gdb-VERSION-NUMBER' source directory if you are +not already in it; then run `configure'. Pass the identifier for the +platform on which GDB will run as an argument. + + For example: + + cd gdb-4.16 + ./configure HOST + make + +where HOST is an identifier such as `sun4' or `decstation', that +identifies the platform where GDB will run. + + Running `configure HOST' followed by `make' builds the `bfd', +`readline', `mmalloc', and `libiberty' libraries, then `gdb' itself. +The configured source files, and the binaries, are left in the +corresponding source directories. + + `configure' is a Bourne-shell (`/bin/sh') script; if your system +does not recognize this automatically when you run a different shell, +you may need to run `sh' on it explicitly: + + sh configure HOST + + If you run `configure' from a directory that contains source +directories for multiple libraries or programs, such as the `gdb-4.16' +source directory for version 4.16, `configure' creates configuration +files for every directory level underneath (unless you tell it not to, +with the `--norecursion' option). + + You can run the `configure' script from any of the subordinate +directories in the GDB distribution, if you only want to configure that +subdirectory; but be sure to specify a path to it. + + For example, with version 4.16, type the following to configure only +the `bfd' subdirectory: + + cd gdb-4.16/bfd + ../configure HOST + + You can install `gdb' anywhere; it has no hardwired paths. However, +you should make sure that the shell on your path (named by the `SHELL' +environment variable) is publicly readable. Remember that GDB uses the +shell to start your program--some systems refuse to let GDB debug child +processes whose programs are not readable. + + +Compiling GDB in another directory +================================== + + If you want to run GDB versions for several host or target machines, +you need a different `gdb' compiled for each combination of host and +target. `configure' is designed to make this easy by allowing you to +generate each configuration in a separate subdirectory, rather than in +the source directory. If your `make' program handles the `VPATH' +feature correctly (GNU `make' and SunOS 'make' are two that should), +running `make' in each of these directories builds the `gdb' program +specified there. + + To build `gdb' in a separate directory, run `configure' with the +`--srcdir' option to specify where to find the source. (You also need +to specify a path to find `configure' itself from your working +directory. If the path to `configure' would be the same as the +argument to `--srcdir', you can leave out the `--srcdir' option; it +will be assumed.) + + For example, with version 4.16, you can build GDB in a separate +directory for a Sun 4 like this: + + cd gdb-4.16 + mkdir ../gdb-sun4 + cd ../gdb-sun4 + ../gdb-4.16/configure sun4 + make + + When `configure' builds a configuration using a remote source +directory, it creates a tree for the binaries with the same structure +(and using the same names) as the tree under the source directory. In +the example, you'd find the Sun 4 library `libiberty.a' in the +directory `gdb-sun4/libiberty', and GDB itself in `gdb-sun4/gdb'. + + One popular reason to build several GDB configurations in separate +directories is to configure GDB for cross-compiling (where GDB runs on +one machine--the host--while debugging programs that run on another +machine--the target). You specify a cross-debugging target by giving +the `--target=TARGET' option to `configure'. + + When you run `make' to build a program or library, you must run it +in a configured directory--whatever directory you were in when you +called `configure' (or one of its subdirectories). + + The `Makefile' that `configure' generates in each source directory +also runs recursively. If you type `make' in a source directory such +as `gdb-4.16' (or in a separate configured directory configured with +`--srcdir=PATH/gdb-4.16'), you will build all the required libraries, +and then build GDB. + + When you have multiple hosts or targets configured in separate +directories, you can run `make' on them in parallel (for example, if +they are NFS-mounted on each of the hosts); they will not interfere +with each other. + + +Specifying names for hosts and targets +====================================== + + The specifications used for hosts and targets in the `configure' +script are based on a three-part naming scheme, but some short +predefined aliases are also supported. The full naming scheme encodes +three pieces of information in the following pattern: + + ARCHITECTURE-VENDOR-OS + + For example, you can use the alias `sun4' as a HOST argument or in a +`--target=TARGET' option. The equivalent full name is +`sparc-sun-sunos4'. + + The `configure' script accompanying GDB does not provide any query +facility to list all supported host and target names or aliases. +`configure' calls the Bourne shell script `config.sub' to map +abbreviations to full names; you can read the script, if you wish, or +you can use it to test your guesses on abbreviations--for example: + + % sh config.sub sun4 + sparc-sun-sunos411 + % sh config.sub sun3 + m68k-sun-sunos411 + % sh config.sub decstation + mips-dec-ultrix42 + % sh config.sub hp300bsd + m68k-hp-bsd + % sh config.sub i386v + i386-unknown-sysv + % sh config.sub i786v + Invalid configuration `i786v': machine `i786v' not recognized + +`config.sub' is also distributed in the GDB source directory +(`gdb-4.16', for version 4.16). + + +`configure' options +=================== + + Here is a summary of the `configure' options and arguments that are +most often useful for building GDB. `configure' also has several other +options not listed here. *note : (configure.info)What Configure Does, +for a full explanation of `configure'. + + configure [--help] + [--prefix=DIR] + [--srcdir=PATH] + [--norecursion] [--rm] + [--target=TARGET] HOST + +You may introduce options with a single `-' rather than `--' if you +prefer; but you may abbreviate option names if you use `--'. + +`--help' + Display a quick summary of how to invoke `configure'. + +`-prefix=DIR' + Configure the source to install programs and files under directory + `DIR'. + +`--srcdir=PATH' + *Warning: using this option requires GNU `make', or another `make' + that compatibly implements the `VPATH' feature.* + Use this option to make configurations in directories separate + from the GDB source directories. Among other things, you can use + this to build (or maintain) several configurations simultaneously, + in separate directories. `configure' writes configuration + specific files in the current directory, but arranges for them to + use the source in the directory PATH. `configure' will create + directories under the working directory in parallel to the source + directories below PATH. + +`--norecursion' + Configure only the directory level where `configure' is executed; + do not propagate configuration to subdirectories. + +`--rm' + Remove the configuration that the other arguments specify. + +`--target=TARGET' + Configure GDB for cross-debugging programs running on the specified + TARGET. Without this option, GDB is configured to debug programs + that run on the same machine (HOST) as GDB itself. + + There is no convenient way to generate a list of all available + targets. + +`HOST ...' + Configure GDB to run on the specified HOST. + + There is no convenient way to generate a list of all available + hosts. + +`configure' accepts other options, for compatibility with configuring +other GNU tools recursively; but these are the only options that affect +GDB or its supporting libraries. + + +Languages other than C +======================= + +See the GDB manual (doc/gdb.texinfo) for information on this. + +Kernel debugging +================= + +I have't done this myself so I can't really offer any advice. +Remote debugging over serial lines works fine, but the kernel debugging +code in here has not been tested in years. Van Jacobson has +better kernel debugging, but the UC lawyers won't let FSF have it. + + +Remote debugging +================= + +The files m68k-stub.c, i386-stub.c, and sparc-stub.c are examples of +remote stubs to be used with remote.c. They are designed to run +standalone on an m68k, i386, or SPARC cpu and communicate properly with +the remote.c stub over a serial line. + +The file rem-multi.shar contains a general stub that can probably +run on various different flavors of unix to allow debugging over a +serial line from one machine to another. + +Some working remote interfaces for talking to existing ROM monitors +are: + remote-adapt.c AMD 29000 "Adapt" + remote-e7000.c Hitachi E7000 ICE + remote-eb.c AMD 29000 "EBMON" + remote-es.c Ericsson 1800 monitor + remote-hms.c Hitachi Micro Systems H8/300 monitor + remote-mips.c MIPS remote debugging protocol + remote-mm.c AMD 29000 "minimon" + remote-nindy.c Intel 960 "Nindy" + remote-os9k.c PC running OS/9000 + remote-sim.c Generalized simulator protocol + remote-st.c Tandem ST-2000 monitor + remote-udi.c AMD 29000 using the AMD "Universal Debug Interface" + remote-vx.c VxWorks realtime kernel + remote-z8k.c Zilog Z8000 simulator + +Remote-vx.c and the vx-share subdirectory contain a remote interface for the +VxWorks realtime kernel, which communicates over TCP using the Sun +RPC library. This would be a useful starting point for other remote- +via-ethernet back ends. + +Remote-udi.c and the 29k-share subdirectory contain a remote interface +for AMD 29000 programs, which uses the AMD "Universal Debug Interface". +This allows GDB to talk to software simulators, emulators, and/or bare +hardware boards, via network or serial interfaces. Note that GDB only +provides an interface that speaks UDI, not a complete solution. You +will need something on the other end that also speaks UDI. + + +Reporting Bugs +=============== + +The correct address for reporting bugs found in gdb is +"bug-gdb@prep.ai.mit.edu". Please email all bugs, and all requests for +help with GDB, to that address. Please include the GDB version number +(e.g., gdb-4.16), and how you configured it (e.g., "sun4" or "mach386 +host, i586-intel-synopsys target"). Since GDB now supports so many +different configurations, it is important that you be precise about this. +If at all possible, you should include the actual banner that GDB prints +when it starts up, or failing that, the actual configure command that +you used when configuring GDB. + +For more information on how/whether to report bugs, see the GDB Bugs +section of the GDB manual (gdb/doc/gdb.texinfo). + +Known bugs: + + * Under Ultrix 4.2 (DECstation-3100) or Alphas under OSF/1, we have + seen problems with backtraces after interrupting the inferior out + of a read(). The problem is caused by ptrace() returning an + incorrect value for the frame pointer register (register 15 or + 30). As far as we can tell, this is a kernel problem. Any help + with this would be greatly appreciated. + + * Under Ultrix 4.4 (DECstation-3100), setting the TERMCAP environment + variable to a string without a trailing ':' can cause GDB to dump + core upon startup. Although the core file makes it look as though + GDB code failed, the crash actually occurs within a call to the + termcap library function tgetent(). The problem can be solved by + using the GNU Termcap library. + + Alphas running OSF/1 (versions 1.0 through 2.1) have the same buggy + termcap code, but GDB behaves strangely rather than crashing. + + * On DECstations there are warnings about shift counts out of range in + various BFD modules. None of them is a cause for alarm, they are actually + a result of bugs in the DECstation compiler. + + * Notes for the DEC Alpha using OSF/1: + The debugging output of native cc has two known problems; we view these + as compiler bugs. + The linker miscompacts symbol tables, which causes gdb to confuse the + type of variables or results in `struct ' type outputs. + dbx has the same problems with those executables. A workaround is to + specify -Wl,-b when linking, but that will increase the executable size + considerably. + If a structure has incomplete type in one file (e.g., "struct foo *" + without a definition for "struct foo"), gdb will be unable to find the + structure definition from another file. + It has been reported that the Ultrix 4.3A compiler on decstations has the + same problems. + + * Notes for Solaris 2.x, using the SPARCworks cc compiler: + You have to compile your program with the -xs option of the SPARCworks + compiler to be able to debug your program with gdb. + Under Solaris 2.3 you also need patch 101409-03 (Jumbo linker patch). + Under Solaris 2.2, if you have patch 101052 installed, make sure + that it is at least at revision 101052-06. + + * Under Irix 5 for SGIs, you must have installed the `compiler_dev.hdr' + subsystem that is on the IDO CD, otherwise you will get complaints + that certain files such as `/usr/include/syms.h' cannot be found. + + * Unixware 2.x is not yet supported. + + * Notes for BSD/386: + To compile gdb-4.16 on BSD/386, you must run the configure script and + its subscripts with bash. Here is an easy way to do this: + + bash -c 'CONFIG_SHELL=/bin/bash ./configure' + + (configure will report i386-unknown-bsd). Then, compile with the + standard "make" command. + +GDB can produce warnings about symbols that it does not understand. By +default, these warnings are disabled. You can enable them by executing +`set complaint 10' (which you can put in your ~/.gdbinit if you like). +I recommend doing this if you are working on a compiler, assembler, +linker, or GDB, since it will point out problems that you may be able +to fix. Warnings produced during symbol reading indicate some mismatch +between the object file and GDB's symbol reading code. In many cases, +it's a mismatch between the specs for the object file format, and what +the compiler actually outputs or the debugger actually understands. + + +X Windows versus GDB +===================== + +There is an "xxgdb", which seems to work for simple operations, +which was posted to comp.sources.x. + +For those interested in auto display of source and the availability of +an editor while debugging I suggest trying gdb-mode in GNU Emacs +(Try typing M-x gdb RETURN). Comments on this mode are welcome. + +Those interested in experimenting with a new kind of gdb-mode +should load gdb/gdba.el into GNU Emacs 19.25 or later. Comments +on this mode are also welcome. + +Writing Code for GDB +===================== + +There is a lot of information about writing code for GDB in the +internals manual, distributed with GDB in gdb/doc/gdbint.texinfo. You +can read it by hand, print it by using TeX and texinfo, or process it +into an `info' file for use with Emacs' info mode or the standalone +`info' program. In particular, see the nodes Getting Started, +Debugging GDB, New Architectures, Coding Style, Clean Design, and +Submitting Patches. + +If you are pondering writing anything but a short patch, especially +take note of the information about copyrights in the node Submitting +Patches. It can take quite a while to get all the paperwork done, so +we encourage you to start that process as soon as you decide you are +planning to work on something, or at least well ahead of when you +think you will be ready to submit the patches. + + +GDB Testsuite +============= + +There is a DejaGNU based testsuite available for testing your newly +built GDB, or for regression testing GDBs with local modifications. +The testsuite is distributed separately from the base GDB distribution +for the convenience of people that wish to get either GDB or the testsuite +separately. + +The name of the testsuite is gdb-4.16-testsuite.tar.gz. You unpack it in the +same directory in which you unpacked the base GDB distribution, and it +will create and populate the directory gdb-4.16/gdb/testsuite. + +Running the testsuite requires the prior installation of DejaGNU, which +is generally available via ftp. Once DejaGNU is installed, you can run +the tests in one of two ways: + + (1) cd gdb-4.16/gdb (assuming you also unpacked gdb) + make check + +or + + (2) cd gdb-4.16/gdb/testsuite + make site.exp (builds the site specific file) + runtest -tool gdb GDB=../gdb (or GDB= as appropriate) + +The second method gives you slightly more control in case of problems with +building one or more test executables or if you are using the testsuite +'standalone', without it being part of the GDB source tree. + +See the DejaGNU documentation for further details. + + +(this is for editing this file with GNU emacs) +Local Variables: +mode: text +End: diff --git a/contrib/gdb/gdb/TODO b/contrib/gdb/gdb/TODO new file mode 100644 index 000000000000..06bd9acced09 --- /dev/null +++ b/contrib/gdb/gdb/TODO @@ -0,0 +1,468 @@ +If you find inaccuracies in this list, please send mail to +bug-gdb@prep.ai.mit.edu. If you would like to work on any of these, +you should consider sending mail to the same address, to find out +whether anyone else is working on it. + +General To Do List +------------------ + +This list is probably not up to date, and opinions vary about the +importance or even desirability of some of the items. + +START_INFERIOR_TRAPS_EXPECTED need never be defined to 2, since that +is its default value. Clean this up. + +It should be possible to use symbols from shared libraries before we know +exactly where the libraries will be loaded. E.g. "b perror" before running +the program. This could maybe be done as an extension of the "breakpoint +re-evaluation" after new symbols are loaded. + +Make single_step() insert and remove breakpoints in one operation. + +Speed up single stepping by avoiding extraneous ptrace calls. + +Speed up single stepping by not inserting and removing breakpoints +each time the inferior starts and stops. + +Breakpoints should not be inserted and deleted all the time. Only the +one(s) there should be removed when we have to step over one. Support +breakpoints that don't have to be removed to step over them. + +Update gdbint.texinfo to include doc on the directory structure and +the various tricks of building gdb. + +Do a tutorial in gdb.texinfo on how to do simple things in gdb. +E.g. how to set a breakpoint that just prints something and continues. +How to break on aborts. Etc. + +Provide "voodoo" debugging of core files. This creates a zombie +process as a child of the debugger, and loads it up with the data, +stack, and regs of the core file. This allows you to call functions +in the executable, to manipulate the data in the core file. + +GDB reopens the source file on every line, as you "next" through it. + +Referencing the vtbl member of a struct doesn't work. It prints OK +if you print the struct, but it gets 0 if you try to deref it. + +Persistent command history: A feature where you could save off a list +of the commands you did, so you can edit it into something that will bring +the target to the same place every time you source it. +This would also be useful for automated fast watchpointing; if you go +past the place where it watchpoints, you just start it over again and +do it more carefully. + +Deal with the SunOS 4.0 and 4.1.1 ptrace bug that loses the registers if +the stack is paged out. + +Finish the C++ exception handling stub routines. Lint points them out +as unused statics functions. + +Perhaps "i source" should take an argument like that of "list". + +See if core-aout.c's fetch_core_registers can be used on more machines. +E.g. MIPS (mips-xdep.c). + +unpack_double() does not handle IEEE float on the target unless the host +is also IEEE. Death on a vax. + +Set up interface between GDB and INFO so that you can hop into interactive +INFO and back out again. When running under Emacs, should use Emacs +info, else fork the info program. Installation of GDB should install +its texinfo files into the info tree automagically, including the readline +texinfo files. + +"help address" ought to find the "help set print address" entry. + +Remove the VTBL internal guts from printouts of C++ structs, unless +vtblprint is set. + +Remove "at 0xnnnn" from the "b foo" response, if `print address off' and if +it matches the source line indicated. + +The prompt at end of screen should accept space as well as CR. + +Check STORE_RETURN_VALUE on all architectures. Check near it in tm-sparc.h +for other bogosities. + +Check for storage leaks in GDB, I'm sure there are a lot! + +vtblprint of a vtbl should demangle the names it's printing. + +Backtrace should point out what the currently selected frame is, in +its display, perhaps showing "@3 foo (bar, ...)" or ">3 foo (bar, +...)" rather than "#3 foo (bar, ...)". + +"i program" should work for core files, and display more info, like what +actually caused it to die. + +"x/10i" should shorten the long name, if any, on subsequent lines. + +Check through the code for FIXME comments and fix them. dbxread.c, +blockframe.c, and plenty more. (I count 634 as of 940621 - sts) + +"next" over a function that longjumps, never stops until next time you happen +to get to that spot by accident. E.g. "n" over execute_command which has +an error. + +"set zeroprint off", don't bother printing members of structs which +are entirely zero. Useful for those big structs with few useful +members. + +GDB does four ioctl's for every command, probably switching terminal modes +to/from inferior or for readline or something. + +terminal_ours versus terminal_inferior: cache state. Switch should be a noop +if the state is the same, too. + +ptype $i6 = void??! + +Clean up invalid_float handling so gdb doesn't coredump when it tries to +access a NaN. While this might work on SPARC, other machines are not +configured right. + +"b value_at ; commands ; continue ; end" stops EVERY OTHER TIME! +Then once you enter a command, it does the command, runs two more +times, and then stops again! Bizarre... (This behaviour has been +modified, but it is not yet 100% predictable when e.g. the commands +call functions in the child, and while there, the child is interrupted +with a signal, or hits a breakpoint.) + +help completion, help history should work. + +Check that we can handle stack trace through varargs AND alloca in same +function, on 29K. + +wait_for_inferior loops forever if wait() gives it an error. + +"i frame" shows wrong "arglist at" location, doesn't show where the args +should be found, only their actual values. + +There should be a way for "set" commands to validate the new setting +before it takes effect. + +A mess of floating point opcodes are missing from sparc-opcode.h. +Also, a little program should test the table for bits that are +overspecified or underspecified. E.g. if the must-be-ones bits +and the must-be-zeroes bits leave some fields unexamined, and the format +string leaves them unprinted, then point this out. If multiple +non-alias patterns match, point this out too. Finally, there should +be a sparc-optest.s file that tries each pattern out. This file +should end up coming back the same (modulo transformation comments) +if fed to "gas" then the .o is fed to gdb for disassembly. + +Eliminate all the core_file_command's in all the xdep files. +Eliminate separate declarations of registers[] everywhere. + +"ena d" is ambiguous, why? "ena delete" seems to think it is a command! + +Perhaps move the tdep, xdep, and nat files, into the config +subdirectories. If not, at least straighten out their names so that +they all start with the machine name. + +inferior_status should include stop_print_frame. It won't need to be +reset in wait_for_inferior after bpstat_stop_status call, then. + +i line VAR produces "Line number not known for symbol ``var''.". I +thought we were stashing that info now! + +We should be able to write to random files at hex offsets like adb. + +Make "target xxx" command interruptible. + +Handle add_file with separate text, data, and bss addresses. Maybe +handle separate addresses for each segment in the object file? + +Handle free_named_symtab to cope with multiply-loaded object files +in a dynamic linking environment. Should remember the last copy loaded, +but not get too snowed if it finds references to the older copy. + +Generalize and Standardize the RPC interface to a target program, +improve it beyond the "ptrace" interface, and see if it can become a +standard for remote debugging. (This is talking about the vxworks +interface. Seems unlikely to me that there will be "a standard" for +remote debugging anytime soon --kingdon, 8 Nov 1994). + +Remove all references to: + text_offset + data_offset + text_data_start + text_end + exec_data_offset + ... +now that we have BFD. All remaining are in machine dependent files. + +When quitting with a running program, if a core file was previously +examined, you get "Couldn't read float regs from core file"...if +indeed it can't. generic_mourn_inferior... + +Have remote targets give a warning on a signal argument to +target_resume. Or better yet, extend the protocols so that it works +like it does on the Unix-like systems. + +Sort help and info output. + +Re-organize help categories into things that tend to fit on a screen +and hang together. + +renote-nindy.c handles interrupts poorly; it error()s out of badly +chosen places, e.g. leaving current_frame zero, which causes core dumps +on the next command. + +Add in commands like ADB's for searching for patterns, etc. We should +be able to examine and patch raw unsymboled binaries as well in gdb as +we can in adb. (E.g. increase the timeout in /bin/login without source). + +Those xdep files that call register_addr without defining it are +probably simply broken. When reconfiguring this part of gdb, I could +only make guesses about how to redo some of those files, and I +probably guessed wrong, or left them "for later" when I have a +machine that can attempt to build them. + +When doing "step" or "next", if a few lines of source are skipped between +the previous line and the current one, print those lines, not just the +last line of a multiline statement. + +When searching for C++ superclasses in value_cast in valops.c, we must +not search the "fields", only the "superclasses". There might be a +struct with a field name that matches the superclass name. This can +happen when the struct was defined before the superclass (before the +name became a typedef). + +Handling of "&" address-of operator needs some serious overhaul +for ANSI C and consistency on arrays and functions. + For "float point[15];": +ptype &point[4] ==> Attempt to take address of non-lvalue. + For "char *malloc();": +ptype malloc ==> "char *()"; should be same as +ptype &malloc ==> "char *(*)()" +call printf ("%x\n", malloc) ==> weird value, should be same as +call printf ("%x\n", &malloc) ==> correct value + +Fix dbxread.c symbol reading in the presence of interrupts. It +currently leaves a cleanup to blow away the entire symbol table when a +QUIT occurs. (What's wrong with that? -kingdon, 28 Oct 1993). + +Mipsread.c reads include files depth-first, because the dependencies +in the psymtabs are way too inclusive (it seems to me). Figure out what +really depends on what, to avoid recursing 20 or 30 times while reading +real symtabs. + +value_add() should be subtracting the lower bound of arrays, if known, +and possibly checking against the upper bound for error reporting. + +mipsread.c symbol table allocation and deallocation should be checked. +My suspicion is that it's full of memory leaks. + +SunOS should have a target_lookup_symbol() for common'd things allocated +by the shared library linker ld.so. + +When listing source lines, check for a preceding \n, to verify that +the file hasn't changed out from under us. + +When listing source lines, eat leading whitespace corresponding to the +line-number prefix we print. This avoids long lines wrapping. + +mipsread.c needs to check for old symtabs and psymtabs for the same +files, the way it happens for dbxread.c and coffread.c, for VxWorks +incremental symbol table reloading. + +Get all the remote systems (where the protocol allows it) to be able to +stop the remote system when the GDB user types ^C (like remote.c +does). For ebmon, use ^Ak. + +Possible feature: A version of the "disassemble" command which shows +both source and assembly code ("set symbol-filename on" is a partial +solution). + +investigate "x/s 0" (right now stops early) (I think maybe GDB is +using a 0 address for bad purposes internally). + +Make "info path" and path_command work again (but independent of the +environment either of gdb or that we'll pass to the inferior). + +Make GDB understand the GCC feature for putting octal constants in +enums. Make it so overflow on an enum constant does not error_type +the whole type. Allow arbitrarily large enums with type attributes. +Put all this stuff in the testsuite. + +Make TYPE_CODE_ERROR with a non-zero TYPE_LENGTH more useful (print +the value in hex; process type attributes). Add this to the +testsuite. This way future compilers can add new types and old +versions of GDB can do something halfway reasonable. + +Clean up formatting of "info registers" on MIPS and 88k. See if it +is possible to do this generically across all target architectures. + +GDB gets bfd/corefile.c and gdb/corefile.c confused (this should be easy to +repeat even with something more recent than GDB 4.9). + +Check that unmatched RBRAC doesn't abort(). + +Fix mdebugread.c:parse_type to do fundamental types right (see +rs6000_builtin_type in stabsread.c for what "right" is--the point is +that the debug format fixes the sizes of these things and it shouldn't +depend on stuff like TARGET_PTR_BIT and so on. For mdebug, there seem +to be separate bt* codes for 64 bit and 32 bit things, and GDB should +be aware of that). Also use a switch statement for clarity and speed. + +Investigate adding symbols in target_load--some targets do, some +don't. + +Put dirname in psymtabs and change lookup*symtab to use dirname (so +/foo/bar.c works whether compiled by cc /foo/bar.c, or cd /foo; cc +bar.c). + +Merge xcoffread.c and coffread.c. Use breakpoint_re_set instead of +fixup_breakpoints. + +Fix byte order and int size sins in tm-a29k.h +(EXTRACT_RETURN_VALUE). Perhaps should reproduce bug and verify fix +(or perhaps should just fix it...). + +Make a watchpoint on a constant expression an error (or warning +perhaps) + +Make a watchpoint which contains a function call an error (it is +broken now, making it work is probably not worth the effort). + +Re-do calls to signal() in remote.c, and inflow.c (set_sigint_trap and +so on) to be independent of the debugging target, using target_stop to +stop the inferior. Probably the part which is now handled by +interrupt_query in remote.c can be done without any new features in +the debugging target. + +New test case based on weird.exp but in which type numbers are not +renumbered (thus multiply defining a type). This currently causes an +infinite loop on "p v_comb". + +Nuke baseclass_addr. + +Nuke USG define. + +"source file more recent" loses on re-read + +Fix 386 floating point so that floating point registers are real +registers (but code can deal at run-time if they are missing, like +mips and 68k). This would clean up "info float" and related stuff. + +Look at Solaris bug in interrupt.exp. Can get out of syscall with +PRSABORT (syscall will return EINTR) but merely doing that leads to a +"can't read memory" error. + +gcc -g -c enummask.c then gdb enummask.o, then "p v". GDB complains +about not being able to access memory location 0. + +-------------------- enummask.c +enum mask +{ + ANIMAL = 0, + VEGETABLE = 1, + MINERAL = 2, + BASIC_CATEGORY = 3, + + WHITE = 0, + BLUE = 4, + GREEN = 8, + BLACK = 0xc, + COLOR = 0xc, + + ALIVE = 0x10, + + LARGE = 0x20 +} v; + +If try to modify value in file with "set write off" should give +appropriate error not "cannot access memory at address 0x65e0". + +Why do we allow a target to omit standard register names (NO_STD_REGS +in tm-z8k.h)? I thought the standard register names were supposed to +be just that, standard. + +Make DEBUG_EXPRESSIONS a maintenance command, dependent on +MAINTENANCE_COMMANDS. + +Allow core file without exec file on RS/6000. + +Make sure "shell" with no arguments works right on DOS. + +Make gdb.ini (as well as .gdbinit) be checked on all platforms, so +the same directory can be NFS-mounted on unix or DOS, and work the +same way. + +cd ~/tmp/ causes infinite loop (where ~/tmp is a directory). + +Get SECT_OFF_TEXT stuff out of objfile_relocate (might be needed to +get RS/6000 to work right, might not be immediately relevant). + +Clean up add_toc_to_loadinfo + +Think about attached processes and sharing terminal. + +John sez in reference to ignoring errors from tcsegpgrp if attach_flag: +set_tty_state should not have any trouble with attached processes. +Instead, the tty handling should leave the pgrp of the tty alone when +attaching to processes (perhaps pass terminal_init_inferior a flag +saying whether we're attaching). + +PAGE_SIZE redefined warnings on AIX. Probably should be using +BFD_PAGE_SIZE throughout BFD. + +Rewrite proceed, wait_for_inferior, and normal_stop to clean them up. +Suggestions: + + 1) Make each test in wait_for_inferior a seperate subroutine + call. + 2) Combine wait_for_inferior and normal_stop to clean up + communication via global variables. + 3) See if you can find some way to clean up the global + variables that are used; possibly group them by data flow + and information content? + +Work out some kind of way to allow running the inferior to be done as +a sub-execution of, eg. breakpoint command lists. Currently running +the inferior interupts any command list execution. This would require +some rewriting of wait_for_inferior & friends, and hence should +probably be done in concert with the above. + +Add function arguments to gdb user defined functions. + +Add convenience variables that refer to exec file, symbol file, +selected frame source file, selected frame function, selected frame +line number, etc. + +Add a "suspend" subcommand of the "continue" command to suspend gdb +while continuing execution of the subprocess. Useful when you are +debugging servers and you want to dodge out and initiate a connection +to a server running under gdb. + +Add stab information to allow reasonable debugging of inline functions +(possibly they should show up on a stack backtrace? With a note +indicating that they weren't "real"?). + +Modify the naked "until" command to step until past the current source +line, rather than past the current pc value. This is tricky simply +because the low level routines have no way of specifying a multi-line +step range, and there is no way of saying "don't print stuff when we +stop" from above (otherwise could just call step many times). + +Modify the handling of symbols grouped through BINCL/EINCL stabs to +allocate a partial symtab for each BINCL/EINCL grouping. This will +seriously decrease the size of inter-psymtab dependencies and hence +lessen the amount that needs to be read in when a new source file is +accessed. + +Do an "x/i $pc" after each stepi or nexti. + +Modify all of the disassemblers to use printf_filtered to get correct +more filtering. + +Modify gdb to work correctly with Pascal. + +Add a command for searching memory, a la adb. It specifies size, +mask, value, start address. ADB searches until it finds it or hits +an error (or is interrupted). + +# Local Variables: +# mode: text +# End: diff --git a/contrib/gdb/gdb/acconfig.h b/contrib/gdb/gdb/acconfig.h new file mode 100644 index 000000000000..bb9b99141af7 --- /dev/null +++ b/contrib/gdb/gdb/acconfig.h @@ -0,0 +1,9 @@ + +/* Define if fpregset_t type is available. */ +#undef HAVE_FPREGSET_T + +/* Define if gregset_t type is available. */ +#undef HAVE_GREGSET_T + +/* Define if the "%Lg" format works to print long doubles. */ +#undef PRINTF_HAS_LONG_DOUBLE diff --git a/contrib/gdb/gdb/aclocal.m4 b/contrib/gdb/gdb/aclocal.m4 new file mode 100644 index 000000000000..d23d084cecdf --- /dev/null +++ b/contrib/gdb/gdb/aclocal.m4 @@ -0,0 +1,605 @@ +dnl This file is duplicated in four places: +dnl * gdb/aclocal.m4 +dnl * gdb/testsuite/aclocal.m4 +dnl * expect/aclocal.m4 +dnl * dejagnu/aclocal.m4 +dnl Consider modifying all copies in parallel. +dnl written by Rob Savoye for Cygnus Support +dnl CYGNUS LOCAL: This gets the right posix flag for gcc +AC_DEFUN(CY_AC_TCL_LYNX_POSIX, +[AC_REQUIRE([AC_PROG_CC])AC_REQUIRE([AC_PROG_CPP]) +AC_MSG_CHECKING([to see if this is LynxOS]) +AC_CACHE_VAL(ac_cv_os_lynx, +[AC_EGREP_CPP(yes, +[/* + * The old Lynx "cc" only defines "Lynx", but the newer one uses "__Lynx__" + */ +#if defined(__Lynx__) || defined(Lynx) +yes +#endif +], ac_cv_os_lynx=yes, ac_cv_os_lynx=no)]) +# +if test "$ac_cv_os_lynx" = "yes" ; then + AC_MSG_RESULT(yes) + AC_DEFINE(LYNX) + AC_MSG_CHECKING([whether -mposix or -X is available]) + AC_CACHE_VAL(ac_cv_c_posix_flag, + [AC_TRY_COMPILE(,[ + /* + * This flag varies depending on how old the compiler is. + * -X is for the old "cc" and "gcc" (based on 1.42). + * -mposix is for the new gcc (at least 2.5.8). + */ + #if defined(__GNUC__) && __GNUC__ >= 2 + choke me + #endif + ], ac_cv_c_posix_flag=" -mposix", ac_cv_c_posix_flag=" -X")]) + CC="$CC $ac_cv_c_posix_flag" + AC_MSG_RESULT($ac_cv_c_posix_flag) + else + AC_MSG_RESULT(no) +fi +]) +# +# Sometimes the native compiler is a bogus stub for gcc or /usr/ucb/cc. This +# makes configure think it's cross compiling. If --target wasn't used, then +# we can't configure, so something is wrong. +AC_DEFUN(CY_AC_C_CROSS, +[# If we cannot run a trivial program, we must be cross compiling. +AC_MSG_CHECKING(whether cross-compiling) +AC_CACHE_VAL(ac_cv_c_cross,[ +AC_TRY_RUN([ + main(){return(0);}], + ac_cv_c_cross=no, ac_cv_c_cross=yes, ac_cv_c_cross=yes) +]) +if test x"${target}" = x"${host}" -a x"${ac_cv_c_cross}" = x"yes"; then + dnl this hack is cause the message is so long we don't call AC_MSG_ERROR + echo "configure: error: You need to specify --target to cross compile," 1>&2; + echo " or the native compiler is broken" 1>&2; + exit 1; +else + cross_compiling=$ac_cv_c_cross + AC_MSG_RESULT($ac_cv_c_cross) +fi +]) +AC_DEFUN(CY_AC_PATH_TCLH, [ +# +# Ok, lets find the tcl source trees so we can use the headers +# Warning: transition of version 9 to 10 will break this algorithm +# because 10 sorts before 9. We also look for just tcl. We have to +# be careful that we don't match stuff like tclX by accident. +# the alternative search directory is involked by --with-tclinclude +# +no_tcl=true +AC_MSG_CHECKING(for Tcl private headers) +AC_ARG_WITH(tclinclude, [ --with-tclinclude directory where tcl private headers are], with_tclinclude=${withval}) +AC_CACHE_VAL(ac_cv_c_tclh,[ +# first check to see if --with-tclinclude was specified +if test x"${with_tclinclude}" != x ; then + if test -f ${with_tclinclude}/tclInt.h ; then + ac_cv_c_tclh=`(cd ${with_tclinclude}; pwd)` + else + AC_MSG_ERROR([${with_tclinclude} directory doesn't contain private headers]) + fi +fi +# next check in private source directory +# +# since ls returns lowest version numbers first, reverse its output +if test x"${ac_cv_c_tclh}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[0-9]]* 2>/dev/null` \ + ${srcdir}/../../tcl \ + `ls -dr ${srcdir}/../../tcl[[0-9]]* 2>/dev/null` \ + ${srcdir}/../../../tcl \ + `ls -dr ${srcdir}/../../../tcl[[0-9]]* 2>/dev/null ` ; do + if test -f $i/tclInt.h ; then + ac_cv_c_tclh=`(cd $i; pwd)` + break + fi + # Tcl 7.5 and greater puts headers in subdirectory. + if test -f $i/generic/tclInt.h ; then + ac_cv_c_tclh=`(cd $i; pwd)`/generic + fi + done +fi +# finally check in a few common install locations +# +# since ls returns lowest version numbers first, reverse its output +if test x"${ac_cv_c_tclh}" = x ; then + for i in \ + `ls -dr /usr/local/src/tcl[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[[0-9]]* 2>/dev/null` \ + /usr/local/src/tcl \ + /usr/local/lib/tcl \ + ${prefix}/include ; do + if test -f $i/tclInt.h ; then + ac_cv_c_tclh=`(cd $i; pwd)` + break + fi + done +fi +# see if one is installed +if test x"${ac_cv_c_tclh}" = x ; then + AC_HEADER_CHECK(tclInt.h, ac_cv_c_tclh=installed, ac_cv_c_tclh="") +fi +]) +if test x"${ac_cv_c_tclh}" = x ; then + TCLHDIR="# no Tcl private headers found" + AC_MSG_ERROR([Can't find Tcl private headers]) +fi +if test x"${ac_cv_c_tclh}" != x ; then + no_tcl="" + if test x"${ac_cv_c_tkh}" = x"installed" ; then + AC_MSG_RESULT([is installed]) + TCLHDIR="" + else + AC_MSG_RESULT([found in ${ac_cv_c_tclh}]) + # this hack is cause the TCLHDIR won't print if there is a "-I" in it. + TCLHDIR="-I${ac_cv_c_tclh}" + fi +fi + +AC_MSG_CHECKING([Tcl version]) +rm -rf tclmajor tclminor +orig_includes="$CPPFLAGS" + +if test x"${TCLHDIR}" != x ; then + CPPFLAGS="$CPPFLAGS $TCLHDIR" +fi + +AC_TRY_RUN([ +#include +#include "tcl.h" +main() { + FILE *maj = fopen("tclmajor","w"); + FILE *min = fopen("tclminor","w"); + fprintf(maj,"%d",TCL_MAJOR_VERSION); + fprintf(min,"%d",TCL_MINOR_VERSION); + fclose(maj); + fclose(min); + return 0; +}], + tclmajor=`cat tclmajor` + tclminor=`cat tclminor` + tclversion=$tclmajor.$tclminor + AC_MSG_RESULT($tclversion) + rm -f tclmajor tclminor +, + AC_MSG_RESULT([can't happen]) +, + AC_MSG_ERROR([can't be cross compiled]) +) +CPPFLAGS="${orig_includes}" + +AC_PROVIDE([$0]) +AC_SUBST(TCLHDIR) +]) +AC_DEFUN(CY_AC_PATH_TCLLIB, [ +# +# Ok, lets find the tcl library +# First, look for one uninstalled. +# the alternative search directory is invoked by --with-tcllib +# + +if test $tclmajor -ge 7 -a $tclminor -ge 4 ; then + installedtcllibroot=tcl$tclversion +else + installedtcllibroot=tcl +fi + +if test x"${no_tcl}" = x ; then + # we reset no_tcl incase something fails here + no_tcl=true + AC_ARG_WITH(tcllib, [ --with-tcllib directory where the tcl library is], + with_tcllib=${withval}) + AC_MSG_CHECKING([for Tcl library]) + AC_CACHE_VAL(ac_cv_c_tcllib,[ + # First check to see if --with-tcllib was specified. + # This requires checking for both the installed and uninstalled name-styles + # since we have no idea if it's installed or not. + if test x"${with_tcllib}" != x ; then + if test -f "${with_tcllib}/lib$installedtcllibroot.so" ; then + ac_cv_c_tcllib=`(cd ${with_tcllib}; pwd)`/lib$installedtcllibroot.so + elif test -f "${with_tcllib}/libtcl.so" ; then + ac_cv_c_tcllib=`(cd ${with_tcllib}; pwd)`/libtcl.so + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtcl will be built first. + elif test -f "${with_tcllib}/lib$installedtcllibroot.a" ; then + ac_cv_c_tcllib=`(cd ${with_tcllib}; pwd)`/lib$installedtcllibroot.a + elif test -f "${with_tcllib}/libtcl.a" ; then + ac_cv_c_tcllib=`(cd ${with_tcllib}; pwd)`/libtcl.a + else + AC_MSG_ERROR([${with_tcllib} directory doesn't contain libraries]) + fi + fi + # then check for a private Tcl library + # Since these are uninstalled, use the simple lib name root. + if test x"${ac_cv_c_tcllib}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[0-9]]* 2>/dev/null` ; do + # Tcl 7.5 and greater puts library in subdir. Look there first. + if test -f "$i/unix/libtcl.so" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/unix/libtcl.so + break + elif test -f "$i/unix/libtcl.a" -o -f "$i/unix/Makefile"; then + ac_cv_c_tcllib=`(cd $i; pwd)`/unix/libtcl.a + break + # look for a freshly built dynamically linked library + elif test -f "$i/libtcl.so" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/libtcl.so + break + + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtcl will be + # built first. + elif test -f "$i/libtcl.a" -o -f "$i/Makefile" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/libtcl.a + break + fi + done + fi + # check in a few common install locations + if test x"${ac_cv_c_tcllib}" = x ; then + for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do + # first look for a freshly built dynamically linked library + if test -f "$i/lib$installedtcllibroot.so" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/lib$installedtcllibroot.so + break + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtcl will be built first. + elif test -f "$i/lib$installedtcllibroot.a" -o -f "$i/Makefile" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/lib$installedtcllibroot.a + break + fi + done + fi + # check in a few other private locations + if test x"${ac_cv_c_tcllib}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[0-9]]* 2>/dev/null` ; do + # Tcl 7.5 and greater puts library in subdir. Look there first. + if test -f "$i/unix/libtcl.so" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/unix/libtcl.so + break + elif test -f "$i/unix/libtcl.a" -o -f "$i/unix/Makefile"; then + ac_cv_c_tcllib=`(cd $i; pwd)`/unix/libtcl.a + break + # look for a freshly built dynamically linked library + elif test -f "$i/libtcl.so" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/libtcl.so + break + + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtcl will be + # built first. + elif test -f "$i/libtcl.a" -o -f "$i/Makefile" ; then + ac_cv_c_tcllib=`(cd $i; pwd)`/libtcl.a + break + fi + done + fi + + # see if one is conveniently installed with the compiler + if test x"${ac_cv_c_tcllib}" = x ; then + orig_libs="$LIBS" + LIBS="$LIBS -l$installedtcllibroot -lm" + AC_TRY_RUN([ + Tcl_AppInit() + { exit(0); }], ac_cv_c_tcllib="-l$installedtcllibroot", ac_cv_c_tcllib="" + , ac_cv_c_tclib="-l$installedtcllibroot") + LIBS="${orig_libs}" + fi + ]) + if test x"${ac_cv_c_tcllib}" = x ; then + TCLLIB="# no Tcl library found" + AC_MSG_WARN(Can't find Tcl library) + else + TCLLIB=${ac_cv_c_tcllib} + AC_MSG_RESULT(found $TCLLIB) + no_tcl= + fi +fi + +AC_PROVIDE([$0]) +AC_SUBST(TCLLIB) +]) +AC_DEFUN(CY_AC_PATH_TKH, [ +# +# Ok, lets find the tk source trees so we can use the headers +# If the directory (presumably symlink) named "tk" exists, use that one +# in preference to any others. Same logic is used when choosing library +# and again with Tcl. The search order is the best place to look first, then in +# decreasing significance. The loop breaks if the trigger file is found. +# Note the gross little conversion here of srcdir by cd'ing to the found +# directory. This converts the path from a relative to an absolute, so +# recursive cache variables for the path will work right. We check all +# the possible paths in one loop rather than many seperate loops to speed +# things up. +# the alternative search directory is invoked by --with-tkinclude +# +AC_MSG_CHECKING(for Tk private headers) +AC_ARG_WITH(tkinclude, [ --with-tkinclude directory where the tk private headers are], + with_tkinclude=${withval}) +no_tk=true +AC_CACHE_VAL(ac_cv_c_tkh,[ +# first check to see if --with-tkinclude was specified +if test x"${with_tkinclude}" != x ; then + if test -f ${with_tkinclude}/tk.h ; then + ac_cv_c_tkh=`(cd ${with_tkinclude}; pwd)` + else + AC_MSG_ERROR([${with_tkinclude} directory doesn't contain private headers]) + fi +fi +# next check in private source directory +# +# since ls returns lowest version numbers first, reverse the entire list +# and search for the worst fit, overwriting it with better fits as we find them +if test x"${ac_cv_c_tkh}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[0-9]]* 2>/dev/null` \ + ${srcdir}/../../tk \ + `ls -dr ${srcdir}/../../tk[[0-9]]* 2>/dev/null` \ + ${srcdir}/../../../tk \ + `ls -dr ${srcdir}/../../../tk[[0-9]]* 2>/dev/null ` ; do + if test -f $i/tk.h ; then + ac_cv_c_tkh=`(cd $i; pwd)` + break + fi + # Tk 4.1 and greater puts this in a subdir. + if test -f $i/generic/tk.h; then + ac_cv_c_tkh=`(cd $i; pwd)`/generic + fi + done +fi +# finally check in a few common install locations +# +# since ls returns lowest version numbers first, reverse the entire list +# and search for the worst fit, overwriting it with better fits as we find them +if test x"${ac_cv_c_tkh}" = x ; then + for i in \ + `ls -dr /usr/local/src/tk[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/lib/tk[[0-9]]* 2>/dev/null` \ + /usr/local/src/tk \ + /usr/local/lib/tk \ + ${prefix}/include ; do + if test -f $i/tk.h ; then + ac_cv_c_tkh=`(cd $i; pwd)` + break + fi + done +fi +# see if one is installed +if test x"${ac_cv_c_tkh}" = x ; then + AC_HEADER_CHECK(tk.h, ac_cv_c_tkh=installed) +fi +]) +if test x"${ac_cv_c_tkh}" != x ; then + no_tk="" + if test x"${ac_cv_c_tkh}" = x"installed" ; then + AC_MSG_RESULT([is installed]) + TKHDIR="" + else + AC_MSG_RESULT([found in $ac_cv_c_tkh]) + # this hack is cause the TKHDIR won't print if there is a "-I" in it. + TKHDIR="-I${ac_cv_c_tkh}" + fi +else + TKHDIR="# no Tk directory found" + AC_MSG_WARN([Can't find Tk private headers]) + no_tk=true +fi + +# if Tk is installed, extract the major/minor version +if test x"${no_tk}" = x ; then +AC_MSG_CHECKING([Tk version]) +rm -rf tkmajor tkminor +orig_includes="$CPPFLAGS" + +if test x"${TCLHDIR}" != x ; then + CPPFLAGS="$CPPFLAGS $TCLHDIR" +fi +if test x"${TKHDIR}" != x ; then + CPPFLAGS="$CPPFLAGS $TKHDIR" +fi +if test x"${x_includes}" != x -a x"${x_includes}" != xNONE ; then + CPPFLAGS="$CPPFLAGS -I$x_includes" +fi + +AC_TRY_RUN([ +#include +#include "tk.h" + main() { + FILE *maj = fopen("tkmajor","w"); + FILE *min = fopen("tkminor","w"); + fprintf(maj,"%d",TK_MAJOR_VERSION); + fprintf(min,"%d",TK_MINOR_VERSION); + fclose(maj); + fclose(min); + return 0; +}], + tkmajor=`cat tkmajor` + tkminor=`cat tkminor` + tkversion=$tkmajor.$tkminor + AC_MSG_RESULT($tkversion) + rm -f tkmajor tkminor +, + AC_MSG_ERROR([ +cannot compile a simple X program - suspect your xmkmf is +misconfigured and is incorrectly reporting the location of your X +include or libraries - report this to your system admin]) , + AC_MSG_ERROR([can't be cross compiled]) +) +CPPFLAGS="${orig_includes}" +fi + +AC_PROVIDE([$0]) +AC_SUBST(TKHDIR) +]) +AC_DEFUN(CY_AC_PATH_TKLIB, [ +AC_REQUIRE([CY_AC_PATH_TCL]) +# +# Ok, lets find the tk library +# First, look for the latest private (uninstalled) copy +# Notice that the destinations in backwards priority since the tests have +# no break. +# Then we look for either .a, .so, or Makefile. A Makefile is acceptable +# is it indicates the target has been configured and will (probably) +# soon be built. This allows an entire tree of Tcl software to be +# configured at once and then built. +# the alternative search directory is invoked by --with-tklib +# + +if test x"${no_tk}" = x ; then + # reset no_tk incase something fails here + no_tk="true" + + if test $tkmajor -ge 4 ; then + installedtklibroot=tk$tkversion + else + installedtkllibroot=tk + fi + + AC_ARG_WITH(tklib, [ --with-tklib directory where the tk library is], + with_tklib=${withval}) + AC_MSG_CHECKING([for Tk library]) + AC_CACHE_VAL(ac_cv_c_tklib,[ + # first check to see if --with-tklib was specified + # This requires checking for both the installed and uninstalled name-styles + # since we have no idea if it's installed or not. + if test x"${with_tklib}" != x ; then + if test -f "${with_tklib}/lib$installedtklibroot.so" ; then + ac_cv_c_tklib=`(cd ${with_tklib}; pwd)`/lib$installedtklibroot.so + no_tk="" + elif test -f "${with_tklib}/libtk.so" ; then + ac_cv_c_tklib=`(cd ${with_tklib}; pwd)`/libtk.so + no_tk="" + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtk will be built + elif test -f "${with_tklib}/lib$installedtklibroot.a" ; then + ac_cv_c_tklib=`(cd ${with_tklib}; pwd)`/lib$installedtklibroot.a + no_tk="" + elif test -f "${with_tklib}/libtk.a" ; then + ac_cv_c_tklib=`(cd ${with_tklib}; pwd)`/libtk.a + no_tk="" + else + AC_MSG_ERROR([${with_tklib} directory doesn't contain libraries]) + fi + fi + # then check for a private Tk library + # Since these are uninstalled, use the simple lib name root. + if test x"${ac_cv_c_tklib}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[0-9]]* 2>/dev/null` ; do + # Tk 4.1 and greater puts things in subdirs. Check these first. + if test -f "$i/unix/libtk.so" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/unix/libtk.so + no_tk= + break + elif test -f "$i/unix/libtk.a" -o -f "$i/unix/Makefile"; then + ac_cv_c_tklib=`(cd $i; pwd)`/unix/libtk.a + no_tk= + break + # look for a freshly built dynamically linked library + elif test -f "$i/libtk.so" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/libtk.so + no_tk= + break + # then look for a freshly built statically linked library + # if Makefile exists we assume its configured and libtk will be built + elif test -f "$i/libtk.a" -o -f "$i/Makefile" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/libtk.a + no_tk="" + break + fi + done + fi + # finally check in a few common install locations + if test x"${ac_cv_c_tklib}" = x ; then + for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do + # first look for a freshly built dynamically linked library + if test -f "$i/lib$installedtklibroot.so" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/lib$installedtklibroot.so + no_tk="" + break + # then look for a freshly built statically linked library + # if Makefile exists, we assume it's configured and libtcl will be built + elif test -f "$i/lib$installedtklibroot.a" -o -f "$i/Makefile" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/lib$installedtklibroot.a + no_tk="" + break + fi + done + fi + # check in a few other private locations + if test x"${ac_cv_c_tklib}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[0-9]]* 2>/dev/null` ; do + # Tk 4.1 and greater puts things in subdirs. Check these first. + if test -f "$i/unix/libtk.so" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/unix/libtk.so + no_tk= + break + elif test -f "$i/unix/libtk.a" -o -f "$i/unix/Makefile"; then + ac_cv_c_tcllib=`(cd $i; pwd)`/unix/libtk.a + no_tk= + break + # look for a freshly built dynamically linked library + elif test -f "$i/libtk.so" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/libtk.so + no_tk="" + break + # then look for a freshly built statically linked library + # if Makefile exists, we assume it's configured and libtcl will be built + elif test -f "$i/libtk.a" -o -f "$i/Makefile" ; then + ac_cv_c_tklib=`(cd $i; pwd)`/libtk.a + no_tk="" + break + fi + done + fi + # see if one is conveniently installed with the compiler + if test x"${ac_cv_c_tklib}" = x ; then + AC_REQUIRE([AC_PATH_X]) + orig_libs="$LIBS" + LIBS="$LIBS -l$installedtklibroot $x_libraries $ac_cv_c_tcllib -lm" + AC_TRY_RUN([ + Tcl_AppInit() + { exit(0); }], ac_cv_c_tklib="-l$installedtklibroot", ac_cv_c_tklib="" + , ac_cv_c_tklib="-l$installedtklibroot") + LIBS="${orig_libs}" + fi + ]) + if test x"${ac_cv_c_tklib}" = x ; then + TKLIB="# no Tk library found" + AC_MSG_WARN(Can't find Tk library) + else + TKLIB=$ac_cv_c_tklib + AC_MSG_RESULT(found $TKLIB) + no_tk= + fi +fi +AC_PROVIDE([$0]) +AC_SUBST(TKLIB) +]) +AC_DEFUN(CY_AC_PATH_TK, [ + CY_AC_PATH_TKH + CY_AC_PATH_TKLIB +]) +AC_DEFUN(CY_AC_PATH_TCL, [ + CY_AC_PATH_TCLH + CY_AC_PATH_TCLLIB +]) diff --git a/contrib/gdb/gdb/alpha-nat.c b/contrib/gdb/gdb/alpha-nat.c new file mode 100644 index 000000000000..b027116804f6 --- /dev/null +++ b/contrib/gdb/gdb/alpha-nat.c @@ -0,0 +1,243 @@ +/* Low level Alpha interface, for GDB when running native. + Copyright 1993, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" +#include +#include +#include + +/* Size of elements in jmpbuf */ + +#define JB_ELEMENT_SIZE 8 + +/* The definition for JB_PC in machine/reg.h is wrong. + And we can't get at the correct definition in setjmp.h as it is + not always available (eg. if _POSIX_SOURCE is defined which is the + default). As the defintion is unlikely to change (see comment + in , define the correct value here. */ + +#undef JB_PC +#define JB_PC 2 + +/* Figure out where the longjmp will land. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target (pc) + CORE_ADDR *pc; +{ + CORE_ADDR jb_addr; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + + jb_addr = read_register(A0_REGNUM); + + if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, raw_buffer, + sizeof(CORE_ADDR))) + return 0; + + *pc = extract_address (raw_buffer, sizeof(CORE_ADDR)); + return 1; +} + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + register int regno; + register int addr; + int bad_reg = -1; + + /* Table to map a gdb regnum to an index in the core register section. + The floating point register values are garbage in OSF/1.2 core files. */ + static int core_reg_mapping[NUM_REGS] = + { +#define EFL (EF_SIZE / 8) + EF_V0, EF_T0, EF_T1, EF_T2, EF_T3, EF_T4, EF_T5, EF_T6, + EF_T7, EF_S0, EF_S1, EF_S2, EF_S3, EF_S4, EF_S5, EF_S6, + EF_A0, EF_A1, EF_A2, EF_A3, EF_A4, EF_A5, EF_T8, EF_T9, + EF_T10, EF_T11, EF_RA, EF_T12, EF_AT, EF_GP, EF_SP, -1, + EFL+0, EFL+1, EFL+2, EFL+3, EFL+4, EFL+5, EFL+6, EFL+7, + EFL+8, EFL+9, EFL+10, EFL+11, EFL+12, EFL+13, EFL+14, EFL+15, + EFL+16, EFL+17, EFL+18, EFL+19, EFL+20, EFL+21, EFL+22, EFL+23, + EFL+24, EFL+25, EFL+26, EFL+27, EFL+28, EFL+29, EFL+30, EFL+31, + EF_PC, -1 + }; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for (regno = 0; regno < NUM_REGS; regno++) + { + if (CANNOT_FETCH_REGISTER (regno)) + { + supply_register (regno, zerobuf); + continue; + } + addr = 8 * core_reg_mapping[regno]; + if (addr < 0 || addr >= core_reg_size) + { + if (bad_reg < 0) + bad_reg = regno; + } + else + { + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg >= 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + +/* Map gdb internal register number to a ptrace ``address''. + These ``addresses'' are defined in */ + +#define REGISTER_PTRACE_ADDR(regno) \ + (regno < FP0_REGNUM ? GPR_BASE + (regno) \ + : regno == PC_REGNUM ? PC \ + : regno >= FP0_REGNUM ? FPR_BASE + ((regno) - FP0_REGNUM) \ + : 0) + +/* Return the ptrace ``address'' of register REGNO. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + return REGISTER_PTRACE_ADDR (regno); +} + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +#ifdef USE_PROC_FS +#include + +/* + * See the comment in m68k-tdep.c regarding the utility of these functions. + */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register long *regp = gregsetp->regs; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for (regi = 0; regi < 31; regi++) + supply_register (regi, (char *)(regp + regi)); + + supply_register (PC_REGNUM, (char *)(regp + 31)); + + /* Fill inaccessible registers with zero. */ + supply_register (ZERO_REGNUM, zerobuf); + supply_register (FP_REGNUM, zerobuf); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register long *regp = gregsetp->regs; + + for (regi = 0; regi < 31; regi++) + if ((regno == -1) || (regno == regi)) + *(regp + regi) = *(long *) ®isters[REGISTER_BYTE (regi)]; + + if ((regno == -1) || (regno == PC_REGNUM)) + *(regp + 31) = *(long *) ®isters[REGISTER_BYTE (PC_REGNUM)]; +} + +/* + * Now we do the same thing for floating-point registers. + * Again, see the comments in m68k-tdep.c. + */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + register int regi; + register long *regp = fpregsetp->regs; + + for (regi = 0; regi < 32; regi++) + supply_register (regi + FP0_REGNUM, (char *)(regp + regi)); +} + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + int regi; + register long *regp = fpregsetp->regs; + + for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++) + { + if ((regno == -1) || (regno == regi)) + { + *(regp + regi - FP0_REGNUM) = + *(long *) ®isters[REGISTER_BYTE (regi)]; + } + } +} +#endif + + +/* Register that we are able to handle alpha core file formats. */ + +static struct core_fns alpha_core_fns = +{ + bfd_target_aout_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_alpha () +{ + add_core_fns (&alpha_core_fns); +} diff --git a/contrib/gdb/gdb/alpha-tdep.c b/contrib/gdb/gdb/alpha-tdep.c new file mode 100644 index 000000000000..7fbf6422e700 --- /dev/null +++ b/contrib/gdb/gdb/alpha-tdep.c @@ -0,0 +1,1274 @@ +/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. + Copyright 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "dis-asm.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb_string.h" + +/* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ + +/* FIXME: Put this declaration in frame.h. */ +extern struct obstack frame_cache_obstack; + + +/* Forward declarations. */ + +static CORE_ADDR read_next_frame_reg PARAMS ((struct frame_info *, int)); + +static CORE_ADDR heuristic_proc_start PARAMS ((CORE_ADDR)); + +static alpha_extra_func_info_t heuristic_proc_desc PARAMS ((CORE_ADDR, + CORE_ADDR, + struct frame_info *)); + +static alpha_extra_func_info_t find_proc_desc PARAMS ((CORE_ADDR, + struct frame_info *)); + +#if 0 +static int alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR)); +#endif + +static void reinit_frame_cache_sfunc PARAMS ((char *, int, + struct cmd_list_element *)); + +static CORE_ADDR after_prologue PARAMS ((CORE_ADDR pc, + alpha_extra_func_info_t proc_desc)); + +static int alpha_in_prologue PARAMS ((CORE_ADDR pc, + alpha_extra_func_info_t proc_desc)); + +/* Heuristic_proc_start may hunt through the text section for a long + time across a 2400 baud serial line. Allows the user to limit this + search. */ +static unsigned int heuristic_fence_post = 0; + +/* Layout of a stack frame on the alpha: + + | | + pdr members: | 7th ... nth arg, | + | `pushed' by caller. | + | | +----------------|-------------------------------|<-- old_sp == vfp + ^ ^ ^ ^ | | + | | | | | | + | |localoff | Copies of 1st .. 6th | + | | | | | argument if necessary. | + | | | v | | + | | | --- |-------------------------------|<-- FRAME_LOCALS_ADDRESS + | | | | | + | | | | Locals and temporaries. | + | | | | | + | | | |-------------------------------| + | | | | | + |-fregoffset | Saved float registers. | + | | | | F9 | + | | | | . | + | | | | . | + | | | | F2 | + | | v | | + | | -------|-------------------------------| + | | | | + | | | Saved registers. | + | | | S6 | + |-regoffset | . | + | | | . | + | | | S0 | + | | | pdr.pcreg | + | v | | + | ----------|-------------------------------| + | | | + frameoffset | Argument build area, gets | + | | 7th ... nth arg for any | + | | called procedure. | + v | | + -------------|-------------------------------|<-- sp + | | +*/ + +#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */ +#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ +#define PROC_DUMMY_FRAME(proc) ((proc)->pdr.iopt) /* frame for CALL_DUMMY */ +#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) +#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg) +#define PROC_REG_MASK(proc) ((proc)->pdr.regmask) +#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask) +#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) +#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) +#define PROC_PC_REG(proc) ((proc)->pdr.pcreg) +#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff) +#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym) +#define _PROC_MAGIC_ 0x0F0F0F0F +#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_) +#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_) + +struct linked_proc_info +{ + struct alpha_extra_func_info info; + struct linked_proc_info *next; +} *linked_proc_desc_table = NULL; + + +/* Guaranteed to set frame->saved_regs to some values (it never leaves it + NULL). */ + +void +alpha_find_saved_regs (frame) + struct frame_info *frame; +{ + int ireg; + CORE_ADDR reg_position; + unsigned long mask; + alpha_extra_func_info_t proc_desc; + int returnreg; + + frame->saved_regs = (struct frame_saved_regs *) + obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs)); + memset (frame->saved_regs, 0, sizeof (struct frame_saved_regs)); + + /* If it is the frame for __sigtramp, the saved registers are located + in a sigcontext structure somewhere on the stack. __sigtramp + passes a pointer to the sigcontext structure on the stack. + If the stack layout for __sigtramp changes, or if sigcontext offsets + change, we might have to update this code. */ +#ifndef SIGFRAME_PC_OFF +#define SIGFRAME_PC_OFF (2 * 8) +#define SIGFRAME_REGSAVE_OFF (4 * 8) +#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8) +#endif + if (frame->signal_handler_caller) + { + CORE_ADDR sigcontext_pointer_addr; + CORE_ADDR sigcontext_addr; + + if (frame->next) + sigcontext_pointer_addr = frame->next->frame; + else + sigcontext_pointer_addr = frame->frame; + sigcontext_addr = read_memory_integer(sigcontext_pointer_addr, 8); + for (ireg = 0; ireg < 32; ireg++) + { + reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8; + frame->saved_regs->regs[ireg] = reg_position; + } + for (ireg = 0; ireg < 32; ireg++) + { + reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8; + frame->saved_regs->regs[FP0_REGNUM + ireg] = reg_position; + } + frame->saved_regs->regs[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF; + return; + } + + proc_desc = frame->proc_desc; + if (proc_desc == NULL) + /* I'm not sure how/whether this can happen. Normally when we can't + find a proc_desc, we "synthesize" one using heuristic_proc_desc + and set the saved_regs right away. */ + return; + + /* Fill in the offsets for the registers which gen_mask says + were saved. */ + + reg_position = frame->frame + PROC_REG_OFFSET (proc_desc); + mask = PROC_REG_MASK (proc_desc); + + returnreg = PROC_PC_REG (proc_desc); + + /* Note that RA is always saved first, regardless of its actual + register number. */ + if (mask & (1 << returnreg)) + { + frame->saved_regs->regs[returnreg] = reg_position; + reg_position += 8; + mask &= ~(1 << returnreg); /* Clear bit for RA so we + don't save again later. */ + } + + for (ireg = 0; ireg <= 31 ; ++ireg) + if (mask & (1 << ireg)) + { + frame->saved_regs->regs[ireg] = reg_position; + reg_position += 8; + } + + /* Fill in the offsets for the registers which float_mask says + were saved. */ + + reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc); + mask = PROC_FREG_MASK (proc_desc); + + for (ireg = 0; ireg <= 31 ; ++ireg) + if (mask & (1 << ireg)) + { + frame->saved_regs->regs[FP0_REGNUM+ireg] = reg_position; + reg_position += 8; + } + + frame->saved_regs->regs[PC_REGNUM] = frame->saved_regs->regs[returnreg]; +} + +static CORE_ADDR +read_next_frame_reg(fi, regno) + struct frame_info *fi; + int regno; +{ + for (; fi; fi = fi->next) + { + /* We have to get the saved sp from the sigcontext + if it is a signal handler frame. */ + if (regno == SP_REGNUM && !fi->signal_handler_caller) + return fi->frame; + else + { + if (fi->saved_regs == NULL) + alpha_find_saved_regs (fi); + if (fi->saved_regs->regs[regno]) + return read_memory_integer(fi->saved_regs->regs[regno], 8); + } + } + return read_register(regno); +} + +CORE_ADDR +alpha_frame_saved_pc(frame) + struct frame_info *frame; +{ + alpha_extra_func_info_t proc_desc = frame->proc_desc; + /* We have to get the saved pc from the sigcontext + if it is a signal handler frame. */ + int pcreg = frame->signal_handler_caller ? PC_REGNUM : frame->pc_reg; + + if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + return read_memory_integer(frame->frame - 8, 8); + + return read_next_frame_reg(frame, pcreg); +} + +CORE_ADDR +alpha_saved_pc_after_call (frame) + struct frame_info *frame; +{ + CORE_ADDR pc = frame->pc; + CORE_ADDR tmp; + alpha_extra_func_info_t proc_desc; + int pcreg; + + /* Skip over shared library trampoline if necessary. */ + tmp = SKIP_TRAMPOLINE_CODE (pc); + if (tmp != 0) + pc = tmp; + + proc_desc = find_proc_desc (pc, frame->next); + pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM; + + return read_register (pcreg); +} + + +static struct alpha_extra_func_info temp_proc_desc; +static struct frame_saved_regs temp_saved_regs; + +/* This fencepost looks highly suspicious to me. Removing it also + seems suspicious as it could affect remote debugging across serial + lines. */ + +static CORE_ADDR +heuristic_proc_start(pc) + CORE_ADDR pc; +{ + CORE_ADDR start_pc = pc; + CORE_ADDR fence = start_pc - heuristic_fence_post; + + if (start_pc == 0) return 0; + + if (heuristic_fence_post == UINT_MAX + || fence < VM_MIN_ADDRESS) + fence = VM_MIN_ADDRESS; + + /* search back for previous return */ + for (start_pc -= 4; ; start_pc -= 4) + if (start_pc < fence) + { + /* It's not clear to me why we reach this point when + stop_soon_quietly, but with this test, at least we + don't print out warnings for every child forked (eg, on + decstation). 22apr93 rich@cygnus.com. */ + if (!stop_soon_quietly) + { + static int blurb_printed = 0; + + if (fence == VM_MIN_ADDRESS) + warning("Hit beginning of text section without finding"); + else + warning("Hit heuristic-fence-post without finding"); + + warning("enclosing function for address 0x%lx", pc); + if (!blurb_printed) + { + printf_filtered ("\ +This warning occurs if you are debugging a function without any symbols\n\ +(for example, in a stripped executable). In that case, you may wish to\n\ +increase the size of the search with the `set heuristic-fence-post' command.\n\ +\n\ +Otherwise, you told GDB there was a function where there isn't one, or\n\ +(more likely) you have encountered a bug in GDB.\n"); + blurb_printed = 1; + } + } + + return 0; + } + else if (ABOUT_TO_RETURN(start_pc)) + break; + + start_pc += 4; /* skip return */ + return start_pc; +} + +static alpha_extra_func_info_t +heuristic_proc_desc(start_pc, limit_pc, next_frame) + CORE_ADDR start_pc, limit_pc; + struct frame_info *next_frame; +{ + CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); + CORE_ADDR cur_pc; + int frame_size; + int has_frame_reg = 0; + unsigned long reg_mask = 0; + int pcreg = -1; + + if (start_pc == 0) + return NULL; + memset (&temp_proc_desc, '\0', sizeof(temp_proc_desc)); + memset (&temp_saved_regs, '\0', sizeof(struct frame_saved_regs)); + PROC_LOW_ADDR (&temp_proc_desc) = start_pc; + + if (start_pc + 200 < limit_pc) + limit_pc = start_pc + 200; + frame_size = 0; + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) + { + char buf[4]; + unsigned long word; + int status; + + status = read_memory_nobpt (cur_pc, buf, 4); + if (status) + memory_error (status, cur_pc); + word = extract_unsigned_integer (buf, 4); + + if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ + frame_size += (-word) & 0xffff; + else if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ + && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ + { + int reg = (word & 0x03e00000) >> 21; + reg_mask |= 1 << reg; + temp_saved_regs.regs[reg] = sp + (short)word; + + /* Starting with OSF/1-3.2C, the system libraries are shipped + without local symbols, but they still contain procedure + descriptors without a symbol reference. GDB is currently + unable to find these procedure descriptors and uses + heuristic_proc_desc instead. + As some low level compiler support routines (__div*, __add*) + use a non-standard return address register, we have to + add some heuristics to determine the return address register, + or stepping over these routines will fail. + Usually the return address register is the first register + saved on the stack, but assembler optimization might + rearrange the register saves. + So we recognize only a few registers (t7, t9, ra) within + the procedure prologue as valid return address registers. + + FIXME: Rewriting GDB to access the procedure descriptors, + e.g. via the minimal symbol table, might obviate this hack. */ + if (pcreg == -1 + && cur_pc < (start_pc + 20) + && (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM)) + pcreg = reg; + } + else if (word == 0x47de040f) /* bis sp,sp fp */ + has_frame_reg = 1; + } + if (pcreg == -1) + { + /* If we haven't found a valid return address register yet, + keep searching in the procedure prologue. */ + while (cur_pc < (limit_pc + 20) && cur_pc < (start_pc + 20)) + { + char buf[4]; + unsigned long word; + int status; + + status = read_memory_nobpt (cur_pc, buf, 4); + if (status) + memory_error (status, cur_pc); + cur_pc += 4; + word = extract_unsigned_integer (buf, 4); + + if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */ + && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */ + { + int reg = (word & 0x03e00000) >> 21; + if (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM) + { + pcreg = reg; + break; + } + } + } + } + + if (has_frame_reg) + PROC_FRAME_REG(&temp_proc_desc) = GCC_FP_REGNUM; + else + PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM; + PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size; + PROC_REG_MASK(&temp_proc_desc) = reg_mask; + PROC_PC_REG(&temp_proc_desc) = (pcreg == -1) ? RA_REGNUM : pcreg; + PROC_LOCALOFF(&temp_proc_desc) = 0; /* XXX - bogus */ + return &temp_proc_desc; +} + +/* This returns the PC of the first inst after the prologue. If we can't + find the prologue, then return 0. */ + +static CORE_ADDR +after_prologue (pc, proc_desc) + CORE_ADDR pc; + alpha_extra_func_info_t proc_desc; +{ + struct symtab_and_line sal; + CORE_ADDR func_addr, func_end; + + if (!proc_desc) + proc_desc = find_proc_desc (pc, NULL); + + if (proc_desc) + { + /* If function is frameless, then we need to do it the hard way. I + strongly suspect that frameless always means prologueless... */ + if (PROC_FRAME_REG (proc_desc) == SP_REGNUM + && PROC_FRAME_OFFSET (proc_desc) == 0) + return 0; + } + + if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + return 0; /* Unknown */ + + sal = find_pc_line (func_addr, 0); + + if (sal.end < func_end) + return sal.end; + + /* The line after the prologue is after the end of the function. In this + case, tell the caller to find the prologue the hard way. */ + + return 0; +} + +/* Return non-zero if we *might* be in a function prologue. Return zero if we + are definatly *not* in a function prologue. */ + +static int +alpha_in_prologue (pc, proc_desc) + CORE_ADDR pc; + alpha_extra_func_info_t proc_desc; +{ + CORE_ADDR after_prologue_pc; + + after_prologue_pc = after_prologue (pc, proc_desc); + + if (after_prologue_pc == 0 + || pc < after_prologue_pc) + return 1; + else + return 0; +} + +static alpha_extra_func_info_t +find_proc_desc (pc, next_frame) + CORE_ADDR pc; + struct frame_info *next_frame; +{ + alpha_extra_func_info_t proc_desc; + struct block *b; + struct symbol *sym; + CORE_ADDR startaddr; + + /* Try to get the proc_desc from the linked call dummy proc_descs + if the pc is in the call dummy. + This is hairy. In the case of nested dummy calls we have to find the + right proc_desc, but we might not yet know the frame for the dummy + as it will be contained in the proc_desc we are searching for. + So we have to find the proc_desc whose frame is closest to the current + stack pointer. */ + + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + { + struct linked_proc_info *link; + CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM); + alpha_extra_func_info_t found_proc_desc = NULL; + long min_distance = LONG_MAX; + + for (link = linked_proc_desc_table; link; link = link->next) + { + long distance = (CORE_ADDR) PROC_DUMMY_FRAME (&link->info) - sp; + if (distance > 0 && distance < min_distance) + { + min_distance = distance; + found_proc_desc = &link->info; + } + } + if (found_proc_desc != NULL) + return found_proc_desc; + } + + b = block_for_pc(pc); + + find_pc_partial_function (pc, NULL, &startaddr, NULL); + if (b == NULL) + sym = NULL; + else + { + if (startaddr > BLOCK_START (b)) + /* This is the "pathological" case referred to in a comment in + print_frame_info. It might be better to move this check into + symbol reading. */ + sym = NULL; + else + sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, + 0, NULL); + } + + /* If we never found a PDR for this function in symbol reading, then + examine prologues to find the information. */ + if (sym && ((mips_extra_func_info_t) SYMBOL_VALUE (sym))->pdr.framereg == -1) + sym = NULL; + + if (sym) + { + /* IF this is the topmost frame AND + * (this proc does not have debugging information OR + * the PC is in the procedure prologue) + * THEN create a "heuristic" proc_desc (by analyzing + * the actual code) to replace the "official" proc_desc. + */ + proc_desc = (alpha_extra_func_info_t)SYMBOL_VALUE(sym); + if (next_frame == NULL) + { + if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc)) + { + alpha_extra_func_info_t found_heuristic = + heuristic_proc_desc (PROC_LOW_ADDR (proc_desc), + pc, next_frame); + if (found_heuristic) + { + PROC_LOCALOFF (found_heuristic) = + PROC_LOCALOFF (proc_desc); + PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc); + proc_desc = found_heuristic; + } + } + } + } + else + { + /* Is linked_proc_desc_table really necessary? It only seems to be used + by procedure call dummys. However, the procedures being called ought + to have their own proc_descs, and even if they don't, + heuristic_proc_desc knows how to create them! */ + + register struct linked_proc_info *link; + for (link = linked_proc_desc_table; link; link = link->next) + if (PROC_LOW_ADDR(&link->info) <= pc + && PROC_HIGH_ADDR(&link->info) > pc) + return &link->info; + + if (startaddr == 0) + startaddr = heuristic_proc_start (pc); + + proc_desc = + heuristic_proc_desc (startaddr, pc, next_frame); + } + return proc_desc; +} + +alpha_extra_func_info_t cached_proc_desc; + +CORE_ADDR +alpha_frame_chain(frame) + struct frame_info *frame; +{ + alpha_extra_func_info_t proc_desc; + CORE_ADDR saved_pc = FRAME_SAVED_PC(frame); + + if (saved_pc == 0 || inside_entry_file (saved_pc)) + return 0; + + proc_desc = find_proc_desc(saved_pc, frame); + if (!proc_desc) + return 0; + + cached_proc_desc = proc_desc; + + /* Fetch the frame pointer for a dummy frame from the procedure + descriptor. */ + if (PROC_DESC_IS_DUMMY(proc_desc)) + return (CORE_ADDR) PROC_DUMMY_FRAME(proc_desc); + + /* If no frame pointer and frame size is zero, we must be at end + of stack (or otherwise hosed). If we don't check frame size, + we loop forever if we see a zero size frame. */ + if (PROC_FRAME_REG (proc_desc) == SP_REGNUM + && PROC_FRAME_OFFSET (proc_desc) == 0 + /* The previous frame from a sigtramp frame might be frameless + and have frame size zero. */ + && !frame->signal_handler_caller) + { + /* The alpha __sigtramp routine is frameless and has a frame size + of zero, but we are able to backtrace through it. */ + char *name; + find_pc_partial_function (saved_pc, &name, + (CORE_ADDR *)NULL, (CORE_ADDR *)NULL); + if (IN_SIGTRAMP (saved_pc, name)) + return frame->frame; + else + return 0; + } + else + return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); +} + +void +init_extra_frame_info (frame) + struct frame_info *frame; +{ + /* Use proc_desc calculated in frame_chain */ + alpha_extra_func_info_t proc_desc = + frame->next ? cached_proc_desc : find_proc_desc(frame->pc, frame->next); + + frame->saved_regs = NULL; + frame->localoff = 0; + frame->pc_reg = RA_REGNUM; + frame->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc; + if (proc_desc) + { + /* Get the locals offset and the saved pc register from the + procedure descriptor, they are valid even if we are in the + middle of the prologue. */ + frame->localoff = PROC_LOCALOFF(proc_desc); + frame->pc_reg = PROC_PC_REG(proc_desc); + + /* Fixup frame-pointer - only needed for top frame */ + + /* Fetch the frame pointer for a dummy frame from the procedure + descriptor. */ + if (PROC_DESC_IS_DUMMY(proc_desc)) + frame->frame = (CORE_ADDR) PROC_DUMMY_FRAME(proc_desc); + + /* This may not be quite right, if proc has a real frame register. + Get the value of the frame relative sp, procedure might have been + interrupted by a signal at it's very start. */ + else if (frame->pc == PROC_LOW_ADDR (proc_desc) && !PROC_DESC_IS_DUMMY (proc_desc)) + frame->frame = read_next_frame_reg (frame->next, SP_REGNUM); + else + frame->frame = read_next_frame_reg (frame->next, PROC_FRAME_REG (proc_desc)) + + PROC_FRAME_OFFSET (proc_desc); + + if (proc_desc == &temp_proc_desc) + { + char *name; + + /* Do not set the saved registers for a sigtramp frame, + alpha_find_saved_registers will do that for us. + We can't use frame->signal_handler_caller, it is not yet set. */ + find_pc_partial_function (frame->pc, &name, + (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + if (!IN_SIGTRAMP (frame->pc, name)) + { + frame->saved_regs = (struct frame_saved_regs*) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_saved_regs)); + *frame->saved_regs = temp_saved_regs; + frame->saved_regs->regs[PC_REGNUM] + = frame->saved_regs->regs[RA_REGNUM]; + } + } + } +} + +/* ALPHA stack frames are almost impenetrable. When execution stops, + we basically have to look at symbol information for the function + that we stopped in, which tells us *which* register (if any) is + the base of the frame pointer, and what offset from that register + the frame itself is at. + + This presents a problem when trying to examine a stack in memory + (that isn't executing at the moment), using the "frame" command. We + don't have a PC, nor do we have any registers except SP. + + This routine takes two arguments, SP and PC, and tries to make the + cached frames look as if these two arguments defined a frame on the + cache. This allows the rest of info frame to extract the important + arguments without difficulty. */ + +struct frame_info * +setup_arbitrary_frame (argc, argv) + int argc; + CORE_ADDR *argv; +{ + if (argc != 2) + error ("ALPHA frame specifications require two arguments: sp and pc"); + + return create_new_frame (argv[0], argv[1]); +} + +/* The alpha passes the first six arguments in the registers, the rest on + the stack. The register arguments are eventually transferred to the + argument transfer area immediately below the stack by the called function + anyway. So we `push' at least six arguments on the stack, `reload' the + argument registers and then adjust the stack pointer to point past the + sixth argument. This algorithm simplifies the passing of a large struct + which extends from the registers to the stack. + If the called function is returning a structure, the address of the + structure to be returned is passed as a hidden first argument. */ + +CORE_ADDR +alpha_push_arguments (nargs, args, sp, struct_return, struct_addr) + int nargs; + value_ptr *args; + CORE_ADDR sp; + int struct_return; + CORE_ADDR struct_addr; +{ + register i; + int accumulate_size = struct_return ? 8 : 0; + int arg_regs_size = ALPHA_NUM_ARG_REGS * 8; + struct alpha_arg { char *contents; int len; int offset; }; + struct alpha_arg *alpha_args = + (struct alpha_arg*)alloca (nargs * sizeof (struct alpha_arg)); + register struct alpha_arg *m_arg; + char raw_buffer[sizeof (CORE_ADDR)]; + int required_arg_regs; + + for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++) + { + value_ptr arg = args[i]; + struct type *arg_type = check_typedef (VALUE_TYPE (arg)); + /* Cast argument to long if necessary as the compiler does it too. */ + switch (TYPE_CODE (arg_type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long)) + { + arg_type = builtin_type_long; + arg = value_cast (arg_type, arg); + } + break; + default: + break; + } + m_arg->len = TYPE_LENGTH (arg_type); + m_arg->offset = accumulate_size; + accumulate_size = (accumulate_size + m_arg->len + 7) & ~7; + m_arg->contents = VALUE_CONTENTS(arg); + } + + /* Determine required argument register loads, loading an argument register + is expensive as it uses three ptrace calls. */ + required_arg_regs = accumulate_size / 8; + if (required_arg_regs > ALPHA_NUM_ARG_REGS) + required_arg_regs = ALPHA_NUM_ARG_REGS; + + /* Make room for the arguments on the stack. */ + if (accumulate_size < arg_regs_size) + accumulate_size = arg_regs_size; + sp -= accumulate_size; + + /* Keep sp aligned to a multiple of 16 as the compiler does it too. */ + sp &= ~15; + + /* `Push' arguments on the stack. */ + for (i = nargs; m_arg--, --i >= 0; ) + write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len); + if (struct_return) + { + store_address (raw_buffer, sizeof (CORE_ADDR), struct_addr); + write_memory (sp, raw_buffer, sizeof (CORE_ADDR)); + } + + /* Load the argument registers. */ + for (i = 0; i < required_arg_regs; i++) + { + LONGEST val; + + val = read_memory_integer (sp + i * 8, 8); + write_register (A0_REGNUM + i, val); + write_register (FPA0_REGNUM + i, val); + } + + return sp + arg_regs_size; +} + +void +alpha_push_dummy_frame() +{ + int ireg; + struct linked_proc_info *link; + alpha_extra_func_info_t proc_desc; + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR save_address; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned long mask; + + link = (struct linked_proc_info *) xmalloc(sizeof (struct linked_proc_info)); + link->next = linked_proc_desc_table; + linked_proc_desc_table = link; + + proc_desc = &link->info; + + /* + * The registers we must save are all those not preserved across + * procedure calls. + * In addition, we must save the PC and RA. + * + * Dummy frame layout: + * (high memory) + * Saved PC + * Saved F30 + * ... + * Saved F0 + * Saved R29 + * ... + * Saved R0 + * Saved R26 (RA) + * Parameter build area + * (low memory) + */ + +/* MASK(i,j) == (1<>= 1) + if (mask & 1) + { + if (ireg == RA_REGNUM) + continue; + store_address (raw_buffer, 8, read_register (ireg)); + write_memory (save_address, raw_buffer, 8); + save_address += 8; + } + + store_address (raw_buffer, 8, read_register (PC_REGNUM)); + write_memory (sp - 8, raw_buffer, 8); + + /* Save floating point registers. */ + save_address = sp + PROC_FREG_OFFSET(proc_desc); + mask = PROC_FREG_MASK(proc_desc) & 0xffffffffL; + for (ireg = 0; mask; ireg++, mask >>= 1) + if (mask & 1) + { + store_address (raw_buffer, 8, read_register (ireg + FP0_REGNUM)); + write_memory (save_address, raw_buffer, 8); + save_address += 8; + } + + /* Set and save the frame address for the dummy. + This is tricky. The only registers that are suitable for a frame save + are those that are preserved across procedure calls (s0-s6). But if + a read system call is interrupted and then a dummy call is made + (see testsuite/gdb.t17/interrupt.exp) the dummy call hangs till the read + is satisfied. Then it returns with the s0-s6 registers set to the values + on entry to the read system call and our dummy frame pointer would be + destroyed. So we save the dummy frame in the proc_desc and handle the + retrieval of the frame pointer of a dummy specifically. The frame register + is set to the virtual frame (pseudo) register, it's value will always + be read as zero and will help us to catch any errors in the dummy frame + retrieval code. */ + PROC_DUMMY_FRAME(proc_desc) = sp; + PROC_FRAME_REG(proc_desc) = FP_REGNUM; + PROC_FRAME_OFFSET(proc_desc) = 0; + sp += PROC_REG_OFFSET(proc_desc); + write_register (SP_REGNUM, sp); + + PROC_LOW_ADDR(proc_desc) = CALL_DUMMY_ADDRESS (); + PROC_HIGH_ADDR(proc_desc) = PROC_LOW_ADDR(proc_desc) + 4; + + SET_PROC_DESC_IS_DUMMY(proc_desc); + PROC_PC_REG(proc_desc) = RA_REGNUM; +} + +void +alpha_pop_frame() +{ + register int regnum; + struct frame_info *frame = get_current_frame (); + CORE_ADDR new_sp = frame->frame; + + alpha_extra_func_info_t proc_desc = frame->proc_desc; + + write_register (PC_REGNUM, FRAME_SAVED_PC(frame)); + if (frame->saved_regs == NULL) + alpha_find_saved_regs (frame); + if (proc_desc) + { + for (regnum = 32; --regnum >= 0; ) + if (PROC_REG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum, + read_memory_integer (frame->saved_regs->regs[regnum], + 8)); + for (regnum = 32; --regnum >= 0; ) + if (PROC_FREG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum + FP0_REGNUM, + read_memory_integer (frame->saved_regs->regs[regnum + FP0_REGNUM], 8)); + } + write_register (SP_REGNUM, new_sp); + flush_cached_frames (); + + if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + { + struct linked_proc_info *pi_ptr, *prev_ptr; + + for (pi_ptr = linked_proc_desc_table, prev_ptr = NULL; + pi_ptr != NULL; + prev_ptr = pi_ptr, pi_ptr = pi_ptr->next) + { + if (&pi_ptr->info == proc_desc) + break; + } + + if (pi_ptr == NULL) + error ("Can't locate dummy extra frame info\n"); + + if (prev_ptr != NULL) + prev_ptr->next = pi_ptr->next; + else + linked_proc_desc_table = pi_ptr->next; + + free (pi_ptr); + } +} + +/* To skip prologues, I use this predicate. Returns either PC itself + if the code at PC does not look like a function prologue; otherwise + returns an address that (if we're lucky) follows the prologue. If + LENIENT, then we must skip everything which is involved in setting + up the frame (it's OK to skip more, just so long as we don't skip + anything which might clobber the registers which are being saved. + Currently we must not skip more on the alpha, but we might the lenient + stuff some day. */ + +CORE_ADDR +alpha_skip_prologue (pc, lenient) + CORE_ADDR pc; + int lenient; +{ + unsigned long inst; + int offset; + CORE_ADDR post_prologue_pc; + char buf[4]; + +#ifdef GDB_TARGET_HAS_SHARED_LIBS + /* Silently return the unaltered pc upon memory errors. + This could happen on OSF/1 if decode_line_1 tries to skip the + prologue for quickstarted shared library functions when the + shared library is not yet mapped in. + Reading target memory is slow over serial lines, so we perform + this check only if the target has shared libraries. */ + if (target_read_memory (pc, buf, 4)) + return pc; +#endif + + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ + + post_prologue_pc = after_prologue (pc, NULL); + + if (post_prologue_pc != 0) + return max (pc, post_prologue_pc); + + /* Can't determine prologue from the symbol table, need to examine + instructions. */ + + /* Skip the typical prologue instructions. These are the stack adjustment + instruction and the instructions that save registers on the stack + or in the gcc frame. */ + for (offset = 0; offset < 100; offset += 4) + { + int status; + + status = read_memory_nobpt (pc + offset, buf, 4); + if (status) + memory_error (status, pc + offset); + inst = extract_unsigned_integer (buf, 4); + + /* The alpha has no delay slots. But let's keep the lenient stuff, + we might need it for something else in the future. */ + if (lenient && 0) + continue; + + if ((inst & 0xffff0000) == 0x27bb0000) /* ldah $gp,n($t12) */ + continue; + if ((inst & 0xffff0000) == 0x23bd0000) /* lda $gp,n($gp) */ + continue; + if ((inst & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */ + continue; + else if ((inst & 0xfc1f0000) == 0xb41e0000 + && (inst & 0xffff0000) != 0xb7fe0000) + continue; /* stq reg,n($sp) */ + /* reg != $zero */ + else if ((inst & 0xfc1f0000) == 0x9c1e0000 + && (inst & 0xffff0000) != 0x9ffe0000) + continue; /* stt reg,n($sp) */ + /* reg != $zero */ + else if (inst == 0x47de040f) /* bis sp,sp,fp */ + continue; + else + break; + } + return pc + offset; +} + +#if 0 +/* Is address PC in the prologue (loosely defined) for function at + STARTADDR? */ + +static int +alpha_in_lenient_prologue (startaddr, pc) + CORE_ADDR startaddr; + CORE_ADDR pc; +{ + CORE_ADDR end_prologue = alpha_skip_prologue (startaddr, 1); + return pc >= startaddr && pc < end_prologue; +} +#endif + +/* The alpha needs a conversion between register and memory format if + the register is a floating point register and + memory format is float, as the register format must be double + or + memory format is an integer with 4 bytes or less, as the representation + of integers in floating point registers is different. */ +void +alpha_register_convert_to_virtual (regnum, valtype, raw_buffer, virtual_buffer) + int regnum; + struct type *valtype; + char *raw_buffer; + char *virtual_buffer; +{ + if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) + { + memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum)); + return; + } + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + double d = extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum)); + store_floating (virtual_buffer, TYPE_LENGTH (valtype), d); + } + else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4) + { + unsigned LONGEST l; + l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum)); + l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff); + store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l); + } + else + error ("Cannot retrieve value from floating point register"); +} + +void +alpha_register_convert_to_raw (valtype, regnum, virtual_buffer, raw_buffer) + struct type *valtype; + int regnum; + char *virtual_buffer; + char *raw_buffer; +{ + if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum)) + { + memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum)); + return; + } + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + double d = extract_floating (virtual_buffer, TYPE_LENGTH (valtype)); + store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d); + } + else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4) + { + unsigned LONGEST l; + if (TYPE_UNSIGNED (valtype)) + l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype)); + else + l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype)); + l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29); + store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l); + } + else + error ("Cannot store value in floating point register"); +} + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + +void +alpha_extract_return_value (valtype, regbuf, valbuf) + struct type *valtype; + char regbuf[REGISTER_BYTES]; + char *valbuf; +{ + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + alpha_register_convert_to_virtual (FP0_REGNUM, valtype, + regbuf + REGISTER_BYTE (FP0_REGNUM), + valbuf); + else + memcpy (valbuf, regbuf + REGISTER_BYTE (V0_REGNUM), TYPE_LENGTH (valtype)); +} + +/* Given a return value in `regbuf' with a type `valtype', + write its value into the appropriate register. */ + +void +alpha_store_return_value (valtype, valbuf) + struct type *valtype; + char *valbuf; +{ + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + int regnum = V0_REGNUM; + int length = TYPE_LENGTH (valtype); + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) + { + regnum = FP0_REGNUM; + length = REGISTER_RAW_SIZE (regnum); + alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer); + } + else + memcpy (raw_buffer, valbuf, length); + + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length); +} + +/* Just like reinit_frame_cache, but with the right arguments to be + callable as an sfunc. */ + +static void +reinit_frame_cache_sfunc (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + reinit_frame_cache (); +} + +/* This is the definition of CALL_DUMMY_ADDRESS. It's a heuristic that is used + to find a convenient place in the text segment to stick a breakpoint to + detect the completion of a target function call (ala call_function_by_hand). + */ + +CORE_ADDR +alpha_call_dummy_address () +{ + CORE_ADDR entry; + struct minimal_symbol *sym; + + entry = entry_point_address (); + + if (entry != 0) + return entry; + + sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile); + + if (!sym || MSYMBOL_TYPE (sym) != mst_text) + return 0; + else + return SYMBOL_VALUE_ADDRESS (sym) + 4; +} + +void +_initialize_alpha_tdep () +{ + struct cmd_list_element *c; + + tm_print_insn = print_insn_alpha; + + /* Let the user set the fence post for heuristic_proc_start. */ + + /* We really would like to have both "0" and "unlimited" work, but + command.c doesn't deal with that. So make it a var_zinteger + because the user can always use "999999" or some such for unlimited. */ + c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger, + (char *) &heuristic_fence_post, + "\ +Set the distance searched for the start of a function.\n\ +If you are debugging a stripped executable, GDB needs to search through the\n\ +program for the start of a function. This command sets the distance of the\n\ +search. The only need to set it is when debugging a stripped executable.", + &setlist); + /* We need to throw away the frame cache when we set this, since it + might change our ability to get backtraces. */ + c->function.sfunc = reinit_frame_cache_sfunc; + add_show_from_set (c, &showlist); +} diff --git a/contrib/gdb/gdb/annotate.c b/contrib/gdb/gdb/annotate.c new file mode 100644 index 000000000000..282e171710a2 --- /dev/null +++ b/contrib/gdb/gdb/annotate.c @@ -0,0 +1,540 @@ +/* Annotation routines for GDB. + Copyright 1986, 1989, 1990, 1991, 1992, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "annotate.h" +#include "value.h" +#include "target.h" +#include "gdbtypes.h" +#include "breakpoint.h" + +static void print_value_flags PARAMS ((struct type *)); + +static void +print_value_flags (t) + struct type *t; +{ + if (can_dereference (t)) + printf_filtered ("*"); + else + printf_filtered ("-"); +} + +void +breakpoints_changed () +{ + if (annotation_level > 1) + { + target_terminal_ours (); + printf_unfiltered ("\n\032\032breakpoints-invalid\n"); + } +} + +void +annotate_breakpoint (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoint %d\n", num); +} + +void +annotate_watchpoint (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032watchpoint %d\n", num); +} + +void +annotate_starting () +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032starting\n"); + } +} + +void +annotate_stopped () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032stopped\n"); +} + +void +annotate_exited (exitstatus) + int exitstatus; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032exited %d\n", exitstatus); +} + +void +annotate_signalled () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signalled\n"); +} + +void +annotate_signal_name () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-name\n"); +} + +void +annotate_signal_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-name-end\n"); +} + +void +annotate_signal_string () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-string\n"); +} + +void +annotate_signal_string_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-string-end\n"); +} + +void +annotate_signal () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal\n"); +} + +void +annotate_breakpoints_headers () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-headers\n"); +} + +void +annotate_field (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field %d\n", num); +} + +void +annotate_breakpoints_table () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-table\n"); +} + +void +annotate_record () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032record\n"); +} + +void +annotate_breakpoints_table_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-table-end\n"); +} + +void +annotate_frames_invalid () +{ + if (annotation_level > 1) + { + target_terminal_ours (); + printf_unfiltered ("\n\032\032frames-invalid\n"); + } +} + +void +annotate_field_begin (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032field-begin "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_field_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-name-end\n"); +} + +void +annotate_field_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-value\n"); +} + +void +annotate_field_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-end\n"); +} + +void +annotate_quit () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032quit\n"); +} + +void +annotate_error () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032error\n"); +} + +void +annotate_error_begin () +{ + if (annotation_level > 1) + fprintf_filtered (gdb_stderr, "\n\032\032error-begin\n"); +} + +void +annotate_value_history_begin (histindex, type) + int histindex; + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032value-history-begin %d ", histindex); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_value_begin (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032value-begin "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_value_history_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-history-value\n"); +} + +void +annotate_value_history_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-history-end\n"); +} + +void +annotate_value_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-end\n"); +} + +void +annotate_display_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-begin\n"); +} + +void +annotate_display_number_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-number-end\n"); +} + +void +annotate_display_format () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-format\n"); +} + +void +annotate_display_expression () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-expression\n"); +} + +void +annotate_display_expression_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-expression-end\n"); +} + +void +annotate_display_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-value\n"); +} + +void +annotate_display_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-end\n"); +} + +void +annotate_arg_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-begin\n"); +} + +void +annotate_arg_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-name-end\n"); +} + +void +annotate_arg_value (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032arg-value "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_arg_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-end\n"); +} + +void +annotate_source (filename, line, character, mid, pc) + char *filename; + int line; + int character; + int mid; + CORE_ADDR pc; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032source "); + else + printf_filtered ("\032\032"); + + printf_filtered ("%s:%d:%d:%s:0x", filename, + line, character, + mid ? "middle" : "beg"); + print_address_numeric (pc, 0, gdb_stdout); + printf_filtered ("\n"); +} + +void +annotate_frame_begin (level, pc) + int level; + CORE_ADDR pc; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032frame-begin %d 0x", level); + print_address_numeric (pc, 0, gdb_stdout); + printf_filtered ("\n"); + } +} + +void +annotate_function_call () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032function-call\n"); +} + +void +annotate_signal_handler_caller () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-handler-caller\n"); +} + +void +annotate_frame_address () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-address\n"); +} + +void +annotate_frame_address_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-address-end\n"); +} + +void +annotate_frame_function_name () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-function-name\n"); +} + +void +annotate_frame_args () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-args\n"); +} + +void +annotate_frame_source_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-begin\n"); +} + +void +annotate_frame_source_file () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-file\n"); +} + +void +annotate_frame_source_file_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-file-end\n"); +} + +void +annotate_frame_source_line () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-line\n"); +} + +void +annotate_frame_source_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-end\n"); +} + +void +annotate_frame_where () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-where\n"); +} + +void +annotate_frame_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-end\n"); +} + +void +annotate_array_section_begin (index, elttype) + int index; + struct type *elttype; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032array-section-begin %d ", index); + print_value_flags (elttype); + printf_filtered ("\n"); + } +} + +void +annotate_elt_rep (repcount) + unsigned int repcount; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt-rep %u\n", repcount); +} + +void +annotate_elt_rep_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt-rep-end\n"); +} + +void +annotate_elt () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt\n"); +} + +void +annotate_array_section_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032array-section-end\n"); +} + +static void +breakpoint_changed (b) + struct breakpoint *b; +{ + breakpoints_changed (); +} + +void +_initialize_annotate () +{ + if (annotation_level > 1) + { + delete_breakpoint_hook = breakpoint_changed; + modify_breakpoint_hook = breakpoint_changed; + } +} diff --git a/contrib/gdb/gdb/annotate.h b/contrib/gdb/gdb/annotate.h new file mode 100644 index 000000000000..b91d140bf82e --- /dev/null +++ b/contrib/gdb/gdb/annotate.h @@ -0,0 +1,95 @@ +/* Annotation routines for GDB. + Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern void breakpoints_changed PARAMS ((void)); + +extern void annotate_breakpoint PARAMS ((int)); +extern void annotate_watchpoint PARAMS ((int)); +extern void annotate_starting PARAMS ((void)); +extern void annotate_stopped PARAMS ((void)); +extern void annotate_exited PARAMS ((int)); +extern void annotate_signalled PARAMS ((void)); +extern void annotate_signal_name PARAMS ((void)); +extern void annotate_signal_name_end PARAMS ((void)); +extern void annotate_signal_string PARAMS ((void)); +extern void annotate_signal_string_end PARAMS ((void)); +extern void annotate_signal PARAMS ((void)); + +extern void annotate_breakpoints_headers PARAMS ((void)); +extern void annotate_field PARAMS ((int)); +extern void annotate_breakpoints_table PARAMS ((void)); +extern void annotate_record PARAMS ((void)); +extern void annotate_breakpoints_table_end PARAMS ((void)); + +extern void annotate_frames_invalid PARAMS ((void)); + +#ifdef __STDC__ +struct type; +#endif + +extern void annotate_field_begin PARAMS ((struct type *)); +extern void annotate_field_name_end PARAMS ((void)); +extern void annotate_field_value PARAMS ((void)); +extern void annotate_field_end PARAMS ((void)); + +extern void annotate_quit PARAMS ((void)); +extern void annotate_error PARAMS ((void)); +extern void annotate_error_begin PARAMS ((void)); + +extern void annotate_value_history_begin PARAMS ((int, struct type *)); +extern void annotate_value_begin PARAMS ((struct type *)); +extern void annotate_value_history_value PARAMS ((void)); +extern void annotate_value_history_end PARAMS ((void)); +extern void annotate_value_end PARAMS ((void)); + +extern void annotate_display_begin PARAMS ((void)); +extern void annotate_display_number_end PARAMS ((void)); +extern void annotate_display_format PARAMS ((void)); +extern void annotate_display_expression PARAMS ((void)); +extern void annotate_display_expression_end PARAMS ((void)); +extern void annotate_display_value PARAMS ((void)); +extern void annotate_display_end PARAMS ((void)); + +extern void annotate_arg_begin PARAMS ((void)); +extern void annotate_arg_name_end PARAMS ((void)); +extern void annotate_arg_value PARAMS ((struct type *)); +extern void annotate_arg_end PARAMS ((void)); + +extern void annotate_source PARAMS ((char *, int, int, int, CORE_ADDR)); + +extern void annotate_frame_begin PARAMS ((int, CORE_ADDR)); +extern void annotate_function_call PARAMS ((void)); +extern void annotate_signal_handler_caller PARAMS ((void)); +extern void annotate_frame_address PARAMS ((void)); +extern void annotate_frame_address_end PARAMS ((void)); +extern void annotate_frame_function_name PARAMS ((void)); +extern void annotate_frame_args PARAMS ((void)); +extern void annotate_frame_source_begin PARAMS ((void)); +extern void annotate_frame_source_file PARAMS ((void)); +extern void annotate_frame_source_file_end PARAMS ((void)); +extern void annotate_frame_source_line PARAMS ((void)); +extern void annotate_frame_source_end PARAMS ((void)); +extern void annotate_frame_where PARAMS ((void)); +extern void annotate_frame_end PARAMS ((void)); + +extern void annotate_array_section_begin PARAMS ((int, struct type *)); +extern void annotate_elt_rep PARAMS ((unsigned int)); +extern void annotate_elt_rep_end PARAMS ((void)); +extern void annotate_elt PARAMS ((void)); +extern void annotate_array_section_end PARAMS ((void)); diff --git a/contrib/gdb/gdb/arm-convert.s b/contrib/gdb/gdb/arm-convert.s new file mode 100644 index 000000000000..416132b77c77 --- /dev/null +++ b/contrib/gdb/gdb/arm-convert.s @@ -0,0 +1,16 @@ + .text + .global _convert_from_extended + +_convert_from_extended: + + ldfe f0,[a1] + stfd f0,[a2] + movs pc,lr + + .global _convert_to_extended + +_convert_to_extended: + + ldfd f0,[a1] + stfe f0,[a2] + movs pc,lr diff --git a/contrib/gdb/gdb/arm-tdep.c b/contrib/gdb/gdb/arm-tdep.c new file mode 100644 index 000000000000..884e9d892008 --- /dev/null +++ b/contrib/gdb/gdb/arm-tdep.c @@ -0,0 +1,826 @@ +/* Target-dependent code for the Acorn Risc Machine, for GDB, the GNU Debugger. + Copyright 1988, 1989, 1991, 1992, 1993, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#if 0 +#include "gdbcore.h" +#include +#include +#include +#include +#include +#include + +#define N_TXTADDR(hdr) 0x8000 +#define N_DATADDR(hdr) (hdr.a_text + 0x8000) + +#include /* After a.out.h */ +#include +#include "gdb_stat.h" + +#include +#endif + + +#if 0 +/* Work with core dump and executable files, for GDB. + This code would be in corefile.c if it weren't machine-dependent. */ + +/* Structure to describe the chain of shared libraries used + by the execfile. + e.g. prog shares Xt which shares X11 which shares c. */ + +struct shared_library { + struct exec_header header; + char name[SHLIBLEN]; + CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */ + long data_offset; /* offset of data section in file */ + int chan; /* file descriptor for the file */ + struct shared_library *shares; /* library this one shares */ +}; +static struct shared_library *shlib = 0; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +static CORE_ADDR unshared_text_start; + +/* extended header from exec file (for shared library info) */ + +static struct exec_header exec_header; + +void +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end -= exec_data_start; + text_start = 0; + unshared_text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + if (shlib) { + close_shared_library(shlib); + shlib = 0; + } + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + + { + struct stat st_exec; + +#ifdef HEADER_SEEK_FD + HEADER_SEEK_FD (execchan); +#endif + + val = myread (execchan, &exec_header, sizeof exec_header); + exec_aouthdr = exec_header.a_exec; + + if (val < 0) + perror_with_name (filename); + + text_start = 0x8000; + + /* Look for shared library if needed */ + if (exec_header.a_exec.a_magic & MF_USES_SL) + shlib = open_shared_library(exec_header.a_shlibname, text_start); + + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + + if (shlib) { + unshared_text_start = shared_text_end(shlib) & ~0x7fff; + stack_start = shlib->header.a_exec.a_sldatabase; + stack_end = STACK_END_ADDR; + } else + unshared_text_start = 0x8000; + text_end = unshared_text_start + exec_aouthdr.a_text; + + exec_data_start = unshared_text_start + exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + + data_start = exec_data_start; + data_end += exec_data_start; + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } + + validate_files (); + } + else if (from_tty) + printf ("No exec file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} +#endif + +#if 0 +/* Read from the program's memory (except for inferior processes). + This function is misnamed, since it only reads, never writes; and + since it will use the core file and/or executable file as necessary. + + It should be extended to write as well as read, FIXME, for patching files. + + Return 0 if address could be read, EIO if addresss out of bounds. */ + +int +xfer_core_file (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + register int val; + int xferchan; + char **xferfile; + int fileptr; + int returnval = 0; + + while (len > 0) + { + xferfile = 0; + xferchan = 0; + + /* Determine which file the next bunch of addresses reside in, + and where in the file. Set the file's read/write pointer + to point at the proper place for the desired address + and set xferfile and xferchan for the correct file. + + If desired address is nonexistent, leave them zero. + + i is set to the number of bytes that can be handled + along with the next address. + + We put the most likely tests first for efficiency. */ + + /* Note that if there is no core file + data_start and data_end are equal. */ + if (memaddr >= data_start && memaddr < data_end) + { + i = min (len, data_end - memaddr); + fileptr = memaddr - data_start + data_offset; + xferfile = &corefile; + xferchan = corechan; + } + /* Note that if there is no core file + stack_start and stack_end define the shared library data. */ + else if (memaddr >= stack_start && memaddr < stack_end) + { + if (corechan < 0) { + struct shared_library *lib; + for (lib = shlib; lib; lib = lib->shares) + if (memaddr >= lib->header.a_exec.a_sldatabase && + memaddr < lib->header.a_exec.a_sldatabase + + lib->header.a_exec.a_data) + break; + if (lib) { + i = min (len, lib->header.a_exec.a_sldatabase + + lib->header.a_exec.a_data - memaddr); + fileptr = lib->data_offset + memaddr - + lib->header.a_exec.a_sldatabase; + xferfile = execfile; + xferchan = lib->chan; + } + } else { + i = min (len, stack_end - memaddr); + fileptr = memaddr - stack_start + stack_offset; + xferfile = &corefile; + xferchan = corechan; + } + } + else if (corechan < 0 + && memaddr >= exec_data_start && memaddr < exec_data_end) + { + i = min (len, exec_data_end - memaddr); + fileptr = memaddr - exec_data_start + exec_data_offset; + xferfile = &execfile; + xferchan = execchan; + } + else if (memaddr >= text_start && memaddr < text_end) + { + struct shared_library *lib; + for (lib = shlib; lib; lib = lib->shares) + if (memaddr >= lib->text_start && + memaddr < lib->text_start + lib->header.a_exec.a_text) + break; + if (lib) { + i = min (len, lib->header.a_exec.a_text + + lib->text_start - memaddr); + fileptr = memaddr - lib->text_start + text_offset; + xferfile = &execfile; + xferchan = lib->chan; + } else { + i = min (len, text_end - memaddr); + fileptr = memaddr - unshared_text_start + text_offset; + xferfile = &execfile; + xferchan = execchan; + } + } + else if (memaddr < text_start) + { + i = min (len, text_start - memaddr); + } + else if (memaddr >= text_end + && memaddr < (corechan >= 0? data_start : exec_data_start)) + { + i = min (len, data_start - memaddr); + } + else if (corechan >= 0 + && memaddr >= data_end && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (corechan < 0 && memaddr >= exec_data_end) + { + i = min (len, - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } + else + { + /* Address did not classify into one of the known ranges. + This shouldn't happen; we catch the endpoints. */ + fatal ("Internal: Bad case logic in xfer_core_file."); + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. + Actually, we never right. */ + else + { + memset (myaddr, '\0', i); + returnval = EIO; + } + + memaddr += i; + myaddr += i; + len -= i; + } + return returnval; +} +#endif + +/* APCS (ARM procedure call standard) defines the following prologue: + + mov ip, sp + [stmfd sp!, {a1,a2,a3,a4}] + stmfd sp!, {...,fp,ip,lr,pc} + [stfe f7, [sp, #-12]!] + [stfe f6, [sp, #-12]!] + [stfe f5, [sp, #-12]!] + [stfe f4, [sp, #-12]!] + sub fp, ip, #nn // nn == 20 or 4 depending on second ins +*/ + +CORE_ADDR +skip_prologue(pc) +CORE_ADDR pc; +{ + CORE_ADDR skip_pc = pc; +#if 0 + union insn_fmt op; + + op.ins = read_memory_integer(skip_pc, 4); + /* look for the "mov ip,sp" */ + if (op.generic.type != TYPE_ARITHMETIC || + op.arith.opcode != OPCODE_MOV || + op.arith.dest != SPTEMP || + op.arith.operand2 != SP) return pc; + skip_pc += 4; + /* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type == TYPE_BLOCK_BRANCH && + op.generic.subtype == SUBTYPE_BLOCK && + op.block.mask == 0xf && + op.block.base == SP && + op.block.is_load == 0 && + op.block.writeback == 1 && + op.block.increment == 0 && + op.block.before == 1) skip_pc += 4; + /* skip the "stmfd sp!,{...,fp,ip,lr,pc} */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type != TYPE_BLOCK_BRANCH || + op.generic.subtype != SUBTYPE_BLOCK || + /* the mask should look like 110110xxxxxx0000 */ + (op.block.mask & 0xd800) != 0xd800 || + op.block.base != SP || + op.block.is_load != 0 || + op.block.writeback != 1 || + op.block.increment != 0 || + op.block.before != 1) return pc; + skip_pc += 4; + /* check for "sub fp,ip,#nn" */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type != TYPE_ARITHMETIC || + op.arith.opcode != OPCODE_SUB || + op.arith.dest != FP || + op.arith.operand1 != SPTEMP) return pc; +#endif + return skip_pc + 4; +} + +void +arm_frame_find_saved_regs (frame_info, saved_regs_addr) + struct frame_info *frame_info; + struct frame_saved_regs *saved_regs_addr; +{ + register int regnum; + register int frame; + register int next_addr; + register int return_data_save; + register int saved_register_mask; + + memset (saved_regs_addr, '\0', sizeof (*saved_regs_addr)); + frame = frame_info->frame; + return_data_save = read_memory_integer (frame, 4) & 0x03fffffc - 12; + saved_register_mask = read_memory_integer (return_data_save, 4); + next_addr = frame - 12; + for (regnum = 4; regnum < 10; regnum++) + if (saved_register_mask & (1 << regnum)) + { + next_addr -= 4; + saved_regs_addr->regs[regnum] = next_addr; + } + if (read_memory_integer (return_data_save + 4, 4) == 0xed6d7103) + { + next_addr -= 12; + saved_regs_addr->regs[F0_REGNUM + 7] = next_addr; + } + if (read_memory_integer (return_data_save + 8, 4) == 0xed6d6103) + { + next_addr -= 12; + saved_regs_addr->regs[F0_REGNUM + 6] = next_addr; + } + if (read_memory_integer (return_data_save + 12, 4) == 0xed6d5103) + { + next_addr -= 12; + saved_regs_addr->regs[F0_REGNUM + 5] = next_addr; + } + if (read_memory_integer(return_data_save + 16, 4) == 0xed6d4103) + { + next_addr -= 12; + saved_regs_addr->regs[F0_REGNUM + 4] = next_addr; + } + saved_regs_addr->regs[SP_REGNUM] = next_addr; + saved_regs_addr->regs[PC_REGNUM] = frame - 4; + saved_regs_addr->regs[PS_REGNUM] = frame - 4; + saved_regs_addr->regs[FP_REGNUM] = frame - 12; +} + +static void +print_fpu_flags(flags) +int flags; +{ + if (flags & (1 << 0)) fputs("IVO ", stdout); + if (flags & (1 << 1)) fputs("DVZ ", stdout); + if (flags & (1 << 2)) fputs("OFL ", stdout); + if (flags & (1 << 3)) fputs("UFL ", stdout); + if (flags & (1 << 4)) fputs("INX ", stdout); + putchar('\n'); +} + +void +arm_float_info() +{ + register unsigned long status = read_register(FPS_REGNUM); + int type; + + type = (status >> 24) & 127; + printf("%s FPU type %d\n", + (status & (1<<31)) ? "Hardware" : "Software", + type); + fputs("mask: ", stdout); + print_fpu_flags(status >> 16); + fputs("flags: ", stdout); + print_fpu_flags(status); +} + + +static void arm_othernames() +{ + static int toggle; + static char *original[] = ORIGINAL_REGISTER_NAMES; + static char *extra_crispy[] = ADDITIONAL_REGISTER_NAMES; + + memcpy (reg_names, toggle ? extra_crispy : original, sizeof(original)); + toggle = !toggle; +} +void +_initialize_arm_tdep () +{ + tm_print_insn = print_insn_little_arm; + add_com ("othernames", class_obscure, arm_othernames); +} + +/* FIXME: Fill in with the 'right thing', see asm + template in arm-convert.s */ + +void +convert_from_extended (ptr, dbl) +void *ptr; +double *dbl; +{ + *dbl = *(double*)ptr; +} + + +void +convert_to_extended (dbl, ptr) +void *ptr; +double *dbl; +{ + *(double*)ptr = *dbl; +} + + +int +arm_nullified_insn (inst) + unsigned long inst; +{ + unsigned long cond = inst & 0xf0000000; + unsigned long status_reg; + + if (cond == INST_AL || cond == INST_NV) + return 0; + + status_reg = read_register (PS_REGNUM); + + switch (cond) + { + case INST_EQ: + return ((status_reg & FLAG_Z) == 0); + case INST_NE: + return ((status_reg & FLAG_Z) != 0); + case INST_CS: + return ((status_reg & FLAG_C) == 0); + case INST_CC: + return ((status_reg & FLAG_C) != 0); + case INST_MI: + return ((status_reg & FLAG_N) == 0); + case INST_PL: + return ((status_reg & FLAG_N) != 0); + case INST_VS: + return ((status_reg & FLAG_V) == 0); + case INST_VC: + return ((status_reg & FLAG_V) != 0); + case INST_HI: + return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C); + case INST_LS: + return (((status_reg & (FLAG_C | FLAG_Z)) ^ FLAG_C) == 0); + case INST_GE: + return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)); + case INST_LT: + return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)); + case INST_GT: + return (((status_reg & FLAG_Z) != 0) || + (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0))); + case INST_LE: + return (((status_reg & FLAG_Z) == 0) && + (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0))); + } + return 0; +} + + + +/* taken from remote-arm.c .. */ + +#define submask(x) ((1L << ((x) + 1)) - 1) +#define bit(obj,st) (((obj) & (1L << (st))) >> st) +#define bits(obj,st,fn) \ + (((obj) & submask (fn) & ~ submask ((st) - 1)) >> (st)) +#define sbits(obj,st,fn) \ + ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st)))) +#define BranchDest(addr,instr) \ + ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2))) +#define ARM_PC_32 1 + +static unsigned long +shifted_reg_val (inst, carry, pc_val) + unsigned long inst; + int carry; + unsigned long pc_val; +{ + unsigned long res, shift; + int rm = bits (inst, 0, 3); + unsigned long shifttype = bits (inst, 5, 6); + + if (bit(inst, 4)) + { + int rs = bits (inst, 8, 11); + shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF; + } + else + shift = bits (inst, 7, 11); + + res = (rm == 15 + ? ((pc_val | (ARM_PC_32 ? 0 : read_register (PS_REGNUM))) + + (bit (inst, 4) ? 12 : 8)) + : read_register (rm)); + + switch (shifttype) + { + case 0: /* LSL */ + res = shift >= 32 ? 0 : res << shift; + break; + + case 1: /* LSR */ + res = shift >= 32 ? 0 : res >> shift; + break; + + case 2: /* ASR */ + if (shift >= 32) shift = 31; + res = ((res & 0x80000000L) + ? ~((~res) >> shift) : res >> shift); + break; + + case 3: /* ROR/RRX */ + shift &= 31; + if (shift == 0) + res = (res >> 1) | (carry ? 0x80000000L : 0); + else + res = (res >> shift) | (res << (32-shift)); + break; + } + + return res & 0xffffffff; +} + + +CORE_ADDR +arm_get_next_pc (pc) + CORE_ADDR pc; +{ + unsigned long pc_val = (unsigned long) pc; + unsigned long this_instr = read_memory_integer (pc, 4); + unsigned long status = read_register (PS_REGNUM); + CORE_ADDR nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */ + + if (! arm_nullified_insn (this_instr)) + { + switch (bits(this_instr, 24, 27)) + { + case 0x0: case 0x1: /* data processing */ + case 0x2: case 0x3: + { + unsigned long operand1, operand2, result = 0; + unsigned long rn; + int c; + + if (bits(this_instr, 12, 15) != 15) + break; + + if (bits (this_instr, 22, 25) == 0 + && bits (this_instr, 4, 7) == 9) /* multiply */ + error ("Illegal update to pc in instruction"); + + /* Multiply into PC */ + c = (status & FLAG_C) ? 1 : 0; + rn = bits (this_instr, 16, 19); + operand1 = (rn == 15) ? pc_val + 8 : read_register (rn); + + if (bit (this_instr, 25)) + { + unsigned long immval = bits (this_instr, 0, 7); + unsigned long rotate = 2 * bits (this_instr, 8, 11); + operand2 = ((immval >> rotate) | (immval << (32-rotate)) + & 0xffffffff); + } + else /* operand 2 is a shifted register */ + operand2 = shifted_reg_val (this_instr, c, pc_val); + + switch (bits (this_instr, 21, 24)) + { + case 0x0: /*and*/ + result = operand1 & operand2; + break; + + case 0x1: /*eor*/ + result = operand1 ^ operand2; + break; + + case 0x2: /*sub*/ + result = operand1 - operand2; + break; + + case 0x3: /*rsb*/ + result = operand2 - operand1; + break; + + case 0x4: /*add*/ + result = operand1 + operand2; + break; + + case 0x5: /*adc*/ + result = operand1 + operand2 + c; + break; + + case 0x6: /*sbc*/ + result = operand1 - operand2 + c; + break; + + case 0x7: /*rsc*/ + result = operand2 - operand1 + c; + break; + + case 0x8: case 0x9: case 0xa: case 0xb: /* tst, teq, cmp, cmn */ + result = (unsigned long) nextpc; + break; + + case 0xc: /*orr*/ + result = operand1 | operand2; + break; + + case 0xd: /*mov*/ + /* Always step into a function. */ + result = operand2; + break; + + case 0xe: /*bic*/ + result = operand1 & ~operand2; + break; + + case 0xf: /*mvn*/ + result = ~operand2; + break; + } + nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result); + + if (nextpc == pc) + error ("Infinite loop detected"); + break; + } + + case 0x4: case 0x5: /* data transfer */ + case 0x6: case 0x7: + if (bit (this_instr, 20)) + { + /* load */ + if (bits (this_instr, 12, 15) == 15) + { + /* rd == pc */ + unsigned long rn; + unsigned long base; + + if (bit (this_instr, 22)) + error ("Illegal update to pc in instruction"); + + /* byte write to PC */ + rn = bits (this_instr, 16, 19); + base = (rn == 15) ? pc_val + 8 : read_register (rn); + if (bit (this_instr, 24)) + { + /* pre-indexed */ + int c = (status & FLAG_C) ? 1 : 0; + unsigned long offset = + (bit (this_instr, 25) + ? shifted_reg_val (this_instr, c, pc_val) + : bits (this_instr, 0, 11)); + + if (bit (this_instr, 23)) + base += offset; + else + base -= offset; + } + nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base, + 4); + + nextpc = ADDR_BITS_REMOVE (nextpc); + + if (nextpc == pc) + error ("Infinite loop detected"); + } + } + break; + + case 0x8: case 0x9: /* block transfer */ + if (bit (this_instr, 20)) + { + /* LDM */ + if (bit (this_instr, 15)) + { + /* loading pc */ + int offset = 0; + + if (bit (this_instr, 23)) + { + /* up */ + unsigned long reglist = bits (this_instr, 0, 14); + unsigned long regbit; + + for (; reglist != 0; reglist &= ~regbit) + { + regbit = reglist & (-reglist); + offset += 4; + } + + if (bit (this_instr, 24)) /* pre */ + offset += 4; + } + else if (bit (this_instr, 24)) + offset = -4; + + { + unsigned long rn_val = + read_register (bits (this_instr, 16, 19)); + nextpc = + (CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val + + offset), + 4); + } + nextpc = ADDR_BITS_REMOVE (nextpc); + if (nextpc == pc) + error ("Infinite loop detected"); + } + } + break; + + case 0xb: /* branch & link */ + case 0xa: /* branch */ + { + nextpc = BranchDest (pc, this_instr); + + nextpc = ADDR_BITS_REMOVE (nextpc); + if (nextpc == pc) + error ("Infinite loop detected"); + break; + } + + case 0xc: case 0xd: + case 0xe: /* coproc ops */ + case 0xf: /* SWI */ + break; + + default: + fprintf (stderr, "Bad bit-field extraction\n"); + return (pc); + } + } + + return nextpc; +} + diff --git a/contrib/gdb/gdb/arm-xdep.c b/contrib/gdb/gdb/arm-xdep.c new file mode 100644 index 000000000000..b855ac8d27b5 --- /dev/null +++ b/contrib/gdb/gdb/arm-xdep.c @@ -0,0 +1,276 @@ +/* Acorn Risc Machine host machine support. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "arm-opcode.h" + +#include +#include +#include +#include +#include +#include + +#define N_TXTADDR(hdr) 0x8000 +#define N_DATADDR(hdr) (hdr.a_text + 0x8000) + +#include "gdbcore.h" + +#include /* After a.out.h */ +#include +#include "gdb_stat.h" + +#include + +void +fetch_inferior_registers (regno) + int regno; /* Original value discarded */ +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) + - KERNEL_U_ADDR; + + registers_fetched (); + + for (regno = 0; regno < 16; regno++) + { + regaddr = offset + regno * 4; + *(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + if (regno == PC_REGNUM) + *(int *)&buf[0] = GET_PC_PART(*(int *)&buf[0]); + supply_register (regno, buf); + } + *(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) (offset + PC*4), 0); + supply_register (PS_REGNUM, buf); /* set virtual register ps same as pc */ + + /* read the floating point registers */ + offset = (char *) &u.u_fp_regs - (char *)&u; + *(int *)buf = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0); + supply_register (FPS_REGNUM, buf); + for (regno = 16; regno < 24; regno++) { + regaddr = offset + 4 + 12 * (regno - 16); + for (i = 0; i < 12; i += sizeof(int)) + *(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) (regaddr + i), 0); + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + struct user u; + unsigned long value; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) + - KERNEL_U_ADDR; + + if (regno >= 0) { + if (regno >= 16) return; + regaddr = offset + 4 * regno; + errno = 0; + value = read_register(regno); + if (regno == PC_REGNUM) + value = SET_PC_PART(read_register (PS_REGNUM), value); + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, value); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < 15; regno++) + { + regaddr = offset + regno * 4; + errno = 0; + value = read_register(regno); + if (regno == PC_REGNUM) + value = SET_PC_PART(read_register (PS_REGNUM), value); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, value); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } +} + +/* Work with core dump and executable files, for GDB. + This code would be in corefile.c if it weren't machine-dependent. */ + +/* Structure to describe the chain of shared libraries used + by the execfile. + e.g. prog shares Xt which shares X11 which shares c. */ + +struct shared_library { + struct exec_header header; + char name[SHLIBLEN]; + CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */ + long data_offset; /* offset of data section in file */ + int chan; /* file descriptor for the file */ + struct shared_library *shares; /* library this one shares */ +}; +static struct shared_library *shlib = 0; + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +static CORE_ADDR unshared_text_start; + +/* extended header from exec file (for shared library info) */ + +static struct exec_header exec_header; + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the program with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset, fp_reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + + /* We are depending on exec_file_command having been called + previously to set exec_data_start. Since the executable + and the core file share the same text segment, the address + of the data segment will be the same in both. */ + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; + fp_reg_offset = (char *) &u.u_fp_regs - (char *)&u; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + N_SET_MAGIC (core_aouthdr, 0); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + if (regno < 16) + val = lseek (corechan, reg_offset + 4 * regno, 0); + else if (regno < 24) + val = lseek (corechan, fp_reg_offset + 4 + 12*(regno - 24), 0); + else if (regno == 24) + val = lseek (corechan, fp_reg_offset, 0); + else if (regno == 25) + val = lseek (corechan, reg_offset + 4 * PC, 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + if (regno == PC_REGNUM) + *(int *)buf = GET_PC_PART(*(int *)buf); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename, NULL); + } + + flush_cached_frames (); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/contrib/gdb/gdb/bcache.c b/contrib/gdb/gdb/bcache.c new file mode 100644 index 000000000000..ae73c11ff3cc --- /dev/null +++ b/contrib/gdb/gdb/bcache.c @@ -0,0 +1,189 @@ +/* Implement a cached obstack. + Written by Fred Fish (fnf@cygnus.com) + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bcache.h" +#include "gdb_string.h" /* For memcpy declaration */ + +/* FIXME: Incredibly simplistic hash generator. Probably way too expensive + (consider long strings) and unlikely to have good distribution across hash + values for typical input. */ + +static unsigned int +hash (bytes, count) + void *bytes; + int count; +{ + unsigned int len; + unsigned long hashval; + unsigned int c; + const unsigned char *data = bytes; + + hashval = 0; + len = 0; + while (count-- > 0) + { + c = *data++; + hashval += c + (c << 17); + hashval ^= hashval >> 2; + ++len; + } + hashval += len + (len << 17); + hashval ^= hashval >> 2; + return (hashval % BCACHE_HASHSIZE); +} + +static void * +lookup_cache (bytes, count, hashval, bcachep) + void *bytes; + int count; + int hashval; + struct bcache *bcachep; +{ + void *location = NULL; + struct hashlink **hashtablep; + struct hashlink *linkp; + + hashtablep = bcachep -> indextable[count]; + if (hashtablep != NULL) + { + linkp = hashtablep[hashval]; + while (linkp != NULL) + { + if (memcmp (BCACHE_DATA (linkp), bytes, count) == 0) + { + location = BCACHE_DATA (linkp); + break; + } + linkp = linkp -> next; + } + } + return (location); +} + +void * +bcache (bytes, count, bcachep) + void *bytes; + int count; + struct bcache *bcachep; +{ + int hashval; + void *location; + struct hashlink *newlink; + struct hashlink **linkpp; + struct hashlink ***hashtablepp; + + if (count >= BCACHE_MAXLENGTH) + { + /* Rare enough to just stash unique copies */ + location = (void *) obstack_alloc (&bcachep->cache, count); + bcachep -> cache_bytes += count; + memcpy (location, bytes, count); + bcachep -> bcache_overflows++; + } + else + { + hashval = hash (bytes, count); + location = lookup_cache (bytes, count, hashval, bcachep); + if (location != NULL) + { + bcachep -> cache_savings += count; + bcachep -> cache_hits++; + } + else + { + bcachep -> cache_misses++; + hashtablepp = &bcachep -> indextable[count]; + if (*hashtablepp == NULL) + { + *hashtablepp = (struct hashlink **) + obstack_alloc (&bcachep->cache, BCACHE_HASHSIZE * sizeof (struct hashlink *)); + bcachep -> cache_bytes += BCACHE_HASHSIZE * sizeof (struct hashlink *); + memset (*hashtablepp, 0, BCACHE_HASHSIZE * sizeof (struct hashlink *)); + } + linkpp = &(*hashtablepp)[hashval]; + newlink = (struct hashlink *) + obstack_alloc (&bcachep->cache, BCACHE_DATA_ALIGNMENT + count); + bcachep -> cache_bytes += BCACHE_DATA_ALIGNMENT + count; + memcpy (BCACHE_DATA (newlink), bytes, count); + newlink -> next = *linkpp; + *linkpp = newlink; + location = BCACHE_DATA (newlink); + } + } + return (location); +} + +#if MAINTENANCE_CMDS + +void +print_bcache_statistics (bcachep, id) + struct bcache *bcachep; + char *id; +{ + struct hashlink **hashtablep; + struct hashlink *linkp; + int tidx, tcount, hidx, hcount, lcount, lmax, temp, lmaxt, lmaxh; + + for (lmax = lcount = tcount = hcount = tidx = 0; tidx < BCACHE_MAXLENGTH; tidx++) + { + hashtablep = bcachep -> indextable[tidx]; + if (hashtablep != NULL) + { + tcount++; + for (hidx = 0; hidx < BCACHE_HASHSIZE; hidx++) + { + linkp = hashtablep[hidx]; + if (linkp != NULL) + { + hcount++; + for (temp = 0; linkp != NULL; linkp = linkp -> next) + { + lcount++; + temp++; + } + if (temp > lmax) + { + lmax = temp; + lmaxt = tidx; + lmaxh = hidx; + } + } + } + } + } + printf_filtered (" Cached '%s' statistics:\n", id); + printf_filtered (" Cache hits: %d\n", bcachep -> cache_hits); + printf_filtered (" Cache misses: %d\n", bcachep -> cache_misses); + printf_filtered (" Cache hit ratio: %d%%\n", ((bcachep -> cache_hits) * 100) / (bcachep -> cache_hits + bcachep -> cache_misses)); + printf_filtered (" Space used for caching: %d\n", bcachep -> cache_bytes); + printf_filtered (" Space saved by cache hits: %d\n", bcachep -> cache_savings); + printf_filtered (" Number of bcache overflows: %d\n", bcachep -> bcache_overflows); + printf_filtered (" Number of index buckets used: %d\n", tcount); + printf_filtered (" Number of hash table buckets used: %d\n", hcount); + printf_filtered (" Number of chained items: %d\n", lcount); + printf_filtered (" Average hash table population: %d%%\n", + (hcount * 100) / (tcount * BCACHE_HASHSIZE)); + printf_filtered (" Average chain length %d\n", lcount / hcount); + printf_filtered (" Maximum chain length %d at %d:%d\n", lmax, lmaxt, lmaxh); +} + +#endif /* MAINTENANCE_CMDS */ diff --git a/contrib/gdb/gdb/bcache.h b/contrib/gdb/gdb/bcache.h new file mode 100644 index 000000000000..48b71e28cf0a --- /dev/null +++ b/contrib/gdb/gdb/bcache.h @@ -0,0 +1,72 @@ +/* Include file cached obstack implementation. + Written by Fred Fish (fnf@cygnus.com) + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BCACHE_H +#define BCACHE_H 1 + +#define BCACHE_HASHLENGTH 12 /* Number of bits in hash value */ +#define BCACHE_HASHSIZE (1 << BCACHE_HASHLENGTH) +#define BCACHE_MAXLENGTH 128 + +/* Note that the user data is stored in data[]. Since it can be any type, + it needs to have the same alignment as the most strict alignment of + any type on the host machine. So do it the same way obstack does. */ + +struct hashlink { + struct hashlink *next; + union { + char data[1]; + double dummy; + } d; +}; + +/* BCACHE_DATA is used to get the address of the cached data. */ + +#define BCACHE_DATA(p) ((p)->d.data) + +/* BCACHE_DATA_ALIGNMENT is used to get the offset of the start of + cached data within the hashlink struct. This value, plus the + size of the cached data, is the amount of space to allocate for + a hashlink struct to hold the next pointer and the data. */ + +#define BCACHE_DATA_ALIGNMENT \ + (((char *) &BCACHE_DATA((struct hashlink*) 0) - (char *) 0)) + +struct bcache { + struct obstack cache; + struct hashlink **indextable[BCACHE_MAXLENGTH]; + int cache_hits; + int cache_misses; + int cache_bytes; + int cache_savings; + int bcache_overflows; +}; + +extern void * +bcache PARAMS ((void *bytes, int count, struct bcache *bcachep)); + +#if MAINTENANCE_CMDS + +extern void +print_bcache_statistics PARAMS ((struct bcache *, char *)); + +#endif /* MAINTENANCE_CMDS */ + +#endif /* BCACHE_H */ diff --git a/contrib/gdb/gdb/blockframe.c b/contrib/gdb/gdb/blockframe.c new file mode 100644 index 000000000000..d98f6a46b90d --- /dev/null +++ b/contrib/gdb/gdb/blockframe.c @@ -0,0 +1,854 @@ +/* Get info from stack frames; + convert between frames, blocks, functions and pc values. + Copyright 1986, 1987, 1988, 1989, 1991, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "frame.h" +#include "gdbcore.h" +#include "value.h" /* for read_register */ +#include "target.h" /* for target_has_stack */ +#include "inferior.h" /* for read_pc */ +#include "annotate.h" + +/* Is ADDR inside the startup file? Note that if your machine + has a way to detect the bottom of the stack, there is no need + to call this function from FRAME_CHAIN_VALID; the reason for + doing so is that some machines have no way of detecting bottom + of stack. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_entry_file (addr) + CORE_ADDR addr; +{ + if (addr == 0) + return 1; + if (symfile_objfile == 0) + return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (addr, 0, 0)) + return 0; +#endif + return (addr >= symfile_objfile -> ei.entry_file_lowpc && + addr < symfile_objfile -> ei.entry_file_highpc); +} + +/* Test a specified PC value to see if it is in the range of addresses + that correspond to the main() function. See comments above for why + we might want to do this. + + Typically called from FRAME_CHAIN_VALID. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_main_func (pc) +CORE_ADDR pc; +{ +struct symbol *mainsym; + if (pc == 0) + return 1; + if (symfile_objfile == 0) + return 0; + + /* If the addr range is not set up at symbol reading time, set it up now. + This is for FRAME_CHAIN_VALID_ALTERNATE. I do this for coff, because + it is unable to set it up and symbol reading time. */ + + if (symfile_objfile -> ei.main_func_lowpc == INVALID_ENTRY_LOWPC && + symfile_objfile -> ei.main_func_highpc == INVALID_ENTRY_HIGHPC) + { + mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL); + if (mainsym && SYMBOL_CLASS(mainsym) == LOC_BLOCK) + { + symfile_objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym)); + symfile_objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym)); + } + + } + return (symfile_objfile -> ei.main_func_lowpc <= pc && + symfile_objfile -> ei.main_func_highpc > pc); +} + +/* Test a specified PC value to see if it is in the range of addresses + that correspond to the process entry point function. See comments + in objfiles.h for why we might want to do this. + + Typically called from FRAME_CHAIN_VALID. + + A PC of zero is always considered to be the bottom of the stack. */ + +int +inside_entry_func (pc) +CORE_ADDR pc; +{ + if (pc == 0) + return 1; + if (symfile_objfile == 0) + return 0; +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + /* Do not stop backtracing if the pc is in the call dummy + at the entry point. */ + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + return 0; +#endif + return (symfile_objfile -> ei.entry_func_lowpc <= pc && + symfile_objfile -> ei.entry_func_highpc > pc); +} + +/* Info about the innermost stack frame (contents of FP register) */ + +static struct frame_info *current_frame; + +/* Cache for frame addresses already read by gdb. Valid only while + inferior is stopped. Control variables for the frame cache should + be local to this module. */ + +struct obstack frame_cache_obstack; + +/* Return the innermost (currently executing) stack frame. */ + +struct frame_info * +get_current_frame () +{ + if (current_frame == NULL) + { + if (target_has_stack) + current_frame = create_new_frame (read_fp (), read_pc ()); + else + error ("No stack."); + } + return current_frame; +} + +void +set_current_frame (frame) + struct frame_info *frame; +{ + current_frame = frame; +} + +/* Create an arbitrary (i.e. address specified by user) or innermost frame. + Always returns a non-NULL value. */ + +struct frame_info * +create_new_frame (addr, pc) + CORE_ADDR addr; + CORE_ADDR pc; +{ + struct frame_info *fi; + char *name; + + fi = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); + + /* Arbitrary frame */ + fi->next = NULL; + fi->prev = NULL; + fi->frame = addr; + fi->pc = pc; + find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + fi->signal_handler_caller = IN_SIGTRAMP (fi->pc, name); + +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO (0, fi); +#endif + + return fi; +} + +/* Return the frame that called FI. + If FI is the original frame (it has no caller), return 0. */ + +struct frame_info * +get_prev_frame (frame) + struct frame_info *frame; +{ + return get_prev_frame_info (frame); +} + +/* Return the frame that FRAME calls (NULL if FRAME is the innermost + frame). */ + +struct frame_info * +get_next_frame (frame) + struct frame_info *frame; +{ + return frame->next; +} + +/* Flush the entire frame cache. */ + +void +flush_cached_frames () +{ + /* Since we can't really be sure what the first object allocated was */ + obstack_free (&frame_cache_obstack, 0); + obstack_init (&frame_cache_obstack); + + current_frame = NULL; /* Invalidate cache */ + select_frame (NULL, -1); + annotate_frames_invalid (); +} + +/* Flush the frame cache, and start a new one if necessary. */ + +void +reinit_frame_cache () +{ + flush_cached_frames (); + + /* FIXME: The inferior_pid test is wrong if there is a corefile. */ + if (inferior_pid != 0) + { + select_frame (get_current_frame (), 0); + } +} + +/* If a machine allows frameless functions, it should define a macro + FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h. FI is the struct + frame_info for the frame, and FRAMELESS should be set to nonzero + if it represents a frameless function invocation. */ + +/* Return nonzero if the function for this frame lacks a prologue. Many + machines can define FRAMELESS_FUNCTION_INVOCATION to just call this + function. */ + +int +frameless_look_for_prologue (frame) + struct frame_info *frame; +{ + CORE_ADDR func_start, after_prologue; + func_start = (get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET); + if (func_start) + { + after_prologue = func_start; +#ifdef SKIP_PROLOGUE_FRAMELESS_P + /* This is faster, since only care whether there *is* a prologue, + not how long it is. */ + SKIP_PROLOGUE_FRAMELESS_P (after_prologue); +#else + SKIP_PROLOGUE (after_prologue); +#endif + return after_prologue == func_start; + } + else + /* If we can't find the start of the function, we don't really + know whether the function is frameless, but we should be able + to get a reasonable (i.e. best we can do under the + circumstances) backtrace by saying that it isn't. */ + return 0; +} + +/* Default a few macros that people seldom redefine. */ + +#if !defined (INIT_FRAME_PC) +#define INIT_FRAME_PC(fromleaf, prev) \ + prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \ + prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ()); +#endif + +#ifndef FRAME_CHAIN_COMBINE +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) +#endif + +/* Return a structure containing various interesting information + about the frame that called NEXT_FRAME. Returns NULL + if there is no such frame. */ + +struct frame_info * +get_prev_frame_info (next_frame) + struct frame_info *next_frame; +{ + CORE_ADDR address = 0; + struct frame_info *prev; + int fromleaf = 0; + char *name; + + /* If the requested entry is in the cache, return it. + Otherwise, figure out what the address should be for the entry + we're about to add to the cache. */ + + if (!next_frame) + { +#if 0 + /* This screws value_of_variable, which just wants a nice clean + NULL return from block_innermost_frame if there are no frames. + I don't think I've ever seen this message happen otherwise. + And returning NULL here is a perfectly legitimate thing to do. */ + if (!current_frame) + { + error ("You haven't set up a process's stack to examine."); + } +#endif + + return current_frame; + } + + /* If we have the prev one, return it */ + if (next_frame->prev) + return next_frame->prev; + + /* On some machines it is possible to call a function without + setting up a stack frame for it. On these machines, we + define this macro to take two args; a frameinfo pointer + identifying a frame and a variable to set or clear if it is + or isn't leafless. */ +#ifdef FRAMELESS_FUNCTION_INVOCATION + /* Still don't want to worry about this except on the innermost + frame. This macro will set FROMLEAF if NEXT_FRAME is a + frameless function invocation. */ + if (!(next_frame->next)) + { + FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf); + if (fromleaf) + address = FRAME_FP (next_frame); + } +#endif + + if (!fromleaf) + { + /* Two macros defined in tm.h specify the machine-dependent + actions to be performed here. + First, get the frame's chain-pointer. + If that is zero, the frame is the outermost frame or a leaf + called by the outermost frame. This means that if start + calls main without a frame, we'll return 0 (which is fine + anyway). + + Nope; there's a problem. This also returns when the current + routine is a leaf of main. This is unacceptable. We move + this to after the ffi test; I'd rather have backtraces from + start go curfluy than have an abort called from main not show + main. */ + address = FRAME_CHAIN (next_frame); + if (!FRAME_CHAIN_VALID (address, next_frame)) + return 0; + address = FRAME_CHAIN_COMBINE (address, next_frame); + } + if (address == 0) + return 0; + + prev = (struct frame_info *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_info)); + + if (next_frame) + next_frame->prev = prev; + prev->next = next_frame; + prev->prev = (struct frame_info *) 0; + prev->frame = address; + prev->signal_handler_caller = 0; + +/* This change should not be needed, FIXME! We should + determine whether any targets *need* INIT_FRAME_PC to happen + after INIT_EXTRA_FRAME_INFO and come up with a simple way to + express what goes on here. + + INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame + (where the PC is already set up) and here (where it isn't). + INIT_FRAME_PC is only called from here, always after + INIT_EXTRA_FRAME_INFO. + + The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the PC + value (which hasn't been set yet). Some other machines appear to + require INIT_EXTRA_FRAME_INFO before they can do INIT_FRAME_PC. Phoo. + + We shouldn't need INIT_FRAME_PC_FIRST to add more complication to + an already overcomplicated part of GDB. gnu@cygnus.com, 15Sep92. + + Assuming that some machines need INIT_FRAME_PC after + INIT_EXTRA_FRAME_INFO, one possible scheme: + + SETUP_INNERMOST_FRAME() + Default version is just create_new_frame (read_fp ()), + read_pc ()). Machines with extra frame info would do that (or the + local equivalent) and then set the extra fields. + SETUP_ARBITRARY_FRAME(argc, argv) + Only change here is that create_new_frame would no longer init extra + frame info; SETUP_ARBITRARY_FRAME would have to do that. + INIT_PREV_FRAME(fromleaf, prev) + Replace INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC. This should + also return a flag saying whether to keep the new frame, or + whether to discard it, because on some machines (e.g. mips) it + is really awkward to have FRAME_CHAIN_VALID called *before* + INIT_EXTRA_FRAME_INFO (there is no good way to get information + deduced in FRAME_CHAIN_VALID into the extra fields of the new frame). + std_frame_pc(fromleaf, prev) + This is the default setting for INIT_PREV_FRAME. It just does what + the default INIT_FRAME_PC does. Some machines will call it from + INIT_PREV_FRAME (either at the beginning, the end, or in the middle). + Some machines won't use it. + kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94. */ + +#ifdef INIT_FRAME_PC_FIRST + INIT_FRAME_PC_FIRST (fromleaf, prev); +#endif + +#ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO(fromleaf, prev); +#endif + + /* This entry is in the frame queue now, which is good since + FRAME_SAVED_PC may use that queue to figure out its value + (see tm-sparc.h). We want the pc saved in the inferior frame. */ + INIT_FRAME_PC(fromleaf, prev); + + /* If ->frame and ->pc are unchanged, we are in the process of getting + ourselves into an infinite backtrace. Some architectures check this + in FRAME_CHAIN or thereabouts, but it seems like there is no reason + this can't be an architecture-independent check. */ + if (next_frame != NULL) + { + if (prev->frame == next_frame->frame + && prev->pc == next_frame->pc) + { + next_frame->prev = NULL; + obstack_free (&frame_cache_obstack, prev); + return NULL; + } + } + + find_pc_partial_function (prev->pc, &name, + (CORE_ADDR *)NULL,(CORE_ADDR *)NULL); + if (IN_SIGTRAMP (prev->pc, name)) + prev->signal_handler_caller = 1; + + return prev; +} + +CORE_ADDR +get_frame_pc (frame) + struct frame_info *frame; +{ + return frame->pc; +} + +#if defined (FRAME_FIND_SAVED_REGS) +/* Find the addresses in which registers are saved in FRAME. */ + +void +get_frame_saved_regs (frame, saved_regs_addr) + struct frame_info *frame; + struct frame_saved_regs *saved_regs_addr; +{ + FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr); +} +#endif + +/* Return the innermost lexical block in execution + in a specified stack frame. The frame address is assumed valid. */ + +struct block * +get_frame_block (frame) + struct frame_info *frame; +{ + CORE_ADDR pc; + + pc = frame->pc; + if (frame->next != 0 && frame->next->signal_handler_caller == 0) + /* We are not in the innermost frame and we were not interrupted + by a signal. We need to subtract one to get the correct block, + in case the call instruction was the last instruction of the block. + If there are any machines on which the saved pc does not point to + after the call insn, we probably want to make frame->pc point after + the call insn anyway. */ + --pc; + return block_for_pc (pc); +} + +struct block * +get_current_block () +{ + return block_for_pc (read_pc ()); +} + +CORE_ADDR +get_pc_function_start (pc) + CORE_ADDR pc; +{ + register struct block *bl; + register struct symbol *symbol; + register struct minimal_symbol *msymbol; + CORE_ADDR fstart; + + if ((bl = block_for_pc (pc)) != NULL && + (symbol = block_function (bl)) != NULL) + { + bl = SYMBOL_BLOCK_VALUE (symbol); + fstart = BLOCK_START (bl); + } + else if ((msymbol = lookup_minimal_symbol_by_pc (pc)) != NULL) + { + fstart = SYMBOL_VALUE_ADDRESS (msymbol); + } + else + { + fstart = 0; + } + return (fstart); +} + +/* Return the symbol for the function executing in frame FRAME. */ + +struct symbol * +get_frame_function (frame) + struct frame_info *frame; +{ + register struct block *bl = get_frame_block (frame); + if (bl == 0) + return 0; + return block_function (bl); +} + +/* Return the blockvector immediately containing the innermost lexical block + containing the specified pc value, or 0 if there is none. + PINDEX is a pointer to the index value of the block. If PINDEX + is NULL, we don't pass this information back to the caller. */ + +struct blockvector * +blockvector_for_pc (pc, pindex) + register CORE_ADDR pc; + int *pindex; +{ + register struct block *b; + register int bot, top, half; + register struct symtab *s; + struct blockvector *bl; + + /* First search all symtabs for one whose file contains our pc */ + s = find_pc_symtab (pc); + if (s == 0) + return 0; + + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + + /* Then search that symtab for the smallest block that wins. */ + /* Use binary search to find the last block that starts before PC. */ + + bot = 0; + top = BLOCKVECTOR_NBLOCKS (bl); + + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + b = BLOCKVECTOR_BLOCK (bl, bot + half); + if (BLOCK_START (b) <= pc) + bot += half; + else + top = bot + half; + } + + /* Now search backward for a block that ends after PC. */ + + while (bot >= 0) + { + b = BLOCKVECTOR_BLOCK (bl, bot); + if (BLOCK_END (b) > pc) + { + if (pindex) + *pindex = bot; + return bl; + } + bot--; + } + + return 0; +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +struct block * +block_for_pc (pc) + register CORE_ADDR pc; +{ + register struct blockvector *bl; + int index; + + bl = blockvector_for_pc (pc, &index); + if (bl) + return BLOCKVECTOR_BLOCK (bl, index); + return 0; +} + +/* Return the function containing pc value PC. + Returns 0 if function is not known. */ + +struct symbol * +find_pc_function (pc) + CORE_ADDR pc; +{ + register struct block *b = block_for_pc (pc); + if (b == 0) + return 0; + return block_function (b); +} + +/* These variables are used to cache the most recent result + * of find_pc_partial_function. */ + +static CORE_ADDR cache_pc_function_low = 0; +static CORE_ADDR cache_pc_function_high = 0; +static char *cache_pc_function_name = 0; + +/* Clear cache, e.g. when symbol table is discarded. */ + +void +clear_pc_function_cache() +{ + cache_pc_function_low = 0; + cache_pc_function_high = 0; + cache_pc_function_name = (char *)0; +} + +/* Finds the "function" (text symbol) that is smaller than PC but + greatest of all of the potential text symbols. Sets *NAME and/or + *ADDRESS conditionally if that pointer is non-null. If ENDADDR is + non-null, then set *ENDADDR to be the end of the function + (exclusive), but passing ENDADDR as non-null means that the + function might cause symbols to be read. This function either + succeeds or fails (not halfway succeeds). If it succeeds, it sets + *NAME, *ADDRESS, and *ENDADDR to real information and returns 1. + If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero + and returns 0. */ + +int +find_pc_partial_function (pc, name, address, endaddr) + CORE_ADDR pc; + char **name; + CORE_ADDR *address; + CORE_ADDR *endaddr; +{ + struct partial_symtab *pst; + struct symbol *f; + struct minimal_symbol *msymbol; + struct partial_symbol *psb; + struct obj_section *sec; + + if (pc >= cache_pc_function_low && pc < cache_pc_function_high) + goto return_cached_value; + + /* If sigtramp is in the u area, it counts as a function (especially + important for step_1). */ +#if defined SIGTRAMP_START + if (IN_SIGTRAMP (pc, (char *)NULL)) + { + cache_pc_function_low = SIGTRAMP_START; + cache_pc_function_high = SIGTRAMP_END; + cache_pc_function_name = ""; + + goto return_cached_value; + } +#endif + + msymbol = lookup_minimal_symbol_by_pc (pc); + pst = find_pc_psymtab (pc); + if (pst) + { + /* Need to read the symbols to get a good value for the end address. */ + if (endaddr != NULL && !pst->readin) + { + /* Need to get the terminal in case symbol-reading produces + output. */ + target_terminal_ours_for_output (); + PSYMTAB_TO_SYMTAB (pst); + } + + if (pst->readin) + { + /* Checking whether the msymbol has a larger value is for the + "pathological" case mentioned in print_frame_info. */ + f = find_pc_function (pc); + if (f != NULL + && (msymbol == NULL + || (BLOCK_START (SYMBOL_BLOCK_VALUE (f)) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) + { + cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_name = SYMBOL_NAME (f); + goto return_cached_value; + } + } + else + { + /* Now that static symbols go in the minimal symbol table, perhaps + we could just ignore the partial symbols. But at least for now + we use the partial or minimal symbol, whichever is larger. */ + psb = find_pc_psymbol (pst, pc); + + if (psb + && (msymbol == NULL || + (SYMBOL_VALUE_ADDRESS (psb) + >= SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* This case isn't being cached currently. */ + if (address) + *address = SYMBOL_VALUE_ADDRESS (psb); + if (name) + *name = SYMBOL_NAME (psb); + /* endaddr non-NULL can't happen here. */ + return 1; + } + } + } + + /* Not in the normal symbol tables, see if the pc is in a known section. + If it's not, then give up. This ensures that anything beyond the end + of the text seg doesn't appear to be part of the last function in the + text segment. */ + + sec = find_pc_section (pc); + + if (!sec) + msymbol = NULL; + + /* Must be in the minimal symbol table. */ + if (msymbol == NULL) + { + /* No available symbol. */ + if (name != NULL) + *name = 0; + if (address != NULL) + *address = 0; + if (endaddr != NULL) + *endaddr = 0; + return 0; + } + + cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); + cache_pc_function_name = SYMBOL_NAME (msymbol); + + /* Use the lesser of the next minimal symbol, or the end of the section, as + the end of the function. */ + + if (SYMBOL_NAME (msymbol + 1) != NULL + && SYMBOL_VALUE_ADDRESS (msymbol + 1) < sec->endaddr) + cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + 1); + else + /* We got the start address from the last msymbol in the objfile. + So the end address is the end of the section. */ + cache_pc_function_high = sec->endaddr; + + return_cached_value: + if (address) + *address = cache_pc_function_low; + if (name) + *name = cache_pc_function_name; + if (endaddr) + *endaddr = cache_pc_function_high; + return 1; +} + +/* Return the innermost stack frame executing inside of BLOCK, + or NULL if there is no such frame. If BLOCK is NULL, just return NULL. */ + +struct frame_info * +block_innermost_frame (block) + struct block *block; +{ + struct frame_info *frame; + register CORE_ADDR start; + register CORE_ADDR end; + + if (block == NULL) + return NULL; + + start = BLOCK_START (block); + end = BLOCK_END (block); + + frame = NULL; + while (1) + { + frame = get_prev_frame (frame); + if (frame == NULL) + return NULL; + if (frame->pc >= start && frame->pc < end) + return frame; + } +} + +/* Return the full FRAME which corresponds to the given CORE_ADDR + or NULL if no FRAME on the chain corresponds to CORE_ADDR. */ + +struct frame_info * +find_frame_addr_in_frame_chain (frame_addr) + CORE_ADDR frame_addr; +{ + struct frame_info *frame = NULL; + + if (frame_addr == (CORE_ADDR)0) + return NULL; + + while (1) + { + frame = get_prev_frame (frame); + if (frame == NULL) + return NULL; + if (FRAME_FP (frame) == frame_addr) + return frame; + } +} + +#ifdef SIGCONTEXT_PC_OFFSET +/* Get saved user PC for sigtramp from sigcontext for BSD style sigtramp. */ + +CORE_ADDR +sigtramp_saved_pc (frame) + struct frame_info *frame; +{ + CORE_ADDR sigcontext_addr; + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT; + int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT; + + /* Get sigcontext address, it is the third parameter on the stack. */ + if (frame->next) + sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next) + + FRAME_ARGS_SKIP + + sigcontext_offs, + ptrbytes); + else + sigcontext_addr = read_memory_integer (read_register (SP_REGNUM) + + sigcontext_offs, + ptrbytes); + + /* Don't cause a memory_error when accessing sigcontext in case the stack + layout has changed or the stack is corrupt. */ + target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes); + return extract_unsigned_integer (buf, ptrbytes); +} +#endif /* SIGCONTEXT_PC_OFFSET */ + +void +_initialize_blockframe () +{ + obstack_init (&frame_cache_obstack); +} diff --git a/contrib/gdb/gdb/breakpoint.c b/contrib/gdb/gdb/breakpoint.c new file mode 100644 index 000000000000..3930e7a63466 --- /dev/null +++ b/contrib/gdb/gdb/breakpoint.c @@ -0,0 +1,4117 @@ +/* Everything about breakpoints, for GDB. + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "symtab.h" +#include "frame.h" +#include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "value.h" +#include "command.h" +#include "inferior.h" +#include "thread.h" +#include "target.h" +#include "language.h" +#include "gdb_string.h" +#include "demangle.h" +#include "annotate.h" + +/* local function prototypes */ + +static void +catch_command_1 PARAMS ((char *, int, int)); + +static void +enable_delete_command PARAMS ((char *, int)); + +static void +enable_delete_breakpoint PARAMS ((struct breakpoint *)); + +static void +enable_once_command PARAMS ((char *, int)); + +static void +enable_once_breakpoint PARAMS ((struct breakpoint *)); + +static void +disable_command PARAMS ((char *, int)); + +static void +enable_command PARAMS ((char *, int)); + +static void +map_breakpoint_numbers PARAMS ((char *, void (*)(struct breakpoint *))); + +static void +ignore_command PARAMS ((char *, int)); + +static int +breakpoint_re_set_one PARAMS ((char *)); + +static void +delete_command PARAMS ((char *, int)); + +static void +clear_command PARAMS ((char *, int)); + +static void +catch_command PARAMS ((char *, int)); + +static struct symtabs_and_lines +get_catch_sals PARAMS ((int)); + +static void +watch_command PARAMS ((char *, int)); + +static int +can_use_hardware_watchpoint PARAMS ((struct value *)); + +static void +tbreak_command PARAMS ((char *, int)); + +static void +break_command_1 PARAMS ((char *, int, int)); + +static void +mention PARAMS ((struct breakpoint *)); + +static struct breakpoint * +set_raw_breakpoint PARAMS ((struct symtab_and_line)); + +static void +check_duplicates PARAMS ((CORE_ADDR)); + +static void +describe_other_breakpoints PARAMS ((CORE_ADDR)); + +static void +breakpoints_info PARAMS ((char *, int)); + +static void +breakpoint_1 PARAMS ((int, int)); + +static bpstat +bpstat_alloc PARAMS ((struct breakpoint *, bpstat)); + +static int +breakpoint_cond_eval PARAMS ((char *)); + +static void +cleanup_executing_breakpoints PARAMS ((int)); + +static void +commands_command PARAMS ((char *, int)); + +static void +condition_command PARAMS ((char *, int)); + +static int +get_number PARAMS ((char **)); + +static void +set_breakpoint_count PARAMS ((int)); + +static int +remove_breakpoint PARAMS ((struct breakpoint *)); + +extern int addressprint; /* Print machine addresses? */ + +/* Are we executing breakpoint commands? */ +static int executing_breakpoint_commands; + +/* Walk the following statement or block through all breakpoints. + ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current + breakpoint. */ + +#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next) + +#define ALL_BREAKPOINTS_SAFE(b,tmp) \ + for (b = breakpoint_chain; \ + b? (tmp=b->next, 1): 0; \ + b = tmp) + +/* True if breakpoint hit counts should be displayed in breakpoint info. */ + +int show_breakpoint_hit_counts = 1; + +/* Chain of all breakpoints defined. */ + +struct breakpoint *breakpoint_chain; + +/* Number of last breakpoint made. */ + +static int breakpoint_count; + +/* Set breakpoint count to NUM. */ + +static void +set_breakpoint_count (num) + int num; +{ + breakpoint_count = num; + set_internalvar (lookup_internalvar ("bpnum"), + value_from_longest (builtin_type_int, (LONGEST) num)); +} + +/* Used in run_command to zero the hit count when a new run starts. */ + +void +clear_breakpoint_hit_counts () +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->hit_count = 0; +} + +/* Default address, symtab and line to put a breakpoint at + for "break" command with no arg. + if default_breakpoint_valid is zero, the other three are + not valid, and "break" with no arg is an error. + + This set by print_stack_frame, which calls set_default_breakpoint. */ + +int default_breakpoint_valid; +CORE_ADDR default_breakpoint_address; +struct symtab *default_breakpoint_symtab; +int default_breakpoint_line; + +/* *PP is a string denoting a breakpoint. Get the number of the breakpoint. + Advance *PP after the string and any trailing whitespace. + + Currently the string can either be a number or "$" followed by the name + of a convenience variable. Making it an expression wouldn't work well + for map_breakpoint_numbers (e.g. "4 + 5 + 6"). */ +static int +get_number (pp) + char **pp; +{ + int retval; + char *p = *pp; + + if (p == NULL) + /* Empty line means refer to the last breakpoint. */ + return breakpoint_count; + else if (*p == '$') + { + /* Make a copy of the name, so we can null-terminate it + to pass to lookup_internalvar(). */ + char *varname; + char *start = ++p; + value_ptr val; + + while (isalnum (*p) || *p == '_') + p++; + varname = (char *) alloca (p - start + 1); + strncpy (varname, start, p - start); + varname[p - start] = '\0'; + val = value_of_internalvar (lookup_internalvar (varname)); + if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_INT) + error ( +"Convenience variables used to specify breakpoints must have integer values." + ); + retval = (int) value_as_long (val); + } + else + { + if (*p == '-') + ++p; + while (*p >= '0' && *p <= '9') + ++p; + if (p == *pp) + /* There is no number here. (e.g. "cond a == b"). */ + error_no_arg ("breakpoint number"); + retval = atoi (*pp); + } + if (!(isspace (*p) || *p == '\0')) + error ("breakpoint number expected"); + while (isspace (*p)) + p++; + *pp = p; + return retval; +} + +/* condition N EXP -- set break condition of breakpoint N to EXP. */ + +static void +condition_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b; + char *p; + register int bnum; + + if (arg == 0) + error_no_arg ("breakpoint number"); + + p = arg; + bnum = get_number (&p); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->cond) + { + free ((PTR)b->cond); + b->cond = 0; + } + if (b->cond_string != NULL) + free ((PTR)b->cond_string); + + if (*p == 0) + { + b->cond = 0; + b->cond_string = NULL; + if (from_tty) + printf_filtered ("Breakpoint %d now unconditional.\n", bnum); + } + else + { + arg = p; + /* I don't know if it matters whether this is the string the user + typed in or the decompiled expression. */ + b->cond_string = savestring (arg, strlen (arg)); + b->cond = parse_exp_1 (&arg, block_for_pc (b->address), 0); + if (*arg) + error ("Junk at end of expression"); + } + breakpoints_changed (); + return; + } + + error ("No breakpoint number %d.", bnum); +} + +/* ARGSUSED */ +static void +commands_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b; + char *p; + register int bnum; + struct command_line *l; + + /* If we allowed this, we would have problems with when to + free the storage, if we change the commands currently + being read from. */ + + if (executing_breakpoint_commands) + error ("Can't use the \"commands\" command among a breakpoint's commands."); + + p = arg; + bnum = get_number (&p); + if (p && *p) + error ("Unexpected extra arguments following breakpoint number."); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (from_tty && input_from_terminal_p ()) + printf_filtered ("Type commands for when breakpoint %d is hit, one per line.\n\ +End with a line saying just \"end\".\n", bnum); + l = read_command_lines (); + free_command_lines (&b->commands); + b->commands = l; + breakpoints_changed (); + return; + } + error ("No breakpoint number %d.", bnum); +} + +extern int memory_breakpoint_size; /* from mem-break.c */ + +/* Like target_read_memory() but if breakpoints are inserted, return + the shadow contents instead of the breakpoints themselves. + + Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used + for address out of bounds. If breakpoints are inserted, returns + shadow contents, not the breakpoints themselves. From breakpoint.c. */ + +int +read_memory_nobpt (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + unsigned len; +{ + int status; + struct breakpoint *b; + + if (memory_breakpoint_size < 0) + /* No breakpoints on this machine. FIXME: This should be + dependent on the debugging target. Probably want + target_insert_breakpoint to return a size, saying how many + bytes of the shadow contents are used, or perhaps have + something like target_xfer_shadow. */ + return target_read_memory (memaddr, myaddr, len); + + ALL_BREAKPOINTS (b) + { + if (b->type == bp_watchpoint + || b->type == bp_hardware_watchpoint + || b->type == bp_read_watchpoint + || b->type == bp_access_watchpoint + || !b->inserted) + continue; + else if (b->address + memory_breakpoint_size <= memaddr) + /* The breakpoint is entirely before the chunk of memory + we are reading. */ + continue; + else if (b->address >= memaddr + len) + /* The breakpoint is entirely after the chunk of memory we + are reading. */ + continue; + else + { + /* Copy the breakpoint from the shadow contents, and recurse + for the things before and after. */ + + /* Addresses and length of the part of the breakpoint that + we need to copy. */ + CORE_ADDR membpt = b->address; + unsigned int bptlen = memory_breakpoint_size; + /* Offset within shadow_contents. */ + int bptoffset = 0; + + if (membpt < memaddr) + { + /* Only copy the second part of the breakpoint. */ + bptlen -= memaddr - membpt; + bptoffset = memaddr - membpt; + membpt = memaddr; + } + + if (membpt + bptlen > memaddr + len) + { + /* Only copy the first part of the breakpoint. */ + bptlen -= (membpt + bptlen) - (memaddr + len); + } + + memcpy (myaddr + membpt - memaddr, + b->shadow_contents + bptoffset, bptlen); + + if (membpt > memaddr) + { + /* Copy the section of memory before the breakpoint. */ + status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr); + if (status != 0) + return status; + } + + if (membpt + bptlen < memaddr + len) + { + /* Copy the section of memory after the breakpoint. */ + status = read_memory_nobpt + (membpt + bptlen, + myaddr + membpt + bptlen - memaddr, + memaddr + len - (membpt + bptlen)); + if (status != 0) + return status; + } + return 0; + } + } + /* Nothing overlaps. Just call read_memory_noerr. */ + return target_read_memory (memaddr, myaddr, len); +} + +/* insert_breakpoints is used when starting or continuing the program. + remove_breakpoints is used when the program stops. + Both return zero if successful, + or an `errno' value if could not write the inferior. */ + +int +insert_breakpoints () +{ + register struct breakpoint *b, *temp; + int val = 0; + int disabled_breaks = 0; + + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->type != bp_watchpoint + && b->type != bp_hardware_watchpoint + && b->type != bp_read_watchpoint + && b->type != bp_access_watchpoint + && b->enable != disabled + && b->enable != shlib_disabled + && ! b->inserted + && ! b->duplicate) + { + if (b->type == bp_hardware_breakpoint) + val = target_insert_hw_breakpoint(b->address, b->shadow_contents); + else + val = target_insert_breakpoint(b->address, b->shadow_contents); + if (val) + { + /* Can't set the breakpoint. */ +#if defined (DISABLE_UNSETTABLE_BREAK) + if (DISABLE_UNSETTABLE_BREAK (b->address)) + { + val = 0; + b->enable = shlib_disabled; + if (!disabled_breaks) + { + target_terminal_ours_for_output (); + fprintf_unfiltered (gdb_stderr, + "Cannot insert breakpoint %d:\n", b->number); + printf_filtered ("Temporarily disabling shared library breakpoints:\n"); + } + disabled_breaks = 1; + printf_filtered ("%d ", b->number); + } + else +#endif + { + target_terminal_ours_for_output (); + fprintf_unfiltered (gdb_stderr, "Cannot insert breakpoint %d:\n", b->number); +#ifdef ONE_PROCESS_WRITETEXT + fprintf_unfiltered (gdb_stderr, + "The same program may be running in another process.\n"); +#endif + memory_error (val, b->address); /* which bombs us out */ + } + } + else + b->inserted = 1; + } + else if ((b->type == bp_hardware_watchpoint || + b->type == bp_read_watchpoint || + b->type == bp_access_watchpoint) + && b->enable == enabled + && ! b->inserted + && ! b->duplicate) + { + struct frame_info *saved_frame; + int saved_level, within_current_scope; + value_ptr mark = value_mark (); + value_ptr v; + + /* Save the current frame and level so we can restore it after + evaluating the watchpoint expression on its own frame. */ + saved_frame = selected_frame; + saved_level = selected_frame_level; + + /* Determine if the watchpoint is within scope. */ + if (b->exp_valid_block == NULL) + within_current_scope = 1; + else + { + struct frame_info *fi = + find_frame_addr_in_frame_chain (b->watchpoint_frame); + within_current_scope = (fi != NULL); + if (within_current_scope) + select_frame (fi, -1); + } + + if (within_current_scope) + { + /* Evaluate the expression and cut the chain of values + produced off from the value chain. */ + v = evaluate_expression (b->exp); + value_release_to_mark (mark); + + b->val_chain = v; + b->inserted = 1; + + /* Look at each value on the value chain. */ + for ( ; v; v=v->next) + { + /* If it's a memory location, then we must watch it. */ + if (v->lval == lval_memory) + { + int addr, len, type; + + addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v); + len = TYPE_LENGTH (VALUE_TYPE (v)); + type = 0; + if (b->type == bp_read_watchpoint) + type = 1; + else if (b->type == bp_access_watchpoint) + type = 2; + + val = target_insert_watchpoint (addr, len, type); + if (val == -1) + { + b->inserted = 0; + break; + } + val = 0; + } + } + /* Failure to insert a watchpoint on any memory value in the + value chain brings us here. */ + if (!b->inserted) + warning ("Hardware watchpoint %d: Could not insert watchpoint\n", + b->number); + } + else + { + printf_filtered ("\ +Hardware watchpoint %d deleted because the program has left the block in\n\ +which its expression is valid.\n", b->number); + if (b->related_breakpoint) + delete_breakpoint (b->related_breakpoint); + delete_breakpoint (b); + } + + /* Restore the frame and level. */ + select_frame (saved_frame, saved_level); + } + if (disabled_breaks) + printf_filtered ("\n"); + return val; +} + + +int +remove_breakpoints () +{ + register struct breakpoint *b; + int val; + + ALL_BREAKPOINTS (b) + { + if (b->inserted) + { + val = remove_breakpoint (b); + if (val != 0) + return val; + } + } + return 0; +} + + +static int +remove_breakpoint (b) + struct breakpoint *b; +{ + int val; + + if (b->type != bp_watchpoint + && b->type != bp_hardware_watchpoint + && b->type != bp_read_watchpoint + && b->type != bp_access_watchpoint) + { + if (b->type == bp_hardware_breakpoint) + val = target_remove_hw_breakpoint(b->address, b->shadow_contents); + else + val = target_remove_breakpoint(b->address, b->shadow_contents); + if (val) + return val; + b->inserted = 0; + } + else if ((b->type == bp_hardware_watchpoint || + b->type == bp_read_watchpoint || + b->type == bp_access_watchpoint) + && b->enable == enabled + && ! b->duplicate) + { + value_ptr v, n; + + b->inserted = 0; + /* Walk down the saved value chain. */ + for (v = b->val_chain; v; v = v->next) + { + /* For each memory reference remove the watchpoint + at that address. */ + if (v->lval == lval_memory) + { + int addr, len; + + addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v); + len = TYPE_LENGTH (VALUE_TYPE (v)); + val = target_remove_watchpoint (addr, len, b->type); + if (val == -1) + b->inserted = 1; + val = 0; + } + } + /* Failure to remove any of the hardware watchpoints comes here. */ + if (b->inserted) + warning ("Hardware watchpoint %d: Could not remove watchpoint\n", + b->number); + + /* Free the saved value chain. We will construct a new one + the next time the watchpoint is inserted. */ + for (v = b->val_chain; v; v = n) + { + n = v->next; + value_free (v); + } + b->val_chain = NULL; + } + return 0; +} + +/* Clear the "inserted" flag in all breakpoints. */ + +void +mark_breakpoints_out () +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->inserted = 0; +} + +/* Clear the "inserted" flag in all breakpoints and delete any breakpoints + which should go away between runs of the program. */ + +void +breakpoint_init_inferior () +{ + register struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + { + b->inserted = 0; + + /* If the call dummy breakpoint is at the entry point it will + cause problems when the inferior is rerun, so we better + get rid of it. */ + if (b->type == bp_call_dummy) + delete_breakpoint (b); + + /* Likewise for scope breakpoints. */ + if (b->type == bp_watchpoint_scope) + delete_breakpoint (b); + + /* Likewise for watchpoints on local expressions. */ + if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint || + b->type == bp_read_watchpoint || b->type == bp_access_watchpoint) + && b->exp_valid_block != NULL) + delete_breakpoint (b); + } +} + +/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC. + When continuing from a location with a breakpoint, + we actually single step once before calling insert_breakpoints. */ + +int +breakpoint_here_p (pc) + CORE_ADDR pc; +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled + && b->enable != shlib_disabled + && b->address == pc) + return 1; + + return 0; +} + +/* Return nonzero if FRAME is a dummy frame. We can't use PC_IN_CALL_DUMMY + because figuring out the saved SP would take too much time, at least using + get_saved_register on the 68k. This means that for this function to + work right a port must use the bp_call_dummy breakpoint. */ + +int +frame_in_dummy (frame) + struct frame_info *frame; +{ + struct breakpoint *b; + +#ifdef CALL_DUMMY + ALL_BREAKPOINTS (b) + { + static unsigned LONGEST dummy[] = CALL_DUMMY; + + if (b->type == bp_call_dummy + && b->frame == frame->frame + + /* We need to check the PC as well as the frame on the sparc, + for signals.exp in the testsuite. */ + && (frame->pc + >= (b->address + - sizeof (dummy) / sizeof (LONGEST) * REGISTER_SIZE)) + && frame->pc <= b->address) + return 1; + } +#endif /* CALL_DUMMY */ + return 0; +} + +/* breakpoint_match_thread (PC, PID) returns true if the breakpoint at PC + is valid for process/thread PID. */ + +int +breakpoint_thread_match (pc, pid) + CORE_ADDR pc; + int pid; +{ + struct breakpoint *b; + int thread; + + thread = pid_to_thread_id (pid); + + ALL_BREAKPOINTS (b) + if (b->enable != disabled + && b->enable != shlib_disabled + && b->address == pc + && (b->thread == -1 || b->thread == thread)) + return 1; + + return 0; +} + + +/* bpstat stuff. External routines' interfaces are documented + in breakpoint.h. */ + +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ + +void +bpstat_clear (bsp) + bpstat *bsp; +{ + bpstat p; + bpstat q; + + if (bsp == 0) + return; + p = *bsp; + while (p != NULL) + { + q = p->next; + if (p->old_val != NULL) + value_free (p->old_val); + free ((PTR)p); + p = q; + } + *bsp = NULL; +} + +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ + +bpstat +bpstat_copy (bs) + bpstat bs; +{ + bpstat p = NULL; + bpstat tmp; + bpstat retval = NULL; + + if (bs == NULL) + return bs; + + for (; bs != NULL; bs = bs->next) + { + tmp = (bpstat) xmalloc (sizeof (*tmp)); + memcpy (tmp, bs, sizeof (*tmp)); + if (p == NULL) + /* This is the first thing in the chain. */ + retval = tmp; + else + p->next = tmp; + p = tmp; + } + p->next = NULL; + return retval; +} + +/* Find the bpstat associated with this breakpoint */ + +bpstat +bpstat_find_breakpoint(bsp, breakpoint) + bpstat bsp; + struct breakpoint *breakpoint; +{ + if (bsp == NULL) return NULL; + + for (;bsp != NULL; bsp = bsp->next) { + if (bsp->breakpoint_at == breakpoint) return bsp; + } + return NULL; +} + +/* Return 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 good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ + +int +bpstat_num (bsp) + bpstat *bsp; +{ + struct breakpoint *b; + + if ((*bsp) == NULL) + return 0; /* No more breakpoint values */ + else + { + b = (*bsp)->breakpoint_at; + *bsp = (*bsp)->next; + if (b == NULL) + return -1; /* breakpoint that's been deleted since */ + else + return b->number; /* We have its number */ + } +} + +/* Modify BS so that the actions will not be performed. */ + +void +bpstat_clear_actions (bs) + bpstat bs; +{ + for (; bs != NULL; bs = bs->next) + { + bs->commands = NULL; + if (bs->old_val != NULL) + { + value_free (bs->old_val); + bs->old_val = NULL; + } + } +} + +/* Stub for cleaning up our state if we error-out of a breakpoint command */ +/* ARGSUSED */ +static void +cleanup_executing_breakpoints (ignore) + int ignore; +{ + executing_breakpoint_commands = 0; +} + +/* Execute all the commands associated with all the breakpoints at this + location. Any of these commands could cause the process to proceed + beyond this point, etc. We look out for such changes by checking + the global "breakpoint_proceeded" after each command. */ + +void +bpstat_do_actions (bsp) + bpstat *bsp; +{ + bpstat bs; + struct cleanup *old_chain; + struct command_line *cmd; + + executing_breakpoint_commands = 1; + old_chain = make_cleanup (cleanup_executing_breakpoints, 0); + +top: + bs = *bsp; + + breakpoint_proceeded = 0; + for (; bs != NULL; bs = bs->next) + { + cmd = bs->commands; + while (cmd != NULL) + { + execute_control_command (cmd); + cmd = cmd->next; + } + if (breakpoint_proceeded) + /* The inferior is proceeded by the command; bomb out now. + The bpstat chain has been blown away by wait_for_inferior. + But since execution has stopped again, there is a new bpstat + to look at, so start over. */ + goto top; + else + bs->commands = NULL; + } + + executing_breakpoint_commands = 0; + discard_cleanups (old_chain); +} + +/* This is the normal print_it function for a bpstat. In the future, + much of this logic could (should?) be moved to bpstat_stop_status, + by having it set different print_it functions. */ + +static int +print_it_normal (bs) + bpstat bs; +{ + /* bs->breakpoint_at can be NULL if it was a momentary breakpoint + which has since been deleted. */ + if (bs->breakpoint_at == NULL + || (bs->breakpoint_at->type != bp_breakpoint + && bs->breakpoint_at->type != bp_hardware_breakpoint + && bs->breakpoint_at->type != bp_watchpoint + && bs->breakpoint_at->type != bp_read_watchpoint + && bs->breakpoint_at->type != bp_access_watchpoint + && bs->breakpoint_at->type != bp_hardware_watchpoint)) + return 0; + + if (bs->breakpoint_at->type == bp_breakpoint || + bs->breakpoint_at->type == bp_hardware_breakpoint) + { + /* I think the user probably only wants to see one breakpoint + number, not all of them. */ + annotate_breakpoint (bs->breakpoint_at->number); + printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number); + return 0; + } + else if ((bs->old_val != NULL) && + (bs->breakpoint_at->type == bp_watchpoint || + bs->breakpoint_at->type == bp_access_watchpoint || + bs->breakpoint_at->type == bp_hardware_watchpoint)) + { + annotate_watchpoint (bs->breakpoint_at->number); + mention (bs->breakpoint_at); + printf_filtered ("\nOld value = "); + value_print (bs->old_val, gdb_stdout, 0, Val_pretty_default); + printf_filtered ("\nNew value = "); + value_print (bs->breakpoint_at->val, gdb_stdout, 0, + Val_pretty_default); + printf_filtered ("\n"); + value_free (bs->old_val); + bs->old_val = NULL; + /* More than one watchpoint may have been triggered. */ + return -1; + } + else if (bs->breakpoint_at->type == bp_access_watchpoint || + bs->breakpoint_at->type == bp_read_watchpoint) + { + mention (bs->breakpoint_at); + printf_filtered ("\nValue = "); + value_print (bs->breakpoint_at->val, gdb_stdout, 0, + Val_pretty_default); + printf_filtered ("\n"); + return -1; + } + /* We can't deal with it. Maybe another member of the bpstat chain can. */ + return -1; +} + +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ +/* Currently we always return zero. */ +int +bpstat_print (bs) + bpstat bs; +{ + int val; + + if (bs == NULL) + return 0; + + val = (*bs->print_it) (bs); + if (val >= 0) + return val; + + /* Maybe another breakpoint in the chain caused us to stop. + (Currently all watchpoints go on the bpstat whether hit or + not. That probably could (should) be changed, provided care is taken + with respect to bpstat_explains_signal). */ + if (bs->next) + return bpstat_print (bs->next); + + /* We reached the end of the chain without printing anything. */ + return 0; +} + +/* Evaluate the expression EXP and return 1 if value is zero. + This is used inside a catch_errors to evaluate the breakpoint condition. + The argument is a "struct expression *" that has been cast to char * to + make it pass through catch_errors. */ + +static int +breakpoint_cond_eval (exp) + char *exp; +{ + value_ptr mark = value_mark (); + int i = !value_true (evaluate_expression ((struct expression *)exp)); + value_free_to_mark (mark); + return i; +} + +/* Allocate a new bpstat and chain it to the current one. */ + +static bpstat +bpstat_alloc (b, cbs) + register struct breakpoint *b; + bpstat cbs; /* Current "bs" value */ +{ + bpstat bs; + + bs = (bpstat) xmalloc (sizeof (*bs)); + cbs->next = bs; + bs->breakpoint_at = b; + /* If the condition is false, etc., don't do the commands. */ + bs->commands = NULL; + bs->old_val = NULL; + bs->print_it = print_it_normal; + return bs; +} + +/* Possible return values for watchpoint_check (this can't be an enum + because of check_errors). */ +/* The watchpoint has been deleted. */ +#define WP_DELETED 1 +/* The value has changed. */ +#define WP_VALUE_CHANGED 2 +/* The value has not changed. */ +#define WP_VALUE_NOT_CHANGED 3 + +#define BP_TEMPFLAG 1 +#define BP_HARDWAREFLAG 2 + +/* Check watchpoint condition. */ + +static int +watchpoint_check (p) + char *p; +{ + bpstat bs = (bpstat) p; + struct breakpoint *b; + struct frame_info *fr; + int within_current_scope; + + b = bs->breakpoint_at; + + if (b->exp_valid_block == NULL) + within_current_scope = 1; + else + { + /* There is no current frame at this moment. If we're going to have + any chance of handling watchpoints on local variables, we'll need + the frame chain (so we can determine if we're in scope). */ + reinit_frame_cache(); + fr = find_frame_addr_in_frame_chain (b->watchpoint_frame); + within_current_scope = (fr != NULL); + if (within_current_scope) + /* If we end up stopping, the current frame will get selected + in normal_stop. So this call to select_frame won't affect + the user. */ + select_frame (fr, -1); + } + + if (within_current_scope) + { + /* We use value_{,free_to_}mark because it could be a + *long* time before we return to the command level and + call free_all_values. We can't call free_all_values because + we might be in the middle of evaluating a function call. */ + + value_ptr mark = value_mark (); + value_ptr new_val = evaluate_expression (bs->breakpoint_at->exp); + if (!value_equal (b->val, new_val)) + { + release_value (new_val); + value_free_to_mark (mark); + bs->old_val = b->val; + b->val = new_val; + /* We will stop here */ + return WP_VALUE_CHANGED; + } + else + { + /* Nothing changed, don't do anything. */ + value_free_to_mark (mark); + /* We won't stop here */ + return WP_VALUE_NOT_CHANGED; + } + } + else + { + /* This seems like the only logical thing to do because + if we temporarily ignored the watchpoint, then when + we reenter the block in which it is valid it contains + garbage (in the case of a function, it may have two + garbage values, one before and one after the prologue). + So we can't even detect the first assignment to it and + watch after that (since the garbage may or may not equal + the first value assigned). */ + printf_filtered ("\ +Watchpoint %d deleted because the program has left the block in\n\ +which its expression is valid.\n", bs->breakpoint_at->number); + if (b->related_breakpoint) + delete_breakpoint (b->related_breakpoint); + delete_breakpoint (b); + + return WP_DELETED; + } +} + +/* This is used when everything which needs to be printed has + already been printed. But we still want to print the frame. */ +static int +print_it_done (bs) + bpstat bs; +{ + return 0; +} + +/* This is used when nothing should be printed for this bpstat entry. */ + +static int +print_it_noop (bs) + bpstat bs; +{ + return -1; +} + +/* Get a bpstat associated with having just stopped at address *PC + and frame address CORE_ADDRESS. Update *PC to point at the + breakpoint (if we hit a breakpoint). NOT_A_BREAKPOINT is nonzero + if this is known to not be a real breakpoint (it could still be a + watchpoint, though). */ + +/* Determine whether we stopped at a breakpoint, etc, or whether we + don't understand this stop. Result is a chain of bpstat's such that: + + if we don't understand the stop, the result is a null pointer. + + if we understand why we stopped, the result is not null. + + Each element of the chain refers to a particular breakpoint or + watchpoint at which we have stopped. (We may have stopped for + several reasons concurrently.) + + Each element of the chain has valid next, breakpoint_at, + commands, FIXME??? fields. + + */ + +bpstat +bpstat_stop_status (pc, not_a_breakpoint) + CORE_ADDR *pc; + int not_a_breakpoint; +{ + register struct breakpoint *b, *temp; + CORE_ADDR bp_addr; +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + /* True if we've hit a breakpoint (as opposed to a watchpoint). */ + int real_breakpoint = 0; +#endif + /* Root of the chain of bpstat's */ + struct bpstats root_bs[1]; + /* Pointer to the last thing in the chain currently. */ + bpstat bs = root_bs; + static char message1[] = + "Error evaluating expression for watchpoint %d\n"; + char message[sizeof (message1) + 30 /* slop */]; + + /* Get the address where the breakpoint would have been. */ + bp_addr = *pc - DECR_PC_AFTER_BREAK; + + ALL_BREAKPOINTS_SAFE (b, temp) + { + if (b->enable == disabled + || b->enable == shlib_disabled) + continue; + + if (b->type != bp_watchpoint + && b->type != bp_hardware_watchpoint + && b->type != bp_read_watchpoint + && b->type != bp_access_watchpoint + && b->type != bp_hardware_breakpoint + && b->address != bp_addr) + continue; + + if (b->type == bp_hardware_breakpoint + && b->address != (bp_addr - DECR_PC_AFTER_HW_BREAK)) + continue; + + if (b->type != bp_watchpoint + && b->type != bp_hardware_watchpoint + && b->type != bp_read_watchpoint + && b->type != bp_access_watchpoint + && not_a_breakpoint) + continue; + + /* Come here if it's a watchpoint, or if the break address matches */ + + ++(b->hit_count); + + bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */ + + bs->stop = 1; + bs->print = 1; + + sprintf (message, message1, b->number); + if (b->type == bp_watchpoint || b->type == bp_hardware_watchpoint) + { + switch (catch_errors (watchpoint_check, (char *) bs, message, + RETURN_MASK_ALL)) + { + case WP_DELETED: + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + /* Stop. */ + break; + case WP_VALUE_CHANGED: + /* Stop. */ + break; + case WP_VALUE_NOT_CHANGED: + /* Don't stop. */ + bs->print_it = print_it_noop; + bs->stop = 0; + continue; + default: + /* Can't happen. */ + /* FALLTHROUGH */ + case 0: + /* Error from catch_errors. */ + printf_filtered ("Watchpoint %d deleted.\n", b->number); + if (b->related_breakpoint) + delete_breakpoint (b->related_breakpoint); + delete_breakpoint (b); + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + + /* Stop. */ + break; + } + } + else if (b->type == bp_read_watchpoint || b->type == bp_access_watchpoint) + { + CORE_ADDR addr; + value_ptr v; + int found = 0; + + addr = target_stopped_data_address(); + if (addr == 0) continue; + for (v = b->val_chain; v; v = v->next) + { + if (v->lval == lval_memory) + { + CORE_ADDR vaddr; + + vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v); + if (addr == vaddr) + found = 1; + } + } + if (found) + switch (catch_errors (watchpoint_check, (char *) bs, message, + RETURN_MASK_ALL)) + { + case WP_DELETED: + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + /* Stop. */ + break; + case WP_VALUE_CHANGED: + case WP_VALUE_NOT_CHANGED: + /* Stop. */ + break; + default: + /* Can't happen. */ + case 0: + /* Error from catch_errors. */ + printf_filtered ("Watchpoint %d deleted.\n", b->number); + if (b->related_breakpoint) + delete_breakpoint (b->related_breakpoint); + delete_breakpoint (b); + /* We've already printed what needs to be printed. */ + bs->print_it = print_it_done; + break; + } + } +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + else + real_breakpoint = 1; +#endif + + if (b->frame && b->frame != (get_current_frame ())->frame) + bs->stop = 0; + else + { + int value_is_zero = 0; + + if (b->cond) + { + /* Need to select the frame, with all that implies + so that the conditions will have the right context. */ + select_frame (get_current_frame (), 0); + value_is_zero + = catch_errors (breakpoint_cond_eval, (char *)(b->cond), + "Error in testing breakpoint condition:\n", + RETURN_MASK_ALL); + /* FIXME-someday, should give breakpoint # */ + free_all_values (); + } + if (b->cond && value_is_zero) + { + bs->stop = 0; + } + else if (b->ignore_count > 0) + { + b->ignore_count--; + bs->stop = 0; + } + else + { + /* We will stop here */ + if (b->disposition == disable) + b->enable = disabled; + bs->commands = b->commands; + if (b->silent) + bs->print = 0; + if (bs->commands && STREQ ("silent", bs->commands->line)) + { + bs->commands = bs->commands->next; + bs->print = 0; + } + } + } + /* Print nothing for this entry if we dont stop or if we dont print. */ + if (bs->stop == 0 || bs->print == 0) + bs->print_it = print_it_noop; + } + + bs->next = NULL; /* Terminate the chain */ + bs = root_bs->next; /* Re-grab the head of the chain */ +#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS) + if (bs) + { + if (real_breakpoint) + { + *pc = bp_addr; +#if defined (SHIFT_INST_REGS) + SHIFT_INST_REGS(); +#else /* No SHIFT_INST_REGS. */ + write_pc (bp_addr); +#endif /* No SHIFT_INST_REGS. */ + } + } +#endif /* DECR_PC_AFTER_BREAK != 0. */ + + /* The value of a hardware watchpoint hasn't changed, but the + intermediate memory locations we are watching may have. */ + if (bs && ! bs->stop && + (bs->breakpoint_at->type == bp_hardware_watchpoint || + bs->breakpoint_at->type == bp_read_watchpoint || + bs->breakpoint_at->type == bp_access_watchpoint)) + { + remove_breakpoints (); + insert_breakpoints (); + } + return bs; +} + +/* Tell what to do about this bpstat. */ +struct bpstat_what +bpstat_what (bs) + bpstat bs; +{ + /* Classify each bpstat as one of the following. */ + enum class { + /* This bpstat element has no effect on the main_action. */ + no_effect = 0, + + /* There was a watchpoint, stop but don't print. */ + wp_silent, + + /* There was a watchpoint, stop and print. */ + wp_noisy, + + /* There was a breakpoint but we're not stopping. */ + bp_nostop, + + /* There was a breakpoint, stop but don't print. */ + bp_silent, + + /* There was a breakpoint, stop and print. */ + bp_noisy, + + /* We hit the longjmp breakpoint. */ + long_jump, + + /* We hit the longjmp_resume breakpoint. */ + long_resume, + + /* We hit the step_resume breakpoint. */ + step_resume, + + /* We hit the through_sigtramp breakpoint. */ + through_sig, + + /* We hit the shared library event breakpoint. */ + shlib_event, + + /* This is just used to count how many enums there are. */ + class_last + }; + + /* Here is the table which drives this routine. So that we can + format it pretty, we define some abbreviations for the + enum bpstat_what codes. */ +#define kc BPSTAT_WHAT_KEEP_CHECKING +#define ss BPSTAT_WHAT_STOP_SILENT +#define sn BPSTAT_WHAT_STOP_NOISY +#define sgl BPSTAT_WHAT_SINGLE +#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME +#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME +#define clrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE +#define sr BPSTAT_WHAT_STEP_RESUME +#define ts BPSTAT_WHAT_THROUGH_SIGTRAMP +#define shl BPSTAT_WHAT_CHECK_SHLIBS + +/* "Can't happen." Might want to print an error message. + abort() is not out of the question, but chances are GDB is just + a bit confused, not unusable. */ +#define err BPSTAT_WHAT_STOP_NOISY + + /* Given an old action and a class, come up with a new action. */ + /* One interesting property of this table is that wp_silent is the same + as bp_silent and wp_noisy is the same as bp_noisy. That is because + after stopping, the check for whether to step over a breakpoint + (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without + reference to how we stopped. We retain separate wp_silent and bp_silent + codes in case we want to change that someday. */ + + /* step_resume entries: a step resume breakpoint overrides another + breakpoint of signal handling (see comment in wait_for_inferior + at first IN_SIGTRAMP where we set the step_resume breakpoint). */ + /* We handle the through_sigtramp_breakpoint the same way; having both + one of those and a step_resume_breakpoint is probably very rare (?). */ + + static const enum bpstat_what_main_action + table[(int)class_last][(int)BPSTAT_WHAT_LAST] = + { + /* old action */ + /* kc ss sn sgl slr clr clrs sr ts shl + */ +/*no_effect*/ {kc, ss, sn, sgl, slr, clr, clrs, sr, ts, shl}, +/*wp_silent*/ {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl}, +/*wp_noisy*/ {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl}, +/*bp_nostop*/ {sgl, ss, sn, sgl, slr, clrs, clrs, sr, ts, shl}, +/*bp_silent*/ {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl}, +/*bp_noisy*/ {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl}, +/*long_jump*/ {slr, ss, sn, slr, err, err, err, sr, ts, shl}, +/*long_resume*/ {clr, ss, sn, clrs, err, err, err, sr, ts, shl}, +/*step_resume*/ {sr, sr, sr, sr, sr, sr, sr, sr, ts, shl}, +/*through_sig*/ {ts, ts, ts, ts, ts, ts, ts, ts, ts, shl}, +/*shlib*/ {shl, shl, shl, shl, shl, shl, shl, shl, ts, shl} + }; +#undef kc +#undef ss +#undef sn +#undef sgl +#undef slr +#undef clr +#undef clrs +#undef err +#undef sr +#undef ts +#undef shl + enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; + struct bpstat_what retval; + + retval.call_dummy = 0; + for (; bs != NULL; bs = bs->next) + { + enum class bs_class = no_effect; + if (bs->breakpoint_at == NULL) + /* I suspect this can happen if it was a momentary breakpoint + which has since been deleted. */ + continue; + switch (bs->breakpoint_at->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_until: + case bp_finish: + if (bs->stop) + { + if (bs->print) + bs_class = bp_noisy; + else + bs_class = bp_silent; + } + else + bs_class = bp_nostop; + break; + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + if (bs->stop) + { + if (bs->print) + bs_class = wp_noisy; + else + bs_class = wp_silent; + } + else + /* There was a watchpoint, but we're not stopping. This requires + no further action. */ + bs_class = no_effect; + break; + case bp_longjmp: + bs_class = long_jump; + break; + case bp_longjmp_resume: + bs_class = long_resume; + break; + case bp_step_resume: + if (bs->stop) + { + bs_class = step_resume; + } + else + /* It is for the wrong frame. */ + bs_class = bp_nostop; + break; + case bp_through_sigtramp: + bs_class = through_sig; + break; + case bp_watchpoint_scope: + bs_class = bp_nostop; + break; + case bp_shlib_event: + bs_class = shlib_event; + break; + case bp_call_dummy: + /* Make sure the action is stop (silent or noisy), so infrun.c + pops the dummy frame. */ + bs_class = bp_silent; + retval.call_dummy = 1; + break; + } + current_action = table[(int)bs_class][(int)current_action]; + } + retval.main_action = current_action; + return retval; +} + +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ + +int +bpstat_should_step () +{ + struct breakpoint *b; + ALL_BREAKPOINTS (b) + if (b->enable == enabled && b->type == bp_watchpoint) + return 1; + return 0; +} + +/* Print information on breakpoint number BNUM, or -1 if all. + If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS + is nonzero, process only watchpoints. */ + +static void +breakpoint_1 (bnum, allflag) + int bnum; + int allflag; +{ + register struct breakpoint *b; + register struct command_line *l; + register struct symbol *sym; + CORE_ADDR last_addr = (CORE_ADDR)-1; + int found_a_breakpoint = 0; + static char *bptypes[] = {"breakpoint", "hw breakpoint", + "until", "finish", "watchpoint", + "hw watchpoint", "read watchpoint", + "acc watchpoint", "longjmp", + "longjmp resume", "step resume", + "sigtramp", + "watchpoint scope", "call dummy", + "shlib events" }; + static char *bpdisps[] = {"del", "dis", "keep"}; + static char bpenables[] = "ny"; + char wrap_indent[80]; + + ALL_BREAKPOINTS (b) + if (bnum == -1 + || bnum == b->number) + { +/* We only print out user settable breakpoints unless the allflag is set. */ + if (!allflag + && b->type != bp_breakpoint + && b->type != bp_hardware_breakpoint + && b->type != bp_watchpoint + && b->type != bp_read_watchpoint + && b->type != bp_access_watchpoint + && b->type != bp_hardware_watchpoint) + continue; + + if (!found_a_breakpoint++) + { + annotate_breakpoints_headers (); + + annotate_field (0); + printf_filtered ("Num "); + annotate_field (1); + printf_filtered ("Type "); + annotate_field (2); + printf_filtered ("Disp "); + annotate_field (3); + printf_filtered ("Enb "); + if (addressprint) + { + annotate_field (4); + printf_filtered ("Address "); + } + annotate_field (5); + printf_filtered ("What\n"); + + annotate_breakpoints_table (); + } + + annotate_record (); + annotate_field (0); + printf_filtered ("%-3d ", b->number); + annotate_field (1); + printf_filtered ("%-14s ", bptypes[(int)b->type]); + annotate_field (2); + printf_filtered ("%-4s ", bpdisps[(int)b->disposition]); + annotate_field (3); + printf_filtered ("%-3c ", bpenables[(int)b->enable]); + + strcpy (wrap_indent, " "); + if (addressprint) + strcat (wrap_indent, " "); + switch (b->type) + { + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + /* Field 4, the address, is omitted (which makes the columns + not line up too nicely with the headers, but the effect + is relatively readable). */ + annotate_field (5); + print_expression (b->exp, gdb_stdout); + break; + + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_step_resume: + case bp_through_sigtramp: + case bp_watchpoint_scope: + case bp_call_dummy: + case bp_shlib_event: + if (addressprint) + { + annotate_field (4); + /* FIXME-32x64: need a print_address_numeric with + field width */ + printf_filtered + ("%s ", + local_hex_string_custom + ((unsigned long) b->address, "08l")); + } + + annotate_field (5); + + last_addr = b->address; + if (b->source_file) + { + sym = find_pc_function (b->address); + if (sym) + { + fputs_filtered ("in ", gdb_stdout); + fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout); + wrap_here (wrap_indent); + fputs_filtered (" at ", gdb_stdout); + } + fputs_filtered (b->source_file, gdb_stdout); + printf_filtered (":%d", b->line_number); + } + else + print_address_symbolic (b->address, gdb_stdout, demangle, " "); + break; + } + + printf_filtered ("\n"); + + if (b->frame) + { + annotate_field (6); + + printf_filtered ("\tstop only in stack frame at "); + print_address_numeric (b->frame, 1, gdb_stdout); + printf_filtered ("\n"); + } + + if (b->cond) + { + annotate_field (7); + + printf_filtered ("\tstop only if "); + print_expression (b->cond, gdb_stdout); + printf_filtered ("\n"); + } + + if (show_breakpoint_hit_counts && b->hit_count) + { + /* FIXME should make an annotation for this */ + + printf_filtered ("\tbreakpoint already hit %d time%s\n", + b->hit_count, (b->hit_count == 1 ? "" : "s")); + } + + if (b->ignore_count) + { + annotate_field (8); + + printf_filtered ("\tignore next %d hits\n", b->ignore_count); + } + + if ((l = b->commands)) + { + annotate_field (9); + + while (l) + { + print_command_line (l, 4); + l = l->next; + } + } + } + + if (!found_a_breakpoint) + { + if (bnum == -1) + printf_filtered ("No breakpoints or watchpoints.\n"); + else + printf_filtered ("No breakpoint or watchpoint number %d.\n", bnum); + } + else + /* Compare against (CORE_ADDR)-1 in case some compiler decides + that a comparison of an unsigned with -1 is always false. */ + if (last_addr != (CORE_ADDR)-1) + set_next_address (last_addr); + + annotate_breakpoints_table_end (); +} + +/* ARGSUSED */ +static void +breakpoints_info (bnum_exp, from_tty) + char *bnum_exp; + int from_tty; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + + breakpoint_1 (bnum, 0); +} + +#if MAINTENANCE_CMDS + +/* ARGSUSED */ +static void +maintenance_info_breakpoints (bnum_exp, from_tty) + char *bnum_exp; + int from_tty; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + + breakpoint_1 (bnum, 1); +} + +#endif + +/* Print a message describing any breakpoints set at PC. */ + +static void +describe_other_breakpoints (pc) + register CORE_ADDR pc; +{ + register int others = 0; + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->address == pc) + others++; + if (others > 0) + { + printf_filtered ("Note: breakpoint%s ", (others > 1) ? "s" : ""); + ALL_BREAKPOINTS (b) + if (b->address == pc) + { + others--; + printf_filtered + ("%d%s%s ", + b->number, + ((b->enable == disabled || b->enable == shlib_disabled) + ? " (disabled)" : ""), + (others > 1) ? "," : ((others == 1) ? " and" : "")); + } + printf_filtered ("also set at pc "); + print_address_numeric (pc, 1, gdb_stdout); + printf_filtered (".\n"); + } +} + +/* Set the default place to put a breakpoint + for the `break' command with no arguments. */ + +void +set_default_breakpoint (valid, addr, symtab, line) + int valid; + CORE_ADDR addr; + struct symtab *symtab; + int line; +{ + default_breakpoint_valid = valid; + default_breakpoint_address = addr; + default_breakpoint_symtab = symtab; + default_breakpoint_line = line; +} + +/* Rescan breakpoints at address ADDRESS, + marking the first one as "first" and any others as "duplicates". + This is so that the bpt instruction is only inserted once. */ + +static void +check_duplicates (address) + CORE_ADDR address; +{ + register struct breakpoint *b; + register int count = 0; + + if (address == 0) /* Watchpoints are uninteresting */ + return; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled + && b->enable != shlib_disabled + && b->address == address) + { + count++; + b->duplicate = count > 1; + } +} + +/* Low level routine to set a breakpoint. + Takes as args the three things that every breakpoint must have. + Returns the breakpoint object so caller can set other things. + Does not set the breakpoint number! + Does not print anything. + + ==> This routine should not be called if there is a chance of later + error(); otherwise it leaves a bogus breakpoint on the chain. Validate + your arguments BEFORE calling this routine! */ + +static struct breakpoint * +set_raw_breakpoint (sal) + struct symtab_and_line sal; +{ + register struct breakpoint *b, *b1; + + b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint)); + memset (b, 0, sizeof (*b)); + b->address = sal.pc; + if (sal.symtab == NULL) + b->source_file = NULL; + else + b->source_file = savestring (sal.symtab->filename, + strlen (sal.symtab->filename)); + b->language = current_language->la_language; + b->input_radix = input_radix; + b->thread = -1; + b->line_number = sal.line; + b->enable = enabled; + b->next = 0; + b->silent = 0; + b->ignore_count = 0; + b->commands = NULL; + b->frame = 0; + + /* Add this breakpoint to the end of the chain + so that a list of breakpoints will come out in order + of increasing numbers. */ + + b1 = breakpoint_chain; + if (b1 == 0) + breakpoint_chain = b; + else + { + while (b1->next) + b1 = b1->next; + b1->next = b; + } + + check_duplicates (sal.pc); + breakpoints_changed (); + + return b; +} + +static int internal_breakpoint_number = -1; + +#ifdef GET_LONGJMP_TARGET + +static void +create_longjmp_breakpoint (func_name) + char *func_name; +{ + struct symtab_and_line sal; + struct breakpoint *b; + + if (func_name != NULL) + { + struct minimal_symbol *m; + + m = lookup_minimal_symbol_text (func_name, NULL, (struct objfile *)NULL); + if (m) + sal.pc = SYMBOL_VALUE_ADDRESS (m); + else + return; + } + else + sal.pc = 0; + + sal.symtab = NULL; + sal.line = 0; + + b = set_raw_breakpoint (sal); + if (!b) return; + + b->type = func_name != NULL ? bp_longjmp : bp_longjmp_resume; + b->disposition = donttouch; + b->enable = disabled; + b->silent = 1; + if (func_name) + b->addr_string = strsave(func_name); + b->number = internal_breakpoint_number--; +} + +#endif /* #ifdef GET_LONGJMP_TARGET */ + +/* Call this routine when stepping and nexting to enable a breakpoint if we do + a longjmp(). When we hit that breakpoint, call + set_longjmp_resume_breakpoint() to figure out where we are going. */ + +void +enable_longjmp_breakpoint() +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_longjmp) + { + b->enable = enabled; + check_duplicates (b->address); + } +} + +void +disable_longjmp_breakpoint() +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if ( b->type == bp_longjmp + || b->type == bp_longjmp_resume) + { + b->enable = disabled; + check_duplicates (b->address); + } +} + +#ifdef SOLIB_ADD +void +remove_solib_event_breakpoints () +{ + register struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->type == bp_shlib_event) + delete_breakpoint (b); +} + +void +create_solib_event_breakpoint (address) + CORE_ADDR address; +{ + struct breakpoint *b; + struct symtab_and_line sal; + + sal.pc = address; + sal.symtab = NULL; + sal.line = 0; + b = set_raw_breakpoint (sal); + b->number = internal_breakpoint_number--; + b->disposition = donttouch; + b->type = bp_shlib_event; +} + +/* Try to reenable any breakpoints in shared libraries. */ +void +re_enable_breakpoints_in_shlibs () +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->enable == shlib_disabled) + { + char buf[1]; + + /* Do not reenable the breakpoint if the shared library + is still not mapped in. */ + if (target_read_memory (b->address, buf, 1) == 0) + b->enable = enabled; + } +} + +#endif + +int +hw_breakpoint_used_count() +{ + register struct breakpoint *b; + int i = 0; + + ALL_BREAKPOINTS (b) + { + if (b->type == bp_hardware_breakpoint && b->enable == enabled) + i++; + } + + return i; +} + +int +hw_watchpoint_used_count(type, other_type_used) + enum bptype type; + int *other_type_used; +{ + register struct breakpoint *b; + int i = 0; + + *other_type_used = 0; + ALL_BREAKPOINTS (b) + { + if (b->enable == enabled) + { + if (b->type == type) i++; + else if ((b->type == bp_hardware_watchpoint || + b->type == bp_read_watchpoint || + b->type == bp_access_watchpoint) + && b->enable == enabled) + *other_type_used = 1; + } + } + return i; +} + +/* Call this after hitting the longjmp() breakpoint. Use this to set a new + breakpoint at the target of the jmp_buf. + + FIXME - This ought to be done by setting a temporary breakpoint that gets + deleted automatically... +*/ + +void +set_longjmp_resume_breakpoint(pc, frame) + CORE_ADDR pc; + struct frame_info *frame; +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_longjmp_resume) + { + b->address = pc; + b->enable = enabled; + if (frame != NULL) + b->frame = frame->frame; + else + b->frame = 0; + check_duplicates (b->address); + return; + } +} + +/* Set a breakpoint that will evaporate an end of command + at address specified by SAL. + Restrict it to frame FRAME if FRAME is nonzero. */ + +struct breakpoint * +set_momentary_breakpoint (sal, frame, type) + struct symtab_and_line sal; + struct frame_info *frame; + enum bptype type; +{ + register struct breakpoint *b; + b = set_raw_breakpoint (sal); + b->type = type; + b->enable = enabled; + b->disposition = donttouch; + b->frame = (frame ? frame->frame : 0); + + /* If we're debugging a multi-threaded program, then we + want momentary breakpoints to be active in only a + single thread of control. */ + if (in_thread_list (inferior_pid)) + b->thread = pid_to_thread_id (inferior_pid); + + return b; +} + +#if 0 +void +clear_momentary_breakpoints () +{ + register struct breakpoint *b, *temp; + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->disposition == delete) + { + delete_breakpoint (b); + break; + } +} +#endif + +/* Tell the user we have just set a breakpoint B. */ + +static void +mention (b) + struct breakpoint *b; +{ + int say_where = 0; + + /* FIXME: This is misplaced; mention() is called by things (like hitting a + watchpoint) other than breakpoint creation. It should be possible to + clean this up and at the same time replace the random calls to + breakpoint_changed with this hook, as has already been done for + delete_breakpoint_hook and so on. */ + if (create_breakpoint_hook) + create_breakpoint_hook (b); + + switch (b->type) + { + case bp_watchpoint: + printf_filtered ("Watchpoint %d: ", b->number); + print_expression (b->exp, gdb_stdout); + break; + case bp_hardware_watchpoint: + printf_filtered ("Hardware watchpoint %d: ", b->number); + print_expression (b->exp, gdb_stdout); + break; + case bp_read_watchpoint: + printf_filtered ("Hardware read watchpoint %d: ", b->number); + print_expression (b->exp, gdb_stdout); + break; + case bp_access_watchpoint: + printf_filtered ("Hardware access(read/write) watchpoint %d: ",b->number); + print_expression (b->exp, gdb_stdout); + break; + case bp_breakpoint: + printf_filtered ("Breakpoint %d", b->number); + say_where = 1; + break; + case bp_hardware_breakpoint: + printf_filtered ("Hardware assisted breakpoint %d", b->number); + say_where = 1; + break; + case bp_until: + case bp_finish: + case bp_longjmp: + case bp_longjmp_resume: + case bp_step_resume: + case bp_through_sigtramp: + case bp_call_dummy: + case bp_watchpoint_scope: + case bp_shlib_event: + break; + } + if (say_where) + { + if (addressprint || b->source_file == NULL) + { + printf_filtered (" at "); + print_address_numeric (b->address, 1, gdb_stdout); + } + if (b->source_file) + printf_filtered (": file %s, line %d.", + b->source_file, b->line_number); + } + printf_filtered ("\n"); +} + +#if 0 +/* Nobody calls this currently. */ +/* Set a breakpoint from a symtab and line. + If TEMPFLAG is nonzero, it is a temporary breakpoint. + ADDR_STRING is a malloc'd string holding the name of where we are + setting the breakpoint. This is used later to re-set it after the + program is relinked and symbols are reloaded. + Print the same confirmation messages that the breakpoint command prints. */ + +void +set_breakpoint (s, line, tempflag, addr_string) + struct symtab *s; + int line; + int tempflag; + char *addr_string; +{ + register struct breakpoint *b; + struct symtab_and_line sal; + + sal.symtab = s; + sal.line = line; + sal.pc = 0; + resolve_sal_pc (&sal); /* Might error out */ + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = 0; + b->addr_string = addr_string; + b->enable = enabled; + b->disposition = tempflag ? delete : donttouch; + + mention (b); +} +#endif /* 0 */ + +/* Set a breakpoint according to ARG (function, linenum or *address) + flag: first bit : 0 non-temporary, 1 temporary. + second bit : 0 normal breakpoint, 1 hardware breakpoint. */ + +static void +break_command_1 (arg, flag, from_tty) + char *arg; + int flag, from_tty; +{ + int tempflag, hardwareflag; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct expression *cond = 0; + register struct breakpoint *b; + + /* Pointers in arg to the start, and one past the end, of the condition. */ + char *cond_start = NULL; + char *cond_end = NULL; + /* Pointers in arg to the start, and one past the end, + of the address part. */ + char *addr_start = NULL; + char *addr_end = NULL; + struct cleanup *old_chain; + struct cleanup *canonical_strings_chain = NULL; + char **canonical = (char **)NULL; + int i; + int thread; + + hardwareflag = flag & BP_HARDWAREFLAG; + tempflag = flag & BP_TEMPFLAG; + + sals.sals = NULL; + sals.nelts = 0; + + sal.line = sal.pc = sal.end = 0; + sal.symtab = 0; + + /* If no arg given, or if first arg is 'if ', use the default breakpoint. */ + + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + if (default_breakpoint_valid) + { + sals.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + sal.pc = default_breakpoint_address; + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sals.sals[0] = sal; + sals.nelts = 1; + } + else + error ("No default breakpoint address now."); + } + else + { + addr_start = arg; + + /* 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 (default_breakpoint_valid + && (!current_source_symtab + || (arg && (*arg == '+' || *arg == '-')))) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line, &canonical); + else + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical); + + addr_end = arg; + } + + if (! sals.nelts) + return; + + /* Make sure that all storage allocated in decode_line_1 gets freed in case + the following `for' loop errors out. */ + old_chain = make_cleanup (free, sals.sals); + if (canonical != (char **)NULL) + { + make_cleanup (free, canonical); + canonical_strings_chain = make_cleanup (null_cleanup, 0); + for (i = 0; i < sals.nelts; i++) + { + if (canonical[i] != NULL) + make_cleanup (free, canonical[i]); + } + } + + thread = -1; /* No specific thread yet */ + + /* Resolve all line numbers to PC's, and verify that conditions + can be parsed, before setting any breakpoints. */ + for (i = 0; i < sals.nelts; i++) + { + char *tok, *end_tok; + int toklen; + + resolve_sal_pc (&sals.sals[i]); + + tok = arg; + + while (tok && *tok) + { + while (*tok == ' ' || *tok == '\t') + tok++; + + end_tok = tok; + + while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000') + end_tok++; + + toklen = end_tok - tok; + + if (toklen >= 1 && strncmp (tok, "if", toklen) == 0) + { + tok = cond_start = end_tok + 1; + cond = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0); + cond_end = tok; + } + else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0) + { + char *tmptok; + + tok = end_tok + 1; + tmptok = tok; + thread = strtol (tok, &tok, 0); + if (tok == tmptok) + error ("Junk after thread keyword."); + if (!valid_thread_id (thread)) + error ("Unknown thread %d\n", thread); + } + else + error ("Junk at end of arguments."); + } + } + if (hardwareflag) + { + int i, target_resources_ok; + + i = hw_breakpoint_used_count (); + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT ( + bp_hardware_breakpoint, i + sals.nelts, 0); + if (target_resources_ok == 0) + error ("No hardware breakpoint support in the target."); + else if (target_resources_ok < 0) + error ("Hardware breakpoints used exceeds limit."); + } + + /* Remove the canonical strings from the cleanup, they are needed below. */ + if (canonical != (char **)NULL) + discard_cleanups (canonical_strings_chain); + + /* Now set all the breakpoints. */ + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (from_tty) + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = hardwareflag ? bp_hardware_breakpoint : bp_breakpoint; + b->cond = cond; + b->thread = thread; + + /* If a canonical line spec is needed use that instead of the + command string. */ + if (canonical != (char **)NULL && canonical[i] != NULL) + b->addr_string = canonical[i]; + else if (addr_start) + b->addr_string = savestring (addr_start, addr_end - addr_start); + if (cond_start) + b->cond_string = savestring (cond_start, cond_end - cond_start); + + b->enable = enabled; + b->disposition = tempflag ? del : donttouch; + + mention (b); + } + + if (sals.nelts > 1) + { + printf_filtered ("Multiple breakpoints were set.\n"); + printf_filtered ("Use the \"delete\" command to delete unwanted breakpoints.\n"); + } + do_cleanups (old_chain); +} + +/* Helper function for break_command_1 and disassemble_command. */ + +void +resolve_sal_pc (sal) + struct symtab_and_line *sal; +{ + CORE_ADDR pc; + + if (sal->pc == 0 && sal->symtab != 0) + { + pc = find_line_pc (sal->symtab, sal->line); + if (pc == 0) + error ("No line %d in file \"%s\".", + sal->line, sal->symtab->filename); + sal->pc = pc; + } +} + +void +break_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, 0, from_tty); +} + +static void +tbreak_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, BP_TEMPFLAG, from_tty); +} + +static void +hbreak_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, BP_HARDWAREFLAG, from_tty); +} + +static void +thbreak_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty); +} + +/* ARGSUSED */ +/* accessflag: 0: watch write, 1: watch read, 2: watch access(read or write) +*/ +static void +watch_command_1 (arg, accessflag, from_tty) + char *arg; + int accessflag; + int from_tty; +{ + struct breakpoint *b; + struct symtab_and_line sal; + struct expression *exp; + struct block *exp_valid_block; + struct value *val, *mark; + struct frame_info *frame, *prev_frame; + char *exp_start = NULL; + char *exp_end = NULL; + char *tok, *end_tok; + int toklen; + char *cond_start = NULL; + char *cond_end = NULL; + struct expression *cond = NULL; + int i, other_type_used, target_resources_ok; + enum bptype bp_type; + int mem_cnt = 0; + + sal.pc = 0; + sal.symtab = NULL; + sal.line = 0; + + /* Parse arguments. */ + innermost_block = NULL; + exp_start = arg; + exp = parse_exp_1 (&arg, 0, 0); + exp_end = arg; + exp_valid_block = innermost_block; + mark = value_mark (); + val = evaluate_expression (exp); + release_value (val); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + + tok = arg; + while (*tok == ' ' || *tok == '\t') + tok++; + end_tok = tok; + + while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000') + end_tok++; + + toklen = end_tok - tok; + if (toklen >= 1 && strncmp (tok, "if", toklen) == 0) + { + tok = cond_start = end_tok + 1; + cond = parse_exp_1 (&tok, 0, 0); + cond_end = tok; + } + if (*tok) + error("Junk at end of command."); + + if (accessflag == 1) bp_type = bp_read_watchpoint; + else if (accessflag == 2) bp_type = bp_access_watchpoint; + else bp_type = bp_hardware_watchpoint; + + mem_cnt = can_use_hardware_watchpoint (val); + if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint) + error ("Expression cannot be implemented with read/access watchpoint."); + if (mem_cnt != 0) { + i = hw_watchpoint_used_count (bp_type, &other_type_used); + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT( + bp_type, i + mem_cnt, other_type_used); + if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint) + error ("Target does not have this type of hardware watchpoint support."); + if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint) + error ("Target resources have been allocated for other types of watchpoints."); + } + + /* Now set up the breakpoint. */ + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->disposition = donttouch; + b->exp = exp; + b->exp_valid_block = exp_valid_block; + b->exp_string = savestring (exp_start, exp_end - exp_start); + b->val = val; + b->cond = cond; + if (cond_start) + b->cond_string = savestring (cond_start, cond_end - cond_start); + else + b->cond_string = 0; + + frame = block_innermost_frame (exp_valid_block); + if (frame) + { + prev_frame = get_prev_frame (frame); + b->watchpoint_frame = frame->frame; + } + else + b->watchpoint_frame = (CORE_ADDR)0; + + if (mem_cnt && target_resources_ok > 0) + b->type = bp_type; + else + b->type = bp_watchpoint; + + /* If the expression is "local", then set up a "watchpoint scope" + breakpoint at the point where we've left the scope of the watchpoint + expression. */ + if (innermost_block) + { + struct breakpoint *scope_breakpoint; + struct symtab_and_line scope_sal; + + if (prev_frame) + { + scope_sal.pc = get_frame_pc (prev_frame); + scope_sal.symtab = NULL; + scope_sal.line = 0; + + scope_breakpoint = set_raw_breakpoint (scope_sal); + set_breakpoint_count (breakpoint_count + 1); + scope_breakpoint->number = breakpoint_count; + + scope_breakpoint->type = bp_watchpoint_scope; + scope_breakpoint->enable = enabled; + + /* Automatically delete the breakpoint when it hits. */ + scope_breakpoint->disposition = del; + + /* Only break in the proper frame (help with recursion). */ + scope_breakpoint->frame = prev_frame->frame; + + /* Set the address at which we will stop. */ + scope_breakpoint->address = get_frame_pc (prev_frame); + + /* The scope breakpoint is related to the watchpoint. We + will need to act on them together. */ + b->related_breakpoint = scope_breakpoint; + } + } + value_free_to_mark (mark); + mention (b); +} + +/* Return count of locations need to be watched and can be handled + in hardware. If the watchpoint can not be handled + in hardware return zero. */ + +static int +can_use_hardware_watchpoint (v) + struct value *v; +{ + int found_memory_cnt = 0; + + /* Make sure all the intermediate values are in memory. Also make sure + we found at least one memory expression. Guards against watch 0x12345, + which is meaningless, but could cause errors if one tries to insert a + hardware watchpoint for the constant expression. */ + for ( ; v; v = v->next) + { + if (v->lval == lval_memory) + { + if (TYPE_LENGTH (VALUE_TYPE (v)) <= REGISTER_SIZE) + found_memory_cnt++; + } + else if (v->lval != not_lval && v->modifiable == 0) + return 0; + } + + /* The expression itself looks suitable for using a hardware + watchpoint, but give the target machine a chance to reject it. */ + return found_memory_cnt; +} + +static void watch_command (arg, from_tty) + char *arg; + int from_tty; +{ + watch_command_1 (arg, 0, from_tty); +} + +static void rwatch_command (arg, from_tty) + char *arg; + int from_tty; +{ + watch_command_1 (arg, 1, from_tty); +} + +static void awatch_command (arg, from_tty) + char *arg; + int from_tty; +{ + watch_command_1 (arg, 2, from_tty); +} + + +/* Helper routine for the until_command routine in infcmd.c. Here + because it uses the mechanisms of breakpoints. */ + +/* ARGSUSED */ +void +until_break_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct frame_info *prev_frame = get_prev_frame (selected_frame); + struct breakpoint *breakpoint; + struct cleanup *old_chain; + + clear_proceed_status (); + + /* Set a breakpoint where the user wants it and at return from + this function */ + + if (default_breakpoint_valid) + sals = decode_line_1 (&arg, 1, default_breakpoint_symtab, + default_breakpoint_line, (char ***)NULL); + else + sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, (char ***)NULL); + + if (sals.nelts != 1) + error ("Couldn't get information on specified line."); + + sal = sals.sals[0]; + free ((PTR)sals.sals); /* malloc'd, so freed */ + + if (*arg) + error ("Junk at end of arguments."); + + resolve_sal_pc (&sal); + + breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until); + + old_chain = make_cleanup(delete_breakpoint, breakpoint); + + /* Keep within the current frame */ + + if (prev_frame) + { + sal = find_pc_line (prev_frame->pc, 0); + sal.pc = prev_frame->pc; + breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until); + make_cleanup(delete_breakpoint, breakpoint); + } + + proceed (-1, TARGET_SIGNAL_DEFAULT, 0); + do_cleanups(old_chain); +} + +#if 0 +/* These aren't used; I don't konw what they were for. */ +/* Set a breakpoint at the catch clause for NAME. */ +static int +catch_breakpoint (name) + char *name; +{ +} + +static int +disable_catch_breakpoint () +{ +} + +static int +delete_catch_breakpoint () +{ +} + +static int +enable_catch_breakpoint () +{ +} +#endif /* 0 */ + +struct sal_chain +{ + struct sal_chain *next; + struct symtab_and_line sal; +}; + +#if 0 +/* This isn't used; I don't know what it was for. */ +/* For each catch clause identified in ARGS, run FUNCTION + with that clause as an argument. */ +static struct symtabs_and_lines +map_catch_names (args, function) + char *args; + int (*function)(); +{ + register char *p = args; + register char *p1; + struct symtabs_and_lines sals; +#if 0 + struct sal_chain *sal_chain = 0; +#endif + + if (p == 0) + error_no_arg ("one or more catch names"); + + sals.nelts = 0; + sals.sals = NULL; + + while (*p) + { + p1 = p; + /* Don't swallow conditional part. */ + if (p1[0] == 'i' && p1[1] == 'f' + && (p1[2] == ' ' || p1[2] == '\t')) + break; + + if (isalpha (*p1)) + { + p1++; + while (isalnum (*p1) || *p1 == '_' || *p1 == '$') + p1++; + } + + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be catch names."); + + *p1 = 0; +#if 0 + if (function (p)) + { + struct sal_chain *next + = (struct sal_chain *)alloca (sizeof (struct sal_chain)); + next->next = sal_chain; + next->sal = get_catch_sal (p); + sal_chain = next; + goto win; + } +#endif + printf_unfiltered ("No catch clause for exception %s.\n", p); +#if 0 + win: +#endif + p = p1; + while (*p == ' ' || *p == '\t') p++; + } +} +#endif /* 0 */ + +/* This shares a lot of code with `print_frame_label_vars' from stack.c. */ + +static struct symtabs_and_lines +get_catch_sals (this_level_only) + int this_level_only; +{ + register struct blockvector *bl; + register struct block *block; + int index, have_default = 0; + CORE_ADDR pc; + struct symtabs_and_lines sals; + struct sal_chain *sal_chain = 0; + char *blocks_searched; + + /* Not sure whether an error message is always the correct response, + but it's better than a core dump. */ + if (selected_frame == NULL) + error ("No selected frame."); + block = get_frame_block (selected_frame); + pc = selected_frame->pc; + + sals.nelts = 0; + sals.sals = NULL; + + if (block == 0) + error ("No symbol table info available.\n"); + + bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); + blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char)); + memset (blocks_searched, 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_searched[index] == 0) + { + struct block *b = BLOCKVECTOR_BLOCK (bl, index); + int nsyms; + register int i; + register struct symbol *sym; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (STREQ (SYMBOL_NAME (sym), "default")) + { + if (have_default) + continue; + have_default = 1; + } + if (SYMBOL_CLASS (sym) == LOC_LABEL) + { + struct sal_chain *next = (struct sal_chain *) + alloca (sizeof (struct sal_chain)); + next->next = sal_chain; + next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0); + sal_chain = next; + } + } + blocks_searched[index] = 1; + } + index++; + } + if (have_default) + break; + if (sal_chain && this_level_only) + break; + + /* 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); + } + + if (sal_chain) + { + struct sal_chain *tmp_chain; + + /* Count the number of entries. */ + for (index = 0, tmp_chain = sal_chain; tmp_chain; + tmp_chain = tmp_chain->next) + index++; + + sals.nelts = index; + sals.sals = (struct symtab_and_line *) + xmalloc (index * sizeof (struct symtab_and_line)); + for (index = 0; sal_chain; sal_chain = sal_chain->next, index++) + sals.sals[index] = sal_chain->sal; + } + + return sals; +} + +/* Commands to deal with catching exceptions. */ + +static void +catch_command_1 (arg, tempflag, from_tty) + char *arg; + int tempflag; + int from_tty; +{ + /* First, translate ARG into something we can deal with in terms + of breakpoints. */ + + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct expression *cond = 0; + register struct breakpoint *b; + char *save_arg; + int i; + + sal.line = sal.pc = sal.end = 0; + sal.symtab = 0; + + /* If no arg given, or if first arg is 'if ', all active catch clauses + are breakpointed. */ + + if (!arg || (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t'))) + { + /* Grab all active catch clauses. */ + sals = get_catch_sals (0); + } + else + { + /* Grab selected catch clauses. */ + error ("catch NAME not implemented"); +#if 0 + /* This isn't used; I don't know what it was for. */ + sals = map_catch_names (arg, catch_breakpoint); +#endif + } + + if (! sals.nelts) + return; + + save_arg = arg; + for (i = 0; i < sals.nelts; i++) + { + resolve_sal_pc (&sals.sals[i]); + + while (arg && *arg) + { + if (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t')) + cond = parse_exp_1 ((arg += 2, &arg), + block_for_pc (sals.sals[i].pc), 0); + else + error ("Junk at end of arguments."); + } + arg = save_arg; + } + + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (from_tty) + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = cond; + b->enable = enabled; + b->disposition = tempflag ? del : donttouch; + + mention (b); + } + + if (sals.nelts > 1) + { + printf_unfiltered ("Multiple breakpoints were set.\n"); + printf_unfiltered ("Use the \"delete\" command to delete unwanted breakpoints.\n"); + } + free ((PTR)sals.sals); +} + +/* Used by the gui, could be made a worker for other things. */ + +struct breakpoint * +set_breakpoint_sal (sal) +struct symtab_and_line sal; +{ + struct breakpoint *b; + b = set_raw_breakpoint (sal); + set_breakpoint_count (breakpoint_count + 1); + b->number = breakpoint_count; + b->type = bp_breakpoint; + b->cond = 0; + b->thread = -1; + return b; +} + +#if 0 +/* These aren't used; I don't know what they were for. */ +/* Disable breakpoints on all catch clauses described in ARGS. */ +static void +disable_catch (args) + char *args; +{ + /* Map the disable command to catch clauses described in ARGS. */ +} + +/* Enable breakpoints on all catch clauses described in ARGS. */ +static void +enable_catch (args) + char *args; +{ + /* Map the disable command to catch clauses described in ARGS. */ +} + +/* Delete breakpoints on all catch clauses in the active scope. */ +static void +delete_catch (args) + char *args; +{ + /* Map the delete command to catch clauses described in ARGS. */ +} +#endif /* 0 */ + +static void +catch_command (arg, from_tty) + char *arg; + int from_tty; +{ + catch_command_1 (arg, 0, from_tty); +} + +static void +clear_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b, *b1; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + register struct breakpoint *found; + int i; + + if (arg) + { + sals = decode_line_spec (arg, 1); + } + else + { + sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line)); + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sal.pc = 0; + if (sal.symtab == 0) + error ("No source file specified."); + + sals.sals[0] = sal; + sals.nelts = 1; + } + + for (i = 0; i < sals.nelts; i++) + { + /* If exact pc given, clear bpts at that pc. + But if sal.pc is zero, clear all bpts on specified line. */ + sal = sals.sals[i]; + found = (struct breakpoint *) 0; + while (breakpoint_chain + && (sal.pc + ? breakpoint_chain->address == sal.pc + : (breakpoint_chain->source_file != NULL + && sal.symtab != NULL + && STREQ (breakpoint_chain->source_file, + sal.symtab->filename) + && breakpoint_chain->line_number == sal.line))) + { + b1 = breakpoint_chain; + breakpoint_chain = b1->next; + b1->next = found; + found = b1; + } + + ALL_BREAKPOINTS (b) + while (b->next + && b->next->type != bp_watchpoint + && b->next->type != bp_hardware_watchpoint + && b->next->type != bp_read_watchpoint + && b->next->type != bp_access_watchpoint + && (sal.pc + ? b->next->address == sal.pc + : (b->next->source_file != NULL + && sal.symtab != NULL + && STREQ (b->next->source_file, sal.symtab->filename) + && b->next->line_number == sal.line))) + { + b1 = b->next; + b->next = b1->next; + b1->next = found; + found = b1; + } + + if (found == 0) + { + if (arg) + error ("No breakpoint at %s.", arg); + else + error ("No breakpoint at this line."); + } + + if (found->next) from_tty = 1; /* Always report if deleted more than one */ + if (from_tty) printf_unfiltered ("Deleted breakpoint%s ", found->next ? "s" : ""); + breakpoints_changed (); + while (found) + { + if (from_tty) printf_unfiltered ("%d ", found->number); + b1 = found->next; + delete_breakpoint (found); + found = b1; + } + if (from_tty) putchar_unfiltered ('\n'); + } + free ((PTR)sals.sals); +} + +/* Delete breakpoint in BS if they are `delete' breakpoints. + This is called after any breakpoint is hit, or after errors. */ + +void +breakpoint_auto_delete (bs) + bpstat bs; +{ + for (; bs; bs = bs->next) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == del + && bs->stop) + delete_breakpoint (bs->breakpoint_at); +} + +/* Delete a breakpoint and clean up all traces of it in the data structures. */ + +void +delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + register struct breakpoint *b; + register bpstat bs; + + if (delete_breakpoint_hook) + delete_breakpoint_hook (bpt); + + if (bpt->inserted) + remove_breakpoint (bpt); + + if (breakpoint_chain == bpt) + breakpoint_chain = bpt->next; + + ALL_BREAKPOINTS (b) + if (b->next == bpt) + { + b->next = bpt->next; + break; + } + + check_duplicates (bpt->address); + /* If this breakpoint was inserted, and there is another breakpoint + at the same address, we need to insert the other breakpoint. */ + if (bpt->inserted + && bpt->type != bp_hardware_watchpoint + && bpt->type != bp_read_watchpoint + && bpt->type != bp_access_watchpoint) + { + ALL_BREAKPOINTS (b) + if (b->address == bpt->address + && !b->duplicate + && b->enable != disabled + && b->enable != shlib_disabled) + { + int val; + val = target_insert_breakpoint (b->address, b->shadow_contents); + if (val != 0) + { + target_terminal_ours_for_output (); + fprintf_unfiltered (gdb_stderr, "Cannot insert breakpoint %d:\n", b->number); + memory_error (val, b->address); /* which bombs us out */ + } + else + b->inserted = 1; + } + } + + free_command_lines (&bpt->commands); + if (bpt->cond) + free (bpt->cond); + if (bpt->cond_string != NULL) + free (bpt->cond_string); + if (bpt->addr_string != NULL) + free (bpt->addr_string); + if (bpt->exp_string != NULL) + free (bpt->exp_string); + if (bpt->source_file != NULL) + free (bpt->source_file); + + /* Be sure no bpstat's are pointing at it after it's been freed. */ + /* FIXME, how can we find all bpstat's? + We just check stop_bpstat for now. */ + for (bs = stop_bpstat; bs; bs = bs->next) + if (bs->breakpoint_at == bpt) + bs->breakpoint_at = NULL; + free ((PTR)bpt); +} + +static void +delete_command (arg, from_tty) + char *arg; + int from_tty; +{ + + if (arg == 0) + { + /* Ask user only if there are some breakpoints to delete. */ + if (!from_tty + || (breakpoint_chain && query ("Delete all breakpoints? "))) + { + /* No arg; clear all breakpoints. */ + while (breakpoint_chain) + delete_breakpoint (breakpoint_chain); + } + } + else + map_breakpoint_numbers (arg, delete_breakpoint); +} + +/* Reset a breakpoint given it's struct breakpoint * BINT. + The value we return ends up being the return value from catch_errors. + Unused in this case. */ + +static int +breakpoint_re_set_one (bint) + char *bint; +{ + struct breakpoint *b = (struct breakpoint *)bint; /* get past catch_errs */ + struct value *mark; + int i; + struct symtabs_and_lines sals; + char *s; + enum enable save_enable; + + switch (b->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + if (b->addr_string == NULL) + { + /* Anything without a string can't be re-set. */ + delete_breakpoint (b); + return 0; + } + /* In case we have a problem, disable this breakpoint. We'll restore + its status if we succeed. */ + save_enable = b->enable; + b->enable = disabled; + + set_language (b->language); + input_radix = b->input_radix; + s = b->addr_string; + sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0, (char ***)NULL); + for (i = 0; i < sals.nelts; i++) + { + resolve_sal_pc (&sals.sals[i]); + + /* Reparse conditions, they might contain references to the + old symtab. */ + if (b->cond_string != NULL) + { + s = b->cond_string; + if (b->cond) + free ((PTR)b->cond); + b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0); + } + + /* We need to re-set the breakpoint if the address changes...*/ + if (b->address != sals.sals[i].pc + /* ...or new and old breakpoints both have source files, and + the source file name or the line number changes... */ + || (b->source_file != NULL + && sals.sals[i].symtab != NULL + && (!STREQ (b->source_file, sals.sals[i].symtab->filename) + || b->line_number != sals.sals[i].line) + ) + /* ...or we switch between having a source file and not having + one. */ + || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL)) + ) + { + if (b->source_file != NULL) + free (b->source_file); + if (sals.sals[i].symtab == NULL) + b->source_file = NULL; + else + b->source_file = + savestring (sals.sals[i].symtab->filename, + strlen (sals.sals[i].symtab->filename)); + b->line_number = sals.sals[i].line; + b->address = sals.sals[i].pc; + + check_duplicates (b->address); + + mention (b); + + /* Might be better to do this just once per breakpoint_re_set, + rather than once for every breakpoint. */ + breakpoints_changed (); + } + b->enable = save_enable; /* Restore it, this worked. */ + } + free ((PTR)sals.sals); + break; + + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + innermost_block = NULL; + /* The issue arises of what context to evaluate this in. The same + one as when it was set, but what does that mean when symbols have + been re-read? We could save the filename and functionname, but + if the context is more local than that, the best we could do would + be something like how many levels deep and which index at that + particular level, but that's going to be less stable than filenames + or functionnames. */ + /* So for now, just use a global context. */ + b->exp = parse_expression (b->exp_string); + b->exp_valid_block = innermost_block; + mark = value_mark (); + b->val = evaluate_expression (b->exp); + release_value (b->val); + if (VALUE_LAZY (b->val)) + value_fetch_lazy (b->val); + + if (b->cond_string != NULL) + { + s = b->cond_string; + b->cond = parse_exp_1 (&s, (struct block *)0, 0); + } + if (b->enable == enabled) + mention (b); + value_free_to_mark (mark); + break; + + default: + printf_filtered ("Deleting unknown breakpoint type %d\n", b->type); + /* fall through */ + /* Delete longjmp breakpoints, they will be reset later by + breakpoint_re_set. */ + case bp_longjmp: + case bp_longjmp_resume: + delete_breakpoint (b); + break; + + /* This breakpoint is special, it's set up when the inferior + starts and we really don't want to touch it. */ + case bp_shlib_event: + + /* Keep temporary breakpoints, which can be encountered when we step + over a dlopen call and SOLIB_ADD is resetting the breakpoints. + Otherwise these should have been blown away via the cleanup chain + or by breakpoint_init_inferior when we rerun the executable. */ + case bp_until: + case bp_finish: + case bp_watchpoint_scope: + case bp_call_dummy: + case bp_step_resume: + break; + } + + return 0; +} + +/* Re-set all breakpoints after symbols have been re-loaded. */ +void +breakpoint_re_set () +{ + struct breakpoint *b, *temp; + enum language save_language; + int save_input_radix; + static char message1[] = "Error in re-setting breakpoint %d:\n"; + char message[sizeof (message1) + 30 /* slop */]; + + save_language = current_language->la_language; + save_input_radix = input_radix; + ALL_BREAKPOINTS_SAFE (b, temp) + { + sprintf (message, message1, b->number); /* Format possible error msg */ + catch_errors (breakpoint_re_set_one, (char *) b, message, + RETURN_MASK_ALL); + } + set_language (save_language); + input_radix = save_input_radix; + +#ifdef GET_LONGJMP_TARGET + create_longjmp_breakpoint ("longjmp"); + create_longjmp_breakpoint ("_longjmp"); + create_longjmp_breakpoint ("siglongjmp"); + create_longjmp_breakpoint (NULL); +#endif + +#if 0 + /* Took this out (temporarily at least), since it produces an extra + blank line at startup. This messes up the gdbtests. -PB */ + /* Blank line to finish off all those mention() messages we just printed. */ + printf_filtered ("\n"); +#endif +} + +/* Set ignore-count of breakpoint number BPTNUM to COUNT. + If from_tty is nonzero, it prints a message to that effect, + which ends with a period (no newline). */ + +void +set_ignore_count (bptnum, count, from_tty) + int bptnum, count, from_tty; +{ + register struct breakpoint *b; + + if (count < 0) + count = 0; + + ALL_BREAKPOINTS (b) + if (b->number == bptnum) + { + b->ignore_count = count; + if (!from_tty) + return; + else if (count == 0) + printf_filtered ("Will stop next time breakpoint %d is reached.", + bptnum); + else if (count == 1) + printf_filtered ("Will ignore next crossing of breakpoint %d.", + bptnum); + else + printf_filtered ("Will ignore next %d crossings of breakpoint %d.", + count, bptnum); + breakpoints_changed (); + return; + } + + error ("No breakpoint number %d.", bptnum); +} + +/* Clear the ignore counts of all breakpoints. */ +void +breakpoint_clear_ignore_counts () +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->ignore_count = 0; +} + +/* Command to set ignore-count of breakpoint N to COUNT. */ + +static void +ignore_command (args, from_tty) + char *args; + int from_tty; +{ + char *p = args; + register int num; + + if (p == 0) + error_no_arg ("a breakpoint number"); + + num = get_number (&p); + + if (*p == 0) + error ("Second argument (specified ignore-count) is missing."); + + set_ignore_count (num, + longest_to_int (value_as_long (parse_and_eval (p))), + from_tty); + printf_filtered ("\n"); + breakpoints_changed (); +} + +/* Call FUNCTION on each of the breakpoints + whose numbers are given in ARGS. */ + +static void +map_breakpoint_numbers (args, function) + char *args; + void (*function) PARAMS ((struct breakpoint *)); +{ + register char *p = args; + char *p1; + register int num; + register struct breakpoint *b; + + if (p == 0) + error_no_arg ("one or more breakpoint numbers"); + + while (*p) + { + p1 = p; + + num = get_number (&p1); + + ALL_BREAKPOINTS (b) + if (b->number == num) + { + struct breakpoint *related_breakpoint = b->related_breakpoint; + function (b); + if (related_breakpoint) + function (related_breakpoint); + goto win; + } + printf_unfiltered ("No breakpoint number %d.\n", num); + win: + p = p1; + } +} + +void +enable_breakpoint (bpt) + struct breakpoint *bpt; +{ + struct frame_info *save_selected_frame = NULL; + int save_selected_frame_level = -1; + int target_resources_ok, other_type_used; + struct value *mark; + + if (bpt->type == bp_hardware_breakpoint) + { + int i; + i = hw_breakpoint_used_count(); + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT( + bp_hardware_breakpoint, i+1, 0); + if (target_resources_ok == 0) + error ("No hardware breakpoint support in the target."); + else if (target_resources_ok < 0) + error ("Hardware breakpoints used exceeds limit."); + } + bpt->enable = enabled; + check_duplicates (bpt->address); + + if (bpt->type == bp_watchpoint || bpt->type == bp_hardware_watchpoint || + bpt->type == bp_read_watchpoint || bpt->type == bp_access_watchpoint) + { + if (bpt->exp_valid_block != NULL) + { + struct frame_info *fr = + find_frame_addr_in_frame_chain (bpt->watchpoint_frame); + if (fr == NULL) + { + printf_filtered ("\ +Cannot enable watchpoint %d because the block in which its expression\n\ +is valid is not currently in scope.\n", bpt->number); + bpt->enable = disabled; + return; + } + + save_selected_frame = selected_frame; + save_selected_frame_level = selected_frame_level; + select_frame (fr, -1); + } + + value_free (bpt->val); + mark = value_mark (); + bpt->val = evaluate_expression (bpt->exp); + release_value (bpt->val); + if (VALUE_LAZY (bpt->val)) + value_fetch_lazy (bpt->val); + + if (bpt->type == bp_hardware_watchpoint || + bpt->type == bp_read_watchpoint || + bpt->type == bp_access_watchpoint) + { + int i = hw_watchpoint_used_count (bpt->type, &other_type_used); + int mem_cnt = can_use_hardware_watchpoint (bpt->val); + + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT( + bpt->type, i + mem_cnt, other_type_used); + /* we can consider of type is bp_hardware_watchpoint, convert to + bp_watchpoint in the following condition */ + if (target_resources_ok < 0) + { + printf_filtered("\ +Cannot enable watchpoint %d because target watch resources\n\ +have been allocated for other watchpoints.\n", bpt->number); + bpt->enable = disabled; + value_free_to_mark (mark); + return; + } + } + + if (save_selected_frame_level >= 0) + select_frame (save_selected_frame, save_selected_frame_level); + value_free_to_mark (mark); + } + + if (modify_breakpoint_hook) + modify_breakpoint_hook (bpt); +} + +/* ARGSUSED */ +static void +enable_command (args, from_tty) + char *args; + int from_tty; +{ + struct breakpoint *bpt; + if (args == 0) + ALL_BREAKPOINTS (bpt) + switch (bpt->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + enable_breakpoint (bpt); + default: + continue; + } + else + map_breakpoint_numbers (args, enable_breakpoint); +} + +void +disable_breakpoint (bpt) + struct breakpoint *bpt; +{ + /* Never disable a watchpoint scope breakpoint; we want to + hit them when we leave scope so we can delete both the + watchpoint and its scope breakpoint at that time. */ + if (bpt->type == bp_watchpoint_scope) + return; + + bpt->enable = disabled; + + check_duplicates (bpt->address); + + if (modify_breakpoint_hook) + modify_breakpoint_hook (bpt); +} + +/* ARGSUSED */ +static void +disable_command (args, from_tty) + char *args; + int from_tty; +{ + register struct breakpoint *bpt; + if (args == 0) + ALL_BREAKPOINTS (bpt) + switch (bpt->type) + { + case bp_breakpoint: + case bp_hardware_breakpoint: + case bp_watchpoint: + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_access_watchpoint: + disable_breakpoint (bpt); + default: + continue; + } + else + map_breakpoint_numbers (args, disable_breakpoint); +} + +static void +enable_once_breakpoint (bpt) + struct breakpoint *bpt; +{ + struct frame_info *save_selected_frame = NULL; + int save_selected_frame_level = -1; + int target_resources_ok, other_type_used; + struct value *mark; + + if (bpt->type == bp_hardware_breakpoint) + { + int i; + i = hw_breakpoint_used_count(); + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT( + bp_hardware_breakpoint, i+1, 0); + if (target_resources_ok == 0) + error ("No hardware breakpoint support in the target."); + else if (target_resources_ok < 0) + error ("Hardware breakpoints used exceeds limit."); + } + + bpt->enable = enabled; + bpt->disposition = disable; + check_duplicates (bpt->address); + breakpoints_changed (); + + if (bpt->type == bp_watchpoint || bpt->type == bp_hardware_watchpoint || + bpt->type == bp_read_watchpoint || bpt->type == bp_access_watchpoint) + { + if (bpt->exp_valid_block != NULL) + { + struct frame_info *fr = + find_frame_addr_in_frame_chain (bpt->watchpoint_frame); + if (fr == NULL) + { + printf_filtered ("\ +Cannot enable watchpoint %d because the block in which its expression\n\ +is valid is not currently in scope.\n", bpt->number); + bpt->enable = disabled; + return; + } + + save_selected_frame = selected_frame; + save_selected_frame_level = selected_frame_level; + select_frame (fr, -1); + } + + value_free (bpt->val); + mark = value_mark (); + bpt->val = evaluate_expression (bpt->exp); + release_value (bpt->val); + if (VALUE_LAZY (bpt->val)) + value_fetch_lazy (bpt->val); + + if (bpt->type == bp_hardware_watchpoint || + bpt->type == bp_read_watchpoint || + bpt->type == bp_access_watchpoint) + { + int i = hw_watchpoint_used_count (bpt->type, &other_type_used); + int mem_cnt = can_use_hardware_watchpoint(bpt->val); + target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT( + bpt->type, i+mem_cnt, other_type_used); + /* we can consider of type is bp_hardware_watchpoint, convert to + bp_watchpoint in the following condition */ + if (target_resources_ok < 0) + { + printf_filtered("\ +Cannot enable watchpoint %d because target watch resources\n\ +have been allocated for other watchpoints.\n", bpt->number); + bpt->enable = disabled; + value_free_to_mark (mark); + } + } + + if (save_selected_frame_level >= 0) + select_frame (save_selected_frame, save_selected_frame_level); + value_free_to_mark (mark); + } +} + +/* ARGSUSED */ +static void +enable_once_command (args, from_tty) + char *args; + int from_tty; +{ + map_breakpoint_numbers (args, enable_once_breakpoint); +} + +static void +enable_delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = enabled; + bpt->disposition = del; + + check_duplicates (bpt->address); + breakpoints_changed (); +} + +/* ARGSUSED */ +static void +enable_delete_command (args, from_tty) + char *args; + int from_tty; +{ + map_breakpoint_numbers (args, enable_delete_breakpoint); +} + +/* Use default_breakpoint_'s, or nothing if they aren't valid. */ + +struct symtabs_and_lines +decode_line_spec_1 (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtabs_and_lines sals; + if (string == 0) + error ("Empty line specification."); + if (default_breakpoint_valid) + sals = decode_line_1 (&string, funfirstline, + default_breakpoint_symtab, default_breakpoint_line, + (char ***)NULL); + else + sals = decode_line_1 (&string, funfirstline, + (struct symtab *)NULL, 0, (char ***)NULL); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + +void +_initialize_breakpoint () +{ + breakpoint_chain = 0; + /* Don't bother to call set_breakpoint_count. $bpnum isn't useful + before a breakpoint is set. */ + breakpoint_count = 0; + + add_com ("ignore", class_breakpoint, ignore_command, + "Set ignore-count of breakpoint number N to COUNT.\n\ +Usage is `ignore N COUNT'."); + + add_com ("commands", class_breakpoint, commands_command, + "Set commands to be executed when a breakpoint is hit.\n\ +Give breakpoint number as argument after \"commands\".\n\ +With no argument, the targeted breakpoint is the last one set.\n\ +The commands themselves follow starting on the next line.\n\ +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, + "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. "); + + add_com ("tbreak", class_breakpoint, tbreak_command, + "Set a temporary breakpoint. Args like \"break\" command.\n\ +Like \"break\" except the breakpoint is only temporary,\n\ +so it will be deleted when hit. Equivalent to \"break\" followed\n\ +by using \"enable delete\" on the breakpoint number."); + + add_com ("hbreak", class_breakpoint, hbreak_command, + "Set a hardware assisted breakpoint. Args like \"break\" command.\n\ +Like \"break\" except the breakpoint requires hardware support,\n\ +some target hardware may not have this support."); + + add_com ("thbreak", class_breakpoint, thbreak_command, + "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\ +Like \"hbreak\" except the breakpoint is only temporary,\n\ +so it will be deleted when hit."); + + add_prefix_cmd ("enable", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +With no subcommand, breakpoints are enabled until you command otherwise.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +With a subcommand you can enable temporarily.", + &enablelist, "enable ", 1, &cmdlist); + + add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +May be abbreviated to simply \"enable\".\n", + &enablebreaklist, "enable breakpoints ", 1, &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes 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.", + &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.", + &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.", + &enablelist); + + add_prefix_cmd ("disable", class_breakpoint, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.", + &disablelist, "disable ", 1, &cmdlist); + add_com_alias ("dis", "disable", class_breakpoint, 1); + add_com_alias ("disa", "disable", class_breakpoint, 1); + + add_cmd ("breakpoints", class_alias, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\ +This command may be abbreviated \"disable\".", + &disablelist); + + add_prefix_cmd ("delete", class_breakpoint, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +\n\ +Also a prefix command for deletion of other GDB objects.\n\ +The \"unset\" command is also an alias for \"delete\".", + &deletelist, "delete ", 1, &cmdlist); + add_com_alias ("d", "delete", class_breakpoint, 1); + + add_cmd ("breakpoints", class_alias, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +This command may be abbreviated \"delete\".", + &deletelist); + + add_com ("clear", class_breakpoint, clear_command, + concat ("Clear breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, all breakpoints in that line are cleared.\n\ +If function is specified, breakpoints at beginning of function are cleared.\n\ +If an address is specified, breakpoints at that address are cleared.\n\n", +"With no argument, clears all breakpoints in the line that the selected frame\n\ +is executing in.\n\ +\n\ +See also the \"delete\" command which clears breakpoints by number.", NULL)); + + add_com ("break", class_breakpoint, break_command, + concat ("Set breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, break at start of code for that line.\n\ +If function is specified, break at start of code for that function.\n\ +If an address is specified, break at that exact address.\n", +"With no arg, uses current execution address of selected stack frame.\n\ +This is useful for breaking on return to a stack frame.\n\ +\n\ +Multiple breakpoints at one place are permitted, and useful if conditional.\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)); + add_com_alias ("b", "break", class_run, 1); + add_com_alias ("br", "break", class_run, 1); + add_com_alias ("bre", "break", class_run, 1); + add_com_alias ("brea", "break", class_run, 1); + + add_info ("breakpoints", breakpoints_info, + concat ("Status of user-settable breakpoints, or breakpoint number NUMBER.\n\ +The \"Type\" column indicates one of:\n\ +\tbreakpoint - normal breakpoint\n\ +\twatchpoint - watchpoint\n\ +The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\ +the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\ +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\ +address and file/line number respectively.\n\n", +"Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed.\n\n\ +Convenience variable \"$bpnum\" contains the number of the last\n\ +breakpoint set.", NULL)); + +#if MAINTENANCE_CMDS + + add_cmd ("breakpoints", class_maintenance, maintenance_info_breakpoints, + concat ("Status of all breakpoints, or breakpoint number NUMBER.\n\ +The \"Type\" column indicates one of:\n\ +\tbreakpoint - normal breakpoint\n\ +\twatchpoint - watchpoint\n\ +\tlongjmp - internal breakpoint used to step through longjmp()\n\ +\tlongjmp resume - internal breakpoint at the target of longjmp()\n\ +\tuntil - internal breakpoint used by the \"until\" command\n\ +\tfinish - internal breakpoint used by the \"finish\" command\n", +"The \"Disp\" column contains one of \"keep\", \"del\", or \"dis\" to indicate\n\ +the disposition of the breakpoint after it gets hit. \"dis\" means that the\n\ +breakpoint will be disabled. The \"Address\" and \"What\" columns indicate the\n\ +address and file/line number respectively.\n\n", +"Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed.\n\n\ +Convenience variable \"$bpnum\" contains the number of the last\n\ +breakpoint set.", NULL), + &maintenanceinfolist); + +#endif /* MAINTENANCE_CMDS */ + + add_com ("catch", class_breakpoint, catch_command, + "Set breakpoints to catch exceptions that are raised.\n\ +Argument may be a single exception to catch, multiple exceptions\n\ +to catch, or the default exception \"default\". If no arguments\n\ +are given, breakpoints are set at all exception handlers catch clauses\n\ +within the current scope.\n\ +\n\ +A condition specified for the catch applies to all breakpoints set\n\ +with this command\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + + add_com ("watch", class_breakpoint, watch_command, + "Set a watchpoint for an expression.\n\ +A watchpoint stops execution of your program whenever the value of\n\ +an expression changes."); + + add_com ("rwatch", class_breakpoint, rwatch_command, + "Set a read watchpoint for an expression.\n\ +A watchpoint stops execution of your program whenever the value of\n\ +an expression is read."); + + add_com ("awatch", class_breakpoint, awatch_command, + "Set a watchpoint for an expression.\n\ +A watchpoint stops execution of your program whenever the value of\n\ +an expression is either read or written."); + + add_info ("watchpoints", breakpoints_info, + "Synonym for ``info breakpoints''."); + +} diff --git a/contrib/gdb/gdb/breakpoint.h b/contrib/gdb/gdb/breakpoint.h new file mode 100644 index 000000000000..90970cd0b29f --- /dev/null +++ b/contrib/gdb/gdb/breakpoint.h @@ -0,0 +1,424 @@ +/* Data structures associated with breakpoints in GDB. + Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (BREAKPOINT_H) +#define BREAKPOINT_H 1 + +#include "frame.h" +#include "value.h" + +/* 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 size + arrays that should be independent of the target architecture. */ + +#define BREAKPOINT_MAX 16 + +/* Type of breakpoint. */ +/* FIXME In the future, we should fold all other breakpoint-like things into + here. This includes: + + * single-step (for machines where we have to simulate single stepping) + (probably, though perhaps it is better for it to look as much as + possible like a single-step to wait_for_inferior). */ + +enum bptype { + bp_breakpoint, /* Normal breakpoint */ + bp_hardware_breakpoint, /* Hardware assisted breakpoint */ + bp_until, /* used by until command */ + bp_finish, /* used by finish command */ + bp_watchpoint, /* Watchpoint */ + bp_hardware_watchpoint, /* Hardware assisted watchpoint */ + bp_read_watchpoint, /* read watchpoint, (hardware assisted) */ + bp_access_watchpoint, /* access watchpoint, (hardware assisted) */ + bp_longjmp, /* secret breakpoint to find longjmp() */ + bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ + + /* Used by wait_for_inferior for stepping over subroutine calls, for + stepping over signal handlers, and for skipping prologues. */ + bp_step_resume, + + /* Used by wait_for_inferior for stepping over signal handlers. */ + bp_through_sigtramp, + + /* Used to detect when a watchpoint expression has gone out of + scope. These breakpoints are usually not visible to the user. + + This breakpoint has some interesting properties: + + 1) There's always a 1:1 mapping between watchpoints + on local variables and watchpoint_scope breakpoints. + + 2) It automatically deletes itself and the watchpoint it's + associated with when hit. + + 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)). */ + bp_call_dummy, + + /* Some dynamic linkers (HP, maybe Solaris) can arrange for special + code in the inferior to run when significant events occur in the + dynamic linker (for example a library is loaded or unloaded). + + By placing a breakpoint in this magic code GDB will get control + when these significant events occur. GDB can then re-examine + the dynamic linker's data structures to discover any newly loaded + dynamic libraries. */ + bp_shlib_event +}; + +/* States of enablement of breakpoint. */ + +enum enable { disabled, enabled, shlib_disabled}; + +/* Disposition of breakpoint. Ie: what to do after hitting it. */ + +enum bpdisp { + del, /* Delete it */ + disable, /* Disable it */ + donttouch /* Leave it alone */ +}; + +/* Note that the ->silent field is not currently used by any commands + (though the code is in there if it was to be, and set_raw_breakpoint + does set it to 0). I implemented it because I thought it would be + useful for a hack I had to put in; I'm going to leave it in because + I can see how there might be times when it would indeed be useful */ + +/* This is for a breakpoint or a watchpoint. */ + +struct breakpoint +{ + struct breakpoint *next; + /* Type of breakpoint. */ + enum bptype type; + /* Zero means disabled; remember the info but don't break here. */ + enum enable enable; + /* What to do with this breakpoint after we hit it. */ + enum bpdisp disposition; + /* Number assigned to distinguish breakpoints. */ + int number; + + /* Address to break at, or NULL if not a breakpoint. */ + CORE_ADDR address; + + /* Line number of this address. Only matters if address is + non-NULL. */ + + int line_number; + + /* Source file name of this address. Only matters if address is + non-NULL. */ + + char *source_file; + + /* Non-zero means a silent breakpoint (don't print frame info + if we stop here). */ + unsigned char silent; + /* Number of stops at this breakpoint that should + be continued automatically before really stopping. */ + int ignore_count; + /* "Real" contents of byte where breakpoint has been inserted. + Valid only when breakpoints are in the program. Under the complete + control of the target insert_breakpoint and remove_breakpoint routines. + No other code should assume anything about the value(s) here. */ + char shadow_contents[BREAKPOINT_MAX]; + /* Nonzero if this breakpoint is now inserted. Only matters if address + is non-NULL. */ + char inserted; + /* Nonzero if this is not the first breakpoint in the list + for the given address. Only matters if address is non-NULL. */ + char duplicate; + /* Chain of command lines to execute when this breakpoint is hit. */ + struct command_line *commands; + /* Stack depth (address of frame). If nonzero, break only if fp + equals this. */ + CORE_ADDR frame; + /* Conditional. Break only if this expression's value is nonzero. */ + struct expression *cond; + + /* String we used to set the breakpoint (malloc'd). Only matters if + address is non-NULL. */ + char *addr_string; + /* Language we used to set the breakpoint. */ + enum language language; + /* Input radix we used to set the breakpoint. */ + int input_radix; + /* String form of the breakpoint condition (malloc'd), or NULL if there + is no condition. */ + char *cond_string; + /* String form of exp (malloc'd), or NULL if none. */ + char *exp_string; + + /* The expression we are watching, or NULL if not a 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; + /* Value of the watchpoint the last time we checked it. */ + value_ptr val; + + /* Holds the value chain for a hardware watchpoint expression. */ + value_ptr val_chain; + + /* Holds the address of the related watchpoint_scope breakpoint + when using watchpoints on local variables (might the concept + of a related breakpoint be useful elsewhere, if not just call + it the watchpoint_scope breakpoint or something like that. FIXME). */ + struct breakpoint *related_breakpoint; + + /* Holds the frame address which identifies the frame this watchpoint + should be evaluated in, or NULL if the watchpoint should be evaluated + on the outermost frame. */ + CORE_ADDR watchpoint_frame; + + /* Thread number for thread-specific breakpoint, or -1 if don't care */ + int thread; + + /* Count of the number of times this breakpoint was taken, dumped + with the info, but not used for anything else. Useful for + seeing how many times you hit a break prior to the program + aborting, so you can back up to just before the abort. */ + int hit_count; + +}; + +/* The following stuff is an abstract data type "bpstat" ("breakpoint status"). + This provides the ability to determine whether we have stopped at a + breakpoint, and what we should do about it. */ + +typedef struct bpstats *bpstat; + +/* Interface: */ +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ +extern void bpstat_clear PARAMS ((bpstat *)); + +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ +extern bpstat bpstat_copy PARAMS ((bpstat)); + +extern bpstat bpstat_stop_status PARAMS ((CORE_ADDR *, int)); + +/* This bpstat_what stuff tells wait_for_inferior what to do with a + breakpoint (a challenging task). */ + +enum bpstat_what_main_action { + /* Perform various other tests; that is, this bpstat does not + say to perform any action (e.g. failed watchpoint and nothing + else). */ + BPSTAT_WHAT_KEEP_CHECKING, + + /* Rather than distinguish between noisy and silent stops here, it + might be cleaner to have bpstat_print make that decision (also + taking into account stop_print_frame and source_only). But the + implications are a bit scary (interaction with auto-displays, etc.), + so I won't try it. */ + + /* Stop silently. */ + BPSTAT_WHAT_STOP_SILENT, + + /* Stop and print. */ + BPSTAT_WHAT_STOP_NOISY, + + /* Remove breakpoints, single step once, then put them back in and + go back to what we were doing. It's possible that this should be + removed from the main_action and put into a separate field, to more + cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */ + BPSTAT_WHAT_SINGLE, + + /* Set longjmp_resume breakpoint, remove all other breakpoints, + and continue. The "remove all other breakpoints" part is required + if we are also stepping over another breakpoint as well as doing + the longjmp handling. */ + BPSTAT_WHAT_SET_LONGJMP_RESUME, + + /* Clear longjmp_resume breakpoint, then handle as + BPSTAT_WHAT_KEEP_CHECKING. */ + BPSTAT_WHAT_CLEAR_LONGJMP_RESUME, + + /* Clear longjmp_resume breakpoint, then handle as BPSTAT_WHAT_SINGLE. */ + BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE, + + /* Clear step resume breakpoint, and keep checking. */ + BPSTAT_WHAT_STEP_RESUME, + + /* Clear through_sigtramp breakpoint, muck with trap_expected, and keep + checking. */ + BPSTAT_WHAT_THROUGH_SIGTRAMP, + + /* Check the dynamic linker's data structures for new libraries, then + keep checking. */ + BPSTAT_WHAT_CHECK_SHLIBS, + + /* This is just used to keep track of how many enums there are. */ + BPSTAT_WHAT_LAST +}; + +struct bpstat_what { + enum bpstat_what_main_action main_action; + + /* Did we hit a call dummy breakpoint? This only goes with a main_action + of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of + continuing from a call dummy without popping the frame is not a + useful one). */ + int call_dummy; +}; + +/* Tell what to do about this bpstat. */ +struct bpstat_what bpstat_what PARAMS ((bpstat)); + +/* Find the bpstat associated with a breakpoint. NULL otherwise. */ +bpstat bpstat_find_breakpoint PARAMS ((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) + +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ +extern int bpstat_should_step PARAMS ((void)); + +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ +extern int bpstat_print PARAMS ((bpstat)); + +/* Return 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 good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ +extern int bpstat_num PARAMS ((bpstat *)); + +/* Perform actions associated with having stopped at *BSP. Actually, we just + use this for breakpoint commands. Perhaps other actions will go here + later, but this is executed at a late time (from the command loop). */ +extern void bpstat_do_actions PARAMS ((bpstat *)); + +/* Modify BS so that the actions will not be performed. */ +extern void bpstat_clear_actions PARAMS ((bpstat)); + +/* Implementation: */ +struct bpstats +{ + /* Linked list because there can be two breakpoints at the + same place, and a bpstat reflects the fact that both have been hit. */ + bpstat next; + /* Breakpoint that we are at. */ + struct breakpoint *breakpoint_at; + /* Commands left to be done. */ + struct command_line *commands; + /* Old value associated with a watchpoint. */ + value_ptr old_val; + + /* Nonzero if this breakpoint tells us to print the frame. */ + char print; + + /* Nonzero if this breakpoint tells us to stop. */ + char stop; + + /* Function called by bpstat_print to print stuff associated with + this element of the bpstat chain. Returns 0 or 1 just like + bpstat_print, or -1 if it can't deal with it. */ + int (*print_it) PARAMS((bpstat bs)); +}; + +/* Prototypes for breakpoint-related functions. */ + +#ifdef __STDC__ /* Forward declarations for prototypes */ +struct frame_info; +#endif + +extern int breakpoint_here_p PARAMS ((CORE_ADDR)); + +extern int frame_in_dummy PARAMS ((struct frame_info *)); + +extern int breakpoint_thread_match PARAMS ((CORE_ADDR, int)); + +extern void until_break_command PARAMS ((char *, int)); + +extern void breakpoint_re_set PARAMS ((void)); + +extern void clear_momentary_breakpoints PARAMS ((void)); + +extern struct breakpoint *set_momentary_breakpoint + PARAMS ((struct symtab_and_line, struct frame_info *, enum bptype)); + +extern void set_ignore_count PARAMS ((int, int, int)); + +extern void set_default_breakpoint PARAMS ((int, CORE_ADDR, struct symtab *, int)); + +extern void mark_breakpoints_out PARAMS ((void)); + +extern void breakpoint_init_inferior PARAMS ((void)); + +extern void delete_breakpoint PARAMS ((struct breakpoint *)); + +extern void breakpoint_auto_delete PARAMS ((bpstat)); + +extern void breakpoint_clear_ignore_counts PARAMS ((void)); + +extern void break_command PARAMS ((char *, int)); + +extern int insert_breakpoints PARAMS ((void)); + +extern int remove_breakpoints PARAMS ((void)); + +extern void enable_longjmp_breakpoint PARAMS ((void)); + +extern void disable_longjmp_breakpoint PARAMS ((void)); + +extern void set_longjmp_resume_breakpoint PARAMS ((CORE_ADDR, + struct frame_info *)); + +extern void clear_breakpoint_hit_counts PARAMS ((void)); + +/* The following are for displays, which aren't really breakpoints, but + here is as good a place as any for them. */ + +extern void disable_current_display PARAMS ((void)); + +extern void do_displays PARAMS ((void)); + +extern void disable_display PARAMS ((int)); + +extern void clear_displays PARAMS ((void)); + +extern void disable_breakpoint PARAMS ((struct breakpoint *)); + +extern void enable_breakpoint PARAMS ((struct breakpoint *)); + +extern void create_solib_event_breakpoint PARAMS ((CORE_ADDR)); + +extern void remove_solib_event_breakpoints PARAMS ((void)); + +extern void re_enable_breakpoints_in_shlibs PARAMS ((void)); + +#endif /* !defined (BREAKPOINT_H) */ diff --git a/contrib/gdb/gdb/buildsym.c b/contrib/gdb/gdb/buildsym.c new file mode 100644 index 000000000000..5a5847a823f4 --- /dev/null +++ b/contrib/gdb/gdb/buildsym.c @@ -0,0 +1,1039 @@ +/* Support routines for building symbol tables in GDB's internal format. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This module provides subroutines used for creating and adding to + the symbol table. These routines are called from various symbol- + file-reading routines. + + Routines to support specific debugging information formats (stabs, + DWARF, etc) belong somewhere else. */ + +#include "defs.h" +#include "bfd.h" +#include "obstack.h" +#include "symtab.h" +#include "symfile.h" /* Needed for "struct complaint" */ +#include "objfiles.h" +#include "gdbtypes.h" +#include "complaints.h" +#include "gdb_string.h" + +/* Ask buildsym.h to define the vars it normally declares `extern'. */ +#define EXTERN /**/ +#include "buildsym.h" /* Our own declarations */ +#undef EXTERN + +/* For cleanup_undefined_types and finish_global_stabs (somewhat + questionable--see comment where we call them). */ +#include "stabsread.h" + +static int +compare_line_numbers PARAMS ((const void *, const void *)); + +static struct blockvector * +make_blockvector PARAMS ((struct objfile *)); + + +/* Initial sizes of data structures. These are realloc'd larger if needed, + and realloc'd down to the size actually used, when completed. */ + +#define INITIAL_CONTEXT_STACK_SIZE 10 +#define INITIAL_LINE_VECTOR_LENGTH 1000 + + +/* Complaints about the symbols we have encountered. */ + +struct complaint innerblock_complaint = + {"inner block not inside outer block in %s", 0, 0}; + +struct complaint innerblock_anon_complaint = + {"inner block not inside outer block", 0, 0}; + +struct complaint blockvector_complaint = + {"block at 0x%lx out of order", 0, 0}; + + +/* maintain the lists of symbols and blocks */ + +/* Add a symbol to one of the lists of symbols. */ + +void +add_symbol_to_list (symbol, listhead) + struct symbol *symbol; + struct pending **listhead; +{ + register struct pending *link; + + /* We keep PENDINGSIZE symbols in each link of the list. + If we don't have a link with room in it, add a new link. */ + if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE) + { + if (free_pendings) + { + link = free_pendings; + free_pendings = link->next; + } + else + { + link = (struct pending *) xmalloc (sizeof (struct pending)); + } + + link->next = *listhead; + *listhead = link; + link->nsyms = 0; + } + + (*listhead)->symbol[(*listhead)->nsyms++] = symbol; +} + +/* Find a symbol named NAME on a LIST. NAME need not be '\0'-terminated; + LENGTH is the length of the name. */ + +struct symbol * +find_symbol_in_list (list, name, length) + struct pending *list; + char *name; + int length; +{ + int j; + char *pp; + + while (list != NULL) + { + for (j = list->nsyms; --j >= 0; ) + { + pp = SYMBOL_NAME (list->symbol[j]); + if (*pp == *name && strncmp (pp, name, length) == 0 && + pp[length] == '\0') + { + return (list->symbol[j]); + } + } + list = list->next; + } + return (NULL); +} + +/* At end of reading syms, or in case of quit, + really free as many `struct pending's as we can easily find. */ + +/* ARGSUSED */ +void +really_free_pendings (foo) + int foo; +{ + struct pending *next, *next1; +#if 0 + struct pending_block *bnext, *bnext1; +#endif + + for (next = free_pendings; next; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + free_pendings = NULL; + +#if 0 /* Now we make the links in the symbol_obstack, so don't free them. */ + for (bnext = pending_blocks; bnext; bnext = bnext1) + { + bnext1 = bnext->next; + free ((PTR)bnext); + } +#endif + pending_blocks = NULL; + + for (next = file_symbols; next != NULL; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + file_symbols = NULL; + + for (next = global_symbols; next != NULL; next = next1) + { + next1 = next->next; + free ((PTR)next); + } + global_symbols = 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. */ + +void +finish_block (symbol, listhead, old_blocks, start, end, objfile) + struct symbol *symbol; + struct pending **listhead; + struct pending_block *old_blocks; + CORE_ADDR start, end; + struct objfile *objfile; +{ + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + register int j; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; + next; + i += next->nsyms, next = next->next) + { + /*EMPTY*/; + } + + block = (struct block *) obstack_alloc (&objfile -> symbol_obstack, + (sizeof (struct block) + ((i - 1) * sizeof (struct symbol *)))); + + /* Copy the symbols into the block. */ + + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + { + for (j = next->nsyms - 1; j >= 0; j--) + { + BLOCK_SYM (block, --i) = next->symbol[j]; + } + } + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + /* Superblock filled in when containing block is made */ + BLOCK_SUPERBLOCK (block) = NULL; + BLOCK_GCC_COMPILED (block) = processing_gcc_compilation; + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + struct type *ftype = SYMBOL_TYPE (symbol); + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + + if (TYPE_NFIELDS (ftype) <= 0) + { + /* No parameter type information is recorded with the function's + type. Set that from the type of the parameter symbols. */ + int nparams = 0, iparams; + struct symbol *sym; + for (i = 0; i < BLOCK_NSYMS (block); i++) + { + sym = BLOCK_SYM (block, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + nparams++; + break; + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_REGISTER: + case LOC_LOCAL: + case LOC_TYPEDEF: + case LOC_LABEL: + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + default: + break; + } + } + if (nparams > 0) + { + TYPE_NFIELDS (ftype) = nparams; + TYPE_FIELDS (ftype) = (struct field *) + TYPE_ALLOC (ftype, nparams * sizeof (struct field)); + + for (i = iparams = 0; iparams < nparams; i++) + { + sym = BLOCK_SYM (block, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym); + iparams++; + break; + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_REGISTER: + case LOC_LOCAL: + case LOC_TYPEDEF: + case LOC_LABEL: + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + default: + break; + } + } + } + } + } + else + { + BLOCK_FUNCTION (block) = NULL; + } + + /* Now "free" the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + next->next = free_pendings; + free_pendings = next; + } + *listhead = NULL; + + /* Install this block as the superblock + of all blocks made since the start of this scope + that don't have superblocks yet. */ + + opblock = NULL; + for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == NULL) + { +#if 1 + /* Check to be sure the blocks are nested as we receive them. + If the compiler/assembler/linker work, this just burns a small + amount of time. */ + if (BLOCK_START (pblock->block) < BLOCK_START (block) || + BLOCK_END (pblock->block) > BLOCK_END (block)) + { + if (symbol) + { + complain (&innerblock_complaint, + SYMBOL_SOURCE_NAME (symbol)); + } + else + { + complain (&innerblock_anon_complaint); + } + BLOCK_START (pblock->block) = BLOCK_START (block); + BLOCK_END (pblock->block) = BLOCK_END (block); + } +#endif + BLOCK_SUPERBLOCK (pblock->block) = block; + } + opblock = pblock; + } + + /* Record this block on the list of all blocks in the file. + Put it after opblock, or at the beginning if opblock is 0. + This puts the block in the list after all its subblocks. */ + + /* Allocate in the symbol_obstack to save time. + It wastes a little space. */ + pblock = (struct pending_block *) + obstack_alloc (&objfile -> symbol_obstack, + sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } +} + +static struct blockvector * +make_blockvector (objfile) + struct objfile *objfile; +{ + register struct pending_block *next; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++) {;} + + blockvector = (struct blockvector *) + obstack_alloc (&objfile -> symbol_obstack, + (sizeof (struct blockvector) + + (i - 1) * sizeof (struct block *))); + + /* Copy the blocks into the blockvector. + This is done in reverse order, which happens to put + the blocks into the proper order (ascending starting address). + finish_block has hair to insert each block into the list + after its subblocks in order to make sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + { + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + } + +#if 0 /* Now we make the links in the obstack, so don't free them. */ + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + free (next); + } +#endif + pending_blocks = NULL; + +#if 1 /* FIXME, shut this off after a while to speed up symbol reading. */ + /* 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. FIXME. */ + if (BLOCKVECTOR_NBLOCKS (blockvector) > 1) + { + for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) + { + if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1)) + > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))) + { + + /* FIXME-32x64: loses if CORE_ADDR doesn't fit in a + long. Possible solutions include a version of + complain which takes a callback, a + sprintf_address_numeric to match + print_address_numeric, or a way to set up a GDB_FILE + * which causes sprintf rather than fprintf to be + called. */ + + complain (&blockvector_complaint, + (unsigned long) BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))); + } + } + } +#endif + + return (blockvector); +} + + +/* Start recording information about source code that came from an included + (or otherwise merged-in) source file with a different name. NAME is + the name of the file (cannot be NULL), DIRNAME is the directory in which + it resides (or NULL if not known). */ + +void +start_subfile (name, dirname) + char *name; + char *dirname; +{ + register struct subfile *subfile; + + /* See if this subfile is already known as a subfile of the + current main source file. */ + + for (subfile = subfiles; subfile; subfile = subfile->next) + { + if (STREQ (subfile->name, name)) + { + current_subfile = subfile; + return; + } + } + + /* This subfile is not known. Add an entry for it. + Make an entry for this subfile in the list of all subfiles + of the current main source file. */ + + subfile = (struct subfile *) xmalloc (sizeof (struct subfile)); + subfile->next = subfiles; + subfiles = subfile; + current_subfile = subfile; + + /* Save its name and compilation directory name */ + subfile->name = (name == NULL) ? NULL : savestring (name, strlen (name)); + subfile->dirname = + (dirname == NULL) ? NULL : savestring (dirname, strlen (dirname)); + + /* Initialize line-number recording for this subfile. */ + subfile->line_vector = NULL; + + /* Default the source language to whatever can be deduced from + the filename. If nothing can be deduced (such as for a C/C++ + include file with a ".h" extension), then inherit whatever + language the previous subfile had. This kludgery is necessary + because there is no standard way in some object formats to + record the source language. Also, when symtabs are allocated + we try to deduce a language then as well, but it is too late + for us to use that information while reading symbols, since + symtabs aren't allocated until after all the symbols have + been processed for a given source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + + /* cfront output is a C program, so in most ways it looks like a C + program. But to demangle we need to set the language to C++. We + can distinguish cfront code by the fact that it has #line + directives which specify a file name ending in .C. + + So if the filename of this subfile ends in .C, then change the language + of any pending subfiles from C to C++. We also accept any other C++ + suffixes accepted by deduce_language_from_filename (in particular, + some people use .cxx with cfront). */ + /* Likewise for f2c. */ + + if (subfile->name) + { + struct subfile *s; + enum language sublang = deduce_language_from_filename (subfile->name); + + if (sublang == language_cplus || sublang == language_fortran) + for (s = subfiles; s != NULL; s = s->next) + if (s->language == language_c) + s->language = sublang; + } + + /* And patch up this file if necessary. */ + if (subfile->language == language_c + && subfile->next != NULL + && (subfile->next->language == language_cplus + || subfile->next->language == language_fortran)) + { + subfile->language = subfile->next->language; + } +} + +/* For stabs readers, the first N_SO symbol is assumed to be the source + file name, and the subfile struct is initialized using that assumption. + If another N_SO symbol is later seen, immediately following the first + one, then the first one is assumed to be the directory name and the + second one is really the source file name. + + So we have to patch up the subfile struct by moving the old name value to + dirname and remembering the new name. Some sanity checking is performed + to ensure that the state of the subfile struct is reasonable and that the + old name we are assuming to be a directory name actually is (by checking + for a trailing '/'). */ + +void +patch_subfile_names (subfile, name) + struct subfile *subfile; + char *name; +{ + if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL + && subfile->name[strlen(subfile->name)-1] == '/') + { + subfile->dirname = subfile->name; + subfile->name = savestring (name, strlen (name)); + 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++ + include file with a ".h" extension), then inherit whatever + language the previous subfile had. This kludgery is necessary + because there is no standard way in some object formats to + record the source language. Also, when symtabs are allocated + we try to deduce a language then as well, but it is too late + for us to use that information while reading symbols, since + symtabs aren't allocated until after all the symbols have + been processed for a given source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + } +} + + +/* Handle the N_BINCL and N_EINCL symbol types + that act like N_SOL for switching source files + (different subfiles, as we call them) within one object file, + but using a stack rather than in an arbitrary order. */ + +void +push_subfile () +{ + register struct subfile_stack *tem + = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack)); + + tem->next = subfile_stack; + subfile_stack = tem; + if (current_subfile == NULL || current_subfile->name == NULL) + { + abort (); + } + tem->name = current_subfile->name; +} + +char * +pop_subfile () +{ + register char *name; + register struct subfile_stack *link = subfile_stack; + + if (link == NULL) + { + abort (); + } + name = link->name; + subfile_stack = link->next; + free ((PTR)link); + return (name); +} + + +/* Add a linetable entry for line number LINE and address PC to the line + vector for SUBFILE. */ + +void +record_line (subfile, line, pc) + register struct subfile *subfile; + int line; + CORE_ADDR pc; +{ + struct linetable_entry *e; + /* Ignore the dummy line number in libg.o */ + + if (line == 0xffff) + { + return; + } + + /* Make sure line vector exists and is big enough. */ + if (!subfile->line_vector) + { + subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH; + subfile->line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + subfile->line_vector_length * sizeof (struct linetable_entry)); + subfile->line_vector->nitems = 0; + } + + if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length) + { + subfile->line_vector_length *= 2; + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, (sizeof (struct linetable) + + subfile->line_vector_length * sizeof (struct linetable_entry))); + } + + e = subfile->line_vector->item + subfile->line_vector->nitems++; + e->line = line; e->pc = pc; +} + + +/* Needed in order to sort line tables from IBM xcoff files. Sigh! */ + +static int +compare_line_numbers (ln1p, ln2p) + const PTR ln1p; + const PTR ln2p; +{ + struct linetable_entry *ln1 = (struct linetable_entry *) ln1p; + struct linetable_entry *ln2 = (struct linetable_entry *) ln2p; + + /* Note: this code does not assume that CORE_ADDRs can fit in ints. + Please keep it that way. */ + if (ln1->pc < ln2->pc) + return -1; + + if (ln1->pc > ln2->pc) + return 1; + + /* If pc equal, sort by line. I'm not sure whether this is optimum + behavior (see comment at struct linetable in symtab.h). */ + return ln1->line - ln2->line; +} + + +/* Start a new symtab for a new source file. + Called, for example, when a stabs symbol of type N_SO is seen, or when + a DWARF TAG_compile_unit DIE is seen. + It indicates the start of data for one original source file. */ + +void +start_symtab (name, dirname, start_addr) + char *name; + char *dirname; + CORE_ADDR start_addr; +{ + + last_source_file = name; + last_source_start_addr = start_addr; + file_symbols = NULL; + global_symbols = NULL; + within_function = 0; + + /* Context stack is initially empty. Allocate first one with room for + 10 levels; reuse it forever afterward. */ + if (context_stack == NULL) + { + context_stack_size = INITIAL_CONTEXT_STACK_SIZE; + context_stack = (struct context_stack *) + xmalloc (context_stack_size * sizeof (struct context_stack)); + } + context_stack_depth = 0; + + /* 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); +} + +/* 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). */ + +struct symtab * +end_symtab (end_addr, objfile, section) + CORE_ADDR end_addr; + struct objfile *objfile; + int section; +{ + register struct symtab *symtab = NULL; + register struct blockvector *blockvector; + register struct subfile *subfile; + register struct context_stack *cstk; + struct subfile *nextsub; + + /* Finish the lexical context of the last function in the file; + pop the context stack. */ + + if (context_stack_depth > 0) + { + context_stack_depth--; + cstk = &context_stack[context_stack_depth]; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, end_addr, objfile); + + if (context_stack_depth > 0) + { + /* This is said to happen with SCO. The old coffread.c code + simply emptied the context stack, so we do the same. FIXME: + Find out why it is happening. This is not believed to happen + in most cases (even for coffread.c); it used to be an abort(). */ + static struct complaint msg = + {"Context stack not empty in end_symtab", 0, 0}; + complain (&msg); + context_stack_depth = 0; + } + } + + /* 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) + { + /* FIXME! Remove this horrid bubble sort and use qsort!!! + It'd be a whole lot easier if they weren't in a linked list!!! */ + int swapped; + do + { + struct pending_block *pb, *pbnext; + + pb = pending_blocks; + pbnext = pb->next; + swapped = 0; + + while (pbnext) + { + /* swap blocks if unordered! */ + + if (BLOCK_START(pb->block) < BLOCK_START(pbnext->block)) + { + struct block *tmp = pb->block; + pb->block = pbnext->block; + pbnext->block = tmp; + swapped = 1; + } + pb = pbnext; + pbnext = pbnext->next; + } + } while (swapped); + } + + /* Cleanup any undefined types that have been left hanging around + (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 + 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 (); + finish_global_stabs (objfile); + + if (pending_blocks == NULL + && file_symbols == NULL + && global_symbols == NULL) + { + /* Ignore symtabs that have no functions with real debugging info */ + blockvector = NULL; + } + else + { + /* Define the STATIC_BLOCK & 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); + blockvector = make_blockvector (objfile); + } + +#ifdef PROCESS_LINENUMBER_HOOK + PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */ +#endif + + /* Now create the symtab objects proper, one for each subfile. */ + /* (The main file is the last one on the chain.) */ + + for (subfile = subfiles; subfile; subfile = nextsub) + { + int linetablesize = 0; + /* If we have blocks of symbols, make a symtab. + Otherwise, just ignore this file and any line number info in it. */ + symtab = NULL; + if (blockvector) + { + if (subfile->line_vector) + { + linetablesize = sizeof (struct linetable) + + subfile->line_vector->nitems * sizeof (struct linetable_entry); +#if 0 + /* I think this is artifact from before it went on the obstack. + I doubt we'll need the memory between now and when we + free it later in this function. */ + /* First, shrink the linetable to make more memory. */ + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, linetablesize); +#endif + + /* Like the pending blocks, the line table may be scrambled + in reordered executables. Sort it if OBJF_REORDERED is + true. */ + if (objfile->flags & OBJF_REORDERED) + qsort (subfile->line_vector->item, + subfile->line_vector->nitems, + sizeof (struct linetable_entry), compare_line_numbers); + } + + /* Now, allocate a symbol table. */ + symtab = allocate_symtab (subfile->name, objfile); + + /* Fill in its components. */ + symtab->blockvector = blockvector; + if (subfile->line_vector) + { + /* Reallocate the line table on the symbol obstack */ + symtab->linetable = (struct linetable *) + obstack_alloc (&objfile -> symbol_obstack, linetablesize); + memcpy (symtab->linetable, subfile->line_vector, linetablesize); + } + else + { + symtab->linetable = NULL; + } + symtab->block_line_section = section; + if (subfile->dirname) + { + /* Reallocate the dirname on the symbol obstack */ + symtab->dirname = (char *) + obstack_alloc (&objfile -> symbol_obstack, + strlen (subfile -> dirname) + 1); + strcpy (symtab->dirname, subfile->dirname); + } + else + { + symtab->dirname = NULL; + } + symtab->free_code = free_linetable; + symtab->free_ptr = NULL; + + /* Use whatever language we have been using for this subfile, + not the one that was deduced in allocate_symtab from the + filename. We already did our own deducing when we created + the subfile, and we may have altered our opinion of what + language it is from things we found in the symbols. */ + symtab->language = subfile->language; + + /* All symtabs for the main file and the subfiles share a + blockvector, so we need to clear primary for everything but + the main file. */ + + symtab->primary = 0; + } + if (subfile->name != NULL) + { + free ((PTR) subfile->name); + } + if (subfile->dirname != NULL) + { + free ((PTR) subfile->dirname); + } + if (subfile->line_vector != NULL) + { + free ((PTR) subfile->line_vector); + } + + nextsub = subfile->next; + free ((PTR)subfile); + } + + /* Set this for the main source file. */ + if (symtab) + { + symtab->primary = 1; + } + + last_source_file = NULL; + current_subfile = NULL; + + return (symtab); +} + + +/* Push a context block. Args are an identifying nesting level (checkable + when you pop it), and the starting PC address of this context. */ + +struct context_stack * +push_context (desc, valu) + int desc; + CORE_ADDR valu; +{ + register struct context_stack *new; + + if (context_stack_depth == context_stack_size) + { + context_stack_size *= 2; + context_stack = (struct context_stack *) + xrealloc ((char *) context_stack, + (context_stack_size * sizeof (struct context_stack))); + } + + new = &context_stack[context_stack_depth++]; + new->depth = desc; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = valu; + new->name = NULL; + + local_symbols = NULL; + + return (new); +} + + +/* Compute a small integer hash code for the given name. */ + +int +hashname (name) + char *name; +{ + register char *p = name; + register int total = p[0]; + register int c; + + c = p[1]; + total += c << 2; + if (c) + { + c = p[2]; + total += c << 4; + if (c) + { + total += p[3] << 6; + } + } + + /* Ensure result is positive. */ + if (total < 0) + { + total += (1000 << 6); + } + return (total % HASHSIZE); +} + + +/* 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. */ + +void +buildsym_init () +{ + free_pendings = NULL; + file_symbols = NULL; + global_symbols = NULL; + pending_blocks = NULL; +} + +/* 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). */ + +void +buildsym_new_init () +{ + buildsym_init (); +} + +/* Initializer for this module */ + +void +_initialize_buildsym () +{ +} diff --git a/contrib/gdb/gdb/buildsym.h b/contrib/gdb/gdb/buildsym.h new file mode 100644 index 000000000000..58529c709b3d --- /dev/null +++ b/contrib/gdb/gdb/buildsym.h @@ -0,0 +1,259 @@ +/* Build symbol tables in GDB's internal format. + Copyright (C) 1986-1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (BUILDSYM_H) +#define BUILDSYM_H 1 + +/* This module provides definitions used for creating and adding to + the symbol table. These routines are called from various symbol- + file-reading routines. + + They originated in dbxread.c of gdb-4.2, and were split out to + make xcoffread.c more maintainable by sharing code. + + Variables declared in this file can be defined by #define-ing + the name EXTERN to null. It is used to declare variables that + are normally extern, but which get defined in a single module + using this technique. */ + +#ifndef EXTERN +#define EXTERN extern +#endif + +#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. */ + +EXTERN char *last_source_file; + +/* Core address of start of text of current source file. + This too comes from the N_SO symbol. */ + +EXTERN CORE_ADDR last_source_start_addr; + +/* The list of sub-source-files within the current individual compilation. + Each file gets its own symtab with its own linetable and associated info, + but they all share one blockvector. */ + +struct subfile +{ + struct subfile *next; + char *name; + char *dirname; + struct linetable *line_vector; + int line_vector_length; + enum language language; +}; + +EXTERN struct subfile *subfiles; + +EXTERN struct subfile *current_subfile; + +/* Global variable which, when set, indicates that we are processing a + .o file compiled with gcc */ + +EXTERN unsigned char processing_gcc_compilation; + +/* When set, we are processing a .o file compiled by sun acc. This is + misnamed; it refers to all stabs-in-elf implementations which use + N_UNDF the way Sun does, including Solaris gcc. Hopefully all + stabs-in-elf implementations ever invented will choose to be + compatible. */ + +EXTERN unsigned char processing_acc_compilation; + +/* Count symbols as they are processed, for error messages. */ + +EXTERN unsigned int symnum; + +/* Record the symbols defined for each context in a list. + We don't create a struct block for the context until we + know how long to make it. */ + +#define PENDINGSIZE 100 + +struct pending +{ + struct pending *next; + int nsyms; + struct symbol *symbol[PENDINGSIZE]; +}; + +/* List of free `struct pending' structures for reuse. */ + +EXTERN struct pending *free_pendings; + +/* Here are the three lists that symbols are put on. */ + +EXTERN struct pending *file_symbols; /* static at top level, and types */ + +EXTERN struct pending *global_symbols; /* global functions and variables */ + +EXTERN struct pending *local_symbols; /* everything local to lexic context */ + +/* Stack representing unclosed lexical contexts + (that will become blocks, eventually). */ + +struct context_stack +{ + /* Outer locals at the time we entered */ + + struct pending *locals; + + /* Pointer into blocklist as of entry */ + + struct pending_block *old_blocks; + + /* Name of function, if any, defining context*/ + + struct symbol *name; + + /* PC where this context starts */ + + CORE_ADDR start_addr; + + /* Temp slot for exception handling. */ + + CORE_ADDR end_addr; + + /* For error-checking matching push/pop */ + + int depth; + +}; + +EXTERN struct context_stack *context_stack; + +/* Index of first unused entry in context stack. */ + +EXTERN int context_stack_depth; + +/* Currently allocated size of context stack. */ + +EXTERN int context_stack_size; + +/* Macro "function" for popping contexts from the stack. Pushing is done + by a real function, push_context. This returns a pointer to a struct + context_stack. */ + +#define pop_context() (&context_stack[--context_stack_depth]); + +/* Nonzero if within a function (so symbols should be local, + if nothing says specifically). */ + +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; +}; + +EXTERN struct pending_block *pending_blocks; + + +struct subfile_stack +{ + struct subfile_stack *next; + char *name; +}; + +EXTERN struct subfile_stack *subfile_stack; + +#define next_symbol_text(objfile) (*next_symbol_text_func)(objfile) + +/* Function to invoke get the next symbol. Return the symbol name. */ + +EXTERN char *(*next_symbol_text_func) PARAMS ((struct objfile *)); + +/* Vector of types defined so far, indexed by their type numbers. + Used for both stabs and coff. + (In newer sun systems, dbx uses a pair of numbers in parens, + as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be + translated through the type_translations hash table to get + the index into the type vector.) */ + +EXTERN struct type **type_vector; + +/* Number of elements allocated for type_vector currently. */ + +EXTERN int type_vector_length; + +/* Initial size of type vector. Is realloc'd larger if needed, + and realloc'd down to the size actually used, when completed. */ + +#define INITIAL_TYPE_VECTOR_LENGTH 160 + +extern void +add_symbol_to_list PARAMS ((struct symbol *, struct pending **)); + +extern struct symbol * +find_symbol_in_list PARAMS ((struct pending *, char *, int)); + +extern void +finish_block PARAMS ((struct symbol *, struct pending **, + struct pending_block *, CORE_ADDR, CORE_ADDR, + struct objfile *)); + +extern void +really_free_pendings PARAMS ((int foo)); + +extern void +start_subfile PARAMS ((char *, char *)); + +extern void +patch_subfile_names PARAMS ((struct subfile *subfile, char *name)); + +extern void +push_subfile PARAMS ((void)); + +extern char * +pop_subfile PARAMS ((void)); + +extern struct symtab * +end_symtab PARAMS ((CORE_ADDR, struct objfile *, int)); + +extern void +scan_file_globals PARAMS ((struct objfile *)); + +extern void +buildsym_new_init PARAMS ((void)); + +extern void +buildsym_init PARAMS ((void)); + +extern struct context_stack * +push_context PARAMS ((int, CORE_ADDR)); + +extern void +record_line PARAMS ((struct subfile *, int, CORE_ADDR)); + +extern void +start_symtab PARAMS ((char *, char *, CORE_ADDR)); + +extern int +hashname PARAMS ((char *)); + +#undef EXTERN + +#endif /* defined (BUILDSYM_H) */ diff --git a/contrib/gdb/gdb/c-exp.tab.c b/contrib/gdb/gdb/c-exp.tab.c new file mode 100644 index 000000000000..0c6249b9b75c --- /dev/null +++ b/contrib/gdb/gdb/c-exp.tab.c @@ -0,0 +1,2705 @@ + +/* A Bison parser, made from ./c-exp.y with Bison version GNU Bison version 1.24 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define INT 258 +#define FLOAT 259 +#define STRING 260 +#define NAME 261 +#define TYPENAME 262 +#define NAME_OR_INT 263 +#define STRUCT 264 +#define CLASS 265 +#define UNION 266 +#define ENUM 267 +#define SIZEOF 268 +#define UNSIGNED 269 +#define COLONCOLON 270 +#define TEMPLATE 271 +#define ERROR 272 +#define SIGNED_KEYWORD 273 +#define LONG 274 +#define SHORT 275 +#define INT_KEYWORD 276 +#define CONST_KEYWORD 277 +#define VOLATILE_KEYWORD 278 +#define DOUBLE_KEYWORD 279 +#define VARIABLE 280 +#define ASSIGN_MODIFY 281 +#define THIS 282 +#define ABOVE_COMMA 283 +#define OROR 284 +#define ANDAND 285 +#define EQUAL 286 +#define NOTEQUAL 287 +#define LEQ 288 +#define GEQ 289 +#define LSH 290 +#define RSH 291 +#define UNARY 292 +#define INCREMENT 293 +#define DECREMENT 294 +#define ARROW 295 +#define BLOCKNAME 296 + +#line 38 "./c-exp.y" + + +#include "defs.h" +#include "gdb_string.h" +#include +#include "expression.h" +#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 */ + +/* 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 c_maxdepth +#define yyparse c_parse +#define yylex c_lex +#define yyerror c_error +#define yylval c_lval +#define yychar c_char +#define yydebug c_debug +#define yypact c_pact +#define yyr1 c_r1 +#define yyr2 c_r2 +#define yydef c_def +#define yychk c_chk +#define yypgo c_pgo +#define yyact c_act +#define yyexca c_exca +#define yyerrflag c_errflag +#define yynerrs c_nerrs +#define yyps c_ps +#define yypv c_pv +#define yys c_s +#define yy_yys c_yys +#define yystate c_state +#define yytmp c_tmp +#define yyv c_v +#define yy_yyv c_yyv +#define yyval c_val +#define yylloc c_lloc +#define yyreds c_reds /* With YYDEBUG defined */ +#define yytoks c_toks /* With YYDEBUG defined */ +#define yylhs c_yylhs +#define yylen c_yylen +#define yydefred c_yydefred +#define yydgoto c_yydgoto +#define yysindex c_yysindex +#define yyrindex c_yyrindex +#define yygindex c_yygindex +#define yytable c_yytable +#define yycheck c_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + + +#line 117 "./c-exp.y" +typedef 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 type **tvec; + int *ivec; + } YYSTYPE; +#line 142 "./c-exp.y" + +/* YYSTYPE gets defined by %union */ +static int +parse_number PARAMS ((char *, int, int, YYSTYPE *)); + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 211 +#define YYFLAG -32768 +#define YYNTBASE 66 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 296 ? yytranslate[x] : 88) + +static const char 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, 59, 2, 2, 2, 50, 36, 2, 57, + 62, 48, 46, 28, 47, 55, 49, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 65, 2, 39, + 30, 40, 31, 45, 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, + 56, 2, 61, 35, 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, 63, 34, 64, 60, 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, 21, 22, 23, 24, 25, + 26, 27, 29, 32, 33, 37, 38, 41, 42, 43, + 44, 51, 52, 53, 54, 58 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 2, 4, 6, 8, 12, 15, 18, 21, 24, + 27, 30, 33, 36, 39, 42, 46, 50, 55, 59, + 63, 68, 73, 74, 80, 82, 83, 85, 89, 91, + 95, 100, 105, 109, 113, 117, 121, 125, 129, 133, + 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, + 177, 181, 185, 191, 195, 199, 201, 203, 205, 207, + 209, 214, 216, 218, 220, 224, 228, 232, 237, 239, + 242, 244, 246, 249, 252, 255, 259, 263, 265, 268, + 270, 273, 275, 279, 282, 284, 287, 289, 292, 296, + 299, 303, 305, 309, 311, 313, 315, 317, 320, 324, + 327, 331, 335, 340, 343, 347, 349, 352, 355, 358, + 361, 364, 367, 369, 372, 374, 380, 383, 386, 388, + 390, 392, 394, 396, 400, 402, 404, 406, 408, 410 +}; + +static const short yyrhs[] = { 68, + 0, 67, 0, 82, 0, 69, 0, 68, 28, 69, + 0, 48, 69, 0, 36, 69, 0, 47, 69, 0, + 59, 69, 0, 60, 69, 0, 52, 69, 0, 53, + 69, 0, 69, 52, 0, 69, 53, 0, 13, 69, + 0, 69, 54, 86, 0, 69, 54, 76, 0, 69, + 54, 48, 69, 0, 69, 55, 86, 0, 69, 55, + 76, 0, 69, 55, 48, 69, 0, 69, 56, 68, + 61, 0, 0, 69, 57, 70, 72, 62, 0, 63, + 0, 0, 69, 0, 72, 28, 69, 0, 64, 0, + 71, 72, 73, 0, 71, 82, 73, 69, 0, 57, + 82, 62, 69, 0, 57, 68, 62, 0, 69, 45, + 69, 0, 69, 48, 69, 0, 69, 49, 69, 0, + 69, 50, 69, 0, 69, 46, 69, 0, 69, 47, + 69, 0, 69, 43, 69, 0, 69, 44, 69, 0, + 69, 37, 69, 0, 69, 38, 69, 0, 69, 41, + 69, 0, 69, 42, 69, 0, 69, 39, 69, 0, + 69, 40, 69, 0, 69, 36, 69, 0, 69, 35, + 69, 0, 69, 34, 69, 0, 69, 33, 69, 0, + 69, 32, 69, 0, 69, 31, 69, 65, 69, 0, + 69, 30, 69, 0, 69, 26, 69, 0, 3, 0, + 8, 0, 4, 0, 75, 0, 25, 0, 13, 57, + 82, 62, 0, 5, 0, 27, 0, 58, 0, 74, + 15, 86, 0, 74, 15, 86, 0, 83, 15, 86, + 0, 83, 15, 60, 86, 0, 76, 0, 15, 86, + 0, 87, 0, 83, 0, 83, 22, 0, 83, 23, + 0, 83, 78, 0, 83, 22, 78, 0, 83, 23, + 78, 0, 48, 0, 48, 78, 0, 36, 0, 36, + 78, 0, 79, 0, 57, 78, 62, 0, 79, 80, + 0, 80, 0, 79, 81, 0, 81, 0, 56, 61, + 0, 56, 3, 61, 0, 57, 62, 0, 57, 85, + 62, 0, 77, 0, 83, 15, 48, 0, 7, 0, + 21, 0, 19, 0, 20, 0, 19, 21, 0, 14, + 19, 21, 0, 19, 19, 0, 19, 19, 21, 0, + 14, 19, 19, 0, 14, 19, 19, 21, 0, 20, + 21, 0, 14, 20, 21, 0, 24, 0, 19, 24, + 0, 9, 86, 0, 10, 86, 0, 11, 86, 0, + 12, 86, 0, 14, 84, 0, 14, 0, 18, 84, + 0, 18, 0, 16, 86, 39, 82, 40, 0, 22, + 83, 0, 23, 83, 0, 7, 0, 21, 0, 19, + 0, 20, 0, 82, 0, 85, 28, 82, 0, 6, + 0, 58, 0, 7, 0, 8, 0, 6, 0, 58, + 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 223, 224, 227, 234, 235, 240, 243, 246, 250, 254, + 258, 262, 266, 270, 274, 278, 284, 291, 295, 302, + 310, 314, 318, 322, 328, 332, 335, 339, 343, 346, + 353, 359, 365, 371, 375, 379, 383, 387, 391, 395, + 399, 403, 407, 411, 415, 419, 423, 427, 431, 435, + 439, 443, 447, 451, 455, 461, 468, 479, 486, 489, + 493, 501, 526, 533, 550, 561, 577, 590, 615, 616, + 650, 708, 714, 715, 716, 718, 720, 724, 726, 728, + 730, 732, 735, 737, 742, 749, 751, 755, 757, 761, + 763, 775, 776, 781, 783, 785, 787, 789, 791, 793, + 795, 797, 799, 801, 803, 805, 807, 809, 812, 815, + 818, 821, 823, 825, 827, 829, 836, 837, 840, 841, + 847, 853, 862, 867, 874, 875, 876, 877, 880, 881 +}; + +static const char * const yytname[] = { "$","error","$undefined.","INT","FLOAT", +"STRING","NAME","TYPENAME","NAME_OR_INT","STRUCT","CLASS","UNION","ENUM","SIZEOF", +"UNSIGNED","COLONCOLON","TEMPLATE","ERROR","SIGNED_KEYWORD","LONG","SHORT","INT_KEYWORD", +"CONST_KEYWORD","VOLATILE_KEYWORD","DOUBLE_KEYWORD","VARIABLE","ASSIGN_MODIFY", +"THIS","','","ABOVE_COMMA","'='","'?'","OROR","ANDAND","'|'","'^'","'&'","EQUAL", +"NOTEQUAL","'<'","'>'","LEQ","GEQ","LSH","RSH","'@'","'+'","'-'","'*'","'/'", +"'%'","UNARY","INCREMENT","DECREMENT","ARROW","'.'","'['","'('","BLOCKNAME", +"'!'","'~'","']'","')'","'{'","'}'","':'","start","type_exp","exp1","exp","@1", +"lcurly","arglist","rcurly","block","variable","qualified_name","ptype","abs_decl", +"direct_abs_decl","array_mod","func_mod","type","typebase","typename","nonempty_typelist", +"name","name_not_typename","" +}; +#endif + +static const short yyr1[] = { 0, + 66, 66, 67, 68, 68, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 70, 69, 71, 72, 72, 72, 73, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 74, 74, 75, 76, 76, 75, 75, + 75, 77, 77, 77, 77, 77, 77, 78, 78, 78, + 78, 78, 79, 79, 79, 79, 79, 80, 80, 81, + 81, 82, 82, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, + 84, 84, 85, 85, 86, 86, 86, 86, 87, 87 +}; + +static const short yyr2[] = { 0, + 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 4, 3, 3, + 4, 4, 0, 5, 1, 0, 1, 3, 1, 3, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 3, 3, 1, 1, 1, 1, 1, + 4, 1, 1, 1, 3, 3, 3, 4, 1, 2, + 1, 1, 2, 2, 2, 3, 3, 1, 2, 1, + 2, 1, 3, 2, 1, 2, 1, 2, 3, 2, + 3, 1, 3, 1, 1, 1, 1, 2, 3, 2, + 3, 3, 4, 2, 3, 1, 2, 2, 2, 2, + 2, 2, 1, 2, 1, 5, 2, 2, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 1 +}; + +static const short yydefact[] = { 0, + 56, 58, 62, 129, 94, 57, 0, 0, 0, 0, + 0, 113, 0, 0, 115, 96, 97, 95, 0, 0, + 106, 60, 63, 0, 0, 0, 0, 0, 0, 130, + 0, 0, 25, 2, 1, 4, 26, 0, 59, 69, + 92, 3, 72, 71, 125, 127, 128, 126, 108, 109, + 110, 111, 0, 15, 0, 119, 121, 122, 120, 112, + 70, 0, 121, 122, 114, 100, 98, 107, 104, 117, + 118, 7, 8, 6, 11, 12, 0, 0, 9, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 14, 0, 0, 0, 23, 27, + 0, 0, 0, 0, 73, 74, 80, 78, 0, 0, + 75, 82, 85, 87, 0, 0, 102, 99, 105, 0, + 101, 33, 0, 5, 55, 54, 0, 52, 51, 50, + 49, 48, 42, 43, 46, 47, 44, 45, 40, 41, + 34, 38, 39, 35, 36, 37, 127, 0, 17, 16, + 0, 20, 19, 0, 26, 0, 29, 30, 0, 66, + 93, 0, 67, 76, 77, 81, 79, 0, 88, 90, + 0, 123, 72, 0, 0, 84, 86, 61, 103, 0, + 32, 0, 18, 21, 22, 0, 28, 31, 68, 89, + 83, 0, 0, 91, 116, 53, 24, 124, 0, 0, + 0 +}; + +static const short yydefgoto[] = { 209, + 34, 77, 36, 165, 37, 111, 168, 38, 39, 40, + 41, 121, 122, 123, 124, 182, 55, 60, 184, 173, + 44 +}; + +static const short yypact[] = { 241, +-32768,-32768,-32768,-32768,-32768,-32768, 5, 5, 5, 5, + 302, 24, 5, 5, 73, 66, 27,-32768, 212, 212, +-32768,-32768,-32768, 241, 241, 241, 241, 241, 241, 32, + 241, 241,-32768,-32768, -1, 523, 241, 42,-32768,-32768, +-32768,-32768, 3,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, 241, 43, 52,-32768, 70, 50,-32768,-32768, +-32768, 64,-32768,-32768,-32768, 60,-32768,-32768,-32768,-32768, +-32768, 43, 43, 43, 43, 43, -7, 44, 43, 43, + 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, + 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, + 241, 241, 241,-32768,-32768, 439, 458, 241,-32768, 523, + -18, 41, 5, 8, 16, 16, 16, 16, 4, 382, +-32768, -34,-32768,-32768, 45, 26, 83,-32768,-32768, 212, +-32768,-32768, 241, 523, 523, 523, 487, 575, 599, 622, + 644, 665, 684, 684, 143, 143, 143, 143, 226, 226, + 69, 287, 287, 43, 43, 43, 94, 241,-32768,-32768, + 241,-32768,-32768, -11, 241, 241,-32768,-32768, 241, 95, +-32768, 5,-32768,-32768,-32768,-32768,-32768, 67,-32768,-32768, + 49,-32768, 13, -4, 152,-32768,-32768, 363,-32768, 72, + 43, 241, 43, 43,-32768, 12, 523, 43,-32768,-32768, +-32768, 65, 212,-32768,-32768, 550,-32768,-32768, 127, 129, +-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, 6, 51,-32768,-32768, 14, 53,-32768,-32768, -65, +-32768, 40,-32768, 47, 55, 1, 0, 163,-32768, -5, +-32768 +}; + + +#define YYLAST 741 + + +static const short yytable[] = { 43, + 42, 49, 50, 51, 52, 35, 178, 61, 62, 166, + 45, 46, 47, 45, 46, 47, 81, 114, 70, 71, + 81, 119, 185, 203, 115, 116, 81, 202, 43, 78, + 56, 45, 46, 47, 115, 116, 43, 112, 117, 166, + 159, 162, 57, 58, 59, 167, -64, 69, 117, 195, + 118, 117, 43, 125, 132, 171, 113, 204, 119, 120, + 118, 54, 48, 118, 179, 48, 126, 172, 119, 120, + 129, 119, 120, 207, 72, 73, 74, 75, 76, 56, + 131, 79, 80, 48, 66, 172, 67, 110, 127, 68, + 128, 63, 64, 59, 104, 105, 106, 107, 108, 109, + 160, 163, 130, 189, 167, 133, 188, 170, -94, -65, + 201, 205, 171, 164, 99, 100, 101, 102, 103, 183, + 104, 105, 106, 107, 108, 109, 210, 200, 211, 183, + 190, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 174, 175, 176, 177, 5, 181, + 7, 8, 9, 10, 169, 12, 199, 14, 186, 15, + 16, 17, 18, 19, 20, 21, 187, 65, 196, 0, + 0, 0, 0, 191, 183, 96, 97, 98, 99, 100, + 101, 102, 103, 0, 104, 105, 106, 107, 108, 109, + 0, 0, 183, 208, 0, 0, 0, 0, 193, 0, + 0, 194, 0, 180, 0, 110, 197, 0, 5, 198, + 7, 8, 9, 10, 0, 12, 0, 14, 0, 15, + 16, 17, 18, 19, 20, 21, 0, 0, 191, 0, + 0, 0, 206, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 0, 15, 16, + 17, 18, 19, 20, 21, 22, 0, 23, 0, 0, + 98, 99, 100, 101, 102, 103, 24, 104, 105, 106, + 107, 108, 109, 0, 0, 0, 0, 25, 26, 0, + 0, 0, 27, 28, 0, 0, 0, 29, 30, 31, + 32, 0, 0, 33, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, + 16, 17, 18, 19, 20, 21, 22, 0, 23, 0, + 0, 0, 0, 0, 101, 102, 103, 24, 104, 105, + 106, 107, 108, 109, 0, 0, 0, 0, 25, 26, + 0, 0, 0, 27, 28, 0, 0, 0, 53, 30, + 31, 32, 0, 0, 33, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, + 15, 16, 17, 18, 19, 20, 21, 22, 5, 23, + 7, 8, 9, 10, 0, 12, 0, 14, 0, 15, + 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, + 0, 0, 0, 0, 27, 28, 0, 117, 0, 29, + 30, 31, 32, 0, 0, 33, 0, 0, 0, 118, + 0, 0, 0, 0, 0, 0, 0, 119, 120, 0, + 0, 0, 0, 180, 45, 157, 47, 7, 8, 9, + 10, 0, 12, 0, 14, 0, 15, 16, 17, 18, + 19, 20, 21, 45, 157, 47, 7, 8, 9, 10, + 0, 12, 0, 14, 0, 15, 16, 17, 18, 19, + 20, 21, 0, 0, 0, 0, 158, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, + 0, 0, 82, 0, 0, 48, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 0, 104, 105, + 106, 107, 108, 109, 0, 0, 0, 0, 82, 0, + 0, 192, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 0, 104, 105, 106, 107, 108, 109, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 0, 104, 105, 106, 107, 108, 109, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 0, 104, 105, 106, 107, + 108, 109, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 0, + 104, 105, 106, 107, 108, 109, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 0, 104, 105, 106, 107, 108, 109, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 0, 104, 105, 106, 107, 108, + 109, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 0, 104, 105, 106, 107, + 108, 109, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 0, 104, 105, 106, 107, 108, + 109 +}; + +static const short yycheck[] = { 0, + 0, 7, 8, 9, 10, 0, 3, 13, 14, 28, + 6, 7, 8, 6, 7, 8, 28, 15, 19, 20, + 28, 56, 57, 28, 22, 23, 28, 15, 29, 29, + 7, 6, 7, 8, 22, 23, 37, 37, 36, 28, + 106, 107, 19, 20, 21, 64, 15, 21, 36, 61, + 48, 36, 53, 53, 62, 48, 15, 62, 56, 57, + 48, 11, 58, 48, 61, 58, 15, 60, 56, 57, + 21, 56, 57, 62, 24, 25, 26, 27, 28, 7, + 21, 31, 32, 58, 19, 60, 21, 37, 19, 24, + 21, 19, 20, 21, 52, 53, 54, 55, 56, 57, + 106, 107, 39, 21, 64, 62, 62, 113, 15, 15, + 62, 40, 48, 108, 46, 47, 48, 49, 50, 120, + 52, 53, 54, 55, 56, 57, 0, 61, 0, 130, + 130, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 115, 116, 117, 118, 7, 120, + 9, 10, 11, 12, 112, 14, 172, 16, 122, 18, + 19, 20, 21, 22, 23, 24, 122, 15, 165, -1, + -1, -1, -1, 133, 185, 43, 44, 45, 46, 47, + 48, 49, 50, -1, 52, 53, 54, 55, 56, 57, + -1, -1, 203, 203, -1, -1, -1, -1, 158, -1, + -1, 161, -1, 62, -1, 165, 166, -1, 7, 169, + 9, 10, 11, 12, -1, 14, -1, 16, -1, 18, + 19, 20, 21, 22, 23, 24, -1, -1, 188, -1, + -1, -1, 192, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, + 20, 21, 22, 23, 24, 25, -1, 27, -1, -1, + 45, 46, 47, 48, 49, 50, 36, 52, 53, 54, + 55, 56, 57, -1, -1, -1, -1, 47, 48, -1, + -1, -1, 52, 53, -1, -1, -1, 57, 58, 59, + 60, -1, -1, 63, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, -1, 18, + 19, 20, 21, 22, 23, 24, 25, -1, 27, -1, + -1, -1, -1, -1, 48, 49, 50, 36, 52, 53, + 54, 55, 56, 57, -1, -1, -1, -1, 47, 48, + -1, -1, -1, 52, 53, -1, -1, -1, 57, 58, + 59, 60, -1, -1, 63, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, + 18, 19, 20, 21, 22, 23, 24, 25, 7, 27, + 9, 10, 11, 12, -1, 14, -1, 16, -1, 18, + 19, 20, 21, 22, 23, 24, -1, -1, -1, -1, + -1, -1, -1, -1, 52, 53, -1, 36, -1, 57, + 58, 59, 60, -1, -1, 63, -1, -1, -1, 48, + -1, -1, -1, -1, -1, -1, -1, 56, 57, -1, + -1, -1, -1, 62, 6, 7, 8, 9, 10, 11, + 12, -1, 14, -1, 16, -1, 18, 19, 20, 21, + 22, 23, 24, 6, 7, 8, 9, 10, 11, 12, + -1, 14, -1, 16, -1, 18, 19, 20, 21, 22, + 23, 24, -1, -1, -1, -1, 48, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, + -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, + -1, -1, 26, -1, -1, 58, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, -1, 52, 53, + 54, 55, 56, 57, -1, -1, -1, -1, 26, -1, + -1, 65, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, -1, 52, 53, 54, 55, 56, 57, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + -1, 52, 53, 54, 55, 56, 57, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, -1, 52, 53, 54, 55, + 56, 57, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, -1, + 52, 53, 54, 55, 56, 57, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, -1, 52, 53, 54, 55, 56, 57, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, -1, 52, 53, 54, 55, 56, + 57, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, -1, 52, 53, 54, 55, + 56, 57, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, -1, 52, 53, 54, 55, 56, + 57 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/unsupported/share/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* 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); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (from, to, count) + char *from; + char *to; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *from, char *to, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 192 "/usr/unsupported/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#else +#define YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#endif + +int +yyparse(YYPARSE_PARAM) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to xreallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + 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 - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* 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; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +#line 228 "./c-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tval); + write_exp_elt_opcode(OP_TYPE);; + break;} +case 5: +#line 236 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_COMMA); ; + break;} +case 6: +#line 241 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_IND); ; + break;} +case 7: +#line 244 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); ; + break;} +case 8: +#line 247 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_NEG); ; + break;} +case 9: +#line 251 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); ; + break;} +case 10: +#line 255 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_COMPLEMENT); ; + break;} +case 11: +#line 259 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_PREINCREMENT); ; + break;} +case 12: +#line 263 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_PREDECREMENT); ; + break;} +case 13: +#line 267 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_POSTINCREMENT); ; + break;} +case 14: +#line 271 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_POSTDECREMENT); ; + break;} +case 15: +#line 275 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); ; + break;} +case 16: +#line 279 "./c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_PTR); ; + break;} +case 17: +#line 285 "./c-exp.y" +{ /* 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); ; + break;} +case 18: +#line 292 "./c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_MPTR); ; + break;} +case 19: +#line 296 "./c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); ; + break;} +case 20: +#line 303 "./c-exp.y" +{ /* 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); ; + break;} +case 21: +#line 311 "./c-exp.y" +{ write_exp_elt_opcode (STRUCTOP_MEMBER); ; + break;} +case 22: +#line 315 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_SUBSCRIPT); ; + break;} +case 23: +#line 321 "./c-exp.y" +{ start_arglist (); ; + break;} +case 24: +#line 323 "./c-exp.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); ; + break;} +case 25: +#line 329 "./c-exp.y" +{ start_arglist (); ; + break;} +case 27: +#line 336 "./c-exp.y" +{ arglist_len = 1; ; + break;} +case 28: +#line 340 "./c-exp.y" +{ arglist_len++; ; + break;} +case 29: +#line 344 "./c-exp.y" +{ yyval.lval = end_arglist () - 1; ; + break;} +case 30: +#line 347 "./c-exp.y" +{ write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_ARRAY); ; + break;} +case 31: +#line 354 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); ; + break;} +case 32: +#line 360 "./c-exp.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_CAST); ; + break;} +case 33: +#line 366 "./c-exp.y" +{ ; + break;} +case 34: +#line 372 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); ; + break;} +case 35: +#line 376 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); ; + break;} +case 36: +#line 380 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); ; + break;} +case 37: +#line 384 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_REM); ; + break;} +case 38: +#line 388 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); ; + break;} +case 39: +#line 392 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); ; + break;} +case 40: +#line 396 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_LSH); ; + break;} +case 41: +#line 400 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_RSH); ; + break;} +case 42: +#line 404 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); ; + break;} +case 43: +#line 408 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); ; + break;} +case 44: +#line 412 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); ; + break;} +case 45: +#line 416 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); ; + break;} +case 46: +#line 420 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); ; + break;} +case 47: +#line 424 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); ; + break;} +case 48: +#line 428 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_AND); ; + break;} +case 49: +#line 432 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_XOR); ; + break;} +case 50: +#line 436 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_IOR); ; + break;} +case 51: +#line 440 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); ; + break;} +case 52: +#line 444 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); ; + break;} +case 53: +#line 448 "./c-exp.y" +{ write_exp_elt_opcode (TERNOP_COND); ; + break;} +case 54: +#line 452 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); ; + break;} +case 55: +#line 456 "./c-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode (yyvsp[-1].opcode); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); ; + break;} +case 56: +#line 462 "./c-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val_int.type); + write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val_int.val)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 57: +#line 469 "./c-exp.y" +{ YYSTYPE val; + parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.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); + ; + break;} +case 58: +#line 480 "./c-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (yyvsp[0].typed_val_float.type); + write_exp_elt_dblcst (yyvsp[0].typed_val_float.dval); + write_exp_elt_opcode (OP_DOUBLE); ; + break;} +case 61: +#line 494 "./c-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + CHECK_TYPEDEF (yyvsp[-1].tval); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 62: +#line 502 "./c-exp.y" +{ /* 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 = yyvsp[0].sval.ptr; int count = yyvsp[0].sval.length; + while (count-- > 0) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST)(*sp++)); + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_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) (yyvsp[0].sval.length)); + write_exp_elt_opcode (OP_ARRAY); ; + break;} +case 63: +#line 527 "./c-exp.y" +{ write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); ; + break;} +case 64: +#line 534 "./c-exp.y" +{ + if (yyvsp[0].ssym.sym != 0) + yyval.bval = SYMBOL_BLOCK_VALUE (yyvsp[0].ssym.sym); + else + { + struct symtab *tem = + lookup_symtab (copy_name (yyvsp[0].ssym.stoken)); + if (tem) + yyval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), STATIC_BLOCK); + else + error ("No file or function \"%s\".", + copy_name (yyvsp[0].ssym.stoken)); + } + ; + break;} +case 65: +#line 551 "./c-exp.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + yyval.bval = SYMBOL_BLOCK_VALUE (tem); ; + break;} +case 66: +#line 562 "./c-exp.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + + 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); ; + break;} +case 67: +#line 578 "./c-exp.y" +{ + struct type *type = yyvsp[-2].tval; + 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 (yyvsp[0].sval); + write_exp_elt_opcode (OP_SCOPE); + ; + break;} +case 68: +#line 591 "./c-exp.y" +{ + struct type *type = yyvsp[-3].tval; + 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 (!STREQ (type_name_no_tag (type), yyvsp[0].sval.ptr)) + error ("invalid destructor `%s::~%s'", + type_name_no_tag (type), yyvsp[0].sval.ptr); + + tmp_token.ptr = (char*) alloca (yyvsp[0].sval.length + 2); + tmp_token.length = yyvsp[0].sval.length + 1; + tmp_token.ptr[0] = '~'; + memcpy (tmp_token.ptr+1, yyvsp[0].sval.ptr, yyvsp[0].sval.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); + ; + break;} +case 70: +#line 617 "./c-exp.y" +{ + char *name = copy_name (yyvsp[0].sval); + struct symbol *sym; + struct minimal_symbol *msymbol; + + sym = + lookup_symbol (name, (const struct block *) NULL, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) 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, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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); + ; + break;} +case 71: +#line 651 "./c-exp.y" +{ struct symbol *sym = yyvsp[0].ssym.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 (yyvsp[0].ssym.is_a_field_of_this) + { + /* C++: it hangs off of `this'. 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 (yyvsp[0].ssym.stoken); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name (yyvsp[0].ssym.stoken); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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 (yyvsp[0].ssym.stoken)); + } + ; + break;} +case 75: +#line 717 "./c-exp.y" +{ yyval.tval = follow_types (yyvsp[-1].tval); ; + break;} +case 76: +#line 719 "./c-exp.y" +{ yyval.tval = follow_types (yyvsp[-2].tval); ; + break;} +case 77: +#line 721 "./c-exp.y" +{ yyval.tval = follow_types (yyvsp[-2].tval); ; + break;} +case 78: +#line 725 "./c-exp.y" +{ push_type (tp_pointer); yyval.voidval = 0; ; + break;} +case 79: +#line 727 "./c-exp.y" +{ push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; ; + break;} +case 80: +#line 729 "./c-exp.y" +{ push_type (tp_reference); yyval.voidval = 0; ; + break;} +case 81: +#line 731 "./c-exp.y" +{ push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; ; + break;} +case 83: +#line 736 "./c-exp.y" +{ yyval.voidval = yyvsp[-1].voidval; ; + break;} +case 84: +#line 738 "./c-exp.y" +{ + push_type_int (yyvsp[0].lval); + push_type (tp_array); + ; + break;} +case 85: +#line 743 "./c-exp.y" +{ + push_type_int (yyvsp[0].lval); + push_type (tp_array); + yyval.voidval = 0; + ; + break;} +case 86: +#line 750 "./c-exp.y" +{ push_type (tp_function); ; + break;} +case 87: +#line 752 "./c-exp.y" +{ push_type (tp_function); ; + break;} +case 88: +#line 756 "./c-exp.y" +{ yyval.lval = -1; ; + break;} +case 89: +#line 758 "./c-exp.y" +{ yyval.lval = yyvsp[-1].typed_val_int.val; ; + break;} +case 90: +#line 762 "./c-exp.y" +{ yyval.voidval = 0; ; + break;} +case 91: +#line 764 "./c-exp.y" +{ free ((PTR)yyvsp[-1].tvec); yyval.voidval = 0; ; + break;} +case 93: +#line 777 "./c-exp.y" +{ yyval.tval = lookup_member_type (builtin_type_int, yyvsp[-2].tval); ; + break;} +case 94: +#line 782 "./c-exp.y" +{ yyval.tval = yyvsp[0].tsym.type; ; + break;} +case 95: +#line 784 "./c-exp.y" +{ yyval.tval = builtin_type_int; ; + break;} +case 96: +#line 786 "./c-exp.y" +{ yyval.tval = builtin_type_long; ; + break;} +case 97: +#line 788 "./c-exp.y" +{ yyval.tval = builtin_type_short; ; + break;} +case 98: +#line 790 "./c-exp.y" +{ yyval.tval = builtin_type_long; ; + break;} +case 99: +#line 792 "./c-exp.y" +{ yyval.tval = builtin_type_unsigned_long; ; + break;} +case 100: +#line 794 "./c-exp.y" +{ yyval.tval = builtin_type_long_long; ; + break;} +case 101: +#line 796 "./c-exp.y" +{ yyval.tval = builtin_type_long_long; ; + break;} +case 102: +#line 798 "./c-exp.y" +{ yyval.tval = builtin_type_unsigned_long_long; ; + break;} +case 103: +#line 800 "./c-exp.y" +{ yyval.tval = builtin_type_unsigned_long_long; ; + break;} +case 104: +#line 802 "./c-exp.y" +{ yyval.tval = builtin_type_short; ; + break;} +case 105: +#line 804 "./c-exp.y" +{ yyval.tval = builtin_type_unsigned_short; ; + break;} +case 106: +#line 806 "./c-exp.y" +{ yyval.tval = builtin_type_double; ; + break;} +case 107: +#line 808 "./c-exp.y" +{ yyval.tval = builtin_type_long_double; ; + break;} +case 108: +#line 810 "./c-exp.y" +{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 109: +#line 813 "./c-exp.y" +{ yyval.tval = lookup_struct (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 110: +#line 816 "./c-exp.y" +{ yyval.tval = lookup_union (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 111: +#line 819 "./c-exp.y" +{ yyval.tval = lookup_enum (copy_name (yyvsp[0].sval), + expression_context_block); ; + break;} +case 112: +#line 822 "./c-exp.y" +{ yyval.tval = lookup_unsigned_typename (TYPE_NAME(yyvsp[0].tsym.type)); ; + break;} +case 113: +#line 824 "./c-exp.y" +{ yyval.tval = builtin_type_unsigned_int; ; + break;} +case 114: +#line 826 "./c-exp.y" +{ yyval.tval = lookup_signed_typename (TYPE_NAME(yyvsp[0].tsym.type)); ; + break;} +case 115: +#line 828 "./c-exp.y" +{ yyval.tval = builtin_type_int; ; + break;} +case 116: +#line 830 "./c-exp.y" +{ yyval.tval = lookup_template_type(copy_name(yyvsp[-3].sval), yyvsp[-1].tval, + expression_context_block); + ; + break;} +case 117: +#line 836 "./c-exp.y" +{ yyval.tval = yyvsp[0].tval; ; + break;} +case 118: +#line 837 "./c-exp.y" +{ yyval.tval = yyvsp[0].tval; ; + break;} +case 120: +#line 842 "./c-exp.y" +{ + yyval.tsym.stoken.ptr = "int"; + yyval.tsym.stoken.length = 3; + yyval.tsym.type = builtin_type_int; + ; + break;} +case 121: +#line 848 "./c-exp.y" +{ + yyval.tsym.stoken.ptr = "long"; + yyval.tsym.stoken.length = 4; + yyval.tsym.type = builtin_type_long; + ; + break;} +case 122: +#line 854 "./c-exp.y" +{ + yyval.tsym.stoken.ptr = "short"; + yyval.tsym.stoken.length = 5; + yyval.tsym.type = builtin_type_short; + ; + break;} +case 123: +#line 863 "./c-exp.y" +{ yyval.tvec = (struct type **) xmalloc (sizeof (struct type *) * 2); + yyval.ivec[0] = 1; /* Number of types in vector */ + yyval.tvec[1] = yyvsp[0].tval; + ; + break;} +case 124: +#line 868 "./c-exp.y" +{ int len = sizeof (struct type *) * (++(yyvsp[-2].ivec[0]) + 1); + yyval.tvec = (struct type **) xrealloc ((char *) yyvsp[-2].tvec, len); + yyval.tvec[yyval.ivec[0]] = yyvsp[0].tval; + ; + break;} +case 125: +#line 874 "./c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 126: +#line 875 "./c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 127: +#line 876 "./c-exp.y" +{ yyval.sval = yyvsp[0].tsym.stoken; ; + break;} +case 128: +#line 877 "./c-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 487 "/usr/unsupported/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) xmalloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 891 "./c-exp.y" + + +/* 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) + register char *p; + register 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. */ + register LONGEST n = 0; + register LONGEST prevn = 0; + unsigned LONGEST un; + + register int i = 0; + register int c; + register 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) + { + char c; + + /* It's a float since it contains a point or an exponent. */ + + if (sizeof (putithere->typed_val_float.dval) <= sizeof (float)) + sscanf (p, "%g", &putithere->typed_val_float.dval); + else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double)) + sscanf (p, "%lg", &putithere->typed_val_float.dval); + else + { +#ifdef PRINTF_HAS_LONG_DOUBLE + sscanf (p, "%Lg", &putithere->typed_val_float.dval); +#else + /* Scan it into a double, then assign it to the long double. + This at least wins with values representable in the range + of doubles. */ + double temp; + sscanf (p, "%lg", &temp); + putithere->typed_val_float.dval = temp; +#endif + } + + /* See if it has `f' or `l' suffix (float or long double). */ + + c = tolower (p[len - 1]); + + if (c == 'f') + putithere->typed_val_float.type = builtin_type_float; + else if (c == 'l') + putithere->typed_val_float.type = builtin_type_long_double; + else if (isdigit (c) || c == '.') + putithere->typed_val_float.type = builtin_type_double; + else + return ERROR; + + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 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 TARGET_INT_BIT + or TARGET_LONG_BIT 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 >> (TARGET_INT_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-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 = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + else if (long_p <= 1 + && (un >> (TARGET_LONG_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = (((unsigned LONGEST)1) + << (TARGET_LONG_LONG_BIT - 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 = builtin_type_unsigned_long_long; + signed_type = builtin_type_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 () +{ + int c; + 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 (STREQN (tokstart, tokentab3[i].operator, 3)) + { + 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 (STREQN (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *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 (&lexptr); + else if (c == '\'') + error ("Empty character constant."); + + yylval.typed_val_int.val = c; + yylval.typed_val_int.type = builtin_type_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 c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + 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; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + 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 && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + /* This test does not include !hex, because a '.' always indicates + a decimal floating point number regardless of the radix. */ + else if (!got_dot && *p == '.') + 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; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + 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 '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + 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 *) xrealloc (tempbuf, tempbufsize += 64); + } + switch (*tokptr) + { + case '\0': + case '"': + /* Do nothing, loop will terminate. */ + break; + case '\\': + tokptr++; + c = parse_escape (&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 (STRING); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= '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 (STREQN (tokstart, "unsigned", 8)) + return UNSIGNED; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "template", 8)) + return TEMPLATE; + if (STREQN (tokstart, "volatile", 8)) + return VOLATILE_KEYWORD; + break; + case 6: + if (STREQN (tokstart, "struct", 6)) + return STRUCT; + if (STREQN (tokstart, "signed", 6)) + return SIGNED_KEYWORD; + if (STREQN (tokstart, "sizeof", 6)) + return SIZEOF; + if (STREQN (tokstart, "double", 6)) + return DOUBLE_KEYWORD; + break; + case 5: + if (current_language->la_language == language_cplus + && STREQN (tokstart, "class", 5)) + return CLASS; + if (STREQN (tokstart, "union", 5)) + return UNION; + if (STREQN (tokstart, "short", 5)) + return SHORT; + if (STREQN (tokstart, "const", 5)) + return CONST_KEYWORD; + break; + case 4: + if (STREQN (tokstart, "enum", 4)) + return ENUM; + if (STREQN (tokstart, "long", 4)) + return LONG; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL)) + return THIS; + } + break; + case 3: + if (STREQN (tokstart, "int", 3)) + 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; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL, + (struct symtab **) NULL); + /* Call lookup_symtab, not lookup_partial_symtab, in case there are + no psymtabs (coff, xcoff, or some future change to blow away the + psymtabs once once symbols are read). */ + 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_NAMESPACE, (int *) NULL, + (struct symtab **) 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; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* 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; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/c-exp.y b/contrib/gdb/gdb/c-exp.y new file mode 100644 index 000000000000..f1156e65a10f --- /dev/null +++ b/contrib/gdb/gdb/c-exp.y @@ -0,0 +1,1641 @@ +/* YACC parser for C expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* 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 "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 */ + +/* 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 c_maxdepth +#define yyparse c_parse +#define yylex c_lex +#define yyerror c_error +#define yylval c_lval +#define yychar c_char +#define yydebug c_debug +#define yypact c_pact +#define yyr1 c_r1 +#define yyr2 c_r2 +#define yydef c_def +#define yychk c_chk +#define yypgo c_pgo +#define yyact c_act +#define yyexca c_exca +#define yyerrflag c_errflag +#define yynerrs c_nerrs +#define yyps c_ps +#define yypv c_pv +#define yys c_s +#define yy_yys c_yys +#define yystate c_state +#define yytmp c_tmp +#define yyv c_v +#define yy_yyv c_yyv +#define yyval c_val +#define yylloc c_lloc +#define yyreds c_reds /* With YYDEBUG defined */ +#define yytoks c_toks /* With YYDEBUG defined */ +#define yylhs c_yylhs +#define yylen c_yylen +#define yydefred c_yydefred +#define yydgoto c_yydgoto +#define yysindex c_yysindex +#define yyrindex c_yyrindex +#define yygindex c_yygindex +#define yytable c_yytable +#define yycheck c_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((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 type **tvec; + int *ivec; + } + +%{ +/* YYSTYPE gets defined by %union */ +static int +parse_number PARAMS ((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 NAME /* BLOCKNAME defined below to give it higher precedence. */ +%token TYPENAME +%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 + +/* C++ */ +%token THIS + +%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); } + ; + +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 : SIZEOF '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_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 (builtin_type_char); + write_exp_elt_longcst ((LONGEST)(*sp++)); + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_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); } + ; + +/* C++. */ +exp : THIS + { write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } + ; + +/* end of C++. */ + +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_NAMESPACE, (int *) NULL, + (struct symtab **) 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_NAMESPACE, (int *) NULL, + (struct symtab **) 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 (!STREQ (type_name_no_tag (type), $4.ptr)) + 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_NAMESPACE, (int *) NULL, + (struct symtab **) 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, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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++: it hangs off of `this'. 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; + register char *arg = copy_name ($1.stoken); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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 ((PTR)$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 COLONCOLON '*' + { $$ = lookup_member_type (builtin_type_int, $1); } + ; + +typebase /* Implements (approximately): (type-qualifier)* type-specifier */ + : TYPENAME + { $$ = $1.type; } + | INT_KEYWORD + { $$ = builtin_type_int; } + | LONG + { $$ = builtin_type_long; } + | SHORT + { $$ = builtin_type_short; } + | LONG INT_KEYWORD + { $$ = builtin_type_long; } + | UNSIGNED LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long; } + | LONG LONG + { $$ = builtin_type_long_long; } + | LONG LONG INT_KEYWORD + { $$ = builtin_type_long_long; } + | UNSIGNED LONG LONG + { $$ = builtin_type_unsigned_long_long; } + | UNSIGNED LONG LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long_long; } + | SHORT INT_KEYWORD + { $$ = builtin_type_short; } + | UNSIGNED SHORT INT_KEYWORD + { $$ = builtin_type_unsigned_short; } + | DOUBLE_KEYWORD + { $$ = builtin_type_double; } + | LONG DOUBLE_KEYWORD + { $$ = builtin_type_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 (TYPE_NAME($2.type)); } + | UNSIGNED + { $$ = builtin_type_unsigned_int; } + | SIGNED_KEYWORD typename + { $$ = lookup_signed_typename (TYPE_NAME($2.type)); } + | SIGNED_KEYWORD + { $$ = builtin_type_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 = builtin_type_int; + } + | LONG + { + $$.stoken.ptr = "long"; + $$.stoken.length = 4; + $$.type = builtin_type_long; + } + | SHORT + { + $$.stoken.ptr = "short"; + $$.stoken.length = 5; + $$.type = builtin_type_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; } + | 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) + register char *p; + register 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. */ + register LONGEST n = 0; + register LONGEST prevn = 0; + unsigned LONGEST un; + + register int i = 0; + register int c; + register 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) + { + char c; + + /* It's a float since it contains a point or an exponent. */ + + if (sizeof (putithere->typed_val_float.dval) <= sizeof (float)) + sscanf (p, "%g", &putithere->typed_val_float.dval); + else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double)) + sscanf (p, "%lg", &putithere->typed_val_float.dval); + else + { +#ifdef PRINTF_HAS_LONG_DOUBLE + sscanf (p, "%Lg", &putithere->typed_val_float.dval); +#else + /* Scan it into a double, then assign it to the long double. + This at least wins with values representable in the range + of doubles. */ + double temp; + sscanf (p, "%lg", &temp); + putithere->typed_val_float.dval = temp; +#endif + } + + /* See if it has `f' or `l' suffix (float or long double). */ + + c = tolower (p[len - 1]); + + if (c == 'f') + putithere->typed_val_float.type = builtin_type_float; + else if (c == 'l') + putithere->typed_val_float.type = builtin_type_long_double; + else if (isdigit (c) || c == '.') + putithere->typed_val_float.type = builtin_type_double; + else + return ERROR; + + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 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 TARGET_INT_BIT + or TARGET_LONG_BIT 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 >> (TARGET_INT_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-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 = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + else if (long_p <= 1 + && (un >> (TARGET_LONG_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = (((unsigned LONGEST)1) + << (TARGET_LONG_LONG_BIT - 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 = builtin_type_unsigned_long_long; + signed_type = builtin_type_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 () +{ + int c; + 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 (STREQN (tokstart, tokentab3[i].operator, 3)) + { + 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 (STREQN (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *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 (&lexptr); + else if (c == '\'') + error ("Empty character constant."); + + yylval.typed_val_int.val = c; + yylval.typed_val_int.type = builtin_type_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 c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + 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; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + 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 && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + /* This test does not include !hex, because a '.' always indicates + a decimal floating point number regardless of the radix. */ + else if (!got_dot && *p == '.') + 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; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + 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 '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + + 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 (&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 (STRING); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= '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 (STREQN (tokstart, "unsigned", 8)) + return UNSIGNED; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "template", 8)) + return TEMPLATE; + if (STREQN (tokstart, "volatile", 8)) + return VOLATILE_KEYWORD; + break; + case 6: + if (STREQN (tokstart, "struct", 6)) + return STRUCT; + if (STREQN (tokstart, "signed", 6)) + return SIGNED_KEYWORD; + if (STREQN (tokstart, "sizeof", 6)) + return SIZEOF; + if (STREQN (tokstart, "double", 6)) + return DOUBLE_KEYWORD; + break; + case 5: + if (current_language->la_language == language_cplus + && STREQN (tokstart, "class", 5)) + return CLASS; + if (STREQN (tokstart, "union", 5)) + return UNION; + if (STREQN (tokstart, "short", 5)) + return SHORT; + if (STREQN (tokstart, "const", 5)) + return CONST_KEYWORD; + break; + case 4: + if (STREQN (tokstart, "enum", 4)) + return ENUM; + if (STREQN (tokstart, "long", 4)) + return LONG; + if (current_language->la_language == language_cplus + && STREQN (tokstart, "this", 4)) + { + static const char this_name[] = + { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' }; + + if (lookup_symbol (this_name, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL)) + return THIS; + } + break; + case 3: + if (STREQN (tokstart, "int", 3)) + 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; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : (int *) NULL, + (struct symtab **) NULL); + /* Call lookup_symtab, not lookup_partial_symtab, in case there are + no psymtabs (coff, xcoff, or some future change to blow away the + psymtabs once once symbols are read). */ + 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_NAMESPACE, (int *) NULL, + (struct symtab **) 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; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* 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; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/c-lang.c b/contrib/gdb/gdb/c-lang.c new file mode 100644 index 000000000000..66ee3e1f9795 --- /dev/null +++ b/contrib/gdb/gdb/c-lang.c @@ -0,0 +1,478 @@ +/* C language support routines for GDB, the GNU debugger. + Copyright 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "c-lang.h" + +/* 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 +emit_char (c, stream, quoter) + register int c; + GDB_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; + } + } +} + +void +c_printchar (c, stream) + int c; + GDB_FILE *stream; +{ + fputs_filtered ("'", stream); + emit_char (c, 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. */ + +void +c_printstr (stream, string, length, force_ellipses) + GDB_FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + extern int inspect_it; + extern int repeat_count_threshold; + extern int print_max; + + /* 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 < 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 > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\", ", stream); + else + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + c_printchar (string[i], stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + in_quotes = 1; + } + emit_char (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* Create a fundamental C type using default reasonable for the current + target machine. + + Some object/debugging file formats (DWARF version 1, COFF, etc) do not + define fundamental types such as "int" or "double". Others (stabs or + DWARF version 2, etc) do define fundamental types. For the formats which + don't provide fundamental types, gdb can create such types using this + function. + + FIXME: Some compilers distinguish explicitly signed integral types + (signed short, signed int, signed long) from "regular" integral types + (short, int, long) in the debugging information. There is some dis- + agreement as to how useful this feature is. In particular, gcc does + not support this. Also, only some debugging formats allow the + distinction to be passed on to a debugger. For now, we always just + use "short", "int", or "long" as the type name, for both the implicit + and explicitly signed types. This also makes life easier for the + gdb test suite since we don't have to account for the differences + in output depending upon what the compiler and debugging format + support. We will probably have to re-examine the issue when gdb + starts taking it's fundamental type information directly from the + debugging information supplied by the compiler. fnf@cygnus.com */ + +struct type * +c_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "", objfile); + warning ("internal error: no C/C++ fundamental type %d", typeid); + break; + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "void", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "char", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "signed char", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned char", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); /* FIXME-fnf */ + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long long", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "signed long long", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "float", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "double", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long double", objfile); + break; + } + return (type); +} + + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +const struct op_print c_op_print_tab[] = + { + {",", BINOP_COMMA, PREC_COMMA, 0}, + {"=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0}, + {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0}, + {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0}, + {"==", BINOP_EQUAL, PREC_EQUAL, 0}, + {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {">>", BINOP_RSH, PREC_SHIFT, 0}, + {"<<", BINOP_LSH, PREC_SHIFT, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"%", BINOP_REM, PREC_MUL, 0}, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0}, + {"*", UNOP_IND, PREC_PREFIX, 0}, + {"&", UNOP_ADDR, PREC_PREFIX, 0}, + {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0}, + {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, + {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}, + /* C++ */ + {"::", BINOP_SCOPE, PREC_PREFIX, 0}, + {NULL, 0, 0, 0} +}; + +struct type ** const (c_builtin_types[]) = +{ + &builtin_type_int, + &builtin_type_long, + &builtin_type_short, + &builtin_type_char, + &builtin_type_float, + &builtin_type_double, + &builtin_type_void, + &builtin_type_long_long, + &builtin_type_signed_char, + &builtin_type_unsigned_char, + &builtin_type_unsigned_short, + &builtin_type_unsigned_int, + &builtin_type_unsigned_long, + &builtin_type_unsigned_long_long, + &builtin_type_long_double, + &builtin_type_complex, + &builtin_type_double_complex, + 0 +}; + +const struct language_defn c_language_defn = { + "c", /* Language name */ + language_c, + c_builtin_types, + range_check_off, + type_check_off, + c_parse, + c_error, + evaluate_subexp_standard, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_create_fundamental_type, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + c_val_print, /* Print a value using appropriate syntax */ + c_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + c_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +const struct language_defn cplus_language_defn = { + "c++", /* Language name */ + language_cplus, + c_builtin_types, + range_check_off, + type_check_off, + c_parse, + c_error, + evaluate_subexp_standard, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_create_fundamental_type, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + c_val_print, /* Print a value using appropriate syntax */ + c_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + c_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +const struct language_defn asm_language_defn = { + "asm", /* Language name */ + language_asm, + c_builtin_types, + range_check_off, + type_check_off, + c_parse, + c_error, + evaluate_subexp_standard, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + c_create_fundamental_type, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + c_val_print, /* Print a value using appropriate syntax */ + c_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + c_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +void +_initialize_c_language () +{ + add_language (&c_language_defn); + add_language (&cplus_language_defn); + add_language (&asm_language_defn); +} diff --git a/contrib/gdb/gdb/c-lang.h b/contrib/gdb/gdb/c-lang.h new file mode 100644 index 000000000000..fbd8b69e95f2 --- /dev/null +++ b/contrib/gdb/gdb/c-lang.h @@ -0,0 +1,84 @@ +/* C language support definitions for GDB, the GNU debugger. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __STDC__ /* Forward decls for prototypes */ +struct value; +#endif + +extern int +c_parse PARAMS ((void)); /* Defined in c-exp.y */ + +extern void +c_error PARAMS ((char *)); /* Defined in c-exp.y */ + +extern void /* Defined in c-typeprint.c */ +c_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int)); + +extern int +c_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int, + int, enum val_prettyprint)); + +extern int +c_value_print PARAMS ((struct value *, GDB_FILE *, int, enum val_prettyprint)); + +/* These are in c-lang.c: */ + +extern void c_printchar PARAMS ((int, GDB_FILE*)); + +extern void c_printstr PARAMS ((GDB_FILE *, char *, unsigned int, int)); + +extern struct type * c_create_fundamental_type PARAMS ((struct objfile*, int)); + +extern struct type ** const (c_builtin_types[]); + +/* These are in c-typeprint.c: */ + +extern void +c_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int)); + +extern void +c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int)); + +extern void +cp_type_print_method_args PARAMS ((struct type **, char *, char *, int, + GDB_FILE *)); +/* These are in cp-valprint.c */ + +extern void +cp_type_print_method_args PARAMS ((struct type **, char *, char *, int, + GDB_FILE *)); + +extern int vtblprint; /* Controls printing of vtbl's */ + +extern void +cp_print_class_member PARAMS ((char *, struct type *, GDB_FILE *, char *)); + +extern void +cp_print_class_method PARAMS ((char *, struct type *, GDB_FILE *)); + +extern void +cp_print_value_fields PARAMS ((struct type *, char *, CORE_ADDR, + GDB_FILE *, int, int, enum val_prettyprint, + struct type**, int)); + +extern int +cp_is_vtbl_ptr_type PARAMS ((struct type *)); + +extern int +cp_is_vtbl_member PARAMS ((struct type *)); diff --git a/contrib/gdb/gdb/c-typeprint.c b/contrib/gdb/gdb/c-typeprint.c new file mode 100644 index 000000000000..a7a5341c1772 --- /dev/null +++ b/contrib/gdb/gdb/c-typeprint.c @@ -0,0 +1,831 @@ +/* Support for printing C and C++ types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "c-lang.h" +#include "typeprint.h" + +#include "gdb_string.h" +#include +#include + +static void +c_type_print_args PARAMS ((struct type *, GDB_FILE *)); + +static void +c_type_print_varspec_suffix PARAMS ((struct type *, GDB_FILE *, int, int, int)); + +static void +cp_type_print_derivation_info PARAMS ((GDB_FILE *, struct type *)); + +void +c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int)); + + +/* Print a description of a type in the format of a + typedef for the current language. + NEW is the new name for a type TYPE. */ + +void +c_typedef_print (type, new, stream) + struct type *type; + struct symbol *new; + GDB_FILE *stream; +{ + CHECK_TYPEDEF (type); + switch (current_language->la_language) + { +#ifdef _LANG_c + case language_c: + case language_cplus: + fprintf_filtered(stream, "typedef "); + type_print(type,"",stream,0); + if(TYPE_NAME ((SYMBOL_TYPE (new))) == 0 + || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new))) + fprintf_filtered(stream, " %s", SYMBOL_SOURCE_NAME(new)); + break; +#endif +#ifdef _LANG_m2 + case language_m2: + fprintf_filtered(stream, "TYPE "); + if(!TYPE_NAME(SYMBOL_TYPE(new)) || + !STREQ (TYPE_NAME(SYMBOL_TYPE(new)), SYMBOL_NAME(new))) + fprintf_filtered(stream, "%s = ", SYMBOL_SOURCE_NAME(new)); + else + fprintf_filtered(stream, " = "); + type_print(type,"",stream,0); + break; +#endif +#ifdef _LANG_chill + case language_chill: + fprintf_filtered(stream, "SYNMODE "); + if(!TYPE_NAME(SYMBOL_TYPE(new)) || + !STREQ (TYPE_NAME(SYMBOL_TYPE(new)), SYMBOL_NAME(new))) + fprintf_filtered(stream, "%s = ", SYMBOL_SOURCE_NAME(new)); + else + fprintf_filtered(stream, " = "); + type_print(type,"",stream,0); + break; +#endif + default: + error("Language not supported."); + } + fprintf_filtered(stream, ";\n"); +} + + +/* LEVEL is the depth to indent lines by. */ + +void +c_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + GDB_FILE *stream; + int show; + int level; +{ + register enum type_code code; + int demangled_args; + + 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_MEMBER + || code == TYPE_CODE_REF))) + fputs_filtered (" ", stream); + c_type_print_varspec_prefix (type, stream, show, 0); + + fputs_filtered (varstring, stream); + + /* 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); + +} + +/* Print the C++ method arguments ARGS to the file STREAM. */ + +void +cp_type_print_method_args (args, prefix, varstring, staticp, stream) + struct type **args; + char *prefix; + char *varstring; + int staticp; + GDB_FILE *stream; +{ + int i; + + fprintf_symbol_filtered (stream, prefix, language_cplus, DMGL_ANSI); + fprintf_symbol_filtered (stream, varstring, language_cplus, DMGL_ANSI); + fputs_filtered (" (", stream); + if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID) + { + i = !staticp; /* skip the class variable */ + while (1) + { + type_print (args[i++], "", stream, 0); + if (!args[i]) + { + fprintf_filtered (stream, " ..."); + break; + } + else if (args[i]->code != TYPE_CODE_VOID) + { + fprintf_filtered (stream, ", "); + } + else break; + } + } + fprintf_filtered (stream, ")"); +} + +/* If TYPE is a derived type, then print out derivation information. + Print only the actual base classes of this type, not the base classes + of the base classes. I.E. for the derivation hierarchy: + + class A { int a; }; + class B : public A {int b; }; + class C : public B {int c; }; + + Print the type of class C as: + + class C : public B { + int c; + } + + Not as the following (like gdb used to), which is not legal C++ syntax for + derived types and may be confused with the multiple inheritance form: + + class C : public B : public A { + int c; + } + + In general, gdb should try to print the types as closely as possible to + the form that they appear in the source code. */ + +static void +cp_type_print_derivation_info (stream, type) + GDB_FILE *stream; + struct type *type; +{ + char *name; + int i; + + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + fputs_filtered (i == 0 ? ": " : ", ", stream); + fprintf_filtered (stream, "%s%s ", + BASETYPE_VIA_PUBLIC (type, i) ? "public" : "private", + BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : ""); + name = type_name_no_tag (TYPE_BASECLASS (type, i)); + fprintf_filtered (stream, "%s", name ? name : "(null)"); + } + if (i > 0) + { + fputs_filtered (" ", stream); + } +} + +/* Print any asterisks or open-parentheses needed before the + variable name (to describe its type). + + On outermost call, pass 0 for PASSED_A_PTR. + On outermost call, SHOW > 0 means should ignore + any typename for TYPE and show its details. + SHOW is always zero on recursive calls. */ + +void +c_type_print_varspec_prefix (type, stream, show, passed_a_ptr) + struct type *type; + GDB_FILE *stream; + int show; + int passed_a_ptr; +{ + char *name; + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fprintf_filtered (stream, "*"); + break; + + case TYPE_CODE_MEMBER: + if (passed_a_ptr) + fprintf_filtered (stream, "("); + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + fprintf_filtered (stream, " "); + name = type_name_no_tag (TYPE_DOMAIN_TYPE (type)); + if (name) + fputs_filtered (name, stream); + else + c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr); + fprintf_filtered (stream, "::"); + break; + + case TYPE_CODE_METHOD: + if (passed_a_ptr) + fprintf_unfiltered (stream, "("); + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + { + fprintf_filtered (stream, " "); + c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr); + fprintf_filtered (stream, "::"); + } + break; + + case TYPE_CODE_REF: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fprintf_filtered (stream, "&"); + break; + + case TYPE_CODE_FUNC: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf_filtered (stream, "("); + break; + + case TYPE_CODE_ARRAY: + c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf_filtered (stream, "("); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + 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 + gcc -Wall will reveal any types that haven't been handled. */ + break; + } +} + +static void +c_type_print_args (type, stream) + struct type *type; + GDB_FILE *stream; +{ + int i; + struct type **args; + + fprintf_filtered (stream, "("); + args = TYPE_ARG_TYPES (type); + if (args != NULL) + { + if (args[1] == NULL) + { + fprintf_filtered (stream, "..."); + } + else + { + for (i = 1; + args[i] != NULL && args[i]->code != TYPE_CODE_VOID; + i++) + { + c_print_type (args[i], "", stream, -1, 0); + if (args[i+1] == NULL) + { + fprintf_filtered (stream, "..."); + } + else if (args[i+1]->code != TYPE_CODE_VOID) + { + fprintf_filtered (stream, ","); + wrap_here (" "); + } + } + } + } + fprintf_filtered (stream, ")"); +} + +/* Print any array sizes, function arguments or close parentheses + needed after the variable name (to describe its type). + Args work like c_type_print_varspec_prefix. */ + +static void +c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args) + struct type *type; + GDB_FILE *stream; + int show; + int passed_a_ptr; + int demangled_args; +{ + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + + fprintf_filtered (stream, "["); + if (TYPE_LENGTH (type) >= 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 + && TYPE_ARRAY_UPPER_BOUND_TYPE(type) != BOUND_CANNOT_BE_DETERMINED) + fprintf_filtered (stream, "%d", + (TYPE_LENGTH (type) + / TYPE_LENGTH (TYPE_TARGET_TYPE (type)))); + fprintf_filtered (stream, "]"); + + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + break; + + case TYPE_CODE_MEMBER: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + break; + + case TYPE_CODE_METHOD: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + if (passed_a_ptr) + { + c_type_print_args (type, stream); + } + break; + + case TYPE_CODE_PTR: + case TYPE_CODE_REF: + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0); + break; + + case TYPE_CODE_FUNC: + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + if (!demangled_args) + { int i, len = TYPE_NFIELDS (type); + fprintf_filtered (stream, "("); + for (i = 0; i < len; i++) + { + if (i > 0) + { + fputs_filtered (", ", stream); + wrap_here (" "); + } + c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); + } + fprintf_filtered (stream, ")"); + } + c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr, 0); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + 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 + gcc -Wall will report types that may not have been considered. */ + break; + } +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element), or the description of a + structure or union. + + SHOW positive means print details about the type (e.g. enum values), + and print structure elements passing SHOW - 1 for show. + SHOW negative means just print the type name or struct tag if there is one. + If there is no name, print something sensible but concise like + "struct {...}". + SHOW zero means just print the type name or struct tag if there is one. + If there is no name, print something sensible but not as concise like + "struct {int x; int y;}". + + LEVEL is the number of spaces to indent by. + We increase it for some recursive calls. */ + +void +c_type_print_base (type, stream, show, level) + struct type *type; + GDB_FILE *stream; + int show; + int level; +{ + register int i; + register int len; + register int lastval; + char *mangled_name; + char *demangled_name; + enum {s_none, s_public, s_private, s_protected} section_type; + QUIT; + + wrap_here (" "); + if (type == NULL) + { + fputs_filtered ("", stream); + return; + } + + /* When SHOW is zero or less, and there is a valid type name, then always + just print the type name directly from the type. */ + /* If we have "typedef struct foo {. . .} bar;" do we want to print it + as "struct foo" or as "bar"? Pick the latter, because C++ folk tend + to expect things like "class5 *foo" rather than "struct class5 *foo". */ + + if (show <= 0 + && TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + return; + } + + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_TYPEDEF: + case TYPE_CODE_ARRAY: + case TYPE_CODE_PTR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_REF: + case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: + c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_STRUCT: + if (HAVE_CPLUS_STRUCT (type)) + { + fprintf_filtered (stream, "class "); + } + else + { + fprintf_filtered (stream, "struct "); + } + goto struct_union; + + case TYPE_CODE_UNION: + fprintf_filtered (stream, "union "); + + struct_union: + if (TYPE_TAG_NAME (type) != NULL) + { + 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) + { + cp_type_print_derivation_info (stream, type); + + fprintf_filtered (stream, "{\n"); + if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0)) + { + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + 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; + + /* If there is a base class for this type, + do not print the field that it occupies. */ + + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; + /* Don't print out virtual function table. */ + if (STREQN (TYPE_FIELD_NAME (type, i), "_vptr", 5) + && is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5])) + continue; + + /* If this is a C++ class we can print the various C++ section + labels. */ + + if (HAVE_CPLUS_STRUCT (type)) + { + 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 (TYPE_FIELD_STATIC (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 (!TYPE_FIELD_STATIC (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 space between. */ + len = TYPE_NFN_FIELDS (type); + if (len && section_type != s_none) + fprintf_filtered (stream, "\n"); + + /* C++: print out the methods */ + + for (i = 0; i < len; i++) + { + 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); + int is_constructor = name && STREQ(method_name, name); + for (j = 0; j < len2; j++) + { + char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); + int is_full_physname_constructor = + ((physname[0]=='_' && physname[1]=='_' && + (isdigit(physname[2]) + || physname[2]=='Q' + || physname[2]=='t')) + || (strncmp(physname, "__ct__", 6) == 0)); + + QUIT; + if (TYPE_FN_FIELD_PROTECTED (f, j)) + { + if (section_type != s_protected) + { + section_type = s_protected; + fprintfi_filtered (level + 2, stream, + "protected:\n"); + } + } + else if (TYPE_FN_FIELD_PRIVATE (f, j)) + { + 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 (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + fprintf_filtered (stream, "virtual "); + else if (TYPE_FN_FIELD_STATIC_P (f, j)) + fprintf_filtered (stream, "static "); + if (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)) == 0) + { + /* Keep GDB from crashing here. */ + fprintf_unfiltered (stream, " %s;\n", + TYPE_FN_FIELD_PHYSNAME (f, j)); + break; + } + else if (!is_constructor && !is_full_physname_constructor) + { + type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), + "", stream, -1); + fputs_filtered (" ", stream); + } + if (TYPE_FN_FIELD_STUB (f, j)) + { + /* Build something we can demangle. */ + mangled_name = gdb_mangle_name (type, i, j); + demangled_name = + cplus_demangle (mangled_name, + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name == NULL) + fprintf_filtered (stream, "", + mangled_name); + else + { + char *demangled_no_class = + strchr (demangled_name, ':'); + + if (demangled_no_class == NULL) + demangled_no_class = demangled_name; + else + { + if (*++demangled_no_class == ':') + ++demangled_no_class; + } + fputs_filtered (demangled_no_class, stream); + free (demangled_name); + } + free (mangled_name); + } + else if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' + && is_cplus_marker (TYPE_FN_FIELD_PHYSNAME (f, j)[1])) + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, + "~", method_name, 0, stream); + else + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "", + method_name, + TYPE_FN_FIELD_STATIC_P (f, j), + stream); + + fprintf_filtered (stream, ";\n"); + } + } + + fprintfi_filtered (level, stream, "}"); + } + break; + + case TYPE_CODE_ENUM: + fprintf_filtered (stream, "enum "); + if (TYPE_TAG_NAME (type) != NULL) + { + 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) + { + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + lastval = 0; + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf_filtered (stream, ", "); + wrap_here (" "); + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + if (lastval != TYPE_FIELD_BITPOS (type, i)) + { + fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); + } + lastval++; + } + fprintf_filtered (stream, "}"); + } + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "void"); + break; + + case TYPE_CODE_UNDEF: + fprintf_filtered (stream, "struct "); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_RANGE: + /* This should not occur */ + fprintf_filtered (stream, ""); + break; + + default: + /* Handle types not explicitly handled by the other cases, + such as fundamental types. For these, just print whatever + the type name is, as recorded in the type itself. If there + is no type name, then complain. */ + if (TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + } + else + { + /* At least for dump_symtab, it is important that this not be + an error (). */ + fprintf_filtered (stream, "", + TYPE_CODE (type)); + } + break; + } +} + diff --git a/contrib/gdb/gdb/c-valprint.c b/contrib/gdb/gdb/c-valprint.c new file mode 100644 index 000000000000..a16f87cf6eb3 --- /dev/null +++ b/contrib/gdb/gdb/c-valprint.c @@ -0,0 +1,469 @@ +/* Support for printing C values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "demangle.h" +#include "valprint.h" +#include "language.h" +#include "c-lang.h" + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter or 0 for natural format). The data at VALADDR is in + target byte order. + + If the data are a string pointer, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. */ + +int +c_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + register unsigned int i = 0; /* Number of characters printed */ + unsigned len; + struct type *elttype; + unsigned eltlen; + LONGEST val; + CORE_ADDR addr; + + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + { + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + if (prettyprint_arrays) + { + print_spaces_filtered (2 + 2 * recurse, stream); + } + /* For an array of chars, print with string syntax. */ + if (eltlen == 1 && + ((TYPE_CODE (elttype) == TYPE_CODE_INT) + || ((current_language->la_language == language_m2) + && (TYPE_CODE (elttype) == TYPE_CODE_CHAR))) + && (format == 0 || format == 's')) + { + /* If requested, look for the first null char and only print + elements up to it. */ + if (stop_print_at_null) + { + int temp_len; + + /* Look for a NULL char. */ + for (temp_len = 0; + valaddr[temp_len] + && temp_len < len && temp_len < print_max; + temp_len++); + len = temp_len; + } + + LA_PRINT_STRING (stream, valaddr, len, 0); + i = len; + } + else + { + fprintf_filtered (stream, "{"); + /* If this is a virtual function table, print the 0th + entry specially, and the rest of the members normally. */ + if (cp_is_vtbl_ptr_type (elttype)) + { + i = 1; + fprintf_filtered (stream, "%d vtable entries", len - 1); + } + else + { + i = 0; + } + val_print_array_elements (type, valaddr, address, stream, + format, deref_ref, recurse, pretty, i); + fprintf_filtered (stream, "}"); + } + break; + } + /* Array of unspecified length: treat like pointer to first elt. */ + addr = address; + goto print_unpacked_pointer; + + case TYPE_CODE_PTR: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + if (vtblprint && cp_is_vtbl_ptr_type(type)) + { + /* Print the unmangled name if desired. */ + /* Print vtable entry - we only get here if we ARE using + -fvtable_thunks. (Otherwise, look under TYPE_CODE_STRUCT.) */ + print_address_demangle(extract_address (valaddr, TYPE_LENGTH (type)), + stream, demangle); + break; + } + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + if (TYPE_CODE (elttype) == TYPE_CODE_METHOD) + { + cp_print_class_method (valaddr, type, stream); + } + else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER) + { + cp_print_class_member (valaddr, + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)), + stream, "&"); + } + else + { + addr = unpack_pointer (type, valaddr); + print_unpacked_pointer: + + if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) + { + /* Try to print what function it points to. */ + print_address_demangle (addr, stream, demangle); + /* Return value is irrelevant except for string pointers. */ + return (0); + } + + if (addressprint && format != 's') + { + print_address_numeric (addr, 1, stream); + } + + /* For a pointer to char or unsigned char, also print the string + pointed to, unless pointer is null. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_INT + && (format == 0 || format == 's') + && addr != 0) + { + i = val_print_string (addr, 0, stream); + } + else if (cp_is_vtbl_member(type)) + { + /* print vtbl's nicely */ + CORE_ADDR vt_address = unpack_pointer (type, valaddr); + + struct minimal_symbol *msymbol = + lookup_minimal_symbol_by_pc (vt_address); + if ((msymbol != NULL) && + (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) + { + fputs_filtered (" <", stream); + fputs_filtered (SYMBOL_SOURCE_NAME (msymbol), stream); + fputs_filtered (">", stream); + } + if (vt_address && vtblprint) + { + value_ptr vt_val; + struct symbol *wsym = (struct symbol *)NULL; + struct type *wtype; + struct symtab *s; + struct block *block = (struct block *)NULL; + int is_this_fld; + + if (msymbol != NULL) + wsym = lookup_symbol (SYMBOL_NAME(msymbol), block, + VAR_NAMESPACE, &is_this_fld, &s); + + if (wsym) + { + wtype = SYMBOL_TYPE(wsym); + } + else + { + wtype = TYPE_TARGET_TYPE(type); + } + vt_val = value_at (wtype, vt_address); + val_print (VALUE_TYPE (vt_val), VALUE_CONTENTS (vt_val), + VALUE_ADDRESS (vt_val), stream, format, + deref_ref, recurse + 1, pretty); + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + } + } + + /* 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_MEMBER: + error ("not implemented: member type in c_val_print"); + break; + + case TYPE_CODE_REF: + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER) + { + cp_print_class_member (valaddr, + TYPE_DOMAIN_TYPE (elttype), + stream, ""); + break; + } + if (addressprint) + { + fprintf_filtered (stream, "@"); + print_address_numeric + (extract_address (valaddr, + TARGET_PTR_BIT / HOST_CHAR_BIT), 1, stream); + if (deref_ref) + fputs_filtered (": ", stream); + } + /* De-reference the reference. */ + if (deref_ref) + { + if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) + { + value_ptr deref_val = + value_at + (TYPE_TARGET_TYPE (type), + unpack_pointer (lookup_pointer_type (builtin_type_void), + valaddr)); + val_print (VALUE_TYPE (deref_val), + VALUE_CONTENTS (deref_val), + VALUE_ADDRESS (deref_val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fputs_filtered ("???", stream); + } + break; + + case TYPE_CODE_UNION: + if (recurse && !unionprint) + { + fprintf_filtered (stream, "{...}"); + break; + } + /* Fall through. */ + case TYPE_CODE_STRUCT: + if (vtblprint && cp_is_vtbl_ptr_type(type)) + { + /* Print the unmangled name if desired. */ + /* Print vtable entry - we only get here if NOT using + -fvtable_thunks. (Otherwise, look under TYPE_CODE_PTR.) */ + print_address_demangle(*((int *) (valaddr + /* FIXME bytesex */ + TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8)), + stream, demangle); + } + else + cp_print_value_fields (type, valaddr, address, stream, format, + recurse, pretty, NULL, 0); + break; + + case TYPE_CODE_ENUM: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + len = TYPE_NFIELDS (type); + val = unpack_long (type, valaddr); + 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_FUNC: + if (format) + { + print_scalar_formatted (valaddr, type, format, 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 (address, stream, demangle); + break; + + case TYPE_CODE_BOOL: + format = format ? format : output_format; + if (format) + print_scalar_formatted (valaddr, type, format, 0, stream); + else + { + val = unpack_long (type, valaddr); + 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: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val_print_type_code_int (type, valaddr, stream); + /* C and C++ has no single byte int type, char is used instead. + 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) + { + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), + stream); + } + } + break; + + case TYPE_CODE_CHAR: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + fprintf_filtered (stream, TYPE_UNSIGNED (type) ? "%u" : "%d", + unpack_long (type, valaddr)); + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), stream); + } + break; + + case TYPE_CODE_FLT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + print_floating (valaddr, type, stream); + } + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "void"); + break; + + case TYPE_CODE_ERROR: + fprintf_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; + + default: + error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type)); + } + gdb_flush (stream); + return (0); +} + +int +c_value_print (val, stream, format, pretty) + value_ptr val; + GDB_FILE *stream; + int format; + enum val_prettyprint pretty; +{ + struct type *type = VALUE_TYPE (val); + + /* If it is a pointer, indicate what it points to. + + Print type also if it is a reference. + + C++: if it is a member pointer, we will take care + of that when we print it. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR || + TYPE_CODE (type) == TYPE_CODE_REF) + { + /* Hack: remove (char *) for char strings. Their + type is indicated by the quoted string anyway. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR && + TYPE_NAME (type) == NULL && + TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL && + STREQ (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char")) + { + /* Print nothing */ + } + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") "); + } + } + return (val_print (type, VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1, 0, pretty)); +} diff --git a/contrib/gdb/gdb/call-cmds.h b/contrib/gdb/gdb/call-cmds.h new file mode 100644 index 000000000000..4c02004f0753 --- /dev/null +++ b/contrib/gdb/gdb/call-cmds.h @@ -0,0 +1,28 @@ +/* Prototypes for GDB commands that are called internally by other functions. + Copyright 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern void +initialize_all_files PARAMS ((void)); + +extern void +exec_file_command PARAMS ((char *, int)); + +extern void +core_file_command PARAMS ((char *, int)); + +extern void +break_command PARAMS ((char *, int)); diff --git a/contrib/gdb/gdb/callback.c b/contrib/gdb/gdb/callback.c new file mode 100644 index 000000000000..d59ecdabd7a1 --- /dev/null +++ b/contrib/gdb/gdb/callback.c @@ -0,0 +1,349 @@ +/* Host callback routines for GDB. + Copyright 1995 Free Software Foundation, Inc. + Contributed by 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file provides a standard way for targets to talk to the host OS + level. + + This interface will probably need a bit more banging to make it + smooth. Currently the simulator uses this file to provide the + callbacks for itself when it's built standalone, which is rather + ugly. */ + +#ifndef INSIDE_SIMULATOR +#include "defs.h" +#endif + +#include "ansidecl.h" +#include "callback.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include +#include +#include +#include + + + +/* Set the callback copy of errno from what we see now. */ +static int +wrap (p, val) + host_callback *p; + int val; +{ + p->last_errno = errno; + return val; +} + +/* Make sure the FD provided is ok. If not, return non-zero + and set errno. */ + +static int +fdbad (p, fd) + host_callback *p; + int fd; +{ + if (fd < 0 || fd > MAX_CALLBACK_FDS || !p->fdopen[fd]) + { + p->last_errno = EINVAL; + return -1; + } + return 0; +} + +static int +fdmap (p, fd) + host_callback *p; + int fd; +{ + return p->fdmap[fd]; +} + +int +os_close (p, fd) + host_callback *p; + int fd; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, close (fdmap (p, fd))); + return result; +} + +int +os_get_errno (p) + host_callback *p; +{ + /* !!! fixme, translate from host to taget errno value */ + return p->last_errno; +} + + +int +os_isatty (p, fd) + host_callback *p; + int fd; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, isatty (fdmap (fd))); + return result; +} + +int +os_lseek (p, fd, off, way) + host_callback *p; + int fd; + long off; + int way; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = lseek (fdmap (p, fd), off, way); + return result; +} + +int +os_open (p, name, flags) + host_callback *p; + const char *name; + int flags; +{ + int i; + for (i = 0; i < MAX_CALLBACK_FDS; i++) + { + if (!p->fdopen[i]) + { + int f = open (name, flags); + if (f < 0) + { + p->last_errno = errno; + return f; + } + p->fdopen[i] = 1; + p->fdmap[i] = f; + return i; + } + } + p->last_errno = EMFILE; + return -1; +} + +int +os_read (p, fd, buf, len) + host_callback *p; + int fd; + char *buf; + int len; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, read (fdmap (p, fd), buf, len)); + return result; +} + +int +os_read_stdin (p, buf, len) + host_callback *p; + char *buf; + int len; +{ + return wrap (p, read (0, buf, len)); +} + +int +os_write (p, fd, buf, len) + host_callback *p; + int fd; + const char *buf; + int len; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, write (fdmap (p, fd), buf, len)); + return result; +} + +/* ignore the grossness of INSIDE_SIMULATOR, it will go away one day. */ +int +os_write_stdout (p, buf, len) + host_callback *p; + const char *buf; + int len; +{ +#ifdef INSIDE_SIMULATOR + return os_write (p, 1, buf, len); +#else + int i; + char b[2]; + for (i = 0; i< len; i++) + { + b[0] = buf[i]; + b[1] = 0; + if (target_output_hook) + target_output_hook (b); + else + fputs_filtered (b, gdb_stdout); + } + return len; +#endif +} + +int +os_rename (p, f1, f2) + host_callback *p; + const char *f1; + const char *f2; +{ + return wrap (p, rename (f1, f2)); +} + + +int +os_system (p, s) + host_callback *p; + const char *s; +{ + return wrap (p, system (s)); +} + +long +os_time (p, t) + host_callback *p; + long *t; +{ + return wrap (p, time (t)); +} + + +int +os_unlink (p, f1) + host_callback *p; + const char *f1; +{ + return wrap (p, unlink (f1)); +} + + +int +os_shutdown (p) +host_callback *p; +{ + int i; + for (i = 0; i < MAX_CALLBACK_FDS; i++) + { + if (p->fdopen[i] && !p->alwaysopen[i]) { + close (p->fdmap[i]); + p->fdopen[i] = 0; + } + } + return 1; +} + +int os_init(p) +host_callback *p; +{ + int i; + os_shutdown (p); + for (i= 0; i < 3; i++) + { + p->fdmap[i] = i; + p->fdopen[i] = 1; + p->alwaysopen[i] = 1; + } + return 1; +} + + +/* !!fixme!! + This bit is ugly. When the interface has settled down I'll + move the whole file into sim/common and remove this bit. */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +os_printf_filtered (host_callback *p, const char *format, ...) +#else +os_printf_filtered (p, va_alist) + host_callback *p; + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + + va_start (args); + format = va_arg (args, char *); +#endif + +#ifdef INSIDE_SIMULATOR + vprintf (format, args); +#else + vfprintf_filtered (stdout, format, args); +#endif + + va_end (args); +} + +host_callback default_callback = +{ + os_close, + os_get_errno, + os_isatty, + os_lseek, + os_open, + os_read, + os_read_stdin, + os_rename, + os_system, + os_time, + os_unlink, + os_write, + os_write_stdout, + + os_shutdown, + os_init, + + os_printf_filtered, + + 0, /* last errno */ +}; diff --git a/contrib/gdb/gdb/callback.h b/contrib/gdb/gdb/callback.h new file mode 100644 index 000000000000..b97c3b2ce81e --- /dev/null +++ b/contrib/gdb/gdb/callback.h @@ -0,0 +1,41 @@ +#ifndef CALLBACK_H +#define CALLBACK_H +typedef struct host_callback_struct host_callback; + +#define MAX_CALLBACK_FDS 10 + +struct host_callback_struct +{ + int (*close) PARAMS ((host_callback *,int)); + int (*get_errno) PARAMS ((host_callback *)); + int (*isatty) PARAMS ((host_callback *, int)); + int (*lseek) PARAMS ((host_callback *, int, long , int)); + int (*open) PARAMS ((host_callback *, const char*, int mode)); + int (*read) PARAMS ((host_callback *,int, char *, int)); + int (*read_stdin) PARAMS (( host_callback *, char *, int)); + int (*rename) PARAMS ((host_callback *, const char *, const char *)); + int (*system) PARAMS ((host_callback *, const char *)); + long (*time) PARAMS ((host_callback *, long *)); + int (*unlink) PARAMS ((host_callback *, const char *)); + int (*write) PARAMS ((host_callback *,int, const char *, int)); + int (*write_stdout) PARAMS ((host_callback *, const char *, int)); + + + /* Used when the target has gone away, so we can close open + handles and free memory etc etc. */ + int (*shutdown) PARAMS ((host_callback *)); + int (*init) PARAMS ((host_callback *)); + + /* Talk to the user on a console. */ + void (*printf_filtered) PARAMS ((host_callback *, const char *, ...)); + + int last_errno; /* host format */ + + int fdmap[MAX_CALLBACK_FDS]; + char fdopen[MAX_CALLBACK_FDS]; + char alwaysopen[MAX_CALLBACK_FDS]; +}; +#endif + + +extern host_callback default_callback; diff --git a/contrib/gdb/gdb/ch-exp.c b/contrib/gdb/gdb/ch-exp.c new file mode 100644 index 000000000000..f6f522ab4a67 --- /dev/null +++ b/contrib/gdb/gdb/ch-exp.c @@ -0,0 +1,2090 @@ +/* Parser for GNU CHILL (CCITT High-Level Language) -*- C -*- + Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Parse a Chill 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 the language accepted by this parser is more liberal + than the one accepted by an actual Chill compiler. For example, the + language rule that a simple name string can not be one of the reserved + simple name strings is not enforced (e.g "case" is not treated as a + reserved name). Another example is that Chill is a strongly typed + language, and certain expressions that violate the type constraints + may still be evaluated if gdb can do so in a meaningful manner, while + such expressions would be rejected by the compiler. The reason for + this more liberal behavior is the philosophy that the debugger + is intended to be a tool that is used by the programmer when things + go wrong, and as such, it should provide as few artificial barriers + to it's use as possible. If it can do something meaningful, even + something that violates language contraints that are enforced by the + compiler, it should do so without complaint. + + */ + +#include "defs.h" +#include "gdb_string.h" +#include +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "ch-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 */ + +typedef union + + { + LONGEST lval; + unsigned LONGEST ulval; + struct { + LONGEST val; + struct type *type; + } typed_val; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + struct ttype tsym; + struct symtoken ssym; + }YYSTYPE; + +enum ch_terminal { + END_TOKEN = 0, + /* '\001' ... '\xff' come first. */ + OPEN_PAREN = '(', + TOKEN_NOT_READ = 999, + INTEGER_LITERAL, + BOOLEAN_LITERAL, + CHARACTER_LITERAL, + FLOAT_LITERAL, + GENERAL_PROCEDURE_NAME, + LOCATION_NAME, + EMPTINESS_LITERAL, + CHARACTER_STRING_LITERAL, + BIT_STRING_LITERAL, + TYPENAME, + FIELD_NAME, + CASE, + OF, + ESAC, + LOGIOR, + ORIF, + LOGXOR, + LOGAND, + ANDIF, + NOTEQUAL, + GEQ, + LEQ, + IN, + SLASH_SLASH, + MOD, + REM, + NOT, + POINTER, + RECEIVE, + UP, + IF, + THEN, + ELSE, + FI, + ELSIF, + ILLEGAL_TOKEN, + NUM, + PRED, + SUCC, + ABS, + CARD, + MAX_TOKEN, + MIN_TOKEN, + ADDR_TOKEN, + SIZE, + UPPER, + LOWER, + LENGTH, + ARRAY, + GDB_VARIABLE, + GDB_ASSIGNMENT +}; + +/* Forward declarations. */ +static void parse_expr (); +static void parse_primval (); +static void parse_untyped_expr (); +static int parse_opt_untyped_expr (); +static void parse_if_expression_body PARAMS((void)); +static void write_lower_upper_value PARAMS ((enum exp_opcode, struct type *)); +static enum ch_terminal ch_lex (); + +#define MAX_LOOK_AHEAD 2 +static enum ch_terminal terminal_buffer[MAX_LOOK_AHEAD+1] = { + TOKEN_NOT_READ, TOKEN_NOT_READ, TOKEN_NOT_READ}; +static YYSTYPE yylval; +static YYSTYPE val_buffer[MAX_LOOK_AHEAD+1]; + +/*int current_token, lookahead_token;*/ + +#ifdef __GNUC__ +__inline__ +#endif +static enum ch_terminal +PEEK_TOKEN() +{ + if (terminal_buffer[0] == TOKEN_NOT_READ) + { + terminal_buffer[0] = ch_lex (); + val_buffer[0] = yylval; + } + return terminal_buffer[0]; +} +#define PEEK_LVAL() val_buffer[0] +#define PEEK_TOKEN1() peek_token_(1) +#define PEEK_TOKEN2() peek_token_(2) +static enum ch_terminal +peek_token_ (i) + int i; +{ + if (i > MAX_LOOK_AHEAD) + fatal ("internal error - too much lookahead"); + if (terminal_buffer[i] == TOKEN_NOT_READ) + { + terminal_buffer[i] = ch_lex (); + val_buffer[i] = yylval; + } + return terminal_buffer[i]; +} + +#if 0 + +static void +pushback_token (code, node) + enum ch_terminal code; + YYSTYPE node; +{ + int i; + if (terminal_buffer[MAX_LOOK_AHEAD] != TOKEN_NOT_READ) + fatal ("internal error - cannot pushback token"); + for (i = MAX_LOOK_AHEAD; i > 0; i--) + { + terminal_buffer[i] = terminal_buffer[i - 1]; + val_buffer[i] = val_buffer[i - 1]; + } + terminal_buffer[0] = code; + val_buffer[0] = node; +} + +#endif + +static void +forward_token_() +{ + int i; + for (i = 0; i < MAX_LOOK_AHEAD; i++) + { + terminal_buffer[i] = terminal_buffer[i+1]; + val_buffer[i] = val_buffer[i+1]; + } + terminal_buffer[MAX_LOOK_AHEAD] = TOKEN_NOT_READ; +} +#define FORWARD_TOKEN() forward_token_() + +/* Skip the next token. + if it isn't TOKEN, the parser is broken. */ + +void +require(token) + enum ch_terminal token; +{ + if (PEEK_TOKEN() != token) + { + char buf[80]; + sprintf (buf, "internal parser error - expected token %d", (int)token); + fatal(buf); + } + FORWARD_TOKEN(); +} + +int +check_token (token) + enum ch_terminal token; +{ + if (PEEK_TOKEN() != token) + return 0; + FORWARD_TOKEN (); + return 1; +} + +/* return 0 if expected token was not found, + else return 1. +*/ +int +expect(token, message) + enum ch_terminal token; + char *message; +{ + if (PEEK_TOKEN() != token) + { + if (message) + error (message); + else if (token < 256) + error ("syntax error - expected a '%c' here \"%s\"", token, lexptr); + else + error ("syntax error"); + return 0; + } + else + FORWARD_TOKEN(); + return 1; +} + +#if 0 +static tree +parse_opt_name_string (allow_all) + int allow_all; /* 1 if ALL is allowed as a postfix */ +{ + int token = PEEK_TOKEN(); + tree name; + if (token != NAME) + { + if (token == ALL && allow_all) + { + FORWARD_TOKEN (); + return ALL_POSTFIX; + } + return NULL_TREE; + } + name = PEEK_LVAL(); + for (;;) + { + FORWARD_TOKEN (); + token = PEEK_TOKEN(); + if (token != '!') + return name; + FORWARD_TOKEN(); + token = PEEK_TOKEN(); + if (token == ALL && allow_all) + return get_identifier3(IDENTIFIER_POINTER (name), "!", "*"); + if (token != NAME) + { + if (pass == 1) + error ("'%s!' is not followed by an identifier", + IDENTIFIER_POINTER (name)); + return name; + } + name = get_identifier3(IDENTIFIER_POINTER(name), + "!", IDENTIFIER_POINTER(PEEK_LVAL())); + } +} + +static tree +parse_simple_name_string () +{ + int token = PEEK_TOKEN(); + tree name; + if (token != NAME) + { + error ("expected a name here"); + return error_mark_node; + } + name = PEEK_LVAL (); + FORWARD_TOKEN (); + return name; +} + +static tree +parse_name_string () +{ + tree name = parse_opt_name_string (0); + if (name) + return name; + if (pass == 1) + error ("expected a name string here"); + return error_mark_node; +} + +/* Matches: + Returns if pass 1: the identifier. + Returns if pass 2: a decl or value for identifier. */ + +static tree +parse_name () +{ + tree name = parse_name_string (); + if (pass == 1 || ignoring) + return name; + else + { + tree decl = lookup_name (name); + if (decl == NULL_TREE) + { + error ("`%s' undeclared", IDENTIFIER_POINTER (name)); + return error_mark_node; + } + else if (TREE_CODE (TREE_TYPE (decl)) == ERROR_MARK) + return error_mark_node; + else if (TREE_CODE (decl) == CONST_DECL) + return DECL_INITIAL (decl); + else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE) + return convert_from_reference (decl); + else + return decl; + } +} +#endif + +#if 0 +static void +pushback_paren_expr (expr) + tree expr; +{ + if (pass == 1 && !ignoring) + expr = build1 (PAREN_EXPR, NULL_TREE, expr); + pushback_token (EXPR, expr); +} +#endif + +/* Matches: */ + +static void +parse_case_label () +{ + if (check_token (ELSE)) + error ("ELSE in tuples labels not implemented"); + /* Does not handle the case of a mode name. FIXME */ + parse_expr (); + if (check_token (':')) + { + parse_expr (); + write_exp_elt_opcode (BINOP_RANGE); + } +} + +static int +parse_opt_untyped_expr () +{ + switch (PEEK_TOKEN ()) + { + case ',': + case ':': + case ')': + return 0; + default: + parse_untyped_expr (); + return 1; + } +} + +static void +parse_unary_call () +{ + FORWARD_TOKEN (); + expect ('(', NULL); + parse_expr (); + expect (')', NULL); +} + +/* Parse NAME '(' MODENAME ')'. */ + +struct type * +parse_mode_call () +{ + struct type *type; + FORWARD_TOKEN (); + expect ('(', NULL); + if (PEEK_TOKEN () != TYPENAME) + error ("expect MODENAME here `%s'", lexptr); + type = PEEK_LVAL().tsym.type; + FORWARD_TOKEN (); + expect (')', NULL); + return type; +} + +struct type * +parse_mode_or_normal_call () +{ + struct type *type; + FORWARD_TOKEN (); + expect ('(', NULL); + if (PEEK_TOKEN () == TYPENAME) + { + type = PEEK_LVAL().tsym.type; + FORWARD_TOKEN (); + } + else + { + parse_expr (); + type = NULL; + } + expect (')', NULL); + return type; +} + +/* Parse something that looks like a function call. + Assume we have parsed the function, and are at the '('. */ + +static void +parse_call () +{ + int arg_count; + require ('('); + /* This is to save the value of arglist_len + being accumulated for each dimension. */ + start_arglist (); + if (parse_opt_untyped_expr ()) + { + int tok = PEEK_TOKEN (); + arglist_len = 1; + if (tok == UP || tok == ':') + { + FORWARD_TOKEN (); + parse_expr (); + expect (')', "expected ')' to terminate slice"); + end_arglist (); + write_exp_elt_opcode (tok == UP ? TERNOP_SLICE_COUNT + : TERNOP_SLICE); + return; + } + while (check_token (',')) + { + parse_untyped_expr (); + arglist_len++; + } + } + else + arglist_len = 0; + expect (')', NULL); + arg_count = end_arglist (); + write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst (arg_count); + write_exp_elt_opcode (MULTI_SUBSCRIPT); +} + +static void +parse_named_record_element () +{ + struct stoken label; + + label = PEEK_LVAL ().sval; + expect (FIELD_NAME, "expected a field name here `%s'", lexptr); + if (check_token (',')) + parse_named_record_element (); + else if (check_token (':')) + parse_expr (); + else + error ("syntax error near `%s' in named record tuple element", lexptr); + write_exp_elt_opcode (OP_LABELED); + write_exp_string (label); + write_exp_elt_opcode (OP_LABELED); +} + +/* Returns one or nore TREE_LIST nodes, in reverse order. */ + +static void +parse_tuple_element () +{ + if (PEEK_TOKEN () == FIELD_NAME) + { + /* Parse a labelled structure tuple. */ + parse_named_record_element (); + return; + } + + if (check_token ('(')) + { + if (check_token ('*')) + { + expect (')', "missing ')' after '*' case label list"); + error ("(*) not implemented in case label list"); + } + else + { + parse_case_label (); + while (check_token (',')) + { + parse_case_label (); + write_exp_elt_opcode (BINOP_COMMA); + } + expect (')', NULL); + } + } + else + parse_untyped_expr (); + if (check_token (':')) + { + /* A powerset range or a labeled Array. */ + parse_untyped_expr (); + write_exp_elt_opcode (BINOP_RANGE); + } +} + +/* Matches: a COMMA-separated list of tuple elements. + Returns a list (of TREE_LIST nodes). */ +static void +parse_opt_element_list () +{ + arglist_len = 0; + if (PEEK_TOKEN () == ']') + return; + for (;;) + { + parse_tuple_element (); + arglist_len++; + if (PEEK_TOKEN () == ']') + break; + if (!check_token (',')) + error ("bad syntax in tuple"); + } +} + +/* Parses: '[' elements ']' + If modename is non-NULL it prefixed the tuple. */ + +static void +parse_tuple (mode) + struct type *mode; +{ + require ('['); + start_arglist (); + parse_opt_element_list (); + expect (']', "missing ']' after tuple"); + write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) end_arglist () - 1); + write_exp_elt_opcode (OP_ARRAY); + if (mode) + { + struct type *type = check_typedef (mode); + if (TYPE_CODE (type) != TYPE_CODE_ARRAY + && TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_SET) + error ("invalid tuple mode"); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (mode); + write_exp_elt_opcode (UNOP_CAST); + } +} + +static void +parse_primval () +{ + struct type *type; + enum exp_opcode op; + char *op_name; + switch (PEEK_TOKEN ()) + { + case INTEGER_LITERAL: + case CHARACTER_LITERAL: + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (PEEK_LVAL ().typed_val.type); + write_exp_elt_longcst (PEEK_LVAL ().typed_val.val); + write_exp_elt_opcode (OP_LONG); + FORWARD_TOKEN (); + break; + case BOOLEAN_LITERAL: + write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) PEEK_LVAL ().ulval); + write_exp_elt_opcode (OP_BOOL); + FORWARD_TOKEN (); + break; + case FLOAT_LITERAL: + write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst (PEEK_LVAL ().dval); + write_exp_elt_opcode (OP_DOUBLE); + FORWARD_TOKEN (); + break; + case EMPTINESS_LITERAL: + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (lookup_pointer_type (builtin_type_void)); + write_exp_elt_longcst (0); + write_exp_elt_opcode (OP_LONG); + FORWARD_TOKEN (); + break; + case CHARACTER_STRING_LITERAL: + write_exp_elt_opcode (OP_STRING); + write_exp_string (PEEK_LVAL ().sval); + write_exp_elt_opcode (OP_STRING); + FORWARD_TOKEN (); + break; + case BIT_STRING_LITERAL: + write_exp_elt_opcode (OP_BITSTRING); + write_exp_bitstring (PEEK_LVAL ().sval); + write_exp_elt_opcode (OP_BITSTRING); + FORWARD_TOKEN (); + break; + case ARRAY: + FORWARD_TOKEN (); + /* This is pseudo-Chill, similar to C's '(TYPE[])EXPR' + which casts to an artificial array. */ + expect ('(', NULL); + expect (')', NULL); + if (PEEK_TOKEN () != TYPENAME) + error ("missing MODENAME after ARRAY()"); + type = PEEK_LVAL().tsym.type; + FORWARD_TOKEN (); + expect ('(', NULL); + parse_expr (); + expect (')', "missing right parenthesis"); + type = create_array_type ((struct type *) NULL, type, + create_range_type ((struct type *) NULL, + builtin_type_int, 0, 0)); + TYPE_ARRAY_UPPER_BOUND_TYPE(type) = BOUND_CANNOT_BE_DETERMINED; + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (type); + write_exp_elt_opcode (UNOP_CAST); + break; +#if 0 + case CONST: + case EXPR: + val = PEEK_LVAL(); + FORWARD_TOKEN (); + break; +#endif + case '(': + FORWARD_TOKEN (); + parse_expr (); + expect (')', "missing right parenthesis"); + break; + case '[': + parse_tuple (NULL); + break; + case GENERAL_PROCEDURE_NAME: + case LOCATION_NAME: + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (PEEK_LVAL ().ssym.sym); + write_exp_elt_opcode (OP_VAR_VALUE); + FORWARD_TOKEN (); + break; + case GDB_VARIABLE: /* gdb specific */ + FORWARD_TOKEN (); + break; + case NUM: + parse_unary_call (); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (builtin_type_int); + write_exp_elt_opcode (UNOP_CAST); + break; + case CARD: + parse_unary_call (); + write_exp_elt_opcode (UNOP_CARD); + break; + case MAX_TOKEN: + parse_unary_call (); + write_exp_elt_opcode (UNOP_CHMAX); + break; + case MIN_TOKEN: + parse_unary_call (); + write_exp_elt_opcode (UNOP_CHMIN); + break; + case PRED: op_name = "PRED"; goto unimplemented_unary_builtin; + case SUCC: op_name = "SUCC"; goto unimplemented_unary_builtin; + case ABS: op_name = "ABS"; goto unimplemented_unary_builtin; + unimplemented_unary_builtin: + parse_unary_call (); + error ("not implemented: %s builtin function", op_name); + break; + case ADDR_TOKEN: + parse_unary_call (); + write_exp_elt_opcode (UNOP_ADDR); + break; + case SIZE: + type = parse_mode_or_normal_call (); + if (type) + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + CHECK_TYPEDEF (type); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (type)); + write_exp_elt_opcode (OP_LONG); + } + else + write_exp_elt_opcode (UNOP_SIZEOF); + break; + case LOWER: + op = UNOP_LOWER; + goto lower_upper; + case UPPER: + op = UNOP_UPPER; + goto lower_upper; + lower_upper: + type = parse_mode_or_normal_call (); + write_lower_upper_value (op, type); + break; + case LENGTH: + parse_unary_call (); + write_exp_elt_opcode (UNOP_LENGTH); + break; + case TYPENAME: + type = PEEK_LVAL ().tsym.type; + FORWARD_TOKEN (); + switch (PEEK_TOKEN()) + { + case '[': + parse_tuple (type); + break; + case '(': + FORWARD_TOKEN (); + parse_expr (); + expect (')', "missing right parenthesis"); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (type); + write_exp_elt_opcode (UNOP_CAST); + break; + default: + error ("typename in invalid context"); + } + break; + + default: + error ("invalid expression syntax at `%s'", lexptr); + } + for (;;) + { + switch (PEEK_TOKEN ()) + { + case FIELD_NAME: + write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (PEEK_LVAL ().sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); + FORWARD_TOKEN (); + continue; + case POINTER: + FORWARD_TOKEN (); + if (PEEK_TOKEN () == TYPENAME) + { + type = PEEK_LVAL ().tsym.type; + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (lookup_pointer_type (type)); + write_exp_elt_opcode (UNOP_CAST); + FORWARD_TOKEN (); + } + write_exp_elt_opcode (UNOP_IND); + continue; + case OPEN_PAREN: + parse_call (); + continue; + case CHARACTER_STRING_LITERAL: + case CHARACTER_LITERAL: + case BIT_STRING_LITERAL: + /* Handle string repetition. (See comment in parse_operand5.) */ + parse_primval (); + write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst (1); + write_exp_elt_opcode (MULTI_SUBSCRIPT); + continue; + case END_TOKEN: + case TOKEN_NOT_READ: + case INTEGER_LITERAL: + case BOOLEAN_LITERAL: + case FLOAT_LITERAL: + case GENERAL_PROCEDURE_NAME: + case LOCATION_NAME: + case EMPTINESS_LITERAL: + case TYPENAME: + case CASE: + case OF: + case ESAC: + case LOGIOR: + case ORIF: + case LOGXOR: + case LOGAND: + case ANDIF: + case NOTEQUAL: + case GEQ: + case LEQ: + case IN: + case SLASH_SLASH: + case MOD: + case REM: + case NOT: + case RECEIVE: + case UP: + case IF: + case THEN: + case ELSE: + case FI: + case ELSIF: + case ILLEGAL_TOKEN: + case NUM: + case PRED: + case SUCC: + case ABS: + case CARD: + case MAX_TOKEN: + case MIN_TOKEN: + case ADDR_TOKEN: + case SIZE: + case UPPER: + case LOWER: + case LENGTH: + case ARRAY: + case GDB_VARIABLE: + case GDB_ASSIGNMENT: + break; + } + break; + } + return; +} + +static void +parse_operand6 () +{ + if (check_token (RECEIVE)) + { + parse_primval (); + error ("not implemented: RECEIVE expression"); + } + else if (check_token (POINTER)) + { + parse_primval (); + write_exp_elt_opcode (UNOP_ADDR); + } + else + parse_primval(); +} + +static void +parse_operand5() +{ + enum exp_opcode op; + /* We are supposed to be looking for a , + but in general we can't distinguish that from a parenthesized + expression. This is especially difficult if we allow the + string operand to be a constant expression (as requested by + some users), and not just a string literal. + Consider: LPRN expr RPRN LPRN expr RPRN + Is that a function call or string repetition? + Instead, we handle string repetition in parse_primval, + and build_generalized_call. */ + switch (PEEK_TOKEN()) + { + case NOT: op = UNOP_LOGICAL_NOT; break; + case '-': op = UNOP_NEG; break; + default: + op = OP_NULL; + } + if (op != OP_NULL) + FORWARD_TOKEN(); + parse_operand6(); + if (op != OP_NULL) + write_exp_elt_opcode (op); +} + +static void +parse_operand4 () +{ + enum exp_opcode op; + parse_operand5(); + for (;;) + { + switch (PEEK_TOKEN()) + { + case '*': op = BINOP_MUL; break; + case '/': op = BINOP_DIV; break; + case MOD: op = BINOP_MOD; break; + case REM: op = BINOP_REM; break; + default: + return; + } + FORWARD_TOKEN(); + parse_operand5(); + write_exp_elt_opcode (op); + } +} + +static void +parse_operand3 () +{ + enum exp_opcode op; + parse_operand4 (); + for (;;) + { + switch (PEEK_TOKEN()) + { + case '+': op = BINOP_ADD; break; + case '-': op = BINOP_SUB; break; + case SLASH_SLASH: op = BINOP_CONCAT; break; + default: + return; + } + FORWARD_TOKEN(); + parse_operand4(); + write_exp_elt_opcode (op); + } +} + +static void +parse_operand2 () +{ + enum exp_opcode op; + parse_operand3 (); + for (;;) + { + if (check_token (IN)) + { + parse_operand3(); + write_exp_elt_opcode (BINOP_IN); + } + else + { + switch (PEEK_TOKEN()) + { + case '>': op = BINOP_GTR; break; + case GEQ: op = BINOP_GEQ; break; + case '<': op = BINOP_LESS; break; + case LEQ: op = BINOP_LEQ; break; + case '=': op = BINOP_EQUAL; break; + case NOTEQUAL: op = BINOP_NOTEQUAL; break; + default: + return; + } + FORWARD_TOKEN(); + parse_operand3(); + write_exp_elt_opcode (op); + } + } +} + +static void +parse_operand1 () +{ + enum exp_opcode op; + parse_operand2 (); + for (;;) + { + switch (PEEK_TOKEN()) + { + case LOGAND: op = BINOP_BITWISE_AND; break; + case ANDIF: op = BINOP_LOGICAL_AND; break; + default: + return; + } + FORWARD_TOKEN(); + parse_operand2(); + write_exp_elt_opcode (op); + } +} + +static void +parse_operand0 () +{ + enum exp_opcode op; + parse_operand1(); + for (;;) + { + switch (PEEK_TOKEN()) + { + case LOGIOR: op = BINOP_BITWISE_IOR; break; + case LOGXOR: op = BINOP_BITWISE_XOR; break; + case ORIF: op = BINOP_LOGICAL_OR; break; + default: + return; + } + FORWARD_TOKEN(); + parse_operand1(); + write_exp_elt_opcode (op); + } +} + +static void +parse_expr () +{ + parse_operand0 (); + if (check_token (GDB_ASSIGNMENT)) + { + parse_expr (); + write_exp_elt_opcode (BINOP_ASSIGN); + } +} + +static void +parse_then_alternative () +{ + expect (THEN, "missing 'THEN' in 'IF' expression"); + parse_expr (); +} + +static void +parse_else_alternative () +{ + if (check_token (ELSIF)) + parse_if_expression_body (); + else if (check_token (ELSE)) + parse_expr (); + else + error ("missing ELSE/ELSIF in IF expression"); +} + +/* Matches: */ + +static void +parse_if_expression_body () +{ + parse_expr (); + parse_then_alternative (); + parse_else_alternative (); + write_exp_elt_opcode (TERNOP_COND); +} + +static void +parse_if_expression () +{ + require (IF); + parse_if_expression_body (); + expect (FI, "missing 'FI' at end of conditional expression"); +} + +/* An is a superset of . It also includes + and untyped , whose types + are not given by their constituents. Hence, these are only + allowed in certain contexts that expect a certain type. + You should call convert() to fix up the . */ + +static void +parse_untyped_expr () +{ + switch (PEEK_TOKEN()) + { + case IF: + parse_if_expression (); + return; + case CASE: + error ("not implemented: CASE expression"); + case '(': + switch (PEEK_TOKEN1()) + { + case IF: + case CASE: + goto skip_lprn; + case '[': + skip_lprn: + FORWARD_TOKEN (); + parse_untyped_expr (); + expect (')', "missing ')'"); + return; + default: ; + /* fall through */ + } + default: + parse_operand0 (); + } +} + +int +chill_parse () +{ + terminal_buffer[0] = TOKEN_NOT_READ; + if (PEEK_TOKEN () == TYPENAME && PEEK_TOKEN1 () == END_TOKEN) + { + write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(PEEK_LVAL ().tsym.type); + write_exp_elt_opcode(OP_TYPE); + FORWARD_TOKEN (); + } + else + parse_expr (); + if (terminal_buffer[0] != END_TOKEN) + { + if (comma_terminates && terminal_buffer[0] == ',') + lexptr--; /* Put the comma back. */ + else + error ("Junk after end of expression."); + } + return 0; +} + + +/* Implementation of a dynamically expandable buffer for processing input + characters acquired through lexptr and building a value to return in + yylval. */ + +static char *tempbuf; /* Current buffer contents */ +static int tempbufsize; /* Size of allocated buffer */ +static int tempbufindex; /* Current index into buffer */ + +#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */ + +#define CHECKBUF(size) \ + do { \ + if (tempbufindex + (size) >= tempbufsize) \ + { \ + growbuf_by_size (size); \ + } \ + } while (0); + +/* Grow the static temp buffer if necessary, including allocating the first one + on demand. */ + +static void +growbuf_by_size (count) + int count; +{ + int growby; + + growby = max (count, GROWBY_MIN_SIZE); + tempbufsize += growby; + if (tempbuf == NULL) + { + tempbuf = (char *) xmalloc (tempbufsize); + } + else + { + tempbuf = (char *) xrealloc (tempbuf, tempbufsize); + } +} + +/* Try to consume a simple name string token. If successful, returns + a pointer to a nullbyte terminated copy of the name that can be used + in symbol table lookups. If not successful, returns NULL. */ + +static char * +match_simple_name_string () +{ + char *tokptr = lexptr; + + if (isalpha (*tokptr) || *tokptr == '_') + { + char *result; + do { + tokptr++; + } while (isalnum (*tokptr) || (*tokptr == '_')); + yylval.sval.ptr = lexptr; + yylval.sval.length = tokptr - lexptr; + lexptr = tokptr; + result = copy_name (yylval.sval); + return result; + } + return (NULL); +} + +/* Start looking for a value composed of valid digits as set by the base + in use. Note that '_' characters are valid anywhere, in any quantity, + and are simply ignored. Since we must find at least one valid digit, + or reject this token as an integer literal, we keep track of how many + digits we have encountered. */ + +static int +decode_integer_value (base, tokptrptr, ivalptr) + int base; + char **tokptrptr; + LONGEST *ivalptr; +{ + char *tokptr = *tokptrptr; + int temp; + int digits = 0; + + while (*tokptr != '\0') + { + temp = *tokptr; + if (isupper (temp)) + temp = tolower (temp); + tokptr++; + switch (temp) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + temp -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + temp -= 'a'; + temp += 10; + break; + default: + temp = base; + break; + } + if (temp < base) + { + digits++; + *ivalptr *= base; + *ivalptr += temp; + } + else + { + /* Found something not in domain for current base. */ + tokptr--; /* Unconsume what gave us indigestion. */ + break; + } + } + + /* If we didn't find any digits, then we don't have a valid integer + value, so reject the entire token. Otherwise, update the lexical + scan pointer, and return non-zero for success. */ + + if (digits == 0) + { + return (0); + } + else + { + *tokptrptr = tokptr; + return (1); + } +} + +static int +decode_integer_literal (valptr, tokptrptr) + LONGEST *valptr; + char **tokptrptr; +{ + char *tokptr = *tokptrptr; + int base = 0; + LONGEST ival = 0; + int explicit_base = 0; + + /* Look for an explicit base specifier, which is optional. */ + + switch (*tokptr) + { + case 'd': + case 'D': + explicit_base++; + base = 10; + tokptr++; + break; + case 'b': + case 'B': + explicit_base++; + base = 2; + tokptr++; + break; + case 'h': + case 'H': + explicit_base++; + base = 16; + tokptr++; + break; + case 'o': + case 'O': + explicit_base++; + base = 8; + tokptr++; + break; + default: + base = 10; + break; + } + + /* If we found an explicit base ensure that the character after the + explicit base is a single quote. */ + + if (explicit_base && (*tokptr++ != '\'')) + { + return (0); + } + + /* Attempt to decode whatever follows as an integer value in the + indicated base, updating the token pointer in the process and + computing the value into ival. Also, if we have an explicit + base, then the next character must not be a single quote, or we + have a bitstring literal, so reject the entire token in this case. + Otherwise, update the lexical scan pointer, and return non-zero + for success. */ + + if (!decode_integer_value (base, &tokptr, &ival)) + { + return (0); + } + else if (explicit_base && (*tokptr == '\'')) + { + return (0); + } + else + { + *valptr = ival; + *tokptrptr = tokptr; + return (1); + } +} + +/* If it wasn't for the fact that floating point values can contain '_' + characters, we could just let strtod do all the hard work by letting it + try to consume as much of the current token buffer as possible and + find a legal conversion. Unfortunately we need to filter out the '_' + characters before calling strtod, which we do by copying the other + legal chars to a local buffer to be converted. However since we also + need to keep track of where the last unconsumed character in the input + buffer is, we have transfer only as many characters as may compose a + legal floating point value. */ + +static enum ch_terminal +match_float_literal () +{ + char *tokptr = lexptr; + char *buf; + char *copy; + double dval; + extern double strtod (); + + /* Make local buffer in which to build the string to convert. This is + required because underscores are valid in chill floating point numbers + but not in the string passed to strtod to convert. The string will be + no longer than our input string. */ + + copy = buf = (char *) alloca (strlen (tokptr) + 1); + + /* Transfer all leading digits to the conversion buffer, discarding any + underscores. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Now accept either a '.', or one of [eEdD]. Dot is legal regardless + of whether we found any leading digits, and we simply accept it and + continue on to look for the fractional part and/or exponent. One of + [eEdD] is legal only if we have seen digits, and means that there + is no fractional part. If we find neither of these, then this is + not a floating point number, so return failure. */ + + switch (*tokptr++) + { + case '.': + /* Accept and then look for fractional part and/or exponent. */ + *copy++ = '.'; + break; + + case 'e': + case 'E': + case 'd': + case 'D': + if (copy == buf) + { + return (0); + } + *copy++ = 'e'; + goto collect_exponent; + break; + + default: + return (0); + break; + } + + /* We found a '.', copy any fractional digits to the conversion buffer, up + to the first nondigit, non-underscore character. */ + + while (isdigit (*tokptr) || *tokptr == '_') + { + if (*tokptr != '_') + { + *copy++ = *tokptr; + } + tokptr++; + } + + /* Look for an exponent, which must start with one of [eEdD]. If none + is found, jump directly to trying to convert what we have collected + so far. */ + + switch (*tokptr) + { + case 'e': + case 'E': + case 'd': + case 'D': + *copy++ = 'e'; + tokptr++; + break; + default: + goto convert_float; + break; + } + + /* Accept an optional '-' or '+' following one of [eEdD]. */ + + collect_exponent: + if (*tokptr == '+' || *tokptr == '-') + { + *copy++ = *tokptr++; + } + + /* Now copy an exponent into the conversion buffer. Note that at the + moment underscores are *not* allowed in exponents. */ + + while (isdigit (*tokptr)) + { + *copy++ = *tokptr++; + } + + /* If we transfered any chars to the conversion buffer, try to interpret its + contents as a floating point value. If any characters remain, then we + must not have a valid floating point string. */ + + convert_float: + *copy = '\0'; + if (copy != buf) + { + dval = strtod (buf, ©); + if (*copy == '\0') + { + yylval.dval = dval; + lexptr = tokptr; + return (FLOAT_LITERAL); + } + } + return (0); +} + +/* Recognize a string literal. A string literal is a sequence + of characters enclosed in matching single or double quotes, except that + a single character inside single quotes is a character literal, which + we reject as a string literal. To embed the terminator character inside + a string, it is simply doubled (I.E. "this""is""one""string") */ + +static enum ch_terminal +match_string_literal () +{ + char *tokptr = lexptr; + int in_ctrlseq = 0; + LONGEST ival; + + for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++) + { + CHECKBUF (1); + tryagain: ; + if (in_ctrlseq) + { + /* skip possible whitespaces */ + while ((*tokptr == ' ' || *tokptr == '\t') && *tokptr) + tokptr++; + if (*tokptr == ')') + { + in_ctrlseq = 0; + tokptr++; + goto tryagain; + } + else if (*tokptr != ',') + error ("Invalid control sequence"); + tokptr++; + /* skip possible whitespaces */ + while ((*tokptr == ' ' || *tokptr == '\t') && *tokptr) + tokptr++; + if (!decode_integer_literal (&ival, &tokptr)) + error ("Invalid control sequence"); + tokptr--; + } + else if (*tokptr == *lexptr) + { + if (*(tokptr + 1) == *lexptr) + { + ival = *tokptr++; + } + else + { + break; + } + } + else if (*tokptr == '^') + { + if (*(tokptr + 1) == '(') + { + in_ctrlseq = 1; + tokptr += 2; + if (!decode_integer_literal (&ival, &tokptr)) + error ("Invalid control sequence"); + tokptr--; + } + else if (*(tokptr + 1) == '^') + ival = *tokptr++; + else + error ("Invalid control sequence"); + } + else + ival = *tokptr; + tempbuf[tempbufindex++] = ival; + } + if (in_ctrlseq) + error ("Invalid control sequence"); + + if (*tokptr == '\0' /* no terminator */ + || (tempbufindex == 1 && *tokptr == '\'')) /* char literal */ + { + return (0); + } + else + { + tempbuf[tempbufindex] = '\0'; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = ++tokptr; + return (CHARACTER_STRING_LITERAL); + } +} + +/* Recognize a character literal. A character literal is single character + or a control sequence, enclosed in single quotes. A control sequence + is a comma separated list of one or more integer literals, enclosed + in parenthesis and introduced with a circumflex character. + + EX: 'a' '^(7)' '^(7,8)' + + As a GNU chill extension, the syntax C'xx' is also recognized as a + character literal, where xx is a hex value for the character. + + Note that more than a single character, enclosed in single quotes, is + a string literal. + + Returns CHARACTER_LITERAL if a match is found. + */ + +static enum ch_terminal +match_character_literal () +{ + char *tokptr = lexptr; + LONGEST ival = 0; + + if ((*tokptr == 'c' || *tokptr == 'C') && (*(tokptr + 1) == '\'')) + { + /* We have a GNU chill extension form, so skip the leading "C'", + decode the hex value, and then ensure that we have a trailing + single quote character. */ + tokptr += 2; + if (!decode_integer_value (16, &tokptr, &ival) || (*tokptr != '\'')) + { + return (0); + } + tokptr++; + } + else if (*tokptr == '\'') + { + tokptr++; + + /* Determine which form we have, either a control sequence or the + single character form. */ + + if (*tokptr == '^') + { + if (*(tokptr + 1) == '(') + { + /* Match and decode a control sequence. Return zero if we don't + find a valid integer literal, or if the next unconsumed character + after the integer literal is not the trailing ')'. */ + tokptr += 2; + if (!decode_integer_literal (&ival, &tokptr) || (*tokptr++ != ')')) + { + return (0); + } + } + else if (*(tokptr + 1) == '^') + { + ival = *tokptr; + tokptr += 2; + } + else + /* fail */ + error ("Invalid control sequence"); + } + else if (*tokptr == '\'') + { + /* this must be duplicated */ + ival = *tokptr; + tokptr += 2; + } + else + { + ival = *tokptr++; + } + + /* The trailing quote has not yet been consumed. If we don't find + it, then we have no match. */ + + if (*tokptr++ != '\'') + { + return (0); + } + } + else + { + /* Not a character literal. */ + return (0); + } + yylval.typed_val.val = ival; + yylval.typed_val.type = builtin_type_chill_char; + lexptr = tokptr; + return (CHARACTER_LITERAL); +} + +/* Recognize an integer literal, as specified in Z.200 sec 5.2.4.2. + Note that according to 5.2.4.2, a single "_" is also a valid integer + literal, however GNU-chill requires there to be at least one "digit" + in any integer literal. */ + +static enum ch_terminal +match_integer_literal () +{ + char *tokptr = lexptr; + LONGEST ival; + + if (!decode_integer_literal (&ival, &tokptr)) + { + return (0); + } + else + { + yylval.typed_val.val = ival; +#if defined(CC_HAS_LONG_LONG) && defined(__STDC__) + if (ival > (LONGEST)2147483647U || ival < -(LONGEST)2147483648U) + yylval.typed_val.type = builtin_type_long_long; + else +#endif + yylval.typed_val.type = builtin_type_int; + lexptr = tokptr; + return (INTEGER_LITERAL); + } +} + +/* Recognize a bit-string literal, as specified in Z.200 sec 5.2.4.8 + Note that according to 5.2.4.8, a single "_" is also a valid bit-string + literal, however GNU-chill requires there to be at least one "digit" + in any bit-string literal. */ + +static enum ch_terminal +match_bitstring_literal () +{ + register char *tokptr = lexptr; + int bitoffset = 0; + int bitcount = 0; + int bits_per_char; + int digit; + + tempbufindex = 0; + CHECKBUF (1); + tempbuf[0] = 0; + + /* Look for the required explicit base specifier. */ + + switch (*tokptr++) + { + case 'b': + case 'B': + bits_per_char = 1; + break; + case 'o': + case 'O': + bits_per_char = 3; + break; + case 'h': + case 'H': + bits_per_char = 4; + break; + default: + return (0); + break; + } + + /* Ensure that the character after the explicit base is a single quote. */ + + if (*tokptr++ != '\'') + { + return (0); + } + + while (*tokptr != '\0' && *tokptr != '\'') + { + digit = *tokptr; + if (isupper (digit)) + digit = tolower (digit); + tokptr++; + switch (digit) + { + case '_': + continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + digit -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + digit -= 'a'; + digit += 10; + break; + default: + /* this is not a bitstring literal, probably an integer */ + return 0; + } + if (digit >= 1 << bits_per_char) + { + /* Found something not in domain for current base. */ + error ("Too-large digit in bitstring or integer."); + } + else + { + /* Extract bits from digit, packing them into the bitstring byte. */ + int k = TARGET_BYTE_ORDER == BIG_ENDIAN ? bits_per_char - 1 : 0; + for (; TARGET_BYTE_ORDER == BIG_ENDIAN ? k >= 0 : k < bits_per_char; + TARGET_BYTE_ORDER == BIG_ENDIAN ? k-- : k++) + { + bitcount++; + if (digit & (1 << k)) + { + tempbuf[tempbufindex] |= + (TARGET_BYTE_ORDER == BIG_ENDIAN) + ? (1 << (HOST_CHAR_BIT - 1 - bitoffset)) + : (1 << bitoffset); + } + bitoffset++; + if (bitoffset == HOST_CHAR_BIT) + { + bitoffset = 0; + tempbufindex++; + CHECKBUF(1); + tempbuf[tempbufindex] = 0; + } + } + } + } + + /* Verify that we consumed everything up to the trailing single quote, + and that we found some bits (IE not just underbars). */ + + if (*tokptr++ != '\'') + { + return (0); + } + else + { + yylval.sval.ptr = tempbuf; + yylval.sval.length = bitcount; + lexptr = tokptr; + return (BIT_STRING_LITERAL); + } +} + +struct token +{ + char *operator; + int token; +}; + +static const struct token idtokentab[] = +{ + { "array", ARRAY }, + { "length", LENGTH }, + { "lower", LOWER }, + { "upper", UPPER }, + { "andif", ANDIF }, + { "pred", PRED }, + { "succ", SUCC }, + { "card", CARD }, + { "size", SIZE }, + { "orif", ORIF }, + { "num", NUM }, + { "abs", ABS }, + { "max", MAX_TOKEN }, + { "min", MIN_TOKEN }, + { "mod", MOD }, + { "rem", REM }, + { "not", NOT }, + { "xor", LOGXOR }, + { "and", LOGAND }, + { "in", IN }, + { "or", LOGIOR }, + { "up", UP }, + { "addr", ADDR_TOKEN }, + { "null", EMPTINESS_LITERAL } +}; + +static const struct token tokentab2[] = +{ + { ":=", GDB_ASSIGNMENT }, + { "//", SLASH_SLASH }, + { "->", POINTER }, + { "/=", NOTEQUAL }, + { "<=", LEQ }, + { ">=", GEQ } +}; + +/* Read one token, getting characters through lexptr. */ +/* This is where we will check to make sure that the language and the + operators used are compatible. */ + +static enum ch_terminal +ch_lex () +{ + unsigned int i; + enum ch_terminal token; + char *inputname; + struct symbol *sym; + + /* Skip over any leading whitespace. */ + while (isspace (*lexptr)) + { + lexptr++; + } + /* Look for special single character cases which can't be the first + character of some other multicharacter token. */ + switch (*lexptr) + { + case '\0': + return END_TOKEN; + case ',': + case '=': + case ';': + case '!': + case '+': + case '*': + case '(': + case ')': + case '[': + case ']': + return (*lexptr++); + } + /* Look for characters which start a particular kind of multicharacter + token, such as a character literal, register name, convenience + variable name, string literal, etc. */ + switch (*lexptr) + { + case '\'': + case '\"': + /* First try to match a string literal, which is any + sequence of characters enclosed in matching single or double + quotes, except that a single character inside single quotes + is a character literal, so we have to catch that case also. */ + token = match_string_literal (); + if (token != 0) + { + return (token); + } + if (*lexptr == '\'') + { + token = match_character_literal (); + if (token != 0) + { + return (token); + } + } + break; + case 'C': + case 'c': + token = match_character_literal (); + if (token != 0) + { + return (token); + } + break; + case '$': + yylval.sval.ptr = lexptr; + do { + lexptr++; + } while (isalnum (*lexptr) || *lexptr == '_' || *lexptr == '$'); + yylval.sval.length = lexptr - yylval.sval.ptr; + write_dollar_variable (yylval.sval); + return GDB_VARIABLE; + break; + } + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++) + { + if (STREQN (lexptr, tokentab2[i].operator, 2)) + { + lexptr += 2; + return (tokentab2[i].token); + } + } + /* Look for single character cases which which could be the first + character of some other multicharacter token, but aren't, or we + would already have found it. */ + switch (*lexptr) + { + case '-': + case ':': + case '/': + case '<': + case '>': + return (*lexptr++); + } + /* Look for a float literal before looking for an integer literal, so + we match as much of the input stream as possible. */ + token = match_float_literal (); + if (token != 0) + { + return (token); + } + token = match_bitstring_literal (); + if (token != 0) + { + return (token); + } + token = match_integer_literal (); + if (token != 0) + { + return (token); + } + + /* Try to match a simple name string, and if a match is found, then + further classify what sort of name it is and return an appropriate + token. Note that attempting to match a simple name string consumes + the token from lexptr, so we can't back out if we later find that + we can't classify what sort of name it is. */ + + inputname = match_simple_name_string (); + + if (inputname != NULL) + { + char *simplename = (char*) alloca (strlen (inputname) + 1); + + char *dptr = simplename, *sptr = inputname; + for (; *sptr; sptr++) + *dptr++ = isupper (*sptr) ? tolower(*sptr) : *sptr; + *dptr = '\0'; + + /* See if it is a reserved identifier. */ + for (i = 0; i < sizeof (idtokentab) / sizeof (idtokentab[0]); i++) + { + if (STREQ (simplename, idtokentab[i].operator)) + { + return (idtokentab[i].token); + } + } + + /* Look for other special tokens. */ + if (STREQ (simplename, "true")) + { + yylval.ulval = 1; + return (BOOLEAN_LITERAL); + } + if (STREQ (simplename, "false")) + { + yylval.ulval = 0; + return (BOOLEAN_LITERAL); + } + + sym = lookup_symbol (inputname, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym == NULL && strcmp (inputname, simplename) != 0) + { + sym = lookup_symbol (simplename, expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + } + if (sym != NULL) + { + yylval.ssym.stoken.ptr = NULL; + yylval.ssym.stoken.length = 0; + yylval.ssym.sym = sym; + yylval.ssym.is_a_field_of_this = 0; /* FIXME, C++'ism */ + switch (SYMBOL_CLASS (sym)) + { + case LOC_BLOCK: + /* Found a procedure name. */ + return (GENERAL_PROCEDURE_NAME); + case LOC_STATIC: + /* Found a global or local static variable. */ + return (LOCATION_NAME); + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + if (innermost_block == NULL + || contained_in (block_found, innermost_block)) + { + innermost_block = block_found; + } + return (LOCATION_NAME); + break; + case LOC_CONST: + case LOC_LABEL: + return (LOCATION_NAME); + break; + case LOC_TYPEDEF: + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + case LOC_UNDEF: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + error ("Symbol \"%s\" names no location.", inputname); + break; + case LOC_UNRESOLVED: + error ("unhandled SYMBOL_CLASS in ch_lex()"); + break; + } + } + 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.", inputname); + } + } + + /* Catch single character tokens which are not part of some + longer token. */ + + switch (*lexptr) + { + case '.': /* Not float for example. */ + lexptr++; + while (isspace (*lexptr)) lexptr++; + inputname = match_simple_name_string (); + if (!inputname) + return '.'; + return FIELD_NAME; + } + + return (ILLEGAL_TOKEN); +} + +static void +write_lower_upper_value (opcode, type) + enum exp_opcode opcode; /* Either UNOP_LOWER or UNOP_UPPER */ + struct type *type; +{ + if (type == NULL) + write_exp_elt_opcode (opcode); + else + { + extern LONGEST type_lower_upper (); + struct type *result_type; + LONGEST val = type_lower_upper (opcode, type, &result_type); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (result_type); + write_exp_elt_longcst (val); + write_exp_elt_opcode (OP_LONG); + } +} + +void +chill_error (msg) + char *msg; +{ + /* Never used. */ +} diff --git a/contrib/gdb/gdb/ch-lang.c b/contrib/gdb/gdb/ch-lang.c new file mode 100644 index 000000000000..8504d670a52f --- /dev/null +++ b/contrib/gdb/gdb/ch-lang.c @@ -0,0 +1,653 @@ +/* Chill language support routines for GDB, the GNU debugger. + Copyright 1992, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "ch-lang.h" + + +/* For now, Chill uses a simple mangling algorithm whereby you simply + discard everything after the occurance of two successive CPLUS_MARKER + characters to derive the demangled form. */ + +char * +chill_demangle (mangled) + const char *mangled; +{ + const char *joiner = NULL; + char *demangled; + const char *cp = mangled; + + while (*cp) + { + if (is_cplus_marker (*cp)) + { + joiner = cp; + break; + } + cp++; + } + if (joiner != NULL && *(joiner + 1) == *joiner) + { + demangled = savestring (mangled, joiner - mangled); + } + else + { + demangled = NULL; + } + return (demangled); +} + +static void +chill_printchar (c, stream) + register int c; + GDB_FILE *stream; +{ + c &= 0xFF; /* Avoid sign bit follies */ + + if (PRINT_LITERAL_FORM (c)) + { + if (c == '\'' || c == '^') + fprintf_filtered (stream, "'%c%c'", c, c); + else + fprintf_filtered (stream, "'%c'", c); + } + else + { + fprintf_filtered (stream, "'^(%u)'", (unsigned int) c); + } +} + +/* 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. + Note that gdb maintains the length of strings without counting the + terminating null byte, while chill strings are typically written with + an explicit null byte. So we always assume an implied null byte + until gdb is able to maintain non-null terminated strings as well + as null terminated strings (FIXME). + */ + +static void +chill_printstr (stream, string, length, force_ellipses) + GDB_FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_literal_form = 0; + int in_control_form = 0; + int need_slashslash = 0; + unsigned int c; + extern int repeat_count_threshold; + extern int print_max; + + if (length == 0) + { + fputs_filtered ("\"\"", stream); + return; + } + + for (i = 0; i < length && things_printed < 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_slashslash) + { + fputs_filtered ("//", stream); + need_slashslash = 0; + } + + rep1 = i + 1; + reps = 1; + while (rep1 < length && string[rep1] == string[i]) + { + ++rep1; + ++reps; + } + + c = string[i]; + if (reps > repeat_count_threshold) + { + if (in_control_form || in_literal_form) + { + if (in_control_form) + fputs_filtered (")", stream); + fputs_filtered ("\"//", stream); + in_control_form = in_literal_form = 0; + } + chill_printchar (c, stream); + fprintf_filtered (stream, "", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_slashslash = 1; + } + else + { + if (! in_literal_form && ! in_control_form) + fputs_filtered ("\"", stream); + if (PRINT_LITERAL_FORM (c)) + { + if (!in_literal_form) + { + if (in_control_form) + { + fputs_filtered (")", stream); + in_control_form = 0; + } + in_literal_form = 1; + } + fprintf_filtered (stream, "%c", c); + if (c == '"' || c == '^') + /* duplicate this one as must be done at input */ + fprintf_filtered (stream, "%c", c); + } + else + { + if (!in_control_form) + { + if (in_literal_form) + { + in_literal_form = 0; + } + fputs_filtered ("^(", stream); + in_control_form = 1; + } + else + fprintf_filtered (stream, ","); + c = c & 0xff; + fprintf_filtered (stream, "%u", (unsigned int) c); + } + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_control_form) + { + fputs_filtered (")", stream); + } + if (in_literal_form || in_control_form) + { + fputs_filtered ("\"", stream); + } + if (force_ellipses || (i < length)) + { + fputs_filtered ("...", stream); + } +} + +static struct type * +chill_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, 2, 0, "", objfile); + warning ("internal error: no chill fundamental type %d", typeid); + break; + case FT_VOID: + /* FIXME: Currently the GNU Chill compiler emits some DWARF entries for + typedefs, unrelated to anything directly in the code being compiled, + that have some FT_VOID types. Just fake it for now. */ + type = init_type (TYPE_CODE_VOID, 0, 0, "", objfile); + break; + case FT_BOOLEAN: + type = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, "BOOL", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, "CHAR", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, 1, 0, "BYTE", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, "UBYTE", objfile); + break; + case FT_SHORT: /* Chill ints are 2 bytes */ + type = init_type (TYPE_CODE_INT, 2, 0, "INT", objfile); + break; + case FT_UNSIGNED_SHORT: /* Chill ints are 2 bytes */ + type = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, "UINT", objfile); + break; + case FT_INTEGER: /* FIXME? */ + case FT_SIGNED_INTEGER: /* FIXME? */ + case FT_LONG: /* Chill longs are 4 bytes */ + case FT_SIGNED_LONG: /* Chill longs are 4 bytes */ + type = init_type (TYPE_CODE_INT, 4, 0, "LONG", objfile); + break; + case FT_UNSIGNED_INTEGER: /* FIXME? */ + case FT_UNSIGNED_LONG: /* Chill longs are 4 bytes */ + type = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, "ULONG", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, 4, 0, "REAL", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, 8, 0, "LONG_REAL", objfile); + break; + } + return (type); +} + + +/* Table of operators and their precedences for printing expressions. */ + +static const struct op_print chill_op_print_tab[] = { + {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"MOD", BINOP_MOD, PREC_MUL, 0}, + {"REM", BINOP_REM, PREC_MUL, 0}, + {"SIZE",UNOP_SIZEOF, PREC_BUILTIN_FUNCTION, 0}, + {"LOWER",UNOP_LOWER, PREC_BUILTIN_FUNCTION, 0}, + {"UPPER",UNOP_UPPER, PREC_BUILTIN_FUNCTION, 0}, + {"CARD",UNOP_CARD, PREC_BUILTIN_FUNCTION, 0}, + {"MAX",UNOP_CHMAX, PREC_BUILTIN_FUNCTION, 0}, + {"MIN",UNOP_CHMIN, PREC_BUILTIN_FUNCTION, 0}, + {":=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"=", BINOP_EQUAL, PREC_EQUAL, 0}, + {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"//", BINOP_CONCAT, PREC_PREFIX, 0}, /* FIXME: precedence? */ + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"->", UNOP_IND, PREC_SUFFIX, 1}, + {"->", UNOP_ADDR, PREC_PREFIX, 0}, + {":", BINOP_RANGE, PREC_ASSIGN, 0}, + {NULL, 0, 0, 0} +}; + +/* The built-in types of Chill. */ + +struct type *builtin_type_chill_bool; +struct type *builtin_type_chill_char; +struct type *builtin_type_chill_long; +struct type *builtin_type_chill_ulong; +struct type *builtin_type_chill_real; + +struct type ** const (chill_builtin_types[]) = +{ + &builtin_type_chill_bool, + &builtin_type_chill_char, + &builtin_type_chill_long, + &builtin_type_chill_ulong, + &builtin_type_chill_real, + 0 +}; + +/* Calculate LOWER or UPPER of TYPE. + Returns the result as an integer. + *RESULT_TYPE is the appropriate type for the result. */ + +LONGEST +type_lower_upper (op, type, result_type) + enum exp_opcode op; /* Either UNOP_LOWER or UNOP_UPPER */ + struct type *type; + struct type **result_type; +{ + LONGEST low, high; + *result_type = type; + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + *result_type = builtin_type_int; + if (chill_varying_type (type)) + return type_lower_upper (op, TYPE_FIELD_TYPE (type, 1), result_type); + break; + case TYPE_CODE_ARRAY: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_STRING: + type = TYPE_FIELD_TYPE (type, 0); /* Get index type */ + + /* ... fall through ... */ + case TYPE_CODE_RANGE: + *result_type = TYPE_TARGET_TYPE (type); + return op == UNOP_LOWER ? TYPE_LOW_BOUND (type) : TYPE_HIGH_BOUND (type); + + case TYPE_CODE_ENUM: + case TYPE_CODE_BOOL: + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + if (get_discrete_bounds (type, &low, &high) >= 0) + { + *result_type = type; + return op == UNOP_LOWER ? low : high; + } + break; + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_REF: + case TYPE_CODE_COMPLEX: + default: + break; + } + error ("unknown mode for LOWER/UPPER builtin"); +} + +static value_ptr +value_chill_length (val) + value_ptr val; +{ + LONGEST tmp; + struct type *type = VALUE_TYPE (val); + struct type *ttype; + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_STRING: + tmp = type_lower_upper (UNOP_UPPER, type, &ttype) + - type_lower_upper (UNOP_LOWER, type, &ttype) + 1; + break; + case TYPE_CODE_STRUCT: + if (chill_varying_type (type)) + { + tmp = unpack_long (TYPE_FIELD_TYPE (type, 0), VALUE_CONTENTS (val)); + break; + } + /* ... else fall through ... */ + default: + error ("bad argument to LENGTH builtin"); + } + return value_from_longest (builtin_type_int, tmp); +} + +static value_ptr +value_chill_card (val) + value_ptr val; +{ + LONGEST tmp = 0; + struct type *type = VALUE_TYPE (val); + CHECK_TYPEDEF (type); + + if (TYPE_CODE (type) == TYPE_CODE_SET) + { + struct type *range_type = TYPE_INDEX_TYPE (type); + LONGEST lower_bound, upper_bound; + int i; + + get_discrete_bounds (range_type, &lower_bound, &upper_bound); + for (i = lower_bound; i <= upper_bound; i++) + if (value_bit_index (type, VALUE_CONTENTS (val), i) > 0) + tmp++; + } + else + error ("bad argument to CARD builtin"); + + return value_from_longest (builtin_type_int, tmp); +} + +static value_ptr +value_chill_max_min (op, val) + enum exp_opcode op; + value_ptr val; +{ + LONGEST tmp = 0; + struct type *type = VALUE_TYPE (val); + struct type *elttype; + CHECK_TYPEDEF (type); + + if (TYPE_CODE (type) == TYPE_CODE_SET) + { + LONGEST lower_bound, upper_bound; + int i, empty = 1; + + elttype = TYPE_INDEX_TYPE (type); + CHECK_TYPEDEF (elttype); + get_discrete_bounds (elttype, &lower_bound, &upper_bound); + + if (op == UNOP_CHMAX) + { + for (i = upper_bound; i >= lower_bound; i--) + { + if (value_bit_index (type, VALUE_CONTENTS (val), i) > 0) + { + tmp = i; + empty = 0; + break; + } + } + } + else + { + for (i = lower_bound; i <= upper_bound; i++) + { + if (value_bit_index (type, VALUE_CONTENTS (val), i) > 0) + { + tmp = i; + empty = 0; + break; + } + } + } + if (empty) + error ("%s for empty powerset", op == UNOP_CHMAX ? "MAX" : "MIN"); + } + else + error ("bad argument to %s builtin", op == UNOP_CHMAX ? "MAX" : "MIN"); + + return value_from_longest (TYPE_CODE (elttype) == TYPE_CODE_RANGE + ? TYPE_TARGET_TYPE (elttype) + : elttype, + tmp); +} + +static value_ptr +evaluate_subexp_chill (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + int pc = *pos; + struct type *type; + int tem, nargs; + value_ptr arg1; + value_ptr *argvec; + enum exp_opcode op = exp->elts[*pos].opcode; + switch (op) + { + case MULTI_SUBSCRIPT: + if (noside == EVAL_SKIP) + break; + (*pos) += 3; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + type = check_typedef (VALUE_TYPE (arg1)); + + if (nargs == 1 && TYPE_CODE (type) == TYPE_CODE_INT) + { + /* Looks like string repetition. */ + value_ptr string = evaluate_subexp_with_coercion (exp, pos, noside); + return value_concat (arg1, string); + } + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + type = check_typedef (TYPE_TARGET_TYPE (type)); + if (!type || TYPE_CODE (type) != TYPE_CODE_FUNC) + error ("reference value used as function"); + /* ... fall through ... */ + case TYPE_CODE_FUNC: + /* It's a function call. */ + if (noside == EVAL_AVOID_SIDE_EFFECTS) + break; + + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + argvec = (value_ptr *) alloca (sizeof (value_ptr) * (nargs + 2)); + argvec[0] = arg1; + tem = 1; + for (; tem <= nargs && tem <= TYPE_NFIELDS (type); tem++) + { + argvec[tem] + = evaluate_subexp_chill (TYPE_FIELD_TYPE (type, tem-1), + exp, pos, noside); + } + for (; tem <= nargs; tem++) + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + argvec[tem] = 0; /* signal end of arglist */ + + return call_function_by_hand (argvec[0], nargs, argvec + 1); + default: + break; + } + + while (nargs-- > 0) + { + value_ptr index = evaluate_subexp_with_coercion (exp, pos, noside); + arg1 = value_subscript (arg1, index); + } + return (arg1); + + case UNOP_LOWER: + case UNOP_UPPER: + (*pos)++; + if (noside == EVAL_SKIP) + { + (*exp->language_defn->evaluate_exp) (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + arg1 = (*exp->language_defn->evaluate_exp) (NULL_TYPE, exp, pos, + EVAL_AVOID_SIDE_EFFECTS); + tem = type_lower_upper (op, VALUE_TYPE (arg1), &type); + return value_from_longest (type, tem); + + case UNOP_LENGTH: + (*pos)++; + arg1 = (*exp->language_defn->evaluate_exp) (NULL_TYPE, exp, pos, noside); + return value_chill_length (arg1); + + case UNOP_CARD: + (*pos)++; + arg1 = (*exp->language_defn->evaluate_exp) (NULL_TYPE, exp, pos, noside); + return value_chill_card (arg1); + + case UNOP_CHMAX: + case UNOP_CHMIN: + (*pos)++; + arg1 = (*exp->language_defn->evaluate_exp) (NULL_TYPE, exp, pos, noside); + return value_chill_max_min (op, arg1); + + case BINOP_COMMA: + error ("',' operator used in invalid context"); + + default: + break; + } + + return evaluate_subexp_standard (expect_type, exp, pos, noside); + nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +const struct language_defn chill_language_defn = { + "chill", + language_chill, + chill_builtin_types, + range_check_on, + type_check_on, + chill_parse, /* parser */ + chill_error, /* parser error function */ + evaluate_subexp_chill, + chill_printchar, /* print a character constant */ + chill_printstr, /* function to print a string constant */ + chill_create_fundamental_type,/* Create fundamental type in this language */ + chill_print_type, /* Print a type using appropriate syntax */ + chill_val_print, /* Print a value using appropriate syntax */ + chill_value_print, /* Print a top-levl value */ + {"", "B'", "", ""}, /* Binary format info */ + {"O'%lo", "O'", "o", ""}, /* Octal format info */ + {"D'%ld", "D'", "d", ""}, /* Decimal format info */ + {"H'%lx", "H'", "x", ""}, /* Hex format info */ + chill_op_print_tab, /* expression operators for printing */ + 0, /* arrays are first-class (not c-style) */ + 0, /* String lower bound */ + &builtin_type_chill_char, /* Type of string elements */ + LANG_MAGIC +}; + +/* Initialization for Chill */ + +void +_initialize_chill_language () +{ + builtin_type_chill_bool = + init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "BOOL", (struct objfile *) NULL); + builtin_type_chill_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CHAR", (struct objfile *) NULL); + builtin_type_chill_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, + "LONG", (struct objfile *) NULL); + builtin_type_chill_ulong = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "ULONG", (struct objfile *) NULL); + builtin_type_chill_real = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "LONG_REAL", (struct objfile *) NULL); + + add_language (&chill_language_defn); +} diff --git a/contrib/gdb/gdb/ch-lang.h b/contrib/gdb/gdb/ch-lang.h new file mode 100644 index 000000000000..f09a35bf2df1 --- /dev/null +++ b/contrib/gdb/gdb/ch-lang.h @@ -0,0 +1,39 @@ +/* Chill language support definitions for GDB, the GNU debugger. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __STDC__ /* Forward decls for prototypes */ +struct value; +#endif + +extern int +chill_parse PARAMS ((void)); /* Defined in ch-exp.y */ + +extern void +chill_error PARAMS ((char *)); /* Defined in ch-exp.y */ + +extern void /* Defined in ch-typeprint.c */ +chill_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int)); + +extern int +chill_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int, + int, enum val_prettyprint)); + +extern int +chill_value_print PARAMS ((struct value *, GDB_FILE *, + int, enum val_prettyprint)); diff --git a/contrib/gdb/gdb/ch-typeprint.c b/contrib/gdb/gdb/ch-typeprint.c new file mode 100644 index 000000000000..a6b1944d3870 --- /dev/null +++ b/contrib/gdb/gdb/ch-typeprint.c @@ -0,0 +1,346 @@ +/* Support for printing Chill types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "ch-lang.h" +#include "typeprint.h" + +#include "gdb_string.h" +#include + +static void +chill_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int)); + +void +chill_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + GDB_FILE *stream; + int show; + int level; +{ + if (varstring != NULL && *varstring != '\0') + { + fputs_filtered (varstring, stream); + fputs_filtered (" ", stream); + } + chill_type_print_base (type, stream, show, level); +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element). + + SHOW nonzero means don't print this type as just its name; + show its real definition even if it has a name. + SHOW zero means print just typename or tag if there is one + SHOW negative means abbreviate structure elements. + SHOW is decremented for printing of structure elements. + + LEVEL is the depth to indent by. + We increase it for some recursive calls. */ + +static void +chill_type_print_base (type, stream, show, level) + struct type *type; + GDB_FILE *stream; + int show; + int level; +{ + register int len; + register int i; + struct type *index_type; + struct type *range_type; + LONGEST low_bound; + LONGEST high_bound; + + QUIT; + + wrap_here (" "); + if (type == NULL) + { + fputs_filtered ("", stream); + return; + } + + /* When SHOW is zero or less, and there is a valid type name, then always + just print the type name directly from the type. */ + + if ((show <= 0) && (TYPE_NAME (type) != NULL)) + { + fputs_filtered (TYPE_NAME (type), stream); + return; + } + + if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_TYPEDEF: + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + break; + case TYPE_CODE_PTR: + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID) + { + fprintf_filtered (stream, + TYPE_NAME (type) ? TYPE_NAME (type) : "PTR"); + break; + } + fprintf_filtered (stream, "REF "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + break; + + case TYPE_CODE_BOOL: + /* FIXME: we should probably just print the TYPE_NAME, in case + anyone ever fixes the compiler to give us the real names + in the presence of the chill equivalent of typedef (assuming + there is one). */ + fprintf_filtered (stream, + TYPE_NAME (type) ? TYPE_NAME (type) : "BOOL"); + break; + + case TYPE_CODE_ARRAY: + fputs_filtered ("ARRAY (", stream); + range_type = TYPE_FIELD_TYPE (type, 0); + if (TYPE_CODE (range_type) != TYPE_CODE_RANGE) + chill_print_type (range_type, "", stream, 0, level); + else + { + index_type = TYPE_TARGET_TYPE (range_type); + low_bound = TYPE_FIELD_BITPOS (range_type, 0); + high_bound = TYPE_FIELD_BITPOS (range_type, 1); + print_type_scalar (index_type, low_bound, stream); + fputs_filtered (":", stream); + print_type_scalar (index_type, high_bound, stream); + } + fputs_filtered (") ", stream); + chill_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, level); + break; + + case TYPE_CODE_BITSTRING: + fprintf_filtered (stream, "BOOLS (%d)", + TYPE_FIELD_BITPOS (TYPE_FIELD_TYPE(type,0), 1) + 1); + break; + + case TYPE_CODE_SET: + fputs_filtered ("POWERSET ", stream); + chill_print_type (TYPE_INDEX_TYPE (type), "", stream, + show - 1, level); + break; + + case TYPE_CODE_STRING: + range_type = TYPE_FIELD_TYPE (type, 0); + index_type = TYPE_TARGET_TYPE (range_type); + high_bound = TYPE_FIELD_BITPOS (range_type, 1); + fputs_filtered ("CHARS (", stream); + print_type_scalar (index_type, high_bound + 1, stream); + fputs_filtered (")", stream); + break; + + case TYPE_CODE_MEMBER: + fprintf_filtered (stream, "MEMBER "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + break; + case TYPE_CODE_REF: + fprintf_filtered (stream, "/*LOC*/ "); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + case TYPE_CODE_FUNC: + fprintf_filtered (stream, "PROC ("); + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + struct type *param_type = TYPE_FIELD_TYPE (type, i); + if (i > 0) + { + fputs_filtered (", ", stream); + wrap_here (" "); + } + if (TYPE_CODE (param_type) == TYPE_CODE_REF) + { + chill_type_print_base (TYPE_TARGET_TYPE (param_type), + stream, 0, level); + fputs_filtered (" LOC", stream); + } + else + chill_type_print_base (param_type, stream, show, level); + } + fprintf_filtered (stream, ")"); + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID) + { + fputs_filtered (" RETURNS (", stream); + chill_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + fputs_filtered (")", stream); + } + break; + + case TYPE_CODE_STRUCT: + if (chill_varying_type (type)) + { + chill_type_print_base (TYPE_FIELD_TYPE (type, 1), + stream, 0, level); + fputs_filtered (" VARYING", stream); + } + else + { + fprintf_filtered (stream, "STRUCT "); + + fprintf_filtered (stream, "(\n"); + if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0)) + { + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + fprintfi_filtered (level + 4, stream, "\n"); + } + else + { + fprintfi_filtered (level + 4, stream, "\n"); + } + } + else + { + len = TYPE_NFIELDS (type); + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + struct type *field_type = TYPE_FIELD_TYPE (type, i); + QUIT; + print_spaces_filtered (level + 4, stream); + if (TYPE_CODE (field_type) == TYPE_CODE_UNION) + { int j; /* variant number */ + fputs_filtered ("CASE OF\n", stream); + for (j = 0; j < TYPE_NFIELDS (field_type); j++) + { int k; /* variant field index */ + struct type *variant_type + = TYPE_FIELD_TYPE (field_type, j); + int var_len = TYPE_NFIELDS (variant_type); + print_spaces_filtered (level + 4, stream); + if (strcmp (TYPE_FIELD_NAME (field_type, j), + "else") == 0) + fputs_filtered ("ELSE\n", stream); + else + fputs_filtered (":\n", stream); + if (TYPE_CODE (variant_type) != TYPE_CODE_STRUCT) + error ("variant record confusion"); + for (k = 0; k < var_len; k++) + { + print_spaces_filtered (level + 8, stream); + chill_print_type (TYPE_FIELD_TYPE (variant_type, k), + TYPE_FIELD_NAME (variant_type, k), + stream, show - 1, level + 8); + if (k < (var_len - 1)) + fputs_filtered (",", stream); + fputs_filtered ("\n", stream); + } + } + print_spaces_filtered (level + 4, stream); + fputs_filtered ("ESAC", stream); + } + else + chill_print_type (field_type, + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4); + if (i < (len - 1)) + { + fputs_filtered (",", stream); + } + fputs_filtered ("\n", stream); + } + } + fprintfi_filtered (level, stream, ")"); + } + break; + + case TYPE_CODE_RANGE: + { + struct type *target = TYPE_TARGET_TYPE (type); + if (target && TYPE_NAME (target)) + fputs_filtered (TYPE_NAME (target), stream); + else + fputs_filtered ("RANGE", stream); + if (target == NULL) + target = builtin_type_long; + fputs_filtered (" (", stream); + print_type_scalar (target, TYPE_LOW_BOUND (type), stream); + fputs_filtered (":", stream); + print_type_scalar (target, TYPE_HIGH_BOUND (type), stream); + fputs_filtered (")", stream); + } + break; + + case TYPE_CODE_ENUM: + { + register int lastval = 0; + fprintf_filtered (stream, "SET ("); + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf_filtered (stream, ", "); + wrap_here (" "); + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + if (lastval != TYPE_FIELD_BITPOS (type, i)) + { + fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); + } + lastval++; + } + fprintf_filtered (stream, ")"); + } + break; + + case TYPE_CODE_VOID: + case TYPE_CODE_UNDEF: + case TYPE_CODE_ERROR: + case TYPE_CODE_UNION: + case TYPE_CODE_METHOD: + error ("missing language support in chill_type_print_base"); + break; + + default: + + /* Handle types not explicitly handled by the other cases, + such as fundamental types. For these, just print whatever + the type name is, as recorded in the type itself. If there + is no type name, then complain. */ + + if (TYPE_NAME (type) != NULL) + { + fputs_filtered (TYPE_NAME (type), stream); + } + else + { + error ("Unrecognized type code (%d) in symbol table.", + TYPE_CODE (type)); + } + break; + } +} diff --git a/contrib/gdb/gdb/ch-valprint.c b/contrib/gdb/gdb/ch-valprint.c new file mode 100644 index 000000000000..de66d46cfebe --- /dev/null +++ b/contrib/gdb/gdb/ch-valprint.c @@ -0,0 +1,664 @@ +/* Support for printing Chill values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "valprint.h" +#include "expression.h" +#include "value.h" +#include "language.h" +#include "demangle.h" +#include "c-lang.h" /* For c_val_print */ +#include "typeprint.h" +#include "ch-lang.h" +#include "annotate.h" + +static void +chill_print_value_fields PARAMS ((struct type *, char *, GDB_FILE *, int, int, + enum val_prettyprint, struct type **)); + + +/* Print integral scalar data VAL, of type TYPE, onto stdio stream STREAM. + Used to print data from type structures in a specified type. For example, + array bounds may be characters or booleans in some languages, and this + allows the ranges to be printed in their "natural" form rather than as + decimal integer values. */ + +void +chill_print_type_scalar (type, val, stream) + struct type *type; + LONGEST val; + GDB_FILE *stream; +{ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_RANGE: + if (TYPE_TARGET_TYPE (type)) + { + chill_print_type_scalar (TYPE_TARGET_TYPE (type), val, stream); + return; + } + break; + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_FUNC: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_REF: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_COMPLEX: + case TYPE_CODE_TYPEDEF: + default: + break; + } + print_type_scalar (type, val, stream); +} + +/* Print the elements of an array. + Similar to val_print_array_elements, but prints + element indexes (in Chill syntax). */ + +static void +chill_val_print_array_elements (type, valaddr, address, stream, + format, deref_ref, recurse, pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + unsigned int i = 0; + unsigned int things_printed = 0; + unsigned len; + struct type *elttype; + struct type *range_type = TYPE_FIELD_TYPE (type, 0); + struct type *index_type = TYPE_TARGET_TYPE (range_type); + unsigned eltlen; + /* Position of the array element we are examining to see + whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + LONGEST low_bound = TYPE_FIELD_BITPOS (range_type, 0); + + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + + annotate_array_section_begin (i, elttype); + + for (; i < len && things_printed < print_max; i++) + { + if (i != 0) + { + if (prettyprint_arrays) + { + fprintf_filtered (stream, ",\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + fprintf_filtered (stream, ", "); + } + } + wrap_here (n_spaces (2 + 2 * recurse)); + + rep1 = i + 1; + reps = 1; + while ((rep1 < len) && + !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) + { + ++reps; + ++rep1; + } + + fputs_filtered ("(", stream); + chill_print_type_scalar (index_type, low_bound + i, stream); + if (reps > 1) + { + fputs_filtered (":", stream); + chill_print_type_scalar (index_type, low_bound + i + reps - 1, + stream); + fputs_filtered ("): ", stream); + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + + i = rep1 - 1; + things_printed += 1; + } + else + { + fputs_filtered ("): ", stream); + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + annotate_elt (); + things_printed++; + } + } + annotate_array_section_end (); + if (i < len) + { + fprintf_filtered (stream, "..."); + } +} + +/* In certain cases it could happen, that an array type doesn't + have a length (this have to do with seizing). The reason is + shown in the following stabs: + + .stabs "m_x:Tt81=s36i:1,0,32;ar:82=ar80;0;1;83=xsm_struct:,32,256;;",128,0,25,0 + + .stabs "m_struct:Tt83=s16f1:9,0,16;f2:85=*84,32,32;f3:84,64,64;;",128,0,10,0 + + When processing t81, the array ar80 doesn't have a length, cause + struct m_struct is specified extern at thse moment. Afterwards m_struct + gets specified and updated, but not the surrounding type. + + So we walk through array's till we find a type with a length and + calculate the array length. + + FIXME: Where may this happen too ? + */ + +static void +calculate_array_length (type) + struct type *type; +{ + struct type *target_type; + struct type *range_type; + LONGEST lower_bound, upper_bound; + + if (TYPE_CODE (type) != TYPE_CODE_ARRAY) + /* not an array, stop processing */ + return; + + target_type = TYPE_TARGET_TYPE (type); + range_type = TYPE_FIELD_TYPE (type, 0); + lower_bound = TYPE_FIELD_BITPOS (range_type, 0); + upper_bound = TYPE_FIELD_BITPOS (range_type, 1); + + if (TYPE_LENGTH (target_type) == 0 && + TYPE_CODE (target_type) == TYPE_CODE_ARRAY) + /* we've got another array */ + calculate_array_length (target_type); + + TYPE_LENGTH (type) = (upper_bound - lower_bound + 1) * TYPE_LENGTH (target_type); +} + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter or 0 for natural format). The data at VALADDR is in + target byte order. + + If the data are a string pointer, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. */ + +int +chill_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + LONGEST val; + unsigned int i = 0; /* Number of characters printed. */ + struct type *elttype; + CORE_ADDR addr; + + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) == 0) + /* see comment function calculate_array_length */ + calculate_array_length (type); + + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + { + if (prettyprint_arrays) + { + print_spaces_filtered (2 + 2 * recurse, stream); + } + fprintf_filtered (stream, "["); + chill_val_print_array_elements (type, valaddr, address, stream, + format, deref_ref, recurse, pretty); + fprintf_filtered (stream, "]"); + } + else + { + error ("unimplemented in chill_val_print; unspecified array length"); + } + break; + + case TYPE_CODE_INT: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val_print_type_code_int (type, valaddr, stream); + } + break; + + case TYPE_CODE_CHAR: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), + stream); + } + break; + + case TYPE_CODE_FLT: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + print_floating (valaddr, type, stream); + } + break; + + case TYPE_CODE_BOOL: + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + /* FIXME: Why is this using builtin_type_chill_bool not type? */ + val = unpack_long (builtin_type_chill_bool, valaddr); + fprintf_filtered (stream, val ? "TRUE" : "FALSE"); + } + 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_PTR: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + addr = unpack_pointer (type, valaddr); + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + + /* We assume a NULL pointer is all zeros ... */ + if (addr == 0) + { + fputs_filtered ("NULL", stream); + return 0; + } + + if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) + { + /* Try to print what function it points to. */ + print_address_demangle (addr, stream, demangle); + /* Return value is irrelevant except for string pointers. */ + return (0); + } + if (addressprint && format != 's') + { + print_address_numeric (addr, 1, stream); + } + + /* For a pointer to char or unsigned char, also print the string + pointed to, unless pointer is null. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_CHAR + && (format == 0 || format == 's') + && addr != 0 + && /* If print_max is UINT_MAX, the alloca below will fail. + In that case don't try to print the string. */ + print_max < UINT_MAX) + { + i = val_print_string (addr, 0, stream); + } + /* Return number of characters printed, plus one for the + terminating null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + break; + + case TYPE_CODE_STRING: + i = TYPE_LENGTH (type); + LA_PRINT_STRING (stream, valaddr, i, 0); + /* Return number of characters printed, plus one for the terminating + null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + break; + + case TYPE_CODE_BITSTRING: + case TYPE_CODE_SET: + elttype = TYPE_INDEX_TYPE (type); + CHECK_TYPEDEF (elttype); + if (TYPE_FLAGS (elttype) & TYPE_FLAG_STUB) + { + fprintf_filtered (stream, ""); + gdb_flush (stream); + break; + } + { + 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); + + i = get_discrete_bounds (range, &low_bound, &high_bound); + maybe_bad_bstring: + if (i < 0) + { + fputs_filtered ("", stream); + goto done; + } + + for (i = low_bound; i <= high_bound; i++) + { + int element = value_bit_index (type, valaddr, i); + if (element < 0) + { + i = element; + goto maybe_bad_bstring; + } + if (is_bitstring) + fprintf_filtered (stream, "%d", element); + else if (element) + { + if (need_comma) + fputs_filtered (", ", stream); + chill_print_type_scalar (range, i, stream); + need_comma = 1; + + /* Look for a continuous range of true elements. */ + if (i+1 <= high_bound && value_bit_index (type, valaddr, ++i)) + { + int j = i; /* j is the upper bound so far of the range */ + fputs_filtered (":", stream); + while (i+1 <= high_bound + && value_bit_index (type, valaddr, ++i)) + j = i; + chill_print_type_scalar (range, j, stream); + } + } + } + done: + if (is_bitstring) + fputs_filtered ("'", stream); + else + fputs_filtered ("]", stream); + } + break; + + case TYPE_CODE_STRUCT: + if (chill_varying_type (type)) + { + struct type *inner = check_typedef (TYPE_FIELD_TYPE (type, 1)); + long length = unpack_long (TYPE_FIELD_TYPE (type, 0), valaddr); + char *data_addr = valaddr + TYPE_FIELD_BITPOS (type, 1) / 8; + + switch (TYPE_CODE (inner)) + { + case TYPE_CODE_STRING: + if (length > TYPE_LENGTH (type)) + { + fprintf_filtered (stream, + " static length %d>", + length, TYPE_LENGTH (type)); + } + LA_PRINT_STRING (stream, data_addr, length, 0); + return length; + default: + break; + } + } + chill_print_value_fields (type, valaddr, stream, format, recurse, pretty, + 0); + break; + + case TYPE_CODE_REF: + if (addressprint) + { + fprintf_filtered (stream, "LOC("); + print_address_numeric + (extract_address (valaddr, TARGET_PTR_BIT / HOST_CHAR_BIT), + 1, + stream); + fprintf_filtered (stream, ")"); + if (deref_ref) + fputs_filtered (": ", stream); + } + /* De-reference the reference. */ + if (deref_ref) + { + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF) + { + value_ptr deref_val = + value_at + (TYPE_TARGET_TYPE (type), + unpack_pointer (lookup_pointer_type (builtin_type_void), + valaddr)); + val_print (VALUE_TYPE (deref_val), + VALUE_CONTENTS (deref_val), + VALUE_ADDRESS (deref_val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fputs_filtered ("???", stream); + } + break; + + case TYPE_CODE_ENUM: + c_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + break; + + case TYPE_CODE_RANGE: + if (TYPE_TARGET_TYPE (type)) + chill_val_print (TYPE_TARGET_TYPE (type), valaddr, address, stream, + format, deref_ref, recurse, pretty); + break; + + case TYPE_CODE_MEMBER: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + default: + /* Let's defer printing to the C printer, rather than + print an error message. FIXME! */ + c_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + } + gdb_flush (stream); + return (0); +} + +/* Mutually recursive subroutines of cplus_print_value and c_val_print to + print out a structure's fields: cp_print_value_fields and cplus_print_value. + + TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the + same meanings as in cplus_print_value and c_val_print. + + DONT_PRINT is an array of baseclass types that we + should not print, or zero if called from top level. */ + +static void +chill_print_value_fields (type, valaddr, stream, format, recurse, pretty, + dont_print) + struct type *type; + char *valaddr; + GDB_FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print; +{ + int i, len; + int fields_seen = 0; + + CHECK_TYPEDEF (type); + + fprintf_filtered (stream, "["); + len = TYPE_NFIELDS (type); + if (len == 0) + { + fprintf_filtered (stream, ""); + } + else + { + for (i = 0; i < len; i++) + { + if (fields_seen) + { + fprintf_filtered (stream, ", "); + } + fields_seen = 1; + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + wrap_here (n_spaces (2 + 2 * recurse)); + } + fputs_filtered (".", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_chill, DMGL_NO_OPTS); + fputs_filtered (": ", stream); + if (TYPE_FIELD_PACKED (type, i)) + { + value_ptr v; + + /* Bitfields require special handling, especially due to byte + order problems. */ + v = value_from_longest (TYPE_FIELD_TYPE (type, i), + unpack_field_as_long (type, valaddr, i)); + + chill_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0, + stream, format, 0, recurse + 1, pretty); + } + else + { + chill_val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, 0, recurse + 1, pretty); + } + } + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + } + fprintf_filtered (stream, "]"); +} + +int +chill_value_print (val, stream, format, pretty) + value_ptr val; + GDB_FILE *stream; + int format; + enum val_prettyprint pretty; +{ + struct type *type = VALUE_TYPE (val); + struct type *real_type = check_typedef (type); + + /* If it is a pointer, indicate what it points to. + + Print type also if it is a reference. */ + + if (TYPE_CODE (real_type) == TYPE_CODE_PTR || + TYPE_CODE (real_type) == TYPE_CODE_REF) + { + char *valaddr = VALUE_CONTENTS (val); + CORE_ADDR addr = unpack_pointer (type, valaddr); + if (TYPE_CODE (type) != TYPE_CODE_PTR || addr != 0) + { + int i; + char *name = TYPE_NAME (type); + if (name) + fputs_filtered (name, stream); + else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID) + fputs_filtered ("PTR", stream); + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ")"); + } + fprintf_filtered (stream, "("); + i = val_print (type, valaddr, VALUE_ADDRESS (val), + stream, format, 1, 0, pretty); + fprintf_filtered (stream, ")"); + return i; + } + } + return (val_print (type, VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1, 0, pretty)); +} + + diff --git a/contrib/gdb/gdb/coff-solib.c b/contrib/gdb/gdb/coff-solib.c new file mode 100644 index 000000000000..c0cfcf5d7bda --- /dev/null +++ b/contrib/gdb/gdb/coff-solib.c @@ -0,0 +1,131 @@ +/* Handle COFF SVR3 shared libraries for GDB, the GNU Debugger. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "defs.h" + +#include "frame.h" +#include "bfd.h" +#include "gdbcore.h" +#include "symtab.h" + +/* + +GLOBAL FUNCTION + + coff_solib_add -- add a shared library files to the symtab list. We + examine the `.lib' section of the exec file and determine the names of + the shared libraries. + + 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. + +SYNOPSIS + + void coff_solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +coff_solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + asection *libsect; + + libsect = bfd_get_section_by_name (exec_bfd, ".lib"); + + if (libsect) + { + int libsize; + unsigned char *lib; + struct libent + { + bfd_byte len[4]; + bfd_byte nameoffset[4]; + }; + + libsize = bfd_section_size (exec_bfd, libsect); + + lib = (unsigned char *) alloca (libsize); + + bfd_get_section_contents (exec_bfd, libsect, lib, 0, libsize); + + while (libsize > 0) + { + struct libent *ent; + struct objfile *objfile; + int len, nameoffset; + char *filename; + + ent = (struct libent *)lib; + + len = bfd_get_32 (exec_bfd, ent->len); + + nameoffset = bfd_get_32 (exec_bfd, ent->nameoffset); + + if (len <= 0) + break; + + filename = (char *)ent + nameoffset * 4; + + objfile = symbol_file_add (filename, from_tty, + 0, /* addr */ + 0, /* not mainline */ + 0, /* not mapped */ + 0); /* Not readnow */ + libsize -= len * 4; + lib += len * 4; + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); + } +} + +/* + +GLOBAL FUNCTION + + coff_solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void coff_solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, the kernel maps in the shared + libraries. We get here with the target stopped at it's first + instruction, and the libraries already mapped. At this point, this + function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + */ + +void +coff_solib_create_inferior_hook() +{ + coff_solib_add ((char *) 0, 0, (struct target_ops *) 0); +} diff --git a/contrib/gdb/gdb/coff-solib.h b/contrib/gdb/gdb/coff-solib.h new file mode 100644 index 000000000000..d154234deb88 --- /dev/null +++ b/contrib/gdb/gdb/coff-solib.h @@ -0,0 +1,60 @@ +/* COFF (SVR3) Shared library declarations for GDB, the GNU Debugger. + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct target_ops; +#endif + +/* Called when we free all symtabs, to free the shared library information + as well. */ + +#if 0 +#define CLEAR_SOLIB coff_clear_solib + +extern void +coff_clear_solib PARAMS ((void)); +#endif + +/* Called to add symbols from a shared library to gdb's symbol table. */ + +#define SOLIB_ADD(filename, from_tty, targ) \ + coff_solib_add (filename, from_tty, targ) + +extern void +coff_solib_add PARAMS ((char *, int, struct target_ops *)); + +/* Function to be called when the inferior starts up, to discover the names + of shared libraries that are dynamically linked, the base addresses to + which they are linked, and sufficient information to read in their symbols + at a later time. */ + +#define SOLIB_CREATE_INFERIOR_HOOK(PID) coff_solib_create_inferior_hook() + +extern void +coff_solib_create_inferior_hook PARAMS((void)); /* solib.c */ + +/* If we can't set a breakpoint, and it's in a shared library, just + disable it. */ + +#if 0 +#define DISABLE_UNSETTABLE_BREAK(addr) coff_solib_address(addr) + +extern int +solib_address PARAMS ((CORE_ADDR)); /* solib.c */ +#endif diff --git a/contrib/gdb/gdb/coffread.c b/contrib/gdb/gdb/coffread.c new file mode 100644 index 000000000000..bd2a70097dba --- /dev/null +++ b/contrib/gdb/gdb/coffread.c @@ -0,0 +1,2164 @@ +/* Read coff symbol tables and convert to internal format, for GDB. + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996 + Free Software Foundation, Inc. + Contributed by David D. Johnson, Brown University (ddj@cs.brown.edu). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "breakpoint.h" + +#include "bfd.h" +#include "obstack.h" + +#include "gdb_string.h" +#include + +#include "coff/internal.h" /* Internal format of COFF symbols in BFD */ +#include "libcoff.h" /* FIXME secret internal data from BFD */ + +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "gdb-stabs.h" +#include "stabsread.h" +#include "complaints.h" +#include "target.h" + +struct coff_symfile_info { + file_ptr min_lineno_offset; /* Where in file lowest line#s are */ + file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ + + CORE_ADDR textaddr; /* Addr of .text section. */ + unsigned int textsize; /* Size of .text section. */ + struct stab_section_list *stabsects; /* .stab sections. */ + asection *stabstrsect; /* Section pointer for .stab section */ + char *stabstrdata; +}; + +/* Translate an external name string into a user-visible name. */ +#define EXTERNAL_NAME(string, abfd) \ + (string[0] == bfd_get_symbol_leading_char(abfd)? string+1: string) + +/* To be an sdb debug type, type must have at least a basic or primary + derived type. Using this rather than checking against T_NULL is + said to prevent core dumps if we try to operate on Michael Bloom + dbx-in-coff file. */ + +#define SDB_TYPE(type) (BTYPE(type) | (type & N_TMASK)) + +/* Convert from an sdb register number to an internal gdb register number. + This should be defined in tm.h, if REGISTER_NAMES is not set up + to map one to one onto the sdb register numbers. */ + +#ifndef SDB_REG_TO_REGNUM +# define SDB_REG_TO_REGNUM(value) (value) +#endif + +/* Core address of start and end of text of current source file. + This comes from a ".text" symbol where x_nlinno > 0. */ + +static CORE_ADDR current_source_start_addr; +static CORE_ADDR current_source_end_addr; + +/* The addresses of the symbol table stream and number of symbols + of the object file we are reading (as copied into core). */ + +static bfd *nlist_bfd_global; +static int nlist_nsyms_global; + +/* Vector of line number information. */ + +static struct linetable *line_vector; + +/* Index of next entry to go in line_vector_index. */ + +static int line_vector_index; + +/* Last line number recorded in the line vector. */ + +static int prev_line_number; + +/* Number of elements allocated for line_vector currently. */ + +static int line_vector_length; + +/* Pointers to scratch storage, used for reading raw symbols and auxents. */ + +static char *temp_sym; +static char *temp_aux; + +/* Local variables that hold the shift and mask values for the + COFF file that we are currently reading. These come back to us + from BFD, and are referenced by their macro names, as well as + internally to the BTYPE, ISPTR, ISFCN, ISARY, ISTAG, and DECREF + macros from include/coff/internal.h . */ + +static unsigned local_n_btmask; +static unsigned local_n_btshft; +static unsigned local_n_tmask; +static unsigned local_n_tshift; + +#define N_BTMASK local_n_btmask +#define N_BTSHFT local_n_btshft +#define N_TMASK local_n_tmask +#define N_TSHIFT local_n_tshift + +/* Local variables that hold the sizes in the file of various COFF structures. + (We only need to know this to read them from the file -- BFD will then + translate the data in them, into `internal_xxx' structs in the right + byte order, alignment, etc.) */ + +static unsigned local_linesz; +static unsigned local_symesz; +static unsigned local_auxesz; + +/* Chain of typedefs of pointers to empty struct/union types. + They are chained thru the SYMBOL_VALUE_CHAIN. */ + +static struct symbol *opaque_type_chain[HASHSIZE]; + +/* Complaints about various problems in the file being read */ + +struct complaint ef_complaint = + {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0}; + +struct complaint ef_stack_complaint = + {"`.ef' symbol without matching `.bf' symbol ignored starting at symnum %d", 0, 0}; + +struct complaint eb_stack_complaint = + {"`.eb' symbol without matching `.bb' symbol ignored starting at symnum %d", 0, 0}; + +struct complaint bf_no_aux_complaint = + {"`.bf' symbol %d has no aux entry", 0, 0}; + +struct complaint ef_no_aux_complaint = + {"`.ef' symbol %d has no aux entry", 0, 0}; + +struct complaint lineno_complaint = + {"Line number pointer %d lower than start of line numbers", 0, 0}; + +struct complaint unexpected_type_complaint = + {"Unexpected type for symbol %s", 0, 0}; + +struct complaint bad_sclass_complaint = + {"Bad n_sclass for symbol %s", 0, 0}; + +struct complaint misordered_blocks_complaint = + {"Blocks out of order at address %x", 0, 0}; + +struct complaint tagndx_bad_complaint = + {"Symbol table entry for %s has bad tagndx value", 0, 0}; + +struct complaint eb_complaint = + {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; + +/* Simplified internal version of coff symbol table information */ + +struct coff_symbol { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_naux; /* 0 if syment only, 1 if syment + auxent, etc */ + long c_value; + int c_sclass; + int c_secnum; + unsigned int c_type; +}; + +static struct type *coff_read_struct_type PARAMS ((int, int, int)); + +static struct type *decode_base_type PARAMS ((struct coff_symbol *, + unsigned int, + union internal_auxent *)); + +static struct type *decode_type PARAMS ((struct coff_symbol *, unsigned int, + union internal_auxent *)); + +static struct type *decode_function_type PARAMS ((struct coff_symbol *, + unsigned int, + union internal_auxent *)); + +static struct type *coff_read_enum_type PARAMS ((int, int, int)); + +static struct symbol *process_coff_symbol PARAMS ((struct coff_symbol *, + union internal_auxent *, + struct section_offsets *, + struct objfile *)); + +static void patch_opaque_types PARAMS ((struct symtab *)); + +static void patch_type PARAMS ((struct type *, struct type *)); + +static void enter_linenos PARAMS ((long, int, int, struct section_offsets *)); + +static void free_linetab PARAMS ((void)); + +static int init_lineno PARAMS ((bfd *, long, int)); + +static char *getsymname PARAMS ((struct internal_syment *)); + +static char *coff_getfilename PARAMS ((union internal_auxent *)); + +static void free_stringtab PARAMS ((void)); + +static int init_stringtab PARAMS ((bfd *, long)); + +static void read_one_sym PARAMS ((struct coff_symbol *, + struct internal_syment *, + union internal_auxent *)); + +static void coff_symtab_read PARAMS ((long, int, struct section_offsets *, + struct objfile *)); + +static void find_linenos PARAMS ((bfd *, sec_ptr, PTR)); + +static void coff_symfile_init PARAMS ((struct objfile *)); + +static void coff_new_init PARAMS ((struct objfile *)); + +static void coff_symfile_read PARAMS ((struct objfile *, + struct section_offsets *, int)); + +static void coff_symfile_finish PARAMS ((struct objfile *)); + +static void record_minimal_symbol PARAMS ((char *, CORE_ADDR, + enum minimal_symbol_type, + struct objfile *)); + +static void coff_end_symtab PARAMS ((struct objfile *)); + +static void complete_symtab PARAMS ((char *, CORE_ADDR, unsigned int)); + +static void coff_start_symtab PARAMS ((void)); + +static void coff_record_line PARAMS ((int, CORE_ADDR)); + +static struct type *coff_alloc_type PARAMS ((int)); + +static struct type **coff_lookup_type PARAMS ((int)); + +static void coff_locate_sections PARAMS ((bfd *, asection *, PTR)); + +/* We are called once per section from coff_symfile_read. We + need to examine each section we are passed, check to see + if it is something we are interested in processing, and + if so, stash away some access information for the section. + + FIXME: The section names should not be hardwired strings (what + should they be? I don't think most object file formats have enough + section flags to specify what kind of debug section it is + -kingdon). */ + +static void +coff_locate_sections (abfd, sectp, csip) + bfd *abfd; + asection *sectp; + PTR csip; +{ + register struct coff_symfile_info *csi; + const char *name; + + csi = (struct coff_symfile_info *) csip; + name = bfd_get_section_name (abfd, sectp); + if (STREQ (name, ".text")) + { + csi->textaddr = bfd_section_vma (abfd, sectp); + csi->textsize += bfd_section_size (abfd, sectp); + } + else if (strncmp (name, ".text", sizeof ".text" - 1) == 0) + { + csi->textsize += bfd_section_size (abfd, sectp); + } + else if (STREQ (name, ".stabstr")) + { + csi->stabstrsect = sectp; + } + else if (strncmp (name, ".stab", sizeof ".stab" - 1) == 0) + { + const char *s; + + /* We can have multiple .stab sections if linked with + --split-by-reloc. */ + for (s = name + sizeof ".stab" - 1; *s != '\0'; s++) + if (! isdigit (*s)) + break; + if (*s == '\0') + { + struct stab_section_list *n, **pn; + + n = ((struct stab_section_list *) + xmalloc (sizeof (struct stab_section_list))); + n->section = sectp; + n->next = NULL; + for (pn = &csi->stabsects; *pn != NULL; pn = &(*pn)->next) + ; + *pn = n; + + /* This will be run after coffstab_build_psymtabs is called + in coff_symfile_read, at which point we no longer need + the information. */ + make_cleanup (free, n); + } + } +} + +/* Return the section_offsets* that CS points to. */ +static int cs_to_section PARAMS ((struct coff_symbol *, struct objfile *)); + +struct find_targ_sec_arg { + int targ_index; + int *resultp; +}; + +static void find_targ_sec PARAMS ((bfd *, asection *, void *)); + +static void find_targ_sec (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR obj; +{ + struct find_targ_sec_arg *args = (struct find_targ_sec_arg *)obj; + if (sect->target_index == args->targ_index) + { + /* This is the section. Figure out what SECT_OFF_* code it is. */ + if (bfd_get_section_flags (abfd, sect) & SEC_CODE) + *args->resultp = SECT_OFF_TEXT; + else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) + *args->resultp = SECT_OFF_DATA; + else + *args->resultp = SECT_OFF_BSS; + } +} + +/* Return the section number (SECT_OFF_*) that CS points to. */ +static int +cs_to_section (cs, objfile) + struct coff_symbol *cs; + struct objfile *objfile; +{ + int off = SECT_OFF_TEXT; + struct find_targ_sec_arg args; + args.targ_index = cs->c_secnum; + args.resultp = &off; + bfd_map_over_sections (objfile->obfd, find_targ_sec, &args); + return off; +} + +/* Look up a coff type-number index. Return the address of the slot + where the type for that index is stored. + The type-number is in INDEX. + + This can be used for finding the type associated with that index + or for associating a new type with the index. */ + +static struct type ** +coff_lookup_type (index) + register int index; +{ + if (index >= type_vector_length) + { + int old_vector_length = type_vector_length; + + type_vector_length *= 2; + if (index /* is still */ >= type_vector_length) + type_vector_length = index * 2; + + type_vector = (struct type **) + xrealloc ((char *) type_vector, + type_vector_length * sizeof (struct type *)); + memset (&type_vector[old_vector_length], 0, + (type_vector_length - old_vector_length) * sizeof(struct type *)); + } + return &type_vector[index]; +} + +/* Make sure there is a type allocated for type number index + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +coff_alloc_type (index) + int index; +{ + register struct type **type_addr = coff_lookup_type (index); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == NULL) + { + type = alloc_type (current_objfile); + *type_addr = type; + } + return type; +} + +/* Record a line number entry for line LINE at address PC. + FIXME: Use record_line instead. */ + +static void +coff_record_line (line, pc) + int line; + CORE_ADDR pc; +{ + struct linetable_entry *e; + /* Make sure line vector is big enough. */ + + if (line_vector_index + 2 >= line_vector_length) + { + line_vector_length *= 2; + line_vector = (struct linetable *) + xrealloc ((char *) line_vector, sizeof (struct linetable) + + (line_vector_length + * sizeof (struct linetable_entry))); + } + + e = line_vector->item + line_vector_index++; + e->line = line; e->pc = pc; +} + +/* Start a new symtab for a new source file. + This is called when a COFF ".file" symbol is seen; + it indicates the start of data for one original source file. */ + +static void +coff_start_symtab () +{ + start_symtab ( + /* We fill in the filename later. start_symtab puts + this pointer into last_source_file and we put it in + subfiles->name, which end_symtab frees; that's why + it must be malloc'd. */ + savestring ("", 0), + /* We never know the directory name for COFF. */ + NULL, + /* The start address is irrelevant, since we set + last_source_start_addr in coff_end_symtab. */ + 0); + + /* Initialize the source file line number information for this file. */ + + if (line_vector) /* Unlikely, but maybe possible? */ + free ((PTR)line_vector); + line_vector_index = 0; + line_vector_length = 1000; + prev_line_number = -2; /* Force first line number to be explicit */ + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry)); +} + +/* Save the vital information from when starting to read a file, + for use when closing off the current file. + NAME is the file name the symbols came from, START_ADDR is the first + text address for the file, and SIZE is the number of bytes of text. */ + +static void +complete_symtab (name, start_addr, size) + char *name; + CORE_ADDR start_addr; + unsigned int size; +{ + if (last_source_file != NULL) + free (last_source_file); + last_source_file = savestring (name, strlen (name)); + current_source_start_addr = start_addr; + current_source_end_addr = start_addr + size; + + if (current_objfile -> ei.entry_point >= current_source_start_addr && + current_objfile -> ei.entry_point < current_source_end_addr) + { + current_objfile -> ei.entry_file_lowpc = current_source_start_addr; + current_objfile -> ei.entry_file_highpc = current_source_end_addr; + } +} + +/* 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. */ + +static void +coff_end_symtab (objfile) + struct objfile *objfile; +{ + struct symtab *symtab; + + last_source_start_addr = current_source_start_addr; + + /* For no good reason, this file stores the number of entries in a + separate variable instead of in line_vector->nitems. Fix it. */ + if (line_vector) + line_vector->nitems = line_vector_index; + + /* For COFF, we only have one subfile, so we can just look at + subfiles and not worry about there being other elements in the + chain. We fill in various fields now because we didn't know them + before (or because doing it now is simply an artifact of how this + file used to be written). */ + subfiles->line_vector = line_vector; + subfiles->name = last_source_file; + + symtab = end_symtab (current_source_end_addr, objfile, 0); + + if (symtab != NULL) + free_named_symtabs (symtab->filename); + + /* Reinitialize for beginning of new file. */ + line_vector = 0; + line_vector_length = -1; + last_source_file = NULL; +} + +static void +record_minimal_symbol (name, address, type, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type type; + struct objfile *objfile; +{ + /* We don't want TDESC entry points in the minimal symbol table */ + if (name[0] == '@') return; + + prim_record_minimal_symbol + (obsavestring (name, strlen (name), &objfile->symbol_obstack), + address, type, + objfile); +} + +/* coff_symfile_init () + is the coff-specific initialization routine for reading symbols. + It is passed a struct objfile which contains, among other things, + the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we fill with cookies and other + treats for coff_symfile_read (). + + We will only be called if this is a COFF or COFF-like file. + BFD handles figuring out the format of the file, and code in symtab.c + uses BFD's determination to vector to us. + + The ultimate result is a new symtab (or, FIXME, eventually a psymtab). */ + +static void +coff_symfile_init (objfile) + struct objfile *objfile; +{ + /* Allocate struct to keep track of stab reading. */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile->md, sizeof (struct dbx_symfile_info)); + + memset ((PTR) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); + + /* Allocate struct to keep track of the symfile */ + objfile->sym_private = xmmalloc (objfile->md, + sizeof (struct coff_symfile_info)); + + memset (objfile->sym_private, 0, sizeof (struct coff_symfile_info)); + + /* 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 limits + of the line table (minimum and maximum file offset) so that the + mainline code can read the whole thing for efficiency. */ + +/* ARGSUSED */ +static void +find_linenos (abfd, asect, vpinfo) + bfd *abfd; + sec_ptr asect; + PTR vpinfo; +{ + struct coff_symfile_info *info; + int size, count; + file_ptr offset, maxoff; + +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + count = asect->lineno_count; +/* End of warning */ + + if (count == 0) + return; + size = count * local_linesz; + + info = (struct coff_symfile_info *)vpinfo; +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + offset = asect->line_filepos; +/* End of warning */ + + if (offset < info->min_lineno_offset || info->min_lineno_offset == 0) + info->min_lineno_offset = offset; + + maxoff = offset + size; + if (maxoff > info->max_lineno_offset) + info->max_lineno_offset = maxoff; +} + + +/* The BFD for this file -- only good while we're actively reading + symbols into a psymtab or a symtab. */ + +static bfd *symfile_bfd; + +/* Read a symbol file, after initialization by coff_symfile_init. */ + +/* ARGSUSED */ +static void +coff_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + struct coff_symfile_info *info; + struct dbx_symfile_info *dbxinfo; + bfd *abfd = objfile->obfd; + coff_data_type *cdata = coff_data (abfd); + char *name = bfd_get_filename (abfd); + register int val; + int num_symbols; + int symtab_offset; + int stringtab_offset; + struct cleanup *back_to; + int stabstrsize; + + info = (struct coff_symfile_info *) objfile -> sym_private; + dbxinfo = (struct dbx_symfile_info *) objfile->sym_stab_info; + symfile_bfd = abfd; /* Kludge for swap routines */ + +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + num_symbols = bfd_get_symcount (abfd); /* How many syms */ + symtab_offset = cdata->sym_filepos; /* Symbol table file offset */ + stringtab_offset = symtab_offset + /* String table file offset */ + num_symbols * cdata->local_symesz; + + /* Set a few file-statics that give us specific information about + the particular COFF file format we're reading. */ + local_linesz = cdata->local_linesz; + local_n_btmask = cdata->local_n_btmask; + local_n_btshft = cdata->local_n_btshft; + local_n_tmask = cdata->local_n_tmask; + local_n_tshift = cdata->local_n_tshift; + local_linesz = cdata->local_linesz; + local_symesz = cdata->local_symesz; + local_auxesz = cdata->local_auxesz; + + /* Allocate space for raw symbol and aux entries, based on their + space requirements as reported by BFD. */ + temp_sym = (char *) xmalloc + (cdata->local_symesz + cdata->local_auxesz); + temp_aux = temp_sym + cdata->local_symesz; + back_to = make_cleanup (free_current_contents, &temp_sym); +/* End of warning */ + + /* Read the line number table, all at once. */ + info->min_lineno_offset = 0; + info->max_lineno_offset = 0; + bfd_map_over_sections (abfd, find_linenos, (PTR) info); + + make_cleanup (free_linetab, 0); + val = init_lineno (abfd, info->min_lineno_offset, + info->max_lineno_offset - info->min_lineno_offset); + if (val < 0) + error ("\"%s\": error reading line numbers\n", name); + + /* Now read the string table, all at once. */ + + make_cleanup (free_stringtab, 0); + val = init_stringtab (abfd, stringtab_offset); + if (val < 0) + error ("\"%s\": can't get string table", name); + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + coff_symtab_read ((long) symtab_offset, num_symbols, section_offsets, + objfile); + + /* Sort symbols alphabetically within each block. */ + + { + struct symtab *s; + + for (s = objfile -> symtabs; s != NULL; s = s -> next) + sort_symtab_syms (s); + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + bfd_map_over_sections (abfd, coff_locate_sections, (PTR) info); + + if (info->stabsects) + { + /* FIXME: dubious. Why can't we use something normal like + bfd_get_section_contents? */ + bfd_seek (abfd, abfd->where, 0); + + stabstrsize = bfd_section_size (abfd, info->stabstrsect); + + coffstab_build_psymtabs (objfile, + section_offsets, + mainline, + info->textaddr, info->textsize, + info->stabsects, + info->stabstrsect->filepos, stabstrsize); + } + + do_cleanups (back_to); +} + +static void +coff_new_init (ignore) + struct objfile *ignore; +{ +} + +/* 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 +coff_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_private != NULL) + { + mfree (objfile -> md, objfile -> sym_private); + } +} + + +/* Given pointers to a symbol table in coff style exec file, + analyze them and create struct symtab's describing the symbols. + NSYMS is the number of symbols in the symbol table. + We read them one at a time using read_one_sym (). */ + +static void +coff_symtab_read (symtab_offset, nsyms, section_offsets, objfile) + long symtab_offset; + int nsyms; + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + register struct context_stack *new; + struct coff_symbol coff_symbol; + register struct coff_symbol *cs = &coff_symbol; + static struct internal_syment main_sym; + static union internal_auxent main_aux; + struct coff_symbol fcn_cs_saved; + static struct internal_syment fcn_sym_saved; + static union internal_auxent fcn_aux_saved; + struct symtab *s; + /* A .file is open. */ + int in_source_file = 0; + int next_file_symnum = -1; + /* Name of the current file. */ + char *filestring = ""; + int depth = 0; + int fcn_first_line = 0; + int fcn_last_line = 0; + int fcn_start_addr = 0; + long fcn_line_ptr = 0; + int val; + CORE_ADDR tmpaddr; + + /* Work around a stdio bug in SunOS4.1.1 (this makes me nervous.... + it's hard to know I've really worked around it. The fix should be + harmless, anyway). The symptom of the bug is that the first + fread (in read_one_sym), will (in my example) actually get data + from file offset 268, when the fseek was to 264 (and ftell shows + 264). This causes all hell to break loose. I was unable to + reproduce this on a short test program which operated on the same + file, performing (I think) the same sequence of operations. + + It stopped happening when I put in this (former) rewind(). + + FIXME: Find out if this has been reported to Sun, whether it has + been fixed in a later release, etc. */ + + bfd_seek (objfile->obfd, 0, 0); + + /* Position to read the symbol table. */ + val = bfd_seek (objfile->obfd, (long) symtab_offset, 0); + if (val < 0) + perror_with_name (objfile->name); + + current_objfile = objfile; + nlist_bfd_global = objfile->obfd; + nlist_nsyms_global = nsyms; + last_source_file = NULL; + memset (opaque_type_chain, 0, sizeof opaque_type_chain); + + if (type_vector) /* Get rid of previous one */ + free ((PTR) type_vector); + type_vector_length = 160; + type_vector = (struct type **) + xmalloc (type_vector_length * sizeof (struct type *)); + memset (type_vector, 0, type_vector_length * sizeof (struct type *)); + + coff_start_symtab (); + + symnum = 0; + while (symnum < nsyms) + { + QUIT; /* Make this command interruptable. */ + + read_one_sym (cs, &main_sym, &main_aux); + +#ifdef SEM + temp_sem_val = cs->c_name[0] << 24 | cs->c_name[1] << 16 | + cs->c_name[2] << 8 | cs->c_name[3]; + if (int_sem_val == temp_sem_val) + last_coffsem = (int) strtol (cs->c_name+4, (char **) NULL, 10); +#endif + + if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) + { + if (last_source_file) + coff_end_symtab (objfile); + + coff_start_symtab (); + complete_symtab ("_globals_", 0, 0); + /* done with all files, everything from here on out is globals */ + } + + /* Special case for file with type declarations only, no text. */ + if (!last_source_file && SDB_TYPE (cs->c_type) + && cs->c_secnum == N_DEBUG) + complete_symtab (filestring, 0, 0); + + /* Typedefs should not be treated as symbol definitions. */ + if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) + { + /* Record all functions -- external and static -- in minsyms. */ + tmpaddr = cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT); + record_minimal_symbol (cs->c_name, tmpaddr, mst_text, objfile); + + fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; + fcn_start_addr = tmpaddr; + fcn_cs_saved = *cs; + fcn_sym_saved = main_sym; + fcn_aux_saved = main_aux; + continue; + } + + switch (cs->c_sclass) + { + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + complain (&bad_sclass_complaint, cs->c_name); + break; + + case C_FILE: + /* c_value field contains symnum of next .file entry in table + or symnum of first global after last .file. */ + next_file_symnum = cs->c_value; + if (cs->c_naux > 0) + filestring = coff_getfilename (&main_aux); + else + filestring = ""; + + /* Complete symbol table for last object file + containing debugging information. */ + if (last_source_file) + { + coff_end_symtab (objfile); + coff_start_symtab (); + } + in_source_file = 1; + break; + + case C_STAT: + if (cs->c_name[0] == '.') + { + if (STREQ (cs->c_name, ".text")) { + /* FIXME: don't wire in ".text" as section name + or symbol name! */ + /* Check for in_source_file deals with case of + a file with debugging symbols + followed by a later file with no symbols. */ + if (in_source_file) + complete_symtab (filestring, + cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT), + main_aux.x_scn.x_scnlen); + in_source_file = 0; + } + /* flush rest of '.' symbols */ + break; + } + else if (!SDB_TYPE (cs->c_type) + && cs->c_name[0] == 'L' + && (strncmp (cs->c_name, "LI%", 3) == 0 + || strncmp (cs->c_name, "LF%", 3) == 0 + || strncmp (cs->c_name,"LC%",3) == 0 + || strncmp (cs->c_name,"LP%",3) == 0 + || strncmp (cs->c_name,"LPB%",4) == 0 + || strncmp (cs->c_name,"LBB%",4) == 0 + || strncmp (cs->c_name,"LBE%",4) == 0 + || strncmp (cs->c_name,"LPBX%",5) == 0)) + /* At least on a 3b1, gcc generates swbeg and string labels + that look like this. Ignore them. */ + break; + /* fall in for static symbols that don't start with '.' */ + case C_EXT: + { + /* Record it in the minimal symbols regardless of + SDB_TYPE. This parallels what we do for other debug + formats, and probably is needed to make + print_address_symbolic work right without the (now + gone) "set fast-symbolic-addr off" kludge. */ + + /* FIXME: should use mst_abs, and not relocate, if absolute. */ + enum minimal_symbol_type ms_type; + int sec; + + if (cs->c_secnum == N_UNDEF) + { + /* This is a common symbol. See if the target + environment knows where it has been relocated to. */ + CORE_ADDR reladdr; + if (target_lookup_symbol (cs->c_name, &reladdr)) + { + /* Error in lookup; ignore symbol. */ + break; + } + tmpaddr = reladdr; + /* The address has already been relocated; make sure that + objfile_relocate doesn't relocate it again. */ + sec = -2; + ms_type = cs->c_sclass == C_STAT ? mst_file_bss : mst_bss; + } + else + { + sec = cs_to_section (cs, objfile); + tmpaddr = cs->c_value; + if (cs->c_sclass != C_STAT) + tmpaddr += ANOFFSET (section_offsets, sec); + + switch (sec) + { + case SECT_OFF_TEXT: + case SECT_OFF_RODATA: + ms_type = + cs->c_sclass == C_STAT ? mst_file_text : mst_text; + break; + case SECT_OFF_DATA: + ms_type = + cs->c_sclass == C_STAT ? mst_file_data : mst_data; + break; + case SECT_OFF_BSS: + ms_type = + cs->c_sclass == C_STAT ? mst_file_bss : mst_bss; + break; + default: + ms_type = mst_unknown; + break; + } + } + + if (cs->c_name[0] != '@' /* Skip tdesc symbols */) + prim_record_minimal_symbol_and_info + (obsavestring (cs->c_name, strlen (cs->c_name), + &objfile->symbol_obstack), + tmpaddr, + ms_type, + NULL, + sec, + objfile); + + if (SDB_TYPE (cs->c_type)) + { + struct symbol *sym; + sym = process_coff_symbol + (cs, &main_aux, section_offsets, objfile); + SYMBOL_VALUE (sym) = tmpaddr; + SYMBOL_SECTION (sym) = sec; + } + } + break; + + case C_FCN: + if (STREQ (cs->c_name, ".bf")) + { + within_function = 1; + + /* value contains address of first non-init type code */ + /* main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains line number of '{' } */ + if (cs->c_naux != 1) + complain (&bf_no_aux_complaint, cs->c_symnum); + fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + + /* Might want to check that locals are 0 and + context_stack_depth is zero, and complain if not. */ + + depth = 0; + new = push_context (depth, fcn_start_addr); + fcn_cs_saved.c_name = getsymname (&fcn_sym_saved); + new->name = + process_coff_symbol (&fcn_cs_saved, &fcn_aux_saved, + section_offsets, objfile); + } + else if (STREQ (cs->c_name, ".ef")) + { + /* the value of .ef is the address of epilogue code; + not useful for gdb. */ + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&ef_stack_complaint, cs->c_symnum); + within_function = 0; + break; + } + + new = pop_context (); + /* Stack must be empty now. */ + if (context_stack_depth > 0 || new == NULL) + { + complain (&ef_complaint, cs->c_symnum); + within_function = 0; + break; + } + if (cs->c_naux != 1) + { + complain (&ef_no_aux_complaint, cs->c_symnum); + fcn_last_line = 0x7FFFFFFF; + } + else + { + fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + } + enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line, + section_offsets); + + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, +#if defined (FUNCTION_EPILOGUE_SIZE) + /* This macro should be defined only on + machines where the + fcn_aux_saved.x_sym.x_misc.x_fsize + field is always zero. + So use the .bf record information that + points to the epilogue and add the size + of the epilogue. */ + cs->c_value + + FUNCTION_EPILOGUE_SIZE + + ANOFFSET (section_offsets, SECT_OFF_TEXT), +#else + fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize + + ANOFFSET (section_offsets, SECT_OFF_TEXT), +#endif + objfile + ); + within_function = 0; + } + break; + + case C_BLOCK: + if (STREQ (cs->c_name, ".bb")) + { + tmpaddr = cs->c_value; + tmpaddr += ANOFFSET (section_offsets, SECT_OFF_TEXT); + push_context (++depth, tmpaddr); + } + else if (STREQ (cs->c_name, ".eb")) + { + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&eb_stack_complaint, cs->c_symnum); + break; + } + + new = pop_context (); + if (depth-- != new->depth) + { + complain (&eb_complaint, symnum); + break; + } + if (local_symbols && context_stack_depth > 0) + { + tmpaddr = + cs->c_value + ANOFFSET (section_offsets, SECT_OFF_TEXT); + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, tmpaddr, objfile); + } + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + } + break; + + default: + process_coff_symbol (cs, &main_aux, section_offsets, objfile); + break; + } + } + + if (last_source_file) + coff_end_symtab (objfile); + + /* Patch up any opaque types (references to types that are not defined + in the file where they are referenced, e.g. "struct foo *bar"). */ + ALL_OBJFILE_SYMTABS (objfile, s) + patch_opaque_types (s); + + current_objfile = NULL; +} + +/* Routines for reading headers and symbols from executable. */ + +/* Read the next symbol, swap it, and return it in both internal_syment + form, and coff_symbol form. Also return its first auxent, if any, + in internal_auxent form, and skip any other auxents. */ + +static void +read_one_sym (cs, sym, aux) + register struct coff_symbol *cs; + register struct internal_syment *sym; + register union internal_auxent *aux; +{ + int i; + + cs->c_symnum = symnum; + bfd_read (temp_sym, local_symesz, 1, nlist_bfd_global); + bfd_coff_swap_sym_in (symfile_bfd, temp_sym, (char *)sym); + cs->c_naux = sym->n_numaux & 0xff; + if (cs->c_naux >= 1) + { + bfd_read (temp_aux, local_auxesz, 1, nlist_bfd_global); + bfd_coff_swap_aux_in (symfile_bfd, temp_aux, sym->n_type, sym->n_sclass, + 0, cs->c_naux, (char *)aux); + /* If more than one aux entry, read past it (only the first aux + is important). */ + for (i = 1; i < cs->c_naux; i++) + bfd_read (temp_aux, local_auxesz, 1, nlist_bfd_global); + } + cs->c_name = getsymname (sym); + cs->c_value = sym->n_value; + cs->c_sclass = (sym->n_sclass & 0xff); + cs->c_secnum = sym->n_scnum; + cs->c_type = (unsigned) sym->n_type; + if (!SDB_TYPE (cs->c_type)) + cs->c_type = 0; + + symnum += 1 + cs->c_naux; +} + +/* Support for string table handling */ + +static char *stringtab = NULL; + +static int +init_stringtab (abfd, offset) + bfd *abfd; + long offset; +{ + long length; + int val; + unsigned char lengthbuf[4]; + + free_stringtab (); + + /* If the file is stripped, the offset might be zero, indicating no + string table. Just return with `stringtab' set to null. */ + if (offset == 0) + return 0; + + if (bfd_seek (abfd, offset, 0) < 0) + return -1; + + val = bfd_read ((char *)lengthbuf, sizeof lengthbuf, 1, abfd); + length = bfd_h_get_32 (symfile_bfd, lengthbuf); + + /* If no string table is needed, then the file may end immediately + after the symbols. Just return with `stringtab' set to null. */ + if (val != sizeof lengthbuf || length < sizeof lengthbuf) + return 0; + + stringtab = (char *) xmalloc (length); + /* This is in target format (probably not very useful, and not currently + used), not host format. */ + memcpy (stringtab, lengthbuf, sizeof lengthbuf); + if (length == sizeof length) /* Empty table -- just the count */ + return 0; + + val = bfd_read (stringtab + sizeof lengthbuf, length - sizeof lengthbuf, 1, abfd); + if (val != length - sizeof lengthbuf || stringtab[length - 1] != '\0') + return -1; + + return 0; +} + +static void +free_stringtab () +{ + if (stringtab) + free (stringtab); + stringtab = NULL; +} + +static char * +getsymname (symbol_entry) + struct internal_syment *symbol_entry; +{ + static char buffer[SYMNMLEN+1]; + char *result; + + if (symbol_entry->_n._n_n._n_zeroes == 0) + { + /* FIXME: Probably should be detecting corrupt symbol files by + seeing whether offset points to within the stringtab. */ + result = stringtab + symbol_entry->_n._n_n._n_offset; + } + else + { + strncpy (buffer, symbol_entry->_n._n_name, SYMNMLEN); + buffer[SYMNMLEN] = '\0'; + result = buffer; + } + return result; +} + +/* Extract the file name from the aux entry of a C_FILE symbol. Return + only the last component of the name. Result is in static storage and + is only good for temporary use. */ + +static char * +coff_getfilename (aux_entry) + union internal_auxent *aux_entry; +{ + static char buffer[BUFSIZ]; + register char *temp; + char *result; + + if (aux_entry->x_file.x_n.x_zeroes == 0) + strcpy (buffer, stringtab + aux_entry->x_file.x_n.x_offset); + else + { + strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); + buffer[FILNMLEN] = '\0'; + } + result = buffer; + + /* FIXME: We should not be throwing away the information about what + directory. It should go into dirname of the symtab, or some such + place. */ + if ((temp = strrchr (result, '/')) != NULL) + result = temp + 1; + return (result); +} + +/* Support for line number handling. */ + +static char *linetab = NULL; +static long linetab_offset; +static unsigned long linetab_size; + +/* Read in all the line numbers for fast lookups later. Leave them in + external (unswapped) format in memory; we'll swap them as we enter + them into GDB's data structures. */ + +static int +init_lineno (abfd, offset, size) + bfd *abfd; + long offset; + int size; +{ + int val; + + linetab_offset = offset; + linetab_size = size; + + free_linetab(); + + if (size == 0) + return 0; + + if (bfd_seek (abfd, offset, 0) < 0) + return -1; + + /* Allocate the desired table, plus a sentinel */ + linetab = (char *) xmalloc (size + local_linesz); + + val = bfd_read (linetab, size, 1, abfd); + if (val != size) + return -1; + + /* Terminate it with an all-zero sentinel record */ + memset (linetab + size, 0, local_linesz); + + return 0; +} + +static void +free_linetab () +{ + if (linetab) + free (linetab); + linetab = NULL; +} + +#if !defined (L_LNNO32) +#define L_LNNO32(lp) ((lp)->l_lnno) +#endif + +static void +enter_linenos (file_offset, first_line, last_line, section_offsets) + long file_offset; + register int first_line; + register int last_line; + struct section_offsets *section_offsets; +{ + register char *rawptr; + struct internal_lineno lptr; + + if (!linetab) + return ; + if (file_offset < linetab_offset) + { + complain (&lineno_complaint, file_offset); + if (file_offset > linetab_size) /* Too big to be an offset? */ + return; + file_offset += linetab_offset; /* Try reading at that linetab offset */ + } + + rawptr = &linetab[file_offset - linetab_offset]; + + /* skip first line entry for each function */ + rawptr += local_linesz; + /* line numbers start at one for the first line of the function */ + first_line--; + + for (;;) { + bfd_coff_swap_lineno_in (symfile_bfd, rawptr, &lptr); + rawptr += local_linesz; + /* The next function, or the sentinel, will have L_LNNO32 zero; we exit. */ + if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line) + coff_record_line (first_line + L_LNNO32 (&lptr), + lptr.l_addr.l_paddr + + ANOFFSET (section_offsets, SECT_OFF_TEXT)); + else + break; + } +} + +static void +patch_type (type, real_type) + struct type *type; + struct type *real_type; +{ + register struct type *target = TYPE_TARGET_TYPE (type); + register struct type *real_target = TYPE_TARGET_TYPE (real_type); + int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field); + + TYPE_LENGTH (target) = TYPE_LENGTH (real_target); + TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target); + TYPE_FIELDS (target) = (struct field *) TYPE_ALLOC (target, field_size); + + memcpy (TYPE_FIELDS (target), TYPE_FIELDS (real_target), field_size); + + if (TYPE_NAME (real_target)) + { + if (TYPE_NAME (target)) + free (TYPE_NAME (target)); + TYPE_NAME (target) = concat (TYPE_NAME (real_target), NULL); + } +} + +/* Patch up all appropriate typedef symbols in the opaque_type_chains + so that they can be used to print out opaque data structures properly. */ + +static void +patch_opaque_types (s) + struct symtab *s; +{ + register struct block *b; + register int i; + register struct symbol *real_sym; + + /* Go through the per-file symbols only */ + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + /* Find completed typedefs to use to fix opaque ones. + Remove syms from the chain when their types are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ + real_sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF && + SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE && + TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0) + { + register char *name = SYMBOL_NAME (real_sym); + register int hash = hashname (name); + register struct symbol *sym, *prev; + + prev = 0; + for (sym = opaque_type_chain[hash]; sym;) + { + if (name[0] == SYMBOL_NAME (sym)[0] && + STREQ (name + 1, SYMBOL_NAME (sym) + 1)) + { + if (prev) + { + SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym); + } + else + { + opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym); + } + + patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym)); + + if (prev) + { + sym = SYMBOL_VALUE_CHAIN (prev); + } + else + { + sym = opaque_type_chain[hash]; + } + } + else + { + prev = sym; + sym = SYMBOL_VALUE_CHAIN (sym); + } + } + } + } +} + +static struct symbol * +process_coff_symbol (cs, aux, section_offsets, objfile) + register struct coff_symbol *cs; + register union internal_auxent *aux; + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + register struct symbol *sym + = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + char *name; + + memset (sym, 0, sizeof (struct symbol)); + name = cs->c_name; + name = EXTERNAL_NAME (name, objfile->obfd); + SYMBOL_NAME (sym) = obstack_copy0 (&objfile->symbol_obstack, name, + strlen (name)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = cs->c_value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_SECTION (sym) = cs_to_section (cs, objfile); + + if (ISFCN (cs->c_type)) + { + SYMBOL_VALUE (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); + SYMBOL_TYPE(sym) = + lookup_function_type (decode_function_type (cs, cs->c_type, aux)); + + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (cs->c_sclass == C_STAT) + add_symbol_to_list (sym, &file_symbols); + else if (cs->c_sclass == C_EXT) + add_symbol_to_list (sym, &global_symbols); + } + else + { + SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux); + switch (cs->c_sclass) + { + case C_NULL: + break; + + case C_AUTO: + SYMBOL_CLASS (sym) = LOC_LOCAL; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_EXT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); + add_symbol_to_list (sym, &global_symbols); + break; + + case C_STAT: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value; + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (section_offsets, SECT_OFF_TEXT); + if (within_function) { + /* Static symbol of local scope */ + add_symbol_to_list (sym, &local_symbols); + } + else { + /* Static symbol at top level of file */ + add_symbol_to_list (sym, &file_symbols); + } + break; + +#ifdef C_GLBLREG /* AMD coff */ + case C_GLBLREG: +#endif + case C_REG: + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); + add_symbol_to_list (sym, &local_symbols); + break; + + case C_LABEL: + break; + + case C_ARG: + SYMBOL_CLASS (sym) = LOC_ARG; + add_symbol_to_list (sym, &local_symbols); +#if !defined (BELIEVE_PCC_PROMOTION) + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + /* If PCC says a parameter is a short or a char, + aligned on an int boundary, realign it to the + "little end" of the int. */ + struct type *temptype; + temptype = lookup_fundamental_type (current_objfile, + FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT + && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (temptype)) + { + SYMBOL_VALUE (sym) += + TYPE_LENGTH (temptype) + - TYPE_LENGTH (SYMBOL_TYPE (sym)); + } + } +#endif + break; + + case C_REGPARM: + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = SDB_REG_TO_REGNUM(cs->c_value); + add_symbol_to_list (sym, &local_symbols); +#if !defined (BELIEVE_PCC_PROMOTION) + /* FIXME: This should retain the current type, since it's just + a register value. gnu@adobe, 26Feb93 */ + { + /* If PCC says a parameter is a short or a char, + it is really an int. */ + struct type *temptype; + temptype = + lookup_fundamental_type (current_objfile, FT_INTEGER); + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (temptype) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) + { + SYMBOL_TYPE (sym) = + (TYPE_UNSIGNED (SYMBOL_TYPE (sym)) + ? lookup_fundamental_type (current_objfile, + FT_UNSIGNED_INTEGER) + : temptype); + } + } +#endif + break; + + case C_TPDEF: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + /* If type has no name, give it one */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + { + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; CC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type + refering to the C_TPDEF symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + ; + } + else + TYPE_NAME (SYMBOL_TYPE (sym)) = + concat (SYMBOL_NAME (sym), NULL); + } +#ifdef CXUX_TARGET + /* Ignore vendor section for Harris CX/UX targets. */ + else if (cs->c_name[0] == '$') + break; +#endif /* CXUX_TARGET */ + + /* Keep track of any type which points to empty structured type, + so it can be filled from a definition from another file. A + simple forward reference (TYPE_CODE_UNDEF) is not an + empty structured type, though; the forward references + work themselves out via the magic of coff_lookup_type. */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0 && + TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) != + TYPE_CODE_UNDEF) + { + register int i = hashname (SYMBOL_NAME (sym)); + + SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i]; + opaque_type_chain[i] = sym; + } + add_symbol_to_list (sym, &file_symbols); + break; + + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + + /* Some compilers try to be helpful by inventing "fake" + names for anonymous enums, structures, and unions, like + "~0fake" or ".0fake". Thanks, but no thanks... */ + if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) + if (SYMBOL_NAME(sym) != NULL + && *SYMBOL_NAME(sym) != '~' + && *SYMBOL_NAME(sym) != '.') + TYPE_TAG_NAME (SYMBOL_TYPE (sym)) = + concat (SYMBOL_NAME (sym), NULL); + + add_symbol_to_list (sym, &file_symbols); + break; + + default: + break; + } + } + return sym; +} + +/* Decode a coff type specifier; return the type that is meant. */ + +static struct type * +decode_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + register struct type *type = 0; + unsigned int new_c_type; + + if (c_type & ~N_BTMASK) + { + new_c_type = DECREF (c_type); + if (ISPTR (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_pointer_type (type); + } + else if (ISFCN (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_function_type (type); + } + else if (ISARY (c_type)) + { + int i, n; + register unsigned short *dim; + struct type *base_type, *index_type, *range_type; + + /* Define an array type. */ + /* auxent refers to array, not base type */ + if (aux->x_sym.x_tagndx.l == 0) + cs->c_naux = 0; + + /* shift the indices down */ + dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0]; + i = 1; + n = dim[0]; + for (i = 0; *dim && i < DIMNUM - 1; i++, dim++) + *dim = *(dim + 1); + *dim = 0; + + base_type = decode_type (cs, new_c_type, aux); + index_type = lookup_fundamental_type (current_objfile, FT_INTEGER); + range_type = + create_range_type ((struct type *) NULL, index_type, 0, n - 1); + type = + create_array_type ((struct type *) NULL, base_type, range_type); + } + return type; + } + + /* Reference to existing type. This only occurs with the + struct, union, and enum types. EPI a29k coff + fakes us out by producing aux entries with a nonzero + x_tagndx for definitions of structs, unions, and enums, so we + have to check the c_sclass field. SCO 3.2v4 cc gets confused + with pointers to pointers to defined structs, and generates + negative x_tagndx fields. */ + if (cs->c_naux > 0 && aux->x_sym.x_tagndx.l != 0) + { + if (cs->c_sclass != C_STRTAG + && cs->c_sclass != C_UNTAG + && cs->c_sclass != C_ENTAG + && aux->x_sym.x_tagndx.l >= 0) + { + type = coff_alloc_type (aux->x_sym.x_tagndx.l); + return type; + } + else + { + complain (&tagndx_bad_complaint, cs->c_name); + /* And fall through to decode_base_type... */ + } + } + + return decode_base_type (cs, BTYPE (c_type), aux); +} + +/* Decode a coff type specifier for function definition; + return the type that the function returns. */ + +static struct type * +decode_function_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + if (aux->x_sym.x_tagndx.l == 0) + cs->c_naux = 0; /* auxent refers to function, not base type */ + + return decode_type (cs, DECREF (c_type), aux); +} + +/* basic C types */ + +static struct type * +decode_base_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register union internal_auxent *aux; +{ + struct type *type; + + switch (c_type) + { + case T_NULL: + /* shows up with "void (*foo)();" structure members */ + return lookup_fundamental_type (current_objfile, FT_VOID); + +#if 0 +/* DGUX actually defines both T_ARG and T_VOID to the same value. */ +#ifdef T_ARG + case T_ARG: + /* Shows up in DGUX, I think. Not sure where. */ + return lookup_fundamental_type (current_objfile, FT_VOID); /* shouldn't show up here */ +#endif +#endif /* 0 */ + +#ifdef T_VOID + case T_VOID: + /* Intel 960 COFF has this symbol and meaning. */ + return lookup_fundamental_type (current_objfile, FT_VOID); +#endif + + case T_CHAR: + return lookup_fundamental_type (current_objfile, FT_CHAR); + + case T_SHORT: + return lookup_fundamental_type (current_objfile, FT_SHORT); + + case T_INT: + return lookup_fundamental_type (current_objfile, FT_INTEGER); + + case T_LONG: + return lookup_fundamental_type (current_objfile, FT_LONG); + + case T_FLOAT: + return lookup_fundamental_type (current_objfile, FT_FLOAT); + + case T_DOUBLE: + return lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); + + case T_LNGDBL: + return lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT); + + case T_STRUCT: + if (cs->c_naux != 1) + { + /* anonymous structure type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "struct {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; + + case T_UNION: + if (cs->c_naux != 1) + { + /* anonymous union type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "union {...}". */ + TYPE_TAG_NAME (type) = NULL; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = coff_read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + TYPE_CODE (type) = TYPE_CODE_UNION; + return type; + + case T_ENUM: + if (cs->c_naux != 1) + { + /* anonymous enum type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NAME (type) = NULL; + /* This used to set the tag to "". But I think setting it + to NULL is right, and the printing code can print it as + "enum {...}". */ + TYPE_TAG_NAME (type) = NULL; + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS(type) = 0; + } + else + { + type = coff_read_enum_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx.l); + } + return type; + + case T_MOE: + /* shouldn't show up here */ + break; + + case T_UCHAR: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); + + case T_USHORT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); + + case T_UINT: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); + + case T_ULONG: + return lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG); + } + complain (&unexpected_type_complaint, cs->c_name); + return lookup_fundamental_type (current_objfile, FT_VOID); +} + +/* This page contains subroutines of read_type. */ + +/* Read the description of a structure (or union type) and return an + object describing the type. */ + +static struct type * +coff_read_struct_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + struct nextfield + { + struct nextfield *next; + struct field field; + }; + + register struct type *type; + register struct nextfield *list = 0; + struct nextfield *new; + int nfields = 0; + register int n; + char *name; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + struct internal_syment sub_sym; + union internal_auxent sub_aux; + int done = 0; + + type = coff_alloc_type (index); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC(type); + TYPE_LENGTH (type) = length; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = EXTERNAL_NAME (name, current_objfile->obfd); + + switch (ms->c_sclass) + { + case C_MOS: + case C_MOU: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = + obsavestring (name, + strlen (name), + ¤t_objfile->symbol_obstack); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = 8 * ms->c_value; + list->field.bitsize = 0; + nfields++; + break; + + case C_FIELD: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = + obsavestring (name, + strlen (name), + ¤t_objfile->symbol_obstack); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = ms->c_value; + list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size; + nfields++; + break; + + case C_EOS: + done = 1; + break; + } + } + /* Now create the vector of fields, and record how big it is. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + TYPE_FIELD (type, --n) = list->field; + + return type; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +/* ARGSUSED */ +static struct type * +coff_read_enum_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + register struct symbol *sym; + register struct type *type; + int nsyms = 0; + int done = 0; + struct pending **symlist; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + struct internal_syment sub_sym; + union internal_auxent sub_aux; + struct pending *osyms, *syms; + int o_nsyms; + register int n; + char *name; + + type = coff_alloc_type (index); + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + o_nsyms = osyms ? osyms->nsyms : 0; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = EXTERNAL_NAME (name, current_objfile->obfd); + + switch (ms->c_sclass) + { + case C_MOE: + sym = (struct symbol *) obstack_alloc + (¤t_objfile->symbol_obstack, + sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = + obsavestring (name, strlen (name), + ¤t_objfile->symbol_obstack); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; + + case C_EOS: + /* Sometimes the linker (on 386/ix 2.0.2 at least) screws + up the count of how many symbols to read. So stop + on .eos. */ + done = 1; + break; + } + } + + /* Now fill in the fields of the type-structure. */ + + if (length > 0) + TYPE_LENGTH (type) = length; + else + TYPE_LENGTH (type) = TARGET_INT_BIT / TARGET_CHAR_BIT; /* Assume ints */ + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + /* Note that we preserve the order of the enum constants, so + that in something like "enum {FOO, LAST_THING=FOO}" we print + FOO, not LAST_THING. */ + + for (syms = *symlist, n = 0; syms; syms = syms->next) + { + int j = 0; + + if (syms == osyms) + j = o_nsyms; + for (; j < syms->nsyms; j++,n++) + { + struct symbol *xsym = syms->symbol[j]; + SYMBOL_TYPE (xsym) = type; + TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + if (syms == osyms) + break; + } + + return type; +} + +struct section_offsets * +coff_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * SECT_OFF_MAX); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* Register our ability to parse symbols for coff BFD files. */ + +static struct sym_fns coff_sym_fns = +{ + bfd_target_coff_flavour, + coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + coff_symfile_read, /* sym_read: read a symbol file into symtab */ + coff_symfile_finish, /* sym_finish: finished with file, cleanup */ + coff_symfile_offsets, /* sym_offsets: xlate external to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_coffread () +{ + add_symtab_fns (&coff_sym_fns); +} diff --git a/contrib/gdb/gdb/command.c b/contrib/gdb/gdb/command.c new file mode 100644 index 000000000000..a5477ddd3273 --- /dev/null +++ b/contrib/gdb/gdb/command.c @@ -0,0 +1,1466 @@ +/* Handle lists of commands, their decoding and documentation, for GDB. + Copyright 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "value.h" +#include "wait.h" +#include +#include "gdb_string.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Prototypes for local functions */ + +static void +undef_cmd_error PARAMS ((char *, char *)); + +static void +show_user PARAMS ((char *, int)); + +static void +show_user_1 PARAMS ((struct cmd_list_element *, GDB_FILE *)); + +static void +make_command PARAMS ((char *, int)); + +static void +shell_escape PARAMS ((char *, int)); + +static int +parse_binary_operation PARAMS ((char *)); + +static void +print_doc_line PARAMS ((GDB_FILE *, char *)); + +/* Add element named NAME. + CLASS is the top level category into which commands are broken down + for "help" purposes. + FUN should be the function to execute the command; + it will get a character string as argument, with leading + and trailing blanks already eliminated. + + DOC is a documentation string for the command. + Its first line should be a complete sentence. + It should start with ? for a command that is an abbreviation + or with * for a command that most users don't need to know about. + + Add this command to command list *LIST. */ + +struct cmd_list_element * +add_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = name; + c->class = class; + c->function.cfunc = fun; + c->doc = doc; + c->hook = NULL; + c->prefixlist = NULL; + c->prefixname = NULL; + c->allow_unknown = 0; + c->abbrev_flag = 0; + c->completer = make_symbol_completion_list; + c->type = not_set_cmd; + c->var = NULL; + c->var_type = var_boolean; + c->enums = NULL; + c->user_commands = NULL; + c->hookee = NULL; + c->cmd_pointer = NULL; + *list = c; + return c; +} + +/* Same as above, except that the abbrev_flag is set. */ + +#if 0 /* Currently unused */ + +struct cmd_list_element * +add_abbrev_cmd (name, class, fun, doc, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = add_cmd (name, class, fun, doc, list); + + c->abbrev_flag = 1; + return c; +} + +#endif + +struct cmd_list_element * +add_alias_cmd (name, oldname, class, abbrev_flag, list) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; + struct cmd_list_element **list; +{ + /* Must do this since lookup_cmd tries to side-effect its first arg */ + char *copied_name; + register struct cmd_list_element *old; + register struct cmd_list_element *c; + copied_name = (char *) alloca (strlen (oldname) + 1); + strcpy (copied_name, oldname); + old = lookup_cmd (&copied_name, *list, "", 1, 1); + + if (old == 0) + { + delete_cmd (name, list); + return 0; + } + + c = add_cmd (name, class, old->function.cfunc, old->doc, list); + c->prefixlist = old->prefixlist; + c->prefixname = old->prefixname; + c->allow_unknown = old->allow_unknown; + c->abbrev_flag = abbrev_flag; + c->cmd_pointer = old; + return c; +} + +/* Like add_cmd but adds an element for a command prefix: + a name that should be followed by a subcommand to be looked up + in another command list. PREFIXLIST should be the address + of the variable containing that list. */ + +struct cmd_list_element * +add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + return c; +} + +/* Like add_prefix_cmd but sets the abbrev_flag on the new command. */ + +struct cmd_list_element * +add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + c->abbrev_flag = 1; + return c; +} + +/* This is an empty "cfunc". */ +void +not_just_help_class_command (args, from_tty) + char *args; + int from_tty; +{ +} + +/* This is an empty "sfunc". */ +static void empty_sfunc PARAMS ((char *, int, struct cmd_list_element *)); + +static void +empty_sfunc (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ +} + +/* Add element named NAME to command list LIST (the list for set + or some sublist thereof). + CLASS is as in add_cmd. + VAR_TYPE is the kind of thing we are setting. + VAR is address of the variable being controlled by this command. + DOC is the documentation string. */ + +struct cmd_list_element * +add_set_cmd (name, class, var_type, var, doc, list) + char *name; + enum command_class class; + var_types var_type; + char *var; + char *doc; + struct cmd_list_element **list; +{ + struct cmd_list_element *c + = add_cmd (name, class, NO_FUNCTION, doc, list); + + c->type = set_cmd; + c->var_type = var_type; + c->var = var; + /* This needs to be something besides NO_FUNCTION so that this isn't + treated as a help class. */ + c->function.sfunc = empty_sfunc; + return c; +} + +/* Add element named NAME to command list LIST (the list for set + or some sublist thereof). + CLASS is as in add_cmd. + ENUMLIST is a list of strings which may follow NAME. + VAR is address of the variable which will contain the matching string + (from ENUMLIST). + DOC is the documentation string. */ + +struct cmd_list_element * +add_set_enum_cmd (name, class, enumlist, var, doc, list) + char *name; + enum command_class class; + char *enumlist[]; + char *var; + char *doc; + struct cmd_list_element **list; +{ + struct cmd_list_element *c + = add_set_cmd (name, class, var_enum, var, doc, list); + + c->enums = enumlist; + + return c; +} + +/* Where SETCMD has already been added, add the corresponding show + command to LIST and return a pointer to it. */ +struct cmd_list_element * +add_show_from_set (setcmd, list) + struct cmd_list_element *setcmd; + struct cmd_list_element **list; +{ + struct cmd_list_element *showcmd = + (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + memcpy (showcmd, setcmd, sizeof (struct cmd_list_element)); + delete_cmd (showcmd->name, list); + showcmd->type = show_cmd; + + /* Replace "set " at start of docstring with "show ". */ + if (setcmd->doc[0] == 'S' && setcmd->doc[1] == 'e' + && setcmd->doc[2] == 't' && setcmd->doc[3] == ' ') + showcmd->doc = concat ("Show ", setcmd->doc + 4, NULL); + else + fprintf_unfiltered (gdb_stderr, "GDB internal error: Bad docstring for set command\n"); + + showcmd->next = *list; + *list = showcmd; + return showcmd; +} + +/* Remove the command named NAME from the command list. */ + +void +delete_cmd (name, list) + char *name; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c; + struct cmd_list_element *p; + + while (*list && STREQ ((*list)->name, name)) + { + if ((*list)->hookee) + (*list)->hookee->hook = 0; /* Hook slips out of its mouth */ + p = (*list)->next; + free ((PTR)*list); + *list = p; + } + + if (*list) + for (c = *list; c->next;) + { + if (STREQ (c->next->name, name)) + { + if (c->next->hookee) + c->next->hookee->hook = 0; /* hooked cmd gets away. */ + p = c->next->next; + free ((PTR)c->next); + c->next = p; + } + else + c = c->next; + } +} + +/* This command really has to deal with two things: + * 1) I want documentation on *this string* (usually called by + * "help commandname"). + * 2) I want documentation on *this list* (usually called by + * giving a command that requires subcommands. Also called by saying + * just "help".) + * + * I am going to split this into two seperate comamnds, help_cmd and + * help_list. + */ + +void +help_cmd (command, stream) + char *command; + GDB_FILE *stream; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (!command) + { + help_list (cmdlist, "", all_classes, stream); + return; + } + + c = lookup_cmd (&command, cmdlist, "", 0, 0); + + if (c == 0) + return; + + /* There are three cases here. + If c->prefixlist is nonzero, we have a prefix command. + Print its documentation, then list its subcommands. + + If c->function is nonzero, we really have a command. + Print its documentation and return. + + If c->function is zero, we have a class name. + Print its documentation (as if it were a command) + and then set class to the number of this class + so that the commands in the class will be listed. */ + + fputs_filtered (c->doc, stream); + fputs_filtered ("\n", stream); + + if (c->prefixlist == 0 && c->function.cfunc != NULL) + return; + fprintf_filtered (stream, "\n"); + + /* If this is a prefix command, print it's subcommands */ + if (c->prefixlist) + help_list (*c->prefixlist, c->prefixname, all_commands, stream); + + /* If this is a class name, print all of the commands in the class */ + if (c->function.cfunc == NULL) + help_list (cmdlist, "", c->class, stream); + + if (c->hook) + fprintf_filtered (stream, "\nThis command has a hook defined: %s\n", + c->hook->name); +} + +/* + * Get a specific kind of help on a command list. + * + * LIST is the list. + * CMDTYPE is the prefix to use in the title string. + * CLASS is the class with which to list the nodes of this list (see + * documentation for help_cmd_list below), As usual, ALL_COMMANDS for + * everything, ALL_CLASSES for just classes, and non-negative for only things + * in a specific class. + * and STREAM is the output stream on which to print things. + * If you call this routine with a class >= 0, it recurses. + */ +void +help_list (list, cmdtype, class, stream) + struct cmd_list_element *list; + char *cmdtype; + enum command_class class; + GDB_FILE *stream; +{ + int len; + char *cmdtype1, *cmdtype2; + + /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */ + len = strlen (cmdtype); + cmdtype1 = (char *) alloca (len + 1); + cmdtype1[0] = 0; + cmdtype2 = (char *) alloca (len + 4); + cmdtype2[0] = 0; + if (len) + { + cmdtype1[0] = ' '; + strncpy (cmdtype1 + 1, cmdtype, len - 1); + cmdtype1[len] = 0; + strncpy (cmdtype2, cmdtype, len - 1); + strcpy (cmdtype2 + len - 1, " sub"); + } + + if (class == all_classes) + fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2); + else + fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2); + + help_cmd_list (list, class, cmdtype, (int)class >= 0, stream); + + if (class == all_classes) + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by a class name for a list of commands in that class.", + cmdtype1); + + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by %scommand name for full documentation.\n\ +Command name abbreviations are allowed if unambiguous.\n", + cmdtype1, cmdtype2); +} + +/* Print only the first line of STR on STREAM. */ +static void +print_doc_line (stream, str) + GDB_FILE *stream; + char *str; +{ + static char *line_buffer = 0; + static int line_size; + register char *p; + + if (!line_buffer) + { + line_size = 80; + line_buffer = (char *) xmalloc (line_size); + } + + p = str; + while (*p && *p != '\n' && *p != '.' && *p != ',') + p++; + if (p - str > line_size - 1) + { + line_size = p - str + 1; + free ((PTR)line_buffer); + line_buffer = (char *) xmalloc (line_size); + } + strncpy (line_buffer, str, p - str); + line_buffer[p - str] = '\0'; + if (islower (line_buffer[0])) + line_buffer[0] = toupper (line_buffer[0]); + fputs_filtered (line_buffer, stream); +} + +/* + * Implement a help command on command list LIST. + * RECURSE should be non-zero if this should be done recursively on + * all sublists of LIST. + * PREFIX is the prefix to print before each command name. + * STREAM is the stream upon which the output should be written. + * CLASS should be: + * A non-negative class number to list only commands in that + * class. + * ALL_COMMANDS to list all commands in list. + * ALL_CLASSES to list all classes in list. + * + * Note that RECURSE will be active on *all* sublists, not just the + * ones selected by the criteria above (ie. the selection mechanism + * is at the low level, not the high-level). + */ +void +help_cmd_list (list, class, prefix, recurse, stream) + struct cmd_list_element *list; + enum command_class class; + char *prefix; + int recurse; + GDB_FILE *stream; +{ + register struct cmd_list_element *c; + + for (c = list; c; c = c->next) + { + if (c->abbrev_flag == 0 && + (class == all_commands + || (class == all_classes && c->function.cfunc == NULL) + || (class == c->class && c->function.cfunc != NULL))) + { + fprintf_filtered (stream, "%s%s -- ", prefix, c->name); + print_doc_line (stream, c->doc); + fputs_filtered ("\n", stream); + } + if (recurse + && c->prefixlist != 0 + && c->abbrev_flag == 0) + help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream); + } +} + +/* This routine takes a line of TEXT and a CLIST in which to start the + lookup. When it returns it will have incremented the text pointer past + the section of text it matched, set *RESULT_LIST to point to the list in + which the last word was matched, and will return a pointer to the cmd + list element which the text matches. It will return NULL if no match at + all was possible. It will return -1 (cast appropriately, ick) if ambigous + matches are possible; in this case *RESULT_LIST will be set to point to + the list in which there are ambiguous choices (and *TEXT will be set to + the ambiguous text string). + + If the located command was an abbreviation, this routine returns the base + command of the abbreviation. + + It does no error reporting whatsoever; control will always return + to the superior routine. + + In the case of an ambiguous return (-1), *RESULT_LIST will be set to point + at the prefix_command (ie. the best match) *or* (special case) will be NULL + if no prefix command was ever found. For example, in the case of "info a", + "info" matches without ambiguity, but "a" could be "args" or "address", so + *RESULT_LIST is set to the cmd_list_element for "info". So in this case + RESULT_LIST should not be interpeted as a pointer to the beginning of a + list; it simply points to a specific command. In the case of an ambiguous + return *TEXT is advanced past the last non-ambiguous prefix (e.g. + "info t" can be "info types" or "info target"; upon return *TEXT has been + advanced past "info "). + + If RESULT_LIST is NULL, don't set *RESULT_LIST (but don't otherwise + affect the operation). + + This routine does *not* modify the text pointed to by TEXT. + + If IGNORE_HELP_CLASSES is nonzero, ignore any command list elements which + are actually help classes rather than commands (i.e. the function field of + the struct cmd_list_element is NULL). */ + +struct cmd_list_element * +lookup_cmd_1 (text, clist, result_list, ignore_help_classes) + char **text; + struct cmd_list_element *clist, **result_list; + int ignore_help_classes; +{ + char *p, *command; + int len, tmp, nfound; + struct cmd_list_element *found, *c; + + while (**text == ' ' || **text == '\t') + (*text)++; + + /* Treating underscores as part of command words is important + so that "set args_foo()" doesn't get interpreted as + "set args _foo()". */ + for (p = *text; + *p && (isalnum(*p) || *p == '-' || *p == '_'); + p++) + ; + + /* If nothing but whitespace, return 0. */ + if (p == *text) + return 0; + + len = p - *text; + + /* *text and p now bracket the first command word to lookup (and + it's length is len). We copy this into a local temporary, + converting to lower case as we go. */ + + command = (char *) alloca (len + 1); + for (tmp = 0; tmp < len; tmp++) + { + char x = (*text)[tmp]; + command[tmp] = isupper(x) ? tolower(x) : x; + } + command[len] = '\0'; + + /* Look it up. */ + found = 0; + nfound = 0; + for (c = clist; c; c = c->next) + if (!strncmp (command, c->name, len) + && (!ignore_help_classes || c->function.cfunc)) + { + found = c; + nfound++; + if (c->name[len] == '\0') + { + nfound = 1; + break; + } + } + + /* If nothing matches, we have a simple failure. */ + if (nfound == 0) + return 0; + + if (nfound > 1) + { + if (result_list != NULL) + /* Will be modified in calling routine + if we know what the prefix command is. */ + *result_list = 0; + return (struct cmd_list_element *) -1; /* Ambiguous. */ + } + + /* We've matched something on this list. Move text pointer forward. */ + + *text = p; + + /* If this was an abbreviation, use the base command instead. */ + + if (found->cmd_pointer) + found = found->cmd_pointer; + + /* If we found a prefix command, keep looking. */ + + if (found->prefixlist) + { + c = lookup_cmd_1 (text, *found->prefixlist, result_list, + ignore_help_classes); + if (!c) + { + /* Didn't find anything; this is as far as we got. */ + if (result_list != NULL) + *result_list = clist; + return found; + } + else if (c == (struct cmd_list_element *) -1) + { + /* We've gotten this far properley, but the next step + is ambiguous. We need to set the result list to the best + we've found (if an inferior hasn't already set it). */ + if (result_list != NULL) + if (!*result_list) + /* This used to say *result_list = *found->prefixlist + If that was correct, need to modify the documentation + at the top of this function to clarify what is supposed + to be going on. */ + *result_list = found; + return c; + } + else + { + /* We matched! */ + return c; + } + } + else + { + if (result_list != NULL) + *result_list = clist; + return found; + } +} + +/* All this hair to move the space to the front of cmdtype */ + +static void +undef_cmd_error (cmdtype, q) + char *cmdtype, *q; +{ + error ("Undefined %scommand: \"%s\". Try \"help%s%.*s\".", + cmdtype, + q, + *cmdtype? " ": "", + strlen(cmdtype)-1, + cmdtype); +} + +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. + + If INGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; + int ignore_help_classes; +{ + struct cmd_list_element *last_list = 0; + struct cmd_list_element *c = + lookup_cmd_1 (line, list, &last_list, ignore_help_classes); +#if 0 + /* This is wrong for complete_command. */ + char *ptr = (*line) + strlen (*line) - 1; + + /* Clear off trailing whitespace. */ + while (ptr >= *line && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; +#endif + + if (!c) + { + if (!allow_unknown) + { + if (!*line) + error ("Lack of needed %scommand", cmdtype); + else + { + char *p = *line, *q; + + while (isalnum(*p) || *p == '-') + p++; + + q = (char *) alloca (p - *line + 1); + strncpy (q, *line, p - *line); + q[p-*line] = '\0'; + undef_cmd_error (cmdtype, q); + } + } + else + return 0; + } + else if (c == (struct cmd_list_element *) -1) + { + /* Ambigous. Local values should be off prefixlist or called + values. */ + int local_allow_unknown = (last_list ? last_list->allow_unknown : + allow_unknown); + char *local_cmdtype = last_list ? last_list->prefixname : cmdtype; + struct cmd_list_element *local_list = + (last_list ? *(last_list->prefixlist) : list); + + if (local_allow_unknown < 0) + { + if (last_list) + return last_list; /* Found something. */ + else + return 0; /* Found nothing. */ + } + else + { + /* Report as error. */ + int amb_len; + char ambbuf[100]; + + for (amb_len = 0; + ((*line)[amb_len] && (*line)[amb_len] != ' ' + && (*line)[amb_len] != '\t'); + amb_len++) + ; + + ambbuf[0] = 0; + for (c = local_list; c; c = c->next) + if (!strncmp (*line, c->name, amb_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < (int)sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype, + *line, ambbuf); + return 0; /* lint */ + } + } + else + { + /* We've got something. It may still not be what the caller + wants (if this command *needs* a subcommand). */ + while (**line == ' ' || **line == '\t') + (*line)++; + + if (c->prefixlist && **line && !c->allow_unknown) + undef_cmd_error (c->prefixname, *line); + + /* Seems to be what he wants. Return it. */ + return c; + } + return 0; +} + +#if 0 +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; +{ + register char *p; + register struct cmd_list_element *c, *found; + int nfound; + char ambbuf[100]; + char *processed_cmd; + int i, cmd_len; + + /* Skip leading whitespace. */ + + while (**line == ' ' || **line == '\t') + (*line)++; + + /* Clear out trailing whitespace. */ + + p = *line + strlen (*line); + while (p != *line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = 0; + + /* Find end of command name. */ + + p = *line; + while (*p == '-' || isalnum(*p)) + p++; + + /* Look up the command name. + If exact match, keep that. + Otherwise, take command abbreviated, if unique. Note that (in my + opinion) a null string does *not* indicate ambiguity; simply the + end of the argument. */ + + if (p == *line) + { + if (!allow_unknown) + error ("Lack of needed %scommand", cmdtype); + return 0; + } + + /* Copy over to a local buffer, converting to lowercase on the way. + This is in case the command being parsed is a subcommand which + doesn't match anything, and that's ok. We want the original + untouched for the routine of the original command. */ + + processed_cmd = (char *) alloca (p - *line + 1); + for (cmd_len = 0; cmd_len < p - *line; cmd_len++) + { + char x = (*line)[cmd_len]; + if (isupper(x)) + processed_cmd[cmd_len] = tolower(x); + else + processed_cmd[cmd_len] = x; + } + processed_cmd[cmd_len] = '\0'; + + /* Check all possibilities in the current command list. */ + found = 0; + nfound = 0; + for (c = list; c; c = c->next) + { + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + found = c; + nfound++; + if (c->name[cmd_len] == 0) + { + nfound = 1; + break; + } + } + } + + /* Report error for undefined command name. */ + + if (nfound != 1) + { + if (nfound > 1 && allow_unknown >= 0) + { + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, + processed_cmd, ambbuf); + } + else if (!allow_unknown) + error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd); + return 0; + } + + /* Skip whitespace before the argument. */ + + while (*p == ' ' || *p == '\t') p++; + *line = p; + + if (found->prefixlist && *p) + { + c = lookup_cmd (line, *found->prefixlist, found->prefixname, + found->allow_unknown); + if (c) + return c; + } + + return found; +} +#endif + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in LIST of TEXT. + + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. 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 ** +complete_on_cmdlist (list, text, word) + struct cmd_list_element *list; + char *text; + char *word; +{ + struct cmd_list_element *ptr; + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + + sizeof_matchlist = 10; + matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); + matches = 0; + + for (ptr = list; ptr; ptr = ptr->next) + if (!strncmp (ptr->name, text, textlen) + && !ptr->abbrev_flag + && (ptr->function.cfunc + || ptr->prefixlist)) + { + 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); + if (word == text) + strcpy (matchlist[matches], ptr->name); + else if (word > text) + { + /* Return some portion of ptr->name. */ + strcpy (matchlist[matches], 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); + } + ++matches; + } + + if (matches == 0) + { + free ((PTR)matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in CMD of TEXT. + + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. 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 ** +complete_on_enum (enumlist, text, word) + char **enumlist; + char *text; + char *word; +{ + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + int i; + 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 *))); + } + + matchlist[matches] = (char *) + xmalloc (strlen (word) + strlen (name) + 1); + if (word == text) + strcpy (matchlist[matches], name); + else if (word > text) + { + /* Return some portion of name. */ + strcpy (matchlist[matches], 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); + } + ++matches; + } + + if (matches == 0) + { + free ((PTR)matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc ((char *)matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +static int +parse_binary_operation (arg) + char *arg; +{ + int length; + + if (!arg || !*arg) + return 1; + + length = strlen (arg); + + while (arg[length - 1] == ' ' || arg[length - 1] == '\t') + length--; + + if (!strncmp (arg, "on", length) + || !strncmp (arg, "1", length) + || !strncmp (arg, "yes", length)) + return 1; + else + if (!strncmp (arg, "off", length) + || !strncmp (arg, "0", length) + || !strncmp (arg, "no", length)) + return 0; + else + { + error ("\"on\" or \"off\" expected."); + return 0; + } +} + +/* 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. */ +void +do_setshow_command (arg, from_tty, c) + char *arg; + int from_tty; + struct cmd_list_element *c; +{ + if (c->type == set_cmd) + { + switch (c->var_type) + { + 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') + { + 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 (&p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) + *q++ = ch; + } + else + *q++ = ch; + } +#if 0 + if (*(p - 1) != '\\') + *q++ = ' '; +#endif + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = new; + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **) c->var = savestring (arg, strlen (arg)); + break; + case var_filename: + if (arg == NULL) + error_no_arg ("filename to set it to."); + if (*(char **)c->var != NULL) + free (*(char **)c->var); + *(char **)c->var = tilde_expand (arg); + break; + case var_boolean: + *(int *) c->var = parse_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_address (arg); + if (*(unsigned int *) c->var == 0) + *(unsigned int *) c->var = UINT_MAX; + break; + case var_integer: + { + unsigned int val; + if (arg == NULL) + error_no_arg ("integer to set it to."); + val = parse_and_eval_address (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; + } + case var_zinteger: + if (arg == NULL) + error_no_arg ("integer to set it to."); + *(int *) c->var = parse_and_eval_address (arg); + break; + case var_enum: + { + int i; + int len; + int nmatches; + char *match; + char *p; + + p = strchr (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) + { + match = c->enums[i]; + nmatches++; + } + + if (nmatches <= 0) + error ("Undefined item: \"%s\".", arg); + + if (nmatches > 1) + error ("Ambiguous item \"%s\".", arg); + + *(char **)c->var = match; + } + break; + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + } + else if (c->type == show_cmd) + { + /* Print doc minus "show" at start. */ + print_doc_line (gdb_stdout, c->doc + 5); + + fputs_filtered (" is ", gdb_stdout); + wrap_here (" "); + switch (c->var_type) + { + case var_string: + { + unsigned char *p; + fputs_filtered ("\"", gdb_stdout); + for (p = *(unsigned char **) c->var; *p != '\0'; p++) + gdb_printchar (*p, gdb_stdout, '"'); + fputs_filtered ("\"", gdb_stdout); + } + break; + case var_string_noescape: + case var_filename: + case var_enum: + fputs_filtered ("\"", gdb_stdout); + fputs_filtered (*(char **) c->var, gdb_stdout); + fputs_filtered ("\"", gdb_stdout); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", gdb_stdout); + break; + case var_uinteger: + if (*(unsigned int *) c->var == UINT_MAX) { + fputs_filtered ("unlimited", gdb_stdout); + break; + } + /* else fall through */ + case var_zinteger: + fprintf_filtered (gdb_stdout, "%u", *(unsigned int *) c->var); + break; + case var_integer: + if (*(int *) c->var == INT_MAX) + { + fputs_filtered ("unlimited", gdb_stdout); + } + else + fprintf_filtered (gdb_stdout, "%d", *(int *) c->var); + break; + + default: + error ("gdb internal error: bad var_type in do_setshow_command"); + } + fputs_filtered (".\n", gdb_stdout); + } + else + error ("gdb internal error: bad cmd_type in do_setshow_command"); + (*c->function.sfunc) (NULL, from_tty, c); +} + +/* Show all the settings in a list of show commands. */ + +void +cmd_show_list (list, from_tty, prefix) + struct cmd_list_element *list; + int from_tty; + char *prefix; +{ + for (; list != NULL; list = list->next) { + /* If we find a prefix, run its list, prefixing our output by its + prefix (with "show " skipped). */ + if (list->prefixlist && !list->abbrev_flag) + cmd_show_list (*list->prefixlist, from_tty, list->prefixname + 5); + if (list->type == show_cmd) + { + fputs_filtered (prefix, gdb_stdout); + fputs_filtered (list->name, gdb_stdout); + fputs_filtered (": ", gdb_stdout); + do_setshow_command ((char *)NULL, from_tty, list); + } + } +} + +/* ARGSUSED */ +static void +shell_escape (arg, from_tty) + char *arg; + int from_tty; +{ +#ifdef CANT_FORK + /* FIXME: what about errors (I don't know how GO32 system() handles + them)? */ + system (arg); +#else /* Can fork. */ + int rc, status, pid; + char *p, *user_shell; + + if ((user_shell = (char *) getenv ("SHELL")) == NULL) + user_shell = "/bin/sh"; + + /* Get the name of the shell for arg0 */ + if ((p = strrchr (user_shell, '/')) == NULL) + p = user_shell; + else + p++; /* Get past '/' */ + + if ((pid = fork()) == 0) + { + if (!arg) + execl (user_shell, p, 0); + else + execl (user_shell, p, "-c", arg, 0); + + fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell, + safe_strerror (errno)); + gdb_flush (gdb_stderr); + _exit (0177); + } + + if (pid != -1) + while ((rc = wait (&status)) != pid && rc != -1) + ; + else + error ("Fork failed"); +#endif /* Can fork. */ +} + +static void +make_command (arg, from_tty) + char *arg; + int from_tty; +{ + char *p; + + if (arg == 0) + p = "make"; + else + { + p = xmalloc (sizeof("make ") + strlen(arg)); + strcpy (p, "make "); + strcpy (p + sizeof("make ")-1, arg); + } + + shell_escape (p, from_tty); +} + +static void +show_user_1 (c, stream) + struct cmd_list_element *c; + GDB_FILE *stream; +{ + register struct command_line *cmdlines; + + cmdlines = c->user_commands; + if (!cmdlines) + return; + fputs_filtered ("User command ", stream); + fputs_filtered (c->name, stream); + fputs_filtered (":\n", stream); + + while (cmdlines) + { + print_command_line (cmdlines, 4); + cmdlines = cmdlines->next; + } + fputs_filtered ("\n", stream); +} + +/* ARGSUSED */ +static void +show_user (args, from_tty) + char *args; + int from_tty; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (args) + { + c = lookup_cmd (&args, cmdlist, "", 0, 1); + if (c->class != class_user) + error ("Not a user command."); + show_user_1 (c, gdb_stdout); + } + else + { + for (c = cmdlist; c; c = c->next) + { + if (c->class == class_user) + show_user_1 (c, gdb_stdout); + } + } +} + +void +_initialize_command () +{ + add_com ("shell", class_support, shell_escape, + "Execute the rest of the line as a shell command. \n\ +With no arguments, run an inferior shell."); + add_com ("make", class_support, make_command, + "Run the ``make'' program using the rest of the line as arguments."); + add_cmd ("user", no_class, show_user, + "Show definitions of 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); +} diff --git a/contrib/gdb/gdb/command.h b/contrib/gdb/gdb/command.h new file mode 100644 index 000000000000..5a209234e08e --- /dev/null +++ b/contrib/gdb/gdb/command.h @@ -0,0 +1,259 @@ +/* Header file for command-reading library command.c. + Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (COMMAND_H) +#define COMMAND_H 1 + +/* Not a set/show command. Note that some commands which begin with + "set" or "show" might be in this category, if their syntax does + not fall into one of the following categories. */ +typedef enum cmd_types { + not_set_cmd, + set_cmd, + show_cmd +} cmd_types; + +/* Types of "set" or "show" command. */ +typedef enum var_types { + /* "on" or "off". *VAR is an integer which is nonzero for on, + zero for off. */ + var_boolean, + /* Unsigned Integer. *VAR is an unsigned int. The user can type 0 + to mean "unlimited", which is stored in *VAR as UINT_MAX. */ + var_uinteger, + + /* 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. */ + var_integer, + + /* String which the user enters with escapes (e.g. the user types \n and + it is a real newline in the stored string). + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string, + /* String which stores what the user types verbatim. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string_noescape, + /* String which stores a filename. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_filename, + /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except + that zero really means zero. */ + var_zinteger, + /* Enumerated type. Can only have one of the specified values. *VAR is a + char pointer to the name of the element that we find. */ + var_enum +} var_types; + +/* This structure records one command'd definition. */ + +struct cmd_list_element + { + /* Points to next command in this list. */ + struct cmd_list_element *next; + + /* Name of this command. */ + char *name; + + /* Command class; class values are chosen by application program. */ + enum command_class class; + + /* Function definition of this command. + NO_FUNCTION for command class names and for help topics that + are not really commands. */ + union + { + /* If type is not_set_cmd, call it like this: */ + void (*cfunc) PARAMS ((char *args, int from_tty)); + + /* If type is cmd_set or show_cmd, first set the variables, and + then call this. */ + void (*sfunc) PARAMS ((char *args, int from_tty, + struct cmd_list_element *c)); + } function; +# define NO_FUNCTION ((void (*) PARAMS((char *args, int from_tty))) 0) + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, + the full documentation. First line should end with a period. + Entire string should also end with a period, not a newline. */ + char *doc; + + /* Hook for another command to be executed before this command. */ + struct cmd_list_element *hook; + + /* Nonzero identifies a prefix command. For them, the address + of the variable containing the list of subcommands. */ + struct cmd_list_element **prefixlist; + + /* For prefix commands only: + String containing prefix commands to get here: this one + plus any others needed to get to it. Should end in a space. + It is used before the word "command" in describing the + commands reached through this prefix. */ + char *prefixname; + + /* For prefix commands only: + nonzero means do not get an error if subcommand is not + recognized; call the prefix's own function in that case. */ + char allow_unknown; + + /* Nonzero says this is an abbreviation, and should not + be mentioned in lists of commands. + This allows "br" to complete to "break", which it + otherwise wouldn't. */ + char abbrev_flag; + + /* Completion routine for this command. TEXT is the text beyond + what was matched for the command itself (leading whitespace is + skipped). It stops where we are supposed to stop completing + (rl_point) and is '\0' terminated. + + Return value is a malloc'd vector of pointers to possible completions + terminated with NULL. If there are no completions, returning a pointer + to a NULL would work but returning NULL itself is also valid. + WORD points in the same buffer as TEXT, and completions should be + returned relative to this position. 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) PARAMS ((char *text, char *word)); + + /* Type of "set" or "show" command (or SET_NOT_SET if not "set" + or "show"). */ + cmd_types type; + + /* Pointer to variable affected by "set" and "show". Doesn't matter + if type is not_set. */ + char *var; + + /* What kind of variable is *VAR? */ + var_types var_type; + + /* Pointer to NULL terminated list of enumerated values (like argv). */ + char **enums; + + /* Pointer to command strings of user-defined commands */ + struct command_line *user_commands; + + /* Pointer to command that is hooked by this one, + so the hook can be removed when this one is deleted. */ + struct cmd_list_element *hookee; + + /* Pointer to command that is aliased by this one, so the + aliased command can be located in case it has been hooked. */ + struct cmd_list_element *cmd_pointer; + }; + +/* Forward-declarations of the entry-points of command.c. */ + +extern struct cmd_list_element * +add_cmd PARAMS ((char *, enum command_class, void (*fun) (char *, int), + char *, struct cmd_list_element **)); + +extern struct cmd_list_element * +add_alias_cmd PARAMS ((char *, char *, enum command_class, int, + struct cmd_list_element **)); + +extern struct cmd_list_element * +add_prefix_cmd PARAMS ((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 PARAMS ((char *, enum command_class, + void (*fun) (char *, int), char *, + struct cmd_list_element **, char *, int, + struct cmd_list_element **)); + +extern struct cmd_list_element * +lookup_cmd PARAMS ((char **, struct cmd_list_element *, char *, int, int)); + +extern struct cmd_list_element * +lookup_cmd_1 PARAMS ((char **, struct cmd_list_element *, + struct cmd_list_element **, int)); + +extern void +add_com PARAMS ((char *, enum command_class, void (*fun)(char *, int), + char *)); + +extern void +add_com_alias PARAMS ((char *, char *, enum command_class, int)); + +extern void +add_info PARAMS ((char *, void (*fun) (char *, int), char *)); + +extern void +add_info_alias PARAMS ((char *, char *, int)); + +extern char ** +complete_on_cmdlist PARAMS ((struct cmd_list_element *, char *, char *)); + +extern char ** +complete_on_enum PARAMS ((char **enumlist, char *, char *)); + +extern void +delete_cmd PARAMS ((char *, struct cmd_list_element **)); + +extern void +help_cmd PARAMS ((char *, GDB_FILE *)); + +extern void +help_list PARAMS ((struct cmd_list_element *, char *, enum command_class, + GDB_FILE *)); + +extern void +help_cmd_list PARAMS ((struct cmd_list_element *, enum command_class, char *, + int, GDB_FILE *)); + +extern struct cmd_list_element * +add_set_cmd PARAMS ((char *, enum command_class, var_types, char *, char *, + struct cmd_list_element **)); + +extern struct cmd_list_element * +add_set_enum_cmd PARAMS ((char *name, enum command_class, char *list[], + char *var, char *doc, struct cmd_list_element **c)); + +extern struct cmd_list_element * +add_show_from_set PARAMS ((struct cmd_list_element *, + struct cmd_list_element **)); + +/* 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 PARAMS ((char *, int, struct cmd_list_element *)); + +/* Do a "show" command for each thing on a command list. */ + +extern void +cmd_show_list PARAMS ((struct cmd_list_element *, int, char *)); + +extern void +error_no_arg PARAMS ((char *)); + +extern void +dont_repeat PARAMS ((void)); + +/* Used to mark commands that don't do anything. If we just leave the + function field NULL, the command is interpreted as a help topic, or + as a class of commands. */ + +extern void +not_just_help_class_command PARAMS ((char *, int)); + +#endif /* !defined (COMMAND_H) */ diff --git a/contrib/gdb/gdb/complaints.c b/contrib/gdb/gdb/complaints.c new file mode 100644 index 000000000000..9db8b4a20bd9 --- /dev/null +++ b/contrib/gdb/gdb/complaints.c @@ -0,0 +1,171 @@ +/* Support for complaint handling during symbol reading in GDB. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "complaints.h" +#include "gdbcmd.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +/* Structure to manage complaints about symbol file contents. */ + +struct complaint complaint_root[1] = { + { + (char *) NULL, /* Complaint message */ + 0, /* Complaint counter */ + complaint_root /* Next complaint. */ + } +}; + +/* How many complaints about a particular thing should be printed before + we stop whining about it? Default is no whining at all, since so many + systems have ill-constructed symbol files. */ + +static unsigned int stop_whining = 0; + +/* Should each complaint be self explanatory, or should we assume that + a series of complaints is being produced? + case 0: self explanatory message. + case 1: First message of a series that must start off with explanation. + case 2: Subsequent message, when user already knows we are reading + symbols and we can just state our piece. */ + +static int complaint_series = 0; + +/* External variables and functions referenced. */ + +extern int info_verbose; + + +/* Functions to handle complaints during symbol reading. */ + +/* Print a complaint about the input symbols, and link the complaint block + into a chain for later handling. */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +complain (struct complaint *complaint, ...) +#else +complain (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, complaint); +#else + struct complaint *complaint; + + va_start (args); + complaint = va_arg (args, struct complaint *); +#endif + + complaint -> counter++; + if (complaint -> next == NULL) + { + complaint -> next = complaint_root -> next; + complaint_root -> next = complaint; + } + if (complaint -> counter > stop_whining) + { + return; + } + wrap_here (""); + + switch (complaint_series + (info_verbose << 1)) + { + + /* Isolated messages, must be self-explanatory. */ + case 0: + begin_line (); + puts_filtered ("During symbol reading, "); + wrap_here (""); + vprintf_filtered (complaint -> message, args); + puts_filtered (".\n"); + break; + + /* First of a series, without `set verbose'. */ + case 1: + begin_line (); + puts_filtered ("During symbol reading..."); + vprintf_filtered (complaint -> message, args); + puts_filtered ("..."); + wrap_here (""); + complaint_series++; + break; + + /* Subsequent messages of a series, or messages under `set verbose'. + (We'll already have produced a "Reading in symbols for XXX..." + message and will clean up at the end with a newline.) */ + default: + vprintf_filtered (complaint -> message, args); + puts_filtered ("..."); + wrap_here (""); + } + /* If GDB dumps core, we'd like to see the complaints first. Presumably + GDB will not be sending so many complaints that this becomes a + performance hog. */ + gdb_flush (gdb_stdout); + va_end (args); +} + +/* Clear out all complaint counters that have ever been incremented. + If sym_reading is 1, be less verbose about successive complaints, + since the messages are appearing all together during a command that + reads symbols (rather than scattered around as psymtabs get fleshed + out into symtabs at random times). If noisy is 1, we are in a + noisy symbol reading command, and our caller will print enough + context for the user to figure it out. */ + +void +clear_complaints (sym_reading, noisy) + int sym_reading; + int noisy; +{ + struct complaint *p; + + for (p = complaint_root -> next; p != complaint_root; p = p -> next) + { + p -> counter = 0; + } + + if (!sym_reading && !noisy && complaint_series > 1) + { + /* Terminate previous series, since caller won't. */ + puts_filtered ("\n"); + } + + complaint_series = sym_reading ? 1 + noisy : 0; +} + +void +_initialize_complaints () +{ + add_show_from_set + (add_set_cmd ("complaints", class_support, var_zinteger, + (char *) &stop_whining, + "Set max number of complaints about incorrect symbols.", + &setlist), + &showlist); + +} diff --git a/contrib/gdb/gdb/complaints.h b/contrib/gdb/gdb/complaints.h new file mode 100644 index 000000000000..022bc19c3993 --- /dev/null +++ b/contrib/gdb/gdb/complaints.h @@ -0,0 +1,46 @@ +/* Definitions for complaint handling during symbol reading in GDB. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Support for complaining about things in the symbol file that aren't + catastrophic. + + Each such thing gets a counter. The first time we have the problem, + during a symbol read, we report it. At the end of symbol reading, + if verbose, we report how many of each problem we had. */ + +struct complaint +{ + char *message; + unsigned counter; + struct complaint *next; +}; + +/* Root of the chain of complaints that have at some point been issued. + This is used to reset the counters, and/or report the total counts. */ + +extern struct complaint complaint_root[1]; + +/* Functions that handle complaints. (in complaints.c) */ + +extern void +complain PARAMS ((struct complaint *, ...)); + +extern void +clear_complaints PARAMS ((int, int)); diff --git a/contrib/gdb/gdb/config.in b/contrib/gdb/gdb/config.in new file mode 100644 index 000000000000..a5c51adfd819 --- /dev/null +++ b/contrib/gdb/gdb/config.in @@ -0,0 +1,90 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if fpregset_t type is available. */ +#undef HAVE_FPREGSET_T + +/* Define if gregset_t type is available. */ +#undef HAVE_GREGSET_T + +/* Define if the "%Lg" format works to print long doubles. */ +#undef PRINTF_HAS_LONG_DOUBLE + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the sbrk function. */ +#undef HAVE_SBRK + +/* Define if you have the setpgid function. */ +#undef HAVE_SETPGID + +/* Define if you have the valloc function. */ +#undef HAVE_VALLOC + +/* Define if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LINK_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_SGTTY_H + +/* Define if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the dl library (-ldl). */ +#undef HAVE_LIBDL diff --git a/contrib/gdb/gdb/config/i386/cygwin32.mh b/contrib/gdb/gdb/config/i386/cygwin32.mh new file mode 100644 index 000000000000..25f15cfcd031 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/cygwin32.mh @@ -0,0 +1,6 @@ +MH_CFLAGS= +XM_FILE=xm-cygwin32.h +TERMCAP= +NATDEPFILES=win32-nat.o +XM_CLIBS=-lkernel32 + diff --git a/contrib/gdb/gdb/config/i386/cygwin32.mt b/contrib/gdb/gdb/config/i386/cygwin32.mt new file mode 100644 index 000000000000..22b45473ad61 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/cygwin32.mt @@ -0,0 +1,6 @@ +# Target: Intel 386 run win32 +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-cygwin32.h + + + diff --git a/contrib/gdb/gdb/config/i386/fbsd.mh b/contrib/gdb/gdb/config/i386/fbsd.mh new file mode 100644 index 000000000000..881fa65cb0a9 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/fbsd.mh @@ -0,0 +1,5 @@ +# Host: Intel 386 running FreeBSD +XDEPFILES= +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o core-aout.o i386b-nat.o +XM_FILE= xm-i386bsd.h +NAT_FILE= nm-fbsd.h diff --git a/contrib/gdb/gdb/config/i386/fbsd.mt b/contrib/gdb/gdb/config/i386/fbsd.mt new file mode 100644 index 000000000000..790e13751683 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/fbsd.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running FreeBSD +TDEPFILES= i386-tdep.o i387-tdep.o solib.o +TM_FILE= tm-i386bsd.h diff --git a/contrib/gdb/gdb/config/i386/gdbserve.mt b/contrib/gdb/gdb/config/i386/gdbserve.mt new file mode 100644 index 000000000000..d8a7cbaf43d8 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/gdbserve.mt @@ -0,0 +1,3 @@ +# Target: GDBSERVE.NLM running on a i386 +TDEPFILES= i386.o +CPU_FILE= i386 diff --git a/contrib/gdb/gdb/config/i386/go32.mh b/contrib/gdb/gdb/config/i386/go32.mh new file mode 100644 index 000000000000..521c7b7527f5 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/go32.mh @@ -0,0 +1,9 @@ +MH_CFLAGS=-D__GO32__ -D__MSDOS__ +XDEPFILES= go32-xdep.o +XM_FILE= xm-go32.h +TERMCAP= +HOST_IPC=-DDOS_IPC +SER_HARDWIRE= ser-go32.o +CC=i386-go32-gcc -O2 -fno-omit-frame-pointer + + diff --git a/contrib/gdb/gdb/config/i386/i386aix.mh b/contrib/gdb/gdb/config/i386/i386aix.mh new file mode 100644 index 000000000000..751f8136a325 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386aix.mh @@ -0,0 +1,12 @@ +# Host: IBM PS/2 (i386) running AIX PS/2 + +XM_FILE= xm-i386aix.h +XDEPFILES= + +NAT_FILE= nm-i386aix.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o i386aix-nat.o + +TERMCAP=-lcurses + +# Use gcc. Only coff output can be debugged +CC=gcc diff --git a/contrib/gdb/gdb/config/i386/i386aix.mt b/contrib/gdb/gdb/config/i386/i386aix.mt new file mode 100644 index 000000000000..12e0e1fc79a9 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386aix.mt @@ -0,0 +1,7 @@ +# This port, for aix ps/2 (i386), will allow you to debug the coff +# output generated gcc-2.3.3 + gas. It will not understand IBM's +# proprietary debug info. +# +# Target: IBM PS/2 (i386) running AIX PS/2 +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-i386aix.h diff --git a/contrib/gdb/gdb/config/i386/i386aout.mt b/contrib/gdb/gdb/config/i386/i386aout.mt new file mode 100644 index 000000000000..1c94ba5216ca --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386aout.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 with a.out +TDEPFILES= i386-tdep.o +TM_FILE= tm-i386v.h diff --git a/contrib/gdb/gdb/config/i386/i386bsd.mh b/contrib/gdb/gdb/config/i386/i386bsd.mh new file mode 100644 index 000000000000..f95c6ed8b12a --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386bsd.mh @@ -0,0 +1,7 @@ +# Host: Intel 386 running 386BSD + +XM_FILE= xm-i386bsd.h +XDEPFILES= + +NAT_FILE= nm-i386bsd.h +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o core-aout.o i386b-nat.o diff --git a/contrib/gdb/gdb/config/i386/i386bsd.mt b/contrib/gdb/gdb/config/i386/i386bsd.mt new file mode 100644 index 000000000000..ef6173111159 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386bsd.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running BSD +TM_FILE= tm-i386bsd.h +TDEPFILES= i386-tdep.o diff --git a/contrib/gdb/gdb/config/i386/i386dgux.mh b/contrib/gdb/gdb/config/i386/i386dgux.mh new file mode 100644 index 000000000000..bc2cee2af73a --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386dgux.mh @@ -0,0 +1,14 @@ +# Host: Intel 386 running DGUX, cloned from SVR4 + +XM_FILE= xm-i386v4.h +XDEPFILES= ser-tcp.o +# for network communication +XM_CLIBS= -lsocket -lnsl + +NAT_FILE= nm-i386v4.h +NATDEPFILES= corelow.o core-regset.o solib.o procfs.o fork-child.o i386v4-nat.o + +# SVR4 comes standard with terminfo, and in some implementations, the +# old termcap descriptions are incomplete. So ensure that we use the +# new terminfo interface and latest terminal descriptions. +TERMCAP=-lcurses diff --git a/contrib/gdb/gdb/config/i386/i386gnu.mh b/contrib/gdb/gdb/config/i386/i386gnu.mh new file mode 100644 index 000000000000..af3186ed6da0 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386gnu.mh @@ -0,0 +1,36 @@ +# Host: Intel 386 running the GNU Hurd +XDEPFILES= i387-tdep.o +NATDEPFILES= i386gnu-nat.o gnu-nat.o fork-child.o solib.o notify_S.o process_reply_S.o msg_reply_S.o msg_U.o exc_request_U.o exc_request_S.o +XM_FILE= xm-i386gnu.h +NAT_FILE= nm-gnu.h + +# Use our own user stubs for the msg rpcs, so we can make them time out, in +# case the program is fucked, or we guess the wrong signal thread. +msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' + +# ick +MIG = mig +MIGCOM = $(MIG) -cc cat - /dev/null + +# Reply servers need special massaging of the code mig generates, to make +# them work correctly for error returns in some cases. +%_reply_S.h %_reply_S.c: %_reply.defs + $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ + | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user /dev/null -header /dev/null \ + && $(AWK) -f $(srcdir)/reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c +# Normal servers +%_S.h %_S.c: %.defs + $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \ + | $(MIGCOM) -sheader $*_S.h -server $*_S.c -user /dev/null -header /dev/null +# User rpc stubs +%_U.h %_U.c: %.defs + $(CPP) $(CPPFLAGS) $($*-MIGUFLAGS) -x c $< \ + | $(MIGCOM) -sheader /dev/null -server /dev/null -user $*_U.c -header $*_U.h + +gnu-nat.o: process_reply_S.h exc_request_S.h notify_S.h msg_reply_S.h exc_request_U.h msg_U.h + +gnu-nat.o i386gnu-nat.o: gnu-nat.h + +# Don't use the mmalloc library in Mach 3. +MMALLOC = +MMALLOC_DISABLE = -DNO_MMALLOC diff --git a/contrib/gdb/gdb/config/i386/i386gnu.mt b/contrib/gdb/gdb/config/i386/i386gnu.mt new file mode 100644 index 000000000000..64fb01897127 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386gnu.mt @@ -0,0 +1,3 @@ +# Target: Intel 386/elf/GNU Hurd +TDEPFILES= i386-tdep.o +TM_FILE= tm-i386gnu.h diff --git a/contrib/gdb/gdb/config/i386/i386lynx.mh b/contrib/gdb/gdb/config/i386/i386lynx.mh new file mode 100644 index 000000000000..9cb086f6e39b --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386lynx.mh @@ -0,0 +1,11 @@ +# Host: Intel 386 running LynxOS + +XM_FILE= xm-i386lynx.h +XM_CLIBS= -lbsd +XDEPFILES= ser-tcp.o + +NAT_FILE= nm-i386lynx.h +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o lynx-nat.o + +GDBSERVER_LIBS= -lbsd +GDBSERVER_DEPFILES= low-lynx.o diff --git a/contrib/gdb/gdb/config/i386/i386lynx.mt b/contrib/gdb/gdb/config/i386/i386lynx.mt new file mode 100644 index 000000000000..6704b43e5b92 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386lynx.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running LynxOS +TDEPFILES= coff-solib.o i386-tdep.o i386ly-tdep.o +TM_FILE= tm-i386lynx.h diff --git a/contrib/gdb/gdb/config/i386/i386m3.mh b/contrib/gdb/gdb/config/i386/i386m3.mh new file mode 100644 index 000000000000..66f984798cb3 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386m3.mh @@ -0,0 +1,11 @@ +# Host: Intel 386 running Mach3 + +XDEPFILES= i387-tdep.o core-aout.o +NATDEPFILES= i386m3-nat.o m3-nat.o fork-child.o +NAT_CLIBS= -lmachid -lnetname -lmach +XM_FILE= xm-i386m3.h +NAT_FILE= nm-m3.h + +# Don't use the mmalloc library in Mach 3. +MMALLOC = +MMALLOC_DISABLE = -DNO_MMALLOC diff --git a/contrib/gdb/gdb/config/i386/i386m3.mt b/contrib/gdb/gdb/config/i386/i386m3.mt new file mode 100644 index 000000000000..e985ae345d98 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386m3.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 with a.out under Mach 3 +TDEPFILES= i386-tdep.o +TM_FILE= tm-i386m3.h diff --git a/contrib/gdb/gdb/config/i386/i386mach.mh b/contrib/gdb/gdb/config/i386/i386mach.mh new file mode 100644 index 000000000000..44766c51c529 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386mach.mh @@ -0,0 +1,10 @@ +# Host: Intel 386 running Mach + +# This is for mach2, maybe, or is obsolete (and seems to have only +# host and native, not target). Once we get the mach3 stuff working, +# I think it can go away. + +XDEPFILES= +XM_FILE= xm-i386mach.h +NAT_FILE= nm-i386mach.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o i386mach-nat.o diff --git a/contrib/gdb/gdb/config/i386/i386mk.mh b/contrib/gdb/gdb/config/i386/i386mk.mh new file mode 100644 index 000000000000..cf1da571b0be --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386mk.mh @@ -0,0 +1,8 @@ +# Host: Intel 386 running Mach3 with OSF 1/MK + +XDEPFILES= os-mach3.o i386mach3-xdep.o i387-tdep.o +XM_FILE= xm-i386osf1mk.h + +# Don't use the mmalloc library in Mach 3. +MMALLOC = +MMALLOC_DISABLE = -DNO_MMALLOC diff --git a/contrib/gdb/gdb/config/i386/i386mk.mt b/contrib/gdb/gdb/config/i386/i386mk.mt new file mode 100644 index 000000000000..aa2f6a48732f --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386mk.mt @@ -0,0 +1,6 @@ +# Target: Intel 386 with a.out in osf 1/mk +TDEPFILES= i386-tdep.o +TM_FILE= tm-i386osf1mk.h +TM_CFLAGS= -I/usr/mach3/include +TM_CLIBS= /usr/mach3/ccs/lib/libmachid.a /usr/mach3/ccs/lib/libnetname.a /usr/mach3/ccs/lib/libmach.a +OBJFORMATS= dbxread.o diff --git a/contrib/gdb/gdb/config/i386/i386nw.mt b/contrib/gdb/gdb/config/i386/i386nw.mt new file mode 100644 index 000000000000..3109c42149ef --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386nw.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running NetWare +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-i386nw.h diff --git a/contrib/gdb/gdb/config/i386/i386os9k.mt b/contrib/gdb/gdb/config/i386/i386os9k.mt new file mode 100644 index 000000000000..5a8794db58f0 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386os9k.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running OS9000 +TDEPFILES= i386-tdep.o remote-os9k.o +TM_FILE= tm-i386os9k.h diff --git a/contrib/gdb/gdb/config/i386/i386sco.mh b/contrib/gdb/gdb/config/i386/i386sco.mh new file mode 100644 index 000000000000..69076b54fae9 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386sco.mh @@ -0,0 +1,13 @@ +# Host: Intel 386 running SCO Unix (pre-SVR4) + +XM_FILE= xm-i386sco.h +XDEPFILES= +XM_CLIBS= -lPW + +NAT_FILE= nm-i386sco.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o core-aout.o i386v-nat.o + +#msg The SCO C compiler cannot parse symtab.h when value.h has been included. +#msg This is a bug in the compiler; the code is valid. +#msg Therefore, you must use GCC to compile GDB on SCO machines. +CC=gcc -D_POSIX_SOURCE=1 diff --git a/contrib/gdb/gdb/config/i386/i386sco4.mh b/contrib/gdb/gdb/config/i386/i386sco4.mh new file mode 100644 index 000000000000..a13f99399f09 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386sco4.mh @@ -0,0 +1,12 @@ +# Host: Intel 386 running SCO Unix 3.2v4 + +XM_FILE= xm-i386sco.h +XDEPFILES= +XM_CLIBS= -lPW + +NAT_FILE= nm-i386sco4.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o core-aout.o i386v-nat.o + +# The cc compiler mishandles const in cases like +# struct type ** const (c_builtin_types[]) = +MH_CFLAGS=-Dconst= diff --git a/contrib/gdb/gdb/config/i386/i386sco5.mh b/contrib/gdb/gdb/config/i386/i386sco5.mh new file mode 100644 index 000000000000..441a59c0d7a2 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386sco5.mh @@ -0,0 +1,17 @@ +# Host: Intel 386 running SCO OpenServer 5 +# Much like 3.2v4, except we don't have to avoid problems with const + +XM_FILE= xm-i386sco.h + +# +# Not all configurations of SCO OpenServer 5 come with the TCP/IP +# runtime, but all come with the development system, so we always +# have socket(), gethostbyname(), and friends. +# +XDEPFILES= ser-tcp.o +XM_CLIBS= -lPW -lsocket + +NAT_FILE= nm-i386sco5.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corefile.o core-aout.o corelow.o \ + i386v-nat.o solib.o + diff --git a/contrib/gdb/gdb/config/i386/i386sol2.mh b/contrib/gdb/gdb/config/i386/i386sol2.mh new file mode 100644 index 000000000000..d73ded282223 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386sol2.mh @@ -0,0 +1,12 @@ +# Host: Intel 386 running Solaris 2 (SVR4) + +XM_FILE= xm-i386v4.h +XDEPFILES= + +NAT_FILE= nm-i386v4.h +NATDEPFILES= core-regset.o procfs.o fork-child.o i386v4-nat.o corelow.o + +# SVR4 comes standard with terminfo, and in some implementations, the +# old termcap descriptions are incomplete. So ensure that we use the +# new terminfo interface and latest terminal descriptions. +TERMCAP=-ltermlib diff --git a/contrib/gdb/gdb/config/i386/i386sol2.mt b/contrib/gdb/gdb/config/i386/i386sol2.mt new file mode 100644 index 000000000000..0bbf9b369cbb --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386sol2.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running SVR4 +TDEPFILES= i386-tdep.o i387-tdep.o solib.o +TM_FILE= tm-i386v4.h diff --git a/contrib/gdb/gdb/config/i386/i386v.mh b/contrib/gdb/gdb/config/i386/i386v.mh new file mode 100644 index 000000000000..d67a30f73ec7 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386v.mh @@ -0,0 +1,8 @@ +# Host: Intel 386 running System V + +XM_FILE= xm-i386v.h +XDEPFILES= +XM_CLIBS= -lPW + +NAT_FILE= nm-i386v.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o core-aout.o i386v-nat.o diff --git a/contrib/gdb/gdb/config/i386/i386v.mt b/contrib/gdb/gdb/config/i386/i386v.mt new file mode 100644 index 000000000000..7242d3e8f389 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386v.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running System V +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-i386v.h diff --git a/contrib/gdb/gdb/config/i386/i386v32.mh b/contrib/gdb/gdb/config/i386/i386v32.mh new file mode 100644 index 000000000000..5b4175fa08c4 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386v32.mh @@ -0,0 +1,9 @@ +# Host: Intel 386 running System V release 3.2 + +XM_FILE= xm-i386v32.h +XDEPFILES= +XM_CLIBS= -lPW + +NAT_FILE= nm-i386v.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o core-aout.o i386v-nat.o + diff --git a/contrib/gdb/gdb/config/i386/i386v4.mh b/contrib/gdb/gdb/config/i386/i386v4.mh new file mode 100644 index 000000000000..aa701251b7dc --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386v4.mh @@ -0,0 +1,14 @@ +# Host: Intel 386 running SVR4 + +XM_FILE= xm-i386v4.h +XDEPFILES= +# for network communication +XM_CLIBS= -lsocket -lnsl + +NAT_FILE= nm-i386v4.h +NATDEPFILES= corelow.o core-regset.o solib.o procfs.o fork-child.o i386v4-nat.o + +# SVR4 comes standard with terminfo, and in some implementations, the +# old termcap descriptions are incomplete. So ensure that we use the +# new terminfo interface and latest terminal descriptions. +TERMCAP=-ltermlib diff --git a/contrib/gdb/gdb/config/i386/i386v4.mt b/contrib/gdb/gdb/config/i386/i386v4.mt new file mode 100644 index 000000000000..c22b6755985a --- /dev/null +++ b/contrib/gdb/gdb/config/i386/i386v4.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running SVR4 +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-i386v4.h diff --git a/contrib/gdb/gdb/config/i386/linux.mh b/contrib/gdb/gdb/config/i386/linux.mh new file mode 100644 index 000000000000..13c33102cb26 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/linux.mh @@ -0,0 +1,13 @@ +# Host: Intel 386 running Linux + +XM_FILE= xm-linux.h +XDEPFILES= ser-tcp.o + +# Needed for frexp() in libiberty for older a.out based systems and should be +# harmless to include for newer linux systems. +XM_CLIBS= -lm + +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o core-aout.o core-regset.o i386v-nat.o i386v4-nat.o + +GDBSERVER_DEPFILES= low-linux.o diff --git a/contrib/gdb/gdb/config/i386/linux.mt b/contrib/gdb/gdb/config/i386/linux.mt new file mode 100644 index 000000000000..b9d74048a859 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/linux.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 with a.out and ELF +TDEPFILES= i386-tdep.o i387-tdep.o +TM_FILE= tm-linux.h diff --git a/contrib/gdb/gdb/config/i386/nbsd.mh b/contrib/gdb/gdb/config/i386/nbsd.mh new file mode 100644 index 000000000000..5b3bd2b8c258 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nbsd.mh @@ -0,0 +1,5 @@ +# Host: Intel 386 running NetBSD +XDEPFILES= +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o i386b-nat.o +XM_FILE= xm-nbsd.h +NAT_FILE= nm-nbsd.h diff --git a/contrib/gdb/gdb/config/i386/nbsd.mt b/contrib/gdb/gdb/config/i386/nbsd.mt new file mode 100644 index 000000000000..757085074d80 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nbsd.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running NetBSD +TDEPFILES= i386-tdep.o i387-tdep.o solib.o +TM_FILE= tm-nbsd.h diff --git a/contrib/gdb/gdb/config/i386/ncr3000.mh b/contrib/gdb/gdb/config/i386/ncr3000.mh new file mode 100644 index 000000000000..1dbe1d185e54 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ncr3000.mh @@ -0,0 +1,21 @@ +# Host: NCR 3000 (Intel 386 running SVR4) + +# The NCR 3000 ships with a MetaWare compiler installed as /bin/cc. +# This compiler not only emits obnoxious copyright messages every time +# you run it, but it chokes and dies on a whole bunch of GNU source +# files. Default to using the AT&T compiler installed in /usr/ccs/ATT/cc. +# Unfortunately though, the AT&T compiler sometimes generates code that +# the assembler barfs on if -g is used, so disable it by default as well. +CC = /usr/ccs/ATT/cc +CFLAGS = + +XM_FILE= xm-i386v4.h +XDEPFILES= + +NAT_FILE= nm-i386v4.h +NATDEPFILES= corelow.o core-regset.o procfs.o fork-child.o i386v4-nat.o + +# SVR4 comes standard with terminfo, and in some implementations, the +# old termcap descriptions are incomplete. So ensure that we use the +# new terminfo interface and latest terminal descriptions. +TERMCAP=-ltermlib diff --git a/contrib/gdb/gdb/config/i386/ncr3000.mt b/contrib/gdb/gdb/config/i386/ncr3000.mt new file mode 100644 index 000000000000..0bbf9b369cbb --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ncr3000.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running SVR4 +TDEPFILES= i386-tdep.o i387-tdep.o solib.o +TM_FILE= tm-i386v4.h diff --git a/contrib/gdb/gdb/config/i386/nm-fbsd.h b/contrib/gdb/gdb/config/i386/nm-fbsd.h new file mode 100644 index 000000000000..f04f352526b4 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-fbsd.h @@ -0,0 +1,101 @@ +/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_FREEBSD_H +#define NM_FREEBSD_H + +/* Be shared lib aware */ +#include "solib.h" + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#include +#define KERNEL_U_ADDR USRSTACK + +#define FLOAT_INFO extern i386_float_info (); \ + i386_float_info () + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#define PTRACE_ARG3_TYPE char* + +/* make structure definitions match up with those expected in solib.c */ +#define link_object sod +#define lo_name sod_name +#define lo_library sod_library +#define lo_unused sod_reserved +#define lo_major sod_major +#define lo_minor sod_minor +#define lo_next sod_next + +#define link_map so_map +#define lm_addr som_addr +#define lm_name som_path +#define lm_next som_next +#define lm_lop som_sod +#define lm_lob som_sodbase +#define lm_rwt som_write +#define lm_ld som_dynamic +#define lm_lpd som_spd + +#define link_dynamic_2 section_dispatch_table +#define ld_loaded sdt_loaded +#define ld_need sdt_sods +#define ld_rules sdt_filler1 +#define ld_got sdt_got +#define ld_plt sdt_plt +#define ld_rel sdt_rel +#define ld_hash sdt_hash +#define ld_stab sdt_nzlist +#define ld_stab_hash sdt_filler2 +#define ld_buckets sdt_buckets +#define ld_symbols sdt_strings +#define ld_symb_size sdt_str_sz +#define ld_text sdt_text_sz +#define ld_plt_sz sdt_plt_sz + +#define rtc_symb rt_symbol +#define rtc_sp rt_sp +#define rtc_next rt_next + +#define ld_debug so_debug +#define ldd_version dd_version +#define ldd_in_debugger dd_in_debugger +#define ldd_sym_loaded dd_sym_loaded +#define ldd_bp_addr dd_bpt_addr +#define ldd_bp_inst dd_bpt_shadow +#define ldd_cp dd_cc + +#define link_dynamic _dynamic +#define ld_version d_version +#define ldd d_debug +#define ld_un d_un +#define ld_2 d_sdt + +/* Return sizeof user struct to callers in less machine dependent routines */ + +#define KERNEL_U_SIZE kernel_u_size() +extern int kernel_u_size PARAMS ((void)); + +#endif /* NM_FREEBSD_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-gnu.h b/contrib/gdb/gdb/config/i386/nm-gnu.h new file mode 100644 index 000000000000..95f25a52e3d5 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-gnu.h @@ -0,0 +1,22 @@ +/* Native-dependent definitions for Intel 386 running the GNU Hurd + Copyright 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include the generic hurd definitions. */ + +#include "nm-gnu.h" diff --git a/contrib/gdb/gdb/config/i386/nm-i386aix.h b/contrib/gdb/gdb/config/i386/nm-i386aix.h new file mode 100644 index 000000000000..42403939637f --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386aix.h @@ -0,0 +1,42 @@ +/* Native support for i386 aix ps/2. + Copyright 1986, 1987, 1989, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Changes for IBM AIX PS/2 by Minh Tran-Le (tranle@intellicorp.com) + * Revision: 5-May-93 00:11:35 + */ + +#ifndef NM_I386AIX_H +#define NM_I386AIX_H 1 + +/* code to execute to print interesting information about the + * floating point processor (if any) + * No need to define if there is nothing to do. + */ +#define FLOAT_INFO { i386_float_info (); } + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#undef KERNEL_U_ADDR +#define KERNEL_U_ADDR 0xf03fd000 + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +#endif /* NM_I386AIX_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-i386bsd.h b/contrib/gdb/gdb/config/i386/nm-i386bsd.h new file mode 100644 index 000000000000..7366f2d17bff --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386bsd.h @@ -0,0 +1,39 @@ +/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_I386BSD_H +#define NM_I386BSD_H + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#include +#define KERNEL_U_ADDR USRSTACK + +#undef FLOAT_INFO /* No float info yet */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#define PTRACE_ARG3_TYPE char* + +#endif /* NM_I386BSD_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-i386lynx.h b/contrib/gdb/gdb/config/i386/nm-i386lynx.h new file mode 100644 index 000000000000..e29821f29ddf --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386lynx.h @@ -0,0 +1,25 @@ +/* Native-dependent definitions for Intel 386 running LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_I386LYNX_H +#define NM_I386LYNX_H + +#include "nm-lynx.h" + +#endif /* NM_I386LYNX_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-i386mach.h b/contrib/gdb/gdb/config/i386/nm-i386mach.h new file mode 100644 index 000000000000..f01d2b142b17 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386mach.h @@ -0,0 +1,26 @@ +/* Native definitions for Mach on an Intel 386 + Copyright (C) 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Do implement the attach and detach commands. */ +/* #define ATTACH_DETACH 1 */ + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) diff --git a/contrib/gdb/gdb/config/i386/nm-i386sco.h b/contrib/gdb/gdb/config/i386/nm-i386sco.h new file mode 100644 index 000000000000..f15a8e9a3d01 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386sco.h @@ -0,0 +1,47 @@ +/* Native support for i386. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu), July 1988. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if 0 +/* code to execute to print interesting information about the + floating point processor (if any) + No need to define if there is nothing to do. + On the 386, unfortunately this code is host-dependent (and lives + in the i386-xdep.c file), so we can't + do this unless we *know* we aren't cross-debugging. FIXME. + */ +#define FLOAT_INFO { i386_float_info (); } +#endif /*0*/ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +/* + * SysV doesn't always have a or file + * (why, I don't know), and we don't need it. + */ +#define NO_PTRACE_H + +/* When calling functions on SCO, sometimes we get an error writing some + of the segment registers. This would appear to be a kernel + bug/non-feature. */ +#define CANNOT_STORE_REGISTER(regno) ((regno) == 14 || (regno) == 15) diff --git a/contrib/gdb/gdb/config/i386/nm-i386sco4.h b/contrib/gdb/gdb/config/i386/nm-i386sco4.h new file mode 100644 index 000000000000..41daef5b9268 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386sco4.h @@ -0,0 +1,32 @@ +/* Native support for SCO 3.2v4. + Copyright 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support. By Ian Lance Taylor + based on work by Martin Walker . + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* SCO 3.2v4 is actually just like SCO 3.2v2, except that it + additionally supports attaching to a process. */ + +#include "i386/nm-i386sco.h" + +#define ATTACH_DETACH + +/* SCO, in its wisdom, does not provide . infptrace.c + does not have defaults for these values. */ +#define PTRACE_ATTACH 10 +#define PTRACE_DETACH 11 diff --git a/contrib/gdb/gdb/config/i386/nm-i386sco5.h b/contrib/gdb/gdb/config/i386/nm-i386sco5.h new file mode 100644 index 000000000000..dcc14e4e2f45 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386sco5.h @@ -0,0 +1,41 @@ +/* Native support for SCO OpenServer 5 + Copyright 1996 Free Software Foundation, Inc. + By Robert Lipe . Based on + work by Ian Lance Taylor . + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* SCO OpenServer 5 is a superset of 3.2v4. It is actually quite + close to SVR4 [ elf, dynamic libes, mmap ] but misses a few things + like /proc. */ + +#include "i386/nm-i386sco.h" + +/* Since the native compilers [ and linkers ] are licensed from USL, + we'll try convincing GDB of this... */ + +#include "solib.h" /* Pick up shared library support */ +#define SVR4_SHARED_LIBS + +#define ATTACH_DETACH + +/* SCO, does not provide . infptrace.c does not + have defaults for these values. */ + +#define PTRACE_ATTACH 10 +#define PTRACE_DETACH 11 diff --git a/contrib/gdb/gdb/config/i386/nm-i386v.h b/contrib/gdb/gdb/config/i386/nm-i386v.h new file mode 100644 index 000000000000..babdd7cd12cf --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386v.h @@ -0,0 +1,38 @@ +/* Native support for i386. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu), July 1988. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if 0 +/* code to execute to print interesting information about the + floating point processor (if any) + No need to define if there is nothing to do. + On the 386, unfortunately this code is host-dependent (and lives + in the i386-xdep.c file), so we can't + do this unless we *know* we aren't cross-debugging. FIXME. + */ +#define FLOAT_INFO { i386_float_info (); } +#endif /*0*/ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#define NO_PTRACE_H diff --git a/contrib/gdb/gdb/config/i386/nm-i386v4.h b/contrib/gdb/gdb/config/i386/nm-i386v4.h new file mode 100644 index 000000000000..59d69f8ae150 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-i386v4.h @@ -0,0 +1,21 @@ +/* Native support for i386 running SVR4. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu), July 1988. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "nm-sysv4.h" diff --git a/contrib/gdb/gdb/config/i386/nm-linux.h b/contrib/gdb/gdb/config/i386/nm-linux.h new file mode 100644 index 000000000000..d6d3a5d1ac8e --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-linux.h @@ -0,0 +1,82 @@ +/* Native support for linux, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1992, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_LINUX_H +#define NM_LINUX_H + +#include "i386/nm-i386v.h" + +/* Return sizeof user struct to callers in less machine dependent routines */ + +#define KERNEL_U_SIZE kernel_u_size() +extern int kernel_u_size PARAMS ((void)); + +/* Tell gdb that we can attach and detach other processes */ +#define ATTACH_DETACH + +#define U_REGS_OFFSET 0 + +/* Linux uses the SYSV i386v-nat.c support, but doesn't have */ + +#define NO_SYS_REG_H + +/* Linux supports the 386 hardware debugging registers. */ + +#define TARGET_HAS_HARDWARE_WATCHPOINTS + +#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1 + +/* After a watchpoint trap, the PC points to the instruction after + the one that caused the trap. Therefore we don't need to step over it. + But we do need to reset the status register to avoid another trap. */ +#define HAVE_CONTINUABLE_WATCHPOINT + +#define STOPPED_BY_WATCHPOINT(W) \ + i386_stopped_by_watchpoint (inferior_pid) + +/* Use these macros for watchpoint insertion/removal. */ + +#define target_insert_watchpoint(addr, len, type) \ + i386_insert_watchpoint (inferior_pid, addr, len, 2) + +#define target_remove_watchpoint(addr, len, type) \ + i386_remove_watchpoint (inferior_pid, addr, len) + +/* We define this if link.h is available, because with ELF we use SVR4 style + shared libraries. */ + +#ifdef HAVE_LINK_H +#include "solib.h" /* Support for shared libraries. */ +#define SVR4_SHARED_LIBS +#endif + +#if 0 +/* We need prototypes for these somewhere, and this file is the logical + spot, but they can't go here because CORE_ADDR is not defined at the + time this file is included in defs.h. FIXME - fnf */ +extern CORE_ADDR +i386_stopped_by_watchpoint PARAM ((int)); +extern int +i386_insert_watchpoint PARAMS ((int pid, CORE_ADDR addr, int len, int rw)); +extern int +i386_remove_watchpoint PARAMS ((int pid, CORE_ADDR addr, int len)); +#endif + +#endif /* #ifndef NM_LINUX_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-m3.h b/contrib/gdb/gdb/config/i386/nm-m3.h new file mode 100644 index 000000000000..51270917422d --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-m3.h @@ -0,0 +1,22 @@ +/* Native-dependent definitions for Intel 386 running Mach 3. + Copyright 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include the generic Mach 3 definitions. */ + +#include "nm-m3.h" diff --git a/contrib/gdb/gdb/config/i386/nm-nbsd.h b/contrib/gdb/gdb/config/i386/nm-nbsd.h new file mode 100644 index 000000000000..b59fec682142 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-nbsd.h @@ -0,0 +1,34 @@ +/* Native-dependent definitions for Intel 386 running NetBSD, for GDB. + Copyright 1986, 1987, 1989, 1992, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_NBSD_H +#define NM_NBSD_H + +/* Get generic NetBSD native definitions. */ +#include "nm-nbsd.h" + +/* #define FLOAT_INFO { i386_float_info(); } */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +extern int +i386_register_u_addr PARAMS ((int, int)); + +#endif /* NM_NBSD_H */ diff --git a/contrib/gdb/gdb/config/i386/nm-ptx4.h b/contrib/gdb/gdb/config/i386/nm-ptx4.h new file mode 100644 index 000000000000..5e6cd569f8cf --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-ptx4.h @@ -0,0 +1,62 @@ +/* Definitions to make GDB run on a Sequent Symmetry under ptx + with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "nm-sysv4.h" + +#undef USE_PROC_FS + +#include "nm-symmetry.h" + +#define PTRACE_READ_REGS(pid,regaddr) mptrace (XPT_RREGS, (pid), (regaddr), 0) +#define PTRACE_WRITE_REGS(pid,regaddr) \ + mptrace (XPT_WREGS, (pid), (regaddr), 0) + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* We must fetch all the regs before storing, since we store all at once. */ + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +#define CHILD_WAIT +struct target_waitstatus; +extern int child_wait PARAMS ((int, struct target_waitstatus *)); + +/* + * ptx does attach as of ptx version 2.1. Prior to that, the interface + * exists but does not work. + * + * FIXME: Using attach/detach requires using the ptx MPDEBUGGER + * interface. There are still problems with that, so for now don't + * enable attach/detach. If you turn it on anyway, it will mostly + * work, but has a number of bugs. -fubar, 2/94. + */ +/*#define ATTACH_DETACH 1*/ +#undef ATTACH_DETACH +#define PTRACE_ATTACH XPT_DEBUG +#define PTRACE_DETACH XPT_UNDEBUG +/* + * The following drivel is needed because there are two ptrace-ish + * calls on ptx: ptrace() and mptrace(), each of which does about half + * of the ptrace functions. + */ +#define PTRACE_ATTACH_CALL(pid) ptx_do_attach(pid) +#define PTRACE_DETACH_CALL(pid, signo) ptx_do_detach(pid, signo) diff --git a/contrib/gdb/gdb/config/i386/nm-sun386.h b/contrib/gdb/gdb/config/i386/nm-sun386.h new file mode 100644 index 000000000000..f7a904b4f1a3 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-sun386.h @@ -0,0 +1,27 @@ +/* Native support for Sun 386i, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Do implement the attach and detach commands. */ + +#define ATTACH_DETACH + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ +#define FETCH_INFERIOR_REGISTERS + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) diff --git a/contrib/gdb/gdb/config/i386/nm-symmetry.h b/contrib/gdb/gdb/config/i386/nm-symmetry.h new file mode 100644 index 000000000000..e8fb6b9db693 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/nm-symmetry.h @@ -0,0 +1,47 @@ +/* Definitions to make GDB run on a Sequent Symmetry under dynix 3.0, + with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* We must fetch all the regs before storing, since we store all at once. */ + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +#ifdef _SEQUENT_ +#define CHILD_WAIT +extern int child_wait PARAMS ((int, struct target_waitstatus *)); +#endif + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#ifdef _SEQUENT_ +#include +#include +#include +/* VA_UAREA is defined in , and is dependant upon + sizeof(struct user) */ +#define KERNEL_U_ADDR (VA_UAREA) /* ptx */ +#else +#define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) /* dynix */ +#define NO_PTRACE_H +#endif diff --git a/contrib/gdb/gdb/config/i386/ptx.mh b/contrib/gdb/gdb/config/i386/ptx.mh new file mode 100644 index 000000000000..e623538e1561 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ptx.mh @@ -0,0 +1,7 @@ +# Host: Sequent Symmetry running ptx 1.3, with Weitek 1167 or i387 + +XM_FILE= xm-ptx.h +XDEPFILES= inftarg.o fork-child.o symm-nat.o corelow.o core-aout.o +XM_CLIBS= -lPW -lseq + +NAT_FILE= nm-symmetry.h diff --git a/contrib/gdb/gdb/config/i386/ptx.mt b/contrib/gdb/gdb/config/i386/ptx.mt new file mode 100644 index 000000000000..757df3328fc6 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ptx.mt @@ -0,0 +1,3 @@ +# Target: Sequent Symmetry running ptx 2.0, with Weitek 1167 or i387. +TDEPFILES= symm-tdep.o i387-tdep.o i386-tdep.o +TM_FILE= tm-ptx.h diff --git a/contrib/gdb/gdb/config/i386/ptx4.mh b/contrib/gdb/gdb/config/i386/ptx4.mh new file mode 100644 index 000000000000..7b9d11b0c850 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ptx4.mh @@ -0,0 +1,7 @@ +# Host: Sequent Symmetry running ptx 1.3, with Weitek 1167 or i387 + +XM_FILE= xm-ptx4.h +XDEPFILES= inftarg.o fork-child.o symm-nat.o corelow.o core-aout.o solib.o core-regset.o +XM_CLIBS= -lseq + +NAT_FILE= nm-ptx4.h diff --git a/contrib/gdb/gdb/config/i386/ptx4.mt b/contrib/gdb/gdb/config/i386/ptx4.mt new file mode 100644 index 000000000000..f34780919961 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/ptx4.mt @@ -0,0 +1,3 @@ +# Target: Sequent Symmetry running ptx 4.0, with Weitek 1167 or i387. +TDEPFILES= symm-tdep.o i387-tdep.o i386-tdep.o +TM_FILE= tm-ptx4.h diff --git a/contrib/gdb/gdb/config/i386/sun386.mh b/contrib/gdb/gdb/config/i386/sun386.mh new file mode 100644 index 000000000000..d2496610b173 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/sun386.mh @@ -0,0 +1,5 @@ +# Host: Sun 386i +XDEPFILES= +XM_FILE= xm-sun386.h +NAT_FILE= nm-sun386.h +NATDEPFILES= infptrace.o inftarg.o fork-child.o sun386-nat.o diff --git a/contrib/gdb/gdb/config/i386/sun386.mt b/contrib/gdb/gdb/config/i386/sun386.mt new file mode 100644 index 000000000000..665ca643fd55 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/sun386.mt @@ -0,0 +1,3 @@ +# Target: Sun 386i target configuration file. +TDEPFILES= i386-tdep.o solib.o +TM_FILE= tm-sun386.h diff --git a/contrib/gdb/gdb/config/i386/symmetry.mh b/contrib/gdb/gdb/config/i386/symmetry.mh new file mode 100644 index 000000000000..69c05bc1db31 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/symmetry.mh @@ -0,0 +1,5 @@ +# Host: Sequent Symmetry running Dynix 3.0, with Weitek 1167 or i387. +XDEPFILES= +XM_FILE= xm-symmetry.h +NAT_FILE= nm-symmetry.h +NATDEPFILES= inftarg.o fork-child.o corelow.o core-aout.o symm-nat.o diff --git a/contrib/gdb/gdb/config/i386/symmetry.mt b/contrib/gdb/gdb/config/i386/symmetry.mt new file mode 100644 index 000000000000..a3dba70bd824 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/symmetry.mt @@ -0,0 +1,3 @@ +# Target: Sequent Symmetry running Dynix 3.0, with Weitek 1167 or i387. +TDEPFILES= i386-tdep.o symm-tdep.o i387-tdep.o +TM_FILE= tm-symmetry.h diff --git a/contrib/gdb/gdb/config/i386/tm-cygwin32.h b/contrib/gdb/gdb/config/i386/tm-cygwin32.h new file mode 100644 index 000000000000..f7464ba66cba --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-cygwin32.h @@ -0,0 +1,125 @@ +/* Macro definitions for i386 running under the win32 API Unix. + Copyright 1995, 1996 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "i386/tm-i386v.h" + +#undef MAX_REGISTER_RAW_SIZE +#undef MAX_REGISTER_VIRTUAL_SIZE +#undef NUM_REGS +#undef REGISTER_BYTE +#undef REGISTER_BYTES +#undef REGISTER_CONVERTIBLE +#undef REGISTER_CONVERT_TO_RAW +#undef REGISTER_CONVERT_TO_VIRTUAL +#undef REGISTER_NAMES +#undef REGISTER_RAW_SIZE +#undef REGISTER_VIRTUAL_SIZE +#undef REGISTER_VIRTUAL_TYPE + +/* Number of machine registers */ + +#define NUM_REGS 24 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ + +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + "st", "st(1)","st(2)","st(3)",\ + "st(4)","st(5)","st(6)","st(7)",} + +#define FP0_REGNUM 16 + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + +#define REGISTER_BYTES (16 * 4 + 8 * 10) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) (((N) < 16) ? (N) * 4 : (((N) - 16) * 10) + (16 * 4)) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (((N) < 16) ? 4 : 10) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((N) < 16) ? 4 : 10) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 10 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 10 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) \ + ((N < FP0_REGNUM) ? 0 : 1) + +/* Convert data from raw format for register REGNUM in buffer FROM + to virtual format with type TYPE in buffer TO. */ +extern void +i387_to_double PARAMS ((char *, char *)); + + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + double val; \ + i387_to_double ((FROM), (char *)&val); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ +} + +extern void +double_to_i387 PARAMS ((char *, char *)); + +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + double_to_i387((char *)&val, (TO)); \ +} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N < FP0_REGNUM) ? builtin_type_int : \ + builtin_type_double) + +#define NAMES_HAVE_UNDERSCORE + + +#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) skip_trampoline_code (pc, name) +#define SKIP_TRAMPOLINE_CODE(pc) skip_trampoline_code (pc, 0) +extern CORE_ADDR skip_trampoline_code PARAMS ((CORE_ADDR pc, char *name)); diff --git a/contrib/gdb/gdb/config/i386/tm-i386.h b/contrib/gdb/gdb/config/i386/tm-i386.h new file mode 100644 index 000000000000..8f8090b96f20 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386.h @@ -0,0 +1,309 @@ +/* Macro definitions for GDB on an Intel i[345]86. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef TM_I386_H +#define TM_I386_H 1 + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct frame_info; +struct frame_saved_regs; +struct type; +#endif + +#define TARGET_BYTE_ORDER LITTLE_ENDIAN + +/* Used for example in valprint.c:print_floating() to enable checking + for NaN's */ + +#define IEEE_FLOAT + +/* Number of traps that happen between exec'ing the shell to run an + inferior, and when we finally get to the inferior code. This is 2 + on most implementations. */ + +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions to reach some + "real" code. */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +extern int i386_skip_prologue PARAMS ((int)); + +/* Immediately after a function call, return the saved pc. Can't always go + through the frames for this because on some machines the new frame is not + set up until the new function executes some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. This is often the + number of bytes in BREAKPOINT but not always. */ + +#define DECR_PC_AFTER_BREAK 1 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer ((pc), 1) == 0xc3) + +/* Say how long (ordinary) registers are. This is a piece of bogosity + used in push_word and a few other places; REGISTER_RAW_SIZE is the + real way to know how big a register is. */ + +#define REGISTER_SIZE 4 + +/* Number of machine registers */ + +#define NUM_FREGS 0 /*8*/ /* Number of FP regs */ +#define NUM_REGS (16 + NUM_FREGS) /* Basic i*86 regs + FP regs */ + +/* Initializer for an array of names of registers. There should be at least + NUM_REGS strings in this initializer. Any excess ones are simply ignored. + The order of the first 8 registers must match the compiler's numbering + scheme (which is the same as the 386 scheme) and also regmap in the various + *-nat.c files. */ + +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "eflags", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + "st0", "st1", "st2", "st3", \ + "st4", "st5", "st6", "st7", \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define FP_REGNUM 5 /* (ebp) Contains address of executing stack frame */ +#define SP_REGNUM 4 /* (usp) Contains address of top of stack */ +#define PC_REGNUM 8 /* (eip) Contains program counter */ +#define PS_REGNUM 9 /* (ps) Contains processor status */ + +#define FP0_REGNUM 16 /* (st0) 387 register */ +#define FPC_REGNUM 25 /* 80387 control register */ + +/* Total amount of space needed to store our copies of the machine's register + state, the array `registers'. */ + +#define REGISTER_BYTES ((NUM_REGS - NUM_FREGS)*4 + NUM_FREGS*10) + +/* Index within `registers' of the first byte of the space for register N. */ + +#define REGISTER_BYTE(N) \ + (((N) < FP0_REGNUM) ? ((N) * 4) : ((((N) - FP0_REGNUM) * 10) + 64)) + +/* Number of bytes of storage in the actual machine representation for + register N. All registers are 4 bytes, except 387 st(0) - st(7), + which are 80 bits each. */ + +#define REGISTER_RAW_SIZE(N) (((N) < FP0_REGNUM) ? 4 : 10) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 10 + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((N) < FP0_REGNUM) ? 4 : 8) + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Return the GDB type object for the "standard" data type of data in + register N. Perhaps si and di should go here, but potentially they + could be used for things other than address. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM) \ + ? lookup_pointer_type (builtin_type_void) \ + : (((N) < FP0_REGNUM) \ + ? builtin_type_int \ + : builtin_type_double)) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), (char *) &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + i386_extract_return_value ((TYPE),(REGBUF),(VALBUF)) + +extern void i386_extract_return_value PARAMS ((struct type *, char [], char *)); + +/* Write into appropriate registers a function return value of type TYPE, given + in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + { \ + if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \ + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), (VALBUF), \ + TYPE_LENGTH (TYPE)); \ + else \ + write_register_bytes (0, (VALBUF), TYPE_LENGTH (TYPE)); \ + } + +/* Extract from an array REGBUF containing the (raw) register state the address + in which a function should return its structure value, as a CORE_ADDR (or an + expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + +/* The following redefines make backtracing through sigtramp work. + They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp + from the sigcontext structure which is pushed by the kernel on the + user stack, along with a pointer to it. */ + +/* FRAME_CHAIN takes a frame's nominal address and produces the frame's + chain-pointer. + In the case of the i386, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) \ + ((thisframe)->signal_handler_caller \ + ? (thisframe)->frame \ + : (!inside_entry_file ((thisframe)->pc) \ + ? read_memory_integer ((thisframe)->frame, 4) \ + : 0)) + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + do { \ + if ((FI)->signal_handler_caller) \ + (FRAMELESS) = 0; \ + else \ + (FRAMELESS) = frameless_look_for_prologue(FI); \ + } while (0) + +/* Saved Pc. Get it from sigcontext if within sigtramp. */ + +#define FRAME_SAVED_PC(FRAME) \ + (((FRAME)->signal_handler_caller \ + ? sigtramp_saved_pc (FRAME) \ + : read_memory_integer ((FRAME)->frame + 4, 4)) \ + ) + +extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *)); + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. Can return -1, meaning no way + to tell, which is typical now that the C compiler delays popping them. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = i386_frame_num_args(fi) + +extern int i386_frame_num_args PARAMS ((struct frame_info *)); + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + +extern void i386_frame_find_saved_regs PARAMS ((struct frame_info *, + struct frame_saved_regs *)); + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); } + +extern void i386_push_dummy_frame PARAMS ((void)); + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +extern void i386_pop_frame PARAMS ((void)); + + +/* this is + * call 11223344 (32 bit relative) + * int3 + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +#define CALL_DUMMY_BREAKPOINT_OFFSET 5 + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + int from, to, delta, loc; \ + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \ + from = loc + 5; \ + to = (int)(fun); \ + delta = to - from; \ + *((char *)(dummyname) + 1) = (delta & 0xff); \ + *((char *)(dummyname) + 2) = ((delta >> 8) & 0xff); \ + *((char *)(dummyname) + 3) = ((delta >> 16) & 0xff); \ + *((char *)(dummyname) + 4) = ((delta >> 24) & 0xff); \ +} + +extern void print_387_control_word PARAMS ((unsigned int)); +extern void print_387_status_word PARAMS ((unsigned int)); + +/* Offset from SP to first arg on stack at first instruction of a function */ + +#define SP_ARG0 (1 * 4) + +#endif /* ifndef TM_I386_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386aix.h b/contrib/gdb/gdb/config/i386/tm-i386aix.h new file mode 100644 index 000000000000..b0121fa92df3 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386aix.h @@ -0,0 +1,67 @@ +/* Macro defintions for IBM AIX PS/2 (i386). + Copyright 1986, 1987, 1989, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Changes for IBM AIX PS/2 by Minh Tran-Le (tranle@intellicorp.com). */ + +#ifndef TM_I386AIX_H +#define TM_I386AIX_H 1 + +#include "i386/tm-i386.h" +#include + +#ifndef I386 +# define I386 1 +#endif +#ifndef I386_AIX_TARGET +# define I386_AIX_TARGET 1 +#endif + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#undef REGISTER_CONVERTIBLE +#define REGISTER_CONVERTIBLE(N) \ + ((N < FP0_REGNUM) ? 0 : 1) + +/* Convert data from raw format for register REGNUM in buffer FROM + to virtual format with type TYPE in buffer TO. */ + +#undef REGISTER_CONVERT_TO_VIRTUAL +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + double val; \ + i387_to_double ((FROM), (char *)&val); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ +} +extern void +i387_to_double PARAMS ((char *, char *)); + +/* Convert data from virtual format with type TYPE in buffer FROM + to raw format for register REGNUM in buffer TO. */ + +#undef REGISTER_CONVERT_TO_RAW +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + double_to_i387((char *)&val, (TO)); \ +} +extern void +double_to_i387 PARAMS ((char *, char *)); + +#endif /* TM_I386AIX_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386bsd.h b/contrib/gdb/gdb/config/i386/tm-i386bsd.h new file mode 100644 index 000000000000..0b0e3d939173 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386bsd.h @@ -0,0 +1,43 @@ +/* Macro definitions for i386 running under BSD Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386BSD_H +#define TM_I386BSD_H 1 + +#include "i386/tm-i386.h" + +/* 386BSD cannot handle the segment registers. */ +/* BSDI can't handle them either. */ + +#undef NUM_REGS +#define NUM_REGS 10 + +/* On 386 bsd, sigtramp is above the user stack and immediately below + the user area. Using constants here allows for cross debugging. + These are tested for BSDI but should work on 386BSD. */ + +#define SIGTRAMP_START 0xfdbfdfc0 +#define SIGTRAMP_END 0xfdbfe000 + +/* Saved Pc. Get it from sigcontext if within sigtramp. */ + +/* Offset to saved PC in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET 20 + +#endif /* ifndef TM_I386BSD_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386gnu.h b/contrib/gdb/gdb/config/i386/tm-i386gnu.h new file mode 100644 index 000000000000..a6e3c087d4d6 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386gnu.h @@ -0,0 +1,48 @@ +/* Macro definitions for i386, GNU Hurd + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include common definitions for gnu systems */ +#include "nm-gnu.h" + +/* Thread flavors used in re-setting the T bit. + * @@ this is also bad for cross debugging. + */ +#define THREAD_STATE_FLAVOR i386_THREAD_STATE +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT +#define THREAD_STATE_SET_TRACED(state) \ + ((struct i386_thread_state *)state)->efl |= 0x100 +#define THREAD_STATE_CLEAR_TRACED(state) \ + ((((struct i386_thread_state *)state)->efl &= ~0x100), 1) + +/* we can do it */ +#define ATTACH_DETACH 1 + +/* Sigh. There should be a file for i386 but no sysv stuff in it */ +#include "i386/tm-i386v.h" + +/* I want to test this float info code. See comment in tm-i386v.h */ +#undef FLOAT_INFO +#define FLOAT_INFO { i386_mach3_float_info (); } + +/* Address of end of stack space. + * for MACH, see + * @@@ I don't know what is in the 5 ints... + */ +#undef STACK_END_ADDR +#define STACK_END_ADDR (0xc0000000-sizeof(int [5])) diff --git a/contrib/gdb/gdb/config/i386/tm-i386lynx.h b/contrib/gdb/gdb/config/i386/tm-i386lynx.h new file mode 100644 index 000000000000..9e732b32e6b7 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386lynx.h @@ -0,0 +1,33 @@ +/* Macro definitions for Intel 386 running under LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386LYNX_H +#define TM_I386LYNX_H + +#include "tm-lynx.h" + +/* Most definitions from sysv could be used. */ +#include "i386/tm-i386.h" + +#undef SAVED_PC_AFTER_CALL + +#define SAVED_PC_AFTER_CALL i386lynx_saved_pc_after_call +CORE_ADDR i386lynx_saved_pc_after_call (); + +#endif /* TM_I386LYNX_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386m3.h b/contrib/gdb/gdb/config/i386/tm-i386m3.h new file mode 100644 index 000000000000..2f97505a19a5 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386m3.h @@ -0,0 +1,60 @@ +/* Macro definitions for i386, Mach 3.0 + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include common definitions for Mach3 systems */ +#include "nm-m3.h" + +/* Define offsets to access CPROC stack when it does not have + * a kernel thread. + */ +#define MACHINE_CPROC_SP_OFFSET 20 +#define MACHINE_CPROC_PC_OFFSET 16 +#define MACHINE_CPROC_FP_OFFSET 12 + +/* Thread flavors used in re-setting the T bit. + * @@ this is also bad for cross debugging. + */ +#define TRACE_FLAVOR i386_THREAD_STATE +#define TRACE_FLAVOR_SIZE i386_THREAD_STATE_COUNT +#define TRACE_SET(x,state) \ + ((struct i386_thread_state *)state)->efl |= 0x100 +#define TRACE_CLEAR(x,state) \ + ((((struct i386_thread_state *)state)->efl &= ~0x100), 1) + +/* we can do it */ +#define ATTACH_DETACH 1 + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Sigh. There should be a file for i386 but no sysv stuff in it */ +#include "i386/tm-i386.h" + +/* I want to test this float info code. See comment in tm-i386v.h */ +#undef FLOAT_INFO +#define FLOAT_INFO { i386_mach3_float_info (); } + +/* Address of end of stack space. + * for MACH, see + * @@@ I don't know what is in the 5 ints... + */ +#undef STACK_END_ADDR +#define STACK_END_ADDR (0xc0000000-sizeof(int [5])) diff --git a/contrib/gdb/gdb/config/i386/tm-i386mk.h b/contrib/gdb/gdb/config/i386/tm-i386mk.h new file mode 100644 index 000000000000..3625efbf6df6 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386mk.h @@ -0,0 +1,25 @@ +/* Macro definitions for i386, Mach 3.0, OSF 1/MK + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Until OSF switches to a newer Mach kernel that has + * a different get_emul_vector() interface. + */ +#define MK67 1 + +#include "i386/tm-i386m3.h" diff --git a/contrib/gdb/gdb/config/i386/tm-i386nw.h b/contrib/gdb/gdb/config/i386/tm-i386nw.h new file mode 100644 index 000000000000..43a1e1a1496c --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386nw.h @@ -0,0 +1,49 @@ +/* Macro definitions for i386 running NetWare. + Copyright 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386NW_H +#define TM_I386NW_H 1 + +#include "i386/tm-i386.h" + +/* Stop backtracing when we wander into main. */ + +#define FRAME_CHAIN_VALID_ALTERNATE + + +/* Offsets (in target ints) into jmp_buf. Not defined in any system header + file, so we have to step through setjmp/longjmp with a debugger and figure + them out. */ + +#define JB_ELEMENT_SIZE 4 /* jmp_buf[] is array of ints */ + +#define JB_PC 6 /* Setjmp()'s return PC saved here */ + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +extern int +get_longjmp_target PARAMS ((CORE_ADDR *)); + +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) + +#endif /* ifndef TM_I386NW_H */ + diff --git a/contrib/gdb/gdb/config/i386/tm-i386os9k.h b/contrib/gdb/gdb/config/i386/tm-i386os9k.h new file mode 100644 index 000000000000..75de74e0b34f --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386os9k.h @@ -0,0 +1,63 @@ +/* Macro definitions for i386 running under BSD Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386OS9K_H +#define TM_I386OS9K_H 1 + +#include "i386/tm-i386.h" + +/* Number of machine registers */ + +#undef NUM_REGS +#define NUM_REGS (16) /* Basic i*86 regs */ + +/* Initializer for an array of names of registers. There should be at least + NUM_REGS strings in this initializer. Any excess ones are simply ignored. + The order of the first 8 registers must match the compiler's numbering + scheme (which is the same as the 386 scheme) and also regmap in the various + *-nat.c files. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "eflags", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +#define DATABASE_REG 3 /* ebx */ + +/* Amount PC must be decremented by after a breakpoint. This is often the + number of bytes in BREAKPOINT but not always (such as now). */ + +#undef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 0 + +/* On 386 bsd, sigtramp is above the user stack and immediately below + the user area. Using constants here allows for cross debugging. + These are tested for BSDI but should work on 386BSD. */ +#define SIGTRAMP_START 0xfdbfdfc0 +#define SIGTRAMP_END 0xfdbfe000 + +/* Saved Pc. Get it from sigcontext if within sigtramp. */ + +/* Offset to saved PC in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET 20 + +#define BELIEVE_PCC_PROMOTION 1 + +#endif /* #ifndef TM_I386OS9K_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386v.h b/contrib/gdb/gdb/config/i386/tm-i386v.h new file mode 100644 index 000000000000..235558b78cc1 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386v.h @@ -0,0 +1,161 @@ +/* Macro definitions for i386, Unix System V. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386V_H +#define TM_I386V_H 1 + +/* First pick up the generic *86 target file. */ + +#include "i386/tm-i386.h" + +/* Number of traps that happen between exec'ing the shell to run an + inferior, and when we finally get to the inferior code. This is + 2 on most implementations. Override here to 4. */ + +#undef START_INFERIOR_TRAPS_EXPECTED +#define START_INFERIOR_TRAPS_EXPECTED 4 + +/* Number of machine registers */ + +#undef NUM_REGS +#define NUM_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + +#undef REGISTER_BYTES +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#undef REGISTER_BYTE +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#undef REGISTER_RAW_SIZE +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#undef REGISTER_VIRTUAL_SIZE +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#undef MAX_REGISTER_RAW_SIZE +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#undef MAX_REGISTER_VIRTUAL_SIZE +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +/* Perhaps si and di should go here, but potentially they could be + used for things other than address. */ + +#undef REGISTER_VIRTUAL_TYPE +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) == PC_REGNUM || (N) == FP_REGNUM || (N) == SP_REGNUM ? \ + lookup_pointer_type (builtin_type_void) : builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#undef STORE_STRUCT_RETURN +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), (char *) &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#undef EXTRACT_RETURN_VALUE +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + memcpy ((VALBUF), (REGBUF), TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#undef STORE_RETURN_VALUE +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. */ + +#undef FRAME_CHAIN +#define FRAME_CHAIN(thisframe) \ + (!inside_entry_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + +#undef FRAMELESS_FUNCTION_INVOCATION +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#undef FRAME_SAVED_PC +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#undef FRAME_NUM_ARGS +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = -1 + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct frame_info; +struct frame_saved_regs; +#endif + +extern int +i386_frame_num_args PARAMS ((struct frame_info *)); + +#endif /* ifndef TM_I386V_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-i386v4.h b/contrib/gdb/gdb/config/i386/tm-i386v4.h new file mode 100644 index 000000000000..0a1e56df6f25 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-i386v4.h @@ -0,0 +1,78 @@ +/* Macro definitions for GDB on an Intel i386 running SVR4. + Copyright (C) 1991, 1994 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com) + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_I386V4_H +#define TM_I386V4_H 1 + +/* Pick up most of what we need from the generic i386 target include file. */ + +#include "i386/tm-i386.h" + +/* Pick up more stuff from the generic SVR4 host include file. */ + +#include "tm-sysv4.h" + +/* Use the alternate method of determining valid frame chains. */ + +#define FRAME_CHAIN_VALID_ALTERNATE + +/* Offsets (in target ints) into jmp_buf. Not defined in any system header + file, so we have to step through setjmp/longjmp with a debugger and figure + them out. Note that defines _JBLEN as 10, which is the default + if no specific machine is selected, even though we only use 6 slots. */ + +#define JB_ELEMENT_SIZE sizeof(int) /* jmp_buf[_JBLEN] is array of ints */ + +#define JB_EBX 0 +#define JB_ESI 1 +#define JB_EDI 2 +#define JB_EBP 3 +#define JB_ESP 4 +#define JB_EDX 5 + +#define JB_PC JB_EDX /* Setjmp()'s return PC saved in EDX */ + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +extern int +get_longjmp_target PARAMS ((CORE_ADDR *)); + +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) + +/* The following redefines make backtracing through sigtramp work. + They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp + from the ucontext structure which is pushed by the kernel on the + user stack. Unfortunately there are three variants of sigtramp handlers. */ + +#define I386V4_SIGTRAMP_SAVED_PC +#define IN_SIGTRAMP(pc, name) ((name) \ + && (STREQ ("_sigreturn", name) \ + || STREQ ("_sigacthandler", name) \ + || STREQ ("sigvechandler", name))) + +/* Saved Pc. Get it from ucontext if within sigtramp. */ + +#define sigtramp_saved_pc i386v4_sigtramp_saved_pc +extern CORE_ADDR i386v4_sigtramp_saved_pc PARAMS ((struct frame_info *)); + +#endif /* ifndef TM_I386V4_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-linux.h b/contrib/gdb/gdb/config/i386/tm-linux.h new file mode 100644 index 000000000000..d8cbf26785c9 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-linux.h @@ -0,0 +1,35 @@ +/* Definitions to target GDB to Linux on 386. + Copyright 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_LINUX_H +#define TM_LINUX_H + +/* FIXME: If nothing else gets added to this file, it could be removed + and configure could just use tm-i386.h instead. -fnf */ + +#include "i386/tm-i386.h" + +/* Offset to saved PC in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET 38 + +/* We need this file for the SOLIB_TRAMPOLINE stuff. */ + +#include "tm-sysv4.h" + +#endif /* #ifndef TM_LINUX_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-nbsd.h b/contrib/gdb/gdb/config/i386/tm-nbsd.h new file mode 100644 index 000000000000..cf5159f2655e --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-nbsd.h @@ -0,0 +1,42 @@ +/* Macro definitions for i386 running under NetBSD. + Copyright 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_NBSD_H +#define TM_NBSD_H + +#include "i386/tm-i386bsd.h" +#include "tm-nbsd.h" + +#undef NUM_REGS +#define NUM_REGS 16 + +#define JB_ELEMENT_SIZE sizeof(int) /* jmp_buf[_JBLEN] is array of ints */ +#define JB_PC 0 /* Setjmp()'s return PC saved here */ + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +extern int +get_longjmp_target PARAMS ((CORE_ADDR *)); + +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) + +#endif /* TM_NBSD_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-ptx.h b/contrib/gdb/gdb/config/i386/tm-ptx.h new file mode 100644 index 000000000000..c9f67d7f6d8d --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-ptx.h @@ -0,0 +1,232 @@ +/* Target machine definitions for GDB on a Sequent Symmetry under ptx + with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + Symmetry version by Jay Vosburgh (fubar@sequent.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_PTX_H +#define TM_PTX_H 1 + +/* I don't know if this will work for cross-debugging, even if you do get + a copy of the right include file. */ + +#include + +#ifdef SEQUENT_PTX4 +#include "i386/tm-i386v4.h" +#else /* !SEQUENT_PTX4 */ +#include "i386/tm-i386v.h" +#endif + +/* Number of traps that happen between exec'ing the shell to run an + inferior, and when we finally get to the inferior code. This is 2 + on most implementations. Here we have to undo what tm-i386v.h gave + us and restore the default. */ + +#undef START_INFERIOR_TRAPS_EXPECTED +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Amount PC must be decremented by after a breakpoint. This is often the + number of bytes in BREAKPOINT but not always (such as now). */ + +#undef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 0 + +#if 0 + --- this code can't be used unless we know we are running native, + since it uses host specific ptrace calls. +/* code for 80387 fpu. Functions are from i386-dep.c, copied into + * symm-dep.c. + */ +#define FLOAT_INFO { i386_float_info(); } +#endif + +/* Number of machine registers */ + +#undef NUM_REGS +#define NUM_REGS 49 + +/* Initializer for an array of names of registers. There should be at least + NUM_REGS strings in this initializer. Any excess ones are simply ignored. + The order of the first 8 registers must match the compiler's numbering + scheme (which is the same as the 386 scheme) and also regmap in the various + *-nat.c files. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "eflags", "st0", "st1", \ + "st2", "st3", "st4", "st5", \ + "st6", "st7", "fp1", "fp2", \ + "fp3", "fp4", "fp5", "fp6", \ + "fp7", "fp8", "fp9", "fp10", \ + "fp11", "fp12", "fp13", "fp14", \ + "fp15", "fp16", "fp17", "fp18", \ + "fp19", "fp20", "fp21", "fp22", \ + "fp23", "fp24", "fp25", "fp26", \ + "fp27", "fp28", "fp29", "fp30", \ + "fp31" } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define EAX_REGNUM 0 +#define ECX_REGNUM 1 +#define EDX_REGNUM 2 +#define EBX_REGNUM 3 + +#define ESP_REGNUM 4 +#define EBP_REGNUM 5 + +#define ESI_REGNUM 6 +#define EDI_REGNUM 7 + +#define EIP_REGNUM 8 +#define EFLAGS_REGNUM 9 + +#define ST0_REGNUM 10 +#define ST1_REGNUM 11 +#define ST2_REGNUM 12 +#define ST3_REGNUM 13 + +#define ST4_REGNUM 14 +#define ST5_REGNUM 15 +#define ST6_REGNUM 16 +#define ST7_REGNUM 17 + +#define FP1_REGNUM 18 /* first 1167 register */ +/* Get %fp2 - %fp31 by addition, since they are contiguous */ + +#undef SP_REGNUM +#define SP_REGNUM ESP_REGNUM /* Contains address of top of stack */ +#undef FP_REGNUM +#define FP_REGNUM EBP_REGNUM /* Contains address of executing stack frame */ +#undef PC_REGNUM +#define PC_REGNUM EIP_REGNUM /* Contains program counter */ +#undef PS_REGNUM +#define PS_REGNUM EFLAGS_REGNUM /* Contains processor status */ + +/* + * For ptx, this is a little bit bizarre, since the register block + * is below the u area in memory. This means that blockend here ends + * up being negative (for the call from coredep.c) since the value in + * u.u_ar0 will be less than KERNEL_U_ADDR (and coredep.c passes us + * u.u_ar0 - KERNEL_U_ADDR in blockend). Since we also define + * FETCH_INFERIOR_REGISTERS (and supply our own functions for that), + * the core file case will be the only use of this function. + */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ (addr) = ptx_register_u_addr((blockend), (regno)); } + +extern int +ptx_register_u_addr PARAMS ((int, int)); + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. 10 i*86 registers, 8 i387 + registers, and 31 Weitek 1167 registers */ + +#undef REGISTER_BYTES +#define REGISTER_BYTES ((10 * 4) + (8 * 10) + (31 * 4)) + +/* Index within `registers' of the first byte of the space for register N. */ + +#undef REGISTER_BYTE +#define REGISTER_BYTE(N) \ +(((N) < ST0_REGNUM) ? ((N) * 4) : \ + ((N) < FP1_REGNUM) ? (40 + (((N) - ST0_REGNUM) * 10)) : \ + (40 + 80 + (((N) - FP1_REGNUM) * 4))) + +/* Number of bytes of storage in the actual machine representation for + register N. All registers are 4 bytes, except 387 st(0) - st(7), + which are 80 bits each. */ + +#undef REGISTER_RAW_SIZE +#define REGISTER_RAW_SIZE(N) \ +(((N) < ST0_REGNUM) ? 4 : \ + ((N) < FP1_REGNUM) ? 10 : \ + 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#undef MAX_REGISTER_RAW_SIZE +#define MAX_REGISTER_RAW_SIZE 10 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#undef REGISTER_CONVERTIBLE +#define REGISTER_CONVERTIBLE(N) \ +((N < ST0_REGNUM) ? 0 : \ + (N < FP1_REGNUM) ? 1 : \ + 0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ +extern const struct floatformat floatformat_i387_ext; /* from floatformat.h */ + +#undef REGISTER_CONVERT_TO_VIRTUAL +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +((REGNUM < ST0_REGNUM) ? (void)memcpy ((TO), (FROM), 4) : \ + (REGNUM < FP1_REGNUM) ? (void)floatformat_to_double(&floatformat_i387_ext, \ + (FROM),(TO)) : \ + (void)memcpy ((TO), (FROM), 4)) + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#undef REGISTER_CONVERT_TO_RAW +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +((REGNUM < ST0_REGNUM) ? (void)memcpy ((TO), (FROM), 4) : \ + (REGNUM < FP1_REGNUM) ? (void)floatformat_from_double(&floatformat_i387_ext, \ + (FROM),(TO)) : \ + (void)memcpy ((TO), (FROM), 4)) + +/* Return the GDB type object for the "standard" data type + of data in register N. */ +/* + * Note: the 1167 registers (the last line, builtin_type_float) are + * generally used in pairs, with each pair being treated as a double. + * It it also possible to use them singly as floats. I'm not sure how + * in gdb to treat the register pair pseudo-doubles. -fubar + */ +#undef REGISTER_VIRTUAL_TYPE +#define REGISTER_VIRTUAL_TYPE(N) \ +((N < ST0_REGNUM) ? builtin_type_int : \ + (N < FP1_REGNUM) ? builtin_type_double : \ + builtin_type_float) + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#undef EXTRACT_RETURN_VALUE +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + symmetry_extract_return_value(TYPE, REGBUF, VALBUF) + +/* +#undef FRAME_FIND_SAVED_REGS +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ ptx_frame_find_saved_regs((frame_info), &(frame_saved_regs)); } +*/ + +#endif /* ifndef TM_PTX_H */ diff --git a/contrib/gdb/gdb/config/i386/tm-ptx4.h b/contrib/gdb/gdb/config/i386/tm-ptx4.h new file mode 100644 index 000000000000..a576accb46bb --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-ptx4.h @@ -0,0 +1,24 @@ +/* Target machine definitions for GDB on a Sequent Symmetry under ptx + with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + Symmetry version by Jay Vosburgh (fubar@sequent.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define SEQUENT_PTX4 + +#include "tm-ptx.h" diff --git a/contrib/gdb/gdb/config/i386/tm-sun386.h b/contrib/gdb/gdb/config/i386/tm-sun386.h new file mode 100644 index 000000000000..259fd5182387 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-sun386.h @@ -0,0 +1,205 @@ +/* Parameters for a Sun 386i target machine, for GDB, the GNU debugger. + Copyright 1986, 1987, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (TM_SUN386_H) +#define TM_SUN386_H 1 + +#include "i386/tm-i386.h" + +#ifndef sun386 +#define sun386 +#endif +#define GDB_TARGET_IS_SUN386 1 +#define SUNOS4 +#define USE_MACHINE_REG_H + +/* Perhaps some day this will work even without the following #define */ +#define COFF_ENCAPSULATE + +#ifdef COFF_ENCAPSULATE +/* Avoid conflicts between our include files and + (maybe not needed anymore). */ +#define _EXEC_ +#endif + +/* sun386 ptrace seems unable to change the frame pointer */ +#define PTRACE_FP_BUG + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xfc000000 + +/* Number of machine registers */ + +#undef NUM_REGS +#define NUM_REGS 35 + +/* Initializer for an array of names of registers. There should be NUM_REGS + strings in this initializer. The order of the first 8 registers must match + the compiler's numbering scheme (which is the same as the 386 scheme) also, + this table must match regmap in i386-pinsn.c. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "gs", "fs", "es", "ds", \ + "edi", "esi", "ebp", "esp", \ + "ebx", "edx", "ecx", "eax", \ + "retaddr", "trapnum", "errcode", "ip", \ + "cs", "ps", "sp", "ss", \ + "fst0", "fst1", "fst2", "fst3", \ + "fst4", "fst5", "fst6", "fst7", \ + "fctrl", "fstat", "ftag", "fip", \ + "fcs", "fopoff", "fopsel" \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#undef FP_REGNUM +#define FP_REGNUM 6 /* (ebp) Contains address of executing stack frame */ +#undef SP_REGNUM +#define SP_REGNUM 18 /* (usp) Contains address of top of stack */ +#undef PS_REGNUM +#define PS_REGNUM 17 /* (ps) Contains processor status */ +#undef PC_REGNUM +#define PC_REGNUM 15 /* (eip) Contains program counter */ +#undef FP0_REGNUM +#define FP0_REGNUM 20 /* Floating point register 0 */ +#undef FPC_REGNUM +#define FPC_REGNUM 28 /* 80387 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + +#undef REGISTER_BYTES +#define REGISTER_BYTES (20*4+8*10+7*4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#undef REGISTER_BYTE +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 160 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 10) + 80 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#undef REGISTER_RAW_SIZE +#define REGISTER_RAW_SIZE(N) (((unsigned)((N) - FP0_REGNUM)) < 8 ? 10 : 4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#undef REGISTER_VIRTUAL_SIZE +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)((N) - FP0_REGNUM)) < 8 ? 8 : 4) + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#undef REGISTER_CONVERTIBLE +#define REGISTER_CONVERTIBLE(N) (((unsigned)((N) - FP0_REGNUM)) < 8) + +/* Convert data from raw format for register REGNUM in buffer FROM + to virtual format with type TYPE in buffer TO. */ + +#undef REGISTER_CONVERT_TO_VIRTUAL +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + double val; \ + i387_to_double ((FROM), (char *)&val); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ +} +extern void +i387_to_double PARAMS ((char *, char *)); + +/* Convert data from virtual format with type TYPE in buffer FROM + to raw format for register REGNUM in buffer TO. */ + +#undef REGISTER_CONVERT_TO_RAW +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + double_to_i387((char *)&val, (TO)); \ +} +extern void +double_to_i387 PARAMS ((char *, char *)); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#undef REGISTER_VIRTUAL_TYPE +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)((N) - FP0_REGNUM)) < 8 ? builtin_type_double : builtin_type_int) + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#undef EXTRACT_RETURN_VALUE +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + memcpy (VALBUF, REGBUF + REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 11), TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#undef STORE_RETURN_VALUE +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 11), VALBUF, TYPE_LENGTH (TYPE)) + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. */ + +#undef FRAME_CHAIN +#define FRAME_CHAIN(thisframe) \ + (!inside_entry_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + +#undef FRAMELESS_FUNCTION_INVOCATION +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ +{ (FRAMELESS) = frameless_look_for_prologue (FI); } + +#undef FRAME_SAVED_PC +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#undef FIX_CALL_DUMMY +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ \ + *(int *)((char *)(dummyname) + 1) = (int)(fun) - (pc) - 5; \ +} + +#endif /* !defined (TM_SUN386_H) */ + diff --git a/contrib/gdb/gdb/config/i386/tm-symmetry.h b/contrib/gdb/gdb/config/i386/tm-symmetry.h new file mode 100644 index 000000000000..11931d41724f --- /dev/null +++ b/contrib/gdb/gdb/config/i386/tm-symmetry.h @@ -0,0 +1,321 @@ +/* Target machine definitions for GDB on a Sequent Symmetry under dynix 3.0, + with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + Symmetry version by Jay Vosburgh (fubar@sequent.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_SYMMETRY_H +#define TM_SYMMETRY_H 1 + +/* I don't know if this will work for cross-debugging, even if you do get + a copy of the right include file. */ +#include + +#include "i386/tm-i386v.h" + +#undef START_INFERIOR_TRAPS_EXPECTED +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Amount PC must be decremented by after a breakpoint. This is often the + number of bytes in BREAKPOINT but not always (such as now). */ + +#undef DECR_PC_AFTER_BREAK +#define DECR_PC_AFTER_BREAK 0 + +#if 0 +/* --- this code can't be used unless we know we are running native, + since it uses host specific ptrace calls. */ +/* code for 80387 fpu. Functions are from i386-dep.c, copied into + * symm-dep.c. + */ +#define FLOAT_INFO { i386_float_info(); } +#endif + +/* Number of machine registers */ + +#undef NUM_REGS +#define NUM_REGS 49 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* Initializer for an array of names of registers. There should be at least + NUM_REGS strings in this initializer. Any excess ones are simply ignored. + Symmetry registers are in this weird order to match the register numbers + in the symbol table entries. If you change the order, things will probably + break mysteriously for no apparent reason. Also note that the st(0)... + st(7) 387 registers are represented as st0...st7. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "eax", "edx", "ecx", "st0", "st1", \ + "ebx", "esi", "edi", "st2", "st3", \ + "st4", "st5", "st6", "st7", "esp", \ + "ebp", "eip", "eflags","fp1", "fp2", \ + "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fp8", "fp9", "fp10", "fp11", "fp12", \ + "fp13", "fp14", "fp15", "fp16", "fp17", \ + "fp18", "fp19", "fp20", "fp21", "fp22", \ + "fp23", "fp24", "fp25", "fp26", "fp27", \ + "fp28", "fp29", "fp30", "fp31" } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define EAX_REGNUM 0 +#define EDX_REGNUM 1 +#define ECX_REGNUM 2 +#define ST0_REGNUM 3 +#define ST1_REGNUM 4 +#define EBX_REGNUM 5 +#define ESI_REGNUM 6 +#define EDI_REGNUM 7 +#define ST2_REGNUM 8 +#define ST3_REGNUM 9 + +#define ST4_REGNUM 10 +#define ST5_REGNUM 11 +#define ST6_REGNUM 12 +#define ST7_REGNUM 13 + +#define FP1_REGNUM 18 /* first 1167 register */ +/* Get %fp2 - %fp31 by addition, since they are contiguous */ + +#undef SP_REGNUM +#define SP_REGNUM 14 /* (usp) Contains address of top of stack */ +#define ESP_REGNUM 14 +#undef FP_REGNUM +#define FP_REGNUM 15 /* (ebp) Contains address of executing stack frame */ +#define EBP_REGNUM 15 +#undef PC_REGNUM +#define PC_REGNUM 16 /* (eip) Contains program counter */ +#define EIP_REGNUM 16 +#undef PS_REGNUM +#define PS_REGNUM 17 /* (ps) Contains processor status */ +#define EFLAGS_REGNUM 17 + +/* + * Following macro translates i386 opcode register numbers to Symmetry + * register numbers. This is used by i386_frame_find_saved_regs. + * + * %eax %ecx %edx %ebx %esp %ebp %esi %edi + * i386 0 1 2 3 4 5 6 7 + * Symmetry 0 2 1 5 14 15 6 7 + * + */ +#define I386_REGNO_TO_SYMMETRY(n) \ +((n)==0?0 :(n)==1?2 :(n)==2?1 :(n)==3?5 :(n)==4?14 :(n)==5?15 :(n)) + +/* The magic numbers below are offsets into u_ar0 in the user struct. + * They live in . Gdb calls this macro with blockend + * holding u.u_ar0 - KERNEL_U_ADDR. Only the registers listed are + * saved in the u area (along with a few others that aren't useful + * here. See ). + */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ struct user foo; /* needed for finding fpu regs */ \ +switch (regno) { \ + case 0: \ + addr = blockend + EAX * sizeof(int); break; \ + case 1: \ + addr = blockend + EDX * sizeof(int); break; \ + case 2: \ + addr = blockend + ECX * sizeof(int); break; \ + case 3: /* st(0) */ \ + addr = ((int)&foo.u_fpusave.fpu_stack[0][0] - (int)&foo); \ + break; \ + case 4: /* st(1) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[1][0] - (int)&foo); \ + break; \ + case 5: \ + addr = blockend + EBX * sizeof(int); break; \ + case 6: \ + addr = blockend + ESI * sizeof(int); break; \ + case 7: \ + addr = blockend + EDI * sizeof(int); break; \ + case 8: /* st(2) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[2][0] - (int)&foo); \ + break; \ + case 9: /* st(3) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[3][0] - (int)&foo); \ + break; \ + case 10: /* st(4) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[4][0] - (int)&foo); \ + break; \ + case 11: /* st(5) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[5][0] - (int)&foo); \ + break; \ + case 12: /* st(6) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[6][0] - (int)&foo); \ + break; \ + case 13: /* st(7) */ \ + addr = ((int) &foo.u_fpusave.fpu_stack[7][0] - (int)&foo); \ + break; \ + case 14: \ + addr = blockend + ESP * sizeof(int); break; \ + case 15: \ + addr = blockend + EBP * sizeof(int); break; \ + case 16: \ + addr = blockend + EIP * sizeof(int); break; \ + case 17: \ + addr = blockend + FLAGS * sizeof(int); break; \ + case 18: /* fp1 */ \ + case 19: /* fp2 */ \ + case 20: /* fp3 */ \ + case 21: /* fp4 */ \ + case 22: /* fp5 */ \ + case 23: /* fp6 */ \ + case 24: /* fp7 */ \ + case 25: /* fp8 */ \ + case 26: /* fp9 */ \ + case 27: /* fp10 */ \ + case 28: /* fp11 */ \ + case 29: /* fp12 */ \ + case 30: /* fp13 */ \ + case 31: /* fp14 */ \ + case 32: /* fp15 */ \ + case 33: /* fp16 */ \ + case 34: /* fp17 */ \ + case 35: /* fp18 */ \ + case 36: /* fp19 */ \ + case 37: /* fp20 */ \ + case 38: /* fp21 */ \ + case 39: /* fp22 */ \ + case 40: /* fp23 */ \ + case 41: /* fp24 */ \ + case 42: /* fp25 */ \ + case 43: /* fp26 */ \ + case 44: /* fp27 */ \ + case 45: /* fp28 */ \ + case 46: /* fp29 */ \ + case 47: /* fp30 */ \ + case 48: /* fp31 */ \ + addr = ((int) &foo.u_fpasave.fpa_regs[(regno)-18] - (int)&foo); \ + } \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. 10 i*86 registers, 8 i387 + registers, and 31 Weitek 1167 registers */ + +#undef REGISTER_BYTES +#define REGISTER_BYTES ((10 * 4) + (8 * 10) + (31 * 4)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#undef REGISTER_BYTE +#define REGISTER_BYTE(N) \ +(((N) < 3) ? ((N) * 4) : \ +((N) < 5) ? ((((N) - 2) * 10) + 2) : \ +((N) < 8) ? ((((N) - 5) * 4) + 32) : \ +((N) < 14) ? ((((N) - 8) * 10) + 44) : \ + ((((N) - 14) * 4) + 104)) + +/* Number of bytes of storage in the actual machine representation + * for register N. All registers are 4 bytes, except 387 st(0) - st(7), + * which are 80 bits each. + */ + +#undef REGISTER_RAW_SIZE +#define REGISTER_RAW_SIZE(N) \ +(((N) < 3) ? 4 : \ +((N) < 5) ? 10 : \ +((N) < 8) ? 4 : \ +((N) < 14) ? 10 : \ + 4) + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#undef REGISTER_CONVERTIBLE +#define REGISTER_CONVERTIBLE(N) \ +(((N) < 3) ? 0 : \ +((N) < 5) ? 1 : \ +((N) < 8) ? 0 : \ +((N) < 14) ? 1 : \ + 0) + +#include "floatformat.h" + +/* Convert data from raw format for register REGNUM in buffer FROM + to virtual format with type TYPE in buffer TO. */ + +#undef REGISTER_CONVERT_TO_VIRTUAL +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + double val; \ + floatformat_to_double (&floatformat_i387_ext, (FROM), &val); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ +} + +/* Convert data from virtual format with type TYPE in buffer FROM + to raw format for register REGNUM in buffer TO. */ + +#undef REGISTER_CONVERT_TO_RAW +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + floatformat_from_double (&floatformat_i387_ext, &val, (TO)); \ +} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#undef REGISTER_VIRTUAL_TYPE +#define REGISTER_VIRTUAL_TYPE(N) \ +((N < 3) ? builtin_type_int : \ +(N < 5) ? builtin_type_double : \ +(N < 8) ? builtin_type_int : \ +(N < 14) ? builtin_type_double : \ + builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. + Native cc passes the address in eax, gcc (up to version 2.5.8) + passes it on the stack. gcc should be fixed in future versions to + adopt native cc conventions. */ + +#undef STORE_STRUCT_RETURN +#define STORE_STRUCT_RETURN(ADDR, SP) write_register(0, (ADDR)) + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#undef EXTRACT_RETURN_VALUE +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + symmetry_extract_return_value(TYPE, REGBUF, VALBUF) + +/* The following redefines make backtracing through sigtramp work. + They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp + from the sigcontext structure which is pushed by the kernel on the + user stack, along with a pointer to it. */ + +#define IN_SIGTRAMP(pc, name) ((name) && STREQ ("_sigcode", name)) + +/* Offset to saved PC in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET 16 + +#endif /* ifndef TM_SYMMETRY_H */ + diff --git a/contrib/gdb/gdb/config/i386/xm-cygwin32.h b/contrib/gdb/gdb/config/i386/xm-cygwin32.h new file mode 100644 index 000000000000..becbebe08ba3 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-cygwin32.h @@ -0,0 +1,41 @@ +/* Definitions for hosting on WIN32, for GDB. + Copyright 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#include "fopen-bin.h" + +#define GDBINIT_FILENAME "gdb.ini" + + +#define SLASH_P(X) ((X)=='\\' || (X) == '/') +#define ROOTED_P(X) ((SLASH_P((X)[0]))|| ((X)[1] ==':')) +#define SLASH_CHAR '/' +#define SLASH_STRING "/" + + +/* If we longjmp out of the signal handler we never get another one. + So disable immediate_quit inside request_quit */ +#define REQUEST_QUIT + + + + + + diff --git a/contrib/gdb/gdb/config/i386/xm-go32.h b/contrib/gdb/gdb/config/i386/xm-go32.h new file mode 100644 index 000000000000..079783322077 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-go32.h @@ -0,0 +1,31 @@ +/* Definitions for hosting on GO32, for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN +#include "fopen-bin.h" + +/* Define this lseek(n) != nth byte of file */ +#define LSEEK_NOT_LINEAR + +#define CANT_FORK + +#undef QUIT +#define QUIT { pollquit(); } + +#define GDBINIT_FILENAME "gdb.ini" diff --git a/contrib/gdb/gdb/config/i386/xm-i386aix.h b/contrib/gdb/gdb/config/i386/xm-i386aix.h new file mode 100644 index 000000000000..652a149d6cbe --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386aix.h @@ -0,0 +1,33 @@ +/* Macro defintions for AIX PS/2 (i386) + Copyright 1986, 1987, 1989, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Changed for IBM AIX ps/2 by Minh Tran Le (tranle@intellicorp.com) + * Revision: 23-Oct-92 17:42:49 + */ + +#include "i386/xm-i386v.h" + +#undef HAVE_TERMIO +#define HAVE_SGTTY + +#include + +/* Use setpgid instead of setpgrp on AIX */ +#define NEED_POSIX_SETPGID diff --git a/contrib/gdb/gdb/config/i386/xm-i386bsd.h b/contrib/gdb/gdb/config/i386/xm-i386bsd.h new file mode 100644 index 000000000000..8a852a29787c --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386bsd.h @@ -0,0 +1,23 @@ +/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#include /* for INT_MIN, to avoid "INT_MIN + redefined" warnings from defs.h */ diff --git a/contrib/gdb/gdb/config/i386/xm-i386gnu.h b/contrib/gdb/gdb/config/i386/xm-i386gnu.h new file mode 100644 index 000000000000..60307b21183e --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386gnu.h @@ -0,0 +1,23 @@ +/* Definitions to make GDB run on the GNU Hurd on an Intel 386 + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Do implement the attach and detach commands. */ +#define ATTACH_DETACH 1 diff --git a/contrib/gdb/gdb/config/i386/xm-i386lynx.h b/contrib/gdb/gdb/config/i386/xm-i386lynx.h new file mode 100644 index 000000000000..6078cb6f2cba --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386lynx.h @@ -0,0 +1,24 @@ +/* Host-dependent definitions for Intel 386 running LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Get generic LynxOS host definitions. */ + +#include "xm-lynx.h" diff --git a/contrib/gdb/gdb/config/i386/xm-i386m3.h b/contrib/gdb/gdb/config/i386/xm-i386m3.h new file mode 100644 index 000000000000..615c80b1405a --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386m3.h @@ -0,0 +1,38 @@ +/* Definitions to make GDB run on Mach 3 on an Intel 386 + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Avoid "INT_MIN redefined" warnings -- by defining it here, exactly + the same as in the system file. */ +#undef INT_MIN +#define INT_MIN 0x80000000 + +/* Do implement the attach and detach commands. */ +#define ATTACH_DETACH 1 + +/* Not needeed */ +#define KERNEL_U_ADDR 0 + +#ifndef EMULATOR_BASE +/* For EMULATOR_BASE and EMULATOR_END. + * OSF 1/MK has different values in some other place. + */ +#include +#endif /* EMULATOR_BASE */ diff --git a/contrib/gdb/gdb/config/i386/xm-i386mach.h b/contrib/gdb/gdb/config/i386/xm-i386mach.h new file mode 100644 index 000000000000..c50da67b3a3d --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386mach.h @@ -0,0 +1,35 @@ +/* Definitions to make GDB run on Mach on an Intel 386 + Copyright (C) 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* Avoid "INT_MIN redefined" warnings -- by defining it here, exactly + the same as in the system file. */ +#undef INT_MIN +#define INT_MIN 0x80000000 + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) + +/* only defines this if __STDC__!!! */ +extern int errno; + +extern char *strdup(); diff --git a/contrib/gdb/gdb/config/i386/xm-i386mk.h b/contrib/gdb/gdb/config/i386/xm-i386mk.h new file mode 100644 index 000000000000..7bbe02f8da70 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386mk.h @@ -0,0 +1,25 @@ +/* Definitions to make GDB run on Mach 3 OSF 1/MK on an Intel 386 + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HAVE_TERMIO 1 + +#define EMULATOR_BASE 0xa0000000 +#define EMULATOR_END 0xa0040000 + +#include "xm-i386mach3.h" diff --git a/contrib/gdb/gdb/config/i386/xm-i386sco.h b/contrib/gdb/gdb/config/i386/xm-i386sco.h new file mode 100644 index 000000000000..31fa7e6b9807 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386sco.h @@ -0,0 +1,42 @@ +/* Macro defintions for i386, running SCO Unix System V/386 3.2. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* In 3.2v4 requires on . */ +#include +#include + +#include "i386/xm-i386v.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate + +/* SCO 3.2v2 and later have job control. */ +/* SCO 3.2v4 I know has termios; I'm not sure about earlier versions. + GDB does not currently support the termio/job control combination. */ +#undef HAVE_TERMIO +#define HAVE_TERMIOS + +/* SCO's assembler doesn't grok dollar signs in identifiers. + So we use dots instead. This item must be coordinated with G++. */ +#undef CPLUS_MARKER +#define CPLUS_MARKER '.' + +/* Use setpgid instead of setpgrp on SCO */ +#define NEED_POSIX_SETPGID diff --git a/contrib/gdb/gdb/config/i386/xm-i386v.h b/contrib/gdb/gdb/config/i386/xm-i386v.h new file mode 100644 index 000000000000..480dfd671a04 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386v.h @@ -0,0 +1,45 @@ +/* Host support for i386. + Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu), July 1988. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +/* I'm running gdb 3.4 under 386/ix 2.0.2, which is a derivative of AT&T's +Sys V/386 3.2. + +On some machines, gdb crashes when it's starting up while calling the +vendor's termio tgetent() routine. It always works when run under +itself (actually, under 3.2, it's not an infinitely recursive bug.) +After some poking around, it appears that depending on the environment +size, or whether you're running YP, or the phase of the moon or something, +the stack is not always long-aligned when main() is called, and tgetent() +takes strong offense at that. On some machines this bug never appears, but +on those where it does, it occurs quite reliably. */ +#define ALIGN_STACK_ON_STARTUP + +/* define USG if you are using sys5 /usr/include's */ +#define USG + +#define HAVE_TERMIO + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0xe0000000 + diff --git a/contrib/gdb/gdb/config/i386/xm-i386v32.h b/contrib/gdb/gdb/config/i386/xm-i386v32.h new file mode 100644 index 000000000000..daaac8047c56 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386v32.h @@ -0,0 +1,24 @@ +/* Macro defintions for i386, running System V 3.2. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "i386/xm-i386v.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate diff --git a/contrib/gdb/gdb/config/i386/xm-i386v4.h b/contrib/gdb/gdb/config/i386/xm-i386v4.h new file mode 100644 index 000000000000..7d5aff04ecdc --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-i386v4.h @@ -0,0 +1,37 @@ +/* Macro definitions for GDB on an Intel i386 running SVR4. + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Pick up most of what we need from the generic i386 host include file. */ + +#include "i386/xm-i386v.h" + +/* Pick up more stuff from the generic SVR4 host include file. */ + +#include "xm-sysv4.h" + +/* If you expect to use the mmalloc package to obtain mapped symbol files, + for now you have to specify some parameters that determine how gdb places + the mappings in it's address space. See the comments in map_to_address() + for details. This is expected to only be a short term solution. Yes it + is a kludge. + FIXME: Make this more automatic. */ + +#define MMAP_BASE_ADDRESS 0x81000000 /* First mapping here */ +#define MMAP_INCREMENT 0x01000000 /* Increment to next mapping */ diff --git a/contrib/gdb/gdb/config/i386/xm-linux.h b/contrib/gdb/gdb/config/i386/xm-linux.h new file mode 100644 index 000000000000..50049260d208 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-linux.h @@ -0,0 +1,46 @@ +/* Native support for linux, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef XM_LINUX_H +#define XM_LINUX_H + +#define HOST_BYTE_ORDER LITTLE_ENDIAN + +#define HAVE_TERMIOS + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#define KERNEL_U_ADDR 0x0 + +#define NEED_POSIX_SETPGID + +/* Need R_OK etc, but USG isn't defined. */ +#include + +/* If you expect to use the mmalloc package to obtain mapped symbol files, + for now you have to specify some parameters that determine how gdb places + the mappings in it's address space. See the comments in map_to_address() + for details. This is expected to only be a short term solution. Yes it + is a kludge. + FIXME: Make this more automatic. */ + +#define MMAP_BASE_ADDRESS 0x20000000 /* First mapping here */ +#define MMAP_INCREMENT 0x01000000 /* Increment to next mapping */ + +#endif /* #ifndef XM_LINUX_H */ diff --git a/contrib/gdb/gdb/config/i386/xm-nbsd.h b/contrib/gdb/gdb/config/i386/xm-nbsd.h new file mode 100644 index 000000000000..b5624acc60f5 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-nbsd.h @@ -0,0 +1,21 @@ +/* Parameters for execution on a i386 running NetBSD, for GDB. + Copyright 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Get generic NetBSD host definitions. */ +#include "xm-nbsd.h" diff --git a/contrib/gdb/gdb/config/i386/xm-ptx.h b/contrib/gdb/gdb/config/i386/xm-ptx.h new file mode 100644 index 000000000000..99b46ccd149c --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-ptx.h @@ -0,0 +1,41 @@ +/* Definitions to make GDB run on a Sequent Symmetry under ptx, with + Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1992, 1993, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Symmetry version by Jay Vosburgh (fubar@sequent.com) */ + +#ifdef _SEQUENT_PTX4_ +#include "xm-sysv4.h" +#endif /* _SEQUENT_PTX4_ */ + +/* This machine doesn't have the siginterrupt call. */ +#define NO_SIGINTERRUPT + +#define HAVE_WAIT_STRUCT + +#undef HAVE_TERMIO +#define HAVE_TERMIOS +#define USG + +#define NEED_POSIX_SETPGID + +#define USE_O_NOCTTY + +#define HOST_BYTE_ORDER LITTLE_ENDIAN diff --git a/contrib/gdb/gdb/config/i386/xm-ptx4.h b/contrib/gdb/gdb/config/i386/xm-ptx4.h new file mode 100644 index 000000000000..bdbdefd6ec81 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-ptx4.h @@ -0,0 +1,25 @@ +/* Definitions to make GDB run on a Sequent Symmetry under ptx, with + Weitek 1167 and i387 support. Copyright 1986, 1987, 1989, 1992, + 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Symmetry version by Jay Vosburgh (fubar@sequent.com) */ + +#include "xm-sysv4.h" + +#include "xm-ptx.h" diff --git a/contrib/gdb/gdb/config/i386/xm-sun386.h b/contrib/gdb/gdb/config/i386/xm-sun386.h new file mode 100644 index 000000000000..51c3b58c11b6 --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-sun386.h @@ -0,0 +1,20 @@ +/* Host support for Sun 386i, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define HOST_BYTE_ORDER LITTLE_ENDIAN diff --git a/contrib/gdb/gdb/config/i386/xm-symmetry.h b/contrib/gdb/gdb/config/i386/xm-symmetry.h new file mode 100644 index 000000000000..52e9a9a2341e --- /dev/null +++ b/contrib/gdb/gdb/config/i386/xm-symmetry.h @@ -0,0 +1,28 @@ +/* Definitions to make GDB run on a Sequent Symmetry under + dynix 3.1, with Weitek 1167 and i387 support. + Copyright 1986, 1987, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Symmetry version by Jay Vosburgh (fubar@sequent.com) */ + +/* This machine doesn't have the siginterrupt call. */ +#define NO_SIGINTERRUPT + +#define HAVE_WAIT_STRUCT + +#define HOST_BYTE_ORDER LITTLE_ENDIAN diff --git a/contrib/gdb/gdb/config/nm-empty.h b/contrib/gdb/gdb/config/nm-empty.h new file mode 100644 index 000000000000..7069d8c8a4e8 --- /dev/null +++ b/contrib/gdb/gdb/config/nm-empty.h @@ -0,0 +1,2 @@ +/* This is just a dummy file to symlink to when GDB is configured as a + cross-only debugger. */ diff --git a/contrib/gdb/gdb/config/nm-gnu.h b/contrib/gdb/gdb/config/nm-gnu.h new file mode 100644 index 000000000000..f59a2dcdfe0c --- /dev/null +++ b/contrib/gdb/gdb/config/nm-gnu.h @@ -0,0 +1,46 @@ +/* Common declarations for the GNU Hurd + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __NM_GNU_H__ +#define __NM_GNU_H__ + +#include +#include +#include + +#include "solib.h" /* Support for shared libraries. */ + +#undef target_pid_to_str +#define target_pid_to_str(pid) gnu_target_pid_to_str(pid) +extern char *gnu_target_pid_to_str (int pid); + +/* Before storing, we need to read all the registers. */ +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +/* Don't do wait_for_inferior on attach. */ +#define ATTACH_NO_WAIT + +/* Use SVR4 style shared library support */ +#define SVR4_SHARED_LIBS +#define NO_CORE_OPS + +#define MAINTENANCE_CMDS 1 + +#endif /* __NM_GNU_H__ */ diff --git a/contrib/gdb/gdb/config/nm-lynx.h b/contrib/gdb/gdb/config/nm-lynx.h new file mode 100644 index 000000000000..8781a9a48bac --- /dev/null +++ b/contrib/gdb/gdb/config/nm-lynx.h @@ -0,0 +1,83 @@ +/* Native-dependent definitions for LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_LYNX_H +#define NM_LYNX_H + +#include +#include +/* sys/kernel.h should define this, but doesn't always, sigh. */ +#ifndef __LYNXOS +#define __LYNXOS +#endif +#include +#include +#include +#include +#include +#include +#include +#include "thread.h" + +/* This is the amount to subtract from u.u_ar0 to get the offset in + the core file of the register values. */ + +#define KERNEL_U_ADDR USRSTACK + +#undef FLOAT_INFO /* No float info yet */ + +/* As of LynxOS 2.2.2 (beta 8/15/94), this is int. Previous versions seem to + have had no prototype, so I'm not sure why GDB used to define this to + char *. */ +#define PTRACE_ARG3_TYPE int + +/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */ + +#define FETCH_INFERIOR_REGISTERS + +/* Thread ID of stopped thread. */ + +#define WIFTID(x) (((union wait *)&x)->w_tid) + +/* Override child_wait in inftarg.c */ + +#define CHILD_WAIT + +/* Override child_resume in infptrace.c */ + +#define CHILD_RESUME + +/* Override child_thread_alive in intarg.c */ + +#define CHILD_THREAD_ALIVE + +#include "target.h" + +extern int child_wait PARAMS ((int pid, struct target_waitstatus *status)); + +/* Lynx needs a special definition of this so that we can + print out the pid and thread number seperatly. */ + +#undef target_pid_to_str + +#define target_pid_to_str(PID) lynx_pid_to_str (PID) + +extern char *lynx_pid_to_str PARAMS ((int pid)); + +#endif /* NM_LYNX_H */ diff --git a/contrib/gdb/gdb/config/nm-m3.h b/contrib/gdb/gdb/config/nm-m3.h new file mode 100644 index 000000000000..6ea52565b947 --- /dev/null +++ b/contrib/gdb/gdb/config/nm-m3.h @@ -0,0 +1,123 @@ +/* Mach 3.0 common definitions and global vars. + + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_M3_H +#define NM_M3_H + +#include + +/* Mach3 doesn't declare errno in . */ +extern int errno; + +/* Task port of our debugged inferior. */ + +extern task_t inferior_task; + +/* Thread port of the current thread in the inferior. */ + +extern thread_t current_thread; + +/* If nonzero, we must suspend/abort && resume threads + * when setting or getting the state. + */ +extern int must_suspend_thread; + +#define PREPARE_TO_PROCEED(select_it) mach3_prepare_to_proceed(select_it) + +/* Try to get the privileged host port for authentication to machid + * + * If you can get this, you may debug anything on this host. + * + * If you can't, gdb gives it's own task port as the + * authentication port + */ +#define mach_privileged_host_port() task_by_pid(-1) + +/* + * This is the MIG ID number of the emulator/server bsd_execve() RPC call. + * + * It SHOULD never change, but if it does, gdb `run' + * command won't work until you fix this define. + * + */ +#define MIG_EXEC_SYSCALL_ID 101000 + +/* If our_message_port gets a msg with this ID, + * GDB suspends it's inferior and enters command level. + * (Useful at least if ^C does not work) + */ +#define GDB_MESSAGE_ID_STOP 0x41151 + +/* wait3 WNOHANG is defined in but + * for some reason gdb does not want to include + * that file. + * + * If your system defines WNOHANG differently, this has to be changed. + */ +#define WNOHANG 1 + +/* Before storing, we need to read all the registers. */ + +#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES) + +/* Check if the inferior exists */ +#define MACH_ERROR_NO_INFERIOR \ + do if (!MACH_PORT_VALID (inferior_task)) \ + error ("Inferior task does not exist."); while(0) + +/* Error handler for mach calls */ +#define CHK(str,ret) \ + do if (ret != KERN_SUCCESS) \ + error ("Gdb %s [%d] %s : %s\n",__FILE__,__LINE__,str, \ + mach_error_string(ret)); while(0) + +/* This is from POE9 emulator/emul_stack.h + */ +/* + * Top of emulator stack holds link and reply port. + */ +struct emul_stack_top { + struct emul_stack_top *link; + mach_port_t reply_port; +}; + +#define EMULATOR_STACK_SIZE (4096*4) + +#define THREAD_ALLOWED_TO_BREAK(mid) mach_thread_for_breakpoint (mid) + +#define THREAD_PARSE_ID(arg) mach_thread_parse_id (arg) + +#define THREAD_OUTPUT_ID(mid) mach_thread_output_id (mid) + +#define ATTACH_TO_THREAD attach_to_thread + +/* Don't do wait_for_inferior on attach. */ +#define ATTACH_NO_WAIT + +/* Do Mach 3 dependent operations when ^C or a STOP is requested */ +#define DO_QUIT() mach3_quit () + +#if 0 +/* This is bogus. It is NOT OK to quit out of target_wait. */ +/* If in mach_msg() and ^C is typed set immediate_quit */ +#define REQUEST_QUIT() mach3_request_quit () +#endif + +#endif /* NM_M3_H */ diff --git a/contrib/gdb/gdb/config/nm-nbsd.h b/contrib/gdb/gdb/config/nm-nbsd.h new file mode 100644 index 000000000000..bc1d6a621ac7 --- /dev/null +++ b/contrib/gdb/gdb/config/nm-nbsd.h @@ -0,0 +1,86 @@ +/* Native-dependent definitions for NetBSD. + Copyright 1994, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#include + +#define KERNEL_U_ADDR USRSTACK + +#define PTRACE_ARG3_TYPE char* + +#define FETCH_INFERIOR_REGISTERS + +#define ATTACH_DETACH + +#include "solib.h" /* Support for shared libraries. */ + +/* make structure definitions match up with those expected in solib.c */ +#define link_object sod +#define lo_name sod_name +#define lo_library sod_library +#define lo_unused sod_reserved +#define lo_major sod_major +#define lo_minor sod_minor +#define lo_next sod_next + +#define link_map so_map +#define lm_addr som_addr +#define lm_name som_path +#define lm_next som_next +#define lm_lop som_sod +#define lm_lob som_sodbase +#define lm_rwt som_write +#define lm_ld som_dynamic +#define lm_lpd som_spd + +#define link_dynamic_2 section_dispatch_table +#define ld_loaded sdt_loaded +#define ld_need sdt_sods +#define ld_rules sdt_filler1 +#define ld_got sdt_got +#define ld_plt sdt_plt +#define ld_rel sdt_rel +#define ld_hash sdt_hash +#define ld_stab sdt_nzlist +#define ld_stab_hash sdt_filler2 +#define ld_buckets sdt_buckets +#define ld_symbols sdt_strings +#define ld_symb_size sdt_str_sz +#define ld_text sdt_text_sz +#define ld_plt_sz sdt_plt_sz + +#define rtc_symb rt_symbol +#define rtc_sp rt_sp +#define rtc_next rt_next + +#define ld_debug so_debug +#define ldd_version dd_version +#define ldd_in_debugger dd_in_debugger +#define ldd_sym_loaded dd_sym_loaded +#define ldd_bp_addr dd_bpt_addr +#define ldd_bp_inst dd_bpt_shadow +#define ldd_cp dd_cc + +#define link_dynamic _dynamic +#define ld_version d_version +#define ldd d_debug +#define ld_un d_un +#define ld_2 d_sdt diff --git a/contrib/gdb/gdb/config/nm-sysv4.h b/contrib/gdb/gdb/config/nm-sysv4.h new file mode 100644 index 000000000000..e4978d0bcc62 --- /dev/null +++ b/contrib/gdb/gdb/config/nm-sysv4.h @@ -0,0 +1,34 @@ +/* Definitions for running gdb on a host machine running any flavor of SVR4. + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "solib.h" /* Support for shared libraries. */ + +/* Use SVR4 style shared library support */ + +#define SVR4_SHARED_LIBS + +/* SVR4 has /proc support, so use it instead of ptrace. */ + +#define USE_PROC_FS + +/* SVR4 machines can easily do attach and detach via /proc (procfs.c) + support */ + +#define ATTACH_DETACH diff --git a/contrib/gdb/gdb/config/tm-lynx.h b/contrib/gdb/gdb/config/tm-lynx.h new file mode 100644 index 000000000000..7107241420c9 --- /dev/null +++ b/contrib/gdb/gdb/config/tm-lynx.h @@ -0,0 +1,34 @@ +/* Macro definitions for LynxOS targets. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_LYNX_H +#define TM_LYNX_H + +/* Override number of expected traps from sysv. */ +#define START_INFERIOR_TRAPS_EXPECTED 2 + +#include "coff-solib.h" /* COFF shared library support */ + +/* Lynx's signal.h doesn't seem to have any macros for what signal numbers + the real-time events are. */ +#define REALTIME_LO 33 +/* One more than the last one. */ +#define REALTIME_HI 64 + +#endif /* TM_LYNX_H */ diff --git a/contrib/gdb/gdb/config/tm-nbsd.h b/contrib/gdb/gdb/config/tm-nbsd.h new file mode 100644 index 000000000000..e295d85ea2d9 --- /dev/null +++ b/contrib/gdb/gdb/config/tm-nbsd.h @@ -0,0 +1,19 @@ +/* Target machine sub-description for NetBSD. + This is included by other tm-*.h files to specify NetBSD-specific stuff. + Copyright 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/contrib/gdb/gdb/config/tm-sunos.h b/contrib/gdb/gdb/config/tm-sunos.h new file mode 100644 index 000000000000..26ec3cff866e --- /dev/null +++ b/contrib/gdb/gdb/config/tm-sunos.h @@ -0,0 +1,31 @@ +/* Target machine sub-description for SunOS version 4. + This is included by other tm-*.h files to specify SunOS-specific stuff. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "solib.h" /* Support for shared libraries. */ + +/* Return non-zero if we are in a shared library trampoline code stub. */ + +#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \ + lookup_solib_trampoline_symbol_by_pc (pc) + +/* If PC is in a shared library trampoline code, return the PC + where the function itself actually starts. If not, return 0. */ + +#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc) diff --git a/contrib/gdb/gdb/config/tm-sysv4.h b/contrib/gdb/gdb/config/tm-sysv4.h new file mode 100644 index 000000000000..2c085410c092 --- /dev/null +++ b/contrib/gdb/gdb/config/tm-sysv4.h @@ -0,0 +1,45 @@ +/* Macro definitions for GDB on all SVR4 target systems. + Copyright 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* For SVR4 shared libraries, each call to a library routine goes through + a small piece of trampoline code in the ".plt" section. + The horribly ugly wait_for_inferior() routine uses this macro to detect + when we have stepped into one of these fragments. + We do not use lookup_solib_trampoline_symbol_by_pc, because + we cannot always find the shared library trampoline symbols + (e.g. on Irix5). */ + +#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) in_plt_section((pc), (name)) +extern int in_plt_section PARAMS ((CORE_ADDR, char *)); + +/* If PC is in a shared library trampoline code, return the PC + where the function itself actually starts. If not, return 0. */ + +#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc) + +/* It is unknown which, if any, SVR4 assemblers do not accept dollar signs + in identifiers. The default in G++ is to use dots instead, for all SVR4 + systems, so we make that our default also. FIXME: There should be some + way to get G++ to tell us what CPLUS_MARKER it is using, perhaps by + stashing it in the debugging information as part of the name of an + invented symbol ("gcc_cplus_marker$" for example). */ + +#undef CPLUS_MARKER +#define CPLUS_MARKER '.' diff --git a/contrib/gdb/gdb/config/xm-aix4.h b/contrib/gdb/gdb/config/xm-aix4.h new file mode 100644 index 000000000000..31bb6da9fc49 --- /dev/null +++ b/contrib/gdb/gdb/config/xm-aix4.h @@ -0,0 +1,96 @@ +/* Parameters for hosting on an PowerPC, for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + Contributed by Cygnus 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The following text is taken from config/rs6000.mh: + * # The IBM version of /usr/include/rpc/rpc.h has a bug -- it says + * # `extern fd_set svc_fdset;' without ever defining the type fd_set. + * # Unfortunately this occurs in the vx-share code, which is not configured + * # like the rest of GDB (e.g. it doesn't include "defs.h"). + * # We circumvent this bug by #define-ing fd_set here, but undefining it in + * # the xm-rs6000.h file before ordinary modules try to use it. FIXME, IBM! + * MH_CFLAGS='-Dfd_set=int' + * So, here we do the undefine...which has to occur before we include + * below. + */ +#undef fd_set + +#include + +/* Big end is at the low address */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* At least as of AIX 3.2, we have termios. */ +#define HAVE_TERMIOS 1 +/* #define HAVE_TERMIO 1 */ + +#define USG 1 +#define HAVE_SIGSETMASK 1 + +#define FIVE_ARG_PTRACE + +/* AIX declares the mem functions differently than defs.h does. AIX is + right, but defs.h works on more old systems. For now, override it. */ + +#define MEM_FNS_DECLARED 1 + +/* This system requires that we open a terminal with O_NOCTTY for it to + not become our controlling terminal. */ + +#define USE_O_NOCTTY + +/* Brain death inherited from PC's pervades. */ +#undef NULL +#define NULL 0 + +/* The IBM compiler requires this in order to properly compile alloca(). */ +#pragma alloca + +/* There is no vfork. */ + +#define vfork fork + +/* Signal handler for SIGWINCH `window size changed'. */ + +#define SIGWINCH_HANDLER aix_resizewindow +extern void aix_resizewindow (); + +/* `lines_per_page' and `chars_per_line' are local to utils.c. Rectify this. */ + +#define SIGWINCH_HANDLER_BODY \ + \ +/* Respond to SIGWINCH `window size changed' signal, and reset GDB's \ + window settings approproatelt. */ \ + \ +void \ +aix_resizewindow () \ +{ \ + int fd = fileno (stdout); \ + if (isatty (fd)) { \ + int val; \ + \ + val = atoi (termdef (fd, 'l')); \ + if (val > 0) \ + lines_per_page = val; \ + val = atoi (termdef (fd, 'c')); \ + if (val > 0) \ + chars_per_line = val; \ + } \ +} diff --git a/contrib/gdb/gdb/config/xm-lynx.h b/contrib/gdb/gdb/config/xm-lynx.h new file mode 100644 index 000000000000..6f19abdb8105 --- /dev/null +++ b/contrib/gdb/gdb/config/xm-lynx.h @@ -0,0 +1,22 @@ +/* Host-dependent definitions for any CPU running LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* for INT_MIN, to avoid "INT_MIN redefined" warnings from defs.h */ + +#include diff --git a/contrib/gdb/gdb/config/xm-mpw.h b/contrib/gdb/gdb/config/xm-mpw.h new file mode 100644 index 000000000000..0c473d755726 --- /dev/null +++ b/contrib/gdb/gdb/config/xm-mpw.h @@ -0,0 +1,81 @@ +/* Macro definitions for running GDB on Apple Macintoshes. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "mpw.h" + +#include "fopen-bin.h" + +#include "spin.h" + +#define CANT_FORK + +/* Map these standard functions to versions that can do I/O in a console + window. */ + +#define printf hacked_printf +#define fprintf hacked_fprintf +#define vprintf hacked_vfprintf +#define fputs hacked_fputs +#define fputc hacked_fputc +#undef putc +#define putc hacked_putc +#define fflush hacked_fflush + +#define fgetc hacked_fgetc + +#define POSIX_UTIME + +/* No declaration of strdup in MPW's string.h, oddly enough. */ + +char *strdup (char *s1); + +/* '.' indicates drivers on the Mac, so we need a different filename. */ + +#define GDBINIT_FILENAME "_gdbinit" + +/* Commas are more common to separate dirnames in a path on Macs. */ + +#define DIRNAME_SEPARATOR ',' + +/* This is a real crufty hack. */ + +#define HAVE_TERMIO + +/* Addons to the basic MPW-supported signal list. */ + +#ifndef SIGQUIT +#define SIGQUIT (1<<6) +#endif +#ifndef SIGHUP +#define SIGHUP (1<<7) +#endif + +/* If __STDC__ is on, then this definition will be missing. */ + +#ifndef fileno +#define fileno(p) (p)->_file +#endif + +#ifndef R_OK +#define R_OK 4 +#endif + +extern int StandAlone; + +extern int mac_app; diff --git a/contrib/gdb/gdb/config/xm-nbsd.h b/contrib/gdb/gdb/config/xm-nbsd.h new file mode 100644 index 000000000000..5d522706672c --- /dev/null +++ b/contrib/gdb/gdb/config/xm-nbsd.h @@ -0,0 +1,37 @@ +/* Host-dependent definitions for any CPU running NetBSD. + Copyright 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* We have to include these files now, so that GDB will not make + competing definitions in defs.h. */ +#include + +#include +#if BYTE_ORDER == BIG_ENDIAN +#define HOST_BYTE_ORDER BIG_ENDIAN +#else +#define HOST_BYTE_ORDER LITTLE_ENDIAN +#endif + +/* NetBSD has termios facilities. */ +#define HAVE_TERMIOS + +#if 0 +#define CC_HAS_LONG_LONG 1 +#define PRINTF_HAS_LONG_LONG 1 +#endif diff --git a/contrib/gdb/gdb/config/xm-sysv4.h b/contrib/gdb/gdb/config/xm-sysv4.h new file mode 100644 index 000000000000..1ffe8fa75b48 --- /dev/null +++ b/contrib/gdb/gdb/config/xm-sysv4.h @@ -0,0 +1,36 @@ +/* Definitions for running gdb on a host machine running any flavor of SVR4. + Copyright 1991, 1992 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* SVR4 has termios facilities. */ + +#undef HAVE_TERMIO +#define HAVE_TERMIOS + +/* SVR4 is a derivative of System V Release 3 (USG) */ + +#define USG + +/* Use setpgid(0,0) to run inferior in a separate process group */ + +#define NEED_POSIX_SETPGID + +/* We have to include these files now, so that GDB will not make + competing definitions in defs.h. */ +#include diff --git a/contrib/gdb/gdb/configure b/contrib/gdb/gdb/configure new file mode 100644 index 000000000000..e8a1ad9babcd --- /dev/null +++ b/contrib/gdb/gdb/configure @@ -0,0 +1,2745 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.8 +# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-netrom " +ac_help="$ac_help + --enable-gm " +ac_help="$ac_help + --enable-sim-powerpc " +ac_help="$ac_help + --enable-gdbtk " +ac_help="$ac_help + --with-x use the X Window System" +ac_help="$ac_help + --with-tclinclude directory where tcl private headers are" +ac_help="$ac_help + --with-tcllib directory where the tcl library is" +ac_help="$ac_help + --with-tkinclude directory where the tk private headers are" +ac_help="$ac_help + --with-tklib directory where the tk library is" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.8" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=main.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 +if test $ac_cv_prog_gcc = yes; then + GCC=yes + if test "${CFLAGS+set}" != set; then + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_gcc_g=yes +else + ac_cv_prog_gcc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 + if test $ac_cv_prog_gcc_g = yes; then + CFLAGS="-g -O" + else + CFLAGS="-O" + fi + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:680: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:695: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for AIX""... $ac_c" 1>&6 +cat > conftest.$ac_ext <&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF +#define _ALL_SOURCE 1 +EOF + +else + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* + + +ac_safe=`echo "minix/config.h" | tr './\055' '___'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:749: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_ifs" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`$ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + +# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_RANLIB"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + RANLIB=":" +fi +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +for ac_prog in mawk gawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + + +ac_aux_dir= +for ac_dir in `cd $srcdir;pwd`/.. $srcdir/`cd $srcdir;pwd`/..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir;pwd`/.. $srcdir/`cd $srcdir;pwd`/.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`$ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`$ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +# If we cannot run a trivial program, we must be cross compiling. +echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_cross=yes +else +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_c_cross=no +else + ac_cv_c_cross=yes +fi +fi +rm -fr conftest* +fi + +echo "$ac_t""$ac_cv_c_cross" 1>&6 +cross_compiling=$ac_cv_c_cross + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1255: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else +cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +{ (eval echo configure:1320: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + : +else + ac_cv_header_stdc=no +fi +fi +rm -fr conftest* +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +for ac_hdr in limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h sys/procfs.h link.h endian.h +do +ac_safe=`echo "$ac_hdr" | tr './\055' '___'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1352: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "You lose" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_header_stat_broken=yes +else + rm -rf conftest* + ac_cv_header_stat_broken=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_stat_broken" 1>&6 +if test $ac_cv_header_stat_broken = yes; then + cat >> confdefs.h <<\EOF +#define STAT_MACROS_BROKEN 1 +EOF + +fi + + +for ac_func in setpgid sbrk +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1461: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +echo $ac_n "checking for gregset_t type""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'gdb_cv_have_gregset_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +gregset_t *gregsetp = 0 +; return 0; } +EOF +if { (eval echo configure:1497: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + gdb_cv_have_gregset_t=yes +else + rm -rf conftest* + gdb_cv_have_gregset_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$gdb_cv_have_gregset_t" 1>&6 +if test $gdb_cv_have_gregset_t = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_GREGSET_T 1 +EOF + +fi + +echo $ac_n "checking for fpregset_t type""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'gdb_cv_have_fpregset_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +fpregset_t *fpregsetp = 0 +; return 0; } +EOF +if { (eval echo configure:1529: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + gdb_cv_have_fpregset_t=yes +else + rm -rf conftest* + gdb_cv_have_fpregset_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$gdb_cv_have_fpregset_t" 1>&6 +if test $gdb_cv_have_fpregset_t = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_FPREGSET_T 1 +EOF + +fi + + +echo $ac_n "checking for long double support in compiler""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_c_long_double'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_long_double=yes +else + rm -rf conftest* + ac_cv_c_long_double=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_c_long_double" 1>&6 +if test $ac_cv_c_long_double = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LONG_DOUBLE 1 +EOF + +fi + + +echo $ac_n "checking for long double support in printf""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'gdb_cv_printf_has_long_double'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + gdb_cv_printf_has_long_double=no +else +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + gdb_cv_printf_has_long_double=yes +else + gdb_cv_printf_has_long_double=no +fi +fi +rm -fr conftest* +fi + +if test $gdb_cv_printf_has_long_double = yes; then + cat >> confdefs.h <<\EOF +#define PRINTF_HAS_LONG_DOUBLE 1 +EOF + +fi +echo "$ac_t""$gdb_cv_printf_has_long_double" 1>&6 + +for ac_func in valloc getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +char $ac_func(); + +int main() { return 0; } +int t() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1647: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_func_mmap'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap=no +else +cat > conftest.$ac_ext < +#include +#include + +#ifndef HAVE_GETPAGESIZE +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif +# else +# ifdef NBPC +# define getpagesize() NBPC +# else +# define getpagesize() PAGESIZE /* SVR4 */ +# endif +# endif +# endif +#endif + +#ifndef HAVE_VALLOC +# define valloc malloc +#endif + +#ifdef __cplusplus +extern "C" { void *valloc(unsigned), *malloc(unsigned); } +#else +char *valloc(), *malloc(); +#endif + +int +main() +{ + char *buf1, *buf2, *buf3; + int i = getpagesize(), j; + int i2 = i * 2; + int fd; + + buf1 = (char *)valloc(i2); + buf2 = (char *)valloc(i); + buf3 = (char *)malloc(i2); + for (j = 0; j < i2; ++j) + *(buf1 + j) = rand(); + fd = open("conftestmmap", O_CREAT | O_RDWR, 0666); + write(fd, buf1, i2); + mmap(buf2, i, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, fd, 0); + for (j = 0; j < i; ++j) + if (*(buf1 + j) != *(buf2 + j)) + exit(1); + lseek(fd, (long)i, 0); + read(fd, buf2, i); /* read into mapped memory -- file should not change */ + /* (it does in i386 SVR4.0 - Jim Avera, jima@netcom.com) */ + lseek(fd, (long)0, 0); + read(fd, buf3, i2); + for (j = 0; j < i2; ++j) + if (*(buf1 + j) != *(buf3 + j)) + exit(1); + exit(0); +} + +EOF +{ (eval echo configure:1746: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } +if test -s conftest && (./conftest; exit) 2>/dev/null; then + ac_cv_func_mmap=yes +else + ac_cv_func_mmap=no +fi +fi +rm -fr conftest* +fi + +echo "$ac_t""$ac_cv_func_mmap" 1>&6 +if test $ac_cv_func_mmap = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + + +ENABLE_CFLAGS= +ENABLE_CLIBS= +ENABLE_OBS= + +# Check whether --enable-netrom or --disable-netrom was given. +if test "${enable_netrom+set}" = set; then + enableval="$enable_netrom" + case "${enableval}" in +yes) enable_netrom=yes ;; +no) enable_netrom=no ;; +*) { echo "configure: error: bad value ${enableval} given for netrom option" 1>&2; exit 1; } ;; +esac +fi + + +if test "${enable_netrom}" = "yes"; then + ENABLE_OBS="${ENABLE_OBS} remote-nrom.o" +fi + + +# Check whether --enable-sim-powerpc or --disable-sim-powerpc was given. +if test "${enable_sim_powerpc+set}" = set; then + enableval="$enable_sim_powerpc" + case "${enableval}" in +yes) powerpc_sim=yes ;; +no) powerpc_sim=no ;; +*) { echo "configure: error: bad value ${enableval} given for sim-powerpc option" 1>&2; exit 1; } ;; +esac +else + if test x"$GCC" != x""; then powerpc_sim=yes; else powerpc_sim=no; fi +fi + + + + + + + +# target_subdir is used by the testsuite to find the target libraries. +target_subdir= +if test "${host}" != "${target}"; then + target_subdir="${target_alias}/" +fi + + +configdirs="doc testsuite" + + +# Map host cpu into the config cpu subdirectory name. +# The default is $host_cpu. + +case "${host_cpu}" in + +c[12]) gdb_host_cpu=convex ;; +hppa*) gdb_host_cpu=pa ;; +i[3456]86) gdb_host_cpu=i386 ;; +m68*) gdb_host_cpu=m68k ;; +m88*) gdb_host_cpu=m88k ;; +np1) gdb_host_cpu=gould ;; +pyramid) gdb_host_cpu=pyr ;; +powerpc*) gdb_host_cpu=powerpc ;; +sparc64) gdb_host_cpu=sparc ;; +*) gdb_host_cpu=$host_cpu ;; + +esac + +# map host info into gdb names. + +case "${host}" in + +a29k-*-*) gdb_host=ultra3 ;; + +alpha-*-osf1*) gdb_host=alpha-osf1 ;; +alpha-*-osf2*) gdb_host=alpha-osf2 ;; +alpha-*-osf[3456789]*) gdb_host=alpha-osf3 ;; + +arm-*-*) gdb_host=arm ;; + +c[12]-*-*) gdb_host=convex ;; + +hppa*-*-bsd*) gdb_host=hppabsd ;; +hppa*-*-hiux*) gdb_host=hppahpux ;; +hppa*-*-hpux*) gdb_host=hppahpux ;; +hppa*-*-osf*) gdb_host=hppaosf ;; + +i[3456]86-ncr-*) gdb_host=ncr3000 ;; +i[3456]86-sequent-bsd*) gdb_host=symmetry ;; # dynix +i[3456]86-sequent-sysv4*) gdb_host=ptx4 ;; +i[3456]86-sequent-sysv*) gdb_host=ptx ;; +i[3456]86-*-aix*) gdb_host=i386aix ;; +i[3456]86-*-bsd*) gdb_host=i386bsd ;; +i[3456]86-*-dgux*) gdb_host=i386dgux ;; +i[3456]86-*-freebsd*) gdb_host=fbsd ;; +i[3456]86-*-netbsd*) gdb_host=nbsd ;; +i[3456]86-*-go32*) gdb_host=go32 ;; +i[3456]86-*-linux*) gdb_host=linux ;; +i[3456]86-*-lynxos*) gdb_host=i386lynx ;; +i[3456]86-*-mach3*) gdb_host=i386m3 ;; +i[3456]86-*-mach*) gdb_host=i386mach ;; +i[3456]86-*-gnu*) gdb_host=i386gnu ;; +i[3456]86-*-osf1mk*) gdb_host=osf1mk ;; +i[3456]86-*-sco3.2v5*) gdb_host=i386sco5 ;; +i[3456]86-*-sco3.2v4*) gdb_host=i386sco4 ;; +i[3456]86-*-sco*) gdb_host=i386sco ;; +i[3456]86-*-solaris*) gdb_host=i386sol2 ;; +i[3456]86-*-sunos*) gdb_host=sun386 ;; +i[3456]86-*-sysv3.2*) gdb_host=i386v32 ;; +i[3456]86-*-sysv32*) gdb_host=i386v32 ;; +i[3456]86-*-sysv4*) gdb_host=i386v4 ;; +i[3456]86-*-unixware) gdb_host=i386v4 ;; +i[3456]86-*-sysv*) gdb_host=i386v ;; +i[3456]86-*-isc*) gdb_host=i386v32 ;; +i[3456]86-*-os9k) gdb_host=i386os9k ;; +i[3456]86-*-cygwin32) gdb_host=cygwin32 ;; +m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; +m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; +m68030-sony-*) gdb_host=news1000 ;; + +m68*-altos-*) gdb_host=altos ;; +m68*-apollo*-sysv*) gdb_host=apollo68v ;; +m68*-apollo*-bsd*) gdb_host=apollo68b ;; +m68*-att-*) gdb_host=3b1 ;; +m68*-bull*-sysv*) gdb_host=dpx2 ;; +m68*-hp-bsd*) gdb_host=hp300bsd ;; +m68*-hp-hpux*) gdb_host=hp300hpux ;; +m68*-isi-*) gdb_host=isi ;; +m68*-*-lynxos*) gdb_host=m68klynx ;; +m68*-*-netbsd*) gdb_host=nbsd ;; +m68*-*-sysv4*) gdb_host=m68kv4 ;; +m68*-motorola-*) gdb_host=delta68 ;; +m68*-sony-*) gdb_host=news ;; +m68*-sun-sunos3*) gdb_host=sun3os3 ;; +m68*-sun-sunos4*) gdb_host=sun3os4 ;; +m68*-sun-*) gdb_host=sun3os4 ;; + +m88*-harris-cxux*) gdb_host=cxux ;; +m88*-motorola-sysv4*) gdb_host=delta88v4 ;; +m88*-motorola-sysv*) gdb_host=delta88 ;; +m88*-*-mach3*) gdb_host=mach3 ;; +m88*-*-*) gdb_host=m88k ;; + +mips-dec-mach3*) gdb_host=mach3 ;; +mips-dec-*) gdb_host=decstation ;; +mips-little-*) gdb_host=littlemips ;; +mips-sgi-irix3*) gdb_host=irix3 ;; +mips-sgi-irix4*) gdb_host=irix4 ;; +mips-sgi-irix5*) gdb_host=irix5 ;; +mips-sony-*) gdb_host=news-mips ;; +mips-*-mach3*) gdb_host=mach3 ;; +mips-*-sysv4*) gdb_host=mipsv4 ;; +mips-*-sysv*) gdb_host=riscos ;; +mips-*-riscos*) gdb_host=riscos ;; + +none-*-*) gdb_host=none ;; + +np1-*-*) gdb_host=np1 ;; + +ns32k-*-mach3*) gdb_host=mach3 ;; +ns32k-*-netbsd*) gdb_host=nbsd ;; +ns32k-umax-*) gdb_host=umax ;; +ns32k-utek-sysv*) gdb_host=merlin ;; + +powerpc-*-aix*) gdb_host=aix ;; +powerpcle-*-cygwin32) gdb_host=cygwin32 ;; +pn-*-*) gdb_host=pn ;; + +pyramid-*-*) gdb_host=pyramid ;; + +romp-*-*) gdb_host=rtbsd ;; + +rs6000-*-lynxos*) gdb_host=rs6000lynx ;; +rs6000-*-aix4*) gdb_host=aix4 ;; +rs6000-*-*) gdb_host=rs6000 ;; + +sparc-*-lynxos*) gdb_host=sparclynx ;; +sparc-*-netbsd*) gdb_host=nbsd ;; +sparc-*-solaris2*) gdb_host=sun4sol2 ;; +sparc-*-sunos4*) gdb_host=sun4os4 ;; +sparc-*-sunos5*) gdb_host=sun4sol2 ;; +sparc-*-*) gdb_host=sun4os4 ;; +sparc64-*-*) gdb_host=sun4sol2 ;; + +tahoe-*-*) gdb_host=tahoe ;; + +vax-*-bsd*) gdb_host=vaxbsd ;; +vax-*-ultrix2*) gdb_host=vaxult2 ;; +vax-*-ultrix*) gdb_host=vaxult ;; + +w65-*-*) gdb_host=w65 ;; + +esac + + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. + +case "${target_cpu}" in + +alpha) gdb_target_cpu=alpha ;; +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[3456]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +m88*) gdb_target_cpu=m88k ;; +mips*) gdb_target_cpu=mips ;; +np1) gdb_target_cpu=gould ;; +powerpc*) gdb_target_cpu=powerpc ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; + +esac + +# map target info into gdb names. + +case "${target}" in + +a29k-*-aout*) gdb_target=a29k ;; +a29k-*-coff*) gdb_target=a29k ;; +a29k-*-elf*) gdb_target=a29k ;; +a29k-*-ebmon*) gdb_target=a29k ;; +a29k-*-kern*) gdb_target=a29k-kern ;; +a29k-*-none*) gdb_target=a29k ;; +a29k-*-sym1*) gdb_target=ultra3 ;; +a29k-*-udi*) gdb_target=a29k-udi ;; +a29k-*-vxworks*) gdb_target=vx29k ;; + +alpha-*-osf*) gdb_target=alpha-osf1 ;; + + +arm-*-*) gdb_target=arm ;; + +c1-*-*) gdb_target=convex ;; +c2-*-*) gdb_target=convex ;; + +h8300-*-*) gdb_target=h8300 ;; +h8500-*-*) gdb_target=h8500 ;; + +sh-*-*) gdb_target=sh ;; + + +hppa*-*-bsd*) gdb_target=hppabsd ;; +hppa*-*-pro*) gdb_target=hppapro ;; +hppa*-*-hpux*) gdb_target=hppahpux ;; +hppa*-*-hiux*) gdb_target=hppahpux ;; +hppa*-*-osf*) gdb_target=hppaosf ;; + +i[3456]86-sequent-bsd*) gdb_target=symmetry ;; +i[3456]86-sequent-sysv4*) gdb_target=ptx4 ;; +i[3456]86-sequent-sysv*) gdb_target=ptx ;; +i[3456]86-ncr-*) gdb_target=ncr3000 ;; +i[3456]86-*-aout*) gdb_target=i386aout ;; +i[3456]86-*-coff*) gdb_target=i386v ;; +i[3456]86-*-elf*) gdb_target=i386v ;; +i[3456]86-*-aix*) gdb_target=i386aix ;; +i[3456]86-*-bsd*) gdb_target=i386bsd ;; +i[3456]86-*-freebsd*) gdb_target=fbsd ;; +i[3456]86-*-netbsd*) gdb_target=nbsd ;; +i[3456]86-*-os9k) gdb_target=i386os9k ;; +i[3456]86-*-go32*) gdb_target=i386aout ;; +i[3456]86-*-lynxos*) gdb_target=i386lynx + configdirs="${configdirs} gdbserver" ;; +i[3456]86-*-solaris*) gdb_target=i386sol2 ;; +i[3456]86-*-sunos*) gdb_target=sun386 ;; +i[3456]86-*-sysv4*) gdb_target=i386v4 ;; +i[3456]86-*-sco*) gdb_target=i386v ;; +i[3456]86-*-sysv*) gdb_target=i386v ;; +i[3456]86-*-linux*) gdb_target=linux + configdirs="${configdirs} gdbserver" ;; +i[3456]86-*-isc*) gdb_target=i386v ;; +i[3456]86-*-mach3*) gdb_target=i386m3 ;; +i[3456]86-*-mach*) gdb_target=i386mach ;; +i[3456]86-*-gnu*) gdb_target=i386gnu ;; +i[3456]86-*-netware*) gdb_target=i386nw + configdirs="${configdirs} nlm" ;; +i[3456]86-*-osf1mk*) gdb_target=i386mk ;; +i[3456]86-*-cygwin32) gdb_target=cygwin32 ;; +i960-*-bout*) gdb_target=vxworks960 ;; +i960-nindy-coff*) gdb_target=nindy960 ;; +i960-*-coff*) gdb_target=mon960 ;; +i960-nindy-elf*) gdb_target=nindy960 ;; +i960-*-elf*) gdb_target=mon960 ;; + +i960-*-nindy*) gdb_target=nindy960 ;; +i960-*-vxworks*) gdb_target=vxworks960 ;; + +m68000-*-sunos3*) gdb_target=sun2os3 ;; +m68000-*-sunos4*) gdb_target=sun2os4 ;; + +m68*-apollo*-bsd*) gdb_target=apollo68b ;; +m68*-bull-sysv*) gdb_target=dpx2 ;; +m68*-hp-bsd*) gdb_target=hp300bsd ;; +m68*-hp-hpux*) gdb_target=hp300hpux ;; +m68*-altos-*) gdb_target=altos ;; +m68*-att-*) gdb_target=3b1 ;; +m68*-cisco*-*) gdb_target=cisco ;; +m68*-ericsson-*) gdb_target=es1800 ;; +m68*-isi-*) gdb_target=isi ;; +m68*-motorola-*) gdb_target=delta68 ;; +m68*-netx-*) gdb_target=vxworks68 ;; +m68*-sony-*) gdb_target=news ;; +m68*-tandem-*) gdb_target=st2000 ;; +m68*-rom68k-*) gdb_target=monitor ;; +m68*-*bug-*) gdb_target=monitor ;; +m68*-monitor-*) gdb_target=monitor ;; +m68*-est-*) gdb_target=monitor ;; +m68*-*-aout*) gdb_target=monitor ;; +m68*-*-coff*) gdb_target=monitor ;; +m68*-*-elf*) gdb_target=monitor ;; +m68*-*-lynxos*) gdb_target=m68klynx + configdirs="${configdirs} gdbserver" ;; +m68*-*-netbsd*) gdb_target=nbsd ;; +m68*-*-os68k*) gdb_target=os68k ;; +m68*-*-sunos3*) gdb_target=sun3os3 ;; +m68*-*-sunos4*) gdb_target=sun3os4 ;; +m68*-*-sysv4*) gdb_target=m68kv4 ;; +m68*-*-vxworks*) gdb_target=vxworks68 ;; + +m88*-harris-cxux*) gdb_target=cxux ;; +m88*-motorola-sysv4*) gdb_target=delta88v4 ;; +m88*-*-mach3*) gdb_target=mach3 ;; +m88*-motorola-*) gdb_target=delta88 ;; +m88*-*-*) gdb_target=m88k ;; + +mips64*-big-*) gdb_target=bigmips64 ;; +mips*-big-*) gdb_target=bigmips ;; +mips*-dec-mach3*) gdb_target=mach3 ;; +mips*-dec-*) gdb_target=decstation ;; +mips64*el-*-ecoff*) gdb_target=embedl64 ;; +mips64*-*-ecoff*) gdb_target=embed64 ;; +mips64*vr4300*el-*-elf*) gdb_target=vr4300el ;; +mips64*vr4300*-*-elf*) gdb_target=vr4300 ;; +mips64*el-*-elf*) gdb_target=embedl64 ;; +mips64*-*-elf*) gdb_target=embed64 ;; +mips*el-*-ecoff*) gdb_target=embedl ;; +mips*-*-ecoff*) gdb_target=embed ;; +mips*el-*-elf*) gdb_target=embedl ;; +mips*-*-elf*) gdb_target=embed ;; +mips*-little-*) gdb_target=littlemips ;; +mips*-sgi-irix5*) gdb_target=irix5 ;; +mips*-sgi-*) gdb_target=irix3 ;; +mips*-sony-*) gdb_target=bigmips ;; +mips*-*-mach3*) gdb_target=mach3 ;; +mips*-*-sysv4*) gdb_target=mipsv4 ;; +mips*-*-sysv*) gdb_target=bigmips ;; +mips*-*-riscos*) gdb_target=bigmips ;; +mips*-*-vxworks*) gdb_target=vxmips ;; + +none-*-*) gdb_target=none ;; + +np1-*-*) gdb_target=np1 ;; + +ns32k-*-mach3*) gdb_target=mach3 ;; +ns32k-*-netbsd*) gdb_target=nbsd ;; +ns32k-utek-sysv*) gdb_target=merlin ;; +ns32k-utek-*) gdb_target=umax ;; + +pn-*-*) gdb_target=pn ;; +powerpc-*-macos*) gdb_target=macos ;; +powerpc-*-netware*) gdb_target=ppc-nw + configdirs="${configdirs} nlm" ;; + +powerpc-*-aix4*) gdb_target=aix4 ;; +powerpc-*-aix*) gdb_target=aix ;; +powerpcle-*-cygwin32) gdb_target=cygwin32 ;; +powerpc-*-eabi*) if test x"$powerpc_sim" = x"yes"; then + gdb_target=ppc-sim + else + gdb_target=ppc-eabi + fi ;; +powerpcle-*-eabi*) if test x"$powerpc_sim" = x"yes"; then + gdb_target=ppcle-sim + else + gdb_target=ppcle-eabi + fi ;; + +pyramid-*-*) gdb_target=pyramid ;; + +rs6000-*-lynxos*) gdb_target=rs6000lynx ;; +rs6000-*-aix4*) gdb_target=aix4 ;; +rs6000-*-*) gdb_target=rs6000 ;; + +sparc-*-aout*) gdb_target=sparc-em ;; +sparc-*-coff*) gdb_target=sparc-em ;; +sparc-*-elf*) gdb_target=sparc-em ;; +sparc-*-lynxos*) gdb_target=sparclynx + configdirs="${configdirs} gdbserver" ;; +sparc-*-netbsd*) gdb_target=nbsd ;; +sparc-*-solaris2*) gdb_target=sun4sol2 ;; +sparc-*-sunos4*) gdb_target=sun4os4 ;; +sparc-*-sunos5*) gdb_target=sun4sol2 ;; +sparc-*-vxworks*) gdb_target=vxsparc ;; +sparc-*-*) gdb_target=sun4os4 ;; +# Use sparc-em for sparclet for now. +sparclet-*-*) gdb_target=sparc-em ;; +sparclite*-*-*) gdb_target=sparclite ;; +sparc64-*-solaris2*) gdb_target=sp64sol2 ;; +sparc64-*-*) gdb_target=sp64 ;; + +tahoe-*-*) gdb_target=tahoe ;; + +vax-*-*) gdb_target=vax ;; + +w65-*-*) gdb_target=w65 ;; + +z8k-*-coff*) gdb_target=z8k ;; + +esac + + +frags= +host_makefile_frag=${srcdir}/config/${gdb_host_cpu}/${gdb_host}.mh +if test ! -f ${host_makefile_frag}; then +{ echo "configure: error: "*** Gdb does not support host ${host}"" 1>&2; exit 1; } +fi +frags="$frags $host_makefile_frag" + +target_makefile_frag=${srcdir}/config/${gdb_target_cpu}/${gdb_target}.mt +if test ! -f ${target_makefile_frag}; then +{ echo "configure: error: "*** Gdb does not support target ${target}"" 1>&2; exit 1; } +fi +frags="$frags $target_makefile_frag" + + + + + +hostfile=`sed -n ' +s/XM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${host_makefile_frag}` + +targetfile=`sed -n ' +s/TM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${target_makefile_frag}` + +# these really aren't orthogonal true/false values of the same condition, +# but shells are slow enough that I like to reuse the test conditions +# whenever possible +if test "${target}" = "${host}"; then +nativefile=`sed -n ' +s/NAT_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${host_makefile_frag}` +else +# GDBserver is only useful in a "native" enviroment +configdirs=`echo $configdirs | sed 's/gdbserver//'` +fi + + +# If hostfile (XM_FILE) and/or targetfile (TM_FILE) and/or nativefile +# (NAT_FILE) is not set in config/*/*.m[ht] files, we don't make the +# corresponding links. But we have to remove the xm.h files and tm.h +# files anyway, e.g. when switching from "configure host" to +# "configure none". + +files= +links= +rm -f xm.h +if test "${hostfile}" != ""; then +files="${files} config/${gdb_host_cpu}/${hostfile}" +links="${links} xm.h" +fi +rm -f tm.h +if test "${targetfile}" != ""; then +files="${files} config/${gdb_target_cpu}/${targetfile}" +links="${links} tm.h" +fi +rm -f nm.h +if test "${nativefile}" != ""; then +files="${files} config/${gdb_host_cpu}/${nativefile}" +links="${links} nm.h" +else +# A cross-only configuration. +files="${files} config/nm-empty.h" +links="${links} nm.h" +fi + + + +subdirs="$configdirs" + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ + >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.8" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile config.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g +s%@YACC@%$YACC%g +s%@AWK@%$AWK%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@X_CFLAGS@%$X_CFLAGS%g +s%@X_PRE_LIBS@%$X_PRE_LIBS%g +s%@X_LIBS@%$X_LIBS%g +s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g +s%@TCLHDIR@%$TCLHDIR%g +s%@TCLLIB@%$TCLLIB%g +s%@TKHDIR@%$TKHDIR%g +s%@TKLIB@%$TKLIB%g +s%@ENABLE_GDBTK@%$ENABLE_GDBTK%g +s%@X_LDFLAGS@%$X_LDFLAGS%g +s%@ENABLE_CFLAGS@%$ENABLE_CFLAGS%g +s%@ENABLE_CLIBS@%$ENABLE_CLIBS%g +s%@ENABLE_OBS@%$ENABLE_OBS%g +s%@target_subdir@%$target_subdir%g +/@host_makefile_frag@/r $host_makefile_frag +s%@host_makefile_frag@%%g +/@target_makefile_frag@/r $target_makefile_frag +s%@target_makefile_frag@%%g +s%@frags@%$frags%g +s%@subdirs@%$subdirs%g + +CEOF +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust relative srcdir, etc. for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file +fi; done +rm -f conftest.subs + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +CONFIG_HEADERS=${CONFIG_HEADERS-"config.h:config.in"} +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + cp $ac_given_srcdir/$ac_file_in conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. +# Maximum number of lines to put in a single here document. +ac_max_here_lines=12 + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +srcdir=$ac_given_srcdir +while test -n "$ac_sources"; do + set $ac_dests; ac_dest=$1; shift; ac_dests=$* + set $ac_sources; ac_source=$1; shift; ac_sources=$* + + echo "linking $srcdir/$ac_source to $ac_dest" + + if test ! -r $srcdir/$ac_source; then + { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; } + fi + rm -f $ac_dest + + # Make relative symlinks. + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'` + if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then + # The dest file is in a subdirectory. + test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir" + ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dest_dir_suffix. + ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dest_dir_suffix= ac_dots= + fi + + case "$srcdir" in + [/$]*) ac_rel_source="$srcdir/$ac_source" ;; + *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;; + esac + + # Make a symlink if possible; otherwise try a hard link. + if ln -s $ac_rel_source $ac_dest 2>/dev/null || + ln $srcdir/$ac_source $ac_dest; then : + else + { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; } + fi +done +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +if test "${nativefile}" = ""; then +sed -e '/^NATDEPFILES= /s//# NATDEPFILES= /' \ + < Makefile > Makefile.tem +mv -f Makefile.tem Makefile +fi + +sed -e '/^TM_FILE[ ]*=/s,^TM_FILE[ ]*=[ ]*,&config/'"${gdb_target_cpu}"'/, +/^XM_FILE[ ]*=/s,^XM_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/, +/^NAT_FILE[ ]*=/s,^NAT_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/,' Makefile.tmp +mv -f Makefile.tmp Makefile + +case ${srcdir} in +.) +;; +*) +grep "source ${srcdir}/.gdbinit" .gdbinit >/dev/null 2>/dev/null || \ +echo "source ${srcdir}/.gdbinit" >> .gdbinit +esac + +case x$CONFIG_HEADERS in +xconfig.h:config.in) +echo > stamp-h ;; +esac + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in $configdirs; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; } + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=../$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2 + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` + case "$cache_file" in + /*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; } + fi + fi + + cd $ac_popdir + done +fi + + +exit 0 + diff --git a/contrib/gdb/gdb/configure.in b/contrib/gdb/gdb/configure.in new file mode 100644 index 000000000000..0967fd101e82 --- /dev/null +++ b/contrib/gdb/gdb/configure.in @@ -0,0 +1,615 @@ +dnl Autoconf configure script for GDB, the GNU debugger. +dnl Copyright 1995, 1996 Free Software Foundation, Inc. +dnl +dnl This file is part of GDB. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.3)dnl +AC_INIT(main.c) +AC_CONFIG_HEADER(config.h:config.in) + +AC_PROG_CC +AC_AIX +AC_MINIX +AC_ISC_POSIX + +AC_PROG_INSTALL +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_PROG_YACC +AC_PROG_AWK + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +AC_HEADER_STDC +AC_CHECK_HEADERS(limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h sys/procfs.h link.h endian.h) +AC_HEADER_STAT + +AC_CHECK_FUNCS(setpgid sbrk) + +AC_MSG_CHECKING([for gregset_t type]) +AC_CACHE_VAL(gdb_cv_have_gregset_t, +[AC_TRY_LINK([#include ],[gregset_t *gregsetp = 0], +gdb_cv_have_gregset_t=yes, gdb_cv_have_gregset_t=no)]) +AC_MSG_RESULT($gdb_cv_have_gregset_t) +if test $gdb_cv_have_gregset_t = yes; then + AC_DEFINE(HAVE_GREGSET_T) +fi + +AC_MSG_CHECKING([for fpregset_t type]) +AC_CACHE_VAL(gdb_cv_have_fpregset_t, +[AC_TRY_LINK([#include ],[fpregset_t *fpregsetp = 0], +gdb_cv_have_fpregset_t=yes, gdb_cv_have_fpregset_t=no)]) +AC_MSG_RESULT($gdb_cv_have_fpregset_t) +if test $gdb_cv_have_fpregset_t = yes; then + AC_DEFINE(HAVE_FPREGSET_T) +fi + +dnl See if compiler supports "long double" type. Can't use AC_C_LONG_DOUBLE +dnl because autoconf complains about cross-compilation issues. However, this +dnl code uses the same variables as the macro for compatibility. + +AC_MSG_CHECKING(for long double support in compiler) +AC_CACHE_VAL(ac_cv_c_long_double, +[AC_TRY_COMPILE(, [long double foo;], +ac_cv_c_long_double=yes, ac_cv_c_long_double=no)]) +AC_MSG_RESULT($ac_cv_c_long_double) +if test $ac_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE) +fi + +dnl See if the compiler and runtime support printing long doubles + +AC_MSG_CHECKING(for long double support in printf) +AC_CACHE_VAL(gdb_cv_printf_has_long_double, +[AC_TRY_RUN([ +int main () { + char buf[16]; + long double f = 3.141592653; + sprintf (buf, "%Lg", f); + return (strncmp ("3.14159", buf, 7)); +}], +gdb_cv_printf_has_long_double=yes, +gdb_cv_printf_has_long_double=no, +gdb_cv_printf_has_long_double=no)]) +if test $gdb_cv_printf_has_long_double = yes; then + AC_DEFINE(PRINTF_HAS_LONG_DOUBLE) +fi +AC_MSG_RESULT($gdb_cv_printf_has_long_double) + +AC_FUNC_MMAP + +dnl Handle optional features that can be enabled. +ENABLE_CFLAGS= +ENABLE_CLIBS= +ENABLE_OBS= + +AC_ARG_ENABLE(netrom, +[ --enable-netrom ], +[case "${enableval}" in +yes) enable_netrom=yes ;; +no) enable_netrom=no ;; +*) AC_MSG_ERROR(bad value ${enableval} given for netrom option) ;; +esac]) + +if test "${enable_netrom}" = "yes"; then + ENABLE_OBS="${ENABLE_OBS} remote-nrom.o" +fi + + +AC_ARG_ENABLE(sim-powerpc, +[ --enable-sim-powerpc ], +[case "${enableval}" in +yes) powerpc_sim=yes ;; +no) powerpc_sim=no ;; +*) AC_MSG_ERROR(bad value ${enableval} given for sim-powerpc option) ;; +esac],[if test x"$GCC" != x""; then powerpc_sim=yes; else powerpc_sim=no; fi]) + + +AC_SUBST(ENABLE_CFLAGS) +AC_SUBST(ENABLE_CLIBS) +AC_SUBST(ENABLE_OBS) + +# target_subdir is used by the testsuite to find the target libraries. +target_subdir= +if test "${host}" != "${target}"; then + target_subdir="${target_alias}/" +fi +AC_SUBST(target_subdir) + +configdirs="doc testsuite" + +dnl +changequote(,)dnl + +# Map host cpu into the config cpu subdirectory name. +# The default is $host_cpu. + +case "${host_cpu}" in + +c[12]) gdb_host_cpu=convex ;; +hppa*) gdb_host_cpu=pa ;; +i[3456]86) gdb_host_cpu=i386 ;; +m68*) gdb_host_cpu=m68k ;; +m88*) gdb_host_cpu=m88k ;; +np1) gdb_host_cpu=gould ;; +pyramid) gdb_host_cpu=pyr ;; +powerpc*) gdb_host_cpu=powerpc ;; +sparc64) gdb_host_cpu=sparc ;; +*) gdb_host_cpu=$host_cpu ;; + +esac + +# map host info into gdb names. + +case "${host}" in + +a29k-*-*) gdb_host=ultra3 ;; + +alpha-*-osf1*) gdb_host=alpha-osf1 ;; +alpha-*-osf2*) gdb_host=alpha-osf2 ;; +alpha-*-osf[3456789]*) gdb_host=alpha-osf3 ;; + +arm-*-*) gdb_host=arm ;; + +c[12]-*-*) gdb_host=convex ;; + +hppa*-*-bsd*) gdb_host=hppabsd ;; +hppa*-*-hiux*) gdb_host=hppahpux ;; +hppa*-*-hpux*) gdb_host=hppahpux ;; +hppa*-*-osf*) gdb_host=hppaosf ;; + +i[3456]86-ncr-*) gdb_host=ncr3000 ;; +i[3456]86-sequent-bsd*) gdb_host=symmetry ;; # dynix +i[3456]86-sequent-sysv4*) gdb_host=ptx4 ;; +i[3456]86-sequent-sysv*) gdb_host=ptx ;; +i[3456]86-*-aix*) gdb_host=i386aix ;; +i[3456]86-*-bsd*) gdb_host=i386bsd ;; +i[3456]86-*-dgux*) gdb_host=i386dgux ;; +i[3456]86-*-freebsd*) gdb_host=fbsd ;; +i[3456]86-*-netbsd*) gdb_host=nbsd ;; +i[3456]86-*-go32*) gdb_host=go32 ;; +i[3456]86-*-linux*) gdb_host=linux ;; +i[3456]86-*-lynxos*) gdb_host=i386lynx ;; +i[3456]86-*-mach3*) gdb_host=i386m3 ;; +i[3456]86-*-mach*) gdb_host=i386mach ;; +i[3456]86-*-gnu*) gdb_host=i386gnu ;; +i[3456]86-*-osf1mk*) gdb_host=osf1mk ;; +i[3456]86-*-sco3.2v5*) gdb_host=i386sco5 ;; +i[3456]86-*-sco3.2v4*) gdb_host=i386sco4 ;; +i[3456]86-*-sco*) gdb_host=i386sco ;; +i[3456]86-*-solaris*) gdb_host=i386sol2 ;; +i[3456]86-*-sunos*) gdb_host=sun386 ;; +i[3456]86-*-sysv3.2*) gdb_host=i386v32 ;; +i[3456]86-*-sysv32*) gdb_host=i386v32 ;; +i[3456]86-*-sysv4*) gdb_host=i386v4 ;; +i[3456]86-*-unixware) gdb_host=i386v4 ;; +i[3456]86-*-sysv*) gdb_host=i386v ;; +i[3456]86-*-isc*) gdb_host=i386v32 ;; +i[3456]86-*-os9k) gdb_host=i386os9k ;; +i[3456]86-*-cygwin32) gdb_host=cygwin32 ;; +m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; +m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; +m68030-sony-*) gdb_host=news1000 ;; + +m68*-altos-*) gdb_host=altos ;; +m68*-apollo*-sysv*) gdb_host=apollo68v ;; +m68*-apollo*-bsd*) gdb_host=apollo68b ;; +m68*-att-*) gdb_host=3b1 ;; +m68*-bull*-sysv*) gdb_host=dpx2 ;; +m68*-hp-bsd*) gdb_host=hp300bsd ;; +m68*-hp-hpux*) gdb_host=hp300hpux ;; +m68*-isi-*) gdb_host=isi ;; +m68*-*-lynxos*) gdb_host=m68klynx ;; +m68*-*-netbsd*) gdb_host=nbsd ;; +m68*-*-sysv4*) gdb_host=m68kv4 ;; +m68*-motorola-*) gdb_host=delta68 ;; +m68*-sony-*) gdb_host=news ;; +m68*-sun-sunos3*) gdb_host=sun3os3 ;; +m68*-sun-sunos4*) gdb_host=sun3os4 ;; +m68*-sun-*) gdb_host=sun3os4 ;; + +m88*-harris-cxux*) gdb_host=cxux ;; +m88*-motorola-sysv4*) gdb_host=delta88v4 ;; +m88*-motorola-sysv*) gdb_host=delta88 ;; +m88*-*-mach3*) gdb_host=mach3 ;; +m88*-*-*) gdb_host=m88k ;; + +mips-dec-mach3*) gdb_host=mach3 ;; +mips-dec-*) gdb_host=decstation ;; +mips-little-*) gdb_host=littlemips ;; +mips-sgi-irix3*) gdb_host=irix3 ;; +mips-sgi-irix4*) gdb_host=irix4 ;; +mips-sgi-irix5*) gdb_host=irix5 ;; +mips-sony-*) gdb_host=news-mips ;; +mips-*-mach3*) gdb_host=mach3 ;; +mips-*-sysv4*) gdb_host=mipsv4 ;; +mips-*-sysv*) gdb_host=riscos ;; +mips-*-riscos*) gdb_host=riscos ;; + +none-*-*) gdb_host=none ;; + +np1-*-*) gdb_host=np1 ;; + +ns32k-*-mach3*) gdb_host=mach3 ;; +ns32k-*-netbsd*) gdb_host=nbsd ;; +ns32k-umax-*) gdb_host=umax ;; +ns32k-utek-sysv*) gdb_host=merlin ;; + +powerpc-*-aix*) gdb_host=aix ;; +powerpcle-*-cygwin32) gdb_host=cygwin32 ;; +pn-*-*) gdb_host=pn ;; + +pyramid-*-*) gdb_host=pyramid ;; + +romp-*-*) gdb_host=rtbsd ;; + +rs6000-*-lynxos*) gdb_host=rs6000lynx ;; +rs6000-*-aix4*) gdb_host=aix4 ;; +rs6000-*-*) gdb_host=rs6000 ;; + +sparc-*-lynxos*) gdb_host=sparclynx ;; +sparc-*-netbsd*) gdb_host=nbsd ;; +sparc-*-solaris2*) gdb_host=sun4sol2 ;; +sparc-*-sunos4*) gdb_host=sun4os4 ;; +sparc-*-sunos5*) gdb_host=sun4sol2 ;; +sparc-*-*) gdb_host=sun4os4 ;; +sparc64-*-*) gdb_host=sun4sol2 ;; + +tahoe-*-*) gdb_host=tahoe ;; + +vax-*-bsd*) gdb_host=vaxbsd ;; +vax-*-ultrix2*) gdb_host=vaxult2 ;; +vax-*-ultrix*) gdb_host=vaxult ;; + +w65-*-*) gdb_host=w65 ;; + +esac + + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. + +case "${target_cpu}" in + +alpha) gdb_target_cpu=alpha ;; +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[3456]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +m88*) gdb_target_cpu=m88k ;; +mips*) gdb_target_cpu=mips ;; +np1) gdb_target_cpu=gould ;; +powerpc*) gdb_target_cpu=powerpc ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; + +esac + +# map target info into gdb names. + +case "${target}" in + +a29k-*-aout*) gdb_target=a29k ;; +a29k-*-coff*) gdb_target=a29k ;; +a29k-*-elf*) gdb_target=a29k ;; +a29k-*-ebmon*) gdb_target=a29k ;; +a29k-*-kern*) gdb_target=a29k-kern ;; +a29k-*-none*) gdb_target=a29k ;; +a29k-*-sym1*) gdb_target=ultra3 ;; +a29k-*-udi*) gdb_target=a29k-udi ;; +a29k-*-vxworks*) gdb_target=vx29k ;; + +alpha-*-osf*) gdb_target=alpha-osf1 ;; + + +arm-*-*) gdb_target=arm ;; + +c1-*-*) gdb_target=convex ;; +c2-*-*) gdb_target=convex ;; + +h8300-*-*) gdb_target=h8300 ;; +h8500-*-*) gdb_target=h8500 ;; + +sh-*-*) gdb_target=sh ;; + + +hppa*-*-bsd*) gdb_target=hppabsd ;; +hppa*-*-pro*) gdb_target=hppapro ;; +hppa*-*-hpux*) gdb_target=hppahpux ;; +hppa*-*-hiux*) gdb_target=hppahpux ;; +hppa*-*-osf*) gdb_target=hppaosf ;; + +i[3456]86-sequent-bsd*) gdb_target=symmetry ;; +i[3456]86-sequent-sysv4*) gdb_target=ptx4 ;; +i[3456]86-sequent-sysv*) gdb_target=ptx ;; +i[3456]86-ncr-*) gdb_target=ncr3000 ;; +i[3456]86-*-aout*) gdb_target=i386aout ;; +i[3456]86-*-coff*) gdb_target=i386v ;; +i[3456]86-*-elf*) gdb_target=i386v ;; +i[3456]86-*-aix*) gdb_target=i386aix ;; +i[3456]86-*-bsd*) gdb_target=i386bsd ;; +i[3456]86-*-freebsd*) gdb_target=fbsd ;; +i[3456]86-*-netbsd*) gdb_target=nbsd ;; +i[3456]86-*-os9k) gdb_target=i386os9k ;; +i[3456]86-*-go32*) gdb_target=i386aout ;; +i[3456]86-*-lynxos*) gdb_target=i386lynx + configdirs="${configdirs} gdbserver" ;; +i[3456]86-*-solaris*) gdb_target=i386sol2 ;; +i[3456]86-*-sunos*) gdb_target=sun386 ;; +i[3456]86-*-sysv4*) gdb_target=i386v4 ;; +i[3456]86-*-sco*) gdb_target=i386v ;; +i[3456]86-*-sysv*) gdb_target=i386v ;; +i[3456]86-*-linux*) gdb_target=linux + configdirs="${configdirs} gdbserver" ;; +i[3456]86-*-isc*) gdb_target=i386v ;; +i[3456]86-*-mach3*) gdb_target=i386m3 ;; +i[3456]86-*-mach*) gdb_target=i386mach ;; +i[3456]86-*-gnu*) gdb_target=i386gnu ;; +i[3456]86-*-netware*) gdb_target=i386nw + configdirs="${configdirs} nlm" ;; +i[3456]86-*-osf1mk*) gdb_target=i386mk ;; +i[3456]86-*-cygwin32) gdb_target=cygwin32 ;; +i960-*-bout*) gdb_target=vxworks960 ;; +i960-nindy-coff*) gdb_target=nindy960 ;; +i960-*-coff*) gdb_target=mon960 ;; +i960-nindy-elf*) gdb_target=nindy960 ;; +i960-*-elf*) gdb_target=mon960 ;; + +i960-*-nindy*) gdb_target=nindy960 ;; +i960-*-vxworks*) gdb_target=vxworks960 ;; + +m68000-*-sunos3*) gdb_target=sun2os3 ;; +m68000-*-sunos4*) gdb_target=sun2os4 ;; + +m68*-apollo*-bsd*) gdb_target=apollo68b ;; +m68*-bull-sysv*) gdb_target=dpx2 ;; +m68*-hp-bsd*) gdb_target=hp300bsd ;; +m68*-hp-hpux*) gdb_target=hp300hpux ;; +m68*-altos-*) gdb_target=altos ;; +m68*-att-*) gdb_target=3b1 ;; +m68*-cisco*-*) gdb_target=cisco ;; +m68*-ericsson-*) gdb_target=es1800 ;; +m68*-isi-*) gdb_target=isi ;; +m68*-motorola-*) gdb_target=delta68 ;; +m68*-netx-*) gdb_target=vxworks68 ;; +m68*-sony-*) gdb_target=news ;; +m68*-tandem-*) gdb_target=st2000 ;; +m68*-rom68k-*) gdb_target=monitor ;; +m68*-*bug-*) gdb_target=monitor ;; +m68*-monitor-*) gdb_target=monitor ;; +m68*-est-*) gdb_target=monitor ;; +m68*-*-aout*) gdb_target=monitor ;; +m68*-*-coff*) gdb_target=monitor ;; +m68*-*-elf*) gdb_target=monitor ;; +m68*-*-lynxos*) gdb_target=m68klynx + configdirs="${configdirs} gdbserver" ;; +m68*-*-netbsd*) gdb_target=nbsd ;; +m68*-*-os68k*) gdb_target=os68k ;; +m68*-*-sunos3*) gdb_target=sun3os3 ;; +m68*-*-sunos4*) gdb_target=sun3os4 ;; +m68*-*-sysv4*) gdb_target=m68kv4 ;; +m68*-*-vxworks*) gdb_target=vxworks68 ;; + +m88*-harris-cxux*) gdb_target=cxux ;; +m88*-motorola-sysv4*) gdb_target=delta88v4 ;; +m88*-*-mach3*) gdb_target=mach3 ;; +m88*-motorola-*) gdb_target=delta88 ;; +m88*-*-*) gdb_target=m88k ;; + +mips64*-big-*) gdb_target=bigmips64 ;; +mips*-big-*) gdb_target=bigmips ;; +mips*-dec-mach3*) gdb_target=mach3 ;; +mips*-dec-*) gdb_target=decstation ;; +mips64*el-*-ecoff*) gdb_target=embedl64 ;; +mips64*-*-ecoff*) gdb_target=embed64 ;; +mips64*vr4300*el-*-elf*) gdb_target=vr4300el ;; +mips64*vr4300*-*-elf*) gdb_target=vr4300 ;; +mips64*el-*-elf*) gdb_target=embedl64 ;; +mips64*-*-elf*) gdb_target=embed64 ;; +mips*el-*-ecoff*) gdb_target=embedl ;; +mips*-*-ecoff*) gdb_target=embed ;; +mips*el-*-elf*) gdb_target=embedl ;; +mips*-*-elf*) gdb_target=embed ;; +mips*-little-*) gdb_target=littlemips ;; +mips*-sgi-irix5*) gdb_target=irix5 ;; +mips*-sgi-*) gdb_target=irix3 ;; +mips*-sony-*) gdb_target=bigmips ;; +mips*-*-mach3*) gdb_target=mach3 ;; +mips*-*-sysv4*) gdb_target=mipsv4 ;; +mips*-*-sysv*) gdb_target=bigmips ;; +mips*-*-riscos*) gdb_target=bigmips ;; +mips*-*-vxworks*) gdb_target=vxmips ;; + +none-*-*) gdb_target=none ;; + +np1-*-*) gdb_target=np1 ;; + +ns32k-*-mach3*) gdb_target=mach3 ;; +ns32k-*-netbsd*) gdb_target=nbsd ;; +ns32k-utek-sysv*) gdb_target=merlin ;; +ns32k-utek-*) gdb_target=umax ;; + +pn-*-*) gdb_target=pn ;; +powerpc-*-macos*) gdb_target=macos ;; +powerpc-*-netware*) gdb_target=ppc-nw + configdirs="${configdirs} nlm" ;; + +powerpc-*-aix4*) gdb_target=aix4 ;; +powerpc-*-aix*) gdb_target=aix ;; +powerpcle-*-cygwin32) gdb_target=cygwin32 ;; +powerpc-*-eabi*) if test x"$powerpc_sim" = x"yes"; then + gdb_target=ppc-sim + else + gdb_target=ppc-eabi + fi ;; +powerpcle-*-eabi*) if test x"$powerpc_sim" = x"yes"; then + gdb_target=ppcle-sim + else + gdb_target=ppcle-eabi + fi ;; + +pyramid-*-*) gdb_target=pyramid ;; + +rs6000-*-lynxos*) gdb_target=rs6000lynx ;; +rs6000-*-aix4*) gdb_target=aix4 ;; +rs6000-*-*) gdb_target=rs6000 ;; + +sparc-*-aout*) gdb_target=sparc-em ;; +sparc-*-coff*) gdb_target=sparc-em ;; +sparc-*-elf*) gdb_target=sparc-em ;; +sparc-*-lynxos*) gdb_target=sparclynx + configdirs="${configdirs} gdbserver" ;; +sparc-*-netbsd*) gdb_target=nbsd ;; +sparc-*-solaris2*) gdb_target=sun4sol2 ;; +sparc-*-sunos4*) gdb_target=sun4os4 ;; +sparc-*-sunos5*) gdb_target=sun4sol2 ;; +sparc-*-vxworks*) gdb_target=vxsparc ;; +sparc-*-*) gdb_target=sun4os4 ;; +# Use sparc-em for sparclet for now. +sparclet-*-*) gdb_target=sparc-em ;; +sparclite*-*-*) gdb_target=sparclite ;; +sparc64-*-solaris2*) gdb_target=sp64sol2 ;; +sparc64-*-*) gdb_target=sp64 ;; + +tahoe-*-*) gdb_target=tahoe ;; + +vax-*-*) gdb_target=vax ;; + +w65-*-*) gdb_target=w65 ;; + +z8k-*-coff*) gdb_target=z8k ;; + +esac + +dnl +changequote([,])dnl + +frags= +host_makefile_frag=${srcdir}/config/${gdb_host_cpu}/${gdb_host}.mh +if test ! -f ${host_makefile_frag}; then +AC_MSG_ERROR("*** Gdb does not support host ${host}") +fi +frags="$frags $host_makefile_frag" + +target_makefile_frag=${srcdir}/config/${gdb_target_cpu}/${gdb_target}.mt +if test ! -f ${target_makefile_frag}; then +AC_MSG_ERROR("*** Gdb does not support target ${target}") +fi +frags="$frags $target_makefile_frag" + +AC_SUBST_FILE(host_makefile_frag) +AC_SUBST_FILE(target_makefile_frag) +AC_SUBST(frags) + +changequote(,)dnl +hostfile=`sed -n ' +s/XM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${host_makefile_frag}` + +targetfile=`sed -n ' +s/TM_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${target_makefile_frag}` + +# these really aren't orthogonal true/false values of the same condition, +# but shells are slow enough that I like to reuse the test conditions +# whenever possible +if test "${target}" = "${host}"; then +nativefile=`sed -n ' +s/NAT_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${host_makefile_frag}` +else +# GDBserver is only useful in a "native" enviroment +configdirs=`echo $configdirs | sed 's/gdbserver//'` +fi +changequote([,]) + +# If hostfile (XM_FILE) and/or targetfile (TM_FILE) and/or nativefile +# (NAT_FILE) is not set in config/*/*.m[ht] files, we don't make the +# corresponding links. But we have to remove the xm.h files and tm.h +# files anyway, e.g. when switching from "configure host" to +# "configure none". + +files= +links= +rm -f xm.h +if test "${hostfile}" != ""; then +files="${files} config/${gdb_host_cpu}/${hostfile}" +links="${links} xm.h" +fi +rm -f tm.h +if test "${targetfile}" != ""; then +files="${files} config/${gdb_target_cpu}/${targetfile}" +links="${links} tm.h" +fi +rm -f nm.h +if test "${nativefile}" != ""; then +files="${files} config/${gdb_host_cpu}/${nativefile}" +links="${links} nm.h" +else +# A cross-only configuration. +files="${files} config/nm-empty.h" +links="${links} nm.h" +fi + +AC_LINK_FILES($files, $links) + +AC_CONFIG_SUBDIRS($configdirs) +AC_OUTPUT(Makefile, +[ +dnl Autoconf doesn't provide a mechanism for modifying definitions +dnl provided by makefile fragments. +dnl +if test "${nativefile}" = ""; then +sed -e '/^NATDEPFILES= /s//# NATDEPFILES= /' \ + < Makefile > Makefile.tem +mv -f Makefile.tem Makefile +fi + +changequote(,)dnl +sed -e '/^TM_FILE[ ]*=/s,^TM_FILE[ ]*=[ ]*,&config/'"${gdb_target_cpu}"'/, +/^XM_FILE[ ]*=/s,^XM_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/, +/^NAT_FILE[ ]*=/s,^NAT_FILE[ ]*=[ ]*,&config/'"${gdb_host_cpu}"'/,' Makefile.tmp +mv -f Makefile.tmp Makefile +changequote([,])dnl + +case ${srcdir} in +.) +;; +*) +grep "source ${srcdir}/.gdbinit" .gdbinit >/dev/null 2>/dev/null || \ +echo "source ${srcdir}/.gdbinit" >> .gdbinit +esac + +case x$CONFIG_HEADERS in +xconfig.h:config.in) +echo > stamp-h ;; +esac +], +[ +gdb_host_cpu=$gdb_host_cpu +gdb_target_cpu=$gdb_target_cpu +nativefile=$nativefile +]) + +exit 0 + diff --git a/contrib/gdb/gdb/copying.awk b/contrib/gdb/gdb/copying.awk new file mode 100644 index 000000000000..ab8efe8b73a3 --- /dev/null +++ b/contrib/gdb/gdb/copying.awk @@ -0,0 +1,77 @@ +BEGIN { + FS="\""; + print "/* ==> Do not modify this file!! It is created automatically"; + print " by copying.awk. Modify copying.awk instead. <== */"; + print "" + print "#include \"defs.h\"" + print "#include \"command.h\"" + print "#include \"gdbcmd.h\"" + print "" + print "static void" + print "show_copying_command PARAMS ((char *, int));" + print "" + print "static void" + print "show_warranty_command PARAMS ((char *, int));" + print "" + print "extern int immediate_quit;"; + print "static void"; + print "show_copying_command (ignore, from_tty)"; + print " char *ignore;"; + print " int from_tty;"; + print "{"; + print " immediate_quit++;"; + } +NR == 1,/^[ ]*NO WARRANTY[ ]*$/ { + if ($0 ~ / /) + { + printf " printf_filtered (\"\\n\");\n"; + } + else if ($0 !~ /^[ ]*NO WARRANTY[ ]*$/) + { + printf " printf_filtered (\""; + for (i = 1; i < NF; i++) + printf "%s\\\"", $i; + printf "%s\\n\");\n", $NF; + } + } +/^[ ]*NO WARRANTY[ ]*$/ { + print " immediate_quit--;"; + print "}"; + print ""; + print "static void"; + print "show_warranty_command (ignore, from_tty)"; + print " char *ignore;"; + print " int from_tty;"; + print "{"; + print " immediate_quit++;"; + } +/^[ ]*NO WARRANTY[ ]*$/, /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/{ + if (! ($0 ~ /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/)) + { + printf " printf_filtered (\""; + for (i = 1; i < NF; i++) + printf "%s\\\"", $i; + printf "%s\\n\");\n", $NF; + } + } +END { + print " immediate_quit--;"; + print "}"; + print ""; + print "void" + print "_initialize_copying ()"; + print "{"; + print " add_cmd (\"copying\", no_class, show_copying_command,"; + print " \"Conditions for redistributing copies of GDB.\","; + print " &showlist);"; + print " add_cmd (\"warranty\", no_class, show_warranty_command,"; + print " \"Various kinds of warranty you do not have.\","; + print " &showlist);"; + print ""; + print " /* For old-timers, allow \"info copying\", etc. */"; + print " add_info (\"copying\", show_copying_command,"; + print " \"Conditions for redistributing copies of GDB.\");"; + print " add_info (\"warranty\", show_warranty_command,"; + print " \"Various kinds of warranty you do not have.\");"; + print "}"; + } diff --git a/contrib/gdb/gdb/copying.c b/contrib/gdb/gdb/copying.c new file mode 100644 index 000000000000..ffc884a67140 --- /dev/null +++ b/contrib/gdb/gdb/copying.c @@ -0,0 +1,327 @@ +/* ==> Do not modify this file!! It is created automatically + by copying.awk. Modify copying.awk instead. <== */ + +#include "defs.h" +#include "command.h" +#include "gdbcmd.h" + +static void +show_copying_command PARAMS ((char *, int)); + +static void +show_warranty_command PARAMS ((char *, int)); + +extern int immediate_quit; +static void +show_copying_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + immediate_quit++; + printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); + printf_filtered (" Version 2, June 1991\n"); + printf_filtered ("\n"); + printf_filtered (" Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n"); + printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n"); + printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n"); + printf_filtered (" of this license document, but changing it is not allowed.\n"); + printf_filtered ("\n"); + printf_filtered (" Preamble\n"); + printf_filtered ("\n"); + printf_filtered (" The licenses for most software are designed to take away your\n"); + printf_filtered ("freedom to share and change it. By contrast, the GNU General Public\n"); + printf_filtered ("License is intended to guarantee your freedom to share and change free\n"); + printf_filtered ("software--to make sure the software is free for all its users. This\n"); + printf_filtered ("General Public License applies to most of the Free Software\n"); + printf_filtered ("Foundation's software and to any other program whose authors commit to\n"); + printf_filtered ("using it. (Some other Free Software Foundation software is covered by\n"); + printf_filtered ("the GNU Library General Public License instead.) You can apply it to\n"); + printf_filtered ("your programs, too.\n"); + printf_filtered ("\n"); + printf_filtered (" When we speak of free software, we are referring to freedom, not\n"); + printf_filtered ("price. Our General Public Licenses are designed to make sure that you\n"); + printf_filtered ("have the freedom to distribute copies of free software (and charge for\n"); + printf_filtered ("this service if you wish), that you receive source code or can get it\n"); + printf_filtered ("if you want it, that you can change the software or use pieces of it\n"); + printf_filtered ("in new free programs; and that you know you can do these things.\n"); + printf_filtered ("\n"); + printf_filtered (" To protect your rights, we need to make restrictions that forbid\n"); + printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n"); + printf_filtered ("These restrictions translate to certain responsibilities for you if you\n"); + printf_filtered ("distribute copies of the software, or if you modify it.\n"); + printf_filtered ("\n"); + printf_filtered (" For example, if you distribute copies of such a program, whether\n"); + printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n"); + printf_filtered ("you have. You must make sure that they, too, receive or can get the\n"); + printf_filtered ("source code. And you must show them these terms so they know their\n"); + printf_filtered ("rights.\n"); + printf_filtered ("\n"); + printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n"); + printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n"); + printf_filtered ("distribute and/or modify the software.\n"); + printf_filtered ("\n"); + printf_filtered (" Also, for each author's protection and ours, we want to make certain\n"); + printf_filtered ("that everyone understands that there is no warranty for this free\n"); + printf_filtered ("software. If the software is modified by someone else and passed on, we\n"); + printf_filtered ("want its recipients to know that what they have is not the original, so\n"); + printf_filtered ("that any problems introduced by others will not reflect on the original\n"); + printf_filtered ("authors' reputations.\n"); + printf_filtered ("\n"); + printf_filtered (" Finally, any free program is threatened constantly by software\n"); + printf_filtered ("patents. We wish to avoid the danger that redistributors of a free\n"); + printf_filtered ("program will individually obtain patent licenses, in effect making the\n"); + printf_filtered ("program proprietary. To prevent this, we have made it clear that any\n"); + printf_filtered ("patent must be licensed for everyone's free use or not licensed at all.\n"); + printf_filtered ("\n"); + printf_filtered (" The precise terms and conditions for copying, distribution and\n"); + printf_filtered ("modification follow.\n"); + printf_filtered ("\n"); + printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); + printf_filtered (" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n"); + printf_filtered ("\n"); + printf_filtered (" 0. This License applies to any program or other work which contains\n"); + printf_filtered ("a notice placed by the copyright holder saying it may be distributed\n"); + printf_filtered ("under the terms of this General Public License. The \"Program\", below,\n"); + printf_filtered ("refers to any such program or work, and a \"work based on the Program\"\n"); + printf_filtered ("means either the Program or any derivative work under copyright law:\n"); + printf_filtered ("that is to say, a work containing the Program or a portion of it,\n"); + printf_filtered ("either verbatim or with modifications and/or translated into another\n"); + printf_filtered ("language. (Hereinafter, translation is included without limitation in\n"); + printf_filtered ("the term \"modification\".) Each licensee is addressed as \"you\".\n"); + printf_filtered ("\n"); + printf_filtered ("Activities other than copying, distribution and modification are not\n"); + printf_filtered ("covered by this License; they are outside its scope. The act of\n"); + printf_filtered ("running the Program is not restricted, and the output from the Program\n"); + printf_filtered ("is covered only if its contents constitute a work based on the\n"); + printf_filtered ("Program (independent of having been made by running the Program).\n"); + printf_filtered ("Whether that is true depends on what the Program does.\n"); + printf_filtered ("\n"); + printf_filtered (" 1. You may copy and distribute verbatim copies of the Program's\n"); + printf_filtered ("source code as you receive it, in any medium, provided that you\n"); + printf_filtered ("conspicuously and appropriately publish on each copy an appropriate\n"); + printf_filtered ("copyright notice and disclaimer of warranty; keep intact all the\n"); + printf_filtered ("notices that refer to this License and to the absence of any warranty;\n"); + printf_filtered ("and give any other recipients of the Program a copy of this License\n"); + printf_filtered ("along with the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("You may charge a fee for the physical act of transferring a copy, and\n"); + printf_filtered ("you may at your option offer warranty protection in exchange for a fee.\n"); + printf_filtered ("\n"); + printf_filtered (" 2. You may modify your copy or copies of the Program or any portion\n"); + printf_filtered ("of it, thus forming a work based on the Program, and copy and\n"); + printf_filtered ("distribute such modifications or work under the terms of Section 1\n"); + printf_filtered ("above, provided that you also meet all of these conditions:\n"); + printf_filtered ("\n"); + printf_filtered (" a) You must cause the modified files to carry prominent notices\n"); + printf_filtered (" stating that you changed the files and the date of any change.\n"); + printf_filtered ("\n"); + printf_filtered (" b) You must cause any work that you distribute or publish, that in\n"); + printf_filtered (" whole or in part contains or is derived from the Program or any\n"); + printf_filtered (" part thereof, to be licensed as a whole at no charge to all third\n"); + printf_filtered (" parties under the terms of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" c) If the modified program normally reads commands interactively\n"); + printf_filtered (" when run, you must cause it, when started running for such\n"); + printf_filtered (" interactive use in the most ordinary way, to print or display an\n"); + printf_filtered (" announcement including an appropriate copyright notice and a\n"); + printf_filtered (" notice that there is no warranty (or else, saying that you provide\n"); + printf_filtered (" a warranty) and that users may redistribute the program under\n"); + printf_filtered (" these conditions, and telling the user how to view a copy of this\n"); + printf_filtered (" License. (Exception: if the Program itself is interactive but\n"); + printf_filtered (" does not normally print such an announcement, your work based on\n"); + printf_filtered (" the Program is not required to print an announcement.)\n"); + printf_filtered ("\n"); + printf_filtered ("These requirements apply to the modified work as a whole. If\n"); + printf_filtered ("identifiable sections of that work are not derived from the Program,\n"); + printf_filtered ("and can be reasonably considered independent and separate works in\n"); + printf_filtered ("themselves, then this License, and its terms, do not apply to those\n"); + printf_filtered ("sections when you distribute them as separate works. But when you\n"); + printf_filtered ("distribute the same sections as part of a whole which is a work based\n"); + printf_filtered ("on the Program, the distribution of the whole must be on the terms of\n"); + printf_filtered ("this License, whose permissions for other licensees extend to the\n"); + printf_filtered ("entire whole, and thus to each and every part regardless of who wrote it.\n"); + printf_filtered ("\n"); + printf_filtered ("Thus, it is not the intent of this section to claim rights or contest\n"); + printf_filtered ("your rights to work written entirely by you; rather, the intent is to\n"); + printf_filtered ("exercise the right to control the distribution of derivative or\n"); + printf_filtered ("collective works based on the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("In addition, mere aggregation of another work not based on the Program\n"); + printf_filtered ("with the Program (or with a work based on the Program) on a volume of\n"); + printf_filtered ("a storage or distribution medium does not bring the other work under\n"); + printf_filtered ("the scope of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 3. You may copy and distribute the Program (or a work based on it,\n"); + printf_filtered ("under Section 2) in object code or executable form under the terms of\n"); + printf_filtered ("Sections 1 and 2 above provided that you also do one of the following:\n"); + printf_filtered ("\n"); + printf_filtered (" a) Accompany it with the complete corresponding machine-readable\n"); + printf_filtered (" source code, which must be distributed under the terms of Sections\n"); + printf_filtered (" 1 and 2 above on a medium customarily used for software interchange; or,\n"); + printf_filtered ("\n"); + printf_filtered (" b) Accompany it with a written offer, valid for at least three\n"); + printf_filtered (" years, to give any third party, for a charge no more than your\n"); + printf_filtered (" cost of physically performing source distribution, a complete\n"); + printf_filtered (" machine-readable copy of the corresponding source code, to be\n"); + printf_filtered (" distributed under the terms of Sections 1 and 2 above on a medium\n"); + printf_filtered (" customarily used for software interchange; or,\n"); + printf_filtered ("\n"); + printf_filtered (" c) Accompany it with the information you received as to the offer\n"); + printf_filtered (" to distribute corresponding source code. (This alternative is\n"); + printf_filtered (" allowed only for noncommercial distribution and only if you\n"); + printf_filtered (" received the program in object code or executable form with such\n"); + printf_filtered (" an offer, in accord with Subsection b above.)\n"); + printf_filtered ("\n"); + printf_filtered ("The source code for a work means the preferred form of the work for\n"); + printf_filtered ("making modifications to it. For an executable work, complete source\n"); + printf_filtered ("code means all the source code for all modules it contains, plus any\n"); + printf_filtered ("associated interface definition files, plus the scripts used to\n"); + printf_filtered ("control compilation and installation of the executable. However, as a\n"); + printf_filtered ("special exception, the source code distributed need not include\n"); + printf_filtered ("anything that is normally distributed (in either source or binary\n"); + printf_filtered ("form) with the major components (compiler, kernel, and so on) of the\n"); + printf_filtered ("operating system on which the executable runs, unless that component\n"); + printf_filtered ("itself accompanies the executable.\n"); + printf_filtered ("\n"); + printf_filtered ("If distribution of executable or object code is made by offering\n"); + printf_filtered ("access to copy from a designated place, then offering equivalent\n"); + printf_filtered ("access to copy the source code from the same place counts as\n"); + printf_filtered ("distribution of the source code, even though third parties are not\n"); + printf_filtered ("compelled to copy the source along with the object code.\n"); + printf_filtered ("\n"); + printf_filtered (" 4. You may not copy, modify, sublicense, or distribute the Program\n"); + printf_filtered ("except as expressly provided under this License. Any attempt\n"); + printf_filtered ("otherwise to copy, modify, sublicense or distribute the Program is\n"); + printf_filtered ("void, and will automatically terminate your rights under this License.\n"); + printf_filtered ("However, parties who have received copies, or rights, from you under\n"); + printf_filtered ("this License will not have their licenses terminated so long as such\n"); + printf_filtered ("parties remain in full compliance.\n"); + printf_filtered ("\n"); + printf_filtered (" 5. You are not required to accept this License, since you have not\n"); + printf_filtered ("signed it. However, nothing else grants you permission to modify or\n"); + printf_filtered ("distribute the Program or its derivative works. These actions are\n"); + printf_filtered ("prohibited by law if you do not accept this License. Therefore, by\n"); + printf_filtered ("modifying or distributing the Program (or any work based on the\n"); + printf_filtered ("Program), you indicate your acceptance of this License to do so, and\n"); + printf_filtered ("all its terms and conditions for copying, distributing or modifying\n"); + printf_filtered ("the Program or works based on it.\n"); + printf_filtered ("\n"); + printf_filtered (" 6. Each time you redistribute the Program (or any work based on the\n"); + printf_filtered ("Program), the recipient automatically receives a license from the\n"); + printf_filtered ("original licensor to copy, distribute or modify the Program subject to\n"); + printf_filtered ("these terms and conditions. You may not impose any further\n"); + printf_filtered ("restrictions on the recipients' exercise of the rights granted herein.\n"); + printf_filtered ("You are not responsible for enforcing compliance by third parties to\n"); + printf_filtered ("this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 7. If, as a consequence of a court judgment or allegation of patent\n"); + printf_filtered ("infringement or for any other reason (not limited to patent issues),\n"); + printf_filtered ("conditions are imposed on you (whether by court order, agreement or\n"); + printf_filtered ("otherwise) that contradict the conditions of this License, they do not\n"); + printf_filtered ("excuse you from the conditions of this License. If you cannot\n"); + printf_filtered ("distribute so as to satisfy simultaneously your obligations under this\n"); + printf_filtered ("License and any other pertinent obligations, then as a consequence you\n"); + printf_filtered ("may not distribute the Program at all. For example, if a patent\n"); + printf_filtered ("license would not permit royalty-free redistribution of the Program by\n"); + printf_filtered ("all those who receive copies directly or indirectly through you, then\n"); + printf_filtered ("the only way you could satisfy both it and this License would be to\n"); + printf_filtered ("refrain entirely from distribution of the Program.\n"); + printf_filtered ("\n"); + printf_filtered ("If any portion of this section is held invalid or unenforceable under\n"); + printf_filtered ("any particular circumstance, the balance of the section is intended to\n"); + printf_filtered ("apply and the section as a whole is intended to apply in other\n"); + printf_filtered ("circumstances.\n"); + printf_filtered ("\n"); + printf_filtered ("It is not the purpose of this section to induce you to infringe any\n"); + printf_filtered ("patents or other property right claims or to contest validity of any\n"); + printf_filtered ("such claims; this section has the sole purpose of protecting the\n"); + printf_filtered ("integrity of the free software distribution system, which is\n"); + printf_filtered ("implemented by public license practices. Many people have made\n"); + printf_filtered ("generous contributions to the wide range of software distributed\n"); + printf_filtered ("through that system in reliance on consistent application of that\n"); + printf_filtered ("system; it is up to the author/donor to decide if he or she is willing\n"); + printf_filtered ("to distribute software through any other system and a licensee cannot\n"); + printf_filtered ("impose that choice.\n"); + printf_filtered ("\n"); + printf_filtered ("This section is intended to make thoroughly clear what is believed to\n"); + printf_filtered ("be a consequence of the rest of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 8. If the distribution and/or use of the Program is restricted in\n"); + printf_filtered ("certain countries either by patents or by copyrighted interfaces, the\n"); + printf_filtered ("original copyright holder who places the Program under this License\n"); + printf_filtered ("may add an explicit geographical distribution limitation excluding\n"); + printf_filtered ("those countries, so that distribution is permitted only in or among\n"); + printf_filtered ("countries not thus excluded. In such case, this License incorporates\n"); + printf_filtered ("the limitation as if written in the body of this License.\n"); + printf_filtered ("\n"); + printf_filtered (" 9. The Free Software Foundation may publish revised and/or new versions\n"); + printf_filtered ("of the General Public License from time to time. Such new versions will\n"); + printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n"); + printf_filtered ("address new problems or concerns.\n"); + printf_filtered ("\n"); + printf_filtered ("Each version is given a distinguishing version number. If the Program\n"); + printf_filtered ("specifies a version number of this License which applies to it and \"any\n"); + printf_filtered ("later version\", you have the option of following the terms and conditions\n"); + printf_filtered ("either of that version or of any later version published by the Free\n"); + printf_filtered ("Software Foundation. If the Program does not specify a version number of\n"); + printf_filtered ("this License, you may choose any version ever published by the Free Software\n"); + printf_filtered ("Foundation.\n"); + printf_filtered ("\n"); + printf_filtered (" 10. If you wish to incorporate parts of the Program into other free\n"); + printf_filtered ("programs whose distribution conditions are different, write to the author\n"); + printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n"); + printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n"); + printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n"); + printf_filtered ("of preserving the free status of all derivatives of our free software and\n"); + printf_filtered ("of promoting the sharing and reuse of software generally.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +static void +show_warranty_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + immediate_quit++; + printf_filtered (" NO WARRANTY\n"); + printf_filtered ("\n"); + printf_filtered (" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"); + printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"); + printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"); + printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"); + printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"); + printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"); + printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"); + printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"); + printf_filtered ("REPAIR OR CORRECTION.\n"); + printf_filtered ("\n"); + printf_filtered (" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"); + printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"); + printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"); + printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"); + printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"); + printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"); + printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"); + printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"); + printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +void +_initialize_copying () +{ + add_cmd ("copying", no_class, show_copying_command, + "Conditions for redistributing copies of GDB.", + &showlist); + add_cmd ("warranty", no_class, show_warranty_command, + "Various kinds of warranty you do not have.", + &showlist); + + /* For old-timers, allow "info copying", etc. */ + add_info ("copying", show_copying_command, + "Conditions for redistributing copies of GDB."); + add_info ("warranty", show_warranty_command, + "Various kinds of warranty you do not have."); +} diff --git a/contrib/gdb/gdb/core-aout.c b/contrib/gdb/gdb/core-aout.c new file mode 100644 index 000000000000..7103a9c8e135 --- /dev/null +++ b/contrib/gdb/gdb/core-aout.c @@ -0,0 +1,143 @@ +/* Extract registers from a "standard" core file, for GDB. + Copyright (C) 1988-1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Typically used on systems that have a.out format executables. + corefile.c is supposed to contain the more machine-independent + aspects of reading registers from core files, while this file is + more machine specific. */ + +#include "defs.h" +#include +#include +#include "gdbcore.h" +#include "value.h" /* For supply_register. */ +#include "inferior.h" /* For ARCH_NUM_REGS. */ + +/* These are needed on various systems to expand REGISTER_U_ADDR. */ +#ifndef USG +#include +#include +#include "gdb_stat.h" +#include +#ifndef NO_PTRACE_H +# ifdef PTRACE_IN_WRONG_PLACE +# include +# else /* !PTRACE_IN_WRONG_PLACE */ +# include +# endif /* !PTRACE_IN_WRONG_PLACE */ +#endif /* NO_PTRACE_H */ +#endif + +#ifndef CORE_REGISTER_ADDR +#define CORE_REGISTER_ADDR(regno, regptr) register_addr(regno, regptr) +#endif /* CORE_REGISTER_ADDR */ + +#ifdef NEED_SYS_CORE_H +#include +#endif + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + register int regno; + register unsigned int addr; + int bad_reg = -1; + register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ + int numregs = ARCH_NUM_REGS; + + /* If u.u_ar0 was an absolute address in the core file, relativize it now, + so we can use it as an offset into core_reg_sect. When we're done, + "register 0" will be at core_reg_sect+reg_ptr, and we can use + CORE_REGISTER_ADDR to offset to the other registers. If this is a modern + core file without a upage, reg_ptr will be zero and this is all a big + NOP. */ + if (reg_ptr > (int) core_reg_size) + reg_ptr -= KERNEL_U_ADDR; + + for (regno = 0; regno < numregs; regno++) + { + addr = CORE_REGISTER_ADDR (regno, reg_ptr); + if (addr >= core_reg_size) { + if (bad_reg < 0) + bad_reg = regno; + } else { + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg >= 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + + +#ifdef REGISTER_U_ADDR + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= ARCH_NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* REGISTER_U_ADDR */ + + +/* Register that we are able to handle aout (trad-core) file formats. */ + +static struct core_fns aout_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_aout () +{ + add_core_fns (&aout_core_fns); +} diff --git a/contrib/gdb/gdb/core-regset.c b/contrib/gdb/gdb/core-regset.c new file mode 100644 index 000000000000..68b08457a491 --- /dev/null +++ b/contrib/gdb/gdb/core-regset.c @@ -0,0 +1,130 @@ +/* Machine independent GDB support for core files on systems using "regsets". + Copyright 1993-1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* N O T E S + +This file is used by most systems that implement /proc. For these systems, +the general registers are laid out the same way in both the core file and +the gregset_p structure. The current exception to this is Irix-4.*, where +the gregset_p structure is split up into two pieces in the core file. + +The general register and floating point register sets are manipulated by +separate ioctl's. This file makes the assumption that if FP0_REGNUM is +defined, then support for the floating point register set is desired, +regardless of whether or not the actual target has floating point hardware. + + */ + +#include "defs.h" + +#include +#ifdef HAVE_SYS_PROCFS_H +#include +#endif +#include +#include +#include "gdb_string.h" + +#include "inferior.h" +#include "target.h" +#include "command.h" +#include "gdbcore.h" + +/* + +GLOBAL FUNCTION + + fetch_core_registers -- fetch current registers from core file + +SYNOPSIS + + void fetch_core_registers (char *core_reg_sect, + unsigned core_reg_size, + int which, unsigned in reg_addr) + +DESCRIPTION + + Read the values of either the general register set (WHICH equals 0) + or the floating point register set (WHICH equals 2) from the core + file data (pointed to by CORE_REG_SECT), and update gdb's idea of + their current values. The CORE_REG_SIZE parameter is ignored. + +NOTES + + Use the indicated sizes to validate the gregset and fpregset + structures. +*/ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int reg_addr; /* Unused in this version */ +{ +#if defined (HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T) + gregset_t gregset; + fpregset_t fpregset; + + if (which == 0) + { + if (core_reg_size != sizeof (gregset)) + { + warning ("wrong size gregset struct in core file"); + } + else + { + memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset)); + supply_gregset (&gregset); + } + } + else if (which == 2) + { + if (core_reg_size != sizeof (fpregset)) + { + warning ("wrong size fpregset struct in core file"); + } + else + { + memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset)); +#if defined (FP0_REGNUM) + supply_fpregset (&fpregset); +#endif + } + } +#endif /* defined(HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T) */ +} + + +/* Register that we are able to handle ELF file formats using standard + procfs "regset" structures. */ + +static struct core_fns regset_core_fns = +{ + bfd_target_elf_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_regset () +{ + add_core_fns (®set_core_fns); +} diff --git a/contrib/gdb/gdb/core-sol2.c b/contrib/gdb/gdb/core-sol2.c new file mode 100644 index 000000000000..5f43002edb9a --- /dev/null +++ b/contrib/gdb/gdb/core-sol2.c @@ -0,0 +1,133 @@ +/* Machine independent support for Solaris 2 core files for GDB. + Copyright 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Solaris comes with two flavours of core files, cores generated by + an ELF executable and cores generated by programs that were + run under BCP (the part of Solaris which allows it to run SunOS4 + a.out files). + This file combines the core register fetching from core-regset.c + and sparc-nat.c to be able to read both flavours. */ + +#include "defs.h" +#undef gregset_t +#undef fpregset_t + +#include +#include +#include +#include +#include +#include "gdb_string.h" + +#include "inferior.h" +#include "target.h" +#include "command.h" +#include "gdbcore.h" + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int reg_addr; /* Unused in this version */ +{ + prgregset_t prgregset; + prfpregset_t prfpregset; + + if (which == 0) + { + if (core_reg_size == sizeof (prgregset)) + { + memcpy ((char *) &prgregset, core_reg_sect, sizeof (prgregset)); + supply_gregset (&prgregset); + } + else if (core_reg_size == sizeof (struct regs)) + { +#define gregs ((struct regs *)core_reg_sect) + /* G0 *always* holds 0. */ + *(int *)®isters[REGISTER_BYTE (0)] = 0; + + /* The globals and output registers. */ + memcpy (®isters[REGISTER_BYTE (G1_REGNUM)], &gregs->r_g1, + 15 * REGISTER_RAW_SIZE (G1_REGNUM)); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = gregs->r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = gregs->r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = gregs->r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = gregs->r_y; + + /* My best guess at where to get the locals and input + registers is exactly where they usually are, right above + the stack pointer. If the core dump was caused by a bus error + from blowing away the stack pointer (as is possible) then this + won't work, but it's worth the try. */ + { + int sp; + + sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)]; + if (0 != target_read_memory (sp, + ®isters[REGISTER_BYTE (L0_REGNUM)], + 16 * REGISTER_RAW_SIZE (L0_REGNUM))) + { + warning ("couldn't read input and local registers from core file\n"); + } + } + } + else + { + warning ("wrong size gregset struct in core file"); + } + } + else if (which == 2) + { + if (core_reg_size == sizeof (prfpregset)) + { + memcpy ((char *) &prfpregset, core_reg_sect, sizeof (prfpregset)); + supply_fpregset (&prfpregset); + } + else if (core_reg_size >= sizeof (struct fpu)) + { +#define fpuregs ((struct fpu *) core_reg_sect) + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &fpuregs->fpu_fr, + sizeof (fpuregs->fpu_fr)); + memcpy (®isters[REGISTER_BYTE (FPS_REGNUM)], &fpuregs->fpu_fsr, + sizeof (FPU_FSR_TYPE)); + } + else + { + warning ("wrong size fpregset struct in core file"); + } + } +} + + +/* Register that we are able to handle solaris core file formats. */ + +static struct core_fns solaris_core_fns = +{ + bfd_target_elf_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_solaris () +{ + add_core_fns (&solaris_core_fns); +} diff --git a/contrib/gdb/gdb/corefile.c b/contrib/gdb/gdb/corefile.c new file mode 100644 index 000000000000..a916bf8ac813 --- /dev/null +++ b/contrib/gdb/gdb/corefile.c @@ -0,0 +1,339 @@ +/* Core dump and executable file functions above target vector, for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include +#include +#include +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "gdbcmd.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" +#include "dis-asm.h" +#include "language.h" + +extern char registers[]; + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) PARAMS ((char *)) = NULL; + +/* Binary file diddling handle for the core file. */ + +bfd *core_bfd = NULL; + + +/* Backward compatability with old way of specifying core files. */ + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + struct target_ops *t; + + dont_repeat (); /* Either way, seems bogus. */ + + t = find_core_target (); + if (t != NULL) + if (!filename) + (t->to_detach) (filename, from_tty); + else + (t->to_open) (filename, from_tty); + else + error ("GDB can't read core files on this machine."); +} + + +/* Call this to specify the hook for exec_file_command to call back. + This is called from the x-window display code. */ + +void +specify_exec_file_hook (hook) + void (*hook) PARAMS ((char *)); +{ + 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 () +{ +#ifdef FIXME + if (exec_bfd) + bfd_tempclose (exec_bfd); +#endif +} + +void +reopen_exec_file () +{ +#ifdef FIXME + if (exec_bfd) + bfd_reopen (exec_bfd); +#endif +} + +/* If we have both a core file and an exec file, + print a warning if they don't go together. */ + +void +validate_files () +{ + if (exec_bfd && core_bfd) + { + if (!core_file_matches_executable_p (core_bfd, exec_bfd)) + warning ("core file may not match specified executable file."); + else if (bfd_get_mtime(exec_bfd) > bfd_get_mtime(core_bfd)) + warning ("exec file is newer than core file."); + } +} + +/* Return the name of the executable file as a string. + ERR nonzero means get error if there is none specified; + otherwise return 0 in that case. */ + +char * +get_exec_file (err) + int err; +{ + if (exec_bfd) return bfd_get_filename(exec_bfd); + if (!err) return NULL; + + error ("No executable file specified.\n\ +Use the \"file\" or \"exec-file\" command."); + return NULL; +} + + +/* Report a memory error with error(). */ + +void +memory_error (status, memaddr) + int status; + CORE_ADDR memaddr; +{ + if (status == EIO) + { + /* Actually, address between memaddr and memaddr + len + was out of bounds. */ + error_begin (); + printf_filtered ("Cannot access memory at address "); + print_address_numeric (memaddr, 1, gdb_stdout); + printf_filtered (".\n"); + return_to_top_level (RETURN_ERROR); + } + else + { + error_begin (); + printf_filtered ("Error accessing memory address "); + print_address_numeric (memaddr, 1, gdb_stdout); + printf_filtered (": %s.\n", + safe_strerror (status)); + return_to_top_level (RETURN_ERROR); + } +} + +/* Same as target_read_memory, but report an error if can't read. */ +void +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + status = target_read_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Like target_read_memory, but slightly different parameters. */ + +int +dis_asm_read_memory (memaddr, myaddr, len, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int len; + disassemble_info *info; +{ + return target_read_memory (memaddr, (char *) myaddr, len); +} + +/* Like memory_error with slightly different parameters. */ +void +dis_asm_memory_error (status, memaddr, info) + int status; + bfd_vma memaddr; + disassemble_info *info; +{ + memory_error (status, memaddr); +} + +/* Like print_address with slightly different parameters. */ +void +dis_asm_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + print_address (addr, info->stream); +} + +/* Same as target_write_memory, but report an error if can't write. */ +void +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int status; + + status = target_write_memory (memaddr, myaddr, len); + if (status != 0) + memory_error (status, memaddr); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +LONGEST +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char buf[sizeof (LONGEST)]; + + read_memory (memaddr, buf, len); + return extract_signed_integer (buf, len); +} + +unsigned LONGEST +read_memory_unsigned_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char buf[sizeof (unsigned LONGEST)]; + + read_memory (memaddr, buf, len); + return extract_unsigned_integer (buf, len); +} + +#if 0 +/* Enable after 4.12. It is not tested. */ + +/* Search code. Targets can just make this their search function, or + if the protocol has a less general search function, they can call this + in the cases it can't handle. */ +void +generic_search (len, data, mask, startaddr, increment, lorange, hirange + addr_found, data_found) + int len; + char *data; + char *mask; + CORE_ADDR startaddr; + int increment; + CORE_ADDR lorange; + CORE_ADDR hirange; + CORE_ADDR *addr_found; + char *data_found; +{ + int i; + CORE_ADDR curaddr = startaddr; + + while (curaddr >= lorange && curaddr < hirange) + { + read_memory (curaddr, data_found, len); + for (i = 0; i < len; ++i) + if ((data_found[i] & mask[i]) != data[i]) + goto try_again; + /* It matches. */ + *addr_found = curaddr; + return; + + try_again: + curaddr += increment; + } + *addr_found = (CORE_ADDR)0; + return; +} +#endif /* 0 */ + +/* The current default bfd target. Points to storage allocated for + gnutarget_string. */ +char *gnutarget; + +/* Same thing, except it is "auto" not NULL for the default case. */ +static char *gnutarget_string; + +static void set_gnutarget_command + PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_gnutarget_command (ignore, from_tty, c) + char *ignore; + int from_tty; + struct cmd_list_element *c; +{ + if (STREQ (gnutarget_string, "auto")) + gnutarget = NULL; + else + gnutarget = gnutarget_string; +} + +/* Set the gnutarget. */ +void +set_gnutarget (newtarget) + char *newtarget; +{ + if (gnutarget_string != NULL) + free (gnutarget_string); + gnutarget_string = savestring (newtarget, strlen (newtarget)); + set_gnutarget_command (NULL, 0, NULL); +} + +void +_initialize_core() +{ + struct cmd_list_element *c; + c = add_cmd ("core-file", class_files, core_file_command, + "Use FILE as core dump for examining memory and registers.\n\ +No arg means have no core file. This command has been superseded by the\n\ +`target core' and `detach' commands.", &cmdlist); + c->completer = filename_completer; + + c = add_set_cmd ("gnutarget", class_files, var_string_noescape, + (char *) &gnutarget_string, + "Set the current BFD target.\n\ +Use `set gnutarget auto' to specify automatic detection.", + &setlist); + c->function.sfunc = set_gnutarget_command; + add_show_from_set (c, &showlist); + + if (getenv ("GNUTARGET")) + set_gnutarget (getenv ("GNUTARGET")); + else + set_gnutarget ("auto"); +} diff --git a/contrib/gdb/gdb/corelow.c b/contrib/gdb/gdb/corelow.c new file mode 100644 index 000000000000..48bc1843f7b0 --- /dev/null +++ b/contrib/gdb/gdb/corelow.c @@ -0,0 +1,419 @@ +/* Core dump and executable file functions below target vector, for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include +#include +#include +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" +#include "thread.h" + +/* List of all available core_fns. On gdb startup, each core file register + reader calls add_core_fns() to register information on each core format it + is prepared to read. */ + +static struct core_fns *core_file_fns = NULL; + +static void core_files_info PARAMS ((struct target_ops *)); + +#ifdef SOLIB_ADD +static int solib_add_stub PARAMS ((char *)); +#endif + +static void core_open PARAMS ((char *, int)); + +static void core_detach PARAMS ((char *, int)); + +static void core_close PARAMS ((int)); + +static void get_core_registers PARAMS ((int)); + +/* Link a new core_fns into the global core_file_fns list. Called on gdb + startup by the _initialize routine in each core file register reader, to + register information about each format the the reader is prepared to + handle. */ + +void +add_core_fns (cf) + struct core_fns *cf; +{ + cf -> next = core_file_fns; + core_file_fns = cf; +} + + +/* Discard all vestiges of any previous core file and mark data and stack + spaces as empty. */ + +/* ARGSUSED */ +static void +core_close (quitting) + int quitting; +{ + char *name; + + inferior_pid = 0; /* Avoid confusion from thread stuff */ + + if (core_bfd) + { + name = bfd_get_filename (core_bfd); + if (!bfd_close (core_bfd)) + warning ("cannot close \"%s\": %s", + name, bfd_errmsg (bfd_get_error ())); + free (name); + core_bfd = NULL; +#ifdef CLEAR_SOLIB + CLEAR_SOLIB (); +#endif + if (core_ops.to_sections) + { + free ((PTR)core_ops.to_sections); + core_ops.to_sections = NULL; + core_ops.to_sections_end = NULL; + } + } +} + +#ifdef SOLIB_ADD +/* Stub function for catch_errors around shared library hacking. FROM_TTYP + is really an int * which points to from_tty. */ + +static int +solib_add_stub (from_ttyp) + char *from_ttyp; +{ + SOLIB_ADD (NULL, *(int *)from_ttyp, ¤t_target); + re_enable_breakpoints_in_shlibs (); + return 0; +} +#endif /* SOLIB_ADD */ + +/* Look for sections whose names start with `.reg/' so that we can extract the + list of threads in a core file. */ + +static void +add_to_thread_list (abfd, asect, reg_sect_arg) + bfd *abfd; + asection *asect; + PTR reg_sect_arg; +{ + int thread_id; + asection *reg_sect = (asection *) reg_sect_arg; + + if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0) + return; + + thread_id = atoi (bfd_section_name (abfd, asect) + 5); + + add_thread (thread_id); + +/* Warning, Will Robinson, looking at BFD private data! */ + + if (asect->filepos == reg_sect->filepos) /* Did we find .reg? */ + inferior_pid = thread_id; /* Yes, make it current */ +} + +/* This routine opens and sets up the core file bfd. */ + +static void +core_open (filename, from_tty) + char *filename; + int from_tty; +{ + const char *p; + int siggy; + struct cleanup *old_chain; + char *temp; + bfd *temp_bfd; + int ontop; + int scratch_chan; + + target_preopen (from_tty); + if (!filename) + { + error (core_bfd ? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') + { + temp = concat (current_directory, "/", filename, NULL); + free (filename); + filename = temp; + } + + old_chain = make_cleanup (free, filename); + + scratch_chan = open (filename, write_files ? O_RDWR : O_RDONLY, 0); + if (scratch_chan < 0) + perror_with_name (filename); + + temp_bfd = bfd_fdopenr (filename, gnutarget, scratch_chan); + if (temp_bfd == NULL) + perror_with_name (filename); + + if (!bfd_check_format (temp_bfd, bfd_core)) + { + /* Do it after the err msg */ + /* 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); + error ("\"%s\" is not a core dump: %s", + filename, bfd_errmsg (bfd_get_error ())); + } + + /* Looks semi-reasonable. Toss the old core file and work on the new. */ + + discard_cleanups (old_chain); /* Don't free filename any more */ + unpush_target (&core_ops); + core_bfd = temp_bfd; + old_chain = make_cleanup (core_close, core_bfd); + + validate_files (); + + /* Find the data section */ + if (build_section_table (core_bfd, &core_ops.to_sections, + &core_ops.to_sections_end)) + error ("\"%s\": Can't find sections: %s", + bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ())); + + ontop = !push_target (&core_ops); + discard_cleanups (old_chain); + + p = bfd_core_file_failing_command (core_bfd); + if (p) + printf_filtered ("Core was generated by `%s'.\n", p); + + siggy = bfd_core_file_failing_signal (core_bfd); + if (siggy > 0) + printf_filtered ("Program terminated with signal %d, %s.\n", siggy, + safe_strsignal (siggy)); + + /* Build up thread list from BFD sections. */ + + init_thread_list (); + bfd_map_over_sections (core_bfd, add_to_thread_list, + bfd_get_section_by_name (core_bfd, ".reg")); + + if (ontop) + { + /* Fetch all registers from core file. */ + target_fetch_registers (-1); + + /* Add symbols and section mappings for any shared libraries. */ +#ifdef SOLIB_ADD + catch_errors (solib_add_stub, &from_tty, (char *)0, + RETURN_MASK_ALL); +#endif + + /* Now, set up the frame cache, and print the top of stack. */ + flush_cached_frames (); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, selected_frame_level, 1); + } + else + { + warning ( +"you won't be able to access this core file until you terminate\n\ +your %s; do ``info files''", target_longname); + } +} + +static void +core_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Too many arguments"); + unpush_target (&core_ops); + reinit_frame_cache (); + if (from_tty) + printf_filtered ("No core file now.\n"); +} + +/* Get the registers out of a core file. This is the machine- + independent part. Fetch_core_registers is the machine-dependent + part, typically implemented in the xm-file for each architecture. */ + +/* We just get all the registers, so we don't use regno. */ + +/* ARGSUSED */ +static void +get_core_registers (regno) + int regno; +{ + sec_ptr reg_sec; + unsigned size; + char *the_regs; + char secname[10]; + enum bfd_flavour our_flavour = bfd_get_flavour (core_bfd); + struct core_fns *cf; + + if (core_file_fns == NULL) + { + fprintf_filtered (gdb_stderr, + "Can't fetch registers from this type of core file\n"); + return; + } + + /* Thread support. If inferior_pid is non-zero, then we have found a core + file with threads (or multiple processes). In that case, we need to + use the appropriate register section, else we just use `.reg'. */ + + /* XXX - same thing needs to be done for floating-point (.reg2) sections. */ + + if (inferior_pid) + sprintf (secname, ".reg/%d", inferior_pid); + else + strcpy (secname, ".reg"); + + reg_sec = bfd_get_section_by_name (core_bfd, secname); + if (!reg_sec) + goto cant; + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + /* Look for the core functions that match this flavor. Default to the + first one if nothing matches. */ + for (cf = core_file_fns; cf != NULL; cf = cf -> next) + { + if (our_flavour == cf -> core_flavour) + { + break; + } + } + if (cf == NULL) + { + cf = core_file_fns; + } + if (cf != NULL && + bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, size) && + cf -> core_read_registers != NULL) + { + (cf -> core_read_registers (the_regs, size, 0, + (unsigned) bfd_section_vma (abfd,reg_sec))); + } + else + { +cant: + fprintf_filtered (gdb_stderr, + "Couldn't fetch registers from core file: %s\n", + bfd_errmsg (bfd_get_error ())); + } + + /* Now do it again for the float registers, if they exist. */ + reg_sec = bfd_get_section_by_name (core_bfd, ".reg2"); + if (reg_sec) + { + size = bfd_section_size (core_bfd, reg_sec); + the_regs = alloca (size); + if (cf != NULL && + bfd_get_section_contents (core_bfd, reg_sec, the_regs, (file_ptr)0, size) && + cf -> core_read_registers != NULL) + { + (cf -> core_read_registers (the_regs, size, 2, + (unsigned) bfd_section_vma (abfd,reg_sec))); + } + else + { + fprintf_filtered (gdb_stderr, + "Couldn't fetch register set 2 from core file: %s\n", + bfd_errmsg (bfd_get_error ())); + } + } + registers_fetched (); +} + +static void +core_files_info (t) + struct target_ops *t; +{ + print_section_info (t, core_bfd); +} + +/* If mourn is being called in all the right places, this could be say + `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ + +static int +ignore (addr, contents) + CORE_ADDR addr; + char *contents; +{ + return 0; +} + +struct target_ops core_ops = { + "core", /* to_shortname */ + "Local core dump file", /* to_longname */ + "Use a core file as a target. Specify the filename of the core file.", /* to_doc */ + core_open, /* to_open */ + core_close, /* to_close */ + find_default_attach, /* to_attach */ + core_detach, /* to_detach */ + 0, /* to_resume */ + 0, /* to_wait */ + get_core_registers, /* to_fetch_registers */ + 0, /* to_store_registers */ + 0, /* to_prepare_to_store */ + xfer_memory, /* to_xfer_memory */ + core_files_info, /* to_files_info */ + ignore, /* to_insert_breakpoint */ + ignore, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + 0, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + find_default_create_inferior, /* to_create_inferior */ + 0, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + core_stratum, /* to_stratum */ + 0, /* to_next */ + 0, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 0, /* to_has_execution */ + 0, /* to_sections */ + 0, /* to_sections_end */ + OPS_MAGIC, /* to_magic */ +}; + +void +_initialize_corelow() +{ + add_target (&core_ops); +} diff --git a/contrib/gdb/gdb/cp-valprint.c b/contrib/gdb/gdb/cp-valprint.c new file mode 100644 index 000000000000..48f490518c6c --- /dev/null +++ b/contrib/gdb/gdb/cp-valprint.c @@ -0,0 +1,600 @@ +/* Support for printing C++ values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "command.h" +#include "gdbcmd.h" +#include "demangle.h" +#include "annotate.h" +#include "gdb_string.h" +#include "c-lang.h" + +int vtblprint; /* Controls printing of vtbl's */ +int objectprint; /* Controls looking up an object's derived type + using what we find in its vtables. */ +static int static_field_print; /* Controls printing of static fields. */ + +static struct obstack dont_print_vb_obstack; +static struct obstack dont_print_statmem_obstack; + +static void +cp_print_static_field PARAMS ((struct type *, value_ptr, GDB_FILE *, int, int, + enum val_prettyprint)); + +static void +cp_print_value PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, + int, int, enum val_prettyprint, struct type **)); + +void +cp_print_class_method (valaddr, type, stream) + char *valaddr; + struct type *type; + GDB_FILE *stream; +{ + struct type *domain; + struct fn_field *f = NULL; + int j = 0; + int len2; + int offset; + char *kind = ""; + CORE_ADDR addr; + struct symbol *sym; + unsigned len; + unsigned int i; + struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); + + domain = TYPE_DOMAIN_TYPE (target_type); + if (domain == (struct type *)NULL) + { + fprintf_filtered (stream, ""); + return; + } + addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr); + if (METHOD_PTR_IS_VIRTUAL (addr)) + { + offset = METHOD_PTR_TO_VOFFSET (addr); + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + for (j = 0; j < len2; j++) + { + QUIT; + if (TYPE_FN_FIELD_VOFFSET (f, j) == offset) + { + kind = "virtual "; + goto common; + } + } + } + } + else + { + sym = find_pc_function (addr); + if (sym == 0) + { + error ("invalid pointer to member function"); + } + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + for (j = 0; j < len2; j++) + { + QUIT; + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (domain, i, j); + if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))) + { + goto common; + } + } + } + } + common: + if (i < len) + { + fprintf_filtered (stream, "&"); + c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0); + fprintf_unfiltered (stream, kind); + if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' + && is_cplus_marker (TYPE_FN_FIELD_PHYSNAME (f, j)[1])) + { + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, "~", + TYPE_FN_FIELDLIST_NAME (domain, i), + 0, stream); + } + else + { + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "", + TYPE_FN_FIELDLIST_NAME (domain, i), + 0, stream); + } + } + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") %d", (int) addr >> 3); + } +} + +/* This was what it was for gcc 2.4.5 and earlier. */ +static const char vtbl_ptr_name_old[] = + { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 }; +/* It was changed to this after 2.4.5. */ +const char vtbl_ptr_name[] = + { '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 }; + +/* Return truth value for assertion that TYPE is of the type + "pointer to virtual function". */ + +int +cp_is_vtbl_ptr_type(type) + struct type *type; +{ + char *typename = type_name_no_tag (type); + + return (typename != NULL + && (STREQ (typename, vtbl_ptr_name) + || STREQ (typename, vtbl_ptr_name_old))); +} + +/* Return truth value for the assertion that TYPE is of the type + "pointer to virtual function table". */ + +int +cp_is_vtbl_member(type) + struct type *type; +{ + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + type = TYPE_TARGET_TYPE (type); + if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + type = TYPE_TARGET_TYPE (type); + if (TYPE_CODE (type) == TYPE_CODE_STRUCT /* if not using thunks */ + || TYPE_CODE (type) == TYPE_CODE_PTR) /* if using thunks */ + { + /* Virtual functions tables are full of pointers + to virtual functions. */ + return cp_is_vtbl_ptr_type (type); + } + } + } + return 0; +} + +/* Mutually recursive subroutines of cp_print_value and c_val_print to + print out a structure's fields: cp_print_value_fields and cp_print_value. + + TYPE, VALADDR, ADDRESS, STREAM, RECURSE, and PRETTY have the + same meanings as in cp_print_value and c_val_print. + + DONT_PRINT is an array of baseclass types that we + should not print, or zero if called from top level. */ + +void +cp_print_value_fields (type, valaddr, address, stream, format, recurse, pretty, + dont_print_vb, dont_print_statmem) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print_vb; + int dont_print_statmem; +{ + int i, len, n_baseclasses; + struct obstack tmp_obstack; + char *last_dont_print = obstack_next_free (&dont_print_statmem_obstack); + + CHECK_TYPEDEF (type); + + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + n_baseclasses = TYPE_N_BASECLASSES (type); + + /* Print out baseclasses such that we don't print + duplicates of virtual baseclasses. */ + if (n_baseclasses > 0) + cp_print_value (type, valaddr, address, stream, + format, recurse+1, pretty, dont_print_vb); + + if (!len && n_baseclasses == 1) + fprintf_filtered (stream, ""); + else + { + extern int inspect_it; + int fields_seen = 0; + + if (dont_print_statmem == 0) + { + /* If we're at top level, carve out a completely fresh + chunk of the obstack and use that until this particular + invocation returns. */ + tmp_obstack = dont_print_statmem_obstack; + obstack_finish (&dont_print_statmem_obstack); + } + + for (i = n_baseclasses; i < len; i++) + { + /* If requested, skip printing of static fields. */ + if (!static_field_print && TYPE_FIELD_STATIC (type, i)) + continue; + if (fields_seen) + fprintf_filtered (stream, ", "); + else if (n_baseclasses > 0) + { + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + fputs_filtered ("members of ", stream); + fputs_filtered (type_name_no_tag (type), stream); + fputs_filtered (": ", stream); + } + } + fields_seen = 1; + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + wrap_here (n_spaces (2 + 2 * recurse)); + } + if (inspect_it) + { + if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) + fputs_filtered ("\"( ptr \"", stream); + else + fputs_filtered ("\"( nodef \"", stream); + if (TYPE_FIELD_STATIC (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 (TYPE_FIELD_STATIC (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 (!TYPE_FIELD_STATIC (type, i) && TYPE_FIELD_PACKED (type, i)) + { + value_ptr v; + + /* Bitfields require special handling, especially due to byte + order problems. */ + if (TYPE_FIELD_IGNORE (type, i)) + { + fputs_filtered ("", stream); + } + else + { + v = value_from_longest (TYPE_FIELD_TYPE (type, i), + unpack_field_as_long (type, valaddr, i)); + + val_print (TYPE_FIELD_TYPE(type, i), VALUE_CONTENTS (v), 0, + stream, format, 0, recurse + 1, pretty); + } + } + else + { + if (TYPE_FIELD_IGNORE (type, i)) + { + fputs_filtered ("", stream); + } + else if (TYPE_FIELD_STATIC (type, i)) + { + value_ptr v; + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (sym == NULL) + fputs_filtered ("", stream); + else + { + v = value_at (TYPE_FIELD_TYPE (type, i), + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + cp_print_static_field (TYPE_FIELD_TYPE (type, i), v, + stream, format, recurse + 1, + pretty); + } + } + else + { + val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, 0, recurse + 1, pretty); + } + } + annotate_field_end (); + } + + if (dont_print_statmem == 0) + { + /* Free the space used to deal with the printing + of the members from top level. */ + obstack_free (&dont_print_statmem_obstack, last_dont_print); + dont_print_statmem_obstack = tmp_obstack; + } + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + } + fprintf_filtered (stream, "}"); +} + +/* Special val_print routine to avoid printing multiple copies of virtual + baseclasses. */ + +static void +cp_print_value (type, valaddr, address, stream, format, recurse, pretty, + dont_print_vb) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; + struct type **dont_print_vb; +{ + struct obstack tmp_obstack; + struct type **last_dont_print + = (struct type **)obstack_next_free (&dont_print_vb_obstack); + int i, n_baseclasses = TYPE_N_BASECLASSES (type); + + if (dont_print_vb == 0) + { + /* If we're at top level, carve out a completely fresh + chunk of the obstack and use that until this particular + invocation returns. */ + tmp_obstack = dont_print_vb_obstack; + /* Bump up the high-water mark. Now alpha is omega. */ + obstack_finish (&dont_print_vb_obstack); + } + + for (i = 0; i < n_baseclasses; i++) + { + int boffset; + struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); + char *basename = TYPE_NAME (baseclass); + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + struct type **first_dont_print + = (struct type **)obstack_base (&dont_print_vb_obstack); + + int j = (struct type **)obstack_next_free (&dont_print_vb_obstack) + - first_dont_print; + + while (--j >= 0) + if (baseclass == first_dont_print[j]) + goto flush_it; + + obstack_ptr_grow (&dont_print_vb_obstack, baseclass); + } + + boffset = baseclass_offset (type, i , valaddr, address); + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("<", stream); + /* Not sure what the best notation is in the case where there is no + baseclass name. */ + fputs_filtered (basename ? basename : "", stream); + fputs_filtered ("> = ", stream); + if (boffset == -1) + fprintf_filtered (stream, ""); + else + cp_print_value_fields (baseclass, valaddr + boffset, address + boffset, + stream, format, recurse, pretty, + (struct type **) obstack_base (&dont_print_vb_obstack), + 0); + fputs_filtered (", ", stream); + + flush_it: + ; + } + + if (dont_print_vb == 0) + { + /* Free the space used to deal with the printing + of this type from top level. */ + obstack_free (&dont_print_vb_obstack, last_dont_print); + /* Reset watermark so that we can continue protecting + ourselves from whatever we were protecting ourselves. */ + dont_print_vb_obstack = tmp_obstack; + } +} + +/* Print value of a static member. + To avoid infinite recursion when printing a class that contains + a static instance of the class, we keep the addresses of all printed + static member classes in an obstack and refuse to print them more + than once. + + VAL contains the value to print, TYPE, STREAM, RECURSE, and PRETTY + have the same meanings as in c_val_print. */ + +static void +cp_print_static_field (type, val, stream, format, recurse, pretty) + struct type *type; + value_ptr val; + GDB_FILE *stream; + int format; + int recurse; + enum val_prettyprint pretty; +{ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + CORE_ADDR *first_dont_print; + int i; + + first_dont_print + = (CORE_ADDR *)obstack_base (&dont_print_statmem_obstack); + i = (CORE_ADDR *)obstack_next_free (&dont_print_statmem_obstack) + - first_dont_print; + + while (--i >= 0) + { + if (VALUE_ADDRESS (val) == first_dont_print[i]) + { + fputs_filtered ("", + stream); + return; + } + } + + obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val), + sizeof (CORE_ADDR)); + + CHECK_TYPEDEF (type); + cp_print_value_fields (type, VALUE_CONTENTS (val), VALUE_ADDRESS (val), + stream, format, recurse, pretty, NULL, 1); + return; + } + val_print (type, VALUE_CONTENTS (val), VALUE_ADDRESS (val), + stream, format, 0, recurse, pretty); +} + +void +cp_print_class_member (valaddr, domain, stream, prefix) + char *valaddr; + struct type *domain; + GDB_FILE *stream; + char *prefix; +{ + + /* VAL is a byte offset into the structure type DOMAIN. + Find the name of the field for that offset and + print it. */ + int extra = 0; + int bits = 0; + register unsigned int i; + unsigned len = TYPE_NFIELDS (domain); + /* @@ Make VAL into bit offset */ + LONGEST val = unpack_long (builtin_type_int, valaddr) << 3; + for (i = TYPE_N_BASECLASSES (domain); i < len; i++) + { + int bitpos = TYPE_FIELD_BITPOS (domain, i); + QUIT; + if (val == bitpos) + break; + if (val < bitpos && i != 0) + { + /* Somehow pointing into a field. */ + i -= 1; + extra = (val - TYPE_FIELD_BITPOS (domain, i)); + if (extra & 0x7) + bits = 1; + else + extra >>= 3; + break; + } + } + if (i < len) + { + char *name; + fprintf_filtered (stream, prefix); + name = type_name_no_tag (domain); + if (name) + fputs_filtered (name, stream); + else + c_type_print_base (domain, stream, 0, 0); + fprintf_filtered (stream, "::"); + fputs_filtered (TYPE_FIELD_NAME (domain, i), stream); + if (extra) + fprintf_filtered (stream, " + %d bytes", extra); + if (bits) + fprintf_filtered (stream, " (offset in bits)"); + } + else + fprintf_filtered (stream, "%d", val >> 3); +} + +void +_initialize_cp_valprint () +{ + add_show_from_set + (add_set_cmd ("static-members", class_support, var_boolean, + (char *)&static_field_print, + "Set printing of C++ static members.", + &setprintlist), + &showprintlist); + /* Turn on printing of static fields. */ + static_field_print = 1; + + add_show_from_set + (add_set_cmd ("vtbl", class_support, var_boolean, (char *)&vtblprint, + "Set printing of C++ virtual function tables.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("object", class_support, var_boolean, (char *)&objectprint, + "Set printing of object's derived type based on vtable info.", + &setprintlist), + &showprintlist); + + /* Give people the defaults which they are used to. */ + objectprint = 0; + vtblprint = 0; + obstack_begin (&dont_print_vb_obstack, 32 * sizeof (struct type *)); + obstack_specify_allocation (&dont_print_statmem_obstack, + 32 * sizeof (CORE_ADDR), sizeof (CORE_ADDR), + xmalloc, free); +} diff --git a/contrib/gdb/gdb/cpu32bug-rom.c b/contrib/gdb/gdb/cpu32bug-rom.c new file mode 100644 index 000000000000..43f76f62a0dc --- /dev/null +++ b/contrib/gdb/gdb/cpu32bug-rom.c @@ -0,0 +1,171 @@ +/* Remote debugging interface for CPU32Bug Rom monitor for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + + Written by Stu Grossman of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void cpu32bug_open PARAMS ((char *args, int from_tty)); + +static void +cpu32bug_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno; + + if (regnamelen != 2) + return; + + switch (regname[0]) + { + case 'S': + if (regname[1] != 'R') + return; + regno = PS_REGNUM; + break; + case 'P': + if (regname[1] != 'C') + return; + regno = PC_REGNUM; + break; + case 'D': + if (regname[1] < '0' || regname[1] > '7') + return; + regno = regname[1] - '0' + D0_REGNUM; + break; + case 'A': + if (regname[1] < '0' || regname[1] > '7') + return; + regno = regname[1] - '0' + A0_REGNUM; + break; + default: + return; + } + + monitor_supply_register (regno, val); +} + +/* + * This array of registers needs to match the indexes used by GDB. The + * whole reason this exists is because the various ROM monitors use + * different names than GDB does, and don't support all the + * registers either. So, typing "info reg sp" becomes an "A7". + */ + +static char *cpu32bug_regnames[NUM_REGS] = +{ + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", + "SR", "PC", +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops cpu32bug_ops; + +static char *cpu32bug_inits[] = {"\r", NULL}; + +static struct monitor_ops cpu32bug_cmds = +{ + MO_CLR_BREAK_USES_ADDR, + cpu32bug_inits, /* Init strings */ + "g\r", /* continue command */ + "t\r", /* single step */ + NULL, /* interrupt command */ + "br %x\r", /* set a breakpoint */ + "nobr %x\r", /* clear a breakpoint */ + "nobr\r", /* clear all breakpoints */ + "bf %x:%x %x;b\r", /* fill (start count val) */ + { + "ms %x %02x\r", /* setmem.cmdb (addr, value) */ + "ms %x %04x\r", /* setmem.cmdw (addr, value) */ + "ms %x %08x\r", /* setmem.cmdl (addr, value) */ + NULL, /* setmem.cmdll (addr, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL, /* setreg.term_cmd */ + }, + { + "md %x:%x;b\r", /* getmem.cmdb (addr, len) */ + "md %x:%x;b\r", /* getmem.cmdw (addr, len) */ + "md %x:%x;b\r", /* getmem.cmdl (addr, len) */ + NULL, /* getmem.cmdll (addr, len) */ + " ", /* getmem.resp_delim */ + NULL, /* getmem.term */ + NULL, /* getmem.term_cmd */ + }, + { + "rs %s %x\r", /* setreg.cmd (name, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL /* setreg.term_cmd */ + }, + { + "rs %s\r", /* getreg.cmd (name) */ + "=", /* getreg.resp_delim */ + NULL, /* getreg.term */ + NULL /* getreg.term_cmd */ + }, + "rd\r", /* dump_registers */ + "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)", /* register_pattern */ + cpu32bug_supply_register, /* supply_register */ + NULL, /* load_routine (defaults to SRECs) */ + "lo\r", /* download command */ + "lo\r\n", /* load response */ + "CPU32Bug>", /* monitor command prompt */ + "\r", /* end-of-line terminator */ + NULL, /* optional command terminator */ + &cpu32bug_ops, /* target operations */ + SERIAL_1_STOPBITS, /* number of stop bits */ + cpu32bug_regnames, /* registers names */ + MONITOR_OPS_MAGIC /* magic */ + }; + +static void +cpu32bug_open(args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &cpu32bug_cmds, from_tty); +} + +void +_initialize_cpu32bug_rom () +{ + init_monitor_ops (&cpu32bug_ops); + + cpu32bug_ops.to_shortname = "cpu32bug"; + cpu32bug_ops.to_longname = "CPU32Bug monitor"; + cpu32bug_ops.to_doc = "Debug via the CPU32Bug monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + cpu32bug_ops.to_open = cpu32bug_open; + + add_target (&cpu32bug_ops); +} diff --git a/contrib/gdb/gdb/cxux-nat.c b/contrib/gdb/gdb/cxux-nat.c new file mode 100644 index 000000000000..2ed1430ea4bf --- /dev/null +++ b/contrib/gdb/gdb/cxux-nat.c @@ -0,0 +1,523 @@ +/* Native support for Motorola 88k running Harris CX/UX. + Copyright 1988, 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include "gdbcore.h" +#include + +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "symtab.h" + +#ifndef USER /* added to support BCS ptrace_user */ +#define USER ptrace_user +#endif +#include +#include +#include +#include "gdb_stat.h" + +#include "symtab.h" +#include "setjmp.h" +#include "value.h" + +#include + +/* CX/UX provides them already, but as word offsets instead of char offsets */ +#define SXIP_OFFSET (PT_SXIP * 4) +#define SNIP_OFFSET (PT_SNIP * 4) +#define SFIP_OFFSET (PT_SFIP * 4) +#define PSR_OFFSET (PT_PSR * sizeof(int)) +#define FPSR_OFFSET (PT_FPSR * sizeof(int)) +#define FPCR_OFFSET (PT_FPCR * sizeof(int)) + +#define XREGADDR(r) (((char *)&u.pt_x0-(char *)&u) + \ + ((r)-X0_REGNUM)*sizeof(X_REGISTER_RAW_TYPE)) + +extern int have_symbol_file_p(); + +extern jmp_buf stack_jmp; + +extern int errno; +extern char registers[REGISTER_BYTES]; + +void +fetch_inferior_registers (regno) + int regno; /* Original value discarded */ +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct USER u; + unsigned int offset; + + offset = (char *) &u.pt_r0 - (char *) &u; + regaddr = offset; /* byte offset to r0;*/ + +/* offset = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) - KERNEL_U_ADDR; */ + for (regno = 0; regno < PC_REGNUM; regno++) + { + /*regaddr = register_addr (regno, offset);*/ + /* 88k enhancement */ + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } + /* now load up registers 32-37; special pc registers */ + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) PSR_OFFSET,0); + supply_register (PSR_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) FPSR_OFFSET,0); + supply_register (FPSR_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) FPCR_OFFSET,0); + supply_register (FPCR_REGNUM, buf); + *(int *) &buf[0] = ptrace (3,inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET ,0); + supply_register (SXIP_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET,0); + supply_register (SNIP_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET,0); + supply_register (SFIP_REGNUM, buf); + + if (target_is_m88110) + { + for (regaddr = XREGADDR(X0_REGNUM), regno = X0_REGNUM; + regno < NUM_REGS; + regno++, regaddr += 16) + { + X_REGISTER_RAW_TYPE xval; + + *(int *) &xval.w1 = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + *(int *) &xval.w2 = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) (regaddr+4), 0); + *(int *) &xval.w3 = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) (regaddr+8), 0); + *(int *) &xval.w4 = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) (regaddr+12), 0); + supply_register(regno, (void *)&xval); + } + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + struct USER u; + + unsigned int offset = (char *) &u.pt_r0 - (char *) &u; + + regaddr = offset; + + /* Don't try to deal with EXIP_REGNUM or ENIP_REGNUM, because I think either + svr3 doesn't run on an 88110, or the kernel isolates the different (not + completely sure this is true, but seems to be. */ + if (regno >= 0) + { + /* regaddr = register_addr (regno, offset); */ + if (regno < PC_REGNUM) + { + regaddr = offset + regno * sizeof (int); + errno = 0; + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else if (regno == PSR_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) PSR_OFFSET, read_register(regno)); + else if (regno == FPSR_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) FPSR_OFFSET, read_register(regno)); + else if (regno == FPCR_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) FPCR_OFFSET, read_register(regno)); + else if (regno == SXIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET, read_register(regno)); + else if (regno == SNIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET, read_register(regno)); + else if (regno == SFIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET, read_register(regno)); + else if (target_is_m88110 && regno < NUM_REGS) + { + X_REGISTER_RAW_TYPE xval; + + read_register_bytes(REGISTER_BYTE(regno), (char *)&xval, + sizeof(X_REGISTER_RAW_TYPE)); + regaddr = XREGADDR(regno); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, xval.w1); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+4, xval.w2); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+8, xval.w3); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+12, xval.w4); + } + else + printf_unfiltered ("Bad register number for store_inferior routine\n"); + } + else + { + for (regno = 0; regno < PC_REGNUM; regno++) + { + /* regaddr = register_addr (regno, offset); */ + errno = 0; + regaddr = offset + regno * sizeof (int); + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) PSR_OFFSET, read_register(regno)); + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) FPSR_OFFSET,read_register(regno)); + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) FPCR_OFFSET,read_register(regno)); + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET,read_register(SXIP_REGNUM)); + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET,read_register(SNIP_REGNUM)); + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET,read_register(SFIP_REGNUM)); + if (target_is_m88110) + { + for (regno = X0_REGNUM; regno < NUM_REGS; regno++) + { + X_REGISTER_RAW_TYPE xval; + + read_register_bytes(REGISTER_BYTE(regno), (char *)&xval, + sizeof(X_REGISTER_RAW_TYPE)); + regaddr = XREGADDR(regno); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, xval.w1); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+4), xval.w2); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+8), xval.w3); + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+12), xval.w4); + } + } + } +} + +/* blockend is the address of the end of the user structure */ + +m88k_register_u_addr (blockend, regnum) + int blockend, regnum; +{ + struct USER u; + int ustart = blockend - sizeof (struct USER); + + if (regnum < PSR_REGNUM) + return (ustart + ((int) &u.pt_r0 - (int) &u) + + REGISTER_SIZE * regnum); + else if (regnum == PSR_REGNUM) + return (ustart + ((int) &u.pt_psr) - (int) &u); + else if (regnum == FPSR_REGNUM) + return (ustart + ((int) &u.pt_fpsr) - (int) &u); + else if (regnum == FPCR_REGNUM) + return (ustart + ((int) &u.pt_fpcr) - (int) &u); + else if (regnum == SXIP_REGNUM) + return (ustart + SXIP_OFFSET); + else if (regnum == SNIP_REGNUM) + return (ustart + SNIP_OFFSET); + else if (regnum == SFIP_REGNUM) + return (ustart + SFIP_OFFSET); + else if (target_is_m88110) + return (ustart + ((int) &u.pt_x0 - (int) &u) + /* Must be X register */ + sizeof(u.pt_x0) * (regnum - X0_REGNUM)); + else + return (blockend + REGISTER_SIZE * regnum); +} + +#ifdef USE_PROC_FS + +#include + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + + for (regi=0; regi <= SP_REGNUM; regi++) + supply_register (regi, (char *) (regp + regi)); + + supply_register (SXIP_REGNUM, (char *) (regp + R_XIP)); + supply_register (SNIP_REGNUM, (char *) (regp + R_NIP)); + supply_register (SFIP_REGNUM, (char *) (regp + R_FIP)); + supply_register (PSR_REGNUM, (char *) (regp + R_PSR)); + supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR)); + supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR)); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register greg_t *regp = (greg_t *) gregsetp; + extern char registers[]; + + for (regi = 0 ; regi <= R_R31 ; regi++) + if ((regno == -1) || (regno == regi)) + *(regp + regi) = *(int *) ®isters[REGISTER_BYTE(regi)]; + + if ((regno == -1) || (regno == SXIP_REGNUM)) + *(regp + R_XIP) = *(int *) ®isters[REGISTER_BYTE(SXIP_REGNUM)]; + if ((regno == -1) || (regno == SNIP_REGNUM)) + *(regp + R_NIP) = *(int *) ®isters[REGISTER_BYTE(SNIP_REGNUM)]; + if ((regno == -1) || (regno == SFIP_REGNUM)) + *(regp + R_FIP) = *(int *) ®isters[REGISTER_BYTE(SFIP_REGNUM)]; + if ((regno == -1) || (regno == PSR_REGNUM)) + *(regp + R_PSR) = *(int *) ®isters[REGISTER_BYTE(PSR_REGNUM)]; + if ((regno == -1) || (regno == FPSR_REGNUM)) + *(regp + R_FPSR) = *(int *) ®isters[REGISTER_BYTE(FPSR_REGNUM)]; + if ((regno == -1) || (regno == FPCR_REGNUM)) + *(regp + R_FPCR) = *(int *) ®isters[REGISTER_BYTE(FPCR_REGNUM)]; +} + +#endif /* USE_PROC_FS */ + +/* This support adds the equivalent of adb's % command. When + the `add-shared-symbol-files' command is given, this routine scans + the dynamic linker's link map and reads the minimal symbols + from each shared object file listed in the map. */ + +struct link_map { + unsigned long l_addr; /* address at which object is mapped */ + char *l_name; /* full name of loaded object */ + void *l_ld; /* dynamic structure of object */ + struct link_map *l_next; /* next link object */ + struct link_map *l_prev; /* previous link object */ +}; + +#define LINKS_MAP_POINTER "_ld_tail" +#define LIBC_FILE "/usr/lib/libc.so.1" +#define SHARED_OFFSET 0xf0001000 + +#ifndef PATH_MAX +#define PATH_MAX 1023 /* maximum size of path name on OS */ +#endif + +void +add_shared_symbol_files () +{ + void *desc; + struct link_map *ld_map, *lm, lms; + struct minimal_symbol *minsym; + struct objfile *objfile; + char *path_name; + + if (! inferior_pid) + { + warning ("The program has not yet been started."); + return; + } + + objfile = symbol_file_add (LIBC_FILE, 0, 0, 0, 0, 1); + minsym = lookup_minimal_symbol (LINKS_MAP_POINTER, objfile); + + ld_map = (struct link_map *) + read_memory_integer (((int)SYMBOL_VALUE_ADDRESS(minsym) + SHARED_OFFSET), 4); + lm = ld_map; + while (lm) + { + int local_errno = 0; + + read_memory ((CORE_ADDR)lm, (char*)&lms, sizeof (struct link_map)); + if (lms.l_name) + { + if (target_read_string ((CORE_ADDR)lms.l_name, &path_name, + PATH_MAX, &local_errno)) + { + symbol_file_add (path_name, 1, lms.l_addr, 0, 0, 0); + free(path_name); + } + } + /* traverse links in reverse order so that we get the + the symbols the user actually gets. */ + lm = lms.l_prev; + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); +} + +#if defined(_ES_MP) + +#include + +unsigned int +m88k_harris_core_register_addr (regno, reg_ptr) + int regno, reg_ptr; +{ + unsigned int word_offset; + + switch (regno) + { + case PSR_REGNUM: + word_offset = R_EPSR; + break; + case FPSR_REGNUM: + word_offset = R_FPSR; + break; + case FPCR_REGNUM: + word_offset = R_FPCR; + break; + case SXIP_REGNUM: + word_offset = R_EXIP; + break; + case SNIP_REGNUM: + word_offset = R_ENIP; + break; + case SFIP_REGNUM: + word_offset = R_EFIP; + break; + default: + if (regno <= FP_REGNUM) + word_offset = regno; + else + word_offset = ((regno - X0_REGNUM) * 4); + } + return (word_offset * 4); +} + +#endif /* _ES_MP */ + +void +_initialize_m88k_nat() +{ +#ifdef _ES_MP + /* Enable 88110 support, as we don't support the 88100 under ES/MP. */ + + target_is_m88110 = 1; +#elif defined(_CX_UX) + /* Determine whether we're running on an 88100 or an 88110. */ + target_is_m88110 = (sinfo(SYSMACHINE,0) == SYS5800); +#endif /* _CX_UX */ +} + +#ifdef _ES_MP +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + + for (regi = 0 ; regi < R_R31 ; regi++) + { + supply_register (regi, (char *) (regp + regi)); + } + supply_register (PSR_REGNUM, (char *) (regp + R_EPSR)); + supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR)); + supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR)); + supply_register (SXIP_REGNUM, (char *) (regp + R_EXIP)); + supply_register (SNIP_REGNUM, (char *) (regp + R_ENIP)); + supply_register (SFIP_REGNUM, (char *) (regp + R_EFIP)); +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), unpack the register contents and supply them as gdb's + idea of the current floating point register values. */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + register int regi; + char *from; + + for (regi = FP0_REGNUM ; regi <= FPLAST_REGNUM ; regi++) + { + from = (char *) &((*fpregsetp)[regi-FP0_REGNUM]); + supply_register (regi, from); + } +} + +#endif /* _ES_MP */ + +#ifdef _CX_UX + +#include + +unsigned int m88k_harris_core_register_addr(int regno, int reg_ptr) +{ + unsigned int word_offset; + + switch (regno) { + case PSR_REGNUM : word_offset = R_PSR; break; + case FPSR_REGNUM : word_offset = R_FPSR; break; + case FPCR_REGNUM : word_offset = R_FPCR; break; + case SXIP_REGNUM : word_offset = R_XIP; break; + case SNIP_REGNUM : word_offset = R_NIP; break; + case SFIP_REGNUM : word_offset = R_FIP; break; + default : + if (regno <= FP_REGNUM) + word_offset = regno; + else + word_offset = ((regno - X0_REGNUM) * 4) + R_X0; + } + return (word_offset * 4); +} + +#endif /* _CX_UX */ diff --git a/contrib/gdb/gdb/dbxread.c b/contrib/gdb/gdb/dbxread.c new file mode 100644 index 000000000000..2bc60bede7ca --- /dev/null +++ b/contrib/gdb/gdb/dbxread.c @@ -0,0 +1,2556 @@ +/* Read dbx symbol tables and convert to internal format, for GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This module provides three functions: dbx_symfile_init, + which initializes to read a symbol file; dbx_new_init, which + discards existing cached information when all symbols are being + discarded; and dbx_symfile_read, which reads a symbol table + from a file. + + dbx_symfile_read 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. dbx_psymtab_to_symtab() is the function that does this */ + +#include "defs.h" +#include "gdb_string.h" + +#if defined(USG) || defined(__CYGNUSCLIB__) +#include +#include +#endif + +#include "obstack.h" +#include +#ifndef NO_SYS_FILE +#include +#endif +#include "gdb_stat.h" +#include +#include "symtab.h" +#include "breakpoint.h" +#include "command.h" +#include "target.h" +#include "gdbcore.h" /* for bfd stuff */ +#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" +#include "demangle.h" +#include "language.h" /* Needed inside partial-stab.h */ +#include "complaints.h" + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now */ + + +/* We put a pointer to this structure in the read_symtab_private field + of the psymtab. */ + +struct symloc { + + /* Offset within the file symbol table of first local symbol for this + file. */ + + int ldsymoff; + + /* Length (in bytes) of the section of the symbol table devoted to + this file's symbols (actually, the section bracketed may contain + more than just this file's symbols). If ldsymlen is 0, the only + reason for this thing's existence is the dependency list. Nothing + else will happen when it is read in. */ + + int ldsymlen; + + /* The size of each symbol in the symbol file (in external form). */ + + int symbol_size; + + /* Further information needed to locate the symbols if they are in + an ELF file. */ + + int symbol_offset; + int string_offset; + int file_string_offset; +}; + +#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff) +#define LDSYMLEN(p) (((struct symloc *)((p)->read_symtab_private))->ldsymlen) +#define SYMLOC(p) ((struct symloc *)((p)->read_symtab_private)) +#define SYMBOL_SIZE(p) (SYMLOC(p)->symbol_size) +#define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset) +#define STRING_OFFSET(p) (SYMLOC(p)->string_offset) +#define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset) + + +/* Macro to determine which symbols to ignore when reading the first symbol + of a file. Some machines override this definition. */ +#ifndef IGNORE_SYMBOL +/* This code is used on Ultrix systems. Ignore it */ +#define IGNORE_SYMBOL(type) (type == (int)N_NSYMS) +#endif + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + +/* Nonzero means give verbose info on gdb action. From main.c. */ +extern int info_verbose; + +/* The BFD for this file -- implicit parameter to next_symbol_text. */ + +static bfd *symfile_bfd; + +/* The size of each symbol in the symbol file (in external form). + This is set by dbx_symfile_read when building psymtabs, and by + dbx_psymtab_to_symtab when building symtabs. */ + +static unsigned symbol_size; + +/* This is the offset of the symbol table in the executable file */ +static unsigned symbol_table_offset; + +/* This is the offset of the string table in the executable file */ +static unsigned string_table_offset; + +/* For elf+stab executables, the n_strx field is not a simple index + into the string table. Instead, each .o file has a base offset + in the string table, and the associated symbols contain offsets + from this base. The following two variables contain the base + offset for the current and next .o files. */ +static unsigned int file_string_table_offset; +static unsigned int next_file_string_table_offset; + +/* .o and NLM files contain unrelocated addresses which are based at 0. When + non-zero, this flag disables some of the special cases for Solaris elf+stab + text addresses at location 0. */ + +static int symfile_relocatable = 0; + + /* If this is nonzero, N_LBRAC, N_RBRAC, and N_SLINE entries are relative + to the function start address. */ + +static int block_address_function_relative = 0; + +/* The lowest text address we have yet encountered. This is needed + because in an a.out file, there is no header field which tells us + what address the program is actually going to be loaded at, so we + need to make guesses based on the symbols (which *are* relocated to + reflect the address it will be loaded at). */ +static CORE_ADDR lowest_text_address; + +/* Complaints about the symbols we have encountered. */ + +struct complaint lbrac_complaint = + {"bad block start address patched", 0, 0}; + +struct complaint string_table_offset_complaint = + {"bad string table offset in symbol %d", 0, 0}; + +struct complaint unknown_symtype_complaint = + {"unknown symbol type %s", 0, 0}; + +struct complaint unknown_symchar_complaint = + {"unknown symbol descriptor `%c'", 0, 0}; + +struct complaint lbrac_rbrac_complaint = + {"block start larger than block end", 0, 0}; + +struct complaint lbrac_unmatched_complaint = + {"unmatched N_LBRAC before symtab pos %d", 0, 0}; + +struct complaint lbrac_mismatch_complaint = + {"N_LBRAC/N_RBRAC symbol mismatch at symtab pos %d", 0, 0}; + +struct complaint repeated_header_complaint = + {"\"repeated\" header file %s not previously seen, at symtab pos %d", 0, 0}; + +/* During initial symbol readin, we need to have a structure to keep + track of which psymtabs have which bincls in them. This structure + is used during readin to setup the list of dependencies within each + partial symbol table. */ + +struct header_file_location +{ + char *name; /* Name of header file */ + int instance; /* See above */ + struct partial_symtab *pst; /* Partial symtab that has the + BINCL/EINCL defs for this file */ +}; + +/* The actual list and controling variables */ +static struct header_file_location *bincl_list, *next_bincl; +static int bincls_allocated; + +/* Local function prototypes */ + +static void +free_header_files PARAMS ((void)); + +static void +init_header_files PARAMS ((void)); + +static void +read_ofile_symtab PARAMS ((struct partial_symtab *)); + +static void +dbx_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +static void +dbx_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +read_dbx_dynamic_symtab PARAMS ((struct section_offsets *, + struct objfile *objfile)); + +static void +read_dbx_symtab PARAMS ((struct section_offsets *, struct objfile *, + CORE_ADDR, int)); + +static void +free_bincl_list PARAMS ((struct objfile *)); + +static struct partial_symtab * +find_corresponding_bincl_psymtab PARAMS ((char *, int)); + +static void +add_bincl_to_list PARAMS ((struct partial_symtab *, char *, int)); + +static void +init_bincl_list PARAMS ((int, struct objfile *)); + +static char * +dbx_next_symbol_text PARAMS ((struct objfile *)); + +static void +fill_symbuf PARAMS ((bfd *)); + +static void +dbx_symfile_init PARAMS ((struct objfile *)); + +static void +dbx_new_init PARAMS ((struct objfile *)); + +static void +dbx_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +dbx_symfile_finish PARAMS ((struct objfile *)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *)); + +static void +add_new_header_file PARAMS ((char *, int)); + +static void +add_old_header_file PARAMS ((char *, int)); + +static void +add_this_object_header_file PARAMS ((int)); + +/* Free up old header file tables */ + +static void +free_header_files () +{ + register int i; + + if (header_files != NULL) + { + for (i = 0; i < n_header_files; i++) + { + free (header_files[i].name); + } + free ((PTR)header_files); + header_files = NULL; + n_header_files = 0; + } + if (this_object_header_files) + { + free ((PTR)this_object_header_files); + this_object_header_files = NULL; + } + n_allocated_header_files = 0; + n_allocated_this_object_header_files = 0; +} + +/* Allocate new header file tables */ + +static void +init_header_files () +{ + n_header_files = 0; + n_allocated_header_files = 10; + header_files = (struct header_file *) + xmalloc (10 * sizeof (struct header_file)); + + n_allocated_this_object_header_files = 10; + this_object_header_files = (int *) xmalloc (10 * sizeof (int)); +} + +/* Add header file number I for this object file + at the next successive FILENUM. */ + +static void +add_this_object_header_file (i) + int i; +{ + if (n_this_object_header_files == n_allocated_this_object_header_files) + { + n_allocated_this_object_header_files *= 2; + this_object_header_files + = (int *) xrealloc ((char *) this_object_header_files, + n_allocated_this_object_header_files * sizeof (int)); + } + + this_object_header_files[n_this_object_header_files++] = i; +} + +/* Add to this file an "old" header file, one already seen in + a previous object file. NAME is the header file's name. + INSTANCE is its instance code, to select among multiple + symbol tables for the same header file. */ + +static void +add_old_header_file (name, instance) + char *name; + int instance; +{ + register struct header_file *p = header_files; + register int i; + + for (i = 0; i < n_header_files; i++) + if (STREQ (p[i].name, name) && instance == p[i].instance) + { + add_this_object_header_file (i); + return; + } + complain (&repeated_header_complaint, name, symnum); +} + +/* Add to this file a "new" header file: definitions for its types follow. + NAME is the header file's name. + Most often this happens only once for each distinct header file, + but not necessarily. If it happens more than once, INSTANCE has + a different value each time, and references to the header file + use INSTANCE values to select among them. + + dbx output contains "begin" and "end" markers for each new header file, + but at this level we just need to know which files there have been; + so we record the file when its "begin" is seen and ignore the "end". */ + +static void +add_new_header_file (name, instance) + char *name; + int instance; +{ + register int i; + + /* Make sure there is room for one more header file. */ + + if (n_header_files == n_allocated_header_files) + { + n_allocated_header_files *= 2; + header_files = (struct header_file *) + xrealloc ((char *) header_files, + (n_allocated_header_files * sizeof (struct header_file))); + } + + /* Create an entry for this header file. */ + + i = n_header_files++; + header_files[i].name = savestring (name, strlen(name)); + header_files[i].instance = instance; + header_files[i].length = 10; + header_files[i].vector + = (struct type **) xmalloc (10 * sizeof (struct type *)); + memset (header_files[i].vector, 0, 10 * sizeof (struct type *)); + + add_this_object_header_file (i); +} + +#if 0 +static struct type ** +explicit_lookup_type (real_filenum, index) + int real_filenum, index; +{ + register struct header_file *f = &header_files[real_filenum]; + + if (index >= f->length) + { + f->length *= 2; + f->vector = (struct type **) + xrealloc (f->vector, f->length * sizeof (struct type *)); + memset (&f->vector[f->length / 2], + '\0', f->length * sizeof (struct type *) / 2); + } + return &f->vector[index]; +} +#endif + +static void +record_minimal_symbol (name, address, type, objfile) + char *name; + CORE_ADDR address; + int type; + struct objfile *objfile; +{ + enum minimal_symbol_type ms_type; + int section; + + switch (type) + { + case N_TEXT | N_EXT: + ms_type = mst_text; + section = SECT_OFF_TEXT; + break; + case N_DATA | N_EXT: + ms_type = mst_data; + section = SECT_OFF_DATA; + break; + case N_BSS | N_EXT: + ms_type = mst_bss; + section = SECT_OFF_BSS; + break; + case N_ABS | N_EXT: + ms_type = mst_abs; + section = -1; + break; +#ifdef N_SETV + case N_SETV | N_EXT: + ms_type = mst_data; + section = SECT_OFF_DATA; + break; + case N_SETV: + /* I don't think this type actually exists; since a N_SETV is the result + of going over many .o files, it doesn't make sense to have one + file local. */ + ms_type = mst_file_data; + section = SECT_OFF_DATA; + break; +#endif + case N_TEXT: + case N_NBTEXT: + case N_FN: + case N_FN_SEQ: + ms_type = mst_file_text; + section = SECT_OFF_TEXT; + break; + case N_DATA: + ms_type = mst_file_data; + + /* Check for __DYNAMIC, which is used by Sun shared libraries. + Record it as global even if it's local, not global, so + lookup_minimal_symbol can find it. We don't check symbol_leading_char + because for SunOS4 it always is '_'. */ + if (name[8] == 'C' && STREQ ("__DYNAMIC", name)) + ms_type = mst_data; + + /* Same with virtual function tables, both global and static. */ + { + char *tempstring = name; + if (tempstring[0] == bfd_get_symbol_leading_char (objfile->obfd)) + ++tempstring; + if (VTBL_PREFIX_P ((tempstring))) + ms_type = mst_data; + } + section = SECT_OFF_DATA; + break; + case N_BSS: + ms_type = mst_file_bss; + section = SECT_OFF_BSS; + break; + default: + ms_type = mst_unknown; + section = -1; + break; + } + + if ((ms_type == mst_file_text || ms_type == mst_text) + && address < lowest_text_address) + lowest_text_address = address; + + prim_record_minimal_symbol_and_info + (obsavestring (name, strlen (name), &objfile -> symbol_obstack), + address, + ms_type, + NULL, + section, + objfile); +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to dbx_symfile_init, which + put all the relevant info into a "struct dbx_symfile_info", + hung off the objfile structure. + + SECTION_OFFSETS contains offsets relative to which the symbols in the + various sections are (depending where the sections were actually loaded). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). */ + +static void +dbx_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; /* FIXME comments above */ +{ + bfd *sym_bfd; + int val; + struct cleanup *back_to; + + val = strlen (objfile->name); + + /* .o and .nlm files are relocatables with text, data and bss segs based at + 0. This flag disables special (Solaris stabs-in-elf only) fixups for + symbols with a value of 0. XXX - This is a Krock. Solaris stabs-in-elf + should be fixed to determine pst->textlow without using this text seg of + 0 fixup crap. */ + + if (strcmp (&objfile->name[val-2], ".o") == 0 + || strcmp (&objfile->name[val-4], ".nlm") == 0) + symfile_relocatable = 1; + + /* This is true for Solaris (and all other systems which put stabs + in sections, hopefully, since it would be silly to do things + differently from Solaris), and false for SunOS4 and other a.out + file formats. */ + block_address_function_relative = + ((0 == strncmp (bfd_get_target (objfile->obfd), "elf", 3)) + || (0 == strncmp (bfd_get_target (objfile->obfd), "som", 3)) + || (0 == strncmp (bfd_get_target (objfile->obfd), "coff", 4)) + || (0 == strncmp (bfd_get_target (objfile->obfd), "pe", 2)) + || (0 == strncmp (bfd_get_target (objfile->obfd), "nlm", 3))); + + sym_bfd = objfile->obfd; + val = bfd_seek (objfile->obfd, DBX_SYMTAB_OFFSET (objfile), SEEK_SET); + if (val < 0) + perror_with_name (objfile->name); + + /* If we are reinitializing, or if we have never loaded syms yet, init */ + if (mainline + || objfile->global_psymbols.size == 0 + || objfile->static_psymbols.size == 0) + init_psymbol_list (objfile, DBX_SYMCOUNT (objfile)); + + symbol_size = DBX_SYMBOL_SIZE (objfile); + symbol_table_offset = DBX_SYMTAB_OFFSET (objfile); + + pending_blocks = 0; + back_to = make_cleanup (really_free_pendings, 0); + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. */ + + read_dbx_symtab (section_offsets, objfile, + DBX_TEXT_ADDR (objfile), + DBX_TEXT_SIZE (objfile)); + + /* Add the dynamic symbols. */ + + read_dbx_dynamic_symtab (section_offsets, objfile); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + +/* 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). */ + +static void +dbx_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); + init_header_files (); +} + + +/* dbx_symfile_init () + is the dbx-specific initialization routine for reading symbols. + It is passed a struct objfile which contains, among other things, + the BFD for the file whose symbols are being read, and a slot for a pointer + to "private data" which we fill with goodies. + + We read the string table into malloc'd space and stash a pointer to it. + + Since BFD doesn't know how to read debug symbols in a format-independent + way (and may never do so...), we have to do it ourselves. We will never + be called unless this is an a.out (or very similar) file. + FIXME, there should be a cleaner peephole into the BFD environment here. */ + +#define DBX_STRINGTAB_SIZE_SIZE sizeof(long) /* FIXME */ + +static void +dbx_symfile_init (objfile) + struct objfile *objfile; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + asection *text_sect; + unsigned char size_temp[DBX_STRINGTAB_SIZE_SIZE]; + + /* Allocate struct to keep track of the symfile */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + + /* FIXME POKING INSIDE BFD DATA STRUCTURES */ +#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd)) +#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd)) + + /* FIXME POKING INSIDE BFD DATA STRUCTURES */ + + DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL; + + text_sect = bfd_get_section_by_name (sym_bfd, ".text"); + if (!text_sect) + error ("Can't find .text section in symbol file"); + DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); + DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); + + DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd); + DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd); + DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET; + + /* Read the string table and stash it away in the psymbol_obstack. It is + only needed as long as we need to expand psymbols into full symbols, + so when we blow away the psymbol the string table goes away as well. + Note that gdb used to use the results of attempting to malloc the + string table, based on the size it read, as a form of sanity check + for botched byte swapping, on the theory that a byte swapped string + table size would be so totally bogus that the malloc would fail. Now + that we put in on the psymbol_obstack, we can't do this since gdb gets + a fatal error (out of virtual memory) if the size is bogus. We can + however at least check to see if the size is less than the size of + the size field itself, or larger than the size of the entire file. + Note that all valid string tables have a size greater than zero, since + the bytes used to hold the size are included in the count. */ + + if (STRING_TABLE_OFFSET == 0) + { + /* It appears that with the existing bfd code, STRING_TABLE_OFFSET + will never be zero, even when there is no string table. This + would appear to be a bug in bfd. */ + DBX_STRINGTAB_SIZE (objfile) = 0; + DBX_STRINGTAB (objfile) = NULL; + } + else + { + val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); + if (val < 0) + perror_with_name (name); + + memset ((PTR) size_temp, 0, sizeof (size_temp)); + val = bfd_read ((PTR) size_temp, sizeof (size_temp), 1, sym_bfd); + if (val < 0) + { + perror_with_name (name); + } + else if (val == 0) + { + /* With the existing bfd code, STRING_TABLE_OFFSET will be set to + EOF if there is no string table, and attempting to read the size + from EOF will read zero bytes. */ + DBX_STRINGTAB_SIZE (objfile) = 0; + DBX_STRINGTAB (objfile) = NULL; + } + else + { + /* Read some data that would appear to be the string table size. + If there really is a string table, then it is probably the right + size. Byteswap if necessary and validate the size. Note that + the minimum is DBX_STRINGTAB_SIZE_SIZE. If we just read some + random data that happened to be at STRING_TABLE_OFFSET, because + bfd can't tell us there is no string table, the sanity checks may + or may not catch this. */ + DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp); + + if (DBX_STRINGTAB_SIZE (objfile) < sizeof (size_temp) + || DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd)) + error ("ridiculous string table size (%d bytes).", + DBX_STRINGTAB_SIZE (objfile)); + + DBX_STRINGTAB (objfile) = + (char *) obstack_alloc (&objfile -> psymbol_obstack, + DBX_STRINGTAB_SIZE (objfile)); + OBJSTAT (objfile, sz_strtab += DBX_STRINGTAB_SIZE (objfile)); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), DBX_STRINGTAB_SIZE (objfile), 1, + sym_bfd); + if (val != DBX_STRINGTAB_SIZE (objfile)) + perror_with_name (name); + } + } +} + +/* 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 +dbx_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile->sym_stab_info != NULL) + { + mfree (objfile -> md, objfile->sym_stab_info); + } + free_header_files (); +} + + +/* Buffer for reading the symbol table entries. */ +static struct internal_nlist symbuf[4096]; +static int symbuf_idx; +static int symbuf_end; + +/* Name of last function encountered. Used in Solaris to approximate + object file boundaries. */ +static char *last_function_name; + +/* The address in memory of the string table of the object file we are + reading (which might not be the "main" object file, but might be a + shared library or some other dynamically loaded thing). This is + set by read_dbx_symtab when building psymtabs, and by + read_ofile_symtab when building symtabs, and is used only by + next_symbol_text. FIXME: If that is true, we don't need it when + building psymtabs, right? */ +static char *stringtab_global; + +/* These variables are used to control fill_symbuf when the stabs + symbols are not contiguous (as may be the case when a COFF file is + linked using --split-by-reloc). */ +static struct stab_section_list *symbuf_sections; +static unsigned int symbuf_left; +static unsigned int symbuf_read; + +/* Refill the symbol table input buffer + and set the variables that control fetching entries from it. + Reports an error if no data available. + This function can read past the end of the symbol table + (into the string table) but this does no harm. */ + +static void +fill_symbuf (sym_bfd) + bfd *sym_bfd; +{ + unsigned int count; + int nbytes; + + if (symbuf_sections == NULL) + count = sizeof (symbuf); + else + { + if (symbuf_left <= 0) + { + file_ptr filepos = symbuf_sections->section->filepos; + if (bfd_seek (sym_bfd, filepos, SEEK_SET) != 0) + perror_with_name (bfd_get_filename (sym_bfd)); + symbuf_left = bfd_section_size (sym_bfd, symbuf_sections->section); + symbol_table_offset = filepos - symbuf_read; + symbuf_sections = symbuf_sections->next; + } + + count = symbuf_left; + if (count > sizeof (symbuf)) + count = sizeof (symbuf); + } + + nbytes = bfd_read ((PTR)symbuf, count, 1, sym_bfd); + if (nbytes < 0) + perror_with_name (bfd_get_filename (sym_bfd)); + else if (nbytes == 0) + error ("Premature end of file reading symbol table"); + symbuf_end = nbytes / symbol_size; + symbuf_idx = 0; + symbuf_left -= nbytes; + symbuf_read += nbytes; +} + +#define SWAP_SYMBOL(symp, abfd) \ + { \ + (symp)->n_strx = bfd_h_get_32(abfd, \ + (unsigned char *)&(symp)->n_strx); \ + (symp)->n_desc = bfd_h_get_16 (abfd, \ + (unsigned char *)&(symp)->n_desc); \ + (symp)->n_value = bfd_h_get_32 (abfd, \ + (unsigned char *)&(symp)->n_value); \ + } + +/* Invariant: The symbol pointed to by symbuf_idx is the first one + that hasn't been swapped. Swap the symbol at the same time + that symbuf_idx is incremented. */ + +/* dbx allows the text of a symbol name to be continued into the + next symbol name! When such a continuation is encountered + (a \ at the end of the text of a name) + call this function to get the continuation. */ + +static char * +dbx_next_symbol_text (objfile) + struct objfile *objfile; +{ + if (symbuf_idx == symbuf_end) + fill_symbuf (symfile_bfd); + symnum++; + SWAP_SYMBOL(&symbuf[symbuf_idx], symfile_bfd); + OBJSTAT (objfile, n_stabs++); + return symbuf[symbuf_idx++].n_strx + stringtab_global + + file_string_table_offset; +} + +/* Initialize the list of bincls to contain none and have some + allocated. */ + +static void +init_bincl_list (number, objfile) + int number; + struct objfile *objfile; +{ + bincls_allocated = number; + next_bincl = bincl_list = (struct header_file_location *) + xmmalloc (objfile -> md, bincls_allocated * sizeof(struct header_file_location)); +} + +/* Add a bincl to the list. */ + +static void +add_bincl_to_list (pst, name, instance) + struct partial_symtab *pst; + char *name; + int instance; +{ + if (next_bincl >= bincl_list + bincls_allocated) + { + int offset = next_bincl - bincl_list; + bincls_allocated *= 2; + bincl_list = (struct header_file_location *) + xmrealloc (pst->objfile->md, (char *)bincl_list, + bincls_allocated * sizeof (struct header_file_location)); + next_bincl = bincl_list + offset; + } + next_bincl->pst = pst; + next_bincl->instance = instance; + next_bincl++->name = name; +} + +/* Given a name, value pair, find the corresponding + bincl in the list. Return the partial symtab associated + with that header_file_location. */ + +static struct partial_symtab * +find_corresponding_bincl_psymtab (name, instance) + char *name; + int instance; +{ + struct header_file_location *bincl; + + for (bincl = bincl_list; bincl < next_bincl; bincl++) + if (bincl->instance == instance + && STREQ (name, bincl->name)) + return bincl->pst; + + complain (&repeated_header_complaint, name, symnum); + return (struct partial_symtab *) 0; +} + +/* Free the storage allocated for the bincl list. */ + +static void +free_bincl_list (objfile) + struct objfile *objfile; +{ + mfree (objfile -> md, (PTR)bincl_list); + bincls_allocated = 0; +} + +/* Scan a SunOs dynamic symbol table for symbols of interest and + add them to the minimal symbol table. */ + +static void +read_dbx_dynamic_symtab (section_offsets, objfile) + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + bfd *abfd = objfile->obfd; + struct cleanup *back_to; + int counter; + long dynsym_size; + long dynsym_count; + asymbol **dynsyms; + asymbol **symptr; + arelent **relptr; + long dynrel_size; + long dynrel_count; + arelent **dynrels; + CORE_ADDR sym_value; + char *name; + + /* Check that the symbol file has dynamic symbols that we know about. + bfd_arch_unknown can happen if we are reading a sun3 symbol file + on a sun4 host (and vice versa) and bfd is not configured + --with-target=all. This would trigger an assertion in bfd/sunos.c, + so we ignore the dynamic symbols in this case. */ + if (bfd_get_flavour (abfd) != bfd_target_aout_flavour + || (bfd_get_file_flags (abfd) & DYNAMIC) == 0 + || bfd_get_arch (abfd) == bfd_arch_unknown) + return; + + dynsym_size = bfd_get_dynamic_symtab_upper_bound (abfd); + if (dynsym_size < 0) + return; + + dynsyms = (asymbol **) xmalloc (dynsym_size); + back_to = make_cleanup (free, dynsyms); + + dynsym_count = bfd_canonicalize_dynamic_symtab (abfd, dynsyms); + if (dynsym_count < 0) + { + do_cleanups (back_to); + return; + } + + /* Enter dynamic symbols into the minimal symbol table + if this is a stripped executable. */ + if (bfd_get_symcount (abfd) <= 0) + { + symptr = dynsyms; + for (counter = 0; counter < dynsym_count; counter++, symptr++) + { + asymbol *sym = *symptr; + asection *sec; + int type; + + sec = bfd_get_section (sym); + + /* BFD symbols are section relative. */ + sym_value = sym->value + sec->vma; + + if (bfd_get_section_flags (abfd, sec) & SEC_CODE) + { + sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + type = N_TEXT; + } + else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) + { + sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA); + type = N_DATA; + } + else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) + { + sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS); + type = N_BSS; + } + else + continue; + + if (sym->flags & BSF_GLOBAL) + type |= N_EXT; + + record_minimal_symbol ((char *) bfd_asymbol_name (sym), sym_value, + type, objfile); + } + } + + /* Symbols from shared libraries have a dynamic relocation entry + that points to the associated slot in the procedure linkage table. + We make a mininal symbol table entry with type mst_solib_trampoline + at the address in the procedure linkage table. */ + dynrel_size = bfd_get_dynamic_reloc_upper_bound (abfd); + if (dynrel_size < 0) + { + do_cleanups (back_to); + return; + } + + dynrels = (arelent **) xmalloc (dynrel_size); + make_cleanup (free, dynrels); + + dynrel_count = bfd_canonicalize_dynamic_reloc (abfd, dynrels, dynsyms); + if (dynrel_count < 0) + { + do_cleanups (back_to); + return; + } + + for (counter = 0, relptr = dynrels; + counter < dynrel_count; + counter++, relptr++) + { + arelent *rel = *relptr; + CORE_ADDR address = + rel->address + ANOFFSET (section_offsets, SECT_OFF_DATA); + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_sparc: + if (rel->howto->type != RELOC_JMP_SLOT) + continue; + break; + case bfd_arch_m68k: + /* `16' is the type BFD produces for a jump table relocation. */ + if (rel->howto->type != 16) + continue; + + /* Adjust address in the jump table to point to + the start of the bsr instruction. */ + address -= 2; + break; + default: + continue; + } + + name = (char *) bfd_asymbol_name (*rel->sym_ptr_ptr); + prim_record_minimal_symbol + (obsavestring (name, strlen (name), &objfile -> symbol_obstack), + address, + mst_solib_trampoline, + objfile); + } + + do_cleanups (back_to); +} + +/* Given pointers to an a.out symbol table in core containing dbx + style data, setup partial_symtab's describing each source file for + which debugging information is available. + SYMFILE_NAME is the name of the file we are reading from + and SECTION_OFFSETS is the set of offsets for the various sections + of the file (a set of zeros if the mainline program). */ + +static void +read_dbx_symtab (section_offsets, objfile, text_addr, text_size) + struct section_offsets *section_offsets; + struct objfile *objfile; + CORE_ADDR text_addr; + int text_size; +{ + register struct internal_nlist *bufp = 0; /* =0 avoids gcc -Wall glitch */ + register char *namestring; + int nsl; + int past_first_source_file = 0; + CORE_ADDR last_o_file_start = 0; + CORE_ADDR last_function_start = 0; + struct cleanup *back_to; + bfd *abfd; + + /* Current partial symtab */ + struct partial_symtab *pst; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + + /* FIXME. We probably want to change stringtab_global rather than add this + while processing every symbol entry. FIXME. */ + file_string_table_offset = 0; + next_file_string_table_offset = 0; + + stringtab_global = DBX_STRINGTAB (objfile); + + pst = (struct partial_symtab *) 0; + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + /* Init bincl list */ + init_bincl_list (20, objfile); + back_to = make_cleanup (free_bincl_list, objfile); + + last_source_file = NULL; + + lowest_text_address = (CORE_ADDR)-1; + + symfile_bfd = objfile->obfd; /* For next_text_symbol */ + abfd = objfile->obfd; + symbuf_end = symbuf_idx = 0; + next_symbol_text_func = dbx_next_symbol_text; + + for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++) + { + /* Get the symbol for this run and pull out some info */ + QUIT; /* allow this to be interruptable */ + if (symbuf_idx == symbuf_end) + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx++]; + + /* + * Special case to speed up readin. + */ + if (bufp->n_type == (unsigned char)N_SLINE) continue; + + SWAP_SYMBOL (bufp, abfd); + OBJSTAT (objfile, n_stabs++); + + /* Ok. There is a lot of code duplicated in the rest of this + switch statement (for efficiency reasons). Since I don't + like duplicating code, I will do my penance here, and + describe the code which is duplicated: + + *) The assignment to namestring. + *) The call to strchr. + *) The addition of a partial symbol the the two partial + symbol lists. This last is a large section of code, so + I've imbedded it in the following macro. + */ + +/* Set namestring based on bufp. If the string table index is invalid, + give a fake name, and print a single error message per symbol file read, + rather than abort the symbol reading or flood the user with messages. */ + +/*FIXME: Too many adds and indirections in here for the inner loop. */ +#define SET_NAMESTRING()\ + if (((unsigned)bufp->n_strx + file_string_table_offset) >= \ + DBX_STRINGTAB_SIZE (objfile)) { \ + complain (&string_table_offset_complaint, symnum); \ + namestring = ""; \ + } else \ + namestring = bufp->n_strx + file_string_table_offset + \ + DBX_STRINGTAB (objfile) + +#define CUR_SYMBOL_TYPE bufp->n_type +#define CUR_SYMBOL_VALUE bufp->n_value +#define DBXREAD_ONLY +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ + start_psymtab(ofile, secoff, fname, low, symoff, global_syms, static_syms) +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)\ + end_psymtab(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) + +#include "partial-stab.h" + } + + /* If there's stuff to be cleaned up, clean it up. */ + if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */ +/*FIXME, does this have a bug at start address 0? */ + && last_o_file_start + && objfile -> ei.entry_point < bufp->n_value + && objfile -> ei.entry_point >= last_o_file_start) + { + objfile -> ei.entry_file_lowpc = last_o_file_start; + objfile -> ei.entry_file_highpc = bufp->n_value; + } + + if (pst) + { + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + (lowest_text_address == (CORE_ADDR)-1 + ? (text_addr + section_offsets->offsets[SECT_OFF_TEXT]) + : lowest_text_address) + + text_size, + dependency_list, dependencies_used); + } + + do_cleanups (back_to); +} + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + + +struct partial_symtab * +start_psymtab (objfile, section_offsets, + filename, textlow, ldsymoff, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + CORE_ADDR textlow; + int ldsymoff; + struct partial_symbol **global_syms; + struct partial_symbol **static_syms; +{ + struct partial_symtab *result = + start_psymtab_common(objfile, section_offsets, + filename, textlow, global_syms, static_syms); + + result->read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc)); + LDSYMOFF(result) = ldsymoff; + result->read_symtab = dbx_psymtab_to_symtab; + SYMBOL_SIZE(result) = symbol_size; + SYMBOL_OFFSET(result) = symbol_table_offset; + STRING_OFFSET(result) = string_table_offset; + FILE_STRING_OFFSET(result) = file_string_table_offset; + + /* If we're handling an ELF file, drag some section-relocation info + for this source file out of the ELF symbol table, to compensate for + Sun brain death. This replaces the section_offsets in this psymtab, + if successful. */ + elfstab_offset_sections (objfile, result); + + /* Deduce the source language from the filename for this psymtab. */ + psymtab_language = deduce_language_from_filename (filename); + + return result; +} + +/* Close off the current usage of PST. + Returns PST or NULL if the partial symtab was empty and thrown away. + + FIXME: List variables and peculiarities of same. */ + +struct partial_symtab * +end_psymtab (pst, include_list, num_includes, capping_symbol_offset, + capping_text, dependency_list, number_dependencies) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_offset; + CORE_ADDR capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; +{ + int i; + struct objfile *objfile = pst -> objfile; + + if (capping_symbol_offset != -1) + LDSYMLEN(pst) = capping_symbol_offset - LDSYMOFF(pst); + pst->texthigh = capping_text; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Under Solaris, the N_SO symbols always have a value of 0, + instead of the usual address of the .o file. Therefore, + we have to do some tricks to fill in texthigh and textlow. + The first trick is in partial-stab.h: if we see a static + or global function, and the textlow for the current pst + is still 0, then we use that function's address for + the textlow of the pst. */ + + /* Now, to fill in texthigh, we remember the last function seen + in the .o file (also in partial-stab.h). Also, there's a hack in + bfd/elf.c and gdb/elfread.c to pass the ELF st_size field + to here via the misc_info field. Therefore, we can fill in + a reliable texthigh by taking the address plus size of the + last function in the file. */ + + if (pst->texthigh == 0 && last_function_name) { + char *p; + int n; + struct minimal_symbol *minsym; + + p = strchr (last_function_name, ':'); + if (p == NULL) + p = last_function_name; + n = p - last_function_name; + p = alloca (n + 1); + strncpy (p, last_function_name, n); + p[n] = 0; + + minsym = lookup_minimal_symbol (p, pst->filename, objfile); + + if (minsym) + pst->texthigh = SYMBOL_VALUE_ADDRESS (minsym) + + (long) MSYMBOL_INFO (minsym); + + last_function_name = NULL; + } + + /* this test will be true if the last .o file is only data */ + if (pst->textlow == 0) + /* This loses if the text section really starts at address zero + (generally true when we are debugging a .o file, for example). + That is why this whole thing is inside SOFUN_ADDRESS_MAYBE_MISSING. */ + pst->textlow = pst->texthigh; + + /* If we know our own starting text address, then walk through all other + psymtabs for this objfile, and if any didn't know their ending text + address, set it to our starting address. Take care to not set our + own ending address to our starting address, nor to set addresses on + `dependency' files that have both textlow and texthigh zero. */ + if (pst->textlow) { + struct partial_symtab *p1; + + ALL_OBJFILE_PSYMTABS (objfile, p1) { + if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) { + p1->texthigh = pst->textlow; + /* if this file has only data, then make textlow match texthigh */ + if (p1->textlow == 0) + p1->textlow = p1->texthigh; + } + } + } + + /* End of kludge for patching Solaris textlow and texthigh. */ +#endif /* SOFUN_ADDRESS_MAYBE_MISSING. */ + + 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); + + pst->number_of_dependencies = number_dependencies; + if (number_dependencies) + { + pst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + number_dependencies * sizeof (struct partial_symtab *)); + memcpy (pst->dependencies, dependency_list, + number_dependencies * sizeof (struct partial_symtab *)); + } + else + pst->dependencies = 0; + + for (i = 0; i < num_includes; i++) + { + struct partial_symtab *subpst = + allocate_psymtab (include_list[i], objfile); + + subpst->section_offsets = pst->section_offsets; + subpst->read_symtab_private = + (char *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc)); + LDSYMOFF(subpst) = + LDSYMLEN(subpst) = + subpst->textlow = + subpst->texthigh = 0; + + /* We could save slight bits of space by only making one of these, + shared by the entire set of include files. FIXME-someday. */ + subpst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct partial_symtab *)); + subpst->dependencies[0] = pst; + subpst->number_of_dependencies = 1; + + subpst->globals_offset = + subpst->n_global_syms = + subpst->statics_offset = + subpst->n_static_syms = 0; + + subpst->readin = 0; + subpst->symtab = 0; + subpst->read_symtab = pst->read_symtab; + } + + sort_pst_symbols (pst); + + /* If there is already a psymtab or symtab for a file of this name, remove it. + (If there is a symtab, more drastic things also happen.) + This happens in VxWorks. */ + free_named_symtabs (pst->filename); + + if (num_includes == 0 + && number_dependencies == 0 + && pst->n_global_syms == 0 + && pst->n_static_syms == 0) + { + /* Throw away this psymtab, it's empty. We can't deallocate it, since + it is on the obstack, but we can forget to chain it on the list. */ + /* Empty psymtabs happen as a result of header files which don't have + any symbols in them. There can be a lot of them. But this check + is wrong, in that a psymtab with N_SLINE entries but nothing else + is not empty, but we don't realize that. Fixing that without slowing + things down might be tricky. */ + struct partial_symtab *prev_pst; + + /* First, snip it out of the psymtab chain */ + + if (pst->objfile->psymtabs == pst) + pst->objfile->psymtabs = pst->next; + else + for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next) + if (prev_pst->next == pst) + prev_pst->next = pst->next; + + /* Next, put it on a free list for recycling */ + + pst->next = pst->objfile->free_psymtabs; + pst->objfile->free_psymtabs = pst; + + /* Indicate that psymtab was thrown away. */ + pst = (struct partial_symtab *)NULL; + } + return pst; +} + +static void +dbx_psymtab_to_symtab_1 (pst) + 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. Shouldn't happen.\n", + pst->filename); + return; + } + + /* Read in all partial symtabs on which this one is dependent */ + 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) + { + 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); + } + dbx_psymtab_to_symtab_1 (pst->dependencies[i]); + } + + if (LDSYMLEN(pst)) /* Otherwise it's a dummy */ + { + /* Init stuff necessary for reading in symbols */ + stabsread_init (); + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + file_string_table_offset = FILE_STRING_OFFSET (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); + sort_symtab_syms (pst->symtab); + + do_cleanups (old_chain); + } + + pst->readin = 1; +} + +/* Read in all of the symbols for a given psymtab for real. + Be verbose about it if the user wants that. */ + +static void +dbx_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + bfd *sym_bfd; + + if (!pst) + return; + + if (pst->readin) + { + fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return; + } + + if (LDSYMLEN(pst) || pst->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); + gdb_flush (gdb_stdout); + } + + sym_bfd = pst->objfile->obfd; + + next_symbol_text_func = dbx_next_symbol_text; + + dbx_psymtab_to_symtab_1 (pst); + + /* 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); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered ("done.\n"); + } +} + +/* Read in a defined section of a specific object file's symbols. */ + +static void +read_ofile_symtab (pst) + struct partial_symtab *pst; +{ + register char *namestring; + register struct internal_nlist *bufp; + unsigned char type; + unsigned max_symnum; + register 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; + text_size = pst->texthigh - pst->textlow; + section_offsets = pst->section_offsets; + + current_objfile = objfile; + subfile_stack = NULL; + + stringtab_global = DBX_STRINGTAB (objfile); + last_source_file = NULL; + + abfd = objfile->obfd; + symfile_bfd = objfile->obfd; /* Implicit param to next_text_symbol */ + symbuf_end = symbuf_idx = 0; + + /* It is necessary to actually read one symbol *before* the start + of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL + occurs before the N_SO symbol. + + Detecting this in read_dbx_symtab + would slow down initial readin, so we look for it here instead. */ + if (!processing_acc_compilation && sym_offset >= (int)symbol_size) + { + bfd_seek (symfile_bfd, sym_offset - symbol_size, SEEK_CUR); + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx++]; + SWAP_SYMBOL (bufp, abfd); + OBJSTAT (objfile, n_stabs++); + + SET_NAMESTRING (); + + processing_gcc_compilation = 0; + if (bufp->n_type == N_TEXT) + { + const char *tempstring = namestring; + + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + if (tempstring[0] == bfd_get_symbol_leading_char (symfile_bfd)) + ++tempstring; + if (STREQN (tempstring, "__gnu_compiled", 14)) + processing_gcc_compilation = 2; + } + + /* Try to select a C++ demangling based on the compilation unit + producer. */ + + if (processing_gcc_compilation) + { + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + } + else + { + /* The N_SO starting this symtab is the first symbol, so we + better not check the symbol before it. I'm not this can + happen, but it doesn't hurt to check for it. */ + bfd_seek (symfile_bfd, sym_offset, SEEK_CUR); + processing_gcc_compilation = 0; + } + + if (symbuf_idx == symbuf_end) + fill_symbuf (abfd); + bufp = &symbuf[symbuf_idx]; + if (bufp->n_type != (unsigned char)N_SO) + error("First symbol in segment of executable not a source symbol"); + + max_symnum = sym_size / symbol_size; + + for (symnum = 0; + symnum < max_symnum; + symnum++) + { + QUIT; /* Allow this to be interruptable */ + if (symbuf_idx == symbuf_end) + fill_symbuf(abfd); + bufp = &symbuf[symbuf_idx++]; + SWAP_SYMBOL (bufp, abfd); + OBJSTAT (objfile, n_stabs++); + + type = bufp->n_type; + + SET_NAMESTRING (); + + if (type & N_STAB) { + process_one_symbol (type, bufp->n_desc, bufp->n_value, + namestring, section_offsets, objfile); + } + /* We skip checking for a new .o or -l file; that should never + happen in this routine. */ + else if (type == N_TEXT) + { + /* I don't think this code will ever be executed, because + the GCC_COMPILED_FLAG_SYMBOL usually is right before + the N_SO symbol which starts this source file. + However, there is no reason not to accept + the GCC_COMPILED_FLAG_SYMBOL anywhere. */ + + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + else if (type & N_EXT || type == (unsigned char)N_TEXT + || type == (unsigned char)N_NBTEXT + ) { + /* Global symbol: see if we came across a dbx defintion for + a corresponding symbol. If so, store the value. Remove + syms from the chain when their values are stored, but + search the whole chain, as there may be several syms from + different files with the same name. */ + /* This is probably not true. Since the files will be read + in one at a time, each reference to a global symbol will + be satisfied in each file as it appears. So we skip this + section. */ + ; + } + } + + current_objfile = NULL; + + /* In a Solaris elf file, this variable, which comes from the + value of the N_SO symbol, will still be 0. Luckily, text_offset, + which comes from pst->textlow is correct. */ + if (last_source_start_addr == 0) + last_source_start_addr = text_offset; + + /* In reordered executables last_source_start_addr may not be the + lower bound for this symtab, instead use text_offset which comes + from pst->textlow which is correct. */ + if (last_source_start_addr > text_offset) + last_source_start_addr = text_offset; + + pst->symtab = end_symtab (text_offset + text_size, objfile, SECT_OFF_TEXT); + end_stabs (); +} + + +/* This handles a single symbol from the symbol-file, building symbols + into a GDB symtab. It takes these arguments and an implicit argument. + + TYPE is the type field of the ".stab" symbol entry. + DESC is the desc field of the ".stab" entry. + VALU is the value field of the ".stab" entry. + NAME is the symbol name, in our address space. + SECTION_OFFSETS is a set of amounts by which the sections of this object + file were relocated when it was loaded into memory. + All symbols that refer + to memory locations need to be offset by these amounts. + OBJFILE is the object file from which we are reading symbols. + It is used in end_symtab. */ + +void +process_one_symbol (type, desc, valu, name, section_offsets, objfile) + int type, desc; + CORE_ADDR valu; + char *name; + struct section_offsets *section_offsets; + struct objfile *objfile; +{ +#ifdef SUN_FIXED_LBRAC_BUG + /* If SUN_FIXED_LBRAC_BUG is defined, then it tells us whether we need + to correct the address of N_LBRAC's. If it is not defined, then + we never need to correct the addresses. */ + + /* This records the last pc address we've seen. We depend on there being + an SLINE or FUN or SO before the first LBRAC, since the variable does + not get reset in between reads of different symbol files. */ + static CORE_ADDR last_pc_address; +#endif + + register struct context_stack *new; + /* This remembers the address of the start of a function. It is used + because in Solaris 2, N_LBRAC, N_RBRAC, and N_SLINE entries are + relative to the current function's start address. On systems + other than Solaris 2, this just holds the SECT_OFF_TEXT value, and is + used to relocate these symbol types rather than SECTION_OFFSETS. */ + static CORE_ADDR function_start_offset; + + /* If this is nonzero, we've seen a non-gcc N_OPT symbol for this source + file. Used to detect the SunPRO solaris compiler. */ + static int n_opt_found; + + /* The stab type used for the definition of the last function. + N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */ + static int function_stab_type = 0; + + if (!block_address_function_relative) + /* N_LBRAC, N_RBRAC and N_SLINE entries are not relative to the + function start address, so just use the text offset. */ + function_start_offset = ANOFFSET (section_offsets, SECT_OFF_TEXT); + + /* Something is wrong if we see real data before + seeing a source file name. */ + + if (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 gracefully with the + case. A complain()t might be in order (if !IGNORE_SYMBOL (type)), + but this should not be an error (). */ + return; + } + + switch (type) + { + case N_FUN: + case N_FNAME: + + if (! strcmp (name, "")) + { + /* This N_FUN marks the end of a function. This closes off the + current block. */ + within_function = 0; + new = pop_context (); + + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + function_start_offset, function_start_offset + valu, + objfile); + break; + } + + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto define_a_symbol; + + case N_LBRAC: + /* This "symbol" just indicates the start of an inner lexical + context within a function. */ + + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (n_opt_found && desc == 1) + break; + +#if defined(BLOCK_ADDRESS_ABSOLUTE) + /* Relocate for dynamic loading (?). */ + valu += function_start_offset; +#else + if (block_address_function_relative) + /* Relocate for Sun ELF acc fn-relative syms. */ + valu += function_start_offset; + else + /* On most machines, the block addresses are relative to the + N_SO, the linker did not relocate them (sigh). */ + valu += last_source_start_addr; +#endif + +#ifdef SUN_FIXED_LBRAC_BUG + if (!SUN_FIXED_LBRAC_BUG && valu < last_pc_address) { + /* Patch current LBRAC pc value to match last handy pc value */ + complain (&lbrac_complaint); + valu = last_pc_address; + } +#endif + new = push_context (desc, valu); + break; + + case N_RBRAC: + /* This "symbol" just indicates the end of an inner lexical + context that was started with N_LBRAC. */ + + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (n_opt_found && desc == 1) + break; + +#if defined(BLOCK_ADDRESS_ABSOLUTE) + /* Relocate for dynamic loading (?). */ + valu += function_start_offset; +#else + if (block_address_function_relative) + /* Relocate for Sun ELF acc fn-relative syms. */ + valu += function_start_offset; + else + /* On most machines, the block addresses are relative to the + N_SO, the linker did not relocate them (sigh). */ + valu += last_source_start_addr; +#endif + + new = pop_context(); + if (desc != new->depth) + complain (&lbrac_mismatch_complaint, symnum); + + /* Some compilers put the variable decls inside of an + LBRAC/RBRAC block. This macro should be nonzero if this + is true. DESC is N_DESC from the N_RBRAC symbol. + GCC_P is true if we've detected the GCC_COMPILED_SYMBOL + or the GCC2_COMPILED_SYMBOL. */ +#if !defined (VARIABLES_INSIDE_BLOCK) +#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0 +#endif + + /* Can only use new->locals as local symbols here if we're in + gcc or on a machine that puts them before the lbrack. */ + if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + local_symbols = new->locals; + + if (context_stack_depth + > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + { + /* This is not the outermost LBRAC...RBRAC pair in the function, + its local symbols preceded it, and are the ones just recovered + from the context stack. Define the block for them (but don't + bother if the block contains no symbols. Should we complain + on blocks without symbols? I can't think of any useful purpose + for them). */ + if (local_symbols != NULL) + { + /* Muzzle a compiler bug that makes end < start. (which + compilers? Is this ever harmful?). */ + if (new->start_addr > valu) + { + complain (&lbrac_rbrac_complaint); + new->start_addr = valu; + } + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + } + else + { + /* This is the outermost LBRAC...RBRAC pair. There is no + need to do anything; leave the symbols that preceded it + to be attached to the function's own block. We need to + indicate that we just moved outside of the function. */ + within_function = 0; + } + + if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + break; + + case N_FN: + case N_FN_SEQ: + /* This kind of symbol indicates the start of an object file. */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + + case N_SO: + /* This type of symbol indicates the start of data + for one source file. + Finish the symbol table of the previous source file + (if any) and start accumulating a new symbol table. */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + + n_opt_found = 0; + +#ifdef SUN_FIXED_LBRAC_BUG + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + +#ifdef PCC_SOL_BROKEN + /* pcc bug, occasionally puts out SO for SOL. */ + if (context_stack_depth > 0) + { + start_subfile (name, NULL); + break; + } +#endif + if (last_source_file) + { + /* Check if previous symbol was also an N_SO (with some + sanity checks). If so, that one was actually the directory + name, and the current one is the real file name. + Patch things up. */ + if (previous_stab_code == (unsigned char) N_SO) + { + patch_subfile_names (current_subfile, name); + break; /* Ignore repeated SOs */ + } + end_symtab (valu, objfile, SECT_OFF_TEXT); + end_stabs (); + } + + /* Null name means this just marks the end of text for this .o file. + Don't start a new symtab in this case. */ + if (*name == '\000') + break; + + start_stabs (); + start_symtab (name, NULL, valu); + break; + + case N_SOL: + /* This type of symbol indicates the start of data for + a sub-source-file, one whose contents were copied or + included in the compilation of the main source file + (whose name was given in the N_SO symbol.) */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + start_subfile (name, current_subfile->dirname); + break; + + case N_BINCL: + push_subfile (); + add_new_header_file (name, valu); + start_subfile (name, current_subfile->dirname); + break; + + case N_EINCL: + start_subfile (pop_subfile (), current_subfile->dirname); + break; + + case N_EXCL: + add_old_header_file (name, valu); + break; + + case N_SLINE: + /* This type of "symbol" really just records + one line-number -- core-address correspondence. + Enter it in the line list for this symbol table. */ + /* Relocate for dynamic loading and for ELF acc fn-relative syms. */ + valu += function_start_offset; +#ifdef SUN_FIXED_LBRAC_BUG + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + record_line (current_subfile, desc, valu); + break; + + case N_BCOMM: + common_block_start (name, objfile); + break; + + case N_ECOMM: + common_block_end (objfile); + break; + + /* The following symbol types need to have the appropriate offset added + to their value; then we process symbol definitions in the name. */ + + case N_STSYM: /* Static symbol in data seg */ + case N_LCSYM: /* Static symbol in BSS seg */ + case N_ROSYM: /* Static symbol in Read-only data seg */ + /* HORRID HACK DEPT. However, it's Sun's furgin' fault. + Solaris2's stabs-in-elf makes *most* symbols relative + but leaves a few absolute (at least for Solaris 2.1 and version + 2.0.1 of the SunPRO compiler). N_STSYM and friends sit on the fence. + .stab "foo:S...",N_STSYM is absolute (ld relocates it) + .stab "foo:V...",N_STSYM is relative (section base subtracted). + This leaves us no choice but to search for the 'S' or 'V'... + (or pass the whole section_offsets stuff down ONE MORE function + call level, which we really don't want to do). */ + { + char *p; + + /* .o files and NLMs have non-zero text seg offsets, but don't need + their static syms offset in this fashion. XXX - This is really a + crock that should be fixed in the solib handling code so that I + don't have to work around it here. */ + + if (!symfile_relocatable) + { + p = strchr (name, ':'); + if (p != 0 && p[1] == 'S') + { + /* The linker relocated it. We don't want to add an + elfstab_offset_sections-type offset, but we *do* want + to add whatever solib.c passed to symbol_file_add as + addr (this is known to affect SunOS4, and I suspect ELF + too). Since elfstab_offset_sections currently does not + muck with the text offset (there is no Ttext.text + symbol), we can get addr from the text offset. If + elfstab_offset_sections ever starts dealing with the + text offset, and we still need to do this, we need to + invent a SECT_OFF_ADDR_KLUDGE or something. */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto define_a_symbol; + } + } + /* Since it's not the kludge case, re-dispatch to the right handler. */ + switch (type) { + case N_STSYM: goto case_N_STSYM; + case N_LCSYM: goto case_N_LCSYM; + case N_ROSYM: goto case_N_ROSYM; + default: abort(); + } + } + + case_N_STSYM: /* Static symbol in data seg */ + case N_DSLINE: /* Source line number, data seg */ + valu += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto define_a_symbol; + + case_N_LCSYM: /* Static symbol in BSS seg */ + case N_BSLINE: /* Source line number, bss seg */ + /* N_BROWS: overlaps with N_BSLINE */ + valu += ANOFFSET (section_offsets, SECT_OFF_BSS); + goto define_a_symbol; + + case_N_ROSYM: /* Static symbol in Read-only data seg */ + valu += ANOFFSET (section_offsets, SECT_OFF_RODATA); + goto define_a_symbol; + + case N_ENTRY: /* Alternate entry point */ + /* Relocate for dynamic loading */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto define_a_symbol; + + /* The following symbol types we don't know how to process. Handle + them in a "default" way, but complain to people who care. */ + default: + case N_CATCH: /* Exception handler catcher */ + case N_EHDECL: /* Exception handler name */ + case N_PC: /* Global symbol in Pascal */ + case N_M2C: /* Modula-2 compilation unit */ + /* N_MOD2: overlaps with N_EHDECL */ + case N_SCOPE: /* Modula-2 scope information */ + case N_ECOML: /* End common (local name) */ + case N_NBTEXT: /* Gould Non-Base-Register symbols??? */ + case N_NBDATA: + case N_NBBSS: + case N_NBSTS: + case N_NBLCS: + complain (&unknown_symtype_complaint, local_hex_string (type)); + /* FALLTHROUGH */ + + /* The following symbol types don't need the address field relocated, + since it is either unused, or is absolute. */ + define_a_symbol: + case N_GSYM: /* Global variable */ + case N_NSYMS: /* Number of symbols (ultrix) */ + case N_NOMAP: /* No map? (ultrix) */ + case N_RSYM: /* Register variable */ + case N_DEFD: /* Modula-2 GNU module dependency */ + case N_SSYM: /* Struct or union element */ + case N_LSYM: /* Local symbol in stack */ + case N_PSYM: /* Parameter variable */ + case N_LENG: /* Length of preceding symbol type */ + if (name) + { + int deftype; + char *colon_pos = strchr (name, ':'); + if (colon_pos == NULL) + deftype = '\0'; + else + deftype = colon_pos[1]; + + switch (deftype) + { + case 'f': + case 'F': + function_stab_type = type; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Deal with the SunPRO 3.0 compiler which omits the address + from N_FUN symbols. */ + if (type == N_FUN + && valu == ANOFFSET (section_offsets, SECT_OFF_TEXT)) + { + struct minimal_symbol *msym; + char *p; + int n; + + p = strchr (name, ':'); + if (p == NULL) + p = name; + n = p - name; + p = alloca (n + 1); + strncpy (p, name, n); + p[n] = 0; + + msym = lookup_minimal_symbol (p, last_source_file, + objfile); + if (msym) + valu = SYMBOL_VALUE_ADDRESS (msym); + } +#endif + +#ifdef SUN_FIXED_LBRAC_BUG + /* The Sun acc compiler, under SunOS4, puts out + functions with N_GSYM or N_STSYM. The problem is + that the address of the symbol is no good (for N_GSYM + it doesn't even attept an address; for N_STSYM it + puts out an address but then it gets relocated + relative to the data segment, not the text segment). + Currently we can't fix this up later as we do for + some types of symbol in scan_file_globals. + Fortunately we do have a way of finding the address - + we know that the value in last_pc_address is either + the one we want (if we're dealing with the first + function in an object file), or somewhere in the + previous function. This means that we can use the + minimal symbol table to get the address. */ + + /* Starting with release 3.0, the Sun acc compiler, + under SunOS4, puts out functions with N_FUN and a value + of zero. This gets relocated to the start of the text + segment of the module, which is no good either. + Under SunOS4 we can deal with this as N_SLINE and N_SO + entries contain valid absolute addresses. + Release 3.0 acc also puts out N_OPT entries, which makes + it possible to discern acc from cc or gcc. */ + + if (type == N_GSYM || type == N_STSYM + || (type == N_FUN + && n_opt_found && !block_address_function_relative)) + { + struct minimal_symbol *m; + int l = colon_pos - name; + + m = lookup_minimal_symbol_by_pc (last_pc_address); + if (m && STREQN (SYMBOL_NAME (m), name, l) + && SYMBOL_NAME (m) [l] == '\0') + /* last_pc_address was in this function */ + valu = SYMBOL_VALUE (m); + else if (m && SYMBOL_NAME (m+1) + && STREQN (SYMBOL_NAME (m+1), name, l) + && SYMBOL_NAME (m+1) [l] == '\0') + /* last_pc_address was in last function */ + valu = SYMBOL_VALUE (m+1); + else + /* Not found - use last_pc_address (for finish_block) */ + valu = last_pc_address; + } + + last_pc_address = valu; /* Save for SunOS bug circumcision */ +#endif + + if (block_address_function_relative) + /* For Solaris 2.0 compilers, the block addresses and + N_SLINE's are relative to the start of the + function. On normal systems, and when using gcc on + Solaris 2.0, these addresses are just absolute, or + relative to the N_SO, depending on + BLOCK_ADDRESS_ABSOLUTE. */ + function_start_offset = valu; + + within_function = 1; + if (context_stack_depth > 0) + { + new = pop_context (); + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + /* Stack must be empty now. */ + if (context_stack_depth != 0) + complain (&lbrac_unmatched_complaint, symnum); + + new = push_context (0, valu); + new->name = define_symbol (valu, name, desc, type, objfile); + break; + + default: + define_symbol (valu, name, desc, type, objfile); + break; + } + } + break; + + /* We use N_OPT to carry the gcc2_compiled flag. Sun uses it + for a bunch of other flags, too. Someday we may parse their + flags; for now we ignore theirs and hope they'll ignore ours. */ + case N_OPT: /* Solaris 2: Compiler options */ + if (name) + { + if (STREQ (name, GCC2_COMPILED_FLAG_SYMBOL)) + { + processing_gcc_compilation = 2; +#if 1 /* Works, but is experimental. -fnf */ + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } +#endif + } + else + n_opt_found = 1; + } + break; + + /* The following symbol types can be ignored. */ + case N_OBJ: /* Solaris 2: Object file dir and name */ + /* N_UNDF: Solaris 2: file separator mark */ + /* N_UNDF: -- we will never encounter it, since we only process one + file's symbols at once. */ + case N_ENDM: /* Solaris 2: End of module */ + case N_MAIN: /* Name of main routine. */ + break; + } + + previous_stab_code = type; +} + +/* FIXME: The only difference between this and elfstab_build_psymtabs + is the call to install_minimal_symbols for elf, and the support for + split sections. If the differences are really that small, the code + should be shared. */ + +/* Scan and build partial symbols for an coff symbol file. + The coff file has already been processed to get its minimal symbols. + + This routine is the equivalent of dbx_symfile_init and dbx_symfile_read + rolled into one. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. + the base address of the text segment). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + TEXTADDR is the address of the text section. + TEXTSIZE is the size of the text section. + STABSECTS is the list of .stab sections in OBJFILE. + STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the + .stabstr section exists. + + This routine is mostly copied from dbx_symfile_init and dbx_symfile_read, + adjusted for coff details. */ + +void +coffstab_build_psymtabs (objfile, section_offsets, mainline, + textaddr, textsize, stabsects, + stabstroffset, stabstrsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + CORE_ADDR textaddr; + unsigned int textsize; + struct stab_section_list *stabsects; + file_ptr stabstroffset; + unsigned int stabstrsize; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + struct dbx_symfile_info *info; + unsigned int stabsize; + + /* 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 = (struct dbx_symfile_info *) objfile->sym_stab_info; + + DBX_TEXT_ADDR (objfile) = textaddr; + DBX_TEXT_SIZE (objfile) = textsize; + +#define COFF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ + DBX_SYMBOL_SIZE (objfile) = COFF_STABS_SYMBOL_SIZE; + DBX_STRINGTAB_SIZE (objfile) = stabstrsize; + + if (stabstrsize > bfd_get_size (sym_bfd)) + error ("ridiculous string table size: %d bytes", stabstrsize); + DBX_STRINGTAB (objfile) = (char *) + obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); + OBJSTAT (objfile, sz_strtab += stabstrsize+1); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + if (val != stabstrsize) + perror_with_name (name); + + stabsread_new_init (); + buildsym_new_init (); + free_header_files (); + init_header_files (); + + processing_acc_compilation = 1; + + /* In a coff file, we've already installed the minimal symbols that came + from the coff (non-stab) symbol table, so always act like an + incremental load here. */ + if (stabsects->next == NULL) + { + stabsize = bfd_section_size (sym_bfd, stabsects->section); + DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); + DBX_SYMTAB_OFFSET (objfile) = stabsects->section->filepos; + } + else + { + struct stab_section_list *stabsect; + + DBX_SYMCOUNT (objfile) = 0; + for (stabsect = stabsects; stabsect != NULL; stabsect = stabsect->next) + { + stabsize = bfd_section_size (sym_bfd, stabsect->section); + DBX_SYMCOUNT (objfile) += stabsize / DBX_SYMBOL_SIZE (objfile); + } + + DBX_SYMTAB_OFFSET (objfile) = stabsects->section->filepos; + + symbuf_sections = stabsects->next; + symbuf_left = bfd_section_size (sym_bfd, stabsects->section); + symbuf_read = 0; + } + + dbx_symfile_read (objfile, section_offsets, 0); +} + +/* Scan and build partial symbols for an ELF symbol file. + This ELF file has already been processed to get its minimal symbols, + and any DWARF symbols that were in it. + + This routine is the equivalent of dbx_symfile_init and dbx_symfile_read + rolled into one. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. + the base address of the text segment). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + STABOFFSET and STABSIZE define the location in OBJFILE where the .stab + section exists. + STABSTROFFSET and STABSTRSIZE define the location in OBJFILE where the + .stabstr section exists. + + This routine is mostly copied from dbx_symfile_init and dbx_symfile_read, + adjusted for elf details. */ + +void +elfstab_build_psymtabs (objfile, section_offsets, mainline, + staboffset, stabsize, + stabstroffset, stabstrsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + file_ptr staboffset; + unsigned int stabsize; + file_ptr stabstroffset; + unsigned int stabstrsize; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + struct dbx_symfile_info *info; + asection *text_sect; + + /* 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 = (struct dbx_symfile_info *) objfile->sym_stab_info; + + text_sect = bfd_get_section_by_name (sym_bfd, ".text"); + if (!text_sect) + error ("Can't find .text section in symbol file"); + DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); + DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); + +#define ELF_STABS_SYMBOL_SIZE 12 /* XXX FIXME XXX */ + DBX_SYMBOL_SIZE (objfile) = ELF_STABS_SYMBOL_SIZE; + DBX_SYMCOUNT (objfile) = stabsize / DBX_SYMBOL_SIZE (objfile); + DBX_STRINGTAB_SIZE (objfile) = stabstrsize; + DBX_SYMTAB_OFFSET (objfile) = staboffset; + + if (stabstrsize > bfd_get_size (sym_bfd)) + error ("ridiculous string table size: %d bytes", stabstrsize); + DBX_STRINGTAB (objfile) = (char *) + obstack_alloc (&objfile->psymbol_obstack, stabstrsize+1); + OBJSTAT (objfile, sz_strtab += stabstrsize+1); + + /* Now read in the string table in one big gulp. */ + + val = bfd_seek (sym_bfd, stabstroffset, SEEK_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (DBX_STRINGTAB (objfile), stabstrsize, 1, sym_bfd); + if (val != stabstrsize) + perror_with_name (name); + + stabsread_new_init (); + buildsym_new_init (); + free_header_files (); + init_header_files (); + install_minimal_symbols (objfile); + + processing_acc_compilation = 1; + + /* In an elf file, we've already installed the minimal symbols that came + from the elf (non-stab) symbol table, so always act like an + incremental load here. */ + dbx_symfile_read (objfile, section_offsets, 0); +} + +/* Scan and build partial symbols for a file with special sections for stabs + and stabstrings. The file has already been processed to get its minimal + symbols, and any other symbols that might be necessary to resolve GSYMs. + + This routine is the equivalent of dbx_symfile_init and dbx_symfile_read + rolled into one. + + OBJFILE is the object file we are reading symbols from. + ADDR is the address relative to which the symbols are (e.g. the base address + of the text segment). + MAINLINE is true if we are reading the main symbol table (as opposed to a + shared lib or dynamically loaded file). + STAB_NAME is the name of the section that contains the stabs. + STABSTR_NAME is the name of the section that contains the stab strings. + + This routine is mostly copied from dbx_symfile_init and dbx_symfile_read. */ + +void +stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, + stabstr_name, text_name) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + char *stab_name; + char *stabstr_name; + char *text_name; +{ + int val; + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + asection *stabsect; + asection *stabstrsect; + asection *text_sect; + + stabsect = bfd_get_section_by_name (sym_bfd, stab_name); + stabstrsect = bfd_get_section_by_name (sym_bfd, stabstr_name); + + if (!stabsect) + return; + + if (!stabstrsect) + error ("stabsect_build_psymtabs: Found stabs (%s), but not string section (%s)", + stab_name, stabstr_name); + + objfile->sym_stab_info = (PTR) xmalloc (sizeof (struct dbx_symfile_info)); + memset (DBX_SYMFILE_INFO (objfile), 0, sizeof (struct dbx_symfile_info)); + + text_sect = bfd_get_section_by_name (sym_bfd, text_name); + if (!text_sect) + error ("Can't find %s section in symbol file", text_name); + DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); + DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); + + DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist); + DBX_SYMCOUNT (objfile) = bfd_section_size (sym_bfd, stabsect) + / DBX_SYMBOL_SIZE (objfile); + DBX_STRINGTAB_SIZE (objfile) = bfd_section_size (sym_bfd, stabstrsect); + DBX_SYMTAB_OFFSET (objfile) = stabsect->filepos; /* XXX - FIXME: POKING INSIDE BFD DATA STRUCTURES */ + + if (DBX_STRINGTAB_SIZE (objfile) > bfd_get_size (sym_bfd)) + error ("ridiculous string table size: %d bytes", DBX_STRINGTAB_SIZE (objfile)); + DBX_STRINGTAB (objfile) = (char *) + obstack_alloc (&objfile->psymbol_obstack, DBX_STRINGTAB_SIZE (objfile) + 1); + OBJSTAT (objfile, sz_strtab += DBX_STRINGTAB_SIZE (objfile) + 1); + + /* Now read in the string table in one big gulp. */ + + val = bfd_get_section_contents (sym_bfd, /* bfd */ + stabstrsect, /* bfd section */ + DBX_STRINGTAB (objfile), /* input buffer */ + 0, /* offset into section */ + DBX_STRINGTAB_SIZE (objfile)); /* amount to read */ + + if (!val) + perror_with_name (name); + + stabsread_new_init (); + buildsym_new_init (); + free_header_files (); + init_header_files (); + install_minimal_symbols (objfile); + + /* Now, do an incremental load */ + + processing_acc_compilation = 1; + dbx_symfile_read (objfile, section_offsets, 0); +} + +/* Parse the user's idea of an offset for dynamic linking, into our idea + of how to represent it for fast symbol reading. */ + +static struct section_offsets * +dbx_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +static struct sym_fns aout_sym_fns = +{ + bfd_target_aout_flavour, + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + dbx_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_dbxread () +{ + add_symtab_fns(&aout_sym_fns); +} diff --git a/contrib/gdb/gdb/dcache.c b/contrib/gdb/gdb/dcache.c new file mode 100644 index 000000000000..9f44e96b9f72 --- /dev/null +++ b/contrib/gdb/gdb/dcache.c @@ -0,0 +1,564 @@ +/* Caching code. Typically used by remote back ends for + caching remote memory. + + Copyright 1992, 1993, 1995 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "dcache.h" +#include "gdbcmd.h" +#include "gdb_string.h" + + +/* + The data cache could lead to incorrect results because it doesn't know + about volatile variables, thus making it impossible to debug + functions which use memory mapped I/O devices. + + set remotecache 0 + + In those cases. + + In general the dcache speeds up performance, some speed improvement + comes from the actual caching mechanism, but the major gain is in + the reduction of the remote protocol overhead; instead of reading + or writing a large area of memory in 4 byte requests, the cache + bundles up the requests into 32 byte (actually LINE_SIZE) chunks. + Reducing the overhead to an eighth of what it was. This is very + obvious when displaying a large amount of data, + + eg, x/200x 0 + + caching | no yes + ---------------------------- + first time | 4 sec 2 sec improvement due to chunking + second time | 4 sec 0 sec improvement due to caching + + The cache structure is unusual, we keep a number of cache blocks + (DCACHE_SIZE) and each one caches a LINE_SIZEed area of memory. + Within each line we remember the address of the line (always a + multiple of the LINE_SIZE) and a vector of bytes over the range. + There's another vector which contains the state of the bytes. + + ENTRY_BAD means that the byte is just plain wrong, and has no + correspondence with anything else (as it would when the cache is + turned on, but nothing has been done to it. + + ENTRY_DIRTY means that the byte has some data in it which should be + written out to the remote target one day, but contains correct + data. ENTRY_OK means that the data is the same in the cache as it + is in remote memory. + + + The ENTRY_DIRTY state is necessary because GDB likes to write large + lumps of memory in small bits. If the caching mechanism didn't + maintain the DIRTY information, then something like a two byte + write would mean that the entire cache line would have to be read, + the two bytes modified and then written out again. The alternative + would be to not read in the cache line in the first place, and just + write the two bytes directly into target memory. The trouble with + that is that it really nails performance, because of the remote + protocol overhead. This way, all those little writes are bundled + up into an entire cache line write in one go, without having to + read the cache line in the first place. + + + */ + + +/* This value regulates the number of cache blocks stored. + Smaller values reduce the time spent searching for a cache + line, and reduce memory requirements, but increase the risk + of a line not being in memory */ + +#define DCACHE_SIZE 64 + +/* This value regulates the size of a cache line. Smaller values + reduce the time taken to read a single byte, but reduce overall + throughput. */ + +#define LINE_SIZE_POWER (5) +#define LINE_SIZE (1 << LINE_SIZE_POWER) + +/* Each cache block holds LINE_SIZE bytes of data + starting at a multiple-of-LINE_SIZE address. */ + +#define LINE_SIZE_MASK ((LINE_SIZE - 1)) +#define XFORM(x) ((x) & LINE_SIZE_MASK) +#define MASK(x) ((x) & ~LINE_SIZE_MASK) + + +#define ENTRY_BAD 0 /* data at this byte is wrong */ +#define ENTRY_DIRTY 1 /* data at this byte needs to be written back */ +#define ENTRY_OK 2 /* data at this byte is same as in memory */ + + +struct dcache_block +{ + struct dcache_block *p; /* next in list */ + unsigned int addr; /* Address for which data is recorded. */ + char data[LINE_SIZE]; /* bytes at given address */ + unsigned char state[LINE_SIZE]; /* what state the data is in */ + + /* whether anything in state is dirty - used to speed up the + dirty scan. */ + int anydirty; + + int refs; +}; + + +struct dcache_struct +{ + /* Function to actually read the target memory. */ + memxferfunc read_memory; + + /* Function to actually write the target memory */ + memxferfunc write_memory; + + /* free list */ + struct dcache_block *free_head; + struct dcache_block *free_tail; + + /* in use list */ + struct dcache_block *valid_head; + struct dcache_block *valid_tail; + + /* The cache itself. */ + struct dcache_block *the_cache; + + /* potentially, if the cache was enabled, and then turned off, and + then turned on again, the stuff in it could be stale, so this is + used to mark it */ + int cache_has_stuff; +} ; + +int remote_dcache = 0; + +DCACHE *last_cache; /* Used by info dcache */ + + + +/* Free all the data cache blocks, thus discarding all cached data. */ + +void +dcache_flush (dcache) + DCACHE *dcache; +{ + int i; + dcache->valid_head = 0; + dcache->valid_tail = 0; + + dcache->free_head = 0; + dcache->free_tail = 0; + + for (i = 0; i < DCACHE_SIZE; i++) + { + struct dcache_block *db = dcache->the_cache + i; + + if (!dcache->free_head) + dcache->free_head = db; + else + dcache->free_tail->p = db; + dcache->free_tail = db; + db->p = 0; + } + + dcache->cache_has_stuff = 0; + + return; +} + +/* If addr is present in the dcache, return the address of the block + containing it. */ +static +struct dcache_block * +dcache_hit (dcache, addr) + DCACHE *dcache; + unsigned int addr; +{ + register struct dcache_block *db; + + /* Search all cache blocks for one that is at this address. */ + db = dcache->valid_head; + + while (db) + { + if (MASK(addr) == db->addr) + { + db->refs++; + return db; + } + db = db->p; + } + + return NULL; +} + +/* Make sure that anything in this line which needs to + be written is. */ + +static int +dcache_write_line (dcache, db) + DCACHE *dcache; + register struct dcache_block *db; +{ + int s; + int e; + s = 0; + if (db->anydirty) + { + for (s = 0; s < LINE_SIZE; s++) + { + if (db->state[s] == ENTRY_DIRTY) + { + int len = 0; + for (e = s ; e < LINE_SIZE; e++, len++) + if (db->state[e] != ENTRY_DIRTY) + break; + { + /* all bytes from s..s+len-1 need to + be written out */ + int done = 0; + while (done < len) { + int t = dcache->write_memory (db->addr + s + done, + db->data + s + done, + len - done); + if (t == 0) + return 0; + done += t; + } + memset (db->state + s, ENTRY_OK, len); + s = e; + } + } + } + db->anydirty = 0; + } + return 1; +} + + +/* Get a free cache block, put or keep it on the valid list, + and return its address. The caller should store into the block + the address and data that it describes, then remque it from the + free list and insert it into the valid list. This procedure + prevents errors from creeping in if a memory retrieval is + interrupted (which used to put garbage blocks in the valid + list...). */ +static +struct dcache_block * +dcache_alloc (dcache) + DCACHE *dcache; +{ + register struct dcache_block *db; + + if (remote_dcache == 0) + abort (); + + /* Take something from the free list */ + db = dcache->free_head; + if (db) + { + dcache->free_head = db->p; + } + else + { + /* Nothing left on free list, so grab one from the valid list */ + db = dcache->valid_head; + dcache->valid_head = db->p; + + dcache_write_line (dcache, db); + } + + /* append this line to end of valid list */ + if (!dcache->valid_head) + dcache->valid_head = db; + else + dcache->valid_tail->p = db; + dcache->valid_tail = db; + db->p = 0; + + return db; +} + +/* Using the data cache DCACHE return the contents of the byte at + address ADDR in the remote machine. + + Returns 0 on error. */ + +int +dcache_peek_byte (dcache, addr, ptr) + DCACHE *dcache; + CORE_ADDR addr; + char *ptr; +{ + register struct dcache_block *db = dcache_hit (dcache, addr); + int ok=1; + int done = 0; + if (db == 0 + || db->state[XFORM (addr)] == ENTRY_BAD) + { + if (db) + { + dcache_write_line (dcache, db); + } + else + db = dcache_alloc (dcache); + immediate_quit++; + db->addr = MASK (addr); + while (done < LINE_SIZE) + { + int try = + (*dcache->read_memory) + (db->addr + done, + db->data + done, + LINE_SIZE - done); + if (try == 0) + return 0; + done += try; + } + immediate_quit--; + + memset (db->state, ENTRY_OK, sizeof (db->data)); + db->anydirty = 0; + } + *ptr = db->data[XFORM (addr)]; + return ok; +} + +/* Using the data cache DCACHE return the contents of the word at + address ADDR in the remote machine. + + Returns 0 on error. */ + +int +dcache_peek (dcache, addr, data) + DCACHE *dcache; + CORE_ADDR addr; + int *data; +{ + char *dp = (char *) data; + int i; + for (i = 0; i < (int) sizeof (int); i++) + { + if (!dcache_peek_byte (dcache, addr + i, dp + i)) + return 0; + } + return 1; +} + + +/* Writeback any dirty lines to the remote. */ +static int +dcache_writeback (dcache) + DCACHE *dcache; +{ + struct dcache_block *db; + + db = dcache->valid_head; + + while (db) + { + if (!dcache_write_line (dcache, db)) + return 0; + db = db->p; + } + return 1; +} + + +/* Using the data cache DCACHE return the contents of the word at + address ADDR in the remote machine. */ +int +dcache_fetch (dcache, addr) + DCACHE *dcache; + CORE_ADDR addr; +{ + int res; + dcache_peek (dcache, addr, &res); + return res; +} + + +/* Write the byte at PTR into ADDR in the data cache. + Return zero on write error. + */ + +int +dcache_poke_byte (dcache, addr, ptr) + DCACHE *dcache; + CORE_ADDR addr; + char *ptr; +{ + register struct dcache_block *db = dcache_hit (dcache, addr); + + if (!db) + { + db = dcache_alloc (dcache); + db->addr = MASK (addr); + memset (db->state, ENTRY_BAD, sizeof (db->data)); + } + + db->data[XFORM (addr)] = *ptr; + db->state[XFORM (addr)] = ENTRY_DIRTY; + db->anydirty = 1; + return 1; +} + +/* Write the word at ADDR both in the data cache and in the remote machine. + Return zero on write error. + */ + +int +dcache_poke (dcache, addr, data) + DCACHE *dcache; + CORE_ADDR addr; + int data; +{ + char *dp = (char *) (&data); + int i; + for (i = 0; i < (int) sizeof (int); i++) + { + if (!dcache_poke_byte (dcache, addr + i, dp + i)) + return 0; + } + dcache_writeback (dcache); + return 1; +} + + +/* Initialize the data cache. */ +DCACHE * +dcache_init (reading, writing) + memxferfunc reading; + memxferfunc writing; +{ + int csize = sizeof (struct dcache_block) * DCACHE_SIZE; + DCACHE *dcache; + + dcache = (DCACHE *) xmalloc (sizeof (*dcache)); + dcache->read_memory = reading; + dcache->write_memory = writing; + + dcache->the_cache = (struct dcache_block *) xmalloc (csize); + memset (dcache->the_cache, 0, csize); + + dcache_flush (dcache); + + last_cache = dcache; + return dcache; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is + nonzero. + + Returns length of data written or read; 0 for error. + + This routine is indended to be called by remote_xfer_ functions. */ + +int +dcache_xfer_memory (dcache, memaddr, myaddr, len, should_write) + DCACHE *dcache; + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; +{ + int i; + + if (remote_dcache) + { + int (*xfunc) () + = should_write ? dcache_poke_byte : dcache_peek_byte; + + for (i = 0; i < len; i++) + { + if (!xfunc (dcache, memaddr + i, myaddr + i)) + return 0; + } + dcache->cache_has_stuff = 1; + dcache_writeback (dcache); + } + else + { + int (*xfunc) () + = should_write ? dcache->write_memory : dcache->read_memory; + + if (dcache->cache_has_stuff) + dcache_flush (dcache); + + len = xfunc (memaddr, myaddr, len); + } + return len; +} + +static void +dcache_info (exp, tty) + char *exp; + int tty; +{ + struct dcache_block *p; + + if (!remote_dcache) + { + printf_filtered ("Dcache not enabled\n"); + return; + } + printf_filtered ("Dcache enabled, line width %d, depth %d\n", + LINE_SIZE, DCACHE_SIZE); + + printf_filtered ("Cache state:\n"); + + for (p = last_cache->valid_head; p; p = p->p) + { + int j; + printf_filtered ("Line at %08xd, referenced %d times\n", + p->addr, p->refs); + + for (j = 0; j < LINE_SIZE; j++) + printf_filtered ("%02x", p->data[j] & 0xFF); + printf_filtered ("\n"); + + for (j = 0; j < LINE_SIZE; j++) + printf_filtered (" %2x", p->state[j]); + printf_filtered ("\n"); + } +} + +void +_initialize_dcache () +{ + add_show_from_set + (add_set_cmd ("remotecache", class_support, var_boolean, + (char *) &remote_dcache, + "\ +Set cache use for remote targets.\n\ +When on, use data caching for remote targets. For many remote targets\n\ +this option can offer better throughput for reading target memory.\n\ +Unfortunately, gdb does not currently know anything about volatile\n\ +registers and thus data caching will produce incorrect results with\n\ +volatile registers are in use. By default, this option is on.", + &setlist), + &showlist); + + add_info ("dcache", dcache_info, + "Print information on the dcache performance."); + +} diff --git a/contrib/gdb/gdb/dcache.h b/contrib/gdb/gdb/dcache.h new file mode 100644 index 000000000000..a0b762a2e134 --- /dev/null +++ b/contrib/gdb/gdb/dcache.h @@ -0,0 +1,50 @@ +/* Declarations for caching. Typically used by remote back ends for + caching remote memory. + + Copyright 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef DCACHE_H +#define DCACHE_H + +typedef int (*memxferfunc) PARAMS((CORE_ADDR memaddr, + char *myaddr, + int len)); + +typedef struct dcache_struct DCACHE; + +/* Using the data cache DCACHE return the contents of the word at + address ADDR in the remote machine. */ +int dcache_fetch PARAMS((DCACHE *dcache, CORE_ADDR addr)); + +/* Flush DCACHE. */ +void dcache_flush PARAMS((DCACHE *dcache)); + +/* Initialize DCACHE. */ +DCACHE *dcache_init PARAMS((memxferfunc reading, memxferfunc writing)); + +/* Write the word at ADDR both in the data cache and in the remote machine. */ +int dcache_poke PARAMS((DCACHE *dcache, CORE_ADDR addr, int data)); + +/* Simple to call from _xfer_memory */ + +int dcache_xfer_memory PARAMS((DCACHE *cache, CORE_ADDR mem, char *my, int len, int should_write)); + +/* Write the bytes at ADDR into the data cache and the remote machine. */ +int dcache_poke_block PARAMS((DCACHE *cache, CORE_ADDR mem, char* my, int len)); +#endif /* DCACHE_H */ diff --git a/contrib/gdb/gdb/defs.h b/contrib/gdb/gdb/defs.h new file mode 100644 index 000000000000..a1d181f1eee0 --- /dev/null +++ b/contrib/gdb/gdb/defs.h @@ -0,0 +1,973 @@ +/* Basic, host-specific, and target-specific definitions for GDB. + Copyright (C) 1986, 1989, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef DEFS_H +#define DEFS_H + +#include "config.h" /* Generated by configure */ +#include +#include /* System call error return status */ + +/* Just in case they're not defined in stdio.h. */ + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +/* First include ansidecl.h so we can use the various macro definitions + here and in all subsequent file inclusions. */ + +#include "ansidecl.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "libiberty.h" + +/* libiberty.h can't declare this one, but evidently we can. */ +extern char *strsignal PARAMS ((int)); + +#include "progress.h" + +#ifndef NO_MMALLOC +#include "mmalloc.h" +#endif + +/* For BFD64 and bfd_vma. */ +#include "bfd.h" + +/* An address in the program being debugged. Host byte order. Rather + than duplicate all the logic in BFD which figures out what type + this is (long, long long, etc.) and whether it needs to be 64 + bits (the host/target interactions are subtle), we just use + bfd_vma. */ + +typedef bfd_vma CORE_ADDR; + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +/* Gdb does *lots* of string compares. Use macros to speed them up by + avoiding function calls if the first characters are not the same. */ + +#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b)) +#define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0) +#define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0) + +/* The character GNU C++ uses to build identifiers that must be unique from + the program's identifiers (such as $this and $$vptr). */ +#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */ + +/* Check if a character is one of the commonly used C++ marker characters. */ +extern int is_cplus_marker PARAMS ((int)); + +extern int quit_flag; +extern int immediate_quit; +extern int sevenbit_strings; + +extern void quit PARAMS ((void)); + +#define QUIT { \ + if (quit_flag) quit (); \ + if (interactive_hook) interactive_hook (); \ + PROGRESS (1); \ +} + +/* Command classes are top-level categories into which commands are broken + down for "help" purposes. + Notes on classes: class_alias is for alias commands which are not + abbreviations of the original command. class-pseudo is for commands + which are not really commands nor help topics ("stop"). */ + +enum command_class +{ + /* Special args to help_list */ + all_classes = -2, all_commands = -1, + /* Classes of commands */ + no_class = -1, class_run = 0, class_vars, class_stack, + class_files, class_support, class_info, class_breakpoint, + class_alias, class_obscure, class_user, class_maintenance, + class_pseudo +}; + +/* Languages represented in the symbol table and elsewhere. + This should probably be in language.h, but since enum's can't + be forward declared to satisfy opaque references before their + actual definition, needs to be here. */ + +enum language +{ + language_unknown, /* Language not known */ + language_auto, /* Placeholder for automatic setting */ + language_c, /* C */ + language_cplus, /* C++ */ + language_chill, /* Chill */ + language_fortran, /* Fortran */ + language_m2, /* Modula-2 */ + language_asm, /* Assembly language */ + language_scm /* Scheme / Guile */ +}; + +/* 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. */ + +struct cleanup +{ + struct cleanup *next; + void (*function) PARAMS ((PTR)); + PTR arg; +}; + + +/* The ability to declare that a function never returns is useful, but + not really required to compile GDB successfully, so the NORETURN and + ATTR_NORETURN macros normally expand into nothing. */ + +/* If compiling with older versions of GCC, a function may be declared + "volatile" to indicate that it does not return. */ + +#ifndef NORETURN +# if defined(__GNUC__) \ + && (__GNUC__ == 1 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)) +# define NORETURN volatile +# else +# define NORETURN /* nothing */ +# endif +#endif + +/* GCC 2.5 and later versions define a function attribute "noreturn", + which is the preferred way to declare that a function never returns. + However GCC 2.7 appears to be the first version in which this fully + works everywhere we use it. */ + +#ifndef ATTR_NORETURN +# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 7 +# define ATTR_NORETURN __attribute__ ((noreturn)) +# else +# define ATTR_NORETURN /* nothing */ +# endif +#endif + +#ifndef ATTR_FORMAT +# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 4 && defined (__ANSI_PROTOTYPES) +# define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y))) +# else +# define ATTR_FORMAT(type, x, y) /* nothing */ +# endif +#endif + +/* Needed for various prototypes */ + +#ifdef __STDC__ +struct symtab; +struct breakpoint; +#endif + +/* From blockframe.c */ + +extern int inside_entry_func PARAMS ((CORE_ADDR)); + +extern int inside_entry_file PARAMS ((CORE_ADDR addr)); + +extern int inside_main_func PARAMS ((CORE_ADDR pc)); + +/* From ch-lang.c, for the moment. (FIXME) */ + +extern char *chill_demangle PARAMS ((const char *)); + +/* From utils.c */ + +extern int strcmp_iw PARAMS ((const char *, const char *)); + +extern char *safe_strerror PARAMS ((int)); + +extern char *safe_strsignal PARAMS ((int)); + +extern void init_malloc PARAMS ((void *)); + +extern void request_quit PARAMS ((int)); + +extern void do_cleanups PARAMS ((struct cleanup *)); + +extern void discard_cleanups PARAMS ((struct cleanup *)); + +/* The bare make_cleanup function is one of those rare beasts that + takes almost any type of function as the first arg and anything that + will fit in a "void *" as the second arg. + + Should be, once all calls and called-functions are cleaned up: +extern struct cleanup * +make_cleanup PARAMS ((void (*function) (void *), void *)); + + Until then, lint and/or various type-checking compiler options will + complain about make_cleanup calls. It'd be wrong to just cast things, + since the type actually passed when the function is called would be + wrong. */ + +extern struct cleanup *make_cleanup (); + +extern struct cleanup *save_cleanups PARAMS ((void)); + +extern void restore_cleanups PARAMS ((struct cleanup *)); + +extern void free_current_contents PARAMS ((char **)); + +extern void null_cleanup PARAMS ((char **)); + +extern int myread PARAMS ((int, char *, int)); + +extern int query PARAMS((char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +/* Annotation stuff. */ + +extern int annotation_level; /* in stack.c */ + +extern void begin_line PARAMS ((void)); + +extern void wrap_here PARAMS ((char *)); + +extern void reinitialize_more_filter PARAMS ((void)); + +typedef FILE GDB_FILE; +#define gdb_stdout stdout +#define gdb_stderr stderr + +extern void gdb_flush PARAMS ((GDB_FILE *)); + +extern GDB_FILE *gdb_fopen PARAMS ((char * name, char * mode)); + +extern void fputs_filtered PARAMS ((const char *, GDB_FILE *)); + +extern void fputs_unfiltered PARAMS ((const char *, GDB_FILE *)); + +extern int fputc_unfiltered PARAMS ((int c, GDB_FILE *)); + +extern int putchar_unfiltered PARAMS ((int c)); + +extern void puts_filtered PARAMS ((const char *)); + +extern void puts_unfiltered PARAMS ((const char *)); + +extern void vprintf_filtered PARAMS ((const char *, va_list)) + ATTR_FORMAT(printf, 1, 0); + +extern void vfprintf_filtered PARAMS ((FILE *, const char *, va_list)) + ATTR_FORMAT(printf, 2, 0); + +extern void fprintf_filtered PARAMS ((FILE *, const char *, ...)) + ATTR_FORMAT(printf, 2, 3); + +extern void fprintfi_filtered PARAMS ((int, FILE *, const char *, ...)) + ATTR_FORMAT(printf, 3, 4); + +extern void printf_filtered PARAMS ((const char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +extern void printfi_filtered PARAMS ((int, const char *, ...)) + ATTR_FORMAT(printf, 2, 3); + +extern void vprintf_unfiltered PARAMS ((const char *, va_list)) + ATTR_FORMAT(printf, 1, 0); + +extern void vfprintf_unfiltered PARAMS ((FILE *, const char *, va_list)) + ATTR_FORMAT(printf, 2, 0); + +extern void fprintf_unfiltered PARAMS ((FILE *, const char *, ...)) + ATTR_FORMAT(printf, 2, 3); + +extern void printf_unfiltered PARAMS ((const char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +extern void print_spaces PARAMS ((int, GDB_FILE *)); + +extern void print_spaces_filtered PARAMS ((int, GDB_FILE *)); + +extern char *n_spaces PARAMS ((int)); + +extern void gdb_printchar PARAMS ((int, GDB_FILE *, int)); + +extern void gdb_print_address PARAMS ((void *, GDB_FILE *)); + +extern void fprintf_symbol_filtered PARAMS ((GDB_FILE *, char *, + enum language, int)); + +extern void perror_with_name PARAMS ((char *)); + +extern void print_sys_errmsg PARAMS ((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 + as "char *". */ + +extern char *re_comp PARAMS ((const char *)); + +/* From symfile.c */ + +extern void symbol_file_command PARAMS ((char *, int)); + +/* From top.c */ + +extern char *skip_quoted PARAMS ((char *)); + +extern char *gdb_readline PARAMS ((char *)); + +extern char *command_line_input PARAMS ((char *, int, char *)); + +extern void print_prompt PARAMS ((void)); + +extern int input_from_terminal_p PARAMS ((void)); + +extern int info_verbose; + +/* From printcmd.c */ + +extern void set_next_address PARAMS ((CORE_ADDR)); + +extern void print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int, + char *)); + +extern void print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *)); + +extern void print_address PARAMS ((CORE_ADDR, GDB_FILE *)); + +/* From source.c */ + +extern int openp PARAMS ((char *, int, char *, int, int, char **)); + +extern void mod_path PARAMS ((char *, char **)); + +extern void directory_command PARAMS ((char *, int)); + +extern void init_source_path PARAMS ((void)); + +extern char *symtab_to_filename PARAMS ((struct symtab *)); + +/* From findvar.c */ + +extern int read_relative_register_raw_bytes PARAMS ((int, char *)); + +/* From readline (but not in any readline .h files). */ + +extern char *tilde_expand PARAMS ((char *)); + +/* Control types for commands */ + +enum misc_command_type +{ + ok_command, + end_command, + else_command, + nop_command +}; + +enum command_control_type +{ + simple_control, + break_control, + continue_control, + while_control, + if_control, + invalid_control +}; + +/* Structure for saved commands lines + (for breakpoints, defined commands, etc). */ + +struct command_line +{ + struct command_line *next; + char *line; + enum command_control_type control_type; + int body_count; + struct command_line **body_list; +}; + +extern struct command_line *read_command_lines PARAMS ((void)); + +extern void free_command_lines PARAMS ((struct command_line **)); + +/* String containing the current directory (what getwd would return). */ + +extern char *current_directory; + +/* Default radixes for input and output. Only some values supported. */ +extern unsigned input_radix; +extern unsigned output_radix; + +/* Possibilities for prettyprint parameters to routines which print + things. Like enum language, this should be in value.h, but needs + to be here for the same reason. FIXME: If we can eliminate this + as an arg to LA_VAL_PRINT, then we can probably move it back to + value.h. */ + +enum val_prettyprint +{ + Val_no_prettyprint = 0, + Val_prettyprint, + /* Use the default setting which the user has specified. */ + Val_pretty_default +}; + + +/* Host machine definition. This will be a symlink to one of the + xm-*.h files, built by the `configure' script. */ + +#include "xm.h" + +/* Native machine support. This will be a symlink to one of the + nm-*.h files, built by the `configure' script. */ + +#include "nm.h" + +/* Target machine definition. This will be a symlink to one of the + tm-*.h files, built by the `configure' script. */ + +#include "tm.h" + +/* If the xm.h file did not define the mode string used to open the + files, assume that binary files are opened the same way as text + files */ +#ifndef FOPEN_RB +#include "fopen-same.h" +#endif + +/* + * Allow things in gdb to be declared "const". If compiling ANSI, it + * just works. If compiling with gcc but non-ansi, redefine to __const__. + * If non-ansi, non-gcc, then eliminate "const" entirely, making those + * objects be read-write rather than read-only. + */ + +#ifndef const +#ifndef __STDC__ +# ifdef __GNUC__ +# define const __const__ +# else +# define const /*nothing*/ +# endif /* GNUC */ +#endif /* STDC */ +#endif /* const */ + +#ifndef volatile +#ifndef __STDC__ +# ifdef __GNUC__ +# define volatile __volatile__ +# else +# define volatile /*nothing*/ +# endif /* GNUC */ +#endif /* STDC */ +#endif /* volatile */ + +/* Defaults for system-wide constants (if not defined by xm.h, we fake it). */ + +#if !defined (UINT_MAX) +#define UINT_MAX ((unsigned int)(~0)) /* 0xFFFFFFFF for 32-bits */ +#endif + +#if !defined (INT_MAX) +#define INT_MAX ((int)(UINT_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ +#endif + +#if !defined (INT_MIN) +#define INT_MIN (-INT_MAX - 1) /* 0x80000000 for 32-bits */ +#endif + +#if !defined (ULONG_MAX) +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */ +#endif + +#if !defined (LONG_MAX) +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ +#endif + +#ifdef BFD64 + +/* This is to make sure that LONGEST is at least as big as CORE_ADDR. */ + +#define LONGEST BFD_HOST_64_BIT + +#else /* No BFD64 */ + +/* If all compilers for this host support "long long" and we want to + use it for LONGEST (the performance hit is about 10% on a testsuite + run based on one DECstation test), then the xm.h file can define + CC_HAS_LONG_LONG. + + Using GCC 1.39 on BSDI with long long causes about 700 new + testsuite failures. Using long long for LONGEST on the DECstation + causes 3 new FAILs in the testsuite and many heuristic fencepost + warnings. These are not investigated, but a first guess would be + that the BSDI problems are GCC bugs in long long support and the + latter are GDB bugs. */ + +#ifndef CC_HAS_LONG_LONG +# if defined (__GNUC__) && defined (FORCE_LONG_LONG) +# define CC_HAS_LONG_LONG 1 +# endif +#endif + +/* LONGEST should not be a typedef, because "unsigned LONGEST" needs to work. + CC_HAS_LONG_LONG is defined if the host compiler supports "long long" + variables and we wish to make use of that support. */ + +#ifndef LONGEST +# ifdef CC_HAS_LONG_LONG +# define LONGEST long long +# else +# define LONGEST long +# endif +#endif + +#endif /* No BFD64 */ + +/* Convert a LONGEST to an int. This is used in contexts (e.g. number of + arguments to a function, number in a value history, register number, etc.) + where the value must not be larger than can fit in an int. */ + +extern int longest_to_int PARAMS ((LONGEST)); + +/* Assorted functions we can declare, now that const and volatile are + defined. */ + +extern char *savestring PARAMS ((const char *, int)); + +extern char *msavestring PARAMS ((void *, const char *, int)); + +extern char *strsave PARAMS ((const char *)); + +extern char *mstrsave PARAMS ((void *, const char *)); + +extern PTR xmmalloc PARAMS ((PTR, long)); + +extern PTR xmrealloc PARAMS ((PTR, PTR, long)); + +extern int parse_escape PARAMS ((char **)); + +extern char *reg_names[]; + +/* 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 NORETURN void error PARAMS((char *, ...)) ATTR_NORETURN; + +extern void error_begin PARAMS ((void)); + +extern NORETURN void fatal PARAMS((char *, ...)) ATTR_NORETURN; + +extern NORETURN void nomem PARAMS ((long)) ATTR_NORETURN; + +/* Reasons for calling return_to_top_level. */ +enum return_reason { + /* User interrupt. */ + RETURN_QUIT, + + /* Any other error. */ + RETURN_ERROR +}; + +#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT) +#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR) +#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) +typedef int return_mask; + +extern NORETURN void +return_to_top_level PARAMS ((enum return_reason)) ATTR_NORETURN; + +extern int +catch_errors PARAMS ((int (*) (char *), void *, char *, return_mask)); + +extern void warning_begin PARAMS ((void)); + +extern void warning PARAMS ((char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +/* Global functions from other, non-gdb GNU thingies. + Libiberty thingies are no longer declared here. We include libiberty.h + above, instead. */ + +#ifndef GETENV_PROVIDED +extern char *getenv PARAMS ((const char *)); +#endif + +/* From other system libraries */ + +#ifdef __STDC__ +#include +#include +#endif + + +/* We take the address of fclose later, but some stdio's forget + to declare this. We can't always declare it since there's + no way to declare the parameters without upsetting some compiler + somewhere. */ + +#ifndef FCLOSE_PROVIDED +extern int fclose (); +#endif + +#ifndef atof +extern double atof (); +#endif + +#ifndef MALLOC_INCOMPATIBLE + +extern PTR malloc (); + +extern PTR realloc (); + +extern void free (); + +#endif /* MALLOC_INCOMPATIBLE */ + +#ifndef __WIN32__ + +#ifndef strchr +extern char *strchr (); +#endif + +#ifndef strrchr +extern char *strrchr (); +#endif + +#ifndef strstr +extern char *strstr (); +#endif + +#ifndef strtok +extern char *strtok (); +#endif + +#ifndef strerror +extern char *strerror (); +#endif + +#endif /* !__WIN32__ */ + +/* Various possibilities for alloca. */ +#ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* Not GNU C */ +# ifdef sparc +# include /* NOTE: Doesn't declare alloca() */ +# endif + +/* We need to be careful not to declare this in a way which conflicts with + bison. Bison never declares it as char *, but under various circumstances + (like __hpux) we need to use void *. */ +# if defined (__STDC__) || defined (__hpux) + extern void *alloca (); +# else /* Don't use void *. */ + extern char *alloca (); +# endif /* Don't use void *. */ +# endif /* Not GNU C */ +#endif /* alloca not defined */ + +/* HOST_BYTE_ORDER must be defined to one of these. */ + +#ifdef HAVE_ENDIAN_H +#include +#endif + +#if !defined (BIG_ENDIAN) +#define BIG_ENDIAN 4321 +#endif + +#if !defined (LITTLE_ENDIAN) +#define LITTLE_ENDIAN 1234 +#endif + +/* Target-system-dependent parameters for GDB. */ + +#ifdef TARGET_BYTE_ORDER_SELECTABLE +/* The target endianness is selectable at runtime. Define + TARGET_BYTE_ORDER to be a variable. The user can use the `set + endian' command to change it. */ +#undef TARGET_BYTE_ORDER +#define TARGET_BYTE_ORDER target_byte_order +extern int target_byte_order; +#endif + +extern void set_endian_from_file PARAMS ((bfd *)); + +/* Number of bits in a char or unsigned char for the target machine. + Just like CHAR_BIT in but describes the target machine. */ +#if !defined (TARGET_CHAR_BIT) +#define TARGET_CHAR_BIT 8 +#endif + +/* Number of bits in a short or unsigned short for the target machine. */ +#if !defined (TARGET_SHORT_BIT) +#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in an int or unsigned int for the target machine. */ +#if !defined (TARGET_INT_BIT) +#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long or unsigned long for the target machine. */ +#if !defined (TARGET_LONG_BIT) +#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long long or unsigned long long for the target machine. */ +#if !defined (TARGET_LONG_LONG_BIT) +#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT) +#endif + +/* Number of bits in a float for the target machine. */ +#if !defined (TARGET_FLOAT_BIT) +#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a double for the target machine. */ +#if !defined (TARGET_DOUBLE_BIT) +#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT) +#endif + +/* Number of bits in a long double for the target machine. */ +#if !defined (TARGET_LONG_DOUBLE_BIT) +#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT) +#endif + +/* Number of bits in a pointer for the target machine */ +#if !defined (TARGET_PTR_BIT) +#define TARGET_PTR_BIT TARGET_INT_BIT +#endif + +/* If we picked up a copy of CHAR_BIT from a configuration file + (which may get it by including ) then use it to set + the number of bits in a host char. If not, use the same size + as the target. */ + +#if defined (CHAR_BIT) +#define HOST_CHAR_BIT CHAR_BIT +#else +#define HOST_CHAR_BIT TARGET_CHAR_BIT +#endif + +/* The bit byte-order has to do just with numbering of bits in + debugging symbols and such. Conceptually, it's quite separate + from byte/word byte order. */ + +#if !defined (BITS_BIG_ENDIAN) +#ifndef TARGET_BYTE_ORDER_SELECTABLE + +#if TARGET_BYTE_ORDER == BIG_ENDIAN +#define BITS_BIG_ENDIAN 1 +#endif /* Big endian. */ + +#if TARGET_BYTE_ORDER == LITTLE_ENDIAN +#define BITS_BIG_ENDIAN 0 +#endif /* Little endian. */ + +#else /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ + +#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BIG_ENDIAN) + +#endif /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ +#endif /* BITS_BIG_ENDIAN not defined. */ + +/* In findvar.c. */ + +extern LONGEST extract_signed_integer PARAMS ((void *, int)); + +extern unsigned LONGEST extract_unsigned_integer PARAMS ((void *, int)); + +extern int extract_long_unsigned_integer PARAMS ((void *, int, LONGEST *)); + +extern CORE_ADDR extract_address PARAMS ((void *, int)); + +extern void store_signed_integer PARAMS ((void *, int, LONGEST)); + +extern void store_unsigned_integer PARAMS ((void *, int, unsigned LONGEST)); + +extern void store_address PARAMS ((void *, int, CORE_ADDR)); + +/* Use `long double' if the host compiler supports it. (Note that this is not + necessarily any longer than `double'. On SunOS/gcc, it's the same as + double.) This is necessary because GDB internally converts all floating + point values to the widest type supported by the host. + + There are problems however, when the target `long double' is longer than the + host's `long double'. In general, we'll probably reduce the precision of + any such values and print a warning. */ + + +#ifdef HAVE_LONG_DOUBLE +typedef long double DOUBLEST; +#else +typedef double DOUBLEST; +#endif + +extern DOUBLEST extract_floating PARAMS ((void *, int)); + +extern void store_floating PARAMS ((void *, int, DOUBLEST)); + +/* On some machines there are bits in addresses which are not really + part of the address, but are used by the kernel, the hardware, etc. + for special purposes. ADDR_BITS_REMOVE takes out any such bits + so we get a "real" address such as one would find in a symbol + table. This is used only for addresses of instructions, and even then + I'm not sure it's used in all contexts. It exists to deal with there + being a few stray bits in the PC which would mislead us, not as some sort + of generic thing to handle alignment or segmentation (it's possible it + should be in TARGET_READ_PC instead). */ +#if !defined (ADDR_BITS_REMOVE) +#define ADDR_BITS_REMOVE(addr) (addr) +#endif /* No ADDR_BITS_REMOVE. */ + +/* From valops.c */ + +extern CORE_ADDR push_bytes PARAMS ((CORE_ADDR, char *, int)); + +extern CORE_ADDR push_word PARAMS ((CORE_ADDR, unsigned LONGEST)); + +/* Some parts of gdb might be considered optional, in the sense that they + are not essential for being able to build a working, usable debugger + for a specific environment. For example, the maintenance commands + are there for the benefit of gdb maintainers. As another example, + some environments really don't need gdb's that are able to read N + different object file formats. In order to make it possible (but + not necessarily recommended) to build "stripped down" versions of + gdb, the following defines control selective compilation of those + parts of gdb which can be safely left out when necessary. Note that + the default is to include everything. */ + +#ifndef MAINTENANCE_CMDS +#define MAINTENANCE_CMDS 1 +#endif + +#ifdef MAINTENANCE_CMDS +extern int watchdog; +#endif + +#include "dis-asm.h" /* Get defs for disassemble_info */ + +extern int dis_asm_read_memory PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, + int len, disassemble_info *info)); + +extern void dis_asm_memory_error PARAMS ((int status, bfd_vma memaddr, + disassemble_info *info)); + +extern void dis_asm_print_address PARAMS ((bfd_vma addr, + disassemble_info *info)); + +extern int (*tm_print_insn) PARAMS ((bfd_vma, disassemble_info*)); + +/* Hooks for alternate command interfaces. */ + +#ifdef __STDC__ +struct target_waitstatus; +struct cmd_list_element; +#endif + +extern void (*init_ui_hook) PARAMS ((void)); +extern void (*command_loop_hook) PARAMS ((void)); +extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, + FILE *stream)); +extern void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, + int line, int stopline, + int noerror)); +extern int (*query_hook) PARAMS (()); +extern void (*flush_hook) PARAMS ((FILE *stream)); +extern void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b)); +extern void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); +extern void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); +extern void (*target_output_hook) PARAMS ((char *)); +extern void (*interactive_hook) PARAMS ((void)); +extern void (*registers_changed_hook) PARAMS ((void)); + +extern int (*target_wait_hook) PARAMS ((int pid, + struct target_waitstatus *status)); + +extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c, + char *cmd, int from_tty)); + +extern NORETURN void (*error_hook) PARAMS (()) ATTR_NORETURN; + + + +/* Inhibit window interface if non-zero. */ + +extern int use_windows; + +/* Symbolic definitions of filename-related things. */ +/* FIXME, this doesn't work very well if host and executable + filesystems conventions are different. */ + +#ifndef DIRNAME_SEPARATOR +#define DIRNAME_SEPARATOR ':' +#endif + +#ifndef SLASH_P +#if defined(__GO32__)||defined(__WIN32__) +#define SLASH_P(X) ((X)=='\\') +#else +#define SLASH_P(X) ((X)=='/') +#endif +#endif + +#ifndef SLASH_CHAR +#if defined(__GO32__)||defined(__WIN32__) +#define SLASH_CHAR '\\' +#else +#define SLASH_CHAR '/' +#endif +#endif + +#ifndef SLASH_STRING +#if defined(__GO32__)||defined(__WIN32__) +#define SLASH_STRING "\\" +#else +#define SLASH_STRING "/" +#endif +#endif + +#ifndef ROOTED_P +#define ROOTED_P(X) (SLASH_P((X)[0])) +#endif + +#endif /* #ifndef DEFS_H */ diff --git a/contrib/gdb/gdb/demangle.c b/contrib/gdb/gdb/demangle.c new file mode 100644 index 000000000000..bb3f0922485a --- /dev/null +++ b/contrib/gdb/gdb/demangle.c @@ -0,0 +1,206 @@ +/* Basic C++ demangling support for GDB. + Copyright 1991, 1992, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file contains support code for C++ demangling that is common + to a styles of demangling, and GDB specific. */ + +#include "defs.h" +#include "command.h" +#include "gdbcmd.h" +#include "demangle.h" +#include "gdb_string.h" + +/* Select the default C++ demangling style to use. The default is "auto", + which allows gdb to attempt to pick an appropriate demangling style for + the executable it has loaded. It can be set to a specific style ("gnu", + "lucid", "arm", etc.) in which case gdb will never attempt to do auto + selection of the style unless you do an explicit "set demangle auto". + To select one of these as the default, set DEFAULT_DEMANGLING_STYLE in + the appropriate target configuration file. */ + +#ifndef DEFAULT_DEMANGLING_STYLE +# define DEFAULT_DEMANGLING_STYLE AUTO_DEMANGLING_STYLE_STRING +#endif + +/* String name for the current demangling style. Set by the "set demangling" + command, printed as part of the output by the "show demangling" command. */ + +static char *current_demangling_style_string; + +/* List of supported demangling styles. Contains the name of the style as + seen by the user, and the enum value that corresponds to that style. */ + +static const struct demangler +{ + char *demangling_style_name; + enum demangling_styles demangling_style; + char *demangling_style_doc; +} demanglers [] = +{ + {AUTO_DEMANGLING_STYLE_STRING, + auto_demangling, + "Automatic selection based on executable"}, + {GNU_DEMANGLING_STYLE_STRING, + gnu_demangling, + "GNU (g++) style demangling"}, + {LUCID_DEMANGLING_STYLE_STRING, + lucid_demangling, + "Lucid (lcc) style demangling"}, + {ARM_DEMANGLING_STYLE_STRING, + arm_demangling, + "ARM style demangling"}, + {NULL, unknown_demangling, NULL} +}; + +/* set current demangling style. called by the "set demangling" command + after it has updated the current_demangling_style_string to match + what the user has entered. + + if the user has entered a string that matches a known demangling style + name in the demanglers[] array then just leave the string alone and update + the current_demangling_style enum value to match. + + if the user has entered a string that doesn't match, including an empty + string, then print a list of the currently known styles and restore + the current_demangling_style_string to match the current_demangling_style + enum value. + + Note: Assumes that current_demangling_style_string always points to + a malloc'd string, even if it is a null-string. */ + +static void +set_demangling_command (ignore, from_tty, c) + char *ignore; + int from_tty; + struct cmd_list_element *c; +{ + const struct demangler *dem; + + /* First just try to match whatever style name the user supplied with + one of the known ones. Don't bother special casing for an empty + name, we just treat it as any other style name that doesn't match. + If we match, update the current demangling style enum. */ + + for (dem = demanglers; dem -> demangling_style_name != NULL; dem++) + { + if (STREQ (current_demangling_style_string, + dem -> demangling_style_name)) + { + current_demangling_style = dem -> demangling_style; + break; + } + } + + /* Check to see if we found a match. If not, gripe about any non-empty + style name and supply a list of valid ones. FIXME: This should + probably be done with some sort of completion and with help. */ + + if (dem -> demangling_style_name == NULL) + { + if (*current_demangling_style_string != '\0') + { + printf_unfiltered ("Unknown demangling style `%s'.\n", + current_demangling_style_string); + } + printf_unfiltered ("The currently understood settings are:\n\n"); + for (dem = demanglers; dem -> demangling_style_name != NULL; dem++) + { + printf_unfiltered ("%-10s %s\n", dem -> demangling_style_name, + dem -> demangling_style_doc); + if (dem -> demangling_style == current_demangling_style) + { + free (current_demangling_style_string); + current_demangling_style_string = + savestring (dem -> demangling_style_name, + strlen (dem -> demangling_style_name)); + } + } + if (current_demangling_style == unknown_demangling) + { + /* This can happen during initialization if gdb is compiled with + a DEMANGLING_STYLE value that is unknown, so pick the first + one as the default. */ + current_demangling_style = demanglers[0].demangling_style; + current_demangling_style_string = + savestring (demanglers[0].demangling_style_name, + strlen (demanglers[0].demangling_style_name)); + warning ("`%s' style demangling chosen as the default.\n", + current_demangling_style_string); + } + } +} + +/* Fake a "set demangling" command. */ + +void +set_demangling_style (style) + char *style; +{ + if (current_demangling_style_string != NULL) + { + free (current_demangling_style_string); + } + current_demangling_style_string = savestring (style, strlen (style)); + set_demangling_command ((char *) NULL, 0); +} + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +int +is_cplus_marker (c) + int c; +{ + return c && strchr (cplus_markers, c) != NULL; +} + +void +_initialize_demangler () +{ + struct cmd_list_element *set, *show; + + set = add_set_cmd ("demangle-style", class_support, var_string_noescape, + (char *) ¤t_demangling_style_string, + "Set the current C++ demangling style.\n\ +Use `set demangle-style' without arguments for a list of demangling styles.", + &setlist); + show = add_show_from_set (set, &showlist); + set -> function.sfunc = set_demangling_command; + + /* Set the default demangling style chosen at compilation time. */ + set_demangling_style (DEFAULT_DEMANGLING_STYLE); + set_cplus_marker_for_demangling (CPLUS_MARKER); +} diff --git a/contrib/gdb/gdb/doc/ChangeLog b/contrib/gdb/gdb/doc/ChangeLog new file mode 100644 index 000000000000..42e8393b2558 --- /dev/null +++ b/contrib/gdb/gdb/doc/ChangeLog @@ -0,0 +1,1206 @@ +Sat Mar 16 15:10:20 1996 Fred Fish + + From Peter Schauer + * gdb.texinfo (Expressions): Fix erroneous array constant example. + +Sat Mar 16 13:28:45 1996 Fred Fish + + * gdb.texinfo: Add missing "@bullet" to some "@itemize" commands. + +Sat Feb 10 03:28:36 1996 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdb.texinfo (Print settings): Document + `set/show print static-members' commands. + +Wed Jan 10 14:16:37 1996 Fred Fish + + * gdbint.texinfo (Native): Document name change, coredep.c to + core-aout.c. + +Wed Dec 13 12:35:28 1995 Ian Lance Taylor + + * stabs.texinfo (Include Files): Document the values the SunOS4 + linker creates for N_BINCL/N_EINCL/N_EXCL stabs. + +Fri Dec 8 21:08:44 1995 Fred Fish + + * gdbint.texinfo (Releases): Change gdb.tar.Z to gdb.tar.gz. + Fix typo. + +Wed Sep 20 13:14:10 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New target, synonym for + realclean. + +Thu Aug 3 10:45:37 1995 Fred Fish + + * Update all FSF addresses except those in COPYING* files. + +Wed Jul 19 18:43:03 1995 Stan Shebs + + From Richard Earnshaw (rearnsha@armltd.co.uk): + * gdb.texinfo (convenience variables): Document $_exitcode. + (quit): Document optional expression to use as exit code. + +Thu Jun 22 21:27:33 1995 Victoria Mixon + + * gdb.texinfo, remote.texi: Brought up to date with various + GDB changes. + +Tue Jun 20 14:35:38 1995 Stan Shebs + + * gdb.texinfo: Update dates and versions, fix comments about + hardware watchpoints in future releases and about the + sharedlibrary command. + +Mon May 8 09:30:36 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Remove node `XCOFF differences'. Describe value of + C_FUN stab. Other cleanups. + +Wed Apr 19 07:02:19 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.texi (Bootstrapping): Clarify that flush_i_cache is only + for the sparc stub. + +Tue Apr 11 11:41:49 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * annotate.texi: Clarify which addresses have differing formats + depending on the language and which do not. + +Tue Mar 28 16:56:22 1995 J.T. Conklin + + * remote.texi (NetWare): Changed example to use BOARD= instead of + NODE= argument to reflect correspoding change to gdbserve.nlm. + +Fri Mar 17 06:47:02 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Mention the fact that + GDB, as well as AIX dbx, supports the size type attribute. + +Thu Mar 16 12:11:32 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Document types -31 to -34. + +Mon Mar 13 16:49:13 1995 Per Bothner + + * gdb.texinfo (Define): Document $arg0... arguments to commands, + and new 'if' and 'while' commands. + +Fri Feb 17 15:24:35 1995 Per Bothner + + * gdb.texinfo (Artificial arrays): Note use of coerce-to-array-type. + +Wed Feb 15 11:59:18 1995 J.T. Conklin + + * all-cfg.texi: New flag, GDBSERVE, for NetWare's gdbserve.nlm. + * remote.texi (NetWare): New node, how to use gdbserve.nlm on + NetWare targets. Mostly stolen from the Server node. + +Fri Feb 10 20:20:08 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Setting): Talk about the language of a source file + versus the working language. The old documentation did not match + what GDB did. + +Wed Feb 1 20:26:36 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Source Files): Document N_SO used to mark the end + of a source file. + +Mon Jan 23 14:23:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Processes): New node. + +Tue Jan 17 14:09:03 1995 Ian Lance Taylor + + * remote.texi: Update documentation of set/show mipsfpu. + + +Sun Sep 4 16:47:21 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdbint.texinfo: Removed mentions of some incorrectly placed and + obsolete conditionals, described some others. + +Mon Aug 1 15:42:39 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo: Remove references to BROKEN_LARGE_ALLOCA and + SET_STACK_LIMIT_HUGE; they were removed from GDB 14 May 1994. + +Mon Aug 1 15:12:02 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdbint.texinfo: Put regex conditionals in their own table. + +Tue Jul 26 18:32:52 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdbint.texinfo: Removed mentions of many obsolete conditionals, + described or fixed the descriptions of many others. + +Sun Jul 17 14:14:03 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdb.texinfo: Add some more credits. + * gdbint.texinfo: Capitalize GDB consistently, describe some + macros and remove some. + +Thu Jul 14 18:43:17 1994 Stan Shebs (shebs@andros.cygnus.com) + + * gdbint.texinfo: Removed mentions of many incorrectly placed and + obsolete conditionals, described some others. + +Tue Jul 12 12:23:15 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdb.texinfo (help targets): Changed to `help target', which + is the correct gdb command. + +Wed Jun 22 18:00:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * annotate.texi (TODO): New node, for keeping track of annotations + suggested but not yet implemented. + +Wed Jun 1 16:10:45 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Statics): Value of xcoff C_BSTAT points to + another symbol, it is not the address itself. + +Thu May 5 20:23:36 1994 Stan Shebs (shebs@andros.cygnus.com) + + * stabs.texinfo (Stab Section Basics): Add comment about alignment + of stabs-in-coff sections. + +Wed May 4 06:26:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * annotate.texi: Change edition to 0.5 and date to May 1994. + Add index. + (Frames): New node, for frame annotation. + (Displays): New node, for display annotation. + + * remote.texi (MIPS Remote): Say that set timeout doesn't apply + when waiting for your program to stop. + +Fri Apr 29 18:24:46 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * annotate.texi (Breakpoint Info): Document annotation of header + fields and record annotation. + +Thu Apr 28 07:44:28 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * annotate.texi: New file, to document annotations. + +Thu Apr 21 14:20:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in (clean): Don't remove GDBvn.texi (apparently on Jan + 16 I meant to make this change but did not). Do remove gdb-cfg.texi. + +Wed Apr 20 11:22:48 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stab Section Basics): Say what is in .stab + section, and say n_strx field is compilation unit relative. + * stabs.texinfo: Don't use @code for a.out when it is the name of + an object file format. + +Wed Apr 13 20:29:54 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * gdb.texinfo: Refer to file names, not path names, per rms + convention. + (Arguments): Fix typo. + +Thu Mar 24 08:09:12 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Global Variables): Talk about stabs in files + where variables are referenced, but not defined. + +Wed Mar 23 07:16:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Move stuff on @ and # type descriptors from node + Cplusplus to new nodes Member Type Descriptor and Method Type + Descriptor. Re-write stuff for #. + +Wed Mar 16 08:20:19 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Print Settings): Don't document "set print + fast-symbolic-addr off". The bug which it worked around was fixed + on 25 Feb 94 in coffread.c, so I'm nuking the command. + + * stabs.texinfo (Alternate Entry Points): New node, rewritten from + N_ENTRY node. + + * stabs.texinfo (Type Descriptors): Add 'Y' type descriptor. + +Tue Mar 15 08:43:02 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo (Host Conditionals, Target Conditionals): Remove + references to ieee-float.c. + +Fri Mar 11 08:09:40 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Set Breaks): Update documentation for tbreak to + match what the code actually does. + +Wed Mar 9 19:43:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Symbol Descriptors): Add OS9000 symbol descriptor s. + +Tue Mar 1 17:04:43 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * stabs.texinfo (Type Descriptors): Add OS9000 type descriptors c, + i, and b. + +Wed Feb 23 10:44:18 1994 Jim Kingdon (kingdon@rtl.cygnus.com) + + * stabs.texinfo: Document N_RBRAC as function relative for COFF as + well as for ELF and SOM. Unify the descriptions of ELF and SOM + as "stabs in sections" rather than just saying "ELF and SOM". + Also make that stuff apply to COFF. + +Fri Feb 18 08:25:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Formatting Documentation): Change GhostScript to + Ghostscript. + +Fri Feb 4 06:31:31 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Continuing and Stepping): When talking about "step" + versus functions without line numbers, also mention stepping into + them as well as "step" when you are in them. Tell the user how to + deal with the situation. Add comment about "debugging information". + +Thu Feb 3 11:39:59 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Enumerations): Document restriction on where + enumeration types can appear and still win with GDB. + +Wed Feb 2 11:29:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Document format for type + -16. + +Thu Jan 27 16:53:56 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Selection, Frame Info): Update information about + arbitrary frame specficiations. + +Wed Jan 26 15:31:57 1994 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, remote.texi: general editing pass prior to Net release + +Tue Jan 25 12:12:04 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (String Field): Discuss continuing stabs with ?. + +Wed Jan 19 06:39:24 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * stabs.texinfo (Non-Stab Symbol Types): Mention N_SET* | N_EXT. + +Sun Jan 16 12:43:32 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Re-do stuff about C_BSTAT and move from XCOFF + Differences node to Statics node. + (Statics): Discuss XCOFF use of V symbol descriptor. + + * Makefile.in: Remove refcard.dvi and GDBvn.texi in realclean, + not clean. + +Wed Jan 12 21:29:54 1994 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo (Print Settings): Document `set print + fast-symbolic-addr' and improve the doc for some other + `set print's. + +Mon Jan 3 17:23:07 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (String Field): Talk about defining several type + numbers at once. + Fix lint regarding changing node ELF Transformations to + ELF and SOM Transformations. + +Fri Dec 31 00:42:43 1993 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Insert Peter Kessler's name as inventor (I think). + +Tue Dec 28 09:30:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Cross-References): `::' is for nested types only + within <>. + (Structures): Document static members. + +Mon Dec 27 13:55:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Document S type attribute. + +Sun Dec 26 20:46:36 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * stabs.texinfo: Add notes about stabs-in-som where appropriate. + +Fri Dec 3 19:13:19 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Fix a few typos. + +Sun Nov 28 18:06:25 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, remote.texi: formatting improvements + + * gdb.texinfo (New Features): mention threads. + (Summary, C): fix xrefs in newly contributed text. + (Threads): index entries, clarifications, example + (passim): minor typos fixed, phrasing improvements + + * remote.texi (Bootstrapping): rephrase text on ^C and add index + entries; (Server): explain use of gdbserver w/real-time systems, + add example of conflicting TCP port; (MIPS Remote) break up + running text into table, highlighting commands, and add example. + +Wed Nov 24 14:15:56 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * refcard.tex: avoid bad linebreaks even when REFEDITS=psrc.sed + +Fri Nov 12 16:10:58 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Nested Symbols): New node. + (String Field, Symbol Descriptors, Cross-References): Refer to it. + +Thu Nov 11 13:26:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs in ELF): Clarify how Bbss.bss work with respect + to picking which Bbss.bss symbol to use, and (because there seems to + be no good way of doing it) re-write some of the text to make it + sound like Bbss.bss isn't such a great idea after all (as currently + designed). + + * gdb.texinfo (C): In addition to saying people have to use g++ for + good results, say they have to use stabs. Specifically say cfront + doesn't work well. + (Summary): Merge in information on Modula-2, Pascal, and Chill from + the gdb README. Add xrefs to places where the support for the various + languages is described in detail. + +Mon Nov 8 11:47:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Clean up stuff about visibility and virtual + characters. + + * stabs.texinfo (N_M2C): Cite Sun doc. + +Fri Nov 5 16:27:27 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: updates re threads. + * remote.texinfo: avoid index entries starting with digits. + +Tue Nov 2 09:08:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Enumerations): Talk about large, negative and + octal values. Clean up cross reference to type attributes. + (String Field): Say that GDB 4.11 supports size attribute. + +Sun Oct 31 13:31:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.texi (VxWorks Remote): Clarify that rebuilding VxWorks kernel + is a mandatory step. Make the stuff about that more concise. + +Wed Oct 27 00:25:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Class Names): New node. + + * gdb.texinfo (Command Files): Explain order of init file reading. + + * remote.texi (Bootstrapping): Talk about getting the serial driver + to deal with ^C sent by gdb to stop the remote system. + +Mon Oct 25 03:25:41 1993 Tom Lord (lord@cygnus.com) + + * libgdb.texinfo (I/O): incorporated better phrasing from rich. + + * libgdb.texinfo (Defining Commands): made the DOC arg + to gdb_define_app_command a char * instead of char ** + per a suggestion from kingdon. + + * libgdb.texinfo: total rewrite from a different starting + premise. + +Wed Oct 20 18:07:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Local Variable Parameters): Re-write paragraph on + floats passed as doubles (to improve clarity). + +Tue Oct 19 14:21:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Source Path): index entries for $cwd, $pdir + + * a4rc.sed: update to work with Andreas Vogel papersize params + + * refcard.tex: use Andreas Vogel simplifications of papersize + params; remove useless version info; update copyright date. + +Tue Oct 19 10:46:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Symbols): Add class NAME to doc for ptype. + +Tue Oct 12 09:11:45 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Files): Say what address the load command loads it at. + + * stabs.texinfo (Common Blocks): Minor cleanups. + + * stabs.texinfo: Update ld stabs in elf relocation to reflect the fact + that Sun has backed away from the linker kludge and thus the relevant + issue is changes to the SunPRO tools, not the Solaris linker. + + * stabs.texinfo (Traditional Integer Types): Clean up description + of octal bounds a little bit. Document extra leading zeroes. + +Thu Oct 7 16:15:37 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Signaling): Update for symbolic symbol names + and add a section explaining the difference between the GDB + signal command and the shell kill utility. + +Wed Oct 6 13:23:01 1993 Tom Lord (lord@rtl.cygnus.com) + + * libgdb.texinfo: added `@' to braces that were unescaped. + +Mon Oct 4 10:42:18 1993 Tom Lord (lord@rtl.cygnus.com) + + * libgdb.texinfo: new file. Spec for the gdb library. + +Sun Oct 3 15:26:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Include Files): Fix typo (start -> end). + +Thu Sep 30 18:24:56 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, remote.texi: assorted small improvements, mostly + from Melissa at FSF's editing pass. + +Thu Sep 30 11:54:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo: Remove stuff about ar and 14 character filenames. + I believe this was fixed by the 13 Sep 89 change to print_frame_info. + Also, modern versions of ar like BSD 4.4 or SVR4 don't have this bug. + +Wed Sep 22 21:22:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * remote.texi (Bootstrapping): Discuss 386 call gates. + +Sat Sep 18 17:10:44 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * stabs.texinfo (Based Variables): New node. + +Thu Sep 16 17:48:55 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Re-write discussions of + names, sizes, and formats to suggest how not to lose. + +Sat Sep 11 09:35:11 1993 Jim Kingdon (kingdon@poseidon.cygnus.com) + + * stabs.texinfo (Methods): Fix typo. + +Fri Sep 10 06:34:20 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * gdb.texinfo: Fix a few typos. + +Wed Sep 8 09:11:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo: Clarify how well it works with Fortran. + + * stabs.texinfo (Stabs In ELF, Statics, ELF Transformations): + More on relocating stabs in ELF files. + +Tue Sep 7 13:45:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs In ELF): Talk about N_FUN value. + +Mon Sep 6 19:23:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Local Variable Parameters): Talk about nameless + parameters on VAX. + +Fri Sep 3 17:06:08 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: @up/@down -> @raisesections/@lowersections + +Fri Sep 3 12:04:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Make info author notice match the TeX author notice. + +Tue Aug 31 13:21:06 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * stabs.texinfo: Initial-caps all words in node names and + non-trivial words in section names. + +Mon Aug 30 11:13:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Many minor cleanups. + + * stabs.texinfo: Remove @deffn except from Expanded Reference node. + +Sat Aug 28 12:08:09 1993 David J. MacKenzie (djm@edison.eng.umd.edu) + + * stabs.texinfo: Remove full description of big example. + It's not really helpful; just use pieces of it where appropriate. + Add more Texinfo formatting directives (@samp, etc.). + Use @deffn to define stab types. + Eliminate some wordiness. Break up some nodes. + Add an (alphabetized) index of symbol types. + Use consistent capitalization style in node and section names. + +Thu Aug 26 06:36:31 1993 Fred Fish (fnf@deneb.cygnus.com) + + * gdb.texinfo: Change typo "Two two" to "The two". + +Sun Aug 22 12:15:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (XCOFF-differences): Remove references to + non-existent types N_DECL and N_RPSYM. + + * stabs.texinfo (String Field): Say that type attributes bug is + fixed in GDB 4.10, since it is. + + * stabs.texinfo: Clean up djm cleanups, and more cleanups of my own. + +Sat Aug 21 04:32:28 1993 David MacKenzie (djm@cygnus.com) + + * stabs.texinfo: Formatting cleanups. + +Fri Aug 20 20:49:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: When explaining the n_type of a stab, standardize + how we do it ('#' as a comment indicator, "36 is N_FUN" as text, + no tabs, use @r). + (Global Variables): Clean up. + +Tue Aug 17 15:57:27 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stack Variables): Re-write. + +Mon Aug 16 21:20:08 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs-in-elf): Talk about getting the start + addresses of a source file. Also revise formatting. + Change "object module" or "object file" to "source file". + Various: Miscellaneous cleanups. + +Thu Aug 12 15:11:51 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Point to mangling info in gcc's gpcompare.texi. + +Tue Aug 10 16:57:49 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * gdbint.texinfo: Removed many nonsensical machine-collected + host and target conditionals, described some of the remainder. + +Tue Aug 10 13:28:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo (Getting Started): Use @itemize, not @table. + + * gdbint.texinfo (Top): Add name to @top line, and re-write the + paragraph which follows. + + * gdbint.texinfo (Host): Use @code not @samp for Makefile + variables. Looks better and avoids overful hbox. + +Fri Jul 30 18:26:21 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Procedures): Improve stuff on nested functions. + +Thu Jul 29 15:10:58 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * remote.texi: (MIPS Remote) clearer doc for set/show timeout, + retransmit-timeout + +Thu Jul 29 13:16:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdbint.texinfo: Update statement about `some ancient Unix + systems, like Ultrix 4.0' to Ultrix 4.2. + +Wed Jul 28 15:26:53 1993 Roland H. Pesch (pesch@el_bosque.cygnus.com) + + * h8-cfg.texi, all-cfg.texi: new flag GDBSERVER + + * Makefile.in: depend on remote.texi rather than gdbinv-s.texi + + * remote.texi: (Server) New node on gdbserver. (Remote Serial, + ST2000 Remote, MIPS Remote): mention `host:port' syntax for TCP. + + * remote.texi: new name for former gdbinv-s.texi + + * gdb.texinfo: use remote.texi rather than gdbinv-s.texi + +Wed Jul 28 08:26:24 1993 Ian Lance Taylor (ian@cygnus.com) + + * gdbinv-s.texi: Documented timeout and retransmit-timeout + variables for MIPS remote debugging protocol. + +Mon Jul 26 13:00:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): FORTRAN LOGICAL fix. + +Tue Jul 20 16:30:41 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * Makefile.in (refcard.dvi): Use srcdir where necessary. + +Mon Jul 19 12:02:50 1993 Roland H. Pesch (pesch@cygnus.com) + + * gdb.texinfo: repair conditional bugs in text markup + +Fri Jul 16 18:57:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, all-cfg.texi, h8-cfg.texi: introduce MOD2 switch + to select Modula-2 material. + +Thu Jul 15 13:15:01 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Cleanups regarding statics. + + * gdbinv-s.texi (Bootstrapping): Document exceptionHandler. + (Debug Session): Mention exceptionHandler. Add xref to Bootstrapping. + +Mon Jul 12 13:37:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: N_MAIN is sometimes used for C. + +Fri Jul 9 09:47:02 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdbint.texinfo (Host, Target Conditionals): Remove TM_FILE_OVERRIDE. + +Tue Jul 6 12:41:28 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo (Target Conditionals): Remove NO_TYPEDEFS, + removed from the code by Kingdon. + +Tue Jul 6 12:24:34 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * gdb.texinfo (Break Commands): Remove stuff about flushing terminal + input when evaluating breakpoint conditions; the bug has been fixed. + + * gdb.texinfo (Continuing and Stepping): Argument to "continue" + sets the ignore count to N-1, not to N. + +Thu Jul 1 14:57:42 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * refcard.tex (\hoffset): correct longstanding error to match + intended offset; avoids cutting off edge on some printers + +Wed Jun 30 18:23:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Parameters): Say that order of stabs is significant. + +Fri Jun 25 21:34:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Common Blocks): Say what Sun FORTRAN does. + +Fri Jun 25 16:15:10 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * Makefile.in: (REFEDITS) new var to control whether PS or CM + fonts and whether US or A4 paper for GDB refcard; (refcard.dvi) + collect sed edits if any, apply to refcard before formatting; + (refcard.ps) stop implying PS fonts if PS output requested; + (lrefcard.ps) delete extra target for variant PS fonts + + * refcard.tex: parametrize papersize dependent info, collect + in easily replaced spot + + * a4rc.sed: new file, edits to refcard for A4 paper + +Fri Jun 25 14:21:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Type -16 is 4 bytes. + +Wed Jun 23 15:02:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Negative Type Numbers): Minor character cleanups. + +Tue Jun 22 16:31:52 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Express disapproval of 'D' symbol descriptor + politely rather than rudely. + +Fri Jun 18 19:42:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Document common blocks. + +Fri Jun 18 12:12:57 1993 Fred Fish (fnf@cygnus.com) + + * stabs.texinfo: Add some basic info about stabs-in-elf. + +Fri Jun 18 13:57:09 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Top): Minor cleanup. + +Mon Jun 14 16:16:51 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) + + * Makefile.in (install-info): remove parentdir support + +Tue Jun 15 18:11:39 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Copying): delete this node and references to it; + RMS says this manual need not carry GPL. (passim): Improvements + from last round at FSF, largely due to Ian Taylor review, and + minor formatting improvements. + + * gdbinv-s.texi (passim): Improvements from last round at FSF, + largely due to Ian Taylor review. (Debug Session): minor edits to + new text. + +Sun Jun 13 12:52:39 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (realclean): Remove info and dvi files too. + +Sat Jun 12 16:09:22 1993 Jim Kingdon (kingdon@cygnus.com) + + * {all,h8}-config.texi: Rename to *-cfg.texi for 14 char filenames. + * Makefile.in: Change accordingly. gdb-config.texi -> gdb-cfg.texi. + * gdb.texinfo: Change accordingly. + + * stabs.texinfo: Clean up N_{L,R}BRAC. Discuss what addresses of + N_{L,R}BRAC,N_SLINE are relative to. + +Fri Jun 11 15:15:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (GDBvn.texi): Update atomically. + +Wed Jun 9 10:58:16 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbinv-s.texi (Debug Session): Document exceptionHook. + +Tue Jun 8 13:42:04 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdb.texinfo (Print Settings): Move all stuff relating to symbolic + addresses together. Also motivate the set print symbol-filename + command and suggest other solutions. + +Tue Jun 1 22:46:43 1993 Fred Fish (fnf@cygnus.com) + + * gdb.texinfo (set print elements): Note that the number of + elements is set to unlimited by "set print elements 0". + +Mon May 31 08:06:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Builtin Type Descriptors): Try to clarify what + NF_LDOUBLE means. + (Stab Types): Include Solaris stab types. + (Procedures): Document Solaris extensions. + +Thu May 27 06:20:42 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * gdb.texinfo: Add `set print symbol-filename' doc. + +Wed May 26 00:26:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Arrays): Talk about type definition vs. type + information. + + * stabs.texinfo (Builtin Type Descriptors): Talk about omitting + the trailing semicolon. + +Tue May 25 14:49:42 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Line Numbers, Source Files): Re-write these two nodes + and merge in other parts of the document addressing these subjects. + gdbint.texinfo (XCOFF): Remove info which is now in stabs.texinfo. + + * stabs.texinfo (Subranges, Arrays): Try to explain about the semicolon + at the end of a range type. + + * stabs.texinfo (Subranges): "A offset" and "T offset" are not + AIX extensions. + +Mon May 24 09:00:33 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Stabs Format): Misc fixes. + +Sat May 22 10:40:56 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Constants): Allow an `e' constant to be non-enum. + (Traditional builtin types): Document convex convention for long long. + (Negative builtin types): Discuss type names, and misc fixes. + +Fri May 21 11:20:31 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Builtin Type Descriptors): Document the floating + point types used with @samp{R} type descriptor. + (Symbol Descriptors): Describe how to handle conflict between + different meanings of @samp{P} symbol descriptor. + +Thu May 20 13:35:10 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo: Remove node Quick Reference and put its children + directly under the main menu. + + * stabs.texinfo: Many more changes to bring it into line with + AIX documentation and reality. I think it now has all the + information from the AIX documentation, except that I burned + out when I got to variant records (Pascal and Modula-2) and + all the COBOL types. Oh well, we can add them later when we're + worrying more about those languages. + + * stabs.texinfo (Automatic variables): Talk about what it means + to omit the symbol descriptor. + +Tue May 18 17:59:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stabs.texinfo (Parameters): Add "(sometimes)" when describing + gcc2 behavior with promoted args. + +Fri May 14 21:35:29 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: include readline appendices in info version of manual + +Fri May 7 11:56:18 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi (Remote Serial): describe new ^C behavior in + target remote. + + * gdb.texinfo (Machine Code): more index entries for disassemble + +Fri May 7 10:12:30 1993 Fred Fish (fnf@cygnus.com) + + * Clarify the intended use of the gdb-testers and gdb-patches + mailing lists, and shrink gzip comment. + +Thu May 6 16:39:50 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo (Shell Commands): do not mention SHELL env var in + DOSHOST configuration of manual. + + * gdb.texinfo (MIPS Stack): new node. + + * all-config.texi (MIPS) new switch. + + * gdbinv-s.texi (Nindy Options) Remove two instances of future + tense; (MIPS Remote) new node. + + * gdb.texinfo (passim) rephrases to work around makeinfo @value + bug; (Environment) less passive, other small cleanups in text about + .cshrc/.bashrc; (Invoking GDB) new MIPS Remote menu entry; + (Remote) new MIPS Remote menu entry. + +Thu Apr 29 09:36:25 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Many changes to include information from the + AIX documentation. + + * gdb.texinfo (Environment): Mention pitfall with .cshrc. + +Tue Apr 27 14:02:57 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbint.texinfo (new node Debugging GDB, elsewhere): + Move a bunch of information from ../README. + (Getting Started): New node. + +Fri Apr 23 17:21:13 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi, gdb.texinfo: include Hitachi SH target + + * gdb.texinfo: advance manual revision dates to present + + * gdbinv-s.texi, gdb.texinfo, all-config.texi, h8-config.texi: + stop using silly Roman numerals in @set variable names + +Fri Apr 23 07:30:01 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): Keep trying to get this right. + +Wed Apr 21 15:18:47 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): More on "local parameters". + +Mon Apr 19 08:00:51 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Parameters): Re-do "local parameters" section. + +Sun Apr 18 09:47:45 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo (Symbol descriptors): Re-do using @table and @xref. + (Parameters): Rewrite. + (xcoff-differences, Sun-differences): Minor changes. + +Thu Apr 15 02:35:24 1993 John Gilmore (gnu@cacophony.cygnus.com) + + * stabs.texinfo: Minor cleanup. + +Wed Apr 14 17:31:00 1993 Jim Kingdon (kingdon@cygnus.com) + + * gdbint.texinfo: Minor xcoff stuff. + +Wed Apr 7 14:11:07 1993 Fred Fish (fnf@cygnus.com) + + * gdbint.texinfo: Update for new config directory structure. + Add info about internal type data structures. + +Mon Apr 5 09:06:30 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in (SFILES_INCLUDED): gdb-config.texi is no longer in + $(srcdir). + (gdb-config.texi): Depend on file in $(srcdir). + +Fri Apr 2 16:55:13 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Fixes about N_SO. + +Fri Mar 26 18:00:35 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: include list of nonstandard init file names + + * *-config.texi: new switch GENERIC for text that applies *only* + to (usual) multiple-target version of manual + + * gdb.texinfo, gdbinv-s.texi: Update conditional markup to correct + h8 config + + * gdb.texinfo: depend on latest fixed makeinfo, use conditionals + in menus (rather than conditionally selected multiple alternative + menus). + + * Makefile.in: define and use DOC_CONFIG var to select + configuration for GDB user manual. + + * gdb-config.texi: delete from repository, generate from Makefile. + + * all-config.texi: normal `generic' configuration file, formerly + stored as gdb-config.texi + +Wed Mar 24 14:03:19 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: add dvi target to build all .dvi files + +Tue Mar 23 16:03:24 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdvinv-s.texinfo: formatting improvements. + +Fri Mar 19 21:46:50 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Doc NO_MMALLOC and NO_MMALLOC_CHECK as + host conditionals. + * stabs.texinfo: More array fixes inspired by Jim's. + +Fri Mar 19 10:23:34 1993 Jim Kingdon (kingdon@cygnus.com) + + * stabs.texinfo: Fixes re arrays and continuations. + + * gdbint.texinfo: Add XCOFF node. + +Mon Mar 8 15:52:18 1993 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Add `set print max-symbolic-offset' doc. + +Sun Feb 21 17:09:38 1993 Per Bothner (bothner@rtl.cygnus.com) + + * stabs.texinfo: Fix for array types to mention lower bounds. + +Thu Feb 18 01:19:49 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Update PTRACE_ARG3_TYPE doc, pull PT_*. + +Wed Feb 17 08:15:24 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Remove SET_STACK_LIMIT_HUGE from target defines. + +Thu Feb 11 10:38:40 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Fix thinko (NM_FILE => NAT_FILE). Found + by Michael Ben-Gershon . + +Wed Feb 10 23:59:19 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Eliminate IBM6000_HOST, document IBM6000_TARGET. + +Tue Feb 9 18:26:21 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdbinv-s.texi: misc updates + +Sat Feb 6 10:25:47 1993 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Brief documentation for longjmp support, + from an email msg by Stu. + +Fri Feb 5 14:10:15 1993 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Fix description of floating point "range" + types (which really define basic types). Reported by Jim Meehan, + . + + * gdbint.texinfo: Remove COFF_NO_LONG_FILE_NAMES define, now gone. + +Thu Feb 4 13:56:46 1993 Ian Lance Taylor (ian@cygnus.com) + + * gdbint.texinfo: Slightly expand section on supporting a new + object file format. + +Thu Feb 4 01:49:04 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in (refcard.ps, lrefcard.ps): Remove psref.tex + intermediate file. + +Tue Feb 2 12:18:06 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, gdbinv-s.texi: miscellaneous stylistic cleanups + +Mon Feb 1 15:35:47 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.texi: z8000 simulator target name is just "sim" + + * gdbinv-s.texi: Mention that Z8000 simulator can simulate Z8001 + as well as Z8002. + +Sat Nov 28 06:51:35 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add sections on clean design and on how to send + in changes. + +Mon Nov 9 23:57:02 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add how to declare the result of make_cleanup. + +Mon Oct 26 11:09:47 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Fix typo, reported by Karl Berry. + +Fri Oct 23 00:41:21 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo: Add opcodes dir to GDB distribution description. + +Sat Oct 10 18:04:58 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * gdbint.texinfo: fixed a stray email address (needs @@), + added @table @code to node "Native Conditionals" + +Tue Sep 22 00:34:15 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Describe coding style of GDB. + +Mon Sep 21 19:32:16 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Minor wording changes. + +Tue Sep 15 02:57:09 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Improve release doc slightly. + +Fri Sep 11 01:34:25 1992 John Gilmore (gnu@sphagnum.cygnus.com) + + * gdbint.texinfo: Improve doc of GDB config macros. + +Wed Sep 9 16:52:06 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Remove Bothner's changes for C++ nested types. + These will be reinserted when examined. + +Mon Aug 24 01:17:55 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Make a start at documenting all the #if macros + in GDB. At least list them all, and start separating them into + host-specific and target-specific. + +Tue Aug 18 15:59:13 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdbinv-s.m4.in: refrain from using @cartouche for just a few + examples (not consistent w others). + gdb.texinfo: issue disclaimer paragraph on cmdline options only + for generic vn of doc + +Tue Aug 18 14:53:27 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: always create installation directories. + +Tue Aug 18 14:11:50 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: in h8 config, do not describe searching commands. + +Mon Aug 17 18:07:59 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo, none.m4, h8.m4, gdbinv-s.m4.in: improve H8/300 + conditionals; introduce a few generic switches that may be + useful for other cross-dev or dos-hosted configs. + + * gdb.texinfo: fix typo in "info reg" description + +Sun Aug 16 01:16:18 1992 John Gilmore (gnu@cygnus.com) + + * stabs.texinfo: Minor updates from running TeX over it. + * Makefile.in (stabs.dvi, stabs.ps): Add. + +Sat Aug 15 20:52:24 1992 Per Bothner (bothner@rtl.cygnus.com) + + * stabs.texinfo: Stabs documentation, written by Julia Menapace. + First pass at converting it to texinfo. + +Sat Aug 15 03:14:59 1992 John Gilmore (gnu@cygnus.com) + + * gdb.texinfo, refcard.tex: Document mult args on `info reg'. + * Makefile.in (refcard.ps, lrefcard.ps): Add missing $(srdir). + +Fri Aug 14 21:08:47 1992 John Gilmore (gnu@cygnus.com) + + * gdbint.texinfo: Add section on partial symbol tables. + +Sat Jun 20 16:31:10 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: document `set remotedebug' and `set + rstack_high_address'. + +Thu May 14 17:09:48 1992 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * gdb.texinfo: slight expansion of new text on reading info files + * gdbinv-s.m4.in: correct and expand info on cross-debugging + H8/300 from DOS. + +Tue May 12 12:22:47 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: `info user' => `show user'. Noticed by David Taylor. + +Mon May 11 19:06:27 1992 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: Say how to read the `info' files. + +Tue May 5 12:11:38 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: gm4 -> m4. + +Fri Apr 10 17:50:43 1992 John Gilmore (gnu at rtl.cygnus.com) + + * gdb.texinfo: Update for GDB-4.5. Move `Formatting + Documentation' ahead of `Installing GDB' to match README. + Update shared library doc, -readnow and -mapped, and directory + structure (add glob and mmalloc). Update configure doc. + +Tue Mar 24 23:28:38 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: remove $(srcdir) from gdb.info rule. + +Sat Mar 7 18:44:50 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * Makefile.in: commented out gdb-all.texinfo rule. This is + temporary. + +Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in: removed traces of namesubdir, + -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced + copyrights to '92, changed some from Cygnus to FSF. + +Fri Dec 13 09:47:31 1991 John Gilmore (gnu at cygnus.com) + + * gdb.texinfo: Improve how we ask for bug reports. + +Tue Dec 10 04:07:21 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: infodir belongs in datadir. + +Fri Dec 6 23:57:34 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: remove spaces following hyphens, bsd make can't + cope. install using INSTALL_DATA. added clean-info. added + standards.text support. + +Thu Dec 5 22:46:12 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: idestdir and ddestdir go away. Added copyrights + and shift gpl to v2. Added ChangeLog if it didn't exist. docdir + and mandir now keyed off datadir by default. + + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/gdb/doc/GDBvn.texi b/contrib/gdb/gdb/doc/GDBvn.texi new file mode 100644 index 000000000000..f90e24dfe8d7 --- /dev/null +++ b/contrib/gdb/gdb/doc/GDBvn.texi @@ -0,0 +1 @@ +@set GDBVN 4.16 diff --git a/contrib/gdb/gdb/doc/Makefile.in b/contrib/gdb/gdb/doc/Makefile.in new file mode 100644 index 000000000000..385b44457ceb --- /dev/null +++ b/contrib/gdb/gdb/doc/Makefile.in @@ -0,0 +1,331 @@ +##Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +# Makefile for GDB documentation. +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +srcdir = . + +prefix = /usr/local + +infodir = $(prefix)/info + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +# main GDB source directory +gdbdir = $(srcdir)/.. + +# where to find texinfo; GDB dist should include a recent one +TEXIDIR=${gdbdir}/../texinfo + +# where to find makeinfo, preferably one designed for texinfo-2 +MAKEINFO=makeinfo + +# where to find texi2roff, ditto +TEXI2ROFF=texi2roff + +# Where is the source dir for the READLINE library doc? +# Traditionally readline is in .. or . +READLINE_DIR = ${gdbdir}/../readline/doc + +SET_TEXINPUTS = TEXINPUTS=${TEXIDIR}:.:$(srcdir):$(READLINE_DIR):$$TEXINPUTS + +# There may be alternate predefined collections of switches to configure +# the GDB manual. Normally this is not done in synch with the software +# config system, since this choice tends to be independent; most people +# want a doc config of `all' for a generic manual, regardless of sw config. +DOC_CONFIG = all + +# This list of sed edits will edit the GDB reference card +# for what fonts and what papersize to use. +# By default (NO edits applied), the refcard uses: +# - Computer Modern (CM) fonts +# - US letter paper (8.5x11in) +# List some of the following files for alternative fonts and paper: +# a4rc.sed use A4 paper (297 x 210 mm) +# psrc.sed use PostScript fonts (Karl Berry short TeX names) +# lpsrc.sed use PostScript fonts (full PostScript names in TeX) +# e.g. for A4, Postscript: REFEDITS = a4rc.sed psrc.sed +# for A4, CM fonts: REFEDITS = a4rc.sed +# for US, PS fonts: REFEDITS = psrc.sed +# for default: +REFEDITS = + +# Don Knuth's TeX formatter +TEX = tex + +# auxiliary program for sorting Texinfo indices +TEXINDEX = texindex + +# Main GDB manual's source files +SFILES_INCLUDED = gdb-cfg.texi $(srcdir)/remote.texi + +SFILES_LOCAL = $(srcdir)/gdb.texinfo GDBvn.texi $(SFILES_INCLUDED) + +SFILES_DOC = $(SFILES_LOCAL) \ + $(READLINE_DIR)/rluser.texinfo $(READLINE_DIR)/inc-hist.texi + +#### Host, target, and site specific Makefile fragments come in here. +### + +all install: + +info: gdb.info gdbint.info stabs.info +dvi: gdb.dvi refcard.dvi gdbint.dvi +all-doc: gdb.info gdb.dvi refcard.dvi gdb-internals gdbint.dvi + +install-info: info + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +STAGESTUFF = *.info* gdb-all.texi GDBvn.texi + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done + +de-stage1: force + -(cd stage1 ; mv -f * ..) + -rmdir stage1 + +de-stage2: force + -(cd stage2 ; mv -f * ..) + -rmdir stage2 + +de-stage3: force + -(cd stage3 ; mv -f * ..) + -rmdir stage3 + +clean-info: + rm -f gdb.info* gdbint.info* stabs.info* + +clean-dvi: + rm -f gdb.dvi gdbint.dvi stabs.dvi sedref.dvi + +mostlyclean: clean-info clean-dvi + rm -f gdb.?? gdb.??? gdb.mm gdb.ms gdb.me + rm -f links2roff + rm -f refcard.ps lrefcard.ps refcard.log sedref.* *~ + rm -f gdbint.?? gdbint.??? stabs.?? stabs.??? + +clean: mostlyclean + rm -f rluser.texinfo inc-hist.texi gdb-cfg.texi + +distclean: clean + rm -f Makefile config.status + +# GDBvn.texi and refcard.dvi are distributed, so they should not be +# removed by "clean" or "distclean". +maintainer-clean realclean: distclean clean-dvi clean-info + rm -f GDBvn.texi refcard.dvi + +# GDB QUICK REFERENCE (dvi output) +refcard.dvi : refcard.tex $(REFEDITS) + if [ -z "$(REFEDITS)" ]; then \ + cp $(srcdir)/refcard.tex sedref.tex ; \ + else \ + echo > tmp.sed ; \ + for f in "$(REFEDITS)" ; do \ + cat $(srcdir)/$$f >>tmp.sed ; done ; \ + sed -f tmp.sed $(srcdir)/refcard.tex >sedref.tex ; \ + fi + $(SET_TEXINPUTS) $(TEX) sedref.tex + mv sedref.dvi refcard.dvi + rm -f sedref.log sedref.tex tmp.sed + +refcard.ps : refcard.dvi + dvips -t landscape refcard.dvi -o + +# File to record current GDB version number (copied from main dir Makefile.in) +GDBvn.texi : ${gdbdir}/Makefile.in + echo "@set GDBVN `sed <$(srcdir)/../Makefile.in -n 's/VERSION = //p'`" > ./GDBvn.new + mv GDBvn.new GDBvn.texi + +# Updated atomically +.PRECIOUS: GDBvn.texi + +# Choose configuration for GDB manual (normally `all'; normally not tied into +# `configure' script because most users prefer generic version of manual, +# not one for their binary config---which may not be specifically +# defined anyways). +gdb-cfg.texi: ${srcdir}/${DOC_CONFIG}-cfg.texi + ln -s ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + ln ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi || \ + cp ${srcdir}/${DOC_CONFIG}-cfg.texi gdb-cfg.texi + +# GDB MANUAL: texinfo source, using @set/@clear/@value/@ifset/@ifclear +# If your texinfo or makeinfo don't support these, get a new texinfo release +# +# The nonsense with GDBvn.texi gets this to run with both Sun and GNU make. +# Note that we can *generate* GDBvn.texi, but since we distribute one in the +# source directory for the benefit of people who *don't* use this makefile, +# VPATH will often tell make not to bother building it, because the one +# in the srcdir is up to date. (if not, then make should build one here). + +# GDB MANUAL: TeX dvi file +gdb.dvi: ${SFILES_DOC} + if [ ! -f ./GDBvn.texi ]; then \ + ln -s $(srcdir)/GDBvn.texi . || \ + ln $(srcdir)/GDBvn.texi . || \ + cp $(srcdir)/GDBvn.texi . ; else true; fi + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + $(TEXINDEX) gdb.?? + $(SET_TEXINPUTS) $(TEX) gdb.texinfo + rm -f gdb.?? gdb.log gdb.aux gdb.toc gdb.??s + +# GDB MANUAL: info file +# We're using texinfo2, and older makeinfo's may not be able to +# cope with all the markup. +gdb.info: ${SFILES_DOC} + $(MAKEINFO) -I ${READLINE_DIR} -I $(srcdir) -o ./gdb.info gdb.texinfo + +# GDB MANUAL: roff translations +# Try to use a recent texi2roff. v2 was put on prep in jan91. +# If you want an index, see texi2roff doc for postprocessing +# and add -i to texi2roff invocations below. +# Workarounds for texi2roff-2 (probably fixed in later texi2roff's, delete +# corresponding -e lines when later texi2roff's are current) +# + @ifinfo's deleted explicitly due to texi2roff-2 bug w nested constructs. +# + @c's deleted explicitly because texi2roff sees texinfo commands in them +# + @ (that's at-BLANK) not recognized by texi2roff, turned into blank +# + @alphaenumerate is ridiculously new, turned into @enumerate + +# texi2roff doesn't have a notion of include dirs, so we have to fake +# it out for gdb manual's include files---but only if not configured +# in main sourcedir. +links2roff: $(SFILES_INCLUDED) + if [ ! -f gdb.texinfo ]; then \ + ln -s $(SFILES_INCLUDED) . || \ + ln $(SFILES_INCLUDED) . || \ + cp $(SFILES_INCLUDED) . ; \ + fi + touch links2roff + +# "Readline" appendices. Get them also due to lack of includes, +# regardless of whether or not configuring in main sourcedir. +# @ftable removed due to bug in texi2roff-2; if your texi2roff +# is newer, try just ln or cp +rluser.texinfo: ${READLINE_DIR}/rluser.texinfo + sed -e 's/^@ftable/@table/g' \ + -e 's/^@end ftable/@end table/g' \ + ${READLINE_DIR}/rluser.texinfo > ./rluser.texinfo + +inc-hist.texi: ${READLINE_DIR}/inc-hist.texi + ln -s ${READLINE_DIR}/inc-hist.texi . || \ + ln ${READLINE_DIR}/inc-hist.texi . || \ + cp ${READLINE_DIR}/inc-hist.texi . + +# gdb manual suitable for [gtn]roff -me +gdb.me: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -me | \ + sed -e 's/---/\\(em/g' \ + >gdb.me + +# gdb manual suitable for [gtn]roff -ms +gdb.ms: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -ms | \ + sed -e 's/---/\\(em/g' \ + >gdb.ms + +# gdb manual suitable for [tn]roff -mm +# '@noindent's removed due to texi2roff-2 mm bug; if yours is newer, +# try leaving them in +gdb.mm: $(SFILES_LOCAL) links2roff rluser.texinfo inc-hist.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e '/^@ifinfo/,/^@end ifinfo/d' \ + -e '/^@c /d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + -e 's/@ / /g' \ + -e 's/^@alphaenumerate/@enumerate/g' \ + -e 's/^@end alphaenumerate/@end enumerate/g' \ + $(srcdir)/gdb.texinfo | \ + $(TEXI2ROFF) -mm | \ + sed -e 's/---/\\(em/g' \ + >gdb.mm + + +# GDB INTERNALS MANUAL: TeX dvi file +gdbint.dvi : gdbint.texinfo + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + $(TEXINDEX) gdbint.?? + $(SET_TEXINPUTS) $(TEX) gdbint.texinfo + rm -f gdbint.?? gdbint.aux gdbint.cps gdbint.fns gdbint.kys \ + gdbint.log gdbint.pgs gdbint.toc gdbint.tps gdbint.vrs + +# GDB INTERNALS MANUAL: info file +gdb-internals: gdbint.info + +gdbint.info: gdbint.texinfo + $(MAKEINFO) -o gdbint.info $(srcdir)/gdbint.texinfo + +stabs.info: stabs.texinfo + $(MAKEINFO) -o stabs.info $(srcdir)/stabs.texinfo + +# STABS DOCUMENTATION: TeX dvi file +stabs.dvi : stabs.texinfo + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + $(TEXINDEX) stabs.?? + $(SET_TEXINPUTS) $(TEX) stabs.texinfo + rm -f stabs.?? stabs.aux stabs.cps stabs.fns stabs.kys \ + stabs.log stabs.pgs stabs.toc stabs.tps stabs.vrs + +stabs.ps: stabs.dvi + dvips -o stabs.ps stabs + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status diff --git a/contrib/gdb/gdb/doc/a4rc.sed b/contrib/gdb/gdb/doc/a4rc.sed new file mode 100644 index 000000000000..22922904efc9 --- /dev/null +++ b/contrib/gdb/gdb/doc/a4rc.sed @@ -0,0 +1,11 @@ +/--- Papersize params:/,/--- end papersize params/c\ +%------- Papersize params:\ +%% A4 paper (297x210mm)\ +%%\ +\\totalwidth=297mm % total width of paper\ +\\totalheight=210mm % total height of paper\ +\\hmargin=5mm % horizontal margin width\ +\\vmargin=10mm % vertical margin width\ +\\secskip=.6pc % space between refcard secs\ +\\lskip=1pt % extra skip between \\sec entries\ +%------- end papersize params diff --git a/contrib/gdb/gdb/doc/all-cfg.texi b/contrib/gdb/gdb/doc/all-cfg.texi new file mode 100644 index 000000000000..5b549c26c8c3 --- /dev/null +++ b/contrib/gdb/gdb/doc/all-cfg.texi @@ -0,0 +1,120 @@ +@c GDB MANUAL configuration file. +@c Copyright (c) 1993 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 +@c source configuration---because the authors expect that, save in +@c unusual cases, the most inclusive form of the manual is appropriate +@c no matter how the program itself is configured. +@c +@c The only automatically-varying variable is the GDB version number, +@c which the Makefile rewrites based on the VERSION variable from +@c `../Makefile.in'. +@c +@c GDB version number is recorded in the variable GDBVN +@include GDBvn.texi +@c +@c ---------------------------------------------------------------------- +@c PLATFORM FLAGS: +@set GENERIC +@c +@c Hitachi H8/300 target: +@set H8 +@c Hitachi H8/300 target ONLY: +@clear H8EXCLUSIVE +@c +@c remote MIPS target: +@set MIPS +@c +@c SPARC target: +@set SPARC +@c +@c AMD 29000 target: +@set AMD29K +@c +@c Intel 960 target: +@set I960 +@c +@c Tandem ST2000 (phone switch) target: +@set ST2000 +@c +@c Zilog 8000 target: +@set Z8K +@c +@c Lucid "Energize" environment: +@clear LUCID +@c +@c Wind River Systems VxWorks environment: +@set VXWORKS +@c +@c ---------------------------------------------------------------------- +@c DOC FEATURE FLAGS: +@c +@c Include change-from-old? +@set NOVEL +@c +@c Bare-board target? +@clear BARETARGET +@c +@c Restrict languages discussed to C? +@c This is backward. As time permits, change this to language-specific +@c switches for what to include. +@clear CONLY +@c Discuss Fortran? +@set FORTRAN +@c +@c Discuss Modula 2? +@set MOD2 +@c +@c Specifically for host machine running DOS? +@clear DOSHOST +@c +@c Talk about CPU simulator targets? +@set SIMS +@c +@c Is manual stand-alone, or part of an agglomeration, with overall GPL? +@clear AGGLOMERATION +@c +@c Remote serial line settings of interest? +@set SERIAL +@c +@c Discuss features requiring Posix or similar OS environment? +@set POSIX +@c +@c Discuss remote serial debugging stub? +@set REMOTESTUB +@c +@c Discuss gdbserver? +@set GDBSERVER +@c +@c Discuss gdbserve.nlm? +@set GDBSERVE +@c +@c Refrain from discussing how to configure sw and format doc? +@clear PRECONFIGURED +@c +@c Refrain from referring to unfree publications? +@set FSFDOC +@c +@c ---------------------------------------------------------------------- +@c STRINGS: +@c +@c Name of GDB program. Used also for (gdb) prompt string. +@set GDBP gdb +@c +@c Name of GDB product. Used in running text. +@set GDBN GDB +@c +@c Name of GDB initialization file. +@set GDBINIT .gdbinit +@c +@c Name of host. Should not be used in generic configs, but generic +@c value may catch some flubs. +@set HOST machine specific +@c +@c Name of GCC product +@set NGCC GCC +@c +@c Name of GCC program +@set GCC gcc + diff --git a/contrib/gdb/gdb/doc/annotate.texi b/contrib/gdb/gdb/doc/annotate.texi new file mode 100644 index 000000000000..9d5850dbf21c --- /dev/null +++ b/contrib/gdb/gdb/doc/annotate.texi @@ -0,0 +1,717 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename annotate.info +@settitle GDB Annotations +@setchapternewpage off +@c %**end of header + +@set EDITION 0.5 +@set DATE May 1994 + +@ifinfo +This file documents GDB annotations. + +This is Edition @value{EDITION}, @value{DATE}, of @cite{GDB +Annotations}. Copyright 1994 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@titlepage +@title GDB Annotations +@subtitle Edition @value{EDITION} +@subtitle @value{DATE} +@author Cygnus Support +@page +@vskip 0pt plus 1filll +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Copyright @copyright{} 1994 Free Software Foundation +@end titlepage + +@ifinfo +@node Top +@top GDB Annotations + +This file describes annotations in GDB, the GNU symbolic debugger. +Annotations are designed to interface GDB to graphical user interfaces +or other similar programs which want to interact with GDB at a +relatively high level. + +This is Edition @value{EDITION}, @value{DATE}. + +@menu +* General:: What annotations are; the general syntax. +* Server:: Issuing a command without affecting user state. +* Values:: Values are marked as such. +* Frames:: Stack frames are annotated. +* Displays:: GDB can be told to display something periodically. +* Prompting:: Annotations marking GDB's need for input. +* Errors:: Annotations for error messages. +* Breakpoint Info:: Information on breakpoints. +* Invalidation:: Some annotations describe things now invalid. +* Running:: Whether the program is running, how it stopped, etc. +* Source:: Annotations describing source code. +* TODO:: Annotations which might be added in the future. +* Index:: Index +@end menu +@end ifinfo + +@node General +@chapter What is an Annotation? + +To produce annotations, start GDB with the @code{--annotate=2} option. + +Annotations start with a newline character, two @samp{control-z} +characters, and the name of the annotation. If there is no additional +information associated with this annotation, the name of the annotation +is followed immediately by a newline. If there is additional +information, the name of the annotation is followed by a space, the +additional information, and a newline. The additional information +cannot contain newline characters. + +Any output not beginning with a newline and two @samp{control-z} +characters denotes literal output from GDB. Currently there is no need +for GDB to output a newline followed by two @samp{control-z} characters, +but if there was such a need, the annotations could be extended with an +@samp{escape} annotation which means those three characters as output. + +A simple example of starting up GDB with annotations is: + +@example +$ gdb --annotate=2 +GDB is free software and you are welcome to distribute copies of it + under certain conditions; type "show copying" to see the conditions. +There is absolutely no warranty for GDB; type "show warranty" for details. +GDB 4.12.3 (sparc-sun-sunos4.1.3), +Copyright 1994 Free Software Foundation, Inc. + +^Z^Zpre-prompt +(gdb) +^Z^Zprompt +quit + +^Z^Zpost-prompt +$ +@end example + +Here @samp{quit} is input to GDB; the rest is output from GDB. The three +lines beginning @samp{^Z^Z} (where @samp{^Z} denotes a @samp{control-z} +character) are annotations; the rest is output from GDB. + +@node Server +@chapter The Server Prefix + +To issue a command to GDB without affecting certain aspects of the state +which is seen by users, prefix it with @samp{server }. This means that +this command will not affect the command history, nor will it affect +GDB's notion of which command to repeat if @key{RET} is pressed on a +line by itself. + +The server prefix does not affect the recording of values into the value +history; to print a value without recording it into the value history, +use the @code{output} command instead of the @code{print} command. + +@node Values +@chapter Values + +When a value is printed in various contexts, GDB uses annotations to +delimit the value from the surrounding text. + +@findex value-history-begin +@findex value-history-value +@findex value-history-end +If a value is printed using @code{print} and added to the value history, +the annotation looks like + +@example +^Z^Zvalue-history-begin @var{history-number} @var{value-flags} +@var{history-string} +^Z^Zvalue-history-value +@var{the-value} +^Z^Zvalue-history-end +@end example + +where @var{history-number} is the number it is getting in the value +history, @var{history-string} is a string, such as @samp{$5 = }, which +introduces the value to the user, @var{the-value} is the output +corresponding to the value itself, and @var{value-flags} is @samp{*} for +a value which can be dereferenced and @samp{-} for a value which cannot. + +@findex value-begin +@findex value-end +If the value is not added to the value history (it is an invalid float +or it is printed with the @code{output} command), the annotation is similar: + +@example +^Z^Zvalue-begin @var{value-flags} +@var{the-value} +^Z^Zvalue-end +@end example + +@findex arg-begin +@findex arg-name-end +@findex arg-value +@findex arg-end +When GDB prints an argument to a function (for example, in the output +from the @code{backtrace} command), it annotates it as follows: + +@example +^Z^Zarg-begin +@var{argument-name} +^Z^Zarg-name-end +@var{separator-string} +^Z^Zarg-value @var{value-flags} +@var{the-value} +^Z^Zarg-end +@end example + +where @var{argument-name} is the name of the argument, +@var{separator-string} is text which separates the name from the value +for the user's benefit (such as @samp{=}), and @var{value-flags} and +@var{the-value} have the same meanings as in a +@code{value-history-begin} annotation. + +@findex field-begin +@findex field-name-end +@findex field-value +@findex field-end +When printing a structure, GDB annotates it as follows: + +@example +^Z^Zfield-begin @var{value-flags} +@var{field-name} +^Z^Zfield-name-end +@var{separator-string} +^Z^Zfield-value +@var{the-value} +^Z^Zfield-end +@end example + +where @var{field-name} is the name of the field, @var{separator-string} +is text which separates the name from the value for the user's benefit +(such as @samp{=}), and @var{value-flags} and @var{the-value} have the +same meanings as in a @code{value-history-begin} annotation. + +When printing an array, GDB annotates it as follows: + +@example +^Z^Zarray-section-begin @var{array-index} @var{value-flags} +@end example + +where @var{array-index} is the index of the first element being +annotated and @var{value-flags} has the same meaning as in a +@code{value-history-begin} annotation. This is followed by any number +of elements, where is element can be either a single element: + +@findex elt +@example +@samp{,} @var{whitespace} ; @r{omitted for the first element} +@var{the-value} +^Z^Zelt +@end example + +or a repeated element + +@findex elt-rep +@findex elt-rep-end +@example +@samp{,} @var{whitespace} ; @r{omitted for the first element} +@var{the-value} +^Z^Zelt-rep @var{number-of-repititions} +@var{repetition-string} +^Z^Zelt-rep-end +@end example + +In both cases, @var{the-value} is the output for the value of the +element and @var{whitespace} can contain spaces, tabs, and newlines. In +the repeated case, @var{number-of-repititons} is the number of +consecutive array elements which contain that value, and +@var{repetition-string} is a string which is designed to convey to the +user that repitition is being depicted. + +@findex array-section-end +Once all the array elements have been output, the array annotation is +ended with + +@example +^Z^Zarray-section-end +@end example + +@node Frames +@chapter Frames + +Whenever GDB prints a frame, it annotates it. For example, this applies +to frames printed when GDB stops, output from commands such as +@code{backtrace} or @code{up}, etc. + +@findex frame-begin +The frame annotation begins with + +@example +^Z^Zframe-begin @var{level} @var{address} +@var{level-string} +@end example + +where @var{level} is the number of the frame (0 is the innermost frame, +and other frames have positive numbers), @var{address} is the address of +the code executing in that frame, and @var{level-string} is a string +designed to convey the level to the user. @var{address} is in the form +@samp{0x} followed by one or more lowercase hex digits (note that this +does not depend on the language). The frame ends with + +@findex frame-end +@example +^Z^Zframe-end +@end example + +Between these annotations is the main body of the frame, which can +consist of + +@itemize @bullet +@item +@findex function-call +@example +^Z^Zfunction-call +@var{function-call-string} +@end example + +where @var{function-call-string} is text designed to convey to the user +that this frame is associated with a function call made by GDB to a +function in the program being debugged. + +@item +@findex signal-handler-caller +@example +^Z^Zsignal-handler-caller +@var{signal-handler-caller-string} +@end example + +where @var{signal-handler-caller-string} is text designed to convey to +the user that this frame is associated with whatever mechanism is used +by this operating system to call a signal handler (it is the frame which +calls the signal handler, not the frame for the signal handler itself). + +@item +A normal frame. + +@findex frame-address +@findex frame-address-end +This can optionally (depending on whether this is thought of as +interesting information for the user to see) begin with + +@example +^Z^Zframe-address +@var{address} +^Z^Zframe-address-end +@var{separator-string} +@end example + +where @var{address} is the address executing in the frame (the same +address as in the @code{frame-begin} annotation, but printed in a form +which is intended for user consumption---in particular, the syntax varies +depending on the language), and @var{separator-string} is a string +intended to separate this address from what follows for the user's +benefit. + +@findex frame-function-name +@findex frame-args +Then comes + +@example +^Z^Zframe-function-name +@var{function-name} +^Z^Zframe-args +@var{arguments} +@end example + +where @var{function-name} is the name of the function executing in the +frame, or @samp{??} if not known, and @var{arguments} are the arguments +to the frame, with parentheses around them (each argument is annotated +individually as well @pxref{Values}). + +@findex frame-source-begin +@findex frame-source-file +@findex frame-source-file-end +@findex frame-source-line +@findex frame-source-end +If source information is available, a reference to it is then printed: + +@example +^Z^Zframe-source-begin +@var{source-intro-string} +^Z^Zframe-source-file +@var{filename} +^Z^Zframe-source-file-end +: +^Z^Zframe-source-line +@var{line-number} +^Z^Zframe-source-end +@end example + +where @var{source-intro-string} separates for the user's benefit the +reference from the text which precedes it, @var{filename} is the name of +the source file, and @var{line-number} is the line number within that +file (the first line is line 1). + +@findex frame-where +If GDB prints some information about where the frame is from (which +library, which load segment, etc.; currently only done on the RS/6000), +it is annotated with + +@example +^Z^Zframe-where +@var{information} +@end example + +Then, if source is to actually be displayed for this frame (for example, +this is not true for output from the @code{backtrace} command), then a +@code{source} annotation (@pxref{Source}) is displayed. Unlike most +annotations, this is output instead of the normal text which would be +output, not in addition. +@end itemize + +@node Displays +@chapter Displays + +@findex display-begin +@findex display-number-end +@findex display-format +@findex display-expression +@findex display-expression-end +@findex display-value +@findex display-end +When GDB is told to display something using the @code{display} command, +the results of the display are annotated: + +@example +^Z^Zdisplay-begin +@var{number} +^Z^Zdisplay-number-end +@var{number-separator} +^Z^Zdisplay-format +@var{format} +^Z^Zdisplay-expression +@var{expression} +^Z^Zdisplay-expression-end +@var{expression-separator} +^Z^Zdisplay-value +@var{value} +^Z^Zdisplay-end +@end example + +where @var{number} is the number of the display, @var{number-separator} +is intended to separate the number from what follows for the user, +@var{format} includes information such as the size, format, or other +information about how the value is being displayed, @var{expression} is +the expression being displayed, @var{expression-separator} is intended +to separate the expression from the text that follows for the user, +and @var{value} is the actual value being displayed. + +@node Prompting +@chapter Annotation for GDB Input + +When GDB prompts for input, it annotates this fact so it is possible +to know when to send output, when the output from a given command is +over, etc. + +Different kinds of input each have a different @dfn{input type}. Each +input type has three annotations: a @code{pre-} annotation, which +denotes the beginning of any prompt which is being output, a plain +annotation, which denotes the end of the prompt, and then a @code{post-} +annotation which denotes the end of any echo which may (or may not) be +associated with the input. For example, the @code{prompt} input type +features the following annotations: + +@example +^Z^Zpre-prompt +^Z^Zprompt +^Z^Zpost-prompt +@end example + +The input types are + +@table @code +@findex pre-prompt +@findex prompt +@findex post-prompt +@item prompt +When GDB is prompting for a command (the main GDB prompt). + +@findex pre-commands +@findex commands +@findex post-commands +@item commands +When GDB prompts for a set of commands, like in the @code{commands} +command. The annotations are repeated for each command which is input. + +@findex pre-overload-choice +@findex overload-choice +@findex post-overload-choice +@item overload-choice +When GDB wants the user to select between various overloaded functions. + +@findex pre-query +@findex query +@findex post-query +@item query +When GDB wants the user to confirm a potentially dangerous operation. + +@findex pre-prompt-for-continue +@findex prompt-for-continue +@findex post-prompt-for-continue +@item prompt-for-continue +When GDB is asking the user to press return to continue. Note: Don't +expect this to work well; instead use @code{set height 0} to disable +prompting. This is because the counting of lines is buggy in the +presence of annotations. +@end table + +@node Errors +@chapter Errors + +@findex quit +@example +^Z^Zquit +@end example + +This annotation occurs right before GDB responds to an interrupt. + +@findex error +@example +^Z^Zerror +@end example + +This annotation occurs right before GDB responds to an error. + +Quit and error annotations indicate that any annotations which GDB was +in the middle of may end abruptly. For example, if a +@code{value-history-begin} annotation is followed by a @code{error}, one +cannot expect to receive the matching @code{value-history-end}. One +cannot expect not to receive it either, however; an error annotation +does not necessarily mean that GDB is immediately returning all the way +to the top level. + +@findex error-begin +A quit or error annotation may be preceded by + +@example +^Z^Zerror-begin +@end example + +Any output between that and the quit or error annotation is the error +message. + +Warning messages are not yet annotated. +@c If we want to change that, need to fix warning(), type_error(), +@c range_error(), and possibly other places. + +@node Breakpoint Info +@chapter Information on Breakpoints + +The output from the @code{info breakpoints} command is annotated as follows: + +@findex breakpoints-headers +@findex breakpoints-table +@example +^Z^Zbreakpoints-headers +@var{header-entry} +^Z^Zbreakpoints-table +@end example + +where @var{header-entry} has the same syntax as an entry (see below) but +instead of containing data, it contains strings which are intended to +convey the meaning of each field to the user. This is followed by any +number of entries. If a field does not apply for this entry, it is +omitted. Fields may contain trailing whitespace. Each entry consists +of: + +@findex record +@findex field +@example +^Z^Zrecord +^Z^Zfield 0 +@var{number} +^Z^Zfield 1 +@var{type} +^Z^Zfield 2 +@var{disposition} +^Z^Zfield 3 +@var{enable} +^Z^Zfield 4 +@var{address} +^Z^Zfield 5 +@var{what} +^Z^Zfield 6 +@var{frame} +^Z^Zfield 7 +@var{condition} +^Z^Zfield 8 +@var{ignore-count} +^Z^Zfield 9 +@var{commands} +@end example + +Note that @var{address} is intended for user consumption---the syntax +varies depending on the language. + +The output ends with + +@findex breakpoints-table-end +@example +^Z^Zbreakpoints-table-end +@end example + +@node Invalidation +@chapter Invalidation Notices + +The following annotations say that certain pieces of state may have +changed. + +@table @code +@findex frames-invalid +@item ^Z^Zframes-invalid + +The frames (for example, output from the @code{backtrace} command) may +have changed. + +@findex breakpoints-invalid +@item ^Z^Zbreakpoints-invalid + +The breakpoints may have changed. For example, the user just added or +deleted a breakpoint. +@end table + +@node Running +@chapter Running the Program + +@findex starting +@findex stopping +When the program starts executing due to a GDB command such as +@code{step} or @code{continue}, + +@example +^Z^Zstarting +@end example + +is output. When the program stops, + +@example +^Z^Zstopped +@end example + +is output. Before the @code{stopped} annotation, a variety of +annotations describe how the program stopped. + +@table @code +@findex exited +@item ^Z^Zexited @var{exit-status} +The program exited, and @var{exit-status} is the exit status (zero for +successful exit, otherwise nonzero). + +@findex signalled +@findex signal-name +@findex signal-name-end +@findex signal-string +@findex signal-string-end +@item ^Z^Zsignalled +The program exited with a signal. After the @code{^Z^Zsignalled}, the +annotation continues: + +@example +@var{intro-text} +^Z^Zsignal-name +@var{name} +^Z^Zsignal-name-end +@var{middle-text} +^Z^Zsignal-string +@var{string} +^Z^Zsignal-string-end +@var{end-text} +@end example + +where @var{name} is the name of the signal, such as @code{SIGILL} or +@code{SIGSEGV}, and @var{string} is the explanation of the signal, such +as @code{Illegal Instruction} or @code{Segmentation fault}. +@var{intro-text}, @var{middle-text}, and @var{end-text} are for the +user's benefit and have no particular format. + +@findex signal +@item ^Z^Zsignal +The syntax of this annotation is just like @code{signalled}, but GDB is +just saying that the program received the signal, not that it was +terminated with it. + +@findex breakpoint +@item ^Z^Zbreakpoint @var{number} +The program hit breakpoint number @var{number}. + +@findex watchpoint +@item ^Z^Zwatchpoint @var{number} +The program hit watchpoint number @var{number}. +@end table + +@node Source +@chapter Displaying Source + +@findex source +The following annotation is used instead of displaying source code: + +@example +^Z^Zsource @var{filename}:@var{line}:@var{character}:@var{middle}:@var{addr} +@end example + +where @var{filename} is an absolute file name indicating which source +file, @var{line} is the line number within that file (where 1 is the +first line in the file), @var{character} is the character position +within the file (where 0 is the first character in the file) (for most +debug formats this will necessarily point to the beginning of a line), +@var{middle} is @samp{middle} if @var{addr} is in the middle of the +line, or @samp{beg} if @var{addr} is at the beginning of the line, and +@var{addr} is the address in the target program associated with the +source which is being displayed. @var{addr} is in the form @samp{0x} +followed by one or more lowercase hex digits (note that this does not +depend on the language). + +@node TODO +@chapter Annotations We Might Want in the Future + +@format + - target-invalid + the target might have changed (registers, heap contents, or + execution status). For performance, we might eventually want + to hit `registers-invalid' and `all-registers-invalid' with + greater precision + + - systematic annotation for set/show parameters (including + invalidation notices). + + - similarly, `info' returns a list of candidates for invalidation + notices. +@end format + +@node Index +@unnumbered Index + +@printindex fn + +@bye diff --git a/contrib/gdb/gdb/doc/configure.in b/contrib/gdb/gdb/doc/configure.in new file mode 100644 index 000000000000..1d2b47e78cc5 --- /dev/null +++ b/contrib/gdb/gdb/doc/configure.in @@ -0,0 +1,7 @@ +srcname="GDB doc" +srctrigger=gdb.texinfo +# per-host: +# per-target: + +files="" +links="" diff --git a/contrib/gdb/gdb/doc/gdb.texinfo b/contrib/gdb/gdb/doc/gdb.texinfo new file mode 100644 index 000000000000..89bfa832df6d --- /dev/null +++ b/contrib/gdb/gdb/doc/gdb.texinfo @@ -0,0 +1,9282 @@ +\input texinfo @c -*-texinfo-*- +@c Copyright 1988 1989 1990 1991 1992 1993 1994 1995 +@c Free Software Foundation, Inc. +@c +@c %**start of header +@c makeinfo ignores cmds prev to setfilename, so its arg cannot make use +@c of @set vars. However, you can override filename with makeinfo -o. +@setfilename gdb.info +@c +@include gdb-cfg.texi +@c +@ifset GENERIC +@settitle Debugging with @value{GDBN} +@end ifset +@ifclear GENERIC +@settitle Debugging with @value{GDBN} (@value{TARGET}) +@end ifclear +@clear RENAMED +@setchapternewpage odd +@c %**end of header + +@iftex +@c @smallbook +@c @cropmarks +@end iftex + +@finalout +@syncodeindex ky cp + +@c readline appendices use @vindex +@syncodeindex vr cp + +@c !!set GDB manual's edition---not the same as GDB version! +@set EDITION 4.12 + +@c !!set GDB manual's revision date +@set DATE January 1994 + +@c GDB CHANGELOG CONSULTED BETWEEN: +@c Fri Oct 11 23:27:06 1991 John Gilmore (gnu at cygnus.com) +@c Sat Dec 22 02:51:40 1990 John Gilmore (gnu at cygint) + +@c THIS MANUAL REQUIRES TEXINFO-2 macros and info-makers to format properly. + +@ifinfo +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. zoo@cygnus.com is developing this facility. +@format +START-INFO-DIR-ENTRY +* Gdb: (gdb). The @sc{gnu} debugger. +END-INFO-DIR-ENTRY +@end format +@end ifinfo +@c +@c +@ifinfo +This file documents the @sc{gnu} debugger @value{GDBN}. + + +This is Edition @value{EDITION}, @value{DATE}, +of @cite{Debugging with @value{GDBN}: the @sc{gnu} Source-Level Debugger} +for @value{GDBN} Version @value{GDBVN}. + +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995 +Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@titlepage +@title Debugging with @value{GDBN} +@subtitle The @sc{gnu} Source-Level Debugger +@ifclear GENERIC +@subtitle (@value{TARGET}) +@end ifclear +@sp 1 +@subtitle Edition @value{EDITION}, for @value{GDBN} version @value{GDBVN} +@subtitle @value{DATE} +@author Richard M. Stallman and Cygnus Support +@page +@tex +{\parskip=0pt +\hfill (Send bugs and comments on @value{GDBN} to bug-gdb\@prep.ai.mit.edu.)\par +\hfill {\it Debugging with @value{GDBN}}\par +\hfill \TeX{}info \texinfoversion\par +\hfill doc\@cygnus.com\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995 +Free Software Foundation, Inc. +@sp 2 +Published by the Free Software Foundation @* +59 Temple Place - Suite 330, @* +Boston, MA 02111-1307 USA @* +Printed copies are available for $20 each. @* +ISBN 1-882114-11-6 @* + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage +@page + +@ifinfo +@node Top +@top Debugging with @value{GDBN} + +This file describes @value{GDBN}, the @sc{gnu} symbolic debugger. + +This is Edition @value{EDITION}, @value{DATE}, for @value{GDBN} Version +@value{GDBVN}. + +@menu +* Summary:: Summary of @value{GDBN} +@ifclear BARETARGET +* Sample Session:: A sample @value{GDBN} session +@end ifclear + +* Invocation:: Getting in and out of @value{GDBN} +* Commands:: @value{GDBN} commands +* Running:: Running programs under @value{GDBN} +* Stopping:: Stopping and continuing +* Stack:: Examining the stack +* Source:: Examining source files +* Data:: Examining data +@ifclear CONLY +* Languages:: Using @value{GDBN} with different languages +@end ifclear +@ifset CONLY +* C:: C language support +@end ifset +@c remnant makeinfo bug, blank line needed after two end-ifs? + +* Symbols:: Examining the symbol table +* Altering:: Altering execution +* GDB Files:: @value{GDBN} files +* Targets:: Specifying a debugging target +* Controlling GDB:: Controlling @value{GDBN} +* Sequences:: Canned sequences of commands +@ifclear DOSHOST +* Emacs:: Using @value{GDBN} under @sc{gnu} Emacs +@end ifclear + +* GDB Bugs:: Reporting bugs in @value{GDBN} +* Command Line Editing:: Facilities of the readline library +* Using History Interactively:: +@c @ifset NOVEL +@c * Renamed Commands:: +@c @end ifset +@ifclear PRECONFIGURED +* Formatting Documentation:: How to format and print @value{GDBN} documentation +* Installing GDB:: Installing GDB +@end ifclear + +* Index:: Index +@end menu +@end ifinfo + +@node Summary +@unnumbered Summary of @value{GDBN} + +The purpose of a debugger such as @value{GDBN} is to allow you to see what is +going on ``inside'' another program while it executes---or what another +program was doing at the moment it crashed. + +@value{GDBN} can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +@itemize @bullet +@item +Start your program, specifying anything that might affect its behavior. + +@item +Make your program stop on specified conditions. + +@item +Examine what has happened, when your program has stopped. + +@item +Change things in your program, so you can experiment with correcting the +effects of one bug and go on to learn about another. +@end itemize + +@ifclear CONLY +You can use @value{GDBN} to debug programs written in C or C++. +@c "MOD2" used as a "miscellaneous languages" flag here. +@c This is acceptable while there is no real doc for Chill and Pascal. +@ifclear MOD2 +For more information, see @ref{Support,,Supported languages}. +@end ifclear +@ifset MOD2 +For more information, see @ref{C,,C and C++}. + +Support for Modula-2 and Chill is partial. For information on Modula-2, +see @ref{Modula-2,,Modula-2}. There is no further documentation on Chill yet. + +Debugging Pascal programs which use sets, subranges, file variables, or nested +functions does not currently work. @value{GDBN} does not support +entering expressions, printing values, or similar features using Pascal syntax. + +@end ifset +@ifset FORTRAN +@cindex Fortran +@value{GDBN} can be used to debug programs written in Fortran, although +it does not yet support entering expressions, printing values, or +similar features using Fortran syntax. It may be necessary to refer to +some variables with a trailing underscore. +@end ifset +@end ifclear + +@menu +* Free Software:: Freely redistributable software +* Contributors:: Contributors to GDB +@end menu + +@node Free Software +@unnumberedsec Free software + +@value{GDBN} is @dfn{free software}, protected by the @sc{gnu} +General Public License +(GPL). The GPL gives you the freedom to copy or adapt a licensed +program---but every person getting a copy also gets with it the +freedom to modify that copy (which means that they must get access to +the source code), and the freedom to distribute further copies. +Typical software companies use copyrights to limit your freedoms; the +Free Software Foundation uses the GPL to preserve these freedoms. + +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 Contributors +@unnumberedsec Contributors to GDB + +Richard Stallman was the original author of GDB, and of many other @sc{gnu} +programs. Many others have contributed to its development. This +section attempts to credit major contributors. One of the virtues of +free software is that everyone is free to contribute to it; with +regret, we cannot actually acknowledge everyone here. The file +@file{ChangeLog} in the @value{GDBN} distribution approximates a blow-by-blow +account. + +Changes much prior to version 2.0 are lost in the mists of time. + +@quotation +@emph{Plea:} Additions to this section are particularly welcome. If you +or your friends (or enemies, to be evenhanded) have been unfairly +omitted from this list, we would like to add your names! +@end quotation + +So that they may not regard their long labor as thankless, we +particularly thank those who shepherded GDB through major releases: +Stan Shebs (release 4.14), +Fred Fish (releases 4.13, 4.12, 4.11, 4.10, and 4.9), +Stu Grossman and John Gilmore (releases 4.8, 4.7, 4.6, 4.5, and 4.4), +John Gilmore (releases 4.3, 4.2, 4.1, 4.0, and 3.9); +Jim Kingdon (releases 3.5, 3.4, and 3.3); +and Randy Smith (releases 3.2, 3.1, and 3.0). +As major maintainer of @value{GDBN} for some period, each +contributed significantly to the structure, stability, and capabilities +of the entire debugger. + +Richard Stallman, assisted at various times by Peter TerMaat, Chris +Hanson, and Richard Mlynarik, handled releases through 2.8. + +@ifclear CONLY +Michael Tiemann is the author of most of the @sc{gnu} C++ support in GDB, +with significant additional contributions from Per Bothner. James +Clark wrote the @sc{gnu} C++ demangler. Early work on C++ was by Peter +TerMaat (who also did much general update work leading to release 3.0). +@end ifclear + +@value{GDBN} 4 uses the BFD subroutine library to examine multiple +object-file formats; BFD was a joint project of David V. +Henkel-Wallace, Rich Pixley, Steve Chamberlain, and John Gilmore. + +David Johnson wrote the original COFF support; Pace Willison did +the original support for encapsulated COFF. + +Adam de Boor and Bradley Davis contributed the ISI Optimum V support. +Per Bothner, Noboyuki Hikichi, and Alessandro Forin contributed MIPS +support. +Jean-Daniel Fekete contributed Sun 386i support. +Chris Hanson improved the HP9000 support. +Noboyuki Hikichi and Tomoyuki Hasei contributed Sony/News OS 3 support. +David Johnson contributed Encore Umax support. +Jyrki Kuoppala contributed Altos 3068 support. +Jeff Law contributed HP PA and SOM support. +Keith Packard contributed NS32K support. +Doug Rabson contributed Acorn Risc Machine support. +Bob Rusk contributed Harris Nighthawk CX-UX support. +Chris Smith contributed Convex support (and Fortran debugging). +Jonathan Stone contributed Pyramid support. +Michael Tiemann contributed SPARC support. +Tim Tucker contributed support for the Gould NP1 and Gould Powernode. +Pace Willison contributed Intel 386 support. +Jay Vosburgh contributed Symmetry support. + +Rich Schaefer and Peter Schauer helped with support of SunOS shared +libraries. + +Jay Fenlason and Roland McGrath ensured that @value{GDBN} and GAS agree about +several machine instruction sets. + +Patrick Duval, Ted Goldstein, Vikram Koka and Glenn Engel helped +develop remote debugging. Intel Corporation and Wind River Systems +contributed remote debugging modules for their products. + +Brian Fox is the author of the readline libraries providing +command-line editing and command history. + +Andrew Beers of SUNY Buffalo wrote the language-switching code, +@ifset MOD2 +the Modula-2 support, +@end ifset +and contributed the Languages chapter of this manual. + +Fred Fish wrote most of the support for Unix System Vr4. +@ifclear CONLY +He also enhanced the command-completion support to cover C++ overloaded +symbols. +@end ifclear + +Hitachi America, Ltd. sponsored the support for Hitachi microprocessors. + +Kung Hsu, Jeff Law, and Rick Sladkey added support for hardware +watchpoints. + +Stu Grossman wrote gdbserver. + +Jim Kingdon, Peter Schauer, Ian Taylor, and Stu Grossman made +nearly innumerable bug fixes and cleanups throughout GDB. + +@ifclear BARETARGET +@node Sample Session +@chapter A Sample @value{GDBN} Session + +You can use this manual at your leisure to read all about @value{GDBN}. +However, a handful of commands are enough to get started using the +debugger. This chapter illustrates those commands. + +@iftex +In this sample session, we emphasize user input like this: @b{input}, +to make it easier to pick out from the surrounding output. +@end iftex + +@c FIXME: this example may not be appropriate for some configs, where +@c FIXME...primary interest is in remote use. + +One of the preliminary versions of @sc{gnu} @code{m4} (a generic macro +processor) exhibits the following bug: sometimes, when we change its +quote strings from the default, the commands used to capture one macro +definition within another stop working. In the following short @code{m4} +session, we define a macro @code{foo} which expands to @code{0000}; we +then use the @code{m4} built-in @code{defn} to define @code{bar} as the +same thing. However, when we change the open quote string to +@code{} and the close quote string to @code{}, the same +procedure fails to define a new synonym @code{baz}: + +@smallexample +$ @b{cd gnu/m4} +$ @b{./m4} +@b{define(foo,0000)} + +@b{foo} +0000 +@b{define(bar,defn(`foo'))} + +@b{bar} +0000 +@b{changequote(,)} + +@b{define(baz,defn(foo))} +@b{baz} +@b{C-d} +m4: End of input: 0: fatal error: EOF in string +@end smallexample + +@noindent +Let us use @value{GDBN} to try to see what is going on. + +@smallexample +$ @b{@value{GDBP} m4} +@c FIXME: this falsifies the exact text played out, to permit smallbook +@c FIXME... format to come out better. +@value{GDBN} is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. +There is absolutely no warranty for @value{GDBN}; type "show warranty" + for details. + +@value{GDBN} @value{GDBVN}, Copyright 1995 Free Software Foundation, Inc... +(@value{GDBP}) +@end smallexample + +@noindent +@value{GDBN} reads only enough symbol data to know where to find the +rest when needed; as a result, the first prompt comes up very quickly. +We now tell @value{GDBN} to use a narrower display width than usual, so +that examples fit in this manual. + +@smallexample +(@value{GDBP}) @b{set width 70} +@end smallexample + +@noindent +We need to see how the @code{m4} built-in @code{changequote} works. +Having looked at the source, we know the relevant subroutine is +@code{m4_changequote}, so we set a breakpoint there with the @value{GDBN} +@code{break} command. + +@smallexample +(@value{GDBP}) @b{break m4_changequote} +Breakpoint 1 at 0x62f4: file builtin.c, line 879. +@end smallexample + +@noindent +Using the @code{run} command, we start @code{m4} running under @value{GDBN} +control; as long as control does not reach the @code{m4_changequote} +subroutine, the program runs as usual: + +@smallexample +(@value{GDBP}) @b{run} +Starting program: /work/Editorial/gdb/gnu/m4/m4 +@b{define(foo,0000)} + +@b{foo} +0000 +@end smallexample + +@noindent +To trigger the breakpoint, we call @code{changequote}. @value{GDBN} +suspends execution of @code{m4}, displaying information about the +context where it stops. + +@smallexample +@b{changequote(,)} + +Breakpoint 1, m4_changequote (argc=3, argv=0x33c70) + at builtin.c:879 +879 if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3)) +@end smallexample + +@noindent +Now we use the command @code{n} (@code{next}) to advance execution to +the next line of the current function. + +@smallexample +(@value{GDBP}) @b{n} +882 set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\ + : nil, +@end smallexample + +@noindent +@code{set_quotes} looks like a promising subroutine. We can go into it +by using the command @code{s} (@code{step}) instead of @code{next}. +@code{step} goes to the next line to be executed in @emph{any} +subroutine, so it steps into @code{set_quotes}. + +@smallexample +(@value{GDBP}) @b{s} +set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 +530 if (lquote != def_lquote) +@end smallexample + +@noindent +The display that shows the subroutine where @code{m4} is now +suspended (and its arguments) is called a stack frame display. It +shows a summary of the stack. We can use the @code{backtrace} +command (which can also be spelled @code{bt}), to see where we are +in the stack as a whole: the @code{backtrace} command displays a +stack frame for each active subroutine. + +@smallexample +(@value{GDBP}) @b{bt} +#0 set_quotes (lq=0x34c78 "", rq=0x34c88 "") + at input.c:530 +#1 0x6344 in m4_changequote (argc=3, argv=0x33c70) + at builtin.c:882 +#2 0x8174 in expand_macro (sym=0x33320) at macro.c:242 +#3 0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30) + at macro.c:71 +#4 0x79dc in expand_input () at macro.c:40 +#5 0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195 +@end smallexample + +@noindent +We step through a few more lines to see what happens. The first two +times, we can use @samp{s}; the next two times we use @code{n} to avoid +falling into the @code{xstrdup} subroutine. + +@smallexample +(@value{GDBP}) @b{s} +0x3b5c 532 if (rquote != def_rquote) +(@value{GDBP}) @b{s} +0x3b80 535 lquote = (lq == nil || *lq == '\0') ? \ +def_lquote : xstrdup(lq); +(@value{GDBP}) @b{n} +536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup(rq); +(@value{GDBP}) @b{n} +538 len_lquote = strlen(rquote); +@end smallexample + +@noindent +The last line displayed looks a little odd; we can examine the variables +@code{lquote} and @code{rquote} to see if they are in fact the new left +and right quotes we specified. We use the command @code{p} +(@code{print}) to see their values. + +@smallexample +(@value{GDBP}) @b{p lquote} +$1 = 0x35d40 "" +(@value{GDBP}) @b{p rquote} +$2 = 0x35d50 "" +@end smallexample + +@noindent +@code{lquote} and @code{rquote} are indeed the new left and right quotes. +To look at some context, we can display ten lines of source +surrounding the current line with the @code{l} (@code{list}) command. + +@smallexample +(@value{GDBP}) @b{l} +533 xfree(rquote); +534 +535 lquote = (lq == nil || *lq == '\0') ? def_lquote\ + : xstrdup (lq); +536 rquote = (rq == nil || *rq == '\0') ? def_rquote\ + : xstrdup (rq); +537 +538 len_lquote = strlen(rquote); +539 len_rquote = strlen(lquote); +540 @} +541 +542 void +@end smallexample + +@noindent +Let us step past the two lines that set @code{len_lquote} and +@code{len_rquote}, and then examine the values of those variables. + +@smallexample +(@value{GDBP}) @b{n} +539 len_rquote = strlen(lquote); +(@value{GDBP}) @b{n} +540 @} +(@value{GDBP}) @b{p len_lquote} +$3 = 9 +(@value{GDBP}) @b{p len_rquote} +$4 = 7 +@end smallexample + +@noindent +That certainly looks wrong, assuming @code{len_lquote} and +@code{len_rquote} are meant to be the lengths of @code{lquote} and +@code{rquote} respectively. We can set them to better values using +the @code{p} command, since it can print the value of +any expression---and that expression can include subroutine calls and +assignments. + +@smallexample +(@value{GDBP}) @b{p len_lquote=strlen(lquote)} +$5 = 7 +(@value{GDBP}) @b{p len_rquote=strlen(rquote)} +$6 = 9 +@end smallexample + +@noindent +Is that enough to fix the problem of using the new quotes with the +@code{m4} built-in @code{defn}? We can allow @code{m4} to continue +executing with the @code{c} (@code{continue}) command, and then try the +example that caused trouble initially: + +@smallexample +(@value{GDBP}) @b{c} +Continuing. + +@b{define(baz,defn(foo))} + +baz +0000 +@end smallexample + +@noindent +Success! The new quotes now work just as well as the default ones. The +problem seems to have been just the two typos defining the wrong +lengths. We allow @code{m4} exit by giving it an EOF as input: + +@smallexample +@b{C-d} +Program exited normally. +@end smallexample + +@noindent +The message @samp{Program exited normally.} is from @value{GDBN}; it +indicates @code{m4} has finished executing. We can end our @value{GDBN} +session with the @value{GDBN} @code{quit} command. + +@smallexample +(@value{GDBP}) @b{quit} +@end smallexample +@end ifclear + +@node Invocation +@chapter Getting In and Out of @value{GDBN} + +This chapter discusses how to start @value{GDBN}, and how to get out of it. +The essentials are: +@itemize @bullet +@item +type @samp{@value{GDBP}} to start GDB. +@item +type @kbd{quit} or @kbd{C-d} to exit. +@end itemize + +@menu +* Invoking GDB:: How to start @value{GDBN} +* Quitting GDB:: How to quit @value{GDBN} +* Shell Commands:: How to use shell commands inside @value{GDBN} +@end menu + +@node Invoking GDB +@section Invoking @value{GDBN} + +@ifset H8EXCLUSIVE +For details on starting up @value{GDBP} as a +remote debugger attached to a Hitachi microprocessor, see @ref{Hitachi +Remote,,@value{GDBN} and Hitachi Microprocessors}. +@end ifset + +Invoke @value{GDBN} by running the program @code{@value{GDBP}}. Once started, +@value{GDBN} reads commands from the terminal until you tell it to exit. + +You can also run @code{@value{GDBP}} with a variety of arguments and options, +to specify more of your debugging environment at the outset. + +@ifset GENERIC +The command-line options described here are designed +to cover a variety of situations; in some environments, some of these +options may effectively be unavailable. +@end ifset + +The most usual way to start @value{GDBN} is with one argument, +specifying an executable program: + +@example +@value{GDBP} @var{program} +@end example + +@ifclear BARETARGET +@noindent +You can also start with both an executable program and a core file +specified: + +@example +@value{GDBP} @var{program} @var{core} +@end example + +You can, instead, specify a process ID as a second argument, if you want +to debug a running process: + +@example +@value{GDBP} @var{program} 1234 +@end example + +@noindent +would attach @value{GDBN} to process @code{1234} (unless you also have a file +named @file{1234}; @value{GDBN} does check for a core file first). + +Taking advantage of the second command-line argument requires a fairly +complete operating system; when you use @value{GDBN} as a remote debugger +attached to a bare board, there may not be any notion of ``process'', +and there is often no way to get a core dump. +@end ifclear + +You can run @code{gdb} without printing the front material, which describes +@value{GDBN}'s non-warranty, by specifying @code{-silent}: + +@smallexample +@value{GDBP} @var{-silent} +@end smallexample + +@noindent +You can further control how @value{GDBN} starts up by using command-line +options. @value{GDBN} itself can remind you of the options available. + +@noindent +Type + +@example +@value{GDBP} -help +@end example + +@noindent +to display all available options and briefly describe their use +(@samp{@value{GDBP} -h} is a shorter equivalent). + +All options and command line arguments you give are processed +in sequential order. The order makes a difference when the +@samp{-x} option is used. + + +@menu +@ifclear GENERIC +@ifset REMOTESTUB +* Remote Serial:: @value{GDBN} remote serial protocol +@end ifset +@ifset I960 +* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) +@end ifset +@ifset AMD29K +* UDI29K Remote:: The UDI protocol for AMD29K +* EB29K Remote:: The EBMON protocol for AMD29K +@end ifset +@ifset VXWORKS +* VxWorks Remote:: @value{GDBN} and VxWorks +@end ifset +@ifset ST2000 +* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 +@end ifset +@ifset H8 +* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors +@end ifset +@ifset MIPS +* MIPS Remote:: @value{GDBN} and MIPS boards +@end ifset +@ifset SIMS +* Simulator:: Simulated CPU target +@end ifset +@end ifclear +@c remnant makeinfo bug requires this blank line after *two* end-ifblahs: + +* File Options:: Choosing files +* Mode Options:: Choosing modes +@end menu + +@ifclear GENERIC +@include remote.texi +@end ifclear + +@node File Options +@subsection Choosing files + +@ifclear BARETARGET +When @value{GDBN} starts, it reads any arguments other than options as +specifying an executable file and core file (or process ID). This is +the same as if the arguments were specified by the @samp{-se} and +@samp{-c} options respectively. (@value{GDBN} reads the first argument +that does not have an associated option flag as equivalent to the +@samp{-se} option followed by that argument; and the second argument +that does not have an associated option flag, if any, as equivalent to +the @samp{-c} option followed by that argument.) +@end ifclear +@ifset BARETARGET +When @value{GDBN} starts, it reads any argument other than options as +specifying an executable file. This is the same as if the argument was +specified by the @samp{-se} option. +@end ifset + +Many options have both long and short forms; both are shown in the +following list. @value{GDBN} also recognizes the long forms if you truncate +them, so long as enough of the option is present to be unambiguous. +(If you prefer, you can flag option arguments with @samp{--} rather +than @samp{-}, though we illustrate the more usual convention.) + +@table @code +@item -symbols @var{file} +@itemx -s @var{file} +Read symbol table from file @var{file}. + +@item -exec @var{file} +@itemx -e @var{file} +Use file @var{file} as the executable file to execute when +@ifset BARETARGET +appropriate. +@end ifset +@ifclear BARETARGET +appropriate, and for examining pure data in conjunction with a core +dump. +@end ifclear + +@item -se @var{file} +Read symbol table from file @var{file} and use it as the executable +file. + +@ifclear BARETARGET +@item -core @var{file} +@itemx -c @var{file} +Use file @var{file} as a core dump to examine. + +@item -c @var{number} +Connect to process ID @var{number}, as with the @code{attach} command +(unless there is a file in core-dump format named @var{number}, in which +case @samp{-c} specifies that file as a core dump to read). +@end ifclear + +@item -command @var{file} +@itemx -x @var{file} +Execute @value{GDBN} commands from file @var{file}. @xref{Command +Files,, Command files}. + +@item -directory @var{directory} +@itemx -d @var{directory} +Add @var{directory} to the path to search for source files. + +@ifclear BARETARGET +@item -m +@itemx -mapped +@emph{Warning: this option depends on operating system facilities that are not +supported on all systems.}@* +If memory-mapped files are available on your system through the @code{mmap} +system call, you can use this option +to have @value{GDBN} write the symbols from your +program into a reusable file in the current directory. If the program you are debugging is +called @file{/tmp/fred}, the mapped symbol file is @file{./fred.syms}. +Future @value{GDBN} debugging sessions notice the presence of this file, +and can quickly map in symbol information from it, rather than reading +the symbol table from the executable program. + +The @file{.syms} file is specific to the host machine where @value{GDBN} +is run. It holds an exact image of the internal @value{GDBN} symbol +table. It cannot be shared across multiple host platforms. +@end ifclear + +@item -r +@itemx -readnow +Read each symbol file's entire symbol table immediately, rather than +the default, which is to read it incrementally as it is needed. +This makes startup slower, but makes future operations faster. +@end table + +@ifclear BARETARGET +The @code{-mapped} and @code{-readnow} options are typically combined in +order to build a @file{.syms} file that contains complete symbol +information. (@xref{Files,,Commands to specify files}, for information + +a @file{.syms} file for future use is: + +@example + gdb -batch -nx -mapped -readnow programname +@end example +@end ifclear + +@node Mode Options +@subsection Choosing modes + +You can run @value{GDBN} in various alternative modes---for example, in +batch mode or quiet mode. + +@table @code +@item -nx +@itemx -n +Do not execute commands from any initialization files (normally called +@file{@value{GDBINIT}}). Normally, the commands in these files are +executed after all the command options and arguments have been +processed. @xref{Command Files,,Command files}. + +@item -quiet +@itemx -q +``Quiet''. Do not print the introductory and copyright messages. These +messages are also suppressed in batch mode. + +@item -batch +Run in batch mode. Exit with status @code{0} after processing all the +command files specified with @samp{-x} (and all commands from +initialization files, if not inhibited with @samp{-n}). Exit with +nonzero status if an error occurs in executing the @value{GDBN} commands +in the command files. + +Batch mode may be useful for running @value{GDBN} as a filter, for example to +download and run a program on another computer; in order to make this +more useful, the message + +@example +Program exited normally. +@end example + +@noindent +(which is ordinarily issued whenever a program running under @value{GDBN} control +terminates) is not issued when running in batch mode. + +@item -cd @var{directory} +Run @value{GDBN} using @var{directory} as its working directory, +instead of the current directory. + +@ifset LUCID +@item -context @var{authentication} +When the Energize programming system starts up @value{GDBN}, it uses this +option to trigger an alternate mode of interaction. +@var{authentication} is a pair of numeric codes that identify @value{GDBN} +as a client in the Energize environment. Avoid this option when you run +@value{GDBN} directly from the command line. See @ref{Energize,,Using +@value{GDBN} with Energize} for more discussion of using @value{GDBN} with Energize. +@end ifset + +@ifclear DOSHOST +@item -fullname +@itemx -f +@sc{gnu} Emacs sets this option when it runs @value{GDBN} as a subprocess. It tells @value{GDBN} +to output the full file name and line number in a standard, +recognizable fashion each time a stack frame is displayed (which +includes each time your program stops). This recognizable format looks +like two @samp{\032} characters, followed by the file name, line number +and character position separated by colons, 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. +@end ifclear + +@ifset SERIAL +@item -b @var{bps} +Set the line speed (baud rate or bits per second) of any serial +interface used by @value{GDBN} for remote debugging. + +@item -tty @var{device} +Run using @var{device} for your program's standard input and output. +@c FIXME: kingdon thinks there is more to -tty. Investigate. +@end ifset +@end table + +@node Quitting GDB +@section Quitting @value{GDBN} +@cindex exiting @value{GDBN} +@cindex leaving @value{GDBN} + +@table @code +@kindex quit @r{[}@var{expression}@r{]} +@kindex q +@item quit +To exit @value{GDBN}, use the @code{quit} command (abbreviated @code{q}), or +type an end-of-file character (usually @kbd{C-d}). If you do not supply +@var{expression}, @value{GDBN} will terminate normally; otherwise it will +terminate using the result of @var{expression} as the error code. +@end table + +@cindex interrupt +An interrupt (often @kbd{C-c}) does not exit from @value{GDBN}, but rather +terminates the action of any @value{GDBN} command that is in progress and +returns to @value{GDBN} command level. It is safe to type the interrupt +character at any time because @value{GDBN} does not allow it to take effect +until a time when it is safe. + +@ifclear BARETARGET +If you have been using @value{GDBN} to control an attached process or +device, you can release it with the @code{detach} command +(@pxref{Attach, ,Debugging an already-running process}). +@end ifclear + +@node Shell Commands +@section Shell commands + +If you need to execute occasional shell commands during your +debugging session, there is no need to leave or suspend @value{GDBN}; you can +just use the @code{shell} command. + +@table @code +@kindex shell +@cindex shell escape +@item shell @var{command string} +Invoke a the standard shell to execute @var{command string}. +@ifclear DOSHOST +If it exists, the environment variable @code{SHELL} determines which +shell to run. Otherwise @value{GDBN} uses @code{/bin/sh}. +@end ifclear +@end table + +The utility @code{make} is often needed in development environments. +You do not have to use the @code{shell} command for this purpose in +@value{GDBN}: + +@table @code +@kindex make +@cindex calling make +@item make @var{make-args} +Execute the @code{make} program with the specified +arguments. This is equivalent to @samp{shell make @var{make-args}}. +@end table + +@node Commands +@chapter @value{GDBN} Commands + +You can abbreviate a @value{GDBN} command to the first few letters of the command +name, if that abbreviation is unambiguous; and you can repeat certain +@value{GDBN} commands by typing just @key{RET}. You can also use the @key{TAB} +key to get @value{GDBN} to fill out the rest of a word in a command (or to +show you the alternatives available, if there is more than one possibility). + +@menu +* Command Syntax:: How to give commands to @value{GDBN} +* Completion:: Command completion +* Help:: How to ask @value{GDBN} for help +@end menu + +@node Command Syntax +@section Command syntax + +A @value{GDBN} command is a single line of input. There is no limit on +how long it can be. It starts with a command name, which is followed by +arguments whose meaning depends on the command name. For example, the +command @code{step} accepts an argument which is the number of times to +step, as in @samp{step 5}. You can also use the @code{step} command +with no arguments. Some command names do not allow any arguments. + +@cindex abbreviation +@value{GDBN} command names may always be truncated if that abbreviation is +unambiguous. Other possible command abbreviations are listed in the +documentation for individual commands. In some cases, even ambiguous +abbreviations are allowed; for example, @code{s} is specially defined as +equivalent to @code{step} even though there are other commands whose +names start with @code{s}. You can test abbreviations by using them as +arguments to the @code{help} command. + +@cindex repeating commands +@kindex RET +A blank line as input to @value{GDBN} (typing just @key{RET}) means to +repeat the previous command. Certain commands (for example, @code{run}) +will not repeat this way; these are commands whose unintentional +repetition might cause trouble and which you are unlikely to want to +repeat. + +The @code{list} and @code{x} commands, when you repeat them with +@key{RET}, construct new arguments rather than repeating +exactly as typed. This permits easy scanning of source or memory. + +@value{GDBN} can also use @key{RET} in another way: to partition lengthy +output, in a way similar to the common utility @code{more} +(@pxref{Screen Size,,Screen size}). Since it is easy to press one +@key{RET} too many in this situation, @value{GDBN} disables command +repetition after any command that generates this sort of display. + +@kindex # +@cindex comment +Any text from a @kbd{#} to the end of the line is a comment; it does +nothing. This is useful mainly in command files (@pxref{Command +Files,,Command files}). + +@node Completion +@section Command completion + +@cindex completion +@cindex word completion +@value{GDBN} can fill in the rest of a word in a command for you, if there is +only one possibility; it can also show you what the valid possibilities +are for the next word in a command, at any time. This works for @value{GDBN} +commands, @value{GDBN} subcommands, and the names of symbols in your program. + +Press the @key{TAB} key whenever you want @value{GDBN} to fill out the rest +of a word. If there is only one possibility, @value{GDBN} fills in the +word, and waits for you to finish the command (or press @key{RET} to +enter it). For example, if you type + +@c FIXME "@key" does not distinguish its argument sufficiently to permit +@c complete accuracy in these examples; space introduced for clarity. +@c If texinfo enhancements make it unnecessary, it would be nice to +@c replace " @key" by "@key" in the following... +@example +(@value{GDBP}) info bre @key{TAB} +@end example + +@noindent +@value{GDBN} fills in the rest of the word @samp{breakpoints}, since that is +the only @code{info} subcommand beginning with @samp{bre}: + +@example +(@value{GDBP}) info breakpoints +@end example + +@noindent +You can either press @key{RET} at this point, to run the @code{info +breakpoints} command, or backspace and enter something else, if +@samp{breakpoints} does not look like the command you expected. (If you +were sure you wanted @code{info breakpoints} in the first place, you +might as well just type @key{RET} immediately after @samp{info bre}, +to exploit command abbreviations rather than command completion). + +If there is more than one possibility for the next word when you press +@key{TAB}, @value{GDBN} sounds a bell. You can either supply more +characters and try again, or just press @key{TAB} a second time; +@value{GDBN} displays all the possible completions for that word. For +example, you might want to set a breakpoint on a subroutine whose name +begins with @samp{make_}, but when you type @kbd{b make_@key{TAB}} @value{GDBN} +just sounds the bell. Typing @key{TAB} again displays all the +function names in your program that begin with those characters, for +example: + +@example +(@value{GDBP}) b make_ @key{TAB} +@exdent @value{GDBN} sounds bell; press @key{TAB} again, to see: +make_a_section_from_file make_environ +make_abs_section make_function_type +make_blockvector make_pointer_type +make_cleanup make_reference_type +make_command make_symbol_completion_list +(@value{GDBP}) b make_ +@end example + +@noindent +After displaying the available possibilities, @value{GDBN} copies your +partial input (@samp{b make_} in the example) so you can finish the +command. + +If you just want to see the list of alternatives in the first place, you +can press @kbd{M-?} rather than pressing @key{TAB} twice. @kbd{M-?} +means @kbd{@key{META} ?}. You can type this +@ifclear DOSHOST +either by holding down a +key designated as the @key{META} shift on your keyboard (if there is +one) while typing @kbd{?}, or +@end ifclear +as @key{ESC} followed by @kbd{?}. + +@cindex quotes in commands +@cindex completion of quoted strings +Sometimes the string you need, while logically a ``word'', may contain +parentheses or other characters that @value{GDBN} normally excludes from its +notion of a word. To permit word completion to work in this situation, +you may enclose words in @code{'} (single quote marks) in @value{GDBN} commands. + +@ifclear CONLY +The most likely situation where you might need this is in typing the +name of a C++ function. This is because C++ allows function overloading +(multiple definitions of the same function, distinguished by argument +type). For example, when you want to set a breakpoint you may need to +distinguish whether you mean the version of @code{name} that takes an +@code{int} parameter, @code{name(int)}, or the version that takes a +@code{float} parameter, @code{name(float)}. To use the word-completion +facilities in this situation, type a single quote @code{'} at the +beginning of the function name. This alerts @value{GDBN} that it may need to +consider more information than usual when you press @key{TAB} or +@kbd{M-?} to request word completion: + +@example +(@value{GDBP}) b 'bubble( @key{M-?} +bubble(double,double) bubble(int,int) +(@value{GDBP}) b 'bubble( +@end example + +In some cases, @value{GDBN} can tell that completing a name requires using +quotes. When this happens, @value{GDBN} inserts the quote for you (while +completing as much as it can) if you do not type the quote in the first +place: + +@example +(@value{GDBP}) b bub @key{TAB} +@exdent @value{GDBN} alters your input line to the following, and rings a bell: +(@value{GDBP}) b 'bubble( +@end example + +@noindent +In general, @value{GDBN} can tell that a quote is needed (and inserts it) if +you have not yet started typing the argument list when you ask for +completion on an overloaded symbol. +@end ifclear + + +@node Help +@section Getting help +@cindex online documentation +@kindex help + +You can always ask @value{GDBN} itself for information on its commands, +using the command @code{help}. + +@table @code +@kindex h +@item help +@itemx h +You can use @code{help} (abbreviated @code{h}) with no arguments to +display a short list of named classes of commands: + +@smallexample +(@value{GDBP}) help +List of classes of commands: + +running -- Running the program +stack -- Examining the stack +data -- Examining data +breakpoints -- Making program stop at certain points +files -- Specifying and examining files +status -- Status inquiries +support -- Support facilities +user-defined -- User-defined commands +aliases -- Aliases of other commands +obscure -- Obscure features + +Type "help" followed by a class name for a list of +commands in that class. +Type "help" followed by command name for full +documentation. +Command name abbreviations are allowed if unambiguous. +(@value{GDBP}) +@end smallexample + +@item help @var{class} +Using one of the general help classes as an argument, you can get a +list of the individual commands in that class. For example, here is the +help display for the class @code{status}: + +@smallexample +(@value{GDBP}) help status +Status inquiries. + +List of commands: + +@c Line break in "show" line falsifies real output, but needed +@c to fit in smallbook page size. +show -- Generic command for showing things set + with "set" +info -- Generic command for printing status + +Type "help" followed by command name for full +documentation. +Command name abbreviations are allowed if unambiguous. +(@value{GDBP}) +@end smallexample + +@item help @var{command} +With a command name as @code{help} argument, @value{GDBN} displays a +short paragraph on how to use that command. + +@kindex complete +@item complete @var{args} +The @code{complete @var{args}} command lists all the possible completions +for the beginning of a command. Use @var{args} to specify the beginning of the +command you want completed. For example: + +@smallexample +complete i +@end smallexample + +@noindent results in: + +@smallexample +info +inspect +ignore +@end smallexample + +@noindent This is intended for use by @sc{gnu} Emacs. +@end table + +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}. + +@c @group +@table @code +@kindex info +@kindex i +@item info +This command (abbreviated @code{i}) is for describing the state of your +program. For example, you can list the arguments given to your program +with @code{info args}, list the registers currently in use with @code{info +registers}, or list the breakpoints you have set with @code{info breakpoints}. +You can get a complete list of the @code{info} sub-commands with +@w{@code{help info}}. + +@kindex set +@item set +You can assign the result of an expresson to an environment variable with +@code{set}. For example, you can set the @value{GDBN} prompt to a $-sign with +@code{set prompt $}. + +@kindex show +@item show +In contrast to @code{info}, @code{show} is for describing the state of +@value{GDBN} itself. +You can change most of the things you can @code{show}, by using the +related command @code{set}; for example, you can control what number +system is used for displays with @code{set radix}, or simply inquire +which is currently in use with @code{show radix}. + +@kindex info set +To display all the settable parameters and their current +values, you can use @code{show} with no arguments; you may also use +@code{info set}. Both commands produce the same display. +@c FIXME: "info set" violates the rule that "info" is for state of +@c FIXME...program. Ck w/ GNU: "info set" to be called something else, +@c FIXME...or change desc of rule---eg "state of prog and debugging session"? +@end table +@c @end group + +Here are three miscellaneous @code{show} subcommands, all of which are +exceptional in lacking corresponding @code{set} commands: + +@table @code +@kindex show version +@cindex version number +@item show version +Show what version of @value{GDBN} is running. You should include this +information in @value{GDBN} bug-reports. If multiple versions of @value{GDBN} are in +use at your site, you may occasionally want to determine which version +of @value{GDBN} you are running; as @value{GDBN} evolves, new commands are introduced, +and old ones may wither away. The version number is also announced +when you start @value{GDBN}. + +@kindex show copying +@item show copying +Display information about permission for copying @value{GDBN}. + +@kindex show warranty +@item show warranty +Display the @sc{gnu} ``NO WARRANTY'' statement. +@end table + +@node Running +@chapter Running Programs Under @value{GDBN} + +When you run a program under @value{GDBN}, you must first generate +debugging information when you compile it. +@ifclear BARETARGET +You may start @value{GDBN} with its arguments, if any, in an environment +of your choice. You may redirect your program's input and output, debug an +already running process, or kill a child process. +@end ifclear + +@menu +* Compilation:: Compiling for debugging +* Starting:: Starting your program +@ifclear BARETARGET +* Arguments:: Your program's arguments +* Environment:: Your program's environment +* Working Directory:: Your program's working directory +* Input/Output:: Your program's input and output +* Attach:: Debugging an already-running process +* Kill Process:: Killing the child process +* Process Information:: Additional process information +* Threads:: Debugging programs with multiple threads +* Processes:: Debugging programs with multiple processes +@end ifclear +@end menu + +@node Compilation +@section Compiling for debugging + +In order to debug a program effectively, you need to generate +debugging information when you compile it. This debugging information +is stored in the object file; it describes the data type of each +variable or function and the correspondence between source line numbers +and addresses in the executable code. + +To request debugging information, specify the @samp{-g} option when you run +the compiler. + +Many C compilers are unable to handle the @samp{-g} and @samp{-O} +options together. Using those compilers, you cannot generate optimized +executables containing debugging information. + +@value{NGCC}, the @sc{gnu} C compiler, supports @samp{-g} with or without +@samp{-O}, making it possible to debug optimized code. We recommend +that you @emph{always} use @samp{-g} whenever you compile a program. +You may think your program is correct, but there is no sense in pushing +your luck. + +@cindex optimized code, debugging +@cindex debugging optimized code +When you debug a program compiled with @samp{-g -O}, remember that the +optimizer is rearranging your code; the debugger shows you what is +really there. Do not be too surprised when the execution path does not +exactly match your source file! An extreme example: if you define a +variable, but never use it, @value{GDBN} never sees that +variable---because the compiler optimizes it out of existence. + +Some things do not work as well with @samp{-g -O} as with just +@samp{-g}, particularly on machines with instruction scheduling. If in +doubt, recompile with @samp{-g} alone, and if this fixes the problem, +please report it to us as a bug (including a test case!). + +Older versions of the @sc{gnu} C compiler permitted a variant option +@w{@samp{-gg}} for debugging information. @value{GDBN} no longer supports this +format; if your @sc{gnu} C compiler has this option, do not use it. + +@need 2000 +@node Starting +@section Starting your program +@cindex starting +@cindex running + +@table @code +@kindex run +@item run +@itemx r +Use the @code{run} command to start your program under @value{GDBN}. You must +first specify the program name +@ifset VXWORKS +(except on VxWorks) +@end ifset +with an argument to @value{GDBN} (@pxref{Invocation, ,Getting In and +Out of @value{GDBN}}), or by using the @code{file} or @code{exec-file} +command (@pxref{Files, ,Commands to specify files}). + +@end table + +@ifclear BARETARGET +If you are running your program in an execution environment that +supports processes, @code{run} creates an inferior process and makes +that process run your program. (In environments without processes, +@code{run} jumps to the start of your program.) + +The execution of a program is affected by certain information it +receives from its superior. @value{GDBN} provides ways to specify this +information, which you must do @emph{before} starting your program. (You +can change it after starting your program, but such changes only affect +your program the next time you start it.) This information may be +divided into four categories: + +@table @asis +@item The @emph{arguments.} +Specify the arguments to give your program as the arguments of the +@code{run} command. If a shell is available on your target, the shell +is used to pass the arguments, so that you may use normal conventions +(such as wildcard expansion or variable substitution) in describing +the arguments. In Unix systems, you can control which shell is used +with the @code{SHELL} environment variable. @xref{Arguments, ,Your +program's arguments}. + +@item The @emph{environment.} +Your program normally inherits its environment from @value{GDBN}, but you can +use the @value{GDBN} commands @code{set environment} and @code{unset +environment} to change parts of the environment that affect +your program. @xref{Environment, ,Your program's environment}. + +@item The @emph{working directory.} +Your program inherits its working directory from @value{GDBN}. You can set +the @value{GDBN} working directory with the @code{cd} command in @value{GDBN}. +@xref{Working Directory, ,Your program's working directory}. + +@item The @emph{standard input and output.} +Your program normally uses the same device for standard input and +standard output as @value{GDBN} is using. You can redirect input and output +in the @code{run} command line, or you can use the @code{tty} command to +set a different device for your program. +@xref{Input/Output, ,Your program's input and output}. + +@cindex pipes +@emph{Warning:} While input and output redirection work, you cannot use +pipes to pass the output of the program you are debugging to another +program; if you attempt this, @value{GDBN} is likely to wind up debugging the +wrong program. +@end table +@end ifclear + +When you issue the @code{run} command, your program begins to execute +immediately. @xref{Stopping, ,Stopping and continuing}, for discussion +of how to arrange for your program to stop. Once your program has +stopped, you may call functions in your program, using the @code{print} +or @code{call} commands. @xref{Data, ,Examining Data}. + +If the modification time of your symbol file has changed since the last +time @value{GDBN} read its symbols, @value{GDBN} discards its symbol +table, and reads it again. When it does this, @value{GDBN} tries to retain +your current breakpoints. + +@ifclear BARETARGET +@node Arguments +@section Your program's arguments + +@cindex arguments (to your program) +The arguments to your program can be specified by the arguments of the +@code{run} command. They are passed to a shell, which expands wildcard +characters and performs redirection of I/O, and thence to your program. +Your @code{SHELL} environment variable (if it exists) specifies what +shell @value{GDBN} uses. If you do not define @code{SHELL}, +@value{GDBN} uses @code{/bin/sh}. + +@code{run} with no arguments uses the same arguments used by the previous +@code{run}, or those set by the @code{set args} command. + +@kindex set args +@table @code +@item set args +Specify the arguments to be used the next time your program is run. If +@code{set args} has no arguments, @code{run} executes your program +with no arguments. Once you have run your program with arguments, +using @code{set args} before the next @code{run} is the only way to run +it again without arguments. + +@kindex show args +@item show args +Show the arguments to give your program when it is started. +@end table + +@node Environment +@section Your program's environment + +@cindex environment (of your program) +The @dfn{environment} consists of a set of environment variables and +their values. Environment variables conventionally record such things as +your user name, your home directory, your terminal type, and your search +path for programs to run. Usually you set up environment variables with +the shell and they are inherited by all the other programs you run. When +debugging, it can be useful to try running your program with a modified +environment without having to start @value{GDBN} over again. + +@table @code +@kindex path +@item path @var{directory} +Add @var{directory} to the front of the @code{PATH} environment variable +(the search path for executables), for both @value{GDBN} and your program. +You may specify several directory names, separated by @samp{:} or +whitespace. If @var{directory} is already in the path, it is moved to +the front, so it is searched sooner. + +You can use the string @samp{$cwd} to refer to whatever is the current +working directory at the time @value{GDBN} searches the path. If you +use @samp{.} instead, it refers to the directory where you executed the +@code{path} command. @value{GDBN} replaces @samp{.} in the +@var{directory} argument (with the current path) before adding +@var{directory} to the search path. +@c 'path' is explicitly nonrepeatable, but RMS points out it is silly to +@c document that, since repeating it would be a no-op. + +@kindex show paths +@item show paths +Display the list of search paths for executables (the @code{PATH} +environment variable). + +@kindex show environment +@item show environment @r{[}@var{varname}@r{]} +Print the value of environment variable @var{varname} to be given to +your program when it starts. If you do not supply @var{varname}, +print the names and values of all environment variables to be given to +your program. You can abbreviate @code{environment} as @code{env}. + +@kindex set environment +@item set environment @var{varname} @r{[}=@r{]} @var{value} +Set environment variable @var{varname} to @var{value}. The value +changes for your program only, not for @value{GDBN} itself. @var{value} may +be any string; the values of environment variables are just strings, and +any interpretation is supplied by your program itself. The @var{value} +parameter is optional; if it is eliminated, the variable is set to a +null value. +@c "any string" here does not include leading, trailing +@c blanks. Gnu asks: does anyone care? + +For example, this command: + +@example +set env USER = foo +@end example + +@noindent +tells a Unix program, when subsequently run, that its user is named +@samp{foo}. (The spaces around @samp{=} are used for clarity here; they +are not actually required.) + +@kindex unset environment +@item unset environment @var{varname} +Remove variable @var{varname} from the environment to be passed to your +program. This is different from @samp{set env @var{varname} =}; +@code{unset environment} removes the variable from the environment, +rather than assigning it an empty value. +@end table + +@emph{Warning:} @value{GDBN} runs your program using the shell indicated +by your @code{SHELL} environment variable if it exists (or +@code{/bin/sh} if not). If your @code{SHELL} variable names a shell +that runs an initialization file---such as @file{.cshrc} for C-shell, or +@file{.bashrc} for BASH---any variables you set in that file affect +your program. You may wish to move setting of environment variables to +files that are only run when you sign on, such as @file{.login} or +@file{.profile}. + +@node Working Directory +@section Your program's working directory + +@cindex working directory (of your program) +Each time you start your program with @code{run}, it inherits its +working directory from the current working directory of @value{GDBN}. +The @value{GDBN} working directory is initially whatever it inherited +from its parent process (typically the shell), but you can specify a new +working directory in @value{GDBN} with the @code{cd} command. + +The @value{GDBN} working directory also serves as a default for the commands +that specify files for @value{GDBN} to operate on. @xref{Files, ,Commands to +specify files}. + +@table @code +@kindex cd +@item cd @var{directory} +Set the @value{GDBN} working directory to @var{directory}. + +@kindex pwd +@item pwd +Print the @value{GDBN} working directory. +@end table + +@node Input/Output +@section Your program's input and output + +@cindex redirection +@cindex i/o +@cindex terminal +By default, the program you run under @value{GDBN} does input and output to +the same terminal that @value{GDBN} uses. @value{GDBN} switches the terminal +to its own terminal modes to interact with you, but it records the terminal +modes your program was using and switches back to them when you continue +running your program. + +@table @code +@kindex info terminal +@item info terminal +Displays information recorded by @value{GDBN} about the terminal modes your +program is using. +@end table + +You can redirect your program's input and/or output using shell +redirection with the @code{run} command. For example, + +@example +run > outfile +@end example + +@noindent +starts your program, diverting its output to the file @file{outfile}. + +@kindex tty +@cindex controlling terminal +Another way to specify where your program should do input and output is +with the @code{tty} command. This command accepts a file name as +argument, and causes this file to be the default for future @code{run} +commands. It also resets the controlling terminal for the child +process, for future @code{run} commands. For example, + +@example +tty /dev/ttyb +@end example + +@noindent +directs that processes started with subsequent @code{run} commands +default to do input and output on the terminal @file{/dev/ttyb} and have +that as their controlling terminal. + +An explicit redirection in @code{run} overrides the @code{tty} command's +effect on the input/output device, but not its effect on the controlling +terminal. + +When you use the @code{tty} command or redirect input in the @code{run} +command, only the input @emph{for your program} is affected. The input +for @value{GDBN} still comes from your terminal. + +@node Attach +@section Debugging an already-running process +@kindex attach +@cindex attach + +@table @code +@item attach @var{process-id} +This command attaches to a running process---one that was started +outside @value{GDBN}. (@code{info files} shows your active +targets.) The command takes as argument a process ID. The usual way to +find out the process-id of a Unix process is with the @code{ps} utility, +or with the @samp{jobs -l} shell command. + +@code{attach} does not repeat if you press @key{RET} a second time after +executing the command. +@end table + +To use @code{attach}, your program must be running in an environment +which supports processes; for example, @code{attach} does not work for +programs on bare-board targets that lack an operating system. You must +also have permission to send the process a signal. + +When using @code{attach}, you should first use the @code{file} command +to specify the program running in the process and load its symbol table. +@xref{Files, ,Commands to Specify Files}. + +The first thing @value{GDBN} does after arranging to debug the specified +process is to stop it. You can examine and modify an attached process +with all the @value{GDBN} commands that are ordinarily available when you start +processes with @code{run}. You can insert breakpoints; you can step and +continue; you can modify storage. If you would rather the process +continue running, you may use the @code{continue} command after +attaching @value{GDBN} to the process. + +@table @code +@kindex detach +@item detach +When you have finished debugging the attached process, you can use the +@code{detach} command to release it from @value{GDBN} control. Detaching +the process continues its execution. After the @code{detach} command, +that process and @value{GDBN} become completely independent once more, and you +are ready to @code{attach} another process or start one with @code{run}. +@code{detach} does not repeat if you press @key{RET} again after +executing the command. +@end table + +If you exit @value{GDBN} or use the @code{run} command while you have an +attached process, you kill that process. By default, @value{GDBN} asks +for confirmation if you try to do either of these things; you can +control whether or not you need to confirm by using the @code{set +confirm} command (@pxref{Messages/Warnings, ,Optional warnings and +messages}). + +@node Kill Process +@c @group +@section Killing the child process + +@table @code +@kindex kill +@item kill +Kill the child process in which your program is running under @value{GDBN}. +@end table + +This command is useful if you wish to debug a core dump instead of a +running process. @value{GDBN} ignores any core dump file while your program +is running. +@c @end group + +On some operating systems, a program cannot be executed outside @value{GDBN} +while you have breakpoints set on it inside @value{GDBN}. You can use the +@code{kill} command in this situation to permit running your program +outside the debugger. + +The @code{kill} command is also useful if you wish to recompile and +relink your program, since on many systems it is impossible to modify an +executable file while it is running in a process. In this case, when you +next type @code{run}, @value{GDBN} notices that the file has changed, and +reads the symbol table again (while trying to preserve your current +breakpoint settings). + +@node Process Information +@section Additional process information + +@kindex /proc +@cindex process image +Some operating 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 on several +kinds of information about the process running your program. +@code{info proc} works only on SVR4 systems that support @code{procfs}. + +@table @code +@kindex info proc +@item info proc +Summarize available information about the process. + +@kindex info proc mappings +@item info proc mappings +Report on the address ranges accessible in the program, with information +on whether your program may read, write, or execute each range. + +@kindex info proc times +@item info proc times +Starting time, user CPU time, and system CPU time for your program and +its children. + +@kindex info proc id +@item info proc id +Report on the process IDs related to your program: its own process ID, +the ID of its parent, the process group ID, and the session ID. + +@kindex info proc status +@item info proc status +General information on the state of the process. If the process is +stopped, this report includes the reason for stopping, and any signal +received. + +@item info proc all +Show all the above information about the process. +@end table + +@node Threads +@section Debugging programs with multiple threads + +@cindex threads of execution +@cindex multiple threads +@cindex switching threads +In some operating systems, a single program may have more than one +@dfn{thread} of execution. The precise semantics of threads differ from +one operating system to another, but in general the threads of a single +program are akin to multiple processes---except that they share one +address space (that is, they can all examine and modify the same +variables). On the other hand, each thread has its own registers and +execution stack, and perhaps private memory. + +@value{GDBN} provides these facilities for debugging multi-thread +programs: + +@itemize @bullet +@item automatic notification of new threads +@item @samp{thread @var{threadno}}, a command to switch among threads +@item @samp{info threads}, a command to inquire about existing threads +@item @samp{thread apply [@var{threadno}] [@var{all}] @var{args}}, +a command to apply a command to a list of threads +@item thread-specific breakpoints +@end itemize + +@quotation +@emph{Warning:} These facilities are not yet available on every +@value{GDBN} configuration where the operating system supports threads. +If your @value{GDBN} does not support threads, these commands have no +effect. For example, a system without thread support shows no output +from @samp{info threads}, and always rejects the @code{thread} command, +like this: + +@smallexample +(@value{GDBP}) info threads +(@value{GDBP}) thread 1 +Thread ID 1 not known. Use the "info threads" command to +see the IDs of currently known threads. +@end smallexample +@c FIXME to implementors: how hard would it be to say "sorry, this GDB +@c doesn't support threads"? +@end quotation + +@cindex focus of debugging +@cindex current thread +The @value{GDBN} thread debugging facility allows you to observe all +threads while your program runs---but whenever @value{GDBN} takes +control, one thread in particular is always the focus of debugging. +This thread is called the @dfn{current thread}. Debugging commands show +program information from the perspective of the current thread. + +@kindex New @var{systag} +@cindex thread identifier (system) +@c FIXME-implementors!! It would be more helpful if the [New...] message +@c included GDB's numeric thread handle, so you could just go to that +@c thread without first checking `info threads'. +Whenever @value{GDBN} detects a new thread in your program, it displays +the target system's identification for the thread with a message in the +form @samp{[New @var{systag}]}. @var{systag} is a thread identifier +whose form varies depending on the particular system. For example, on +LynxOS, you might see + +@example +[New process 35 thread 27] +@end example + +@noindent +when @value{GDBN} notices a new thread. In contrast, on an SGI system, +the @var{systag} is simply something like @samp{process 368}, with no +further qualifier. + +@c FIXME!! (1) Does the [New...] message appear even for the very first +@c thread of a program, or does it only appear for the +@c second---i.e., when it becomes obvious we have a multithread +@c program? +@c (2) *Is* there necessarily a first thread always? Or do some +@c multithread systems permit starting a program with multiple +@c threads ab initio? + +@cindex thread number +@cindex thread identifier (GDB) +For debugging purposes, @value{GDBN} associates its own thread +number---always a single integer---with each thread in your program. + +@table @code +@kindex info threads +@item info threads +Display a summary of all threads currently in your +program. @value{GDBN} displays for each thread (in this order): + +@enumerate +@item the thread number assigned by @value{GDBN} + +@item the target system's thread identifier (@var{systag}) + +@item the current stack frame summary for that thread +@end enumerate + +@noindent +An asterisk @samp{*} to the left of the @value{GDBN} thread number +indicates the current thread. + +For example, +@end table +@c end table here to get a little more width for example + +@smallexample +(@value{GDBP}) info threads + 3 process 35 thread 27 0x34e5 in sigpause () + 2 process 35 thread 23 0x34e5 in sigpause () +* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8) + at threadtest.c:68 +@end smallexample + +@table @code +@kindex thread @var{threadno} +@item thread @var{threadno} +Make thread number @var{threadno} the current thread. The command +argument @var{threadno} is the internal @value{GDBN} thread number, as +shown in the first field of the @samp{info threads} display. +@value{GDBN} responds by displaying the system identifier of the thread +you selected, and its current stack frame summary: + +@smallexample +@c FIXME!! This example made up; find a @value{GDBN} w/threads and get real one +(@value{GDBP}) thread 2 +[Switching to process 35 thread 23] +0x34e5 in sigpause () +@end smallexample + +@noindent +As with the @samp{[New @dots{}]} message, the form of the text after +@samp{Switching to} depends on your system's conventions for identifying +threads. + +@kindex thread apply +@item thread apply [@var{threadno}] [@var{all}] @var{args} +The @code{thread apply} command allows you to apply a command to one or +more threads. Specify the numbers of the threads that you want affected +with the command argument @var{threadno}. @var{threadno} is the internal +@value{GDBN} thread number, as shown in the first field of the @samp{info +threads} display. To apply a command to all threads, use +@code{thread apply all} @var{args}. +@end table + +@cindex automatic thread selection +@cindex switching threads automatically +@cindex threads, automatic switching +Whenever @value{GDBN} stops your program, due to a breakpoint or a +signal, it automatically selects the thread where that breakpoint or +signal happened. @value{GDBN} alerts you to the context switch with a +message of the form @samp{[Switching to @var{systag}]} to identify the +thread. + +@xref{Thread Stops,,Stopping and starting multi-thread programs}, for +more information about how @value{GDBN} behaves when you stop and start +programs with multiple threads. + +@xref{Set Watchpoints,,Setting watchpoints}, for information about +watchpoints in programs with multiple threads. +@end ifclear + +@node Processes +@section Debugging programs with multiple processes + +@cindex fork, debugging programs which call +@cindex multiple processes +@cindex processes, multiple +@value{GDBN} has no special support for debugging programs which create +additional processes using the @code{fork} function. When a program +forks, @value{GDBN} will continue to debug the parent process and the +child process will run unimpeded. If you have set a breakpoint in any +code which the child then executes, the child will get a @code{SIGTRAP} +signal which (unless it catches the signal) will cause it to terminate. + +However, if you want to debug the child process there is a workaround +which isn't too painful. Put a call to @code{sleep} in the code which +the child process executes after the fork. It may be useful to sleep +only if a certain environment variable is set, or a certain file exists, +so that the delay need not occur when you don't want to run @value{GDBN} +on the child. While the child is sleeping, use the @code{ps} program to +get its process ID. Then tell @value{GDBN} (a new invocation of +@value{GDBN} if you are also debugging the parent process) to attach to +the child process (see @ref{Attach}). From that point on you can debug +the child process just like any other process which you attached to. + +@node Stopping +@chapter Stopping and Continuing + +The principal purposes of using a debugger are so that you can stop your +program before it terminates; or so that, if your program runs into +trouble, you can investigate and find out why. + +Inside @value{GDBN}, your program may stop for any of several reasons, such +as +@ifclear BARETARGET +a signal, +@end ifclear +a breakpoint, or reaching a new line after a @value{GDBN} +command such as @code{step}. You may then examine and change +variables, set new breakpoints or remove old ones, and then continue +execution. Usually, the messages shown by @value{GDBN} provide ample +explanation of the status of your program---but you can also explicitly +request this information at any time. + +@table @code +@kindex info program +@item info program +Display information about the status of your program: whether it is +running or not, +@ifclear BARETARGET +what process it is, +@end ifclear +and why it stopped. +@end table + +@menu +@ifclear CONLY +* Breakpoints:: Breakpoints, watchpoints, and exceptions +@end ifclear +@ifset CONLY +* Breakpoints:: Breakpoints and watchpoints +@end ifset +@c Remnant makeinfo bug requires blank line after *successful* end-if in menu: + +* Continuing and Stepping:: Resuming execution +@ifset POSIX +* Signals:: Signals +@end ifset +@ifclear BARETARGET +* Thread Stops:: Stopping and starting multi-thread programs +@end ifclear +@end menu + +@c makeinfo node-defaulting requires adjacency of @node and sectioning cmds +@c ...hence distribute @node Breakpoints over two possible @if expansions. +@c +@ifclear CONLY +@node Breakpoints +@section Breakpoints, watchpoints, and exceptions +@end ifclear +@ifset CONLY +@node Breakpoints +@section Breakpoints and watchpoints +@end ifset + +@cindex breakpoints +A @dfn{breakpoint} makes your program stop whenever a certain point in +the program is reached. For each breakpoint, you can add +conditions to control in finer detail whether your program stops. +You can set breakpoints with the @code{break} command and its variants +(@pxref{Set Breaks, ,Setting breakpoints}), to specify the place where +your program should stop by line number, function name or exact address +in the program. +@ifclear CONLY +In languages with exception handling (such as @sc{gnu} C++), you can also set +breakpoints where an exception is raised (@pxref{Exception Handling,, +Breakpoints and exceptions}). +@end ifclear + +In SunOS 4.x, SVR4, and Alpha OSF/1 configurations, you can now set +breakpoints in shared libraries before the executable is run. + +@cindex watchpoints +@cindex memory tracing +@cindex breakpoint on memory address +@cindex breakpoint on variable modification +A @dfn{watchpoint} is a special breakpoint that stops your program +when the value of an expression changes. You must use a different +command to set watchpoints (@pxref{Set Watchpoints, ,Setting +watchpoints}), but aside from that, you can manage a watchpoint like +any other breakpoint: you enable, disable, and delete both breakpoints +and watchpoints using the same commands. + +You can arrange to have values from your program displayed automatically +whenever @value{GDBN} stops at a breakpoint. @xref{Auto Display,, +Automatic display}. + +@cindex breakpoint numbers +@cindex numbers for breakpoints +@value{GDBN} assigns a number to each breakpoint or watchpoint when you +create it; these numbers are successive integers starting with one. In +many of the commands for controlling various features of breakpoints you +use the breakpoint number to say which breakpoint you want to change. +Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has +no effect on your program until you enable it again. + +@menu +* Set Breaks:: Setting breakpoints +* Set Watchpoints:: Setting watchpoints +@ifclear CONLY +* Exception Handling:: Breakpoints and exceptions +@end ifclear + +* Delete Breaks:: Deleting breakpoints +* Disabling:: Disabling breakpoints +* Conditions:: Break conditions +* Break Commands:: Breakpoint command lists +@ifclear CONLY +* Breakpoint Menus:: Breakpoint menus +@end ifclear +@c @ifclear BARETARGET +@c * Error in Breakpoints:: ``Cannot insert breakpoints'' +@c @end ifclear +@end menu + +@node Set Breaks +@subsection Setting breakpoints + +@c FIXME LMB what does GDB do if no code on line of breakpt? +@c consider in particular declaration with/without initialization. +@c +@c FIXME 2 is there stuff on this already? break at fun start, already init? + +@kindex break +@kindex b +@kindex $bpnum +@cindex latest breakpoint +Breakpoints are set with the @code{break} command (abbreviated +@code{b}). The debugger convenience variable @samp{$bpnum} records the +number of the breakpoints you've set most recently; see @ref{Convenience +Vars,, Convenience variables}, for a discussion of what you can do with +convenience variables. + +You have several ways to say where the breakpoint should go. + +@table @code +@item break @var{function} +Set a breakpoint at entry to function @var{function}. +@ifclear CONLY +When using source languages that permit overloading of symbols, such as +C++, @var{function} may refer to more than one possible place to break. +@xref{Breakpoint Menus,,Breakpoint menus}, for a discussion of that situation. +@end ifclear + +@item break +@var{offset} +@itemx break -@var{offset} +Set a breakpoint some number of lines forward or back from the position +at which execution stopped in the currently selected frame. + +@item break @var{linenum} +Set a breakpoint at line @var{linenum} in the current source file. +That file is the last file whose source text was printed. This +breakpoint stops your program just before it executes any of the +code on that line. + +@item break @var{filename}:@var{linenum} +Set a breakpoint at line @var{linenum} in source file @var{filename}. + +@item break @var{filename}:@var{function} +Set a breakpoint at entry to function @var{function} found in file +@var{filename}. Specifying a file name as well as a function name is +superfluous except when multiple files contain similarly named +functions. + +@item break *@var{address} +Set a breakpoint at address @var{address}. You can use this to set +breakpoints in parts of your program which do not have debugging +information or source files. + +@item break +When called without any arguments, @code{break} sets a breakpoint at +the next instruction to be executed in the selected stack frame +(@pxref{Stack, ,Examining the Stack}). In any selected frame but the +innermost, this makes your program stop as soon as control +returns to that frame. This is similar to the effect of a +@code{finish} command in the frame inside the selected frame---except +that @code{finish} does not leave an active breakpoint. If you use +@code{break} without an argument in the innermost frame, @value{GDBN} stops +the next time it reaches the current location; this may be useful +inside loops. + +@value{GDBN} normally ignores breakpoints when it resumes execution, until at +least one instruction has been executed. If it did not do this, you +would be unable to proceed past a breakpoint without first disabling the +breakpoint. This rule applies whether or not the breakpoint already +existed when your program stopped. + +@item break @dots{} if @var{cond} +Set a breakpoint with condition @var{cond}; evaluate the expression +@var{cond} each time the breakpoint is reached, and stop only if the +value is nonzero---that is, if @var{cond} evaluates as true. +@samp{@dots{}} stands for one of the possible arguments described +above (or no argument) specifying where to break. @xref{Conditions, +,Break conditions}, for more information on breakpoint conditions. + +@kindex tbreak +@item tbreak @var{args} +Set a breakpoint enabled only for one stop. @var{args} are the +same as for the @code{break} command, and the breakpoint is set in the same +way, but the breakpoint is automatically deleted after the first time your +program stops there. @xref{Disabling, ,Disabling breakpoints}. + +@kindex hbreak +@item hbreak @var{args} +Set a hardware-assisted breakpoint. @var{args} are the same as for the +@code{break} command and the breakpoint is set in the same way, but the +breakpoint requires hardware support and some target hardware may not +have this support. The main purpose of this is EPROM/ROM code +debugging, so you can set a breakpoint at an instruction without +changing the instruction. This can be used with the new trap-generation +provided by SPARClite DSU. DSU will generate traps when a program accesses +some date or instruction address that is assigned to the debug registers. +However the hardware breakpoint registers can only take two data breakpoints, +and @value{GDBN} will reject this command if more than two are used. +Delete or disable usused hardware breakpoints before setting +new ones. @xref{Conditions, ,Break conditions}. + +@kindex thbreak +@item thbreak @var{args} +Set a hardware-assisted breakpoint enabled only for one stop. @var{args} +are the same as for the @code{hbreak} command and the breakpoint is set in +the same way. However, like the @code{tbreak} command, +the breakpoint is automatically deleted after the +first time your program stops there. Also, like the @code{hbreak} +command, the breakpoint requires hardware support and some target hardware +may not have this support. @xref{Disabling, ,Disabling breakpoints}. +Also @xref{Conditions, ,Break conditions}. + +@kindex rbreak +@cindex regular expression +@item rbreak @var{regex} +@c FIXME what kind of regexp? +Set breakpoints on all functions matching the regular expression +@var{regex}. This command +sets an unconditional breakpoint on all matches, printing a list of all +breakpoints it set. Once these breakpoints are set, they are treated +just like the breakpoints set with the @code{break} command. You can +delete them, disable them, or make them conditional the same way as any +other breakpoint. + +@ifclear CONLY +When debugging C++ programs, @code{rbreak} is useful for setting +breakpoints on overloaded functions that are not members of any special +classes. +@end ifclear + +@kindex info breakpoints +@cindex @code{$_} and @code{info breakpoints} +@item info breakpoints @r{[}@var{n}@r{]} +@itemx info break @r{[}@var{n}@r{]} +@itemx info watchpoints @r{[}@var{n}@r{]} +Print a table of all breakpoints and watchpoints set and not +deleted, with the following columns for each breakpoint: + +@table @emph +@item Breakpoint Numbers +@item Type +Breakpoint or watchpoint. +@item Disposition +Whether the breakpoint is marked to be disabled or deleted when hit. +@item Enabled or Disabled +Enabled breakpoints are marked with @samp{y}. @samp{n} marks breakpoints +that are not enabled. +@item Address +Where the breakpoint is in your program, as a memory address +@item What +Where the breakpoint is in the source for your program, as a file and +line number. +@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. + +@noindent +@code{info break} with a breakpoint +number @var{n} as argument lists only that breakpoint. The +convenience variable @code{$_} and the default examining-address for +the @code{x} command are set to the address of the last breakpoint +listed (@pxref{Memory, ,Examining memory}). + +@noindent +@code{info break} now displays a count of the number of times the +breakpoint has been hit. This is especially useful in conjunction with +the @code{ignore} command. You can ignore a large number of breakpoint +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. +@end table + +@value{GDBN} allows you to set any number of breakpoints at the same place in +your program. There is nothing silly or meaningless about this. When +the breakpoints are conditional, this is even useful +(@pxref{Conditions, ,Break conditions}). + +@cindex negative breakpoint numbers +@cindex internal @value{GDBN} breakpoints +@value{GDBN} itself sometimes sets breakpoints in your program for special +purposes, such as proper handling of @code{longjmp} (in C programs). +These internal breakpoints are assigned negative numbers, starting with +@code{-1}; @samp{info breakpoints} does not display them. + +You can see these breakpoints with the @value{GDBN} maintenance command +@samp{maint info breakpoints}. + +@table @code +@kindex maint info breakpoints +@item maint info breakpoints +Using the same format as @samp{info breakpoints}, display both the +breakpoints you've set explicitly, and those @value{GDBN} is using for +internal purposes. Internal breakpoints are shown with negative +breakpoint numbers. The type column identifies what kind of breakpoint +is shown: + +@table @code +@item breakpoint +Normal, explicitly set breakpoint. + +@item watchpoint +Normal, explicitly set watchpoint. + +@item longjmp +Internal breakpoint, used to handle correctly stepping through +@code{longjmp} calls. + +@item longjmp resume +Internal breakpoint at the target of a @code{longjmp}. + +@item until +Temporary internal breakpoint used by the @value{GDBN} @code{until} command. + +@item finish +Temporary internal breakpoint used by the @value{GDBN} @code{finish} command. +@end table + +@end table + + +@node Set Watchpoints +@subsection Setting watchpoints +@cindex setting watchpoints + +You can use a watchpoint to stop execution whenever the value of an +expression changes, without having to predict a particular place +where this may happen. + +Watchpoints currently execute two orders of magnitude more slowly than +other breakpoints, but this can be well worth it to catch errors where +you have no clue what part of your program is the culprit. + +@c FIXME - did Stan mean to @ignore this out? +@ignore +Some processors provide special hardware to support watchpoint +evaluation; @value{GDBN} will use such hardware if it is available, +and if the support code has been added for that configuration. +@end ignore + +@table @code +@kindex watch +@item watch @var{expr} +Set a watchpoint for an expression. @value{GDBN} will break when @var{expr} +is written into by the program and its value changes. +This can be used with the new trap-generation provided by +SPARClite DSU. DSU will generate traps when a program accesses +some date or instruction address that is assigned to the debug registers. +For the data addresses, DSU facilitates the @code{watch} command. +However the hardware breakpoint registers can only take two data watchpoints, +and both watchpoints must be the same kind. For example, you can set two +watchpoints with @code{watch} commands, two with @code{rwatch} +commands, @strong{or} two with @code{awatch} commands, but you cannot set one +watchpoint with one command and the other with a different command. +@value{GBDN} will reject the command if you try to mix watchpoints. +Delete or disable unused watchpoint commands before setting new ones. + +@kindex rwatch +@item rwatch @var{expr} +Set a watchpoint that will break when watch @var{args} is read by the program. +If you use both watchpoints, both must be set with the @code{rwatch} +command. + +@kindex awatch +@item awatch @var{expr} +Set a watchpoint that will break when @var{args} is read and written into +by the program. If you use both watchpoints, both must be set with the +@code{awatch} command. + +@kindex info watchpoints +@item info watchpoints +This command prints a list of watchpoints and breakpoints; it is the +same as @code{info break}. +@end table + +@ifclear BARETARGET +@quotation +@cindex watchpoints and threads +@cindex threads and watchpoints +@emph{Warning:} in multi-thread programs, watchpoints have only limited +usefulness. With the current watchpoint implementation, @value{GDBN} +can only watch the value of an expression @emph{in a single thread}. If +you are confident that the expression can only change due to the current +thread's activity (and if you are also confident that no other thread +can become current), then you can use watchpoints as usual. However, +@value{GDBN} may not notice when a non-current thread's activity changes +the expression. +@end quotation +@end ifclear + +@ifclear CONLY +@node Exception Handling +@subsection Breakpoints and exceptions +@cindex exception handlers + +Some languages, such as @sc{gnu} C++, implement exception handling. You can +use @value{GDBN} to examine what caused your program to raise an exception, +and to list the exceptions your program is prepared to handle at a +given point in time. + +@table @code +@kindex catch +@item catch @var{exceptions} +You can set breakpoints at active exception handlers by using the +@code{catch} command. @var{exceptions} is a list of names of exceptions +to catch. +@end table + +You can use @code{info catch} to list active exception handlers. +@xref{Frame Info, ,Information about a frame}. + +There are currently some limitations to exception handling in @value{GDBN}: + +@itemize @bullet +@item +If you call a function interactively, @value{GDBN} normally returns +control to you when the function has finished executing. If the call +raises an exception, however, the call may bypass the mechanism that +returns control to you and cause your program to simply continue +running until it hits a breakpoint, catches a signal that @value{GDBN} is +listening for, or exits. + +@item +You cannot raise an exception interactively. + +@item +You cannot install an exception handler interactively. +@end itemize + +@cindex raise exceptions +Sometimes @code{catch} is not the best way to debug exception handling: +if you need to know exactly where an exception is raised, it is better to +stop @emph{before} the exception handler is called, since that way you +can see the stack before any unwinding takes place. If you set a +breakpoint in an exception handler instead, it may not be easy to find +out where the exception was raised. + +To stop just before an exception handler is called, you need some +knowledge of the implementation. In the case of @sc{gnu} C++, exceptions are +raised by calling a library function named @code{__raise_exception} +which has the following ANSI C interface: + +@example + /* @var{addr} is where the exception identifier is stored. + ID is the exception identifier. */ + void __raise_exception (void **@var{addr}, void *@var{id}); +@end example + +@noindent +To make the debugger catch all exceptions before any stack +unwinding takes place, set a breakpoint on @code{__raise_exception} +(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}). + +With a conditional breakpoint (@pxref{Conditions, ,Break conditions}) +that depends on the value of @var{id}, you can stop your program when +a specific exception is raised. You can use multiple conditional +breakpoints to stop your program when any of a number of exceptions are +raised. +@end ifclear + +@node Delete Breaks +@subsection Deleting breakpoints + +@cindex clearing breakpoints, watchpoints +@cindex deleting breakpoints, watchpoints +It is often necessary to eliminate a breakpoint or watchpoint once it +has done its job and you no longer want your program to stop there. This +is called @dfn{deleting} the breakpoint. A breakpoint that has been +deleted no longer exists; it is forgotten. + +With the @code{clear} command you can delete breakpoints according to +where they are in your program. With the @code{delete} command you can +delete individual breakpoints or watchpoints by specifying their +breakpoint numbers. + +It is not necessary to delete a breakpoint to proceed past it. @value{GDBN} +automatically ignores breakpoints on the first instruction to be executed +when you continue execution without changing the execution address. + +@table @code +@item clear +@kindex clear +Delete any breakpoints at the next instruction to be executed in the +selected stack frame (@pxref{Selection, ,Selecting a frame}). When +the innermost frame is selected, this is a good way to delete a +breakpoint where your program just stopped. + +@item clear @var{function} +@itemx clear @var{filename}:@var{function} +Delete any breakpoints set at entry to the function @var{function}. + +@item clear @var{linenum} +@itemx clear @var{filename}:@var{linenum} +Delete any breakpoints set at or within the code of the specified line. + +@cindex delete breakpoints +@kindex delete +@kindex d +@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +Delete the breakpoints or watchpoints of the numbers specified as +arguments. If no argument is specified, delete all breakpoints (@value{GDBN} +asks confirmation, unless you have @code{set confirm off}). You +can abbreviate this command as @code{d}. +@end table + +@node Disabling +@subsection Disabling breakpoints + +@kindex disable breakpoints +@kindex enable breakpoints +Rather than deleting a breakpoint or watchpoint, you might prefer to +@dfn{disable} it. This makes the breakpoint inoperative as if it had +been deleted, but remembers the information on the breakpoint so that +you can @dfn{enable} it again later. + +You disable and enable breakpoints and watchpoints with the +@code{enable} and @code{disable} commands, optionally specifying one or +more breakpoint numbers as arguments. Use @code{info break} or +@code{info watch} to print a list of breakpoints or watchpoints if you +do not know which numbers to use. + +A breakpoint or watchpoint can have any of four different states of +enablement: + +@itemize @bullet +@item +Enabled. The breakpoint stops your program. A breakpoint set +with the @code{break} command starts out in this state. +@item +Disabled. The breakpoint has no effect on your program. +@item +Enabled once. The breakpoint stops your program, but then becomes +disabled. A breakpoint set with the @code{tbreak} command starts out in +this state. +@item +Enabled for deletion. The breakpoint stops your program, but +immediately after it does so it is deleted permanently. +@end itemize + +You can use the following commands to enable or disable breakpoints and +watchpoints: + +@table @code +@kindex disable breakpoints +@kindex disable +@kindex dis +@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +Disable the specified breakpoints---or all breakpoints, if none are +listed. A disabled breakpoint has no effect but is not forgotten. All +options such as ignore-counts, conditions and commands are remembered in +case the breakpoint is enabled again later. You may abbreviate +@code{disable} as @code{dis}. + +@kindex enable breakpoints +@kindex enable +@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +Enable the specified breakpoints (or all defined breakpoints). They +become effective once again in stopping your program. + +@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{} +Enable the specified breakpoints temporarily. @value{GDBN} disables any +of these breakpoints immediately after stopping your program. + +@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{} +Enable the specified breakpoints to work once, then die. @value{GDBN} +deletes any of these breakpoints as soon as your program stops there. +@end table + +Except for a breakpoint set with @code{tbreak} (@pxref{Set Breaks, +,Setting breakpoints}), breakpoints that you set are initially enabled; +subsequently, they become disabled or enabled only when you use one of +the commands above. (The command @code{until} can set and delete a +breakpoint of its own, but it does not change the state of your other +breakpoints; see @ref{Continuing and Stepping, ,Continuing and +stepping}.) + +@node Conditions +@subsection Break conditions +@cindex conditional breakpoints +@cindex breakpoint conditions + +@c FIXME what is scope of break condition expr? Context where wanted? +@c in particular for a watchpoint? +The simplest sort of breakpoint breaks every time your program reaches a +specified place. You can also specify a @dfn{condition} for a +breakpoint. A condition is just a Boolean expression in your +programming language (@pxref{Expressions, ,Expressions}). A breakpoint with +a condition evaluates the expression each time your program reaches it, +and your program stops only if the condition is @emph{true}. + +This is the converse of using assertions for program validation; in that +situation, you want to stop when the assertion is violated---that is, +when the condition is false. In C, if you want to test an assertion expressed +by the condition @var{assert}, you should set the condition +@samp{! @var{assert}} on the appropriate breakpoint. + +Conditions are also accepted for watchpoints; you may not need them, +since a watchpoint is inspecting the value of an expression anyhow---but +it might be simpler, say, to just set a watchpoint on a variable name, +and specify a condition that tests whether the new value is an interesting +one. + +Break conditions can have side effects, and may even call functions in +your program. This can be useful, for example, to activate functions +that log program progress, or to use your own print functions to +format special data structures. The effects are completely predictable +unless there is another enabled breakpoint at the same address. (In +that case, @value{GDBN} might see the other breakpoint first and stop your +program without checking the condition of this one.) Note that +breakpoint commands are usually more convenient and flexible for the +purpose of performing side effects when a breakpoint is reached +(@pxref{Break Commands, ,Breakpoint command lists}). + +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 +with the @code{condition} command. The @code{watch} command does not +recognize the @code{if} keyword; @code{condition} is the only way to +impose a further condition on a watchpoint. + +@table @code +@kindex condition +@item condition @var{bnum} @var{expression} +Specify @var{expression} as the break condition for breakpoint or +watchpoint number @var{bnum}. After you set a condition, breakpoint +@var{bnum} stops your program only if the value of @var{expression} is +true (nonzero, in C). When you use @code{condition}, @value{GDBN} +checks @var{expression} immediately for syntactic correctness, and to +determine whether symbols in it have referents in the context of your +breakpoint. +@c FIXME so what does GDB do if there is no referent? Moreover, what +@c about watchpoints? +@value{GDBN} does +not actually evaluate @var{expression} at the time the @code{condition} +command is given, however. @xref{Expressions, ,Expressions}. + +@item condition @var{bnum} +Remove the condition from breakpoint number @var{bnum}. It becomes +an ordinary unconditional breakpoint. +@end table + +@cindex ignore count (of breakpoint) +A special case of a breakpoint condition is to stop only when the +breakpoint has been reached a certain number of times. This is so +useful that there is a special way to do it, using the @dfn{ignore +count} of the breakpoint. Every breakpoint has an ignore count, which +is an integer. Most of the time, the ignore count is zero, and +therefore has no effect. But if your program reaches a breakpoint whose +ignore count is positive, then instead of stopping, it just decrements +the ignore count by one and continues. As a result, if the ignore count +value is @var{n}, the breakpoint does not stop the next @var{n} times +your program reaches it. + +@table @code +@kindex ignore +@item ignore @var{bnum} @var{count} +Set the ignore count of breakpoint number @var{bnum} to @var{count}. +The next @var{count} times the breakpoint is reached, your program's +execution does not stop; other than to decrement the ignore count, @value{GDBN} +takes no action. + +To make the breakpoint stop the next time it is reached, specify +a count of zero. + +When you use @code{continue} to resume execution of your program from a +breakpoint, you can specify an ignore count directly as an argument to +@code{continue}, rather than using @code{ignore}. @xref{Continuing and +Stepping,,Continuing and stepping}. + +If a breakpoint has a positive ignore count and a condition, the +condition is not checked. Once the ignore count reaches zero, +@value{GDBN} resumes checking the condition. + +You could achieve the effect of the ignore count with a condition such +as @w{@samp{$foo-- <= 0}} using a debugger convenience variable that +is decremented each time. @xref{Convenience Vars, ,Convenience +variables}. +@end table + +@node Break Commands +@subsection Breakpoint command lists + +@cindex breakpoint commands +You can give any breakpoint (or watchpoint) a series of commands to +execute when your program stops due to that breakpoint. For example, you +might want to print the values of certain expressions, or enable other +breakpoints. + +@table @code +@kindex commands +@kindex end +@item commands @r{[}@var{bnum}@r{]} +@itemx @dots{} @var{command-list} @dots{} +@itemx end +Specify a list of commands for breakpoint number @var{bnum}. The commands +themselves appear on the following lines. Type a line containing just +@code{end} to terminate the commands. + +To remove all commands from a breakpoint, type @code{commands} and +follow it immediately with @code{end}; that is, give no commands. + +With no @var{bnum} argument, @code{commands} refers to the last +breakpoint or watchpoint set (not to the breakpoint most recently +encountered). +@end table + +Pressing @key{RET} as a means of repeating the last @value{GDBN} command is +disabled within a @var{command-list}. + +You can use breakpoint commands to start your program up again. Simply +use the @code{continue} command, or @code{step}, or any other command +that resumes execution. + +Any other commands in the command list, after a command that resumes +execution, are ignored. This is because any time you resume execution +(even with a simple @code{next} or @code{step}), you may encounter +another breakpoint---which could have its own command list, leading to +ambiguities about which list to execute. + +@kindex silent +If the first command you specify in a command list is @code{silent}, the +usual message about stopping at a breakpoint is not printed. This may +be desirable for breakpoints that are to print a specific message and +then continue. If none of the remaining commands print anything, you +see no sign that the breakpoint was reached. @code{silent} is +meaningful only at the beginning of a breakpoint command list. + +The commands @code{echo}, @code{output}, and @code{printf} allow you to +print precisely controlled output, and are often useful in silent +breakpoints. @xref{Output, ,Commands for controlled output}. + +For example, here is how you could use breakpoint commands to print the +value of @code{x} at entry to @code{foo} whenever @code{x} is positive. + +@example +break foo if x>0 +commands +silent +printf "x is %d\n",x +cont +end +@end example + +One application for breakpoint commands is to compensate for one bug so +you can test for another. Put a breakpoint just after the erroneous line +of code, give it a condition to detect the case in which something +erroneous has been done, and give it commands to assign correct values +to any variables that need them. End with the @code{continue} command +so that your program does not stop, and start with the @code{silent} +command so that no output is produced. Here is an example: + +@example +break 403 +commands +silent +set x = y + 4 +cont +end +@end example + +@ifclear CONLY +@node Breakpoint Menus +@subsection Breakpoint menus +@cindex overloading +@cindex symbol overloading + +Some programming languages (notably C++) permit a single function name +to be defined several times, for application in different contexts. +This is called @dfn{overloading}. When a function name is overloaded, +@samp{break @var{function}} is not enough to tell @value{GDBN} where you want +a breakpoint. If you realize this is a problem, you can use +something like @samp{break @var{function}(@var{types})} to specify which +particular version of the function you want. Otherwise, @value{GDBN} offers +you a menu of numbered choices for different possible breakpoints, and +waits for your selection with the prompt @samp{>}. The first two +options are always @samp{[0] cancel} and @samp{[1] all}. Typing @kbd{1} +sets a breakpoint at each definition of @var{function}, and typing +@kbd{0} aborts the @code{break} command without setting any new +breakpoints. + +For example, the following session excerpt shows an attempt to set a +breakpoint at the overloaded symbol @code{String::after}. +We choose three particular definitions of that function name: + +@c FIXME! This is likely to change to show arg type lists, at least +@smallexample +(@value{GDBP}) b String::after +[0] cancel +[1] all +[2] file:String.cc; line number:867 +[3] file:String.cc; line number:860 +[4] file:String.cc; line number:875 +[5] file:String.cc; line number:853 +[6] file:String.cc; line number:846 +[7] file:String.cc; line number:735 +> 2 4 6 +Breakpoint 1 at 0xb26c: file String.cc, line 867. +Breakpoint 2 at 0xb344: file String.cc, line 875. +Breakpoint 3 at 0xafcc: file String.cc, line 846. +Multiple breakpoints were set. +Use the "delete" command to delete unwanted + breakpoints. +(@value{GDBP}) +@end smallexample +@end ifclear + +@c @ifclear BARETARGET +@c @node Error in Breakpoints +@c @subsection ``Cannot insert breakpoints'' +@c +@c FIXME!! 14/6/95 Is there a real example of this? Let's use it. +@c +@c Under some operating systems, breakpoints cannot be used in a program if +@c any other process is running that program. In this situation, +@c attempting to run or continue a program with a breakpoint causes +@c @value{GDBN} to stop the other process. +@c +@c When this happens, you have three ways to proceed: +@c +@c @enumerate +@c @item +@c Remove or disable the breakpoints, then continue. +@c +@c @item +@c Suspend @value{GDBN}, and copy the file containing your program to a new +@c name. Resume @value{GDBN} and use the @code{exec-file} command to specify +@c that @value{GDBN} should run your program under that name. +@c Then start your program again. +@c +@c @item +@c Relink your program so that the text segment is nonsharable, using the +@c linker option @samp{-N}. The operating system limitation may not apply +@c to nonsharable executables. +@c @end enumerate +@c @end ifclear + +@node Continuing and Stepping +@section Continuing and stepping + +@cindex stepping +@cindex continuing +@cindex resuming execution +@dfn{Continuing} means resuming program execution until your program +completes normally. In contrast, @dfn{stepping} means executing just +one more ``step'' of your program, where ``step'' may mean either one +line of source code, or one machine instruction (depending on what +particular command you use). Either when continuing +or when stepping, your program may stop even sooner, due to +@ifset BARETARGET +a breakpoint. +@end ifset +@ifclear BARETARGET +a breakpoint or a signal. (If due to a signal, you may want to use +@code{handle}, or use @samp{signal 0} to resume execution. +@xref{Signals, ,Signals}.) +@end ifclear + +@table @code +@kindex continue +@kindex c +@kindex fg +@item continue @r{[}@var{ignore-count}@r{]} +@itemx c @r{[}@var{ignore-count}@r{]} +@itemx fg @r{[}@var{ignore-count}@r{]} +Resume program execution, at the address where your program last stopped; +any breakpoints set at that address are bypassed. The optional argument +@var{ignore-count} allows you to specify a further number of times to +ignore a breakpoint at this location; its effect is like that of +@code{ignore} (@pxref{Conditions, ,Break conditions}). + +The argument @var{ignore-count} is meaningful only when your program +stopped due to a breakpoint. At other times, the argument to +@code{continue} is ignored. + +The synonyms @code{c} and @code{fg} are provided purely for convenience, +and have exactly the same behavior as @code{continue}. +@end table + +To resume execution at a different place, you can use @code{return} +(@pxref{Returning, ,Returning from a function}) to go back to the +calling function; or @code{jump} (@pxref{Jumping, ,Continuing at a +different address}) to go to an arbitrary location in your program. + +A typical technique for using stepping is to set a breakpoint +@ifclear CONLY +(@pxref{Breakpoints, ,Breakpoints; watchpoints; and exceptions}) +@end ifclear +@ifset CONLY +(@pxref{Breakpoints, ,Breakpoints and watchpoints}) +@end ifset +at the +beginning of the function or the section of your program where a +problem is believed to lie, run your program until it stops at that +breakpoint, and then step through the suspect area, examining the +variables that are interesting, until you see the problem happen. + +@table @code +@kindex step +@kindex s +@item step +Continue running your program until control reaches a different source +line, then stop it and return control to @value{GDBN}. This command is +abbreviated @code{s}. + +@quotation +@c "without debugging information" is imprecise; actually "without line +@c numbers in the debugging information". (gcc -g1 has debugging info but +@c not line numbers). But it seems complex to try to make that +@c distinction here. +@emph{Warning:} If you use the @code{step} command while control is +within a function that was compiled without debugging information, +execution proceeds until control reaches a function that does have +debugging information. Likewise, it will not step into a function which +is compiled without debugging information. To step through functions +without debugging information, use the @code{stepi} command, described +below. +@end quotation + +The @code{step} command now only stops at the first instruction of a +source line. This prevents the multiple stops that used to occur in +switch statements, for loops, etc. @code{step} continues to stop if a +function that has debugging information is called within the line. + +Also, the @code{step} command now only enters a subroutine if there is line +number information for the subroutine. 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 +was any debugging information about the routine. + +@item step @var{count} +Continue running as in @code{step}, but do so @var{count} times. If a +breakpoint is reached, +@ifclear BARETARGET +or a signal not related to stepping occurs before @var{count} steps, +@end ifclear +stepping stops right away. + +@kindex next +@kindex n +@item next @r{[}@var{count}@r{]} +Continue to the next source line in the current (innermost) stack frame. +This is similar to @code{step}, but function calls that appear within the line +of code are executed without stopping. Execution stops when control +reaches a different line of code at the original stack level that was +executing when you gave the @code{next} command. This command is abbreviated +@code{n}. + +An argument @var{count} is a repeat count, as for @code{step}. + + +@c FIX ME!! Do we delete this, or is there a way it fits in with +@c the following paragraph? --- Vctoria +@c +@c @code{next} within a function that lacks debugging information acts like +@c @code{step}, but any function calls appearing within the code of the +@c function are executed without stopping. + +The @code{next} command now only stops at the first instruction of a +source line. This prevents the multiple stops that used to occur in +swtch statements, for loops, etc. + +@kindex finish +@item finish +Continue running until just after function in the selected stack frame +returns. Print the returned value (if any). + +Contrast this with the @code{return} command (@pxref{Returning, +,Returning from a function}). + +@kindex until +@itemx u +@kindex u +@item until +Continue running until a source line past the current line, in the +current stack frame, is reached. This command is used to avoid single +stepping through a loop more than once. It is like the @code{next} +command, except that when @code{until} encounters a jump, it +automatically continues execution until the program counter is greater +than the address of the jump. + +This means that when you reach the end of a loop after single stepping +though it, @code{until} makes your program continue execution until it +exits the loop. In contrast, a @code{next} command at the end of a loop +simply steps back to the beginning of the loop, which forces you to step +through the next iteration. + +@code{until} always stops your program if it attempts to exit the current +stack frame. + +@code{until} may produce somewhat counterintuitive results if the order +of machine code does not match the order of the source lines. For +example, in the following excerpt from a debugging session, the @code{f} +(@code{frame}) command shows that execution is stopped at line +@code{206}; yet when we use @code{until}, we get to line @code{195}: + +@example +(@value{GDBP}) f +#0 main (argc=4, argv=0xf7fffae8) at m4.c:206 +206 expand_input(); +(@value{GDBP}) until +195 for ( ; argc > 0; NEXTARG) @{ +@end example + +This happened because, for execution efficiency, the compiler had +generated code for the loop closure test at the end, rather than the +start, of the loop---even though the test in a C @code{for}-loop is +written before the body of the loop. The @code{until} command appeared +to step back to the beginning of the loop when it advanced to this +expression; however, it has not really gone to an earlier +statement---not in terms of the actual machine code. + +@code{until} with no argument works by means of single +instruction stepping, and hence is slower than @code{until} with an +argument. + +@item until @var{location} +@itemx u @var{location} +Continue running your program until either the specified location is +reached, or the current stack frame returns. @var{location} is any of +the forms of argument acceptable to @code{break} (@pxref{Set Breaks, +,Setting breakpoints}). This form of the command uses breakpoints, +and hence is quicker than @code{until} without an argument. + +@kindex stepi +@kindex si +@item stepi +@itemx si +Execute one machine instruction, then stop and return to the debugger. + +It is often useful to do @samp{display/i $pc} when stepping by machine +instructions. This makes @value{GDBN} automatically display the next +instruction to be executed, each time your program stops. @xref{Auto +Display,, Automatic display}. + +An argument is a repeat count, as in @code{step}. + +@need 750 +@kindex nexti +@kindex ni +@item nexti +@itemx ni +Execute one machine instruction, but if it is a function call, +proceed until the function returns. + +An argument is a repeat count, as in @code{next}. +@end table + +@ifset POSIX +@node Signals +@section Signals +@cindex signals + +A signal is an asynchronous event that can happen in a program. The +operating system defines the possible kinds of signals, and gives each +kind a name and a number. For example, in Unix @code{SIGINT} is the +signal a program gets when you type an interrupt (often @kbd{C-c}); +@code{SIGSEGV} is the signal a program gets from referencing a place in +memory far away from all the areas in use; @code{SIGALRM} occurs when +the alarm clock timer goes off (which happens only if your program has +requested an alarm). + +@cindex fatal signals +Some signals, including @code{SIGALRM}, are a normal part of the +functioning of your program. Others, such as @code{SIGSEGV}, indicate +errors; these signals are @dfn{fatal} (kill your program immediately) if the +program has not specified in advance some other way to handle the signal. +@code{SIGINT} does not indicate an error in your program, but it is normally +fatal so it can carry out the purpose of the interrupt: to kill the program. + +@value{GDBN} has the ability to detect any occurrence of a signal in your +program. You can tell @value{GDBN} in advance what to do for each kind of +signal. + +@cindex handling signals +Normally, @value{GDBN} is set up to ignore non-erroneous signals like @code{SIGALRM} +(so as not to interfere with their role in the functioning of your program) +but to stop your program immediately whenever an error signal happens. +You can change these settings with the @code{handle} command. + +@table @code +@kindex info signals +@item info signals +Print a table of all the kinds of signals and how @value{GDBN} has been told to +handle each one. You can use this to see the signal numbers of all +the defined types of signals. + +@code{info handle} is the new alias for @code{info signals}. + +@kindex handle +@item handle @var{signal} @var{keywords}@dots{} +Change the way @value{GDBN} handles signal @var{signal}. @var{signal} can +be the number of a signal or its name (with or without the @samp{SIG} at the +beginning). The @var{keywords} say what change to make. +@end table + +@c @group +The keywords allowed by the @code{handle} command can be abbreviated. +Their full names are: + +@table @code +@item nostop +@value{GDBN} should not stop your program when this signal happens. It may +still print a message telling you that the signal has come in. + +@item stop +@value{GDBN} should stop your program when this signal happens. This implies +the @code{print} keyword as well. + +@item print +@value{GDBN} should print a message when this signal happens. + +@item noprint +@value{GDBN} should not mention the occurrence of the signal at all. This +implies the @code{nostop} keyword as well. + +@item pass +@value{GDBN} should allow your program to see this signal; your program +can handle the signal, or else it may terminate if the signal is fatal +and not handled. + +@item nopass +@value{GDBN} should not allow your program to see this signal. +@end table +@c @end group + +When a signal stops your program, the signal is not visible until you +continue. Your program sees the signal then, if @code{pass} is in +effect for the signal in question @emph{at that time}. In other words, +after @value{GDBN} reports a signal, you can use the @code{handle} +command with @code{pass} or @code{nopass} to control whether your +program sees that signal when you continue. + +You can also use the @code{signal} command to prevent your program from +seeing a signal, or cause it to see a signal it normally would not see, +or to give it any signal at any time. For example, if your program stopped +due to some sort of memory reference error, you might store correct +values into the erroneous variables and continue, hoping to see more +execution; but your program would probably terminate immediately as +a result of the fatal signal once it saw the signal. To prevent this, +you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your +program a signal}. +@end ifset + +@ifclear BARETARGET +@node Thread Stops +@section Stopping and starting multi-thread programs + +When your program has multiple threads (@pxref{Threads,, Debugging +programs with multiple threads}), you can choose whether to set +breakpoints on all threads, or on a particular thread. + +@table @code +@cindex breakpoints and threads +@cindex thread breakpoints +@kindex break @dots{} thread @var{threadno} +@item break @var{linespec} thread @var{threadno} +@itemx break @var{linespec} thread @var{threadno} if @dots{} +@var{linespec} specifies source lines; there are several ways of +writing them, but the effect is always to specify some source line. + +Use the qualifier @samp{thread @var{threadno}} with a breakpoint command +to specify that you only want @value{GDBN} to stop the program when a +particular thread reaches this breakpoint. @var{threadno} is one of the +numeric thread identifiers assigned by @value{GDBN}, shown in the first +column of the @samp{info threads} display. + +If you do not specify @samp{thread @var{threadno}} when you set a +breakpoint, the breakpoint applies to @emph{all} threads of your +program. + +You can use the @code{thread} qualifier on conditional breakpoints as +well; in this case, place @samp{thread @var{threadno}} before the +breakpoint condition, like this: + +@smallexample +(gdb) break frik.c:13 thread 28 if bartab > lim +@end smallexample + +@end table + +@cindex stopped threads +@cindex threads, stopped +Whenever your program stops under @value{GDBN} for any reason, +@emph{all} threads of execution stop, not just the current thread. This +allows you to examine the overall state of the program, including +switching between threads, without worrying that things may change +underfoot. + +@cindex continuing threads +@cindex threads, continuing +Conversely, whenever you restart the program, @emph{all} threads start +executing. @emph{This is true even when single-stepping} with commands +like @code{step} or @code{next}. + +In particular, @value{GDBN} cannot single-step all threads in lockstep. +Since thread scheduling is up to your debugging target's operating +system (not controlled by @value{GDBN}), other threads may +execute more than one statement while the current thread completes a +single step. Moreover, in general other threads stop in the middle of a +statement, rather than at a clean statement boundary, when the program +stops. + +You might even find your program stopped in another thread after +continuing or even single-stepping. This happens whenever some other +thread runs into a breakpoint, a signal, or an exception before the +first thread completes whatever you requested. +@end ifclear + +@node Stack +@chapter Examining the Stack + +When your program has stopped, the first thing you need to know is where it +stopped and how it got there. + +@cindex call stack +Each time your program performs a function call, information about the call +is generated. +That information includes the location of the call in your program, +the arguments of the call, +and the local variables of the function being called. +The information is saved in a block of data called a @dfn{stack frame}. +The stack frames are allocated in a region of memory called the @dfn{call +stack}. + +When your program stops, the @value{GDBN} commands for examining the +stack allow you to see all of this information. + +@cindex selected frame +One of the stack frames is @dfn{selected} by @value{GDBN} and many +@value{GDBN} commands refer implicitly to the selected frame. In +particular, whenever you ask @value{GDBN} for the value of a variable in +your program, the value is found in the selected frame. There are +special @value{GDBN} commands to select whichever frame you are +interested in. @xref{Selection, ,Selecting a frame}. + +When your program stops, @value{GDBN} automatically selects the +currently executing frame and describes it briefly, similar to the +@code{frame} command (@pxref{Frame Info, ,Information about a frame}). + +@menu +* Frames:: Stack frames +* Backtrace:: Backtraces +* Selection:: Selecting a frame +* Frame Info:: Information on a frame +@ifset MIPS +* MIPS Stack:: MIPS machines and the function stack +@end ifset +@end menu + +@node Frames +@section Stack frames + +@cindex frame +@cindex stack frame +The call stack is divided up into contiguous pieces called @dfn{stack +frames}, or @dfn{frames} for short; each frame is the data associated +with one call to one function. The frame contains the arguments given +to the function, the function's local variables, and the address at +which the function is executing. + +@cindex initial frame +@cindex outermost frame +@cindex innermost frame +When your program is started, the stack has only one frame, that of the +function @code{main}. This is called the @dfn{initial} frame or the +@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@cindex frame pointer +Inside your program, stack frames are identified by their addresses. A +stack frame consists of many bytes, each of which has its own address; each +kind of computer has a convention for choosing one byte whose +address serves as the address of the frame. Usually this address is kept +in a register called the @dfn{frame pointer register} while execution is +going on in that frame. + +@cindex frame number +@value{GDBN} assigns numbers to all existing stack frames, starting with +zero for the innermost frame, one for the frame that called it, +and so on upward. These numbers do not really exist in your program; +they are assigned by @value{GDBN} to give you a way of designating stack +frames in @value{GDBN} commands. + +@c below produces an acceptable overful hbox. --mew 13aug1993 +@cindex frameless execution +Some compilers provide a way to compile functions so that they operate +without stack frames. (For example, the @code{@value{GCC}} option +@samp{-fomit-frame-pointer} generates functions without a frame.) +This is occasionally done with heavily used library functions to save +the frame setup time. @value{GDBN} has limited facilities for dealing +with these function invocations. If the innermost function invocation +has no stack frame, @value{GDBN} nevertheless regards it as though +it had a separate frame, which is numbered zero as usual, allowing +correct tracing of the function call chain. However, @value{GDBN} has +no provision for frameless functions elsewhere in the stack. + +@table @code +@kindex frame +@item frame @var{args} +The @code{frame} command allows you to move from one stack frame to another, +and to print the stack frame you select. @var{args} may be either the +address of the frame of the stack frame number. Without an argument, +@code{frame} prints the current stack frame. + +@kindex select-frame +@item select-frame +The @code{select-frame} command allows you to move from one stack frame +to another without printing the frame. This is the silent version of +@code{frame}. +@end table + +@node Backtrace +@section Backtraces + +A backtrace is a summary of how your program got where it is. It shows one +line per frame, for many frames, starting with the currently executing +frame (frame zero), followed by its caller (frame one), and on up the +stack. + +@table @code +@kindex backtrace +@kindex bt +@item backtrace +@itemx bt +Print a backtrace of the entire stack: one line per frame for all +frames in the stack. + +You can stop the backtrace at any time by typing the system interrupt +character, normally @kbd{C-c}. + +@item backtrace @var{n} +@itemx bt @var{n} +Similar, but print only the innermost @var{n} frames. + +@item backtrace -@var{n} +@itemx bt -@var{n} +Similar, but print only the outermost @var{n} frames. +@end table + +@kindex where +@kindex info stack +@kindex info s +The names @code{where} and @code{info stack} (abbreviated @code{info s}) +are additional aliases for @code{backtrace}. + +Each line in the backtrace shows the frame number and the function name. +The program counter value is also shown---unless you use @code{set +print address off}. The backtrace also shows the source file name and +line number, as well as the arguments to the function. The program +counter value is omitted if it is at the beginning of the code for that +line number. + +Here is an example of a backtrace. It was made with the command +@samp{bt 3}, so it shows the innermost three frames. + +@smallexample +@group +#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) + at builtin.c:993 +#1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242 +#2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) + at macro.c:71 +(More stack frames follow...) +@end group +@end smallexample + +@noindent +The display for frame zero does not begin with a program counter +value, indicating that your program has stopped at the beginning of the +code for line @code{993} of @code{builtin.c}. + +@node Selection +@section Selecting a frame + +Most commands for examining the stack and other data in your program work on +whichever stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief description +of the stack frame just selected. + +@table @code +@kindex frame +@kindex f +@item frame @var{n} +@itemx f @var{n} +Select frame number @var{n}. Recall that frame zero is the innermost +(currently executing) frame, frame one is the frame that called the +innermost one, and so on. The highest-numbered frame is the one for +@code{main}. + +@item frame @var{addr} +@itemx f @var{addr} +Select the frame at address @var{addr}. This is useful mainly if the +chaining of stack frames has been damaged by a bug, making it +impossible for @value{GDBN} to assign numbers properly to all frames. In +addition, this can be useful when your program has multiple stacks and +switches between them. + +@ifclear H8EXCLUSIVE +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 +pointer and a program counter. + +On the 29k architecture, it needs three addresses: a register stack +pointer, a program counter, and a memory stack pointer. +@c note to future updaters: this is conditioned on a flag +@c SETUP_ARBITRARY_FRAME in the tm-*.h files. The above is up to date +@c as of 27 Jan 1994. +@end ifclear + +@kindex up +@item up @var{n} +Move @var{n} frames up the stack. For positive numbers @var{n}, this +advances toward the outermost frame, to higher frame numbers, to frames +that have existed longer. @var{n} defaults to one. + +@kindex down +@kindex do +@item down @var{n} +Move @var{n} frames down the stack. For positive numbers @var{n}, this +advances toward the innermost frame, to lower frame numbers, to frames +that were created more recently. @var{n} defaults to one. You may +abbreviate @code{down} as @code{do}. +@end table + +All of these commands end by printing two lines of output describing the +frame. The first line shows the frame number, the function name, the +arguments, and the source file and line number of execution in that +frame. The second line shows the text of that source line. + +@need 1000 +For example: + +@smallexample +@group +(@value{GDBP}) up +#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc) + at env.c:10 +10 read_input_file (argv[i]); +@end group +@end smallexample + +After such a printout, the @code{list} command with no arguments +prints ten lines centered on the point of execution in the frame. +@xref{List, ,Printing source lines}. + +@table @code +@kindex down-silently +@kindex up-silently +@item up-silently @var{n} +@itemx down-silently @var{n} +These two commands are variants of @code{up} and @code{down}, +respectively; they differ in that they do their work silently, without +causing display of the new frame. They are intended primarily for use +in @value{GDBN} command scripts, where the output might be unnecessary and +distracting. +@end table + +@node Frame Info +@section Information about a frame + +There are several other commands to print information about the selected +stack frame. + +@table @code +@item frame +@itemx f +When used without any argument, this command does not change which +frame is selected, but prints a brief description of the currently +selected stack frame. It can be abbreviated @code{f}. With an +argument, this command is used to select a stack frame. +@xref{Selection, ,Selecting a frame}. + +@kindex info frame +@kindex info f +@item info frame +@itemx info f +This command prints a verbose description of the selected stack frame, +including: + +@itemize @bullet +@item +the address of the frame +@item +the address of the next frame down (called by this frame) +@item +the address of the next frame up (caller of this frame) +@item +the language in which the source code corresponding to this frame is written +@item +the address of the frame's arguments +@item +the program counter saved in it (the address of execution in the caller frame) +@item +which registers were saved in the frame +@end itemize + +@noindent The verbose description is useful when +something has gone wrong that has made the stack format fail to fit +the usual conventions. + +@item info frame @var{addr} +@itemx info f @var{addr} +Print a verbose description of the frame at address @var{addr}, without +selecting that frame. The selected frame remains unchanged by this +command. This requires the same kind of address (more than one for some +architectures) that you specify in the @code{frame} command. +@xref{Selection, ,Selecting a frame}. + +@kindex info args +@item info args +Print the arguments of the selected frame, each on a separate line. + +@item info locals +@kindex info locals +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. + +@ifclear CONLY +@kindex info catch +@cindex catch exceptions +@cindex exception handlers +@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{Exception Handling, ,Breakpoints and exceptions}. +@end ifclear +@end table + +@ifset MIPS +@node MIPS Stack +@section MIPS machines and the function stack + +@cindex stack on MIPS +@cindex MIPS stack +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 +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} (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 default) +means there is no limit. However, except for @var{0}, the larger the +limit the more bytes @code{heuristic-fence-post} must search and +therefore the longer it takes to run. + +@item show heuristic-fence-post +Display the current limit. +@end table + +@noindent +These commands are available @emph{only} when @value{GDBN} is configured +for debugging programs on MIPS processors. +@end ifset + +@node Source +@chapter Examining Source Files + +@value{GDBN} can print parts of your program's source, since the debugging +information recorded in the program tells @value{GDBN} what source files were +used to build it. When your program stops, @value{GDBN} spontaneously prints +the line where it stopped. Likewise, when you select a stack frame +(@pxref{Selection, ,Selecting a frame}), @value{GDBN} prints the line where +execution in that frame has stopped. You can print other portions of +source files by explicit command. + +@ifclear DOSHOST +If you use @value{GDBN} through its @sc{gnu} Emacs interface, you may prefer +to use +Emacs facilities to view source; @pxref{Emacs, ,Using @value{GDBN} under @sc{gnu} Emacs}. +@end ifclear + +@menu +* List:: Printing source lines +@ifclear DOSHOST +* Search:: Searching source files +@end ifclear + +* Source Path:: Specifying source directories +* Machine Code:: Source and machine code +@end menu + +@node List +@section Printing source lines + +@kindex list +@kindex l +To print lines from a source file, use the @code{list} command +(abbreviated @code{l}). By default, ten lines are printed. +There are several ways to specify what part of the file you want to print. + +Here are the forms of the @code{list} command most commonly used: + +@table @code +@item list @var{linenum} +Print lines centered around line number @var{linenum} in the +current source file. + +@item list @var{function} +Print lines centered around the beginning of function +@var{function}. + +@item list +Print more lines. If the last lines printed were printed with a +@code{list} command, this prints lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@pxref{Stack, ,Examining the +Stack}), this prints lines centered around that line. + +@item list - +Print lines just before the lines last printed. +@end table + +By default, @value{GDBN} prints ten source lines with any of these forms of +the @code{list} command. You can change this using @code{set listsize}: + +@table @code +@kindex 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). + +@kindex show listsize +@item show listsize +Display the number of lines that @code{list} prints. +@end table + +Repeating a @code{list} command with @key{RET} discards the argument, +so it is equivalent to typing just @code{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @samp{-}; that argument is preserved in repetition so that +each repetition moves up in the source file. + +@cindex linespec +In general, the @code{list} command expects you to supply zero, one or two +@dfn{linespecs}. Linespecs specify source lines; there are several ways +of writing them but the effect is always to specify some source line. +Here is a complete description of the possible arguments for @code{list}: + +@table @code +@item list @var{linespec} +Print lines centered around the line specified by @var{linespec}. + +@item list @var{first},@var{last} +Print lines from @var{first} to @var{last}. Both arguments are +linespecs. + +@item list ,@var{last} +Print lines ending with @var{last}. + +@item list @var{first}, +Print lines starting with @var{first}. + +@item list + +Print lines just after the lines last printed. + +@item list - +Print lines just before the lines last printed. + +@item list +As described in the preceding table. +@end table + +Here are the ways of specifying a single source line---all the +kinds of linespec. + +@table @code +@item @var{number} +Specifies line @var{number} of the current source file. +When a @code{list} command has two linespecs, this refers to +the same source file as the first linespec. + +@item +@var{offset} +Specifies the line @var{offset} lines after the last line printed. +When used as the second linespec in a @code{list} command that has +two, this specifies the line @var{offset} lines down from the +first linespec. + +@item -@var{offset} +Specifies the line @var{offset} lines before the last line printed. + +@item @var{filename}:@var{number} +Specifies line @var{number} in the source file @var{filename}. + +@item @var{function} +Specifies the line that begins the body of the function @var{function}. +For example: in C, this is the line with the open brace. + +@item @var{filename}:@var{function} +Specifies the line of the open-brace that begins the body of the +function @var{function} in the file @var{filename}. You only need the +file name with a function name to avoid ambiguity when there are +identically named functions in different source files. + +@item *@var{address} +Specifies the line containing the program address @var{address}. +@var{address} may be any expression. +@end table + +@ifclear DOSHOST +@node Search +@section Searching source files +@cindex searching +@kindex reverse-search + +There are two commands for searching through the current source file for a +regular expression. + +@table @code +@kindex search +@kindex forward-search +@item forward-search @var{regexp} +@itemx search @var{regexp} +The command @samp{forward-search @var{regexp}} checks each line, +starting with the one following the last line listed, for a match for +@var{regexp}. It lists the line that is found. You can use the +synonym @samp{search @var{regexp}} or abbreviate the command name as +@code{fo}. + +@item reverse-search @var{regexp} +The command @samp{reverse-search @var{regexp}} checks each line, starting +with the one before the last line listed and going backward, for a match +for @var{regexp}. It lists the line that is found. You can abbreviate +this command as @code{rev}. +@end table +@end ifclear + +@node Source Path +@section Specifying source directories + +@cindex source path +@cindex directories for source files +Executable programs sometimes do not record the directories of the source +files from which they were compiled, just the names. Even when they do, +the directories could be moved between the compilation and your debugging +session. @value{GDBN} has a list of directories to search for source files; +this is called the @dfn{source path}. Each time @value{GDBN} wants a source file, +it tries all the directories in the list, in the order they are present +in the list, until it finds a file with the desired name. Note that +the executable search path is @emph{not} used for this purpose. Neither is +the current working directory, unless it happens to be in the source +path. + +If @value{GDBN} cannot find a source file in the source path, and the +object program records a directory, @value{GDBN} tries that directory +too. If the source path is empty, and there is no record of the +compilation directory, @value{GDBN} looks in the current directory as a +last resort. + +Whenever you reset or rearrange the source path, @value{GDBN} clears out +any information it has cached about where source files are found and where +each line is in the file. + +@kindex directory +@kindex dir +When you start @value{GDBN}, its source path is empty. +To add other directories, use the @code{directory} command. + +@table @code +@item directory @var{dirname} @dots{} +@item dir @var{dirname} @dots{} +Add directory @var{dirname} to the front of the source path. Several +directory names may be given to this command, separated by @samp{:} or +whitespace. You may specify a directory that is already in the source +path; this moves it forward, so @value{GDBN} searches it sooner. + +@kindex cdir +@kindex cwd +@kindex $cdir +@kindex $cwd +@cindex compilation directory +@cindex current directory +@cindex working directory +@cindex directory, current +@cindex directory, compilation +You can use the string @samp{$cdir} to refer to the compilation +directory (if one is recorded), and @samp{$cwd} to refer to the current +working directory. @samp{$cwd} is not the same as @samp{.}---the former +tracks the current working directory as it changes during your @value{GDBN} +session, while the latter is immediately expanded to the current +directory at the time you add an entry to the source path. + +@item directory +Reset the source path to empty again. This requires confirmation. + +@c RET-repeat for @code{directory} is explicitly disabled, but since +@c repeating it would be a no-op we do not say that. (thanks to RMS) + +@item show directories +@kindex show directories +Print the source path: show which directories it contains. +@end table + +If your source path is cluttered with directories that are no longer of +interest, @value{GDBN} may sometimes cause confusion by finding the wrong +versions of source. You can correct the situation as follows: + +@enumerate +@item +Use @code{directory} with no argument to reset the source path to empty. + +@item +Use @code{directory} with suitable arguments to reinstall the +directories you want in the source path. You can add all the +directories in one command. +@end enumerate + +@node Machine Code +@section Source and machine code + +You can use the command @code{info line} to map source lines to program +addresses (and vice versa), and the command @code{disassemble} to display +a range of addresses as machine instructions. When run under @sc{gnu} Emacs +mode, the @code{info line} command now causes the arrow to point to the +line specified. Also, @code{info line} prints addresses in symbolic form as +well as hex. + +@table @code +@kindex info line +@item info line @var{linespec} +Print the starting and ending addresses of the compiled code for +source line @var{linespec}. You can specify source lines in any of +the ways understood by the @code{list} command (@pxref{List, ,Printing +source lines}). +@end table + +For example, we can use @code{info line} to discover the location of +the object code for the first line of function +@code{m4_changequote}: + +@smallexample +(@value{GDBP}) info line m4_changecom +Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350. +@end smallexample + +@noindent +We can also inquire (using @code{*@var{addr}} as the form for +@var{linespec}) what source line covers a particular address: +@smallexample +(@value{GDBP}) info line *0x63ff +Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404. +@end smallexample + +@cindex @code{$_} and @code{info line} +After @code{info line}, the default address for the @code{x} command +is changed to the starting address of the line, so that @samp{x/i} is +sufficient to begin examining the machine code (@pxref{Memory, +,Examining memory}). Also, this address is saved as the value of the +convenience variable @code{$_} (@pxref{Convenience Vars, ,Convenience +variables}). + +@table @code +@kindex disassemble +@cindex assembly instructions +@cindex instructions, assembly +@cindex machine instructions +@cindex listing machine instructions +@item disassemble +This specialized command dumps a range of memory as machine +instructions. The default memory range is the function surrounding the +program counter of the selected frame. A single argument to this +command is a program counter value; @value{GDBN} dumps the function +surrounding this value. Two arguments specify a range of addresses +(first inclusive, second exclusive) to dump. +@end table + +@ifclear H8EXCLUSIVE +We can use @code{disassemble} to inspect the object code +range shown in the last @code{info line} example (the example +shows SPARC machine instructions): + + +@smallexample +(@value{GDBP}) disas 0x63e4 0x6404 +Dump of assembler code from 0x63e4 to 0x6404: +0x63e4 : ble 0x63f8 +0x63e8 : sethi %hi(0x4c00), %o0 +0x63ec : ld [%i1+4], %o0 +0x63f0 : b 0x63fc +0x63f4 : ld [%o0+4], %o0 +0x63f8 : or %o0, 0x1a4, %o0 +0x63fc : call 0x9288 +0x6400 : nop +End of assembler dump. +@end smallexample +@end ifclear + +@ifset H8EXCLUSIVE +For example, here is the beginning of the output for the +disassembly of a function @code{fact}: + + +@smallexample +(@value{GDBP}) disas fact +Dump of assembler code for function fact: +to 0x808c: +0x802c : 6d f2 mov.w r2,@@-r7 +0x802e : 6d f3 mov.w r3,@@-r7 +0x8030 : 6d f6 mov.w r6,@@-r7 +0x8032 : 0d 76 mov.w r7,r6 +0x8034 : 6f 70 00 08 mov.w @@(0x8,r7),r0 +0x8038 19 11 sub.w r1,r1 + . + . + . +@end smallexample +@end ifset + +@node Data +@chapter Examining Data + +@cindex printing data +@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}. +@ifclear CONLY +It evaluates and prints the value of an expression of the language your +program is written in (@pxref{Languages, ,Using @value{GDBN} with Different +Languages}). +@end ifclear + +@table @code +@item print @var{exp} +@itemx print /@var{f} @var{exp} +@var{exp} is an expression (in the source language). By default the +value of @var{exp} is printed in a format appropriate to its data type; +you can choose a different format by specifying @samp{/@var{f}}, where +@var{f} is a letter specifying the format; @pxref{Output Formats,,Output +formats}. + +@item print +@itemx print /@var{f} +If you omit @var{exp}, @value{GDBN} displays the last value again (from the +@dfn{value history}; @pxref{Value History, ,Value history}). This allows you to +conveniently inspect the same value in an alternative format. +@end table + +A more low-level way of examining data is with the @code{x} command. +It examines data in memory at a specified address and prints it in a +specified format. @xref{Memory, ,Examining memory}. + +If you are interested in information about types, or about how the fields +of a struct +@ifclear CONLY +or class +@end ifclear +are declared, use the @code{ptype @var{exp}} +command rather than @code{print}. @xref{Symbols, ,Examining the Symbol Table}. + +@menu +* Expressions:: Expressions +* Variables:: Program variables +* Arrays:: Artificial arrays +* Output Formats:: Output formats +* Memory:: Examining memory +* Auto Display:: Automatic display +* Print Settings:: Print settings +* Value History:: Value history +* Convenience Vars:: Convenience variables +* Registers:: Registers +@ifclear HAVE-FLOAT +* Floating Point Hardware:: Floating point hardware +@end ifclear +@end menu + +@node Expressions +@section Expressions + +@cindex expressions +@code{print} and many other @value{GDBN} commands accept an expression and +compute its value. Any kind of constant, variable or operator defined +by the programming language you are using is valid in an expression in +@value{GDBN}. This includes conditional expressions, function calls, casts +and string constants. It unfortunately does not include symbols defined +by preprocessor @code{#define} commands. + +@value{GDBN} now supports array constants in expressions input by +the user. The syntax is @var{@{element, element@dots{}@}}. For example, +you can now use the command @code{print @{1, 2, 3@}} to build up an array in +memory that is malloc'd in the target program. + +@ifclear CONLY +Because C is so widespread, most of the expressions shown in examples in +this manual are in C. @xref{Languages, , Using @value{GDBN} with Different +Languages}, for information on how to use expressions in other +languages. + +In this section, we discuss operators that you can use in @value{GDBN} +expressions regardless of your programming language. + +Casts are supported in all languages, not just in C, because it is so +useful to cast a number into a pointer in order to examine a structure +at that address in memory. +@c FIXME: casts supported---Mod2 true? +@end ifclear + +@value{GDBN} supports these operators, in addition to those common +to programming languages: + +@table @code +@item @@ +@samp{@@} is a binary operator for treating parts of memory as arrays. +@xref{Arrays, ,Artificial arrays}, for more information. + +@item :: +@samp{::} allows you to specify a variable in terms of the file or +function where it is defined. @xref{Variables, ,Program variables}. + +@cindex @{@var{type}@} +@cindex type casting memory +@cindex memory, viewing as typed object +@cindex casts, to view memory +@item @{@var{type}@} @var{addr} +Refers to an object of type @var{type} stored at address @var{addr} in +memory. @var{addr} may be any expression whose value is an integer or +pointer (but parentheses are required around binary operators, just as in +a cast). This construct is allowed regardless of what kind of data is +normally supposed to reside at @var{addr}. +@end table + +@node Variables +@section Program variables + +The most common kind of expression to use is the name of a variable +in your program. + +Variables in expressions are understood in the selected stack frame +(@pxref{Selection, ,Selecting a frame}); they must be either: + +@itemize @bullet +@item +global (or static) +@end itemize + +@noindent or + +@itemize @bullet +@item +visible according to the scope rules of the +programming language from the point of execution in that frame +@end itemize + +@noindent This means that in the function + +@example +foo (a) + int a; +@{ + bar (a); + @{ + int b = test (); + bar (b); + @} +@} +@end example + +@noindent +you can examine and use the variable @code{a} whenever your program is +executing within the function @code{foo}, but you can only use or +examine the variable @code{b} while your program is executing inside +the block where @code{b} is declared. + +@cindex variable name conflict +There is an exception: you can refer to a variable or function whose +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, +using the colon-colon notation: + +@cindex colon-colon +@iftex +@c info cannot cope with a :: index entry, but why deprive hard copy readers? +@kindex :: +@end iftex +@example +@var{file}::@var{variable} +@var{function}::@var{variable} +@end example + +@noindent +Here @var{file} or @var{function} is the name of the context for the +static @var{variable}. In the case of file names, you can use quotes to +make sure @value{GDBN} parses the file name as a single word---for example, +to print a global value of @code{x} defined in @file{f2.c}: + +@example +(@value{GDBP}) p 'f2.c'::x +@end example + +@ifclear CONLY +@cindex C++ scope resolution +This use of @samp{::} is very rarely in conflict with the very similar +use of the same notation in C++. @value{GDBN} also supports use of the C++ +scope resolution operator in @value{GDBN} expressions. +@c FIXME: Um, so what happens in one of those rare cases where it's in +@c conflict?? --mew +@end ifclear + +@cindex wrong values +@cindex variable values, wrong +@quotation +@emph{Warning:} Occasionally, a local variable may appear to have the +wrong value at certain points in a function---just after entry to a new +scope, and just before exit. +@end quotation +You may see this problem when you are stepping by machine instructions. +This is because, on most machines, it takes more than one instruction to +set up a stack frame (including local variable definitions); if you are +stepping by machine instructions, variables may appear to have the wrong +values until the stack frame is completely built. On exit, it usually +also takes more than one machine instruction to destroy a stack frame; +after you begin stepping through that group of instructions, local +variable definitions may be gone. + +@node Arrays +@section Artificial arrays + +@cindex artificial array +@kindex @@ +It is often useful to print out several successive objects of the +same type in memory; a section of an array, or an array of +dynamically determined size for which only a pointer exists in the +program. + +You can do this by referring to a contiguous span of memory as an +@dfn{artificial array}, using the binary operator @samp{@@}. The left +operand of @samp{@@} should be the first element of the desired array +and be an individual object. The right operand should be the desired length +of the array. The result is an array value whose elements are all of +the type of the left argument. The first element is actually the left +argument; the second element comes from bytes of memory immediately +following those that hold the first element, and so on. Here is an +example. If a program says + +@example +int *array = (int *) malloc (len * sizeof (int)); +@end example + +@noindent +you can print the contents of @code{array} with + +@example +p *array@@len +@end example + +The left operand of @samp{@@} must reside in memory. Array values made +with @samp{@@} in this way behave just like other arrays in terms of +subscripting, and are coerced to pointers when used in expressions. +Artificial arrays most often appear in expressions via the value history +(@pxref{Value History, ,Value history}), after printing one out. + +Another way to create an artificial array is to use a cast. +This re-interprets a value as if it were an array. +The value need not be in memory: +@example +(@value{GDBP}) p/x (short[2])0x12345678 +$1 = @{0x1234, 0x5678@} +@end example + +As a convenience, if you leave the array length out (as in +@samp{(@var{type})[])@var{value}}) gdb calculates the size to fill +the value (as @samp{sizeof(@var{value})/sizeof(@var{type})}: +@example +(@value{GDBP}) p/x (short[])0x12345678 +$2 = @{0x1234, 0x5678@} +@end example + +Sometimes the artificial array mechanism is not quite enough; in +moderately complex data structures, the elements of interest may not +actually be adjacent---for example, if you are interested in the values +of pointers in an array. One useful work-around in this situation is +to use a convenience variable (@pxref{Convenience Vars, ,Convenience +variables}) as a counter in an expression that prints the first +interesting value, and then repeat that expression via @key{RET}. For +instance, suppose you have an array @code{dtab} of pointers to +structures, and you are interested in the values of a field @code{fv} +in each structure. Here is an example of what you might type: + +@example +set $i = 0 +p dtab[$i++]->fv +@key{RET} +@key{RET} +@dots{} +@end example + +@node Output Formats +@section Output formats + +@cindex formatted output +@cindex output formats +By default, @value{GDBN} prints a value according to its data type. Sometimes +this is not what you want. For example, you might want to print a number +in hex, or a pointer in decimal. Or you might want to view data in memory +at a certain address as a character string or as an instruction. To do +these things, specify an @dfn{output format} when you print a value. + +The simplest use of output formats is to say how to print a value +already computed. This is done by starting the arguments of the +@code{print} command with a slash and a format letter. The format +letters supported are: + +@table @code +@item x +Regard the bits of the value as an integer, and print the integer in +hexadecimal. + +@item d +Print as integer in signed decimal. + +@item u +Print as integer in unsigned decimal. + +@item o +Print as integer in octal. + +@item t +Print as integer in binary. The letter @samp{t} stands for ``two''. +@footnote{@samp{b} cannot be used because these format letters are also +used with the @code{x} command, where @samp{b} stands for ``byte''; +@pxref{Memory,,Examining memory}.} + +@item a +@cindex unknown address, locating +Print as an address, both absolute in hexadecimal and as an offset from +the nearest preceding symbol. You can use this format used to discover +where (in what function) an unknown address is located: + +@example +(@value{GDBP}) p/a 0x54320 +$3 = 0x54320 <_initialize_vx+396> +@end example + +@item c +Regard as an integer and print it as a character constant. + +@item f +Regard the bits of the value as a floating point number and print +using typical floating point syntax. +@end table + +For example, to print the program counter in hex (@pxref{Registers}), type + +@example +p/x $pc +@end example + +@noindent +Note that no space is required before the slash; this is because command +names in @value{GDBN} cannot contain a slash. + +To reprint the last value in the value history with a different format, +you can use the @code{print} command with just a format and no +expression. For example, @samp{p/x} reprints the last value in hex. + +@node Memory +@section Examining memory + +You can use the command @code{x} (for ``examine'') to examine memory in +any of several formats, independently of your program's data types. + +@cindex examining memory +@table @code +@kindex x +@item x/@var{nfu} @var{addr} +@itemx x @var{addr} +@itemx x +Use the @code{x} command to examine memory. +@end table + +@var{n}, @var{f}, and @var{u} are all optional parameters that specify how +much memory to display and how to format it; @var{addr} is an +expression giving the address where you want to start displaying memory. +If you use defaults for @var{nfu}, you need not type the slash @samp{/}. +Several commands set convenient defaults for @var{addr}. + +@table @r +@item @var{n}, the repeat count +The repeat count is a decimal integer; the default is 1. It specifies +how much memory (counting by units @var{u}) to display. +@c This really is **decimal**; unaffected by 'set radix' as of GDB +@c 4.1.2. + +@item @var{f}, the display format +The display format is one of the formats used by @code{print}, +@samp{s} (null-terminated string), or @samp{i} (machine instruction). +The default is @samp{x} (hexadecimal) initially. +The default changes each time you use either @code{x} or @code{print}. + +@item @var{u}, the unit size +The unit size is any of + +@table @code +@item b +Bytes. +@item h +Halfwords (two bytes). +@item w +Words (four bytes). This is the initial default. +@item g +Giant words (eight bytes). +@end table + +Each time you specify a unit size with @code{x}, that size becomes the +default unit the next time you use @code{x}. (For the @samp{s} and +@samp{i} formats, the unit size is ignored and is normally not written.) + +@item @var{addr}, starting display address +@var{addr} is the address where you want @value{GDBN} to begin displaying +memory. The expression need not have a pointer value (though it may); +it is always interpreted as an integer address of a byte of memory. +@xref{Expressions, ,Expressions}, for more information on expressions. The default for +@var{addr} is usually just after the last address examined---but several +other commands also set the default address: @code{info breakpoints} (to +the address of the last breakpoint listed), @code{info line} (to the +starting address of a line), and @code{print} (if you use it to display +a value from memory). +@end table + +For example, @samp{x/3uh 0x54320} is a request to display three halfwords +(@code{h}) of memory, formatted as unsigned decimal integers (@samp{u}), +starting at address @code{0x54320}. @samp{x/4xw $sp} prints the four +words (@samp{w}) of memory above the stack pointer (here, @samp{$sp}; +@pxref{Registers}) in hexadecimal (@samp{x}). + +Since the letters indicating unit sizes are all distinct from the +letters specifying output formats, you do not have to remember whether +unit size or format comes first; either order works. The output +specifications @samp{4xw} and @samp{4wx} mean exactly the same thing. +(However, the count @var{n} must come first; @samp{wx4} does not work.) + +Even though the unit size @var{u} is ignored for the formats @samp{s} +and @samp{i}, you might still want to use a count @var{n}; for example, +@samp{3i} specifies that you want to see three machine instructions, +including any operands. The command @code{disassemble} gives an +alternative way of inspecting machine instructions; @pxref{Machine +Code,,Source and machine code}. + +All the defaults for the arguments to @code{x} are designed to make it +easy to continue scanning memory with minimal specifications each time +you use @code{x}. For example, after you have inspected three machine +instructions with @samp{x/3i @var{addr}}, you can inspect the next seven +with just @samp{x/7}. If you use @key{RET} to repeat the @code{x} command, +the repeat count @var{n} is used again; the other arguments default as +for successive uses of @code{x}. + +@cindex @code{$_}, @code{$__}, and value history +The addresses and contents printed by the @code{x} command are not saved +in the value history because there is often too much of them and they +would get in the way. Instead, @value{GDBN} makes these values available for +subsequent use in expressions as values of the convenience variables +@code{$_} and @code{$__}. After an @code{x} command, the last address +examined is available for use in expressions in the convenience variable +@code{$_}. The contents of that address, as examined, are available in +the convenience variable @code{$__}. + +If the @code{x} command has a repeat count, the address and contents saved +are from the last memory unit printed; this is not the same as the last +address printed if several units were printed on the last line of output. + +@node Auto Display +@section Automatic display +@cindex automatic display +@cindex display of expressions + +If you find that you want to print the value of an expression frequently +(to see how it changes), you might want to add it to the @dfn{automatic +display list} so that @value{GDBN} prints its value each time your program stops. +Each expression added to the list is given a number to identify it; +to remove an expression from the list, you specify that number. +The automatic display looks like this: + +@example +2: foo = 38 +3: bar[5] = (struct hack *) 0x3804 +@end example + +@noindent +This display shows item numbers, expressions and their current values. As with +displays you request manually using @code{x} or @code{print}, you can +specify the output format you prefer; in fact, @code{display} decides +whether to use @code{print} or @code{x} depending on how elaborate your +format specification is---it uses @code{x} if you specify a unit size, +or one of the two formats (@samp{i} and @samp{s}) that are only +supported by @code{x}; otherwise it uses @code{print}. + +@table @code +@kindex display +@item display @var{exp} +Add the expression @var{exp} to the list of expressions to display +each time your program stops. @xref{Expressions, ,Expressions}. + +@code{display} does not repeat if you press @key{RET} again after using it. + +@item display/@var{fmt} @var{exp} +For @var{fmt} specifying only a display format and not a size or +count, add the expression @var{exp} to the auto-display list but +arrange to display it each time in the specified format @var{fmt}. +@xref{Output Formats,,Output formats}. + +@item display/@var{fmt} @var{addr} +For @var{fmt} @samp{i} or @samp{s}, or including a unit-size or a +number of units, add the expression @var{addr} as a memory address to +be examined each time your program stops. Examining means in effect +doing @samp{x/@var{fmt} @var{addr}}. @xref{Memory, ,Examining memory}. +@end table + +For example, @samp{display/i $pc} can be helpful, to see the machine +instruction about to be executed each time execution stops (@samp{$pc} +is a common name for the program counter; @pxref{Registers}). + +@table @code +@kindex delete display +@kindex undisplay +@item undisplay @var{dnums}@dots{} +@itemx delete display @var{dnums}@dots{} +Remove item numbers @var{dnums} from the list of expressions to display. + +@code{undisplay} does not repeat if you press @key{RET} after using it. +(Otherwise you would just get the error @samp{No display number @dots{}}.) + +@kindex disable display +@item disable display @var{dnums}@dots{} +Disable the display of item numbers @var{dnums}. A disabled display +item is not printed automatically, but is not forgotten. It may be +enabled again later. + +@kindex enable display +@item enable display @var{dnums}@dots{} +Enable display of item numbers @var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@item display +Display the current values of the expressions on the list, just as is +done when your program stops. + +@kindex info display +@item info display +Print the list of expressions previously set up to display +automatically, each one with its item number, but without showing the +values. This includes disabled expressions, which are marked as such. +It also includes expressions which would not be displayed right now +because they refer to automatic variables not currently available. +@end table + +If a display expression refers to local variables, then it does not make +sense outside the lexical context for which it was set up. Such an +expression is disabled when execution enters a context where one of its +variables is not defined. For example, if you give the command +@code{display last_char} while inside a function with an argument +@code{last_char}, @value{GDBN} displays this argument while your program +continues to stop inside that function. When it stops elsewhere---where +there is no variable @code{last_char}---the display is disabled +automatically. The next time your program stops where @code{last_char} +is meaningful, you can enable the display expression once again. + +@node Print Settings +@section Print settings + +@cindex format options +@cindex print settings +@value{GDBN} provides the following ways to control how arrays, structures, +and symbols are printed. + +@noindent +These settings are useful for debugging programs in any language: + +@table @code +@kindex set print address +@item set print address +@itemx set print address on +@value{GDBN} prints memory addresses showing the location of stack +traces, structure values, pointer values, breakpoints, and so forth, +even when it also displays the contents of those addresses. The default +is @code{on}. For example, this is what a stack frame display looks like with +@code{set print address on}: + +@smallexample +@group +(@value{GDBP}) f +#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>") + at input.c:530 +530 if (lquote != def_lquote) +@end group +@end smallexample + +@item set print address off +Do not print addresses when displaying their contents. For example, +this is the same stack frame displayed with @code{set print address off}: + +@smallexample +@group +(@value{GDBP}) set print addr off +(@value{GDBP}) f +#0 set_quotes (lq="<<", rq=">>") at input.c:530 +530 if (lquote != def_lquote) +@end group +@end smallexample + +You can use @samp{set print address off} to eliminate all machine +dependent displays from the @value{GDBN} interface. For example, with +@code{print address off}, you should get the same text for backtraces on +all machines---whether or not they involve pointer arguments. + +@kindex show print address +@item show print address +Show whether or not addresses are to be printed. +@end table + +When @value{GDBN} prints a symbolic address, it normally prints the +closest earlier symbol plus an offset. If that symbol does not uniquely +identify the address (for example, it is a name whose scope is a single +source file), you may need to clarify. One way to do this is with +@code{info line}, for example @samp{info line *0x4537}. Alternately, +you can set @value{GDBN} to print the source file and line number when +it prints a symbolic address: + +@table @code +@kindex set print symbol-filename +@item set print symbol-filename on +Tell @value{GDBN} to print the source file name and line number of a +symbol in the symbolic form of an address. + +@item set print symbol-filename off +Do not print source file name and line number of a symbol. This is the +default. + +@kindex show print symbol-filename +@item show print symbol-filename +Show whether or not @value{GDBN} will print the source file name and +line number of a symbol in the symbolic form of an address. +@end table + +Another situation where it is helpful to show symbol filenames and line +numbers is when disassembling code; @value{GDBN} shows you the line +number and source file that corresponds to each instruction. + +Also, you may wish to see the symbolic form only if the address being +printed is reasonably close to the closest earlier symbol: + +@table @code +@kindex set print max-symbolic-offset +@item set print max-symbolic-offset @var{max-offset} +Tell @value{GDBN} to only display the symbolic form of an address if the +offset between the closest earlier symbol and the address is less than +@var{max-offset}. The default is 0, which tells @value{GDBN} +to always print the symbolic form of an address if any symbol precedes it. + +@kindex show print max-symbolic-offset +@item show print max-symbolic-offset +Ask how large the maximum offset is that @value{GDBN} prints in a +symbolic address. +@end table + +@cindex wild pointer, interpreting +@cindex pointer, finding referent +If you have a pointer and you are not sure where it points, try +@samp{set print symbol-filename on}. Then you can determine the name +and source file location of the variable where it points, using +@samp{p/a @var{pointer}}. This interprets the address in symbolic form. +For example, here @value{GDBN} shows that a variable @code{ptt} points +at another variable @code{t}, defined in @file{hi2.c}: + +@example +(@value{GDBP}) set print symbol-filename on +(@value{GDBP}) p/a ptt +$4 = 0xe008 +@end example + +@quotation +@emph{Warning:} For pointers that point to a local variable, @samp{p/a} +does not show the symbol name and filename of the referent, even with +the appropriate @code{set print} options turned on. +@end quotation + +Other settings control how different kinds of objects are printed: + +@table @code +@kindex set print array +@item set print array +@itemx set print array on +Pretty print arrays. This format is more convenient to read, +but uses more space. The default is off. + +@item set print array off +Return to compressed format for arrays. + +@kindex show print array +@item show print array +Show whether compressed or pretty format is selected for displaying +arrays. + +@kindex set print elements +@item set print elements @var{number-of-elements} +Set a limit on how many elements of an array @value{GDBN} will print. +If @value{GDBN} is printing a large array, it stops printing after it has +printed the number of elements set by the @code{set print elements} command. +This limit also applies to the display of strings. +Setting @var{number-of-elements} to zero means that the printing is unlimited. + +@kindex show print elements +@item show print elements +Display the number of elements of a large array that @value{GDBN} will print. +If the number is 0, then the printing is unlimited. + +@kindex set print null-stop +@item set print null-stop +Cause @value{GDBN} to stop printing the characters of an array when the first +@sc{NULL} is encountered. This is useful when large arrays actually +contain only short strings. + +@kindex set print pretty +@item set print pretty on +Cause @value{GDBN} to print structures in an indented format with one member +per line, like this: + +@smallexample +@group +$1 = @{ + next = 0x0, + flags = @{ + sweet = 1, + sour = 1 + @}, + meat = 0x54 "Pork" +@} +@end group +@end smallexample + +@item set print pretty off +Cause @value{GDBN} to print structures in a compact format, like this: + +@smallexample +@group +$1 = @{next = 0x0, flags = @{sweet = 1, sour = 1@}, \ +meat = 0x54 "Pork"@} +@end group +@end smallexample + +@noindent +This is the default format. + +@kindex show print pretty +@item show print pretty +Show which format @value{GDBN} is using to print structures. + +@kindex set print sevenbit-strings +@item set print sevenbit-strings on +Print using only seven-bit characters; if this option is set, +@value{GDBN} displays any eight-bit characters (in strings or +character values) using the notation @code{\}@var{nnn}. This setting is +best if you are working in English (@sc{ascii}) and you use the +high-order bit of characters as a marker or ``meta'' bit. + +@item set print sevenbit-strings off +Print full eight-bit characters. This allows the use of more +international character sets, and is the default. + +@kindex show print sevenbit-strings +@item show print sevenbit-strings +Show whether or not @value{GDBN} is printing only seven-bit characters. + +@kindex set print union +@item set print union on +Tell @value{GDBN} to print unions which are contained in structures. This +is the default setting. + +@item set print union off +Tell @value{GDBN} not to print unions which are contained in structures. + +@kindex show print union +@item show print union +Ask @value{GDBN} whether or not it will print unions which are contained in +structures. + +For example, given the declarations + +@smallexample +typedef enum @{Tree, Bug@} Species; +typedef enum @{Big_tree, Acorn, Seedling@} Tree_forms; +typedef enum @{Caterpillar, Cocoon, Butterfly@} + Bug_forms; + +struct thing @{ + Species it; + union @{ + Tree_forms tree; + Bug_forms bug; + @} form; +@}; + +struct thing foo = @{Tree, @{Acorn@}@}; +@end smallexample + +@noindent +with @code{set print union on} in effect @samp{p foo} would print + +@smallexample +$1 = @{it = Tree, form = @{tree = Acorn, bug = Cocoon@}@} +@end smallexample + +@noindent +and with @code{set print union off} in effect it would print + +@smallexample +$1 = @{it = Tree, form = @{...@}@} +@end smallexample +@end table + +@ifclear CONLY +@need 1000 +@noindent +These settings are of interest when debugging C++ programs: + +@table @code +@cindex demangling +@kindex set print demangle +@item set print demangle +@itemx set print demangle on +Print C++ names in their source form rather than in the encoded +(``mangled'') form passed to the assembler and linker for type-safe +linkage. The default is @samp{on}. + +@kindex show print demangle +@item show print demangle +Show whether C++ names are printed in mangled or demangled form. + +@kindex set print asm-demangle +@item set print asm-demangle +@itemx set print asm-demangle on +Print C++ names in their source form rather than their mangled form, even +in assembler code printouts such as instruction disassemblies. +The default is off. + +@kindex show print asm-demangle +@item show print asm-demangle +Show whether C++ names in assembly listings are printed in mangled +or demangled form. + +@kindex set demangle-style +@cindex C++ symbol decoding style +@cindex symbol decoding style, C++ +@item set demangle-style @var{style} +Choose among several encoding schemes used by different compilers to +represent C++ names. The choices for @var{style} are currently: + +@table @code +@item auto +Allow @value{GDBN} to choose a decoding style by inspecting your program. + +@item gnu +Decode based on the @sc{gnu} C++ compiler (@code{g++}) encoding algorithm. +This is the default. + +@item lucid +Decode based on the Lucid C++ compiler (@code{lcc}) encoding algorithm. + +@item arm +Decode using the algorithm in the @cite{C++ Annotated Reference Manual}. +@strong{Warning:} this setting alone is not sufficient to allow +debugging @code{cfront}-generated executables. @value{GDBN} would +require further enhancement to permit that. + +@item foo +Show the list of formats. +@end table + +@kindex show demangle-style +@item show demangle-style +Display the encoding style currently in use for decoding C++ symbols. + +@kindex set print object +@item set print object +@itemx set print object on +When displaying a pointer to an object, identify the @emph{actual} +(derived) type of the object rather than the @emph{declared} type, using +the virtual function table. + +@item set print object off +Display only the declared type of objects, without reference to the +virtual function table. This is the default setting. + +@kindex show print object +@item show print object +Show whether actual, or declared, object types are displayed. + +@kindex set print static-members +@item set print static-members +@itemx set print static-members on +Print static members when displaying a C++ object. The default is on. + +@item set print static-members off +Do not print static members when displaying a C++ object. + +@kindex show print static-members +@item show print static-members +Show whether C++ static members are printed, or not. + +@kindex set print vtbl +@item set print vtbl +@itemx set print vtbl on +Pretty print C++ virtual function tables. The default is off. + +@item set print vtbl off +Do not pretty print C++ virtual function tables. + +@kindex show print vtbl +@item show print vtbl +Show whether C++ virtual function tables are pretty printed, or not. +@end table +@end ifclear + +@node Value History +@section Value history + +@cindex value history +Values printed by the @code{print} command are saved in the @value{GDBN} +@dfn{value history}. This allows you to refer to them in other expressions. +Values are kept until the symbol table is re-read or discarded +(for example with the @code{file} or @code{symbol-file} commands). +When the symbol table changes, the value history is discarded, +since the values may contain pointers back to the types defined in the +symbol table. + +@cindex @code{$} +@cindex @code{$$} +@cindex history number +The values printed are given @dfn{history numbers} by which you can +refer to them. These are successive integers starting with one. +@code{print} shows you the history number assigned to a value by +printing @samp{$@var{num} = } before the value; here @var{num} is the +history number. + +To refer to any previous value, use @samp{$} followed by the value's +history number. The way @code{print} labels its output is designed to +remind you of this. Just @code{$} refers to the most recent value in +the history, and @code{$$} refers to the value before that. +@code{$$@var{n}} refers to the @var{n}th value from the end; @code{$$2} +is the value just prior to @code{$$}, @code{$$1} is equivalent to +@code{$$}, and @code{$$0} is equivalent to @code{$}. + +For example, suppose you have just printed a pointer to a structure and +want to see the contents of the structure. It suffices to type + +@example +p *$ +@end example + +If you have a chain of structures where the component @code{next} points +to the next one, you can print the contents of the next one with this: + +@example +p *$.next +@end example + +@noindent +You can print successive links in the chain by repeating this +command---which you can do by just typing @key{RET}. + +Note that the history records values, not expressions. If the value of +@code{x} is 4 and you type these commands: + +@example +print x +set x=5 +@end example + +@noindent +then the value recorded in the value history by the @code{print} command +remains 4 even though the value of @code{x} has changed. + +@table @code +@kindex show values +@item show values +Print the last ten values in the value history, with their item numbers. +This is like @samp{p@ $$9} repeated ten times, except that @code{show +values} does not change the history. + +@item show values @var{n} +Print ten history values centered on history item number @var{n}. + +@item show values + +Print ten history values just after the values last printed. If no more +values are available, @code{show values +} produces no display. +@end table + +Pressing @key{RET} to repeat @code{show values @var{n}} has exactly the +same effect as @samp{show values +}. + +@node Convenience Vars +@section Convenience variables + +@cindex convenience variables +@value{GDBN} provides @dfn{convenience variables} that you can use within +@value{GDBN} to hold on to a value and refer to it later. These variables +exist entirely within @value{GDBN}; they are not part of your program, and +setting a convenience variable has no direct effect on further execution +of your program. That is why you can use them freely. + +Convenience variables are prefixed with @samp{$}. Any name preceded by +@samp{$} can be used for a convenience variable, unless it is one of +the predefined machine-specific register names (@pxref{Registers}). +(Value history references, in contrast, are @emph{numbers} preceded +by @samp{$}. @xref{Value History, ,Value history}.) + +You can save a value in a convenience variable with an assignment +expression, just as you would set a variable in your program. +For example: + +@example +set $foo = *object_ptr +@end example + +@noindent +would save in @code{$foo} the value contained in the object pointed to by +@code{object_ptr}. + +Using a convenience variable for the first time creates it, but its +value is @code{void} until you assign a new value. You can alter the +value with another assignment at any time. + +Convenience variables have no fixed types. You can assign a convenience +variable any type of value, including structures and arrays, even if +that variable already has a value of a different type. The convenience +variable, when used as an expression, has the type of its current value. + +@table @code +@kindex show convenience +@item show convenience +Print a list of convenience variables used so far, and their values. +Abbreviated @code{show con}. +@end table + +One of the ways to use a convenience variable is as a counter to be +incremented or a pointer to be advanced. For example, to print +a field from successive elements of an array of structures: + +@example +set $i = 0 +print bar[$i++]->contents +@end example + +@noindent Repeat that command by typing @key{RET}. + +Some convenience variables are created automatically by @value{GDBN} and given +values likely to be useful. + +@table @code +@kindex $_ +@item $_ +The variable @code{$_} is automatically set by the @code{x} command to +the last address examined (@pxref{Memory, ,Examining memory}). Other +commands which provide a default address for @code{x} to examine also +set @code{$_} to that address; these commands include @code{info line} +and @code{info breakpoint}. The type of @code{$_} is @code{void *} +except when set by the @code{x} command, in which case it is a pointer +to the type of @code{$__}. + +@kindex $__ +@item $__ +The variable @code{$__} is automatically set by the @code{x} command +to the value found in the last address examined. Its type is chosen +to match the format in which the data was printed. + +@item $_exitcode +@kindex $_exitcode +The variable @code{$_exitcode} is automatically set to the exit code when +the program being debugged terminates. +@end table + +@node Registers +@section Registers + +@cindex registers +You can refer to machine register contents, in expressions, as variables +with names starting with @samp{$}. The names of registers are different +for each machine; use @code{info registers} to see the names used on +your machine. + +@table @code +@kindex info registers +@item info registers +Print the names and values of all registers except floating-point +registers (in the selected stack frame). + +@kindex info all-registers +@cindex floating point registers +@item info all-registers +Print the names and values of all registers, including floating-point +registers. + +@item info registers @var{regname} @dots{} +Print the @dfn{relativized} value of each specified register @var{regname}. +As discussed in detail below, register values are normally relative to +the selected stack frame. @var{regname} may be any register name valid on +the machine you are using, with or without the initial @samp{$}. +@end table + +@value{GDBN} has four ``standard'' register names that are available (in +expressions) on most machines---whenever they do not conflict with an +architecture's canonical mnemonics for registers. The register names +@code{$pc} and @code{$sp} are used for the program counter register and +the stack pointer. @code{$fp} is used for a register that contains a +pointer to the current stack frame, and @code{$ps} is used for a +register that contains the processor status. For example, +you could print the program counter in hex with + +@example +p/x $pc +@end example + +@noindent +or print the instruction to be executed next with + +@example +x/i $pc +@end example + +@noindent +or add four to the stack pointer@footnote{This is a way of removing +one word from the stack, on machines where stacks grow downward in +memory (most machines, nowadays). This assumes that the innermost +stack frame is selected; setting @code{$sp} is not allowed when other +stack frames are selected. To pop entire frames off the stack, +regardless of machine architecture, use @code{return}; +@pxref{Returning, ,Returning from a function}.} with + +@example +set $sp += 4 +@end example + +Whenever possible, these four standard register names are available on +your machine even though the machine has different canonical mnemonics, +so long as there is no conflict. The @code{info registers} command +shows the canonical names. For example, on the SPARC, @code{info +registers} displays the processor status register as @code{$psr} but you +can also refer to it as @code{$ps}. + +@value{GDBN} always considers the contents of an ordinary register as an +integer when the register is examined in this way. Some machines have +special registers which can hold nothing but floating point; these +registers are considered to have floating point values. There is no way +to refer to the contents of an ordinary register as floating point value +(although you can @emph{print} it as a floating point value with +@samp{print/f $@var{regname}}). + +Some registers have distinct ``raw'' and ``virtual'' data formats. This +means that the data format in which the register contents are saved by +the operating system is not the same one that your program normally +sees. For example, the registers of the 68881 floating point +coprocessor are always saved in ``extended'' (raw) format, but all C +programs expect to work with ``double'' (virtual) format. In such +cases, @value{GDBN} normally works with the virtual format only (the format +that makes sense for your program), but the @code{info registers} command +prints the data in both formats. + +Normally, register values are relative to the selected stack frame +(@pxref{Selection, ,Selecting a frame}). This means that you get the +value that the register would contain if all stack frames farther in +were exited and their saved registers restored. In order to see the +true contents of hardware registers, you must select the innermost +frame (with @samp{frame 0}). + +However, @value{GDBN} must deduce where registers are saved, from the machine +code generated by your compiler. If some registers are not saved, or if +@value{GDBN} is unable to locate the saved registers, the selected stack +frame makes no difference. + +@ifset AMD29K +@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 +``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 +@end ifset + +@ifclear HAVE-FLOAT +@node Floating Point Hardware +@section Floating point hardware +@cindex floating point + +Depending on the configuration, @value{GDBN} may be able to give +you more information about the status of the floating point hardware. + +@table @code +@kindex info float +@item info float +Display hardware-dependent information about the floating +point unit. The exact contents and layout vary depending on the +floating point chip. Currently, @samp{info float} is supported on +the ARM and x86 machines. +@end table +@end ifclear + +@ifclear CONLY +@node Languages +@chapter Using @value{GDBN} with Different Languages +@cindex languages + +@ifset MOD2 +Although programming languages generally have common aspects, they are +rarely expressed in the same manner. For instance, in ANSI C, +dereferencing a pointer @code{p} is accomplished by @code{*p}, but in +Modula-2, it is accomplished by @code{p^}. Values can also be +represented (and displayed) differently. Hex numbers in C appear as +@samp{0x1ae}, while in Modula-2 they appear as @samp{1AEH}. +@end ifset + +@cindex working language +Language-specific information is built into @value{GDBN} for some languages, +allowing you to express operations like the above in your program's +native language, and allowing @value{GDBN} to output values in a manner +consistent with the syntax of your program's native language. The +language you use to build expressions is called the @dfn{working +language}. + +@menu +* Setting:: Switching between source languages +* Show:: Displaying the language +@ifset MOD2 +* Checks:: Type and range checks +@end ifset + +* Support:: Supported languages +@end menu + +@node Setting +@section Switching between source languages + +There are two ways to control the working language---either have @value{GDBN} +set it automatically, or select it manually yourself. You can use the +@code{set language} command for either purpose. On startup, @value{GDBN} +defaults to setting the language automatically. The working language is +used to determine how expressions you type are interpreted, how values +are printed, etc. + +In addition to the working language, every source file that +@value{GDBN} knows about has its own working language. For some object +file formats, the compiler might indicate which language a particular +source file is in. However, most of the time @value{GDBN} infers the +language from the name of the file. The language of a source file +controls whether C++ names are demangled---this way @code{backtrace} can +show each frame appropriately for its own language. There is no way to +set the language of a source file from within @value{GDBN}. + +This is most commonly a problem when you use a program, such +as @code{cfront} or @code{f2c}, that generates C but is written in +another language. In that case, make the +program use @code{#line} directives in its C output; that way +@value{GDBN} will know the correct language of the source code of the original +program, and will display that source code, not the generated C code. + +@menu +* Filenames:: Filename extensions and languages. +* Manually:: Setting the working language manually +* Automatically:: Having @value{GDBN} infer the source language +@end menu + +@node Filenames +@subsection List of filename extensions and languages + +If a source file name ends in one of the following extensions, then +@value{GDBN} infers that its language is the one indicated. + +@table @file +@ifset MOD2 +@item .mod +Modula-2 source file +@end ifset + +@item .c +C source file + +@item .C +@itemx .cc +@itemx .cxx +@itemx .cpp +@itemx .cp +@itemx .c++ +C++ source file + +@item .ch +@itemx .c186 +@itemx .c286 +CHILL source file. + +@item .s +@itemx .S +Assembler source file. This actually behaves almost like C, but +@value{GDBN} does not skip over function prologues when stepping. +@end table + +@node Manually +@subsection Setting the working language + +If you allow @value{GDBN} to set the language automatically, +expressions are interpreted the same way in your debugging session and +your program. + +@kindex set language +If you wish, you may set the language manually. To do this, issue the +command @samp{set language @var{lang}}, where @var{lang} is the name of +a language, such as +@ifclear MOD2 +@code{c}. +@end ifclear +@ifset MOD2 +@code{c} or @code{modula-2}. +@end ifset +For a list of the supported languages, type @samp{set language}. + +@ifset MOD2 +Setting the language manually prevents @value{GDBN} from updating the working +language automatically. This can lead to confusion if you try +to debug a program when the working language is not the same as the +source language, when an expression is acceptable to both +languages---but means different things. For instance, if the current +source file were written in C, and @value{GDBN} was parsing Modula-2, a +command such as: + +@example +print a = b + c +@end example + +@noindent +might not have the effect you intended. In C, this means to add +@code{b} and @code{c} and place the result in @code{a}. The result +printed would be the value of @code{a}. In Modula-2, this means to compare +@code{a} to the result of @code{b+c}, yielding a @code{BOOLEAN} value. +@end ifset + +@node Automatically +@subsection Having @value{GDBN} infer the source language + +To have @value{GDBN} set the working language automatically, use +@samp{set language local} or @samp{set language auto}. @value{GDBN} +then infers the working language. That is, when your program stops in a +frame (usually by encountering a breakpoint), @value{GDBN} sets the +working language to the language recorded for the function in that +frame. If the language for a frame is unknown (that is, if the function +or block corresponding to the frame was defined in a source file that +does not have a recognized extension), the current working language is +not changed, and @value{GDBN} issues a warning. + +This may not seem necessary for most programs, which are written +entirely in one source language. However, program modules and libraries +written in one source language can be used by a main program written in +a different source language. Using @samp{set language auto} in this +case frees you from having to set the working language manually. + +@node Show +@section Displaying the language + +The following commands help you find out which language is the +working language, and also what language source files were written in. + +@kindex show language +@kindex info frame +@kindex info source +@table @code +@item show language +Display the current working language. This is the +language you can use with commands such as @code{print} to +build and compute expressions that may involve variables in your program. + +@item info frame +Display the source language for this frame. This language becomes the +working language if you use an identifier from this frame. +@xref{Frame Info, ,Information about a frame}, to identify the other +information listed here. + +@item info source +Display the source language of this source file. +@xref{Symbols, ,Examining the Symbol Table}, to identify the other +information listed here. +@end table + +@ifset MOD2 +@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 +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 +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{Support, ,Supported languages}, +for the default settings of supported languages. + +@menu +* Type Checking:: An overview of type checking +* Range Checking:: An overview of range checking +@end menu + +@cindex type checking +@cindex checks, type +@node Type Checking +@subsection An overview of type checking + +Some languages, such as Modula-2, 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 +@exdent but +@error{} 1 + 2.3 +@end smallexample + +The second example fails because the @code{CARDINAL} 1 is not +type-compatible with the @code{REAL} 2.3. + +For the expressions you use in @value{GDBN} commands, you can tell the +@value{GDBN} type checker to skip checking; +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. + +Even if you turn type checking 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{Support, ,Supported languages}, for further +details on specific languages. + +@value{GDBN} provides some additional commands for controlling the type checker: + +@kindex set check +@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{Support, ,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 +evaluating an expression while typechecking 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. +@end table + +@cindex range checking +@cindex checks, range +@node Range Checking +@subsection An overview of range checking + +In some languages (such as Modula-2), it is an error to exceed the +bounds of a type; this is enforced with run-time checks. Such range +checking is meant to ensure program correctness by making sure +computations do not overflow, or indices on an array element access do +not exceed the bounds of the array. + +For expressions you use in @value{GDBN} commands, you can tell +@value{GDBN} to treat range errors in one of three ways: ignore them, +always treat them as errors and abandon the expression, or issue +warnings but evaluate the expression anyway. + +A range error can result from numerical overflow, from exceeding an +array index bound, or when you type a constant that is not a member +of any type. Some languages, however, do not treat overflows as an +error. In many implementations of C, mathematical overflow causes the +result to ``wrap around'' to lower values---for example, if @var{m} is +the largest integer value, and @var{s} is the smallest, then + +@example +@var{m} + 1 @result{} @var{s} +@end example + +This, too, is specific to individual languages, and in some cases +specific to individual compilers or machines. @xref{Support, , +Supported languages}, for further details on specific languages. + +@value{GDBN} provides some additional commands for controlling the range checker: + +@kindex set check +@kindex set check range +@kindex show check range +@table @code +@item set check range auto +Set range checking on or off based on the current working language. +@xref{Support, ,Supported languages}, for the default settings for +each language. + +@item set check range on +@itemx set check range off +Set range checking on or off, overriding the default setting for the +current working language. A warning is issued if the setting does not +match the language default. If a range error occurs, then a message +is printed and evaluation of the expression is aborted. + +@item set check range warn +Output messages when the @value{GDBN} range checker detects a range error, +but attempt to evaluate the expression anyway. Evaluating the +expression may still be impossible for other reasons, such as accessing +memory that the process does not own (a typical example from many Unix +systems). + +@item show range +Show the current setting of the range checker, and whether or not it is +being set automatically by @value{GDBN}. +@end table +@end ifset + +@node Support +@section Supported languages + +@ifset MOD2 +@value{GDBN} 4 supports C, C++, and Modula-2. +@end ifset +@ifclear MOD2 +@value{GDBN} 4 supports C, and C++. +@end ifclear +Some @value{GDBN} features may be used in expressions regardless of the +language you use: the @value{GDBN} @code{@@} and @code{::} operators, +and the @samp{@{type@}addr} construct (@pxref{Expressions, +,Expressions}) can be used with the constructs of any supported +language. + +The following sections detail to what degree each source language is +supported by @value{GDBN}. These sections are not meant to be language +tutorials or references, but serve only as a reference guide to what the +@value{GDBN} expression parser accepts, and what input and output +formats should look like for different languages. There are many good +books written on each of these languages; please look to these for a +language reference or tutorial. + +@ifset MOD2 +@menu +* C:: C and C++ +* Modula-2:: Modula-2 +@end menu + +@node C +@subsection C and C++ +@cindex C and C++ +@cindex expressions in C or C++ + +Since C and C++ are so closely related, many features of @value{GDBN} apply +to both languages. Whenever this is the case, we discuss those languages +together. +@end ifset +@ifclear MOD2 +@c Cancel this below, under same condition, at end of this chapter! +@raisesections +@end ifclear + +@cindex C++ +@kindex g++ +@cindex @sc{gnu} C++ +The C++ debugging facilities are jointly implemented by the @sc{gnu} C++ +compiler and @value{GDBN}. Therefore, to debug your C++ code +effectively, you must compile your C++ programs with the @sc{gnu} C++ +compiler, @code{g++}. + +For best results when debugging C++ programs, use the stabs debugging +format. You can select that format explicitly with the @code{g++} +command-line options @samp{-gstabs} or @samp{-gstabs+}. See +@ref{Debugging Options,,Options for Debugging Your Program or @sc{gnu} CC, +gcc.info, Using @sc{gnu} CC}, for more information. +@end ifclear +@ifset CONLY +@node C +@chapter C Language Support +@cindex C language +@cindex expressions in C + +Information specific to the C language is built into @value{GDBN} so that you +can use C expressions while degugging. This also permits @value{GDBN} to +output values in a manner consistent with C conventions. + +@menu +* C Operators:: C operators +* C Constants:: C constants +* Debugging C:: @value{GDBN} and C +@end menu +@end ifset +@ifclear CONLY +@menu +* C Operators:: C and C++ operators +* C Constants:: C and C++ constants +* Cplus expressions:: C++ expressions +* C Defaults:: Default settings for C and C++ +@ifset MOD2 +* C Checks:: C and C++ type and range checks +@end ifset + +* Debugging C:: @value{GDBN} and C +* Debugging C plus plus:: Special features for C++ +@end menu +@end ifclear + +@ifclear CONLY +@cindex C and C++ operators +@node C Operators +@subsubsection C and C++ operators +@end ifclear +@ifset CONLY +@cindex C operators +@node C Operators +@section C operators +@end ifset + +Operators must be defined on values of specific types. For instance, +@code{+} is defined on numbers, but not on structures. Operators are +often defined on groups of types. + +@ifclear CONLY +For the purposes of C and C++, the following definitions hold: +@end ifclear + +@itemize @bullet +@item +@emph{Integral types} include @code{int} with any of its storage-class +specifiers; @code{char}; and @code{enum}. + +@item +@emph{Floating-point types} include @code{float} and @code{double}. + +@item +@emph{Pointer types} include all types defined as @code{(@var{type} +*)}. + +@item +@emph{Scalar types} include all of the above. +@end itemize + +@noindent +The following operators are supported. They are listed here +in order of increasing precedence: + +@table @code +@item , +The comma or sequencing operator. Expressions in a comma-separated list +are evaluated from left to right, with the result of the entire +expression being the last expression evaluated. + +@item = +Assignment. The value of an assignment expression is the value +assigned. Defined on scalar types. + +@item @var{op}= +Used in an expression of the form @w{@code{@var{a} @var{op}= @var{b}}}, +and translated to @w{@code{@var{a} = @var{a op b}}}. +@w{@code{@var{op}=}} and @code{=} have the same precendence. +@var{op} is any one of the operators @code{|}, @code{^}, @code{&}, +@code{<<}, @code{>>}, @code{+}, @code{-}, @code{*}, @code{/}, @code{%}. + +@item ?: +The ternary operator. @code{@var{a} ? @var{b} : @var{c}} can be thought +of as: if @var{a} then @var{b} else @var{c}. @var{a} should be of an +integral type. + +@item || +Logical @sc{or}. Defined on integral types. + +@item && +Logical @sc{and}. Defined on integral types. + +@item | +Bitwise @sc{or}. Defined on integral types. + +@item ^ +Bitwise exclusive-@sc{or}. Defined on integral types. + +@item & +Bitwise @sc{and}. Defined on integral types. + +@item ==@r{, }!= +Equality and inequality. Defined on scalar types. The value of these +expressions is 0 for false and non-zero for true. + +@item <@r{, }>@r{, }<=@r{, }>= +Less than, greater than, less than or equal, greater than or equal. +Defined on scalar types. The value of these expressions is 0 for false +and non-zero for true. + +@item <<@r{, }>> +left shift, and right shift. Defined on integral types. + +@item @@ +The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}). + +@item +@r{, }- +Addition and subtraction. Defined on integral types, floating-point types and +pointer types. + +@item *@r{, }/@r{, }% +Multiplication, division, and modulus. Multiplication and division are +defined on integral and floating-point types. Modulus is defined on +integral types. + +@item ++@r{, }-- +Increment and decrement. When appearing before a variable, the +operation is performed before the variable is used in an expression; +when appearing after it, the variable's value is used before the +operation takes place. + +@item * +Pointer dereferencing. Defined on pointer types. Same precedence as +@code{++}. + +@item & +Address operator. Defined on variables. Same precedence as @code{++}. + +@ifclear CONLY +For debugging C++, @value{GDBN} implements a use of @samp{&} beyond what is +allowed in the C++ language itself: you can use @samp{&(&@var{ref})} +(or, if you prefer, simply @samp{&&@var{ref}}) to examine the address +where a C++ reference variable (declared with @samp{&@var{ref}}) is +stored. +@end ifclear + +@item - +Negative. Defined on integral and floating-point types. Same +precedence as @code{++}. + +@item ! +Logical negation. Defined on integral types. Same precedence as +@code{++}. + +@item ~ +Bitwise complement operator. Defined on integral types. Same precedence as +@code{++}. + + +@item .@r{, }-> +Structure member, and pointer-to-structure member. For convenience, +@value{GDBN} regards the two as equivalent, choosing whether to dereference a +pointer based on the stored type information. +Defined on @code{struct} and @code{union} data. + +@item [] +Array indexing. @code{@var{a}[@var{i}]} is defined as +@code{*(@var{a}+@var{i})}. Same precedence as @code{->}. + +@item () +Function parameter list. Same precedence as @code{->}. + +@ifclear CONLY +@item :: +C++ scope resolution operator. Defined on +@code{struct}, @code{union}, and @code{class} types. +@end ifclear + +@item :: +Doubled colons +@ifclear CONLY +also +@end ifclear +represent the @value{GDBN} scope operator (@pxref{Expressions, +,Expressions}). +@ifclear CONLY +Same precedence as @code{::}, above. +@end ifclear +@end table + +@ifclear CONLY +@cindex C and C++ constants +@node C Constants +@subsubsection C and C++ constants + +@value{GDBN} allows you to express the constants of C and C++ in the +following ways: +@end ifclear +@ifset CONLY +@cindex C constants +@node C Constants +@section C constants + +@value{GDBN} allows you to express the constants of C in the +following ways: +@end ifset + +@itemize @bullet +@item +Integer constants are a sequence of digits. Octal constants are +specified by a leading @samp{0} (i.e. zero), and hexadecimal constants by +a leading @samp{0x} or @samp{0X}. Constants may also end with a letter +@samp{l}, specifying that the constant should be treated as a +@code{long} value. + +@item +Floating point constants are a sequence of digits, followed by a decimal +point, followed by a sequence of digits, and optionally followed by an +exponent. An exponent is of the form: +@samp{@w{e@r{[[}+@r{]|}-@r{]}@var{nnn}}}, where @var{nnn} is another +sequence of digits. The @samp{+} is optional for positive exponents. + +@item +Enumerated constants consist of enumerated identifiers, or their +integral equivalents. + +@item +Character constants are a single character surrounded by single quotes +(@code{'}), or a number---the ordinal value of the corresponding character +(usually its @sc{ASCII} value). Within quotes, the single character may +be represented by a letter or by @dfn{escape sequences}, which are of +the form @samp{\@var{nnn}}, where @var{nnn} is the octal representation +of the character's ordinal value; or of the form @samp{\@var{x}}, where +@samp{@var{x}} is a predefined special character---for example, +@samp{\n} for newline. + +@item +String constants are a sequence of character constants surrounded +by double quotes (@code{"}). + +@item +Pointer constants are an integral value. You can also write pointers +to constants using the C operator @samp{&}. + +@item +Array constants are comma-separated lists surrounded by braces @samp{@{} +and @samp{@}}; for example, @samp{@{1,2,3@}} is a three-element array of +integers, @samp{@{@{1,2@}, @{3,4@}, @{5,6@}@}} is a three-by-two array, +and @samp{@{&"hi", &"there", &"fred"@}} is a three-element array of pointers. +@end itemize + +@ifclear CONLY +@node Cplus expressions +@subsubsection C++ expressions + +@cindex expressions in C++ +@value{GDBN} expression handling has a number of extensions to +interpret a significant subset of C++ expressions. + +@cindex C++ support, not in @sc{coff} +@cindex @sc{coff} versus C++ +@cindex C++ and object formats +@cindex object formats and C++ +@cindex a.out and C++ +@cindex @sc{ecoff} and C++ +@cindex @sc{xcoff} and C++ +@cindex @sc{elf}/stabs and C++ +@cindex @sc{elf}/@sc{dwarf} and C++ +@c FIXME!! GDB may eventually be able to debug C++ using DWARF; check +@c periodically whether this has happened... +@quotation +@emph{Warning:} @value{GDBN} can only debug C++ code if you compile with +the @sc{gnu} C++ compiler. Moreover, C++ debugging depends on the use of +additional debugging information in the symbol table, and thus requires +special support. @value{GDBN} has this support @emph{only} with the +stabs debug format. In particular, if your compiler generates a.out, +MIPS @sc{ecoff}, RS/6000 @sc{xcoff}, or @sc{elf} with stabs extensions +to the symbol table, these facilities are all available. (With @sc{gnu} CC, +you can use the @samp{-gstabs} option to request stabs debugging +extensions explicitly.) Where the object code format is standard +@sc{coff} or @sc{dwarf} in @sc{elf}, on the other hand, most of the C++ +support in @value{GDBN} does @emph{not} work. +@end quotation + +@enumerate + +@cindex member functions +@item +Member function calls are allowed; you can use expressions like + +@example +count = aml->GetOriginal(x, y) +@end example + +@kindex this +@cindex namespace in C++ +@item +While a member function is active (in the selected stack frame), your +expressions have the same namespace available as the member function; +that is, @value{GDBN} allows implicit references to the class instance +pointer @code{this} following the same rules as C++. + +@cindex call overloaded functions +@cindex type conversions in C++ +@item +You can call overloaded functions; @value{GDBN} resolves the function +call to the right definition, with one restriction---you must use +arguments of the type required by the function that you want to call. +@value{GDBN} does not perform conversions requiring constructors or +user-defined type operators. + +@cindex reference declarations +@item +@value{GDBN} understands variables declared as C++ references; you can use +them in expressions just as you do in C++ source---they are automatically +dereferenced. + +In the parameter list shown when @value{GDBN} displays a frame, the values of +reference variables are not displayed (unlike other variables); this +avoids clutter, since references are often used for large structures. +The @emph{address} of a reference variable is always shown, unless +you have specified @samp{set print address off}. + +@item +@value{GDBN} supports the C++ name resolution operator @code{::}---your +expressions can use it just as expressions in your program do. Since +one scope may be defined in another, you can use @code{::} repeatedly if +necessary, for example in an expression like +@samp{@var{scope1}::@var{scope2}::@var{name}}. @value{GDBN} also allows +resolving name scope by reference to source files, in both C and C++ +debugging (@pxref{Variables, ,Program variables}). +@end enumerate + +@node C Defaults +@subsubsection C and C++ defaults +@cindex C and C++ 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 +C or C++. This happens regardless of whether you or @value{GDBN} +selects the working language. + +If you allow @value{GDBN} to set the language automatically, it recognizes +source files whose names end with @file{.c}, @file{.C}, or @file{.cc}, and +when @value{GDBN} enters code compiled from one of these files, +it sets the working language to C or C++. +@xref{Automatically, ,Having @value{GDBN} infer the source language}, for +further details. + +@ifset MOD2 +@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++ type and range checks +@cindex C and C++ checks + +By default, when @value{GDBN} parses C or C++ 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 + +Range checking, if turned on, is done on mathematical operations. Array +indices are not checked, since they are often used to index a pointer +that is not itself an array. +@end ifset +@end ifclear + +@ifclear CONLY +@node Debugging C +@subsubsection @value{GDBN} and C +@end ifclear +@ifset CONLY +@node Debugging C +@section @value{GDBN} and C +@end ifset + +The @code{set print union} and @code{show print union} commands apply to +the @code{union} type. When set to @samp{on}, any @code{union} that is +inside a @code{struct} +@ifclear CONLY +or @code{class} +@end ifclear +is also printed. +Otherwise, it appears as @samp{@{...@}}. + +The @code{@@} operator aids in the debugging of dynamic arrays, formed +with pointers and a memory allocation function. @xref{Expressions, +,Expressions}. + +@ifclear CONLY +@node Debugging C plus plus +@subsubsection @value{GDBN} features for C++ + +@cindex commands for C++ +Some @value{GDBN} commands are particularly useful with C++, and some are +designed specifically for use with C++. Here is a summary: + +@table @code +@cindex break in overloaded functions +@item @r{breakpoint menus} +When you want a breakpoint in a function whose name is overloaded, +@value{GDBN} breakpoint menus help you specify which function definition +you want. @xref{Breakpoint Menus,,Breakpoint menus}. + +@cindex overloading in C++ +@item rbreak @var{regex} +Setting breakpoints using regular expressions is helpful for setting +breakpoints on overloaded functions that are not members of any special +classes. +@xref{Set Breaks, ,Setting breakpoints}. + +@cindex C++ exception handling +@item catch @var{exceptions} +@itemx info catch +Debug C++ exception handling using these commands. @xref{Exception +Handling, ,Breakpoints and exceptions}. + +@cindex inheritance +@item ptype @var{typename} +Print inheritance relationships as well as other information for type +@var{typename}. +@xref{Symbols, ,Examining the Symbol Table}. + +@cindex C++ symbol display +@item set print demangle +@itemx show print demangle +@itemx set print asm-demangle +@itemx show print asm-demangle +Control whether C++ symbols display in their source form, both when +displaying code as C++ source and when displaying disassemblies. +@xref{Print Settings, ,Print settings}. + +@item set print object +@itemx show print object +Choose whether to print derived (actual) or declared types of objects. +@xref{Print Settings, ,Print settings}. + +@item set print vtbl +@itemx show print vtbl +Control the format for printing virtual function tables. +@xref{Print Settings, ,Print settings}. + +@item @r{Overloaded symbol names} +You can specify a particular definition of an overloaded symbol, using +the same notation that is used to declare such symbols in C++: type +@code{@var{symbol}(@var{types})} rather than just @var{symbol}. You can +also use the @value{GDBN} command-line word completion facilities to list the +available choices, or to finish the type list for you. +@xref{Completion,, Command completion}, for details on how to do this. +@end table +@ifclear MOD2 +@c cancels "raisesections" under same conditions near bgn of chapter +@lowersections +@end ifclear + +@ifset MOD2 +@node Modula-2 +@subsection Modula-2 +@cindex Modula-2 + +The extensions made to @value{GDBN} to support Modula-2 only support +output from the @sc{gnu} Modula-2 compiler (which is currently being +developed). Other Modula-2 compilers are not currently supported, and +attempting to debug executables produced by them is most likely +to give an error as @value{GDBN} reads in the executable's symbol +table. + +@cindex expressions in Modula-2 +@menu +* M2 Operators:: Built-in operators +* Built-In Func/Proc:: Built-in functions and procedures +* M2 Constants:: Modula-2 constants +* M2 Defaults:: Default settings for Modula-2 +* Deviations:: Deviations from standard Modula-2 +* M2 Checks:: Modula-2 type and range checks +* M2 Scope:: The scope operators @code{::} and @code{.} +* GDB/M2:: @value{GDBN} and Modula-2 +@end menu + +@node M2 Operators +@subsubsection Operators +@cindex Modula-2 operators + +Operators must be defined on values of specific types. For instance, +@code{+} is defined on numbers, but not on structures. Operators are +often defined on groups of types. For the purposes of Modula-2, the +following definitions hold: + +@itemize @bullet + +@item +@emph{Integral types} consist of @code{INTEGER}, @code{CARDINAL}, and +their subranges. + +@item +@emph{Character types} consist of @code{CHAR} and its subranges. + +@item +@emph{Floating-point types} consist of @code{REAL}. + +@item +@emph{Pointer types} consist of anything declared as @code{POINTER TO +@var{type}}. + +@item +@emph{Scalar types} consist of all of the above. + +@item +@emph{Set types} consist of @code{SET} and @code{BITSET} types. + +@item +@emph{Boolean types} consist of @code{BOOLEAN}. +@end itemize + +@noindent +The following operators are supported, and appear in order of +increasing precedence: + +@table @code +@item , +Function argument or array index separator. + +@item := +Assignment. The value of @var{var} @code{:=} @var{value} is +@var{value}. + +@item <@r{, }> +Less than, greater than on integral, floating-point, or enumerated +types. + +@item <=@r{, }>= +Less than, greater than, less than or equal to, greater than or equal to +on integral, floating-point and enumerated types, or set inclusion on +set types. Same precedence as @code{<}. + +@item =@r{, }<>@r{, }# +Equality and two ways of expressing inequality, valid on scalar types. +Same precedence as @code{<}. In @value{GDBN} scripts, only @code{<>} is +available for inequality, since @code{#} conflicts with the script +comment character. + +@item IN +Set membership. Defined on set types and the types of their members. +Same precedence as @code{<}. + +@item OR +Boolean disjunction. Defined on boolean types. + +@item AND@r{, }& +Boolean conjuction. Defined on boolean types. + +@item @@ +The @value{GDBN} ``artificial array'' operator (@pxref{Expressions, ,Expressions}). + +@item +@r{, }- +Addition and subtraction on integral and floating-point types, or union +and difference on set types. + +@item * +Multiplication on integral and floating-point types, or set intersection +on set types. + +@item / +Division on floating-point types, or symmetric set difference on set +types. Same precedence as @code{*}. + +@item DIV@r{, }MOD +Integer division and remainder. Defined on integral types. Same +precedence as @code{*}. + +@item - +Negative. Defined on @code{INTEGER} and @code{REAL} data. + +@item ^ +Pointer dereferencing. Defined on pointer types. + +@item NOT +Boolean negation. Defined on boolean types. Same precedence as +@code{^}. + +@item . +@code{RECORD} field selector. Defined on @code{RECORD} data. Same +precedence as @code{^}. + +@item [] +Array indexing. Defined on @code{ARRAY} data. Same precedence as @code{^}. + +@item () +Procedure argument list. Defined on @code{PROCEDURE} objects. Same precedence +as @code{^}. + +@item ::@r{, }. +@value{GDBN} and Modula-2 scope operators. +@end table + +@quotation +@emph{Warning:} Sets and their operations are not yet supported, so @value{GDBN} +treats the use of the operator @code{IN}, or the use of operators +@code{+}, @code{-}, @code{*}, @code{/}, @code{=}, , @code{<>}, @code{#}, +@code{<=}, and @code{>=} on sets as an error. +@end quotation + +@cindex Modula-2 built-ins +@node Built-In Func/Proc +@subsubsection Built-in functions and procedures + +Modula-2 also makes available several built-in procedures and functions. +In describing these, the following metavariables are used: + +@table @var + +@item a +represents an @code{ARRAY} variable. + +@item c +represents a @code{CHAR} constant or variable. + +@item i +represents a variable or constant of integral type. + +@item m +represents an identifier that belongs to a set. Generally used in the +same function with the metavariable @var{s}. The type of @var{s} should +be @code{SET OF @var{mtype}} (where @var{mtype} is the type of @var{m}). + +@item n +represents a variable or constant of integral or floating-point type. + +@item r +represents a variable or constant of floating-point type. + +@item t +represents a type. + +@item v +represents a variable. + +@item x +represents a variable or constant of one of many types. See the +explanation of the function for details. +@end table + +All Modula-2 built-in procedures also return a result, described below. + +@table @code +@item ABS(@var{n}) +Returns the absolute value of @var{n}. + +@item CAP(@var{c}) +If @var{c} is a lower case letter, it returns its upper case +equivalent, otherwise it returns its argument + +@item CHR(@var{i}) +Returns the character whose ordinal value is @var{i}. + +@item DEC(@var{v}) +Decrements the value in the variable @var{v}. Returns the new value. + +@item DEC(@var{v},@var{i}) +Decrements the value in the variable @var{v} by @var{i}. Returns the +new value. + +@item EXCL(@var{m},@var{s}) +Removes the element @var{m} from the set @var{s}. Returns the new +set. + +@item FLOAT(@var{i}) +Returns the floating point equivalent of the integer @var{i}. + +@item HIGH(@var{a}) +Returns the index of the last member of @var{a}. + +@item INC(@var{v}) +Increments the value in the variable @var{v}. Returns the new value. + +@item INC(@var{v},@var{i}) +Increments the value in the variable @var{v} by @var{i}. Returns the +new value. + +@item INCL(@var{m},@var{s}) +Adds the element @var{m} to the set @var{s} if it is not already +there. Returns the new set. + +@item MAX(@var{t}) +Returns the maximum value of the type @var{t}. + +@item MIN(@var{t}) +Returns the minimum value of the type @var{t}. + +@item ODD(@var{i}) +Returns boolean TRUE if @var{i} is an odd number. + +@item ORD(@var{x}) +Returns the ordinal value of its argument. For example, the ordinal +value of a character is its ASCII value (on machines supporting the +ASCII character set). @var{x} must be of an ordered type, which include +integral, character and enumerated types. + +@item SIZE(@var{x}) +Returns the size of its argument. @var{x} can be a variable or a type. + +@item TRUNC(@var{r}) +Returns the integral part of @var{r}. + +@item VAL(@var{t},@var{i}) +Returns the member of the type @var{t} whose ordinal value is @var{i}. +@end table + +@quotation +@emph{Warning:} Sets and their operations are not yet supported, so +@value{GDBN} treats the use of procedures @code{INCL} and @code{EXCL} as +an error. +@end quotation + +@cindex Modula-2 constants +@node M2 Constants +@subsubsection Constants + +@value{GDBN} allows you to express the constants of Modula-2 in the following +ways: + +@itemize @bullet + +@item +Integer constants are simply a sequence of digits. When used in an +expression, a constant is interpreted to be type-compatible with the +rest of the expression. Hexadecimal integers are specified by a +trailing @samp{H}, and octal integers by a trailing @samp{B}. + +@item +Floating point constants appear as a sequence of digits, followed by a +decimal point and another sequence of digits. An optional exponent can +then be specified, in the form @samp{E@r{[}+@r{|}-@r{]}@var{nnn}}, where +@samp{@r{[}+@r{|}-@r{]}@var{nnn}} is the desired exponent. All of the +digits of the floating point constant must be valid decimal (base 10) +digits. + +@item +Character constants consist of a single character enclosed by a pair of +like quotes, either single (@code{'}) or double (@code{"}). They may +also be expressed by their ordinal value (their ASCII value, usually) +followed by a @samp{C}. + +@item +String constants consist of a sequence of characters enclosed by a +pair of like quotes, either single (@code{'}) or double (@code{"}). +Escape sequences in the style of C are also allowed. @xref{C +Constants, ,C and C++ constants}, for a brief explanation of escape +sequences. + +@item +Enumerated constants consist of an enumerated identifier. + +@item +Boolean constants consist of the identifiers @code{TRUE} and +@code{FALSE}. + +@item +Pointer constants consist of integral values only. + +@item +Set constants are not yet supported. +@end itemize + +@node M2 Defaults +@subsubsection Modula-2 defaults +@cindex Modula-2 defaults + +If type and range checking are set automatically by @value{GDBN}, they +both default to @code{on} whenever the working language changes to +Modula-2. This happens regardless of whether you, or @value{GDBN}, +selected the working language. + +If you allow @value{GDBN} to set the language automatically, then entering +code compiled from a file whose name ends with @file{.mod} sets the +working language to Modula-2. @xref{Automatically, ,Having @value{GDBN} set +the language automatically}, for further details. + +@node Deviations +@subsubsection Deviations from standard Modula-2 +@cindex Modula-2, deviations from + +A few changes have been made to make Modula-2 programs easier to debug. +This is done primarily via loosening its type strictness: + +@itemize @bullet +@item +Unlike in standard Modula-2, pointer constants can be formed by +integers. This allows you to modify pointer variables during +debugging. (In standard Modula-2, the actual address contained in a +pointer variable is hidden from you; it can only be modified +through direct assignment to another pointer variable or expression that +returned a pointer.) + +@item +C escape sequences can be used in strings and characters to represent +non-printable characters. @value{GDBN} prints out strings with these +escape sequences embedded. Single non-printable characters are +printed using the @samp{CHR(@var{nnn})} format. + +@item +The assignment operator (@code{:=}) returns the value of its right-hand +argument. + +@item +All built-in procedures both modify @emph{and} return their argument. +@end itemize + +@node M2 Checks +@subsubsection Modula-2 type and range checks +@cindex Modula-2 checks + +@quotation +@emph{Warning:} in this release, @value{GDBN} does not yet perform type or +range checking. +@end quotation +@c FIXME remove warning when type/range checks added + +@value{GDBN} considers two Modula-2 variables type equivalent if: + +@itemize @bullet +@item +They are of types that have been declared equivalent via a @code{TYPE +@var{t1} = @var{t2}} statement + +@item +They have been declared on the same line. (Note: This is true of the +@sc{gnu} Modula-2 compiler, but it may not be true of other compilers.) +@end itemize + +As long as type checking is enabled, any attempt to combine variables +whose types are not equivalent is an error. + +Range checking is done on all mathematical operations, assignment, array +index bounds, and all built-in functions and procedures. + +@node M2 Scope +@subsubsection The scope operators @code{::} and @code{.} +@cindex scope +@kindex . +@cindex colon, doubled as scope operator +@ifinfo +@kindex colon-colon +@c Info cannot handle :: but TeX can. +@end ifinfo +@iftex +@kindex :: +@end iftex + +There are a few subtle differences between the Modula-2 scope operator +(@code{.}) and the @value{GDBN} scope operator (@code{::}). The two have +similar syntax: + +@example + +@var{module} . @var{id} +@var{scope} :: @var{id} +@end example + +@noindent +where @var{scope} is the name of a module or a procedure, +@var{module} the name of a module, and @var{id} is any declared +identifier within your program, except another module. + +Using the @code{::} operator makes @value{GDBN} search the scope +specified by @var{scope} for the identifier @var{id}. If it is not +found in the specified scope, then @value{GDBN} searches all scopes +enclosing the one specified by @var{scope}. + +Using the @code{.} operator makes @value{GDBN} search the current scope for +the identifier specified by @var{id} that was imported from the +definition module specified by @var{module}. With this operator, it is +an error if the identifier @var{id} was not imported from definition +module @var{module}, or if @var{id} is not an identifier in +@var{module}. + +@node GDB/M2 +@subsubsection @value{GDBN} and Modula-2 + +Some @value{GDBN} commands have little use when debugging Modula-2 programs. +Five subcommands of @code{set print} and @code{show print} apply +specifically to C and C++: @samp{vtbl}, @samp{demangle}, +@samp{asm-demangle}, @samp{object}, and @samp{union}. The first four +apply to C++, and the last to the C @code{union} type, which has no direct +analogue in Modula-2. + +The @code{@@} operator (@pxref{Expressions, ,Expressions}), while available +while using any language, is not useful with Modula-2. Its +intent is to aid the debugging of @dfn{dynamic arrays}, which cannot be +created in Modula-2 as they can in C or C++. However, because an +address can be specified by an integral constant, the construct +@samp{@{@var{type}@}@var{adrexp}} is still useful. (@pxref{Expressions, ,Expressions}) + +@cindex @code{#} in Modula-2 +In @value{GDBN} scripts, the Modula-2 inequality operator @code{#} is +interpreted as the beginning of a comment. Use @code{<>} instead. +@end ifset +@end ifclear + +@node Symbols +@chapter Examining the Symbol Table + +The commands described in this section allow you to inquire about the +symbols (names of variables, functions and types) defined in your +program. This information is inherent in the text of your program and +does not change as your program executes. @value{GDBN} finds it in your +program's symbol table, in the file indicated when you started @value{GDBN} +(@pxref{File Options, ,Choosing files}), or by one of the +file-management commands (@pxref{Files, ,Commands to specify files}). + +@cindex symbol names +@cindex names of symbols +@cindex quoting names +Occasionally, you may need to refer to symbols that contain unusual +characters, which @value{GDBN} ordinarily treats as word delimiters. The +most frequent case is in referring to static variables in other +source files (@pxref{Variables,,Program variables}). File names +are recorded in object files as debugging symbols, but @value{GDBN} would +ordinarily parse a typical file name, like @file{foo.c}, as the three words +@samp{foo} @samp{.} @samp{c}. To allow @value{GDBN} to recognize +@samp{foo.c} as a single symbol, enclose it in single quotes; for example, + +@example +p 'foo.c'::x +@end example + +@noindent +looks up the value of @code{x} in the scope of the file @file{foo.c}. + +@table @code +@kindex info address +@item info address @var{symbol} +Describe where the data for @var{symbol} is stored. For a register +variable, this says which register it is kept in. For a non-register +local variable, this prints the stack-frame offset at which the variable +is always stored. + +Note the contrast with @samp{print &@var{symbol}}, which does not work +at all for a register variable, and for a stack local variable prints +the exact address of the current instantiation of the variable. + +@kindex whatis +@item whatis @var{exp} +Print the data type of expression @var{exp}. @var{exp} is not +actually evaluated, and any side-effecting operations (such as +assignments or function calls) inside it do not take place. +@xref{Expressions, ,Expressions}. + +@item whatis +Print the data type of @code{$}, the last value in the value history. + +@kindex ptype +@item ptype @var{typename} +Print a description of data type @var{typename}. @var{typename} may be +the name of a type, or for C code it may have the form +@ifclear CONLY +@samp{class @var{class-name}}, +@end ifclear +@samp{struct @var{struct-tag}}, @samp{union @var{union-tag}} or +@samp{enum @var{enum-tag}}. + +@item ptype @var{exp} +@itemx ptype +Print a description of the type of expression @var{exp}. @code{ptype} +differs from @code{whatis} by printing a detailed description, instead +of just the name of the type. + +For example, for this variable declaration: + +@example +struct complex @{double real; double imag;@} v; +@end example + +@noindent +the two commands give this output: + +@example +@group +(@value{GDBP}) whatis v +type = struct complex +(@value{GDBP}) ptype v +type = struct complex @{ + double real; + double imag; +@} +@end group +@end example + +@noindent +As with @code{whatis}, using @code{ptype} without an argument refers to +the type of @code{$}, the last value in the value history. + +@kindex info types +@item info types @var{regexp} +@itemx info types +Print a brief description of all types whose name matches @var{regexp} +(or all types in your program, if you supply no argument). Each +complete typename is matched as though it were a complete line; thus, +@samp{i type value} gives information on all types in your program whose +name includes the string @code{value}, but @samp{i type ^value$} gives +information only on types whose complete name is @code{value}. + +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 source +@item info source +Show the name of the current source file---that is, the source file for +the function containing the current point of execution---and the language +it was written in. + +@kindex info sources +@item info sources +Print the names of all source files in your program for which there is +debugging information, organized into two lists: files whose symbols +have already been read, and files whose symbols will be read when needed. + +@kindex info functions +@item info functions +Print the names and data types of all defined functions. + +@item info functions @var{regexp} +Print the names and data types of all defined functions +whose names contain a match for regular expression @var{regexp}. +Thus, @samp{info fun step} finds all functions whose names +include @code{step}; @samp{info fun ^step} finds those whose names +start with @code{step}. + +@kindex info variables +@item info variables +Print the names and data types of all variables that are declared +outside of functions (i.e., excluding local variables). + +@item info variables @var{regexp} +Print the names and data types of all variables (except for local +variables) whose names contain a match for regular expression +@var{regexp}. + +@ignore +This was never implemented. +@kindex info methods +@item info methods +@itemx info methods @var{regexp} +The @code{info methods} command permits the user to examine all defined +methods within C++ program, or (with the @var{regexp} argument) a +specific set of methods found in the various C++ classes. Many +C++ classes provide a large number of methods. Thus, the output +from the @code{ptype} command can be overwhelming and hard to use. The +@code{info-methods} command filters the methods, printing only those +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. +@ifset VXWORKS +For example, in VxWorks you can simply recompile a defective object file +and keep on running. +@end ifset +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 re-encountering object files of +the same name. This is the default state; if you are not running on a +system that permits automatically relinking 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 + +@kindex maint print symbols +@cindex symbol dump +@kindex maint print psymbols +@cindex partial symbol dump +@item maint print symbols @var{filename} +@itemx maint print psymbols @var{filename} +@itemx maint print msymbols @var{filename} +Write a dump of debugging symbol data into the file @var{filename}. +These commands are used to debug the @value{GDBN} symbol-reading code. Only +symbols with debugging data are included. If you use @samp{maint print +symbols}, @value{GDBN} includes all the symbols for which it has already +collected full details: that is, @var{filename} reflects symbols for +only those files whose symbols @value{GDBN} has read. You can use the +command @code{info sources} to find out which files these are. If you +use @samp{maint print psymbols} instead, the dump shows information about +symbols that @value{GDBN} only knows partially---that is, symbols defined in +files that @value{GDBN} has skimmed, but not yet read completely. Finally, +@samp{maint print msymbols} dumps just the minimal symbol information +required for each object file from which @value{GDBN} has read some symbols. +@xref{Files, ,Commands to specify files}, for a discussion of how +@value{GDBN} reads symbols (in the description of @code{symbol-file}). +@end table + +@node Altering +@chapter Altering Execution + +Once you think you have found an error in your program, you might want to +find out for certain whether correcting the apparent error would lead to +correct results in the rest of the run. You can find the answer by +experiment, using the @value{GDBN} features for altering execution of the +program. + +For example, you can store new values into variables or memory +locations, +@ifclear BARETARGET +give your program a signal, restart it +@end ifclear +@ifset BARETARGET +restart your program +@end ifset +at a different address, or even return prematurely from a function. + +@menu +* Assignment:: Assignment to variables +* Jumping:: Continuing at a different address +@ifclear BARETARGET +* Signaling:: Giving your program a signal +@end ifclear + +* Returning:: Returning from a function +* Calling:: Calling your program's functions +* Patching:: Patching your program +@end menu + +@node Assignment +@section Assignment to variables + +@cindex assignment +@cindex setting variables +To alter the value of a variable, evaluate an assignment expression. +@xref{Expressions, ,Expressions}. For example, + +@example +print x=4 +@end example + +@noindent +stores the value 4 into the variable @code{x}, and then prints the +value of the assignment expression (which is 4). +@ifclear CONLY +@xref{Languages, ,Using @value{GDBN} with Different Languages}, for more +information on operators in supported languages. +@end ifclear + +@kindex set variable +@cindex variables, setting +If you are not interested in seeing the value of the assignment, use the +@code{set} command instead of the @code{print} command. @code{set} is +really the same as @code{print} except that the expression's value is +not printed and is not put in the value history (@pxref{Value History, +,Value history}). The expression is evaluated only for its effects. + +If the beginning of the argument string of the @code{set} command +appears identical to a @code{set} subcommand, use the @code{set +variable} command instead of just @code{set}. This command is identical +to @code{set} except for its lack of subcommands. For example, if +your program has a variable @code{width}, you get +an error if you try to set a new value with just @samp{set width=13}, +because @value{GDBN} has the command @code{set width}: + +@example +(@value{GDBP}) whatis width +type = double +(@value{GDBP}) p width +$4 = 13 +(@value{GDBP}) set width=47 +Invalid syntax in expression. +@end example + +@noindent +The invalid expression, of course, is @samp{=47}. In +order to actually set the program's variable @code{width}, use + +@example +(@value{GDBP}) set var width=47 +@end example + +@value{GDBN} allows more implicit conversions in assignments than C; you can +freely store an integer value into a pointer variable or vice versa, +and you can convert any structure to any other structure that is the +same length or shorter. +@comment FIXME: how do structs align/pad in these conversions? +@comment /doc@cygnus.com 18dec1990 + +To store values into arbitrary places in memory, use the @samp{@{@dots{}@}} +construct to generate a value of specified type at a specified address +(@pxref{Expressions, ,Expressions}). For example, @code{@{int@}0x83040} refers +to memory location @code{0x83040} as an integer (which implies a certain size +and representation in memory), and + +@example +set @{int@}0x83040 = 4 +@end example + +@noindent +stores the value 4 into that memory location. + +@node Jumping +@section Continuing at a different address + +Ordinarily, when you continue your program, you do so at the place where +it stopped, with the @code{continue} command. You can instead continue at +an address of your own choosing, with the following commands: + +@table @code +@kindex jump +@item jump @var{linespec} +Resume execution at line @var{linespec}. Execution stops again +immediately if there is a breakpoint there. @xref{List, ,Printing +source lines}, for a description of the different forms of +@var{linespec}. + +The @code{jump} command does not change the current stack frame, or +the stack pointer, or the contents of any memory location or any +register other than the program counter. If line @var{linespec} is in +a different function from the one currently executing, the results may +be bizarre if the two functions expect different patterns of arguments or +of local variables. For this reason, the @code{jump} command requests +confirmation if the specified line is not in the function currently +executing. However, even bizarre results are predictable if you are +well acquainted with the machine-language code of your program. + +@item jump *@var{address} +Resume execution at the instruction at address @var{address}. +@end table + +You can get much the same effect as the @code{jump} command by storing a +new value into the register @code{$pc}. The difference is that this +does not start your program running; it only changes the address of where it +@emph{will} run when you continue. For example, + +@example +set $pc = 0x485 +@end example + +@noindent +makes the next @code{continue} command or stepping command execute at +address @code{0x485}, rather than at the address where your program stopped. +@xref{Continuing and Stepping, ,Continuing and stepping}. + +The most common occasion to use the @code{jump} command is to back up-- +perhaps with more breakpoints set--over a portion of a program that has +already executed, in order to examine its execution in more detail. + +@ifclear BARETARGET +@c @group +@node Signaling +@section Giving your program a signal + +@table @code +@kindex signal +@item signal @var{signal} +Resume execution where your program stopped, but immediately give it the +signal @var{signal}. @var{signal} can be the name or the number of a +signal. For example, on many systems @code{signal 2} and @code{signal +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 +@code{continue} command; @samp{signal 0} causes it to resume without a +signal. + +@code{signal} does not repeat when you press @key{RET} a second time +after executing the command. +@end table +@c @end group + +Invoking the @code{signal} command is not the same as invoking the +@code{kill} utility from the shell. Sending a signal with @code{kill} +causes @value{GDBN} to decide what to do with the signal depending on +the signal handling tables (@pxref{Signals}). The @code{signal} command +passes the signal directly to your program. + +@end ifclear + +@node Returning +@section Returning from a function + +@table @code +@cindex returning from a function +@kindex return +@item return +@itemx return @var{expression} +You can cancel execution of a function call with the @code{return} +command. If you give an +@var{expression} argument, its value is used as the function's return +value. +@end table + +When you use @code{return}, @value{GDBN} discards the selected stack frame +(and all frames within it). You can think of this as making the +discarded frame return prematurely. If you wish to specify a value to +be returned, give that value as the argument to @code{return}. + +This pops the selected stack frame (@pxref{Selection, ,Selecting a +frame}), and any other frames inside of it, leaving its caller as the +innermost remaining frame. That frame becomes selected. The +specified value is stored in the registers used for returning values +of functions. + +The @code{return} command does not resume execution; it leaves the +program stopped in the state that would exist if the function had just +returned. In contrast, the @code{finish} command (@pxref{Continuing +and Stepping, ,Continuing and stepping}) resumes execution until the +selected stack frame returns naturally. + +@node Calling +@section Calling program functions + +@cindex calling functions +@kindex call +@table @code +@item call @var{expr} +Evaluate the expression @var{expr} without displaying @code{void} +returned values. +@end table + +You can use this variant of the @code{print} command if you want to +execute a function from your program, but without cluttering the output +with @code{void} returned values. If the result is not void, it +is printed and saved in the value history. + +A new user-controlled variable, @var{call_scratch_address}, specifies +the location of a scratch area to be used when @value{GDBN} calls a +function in the target. This is necessary because the usual method +of putting the scratch area on the stack does not work in systems that +have separate instruction and data spaces. + +@node Patching +@section Patching programs +@cindex patching binaries +@cindex writing into executables +@ifclear BARETARGET +@cindex writing into corefiles +@end ifclear + +By default, @value{GDBN} opens the file containing your program's executable +code +@ifclear BARETARGET +(or the corefile) +@end ifclear +read-only. This prevents accidental alterations +to machine code; but it also prevents you from intentionally patching +your program's binary. + +If you'd like to be able to patch the binary, you can specify that +explicitly with the @code{set write} command. For example, you might +want to turn on internal debugging flags, or even to make emergency +repairs. + +@table @code +@kindex set write +@item set write on +@itemx set write off +If you specify @samp{set write on}, @value{GDBN} opens executable +@ifclear BARETARGET +and core +@end ifclear +files for both reading and writing; if you specify @samp{set write +off} (the default), @value{GDBN} opens them read-only. + +If you have already loaded a file, you must load it again (using the +@code{exec-file} +@ifclear BARETARGET +or @code{core-file} +@end ifclear +command) after changing @code{set write}, for your new setting to take +effect. + +@item show write +@kindex show write +Display whether executable files +@ifclear BARETARGET +and core files +@end ifclear +are opened for writing as well as reading. +@end table + +@node GDB Files +@chapter @value{GDBN} Files + +@value{GDBN} needs to know the file name of the program to be debugged, both in +order to read its symbol table and in order to start your program. +@ifclear BARETARGET +To debug a core dump of a previous run, you must also tell @value{GDBN} +the name of the core dump file. +@end ifclear + +@menu +* Files:: Commands to specify files +* Symbol Errors:: Errors reading symbol files +@end menu + +@node Files +@section Commands to specify files +@cindex symbol table + +@ifclear BARETARGET +@cindex core dump file +You may want to specify executable and core dump file names. +The usual way to do this is at start-up time, using the arguments to +@value{GDBN}'s start-up commands (@pxref{Invocation, , +Getting In and Out of @value{GDBN}}). +@end ifclear +@ifset BARETARGET +The usual way to specify an executable file name is with +the command argument given when you start @value{GDBN}, (@pxref{Invocation, +,Getting In and Out of @value{GDBN}}. +@end ifset + +Occasionally it is necessary to change to a different file during a +@value{GDBN} session. Or you may run @value{GDBN} and forget to specify +a file you want to use. In these situations the @value{GDBN} commands +to specify new files are useful. + +@table @code +@cindex executable file +@kindex file +@item file @var{filename} +Use @var{filename} as the program to be debugged. It is read for its +symbols and for the contents of pure memory. It is also the program +executed when you use the @code{run} command. If you do not specify a +directory and the file is not found in the @value{GDBN} working directory, +@value{GDBN} uses the environment variable @code{PATH} as a list of +directories to search, just as the shell does when looking for a program +to run. You can change the value of this variable, for both @value{GDBN} +and your program, using the @code{path} command. + +On systems with memory-mapped files, an auxiliary file +@file{@var{filename}.syms} may hold symbol table information for +@var{filename}. If so, @value{GDBN} maps in the symbol table from +@file{@var{filename}.syms}, starting up more quickly. See the +descriptions of the file options @samp{-mapped} and @samp{-readnow} +(available on the command line, and with the commands @code{file}, +@code{symbol-file}, or @code{add-symbol-file}, described below), +for more information. + +@item file +@code{file} with no argument makes @value{GDBN} discard any information it +has on both executable file and the symbol table. + +@kindex exec-file +@item exec-file @r{[} @var{filename} @r{]} +Specify that the program to be run (but not the symbol table) is found +in @var{filename}. @value{GDBN} searches the environment variable @code{PATH} +if necessary to locate your program. Omitting @var{filename} means to +discard information on the executable file. + +@kindex symbol-file +@item symbol-file @r{[} @var{filename} @r{]} +Read symbol table information from file @var{filename}. @code{PATH} is +searched when necessary. Use the @code{file} command to get both symbol +table and program to run from the same file. + +@code{symbol-file} with no argument clears out @value{GDBN} information on your +program's symbol table. + +The @code{symbol-file} command causes @value{GDBN} to forget the contents +of its convenience variables, the value history, and all breakpoints and +auto-display expressions. This is because they may contain pointers to +the internal data recording symbols and data types, which are part of +the old symbol table data being discarded inside @value{GDBN}. + +@code{symbol-file} does not repeat if you press @key{RET} again after +executing it once. + +When @value{GDBN} is configured for a particular environment, it +understands debugging information in whatever format is the standard +generated for that environment; you may use either a @sc{gnu} compiler, or +other compilers that adhere to the local conventions. Best results are +usually obtained from @sc{gnu} compilers; for example, using @code{@value{GCC}} +you can generate debugging information for optimized code. + +On some kinds of object files, the @code{symbol-file} command does not +normally read the symbol table in full right away. Instead, it scans +the symbol table quickly to find which source files and which symbols +are present. The details are read later, one source file at a time, +as they are needed. + +The purpose of this two-stage reading strategy is to make @value{GDBN} start up +faster. For the most part, it is invisible except for occasional +pauses while the symbol table details for a particular source file are +being read. (The @code{set verbose} command can turn these pauses +into messages if desired. @xref{Messages/Warnings, ,Optional warnings +and messages}.) + +We have not implemented the two-stage strategy for COFF yet. When the +symbol table is stored in COFF format, @code{symbol-file} reads the +symbol table data in full right away. + +@kindex readnow +@cindex reading symbols immediately +@cindex symbols, reading immediately +@kindex mapped +@cindex memory-mapped symbol file +@cindex saving symbol table +@item symbol-file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +@itemx file @var{filename} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +You can override the @value{GDBN} two-stage strategy for reading symbol +tables by using the @samp{-readnow} option with any of the commands that +load symbol table information, if you want to be sure @value{GDBN} has the +entire symbol table available. + +@ifclear BARETARGET +If memory-mapped files are available on your system through the +@code{mmap} system call, you can use another option, @samp{-mapped}, to +cause @value{GDBN} to write the symbols for your program into a reusable +file. Future @value{GDBN} debugging sessions map in symbol information +from this auxiliary symbol file (if the program has not changed), rather +than spending time reading the symbol table from the executable +program. Using the @samp{-mapped} option has the same effect as +starting @value{GDBN} with the @samp{-mapped} command-line option. + +You can use both options together, to make sure the auxiliary symbol +file has all the symbol information for your program. + +The auxiliary symbol file for a program called @var{myprog} is called +@samp{@var{myprog}.syms}. Once this file exists (so long as it is newer +than the corresponding executable), @value{GDBN} always attempts to use +it when you debug @var{myprog}; no special options or commands are +needed. + +The @file{.syms} file is specific to the host machine where you run +@value{GDBN}. It holds an exact image of the internal @value{GDBN} +symbol table. It cannot be shared across multiple host platforms. + +@c FIXME: for now no mention of directories, since this seems to be in +@c flux. 13mar1992 status is that in theory GDB would look either in +@c current dir or in same dir as myprog; but issues like competing +@c GDB's, or clutter in system dirs, mean that in practice right now +@c only current dir is used. FFish says maybe a special GDB hierarchy +@c (eg rooted in val of env var GDBSYMS) could exist for mappable symbol +@c files. + +@kindex core +@kindex core-file +@item core-file @r{[} @var{filename} @r{]} +Specify the whereabouts of a core dump file to be used as the ``contents +of memory''. Traditionally, core files contain only some parts of the +address space of the process that generated them; @value{GDBN} can access the +executable file itself for other parts. + +@code{core-file} with no argument specifies that no core file is +to be used. + +Note that the core file is ignored when your program is actually running +under @value{GDBN}. So, if you have been running your program and you wish to +debug a core file instead, you must kill the subprocess in which the +program is running. To do this, use the @code{kill} command +(@pxref{Kill Process, ,Killing the child process}). +@end ifclear + +@kindex load @var{filename} +@item load @var{filename} +@ifset GENERIC +Depending on what remote debugging facilities are configured into +@value{GDBN}, the @code{load} command may be available. Where it exists, it +is meant to make @var{filename} (an executable) available for debugging +on the remote system---by downloading, or dynamic linking, for example. +@code{load} also records the @var{filename} symbol table in @value{GDBN}, like +the @code{add-symbol-file} command. + +If your @value{GDBN} does not have a @code{load} command, attempting to +execute it gets the error message ``@code{You can't do that when your +target is @dots{}}'' +@end ifset + +The file is loaded at whatever address is specified in the executable. +For some object file formats, you can specify the load address when you +link the program; for other formats, like a.out, the object file format +specifies a fixed address. +@c FIXME! This would be a good place for an xref to the GNU linker doc. + +@ifset VXWORKS +On VxWorks, @code{load} links @var{filename} dynamically on the +current target system as well as adding its symbols in @value{GDBN}. +@end ifset + +@ifset I960 +@cindex download to Nindy-960 +With the Nindy interface to an Intel 960 board, @code{load} +downloads @var{filename} to the 960 as well as adding its symbols in +@value{GDBN}. +@end ifset + +@ifset H8 +@cindex download to H8/300 or H8/500 +@cindex H8/300 or H8/500 download +@cindex download to Hitachi SH +@cindex Hitachi SH download +When you select remote debugging to a Hitachi SH, H8/300, or H8/500 board +(@pxref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}), +the @code{load} command downloads your program to the Hitachi board and also +opens it as the current executable target for @value{GDBN} on your host +(like the @code{file} command). +@end ifset + +@code{load} does not repeat if you press @key{RET} again after using it. + +@ifclear BARETARGET +@kindex add-symbol-file +@cindex dynamic linking +@item add-symbol-file @var{filename} @var{address} +@itemx add-symbol-file @var{filename} @var{address} @r{[} -readnow @r{]} @r{[} -mapped @r{]} +The @code{add-symbol-file} command reads additional symbol table information +from the file @var{filename}. You would use this command when @var{filename} +has been dynamically loaded (by some other means) into the program that +is running. @var{address} should be the memory address at which the +file has been loaded; @value{GDBN} cannot figure this out for itself. +You can specify @var{address} as an expression. + +The symbol table of the file @var{filename} is added to the symbol table +originally read with the @code{symbol-file} command. You can use the +@code{add-symbol-file} command any number of times; the new symbol data thus +read keeps adding to the old. To discard all old symbol data instead, +use the @code{symbol-file} command. + +@code{add-symbol-file} does not repeat if you press @key{RET} after using it. + +You can use the @samp{-mapped} and @samp{-readnow} options just as with +the @code{symbol-file} command, to change how @value{GDBN} manages the symbol +table information for @var{filename}. + +@kindex add-shared-symbol-file +@item add-shared-symbol-file +The @code{add-shared-symbol-file} command can be used only under Harris' CXUX +operating system for the Motorola 88k. @value{GDBN} automatically looks for +shared libraries, however if @value{GDBN} does not find yours, you can run +@code{add-shared-symbol-file}. It takes no arguments. +@end ifclear + +@kindex section +@item section +The @code{section} command changes the base address of section SECTION of +the exec file to ADDR. This can be used if the exec file does not contain +section addresses, (such as in the a.out format), or when the addresses +specified in the file itself are wrong. Each section must be changed +separately. The ``info files'' command lists all the sections and their +addresses. + +@kindex info files +@kindex info target +@item info files +@itemx info target +@code{info files} and @code{info target} are synonymous; both print +the current target (@pxref{Targets, ,Specifying a Debugging Target}), +including the +@ifclear BARETARGET +names of the executable and core dump files +@end ifclear +@ifset BARETARGET +name of the executable file +@end ifset +currently in use by @value{GDBN}, and the files from which symbols were +loaded. The command @code{help target} lists all possible targets +rather than current ones. +@end table + +All file-specifying commands allow both absolute and relative file names +as arguments. @value{GDBN} always converts the file name to an absolute file +name and remembers it that way. + +@ifclear BARETARGET +@cindex shared libraries +@value{GDBN} supports SunOS, SVr4, Irix 5, and IBM RS/6000 shared libraries. +@value{GDBN} automatically loads symbol definitions from shared libraries +when you use the @code{run} command, or when you examine a core file. +(Before you issue the @code{run} command, @value{GDBN} does not understand +references to a function in a shared library, however---unless you are +debugging a core file). +@c FIXME: some @value{GDBN} release may permit some refs to undef +@c FIXME...symbols---eg in a break cmd---assuming they are from a shared +@c FIXME...lib; check this from time to time when updating manual + +@table @code +@kindex info sharedlibrary +@kindex info share +@item info share +@itemx info sharedlibrary +Print the names of the shared libraries which are currently loaded. + +@kindex sharedlibrary +@kindex share +@item sharedlibrary @var{regex} +@itemx share @var{regex} + +Load shared object library symbols for files matching a +Unix regular expression. +As with files loaded automatically, it only loads shared libraries +required by your program for a core file or after typing @code{run}. If +@var{regex} is omitted all shared libraries required by your program are +loaded. +@end table +@end ifclear + +@node Symbol Errors +@section Errors reading symbol files + +While reading a symbol file, @value{GDBN} occasionally encounters problems, +such as symbol types it does not recognize, or known bugs in compiler +output. By default, @value{GDBN} does not notify you of such problems, since +they are relatively common and primarily of interest to people +debugging compilers. If you are interested in seeing information +about ill-constructed symbol tables, you can either ask @value{GDBN} to print +only one message about each such type of problem, no matter how many +times the problem occurs; or you can ask @value{GDBN} to print more messages, +to see how many times the problems occur, with the @code{set +complaints} command (@pxref{Messages/Warnings, ,Optional warnings and +messages}). + +The messages currently printed, and their meanings, include: + +@table @code +@item inner block not inside outer block in @var{symbol} + +The symbol information shows where symbol scopes begin and end +(such as at the start of a function or a block of statements). This +error indicates that an inner scope block is not fully contained +in its outer scope blocks. + +@value{GDBN} circumvents the problem by treating the inner block as if it had +the same scope as the outer block. In the error message, @var{symbol} +may be shown as ``@code{(don't know)}'' if the outer block is not a +function. + +@item block at @var{address} out of order + +The symbol information for symbol scope blocks should occur in +order of increasing addresses. This error indicates that it does not +do so. + +@value{GDBN} does not circumvent this problem, and has trouble +locating symbols in the source file whose symbols it is reading. (You +can often determine what source file is affected by specifying +@code{set verbose on}. @xref{Messages/Warnings, ,Optional warnings and +messages}.) + +@item bad block start address patched + +The symbol information for a symbol scope block has a start address +smaller than the address of the preceding source line. This is known +to occur in the SunOS 4.1.1 (and earlier) C compiler. + +@value{GDBN} circumvents the problem by treating the symbol scope block as +starting on the previous source line. + +@item bad string table offset in symbol @var{n} + +@cindex foo +Symbol number @var{n} contains a pointer into the string table which is +larger than the size of the string table. + +@value{GDBN} circumvents the problem by considering the symbol to have the +name @code{foo}, which may cause other problems if many symbols end up +with this name. + +@item unknown symbol type @code{0x@var{nn}} + +The symbol information contains new data types that @value{GDBN} does not yet +know how to read. @code{0x@var{nn}} is the symbol type of the misunderstood +information, in hexadecimal. + +@value{GDBN} circumvents the error by ignoring this symbol information. This +usually allows you to debug your program, though certain symbols +are not accessible. If you encounter such a problem and feel like +debugging it, you can debug @code{@value{GDBP}} with itself, breakpoint on +@code{complain}, then go up to the function @code{read_dbx_symtab} and +examine @code{*bufp} to see the symbol. + +@item stub type has NULL name +@value{GDBN} could not find the full definition for +@ifclear CONLY +a struct or class. +@end ifclear +@ifset CONLY +a struct. +@end ifset + +@ifclear CONLY +@item const/volatile indicator missing (ok if using g++ v1.x), got@dots{} + +The symbol information for a C++ member function is missing some +information that recent versions of the compiler should have output +for it. +@end ifclear + +@item info mismatch between compiler and debugger + +@value{GDBN} could not parse a type specification output by the compiler. +@end table + +@node Targets +@chapter Specifying a Debugging Target +@cindex debugging target +@kindex target + +A @dfn{target} is the execution environment occupied by your program. +@ifclear BARETARGET +Often, @value{GDBN} runs in the same host environment as your program; in +that case, the debugging target is specified as a side effect when you +use the @code{file} or @code{core} commands. When you need more +flexibility---for example, running @value{GDBN} on a physically separate +host, or controlling a standalone system over a serial port or a +realtime system over a TCP/IP connection---you +@end ifclear +@ifset BARETARGET +You +@end ifset +can use the @code{target} command to specify one of the target types +configured for @value{GDBN} (@pxref{Target Commands, ,Commands for managing +targets}). + +@menu +* Active Targets:: Active targets +* Target Commands:: Commands for managing targets +* Remote:: Remote debugging +@end menu + +@node Active Targets +@section Active targets +@cindex stacking targets +@cindex active targets +@cindex multiple targets + +@ifclear BARETARGET +There are three classes of targets: processes, core files, and +executable files. @value{GDBN} can work concurrently on up to three active +targets, one in each class. This allows you to (for example) start a +process and inspect its activity without abandoning your work on a core +file. + +For example, if you execute @samp{gdb a.out}, then the executable file +@code{a.out} is the only active target. If you designate a core file as +well---presumably from a prior run that crashed and coredumped---then +@value{GDBN} has two active targets and uses them in tandem, looking +first in the corefile target, then in the executable file, to satisfy +requests for memory addresses. (Typically, these two classes of target +are complementary, since core files contain only a program's +read-write memory---variables and so on---plus machine status, while +executable files contain only the program text and initialized data.) +@end ifclear + +When you type @code{run}, your executable file becomes an active process +target as well. When a process target is active, all @value{GDBN} commands +requesting memory addresses refer to that target; addresses in an +@ifclear BARETARGET +active core file or +@end ifclear +executable file target are obscured while the process +target is active. + +@ifset BARETARGET +Use the @code{exec-file} command to select a +new executable target (@pxref{Files, ,Commands to specify +files}). +@end ifset +@ifclear BARETARGET +Use the @code{core-file} and @code{exec-file} commands to select a +new core file or executable target (@pxref{Files, ,Commands to specify +files}). To specify as a target a process that is already running, use +the @code{attach} command (@pxref{Attach, ,Debugging an +already-running process}). +@end ifclear + +@node Target Commands +@section Commands for managing targets + +@table @code +@item target @var{type} @var{parameters} +Connects the @value{GDBN} host environment to a target +@ifset BARETARGET +machine. +@end ifset +@ifclear BARETARGET +machine or process. A target is typically a protocol for talking to +debugging facilities. You use the argument @var{type} to specify the +type or protocol of the target machine. + +Further @var{parameters} are interpreted by the target protocol, but +typically include things like device names or host names to connect +with, process numbers, and baud rates. +@end ifclear + +The @code{target} command does not repeat if you press @key{RET} again +after executing the command. + +@kindex help target +@item help target +Displays the names of all targets available. To display targets +currently selected, use either @code{info target} or @code{info files} +(@pxref{Files, ,Commands to specify files}). + +@item help target @var{name} +Describe a particular target, including any parameters necessary to +select it. + +@kindex set gnutarget +@item set gnutarget @var{args} +@value{GDBN}uses its own library BFD to read your files. @value{GDBN} +knows whether it is reading an @dfn{executable}, +a @dfn{core}, or a @dfn{.o} file, however you can specify the file format +with the @code{set gnutarget} command. Unlike most @code{target} commands, +with @code{gnutarget} the @code{target} refers to a program, not a machine. + +@emph{Warning:} To specify a file format with @code{set gnutarget}, +you must know the actual BFD name. + +@noindent @xref{Files, , Commands to specify files}. + +@kindex show gnutarget +@item show gnutarget +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 @code{The current BDF target is "auto"}. +@end table + +Here are some common targets (available, or not, depending on the GDB +configuration): + +@table @code +@kindex target exec +@item target exec @var{program} +An executable file. @samp{target exec @var{program}} is the same as +@samp{exec-file @var{program}}. + +@ifclear BARETARGET +@kindex target core +@item target core @var{filename} +A core dump file. @samp{target core @var{filename}} is the same as +@samp{core-file @var{filename}}. +@end ifclear + +@ifset REMOTESTUB +@kindex target remote +@item target remote @var{dev} +Remote serial target in GDB-specific protocol. The argument @var{dev} +specifies what serial device to use for the connection (e.g. +@file{/dev/ttya}). @xref{Remote, ,Remote debugging}. @code{target remote} +now supports the @code{load} command. This is only useful if you have +some other way of getting the stub to the target system, and you can put +it somewhere in memory where it won't get clobbered by the download. +@end ifset + +@ifset SIMS +@kindex target sim +@item target sim +CPU simulator. @xref{Simulator,,Simulated CPU Target}. +@end ifset + +@ifset AMD29K +@kindex target udi +@item target udi @var{keyword} +Remote AMD29K target, using the AMD UDI protocol. The @var{keyword} +argument specifies which 29K board or simulator to use. @xref{UDI29K +Remote,,The UDI protocol for AMD29K}. + +@kindex target amd-eb +@item target amd-eb @var{dev} @var{speed} @var{PROG} +@cindex AMD EB29K +Remote PC-resident AMD EB29K board, attached over serial lines. +@var{dev} is the serial device, as for @code{target remote}; +@var{speed} allows you to specify the linespeed; and @var{PROG} is the +name of the program to be debugged, as it appears to DOS on the PC. +@xref{EB29K Remote, ,The EBMON protocol for AMD29K}. + +@end ifset +@ifset H8 +@kindex target hms +@item target hms @var{dev} +A Hitachi SH, H8/300, or H8/500 board, attached via serial line to your host. +@ifclear H8EXCLUSIVE +Use special commands @code{device} and @code{speed} to control the serial +line and the communications speed used. +@end ifclear +@xref{Hitachi Remote,,@value{GDBN} and Hitachi Microprocessors}. + +@end ifset +@ifset I960 +@kindex target nindy +@item target nindy @var{devicename} +An Intel 960 board controlled by a Nindy Monitor. @var{devicename} is +the name of the serial device to use for the connection, e.g. +@file{/dev/ttya}. @xref{i960-Nindy Remote, ,@value{GDBN} with a remote i960 (Nindy)}. + +@end ifset +@ifset ST2000 +@kindex target st2000 +@item target st2000 @var{dev} @var{speed} +A Tandem ST2000 phone switch, running Tandem's STDBUG protocol. @var{dev} +is the name of the device attached to the ST2000 serial line; +@var{speed} is the communication line speed. The arguments are not used +if @value{GDBN} is configured to connect to the ST2000 using TCP or Telnet. +@xref{ST2000 Remote,,@value{GDBN} with a Tandem ST2000}. +@end ifset + +@ifset VXWORKS +@kindex target vxworks +@item target vxworks @var{machinename} +A VxWorks system, attached via TCP/IP. The argument @var{machinename} +is the target system's machine name or IP address. +@xref{VxWorks Remote, ,@value{GDBN} and VxWorks}. +@end ifset + +@kindex target cpu32bug +@item target cpu32bug @var{dev} +CPU32BUG monitor, running on a CPU32 (M68K) board. + +@kindex target op50n +@item target op50n @var{dev} +OP50N monitor, running on an OKI HPPA board. + +@kindex target w89k +@item target w89k @var{dev} +W89K monitor, running on a Winbond HPPA board. + +@kindex target est +@item target est @var{dev} +EST-300 ICE monitor, running on a CPU32 (M68K) board. + +@kindex target rom68k +@item target rom68k @var{dev} +ROM 68K monitor, running on an IDP board. + +@kindex target array +@item target array @var{dev} +Array Tech LSI33K RAID controller board. + +@kindex target sparclite +@item target sparclite @var{dev} +Fujitsu sparclite boards, used only for the purpose of loading. +You must use an additional command to debug the program. +For example: target remote @var{dev} using @value{GDBN} standard +remote protocol. +@end table + +@ifset GENERIC +Different targets are available on different configurations of @value{GDBN}; +your configuration may have more or fewer targets. +@end ifset + +@section Choosing target byte order +@cindex choosing target byte order +@cindex target byte order +@kindex set endian big +@kindex set endian little +@kindex set endian auto +@kindex show endian + +You can now choose which byte order to use with a target system. +Use the @code{set endian big} and @code{set endian little} commands. +Use the @code{set endian auto} command to instruct +@value{GDBN} to use the byte order associated with the executable. +You can see the current setting for byte order with the @code{show endian} +command. + +@emph{Warning:} Currently, only embedded MIPS configurations support +dynamic selection of target byte order. + +@node Remote +@section Remote debugging +@cindex remote debugging + +If you are trying to debug a program running on a machine that cannot run +@value{GDBN} in the usual way, it is often useful to use remote debugging. +For example, you might use remote debugging on an operating system kernel, +or on a small system which does not have a general purpose operating system +powerful enough to run a full-featured debugger. + +Some configurations of @value{GDBN} have special serial or TCP/IP interfaces +to make this work with particular debugging targets. In addition, +@value{GDBN} comes with a generic serial protocol (specific to @value{GDBN}, +but not specific to any particular target system) which you can use if you +write the remote stubs---the code that runs on the remote system to +communicate with @value{GDBN}. + +Other remote targets may be available in your +configuration of @value{GDBN}; use @code{help target} to list them. + +@ifset GENERIC +@c Text on starting up GDB in various specific cases; it goes up front +@c in manuals configured for any of those particular situations, here +@c otherwise. +@menu +@ifset REMOTESTUB +* Remote Serial:: @value{GDBN} remote serial protocol +@end ifset +@ifset I960 +* i960-Nindy Remote:: @value{GDBN} with a remote i960 (Nindy) +@end ifset +@ifset AMD29K +* UDI29K Remote:: The UDI protocol for AMD29K +* EB29K Remote:: The EBMON protocol for AMD29K +@end ifset +@ifset VXWORKS +* VxWorks Remote:: @value{GDBN} and VxWorks +@end ifset +@ifset ST2000 +* ST2000 Remote:: @value{GDBN} with a Tandem ST2000 +@end ifset +@ifset H8 +* Hitachi Remote:: @value{GDBN} and Hitachi Microprocessors +@end ifset +@ifset MIPS +* MIPS Remote:: @value{GDBN} and MIPS boards +@end ifset +@ifset SIMS +* Simulator:: Simulated CPU target +@end ifset +@end menu + +@include remote.texi +@end ifset + +@node Controlling GDB +@chapter Controlling @value{GDBN} + +You can alter the way @value{GDBN} interacts with you by using +the @code{set} command. For commands controlling how @value{GDBN} displays +data, @pxref{Print Settings, ,Print settings}; other settings are described +here. + +@menu +* Prompt:: Prompt +* Editing:: Command editing +* History:: Command history +* Screen Size:: Screen size +* Numbers:: Numbers +* Messages/Warnings:: Optional warnings and messages +@end menu + +@node Prompt +@section Prompt + +@cindex prompt + +@value{GDBN} indicates its readiness to read a command by printing a string +called the @dfn{prompt}. This string is normally @samp{(@value{GDBP})}. You +can change the prompt string with the @code{set prompt} command. For +instance, when debugging @value{GDBN} with @value{GDBN}, it is useful to change +the prompt in one of the @value{GDBN} sessions so that you can always tell +which one you are talking to. + +@emph{Note:} @code{set prompt} no longer adds a space for you after the +prompt you set. This allows you to set a prompt which ends in a space +or a prompt that does not. + +@table @code +@kindex set prompt +@item set prompt @var{newprompt} +Directs @value{GDBN} to use @var{newprompt} as its prompt string henceforth. + +@kindex show prompt +@item show prompt +Prints a line of the form: @samp{Gdb's prompt is: @var{your-prompt}} +@end table + +@node Editing +@section Command editing +@cindex readline +@cindex command line editing + +@value{GDBN} reads its input commands via the @dfn{readline} interface. This +@sc{gnu} library provides consistent behavior for programs which provide a +command line interface to the user. Advantages are @sc{gnu} Emacs-style +or @dfn{vi}-style inline editing of commands, @code{csh}-like history +substitution, and a storage and recall of command history across +debugging sessions. + +You may control the behavior of command line editing in @value{GDBN} with the +command @code{set}. + +@table @code +@kindex set editing +@cindex editing +@item set editing +@itemx set editing on +Enable command line editing (enabled by default). + +@item set editing off +Disable command line editing. + +@kindex show editing +@item show editing +Show whether command line editing is enabled. +@end table + +@node History +@section Command history + +@value{GDBN} can keep track of the commands you type during your +debugging sessions, so that you can be certain of precisely what +happened. Use these commands to manage the @value{GDBN} command +history facility. + +@table @code +@cindex history substitution +@cindex history file +@kindex set history filename +@kindex GDBHISTFILE +@item set history filename @var{fname} +Set the name of the @value{GDBN} command history file to @var{fname}. +This is the file where @value{GDBN} reads an initial command history +list, and where it writes the command history from this session when it +exits. You can access this list through history expansion or through +the history command editing characters listed below. This file defaults +to the value of the environment variable @code{GDBHISTFILE}, or to +@file{./.gdb_history} if this variable is not set. + +@cindex history save +@kindex set history save +@item set history save +@itemx set history save on +Record command history in a file, whose name may be specified with the +@code{set history filename} command. By default, this option is disabled. + +@item set history save off +Stop recording command history in a file. + +@cindex history size +@kindex set history size +@item set history size @var{size} +Set the number of commands which @value{GDBN} keeps in its history list. +This defaults to the value of the environment variable +@code{HISTSIZE}, or to 256 if this variable is not set. +@end table + +@cindex history expansion +History expansion assigns special meaning to the character @kbd{!}. +@ifset have-readline-appendices +@xref{Event Designators}. +@end ifset + +Since @kbd{!} is also the logical not operator in C, history expansion +is off by default. If you decide to enable history expansion with the +@code{set history expansion on} command, you may sometimes need to +follow @kbd{!} (when it is used as logical not, in an expression) with +a space or a tab to prevent it from being expanded. The readline +history facilities do not attempt substitution on the strings +@kbd{!=} and @kbd{!(}, even when history expansion is enabled. + +The commands to control history expansion are: + +@table @code +@kindex set history expansion +@item set history expansion on +@itemx set history expansion +Enable history expansion. History expansion is off by default. + +@item set history expansion off +Disable history expansion. + +The readline code comes with more complete documentation of +editing and history expansion features. Users unfamiliar with @sc{gnu} Emacs +or @code{vi} may wish to read it. +@ifset have-readline-appendices +@xref{Command Line Editing}. +@end ifset + +@c @group +@kindex show history +@item show history +@itemx show history filename +@itemx show history save +@itemx show history size +@itemx show history expansion +These commands display the state of the @value{GDBN} history parameters. +@code{show history} by itself displays all four states. +@c @end group +@end table + +@table @code +@kindex show commands +@item show commands +Display the last ten commands in the command history. + +@item show commands @var{n} +Print ten commands centered on command number @var{n}. + +@item show commands + +Print ten commands just after the commands last printed. +@end table + +@node Screen Size +@section Screen size +@cindex size of screen +@cindex pauses in output + +Certain commands to @value{GDBN} may produce large amounts of +information output to the screen. To help you read all of it, +@value{GDBN} pauses and asks you for input at the end of each page of +output. Type @key{RET} when you want to continue the output, or @kbd{q} +to discard the remaining output. Also, the screen width setting +determines when to wrap lines of output. Depending on what is being +printed, @value{GDBN} tries to break the line at a readable place, +rather than simply letting it overflow onto the following line. + +Normally @value{GDBN} knows the size of the screen from the termcap data base +together with the value of the @code{TERM} environment variable and the +@code{stty rows} and @code{stty cols} settings. If this is not correct, +you can override it with the @code{set height} and @code{set +width} commands: + +@table @code +@kindex set height +@kindex set width +@kindex show width +@kindex show height +@item set height @var{lpp} +@itemx show height +@itemx set width @var{cpl} +@itemx show width +These @code{set} commands specify a screen height of @var{lpp} lines and +a screen width of @var{cpl} characters. The associated @code{show} +commands display the current settings. + +If you specify a height of zero lines, @value{GDBN} does not pause during +output no matter how long the output is. This is useful if output is to a +file or to an editor buffer. + +Likewise, you can specify @samp{set width 0} to prevent @value{GDBN} +from wrapping its output. +@end table + +@node Numbers +@section Numbers +@cindex number representation +@cindex entering numbers + +You can always enter numbers in octal, decimal, or hexadecimal in @value{GDBN} by +the usual conventions: octal numbers begin with @samp{0}, decimal +numbers end with @samp{.}, and hexadecimal numbers begin with @samp{0x}. +Numbers that begin with none of these are, by default, entered in base +10; likewise, the default display for numbers---when no particular +format is specified---is base 10. You can change the default base for +both input and output with the @code{set radix} command. + +@table @code +@kindex set input-radix +@item set input-radix @var{base} +Set the default base for numeric input. Supported choices +for @var{base} are decimal 8, 10, or 16. @var{base} must itself be +specified either unambiguously or using the current default radix; for +example, any of + +@smallexample +set radix 012 +set radix 10. +set radix 0xa +@end smallexample + +@noindent +sets the base to decimal. On the other hand, @samp{set radix 10} +leaves the radix unchanged no matter what it was. + +@kindex set output-radix +@item set output-radix @var{base} +Set the default base for numeric display. Supported choices +for @var{base} are decimal 8, 10, or 16. @var{base} must itself be +specified either unambiguously or using the current default radix. + +@kindex show input-radix +@item show input-radix +Display the current default base for numeric input. + +@kindex show output-radix +@item show output-radix +Display the current default base for numeric display. +@end table + +@node Messages/Warnings +@section Optional warnings and messages + +By default, @value{GDBN} is silent about its inner workings. If you are running +on a slow machine, you may want to use the @code{set verbose} command. +This makes @value{GDBN} tell you when it does a lengthy internal operation, so +you will not think it has crashed. + +Currently, the messages controlled by @code{set verbose} are those +which announce that the symbol table for a source file is being read; +see @code{symbol-file} in @ref{Files, ,Commands to specify files}. + +@table @code +@kindex set verbose +@item set verbose on +Enables @value{GDBN} output of certain informational messages. + +@item set verbose off +Disables @value{GDBN} output of certain informational messages. + +@kindex show verbose +@item show verbose +Displays whether @code{set verbose} is on or off. +@end table + +By default, if @value{GDBN} encounters bugs in the symbol table of an object +file, it is silent; but if you are debugging a compiler, you may find +this information useful (@pxref{Symbol Errors, ,Errors reading symbol files}). + +@table @code +@kindex set complaints +@item set complaints @var{limit} +Permits @value{GDBN} to output @var{limit} complaints about each type of unusual +symbols before becoming silent about the problem. Set @var{limit} to +zero to suppress all complaints; set it to a large number to prevent +complaints from being suppressed. + +@kindex show complaints +@item show complaints +Displays how many symbol complaints @value{GDBN} is permitted to produce. +@end table + +By default, @value{GDBN} is cautious, and asks what sometimes seems to be a +lot of stupid questions to confirm certain commands. For example, if +you try to run a program which is already running: + +@example +(@value{GDBP}) run +The program being debugged has been started already. +Start it from the beginning? (y or n) +@end example + +If you are willing to unflinchingly face the consequences of your own +commands, you can disable this ``feature'': + +@table @code +@kindex set confirm +@cindex flinching +@cindex confirmation +@cindex stupid questions +@item set confirm off +Disables confirmation requests. + +@item set confirm on +Enables confirmation requests (the default). + +@kindex show confirm +@item show confirm +Displays state of confirmation requests. +@end table + +@node Sequences +@chapter Canned Sequences of Commands + +Aside from breakpoint commands (@pxref{Break Commands, ,Breakpoint +command lists}), @value{GDBN} provides two ways to store sequences of commands +for execution as a unit: user-defined commands and command files. + +@menu +* Define:: User-defined commands +* Hooks:: User-defined command hooks +* Command Files:: Command files +* Output:: Commands for controlled output +@end menu + +@node Define +@section User-defined commands + +@cindex user-defined command +A @dfn{user-defined command} is a sequence of @value{GDBN} commands to which +you assign a new name as a command. This is done with the @code{define} +command. User commands may accept up to 10 arguments separated by whitespace. +Arguments are accessed within the user command via @var{$arg0@dots{}$arg9}. +A trivial example: + +@smallexample +define adder + print $arg0 + $arg1 + $arg2 +@end smallexample + +@noindent To execute the command use: + +@smallexample +adder 1 2 3 +@end smallexample + +@noindent This defines the command @code{adder}, which prints the sum of +its three arguments. Note the arguments are text substitutions, so they may +reference variables, use complex expressions, or even perform inferior +functions calls. + +@table @code +@kindex define +@item define @var{commandname} +Define a command named @var{commandname}. If there is already a command +by that name, you are asked to confirm that you want to redefine it. + +The definition of the command is made up of other @value{GDBN} command lines, +which are given following the @code{define} command. The end of these +commands is marked by a line containing @code{end}. + +@kindex if +@kindex else +@item if +Takes a single argument, which is an expression to evaluate. +It is followed by a series of commands that are executed +only if the expression is true (nonzero). +There can then optionally be a line @code{else}, followed +by a series of commands that are only executed if the expression +was false. The end of the list is marked by a line containing @code{end}. + +@kindex while +@item while +The syntax is similar to @code{if}: the command takes a single argument, +which is an expression to evaluate, and must be followed by the commands to +execute, one per line, terminated by an @code{end}. +The commands are executed repeatedly as long as the expression +evaluates to true. + +@kindex document +@item document @var{commandname} +Document the user-defined command @var{commandname}, so that it can be +accessed by @code{help}. The command @var{commandname} must already be +defined. This command reads lines of documentation just as @code{define} +reads the lines of the command definition, ending with @code{end}. +After the @code{document} command is finished, @code{help} on command +@var{commandname} displays the documentation you have written. + +You may use the @code{document} command again to change the +documentation of a command. Redefining the command with @code{define} +does not change the documentation. + +@kindex help user-defined +@item help user-defined +List all user-defined commands, with the first line of the documentation +(if any) for each. + +@kindex show user +@item show user +@itemx show user @var{commandname} +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. +@end table + +When user-defined commands are executed, the +commands of the definition are not printed. An error in any command +stops execution of the user-defined command. + +If used interactively, commands that would ask for confirmation proceed +without asking when used inside a user-defined command. Many @value{GDBN} +commands that normally print messages to say what they are doing omit the +messages when used in a user-defined command. + +@node Hooks +@section User-defined command hooks +@cindex command files + +You may define @emph{hooks}, which are a special kind of user-defined +command. Whenever you run the command @samp{foo}, if the user-defined +command @samp{hook-foo} exists, it is executed (with no arguments) +before that command. + +In addition, a pseudo-command, @samp{stop} exists. Defining +(@samp{hook-stop}) makes the associated commands execute every time +execution stops in your program: before breakpoint commands are run, +displays are printed, or the stack frame is printed. + +@ifclear BARETARGET +For example, to ignore @code{SIGALRM} signals while +single-stepping, but treat them normally during normal execution, +you could define: + +@example +define hook-stop +handle SIGALRM nopass +end + +define hook-run +handle SIGALRM pass +end + +define hook-continue +handle SIGLARM pass +end +@end example +@end ifclear + +You can define a hook for any single-word command in @value{GDBN}, but +not for command aliases; you should define a hook for the basic command +name, e.g. @code{backtrace} rather than @code{bt}. +@c FIXME! So how does Joe User discover whether a command is an alias +@c or not? +If an error occurs during the execution of your hook, execution of +@value{GDBN} commands stops and @value{GDBN} issues a prompt +(before the command that you actually typed had a chance to run). + +If you try to define a hook which does not match any known command, you +get a warning from the @code{define} command. + +@node Command Files +@section Command files + +@cindex command files +A command file for @value{GDBN} is a file of lines that are @value{GDBN} +commands. Comments (lines starting with @kbd{#}) may also be included. +An empty line in a command file does nothing; it does not mean to repeat +the last command, as it would from the terminal. + +@cindex init file +@cindex @file{@value{GDBINIT}} +When you start @value{GDBN}, it automatically executes commands from its +@dfn{init files}. These are files named @file{@value{GDBINIT}}. +@value{GDBN} reads the init file (if any) in your home directory, then +processes command line options and operands, and then reads the init +file (if any) in the current working directory. This is so the init +file in your home directory can set options (such as @code{set +complaints}) which affect the processing of the command line options and +operands. The init files are not executed if you use the @samp{-nx} +option; @pxref{Mode Options, ,Choosing modes}. + +@ifset GENERIC +@cindex init file name +On some configurations of @value{GDBN}, the init file is known by a +different name (these are typically environments where a specialized +form of @value{GDBN} may need to coexist with other forms, +hence a different name +for the specialized version's init file). These are the environments +with special init file names: + +@kindex .vxgdbinit +@itemize @bullet +@item +VxWorks (Wind River Systems real-time OS): @samp{.vxgdbinit} + +@kindex .os68gdbinit +@item +OS68K (Enea Data Systems real-time OS): @samp{.os68gdbinit} + +@kindex .esgdbinit +@item +ES-1800 (Ericsson Telecom AB M68000 emulator): @samp{.esgdbinit} +@end itemize +@end ifset + +You can also request the execution of a command file with the +@code{source} command: + +@table @code +@kindex source +@item source @var{filename} +Execute the command file @var{filename}. +@end table + +The lines in a command file are executed sequentially. They are not +printed as they are executed. An error in any command terminates execution +of the command file. + +Commands that would ask for confirmation if used interactively proceed +without asking when used in a command file. Many @value{GDBN} commands that +normally print messages to say what they are doing omit the messages +when called from command files. + +@node Output +@section Commands for controlled output + +During the execution of a command file or a user-defined command, normal +@value{GDBN} output is suppressed; the only output that appears is what is +explicitly printed by the commands in the definition. This section +describes three commands useful for generating exactly the output you +want. + +@table @code +@kindex echo +@item echo @var{text} +@c I do not consider backslash-space a standard C escape sequence +@c because it is not in ANSI. +Print @var{text}. Nonprinting characters can be included in +@var{text} using C escape sequences, such as @samp{\n} to print a +newline. @strong{No newline is printed unless you specify one.} +In addition to the standard C escape sequences, a backslash followed +by a space stands for a space. This is useful for displaying a +string with spaces at the beginning or the end, since leading and +trailing spaces are otherwise trimmed from all arguments. +To print @samp{@w{ }and foo =@w{ }}, use the command +@samp{echo \@w{ }and foo = \@w{ }}. + +A backslash at the end of @var{text} can be used, as in C, to continue +the command onto subsequent lines. For example, + +@example +echo This is some text\n\ +which is continued\n\ +onto several lines.\n +@end example + +produces the same output as + +@example +echo This is some text\n +echo which is continued\n +echo onto several lines.\n +@end example + +@kindex output +@item output @var{expression} +Print the value of @var{expression} and nothing but that value: no +newlines, no @samp{$@var{nn} = }. The value is not entered in the +value history either. @xref{Expressions, ,Expressions}, for more information +on expressions. + +@item output/@var{fmt} @var{expression} +Print the value of @var{expression} in format @var{fmt}. You can use +the same formats as for @code{print}. @xref{Output Formats,,Output +formats}, for more information. + +@kindex printf +@item printf @var{string}, @var{expressions}@dots{} +Print the values of the @var{expressions} under the control of +@var{string}. The @var{expressions} are separated by commas and may be +either numbers or pointers. Their values are printed as specified by +@var{string}, exactly as if your program were to execute the C +subroutine + +@example +printf (@var{string}, @var{expressions}@dots{}); +@end example + +For example, you can print two values in hex like this: + +@smallexample +printf "foo, bar-foo = 0x%x, 0x%x\n", foo, bar-foo +@end smallexample + +The only backslash-escape sequences that you can use in the format +string are the simple ones that consist of backslash followed by a +letter. +@end table + +@ifclear DOSHOST +@node Emacs +@chapter Using @value{GDBN} under @sc{gnu} Emacs + +@cindex Emacs +@cindex @sc{gnu} Emacs +A special interface allows you to use @sc{gnu} Emacs to view (and +edit) the source files for the program you are debugging with +@value{GDBN}. + +To use this interface, use the command @kbd{M-x gdb} in Emacs. Give the +executable file you want to debug as an argument. This command starts +@value{GDBN} as a subprocess of Emacs, with input and output through a newly +created Emacs buffer. + +Using @value{GDBN} under Emacs is just like using @value{GDBN} normally except for two +things: + +@itemize @bullet +@item +All ``terminal'' input and output goes through the Emacs buffer. +@end itemize + +This applies both to @value{GDBN} commands and their output, and to the input +and output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of Emacs' Shell mode are available for interacting +with your program. In particular, you can send signals the usual +way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a +stop. + +@itemize @bullet +@item +@value{GDBN} displays source code through Emacs. +@end itemize + +Each time @value{GDBN} displays a stack frame, Emacs automatically finds the +source file for that frame and puts an arrow (@samp{=>}) at the +left margin of the current line. Emacs uses a separate buffer for +source display, and splits the screen to show both your @value{GDBN} session +and the source. + +Explicit @value{GDBN} @code{list} or search commands still produce output as +usual, but you probably have no reason to use them from Emacs. + +@quotation +@emph{Warning:} If the directory where your program resides is not your +current directory, it can be easy to confuse Emacs about the location of +the source files, in which case the auxiliary display buffer does not +appear to show your source. @value{GDBN} can find programs by searching your +environment's @code{PATH} variable, so the @value{GDBN} input and output +session proceeds normally; but Emacs does not get enough information +back from @value{GDBN} to locate the source files in this situation. To +avoid this problem, either start @value{GDBN} mode from the directory where +your program resides, or specify an absolute file name when prompted for the +@kbd{M-x gdb} argument. + +A similar confusion can result if you use the @value{GDBN} @code{file} command to +switch to debugging a program in some other location, from an existing +@value{GDBN} buffer in Emacs. +@end quotation + +By default, @kbd{M-x gdb} calls the program called @file{gdb}. If +you need to call @value{GDBN} by a different name (for example, if you keep +several configurations around, with different names) you can set the +Emacs variable @code{gdb-command-name}; for example, + +@example +(setq gdb-command-name "mygdb") +@end example + +@noindent +(preceded by @kbd{ESC ESC}, or typed in the @code{*scratch*} buffer, or +in your @file{.emacs} file) makes Emacs call the program named +``@code{mygdb}'' instead. + +In the @value{GDBN} I/O buffer, you can use these special Emacs commands in +addition to the standard Shell mode commands: + +@table @kbd +@item C-h m +Describe the features of Emacs' @value{GDBN} Mode. + +@item M-s +Execute to another source line, like the @value{GDBN} @code{step} command; also +update the display window to show the current file and location. + +@item M-n +Execute to next source line in this function, skipping all function +calls, like the @value{GDBN} @code{next} command. Then update the display window +to show the current file and location. + +@item M-i +Execute one instruction, like the @value{GDBN} @code{stepi} command; update +display window accordingly. + +@item M-x gdb-nexti +Execute to next instruction, using the @value{GDBN} @code{nexti} command; update +display window accordingly. + +@item C-c C-f +Execute until exit from the selected stack frame, like the @value{GDBN} +@code{finish} command. + +@item M-c +Continue execution of your program, like the @value{GDBN} @code{continue} +command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-p}. + +@item M-u +Go up the number of frames indicated by the numeric argument +(@pxref{Arguments, , Numeric Arguments, Emacs, The @sc{gnu} Emacs Manual}), +like the @value{GDBN} @code{up} command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-u}. + +@item M-d +Go down the number of frames indicated by the numeric argument, like the +@value{GDBN} @code{down} command. + +@emph{Warning:} In Emacs v19, this command is @kbd{C-c C-d}. + +@item C-x & +Read the number where the cursor is positioned, and insert it at the end +of the @value{GDBN} I/O buffer. For example, if you wish to disassemble code +around an address that was displayed earlier, type @kbd{disassemble}; +then move the cursor to the address display, and pick up the +argument for @code{disassemble} by typing @kbd{C-x &}. + +You can customize this further by defining elements of the list +@code{gdb-print-command}; once it is defined, you can format or +otherwise process numbers picked up by @kbd{C-x &} before they are +inserted. A numeric argument to @kbd{C-x &} indicates that you +wish special formatting, and also acts as an index to pick an element of the +list. If the list element is a string, the number to be inserted is +formatted using the Emacs function @code{format}; otherwise the number +is passed as an argument to the corresponding list element. +@end table + +In any source file, the Emacs command @kbd{C-x SPC} (@code{gdb-break}) +tells @value{GDBN} to set a breakpoint on the source line point is on. + +If you accidentally delete the source-display buffer, an easy way to get +it back is to type the command @code{f} in the @value{GDBN} buffer, to +request a frame display; when you run under Emacs, this recreates +the source buffer if necessary to show you the context of the current +frame. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that @value{GDBN} +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that @value{GDBN} knows cease +to correspond properly with the code. + +@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 +@end ifclear + +@ifset LUCID +@node Energize +@chapter Using @value{GDBN} with Energize + +@cindex Energize +The Energize Programming System is an integrated development environment +that includes a point-and-click interface to many programming tools. +When you use @value{GDBN} in this environment, you can use the standard +Energize graphical interface to drive @value{GDBN}; you can also, if you +choose, type @value{GDBN} commands as usual in a debugging window. Even if +you use the graphical interface, the debugging window (which uses Emacs, +and resembles the standard @sc{gnu} Emacs interface to +@value{GDBN}) displays the +equivalent commands, so that the history of your debugging session is +properly reflected. + +When Energize starts up a @value{GDBN} session, it uses one of the +command-line options @samp{-energize} or @samp{-cadillac} (``cadillac'' +is the name of the communications protocol used by the Energize system). +This option makes @value{GDBN} run as one of the tools in the Energize Tool +Set: it sends all output to the Energize kernel, and accept input from +it as well. + +See the user manual for the Energize Programming System for +information on how to use the Energize graphical interface and the other +development tools that Energize integrates with @value{GDBN}. + +@end ifset + +@node GDB Bugs +@chapter Reporting Bugs in @value{GDBN} +@cindex bugs in @value{GDBN} +@cindex reporting bugs in @value{GDBN} + +Your bug reports play an essential role in making @value{GDBN} reliable. + +Reporting a bug may help you by bringing a solution to your problem, or it +may not. But in any case the principal function of a bug report is to help +the entire community by making the next version of @value{GDBN} work better. Bug +reports are your contribution to the maintenance of @value{GDBN}. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have you found a bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@cindex fatal signal +@cindex debugger crash +@cindex crash of debugger +@item +If the debugger gets a fatal signal, for any input whatever, that is a +@value{GDBN} bug. Reliable debuggers never crash. + +@cindex error on valid input +@item +If @value{GDBN} produces an error message for valid input, that is a bug. + +@cindex invalid input +@item +If @value{GDBN} does not produce an error message for invalid input, +that is a bug. However, you should note that your idea of +``invalid input'' might be our idea of ``an extension'' or ``support +for traditional practice''. + +@item +If you are an experienced user of debugging tools, your suggestions +for improvement of @value{GDBN} are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to report bugs +@cindex bug reports +@cindex @value{GDBN} bugs, reporting + +A number of companies and individuals offer support for @sc{gnu} products. +If you obtained @value{GDBN} from a support organization, we recommend you +contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs +distribution. + +In any event, we also recommend that you send bug reports for @value{GDBN} to one +of these addresses: + +@example +bug-gdb@@prep.ai.mit.edu +@{ucbvax|mit-eddie|uunet@}!prep.ai.mit.edu!bug-gdb +@end example + +@strong{Do not send bug reports to @samp{info-gdb}, or to +@samp{help-gdb}, or to any newsgroups.} Most users of @value{GDBN} do not want to +receive bug reports. Those that do have arranged to receive @samp{bug-gdb}. + +The mailing list @samp{bug-gdb} has a newsgroup @samp{gnu.gdb.bug} which +serves as a repeater. The mailing list and the newsgroup carry exactly +the same messages. Often people think of posting bug reports to the +newsgroup instead of mailing them. This appears to work, but it has one +problem which can be crucial: a newsgroup posting often lacks a mail +path back to the sender. Thus, if we need to ask for more information, +we may be unable to reach you. For this reason, it is better to send +bug reports to the mailing list. + +As a last resort, send bug reports on paper to: + +@example +@sc{gnu} Debugger Bugs +Free Software Foundation Inc. +59 Temple Place - Suite 330 +Boston, MA 02111-1307 +USA +@end example + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the +problem and assume that some details do not matter. Thus, you might +assume that the name of the variable you use in an example does not matter. +Well, probably it does not, but one cannot be sure. Perhaps the bug is a +stray memory reference which happens to fetch from the location where that +name is stored in memory; perhaps, if the name were different, the contents +of that location would fool the debugger into doing the right thing despite +the bug. Play it safe and give a specific, complete example. That is the +easiest thing for you to do, and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix +the bug if it is new to us. +@c +@c FIX ME!!--What the heck does the following sentence mean, +@c in the context of the one above? +@c +@c It is not as important as what happens if the bug is already known. +@c +Therefore, always write your bug reports on +the assumption that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' Those bug reports are useless, and we urge everyone to +@emph{refuse to respond to them} except to chide the sender to report +bugs properly. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of @value{GDBN}. @value{GDBN} announces it if you start with no +arguments; you can also print it at any time using @code{show version}. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of @value{GDBN}. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile @value{GDBN}---e.g. +``@value{GCC}--2.0''. + +@item +What compiler (and its version) was used to compile the program you +are debugging---e.g. ``@value{GCC}--2.0''. + +@item +The command arguments you gave the compiler to compile your example and +observe the bug. For example, did you use @samp{-O}? To guarantee +you will not omit something important, list them all. A copy of the +Makefile (or the output from make) is sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input script, and all necessary source files, that will +reproduce the bug. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that @value{GDBN} gets a fatal signal, then we will +certainly notice it. But if the bug is incorrect output, we might not +notice unless it is glaringly wrong. You might as well not give us a +chance to make a mistake. + +Even if the problem you experience is a fatal signal, you should still +say so explicitly. Suppose something strange is going on, such as, +your copy of @value{GDBN} is out of synch, or you have encountered a +bug in the C library on your system. (This has happened!) Your copy +might crash and ours would not. If you told us to expect a crash, +then when ours fails to crash, we would know that the bug was not +happening for us. If you had not told us to expect a crash, then we +would not be able to draw any conclusion from our observations. + +@item +If you wish to suggest changes to the @value{GDBN} source, send us context +diffs. If you even discuss something in the @value{GDBN} source, refer to +it by context, not by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, and so on. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with a program as complicated as @value{GDBN} it is very hard to +construct an example that will make the program follow a certain path +through the code. If you do not send us the example, we will not be able +to construct one, so we will not be able to verify that the bug is fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@c The readline documentation is distributed with the readline code +@c and consists of the two following files: +@c rluser.texinfo +@c inc-hist.texi +@c Use -I with makeinfo to point to the appropriate directory, +@c environment var TEXINPUTS with TeX. +@include rluser.texinfo +@include inc-hist.texi + +@ifset NOVEL +@ifset RENAMED +@node Renamed Commands +@appendix Renamed Commands + +The following commands were renamed in @value{GDBN} 4, in order to make the +command set as a whole more consistent and easier to use and remember: + +@kindex add-syms +@kindex delete environment +@kindex info copying +@kindex info convenience +@kindex info directories +@kindex info editing +@kindex info history +@kindex info targets +@kindex info values +@kindex info version +@kindex info warranty +@kindex set addressprint +@kindex set arrayprint +@kindex set prettyprint +@kindex set screen-height +@kindex set screen-width +@kindex set unionprint +@kindex set vtblprint +@kindex set demangle +@kindex set asm-demangle +@kindex set sevenbit-strings +@kindex set array-max +@kindex set caution +@kindex set history write +@kindex show addressprint +@kindex show arrayprint +@kindex show prettyprint +@kindex show screen-height +@kindex show screen-width +@kindex show unionprint +@kindex show vtblprint +@kindex show demangle +@kindex show asm-demangle +@kindex show sevenbit-strings +@kindex show array-max +@kindex show caution +@kindex show history write +@kindex unset + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@example +OLD COMMAND NEW COMMAND +@c TEXI2ROFF-KILL +--------------- ------------------------------- +@c END TEXI2ROFF-KILL +add-syms add-symbol-file +delete environment unset environment +info convenience show convenience +info copying show copying +info directories show directories +info editing show commands +info history show values +info targets help target +info values show values +info version show version +info warranty show warranty +set/show addressprint set/show print address +set/show array-max set/show print elements +set/show arrayprint set/show print array +set/show asm-demangle set/show print asm-demangle +set/show caution set/show confirm +set/show demangle set/show print demangle +set/show history write set/show history save +set/show prettyprint set/show print pretty +set/show screen-height set/show height +set/show screen-width set/show width +set/show sevenbit-strings set/show print sevenbit-strings +set/show unionprint set/show print union +set/show vtblprint set/show print vtbl + +unset [No longer an alias for delete] +@end example +@c TEXI2ROFF-KILL +@end ifinfo + +@tex +\vskip \parskip\vskip \baselineskip +\halign{\tt #\hfil &\qquad#&\tt #\hfil\cr +{\bf Old Command} &&{\bf New Command}\cr +add-syms &&add-symbol-file\cr +delete environment &&unset environment\cr +info convenience &&show convenience\cr +info copying &&show copying\cr +info directories &&show directories \cr +info editing &&show commands\cr +info history &&show values\cr +info targets &&help target\cr +info values &&show values\cr +info version &&show version\cr +info warranty &&show warranty\cr +set{\rm / }show addressprint &&set{\rm / }show print address\cr +set{\rm / }show array-max &&set{\rm / }show print elements\cr +set{\rm / }show arrayprint &&set{\rm / }show print array\cr +set{\rm / }show asm-demangle &&set{\rm / }show print asm-demangle\cr +set{\rm / }show caution &&set{\rm / }show confirm\cr +set{\rm / }show demangle &&set{\rm / }show print demangle\cr +set{\rm / }show history write &&set{\rm / }show history save\cr +set{\rm / }show prettyprint &&set{\rm / }show print pretty\cr +set{\rm / }show screen-height &&set{\rm / }show height\cr +set{\rm / }show screen-width &&set{\rm / }show width\cr +set{\rm / }show sevenbit-strings &&set{\rm / }show print sevenbit-strings\cr +set{\rm / }show unionprint &&set{\rm / }show print union\cr +set{\rm / }show vtblprint &&set{\rm / }show print vtbl\cr +\cr +unset &&\rm(No longer an alias for delete)\cr +} +@end tex +@c END TEXI2ROFF-KILL +@end ifset +@end ifset + +@ifclear PRECONFIGURED +@node Formatting Documentation +@appendix Formatting Documentation + +@cindex @value{GDBN} reference card +@cindex reference card +The @value{GDBN} 4 release includes an already-formatted reference card, ready +for printing with PostScript or Ghostscript, in the @file{gdb} +subdirectory of the main source directory@footnote{In +@file{gdb-@value{GDBVN}/gdb/refcard.ps} of the version @value{GDBVN} +release.}. If you can use PostScript or Ghostscript with your printer, +you can print the reference card immediately with @file{refcard.ps}. + +The release also includes the source for the reference card. You +can format it, using @TeX{}, by typing: + +@example +make refcard.dvi +@end example + +The @value{GDBN} reference card is designed to print in @dfn{landscape} +mode on US ``letter'' size paper; +that is, on a sheet 11 inches wide by 8.5 inches +high. You will need to specify this form of printing as an option to +your @sc{dvi} output program. + +@cindex documentation + +All the documentation for @value{GDBN} comes as part of the machine-readable +distribution. The documentation is written in Texinfo format, which is +a documentation system that uses a single source file to produce both +on-line information and a printed manual. You can use one of the Info +formatting commands to create the on-line version of the documentation +and @TeX{} (or @code{texi2roff}) to typeset the printed version. + +@value{GDBN} includes an already formatted copy of the on-line Info version of +this manual in the @file{gdb} subdirectory. The main Info file is +@file{gdb-@r{version-number}/gdb/gdb.info}, and it refers to +subordinate files matching @samp{gdb.info*} in the same directory. If +necessary, you can print out these files, or read them with any editor; +but they are easier to read using the @code{info} subsystem in @sc{gnu} Emacs +or the standalone @code{info} program, available as part of the @sc{gnu} +Texinfo distribution. + +If you want to format these Info files yourself, you need one of the +Info formatting programs, such as @code{texinfo-format-buffer} or +@code{makeinfo}. + +If you have @code{makeinfo} installed, and are in the top level @value{GDBN} +source directory (@file{gdb-@value{GDBVN}}, in the case of version @value{GDBVN}), you can +make the Info file by typing: + +@example +cd gdb +make gdb.info +@end example + +If you want to typeset and print copies of this manual, you need @TeX{}, +a program to print its @sc{dvi} output files, and @file{texinfo.tex}, the +Texinfo definitions file. + +@TeX{} is a typesetting program; it does not print files directly, but +produces output files called @sc{dvi} files. To print a typeset +document, you need a program to print @sc{dvi} files. If your system +has @TeX{} installed, chances are it has such a program. The precise +command to use depends on your system; @kbd{lpr -d} is common; another +(for PostScript devices) is @kbd{dvips}. The @sc{dvi} print command may +require a file name without any extension or a @samp{.dvi} extension. + +@TeX{} also requires a macro definitions file called +@file{texinfo.tex}. This file tells @TeX{} how to typeset a document +written in Texinfo format. On its own, @TeX{} cannot either read or +typeset a Texinfo file. @file{texinfo.tex} is distributed with GDB +and is located in the @file{gdb-@var{version-number}/texinfo} +directory. + +If you have @TeX{} and a @sc{dvi} printer program installed, you can +typeset and print this manual. First switch to the the @file{gdb} +subdirectory of the main source directory (for example, to +@file{gdb-@value{GDBVN}/gdb}) and then type: + +@example +make gdb.dvi +@end example + +@node Installing GDB +@appendix Installing @value{GDBN} +@cindex configuring @value{GDBN} +@cindex installation + +@value{GDBN} comes with a @code{configure} script that automates the process +of preparing @value{GDBN} for installation; you can then use @code{make} to +build the @code{gdb} program. +@iftex +@c irrelevant in info file; it's as current as the code it lives with. +@footnote{If you have a more recent version of @value{GDBN} than @value{GDBVN}, +look at the @file{README} file in the sources; we may have improved the +installation procedures since publishing this manual.} +@end iftex + +The @value{GDBN} distribution includes all the source code you need for +@value{GDBN} in a single directory, whose name is usually composed by +appending the version number to @samp{gdb}. + +For example, the @value{GDBN} version @value{GDBVN} distribution is in the +@file{gdb-@value{GDBVN}} directory. That directory contains: + +@table @code +@item gdb-@value{GDBVN}/configure @r{(and supporting files)} +script for configuring @value{GDBN} and all its supporting libraries + +@item gdb-@value{GDBVN}/gdb +the source specific to @value{GDBN} itself + +@item gdb-@value{GDBVN}/bfd +source for the Binary File Descriptor library + +@item gdb-@value{GDBVN}/include +@sc{gnu} include files + +@item gdb-@value{GDBVN}/libiberty +source for the @samp{-liberty} free software library + +@item gdb-@value{GDBVN}/opcodes +source for the library of opcode tables and disassemblers + +@item gdb-@value{GDBVN}/readline +source for the @sc{gnu} command-line interface + +@item gdb-@value{GDBVN}/glob +source for the @sc{gnu} filename pattern-matching subroutine + +@item gdb-@value{GDBVN}/mmalloc +source for the @sc{gnu} memory-mapped malloc package +@end table + +The simplest way to configure and build @value{GDBN} is to run @code{configure} +from the @file{gdb-@var{version-number}} source directory, which in +this example is the @file{gdb-@value{GDBVN}} directory. + +First switch to the @file{gdb-@var{version-number}} source directory +if you are not already in it; then run @code{configure}. Pass the +identifier for the platform on which @value{GDBN} will run as an +argument. + +For example: + +@example +cd gdb-@value{GDBVN} +./configure @var{host} +make +@end example + +@noindent +where @var{host} is an identifier such as @samp{sun4} or +@samp{decstation}, that identifies the platform where @value{GDBN} will run. +(You can often leave off @var{host}; @code{configure} tries to guess the +correct value by examining your system.) + +Running @samp{configure @var{host}} and then running @code{make} builds the +@file{bfd}, @file{readline}, @file{mmalloc}, and @file{libiberty} +libraries, then @code{gdb} itself. The configured source files, and the +binaries, are left in the corresponding source directories. + +@need 750 +@code{configure} is a Bourne-shell (@code{/bin/sh}) script; if your +system does not recognize this automatically when you run a different +shell, you may need to run @code{sh} on it explicitly: + +@example +sh configure @var{host} +@end example + +If you run @code{configure} from a directory that contains source +directories for multiple libraries or programs, such as the +@file{gdb-@value{GDBVN}} source directory for version @value{GDBVN}, @code{configure} +creates configuration files for every directory level underneath (unless +you tell it not to, with the @samp{--norecursion} option). + +You can run the @code{configure} script from any of the +subordinate directories in the @value{GDBN} distribution if you only want to +configure that subdirectory, but be sure to specify a path to it. + +For example, with version @value{GDBVN}, type the following to configure only +the @code{bfd} subdirectory: + +@example +@group +cd gdb-@value{GDBVN}/bfd +../configure @var{host} +@end group +@end example + +You can install @code{@value{GDBP}} anywhere; it has no hardwired paths. +However, you should make sure that the shell on your path (named by +the @samp{SHELL} environment variable) is publicly readable. Remember +that @value{GDBN} uses the shell to start your program---some systems refuse to +let @value{GDBN} debug child processes whose programs are not readable. + +@menu +* Separate Objdir:: Compiling @value{GDBN} in another directory +* Config Names:: Specifying names for hosts and targets +* configure Options:: Summary of options for configure +@end menu + +@node Separate Objdir +@section Compiling @value{GDBN} in another directory + +If you want to run @value{GDBN} versions for several host or target machines, +you need a different @code{gdb} compiled for each combination of +host and target. @code{configure} is designed to make this easy by +allowing you to generate each configuration in a separate subdirectory, +rather than in the source directory. If your @code{make} program +handles the @samp{VPATH} feature (@sc{gnu} @code{make} does), running +@code{make} in each of these directories builds the @code{gdb} +program specified there. + +To build @code{gdb} in a separate directory, run @code{configure} +with the @samp{--srcdir} option to specify where to find the source. +(You also need to specify a path to find @code{configure} +itself from your working directory. If the path to @code{configure} +would be the same as the argument to @samp{--srcdir}, you can leave out +the @samp{--srcdir} option; it is assumed.) + +For example, with version @value{GDBVN}, you can build @value{GDBN} in a +separate directory for a Sun 4 like this: + +@example +@group +cd gdb-@value{GDBVN} +mkdir ../gdb-sun4 +cd ../gdb-sun4 +../gdb-@value{GDBVN}/configure sun4 +make +@end group +@end example + +When @code{configure} builds a configuration using a remote source +directory, it creates a tree for the binaries with the same structure +(and using the same names) as the tree under the source directory. In +the example, you'd find the Sun 4 library @file{libiberty.a} in the +directory @file{gdb-sun4/libiberty}, and @value{GDBN} itself in +@file{gdb-sun4/gdb}. + +One popular reason to build several @value{GDBN} configurations in separate +directories is to configure @value{GDBN} for cross-compiling (where +@value{GDBN} runs on one machine---the @dfn{host}---while debugging +programs that run on another machine---the @dfn{target}). +You specify a cross-debugging target by +giving the @samp{--target=@var{target}} option to @code{configure}. + +When you run @code{make} to build a program or library, you must run +it in a configured directory---whatever directory you were in when you +called @code{configure} (or one of its subdirectories). + +The @code{Makefile} that @code{configure} generates in each source +directory also runs recursively. If you type @code{make} in a source +directory such as @file{gdb-@value{GDBVN}} (or in a separate configured +directory configured with @samp{--srcdir=@var{dirname}/gdb-@value{GDBVN}}), you +will build all the required libraries, and then build GDB. + +When you have multiple hosts or targets configured in separate +directories, you can run @code{make} on them in parallel (for example, +if they are NFS-mounted on each of the hosts); they will not interfere +with each other. + +@node Config Names +@section Specifying names for hosts and targets + +The specifications used for hosts and targets in the @code{configure} +script are based on a three-part naming scheme, but some short predefined +aliases are also supported. The full naming scheme encodes three pieces +of information in the following pattern: + +@example +@var{architecture}-@var{vendor}-@var{os} +@end example + +For example, you can use the alias @code{sun4} as a @var{host} argument, +or as the value for @var{target} in a @code{--target=@var{target}} +option. The equivalent full name is @samp{sparc-sun-sunos4}. + +The @code{configure} script accompanying @value{GDBN} does not provide +any query facility to list all supported host and target names or +aliases. @code{configure} calls the Bourne shell script +@code{config.sub} to map abbreviations to full names; you can read the +script, if you wish, or you can use it to test your guesses on +abbreviations---for example: + +@smallexample +% sh config.sub sun4 +sparc-sun-sunos4.1.1 +% sh config.sub sun3 +m68k-sun-sunos4.1.1 +% sh config.sub decstation +mips-dec-ultrix4.2 +% sh config.sub hp300bsd +m68k-hp-bsd +% sh config.sub i386v +i386-unknown-sysv +% sh config.sub i786v +Invalid configuration `i786v': machine `i786v' not recognized +@end smallexample + +@noindent +@code{config.sub} is also distributed in the @value{GDBN} source +directory (@file{gdb-@value{GDBVN}}, for version @value{GDBVN}). + +@node configure Options +@section @code{configure} options + +Here is a summary of the @code{configure} options and arguments that +are most often useful for building @value{GDBN}. @code{configure} also has +several other options not listed here. @inforef{What Configure +Does,,configure.info}, for a full explanation of @code{configure}. + +@example +configure @r{[}--help@r{]} + @r{[}--prefix=@var{dir}@r{]} + @r{[}--srcdir=@var{dirname}@r{]} + @r{[}--norecursion@r{]} @r{[}--rm@r{]} + @r{[}--target=@var{target}@r{]} @var{host} +@end example + +@noindent +You may introduce options with a single @samp{-} rather than +@samp{--} if you prefer; but you may abbreviate option names if you use +@samp{--}. + +@table @code +@item --help +Display a quick summary of how to invoke @code{configure}. + +@item -prefix=@var{dir} +Configure the source to install programs and files under directory +@file{@var{dir}}. + +@c avoid splitting the warning from the explanation: +@need 2000 +@item --srcdir=@var{dirname} +@strong{Warning: using this option requires @sc{gnu} @code{make}, or another +@code{make} that implements the @code{VPATH} feature.}@* +Use this option to make configurations in directories separate from the +@value{GDBN} source directories. Among other things, you can use this to +build (or maintain) several configurations simultaneously, in separate +directories. @code{configure} writes configuration specific files in +the current directory, but arranges for them to use the source in the +directory @var{dirname}. @code{configure} creates directories under +the working directory in parallel to the source directories below +@var{dirname}. + +@item --norecursion +Configure only the directory level where @code{configure} is executed; do not +propagate configuration to subdirectories. + +@item --rm +@emph{Remove} files otherwise built during configuration. + +@c This does not work (yet if ever). FIXME. +@c @item --parse=@var{lang} @dots{} +@c Configure the @value{GDBN} expression parser to parse the listed languages. +@c @samp{all} configures @value{GDBN} for all supported languages. To get a +@c list of all supported languages, omit the argument. Without this +@c option, @value{GDBN} is configured to parse all supported languages. + +@item --target=@var{target} +Configure @value{GDBN} for cross-debugging programs running on the specified +@var{target}. Without this option, @value{GDBN} is configured to debug +programs that run on the same machine (@var{host}) as @value{GDBN} itself. + +There is no convenient way to generate a list of all available targets. + +@item @var{host} @dots{} +Configure @value{GDBN} to run on the specified @var{host}. + +There is no convenient way to generate a list of all available hosts. +@end table + +@noindent +@code{configure} accepts other options, for compatibility with +configuring other @sc{gnu} tools recursively; but these are the only +options that affect @value{GDBN} or its supporting libraries. +@end ifclear + +@node Index +@unnumbered Index + +@printindex cp + +@tex +% 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} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 1991. +@end tex + +@contents +@bye diff --git a/contrib/gdb/gdb/doc/gdbint.texinfo b/contrib/gdb/gdb/doc/gdbint.texinfo new file mode 100644 index 000000000000..c7f43908e3c8 --- /dev/null +++ b/contrib/gdb/gdb/doc/gdbint.texinfo @@ -0,0 +1,2543 @@ +\input texinfo +@setfilename gdbint.info +@c $Id: gdbint.texinfo,v 1.84 1996/01/11 20:08:19 fnf Exp $ + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Gdb-Internals: (gdbint). The GNU debugger's internals. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the internals of the GNU debugger GDB. + +Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. +Contributed by Cygnus Support. Written by John Gilmore. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy or distribute modified versions of this +manual under the terms of the GPL (for which purpose this text may be +regarded as a program in the language TeX). +@end ifinfo + +@setchapternewpage off +@settitle GDB Internals +@titlepage +@title{Working in GDB} +@subtitle{A guide to the internals of the GNU debugger} +@author John Gilmore +@author Cygnus Support +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.84 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@end titlepage + +@node Top +@c Perhaps this should be the title of the document (but only for info, +@c not for TeX). Existing GNU manuals seem inconsistent on this point. +@top Scope of this Document + +This document documents the internals of the GNU debugger, GDB. It is +intended to document aspects of GDB which apply across many different +parts of GDB (for example, @pxref{Coding Style}), or which are global +aspects of design (for example, what are the major modules and which +files document them in detail?). Information which pertains to specific +data structures, functions, variables, etc., should be put in comments +in the source code, not here. It is more likely to get noticed and kept +up to date there. Some of the information in this document should +probably be moved into comments. + +@menu +* README:: The README File +* Getting Started:: Getting started working on GDB +* Debugging GDB:: Debugging GDB with itself +* New Architectures:: Defining a New Host or Target Architecture +* Config:: Adding a New Configuration +* Host:: Adding a New Host +* Native:: Adding a New Native Configuration +* Target:: Adding a New Target +* Languages:: Defining New Source Languages +* Releases:: Configuring GDB for Release +* Partial Symbol Tables:: How GDB reads symbols quickly at startup +* Types:: How GDB keeps track of types +* BFD support for GDB:: How BFD and GDB interface +* Symbol Reading:: Defining New Symbol Readers +* Cleanups:: Cleanups +* Wrapping:: Wrapping Output Lines +* Frames:: Keeping track of function calls +* Remote Stubs:: Code that runs in targets and talks to GDB +* Longjmp Support:: Stepping through longjmp's in the target +* Coding Style:: Strunk and White for GDB maintainers +* Clean Design:: Frank Lloyd Wright for GDB maintainers +* Submitting Patches:: How to get your changes into GDB releases +* Host Conditionals:: What features exist in the host +* Target Conditionals:: What features exist in the target +* Native Conditionals:: Conditionals for when host and target are same +* Obsolete Conditionals:: Conditionals that don't exist any more +* XCOFF:: The Object file format used on IBM's RS/6000 +@end menu + +@node README +@chapter The @file{README} File + +Check the @file{README} file, it often has useful information that does not +appear anywhere else in the directory. + +@node Getting Started +@chapter Getting Started Working on GDB + +GDB is a large and complicated program, and if you first starting to +work on it, it can be hard to know where to start. Fortunately, if you +know how to go about it, there are ways to figure out what is going on: + +@itemize @bullet +@item +This manual, the GDB Internals manual, has information which applies +generally to many parts of GDB. + +@item +Information about particular functions or data structures are located in +comments with those functions or data structures. If you run across a +function or a global variable which does not have a comment correctly +explaining what is does, this can be thought of as a bug in GDB; feel +free to submit a bug report, with a suggested comment if you can figure +out what the comment should say (@pxref{Submitting Patches}). If you +find a comment which is actually wrong, be especially sure to report that. + +Comments explaining the function of macros defined in host, target, or +native dependent files can be in several places. Sometimes they are +repeated every place the macro is defined. Sometimes they are where the +macro is used. Sometimes there is a header file which supplies a +default definition of the macro, and the comment is there. This manual +also has a list of macros (@pxref{Host Conditionals}, @pxref{Target +Conditionals}, @pxref{Native Conditionals}, and @pxref{Obsolete +Conditionals}) with some documentation. + +@item +Start with the header files. Once you some idea of how GDB's internal +symbol tables are stored (see @file{symtab.h}, @file{gdbtypes.h}), you +will find it much easier to understand the code which uses and creates +those symbol tables. + +@item +You may wish to process the information you are getting somehow, to +enhance your understanding of it. Summarize it, translate it to another +language, add some (perhaps trivial or non-useful) feature to GDB, use +the code to predict what a test case would do and write the test case +and verify your prediction, etc. If you are reading code and your eyes +are starting to glaze over, this is a sign you need to use a more active +approach. + +@item +Once you have a part of GDB to start with, you can find more +specifically the part you are looking for by stepping through each +function with the @code{next} command. Do not use @code{step} or you +will quickly get distracted; when the function you are stepping through +calls another function try only to get a big-picture understanding +(perhaps using the comment at the beginning of the function being +called) of what it does. This way you can identify which of the +functions being called by the function you are stepping through is the +one which you are interested in. You may need to examine the data +structures generated at each stage, with reference to the comments in +the header files explaining what the data structures are supposed to +look like. + +Of course, this same technique can be used if you are just reading the +code, rather than actually stepping through it. The same general +principle applies---when the code you are looking at calls something +else, just try to understand generally what the code being called does, +rather than worrying about all its details. + +@item +A good place to start when tracking down some particular area is with a +command which invokes that feature. Suppose you want to know how +single-stepping works. As a GDB user, you know that the @code{step} +command invokes single-stepping. The command is invoked via command +tables (see @file{command.h}); by convention the function which actually +performs the command is formed by taking the name of the command and +adding @samp{_command}, or in the case of an @code{info} subcommand, +@samp{_info}. For example, the @code{step} command invokes the +@code{step_command} function and the @code{info display} command invokes +@code{display_info}. When this convention is not followed, you might +have to use @code{grep} or @kbd{M-x tags-search} in emacs, or run GDB on +itself and set a breakpoint in @code{execute_command}. + +@item +If all of the above fail, it may be appropriate to ask for information +on @code{bug-gdb}. But @emph{never} post a generic question like ``I was +wondering if anyone could give me some tips about understanding +GDB''---if we had some magic secret we would put it in this manual. +Suggestions for improving the manual are always welcome, of course. +@end itemize + +Good luck! + +@node Debugging GDB +@chapter Debugging GDB with itself +If GDB is limping on your machine, this is the preferred way to get it +fully functional. Be warned that in some ancient Unix systems, like +Ultrix 4.2, a program can't be running in one process while it is being +debugged in another. Rather than typing the command @code{@w{./gdb +./gdb}}, which works on Suns and such, you can copy @file{gdb} to +@file{gdb2} and then type @code{@w{./gdb ./gdb2}}. + +When you run GDB in the GDB 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 GDB being debugged by gdb, will pop you back up to the top level +gdb. See @file{.gdbinit} 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 +routines for your local machine where they will be accessed first by +@kbd{M-.} + +Also, make sure that you've either compiled GDB with your local cc, or +have run @code{fixincludes} if you are compiling with gcc. + +@node New Architectures +@chapter Defining a New Host or Target Architecture + +When building support for a new host and/or target, much of the work you +need to do is handled by specifying configuration files; +@pxref{Config,,Adding a New Configuration}. Further work can be +divided into ``host-dependent'' (@pxref{Host,,Adding a New Host}) and +``target-dependent'' (@pxref{Target,,Adding a New Target}). The +following discussion is meant to explain the difference between hosts +and targets. + +@heading What is considered ``host-dependent'' versus ``target-dependent''? + +@dfn{Host} refers to attributes of the system where GDB runs. +@dfn{Target} refers to the system where the program being debugged +executes. In most cases they are the same machine, in which case +a third type of @dfn{Native} attributes come into play. + +Defines and include files needed to build on the host are host support. +Examples are tty support, system defined types, host byte order, host +float format. + +Defines and information needed to handle the target format are target +dependent. Examples are the stack frame format, instruction set, +breakpoint instruction, registers, and how to set up and tear down the stack +to call a function. + +Information that is only needed when the host and target are the same, +is native dependent. One example is Unix child process support; if the +host and target are not the same, doing a fork to start the target +process is a bad idea. The various macros needed for finding the +registers in the @code{upage}, running @code{ptrace}, and such are all in the +native-dependent files. + +Another example of native-dependent code is support for features +that are really part of the target environment, but which require +@code{#include} files that are only available on the host system. +Core file handling and @code{setjmp} handling are two common cases. + +When you want to make GDB work ``native'' on a particular +machine, you have to include all three kinds of information. + +The dependent information in GDB is organized into files by naming +conventions. + +Host-Dependent Files +@table @file +@item config/*/*.mh +Sets Makefile parameters +@item config/*/xm-*.h +Global #include's and #define's and definitions +@item *-xdep.c +Global variables and functions +@end table + +Native-Dependent Files +@table @file +@item config/*/*.mh +Sets Makefile parameters (for @emph{both} host and native) +@item config/*/nm-*.h +#include's and #define's and definitions. This file +is only included by the small number of modules that need it, +so beware of doing feature-test #define's from its macros. +@item *-nat.c +global variables and functions +@end table + +Target-Dependent Files +@table @file +@item config/*/*.mt +Sets Makefile parameters +@item config/*/tm-*.h +Global #include's and #define's and definitions +@item *-tdep.c +Global variables and functions +@end table + +At this writing, most supported hosts have had their host and native +dependencies sorted out properly. There are a few stragglers, which +can be recognized by the absence of NATDEPFILES lines in their +@file{config/*/*.mh}. + +@node Config +@chapter Adding a New Configuration + +Most of the work in making GDB compile on a new machine is in specifying +the configuration of the machine. This is done in a dizzying variety of +header files and configuration scripts, which we hope to make more +sensible soon. Let's say your new host is called an @var{xxx} (e.g. +@samp{sun4}), and its full three-part configuration name is +@code{@var{xarch}-@var{xvend}-@var{xos}} (e.g. @samp{sparc-sun-sunos4}). In +particular: + +In the top level directory, edit @file{config.sub} and add @var{xarch}, +@var{xvend}, and @var{xos} to the lists of supported architectures, +vendors, and operating systems near the bottom of the file. Also, add +@var{xxx} as an alias that maps to +@code{@var{xarch}-@var{xvend}-@var{xos}}. You can test your changes by +running + +@example +./config.sub @var{xxx} +@end example +@noindent +and +@example +./config.sub @code{@var{xarch}-@var{xvend}-@var{xos}} +@end example +@noindent +which should both respond with @code{@var{xarch}-@var{xvend}-@var{xos}} +and no error messages. + +Now, go to the @file{bfd} directory and +create a new file @file{bfd/hosts/h-@var{xxx}.h}. Examine the +other @file{h-*.h} files as templates, and create one that brings in the +right include files for your system, and defines any host-specific +macros needed by BFD, the Binutils, GNU LD, or the Opcodes directories. +(They all share the bfd @file{hosts} directory and the @file{configure.host} +file.) + +Then edit @file{bfd/configure.host}. Add a line to recognize your +@code{@var{xarch}-@var{xvend}-@var{xos}} configuration, and set +@code{my_host} to @var{xxx} when you recognize it. This will cause your +file @file{h-@var{xxx}.h} to be linked to @file{sysdep.h} at configuration +time. When creating the line that recognizes your configuration, +only match the fields that you really need to match; e.g. don't +match the architecture or manufacturer if the OS is sufficient +to distinguish the configuration that your @file{h-@var{xxx}.h} file supports. +Don't match the manufacturer name unless you really need to. +This should make future ports easier. + +Also, if this host requires any changes to the Makefile, create a file +@file{bfd/config/@var{xxx}.mh}, which includes the required lines. + +It's possible that the @file{libiberty} and @file{readline} directories +won't need any changes for your configuration, but if they do, you can +change the @file{configure.in} file there to recognize your system and +map to an @file{mh-@var{xxx}} file. Then add @file{mh-@var{xxx}} +to the @file{config/} subdirectory, to set any makefile variables you +need. The only current options in there are things like @samp{-DSYSV}. +(This @file{mh-@var{xxx}} naming convention differs from elsewhere +in GDB, by historical accident. It should be cleaned up so that all +such files are called @file{@var{xxx}.mh}.) + +Aha! Now to configure GDB itself! Edit +@file{gdb/configure.in} to recognize your system and set @code{gdb_host} +to @var{xxx}, and (unless your desired target is already available) also +set @code{gdb_target} to something appropriate (for instance, +@var{xxx}). To handle new hosts, modify the segment after the comment +@samp{# per-host}; to handle new targets, modify after @samp{# +per-target}. +@c Would it be simpler to just use different per-host and per-target +@c *scripts*, and call them from {configure} ? + +Finally, you'll need to specify and define GDB's host-, native-, and +target-dependent @file{.h} and @file{.c} files used for your +configuration; the next two chapters discuss those. + + +@node Host +@chapter Adding a New Host + +Once you have specified a new configuration for your host +(@pxref{Config,,Adding a New Configuration}), there are three remaining +pieces to making GDB work on a new machine. First, you have to make it +host on the new machine (compile there, handle that machine's terminals +properly, etc). If you will be cross-debugging to some other kind of +system that's already supported, you are done. + +If you want to use GDB to debug programs that run on the new machine, +you have to get it to understand the machine's object files, symbol +files, and interfaces to processes; @pxref{Target,,Adding a New Target} +and @pxref{Native,,Adding a New Native Configuration} + +Several files control GDB's configuration for host systems: + +@table @file +@item gdb/config/@var{arch}/@var{xxx}.mh +Specifies Makefile fragments needed when hosting on machine @var{xxx}. +In particular, this lists the required machine-dependent object files, +by defining @samp{XDEPFILES=@dots{}}. Also +specifies the header file which describes host @var{xxx}, by defining +@code{XM_FILE= xm-@var{xxx}.h}. You can also define @code{CC}, +@code{REGEX} and @code{REGEX1}, @code{SYSV_DEFINE}, @code{XM_CFLAGS}, +@code{XM_ADD_FILES}, @code{XM_CLIBS}, @code{XM_CDEPS}, +etc.; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/xm-@var{xxx}.h +(@file{xm.h} is a link to this file, created by configure). +Contains C macro definitions describing the host system environment, +such as byte order, host C compiler and library, ptrace support, +and core file structure. Crib from existing @file{xm-*.h} files +to create a new one. + +@item gdb/@var{xxx}-xdep.c +Contains any miscellaneous C code required for this machine +as a host. On many machines it doesn't exist at all. If it does +exist, put @file{@var{xxx}-xdep.o} into the @code{XDEPFILES} line +in @file{gdb/config/mh-@var{xxx}}. +@end table + +@subheading Generic Host Support Files + +There are some ``generic'' versions of routines that can be used by +various systems. These can be customized in various ways by macros +defined in your @file{xm-@var{xxx}.h} file. If these routines work for +the @var{xxx} host, you can just include the generic file's name (with +@samp{.o}, not @samp{.c}) in @code{XDEPFILES}. + +Otherwise, if your machine needs custom support routines, you will need +to write routines that perform the same functions as the generic file. +Put them into @code{@var{xxx}-xdep.c}, and put @code{@var{xxx}-xdep.o} +into @code{XDEPFILES}. + +@table @file +@item ser-bsd.c +This contains serial line support for Berkeley-derived Unix systems. + +@item ser-go32.c +This contains serial line support for 32-bit programs running under DOS +using the GO32 execution environment. + +@item ser-termios.c +This contains serial line support for System V-derived Unix systems. +@end table + +Now, you are now ready to try configuring GDB to compile using your system +as its host. From the top level (above @file{bfd}, @file{gdb}, etc), do: + +@example +./configure @var{xxx} --target=vxworks960 +@end example + +This will configure your system to cross-compile for VxWorks on +the Intel 960, which is probably not what you really want, but it's +a test case that works at this stage. (You haven't set up to be +able to debug programs that run @emph{on} @var{xxx} yet.) + +If this succeeds, you can try building it all with: + +@example +make +@end example + +Repeat until the program configures, compiles, links, and runs. +When run, it won't be able to do much (unless you have a VxWorks/960 +board on your network) but you will know that the host support is +pretty well done. + +Good luck! Comments and suggestions about this section are particularly +welcome; send them to @samp{bug-gdb@@prep.ai.mit.edu}. + +@node Native +@chapter Adding a New Native Configuration + +If you are making GDB run native on the @var{xxx} machine, you have +plenty more work to do. Several files control GDB's configuration for +native support: + +@table @file +@item gdb/config/@var{xarch}/@var{xxx}.mh +Specifies Makefile fragments needed when hosting @emph{or native} +on machine @var{xxx}. +In particular, this lists the required native-dependent object files, +by defining @samp{NATDEPFILES=@dots{}}. Also +specifies the header file which describes native support on @var{xxx}, +by defining @samp{NAT_FILE= nm-@var{xxx}.h}. +You can also define @samp{NAT_CFLAGS}, +@samp{NAT_ADD_FILES}, @samp{NAT_CLIBS}, @samp{NAT_CDEPS}, +etc.; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/nm-@var{xxx}.h +(@file{nm.h} is a link to this file, created by configure). +Contains C macro definitions describing the native system environment, +such as child process control and core file support. +Crib from existing @file{nm-*.h} files to create a new one. + +@item gdb/@var{xxx}-nat.c +Contains any miscellaneous C code required for this native support +of this machine. On some machines it doesn't exist at all. +@end table + +@subheading Generic Native Support Files + +There are some ``generic'' versions of routines that can be used by +various systems. These can be customized in various ways by macros +defined in your @file{nm-@var{xxx}.h} file. If these routines work for +the @var{xxx} host, you can just include the generic file's name (with +@samp{.o}, not @samp{.c}) in @code{NATDEPFILES}. + +Otherwise, if your machine needs custom support routines, you will need +to write routines that perform the same functions as the generic file. +Put them into @code{@var{xxx}-nat.c}, and put @code{@var{xxx}-nat.o} +into @code{NATDEPFILES}. + +@table @file + +@item inftarg.c +This contains the @emph{target_ops vector} that supports Unix child +processes on systems which use ptrace and wait to control the child. + +@item procfs.c +This contains the @emph{target_ops vector} that supports Unix child +processes on systems which use /proc to control the child. + +@item fork-child.c +This does the low-level grunge that uses Unix system calls +to do a "fork and exec" to start up a child process. + +@item infptrace.c +This is the low level interface to inferior processes for systems +using the Unix @code{ptrace} call in a vanilla way. + +@item core-aout.c::fetch_core_registers() +Support for reading registers out of a core file. This routine calls +@code{register_addr()}, see below. +Now that BFD is used to read core files, virtually all machines should +use @code{core-aout.c}, and should just provide @code{fetch_core_registers} in +@code{@var{xxx}-nat.c} (or @code{REGISTER_U_ADDR} in @code{nm-@var{xxx}.h}). + +@item core-aout.c::register_addr() +If your @code{nm-@var{xxx}.h} file defines the macro +@code{REGISTER_U_ADDR(addr, blockend, regno)}, it should be defined to +set @code{addr} to the offset within the @samp{user} +struct of GDB register number @code{regno}. @code{blockend} is the +offset within the ``upage'' of @code{u.u_ar0}. +If @code{REGISTER_U_ADDR} is defined, +@file{core-aout.c} will define the @code{register_addr()} function and use +the macro in it. If you do not define @code{REGISTER_U_ADDR}, but you +are using the standard @code{fetch_core_registers()}, you will need to +define your own version of @code{register_addr()}, put it into your +@code{@var{xxx}-nat.c} file, and be sure @code{@var{xxx}-nat.o} is in +the @code{NATDEPFILES} list. If you have your own +@code{fetch_core_registers()}, you may not need a separate +@code{register_addr()}. Many custom @code{fetch_core_registers()} +implementations simply locate the registers themselves.@refill +@end table + +When making GDB run native on a new operating system, +to make it possible to debug +core files, you will need to either write specific code for parsing your +OS's core files, or customize @file{bfd/trad-core.c}. First, use +whatever @code{#include} files your machine uses to define the struct of +registers that is accessible (possibly in the u-area) in a core file +(rather than @file{machine/reg.h}), and an include file that defines whatever +header exists on a core file (e.g. the u-area or a @samp{struct core}). Then +modify @code{trad_unix_core_file_p()} to use these values to set up the +section information for the data segment, stack segment, any other +segments in the core file (perhaps shared library contents or control +information), ``registers'' segment, and if there are two discontiguous +sets of registers (e.g. integer and float), the ``reg2'' segment. This +section information basically delimits areas in the core file in a +standard way, which the section-reading routines in BFD know how to seek +around in. + +Then back in GDB, you need a matching routine called +@code{fetch_core_registers()}. If you can use the generic one, it's in +@file{core-aout.c}; if not, it's in your @file{@var{xxx}-nat.c} file. +It will be passed a char pointer to the entire ``registers'' segment, +its length, and a zero; or a char pointer to the entire ``regs2'' +segment, its length, and a 2. The routine should suck out the supplied +register values and install them into GDB's ``registers'' array. +(@xref{New Architectures,,Defining a New Host or Target Architecture}, +for more info about this.) + +If your system uses @file{/proc} to control processes, and uses ELF +format core files, then you may be able to use the same routines +for reading the registers out of processes and out of core files. + +@node Target +@chapter Adding a New Target + +For a new target called @var{ttt}, first specify the configuration as +described in @ref{Config,,Adding a New Configuration}. If your new +target is the same as your new host, you've probably already done that. + +A variety of files specify attributes of the GDB target environment: + +@table @file +@item gdb/config/@var{arch}/@var{ttt}.mt +Contains a Makefile fragment specific to this target. +Specifies what object files are needed for target @var{ttt}, by +defining @samp{TDEPFILES=@dots{}}. +Also specifies the header file which describes @var{ttt}, by defining +@samp{TM_FILE= tm-@var{ttt}.h}. You can also define @samp{TM_CFLAGS}, +@samp{TM_CLIBS}, @samp{TM_CDEPS}, +and other Makefile variables here; see @file{Makefile.in}. + +@item gdb/config/@var{arch}/tm-@var{ttt}.h +(@file{tm.h} is a link to this file, created by configure). +Contains macro definitions about the target machine's +registers, stack frame format and instructions. +Crib from existing @file{tm-*.h} files when building a new one. + +@item gdb/@var{ttt}-tdep.c +Contains any miscellaneous code required for this target machine. +On some machines it doesn't exist at all. Sometimes the macros +in @file{tm-@var{ttt}.h} become very complicated, so they are +implemented as functions here instead, and the macro is simply +defined to call the function. + +@item gdb/exec.c +Defines functions for accessing files that are +executable on the target system. These functions open and examine an +exec file, extract data from one, write data to one, print information +about one, etc. Now that executable files are handled with BFD, every +target should be able to use the generic exec.c rather than its +own custom code. + +@item gdb/@var{arch}-pinsn.c +Prints (disassembles) the target machine's instructions. +This file is usually shared with other target machines which use the +same processor, which is why it is @file{@var{arch}-pinsn.c} rather +than @file{@var{ttt}-pinsn.c}. + +@item gdb/@var{arch}-opcode.h +Contains some large initialized +data structures describing the target machine's instructions. +This is a bit strange for a @file{.h} file, but it's OK since +it is only included in one place. @file{@var{arch}-opcode.h} is shared +between the debugger and the assembler, if the GNU assembler has been +ported to the target machine. + +@item gdb/config/@var{arch}/tm-@var{arch}.h +This often exists to describe the basic layout of the target machine's +processor chip (registers, stack, etc). +If used, it is included by @file{tm-@var{xxx}.h}. It can +be shared among many targets that use the same processor. + +@item gdb/@var{arch}-tdep.c +Similarly, there are often common subroutines that are shared by all +target machines that use this particular architecture. +@end table + +When adding support for a new target machine, there are various areas +of support that might need change, or might be OK. + +If you are using an existing object file format (a.out or COFF), +there is probably little to be done. See @file{bfd/doc/bfd.texinfo} +for more information on writing new a.out or COFF versions. + +If you need to add a new object file format, you must first add it to +BFD. This is beyond the scope of this document right now. Basically +you must build a transfer vector (of type @code{bfd_target}), which will +mean writing all the required routines, and add it to the list in +@file{bfd/targets.c}. + +You must then arrange for the BFD code to provide access to the +debugging symbols. Generally GDB will have to call swapping routines +from BFD and a few other BFD internal routines to locate the debugging +information. As much as possible, GDB should not depend on the BFD +internal data structures. + +For some targets (e.g., COFF), there is a special transfer vector used +to call swapping routines, since the external data structures on various +platforms have different sizes and layouts. Specialized routines that +will only ever be implemented by one object file format may be called +directly. This interface should be described in a file +@file{bfd/libxxx.h}, which is included by GDB. + +If you are adding a new operating system for an existing CPU chip, add a +@file{tm-@var{xos}.h} file that describes the operating system +facilities that are unusual (extra symbol table info; the breakpoint +instruction needed; etc). Then write a +@file{tm-@var{xarch}-@var{xos}.h} that just @code{#include}s +@file{tm-@var{xarch}.h} and @file{tm-@var{xos}.h}. (Now that we have +three-part configuration names, this will probably get revised to +separate the @var{xos} configuration from the @var{xarch} +configuration.) + + +@node Languages +@chapter Adding a Source Language to GDB + +To add other languages to GDB's expression parser, follow the following steps: + +@table @emph +@item Create the expression parser. + +This should reside in a file @file{@var{lang}-exp.y}. Routines for building +parsed expressions into a @samp{union exp_element} list are in @file{parse.c}. + +Since we can't depend upon everyone having Bison, and YACC produces +parsers that define a bunch of global names, the following lines +@emph{must} be included at the top of the YACC parser, to prevent +the various parsers from defining the same global names: + +@example +#define yyparse @var{lang}_parse +#define yylex @var{lang}_lex +#define yyerror @var{lang}_error +#define yylval @var{lang}_lval +#define yychar @var{lang}_char +#define yydebug @var{lang}_debug +#define yypact @var{lang}_pact +#define yyr1 @var{lang}_r1 +#define yyr2 @var{lang}_r2 +#define yydef @var{lang}_def +#define yychk @var{lang}_chk +#define yypgo @var{lang}_pgo +#define yyact @var{lang}_act +#define yyexca @var{lang}_exca +#define yyerrflag @var{lang}_errflag +#define yynerrs @var{lang}_nerrs +@end example + +At the bottom of your parser, define a @code{struct language_defn} and +initialize it with the right values for your language. Define an +@code{initialize_@var{lang}} routine and have it call +@samp{add_language(@var{lang}_language_defn)} to tell the rest of GDB +that your language exists. You'll need some other supporting variables +and functions, which will be used via pointers from your +@code{@var{lang}_language_defn}. See the declaration of @code{struct +language_defn} in @file{language.h}, and the other @file{*-exp.y} files, +for more information. + +@item Add any evaluation routines, if necessary + +If you need new opcodes (that represent the operations of the language), +add them to the enumerated type in @file{expression.h}. Add support +code for these operations in @code{eval.c:evaluate_subexp()}. Add cases +for new opcodes in two functions from @file{parse.c}: +@code{prefixify_subexp()} and @code{length_of_subexp()}. These compute +the number of @code{exp_element}s that a given operation takes up. + +@item Update some existing code + +Add an enumerated identifier for your language to the enumerated type +@code{enum language} in @file{defs.h}. + +Update the routines in @file{language.c} so your language is included. These +routines include type predicates and such, which (in some cases) are +language dependent. If your language does not appear in the switch +statement, an error is reported. + +Also included in @file{language.c} is the code that updates the variable +@code{current_language}, and the routines that translate the +@code{language_@var{lang}} enumerated identifier into a printable +string. + +Update the function @code{_initialize_language} to include your language. This +function picks the default language upon startup, so is dependent upon +which languages that GDB is built for. + +Update @code{allocate_symtab} in @file{symfile.c} and/or symbol-reading +code so that the language of each symtab (source file) is set properly. +This is used to determine the language to use at each stack frame level. +Currently, the language is set based upon the extension of the source +file. If the language can be better inferred from the symbol +information, please set the language of the symtab in the symbol-reading +code. + +Add helper code to @code{expprint.c:print_subexp()} to handle any new +expression opcodes you have added to @file{expression.h}. Also, add the +printed representations of your operators to @code{op_print_tab}. + +@item Add a place of call + +Add a call to @code{@var{lang}_parse()} and @code{@var{lang}_error} in +@code{parse.c:parse_exp_1()}. + +@item Use macros to trim code + +The user has the option of building GDB for some or all of the +languages. If the user decides to build GDB for the language +@var{lang}, then every file dependent on @file{language.h} will have the +macro @code{_LANG_@var{lang}} defined in it. Use @code{#ifdef}s to +leave out large routines that the user won't need if he or she is not +using your language. + +Note that you do not need to do this in your YACC parser, since if GDB +is not build for @var{lang}, then @file{@var{lang}-exp.tab.o} (the +compiled form of your parser) is not linked into GDB at all. + +See the file @file{configure.in} for how GDB is configured for different +languages. + +@item Edit @file{Makefile.in} + +Add dependencies in @file{Makefile.in}. Make sure you update the macro +variables such as @code{HFILES} and @code{OBJS}, otherwise your code may +not get linked in, or, worse yet, it may not get @code{tar}red into the +distribution! +@end table + + +@node Releases +@chapter Configuring GDB for Release + +From the top level directory (containing @file{gdb}, @file{bfd}, +@file{libiberty}, and so on): +@example +make -f Makefile.in gdb.tar.gz +@end example + +This will properly configure, clean, rebuild any files that are +distributed pre-built (e.g. @file{c-exp.tab.c} or @file{refcard.ps}), +and will then make a tarfile. (If the top level directory has already +been configured, you can just do @code{make gdb.tar.gz} instead.) + +This procedure requires: +@itemize @bullet +@item symbolic links +@item @code{makeinfo} (texinfo2 level) +@item @TeX{} +@item @code{dvips} +@item @code{yacc} or @code{bison} +@end itemize +@noindent +@dots{} and the usual slew of utilities (@code{sed}, @code{tar}, etc.). + +@subheading TEMPORARY RELEASE PROCEDURE FOR DOCUMENTATION + +@file{gdb.texinfo} is currently marked up using the texinfo-2 macros, +which are not yet a default for anything (but we have to start using +them sometime). + +For making paper, the only thing this implies is the right generation of +@file{texinfo.tex} needs to be included in the distribution. + +For making info files, however, rather than duplicating the texinfo2 +distribution, generate @file{gdb-all.texinfo} locally, and include the files +@file{gdb.info*} in the distribution. Note the plural; @code{makeinfo} will +split the document into one overall file and five or so included files. + + +@node Partial Symbol Tables +@chapter Partial Symbol Tables + +GDB has three types of symbol tables. + +@itemize @bullet +@item full symbol tables (symtabs). These contain the main +information about symbols and addresses. +@item partial symbol tables (psymtabs). These contain enough +information to know when to read the corresponding +part of the full symbol table. +@item minimal symbol tables (msymtabs). These contain information +gleaned from non-debugging symbols. +@end itemize + +This section describes partial symbol tables. + +A psymtab is constructed by doing a very quick pass over an executable +file's debugging information. Small amounts of information are +extracted -- enough to identify which parts of the symbol table will +need to be re-read and fully digested later, when the user needs the +information. The speed of this pass causes GDB to start up very +quickly. Later, as the detailed rereading occurs, it occurs in small +pieces, at various times, and the delay therefrom is mostly invisible to +the user. (@xref{Symbol Reading}.) + +The symbols that show up in a file's psymtab should be, roughly, those +visible to the debugger's user when the program is not running code from +that file. These include external symbols and types, static +symbols and types, and enum values declared at file scope. + +The psymtab also contains the range of instruction addresses that the +full symbol table would represent. + +The idea is that there are only two ways for the user (or much of +the code in the debugger) to reference a symbol: + +@itemize @bullet + +@item by its address +(e.g. execution stops at some address which is inside a function +in this file). The address will be noticed to be in the +range of this psymtab, and the full symtab will be read in. +@code{find_pc_function}, @code{find_pc_line}, and other @code{find_pc_@dots{}} +functions handle this. + +@item by its name +(e.g. the user asks to print a variable, or set a breakpoint on a +function). Global names and file-scope names will be found in the +psymtab, which will cause the symtab to be pulled in. Local names will +have to be qualified by a global name, or a file-scope name, in which +case we will have already read in the symtab as we evaluated the +qualifier. Or, a local symbol can be referenced when +we are "in" a local scope, in which case the first case applies. +@code{lookup_symbol} does most of the work here. + +@end itemize + +The only reason that psymtabs exist is to cause a symtab to be read in +at the right moment. Any symbol that can be elided from a psymtab, +while still causing that to happen, should not appear in it. Since +psymtabs don't have the idea of scope, you can't put local symbols in +them anyway. Psymtabs don't have the idea of the type of a symbol, +either, so types need not appear, unless they will be referenced by +name. + +It is a bug for GDB to behave one way when only a psymtab has been read, +and another way if the corresponding symtab has been read in. Such +bugs are typically caused by a psymtab that does not contain all the +visible symbols, or which has the wrong instruction address ranges. + +The psymtab for a particular section of a symbol-file (objfile) +could be thrown away after the symtab has been read in. The symtab +should always be searched before the psymtab, so the psymtab will +never be used (in a bug-free environment). Currently, +psymtabs are allocated on an obstack, and all the psymbols themselves +are allocated in a pair of large arrays on an obstack, so there is +little to be gained by trying to free them unless you want to do a lot +more work. + +@node Types +@chapter Types + +Fundamental Types (e.g., FT_VOID, FT_BOOLEAN). + +These are the fundamental types that GDB uses internally. Fundamental +types from the various debugging formats (stabs, ELF, etc) are mapped into +one of these. They are basically a union of all fundamental types that +gdb knows about for all the languages that GDB knows about. + +Type Codes (e.g., TYPE_CODE_PTR, TYPE_CODE_ARRAY). + +Each time GDB builds an internal type, it marks it with one of these +types. The type may be a fundamental type, such as TYPE_CODE_INT, or +a derived type, such as TYPE_CODE_PTR which is a pointer to another +type. Typically, several FT_* types map to one TYPE_CODE_* type, and +are distinguished by other members of the type struct, such as whether +the type is signed or unsigned, and how many bits it uses. + +Builtin Types (e.g., builtin_type_void, builtin_type_char). + +These are instances of type structs that roughly correspond to fundamental +types and are created as global types for GDB to use for various ugly +historical reasons. We eventually want to eliminate these. Note for +example that builtin_type_int initialized in gdbtypes.c is basically the +same as a TYPE_CODE_INT type that is initialized in c-lang.c for an +FT_INTEGER fundamental type. The difference is that the builtin_type is +not associated with any particular objfile, and only one instance exists, +while c-lang.c builds as many TYPE_CODE_INT types as needed, with each +one associated with some particular objfile. + +@node BFD support for GDB +@chapter Binary File Descriptor Library Support for GDB + +BFD provides support for GDB in several ways: + +@table @emph +@item identifying executable and core files +BFD will identify a variety of file types, including a.out, coff, and +several variants thereof, as well as several kinds of core files. + +@item access to sections of files +BFD parses the file headers to determine the names, virtual addresses, +sizes, and file locations of all the various named sections in files +(such as the text section or the data section). GDB simply calls +BFD to read or write section X at byte offset Y for length Z. + +@item specialized core file support +BFD provides routines to determine the failing command name stored +in a core file, the signal with which the program failed, and whether +a core file matches (i.e. could be a core dump of) a particular executable +file. + +@item locating the symbol information +GDB uses an internal interface of BFD to determine where to find the +symbol information in an executable file or symbol-file. GDB itself +handles the reading of symbols, since BFD does not ``understand'' debug +symbols, but GDB uses BFD's cached information to find the symbols, +string table, etc. +@end table + +@c The interface for symbol reading is described in @ref{Symbol +@c Reading,,Symbol Reading}. + + +@node Symbol Reading +@chapter Symbol Reading + +GDB reads symbols from "symbol files". The usual symbol file is the +file containing the program which GDB is debugging. GDB can be directed +to use a different file for symbols (with the ``symbol-file'' +command), and it can also read more symbols via the ``add-file'' and ``load'' +commands, or while reading symbols from shared libraries. + +Symbol files are initially opened by @file{symfile.c} using the BFD +library. BFD identifies the type of the file by examining its header. +@code{symfile_init} then uses this identification to locate a +set of symbol-reading functions. + +Symbol reading modules identify themselves to GDB by calling +@code{add_symtab_fns} during their module initialization. The argument +to @code{add_symtab_fns} is a @code{struct sym_fns} which contains +the name (or name prefix) of the symbol format, the length of the prefix, +and pointers to four functions. These functions are called at various +times to process symbol-files whose identification matches the specified +prefix. + +The functions supplied by each module are: + +@table @code +@item @var{xxx}_symfile_init(struct sym_fns *sf) + +Called from @code{symbol_file_add} when we are about to read a new +symbol file. This function should clean up any internal state +(possibly resulting from half-read previous files, for example) +and prepare to read a new symbol file. Note that the symbol file +which we are reading might be a new "main" symbol file, or might +be a secondary symbol file whose symbols are being added to the +existing symbol table. + +The argument to @code{@var{xxx}_symfile_init} is a newly allocated +@code{struct sym_fns} whose @code{bfd} field contains the BFD +for the new symbol file being read. Its @code{private} field +has been zeroed, and can be modified as desired. Typically, +a struct of private information will be @code{malloc}'d, and +a pointer to it will be placed in the @code{private} field. + +There is no result from @code{@var{xxx}_symfile_init}, but it can call +@code{error} if it detects an unavoidable problem. + +@item @var{xxx}_new_init() + +Called from @code{symbol_file_add} when discarding existing symbols. +This function need only handle +the symbol-reading module's internal state; the symbol table data +structures visible to the rest of GDB will be discarded by +@code{symbol_file_add}. It has no arguments and no result. +It may be called after @code{@var{xxx}_symfile_init}, if a new symbol +table is being read, or may be called alone if all symbols are +simply being discarded. + +@item @var{xxx}_symfile_read(struct sym_fns *sf, CORE_ADDR addr, int mainline) + +Called from @code{symbol_file_add} to actually read the symbols from a +symbol-file into a set of psymtabs or symtabs. + +@code{sf} points to the struct sym_fns originally passed to +@code{@var{xxx}_sym_init} for possible initialization. @code{addr} is the +offset between the file's specified start address and its true address +in memory. @code{mainline} is 1 if this is the main symbol table being +read, and 0 if a secondary symbol file (e.g. shared library or +dynamically loaded file) is being read.@refill +@end table + +In addition, if a symbol-reading module creates psymtabs when +@var{xxx}_symfile_read is called, these psymtabs will contain a pointer to +a function @code{@var{xxx}_psymtab_to_symtab}, which can be called from +any point in the GDB symbol-handling code. + +@table @code +@item @var{xxx}_psymtab_to_symtab (struct partial_symtab *pst) + +Called from @code{psymtab_to_symtab} (or the PSYMTAB_TO_SYMTAB +macro) if the psymtab has not already been read in and had its +@code{pst->symtab} pointer set. The argument is the psymtab +to be fleshed-out into a symtab. Upon return, pst->readin +should have been set to 1, and pst->symtab should contain a +pointer to the new corresponding symtab, or zero if there +were no symbols in that part of the symbol file. +@end table + + +@node Cleanups +@chapter Cleanups + +Cleanups are a structured way to deal with things that need to be done +later. When your code does something (like @code{malloc} some memory, or open +a file) that needs to be undone later (e.g. free the memory or close +the file), it can make a cleanup. The cleanup will be done at some +future point: when the command is finished, when an error occurs, or +when your code decides it's time to do cleanups. + +You can also discard cleanups, that is, throw them away without doing +what they say. This is only done if you ask that it be done. + +Syntax: + +@table @code +@item struct cleanup *@var{old_chain}; +Declare a variable which will hold a cleanup chain handle. + +@item @var{old_chain} = make_cleanup (@var{function}, @var{arg}); +Make a cleanup which will cause @var{function} to be called with @var{arg} +(a @code{char *}) later. The result, @var{old_chain}, is a handle that can be +passed to @code{do_cleanups} or @code{discard_cleanups} later. Unless you are +going to call @code{do_cleanups} or @code{discard_cleanups} yourself, +you can ignore the result from @code{make_cleanup}. + + +@item do_cleanups (@var{old_chain}); +Perform all cleanups done since @code{make_cleanup} returned @var{old_chain}. +E.g.: +@example +make_cleanup (a, 0); +old = make_cleanup (b, 0); +do_cleanups (old); +@end example +@noindent +will call @code{b()} but will not call @code{a()}. The cleanup that calls @code{a()} will remain +in the cleanup chain, and will be done later unless otherwise discarded.@refill + +@item discard_cleanups (@var{old_chain}); +Same as @code{do_cleanups} except that it just removes the cleanups from the +chain and does not call the specified functions. + +@end table + +Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they +``should not be called when cleanups are not in place''. This means +that any actions you need to reverse in the case of an error or +interruption must be on the cleanup chain before you call these functions, +since they might never return to your code (they @samp{longjmp} instead). + + +@node Wrapping +@chapter Wrapping Output Lines + +Output that goes through @code{printf_filtered} or @code{fputs_filtered} or +@code{fputs_demangled} needs only to have calls to @code{wrap_here} added +in places that would be good breaking points. The utility routines +will take care of actually wrapping if the line width is exceeded. + +The argument to @code{wrap_here} is an indentation string which is printed +@emph{only} if the line breaks there. This argument is saved away and used +later. It must remain valid until the next call to @code{wrap_here} or +until a newline has been printed through the @code{*_filtered} functions. +Don't pass in a local variable and then return! + +It is usually best to call @code{wrap_here()} after printing a comma or space. +If you call it before printing a space, make sure that your indentation +properly accounts for the leading space that will print if the line wraps +there. + +Any function or set of functions that produce filtered output must finish +by printing a newline, to flush the wrap buffer, before switching to +unfiltered (``@code{printf}'') output. Symbol reading routines that print +warnings are a good example. + + +@node Frames +@chapter Frames + +A frame is a construct that GDB uses to keep track of calling and called +functions. + +@table @code +@item FRAME_FP +in the machine description has no meaning to the machine-independent +part of GDB, except that it is used when setting up a new frame from +scratch, as follows: + +@example + create_new_frame (read_register (FP_REGNUM), read_pc ())); +@end example + +Other than that, all the meaning imparted to @code{FP_REGNUM} is imparted by +the machine-dependent code. So, @code{FP_REGNUM} can have any value that +is convenient for the code that creates new frames. (@code{create_new_frame} +calls @code{INIT_EXTRA_FRAME_INFO} if it is defined; that is where you should +use the @code{FP_REGNUM} value, if your frames are nonstandard.) + +@item FRAME_CHAIN +Given a GDB frame, determine the address of the calling function's +frame. This will be used to create a new GDB frame struct, and then +@code{INIT_EXTRA_FRAME_INFO} and @code{INIT_FRAME_PC} will be called for +the new frame. +@end table + +@node Remote Stubs +@chapter Remote Stubs + +GDB's file @file{remote.c} talks a serial protocol to code that runs +in the target system. GDB provides several sample ``stubs'' that can +be integrated into target programs or operating systems for this purpose; +they are named @file{*-stub.c}. + +The GDB user's manual describes how to put such a stub into your target +code. What follows is a discussion of integrating the SPARC stub +into a complicated operating system (rather than a simple program), +by Stu Grossman, the author of this stub. + +The trap handling code in the stub assumes the following upon entry to +trap_low: + +@enumerate +@item %l1 and %l2 contain pc and npc respectively at the time of the trap +@item traps are disabled +@item you are in the correct trap window +@end enumerate + +As long as your trap handler can guarantee those conditions, then there is no +reason why you shouldn't be able to `share' traps with the stub. The stub has +no requirement that it be jumped to directly from the hardware trap vector. +That is why it calls @code{exceptionHandler()}, which is provided by the external +environment. For instance, this could setup the hardware traps to actually +execute code which calls the stub first, and then transfers to its own trap +handler. + +For the most point, there probably won't be much of an issue with `sharing' +traps, as the traps we use are usually not used by the kernel, and often +indicate unrecoverable error conditions. Anyway, this is all controlled by a +table, and is trivial to modify. +The most important trap for us is for @code{ta 1}. Without that, we +can't single step or do breakpoints. Everything else is unnecessary +for the proper operation of the debugger/stub. + +From reading the stub, it's probably not obvious how breakpoints work. They +are simply done by deposit/examine operations from GDB. + +@node Longjmp Support +@chapter Longjmp Support + +GDB has support for figuring out that the target is doing a +@code{longjmp} and for stopping at the target of the jump, if we are +stepping. This is done with a few specialized internal breakpoints, +which are visible in the @code{maint info breakpoint} command. + +To make this work, you need to define a macro called +@code{GET_LONGJMP_TARGET}, which will examine the @code{jmp_buf} +structure and extract the longjmp target address. Since @code{jmp_buf} +is target specific, you will need to define it in the appropriate +@file{tm-xxx.h} file. Look in @file{tm-sun4os4.h} and +@file{sparc-tdep.c} for examples of how to do this. + +@node Coding Style +@chapter Coding Style + +GDB is generally written using the GNU coding standards, as described in +@file{standards.texi}, which is available for anonymous FTP from GNU +archive sites. There are some additional considerations for GDB +maintainers that reflect the unique environment and style of GDB +maintenance. If you follow these guidelines, GDB will be more +consistent and easier to maintain. + +GDB's policy on the use of prototypes is that prototypes are used +to @emph{declare} functions but never to @emph{define} them. Simple +macros are used in the declarations, so that a non-ANSI compiler can +compile GDB without trouble. The simple macro calls are used like +this: + +@example @code +extern int +memory_remove_breakpoint PARAMS ((CORE_ADDR, char *)); +@end example + +Note the double parentheses around the parameter types. This allows +an arbitrary number of parameters to be described, without freaking +out the C preprocessor. When the function has no parameters, it +should be described like: + +@example @code +void +noprocess PARAMS ((void)); +@end example + +The @code{PARAMS} macro expands to its argument in ANSI C, or to a simple +@code{()} in traditional C. + +All external functions should have a @code{PARAMS} declaration in a +header file that callers include. All static functions should have such +a declaration near the top of their source file. + +We don't have a gcc option that will properly check that these rules +have been followed, but it's GDB policy, and we periodically check it +using the tools available (plus manual labor), and clean up any remnants. + +@node Clean Design +@chapter Clean Design + +In addition to getting the syntax right, there's the little question of +semantics. Some things are done in certain ways in GDB because long +experience has shown that the more obvious ways caused various kinds of +trouble. In particular: + +@table @bullet +@item +You can't assume the byte order of anything that comes from a +target (including @var{value}s, object files, and instructions). Such +things must be byte-swapped using @code{SWAP_TARGET_AND_HOST} in GDB, +or one of the swap routines defined in @file{bfd.h}, such as @code{bfd_get_32}. + +@item +You can't assume that you know what interface is being used to talk to +the target system. All references to the target must go through the +current @code{target_ops} vector. + +@item +You can't assume that the host and target machines are the same machine +(except in the ``native'' support modules). +In particular, you can't assume that the target machine's header files +will be available on the host machine. Target code must bring along its +own header files -- written from scratch or explicitly donated by their +owner, to avoid copyright problems. + +@item +Insertion of new @code{#ifdef}'s will be frowned upon. It's much better +to write the code portably than to conditionalize it for various systems. + +@item +New @code{#ifdef}'s which test for specific compilers or manufacturers +or operating systems are unacceptable. All @code{#ifdef}'s should test +for features. The information about which configurations contain which +features should be segregated into the configuration files. Experience +has proven far too often that a feature unique to one particular system +often creeps into other systems; and that a conditional based on +some predefined macro for your current system will become worthless +over time, as new versions of your system come out that behave differently +with regard to this feature. + +@item +Adding code that handles specific architectures, operating systems, target +interfaces, or hosts, is not acceptable in generic code. If a hook +is needed at that point, invent a generic hook and define it for your +configuration, with something like: + +@example +#ifdef WRANGLE_SIGNALS + WRANGLE_SIGNALS (signo); +#endif +@end example + +In your host, target, or native configuration file, as appropriate, +define @code{WRANGLE_SIGNALS} to do the machine-dependent thing. Take +a bit of care in defining the hook, so that it can be used by other +ports in the future, if they need a hook in the same place. + +If the hook is not defined, the code should do whatever "most" machines +want. Using @code{#ifdef}, as above, is the preferred way to do this, +but sometimes that gets convoluted, in which case use + +@example +#ifndef SPECIAL_FOO_HANDLING +#define SPECIAL_FOO_HANDLING(pc, sp) (0) +#endif +@end example + +where the macro is used or in an appropriate header file. + +Whether to include a @dfn{small} hook, a hook around the exact pieces of +code which are system-dependent, or whether to replace a whole function +with a hook depends on the case. A good example of this dilemma can be +found in @code{get_saved_register}. All machines that GDB 2.8 ran on +just needed the @code{FRAME_FIND_SAVED_REGS} hook to find the saved +registers. Then the SPARC and Pyramid came along, and +@code{HAVE_REGISTER_WINDOWS} and @code{REGISTER_IN_WINDOW_P} were +introduced. Then the 29k and 88k required the @code{GET_SAVED_REGISTER} +hook. The first three are examples of small hooks; the latter replaces +a whole function. In this specific case, it is useful to have both +kinds; it would be a bad idea to replace all the uses of the small hooks +with @code{GET_SAVED_REGISTER}, since that would result in much +duplicated code. Other times, duplicating a few lines of code here or +there is much cleaner than introducing a large number of small hooks. + +Another way to generalize GDB along a particular interface is with an +attribute struct. For example, GDB has been generalized to handle +multiple kinds of remote interfaces -- not by #ifdef's everywhere, but +by defining the "target_ops" structure and having a current target (as +well as a stack of targets below it, for memory references). Whenever +something needs to be done that depends on which remote interface we are +using, a flag in the current target_ops structure is tested (e.g. +`target_has_stack'), or a function is called through a pointer in the +current target_ops structure. In this way, when a new remote interface +is added, only one module needs to be touched -- the one that actually +implements the new remote interface. Other examples of +attribute-structs are BFD access to multiple kinds of object file +formats, or GDB's access to multiple source languages. + +Please avoid duplicating code. For example, in GDB 3.x all the code +interfacing between @code{ptrace} and the rest of GDB was duplicated in +@file{*-dep.c}, and so changing something was very painful. In GDB 4.x, +these have all been consolidated into @file{infptrace.c}. +@file{infptrace.c} can deal with variations between systems the same way +any system-independent file would (hooks, #if defined, etc.), and +machines which are radically different don't need to use infptrace.c at +all. + +@item +@emph{Do} write code that doesn't depend on the sizes of C data types, +the format of the host's floating point numbers, the alignment of anything, +or the order of evaluation of expressions. In short, follow good +programming practices for writing portable C code. + +@end table + +@node Submitting Patches +@chapter Submitting Patches + +Thanks for thinking of offering your changes back to the community of +GDB users. In general we like to get well designed enhancements. +Thanks also for checking in advance about the best way to transfer the +changes. + +The two main problems with getting your patches in are, + +@table @bullet +@item +The GDB maintainers will only install ``cleanly designed'' patches. +You may not always agree on what is clean design. +@pxref{Coding Style}, @pxref{Clean Design}. + +@item +If the maintainers don't have time to put the patch in when it +arrives, or if there is any question about a patch, it +goes into a large queue with everyone else's patches and +bug reports. +@end table + +I don't know how to get past these problems except by continuing to try. + +There are two issues here -- technical and legal. + +The legal issue is that to incorporate substantial changes requires a +copyright assignment from you and/or your employer, granting ownership +of the changes to the Free Software Foundation. You can get the +standard document for doing this by sending mail to +@code{gnu@@prep.ai.mit.edu} and asking for it. I recommend that people +write in "All programs owned by the Free Software Foundation" as "NAME +OF PROGRAM", so that changes in many programs (not just GDB, but GAS, +Emacs, GCC, etc) can be contributed with only one piece of legalese +pushed through the bureacracy and filed with the FSF. I can't start +merging changes until this paperwork is received by the FSF (their +rules, which I follow since I maintain it for them). + +Technically, the easiest way to receive changes is to receive each +feature as a small context diff or unidiff, suitable for "patch". +Each message sent to me should include the changes to C code and +header files for a single feature, plus ChangeLog entries for each +directory where files were modified, and diffs for any changes needed +to the manuals (gdb/doc/gdb.texi or gdb/doc/gdbint.texi). If there +are a lot of changes for a single feature, they can be split down +into multiple messages. + +In this way, if I read and like the feature, I can add it to the +sources with a single patch command, do some testing, and check it in. +If you leave out the ChangeLog, I have to write one. If you leave +out the doc, I have to puzzle out what needs documenting. Etc. + +The reason to send each change in a separate message is that I will +not install some of the changes. They'll be returned to you with +questions or comments. If I'm doing my job, my message back to you +will say what you have to fix in order to make the change acceptable. +The reason to have separate messages for separate features is so +that other changes (which I @emph{am} willing to accept) can be installed +while one or more changes are being reworked. If multiple features +are sent in a single message, I tend to not put in the effort to sort +out the acceptable changes from the unacceptable, so none of the +features get installed until all are acceptable. + +If this sounds painful or authoritarian, well, it is. But I get a lot +of bug reports and a lot of patches, and most of them don't get +installed because I don't have the time to finish the job that the bug +reporter or the contributor could have done. Patches that arrive +complete, working, and well designed, tend to get installed on the day +they arrive. The others go into a queue and get installed if and when +I scan back over the queue -- which can literally take months +sometimes. It's in both our interests to make patch installation easy +-- you get your changes installed, and I make some forward progress on +GDB in a normal 12-hour day (instead of them having to wait until I +have a 14-hour or 16-hour day to spend cleaning up patches before I +can install them). + +Please send patches to @code{bug-gdb@@prep.ai.mit.edu}, if they are less +than about 25,000 characters. If longer than that, either make them +available somehow (e.g. anonymous FTP), and announce it on +@code{bug-gdb}, or send them directly to the GDB maintainers at +@code{gdb-patches@@cygnus.com}. + +@node Host Conditionals +@chapter Host Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation based on the attributes of the host +system. These macros and their meanings (or if the meaning is not +documented here, then one of the source files where they are used is +indicated) are: + +@emph{NOTE: For now, both host and target conditionals are here. +Eliminate target conditionals from this list as they are identified.} + +@table @code + +@item BLOCK_ADDRESS_FUNCTION_RELATIVE +dbxread.c + +@item GDBINIT_FILENAME +The default name of GDB's initialization file (normally @file{.gdbinit}). + +@item MEM_FNS_DECLARED +Your host config file defines this if it includes +declarations of @code{memcpy} and @code{memset}. Define this +to avoid conflicts between the native include +files and the declarations in @file{defs.h}. + +@item NO_SYS_FILE +Define this if your system does not have a @code{}. + +@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 ADDITIONAL_OPTIONS +main.c +@item ADDITIONAL_OPTION_CASES +main.c +@item ADDITIONAL_OPTION_HANDLER +main.c +@item ADDITIONAL_OPTION_HELP +main.c + +@item AIX_BUGGY_PTRACE_CONTINUE +infptrace.c + +@item ALIGN_STACK_ON_STARTUP +Define this if your system is of a sort that will crash in @code{tgetent} +if the stack happens not to be longword-aligned when @code{main} is +called. This is a rare situation, but is known to occur on several +different types of systems. + +@item CFRONT_PRODUCER +dwarfread.c +@item DBX_PARM_SYMBOL_CLASS +stabsread.c + +@item DEFAULT_PROMPT +The default value of the prompt string (normally @code{"(gdb) "}). + +@item DEV_TTY +symmisc.c +@item DO_REGISTERS_INFO +infcmd.c + +@item FCLOSE_PROVIDED +Define this if the system declares @code{fclose} in the headers included in +@code{defs.h}. This isn't needed unless your compiler is unusually anal. + +@sc{ANSI} definition. + +@item FILES_INFO_HOOK +target.c +@item FLOAT_INFO +infcmd.c + +@item FOPEN_RB +Define this if binary files are opened the same way as text files. + +@item GCC2_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_MANGLE_BUG +symtab.c +@item GCC_PRODUCER +dwarfread.c + +@item GETENV_PROVIDED +Define this if the system declares @code{getenv} in its headers included in +@code{defs.h}. This isn't needed unless your compiler is unusually anal. + +@item GPLUS_PRODUCER +dwarfread.c + +@item HAVE_MMAP +In some cases, use the system call @code{mmap} for reading symbol +tables. For some machines this allows for sharing and quick updates. + +@item HAVE_SIGSETMASK +Define this if the host system has job control, but does not +define @code{sigsetmask()}. +Currently, this is only true of the RS/6000. + +@item HAVE_TERMIO +inflow.c + +@item HOST_BYTE_ORDER +The ordering of bytes in the host. +This must be defined to be either @code{BIG_ENDIAN} or @code{LITTLE_ENDIAN}. + +@item INT_MAX +@item INT_MIN +@item LONG_MAX +@item UINT_MAX +@item ULONG_MAX +Values for host-side constants. + +@item ISATTY +Substitute for isatty, if not available. + +@item KERNEL_DEBUGGING +tm-ultra3.h + +@item KERNEL_U_ADDR +Define this to the address of the @code{u} structure (the ``user struct'', +also known as the ``u-page'') in kernel virtual memory. GDB needs to know +this so that it can subtract this address from absolute addresses in +the upage, that are obtained via ptrace or from core files. On systems +that don't need this value, set it to zero. + +@item KERNEL_U_ADDR_BSD +Define this to cause GDB to determine the address of @code{u} at runtime, +by using Berkeley-style @code{nlist} on the kernel's image in the root +directory. + +@item KERNEL_U_ADDR_HPUX +Define this to cause GDB to determine the address of @code{u} at runtime, +by using HP-style @code{nlist} on the kernel's image in the root +directory. + +@item LCC_PRODUCER +dwarfread.c + +@item LONGEST +This is the longest integer type available on the host. +If not defined, it will default to @code{long long} or @code{long}, +depending on @code{CC_HAS_LONG_LONG}. + +@item CC_HAS_LONG_LONG +Define this if the host C compiler supports ``long long''. +This will be defined automatically if GNU CC is used to compile GDB. + +@item PRINTF_HAS_LONG_LONG +Define this if the host can handle printing of long long integers via a +format directive ``ll''. + +@item LSEEK_NOT_LINEAR +source.c +@item L_LNNO32 +coffread.c + +@item L_SET +This macro is used as the argument to lseek (or, most commonly, bfd_seek). +FIXME, should be replaced by SEEK_SET instead, which is the POSIX equivalent. + +@item MAINTENANCE_CMDS +If the value of this is 1, then a number of optional maintenance commands +are compiled in. + +@item MALLOC_INCOMPATIBLE +Define this if the system's prototype for @code{malloc} differs from the +@sc{ANSI} definition. + +@item MMAP_BASE_ADDRESS +When using HAVE_MMAP, the first mapping should go at this address. + +@item MMAP_INCREMENT +when using HAVE_MMAP, this is the increment between mappings. + +@item NEED_POSIX_SETPGID +Define this to use the POSIX version of @code{setpgid} to determine +whether job control is available. + +@item NORETURN +If defined, this should be one or more tokens, such as @code{volatile}, +that can be used in both the declaration and definition of functions +to indicate that they never return. The default is already set +correctly if compiling with GCC. +This will almost never need to be defined. + +@item ATTR_NORETURN +If defined, this should be one or more tokens, such as +@code{__attribute__ ((noreturn))}, that can be used in the declarations +of functions to indicate that they never return. The default is already +set correctly if compiling with GCC. +This will almost never need to be defined. + +@item NOTICE_SIGNAL_HANDLING_CHANGE +infrun.c +@item NO_HIF_SUPPORT +remote-mm.c +@item NO_JOB_CONTROL +signals.h + +@item NO_MMALLOC +GDB will use the @code{mmalloc} library for memory allocation for symbol +reading, unless this symbol is defined. Define it on systems +on which @code{mmalloc} does not +work for some reason. One example is the DECstation, where its RPC +library can't cope with our redefinition of @code{malloc} to call +@code{mmalloc}. When defining @code{NO_MMALLOC}, you will also have +to override the setting of @code{MMALLOC_LIB} to empty, in the Makefile. +Therefore, this define is usually set on the command line by overriding +@code{MMALLOC_DISABLE} in @file{config/*/*.mh}, rather than by defining +it in @file{xm-*.h}. + +@item NO_MMALLOC_CHECK +Define this if you are using @code{mmalloc}, but don't want the overhead +of checking the heap with @code{mmcheck}. + +@item NO_SIGINTERRUPT +remote-adapt.c +@item NUMERIC_REG_NAMES +mips-tdep.c +@item N_SETV +dbxread.c +@item N_SET_MAGIC +hppabsd-tdep.c +@item ONE_PROCESS_WRITETEXT +breakpoint.c +@item O_BINARY +exec.c +@item O_RDONLY +xm-ultra3.h +@item PCC_SOL_BROKEN +dbxread.c +@item PC_LOAD_SEGMENT +stack.c +@item PRINT_RANDOM_SIGNAL +infcmd.c +@item PRINT_REGISTER_HOOK +infcmd.c +@item PROCESS_LINENUMBER_HOOK +buildsym.c +@item PROLOGUE_FIRSTLINE_OVERLAP +infrun.c +@item PUSH_ARGUMENTS +valops.c +@item PYRAMID_CONTROL_FRAME_DEBUGGING +pyr-xdep.c +@item PYRAMID_CORE +pyr-xdep.c +@item PYRAMID_PTRACE +pyr-xdep.c +@item REGISTER_BYTES +remote.c +@item REG_STACK_SEGMENT +exec.c +@item REG_STRUCT_HAS_ADDR +findvar.c +@item R_FP +dwarfread.c +@item R_OK +xm-altos.h +@item SEEK_END +state.c +@item SEEK_SET +state.c +@item SEM +coffread.c + +@item SHELL_COMMAND_CONCAT +infrun.c +@item SHELL_FILE +infrun.c +@item SHIFT_INST_REGS +breakpoint.c +@item SIGTRAP_STOP_AFTER_LOAD +infrun.c +@item STACK_ALIGN +valops.c +@item STOP_SIGNAL +main.c +@item SUN4_COMPILER_FEATURE +infrun.c +@item SUN_FIXED_LBRAC_BUG +dbxread.c +@item SVR4_SHARED_LIBS +solib.c +@item SYMBOL_RELOADING_DEFAULT +symfile.c +@item TIOCGETC +inflow.c +@item TIOCGLTC +inflow.c +@item TIOCGPGRP +inflow.c +@item TIOCLGET +inflow.c +@item TIOCLSET +inflow.c +@item TIOCNOTTY +inflow.c +@item UPAGES +altos-xdep.c +@item USE_O_NOCTTY +inflow.c + +@item USG +Means that System V (prior to SVR4) include files are in use. +(FIXME: This symbol is abused in @file{infrun.c}, @file{regex.c}, +@file{remote-nindy.c}, and @file{utils.c} for other things, at the moment.) + +@item WRS_ORIG +remote-vx.c +@item alloca +defs.h +@item const +defs.h + +@item lint +Define this to help lint in some stupid way. + +@item volatile +Define this to override the defaults of @code{__volatile__} or @code{/**/}. + +@end table + +Platform-specific host conditionals. + +@table @code + +@item ALTOS +altos-xdep.c +@item ALTOS_AS +xm-altos.h +@item MOTOROLA +xm-altos.h +@item NBPG +altos-xdep.c + +@item BCS +tm-delta88.h + +@item DELTA88 +m88k-xdep.c +@item DGUX +m88k-xdep.c + +@item F_OK +xm-ultra3.h + +@end table + +Regex conditionals. + +@table @code + +@item C_ALLOCA +regex.c +@item NFAILURES +regex.c +@item RE_NREGS +regex.h +@item SIGN_EXTEND_CHAR +regex.c +@item SWITCH_ENUM_BUG +regex.c +@item SYNTAX_TABLE +regex.c +@item Sword +regex.c +@item sparc +regex.c +@item test +regex.c + +@end table + +@node Target Conditionals +@chapter Target Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation based on the attributes of the target +system. These macros and their meanings are: + +@emph{NOTE: For now, both host and target conditionals are here. +Eliminate host conditionals from this list as they are identified.} + +@table @code + +@item PUSH_DUMMY_FRAME +Used in @samp{call_function_by_hand} to create an artificial stack frame. + +@item POP_FRAME +Used in @samp{call_function_by_hand} to remove an artificial stack frame. + +@item BLOCK_ADDRESS_FUNCTION_RELATIVE +dbxread.c +@item PYRAMID_CONTROL_FRAME_DEBUGGING +pyr-xdep.c +@item ADDITIONAL_OPTIONS +main.c +@item ADDITIONAL_OPTION_CASES +main.c +@item ADDITIONAL_OPTION_HANDLER +main.c +@item ADDITIONAL_OPTION_HELP +main.c + +@item ADDR_BITS_REMOVE (addr) +If a raw machine address includes any bits that are not really part +of the address, then define this macro to expand into an expression +that zeros those bits in @var{addr}. For example, the two low-order +bits of a Motorola 88K address may be used by some kernels for their +own purposes, since addresses must always be 4-byte aligned, and so +are of no use for addressing. Those bits should be filtered out with +an expression such as @code{((addr) & ~3)}. + +@item ALIGN_STACK_ON_STARTUP +main.c +@item ALTOS +altos-xdep.c +@item ALTOS_AS +xm-altos.h +@item BCS +tm-delta88.h + +@item BEFORE_MAIN_LOOP_HOOK +Define this to expand into any code that you want to execute before +the main loop starts. Although this is not, strictly speaking, +a target conditional, that is how it is currently being used. +Note that if a configuration were to define it one way for a host +and a different way for the target, GDB will probably not compile, +let alone run correctly. + +@item BELIEVE_PCC_PROMOTION +coffread.c +@item BELIEVE_PCC_PROMOTION_TYPE +stabsread.c + +@item BITS_BIG_ENDIAN +Define this if the numbering of bits in the targets does *not* match +the endianness of the target byte order. +A value of 1 means that the bits are numbered in a big-endian order, +0 means little-endian. + +@item BLOCK_ADDRESS_ABSOLUTE +dbxread.c +@item BREAKPOINT +tm-m68k.h + +@item CALL_DUMMY +valops.c +@item CALL_DUMMY_LOCATION +inferior.h +@item CALL_DUMMY_STACK_ADJUST +valops.c + +@item CANNOT_FETCH_REGISTER (regno) +A C expression that should be nonzero if @var{regno} cannot be +fetched from an inferior process. +This is only relevant if @code{FETCH_INFERIOR_REGISTERS} is not +defined. + +@item CANNOT_STORE_REGISTER (regno) +A C expression that should be nonzero if @var{regno} should not be +written to the target. This is often the case for program counters, +status words, and other special registers. If this is not defined, +GDB will assume that all registers may be written. + +@item CFRONT_PRODUCER +dwarfread.c + +@item DO_DEFERRED_STORES +@item CLEAR_DEFERRED_STORES +Define this to execute any deferred stores of registers into the inferior, +and to cancel any deferred stores. + +Currently only implemented correctly for native Sparc configurations? + +@item CPLUS_MARKER +Define this to expand into the character that G++ uses to +distinguish compiler-generated identifiers from programmer-specified +identifiers. By default, this expands into @code{'$'}. +Most System V targets should define this to @code{'.'}. + +@item DBX_PARM_SYMBOL_CLASS +stabsread.c + +@item DECR_PC_AFTER_BREAK +Define this to be the amount by which to decrement the PC after +the program encounters a breakpoint. +This is often the number of bytes in BREAKPOINT, though not always. +For most targets this value will be 0. + +@item DECR_PC_AFTER_HW_BREAK +Similarly, for hardware breakpoints. + +@item DELTA88 +m88k-xdep.c +@item DEV_TTY +symmisc.c +@item DGUX +m88k-xdep.c + +@item DISABLE_UNSETTABLE_BREAK addr +If defined, this should evaluate to 1 if @var{addr} is in a shared +library in which breakpoints cannot be set and so should be disabled. + +@item DO_REGISTERS_INFO +infcmd.c + +@item END_OF_TEXT_DEFAULT +This is an expression that should designate the end of the text section +(? FIXME ?) + +@item EXTRACT_RETURN_VALUE +tm-m68k.h +@item EXTRACT_STRUCT_VALUE_ADDRESS +values.c + +@item EXTRA_FRAME_INFO +If defined, this must be a list of slots that may be inserted into +the @code{frame_info} structure defined in @code{frame.h}. + +@item EXTRA_SYMTAB_INFO +If defined, this must be a list of slots that may be inserted into +the @code{symtab} structure defined in @code{symtab.h}. + +@item FILES_INFO_HOOK +target.c +@item FLOAT_INFO +infcmd.c +@item FP0_REGNUM +a68v-xdep.c +@item FPC_REGNUM +mach386-xdep.c +@item FP_REGNUM +parse.c +@item FRAMELESS_FUNCTION_INVOCATION +blockframe.c +@item FRAME_ARGS_ADDRESS_CORRECT +stack.c + +@item FRAME_CHAIN +Given FRAME, return a pointer to the calling frame. + +@item FRAME_CHAIN_COMBINE +blockframe.c +@item FRAME_CHAIN_VALID +frame.h +@item FRAME_CHAIN_VALID_ALTERNATE +frame.h +@item FRAME_FIND_SAVED_REGS +stack.c +@item FRAME_GET_BASEREG_VALUE +frame.h + +@item FRAME_NUM_ARGS (val, fi) +For the frame described by fi, set val to the number of arguments +that are being passed. + +@item FRAME_SPECIFICATION_DYADIC +stack.c + +@item FRAME_SAVED_PC +Given FRAME, return the pc saved there. That is, the return address. + +@item FUNCTION_EPILOGUE_SIZE +For some COFF targets, the @code{x_sym.x_misc.x_fsize} field of the +function end symbol is 0. For such targets, you must define +@code{FUNCTION_EPILOGUE_SIZE} to expand into the standard size +of a function's epilogue. + +@item GCC2_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_COMPILED_FLAG_SYMBOL +dbxread.c +@item GCC_MANGLE_BUG +symtab.c +@item GCC_PRODUCER +dwarfread.c + +@item GDB_TARGET_IS_HPPA +This determines whether horrible kludge code in dbxread.c and partial-stab.h +is used to mangle multiple-symbol-table files from HPPA's. This should all +be ripped out, and a scheme like elfread.c used. + +@item GDB_TARGET_IS_MACH386 +mach386-xdep.c +@item GDB_TARGET_IS_SUN3 +a68v-xdep.c +@item GDB_TARGET_IS_SUN386 +sun386-xdep.c + +@item GET_LONGJMP_TARGET +For most machines, this is a target-dependent parameter. On the DECstation +and the Iris, this is a native-dependent parameter, since is +needed to define it. + +This macro determines the target PC address that longjmp() will jump +to, assuming that we have just stopped at a longjmp breakpoint. It +takes a CORE_ADDR * as argument, and stores the target PC value through +this pointer. It examines the current state of the machine as needed. + +@item GET_SAVED_REGISTER +Define this if you need to supply your own definition for the +function @code{get_saved_register}. +Currently this is only done for the a29k. + +@item GPLUS_PRODUCER +dwarfread.c + +@item GR64_REGNUM +Very a29k-specific. + +@item HAVE_REGISTER_WINDOWS +Define this if the target has register windows. +@item REGISTER_IN_WINDOW_P regnum +Define this to be an expression that is 1 is the given register is +in the window. + +@item IBM6000_TARGET +Shows that we are configured for an IBM RS/6000 target. This conditional +should be eliminated (FIXME) and replaced by feature-specific macros. +It was introduced in haste and we are repenting at leisure. + +@item IEEE_FLOAT +Define this if the target system uses IEEE-format floating point numbers. + +@item IGNORE_SYMBOL type +This seems to be no longer used. + +@item INIT_EXTRA_FRAME_INFO (fromleaf, fci) +If defined, this should be a C expression or statement that fills +in the @code{EXTRA_FRAME_INFO} slots of the given frame @var{fci}. + +@item INIT_EXTRA_SYMTAB_INFO +symfile.c + +@item INIT_FRAME_PC (fromleaf, prev) +This is a C statement that sets the pc of the frame pointed +to by @var{prev}. [By default...] + +@item INNER_THAN +Define this to be either @code{<} if the target's stack grows +downward in memory, or @code{>} is the stack grows upwards. + +@item IN_SIGTRAMP pc name +Define this to return true if the given pc and/or name indicates +that the current function is a sigtramp. + +@item SIGTRAMP_START +@item SIGTRAMP_END +Define these to be the start and end address of the sigtramp. +These will be used if defined, and @code{IN_SIGTRAMP} is not; +otherwise the name of the sigtramp will be assumed to be @code{_sigtramp}. + +@item IN_SOLIB_TRAMPOLINE pc name +Define this to evaluate to nonzero if the program is stopped in +the trampoline that connects to a shared library. + +@item IS_TRAPPED_INTERNALVAR name +This is an ugly hook to allow the specification of special actions +that should occur as a side-effect of setting the value of a variable +internal to GDB. Currently only used by the h8500. +Note that this could be either a host or target conditional. + +@item KERNEL_DEBUGGING +tm-ultra3.h +@item LCC_PRODUCER +dwarfread.c +@item L_LNNO32 +coffread.c +@item MIPSEL +mips-tdep.c +@item MOTOROLA +xm-altos.h +@item NBPG +altos-xdep.c + +@item NEED_TEXT_START_END +Define this if GDB should determine the start and end addresses +of the text section. (Seems dubious.) + +@item NOTICE_SIGNAL_HANDLING_CHANGE +infrun.c +@item NO_HIF_SUPPORT +remote-mm.c +@item NO_SIGINTERRUPT +remote-adapt.c + +@item NO_SINGLE_STEP +Define this if the target does not support single-stepping. +If this is defined, you must supply, in @code{*-tdep.c}, the function +@code{single_step}, which takes a pid as argument and returns nothing. +It must insert breakpoints at each possible destinations of the next +instruction. See @code{sparc-tdep.c} and @code{rs6000-tdep.c} +for examples. + +@item NUMERIC_REG_NAMES +mips-tdep.c +@item N_SETV +dbxread.c +@item N_SET_MAGIC +hppabsd-tdep.c +@item ONE_PROCESS_WRITETEXT +breakpoint.c +@item PCC_SOL_BROKEN +dbxread.c +@item PC_IN_CALL_DUMMY +inferior.h +@item PC_LOAD_SEGMENT +stack.c + +@item PC_REGNUM +If the program counter is kept in a register, then define this macro +to be the number of that register. +This need be defined only if @code{TARGET_WRITE_PC} is not defined. + +@item NPC_REGNUM +The number of the ``next program counter'' register, if defined. + +@item NNPC_REGNUM +The number of the ``next next program counter'' register, if defined. +Currently, this is only defined for the Motorola 88K. + +@item PRINT_RANDOM_SIGNAL +infcmd.c +@item PRINT_REGISTER_HOOK +infcmd.c + +@item PRINT_TYPELESS_INTEGER +This is an obscure substitute for @code{print_longest} that +seems to have been defined for the Convex target. + +@item PROCESS_LINENUMBER_HOOK +buildsym.c +@item PROLOGUE_FIRSTLINE_OVERLAP +infrun.c +@item PS_REGNUM +parse.c +@item PUSH_ARGUMENTS +valops.c +@item REGISTER_BYTES +remote.c + +@item REGISTER_NAMES +Define this to expand into an initializer of an array of strings. +Each string is the name of a register. +[more detail] + +@item REG_STACK_SEGMENT +exec.c +@item REG_STRUCT_HAS_ADDR +findvar.c +@item R_FP +dwarfread.c +@item R_OK +xm-altos.h + +@item SDB_REG_TO_REGNUM +Define this to convert sdb register numbers +into GDB regnums. If not defined, no conversion will be done. + +@item SEEK_END +state.c +@item SEEK_SET +state.c +@item SEM +coffread.c +@item SHELL_COMMAND_CONCAT +infrun.c +@item SHELL_FILE +infrun.c +@item SHIFT_INST_REGS +breakpoint.c +@item SIGTRAP_STOP_AFTER_LOAD +infrun.c + +@item SKIP_PROLOGUE +A C statement that advances the PC across any function entry +prologue instructions so as to reach ``real'' code. + +@item SKIP_PROLOGUE_FRAMELESS_P +A C statement that should behave similarly, but that can stop +as soon as the function is known to have a frame. +If not defined, @code{SKIP_PROLOGUE} will be used instead. + +@item SKIP_TRAMPOLINE_CODE (pc) +If the target machine has trampoline code that sits between callers +and the functions being called, then define this macro to return +a new PC that is at the start of the real function. + +@item SP_REGNUM +parse.c + +@item STAB_REG_TO_REGNUM +Define this to convert stab register numbers (as gotten from `r' declarations) +into GDB regnums. If not defined, no conversion will be done. + +@item STACK_ALIGN +valops.c +@item STOP_SIGNAL +main.c + +@item STORE_RETURN_VALUE (type, valbuf) +A C expression that stores a function return value of type @var{type}, +where @var{valbuf} is the address of the value to be stored. + +@item SUN4_COMPILER_FEATURE +infrun.c +@item SUN_FIXED_LBRAC_BUG +dbxread.c +@item SVR4_SHARED_LIBS +solib.c +@item SYMBOL_RELOADING_DEFAULT +symfile.c + +@item TARGET_BYTE_ORDER +The ordering of bytes in the target. +This must be defined to be either @code{BIG_ENDIAN} or @code{LITTLE_ENDIAN}. + +@item TARGET_CHAR_BIT +Number of bits in a char; defaults to 8. + +@item TARGET_COMPLEX_BIT +Number of bits in a complex number; defaults to @code{2 * TARGET_FLOAT_BIT}. + +@item TARGET_DOUBLE_BIT +Number of bits in a double float; defaults to @code{8 * TARGET_CHAR_BIT}. + +@item TARGET_DOUBLE_COMPLEX_BIT +Number of bits in a double complex; defaults to @code{2 * TARGET_DOUBLE_BIT}. + +@item TARGET_FLOAT_BIT +Number of bits in a float; defaults to @code{4 * TARGET_CHAR_BIT}. + +@item TARGET_INT_BIT +Number of bits in an integer; defaults to @code{4 * TARGET_CHAR_BIT}. + +@item TARGET_LONG_BIT +Number of bits in a long integer; defaults to @code{4 * TARGET_CHAR_BIT}. + +@item TARGET_LONG_DOUBLE_BIT +Number of bits in a long double float; +defaults to @code{2 * TARGET_DOUBLE_BIT}. + +@item TARGET_LONG_LONG_BIT +Number of bits in a long long integer; defaults to @code{2 * TARGET_LONG_BIT}. + +@item TARGET_PTR_BIT +Number of bits in a pointer; defaults to @code{TARGET_INT_BIT}. + +@item TARGET_SHORT_BIT +Number of bits in a short integer; defaults to @code{2 * TARGET_CHAR_BIT}. + +@item TARGET_READ_PC +@item TARGET_WRITE_PC (val, pid) +@item TARGET_READ_SP +@item TARGET_WRITE_SP +@item TARGET_READ_FP +@item TARGET_WRITE_FP +These change the behavior of @code{read_pc}, @code{write_pc}, +@code{read_sp}, @code{write_sp}, @code{read_fp} and @code{write_fp}. +For most targets, these may be left undefined. GDB will call the +read and write register functions with the relevant @code{_REGNUM} argument. + +These macros are useful when a target keeps one of these registers in a +hard to get at place; for example, part in a segment register and part +in an ordinary register. + +@item USE_STRUCT_CONVENTION (gcc_p, type) +If defined, this must be an expression that is nonzero if a value +of the given @var{type} being returned from a function must have +space allocated for it on the stack. @var{gcc_p} is true if the +function being considered is known to have been compiled by GCC; +this is helpful for systems where GCC is known to use different calling +convention than other compilers. + +@item VARIABLES_INSIDE_BLOCK (desc, gcc_p) +For dbx-style debugging information, if the compiler puts variable +declarations inside LBRAC/RBRAC blocks, this should be defined +to be nonzero. @var{desc} is the value of @code{n_desc} from the +@code{N_RBRAC} symbol, and @var{gcc_p} is true if GDB has noticed +the presence of either the @code{GCC_COMPILED_SYMBOL} or the +@code{GCC2_COMPILED_SYMBOL}. +By default, this is 0. + +@item OS9K_VARIABLES_INSIDE_BLOCK (desc, gcc_p) +Similarly, for OS/9000. Defaults to 1. + +@item WRS_ORIG +remote-vx.c + +@item test +(Define this to enable testing code in regex.c.) + +@end table + +Motorola M68K target conditionals. + +@table @code + +@item BPT_VECTOR +Define this to be the 4-bit location of the breakpoint trap vector. +If not defined, it will default to @code{0xf}. + +@item REMOTE_BPT_VECTOR +Defaults to @code{1}. + +@end table + +@node Native Conditionals +@chapter Native Conditionals + +When GDB is configured and compiled, various macros are defined or left +undefined, to control compilation when the host and target systems +are the same. These macros should be defined (or left undefined) +in @file{nm-@var{system}.h}. + +@table @code + +@item ATTACH_DETACH +If defined, then GDB will include support for the @code{attach} and +@code{detach} commands. + +@item CHILD_PREPARE_TO_STORE +If the machine stores all registers at once in the child process, +then define this to ensure that all values are correct. +This usually entails a read from the child. + +[Note that this is incorrectly defined in @file{xm-@var{system}.h} +files currently.] + +@item FETCH_INFERIOR_REGISTERS +Define this if the native-dependent code will provide its +own routines +@code{fetch_inferior_registers} and @code{store_inferior_registers} in +@file{@var{HOST}-nat.c}. +If this symbol is @emph{not} defined, and @file{infptrace.c} +is included in this configuration, the default routines in +@file{infptrace.c} are used for these functions. + +@item GET_LONGJMP_TARGET +For most machines, this is a target-dependent parameter. On the DECstation +and the Iris, this is a native-dependent parameter, since is +needed to define it. + +This macro determines the target PC address that longjmp() will jump +to, assuming that we have just stopped at a longjmp breakpoint. It +takes a CORE_ADDR * as argument, and stores the target PC value through +this pointer. It examines the current state of the machine as needed. + +@item PROC_NAME_FMT +Defines the format for the name of a @file{/proc} device. Should be +defined in @file{nm.h} @emph{only} in order to override the default +definition in @file{procfs.c}. + +@item PTRACE_FP_BUG +mach386-xdep.c + +@item PTRACE_ARG3_TYPE +The type of the third argument to the @code{ptrace} system call, if it exists +and is different from @code{int}. + +@item REGISTER_U_ADDR +Defines the offset of the registers in the ``u area''; @pxref{Host}. + +@item SOLIB_ADD (filename, from_tty, targ) +Define this to expand into an expression that will cause the symbols +in @var{filename} to be added to GDB's symbol table. + +@item SOLIB_CREATE_INFERIOR_HOOK +Define this to expand into any shared-library-relocation code +that you want to be run just after the child process has been forked. + +@item START_INFERIOR_TRAPS_EXPECTED +When starting an inferior, GDB normally expects to trap twice; +once when the shell execs, and once when the program itself execs. +If the actual number of traps is something other than 2, then +define this macro to expand into the number expected. + +@item USE_PROC_FS +This determines whether small routines in @file{*-tdep.c}, which +translate register values +between GDB's internal representation and the /proc representation, +are compiled. + +@item U_REGS_OFFSET +This is the offset of the registers in the upage. It need only be +defined if the generic ptrace register access routines in +@file{infptrace.c} are being used (that is, +@file{infptrace.c} is configured in, and +@code{FETCH_INFERIOR_REGISTERS} is not defined). If the default value +from @file{infptrace.c} is good enough, leave it undefined. + +The default value means that u.u_ar0 @emph{points to} the location of the +registers. I'm guessing that @code{#define U_REGS_OFFSET 0} means that +u.u_ar0 @emph{is} the location of the registers. + +@item CLEAR_SOLIB +objfiles.c + +@item DEBUG_PTRACE +Define this to debug ptrace calls. + +@end table + +@node Obsolete Conditionals +@chapter Obsolete Conditionals + +Fragments of old code in GDB sometimes reference or set the following +configuration macros. They should not be used by new code, and +old uses should be removed as those parts of the debugger are +otherwise touched. + +@table @code + +@item STACK_END_ADDR +This macro used to define where the end of the stack appeared, for use +in interpreting core file formats that don't record this address in the +core file itself. This information is now configured in BFD, and GDB +gets the info portably from there. The values in GDB's configuration +files should be moved into BFD configuration files (if needed there), +and deleted from all of GDB's config files. + +Any @file{@var{foo}-xdep.c} file that references STACK_END_ADDR +is so old that it has never been converted to use BFD. Now that's old! + +@end table + +@node XCOFF +@chapter The XCOFF Object File Format + +The IBM RS/6000 running AIX uses an object file format called xcoff. +The COFF sections, symbols, and line numbers are used, but debugging +symbols are dbx-style stabs whose strings are located in the +@samp{.debug} section (rather than the string table). For more +information, @xref{Top,,,stabs,The Stabs Debugging Format}, and search +for XCOFF. + +The shared library scheme has a nice clean interface for figuring out +what shared libraries are in use, but the catch is that everything which +refers to addresses (symbol tables and breakpoints at least) needs to be +relocated for both shared libraries and the main executable. At least +using the standard mechanism this can only be done once the program has +been run (or the core file has been read). + +@contents +@bye diff --git a/contrib/gdb/gdb/doc/h8-cfg.texi b/contrib/gdb/gdb/doc/h8-cfg.texi new file mode 100644 index 000000000000..823c7c244b5a --- /dev/null +++ b/contrib/gdb/gdb/doc/h8-cfg.texi @@ -0,0 +1,47 @@ +@c GDB version number is recorded in the variable GDBVN +@include GDBvn.texi +@c +@set AGGLOMERATION +@clear AMD29K +@set BARETARGET +@clear CONLY +@set DOSHOST +@clear FORTRAN +@clear FSFDOC +@clear GDBSERVER +@clear GENERIC +@set H8 +@set H8EXCLUSIVE +@clear HAVE-FLOAT +@clear I960 +@clear MOD2 +@clear NOVEL +@clear POSIX +@set PRECONFIGURED +@clear REMOTESTUB +@set SIMS +@clear SERIAL +@clear SPARC +@clear ST2000 +@clear VXWORKS +@clear Z8K +@c ---------------------------------------------------------------------- +@c STRINGS: +@c +@c Name of GDB program. Used also for (gdb) prompt string. +@set GDBP gdb +@c +@c Name of GDB product. Used in running text. +@set GDBN GDB +@c +@c Name of GDB initialization file. +@set GDBINIT .gdbinit +@c +@c Name of target. +@set TARGET Hitachi Microprocessors +@c +@c Name of GCC product +@set NGCC GCC +@c +@c Name of GCC program +@set GCC gcc diff --git a/contrib/gdb/gdb/doc/libgdb.texinfo b/contrib/gdb/gdb/doc/libgdb.texinfo new file mode 100644 index 000000000000..4fadcb2c9b58 --- /dev/null +++ b/contrib/gdb/gdb/doc/libgdb.texinfo @@ -0,0 +1,878 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename libgdb.info +@settitle Libgdb +@setchapternewpage off +@c %**end of header + +@ifinfo +This file documents libgdb, the GNU symbolic debugger in a library. + +This is Edition 0.3, Oct 1993, of @cite{Libgdb}. +Copyright 1993 Cygnus Support + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@c This title page illustrates only one of the +@c two methods of forming a title page. + +@titlepage +@title Libgdb +@subtitle Version 0.3 +@subtitle Oct 1993 +@author Thomas Lord + +@c The following two commands +@c start the copyright page. +@page +@vskip 0pt plus 1filll +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Copyright @copyright{} 1993 Cygnus Support +@end titlepage + +@ifinfo +@node Top, Overview, (dir), (dir) + +This info file documents libgdb: an API for GDB, the GNU symbolic debugger. + +@menu +* Overview:: The basics of libgdb and this document. +* Interpreter:: Libgdb is an Interpreter-Based Server. +* Top Level:: You Provide the Top Level for the Libgdb + Command Interpreter . +* I/O:: How the Server's I/O Can be Used. +* Invoking:: Invoking the Interpreter, Executing + Commands. +* Defining Commands:: How New Commands are Created. +* Variables:: How Builtin Variables are Defined. +* Asynchronous:: Scheduling Asynchronous Computations. +* Commands:: Debugger Commands for Libgdb Applications +@end menu + +@end ifinfo +@node Overview, Interpreter, top, top +@comment node-name, next, previous, up +@chapter Overview +@cindex overview +@cindex definitions + +@heading Function and Purpose + +Libgdb is a package which provides an API to the functionality of GDB, +the GNU symbolic debugger. It is specifically intended to support the +development of a symbolic debugger with a graphic interface. + + +@heading This Document + +This document is a specification of the libgdb API. It is written in +the form of a programmer's manual. So the goal of this document is to +explain what functions make up the API, and how they can be used in a +running application. + + +@heading Terminology + +In this document, @dfn{libgdb} refers to a library containing the +functions defined herein, @dfn{application} refers to any program built +with that library. + + +@heading Dependencies + +Programs which are linked with libgdb must be linked with libbfd, +libopcodes, libiberty, and libmmalloc. + +@heading Acknowledgments + +Essential contributions to this design were made by Stu Grossman, Jim +Kingdon, and Rich Pixley. + +@node Interpreter, Top Level, Overview, Top +@comment node-name, next, previous, up +@chapter Libgdb is an Interpreter Based Server +@cindex interpreter +@cindex server + +To understand libgdb, it is necessary to understand how the library is +structured. Historically, GDB is written as a small interpreter for a +simple command language. The commands of the language perform useful +debugging functions. + +Libgdb is built from GDB by turning the interpreter into a debugging +server. The server reads debugging commands from any source and +interprets them, directing the output arbitrarily. + +In addition to changing GDB from a tty-based program to a server, a +number of new GDB commands have been added to make the server more +useful for a program with a graphic interface. + +Finally, libgdb includes provisions for asynchronous processing within +the application. + +Most operations that can be carried out with libgdb involve the GDB +command interpreter. The usual mode of operation is that the operation +is expressed as a string of GDB commands, which the interpreter is then +invoked to carry out. The output from commands executed in this manner +can be redirected in a variety of useful ways for further processing by +the application. + +The command interpreter provides an extensive system of hooks so an +application can monitor any aspect of the debugging library's state. An +application can set its own breakpoints and attach commands and +conditions to those. It is possible to attach hooks to any debugger +command; the hooks are invoked whenever that command is about to be +invoked. By means of these, the displays of a graphical interface can +be kept fully up to date at all times. + +We show you how to define new primitives in the command language. By +defining new primitives and using them in breakpoint scripts and command +hooks, an application can schedule the execution of arbitrary C-code at +almost any point of interest in the operation of libgdb. + +We show you how to define new GDB convenience variables for which your +code computes a value on demand. Referring to such variables in a +breakpoint condition is a convenient way to conditionalize breakpoints +in novel ways. + +To summarize: in libgdb, the gdb command language is turned into a +debugging server. The server takes commands as input, and the server's +output is redirectable. An application uses libgdb by formatting +debugging commands and invoking the interpreter. The application might +maintain breakpoints, watchpoints and many kinds of hooks. An application +can define new primitives for the interpreter. + +@node Top Level, I/O, Interpreter, Top +@chapter You Provide the Top Level for the Libgdb Command Interpreter +@cindex {top level} + +When you use libgdb, your code is providing a @dfn{top level} for the +command language interpreter. The top level is significant because it +provides commands for the the interpreter to execute. In addition, the +top level is responsible for handling some kinds of errors, and +performing certain cleanup operations on behalf of the interpreter. + +@heading Initialization + +Before calling any other libgdb functions, call this: + +@deftypefun void gdb_init (void) +Perform one-time initialization for libgdb. +@end deftypefun + +An application may wish to evaluate specific gdb commands as part of its +own initialization. The details of how this can be accomplished are +explained below. + +@heading The Top-Level Loop + +There is a strong presumption in libgdb that the application has +the form of a loop. Here is what such a loop might look like: + +@example +while (gdb_still_going ()) + @{ + if (!GDB_TOP_LEVEL ()) + @{ + char * command; + gdb_start_top_loop (); + command = process_events (); + gdb_execute_command (command); + gdb_finish_top_loop (); + @} + @} +@end example + +The function @code{gdb_still_going} returns 1 until the gdb command +`quit' is run. + +The macro @code{GDB_TOP_LEVEL} invokes setjmp to set the top level error +handler. When a command results in an error, the interpreter exits with +a longjmp. There is nothing special libgdb requires of the top level +error handler other than it be present and that it restart the top level +loop. Errors are explained in detail in a later chapter. + +Each time through the top level loop two important things happen: a +debugger command is constructed on the basis of user input, and the +interpreter is invoked to execute that command. In the sample code, the +call to the imaginary function @code{process_events} represents the +point at which a graphical interface should read input events until +ready to execute a debugger command. The call to +@code{gdb_execute_command} invokes the command interpreter (what happens +to the output from the command will be explained later). + +Libgdb manages some resources using the top-level loop. The primary +reason for this is error-handling: even if a command terminates with an +error, it may already have allocated resources which need to be freed. +The freeing of such resources takes place at the top-level, regardless +of how the the command exits. The calls to @code{gdb_start_top_loop} +and @code{gdb_finish_top_loop} let libgdb know when it is safe to +perform operations associated with these resources. + +@heading Breakpoint Commands + +Breakpoint commands are scripts of GDB operations associated with +particular breakpoints. When a breakpoint is reached, its associated +commands are executed. + +Breakpoint commands are invoked by the libgdb function +@code{gdb_finish_top_loop}. + +Notice that if control returns to the top-level error handler, the +execution of breakpoint commands is bypassed. This can happen as a +result of errors during either @code{gdb_execute_command} or +@code{gdb_finish_top_loop}. + +@heading Application Initialization + +Sometimes it is inconvenient to execute commands via a command loop for +example, the commands an application uses to initialize itself. An +alternative to @code{execute_command} is @code{execute_catching_errors}. +When @code{execute_catching_errors} is used, no top level error handler +need be in effect, and it is not necessary to call +@code{gdb_start_top_loop} or @code{gdb_finish_top_loop}. + + +@heading Cleanup + +The debugger command ``quit'' performs all necessary cleanup for libgdb. +After it has done so, it changes the return value of +@code{gdb_still_going} to 0 and returns to the top level error handler. + + +@node I/O, Invoking, Top Level, Top +@comment node-name, next, previous, up +@chapter How the Server's I/O Can be Used +@cindex I/O + +In the last chapter it was pointed out that a libgdb application is +responsible for providing commands for the interpreter to execute. +However some commands require further input (for example, the ``quit'' +command might ask for confirmation). Almost all commands produce output +of some kind. The purpose of this section is to explain how libgdb +performs its I/O, and how an application can take advantage of +this. + + +@heading I/O Vectors + +Libgdb has no fixed strategy for I/O. Instead, all operations are +performed by functions called via structures of function pointers. +Applications supply theses structures and can change them at any +time. + +@deftp Type {struct gdb_input_vector} +@deftpx Type {struct gdb_output_vector} +These structures contain a set of function pointers. Each function +determines how a particular type of i/o is performed. The details of +these strucutres are explained below. + +The application allocates these structures, initializes them to all bits +zero, fills in the function pointers, and then registers names for them +them with libgdb. +@end deftp + +@deftypefun void gdb_name_input_vector (@var{name}, @var{vec}) +@deftypefunx void gdb_remove_input_vector (@var{name}, @var{vec}) +@deftypefunx void gdb_name_output_vector (@var{name}, @var{vec}) +@deftypefunx void gdb_remove_input_vector (@var{name}, @var{vec}) +@example + char * @var{name}; + struct gdb_output_vector * @var{vec}; +@end example +These functions are used to give and remove names to i/o vectors. Note +that if a name is used twice, the most recent definition applies. +@end deftypefun + + + +@subheading Output + +An output vector is a structure with at least these fields: + +@example +struct gdb_output_vector +@{ + /* output */ + void (*put_string) (struct gdb_output_vector *, char * str); +@} +@end example + +Use the function @code{memset} or something equivalent to initialize an +output vector to all bits zero. Then fill in the function pointer with +your function. + +A debugger command can produce three kinds of output: error messages +(such as when trying to delete a non-existent breakpoint), informational +messages (such as the notification printed when a breakpoint is hit), +and the output specifically requested by a command (for example, the +value printed by the ``print'' command). At any given time, then, +libgdb has three output vectors. These are called the @dfn{error}, +@dfn{info}, @dfn{value} vector respectively. + +@subheading Input + +@example +struct gdb_input_vector +@{ + int (*query) (struct gdb_input_vector *, + char * prompt, + int quit_allowed); + int * (*selection) (struct gdb_input_vector *, + char * prompt, + char ** choices); + char * (*read_string) (struct gdb_input_vector *, + char * prompt); + char ** (*read_strings) (struct gdb_input_vector *, + char * prompt); +@} +@end example + +Use the function @code{memset} or something equivalent to initialize an +input vector to all bits zero. Then fill in the function pointers with +your functions. + +There are four kinds of input requests explicitly made by libgdb. + +A @dfn{query} is a yes or no question. The user can respond to a query +with an affirmative or negative answer, or by telling gdb to abort the +command (in some cases an abort is not permitted). Query should return +'y' or 'n' or 0 to abort. + +A @dfn{selection} is a list of options from which the user selects a subset. +Selections should return a NULL terminated array of integers, which are +indexes into the array of choices. It can return NULL instead to abort +the command. The array returned by this function will be passed to +@code{free} by libgdb. + +A @dfn{read_string} asks the user to supply an arbitrary string. It may +return NULL to abort the command. The string returned by @code{read_string} +should be allocated by @code{malloc}; it will be freed by libgdb. + +A @dfn{read_strings} asks the user to supply multiple lines of input +(for example, the body of a command created using `define'). It, too, +may return NULL to abort. The array and the strings returned by this +function will be freed by libgdb. + +@heading I/O Redirection from the Application Top-Level + +@deftypefun struct gdb_io_vecs gdb_set_io (struct gdb_io_vecs *) +@example + +struct gdb_io_vecs +@{ + struct gdb_input_vector * input; + struct gdb_output_vector * error; + struct gdb_output_vector * info; + struct gdb_output_vector * value; +@} +@end example + +This establishes a new set of i/o vectors, and returns the old setting. +Any of the pointers in this structure may be NULL, indicating that the +current value should be used. + +This function is useful for setting up i/o vectors before any libgdb +commands have been invoked (hence before any input or output has taken +place). +@end deftypefun + +It is explained in a later chapter how to redirect output temporarily. +(@xref{Invoking}.) + +@heading I/O Redirection in Debugger Commands + +A libgdb application creates input and output vectors and assigns them names. +Which input and output vectors are used by libgdb is established by +executing these debugger commands: + +@defun {set input-vector} name +@defunx {set error-output-vector} name +@defunx {set info-output-vector} name +@defunx {set value-output-vector} name +Choose an I/O vector by name. +@end defun + + +A few debugger commands are for use only within commands defined using +the debugger command `define' (they have no effect at other times). +These commands exist so that an application can maintain hooks which +redirect output without affecting the global I/O vectors. + +@defun with-input-vector name +@defunx with-error-output-vector name +@defunx with-info-output-vector name +@defunx with-value-output-vector name +Set an I/O vector, but only temporarily. The setting has effect only +within the command definition in which it occurs. +@end defun + + +@heading Initial Conditions + +When libgdb is initialized, a set of default I/O vectors is put in +place. The default vectors are called @code{default-input-vector}, +@code{default-output-vector}, &c. + +The default query function always returns `y'. Other input functions +always abort. The default output functions discard output silently. + + +@node Invoking, Defining Commands, I/O, Top +@chapter Invoking the Interpreter, Executing Commands +@cindex {executing commands} +@cindex {invoking the interpreter} + +This section introduces the libgdb functions which invoke the command +interpreter. + +@deftypefun void gdb_execute_command (@var{command}) +@example +char * @var{command}; +@end example +Interpret the argument debugger command. An error handler must be set +when this function is called. (@xref{Top Level}.) +@end deftypefun + +It is possible to override the current I/O vectors for the duration of a +single command: + +@deftypefun void gdb_execute_with_io (@var{command}, @var{vecs}) +@example +char * @var{command}; +struct gdb_io_vecs * @var{vecs}; + +struct gdb_io_vecs +@{ + struct gdb_input_vector * input; + struct gdb_output_vector * error; + struct gdb_output_vector * info; + struct gdb_output_vector * value; +@} +@end example + +Execute @var{command}, temporarily using the i/o vectors in @var{vecs}. + +Any of the vectors may be NULL, indicating that the current value should +be used. An error handler must be in place when this function is used. +@end deftypefun + +@deftypefun {struct gdb_str_output} gdb_execute_for_strings (@var{cmd}) +@example +char * cmd; +@end example +@deftypefunx {struct gdb_str_output} gdb_execute_for_strings2 (@var{cmd}, @var{input}) +@example +char * cmd; +struct gdb_input_vector * input; +@end example +@page +@example +struct gdb_str_output +@{ + char * error; + char * info; + char * value; +@}; +@end example + +Execute @var{cmd}, collecting its output as strings. If no error +occurs, all three strings will be present in the structure, the +empty-string rather than NULL standing for no output of a particular +kind. + +If the command aborts with an error, then the @code{value} field will be +NULL, though the other two strings will be present. + +In all cases, the strings returned are allocated by malloc and should be +freed by the caller. + +The first form listed uses the current input vector, but overrides the +current output vector. The second form additionally allows the input +vector to be overridden. + +This function does not require that an error handler be installed. +@end deftypefun + +@deftypefun void execute_catching_errors (@var{command}) +@example +char * @var{command}; +@end example +Like @code{execute_command} except that no error handler is required. +@end deftypefun + +@deftypefun void execute_with_text (@var{command}, @var{text}) +@example +char * @var{command}; +char ** @var{text}; +@end example +Like @code{execute_catching_errors}, except that the input vector is +overridden. The new input vector handles only calls to @code{query} (by +returning 'y') and calls to @code{read_strings} by returning a copy of +@var{text} and the strings it points to. + +This form of execute_command is useful for commands like @code{define}, +@code{document}, and @code{commands}. +@end deftypefun + + + +@node Defining Commands, Variables, Invoking, Top +@comment node-name, next, previous, up +@chapter How New Commands are Created +@cindex {commands, defining} + +Applications are, of course, free to take advantage of the existing GDB +macro definition capability (the @code{define} and @code{document} +functions). + +In addition, an application can add new primitives to the GDB command +language. + +@deftypefun void gdb_define_app_command (@var{name}, @var{fn}, @var{doc}) +@example +char * @var{name}; +gdb_cmd_fn @var{fn}; +char * @var{doc}; + +typedef void (*gdb_cmd_fn) (char * args); +@end example + +Create a new command call @var{name}. The new command is in the +@code{application} help class. When invoked, the command-line arguments +to the command are passed as a single string. + +Calling this function twice with the same name replaces an earlier +definition, but application commands can not replace builtin commands of +the same name. + +The documentation string of the command is set to a copy the string +@var{doc}. +@end deftypefun + +@node Variables, Asynchronous, Defining Commands, Top +@comment node-name, next, previous, up +@chapter How Builtin Variables are Defined +@cindex {variables, defining} + +Convenience variables provide a way for values maintained by libgdb to +be referenced in expressions (e.g. @code{$bpnum}). Libgdb includes a +means by which the application can define new, integer valued +convenience variables: +@page +@deftypefun void gdb_define_int_var (@var{name}, @var{fn}, @var{fn_arg}) +@example +char * @var{name}; +int (*@var{fn}) (void *); +void * @var{fn_arg}; +@end example +This function defines (or undefines) a convenience variable called @var{name}. +If @var{fn} is NULL, the variable becomes undefined. Otherwise, +@var{fn} is a function which, when passed @var{fn_arg} returns the value +of the newly defined variable. + +No libgdb functions should be called by @var{fn}. +@end deftypefun + +One use for this function is to create breakpoint conditions computed in +novel ways. This is done by defining a convenience variable and +referring to that variable in a breakpoint condition expression. + + +@node Asynchronous, Commands, Variables, Top +@chapter Scheduling Asynchronous Computations +@cindex asynchronous + + +A running libgdb function can take a long time. Libgdb includes a hook +so that an application can run intermittently during long debugger +operations. + +@deftypefun void gdb_set_poll_fn (@var{fn}, @var{fn_arg}) +@example +void (*@var{fn})(void * fn_arg, int (*gdb_poll)()); +void * @var{fn_arg}; +@end example +Arrange to call @var{fn} periodically during lengthy debugger operations. +If @var{fn} is NULL, polling is turned off. @var{fn} should take two +arguments: an opaque pointer passed as @var{fn_arg} to +@code{gdb_set_poll_fn}, and a function pointer. The function pointer +passed to @var{fn} is provided by libgdb and points to a function that +returns 0 when the poll function should return. That is, when +@code{(*gdb_poll)()} returns 0, libgdb is ready to continue @var{fn} +should return quickly. + +It is possible that @code{(*gdb_poll)()} will return 0 the first time it +is called, so it is reasonable for an application to do minimal processing +before checking whether to return. + +No libgdb functions should be called from an application's poll function, +with one exception: @code{gdb_request_quit}. +@end deftypefun + + +@deftypefun void gdb_request_quit (void) +This function, if called from a poll function, requests that the +currently executing libgdb command be interrupted as soon as possible, +and that control be returned to the top-level via an error. + +The quit is not immediate. It will not occur until at least after the +application's poll function returns. +@end deftypefun + +@node Commands, Top, Asynchronous, Top +@comment node-name, next, previous, up +@chapter Debugger Commands for Libgdb Applications + +The debugger commands available to libgdb applications are the same commands +available interactively via GDB. This section is an overview of the +commands newly created as part of libgdb. + +This section is not by any means a complete reference to the GDB command +language. See the GDB manual for such a reference. + +@menu +* Command Hooks:: Setting Hooks to Execute With Debugger Commands. +* View Commands:: View Commands Mirror Show Commands +* Breakpoints:: The Application Can Have Its Own Breakpoints +@end menu + +@node Command Hooks, View Commands, Commands, Commands +@comment node-name, next, previous, up +@section Setting Hooks to Execute With Debugger Commands. + +Debugger commands support hooks. A command hook is executed just before +the interpreter invokes the hooked command. + +There are two hooks allowed for every command. By convention, one hook +is for use by users, the other is for use by the application. + +A user hook is created for a command XYZZY by using +@code{define-command} to create a command called @code{hook-XYZZY}. + +An application hook is created for a command XYZZY by using +@code{define-command} to create a command called @code{apphook-XYZZY}. + +Application hooks are useful for interfaces which wish to continuously +monitor certain aspects of debugger state. The application can set a +hook on all commands that might modify the watched state. When the hook +is executed, it can use i/o redirection to notify parts of the +application that previous data may be out of date. After the top-level loop +resumes, the application can recompute any values that may have changed. +(@xref{I/O}.) + +@node View Commands, Breakpoints, Command Hooks, Commands +@comment node-name, next, previous, up +@section View Commands Mirror Show Commands + +The GDB command language contains many @code{set} and @code{show} +commands. These commands are used to modify or examine parameters to +the debugger. + +It is difficult to get the current state of a parameter from the +@code{show} command because @code{show} is very verbose. + +@example +(gdb) show check type +Type checking is "auto; currently off". +(gdb) show width +Number of characters gdb thinks are in a line is 80. +@end example + +For every @code{show} command, libgdb includes a @code{view} command. +@code{view} is like @code{show} without the verbose commentary: + +@example +(gdb) view check type +auto; currently off +(gdb) view width +80 +@end example + +(The precise format of the ouput from @code{view} is subject to change. +In particular, @code{view} may one-day print values which can be used as +arguments to the corresponding @code{set} command.) + +@node Breakpoints, Structured Output, View Commands, Commands +@comment node-name, next, previous, up +@section The Application Can Have Its Own Breakpoints + +The GDB breakpoint commands were written with a strong presumption that +all breakpoints are managed by a human user. Therefore, the command +language contains commands like `delete' which affect all breakpoints +without discrimination. + +In libgdb, there is added support for breakpoints and watchpoints which +are set by the application and which should not be affected by ordinary, +indiscriminate commands. These are called @dfn{protected} breakpoints. + +@deffn {Debugger Command} break-protected ... +@deffnx {Debugger Command} watch-protected ... +These work like @code{break} and @code{watch} except that the resulting +breakpoint is given a negative number. Negative numbered breakpoints do +not appear in the output of @code{info breakpoints} but do in that of +@code{info all-breakpoints}. Negative numbered breakpoints are not +affected by commands which ordinarily affect `all' breakpoints (e.g. +@code{delete} with no arguments). + +Note that libgdb itself creates protected breakpoints, so programs +should not rely on being able to allocate particular protected +breakpoint numbers for themselves. +@end deffn + +More than one breakpoint may be set at a given location. Libgdb adds +the concept of @dfn{priority} to breakpoints. A priority is an integer, +assigned to each breakpoint. When a breakpoint is reached, the +conditions of all breakpoints at the same location are evaluated in +order of ascending priority. When breakpoint commands are executed, +they are also executed in ascending priority (until all have been +executed, an error occurs, or one set of commands continues the +target). + +@deffn {Debugger Command} priority n bplist +Set the priority for breakpoints @var{bplist} to @var{n}. +By default, breakpoints are assigned a priority of zero. +@end deffn + +@node Structured Output, Commands, Breakpoints, Commands +@comment node-name, next, previous, up +@section Structured Output, The @code{Explain} Command + +(This section may be subject to considerable revision.) + +When GDB prints a the value of an expression, the printed representation +contains information that can be usefully fed back into future commands +and expressions. For example, + +@example +(gdb) print foo +$16 = @{v = 0x38ae0, v_length = 40@} +@end example + +On the basis of this output, a user knows, for example, that +@code{$16.v} refers to a pointer valued @code{0x38ae0} + +A new output command helps to make information like this available to +the application. + +@deffn {Debugger Command} explain expression +@deffnx {Debugger Command} explain /format expression +Print the value of @var{expression} in the manner of the @code{print} +command, but embed that output in a list syntax containing information +about the structure of the output. +@end deffn + +As an example, @code{explain argv} might produce this output: + +@example +(exp-attribute + ((expression "$19") + (type "char **") + (address "48560") + (deref-expression "*$19")) + "$19 = 0x3800\n") +@end example + +The syntax of output from @code{explain} is: + +@example + := + | (exp-concat *) + | (exp-attribute ) + + := ( * ) + + := ( ) +@end example + +The string-concatenation of all of the @code{} (except +those in property lists) yields the output generated by the equivalent +@code{print} command. Quoted strings may contain quotes and backslashes +if they are escaped by backslash. "\n" in a quoted string stands for +newline; unescaped newlines do not occur within the strings output by +@code{explain}. + +Property names are made up of alphabetic characters, dashes, and +underscores. + +The set of properties is open-ended. As GDB acquires support for new +source languages and other new capabilities, new property types may be +added to the output of this command. Future commands may offer +applications some selectivity concerning which properties are reported. + +The initial set of properties defined includes: + +@itemize @bullet +@item @code{expression} + +This is an expression, such as @code{$42} or @code{$42.x}. The +expression can be used to refer to the value printed in the attributed +part of the string. + +@item @code{type} + +This is a user-readable name for the type of the attributed value. + +@item @code{address} + +If the value is stored in a target register, this is a register number. +If the value is stored in a GDB convenience variable, this is an integer +that is unique among all the convenience variables. Otherwise, this is +the address in the target where the value is stored. + +@item @code{deref-expression} + +If the attributed value is a pointer type, this is an expression that +refers to the dereferenced value. +@end itemize + +Here is a larger example, using the same object passed to @code{print} +in an earlier example of this section. + +@example +(gdb) explain foo +(exp-attribute + ( (expression "$16") + (type "struct bytecode_vector") + (address 14336) ) + (exp-concat + "$16 = @{" + (exp-attribute + ( (expression "$16.v") + (type "char *") + (address 14336) + (deref-expression "*$16.v") ) + "v = 0x38ae0") + (exp-attribute + ( (expression "$16.v_length") + (type "int") + (address 14340) ) + ", v_length = 40") + "@}\n")) +@end example + +It is undefined how libgdb will indent these lines of output or +where newlines will be included. + +@bye diff --git a/contrib/gdb/gdb/doc/lpsrc.sed b/contrib/gdb/gdb/doc/lpsrc.sed new file mode 100644 index 000000000000..1c7af4aaf48f --- /dev/null +++ b/contrib/gdb/gdb/doc/lpsrc.sed @@ -0,0 +1,13 @@ +/font defs: ---/,/end font defs ---/c\ +%-------------------- PostScript (long names) font defs: -----------------\ +\\font\\bbf=Times-Bold at 10pt\ +\\font\\vbbf=Times-Bold at 12pt\ +\\font\\smrm=Times-Roman at 6pt\ +\\font\\brm=Times-Roman at 10pt\ +\\font\\rm=Times-Roman at 8pt\ +\\font\\it=Times-Italic at 8pt\ +\\font\\tt=Courier at 8pt\ +% Used only for \copyright, replacing plain TeX macro.\ +\\font\\sym=Symbol at 7pt\ +\\def\\copyright{{\\sym\\char'323}}\ +%-------------------- end font defs --------------------------------- diff --git a/contrib/gdb/gdb/doc/psrc.sed b/contrib/gdb/gdb/doc/psrc.sed new file mode 100644 index 000000000000..9bb557eae21e --- /dev/null +++ b/contrib/gdb/gdb/doc/psrc.sed @@ -0,0 +1,13 @@ +/font defs: ---/,/end font defs ---/c\ +%-------------------- PostScript (K Berry names) font defs: --------------\ +\\font\\bbf=ptmb at 10pt\ +\\font\\vbbf=ptmb at 12pt\ +\\font\\smrm=ptmr at 6pt\ +\\font\\brm=ptmr at 10pt\ +\\font\\rm=ptmr at 8pt\ +\\font\\it=ptmri at 8pt\ +\\font\\tt=pcrr at 8pt\ +% Used only for \copyright, replacing plain TeX macro.\ +\\font\\sym=psyr at 7pt\ +\\def\\copyright{{\\sym\\char'323}}\ +%-------------------- end font defs --------------------------------- diff --git a/contrib/gdb/gdb/doc/refcard.dvi b/contrib/gdb/gdb/doc/refcard.dvi new file mode 100644 index 0000000000000000000000000000000000000000..e152395d31db024bdbcf82bfe7ac05fcc86b488c GIT binary patch literal 21732 zcmcIseXJZ;b$@mslsKU@Aq^j)O_K=hv3Np zi+^?WiG?e%n}074yRB1u_x;_ycfa%T%O1G%eGk0r@Vm|NBljFRe&p!kBO5RO$OkXI z>`x8_pI^9~i}CkmVK;l*Q&?`^zwz877oseW)5N@WxcT$?$Z!Ui8q4B~i@PL2$Fur}#%N~3DtEpMZOwcVaExh|*J~*h(#*%FBo(m67LX&1D zy72IDIOIvMX@Bj~Wq)m+I9>rGRkx4YQLDegqnc1JJUHs-ak5f|X%@Bn-CpSf96otf zO~ANC+Hm5PooIaE!o!p0ei9boP<`?!j|#H7l|{kH-kIC4PvhjwH=Zp_P?&1D!I^Pl z2u83Te#WtAob?lXMv$F({HrUSI4^w4MtKora>4*$(|%@pS-O%1UBXYGU>7j62tXTPPHPyn()vA5~d08D!`(CL{z|(1QIe+ zBsT#h9)Kh|B|PfHNwjG4BI@m^ zoi&(-+BXTdcd)Ud)NAE|6;OofZi<sx{B;D4!NKi*7`07{Dgg0rysrJV23Q`v zdG$M<^Las9mX=ndPOouV9%iwSqGyUlF%+pud%ShRl+Ek@_*uv9RKz^X?nnEvulCWY zShNG|K4^kYo|^HaW&|?EN8Wpn8SRW#%=qw9d$db%z2X(uSGd0G=>12IAAjK3{T`lJ zPW-SV9PKhily&1IC?XT~vkW$ocRy5XxClFCSpsX>=B^?&PPvtPA?}78dxO)Wd!xcB z(XWz2wH8e=jHW_3)d^sYbKW<5@Ras&pQumBl^!W+5-pLxgwl@4e&w@S26G%N6DLlt zZvSxe)z8)@rUnlKrj&bUC|nV%;@~eD*3vw3Dhm4~oX8B|T4?Kzsjc&PVC|)6^t`jG zi#269^o}+6c%}$2=K?v`G`Mn6Rmvsod$!W=MoC#%=1>}d0@nQPqm}*u@@Z0i>GB;< zwC=1t8N6sW-n-|E2Oi({h0h-_2ZkG0KXB9d?UOiJ=IZgC69fy(b8&)x`A$G^iW3AD zP&NrLEIM#)aTbL|)E1-=9Mq=wWZda^!1+%y-BV0D81DN_y{RY$BENRD=I!n0qC6A) zYDPg0)7yp>M5SjP!I=DrW}famn5Q5Y|aZ}G%uMpV!(!4gk` z-4ayP?G+I2pcW#`jEb)&IA2ZI=Ri`22gfpCXkoR$6lDcq7DANxECXDey-tq96B($` zTAZbc=#o0mEDl;TE`aE84}h7;THyO&52EjUw}kBWdsn~;!vTl%GF(NUfl)zvBRXn_ zFQ}ID6yMTff{n`XdSo5!%N z3L5*oVZgH*Br6fIUxz_H3A#$X8)-Hui?p2JUp%E2TyLGX28znqa&!!=02HBr7D97p zH#ix|jj!*v2Z^BvaeQdZb)y@bdvizIB<%XRc`AorO8dBx>O_N%)B4B0y}!s$Z|u0^OEt0^ufOBdPeGrI=okbSKlT(7 zpuLO44ga%m(cr&tG535L$wwAN=0v(&0Izi%Cj{S967_)If6=@v33qS2>I+XCJNNDV zbh{E&!tW&pfo;iv6`9eWAu~F=@bvE=`kjUC$SW3JcW(H^_Pciec=|_(SJSAo3zNx> z7vHJz`}>|j{C*C3O->AH$9`?&xhpONMOd!(&dAe}^k4btGqhu}cPz0#NWd^

RSvcWTs3ybQ!@ zoWx2iLWPhrMY_+_0`8fKH0>M@ko5-*953CXSznD31Du$ou4;HAmRq4`m0nL+N{Gx# zbjk-_@e!P(`*rzTZo0VS1j!7nvDX*dIu@;po2m2QhE@e;9lipq4D5we1B?Xe3|Q(^ zxMqxpdRW1pk1=lD;ahJt@Mi5!lu2Y2oeCof+0BG|Y`mtNKropSQ=!;rffp{cqbn08 zZ=Q&0-Uz8SZw`>q{``Q}OVB_|DU>@<9;~nvxzI(~){Z(+A*S9(f>tKy)t`5Zru3T- zr;ICv>f<^844PLtgF!qzDpE5RY(_gJ4RmE7dx_>8A{O4WTJuj)N}y~x!uBwdbQZYz z{MC(?grs>pr-7cU3QReTFO*8zR=Tp&L;(!X!zpZD@nNaODGm1iY;lfWuIjq=Ui3kp zaHE75bp8SQ?EeBjVWbII33E2Zt(SDj=pfQdv1pbi+?u z>T=96dYj1UJhK|FBnZ=pJ1l+3B)gy3B8c9!dcpKfGce_gsO{KIW>myotw4RwJHXWg zDBnp!o-I5(*>~Z=aUOS~ghfmHlLC_J4XO*0R#g#&7t6BfJiXM6qBY!@h}RJ~IKlV` z^V(V}M{zEWpoAOP&2naijE%hLrbcL-n=1mEcLGY10@H0p*10OT6f*b~{~{Dm<9>;vlqBXwEuU z51(upS^7$9r_u=vMLMTVdZW&%c)|(G7M2WaCRJf*Gp=?Hxvp{O4Y$PzaXCZ+YS4sE zd_A%qoKA|w)K*IrQip|I{75KXiZ3P3eUvNV1WVW;&E}`uzWE0SX7bbK zk9B^!?R(#S!$n&jO+`-+r_y`N($4Tn+iyF|RbxcpAgb?tu(Rk;KnCry!rou+k#c5iAlw_4lSLnvGNLBdGdFCNZVtH6gj9r(=vFYI@kMMJW;9o%3JXUK^$%7>~CSsqf zqCUZl0rb|0x!&V^ZSWW=aX8O_yyXV*>ICd|45}2$!>j7CHQ7Wcb6DZnl+1bNv5C9M zCNK!+PP6DmaYz_cS!`htqNG@gaxhn&6e(i}_k{GiGTL%6P`u{Red+H&pM)QtfXq&q zq{e>NO|s@h&RUL>I9~-4G;vM1bnbxbOqliN))iz?(a*H~rM6a}>91C}%q^QJi(wPJ zY5)c6PFk>R9>Dv1a#M*zwj>t$1&TIeB=xAOwJQe=H?MhG(+j~ShaJ#afJxG4^Pr|N z%F!tyL<=6-kn}Bdi<#u;!J&!)jbAq7J<2%Oc~-0S2-@@{bRtQY(--%vmUs}oYA@}1 z4@T&bGr2)q0oDs5<4qg6aHWjcuscgLkV;Z19=L*xy60yBo#ipwQgDYzp>+K#uJ}@& zjW|}?;OGpJa(Ql~Vb88e9ewg1#l=B`Mv6Nb-i=#=4qTsjDBJM&9WfPolPyER9Vav|FWov67W=^h;ra;|+y8fRy>{ph>5j$H{v zZpmtNDriGu-GF^7n>))g7pBWH>Qf|5fccC2*jot*y@?lCp8CrrAS!0gXUtH6Y@rdH z4e*PPVc@T@QLmK0gI1n)5PM6vEQ>m@Iubif?RN!Pp->E8fbk8e#?(67E>yE(gBxn+ zbbRBAgCca==^44t=yE4M3G*a+JQjsAqZXBzJV7J{*J>5I9GLN18dE64O*=;;3VNzK z(Azs8R|ENXaADZc&$ zNeIHMg=;md?bWHJx#l|C=j~*SIzP1K#Odf%K;lELTf1z!BA0N5fSviSa*{wj(C3wg zd5KG6FLL1c3rwW7uHd0;0~58&x^}LDzxsErv!El!QdSgoX@as5`T~D$nH?@g(&_lq9PIQIS~}!`1jn_AkRzDGi|kfNJ>xzd6YB&^`!v?% zkl4;DkD%CG8%C$|c5#~q1y_HT8Y>-biN!V+p8mo3t_doRAdnB(q1W?+EK||4{DlR$ zNu5Z>DsnAEVL~opK;_asnN_2eAhZ0r9U1pLFiC6}t7i~RF9ef9jU5Mt!gUSiO{JLv z+BxVcFs-xY=)#wmC&i%0Q1Z(wuCC+oM?xx6bruOh5z*3#8p%*?v}z$J>{sn~oEhJY zUmP%3;=}Y$q-I`~q#Tq8c%8i=2p3}$z46WN(vaF@RIKvu>P~kD{k@{Oy3s$pv7zD^ zr$M1fYjN5ahsqsl=PiU6e|Cvhzd2co1(^nOdSl_Yho4wjSYBS({;5Cb8IC86Nr{b% zCTytD);vUl%^IJZr{JJfx$&d9U>!pQbRDbQeEQ6XGP|LD5AmphgU`+39WA+FN;Qci zbTx!$jI4F22J?!Ta#%sHQgdyMs|BL-eZoR`6b;H5cC$uSw?;&Jy|`WC^Syg2O>m7Q zHz&dy0%fo{o>L+Jg0vOmzIGIw5;jsy$JwbD{FGt=Y^%nrIJk+(QkAu0I%GHU@# zu9jCQtLlWf5Yn2b{daQp94R^^m{Q3HIwO&GB&|e)06r75aO9Zl8#chw@JOZ7HH%#m z?brsogtH0j?28zA!X=ilm)2Kryfa=o#4M%_Jdh9{HG%nEWzBKVUwc9k0x}+k)qnG?{ZhA^?zD;K zhB#GA4;b+9PedKJ+eRW~k+H|>sWd)rBtT+{dF?JYXCwTs8f9|m^Y_U-TGEiSvr;|r zsNosB$l&eT6!#dD|SH~wQ6sPw2uG;?I6xG^fVN)>nV5$ z5^4XqK1n4X_jXkC^U{?ii{!j{o0&~`JCSgTkF1MyoLUglrVpLk*_M_U%K(I7H4CIR zxAox3yyIY&IRClMtB5(KepX^2o^!_>$yDZ+^G}}wRG&_eG}lN({TXTGM>$3dr-3o( zaY45}^U?D>OCe)NF!y%VqFg7Hrlt{0*hp+W&3-rEJ>tt8)IfD>*-C`bnpz9-vIu?= z1%fd>$62Lb8DynQUONW|Pny`qD#*|+OjjXT7Qh#oA;KN;EdmL(ZQxm7HL5gm(5)W- z>qw0f2-IoB9nxCrVo9`WNI`)Hv(7&C;GE#5o(EIcZ>iBEe`;Vf-=VF9%RNT{EDCg( z+)^oqQB9>(-P!GuKdy=P(+_zbuKH#$CDm&>&X8;CA4OdkR#luEyE*QE-Tn%1xG-1 zzVsMQuTCZYNY8P8k;2=dfQ7kHIJ=S+>k`>g8~+D9V0}a)XBWPA{1)^MyO@YTxmb*5 zC+@m;Xq4zi5-Q{`8$?8Tu!49KmO`p%{hW2JItUX6RCNP;OtKtjQlpuq$!+NlpZ+?L zM(6})$ju8;8h|z7)bpc#l*IjlnSjKr4uzHHEJ)lSN(S0Pq{no|TJyIqLSBGDg+V}& zsUAyKSs1hY=viCYu{<`FJ9UZxO;2%~(M?$r?dEQu_yvaZG|pUYX$j!y}M7SdxF z0Ut^V4u`0_O8{ld`eNzO6R4(4Y}~e%H(xugC2|O=Q@kwW`GF80_ndU(B!dMwAmZ>~>?cl^1k9 zi;FF=K4d+g+)Eh^ZN+Vb5Phvqxi26(W!(~^+a&>`+G)4s(S_Phr@gJ?u`|CumT}c&UQEM&G@(N0KS7Vl!*li4m_V zSGmHO)(BvQ!8e_ULs;ahH0q6A5nD7=+T*Mn4(4*O+e4HmqCv1zaPAI0I-DuILmDkC z-cVAdrGy27Lt(6+ z>buNM3#Vk|-6g=DbGSQ^$8(|_&_I-hM%KB0$dY%mH|#(R(8b0}htzhL4|+n=x+|Jz zXs^GBFrq5l*7e%CUAJ0fY3mV0#dApWm4c)p2#QgOYF9M~O~2CCnPfjf%oQ6v2;O#_ zqY+vtAluZbgKGnMkDjp;ltTsB=0N$3^%j{(g<%fbH8|0>W%eEsQ$elm8$WaLTq|1C ztvOcEj<#B0WCY&XD;S%(S`~5$MEZIqFe+{}mv81UGNgp9Y2cE|z~UM7PU>NX#rTxibt}>_*pbKwkN#%9a7JNH~%y^r4H%r`1Y3*x1O>Q4_W|l6GB;XAh zB!M#O8U`6(q8AW?Xk*Tt-ghfRT=Re^N}$EX{H}$J0z-G@-49q-o#U8|-|b6SO^6;LEV}Az z1yi_z1Q;ZE57!2ANdfPTt4L7w8dpzE1Y0po@2dAu!Lqz$MrU*OGREbR5Zb?uhy*n( z#jCCjsGvh=y@^ zyft#R=QhMB7ii9EdP%_u9Gqt5T0tO}mZq?9-ly&+I#62xkO4oZ^4<^#0Ewlr-0+)U zx&^7VE8${LkP5;fwjkGxfehz?#(ZIStNpcD(iecT)yyVYMucqof_fCQL9vwe7^XU$hN4WC$BPq}a*Lc< zKO`hV#E_v}BmIA=BYH4g>rJ0d$c z2wJfD5)9V;NKf<_4~B1mVUSq?N#9X7z~>bdEll{JAXWlI+1T#ia|{KDF|691GvJ|v z5-UNq@SPzlgU3nRO!0SX-$rM)P;#OMNG;Udd-MTw1es0UxzjTWxI?l^zdu~=%!_RT0r+LHH6|`0bos8RAlFvKiMjt%UMMv z_bnyMjKg>((P*dcS*e~-nSF$#DkXW8Yd%7>4j zqZqB0chC?-z_y>!BJcFJokb9VK8BKne0*^k0huXgPm_bt;j_OKjd z{98*%U*00>v)lP9*v!#~RYl(9LkZKK3&wQ9jeX@z2UB_`RpYsca4e6q0uFY)o$a&??+V@1-S7mvxM$nn?|KvXLE=!eUqyNoH-(X z6*s4^nI%NF4viDtG=+XS5gv}EVA0J_{bXU`mXG;g|KvA2w?F-vAK@FA+vk6-bMB`w qFU|XS=B2q`?Cd0)?*`|ZttUsyQtpWDB$fBpyTeqaFr literal 0 HcmV?d00001 diff --git a/contrib/gdb/gdb/doc/refcard.tex b/contrib/gdb/gdb/doc/refcard.tex new file mode 100644 index 000000000000..c57c2d8f6332 --- /dev/null +++ b/contrib/gdb/gdb/doc/refcard.tex @@ -0,0 +1,645 @@ +%%%%%%%%%%%%%%%% gdb-refcard.tex %%%%%%%%%%%%%%%% + +%This file is TeX source for a reference card describing GDB, the GNU debugger. +%Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +%Permission is granted to make and distribute verbatim copies of +%this reference provided the copyright notices and permission notices +%are preserved on all copies. +% +%TeX markup is a programming language; accordingly this file is source +%for a program to generate a reference. +% +%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 1, 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 can find a copy of the GNU General Public License in the GDB +%manual; or write to the Free Software Foundation, Inc., +%59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +% +%You can contact the author at: doc@cygnus.com +% +% Documentation Department +% Cygnus Support +% 1937 Landings Drive +% Mountain View, CA 94043 USA +% +% +1 415 903 1400 +% +% +% +% 22-AUG-1993 Andreas Vogel +% +% Modifications made in order to handle different papersizes correctly. +% You only have to set the total width and height of the paper, the +% horizontal and vertical margin space measured from *paper edge* +% and the interline and interspec spacing. +% In order to support a new papersize, you have to fiddle with the +% latter four dimensions. Just try out a few values. +% All other values will be computed at process time so it should be +% quite easy to support different paper sizes - only four values to +% guess :-) +% +% To find the configuration places, just search for the string +% "CONFIGURATION". +% +% Andreas Vogel (av@ssw.de) +% +% +% +% Uncomment the following `magnification' command if you want to print +% out in a larger font. Caution! You may need larger paper. You had +% best avoid using 3-column output if you try this. See the ``Three +% column format'' section below if you want to print in three column +% format. +% +%\magnification=\magstep 1 +% +% NOTE ON INTENTIONAL OMISSIONS: This reference card includes most GDB +% commands, but due to space constraints there are some things I chose +% to omit. In general, not all synonyms for commands are covered, nor +% all variations of a command. +% The GDB-under-Emacs section omits gdb-mode functions without default +% keybindings. GDB startup options are not described. +% set print sevenbit-strings, set symbol-reloading omitted. +% printsyms, printpsyms, omitted since they're for GDB maintenance primarily +% share omitted due to obsolescence +% set check range/type omitted at least til code is in GDB. +% +%-------------------- Three column format ----------------------- + +%%%% --- To disable three column format, comment out this entire section + +% Three-column format for landscape printing + +%-------- Papersize defs: + +\newdimen\totalwidth \newdimen\totalheight +\newdimen\hmargin \newdimen\vmargin +\newdimen\secskip \newdimen\lskip +\newdimen\barwidth \newdimen\barheight +\newdimen\intersecwidth + +%% +%% START CONFIGURATION - PAPERSIZE DEFINITIONS +%------- Papersize params: +%% US letter paper (8.5x11in) +%% +\totalwidth=11in % total width of paper +\totalheight=8.5in % total height of paper +\hmargin=.25in % horizontal margin width +\vmargin=.25in % vertical margin width +\secskip=1pc % space between refcard secs +\lskip=2pt % extra skip between \sec entries +%------- end papersize params +%% +%% change according to personal taste, not papersize dependent +%% +\barwidth=.1pt % width of the cropmark bar +\barheight=2pt % height of the cropmark bar +\intersecwidth=0.5em % width between \itmwid and \dfnwid +%% +%% END CONFIGURATION - PAPERSIZE DEFINITIONS +%% + +%% +%% values to be computed - nothing to configure +%% +\newdimen\fullhsize % width of area without margins +\newdimen\itmwid % width of item column +\newdimen\dfnwid % width of definition column +\newdimen\temp % only for temporary use + +%% +%% adjust the offsets so the margins are measured *from paper edge* +%% +\hoffset=-1in \advance \hoffset by \hmargin +\voffset=-1in \advance \voffset by \vmargin + +%% +%% fullhsize = totalwidth - (2 * hmargin) +%% +\fullhsize=\totalwidth +\temp=\hmargin \multiply \temp by 2 \advance \fullhsize by -\temp + +%% +%% hsize = (fullhsize - (4 * hmargin) - (2 * barwidth)) / 3 +%% +\hsize=\fullhsize +\temp=\hmargin \multiply \temp by 4 \advance \hsize by -\temp +\temp=\barwidth \multiply \temp by 2 \advance \hsize by -\temp +\divide \hsize by 3 + +%% +%% vsize = totalheight - (2 * vmargin) +%% +\vsize=\totalheight +\temp=\vmargin \multiply \temp by 2 \advance \vsize by -\temp + +%% +%% itmwid = (hsize - intersecwidth) * 1/3 +%% dfnwid = (hsize - intersecwidth) * 2/3 +%% +\temp=\hsize \advance \temp by -\intersecwidth \divide \temp by 3 +\itmwid=\temp +\dfnwid=\hsize \advance \dfnwid by -\itmwid + +%-------- end papersize defs + + +\def\fulline{\hbox to \fullhsize} +\let\lcr=L \newbox\leftcolumn\newbox\centercolumn +\output={\if L\lcr + \global\setbox\leftcolumn=\columnbox \global\let\lcr=C + \else + \if C\lcr + \global\setbox\centercolumn=\columnbox \global\let\lcr=R + \else \tripleformat \global\let\lcr=L + \fi + \fi +% \ifnum\outputpenalty>-20000 \else\dosupereject\fi + } + +%% +%% START CONFIGURATION - ALTERNATIVE FOLDING GUIDES +%% +%% For NO printed folding guide, +%% comment out other \def\vdecor's and uncomment: + +%\def\vdecor{\hskip\hmargin plus1fil\hskip\barwidth plus1fil\hskip\hmargin plus1fil} + +%% For SOLID LINE folding guide, +%% comment out other \def\vdecor's and uncomment: + +%\def\vdecor{\hskip\hmargin plus1fil \vrule width \barwidth \hskip\hmargin plus1fil} + +%% For SMALL MARKS NEAR TOP AND BOTTOM as folding guide, +%% comment out other \def\vdecor's and uncomment: + +\def\vdecor{\hskip\hmargin plus1fil +\vbox to \vsize{\hbox to \barwidth{\vrule height\barheight width\barwidth}\vfill +\hbox to \barwidth{\vrule height\barheight width\barwidth}}%THIS PERCENT SIGN IS ESSENTIAL +\hskip\hmargin plus1fil} + +%% +%% END CONFIGURATION - ALTERNATIVES FOR FOLDING GUIDES +%% + +\def\tripleformat{\shipout\vbox{\fulline{\box\leftcolumn\vdecor + \box\centercolumn\vdecor + \columnbox} + } + \advancepageno} +\def\columnbox{\leftline{\pagebody}} +\def\bye{\par\vfill + \supereject + \if R\lcr \null\vfill\eject\fi + \end} + +%-------------------- end three column format ----------------------- + +%-------------------- Computer Modern font defs: -------------------- +\font\bbf=cmbx10 +\font\vbbf=cmbx12 +\font\smrm=cmr6 +\font\brm=cmr10 +\font\rm=cmr7 +\font\it=cmti7 +\font\tt=cmtt8 +%-------------------- end font defs --------------------------------- + +% +\hyphenpenalty=5000\tolerance=2000\raggedright\raggedbottom +\normalbaselineskip=9pt\baselineskip=9pt +% +\parindent=0pt +\parskip=0pt +\footline={\vbox to0pt{\hss}} +% +\def\ctl#1{{\tt C-#1}} +\def\opt#1{{\brm[{\rm #1}]}} +\def\xtra#1{\noalign{\smallskip{\tt#1}}} +% +\long\def\sec#1;#2\endsec{\vskip \secskip +\halign{% +%COL 1 (of halign): +\vtop{\hsize=\itmwid\tt +##\par\vskip \lskip }\hfil +%COL 2 (of halign): +&\vtop{\hsize=\dfnwid\hangafter=1\hangindent=\intersecwidth +\rm ##\par\vskip \lskip}\cr +%Tail of \long\def fills in halign body with \sec args: +\noalign{{\bbf #1}\vskip \lskip} +#2 +} +} + +{\vbbf GDB QUICK REFERENCE}\hfil{\smrm GDB Version 4}\qquad + +\sec Essential Commands; +gdb {\it program} \opt{{\it core}}&debug {\it program} \opt{using +coredump {\it core}}\cr +b \opt{\it file\tt:}{\it function}&set breakpoint at {\it function} \opt{in \it file}\cr +run \opt{{\it arglist}}&start your program \opt{with {\it arglist}}\cr +bt& backtrace: display program stack\cr +p {\it expr}&display the value of an expression\cr +c &continue running your program\cr +n &next line, stepping over function calls\cr +s &next line, stepping into function calls\cr +\endsec + +\sec Starting GDB; +gdb&start GDB, with no debugging files\cr +gdb {\it program}&begin debugging {\it program}\cr +gdb {\it program core}&debug coredump {\it core} produced by {\it +program}\cr +gdb --help&describe command line options\cr +\endsec + +\sec Stopping GDB; +quit&exit GDB; also {\tt q} or {\tt EOF} (eg \ctl{d})\cr +INTERRUPT&(eg \ctl{c}) terminate current command, or send to running process\cr +\endsec + +\sec Getting Help; +help&list classes of commands\cr +help {\it class}&one-line descriptions for commands in {\it class}\cr +help {\it command}&describe {\it command}\cr +\endsec + +\sec Executing your Program; +run {\it arglist}&start your program with {\it arglist}\cr +run&start your program with current argument list\cr +run $\ldots$ <{\it inf} >{\it outf}&start your program with input, output +redirected\cr +\cr +kill&kill running program\cr +\cr +tty {\it dev}&use {\it dev} as stdin and stdout for next {\tt run}\cr +set args {\it arglist}&specify {\it arglist} for next +{\tt run}\cr +set args&specify empty argument list\cr +show args&display argument list\cr +\cr +show env&show all environment variables\cr +show env {\it var}&show value of environment variable {\it var}\cr +set env {\it var} {\it string}&set environment variable {\it var}\cr +unset env {\it var}&remove {\it var} from environment\cr +\endsec + +\sec Shell Commands; +cd {\it dir}&change working directory to {\it dir}\cr +pwd&Print working directory\cr +make $\ldots$&call ``{\tt make}''\cr +shell {\it cmd}&execute arbitrary shell command string\cr +\endsec + +\vfill +\line{\smrm \opt{ } surround optional arguments \hfill $\ldots$ show +one or more arguments} +\vskip\baselineskip +\centerline{\smrm \copyright 1991, 1992, 1993 Free Software Foundation, Inc.\qquad Permissions on back} +\eject +\sec Breakpoints and Watchpoints; +break \opt{\it file\tt:}{\it line}\par +b \opt{\it file\tt:}{\it line}&set breakpoint at {\it line} number \opt{in \it file}\par +eg:\quad{\tt break main.c:37}\quad\cr +break \opt{\it file\tt:}{\it func}&set breakpoint at {\it +func} \opt{in \it file}\cr +break +{\it offset}\par +break -{\it offset}&set break at {\it offset} lines from current stop\cr +break *{\it addr}&set breakpoint at address {\it addr}\cr +break&set breakpoint at next instruction\cr +break $\ldots$ if {\it expr}&break conditionally on nonzero {\it expr}\cr +cond {\it n} \opt{\it expr}&new conditional expression on breakpoint +{\it n}; make unconditional if no {\it expr}\cr +tbreak $\ldots$&temporary break; disable when reached\cr +rbreak {\it regex}&break on all functions matching {\it regex}\cr +watch {\it expr}&set a watchpoint for expression {\it expr}\cr +catch {\it x}&break at C++ handler for exception {\it x}\cr +\cr +info break&show defined breakpoints\cr +info watch&show defined watchpoints\cr +\cr +clear&delete breakpoints at next instruction\cr +clear \opt{\it file\tt:}{\it fun}&delete breakpoints at entry to {\it fun}()\cr +clear \opt{\it file\tt:}{\it line}&delete breakpoints on source line \cr +delete \opt{{\it n}}&delete breakpoints +\opt{or breakpoint {\it n}}\cr +\cr +disable \opt{{\it n}}&disable breakpoints +\opt{or breakpoint {\it n}} +\cr +enable \opt{{\it n}}&enable breakpoints +\opt{or breakpoint {\it n}} +\cr +enable once \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}}; +disable again when reached +\cr +enable del \opt{{\it n}}&enable breakpoints \opt{or breakpoint {\it n}}; +delete when reached +\cr +\cr +ignore {\it n} {\it count}&ignore breakpoint {\it n}, {\it count} +times\cr +\cr +commands {\it n}\par +\qquad \opt{\tt silent}\par +\qquad {\it command-list}&execute GDB {\it command-list} every time breakpoint {\it n} is reached. \opt{{\tt silent} suppresses default +display}\cr +end&end of {\it command-list}\cr +\endsec + +\sec Program Stack; +backtrace \opt{\it n}\par +bt \opt{\it n}&print trace of all frames in stack; or of {\it n} +frames---innermost if {\it n}{\tt >0}, outermost if {\it n}{\tt <0}\cr +frame \opt{\it n}&select frame number {\it n} or frame at address {\it +n}; if no {\it n}, display current frame\cr +up {\it n}&select frame {\it n} frames up\cr +down {\it n}&select frame {\it n} frames down\cr +info frame \opt{\it addr}&describe selected frame, or frame at +{\it addr}\cr +info args&arguments of selected frame\cr +info locals&local variables of selected frame\cr +info reg \opt{\it rn}$\ldots$\par +info all-reg \opt{\it rn}®ister values \opt{for regs {\it rn\/}} in +selected frame; {\tt all-reg} includes floating point\cr +info catch&exception handlers active in selected frame\cr +\endsec + +\vfill\eject +\sec Execution Control; +continue \opt{\it count}\par +c \opt{\it count}&continue running; if {\it count} specified, ignore +this breakpoint next {\it count} times\cr +\cr +step \opt{\it count}\par +s \opt{\it count}&execute until another line reached; repeat {\it count} times if +specified\cr +stepi \opt{\it count}\par +si \opt{\it count}&step by machine instructions rather than source +lines\cr +\cr +next \opt{\it count}\par +n \opt{\it count}&execute next line, including any function calls\cr +nexti \opt{\it count}\par +ni \opt{\it count}&next machine instruction rather than source +line\cr +\cr +until \opt{\it location}&run until next instruction (or {\it +location})\cr +finish&run until selected stack frame returns\cr +return \opt{\it expr}&pop selected stack frame without executing +\opt{setting return value}\cr +signal {\it num}&resume execution with signal {\it s} (none if {\tt 0})\cr +jump {\it line}\par +jump *{\it address}&resume execution at specified {\it line} number or +{\it address}\cr +set var={\it expr}&evaluate {\it expr} without displaying it; use for +altering program variables\cr +\endsec + +\sec Display; +print \opt{\tt/{\it f}\/} \opt{\it expr}\par +p \opt{\tt/{\it f}\/} \opt{\it expr}&show value of {\it expr} \opt{or +last value \tt \$} according to format {\it f}:\cr +\qquad x&hexadecimal\cr +\qquad d&signed decimal\cr +\qquad u&unsigned decimal\cr +\qquad o&octal\cr +\qquad t&binary\cr +\qquad a&address, absolute and relative\cr +\qquad c&character\cr +\qquad f&floating point\cr +call \opt{\tt /{\it f}\/} {\it expr}&like {\tt print} but does not display +{\tt void}\cr +x \opt{\tt/{\it Nuf}\/} {\it expr}&examine memory at address {\it expr}; +optional format spec follows slash\cr +\quad {\it N}&count of how many units to display\cr +\quad {\it u}&unit size; one of\cr +&{\tt\qquad b}\ individual bytes\cr +&{\tt\qquad h}\ halfwords (two bytes)\cr +&{\tt\qquad w}\ words (four bytes)\cr +&{\tt\qquad g}\ giant words (eight bytes)\cr +\quad {\it f}&printing format. Any {\tt print} format, or\cr +&{\tt\qquad s}\ null-terminated string\cr +&{\tt\qquad i}\ machine instructions\cr +disassem \opt{\it addr}&display memory as machine instructions\cr +\endsec + +\sec Automatic Display; +display \opt{\tt/\it f\/} {\it expr}&show value of {\it expr} each time +program stops \opt{according to format {\it f}\/}\cr +display&display all enabled expressions on list\cr +undisplay {\it n}&remove number(s) {\it n} from list of +automatically displayed expressions\cr +disable disp {\it n}&disable display for expression(s) number {\it +n}\cr +enable disp {\it n}&enable display for expression(s) number {\it +n}\cr +info display&numbered list of display expressions\cr +\endsec + +\vfill\eject + +\sec Expressions; +{\it expr}&an expression in C, C++, or Modula-2 (including function calls), or:\cr +{\it addr\/}@{\it len}&an array of {\it len} elements beginning at {\it +addr}\cr +{\it file}::{\it nm}&a variable or function {\it nm} defined in {\it +file}\cr +$\tt\{${\it type}$\tt\}${\it addr}&read memory at {\it addr} as specified +{\it type}\cr +\$&most recent displayed value\cr +\${\it n}&{\it n}th displayed value\cr +\$\$&displayed value previous to \$\cr +\$\${\it n}&{\it n}th displayed value back from \$\cr +\$\_&last address examined with {\tt x}\cr +\$\_\_&value at address \$\_\cr +\${\it var}&convenience variable; assign any value\cr +\cr +show values \opt{{\it n}}&show last 10 values \opt{or surrounding +\${\it n}}\cr +show conv&display all convenience variables\cr +\endsec + +\sec Symbol Table; +info address {\it s}&show where symbol {\it s} is stored\cr +info func \opt{\it regex}&show names, types of defined functions +(all, or matching {\it regex})\cr +info var \opt{\it regex}&show names, types of global variables (all, +or matching {\it regex})\cr +whatis \opt{\it expr}\par +ptype \opt{\it expr}&show data type of {\it expr} \opt{or \tt \$} +without evaluating; {\tt ptype} gives more detail\cr +ptype {\it type}&describe type, struct, union, or enum\cr +\endsec + +\sec GDB Scripts; +source {\it script}&read, execute GDB commands from file {\it +script}\cr +\cr +define {\it cmd}\par +\qquad {\it command-list}&create new GDB command {\it cmd}; +execute script defined by {\it command-list}\cr +end&end of {\it command-list}\cr +document {\it cmd}\par +\qquad {\it help-text}&create online documentation +for new GDB command {\it cmd}\cr +end&end of {\it help-text}\cr +\endsec + +\sec Signals; +handle {\it signal} {\it act}&specify GDB actions for {\it signal}:\cr +\quad print&announce signal\cr +\quad noprint&be silent for signal\cr +\quad stop&halt execution on signal\cr +\quad nostop&do not halt execution\cr +\quad pass&allow your program to handle signal\cr +\quad nopass&do not allow your program to see signal\cr +info signals&show table of signals, GDB action for each\cr +\endsec + +\sec Debugging Targets; +target {\it type} {\it param}&connect to target machine, process, or file\cr +help target&display available targets\cr +attach {\it param}&connect to another process\cr +detach&release target from GDB control\cr +\endsec + +\vfill\eject +\sec Controlling GDB; +set {\it param} {\it value}&set one of GDB's internal parameters\cr +show {\it param}&display current setting of parameter\cr +\xtra{\rm Parameters understood by {\tt set} and {\tt show}:} +\quad complaint {\it limit}&number of messages on unusual symbols\cr +\quad confirm {\it on/off}&enable or disable cautionary queries\cr +\quad editing {\it on/off}&control {\tt readline} command-line editing\cr +\quad height {\it lpp}&number of lines before pause in display\cr +\quad language {\it lang}&Language for GDB expressions ({\tt auto}, {\tt c} or +{\tt modula-2})\cr +\quad listsize {\it n}&number of lines shown by {\tt list}\cr +\quad prompt {\it str}&use {\it str} as GDB prompt\cr +\quad radix {\it base}&octal, decimal, or hex number representation\cr +\quad verbose {\it on/off}&control messages when loading +symbols\cr +\quad width {\it cpl}&number of characters before line folded\cr +\quad write {\it on/off}&Allow or forbid patching binary, core files +(when reopened with {\tt exec} or {\tt core}) +\cr +\quad history $\ldots$\par +\quad h $\ldots$&groups with the following options:\cr +\quad h exp {\it off/on}&disable/enable {\tt readline} history expansion\cr +\quad h file {\it filename}&file for recording GDB command history\cr +\quad h size {\it size}&number of commands kept in history list\cr +\quad h save {\it off/on}&control use of external file for +command history\cr +\cr +\quad print $\ldots$\par +\quad p $\ldots$&groups with the following options:\cr +\quad p address {\it on/off}&print memory addresses in stacks, +values\cr +\quad p array {\it off/on}&compact or attractive format for +arrays\cr +\quad p demangl {\it on/off}&source (demangled) or internal form for C++ +symbols\cr +\quad p asm-dem {\it on/off}&demangle C++ symbols in +machine-instruction output\cr +\quad p elements {\it limit}&number of array elements to display\cr +\quad p object {\it on/off}&print C++ derived types for objects\cr +\quad p pretty {\it off/on}&struct display: compact or indented\cr +\quad p union {\it on/off}&display of union members\cr +\quad p vtbl {\it off/on}&display of C++ virtual function +tables\cr +\cr +show commands&show last 10 commands\cr +show commands {\it n}&show 10 commands around number {\it n}\cr +show commands +&show next 10 commands\cr +\endsec + +\sec Working Files; +file \opt{\it file}&use {\it file} for both symbols and executable; +with no arg, discard both\cr +core \opt{\it file}&read {\it file} as coredump; or discard\cr +exec \opt{\it file}&use {\it file} as executable only; or discard\cr +symbol \opt{\it file}&use symbol table from {\it file}; or discard\cr +load {\it file}&dynamically link {\it file\/} and add its symbols\cr +add-sym {\it file} {\it addr}&read additional symbols from {\it file}, +dynamically loaded at {\it addr}\cr +info files&display working files and targets in use\cr +path {\it dirs}&add {\it dirs} to front of path searched for +executable and symbol files\cr +show path&display executable and symbol file path\cr +info share&list names of shared libraries currently loaded\cr +\endsec + +\vfill\eject +\sec Source Files; +dir {\it names}&add directory {\it names} to front of source path\cr +dir&clear source path\cr +show dir&show current source path\cr +\cr +list&show next ten lines of source\cr +list -&show previous ten lines\cr +list {\it lines}&display source surrounding {\it lines}, +specified as:\cr +\quad{\opt{\it file\tt:}\it num}&line number \opt{in named file}\cr +\quad{\opt{\it file\tt:}\it function}&beginning of function \opt{in +named file}\cr +\quad{\tt +\it off}&{\it off} lines after last printed\cr +\quad{\tt -\it off}&{\it off} lines previous to last printed\cr +\quad{\tt*\it address}&line containing {\it address}\cr +list {\it f},{\it l}&from line {\it f} to line {\it l}\cr +info line {\it num}&show starting, ending addresses of compiled code for +source line {\it num}\cr +info source&show name of current source file\cr +info sources&list all source files in use\cr +forw {\it regex}&search following source lines for {\it regex}\cr +rev {\it regex}&search preceding source lines for {\it regex}\cr +\endsec + +\sec GDB under GNU Emacs; +M-x gdb&run GDB under Emacs\cr +\ctl{h} m&describe GDB mode\cr +M-s&step one line ({\tt step})\cr +M-n&next line ({\tt next})\cr +M-i&step one instruction ({\tt stepi})\cr +\ctl{c} \ctl{f}&finish current stack frame ({\tt finish})\cr +M-c&continue ({\tt cont})\cr +M-u&up {\it arg} frames ({\tt up})\cr +M-d&down {\it arg} frames ({\tt down})\cr +\ctl{x} \&© number from point, insert at end\cr +\ctl{x} SPC&(in source file) set break at point\cr +\endsec + +\sec GDB License; +show copying&Display GNU General Public License\cr +show warranty&There is NO WARRANTY for GDB. Display full no-warranty +statement.\cr +\endsec + + +\vfill +{\smrm\parskip=6pt +\centerline{Copyright \copyright 1991, 1992, 1993 Free Software Foundation, Inc.} +\centerline{Cygnus Support (doc@cygnus.com)} +\centerline{The author assumes no responsibility for any errors on this card.} + +This card may be freely distributed under the terms of the GNU +General Public License. + +\centerline{Please contribute to development of this card by +annotating it.} + +GDB itself is free software; you are welcome to distribute copies of +it under the terms of the GNU General Public License. There is +absolutely no warranty for GDB. +} +\end diff --git a/contrib/gdb/gdb/doc/remote.texi b/contrib/gdb/gdb/doc/remote.texi new file mode 100644 index 000000000000..b878e1964a67 --- /dev/null +++ b/contrib/gdb/gdb/doc/remote.texi @@ -0,0 +1,1531 @@ +@c -*- Texinfo -*- +@c Copyright (c) 1990 1991 1992 1993 Free Software Foundation, Inc. +@c This file is part of the source for the GDB manual. +@c This text diverted to "Remote Debugging" section in general case; +@c however, if we're doing a manual specifically for one of these, it +@c belongs up front (in "Getting In and Out" chapter). + +@ifset REMOTESTUB +@node Remote Serial +@subsection The @value{GDBN} remote serial protocol + +@cindex remote serial debugging, overview +To debug a program running on another machine (the debugging +@dfn{target} machine), you must first arrange for all the usual +prerequisites for the program to run by itself. For example, for a C +program, you need: + +@enumerate +@item +A startup routine to set up the C runtime environment; these usually +have a name like @file{crt0}. The startup routine may be supplied by +your hardware supplier, or you may have to write your own. + +@item +You probably need a C subroutine library to support your program's +subroutine calls, notably managing input and output. + +@item +A way of getting your program to the other machine---for example, a +download program. These are often supplied by the hardware +manufacturer, but you may have to write your own from hardware +documentation. +@end enumerate + +The next step is to arrange for your program to use a serial port to +communicate with the machine where @value{GDBN} is running (the @dfn{host} +machine). In general terms, the scheme looks like this: + +@table @emph +@item On the host, +@value{GDBN} already understands how to use this protocol; when everything +else is set up, you can simply use the @samp{target remote} command +(@pxref{Targets,,Specifying a Debugging Target}). + +@item On the target, +you must link with your program a few special-purpose subroutines that +implement the @value{GDBN} remote serial protocol. The file containing these +subroutines is called a @dfn{debugging stub}. + +@ifset GDBSERVER +On certain remote targets, you can use an auxiliary program +@code{gdbserver} instead of linking a stub into your program. +@xref{Server,,Using the @code{gdbserver} program}, for details. +@end ifset +@end table + +The debugging stub is specific to the architecture of the remote +machine; for example, use @file{sparc-stub.c} to debug programs on +@sc{sparc} boards. + +@cindex remote serial stub list +These working remote stubs are distributed with @value{GDBN}: + +@table @code +@item sparc-stub.c +@kindex sparc-stub.c +For @sc{sparc} architectures. + +@item m68k-stub.c +@kindex m68k-stub.c +@cindex Motorola 680x0 +@cindex m680x0 +For Motorola 680x0 architectures. + +@item i386-stub.c +@kindex i386-stub.c +@cindex Intel +@cindex i386 +For Intel 386 and compatible architectures. +@end table + +The @file{README} file in the @value{GDBN} distribution may list other +recently added stubs. + +@menu +* Stub Contents:: What the stub can do for you +* Bootstrapping:: What you must do for the stub +* Debug Session:: Putting it all together +* Protocol:: Outline of the communication protocol +@ifset GDBSERVER +* Server:: Using the `gdbserver' program +@end ifset +@ifset GDBSERVE +* NetWare:: Using the `gdbserve.nlm' program +@end ifset +@end menu + +@node Stub Contents +@subsubsection What the stub can do for you + +@cindex remote serial stub +The debugging stub for your architecture supplies these three +subroutines: + +@table @code +@item set_debug_traps +@kindex 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. + +@item handle_exception +@kindex handle_exception +@cindex remote serial stub, main routine +This is the central workhorse, but your program never calls it +explicitly---the setup code arranges for @code{handle_exception} to +run when a trap is triggered. + +@code{handle_exception} takes control when your program stops during +execution (for example, on a breakpoint), and mediates communications +with @value{GDBN} on the host machine. This is where the communications +protocol is implemented; @code{handle_exception} acts as the @value{GDBN} +representative on the target machine; it begins by sending summary +information on the state of your program, then continues to execute, +retrieving and transmitting any information @value{GDBN} needs, until you +execute a @value{GDBN} command that makes your program resume; at that point, +@code{handle_exception} returns control to your own code on the target +machine. + +@item breakpoint +@cindex @code{breakpoint} subroutine, remote +Use this auxiliary subroutine to make your program contain a +breakpoint. Depending on the particular situation, this may be the only +way for @value{GDBN} to get control. For instance, if your target +machine has some sort of interrupt button, you won't need to call this; +pressing the interrupt button transfers control to +@code{handle_exception}---in effect, to @value{GDBN}. On some machines, +simply receiving characters on the serial port may also trigger a trap; +again, in that situation, you don't need to call @code{breakpoint} from +your own program---simply running @samp{target remote} from the host +@value{GDBN} session gets control. + +Call @code{breakpoint} if none of these is true, or if you simply want +to make certain your program stops at a predetermined point for the +start of your debugging session. +@end table + +@node Bootstrapping +@subsubsection What you must do for the stub + +@cindex remote stub, support routines +The debugging stubs that come with @value{GDBN} are set up for a particular +chip architecture, but they have no information about the rest of your +debugging target machine. + +First of all you need to tell the stub how to communicate with the +serial port. + +@table @code +@item int getDebugChar() +@kindex getDebugChar +Write this subroutine to read a single character from the serial port. +It may be identical to @code{getchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. + +@item void putDebugChar(int) +@kindex putDebugChar +Write this subroutine to write a single character to the serial port. +It may be identical to @code{putchar} for your target system; a +different name is used to allow you to distinguish the two if you wish. +@end table + +@cindex control C, and remote debugging +@cindex interrupting remote targets +If you want @value{GDBN} to be able to stop your program while it is +running, you need to use an interrupt-driven serial driver, and arrange +for it to stop when it receives a @code{^C} (@samp{\003}, the control-C +character). That is the character which @value{GDBN} uses to tell the +remote system to stop. + +Getting the debugging target to return the proper status to @value{GDBN} +probably requires changes to the standard stub; one quick and dirty way +is to just execute a breakpoint instruction (the ``dirty'' part is that +@value{GDBN} reports a @code{SIGTRAP} instead of a @code{SIGINT}). + +Other routines you need to supply are: + +@table @code +@item void exceptionHandler (int @var{exception_number}, void *@var{exception_address}) +@kindex exceptionHandler +Write this function to install @var{exception_address} in the exception +handling tables. You need to do this because the stub does not have any +way of knowing what the exception handling tables on your target system +are like (for example, the processor's table might be in @sc{rom}, +containing entries which point to a table in @sc{ram}). +@var{exception_number} is the exception number which should be changed; +its meaning is architecture-dependent (for example, different numbers +might represent divide by zero, misaligned access, etc). When this +exception occurs, control should be transferred directly to +@var{exception_address}, and the processor state (stack, registers, +and so on) should be just as it is when a processor exception occurs. So if +you want to use a jump instruction to reach @var{exception_address}, it +should be a simple jump, not a jump to subroutine. + +For the 386, @var{exception_address} should be installed as an interrupt +gate so that interrupts are masked while the handler runs. The gate +should be at privilege level 0 (the most privileged level). The +@sc{sparc} and 68k stubs are able to mask interrup themselves without +help from @code{exceptionHandler}. + +@item void flush_i_cache() +@kindex flush_i_cache +(sparc and sparclite only) Write this subroutine to flush the +instruction cache, if any, on your target machine. If there is no +instruction cache, this subroutine may be a no-op. + +On target machines that have instruction caches, @value{GDBN} requires this +function to make certain that the state of your program is stable. +@end table + +@noindent +You must also make sure this library routine is available: + +@table @code +@item void *memset(void *, int, int) +@kindex memset +This is the standard library function @code{memset} that sets an area of +memory to a known value. If you have one of the free versions of +@code{libc.a}, @code{memset} can be found there; otherwise, you must +either obtain it from your hardware manufacturer, or write your own. +@end table + +If you do not use the GNU C compiler, you may need other standard +library subroutines as well; this varies from one stub to another, +but in general the stubs are likely to use any of the common library +subroutines which @code{gcc} generates as inline code. + + +@node Debug Session +@subsubsection Putting it all together + +@cindex remote serial debugging summary +In summary, when your program is ready to debug, you must follow these +steps. + +@enumerate +@item +Make sure you have the supporting low-level routines +(@pxref{Bootstrapping,,What you must do for the stub}): +@display +@code{getDebugChar}, @code{putDebugChar}, +@code{flush_i_cache}, @code{memset}, @code{exceptionHandler}. +@end display + +@item +Insert these lines near the top of your program: + +@example +set_debug_traps(); +breakpoint(); +@end example + +@item +For the 680x0 stub only, you need to provide a variable called +@code{exceptionHook}. Normally you just use: + +@example +void (*exceptionHook)() = 0; +@end example + +but if before calling @code{set_debug_traps}, you set it to point to a +function in your program, that function is called when +@code{@value{GDBN}} continues after stopping on a trap (for example, bus +error). The function indicated by @code{exceptionHook} is called with +one parameter: an @code{int} which is the exception number. + +@item +Compile and link together: your program, the @value{GDBN} debugging stub for +your target architecture, and the supporting subroutines. + +@item +Make sure you have a serial connection between your target machine and +the @value{GDBN} host, and identify the serial port on the host. + +@item +@c The "remote" target now provides a `load' command, so we should +@c document that. FIXME. +Download your program to your target machine (or get it there by +whatever means the manufacturer provides), and start it. + +@item +To start remote debugging, run @value{GDBN} on the host machine, and specify +as an executable file the program that is running in the remote machine. +This tells @value{GDBN} how to find your program's symbols and the contents +of its pure text. + +@cindex serial line, @code{target remote} +Then establish communication using the @code{target remote} command. +Its argument specifies how to communicate with the target +machine---either via a devicename attached to a direct serial line, or a +TCP port (usually to a terminal server which in turn has a serial line +to the target). For example, to use a serial line connected to the +device named @file{/dev/ttyb}: + +@example +target remote /dev/ttyb +@end example + +@cindex TCP port, @code{target remote} +To use a TCP connection, use an argument of the form +@code{@var{host}:port}. For example, to connect to port 2828 on a +terminal server named @code{manyfarms}: + +@example +target remote manyfarms:2828 +@end example +@end enumerate + +Now you can use all the usual commands to examine and change data and to +step and continue the remote program. + +To resume the remote program and stop debugging it, use the @code{detach} +command. + +@cindex interrupting remote programs +@cindex remote programs, interrupting +Whenever @value{GDBN} is waiting for the remote program, if you type the +interrupt character (often @key{C-C}), @value{GDBN} attempts to stop the +program. This may or may not succeed, depending in part on the hardware +and the serial drivers the remote system uses. If you type the +interrupt character once again, @value{GDBN} displays this prompt: + +@example +Interrupted while waiting for the program. +Give up (and stop debugging it)? (y or n) +@end example + +If you type @kbd{y}, @value{GDBN} abandons the remote debugging session. +(If you decide you want to try again later, you can use @samp{target +remote} again to connect once more.) If you type @kbd{n}, @value{GDBN} +goes back to waiting. + +@node Protocol +@subsubsection Communication protocol + +@cindex debugging stub, example +@cindex remote stub, example +@cindex stub example, remote debugging +The stub files provided with @value{GDBN} implement the target side of the +communication protocol, and the @value{GDBN} side is implemented in the +@value{GDBN} source file @file{remote.c}. Normally, you can simply allow +these subroutines to communicate, and ignore the details. (If you're +implementing your own stub file, you can still ignore the details: start +with one of the existing stub files. @file{sparc-stub.c} is the best +organized, and therefore the easiest to read.) + +However, there may be occasions when you need to know something about +the protocol---for example, if there is only one serial port to your +target machine, you might want your program to do something special if +it recognizes a packet meant for @value{GDBN}. + +@cindex protocol, @value{GDBN} remote serial +@cindex serial protocol, @value{GDBN} remote +@cindex remote serial protocol +All @value{GDBN} commands and responses (other than acknowledgements, which +are single characters) are sent as a packet which includes a +checksum. A packet is introduced with the character @samp{$}, and ends +with the character @samp{#} followed by a two-digit checksum: + +@example +$@var{packet info}#@var{checksum} +@end example + +@cindex checksum, for @value{GDBN} remote +@noindent +@var{checksum} is computed as the modulo 256 sum of the @var{packet +info} characters. + +When either the host or the target machine receives a packet, the first +response expected is an acknowledgement: a single character, either +@samp{+} (to indicate the package was received correctly) or @samp{-} +(to request retransmission). + +The host (@value{GDBN}) sends commands, and the target (the debugging stub +incorporated in your program) sends data in response. The target also +sends data when your program stops. + +Command packets are distinguished by their first character, which +identifies the kind of command. + +These are some of the commands currently supported (for a complete list of +commands, look in @file{gdb/remote.c.}): + +@table @code +@item g +Requests the values of CPU registers. + +@item G +Sets the values of CPU registers. + +@item m@var{addr},@var{count} +Read @var{count} bytes at location @var{addr}. + +@item M@var{addr},@var{count}:@dots{} +Write @var{count} bytes at location @var{addr}. + +@need 500 +@item c +@itemx c@var{addr} +Resume execution at the current address (or at @var{addr} if supplied). + +@need 500 +@item s +@itemx s@var{addr} +Step the target program for one instruction, from either the current +program counter or from @var{addr} if supplied. + +@item k +Kill the target program. + +@item ? +Report the most recent signal. To allow you to take advantage of the +@value{GDBN} signal handling commands, one of the functions of the debugging +stub is to report CPU traps as the corresponding POSIX signal values. + +@item T +Allows the remote stub to send only the registers that @value{GDBN} needs +to make a quick decision about single-stepping or conditional breakpoints. +This eliminates the need to fetch the entire register set for each instruction +being stepped through. + +The @value{GDBN} remote serial protocol now implements a write-through +cache for registers. @value{GDBN} only re-reads the registers if the +target has run. +@end table + +@kindex set remotedebug +@kindex show remotedebug +@cindex packets, reporting on stdout +@cindex serial connections, debugging +If you have trouble with the serial connection, you can use the command +@code{set remotedebug}. This makes @value{GDBN} report on all packets sent +back and forth across the serial line to the remote machine. The +packet-debugging information is printed on the @value{GDBN} standard output +stream. @code{set remotedebug off} turns it off, and @code{show +remotedebug} shows you its current state. + +@ifset GDBSERVER +@node Server +@subsubsection Using the @code{gdbserver} program + +@kindex gdbserver +@cindex remote connection without stubs +@code{gdbserver} is a control program for Unix-like systems, which +allows you to connect your program with a remote @value{GDBN} via +@code{target remote}---but without linking in the usual debugging stub. + +@code{gdbserver} is not a complete replacement for the debugging stubs, +because it requires essentially the same operating-system facilities +that @value{GDBN} itself does. In fact, a system that can run +@code{gdbserver} to connect to a remote @value{GDBN} could also run +@value{GDBN} locally! @code{gdbserver} is sometimes useful nevertheless, +because it is a much smaller program than @value{GDBN} itself. It is +also easier to port than all of @value{GDBN}, so you may be able to get +started more quickly on a new system by using @code{gdbserver}. +Finally, if you develop code for real-time systems, you may find that +the tradeoffs involved in real-time operation make it more convenient to +do as much development work as possible on another system, for example +by cross-compiling. You can use @code{gdbserver} to make a similar +choice for debugging. + +@value{GDBN} and @code{gdbserver} communicate via either a serial line +or a TCP connection, using the standard @value{GDBN} remote serial +protocol. + +@table @emph +@item On the target machine, +you need to have a copy of the program you want to debug. +@code{gdbserver} does not need your program's symbol table, so you can +strip the program if necessary to save space. @value{GDBN} on the host +system does all the symbol handling. + +To use the server, you must tell it how to communicate with @value{GDBN}; +the name of your program; and the arguments for your program. The +syntax is: + +@smallexample +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 +@samp{foo.txt} and communicate with @value{GDBN} over the serial port +@file{/dev/com1}: + +@smallexample +target> gdbserver /dev/com1 emacs foo.txt +@end smallexample + +@code{gdbserver} waits passively for the host @value{GDBN} to communicate +with it. + +To use a TCP connection instead of a serial line: + +@smallexample +target> gdbserver host:2345 emacs foo.txt +@end smallexample + +The only difference from the previous example is the first argument, +specifying that you are communicating with the host @value{GDBN} via +TCP. The @samp{host:2345} argument means that @code{gdbserver} is to +expect a TCP connection from machine @samp{host} to local TCP port 2345. +(Currently, the @samp{host} part is ignored.) You can choose any number +you want for the port number as long as it does not conflict with any +TCP ports already in use on the target system (for example, @code{23} is +reserved for @code{telnet}).@footnote{If you choose a port number that +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. + +@item On the @value{GDBN} host machine, +you need an unstripped copy of your program, since @value{GDBN} needs +symbols and debugging information. Start up @value{GDBN} as usual, +using the name of the local copy of your program as the first argument. +(You may also need the @w{@samp{--baud}} option if the serial line is +running at anything other than 9600 bps.) After that, use @code{target +remote} to establish communications with @code{gdbserver}. Its argument +is either a device name (usually a serial device, like +@file{/dev/ttyb}), or a TCP port descriptor in the form +@code{@var{host}:@var{PORT}}. For example: + +@smallexample +(@value{GDBP}) target remote /dev/ttyb +@end smallexample + +@noindent +communicates with the server via serial line @file{/dev/ttyb}, and + +@smallexample +(@value{GDBP}) target remote the-target:2345 +@end smallexample + +@noindent +communicates via a TCP connection to port 2345 on host @w{@file{the-target}}. +For TCP connections, you must start up @code{gdbserver} prior to using +the @code{target remote} command. Otherwise you may get an error whose +text depends on the host system, but which usually looks something like +@samp{Connection refused}. +@end table +@end ifset + +@ifset GDBSERVE +@node NetWare +@subsubsection Using the @code{gdbserve.nlm} program + +@kindex gdbserve.nlm +@code{gdbserve.nlm} is a control program for NetWare systems, which +allows you to connect your program with a remote @value{GDBN} via +@code{target remote}. + +@value{GDBN} and @code{gdbserve.nlm} communicate via a serial line, +using the standard @value{GDBN} remote serial protocol. + +@table @emph +@item On the target machine, +you need to have a copy of the program you want to debug. +@code{gdbserve.nlm} does not need your program's symbol table, so you +can strip the program if necessary to save space. @value{GDBN} on the +host system does all the symbol handling. + +To use the server, you must tell it how to communicate with +@value{GDBN}; the name of your program; and the arguments for your +program. The syntax is: + +@smallexample +load gdbserve [ BOARD=@var{board} ] [ PORT=@var{port} ] + [ BAUD=@var{baud} ] @var{program} [ @var{args} @dots{} ] +@end smallexample + +@var{board} and @var{port} specify the serial line; @var{baud} specifies +the baud rate used by the connection. @var{port} and @var{node} default +to 0, @var{baud} defaults to 9600 bps. + +For example, to debug Emacs with the argument @samp{foo.txt}and +communicate with @value{GDBN} over serial port number 2 or board 1 +using a 19200 bps connection: + +@smallexample +load gdbserve BOARD=1 PORT=2 BAUD=19200 emacs foo.txt +@end smallexample + +@item On the @value{GDBN} host machine, +you need an unstripped copy of your program, since @value{GDBN} needs +symbols and debugging information. Start up @value{GDBN} as usual, +using the name of the local copy of your program as the first argument. +(You may also need the @w{@samp{--baud}} option if the serial line is +running at anything other than 9600 bps. After that, use @code{target +remote} to establish communications with @code{gdbserve.nlm}. Its +argument is a device name (usually a serial device, like +@file{/dev/ttyb}). For example: + +@smallexample +(@value{GDBP}) target remote /dev/ttyb +@end smallexample + +@noindent +communications with the server via serial line @file{/dev/ttyb}. +@end table +@end ifset + +@end ifset + +@ifset I960 +@node i960-Nindy Remote +@subsection @value{GDBN} with a remote i960 (Nindy) + +@cindex Nindy +@cindex i960 +@dfn{Nindy} is a ROM Monitor program for Intel 960 target systems. When +@value{GDBN} is configured to control a remote Intel 960 using Nindy, you can +tell @value{GDBN} how to connect to the 960 in several ways: + +@itemize @bullet +@item +Through command line options specifying serial port, version of the +Nindy protocol, and communications speed; + +@item +By responding to a prompt on startup; + +@item +By using the @code{target} command at any point during your @value{GDBN} +session. @xref{Target Commands, ,Commands for managing targets}. + +@end itemize + +@menu +* Nindy Startup:: Startup with Nindy +* Nindy Options:: Options for Nindy +* Nindy Reset:: Nindy reset command +@end menu + +@node Nindy Startup +@subsubsection Startup with Nindy + +If you simply start @code{@value{GDBP}} without using any command-line +options, you are prompted for what serial port to use, @emph{before} you +reach the ordinary @value{GDBN} prompt: + +@example +Attach /dev/ttyNN -- specify NN, or "quit" to quit: +@end example + +@noindent +Respond to the prompt with whatever suffix (after @samp{/dev/tty}) +identifies the serial port you want to use. You can, if you choose, +simply start up with no Nindy connection by responding to the prompt +with an empty line. If you do this and later wish to attach to Nindy, +use @code{target} (@pxref{Target Commands, ,Commands for managing targets}). + +@node Nindy Options +@subsubsection Options for Nindy + +These are the startup options for beginning your @value{GDBN} session with a +Nindy-960 board attached: + +@table @code +@item -r @var{port} +Specify the serial port name of a serial interface to be used to connect +to the target system. This option is only available when @value{GDBN} is +configured for the Intel 960 target architecture. You may specify +@var{port} as any of: a full pathname (e.g. @samp{-r /dev/ttya}), a +device name in @file{/dev} (e.g. @samp{-r ttya}), or simply the unique +suffix for a specific @code{tty} (e.g. @samp{-r a}). + +@item -O +(An uppercase letter ``O'', not a zero.) Specify that @value{GDBN} should use +the ``old'' Nindy monitor protocol to connect to the target system. +This option is only available when @value{GDBN} is configured for the Intel 960 +target architecture. + +@quotation +@emph{Warning:} if you specify @samp{-O}, but are actually trying to +connect to a target system that expects the newer protocol, the connection +fails, appearing to be a speed mismatch. @value{GDBN} repeatedly +attempts to reconnect at several different line speeds. You can abort +this process with an interrupt. +@end quotation + +@item -brk +Specify that @value{GDBN} should first send a @code{BREAK} signal to the target +system, in an attempt to reset it, before connecting to a Nindy target. + +@quotation +@emph{Warning:} Many target systems do not have the hardware that this +requires; it only works with a few boards. +@end quotation +@end table + +The standard @samp{-b} option controls the line speed used on the serial +port. + +@c @group +@node Nindy Reset +@subsubsection Nindy reset command + +@table @code +@item reset +@kindex reset +For a Nindy target, this command sends a ``break'' to the remote target +system; this is only useful if the target has been equipped with a +circuit to perform a hard reset (or some other interesting action) when +a break is detected. +@end table +@c @end group +@end ifset + +@ifset AMD29K +@node UDI29K Remote +@subsection The UDI protocol for AMD29K + +@cindex UDI +@cindex AMD29K via UDI +@value{GDBN} supports AMD's UDI (``Universal Debugger Interface'') +protocol for debugging the a29k processor family. To use this +configuration with AMD targets running the MiniMON monitor, you need the +program @code{MONTIP}, available from AMD at no charge. You can also +use @value{GDBN} with the UDI-conformant a29k simulator program +@code{ISSTIP}, also available from AMD. + +@table @code +@item target udi @var{keyword} +@kindex udi +Select the UDI interface to a remote a29k board or simulator, where +@var{keyword} is an entry in the AMD configuration file @file{udi_soc}. +This file contains keyword entries which specify parameters used to +connect to a29k targets. If the @file{udi_soc} file is not in your +working directory, you must set the environment variable @samp{UDICONF} +to its pathname. +@end table + +@node EB29K Remote +@subsection The EBMON protocol for AMD29K + +@cindex EB29K board +@cindex running 29K programs + +AMD distributes a 29K development board meant to fit in a PC, together +with a DOS-hosted monitor program called @code{EBMON}. As a shorthand +term, this development system is called the ``EB29K''. To use +@value{GDBN} from a Unix system to run programs on the EB29K board, you +must first connect a serial cable between the PC (which hosts the EB29K +board) and a serial port on the Unix system. In the following, we +assume you've hooked the cable between the PC's @file{COM1} port and +@file{/dev/ttya} on the Unix system. + +@menu +* Comms (EB29K):: Communications setup +* gdb-EB29K:: EB29K cross-debugging +* Remote Log:: Remote log +@end menu + +@node Comms (EB29K) +@subsubsection Communications setup + +The next step is to set up the PC's port, by doing something like this +in DOS on the PC: + +@example +C:\> MODE com1:9600,n,8,1,none +@end example + +@noindent +This example---run on an MS DOS 4.0 system---sets the PC port to 9600 +bps, no parity, eight data bits, one stop bit, and no ``retry'' action; +you must match the communications parameters when establishing the Unix +end of the connection as well. +@c FIXME: Who knows what this "no retry action" crud from the DOS manual may +@c mean? It's optional; leave it out? ---doc@cygnus.com, 25feb91 + +To give control of the PC to the Unix side of the serial line, type +the following at the DOS console: + +@example +C:\> CTTY com1 +@end example + +@noindent +(Later, if you wish to return control to the DOS console, you can use +the command @code{CTTY con}---but you must send it over the device that +had control, in our example over the @file{COM1} serial line). + +From the Unix host, use a communications program such as @code{tip} or +@code{cu} to communicate with the PC; for example, + +@example +cu -s 9600 -l /dev/ttya +@end example + +@noindent +The @code{cu} options shown specify, respectively, the linespeed and the +serial port to use. If you use @code{tip} instead, your command line +may look something like the following: + +@example +tip -9600 /dev/ttya +@end example + +@noindent +Your system may require a different name where we show +@file{/dev/ttya} as the argument to @code{tip}. The communications +parameters, including which port to use, are associated with the +@code{tip} argument in the ``remote'' descriptions file---normally the +system table @file{/etc/remote}. +@c FIXME: What if anything needs doing to match the "n,8,1,none" part of +@c the DOS side's comms setup? cu can support -o (odd +@c parity), -e (even parity)---apparently no settings for no parity or +@c for character size. Taken from stty maybe...? John points out tip +@c can set these as internal variables, eg ~s parity=none; man stty +@c suggests that it *might* work to stty these options with stdin or +@c stdout redirected... ---doc@cygnus.com, 25feb91 + +@kindex EBMON +Using the @code{tip} or @code{cu} connection, change the DOS working +directory to the directory containing a copy of your 29K program, then +start the PC program @code{EBMON} (an EB29K control program supplied +with your board by AMD). You should see an initial display from +@code{EBMON} similar to the one that follows, ending with the +@code{EBMON} prompt @samp{#}--- + +@example +C:\> G: + +G:\> CD \usr\joe\work29k + +G:\USR\JOE\WORK29K> EBMON +Am29000 PC Coprocessor Board Monitor, version 3.0-18 +Copyright 1990 Advanced Micro Devices, Inc. +Written by Gibbons and Associates, Inc. + +Enter '?' or 'H' for help + +PC Coprocessor Type = EB29K +I/O Base = 0x208 +Memory Base = 0xd0000 + +Data Memory Size = 2048KB +Available I-RAM Range = 0x8000 to 0x1fffff +Available D-RAM Range = 0x80002000 to 0x801fffff + +PageSize = 0x400 +Register Stack Size = 0x800 +Memory Stack Size = 0x1800 + +CPU PRL = 0x3 +Am29027 Available = No +Byte Write Available = Yes + +# ~. +@end example + +Then exit the @code{cu} or @code{tip} program (done in the example by +typing @code{~.} at the @code{EBMON} prompt). @code{EBMON} keeps +running, ready for @value{GDBN} to take over. + +For this example, we've assumed what is probably the most convenient +way to make sure the same 29K program is on both the PC and the Unix +system: a PC/NFS connection that establishes ``drive @code{G:}'' on the +PC as a file system on the Unix host. If you do not have PC/NFS or +something similar connecting the two systems, you must arrange some +other way---perhaps floppy-disk transfer---of getting the 29K program +from the Unix system to the PC; @value{GDBN} does @emph{not} download it over the +serial line. + +@node gdb-EB29K +@subsubsection EB29K cross-debugging + +Finally, @code{cd} to the directory containing an image of your 29K +program on the Unix system, and start @value{GDBN}---specifying as argument the +name of your 29K program: + +@example +cd /usr/joe/work29k +@value{GDBP} myfoo +@end example + +@need 500 +Now you can use the @code{target} command: + +@example +target amd-eb /dev/ttya 9600 MYFOO +@c FIXME: test above 'target amd-eb' as spelled, with caps! caps are meant to +@c emphasize that this is the name as seen by DOS (since I think DOS is +@c single-minded about case of letters). ---doc@cygnus.com, 25feb91 +@end example + +@noindent +In this example, we've assumed your program is in a file called +@file{myfoo}. Note that the filename given as the last argument to +@code{target amd-eb} should be the name of the program as it appears to DOS. +In our example this is simply @code{MYFOO}, but in general it can include +a DOS path, and depending on your transfer mechanism may not resemble +the name on the Unix side. + +At this point, you can set any breakpoints you wish; when you are ready +to see your program run on the 29K board, use the @value{GDBN} command +@code{run}. + +To stop debugging the remote program, use the @value{GDBN} @code{detach} +command. + +To return control of the PC to its console, use @code{tip} or @code{cu} +once again, after your @value{GDBN} session has concluded, to attach to +@code{EBMON}. You can then type the command @code{q} to shut down +@code{EBMON}, returning control to the DOS command-line interpreter. +Type @code{CTTY con} to return command input to the main DOS console, +and type @kbd{~.} to leave @code{tip} or @code{cu}. + +@node Remote Log +@subsubsection Remote log +@kindex eb.log +@cindex log file for EB29K + +The @code{target amd-eb} command creates a file @file{eb.log} in the +current working directory, to help debug problems with the connection. +@file{eb.log} records all the output from @code{EBMON}, including echoes +of the commands sent to it. Running @samp{tail -f} on this file in +another window often helps to understand trouble with @code{EBMON}, or +unexpected events on the PC side of the connection. + +@end ifset + +@ifset ST2000 +@node ST2000 Remote +@subsection @value{GDBN} with a Tandem ST2000 + +To connect your ST2000 to the host system, see the manufacturer's +manual. Once the ST2000 is physically attached, you can run: + +@example +target st2000 @var{dev} @var{speed} +@end example + +@noindent +to establish it as your debugging environment. @var{dev} is normally +the name of a serial device, such as @file{/dev/ttya}, connected to the +ST2000 via a serial line. You can instead specify @var{dev} as a TCP +connection (for example, to a serial line attached via a terminal +concentrator) using the syntax @code{@var{hostname}:@var{portnumber}}. + +The @code{load} and @code{attach} commands are @emph{not} defined for +this target; you must load your program into the ST2000 as you normally +would for standalone operation. @value{GDBN} reads debugging information +(such as symbols) from a separate, debugging version of the program +available on your host computer. +@c FIXME!! This is terribly vague; what little content is here is +@c basically hearsay. + +@cindex ST2000 auxiliary commands +These auxiliary @value{GDBN} commands are available to help you with the ST2000 +environment: + +@table @code +@item st2000 @var{command} +@kindex st2000 @var{cmd} +@cindex STDBUG commands (ST2000) +@cindex commands to STDBUG (ST2000) +Send a @var{command} to the STDBUG monitor. See the manufacturer's +manual for available commands. + +@item connect +@cindex connect (to STDBUG) +Connect the controlling terminal to the STDBUG command monitor. When +you are done interacting with STDBUG, typing either of two character +sequences gets you back to the @value{GDBN} command prompt: +@kbd{@key{RET}~.} (Return, followed by tilde and period) or +@kbd{@key{RET}~@key{C-d}} (Return, followed by tilde and control-D). +@end table +@end ifset + +@ifset VXWORKS +@node VxWorks Remote +@subsection @value{GDBN} and VxWorks +@cindex VxWorks + +@value{GDBN} enables developers to spawn and debug tasks running on networked +VxWorks targets from a Unix host. Already-running tasks spawned from +the VxWorks shell can also be debugged. @value{GDBN} uses code that runs on +both the Unix host and on the VxWorks target. The program +@code{gdb} is installed and executed on the Unix host. (It may be +installed with the name @code{vxgdb}, to distinguish it from a +@value{GDBN} for debugging programs on the host itself.) + +@table @code +@item VxWorks-timeout @var{args} +@kindex vxworks-timeout +All VxWorks-based targets now support the option @code{vxworks-timeout}. +This option is set by the user, and @var{args} represents the number of +seconds @value{GDBN} waits for responses to rpc's. You might use this if +your VxWorks target is a slow software simulator or is on the far side +of a thin network line. +@end table + +The following information on connecting to VxWorks was current when +this manual was produced; newer releases of VxWorks may use revised +procedures. + +@kindex INCLUDE_RDB +To use @value{GDBN} with VxWorks, you must rebuild your VxWorks kernel +to include the remote debugging interface routines in the VxWorks +library @file{rdb.a}. To do this, define @code{INCLUDE_RDB} in the +VxWorks configuration file @file{configAll.h} and rebuild your VxWorks +kernel. The resulting kernel contains @file{rdb.a}, and spawns the +source debugging task @code{tRdbTask} when VxWorks is booted. For more +information on configuring and remaking VxWorks, see the manufacturer's +manual. +@c VxWorks, see the @cite{VxWorks Programmer's Guide}. + +Once you have included @file{rdb.a} in your VxWorks system image and set +your Unix execution search path to find @value{GDBN}, you are ready to +run @value{GDBN}. From your Unix host, run @code{gdb} (or @code{vxgdb}, +depending on your installation). + +@value{GDBN} comes up showing the prompt: + +@example +(vxgdb) +@end example + +@menu +* VxWorks Connection:: Connecting to VxWorks +* VxWorks Download:: VxWorks download +* VxWorks Attach:: Running tasks +@end menu + +@node VxWorks Connection +@subsubsection Connecting to VxWorks + +The @value{GDBN} command @code{target} lets you connect to a VxWorks target on the +network. To connect to a target whose host name is ``@code{tt}'', type: + +@example +(vxgdb) target vxworks tt +@end example + +@need 750 +@value{GDBN} displays messages like these: + +@smallexample +Attaching remote machine across net... +Connected to tt. +@end smallexample + +@need 1000 +@value{GDBN} then attempts to read the symbol tables of any object modules +loaded into the VxWorks target since it was last booted. @value{GDBN} locates +these files by searching the directories listed in the command search +path (@pxref{Environment, ,Your program's environment}); if it fails +to find an object file, it displays a message such as: + +@example +prog.o: No such file or directory. +@end example + +When this happens, add the appropriate directory to the search path with +the @value{GDBN} command @code{path}, and execute the @code{target} +command again. + +@node VxWorks Download +@subsubsection VxWorks download + +@cindex download to VxWorks +If you have connected to the VxWorks target and you want to debug an +object that has not yet been loaded, you can use the @value{GDBN} +@code{load} command to download a file from Unix to VxWorks +incrementally. The object file given as an argument to the @code{load} +command is actually opened twice: first by the VxWorks target in order +to download the code, then by @value{GDBN} in order to read the symbol +table. This can lead to problems if the current working directories on +the two systems differ. If both systems have NFS mounted the same +filesystems, you can avoid these problems by using absolute paths. +Otherwise, it is simplest to set the working directory on both systems +to the directory in which the object file resides, and then to reference +the file by its name, without any path. For instance, a program +@file{prog.o} may reside in @file{@var{vxpath}/vw/demo/rdb} in VxWorks +and in @file{@var{hostpath}/vw/demo/rdb} on the host. To load this +program, type this on VxWorks: + +@example +-> cd "@var{vxpath}/vw/demo/rdb" +@end example +v +Then, in @value{GDBN}, type: + +@example +(vxgdb) cd @var{hostpath}/vw/demo/rdb +(vxgdb) load prog.o +@end example + +@value{GDBN} displays a response similar to this: + +@smallexample +Reading symbol data from wherever/vw/demo/rdb/prog.o... done. +@end smallexample + +You can also use the @code{load} command to reload an object module +after editing and recompiling the corresponding source file. Note that +this makes @value{GDBN} delete all currently-defined breakpoints, +auto-displays, and convenience variables, and to clear the value +history. (This is necessary in order to preserve the integrity of +debugger data structures that reference the target system's symbol +table.) + +@node VxWorks Attach +@subsubsection Running tasks + +@cindex running VxWorks tasks +You can also attach to an existing task using the @code{attach} command as +follows: + +@example +(vxgdb) attach @var{task} +@end example + +@noindent +where @var{task} is the VxWorks hexadecimal task ID. The task can be running +or suspended when you attach to it. Running tasks are suspended at +the time of attachment. +@end ifset + +@ifset H8 +@node Hitachi Remote +@subsection @value{GDBN} and Hitachi microprocessors +@value{GDBN} needs to know these things to talk to your +Hitachi SH, H8/300, or H8/500: + +@enumerate +@item +that you want to use @samp{target hms}, the remote debugging interface +for Hitachi microprocessors, or @samp{target e7000}, the in-circuit +emulator for the Hitachi SH and the Hitachi 300H. (@samp{target hms} is +the default when GDB is configured specifically for the Hitachi SH, +H8/300, or H8/500.) + +@item +what serial device connects your host to your Hitachi board (the first +serial device available on your host is the default). + +@ifclear H8EXCLUSIVE +@c this is only for Unix hosts, not of interest to Hitachi +@item +what speed to use over the serial device. +@end ifclear +@end enumerate + +@menu +* Hitachi Boards:: Connecting to Hitachi boards. +* Hitachi ICE:: Using the E7000 In-Circuit Emulator. +* Hitachi Special:: Special @value{GDBN} commands for Hitachi micros. +@end menu + +@node Hitachi Boards +@subsubsection Connecting to Hitachi boards + +@ifclear H8EXCLUSIVE +@c only for Unix hosts +@kindex device +@cindex serial device, Hitachi micros +Use the special @code{@value{GDBP}} command @samp{device @var{port}} if you +need to explicitly set the serial device. The default @var{port} is the +first available port on your host. This is only necessary on Unix +hosts, where it is typically something like @file{/dev/ttya}. + +@kindex speed +@cindex serial line speed, Hitachi micros +@code{@value{GDBP}} has another special command to set the communications +speed: @samp{speed @var{bps}}. This command also is only used from Unix +hosts; on DOS hosts, set the line speed as usual from outside GDB with +the DOS @kbd{mode} command (for instance, @w{@samp{mode +com2:9600,n,8,1,p}} for a 9600 bps connection). + +The @samp{device} and @samp{speed} commands are available only when you +use a Unix host to debug your Hitachi microprocessor programs. If you +use a DOS host, +@end ifclear +@value{GDBN} depends on an auxiliary terminate-and-stay-resident program +called @code{asynctsr} to communicate with the development board +through a PC serial port. You must also use the DOS @code{mode} command +to set up the serial port on the DOS side. + +@ifset DOSHOST +The following sample session illustrates the steps needed to start a +program under @value{GDBN} control on an H8/300. The example uses a +sample H8/300 program called @file{t.x}. The procedure is the same for +the Hitachi SH and the H8/500. + +First hook up your development board. In this example, we use a +board attached to serial port @code{COM2}; if you use a different serial +port, substitute its name in the argument of the @code{mode} command. +When you call @code{asynctsr}, the auxiliary comms program used by the +degugger, you give it just the numeric part of the serial port's name; +for example, @samp{asyncstr 2} below runs @code{asyncstr} on +@code{COM2}. + +@example +C:\H8300\TEST> asynctsr 2 +C:\H8300\TEST> mode com2:9600,n,8,1,p + +Resident portion of MODE loaded + +COM2: 9600, n, 8, 1, p + +@end example + +@quotation +@emph{Warning:} We have noticed a bug in PC-NFS that conflicts with +@code{asynctsr}. If you also run PC-NFS on your DOS host, you may need to +disable it, or even boot without it, to use @code{asynctsr} to control +your development board. +@end quotation + +@kindex target hms +Now that serial communications are set up, and the development board is +connected, you can start up @value{GDBN}. Call @code{@value{GDBP}} with +the name of your program as the argument. @code{@value{GDBP}} prompts +you, as usual, with the prompt @samp{(@value{GDBP})}. Use two special +commands to begin your debugging session: @samp{target hms} to specify +cross-debugging to the Hitachi board, and the @code{load} command to +download your program to the board. @code{load} displays the names of +the program's sections, and a @samp{*} for each 2K of data downloaded. +(If you want to refresh @value{GDBN} data on symbols or on the +executable file without downloading, use the @value{GDBN} commands +@code{file} or @code{symbol-file}. These commands, and @code{load} +itself, are described in @ref{Files,,Commands to specify files}.) + +@smallexample +(eg-C:\H8300\TEST) @value{GDBP} t.x +GDB is free software and you are welcome to distribute copies + of it under certain conditions; type "show copying" to see + the conditions. +There is absolutely no warranty for GDB; type "show warranty" +for details. +GDB @value{GDBVN}, Copyright 1992 Free Software Foundation, Inc... +(gdb) target hms +Connected to remote H8/300 HMS system. +(gdb) load t.x +.text : 0x8000 .. 0xabde *********** +.data : 0xabde .. 0xad30 * +.stack : 0xf000 .. 0xf014 * +@end smallexample + +At this point, you're ready to run or debug your program. From here on, +you can use all the usual @value{GDBN} commands. The @code{break} command +sets breakpoints; the @code{run} command starts your program; +@code{print} or @code{x} display data; the @code{continue} command +resumes execution after stopping at a breakpoint. You can use the +@code{help} command at any time to find out more about @value{GDBN} commands. + +Remember, however, that @emph{operating system} facilities aren't +available on your development board; for example, if your program hangs, +you can't send an interrupt---but you can press the @sc{reset} switch! + +Use the @sc{reset} button on the development board +@itemize @bullet +@item +to interrupt your program (don't use @kbd{ctl-C} on the DOS host---it has +no way to pass an interrupt signal to the development board); and + +@item +to return to the @value{GDBN} command prompt after your program finishes +normally. The communications protocol provides no other way for @value{GDBN} +to detect program completion. +@end itemize + +In either case, @value{GDBN} sees the effect of a @sc{reset} on the +development board as a ``normal exit'' of your program. +@end ifset + +@node Hitachi ICE +@subsubsection Using the E7000 in-circuit emulator + +@kindex target e7000 +You can use the E7000 in-circuit emulator to develop code for either the +Hitachi SH or the H8/300H. Use one of these forms of the @samp{target +e7000} command to connect @value{GDBN} to your E7000: + +@table @code +@item target e7000 @var{port} @var{speed} +Use this form if your E7000 is connected to a serial port. The +@var{port} argument identifies what serial port to use (for example, +@samp{com2}). The third argument is the line speed in bits per second +(for example, @samp{9600}). + +@item target e7000 @var{hostname} +If your E7000 is installed as a host on a TCP/IP network, you can just +specify its hostname; @value{GDBN} uses @code{telnet} to connect. +@end table + +@node Hitachi Special +@subsubsection Special @value{GDBN} commands for Hitachi micros + +Some @value{GDBN} commands are available only on the H8/300 or the +H8/500 configurations: + +@table @code +@kindex set machine +@kindex show machine +@item set machine h8300 +@itemx set machine h8300h +Condition @value{GDBN} for one of the two variants of the H8/300 +architecture with @samp{set machine}. You can use @samp{show machine} +to check which variant is currently in effect. + +@kindex set memory @var{mod} +@cindex memory models, H8/500 +@item set memory @var{mod} +@itemx show memory +Specify which H8/500 memory model (@var{mod}) you are using with +@samp{set memory}; check which memory model is in effect with @samp{show +memory}. The accepted values for @var{mod} are @code{small}, +@code{big}, @code{medium}, and @code{compact}. +@end table + +@end ifset + +@ifset MIPS +@node MIPS Remote +@subsection @value{GDBN} and remote MIPS boards + +@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}. + +@need 1000 +Use these @value{GDBN} commands to specify the connection to your target board: + +@table @code +@item target mips @var{port} +@kindex target mips @var{port} +To run a program on the board, start up @code{@value{GDBP}} with the +name of your program as the argument. To connect to the board, use the +command @samp{target mips @var{port}}, where @var{port} is the name of +the serial port connected to the board. If the program has not already +been downloaded to the board, you may use the @code{load} command to +download it. You can then use all the usual @value{GDBN} commands. + +For example, this sequence connects to the target board through a serial +port, and loads and runs a program called @var{prog} through the +debugger: + +@example +host$ @value{GDBP} @var{prog} +GDB is free software and @dots{} +(gdb) target mips /dev/ttyb +(gdb) load @var{prog} +(gdb) run +@end example + +@item target mips @var{hostname}:@var{portnumber} +On some @value{GDBN} host configurations, you can specify a TCP +connection (for instance, to a serial line managed by a terminal +concentrator) instead of a serial port, using the syntax +@samp{@var{hostname}:@var{portnumber}}. +@end table + +@noindent +@value{GDBN} also supports these special commands for MIPS targets: + +@table @code +@item set processor @var{args} +@itemx show processor +@kindex set processor @var{args} +@kindex show processor +Use the @code{set processor} command to set the type of MIPS +processor when you want to access processor-type-specific registers. +For example, @code{set processor @var{r3041}} tells @value{GDBN} +to use the CPO registers appropriate for the 3041 chip. +Use the @code{show processor} command to see what MIPS processor @value{GDBN} +is using. Use the @code{info reg} command to see what registers +@value{GDBN} is using. + +@item set mipsfpu double +@itemx set mipsfpu single +@itemx set mipsfpu none +@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 +coprocessor, you should use the command @samp{set mipsfpu none} (if you +need this, you may wish to put the command in your @value{GDBINIT} +file). This tells @value{GDBN} how to find the return value of +functions which return floating point values. It also allows +@value{GDBN} to avoid saving the floating point registers when calling +functions on the board. If you are using a floating point coprocessor +with only single precision floating point support, as on the @sc{r4650} +processor, use the command @samp{set mipsfpu single}. The default +double precision floating point coprocessor may be selected using +@samp{set mipsfpu double}. + +In previous versions the only choices were double precision or no +floating point, so @samp{set mipsfpu on} will select double precision +and @samp{set mipsfpu off} will select no floating point. + +As usual, you can inquire about the @code{mipsfpu} variable with +@samp{show mipsfpu}. + +@item set remotedebug @var{n} +@itemx show remotedebug +@kindex set remotedebug +@kindex show remotedebug +@cindex @code{remotedebug}, MIPS protocol +@cindex MIPS @code{remotedebug} protocol +@c FIXME! For this to be useful, you must know something about the MIPS +@c FIXME...protocol. Where is it described? +You can see some debugging information about communications with the board +by setting the @code{remotedebug} variable. If you set it to @code{1} using +@samp{set remotedebug 1}, every packet is displayed. If you set it +to @code{2}, every character is displayed. You can check the current value +at any time with the command @samp{show remotedebug}. + +@item set timeout @var{seconds} +@itemx set retransmit-timeout @var{seconds} +@itemx show timeout +@itemx show retransmit-timeout +@cindex @code{timeout}, MIPS protocol +@cindex @code{retransmit-timeout}, 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 +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 acknowledgement 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}.) + +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 +forever because it has no way of knowing how long the program is going +to run before stopping. +@end table +@end ifset + +@ifset SIMS +@node Simulator +@subsection Simulated CPU target + +@ifset GENERIC +@cindex simulator +@cindex simulator, Z8000 +@cindex Z8000 simulator +@cindex simulator, H8/300 or H8/500 +@cindex H8/300 or H8/500 simulator +@cindex simulator, Hitachi SH +@cindex Hitachi SH simulator +@cindex CPU simulator +For some configurations, @value{GDBN} includes a CPU simulator that you +can use instead of a hardware CPU to debug your programs. Currently, +a simulator is available when @value{GDBN} is configured to debug Zilog +Z8000 or Hitachi microprocessor targets. +@end ifset + +@ifclear GENERIC +@ifset H8 +@cindex simulator, H8/300 or H8/500 +@cindex Hitachi H8/300 or H8/500 simulator +@cindex simulator, Hitachi SH +@cindex Hitachi SH simulator +When configured for debugging Hitachi microprocessor targets, +@value{GDBN} includes a CPU simulator for the target chip (a Hitachi SH, +H8/300, or H8/500). +@end ifset + +@ifset Z8K +@cindex simulator, Z8000 +@cindex Zilog Z8000 simulator +When configured for debugging Zilog Z8000 targets, @value{GDBN} includes +a Z8000 simulator. +@end ifset +@end ifclear + +@ifset Z8K +For the Z8000 family, @samp{target sim} simulates either the Z8002 (the +unsegmented variant of the Z8000 architecture) or the Z8001 (the +segmented variant). The simulator recognizes which architecture is +appropriate by inspecting the object code. +@end ifset + +@table @code +@item target sim +@kindex sim +@kindex target sim +Debug programs on a simulated CPU +@ifset GENERIC +(which CPU depends on the @value{GDBN} configuration) +@end ifset +@end table + +@noindent +After specifying this target, you can debug programs for the simulated +CPU in the same style as programs for your host computer; use the +@code{file} command to load a new program image, the @code{run} command +to run your program, and so on. + +As well as making available all the usual machine registers (see +@code{info reg}), this debugging target provides three additional items +of information as specially named registers: + +@table @code +@item cycles +Counts clock-ticks in the simulator. + +@item insts +Counts instructions run in the simulator. + +@item time +Execution time in 60ths of a second. +@end table + +You can refer to these values in @value{GDBN} expressions with the usual +conventions; for example, @w{@samp{b fputc if $cycles>5000}} sets a +conditional breakpoint that suspends only after at least 5000 +simulated clock ticks. +@end ifset diff --git a/contrib/gdb/gdb/doc/stabs.texinfo b/contrib/gdb/gdb/doc/stabs.texinfo new file mode 100644 index 000000000000..b0d26c387112 --- /dev/null +++ b/contrib/gdb/gdb/doc/stabs.texinfo @@ -0,0 +1,4004 @@ +\input texinfo +@setfilename stabs.info + +@c @finalout + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Stabs: (stabs). The "stabs" debugging information format. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This document describes the stabs debugging symbol tables. + +Copyright 1992, 1993 Free Software Foundation, Inc. +Contributed by Cygnus Support. Written by Julia Menapace, Jim Kingdon, +and David MacKenzie. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy or distribute modified versions of this +manual under the terms of the GPL (for which purpose this text may be +regarded as a program in the language TeX). +@end ifinfo + +@setchapternewpage odd +@settitle STABS +@titlepage +@title The ``stabs'' debug format +@author Julia Menapace, Jim Kingdon, David MacKenzie +@author Cygnus Support +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 2.125 $} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1992, 1993 Free Software Foundation, Inc. +Contributed by Cygnus Support. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@end titlepage + +@ifinfo +@node Top +@top The "stabs" representation of debugging information + +This document describes the stabs debugging format. + +@menu +* Overview:: Overview of stabs +* Program Structure:: Encoding of the structure of the program +* Constants:: Constants +* Variables:: +* Types:: Type definitions +* Symbol Tables:: Symbol information in symbol tables +* Cplusplus:: Stabs specific to C++ +* Stab Types:: Symbol types in a.out files +* Symbol Descriptors:: Table of symbol descriptors +* Type Descriptors:: Table of type descriptors +* Expanded Reference:: Reference information by stab type +* Questions:: Questions and anomolies +* Sun Differences:: Differences between GNU stabs and Sun + native stabs +* Stab Sections:: In some object file formats, stabs are + in sections. +* Symbol Types Index:: Index of symbolic stab symbol type names. +@end menu +@end ifinfo + + +@node Overview +@chapter Overview of Stabs + +@dfn{Stabs} refers to a format for information that describes a program +to a debugger. This format was apparently invented by +Peter Kessler at +the University of California at Berkeley, for the @code{pdx} Pascal +debugger; the format has spread widely since then. + +This document is one of the few published sources of documentation on +stabs. It is believed to be comprehensive for stabs used by C. The +lists of symbol descriptors (@pxref{Symbol Descriptors}) and type +descriptors (@pxref{Type Descriptors}) are believed to be completely +comprehensive. Stabs for COBOL-specific features and for variant +records (used by Pascal and Modula-2) are poorly documented here. + +@c FIXME: Need to document all OS9000 stuff in GDB; see all references +@c to os9k_stabs in stabsread.c. + +Other sources of information on stabs are @cite{Dbx and Dbxtool +Interfaces}, 2nd edition, by Sun, 1988, and @cite{AIX Version 3.2 Files +Reference}, Fourth Edition, September 1992, "dbx Stabstring Grammar" in +the a.out section, page 2-31. This document is believed to incorporate +the information from those two sources except where it explicitly directs +you to them for more information. + +@menu +* Flow:: Overview of debugging information flow +* Stabs Format:: Overview of stab format +* String Field:: The string field +* C Example:: A simple example in C source +* Assembly Code:: The simple example at the assembly level +@end menu + +@node Flow +@section Overview of Debugging Information Flow + +The GNU C compiler compiles C source in a @file{.c} file into assembly +language in a @file{.s} file, which the assembler translates into +a @file{.o} file, which the linker combines with other @file{.o} files and +libraries to produce an executable file. + +With the @samp{-g} option, GCC puts in the @file{.s} file additional +debugging information, which is slightly transformed by the assembler +and linker, and carried through into the final executable. This +debugging information describes features of the source file like line +numbers, the types and scopes of variables, and function names, +parameters, and scopes. + +For some object file formats, the debugging information is encapsulated +in assembler directives known collectively as @dfn{stab} (symbol table) +directives, which are interspersed with the generated code. Stabs are +the native format for debugging information in the a.out and XCOFF +object file formats. The GNU tools can also emit stabs in the COFF and +ECOFF object file formats. + +The assembler adds the information from stabs to the symbol information +it places by default in the symbol table and the string table of the +@file{.o} file it is building. The linker consolidates the @file{.o} +files into one executable file, with one symbol table and one string +table. Debuggers use the symbol and string tables in the executable as +a source of debugging information about the program. + +@node Stabs Format +@section Overview of Stab Format + +There are three overall formats for stab assembler directives, +differentiated by the first word of the stab. The name of the directive +describes which combination of four possible data fields follows. It is +either @code{.stabs} (string), @code{.stabn} (number), or @code{.stabd} +(dot). IBM's XCOFF assembler uses @code{.stabx} (and some other +directives such as @code{.file} and @code{.bi}) instead of +@code{.stabs}, @code{.stabn} or @code{.stabd}. + +The overall format of each class of stab is: + +@example +.stabs "@var{string}",@var{type},@var{other},@var{desc},@var{value} +.stabn @var{type},@var{other},@var{desc},@var{value} +.stabd @var{type},@var{other},@var{desc} +.stabx "@var{string}",@var{value},@var{type},@var{sdb-type} +@end example + +@c what is the correct term for "current file location"? My AIX +@c assembler manual calls it "the value of the current location counter". +For @code{.stabn} and @code{.stabd}, there is no @var{string} (the +@code{n_strx} field is zero; see @ref{Symbol Tables}). For +@code{.stabd}, the @var{value} field is implicit and has the value of +the current file location. For @code{.stabx}, the @var{sdb-type} field +is unused for stabs and can always be set to zero. The @var{other} +field is almost always unused and can be set to zero. + +The number in the @var{type} field gives some basic information about +which type of stab this is (or whether it @emph{is} a stab, as opposed +to an ordinary symbol). Each valid type number defines a different stab +type; further, the stab type defines the exact interpretation of, and +possible values for, any remaining @var{string}, @var{desc}, or +@var{value} fields present in the stab. @xref{Stab Types}, for a list +in numeric order of the valid @var{type} field values for stab directives. + +@node String Field +@section The String Field + +For most stabs the string field holds the meat of the +debugging information. The flexible nature of this field +is what makes stabs extensible. For some stab types the string field +contains only a name. For other stab types the contents can be a great +deal more complex. + +The overall format of the string field for most stab types is: + +@example +"@var{name}:@var{symbol-descriptor} @var{type-information}" +@end example + +@var{name} is the name of the symbol represented by the stab; it can +contain a pair of colons (@pxref{Nested Symbols}). @var{name} can be +omitted, which means the stab represents an unnamed object. For +example, @samp{:t10=*2} defines type 10 as a pointer to type 2, but does +not give the type a name. Omitting the @var{name} field is supported by +AIX dbx and GDB after about version 4.8, but not other debuggers. GCC +sometimes uses a single space as the name instead of omitting the name +altogether; apparently that is supported by most debuggers. + +The @var{symbol-descriptor} following the @samp{:} is an alphabetic +character that tells more specifically what kind of symbol the stab +represents. If the @var{symbol-descriptor} is omitted, but type +information follows, then the stab represents a local variable. For a +list of symbol descriptors, see @ref{Symbol Descriptors}. The @samp{c} +symbol descriptor is an exception in that it is not followed by type +information. @xref{Constants}. + +@var{type-information} is either a @var{type-number}, or +@samp{@var{type-number}=}. A @var{type-number} alone is a type +reference, referring directly to a type that has already been defined. + +The @samp{@var{type-number}=} form is a type definition, where the +number represents a new type which is about to be defined. The type +definition may refer to other types by number, and those type numbers +may be followed by @samp{=} and nested definitions. Also, the Lucid +compiler will repeat @samp{@var{type-number}=} more than once if it +wants to define several type numbers at once. + +In a type definition, if the character that follows the equals sign is +non-numeric then it is a @var{type-descriptor}, and tells what kind of +type is about to be defined. Any other values following the +@var{type-descriptor} vary, depending on the @var{type-descriptor}. +@xref{Type Descriptors}, for a list of @var{type-descriptor} values. If +a number follows the @samp{=} then the number is a @var{type-reference}. +For a full description of types, @ref{Types}. + +There is an AIX extension for type attributes. Following the @samp{=} +are any number of type attributes. Each one starts with @samp{@@} and +ends with @samp{;}. Debuggers, including AIX's dbx and GDB 4.10, skip +any type attributes they do not recognize. GDB 4.9 and other versions +of dbx may not do this. Because of a conflict with C++ +(@pxref{Cplusplus}), new attributes should not be defined which begin +with a digit, @samp{(}, or @samp{-}; GDB may be unable to distinguish +those from the C++ type descriptor @samp{@@}. The attributes are: + +@table @code +@item a@var{boundary} +@var{boundary} is an integer specifying the alignment. I assume it +applies to all variables of this type. + +@item p@var{integer} +Pointer class (for checking). Not sure what this means, or how +@var{integer} is interpreted. + +@item P +Indicate this is a packed type, meaning that structure fields or array +elements are placed more closely in memory, to save memory at the +expense of speed. + +@item s@var{size} +Size in bits of a variable of this type. This is fully supported by GDB +4.11 and later. + +@item S +Indicate that this type is a string instead of an array of characters, +or a bitstring instead of a set. It doesn't change the layout of the +data being represented, but does enable the debugger to know which type +it is. +@end table + +All of this can make the string field quite long. All versions of GDB, +and some versions of dbx, can handle arbitrarily long strings. But many +versions of dbx (or assemblers or linkers, I'm not sure which) +cretinously limit the strings to about 80 characters, so compilers which +must work with such systems need to split the @code{.stabs} directive +into several @code{.stabs} directives. Each stab duplicates every field +except the string field. The string field of every stab except the last +is marked as continued with a backslash at the end (in the assembly code +this may be written as a double backslash, depending on the assembler). +Removing the backslashes and concatenating the string fields of each +stab produces the original, long string. Just to be incompatible (or so +they don't have to worry about what the assembler does with +backslashes), AIX can use @samp{?} instead of backslash. + +@node C Example +@section A Simple Example in C Source + +To get the flavor of how stabs describe source information for a C +program, let's look at the simple program: + +@example +main() +@{ + printf("Hello world"); +@} +@end example + +When compiled with @samp{-g}, the program above yields the following +@file{.s} file. Line numbers have been added to make it easier to refer +to parts of the @file{.s} file in the description of the stabs that +follows. + +@node Assembly Code +@section The Simple Example at the Assembly Level + +This simple ``hello world'' example demonstrates several of the stab +types used to describe C language source files. + +@example +1 gcc2_compiled.: +2 .stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 +3 .stabs "hello.c",100,0,0,Ltext0 +4 .text +5 Ltext0: +6 .stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 +7 .stabs "char:t2=r2;0;127;",128,0,0,0 +8 .stabs "long int:t3=r1;-2147483648;2147483647;",128,0,0,0 +9 .stabs "unsigned int:t4=r1;0;-1;",128,0,0,0 +10 .stabs "long unsigned int:t5=r1;0;-1;",128,0,0,0 +11 .stabs "short int:t6=r1;-32768;32767;",128,0,0,0 +12 .stabs "long long int:t7=r1;0;-1;",128,0,0,0 +13 .stabs "short unsigned int:t8=r1;0;65535;",128,0,0,0 +14 .stabs "long long unsigned int:t9=r1;0;-1;",128,0,0,0 +15 .stabs "signed char:t10=r1;-128;127;",128,0,0,0 +16 .stabs "unsigned char:t11=r1;0;255;",128,0,0,0 +17 .stabs "float:t12=r1;4;0;",128,0,0,0 +18 .stabs "double:t13=r1;8;0;",128,0,0,0 +19 .stabs "long double:t14=r1;8;0;",128,0,0,0 +20 .stabs "void:t15=15",128,0,0,0 +21 .align 4 +22 LC0: +23 .ascii "Hello, world!\12\0" +24 .align 4 +25 .global _main +26 .proc 1 +27 _main: +28 .stabn 68,0,4,LM1 +29 LM1: +30 !#PROLOGUE# 0 +31 save %sp,-136,%sp +32 !#PROLOGUE# 1 +33 call ___main,0 +34 nop +35 .stabn 68,0,5,LM2 +36 LM2: +37 LBB2: +38 sethi %hi(LC0),%o1 +39 or %o1,%lo(LC0),%o0 +40 call _printf,0 +41 nop +42 .stabn 68,0,6,LM3 +43 LM3: +44 LBE2: +45 .stabn 68,0,6,LM4 +46 LM4: +47 L1: +48 ret +49 restore +50 .stabs "main:F1",36,0,0,_main +51 .stabn 192,0,0,LBB2 +52 .stabn 224,0,0,LBE2 +@end example + +@node Program Structure +@chapter Encoding the Structure of the Program + +The elements of the program structure that stabs encode include the name +of the main function, the names of the source and include files, the +line numbers, procedure names and types, and the beginnings and ends of +blocks of code. + +@menu +* Main Program:: Indicate what the main program is +* Source Files:: The path and name of the source file +* Include Files:: Names of include files +* Line Numbers:: +* Procedures:: +* Nested Procedures:: +* Block Structure:: +* Alternate Entry Points:: Entering procedures except at the beginning. +@end menu + +@node Main Program +@section Main Program + +@findex N_MAIN +Most languages allow the main program to have any name. The +@code{N_MAIN} stab type tells the debugger the name that is used in this +program. Only the string field is significant; it is the name of +a function which is the main program. Most C compilers do not use this +stab (they expect the debugger to assume that the name is @code{main}), +but some C compilers emit an @code{N_MAIN} stab for the @code{main} +function. I'm not sure how XCOFF handles this. + +@node Source Files +@section Paths and Names of the Source Files + +@findex N_SO +Before any other stabs occur, there must be a stab specifying the source +file. This information is contained in a symbol of stab type +@code{N_SO}; the string field contains the name of the file. The +value of the symbol is the start address of the portion of the +text section corresponding to that file. + +With the Sun Solaris2 compiler, the desc field contains a +source-language code. +@c Do the debuggers use it? What are the codes? -djm + +Some compilers (for example, GCC2 and SunOS4 @file{/bin/cc}) also +include the directory in which the source was compiled, in a second +@code{N_SO} symbol preceding the one containing the file name. This +symbol can be distinguished by the fact that it ends in a slash. Code +from the @code{cfront} C++ compiler can have additional @code{N_SO} symbols for +nonexistent source files after the @code{N_SO} for the real source file; +these are believed to contain no useful information. + +For example: + +@example +.stabs "/cygint/s1/users/jcm/play/",100,0,0,Ltext0 # @r{100 is N_SO} +.stabs "hello.c",100,0,0,Ltext0 + .text +Ltext0: +@end example + +@findex C_FILE +Instead of @code{N_SO} symbols, XCOFF uses a @code{.file} assembler +directive which assembles to a @code{C_FILE} symbol; explaining this in +detail is outside the scope of this document. + +@c FIXME: Exactly when should the empty N_SO be used? Why? +If it is useful to indicate the end of a source file, this is done with +an @code{N_SO} symbol with an empty string for the name. The value is +the address of the end of the text section for the file. For some +systems, there is no indication of the end of a source file, and you +just need to figure it ended when you see an @code{N_SO} for a different +source file, or a symbol ending in @code{.o} (which at least some +linkers insert to mark the start of a new @code{.o} file). + +@node Include Files +@section Names of Include Files + +There are several schemes for dealing with include files: the +traditional @code{N_SOL} approach, Sun's @code{N_BINCL} approach, and the +XCOFF @code{C_BINCL} approach (which despite the similar name has little in +common with @code{N_BINCL}). + +@findex N_SOL +An @code{N_SOL} symbol specifies which include file subsequent symbols +refer to. The string field is the name of the file and the value is the +text address corresponding to the end of the previous include file and +the start of this one. To specify the main source file again, use an +@code{N_SOL} symbol with the name of the main source file. + +@findex N_BINCL +@findex N_EINCL +@findex N_EXCL +The @code{N_BINCL} approach works as follows. An @code{N_BINCL} symbol +specifies the start of an include file. In an object file, only the +string is significant; the Sun linker puts data into some of the other +fields. The end of the include file is marked by an @code{N_EINCL} +symbol (which has no string field). In an object file, there is no +significant data in the @code{N_EINCL} symbol. @code{N_BINCL} and +@code{N_EINCL} can be nested. + +If the linker detects that two source files have identical stabs between +an @code{N_BINCL} and @code{N_EINCL} pair (as will generally be the case +for a header file), then it only puts out the stabs once. Each +additional occurance is replaced by an @code{N_EXCL} symbol. I believe +the Sun (SunOS4, not sure about Solaris) linker is the only one which +supports this feature. + +The SunOS4 linker sets the value of a @code{N_BINCL} symbol to the total +of all the characters in the stabs strings included in the header file, +omitting the file number. The value of an @code{N_EXCL} symbol is the +same as the value of the @code{N_BINCL} symbol it replaces. I do not +know if this information is used by anything. The @code{N_EINCL} value, +and the values of the other and description fields for all three, appear +to always be zero. + +@findex C_BINCL +@findex C_EINCL +For the start of an include file in XCOFF, use the @file{.bi} assembler +directive, which generates a @code{C_BINCL} symbol. A @file{.ei} +directive, which generates a @code{C_EINCL} symbol, denotes the end of +the include file. Both directives are followed by the name of the +source file in quotes, which becomes the string for the symbol. +The value of each symbol, produced automatically by the assembler +and linker, is the offset into the executable of the beginning +(inclusive, as you'd expect) or end (inclusive, as you would not expect) +of the portion of the COFF line table that corresponds to this include +file. @code{C_BINCL} and @code{C_EINCL} do not nest. + +@node Line Numbers +@section Line Numbers + +@findex N_SLINE +An @code{N_SLINE} symbol represents the start of a source line. The +desc field contains the line number and the value contains the code +address for the start of that source line. On most machines the address +is absolute; for stabs in sections (@pxref{Stab Sections}), it is +relative to the function in which the @code{N_SLINE} symbol occurs. + +@findex N_DSLINE +@findex N_BSLINE +GNU documents @code{N_DSLINE} and @code{N_BSLINE} symbols for line +numbers in the data or bss segments, respectively. They are identical +to @code{N_SLINE} but are relocated differently by the linker. They +were intended to be used to describe the source location of a variable +declaration, but I believe that GCC2 actually puts the line number in +the desc field of the stab for the variable itself. GDB has been +ignoring these symbols (unless they contain a string field) since +at least GDB 3.5. + +For single source lines that generate discontiguous code, such as flow +of control statements, there may be more than one line number entry for +the same source line. In this case there is a line number entry at the +start of each code range, each with the same line number. + +XCOFF does not use stabs for line numbers. Instead, it uses COFF line +numbers (which are outside the scope of this document). Standard COFF +line numbers cannot deal with include files, but in XCOFF this is fixed +with the @code{C_BINCL} method of marking include files (@pxref{Include +Files}). + +@node Procedures +@section Procedures + +@findex N_FUN, for functions +@findex N_FNAME +@findex N_STSYM, for functions (Sun acc) +@findex N_GSYM, for functions (Sun acc) +All of the following stabs normally use the @code{N_FUN} symbol type. +However, Sun's @code{acc} compiler on SunOS4 uses @code{N_GSYM} and +@code{N_STSYM}, which means that the value of the stab for the function +is useless and the debugger must get the address of the function from +the non-stab symbols instead. On systems where non-stab symbols have +leading underscores, the stabs will lack underscores and the debugger +needs to know about the leading underscore to match up the stab and the +non-stab symbol. BSD Fortran is said to use @code{N_FNAME} with the +same restriction; the value of the symbol is not useful (I'm not sure it +really does use this, because GDB doesn't handle this and no one has +complained). + +@findex C_FUN +A function is represented by an @samp{F} symbol descriptor for a global +(extern) function, and @samp{f} for a static (local) function. For +a.out, the value of the symbol is the address of the start of the +function; it is already relocated. For stabs in ELF, the SunPRO +compiler version 2.0.1 and GCC put out an address which gets relocated +by the linker. In a future release SunPRO is planning to put out zero, +in which case the address can be found from the ELF (non-stab) symbol. +Because looking things up in the ELF symbols would probably be slow, I'm +not sure how to find which symbol of that name is the right one, and +this doesn't provide any way to deal with nested functions, it would +probably be better to make the value of the stab an address relative to +the start of the file, or just absolute. See @ref{ELF Linker +Relocation} for more information on linker relocation of stabs in ELF +files. For XCOFF, the stab uses the @code{C_FUN} storage class and the +value of the stab is meaningless; the address of the function can be +found from the csect symbol (XTY_LD/XMC_PR). + +The type information of the stab represents the return type of the +function; thus @samp{foo:f5} means that foo is a function returning type +5. There is no need to try to get the line number of the start of the +function from the stab for the function; it is in the next +@code{N_SLINE} symbol. + +@c FIXME: verify whether the "I suspect" below is true or not. +Some compilers (such as Sun's Solaris compiler) support an extension for +specifying the types of the arguments. I suspect this extension is not +used for old (non-prototyped) function definitions in C. If the +extension is in use, the type information of the stab for the function +is followed by type information for each argument, with each argument +preceded by @samp{;}. An argument type of 0 means that additional +arguments are being passed, whose types and number may vary (@samp{...} +in ANSI C). GDB has tolerated this extension (parsed the syntax, if not +necessarily used the information) since at least version 4.8; I don't +know whether all versions of dbx tolerate it. The argument types given +here are not redundant with the symbols for the formal parameters +(@pxref{Parameters}); they are the types of the arguments as they are +passed, before any conversions might take place. For example, if a C +function which is declared without a prototype takes a @code{float} +argument, the value is passed as a @code{double} but then converted to a +@code{float}. Debuggers need to use the types given in the arguments +when printing values, but when calling the function they need to use the +types given in the symbol defining the function. + +If the return type and types of arguments of a function which is defined +in another source file are specified (i.e., a function prototype in ANSI +C), traditionally compilers emit no stab; the only way for the debugger +to find the information is if the source file where the function is +defined was also compiled with debugging symbols. As an extension the +Solaris compiler uses symbol descriptor @samp{P} followed by the return +type of the function, followed by the arguments, each preceded by +@samp{;}, as in a stab with symbol descriptor @samp{f} or @samp{F}. +This use of symbol descriptor @samp{P} can be distinguished from its use +for register parameters (@pxref{Register Parameters}) by the fact that it has +symbol type @code{N_FUN}. + +The AIX documentation also defines symbol descriptor @samp{J} as an +internal function. I assume this means a function nested within another +function. It also says symbol descriptor @samp{m} is a module in +Modula-2 or extended Pascal. + +Procedures (functions which do not return values) are represented as +functions returning the @code{void} type in C. I don't see why this couldn't +be used for all languages (inventing a @code{void} type for this purpose if +necessary), but the AIX documentation defines @samp{I}, @samp{P}, and +@samp{Q} for internal, global, and static procedures, respectively. +These symbol descriptors are unusual in that they are not followed by +type information. + +The following example shows a stab for a function @code{main} which +returns type number @code{1}. The @code{_main} specified for the value +is a reference to an assembler label which is used to fill in the start +address of the function. + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +@end example + +The stab representing a procedure is located immediately following the +code of the procedure. This stab is in turn directly followed by a +group of other stabs describing elements of the procedure. These other +stabs describe the procedure's parameters, its block local variables, and +its block structure. + +@node Nested Procedures +@section Nested Procedures + +For any of the symbol descriptors representing procedures, after the +symbol descriptor and the type information is optionally a scope +specifier. This consists of a comma, the name of the procedure, another +comma, and the name of the enclosing procedure. The first name is local +to the scope specified, and seems to be redundant with the name of the +symbol (before the @samp{:}). This feature is used by GCC, and +presumably Pascal, Modula-2, etc., compilers, for nested functions. + +If procedures are nested more than one level deep, only the immediately +containing scope is specified. For example, this code: + +@example +int +foo (int x) +@{ + int bar (int y) + @{ + int baz (int z) + @{ + return x + y + z; + @} + return baz (x + 2 * y); + @} + return x + bar (3 * x); +@} +@end example + +@noindent +produces the stabs: + +@example +.stabs "baz:f1,baz,bar",36,0,0,_baz.15 # @r{36 is N_FUN} +.stabs "bar:f1,bar,foo",36,0,0,_bar.12 +.stabs "foo:F1",36,0,0,_foo +@end example + +@node Block Structure +@section Block Structure + +@findex N_LBRAC +@findex N_RBRAC +@c For GCC 2.5.8 or so stabs-in-coff, these are absolute instead of +@c function relative (as documented below). But GDB has never been able +@c to deal with that (it had wanted them to be relative to the file, but +@c I just fixed that (between GDB 4.12 and 4.13)), so it is function +@c relative just like ELF and SOM and the below documentation. +The program's block structure is represented by the @code{N_LBRAC} (left +brace) and the @code{N_RBRAC} (right brace) stab types. The variables +defined inside a block precede the @code{N_LBRAC} symbol for most +compilers, including GCC. Other compilers, such as the Convex, Acorn +RISC machine, and Sun @code{acc} compilers, put the variables after the +@code{N_LBRAC} symbol. The values of the @code{N_LBRAC} and +@code{N_RBRAC} symbols are the start and end addresses of the code of +the block, respectively. For most machines, they are relative to the +starting address of this source file. For the Gould NP1, they are +absolute. For stabs in sections (@pxref{Stab Sections}), they are +relative to the function in which they occur. + +The @code{N_LBRAC} and @code{N_RBRAC} stabs that describe the block +scope of a procedure are located after the @code{N_FUN} stab that +represents the procedure itself. + +Sun documents the desc field of @code{N_LBRAC} and +@code{N_RBRAC} symbols as containing the nesting level of the block. +However, dbx seems to not care, and GCC always sets desc to +zero. + +@findex .bb +@findex .be +@findex C_BLOCK +For XCOFF, block scope is indicated with @code{C_BLOCK} symbols. If the +name of the symbol is @samp{.bb}, then it is the beginning of the block; +if the name of the symbol is @samp{.be}; it is the end of the block. + +@node Alternate Entry Points +@section Alternate Entry Points + +@findex N_ENTRY +@findex C_ENTRY +Some languages, like Fortran, have the ability to enter procedures at +some place other than the beginning. One can declare an alternate entry +point. The @code{N_ENTRY} stab is for this; however, the Sun FORTRAN +compiler doesn't use it. According to AIX documentation, only the name +of a @code{C_ENTRY} stab is significant; the address of the alternate +entry point comes from the corresponding external symbol. A previous +revision of this document said that the value of an @code{N_ENTRY} stab +was the address of the alternate entry point, but I don't know the +source for that information. + +@node Constants +@chapter Constants + +The @samp{c} symbol descriptor indicates that this stab represents a +constant. This symbol descriptor is an exception to the general rule +that symbol descriptors are followed by type information. Instead, it +is followed by @samp{=} and one of the following: + +@table @code +@item b @var{value} +Boolean constant. @var{value} is a numeric value; I assume it is 0 for +false or 1 for true. + +@item c @var{value} +Character constant. @var{value} is the numeric value of the constant. + +@item e @var{type-information} , @var{value} +Constant whose value can be represented as integral. +@var{type-information} is the type of the constant, as it would appear +after a symbol descriptor (@pxref{String Field}). @var{value} is the +numeric value of the constant. GDB 4.9 does not actually get the right +value if @var{value} does not fit in a host @code{int}, but it does not +do anything violent, and future debuggers could be extended to accept +integers of any size (whether unsigned or not). This constant type is +usually documented as being only for enumeration constants, but GDB has +never imposed that restriction; I don't know about other debuggers. + +@item i @var{value} +Integer constant. @var{value} is the numeric value. The type is some +sort of generic integer type (for GDB, a host @code{int}); to specify +the type explicitly, use @samp{e} instead. + +@item r @var{value} +Real constant. @var{value} is the real value, which can be @samp{INF} +(optionally preceded by a sign) for infinity, @samp{QNAN} for a quiet +NaN (not-a-number), or @samp{SNAN} for a signalling NaN. If it is a +normal number the format is that accepted by the C library function +@code{atof}. + +@item s @var{string} +String constant. @var{string} is a string enclosed in either @samp{'} +(in which case @samp{'} characters within the string are represented as +@samp{\'} or @samp{"} (in which case @samp{"} characters within the +string are represented as @samp{\"}). + +@item S @var{type-information} , @var{elements} , @var{bits} , @var{pattern} +Set constant. @var{type-information} is the type of the constant, as it +would appear after a symbol descriptor (@pxref{String Field}). +@var{elements} is the number of elements in the set (does this means +how many bits of @var{pattern} are actually used, which would be +redundant with the type, or perhaps the number of bits set in +@var{pattern}? I don't get it), @var{bits} is the number of bits in the +constant (meaning it specifies the length of @var{pattern}, I think), +and @var{pattern} is a hexadecimal representation of the set. AIX +documentation refers to a limit of 32 bytes, but I see no reason why +this limit should exist. This form could probably be used for arbitrary +constants, not just sets; the only catch is that @var{pattern} should be +understood to be target, not host, byte order and format. +@end table + +The boolean, character, string, and set constants are not supported by +GDB 4.9, but it ignores them. GDB 4.8 and earlier gave an error +message and refused to read symbols from the file containing the +constants. + +The above information is followed by @samp{;}. + +@node Variables +@chapter Variables + +Different types of stabs describe the various ways that variables can be +allocated: on the stack, globally, in registers, in common blocks, +statically, or as arguments to a function. + +@menu +* Stack Variables:: Variables allocated on the stack. +* Global Variables:: Variables used by more than one source file. +* Register Variables:: Variables in registers. +* Common Blocks:: Variables statically allocated together. +* Statics:: Variables local to one source file. +* Based Variables:: Fortran pointer based variables. +* Parameters:: Variables for arguments to functions. +@end menu + +@node Stack Variables +@section Automatic Variables Allocated on the Stack + +If a variable's scope is local to a function and its lifetime is only as +long as that function executes (C calls such variables +@dfn{automatic}), it can be allocated in a register (@pxref{Register +Variables}) or on the stack. + +@findex N_LSYM, for stack variables +@findex C_LSYM +Each variable allocated on the stack has a stab with the symbol +descriptor omitted. Since type information should begin with a digit, +@samp{-}, or @samp{(}, only those characters precluded from being used +for symbol descriptors. However, the Acorn RISC machine (ARM) is said +to get this wrong: it puts out a mere type definition here, without the +preceding @samp{@var{type-number}=}. This is a bad idea; there is no +guarantee that type descriptors are distinct from symbol descriptors. +Stabs for stack variables use the @code{N_LSYM} stab type, or +@code{C_LSYM} for XCOFF. + +The value of the stab is the offset of the variable within the +local variables. On most machines this is an offset from the frame +pointer and is negative. The location of the stab specifies which block +it is defined in; see @ref{Block Structure}. + +For example, the following C code: + +@example +int +main () +@{ + int x; +@} +@end example + +produces the following stabs: + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +.stabs "x:1",128,0,0,-12 # @r{128 is N_LSYM} +.stabn 192,0,0,LBB2 # @r{192 is N_LBRAC} +.stabn 224,0,0,LBE2 # @r{224 is N_RBRAC} +@end example + +@xref{Procedures} for more information on the @code{N_FUN} stab, and +@ref{Block Structure} for more information on the @code{N_LBRAC} and +@code{N_RBRAC} stabs. + +@node Global Variables +@section Global Variables + +@findex N_GSYM +@findex C_GSYM +@c FIXME: verify for sure that it really is C_GSYM on XCOFF +A variable whose scope is not specific to just one source file is +represented by the @samp{G} symbol descriptor. These stabs use the +@code{N_GSYM} stab type (C_GSYM for XCOFF). The type information for +the stab (@pxref{String Field}) gives the type of the variable. + +For example, the following source code: + +@example +char g_foo = 'c'; +@end example + +@noindent +yields the following assembly code: + +@example +.stabs "g_foo:G2",32,0,0,0 # @r{32 is N_GSYM} + .global _g_foo + .data +_g_foo: + .byte 99 +@end example + +The address of the variable represented by the @code{N_GSYM} is not +contained in the @code{N_GSYM} stab. The debugger gets this information +from the external symbol for the global variable. In the example above, +the @code{.global _g_foo} and @code{_g_foo:} lines tell the assembler to +produce an external symbol. + +Some compilers, like GCC, output @code{N_GSYM} stabs only once, where +the variable is defined. Other compilers, like SunOS4 /bin/cc, output a +@code{N_GSYM} stab for each compilation unit which references the +variable. + +@node Register Variables +@section Register Variables + +@findex N_RSYM +@findex C_RSYM +@c According to an old version of this manual, AIX uses C_RPSYM instead +@c of C_RSYM. I am skeptical; this should be verified. +Register variables have their own stab type, @code{N_RSYM} +(@code{C_RSYM} for XCOFF), and their own symbol descriptor, @samp{r}. +The stab's value is the number of the register where the variable data +will be stored. +@c .stabs "name:type",N_RSYM,0,RegSize,RegNumber (Sun doc) + +AIX defines a separate symbol descriptor @samp{d} for floating point +registers. This seems unnecessary; why not just just give floating +point registers different register numbers? I have not verified whether +the compiler actually uses @samp{d}. + +If the register is explicitly allocated to a global variable, but not +initialized, as in: + +@example +register int g_bar asm ("%g5"); +@end example + +@noindent +then the stab may be emitted at the end of the object file, with +the other bss symbols. + +@node Common Blocks +@section Common Blocks + +A common block is a statically allocated section of memory which can be +referred to by several source files. It may contain several variables. +I believe Fortran is the only language with this feature. + +@findex N_BCOMM +@findex N_ECOMM +@findex C_BCOMM +@findex C_ECOMM +A @code{N_BCOMM} stab begins a common block and an @code{N_ECOMM} stab +ends it. The only field that is significant in these two stabs is the +string, which names a normal (non-debugging) symbol that gives the +address of the common block. According to IBM documentation, only the +@code{N_BCOMM} has the name of the common block (even though their +compiler actually puts it both places). + +@findex N_ECOML +@findex C_ECOML +The stabs for the members of the common block are between the +@code{N_BCOMM} and the @code{N_ECOMM}; the value of each stab is the +offset within the common block of that variable. IBM uses the +@code{C_ECOML} stab type, and there is a corresponding @code{N_ECOML} +stab type, but Sun's Fortran compiler uses @code{N_GSYM} instead. The +variables within a common block use the @samp{V} symbol descriptor (I +believe this is true of all Fortran variables). Other stabs (at least +type declarations using @code{C_DECL}) can also be between the +@code{N_BCOMM} and the @code{N_ECOMM}. + +@node Statics +@section Static Variables + +Initialized static variables are represented by the @samp{S} and +@samp{V} symbol descriptors. @samp{S} means file scope static, and +@samp{V} means procedure scope static. One exception: in XCOFF, IBM's +xlc compiler always uses @samp{V}, and whether it is file scope or not +is distinguished by whether the stab is located within a function. + +@c This is probably not worth mentioning; it is only true on the sparc +@c for `double' variables which although declared const are actually in +@c the data segment (the text segment can't guarantee 8 byte alignment). +@c (although GCC +@c 2.4.5 has a bug in that it uses @code{N_FUN}, so neither dbx nor GDB can +@c find the variables) +@findex N_STSYM +@findex N_LCSYM +@findex N_FUN, for variables +@findex N_ROSYM +In a.out files, @code{N_STSYM} means the data section, @code{N_FUN} +means the text section, and @code{N_LCSYM} means the bss section. For +those systems with a read-only data section separate from the text +section (Solaris), @code{N_ROSYM} means the read-only data section. + +For example, the source lines: + +@example +static const int var_const = 5; +static int var_init = 2; +static int var_noinit; +@end example + +@noindent +yield the following stabs: + +@example +.stabs "var_const:S1",36,0,0,_var_const # @r{36 is N_FUN} +@dots{} +.stabs "var_init:S1",38,0,0,_var_init # @r{38 is N_STSYM} +@dots{} +.stabs "var_noinit:S1",40,0,0,_var_noinit # @r{40 is N_LCSYM} +@end example + +@findex C_STSYM +@findex C_BSTAT +@findex C_ESTAT +In XCOFF files, the stab type need not indicate the section; +@code{C_STSYM} can be used for all statics. Also, each static variable +is enclosed in a static block. A @code{C_BSTAT} (emitted with a +@samp{.bs} assembler directive) symbol begins the static block; its +value is the symbol number of the csect symbol whose value is the +address of the static block, its section is the section of the variables +in that static block, and its name is @samp{.bs}. A @code{C_ESTAT} +(emitted with a @samp{.es} assembler directive) symbol ends the static +block; its name is @samp{.es} and its value and section are ignored. + +In ECOFF files, the storage class is used to specify the section, so the +stab type need not indicate the section. + +In ELF files, for the SunPRO compiler version 2.0.1, symbol descriptor +@samp{S} means that the address is absolute (the linker relocates it) +and symbol descriptor @samp{V} means that the address is relative to the +start of the relevant section for that compilation unit. SunPRO has +plans to have the linker stop relocating stabs; I suspect that their the +debugger gets the address from the corresponding ELF (not stab) symbol. +I'm not sure how to find which symbol of that name is the right one. +The clean way to do all this would be to have a the value of a symbol +descriptor @samp{S} symbol be an offset relative to the start of the +file, just like everything else, but that introduces obvious +compatibility problems. For more information on linker stab relocation, +@xref{ELF Linker Relocation}. + +@node Based Variables +@section Fortran Based Variables + +Fortran (at least, the Sun and SGI dialects of FORTRAN-77) has a feature +which allows allocating arrays with @code{malloc}, but which avoids +blurring the line between arrays and pointers the way that C does. In +stabs such a variable uses the @samp{b} symbol descriptor. + +For example, the Fortran declarations + +@example +real foo, foo10(10), foo10_5(10,5) +pointer (foop, foo) +pointer (foo10p, foo10) +pointer (foo105p, foo10_5) +@end example + +produce the stabs + +@example +foo:b6 +foo10:bar3;1;10;6 +foo10_5:bar3;1;5;ar3;1;10;6 +@end example + +In this example, @code{real} is type 6 and type 3 is an integral type +which is the type of the subscripts of the array (probably +@code{integer}). + +The @samp{b} symbol descriptor is like @samp{V} in that it denotes a +statically allocated symbol whose scope is local to a function; see +@xref{Statics}. The value of the symbol, instead of being the address +of the variable itself, is the address of a pointer to that variable. +So in the above example, the value of the @code{foo} stab is the address +of a pointer to a real, the value of the @code{foo10} stab is the +address of a pointer to a 10-element array of reals, and the value of +the @code{foo10_5} stab is the address of a pointer to a 5-element array +of 10-element arrays of reals. + +@node Parameters +@section Parameters + +Formal parameters to a function are represented by a stab (or sometimes +two; see below) for each parameter. The stabs are in the order in which +the debugger should print the parameters (i.e., the order in which the +parameters are declared in the source file). The exact form of the stab +depends on how the parameter is being passed. + +@findex N_PSYM +@findex C_PSYM +Parameters passed on the stack use the symbol descriptor @samp{p} and +the @code{N_PSYM} symbol type (or @code{C_PSYM} for XCOFF). The value +of the symbol is an offset used to locate the parameter on the stack; +its exact meaning is machine-dependent, but on most machines it is an +offset from the frame pointer. + +As a simple example, the code: + +@example +main (argc, argv) + int argc; + char **argv; +@end example + +produces the stabs: + +@example +.stabs "main:F1",36,0,0,_main # @r{36 is N_FUN} +.stabs "argc:p1",160,0,0,68 # @r{160 is N_PSYM} +.stabs "argv:p20=*21=*2",160,0,0,72 +@end example + +The type definition of @code{argv} is interesting because it contains +several type definitions. Type 21 is pointer to type 2 (char) and +@code{argv} (type 20) is pointer to type 21. + +@c FIXME: figure out what these mean and describe them coherently. +The following symbol descriptors are also said to go with @code{N_PSYM}. +The value of the symbol is said to be an offset from the argument +pointer (I'm not sure whether this is true or not). + +@example +pP (<>) +pF Fortran function parameter +X (function result variable) +@end example + +@menu +* Register Parameters:: +* Local Variable Parameters:: +* Reference Parameters:: +* Conformant Arrays:: +@end menu + +@node Register Parameters +@subsection Passing Parameters in Registers + +If the parameter is passed in a register, then traditionally there are +two symbols for each argument: + +@example +.stabs "arg:p1" . . . ; N_PSYM +.stabs "arg:r1" . . . ; N_RSYM +@end example + +Debuggers use the second one to find the value, and the first one to +know that it is an argument. + +@findex C_RPSYM +@findex N_RSYM, for parameters +Because that approach is kind of ugly, some compilers use symbol +descriptor @samp{P} or @samp{R} to indicate an argument which is in a +register. Symbol type @code{C_RPSYM} is used in XCOFF and @code{N_RSYM} +is used otherwise. The symbol's value is the register number. @samp{P} +and @samp{R} mean the same thing; the difference is that @samp{P} is a +GNU invention and @samp{R} is an IBM (XCOFF) invention. As of version +4.9, GDB should handle either one. + +There is at least one case where GCC uses a @samp{p} and @samp{r} pair +rather than @samp{P}; this is where the argument is passed in the +argument list and then loaded into a register. + +According to the AIX documentation, symbol descriptor @samp{D} is for a +parameter passed in a floating point register. This seems +unnecessary---why not just use @samp{R} with a register number which +indicates that it's a floating point register? I haven't verified +whether the system actually does what the documentation indicates. + +@c FIXME: On the hppa this is for any type > 8 bytes, I think, and not +@c for small structures (investigate). +On the sparc and hppa, for a @samp{P} symbol whose type is a structure +or union, the register contains the address of the structure. On the +sparc, this is also true of a @samp{p} and @samp{r} pair (using Sun +@code{cc}) or a @samp{p} symbol. However, if a (small) structure is +really in a register, @samp{r} is used. And, to top it all off, on the +hppa it might be a structure which was passed on the stack and loaded +into a register and for which there is a @samp{p} and @samp{r} pair! I +believe that symbol descriptor @samp{i} is supposed to deal with this +case (it is said to mean "value parameter by reference, indirect +access"; I don't know the source for this information), but I don't know +details or what compilers or debuggers use it, if any (not GDB or GCC). +It is not clear to me whether this case needs to be dealt with +differently than parameters passed by reference (@pxref{Reference Parameters}). + +@node Local Variable Parameters +@subsection Storing Parameters as Local Variables + +There is a case similar to an argument in a register, which is an +argument that is actually stored as a local variable. Sometimes this +happens when the argument was passed in a register and then the compiler +stores it as a local variable. If possible, the compiler should claim +that it's in a register, but this isn't always done. + +If a parameter is passed as one type and converted to a smaller type by +the prologue (for example, the parameter is declared as a @code{float}, +but the calling conventions specify that it is passed as a +@code{double}), then GCC2 (sometimes) uses a pair of symbols. The first +symbol uses symbol descriptor @samp{p} and the type which is passed. +The second symbol has the type and location which the parameter actually +has after the prologue. For example, suppose the following C code +appears with no prototypes involved: + +@example +void +subr (f) + float f; +@{ +@end example + +if @code{f} is passed as a double at stack offset 8, and the prologue +converts it to a float in register number 0, then the stabs look like: + +@example +.stabs "f:p13",160,0,3,8 # @r{160 is @code{N_PSYM}, here 13 is @code{double}} +.stabs "f:r12",64,0,3,0 # @r{64 is @code{N_RSYM}, here 12 is @code{float}} +@end example + +In both stabs 3 is the line number where @code{f} is declared +(@pxref{Line Numbers}). + +@findex N_LSYM, for parameter +GCC, at least on the 960, has another solution to the same problem. It +uses a single @samp{p} symbol descriptor for an argument which is stored +as a local variable but uses @code{N_LSYM} instead of @code{N_PSYM}. In +this case, the value of the symbol is an offset relative to the local +variables for that function, not relative to the arguments; on some +machines those are the same thing, but not on all. + +@c This is mostly just background info; the part that logically belongs +@c here is the last sentence. +On the VAX or on other machines in which the calling convention includes +the number of words of arguments actually passed, the debugger (GDB at +least) uses the parameter symbols to keep track of whether it needs to +print nameless arguments in addition to the formal parameters which it +has printed because each one has a stab. For example, in + +@example +extern int fprintf (FILE *stream, char *format, @dots{}); +@dots{} +fprintf (stdout, "%d\n", x); +@end example + +there are stabs for @code{stream} and @code{format}. On most machines, +the debugger can only print those two arguments (because it has no way +of knowing that additional arguments were passed), but on the VAX or +other machines with a calling convention which indicates the number of +words of arguments, the debugger can print all three arguments. To do +so, the parameter symbol (symbol descriptor @samp{p}) (not necessarily +@samp{r} or symbol descriptor omitted symbols) needs to contain the +actual type as passed (for example, @code{double} not @code{float} if it +is passed as a double and converted to a float). + +@node Reference Parameters +@subsection Passing Parameters by Reference + +If the parameter is passed by reference (e.g., Pascal @code{VAR} +parameters), then the symbol descriptor is @samp{v} if it is in the +argument list, or @samp{a} if it in a register. Other than the fact +that these contain the address of the parameter rather than the +parameter itself, they are identical to @samp{p} and @samp{R}, +respectively. I believe @samp{a} is an AIX invention; @samp{v} is +supported by all stabs-using systems as far as I know. + +@node Conformant Arrays +@subsection Passing Conformant Array Parameters + +@c Is this paragraph correct? It is based on piecing together patchy +@c information and some guesswork +Conformant arrays are a feature of Modula-2, and perhaps other +languages, in which the size of an array parameter is not known to the +called function until run-time. Such parameters have two stabs: a +@samp{x} for the array itself, and a @samp{C}, which represents the size +of the array. The value of the @samp{x} stab is the offset in the +argument list where the address of the array is stored (it this right? +it is a guess); the value of the @samp{C} stab is the offset in the +argument list where the size of the array (in elements? in bytes?) is +stored. + +@node Types +@chapter Defining Types + +The examples so far have described types as references to previously +defined types, or defined in terms of subranges of or pointers to +previously defined types. This chapter describes the other type +descriptors that may follow the @samp{=} in a type definition. + +@menu +* Builtin Types:: Integers, floating point, void, etc. +* Miscellaneous Types:: Pointers, sets, files, etc. +* Cross-References:: Referring to a type not yet defined. +* Subranges:: A type with a specific range. +* Arrays:: An aggregate type of same-typed elements. +* Strings:: Like an array but also has a length. +* Enumerations:: Like an integer but the values have names. +* Structures:: An aggregate type of different-typed elements. +* Typedefs:: Giving a type a name. +* Unions:: Different types sharing storage. +* Function Types:: +@end menu + +@node Builtin Types +@section Builtin Types + +Certain types are built in (@code{int}, @code{short}, @code{void}, +@code{float}, etc.); the debugger recognizes these types and knows how +to handle them. Thus, don't be surprised if some of the following ways +of specifying builtin types do not specify everything that a debugger +would need to know about the type---in some cases they merely specify +enough information to distinguish the type from other types. + +The traditional way to define builtin types is convolunted, so new ways +have been invented to describe them. Sun's @code{acc} uses special +builtin type descriptors (@samp{b} and @samp{R}), and IBM uses negative +type numbers. GDB accepts all three ways, as of version 4.8; dbx just +accepts the traditional builtin types and perhaps one of the other two +formats. The following sections describe each of these formats. + +@menu +* Traditional Builtin Types:: Put on your seatbelts and prepare for kludgery +* Builtin Type Descriptors:: Builtin types with special type descriptors +* Negative Type Numbers:: Builtin types using negative type numbers +@end menu + +@node Traditional Builtin Types +@subsection Traditional Builtin Types + +This is the traditional, convoluted method for defining builtin types. +There are several classes of such type definitions: integer, floating +point, and @code{void}. + +@menu +* Traditional Integer Types:: +* Traditional Other Types:: +@end menu + +@node Traditional Integer Types +@subsubsection Traditional Integer Types + +Often types are defined as subranges of themselves. If the bounding values +fit within an @code{int}, then they are given normally. For example: + +@example +.stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 # @r{128 is N_LSYM} +.stabs "char:t2=r2;0;127;",128,0,0,0 +@end example + +Builtin types can also be described as subranges of @code{int}: + +@example +.stabs "unsigned short:t6=r1;0;65535;",128,0,0,0 +@end example + +If the lower bound of a subrange is 0 and the upper bound is -1, +the type is an unsigned integral type whose bounds are too +big to describe in an @code{int}. Traditionally this is only used for +@code{unsigned int} and @code{unsigned long}: + +@example +.stabs "unsigned int:t4=r1;0;-1;",128,0,0,0 +@end example + +For larger types, GCC 2.4.5 puts out bounds in octal, with one or more +leading zeroes. In this case a negative bound consists of a number +which is a 1 bit (for the sign bit) followed by a 0 bit for each bit in +the number (except the sign bit), and a positive bound is one which is a +1 bit for each bit in the number (except possibly the sign bit). All +known versions of dbx and GDB version 4 accept this (at least in the +sense of not refusing to process the file), but GDB 3.5 refuses to read +the whole file containing such symbols. So GCC 2.3.3 did not output the +proper size for these types. As an example of octal bounds, the string +fields of the stabs for 64 bit integer types look like: + +@c .stabs directives, etc., omitted to make it fit on the page. +@example +long int:t3=r1;001000000000000000000000;000777777777777777777777; +long unsigned int:t5=r1;000000000000000000000000;001777777777777777777777; +@end example + +If the lower bound of a subrange is 0 and the upper bound is negative, +the type is an unsigned integral type whose size in bytes is the +absolute value of the upper bound. I believe this is a Convex +convention for @code{unsigned long long}. + +If the lower bound of a subrange is negative and the upper bound is 0, +the type is a signed integral type whose size in bytes is +the absolute value of the lower bound. I believe this is a Convex +convention for @code{long long}. To distinguish this from a legitimate +subrange, the type should be a subrange of itself. I'm not sure whether +this is the case for Convex. + +@node Traditional Other Types +@subsubsection Traditional Other Types + +If the upper bound of a subrange is 0 and the lower bound is positive, +the type is a floating point type, and the lower bound of the subrange +indicates the number of bytes in the type: + +@example +.stabs "float:t12=r1;4;0;",128,0,0,0 +.stabs "double:t13=r1;8;0;",128,0,0,0 +@end example + +However, GCC writes @code{long double} the same way it writes +@code{double}, so there is no way to distinguish. + +@example +.stabs "long double:t14=r1;8;0;",128,0,0,0 +@end example + +Complex types are defined the same way as floating-point types; there is +no way to distinguish a single-precision complex from a double-precision +floating-point type. + +The C @code{void} type is defined as itself: + +@example +.stabs "void:t15=15",128,0,0,0 +@end example + +I'm not sure how a boolean type is represented. + +@node Builtin Type Descriptors +@subsection Defining Builtin Types Using Builtin Type Descriptors + +This is the method used by Sun's @code{acc} for defining builtin types. +These are the type descriptors to define builtin types: + +@table @code +@c FIXME: clean up description of width and offset, once we figure out +@c what they mean +@item b @var{signed} @var{char-flag} @var{width} ; @var{offset} ; @var{nbits} ; +Define an integral type. @var{signed} is @samp{u} for unsigned or +@samp{s} for signed. @var{char-flag} is @samp{c} which indicates this +is a character type, or is omitted. I assume this is to distinguish an +integral type from a character type of the same size, for example it +might make sense to set it for the C type @code{wchar_t} so the debugger +can print such variables differently (Solaris does not do this). Sun +sets it on the C types @code{signed char} and @code{unsigned char} which +arguably is wrong. @var{width} and @var{offset} appear to be for small +objects stored in larger ones, for example a @code{short} in an +@code{int} register. @var{width} is normally the number of bytes in the +type. @var{offset} seems to always be zero. @var{nbits} is the number +of bits in the type. + +Note that type descriptor @samp{b} used for builtin types conflicts with +its use for Pascal space types (@pxref{Miscellaneous Types}); they can +be distinguished because the character following the type descriptor +will be a digit, @samp{(}, or @samp{-} for a Pascal space type, or +@samp{u} or @samp{s} for a builtin type. + +@item w +Documented by AIX to define a wide character type, but their compiler +actually uses negative type numbers (@pxref{Negative Type Numbers}). + +@item R @var{fp-type} ; @var{bytes} ; +Define a floating point type. @var{fp-type} has one of the following values: + +@table @code +@item 1 (NF_SINGLE) +IEEE 32-bit (single precision) floating point format. + +@item 2 (NF_DOUBLE) +IEEE 64-bit (double precision) floating point format. + +@item 3 (NF_COMPLEX) +@item 4 (NF_COMPLEX16) +@item 5 (NF_COMPLEX32) +@c "GDB source" really means @file{include/aout/stab_gnu.h}, but trying +@c to put that here got an overfull hbox. +These are for complex numbers. A comment in the GDB source describes +them as Fortran @code{complex}, @code{double complex}, and +@code{complex*16}, respectively, but what does that mean? (i.e., Single +precision? Double precison?). + +@item 6 (NF_LDOUBLE) +Long double. This should probably only be used for Sun format +@code{long double}, and new codes should be used for other floating +point formats (@code{NF_DOUBLE} can be used if a @code{long double} is +really just an IEEE double, of course). +@end table + +@var{bytes} is the number of bytes occupied by the type. This allows a +debugger to perform some operations with the type even if it doesn't +understand @var{fp-type}. + +@item g @var{type-information} ; @var{nbits} +Documented by AIX to define a floating type, but their compiler actually +uses negative type numbers (@pxref{Negative Type Numbers}). + +@item c @var{type-information} ; @var{nbits} +Documented by AIX to define a complex type, but their compiler actually +uses negative type numbers (@pxref{Negative Type Numbers}). +@end table + +The C @code{void} type is defined as a signed integral type 0 bits long: +@example +.stabs "void:t19=bs0;0;0",128,0,0,0 +@end example +The Solaris compiler seems to omit the trailing semicolon in this case. +Getting sloppy in this way is not a swift move because if a type is +embedded in a more complex expression it is necessary to be able to tell +where it ends. + +I'm not sure how a boolean type is represented. + +@node Negative Type Numbers +@subsection Negative Type Numbers + +This is the method used in XCOFF for defining builtin types. +Since the debugger knows about the builtin types anyway, the idea of +negative type numbers is simply to give a special type number which +indicates the builtin type. There is no stab defining these types. + +There are several subtle issues with negative type numbers. + +One is the size of the type. A builtin type (for example the C types +@code{int} or @code{long}) might have different sizes depending on +compiler options, the target architecture, the ABI, etc. This issue +doesn't come up for IBM tools since (so far) they just target the +RS/6000; the sizes indicated below for each size are what the IBM +RS/6000 tools use. To deal with differing sizes, either define separate +negative type numbers for each size (which works but requires changing +the debugger, and, unless you get both AIX dbx and GDB to accept the +change, introduces an incompatibility), or use a type attribute +(@pxref{String Field}) to define a new type with the appropriate size +(which merely requires a debugger which understands type attributes, +like AIX dbx or GDB). For example, + +@example +.stabs "boolean:t10=@@s8;-16",128,0,0,0 +@end example + +defines an 8-bit boolean type, and + +@example +.stabs "boolean:t10=@@s64;-16",128,0,0,0 +@end example + +defines a 64-bit boolean type. + +A similar issue is the format of the type. This comes up most often for +floating-point types, which could have various formats (particularly +extended doubles, which vary quite a bit even among IEEE systems). +Again, it is best to define a new negative type number for each +different format; changing the format based on the target system has +various problems. One such problem is that the Alpha has both VAX and +IEEE floating types. One can easily imagine one library using the VAX +types and another library in the same executable using the IEEE types. +Another example is that the interpretation of whether a boolean is true +or false can be based on the least significant bit, most significant +bit, whether it is zero, etc., and different compilers (or different +options to the same compiler) might provide different kinds of boolean. + +The last major issue is the names of the types. The name of a given +type depends @emph{only} on the negative type number given; these do not +vary depending on the language, the target system, or anything else. +One can always define separate type numbers---in the following list you +will see for example separate @code{int} and @code{integer*4} types +which are identical except for the name. But compatibility can be +maintained by not inventing new negative type numbers and instead just +defining a new type with a new name. For example: + +@example +.stabs "CARDINAL:t10=-8",128,0,0,0 +@end example + +Here is the list of negative type numbers. The phrase @dfn{integral +type} is used to mean twos-complement (I strongly suspect that all +machines which use stabs use twos-complement; most machines use +twos-complement these days). + +@table @code +@item -1 +@code{int}, 32 bit signed integral type. + +@item -2 +@code{char}, 8 bit type holding a character. Both GDB and dbx on AIX +treat this as signed. GCC uses this type whether @code{char} is signed +or not, which seems like a bad idea. The AIX compiler (@code{xlc}) seems to +avoid this type; it uses -5 instead for @code{char}. + +@item -3 +@code{short}, 16 bit signed integral type. + +@item -4 +@code{long}, 32 bit signed integral type. + +@item -5 +@code{unsigned char}, 8 bit unsigned integral type. + +@item -6 +@code{signed char}, 8 bit signed integral type. + +@item -7 +@code{unsigned short}, 16 bit unsigned integral type. + +@item -8 +@code{unsigned int}, 32 bit unsigned integral type. + +@item -9 +@code{unsigned}, 32 bit unsigned integral type. + +@item -10 +@code{unsigned long}, 32 bit unsigned integral type. + +@item -11 +@code{void}, type indicating the lack of a value. + +@item -12 +@code{float}, IEEE single precision. + +@item -13 +@code{double}, IEEE double precision. + +@item -14 +@code{long double}, IEEE double precision. The compiler claims the size +will increase in a future release, and for binary compatibility you have +to avoid using @code{long double}. I hope when they increase it they +use a new negative type number. + +@item -15 +@code{integer}. 32 bit signed integral type. + +@item -16 +@code{boolean}. 32 bit type. GDB and GCC assume that zero is false, +one is true, and other values have unspecified meaning. I hope this +agrees with how the IBM tools use the type. + +@item -17 +@code{short real}. IEEE single precision. + +@item -18 +@code{real}. IEEE double precision. + +@item -19 +@code{stringptr}. @xref{Strings}. + +@item -20 +@code{character}, 8 bit unsigned character type. + +@item -21 +@code{logical*1}, 8 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -22 +@code{logical*2}, 16 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -23 +@code{logical*4}, 32 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -24 +@code{logical}, 32 bit type. This Fortran type has a split +personality in that it is used for boolean variables, but can also be +used for unsigned integers. 0 is false, 1 is true, and other values are +non-boolean. + +@item -25 +@code{complex}. A complex type consisting of two IEEE single-precision +floating point values. + +@item -26 +@code{complex}. A complex type consisting of two IEEE double-precision +floating point values. + +@item -27 +@code{integer*1}, 8 bit signed integral type. + +@item -28 +@code{integer*2}, 16 bit signed integral type. + +@item -29 +@code{integer*4}, 32 bit signed integral type. + +@item -30 +@code{wchar}. Wide character, 16 bits wide, unsigned (what format? +Unicode?). + +@item -31 +@code{long long}, 64 bit signed integral type. + +@item -32 +@code{unsigned long long}, 64 bit unsigned integral type. + +@item -33 +@code{logical*8}, 64 bit unsigned integral type. + +@item -34 +@code{integer*8}, 64 bit signed integral type. +@end table + +@node Miscellaneous Types +@section Miscellaneous Types + +@table @code +@item b @var{type-information} ; @var{bytes} +Pascal space type. This is documented by IBM; what does it mean? + +This use of the @samp{b} type descriptor can be distinguished +from its use for builtin integral types (@pxref{Builtin Type +Descriptors}) because the character following the type descriptor is +always a digit, @samp{(}, or @samp{-}. + +@item B @var{type-information} +A volatile-qualified version of @var{type-information}. This is +a Sun extension. References and stores to a variable with a +volatile-qualified type must not be optimized or cached; they +must occur as the user specifies them. + +@item d @var{type-information} +File of type @var{type-information}. As far as I know this is only used +by Pascal. + +@item k @var{type-information} +A const-qualified version of @var{type-information}. This is a Sun +extension. A variable with a const-qualified type cannot be modified. + +@item M @var{type-information} ; @var{length} +Multiple instance type. The type seems to composed of @var{length} +repetitions of @var{type-information}, for example @code{character*3} is +represented by @samp{M-2;3}, where @samp{-2} is a reference to a +character type (@pxref{Negative Type Numbers}). I'm not sure how this +differs from an array. This appears to be a Fortran feature. +@var{length} is a bound, like those in range types; see @ref{Subranges}. + +@item S @var{type-information} +Pascal set type. @var{type-information} must be a small type such as an +enumeration or a subrange, and the type is a bitmask whose length is +specified by the number of elements in @var{type-information}. + +In CHILL, if it is a bitstring instead of a set, also use the @samp{S} +type attribute (@pxref{String Field}). + +@item * @var{type-information} +Pointer to @var{type-information}. +@end table + +@node Cross-References +@section Cross-References to Other Types + +A type can be used before it is defined; one common way to deal with +that situation is just to use a type reference to a type which has not +yet been defined. + +Another way is with the @samp{x} type descriptor, which is followed by +@samp{s} for a structure tag, @samp{u} for a union tag, or @samp{e} for +a enumerator tag, followed by the name of the tag, followed by @samp{:}. +If the name contains @samp{::} between a @samp{<} and @samp{>} pair (for +C++ templates), such a @samp{::} does not end the name---only a single +@samp{:} ends the name; see @ref{Nested Symbols}. + +For example, the following C declarations: + +@example +struct foo; +struct foo *bar; +@end example + +@noindent +produce: + +@example +.stabs "bar:G16=*17=xsfoo:",32,0,0,0 +@end example + +Not all debuggers support the @samp{x} type descriptor, so on some +machines GCC does not use it. I believe that for the above example it +would just emit a reference to type 17 and never define it, but I +haven't verified that. + +Modula-2 imported types, at least on AIX, use the @samp{i} type +descriptor, which is followed by the name of the module from which the +type is imported, followed by @samp{:}, followed by the name of the +type. There is then optionally a comma followed by type information for +the type. This differs from merely naming the type (@pxref{Typedefs}) in +that it identifies the module; I don't understand whether the name of +the type given here is always just the same as the name we are giving +it, or whether this type descriptor is used with a nameless stab +(@pxref{String Field}), or what. The symbol ends with @samp{;}. + +@node Subranges +@section Subrange Types + +The @samp{r} type descriptor defines a type as a subrange of another +type. It is followed by type information for the type of which it is a +subrange, a semicolon, an integral lower bound, a semicolon, an +integral upper bound, and a semicolon. The AIX documentation does not +specify the trailing semicolon, in an effort to specify array indexes +more cleanly, but a subrange which is not an array index has always +included a trailing semicolon (@pxref{Arrays}). + +Instead of an integer, either bound can be one of the following: + +@table @code +@item A @var{offset} +The bound is passed by reference on the stack at offset @var{offset} +from the argument list. @xref{Parameters}, for more information on such +offsets. + +@item T @var{offset} +The bound is passed by value on the stack at offset @var{offset} from +the argument list. + +@item a @var{register-number} +The bound is pased by reference in register number +@var{register-number}. + +@item t @var{register-number} +The bound is passed by value in register number @var{register-number}. + +@item J +There is no bound. +@end table + +Subranges are also used for builtin types; see @ref{Traditional Builtin Types}. + +@node Arrays +@section Array Types + +Arrays use the @samp{a} type descriptor. Following the type descriptor +is the type of the index and the type of the array elements. If the +index type is a range type, it ends in a semicolon; otherwise +(for example, if it is a type reference), there does not +appear to be any way to tell where the types are separated. In an +effort to clean up this mess, IBM documents the two types as being +separated by a semicolon, and a range type as not ending in a semicolon +(but this is not right for range types which are not array indexes, +@pxref{Subranges}). I think probably the best solution is to specify +that a semicolon ends a range type, and that the index type and element +type of an array are separated by a semicolon, but that if the index +type is a range type, the extra semicolon can be omitted. GDB (at least +through version 4.9) doesn't support any kind of index type other than a +range anyway; I'm not sure about dbx. + +It is well established, and widely used, that the type of the index, +unlike most types found in the stabs, is merely a type definition, not +type information (@pxref{String Field}) (that is, it need not start with +@samp{@var{type-number}=} if it is defining a new type). According to a +comment in GDB, this is also true of the type of the array elements; it +gives @samp{ar1;1;10;ar1;1;10;4} as a legitimate way to express a two +dimensional array. According to AIX documentation, the element type +must be type information. GDB accepts either. + +The type of the index is often a range type, expressed as the type +descriptor @samp{r} and some parameters. It defines the size of the +array. In the example below, the range @samp{r1;0;2;} defines an index +type which is a subrange of type 1 (integer), with a lower bound of 0 +and an upper bound of 2. This defines the valid range of subscripts of +a three-element C array. + +For example, the definition: + +@example +char char_vec[3] = @{'a','b','c'@}; +@end example + +@noindent +produces the output: + +@example +.stabs "char_vec:G19=ar1;0;2;2",32,0,0,0 + .global _char_vec + .align 4 +_char_vec: + .byte 97 + .byte 98 + .byte 99 +@end example + +If an array is @dfn{packed}, the elements are spaced more +closely than normal, saving memory at the expense of speed. For +example, an array of 3-byte objects might, if unpacked, have each +element aligned on a 4-byte boundary, but if packed, have no padding. +One way to specify that something is packed is with type attributes +(@pxref{String Field}). In the case of arrays, another is to use the +@samp{P} type descriptor instead of @samp{a}. Other than specifying a +packed array, @samp{P} is identical to @samp{a}. + +@c FIXME-what is it? A pointer? +An open array is represented by the @samp{A} type descriptor followed by +type information specifying the type of the array elements. + +@c FIXME: what is the format of this type? A pointer to a vector of pointers? +An N-dimensional dynamic array is represented by + +@example +D @var{dimensions} ; @var{type-information} +@end example + +@c Does dimensions really have this meaning? The AIX documentation +@c doesn't say. +@var{dimensions} is the number of dimensions; @var{type-information} +specifies the type of the array elements. + +@c FIXME: what is the format of this type? A pointer to some offsets in +@c another array? +A subarray of an N-dimensional array is represented by + +@example +E @var{dimensions} ; @var{type-information} +@end example + +@c Does dimensions really have this meaning? The AIX documentation +@c doesn't say. +@var{dimensions} is the number of dimensions; @var{type-information} +specifies the type of the array elements. + +@node Strings +@section Strings + +Some languages, like C or the original Pascal, do not have string types, +they just have related things like arrays of characters. But most +Pascals and various other languages have string types, which are +indicated as follows: + +@table @code +@item n @var{type-information} ; @var{bytes} +@var{bytes} is the maximum length. I'm not sure what +@var{type-information} is; I suspect that it means that this is a string +of @var{type-information} (thus allowing a string of integers, a string +of wide characters, etc., as well as a string of characters). Not sure +what the format of this type is. This is an AIX feature. + +@item z @var{type-information} ; @var{bytes} +Just like @samp{n} except that this is a gstring, not an ordinary +string. I don't know the difference. + +@item N +Pascal Stringptr. What is this? This is an AIX feature. +@end table + +Languages, such as CHILL which have a string type which is basically +just an array of characters use the @samp{S} type attribute +(@pxref{String Field}). + +@node Enumerations +@section Enumerations + +Enumerations are defined with the @samp{e} type descriptor. + +@c FIXME: Where does this information properly go? Perhaps it is +@c redundant with something we already explain. +The source line below declares an enumeration type at file scope. +The type definition is located after the @code{N_RBRAC} that marks the end of +the previous procedure's block scope, and before the @code{N_FUN} that marks +the beginning of the next procedure's block scope. Therefore it does not +describe a block local symbol, but a file local one. + +The source line: + +@example +enum e_places @{first,second=3,last@}; +@end example + +@noindent +generates the following stab: + +@example +.stabs "e_places:T22=efirst:0,second:3,last:4,;",128,0,0,0 +@end example + +The symbol descriptor (@samp{T}) says that the stab describes a +structure, enumeration, or union tag. The type descriptor @samp{e}, +following the @samp{22=} of the type definition narrows it down to an +enumeration type. Following the @samp{e} is a list of the elements of +the enumeration. The format is @samp{@var{name}:@var{value},}. The +list of elements ends with @samp{;}. The fact that @var{value} is +specified as an integer can cause problems if the value is large. GCC +2.5.2 tries to output it in octal in that case with a leading zero, +which is probably a good thing, although GDB 4.11 supports octal only in +cases where decimal is perfectly good. Negative decimal values are +supported by both GDB and dbx. + +There is no standard way to specify the size of an enumeration type; it +is determined by the architecture (normally all enumerations types are +32 bits). Type attributes can be used to specify an enumeration type of +another size for debuggers which support them; see @ref{String Field}. + +Enumeration types are unusual in that they define symbols for the +enumeration values (@code{first}, @code{second}, and @code{third} in the +above example), and even though these symbols are visible in the file as +a whole (rather than being in a more local namespace like structure +member names), they are defined in the type definition for the +enumeration type rather than each having their own symbol. In order to +be fast, GDB will only get symbols from such types (in its initial scan +of the stabs) if the type is the first thing defined after a @samp{T} or +@samp{t} symbol descriptor (the above example fulfills this +requirement). If the type does not have a name, the compiler should +emit it in a nameless stab (@pxref{String Field}); GCC does this. + +@node Structures +@section Structures + +The encoding of structures in stabs can be shown with an example. + +The following source code declares a structure tag and defines an +instance of the structure in global scope. Then a @code{typedef} equates the +structure tag with a new type. Seperate stabs are generated for the +structure tag, the structure @code{typedef}, and the structure instance. The +stabs for the tag and the @code{typedef} are emited when the definitions are +encountered. Since the structure elements are not initialized, the +stab and code for the structure variable itself is located at the end +of the program in the bss section. + +@example +struct s_tag @{ + int s_int; + float s_float; + char s_char_vec[8]; + struct s_tag* s_next; +@} g_an_s; + +typedef struct s_tag s_typedef; +@end example + +The structure tag has an @code{N_LSYM} stab type because, like the +enumeration, the symbol has file scope. Like the enumeration, the +symbol descriptor is @samp{T}, for enumeration, structure, or tag type. +The type descriptor @samp{s} following the @samp{16=} of the type +definition narrows the symbol type to structure. + +Following the @samp{s} type descriptor is the number of bytes the +structure occupies, followed by a description of each structure element. +The structure element descriptions are of the form @var{name:type, bit +offset from the start of the struct, number of bits in the element}. + +@c FIXME: phony line break. Can probably be fixed by using an example +@c with fewer fields. +@example +# @r{128 is N_LSYM} +.stabs "s_tag:T16=s20s_int:1,0,32;s_float:12,32,32; + s_char_vec:17=ar1;0;7;2,64,64;s_next:18=*16,128,32;;",128,0,0,0 +@end example + +In this example, the first two structure elements are previously defined +types. For these, the type following the @samp{@var{name}:} part of the +element description is a simple type reference. The other two structure +elements are new types. In this case there is a type definition +embedded after the @samp{@var{name}:}. The type definition for the +array element looks just like a type definition for a standalone array. +The @code{s_next} field is a pointer to the same kind of structure that +the field is an element of. So the definition of structure type 16 +contains a type definition for an element which is a pointer to type 16. + +If a field is a static member (this is a C++ feature in which a single +variable appears to be a field of every structure of a given type) it +still starts out with the field name, a colon, and the type, but then +instead of a comma, bit position, comma, and bit size, there is a colon +followed by the name of the variable which each such field refers to. + +If the structure has methods (a C++ feature), they follow the non-method +fields; see @ref{Cplusplus}. + +@node Typedefs +@section Giving a Type a Name + +@findex N_LSYM, for types +@findex C_DECL, for types +To give a type a name, use the @samp{t} symbol descriptor. The type +is specified by the type information (@pxref{String Field}) for the stab. +For example, + +@example +.stabs "s_typedef:t16",128,0,0,0 # @r{128 is N_LSYM} +@end example + +specifies that @code{s_typedef} refers to type number 16. Such stabs +have symbol type @code{N_LSYM} (or @code{C_DECL} for XCOFF). + +If you are specifying the tag name for a structure, union, or +enumeration, use the @samp{T} symbol descriptor instead. I believe C is +the only language with this feature. + +If the type is an opaque type (I believe this is a Modula-2 feature), +AIX provides a type descriptor to specify it. The type descriptor is +@samp{o} and is followed by a name. I don't know what the name +means---is it always the same as the name of the type, or is this type +descriptor used with a nameless stab (@pxref{String Field})? There +optionally follows a comma followed by type information which defines +the type of this type. If omitted, a semicolon is used in place of the +comma and the type information, and the type is much like a generic +pointer type---it has a known size but little else about it is +specified. + +@node Unions +@section Unions + +@example +union u_tag @{ + int u_int; + float u_float; + char* u_char; +@} an_u; +@end example + +This code generates a stab for a union tag and a stab for a union +variable. Both use the @code{N_LSYM} stab type. If a union variable is +scoped locally to the procedure in which it is defined, its stab is +located immediately preceding the @code{N_LBRAC} for the procedure's block +start. + +The stab for the union tag, however, is located preceding the code for +the procedure in which it is defined. The stab type is @code{N_LSYM}. This +would seem to imply that the union type is file scope, like the struct +type @code{s_tag}. This is not true. The contents and position of the stab +for @code{u_type} do not convey any infomation about its procedure local +scope. + +@c FIXME: phony line break. Can probably be fixed by using an example +@c with fewer fields. +@smallexample +# @r{128 is N_LSYM} +.stabs "u_tag:T23=u4u_int:1,0,32;u_float:12,0,32;u_char:21,0,32;;", + 128,0,0,0 +@end smallexample + +The symbol descriptor @samp{T}, following the @samp{name:} means that +the stab describes an enumeration, structure, or union tag. The type +descriptor @samp{u}, following the @samp{23=} of the type definition, +narrows it down to a union type definition. Following the @samp{u} is +the number of bytes in the union. After that is a list of union element +descriptions. Their format is @var{name:type, bit offset into the +union, number of bytes for the element;}. + +The stab for the union variable is: + +@example +.stabs "an_u:23",128,0,0,-20 # @r{128 is N_LSYM} +@end example + +@samp{-20} specifies where the variable is stored (@pxref{Stack +Variables}). + +@node Function Types +@section Function Types + +Various types can be defined for function variables. These types are +not used in defining functions (@pxref{Procedures}); they are used for +things like pointers to functions. + +The simple, traditional, type is type descriptor @samp{f} is followed by +type information for the return type of the function, followed by a +semicolon. + +This does not deal with functions for which the number and types of the +parameters are part of the type, as in Modula-2 or ANSI C. AIX provides +extensions to specify these, using the @samp{f}, @samp{F}, @samp{p}, and +@samp{R} type descriptors. + +First comes the type descriptor. If it is @samp{f} or @samp{F}, this +type involves a function rather than a procedure, and the type +information for the return type of the function follows, followed by a +comma. Then comes the number of parameters to the function and a +semicolon. Then, for each parameter, there is the name of the parameter +followed by a colon (this is only present for type descriptors @samp{R} +and @samp{F} which represent Pascal function or procedure parameters), +type information for the parameter, a comma, 0 if passed by reference or +1 if passed by value, and a semicolon. The type definition ends with a +semicolon. + +For example, this variable definition: + +@example +int (*g_pf)(); +@end example + +@noindent +generates the following code: + +@example +.stabs "g_pf:G24=*25=f1",32,0,0,0 + .common _g_pf,4,"bss" +@end example + +The variable defines a new type, 24, which is a pointer to another new +type, 25, which is a function returning @code{int}. + +@node Symbol Tables +@chapter Symbol Information in Symbol Tables + +This chapter describes the format of symbol table entries +and how stab assembler directives map to them. It also describes the +transformations that the assembler and linker make on data from stabs. + +@menu +* Symbol Table Format:: +* Transformations On Symbol Tables:: +@end menu + +@node Symbol Table Format +@section Symbol Table Format + +Each time the assembler encounters a stab directive, it puts +each field of the stab into a corresponding field in a symbol table +entry of its output file. If the stab contains a string field, the +symbol table entry for that stab points to a string table entry +containing the string data from the stab. Assembler labels become +relocatable addresses. Symbol table entries in a.out have the format: + +@c FIXME: should refer to external, not internal. +@example +struct internal_nlist @{ + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +@}; +@end example + +If the stab has a string, the @code{n_strx} field holds the offset in +bytes of the string within the string table. The string is terminated +by a NUL character. If the stab lacks a string (for example, it was +produced by a @code{.stabn} or @code{.stabd} directive), the +@code{n_strx} field is zero. + +Symbol table entries with @code{n_type} field values greater than 0x1f +originated as stabs generated by the compiler (with one random +exception). The other entries were placed in the symbol table of the +executable by the assembler or the linker. + +@node Transformations On Symbol Tables +@section Transformations on Symbol Tables + +The linker concatenates object files and does fixups of externally +defined symbols. + +You can see the transformations made on stab data by the assembler and +linker by examining the symbol table after each pass of the build. To +do this, use @samp{nm -ap}, which dumps the symbol table, including +debugging information, unsorted. For stab entries the columns are: +@var{value}, @var{other}, @var{desc}, @var{type}, @var{string}. For +assembler and linker symbols, the columns are: @var{value}, @var{type}, +@var{string}. + +The low 5 bits of the stab type tell the linker how to relocate the +value of the stab. Thus for stab types like @code{N_RSYM} and +@code{N_LSYM}, where the value is an offset or a register number, the +low 5 bits are @code{N_ABS}, which tells the linker not to relocate the +value. + +Where the value of a stab contains an assembly language label, +it is transformed by each build step. The assembler turns it into a +relocatable address and the linker turns it into an absolute address. + +@menu +* Transformations On Static Variables:: +* Transformations On Global Variables:: +* Stab Section Transformations:: For some object file formats, + things are a bit different. +@end menu + +@node Transformations On Static Variables +@subsection Transformations on Static Variables + +This source line defines a static variable at file scope: + +@example +static int s_g_repeat +@end example + +@noindent +The following stab describes the symbol: + +@example +.stabs "s_g_repeat:S1",38,0,0,_s_g_repeat +@end example + +@noindent +The assembler transforms the stab into this symbol table entry in the +@file{.o} file. The location is expressed as a data segment offset. + +@example +00000084 - 00 0000 STSYM s_g_repeat:S1 +@end example + +@noindent +In the symbol table entry from the executable, the linker has made the +relocatable address absolute. + +@example +0000e00c - 00 0000 STSYM s_g_repeat:S1 +@end example + +@node Transformations On Global Variables +@subsection Transformations on Global Variables + +Stabs for global variables do not contain location information. In +this case, the debugger finds location information in the assembler or +linker symbol table entry describing the variable. The source line: + +@example +char g_foo = 'c'; +@end example + +@noindent +generates the stab: + +@example +.stabs "g_foo:G2",32,0,0,0 +@end example + +The variable is represented by two symbol table entries in the object +file (see below). The first one originated as a stab. The second one +is an external symbol. The upper case @samp{D} signifies that the +@code{n_type} field of the symbol table contains 7, @code{N_DATA} with +local linkage. The stab's value is zero since the value is not used for +@code{N_GSYM} stabs. The value of the linker symbol is the relocatable +address corresponding to the variable. + +@example +00000000 - 00 0000 GSYM g_foo:G2 +00000080 D _g_foo +@end example + +@noindent +These entries as transformed by the linker. The linker symbol table +entry now holds an absolute address: + +@example +00000000 - 00 0000 GSYM g_foo:G2 +@dots{} +0000e008 D _g_foo +@end example + +@node Stab Section Transformations +@subsection Transformations of Stabs in separate sections + +For object file formats using stabs in separate sections (@pxref{Stab +Sections}), use @code{objdump --stabs} instead of @code{nm} to show the +stabs in an object or executable file. @code{objdump} is a GNU utility; +Sun does not provide any equivalent. + +The following example is for a stab whose value is an address is +relative to the compilation unit (@pxref{ELF Linker Relocation}). For +example, if the source line + +@example +static int ld = 5; +@end example + +appears within a function, then the assembly language output from the +compiler contains: + +@example +.Ddata.data: +@dots{} + .stabs "ld:V(0,3)",0x26,0,4,.L18-Ddata.data # @r{0x26 is N_STSYM} +@dots{} +.L18: + .align 4 + .word 0x5 +@end example + +Because the value is formed by subtracting one symbol from another, the +value is absolute, not relocatable, and so the object file contains + +@example +Symnum n_type n_othr n_desc n_value n_strx String +31 STSYM 0 4 00000004 680 ld:V(0,3) +@end example + +without any relocations, and the executable file also contains + +@example +Symnum n_type n_othr n_desc n_value n_strx String +31 STSYM 0 4 00000004 680 ld:V(0,3) +@end example + +@node Cplusplus +@chapter GNU C++ Stabs + +@menu +* Class Names:: C++ class names are both tags and typedefs. +* Nested Symbols:: C++ symbol names can be within other types. +* Basic Cplusplus Types:: +* Simple Classes:: +* Class Instance:: +* Methods:: Method definition +* Method Type Descriptor:: The @samp{#} type descriptor +* Member Type Descriptor:: The @samp{@@} type descriptor +* Protections:: +* Method Modifiers:: +* Virtual Methods:: +* Inheritence:: +* Virtual Base Classes:: +* Static Members:: +@end menu + +@node Class Names +@section C++ Class Names + +In C++, a class name which is declared with @code{class}, @code{struct}, +or @code{union}, is not only a tag, as in C, but also a type name. Thus +there should be stabs with both @samp{t} and @samp{T} symbol descriptors +(@pxref{Typedefs}). + +To save space, there is a special abbreviation for this case. If the +@samp{T} symbol descriptor is followed by @samp{t}, then the stab +defines both a type name and a tag. + +For example, the C++ code + +@example +struct foo @{int x;@}; +@end example + +can be represented as either + +@example +.stabs "foo:T19=s4x:1,0,32;;",128,0,0,0 # @r{128 is N_LSYM} +.stabs "foo:t19",128,0,0,0 +@end example + +or + +@example +.stabs "foo:Tt19=s4x:1,0,32;;",128,0,0,0 +@end example + +@node Nested Symbols +@section Defining a Symbol Within Another Type + +In C++, a symbol (such as a type name) can be defined within another type. +@c FIXME: Needs example. + +In stabs, this is sometimes represented by making the name of a symbol +which contains @samp{::}. Such a pair of colons does not end the name +of the symbol, the way a single colon would (@pxref{String Field}). I'm +not sure how consistently used or well thought out this mechanism is. +So that a pair of colons in this position always has this meaning, +@samp{:} cannot be used as a symbol descriptor. + +For example, if the string for a stab is @samp{foo::bar::baz:t5=*6}, +then @code{foo::bar::baz} is the name of the symbol, @samp{t} is the +symbol descriptor, and @samp{5=*6} is the type information. + +@node Basic Cplusplus Types +@section Basic Types For C++ + +<< the examples that follow are based on a01.C >> + + +C++ adds two more builtin types to the set defined for C. These are +the unknown type and the vtable record type. The unknown type, type +16, is defined in terms of itself like the void type. + +The vtable record type, type 17, is defined as a structure type and +then as a structure tag. The structure has four fields: delta, index, +pfn, and delta2. pfn is the function pointer. + +<< In boilerplate $vtbl_ptr_type, what are the fields delta, +index, and delta2 used for? >> + +This basic type is present in all C++ programs even if there are no +virtual methods defined. + +@display +.stabs "struct_name:sym_desc(type)type_def(17)=type_desc(struct)struct_bytes(8) + elem_name(delta):type_ref(short int),bit_offset(0),field_bits(16); + elem_name(index):type_ref(short int),bit_offset(16),field_bits(16); + elem_name(pfn):type_def(18)=type_desc(ptr to)type_ref(void), + bit_offset(32),field_bits(32); + elem_name(delta2):type_def(short int);bit_offset(32),field_bits(16);;" + N_LSYM, NIL, NIL +@end display + +@smallexample +.stabs "$vtbl_ptr_type:t17=s8 + delta:6,0,16;index:6,16,16;pfn:18=*15,32,32;delta2:6,32,16;;" + ,128,0,0,0 +@end smallexample + +@display +.stabs "name:sym_dec(struct tag)type_ref($vtbl_ptr_type)",N_LSYM,NIL,NIL,NIL +@end display + +@example +.stabs "$vtbl_ptr_type:T17",128,0,0,0 +@end example + +@node Simple Classes +@section Simple Class Definition + +The stabs describing C++ language features are an extension of the +stabs describing C. Stabs representing C++ class types elaborate +extensively on the stab format used to describe structure types in C. +Stabs representing class type variables look just like stabs +representing C language variables. + +Consider the following very simple class definition. + +@example +class baseA @{ +public: + int Adat; + int Ameth(int in, char other); +@}; +@end example + +The class @code{baseA} is represented by two stabs. The first stab describes +the class as a structure type. The second stab describes a structure +tag of the class type. Both stabs are of stab type @code{N_LSYM}. Since the +stab is not located between an @code{N_FUN} and an @code{N_LBRAC} stab this indicates +that the class is defined at file scope. If it were, then the @code{N_LSYM} +would signify a local variable. + +A stab describing a C++ class type is similar in format to a stab +describing a C struct, with each class member shown as a field in the +structure. The part of the struct format describing fields is +expanded to include extra information relevent to C++ class members. +In addition, if the class has multiple base classes or virtual +functions the struct format outside of the field parts is also +augmented. + +In this simple example the field part of the C++ class stab +representing member data looks just like the field part of a C struct +stab. The section on protections describes how its format is +sometimes extended for member data. + +The field part of a C++ class stab representing a member function +differs substantially from the field part of a C struct stab. It +still begins with @samp{name:} but then goes on to define a new type number +for the member function, describe its return type, its argument types, +its protection level, any qualifiers applied to the method definition, +and whether the method is virtual or not. If the method is virtual +then the method description goes on to give the vtable index of the +method, and the type number of the first base class defining the +method. + +When the field name is a method name it is followed by two colons rather +than one. This is followed by a new type definition for the method. +This is a number followed by an equal sign and the type of the method. +Normally this will be a type declared using the @samp{#} type +descriptor; see @ref{Method Type Descriptor}; static member functions +are declared using the @samp{f} type descriptor instead; see +@ref{Function Types}. + +The format of an overloaded operator method name differs from that of +other methods. It is @samp{op$::@var{operator-name}.} where +@var{operator-name} is the operator name such as @samp{+} or @samp{+=}. +The name ends with a period, and any characters except the period can +occur in the @var{operator-name} string. + +The next part of the method description represents the arguments to the +method, preceeded by a colon and ending with a semi-colon. The types of +the arguments are expressed in the same way argument types are expressed +in C++ name mangling. In this example an @code{int} and a @code{char} +map to @samp{ic}. + +This is followed by a number, a letter, and an asterisk or period, +followed by another semicolon. The number indicates the protections +that apply to the member function. Here the 2 means public. The +letter encodes any qualifier applied to the method definition. In +this case, @samp{A} means that it is a normal function definition. The dot +shows that the method is not virtual. The sections that follow +elaborate further on these fields and describe the additional +information present for virtual methods. + + +@display +.stabs "class_name:sym_desc(type)type_def(20)=type_desc(struct)struct_bytes(4) + field_name(Adat):type(int),bit_offset(0),field_bits(32); + + method_name(Ameth)::type_def(21)=type_desc(method)return_type(int); + :arg_types(int char); + protection(public)qualifier(normal)virtual(no);;" + N_LSYM,NIL,NIL,NIL +@end display + +@smallexample +.stabs "baseA:t20=s4Adat:1,0,32;Ameth::21=##1;:ic;2A.;;",128,0,0,0 + +.stabs "class_name:sym_desc(struct tag)",N_LSYM,NIL,NIL,NIL + +.stabs "baseA:T20",128,0,0,0 +@end smallexample + +@node Class Instance +@section Class Instance + +As shown above, describing even a simple C++ class definition is +accomplished by massively extending the stab format used in C to +describe structure types. However, once the class is defined, C stabs +with no modifications can be used to describe class instances. The +following source: + +@example +main () @{ + baseA AbaseA; +@} +@end example + +@noindent +yields the following stab describing the class instance. It looks no +different from a standard C stab describing a local variable. + +@display +.stabs "name:type_ref(baseA)", N_LSYM, NIL, NIL, frame_ptr_offset +@end display + +@example +.stabs "AbaseA:20",128,0,0,-20 +@end example + +@node Methods +@section Method Definition + +The class definition shown above declares Ameth. The C++ source below +defines Ameth: + +@example +int +baseA::Ameth(int in, char other) +@{ + return in; +@}; +@end example + + +This method definition yields three stabs following the code of the +method. One stab describes the method itself and following two describe +its parameters. Although there is only one formal argument all methods +have an implicit argument which is the @code{this} pointer. The @code{this} +pointer is a pointer to the object on which the method was called. Note +that the method name is mangled to encode the class name and argument +types. Name mangling is described in the @sc{arm} (@cite{The Annotated +C++ Reference Manual}, by Ellis and Stroustrup, @sc{isbn} +0-201-51459-1); @file{gpcompare.texi} in Cygnus GCC distributions +describes the differences between GNU mangling and @sc{arm} +mangling. +@c FIXME: Use @xref, especially if this is generally installed in the +@c info tree. +@c FIXME: This information should be in a net release, either of GCC or +@c GDB. But gpcompare.texi doesn't seem to be in the FSF GCC. + +@example +.stabs "name:symbol_desriptor(global function)return_type(int)", + N_FUN, NIL, NIL, code_addr_of_method_start + +.stabs "Ameth__5baseAic:F1",36,0,0,_Ameth__5baseAic +@end example + +Here is the stab for the @code{this} pointer implicit argument. The +name of the @code{this} pointer is always @code{this}. Type 19, the +@code{this} pointer is defined as a pointer to type 20, @code{baseA}, +but a stab defining @code{baseA} has not yet been emited. Since the +compiler knows it will be emited shortly, here it just outputs a cross +reference to the undefined symbol, by prefixing the symbol name with +@samp{xs}. + +@example +.stabs "name:sym_desc(register param)type_def(19)= + type_desc(ptr to)type_ref(baseA)= + type_desc(cross-reference to)baseA:",N_RSYM,NIL,NIL,register_number + +.stabs "this:P19=*20=xsbaseA:",64,0,0,8 +@end example + +The stab for the explicit integer argument looks just like a parameter +to a C function. The last field of the stab is the offset from the +argument pointer, which in most systems is the same as the frame +pointer. + +@example +.stabs "name:sym_desc(value parameter)type_ref(int)", + N_PSYM,NIL,NIL,offset_from_arg_ptr + +.stabs "in:p1",160,0,0,72 +@end example + +<< The examples that follow are based on A1.C >> + +@node Method Type Descriptor +@section The @samp{#} Type Descriptor + +This is like the @samp{f} type descriptor for functions (@pxref{Function +Types}), except that a function which uses the @samp{#} type descriptor +takes an extra argument as its first argument, for the @code{this} +pointer. The @samp{#} type descriptor is optionally followed by the +types of the arguments, then another @samp{#}. If the types of the +arguments are omitted, so that the second @samp{#} immediately follows +the @samp{#} which is the type descriptor, the arguments are being +omitted (to save space) and can be deduced from the mangled name of the +method. After the second @samp{#} there is type information for the +return type of the method and a semicolon. + +Note that although such a type will normally be used to describe fields +in structures, unions, or classes, for at least some versions of the +compiler it can also be used in other contexts. + +@node Member Type Descriptor +@section The @samp{@@} Type Descriptor + +The @samp{@@} type descriptor is for a member (class and variable) type. +It is followed by type information for the offset basetype, a comma, and +type information for the type of the field being pointed to. (FIXME: +this is acknowledged to be gibberish. Can anyone say what really goes +here?). + +Note that there is a conflict between this and type attributes +(@pxref{String Field}); both use type descriptor @samp{@@}. +Fortunately, the @samp{@@} type descriptor used in this C++ sense always +will be followed by a digit, @samp{(}, or @samp{-}, and type attributes +never start with those things. + +@node Protections +@section Protections + +In the simple class definition shown above all member data and +functions were publicly accessable. The example that follows +contrasts public, protected and privately accessable fields and shows +how these protections are encoded in C++ stabs. + +If the character following the @samp{@var{field-name}:} part of the +string is @samp{/}, then the next character is the visibility. @samp{0} +means private, @samp{1} means protected, and @samp{2} means public. +Debuggers should ignore visibility characters they do not recognize, and +assume a reasonable default (such as public) (GDB 4.11 does not, but +this should be fixed in the next GDB release). If no visibility is +specified the field is public. The visibility @samp{9} means that the +field has been optimized out and is public (there is no way to specify +an optimized out field with a private or protected visibility). +Visibility @samp{9} is not supported by GDB 4.11; this should be fixed +in the next GDB release. + +The following C++ source: + +@example +class vis @{ +private: + int priv; +protected: + char prot; +public: + float pub; +@}; +@end example + +@noindent +generates the following stab: + +@example +# @r{128 is N_LSYM} +.stabs "vis:T19=s12priv:/01,0,32;prot:/12,32,8;pub:12,64,32;;",128,0,0,0 +@end example + +@samp{vis:T19=s12} indicates that type number 19 is a 12 byte structure +named @code{vis} The @code{priv} field has public visibility +(@samp{/0}), type int (@samp{1}), and offset and size @samp{,0,32;}. +The @code{prot} field has protected visibility (@samp{/1}), type char +(@samp{2}) and offset and size @samp{,32,8;}. The @code{pub} field has +type float (@samp{12}), and offset and size @samp{,64,32;}. + +Protections for member functions are signified by one digit embeded in +the field part of the stab describing the method. The digit is 0 if +private, 1 if protected and 2 if public. Consider the C++ class +definition below: + +@example +class all_methods @{ +private: + int priv_meth(int in)@{return in;@}; +protected: + char protMeth(char in)@{return in;@}; +public: + float pubMeth(float in)@{return in;@}; +@}; +@end example + +It generates the following stab. The digit in question is to the left +of an @samp{A} in each case. Notice also that in this case two symbol +descriptors apply to the class name struct tag and struct type. + +@display +.stabs "class_name:sym_desc(struct tag&type)type_def(21)= + sym_desc(struct)struct_bytes(1) + meth_name::type_def(22)=sym_desc(method)returning(int); + :args(int);protection(private)modifier(normal)virtual(no); + meth_name::type_def(23)=sym_desc(method)returning(char); + :args(char);protection(protected)modifier(normal)virual(no); + meth_name::type_def(24)=sym_desc(method)returning(float); + :args(float);protection(public)modifier(normal)virtual(no);;", + N_LSYM,NIL,NIL,NIL +@end display + +@smallexample +.stabs "all_methods:Tt21=s1priv_meth::22=##1;:i;0A.;protMeth::23=##2;:c;1A.; + pubMeth::24=##12;:f;2A.;;",128,0,0,0 +@end smallexample + +@node Method Modifiers +@section Method Modifiers (@code{const}, @code{volatile}, @code{const volatile}) + +<< based on a6.C >> + +In the class example described above all the methods have the normal +modifier. This method modifier information is located just after the +protection information for the method. This field has four possible +character values. Normal methods use @samp{A}, const methods use +@samp{B}, volatile methods use @samp{C}, and const volatile methods use +@samp{D}. Consider the class definition below: + +@example +class A @{ +public: + int ConstMeth (int arg) const @{ return arg; @}; + char VolatileMeth (char arg) volatile @{ return arg; @}; + float ConstVolMeth (float arg) const volatile @{return arg; @}; +@}; +@end example + +This class is described by the following stab: + +@display +.stabs "class(A):sym_desc(struct)type_def(20)=type_desc(struct)struct_bytes(1) + meth_name(ConstMeth)::type_def(21)sym_desc(method) + returning(int);:arg(int);protection(public)modifier(const)virtual(no); + meth_name(VolatileMeth)::type_def(22)=sym_desc(method) + returning(char);:arg(char);protection(public)modifier(volatile)virt(no) + meth_name(ConstVolMeth)::type_def(23)=sym_desc(method) + returning(float);:arg(float);protection(public)modifer(const volatile) + virtual(no);;", @dots{} +@end display + +@example +.stabs "A:T20=s1ConstMeth::21=##1;:i;2B.;VolatileMeth::22=##2;:c;2C.; + ConstVolMeth::23=##12;:f;2D.;;",128,0,0,0 +@end example + +@node Virtual Methods +@section Virtual Methods + +<< The following examples are based on a4.C >> + +The presence of virtual methods in a class definition adds additional +data to the class description. The extra data is appended to the +description of the virtual method and to the end of the class +description. Consider the class definition below: + +@example +class A @{ +public: + int Adat; + virtual int A_virt (int arg) @{ return arg; @}; +@}; +@end example + +This results in the stab below describing class A. It defines a new +type (20) which is an 8 byte structure. The first field of the class +struct is @samp{Adat}, an integer, starting at structure offset 0 and +occupying 32 bits. + +The second field in the class struct is not explicitly defined by the +C++ class definition but is implied by the fact that the class +contains a virtual method. This field is the vtable pointer. The +name of the vtable pointer field starts with @samp{$vf} and continues with a +type reference to the class it is part of. In this example the type +reference for class A is 20 so the name of its vtable pointer field is +@samp{$vf20}, followed by the usual colon. + +Next there is a type definition for the vtable pointer type (21). +This is in turn defined as a pointer to another new type (22). + +Type 22 is the vtable itself, which is defined as an array, indexed by +a range of integers between 0 and 1, and whose elements are of type +17. Type 17 was the vtable record type defined by the boilerplate C++ +type definitions, as shown earlier. + +The bit offset of the vtable pointer field is 32. The number of bits +in the field are not specified when the field is a vtable pointer. + +Next is the method definition for the virtual member function @code{A_virt}. +Its description starts out using the same format as the non-virtual +member functions described above, except instead of a dot after the +@samp{A} there is an asterisk, indicating that the function is virtual. +Since is is virtual some addition information is appended to the end +of the method description. + +The first number represents the vtable index of the method. This is a +32 bit unsigned number with the high bit set, followed by a +semi-colon. + +The second number is a type reference to the first base class in the +inheritence hierarchy defining the virtual member function. In this +case the class stab describes a base class so the virtual function is +not overriding any other definition of the method. Therefore the +reference is to the type number of the class that the stab is +describing (20). + +This is followed by three semi-colons. One marks the end of the +current sub-section, one marks the end of the method field, and the +third marks the end of the struct definition. + +For classes containing virtual functions the very last section of the +string part of the stab holds a type reference to the first base +class. This is preceeded by @samp{~%} and followed by a final semi-colon. + +@display +.stabs "class_name(A):type_def(20)=sym_desc(struct)struct_bytes(8) + field_name(Adat):type_ref(int),bit_offset(0),field_bits(32); + field_name(A virt func ptr):type_def(21)=type_desc(ptr to)type_def(22)= + sym_desc(array)index_type_ref(range of int from 0 to 1); + elem_type_ref(vtbl elem type), + bit_offset(32); + meth_name(A_virt)::typedef(23)=sym_desc(method)returning(int); + :arg_type(int),protection(public)normal(yes)virtual(yes) + vtable_index(1);class_first_defining(A);;;~%first_base(A);", + N_LSYM,NIL,NIL,NIL +@end display + +@c FIXME: bogus line break. +@example +.stabs "A:t20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32; + A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0 +@end example + +@node Inheritence +@section Inheritence + +Stabs describing C++ derived classes include additional sections that +describe the inheritence hierarchy of the class. A derived class stab +also encodes the number of base classes. For each base class it tells +if the base class is virtual or not, and if the inheritence is private +or public. It also gives the offset into the object of the portion of +the object corresponding to each base class. + +This additional information is embeded in the class stab following the +number of bytes in the struct. First the number of base classes +appears bracketed by an exclamation point and a comma. + +Then for each base type there repeats a series: a virtual character, a +visibilty character, a number, a comma, another number, and a +semi-colon. + +The virtual character is @samp{1} if the base class is virtual and +@samp{0} if not. The visibility character is @samp{2} if the derivation +is public, @samp{1} if it is protected, and @samp{0} if it is private. +Debuggers should ignore virtual or visibility characters they do not +recognize, and assume a reasonable default (such as public and +non-virtual) (GDB 4.11 does not, but this should be fixed in the next +GDB release). + +The number following the virtual and visibility characters is the offset +from the start of the object to the part of the object pertaining to the +base class. + +After the comma, the second number is a type_descriptor for the base +type. Finally a semi-colon ends the series, which repeats for each +base class. + +The source below defines three base classes @code{A}, @code{B}, and +@code{C} and the derived class @code{D}. + + +@example +class A @{ +public: + int Adat; + virtual int A_virt (int arg) @{ return arg; @}; +@}; + +class B @{ +public: + int B_dat; + virtual int B_virt (int arg) @{return arg; @}; +@}; + +class C @{ +public: + int Cdat; + virtual int C_virt (int arg) @{return arg; @}; +@}; + +class D : A, virtual B, public C @{ +public: + int Ddat; + virtual int A_virt (int arg ) @{ return arg+1; @}; + virtual int B_virt (int arg) @{ return arg+2; @}; + virtual int C_virt (int arg) @{ return arg+3; @}; + virtual int D_virt (int arg) @{ return arg; @}; +@}; +@end example + +Class stabs similar to the ones described earlier are generated for +each base class. + +@c FIXME!!! the linebreaks in the following example probably make the +@c examples literally unusable, but I don't know any other way to get +@c them on the page. +@c One solution would be to put some of the type definitions into +@c separate stabs, even if that's not exactly what the compiler actually +@c emits. +@smallexample +.stabs "A:T20=s8Adat:1,0,32;$vf20:21=*22=ar1;0;1;17,32; + A_virt::23=##1;:i;2A*-2147483647;20;;;~%20;",128,0,0,0 + +.stabs "B:Tt25=s8Bdat:1,0,32;$vf25:21,32;B_virt::26=##1; + :i;2A*-2147483647;25;;;~%25;",128,0,0,0 + +.stabs "C:Tt28=s8Cdat:1,0,32;$vf28:21,32;C_virt::29=##1; + :i;2A*-2147483647;28;;;~%28;",128,0,0,0 +@end smallexample + +In the stab describing derived class @code{D} below, the information about +the derivation of this class is encoded as follows. + +@display +.stabs "derived_class_name:symbol_descriptors(struct tag&type)= + type_descriptor(struct)struct_bytes(32)!num_bases(3), + base_virtual(no)inheritence_public(no)base_offset(0), + base_class_type_ref(A); + base_virtual(yes)inheritence_public(no)base_offset(NIL), + base_class_type_ref(B); + base_virtual(no)inheritence_public(yes)base_offset(64), + base_class_type_ref(C); @dots{} +@end display + +@c FIXME! fake linebreaks. +@smallexample +.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat: + 1,160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt: + :32:i;2A*-2147483647;25;;C_virt::32:i;2A*-2147483647; + 28;;D_virt::32:i;2A*-2147483646;31;;;~%20;",128,0,0,0 +@end smallexample + +@node Virtual Base Classes +@section Virtual Base Classes + +A derived class object consists of a concatination in memory of the data +areas defined by each base class, starting with the leftmost and ending +with the rightmost in the list of base classes. The exception to this +rule is for virtual inheritence. In the example above, class @code{D} +inherits virtually from base class @code{B}. This means that an +instance of a @code{D} object will not contain its own @code{B} part but +merely a pointer to a @code{B} part, known as a virtual base pointer. + +In a derived class stab, the base offset part of the derivation +information, described above, shows how the base class parts are +ordered. The base offset for a virtual base class is always given as 0. +Notice that the base offset for @code{B} is given as 0 even though +@code{B} is not the first base class. The first base class @code{A} +starts at offset 0. + +The field information part of the stab for class @code{D} describes the field +which is the pointer to the virtual base class @code{B}. The vbase pointer +name is @samp{$vb} followed by a type reference to the virtual base class. +Since the type id for @code{B} in this example is 25, the vbase pointer name +is @samp{$vb25}. + +@c FIXME!! fake linebreaks below +@smallexample +.stabs "D:Tt31=s32!3,000,20;100,25;0264,28;$vb25:24,128;Ddat:1, + 160,32;A_virt::32=##1;:i;2A*-2147483647;20;;B_virt::32:i; + 2A*-2147483647;25;;C_virt::32:i;2A*-2147483647;28;;D_virt: + :32:i;2A*-2147483646;31;;;~%20;",128,0,0,0 +@end smallexample + +Following the name and a semicolon is a type reference describing the +type of the virtual base class pointer, in this case 24. Type 24 was +defined earlier as the type of the @code{B} class @code{this} pointer. The +@code{this} pointer for a class is a pointer to the class type. + +@example +.stabs "this:P24=*25=xsB:",64,0,0,8 +@end example + +Finally the field offset part of the vbase pointer field description +shows that the vbase pointer is the first field in the @code{D} object, +before any data fields defined by the class. The layout of a @code{D} +class object is a follows, @code{Adat} at 0, the vtable pointer for +@code{A} at 32, @code{Cdat} at 64, the vtable pointer for C at 96, the +virtual base pointer for @code{B} at 128, and @code{Ddat} at 160. + + +@node Static Members +@section Static Members + +The data area for a class is a concatenation of the space used by the +data members of the class. If the class has virtual methods, a vtable +pointer follows the class data. The field offset part of each field +description in the class stab shows this ordering. + +<< How is this reflected in stabs? See Cygnus bug #677 for some info. >> + +@node Stab Types +@appendix Table of Stab Types + +The following are all the possible values for the stab type field, for +a.out files, in numeric order. This does not apply to XCOFF, but +it does apply to stabs in sections (@pxref{Stab Sections}). Stabs in +ECOFF use these values but add 0x8f300 to distinguish them from non-stab +symbols. + +The symbolic names are defined in the file @file{include/aout/stabs.def}. + +@menu +* Non-Stab Symbol Types:: Types from 0 to 0x1f +* Stab Symbol Types:: Types from 0x20 to 0xff +@end menu + +@node Non-Stab Symbol Types +@appendixsec Non-Stab Symbol Types + +The following types are used by the linker and assembler, not by stab +directives. Since this document does not attempt to describe aspects of +object file format other than the debugging format, no details are +given. + +@c Try to get most of these to fit on a single line. +@iftex +@tableindent=1.5in +@end iftex + +@table @code +@item 0x0 N_UNDF +Undefined symbol + +@item 0x2 N_ABS +File scope absolute symbol + +@item 0x3 N_ABS | N_EXT +External absolute symbol + +@item 0x4 N_TEXT +File scope text symbol + +@item 0x5 N_TEXT | N_EXT +External text symbol + +@item 0x6 N_DATA +File scope data symbol + +@item 0x7 N_DATA | N_EXT +External data symbol + +@item 0x8 N_BSS +File scope BSS symbol + +@item 0x9 N_BSS | N_EXT +External BSS symbol + +@item 0x0c N_FN_SEQ +Same as @code{N_FN}, for Sequent compilers + +@item 0x0a N_INDR +Symbol is indirected to another symbol + +@item 0x12 N_COMM +Common---visible after shared library dynamic link + +@item 0x14 N_SETA +@itemx 0x15 N_SETA | N_EXT +Absolute set element + +@item 0x16 N_SETT +@itemx 0x17 N_SETT | N_EXT +Text segment set element + +@item 0x18 N_SETD +@itemx 0x19 N_SETD | N_EXT +Data segment set element + +@item 0x1a N_SETB +@itemx 0x1b N_SETB | N_EXT +BSS segment set element + +@item 0x1c N_SETV +@itemx 0x1d N_SETV | N_EXT +Pointer to set vector + +@item 0x1e N_WARNING +Print a warning message during linking + +@item 0x1f N_FN +File name of a @file{.o} file +@end table + +@node Stab Symbol Types +@appendixsec Stab Symbol Types + +The following symbol types indicate that this is a stab. This is the +full list of stab numbers, including stab types that are used in +languages other than C. + +@table @code +@item 0x20 N_GSYM +Global symbol; see @ref{Global Variables}. + +@item 0x22 N_FNAME +Function name (for BSD Fortran); see @ref{Procedures}. + +@item 0x24 N_FUN +Function name (@pxref{Procedures}) or text segment variable +(@pxref{Statics}). + +@item 0x26 N_STSYM +Data segment file-scope variable; see @ref{Statics}. + +@item 0x28 N_LCSYM +BSS segment file-scope variable; see @ref{Statics}. + +@item 0x2a N_MAIN +Name of main routine; see @ref{Main Program}. + +@item 0x2c N_ROSYM +Variable in @code{.rodata} section; see @ref{Statics}. + +@item 0x30 N_PC +Global symbol (for Pascal); see @ref{N_PC}. + +@item 0x32 N_NSYMS +Number of symbols (according to Ultrix V4.0); see @ref{N_NSYMS}. + +@item 0x34 N_NOMAP +No DST map; see @ref{N_NOMAP}. + +@c FIXME: describe this solaris feature in the body of the text (see +@c comments in include/aout/stab.def). +@item 0x38 N_OBJ +Object file (Solaris2). + +@c See include/aout/stab.def for (a little) more info. +@item 0x3c N_OPT +Debugger options (Solaris2). + +@item 0x40 N_RSYM +Register variable; see @ref{Register Variables}. + +@item 0x42 N_M2C +Modula-2 compilation unit; see @ref{N_M2C}. + +@item 0x44 N_SLINE +Line number in text segment; see @ref{Line Numbers}. + +@item 0x46 N_DSLINE +Line number in data segment; see @ref{Line Numbers}. + +@item 0x48 N_BSLINE +Line number in bss segment; see @ref{Line Numbers}. + +@item 0x48 N_BROWS +Sun source code browser, path to @file{.cb} file; see @ref{N_BROWS}. + +@item 0x4a N_DEFD +GNU Modula2 definition module dependency; see @ref{N_DEFD}. + +@item 0x4c N_FLINE +Function start/body/end line numbers (Solaris2). + +@item 0x50 N_EHDECL +GNU C++ exception variable; see @ref{N_EHDECL}. + +@item 0x50 N_MOD2 +Modula2 info "for imc" (according to Ultrix V4.0); see @ref{N_MOD2}. + +@item 0x54 N_CATCH +GNU C++ @code{catch} clause; see @ref{N_CATCH}. + +@item 0x60 N_SSYM +Structure of union element; see @ref{N_SSYM}. + +@item 0x62 N_ENDM +Last stab for module (Solaris2). + +@item 0x64 N_SO +Path and name of source file; see @ref{Source Files}. + +@item 0x80 N_LSYM +Stack variable (@pxref{Stack Variables}) or type (@pxref{Typedefs}). + +@item 0x82 N_BINCL +Beginning of an include file (Sun only); see @ref{Include Files}. + +@item 0x84 N_SOL +Name of include file; see @ref{Include Files}. + +@item 0xa0 N_PSYM +Parameter variable; see @ref{Parameters}. + +@item 0xa2 N_EINCL +End of an include file; see @ref{Include Files}. + +@item 0xa4 N_ENTRY +Alternate entry point; see @ref{Alternate Entry Points}. + +@item 0xc0 N_LBRAC +Beginning of a lexical block; see @ref{Block Structure}. + +@item 0xc2 N_EXCL +Place holder for a deleted include file; see @ref{Include Files}. + +@item 0xc4 N_SCOPE +Modula2 scope information (Sun linker); see @ref{N_SCOPE}. + +@item 0xe0 N_RBRAC +End of a lexical block; see @ref{Block Structure}. + +@item 0xe2 N_BCOMM +Begin named common block; see @ref{Common Blocks}. + +@item 0xe4 N_ECOMM +End named common block; see @ref{Common Blocks}. + +@item 0xe8 N_ECOML +Member of a common block; see @ref{Common Blocks}. + +@c FIXME: How does this really work? Move it to main body of document. +@item 0xea N_WITH +Pascal @code{with} statement: type,,0,0,offset (Solaris2). + +@item 0xf0 N_NBTEXT +Gould non-base registers; see @ref{Gould}. + +@item 0xf2 N_NBDATA +Gould non-base registers; see @ref{Gould}. + +@item 0xf4 N_NBBSS +Gould non-base registers; see @ref{Gould}. + +@item 0xf6 N_NBSTS +Gould non-base registers; see @ref{Gould}. + +@item 0xf8 N_NBLCS +Gould non-base registers; see @ref{Gould}. +@end table + +@c Restore the default table indent +@iftex +@tableindent=.8in +@end iftex + +@node Symbol Descriptors +@appendix Table of Symbol Descriptors + +The symbol descriptor is the character which follows the colon in many +stabs, and which tells what kind of stab it is. @xref{String Field}, +for more information about their use. + +@c Please keep this alphabetical +@table @code +@c In TeX, this looks great, digit is in italics. But makeinfo insists +@c on putting it in `', not realizing that @var should override @code. +@c I don't know of any way to make makeinfo do the right thing. Seems +@c like a makeinfo bug to me. +@item @var{digit} +@itemx ( +@itemx - +Variable on the stack; see @ref{Stack Variables}. + +@item : +C++ nested symbol; see @xref{Nested Symbols} + +@item a +Parameter passed by reference in register; see @ref{Reference Parameters}. + +@item b +Based variable; see @ref{Based Variables}. + +@item c +Constant; see @ref{Constants}. + +@item C +Conformant array bound (Pascal, maybe other languages); @ref{Conformant +Arrays}. Name of a caught exception (GNU C++). These can be +distinguished because the latter uses @code{N_CATCH} and the former uses +another symbol type. + +@item d +Floating point register variable; see @ref{Register Variables}. + +@item D +Parameter in floating point register; see @ref{Register Parameters}. + +@item f +File scope function; see @ref{Procedures}. + +@item F +Global function; see @ref{Procedures}. + +@item G +Global variable; see @ref{Global Variables}. + +@item i +@xref{Register Parameters}. + +@item I +Internal (nested) procedure; see @ref{Nested Procedures}. + +@item J +Internal (nested) function; see @ref{Nested Procedures}. + +@item L +Label name (documented by AIX, no further information known). + +@item m +Module; see @ref{Procedures}. + +@item p +Argument list parameter; see @ref{Parameters}. + +@item pP +@xref{Parameters}. + +@item pF +Fortran Function parameter; see @ref{Parameters}. + +@item P +Unfortunately, three separate meanings have been independently invented +for this symbol descriptor. At least the GNU and Sun uses can be +distinguished by the symbol type. Global Procedure (AIX) (symbol type +used unknown); see @ref{Procedures}. Register parameter (GNU) (symbol +type @code{N_PSYM}); see @ref{Parameters}. Prototype of function +referenced by this file (Sun @code{acc}) (symbol type @code{N_FUN}). + +@item Q +Static Procedure; see @ref{Procedures}. + +@item R +Register parameter; see @ref{Register Parameters}. + +@item r +Register variable; see @ref{Register Variables}. + +@item S +File scope variable; see @ref{Statics}. + +@item s +Local variable (OS9000). + +@item t +Type name; see @ref{Typedefs}. + +@item T +Enumeration, structure, or union tag; see @ref{Typedefs}. + +@item v +Parameter passed by reference; see @ref{Reference Parameters}. + +@item V +Procedure scope static variable; see @ref{Statics}. + +@item x +Conformant array; see @ref{Conformant Arrays}. + +@item X +Function return variable; see @ref{Parameters}. +@end table + +@node Type Descriptors +@appendix Table of Type Descriptors + +The type descriptor is the character which follows the type number and +an equals sign. It specifies what kind of type is being defined. +@xref{String Field}, for more information about their use. + +@table @code +@item @var{digit} +@itemx ( +Type reference; see @ref{String Field}. + +@item - +Reference to builtin type; see @ref{Negative Type Numbers}. + +@item # +Method (C++); see @ref{Method Type Descriptor}. + +@item * +Pointer; see @ref{Miscellaneous Types}. + +@item & +Reference (C++). + +@item @@ +Type Attributes (AIX); see @ref{String Field}. Member (class and variable) +type (GNU C++); see @ref{Member Type Descriptor}. + +@item a +Array; see @ref{Arrays}. + +@item A +Open array; see @ref{Arrays}. + +@item b +Pascal space type (AIX); see @ref{Miscellaneous Types}. Builtin integer +type (Sun); see @ref{Builtin Type Descriptors}. Const and volatile +qualfied type (OS9000). + +@item B +Volatile-qualified type; see @ref{Miscellaneous Types}. + +@item c +Complex builtin type (AIX); see @ref{Builtin Type Descriptors}. +Const-qualified type (OS9000). + +@item C +COBOL Picture type. See AIX documentation for details. + +@item d +File type; see @ref{Miscellaneous Types}. + +@item D +N-dimensional dynamic array; see @ref{Arrays}. + +@item e +Enumeration type; see @ref{Enumerations}. + +@item E +N-dimensional subarray; see @ref{Arrays}. + +@item f +Function type; see @ref{Function Types}. + +@item F +Pascal function parameter; see @ref{Function Types} + +@item g +Builtin floating point type; see @ref{Builtin Type Descriptors}. + +@item G +COBOL Group. See AIX documentation for details. + +@item i +Imported type (AIX); see @ref{Cross-References}. Volatile-qualified +type (OS9000). + +@item k +Const-qualified type; see @ref{Miscellaneous Types}. + +@item K +COBOL File Descriptor. See AIX documentation for details. + +@item M +Multiple instance type; see @ref{Miscellaneous Types}. + +@item n +String type; see @ref{Strings}. + +@item N +Stringptr; see @ref{Strings}. + +@item o +Opaque type; see @ref{Typedefs}. + +@item p +Procedure; see @ref{Function Types}. + +@item P +Packed array; see @ref{Arrays}. + +@item r +Range type; see @ref{Subranges}. + +@item R +Builtin floating type; see @ref{Builtin Type Descriptors} (Sun). Pascal +subroutine parameter; see @ref{Function Types} (AIX). Detecting this +conflict is possible with careful parsing (hint: a Pascal subroutine +parameter type will always contain a comma, and a builtin type +descriptor never will). + +@item s +Structure type; see @ref{Structures}. + +@item S +Set type; see @ref{Miscellaneous Types}. + +@item u +Union; see @ref{Unions}. + +@item v +Variant record. This is a Pascal and Modula-2 feature which is like a +union within a struct in C. See AIX documentation for details. + +@item w +Wide character; see @ref{Builtin Type Descriptors}. + +@item x +Cross-reference; see @ref{Cross-References}. + +@item Y +Used by IBM's xlC C++ compiler (for structures, I think). + +@item z +gstring; see @ref{Strings}. +@end table + +@node Expanded Reference +@appendix Expanded Reference by Stab Type + +@c FIXME: This appendix should go away; see N_PSYM or N_SO for an example. + +For a full list of stab types, and cross-references to where they are +described, see @ref{Stab Types}. This appendix just covers certain +stabs which are not yet described in the main body of this document; +eventually the information will all be in one place. + +Format of an entry: + +The first line is the symbol type (see @file{include/aout/stab.def}). + +The second line describes the language constructs the symbol type +represents. + +The third line is the stab format with the significant stab fields +named and the rest NIL. + +Subsequent lines expand upon the meaning and possible values for each +significant stab field. + +Finally, any further information. + +@menu +* N_PC:: Pascal global symbol +* N_NSYMS:: Number of symbols +* N_NOMAP:: No DST map +* N_M2C:: Modula-2 compilation unit +* N_BROWS:: Path to .cb file for Sun source code browser +* N_DEFD:: GNU Modula2 definition module dependency +* N_EHDECL:: GNU C++ exception variable +* N_MOD2:: Modula2 information "for imc" +* N_CATCH:: GNU C++ "catch" clause +* N_SSYM:: Structure or union element +* N_SCOPE:: Modula2 scope information (Sun only) +* Gould:: non-base register symbols used on Gould systems +* N_LENG:: Length of preceding entry +@end menu + +@node N_PC +@section N_PC + +@deffn @code{.stabs} N_PC +@findex N_PC +Global symbol (for Pascal). + +@example +"name" -> "symbol_name" <> +value -> supposedly the line number (stab.def is skeptical) +@end example + +@display +@file{stabdump.c} says: + +global pascal symbol: name,,0,subtype,line +<< subtype? >> +@end display +@end deffn + +@node N_NSYMS +@section N_NSYMS + +@deffn @code{.stabn} N_NSYMS +@findex N_NSYMS +Number of symbols (according to Ultrix V4.0). + +@display + 0, files,,funcs,lines (stab.def) +@end display +@end deffn + +@node N_NOMAP +@section N_NOMAP + +@deffn @code{.stabs} N_NOMAP +@findex N_NOMAP +No DST map for symbol (according to Ultrix V4.0). I think this means a +variable has been optimized out. + +@display + name, ,0,type,ignored (stab.def) +@end display +@end deffn + +@node N_M2C +@section N_M2C + +@deffn @code{.stabs} N_M2C +@findex N_M2C +Modula-2 compilation unit. + +@example +"string" -> "unit_name,unit_time_stamp[,code_time_stamp]" +desc -> unit_number +value -> 0 (main unit) + 1 (any other unit) +@end example + +See @cite{Dbx and Dbxtool Interfaces}, 2nd edition, by Sun, 1988, for +more information. + +@end deffn + +@node N_BROWS +@section N_BROWS + +@deffn @code{.stabs} N_BROWS +@findex N_BROWS +Sun source code browser, path to @file{.cb} file + +<> +"path to associated @file{.cb} file" + +Note: N_BROWS has the same value as N_BSLINE. +@end deffn + +@node N_DEFD +@section N_DEFD + +@deffn @code{.stabn} N_DEFD +@findex N_DEFD +GNU Modula2 definition module dependency. + +GNU Modula-2 definition module dependency. The value is the +modification time of the definition file. The other field is non-zero +if it is imported with the GNU M2 keyword @code{%INITIALIZE}. Perhaps +@code{N_M2C} can be used if there are enough empty fields? +@end deffn + +@node N_EHDECL +@section N_EHDECL + +@deffn @code{.stabs} N_EHDECL +@findex N_EHDECL +GNU C++ exception variable <>. + +"@var{string} is variable name" + +Note: conflicts with @code{N_MOD2}. +@end deffn + +@node N_MOD2 +@section N_MOD2 + +@deffn @code{.stab?} N_MOD2 +@findex N_MOD2 +Modula2 info "for imc" (according to Ultrix V4.0) + +Note: conflicts with @code{N_EHDECL} <> +@end deffn + +@node N_CATCH +@section N_CATCH + +@deffn @code{.stabn} N_CATCH +@findex N_CATCH +GNU C++ @code{catch} clause + +GNU C++ @code{catch} clause. The value is its address. The desc field +is nonzero if this entry is immediately followed by a @code{CAUGHT} stab +saying what exception was caught. Multiple @code{CAUGHT} stabs means +that multiple exceptions can be caught here. If desc is 0, it means all +exceptions are caught here. +@end deffn + +@node N_SSYM +@section N_SSYM + +@deffn @code{.stabn} N_SSYM +@findex N_SSYM +Structure or union element. + +The value is the offset in the structure. + +<> +@end deffn + +@node N_SCOPE +@section N_SCOPE + +@deffn @code{.stab?} N_SCOPE +@findex N_SCOPE +Modula2 scope information (Sun linker) +<> +@end deffn + +@node Gould +@section Non-base registers on Gould systems + +@deffn @code{.stab?} N_NBTEXT +@deffnx @code{.stab?} N_NBDATA +@deffnx @code{.stab?} N_NBBSS +@deffnx @code{.stab?} N_NBSTS +@deffnx @code{.stab?} N_NBLCS +@findex N_NBTEXT +@findex N_NBDATA +@findex N_NBBSS +@findex N_NBSTS +@findex N_NBLCS +These are used on Gould systems for non-base registers syms. + +However, the following values are not the values used by Gould; they are +the values which GNU has been documenting for these values for a long +time, without actually checking what Gould uses. I include these values +only because perhaps some someone actually did something with the GNU +information (I hope not, why GNU knowingly assigned wrong values to +these in the header file is a complete mystery to me). + +@example +240 0xf0 N_NBTEXT ?? +242 0xf2 N_NBDATA ?? +244 0xf4 N_NBBSS ?? +246 0xf6 N_NBSTS ?? +248 0xf8 N_NBLCS ?? +@end example +@end deffn + +@node N_LENG +@section N_LENG + +@deffn @code{.stabn} N_LENG +@findex N_LENG +Second symbol entry containing a length-value for the preceding entry. +The value is the length. +@end deffn + +@node Questions +@appendix Questions and Anomalies + +@itemize @bullet +@item +@c I think this is changed in GCC 2.4.5 to put the line number there. +For GNU C stabs defining local and global variables (@code{N_LSYM} and +@code{N_GSYM}), the desc field is supposed to contain the source +line number on which the variable is defined. In reality the desc +field is always 0. (This behavior is defined in @file{dbxout.c} and +putting a line number in desc is controlled by @samp{#ifdef +WINNING_GDB}, which defaults to false). GDB supposedly uses this +information if you say @samp{list @var{var}}. In reality, @var{var} can +be a variable defined in the program and GDB says @samp{function +@var{var} not defined}. + +@item +In GNU C stabs, there seems to be no way to differentiate tag types: +structures, unions, and enums (symbol descriptor @samp{T}) and typedefs +(symbol descriptor @samp{t}) defined at file scope from types defined locally +to a procedure or other more local scope. They all use the @code{N_LSYM} +stab type. Types defined at procedure scope are emited after the +@code{N_RBRAC} of the preceding function and before the code of the +procedure in which they are defined. This is exactly the same as +types defined in the source file between the two procedure bodies. +GDB overcompensates by placing all types in block #1, the block for +symbols of file scope. This is true for default, @samp{-ansi} and +@samp{-traditional} compiler options. (Bugs gcc/1063, gdb/1066.) + +@item +What ends the procedure scope? Is it the proc block's @code{N_RBRAC} or the +next @code{N_FUN}? (I believe its the first.) +@end itemize + +@node Sun Differences +@appendix Differences Between GNU Stabs and Sun Native Stabs + +@c FIXME: Merge all this stuff into the main body of the document. + +@itemize @bullet +@item +GNU C stabs define @emph{all} types, file or procedure scope, as +@code{N_LSYM}. Sun doc talks about using @code{N_GSYM} too. + +@item +Sun C stabs use type number pairs in the format +(@var{file-number},@var{type-number}) where @var{file-number} is a +number starting with 1 and incremented for each sub-source file in the +compilation. @var{type-number} is a number starting with 1 and +incremented for each new type defined in the compilation. GNU C stabs +use the type number alone, with no source file number. +@end itemize + +@node Stab Sections +@appendix Using Stabs in Their Own Sections + +Many object file formats allow tools to create object files with custom +sections containing any arbitrary data. For any such object file +format, stabs can be embedded in special sections. This is how stabs +are used with ELF and SOM, and aside from ECOFF and XCOFF, is how stabs +are used with COFF. + +@menu +* Stab Section Basics:: How to embed stabs in sections +* ELF Linker Relocation:: Sun ELF hacks +@end menu + +@node Stab Section Basics +@appendixsec How to Embed Stabs in Sections + +The assembler creates two custom sections, a section named @code{.stab} +which contains an array of fixed length structures, one struct per stab, +and a section named @code{.stabstr} containing all the variable length +strings that are referenced by stabs in the @code{.stab} section. The +byte order of the stabs binary data depends on the object file format. +For ELF, it matches the byte order of the ELF file itself, as determined +from the @code{EI_DATA} field in the @code{e_ident} member of the ELF +header. For SOM, it is always big-endian (is this true??? FIXME). For +COFF, it matches the byte order of the COFF headers. The meaning of the +fields is the same as for a.out (@pxref{Symbol Table Format}), except +that the @code{n_strx} field is relative to the strings for the current +compilation unit (which can be found using the synthetic N_UNDF stab +described below), rather than the entire string table. + +The first stab in the @code{.stab} section for each compilation unit is +synthetic, generated entirely by the assembler, with no corresponding +@code{.stab} directive as input to the assembler. This stab contains +the following fields: + +@table @code +@item n_strx +Offset in the @code{.stabstr} section to the source filename. + +@item n_type +@code{N_UNDF}. + +@item n_other +Unused field, always zero. +This may eventually be used to hold overflows from the count in +the @code{n_desc} field. + +@item n_desc +Count of upcoming symbols, i.e., the number of remaining stabs for this +source file. + +@item n_value +Size of the string table fragment associated with this source file, in +bytes. +@end table + +The @code{.stabstr} section always starts with a null byte (so that string +offsets of zero reference a null string), followed by random length strings, +each of which is null byte terminated. + +The ELF section header for the @code{.stab} section has its +@code{sh_link} member set to the section number of the @code{.stabstr} +section, and the @code{.stabstr} section has its ELF section +header @code{sh_type} member set to @code{SHT_STRTAB} to mark it as a +string table. SOM and COFF have no way of linking the sections together +or marking them as string tables. + +For COFF, the @code{.stab} and @code{.stabstr} sections are simply +concatenated by the linker. GDB then uses the @code{n_desc} fields to +figure out the extent of the original sections. Similarly, the +@code{n_value} fields of the header symbols are added together in order +to get the actual position of the strings in a desired @code{.stabstr} +section. Although this design obviates any need for the linker to relocate +or otherwise manipulate @code{.stab} and @code{.stabstr} sections, it also +requires some care to ensure that the offsets are calculated correctly. +For instance, if the linker were to pad in between the @code{.stabstr} +sections before concatenating, then the offsets to strings in the middle +of the executable's @code{.stabstr} section would be wrong. + +@node ELF Linker Relocation +@appendixsec Having the Linker Relocate Stabs in ELF + +This section describes some Sun hacks for Stabs in ELF; it does not +apply to COFF or SOM. + +To keep linking fast, you don't want the linker to have to relocate very +many stabs. Making sure this is done for @code{N_SLINE}, +@code{N_RBRAC}, and @code{N_LBRAC} stabs is the most important thing +(see the descriptions of those stabs for more information). But Sun's +stabs in ELF has taken this further, to make all addresses in the +@code{n_value} field (functions and static variables) relative to the +source file. For the @code{N_SO} symbol itself, Sun simply omits the +address. To find the address of each section corresponding to a given +source file, the compiler puts out symbols giving the address of each +section for a given source file. Since these are ELF (not stab) +symbols, the linker relocates them correctly without having to touch the +stabs section. They are named @code{Bbss.bss} for the bss section, +@code{Ddata.data} for the data section, and @code{Drodata.rodata} for +the rodata section. For the text section, there is no such symbol (but +there should be, see below). For an example of how these symbols work, +@xref{Stab Section Transformations}. GCC does not provide these symbols; +it instead relies on the stabs getting relocated. Thus addresses which +would normally be relative to @code{Bbss.bss}, etc., are already +relocated. The Sun linker provided with Solaris 2.2 and earlier +relocates stabs using normal ELF relocation information, as it would do +for any section. Sun has been threatening to kludge their linker to not +do this (to speed up linking), even though the correct way to avoid +having the linker do these relocations is to have the compiler no longer +output relocatable values. Last I heard they had been talked out of the +linker kludge. See Sun point patch 101052-01 and Sun bug 1142109. With +the Sun compiler this affects @samp{S} symbol descriptor stabs +(@pxref{Statics}) and functions (@pxref{Procedures}). In the latter +case, to adopt the clean solution (making the value of the stab relative +to the start of the compilation unit), it would be necessary to invent a +@code{Ttext.text} symbol, analogous to the @code{Bbss.bss}, etc., +symbols. I recommend this rather than using a zero value and getting +the address from the ELF symbols. + +Finding the correct @code{Bbss.bss}, etc., symbol is difficult, because +the linker simply concatenates the @code{.stab} sections from each +@file{.o} file without including any information about which part of a +@code{.stab} section comes from which @file{.o} file. The way GDB does +this is to look for an ELF @code{STT_FILE} symbol which has the same +name as the last component of the file name from the @code{N_SO} symbol +in the stabs (for example, if the file name is @file{../../gdb/main.c}, +it looks for an ELF @code{STT_FILE} symbol named @code{main.c}). This +loses if different files have the same name (they could be in different +directories, a library could have been copied from one system to +another, etc.). It would be much cleaner to have the @code{Bbss.bss} +symbols in the stabs themselves. Having the linker relocate them there +is no more work than having the linker relocate ELF symbols, and it +solves the problem of having to associate the ELF and stab symbols. +However, no one has yet designed or implemented such a scheme. + +@node Symbol Types Index +@unnumbered Symbol Types Index + +@printindex fn + +@contents +@bye diff --git a/contrib/gdb/gdb/dwarfread.c b/contrib/gdb/gdb/dwarfread.c new file mode 100644 index 000000000000..ed82009e74f0 --- /dev/null +++ b/contrib/gdb/gdb/dwarfread.c @@ -0,0 +1,3883 @@ +/* DWARF debugging format support for GDB. + Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support. Portions based on dbxread.c, + mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + +FIXME: Do we need to generate dependencies in partial symtabs? +(Perhaps we don't need to). + +FIXME: Resolve minor differences between what information we put in the +partial symbol table and what dbxread puts in. For example, we don't yet +put enum constants there. And dbxread seems to invent a lot of typedefs +we never see. Use the new printpsym command to see the partial symbol table +contents. + +FIXME: Figure out a better way to tell gdb about the name of the function +contain the user's entry point (I.E. main()) + +FIXME: See other FIXME's and "ifdef 0" scattered throughout the code for +other things to work on, if you get bored. :-) + +*/ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "symfile.h" +#include "objfiles.h" +#include "elf/dwarf.h" +#include "buildsym.h" +#include "demangle.h" +#include "expression.h" /* Needed for enum exp_opcode in language.h, sigh... */ +#include "language.h" +#include "complaints.h" + +#include +#include "gdb_string.h" + +#ifndef NO_SYS_FILE +#include +#endif + +/* Some macros to provide DIE info for complaints. */ + +#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0) +#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : "" + +/* Complaints that can be issued during DWARF debug info reading. */ + +struct complaint no_bfd_get_N = +{ + "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0 +}; + +struct complaint malformed_die = +{ + "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0 +}; + +struct complaint bad_die_ref = +{ + "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0 +}; + +struct complaint unknown_attribute_form = +{ + "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0 +}; + +struct complaint unknown_attribute_length = +{ + "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0 +}; + +struct complaint unexpected_fund_type = +{ + "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0 +}; + +struct complaint unknown_type_modifier = +{ + "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0 +}; + +struct complaint volatile_ignored = +{ + "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0 +}; + +struct complaint const_ignored = +{ + "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0 +}; + +struct complaint botched_modified_type = +{ + "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0 +}; + +struct complaint op_deref2 = +{ + "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0 +}; + +struct complaint op_deref4 = +{ + "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0 +}; + +struct complaint basereg_not_handled = +{ + "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0 +}; + +struct complaint dup_user_type_allocation = +{ + "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0 +}; + +struct complaint dup_user_type_definition = +{ + "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0 +}; + +struct complaint missing_tag = +{ + "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0 +}; + +struct complaint bad_array_element_type = +{ + "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0 +}; + +struct complaint subscript_data_items = +{ + "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0 +}; + +struct complaint unhandled_array_subscript_format = +{ + "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0 +}; + +struct complaint unknown_array_subscript_format = +{ + "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0 +}; + +struct complaint not_row_major = +{ + "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0 +}; + +struct complaint missing_at_name = +{ + "DIE @ 0x%x, AT_name tag missing", 0, 0 +}; + +typedef unsigned int DIE_REF; /* Reference to a DIE */ + +#ifndef GCC_PRODUCER +#define GCC_PRODUCER "GNU C " +#endif + +#ifndef GPLUS_PRODUCER +#define GPLUS_PRODUCER "GNU C++ " +#endif + +#ifndef LCC_PRODUCER +#define LCC_PRODUCER "NCR C/C++" +#endif + +#ifndef CHILL_PRODUCER +#define CHILL_PRODUCER "GNU Chill " +#endif + +/* Provide a default mapping from a DWARF register number to a gdb REGNUM. */ +#ifndef DWARF_REG_TO_REGNUM +#define DWARF_REG_TO_REGNUM(num) (num) +#endif + +/* Flags to target_to_host() that tell whether or not the data object is + expected to be signed. Used, for example, when fetching a signed + integer in the target environment which is used as a signed integer + in the host environment, and the two environments have different sized + ints. In this case, *somebody* has to sign extend the smaller sized + int. */ + +#define GET_UNSIGNED 0 /* No sign extension required */ +#define GET_SIGNED 1 /* Sign extension required */ + +/* Defines for things which are specified in the document "DWARF Debugging + Information Format" published by UNIX International, Programming Languages + SIG. These defines are based on revision 1.0.0, Jan 20, 1992. */ + +#define SIZEOF_DIE_LENGTH 4 +#define SIZEOF_DIE_TAG 2 +#define SIZEOF_ATTRIBUTE 2 +#define SIZEOF_FORMAT_SPECIFIER 1 +#define SIZEOF_FMT_FT 2 +#define SIZEOF_LINETBL_LENGTH 4 +#define SIZEOF_LINETBL_LINENO 4 +#define SIZEOF_LINETBL_STMT 2 +#define SIZEOF_LINETBL_DELTA 4 +#define SIZEOF_LOC_ATOM_CODE 1 + +#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified */ + +/* Macros that return the sizes of various types of data in the target + environment. + + FIXME: Currently these are just compile time constants (as they are in + other parts of gdb as well). They need to be able to get the right size + either from the bfd or possibly from the DWARF info. It would be nice if + the DWARF producer inserted DIES that describe the fundamental types in + the target environment into the DWARF info, similar to the way dbx stabs + producers produce information about their fundamental types. */ + +#define TARGET_FT_POINTER_SIZE(objfile) (TARGET_PTR_BIT / TARGET_CHAR_BIT) +#define TARGET_FT_LONG_SIZE(objfile) (TARGET_LONG_BIT / TARGET_CHAR_BIT) + +/* The Amiga SVR4 header file defines AT_element_list as a + FORM_BLOCK2, and this is the value emitted by the AT&T compiler. + However, the Issue 2 DWARF specification from AT&T defines it as + a FORM_BLOCK4, as does the latest specification from UI/PLSIG. + For backwards compatibility with the AT&T compiler produced executables + we define AT_short_element_list for this variant. */ + +#define AT_short_element_list (0x00f0|FORM_BLOCK2) + +/* External variables referenced. */ + +extern int info_verbose; /* From main.c; nonzero => verbose */ +extern char *warning_pre_print; /* From utils.c */ + +/* The DWARF debugging information consists of two major pieces, + one is a block of DWARF Information Entries (DIE's) and the other + is a line number table. The "struct dieinfo" structure contains + the information for a single DIE, the one currently being processed. + + In order to make it easier to randomly access the attribute fields + of the current DIE, which are specifically unordered within the DIE, + each DIE is scanned and an instance of the "struct dieinfo" + structure is initialized. + + Initialization is done in two levels. The first, done by basicdieinfo(), + just initializes those fields that are vital to deciding whether or not + to use this DIE, how to skip past it, etc. The second, done by the + function completedieinfo(), fills in the rest of the information. + + Attributes which have block forms are not interpreted at the time + the DIE is scanned, instead we just save pointers to the start + of their value fields. + + Some fields have a flag _p that is set when the value of the + field is valid (I.E. we found a matching attribute in the DIE). Since + we may want to test for the presence of some attributes in the DIE, + such as AT_low_pc, without restricting the values of the field, + we need someway to note that we found such an attribute. + + */ + +typedef char BLOCK; + +struct dieinfo { + char * die; /* Pointer to the raw DIE data */ + unsigned long die_length; /* Length of the raw DIE data */ + DIE_REF die_ref; /* Offset of this DIE */ + unsigned short die_tag; /* Tag for this DIE */ + unsigned long at_padding; + unsigned long at_sibling; + BLOCK * at_location; + char * at_name; + unsigned short at_fund_type; + BLOCK * at_mod_fund_type; + unsigned long at_user_def_type; + BLOCK * at_mod_u_d_type; + unsigned short at_ordering; + BLOCK * at_subscr_data; + unsigned long at_byte_size; + unsigned short at_bit_offset; + unsigned long at_bit_size; + BLOCK * at_element_list; + unsigned long at_stmt_list; + CORE_ADDR at_low_pc; + CORE_ADDR at_high_pc; + unsigned long at_language; + unsigned long at_member; + unsigned long at_discr; + BLOCK * at_discr_value; + BLOCK * at_string_length; + char * at_comp_dir; + char * at_producer; + unsigned long at_start_scope; + unsigned long at_stride_size; + unsigned long at_src_info; + char * at_prototyped; + unsigned int has_at_low_pc:1; + unsigned int has_at_stmt_list:1; + unsigned int has_at_byte_size:1; + unsigned int short_element_list:1; +}; + +static int diecount; /* Approximate count of dies for compilation unit */ +static struct dieinfo *curdie; /* For warnings and such */ + +static char *dbbase; /* Base pointer to dwarf info */ +static int dbsize; /* Size of dwarf info in bytes */ +static int dbroff; /* Relative offset from start of .debug section */ +static char *lnbase; /* Base pointer to line section */ +static int isreg; /* Kludge to identify register variables */ +static int optimized_out; /* Kludge to identify optimized out variables */ +/* Kludge to identify basereg references. Nonzero if we have an offset + relative to a basereg. */ +static int offreg; +/* Which base register is it relative to? */ +static int basereg; + +/* This value is added to each symbol value. FIXME: Generalize to + the section_offsets structure used by dbxread (once this is done, + pass the appropriate section number to end_symtab). */ +static CORE_ADDR baseaddr; /* Add to each symbol value */ + +/* The section offsets used in the current psymtab or symtab. FIXME, + only used to pass one value (baseaddr) at the moment. */ +static struct section_offsets *base_section_offsets; + +/* We put a pointer to this structure in the read_symtab_private field + of the psymtab. */ + +struct dwfinfo { + /* Always the absolute file offset to the start of the ".debug" + section for the file containing the DIE's being accessed. */ + file_ptr dbfoff; + /* Relative offset from the start of the ".debug" section to the + first DIE to be accessed. When building the partial symbol + table, this value will be zero since we are accessing the + entire ".debug" section. When expanding a partial symbol + table entry, this value will be the offset to the first + DIE for the compilation unit containing the symbol that + triggers the expansion. */ + int dbroff; + /* The size of the chunk of DIE's being examined, in bytes. */ + int dblength; + /* The absolute file offset to the line table fragment. Ignored + when building partial symbol tables, but used when expanding + them, and contains the absolute file offset to the fragment + of the ".line" section containing the line numbers for the + current compilation unit. */ + file_ptr lnfoff; +}; + +#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff) +#define DBROFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbroff) +#define DBLENGTH(p) (((struct dwfinfo *)((p)->read_symtab_private))->dblength) +#define LNFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->lnfoff) + +/* The generic symbol table building routines have separate lists for + file scope symbols and all all other scopes (local scopes). So + we need to select the right one to pass to add_symbol_to_list(). + We do it by keeping a pointer to the correct list in list_in_scope. + + FIXME: The original dwarf code just treated the file scope as the first + local scope, and all other local scopes as nested local scopes, and worked + fine. Check to see if we really need to distinguish these in buildsym.c */ + +struct pending **list_in_scope = &file_symbols; + +/* DIES which have user defined types or modified user defined types refer to + other DIES for the type information. Thus we need to associate the offset + of a DIE for a user defined type with a pointer to the type information. + + Originally this was done using a simple but expensive algorithm, with an + array of unsorted structures, each containing an offset/type-pointer pair. + This array was scanned linearly each time a lookup was done. The result + was that gdb was spending over half it's startup time munging through this + array of pointers looking for a structure that had the right offset member. + + The second attempt used the same array of structures, but the array was + sorted using qsort each time a new offset/type was recorded, and a binary + search was used to find the type pointer for a given DIE offset. This was + even slower, due to the overhead of sorting the array each time a new + offset/type pair was entered. + + The third attempt uses a fixed size array of type pointers, indexed by a + value derived from the DIE offset. Since the minimum DIE size is 4 bytes, + we can divide any DIE offset by 4 to obtain a unique index into this fixed + size array. Since each element is a 4 byte pointer, it takes exactly as + much memory to hold this array as to hold the DWARF info for a given + compilation unit. But it gets freed as soon as we are done with it. + This has worked well in practice, as a reasonable tradeoff between memory + consumption and speed, without having to resort to much more complicated + algorithms. */ + +static struct type **utypes; /* Pointer to array of user type pointers */ +static int numutypes; /* Max number of user type pointers */ + +/* Maintain an array of referenced fundamental types for the current + compilation unit being read. For DWARF version 1, we have to construct + the fundamental types on the fly, since no information about the + fundamental types is supplied. Each such fundamental type is created by + calling a language dependent routine to create the type, and then a + pointer to that type is then placed in the array at the index specified + by it's FT_ value. The array has a fixed size set by the + FT_NUM_MEMBERS compile time constant, which is the number of predefined + fundamental types gdb knows how to construct. */ + +static struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */ + +/* Record the language for the compilation unit which is currently being + processed. We know it once we have seen the TAG_compile_unit DIE, + and we need it while processing the DIE's for that compilation unit. + It is eventually saved in the symtab structure, but we don't finalize + the symtab struct until we have processed all the DIE's for the + compilation unit. We also need to get and save a pointer to the + language struct for this language, so we can call the language + dependent routines for doing things such as creating fundamental + types. */ + +static enum language cu_language; +static const struct language_defn *cu_language_defn; + +/* Forward declarations of static functions so we don't have to worry + about ordering within this file. */ + +static int +attribute_size PARAMS ((unsigned int)); + +static CORE_ADDR +target_to_host PARAMS ((char *, int, int, struct objfile *)); + +static void +add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +handle_producer PARAMS ((char *)); + +static void +read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static void +read_func_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static void +read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *, + struct objfile *)); + +static void +scan_partial_symbols PARAMS ((char *, char *, struct objfile *)); + +static void +scan_compilation_units PARAMS ((char *, char *, file_ptr, + file_ptr, struct objfile *)); + +static void +add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +basicdieinfo PARAMS ((struct dieinfo *, char *, struct objfile *)); + +static void +completedieinfo PARAMS ((struct dieinfo *, struct objfile *)); + +static void +dwarf_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +static void +psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +read_ofile_symtab PARAMS ((struct partial_symtab *)); + +static void +process_dies PARAMS ((char *, char *, struct objfile *)); + +static void +read_structure_scope PARAMS ((struct dieinfo *, char *, char *, + struct objfile *)); + +static struct type * +decode_array_element_type PARAMS ((char *)); + +static struct type * +decode_subscript_data_item PARAMS ((char *, char *)); + +static void +dwarf_read_array_type PARAMS ((struct dieinfo *)); + +static void +read_tag_pointer_type PARAMS ((struct dieinfo *dip)); + +static void +read_tag_string_type PARAMS ((struct dieinfo *dip)); + +static void +read_subroutine_type PARAMS ((struct dieinfo *, char *, char *)); + +static void +read_enumeration PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static struct type * +struct_type PARAMS ((struct dieinfo *, char *, char *, struct objfile *)); + +static struct type * +enum_type PARAMS ((struct dieinfo *, struct objfile *)); + +static void +decode_line_numbers PARAMS ((char *)); + +static struct type * +decode_die_type PARAMS ((struct dieinfo *)); + +static struct type * +decode_mod_fund_type PARAMS ((char *)); + +static struct type * +decode_mod_u_d_type PARAMS ((char *)); + +static struct type * +decode_modified_type PARAMS ((char *, unsigned int, int)); + +static struct type * +decode_fund_type PARAMS ((unsigned int)); + +static char * +create_name PARAMS ((char *, struct obstack *)); + +static struct type * +lookup_utype PARAMS ((DIE_REF)); + +static struct type * +alloc_utype PARAMS ((DIE_REF, struct type *)); + +static struct symbol * +new_symbol PARAMS ((struct dieinfo *, struct objfile *)); + +static void +synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *, + struct type *)); + +static int +locval PARAMS ((char *)); + +static void +set_cu_language PARAMS ((struct dieinfo *)); + +static struct type * +dwarf_fundamental_type PARAMS ((struct objfile *, int)); + + +/* + +LOCAL FUNCTION + + dwarf_fundamental_type -- lookup or create a fundamental type + +SYNOPSIS + + struct type * + dwarf_fundamental_type (struct objfile *objfile, int typeid) + +DESCRIPTION + + DWARF version 1 doesn't supply any fundamental type information, + so gdb has to construct such types. It has a fixed number of + fundamental types that it knows how to construct, which is the + union of all types that it knows how to construct for all languages + that it knows about. These are enumerated in gdbtypes.h. + + As an example, assume we find a DIE that references a DWARF + fundamental type of FT_integer. We first look in the ftypes + array to see if we already have such a type, indexed by the + gdb internal value of FT_INTEGER. If so, we simply return a + pointer to that type. If not, then we ask an appropriate + language dependent routine to create a type FT_INTEGER, using + defaults reasonable for the current target machine, and install + that type in ftypes for future reference. + +RETURNS + + Pointer to a fundamental type. + +*/ + +static struct type * +dwarf_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + if (typeid < 0 || typeid >= FT_NUM_MEMBERS) + { + error ("internal error - invalid fundamental type id %d", typeid); + } + + /* Look for this particular type in the fundamental type vector. If one is + not found, create and install one appropriate for the current language + and the current target machine. */ + + if (ftypes[typeid] == NULL) + { + ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid); + } + + return (ftypes[typeid]); +} + +/* + +LOCAL FUNCTION + + set_cu_language -- set local copy of language for compilation unit + +SYNOPSIS + + void + set_cu_language (struct dieinfo *dip) + +DESCRIPTION + + Decode the language attribute for a compilation unit DIE and + remember what the language was. We use this at various times + when processing DIE's for a given compilation unit. + +RETURNS + + No return value. + + */ + +static void +set_cu_language (dip) + struct dieinfo *dip; +{ + switch (dip -> at_language) + { + case LANG_C89: + case LANG_C: + cu_language = language_c; + break; + case LANG_C_PLUS_PLUS: + cu_language = language_cplus; + break; + case LANG_CHILL: + cu_language = language_chill; + break; + case LANG_MODULA2: + cu_language = language_m2; + break; + case LANG_ADA83: + case LANG_COBOL74: + case LANG_COBOL85: + case LANG_FORTRAN77: + case LANG_FORTRAN90: + case LANG_PASCAL83: + /* We don't know anything special about these yet. */ + cu_language = language_unknown; + break; + default: + /* If no at_language, try to deduce one from the filename */ + cu_language = deduce_language_from_filename (dip -> at_name); + break; + } + cu_language_defn = language_def (cu_language); +} + +/* + +GLOBAL FUNCTION + + dwarf_build_psymtabs -- build partial symtabs from DWARF debug info + +SYNOPSIS + + void dwarf_build_psymtabs (struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, file_ptr dbfoff, unsigned int dbfsize, + file_ptr lnoffset, unsigned int lnsize) + +DESCRIPTION + + This function is called upon to build partial symtabs from files + containing DIE's (Dwarf Information Entries) and DWARF line numbers. + + It is passed a bfd* containing the DIES + and line number information, the corresponding filename for that + file, a base address for relocating the symbols, a flag indicating + whether or not this debugging information is from a "main symbol + table" rather than a shared library or dynamically linked file, + and file offset/size pairs for the DIE information and line number + information. + +RETURNS + + No return value. + + */ + +void +dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize, + lnoffset, lnsize) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; + file_ptr dbfoff; + unsigned int dbfsize; + file_ptr lnoffset; + unsigned int lnsize; +{ + bfd *abfd = objfile->obfd; + struct cleanup *back_to; + + current_objfile = objfile; + dbsize = dbfsize; + dbbase = xmalloc (dbsize); + dbroff = 0; + if ((bfd_seek (abfd, dbfoff, SEEK_SET) != 0) || + (bfd_read (dbbase, dbsize, 1, abfd) != dbsize)) + { + free (dbbase); + error ("can't read DWARF data from '%s'", bfd_get_filename (abfd)); + } + back_to = make_cleanup (free, dbbase); + + /* If we are reinitializing, or if we have never loaded syms yet, init. + Since we have no idea how many DIES we are looking at, we just guess + some arbitrary value. */ + + if (mainline || objfile -> global_psymbols.size == 0 || + objfile -> static_psymbols.size == 0) + { + init_psymbol_list (objfile, 1024); + } + + /* Save the relocation factor where everybody can see it. */ + + base_section_offsets = section_offsets; + baseaddr = ANOFFSET (section_offsets, 0); + + /* Follow the compilation unit sibling chain, building a partial symbol + table entry for each one. Save enough information about each compilation + unit to locate the full DWARF information later. */ + + scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile); + + do_cleanups (back_to); + current_objfile = NULL; +} + +/* + +LOCAL FUNCTION + + read_lexical_block_scope -- process all dies in a lexical block + +SYNOPSIS + + static void read_lexical_block_scope (struct dieinfo *dip, + char *thisdie, char *enddie) + +DESCRIPTION + + Process all the DIES contained within a lexical block scope. + Start a new scope, process the dies, and then close the scope. + + */ + +static void +read_lexical_block_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + register struct context_stack *new; + + push_context (0, dip -> at_low_pc); + process_dies (thisdie + dip -> die_length, enddie, objfile); + new = pop_context (); + if (local_symbols != NULL) + { + finish_block (0, &local_symbols, new -> old_blocks, new -> start_addr, + dip -> at_high_pc, objfile); + } + local_symbols = new -> locals; +} + +/* + +LOCAL FUNCTION + + lookup_utype -- look up a user defined type from die reference + +SYNOPSIS + + static type *lookup_utype (DIE_REF die_ref) + +DESCRIPTION + + Given a DIE reference, lookup the user defined type associated with + that DIE, if it has been registered already. If not registered, then + return NULL. Alloc_utype() can be called to register an empty + type for this reference, which will be filled in later when the + actual referenced DIE is processed. + */ + +static struct type * +lookup_utype (die_ref) + DIE_REF die_ref; +{ + struct type *type = NULL; + int utypeidx; + + utypeidx = (die_ref - dbroff) / 4; + if ((utypeidx < 0) || (utypeidx >= numutypes)) + { + complain (&bad_die_ref, DIE_ID, DIE_NAME); + } + else + { + type = *(utypes + utypeidx); + } + return (type); +} + + +/* + +LOCAL FUNCTION + + alloc_utype -- add a user defined type for die reference + +SYNOPSIS + + static type *alloc_utype (DIE_REF die_ref, struct type *utypep) + +DESCRIPTION + + Given a die reference DIE_REF, and a possible pointer to a user + defined type UTYPEP, register that this reference has a user + defined type and either use the specified type in UTYPEP or + make a new empty type that will be filled in later. + + We should only be called after calling lookup_utype() to verify that + there is not currently a type registered for DIE_REF. + */ + +static struct type * +alloc_utype (die_ref, utypep) + DIE_REF die_ref; + struct type *utypep; +{ + struct type **typep; + int utypeidx; + + utypeidx = (die_ref - dbroff) / 4; + typep = utypes + utypeidx; + if ((utypeidx < 0) || (utypeidx >= numutypes)) + { + utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + complain (&bad_die_ref, DIE_ID, DIE_NAME); + } + else if (*typep != NULL) + { + utypep = *typep; + complain (&dup_user_type_allocation, DIE_ID, DIE_NAME); + } + else + { + if (utypep == NULL) + { + utypep = alloc_type (current_objfile); + } + *typep = utypep; + } + return (utypep); +} + +/* + +LOCAL FUNCTION + + free_utypes -- free the utypes array and reset pointer & count + +SYNOPSIS + + static void free_utypes (PTR dummy) + +DESCRIPTION + + Called via do_cleanups to free the utypes array, reset the pointer to NULL, + and set numutypes back to zero. This ensures that the utypes does not get + referenced after being freed. + */ + +static void +free_utypes (dummy) + PTR dummy; +{ + free (utypes); + utypes = NULL; + numutypes = 0; +} + + +/* + +LOCAL FUNCTION + + decode_die_type -- return a type for a specified die + +SYNOPSIS + + static struct type *decode_die_type (struct dieinfo *dip) + +DESCRIPTION + + Given a pointer to a die information structure DIP, decode the + type of the die and return a pointer to the decoded type. All + dies without specific types default to type int. + */ + +static struct type * +decode_die_type (dip) + struct dieinfo *dip; +{ + struct type *type = NULL; + + if (dip -> at_fund_type != 0) + { + type = decode_fund_type (dip -> at_fund_type); + } + else if (dip -> at_mod_fund_type != NULL) + { + type = decode_mod_fund_type (dip -> at_mod_fund_type); + } + else if (dip -> at_user_def_type) + { + if ((type = lookup_utype (dip -> at_user_def_type)) == NULL) + { + type = alloc_utype (dip -> at_user_def_type, NULL); + } + } + else if (dip -> at_mod_u_d_type) + { + type = decode_mod_u_d_type (dip -> at_mod_u_d_type); + } + else + { + type = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + return (type); +} + +/* + +LOCAL FUNCTION + + struct_type -- compute and return the type for a struct or union + +SYNOPSIS + + static struct type *struct_type (struct dieinfo *dip, char *thisdie, + char *enddie, struct objfile *objfile) + +DESCRIPTION + + Given pointer to a die information structure for a die which + defines a union or structure (and MUST define one or the other), + and pointers to the raw die data that define the range of dies which + define the members, compute and return the user defined type for the + structure or union. + */ + +static struct type * +struct_type (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct nextfield { + struct nextfield *next; + struct field field; + }; + struct nextfield *list = NULL; + struct nextfield *new; + int nfields = 0; + int n; + struct dieinfo mbr; + char *nextdie; + int anonymous_size; + + if ((type = lookup_utype (dip -> die_ref)) == NULL) + { + /* No forward references created an empty type, so install one now */ + type = alloc_utype (dip -> die_ref, NULL); + } + INIT_CPLUS_SPECIFIC(type); + switch (dip -> die_tag) + { + case TAG_class_type: + TYPE_CODE (type) = TYPE_CODE_CLASS; + break; + case TAG_structure_type: + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case TAG_union_type: + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + default: + /* Should never happen */ + TYPE_CODE (type) = TYPE_CODE_UNDEF; + complain (&missing_tag, DIE_ID, DIE_NAME); + break; + } + /* Some compilers try to be helpful by inventing "fake" names for + anonymous enums, structures, and unions, like "~0fake" or ".0fake". + Thanks, but no thanks... */ + if (dip -> at_name != NULL + && *dip -> at_name != '~' + && *dip -> at_name != '.') + { + TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack, + "", "", dip -> at_name); + } + /* Use whatever size is known. Zero is a valid size. We might however + wish to check has_at_byte_size to make sure that some byte size was + given explicitly, but DWARF doesn't specify that explicit sizes of + zero have to present, so complaining about missing sizes should + probably not be the default. */ + TYPE_LENGTH (type) = dip -> at_byte_size; + thisdie += dip -> die_length; + while (thisdie < enddie) + { + basicdieinfo (&mbr, thisdie, objfile); + completedieinfo (&mbr, objfile); + if (mbr.die_length <= SIZEOF_DIE_LENGTH) + { + break; + } + else if (mbr.at_sibling != 0) + { + nextdie = dbbase + mbr.at_sibling - dbroff; + } + else + { + nextdie = thisdie + mbr.die_length; + } + switch (mbr.die_tag) + { + case TAG_member: + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new -> next = list; + list = new; + /* Save the data. */ + list -> field.name = + obsavestring (mbr.at_name, strlen (mbr.at_name), + &objfile -> type_obstack); + list -> field.type = decode_die_type (&mbr); + list -> field.bitpos = 8 * locval (mbr.at_location); + /* Handle bit fields. */ + list -> field.bitsize = mbr.at_bit_size; + if (BITS_BIG_ENDIAN) + { + /* For big endian bits, the at_bit_offset gives the + additional bit offset from the MSB of the containing + 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. */ + list -> field.bitpos += mbr.at_bit_offset; + } + else + { + /* For little endian bits, we need to have a non-zero + at_bit_size, so that we know we are in fact dealing + with a bitfield. Compute the bit offset to the MSB + of the anonymous object, subtract off the number of + bits from the MSB of the field to the MSB of the + object, and then subtract off the number of bits of + the field itself. The result is the bit offset of + the LSB of the field. */ + if (mbr.at_bit_size > 0) + { + if (mbr.has_at_byte_size) + { + /* The size of the anonymous object containing + the bit field is explicit, so use the + indicated size (in bytes). */ + anonymous_size = mbr.at_byte_size; + } + else + { + /* The size of the anonymous object containing + the bit field matches the size of an object + of the bit field's type. DWARF allows + at_byte_size to be left out in such cases, as + a debug information size optimization. */ + anonymous_size = TYPE_LENGTH (list -> field.type); + } + list -> field.bitpos += + anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size; + } + } + nfields++; + break; + default: + process_dies (thisdie, nextdie, objfile); + break; + } + thisdie = nextdie; + } + /* Now create the vector of fields, and record how big it is. We may + not even have any fields, if this DIE was generated due to a reference + to an anonymous structure or union. In this case, TYPE_FLAG_STUB is + set, which clues gdb in to the fact that it needs to search elsewhere + for the full structure definition. */ + if (nfields == 0) + { + TYPE_FLAGS (type) |= TYPE_FLAG_STUB; + } + else + { + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + /* Copy the saved-up fields into the field vector. */ + for (n = nfields; list; list = list -> next) + { + TYPE_FIELD (type, --n) = list -> field; + } + } + return (type); +} + +/* + +LOCAL FUNCTION + + read_structure_scope -- process all dies within struct or union + +SYNOPSIS + + static void read_structure_scope (struct dieinfo *dip, + char *thisdie, char *enddie, struct objfile *objfile) + +DESCRIPTION + + Called when we find the DIE that starts a structure or union + scope (definition) to process all dies that define the members + of the structure or union. DIP is a pointer to the die info + struct for the DIE that names the structure or union. + +NOTES + + Note that we need to call struct_type regardless of whether or not + the DIE has an at_name attribute, since it might be an anonymous + structure or union. This gets the type entered into our set of + user defined types. + + However, if the structure is incomplete (an opaque struct/union) + then suppress creating a symbol table entry for it since gdb only + wants to find the one with the complete definition. Note that if + it is complete, we just call new_symbol, which does it's own + checking about whether the struct/union is anonymous or not (and + suppresses creating a symbol table entry itself). + + */ + +static void +read_structure_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct symbol *sym; + + type = struct_type (dip, thisdie, enddie, objfile); + if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB)) + { + sym = new_symbol (dip, objfile); + if (sym != NULL) + { + SYMBOL_TYPE (sym) = type; + if (cu_language == language_cplus) + { + synthesize_typedef (dip, objfile, type); + } + } + } +} + +/* + +LOCAL FUNCTION + + decode_array_element_type -- decode type of the array elements + +SYNOPSIS + + static struct type *decode_array_element_type (char *scan, char *end) + +DESCRIPTION + + As the last step in decoding the array subscript information for an + array DIE, we need to decode the type of the array elements. We are + passed a pointer to this last part of the subscript information and + must return the appropriate type. If the type attribute is not + recognized, just warn about the problem and return type int. + */ + +static struct type * +decode_array_element_type (scan) + char *scan; +{ + struct type *typep; + DIE_REF die_ref; + unsigned short attribute; + unsigned short fundtype; + int nbytes; + + attribute = target_to_host (scan, SIZEOF_ATTRIBUTE, GET_UNSIGNED, + current_objfile); + scan += SIZEOF_ATTRIBUTE; + if ((nbytes = attribute_size (attribute)) == -1) + { + complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + else + { + switch (attribute) + { + case AT_fund_type: + fundtype = target_to_host (scan, nbytes, GET_UNSIGNED, + current_objfile); + typep = decode_fund_type (fundtype); + break; + case AT_mod_fund_type: + typep = decode_mod_fund_type (scan); + break; + case AT_user_def_type: + die_ref = target_to_host (scan, nbytes, GET_UNSIGNED, + current_objfile); + if ((typep = lookup_utype (die_ref)) == NULL) + { + typep = alloc_utype (die_ref, NULL); + } + break; + case AT_mod_u_d_type: + typep = decode_mod_u_d_type (scan); + break; + default: + complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + } + } + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_subscript_data_item -- decode array subscript item + +SYNOPSIS + + static struct type * + decode_subscript_data_item (char *scan, char *end) + +DESCRIPTION + + The array subscripts and the data type of the elements of an + array are described by a list of data items, stored as a block + of contiguous bytes. There is a data item describing each array + dimension, and a final data item describing the element type. + The data items are ordered the same as their appearance in the + source (I.E. leftmost dimension first, next to leftmost second, + etc). + + The data items describing each array dimension consist of four + parts: (1) a format specifier, (2) type type of the subscript + index, (3) a description of the low bound of the array dimension, + and (4) a description of the high bound of the array dimension. + + The last data item is the description of the type of each of + the array elements. + + We are passed a pointer to the start of the block of bytes + containing the remaining data items, and a pointer to the first + byte past the data. This function recursively decodes the + remaining data items and returns a type. + + If we somehow fail to decode some data, we complain about it + and return a type "array of int". + +BUGS + FIXME: This code only implements the forms currently used + by the AT&T and GNU C compilers. + + The end pointer is supplied for error checking, maybe we should + use it for that... + */ + +static struct type * +decode_subscript_data_item (scan, end) + char *scan; + char *end; +{ + struct type *typep = NULL; /* Array type we are building */ + struct type *nexttype; /* Type of each element (may be array) */ + struct type *indextype; /* Type of this index */ + struct type *rangetype; + unsigned int format; + unsigned short fundtype; + unsigned long lowbound; + unsigned long highbound; + int nbytes; + + format = target_to_host (scan, SIZEOF_FORMAT_SPECIFIER, GET_UNSIGNED, + current_objfile); + scan += SIZEOF_FORMAT_SPECIFIER; + switch (format) + { + case FMT_ET: + typep = decode_array_element_type (scan); + break; + case FMT_FT_C_C: + fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED, + current_objfile); + indextype = decode_fund_type (fundtype); + scan += SIZEOF_FMT_FT; + nbytes = TARGET_FT_LONG_SIZE (current_objfile); + lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile); + scan += nbytes; + highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile); + scan += nbytes; + nexttype = decode_subscript_data_item (scan, end); + if (nexttype == NULL) + { + /* Munged subscript data or other problem, fake it. */ + complain (&subscript_data_items, DIE_ID, DIE_NAME); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + } + rangetype = create_range_type ((struct type *) NULL, indextype, + lowbound, highbound); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + case FMT_FT_C_X: + case FMT_FT_X_C: + case FMT_FT_X_X: + case FMT_UT_C_C: + case FMT_UT_C_X: + case FMT_UT_X_C: + case FMT_UT_X_X: + complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + default: + complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format); + nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0); + typep = create_array_type ((struct type *) NULL, nexttype, rangetype); + break; + } + return (typep); +} + +/* + +LOCAL FUNCTION + + dwarf_read_array_type -- read TAG_array_type DIE + +SYNOPSIS + + static void dwarf_read_array_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a TAG_array_type DIE and add to + the user defined type vector. + */ + +static void +dwarf_read_array_type (dip) + struct dieinfo *dip; +{ + struct type *type; + struct type *utype; + char *sub; + char *subend; + unsigned short blocksz; + int nbytes; + + if (dip -> at_ordering != ORD_row_major) + { + /* FIXME: Can gdb even handle column major arrays? */ + complain (¬_row_major, DIE_ID, DIE_NAME); + } + if ((sub = dip -> at_subscr_data) != NULL) + { + nbytes = attribute_size (AT_subscr_data); + blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile); + subend = sub + nbytes + blocksz; + sub += nbytes; + type = decode_subscript_data_item (sub, subend); + if ((utype = lookup_utype (dip -> die_ref)) == NULL) + { + /* Install user defined type that has not been referenced yet. */ + alloc_utype (dip -> die_ref, type); + } + else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF) + { + /* Ick! A forward ref has already generated a blank type in our + slot, and this type probably already has things pointing to it + (which is what caused it to be created in the first place). + If it's just a place holder we can plop our fully defined type + on top of it. We can't recover the space allocated for our + new type since it might be on an obstack, but we could reuse + it if we kept a list of them, but it might not be worth it + (FIXME). */ + *utype = *type; + } + else + { + /* Double ick! Not only is a type already in our slot, but + someone has decorated it. Complain and leave it alone. */ + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + } + } +} + +/* + +LOCAL FUNCTION + + read_tag_pointer_type -- read TAG_pointer_type DIE + +SYNOPSIS + + static void read_tag_pointer_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a TAG_pointer_type DIE and add to + the user defined type vector. + */ + +static void +read_tag_pointer_type (dip) + struct dieinfo *dip; +{ + struct type *type; + struct type *utype; + + type = decode_die_type (dip); + if ((utype = lookup_utype (dip -> die_ref)) == NULL) + { + utype = lookup_pointer_type (type); + alloc_utype (dip -> die_ref, utype); + } + else + { + TYPE_TARGET_TYPE (utype) = type; + TYPE_POINTER_TYPE (type) = utype; + + /* We assume the machine has only one representation for pointers! */ + /* FIXME: This confuses host<->target data representations, and is a + poor assumption besides. */ + + TYPE_LENGTH (utype) = sizeof (char *); + TYPE_CODE (utype) = TYPE_CODE_PTR; + } +} + +/* + +LOCAL FUNCTION + + read_tag_string_type -- read TAG_string_type DIE + +SYNOPSIS + + static void read_tag_string_type (struct dieinfo *dip) + +DESCRIPTION + + Extract all information from a 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 attribute to reference it. + */ + +static void +read_tag_string_type (dip) + struct dieinfo *dip; +{ + struct type *utype; + struct type *indextype; + struct type *rangetype; + unsigned long lowbound = 0; + unsigned long highbound; + + if (dip -> has_at_byte_size) + { + /* A fixed bounds string */ + highbound = dip -> at_byte_size - 1; + } + else + { + /* A varying length string. Stub for now. (FIXME) */ + highbound = 1; + } + indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER); + rangetype = create_range_type ((struct type *) NULL, indextype, lowbound, + highbound); + + utype = lookup_utype (dip -> die_ref); + if (utype == NULL) + { + /* No type defined, go ahead and create a blank one to use. */ + utype = alloc_utype (dip -> die_ref, (struct type *) NULL); + } + else + { + /* Already a type in our slot due to a forward reference. Make sure it + is a blank one. If not, complain and leave it alone. */ + if (TYPE_CODE (utype) != TYPE_CODE_UNDEF) + { + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + return; + } + } + + /* Create the string type using the blank type we either found or created. */ + utype = create_string_type (utype, rangetype); +} + +/* + +LOCAL FUNCTION + + read_subroutine_type -- process TAG_subroutine_type dies + +SYNOPSIS + + static void read_subroutine_type (struct dieinfo *dip, char thisdie, + char *enddie) + +DESCRIPTION + + Handle DIES due to C code like: + + struct foo { + int (*funcp)(int a, long l); (Generates TAG_subroutine_type DIE) + int b; + }; + +NOTES + + The parameter DIES are currently ignored. See if gdb has a way to + include this info in it's type system, and decode them if so. Is + this what the type structure's "arg_types" field is for? (FIXME) + */ + +static void +read_subroutine_type (dip, thisdie, enddie) + struct dieinfo *dip; + char *thisdie; + char *enddie; +{ + struct type *type; /* Type that this function returns */ + struct type *ftype; /* Function that returns above type */ + + /* Decode the type that this subroutine returns */ + + type = decode_die_type (dip); + + /* Check to see if we already have a partially constructed user + defined type for this DIE, from a forward reference. */ + + if ((ftype = lookup_utype (dip -> die_ref)) == NULL) + { + /* This is the first reference to one of these types. Make + a new one and place it in the user defined types. */ + ftype = lookup_function_type (type); + alloc_utype (dip -> die_ref, ftype); + } + else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF) + { + /* We have an existing partially constructed type, so bash it + into the correct type. */ + TYPE_TARGET_TYPE (ftype) = type; + TYPE_LENGTH (ftype) = 1; + TYPE_CODE (ftype) = TYPE_CODE_FUNC; + } + else + { + complain (&dup_user_type_definition, DIE_ID, DIE_NAME); + } +} + +/* + +LOCAL FUNCTION + + read_enumeration -- process dies which define an enumeration + +SYNOPSIS + + static void read_enumeration (struct dieinfo *dip, char *thisdie, + char *enddie, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a die which begins an enumeration, process all + the dies that define the members of the enumeration. + +NOTES + + Note that we need to call enum_type regardless of whether or not we + have a symbol, since we might have an enum without a tag name (thus + no symbol for the tagname). + */ + +static void +read_enumeration (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct type *type; + struct symbol *sym; + + type = enum_type (dip, objfile); + sym = new_symbol (dip, objfile); + if (sym != NULL) + { + SYMBOL_TYPE (sym) = type; + if (cu_language == language_cplus) + { + synthesize_typedef (dip, objfile, type); + } + } +} + +/* + +LOCAL FUNCTION + + enum_type -- decode and return a type for an enumeration + +SYNOPSIS + + static type *enum_type (struct dieinfo *dip, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a die information structure for the die which + starts an enumeration, process all the dies that define the members + of the enumeration and return a type pointer for the enumeration. + + At the same time, for each member of the enumeration, create a + symbol for it with namespace VAR_NAMESPACE and class LOC_CONST, + and give it the type of the enumeration itself. + +NOTES + + Note that the DWARF specification explicitly mandates that enum + constants occur in reverse order from the source program order, + for "consistency" and because this ordering is easier for many + compilers to generate. (Draft 6, sec 3.8.5, Enumeration type + Entries). Because gdb wants to see the enum members in program + source order, we have to ensure that the order gets reversed while + we are processing them. + */ + +static struct type * +enum_type (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + struct type *type; + struct nextfield { + struct nextfield *next; + struct field field; + }; + struct nextfield *list = NULL; + struct nextfield *new; + int nfields = 0; + int n; + char *scan; + char *listend; + unsigned short blocksz; + struct symbol *sym; + int nbytes; + int unsigned_enum = 1; + + if ((type = lookup_utype (dip -> die_ref)) == NULL) + { + /* No forward references created an empty type, so install one now */ + type = alloc_utype (dip -> die_ref, NULL); + } + TYPE_CODE (type) = TYPE_CODE_ENUM; + /* Some compilers try to be helpful by inventing "fake" names for + anonymous enums, structures, and unions, like "~0fake" or ".0fake". + Thanks, but no thanks... */ + if (dip -> at_name != NULL + && *dip -> at_name != '~' + && *dip -> at_name != '.') + { + TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack, + "", "", dip -> at_name); + } + if (dip -> at_byte_size != 0) + { + TYPE_LENGTH (type) = dip -> at_byte_size; + } + if ((scan = dip -> at_element_list) != NULL) + { + if (dip -> short_element_list) + { + nbytes = attribute_size (AT_short_element_list); + } + else + { + nbytes = attribute_size (AT_element_list); + } + blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile); + listend = scan + nbytes + blocksz; + scan += nbytes; + while (scan < listend) + { + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new -> next = list; + list = new; + list -> field.type = NULL; + list -> field.bitsize = 0; + list -> field.bitpos = + target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED, + objfile); + scan += TARGET_FT_LONG_SIZE (objfile); + list -> field.name = obsavestring (scan, strlen (scan), + &objfile -> type_obstack); + scan += strlen (scan) + 1; + nfields++; + /* Handcraft a new symbol for this enum member. */ + sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (list -> field.name, + &objfile->symbol_obstack); + SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = type; + SYMBOL_VALUE (sym) = list -> field.bitpos; + if (SYMBOL_VALUE (sym) < 0) + unsigned_enum = 0; + add_symbol_to_list (sym, list_in_scope); + } + /* Now create the vector of fields, and record how big it is. This is + where we reverse the order, by pulling the members off the list in + reverse order from how they were inserted. If we have no fields + (this is apparently possible in C++) then skip building a field + vector. */ + if (nfields > 0) + { + if (unsigned_enum) + TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED; + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields); + /* Copy the saved-up fields into the field vector. */ + for (n = 0; (n < nfields) && (list != NULL); list = list -> next) + { + TYPE_FIELD (type, n++) = list -> field; + } + } + } + return (type); +} + +/* + +LOCAL FUNCTION + + read_func_scope -- process all dies within a function scope + +DESCRIPTION + + Process all dies within a given function scope. We are passed + a die information structure pointer DIP for the die which + starts the function scope, and pointers into the raw die data + that define the dies within the function scope. + + For now, we ignore lexical block scopes within the function. + The problem is that AT&T cc does not define a DWARF lexical + block scope for the function itself, while gcc defines a + lexical block scope for the function. We need to think about + how to handle this difference, or if it is even a problem. + (FIXME) + */ + +static void +read_func_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + register struct context_stack *new; + + /* AT_name is absent if the function is described with an + AT_abstract_origin tag. + Ignore the function description for now to avoid GDB core dumps. + FIXME: Add code to handle AT_abstract_origin tags properly. */ + if (dip -> at_name == NULL) + { + complain (&missing_at_name, DIE_ID); + return; + } + + if (objfile -> ei.entry_point >= dip -> at_low_pc && + objfile -> ei.entry_point < dip -> at_high_pc) + { + objfile -> ei.entry_func_lowpc = dip -> at_low_pc; + objfile -> ei.entry_func_highpc = dip -> at_high_pc; + } + if (STREQ (dip -> at_name, "main")) /* FIXME: hardwired name */ + { + objfile -> ei.main_func_lowpc = dip -> at_low_pc; + objfile -> ei.main_func_highpc = dip -> at_high_pc; + } + new = push_context (0, dip -> at_low_pc); + new -> name = new_symbol (dip, objfile); + list_in_scope = &local_symbols; + process_dies (thisdie + dip -> die_length, enddie, objfile); + new = pop_context (); + /* Make a block for the local symbols within. */ + finish_block (new -> name, &local_symbols, new -> old_blocks, + new -> start_addr, dip -> at_high_pc, objfile); + list_in_scope = &file_symbols; +} + + +/* + +LOCAL FUNCTION + + handle_producer -- process the AT_producer attribute + +DESCRIPTION + + Perform any operations that depend on finding a particular + AT_producer attribute. + + */ + +static void +handle_producer (producer) + char *producer; +{ + + /* If this compilation unit was compiled with g++ or gcc, then set the + processing_gcc_compilation flag. */ + + processing_gcc_compilation = + STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)) + || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER)) + || STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER)); + + /* Select a demangling style if we can identify the producer and if + the current style is auto. We leave the current style alone if it + is not auto. We also leave the demangling style alone if we find a + gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */ + + if (AUTO_DEMANGLING) + { + if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER))) + { + set_demangling_style (LUCID_DEMANGLING_STYLE_STRING); + } + } +} + + +/* + +LOCAL FUNCTION + + read_file_scope -- process all dies within a file scope + +DESCRIPTION + + Process all dies within a given file scope. We are passed a + pointer to the die information structure for the die which + starts the file scope, and pointers into the raw die data which + mark the range of dies within the file scope. + + When the partial symbol table is built, the file offset for the line + number table for each compilation unit is saved in the partial symbol + table entry for that compilation unit. As the symbols for each + compilation unit are read, the line number table is read into memory + and the variable lnbase is set to point to it. Thus all we have to + do is use lnbase to access the line number table for the current + compilation unit. + */ + +static void +read_file_scope (dip, thisdie, enddie, objfile) + struct dieinfo *dip; + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + struct cleanup *back_to; + struct symtab *symtab; + + if (objfile -> ei.entry_point >= dip -> at_low_pc && + objfile -> ei.entry_point < dip -> at_high_pc) + { + objfile -> ei.entry_file_lowpc = dip -> at_low_pc; + objfile -> ei.entry_file_highpc = dip -> at_high_pc; + } + set_cu_language (dip); + if (dip -> at_producer != NULL) + { + handle_producer (dip -> at_producer); + } + numutypes = (enddie - thisdie) / 4; + utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *)); + back_to = make_cleanup (free_utypes, NULL); + memset (utypes, 0, numutypes * sizeof (struct type *)); + memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *)); + start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc); + decode_line_numbers (lnbase); + process_dies (thisdie + dip -> die_length, enddie, objfile); + + symtab = end_symtab (dip -> at_high_pc, objfile, 0); + if (symtab != NULL) + { + symtab -> language = cu_language; + } + do_cleanups (back_to); +} + +/* + +LOCAL FUNCTION + + process_dies -- process a range of DWARF Information Entries + +SYNOPSIS + + static void process_dies (char *thisdie, char *enddie, + struct objfile *objfile) + +DESCRIPTION + + Process all DIE's in a specified range. May be (and almost + certainly will be) called recursively. + */ + +static void +process_dies (thisdie, enddie, objfile) + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + char *nextdie; + struct dieinfo di; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else if (di.die_tag == TAG_padding) + { + nextdie = thisdie + di.die_length; + } + else + { + completedieinfo (&di, objfile); + if (di.at_sibling != 0) + { + nextdie = dbbase + di.at_sibling - dbroff; + } + else + { + nextdie = thisdie + di.die_length; + } +#ifdef SMASH_TEXT_ADDRESS + /* I think that these are always text, not data, addresses. */ + SMASH_TEXT_ADDRESS (di.at_low_pc); + SMASH_TEXT_ADDRESS (di.at_high_pc); +#endif + switch (di.die_tag) + { + case TAG_compile_unit: + /* Skip Tag_compile_unit if we are already inside a compilation + unit, we are unable to handle nested compilation units + properly (FIXME). */ + if (current_subfile == NULL) + read_file_scope (&di, thisdie, nextdie, objfile); + else + nextdie = thisdie + di.die_length; + break; + case TAG_global_subroutine: + case TAG_subroutine: + if (di.has_at_low_pc) + { + read_func_scope (&di, thisdie, nextdie, objfile); + } + break; + case TAG_lexical_block: + read_lexical_block_scope (&di, thisdie, nextdie, objfile); + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + read_structure_scope (&di, thisdie, nextdie, objfile); + break; + case TAG_enumeration_type: + read_enumeration (&di, thisdie, nextdie, objfile); + break; + case TAG_subroutine_type: + read_subroutine_type (&di, thisdie, nextdie); + break; + case TAG_array_type: + dwarf_read_array_type (&di); + break; + case TAG_pointer_type: + read_tag_pointer_type (&di); + break; + case TAG_string_type: + read_tag_string_type (&di); + break; + default: + new_symbol (&di, objfile); + break; + } + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + decode_line_numbers -- decode a line number table fragment + +SYNOPSIS + + static void decode_line_numbers (char *tblscan, char *tblend, + long length, long base, long line, long pc) + +DESCRIPTION + + Translate the DWARF line number information to gdb form. + + The ".line" section contains one or more line number tables, one for + each ".line" section from the objects that were linked. + + The AT_stmt_list attribute for each TAG_source_file entry in the + ".debug" section contains the offset into the ".line" section for the + start of the table for that file. + + The table itself has the following structure: + +

+ 4 bytes 4 bytes 10 bytes + + The table length is the total size of the table, including the 4 bytes + for the length information. + + The base address is the address of the first instruction generated + for the source file. + + Each source statement entry has the following structure: + +
+ 4 bytes 2 bytes 4 bytes + + The line number is relative to the start of the file, starting with + line 1. + + The statement position either -1 (0xFFFF) or the number of characters + from the beginning of the line to the beginning of the statement. + + The address delta is the difference between the base address and + the address of the first instruction for the statement. + + Note that we must copy the bytes from the packed table to our local + variables before attempting to use them, to avoid alignment problems + on some machines, particularly RISC processors. + +BUGS + + Does gdb expect the line numbers to be sorted? They are now by + chance/luck, but are not required to be. (FIXME) + + The line with number 0 is unused, gdb apparently can discover the + span of the last line some other way. How? (FIXME) + */ + +static void +decode_line_numbers (linetable) + char *linetable; +{ + char *tblscan; + char *tblend; + unsigned long length; + unsigned long base; + unsigned long line; + unsigned long pc; + + if (linetable != NULL) + { + tblscan = tblend = linetable; + length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_LENGTH; + tblend += length; + base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile), + GET_UNSIGNED, current_objfile); + tblscan += TARGET_FT_POINTER_SIZE (objfile); + base += baseaddr; + while (tblscan < tblend) + { + line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT; + pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED, + current_objfile); + tblscan += SIZEOF_LINETBL_DELTA; + pc += base; + if (line != 0) + { + record_line (current_subfile, line, pc); + } + } + } +} + +/* + +LOCAL FUNCTION + + locval -- compute the value of a location attribute + +SYNOPSIS + + static int locval (char *loc) + +DESCRIPTION + + Given pointer to a string of bytes that define a location, compute + the location and return the value. + A location description containing no atoms indicates that the + object is optimized out. The global optimized_out flag is set for + those, the return value is meaningless. + + When computing values involving the current value of the frame pointer, + the value zero is used, which results in a value relative to the frame + pointer, rather than the absolute value. This is what GDB wants + anyway. + + When the result is a register number, the global isreg flag is set, + otherwise it is cleared. This is a kludge until we figure out a better + way to handle the problem. Gdb's design does not mesh well with the + DWARF notion of a location computing interpreter, which is a shame + because the flexibility goes unused. + +NOTES + + Note that stack[0] is unused except as a default error return. + Note that stack overflow is not yet handled. + */ + +static int +locval (loc) + char *loc; +{ + unsigned short nbytes; + unsigned short locsize; + auto long stack[64]; + int stacki; + char *end; + int loc_atom_code; + int loc_value_size; + + nbytes = attribute_size (AT_location); + locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile); + loc += nbytes; + end = loc + locsize; + stacki = 0; + stack[stacki] = 0; + isreg = 0; + offreg = 0; + optimized_out = 1; + loc_value_size = TARGET_FT_LONG_SIZE (current_objfile); + while (loc < end) + { + optimized_out = 0; + loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED, + current_objfile); + loc += SIZEOF_LOC_ATOM_CODE; + switch (loc_atom_code) + { + case 0: + /* error */ + loc = end; + break; + case OP_REG: + /* push register (number) */ + stack[++stacki] + = DWARF_REG_TO_REGNUM (target_to_host (loc, loc_value_size, + GET_UNSIGNED, + current_objfile)); + loc += loc_value_size; + isreg = 1; + break; + case OP_BASEREG: + /* push value of register (number) */ + /* Actually, we compute the value as if register has 0, so the + value ends up being the offset from that register. */ + offreg = 1; + basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED, + current_objfile); + loc += loc_value_size; + stack[++stacki] = 0; + break; + case OP_ADDR: + /* push address (relocated address) */ + stack[++stacki] = target_to_host (loc, loc_value_size, + GET_UNSIGNED, current_objfile); + loc += loc_value_size; + break; + case OP_CONST: + /* push constant (number) FIXME: signed or unsigned! */ + stack[++stacki] = target_to_host (loc, loc_value_size, + GET_SIGNED, current_objfile); + loc += loc_value_size; + break; + case OP_DEREF2: + /* pop, deref and push 2 bytes (as a long) */ + complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]); + break; + case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */ + complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]); + break; + case OP_ADD: /* pop top 2 items, add, push result */ + stack[stacki - 1] += stack[stacki]; + stacki--; + break; + } + } + return (stack[stacki]); +} + +/* + +LOCAL FUNCTION + + read_ofile_symtab -- build a full symtab entry from chunk of DIE's + +SYNOPSIS + + static void read_ofile_symtab (struct partial_symtab *pst) + +DESCRIPTION + + When expanding a partial symbol table entry to a full symbol table + entry, this is the function that gets called to read in the symbols + for the compilation unit. A pointer to the newly constructed symtab, + which is now the new first one on the objfile's symtab list, is + stashed in the partial symbol table entry. + */ + +static void +read_ofile_symtab (pst) + struct partial_symtab *pst; +{ + struct cleanup *back_to; + unsigned long lnsize; + file_ptr foffset; + bfd *abfd; + char lnsizedata[SIZEOF_LINETBL_LENGTH]; + + abfd = pst -> objfile -> obfd; + current_objfile = pst -> objfile; + + /* Allocate a buffer for the entire chunk of DIE's for this compilation + unit, seek to the location in the file, and read in all the DIE's. */ + + diecount = 0; + dbsize = DBLENGTH (pst); + dbbase = xmalloc (dbsize); + dbroff = DBROFF(pst); + foffset = DBFOFF(pst) + dbroff; + base_section_offsets = pst->section_offsets; + baseaddr = ANOFFSET (pst->section_offsets, 0); + if (bfd_seek (abfd, foffset, SEEK_SET) || + (bfd_read (dbbase, dbsize, 1, abfd) != dbsize)) + { + free (dbbase); + error ("can't read DWARF data"); + } + back_to = make_cleanup (free, dbbase); + + /* If there is a line number table associated with this compilation unit + then read the size of this fragment in bytes, from the fragment itself. + Allocate a buffer for the fragment and read it in for future + processing. */ + + lnbase = NULL; + if (LNFOFF (pst)) + { + if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) || + (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) != + sizeof (lnsizedata))) + { + error ("can't read DWARF line number table size"); + } + lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH, + GET_UNSIGNED, pst -> objfile); + lnbase = xmalloc (lnsize); + if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) || + (bfd_read (lnbase, lnsize, 1, abfd) != lnsize)) + { + free (lnbase); + error ("can't read DWARF line numbers"); + } + make_cleanup (free, lnbase); + } + + process_dies (dbbase, dbbase + dbsize, pst -> objfile); + do_cleanups (back_to); + current_objfile = NULL; + pst -> symtab = pst -> objfile -> symtabs; +} + +/* + +LOCAL FUNCTION + + psymtab_to_symtab_1 -- do grunt work for building a full symtab entry + +SYNOPSIS + + static void psymtab_to_symtab_1 (struct partial_symtab *pst) + +DESCRIPTION + + Called once for each partial symbol table entry that needs to be + expanded into a full symbol table entry. + +*/ + +static void +psymtab_to_symtab_1 (pst) + struct partial_symtab *pst; +{ + int i; + struct cleanup *old_chain; + + if (pst != NULL) + { + if (pst->readin) + { + warning ("psymtab for %s already read in. Shouldn't happen.", + pst -> filename); + } + else + { + /* Read in all partial symtabs on which this one is dependent */ + 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) + { + fputs_filtered (" ", gdb_stdout); + wrap_here (""); + fputs_filtered ("and ", gdb_stdout); + wrap_here (""); + printf_filtered ("%s...", + pst -> dependencies[i] -> filename); + wrap_here (""); + gdb_flush (gdb_stdout); /* Flush output */ + } + psymtab_to_symtab_1 (pst -> dependencies[i]); + } + } + if (DBLENGTH (pst)) /* Otherwise it's a dummy */ + { + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + read_ofile_symtab (pst); + if (info_verbose) + { + printf_filtered ("%d DIE's, sorting...", diecount); + wrap_here (""); + gdb_flush (gdb_stdout); + } + sort_symtab_syms (pst -> symtab); + do_cleanups (old_chain); + } + pst -> readin = 1; + } + } +} + +/* + +LOCAL FUNCTION + + dwarf_psymtab_to_symtab -- build a full symtab entry from partial one + +SYNOPSIS + + static void dwarf_psymtab_to_symtab (struct partial_symtab *pst) + +DESCRIPTION + + This is the DWARF support entry point for building a full symbol + table entry from a partial symbol table entry. We are passed a + pointer to the partial symbol table entry that needs to be expanded. + +*/ + +static void +dwarf_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + + if (pst != NULL) + { + if (pst -> readin) + { + warning ("psymtab for %s already read in. Shouldn't happen.", + pst -> filename); + } + else + { + if (DBLENGTH (pst) || pst -> number_of_dependencies) + { + /* Print the message now, before starting serious work, to avoid + disconcerting pauses. */ + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", + pst -> filename); + gdb_flush (gdb_stdout); + } + + psymtab_to_symtab_1 (pst); + +#if 0 /* FIXME: Check to see what dbxread is doing here and see if + we need to do an equivalent or is this something peculiar to + stabs/a.out format. + 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); +#endif + + /* Finish up the verbose info message. */ + if (info_verbose) + { + printf_filtered ("done.\n"); + gdb_flush (gdb_stdout); + } + } + } + } +} + +/* + +LOCAL FUNCTION + + add_enum_psymbol -- add enumeration members to partial symbol table + +DESCRIPTION + + Given pointer to a DIE that is known to be for an enumeration, + extract the symbolic names of the enumeration members and add + partial symbols for them. +*/ + +static void +add_enum_psymbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + char *scan; + char *listend; + unsigned short blocksz; + int nbytes; + + if ((scan = dip -> at_element_list) != NULL) + { + if (dip -> short_element_list) + { + nbytes = attribute_size (AT_short_element_list); + } + else + { + nbytes = attribute_size (AT_element_list); + } + blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile); + scan += nbytes; + listend = scan + blocksz; + while (scan < listend) + { + scan += TARGET_FT_LONG_SIZE (objfile); + add_psymbol_to_list (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST, + &objfile -> static_psymbols, 0, 0, cu_language, + objfile); + scan += strlen (scan) + 1; + } + } +} + +/* + +LOCAL FUNCTION + + add_partial_symbol -- add symbol to partial symbol table + +DESCRIPTION + + Given a DIE, if it is one of the types that we want to + add to a partial symbol table, finish filling in the die info + and then add a partial symbol table entry for it. + +NOTES + + The caller must ensure that the DIE has a valid name attribute. +*/ + +static void +add_partial_symbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + switch (dip -> die_tag) + { + case TAG_global_subroutine: + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_BLOCK, + &objfile -> global_psymbols, + 0, dip -> at_low_pc, cu_language, objfile); + break; + case TAG_global_variable: + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_STATIC, + &objfile -> global_psymbols, + 0, 0, cu_language, objfile); + break; + case TAG_subroutine: + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_BLOCK, + &objfile -> static_psymbols, + 0, dip -> at_low_pc, cu_language, objfile); + break; + case TAG_local_variable: + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_STATIC, + &objfile -> static_psymbols, + 0, 0, cu_language, objfile); + break; + case TAG_typedef: + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile -> static_psymbols, + 0, 0, cu_language, objfile); + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + case TAG_enumeration_type: + /* Do not add opaque aggregate definitions to the psymtab. */ + if (!dip -> has_at_byte_size) + break; + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + STRUCT_NAMESPACE, LOC_TYPEDEF, + &objfile -> static_psymbols, + 0, 0, cu_language, objfile); + if (cu_language == language_cplus) + { + /* For C++, these implicitly act as typedefs as well. */ + add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name), + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile -> static_psymbols, + 0, 0, cu_language, objfile); + } + break; + } +} + +/* + +LOCAL FUNCTION + + scan_partial_symbols -- scan DIE's within a single compilation unit + +DESCRIPTION + + Process the DIE's within a single compilation unit, looking for + interesting DIE's that contribute to the partial symbol table entry + for this compilation unit. + +NOTES + + There are some DIE's that may appear both at file scope and within + the scope of a function. We are only interested in the ones at file + scope, and the only way to tell them apart is to keep track of the + scope. For example, consider the test case: + + static int i; + main () { int j; } + + for which the relevant DWARF segment has the structure: + + 0x51: + 0x23 global subrtn sibling 0x9b + name main + fund_type FT_integer + low_pc 0x800004cc + high_pc 0x800004d4 + + 0x74: + 0x23 local var sibling 0x97 + name j + fund_type FT_integer + location OP_BASEREG 0xe + OP_CONST 0xfffffffc + OP_ADD + 0x97: + 0x4 + + 0x9b: + 0x1d local var sibling 0xb8 + name i + fund_type FT_integer + location OP_ADDR 0x800025dc + + 0xb8: + 0x4 + + We want to include the symbol 'i' in the partial symbol table, but + not the symbol 'j'. In essence, we want to skip all the dies within + the scope of a TAG_global_subroutine DIE. + + Don't attempt to add anonymous structures or unions since they have + no name. Anonymous enumerations however are processed, because we + want to extract their member names (the check for a tag name is + done later). + + Also, for variables and subroutines, check that this is the place + where the actual definition occurs, rather than just a reference + to an external. + */ + +static void +scan_partial_symbols (thisdie, enddie, objfile) + char *thisdie; + char *enddie; + struct objfile *objfile; +{ + char *nextdie; + char *temp; + struct dieinfo di; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else + { + nextdie = thisdie + di.die_length; + /* To avoid getting complete die information for every die, we + only do it (below) for the cases we are interested in. */ + switch (di.die_tag) + { + case TAG_global_subroutine: + case TAG_subroutine: + completedieinfo (&di, objfile); + if (di.at_name && (di.has_at_low_pc || di.at_location)) + { + add_partial_symbol (&di, objfile); + /* If there is a sibling attribute, adjust the nextdie + pointer to skip the entire scope of the subroutine. + Apply some sanity checking to make sure we don't + overrun or underrun the range of remaining DIE's */ + if (di.at_sibling != 0) + { + temp = dbbase + di.at_sibling - dbroff; + if ((temp < thisdie) || (temp >= enddie)) + { + complain (&bad_die_ref, DIE_ID, DIE_NAME, + di.at_sibling); + } + else + { + nextdie = temp; + } + } + } + break; + case TAG_global_variable: + case TAG_local_variable: + completedieinfo (&di, objfile); + if (di.at_name && (di.has_at_low_pc || di.at_location)) + { + add_partial_symbol (&di, objfile); + } + break; + case TAG_typedef: + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + completedieinfo (&di, objfile); + if (di.at_name) + { + add_partial_symbol (&di, objfile); + } + break; + case TAG_enumeration_type: + completedieinfo (&di, objfile); + if (di.at_name) + { + add_partial_symbol (&di, objfile); + } + add_enum_psymbol (&di, objfile); + break; + } + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + scan_compilation_units -- build a psymtab entry for each compilation + +DESCRIPTION + + This is the top level dwarf parsing routine for building partial + symbol tables. + + It scans from the beginning of the DWARF table looking for the first + TAG_compile_unit DIE, and then follows the sibling chain to locate + each additional TAG_compile_unit DIE. + + For each TAG_compile_unit DIE it creates a partial symtab structure, + calls a subordinate routine to collect all the compilation unit's + global DIE's, file scope DIEs, typedef DIEs, etc, and then links the + new partial symtab structure into the partial symbol table. It also + records the appropriate information in the partial symbol table entry + to allow the chunk of DIE's and line number table for this compilation + unit to be located and re-read later, to generate a complete symbol + table entry for the compilation unit. + + Thus it effectively partitions up a chunk of DIE's for multiple + compilation units into smaller DIE chunks and line number tables, + and associates them with a partial symbol table entry. + +NOTES + + If any compilation unit has no line number table associated with + it for some reason (a missing at_stmt_list attribute, rather than + just one with a value of zero, which is valid) then we ensure that + the recorded file offset is zero so that the routine which later + reads line number table fragments knows that there is no fragment + to read. + +RETURNS + + Returns no value. + + */ + +static void +scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile) + char *thisdie; + char *enddie; + file_ptr dbfoff; + file_ptr lnoffset; + struct objfile *objfile; +{ + char *nextdie; + struct dieinfo di; + struct partial_symtab *pst; + int culength; + int curoff; + file_ptr curlnoffset; + + while (thisdie < enddie) + { + basicdieinfo (&di, thisdie, objfile); + if (di.die_length < SIZEOF_DIE_LENGTH) + { + break; + } + else if (di.die_tag != TAG_compile_unit) + { + nextdie = thisdie + di.die_length; + } + else + { + completedieinfo (&di, objfile); + set_cu_language (&di); + if (di.at_sibling != 0) + { + nextdie = dbbase + di.at_sibling - dbroff; + } + else + { + nextdie = thisdie + di.die_length; + } + curoff = thisdie - dbbase; + culength = nextdie - thisdie; + curlnoffset = di.has_at_stmt_list ? lnoffset + di.at_stmt_list : 0; + + /* First allocate a new partial symbol table structure */ + + pst = start_psymtab_common (objfile, base_section_offsets, + di.at_name, di.at_low_pc, + objfile -> global_psymbols.next, + objfile -> static_psymbols.next); + + pst -> texthigh = di.at_high_pc; + pst -> read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct dwfinfo)); + DBFOFF (pst) = dbfoff; + DBROFF (pst) = curoff; + DBLENGTH (pst) = culength; + LNFOFF (pst) = curlnoffset; + pst -> read_symtab = dwarf_psymtab_to_symtab; + + /* Now look for partial symbols */ + + scan_partial_symbols (thisdie + di.die_length, nextdie, objfile); + + 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); + /* If there is already a psymtab or symtab for a file of this name, + remove it. (If there is a symtab, more drastic things also + happen.) This happens in VxWorks. */ + free_named_symtabs (pst -> filename); + } + thisdie = nextdie; + } +} + +/* + +LOCAL FUNCTION + + new_symbol -- make a symbol table entry for a new symbol + +SYNOPSIS + + static struct symbol *new_symbol (struct dieinfo *dip, + struct objfile *objfile) + +DESCRIPTION + + Given a pointer to a DWARF information entry, figure out if we need + to make a symbol table entry for it, and if so, create a new entry + and return a pointer to it. + */ + +static struct symbol * +new_symbol (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + struct symbol *sym = NULL; + + if (dip -> at_name != NULL) + { + sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack, + sizeof (struct symbol)); + OBJSTAT (objfile, n_syms++); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (dip -> at_name, + &objfile->symbol_obstack); + /* default assumptions */ + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_TYPE (sym) = decode_die_type (dip); + + /* If this symbol is from a C++ compilation, then attempt to cache the + demangled form for future reference. This is a typical time versus + space tradeoff, that was decided in favor of time because it sped up + C++ symbol lookups by a factor of about 20. */ + + SYMBOL_LANGUAGE (sym) = cu_language; + SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack); + switch (dip -> die_tag) + { + case TAG_label: + SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc; + SYMBOL_CLASS (sym) = LOC_LABEL; + break; + case TAG_global_subroutine: + case TAG_subroutine: + SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc; + SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym)); + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (dip -> die_tag == TAG_global_subroutine) + { + add_symbol_to_list (sym, &global_symbols); + } + else + { + add_symbol_to_list (sym, list_in_scope); + } + break; + case TAG_global_variable: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + add_symbol_to_list (sym, &global_symbols); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) += baseaddr; + } + break; + case TAG_local_variable: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + add_symbol_to_list (sym, list_in_scope); + if (optimized_out) + { + SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + } + else if (isreg) + { + SYMBOL_CLASS (sym) = LOC_REGISTER; + } + else if (offreg) + { + SYMBOL_CLASS (sym) = LOC_BASEREG; + SYMBOL_BASEREG (sym) = basereg; + } + else + { + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) += baseaddr; + } + } + break; + case TAG_formal_parameter: + if (dip -> at_location != NULL) + { + SYMBOL_VALUE (sym) = locval (dip -> at_location); + } + add_symbol_to_list (sym, list_in_scope); + if (isreg) + { + SYMBOL_CLASS (sym) = LOC_REGPARM; + } + else if (offreg) + { + SYMBOL_CLASS (sym) = LOC_BASEREG_ARG; + SYMBOL_BASEREG (sym) = basereg; + } + else + { + SYMBOL_CLASS (sym) = LOC_ARG; + } + break; + case TAG_unspecified_parameters: + /* From varargs functions; gdb doesn't seem to have any interest in + this information, so just ignore it for now. (FIXME?) */ + break; + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + case TAG_enumeration_type: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + break; + case TAG_typedef: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + break; + default: + /* Not a tag we recognize. Hopefully we aren't processing trash + data, but since we must specifically ignore things we don't + recognize, there is nothing else we should do at this point. */ + break; + } + } + return (sym); +} + +/* + +LOCAL FUNCTION + + synthesize_typedef -- make a symbol table entry for a "fake" typedef + +SYNOPSIS + + static void synthesize_typedef (struct dieinfo *dip, + struct objfile *objfile, + struct type *type); + +DESCRIPTION + + Given a pointer to a DWARF information entry, synthesize a typedef + for the name in the DIE, using the specified type. + + This is used for C++ class, structs, unions, and enumerations to + set up the tag name as a type. + + */ + +static void +synthesize_typedef (dip, objfile, type) + struct dieinfo *dip; + struct objfile *objfile; + struct type *type; +{ + struct symbol *sym = NULL; + + if (dip -> at_name != NULL) + { + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + OBJSTAT (objfile, n_syms++); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = create_name (dip -> at_name, + &objfile->symbol_obstack); + SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language); + SYMBOL_TYPE (sym) = type; + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, list_in_scope); + } +} + +/* + +LOCAL FUNCTION + + decode_mod_fund_type -- decode a modified fundamental type + +SYNOPSIS + + static struct type *decode_mod_fund_type (char *typedata) + +DESCRIPTION + + Decode a block of data containing a modified fundamental + type specification. TYPEDATA is a pointer to the block, + which starts with a length containing the size of the rest + of the block. At the end of the block is a fundmental type + code value that gives the fundamental type. Everything + in between are type modifiers. + + We simply compute the number of modifiers and call the general + function decode_modified_type to do the actual work. +*/ + +static struct type * +decode_mod_fund_type (typedata) + char *typedata; +{ + struct type *typep = NULL; + unsigned short modcount; + int nbytes; + + /* Get the total size of the block, exclusive of the size itself */ + + nbytes = attribute_size (AT_mod_fund_type); + modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile); + typedata += nbytes; + + /* Deduct the size of the fundamental type bytes at the end of the block. */ + + modcount -= attribute_size (AT_fund_type); + + /* Now do the actual decoding */ + + typep = decode_modified_type (typedata, modcount, AT_mod_fund_type); + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_mod_u_d_type -- decode a modified user defined type + +SYNOPSIS + + static struct type *decode_mod_u_d_type (char *typedata) + +DESCRIPTION + + Decode a block of data containing a modified user defined + type specification. TYPEDATA is a pointer to the block, + which consists of a two byte length, containing the size + of the rest of the block. At the end of the block is a + four byte value that gives a reference to a user defined type. + Everything in between are type modifiers. + + We simply compute the number of modifiers and call the general + function decode_modified_type to do the actual work. +*/ + +static struct type * +decode_mod_u_d_type (typedata) + char *typedata; +{ + struct type *typep = NULL; + unsigned short modcount; + int nbytes; + + /* Get the total size of the block, exclusive of the size itself */ + + nbytes = attribute_size (AT_mod_u_d_type); + modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile); + typedata += nbytes; + + /* Deduct the size of the reference type bytes at the end of the block. */ + + modcount -= attribute_size (AT_user_def_type); + + /* Now do the actual decoding */ + + typep = decode_modified_type (typedata, modcount, AT_mod_u_d_type); + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_modified_type -- decode modified user or fundamental type + +SYNOPSIS + + static struct type *decode_modified_type (char *modifiers, + unsigned short modcount, int mtype) + +DESCRIPTION + + Decode a modified type, either a modified fundamental type or + a modified user defined type. MODIFIERS is a pointer to the + block of bytes that define MODCOUNT modifiers. Immediately + following the last modifier is a short containing the fundamental + type or a long containing the reference to the user defined + type. Which one is determined by MTYPE, which is either + AT_mod_fund_type or AT_mod_u_d_type to indicate what modified + type we are generating. + + We call ourself recursively to generate each modified type,` + until MODCOUNT reaches zero, at which point we have consumed + all the modifiers and generate either the fundamental type or + user defined type. When the recursion unwinds, each modifier + is applied in turn to generate the full modified type. + +NOTES + + If we find a modifier that we don't recognize, and it is not one + of those reserved for application specific use, then we issue a + warning and simply ignore the modifier. + +BUGS + + We currently ignore MOD_const and MOD_volatile. (FIXME) + + */ + +static struct type * +decode_modified_type (modifiers, modcount, mtype) + char *modifiers; + unsigned int modcount; + int mtype; +{ + struct type *typep = NULL; + unsigned short fundtype; + DIE_REF die_ref; + char modifier; + int nbytes; + + if (modcount == 0) + { + switch (mtype) + { + case AT_mod_fund_type: + nbytes = attribute_size (AT_fund_type); + fundtype = target_to_host (modifiers, nbytes, GET_UNSIGNED, + current_objfile); + typep = decode_fund_type (fundtype); + break; + case AT_mod_u_d_type: + nbytes = attribute_size (AT_user_def_type); + die_ref = target_to_host (modifiers, nbytes, GET_UNSIGNED, + current_objfile); + if ((typep = lookup_utype (die_ref)) == NULL) + { + typep = alloc_utype (die_ref, NULL); + } + break; + default: + complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype); + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + } + } + else + { + modifier = *modifiers++; + typep = decode_modified_type (modifiers, --modcount, mtype); + switch (modifier) + { + case MOD_pointer_to: + typep = lookup_pointer_type (typep); + break; + case MOD_reference_to: + typep = lookup_reference_type (typep); + break; + case MOD_const: + complain (&const_ignored, DIE_ID, DIE_NAME); /* FIXME */ + break; + case MOD_volatile: + complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */ + break; + default: + if (!(MOD_lo_user <= (unsigned char) modifier + && (unsigned char) modifier <= MOD_hi_user)) + { + complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier); + } + break; + } + } + return (typep); +} + +/* + +LOCAL FUNCTION + + decode_fund_type -- translate basic DWARF type to gdb base type + +DESCRIPTION + + Given an integer that is one of the fundamental DWARF types, + translate it to one of the basic internal gdb types and return + a pointer to the appropriate gdb type (a "struct type *"). + +NOTES + + For robustness, if we are asked to translate a fundamental + type that we are unprepared to deal with, we return int so + callers can always depend upon a valid type being returned, + and so gdb may at least do something reasonable by default. + If the type is not in the range of those types defined as + application specific types, we also issue a warning. +*/ + +static struct type * +decode_fund_type (fundtype) + unsigned int fundtype; +{ + struct type *typep = NULL; + + switch (fundtype) + { + + case FT_void: + typep = dwarf_fundamental_type (current_objfile, FT_VOID); + break; + + case FT_boolean: /* Was FT_set in AT&T version */ + typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN); + break; + + case FT_pointer: /* (void *) */ + typep = dwarf_fundamental_type (current_objfile, FT_VOID); + typep = lookup_pointer_type (typep); + break; + + case FT_char: + typep = dwarf_fundamental_type (current_objfile, FT_CHAR); + break; + + case FT_signed_char: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR); + break; + + case FT_unsigned_char: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR); + break; + + case FT_short: + typep = dwarf_fundamental_type (current_objfile, FT_SHORT); + break; + + case FT_signed_short: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT); + break; + + case FT_unsigned_short: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT); + break; + + case FT_integer: + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + break; + + case FT_signed_integer: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER); + break; + + case FT_unsigned_integer: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER); + break; + + case FT_long: + typep = dwarf_fundamental_type (current_objfile, FT_LONG); + break; + + case FT_signed_long: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG); + break; + + case FT_unsigned_long: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG); + break; + + case FT_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG); + break; + + case FT_signed_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG); + break; + + case FT_unsigned_long_long: + typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG); + break; + + case FT_float: + typep = dwarf_fundamental_type (current_objfile, FT_FLOAT); + break; + + case FT_dbl_prec_float: + typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT); + break; + + case FT_ext_prec_float: + typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT); + break; + + case FT_complex: + typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX); + break; + + case FT_dbl_prec_complex: + typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX); + break; + + case FT_ext_prec_complex: + typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX); + break; + + } + + if (typep == NULL) + { + typep = dwarf_fundamental_type (current_objfile, FT_INTEGER); + if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user)) + { + complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype); + } + } + + return (typep); +} + +/* + +LOCAL FUNCTION + + create_name -- allocate a fresh copy of a string on an obstack + +DESCRIPTION + + Given a pointer to a string and a pointer to an obstack, allocates + a fresh copy of the string on the specified obstack. + +*/ + +static char * +create_name (name, obstackp) + char *name; + struct obstack *obstackp; +{ + int length; + char *newname; + + length = strlen (name) + 1; + newname = (char *) obstack_alloc (obstackp, length); + strcpy (newname, name); + return (newname); +} + +/* + +LOCAL FUNCTION + + basicdieinfo -- extract the minimal die info from raw die data + +SYNOPSIS + + void basicdieinfo (char *diep, struct dieinfo *dip, + struct objfile *objfile) + +DESCRIPTION + + Given a pointer to raw DIE data, and a pointer to an instance of a + die info structure, this function extracts the basic information + from the DIE data required to continue processing this DIE, along + with some bookkeeping information about the DIE. + + The information we absolutely must have includes the DIE tag, + and the DIE length. If we need the sibling reference, then we + will have to call completedieinfo() to process all the remaining + DIE information. + + Note that since there is no guarantee that the data is properly + aligned in memory for the type of access required (indirection + through anything other than a char pointer), and there is no + guarantee that it is in the same byte order as the gdb host, + we call a function which deals with both alignment and byte + swapping issues. Possibly inefficient, but quite portable. + + We also take care of some other basic things at this point, such + as ensuring that the instance of the die info structure starts + out completely zero'd and that curdie is initialized for use + in error reporting if we have a problem with the current die. + +NOTES + + All DIE's must have at least a valid length, thus the minimum + DIE size is SIZEOF_DIE_LENGTH. In order to have a valid tag, the + DIE size must be at least SIZEOF_DIE_TAG larger, otherwise they + are forced to be TAG_padding DIES. + + Padding DIES must be at least SIZEOF_DIE_LENGTH in length, implying + that if a padding DIE is used for alignment and the amount needed is + less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big + enough to align to the next alignment boundry. + + We do some basic sanity checking here, such as verifying that the + length of the die would not cause it to overrun the recorded end of + the buffer holding the DIE info. If we find a DIE that is either + too small or too large, we force it's length to zero which should + cause the caller to take appropriate action. + */ + +static void +basicdieinfo (dip, diep, objfile) + struct dieinfo *dip; + char *diep; + struct objfile *objfile; +{ + curdie = dip; + memset (dip, 0, sizeof (struct dieinfo)); + dip -> die = diep; + dip -> die_ref = dbroff + (diep - dbbase); + dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED, + objfile); + if ((dip -> die_length < SIZEOF_DIE_LENGTH) || + ((diep + dip -> die_length) > (dbbase + dbsize))) + { + complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length); + dip -> die_length = 0; + } + else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG)) + { + dip -> die_tag = TAG_padding; + } + else + { + diep += SIZEOF_DIE_LENGTH; + dip -> die_tag = target_to_host (diep, SIZEOF_DIE_TAG, GET_UNSIGNED, + objfile); + } +} + +/* + +LOCAL FUNCTION + + completedieinfo -- finish reading the information for a given DIE + +SYNOPSIS + + void completedieinfo (struct dieinfo *dip, struct objfile *objfile) + +DESCRIPTION + + Given a pointer to an already partially initialized die info structure, + scan the raw DIE data and finish filling in the die info structure + from the various attributes found. + + Note that since there is no guarantee that the data is properly + aligned in memory for the type of access required (indirection + through anything other than a char pointer), and there is no + guarantee that it is in the same byte order as the gdb host, + we call a function which deals with both alignment and byte + swapping issues. Possibly inefficient, but quite portable. + +NOTES + + Each time we are called, we increment the diecount variable, which + keeps an approximate count of the number of dies processed for + each compilation unit. This information is presented to the user + if the info_verbose flag is set. + + */ + +static void +completedieinfo (dip, objfile) + struct dieinfo *dip; + struct objfile *objfile; +{ + char *diep; /* Current pointer into raw DIE data */ + char *end; /* Terminate DIE scan here */ + unsigned short attr; /* Current attribute being scanned */ + unsigned short form; /* Form of the attribute */ + int nbytes; /* Size of next field to read */ + + diecount++; + diep = dip -> die; + end = diep + dip -> die_length; + diep += SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG; + while (diep < end) + { + attr = target_to_host (diep, SIZEOF_ATTRIBUTE, GET_UNSIGNED, objfile); + diep += SIZEOF_ATTRIBUTE; + if ((nbytes = attribute_size (attr)) == -1) + { + complain (&unknown_attribute_length, DIE_ID, DIE_NAME); + diep = end; + continue; + } + switch (attr) + { + case AT_fund_type: + dip -> at_fund_type = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_ordering: + dip -> at_ordering = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_bit_offset: + dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_sibling: + dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_stmt_list: + dip -> at_stmt_list = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> has_at_stmt_list = 1; + break; + case AT_low_pc: + dip -> at_low_pc = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> at_low_pc += baseaddr; + dip -> has_at_low_pc = 1; + break; + case AT_high_pc: + dip -> at_high_pc = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> at_high_pc += baseaddr; + break; + case AT_language: + dip -> at_language = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_user_def_type: + dip -> at_user_def_type = target_to_host (diep, nbytes, + GET_UNSIGNED, objfile); + break; + case AT_byte_size: + dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + dip -> has_at_byte_size = 1; + break; + case AT_bit_size: + dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_member: + dip -> at_member = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_discr: + dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_location: + dip -> at_location = diep; + break; + case AT_mod_fund_type: + dip -> at_mod_fund_type = diep; + break; + case AT_subscr_data: + dip -> at_subscr_data = diep; + break; + case AT_mod_u_d_type: + dip -> at_mod_u_d_type = diep; + break; + case AT_element_list: + dip -> at_element_list = diep; + dip -> short_element_list = 0; + break; + case AT_short_element_list: + dip -> at_element_list = diep; + dip -> short_element_list = 1; + break; + case AT_discr_value: + dip -> at_discr_value = diep; + break; + case AT_string_length: + dip -> at_string_length = diep; + break; + case AT_name: + dip -> at_name = diep; + break; + case AT_comp_dir: + /* For now, ignore any "hostname:" portion, since gdb doesn't + know how to deal with it. (FIXME). */ + dip -> at_comp_dir = strrchr (diep, ':'); + if (dip -> at_comp_dir != NULL) + { + dip -> at_comp_dir++; + } + else + { + dip -> at_comp_dir = diep; + } + break; + case AT_producer: + dip -> at_producer = diep; + break; + case AT_start_scope: + dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_stride_size: + dip -> at_stride_size = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_src_info: + dip -> at_src_info = target_to_host (diep, nbytes, GET_UNSIGNED, + objfile); + break; + case AT_prototyped: + dip -> at_prototyped = diep; + break; + default: + /* Found an attribute that we are unprepared to handle. However + it is specifically one of the design goals of DWARF that + consumers should ignore unknown attributes. As long as the + form is one that we recognize (so we know how to skip it), + we can just ignore the unknown attribute. */ + break; + } + form = FORM_FROM_ATTR (attr); + switch (form) + { + case FORM_DATA2: + diep += 2; + break; + case FORM_DATA4: + case FORM_REF: + diep += 4; + break; + case FORM_DATA8: + diep += 8; + break; + case FORM_ADDR: + diep += TARGET_FT_POINTER_SIZE (objfile); + break; + case FORM_BLOCK2: + diep += 2 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile); + break; + case FORM_BLOCK4: + diep += 4 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile); + break; + case FORM_STRING: + diep += strlen (diep) + 1; + break; + default: + complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form); + diep = end; + break; + } + } +} + +/* + +LOCAL FUNCTION + + target_to_host -- swap in target data to host + +SYNOPSIS + + target_to_host (char *from, int nbytes, int signextend, + struct objfile *objfile) + +DESCRIPTION + + Given pointer to data in target format in FROM, a byte count for + the size of the data in NBYTES, a flag indicating whether or not + the data is signed in SIGNEXTEND, and a pointer to the current + objfile in OBJFILE, convert the data to host format and return + the converted value. + +NOTES + + FIXME: If we read data that is known to be signed, and expect to + use it as signed data, then we need to explicitly sign extend the + result until the bfd library is able to do this for us. + + FIXME: Would a 32 bit target ever need an 8 byte result? + + */ + +static CORE_ADDR +target_to_host (from, nbytes, signextend, objfile) + char *from; + int nbytes; + int signextend; /* FIXME: Unused */ + struct objfile *objfile; +{ + CORE_ADDR rtnval; + + switch (nbytes) + { + case 8: + rtnval = bfd_get_64 (objfile -> obfd, (bfd_byte *) from); + break; + case 4: + rtnval = bfd_get_32 (objfile -> obfd, (bfd_byte *) from); + break; + case 2: + rtnval = bfd_get_16 (objfile -> obfd, (bfd_byte *) from); + break; + case 1: + rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from); + break; + default: + complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes); + rtnval = 0; + break; + } + return (rtnval); +} + +/* + +LOCAL FUNCTION + + attribute_size -- compute size of data for a DWARF attribute + +SYNOPSIS + + static int attribute_size (unsigned int attr) + +DESCRIPTION + + Given a DWARF attribute in ATTR, compute the size of the first + piece of data associated with this attribute and return that + size. + + Returns -1 for unrecognized attributes. + + */ + +static int +attribute_size (attr) + unsigned int attr; +{ + int nbytes; /* Size of next data for this attribute */ + unsigned short form; /* Form of the attribute */ + + form = FORM_FROM_ATTR (attr); + switch (form) + { + case FORM_STRING: /* A variable length field is next */ + nbytes = 0; + break; + case FORM_DATA2: /* Next 2 byte field is the data itself */ + case FORM_BLOCK2: /* Next 2 byte field is a block length */ + nbytes = 2; + break; + case FORM_DATA4: /* Next 4 byte field is the data itself */ + case FORM_BLOCK4: /* Next 4 byte field is a block length */ + case FORM_REF: /* Next 4 byte field is a DIE offset */ + nbytes = 4; + break; + case FORM_DATA8: /* Next 8 byte field is the data itself */ + nbytes = 8; + break; + case FORM_ADDR: /* Next field size is target sizeof(void *) */ + nbytes = TARGET_FT_POINTER_SIZE (objfile); + break; + default: + complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form); + nbytes = -1; + break; + } + return (nbytes); +} diff --git a/contrib/gdb/gdb/elfread.c b/contrib/gdb/gdb/elfread.c new file mode 100644 index 000000000000..9a7a0fe3e199 --- /dev/null +++ b/contrib/gdb/gdb/elfread.c @@ -0,0 +1,826 @@ +/* Read ELF (Executable and Linking Format) object files for GDB. + Copyright 1991, 1992, 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "bfd.h" +#include "gdb_string.h" +#include "elf-bfd.h" +#include "elf/mips.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" +#include "complaints.h" +#include "demangle.h" + +/* The struct elfinfo is available only during ELF symbol table and + psymtab reading. It is destroyed at the complation of psymtab-reading. + It's local to elf_symfile_read. */ + +struct elfinfo { + file_ptr dboffset; /* Offset to dwarf debug section */ + unsigned int dbsize; /* Size of dwarf debug section */ + file_ptr lnoffset; /* Offset to dwarf line number section */ + unsigned int lnsize; /* Size of dwarf line number section */ + asection *stabsect; /* Section pointer for .stab section */ + asection *stabindexsect; /* Section pointer for .stab.index section */ + asection *mdebugsect; /* Section pointer for .mdebug section */ +}; + +/* Various things we might complain about... */ + +struct complaint section_info_complaint = + {"elf/stab section information %s without a preceding file symbol", 0, 0}; + +struct complaint section_info_dup_complaint = + {"duplicated elf/stab section information for %s", 0, 0}; + +struct complaint stab_info_mismatch_complaint = + {"elf/stab section information missing for %s", 0, 0}; + +struct complaint stab_info_questionable_complaint = + {"elf/stab section information questionable for %s", 0, 0}; + +static void +elf_symfile_init PARAMS ((struct objfile *)); + +static void +elf_new_init PARAMS ((struct objfile *)); + +static void +elf_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +elf_symfile_finish PARAMS ((struct objfile *)); + +static void +elf_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *, int)); + +static void +free_elfinfo PARAMS ((void *)); + +static struct section_offsets * +elf_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static struct minimal_symbol * +record_minimal_symbol_and_info PARAMS ((char *, CORE_ADDR, + enum minimal_symbol_type, char *, + struct objfile *)); + +static void +elf_locate_sections PARAMS ((bfd *, asection *, void *)); + +/* We are called once per section from elf_symfile_read. We + need to examine each section we are passed, check to see + if it is something we are interested in processing, and + if so, stash away some access information for the section. + + For now we recognize the dwarf debug information sections and + line number sections from matching their section names. The + ELF definition is no real help here since it has no direct + knowledge of DWARF (by design, so any debugging format can be + used). + + We also recognize the ".stab" sections used by the Sun compilers + released with Solaris 2. + + FIXME: The section names should not be hardwired strings (what + should they be? I don't think most object file formats have enough + section flags to specify what kind of debug section it is + -kingdon). */ + +static void +elf_locate_sections (ignore_abfd, sectp, eip) + bfd *ignore_abfd; + asection *sectp; + PTR eip; +{ + register struct elfinfo *ei; + + ei = (struct elfinfo *) eip; + if (STREQ (sectp -> name, ".debug")) + { + ei -> dboffset = sectp -> filepos; + ei -> dbsize = bfd_get_section_size_before_reloc (sectp); + } + else if (STREQ (sectp -> name, ".line")) + { + ei -> lnoffset = sectp -> filepos; + ei -> lnsize = bfd_get_section_size_before_reloc (sectp); + } + else if (STREQ (sectp -> name, ".stab")) + { + ei -> stabsect = sectp; + } + else if (STREQ (sectp -> name, ".stab.index")) + { + ei -> stabindexsect = sectp; + } + else if (STREQ (sectp -> name, ".mdebug")) + { + ei -> mdebugsect = sectp; + } +} + +#if 0 /* Currently unused */ + +char * +elf_interpreter (abfd) + bfd *abfd; +{ + sec_ptr interp_sec; + unsigned size; + char *interp = NULL; + + interp_sec = bfd_get_section_by_name (abfd, ".interp"); + if (interp_sec) + { + size = bfd_section_size (abfd, interp_sec); + interp = alloca (size); + if (bfd_get_section_contents (abfd, interp_sec, interp, (file_ptr)0, + size)) + { + interp = savestring (interp, size - 1); + } + else + { + interp = NULL; + } + } + return (interp); +} + +#endif + +static struct minimal_symbol * +record_minimal_symbol_and_info (name, address, ms_type, info, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + char *info; /* FIXME, is this really char *? */ + struct objfile *objfile; +{ + int section; + + /* Guess the section from the type. This is likely to be wrong in + some cases. */ + switch (ms_type) + { + case mst_text: + case mst_file_text: + section = SECT_OFF_TEXT; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (address); +#endif + break; + case mst_data: + case mst_file_data: + section = SECT_OFF_DATA; + break; + case mst_bss: + case mst_file_bss: + section = SECT_OFF_BSS; + break; + default: + section = -1; + break; + } + + name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); + return prim_record_minimal_symbol_and_info + (name, address, ms_type, info, section, objfile); +} + +/* + +LOCAL FUNCTION + + elf_symtab_read -- read the symbol table of an ELF file + +SYNOPSIS + + void elf_symtab_read (bfd *abfd, CORE_ADDR addr, + struct objfile *objfile, int dynamic) + +DESCRIPTION + + 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. + + In stabs-in-ELF, as implemented by Sun, there are some local symbols + defined in the ELF symbol table, which can be used to locate + the beginnings of sections from each ".o" file that was linked to + form the executable objfile. We gather any such info and record it + in data structures hung off the objfile's private data. + +*/ + +static void +elf_symtab_read (abfd, addr, objfile, dynamic) + bfd *abfd; + CORE_ADDR addr; + struct objfile *objfile; + int dynamic; +{ + long storage_needed; + asymbol *sym; + asymbol **symbol_table; + long number_of_symbols; + long i; + int index; + struct cleanup *back_to; + CORE_ADDR symaddr; + enum minimal_symbol_type ms_type; + /* If sectinfo is nonNULL, it contains section info that should end up + filed in the objfile. */ + struct stab_section_info *sectinfo = NULL; + /* If filesym is nonzero, it points to a file symbol, but we haven't + seen any section info for it yet. */ + asymbol *filesym = 0; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Name of filesym, as saved on the symbol_obstack. */ + char *filesymname = obsavestring ("", 0, &objfile->symbol_obstack); +#endif + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_stab_info; + unsigned long size; + int stripped = (bfd_get_symcount (abfd) == 0); + + if (dynamic) + { + storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd); + + /* Nothing to be done if there is no dynamic symtab. */ + if (storage_needed < 0) + return; + } + else + { + storage_needed = bfd_get_symtab_upper_bound (abfd); + if (storage_needed < 0) + error ("Can't read symbols from %s: %s", bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + } + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, symbol_table); + if (dynamic) + number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, + symbol_table); + else + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + if (number_of_symbols < 0) + error ("Can't read symbols from %s: %s", bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + for (i = 0; i < number_of_symbols; i++) + { + sym = symbol_table[i]; + if (sym -> name == NULL || *sym -> name == '\0') + { + /* Skip names that don't exist (shouldn't happen), or names + that are null strings (may happen). */ + continue; + } + + if (dynamic + && sym -> section == &bfd_und_section + && (sym -> flags & BSF_FUNCTION)) + { + struct minimal_symbol *msym; + + /* Symbol is a reference to a function defined in + a shared library. + If its value is non zero then it is usually the address + of the corresponding entry in the procedure linkage table, + relative to the base address. + If its value is zero then the dynamic linker has to resolve + the symbol. We are unable to find any meaningful address + for this symbol in the executable file, so we skip it. */ + symaddr = sym -> value; + if (symaddr == 0) + continue; + symaddr += addr; + msym = record_minimal_symbol_and_info + ((char *) sym -> name, symaddr, + mst_solib_trampoline, NULL, objfile); +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (msym != NULL) + msym->filename = filesymname; +#endif + continue; + } + + /* If it is a nonstripped executable, do not enter dynamic + symbols, as the dynamic symbol table is usually a subset + of the main symbol table. */ + if (dynamic && !stripped) + continue; + if (sym -> flags & BSF_FILE) + { + /* STT_FILE debugging symbol that helps stabs-in-elf debugging. + Chain any old one onto the objfile; remember new sym. */ + if (sectinfo != NULL) + { + sectinfo -> next = dbx -> stab_section_info; + dbx -> stab_section_info = sectinfo; + sectinfo = NULL; + } + filesym = sym; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + filesymname = + obsavestring ((char *)filesym->name, strlen (filesym->name), + &objfile->symbol_obstack); +#endif + } + else if (sym -> flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK)) + { + struct minimal_symbol *msym; + + /* Select global/local/weak symbols. Note that bfd puts abs + symbols in their own section, so all symbols we are + interested in will have a section. */ + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + { + symaddr += addr; + } + /* 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) + { + /* This is a hack to get the minimal symbol type + right for Irix 5, which has absolute adresses + with special section indices for dynamic symbols. */ + unsigned short shndx = + ((elf_symbol_type *) sym)->internal_elf_sym.st_shndx; + + switch (shndx) + { + case SHN_MIPS_TEXT: + ms_type = mst_text; + break; + case SHN_MIPS_DATA: + ms_type = mst_data; + break; + case SHN_MIPS_ACOMMON: + ms_type = mst_bss; + break; + default: + ms_type = mst_abs; + } + } + else if (sym -> section -> flags & SEC_CODE) + { + if (sym -> flags & BSF_GLOBAL) + { + ms_type = mst_text; + } + else if ((sym->name[0] == '.' && sym->name[1] == 'L') + || ((sym -> flags & BSF_LOCAL) + && sym->name[0] == '$' + && sym->name[1] == 'L')) + /* Looks like a compiler-generated label. Skip it. + The assembler should be skipping these (to keep + executables small), but apparently with gcc on the + delta m88k SVR4, it loses. So to have us check too + should be harmless (but I encourage people to fix this + in the assembler instead of adding checks here). */ + continue; + else + { + ms_type = mst_file_text; + } + } + else if (sym -> section -> flags & SEC_ALLOC) + { + if (sym -> flags & BSF_GLOBAL) + { + if (sym -> section -> flags & SEC_LOAD) + { + ms_type = mst_data; + } + else + { + ms_type = mst_bss; + } + } + else if (sym -> flags & BSF_LOCAL) + { + /* Named Local variable in a Data section. Check its + name for stabs-in-elf. The STREQ macro checks the + first character inline, so we only actually do a + strcmp function call on names that start with 'B' + or 'D' */ + index = SECT_OFF_MAX; + if (STREQ ("Bbss.bss", sym -> name)) + { + index = SECT_OFF_BSS; + } + else if (STREQ ("Ddata.data", sym -> name)) + { + index = SECT_OFF_DATA; + } + else if (STREQ ("Drodata.rodata", sym -> name)) + { + index = SECT_OFF_RODATA; + } + if (index != SECT_OFF_MAX) + { + /* Found a special local symbol. Allocate a + sectinfo, if needed, and fill it in. */ + if (sectinfo == NULL) + { + sectinfo = (struct stab_section_info *) + xmmalloc (objfile -> md, sizeof (*sectinfo)); + memset ((PTR) sectinfo, 0, sizeof (*sectinfo)); + if (filesym == NULL) + { + complain (§ion_info_complaint, + sym -> name); + } + else + { + sectinfo -> filename = + (char *) filesym -> name; + } + } + if (sectinfo -> sections[index] != 0) + { + complain (§ion_info_dup_complaint, + sectinfo -> filename); + } + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + { + symaddr += addr; + } + sectinfo -> sections[index] = symaddr; + /* The special local symbols don't go in the + minimal symbol table, so ignore this one. */ + continue; + } + /* Not a special stabs-in-elf symbol, do regular + symbol processing. */ + if (sym -> section -> flags & SEC_LOAD) + { + ms_type = mst_file_data; + } + else + { + ms_type = mst_file_bss; + } + } + else + { + ms_type = mst_unknown; + } + } + else + { + /* FIXME: Solaris2 shared libraries include lots of + odd "absolute" and "undefined" symbols, that play + hob with actions like finding what function the PC + is in. Ignore them if they aren't text, data, or bss. */ + /* ms_type = mst_unknown; */ + continue; /* Skip this symbol. */ + } + /* Pass symbol size field in via BFD. FIXME!!! */ + size = ((elf_symbol_type *) sym) -> internal_elf_sym.st_size; + msym = record_minimal_symbol_and_info + ((char *) sym -> name, symaddr, + ms_type, (PTR) size, objfile); +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (msym != NULL) + msym->filename = filesymname; +#endif + } + } + do_cleanups (back_to); + } +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to elf_symfile_init, which + currently does nothing. + + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. We simplify it down to a single offset for all + symbols. FIXME. + + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + 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!!! + + dwarf_build_psymtabs() builds psymtabs for DWARF symbols; + elfstab_build_psymtabs() handles STABS symbols; + mdebug_build_psymtabs() handles ECOFF debugging information. + + Note that ELF files have a "minimal" symbol table, which looks a lot + like 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 +elf_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile->obfd; + struct elfinfo ei; + struct cleanup *back_to; + CORE_ADDR offset; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + memset ((char *) &ei, 0, sizeof (ei)); + + /* Allocate struct to keep track of the symfile */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + memset ((char *) objfile->sym_stab_info, 0, sizeof (struct dbx_symfile_info)); + make_cleanup (free_elfinfo, (PTR) objfile); + + /* Process the normal ELF symbol table first. This may write some + chain of info into the dbx_symfile_info in objfile->sym_stab_info, + which can later be used by elfstab_offset_sections. */ + + /* FIXME, should take a section_offsets param, not just an offset. */ + offset = ANOFFSET (section_offsets, 0); + elf_symtab_read (abfd, offset, objfile, 0); + + /* Add the dynamic symbols. */ + + elf_symtab_read (abfd, offset, objfile, 1); + + /* Now process debugging information, which is contained in + special ELF sections. We first have to find them... */ + + bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei); + if (ei.dboffset && ei.lnoffset) + { + /* DWARF sections */ + dwarf_build_psymtabs (objfile, + section_offsets, mainline, + ei.dboffset, ei.dbsize, + ei.lnoffset, ei.lnsize); + } + if (ei.stabsect) + { + asection *str_sect; + + /* Stab sections have an associated string table that looks like + a separate section. */ + str_sect = bfd_get_section_by_name (abfd, ".stabstr"); + + /* FIXME should probably warn about a stab section without a stabstr. */ + if (str_sect) + elfstab_build_psymtabs (objfile, + section_offsets, + mainline, + ei.stabsect->filepos, + bfd_section_size (abfd, ei.stabsect), + str_sect->filepos, + bfd_section_size (abfd, str_sect)); + } + if (ei.mdebugsect) + { + const struct ecoff_debug_swap *swap; + + /* .mdebug section, presumably holding ECOFF debugging + information. */ + swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + if (swap) + elfmdebug_build_psymtabs (objfile, swap, ei.mdebugsect, + section_offsets); + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + +/* This cleans up the objfile's sym_stab_info pointer, and the chain of + stab_section_info's, that might be dangling from it. */ + +static void +free_elfinfo (objp) + PTR objp; +{ + struct objfile *objfile = (struct objfile *)objp; + struct dbx_symfile_info *dbxinfo = (struct dbx_symfile_info *) + objfile->sym_stab_info; + struct stab_section_info *ssi, *nssi; + + ssi = dbxinfo->stab_section_info; + while (ssi) + { + nssi = ssi->next; + mfree (objfile->md, ssi); + ssi = nssi; + } + + dbxinfo->stab_section_info = 0; /* Just say No mo info about this. */ +} + + +/* 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 an ELF file. */ + +static void +elf_new_init (ignore) + 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 +elf_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_stab_info != NULL) + { + mfree (objfile -> md, objfile -> sym_stab_info); + } +} + +/* ELF specific initialization routine for reading symbols. + + It is passed a pointer to a struct sym_fns which contains, among other + things, the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we can fill with goodies. + + For now at least, we have nothing in particular to do, so this function is + just a stub. */ + +static void +elf_symfile_init (objfile) + struct objfile *objfile; +{ + /* ELF 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; +} + +/* ELF specific parsing routine for section offsets. + + Plain and simple for now. */ + +static +struct section_offsets * +elf_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* When handling an ELF file that contains Sun STABS debug info, + some of the debug info is relative to the particular chunk of the + section that was generated in its individual .o file. E.g. + offsets to static variables are relative to the start of the data + segment *for that module before linking*. This information is + painfully squirreled away in the ELF symbol table as local symbols + with wierd names. Go get 'em when needed. */ + +void +elfstab_offset_sections (objfile, pst) + struct objfile *objfile; + struct partial_symtab *pst; +{ + char *filename = pst->filename; + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_stab_info; + struct stab_section_info *maybe = dbx->stab_section_info; + struct stab_section_info *questionable = 0; + int i; + char *p; + + /* The ELF symbol info doesn't include path names, so strip the path + (if any) from the psymtab filename. */ + while (0 != (p = strchr (filename, '/'))) + filename = p+1; + + /* FIXME: This linear search could speed up significantly + if it was chained in the right order to match how we search it, + and if we unchained when we found a match. */ + for (; maybe; maybe = maybe->next) + { + if (filename[0] == maybe->filename[0] + && STREQ (filename, maybe->filename)) + { + /* We found a match. But there might be several source files + (from different directories) with the same name. */ + if (0 == maybe->found) + break; + questionable = maybe; /* Might use it later. */ + } + } + + if (maybe == 0 && questionable != 0) + { + complain (&stab_info_questionable_complaint, filename); + maybe = questionable; + } + + if (maybe) + { + /* Found it! Allocate a new psymtab struct, and fill it in. */ + maybe->found++; + pst->section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (pst->section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (pst->section_offsets, i) = maybe->sections[i]; + return; + } + + /* We were unable to find any offsets for this file. Complain. */ + if (dbx->stab_section_info) /* If there *is* any info, */ + complain (&stab_info_mismatch_complaint, filename); +} + +/* Register that we are able to handle ELF object file formats. */ + +static struct sym_fns elf_sym_fns = +{ + bfd_target_elf_flavour, + elf_new_init, /* sym_new_init: init anything gbl to entire symtab */ + elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + elf_symfile_read, /* sym_read: read a symbol file into symtab */ + elf_symfile_finish, /* sym_finish: finished with file, cleanup */ + elf_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_elfread () +{ + add_symtab_fns (&elf_sym_fns); +} diff --git a/contrib/gdb/gdb/environ.c b/contrib/gdb/gdb/environ.c new file mode 100644 index 000000000000..77296bef2a41 --- /dev/null +++ b/contrib/gdb/gdb/environ.c @@ -0,0 +1,194 @@ +/* environ.c -- library for manipulating environments for GNU. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#include "defs.h" +#include "environ.h" +#include "gdb_string.h" +#include "gdbcore.h" + + +/* Return a new environment object. */ + +struct environ * +make_environ () +{ + register struct environ *e; + + e = (struct environ *) xmalloc (sizeof (struct environ)); + + e->allocated = 10; + e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *)); + e->vector[0] = 0; + return e; +} + +/* Free an environment and all the strings in it. */ + +void +free_environ (e) + register struct environ *e; +{ + register char **vector = e->vector; + + while (*vector) + free (*vector++); + + free (e); +} + +/* Copy the environment given to this process into E. + Also copies all the strings in it, so we can be sure + that all strings in these environments are safe to free. */ + +void +init_environ (e) + register struct environ *e; +{ + extern char **environ; + register int i; + + if (environ == NULL) + return; + + for (i = 0; environ[i]; i++) /*EMPTY*/; + + if (e->allocated < i) + { + e->allocated = max (i, e->allocated + 10); + e->vector = (char **) xrealloc ((char *)e->vector, + (e->allocated + 1) * sizeof (char *)); + } + + memcpy (e->vector, environ, (i + 1) * sizeof (char *)); + + while (--i >= 0) + { + register int len = strlen (e->vector[i]); + register char *new = (char *) xmalloc (len + 1); + memcpy (new, e->vector[i], len + 1); + e->vector[i] = new; + } +} + +/* Return the vector of environment E. + This is used to get something to pass to execve. */ + +char ** +environ_vector (e) + struct environ *e; +{ + return e->vector; +} + +/* Return the value in environment E of variable VAR. */ + +char * +get_in_environ (e, var) + const struct environ *e; + const char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; (s = *vector) != NULL; vector++) + if (STREQN (s, var, len) && s[len] == '=') + return &s[len + 1]; + + return 0; +} + +/* Store the value in E of VAR as VALUE. */ + +void +set_in_environ (e, var, value) + struct environ *e; + const char *var; + const char *value; +{ + register int i; + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (i = 0; (s = vector[i]) != NULL; i++) + if (STREQN (s, var, len) && s[len] == '=') + break; + + if (s == 0) + { + if (i == e->allocated) + { + e->allocated += 10; + vector = (char **) xrealloc ((char *)vector, + (e->allocated + 1) * sizeof (char *)); + e->vector = vector; + } + vector[i + 1] = 0; + } + else + free (s); + + s = (char *) xmalloc (len + strlen (value) + 2); + strcpy (s, var); + strcat (s, "="); + strcat (s, value); + vector[i] = s; + + /* This used to handle setting the PATH and GNUTARGET variables + specially. The latter has been replaced by "set gnutarget" + (which has worked since GDB 4.11). The former affects searching + the PATH to find SHELL, and searching the PATH to find the + argument of "symbol-file" or "exec-file". Maybe we should have + some kind of "set exec-path" for that. But in any event, having + "set env" affect anything besides the inferior is a bad idea. + What if we want to change the environment we pass to the program + without afecting GDB's behavior? */ + + return; +} + +/* Remove the setting for variable VAR from environment E. */ + +void +unset_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; (s = *vector) != NULL; vector++) + { + if (STREQN (s, var, len) && s[len] == '=') + { + free (s); + /* Walk through the vector, shuffling args down by one, including + the NULL terminator. Can't use memcpy() here since the regions + overlap, and memmove() might not be available. */ + while ((vector[0] = vector[1]) != NULL) + { + vector++; + } + break; + } + } +} diff --git a/contrib/gdb/gdb/environ.h b/contrib/gdb/gdb/environ.h new file mode 100644 index 000000000000..87a538a1b47b --- /dev/null +++ b/contrib/gdb/gdb/environ.h @@ -0,0 +1,58 @@ +/* Header for environment manipulation library. + Copyright 1989, 1992 Free Software Foundation. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (ENVIRON_H) +#define ENVIRON_H 1 + +/* We manipulate environments represented as these structures. */ + +struct environ +{ + /* Number of usable slots allocated in VECTOR. + VECTOR always has one slot not counted here, + to hold the terminating zero. */ + int allocated; + /* A vector of slots, ALLOCATED + 1 of them. + The first few slots contain strings "VAR=VALUE" + and the next one contains zero. + Then come some unused slots. */ + char **vector; +}; + +extern struct environ * +make_environ PARAMS ((void)); + +extern void +free_environ PARAMS ((struct environ *)); + +extern void +init_environ PARAMS ((struct environ *)); + +extern char * +get_in_environ PARAMS ((const struct environ *, const char *)); + +extern void +set_in_environ PARAMS ((struct environ *, const char *, + const char *)); + +extern void +unset_in_environ PARAMS ((struct environ *, char *)); + +extern char ** +environ_vector PARAMS ((struct environ *)); + +#endif /* defined (ENVIRON_H) */ diff --git a/contrib/gdb/gdb/eval.c b/contrib/gdb/gdb/eval.c new file mode 100644 index 000000000000..ed9fd53b37e4 --- /dev/null +++ b/contrib/gdb/gdb/eval.c @@ -0,0 +1,1780 @@ +/* Evaluate expressions for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "expression.h" +#include "target.h" +#include "frame.h" +#include "demangle.h" +#include "language.h" /* For CAST_IS_CONVERSION */ +#include "f-lang.h" /* for array bound stuff */ + +/* Prototypes for local functions. */ + +static value_ptr evaluate_subexp_for_sizeof PARAMS ((struct expression *, + int *)); + +static value_ptr evaluate_subexp_for_address PARAMS ((struct expression *, + int *, enum noside)); + +#ifdef __GNUC__ +inline +#endif +static value_ptr +evaluate_subexp (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + return (*exp->language_defn->evaluate_exp) (expect_type, exp, pos, noside); +} + +/* Parse the string EXP as a C expression, evaluate it, + and return the result as a number. */ + +CORE_ADDR +parse_and_eval_address (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +/* Like parse_and_eval_address but takes a pointer to a char * variable + and advanced that variable across the characters parsed. */ + +CORE_ADDR +parse_and_eval_address_1 (expptr) + char **expptr; +{ + struct expression *expr = parse_exp_1 (expptr, (struct block *)0, 0); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +value_ptr +parse_and_eval (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register value_ptr val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Parse up to a comma (or to a closeparen) + in the string EXPP as an expression, evaluate it, and return the value. + EXPP is advanced to point to the comma. */ + +value_ptr +parse_to_comma_and_eval (expp) + char **expp; +{ + struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1); + register value_ptr val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Evaluate an expression in internal prefix form + such as is constructed by parse.y. + + See expression.h for info on the format of an expression. */ + +value_ptr +evaluate_expression (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); +} + +/* Evaluate an expression, avoiding all memory references + and getting a value whose type alone is correct. */ + +value_ptr +evaluate_type (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS); +} + +/* If the next expression is an OP_LABELED, skips past it, + returning the label. Otherwise, does nothing and returns NULL. */ + +static char* +get_label (exp, pos) + register 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 tupes (in Chill) or brace-initializers + (in C/C++) for structure types. */ + +static value_ptr +evaluate_struct_tuple (struct_val, exp, pos, noside, nargs) + value_ptr struct_val; + register struct expression *exp; + register 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; + value_ptr val = NULL; + int nlabels = 0; + int bitpos, bitsize; + char *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 && STREQ (field_name, label)) + { + 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 (STREQ (TYPE_FIELD_NAME (substruct_type, + subfieldno), + label)) + { + 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++; + 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"); + } + } + + /* 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 (struct_val) + bitpos / 8; + if (bitsize) + modify_field (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; +} + +/* Recursive helper function for setting elements of array tuples for Chill. + The target is ARRAY (which has bounds LOW_BOUND to HIGH_BOUND); + the element value is ELEMENT; + EXP, POS and NOSIDE are as usual. + Evaluates index expresions and sets the specified element(s) of + ARRAY to ELEMENT. + Returns last index value. */ + +static LONGEST +init_array_element (array, element, exp, pos, noside, low_bound, high_bound) + value_ptr array, element; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + LONGEST index; + int element_size = TYPE_LENGTH (VALUE_TYPE (element)); + if (exp->elts[*pos].opcode == BINOP_COMMA) + { + (*pos)++; + init_array_element (array, element, exp, pos, noside, + low_bound, high_bound); + return init_array_element (array, element, + exp, pos, noside, low_bound, high_bound); + } + else if (exp->elts[*pos].opcode == BINOP_RANGE) + { + LONGEST low, high; + (*pos)++; + low = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + high = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + if (low < low_bound || high > high_bound) + error ("tuple range index out of range"); + for (index = low ; index <= high; index++) + { + memcpy (VALUE_CONTENTS_RAW (array) + + (index - low_bound) * element_size, + VALUE_CONTENTS (element), element_size); + } + } + else + { + index = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + if (index < low_bound || index > high_bound) + error ("tuple index out of range"); + memcpy (VALUE_CONTENTS_RAW (array) + (index - low_bound) * element_size, + VALUE_CONTENTS (element), element_size); + } + return index; +} + +value_ptr +evaluate_subexp_standard (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + int tem, tem2, tem3; + register int pc, pc2 = 0, oldpos; + register value_ptr arg1 = NULL, arg2 = NULL, arg3; + struct type *type; + int nargs; + value_ptr *argvec; + int upper, lower, retcode; + int code; + + /* This expect_type crap should not be used for C. C expressions do + not have any notion of expected types, never has and (goddess + willing) never will. The C++ code uses it for some twisted + purpose (I haven't investigated but I suspect it just the usual + combination of Stroustrup figuring out some crazy language + feature and Tiemann figuring out some crazier way to try to + implement it). CHILL has the tuple stuff; I don't know enough + about CHILL to know whether expected types is the way to do it. + FORTRAN I don't know. */ + if (exp->language_defn->la_language != language_cplus + && exp->language_defn->la_language != language_chill) + expect_type = NULL_TYPE; + + pc = (*pos)++; + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_SCOPE: + tem = longest_to_int (exp->elts[pc + 2].longconst); + (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type, + 0, + exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, + expect_type); + if (arg1 == NULL) + error ("There is no field named %s", &exp->elts[pc + 3].string); + return arg1; + + case OP_LONG: + (*pos) += 3; + return value_from_longest (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst); + + case OP_DOUBLE: + (*pos) += 3; + return value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst); + + case OP_VAR_VALUE: + (*pos) += 3; + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct symbol * sym = exp->elts[pc + 2].symbol; + enum lval_type lv; + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_LABEL: + case LOC_CONST_BYTES: + lv = not_lval; + break; + + case LOC_REGISTER: + case LOC_REGPARM: + lv = lval_register; + break; + + default: + lv = lval_memory; + break; + } + + return value_zero (SYMBOL_TYPE (sym), lv); + } + else + return value_of_variable (exp->elts[pc + 2].symbol, + exp->elts[pc + 1].block); + + case OP_LAST: + (*pos) += 2; + return + access_value_history (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_REGISTER: + (*pos) += 2; + return value_of_register (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_BOOL: + (*pos) += 2; + return value_from_longest (LA_BOOL_TYPE, + exp->elts[pc + 1].longconst); + + case OP_INTERNALVAR: + (*pos) += 2; + return value_of_internalvar (exp->elts[pc + 1].internalvar); + + case OP_STRING: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + if (noside == EVAL_SKIP) + goto nosideret; + return value_string (&exp->elts[pc + 2].string, tem); + + 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); + break; + + case OP_ARRAY: + (*pos) += 3; + tem2 = longest_to_int (exp->elts[pc + 1].longconst); + tem3 = longest_to_int (exp->elts[pc + 2].longconst); + nargs = tem3 - tem2 + 1; + type = expect_type ? check_typedef (expect_type) : NULL_TYPE; + + if (expect_type != NULL_TYPE && noside != EVAL_SKIP + && TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + value_ptr rec = allocate_value (expect_type); + memset (VALUE_CONTENTS_RAW (rec), '\0', TYPE_LENGTH (type)); + return evaluate_struct_tuple (rec, exp, pos, noside, nargs); + } + + if (expect_type != NULL_TYPE && noside != EVAL_SKIP + && TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + struct type *range_type = TYPE_FIELD_TYPE (type, 0); + struct type *element_type = TYPE_TARGET_TYPE (type); + value_ptr array = allocate_value (expect_type); + int element_size = TYPE_LENGTH (check_typedef (element_type)); + LONGEST low_bound, high_bound, index; + if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) + { + low_bound = 0; + high_bound = (TYPE_LENGTH (type) / element_size) - 1; + } + index = low_bound; + memset (VALUE_CONTENTS_RAW (array), 0, TYPE_LENGTH (expect_type)); + for (tem = nargs; --nargs >= 0; ) + { + value_ptr element; + int index_pc = 0; + if (exp->elts[*pos].opcode == BINOP_RANGE) + { + index_pc = ++(*pos); + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + } + element = evaluate_subexp (element_type, exp, pos, noside); + if (VALUE_TYPE (element) != element_type) + element = value_cast (element_type, element); + if (index_pc) + { + int continue_pc = *pos; + *pos = index_pc; + index = init_array_element (array, element, exp, pos, noside, + low_bound, high_bound); + *pos = continue_pc; + } + else + { + memcpy (VALUE_CONTENTS_RAW (array) + + (index - low_bound) * element_size, + VALUE_CONTENTS (element), + element_size); + } + index++; + } + return array; + } + + if (expect_type != NULL_TYPE && noside != EVAL_SKIP + && TYPE_CODE (type) == TYPE_CODE_SET) + { + value_ptr set = allocate_value (expect_type); + char *valaddr = VALUE_CONTENTS_RAW (set); + struct type *element_type = TYPE_INDEX_TYPE (type); + LONGEST low_bound, high_bound; + if (get_discrete_bounds (element_type, &low_bound, &high_bound) < 0) + error ("(power)set type with unknown size"); + memset (valaddr, '\0', TYPE_LENGTH (type)); + for (tem = 0; tem < nargs; tem++) + { + LONGEST range_low, range_high; + value_ptr elem_val; + if (exp->elts[*pos].opcode == BINOP_RANGE) + { + (*pos)++; + elem_val = evaluate_subexp (element_type, exp, pos, noside); + range_low = value_as_long (elem_val); + elem_val = evaluate_subexp (element_type, exp, pos, noside); + range_high = value_as_long (elem_val); + } + else + { + elem_val = evaluate_subexp (element_type, exp, pos, noside); + range_low = range_high = value_as_long (elem_val); + } + if (range_low > range_high) + { + warning ("empty POWERSET tuple range"); + continue; + } + if (range_low < low_bound || range_high > high_bound) + error ("POWERSET tuple element out of range"); + range_low -= low_bound; + range_high -= low_bound; + for ( ; range_low <= range_high; range_low++) + { + int bit_index = (unsigned) range_low % TARGET_CHAR_BIT; + if (BITS_BIG_ENDIAN) + bit_index = TARGET_CHAR_BIT - 1 - bit_index; + valaddr [(unsigned) range_low / TARGET_CHAR_BIT] + |= 1 << bit_index; + } + } + return set; + } + + argvec = (value_ptr *) alloca (sizeof (value_ptr) * nargs); + for (tem = 0; tem < nargs; tem++) + { + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + } + if (noside == EVAL_SKIP) + goto nosideret; + return value_array (tem2, tem3, argvec); + + case TERNOP_SLICE: + { + value_ptr array = evaluate_subexp (NULL_TYPE, exp, pos, noside); + int lowbound + = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + int upper + = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + if (noside == EVAL_SKIP) + goto nosideret; + return value_slice (array, lowbound, upper - lowbound + 1); + } + + case TERNOP_SLICE_COUNT: + { + value_ptr 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); + if (value_logical_not (arg1)) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return arg2; + } + + case OP_FUNCALL: + (*pos) += 2; + op = exp->elts[*pos].opcode; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + argvec = (value_ptr *) alloca (sizeof (value_ptr) * (nargs + 3)); + if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + LONGEST fnptr; + + nargs++; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_MEMBER) + { + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + + /* If the function is a virtual function, then the + aggregate value (providing the structure) plays + its part by providing the vtable. Otherwise, + it is just along for the ride: call the function + directly. */ + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + fnptr = value_as_long (arg1); + + if (METHOD_PTR_IS_VIRTUAL(fnptr)) + { + int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr); + struct type *basetype; + struct type *domain_type = + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + int i, j; + basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if (domain_type != basetype) + arg2 = value_cast(lookup_pointer_type (domain_type), arg2); + basetype = TYPE_VPTR_BASETYPE (domain_type); + for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--) + { + struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i); + /* If one is virtual, then all are virtual. */ + if (TYPE_FN_FIELD_VIRTUAL_P (f, 0)) + for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j) + if ((int) TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset) + { + value_ptr temp = value_ind (arg2); + arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0); + arg2 = value_addr (temp); + goto got_it; + } + } + if (i < 0) + error ("virtual function at index %d not found", fnoffset); + } + else + { + VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + } + got_it: + + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + /* Hair for method invocations */ + int tem2; + + nargs++; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + tem2 = longest_to_int (exp->elts[pc2 + 1].longconst); + *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1); + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_STRUCT) + { + /* If v is a variable in a register, and the user types + v.method (), this will produce an error, because v has + no address. + + A possible way around this would be to allocate a + copy of the variable on the stack, copy in the + contents, call the function, and copy out the + contents. I.e. convert this from call by reference + to call by copy-return (or whatever it's called). + However, this does not work because it is not the + same: the method being called could stash a copy of + the address, and then future uses through that address + (after the method returns) would be expected to + use the variable itself, not some copy of it. */ + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else + { + argvec[0] = evaluate_subexp_with_coercion (exp, pos, noside); + tem = 1; + type = VALUE_TYPE (argvec[0]); + if (type && TYPE_CODE (type) == TYPE_CODE_PTR) + type = TYPE_TARGET_TYPE (type); + if (type && TYPE_CODE (type) == TYPE_CODE_FUNC) + { + for (; tem <= nargs && tem <= TYPE_NFIELDS (type); tem++) + { + argvec[tem] = evaluate_subexp (TYPE_FIELD_TYPE (type, tem-1), + exp, pos, noside); + } + } + } + + for (; tem <= nargs; tem++) + { + /* Ensure that array expressions are coerced into pointer objects. */ + + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + } + + /* signal end of arglist */ + argvec[tem] = 0; + + if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + int static_memfuncp; + value_ptr temp = arg2; + char tstr[64]; + + argvec[1] = arg2; + argvec[0] = 0; + strcpy(tstr, &exp->elts[pc2+2].string); + if (!argvec[0]) + { + temp = arg2; + argvec[0] = + value_struct_elt (&temp, argvec+1, tstr, + &static_memfuncp, + op == STRUCTOP_STRUCT + ? "structure" : "structure pointer"); + } + arg2 = value_from_longest (lookup_pointer_type(VALUE_TYPE (temp)), + VALUE_ADDRESS (temp)+VALUE_OFFSET (temp)); + argvec[1] = arg2; + + if (static_memfuncp) + { + argvec[1] = argvec[0]; + nargs--; + argvec++; + } + } + else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + argvec[1] = arg2; + argvec[0] = arg1; + } + + do_call_it: + + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the return type doesn't look like a function type, call an + error. This can happen if somebody tries to turn a variable into + a function call. This is here because people often want to + call, eg, strcmp, which gdb doesn't know is a function. If + gdb isn't asked for it's opinion (ie. through "whatis"), + it won't offer it. */ + + struct type *ftype = + TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])); + + if (ftype) + return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]))); + else + error ("Expression of type other than \"Function returning ...\" used as function"); + } + return call_function_by_hand (argvec[0], nargs, argvec + 1); + + case OP_F77_UNDETERMINED_ARGLIST: + + /* Remember that in F77, functions, substring ops and + array subscript operations cannot be disambiguated + at parse time. We have made all array subscript operations, + substring operations as well as function calls come here + and we now have to discover what the heck this thing actually was. + If it is a function, we process just as if we got an OP_FUNCALL. */ + + nargs = longest_to_int (exp->elts[pc+1].longconst); + (*pos) += 2; + + /* First determine the type code we are dealing with. */ + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + type = check_typedef (VALUE_TYPE (arg1)); + code = TYPE_CODE (type); + + switch (code) + { + case TYPE_CODE_ARRAY: + goto multi_f77_subscript; + + case TYPE_CODE_STRING: + goto op_f77_substr; + + case TYPE_CODE_PTR: + case TYPE_CODE_FUNC: + /* It's a function call. */ + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + argvec = (value_ptr *) alloca (sizeof (value_ptr) * (nargs + 2)); + argvec[0] = arg1; + tem = 1; + for (; tem <= nargs; tem++) + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + argvec[tem] = 0; /* signal end of arglist */ + goto do_call_it; + + default: + error ("Cannot perform substring on this type"); + } + + op_f77_substr: + /* We have a substring operation on our hands here, + let us get the string we will be dealing with */ + + /* Now evaluate the 'from' and 'to' */ + + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + + if (nargs < 2) + return value_subscript (arg1, arg2); + + arg3 = evaluate_subexp_with_coercion (exp, pos, noside); + + if (noside == EVAL_SKIP) + goto nosideret; + + tem2 = value_as_long (arg2); + tem3 = value_as_long (arg3); + + return value_slice (arg1, tem2, tem3 - tem2 + 1); + + case OP_COMPLEX: + /* We have a complex number, There should be 2 floating + point numbers that compose it */ + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + return value_literal_complex (arg1, arg2, builtin_type_f_complex_s16); + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value_ptr temp = arg1; + return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string, + NULL, "structure"); + } + + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value_ptr temp = arg1; + return value_struct_elt (&temp, NULL, &exp->elts[pc + 2].string, + NULL, "structure pointer"); + } + + + case STRUCTOP_MEMBER: + arg1 = evaluate_subexp_for_address (exp, pos, noside); + goto handle_pointer_to_member; + case STRUCTOP_MPTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + handle_pointer_to_member: + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + type = check_typedef (VALUE_TYPE (arg2)); + if (TYPE_CODE (type) != TYPE_CODE_PTR) + goto bad_pointer_to_member; + type = check_typedef (TYPE_TARGET_TYPE (type)); + if (TYPE_CODE (type) == TYPE_CODE_METHOD) + error ("not implemented: pointer-to-method in pointer-to-member construct"); + if (TYPE_CODE (type) != TYPE_CODE_MEMBER) + goto bad_pointer_to_member; + /* Now, convert these values to an address. */ + arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg1); + arg3 = value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_as_long (arg1) + value_as_long (arg2)); + return value_ind (arg3); + bad_pointer_to_member: + error("non-pointer-to-member value used in pointer-to-member construct"); + + case BINOP_CONCAT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_concat (arg1, arg2); + + case BINOP_ASSIGN: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_assign (arg1, arg2); + + case BINOP_ASSIGN_MODIFY: + (*pos) += 2; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + op = exp->elts[pc + 1].opcode; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op); + else if (op == BINOP_ADD) + arg2 = value_add (arg1, arg2); + else if (op == BINOP_SUB) + arg2 = value_sub (arg1, arg2); + else + arg2 = value_binop (arg1, arg2, op); + return value_assign (arg1, arg2); + + case BINOP_ADD: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_add (arg1, arg2); + + case BINOP_SUB: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_sub (arg1, arg2); + + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_LSH: + case BINOP_RSH: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + if (noside == EVAL_AVOID_SIDE_EFFECTS + && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + return value_binop (arg1, arg2, op); + + case BINOP_RANGE: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + error ("':' operator used in invalid context"); + + case BINOP_SUBSCRIPT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (check_typedef (VALUE_TYPE (arg1))); + if (type) + return value_zero (type, VALUE_LVAL (arg1)); + else + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_subscript (arg1, arg2); + + case BINOP_IN: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_in (arg1, arg2); + + case MULTI_SUBSCRIPT: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + while (nargs-- > 0) + { + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + /* FIXME: EVAL_SKIP handling may not be correct. */ + if (noside == EVAL_SKIP) + { + if (nargs > 0) + { + continue; + } + else + { + goto nosideret; + } + } + /* FIXME: EVAL_AVOID_SIDE_EFFECTS handling may not be correct. */ + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (check_typedef (VALUE_TYPE (arg1))); + if (type != NULL) + { + arg1 = value_zero (type, VALUE_LVAL (arg1)); + noside = EVAL_SKIP; + continue; + } + else + { + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + } + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg1 = value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + arg1 = value_subscript (arg1, arg2); + } + } + return (arg1); + + multi_f77_subscript: + { + int subscript_array[MAX_FORTRAN_DIMS+1]; /* 1-based array of + subscripts, max == 7 */ + int array_size_array[MAX_FORTRAN_DIMS+1]; + int ndimensions=1,i; + struct type *tmp_type; + int offset_item; /* The array offset where the item lives */ + + if (nargs > MAX_FORTRAN_DIMS) + error ("Too many subscripts for F77 (%d Max)", MAX_FORTRAN_DIMS); + + tmp_type = check_typedef (VALUE_TYPE (arg1)); + ndimensions = calc_f77_array_dims (type); + + if (nargs != ndimensions) + error ("Wrong number of subscripts"); + + /* Now that we know we have a legal array subscript expression + let us actually find out where this element exists in the array. */ + + offset_item = 0; + for (i = 1; i <= nargs; i++) + { + /* Evaluate each subscript, It must be a legal integer in F77 */ + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + + /* Fill in the subscript and array size arrays */ + + subscript_array[i] = value_as_long (arg2); + + retcode = f77_get_dynamic_upperbound (tmp_type, &upper); + if (retcode == BOUND_FETCH_ERROR) + error ("Cannot obtain dynamic upper bound"); + + retcode = f77_get_dynamic_lowerbound (tmp_type, &lower); + if (retcode == BOUND_FETCH_ERROR) + error("Cannot obtain dynamic lower bound"); + + array_size_array[i] = upper - lower + 1; + + /* Zero-normalize subscripts so that offsetting will work. */ + + subscript_array[i] -= lower; + + /* If we are at the bottom of a multidimensional + array type then keep a ptr to the last ARRAY + type around for use when calling value_subscript() + below. This is done because we pretend to value_subscript + that we actually have a one-dimensional array + of base element type that we apply a simple + offset to. */ + + if (i < nargs) + tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)); + } + + /* Now let us calculate the offset for this item */ + + offset_item = subscript_array[ndimensions]; + + for (i = ndimensions - 1; i >= 1; i--) + offset_item = + array_size_array[i] * offset_item + subscript_array[i]; + + /* Construct a value node with the value of the offset */ + + arg2 = value_from_longest (builtin_type_f_integer, offset_item); + + /* Let us now play a dirty trick: we will take arg1 + which is a value node pointing to the topmost level + of the multidimensional array-set and pretend + that it is actually a array of the final element + type, this will ensure that value_subscript() + returns the correct type value */ + + VALUE_TYPE (arg1) = tmp_type; + return value_ind (value_add (value_coerce_array (arg1), arg2)); + } + + case BINOP_LOGICAL_AND: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (tem ? EVAL_SKIP : noside)); + return value_from_longest (LA_BOOL_TYPE, + (LONGEST) (!tem && !value_logical_not (arg2))); + } + + case BINOP_LOGICAL_OR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (!tem ? EVAL_SKIP : noside)); + return value_from_longest (LA_BOOL_TYPE, + (LONGEST) (!tem || !value_logical_not (arg2))); + } + + case BINOP_EQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) tem); + } + + case BINOP_NOTEQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) ! tem); + } + + case BINOP_LESS: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) tem); + } + + case BINOP_GTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) tem); + } + + case BINOP_GEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1) || value_equal (arg1, arg2); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) tem); + } + + case BINOP_LEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2) || value_equal (arg1, arg2); + return value_from_longest (LA_BOOL_TYPE, (LONGEST) tem); + } + + case BINOP_REPEAT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT) + error ("Non-integral right operand for \"@\" operator."); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + return allocate_repeat_value (VALUE_TYPE (arg1), + longest_to_int (value_as_long (arg2))); + } + else + return value_repeat (arg1, longest_to_int (value_as_long (arg2))); + + case BINOP_COMMA: + evaluate_subexp (NULL_TYPE, exp, pos, noside); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_NEG: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_neg (arg1); + + case UNOP_COMPLEMENT: + /* C++: check for and handle destructor names. */ + op = exp->elts[*pos].opcode; + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (UNOP_COMPLEMENT, arg1)) + return value_x_unop (arg1, UNOP_COMPLEMENT); + else + return value_complement (arg1); + + case UNOP_LOGICAL_NOT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_from_longest (builtin_type_int, + (LONGEST) value_logical_not (arg1)); + + case UNOP_IND: + if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) + expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type)); + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + type = check_typedef (VALUE_TYPE (arg1)); + if (TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF + /* In C you can dereference an array to get the 1st elt. */ + || TYPE_CODE (type) == TYPE_CODE_ARRAY + ) + return value_zero (TYPE_TARGET_TYPE (type), + lval_memory); + else if (TYPE_CODE (type) == TYPE_CODE_INT) + /* GDB allows dereferencing an int. */ + return value_zero (builtin_type_int, lval_memory); + else + error ("Attempt to take contents of a non-pointer value."); + } + return value_ind (arg1); + + case UNOP_ADDR: + /* C++: check for and handle pointer to members. */ + + op = exp->elts[*pos].opcode; + + if (noside == EVAL_SKIP) + { + if (op == OP_SCOPE) + { + int temm = longest_to_int (exp->elts[pc+3].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1); + } + else + evaluate_subexp (expect_type, exp, pos, EVAL_SKIP); + goto nosideret; + } + + return evaluate_subexp_for_address (exp, pos, noside); + + case UNOP_SIZEOF: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_sizeof (exp, pos); + + case UNOP_CAST: + (*pos) += 2; + type = exp->elts[pc + 1].type; + 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_MEMVAL: + (*pos) += 2; + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (exp->elts[pc + 1].type, lval_memory); + else + return value_at_lazy (exp->elts[pc + 1].type, + value_as_pointer (arg1)); + + case UNOP_PREINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_PREDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_POSTINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case UNOP_POSTDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case OP_THIS: + (*pos) += 1; + return value_of_this (1); + + case OP_TYPE: + error ("Attempt to use a type name 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 + probably be removed from expression.h (e.g. do we need a BINOP_SCOPE + and an OP_SCOPE?); others are legitimate expressions which are + (apparently) not fully implemented. + + If there are any cases landing here which mean a user error, + then they should be separate cases, with more descriptive + error messages. */ + + error ("\ +GDB does not (yet) know how to evaluate that kind of expression"); + } + + nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return the address of that subexpression. + Advance *POS over the subexpression. + If the subexpression isn't an lvalue, get an error. + NOSIDE may be EVAL_AVOID_SIDE_EFFECTS; + then only the type of the result need be correct. */ + +static value_ptr +evaluate_subexp_for_address (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + register int pc; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case UNOP_IND: + (*pos)++; + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (NULL_TYPE, exp, pos, noside)); + + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + + /* C++: The "address" of a reference should yield the address + * of the object pointed to. Let value_addr() deal with it. */ + if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_REF) + goto default_case; + + (*pos) += 4; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct type *type = + lookup_pointer_type (SYMBOL_TYPE (var)); + enum address_class sym_class = SYMBOL_CLASS (var); + + if (sym_class == LOC_CONST + || sym_class == LOC_CONST_BYTES + || sym_class == LOC_REGISTER + || sym_class == LOC_REGPARM) + error ("Attempt to take address of register or constant."); + + return + value_zero (type, not_lval); + } + else + return + locate_var_value + (var, + block_innermost_frame (exp->elts[pc + 1].block)); + + default: + default_case: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + value_ptr x = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (VALUE_LVAL (x) == lval_memory) + return value_zero (lookup_pointer_type (VALUE_TYPE (x)), + not_lval); + else + error ("Attempt to take address of non-lval"); + } + return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + } +} + +/* Evaluate like `evaluate_subexp' except coercing arrays to pointers. + When used in contexts where arrays will be coerced anyway, this is + equivalent to `evaluate_subexp' but much faster because it avoids + actually fetching array contents (perhaps obsolete now that we have + VALUE_LAZY). + + Note that we currently only do the coercion for C expressions, where + arrays are zero based and the coercion is correct. For other languages, + with nonzero based arrays, coercion loses. Use CAST_IS_CONVERSION + to decide if coercion is appropriate. + + */ + +value_ptr +evaluate_subexp_with_coercion (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + register enum exp_opcode op; + register int pc; + register value_ptr val; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + if (TYPE_CODE (check_typedef (SYMBOL_TYPE (var))) == TYPE_CODE_ARRAY + && CAST_IS_CONVERSION) + { + (*pos) += 4; + val = + locate_var_value + (var, block_innermost_frame (exp->elts[pc + 1].block)); + return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (var))), + val); + } + /* FALLTHROUGH */ + + default: + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return a value for the size of that subexpression. + Advance *POS over the subexpression. */ + +static value_ptr +evaluate_subexp_for_sizeof (exp, pos) + register struct expression *exp; + register int *pos; +{ + enum exp_opcode op; + register int pc; + struct type *type; + value_ptr val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + /* This case is handled specially + so that we avoid creating a value for the result type. + If the result type is very big, it's desirable not to + create a value unnecessarily. */ + case UNOP_IND: + (*pos)++; + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + type = check_typedef (VALUE_TYPE (val)); + type = check_typedef (TYPE_TARGET_TYPE (type)); + return value_from_longest (builtin_type_int, (LONGEST) + TYPE_LENGTH (type)); + + case UNOP_MEMVAL: + (*pos) += 3; + type = check_typedef (exp->elts[pc + 1].type); + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (type)); + + case OP_VAR_VALUE: + (*pos) += 4; + type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol)); + return + value_from_longest (builtin_type_int, (LONGEST) TYPE_LENGTH (type)); + + default: + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); + } +} + +/* Parse a type expression in the string [P..P+LENGTH). */ + +struct type * +parse_and_eval_type (p, length) + char *p; + int length; +{ + char *tmp = (char *)alloca (length + 4); + struct expression *expr; + tmp[0] = '('; + memcpy (tmp+1, p, length); + tmp[length+1] = ')'; + tmp[length+2] = '0'; + tmp[length+3] = '\0'; + expr = parse_expression (tmp); + if (expr->elts[0].opcode != UNOP_CAST) + error ("Internal error in eval_type."); + return expr->elts[1].type; +} + +int +calc_f77_array_dims (array_type) + struct type *array_type; +{ + int ndimen = 1; + struct type *tmp_type; + + if ((TYPE_CODE(array_type) != TYPE_CODE_ARRAY)) + error ("Can't get dimensions for a non-array type"); + + tmp_type = array_type; + + while ((tmp_type = TYPE_TARGET_TYPE (tmp_type))) + { + if (TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY) + ++ndimen; + } + return ndimen; +} diff --git a/contrib/gdb/gdb/exc_request.defs b/contrib/gdb/gdb/exc_request.defs new file mode 100644 index 000000000000..9b5ed2ee421a --- /dev/null +++ b/contrib/gdb/gdb/exc_request.defs @@ -0,0 +1,51 @@ +/* + * Mach Operating System + * Copyright (c) 1993,1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * Abstract: + * MiG definitions file for Mach exception interface (request half). + */ + +subsystem exc 2400; + +#include + +#ifdef USERPREFIX +userprefix USERPREFIX; +#endif + +#ifdef SERVERPREFIX +serverprefix SERVERPREFIX; +#endif + +simpleroutine exception_raise_request ( + exception_port : mach_port_t; + replyport reply : mach_port_send_once_t; + thread : mach_port_t; + task : mach_port_t; + exception : integer_t; + code : integer_t; + subcode : integer_t); diff --git a/contrib/gdb/gdb/exec.c b/contrib/gdb/gdb/exec.c new file mode 100644 index 000000000000..dc71a4907154 --- /dev/null +++ b/contrib/gdb/gdb/exec.c @@ -0,0 +1,677 @@ +/* Work with executable files, for GDB. + Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "gdbcmd.h" +#include "language.h" +#include "symfile.h" +#include "objfiles.h" + +#ifdef USG +#include +#endif + +#include +#include +#include "gdb_string.h" + +#include "gdbcore.h" + +#include +#include "gdb_stat.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include "xcoffsolib.h" + +struct vmap *map_vmap PARAMS ((bfd *, bfd *)); + +/* Prototypes for local functions */ + +static void add_to_section_table PARAMS ((bfd *, sec_ptr, PTR)); + +static void exec_close PARAMS ((int)); + +static void file_command PARAMS ((char *, int)); + +static void set_section_command PARAMS ((char *, int)); + +static void exec_files_info PARAMS ((struct target_ops *)); + +extern int info_verbose; + +/* The Binary File Descriptor handle for the executable file. */ + +bfd *exec_bfd = NULL; + +/* Whether to open exec and core files read-only or read-write. */ + +int write_files = 0; + +/* Text start and end addresses (KLUDGE) if needed */ + +#ifdef NEED_TEXT_START_END +CORE_ADDR text_start = 0; +CORE_ADDR text_end = 0; +#endif + +struct vmap *vmap; + +/* Forward decl */ + +extern struct target_ops exec_ops; + +/* ARGSUSED */ +static void +exec_close (quitting) + int quitting; +{ + int need_symtab_cleanup = 0; + struct vmap *vp, *nxt; + + for (nxt = vmap; nxt != NULL; ) + { + 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. */ + if (!bfd_close (vp->bfd)) + warning ("cannot close \"%s\": %s", + vp->name, bfd_errmsg (bfd_get_error ())); + + /* FIXME: This routine is #if 0'd in symfile.c. What should we + be doing here? Should we just free everything in + vp->objfile->symtabs? Should free_objfile do that? + FIXME-as-well: free_objfile already free'd vp->name, so it isn't + valid here. */ + free_named_symtabs (vp->name); + free (vp); + } + + vmap = NULL; + + if (exec_bfd) + { + char *name = bfd_get_filename (exec_bfd); + + if (!bfd_close (exec_bfd)) + warning ("cannot close \"%s\": %s", + name, bfd_errmsg (bfd_get_error ())); + free (name); + exec_bfd = NULL; + } + + if (exec_ops.to_sections) + { + free ((PTR)exec_ops.to_sections); + exec_ops.to_sections = NULL; + exec_ops.to_sections_end = NULL; + } +} + +/* Process the first arg in ARGS as the new exec file. + + Note that we have to explicitly ignore additional args, since we can + be called from file_command(), which also calls symbol_file_command() + which can take multiple args. */ + +void +exec_file_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + char *filename; + + target_preopen (from_tty); + + /* Remove any previous exec file. */ + unpush_target (&exec_ops); + + /* Now open and digest the file the user requested, if any. */ + + if (args) + { + char *scratch_pathname; + int scratch_chan; + + /* Scan through the args and pick up the first non option arg + as the filename. */ + + argv = buildargv (args); + if (argv == NULL) + nomem (0); + + make_cleanup (freeargv, (char *) argv); + + for (; (*argv != NULL) && (**argv == '-'); argv++) {;} + if (*argv == NULL) + error ("no exec file name was specified"); + + filename = tilde_expand (*argv); + make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, + write_files? O_RDWR|O_BINARY: O_RDONLY|O_BINARY, 0, + &scratch_pathname); + if (scratch_chan < 0) + perror_with_name (filename); + exec_bfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + + if (!exec_bfd) + 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 = strdup (scratch_pathname); + make_cleanup (free, scratch_pathname); + + if (!bfd_check_format (exec_bfd, bfd_object)) + { + /* Make sure to close exec_bfd, or else "run" might try to use + it. */ + exec_close (0); + error ("\"%s\": not in executable format: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + + /* FIXME - This should only be run for RS6000, but the ifdef is a poor + way to accomplish. */ +#ifdef IBM6000_TARGET + /* Setup initial vmap. */ + + map_vmap (exec_bfd, 0); + if (vmap == NULL) + { + /* Make sure to close exec_bfd, or else "run" might try to use + it. */ + exec_close (0); + error ("\"%s\": can't find the file sections: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } +#endif /* IBM6000_TARGET */ + + if (build_section_table (exec_bfd, &exec_ops.to_sections, + &exec_ops.to_sections_end)) + { + /* Make sure to close exec_bfd, or else "run" might try to use + it. */ + exec_close (0); + error ("\"%s\": can't find the file sections: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + +#ifdef NEED_TEXT_START_END + + /* text_end is sometimes used for where to put call dummies. A + few ports use these for other purposes too. */ + + { + struct section_table *p; + + /* Set text_start to the lowest address of the start of any + readonly code section and set text_end to the highest + address of the end of any readonly code section. */ + /* FIXME: The comment above does not match the code. The code + checks for sections with are either code *or* readonly. */ + + text_start = ~(CORE_ADDR)0; + text_end = (CORE_ADDR)0; + for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) + if (bfd_get_section_flags (p->bfd, p->the_bfd_section) + & (SEC_CODE | SEC_READONLY)) + { + if (text_start > p->addr) + text_start = p->addr; + if (text_end < p->endaddr) + text_end = p->endaddr; + } + } +#endif + + validate_files (); + + set_endian_from_file (exec_bfd); + + push_target (&exec_ops); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); + } + else if (from_tty) + printf_unfiltered ("No exec file now.\n"); +} + +/* Set both the exec file and the symbol file, in one command. + What a novelty. Why did GDB go through four major releases before this + command was added? */ + +static void +file_command (arg, from_tty) + char *arg; + int from_tty; +{ + /* FIXME, if we lose on reading the symbol file, we should revert + the exec file, but that's rough. */ + exec_file_command (arg, from_tty); + symbol_file_command (arg, from_tty); +} + + +/* Locate all mappable sections of a BFD file. + table_pp_char is a char * to get it through bfd_map_over_sections; + we cast it back to its proper type. */ + +static void +add_to_section_table (abfd, asect, table_pp_char) + bfd *abfd; + sec_ptr asect; + PTR table_pp_char; +{ + struct section_table **table_pp = (struct section_table **)table_pp_char; + flagword aflag; + + aflag = bfd_get_section_flags (abfd, asect); + if (!(aflag & SEC_ALLOC)) + return; + if (0 == bfd_section_size (abfd, asect)) + return; + (*table_pp)->bfd = abfd; + (*table_pp)->the_bfd_section = asect; + (*table_pp)->addr = bfd_section_vma (abfd, asect); + (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect); + (*table_pp)++; +} + +/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. + Returns 0 if OK, 1 on error. */ + +int +build_section_table (some_bfd, start, end) + bfd *some_bfd; + struct section_table **start, **end; +{ + unsigned count; + + count = bfd_count_sections (some_bfd); + if (*start) + free ((PTR)*start); + *start = (struct section_table *) xmalloc (count * sizeof (**start)); + *end = *start; + bfd_map_over_sections (some_bfd, add_to_section_table, (char *)end); + if (*end > *start + count) + abort(); + /* We could realloc the table, but it probably loses for most files. */ + return 0; +} + +static void +bfdsec_to_vmap(abfd, sect, arg3) + bfd *abfd; + sec_ptr sect; + PTR arg3; +{ + struct vmap_and_bfd *vmap_bfd = (struct vmap_and_bfd *) arg3; + struct vmap *vp; + + vp = vmap_bfd->pvmap; + + if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0) + return; + + if (STREQ (bfd_section_name (abfd, sect), ".text")) + { + vp->tstart = 0; + vp->tend = vp->tstart + bfd_section_size (abfd, sect); + + /* When it comes to this adjustment value, in contrast to our previous + belief shared objects should behave the same as the main load segment. + This is the offset from the beginning of text section to the first + real instruction. */ + + vp->tadj = sect->filepos - bfd_section_vma (abfd, sect); + } + else if (STREQ (bfd_section_name (abfd, sect), ".data")) + { + vp->dstart = 0; + vp->dend = vp->dstart + bfd_section_size (abfd, sect); + } + /* Silently ignore other types of sections. (FIXME?) */ +} + +/* Make a vmap for ABFD which might be a member of the archive ARCH. + Return the new vmap. */ + +struct vmap * +map_vmap (abfd, arch) + bfd *abfd; + bfd *arch; +{ + struct vmap_and_bfd vmap_bfd; + struct vmap *vp, **vpp; + + vp = (struct vmap *) xmalloc (sizeof (*vp)); + memset ((char *) vp, '\0', sizeof (*vp)); + vp->nxt = 0; + vp->bfd = abfd; + vp->name = bfd_get_filename (arch ? arch : abfd); + vp->member = arch ? bfd_get_filename (abfd) : ""; + + vmap_bfd.pbfd = arch; + vmap_bfd.pvmap = vp; + bfd_map_over_sections (abfd, bfdsec_to_vmap, &vmap_bfd); + + /* Find the end of the list and append. */ + for (vpp = &vmap; *vpp; vpp = &(*vpp)->nxt) + ; + *vpp = vp; + + return vp; +} + +/* Read or write the exec file. + + Args are address within a BFD file, address within gdb address-space, + length, and a flag indicating whether to read or write. + + Result is a length: + + 0: We cannot handle this address and length. + > 0: We have handled N bytes starting at this address. + (If N == length, we did it all.) We might be able + to handle more bytes beyond this length, but no + promises. + < 0: We cannot handle this address, but if somebody + else handles (-N) bytes, we can start from there. + + The same routine is used to handle both core and exec files; + we just tail-call it with more arguments to select between them. */ + +int +xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + boolean res; + struct section_table *p; + CORE_ADDR nextsectaddr, memend; + boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + + if (len <= 0) + abort(); + + memend = memaddr + len; + xfer_fn = write ? bfd_set_section_contents : bfd_get_section_contents; + nextsectaddr = memend; + + for (p = target->to_sections; p < target->to_sections_end; p++) + { + if (p->addr <= memaddr) + if (p->endaddr >= memend) + { + /* Entire transfer is within this section. */ + res = xfer_fn (p->bfd, p->the_bfd_section, myaddr, + memaddr - p->addr, len); + return (res != 0) ? len : 0; + } + else if (p->endaddr <= memaddr) + { + /* This section ends before the transfer starts. */ + continue; + } + else + { + /* This section overlaps the transfer. Just do half. */ + len = p->endaddr - memaddr; + res = xfer_fn (p->bfd, p->the_bfd_section, myaddr, + memaddr - p->addr, len); + return (res != 0) ? len : 0; + } + else if (p->addr < nextsectaddr) + nextsectaddr = p->addr; + } + + if (nextsectaddr >= memend) + return 0; /* We can't help */ + else + return - (nextsectaddr - memaddr); /* Next boundary where we can help */ +} + +#ifdef FIXME +#ifdef REG_STACK_SEGMENT +/* MOVE TO BFD... */ + /* Pyramids and AM29000s have an extra segment in the virtual address space + for the (control) stack of register-window frames. The AM29000 folk + call it the "register stack" rather than the "memory stack". */ + else if (memaddr >= reg_stack_start && memaddr < reg_stack_end) + { + i = min (len, reg_stack_end - memaddr); + fileptr = memaddr - reg_stack_start + reg_stack_offset; + wanna_xfer = coredata; + } +#endif /* REG_STACK_SEGMENT */ +#endif /* FIXME */ + +void +print_section_info (t, abfd) + struct target_ops *t; + bfd *abfd; +{ + struct section_table *p; + + printf_filtered ("\t`%s', ", bfd_get_filename(abfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(abfd)); + if (abfd == exec_bfd) + { + printf_filtered ("\tEntry point: "); + print_address_numeric (bfd_get_start_address (abfd), 1, gdb_stdout); + printf_filtered ("\n"); + } + for (p = t->to_sections; p < t->to_sections_end; p++) + { + /* FIXME-32x64 need a print_address_numeric with field width */ + printf_filtered ("\t%s", local_hex_string_custom ((unsigned long) p->addr, "08l")); + printf_filtered (" - %s", local_hex_string_custom ((unsigned long) p->endaddr, "08l")); + if (info_verbose) + printf_filtered (" @ %s", + local_hex_string_custom ((unsigned long) p->the_bfd_section->filepos, "08l")); + printf_filtered (" is %s", bfd_section_name (p->bfd, p->the_bfd_section)); + if (p->bfd != abfd) + { + printf_filtered (" in %s", bfd_get_filename (p->bfd)); + } + printf_filtered ("\n"); + } +} + +static void +exec_files_info (t) + struct target_ops *t; +{ + print_section_info (t, exec_bfd); + + if (vmap) + { + struct vmap *vp; + + printf_unfiltered ("\tMapping info for file `%s'.\n", vmap->name); + printf_unfiltered ("\t %8.8s %8.8s %8.8s %8.8s %8.8s %s\n", + "tstart", "tend", "dstart", "dend", "section", + "file(member)"); + + for (vp = vmap; vp; vp = vp->nxt) + printf_unfiltered ("\t0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x %s%s%s%s\n", + vp->tstart, vp->tend, vp->dstart, vp->dend, vp->name, + *vp->member ? "(" : "", vp->member, + *vp->member ? ")" : ""); + } +} + +static void +set_section_command (args, from_tty) + char *args; + int from_tty; +{ + struct section_table *p; + char *secname; + unsigned seclen; + unsigned long secaddr; + char secprint[100]; + long offset; + + if (args == 0) + error ("Must specify section name and its virtual address"); + + /* Parse out section name */ + for (secname = args; !isspace(*args); args++) ; + seclen = args - secname; + + /* Parse out new virtual address */ + secaddr = parse_and_eval_address (args); + + for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) { + if (!strncmp (secname, bfd_section_name (exec_bfd, p->the_bfd_section), seclen) + && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') { + offset = secaddr - p->addr; + p->addr += offset; + p->endaddr += offset; + if (from_tty) + exec_files_info(&exec_ops); + return; + } + } + if (seclen >= sizeof (secprint)) + seclen = sizeof (secprint) - 1; + strncpy (secprint, secname, seclen); + secprint[seclen] = '\0'; + error ("Section %s not found", secprint); +} + +/* If mourn is being called in all the right places, this could be say + `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ + +static int +ignore (addr, contents) + CORE_ADDR addr; + char *contents; +{ + return 0; +} + +struct target_ops exec_ops = { + "exec", /* to_shortname */ + "Local exec file", /* to_longname */ + "Use an executable file as a target.\n\ +Specify the filename of the executable file.", /* to_doc */ + exec_file_command, /* to_open */ + exec_close, /* to_close */ + find_default_attach, /* to_attach */ + 0, /* to_detach */ + 0, /* to_resume */ + 0, /* to_wait */ + 0, /* to_fetch_registers */ + 0, /* to_store_registers */ + 0, /* to_prepare_to_store */ + xfer_memory, /* to_xfer_memory */ + exec_files_info, /* to_files_info */ + ignore, /* to_insert_breakpoint */ + ignore, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + 0, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + find_default_create_inferior, /* to_create_inferior */ + 0, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + file_stratum, /* to_stratum */ + 0, /* to_next */ + 0, /* to_has_all_memory */ + 1, /* to_has_memory */ + 0, /* to_has_stack */ + 0, /* to_has_registers */ + 0, /* to_has_execution */ + 0, /* to_sections */ + 0, /* to_sections_end */ + OPS_MAGIC, /* to_magic */ +}; + +void +_initialize_exec() +{ + struct cmd_list_element *c; + + c = add_cmd ("file", class_files, file_command, + "Use FILE as program to be debugged.\n\ +It is read for its symbols, for getting the contents of pure memory,\n\ +and it is the program executed when you use the `run' command.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +($PATH) is searched for a command of that name.\n\ +No arg means to have no executable file and no symbols.", &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("exec-file", class_files, exec_file_command, + "Use FILE as program for getting contents of pure memory.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +is searched for a command of that name.\n\ +No arg means have no executable file.", &cmdlist); + c->completer = filename_completer; + + add_com ("section", class_files, set_section_command, + "Change the base address of section SECTION of the exec file to ADDR.\n\ +This can be used if the exec file does not contain section addresses,\n\ +(such as in the a.out format), or when the addresses specified in the\n\ +file itself are wrong. Each section must be changed separately. The\n\ +``info files'' command lists all the sections and their addresses."); + + add_show_from_set + (add_set_cmd ("write", class_support, var_boolean, (char *)&write_files, + "Set writing into executable and core files.", + &setlist), + &showlist); + + add_target (&exec_ops); +} diff --git a/contrib/gdb/gdb/expprint.c b/contrib/gdb/gdb/expprint.c new file mode 100644 index 000000000000..b44ada2ab52a --- /dev/null +++ b/contrib/gdb/gdb/expprint.c @@ -0,0 +1,634 @@ +/* Print in infix form a struct expression. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "language.h" +#include "parser-defs.h" + +/* Prototypes for local functions */ + +static void +print_subexp PARAMS ((struct expression *, int *, GDB_FILE *, enum precedence)); + +void +print_expression (exp, stream) + struct expression *exp; + GDB_FILE *stream; +{ + int pc = 0; + print_subexp (exp, &pc, stream, PREC_NULL); +} + +/* Print the subexpression of EXP that starts in position POS, on STREAM. + PREC is the precedence of the surrounding operator; + if the precedence of the main operator of this subexpression is less, + parentheses are needed here. */ + +static void +print_subexp (exp, pos, stream, prec) + register struct expression *exp; + register int *pos; + GDB_FILE *stream; + enum precedence prec; +{ + register unsigned tem; + register const struct op_print *op_print_tab; + register int pc; + unsigned nargs; + register char *op_str; + int assign_modify = 0; + enum exp_opcode opcode; + enum precedence myprec = PREC_NULL; + /* Set to 1 for a right-associative operator. */ + int assoc = 0; + value_ptr val; + char *tempstr = NULL; + + op_print_tab = exp->language_defn->la_op_print_tab; + pc = (*pos)++; + opcode = exp->elts[pc].opcode; + switch (opcode) + { + /* Common ops */ + + case OP_SCOPE: + myprec = PREC_PREFIX; + assoc = 0; + fputs_filtered (type_name_no_tag (exp->elts[pc + 1].type), stream); + fputs_filtered ("::", stream); + nargs = longest_to_int (exp->elts[pc + 2].longconst); + (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1); + fputs_filtered (&exp->elts[pc + 3].string, stream); + return; + + case OP_LONG: + (*pos) += 3; + value_print (value_from_longest (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_DOUBLE: + (*pos) += 3; + value_print (value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_VAR_VALUE: + { + struct block *b; + (*pos) += 3; + b = exp->elts[pc + 1].block; + if (b != NULL + && BLOCK_FUNCTION (b) != NULL + && SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)) != NULL) + { + fputs_filtered (SYMBOL_SOURCE_NAME (BLOCK_FUNCTION (b)), stream); + fputs_filtered ("::", stream); + } + fputs_filtered (SYMBOL_SOURCE_NAME (exp->elts[pc + 2].symbol), stream); + } + return; + + case OP_LAST: + (*pos) += 2; + fprintf_filtered (stream, "$%d", + longest_to_int (exp->elts[pc + 1].longconst)); + return; + + case OP_REGISTER: + (*pos) += 2; + fprintf_filtered (stream, "$%s", + reg_names[longest_to_int (exp->elts[pc + 1].longconst)]); + return; + + case OP_BOOL: + (*pos) += 2; + fprintf_filtered (stream, "%s", + longest_to_int (exp->elts[pc + 1].longconst) + ? "TRUE" : "FALSE"); + return; + + case OP_INTERNALVAR: + (*pos) += 2; + fprintf_filtered (stream, "$%s", + internalvar_name (exp->elts[pc + 1].internalvar)); + return; + + case OP_FUNCALL: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered (" (", stream); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + fputs_filtered (", ", stream); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fputs_filtered (")", stream); + return; + + case OP_NAME: + case OP_EXPRSTRING: + nargs = longest_to_int (exp -> elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1); + fputs_filtered (&exp->elts[pc + 2].string, stream); + return; + + case OP_STRING: + nargs = longest_to_int (exp -> elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1); + /* LA_PRINT_STRING will print using the current repeat count threshold. + If necessary, we can temporarily set it to zero, or pass it as an + additional parameter to LA_PRINT_STRING. -fnf */ + LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 0); + 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 (stream, "B''"); + return; + + case OP_ARRAY: + (*pos) += 3; + nargs = longest_to_int (exp->elts[pc + 2].longconst); + nargs -= longest_to_int (exp->elts[pc + 1].longconst); + nargs++; + tem = 0; + if (exp->elts[pc + 4].opcode == OP_LONG + && exp->elts[pc + 5].type == builtin_type_char + && exp->language_defn->la_language == language_c) + { + /* Attempt to print C character arrays using string syntax. + Walk through the args, picking up one character from each + of the OP_LONG expression elements. If any array element + does not match our expection of what we should find for + a simple string, revert back to array printing. Note that + the last expression element is an explicit null terminator + byte, which doesn't get printed. */ + tempstr = alloca (nargs); + pc += 4; + while (tem < nargs) + { + if (exp->elts[pc].opcode != OP_LONG + || exp->elts[pc + 1].type != builtin_type_char) + { + /* Not a simple array of char, use regular array printing. */ + tem = 0; + break; + } + else + { + tempstr[tem++] = + longest_to_int (exp->elts[pc + 2].longconst); + pc += 4; + } + } + } + if (tem > 0) + { + LA_PRINT_STRING (stream, tempstr, nargs - 1, 0); + (*pos) = pc; + } + else + { + int is_chill = exp->language_defn->la_language == language_chill; + fputs_filtered (is_chill ? " [" : " {", stream); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + { + fputs_filtered (", ", stream); + } + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fputs_filtered (is_chill ? "]" : "}", stream); + } + return; + + case OP_LABELED: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + + if (exp->language_defn->la_language == language_chill) + { + fputs_filtered (".", stream); + fputs_filtered (&exp->elts[pc + 2].string, stream); + fputs_filtered (exp->elts[*pos].opcode == OP_LABELED ? ", " + : ": ", + stream); + } + else + { + /* 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); + /* Print the subexpressions, forcing parentheses + around any binary operations within them. + This is more parentheses than are strictly necessary, + but it looks clearer. */ + print_subexp (exp, pos, stream, PREC_HYPER); + fputs_filtered (" ? ", stream); + print_subexp (exp, pos, stream, PREC_HYPER); + fputs_filtered (" : ", stream); + print_subexp (exp, pos, stream, PREC_HYPER); + if ((int) prec > (int) PREC_COMMA) + fputs_filtered (")", stream); + 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); + fputs_filtered (opcode == TERNOP_SLICE ? " : " : " UP ", stream); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + fputs_filtered (")", stream); + return; + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered (".", stream); + fputs_filtered (&exp->elts[pc + 2].string, stream); + return; + + /* Will not occur for Modula-2 */ + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("->", stream); + fputs_filtered (&exp->elts[pc + 2].string, stream); + return; + + + case BINOP_SUBSCRIPT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("[", stream); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + fputs_filtered ("]", stream); + return; + + case UNOP_POSTINCREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("++", stream); + return; + + case UNOP_POSTDECREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered ("--", stream); + return; + + case UNOP_CAST: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + fputs_filtered ("(", stream); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered (") ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + + case UNOP_MEMVAL: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered ("(", stream); + if (exp->elts[pc + 1].type->code == TYPE_CODE_FUNC && + exp->elts[pc + 3].opcode == OP_LONG) { + /* We have a minimal symbol fn, probably. It's encoded + as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address). + Swallow the OP_LONG (including both its opcodes); ignore + its type; print the value in the type of the MEMVAL. */ + (*pos) += 4; + val = value_at_lazy (exp->elts[pc + 1].type, + (CORE_ADDR) exp->elts[pc + 5].longconst); + value_print (val, stream, 0, Val_no_prettyprint); + } else { + fputs_filtered ("{", stream); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered ("} ", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + } + if ((int) prec > (int) PREC_PREFIX) + fputs_filtered (")", stream); + return; + + case BINOP_ASSIGN_MODIFY: + opcode = exp->elts[pc + 1].opcode; + (*pos) += 2; + myprec = PREC_ASSIGN; + assoc = 1; + assign_modify = 1; + op_str = "???"; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + break; + } + if (op_print_tab[tem].opcode != opcode) + /* Not found; don't try to keep going because we don't know how + to interpret further elements. */ + error ("Invalid expression"); + break; + + /* C++ ops */ + + case OP_THIS: + ++(*pos); + fputs_filtered ("this", stream); + return; + + /* Modula-2 ops */ + + case MULTI_SUBSCRIPT: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf_unfiltered (stream, " ["); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + fprintf_unfiltered (stream, ", "); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fprintf_unfiltered (stream, "]"); + return; + + case BINOP_VAL: + (*pos)+=2; + fprintf_unfiltered(stream,"VAL("); + type_print(exp->elts[pc+1].type,"",stream,0); + fprintf_unfiltered(stream,","); + print_subexp(exp,pos,stream,PREC_PREFIX); + fprintf_unfiltered(stream,")"); + return; + + case BINOP_INCL: + case BINOP_EXCL: + error("print_subexp: Not implemented."); + + /* Default ops */ + + default: + op_str = "???"; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + myprec = op_print_tab[tem].precedence; + assoc = op_print_tab[tem].right_assoc; + break; + } + if (op_print_tab[tem].opcode != opcode) + /* Not found; don't try to keep going because we don't know how + to interpret further elements. For example, this happens + if opcode is OP_TYPE. */ + error ("Invalid expression"); + } + + /* Note that PREC_BUILTIN will always emit parentheses. */ + if ((int) myprec < (int) prec) + fputs_filtered ("(", stream); + if ((int) opcode > (int) BINOP_END) + { + if (assoc) + { + /* Unary postfix operator. */ + print_subexp (exp, pos, stream, PREC_SUFFIX); + fputs_filtered (op_str, stream); + } + else + { + /* Unary prefix operator. */ + fputs_filtered (op_str, stream); + if (myprec == PREC_BUILTIN_FUNCTION) + fputs_filtered ("(", stream); + print_subexp (exp, pos, stream, PREC_PREFIX); + if (myprec == PREC_BUILTIN_FUNCTION) + fputs_filtered (")", stream); + } + } + else + { + /* Binary operator. */ + /* Print left operand. + If operator is right-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, + (enum precedence) ((int) myprec + assoc)); + /* Print the operator itself. */ + if (assign_modify) + fprintf_filtered (stream, " %s= ", op_str); + else if (op_str[0] == ',') + fprintf_filtered (stream, "%s ", op_str); + else + fprintf_filtered (stream, " %s ", op_str); + /* Print right operand. + If operator is left-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, + (enum precedence) ((int) myprec + !assoc)); + } + + if ((int) myprec < (int) prec) + fputs_filtered (")", stream); +} + +/* Return the operator corresponding to opcode OP as + a string. NULL indicates that the opcode was not found in the + current language table. */ +char * +op_string(op) + enum exp_opcode op; +{ + int tem; + register const struct op_print *op_print_tab; + + op_print_tab = current_language->la_op_print_tab; + for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++) + if (op_print_tab[tem].opcode == op) + return op_print_tab[tem].string; + return NULL; +} + +#ifdef DEBUG_EXPRESSIONS + +/* Support for dumping the raw data from expressions in a human readable + form. */ + +void +dump_expression (exp, stream, note) + struct expression *exp; + GDB_FILE *stream; + char *note; +{ + int elt; + char *opcode_name; + char *eltscan; + int eltsize; + + fprintf_filtered (stream, "Dump of expression @ "); + gdb_print_address (exp, stream); + fprintf_filtered (stream, ", %s:\n", note); + fprintf_filtered (stream, "\tLanguage %s, %d elements, %d bytes each.\n", + exp->language_defn->la_name, exp -> nelts, + sizeof (union exp_element)); + fprintf_filtered (stream, "\t%5s %20s %16s %s\n", "Index", "Opcode", + "Hex Value", "String Value"); + for (elt = 0; elt < exp -> nelts; elt++) + { + fprintf_filtered (stream, "\t%5d ", elt); + switch (exp -> elts[elt].opcode) + { + default: opcode_name = ""; break; + case OP_NULL: opcode_name = "OP_NULL"; break; + case BINOP_ADD: opcode_name = "BINOP_ADD"; break; + case BINOP_SUB: opcode_name = "BINOP_SUB"; break; + case BINOP_MUL: opcode_name = "BINOP_MUL"; break; + case BINOP_DIV: opcode_name = "BINOP_DIV"; break; + case BINOP_REM: opcode_name = "BINOP_REM"; break; + case BINOP_MOD: opcode_name = "BINOP_MOD"; break; + case BINOP_LSH: opcode_name = "BINOP_LSH"; break; + case BINOP_RSH: opcode_name = "BINOP_RSH"; break; + case BINOP_LOGICAL_AND: opcode_name = "BINOP_LOGICAL_AND"; break; + case BINOP_LOGICAL_OR: opcode_name = "BINOP_LOGICAL_OR"; break; + case BINOP_BITWISE_AND: opcode_name = "BINOP_BITWISE_AND"; break; + case BINOP_BITWISE_IOR: opcode_name = "BINOP_BITWISE_IOR"; break; + case BINOP_BITWISE_XOR: opcode_name = "BINOP_BITWISE_XOR"; break; + case BINOP_EQUAL: opcode_name = "BINOP_EQUAL"; break; + case BINOP_NOTEQUAL: opcode_name = "BINOP_NOTEQUAL"; break; + case BINOP_LESS: opcode_name = "BINOP_LESS"; break; + case BINOP_GTR: opcode_name = "BINOP_GTR"; break; + case BINOP_LEQ: opcode_name = "BINOP_LEQ"; break; + case BINOP_GEQ: opcode_name = "BINOP_GEQ"; break; + case BINOP_REPEAT: opcode_name = "BINOP_REPEAT"; break; + case BINOP_ASSIGN: opcode_name = "BINOP_ASSIGN"; break; + case BINOP_COMMA: opcode_name = "BINOP_COMMA"; break; + case BINOP_SUBSCRIPT: opcode_name = "BINOP_SUBSCRIPT"; break; + case MULTI_SUBSCRIPT: opcode_name = "MULTI_SUBSCRIPT"; break; + case BINOP_EXP: opcode_name = "BINOP_EXP"; break; + case BINOP_MIN: opcode_name = "BINOP_MIN"; break; + case BINOP_MAX: opcode_name = "BINOP_MAX"; break; + case BINOP_SCOPE: opcode_name = "BINOP_SCOPE"; break; + case STRUCTOP_MEMBER: opcode_name = "STRUCTOP_MEMBER"; break; + case STRUCTOP_MPTR: opcode_name = "STRUCTOP_MPTR"; break; + case BINOP_INTDIV: opcode_name = "BINOP_INTDIV"; break; + case BINOP_ASSIGN_MODIFY: opcode_name = "BINOP_ASSIGN_MODIFY"; break; + case BINOP_VAL: opcode_name = "BINOP_VAL"; break; + case BINOP_INCL: opcode_name = "BINOP_INCL"; break; + case BINOP_EXCL: opcode_name = "BINOP_EXCL"; break; + case BINOP_CONCAT: opcode_name = "BINOP_CONCAT"; break; + case BINOP_RANGE: opcode_name = "BINOP_RANGE"; break; + case BINOP_END: opcode_name = "BINOP_END"; break; + case TERNOP_COND: opcode_name = "TERNOP_COND"; break; + case TERNOP_SLICE: opcode_name = "TERNOP_SLICE"; break; + case TERNOP_SLICE_COUNT: opcode_name = "TERNOP_SLICE_COUNT"; break; + case OP_LONG: opcode_name = "OP_LONG"; break; + case OP_DOUBLE: opcode_name = "OP_DOUBLE"; break; + case OP_VAR_VALUE: opcode_name = "OP_VAR_VALUE"; break; + case OP_LAST: opcode_name = "OP_LAST"; break; + case OP_REGISTER: opcode_name = "OP_REGISTER"; break; + case OP_INTERNALVAR: opcode_name = "OP_INTERNALVAR"; break; + case OP_FUNCALL: opcode_name = "OP_FUNCALL"; break; + case OP_STRING: opcode_name = "OP_STRING"; break; + case OP_BITSTRING: opcode_name = "OP_BITSTRING"; break; + case OP_ARRAY: opcode_name = "OP_ARRAY"; break; + case UNOP_CAST: opcode_name = "UNOP_CAST"; break; + case UNOP_MEMVAL: opcode_name = "UNOP_MEMVAL"; break; + case UNOP_NEG: opcode_name = "UNOP_NEG"; break; + case UNOP_LOGICAL_NOT: opcode_name = "UNOP_LOGICAL_NOT"; break; + case UNOP_COMPLEMENT: opcode_name = "UNOP_COMPLEMENT"; break; + case UNOP_IND: opcode_name = "UNOP_IND"; break; + case UNOP_ADDR: opcode_name = "UNOP_ADDR"; break; + case UNOP_PREINCREMENT: opcode_name = "UNOP_PREINCREMENT"; break; + case UNOP_POSTINCREMENT: opcode_name = "UNOP_POSTINCREMENT"; break; + case UNOP_PREDECREMENT: opcode_name = "UNOP_PREDECREMENT"; break; + case UNOP_POSTDECREMENT: opcode_name = "UNOP_POSTDECREMENT"; break; + case UNOP_SIZEOF: opcode_name = "UNOP_SIZEOF"; break; + case UNOP_LOWER: opcode_name = "UNOP_LOWER"; break; + case UNOP_UPPER: opcode_name = "UNOP_UPPER"; break; + case UNOP_LENGTH: opcode_name = "UNOP_LENGTH"; break; + case UNOP_PLUS: opcode_name = "UNOP_PLUS"; break; + case UNOP_CAP: opcode_name = "UNOP_CAP"; break; + case UNOP_CHR: opcode_name = "UNOP_CHR"; break; + case UNOP_ORD: opcode_name = "UNOP_ORD"; break; + case UNOP_ABS: opcode_name = "UNOP_ABS"; break; + case UNOP_FLOAT: opcode_name = "UNOP_FLOAT"; break; + case UNOP_HIGH: opcode_name = "UNOP_HIGH"; break; + case UNOP_MAX: opcode_name = "UNOP_MAX"; break; + case UNOP_MIN: opcode_name = "UNOP_MIN"; break; + case UNOP_ODD: opcode_name = "UNOP_ODD"; break; + case UNOP_TRUNC: opcode_name = "UNOP_TRUNC"; break; + case OP_BOOL: opcode_name = "OP_BOOL"; break; + case OP_M2_STRING: opcode_name = "OP_M2_STRING"; break; + case STRUCTOP_STRUCT: opcode_name = "STRUCTOP_STRUCT"; break; + case STRUCTOP_PTR: opcode_name = "STRUCTOP_PTR"; break; + case OP_THIS: opcode_name = "OP_THIS"; break; + case OP_SCOPE: opcode_name = "OP_SCOPE"; break; + case OP_TYPE: opcode_name = "OP_TYPE"; break; + case OP_LABELED: opcode_name = "OP_LABELED"; break; + } + fprintf_filtered (stream, "%20s ", opcode_name); + fprintf_filtered (stream, +#if defined (PRINTF_HAS_LONG_LONG) + "%ll16x ", +#else + "%l16x ", +#endif + exp -> elts[elt].longconst); + + for (eltscan = (char *) &exp->elts[elt], + eltsize = sizeof (union exp_element) ; + eltsize-- > 0; + eltscan++) + { + fprintf_filtered (stream, "%c", + isprint (*eltscan) ? (*eltscan & 0xFF) : '.'); + } + fprintf_filtered (stream, "\n"); + } +} + +#endif /* DEBUG_EXPRESSIONS */ diff --git a/contrib/gdb/gdb/expression.h b/contrib/gdb/gdb/expression.h new file mode 100644 index 000000000000..6526db15a792 --- /dev/null +++ b/contrib/gdb/gdb/expression.h @@ -0,0 +1,386 @@ +/* Definitions for expressions stored in reversed prefix form, for GDB. + Copyright 1986, 1989, 1992, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (EXPRESSION_H) +#define EXPRESSION_H 1 + +#ifdef __STDC__ +struct block; /* Forward declaration for prototypes */ +#endif + +/* Definitions for saved C expressions. */ + +/* An expression is represented as a vector of union exp_element's. + Each exp_element is an opcode, except that some opcodes cause + the following exp_element to be treated as a long or double constant + or as a variable. The opcodes are obeyed, using a stack for temporaries. + The value is left on the temporary stack at the end. */ + +/* When it is necessary to include a string, + it can occupy as many exp_elements as it needs. + We find the length of the string using strlen, + divide to find out how many exp_elements are used up, + and skip that many. Strings, like numbers, are indicated + by the preceding opcode. */ + +enum exp_opcode +{ + /* Used when it's necessary to pass an opcode which will be ignored, + or to catch uninitialized values. */ + OP_NULL, + +/* BINOP_... operate on two values computed by following subexpressions, + replacing them by one result value. They take no immediate arguments. */ + + BINOP_ADD, /* + */ + BINOP_SUB, /* - */ + BINOP_MUL, /* * */ + BINOP_DIV, /* / */ + BINOP_REM, /* % */ + BINOP_MOD, /* mod (Knuth 1.2.4) */ + BINOP_LSH, /* << */ + BINOP_RSH, /* >> */ + BINOP_LOGICAL_AND, /* && */ + BINOP_LOGICAL_OR, /* || */ + BINOP_BITWISE_AND, /* & */ + BINOP_BITWISE_IOR, /* | */ + BINOP_BITWISE_XOR, /* ^ */ + BINOP_EQUAL, /* == */ + BINOP_NOTEQUAL, /* != */ + BINOP_LESS, /* < */ + BINOP_GTR, /* > */ + BINOP_LEQ, /* <= */ + BINOP_GEQ, /* >= */ + BINOP_REPEAT, /* @ */ + BINOP_ASSIGN, /* = */ + BINOP_COMMA, /* , */ + BINOP_SUBSCRIPT, /* x[y] */ + BINOP_EXP, /* Exponentiation */ + + /* C++. */ + + BINOP_MIN, /* ? */ + BINOP_SCOPE, /* :: */ + + /* STRUCTOP_MEMBER is used for pointer-to-member constructs. + X . * Y translates into X STRUCTOP_MEMBER Y. */ + STRUCTOP_MEMBER, + + /* STRUCTOP_MPTR is used for pointer-to-member constructs + when X is a pointer instead of an aggregate. */ + STRUCTOP_MPTR, + + /* end of C++. */ + + /* For Modula-2 integer division DIV */ + BINOP_INTDIV, + + BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on. + The following exp_element is another opcode, + a BINOP_, saying how to modify. + Then comes another BINOP_ASSIGN_MODIFY, + making three exp_elements in total. */ + + /* Modula-2 standard (binary) procedures */ + BINOP_VAL, + BINOP_INCL, + BINOP_EXCL, + + /* Concatenate two operands, such as character strings or bitstrings. + If the first operand is a integer expression, then it means concatenate + the second operand with itself that many times. */ + BINOP_CONCAT, + + /* For Chill and Pascal. */ + BINOP_IN, /* Returns 1 iff ARG1 IN ARG2. */ + + /* This is the "colon operator" used various places in Chill. */ + BINOP_RANGE, + + /* This must be the highest BINOP_ value, for expprint.c. */ + BINOP_END, + + /* Operates on three values computed by following subexpressions. */ + TERNOP_COND, /* ?: */ + + /* A sub-string/sub-array. Chill syntax: OP1(OP2:OP3). + Return elements OP2 through OP3 of OP1. */ + TERNOP_SLICE, + + /* A sub-string/sub-array. Chill syntax: OP1(OP2 UP OP3). + Return OP3 elements of OP1, starting with element OP2. */ + 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. . + The value of the first following subexpression is subscripted + by each of the next following subexpressions, one per dimension. */ + MULTI_SUBSCRIPT, + + /* The OP_... series take immediate following arguments. + After the arguments come another OP_... (the same one) + so that the grouping can be recognized from the end. */ + + /* OP_LONG is followed by a type pointer in the next exp_element + and the long constant value in the following exp_element. + Then comes another OP_LONG. + Thus, the operation occupies four exp_elements. */ + OP_LONG, + + /* OP_DOUBLE is similar but takes a DOUBLEST constant instead of a long. */ + OP_DOUBLE, + + /* OP_VAR_VALUE takes one struct block * in the following element, + and one struct symbol * in the following exp_element, followed by + another OP_VAR_VALUE, making four exp_elements. If the block is + non-NULL, evaluate the symbol relative to the innermost frame + executing in that block; if the block is NULL use the selected frame. */ + OP_VAR_VALUE, + + /* OP_LAST is followed by an integer in the next exp_element. + The integer is zero for the last value printed, + or it is the absolute number of a history element. + With another OP_LAST at the end, this makes three exp_elements. */ + OP_LAST, + + /* OP_REGISTER is followed by an integer in the next exp_element. + This is the number of a register to fetch (as an int). + With another OP_REGISTER at the end, this makes three exp_elements. */ + OP_REGISTER, + + /* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element. + With another OP_INTERNALVAR at the end, this makes three exp_elements. */ + OP_INTERNALVAR, + + /* OP_FUNCALL is followed by an integer in the next exp_element. + The integer is the number of args to the function call. + That many plus one values from following subexpressions + are used, the first one being the function. + The integer is followed by a repeat of OP_FUNCALL, + making three exp_elements. */ + OP_FUNCALL, + + /* This is EXACTLY like OP_FUNCALL but is semantically different. + In F77, array subscript expressions, substring expressions + and function calls are all exactly the same syntactically. They may + only be dismabiguated at runtime. Thus this operator, which + indicates that we have found something of the form ( ) */ + OP_F77_UNDETERMINED_ARGLIST, + + /* The following OP is a special one, it introduces a F77 complex + literal. It is followed by exactly two args that are doubles. */ + OP_COMPLEX, + + /* OP_STRING represents a string constant. + Its format is the same as that of a STRUCTOP, but the string + data is just made into a string constant when the operation + is executed. */ + 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_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 + integer that is the upper bound of the array. The second integer is + followed by a repeat of OP_ARRAY, making four exp_elements total. + The bounds are used to compute the number of following subexpressions + to consume, as well as setting the bounds in the created array constant. + The type of the elements is taken from the type of the first subexp, + and they must all match. */ + OP_ARRAY, + + /* UNOP_CAST is followed by a type pointer in the next exp_element. + With another UNOP_CAST at the end, this makes three exp_elements. + It casts the value of the following subexpression. */ + UNOP_CAST, + + /* UNOP_MEMVAL is followed by a type pointer in the next exp_element + With another UNOP_MEMVAL at the end, this makes three exp_elements. + It casts the contents of the word addressed by the value of the + following subexpression. */ + UNOP_MEMVAL, + + /* UNOP_... operate on one value from a following subexpression + and replace it with a result. They take no immediate arguments. */ + + UNOP_NEG, /* Unary - */ + UNOP_LOGICAL_NOT, /* Unary ! */ + UNOP_COMPLEMENT, /* Unary ~ */ + UNOP_IND, /* Unary * */ + UNOP_ADDR, /* Unary & */ + UNOP_PREINCREMENT, /* ++ before an expression */ + UNOP_POSTINCREMENT, /* ++ after an expression */ + UNOP_PREDECREMENT, /* -- before an expression */ + UNOP_POSTDECREMENT, /* -- after an expression */ + UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + + UNOP_PLUS, /* Unary plus */ + + UNOP_CAP, /* Modula-2 standard (unary) procedures */ + UNOP_CHR, + UNOP_ORD, + UNOP_ABS, + UNOP_FLOAT, + UNOP_HIGH, + UNOP_MAX, + UNOP_MIN, + UNOP_ODD, + UNOP_TRUNC, + + /* Chill builtin functions. */ + UNOP_LOWER, UNOP_UPPER, UNOP_LENGTH, UNOP_CARD, UNOP_CHMAX, UNOP_CHMIN, + + OP_BOOL, /* Modula-2 builtin BOOLEAN type */ + OP_M2_STRING, /* Modula-2 string constants */ + + /* STRUCTOP_... operate on a value from a following subexpression + by extracting a structure component specified by a string + that appears in the following exp_elements (as many as needed). + STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->". + They differ only in the error message given in case the value is + not suitable or the structure component specified is not found. + + The length of the string follows the opcode, followed by + BYTES_TO_EXP_ELEM(length) elements containing the data of the + string, followed by the length again and the opcode again. */ + + STRUCTOP_STRUCT, + STRUCTOP_PTR, + + + /* C++ */ + /* OP_THIS is just a placeholder for the class instance variable. + It just comes in a tight (OP_THIS, OP_THIS) pair. */ + OP_THIS, + + /* OP_SCOPE surrounds a type name and a field name. The type + name is encoded as one element, but the field name stays as + a string, which, of course, is variable length. */ + OP_SCOPE, + + /* Used to represent named structure field values in brace initializers + (or tuples as they are called in Chill). + The gcc C syntax is NAME:VALUE or .NAME=VALUE, the Chill syntax is + .NAME:VALUE. Multiple labels (as in the Chill syntax + .NAME1,.NAME2:VALUE) is represented as if it were + .NAME1:(.NAME2:VALUE) (though that is not valid Chill syntax). + + The NAME is represented as for STRUCTOP_STRUCT; VALUE follows. */ + 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. */ + OP_TYPE, + + /* An un-looked-up identifier. */ + OP_NAME, + + /* An unparsed expression. Used for Scheme (for now at least) */ + OP_EXPRSTRING +}; + +union exp_element +{ + enum exp_opcode opcode; + struct symbol *symbol; + LONGEST longconst; + DOUBLEST doubleconst; + /* Really sizeof (union exp_element) characters (or less for the last + element of a string). */ + char string; + struct type *type; + struct internalvar *internalvar; + struct block *block; +}; + +struct expression +{ + const struct language_defn *language_defn; /* language it was entered in */ + int nelts; + union exp_element elts[1]; +}; + +/* Macros for converting between number of expression elements and bytes + to store that many expression elements. */ + +#define EXP_ELEM_TO_BYTES(elements) \ + ((elements) * sizeof (union exp_element)) +#define BYTES_TO_EXP_ELEM(bytes) \ + (((bytes) + sizeof (union exp_element) - 1) / sizeof (union exp_element)) + +/* From parse.c */ + +extern struct expression *parse_expression PARAMS ((char *)); + +extern struct expression *parse_exp_1 PARAMS ((char **, struct block *, int)); + +/* 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; + +/* From eval.c */ + +/* Values of NOSIDE argument to eval_subexp. */ + +enum noside +{ + EVAL_NORMAL, + EVAL_SKIP, /* Only effect is to increment pos. */ + EVAL_AVOID_SIDE_EFFECTS /* Don't modify any variables or + call any functions. The value + returned will have the correct + type, and will have an + approximately correct lvalue + type (inaccuracy: anything that is + listed as being in a register in + the function in which it was + declared will be lval_register). */ +}; + +extern struct value* evaluate_subexp_standard +PARAMS ((struct type *, struct expression *, int*, enum noside)); + +/* From expprint.c */ + +extern void print_expression PARAMS ((struct expression *, GDB_FILE *)); + +extern char *op_string PARAMS ((enum exp_opcode)); + +/* To enable dumping of all parsed expressions in a human readable + form, define DEBUG_EXPRESSIONS. This is a compile time constant + at the moment, since it's not clear that this feature is important + enough to include by default. */ + +#ifdef DEBUG_EXPRESSIONS +extern void dump_expression PARAMS ((struct expression *, GDB_FILE *, char *)); +#define DUMP_EXPRESSION(exp,file,note) dump_expression ((exp), (file), (note)) +#else +#define DUMP_EXPRESSION(exp,file,note) /* Null expansion */ +#endif /* DEBUG_EXPRESSIONS */ + +#endif /* !defined (EXPRESSION_H) */ diff --git a/contrib/gdb/gdb/f-exp.tab.c b/contrib/gdb/gdb/f-exp.tab.c new file mode 100644 index 000000000000..5ba51daa9b5d --- /dev/null +++ b/contrib/gdb/gdb/f-exp.tab.c @@ -0,0 +1,2089 @@ + +/* A Bison parser, made from ./f-exp.y with Bison version GNU Bison version 1.24 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define INT 258 +#define FLOAT 259 +#define STRING_LITERAL 260 +#define BOOLEAN_LITERAL 261 +#define NAME 262 +#define TYPENAME 263 +#define NAME_OR_INT 264 +#define SIZEOF 265 +#define ERROR 266 +#define INT_KEYWORD 267 +#define INT_S2_KEYWORD 268 +#define LOGICAL_S1_KEYWORD 269 +#define LOGICAL_S2_KEYWORD 270 +#define LOGICAL_KEYWORD 271 +#define REAL_KEYWORD 272 +#define REAL_S8_KEYWORD 273 +#define REAL_S16_KEYWORD 274 +#define COMPLEX_S8_KEYWORD 275 +#define COMPLEX_S16_KEYWORD 276 +#define COMPLEX_S32_KEYWORD 277 +#define BOOL_AND 278 +#define BOOL_OR 279 +#define BOOL_NOT 280 +#define CHARACTER 281 +#define VARIABLE 282 +#define ASSIGN_MODIFY 283 +#define ABOVE_COMMA 284 +#define EQUAL 285 +#define NOTEQUAL 286 +#define LESSTHAN 287 +#define GREATERTHAN 288 +#define LEQ 289 +#define GEQ 290 +#define LSH 291 +#define RSH 292 +#define UNARY 293 + +#line 43 "./f-exp.y" + + +#include "defs.h" +#include "gdb_string.h" +#include "expression.h" +#include "value.h" +#include "parser-defs.h" +#include "language.h" +#include "f-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 */ + +/* 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 f_maxdepth +#define yyparse f_parse +#define yylex f_lex +#define yyerror f_error +#define yylval f_lval +#define yychar f_char +#define yydebug f_debug +#define yypact f_pact +#define yyr1 f_r1 +#define yyr2 f_r2 +#define yydef f_def +#define yychk f_chk +#define yypgo f_pgo +#define yyact f_act +#define yyexca f_exca +#define yyerrflag f_errflag +#define yynerrs f_nerrs +#define yyps f_ps +#define yypv f_pv +#define yys f_s +#define yy_yys f_yys +#define yystate f_state +#define yytmp f_tmp +#define yyv f_v +#define yy_yyv f_yyv +#define yyval f_val +#define yylloc f_lloc +#define yyreds f_reds /* With YYDEBUG defined */ +#define yytoks f_toks /* With YYDEBUG defined */ +#define yylhs f_yylhs +#define yylen f_yylen +#define yydefred f_yydefred +#define yydgoto f_yydgoto +#define yysindex f_yysindex +#define yyrindex f_yyrindex +#define yygindex f_yygindex +#define yytable f_yytable +#define yycheck f_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 1 /* Default to no yydebug support */ +#endif + +int yyparse PARAMS ((void)); + +static int yylex PARAMS ((void)); + +void yyerror PARAMS ((char *)); + + +#line 118 "./f-exp.y" +typedef union + { + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + DOUBLEST dval; + 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 type **tvec; + int *ivec; + } YYSTYPE; +#line 140 "./f-exp.y" + +/* YYSTYPE gets defined by %union */ +static int parse_number PARAMS ((char *, int, int, YYSTYPE *)); + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 125 +#define YYFLAG -32768 +#define YYNTBASE 55 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 293 ? yytranslate[x] : 71) + +static const char 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, 49, 35, 2, 51, + 52, 47, 45, 29, 46, 2, 48, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 54, 2, 2, + 31, 2, 32, 44, 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, 34, 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, 33, 2, 53, 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, 21, 22, 23, 24, 25, + 26, 27, 28, 30, 36, 37, 38, 39, 40, 41, + 42, 43, 50 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 2, 4, 6, 10, 13, 16, 19, 22, 25, + 28, 29, 35, 36, 38, 40, 44, 48, 52, 56, + 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, + 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, + 141, 145, 147, 149, 151, 153, 155, 160, 162, 164, + 166, 168, 170, 173, 175, 178, 180, 183, 185, 189, + 192, 194, 197, 201, 203, 205, 207, 209, 211, 213, + 215, 217, 219, 221, 223, 225, 227, 229, 231, 235, + 237, 239, 241 +}; + +static const short yyrhs[] = { 57, + 0, 56, 0, 63, 0, 51, 57, 52, 0, 47, + 57, 0, 35, 57, 0, 46, 57, 0, 25, 57, + 0, 53, 57, 0, 10, 57, 0, 0, 57, 51, + 58, 59, 52, 0, 0, 57, 0, 60, 0, 59, + 29, 57, 0, 57, 54, 57, 0, 57, 29, 57, + 0, 51, 61, 52, 0, 51, 63, 52, 57, 0, + 57, 44, 57, 0, 57, 47, 57, 0, 57, 48, + 57, 0, 57, 49, 57, 0, 57, 45, 57, 0, + 57, 46, 57, 0, 57, 42, 57, 0, 57, 43, + 57, 0, 57, 36, 57, 0, 57, 37, 57, 0, + 57, 40, 57, 0, 57, 41, 57, 0, 57, 38, + 57, 0, 57, 39, 57, 0, 57, 35, 57, 0, + 57, 34, 57, 0, 57, 33, 57, 0, 57, 23, + 57, 0, 57, 24, 57, 0, 57, 31, 57, 0, + 57, 28, 57, 0, 3, 0, 9, 0, 4, 0, + 62, 0, 27, 0, 10, 51, 63, 52, 0, 6, + 0, 5, 0, 70, 0, 64, 0, 68, 0, 68, + 65, 0, 47, 0, 47, 65, 0, 35, 0, 35, + 65, 0, 66, 0, 51, 65, 52, 0, 66, 67, + 0, 67, 0, 51, 52, 0, 51, 69, 52, 0, + 8, 0, 12, 0, 13, 0, 26, 0, 16, 0, + 15, 0, 14, 0, 17, 0, 18, 0, 19, 0, + 20, 0, 21, 0, 22, 0, 8, 0, 63, 0, + 69, 29, 63, 0, 7, 0, 8, 0, 9, 0, + 7, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 217, 218, 221, 227, 232, 235, 238, 242, 246, 250, + 259, 261, 267, 270, 274, 277, 281, 286, 290, 294, + 302, 306, 310, 314, 318, 322, 326, 330, 334, 338, + 342, 346, 350, 354, 358, 362, 366, 370, 375, 379, + 383, 389, 396, 405, 412, 415, 418, 426, 433, 441, + 485, 488, 489, 532, 534, 536, 538, 540, 543, 545, + 547, 551, 553, 558, 560, 562, 564, 566, 568, 570, + 572, 574, 576, 578, 580, 582, 586, 590, 595, 602, + 604, 606, 610 +}; + +static const char * const yytname[] = { "$","error","$undefined.","INT","FLOAT", +"STRING_LITERAL","BOOLEAN_LITERAL","NAME","TYPENAME","NAME_OR_INT","SIZEOF", +"ERROR","INT_KEYWORD","INT_S2_KEYWORD","LOGICAL_S1_KEYWORD","LOGICAL_S2_KEYWORD", +"LOGICAL_KEYWORD","REAL_KEYWORD","REAL_S8_KEYWORD","REAL_S16_KEYWORD","COMPLEX_S8_KEYWORD", +"COMPLEX_S16_KEYWORD","COMPLEX_S32_KEYWORD","BOOL_AND","BOOL_OR","BOOL_NOT", +"CHARACTER","VARIABLE","ASSIGN_MODIFY","','","ABOVE_COMMA","'='","'?'","'|'", +"'^'","'&'","EQUAL","NOTEQUAL","LESSTHAN","GREATERTHAN","LEQ","GEQ","LSH","RSH", +"'@'","'+'","'-'","'*'","'/'","'%'","UNARY","'('","')'","'~'","':'","start", +"type_exp","exp","@1","arglist","substring","complexnum","variable","type","ptype", +"abs_decl","direct_abs_decl","func_mod","typebase","nonempty_typelist","name_not_typename", +"" +}; +#endif + +static const short yyr1[] = { 0, + 55, 55, 56, 57, 57, 57, 57, 57, 57, 57, + 58, 57, 59, 59, 59, 59, 60, 61, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 62, + 63, 64, 64, 65, 65, 65, 65, 65, 66, 66, + 66, 67, 67, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, -1, 69, 69, -1, + -1, -1, 70 +}; + +static const short yyr2[] = { 0, + 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, + 0, 5, 0, 1, 1, 3, 3, 3, 3, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 4, 1, 1, 1, + 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, + 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1 +}; + +static const short yydefact[] = { 0, + 42, 44, 49, 48, 83, 64, 43, 0, 65, 66, + 70, 69, 68, 71, 72, 73, 74, 75, 76, 0, + 67, 46, 0, 0, 0, 0, 0, 2, 1, 45, + 3, 51, 52, 50, 0, 10, 8, 6, 7, 5, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 11, 56, 54, 0, 53, + 58, 61, 0, 0, 4, 19, 0, 38, 39, 41, + 40, 37, 36, 35, 29, 30, 33, 34, 31, 32, + 27, 28, 21, 25, 26, 22, 23, 24, 13, 57, + 55, 62, 78, 0, 0, 0, 60, 47, 18, 20, + 14, 0, 15, 59, 0, 63, 0, 0, 12, 79, + 17, 16, 0, 0, 0 +}; + +static const short yydefgoto[] = { 123, + 28, 41, 99, 112, 113, 42, 30, 103, 32, 70, + 71, 72, 33, 105, 34 +}; + +static const short yypact[] = { 75, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 126,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 135, +-32768,-32768, 135, 135, 135, 75, 135,-32768, 309,-32768, +-32768,-32768, -34,-32768, 75, -49, -49, -49, -49, -49, + 279, -46, -45, -49, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135,-32768, -34, -34, 206,-32768, + -42,-32768, -36, 135,-32768,-32768, 135, 355, 336, 309, + 309, 390, 407, 161, 221, 221, -11, -11, -11, -11, + 22, 22, 58, -37, -37, -49, -49, -49, 135,-32768, +-32768,-32768,-32768, -33, -26, 230,-32768, 186, 309, -49, + 250, -24,-32768,-32768, 397,-32768, 135, 135,-32768,-32768, + 309, 309, 15, 18,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, 0,-32768,-32768,-32768,-32768,-32768, 4,-32768, -25, +-32768, -50,-32768,-32768,-32768 +}; + + +#define YYLAST 458 + + +static const short yytable[] = { 29, + 67, 66, 115, 31, 118, 76, 77, 36, 106, 63, + 64, 65, 68, 66, 124, 108, 69, 125, 114, 37, + 107, 0, 38, 39, 40, 116, 44, 119, 0, 43, + 58, 59, 60, 61, 62, 63, 64, 65, 73, 66, + 0, 100, 101, 104, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 60, 61, 62, 63, 64, + 65, 0, 66, 109, 0, 0, 110, 1, 2, 3, + 4, 5, 6, 7, 8, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 0, 111, 20, + 21, 22, 61, 62, 63, 64, 65, 110, 66, 23, + 0, 0, 0, 0, 0, 0, 121, 122, 120, 0, + 24, 25, 0, 0, 0, 26, 0, 27, 1, 2, + 3, 4, 5, 0, 7, 8, 0, 1, 2, 3, + 4, 5, 0, 7, 8, 0, 0, 0, 0, 0, + 20, 0, 22, 0, 0, 0, 0, 0, 0, 20, + 23, 22, 0, 0, 0, 0, 0, 0, 0, 23, + 0, 24, 25, 0, 0, 0, 35, 0, 27, 0, + 24, 25, 0, 0, 0, 26, 0, 27, 1, 2, + 3, 4, 5, 0, 7, 8, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 20, 66, 22, 6, 0, 0, 0, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 21, 0, 0, 0, 0, 26, 6, 27, 0, + 67, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 68, 0, 0, 21, 69, 102, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 0, 66, 45, 46, 0, 0, 0, 47, 0, 0, + 48, 102, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, + 66, 45, 46, 117, 0, 0, 47, 74, 0, 48, + 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 0, 66, + 75, 45, 46, 0, 0, 0, 47, 0, 0, 48, + 0, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 45, 66, + 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 0, 66, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 6, 66, 0, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, + 0, 0, 21, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, + 66, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 0, 66 +}; + +static const short yycheck[] = { 0, + 35, 51, 29, 0, 29, 52, 52, 8, 51, 47, + 48, 49, 47, 51, 0, 52, 51, 0, 52, 20, + 71, -1, 23, 24, 25, 52, 27, 52, -1, 26, + 42, 43, 44, 45, 46, 47, 48, 49, 35, 51, + -1, 67, 68, 69, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 44, 45, 46, 47, 48, + 49, -1, 51, 74, -1, -1, 77, 3, 4, 5, + 6, 7, 8, 9, 10, -1, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, -1, 99, 25, + 26, 27, 45, 46, 47, 48, 49, 108, 51, 35, + -1, -1, -1, -1, -1, -1, 117, 118, 115, -1, + 46, 47, -1, -1, -1, 51, -1, 53, 3, 4, + 5, 6, 7, -1, 9, 10, -1, 3, 4, 5, + 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, + 25, -1, 27, -1, -1, -1, -1, -1, -1, 25, + 35, 27, -1, -1, -1, -1, -1, -1, -1, 35, + -1, 46, 47, -1, -1, -1, 51, -1, 53, -1, + 46, 47, -1, -1, -1, 51, -1, 53, 3, 4, + 5, 6, 7, -1, 9, 10, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 25, 51, 27, 8, -1, -1, -1, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, -1, -1, + -1, 26, -1, -1, -1, -1, 51, 8, 53, -1, + 35, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 47, -1, -1, 26, 51, 52, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + -1, 51, 23, 24, -1, -1, -1, 28, -1, -1, + 31, 52, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, -1, + 51, 23, 24, 54, -1, -1, 28, 29, -1, 31, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, -1, 51, + 52, 23, 24, -1, -1, -1, 28, -1, -1, 31, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 23, 51, + -1, -1, -1, -1, -1, -1, -1, -1, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, -1, 51, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 8, 51, -1, -1, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, -1, + -1, -1, 26, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, -1, + 51, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, -1, 51 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/unsupported/share/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* 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); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (from, to, count) + char *from; + char *to; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *from, char *to, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 192 "/usr/unsupported/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#else +#define YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#endif + +int +yyparse(YYPARSE_PARAM) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to xreallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + 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 - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* 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; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +#line 222 "./f-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tval); + write_exp_elt_opcode(OP_TYPE); ; + break;} +case 4: +#line 228 "./f-exp.y" +{ ; + break;} +case 5: +#line 233 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_IND); ; + break;} +case 6: +#line 236 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); ; + break;} +case 7: +#line 239 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_NEG); ; + break;} +case 8: +#line 243 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); ; + break;} +case 9: +#line 247 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_COMPLEMENT); ; + break;} +case 10: +#line 251 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); ; + break;} +case 11: +#line 260 "./f-exp.y" +{ start_arglist (); ; + break;} +case 12: +#line 262 "./f-exp.y" +{ write_exp_elt_opcode (OP_F77_UNDETERMINED_ARGLIST); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_F77_UNDETERMINED_ARGLIST); ; + break;} +case 14: +#line 271 "./f-exp.y" +{ arglist_len = 1; ; + break;} +case 15: +#line 275 "./f-exp.y" +{ arglist_len = 2;; + break;} +case 16: +#line 278 "./f-exp.y" +{ arglist_len++; ; + break;} +case 17: +#line 282 "./f-exp.y" +{ ; + break;} +case 18: +#line 287 "./f-exp.y" +{ ; + break;} +case 19: +#line 291 "./f-exp.y" +{ write_exp_elt_opcode(OP_COMPLEX); ; + break;} +case 20: +#line 295 "./f-exp.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_CAST); ; + break;} +case 21: +#line 303 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); ; + break;} +case 22: +#line 307 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); ; + break;} +case 23: +#line 311 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); ; + break;} +case 24: +#line 315 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_REM); ; + break;} +case 25: +#line 319 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); ; + break;} +case 26: +#line 323 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); ; + break;} +case 27: +#line 327 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_LSH); ; + break;} +case 28: +#line 331 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_RSH); ; + break;} +case 29: +#line 335 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); ; + break;} +case 30: +#line 339 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); ; + break;} +case 31: +#line 343 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); ; + break;} +case 32: +#line 347 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); ; + break;} +case 33: +#line 351 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); ; + break;} +case 34: +#line 355 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); ; + break;} +case 35: +#line 359 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_AND); ; + break;} +case 36: +#line 363 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_XOR); ; + break;} +case 37: +#line 367 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_IOR); ; + break;} +case 38: +#line 371 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); ; + break;} +case 39: +#line 376 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); ; + break;} +case 40: +#line 380 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); ; + break;} +case 41: +#line 384 "./f-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode (yyvsp[-1].opcode); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); ; + break;} +case 42: +#line 390 "./f-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val.type); + write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 43: +#line 397 "./f-exp.y" +{ YYSTYPE val; + parse_number (yyvsp[0].ssym.stoken.ptr, yyvsp[0].ssym.stoken.length, 0, &val); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (val.typed_val.type); + write_exp_elt_longcst ((LONGEST)val.typed_val.val); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 44: +#line 406 "./f-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_f_real_s8); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); ; + break;} +case 47: +#line 419 "./f-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_f_integer); + CHECK_TYPEDEF (yyvsp[-1].tval); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 48: +#line 427 "./f-exp.y" +{ write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_BOOL); + ; + break;} +case 49: +#line 434 "./f-exp.y" +{ + write_exp_elt_opcode (OP_STRING); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_STRING); + ; + break;} +case 50: +#line 442 "./f-exp.y" +{ struct symbol *sym = yyvsp[0].ssym.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); + break; + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name (yyvsp[0].ssym.stoken); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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 (yyvsp[0].ssym.stoken)); + } + ; + break;} +case 53: +#line 490 "./f-exp.y" +{ + /* This is where the interesting stuff happens. */ + int done = 0; + int array_size; + struct type *follow_type = yyvsp[-1].tval; + struct type *range_type; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = pop_type_int (); + if (array_size != -1) + { + range_type = + create_range_type ((struct type *) NULL, + builtin_type_f_integer, 0, + array_size - 1); + follow_type = + create_array_type ((struct type *) NULL, + follow_type, range_type); + } + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + yyval.tval = follow_type; + ; + break;} +case 54: +#line 533 "./f-exp.y" +{ push_type (tp_pointer); yyval.voidval = 0; ; + break;} +case 55: +#line 535 "./f-exp.y" +{ push_type (tp_pointer); yyval.voidval = yyvsp[0].voidval; ; + break;} +case 56: +#line 537 "./f-exp.y" +{ push_type (tp_reference); yyval.voidval = 0; ; + break;} +case 57: +#line 539 "./f-exp.y" +{ push_type (tp_reference); yyval.voidval = yyvsp[0].voidval; ; + break;} +case 59: +#line 544 "./f-exp.y" +{ yyval.voidval = yyvsp[-1].voidval; ; + break;} +case 60: +#line 546 "./f-exp.y" +{ push_type (tp_function); ; + break;} +case 61: +#line 548 "./f-exp.y" +{ push_type (tp_function); ; + break;} +case 62: +#line 552 "./f-exp.y" +{ yyval.voidval = 0; ; + break;} +case 63: +#line 554 "./f-exp.y" +{ free ((PTR)yyvsp[-1].tvec); yyval.voidval = 0; ; + break;} +case 64: +#line 559 "./f-exp.y" +{ yyval.tval = yyvsp[0].tsym.type; ; + break;} +case 65: +#line 561 "./f-exp.y" +{ yyval.tval = builtin_type_f_integer; ; + break;} +case 66: +#line 563 "./f-exp.y" +{ yyval.tval = builtin_type_f_integer_s2; ; + break;} +case 67: +#line 565 "./f-exp.y" +{ yyval.tval = builtin_type_f_character; ; + break;} +case 68: +#line 567 "./f-exp.y" +{ yyval.tval = builtin_type_f_logical;; + break;} +case 69: +#line 569 "./f-exp.y" +{ yyval.tval = builtin_type_f_logical_s2;; + break;} +case 70: +#line 571 "./f-exp.y" +{ yyval.tval = builtin_type_f_logical_s1;; + break;} +case 71: +#line 573 "./f-exp.y" +{ yyval.tval = builtin_type_f_real;; + break;} +case 72: +#line 575 "./f-exp.y" +{ yyval.tval = builtin_type_f_real_s8;; + break;} +case 73: +#line 577 "./f-exp.y" +{ yyval.tval = builtin_type_f_real_s16;; + break;} +case 74: +#line 579 "./f-exp.y" +{ yyval.tval = builtin_type_f_complex_s8;; + break;} +case 75: +#line 581 "./f-exp.y" +{ yyval.tval = builtin_type_f_complex_s16;; + break;} +case 76: +#line 583 "./f-exp.y" +{ yyval.tval = builtin_type_f_complex_s32;; + break;} +case 78: +#line 591 "./f-exp.y" +{ yyval.tvec = (struct type **) xmalloc (sizeof (struct type *) * 2); + yyval.ivec[0] = 1; /* Number of types in vector */ + yyval.tvec[1] = yyvsp[0].tval; + ; + break;} +case 79: +#line 596 "./f-exp.y" +{ int len = sizeof (struct type *) * (++(yyvsp[-2].ivec[0]) + 1); + yyval.tvec = (struct type **) xrealloc ((char *) yyvsp[-2].tvec, len); + yyval.tvec[yyval.ivec[0]] = yyvsp[0].tval; + ; + break;} +case 80: +#line 603 "./f-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +case 81: +#line 605 "./f-exp.y" +{ yyval.sval = yyvsp[0].tsym.stoken; ; + break;} +case 82: +#line 607 "./f-exp.y" +{ yyval.sval = yyvsp[0].ssym.stoken; ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 487 "/usr/unsupported/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) xmalloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 620 "./f-exp.y" + + +/* 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) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register LONGEST prevn = 0; + register int i; + register int c; + register int base = input_radix; + int unsigned_p = 0; + int long_p = 0; + unsigned LONGEST high_bit; + struct type *signed_type; + struct type *unsigned_type; + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + /* [dD] is not understood as an exponent by atof, change it to 'e'. */ + char *tmp, *tmp2; + + tmp = strsave (p); + for (tmp2 = tmp; *tmp2; ++tmp2) + if (*tmp2 == 'd' || *tmp2 == 'D') + *tmp2 = 'e'; + putithere->dval = atof (tmp); + free (tmp); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 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') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + long_p = 1; + else if (len == 0 && c == 'u') + unsigned_p = 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). */ + if ((prevn >= n) && n != 0) + unsigned_p=1; /* Try something unsigned */ + /* If range checking enabled, portably test for unsigned overflow. */ + if (RANGE_CHECK && n != 0) + { + if ((unsigned_p && (unsigned)prevn >= (unsigned)n)) + range_error("Overflow on numeric constant."); + } + prevn = n; + } + + /* If the number is too big to be an int, or it's got an l suffix + then it's a long. Work out if this has to be a long by + shifting right and and seeing if anything remains, and the + target int size is different to the target long size. + + In the expression below, we could have tested + (n >> TARGET_INT_BIT) + to see if it was zero, + but too many compilers warn about that, when ints and longs + are the same size. So we shift it twice, with fewer bits + each time, for the same result. */ + + if ((TARGET_INT_BIT != TARGET_LONG_BIT + && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */ + || long_p) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + unsigned_type = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + + putithere->typed_val.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.type = unsigned_type; + else + putithere->typed_val.type = signed_type; + + return INT; +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static const struct token dot_ops[] = +{ + { ".and.", BOOL_AND, BINOP_END }, + { ".AND.", BOOL_AND, BINOP_END }, + { ".or.", BOOL_OR, BINOP_END }, + { ".OR.", BOOL_OR, BINOP_END }, + { ".not.", BOOL_NOT, BINOP_END }, + { ".NOT.", BOOL_NOT, BINOP_END }, + { ".eq.", EQUAL, BINOP_END }, + { ".EQ.", EQUAL, BINOP_END }, + { ".eqv.", EQUAL, BINOP_END }, + { ".NEQV.", NOTEQUAL, BINOP_END }, + { ".neqv.", NOTEQUAL, BINOP_END }, + { ".EQV.", EQUAL, BINOP_END }, + { ".ne.", NOTEQUAL, BINOP_END }, + { ".NE.", NOTEQUAL, BINOP_END }, + { ".le.", LEQ, BINOP_END }, + { ".LE.", LEQ, BINOP_END }, + { ".ge.", GEQ, BINOP_END }, + { ".GE.", GEQ, BINOP_END }, + { ".gt.", GREATERTHAN, BINOP_END }, + { ".GT.", GREATERTHAN, BINOP_END }, + { ".lt.", LESSTHAN, BINOP_END }, + { ".LT.", LESSTHAN, BINOP_END }, + { NULL, 0, 0 } +}; + +struct f77_boolean_val +{ + char *name; + int value; +}; + +static const struct f77_boolean_val boolean_values[] = +{ + { ".true.", 1 }, + { ".TRUE.", 1 }, + { ".false.", 0 }, + { ".FALSE.", 0 }, + { NULL, 0 } +}; + +static const struct token f77_keywords[] = +{ + { "complex_16", COMPLEX_S16_KEYWORD, BINOP_END }, + { "complex_32", COMPLEX_S32_KEYWORD, BINOP_END }, + { "character", CHARACTER, BINOP_END }, + { "integer_2", INT_S2_KEYWORD, BINOP_END }, + { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END }, + { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END }, + { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END }, + { "integer", INT_KEYWORD, BINOP_END }, + { "logical", LOGICAL_KEYWORD, BINOP_END }, + { "real_16", REAL_S16_KEYWORD, BINOP_END }, + { "complex", COMPLEX_S8_KEYWORD, BINOP_END }, + { "sizeof", SIZEOF, BINOP_END }, + { "real_8", REAL_S8_KEYWORD, BINOP_END }, + { "real", REAL_KEYWORD, BINOP_END }, + { NULL, 0, 0 } +}; + +/* Implementation of a dynamically expandable buffer for processing input + characters acquired through lexptr and building a value to return in + yylval. Ripped off from ch-exp.y */ + +static char *tempbuf; /* Current buffer contents */ +static int tempbufsize; /* Size of allocated buffer */ +static int tempbufindex; /* Current index into buffer */ + +#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */ + +#define CHECKBUF(size) \ + do { \ + if (tempbufindex + (size) >= tempbufsize) \ + { \ + growbuf_by_size (size); \ + } \ + } while (0); + + +/* Grow the static temp buffer if necessary, including allocating the first one + on demand. */ + +static void +growbuf_by_size (count) + int count; +{ + int growby; + + growby = max (count, GROWBY_MIN_SIZE); + tempbufsize += growby; + if (tempbuf == NULL) + tempbuf = (char *) xmalloc (tempbufsize); + else + tempbuf = (char *) xrealloc (tempbuf, tempbufsize); +} + +/* Blatantly ripped off from ch-exp.y. This routine recognizes F77 + string-literals. + + Recognize a string literal. A string literal is a nonzero sequence + of characters enclosed in matching single quotes, except that + a single character inside single quotes is a character literal, which + we reject as a string literal. To embed the terminator character inside + a string, it is simply doubled (I.E. 'this''is''one''string') */ + +static int +match_string_literal () +{ + char *tokptr = lexptr; + + for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++) + { + CHECKBUF (1); + if (*tokptr == *lexptr) + { + if (*(tokptr + 1) == *lexptr) + tokptr++; + else + break; + } + tempbuf[tempbufindex++] = *tokptr; + } + if (*tokptr == '\0' /* no terminator */ + || tempbufindex == 0) /* no string */ + return 0; + else + { + tempbuf[tempbufindex] = '\0'; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = ++tokptr; + return STRING_LITERAL; + } +} + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + int c; + int namelen; + unsigned int i,token; + char *tokstart; + + retry: + + tokstart = lexptr; + + /* First of all, let us make sure we are not dealing with the + special tokens .true. and .false. which evaluate to 1 and 0. */ + + if (*lexptr == '.') + { + for (i = 0; boolean_values[i].name != NULL; i++) + { + if STREQN (tokstart, boolean_values[i].name, + strlen (boolean_values[i].name)) + { + lexptr += strlen (boolean_values[i].name); + yylval.lval = boolean_values[i].value; + return BOOLEAN_LITERAL; + } + } + } + + /* See if it is a special .foo. operator */ + + for (i = 0; dot_ops[i].operator != NULL; i++) + if (STREQN (tokstart, dot_ops[i].operator, strlen (dot_ops[i].operator))) + { + lexptr += strlen (dot_ops[i].operator); + yylval.opcode = dot_ops[i].opcode; + return dot_ops[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + token = match_string_literal (); + if (token != 0) + return (token); + break; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + 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, got_d = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!hex && !got_d && (*p == 'd' || *p == 'D')) + got_dot = got_d = 1; + else if (!hex && !got_dot && *p == '.') + got_dot = 1; + else if (((got_e && (p[-1] == 'e' || p[-1] == 'E')) + || (got_d && (p[-1] == 'd' || p[-1] == 'D'))) + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e|got_d, + &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 '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + 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; + + /* Catch specific keywords. */ + + for (i = 0; f77_keywords[i].operator != NULL; i++) + if (STREQN(tokstart, f77_keywords[i].operator, + strlen(f77_keywords[i].operator))) + { + /* lexptr += strlen(f77_keywords[i].operator); */ + yylval.opcode = f77_keywords[i].opcode; + return f77_keywords[i].token; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + if (*tokstart == '$') + { + write_dollar_variable (yylval.sval); + return VARIABLE; + } + + /* 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; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : NULL, + NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* 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; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/f-exp.y b/contrib/gdb/gdb/f-exp.y new file mode 100644 index 000000000000..528d2154677f --- /dev/null +++ b/contrib/gdb/gdb/f-exp.y @@ -0,0 +1,1170 @@ +/* YACC parser for Fortran expressions, for GDB. + Copyright 1986, 1989, 1990, 1991, 1993, 1994 + Free Software Foundation, Inc. + Contributed by Motorola. Adapted from the C parser by Farooq Butt + (fmbutt@engage.sps.mot.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This was blantantly ripped off the C expression parser, please + be aware of that as you look at its basic structure -FMB */ + +/* Parse a F77 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 "expression.h" +#include "value.h" +#include "parser-defs.h" +#include "language.h" +#include "f-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 */ + +/* 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 f_maxdepth +#define yyparse f_parse +#define yylex f_lex +#define yyerror f_error +#define yylval f_lval +#define yychar f_char +#define yydebug f_debug +#define yypact f_pact +#define yyr1 f_r1 +#define yyr2 f_r2 +#define yydef f_def +#define yychk f_chk +#define yypgo f_pgo +#define yyact f_act +#define yyexca f_exca +#define yyerrflag f_errflag +#define yynerrs f_nerrs +#define yyps f_ps +#define yypv f_pv +#define yys f_s +#define yy_yys f_yys +#define yystate f_state +#define yytmp f_tmp +#define yyv f_v +#define yy_yyv f_yyv +#define yyval f_val +#define yylloc f_lloc +#define yyreds f_reds /* With YYDEBUG defined */ +#define yytoks f_toks /* With YYDEBUG defined */ +#define yylhs f_yylhs +#define yylen f_yylen +#define yydefred f_yydefred +#define yydgoto f_yydgoto +#define yysindex f_yysindex +#define yyrindex f_yyrindex +#define yygindex f_yygindex +#define yytable f_yytable +#define yycheck f_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 1 /* Default to no yydebug support */ +#endif + +int yyparse PARAMS ((void)); + +static int yylex PARAMS ((void)); + +void yyerror PARAMS ((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; + DOUBLEST dval; + 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 type **tvec; + int *ivec; + } + +%{ +/* YYSTYPE gets defined by %union */ +static int parse_number PARAMS ((char *, int, int, YYSTYPE *)); +%} + +%type exp type_exp start variable +%type type typebase +%type nonempty_typelist +/* %type block */ + +/* Fancy type parsing. */ +%type func_mod direct_abs_decl abs_decl +%type ptype + +%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_LITERAL +%token BOOLEAN_LITERAL +%token NAME +%token TYPENAME +%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 SIZEOF +%token ERROR + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token INT_KEYWORD INT_S2_KEYWORD LOGICAL_S1_KEYWORD LOGICAL_S2_KEYWORD +%token LOGICAL_KEYWORD REAL_KEYWORD REAL_S8_KEYWORD REAL_S16_KEYWORD +%token COMPLEX_S8_KEYWORD COMPLEX_S16_KEYWORD COMPLEX_S32_KEYWORD +%token BOOL_AND BOOL_OR BOOL_NOT +%token CHARACTER + +%token VARIABLE + +%token ASSIGN_MODIFY + +%left ',' +%left ABOVE_COMMA +%right '=' ASSIGN_MODIFY +%right '?' +%left BOOL_OR +%right BOOL_NOT +%left BOOL_AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left LESSTHAN GREATERTHAN LEQ GEQ +%left LSH RSH +%left '@' +%left '+' '-' +%left '*' '/' '%' +%right UNARY +%right '(' + + +%% + +start : exp + | type_exp + ; + +type_exp: type + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1); + write_exp_elt_opcode(OP_TYPE); } + ; + +exp : '(' exp ')' + { } + ; + +/* 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 : BOOL_NOT exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +exp : '~' exp %prec UNARY + { write_exp_elt_opcode (UNOP_COMPLEMENT); } + ; + +exp : SIZEOF exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + +/* No more explicit array operators, we treat everything in F77 as + a function call. The disambiguation as to whether we are + doing a subscript operation or a function call is done + later in eval.c. */ + +exp : exp '(' + { start_arglist (); } + arglist ')' + { write_exp_elt_opcode (OP_F77_UNDETERMINED_ARGLIST); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_F77_UNDETERMINED_ARGLIST); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : substring + { arglist_len = 2;} + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +substring: exp ':' exp %prec ABOVE_COMMA + { } + ; + + +complexnum: exp ',' exp + { } + ; + +exp : '(' complexnum ')' + { write_exp_elt_opcode(OP_COMPLEX); } + ; + +exp : '(' type ')' exp %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_CAST); } + ; + +/* 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 LESSTHAN exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp GREATERTHAN 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 BOOL_AND exp + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + + +exp : exp BOOL_OR exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +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.type); + write_exp_elt_longcst ((LONGEST)val.typed_val.val); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_f_real_s8); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : VARIABLE + ; + +exp : SIZEOF '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_f_integer); + CHECK_TYPEDEF ($3); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : BOOLEAN_LITERAL + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); + } + ; + +exp : STRING_LITERAL + { + write_exp_elt_opcode (OP_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_STRING); + } + ; + +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); + break; + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name ($1.stoken); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + 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)); + } + } + ; + + +type : ptype + ; + +ptype : typebase + | typebase abs_decl + { + /* This is where the interesting stuff happens. */ + int done = 0; + int array_size; + struct type *follow_type = $1; + struct type *range_type; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = pop_type_int (); + if (array_size != -1) + { + range_type = + create_range_type ((struct type *) NULL, + builtin_type_f_integer, 0, + array_size - 1); + follow_type = + create_array_type ((struct type *) NULL, + follow_type, range_type); + } + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + $$ = follow_type; + } + ; + +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 func_mod + { push_type (tp_function); } + | func_mod + { push_type (tp_function); } + ; + +func_mod: '(' ')' + { $$ = 0; } + | '(' nonempty_typelist ')' + { free ((PTR)$2); $$ = 0; } + ; + +typebase /* Implements (approximately): (type-qualifier)* type-specifier */ + : TYPENAME + { $$ = $1.type; } + | INT_KEYWORD + { $$ = builtin_type_f_integer; } + | INT_S2_KEYWORD + { $$ = builtin_type_f_integer_s2; } + | CHARACTER + { $$ = builtin_type_f_character; } + | LOGICAL_KEYWORD + { $$ = builtin_type_f_logical;} + | LOGICAL_S2_KEYWORD + { $$ = builtin_type_f_logical_s2;} + | LOGICAL_S1_KEYWORD + { $$ = builtin_type_f_logical_s1;} + | REAL_KEYWORD + { $$ = builtin_type_f_real;} + | REAL_S8_KEYWORD + { $$ = builtin_type_f_real_s8;} + | REAL_S16_KEYWORD + { $$ = builtin_type_f_real_s16;} + | COMPLEX_S8_KEYWORD + { $$ = builtin_type_f_complex_s8;} + | COMPLEX_S16_KEYWORD + { $$ = builtin_type_f_complex_s16;} + | COMPLEX_S32_KEYWORD + { $$ = builtin_type_f_complex_s32;} + ; + +typename: TYPENAME + ; + +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; } + | TYPENAME + { $$ = $1.stoken; } + | NAME_OR_INT + { $$ = $1.stoken; } + ; + +name_not_typename : NAME +/* 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) + register char *p; + register int len; + int parsed_float; + YYSTYPE *putithere; +{ + register LONGEST n = 0; + register LONGEST prevn = 0; + register int i; + register int c; + register int base = input_radix; + int unsigned_p = 0; + int long_p = 0; + unsigned LONGEST high_bit; + struct type *signed_type; + struct type *unsigned_type; + + if (parsed_float) + { + /* It's a float since it contains a point or an exponent. */ + /* [dD] is not understood as an exponent by atof, change it to 'e'. */ + char *tmp, *tmp2; + + tmp = strsave (p); + for (tmp2 = tmp; *tmp2; ++tmp2) + if (*tmp2 == 'd' || *tmp2 == 'D') + *tmp2 = 'e'; + putithere->dval = atof (tmp); + free (tmp); + return FLOAT; + } + + /* Handle base-switching prefixes 0x, 0t, 0d, 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') + n += i = c - '0'; + else + { + if (base > 10 && c >= 'a' && c <= 'f') + n += i = c - 'a' + 10; + else if (len == 0 && c == 'l') + long_p = 1; + else if (len == 0 && c == 'u') + unsigned_p = 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). */ + if ((prevn >= n) && n != 0) + unsigned_p=1; /* Try something unsigned */ + /* If range checking enabled, portably test for unsigned overflow. */ + if (RANGE_CHECK && n != 0) + { + if ((unsigned_p && (unsigned)prevn >= (unsigned)n)) + range_error("Overflow on numeric constant."); + } + prevn = n; + } + + /* If the number is too big to be an int, or it's got an l suffix + then it's a long. Work out if this has to be a long by + shifting right and and seeing if anything remains, and the + target int size is different to the target long size. + + In the expression below, we could have tested + (n >> TARGET_INT_BIT) + to see if it was zero, + but too many compilers warn about that, when ints and longs + are the same size. So we shift it twice, with fewer bits + each time, for the same result. */ + + if ((TARGET_INT_BIT != TARGET_LONG_BIT + && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */ + || long_p) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + unsigned_type = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + + putithere->typed_val.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.type = unsigned_type; + else + putithere->typed_val.type = signed_type; + + return INT; +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static const struct token dot_ops[] = +{ + { ".and.", BOOL_AND, BINOP_END }, + { ".AND.", BOOL_AND, BINOP_END }, + { ".or.", BOOL_OR, BINOP_END }, + { ".OR.", BOOL_OR, BINOP_END }, + { ".not.", BOOL_NOT, BINOP_END }, + { ".NOT.", BOOL_NOT, BINOP_END }, + { ".eq.", EQUAL, BINOP_END }, + { ".EQ.", EQUAL, BINOP_END }, + { ".eqv.", EQUAL, BINOP_END }, + { ".NEQV.", NOTEQUAL, BINOP_END }, + { ".neqv.", NOTEQUAL, BINOP_END }, + { ".EQV.", EQUAL, BINOP_END }, + { ".ne.", NOTEQUAL, BINOP_END }, + { ".NE.", NOTEQUAL, BINOP_END }, + { ".le.", LEQ, BINOP_END }, + { ".LE.", LEQ, BINOP_END }, + { ".ge.", GEQ, BINOP_END }, + { ".GE.", GEQ, BINOP_END }, + { ".gt.", GREATERTHAN, BINOP_END }, + { ".GT.", GREATERTHAN, BINOP_END }, + { ".lt.", LESSTHAN, BINOP_END }, + { ".LT.", LESSTHAN, BINOP_END }, + { NULL, 0, 0 } +}; + +struct f77_boolean_val +{ + char *name; + int value; +}; + +static const struct f77_boolean_val boolean_values[] = +{ + { ".true.", 1 }, + { ".TRUE.", 1 }, + { ".false.", 0 }, + { ".FALSE.", 0 }, + { NULL, 0 } +}; + +static const struct token f77_keywords[] = +{ + { "complex_16", COMPLEX_S16_KEYWORD, BINOP_END }, + { "complex_32", COMPLEX_S32_KEYWORD, BINOP_END }, + { "character", CHARACTER, BINOP_END }, + { "integer_2", INT_S2_KEYWORD, BINOP_END }, + { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END }, + { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END }, + { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END }, + { "integer", INT_KEYWORD, BINOP_END }, + { "logical", LOGICAL_KEYWORD, BINOP_END }, + { "real_16", REAL_S16_KEYWORD, BINOP_END }, + { "complex", COMPLEX_S8_KEYWORD, BINOP_END }, + { "sizeof", SIZEOF, BINOP_END }, + { "real_8", REAL_S8_KEYWORD, BINOP_END }, + { "real", REAL_KEYWORD, BINOP_END }, + { NULL, 0, 0 } +}; + +/* Implementation of a dynamically expandable buffer for processing input + characters acquired through lexptr and building a value to return in + yylval. Ripped off from ch-exp.y */ + +static char *tempbuf; /* Current buffer contents */ +static int tempbufsize; /* Size of allocated buffer */ +static int tempbufindex; /* Current index into buffer */ + +#define GROWBY_MIN_SIZE 64 /* Minimum amount to grow buffer by */ + +#define CHECKBUF(size) \ + do { \ + if (tempbufindex + (size) >= tempbufsize) \ + { \ + growbuf_by_size (size); \ + } \ + } while (0); + + +/* Grow the static temp buffer if necessary, including allocating the first one + on demand. */ + +static void +growbuf_by_size (count) + int count; +{ + int growby; + + growby = max (count, GROWBY_MIN_SIZE); + tempbufsize += growby; + if (tempbuf == NULL) + tempbuf = (char *) malloc (tempbufsize); + else + tempbuf = (char *) realloc (tempbuf, tempbufsize); +} + +/* Blatantly ripped off from ch-exp.y. This routine recognizes F77 + string-literals. + + Recognize a string literal. A string literal is a nonzero sequence + of characters enclosed in matching single quotes, except that + a single character inside single quotes is a character literal, which + we reject as a string literal. To embed the terminator character inside + a string, it is simply doubled (I.E. 'this''is''one''string') */ + +static int +match_string_literal () +{ + char *tokptr = lexptr; + + for (tempbufindex = 0, tokptr++; *tokptr != '\0'; tokptr++) + { + CHECKBUF (1); + if (*tokptr == *lexptr) + { + if (*(tokptr + 1) == *lexptr) + tokptr++; + else + break; + } + tempbuf[tempbufindex++] = *tokptr; + } + if (*tokptr == '\0' /* no terminator */ + || tempbufindex == 0) /* no string */ + return 0; + else + { + tempbuf[tempbufindex] = '\0'; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbufindex; + lexptr = ++tokptr; + return STRING_LITERAL; + } +} + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + int c; + int namelen; + unsigned int i,token; + char *tokstart; + + retry: + + tokstart = lexptr; + + /* First of all, let us make sure we are not dealing with the + special tokens .true. and .false. which evaluate to 1 and 0. */ + + if (*lexptr == '.') + { + for (i = 0; boolean_values[i].name != NULL; i++) + { + if STREQN (tokstart, boolean_values[i].name, + strlen (boolean_values[i].name)) + { + lexptr += strlen (boolean_values[i].name); + yylval.lval = boolean_values[i].value; + return BOOLEAN_LITERAL; + } + } + } + + /* See if it is a special .foo. operator */ + + for (i = 0; dot_ops[i].operator != NULL; i++) + if (STREQN (tokstart, dot_ops[i].operator, strlen (dot_ops[i].operator))) + { + lexptr += strlen (dot_ops[i].operator); + yylval.opcode = dot_ops[i].opcode; + return dot_ops[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + token = match_string_literal (); + if (token != 0) + return (token); + break; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + 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, got_d = 0, toktype; + register char *p = tokstart; + int hex = input_radix > 10; + + if (c == '0' && (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + hex = 1; + } + else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D')) + { + p += 2; + hex = 0; + } + + for (;; ++p) + { + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!hex && !got_d && (*p == 'd' || *p == 'D')) + got_dot = got_d = 1; + else if (!hex && !got_dot && *p == '.') + got_dot = 1; + else if (((got_e && (p[-1] == 'e' || p[-1] == 'E')) + || (got_d && (p[-1] == 'd' || p[-1] == 'D'))) + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + /* We will take any letters or digits. parse_number will + complain if past the radix, or if L or U are not final. */ + else if ((*p < '0' || *p > '9') + && ((*p < 'a' || *p > 'z') + && (*p < 'A' || *p > 'Z'))) + break; + } + toktype = parse_number (tokstart, p - tokstart, got_dot|got_e|got_d, + &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 '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + symbol: + lexptr++; + return c; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + 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; + + /* Catch specific keywords. */ + + for (i = 0; f77_keywords[i].operator != NULL; i++) + if (STREQN(tokstart, f77_keywords[i].operator, + strlen(f77_keywords[i].operator))) + { + /* lexptr += strlen(f77_keywords[i].operator); */ + yylval.opcode = f77_keywords[i].opcode; + return f77_keywords[i].token; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + if (*tokstart == '$') + { + write_dollar_variable (yylval.sval); + return VARIABLE; + } + + /* 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; + int hextype; + + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, + current_language->la_language == language_cplus + ? &is_a_field_of_this : NULL, + NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + yylval.tsym.type = SYMBOL_TYPE (sym); + return TYPENAME; + } + if ((yylval.tsym.type = lookup_primitive_typename (tmp)) != 0) + return TYPENAME; + + /* 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; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/f-lang.c b/contrib/gdb/gdb/f-lang.c new file mode 100644 index 000000000000..57a68099ece2 --- /dev/null +++ b/contrib/gdb/gdb/f-lang.c @@ -0,0 +1,944 @@ +/* Fortran language support routines for GDB, the GNU debugger. + Copyright 1993, 1994, 1996 Free Software Foundation, Inc. + Contributed by Motorola. Adapted from the C parser by Farooq Butt + (fmbutt@engage.sps.mot.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "f-lang.h" + +/* The built-in types of F77. FIXME: integer*4 is missing, plain + logical is missing (builtin_type_logical is logical*4). */ + +struct type *builtin_type_f_character; +struct type *builtin_type_f_logical; +struct type *builtin_type_f_logical_s1; +struct type *builtin_type_f_logical_s2; +struct type *builtin_type_f_integer; +struct type *builtin_type_f_integer_s2; +struct type *builtin_type_f_real; +struct type *builtin_type_f_real_s8; +struct type *builtin_type_f_real_s16; +struct type *builtin_type_f_complex_s8; +struct type *builtin_type_f_complex_s16; +struct type *builtin_type_f_complex_s32; +struct type *builtin_type_f_void; + +/* 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. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true F77 version. */ + +static void +emit_char (c, stream, quoter) + register int c; + 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; + } + } +} + +/* FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true F77version. */ + +static void +f_printchar (c, stream) + int c; + FILE *stream; +{ + fputs_filtered ("'", stream); + emit_char (c, 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. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true F77 version. */ + +static void +f_printstr (stream, string, length, force_ellipses) + FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + extern int inspect_it; + extern int repeat_count_threshold; + extern int print_max; + + if (length == 0) + { + fputs_filtered ("''", stdout); + return; + } + + for (i = 0; i < length && things_printed < 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 > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\', ", stream); + else + fputs_filtered ("', ", stream); + in_quotes = 0; + } + f_printchar (string[i], stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\'", stream); + else + fputs_filtered ("'", stream); + in_quotes = 1; + } + emit_char (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\'", stream); + else + fputs_filtered ("'", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* FIXME: This is a copy of c_create_fundamental_type(), before + all the non-C types were stripped from it. Needs to be fixed + by an experienced F77 programmer. */ + +static struct type * +f_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "VOID", objfile); + break; + case FT_BOOLEAN: + type = init_type (TYPE_CODE_BOOL, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "boolean", objfile); + break; + case FT_STRING: + type = init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "character", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "integer*1", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_BOOL, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "logical*1", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "integer*2", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); /* FIXME-fnf */ + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_BOOL, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "logical*2", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "integer*4", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "integer", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_BOOL, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "logical*4", objfile); + break; + case FT_FIXED_DECIMAL: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long long", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "signed long long", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "real", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "real*8", objfile); + break; + case FT_FLOAT_DECIMAL: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "real*16", objfile); + break; + case FT_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "complex*8", objfile); + TYPE_TARGET_TYPE (type) = builtin_type_f_real; + break; + case FT_DBL_PREC_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "complex*16", objfile); + TYPE_TARGET_TYPE (type) = builtin_type_f_real_s8; + break; + case FT_EXT_PREC_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "complex*32", objfile); + TYPE_TARGET_TYPE (type) = builtin_type_f_real_s16; + break; + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "", objfile); + warning ("internal error: no F77 fundamental type %d", typeid); + break; + } + return (type); +} + + +/* Table of operators and their precedences for printing expressions. */ + +static const struct op_print f_op_print_tab[] = { + { "+", BINOP_ADD, PREC_ADD, 0 }, + { "+", UNOP_PLUS, PREC_PREFIX, 0 }, + { "-", BINOP_SUB, PREC_ADD, 0 }, + { "-", UNOP_NEG, PREC_PREFIX, 0 }, + { "*", BINOP_MUL, PREC_MUL, 0 }, + { "/", BINOP_DIV, PREC_MUL, 0 }, + { "DIV", BINOP_INTDIV, PREC_MUL, 0 }, + { "MOD", BINOP_REM, PREC_MUL, 0 }, + { "=", BINOP_ASSIGN, PREC_ASSIGN, 1 }, + { ".OR.", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0 }, + { ".AND.", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0 }, + { ".NOT.", UNOP_LOGICAL_NOT, PREC_PREFIX, 0 }, + { ".EQ.", BINOP_EQUAL, PREC_EQUAL, 0 }, + { ".NE.", BINOP_NOTEQUAL, PREC_EQUAL, 0 }, + { ".LE.", BINOP_LEQ, PREC_ORDER, 0 }, + { ".GE.", BINOP_GEQ, PREC_ORDER, 0 }, + { ".GT.", BINOP_GTR, PREC_ORDER, 0 }, + { ".LT.", BINOP_LESS, PREC_ORDER, 0 }, + { "**", UNOP_IND, PREC_PREFIX, 0 }, + { "@", BINOP_REPEAT, PREC_REPEAT, 0 }, + { NULL, 0, 0, 0 } +}; + +struct type ** const (f_builtin_types[]) = +{ + &builtin_type_f_character, + &builtin_type_f_logical, + &builtin_type_f_logical_s1, + &builtin_type_f_logical_s2, + &builtin_type_f_integer, + &builtin_type_f_integer_s2, + &builtin_type_f_real, + &builtin_type_f_real_s8, + &builtin_type_f_real_s16, + &builtin_type_f_complex_s8, + &builtin_type_f_complex_s16, +#if 0 + &builtin_type_f_complex_s32, +#endif + &builtin_type_f_void, + 0 +}; + +int c_value_print(); + +const struct language_defn f_language_defn = { + "fortran", + language_fortran, + f_builtin_types, + range_check_on, + type_check_on, + f_parse, /* parser */ + f_error, /* parser error function */ + evaluate_subexp_standard, + f_printchar, /* Print character constant */ + f_printstr, /* function to print string constant */ + f_create_fundamental_type, /* Create fundamental type in this language */ + f_print_type, /* Print a type using appropriate syntax */ + f_val_print, /* Print a value using appropriate syntax */ + c_value_print, /* FIXME */ + {"", "", "", ""}, /* Binary format info */ + {"0%o", "0", "o", ""}, /* Octal format info */ + {"%d", "", "d", ""}, /* Decimal format info */ + {"0x%x", "0x", "x", ""}, /* Hex format info */ + f_op_print_tab, /* expression operators for printing */ + 0, /* arrays are first-class (not c-style) */ + 1, /* String lower bound */ + &builtin_type_f_character, /* Type of string elements */ + LANG_MAGIC + }; + +void +_initialize_f_language () +{ + builtin_type_f_void = + init_type (TYPE_CODE_VOID, 1, + 0, + "VOID", (struct objfile *) NULL); + + builtin_type_f_character = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "character", (struct objfile *) NULL); + + builtin_type_f_logical_s1 = + init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "logical*1", (struct objfile *) NULL); + + builtin_type_f_integer_s2 = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, + "integer*2", (struct objfile *) NULL); + + builtin_type_f_logical_s2 = + init_type (TYPE_CODE_BOOL, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "logical*2", (struct objfile *) NULL); + + builtin_type_f_integer = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "integer", (struct objfile *) NULL); + + builtin_type_f_logical = + init_type (TYPE_CODE_BOOL, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "logical*4", (struct objfile *) NULL); + + builtin_type_f_real = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "real", (struct objfile *) NULL); + + builtin_type_f_real_s8 = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "real*8", (struct objfile *) NULL); + + builtin_type_f_real_s16 = + init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "real*16", (struct objfile *) NULL); + + builtin_type_f_complex_s8 = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "complex*8", (struct objfile *) NULL); + TYPE_TARGET_TYPE (builtin_type_f_complex_s8) = builtin_type_f_real; + + builtin_type_f_complex_s16 = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "complex*16", (struct objfile *) NULL); + TYPE_TARGET_TYPE (builtin_type_f_complex_s16) = builtin_type_f_real_s8; + + /* We have a new size == 4 double floats for the + complex*32 data type */ + + builtin_type_f_complex_s32 = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "complex*32", (struct objfile *) NULL); + TYPE_TARGET_TYPE (builtin_type_f_complex_s32) = builtin_type_f_real_s16; + + builtin_type_string = + init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "character string", (struct objfile *) NULL); + + add_language (&f_language_defn); +} + +/* 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; + + +SAVED_BF_PTR allocate_saved_bf_node() +{ + SAVED_BF_PTR new; + + new = (SAVED_BF_PTR) xmalloc (sizeof (SAVED_BF)); + return(new); +} + +SAVED_FUNCTION *allocate_saved_function_node() +{ + SAVED_FUNCTION *new; + + new = (SAVED_FUNCTION *) xmalloc (sizeof (SAVED_FUNCTION)); + return(new); +} + +SAVED_F77_COMMON_PTR allocate_saved_f77_common_node() +{ + SAVED_F77_COMMON_PTR new; + + new = (SAVED_F77_COMMON_PTR) xmalloc (sizeof (SAVED_F77_COMMON)); + return(new); +} + +COMMON_ENTRY_PTR allocate_common_entry_node() +{ + COMMON_ENTRY_PTR new; + + new = (COMMON_ENTRY_PTR) xmalloc (sizeof (COMMON_ENTRY)); + return(new); +} + + +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 */ + +static SAVED_BF_PTR saved_bf_list=NULL; /* Ptr to (.bf,function) + list*/ +#if 0 +static SAVED_BF_PTR saved_bf_list_end=NULL; /* Ptr to above list's end */ +#endif +static SAVED_BF_PTR current_head_bf_list=NULL; /* Current head of above list + */ + +#if 0 +static SAVED_BF_PTR tmp_bf_ptr; /* Generic temporary for use + in macros */ +#endif + +/* The following function simply enters a given common block onto + the global common block chain */ + +void add_common_block(name,offset,secnum,func_stab) + 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 (STREQ(name,BLANK_COMMON_NAME_ORIGINAL) || + STREQ(name,BLANK_COMMON_NAME_MF77)) + { + + free(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; + } + +} + + +/* The following function simply enters a given common entry onto + the "current_common" block that has been saved away. */ + +void add_common_entry(entry_sym_ptr) + 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; + } + } + + +} + +/* This routine finds the first encountred COMMON block named "name" */ + +SAVED_F77_COMMON_PTR find_first_common_named(name) + char *name; +{ + + SAVED_F77_COMMON_PTR tmp; + + tmp = head_common_list; + + while (tmp != NULL) + { + if (STREQ(tmp->name,name)) + return(tmp); + else + tmp = tmp->next; + } + return(NULL); +} + +/* This routine finds the first encountred COMMON block named "name" + that belongs to function funcname */ + +SAVED_F77_COMMON_PTR find_common_for_function(name, funcname) + char *name; + char *funcname; +{ + + SAVED_F77_COMMON_PTR tmp; + + tmp = head_common_list; + + while (tmp != NULL) + { + if (STREQ(tmp->name,name) && STREQ(tmp->owning_function,funcname)) + return(tmp); + else + tmp = tmp->next; + } + return(NULL); +} + + + + +/* The following function is called to patch up the offsets + for the statics contained in the COMMON block named + "name." */ + + +void patch_common_entries (blk, offset, secnum) + 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). */ + + +void patch_all_commons_by_name (name, offset, secnum) + 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 ((STREQ(name,BLANK_COMMON_NAME_ORIGINAL)) || + (STREQ(name,BLANK_COMMON_NAME_MF77))) + { + free(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 (STREQ(tmp->name,name)) + patch_common_entries(tmp,offset,secnum); + + tmp = tmp->next; + } + +} + + + + + +/* 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 */ + +void + clear_bf_list() +{ + + SAVED_BF_PTR tmp = saved_bf_list; + SAVED_BF_PTR next = NULL; + + while (tmp != NULL) + { + next = tmp->next; + free(tmp); + tmp=next; + } + saved_bf_list = NULL; +} + +int global_remote_debug; + +long +get_bf_for_fcn (the_function) + 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) + fatal ("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(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(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(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; +#if 0 /* Currently unused */ +static SAVED_FUNCTION_PTR saved_function_list_end=NULL; +#endif + +void clear_function_list() +{ + SAVED_FUNCTION_PTR tmp = saved_function_list; + SAVED_FUNCTION_PTR next = NULL; + + while (tmp != NULL) + { + next = tmp->next; + free(tmp); + tmp = next; + } + + saved_function_list = NULL; +} diff --git a/contrib/gdb/gdb/f-lang.h b/contrib/gdb/gdb/f-lang.h new file mode 100644 index 000000000000..226b3993861b --- /dev/null +++ b/contrib/gdb/gdb/f-lang.h @@ -0,0 +1,94 @@ +/* Fortran language support definitions for GDB, the GNU debugger. + Copyright 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by Motorola. Adapted from the C definitions by Farooq Butt + (fmbutt@engage.sps.mot.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern int f_parse PARAMS ((void)); + +extern void f_error PARAMS ((char *)); /* Defined in f-exp.y */ + +extern void f_print_type PARAMS ((struct type *, char *, FILE *, int, int)); + +extern int f_val_print PARAMS ((struct type *, char *, CORE_ADDR, FILE *, + int, int, int, enum val_prettyprint)); + +/* Language-specific data structures */ + +struct common_entry +{ + struct symbol *symbol; /* The symbol node corresponding + to this component */ + struct common_entry *next; /* The next component */ +}; + +struct saved_f77_common +{ + char *name; /* Name of COMMON */ + char *owning_function; /* Name of parent function */ + int secnum; /* Section # of .bss */ + CORE_ADDR offset; /* Offset from .bss for + this block */ + struct common_entry *entries; /* List of block's components */ + struct common_entry *end_of_entries; /* ptr. to end of components */ + struct saved_f77_common *next; /* Next saved COMMON block */ +}; + +typedef struct saved_f77_common SAVED_F77_COMMON, *SAVED_F77_COMMON_PTR; + +typedef struct common_entry COMMON_ENTRY, *COMMON_ENTRY_PTR; + +extern SAVED_F77_COMMON_PTR head_common_list; /* Ptr to 1st saved COMMON */ +extern SAVED_F77_COMMON_PTR tail_common_list; /* Ptr to last saved COMMON */ +extern SAVED_F77_COMMON_PTR current_common; /* Ptr to current COMMON */ + +extern SAVED_F77_COMMON_PTR find_common_for_function PARAMS ((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 */ + +#define BOUND_FETCH_OK 1 +#define BOUND_FETCH_ERROR -999 + +/* 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 + +extern char *real_main_name; /* Name of main function */ +extern int real_main_c_value; /* C_value field of main function */ + +extern int f77_get_dynamic_upperbound PARAMS ((struct type *, int *)); + +extern int f77_get_dynamic_lowerbound PARAMS ((struct type *, int *)); + +extern void f77_get_dynamic_array_length PARAMS ((struct type *)); + +extern int calc_f77_array_dims PARAMS ((struct type *)); + +#define DEFAULT_DOTMAIN_NAME_IN_MF77 ".MAIN_" +#define DEFAULT_MAIN_NAME_IN_MF77 "MAIN_" +#define DEFAULT_DOTMAIN_NAME_IN_XLF_BUGGY ".main " +#define DEFAULT_DOTMAIN_NAME_IN_XLF ".main" diff --git a/contrib/gdb/gdb/f-typeprint.c b/contrib/gdb/gdb/f-typeprint.c new file mode 100644 index 000000000000..3ab6237c59d8 --- /dev/null +++ b/contrib/gdb/gdb/f-typeprint.c @@ -0,0 +1,454 @@ +/* Support for printing Fortran types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1993, 1994 Free Software Foundation, Inc. + Contributed by Motorola. Adapted from the C version by Farooq Butt + (fmbutt@engage.sps.mot.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "f-lang.h" +#include "typeprint.h" +#include "frame.h" /* ??? */ + +#include "gdb_string.h" +#include + +#if 0 /* Currently unused */ +static void f_type_print_args PARAMS ((struct type *, FILE *)); +#endif + +static void f_type_print_varspec_suffix PARAMS ((struct type *, FILE *, + int, int, int)); + +void f_type_print_varspec_prefix PARAMS ((struct type *, FILE *, int, int)); + +void f_type_print_base PARAMS ((struct type *, FILE *, int, int)); + + +/* LEVEL is the depth to indent lines by. */ + +void +f_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + register enum type_code code; + int demangled_args; + + f_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_MEMBER + || code == TYPE_CODE_REF))) + fputs_filtered (" ", stream); + f_type_print_varspec_prefix (type, stream, show, 0); + + fputs_filtered (varstring, stream); + + /* 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[strlen(varstring) - 1] == ')'; + f_type_print_varspec_suffix (type, stream, show, 0, demangled_args); +} + +/* Print any asterisks or open-parentheses needed before the + variable name (to describe its type). + + On outermost call, pass 0 for PASSED_A_PTR. + On outermost call, SHOW > 0 means should ignore + any typename for TYPE and show its details. + SHOW is always zero on recursive calls. */ + +void +f_type_print_varspec_prefix (type, stream, show, passed_a_ptr) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; +{ + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + f_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + break; + + case TYPE_CODE_FUNC: + f_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf_filtered (stream, "("); + break; + + case TYPE_CODE_ARRAY: + f_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_METHOD: + case TYPE_CODE_MEMBER: + case TYPE_CODE_REF: + case TYPE_CODE_COMPLEX: + case TYPE_CODE_TYPEDEF: + /* These types need no prefix. They are listed here so that + gcc -Wall will reveal any types that haven't been handled. */ + break; + } +} + +#if 0 /* Currently unused */ + +static void +f_type_print_args (type, stream) + struct type *type; + FILE *stream; +{ + int i; + struct type **args; + + fprintf_filtered (stream, "("); + args = TYPE_ARG_TYPES (type); + if (args != NULL) + { + if (args[1] == NULL) + { + fprintf_filtered (stream, "..."); + } + else + { + for (i = 1; args[i] != NULL && args[i]->code != TYPE_CODE_VOID; i++) + { + f_print_type (args[i], "", stream, -1, 0); + if (args[i+1] == NULL) + fprintf_filtered (stream, "..."); + else if (args[i+1]->code != TYPE_CODE_VOID) + { + fprintf_filtered (stream, ","); + wrap_here (" "); + } + } + } + } + fprintf_filtered (stream, ")"); +} + +#endif /* 0 */ + +/* Print any array sizes, function arguments or close parentheses + needed after the variable name (to describe its type). + Args work like c_type_print_varspec_prefix. */ + +static void +f_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; + int demangled_args; +{ + int upper_bound, lower_bound; + int lower_bound_was_default = 0; + static int arrayprint_recurse_level = 0; + int retcode; + + if (type == 0) + return; + + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + arrayprint_recurse_level++; + + if (arrayprint_recurse_level == 1) + fprintf_filtered(stream,"("); + + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY) + f_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + + retcode = f77_get_dynamic_lowerbound (type,&lower_bound); + + lower_bound_was_default = 0; + + if (retcode == BOUND_FETCH_ERROR) + fprintf_filtered (stream,"???"); + else + if (lower_bound == 1) /* The default */ + lower_bound_was_default = 1; + else + fprintf_filtered (stream,"%d",lower_bound); + + if (lower_bound_was_default) + lower_bound_was_default = 0; + else + fprintf_filtered(stream,":"); + + /* Make sure that, if we have an assumed size array, we + print out a warning and print the upperbound as '*' */ + + if (TYPE_ARRAY_UPPER_BOUND_TYPE(type) == BOUND_CANNOT_BE_DETERMINED) + fprintf_filtered (stream, "*"); + else + { + retcode = f77_get_dynamic_upperbound(type,&upper_bound); + + if (retcode == BOUND_FETCH_ERROR) + fprintf_filtered(stream,"???"); + else + fprintf_filtered(stream,"%d",upper_bound); + } + + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_ARRAY) + f_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0); + if (arrayprint_recurse_level == 1) + fprintf_filtered (stream, ")"); + else + fprintf_filtered(stream,","); + arrayprint_recurse_level--; + break; + + case TYPE_CODE_PTR: + case TYPE_CODE_REF: + f_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1, 0); + fprintf_filtered(stream,")"); + break; + + case TYPE_CODE_FUNC: + f_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr, 0); + if (passed_a_ptr) + fprintf_filtered (stream, ")"); + + fprintf_filtered (stream, "()"); + break; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_ERROR: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_METHOD: + case TYPE_CODE_MEMBER: + case TYPE_CODE_COMPLEX: + case TYPE_CODE_TYPEDEF: + /* These types do not need a suffix. They are listed so that + gcc -Wall will report types that may not have been considered. */ + break; + } +} + +void +print_equivalent_f77_float_type (type, stream) + struct type *type; + FILE *stream; +{ + /* Override type name "float" and make it the + appropriate real. XLC stupidly outputs -12 as a type + for real when it really should be outputting -18 */ + + fprintf_filtered (stream, "real*%d", TYPE_LENGTH (type)); +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element), or the description of a + structure or union. + + SHOW nonzero means don't print this type as just its name; + show its real definition even if it has a name. + SHOW zero means print just typename or struct tag if there is one + SHOW negative means abbreviate structure elements. + SHOW is decremented for printing of structure elements. + + LEVEL is the depth to indent by. + We increase it for some recursive calls. */ + +void +f_type_print_base (type, stream, show, level) + struct type *type; + FILE *stream; + int show; + int level; +{ + int retcode; + int upper_bound; + + QUIT; + + wrap_here (" "); + if (type == NULL) + { + fputs_filtered ("", stream); + return; + } + + /* When SHOW is zero or less, and there is a valid type name, then always + just print the type name directly from the type. */ + + if ((show <= 0) && (TYPE_NAME (type) != NULL)) + { + if (TYPE_CODE (type) == TYPE_CODE_FLT) + print_equivalent_f77_float_type (type, stream); + else + fputs_filtered (TYPE_NAME (type), stream); + return; + } + + if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_TYPEDEF: + f_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + break; + + case TYPE_CODE_ARRAY: + case TYPE_CODE_FUNC: + f_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_PTR: + fprintf_filtered (stream, "PTR TO -> ( "); + f_type_print_base (TYPE_TARGET_TYPE (type), stream, 0, level); + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "VOID"); + break; + + case TYPE_CODE_UNDEF: + fprintf_filtered (stream, "struct "); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_RANGE: + /* This should not occur */ + fprintf_filtered (stream, ""); + break; + + case TYPE_CODE_CHAR: + /* Override name "char" and make it "character" */ + fprintf_filtered (stream, "character"); + break; + + case TYPE_CODE_INT: + /* There may be some character types that attempt to come + through as TYPE_CODE_INT since dbxstclass.h is so + C-oriented, we must change these to "character" from "char". */ + + if (STREQ (TYPE_NAME (type), "char")) + fprintf_filtered (stream, "character"); + else + goto default_case; + break; + + case TYPE_CODE_COMPLEX: + fprintf_filtered (stream, "complex*%d", TYPE_LENGTH (type)); + break; + + case TYPE_CODE_FLT: + print_equivalent_f77_float_type (type, stream); + break; + + case TYPE_CODE_STRING: + /* Strings may have dynamic upperbounds (lengths) like arrays. */ + + if (TYPE_ARRAY_UPPER_BOUND_TYPE (type) == BOUND_CANNOT_BE_DETERMINED) + fprintf_filtered (stream, "character*(*)"); + else + { + retcode = f77_get_dynamic_upperbound (type, &upper_bound); + + if (retcode == BOUND_FETCH_ERROR) + fprintf_filtered (stream, "character*???"); + else + fprintf_filtered (stream, "character*%d", upper_bound); + } + break; + + default_case: + default: + /* Handle types not explicitly handled by the other cases, + such as fundamental types. For these, just print whatever + the type name is, as recorded in the type itself. If there + is no type name, then complain. */ + if (TYPE_NAME (type) != NULL) + fputs_filtered (TYPE_NAME (type), stream); + else + error ("Invalid type code (%d) in symbol table.", TYPE_CODE (type)); + break; + } +} diff --git a/contrib/gdb/gdb/f-valprint.c b/contrib/gdb/gdb/f-valprint.c new file mode 100644 index 000000000000..1143b9d406bd --- /dev/null +++ b/contrib/gdb/gdb/f-valprint.c @@ -0,0 +1,748 @@ +/* Support for printing Fortran values for GDB, the GNU debugger. + Copyright 1993, 1994, 1995 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. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "demangle.h" +#include "valprint.h" +#include "language.h" +#include "f-lang.h" +#include "frame.h" +#include "gdbcore.h" +#include "command.h" + +extern unsigned int print_max; /* No of array elements to print */ + +extern int calc_f77_array_dims PARAMS ((struct type *)); + +int f77_array_offset_tbl[MAX_FORTRAN_DIMS+1][2]; + +/* Array which holds offsets to be applied to get a row's elements + for a given array. Array also holds the size of each subarray. */ + +/* The following macro gives us the size of the nth dimension, Where + n is 1 based. */ + +#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1]) + +/* The following gives us the offset for row n where n is 1-based. */ + +#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0]) + +int +f77_get_dynamic_lowerbound (type, lower_bound) + struct type *type; + int *lower_bound; +{ + CORE_ADDR current_frame_addr; + CORE_ADDR ptr_to_lower_bound; + + switch (TYPE_ARRAY_LOWER_BOUND_TYPE (type)) + { + case BOUND_BY_VALUE_ON_STACK: + current_frame_addr = selected_frame->frame; + if (current_frame_addr > 0) + { + *lower_bound = + read_memory_integer (current_frame_addr + + TYPE_ARRAY_LOWER_BOUND_VALUE (type), + 4); + } + else + { + *lower_bound = DEFAULT_LOWER_BOUND; + return BOUND_FETCH_ERROR; + } + break; + + case BOUND_SIMPLE: + *lower_bound = TYPE_ARRAY_LOWER_BOUND_VALUE (type); + break; + + case BOUND_CANNOT_BE_DETERMINED: + error ("Lower bound may not be '*' in F77"); + break; + + case BOUND_BY_REF_ON_STACK: + current_frame_addr = selected_frame->frame; + if (current_frame_addr > 0) + { + ptr_to_lower_bound = + read_memory_integer (current_frame_addr + + TYPE_ARRAY_LOWER_BOUND_VALUE (type), + 4); + *lower_bound = read_memory_integer (ptr_to_lower_bound, 4); + } + else + { + *lower_bound = DEFAULT_LOWER_BOUND; + return BOUND_FETCH_ERROR; + } + break; + + case BOUND_BY_REF_IN_REG: + case BOUND_BY_VALUE_IN_REG: + default: + error ("??? unhandled dynamic array bound type ???"); + break; + } + return BOUND_FETCH_OK; +} + +int +f77_get_dynamic_upperbound (type, upper_bound) + struct type *type; + int *upper_bound; +{ + CORE_ADDR current_frame_addr = 0; + CORE_ADDR ptr_to_upper_bound; + + switch (TYPE_ARRAY_UPPER_BOUND_TYPE (type)) + { + case BOUND_BY_VALUE_ON_STACK: + current_frame_addr = selected_frame->frame; + if (current_frame_addr > 0) + { + *upper_bound = + read_memory_integer (current_frame_addr + + TYPE_ARRAY_UPPER_BOUND_VALUE (type), + 4); + } + else + { + *upper_bound = DEFAULT_UPPER_BOUND; + return BOUND_FETCH_ERROR; + } + break; + + case BOUND_SIMPLE: + *upper_bound = TYPE_ARRAY_UPPER_BOUND_VALUE (type); + break; + + case BOUND_CANNOT_BE_DETERMINED: + /* we have an assumed size array on our hands. Assume that + upper_bound == lower_bound so that we show at least + 1 element.If the user wants to see more elements, let + him manually ask for 'em and we'll subscript the + array and show him */ + f77_get_dynamic_lowerbound (type, upper_bound); + break; + + case BOUND_BY_REF_ON_STACK: + current_frame_addr = selected_frame->frame; + if (current_frame_addr > 0) + { + ptr_to_upper_bound = + read_memory_integer (current_frame_addr + + TYPE_ARRAY_UPPER_BOUND_VALUE (type), + 4); + *upper_bound = read_memory_integer(ptr_to_upper_bound, 4); + } + else + { + *upper_bound = DEFAULT_UPPER_BOUND; + return BOUND_FETCH_ERROR; + } + break; + + case BOUND_BY_REF_IN_REG: + case BOUND_BY_VALUE_IN_REG: + default: + error ("??? unhandled dynamic array bound type ???"); + break; + } + return BOUND_FETCH_OK; +} + +/* Obtain F77 adjustable array dimensions */ + +void +f77_get_dynamic_length_of_aggregate (type) + struct type *type; +{ + int upper_bound = -1; + int lower_bound = 1; + int retcode; + + /* Recursively go all the way down into a possibly multi-dimensional + F77 array and get the bounds. For simple arrays, this is pretty + easy but when the bounds are dynamic, we must be very careful + to add up all the lengths correctly. Not doing this right + will lead to horrendous-looking arrays in parameter lists. + + This function also works for strings which behave very + similarly to arrays. */ + + if (TYPE_CODE(TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY + || TYPE_CODE(TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRING) + f77_get_dynamic_length_of_aggregate (TYPE_TARGET_TYPE (type)); + + /* Recursion ends here, start setting up lengths. */ + retcode = f77_get_dynamic_lowerbound (type, &lower_bound); + if (retcode == BOUND_FETCH_ERROR) + error ("Cannot obtain valid array lower bound"); + + retcode = f77_get_dynamic_upperbound (type, &upper_bound); + if (retcode == BOUND_FETCH_ERROR) + error ("Cannot obtain valid array upper bound"); + + /* Patch in a valid length value. */ + + TYPE_LENGTH (type) = + (upper_bound - lower_bound + 1) * TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type))); +} + +/* Function that sets up the array offset,size table for the array + type "type". */ + +void +f77_create_arrayprint_offset_tbl (type, stream) + struct type *type; + FILE *stream; +{ + struct type *tmp_type; + int eltlen; + int ndimen = 1; + int upper, lower, retcode; + + tmp_type = type; + + while ((TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY)) + { + if (TYPE_ARRAY_UPPER_BOUND_TYPE (tmp_type) == BOUND_CANNOT_BE_DETERMINED) + fprintf_filtered (stream, " "); + + retcode = f77_get_dynamic_upperbound (tmp_type, &upper); + if (retcode == BOUND_FETCH_ERROR) + error ("Cannot obtain dynamic upper bound"); + + retcode = f77_get_dynamic_lowerbound(tmp_type,&lower); + if (retcode == BOUND_FETCH_ERROR) + error("Cannot obtain dynamic lower bound"); + + F77_DIM_SIZE (ndimen) = upper - lower + 1; + + tmp_type = TYPE_TARGET_TYPE (tmp_type); + ndimen++; + } + + /* Now we multiply eltlen by all the offsets, so that later we + can print out array elements correctly. Up till now we + know an offset to apply to get the item but we also + have to know how much to add to get to the next item */ + + ndimen--; + eltlen = TYPE_LENGTH (tmp_type); + F77_DIM_OFFSET (ndimen) = eltlen; + while (--ndimen > 0) + { + eltlen *= F77_DIM_SIZE (ndimen + 1); + F77_DIM_OFFSET (ndimen) = eltlen; + } +} + +/* Actual function which prints out F77 arrays, Valaddr == address in + the superior. Address == the address in the inferior. */ + +void +f77_print_array_1 (nss, ndimensions, type, valaddr, address, + stream, format, deref_ref, recurse, pretty) + int nss; + int ndimensions; + char *valaddr; + struct type *type; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + int i; + + if (nss != ndimensions) + { + for (i = 0; i< F77_DIM_SIZE(nss); i++) + { + fprintf_filtered (stream, "( "); + f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type), + valaddr + i * F77_DIM_OFFSET (nss), + address + i * F77_DIM_OFFSET (nss), + stream, format, deref_ref, recurse, pretty, i); + fprintf_filtered (stream, ") "); + } + } + else + { + for (i = 0; (i < F77_DIM_SIZE (nss) && i < print_max); i++) + { + val_print (TYPE_TARGET_TYPE (type), + valaddr + i * F77_DIM_OFFSET (ndimensions), + address + i * F77_DIM_OFFSET (ndimensions), + stream, format, deref_ref, recurse, pretty); + + if (i != (F77_DIM_SIZE (nss) - 1)) + fprintf_filtered (stream, ", "); + + if (i == print_max - 1) + fprintf_filtered (stream, "..."); + } + } +} + +/* This function gets called to print an F77 array, we set up some + stuff and then immediately call f77_print_array_1() */ + +void +f77_print_array (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + int ndimensions; + + ndimensions = calc_f77_array_dims (type); + + if (ndimensions > MAX_FORTRAN_DIMS || ndimensions < 0) + error ("Type node corrupt! F77 arrays cannot have %d subscripts (%d Max)", + ndimensions, MAX_FORTRAN_DIMS); + + /* Since F77 arrays are stored column-major, we set up an + offset table to get at the various row's elements. The + offset table contains entries for both offset and subarray size. */ + + f77_create_arrayprint_offset_tbl (type, stream); + + f77_print_array_1 (1, ndimensions, type, valaddr, address, stream, format, + deref_ref, recurse, pretty); +} + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter or 0 for natural format). The data at VALADDR is in + target byte order. + + If the data are a string pointer, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. */ + +int +f_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + register unsigned int i = 0; /* Number of characters printed */ + struct type *elttype; + LONGEST val; + CORE_ADDR addr; + + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRING: + f77_get_dynamic_length_of_aggregate (type); + LA_PRINT_STRING (stream, valaddr, TYPE_LENGTH (type), 0); + break; + + case TYPE_CODE_ARRAY: + fprintf_filtered (stream, "("); + f77_print_array (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + fprintf_filtered (stream, ")"); + break; +#if 0 + /* Array of unspecified length: treat like pointer to first elt. */ + valaddr = (char *) &address; + /* FALL THROUGH */ +#endif + case TYPE_CODE_PTR: + if (format && format != 's') + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + else + { + addr = unpack_pointer (type, valaddr); + 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 (addr, stream, demangle); + /* Return value is irrelevant except for string pointers. */ + return 0; + } + + if (addressprint && format != 's') + fprintf_filtered (stream, "0x%x", addr); + + /* For a pointer to char or unsigned char, also print the string + pointed to, unless pointer is null. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_INT + && (format == 0 || format == 's') + && addr != 0) + i = val_print_string (addr, 0, stream); + + /* Return number of characters printed, plus one for the + terminating null if we have "reached the end". */ + return (i + (print_max && i != print_max)); + } + break; + + case TYPE_CODE_FUNC: + if (format) + { + print_scalar_formatted (valaddr, type, format, 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 (address, stream, demangle); + break; + + case TYPE_CODE_INT: + format = format ? format : output_format; + if (format) + print_scalar_formatted (valaddr, type, format, 0, stream); + else + { + val_print_type_code_int (type, valaddr, stream); + /* C and C++ has no single byte int type, char is used instead. + 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) + { + fputs_filtered (" ", stream); + LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), + stream); + } + } + break; + + case TYPE_CODE_FLT: + if (format) + print_scalar_formatted (valaddr, type, format, 0, stream); + else + print_floating (valaddr, type, stream); + break; + + case TYPE_CODE_VOID: + fprintf_filtered (stream, "VOID"); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, ""); + 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: + format = format ? format : output_format; + if (format) + print_scalar_formatted (valaddr, type, format, 0, stream); + else + { + val = 0; + switch (TYPE_LENGTH(type)) + { + case 1: + val = unpack_long (builtin_type_f_logical_s1, valaddr); + break ; + + case 2: + val = unpack_long (builtin_type_f_logical_s2, valaddr); + break ; + + case 4: + val = unpack_long (builtin_type_f_logical, valaddr); + break ; + + default: + error ("Logicals of length %d bytes not supported", + TYPE_LENGTH (type)); + + } + + 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; + f_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + /* Restore the type code so later uses work as intended. */ + TYPE_CODE (type) = TYPE_CODE_BOOL; + } + } + break; + + case TYPE_CODE_COMPLEX: + switch (TYPE_LENGTH (type)) + { + case 8: type = builtin_type_f_real; break; + case 16: type = builtin_type_f_real_s8; break; + case 32: type = builtin_type_f_real_s16; break; + default: + error ("Cannot print out complex*%d variables", TYPE_LENGTH(type)); + } + fputs_filtered ("(", stream); + print_floating (valaddr, type, stream); + fputs_filtered (",", stream); + print_floating (valaddr, 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; + + default: + error ("Invalid F77 type code %d in symbol table.", TYPE_CODE (type)); + } + fflush (stream); + return 0; +} + +void +list_all_visible_commons (funname) + char *funname; +{ + SAVED_F77_COMMON_PTR tmp; + + tmp = head_common_list; + + printf_filtered ("All COMMON blocks visible at this level:\n\n"); + + while (tmp != NULL) + { + if (STREQ(tmp->owning_function,funname)) + printf_filtered ("%s\n", tmp->name); + + tmp = tmp->next; + } +} + +/* This function is used to print out the values in a given COMMON + block. It will always use the most local common block of the + given name */ + +static void +info_common_command (comname, from_tty) + char *comname; + int from_tty; +{ + SAVED_F77_COMMON_PTR the_common; + COMMON_ENTRY_PTR entry; + struct frame_info *fi; + register char *funname = 0; + struct symbol *func; + + /* We have been told to display the contents of F77 COMMON + block supposedly visible in this function. Let us + first make sure that it is visible and if so, let + us display its contents */ + + fi = selected_frame; + + if (fi == NULL) + error ("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) + { + /* 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_NAME (msymbol); + else + funname = SYMBOL_NAME (func); + } + else + { + register struct minimal_symbol *msymbol = + lookup_minimal_symbol_by_pc (fi->pc); + + if (msymbol != NULL) + funname = SYMBOL_NAME (msymbol); + } + + /* If comname is NULL, we assume the user wishes to see the + which COMMON blocks are visible here and then return */ + + if (comname == 0) + { + list_all_visible_commons (funname); + return; + } + + the_common = find_common_for_function (comname,funname); + + if (the_common) + { + if (STREQ(comname,BLANK_COMMON_NAME_LOCAL)) + 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) + { + printf_filtered ("%s = ",SYMBOL_NAME(entry->symbol)); + print_variable_value (entry->symbol,fi,stdout); + printf_filtered ("\n"); + entry = entry->next; + } + } + 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'. */ + +int +there_is_a_visible_common_named (comname) + char *comname; +{ + SAVED_F77_COMMON_PTR the_common; + struct frame_info *fi; + register char *funname = 0; + struct symbol *func; + + if (comname == NULL) + error ("Cannot deal with NULL common name!"); + + fi = selected_frame; + + if (fi == NULL) + error ("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) + { + /* 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_NAME (msymbol); + else + funname = SYMBOL_NAME (func); + } + else + { + register struct minimal_symbol *msymbol = + lookup_minimal_symbol_by_pc (fi->pc); + + if (msymbol != NULL) + funname = SYMBOL_NAME (msymbol); + } + + the_common = find_common_for_function (comname, funname); + + return (the_common ? 1 : 0); +} + +void +_initialize_f_valprint () +{ + add_info ("common", info_common_command, + "Print out the values contained in a Fortran COMMON block."); +} diff --git a/contrib/gdb/gdb/findvar.c b/contrib/gdb/gdb/findvar.c new file mode 100644 index 000000000000..1dce9050d7f0 --- /dev/null +++ b/contrib/gdb/gdb/findvar.c @@ -0,0 +1,1444 @@ +/* Find a variable's value in memory, for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "value.h" +#include "gdbcore.h" +#include "inferior.h" +#include "target.h" +#include "gdb_string.h" + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +static void write_register_pid PARAMS ((int regno, LONGEST val, int pid)); + +/* Basic byte-swapping routines. GDB has needed these for a long time... + All extract a target-format integer at ADDR which is LEN bytes long. */ + +#if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8 + /* 8 bit characters are a pretty safe assumption these days, so we + assume it throughout all these swapping routines. If we had to deal with + 9 bit characters, we would need to make len be in bits and would have + to re-write these routines... */ + you lose +#endif + +LONGEST +extract_signed_integer (addr, len) + PTR addr; + int len; +{ + LONGEST retval; + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + if (len > (int) sizeof (LONGEST)) + error ("\ +That operation is not available on integers of more than %d bytes.", + sizeof (LONGEST)); + + /* Start at the most significant end of the integer, and work towards + the least significant. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + p = startaddr; + /* Do the sign extension once at the start. */ + retval = ((LONGEST)*p ^ 0x80) - 0x80; + for (++p; p < endaddr; ++p) + retval = (retval << 8) | *p; + } + else + { + p = endaddr - 1; + /* Do the sign extension once at the start. */ + retval = ((LONGEST)*p ^ 0x80) - 0x80; + for (--p; p >= startaddr; --p) + retval = (retval << 8) | *p; + } + return retval; +} + +unsigned LONGEST +extract_unsigned_integer (addr, len) + PTR addr; + int len; +{ + unsigned LONGEST retval; + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + if (len > (int) sizeof (unsigned LONGEST)) + error ("\ +That operation is not available on integers of more than %d bytes.", + sizeof (unsigned LONGEST)); + + /* Start at the most significant end of the integer, and work towards + the least significant. */ + retval = 0; + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = startaddr; p < endaddr; ++p) + retval = (retval << 8) | *p; + } + else + { + for (p = endaddr - 1; p >= startaddr; --p) + retval = (retval << 8) | *p; + } + return retval; +} + +/* Sometimes a long long unsigned integer can be extracted as a + LONGEST value. This is done so that we can print these values + better. If this integer can be converted to a LONGEST, this + function returns 1 and sets *PVAL. Otherwise it returns 0. */ + +int +extract_long_unsigned_integer (addr, orig_len, pval) + PTR addr; + int orig_len; + LONGEST *pval; +{ + char *p, *first_addr; + int len; + + len = orig_len; + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = (char *) addr; + len > (int) sizeof (LONGEST) && p < (char *) addr + orig_len; + p++) + { + if (*p == 0) + len--; + else + break; + } + first_addr = p; + } + else + { + first_addr = (char *) addr; + for (p = (char *) addr + orig_len - 1; + len > (int) sizeof (LONGEST) && p >= (char *) addr; + p--) + { + if (*p == 0) + len--; + else + break; + } + } + + if (len <= (int) sizeof (LONGEST)) + { + *pval = (LONGEST) extract_unsigned_integer (first_addr, + sizeof (LONGEST)); + return 1; + } + + return 0; +} + +CORE_ADDR +extract_address (addr, len) + PTR addr; + int len; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + return extract_unsigned_integer (addr, len); +} + +void +store_signed_integer (addr, len, val) + PTR addr; + int len; + LONGEST val; +{ + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + /* Start at the least significant end of the integer, and work towards + the most significant. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = endaddr - 1; p >= startaddr; --p) + { + *p = val & 0xff; + val >>= 8; + } + } + else + { + for (p = startaddr; p < endaddr; ++p) + { + *p = val & 0xff; + val >>= 8; + } + } +} + +void +store_unsigned_integer (addr, len, val) + PTR addr; + int len; + unsigned LONGEST val; +{ + unsigned char *p; + unsigned char *startaddr = (unsigned char *)addr; + unsigned char *endaddr = startaddr + len; + + /* Start at the least significant end of the integer, and work towards + the most significant. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = endaddr - 1; p >= startaddr; --p) + { + *p = val & 0xff; + val >>= 8; + } + } + else + { + for (p = startaddr; p < endaddr; ++p) + { + *p = val & 0xff; + val >>= 8; + } + } +} + +void +store_address (addr, len, val) + PTR addr; + int len; + CORE_ADDR val; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + store_unsigned_integer (addr, len, (LONGEST)val); +} + +/* Swap LEN bytes at BUFFER between target and host byte-order. */ +#define SWAP_FLOATING(buffer,len) \ + do \ + { \ + if (TARGET_BYTE_ORDER != HOST_BYTE_ORDER) \ + { \ + char tmp; \ + char *p = (char *)(buffer); \ + char *q = ((char *)(buffer)) + len - 1; \ + for (; p < q; p++, q--) \ + { \ + tmp = *q; \ + *q = *p; \ + *p = tmp; \ + } \ + } \ + } \ + while (0) + +/* There are various problems with the extract_floating and store_floating + routines. + + 1. These routines only handle byte-swapping, not conversion of + formats. So if host is IEEE floating and target is VAX floating, + or vice-versa, it loses. This means that we can't (yet) use these + routines for extendeds. Extendeds are handled by + REGISTER_CONVERTIBLE. What we want is to use floatformat.h, but that + doesn't yet handle VAX floating at all. + + 2. We can't deal with it if there is more than one floating point + format in use. This has to be fixed at the unpack_double level. + + 3. We probably should have a LONGEST_DOUBLE or DOUBLEST or whatever + we want to call it which is long double where available. */ + +DOUBLEST +extract_floating (addr, len) + PTR addr; + int len; +{ + if (len == sizeof (float)) + { + float retval; + memcpy (&retval, addr, sizeof (retval)); + SWAP_FLOATING (&retval, sizeof (retval)); + return retval; + } + else if (len == sizeof (double)) + { + double retval; + memcpy (&retval, addr, sizeof (retval)); + SWAP_FLOATING (&retval, sizeof (retval)); + return retval; + } + else if (len == sizeof (DOUBLEST)) + { + DOUBLEST retval; + memcpy (&retval, addr, sizeof (retval)); + SWAP_FLOATING (&retval, sizeof (retval)); + return retval; + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } +} + +void +store_floating (addr, len, val) + PTR addr; + int len; + DOUBLEST val; +{ + if (len == sizeof (float)) + { + float floatval = val; + SWAP_FLOATING (&floatval, sizeof (floatval)); + memcpy (addr, &floatval, sizeof (floatval)); + } + else if (len == sizeof (double)) + { + double doubleval = val; + + SWAP_FLOATING (&doubleval, sizeof (doubleval)); + memcpy (addr, &doubleval, sizeof (doubleval)); + } + else if (len == sizeof (DOUBLEST)) + { + SWAP_FLOATING (&val, sizeof (val)); + memcpy (addr, &val, sizeof (val)); + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } +} + +#if !defined (GET_SAVED_REGISTER) + +/* Return the address in which frame FRAME's value of register REGNUM + has been saved in memory. Or return zero if it has not been saved. + If REGNUM specifies the SP, the value we return is actually + the SP value, not an address where it was saved. */ + +CORE_ADDR +find_saved_register (frame, regnum) + struct frame_info *frame; + int regnum; +{ + struct frame_saved_regs saved_regs; + + register struct frame_info *frame1 = NULL; + register CORE_ADDR addr = 0; + + if (frame == NULL) /* No regs saved if want current frame */ + return 0; + +#ifdef HAVE_REGISTER_WINDOWS + /* We assume that a register in a register window will only be saved + in one place (since the name changes and/or disappears as you go + towards inner frames), so we only call get_frame_saved_regs on + the current frame. This is directly in contradiction to the + usage below, which assumes that registers used in a frame must be + saved in a lower (more interior) frame. This change is a result + of working on a register window machine; get_frame_saved_regs + always returns the registers saved within a frame, within the + context (register namespace) of that frame. */ + + /* However, note that we don't want this to return anything if + nothing is saved (if there's a frame inside of this one). Also, + callers to this routine asking for the stack pointer want the + stack pointer saved for *this* frame; this is returned from the + next frame. */ + + if (REGISTER_IN_WINDOW_P(regnum)) + { + frame1 = get_next_frame (frame); + if (!frame1) return 0; /* Registers of this frame are active. */ + + /* Get the SP from the next frame in; it will be this + current frame. */ + if (regnum != SP_REGNUM) + frame1 = frame; + + get_frame_saved_regs (frame1, &saved_regs); + return saved_regs.regs[regnum]; /* ... which might be zero */ + } +#endif /* HAVE_REGISTER_WINDOWS */ + + /* Note that this next routine assumes that registers used in + frame x will be saved only in the frame that x calls and + frames interior to it. This is not true on the sparc, but the + above macro takes care of it, so we should be all right. */ + while (1) + { + QUIT; + frame1 = get_prev_frame (frame1); + if (frame1 == 0 || frame1 == frame) + break; + get_frame_saved_regs (frame1, &saved_regs); + if (saved_regs.regs[regnum]) + addr = saved_regs.regs[regnum]; + } + + return addr; +} + +/* Find register number REGNUM relative to FRAME and put its (raw, + target format) contents in *RAW_BUFFER. Set *OPTIMIZED if the + variable was optimized out (and thus can't be fetched). Set *LVAL + to lval_memory, lval_register, or not_lval, depending on whether + the value was fetched from memory, from a register, or in a strange + and non-modifiable way (e.g. a frame pointer which was calculated + rather than fetched). Set *ADDRP to the address, either in memory + on as a REGISTER_BYTE offset into the registers array. + + Note that this implementation never sets *LVAL to not_lval. But + it can be replaced by defining GET_SAVED_REGISTER and supplying + your own. + + The argument RAW_BUFFER must point to aligned memory. */ + +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + CORE_ADDR addr; + + if (!target_has_registers) + error ("No registers."); + + /* Normal systems don't optimize out things with register numbers. */ + if (optimized != NULL) + *optimized = 0; + addr = find_saved_register (frame, regnum); + if (addr != 0) + { + if (lval != NULL) + *lval = lval_memory; + if (regnum == SP_REGNUM) + { + if (raw_buffer != NULL) + { + /* Put it back in target format. */ + store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr); + } + if (addrp != NULL) + *addrp = 0; + return; + } + if (raw_buffer != NULL) + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); + } + else + { + if (lval != NULL) + *lval = lval_register; + addr = REGISTER_BYTE (regnum); + if (raw_buffer != NULL) + read_register_gen (regnum, raw_buffer); + } + if (addrp != NULL) + *addrp = addr; +} +#endif /* GET_SAVED_REGISTER. */ + +/* Copy the bytes of register REGNUM, relative to the current stack frame, + into our memory at MYADDR, in target byte order. + The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). + + Returns 1 if could not be read, 0 if could. */ + +int +read_relative_register_raw_bytes (regnum, myaddr) + int regnum; + char *myaddr; +{ + int optim; + if (regnum == FP_REGNUM && selected_frame) + { + /* Put it back in target format. */ + store_address (myaddr, REGISTER_RAW_SIZE(FP_REGNUM), + FRAME_FP(selected_frame)); + return 0; + } + + get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, selected_frame, + regnum, (enum lval_type *)NULL); + return optim; +} + +/* Return a `value' with the contents of register REGNUM + in its virtual format, with the type specified by + REGISTER_VIRTUAL_TYPE. */ + +value_ptr +value_of_register (regnum) + int regnum; +{ + CORE_ADDR addr; + int optim; + register value_ptr reg_val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + enum lval_type lval; + + get_saved_register (raw_buffer, &optim, &addr, + selected_frame, regnum, &lval); + + reg_val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + + /* Convert raw data to virtual format if necessary. */ + +#ifdef REGISTER_CONVERTIBLE + if (REGISTER_CONVERTIBLE (regnum)) + { + REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum), + raw_buffer, VALUE_CONTENTS_RAW (reg_val)); + } + else +#endif + memcpy (VALUE_CONTENTS_RAW (reg_val), raw_buffer, + REGISTER_RAW_SIZE (regnum)); + VALUE_LVAL (reg_val) = lval; + VALUE_ADDRESS (reg_val) = addr; + VALUE_REGNO (reg_val) = regnum; + VALUE_OPTIMIZED_OUT (reg_val) = optim; + return reg_val; +} + +/* Low level examining and depositing of registers. + + The caller is responsible for making + sure that the inferior is stopped before calling the fetching routines, + or it will get garbage. (a change from GDB version 3, in which + the caller got the value from the last stop). */ + +/* Contents of the registers in target byte order. + We allocate some extra slop since we do a lot of memcpy's around `registers', + and failing-soft is better than failing hard. */ +char registers[REGISTER_BYTES + /* SLOP */ 256]; + +/* Nonzero if that register has been fetched. */ +char register_valid[NUM_REGS]; + +/* The thread/process associated with the current set of registers. For now, + -1 is special, and means `no current process'. */ +int registers_pid = -1; + +/* Indicate that registers may have changed, so invalidate the cache. */ + +void +registers_changed () +{ + int i; + int numregs = ARCH_NUM_REGS; + + registers_pid = -1; + + for (i = 0; i < numregs; i++) + register_valid[i] = 0; + + if (registers_changed_hook) + registers_changed_hook (); +} + +/* Indicate that all registers have been fetched, so mark them all valid. */ +void +registers_fetched () +{ + int i; + int numregs = ARCH_NUM_REGS; + for (i = 0; i < numregs; i++) + register_valid[i] = 1; +} + +/* read_register_bytes and write_register_bytes are generally a *BAD* idea. + They are inefficient because they need to check for partial updates, which + can only be done by scanning through all of the registers and seeing if the + bytes that are being read/written fall inside of an invalid register. [The + main reason this is necessary is that register sizes can vary, so a simple + index won't suffice.] It is far better to call read_register_gen if you + want to get at the raw register contents, as it only takes a regno as an + argument, and therefore can't do a partial register update. It would also + be good to have a write_register_gen for similar reasons. + + Prior to the recent fixes to check for partial updates, both read and + write_register_bytes always checked to see if any registers were stale, and + then called target_fetch_registers (-1) to update the whole set. This + caused really slowed things down for remote targets. */ + +/* Copy INLEN bytes of consecutive data from registers + starting with the INREGBYTE'th byte of register data + into memory at MYADDR. */ + +void +read_register_bytes (inregbyte, myaddr, inlen) + int inregbyte; + char *myaddr; + int inlen; +{ + int inregend = inregbyte + inlen; + int regno; + + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + /* See if we are trying to read bytes from out-of-date registers. If so, + update just those registers. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + int regstart, regend; + int startin, endin; + + if (register_valid[regno]) + continue; + + regstart = REGISTER_BYTE (regno); + regend = regstart + REGISTER_RAW_SIZE (regno); + + startin = regstart >= inregbyte && regstart < inregend; + endin = regend > inregbyte && regend <= inregend; + + if (!startin && !endin) + continue; + + /* We've found an invalid register where at least one byte will be read. + Update it from the target. */ + + target_fetch_registers (regno); + + if (!register_valid[regno]) + error ("read_register_bytes: Couldn't update register %d.", regno); + } + + if (myaddr != NULL) + memcpy (myaddr, ®isters[inregbyte], inlen); +} + +/* Read register REGNO into memory at MYADDR, which must be large enough + for REGISTER_RAW_BYTES (REGNO). Target byte-order. + If the register is known to be the size of a CORE_ADDR or smaller, + read_register can be used instead. */ +void +read_register_gen (regno, myaddr) + int regno; + char *myaddr; +{ + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + if (!register_valid[regno]) + target_fetch_registers (regno); + memcpy (myaddr, ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno)); +} + +/* Write register REGNO at MYADDR to the target. MYADDR points at + REGISTER_RAW_BYTES(REGNO), which must be in target byte-order. */ + +void +write_register_gen (regno, myaddr) + int regno; + char *myaddr; +{ + int size; + + /* On the sparc, writing %g0 is a no-op, so we don't even want to change + the registers array if something writes to this register. */ + if (CANNOT_STORE_REGISTER (regno)) + return; + + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + size = REGISTER_RAW_SIZE(regno); + + /* If we have a valid copy of the register, and new value == old value, + then don't bother doing the actual store. */ + + if (register_valid [regno] + && memcmp (®isters[REGISTER_BYTE (regno)], myaddr, size) == 0) + return; + + target_prepare_to_store (); + + memcpy (®isters[REGISTER_BYTE (regno)], myaddr, size); + + register_valid [regno] = 1; + + target_store_registers (regno); +} + +/* Copy INLEN bytes of consecutive data from memory at MYADDR + into registers starting with the MYREGSTART'th byte of register data. */ + +void +write_register_bytes (myregstart, myaddr, inlen) + int myregstart; + char *myaddr; + int inlen; +{ + int myregend = myregstart + inlen; + int regno; + + target_prepare_to_store (); + + /* Scan through the registers updating any that are covered by the range + myregstart<=>myregend using write_register_gen, which does nice things + like handling threads, and avoiding updates when the new and old contents + are the same. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + int regstart, regend; + int startin, endin; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + regstart = REGISTER_BYTE (regno); + regend = regstart + REGISTER_RAW_SIZE (regno); + + startin = regstart >= myregstart && regstart < myregend; + endin = regend > myregstart && regend <= myregend; + + if (!startin && !endin) + continue; /* Register is completely out of range */ + + if (startin && endin) /* register is completely in range */ + { + write_register_gen (regno, myaddr + (regstart - myregstart)); + continue; + } + + /* We may be doing a partial update of an invalid register. Update it + from the target before scribbling on it. */ + read_register_gen (regno, regbuf); + + if (startin) + memcpy (registers + regstart, + myaddr + regstart - myregstart, + myregend - regstart); + else /* endin */ + memcpy (registers + myregstart, + myaddr, + regend - myregstart); + target_store_registers (regno); + } +} + +/* Return the raw contents of register REGNO, regarding it as an integer. */ +/* This probably should be returning LONGEST rather than CORE_ADDR. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + if (!register_valid[regno]) + target_fetch_registers (regno); + + return extract_address (®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE(regno)); +} + +CORE_ADDR +read_register_pid (regno, pid) + int regno, pid; +{ + int save_pid; + CORE_ADDR retval; + + if (pid == inferior_pid) + return read_register (regno); + + save_pid = inferior_pid; + + inferior_pid = pid; + + retval = read_register (regno); + + inferior_pid = save_pid; + + return retval; +} + +/* Store VALUE, into the raw contents of register number REGNO. */ + +void +write_register (regno, val) + int regno; + LONGEST val; +{ + PTR buf; + int size; + + /* On the sparc, writing %g0 is a no-op, so we don't even want to change + the registers array if something writes to this register. */ + if (CANNOT_STORE_REGISTER (regno)) + return; + + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + size = REGISTER_RAW_SIZE(regno); + buf = alloca (size); + store_signed_integer (buf, size, (LONGEST) val); + + /* If we have a valid copy of the register, and new value == old value, + then don't bother doing the actual store. */ + + if (register_valid [regno] + && memcmp (®isters[REGISTER_BYTE (regno)], buf, size) == 0) + return; + + target_prepare_to_store (); + + memcpy (®isters[REGISTER_BYTE (regno)], buf, size); + + register_valid [regno] = 1; + + target_store_registers (regno); +} + +static void +write_register_pid (regno, val, pid) + int regno; + LONGEST val; + int pid; +{ + int save_pid; + + if (pid == inferior_pid) + { + write_register (regno, val); + return; + } + + save_pid = inferior_pid; + + inferior_pid = pid; + + write_register (regno, val); + + inferior_pid = save_pid; +} + +/* Record that register REGNO contains VAL. + This is used when the value is obtained from the inferior or core dump, + so there is no need to store the value there. */ + +void +supply_register (regno, val) + int regno; + char *val; +{ + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + register_valid[regno] = 1; + memcpy (®isters[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno)); + + /* On some architectures, e.g. HPPA, there are a few stray bits in some + registers, that the rest of the code would like to ignore. */ +#ifdef CLEAN_UP_REGISTER_VALUE + CLEAN_UP_REGISTER_VALUE(regno, ®isters[REGISTER_BYTE(regno)]); +#endif +} + + +/* This routine is getting awfully cluttered with #if's. It's probably + time to turn this into READ_PC and define it in the tm.h file. + Ditto for write_pc. */ + +CORE_ADDR +read_pc () +{ +#ifdef TARGET_READ_PC + return TARGET_READ_PC (inferior_pid); +#else + return ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, inferior_pid)); +#endif +} + +CORE_ADDR +read_pc_pid (pid) + int pid; +{ +#ifdef TARGET_READ_PC + return TARGET_READ_PC (pid); +#else + return ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, pid)); +#endif +} + +void +write_pc (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_PC + TARGET_WRITE_PC (val, inferior_pid); +#else + write_register_pid (PC_REGNUM, val, inferior_pid); +#ifdef NPC_REGNUM + write_register_pid (NPC_REGNUM, val + 4, inferior_pid); +#ifdef NNPC_REGNUM + write_register_pid (NNPC_REGNUM, val + 8, inferior_pid); +#endif +#endif +#endif +} + +void +write_pc_pid (val, pid) + CORE_ADDR val; + int pid; +{ +#ifdef TARGET_WRITE_PC + TARGET_WRITE_PC (val, pid); +#else + write_register_pid (PC_REGNUM, val, pid); +#ifdef NPC_REGNUM + write_register_pid (NPC_REGNUM, val + 4, pid); +#ifdef NNPC_REGNUM + write_register_pid (NNPC_REGNUM, val + 8, pid); +#endif +#endif +#endif +} + +/* Cope with strage ways of getting to the stack and frame pointers */ + +CORE_ADDR +read_sp () +{ +#ifdef TARGET_READ_SP + return TARGET_READ_SP (); +#else + return read_register (SP_REGNUM); +#endif +} + +void +write_sp (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_SP + TARGET_WRITE_SP (val); +#else + write_register (SP_REGNUM, val); +#endif +} + +CORE_ADDR +read_fp () +{ +#ifdef TARGET_READ_FP + return TARGET_READ_FP (); +#else + return read_register (FP_REGNUM); +#endif +} + +void +write_fp (val) + CORE_ADDR val; +{ +#ifdef TARGET_WRITE_FP + TARGET_WRITE_FP (val); +#else + write_register (FP_REGNUM, val); +#endif +} + +/* Will calling read_var_value or locate_var_value on SYM end + up caring what frame it is being evaluated relative to? SYM must + be non-NULL. */ +int +symbol_read_needs_frame (sym) + struct symbol *sym; +{ + switch (SYMBOL_CLASS (sym)) + { + /* All cases listed explicitly so that gcc -Wall will detect it if + we failed to consider one. */ + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + return 1; + + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_TYPEDEF: + + case LOC_LABEL: + /* Getting the address of a label can be done independently of the block, + even if some *uses* of that address wouldn't work so well without + the right frame. */ + + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + return 0; + } + return 1; +} + +/* Given a struct symbol for a variable, + and a stack frame id, read the value of the variable + and return a (pointer to a) struct value containing the value. + If the variable cannot be found, return a zero pointer. + If FRAME is NULL, use the selected_frame. */ + +value_ptr +read_var_value (var, frame) + register struct symbol *var; + struct frame_info *frame; +{ + register value_ptr v; + struct type *type = SYMBOL_TYPE (var); + CORE_ADDR addr; + register int len; + + v = allocate_value (type); + VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ + len = TYPE_LENGTH (type); + + if (frame == NULL) frame = selected_frame; + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + /* Put the constant back in target format. */ + store_signed_integer (VALUE_CONTENTS_RAW (v), len, + (LONGEST) SYMBOL_VALUE (var)); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_LABEL: + /* Put the constant back in target format. */ + store_address (VALUE_CONTENTS_RAW (v), len, SYMBOL_VALUE_ADDRESS (var)); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_CONST_BYTES: + { + char *bytes_addr; + bytes_addr = SYMBOL_VALUE_BYTES (var); + memcpy (VALUE_CONTENTS_RAW (v), bytes_addr, len); + VALUE_LVAL (v) = not_lval; + return v; + } + + case LOC_STATIC: + addr = SYMBOL_VALUE_ADDRESS (var); + break; + + case LOC_ARG: + if (frame == NULL) + return 0; + addr = FRAME_ARGS_ADDRESS (frame); + if (!addr) + return 0; + addr += SYMBOL_VALUE (var); + break; + + case LOC_REF_ARG: + if (frame == NULL) + return 0; + addr = FRAME_ARGS_ADDRESS (frame); + if (!addr) + return 0; + addr += SYMBOL_VALUE (var); + addr = read_memory_unsigned_integer + (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); + break; + + case LOC_LOCAL: + case LOC_LOCAL_ARG: + if (frame == NULL) + return 0; + addr = FRAME_LOCALS_ADDRESS (frame); + addr += SYMBOL_VALUE (var); + break; + + case LOC_BASEREG: + case LOC_BASEREG_ARG: + { + char buf[MAX_REGISTER_RAW_SIZE]; + get_saved_register (buf, NULL, NULL, frame, SYMBOL_BASEREG (var), + NULL); + addr = extract_address (buf, REGISTER_RAW_SIZE (SYMBOL_BASEREG (var))); + addr += SYMBOL_VALUE (var); + break; + } + + case LOC_TYPEDEF: + error ("Cannot look up value of a typedef"); + break; + + case LOC_BLOCK: + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + return v; + + case LOC_REGISTER: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + { + struct block *b; + + if (frame == NULL) + return 0; + b = get_frame_block (frame); + + + if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR) + { + addr = + value_as_pointer (value_from_register (lookup_pointer_type (type), + SYMBOL_VALUE (var), + frame)); + VALUE_LVAL (v) = lval_memory; + } + else + return value_from_register (type, SYMBOL_VALUE (var), frame); + } + break; + + case LOC_UNRESOLVED: + { + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol (SYMBOL_NAME (var), NULL, NULL); + if (msym == NULL) + return 0; + addr = SYMBOL_VALUE_ADDRESS (msym); + } + break; + + case LOC_OPTIMIZED_OUT: + VALUE_LVAL (v) = not_lval; + VALUE_OPTIMIZED_OUT (v) = 1; + return v; + + default: + error ("Cannot look up value of a botched symbol."); + break; + } + + VALUE_ADDRESS (v) = addr; + VALUE_LAZY (v) = 1; + return v; +} + +/* Return a value of type TYPE, stored in register REGNUM, in frame + FRAME. */ + +value_ptr +value_from_register (type, regnum, frame) + struct type *type; + int regnum; + struct frame_info *frame; +{ + char raw_buffer [MAX_REGISTER_RAW_SIZE]; + CORE_ADDR addr; + int optim; + value_ptr v = allocate_value (type); + char *value_bytes = 0; + int value_bytes_copied = 0; + int num_storage_locs; + enum lval_type lval; + int len; + + CHECK_TYPEDEF (type); + len = TYPE_LENGTH (type); + + VALUE_REGNO (v) = regnum; + + num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ? + ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 : + 1); + + if (num_storage_locs > 1 +#ifdef GDB_TARGET_IS_H8500 + || TYPE_CODE (type) == TYPE_CODE_PTR +#endif + ) + { + /* Value spread across multiple storage locations. */ + + int local_regnum; + int mem_stor = 0, reg_stor = 0; + int mem_tracking = 1; + CORE_ADDR last_addr = 0; + CORE_ADDR first_addr = 0; + + value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE); + + /* Copy all of the data out, whereever it may be. */ + +#ifdef GDB_TARGET_IS_H8500 +/* This piece of hideosity is required because the H8500 treats registers + differently depending upon whether they are used as pointers or not. As a + pointer, a register needs to have a page register tacked onto the front. + An alternate way to do this would be to have gcc output different register + numbers for the pointer & non-pointer form of the register. But, it + doesn't, so we're stuck with this. */ + + if (TYPE_CODE (type) == TYPE_CODE_PTR + && len > 2) + { + int page_regnum; + + switch (regnum) + { + case R0_REGNUM: case R1_REGNUM: case R2_REGNUM: case R3_REGNUM: + page_regnum = SEG_D_REGNUM; + break; + case R4_REGNUM: case R5_REGNUM: + page_regnum = SEG_E_REGNUM; + break; + case R6_REGNUM: case R7_REGNUM: + page_regnum = SEG_T_REGNUM; + break; + } + + value_bytes[0] = 0; + get_saved_register (value_bytes + 1, + &optim, + &addr, + frame, + page_regnum, + &lval); + + if (lval == lval_register) + reg_stor++; + else + mem_stor++; + first_addr = addr; + last_addr = addr; + + get_saved_register (value_bytes + 2, + &optim, + &addr, + frame, + regnum, + &lval); + + if (lval == lval_register) + reg_stor++; + else + { + mem_stor++; + mem_tracking = mem_tracking && (addr == last_addr); + } + last_addr = addr; + } + else +#endif /* GDB_TARGET_IS_H8500 */ + for (local_regnum = regnum; + value_bytes_copied < len; + (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum), + ++local_regnum)) + { + get_saved_register (value_bytes + value_bytes_copied, + &optim, + &addr, + frame, + local_regnum, + &lval); + + if (regnum == local_regnum) + first_addr = addr; + if (lval == lval_register) + reg_stor++; + else + { + mem_stor++; + + mem_tracking = + (mem_tracking + && (regnum == local_regnum + || addr == last_addr)); + } + last_addr = addr; + } + + if ((reg_stor && mem_stor) + || (mem_stor && !mem_tracking)) + /* Mixed storage; all of the hassle we just went through was + for some good purpose. */ + { + VALUE_LVAL (v) = lval_reg_frame_relative; + VALUE_FRAME (v) = FRAME_FP (frame); + VALUE_FRAME_REGNUM (v) = regnum; + } + else if (mem_stor) + { + VALUE_LVAL (v) = lval_memory; + VALUE_ADDRESS (v) = first_addr; + } + else if (reg_stor) + { + VALUE_LVAL (v) = lval_register; + VALUE_ADDRESS (v) = first_addr; + } + else + fatal ("value_from_register: Value not stored anywhere!"); + + VALUE_OPTIMIZED_OUT (v) = optim; + + /* Any structure stored in more than one register will always be + an integral number of registers. Otherwise, you'd need to do + some fiddling with the last register copied here for little + endian machines. */ + + /* Copy into the contents section of the value. */ + memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len); + + /* Finally do any conversion necessary when extracting this + type from more than one register. */ +#ifdef REGISTER_CONVERT_TO_TYPE + REGISTER_CONVERT_TO_TYPE(regnum, type, VALUE_CONTENTS_RAW(v)); +#endif + return v; + } + + /* Data is completely contained within a single register. Locate the + register's contents in a real register or in core; + read the data in raw format. */ + + get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval); + VALUE_OPTIMIZED_OUT (v) = optim; + VALUE_LVAL (v) = lval; + VALUE_ADDRESS (v) = addr; + + /* Convert raw data to virtual format if necessary. */ + +#ifdef REGISTER_CONVERTIBLE + if (REGISTER_CONVERTIBLE (regnum)) + { + REGISTER_CONVERT_TO_VIRTUAL (regnum, type, + raw_buffer, VALUE_CONTENTS_RAW (v)); + } + else +#endif + { + /* Raw and virtual formats are the same for this register. */ + + if (TARGET_BYTE_ORDER == BIG_ENDIAN && len < REGISTER_RAW_SIZE (regnum)) + { + /* Big-endian, and we want less than full size. */ + VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len; + } + + memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len); + } + + return v; +} + +/* Given a struct symbol for a variable or function, + and a stack frame id, + return a (pointer to a) struct value containing the properly typed + address. */ + +value_ptr +locate_var_value (var, frame) + register struct symbol *var; + struct frame_info *frame; +{ + CORE_ADDR addr = 0; + struct type *type = SYMBOL_TYPE (var); + value_ptr lazy_value; + + /* Evaluate it first; if the result is a memory address, we're fine. + Lazy evaluation pays off here. */ + + lazy_value = read_var_value (var, frame); + if (lazy_value == 0) + error ("Address of \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var)); + + if (VALUE_LAZY (lazy_value) + || TYPE_CODE (type) == TYPE_CODE_FUNC) + { + addr = VALUE_ADDRESS (lazy_value); + return value_from_longest (lookup_pointer_type (type), (LONGEST) addr); + } + + /* Not a memory address; check what the problem was. */ + switch (VALUE_LVAL (lazy_value)) + { + case lval_register: + case lval_reg_frame_relative: + error ("Address requested for identifier \"%s\" which is in a register.", + SYMBOL_SOURCE_NAME (var)); + break; + + default: + error ("Can't take address of \"%s\" which isn't an lvalue.", + SYMBOL_SOURCE_NAME (var)); + break; + } + return 0; /* For lint -- never reached */ +} diff --git a/contrib/gdb/gdb/fork-child.c b/contrib/gdb/gdb/fork-child.c new file mode 100644 index 000000000000..df289d43d354 --- /dev/null +++ b/contrib/gdb/gdb/fork-child.c @@ -0,0 +1,309 @@ +/* Fork a Unix child process, and set up to debug it, for GDB. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "gdbcore.h" +#include "terminal.h" +#include "thread.h" + +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +extern char **environ; + +#ifndef SHELL_FILE +#define SHELL_FILE "/bin/sh" +#endif + +/* Start an inferior Unix child process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. SHELL_FILE is the shell file, + or NULL if we should pick one. Errors reported with error(). */ + +void +fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun, + shell_file) + char *exec_file; + char *allargs; + char **env; + void (*traceme_fun) PARAMS ((void)); + void (*init_trace_fun) PARAMS ((int)); + char *shell_file; +{ + int pid; + char *shell_command; + static char default_shell_file[] = SHELL_FILE; + int len; + /* Set debug_fork then attach to the child while it sleeps, to debug. */ + static int debug_fork = 0; + /* This is set to the result of setpgrp, which if vforked, will be visible + to you in the parent process. It's only used by humans for debugging. */ + static int debug_setpgrp = 657473; + char **save_our_env; + + /* If no exec file handed to us, get it from the exec-file command -- with + a good, common error message if none is specified. */ + if (exec_file == 0) + exec_file = get_exec_file(1); + + /* The user might want tilde-expansion, and in general probably wants + the program to behave the same way as if run from + his/her favorite shell. So we let the shell run it for us. + FIXME-maybe, we might want a "set shell" command so the user can change + the shell from within GDB (if so, change callers which pass in a non-NULL + shell_file too). */ + if (shell_file == NULL) + shell_file = getenv ("SHELL"); + if (shell_file == NULL) + shell_file = default_shell_file; + + /* Multiplying the length of exec_file by 4 is to account for the fact + that it may expand when quoted; it is a worst-case number based on + every character being '. */ + len = 5 + 4 * strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 12; + /* If desired, concat something onto the front of ALLARGS. + SHELL_COMMAND is the result. */ +#ifdef SHELL_COMMAND_CONCAT + shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len); + strcpy (shell_command, SHELL_COMMAND_CONCAT); +#else + shell_command = (char *) alloca (len); + shell_command[0] = '\0'; +#endif + strcat (shell_command, "exec "); + + /* Now add exec_file, quoting as necessary. */ + { + char *p; + int need_to_quote; + + /* Quoting in this style is said to work with all shells. But csh + on IRIX 4.0.1 can't deal with it. So we only quote it if we need + to. */ + p = exec_file; + while (1) + { + switch (*p) + { + case '\'': + case '"': + case '(': + case ')': + case '$': + case '&': + case ';': + case '<': + case '>': + case ' ': + case '\n': + case '\t': + need_to_quote = 1; + goto end_scan; + + case '\0': + need_to_quote = 0; + goto end_scan; + + default: + break; + } + ++p; + } + end_scan: + if (need_to_quote) + { + strcat (shell_command, "'"); + for (p = exec_file; *p != '\0'; ++p) + { + if (*p == '\'') + strcat (shell_command, "'\\''"); + else + strncat (shell_command, p, 1); + } + strcat (shell_command, "'"); + } + else + strcat (shell_command, exec_file); + } + + strcat (shell_command, " "); + strcat (shell_command, allargs); + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + + /* Retain a copy of our environment variables, since the child will + replace the value of environ and if we're vforked, we have to + restore it. */ + save_our_env = environ; + + /* Tell the terminal handling subsystem what tty we plan to run on; + it will just record the information for later. */ + + new_tty_prefork (inferior_io_terminal); + + /* It is generally good practice to flush any possible pending stdio + output prior to doing a fork, to avoid the possibility of both the + parent and child flushing the same data after the fork. */ + + gdb_flush (gdb_stdout); + gdb_flush (gdb_stderr); + +#if defined(USG) && !defined(HAVE_VFORK) + pid = fork (); +#else + if (debug_fork) + pid = fork (); + else + pid = vfork (); +#endif + + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + if (debug_fork) + sleep (debug_fork); + + /* Run inferior in a separate process group. */ + debug_setpgrp = gdb_setpgid (); + if (debug_setpgrp == -1) + perror("setpgrp failed in child"); + + /* Ask the tty subsystem to switch to the one we specified earlier + (or to share the current terminal, if none was specified). */ + + new_tty (); + + /* Changing the signal handlers for the inferior after + a vfork can also change them for the superior, so we don't mess + with signals here. See comments in + initialize_signals for how we get the right signal handlers + for the inferior. */ + + /* "Trace me, Dr. Memory!" */ + (*traceme_fun) (); + + /* There is no execlpe call, so we have to set the environment + for our child in the global variable. If we've vforked, this + clobbers the parent, but environ is restored a few lines down + in the parent. By the way, yes we do need to look down the + path to find $SHELL. Rich Pixley says so, and I agree. */ + environ = env; + execlp (shell_file, shell_file, "-c", shell_command, (char *)0); + + fprintf_unfiltered (gdb_stderr, "Cannot exec %s: %s.\n", shell_file, + safe_strerror (errno)); + gdb_flush (gdb_stderr); + _exit (0177); + } + + /* Restore our environment in case a vforked child clob'd it. */ + environ = save_our_env; + + init_thread_list(); + + inferior_pid = pid; /* Needed for wait_for_inferior stuff below */ + + /* Now that we have a child process, make it our target, and + initialize anything target-vector-specific that needs initializing. */ + (*init_trace_fun)(pid); + + /* We are now in the child process of interest, having exec'd the + correct program, and are poised at the first instruction of the + new program. */ + + /* Allow target dependant code to play with the new process. This might be + used to have target-specific code initialize a variable in the new process + prior to executing the first instruction. */ + TARGET_CREATE_INFERIOR_HOOK (pid); + +#ifdef SOLIB_CREATE_INFERIOR_HOOK + SOLIB_CREATE_INFERIOR_HOOK (pid); +#endif +} + +/* Accept NTRAPS traps from the inferior. */ + +void +startup_inferior (ntraps) + int ntraps; +{ + int pending_execs = ntraps; + int terminal_initted; + + /* The process was started by the fork that created it, + but it will have stopped one instruction after execing the shell. + Here we must get it up to actual execution of the real program. */ + + clear_proceed_status (); + + init_wait_for_inferior (); + + terminal_initted = 0; + +#ifdef STARTUP_INFERIOR + STARTUP_INFERIOR (pending_execs); +#else + while (1) + { + stop_soon_quietly = 1; /* Make wait_for_inferior be quiet */ + wait_for_inferior (); + if (stop_signal != TARGET_SIGNAL_TRAP) + { + /* Let shell child handle its own signals in its own way */ + /* FIXME, what if child has exit()ed? Must exit loop somehow */ + resume (0, stop_signal); + } + else + { + /* We handle SIGTRAP, however; it means child did an exec. */ + if (!terminal_initted) + { + /* Now that the child has exec'd we know it has already set its + process group. On POSIX systems, tcsetpgrp will fail with + EPERM if we try it before the child's setpgid. */ + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + terminal_initted = 1; + } + if (0 == --pending_execs) + break; + resume (0, TARGET_SIGNAL_0); /* Just make it go on */ + } + } +#endif /* STARTUP_INFERIOR */ + stop_soon_quietly = 0; +} diff --git a/contrib/gdb/gdb/frame.h b/contrib/gdb/gdb/frame.h new file mode 100644 index 000000000000..d9dc0f858129 --- /dev/null +++ b/contrib/gdb/gdb/frame.h @@ -0,0 +1,196 @@ +/* Definitions for dealing with stack frames, for GDB, the GNU debugger. + Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (FRAME_H) +#define FRAME_H 1 + +/* We keep a cache of stack frames, each of which is a "struct + frame_info". The innermost one gets allocated (in + wait_for_inferior) each time the inferior stops; current_frame + points to it. Additional frames get allocated (in + get_prev_frame_info) as needed, and are chained through the next + and prev fields. Any time that the frame cache becomes invalid + (most notably when we execute something, but also if we change how + we interpret the frames (e.g. "set heuristic-fence-post" in + mips-tdep.c, or anything which reads new symbols)), we should call + reinit_frame_cache. */ + +struct frame_info + { + /* Nominal address of the frame described. See comments at FRAME_FP + about what this means outside the *FRAME* macros; in the *FRAME* + macros, it can mean whatever makes most sense for this machine. */ + CORE_ADDR frame; + + /* Address at which execution is occurring in this frame. + For the innermost frame, it's the current pc. + For other frames, it is a pc saved in the next frame. */ + CORE_ADDR pc; + + /* Nonzero if this is a frame associated with calling a signal handler. + + Set by machine-dependent code. On some machines, if + the machine-dependent code fails to check for this, the backtrace + will look relatively normal. For example, on the i386 + #3 0x158728 in sighold () + On other machines (e.g. rs6000), the machine-dependent code better + set this to prevent us from trying to print it like a normal frame. */ + int signal_handler_caller; + + /* Anything extra for this structure that may have been defined + in the machine dependent files. */ +#ifdef EXTRA_FRAME_INFO + EXTRA_FRAME_INFO +#endif + + /* We should probably also store a "struct frame_saved_regs" here. + This is already done by some machines (e.g. config/m88k/tm-m88k.h) + but there is no reason it couldn't be general. */ + + /* Pointers to the next and previous frame_info's in the frame cache. */ + struct frame_info *next, *prev; + }; + +/* Describe the saved registers of a frame. */ + +struct frame_saved_regs + { + + /* For each register, address of where it was saved on entry to + the frame, or zero if it was not saved on entry to this frame. + This includes special registers such as pc and fp saved in + special ways in the stack frame. The SP_REGNUM is even more + special, the address here is the sp for the next frame, not the + address where the sp was saved. */ + + CORE_ADDR regs[NUM_REGS]; + }; + +/* Return the frame address from FR. Except in the machine-dependent + *FRAME* macros, a frame address has no defined meaning other than + as a magic cookie which identifies a frame over calls to the + inferior. The only known exception is inferior.h + (PC_IN_CALL_DUMMY) [ON_STACK]; see comments there. You cannot + assume that a frame address contains enough information to + reconstruct the frame; if you want more than just to identify the + frame (e.g. be able to fetch variables relative to that frame), + then save the whole struct frame_info (and the next struct + frame_info, since the latter is used for fetching variables on some + machines). */ + +#define FRAME_FP(fi) ((fi)->frame) + +/* Define a default FRAME_CHAIN_VALID, in the form that is suitable for most + targets. If FRAME_CHAIN_VALID returns zero it means that the given frame + is the outermost one and has no caller. + + If a particular target needs a different definition, then it can override + the definition here by providing one in the tm file. */ + +#if !defined (FRAME_CHAIN_VALID) + +#if defined (FRAME_CHAIN_VALID_ALTERNATE) + +/* Use the alternate method of avoiding running up off the end of the frame + chain or following frames back into the startup code. See the comments + in objfiles.h. */ + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_main_func ((thisframe) -> pc) \ + && !inside_entry_func ((thisframe) -> pc)) + +#else + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + ((chain) != 0 \ + && !inside_entry_file (FRAME_SAVED_PC (thisframe))) + +#endif /* FRAME_CHAIN_VALID_ALTERNATE */ + +#endif /* FRAME_CHAIN_VALID */ + +/* The stack frame that the user has specified for commands to act on. + Note that one cannot assume this is the address of valid data. */ + +extern struct frame_info *selected_frame; + +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +extern int selected_frame_level; + +extern struct frame_info *get_prev_frame_info PARAMS ((struct frame_info *)); + +extern struct frame_info *create_new_frame PARAMS ((CORE_ADDR, CORE_ADDR)); + +extern void flush_cached_frames PARAMS ((void)); + +extern void reinit_frame_cache PARAMS ((void)); + +extern void get_frame_saved_regs PARAMS ((struct frame_info *, + struct frame_saved_regs *)); + +extern void set_current_frame PARAMS ((struct frame_info *)); + +extern struct frame_info *get_prev_frame PARAMS ((struct frame_info *)); + +extern struct frame_info *get_current_frame PARAMS ((void)); + +extern struct frame_info *get_next_frame PARAMS ((struct frame_info *)); + +extern struct block *get_frame_block PARAMS ((struct frame_info *)); + +extern struct block *get_current_block PARAMS ((void)); + +extern struct block *get_selected_block PARAMS ((void)); + +extern struct symbol *get_frame_function PARAMS ((struct frame_info *)); + +extern CORE_ADDR get_frame_pc PARAMS ((struct frame_info *)); + +extern CORE_ADDR get_pc_function_start PARAMS ((CORE_ADDR)); + +extern struct block * block_for_pc PARAMS ((CORE_ADDR)); + +extern int frameless_look_for_prologue PARAMS ((struct frame_info *)); + +extern void print_frame_args PARAMS ((struct symbol *, struct frame_info *, + int, GDB_FILE *)); + +extern struct frame_info *find_relative_frame PARAMS ((struct frame_info *, int*)); + +extern void print_stack_frame PARAMS ((struct frame_info *, int, int)); + +extern void select_frame PARAMS ((struct frame_info *, int)); + +extern void record_selected_frame PARAMS ((CORE_ADDR *, int *)); + +extern void print_frame_info PARAMS ((struct frame_info *, int, int, int)); + +extern CORE_ADDR find_saved_register PARAMS ((struct frame_info *, int)); + +extern struct frame_info *block_innermost_frame PARAMS ((struct block *)); + +extern struct frame_info *find_frame_addr_in_frame_chain PARAMS ((CORE_ADDR)); + +extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *)); + +#endif /* !defined (FRAME_H) */ diff --git a/contrib/gdb/gdb/gdb-stabs.h b/contrib/gdb/gdb/gdb-stabs.h new file mode 100644 index 000000000000..cb7b6215da22 --- /dev/null +++ b/contrib/gdb/gdb/gdb-stabs.h @@ -0,0 +1,78 @@ +/* Definitions for symbol-reading containing "stabs", for GDB. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file exists to hold the common definitions required of most of + the symbol-readers that end up using stabs. The common use of + these `symbol-type-specific' customizations of the generic data + structures makes the stabs-oriented symbol readers able to call + each others' functions as required. */ + +#if !defined (GDBSTABS_H) +#define GDBSTABS_H + +/* Offsets in the psymtab's section_offsets array for various kinds of + stabs symbols. Every psymtab built from stabs will have these offsets + filled in by these guidelines, so that when actually reading symbols, the + proper offset can simply be selected and added to the symbol value. */ + +#define SECT_OFF_TEXT 0 +#define SECT_OFF_DATA 1 +#define SECT_OFF_BSS 2 +#define SECT_OFF_RODATA 3 +#define SECT_OFF_MAX 4 /* Count of possible values */ + +/* The stab_section_info chain remembers info from the ELF symbol table, + while psymtabs are being built for the other symbol tables in the + objfile. It is destroyed at the complation of psymtab-reading. + Any info that was used from it has been copied into psymtabs. */ + +struct stab_section_info { + char *filename; + CORE_ADDR sections[SECT_OFF_MAX]; + struct stab_section_info *next; + int found; /* Count of times it's found in searching */ +}; + +/* Information is passed among various dbxread routines for accessing + symbol files. A pointer to this structure is kept in the sym_stab_info + field of the objfile struct. */ + +struct dbx_symfile_info { + CORE_ADDR text_addr; /* Start of text section */ + int text_size; /* Size of text section */ + int symcount; /* How many symbols are there in the file */ + char *stringtab; /* The actual string table */ + int stringtab_size; /* Its size */ + file_ptr symtab_offset; /* Offset in file to symbol table */ + int symbol_size; /* Bytes in a single symbol */ + struct stab_section_info *stab_section_info; /* section starting points + of the original .o files before linking. */ +}; + +#define DBX_SYMFILE_INFO(o) ((struct dbx_symfile_info *)((o)->sym_stab_info)) +#define DBX_TEXT_ADDR(o) (DBX_SYMFILE_INFO(o)->text_addr) +#define DBX_TEXT_SIZE(o) (DBX_SYMFILE_INFO(o)->text_size) +#define DBX_SYMCOUNT(o) (DBX_SYMFILE_INFO(o)->symcount) +#define DBX_STRINGTAB(o) (DBX_SYMFILE_INFO(o)->stringtab) +#define DBX_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->stringtab_size) +#define DBX_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->symtab_offset) +#define DBX_SYMBOL_SIZE(o) (DBX_SYMFILE_INFO(o)->symbol_size) + +#endif /* GDBSTABS_H */ diff --git a/contrib/gdb/gdb/gdb.1 b/contrib/gdb/gdb/gdb.1 new file mode 100644 index 000000000000..cb1cba12808e --- /dev/null +++ b/contrib/gdb/gdb/gdb.1 @@ -0,0 +1,371 @@ +.\" Copyright (c) 1991 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.\" $Id: gdb.1,v 1.3 1991/12/13 22:22:58 pesch Exp $ +.TH gdb 1 "4nov1991" "GNU Tools" "GNU Tools" +.SH NAME +gdb \- The GNU Debugger +.SH SYNOPSIS +.na +.TP +.B gdb +.RB "[\|" \-help "\|]" +.RB "[\|" \-nx "\|]" +.RB "[\|" \-q "\|]" +.RB "[\|" \-batch "\|]" +.RB "[\|" \-cd=\c +.I dir\c +\|] +.RB "[\|" \-f "\|]" +.RB "[\|" "\-b\ "\c +.IR bps "\|]" +.RB "[\|" "\-tty="\c +.IR dev "\|]" +.RB "[\|" "\-s "\c +.I symfile\c +\&\|] +.RB "[\|" "\-e "\c +.I prog\c +\&\|] +.RB "[\|" "\-se "\c +.I prog\c +\&\|] +.RB "[\|" "\-c "\c +.I core\c +\&\|] +.RB "[\|" "\-x "\c +.I cmds\c +\&\|] +.RB "[\|" "\-d "\c +.I dir\c +\&\|] +.RB "[\|" \c +.I prog\c +.RB "[\|" \c +.IR core \||\| procID\c +\&\|]\&\|] +.ad b +.SH DESCRIPTION +The purpose of a debugger such as GDB is to allow you to see what is +going on ``inside'' another program while it executes\(em\&or what another +program was doing at the moment it crashed. + +GDB can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +.TP +\ \ \ \(bu +Start your program, specifying anything that might affect its behavior. + +.TP +\ \ \ \(bu +Make your program stop on specified conditions. + +.TP +\ \ \ \(bu +Examine what has happened, when your program has stopped. + +.TP +\ \ \ \(bu +Change things in your program, so you can experiment with correcting the +effects of one bug and go on to learn about another. +.PP + +You can use GDB to debug programs written in C, C++, and Modula-2. +Fortran support will be added when a GNU Fortran compiler is ready. + +GDB is invoked with the shell command \c +.B gdb\c +\&. Once started, it reads +commands from the terminal until you tell it to exit with the GDB +command \c +.B quit\c +\&. You can get online help from \c +.B gdb\c +\& itself +by using the command \c +.B help\c +\&. + +You can run \c +.B gdb\c +\& with no arguments or options; but the most +usual way to start GDB is with one argument or two, specifying an +executable program as the argument: +.sp +.br +gdb\ program +.br +.sp + +You can also start with both an executable program and a core file specified: +.sp +.br +gdb\ program\ core +.br +.sp + +You can, instead, specify a process ID as a second argument, if you want +to debug a running process: +.sp +.br +gdb\ program\ 1234 +.br +.sp + +would attach GDB to process \c +.B 1234\c +\& (unless you also have a file +named `\|\c +.B 1234\c +\&\|'; GDB does check for a core file first). + +Here are some of the most frequently needed GDB commands: +.TP +.B break \fR[\|\fIfile\fB:\fR\|]\fIfunction +\& +Set a breakpoint at \c +.I function\c +\& (in \c +.I file\c +\&). +.TP +.B run \fR[\|\fIarglist\fR\|] +Start your program (with \c +.I arglist\c +\&, if specified). +.TP +.B bt +Backtrace: display the program stack. +.TP +.BI print " expr"\c +\& +Display the value of an expression. +.TP +.B c +Continue running your program (after stopping, e.g. at a breakpoint). +.TP +.B next +Execute next program line (after stopping); step \c +.I over\c +\& any +function calls in the line. +.TP +.B step +Execute next program line (after stopping); step \c +.I into\c +\& any +function calls in the line. +.TP +.B help \fR[\|\fIname\fR\|] +Show information about GDB command \c +.I name\c +\&, or general information +about using GDB. +.TP +.B quit +Exit from GDB. +.PP +For full details on GDB, see \c +.I +Using GDB: A Guide to the GNU Source-Level Debugger\c +\&, by Richard M. Stallman and Roland H. Pesch. The same text is available online +as the \c +.B gdb\c +\& entry in the \c +.B info\c +\& program. +.SH OPTIONS +Any arguments other than options specify an executable +file and core file (or process ID); that is, the first argument +encountered with no +associated option flag is equivalent to a `\|\c +.B \-se\c +\&\|' option, and the +second, if any, is equivalent to a `\|\c +.B \-c\c +\&\|' option if it's the name of a file. Many options have +both long and short forms; both are shown here. The long forms are also +recognized if you truncate them, so long as enough of the option is +present to be unambiguous. (If you prefer, you can flag option +arguments with `\|\c +.B +\c +\&\|' rather than `\|\c +.B \-\c +\&\|', though we illustrate the +more usual convention.) + +All the options and command line arguments you give are processed +in sequential order. The order makes a difference when the +`\|\c +.B \-x\c +\&\|' option is used. + +.TP +.B \-help +.TP +.B \-h +List all options, with brief explanations. + +.TP +.BI "\-symbols=" "file"\c +.TP +.BI "\-s " "file"\c +\& +Read symbol table from file \c +.I file\c +\&. + +.TP +.BI "\-exec=" "file"\c +.TP +.BI "\-e " "file"\c +\& +Use file \c +.I file\c +\& as the executable file to execute when +appropriate, and for examining pure data in conjunction with a core +dump. + +.TP +.BI "\-se=" "file"\c +\& +Read symbol table from file \c +.I file\c +\& and use it as the executable +file. + +.TP +.BI "\-core=" "file"\c +.TP +.BI "\-c " "file"\c +\& +Use file \c +.I file\c +\& as a core dump to examine. + +.TP +.BI "\-command=" "file"\c +.TP +.BI "\-x " "file"\c +\& +Execute GDB commands from file \c +.I file\c +\&. + +.TP +.BI "\-directory=" "directory"\c +.TP +.BI "\-d " "directory"\c +\& +Add \c +.I directory\c +\& to the path to search for source files. +.PP + +.TP +.B \-nx +.TP +.B \-n +Do not execute commands from any `\|\c +.B .gdbinit\c +\&\|' initialization files. +Normally, the commands in these files are executed after all the +command options and arguments have been processed. + + +.TP +.B \-quiet +.TP +.B \-q +``Quiet''. Do not print the introductory and copyright messages. These +messages are also suppressed in batch mode. + +.TP +.B \-batch +Run in batch mode. Exit with status \c +.B 0\c +\& after processing all the command +files specified with `\|\c +.B \-x\c +\&\|' (and `\|\c +.B .gdbinit\c +\&\|', if not inhibited). +Exit with nonzero status if an error occurs in executing the GDB +commands in the command files. + +Batch mode may be useful for running GDB as a filter, for example to +download and run a program on another computer; in order to make this +more useful, the message +.sp +.br +Program\ exited\ normally. +.br +.sp + +(which is ordinarily issued whenever a program running under GDB control +terminates) is not issued when running in batch mode. + +.TP +.BI "\-cd=" "directory"\c +\& +Run GDB using \c +.I directory\c +\& as its working directory, +instead of the current directory. + +.TP +.B \-fullname +.TP +.B \-f +Emacs sets this option when it runs GDB as a subprocess. It tells GDB +to output the full file name and line number in a standard, +recognizable fashion each time a stack frame is displayed (which +includes each time the program stops). This recognizable format looks +like two `\|\c +.B \032\c +\&\|' characters, followed by the file name, line number +and character position separated by colons, and a newline. The +Emacs-to-GDB interface program uses the two `\|\c +.B \032\c +\&\|' characters as +a signal to display the source code for the frame. + +.TP +.BI "\-b " "bps"\c +\& +Set the line speed (baud rate or bits per second) of any serial +interface used by GDB for remote debugging. + +.TP +.BI "\-tty=" "device"\c +\& +Run using \c +.I device\c +\& for your program's standard input and output. +.PP + +.SH "SEE ALSO" +.RB "`\|" gdb "\|'" +entry in +.B info\c +\&; +.I +Using GDB: A Guide to the GNU Source-Level Debugger\c +, Richard M. Stallman and Roland H. Pesch, July 1991. +.SH COPYING +Copyright (c) 1991 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/contrib/gdb/gdb/gdb.gdb b/contrib/gdb/gdb/gdb.gdb new file mode 100644 index 000000000000..437784102c1f --- /dev/null +++ b/contrib/gdb/gdb/gdb.gdb @@ -0,0 +1,35 @@ +# Examples of using gdb's command language to print out various gdb data +# structures. + +define list-objfiles + set $obj = object_files + printf "objfile bfd msyms name\n" + while $obj != 0 + printf "0x%-8x 0x%-8x %6d %s\n", $obj, $obj->obfd, \ + $obj->minimal_symbol_count, $obj->name + set var $obj = $obj->next + end +end +document list-objfiles +Print a table of the current objfiles. +end + +define print-values + printf "Location Offset Size Lazy Contents0-3 Lval\n" + set $val = $arg0 + while $val != 0 + printf "%8x %6d %10d %4d %12x ", $val->location.address, \ + $val->offset, \ + $val->type->length, $val->lazy, $val->aligner.contents[0] + output $val->lval + printf "\n" + set $val = $val->next + end +end +document print-values +Print a list of values. +Takes one argument, the value to print, and prints all the values which +are chained through the next field. Thus the most recently created values +will be listed first. The "Contents0-3" field gives the first "int" +of the VALUE_CONTENTS; not the entire contents. +end diff --git a/contrib/gdb/gdb/gdb_stat.h b/contrib/gdb/gdb/gdb_stat.h new file mode 100644 index 000000000000..b871b292a53c --- /dev/null +++ b/contrib/gdb/gdb/gdb_stat.h @@ -0,0 +1,68 @@ +/* Portable + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined(GDB_STAT_H) +#define GDB_STAT_H + +#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 +#if !defined(S_ISCHR) && defined(S_IFCHR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ +#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ +#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +#endif /* !defined(GDB_STAT_H) */ diff --git a/contrib/gdb/gdb/gdb_string.h b/contrib/gdb/gdb/gdb_string.h new file mode 100644 index 000000000000..4fb53bb519b7 --- /dev/null +++ b/contrib/gdb/gdb/gdb_string.h @@ -0,0 +1,48 @@ +/* Portable + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined(GDB_STRING_H) +#define GDB_STRING_H + +#ifdef STDC_HEADERS +#include +#else +# ifdef HAVE_STRING_H +# include +# else +# include +# endif +extern char *strchr(); +extern char *strrchr(); +extern char *strstr(); +extern char *strtok(); +extern char *strerror(); +# ifdef HAVE_MEMORY_H +# include +# else +extern void *memset(); +extern void *memcpy(); +extern void *memmove(); +extern int memcmp(); +# endif +#endif + +extern char *strdup(); + +#endif /* !defined(GDB_STRING_H) */ diff --git a/contrib/gdb/gdb/gdba.el b/contrib/gdb/gdb/gdba.el new file mode 100644 index 000000000000..0f7158642280 --- /dev/null +++ b/contrib/gdb/gdb/gdba.el @@ -0,0 +1,2607 @@ +(defmacro gud (form) + (` (save-excursion (set-buffer "*gud-a.out*") (, form)))) + +(defun dbug (foo &optional fun) + (save-excursion + (set-buffer (get-buffer-create "*trace*")) + (goto-char (point-max)) + (insert "***" (symbol-name foo) "\n") + (if fun + (funcall fun)))) + + +;;; gud.el --- Grand Unified Debugger mode for gdb, sdb, dbx, or xdb +;;; under Emacs + +;; Author: Eric S. Raymond +;; Maintainer: FSF +;; Version: 1.3 +;; Keywords: unix, tools + +;; Copyright (C) 1992, 1993 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs 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 GNU Emacs; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; The ancestral gdb.el was by W. Schelter +;; It was later rewritten by rms. Some ideas were due to Masanobu. +;; Grand Unification (sdb/dbx support) by Eric S. Raymond +;; The overloading code was then rewritten by Barry Warsaw , +;; who also hacked the mode to use comint.el. Shane Hartman +;; added support for xdb (HPUX debugger). + +;; Cygnus Support added support for gdb's --annotate=2. + +;;; Code: + +(require 'comint) +(require 'etags) + +;; ====================================================================== +;; GUD commands must be visible in C buffers visited by GUD + +(defvar gud-key-prefix "\C-x\C-a" + "Prefix of all GUD commands valid in C buffers.") + +(global-set-key (concat gud-key-prefix "\C-l") 'gud-refresh) +(global-set-key "\C-x " 'gud-break) ;; backward compatibility hack + +;; ====================================================================== +;; the overloading mechanism + +(defun gud-overload-functions (gud-overload-alist) + "Overload functions defined in GUD-OVERLOAD-ALIST. +This association list has elements of the form + (ORIGINAL-FUNCTION-NAME OVERLOAD-FUNCTION)" + (mapcar + (function (lambda (p) (fset (car p) (symbol-function (cdr p))))) + gud-overload-alist)) + +(defun gud-massage-args (file args) + (error "GUD not properly entered.")) + +(defun gud-marker-filter (str) + (error "GUD not properly entered.")) + +(defun gud-find-file (f) + (error "GUD not properly entered.")) + +;; ====================================================================== +;; command definition + +;; This macro is used below to define some basic debugger interface commands. +;; Of course you may use `gud-def' with any other debugger command, including +;; user defined ones. + +;; A macro call like (gud-def FUNC NAME KEY DOC) expands to a form +;; which defines FUNC to send the command NAME to the debugger, gives +;; it the docstring DOC, and binds that function to KEY in the GUD +;; major mode. The function is also bound in the global keymap with the +;; GUD prefix. + +(defmacro gud-def (func cmd key &optional doc) + "Define FUNC to be a command sending STR and bound to KEY, with +optional doc string DOC. Certain %-escapes in the string arguments +are interpreted specially if present. These are: + + %f name (without directory) of current source file. + %d directory of current source file. + %l number of current source line + %e text of the C lvalue or function-call expression surrounding point. + %a text of the hexadecimal address surrounding point + %p prefix argument to the command (if any) as a number + + The `current' source file is the file of the current buffer (if +we're in a C file) or the source file current at the last break or +step (if we're in the GUD buffer). + The `current' line is that of the current buffer (if we're in a +source file) or the source line number at the last break or step (if +we're in the GUD buffer)." + (list 'progn + (list 'defun func '(arg) + (or doc "") + '(interactive "p") + (list 'gud-call cmd 'arg)) + (if key + (list 'define-key + '(current-local-map) + (concat "\C-c" key) + (list 'quote func))) + (if key + (list 'global-set-key + (list 'concat 'gud-key-prefix key) + (list 'quote func))))) + +;; Where gud-display-frame should put the debugging arrow. This is +;; set by the marker-filter, which scans the debugger's output for +;; indications of the current program counter. +(defvar gud-last-frame nil) + +;; Used by gud-refresh, which should cause gud-display-frame to redisplay +;; the last frame, even if it's been called before and gud-last-frame has +;; been set to nil. +(defvar gud-last-last-frame nil) + +;; All debugger-specific information is collected here. +;; Here's how it works, in case you ever need to add a debugger to the mode. +;; +;; Each entry must define the following at startup: +;; +;; +;; comint-prompt-regexp +;; gud--massage-args +;; gud--marker-filter +;; gud--find-file +;; +;; The job of the massage-args method is to modify the given list of +;; debugger arguments before running the debugger. +;; +;; The job of the marker-filter method is to detect file/line markers in +;; strings and set the global gud-last-frame to indicate what display +;; action (if any) should be triggered by the marker. Note that only +;; whatever the method *returns* is displayed in the buffer; thus, you +;; can filter the debugger's output, interpreting some and passing on +;; the rest. +;; +;; The job of the find-file method is to visit and return the buffer indicated +;; by the car of gud-tag-frame. This may be a file name, a tag name, or +;; something else. + +;; ====================================================================== +;; gdb functions + +;;; History of argument lists passed to gdb. +(defvar gud-gdb-history nil) + +(defun gud-gdb-massage-args (file args) + (cons "--annotate=2" (cons file args))) + + +;; +;; In this world, there are gdb instance objects (of unspecified +;; representation) and buffers associated with those objects. +;; + +;; +;; gdb-instance objects +;; + +(defun make-gdb-instance (proc) + "Create a gdb instance object from a gdb process." + (setq last-proc proc) + (let ((instance (cons 'gdb-instance proc))) + (save-excursion + (set-buffer (process-buffer proc)) + (setq gdb-buffer-instance instance) + (progn + (mapcar 'make-variable-buffer-local gdb-instance-variables) + (setq gdb-buffer-type 'gud) + ;; If we're taking over the buffer of another process, + ;; take over it's ancillery buffers as well. + ;; + (let ((dead (or old-gdb-buffer-instance))) + (mapcar + (function + (lambda (b) + (progn + (set-buffer b) + (if (eq dead gdb-buffer-instance) + (setq gdb-buffer-instance instance))))) + (buffer-list))))) + instance)) + +(defun gdb-instance-process (inst) (cdr inst)) + +;;; The list of instance variables is built up by the expansions of +;;; DEF-GDB-VARIABLE +;;; +(defvar gdb-instance-variables '() + "A list of variables that are local to the gud buffer associated +with a gdb instance.") + +(defmacro def-gdb-variable + (name accessor setter &optional default doc) + (` + (progn + (defvar (, name) (, default) (, (or doc "undocumented"))) + (if (not (memq '(, name) gdb-instance-variables)) + (setq gdb-instance-variables + (cons '(, name) gdb-instance-variables))) + (, (and accessor + (` + (defun (, accessor) (instance) + (let + ((buffer (gdb-get-instance-buffer instance 'gud))) + (and buffer + (save-excursion + (set-buffer buffer) + (, name)))))))) + (, (and setter + (` + (defun (, setter) (instance val) + (let + ((buffer (gdb-get-instance-buffer instance 'gud))) + (and buffer + (save-excursion + (set-buffer buffer) + (setq (, name) val))))))))))) + +(defmacro def-gdb-var (root-symbol &optional default doc) + (let* ((root (symbol-name root-symbol)) + (accessor (intern (concat "gdb-instance-" root))) + (setter (intern (concat "set-gdb-instance-" root))) + (var-name (intern (concat "gdb-" root)))) + (` (def-gdb-variable + (, var-name) (, accessor) (, setter) + (, default) (, doc))))) + +(def-gdb-var buffer-instance nil + "In an instance buffer, the buffer's instance.") + +(def-gdb-var buffer-type nil + "One of the symbols bound in gdb-instance-buffer-rules") + +(def-gdb-var burst "" + "A string of characters from gdb that have not yet been processed.") + +(def-gdb-var input-queue () + "A list of high priority gdb command objects.") + +(def-gdb-var idle-input-queue () + "A list of low priority gdb command objects.") + +(def-gdb-var prompting nil + "True when gdb is idle with no pending input.") + +(def-gdb-var output-sink 'user + "The disposition of the output of the current gdb command. +Possible values are these symbols: + + user -- gdb output should be copied to the gud buffer + for the user to see. + + inferior -- gdb output should be copied to the inferior-io buffer + + pre-emacs -- output should be ignored util the post-prompt + annotation is received. Then the output-sink + becomes:... + emacs -- output should be collected in the partial-output-buffer + for subsequent processing by a command. This is the + disposition of output generated by commands that + gud mode sends to gdb on its own behalf. + post-emacs -- ignore input until the prompt annotation is + received, then go to USER disposition. +") + +(def-gdb-var current-item nil + "The most recent command item sent to gdb.") + +(def-gdb-var pending-triggers '() + "A list of trigger functions that have run later than their output +handlers.") + +(defun in-gdb-instance-context (instance form) + "Funcall `form' in the gud buffer of `instance'" + (save-excursion + (set-buffer (gdb-get-instance-buffer instance 'gud)) + (funcall form))) + +;; end of instance vars + +;; +;; finding instances +;; + +(defun gdb-proc->instance (proc) + (save-excursion + (set-buffer (process-buffer proc)) + gdb-buffer-instance)) + +(defun gdb-mru-instance-buffer () + "Return the most recently used (non-auxiliary) gdb gud buffer." + (save-excursion + (gdb-goto-first-gdb-instance (buffer-list)))) + +(defun gdb-goto-first-gdb-instance (blist) + "Use gdb-mru-instance-buffer -- not this." + (and blist + (progn + (set-buffer (car blist)) + (or (and gdb-buffer-instance + (eq gdb-buffer-type 'gud) + (car blist)) + (gdb-goto-first-gdb-instance (cdr blist)))))) + +(defun buffer-gdb-instance (buf) + (save-excursion + (set-buffer buf) + gdb-buffer-instance)) + +(defun gdb-needed-default-instance () + "Return the most recently used gdb instance or signal an error." + (let ((buffer (gdb-mru-instance-buffer))) + (or (and buffer (buffer-gdb-instance buffer)) + (error "No instance of gdb found.")))) + +(defun gdb-instance-target-string (instance) + "The apparent name of the program being debugged by a gdb instance. +For sure this the root string used in smashing together the gud +buffer's name, even if that doesn't happen to be the name of a +program." + (in-gdb-instance-context + instance + (function (lambda () gud-target-name)))) + + + +;; +;; Instance Buffers. +;; + +;; More than one buffer can be associated with a gdb instance. +;; +;; Each buffer has a TYPE -- a symbol that identifies the function +;; of that particular buffer. +;; +;; The usual gud interaction buffer is given the type `gud' and +;; is constructed specially. +;; +;; Others are constructed by gdb-get-create-instance-buffer and +;; named according to the rules set forth in the gdb-instance-buffer-rules-assoc + +(defun gdb-get-instance-buffer (instance key) + "Return the instance buffer for `instance' tagged with type `key'. +The key should be one of the cars in `gdb-instance-buffer-rules-assoc'." + (save-excursion + (gdb-look-for-tagged-buffer instance key (buffer-list)))) + +(defun gdb-get-create-instance-buffer (instance key) + "Create a new gdb instance buffer of the type specified by `key'. +The key should be one of the cars in `gdb-instance-buffer-rules-assoc'." + (or (gdb-get-instance-buffer instance key) + (let* ((rules (assoc key gdb-instance-buffer-rules-assoc)) + (name (funcall (gdb-rules-name-maker rules) instance)) + (new (get-buffer-create name))) + (save-excursion + (set-buffer new) + (make-variable-buffer-local 'gdb-buffer-type) + (setq gdb-buffer-type key) + (make-variable-buffer-local 'gdb-buffer-instance) + (setq gdb-buffer-instance instance) + (if (cdr (cdr rules)) + (funcall (car (cdr (cdr rules))))) + new)))) + +(defun gdb-rules-name-maker (rules) (car (cdr rules))) + +(defun gdb-look-for-tagged-buffer (instance key bufs) + (let ((retval nil)) + (while (and (not retval) bufs) + (set-buffer (car bufs)) + (if (and (eq gdb-buffer-instance instance) + (eq gdb-buffer-type key)) + (setq retval (car bufs))) + (setq bufs (cdr bufs)) + ) + retval)) + +(defun gdb-instance-buffer-p (buf) + (save-excursion + (set-buffer buf) + (and gdb-buffer-type + (not (eq gdb-buffer-type 'gud))))) + +;; +;; This assoc maps buffer type symbols to rules. Each rule is a list of +;; at least one and possible more functions. The functions have these +;; roles in defining a buffer type: +;; +;; NAME - take an instance, return a name for this type buffer for that +;; instance. +;; The remaining function(s) are optional: +;; +;; MODE - called in new new buffer with no arguments, should establish +;; the proper mode for the buffer. +;; + +(defvar gdb-instance-buffer-rules-assoc '()) + +(defun gdb-set-instance-buffer-rules (buffer-type &rest rules) + (let ((binding (assoc buffer-type gdb-instance-buffer-rules-assoc))) + (if binding + (setcdr binding rules) + (setq gdb-instance-buffer-rules-assoc + (cons (cons buffer-type rules) + gdb-instance-buffer-rules-assoc))))) + +(gdb-set-instance-buffer-rules 'gud 'error) ; gud buffers are an exception to the rules + +;; +;; partial-output buffers +;; +;; These accumulate output from a command executed on +;; behalf of emacs (rather than the user). +;; + +(gdb-set-instance-buffer-rules 'gdb-partial-output-buffer + 'gdb-partial-output-name) + +(defun gdb-partial-output-name (instance) + (concat "*partial-output-" + (gdb-instance-target-string instance) + "*")) + + +(gdb-set-instance-buffer-rules 'gdb-inferior-io + 'gdb-inferior-io-name + 'gud-inferior-io-mode) + +(defun gdb-inferior-io-name (instance) + (concat "*input/output of " + (gdb-instance-target-string instance) + "*")) + +(defvar gdb-inferior-io-mode-map (copy-keymap comint-mode-map)) +(define-key comint-mode-map "\C-c\C-c" 'gdb-inferior-io-interrupt) +(define-key comint-mode-map "\C-c\C-z" 'gdb-inferior-io-stop) +(define-key comint-mode-map "\C-c\C-\\" 'gdb-inferior-io-quit) +(define-key comint-mode-map "\C-c\C-d" 'gdb-inferior-io-eof) + +(defun gud-inferior-io-mode () + "Major mode for gud inferior-io. + +\\{comint-mode-map}" + ;; We want to use comint because it has various nifty and familiar + ;; features. We don't need a process, but comint wants one, so create + ;; a dummy one. + (make-comint (substring (buffer-name) 1 (- (length (buffer-name)) 1)) + "/bin/cat") + (setq major-mode 'gud-inferior-io-mode) + (setq mode-name "Debuggee I/O") + (setq comint-input-sender 'gud-inferior-io-sender) +) + +(defun gud-inferior-io-sender (proc string) + (save-excursion + (set-buffer (process-buffer proc)) + (let ((instance gdb-buffer-instance)) + (set-buffer (gdb-get-instance-buffer instance 'gud)) + (let ((gud-proc (get-buffer-process (current-buffer)))) + (process-send-string gud-proc string) + (process-send-string gud-proc "\n") + )) + )) + +(defun gdb-inferior-io-interrupt (instance) + "Interrupt the program being debugged." + (interactive (list (gdb-needed-default-instance))) + (interrupt-process + (get-buffer-process (gdb-get-instance-buffer instance 'gud)) comint-ptyp)) + +(defun gdb-inferior-io-quit (instance) + "Send quit signal to the program being debugged." + (interactive (list (gdb-needed-default-instance))) + (quit-process + (get-buffer-process (gdb-get-instance-buffer instance 'gud)) comint-ptyp)) + +(defun gdb-inferior-io-stop (instance) + "Stop the program being debugged." + (interactive (list (gdb-needed-default-instance))) + (stop-process + (get-buffer-process (gdb-get-instance-buffer instance 'gud)) comint-ptyp)) + +(defun gdb-inferior-io-eof (instance) + "Send end-of-file to the program being debugged." + (interactive (list (gdb-needed-default-instance))) + (process-send-eof + (get-buffer-process (gdb-get-instance-buffer instance 'gud)))) + + +;; +;; gdb communications +;; + +;; INPUT: things sent to gdb +;; +;; Each instance has a high and low priority +;; input queue. Low priority input is sent only +;; when the high priority queue is idle. +;; +;; The queues are lists. Each element is either +;; a string (indicating user or user-like input) +;; or a list of the form: +;; +;; (INPUT-STRING HANDLER-FN) +;; +;; +;; The handler function will be called from the +;; partial-output buffer when the command completes. +;; This is the way to write commands which +;; invoke gdb commands autonomously. +;; +;; These lists are consumed tail first. +;; + +(defun gdb-send (proc string) + "A comint send filter for gdb. +This filter may simply queue output for a later time." + (let ((instance (gdb-proc->instance proc))) + (gdb-instance-enqueue-input instance (concat string "\n")))) + +;; Note: Stuff enqueued here will be sent to the next prompt, even if it +;; is a query, or other non-top-level prompt. To guarantee stuff will get +;; sent to the top-level prompt, currently it must be put in the idle queue. +;; ^^^^^^^^^ +;; [This should encourage gud extentions that invoke gdb commands to let +;; the user go first; it is not a bug. -t] +;; + +(defun gdb-instance-enqueue-input (instance item) + (if (gdb-instance-prompting instance) + (progn + (gdb-send-item instance item) + (set-gdb-instance-prompting instance nil)) + (set-gdb-instance-input-queue + instance + (cons item (gdb-instance-input-queue instance))))) + +(defun gdb-instance-dequeue-input (instance) + (let ((queue (gdb-instance-input-queue instance))) + (and queue + (if (not (cdr queue)) + (let ((answer (car queue))) + (set-gdb-instance-input-queue instance '()) + answer) + (gdb-take-last-elt queue))))) + +(defun gdb-instance-enqueue-idle-input (instance item) + (if (and (gdb-instance-prompting instance) + (not (gdb-instance-input-queue instance))) + (progn + (gdb-send-item instance item) + (set-gdb-instance-prompting instance nil)) + (set-gdb-instance-idle-input-queue + instance + (cons item (gdb-instance-idle-input-queue instance))))) + +(defun gdb-instance-dequeue-idle-input (instance) + (let ((queue (gdb-instance-idle-input-queue instance))) + (and queue + (if (not (cdr queue)) + (let ((answer (car queue))) + (set-gdb-instance-idle-input-queue instance '()) + answer) + (gdb-take-last-elt queue))))) + +; Don't use this in general. +(defun gdb-take-last-elt (l) + (if (cdr (cdr l)) + (gdb-take-last-elt (cdr l)) + (let ((answer (car (cdr l)))) + (setcdr l '()) + answer))) + + +;; +;; output -- things gdb prints to emacs +;; +;; GDB output is a stream interrupted by annotations. +;; Annotations can be recognized by their beginning +;; with \C-j\C-z\C-z\C-j +;; +;; The tag is a string obeying symbol syntax. +;; +;; The optional part `' can be either the empty string +;; or a space followed by more data relating to the annotation. +;; For example, the SOURCE annotation is followed by a filename, +;; line number and various useless goo. This data must not include +;; any newlines. +;; + + +(defun gud-gdb-marker-filter (string) + "A gud marker filter for gdb." + ;; Bogons don't tell us the process except through scoping crud. + (let ((instance (gdb-proc->instance proc))) + (gdb-output-burst instance string))) + +(defvar gdb-annotation-rules + '(("frames-invalid" gdb-invalidate-frames) + ("breakpoints-invalid" gdb-invalidate-breakpoints) + ("pre-prompt" gdb-pre-prompt) + ("prompt" gdb-prompt) + ("commands" gdb-subprompt) + ("overload-choice" gdb-subprompt) + ("query" gdb-subprompt) + ("prompt-for-continue" gdb-subprompt) + ("post-prompt" gdb-post-prompt) + ("source" gdb-source) + ("starting" gdb-starting) + ("exited" gdb-stopping) + ("signalled" gdb-stopping) + ("signal" gdb-stopping) + ("breakpoint" gdb-stopping) + ("watchpoint" gdb-stopping) + ("stopped" gdb-stopped) + ) + "An assoc mapping annotation tags to functions which process them.") + + +(defun gdb-ignore-annotation (instance args) + nil) + +(defconst gdb-source-spec-regexp + "\\(.*\\):\\([0-9]*\\):[0-9]*:[a-z]*:0x[a-f0-9]*") + +;; Do not use this except as an annotation handler." +(defun gdb-source (instance args) + (string-match gdb-source-spec-regexp args) + ;; Extract the frame position from the marker. + (setq gud-last-frame + (cons + (substring args (match-beginning 1) (match-end 1)) + (string-to-int (substring args + (match-beginning 2) + (match-end 2)))))) + +;; An annotation handler for `prompt'. +;; This sends the next command (if any) to gdb. +(defun gdb-prompt (instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'user) t) + ((eq sink 'post-emacs) + (set-gdb-instance-output-sink instance 'user)) + (t + (set-gdb-instance-output-sink instance 'user) + (error "Phase error in gdb-prompt (got %s)" sink)))) + (let ((highest (gdb-instance-dequeue-input instance))) + (if highest + (gdb-send-item instance highest) + (let ((lowest (gdb-instance-dequeue-idle-input instance))) + (if lowest + (gdb-send-item instance lowest) + (progn + (set-gdb-instance-prompting instance t) + (gud-display-frame))))))) + +;; An annotation handler for non-top-level prompts. +(defun gdb-subprompt (instance ignored) + (let ((highest (gdb-instance-dequeue-input instance))) + (if highest + (gdb-send-item instance highest) + (set-gdb-instance-prompting instance t)))) + +(defun gdb-send-item (instance item) + (set-gdb-instance-current-item instance item) + (if (stringp item) + (progn + (set-gdb-instance-output-sink instance 'user) + (process-send-string (gdb-instance-process instance) + item)) + (progn + (gdb-clear-partial-output instance) + (set-gdb-instance-output-sink instance 'pre-emacs) + (process-send-string (gdb-instance-process instance) + (car item))))) + +;; An annotation handler for `pre-prompt'. +;; This terminates the collection of output from a previous +;; command if that happens to be in effect. +(defun gdb-pre-prompt (instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'user) t) + ((eq sink 'emacs) + (set-gdb-instance-output-sink instance 'post-emacs) + (let ((handler + (car (cdr (gdb-instance-current-item instance))))) + (save-excursion + (set-buffer (gdb-get-create-instance-buffer + instance 'gdb-partial-output-buffer)) + (funcall handler)))) + (t + (set-gdb-instance-output-sink instance 'user) + (error "Output sink phase error 1."))))) + +;; An annotation handler for `starting'. This says that I/O for the subprocess +;; is now the program being debugged, not GDB. +(defun gdb-starting (instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'user) + (set-gdb-instance-output-sink instance 'inferior) + ;; FIXME: need to send queued input + ) + (t (error "Unexpected `starting' annotation"))))) + +;; An annotation handler for `exited' and other annotations which say that +;; I/O for the subprocess is now GDB, not the program being debugged. +(defun gdb-stopping (instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'inferior) + (set-gdb-instance-output-sink instance 'user) + ) + (t (error "Unexpected stopping annotation"))))) + +;; An annotation handler for `stopped'. It is just like gdb-stopping, except +;; that if we already set the output sink to 'user in gdb-stopping, that is +;; fine. +(defun gdb-stopped (instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'inferior) + (set-gdb-instance-output-sink instance 'user) + ) + ((eq sink 'user) + t) + (t (error "Unexpected stopping annotation"))))) + +;; An annotation handler for `post-prompt'. +;; This begins the collection of output from the current +;; command if that happens to be appropriate." +(defun gdb-post-prompt (instance ignored) + (gdb-invalidate-registers instance ignored) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'user) t) + ((eq sink 'pre-emacs) + (set-gdb-instance-output-sink instance 'emacs)) + + (t + (set-gdb-instance-output-sink instance 'user) + (error "Output sink phase error 3."))))) + +;; Handle a burst of output from a gdb instance. +;; This function is (indirectly) used as a gud-marker-filter. +;; It must return output (if any) to be insterted in the gud +;; buffer. + +(defun gdb-output-burst (instance string) + "Handle a burst of output from a gdb instance. +This function is (indirectly) used as a gud-marker-filter. +It must return output (if any) to be insterted in the gud +buffer." + + (save-match-data + (let ( + ;; Recall the left over burst from last time + (burst (concat (gdb-instance-burst instance) string)) + ;; Start accumulating output for the gud buffer + (output "")) + + ;; Process all the complete markers in this chunk. + + (while (string-match "\n\032\032\\(.*\\)\n" burst) + (let ((annotation (substring burst + (match-beginning 1) + (match-end 1)))) + + ;; Stuff prior to the match is just ordinary output. + ;; It is either concatenated to OUTPUT or directed + ;; elsewhere. + (setq output + (gdb-concat-output + instance + output + (substring burst 0 (match-beginning 0)))) + + ;; Take that stuff off the burst. + (setq burst (substring burst (match-end 0))) + + ;; Parse the tag from the annotation, and maybe its arguments. + (string-match "\\(\\S-*\\) ?\\(.*\\)" annotation) + (let* ((annotation-type (substring annotation + (match-beginning 1) + (match-end 1))) + (annotation-arguments (substring annotation + (match-beginning 2) + (match-end 2))) + (annotation-rule (assoc annotation-type + gdb-annotation-rules))) + ;; Call the handler for this annotation. + (if annotation-rule + (funcall (car (cdr annotation-rule)) + instance + annotation-arguments) + ;; Else the annotation is not recognized. Ignore it silently, + ;; so that GDB can add new annotations without causing + ;; us to blow up. + )))) + + + ;; Does the remaining text end in a partial line? + ;; If it does, then keep part of the burst until we get more. + (if (string-match "\n\\'\\|\n\032\\'\\|\n\032\032.*\\'" + burst) + (progn + ;; Everything before the potential marker start can be output. + (setq output + (gdb-concat-output + instance + output + (substring burst 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq burst (substring burst (match-beginning 0)))) + + ;; In case we know the burst contains no partial annotations: + (progn + (setq output (gdb-concat-output instance output burst)) + (setq burst ""))) + + ;; Save the remaining burst for the next call to this function. + (set-gdb-instance-burst instance burst) + output))) + +(defun gdb-concat-output (instance so-far new) + (let ((sink (gdb-instance-output-sink instance))) + (cond + ((eq sink 'user) (concat so-far new)) + ((or (eq sink 'pre-emacs) (eq sink 'post-emacs)) so-far) + ((eq sink 'emacs) + (gdb-append-to-partial-output instance new) + so-far) + ((eq sink 'inferior) + (gdb-append-to-inferior-io instance new) + so-far) + (t (error "Bogon output sink %S" sink))))) + +(defun gdb-append-to-partial-output (instance string) + (save-excursion + (set-buffer + (gdb-get-create-instance-buffer + instance 'gdb-partial-output-buffer)) + (goto-char (point-max)) + (insert string))) + +(defun gdb-clear-partial-output (instance) + (save-excursion + (set-buffer + (gdb-get-create-instance-buffer + instance 'gdb-partial-output-buffer)) + (delete-region (point-min) (point-max)))) + +(defun gdb-append-to-inferior-io (instance string) + (save-excursion + (set-buffer + (gdb-get-create-instance-buffer + instance 'gdb-inferior-io)) + (goto-char (point-max)) + (insert-before-markers string)) + (gud-display-buffer + (gdb-get-create-instance-buffer instance + 'gdb-inferior-io))) + +(defun gdb-clear-inferior-io (instance) + (save-excursion + (set-buffer + (gdb-get-create-instance-buffer + instance 'gdb-inferior-io)) + (delete-region (point-min) (point-max)))) + + + +;; One trick is to have a command who's output is always available in +;; a buffer of it's own, and is always up to date. We build several +;; buffers of this type. +;; +;; There are two aspects to this: gdb has to tell us when the output +;; for that command might have changed, and we have to be able to run +;; the command behind the user's back. +;; +;; The idle input queue and the output phasing associated with +;; the instance variable `(gdb-instance-output-sink instance)' help +;; us to run commands behind the user's back. +;; +;; Below is the code for specificly managing buffers of output from one +;; command. +;; + + +;; The trigger function is suitable for use in the assoc GDB-ANNOTATION-RULES +;; It adds an idle input for the command we are tracking. It should be the +;; annotation rule binding of whatever gdb sends to tell us this command +;; might have changed it's output. +;; +;; NAME is the fucntion name. DEMAND-PREDICATE tests if output is really needed. +;; GDB-COMMAND is a string of such. OUTPUT-HANDLER is the function bound to the +;; input in the input queue (see comment about ``gdb communications'' above). +(defmacro def-gdb-auto-update-trigger (name demand-predicate gdb-command output-handler) + (` + (defun (, name) (instance &optional ignored) + (if (and ((, demand-predicate) instance) + (not (member '(, name) + (gdb-instance-pending-triggers instance)))) + (progn + (gdb-instance-enqueue-idle-input + instance + (list (, gdb-command) '(, output-handler))) + (set-gdb-instance-pending-triggers + instance + (cons '(, name) + (gdb-instance-pending-triggers instance)))))))) + +(defmacro def-gdb-auto-update-handler (name trigger buf-key) + (` + (defun (, name) () + (set-gdb-instance-pending-triggers + instance + (delq '(, trigger) + (gdb-instance-pending-triggers instance))) + (let ((buf (gdb-get-instance-buffer instance + '(, buf-key)))) + (and buf + (save-excursion + (set-buffer buf) + (let ((p (point)) + (buffer-read-only nil)) + (delete-region (point-min) (point-max)) + (insert-buffer (gdb-get-create-instance-buffer + instance + 'gdb-partial-output-buffer)) + (goto-char p)))))))) + +(defmacro def-gdb-auto-updated-buffer + (buffer-key trigger-name gdb-command output-handler-name) + (` + (progn + (def-gdb-auto-update-trigger (, trigger-name) + ;; The demand predicate: + (lambda (instance) + (gdb-get-instance-buffer instance '(, buffer-key))) + (, gdb-command) + (, output-handler-name)) + (def-gdb-auto-update-handler (, output-handler-name) + (, trigger-name) (, buffer-key))))) + + + +;; +;; Breakpoint buffers +;; +;; These display the output of `info breakpoints'. +;; + + +(gdb-set-instance-buffer-rules 'gdb-breakpoints-buffer + 'gdb-breakpoints-buffer-name + 'gud-breakpoints-mode) + +(def-gdb-auto-updated-buffer gdb-breakpoints-buffer + ;; This defines the auto update rule for buffers of type + ;; `gdb-breakpoints-buffer'. + ;; + ;; It defines a function to serve as the annotation handler that + ;; handles the `foo-invalidated' message. That function is called: + gdb-invalidate-breakpoints + + ;; To update the buffer, this command is sent to gdb. + "server info breakpoints\n" + + ;; This also defines a function to be the handler for the output + ;; from the command above. That function will copy the output into + ;; the appropriately typed buffer. That function will be called: + gdb-info-breakpoints-handler) + +(defun gdb-breakpoints-buffer-name (instance) + (save-excursion + (set-buffer (process-buffer (gdb-instance-process instance))) + (concat "*breakpoints of " (gdb-instance-target-string instance) "*"))) + +(defun gud-display-breakpoints-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-display-buffer + (gdb-get-create-instance-buffer instance + 'gdb-breakpoints-buffer))) + +(defun gud-frame-breakpoints-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-frame-buffer + (gdb-get-create-instance-buffer instance + 'gdb-breakpoints-buffer))) + +(defvar gud-breakpoints-mode-map nil) +(setq gud-breakpoints-mode-map (make-keymap)) +(suppress-keymap gud-breakpoints-mode-map) +(define-key gud-breakpoints-mode-map " " 'gud-toggle-bp-this-line) +(define-key gud-breakpoints-mode-map "d" 'gud-delete-bp-this-line) + +(defun gud-breakpoints-mode () + "Major mode for gud breakpoints. + +\\{gud-breakpoints-mode-map}" + (setq major-mode 'gud-breakpoints-mode) + (setq mode-name "Breakpoints") + (use-local-map gud-breakpoints-mode-map) + (setq buffer-read-only t) + (gdb-invalidate-breakpoints gdb-buffer-instance)) + +(defun gud-toggle-bp-this-line () + (interactive) + (save-excursion + (beginning-of-line 1) + (if (not (looking-at "\\([0-9]*\\)\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)")) + (error "Not recognized as breakpoint line (demo foo).") + (gdb-instance-enqueue-idle-input + gdb-buffer-instance + (list + (concat + (if (eq ?y (char-after (match-beginning 2))) + "server disable " + "server enable ") + (buffer-substring (match-beginning 0) + (match-end 1)) + "\n") + '(lambda () nil))) + ))) + +(defun gud-delete-bp-this-line () + (interactive) + (save-excursion + (beginning-of-line 1) + (if (not (looking-at "\\([0-9]*\\)\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)")) + (error "Not recognized as breakpoint line (demo foo).") + (gdb-instance-enqueue-idle-input + gdb-buffer-instance + (list + (concat + "server delete " + (buffer-substring (match-beginning 0) + (match-end 1)) + "\n") + '(lambda () nil))) + ))) + + + + +;; +;; Frames buffers. These display a perpetually correct bactracktrace +;; (from the command `where'). +;; +;; Alas, if your stack is deep, they are costly. +;; + +(gdb-set-instance-buffer-rules 'gdb-stack-buffer + 'gdb-stack-buffer-name + 'gud-frames-mode) + +(def-gdb-auto-updated-buffer gdb-stack-buffer + gdb-invalidate-frames + "server where\n" + gdb-info-frames-handler) + +(defun gdb-stack-buffer-name (instance) + (save-excursion + (set-buffer (process-buffer (gdb-instance-process instance))) + (concat "*stack frames of " + (gdb-instance-target-string instance) "*"))) + +(defun gud-display-stack-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-display-buffer + (gdb-get-create-instance-buffer instance + 'gdb-stack-buffer))) + +(defun gud-frame-stack-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-frame-buffer + (gdb-get-create-instance-buffer instance + 'gdb-stack-buffer))) + +(defvar gud-frames-mode-map nil) +(setq gud-frames-mode-map (make-keymap)) +(suppress-keymap gud-frames-mode-map) +(define-key gud-frames-mode-map [mouse-2] + 'gud-frames-select-by-mouse) + +(defun gud-frames-mode () + "Major mode for gud frames. + +\\{gud-frames-mode-map}" + (setq major-mode 'gud-frames-mode) + (setq mode-name "Frames") + (setq buffer-read-only t) + (use-local-map gud-frames-mode-map) + (gdb-invalidate-frames gdb-buffer-instance)) + +(defun gud-get-frame-number () + (save-excursion + (let* ((pos (re-search-backward "^#\\([0-9]*\\)" nil t)) + (n (or (and pos + (string-to-int + (buffer-substring (match-beginning 1) + (match-end 1)))) + 0))) + n))) + +(defun gud-frames-select-by-mouse (e) + (interactive "e") + (let (selection) + (save-excursion + (set-buffer (window-buffer (posn-window (event-end e)))) + (save-excursion + (goto-char (posn-point (event-end e))) + (setq selection (gud-get-frame-number)))) + (select-window (posn-window (event-end e))) + (save-excursion + (set-buffer (gdb-get-instance-buffer (gdb-needed-default-instance) 'gud)) + (gud-call "fr %p" selection) + (gud-display-frame)))) + + +;; +;; Registers buffers +;; + +(def-gdb-auto-updated-buffer gdb-registers-buffer + gdb-invalidate-registers + "server info registers\n" + gdb-info-registers-handler) + +(gdb-set-instance-buffer-rules 'gdb-registers-buffer + 'gdb-registers-buffer-name + 'gud-registers-mode) + +(defvar gud-registers-mode-map nil) +(setq gud-registers-mode-map (make-keymap)) +(suppress-keymap gud-registers-mode-map) + +(defun gud-registers-mode () + "Major mode for gud registers. + +\\{gud-registers-mode-map}" + (setq major-mode 'gud-registers-mode) + (setq mode-name "Registers") + (setq buffer-read-only t) + (use-local-map gud-registers-mode-map) + (gdb-invalidate-registers gdb-buffer-instance)) + +(defun gdb-registers-buffer-name (instance) + (save-excursion + (set-buffer (process-buffer (gdb-instance-process instance))) + (concat "*registers of " (gdb-instance-target-string instance) "*"))) + +(defun gud-display-registers-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-display-buffer + (gdb-get-create-instance-buffer instance + 'gdb-registers-buffer))) + +(defun gud-frame-registers-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-frame-buffer + (gdb-get-create-instance-buffer instance + 'gdb-registers-buffer))) + + + +;;;; Menu windows: + + +;; MENU-LIST is ((option option option...) (option option ...)...) +;; +(defun gud-display-menu (menu-list) + (setq fill-column (min 120 (- (window-width) + (min 8 (window-width))))) + (while menu-list + (mapcar (function (lambda (x) (insert (symbol-name x) " "))) (car menu-list)) + (fill-paragraph nil) + (insert "\n\n") + (setq menu-list (cdr menu-list))) + (goto-char (point-min)) + (while (re-search-forward "\\([^ \n]+\\)\\(\n\\| \\)" nil t) + (put-text-property (match-beginning 1) (match-end 1) + 'mouse-face 'highlight)) + (goto-char (point-min))) + +(defun gud-goto-menu (menu) + (setq gud-menu-position menu) + (let ((buffer-read-only nil)) + (delete-region (point-min) (point-max)) + (gud-display-menu menu))) + +(defun gud-menu-pick (event) + "Choose an item from a gdb command menu." + (interactive "e") + (let (choice) + (save-excursion + (set-buffer (window-buffer (posn-window (event-start event)))) + (goto-char (posn-point (event-start event))) + (let (beg end) + (skip-chars-forward "^ \t\n") + (setq end (point)) + (skip-chars-backward "^ \t\n") + (setq beg (point)) + (setq choice (buffer-substring beg end)) + (message choice) + (gud-invoke-menu (intern choice)))))) + +(defun gud-invoke-menu (symbol) + (let ((meaning (assoc symbol gud-menu-rules))) + (cond + ((and (consp meaning) + (consp (car (cdr meaning)))) + (gud-goto-menu (car (cdr meaning)))) + (meaning (call-interactively (car (cdr meaning))))))) + + + +(gdb-set-instance-buffer-rules 'gdb-command-buffer + 'gdb-command-buffer-name + 'gud-command-mode) + +(defvar gud-command-mode-map nil) +(setq gud-command-mode-map (make-keymap)) +(suppress-keymap gud-command-mode-map) +(define-key gud-command-mode-map [mouse-2] 'gud-menu-pick) + +(defun gud-command-mode () + "Major mode for gud menu. + +\\{gud-command-mode-map}" (interactive) (setq major-mode 'gud-command-mode) + (setq mode-name "Menu") (setq buffer-read-only t) (use-local-map + gud-command-mode-map) (make-variable-buffer-local 'gud-menu-position) + (if (not gud-menu-position) (gud-goto-menu gud-running-menu))) + +(defun gdb-command-buffer-name (instance) + (save-excursion + (set-buffer (process-buffer (gdb-instance-process instance))) + (concat "*menu of " (gdb-instance-target-string instance) "*"))) + +(defun gud-display-command-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-display-buffer + (gdb-get-create-instance-buffer instance + 'gdb-command-buffer) + 6)) + +(defun gud-frame-command-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-frame-buffer + (gdb-get-create-instance-buffer instance + 'gdb-command-buffer))) + +(defvar gud-selected-menu-titles ()) +(setq gud-selected-menu-titles + '(RUNNING STACK DATA BREAKPOINTS FILES)) + +(setq gud-running-menu + (list + '(RUNNING stack breakpoints files) + '(target run next step continue finish stepi kill help-running))) + +(setq gud-stack-menu + (list + '(running STACK breakpoints files) + '(up down frame backtrace return help-stack))) + +(setq gud-data-menu + (list + '(running stack DATA breakpoints files) + '(whatis ptype print set display undisplay disassemble help-data))) + +(setq gud-breakpoints-menu + (list + '(running stack BREAKPOINTS files) + '(awatch rwatch watch break delete enable disable condition ignore help-breakpoints))) + +(setq gud-files-menu + (list + '(running stack breakpoints FILES) + '(file core-file help-files) + '(exec-file load symbol-file add-symbol-file sharedlibrary))) + +(setq gud-menu-rules + (list + (list 'running gud-running-menu) + (list 'RUNNING gud-running-menu) + (list 'stack gud-stack-menu) + (list 'STACK gud-stack-menu) + (list 'data gud-data-menu) + (list 'DATA gud-data-menu) + (list 'breakpoints gud-breakpoints-menu) + (list 'BREAKPOINTS gud-breakpoints-menu) + (list 'files gud-files-menu) + (list 'FILES gud-files-menu) + + (list 'target 'gud-target) + (list 'kill 'gud-kill) + (list 'stepi 'gud-stepi) + (list 'step 'gud-step) + (list 'next 'gud-next) + (list 'finish 'gud-finish) + (list 'continue 'gud-cont) + (list 'run 'gud-run) + + (list 'backtrace 'gud-backtrace) + (list 'frame 'gud-frame) + (list 'down 'gud-down) + (list 'up 'gud-up) + (list 'return 'gud-return) + + (list 'file 'gud-file) + (list 'core-file 'gud-core-file) + (list 'cd 'gud-cd) + + (list 'exec-file 'gud-exec-file) + (list 'load 'gud-load) + (list 'symbol-file 'gud-symbol-file) + (list 'add-symbol-file 'gud-add-symbol-file) + (list 'sharedlibrary 'gud-sharedlibrary) + )) + + + + +(defun gdb-call-showing-gud (instance command) + (gud-display-gud-buffer instance) + (comint-input-sender (gdb-instance-process instance) command)) + +(defvar gud-target-history ()) + +(defun gud-temp-buffer-show (buf) + (let ((ow (selected-window))) + (unwind-protect + (progn + (pop-to-buffer buf) + + ;; This insertion works around a bug in emacs. + ;; The bug is that all the empty space after a + ;; highlighted word that terminates a buffer + ;; gets highlighted. That's really ugly, so + ;; make sure a highlighted word can't ever + ;; terminate the buffer. + (goto-char (point-max)) + (insert "\n") + (goto-char (point-min)) + + (if (< (window-height) 10) + (enlarge-window (- 10 (window-height))))) + (select-window ow)))) + +(defun gud-target (instance command) + (interactive + (let* ((instance (gdb-needed-default-instance)) + (temp-buffer-show-function (function gud-temp-buffer-show)) + (target-name (completing-read (format "Target type: ") + '(("remote") + ("core") + ("child") + ("exec")) + nil + t + nil + 'gud-target-history))) + (list instance + (cond + ((equal target-name "child") "run") + + ((equal target-name "core") + (concat "target core " + (read-file-name "core file: " + nil + "core" + t))) + + ((equal target-name "exec") + (concat "target exec " + (read-file-name "exec file: " + nil + "a.out" + t))) + + ((equal target-name "remote") + (concat "target remote " + (read-file-name "serial line for remote: " + "/dev/" + "ttya" + t))) + + (t "echo No such target command!"))))) + + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + +(defun gud-backtrace () + (interactive) + (let ((instance (gdb-needed-default-instance))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) + "backtrace")))) + +(defun gud-frame () + (interactive) + (let ((instance (gdb-needed-default-instance))) + (apply comint-input-sender + (list (gdb-instance-process instance) + "frame")))) + +(defun gud-return (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "return " (read-string "Expression to return: "))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + + +(defun gud-file (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "file " (read-file-name "Executable to debug: " + nil + "a.out" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + +(defun gud-core-file (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "core " (read-file-name "Core file to debug: " + nil + "core-file" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + +(defun gud-cd (dir) + (interactive "FChange GDB's default directory: ") + (let ((instance (gdb-needed-default-instance))) + (save-excursion + (set-buffer (gdb-get-instance-buffer instance 'gud)) + (cd dir)) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) + (concat "cd " dir))))) + + +(defun gud-exec-file (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "exec-file " (read-file-name "Init memory from executable: " + nil + "a.out" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + +(defun gud-load (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "load " (read-file-name "Dynamicly load from file: " + nil + "a.out" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + +(defun gud-symbol-file (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "symbol-file " (read-file-name "Read symbol table from file: " + nil + "a.out" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + + +(defun gud-add-symbol-file (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "add-symbol-file " + (read-file-name "Add symbols from file: " + nil + "a.out" + t))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + + +(defun gud-sharedlibrary (instance command) + (interactive + (let ((temp-buffer-show-function (function gud-temp-buffer-show))) + (list (gdb-needed-default-instance) + (concat "sharedlibrary " + (read-string "Load symbols for files matching regexp: "))))) + (gud-display-gud-buffer instance) + (apply comint-input-sender + (list (gdb-instance-process instance) command))) + + + + + +;;;; Window management + + +;;; FIXME: This should only return true for buffers in the current instance +(defun gud-protected-buffer-p (buffer) + "Is BUFFER a buffer which we want to leave displayed?" + (save-excursion + (set-buffer buffer) + (or gdb-buffer-type + overlay-arrow-position))) + +;;; The way we abuse the dedicated-p flag is pretty gross, but seems +;;; to do the right thing. Seeing as there is no way for Lisp code to +;;; get at the use_time field of a window, I'm not sure there exists a +;;; more elegant solution without writing C code. + +(defun gud-display-buffer (buf &optional size) + (let ((must-split nil) + (answer nil)) + (unwind-protect + (progn + (walk-windows + '(lambda (win) + (if (gud-protected-buffer-p (window-buffer win)) + (set-window-dedicated-p win t)))) + (setq answer (get-buffer-window buf)) + (if (not answer) + (let ((window (get-lru-window))) + (if window + (progn + (set-window-buffer window buf) + (setq answer window)) + (setq must-split t))))) + (walk-windows + '(lambda (win) + (if (gud-protected-buffer-p (window-buffer win)) + (set-window-dedicated-p win nil))))) + (if must-split + (let* ((largest (get-largest-window)) + (cur-size (window-height largest)) + (new-size (and size (< size cur-size) (- cur-size size)))) + (setq answer (split-window largest new-size)) + (set-window-buffer answer buf))) + answer)) + +(defun existing-source-window (buffer) + (catch 'found + (save-excursion + (walk-windows + (function + (lambda (win) + (if (and overlay-arrow-position + (eq (window-buffer win) + (marker-buffer overlay-arrow-position))) + (progn + (set-window-buffer win buffer) + (throw 'found win)))))) + nil))) + +(defun gud-display-source-buffer (buffer) + (or (existing-source-window buffer) + (gud-display-buffer buffer))) + +(defun gud-frame-buffer (buf) + (save-excursion + (set-buffer buf) + (make-frame))) + + + +;;; Shared keymap initialization: + +(defun make-windows-menu (map) + (define-key map [menu-bar displays] + (cons "GDB-Windows" (make-sparse-keymap "GDB-Windows"))) + (define-key map [menu-bar displays gdb] + '("Gdb" . gud-display-gud-buffer)) + (define-key map [menu-bar displays registers] + '("Registers" . gud-display-registers-buffer)) + (define-key map [menu-bar displays frames] + '("Stack" . gud-display-stack-buffer)) + (define-key map [menu-bar displays breakpoints] + '("Breakpoints" . gud-display-breakpoints-buffer)) + (define-key map [menu-bar displays commands] + '("Commands" . gud-display-command-buffer))) + +(defun gud-display-gud-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-display-buffer + (gdb-get-create-instance-buffer instance 'gud))) + +(make-windows-menu gud-breakpoints-mode-map) +(make-windows-menu gud-frames-mode-map) +(make-windows-menu gud-registers-mode-map) + + + +(defun make-frames-menu (map) + (define-key map [menu-bar frames] + (cons "GDB-Frames" (make-sparse-keymap "GDB-Frames"))) + (define-key map [menu-bar frames gdb] + '("Gdb" . gud-frame-gud-buffer)) + (define-key map [menu-bar frames registers] + '("Registers" . gud-frame-registers-buffer)) + (define-key map [menu-bar frames frames] + '("Stack" . gud-frame-stack-buffer)) + (define-key map [menu-bar frames breakpoints] + '("Breakpoints" . gud-frame-breakpoints-buffer)) + (define-key map [menu-bar displays commands] + '("Commands" . gud-display-command-buffer))) + +(defun gud-frame-gud-buffer (instance) + (interactive (list (gdb-needed-default-instance))) + (gud-frame-buffer + (gdb-get-create-instance-buffer instance 'gud))) + +(make-frames-menu gud-breakpoints-mode-map) +(make-frames-menu gud-frames-mode-map) +(make-frames-menu gud-registers-mode-map) + + +(defun gud-gdb-find-file (f) + (find-file-noselect f)) + +;;;###autoload +(defun gdb (command-line) + "Run gdb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run gdb (like this): " + (if (consp gud-gdb-history) + (car gud-gdb-history) + "gdb ") + nil nil + '(gud-gdb-history . 1)))) + (gud-overload-functions + '((gud-massage-args . gud-gdb-massage-args) + (gud-marker-filter . gud-gdb-marker-filter) + (gud-find-file . gud-gdb-find-file) + )) + + (let* ((words (gud-chop-words command-line)) + (program (car words)) + (file-word (let ((w (cdr words))) + (while (and w (= ?- (aref (car w) 0))) + (setq w (cdr w))) + (car w))) + (args (delq file-word (cdr words))) + (file (expand-file-name file-word)) + (filepart (file-name-nondirectory file)) + (buffer-name (concat "*gud-" filepart "*"))) + (setq gdb-first-time (not (get-buffer-process buffer-name)))) + + (gud-common-init command-line) + + (gud-def gud-break "break %f:%l" "\C-b" "Set breakpoint at current line.") + (gud-def gud-tbreak "tbreak %f:%l" "\C-t" "Set breakpoint at current line.") + (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-kill "kill" nil "Kill the program.") + (gud-def gud-run "run" nil "Run the program.") + (gud-def gud-stepi "stepi %p" "\C-i" "Step one instruction with display.") + (gud-def gud-step "step %p" "\C-s" "Step one source line with display.") + (gud-def gud-next "next %p" "\C-n" "Step one line (skip functions).") + (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") + (gud-def gud-cont "cont" "\C-r" "Continue with display.") + (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") + (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") + (gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.") + + (setq comint-prompt-regexp "^(.*gdb[+]?) *") + (setq comint-input-sender 'gdb-send) + (run-hooks 'gdb-mode-hook) + (let ((instance + (make-gdb-instance (get-buffer-process (current-buffer))) + )) + (if gdb-first-time (gdb-clear-inferior-io instance))) + ) + + +;; ====================================================================== +;; sdb functions + +;;; History of argument lists passed to sdb. +(defvar gud-sdb-history nil) + +(defvar gud-sdb-needs-tags (not (file-exists-p "/var")) + "If nil, we're on a System V Release 4 and don't need the tags hack.") + +(defvar gud-sdb-lastfile nil) + +(defun gud-sdb-massage-args (file args) + (cons file args)) + +(defun gud-sdb-marker-filter (string) + (cond + ;; System V Release 3.2 uses this format + ((string-match "\\(^0x\\w* in \\|^\\|\n\\)\\([^:\n]*\\):\\([0-9]*\\):.*\n" + string) + (setq gud-last-frame + (cons + (substring string (match-beginning 2) (match-end 2)) + (string-to-int + (substring string (match-beginning 3) (match-end 3)))))) + ;; System V Release 4.0 + ((string-match "^\\(BREAKPOINT\\|STEPPED\\) process [0-9]+ function [^ ]+ in \\(.+\\)\n" + string) + (setq gud-sdb-lastfile + (substring string (match-beginning 2) (match-end 2)))) + ((and gud-sdb-lastfile (string-match "^\\([0-9]+\\):" string)) + (setq gud-last-frame + (cons + gud-sdb-lastfile + (string-to-int + (substring string (match-beginning 1) (match-end 1)))))) + (t + (setq gud-sdb-lastfile nil))) + string) + +(defun gud-sdb-find-file (f) + (if gud-sdb-needs-tags + (find-tag-noselect f) + (find-file-noselect f))) + +;;;###autoload +(defun sdb (command-line) + "Run sdb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run sdb (like this): " + (if (consp gud-sdb-history) + (car gud-sdb-history) + "sdb ") + nil nil + '(gud-sdb-history . 1)))) + (if (and gud-sdb-needs-tags + (not (and (boundp 'tags-file-name) (file-exists-p tags-file-name)))) + (error "The sdb support requires a valid tags table to work.")) + (gud-overload-functions '((gud-massage-args . gud-sdb-massage-args) + (gud-marker-filter . gud-sdb-marker-filter) + (gud-find-file . gud-sdb-find-file) + )) + + (gud-common-init command-line) + + (gud-def gud-break "%l b" "\C-b" "Set breakpoint at current line.") + (gud-def gud-tbreak "%l c" "\C-t" "Set temporary breakpoint at current line.") + (gud-def gud-remove "%l d" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "s %p" "\C-s" "Step one source line with display.") + (gud-def gud-stepi "i %p" "\C-i" "Step one instruction with display.") + (gud-def gud-next "S %p" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "c" "\C-r" "Continue with display.") + (gud-def gud-print "%e/" "\C-p" "Evaluate C expression at point.") + + (setq comint-prompt-regexp "\\(^\\|\n\\)\\*") + (run-hooks 'sdb-mode-hook) + ) + +;; ====================================================================== +;; dbx functions + +;;; History of argument lists passed to dbx. +(defvar gud-dbx-history nil) + +(defun gud-dbx-massage-args (file args) + (cons file args)) + +(defun gud-dbx-marker-filter (string) + (if (or (string-match + "stopped in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" + string) + (string-match + "signal .* in .* at line \\([0-9]*\\) in file \"\\([^\"]*\\)\"" + string)) + (setq gud-last-frame + (cons + (substring string (match-beginning 2) (match-end 2)) + (string-to-int + (substring string (match-beginning 1) (match-end 1)))))) + string) + +(defun gud-dbx-find-file (f) + (find-file-noselect f)) + +;;;###autoload +(defun dbx (command-line) + "Run dbx on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run dbx (like this): " + (if (consp gud-dbx-history) + (car gud-dbx-history) + "dbx ") + nil nil + '(gud-dbx-history . 1)))) + (gud-overload-functions '((gud-massage-args . gud-dbx-massage-args) + (gud-marker-filter . gud-dbx-marker-filter) + (gud-find-file . gud-dbx-find-file) + )) + + (gud-common-init command-line) + + (gud-def gud-break "file \"%d%f\"\nstop at %l" + "\C-b" "Set breakpoint at current line.") +;; (gud-def gud-break "stop at \"%f\":%l" +;; "\C-b" "Set breakpoint at current line.") + (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "step %p" "\C-s" "Step one line with display.") + (gud-def gud-stepi "stepi %p" "\C-i" "Step one instruction with display.") + (gud-def gud-next "next %p" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "cont" "\C-r" "Continue with display.") + (gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.") + (gud-def gud-down "down %p" ">" "Down (numeric arg) stack frames.") + (gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.") + + (setq comint-prompt-regexp "^[^)]*dbx) *") + (run-hooks 'dbx-mode-hook) + ) + +;; ====================================================================== +;; xdb (HP PARISC debugger) functions + +;;; History of argument lists passed to xdb. +(defvar gud-xdb-history nil) + +(defvar gud-xdb-directories nil + "*A list of directories that xdb should search for source code. +If nil, only source files in the program directory +will be known to xdb. + +The file names should be absolute, or relative to the directory +containing the executable being debugged.") + +(defun gud-xdb-massage-args (file args) + (nconc (let ((directories gud-xdb-directories) + (result nil)) + (while directories + (setq result (cons (car directories) (cons "-d" result))) + (setq directories (cdr directories))) + (nreverse (cons file result))) + args)) + +(defun gud-xdb-file-name (f) + "Transform a relative pathname to a full pathname in xdb mode" + (let ((result nil)) + (if (file-exists-p f) + (setq result (expand-file-name f)) + (let ((directories gud-xdb-directories)) + (while directories + (let ((path (concat (car directories) "/" f))) + (if (file-exists-p path) + (setq result (expand-file-name path) + directories nil))) + (setq directories (cdr directories))))) + result)) + +;; xdb does not print the lines all at once, so we have to accumulate them +(defvar gud-xdb-accumulation "") + +(defun gud-xdb-marker-filter (string) + (let (result) + (if (or (string-match comint-prompt-regexp string) + (string-match ".*\012" string)) + (setq result (concat gud-xdb-accumulation string) + gud-xdb-accumulation "") + (setq gud-xdb-accumulation (concat gud-xdb-accumulation string))) + (if result + (if (or (string-match "\\([^\n \t:]+\\): [^:]+: \\([0-9]+\\):" result) + (string-match "[^: \t]+:[ \t]+\\([^:]+\\): [^:]+: \\([0-9]+\\):" + result)) + (let ((line (string-to-int + (substring result (match-beginning 2) (match-end 2)))) + (file (gud-xdb-file-name + (substring result (match-beginning 1) (match-end 1))))) + (if file + (setq gud-last-frame (cons file line)))))) + (or result ""))) + +(defun gud-xdb-find-file (f) + (let ((realf (gud-xdb-file-name f))) + (if realf (find-file-noselect realf)))) + +;;;###autoload +(defun xdb (command-line) + "Run xdb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger. + +You can set the variable 'gud-xdb-directories' to a list of program source +directories if your program contains sources from more than one directory." + (interactive + (list (read-from-minibuffer "Run xdb (like this): " + (if (consp gud-xdb-history) + (car gud-xdb-history) + "xdb ") + nil nil + '(gud-xdb-history . 1)))) + (gud-overload-functions '((gud-massage-args . gud-xdb-massage-args) + (gud-marker-filter . gud-xdb-marker-filter) + (gud-find-file . gud-xdb-find-file))) + + (gud-common-init command-line) + + (gud-def gud-break "b %f:%l" "\C-b" "Set breakpoint at current line.") + (gud-def gud-tbreak "b %f:%l\\t" "\C-t" + "Set temporary breakpoint at current line.") + (gud-def gud-remove "db" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "s %p" "\C-s" "Step one line with display.") + (gud-def gud-next "S %p" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "c" "\C-r" "Continue with display.") + (gud-def gud-up "up %p" "<" "Up (numeric arg) stack frames.") + (gud-def gud-down "down %p" ">" "Down (numeric arg) stack frames.") + (gud-def gud-finish "bu\\t" "\C-f" "Finish executing current function.") + (gud-def gud-print "p %e" "\C-p" "Evaluate C expression at point.") + + (setq comint-prompt-regexp "^>") + (make-local-variable 'gud-xdb-accumulation) + (setq gud-xdb-accumulation "") + (run-hooks 'xdb-mode-hook)) + +;; ====================================================================== +;; perldb functions + +;;; History of argument lists passed to perldb. +(defvar gud-perldb-history nil) + +(defun gud-perldb-massage-args (file args) + (cons "-d" (cons file (cons "-emacs" args)))) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defvar gud-perldb-marker-acc "") + +(defun gud-perldb-marker-filter (string) + (save-match-data + (setq gud-perldb-marker-acc (concat gud-perldb-marker-acc string)) + (let ((output "")) + + ;; Process all the complete markers in this chunk. + (while (string-match "^\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" + gud-perldb-marker-acc) + (setq + + ;; Extract the frame position from the marker. + gud-last-frame + (cons (substring gud-perldb-marker-acc (match-beginning 1) (match-end 1)) + (string-to-int (substring gud-perldb-marker-acc + (match-beginning 2) + (match-end 2)))) + + ;; Append any text before the marker to the output we're going + ;; to return - we don't include the marker in this text. + output (concat output + (substring gud-perldb-marker-acc 0 (match-beginning 0))) + + ;; Set the accumulator to the remaining text. + gud-perldb-marker-acc (substring gud-perldb-marker-acc (match-end 0)))) + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; gud-perldb-marker-acc until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + (if (string-match "^\032.*\\'" gud-perldb-marker-acc) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring gud-perldb-marker-acc + 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq gud-perldb-marker-acc + (substring gud-perldb-marker-acc (match-beginning 0)))) + + (setq output (concat output gud-perldb-marker-acc) + gud-perldb-marker-acc "")) + + output))) + +(defun gud-perldb-find-file (f) + (find-file-noselect f)) + +;;;###autoload +(defun perldb (command-line) + "Run perldb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run perldb (like this): " + (if (consp gud-perldb-history) + (car gud-perldb-history) + "perl ") + nil nil + '(gud-perldb-history . 1)))) + (gud-overload-functions '((gud-massage-args . gud-perldb-massage-args) + (gud-marker-filter . gud-perldb-marker-filter) + (gud-find-file . gud-perldb-find-file) + )) + + (gud-common-init command-line) + + (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") + (gud-def gud-remove "d %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "s" "\C-s" "Step one source line with display.") + (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "c" "\C-r" "Continue with display.") +; (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") +; (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") +; (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") + (gud-def gud-print "%e" "\C-p" "Evaluate perl expression at point.") + + (setq comint-prompt-regexp "^ DB<[0-9]+> ") + (run-hooks 'perldb-mode-hook) + ) + +;; +;; End of debugger-specific information +;; + + +;;; When we send a command to the debugger via gud-call, it's annoying +;;; to see the command and the new prompt inserted into the debugger's +;;; buffer; we have other ways of knowing the command has completed. +;;; +;;; If the buffer looks like this: +;;; -------------------- +;;; (gdb) set args foo bar +;;; (gdb) -!- +;;; -------------------- +;;; (the -!- marks the location of point), and we type `C-x SPC' in a +;;; source file to set a breakpoint, we want the buffer to end up like +;;; this: +;;; -------------------- +;;; (gdb) set args foo bar +;;; Breakpoint 1 at 0x92: file make-docfile.c, line 49. +;;; (gdb) -!- +;;; -------------------- +;;; Essentially, the old prompt is deleted, and the command's output +;;; and the new prompt take its place. +;;; +;;; Not echoing the command is easy enough; you send it directly using +;;; comint-input-sender, and it never enters the buffer. However, +;;; getting rid of the old prompt is trickier; you don't want to do it +;;; when you send the command, since that will result in an annoying +;;; flicker as the prompt is deleted, redisplay occurs while Emacs +;;; waits for a response from the debugger, and the new prompt is +;;; inserted. Instead, we'll wait until we actually get some output +;;; from the subprocess before we delete the prompt. If the command +;;; produced no output other than a new prompt, that prompt will most +;;; likely be in the first chunk of output received, so we will delete +;;; the prompt and then replace it with an identical one. If the +;;; command produces output, the prompt is moving anyway, so the +;;; flicker won't be annoying. +;;; +;;; So - when we want to delete the prompt upon receipt of the next +;;; chunk of debugger output, we position gud-delete-prompt-marker at +;;; the start of the prompt; the process filter will notice this, and +;;; delete all text between it and the process output marker. If +;;; gud-delete-prompt-marker points nowhere, we leave the current +;;; prompt alone. +(defvar gud-delete-prompt-marker nil) + + +(defvar gdbish-comint-mode-map (copy-keymap comint-mode-map)) +(define-key gdbish-comint-mode-map "\C-c\M-\C-r" 'gud-display-registers-buffer) +(define-key gdbish-comint-mode-map "\C-c\M-\C-f" 'gud-display-stack-buffer) +(define-key gdbish-comint-mode-map "\C-c\M-\C-b" 'gud-display-breakpoints-buffer) + +(make-windows-menu gdbish-comint-mode-map) +(make-frames-menu gdbish-comint-mode-map) + +(defun gud-mode () + "Major mode for interacting with an inferior debugger process. + + You start it up with one of the commands M-x gdb, M-x sdb, M-x dbx, +or M-x xdb. Each entry point finishes by executing a hook; `gdb-mode-hook', +`sdb-mode-hook', `dbx-mode-hook' or `xdb-mode-hook' respectively. + +After startup, the following commands are available in both the GUD +interaction buffer and any source buffer GUD visits due to a breakpoint stop +or step operation: + +\\[gud-break] sets a breakpoint at the current file and line. In the +GUD buffer, the current file and line are those of the last breakpoint or +step. In a source buffer, they are the buffer's file and current line. + +\\[gud-remove] removes breakpoints on the current file and line. + +\\[gud-refresh] displays in the source window the last line referred to +in the gud buffer. + +\\[gud-step], \\[gud-next], and \\[gud-stepi] do a step-one-line, +step-one-line (not entering function calls), and step-one-instruction +and then update the source window with the current file and position. +\\[gud-cont] continues execution. + +\\[gud-print] tries to find the largest C lvalue or function-call expression +around point, and sends it to the debugger for value display. + +The above commands are common to all supported debuggers except xdb which +does not support stepping instructions. + +Under gdb, sdb and xdb, \\[gud-tbreak] behaves exactly like \\[gud-break], +except that the breakpoint is temporary; that is, it is removed when +execution stops on it. + +Under gdb, dbx, and xdb, \\[gud-up] pops up through an enclosing stack +frame. \\[gud-down] drops back down through one. + +If you are using gdb or xdb, \\[gud-finish] runs execution to the return from +the current function and stops. + +All the keystrokes above are accessible in the GUD buffer +with the prefix C-c, and in all buffers through the prefix C-x C-a. + +All pre-defined functions for which the concept make sense repeat +themselves the appropriate number of times if you give a prefix +argument. + +You may use the `gud-def' macro in the initialization hook to define other +commands. + +Other commands for interacting with the debugger process are inherited from +comint mode, which see." + (interactive) + (comint-mode) + (setq major-mode 'gud-mode) + (setq mode-name "Debugger") + (setq mode-line-process '(": %s")) + (use-local-map (copy-keymap gdbish-comint-mode-map)) + (setq gud-last-frame nil) + (make-local-variable 'comint-prompt-regexp) + (make-local-variable 'gud-delete-prompt-marker) + (setq gud-delete-prompt-marker (make-marker)) + (run-hooks 'gud-mode-hook) +) + +(defvar gud-comint-buffer nil) + +;; Chop STRING into words separated by SPC or TAB and return a list of them. +(defun gud-chop-words (string) + (let ((i 0) (beg 0) + (len (length string)) + (words nil)) + (while (< i len) + (if (memq (aref string i) '(?\t ? )) + (progn + (setq words (cons (substring string beg i) words) + beg (1+ i)) + (while (and (< beg len) (memq (aref string beg) '(?\t ? ))) + (setq beg (1+ beg))) + (setq i (1+ beg))) + (setq i (1+ i)))) + (if (< beg len) + (setq words (cons (substring string beg) words))) + (nreverse words))) + +(defvar gud-target-name "--unknown--" + "The apparent name of the program being debugged in a gud buffer. +For sure this the root string used in smashing together the gud +buffer's name, even if that doesn't happen to be the name of a +program.") + +;; Perform initializations common to all debuggers. +(defun gud-common-init (command-line) + (let* ((words (gud-chop-words command-line)) + (program (car words)) + (file-word (let ((w (cdr words))) + (while (and w (= ?- (aref (car w) 0))) + (setq w (cdr w))) + (car w))) + (args (delq file-word (cdr words))) + (file (expand-file-name file-word)) + (filepart (file-name-nondirectory file)) + (buffer-name (concat "*gud-" filepart "*"))) + (switch-to-buffer buffer-name) + (setq default-directory (file-name-directory file)) + (or (bolp) (newline)) + (insert "Current directory is " default-directory "\n") + (let ((old-instance gdb-buffer-instance)) + (apply 'make-comint (concat "gud-" filepart) program nil + (gud-massage-args file args)) + (gud-mode) + (make-variable-buffer-local 'old-gdb-buffer-instance) + (setq old-gdb-buffer-instance old-instance)) + (make-variable-buffer-local 'gud-target-name) + (setq gud-target-name filepart)) + (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) + (set-process-sentinel (get-buffer-process (current-buffer)) 'gud-sentinel) + (gud-set-buffer) + ) + +(defun gud-set-buffer () + (cond ((eq major-mode 'gud-mode) + (setq gud-comint-buffer (current-buffer))))) + +;; These functions are responsible for inserting output from your debugger +;; into the buffer. The hard work is done by the method that is +;; the value of gud-marker-filter. + +(defun gud-filter (proc string) + ;; Here's where the actual buffer insertion is done + (let ((inhibit-quit t)) + (save-excursion + (set-buffer (process-buffer proc)) + (let (moving output-after-point) + (save-excursion + (goto-char (process-mark proc)) + ;; If we have been so requested, delete the debugger prompt. + (if (marker-buffer gud-delete-prompt-marker) + (progn + (delete-region (point) gud-delete-prompt-marker) + (set-marker gud-delete-prompt-marker nil))) + (insert-before-markers (gud-marker-filter string)) + (setq moving (= (point) (process-mark proc))) + (setq output-after-point (< (point) (process-mark proc))) + ;; Check for a filename-and-line number. + ;; Don't display the specified file + ;; unless (1) point is at or after the position where output appears + ;; and (2) this buffer is on the screen. + (if (and gud-last-frame + (not output-after-point) + (get-buffer-window (current-buffer))) + (gud-display-frame))) + (if moving (goto-char (process-mark proc))))))) + +(defun gud-proc-died (proc) + ;; Stop displaying an arrow in a source file. + (setq overlay-arrow-position nil) + + ;; Kill the dummy process, so that C-x C-c won't worry about it. + (save-excursion + (set-buffer (process-buffer proc)) + (kill-process + (get-buffer-process + (gdb-get-instance-buffer gdb-buffer-instance 'gdb-inferior-io)))) + ) + +(defun gud-sentinel (proc msg) + (cond ((null (buffer-name (process-buffer proc))) + ;; buffer killed + (gud-proc-died proc) + (set-process-buffer proc nil)) + ((memq (process-status proc) '(signal exit)) + (gud-proc-died proc) + + ;; Fix the mode line. + (setq mode-line-process + (concat ": " + (symbol-name (process-status proc)))) + (let* ((obuf (current-buffer))) + ;; save-excursion isn't the right thing if + ;; process-buffer is current-buffer + (unwind-protect + (progn + ;; Write something in *compilation* and hack its mode line, + (set-buffer (process-buffer proc)) + ;; Force mode line redisplay soon + (set-buffer-modified-p (buffer-modified-p)) + (if (eobp) + (insert ?\n mode-name " " msg) + (save-excursion + (goto-char (point-max)) + (insert ?\n mode-name " " msg))) + ;; If buffer and mode line will show that the process + ;; is dead, we can delete it now. Otherwise it + ;; will stay around until M-x list-processes. + (delete-process proc)) + ;; Restore old buffer, but don't restore old point + ;; if obuf is the gud buffer. + (set-buffer obuf)))))) + +(defun gud-display-frame () + "Find and obey the last filename-and-line marker from the debugger. +Obeying it means displaying in another window the specified file and line." + (interactive) + (if gud-last-frame + (progn +; (gud-set-buffer) + (gud-display-line (car gud-last-frame) (cdr gud-last-frame)) + (setq gud-last-last-frame gud-last-frame + gud-last-frame nil)))) + +;; Make sure the file named TRUE-FILE is in a buffer that appears on the screen +;; and that its line LINE is visible. +;; Put the overlay-arrow on the line LINE in that buffer. +;; Most of the trickiness in here comes from wanting to preserve the current +;; region-restriction if that's possible. We use an explicit display-buffer +;; to get around the fact that this is called inside a save-excursion. + +(defun gud-display-line (true-file line) + (let* ((buffer (gud-find-file true-file)) + (window (gud-display-source-buffer buffer)) + (pos)) + (if (not window) + (error "foo bar baz")) +;;; (if (equal buffer (current-buffer)) +;;; nil +;;; (setq buffer-read-only nil)) + (save-excursion +;;; (setq buffer-read-only t) + (set-buffer buffer) + (save-restriction + (widen) + (goto-line line) + (setq pos (point)) + (setq overlay-arrow-string "=>") + (or overlay-arrow-position + (setq overlay-arrow-position (make-marker))) + (set-marker overlay-arrow-position (point) (current-buffer))) + (cond ((or (< pos (point-min)) (> pos (point-max))) + (widen) + (goto-char pos)))) + (set-window-point window overlay-arrow-position))) + +;;; The gud-call function must do the right thing whether its invoking +;;; keystroke is from the GUD buffer itself (via major-mode binding) +;;; or a C buffer. In the former case, we want to supply data from +;;; gud-last-frame. Here's how we do it: + +(defun gud-format-command (str arg) + (let ((insource (not (eq (current-buffer) gud-comint-buffer)))) + (if (string-match "\\(.*\\)%f\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (file-name-nondirectory (if insource + (buffer-file-name) + (car gud-last-frame))) + (substring str (match-beginning 2) (match-end 2))))) + (if (string-match "\\(.*\\)%d\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (file-name-directory (if insource + (buffer-file-name) + (car gud-last-frame))) + (substring str (match-beginning 2) (match-end 2))))) + (if (string-match "\\(.*\\)%l\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (if insource + (save-excursion + (beginning-of-line) + (save-restriction (widen) + (1+ (count-lines 1 (point))))) + (cdr gud-last-frame)) + (substring str (match-beginning 2) (match-end 2))))) + (if (string-match "\\(.*\\)%e\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (find-c-expr) + (substring str (match-beginning 2) (match-end 2))))) + (if (string-match "\\(.*\\)%a\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (gud-read-address) + (substring str (match-beginning 2) (match-end 2))))) + (if (string-match "\\(.*\\)%p\\(.*\\)" str) + (setq str (concat + (substring str (match-beginning 1) (match-end 1)) + (if arg (int-to-string arg) "") + (substring str (match-beginning 2) (match-end 2))))) + ) + str + ) + +(defun gud-read-address () + "Return a string containing the core-address found in the buffer at point." + (save-excursion + (let ((pt (point)) found begin) + (setq found (if (search-backward "0x" (- pt 7) t) (point))) + (cond + (found (forward-char 2) + (buffer-substring found + (progn (re-search-forward "[^0-9a-f]") + (forward-char -1) + (point)))) + (t (setq begin (progn (re-search-backward "[^0-9]") + (forward-char 1) + (point))) + (forward-char 1) + (re-search-forward "[^0-9]") + (forward-char -1) + (buffer-substring begin (point))))))) + +(defun gud-call (fmt &optional arg) + (let ((msg (gud-format-command fmt arg))) + (message "Command: %s" msg) + (sit-for 0) + (gud-basic-call msg))) + +(defun gud-basic-call (command) + "Invoke the debugger COMMAND displaying source in other window." + (interactive) + (gud-set-buffer) + (let ((proc (get-buffer-process gud-comint-buffer))) + + ;; Arrange for the current prompt to get deleted. + (save-excursion + (set-buffer gud-comint-buffer) + (goto-char (process-mark proc)) + (beginning-of-line) + (if (looking-at comint-prompt-regexp) + (set-marker gud-delete-prompt-marker (point))) + (apply comint-input-sender (list proc command))))) + +(defun gud-refresh (&optional arg) + "Fix up a possibly garbled display, and redraw the arrow." + (interactive "P") + (recenter arg) + (or gud-last-frame (setq gud-last-frame gud-last-last-frame)) + (gud-display-frame)) + +;;; Code for parsing expressions out of C code. The single entry point is +;;; find-c-expr, which tries to return an lvalue expression from around point. +;;; +;;; The rest of this file is a hacked version of gdbsrc.el by +;;; Debby Ayers , +;;; Rich Schaefer Schlumberger, Austin, Tx. + +(defun find-c-expr () + "Returns the C expr that surrounds point." + (interactive) + (save-excursion + (let ((p) (expr) (test-expr)) + (setq p (point)) + (setq expr (expr-cur)) + (setq test-expr (expr-prev)) + (while (expr-compound test-expr expr) + (setq expr (cons (car test-expr) (cdr expr))) + (goto-char (car expr)) + (setq test-expr (expr-prev))) + (goto-char p) + (setq test-expr (expr-next)) + (while (expr-compound expr test-expr) + (setq expr (cons (car expr) (cdr test-expr))) + (setq test-expr (expr-next)) + ) + (buffer-substring (car expr) (cdr expr))))) + +(defun expr-cur () + "Returns the expr that point is in; point is set to beginning of expr. +The expr is represented as a cons cell, where the car specifies the point in +the current buffer that marks the beginning of the expr and the cdr specifies +the character after the end of the expr." + (let ((p (point)) (begin) (end)) + (expr-backward-sexp) + (setq begin (point)) + (expr-forward-sexp) + (setq end (point)) + (if (>= p end) + (progn + (setq begin p) + (goto-char p) + (expr-forward-sexp) + (setq end (point)) + ) + ) + (goto-char begin) + (cons begin end))) + +(defun expr-backward-sexp () + "Version of `backward-sexp' that catches errors." + (condition-case nil + (backward-sexp) + (error t))) + +(defun expr-forward-sexp () + "Version of `forward-sexp' that catches errors." + (condition-case nil + (forward-sexp) + (error t))) + +(defun expr-prev () + "Returns the previous expr, point is set to beginning of that expr. +The expr is represented as a cons cell, where the car specifies the point in +the current buffer that marks the beginning of the expr and the cdr specifies +the character after the end of the expr" + (let ((begin) (end)) + (expr-backward-sexp) + (setq begin (point)) + (expr-forward-sexp) + (setq end (point)) + (goto-char begin) + (cons begin end))) + +(defun expr-next () + "Returns the following expr, point is set to beginning of that expr. +The expr is represented as a cons cell, where the car specifies the point in +the current buffer that marks the beginning of the expr and the cdr specifies +the character after the end of the expr." + (let ((begin) (end)) + (expr-forward-sexp) + (expr-forward-sexp) + (setq end (point)) + (expr-backward-sexp) + (setq begin (point)) + (cons begin end))) + +(defun expr-compound-sep (span-start span-end) + "Returns '.' for '->' & '.', returns ' ' for white space, +returns '?' for other punctuation." + (let ((result ? ) + (syntax)) + (while (< span-start span-end) + (setq syntax (char-syntax (char-after span-start))) + (cond + ((= syntax ? ) t) + ((= syntax ?.) (setq syntax (char-after span-start)) + (cond + ((= syntax ?.) (setq result ?.)) + ((and (= syntax ?-) (= (char-after (+ span-start 1)) ?>)) + (setq result ?.) + (setq span-start (+ span-start 1))) + (t (setq span-start span-end) + (setq result ??))))) + (setq span-start (+ span-start 1))) + result)) + +(defun expr-compound (first second) + "Non-nil if concatenating FIRST and SECOND makes a single C token. +The two exprs are represented as a cons cells, where the car +specifies the point in the current buffer that marks the beginning of the +expr and the cdr specifies the character after the end of the expr. +Link exprs of the form: + Expr -> Expr + Expr . Expr + Expr (Expr) + Expr [Expr] + (Expr) Expr + [Expr] Expr" + (let ((span-start (cdr first)) + (span-end (car second)) + (syntax)) + (setq syntax (expr-compound-sep span-start span-end)) + (cond + ((= (car first) (car second)) nil) + ((= (cdr first) (cdr second)) nil) + ((= syntax ?.) t) + ((= syntax ? ) + (setq span-start (char-after (- span-start 1))) + (setq span-end (char-after span-end)) + (cond + ((= span-start ?) ) t ) + ((= span-start ?] ) t ) + ((= span-end ?( ) t ) + ((= span-end ?[ ) t ) + (t nil)) + ) + (t nil)))) + +(provide 'gud) + +;;; gud.el ends here diff --git a/contrib/gdb/gdb/gdbcmd.h b/contrib/gdb/gdb/gdbcmd.h new file mode 100644 index 000000000000..2459f8144cd8 --- /dev/null +++ b/contrib/gdb/gdb/gdbcmd.h @@ -0,0 +1,106 @@ +/* Header file for GDB-specific command-line stuff. + Copyright 1986, 1989, 1990, 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (GDBCMD_H) +#define GDBCMD_H 1 + +#include "command.h" + +/* Chain containing all defined commands. */ + +extern struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +extern struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +extern struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +extern struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +extern struct cmd_list_element *deletelist; + +/* 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; + +/* Chain containing all defined unset subcommands */ + +extern struct cmd_list_element *unsetlist; + +/* Chain containing all defined show subcommands. */ + +extern struct cmd_list_element *showlist; + +/* Chain containing all defined \"set history\". */ + +extern struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ + +extern struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +extern struct cmd_list_element *unsethistlist; + +/* Chain containing all defined maintenance subcommands. */ + +extern struct cmd_list_element *maintenancelist; + +/* Chain containing all defined "maintenance info" subcommands. */ + +extern struct cmd_list_element *maintenanceinfolist; + +/* Chain containing all defined "maintenance print" subcommands. */ + +extern struct cmd_list_element *maintenanceprintlist; + +extern struct cmd_list_element *setprintlist; + +extern struct cmd_list_element *showprintlist; + +extern struct cmd_list_element *setchecklist; + +extern struct cmd_list_element *showchecklist; + +extern void +execute_user_command PARAMS ((struct cmd_list_element *, char *)); + +extern void +execute_command PARAMS ((char *, int)); + +enum command_control_type +execute_control_command PARAMS ((struct command_line *)); + +void print_command_line PARAMS ((struct command_line *, unsigned int)); + +extern char **noop_completer PARAMS ((char *, char *)); + +extern char **filename_completer PARAMS ((char *, char *)); + +#endif /* !defined (GDBCMD_H) */ diff --git a/contrib/gdb/gdb/gdbcore.h b/contrib/gdb/gdb/gdbcore.h new file mode 100644 index 000000000000..bf7cb3217dba --- /dev/null +++ b/contrib/gdb/gdb/gdbcore.h @@ -0,0 +1,155 @@ +/* Machine independent variables that describe the core file under GDB. + Copyright 1986, 1987, 1989, 1990, 1992, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Interface routines for core, executable, etc. */ + +#if !defined (GDBCORE_H) +#define GDBCORE_H 1 + +#include "bfd.h" + +/* Return the name of the executable file as a string. + ERR nonzero means get error if there is none specified; + otherwise return 0 in that case. */ + +extern char *get_exec_file PARAMS ((int err)); + +/* Nonzero if there is a core file. */ + +extern int have_core_file_p PARAMS ((void)); + +/* Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used for + address out of bounds. If breakpoints are inserted, returns shadow + contents, not the breakpoints themselves. From breakpoint.c. */ + +extern int read_memory_nobpt PARAMS ((CORE_ADDR memaddr, char *myaddr, + unsigned len)); + +/* Report a memory error with error(). */ + +extern void memory_error PARAMS ((int status, CORE_ADDR memaddr)); + +/* Like target_read_memory, but report an error if can't read. */ + +extern void read_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +/* Read an integer from debugged memory, given address and number of + bytes. */ + +extern LONGEST read_memory_integer PARAMS ((CORE_ADDR memaddr, int len)); + +/* Read an unsigned integer from debugged memory, given address and + number of bytes. */ + +extern unsigned LONGEST read_memory_unsigned_integer PARAMS ((CORE_ADDR memaddr, int len)); + +/* This takes a char *, not void *. This is probably right, because + passing in an int * or whatever is wrong with respect to + byteswapping, alignment, different sizes for host vs. target types, + etc. */ + +extern void write_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +extern void generic_search PARAMS ((int len, char *data, char *mask, + CORE_ADDR startaddr, int increment, + CORE_ADDR lorange, CORE_ADDR hirange, + CORE_ADDR *addr_found, char *data_found)); + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) PARAMS ((char *filename)); + +extern void specify_exec_file_hook PARAMS ((void (*hook) (char *filename))); + +/* Binary File Diddlers for the exec and core files */ + +extern bfd *core_bfd; +extern bfd *exec_bfd; + +/* Whether to open exec and core files read-only or read-write. */ + +extern int write_files; + +extern void core_file_command PARAMS ((char *filename, int from_tty)); + +extern void exec_file_command PARAMS ((char *filename, int from_tty)); + +extern void validate_files PARAMS ((void)); + +extern unsigned int register_addr PARAMS ((int regno, int blockend)); + +extern void registers_fetched PARAMS ((void)); + +#if !defined (KERNEL_U_ADDR) +extern CORE_ADDR kernel_u_addr; +#define KERNEL_U_ADDR kernel_u_addr +#endif + +/* The target vector for core files. */ + +extern struct target_ops core_ops; + +/* The current default bfd target. */ + +extern char *gnutarget; + +extern void set_gnutarget PARAMS ((char *)); + +/* Structure to keep track of core register reading functions for + various core file types. */ + +struct core_fns { + + /* BFD flavour that we handle. Note that bfd_target_unknown_flavour matches + anything, and if there is no better match, this function will be called + as the default. */ + + enum bfd_flavour core_flavour; + + /* Extract the register values out of the core file and store them where + `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into + memory. + + CORE_REG_SIZE is the size of that area. + + WHICH says which set of registers we are handling (0 = int, 2 = float on + machines where they are discontiguous). + + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to locate the + registers in a large upage-plus-stack ".reg" section. Original upage + address X is at location core_reg_sect+x+reg_addr. */ + + void (*core_read_registers) PARAMS ((char *core_reg_sect, unsigned core_reg_size, + int which, unsigned reg_addr)); + + /* Finds the next struct core_fns. They are allocated and initialized + in whatever module implements the functions pointed to; an + initializer calls add_core_fns to add them to the global chain. */ + + struct core_fns *next; + +}; + +extern void add_core_fns PARAMS ((struct core_fns *cf)); + +#endif /* !defined (GDBCORE_H) */ diff --git a/contrib/gdb/gdb/gdbserver/Makefile.in b/contrib/gdb/gdb/gdbserver/Makefile.in new file mode 100644 index 000000000000..2ce6fac9329d --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/Makefile.in @@ -0,0 +1,245 @@ +#Copyright 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +prefix = /usr/local + +program_transform_name = +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(libdir)/$(target_alias) + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = `cd $(srcdir)/../..;pwd`/install.sh -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' +INSTALL_XFORM1 = $(INSTALL_XFORM) -b=.1 + +AR = ar +AR_FLAGS = qv +RANLIB = ranlib + +# If you are compiling with GCC, make sure that either 1) You use the +# -traditional flag, or 2) You have the fixed include files where GCC +# can reach them. Otherwise the ioctl calls in inflow.c +# will be incorrectly compiled. The "fixincludes" script in the gcc +# distribution will fix your include files up. +#CC=cc +#CC=gcc -traditional +GCC=gcc + +# Directory containing source files. Don't clean up the spacing, +# this exact string is matched for by the "configure" script. +srcdir = . + +# It is also possible that you will need to add -I/usr/include/sys to the +# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which +# is where it should be according to Posix). + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +#CC-LD=gcc -static +CC-LD=${CC} + +# Where is the "include" directory? Traditionally ../include or ./include +INCLUDE_DIR = ${srcdir}/../../include +INCLUDE_DEP = $$(INCLUDE_DIR) + +# Where is the source dir for the MMALLOC library? Traditionally ../mmalloc +# or ./mmalloc (When we want the binary library built from it, we use +# ${MMALLOC_DIR}${subdir}.) +# Note that mmalloc can still be used on systems without mmap(). +# To use your system malloc, comment out the following defines. +MMALLOC_DIR = ${srcdir}/../../mmalloc +MMALLOC_DEP = $$(MMALLOC_DIR) +# To use your system malloc, uncomment MMALLOC_DISABLE. +#MMALLOC_DISABLE = -DNO_MMALLOC +# To use mmalloc but disable corruption checking, uncomment MMALLOC_CHECK +#MMALLOC_CHECK = -DNO_MMALLOC_CHECK +MMALLOC_CFLAGS = ${MMALLOC_CHECK} ${MMALLOC_DISABLE} -I${MMALLOC_DIR} + +# Where are the BFD library? +BFD_DIR = ../../bfd +BFD = $(BFD_DIR)/libbfd.a +BFD_SRC = $(srcdir)/$(BFD_DIR) +BFD_CFLAGS = -I$(BFD_DIR) -I$(BFD_SRC) + +# Where is the source dir for the READLINE library? Traditionally in .. or . +# (For the binary library built from it, we use ${READLINE_DIR}${subdir}.) +READLINE_DIR = ${srcdir}/../readline +READLINE_DEP = $$(READLINE_DIR) + +# All the includes used for CFLAGS and for lint. +# -I. for config files. +# -I${srcdir} possibly for regex.h also. +# -I${srcdir}/config for more generic config files. +INCLUDE_CFLAGS = -I. -I${srcdir} -I${srcdir}/.. -I${srcdir}/../config -I$(INCLUDE_DIR) + +# M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS +# from the config/ directory. +GLOBAL_CFLAGS = ${MT_CFLAGS} ${MH_CFLAGS} +#PROFILE_CFLAGS = -pg + +# CFLAGS is specifically reserved for setting from the command line +# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". +CFLAGS = -g +# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. +INTERNAL_CFLAGS = ${CFLAGS} ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} \ + ${BFD_CFLAGS} ${MMALLOC_CFLAGS} ${INCLUDE_CFLAGS} + +# LDFLAGS is specifically reserved for setting from the command line +# when running make. + +# Perhaps should come from parent Makefile +VERSION = gdbserver-4.12.3 +DIST=gdb + +LINT=/usr/5bin/lint +LINTFLAGS= $(BFD_CFLAGS) + +# Host and target-dependent makefile fragments come in here. +#### +# End of host and target-dependent makefile fragments + +# All source files that go into linking GDB remote server. + +SFILES = $(srcdir)/low-lynx.c $(srcdir)/low-sparc.c $(srcdir)/low-sun3.c \ + $(srcdir)/low-hppabsd.c \ + $(srcdir)/utils.c $(srcdir)/server.c $(srcdir)/remote-utils.c + +DEPFILES = $(GDBSERVER_DEPFILES) + +SOURCES = $(SFILES) $(ALLDEPFILES) +TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} + +OBS = utils.o $(GDBSERVER_DEPFILES) server.o remote-utils.o + +# Prevent Sun make from putting in the machine type. Setting +# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. +.c.o: + ${CC} -c ${INTERNAL_CFLAGS} $< + +all: gdbserver gdbreplay + +# Traditionally "install" depends on "all". But it may be useful +# not to; for example, if the user has made some trivial change to a +# source file and doesn't care about rebuilding or just wants to save the +# time it takes for make to check that all is up to date. +# install-only is intended to address that need. +install: all install-only +install-only: + $(INSTALL_XFORM) gdbserver $(bindir)/gdbserver + $(INSTALL_XFORM1) $(srcdir)/gdbserver.1 $(man1dir)/gdbserver.1 + +uninstall: force + rm -f $(bindir)/gdbserver $(man1dir)/gdbserver.1 + +installcheck: +check: +info dvi: +install-info: +clean-info: + +gdbserver: $(OBS) ${ADD_DEPS} ${CDEPS} + rm -f gdbserver + ${CC-LD} $(GLOBAL_CFLAGS) $(LDFLAGS) -o gdbserver $(OBS) \ + $(GDBSERVER_LIBS) + +config.status: + @echo "You must configure gdbserver. Look at the README file for details." + @false + +# Put the proper machine-specific files first, so M-. on a machine +# specific routine gets the one for the correct machine. +# The xyzzy stuff below deals with empty DEPFILES +TAGS: ${TAGFILES} + etags `find ${srcdir}/../config -name $(TM_FILE) -print` \ + `find ${srcdir}/../config -name ${XM_FILE} -print` \ + `find ${srcdir}/../config -name ${NAT_FILE} -print` \ + `for i in yzzy ${DEPFILES}; do \ + if [ x$$i != xyzzy ]; then \ + echo ${srcdir}/$$i | sed -e 's/\.o$$/\.c/' ; \ + fi; \ + done` \ + ${TAGFILES} +tags: TAGS + +clean: + rm -f *.o ${ADD_FILES} *~ + rm -f gdbserver core make.log + +distclean: clean + rm -f nm.h tm.h xm.h config.status + rm -f Makefile + +maintainer-clean realclean: clean + rm -f nm.h tm.h xm.h config.status + rm -f Makefile + +STAGESTUFF=${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} init.c init.o version.c gdb + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + +force: + +version.c: Makefile + echo 'char *version = "$(VERSION)";' >version.c + +# GNU Make has an annoying habit of putting *all* the Makefile variables +# into the environment, unless you include this target as a circumvention. +# Rumor is that this will be fixed (and this target can be removed) +# in GNU Make 4.0. +.NOEXPORT: + +# GNU Make 3.63 has a different problem: it keeps tacking command line +# overrides onto the definition of $(MAKE). This variable setting +# will remove them. +MAKEOVERRIDES= + +## This is ugly, but I don't want GNU make to put these variables in +## the environment. Older makes will see this as a set of targets +## with no dependencies and no actions. +unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET : + +server.o : ${srcdir}/server.c ${srcdir}/server.h +remote-utils.o : ${srcdir}/remote-utils.c ${srcdir}/server.h +low-lynx.o : ${srcdir}/low-lynx.c ${srcdir}/server.h +low-sparc.o : $(srcdir)/low-sparc.c $(srcdir)/server.h +low-sun3.o : $(srcdir)/low-sun3.c $(srcdir)/server.h +low-hppabsd.o : $(srcdir)/low-hppabsd.c $(srcdir)/server.h +utils.o : ${srcdir}/utils.c ${srcdir}/server.h + +# This is the end of "Makefile.in". diff --git a/contrib/gdb/gdb/gdbserver/README b/contrib/gdb/gdb/gdbserver/README new file mode 100644 index 000000000000..2281bf686c1d --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/README @@ -0,0 +1,127 @@ + README for GDBserver & GDBreplay + by Stu Grossman and Fred Fish + +Introduction: + +This is GDBserver, a remote server for Un*x-like systems. It can be used to +control the execution of a program on a target system from a GDB on a different +host. GDB and GDBserver communicate using the standard remote serial protocol +implemented in remote.c, and various *-stub.c files. They communicate via +either a serial line or a TCP connection. + +Usage (server (target) side): + +First, you need to have a copy of the program you want to debug put onto +the target system. The program can be stripped to save space if needed, as +GDBserver doesn't care about symbols. All symbol handling is taken care of by +the GDB running on the host system. + +To use the server, you log on to the target system, and run the `gdbserver' +program. You must tell it (a) how to communicate with GDB, (b) the name of +your program, and (c) its arguments. The general syntax is: + + target> gdbserver COMM PROGRAM [ARGS ...] + +For example, using a serial port, you might say: + + target> gdbserver /dev/com1 emacs foo.txt + +This tells gdbserver to debug emacs with an argument of foo.txt, and to +communicate with GDB via /dev/com1. Gdbserver now waits patiently for the +host GDB to communicate with it. + +To use a TCP connection, you could say: + + target> gdbserver host:2345 emacs foo.txt + +This says pretty much the same thing as the last example, except that we are +going to communicate with the host GDB via TCP. The `host:2345' argument means +that we are expecting to see a TCP connection from `host' to local TCP port +2345. (Currently, the `host' part is ignored.) You can choose any number you +want for the port number as long as it does not conflict with any existing TCP +ports on the target system. This same port number must be used in the host +GDBs `target remote' command, which will be described shortly. Note that if +you chose a port number that conflicts with another service, gdbserver will +print an error message and exit. + +Usage (host side): + +You need an unstripped copy of the target program on your host system, since +GDB needs to examine it's symbol tables and such. Start up GDB as you normally +would, with the target program as the first argument. (You may need to use the +--baud option if the serial line is running at anything except 9600 baud.) +Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only +new command you need to know about is `target remote'. It's argument is either +a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT +descriptor. For example: + + (gdb) target remote /dev/ttyb + +communicates with the server via serial line /dev/ttyb, and: + + (gdb) target remote the-target:2345 + +communicates via a TCP connection to port 2345 on host `the-target', where +you previously started up gdbserver with the same port number. Note that for +TCP connections, you must start up gdbserver prior to using the `target remote' +command, otherwise you may get an error that looks something like +`Connection refused'. + +Building: + +Configuring gdbserver you should specify the same machine for host and +target (which are the machine that gdbserver is going to run on. This +is not the same as the machine that gdb is going to run on; building +gdbserver automatically as part of building a whole tree of tools does +not currently work if cross-compilation is involved (we don't get the +right CC in the Makefile, to start with)). + +gdbserver should work on sparc-sun-sunos4* or Lynx. The following +instructions pertain to Lynx. To build the server for Lynx, make a +new copy of the distribution onto a disk that is NFS shared with the +Lynx system. Lets say that's in a directory called xyzzy. Then, +follow these steps under the host system: + + 1) cd xyzzy/gdb/gdbserver + 2) ../../configure i386-none-lynx + +When that completes, do the following on the Lynx system: + + 3) cd xyzzy/gdb/gdbserver + 4) make CC=gcc + +It should build with only a minor complaint about NULL being redefined. That's +a LynxOS problem, and can be ignored. + +It's also possible that you may have a cross-compiler to Lynx. In that case, +you can skip the stuff about NFS. You would replace steps 3 & 4 with: + + make CC=lynx-target-compiler... + +Using GDBreplay: + +A special hacked down version of gdbserver can be used to replay remote +debug log files created by gdb. Before using the gdb "target" command to +initiate a remote debug session, use "set remotelogfile " to tell +gdb that you want to make a recording of the serial or tcp session. Note +that when replaying the session, gdb communicates with gdbreplay via tcp, +regardless of whether the original session was via a serial link or tcp. + +Once you are done with the remote debug session, start gdbreplay and +tell it the name of the log file and the host and port number that gdb +should connect to (typically the same as the host running gdb): + + $ gdbreplay logfile host:port + +Then start gdb (preferably in a different screen or window) and use the +"target" command to connect to gdbreplay: + + (gdb) target remote host:port + +Repeat the same sequence of user commands to gdb that you gave in the +original debug session. Gdb should not be able to tell that it is talking +to gdbreplay rather than a real target, all other things being equal. Note +that gdbreplay echos the command lines to stderr, as well as the contents of +the packets it sends and receives. The last command echoed by gdbreplay is +the next command that needs to be typed to gdb to continue the session in +sync with the original session. diff --git a/contrib/gdb/gdb/gdbserver/configure.in b/contrib/gdb/gdb/gdbserver/configure.in new file mode 100644 index 000000000000..67215bd0cf4f --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/configure.in @@ -0,0 +1,335 @@ +srcname="Remote GDB server" +srctrigger=server.c +gdb_serial_driver=../ser-unix.c + +# per-host: + +# per-target: + +# Hack alert! We want this directory to be configured only for the target, +# which is where it will be running, so we just eliminate the per-host section, +# and make the per-target stuff setup host & host_cpu according to the target. + +host_cpu=$target_cpu +host=$target + +# Map host cpu into the config cpu subdirectory name. +# The default is $host_cpu. + +case "${host_cpu}" in + +c[12]) gdb_host_cpu=convex ;; +hppa*) gdb_host_cpu=pa ;; +i[345]86) gdb_host_cpu=i386 ;; +m68*) gdb_host_cpu=m68k ;; +np1) gdb_host_cpu=gould ;; +pyramid) gdb_host_cpu=pyr ;; +*) gdb_host_cpu=$target_cpu ;; + +esac + +# map host info into gdb names. + +case "${host}" in + +a29k-*-*) gdb_host=ultra3 ;; + +arm-*-*) gdb_host=arm ;; + +c[12]-*-*) gdb_host=convex ;; + +hppa*-hp-bsd*) gdb_host=hppabsd ;; +hppa*-hp-hpux*) gdb_host=hppahpux ;; + +i[345]86-ncr-*) gdb_host=ncr3000 ;; +i[345]86-sequent-*) gdb_host=symmetry ;; + +i[345]86-*-bsd*) gdb_host=i386bsd ;; +i[345]86-*-lynxos*) gdb_host=i386lynx ;; +i[345]86-*-go32) gdb_host=go32 + gdb_serial_driver=ser-go32.c + ;; +i[345]86-*-linux*) gdb_host=linux ;; +i[345]86-*-mach) gdb_host=i386mach ;; +i[345]86-*-sco3.2v4*) gdb_host=i386sco4 ;; +i[345]86-*-sco*) gdb_host=i386sco ;; +i[345]86-*-solaris*) gdb_host=i386sol2 ;; +i[345]86-*-sunos*) gdb_host=sun386 ;; +i[345]86-*-sysv3.2) gdb_host=i386v32 ;; +i[345]86-*-sysv4*) gdb_host=i386v4 ;; +i[345]86-*-sysv*) gdb_host=i386v ;; + +m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; +m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; +m68030-sony-*) gdb_host=news1000 ;; + +m68*-altos-*) gdb_host=altos ;; +m68*-apollo*-sysv*) gdb_host=apollo68v ;; +m68*-apollo*-bsd*) gdb_host=apollo68b ;; +m68*-att-*) gdb_host=3b1 ;; +m68*-cbm-sysv4*) gdb_host=amix ;; +m68*-hp-bsd*) gdb_host=hp300bsd ;; +m68*-hp-hpux*) gdb_host=hp300hpux ;; +m68*-isi-*) gdb_host=isi ;; +m68*-*-lynxos*) gdb_host=m68klynx ;; +m68*-sony-*) gdb_host=news ;; +m68*-sun-sunos3*) gdb_host=sun3os3 ;; +m68*-sun-sunos4*) gdb_host=sun3os4 ;; +m68*-sun-*) gdb_host=sun3os4 ;; + +m88k-motorola-*) gdb_host=delta88 ;; +m88k-*-*) gdb_host=m88k ;; + +mips-dec-*) gdb_host=decstation ;; +mips-little-*) gdb_host=littlemips ;; +mips-sgi-irix3) gdb_host=irix3 ;; +mips-sgi-irix4*) gdb_host=irix4 ;; +mips-sony-*) gdb_host=bigmips ;; + +none-*-*) gdb_host=none ;; + +np1-*-*) gdb_host=np1 ;; + +ns32k-umax-*) gdb_host=umax ;; +ns32k-utek-sysv) gdb_host=merlin ;; + +pn-*-*) gdb_host=pn ;; + +pyramid-*-*) gdb_host=pyramid ;; + +romp-*-*) gdb_host=rtbsd ;; + +rs6000-*-*) gdb_host=rs6000 ;; + +sparc-*-lynxos*) gdb_host=sparclynx ;; +sparc-*-solaris2*) gdb_host=sun4sol2 ;; +sparc-*-sunos4*) gdb_host=sun4os4 ;; +sparc-*-*) gdb_host=sun4os4 ;; + +tahoe-*-*) gdb_host=tahoe ;; + +vax-*-bsd*) gdb_host=vaxbsd ;; +vax-*-ultrix2*) gdb_host=vaxult2 ;; +vax-*-ultrix*) gdb_host=vaxult ;; + +esac + +if [ ! -f ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ]; then + echo '***' "GDB remote does not support host ${host}" 1>&2 + exit 1 +fi + +# We really shouldn't depend on there being a space after XM_FILE= ... +hostfile=`awk '$1 == "XM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` + +# per-target: + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. + +case "${target_cpu}" in + +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[345]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +np1) gdb_target_cpu=gould ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; + +esac + +# map target info into gdb names. + +case "${target}" in + +a29k-*-aout) gdb_target=a29k ;; +a29k-*-coff) gdb_target=a29k ;; +a29k-*-elf) gdb_target=a29k ;; +a29k-*-ebmon) gdb_target=a29k ;; +a29k-*-kern) gdb_target=a29k-kern ;; +a29k-*-none) gdb_target=a29k ;; +a29k-*-sym1) gdb_target=ultra3 ;; +a29k-*-udi) gdb_target=a29k-udi ;; + +arm-*-*) gdb_target=arm ;; + +c1-*-*) gdb_target=convex ;; +c2-*-*) gdb_target=convex ;; + +h8300-*-*) gdb_target=h8300hms ;; +h8500-*-*) gdb_target=h8500hms ;; + +sh-*-*) gdb_target=sh ;; + +hppa*-*-bsd*) gdb_target=hppabsd ;; +hppa*-*-hpux*) gdb_target=hppahpux ;; + +i[345]86-sequent-*) gdb_target=symmetry ;; +i[345]86-ncr-*) gdb_target=ncr3000 ;; + +i[345]86-*-aout) gdb_target=i386aout ;; +i[345]86-*-coff) gdb_target=i386v ;; +i[345]86-*-elf) gdb_target=i386v ;; + +i[345]86-*-bsd*) gdb_target=i386bsd ;; +i[345]86-*-lynxos*) gdb_target=i386lynx ;; +i[345]86-*-go32) gdb_target=i386aout ;; +i[345]86-*-solaris*) gdb_target=i386sol2 ;; +i[345]86-*-sunos*) gdb_target=sun386 ;; +i[345]86-*-sysv4*) gdb_target=i386v4 ;; +i[345]86-*-sco*) gdb_target=i386v ;; +i[345]86-*-sysv*) gdb_target=i386v ;; +i[345]86-*-linux*) gdb_target=linux ;; + +i960-*-bout) gdb_target=vxworks960 ;; +i960-*-coff) gdb_target=nindy960 ;; +i960-*-elf) gdb_target=nindy960 ;; + +i960-*-nindy) gdb_target=nindy960 ;; +i960-*-vxworks) gdb_target=vxworks960 ;; + +m68000-*-aout) gdb_target=m68k-nofp ;; +m68000-*-coff) gdb_target=m68k-nofp ;; +m68000-*-elf) gdb_target=m68k-nofp ;; +m68000-*-sunos3*) gdb_target=sun2os3 ;; +m68000-*-sunos4*) gdb_target=sun2os4 ;; + +m68*-cbm-sysv4*) gdb_target=amix ;; +m68*-hp-bsd*) gdb_target=hp300bsd ;; +m68*-hp-hpux*) gdb_target=hp300hpux ;; + +m68*-altos-*) gdb_target=altos ;; +m68*-att-*) gdb_target=3b1 ;; +m68*-ericsson-*) gdb_target=es1800 ;; +m68*-isi-*) gdb_target=isi ;; +m68*-netx-*) gdb_target=vxworks68 ;; +m68*-sony-*) gdb_target=news ;; +m68*-tandem-*) gdb_target=st2000 ;; + +m68*-*-aout) gdb_target=m68k-fp ;; +m68*-*-coff) gdb_target=m68k-fp ;; +m68*-*-elf) gdb_target=m68k-fp ;; +m68*-*-lynxos*) gdb_target=m68klynx ;; +m68*-*-os68k) gdb_target=os68k ;; +m68*-*-sunos3*) gdb_target=sun3os3 ;; +m68*-*-sunos4*) gdb_target=sun3os4 ;; +m68*-*-vxworks*) gdb_target=vxworks68 ;; + +m88k-motorola-*) gdb_target=delta88 ;; +m88k-*-*) gdb_target=m88k ;; + +mips-big-*) gdb_target=bigmips ;; +mips-dec-*) gdb_target=decstation ;; +mips-idt-ecoff) gdb_target=idt ;; +mips-little-*) gdb_target=littlemips ;; +mips-sgi-*) gdb_target=irix3 ;; +mips-sony-*) gdb_target=bigmips ;; + +none-*-*) gdb_target=none ;; + +np1-*-*) gdb_target=np1 ;; + +ns32k-utek-sysv) gdb_target=merlin ;; +ns32k-utek-*) gdb_target=umax ;; + +pn-*-*) gdb_target=pn ;; + +pyramid-*-*) gdb_target=pyramid ;; + +rs6000-*-*) gdb_target=rs6000 ;; + +sparc-*-aout) gdb_target=sparc-em ;; +sparc-*-coff) gdb_target=sparc-em ;; +sparc-*-elf) gdb_target=sparc-em ;; +sparc-*-lynxos*) gdb_target=sparclynx ;; +sparc-*-solaris2*) gdb_target=sun4sol2 ;; +sparc-*-sunos4*) gdb_target=sun4os4 ;; +sparc-*-vxworks*) gdb_target=sparc-em ;; +sparc-*-*) gdb_target=sun4os4 ;; +sparclite*-*-*) gdb_target=sparclite ;; + +tahoe-*-*) gdb_target=tahoe ;; +vax-*-*) gdb_target=vax ;; + +z8k-*-sim) gdb_target=z8ksim ;; +esac + +if [ ! -f ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt ]; then + echo '***' "GDB remote does not support target ${target}" 1>&2 + exit 1 +fi + +if [ -z "${removing}" ] ; then + cat ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt | awk '$1 == "#msg" { + print substr($0,6)}' +fi + +# We really shouldn't depend on there being a space after TM_FILE= ... +targetfile=`awk '$1 == "TM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt` + +if [ "${target}" = "${host}" ] ; then + nativefile=`awk '$1 == "NAT_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` +fi + +host_makefile_frag=../config/${gdb_host_cpu}/${gdb_host}.mh +target_makefile_frag=../config/${gdb_target_cpu}/${gdb_target}.mt + +# If hostfile (XM_FILE) and/or targetfile (TM_FILE) and/or nativefile +# (NAT_FILE) is not set in the ?config/* file, we don't make the +# corresponding links. But we have to remove the xm.h files and tm.h +# files anyway, e.g. when switching from "configure host" to +# "configure none". + +files= +links= +rm -f xm.h +rm -f ser-hardwire.c +if [ "${hostfile}" != "" ]; then + if [ -f ${srcdir}/../config/${hostfile} ]; then + files="${files} ../config/${hostfile}" + else + files="${files} ../config/${gdb_host_cpu}/${hostfile}" + fi + links="${links} xm.h" + +# files="${files} ${gdb_serial_driver}" +# links="${links} ser-hardwire.c" +fi +rm -f tm.h +if [ "${targetfile}" != "" ]; then + if [ -f ${srcdir}/../config/${targetfile} ]; then + files="${files} ../config/${targetfile}" + else + files="${files} ../config/${gdb_target_cpu}/${targetfile}" + fi + links="${links} tm.h" +fi +rm -f nm.h +if [ "${nativefile}" != "" ]; then + if [ -f ${srcdir}/../config/${nativefile} ]; then + files="${files} ../config/${nativefile}" + else + files="${files} ../config/${gdb_host_cpu}/${nativefile}" + fi + links="${links} nm.h" +# temporary scaffolding until all hosts have the host/target/native +# split in place. +else + files="${files} ../config/nm-trash.h" + links="${links} nm.h" +fi + +if [ ${target_cpu} = "sparclite" ]; then + configdirs="${configdirs} sparclite" +fi + +# post-target: + +if [ "${nativefile}" = "" ] ; then + sed -e '/^NATDEPFILES= /s//# NATDEPFILES= /' \ + < Makefile > Makefile.tem + mv -f Makefile.tem Makefile +fi diff --git a/contrib/gdb/gdb/gdbserver/gdbreplay.c b/contrib/gdb/gdb/gdbserver/gdbreplay.c new file mode 100644 index 000000000000..4d5795aba91f --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/gdbreplay.c @@ -0,0 +1,319 @@ +/* Replay a remote debug session logfile for GDB. + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Sort of a hack... */ +#define EOL (EOF - 1) + +static int remote_desc; + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + err = (errno < sys_nerr) ? sys_errlist[errno] : "unknown error"; + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + fprintf (stderr, "\n%s.\n", combined); + fflush (stderr); + exit (1); +} + +static void +sync_error (fp, desc, expect, got) + FILE *fp; + char *desc; + int expect; + int got; +{ + fprintf (stderr, "\n%s\n", desc); + fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n", + ftell (fp), expect, got); + fflush (stderr); + exit (1); +} + +void +remote_close() +{ + close (remote_desc); +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (name) + char *name; +{ + struct sgttyb sg; + extern char *strchr (); + + if (!strchr (name, ':')) + { + fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name); + fflush (stderr); + exit (1); + } + else + { + char *port_str; + int port; + struct sockaddr_in sockaddr; + int tmp; + struct protoent *protoent; + int tmp_desc; + + port_str = strchr (name, ':'); + + port = atoi (port_str + 1); + + tmp_desc = socket (PF_INET, SOCK_STREAM, 0); + if (tmp_desc < 0) + perror_with_name ("Can't open socket"); + + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, + sizeof(tmp)); + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = INADDR_ANY; + + if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) + || listen (tmp_desc, 1)) + perror_with_name ("Can't bind address"); + + tmp = sizeof (sockaddr); + remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp); + if (remote_desc == -1) + perror_with_name ("Accept failed"); + + protoent = getprotobyname ("tcp"); + if (!protoent) + perror_with_name ("getprotobyname"); + + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + + /* Tell TCP not to delay small packets. This greatly speeds up + interactive response. */ + tmp = 1; + setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY, + (char *)&tmp, sizeof(tmp)); + + close (tmp_desc); /* No longer need this */ + + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply + exits when the remote side dies. */ + } + + fcntl (remote_desc, F_SETFL, FASYNC); + + fprintf (stderr, "Replay logfile using %s\n", name); + fflush (stderr); +} + +static int tohex (ch) + int ch; +{ + if (ch >= '0' && ch <= '9') + { + return (ch - '0'); + } + if (ch >= 'A' && ch <= 'F') + { + return (ch - 'A' + 10); + } + if (ch >= 'a' && ch <= 'f') + { + return (ch - 'a' + 10); + } + fprintf (stderr, "\nInvalid hex digit '%c'\n", ch); + fflush (stderr); + exit (1); +} + +static int +logchar (fp) + FILE *fp; +{ + int ch; + int ch2; + + ch = fgetc (fp); + fputc (ch, stdout); + fflush (stdout); + switch (ch) + { + case '\n': + ch = EOL; + break; + case '\\': + ch = fgetc (fp); + fputc (ch, stdout); + fflush (stdout); + switch (ch) + { + case '\\': break; + case 'b': ch = '\b'; break; + case 'f': ch = '\f'; break; + case 'n': ch = '\n'; break; + case 'r': ch = '\r'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + case 'x': + ch2 = fgetc (fp); + fputc (ch2, stdout); + fflush (stdout); + ch = tohex (ch2) << 4; + ch2 = fgetc (fp); + fputc (ch2, stdout); + fflush (stdout); + ch |= tohex (ch2); + break; + default: + /* Treat any other char as just itself */ + break; + } + default: + break; + } + return (ch); +} + +/* Accept input from gdb and match with chars from fp (after skipping one + blank) up until a \n is read from fp (which is not matched) */ + +void +expect (fp) + FILE *fp; +{ + int fromlog; + unsigned char fromgdb; + + if ((fromlog = logchar (fp)) != ' ') + { + sync_error (fp, "Sync error during gdb read of leading blank", ' ', + fromlog); + } + do + { + fromlog = logchar (fp); + if (fromlog == EOL) + { + break; + } + read (remote_desc, &fromgdb, 1); + } while (fromlog == fromgdb); + if (fromlog != EOL) + { + sync_error (fp, "Sync error during read of gdb packet", fromlog, + fromgdb); + } +} + +/* Play data back to gdb from fp (after skipping leading blank) up until a + \n is read from fp (which is discarded and not sent to gdb). */ + +void +play (fp) + FILE *fp; +{ + int fromlog; + char ch; + + if ((fromlog = logchar (fp)) != ' ') + { + sync_error (fp, "Sync error skipping blank during write to gdb", ' ', + fromlog); + } + while ((fromlog = logchar (fp)) != EOL) + { + ch = fromlog; + write (remote_desc, &ch, 1); + } +} + +int +main (argc, argv) + int argc; + char *argv[]; +{ + FILE *fp; + int ch; + + if (argc < 3) + { + fprintf (stderr, "Usage: gdbreplay \n"); + fflush (stderr); + exit (1); + } + fp = fopen (argv[1], "r"); + if (fp == NULL) + { + perror_with_name (argv[1]); + } + remote_open (argv[2]); + while ((ch = logchar (fp)) != EOF) + { + switch (ch) + { + case 'w': + /* data sent from gdb to gdbreplay, accept and match it */ + expect (fp); + break; + case 'r': + /* data sent from gdbreplay to gdb, play it */ + play (fp); + break; + case 'c': + /* Command executed by gdb */ + while ((ch = logchar (fp)) != EOL); + break; + } + } + remote_close (); + exit (0); +} + diff --git a/contrib/gdb/gdb/gdbserver/gdbserver.1 b/contrib/gdb/gdb/gdbserver/gdbserver.1 new file mode 100644 index 000000000000..9d3fdcd8011b --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/gdbserver.1 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1993 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.TH gdbserver 1 "2 November 1993" "Cygnus Support" "GNU Development Tools" +.SH NAME +gdbserver \- Remote Server for the GNU Debugger +.SH SYNOPSIS +.na +.TP +.B gdbserver +.RB tty +.RB prog +.RB "[\|" args... "\|]" +.ad b +.SH DESCRIPTION +GDBSERVER is a program that allows you to run GDB on a different machine +than the one which is running the program being debugged. + +Usage (server (target) side): + +First, you need to have a copy of the program you want to debug put onto +the target system. The program can be stripped to save space if needed, as +GDBserver doesn't care about symbols. All symbol handling is taken care of by +the GDB running on the host system. + +To use the server, you log on to the target system, and run the `gdbserver' +program. You must tell it (a) how to communicate with GDB, (b) the name of +your program, and (c) its arguments. The general syntax is: + + target> gdbserver COMM PROGRAM [ARGS ...] + +For example, using a serial port, you might say: + + target> gdbserver /dev/com1 emacs foo.txt + +This tells gdbserver to debug emacs with an argument of foo.txt, and to +communicate with GDB via /dev/com1. Gdbserver now waits patiently for the +host GDB to communicate with it. + +To use a TCP connection, you could say: + + target> gdbserver host:2345 emacs foo.txt + +This says pretty much the same thing as the last example, except that we are +going to communicate with the host GDB via TCP. The `host:2345' argument means +that we are expecting to see a TCP connection from `host' to local TCP port +2345. (Currently, the `host' part is ignored.) You can choose any number you +want for the port number as long as it does not conflict with any existing TCP +ports on the target system. This same port number must be used in the host +GDBs `target remote' command, which will be described shortly. Note that if +you chose a port number that conflicts with another service, gdbserver will +print an error message and exit. + +Usage (host side): + +You need an unstripped copy of the target program on your host system, since +GDB needs to examine it's symbol tables and such. Start up GDB as you normally +would, with the target program as the first argument. (You may need to use the +--baud option if the serial line is running at anything except 9600 baud.) +Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET-PROG'. After that, the only +new command you need to know about is `target remote'. It's argument is either +a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT +descriptor. For example: + + (gdb) target remote /dev/ttyb + +communicates with the server via serial line /dev/ttyb, and: + + (gdb) target remote the-target:2345 + +communicates via a TCP connection to port 2345 on host `the-target', where +you previously started up gdbserver with the same port number. Note that for +TCP connections, you must start up gdbserver prior to using the `target remote' +command, otherwise you may get an error that looks something like +`Connection refused'. +.SH OPTIONS +You have to supply the name of the program to debug +and the tty to communicate on; the remote GDB will do everything else. +Any remaining arguments will be passed to the program verbatim. +.SH "SEE ALSO" +.RB "`\|" gdb "\|'" +entry in +.B info\c +\&; +.I +Using GDB: A Guide to the GNU Source-Level Debugger\c +, Richard M. Stallman and Roland H. Pesch, July 1991. +.SH COPYING +Copyright (c) 1993 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/contrib/gdb/gdb/gdbserver/low-hppabsd.c b/contrib/gdb/gdb/gdbserver/low-hppabsd.c new file mode 100644 index 000000000000..337e6ed6cd99 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/low-hppabsd.c @@ -0,0 +1,379 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#include +#include + +extern char **environ; +extern int errno; +extern int inferior_pid; +void quit (), perror_with_name (); +int query (); + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (program, allargs) + char *program; + char **allargs; +{ + int pid; + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PT_TRACE_ME, 0, 0, 0, 0); + + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Return nonzero if the given thread is still alive. */ +int +mythread_alive (pid) + int pid; +{ + return 1; +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + pid = wait (&w); + if (pid != inferior_pid) + perror_with_name ("wait"); + + if (WIFEXITED (w)) + { + fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + *status = 'W'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + *status = 'X'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'T'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PT_STEP : PT_CONTINUE, inferior_pid, 1, signal, 0); + if (errno) + perror_with_name ("ptrace"); +} + + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= ARCH_NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + errno = 0; + *(int *) ®isters[ regno * 4 + i] = ptrace (PT_RUREGS, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0, 0); + regaddr += sizeof (int); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes the + kernel doesn't let us at the registers. */ + char *err = strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "reading register %d: %s", regno, err); + error (msg); + goto error_exit; + } + } + error_exit:; +} + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno == -1 || regno == 0) + for (regno = 0; regno < NUM_REGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + extern char registers[]; + register int i; + unsigned int offset = U_REGS_OFFSET; + int scratch; + + if (regno >= 0) + { + if (CANNOT_STORE_REGISTER (regno)) + return; + regaddr = register_addr (regno, offset); + errno = 0; + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + { + scratch = *(int *) ®isters[REGISTER_BYTE (regno)] | 0x3; + ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + scratch, 0); + if (errno != 0) + { + /* Error, even if attached. Failing to write these two + registers is pretty serious. */ + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i], 0); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes the + kernel doesn't let us at the registers. */ + char *err = strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "writing register %d: %s", + regno, err); + error (msg); + return; + } + regaddr += sizeof(int); + } + } + else + for (regno = 0; regno < NUM_REGS; regno++) + store_inferior_registers (regno); +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0, 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i], 0); + if (errno) + return errno; + } + + return 0; +} + +void +initialize () +{ + inferior_pid = 0; +} + +int +have_inferior_p () +{ + return inferior_pid != 0; +} diff --git a/contrib/gdb/gdb/gdbserver/low-linux.c b/contrib/gdb/gdb/gdbserver/low-linux.c new file mode 100644 index 000000000000..34dc64355f69 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/low-linux.c @@ -0,0 +1,420 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#include +#if 0 +#include +#endif + +extern char **environ; +extern int errno; +extern int inferior_pid; +void quit (), perror_with_name (); +int query (); + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (program, allargs) + char *program; + char **allargs; +{ + int pid; + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME, 0, 0, 0); + + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (PTRACE_KILL, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Return nonzero if the given thread is still alive. */ +int +mythread_alive (pid) + int pid; +{ + return 1; +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + pid = wait (&w); + if (pid != inferior_pid) + perror_with_name ("wait"); + + if (WIFEXITED (w)) + { + fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + *status = 'W'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + *status = 'X'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'T'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +/* this table must line up with REGISTER_NAMES in tm-i386v.h */ +/* symbols like 'EAX' come from */ +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + UESP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + +int +i386_register_u_addr (blockend, regnum) + int blockend; + int regnum; +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); + +} + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= ARCH_NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + errno = 0; + *(int *) ®isters[ regno * 4 + i] = ptrace (PTRACE_PEEKUSR, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (int); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes the + kernel doesn't let us at the registers. */ + char *err = strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "reading register %d: %s", regno, err); + error (msg); + goto error_exit; + } + } + error_exit:; +} + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno == -1 || regno == 0) + for (regno = 0; regno < NUM_REGS-NUM_FREGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + register int i; + unsigned int offset = U_REGS_OFFSET; + int scratch; + + if (regno >= 0) + { +#if 0 + if (CANNOT_STORE_REGISTER (regno)) + return; +#endif + regaddr = register_addr (regno, offset); + errno = 0; +#if 0 + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + { + scratch = *(int *) ®isters[REGISTER_BYTE (regno)] | 0x3; + ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + scratch, 0); + if (errno != 0) + { + /* Error, even if attached. Failing to write these two + registers is pretty serious. */ + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else +#endif + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PTRACE_POKEUSR, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + /* Warning, not error, in case we are attached; sometimes the + kernel doesn't let us at the registers. */ + char *err = strerror (errno); + char *msg = alloca (strlen (err) + 128); + sprintf (msg, "writing register %d: %s", + regno, err); + error (msg); + return; + } + regaddr += sizeof(int); + } + } + else + for (regno = 0; regno < NUM_REGS-NUM_FREGS; regno++) + store_inferior_registers (regno); +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (PTRACE_PEEKTEXT, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +void +initialize () +{ + inferior_pid = 0; +} + +int +have_inferior_p () +{ + return inferior_pid != 0; +} diff --git a/contrib/gdb/gdb/gdbserver/low-lynx.c b/contrib/gdb/gdb/gdbserver/low-lynx.c new file mode 100644 index 000000000000..3444f7a116e5 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/low-lynx.c @@ -0,0 +1,746 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "server.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#define LYNXOS +#include +#include +#include +#include +#ifndef __LYNXOS +#define __LYNXOS +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char registers[REGISTER_BYTES]; + +#include + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. */ + +int +create_inferior (program, allargs) + char *program; + char **allargs; +{ + int pid; + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + int pgrp; + + /* Switch child to it's own process group so that signals won't + directly affect gdbserver. */ + + pgrp = getpid(); + setpgrp(0, pgrp); + ioctl (0, TIOCSPGRP, &pgrp); + + ptrace (PTRACE_TRACEME, 0, (PTRACE_ARG3_TYPE)0, 0); + + execv (program, allargs); + + fprintf (stderr, "GDBserver (process %d): Cannot exec %s: %s.\n", + getpid(), program, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (PTRACE_KILL, inferior_pid, 0, 0); + wait (0); + + inferior_pid = 0; +} + +/* Return nonzero if the given thread is still alive. */ +int +mythread_alive (pid) + int pid; +{ + /* Arggh. Apparently pthread_kill only works for threads within + the process that calls pthread_kill. + + We want to avoid the lynx signal extensions as they simply don't + map well to the generic gdb interface we want to keep. + + All we want to do is determine if a particular thread is alive; + it appears as if we can just make a harmless thread specific + ptrace call to do that. */ + return (ptrace (PTRACE_THREADUSER, + BUILDPID (PIDGET (inferior_pid), pid), 0, 0) != -1); +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + while (1) + { + enable_async_io(); + + pid = wait (&w); + + disable_async_io(); + + if (pid != PIDGET(inferior_pid)) + perror_with_name ("wait"); + + thread_from_wait = w.w_tid; + inferior_pid = BUILDPID (inferior_pid, w.w_tid); + + if (WIFSTOPPED(w) + && WSTOPSIG(w) == SIGTRAP) + { + int realsig; + + realsig = ptrace (PTRACE_GETTRACESIG, inferior_pid, + (PTRACE_ARG3_TYPE)0, 0); + + if (realsig == SIGNEWTHREAD) + { + /* It's a new thread notification. Nothing to do here since + the machine independent code in wait_for_inferior will + add the thread to the thread list and restart the thread + when pid != inferior_pid and pid is not in the thread list. + We don't even want to muck with realsig -- the code in + wait_for_inferior expects SIGTRAP. */ + ; + } + } + break; + } + + if (WIFEXITED (w)) + { + *status = 'W'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + *status = 'X'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'T'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT, + BUILDPID (inferior_pid, cont_thread == -1 ? 0 : cont_thread), + 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) + +/* Mapping between GDB register #s and offsets into econtext. Must be + consistent with REGISTER_NAMES macro in various tmXXX.h files. */ + +#define X(ENTRY)(offsetof(struct econtext, ENTRY)) + +#ifdef I386 +/* Mappings from tm-i386v.h */ + +static int regmap[] = +{ + X(eax), + X(ecx), + X(edx), + X(ebx), + X(esp), /* sp */ + X(ebp), /* fp */ + X(esi), + X(edi), + X(eip), /* pc */ + X(flags), /* ps */ + X(cs), + X(ss), + X(ds), + X(es), + X(ecode), /* Lynx doesn't give us either fs or gs, so */ + X(fault), /* we just substitute these two in the hopes + that they are useful. */ +}; +#endif + +#ifdef M68K +/* Mappings from tm-m68k.h */ + +static int regmap[] = +{ + X(regs[0]), /* d0 */ + X(regs[1]), /* d1 */ + X(regs[2]), /* d2 */ + X(regs[3]), /* d3 */ + X(regs[4]), /* d4 */ + X(regs[5]), /* d5 */ + X(regs[6]), /* d6 */ + X(regs[7]), /* d7 */ + X(regs[8]), /* a0 */ + X(regs[9]), /* a1 */ + X(regs[10]), /* a2 */ + X(regs[11]), /* a3 */ + X(regs[12]), /* a4 */ + X(regs[13]), /* a5 */ + X(regs[14]), /* fp */ + 0, /* sp */ + X(status), /* ps */ + X(pc), + + X(fregs[0*3]), /* fp0 */ + X(fregs[1*3]), /* fp1 */ + X(fregs[2*3]), /* fp2 */ + X(fregs[3*3]), /* fp3 */ + X(fregs[4*3]), /* fp4 */ + X(fregs[5*3]), /* fp5 */ + X(fregs[6*3]), /* fp6 */ + X(fregs[7*3]), /* fp7 */ + + X(fcregs[0]), /* fpcontrol */ + X(fcregs[1]), /* fpstatus */ + X(fcregs[2]), /* fpiaddr */ + X(ssw), /* fpcode */ + X(fault), /* fpflags */ +}; +#endif + +#ifdef SPARC +/* Mappings from tm-sparc.h */ + +#define FX(ENTRY)(offsetof(struct fcontext, ENTRY)) + +static int regmap[] = +{ + -1, /* g0 */ + X(g1), + X(g2), + X(g3), + X(g4), + -1, /* g5->g7 aren't saved by Lynx */ + -1, + -1, + + X(o[0]), + X(o[1]), + X(o[2]), + X(o[3]), + X(o[4]), + X(o[5]), + X(o[6]), /* sp */ + X(o[7]), /* ra */ + + -1,-1,-1,-1,-1,-1,-1,-1, /* l0 -> l7 */ + + -1,-1,-1,-1,-1,-1,-1,-1, /* i0 -> i7 */ + + FX(f.fregs[0]), /* f0 */ + FX(f.fregs[1]), + FX(f.fregs[2]), + FX(f.fregs[3]), + FX(f.fregs[4]), + FX(f.fregs[5]), + FX(f.fregs[6]), + FX(f.fregs[7]), + FX(f.fregs[8]), + FX(f.fregs[9]), + FX(f.fregs[10]), + FX(f.fregs[11]), + FX(f.fregs[12]), + FX(f.fregs[13]), + FX(f.fregs[14]), + FX(f.fregs[15]), + FX(f.fregs[16]), + FX(f.fregs[17]), + FX(f.fregs[18]), + FX(f.fregs[19]), + FX(f.fregs[20]), + FX(f.fregs[21]), + FX(f.fregs[22]), + FX(f.fregs[23]), + FX(f.fregs[24]), + FX(f.fregs[25]), + FX(f.fregs[26]), + FX(f.fregs[27]), + FX(f.fregs[28]), + FX(f.fregs[29]), + FX(f.fregs[30]), + FX(f.fregs[31]), + + X(y), + X(psr), + X(wim), + X(tbr), + X(pc), + X(npc), + FX(fsr), /* fpsr */ + -1, /* cpsr */ +}; +#endif + +#ifdef SPARC + +/* This routine handles some oddball cases for Sparc registers and LynxOS. + In partucular, it causes refs to G0, g5->7, and all fp regs to return zero. + It also handles knows where to find the I & L regs on the stack. */ + +void +fetch_inferior_registers (regno) + int regno; +{ +#if 0 + int whatregs = 0; + +#define WHATREGS_FLOAT 1 +#define WHATREGS_GEN 2 +#define WHATREGS_STACK 4 + + if (regno == -1) + whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK; + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + whatregs = WHATREGS_STACK; + else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + whatregs = WHATREGS_FLOAT; + else + whatregs = WHATREGS_GEN; + + if (whatregs & WHATREGS_GEN) + { + struct econtext ec; /* general regs */ + char buf[MAX_REGISTER_RAW_SIZE]; + int retval; + int i; + + errno = 0; + retval = ptrace (PTRACE_GETREGS, + BUILDPID (inferior_pid, general_thread), + (PTRACE_ARG3_TYPE) &ec, + 0); + if (errno) + perror_with_name ("Sparc fetch_inferior_registers(ptrace)"); + + memset (buf, 0, REGISTER_RAW_SIZE (G0_REGNUM)); + supply_register (G0_REGNUM, buf); + supply_register (TBR_REGNUM, (char *)&ec.tbr); + + memcpy (®isters[REGISTER_BYTE (G1_REGNUM)], &ec.g1, + 4 * REGISTER_RAW_SIZE (G1_REGNUM)); + for (i = G1_REGNUM; i <= G1_REGNUM + 3; i++) + register_valid[i] = 1; + + supply_register (PS_REGNUM, (char *)&ec.psr); + supply_register (Y_REGNUM, (char *)&ec.y); + supply_register (PC_REGNUM, (char *)&ec.pc); + supply_register (NPC_REGNUM, (char *)&ec.npc); + supply_register (WIM_REGNUM, (char *)&ec.wim); + + memcpy (®isters[REGISTER_BYTE (O0_REGNUM)], ec.o, + 8 * REGISTER_RAW_SIZE (O0_REGNUM)); + for (i = O0_REGNUM; i <= O0_REGNUM + 7; i++) + register_valid[i] = 1; + } + + if (whatregs & WHATREGS_STACK) + { + CORE_ADDR sp; + int i; + + sp = read_register (SP_REGNUM); + + target_xfer_memory (sp + FRAME_SAVED_I0, + ®isters[REGISTER_BYTE(I0_REGNUM)], + 8 * REGISTER_RAW_SIZE (I0_REGNUM), 0); + for (i = I0_REGNUM; i <= I7_REGNUM; i++) + register_valid[i] = 1; + + target_xfer_memory (sp + FRAME_SAVED_L0, + ®isters[REGISTER_BYTE(L0_REGNUM)], + 8 * REGISTER_RAW_SIZE (L0_REGNUM), 0); + for (i = L0_REGNUM; i <= L0_REGNUM + 7; i++) + register_valid[i] = 1; + } + + if (whatregs & WHATREGS_FLOAT) + { + struct fcontext fc; /* fp regs */ + int retval; + int i; + + errno = 0; + retval = ptrace (PTRACE_GETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("Sparc fetch_inferior_registers(ptrace)"); + + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], fc.f.fregs, + 32 * REGISTER_RAW_SIZE (FP0_REGNUM)); + for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++) + register_valid[i] = 1; + + supply_register (FPS_REGNUM, (char *)&fc.fsr); + } +#endif +} + +/* This routine handles storing of the I & L regs for the Sparc. The trick + here is that they actually live on the stack. The really tricky part is + that when changing the stack pointer, the I & L regs must be written to + where the new SP points, otherwise the regs will be incorrect when the + process is started up again. We assume that the I & L regs are valid at + this point. */ + +void +store_inferior_registers (regno) + int regno; +{ +#if 0 + int whatregs = 0; + + if (regno == -1) + whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK; + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + whatregs = WHATREGS_STACK; + else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + whatregs = WHATREGS_FLOAT; + else if (regno == SP_REGNUM) + whatregs = WHATREGS_STACK | WHATREGS_GEN; + else + whatregs = WHATREGS_GEN; + + if (whatregs & WHATREGS_GEN) + { + struct econtext ec; /* general regs */ + int retval; + + ec.tbr = read_register (TBR_REGNUM); + memcpy (&ec.g1, ®isters[REGISTER_BYTE (G1_REGNUM)], + 4 * REGISTER_RAW_SIZE (G1_REGNUM)); + + ec.psr = read_register (PS_REGNUM); + ec.y = read_register (Y_REGNUM); + ec.pc = read_register (PC_REGNUM); + ec.npc = read_register (NPC_REGNUM); + ec.wim = read_register (WIM_REGNUM); + + memcpy (ec.o, ®isters[REGISTER_BYTE (O0_REGNUM)], + 8 * REGISTER_RAW_SIZE (O0_REGNUM)); + + errno = 0; + retval = ptrace (PTRACE_SETREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &ec, + 0); + if (errno) + perror_with_name ("Sparc fetch_inferior_registers(ptrace)"); + } + + if (whatregs & WHATREGS_STACK) + { + int regoffset; + CORE_ADDR sp; + + sp = read_register (SP_REGNUM); + + if (regno == -1 || regno == SP_REGNUM) + { + if (!register_valid[L0_REGNUM+5]) + abort(); + target_xfer_memory (sp + FRAME_SAVED_I0, + ®isters[REGISTER_BYTE (I0_REGNUM)], + 8 * REGISTER_RAW_SIZE (I0_REGNUM), 1); + + target_xfer_memory (sp + FRAME_SAVED_L0, + ®isters[REGISTER_BYTE (L0_REGNUM)], + 8 * REGISTER_RAW_SIZE (L0_REGNUM), 1); + } + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + { + if (!register_valid[regno]) + abort(); + if (regno >= L0_REGNUM && regno <= L0_REGNUM + 7) + regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM) + + FRAME_SAVED_L0; + else + regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (I0_REGNUM) + + FRAME_SAVED_I0; + target_xfer_memory (sp + regoffset, ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno), 1); + } + } + + if (whatregs & WHATREGS_FLOAT) + { + struct fcontext fc; /* fp regs */ + int retval; + +/* We read fcontext first so that we can get good values for fq_t... */ + errno = 0; + retval = ptrace (PTRACE_GETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("Sparc fetch_inferior_registers(ptrace)"); + + memcpy (fc.f.fregs, ®isters[REGISTER_BYTE (FP0_REGNUM)], + 32 * REGISTER_RAW_SIZE (FP0_REGNUM)); + + fc.fsr = read_register (FPS_REGNUM); + + errno = 0; + retval = ptrace (PTRACE_SETFPREGS, BUILDPID (inferior_pid, general_thread), (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("Sparc fetch_inferior_registers(ptrace)"); + } +#endif +} +#endif /* SPARC */ + +#ifndef SPARC + +/* Return the offset relative to the start of the per-thread data to the + saved context block. */ + +static unsigned long +lynx_registers_addr() +{ + CORE_ADDR stblock; + int ecpoff = offsetof(st_t, ecp); + CORE_ADDR ecp; + + errno = 0; + stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, BUILDPID (inferior_pid, general_thread), + (PTRACE_ARG3_TYPE)0, 0); + if (errno) + perror_with_name ("PTRACE_THREADUSER"); + + ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, BUILDPID (inferior_pid, general_thread), + (PTRACE_ARG3_TYPE)ecpoff, 0); + if (errno) + perror_with_name ("lynx_registers_addr(PTRACE_PEEKTHREAD)"); + + return ecp - stblock; +} + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ + +void +fetch_inferior_registers (ignored) + int ignored; +{ + int regno; + unsigned long reg; + unsigned long ecp; + + ecp = lynx_registers_addr(); + + for (regno = 0; regno < NUM_REGS; regno++) + { + int ptrace_fun = PTRACE_PEEKTHREAD; + +#ifdef PTRACE_PEEKUSP + ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD; +#endif + + errno = 0; + reg = ptrace (ptrace_fun, BUILDPID (inferior_pid, general_thread), + (PTRACE_ARG3_TYPE) (ecp + regmap[regno]), 0); + if (errno) + perror_with_name ("fetch_inferior_registers(PTRACE_PEEKTHREAD)"); + + *(unsigned long *)®isters[REGISTER_BYTE (regno)] = reg; + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (ignored) + int ignored; +{ + int regno; + unsigned long reg; + unsigned long ecp; + + ecp = lynx_registers_addr(); + + for (regno = 0; regno < NUM_REGS; regno++) + { + int ptrace_fun = PTRACE_POKEUSER; + +#ifdef PTRACE_POKEUSP + ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER; +#endif + + reg = *(unsigned long *)®isters[REGISTER_BYTE (regno)]; + + errno = 0; + ptrace (ptrace_fun, BUILDPID (inferior_pid, general_thread), + (PTRACE_ARG3_TYPE) (ecp + regmap[regno]), reg); + if (errno) + perror_with_name ("PTRACE_POKEUSER"); + } +} + +#endif /* ! SPARC */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +void +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread), addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread), addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (PTRACE_PEEKTEXT, BUILDPID (inferior_pid, general_thread), + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + while (1) + { + errno = 0; + ptrace (PTRACE_POKETEXT, BUILDPID (inferior_pid, general_thread), addr, buffer[i]); + if (errno) + { + fprintf(stderr, "\ +ptrace (PTRACE_POKETEXT): errno=%d, pid=0x%x, addr=0x%x, buffer[i] = 0x%x\n", + errno, BUILDPID (inferior_pid, general_thread), + addr, buffer[i]); + fprintf(stderr, "Sleeping for 1 second\n"); + sleep(1); + } + else + break; + } + } + + return 0; +} diff --git a/contrib/gdb/gdb/gdbserver/low-sparc.c b/contrib/gdb/gdb/gdbserver/low-sparc.c new file mode 100644 index 000000000000..6f9810e9a998 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/low-sparc.c @@ -0,0 +1,334 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "frame.h" +#include "inferior.h" +/*************************** +#include "initialize.h" +****************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#include +#include + +extern int sys_nerr; +extern char **sys_errlist; +extern char **environ; +extern int errno; +extern int inferior_pid; +void quit (), perror_with_name (); +int query (); + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (program, allargs) + char *program; + char **allargs; +{ + int pid; + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME); + + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Return nonzero if the given thread is still alive. */ +int +mythread_alive (pid) + int pid; +{ + return 1; +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + pid = wait (&w); + if (pid != inferior_pid) + perror_with_name ("wait"); + + if (WIFEXITED (w)) + { + fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + *status = 'W'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + *status = 'X'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'T'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ + +void +fetch_inferior_registers (ignored) + int ignored; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + int i; + + /* Global and Out regs are fetched directly, as well as the control + registers. If we're getting one of the in or local regs, + and the stack pointer has not yet been fetched, + we have to do that first, since they're found in memory relative + to the stack pointer. */ + + if (ptrace (PTRACE_GETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers, 0)) + perror("ptrace_getregs"); + + registers[REGISTER_BYTE (0)] = 0; + memcpy (®isters[REGISTER_BYTE (1)], &inferior_registers.r_g1, + 15 * REGISTER_RAW_SIZE (G0_REGNUM)); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = inferior_registers.r_npc; + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = inferior_registers.r_y; + + /* Floating point registers */ + + if (ptrace (PTRACE_GETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers, + 0)) + perror("ptrace_getfpregs"); + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fpu_fr); + + /* These regs are saved on the stack by the kernel. Only read them + all (16 ptrace calls!) if we really need them. */ + + read_inferior_memory (*(CORE_ADDR*)®isters[REGISTER_BYTE (SP_REGNUM)], + ®isters[REGISTER_BYTE (L0_REGNUM)], + 16*REGISTER_RAW_SIZE (L0_REGNUM)); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (ignored) + int ignored; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + CORE_ADDR sp = *(CORE_ADDR *)®isters[REGISTER_BYTE (SP_REGNUM)]; + + write_inferior_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], + 16*REGISTER_RAW_SIZE (L0_REGNUM)); + + memcpy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (G1_REGNUM)], + 15 * REGISTER_RAW_SIZE (G1_REGNUM)); + + inferior_registers.r_ps = + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + inferior_registers.r_npc = + *(int *)®isters[REGISTER_BYTE (NPC_REGNUM)]; + inferior_registers.r_y = + *(int *)®isters[REGISTER_BYTE (Y_REGNUM)]; + + if (ptrace (PTRACE_SETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers, 0)) + perror("ptrace_setregs"); + + memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fpu_fr); + + if (ptrace (PTRACE_SETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0)) + perror("ptrace_setfpregs"); +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +void +initialize () +{ + inferior_pid = 0; +} + +int +have_inferior_p () +{ + return inferior_pid != 0; +} diff --git a/contrib/gdb/gdb/gdbserver/low-sun3.c b/contrib/gdb/gdb/gdbserver/low-sun3.c new file mode 100644 index 000000000000..c84b79f2f684 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/low-sun3.c @@ -0,0 +1,313 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#include +#include + +extern int sys_nerr; +extern char **sys_errlist; +extern char **environ; +extern int errno; +extern int inferior_pid; +void quit (), perror_with_name (); +int query (); + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (program, allargs) + char *program; + char **allargs; +{ + int pid; + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + ptrace (PTRACE_TRACEME); + + execv (program, allargs); + + fprintf (stderr, "Cannot exec %s: %s.\n", program, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Return nonzero if the given thread is still alive. */ +int +mythread_alive (pid) + int pid; +{ + return 1; +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + pid = wait (&w); + if (pid != inferior_pid) + perror_with_name ("wait"); + + if (WIFEXITED (w)) + { + fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + *status = 'W'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + *status = 'X'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'T'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ + +void +fetch_inferior_registers (ignored) + int ignored; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + + ptrace (PTRACE_GETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers); +#ifdef FP0_REGNUM + ptrace (PTRACE_GETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers); +#endif + + memcpy (registers, &inferior_registers, 16 * 4); +#ifdef FP0_REGNUM + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); +#endif + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; +#ifdef FP0_REGNUM + memcpy + (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +#endif +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (ignored) + int ignored; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + + memcpy (&inferior_registers, registers, 16 * 4); +#ifdef FP0_REGNUM + memcpy (&inferior_fp_registers, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); +#endif + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + +#ifdef FP0_REGNUM + memcpy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + (sizeof inferior_fp_registers + - sizeof inferior_fp_registers.fps_regs)); +#endif + + ptrace (PTRACE_SETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers); +#if FP0_REGNUM + ptrace (PTRACE_SETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers); +#endif +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +void +initialize () +{ + inferior_pid = 0; +} + +int +have_inferior_p () +{ + return inferior_pid != 0; +} diff --git a/contrib/gdb/gdb/gdbserver/remote-utils.c b/contrib/gdb/gdb/gdbserver/remote-utils.c new file mode 100644 index 000000000000..ff2183ec1b95 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/remote-utils.c @@ -0,0 +1,479 @@ +/* Remote utility routines for the remote server for GDB. + Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int kiodebug = 0; +static int remote_desc; + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (name) + char *name; +{ + struct sgttyb sg; + + if (!strchr (name, ':')) + { + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + perror_with_name ("Could not open remote device"); + + ioctl (remote_desc, TIOCGETP, &sg); + sg.sg_flags = RAW; + ioctl (remote_desc, TIOCSETP, &sg); + } + else + { + char *port_str; + int port; + struct sockaddr_in sockaddr; + int tmp; + struct protoent *protoent; + int tmp_desc; + + port_str = strchr (name, ':'); + + port = atoi (port_str + 1); + + tmp_desc = socket (PF_INET, SOCK_STREAM, 0); + if (tmp_desc < 0) + perror_with_name ("Can't open socket"); + + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, + sizeof(tmp)); + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = INADDR_ANY; + + if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) + || listen (tmp_desc, 1)) + perror_with_name ("Can't bind address"); + + tmp = sizeof (sockaddr); + remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp); + if (remote_desc == -1) + perror_with_name ("Accept failed"); + + protoent = getprotobyname ("tcp"); + if (!protoent) + perror_with_name ("getprotobyname"); + + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + + /* Tell TCP not to delay small packets. This greatly speeds up + interactive response. */ + tmp = 1; + setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY, + (char *)&tmp, sizeof(tmp)); + + close (tmp_desc); /* No longer need this */ + + signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply + exits when the remote side dies. */ + } + + fcntl (remote_desc, F_SETFL, FASYNC); + + fprintf (stderr, "Remote debugging using %s\n", name); +} + +void +remote_close() +{ + close (remote_desc); +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */ + +int +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[2000]; + char buf3[1]; + int cnt = strlen (buf); + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + do + { + int cc; + + if (write (remote_desc, buf2, p - buf2) != p - buf2) + { + perror ("putpkt(write)"); + return -1; + } + + cc = read (remote_desc, buf3, 1); + if (cc <= 0) + { + if (cc == 0) + fprintf (stderr, "putpkt(read): Got EOF\n"); + else + perror ("putpkt(read)"); + + return -1; + } + } + while (buf3[0] != '+'); + + return 1; /* Success! */ +} + +/* Come here when we get an input interrupt from the remote side. This + interrupt should only be active while we are waiting for the child to do + something. About the only thing that should come through is a ^C, which + will cause us to send a SIGINT to the child. */ + +static void +input_interrupt() +{ + int cc; + char c; + + cc = read (remote_desc, &c, 1); + + if (cc != 1 || c != '\003') + { + fprintf(stderr, "input_interrupt, cc = %d c = %d\n", cc, c); + return; + } + + kill (inferior_pid, SIGINT); +} + +void +enable_async_io() +{ + signal (SIGIO, input_interrupt); +} + +void +disable_async_io() +{ + signal (SIGIO, SIG_IGN); +} + +/* Returns next char from remote GDB. -1 if error. */ + +static int +readchar () +{ + static char buf[BUFSIZ]; + static int bufcnt = 0; + static char *bufp; + + if (bufcnt-- > 0) + return *bufp++ & 0x7f; + + bufcnt = read (remote_desc, buf, sizeof (buf)); + + if (bufcnt <= 0) + { + if (bufcnt == 0) + fprintf (stderr, "readchar: Got EOF\n"); + else + perror ("readchar"); + + return -1; + } + + bufp = buf; + bufcnt--; + return *bufp++ & 0x7f; +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. Returns length of packet, or negative if error. */ + +int +getpkt (buf) + char *buf; +{ + char *bp; + unsigned char csum, c1, c2; + int c; + + while (1) + { + csum = 0; + + while (1) + { + c = readchar (); + if (c == '$') + break; + if (c < 0) + return -1; + } + + bp = buf; + while (1) + { + c = readchar (); + if (c < 0) + return -1; + if (c == '#') + break; + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + if (csum == (c1 << 4) + c2) + break; + + fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + write (remote_desc, "-", 1); + } + + write (remote_desc, "+", 1); + return bp - buf; +} + +void +write_ok (buf) + char *buf; +{ + buf[0] = 'O'; + buf[1] = 'K'; + buf[2] = '\0'; +} + +void +write_enn (buf) + char *buf; +{ + buf[0] = 'E'; + buf[1] = 'N'; + buf[2] = 'N'; + buf[3] = '\0'; +} + +void +convert_int_to_ascii (from, to, n) + char *from, *to; + int n; +{ + int nib; + char ch; + while (n--) + { + ch = *from++; + nib = ((ch & 0xf0) >> 4) & 0x0f; + *to++ = tohex (nib); + nib = ch & 0x0f; + *to++ = tohex (nib); + } + *to++ = 0; +} + + +void +convert_ascii_to_int (from, to, n) + char *from, *to; + int n; +{ + int nib1, nib2; + while (n--) + { + nib1 = fromhex (*from++); + nib2 = fromhex (*from++); + *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f); + } +} + +static char * +outreg(regno, buf) + int regno; + char *buf; +{ + extern char registers[]; + + *buf++ = tohex (regno >> 4); + *buf++ = tohex (regno & 0xf); + *buf++ = ':'; + convert_int_to_ascii (®isters[REGISTER_BYTE (regno)], buf, 4); + buf += 8; + *buf++ = ';'; + + return buf; +} + +void +prepare_resume_reply (buf, status, signal) + char *buf; + char status; + unsigned char signal; +{ + int nib; + char ch; + + *buf++ = status; + + /* FIXME! Should be converting this signal number (numbered + according to the signal numbering of the system we are running on) + to the signal numbers used by the gdb protocol (see enum target_signal + in gdb/target.h). */ + nib = ((signal & 0xf0) >> 4); + *buf++ = tohex (nib); + nib = signal & 0x0f; + *buf++ = tohex (nib); + + if (status == 'T') + { + buf = outreg (PC_REGNUM, buf); + buf = outreg (FP_REGNUM, buf); + buf = outreg (SP_REGNUM, buf); +#ifdef NPC_REGNUM + buf = outreg (NPC_REGNUM, buf); +#endif +#ifdef O7_REGNUM + buf = outreg (O7_REGNUM, buf); +#endif + + /* If the debugger hasn't used any thread features, don't burden it with + threads. If we didn't check this, GDB 4.13 and older would choke. */ + if (cont_thread != 0) + { + if (old_thread_from_wait != thread_from_wait) + { + sprintf (buf, "thread:%x;", thread_from_wait); + buf += strlen (buf); + old_thread_from_wait = thread_from_wait; + } + } + } + /* For W and X, we're done. */ + *buf++ = 0; +} + +void +decode_m_packet (from, mem_addr_ptr, len_ptr) + char *from; + unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + for (j = 0; j < 4; j++) + { + if ((ch = from[i++]) == 0) + break; + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } +} + +void +decode_M_packet (from, mem_addr_ptr, len_ptr, to) + char *from, *to; + unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + while ((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } + + convert_ascii_to_int (&from[i++], to, *len_ptr); +} diff --git a/contrib/gdb/gdb/gdbserver/server.c b/contrib/gdb/gdb/gdbserver/server.c new file mode 100644 index 000000000000..a583c545d785 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/server.c @@ -0,0 +1,249 @@ +/* Main code for remote server for GDB. + Copyright (C) 1989, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "server.h" + +int cont_thread; +int general_thread; +int thread_from_wait; +int old_thread_from_wait; +int extended_protocol; + +int +main (argc, argv) + int argc; + char *argv[]; +{ + char ch, status, own_buf[2000], mem_buf[2000]; + int i = 0; + unsigned char signal; + unsigned int mem_addr, len; + + if (setjmp(toplevel)) + { + fprintf(stderr, "Exiting\n"); + exit(1); + } + + if (argc < 3) + error("Usage: gdbserver tty prog [args ...]"); + + inferior_pid = create_inferior (argv[2], &argv[2]); + fprintf (stderr, "Process %s created; pid = %d\n", argv[2], inferior_pid); + + signal = mywait (&status); /* Wait till we are at 1st instr in prog */ + + /* We are now stopped at the first instruction of the target process */ + + while (1) + { + remote_open (argv[1]); + +restart: + setjmp(toplevel); + while (getpkt (own_buf) > 0) + { + unsigned char sig; + i = 0; + ch = own_buf[i++]; + switch (ch) + { + case '!': + extended_protocol = 1; + prepare_resume_reply (own_buf, status, signal); + break; + case '?': + prepare_resume_reply (own_buf, status, signal); + break; + case 'H': + switch (own_buf[1]) + { + case 'g': + general_thread = strtol (&own_buf[2], NULL, 16); + write_ok (own_buf); + fetch_inferior_registers (0); + break; + case 'c': + cont_thread = strtol (&own_buf[2], NULL, 16); + write_ok (own_buf); + break; + default: + /* Silently ignore it so that gdb can extend the protocol + without compatibility headaches. */ + own_buf[0] = '\0'; + break; + } + break; + case 'g': + convert_int_to_ascii (registers, own_buf, REGISTER_BYTES); + break; + case 'G': + convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES); + store_inferior_registers (-1); + write_ok (own_buf); + break; + case 'm': + decode_m_packet (&own_buf[1], &mem_addr, &len); + read_inferior_memory (mem_addr, mem_buf, len); + convert_int_to_ascii (mem_buf, own_buf, len); + break; + case 'M': + decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); + if (write_inferior_memory (mem_addr, mem_buf, len) == 0) + write_ok (own_buf); + else + write_enn (own_buf); + break; + case 'C': + convert_ascii_to_int (own_buf + 1, &sig, 1); + myresume (0, sig); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 'S': + convert_ascii_to_int (own_buf + 1, &sig, 1); + myresume (1, sig); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 'c': + myresume (0, 0); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 's': + myresume (1, 0); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 'k': + fprintf (stderr, "Killing inferior\n"); + kill_inferior (); + /* When using the extended protocol, we start up a new + debugging session. The traditional protocol will + exit instead. */ + if (extended_protocol) + { + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + inferior_pid = create_inferior (argv[2], &argv[2]); + fprintf (stderr, "Process %s created; pid = %d\n", + argv[2], inferior_pid); + + /* Wait till we are at 1st instruction in prog. */ + signal = mywait (&status); + goto restart; + break; + } + else + { + exit (0); + break; + } + case 'T': + if (mythread_alive (strtol (&own_buf[1], NULL, 16))) + write_ok (own_buf); + else + write_enn (own_buf); + break; + case 'R': + /* Restarting the inferior is only supported in the + extended protocol. */ + if (extended_protocol) + { + kill_inferior (); + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + inferior_pid = create_inferior (argv[2], &argv[2]); + fprintf (stderr, "Process %s created; pid = %d\n", + argv[2], inferior_pid); + + /* Wait till we are at 1st instruction in prog. */ + signal = mywait (&status); + goto restart; + break; + } + else + { + /* It is a request we don't understand. Respond with an + empty packet so that gdb knows that we don't support this + request. */ + own_buf[0] = '\0'; + break; + } + default: + /* It is a request we don't understand. Respond with an + empty packet so that gdb knows that we don't support this + request. */ + own_buf[0] = '\0'; + break; + } + + putpkt (own_buf); + + if (status == 'W') + fprintf (stderr, + "\nChild exited with status %d\n", sig); + if (status == 'X') + fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig); + if (status == 'W' || status == 'X') + { + if (extended_protocol) + { + fprintf (stderr, "Killing inferior\n"); + kill_inferior (); + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + inferior_pid = create_inferior (argv[2], &argv[2]); + fprintf (stderr, "Process %s created; pid = %d\n", + argv[2], inferior_pid); + + /* Wait till we are at 1st instruction in prog. */ + signal = mywait (&status); + goto restart; + break; + } + else + { + fprintf (stderr, "GDBserver exiting\n"); + exit (0); + } + } + } + + /* We come here when getpkt fails. + + For the extended remote protocol we exit (and this is the only + way we gracefully exit!). + + For the traditional remote protocol close the connection, + and re-open it at the top of the loop. */ + if (extended_protocol) + { + remote_close (); + exit (0); + } + else + { + fprintf (stderr, "Remote side has terminated connection. GDBserver will reopen the connection.\n"); + + remote_close (); + } + } +} diff --git a/contrib/gdb/gdb/gdbserver/server.h b/contrib/gdb/gdb/gdbserver/server.h new file mode 100644 index 000000000000..6aeaa0989e85 --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/server.h @@ -0,0 +1,50 @@ +/* Common definitions for remote server for GDB. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include + +void read_inferior_memory (); +unsigned char mywait (); +void myresume(); +int mythread_alive (); +int create_inferior (); + +extern char registers[]; +int inferior_pid; +extern int cont_thread; +extern int general_thread; +extern int thread_from_wait; +extern int old_thread_from_wait; + +int remote_send (); +int putpkt (); +int getpkt (); +void remote_open (); +void write_ok (); +void write_enn (); +void convert_ascii_to_int (); +void convert_int_to_ascii (); +void prepare_resume_reply (); +void decode_m_packet (); +void decode_M_packet (); + +jmp_buf toplevel; + +void perror_with_name (); diff --git a/contrib/gdb/gdb/gdbserver/utils.c b/contrib/gdb/gdb/gdbserver/utils.c new file mode 100644 index 000000000000..032dbbf2fb6b --- /dev/null +++ b/contrib/gdb/gdb/gdbserver/utils.c @@ -0,0 +1,113 @@ +/* General utility routines for the remote server for GDB. + Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "server.h" +#include + +/* Generally useful subroutines used throughout the program. */ + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +#ifdef ANSI_PROTOTYPES +NORETURN void +error (char *string, ...) +#else +void +error (va_alist) + va_dcl +#endif +{ + extern jmp_buf toplevel; + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + va_start (args); +#endif + fflush (stdout); +#ifdef ANSI_PROTOTYPES + vfprintf (stderr, string, args); +#else + { + char *string1; + + string1 = va_arg (args, char *); + vfprintf (stderr, string1, args); + } +#endif + fprintf (stderr, "\n"); + longjmp(toplevel, 1); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +/* VARARGS */ +NORETURN void +#ifdef ANSI_PROTOTYPES +fatal (char *string, ...) +#else +fatal (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + va_start (args); + string = va_arg (args, char *); +#endif + fprintf (stderr, "gdb: "); + vfprintf (stderr, string, args); + fprintf (stderr, "\n"); + va_end (args); + exit (1); +} diff --git a/contrib/gdb/gdb/gdbtypes.c b/contrib/gdb/gdb/gdbtypes.c new file mode 100644 index 000000000000..13a111f08886 --- /dev/null +++ b/contrib/gdb/gdb/gdbtypes.c @@ -0,0 +1,1683 @@ +/* Support routines for manipulating internal types for GDB. + Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "bfd.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "target.h" +#include "value.h" +#include "demangle.h" +#include "complaints.h" + +/* These variables point to the objects + representing the predefined C data types. */ + +struct type *builtin_type_void; +struct type *builtin_type_char; +struct type *builtin_type_short; +struct type *builtin_type_int; +struct type *builtin_type_long; +struct type *builtin_type_long_long; +struct type *builtin_type_signed_char; +struct type *builtin_type_unsigned_char; +struct type *builtin_type_unsigned_short; +struct type *builtin_type_unsigned_int; +struct type *builtin_type_unsigned_long; +struct type *builtin_type_unsigned_long_long; +struct type *builtin_type_float; +struct type *builtin_type_double; +struct type *builtin_type_long_double; +struct type *builtin_type_complex; +struct type *builtin_type_double_complex; +struct type *builtin_type_string; + +/* Alloc a new type structure and fill it with some defaults. If + OBJFILE is non-NULL, then allocate the space for the type structure + in that objfile's type_obstack. */ + +struct type * +alloc_type (objfile) + struct objfile *objfile; +{ + register struct type *type; + + /* Alloc the structure and start off with all fields zeroed. */ + + if (objfile == NULL) + { + type = (struct type *) xmalloc (sizeof (struct type)); + } + else + { + type = (struct type *) obstack_alloc (&objfile -> type_obstack, + sizeof (struct type)); + OBJSTAT (objfile, n_types++); + } + memset ((char *) type, 0, sizeof (struct type)); + + /* Initialize the fields that might not be zero. */ + + TYPE_CODE (type) = TYPE_CODE_UNDEF; + TYPE_OBJFILE (type) = objfile; + TYPE_VPTR_FIELDNO (type) = -1; + + return (type); +} + +/* Lookup a pointer to a type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the pointer type should be stored. + If *TYPEPTR is zero, update it to point to the pointer type we return. + We allocate new memory if needed. */ + +struct type * +make_pointer_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + ntype = TYPE_POINTER_TYPE (type); + + if (ntype) + if (typeptr == 0) + return ntype; /* Don't care about alloc, and have new type. */ + else if (*typeptr == 0) + { + *typeptr = ntype; /* Tracking alloc, and we have new type. */ + return ntype; + } + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + TYPE_POINTER_TYPE (type) = ntype; + + /* FIXME! Assume the machine has only one representation for pointers! */ + + TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT; + TYPE_CODE (ntype) = TYPE_CODE_PTR; + + /* pointers are unsigned */ + TYPE_FLAGS (ntype) |= TYPE_FLAG_UNSIGNED; + + if (!TYPE_POINTER_TYPE (type)) /* Remember it, if don't have one. */ + TYPE_POINTER_TYPE (type) = ntype; + + return ntype; +} + +/* Given a type TYPE, return a type of pointers to that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_pointer_type (type) + struct type *type; +{ + return make_pointer_type (type, (struct type **)0); +} + +/* Lookup a C++ `reference' to a type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the reference type should be stored. + If *TYPEPTR is zero, update it to point to the reference type we return. + We allocate new memory if needed. */ + +struct type * +make_reference_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + ntype = TYPE_REFERENCE_TYPE (type); + + if (ntype) + if (typeptr == 0) + return ntype; /* Don't care about alloc, and have new type. */ + else if (*typeptr == 0) + { + *typeptr = ntype; /* Tracking alloc, and we have new type. */ + return ntype; + } + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + TYPE_REFERENCE_TYPE (type) = ntype; + + /* FIXME! Assume the machine has only one representation for references, + and that it matches the (only) representation for pointers! */ + + TYPE_LENGTH (ntype) = TARGET_PTR_BIT / TARGET_CHAR_BIT; + TYPE_CODE (ntype) = TYPE_CODE_REF; + + if (!TYPE_REFERENCE_TYPE (type)) /* Remember it, if don't have one. */ + TYPE_REFERENCE_TYPE (type) = ntype; + + return ntype; +} + +/* Same as above, but caller doesn't care about memory allocation details. */ + +struct type * +lookup_reference_type (type) + struct type *type; +{ + return make_reference_type (type, (struct type **)0); +} + +/* Lookup a function type that returns type TYPE. TYPEPTR, if nonzero, points + to a pointer to memory where the function type should be stored. + If *TYPEPTR is zero, update it to point to the function type we return. + We allocate new memory if needed. */ + +struct type * +make_function_type (type, typeptr) + struct type *type; + struct type **typeptr; +{ + register struct type *ntype; /* New type */ + struct objfile *objfile; + + if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ + { + ntype = alloc_type (TYPE_OBJFILE (type)); + if (typeptr) + *typeptr = ntype; + } + else /* We have storage, but need to reset it. */ + { + ntype = *typeptr; + objfile = TYPE_OBJFILE (ntype); + memset ((char *) ntype, 0, sizeof (struct type)); + TYPE_OBJFILE (ntype) = objfile; + } + + TYPE_TARGET_TYPE (ntype) = type; + + TYPE_LENGTH (ntype) = 1; + TYPE_CODE (ntype) = TYPE_CODE_FUNC; + + return ntype; +} + + +/* Given a type TYPE, return a type of functions that return that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_function_type (type) + struct type *type; +{ + return make_function_type (type, (struct type **)0); +} + +/* Implement direct support for MEMBER_TYPE in GNU C++. + May need to construct such a type if this is the first use. + The TYPE is the type of the member. The DOMAIN is the type + of the aggregate that the member belongs to. */ + +struct type * +lookup_member_type (type, domain) + struct type *type; + struct type *domain; +{ + register struct type *mtype; + + mtype = alloc_type (TYPE_OBJFILE (type)); + smash_to_member_type (mtype, domain, type); + return (mtype); +} + +/* Allocate a stub method whose return type is TYPE. + This apparently happens for speed of symbol reading, since parsing + out the arguments to the method is cpu-intensive, the way we are doing + it. So, we will fill in arguments later. + This always returns a fresh type. */ + +struct type * +allocate_stub_method (type) + struct type *type; +{ + struct type *mtype; + + mtype = alloc_type (TYPE_OBJFILE (type)); + TYPE_TARGET_TYPE (mtype) = type; + /* _DOMAIN_TYPE (mtype) = unknown yet */ + /* _ARG_TYPES (mtype) = unknown yet */ + TYPE_FLAGS (mtype) = TYPE_FLAG_STUB; + TYPE_CODE (mtype) = TYPE_CODE_METHOD; + TYPE_LENGTH (mtype) = 1; + return (mtype); +} + +/* Create a range type using either a blank type supplied in RESULT_TYPE, + or creating a new type, inheriting the objfile from INDEX_TYPE. + + Indices will be of type INDEX_TYPE, and will range from LOW_BOUND to + HIGH_BOUND, inclusive. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into a range type? */ + +struct type * +create_range_type (result_type, index_type, low_bound, high_bound) + struct type *result_type; + struct type *index_type; + int low_bound; + int high_bound; +{ + if (result_type == NULL) + { + result_type = alloc_type (TYPE_OBJFILE (index_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_RANGE; + TYPE_TARGET_TYPE (result_type) = index_type; + if (TYPE_FLAGS (index_type) & TYPE_FLAG_STUB) + TYPE_FLAGS (result_type) |= TYPE_FLAG_TARGET_STUB; + else + TYPE_LENGTH (result_type) = TYPE_LENGTH (check_typedef (index_type)); + TYPE_NFIELDS (result_type) = 2; + TYPE_FIELDS (result_type) = (struct field *) + TYPE_ALLOC (result_type, 2 * sizeof (struct field)); + memset (TYPE_FIELDS (result_type), 0, 2 * sizeof (struct field)); + TYPE_FIELD_BITPOS (result_type, 0) = low_bound; + TYPE_FIELD_BITPOS (result_type, 1) = high_bound; + TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int; /* FIXME */ + TYPE_FIELD_TYPE (result_type, 1) = builtin_type_int; /* FIXME */ + + return (result_type); +} + +/* Set *LOWP and *HIGHP to the lower and upper bounds of discrete type TYPE. + Return 1 of type is a range type, 0 if it is discrete (and bounds + will fit in LONGEST), or -1 otherwise. */ + +int +get_discrete_bounds (type, lowp, highp) + struct type *type; + LONGEST *lowp, *highp; +{ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_RANGE: + *lowp = TYPE_LOW_BOUND (type); + *highp = TYPE_HIGH_BOUND (type); + return 1; + case TYPE_CODE_ENUM: + if (TYPE_NFIELDS (type) > 0) + { + /* The enums may not be sorted by value, so search all + entries */ + int i; + + *lowp = *highp = TYPE_FIELD_BITPOS (type, 0); + for (i = 0; i < TYPE_NFIELDS (type); i++) + { + if (TYPE_FIELD_BITPOS (type, i) < *lowp) + *lowp = TYPE_FIELD_BITPOS (type, i); + if (TYPE_FIELD_BITPOS (type, i) > *highp) + *highp = TYPE_FIELD_BITPOS (type, i); + } + } + else + { + *lowp = 0; + *highp = -1; + } + return 0; + case TYPE_CODE_BOOL: + *lowp = 0; + *highp = 1; + return 0; + case TYPE_CODE_INT: + if (TYPE_LENGTH (type) > sizeof (LONGEST)) /* Too big */ + return -1; + if (!TYPE_UNSIGNED (type)) + { + *lowp = - (1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1)); + *highp = -*lowp - 1; + return 0; + } + /* ... fall through for unsigned ints ... */ + case TYPE_CODE_CHAR: + *lowp = 0; + /* This round-about calculation is to avoid shifting by + TYPE_LENGTH (type) * TARGET_CHAR_BIT, which will not work + if TYPE_LENGTH (type) == sizeof (LONGEST). */ + *highp = 1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1); + *highp = (*highp - 1) | *highp; + return 0; + default: + return -1; + } +} + +/* Create an array type using either a blank type supplied in RESULT_TYPE, + or creating a new type, inheriting the objfile from RANGE_TYPE. + + Elements will be of type ELEMENT_TYPE, the indices will be of type + RANGE_TYPE. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into an array type? */ + +struct type * +create_array_type (result_type, element_type, range_type) + struct type *result_type; + struct type *element_type; + struct type *range_type; +{ + LONGEST low_bound, high_bound; + + if (result_type == NULL) + { + result_type = alloc_type (TYPE_OBJFILE (range_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (result_type) = element_type; + if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) + low_bound = high_bound = 0; + CHECK_TYPEDEF (element_type); + TYPE_LENGTH (result_type) = + TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); + TYPE_NFIELDS (result_type) = 1; + TYPE_FIELDS (result_type) = + (struct field *) TYPE_ALLOC (result_type, sizeof (struct field)); + memset (TYPE_FIELDS (result_type), 0, sizeof (struct field)); + TYPE_FIELD_TYPE (result_type, 0) = range_type; + TYPE_VPTR_FIELDNO (result_type) = -1; + + return (result_type); +} + +/* Create a string type using either a blank type supplied in RESULT_TYPE, + or creating a new type. String types are similar enough to array of + char types that we can use create_array_type to build the basic type + and then bash it into a string type. + + For fixed length strings, the range type contains 0 as the lower + bound and the length of the string minus one as the upper bound. + + FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make + sure it is TYPE_CODE_UNDEF before we bash it into a string type? */ + +struct type * +create_string_type (result_type, range_type) + struct type *result_type; + struct type *range_type; +{ + result_type = create_array_type (result_type, + *current_language->string_char_type, + range_type); + TYPE_CODE (result_type) = TYPE_CODE_STRING; + return (result_type); +} + +struct type * +create_set_type (result_type, domain_type) + struct type *result_type; + struct type *domain_type; +{ + LONGEST low_bound, high_bound, bit_length; + if (result_type == NULL) + { + result_type = alloc_type (TYPE_OBJFILE (domain_type)); + } + TYPE_CODE (result_type) = TYPE_CODE_SET; + TYPE_NFIELDS (result_type) = 1; + TYPE_FIELDS (result_type) = (struct field *) + TYPE_ALLOC (result_type, 1 * sizeof (struct field)); + memset (TYPE_FIELDS (result_type), 0, sizeof (struct field)); + + if (! (TYPE_FLAGS (domain_type) & TYPE_FLAG_STUB)) + { + if (get_discrete_bounds (domain_type, &low_bound, &high_bound) < 0) + low_bound = high_bound = 0; + bit_length = high_bound - low_bound + 1; + TYPE_LENGTH (result_type) + = (bit_length + TARGET_CHAR_BIT - 1) / TARGET_CHAR_BIT; + } + TYPE_FIELD_TYPE (result_type, 0) = domain_type; + return (result_type); +} + +/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE. + A MEMBER is a wierd thing -- it amounts to a typed offset into + a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't + include the offset (that's the value of the MEMBER itself), but does + include the structure type into which it points (for some reason). + + When "smashing" the type, we preserve the objfile that the + old type pointed to, since we aren't changing where the type is actually + allocated. */ + +void +smash_to_member_type (type, domain, to_type) + struct type *type; + struct type *domain; + struct type *to_type; +{ + struct objfile *objfile; + + objfile = TYPE_OBJFILE (type); + + memset ((char *) type, 0, sizeof (struct type)); + TYPE_OBJFILE (type) = objfile; + TYPE_TARGET_TYPE (type) = to_type; + TYPE_DOMAIN_TYPE (type) = domain; + TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */ + TYPE_CODE (type) = TYPE_CODE_MEMBER; +} + +/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. + METHOD just means `function that gets an extra "this" argument'. + + When "smashing" the type, we preserve the objfile that the + old type pointed to, since we aren't changing where the type is actually + allocated. */ + +void +smash_to_method_type (type, domain, to_type, args) + struct type *type; + struct type *domain; + struct type *to_type; + struct type **args; +{ + struct objfile *objfile; + + objfile = TYPE_OBJFILE (type); + + memset ((char *) type, 0, sizeof (struct type)); + TYPE_OBJFILE (type) = objfile; + TYPE_TARGET_TYPE (type) = to_type; + TYPE_DOMAIN_TYPE (type) = domain; + TYPE_ARG_TYPES (type) = args; + TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */ + TYPE_CODE (type) = TYPE_CODE_METHOD; +} + +/* Return a typename for a struct/union/enum type without "struct ", + "union ", or "enum ". If the type has a NULL name, return NULL. */ + +char * +type_name_no_tag (type) + register const struct type *type; +{ + if (TYPE_TAG_NAME (type) != NULL) + return TYPE_TAG_NAME (type); + + /* Is there code which expects this to return the name if there is no + tag name? My guess is that this is mainly used for C++ in cases where + the two will always be the same. */ + return TYPE_NAME (type); +} + +/* Lookup a primitive type named NAME. + Return zero if NAME is not a primitive type.*/ + +struct type * +lookup_primitive_typename (name) + char *name; +{ + struct type ** const *p; + + for (p = current_language -> la_builtin_type_vector; *p != NULL; p++) + { + if (STREQ ((**p) -> name, name)) + { + return (**p); + } + } + return (NULL); +} + +/* Lookup a typedef or primitive type named NAME, + visible in lexical block BLOCK. + If NOERR is nonzero, return zero if NAME is not suitably defined. */ + +struct type * +lookup_typename (name, block, noerr) + char *name; + struct block *block; + int noerr; +{ + register struct symbol *sym; + register struct type *tmp; + + sym = lookup_symbol (name, block, VAR_NAMESPACE, 0, (struct symtab **) NULL); + if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + { + tmp = lookup_primitive_typename (name); + if (tmp) + { + return (tmp); + } + else if (!tmp && noerr) + { + return (NULL); + } + else + { + error ("No type named %s.", name); + } + } + return (SYMBOL_TYPE (sym)); +} + +struct type * +lookup_unsigned_typename (name) + char *name; +{ + char *uns = alloca (strlen (name) + 10); + + strcpy (uns, "unsigned "); + strcpy (uns + 9, name); + return (lookup_typename (uns, (struct block *) NULL, 0)); +} + +struct type * +lookup_signed_typename (name) + char *name; +{ + struct type *t; + char *uns = alloca (strlen (name) + 8); + + strcpy (uns, "signed "); + strcpy (uns + 7, name); + t = lookup_typename (uns, (struct block *) NULL, 1); + /* If we don't find "signed FOO" just try again with plain "FOO". */ + if (t != NULL) + return t; + return lookup_typename (name, (struct block *) NULL, 0); +} + +/* Lookup a structure type named "struct NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_struct (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + + if (sym == NULL) + { + error ("No struct type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + { + error ("This context has class, union or enum %s, not a struct.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup a union type named "union NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_union (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + + if (sym == NULL) + { + error ("No union type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION) + { + error ("This context has class, struct or enum %s, not a union.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup an enum type named "enum NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_enum (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym; + + sym = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + if (sym == NULL) + { + error ("No enum type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM) + { + error ("This context has class, struct or union %s, not an enum.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Lookup a template type named "template NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_template_type (name, type, block) + char *name; + struct type *type; + struct block *block; +{ + struct symbol *sym; + char *nam = (char*) alloca(strlen(name) + strlen(type->name) + 4); + strcpy (nam, name); + strcat (nam, "<"); + strcat (nam, type->name); + strcat (nam, " >"); /* FIXME, extra space still introduced in gcc? */ + + sym = lookup_symbol (nam, block, VAR_NAMESPACE, 0, (struct symtab **)NULL); + + if (sym == NULL) + { + error ("No template type named %s.", name); + } + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + { + error ("This context has class, union or enum %s, not a struct.", name); + } + return (SYMBOL_TYPE (sym)); +} + +/* Given a type TYPE, lookup the type of the component of type named NAME. + + TYPE can be either a struct or union, or a pointer or reference to a struct or + union. If it is a pointer or reference, its target type is automatically used. + Thus '.' and '->' are interchangable, as specified for the definitions of the + expression element types STRUCTOP_STRUCT and STRUCTOP_PTR. + + If NOERR is nonzero, return zero if NAME is not suitably defined. + If NAME is the name of a baseclass type, return that type. */ + +struct type * +lookup_struct_elt_type (type, name, noerr) + struct type *type; + char *name; + int noerr; +{ + int i; + + for (;;) + { + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) != TYPE_CODE_PTR + && TYPE_CODE (type) != TYPE_CODE_REF) + break; + type = TYPE_TARGET_TYPE (type); + } + + if (TYPE_CODE (type) != TYPE_CODE_STRUCT && + TYPE_CODE (type) != TYPE_CODE_UNION) + { + target_terminal_ours (); + gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stderr, "Type "); + type_print (type, "", gdb_stderr, -1); + error (" is not a structure or union type."); + } + +#if 0 + /* FIXME: This change put in by Michael seems incorrect for the case where + the structure tag name is the same as the member name. I.E. when doing + "ptype bell->bar" for "struct foo { int bar; int foo; } bell;" + Disabled by fnf. */ + { + char *typename; + + typename = type_name_no_tag (type); + if (typename != NULL && STREQ (typename, name)) + return type; + } +#endif + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + return TYPE_FIELD_TYPE (type, i); + } + } + + /* OK, it's not in this class. Recursively check the baseclasses. */ + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + struct type *t; + + t = lookup_struct_elt_type (TYPE_BASECLASS (type, i), name, noerr); + if (t != NULL) + { + return t; + } + } + + if (noerr) + { + return NULL; + } + + target_terminal_ours (); + gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stderr, "Type "); + type_print (type, "", gdb_stderr, -1); + fprintf_unfiltered (gdb_stderr, " has no component named "); + fputs_filtered (name, gdb_stderr); + error ("."); + return (struct type *)-1; /* For lint */ +} + +/* If possible, make the vptr_fieldno and vptr_basetype fields of TYPE + valid. Callers should be aware that in some cases (for example, + the type or one of its baseclasses is a stub type and we are + debugging a .o file), this function will not be able to find the virtual + function table pointer, and vptr_fieldno will remain -1 and vptr_basetype + will remain NULL. */ + +void +fill_in_vptr_fieldno (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + + if (TYPE_VPTR_FIELDNO (type) < 0) + { + int i; + + /* We must start at zero in case the first (and only) baseclass is + virtual (and hence we cannot share the table pointer). */ + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + fill_in_vptr_fieldno (TYPE_BASECLASS (type, i)); + if (TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)) >= 0) + { + TYPE_VPTR_FIELDNO (type) + = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, i)); + TYPE_VPTR_BASETYPE (type) + = TYPE_VPTR_BASETYPE (TYPE_BASECLASS (type, i)); + break; + } + } + } +} + +/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989. + + If this is a stubbed struct (i.e. declared as struct foo *), see if + we can find a full definition in some other file. If so, copy this + definition, so we can use it in future. There used to be a comment (but + not any code) that if we don't find a full definition, we'd set a flag + so we don't spend time in the future checking the same type. That would + be a mistake, though--we might load in more symbols which contain a + full definition for the type. + + This used to be coded as a macro, but I don't think it is called + often enough to merit such treatment. */ + +struct complaint stub_noname_complaint = + {"stub type has NULL name", 0, 0}; + +struct type * +check_typedef (type) + register struct type *type; +{ + struct type *orig_type = type; + while (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + { + if (!TYPE_TARGET_TYPE (type)) + { + char* name; + struct symbol *sym; + + /* It is dangerous to call lookup_symbol if we are currently + reading a symtab. Infinite recursion is one danger. */ + if (currently_reading_symtab) + return type; + + name = type_name_no_tag (type); + /* FIXME: shouldn't we separately check the TYPE_NAME and the + TYPE_TAG_NAME, and look in STRUCT_NAMESPACE and/or VAR_NAMESPACE + as appropriate? (this code was written before TYPE_NAME and + TYPE_TAG_NAME were separate). */ + if (name == NULL) + { + complain (&stub_noname_complaint); + return type; + } + sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + if (sym) + TYPE_TARGET_TYPE (type) = SYMBOL_TYPE (sym); + else + TYPE_TARGET_TYPE (type) = alloc_type (NULL); /* TYPE_CODE_UNDEF */ + } + type = TYPE_TARGET_TYPE (type); + } + + if ((TYPE_FLAGS(type) & TYPE_FLAG_STUB) && ! currently_reading_symtab) + { + char* name = type_name_no_tag (type); + /* FIXME: shouldn't we separately check the TYPE_NAME and the + TYPE_TAG_NAME, and look in STRUCT_NAMESPACE and/or VAR_NAMESPACE + as appropriate? (this code was written before TYPE_NAME and + TYPE_TAG_NAME were separate). */ + struct symbol *sym; + if (name == NULL) + { + complain (&stub_noname_complaint); + return type; + } + sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0, + (struct symtab **) NULL); + if (sym) + { + memcpy ((char *)type, + (char *)SYMBOL_TYPE(sym), + sizeof (struct type)); + } + } + + if (TYPE_FLAGS (type) & TYPE_FLAG_TARGET_STUB) + { + struct type *range_type; + struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); + + if (TYPE_FLAGS (target_type) & TYPE_FLAG_STUB) + { } + else if (TYPE_CODE (type) == TYPE_CODE_ARRAY + && TYPE_NFIELDS (type) == 1 + && (TYPE_CODE (range_type = TYPE_FIELD_TYPE (type, 0)) + == TYPE_CODE_RANGE)) + { + /* Now recompute the length of the array type, based on its + number of elements and the target type's length. */ + TYPE_LENGTH (type) = + ((TYPE_FIELD_BITPOS (range_type, 1) + - TYPE_FIELD_BITPOS (range_type, 0) + + 1) + * TYPE_LENGTH (target_type)); + TYPE_FLAGS (type) &= ~TYPE_FLAG_TARGET_STUB; + } + else if (TYPE_CODE (type) == TYPE_CODE_RANGE) + { + TYPE_LENGTH (type) = TYPE_LENGTH (target_type); + TYPE_FLAGS (type) &= ~TYPE_FLAG_TARGET_STUB; + } + } + /* Cache TYPE_LENGTH for future use. */ + TYPE_LENGTH (orig_type) = TYPE_LENGTH (type); + return type; +} + +/* Ugly hack to convert method stubs into method types. + + He ain't kiddin'. This demangles the name of the method into a string + including argument types, parses out each argument type, generates + a string casting a zero to that type, evaluates the string, and stuffs + the resulting type into an argtype vector!!! Then it knows the type + of the whole function (including argument types for overloading), + which info used to be in the stab's but was removed to hack back + the space required for them. */ + +void +check_stub_method (type, i, j) + struct type *type; + int i; + int j; +{ + struct fn_field *f; + char *mangled_name = gdb_mangle_name (type, i, j); + char *demangled_name = cplus_demangle (mangled_name, + DMGL_PARAMS | DMGL_ANSI); + char *argtypetext, *p; + int depth = 0, argcount = 1; + struct type **argtypes; + struct type *mtype; + + /* Make sure we got back a function string that we can use. */ + if (demangled_name) + p = strchr (demangled_name, '('); + + if (demangled_name == NULL || p == NULL) + error ("Internal: Cannot demangle mangled name `%s'.", mangled_name); + + /* Now, read in the parameters that define this type. */ + p += 1; + argtypetext = p; + while (*p) + { + if (*p == '(') + { + depth += 1; + } + else if (*p == ')') + { + depth -= 1; + } + else if (*p == ',' && depth == 0) + { + argcount += 1; + } + + p += 1; + } + + /* We need two more slots: one for the THIS pointer, and one for the + NULL [...] or void [end of arglist]. */ + + argtypes = (struct type **) + TYPE_ALLOC (type, (argcount + 2) * sizeof (struct type *)); + p = argtypetext; + /* FIXME: This is wrong for static member functions. */ + argtypes[0] = lookup_pointer_type (type); + argcount = 1; + + if (*p != ')') /* () means no args, skip while */ + { + depth = 0; + while (*p) + { + if (depth <= 0 && (*p == ',' || *p == ')')) + { + /* Avoid parsing of ellipsis, they will be handled below. */ + if (strncmp (argtypetext, "...", p - argtypetext) != 0) + { + argtypes[argcount] = + parse_and_eval_type (argtypetext, p - argtypetext); + argcount += 1; + } + argtypetext = p + 1; + } + + if (*p == '(') + { + depth += 1; + } + else if (*p == ')') + { + depth -= 1; + } + + p += 1; + } + } + + if (p[-2] != '.') /* Not '...' */ + { + argtypes[argcount] = builtin_type_void; /* List terminator */ + } + else + { + argtypes[argcount] = NULL; /* Ellist terminator */ + } + + free (demangled_name); + + f = TYPE_FN_FIELDLIST1 (type, i); + TYPE_FN_FIELD_PHYSNAME (f, j) = mangled_name; + + /* Now update the old "stub" type into a real type. */ + mtype = TYPE_FN_FIELD_TYPE (f, j); + TYPE_DOMAIN_TYPE (mtype) = type; + TYPE_ARG_TYPES (mtype) = argtypes; + TYPE_FLAGS (mtype) &= ~TYPE_FLAG_STUB; + TYPE_FN_FIELD_STUB (f, j) = 0; +} + +const struct cplus_struct_type cplus_struct_default; + +void +allocate_cplus_struct_type (type) + struct type *type; +{ + if (!HAVE_CPLUS_STRUCT (type)) + { + TYPE_CPLUS_SPECIFIC (type) = (struct cplus_struct_type *) + TYPE_ALLOC (type, sizeof (struct cplus_struct_type)); + *(TYPE_CPLUS_SPECIFIC(type)) = cplus_struct_default; + } +} + +/* Helper function to initialize the standard scalar types. + + If NAME is non-NULL and OBJFILE is non-NULL, then we make a copy + of the string pointed to by name in the type_obstack for that objfile, + and initialize the type name to that copy. There are places (mipsread.c + in particular, where init_type is called with a NULL value for NAME). */ + +struct type * +init_type (code, length, flags, name, objfile) + enum type_code code; + int length; + int flags; + char *name; + struct objfile *objfile; +{ + register struct type *type; + + type = alloc_type (objfile); + TYPE_CODE (type) = code; + TYPE_LENGTH (type) = length; + TYPE_FLAGS (type) |= flags; + if ((name != NULL) && (objfile != NULL)) + { + TYPE_NAME (type) = + obsavestring (name, strlen (name), &objfile -> type_obstack); + } + else + { + TYPE_NAME (type) = name; + } + + /* C++ fancies. */ + + if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) + { + INIT_CPLUS_SPECIFIC (type); + } + return (type); +} + +/* Look up a fundamental type for the specified objfile. + May need to construct such a type if this is the first use. + + Some object file formats (ELF, COFF, etc) do not define fundamental + types such as "int" or "double". Others (stabs for example), do + define fundamental types. + + For the formats which don't provide fundamental types, gdb can create + such types, using defaults reasonable for the current language and + the current target machine. + + NOTE: This routine is obsolescent. Each debugging format reader + should manage it's own fundamental types, either creating them from + suitable defaults or reading them from the debugging information, + whichever is appropriate. The DWARF reader has already been + fixed to do this. Once the other readers are fixed, this routine + will go away. Also note that fundamental types should be managed + on a compilation unit basis in a multi-language environment, not + on a linkage unit basis as is done here. */ + + +struct type * +lookup_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type **typep; + register int nbytes; + + if (typeid < 0 || typeid >= FT_NUM_MEMBERS) + { + error ("internal error - invalid fundamental type id %d", typeid); + } + + /* If this is the first time we need a fundamental type for this objfile + then we need to initialize the vector of type pointers. */ + + if (objfile -> fundamental_types == NULL) + { + nbytes = FT_NUM_MEMBERS * sizeof (struct type *); + objfile -> fundamental_types = (struct type **) + obstack_alloc (&objfile -> type_obstack, nbytes); + memset ((char *) objfile -> fundamental_types, 0, nbytes); + OBJSTAT (objfile, n_types += FT_NUM_MEMBERS); + } + + /* Look for this particular type in the fundamental type vector. If one is + not found, create and install one appropriate for the current language. */ + + typep = objfile -> fundamental_types + typeid; + if (*typep == NULL) + { + *typep = create_fundamental_type (objfile, typeid); + } + + return (*typep); +} + +int +can_dereference (t) + struct type *t; +{ + /* FIXME: Should we return true for references as well as pointers? */ + CHECK_TYPEDEF (t); + return + (t != NULL + && TYPE_CODE (t) == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (t)) != TYPE_CODE_VOID); +} + +/* Chill varying string and arrays are represented as follows: + + struct { int __var_length; ELEMENT_TYPE[MAX_SIZE] __var_data}; + + Return true if TYPE is such a Chill varying type. */ + +int +chill_varying_type (type) + struct type *type; +{ + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + || TYPE_NFIELDS (type) != 2 + || strcmp (TYPE_FIELD_NAME (type, 0), "__var_length") != 0) + return 0; + return 1; +} + +#if MAINTENANCE_CMDS + +static void +print_bit_vector (bits, nbits) + B_TYPE *bits; + int nbits; +{ + int bitno; + + for (bitno = 0; bitno < nbits; bitno++) + { + if ((bitno % 8) == 0) + { + puts_filtered (" "); + } + if (B_TST (bits, bitno)) + { + printf_filtered ("1"); + } + else + { + printf_filtered ("0"); + } + } +} + +/* The args list is a strange beast. It is either terminated by a NULL + pointer for varargs functions, or by a pointer to a TYPE_CODE_VOID + type for normal fixed argcount functions. (FIXME someday) + Also note the first arg should be the "this" pointer, we may not want to + include it since we may get into a infinitely recursive situation. */ + +static void +print_arg_types (args, spaces) + struct type **args; + int spaces; +{ + if (args != NULL) + { + while (*args != NULL) + { + recursive_dump_type (*args, spaces + 2); + if ((*args++) -> code == TYPE_CODE_VOID) + { + break; + } + } + } +} + +static void +dump_fn_fieldlists (type, spaces) + struct type *type; + int spaces; +{ + int method_idx; + int overload_idx; + struct fn_field *f; + + printfi_filtered (spaces, "fn_fieldlists "); + gdb_print_address (TYPE_FN_FIELDLISTS (type), gdb_stdout); + printf_filtered ("\n"); + for (method_idx = 0; method_idx < TYPE_NFN_FIELDS (type); method_idx++) + { + f = TYPE_FN_FIELDLIST1 (type, method_idx); + printfi_filtered (spaces + 2, "[%d] name '%s' (", + method_idx, + TYPE_FN_FIELDLIST_NAME (type, method_idx)); + gdb_print_address (TYPE_FN_FIELDLIST_NAME (type, method_idx), + gdb_stdout); + printf_filtered (") length %d\n", + TYPE_FN_FIELDLIST_LENGTH (type, method_idx)); + for (overload_idx = 0; + overload_idx < TYPE_FN_FIELDLIST_LENGTH (type, method_idx); + overload_idx++) + { + printfi_filtered (spaces + 4, "[%d] physname '%s' (", + overload_idx, + TYPE_FN_FIELD_PHYSNAME (f, overload_idx)); + gdb_print_address (TYPE_FN_FIELD_PHYSNAME (f, overload_idx), + gdb_stdout); + printf_filtered (")\n"); + printfi_filtered (spaces + 8, "type "); + gdb_print_address (TYPE_FN_FIELD_TYPE (f, overload_idx), gdb_stdout); + printf_filtered ("\n"); + + recursive_dump_type (TYPE_FN_FIELD_TYPE (f, overload_idx), + spaces + 8 + 2); + + printfi_filtered (spaces + 8, "args "); + gdb_print_address (TYPE_FN_FIELD_ARGS (f, overload_idx), gdb_stdout); + printf_filtered ("\n"); + + print_arg_types (TYPE_FN_FIELD_ARGS (f, overload_idx), spaces); + printfi_filtered (spaces + 8, "fcontext "); + gdb_print_address (TYPE_FN_FIELD_FCONTEXT (f, overload_idx), + gdb_stdout); + printf_filtered ("\n"); + + printfi_filtered (spaces + 8, "is_const %d\n", + TYPE_FN_FIELD_CONST (f, overload_idx)); + printfi_filtered (spaces + 8, "is_volatile %d\n", + TYPE_FN_FIELD_VOLATILE (f, overload_idx)); + printfi_filtered (spaces + 8, "is_private %d\n", + TYPE_FN_FIELD_PRIVATE (f, overload_idx)); + printfi_filtered (spaces + 8, "is_protected %d\n", + TYPE_FN_FIELD_PROTECTED (f, overload_idx)); + printfi_filtered (spaces + 8, "is_stub %d\n", + TYPE_FN_FIELD_STUB (f, overload_idx)); + printfi_filtered (spaces + 8, "voffset %u\n", + TYPE_FN_FIELD_VOFFSET (f, overload_idx)); + } + } +} + +static void +print_cplus_stuff (type, spaces) + struct type *type; + int spaces; +{ + printfi_filtered (spaces, "n_baseclasses %d\n", + TYPE_N_BASECLASSES (type)); + printfi_filtered (spaces, "nfn_fields %d\n", + TYPE_NFN_FIELDS (type)); + printfi_filtered (spaces, "nfn_fields_total %d\n", + TYPE_NFN_FIELDS_TOTAL (type)); + if (TYPE_N_BASECLASSES (type) > 0) + { + printfi_filtered (spaces, "virtual_field_bits (%d bits at *", + TYPE_N_BASECLASSES (type)); + gdb_print_address (TYPE_FIELD_VIRTUAL_BITS (type), gdb_stdout); + printf_filtered (")"); + + print_bit_vector (TYPE_FIELD_VIRTUAL_BITS (type), + TYPE_N_BASECLASSES (type)); + puts_filtered ("\n"); + } + if (TYPE_NFIELDS (type) > 0) + { + if (TYPE_FIELD_PRIVATE_BITS (type) != NULL) + { + printfi_filtered (spaces, "private_field_bits (%d bits at *", + TYPE_NFIELDS (type)); + gdb_print_address (TYPE_FIELD_PRIVATE_BITS (type), gdb_stdout); + printf_filtered (")"); + print_bit_vector (TYPE_FIELD_PRIVATE_BITS (type), + TYPE_NFIELDS (type)); + puts_filtered ("\n"); + } + if (TYPE_FIELD_PROTECTED_BITS (type) != NULL) + { + printfi_filtered (spaces, "protected_field_bits (%d bits at *", + TYPE_NFIELDS (type)); + gdb_print_address (TYPE_FIELD_PROTECTED_BITS (type), gdb_stdout); + printf_filtered (")"); + print_bit_vector (TYPE_FIELD_PROTECTED_BITS (type), + TYPE_NFIELDS (type)); + puts_filtered ("\n"); + } + } + if (TYPE_NFN_FIELDS (type) > 0) + { + dump_fn_fieldlists (type, spaces); + } +} + +static struct obstack dont_print_type_obstack; + +void +recursive_dump_type (type, spaces) + struct type *type; + int spaces; +{ + int idx; + + if (spaces == 0) + obstack_begin (&dont_print_type_obstack, 0); + + if (TYPE_NFIELDS (type) > 0 + || (TYPE_CPLUS_SPECIFIC (type) && TYPE_NFN_FIELDS (type) > 0)) + { + struct type **first_dont_print + = (struct type **)obstack_base (&dont_print_type_obstack); + + int i = (struct type **)obstack_next_free (&dont_print_type_obstack) + - first_dont_print; + + while (--i >= 0) + { + if (type == first_dont_print[i]) + { + printfi_filtered (spaces, "type node "); + gdb_print_address (type, gdb_stdout); + printf_filtered (" \n"); + return; + } + } + + obstack_ptr_grow (&dont_print_type_obstack, type); + } + + printfi_filtered (spaces, "type node "); + gdb_print_address (type, gdb_stdout); + printf_filtered ("\n"); + printfi_filtered (spaces, "name '%s' (", + TYPE_NAME (type) ? TYPE_NAME (type) : ""); + gdb_print_address (TYPE_NAME (type), gdb_stdout); + printf_filtered (")\n"); + if (TYPE_TAG_NAME (type) != NULL) + { + printfi_filtered (spaces, "tagname '%s' (", + TYPE_TAG_NAME (type)); + gdb_print_address (TYPE_TAG_NAME (type), gdb_stdout); + printf_filtered (")\n"); + } + printfi_filtered (spaces, "code 0x%x ", TYPE_CODE (type)); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_UNDEF: + printf_filtered ("(TYPE_CODE_UNDEF)"); + break; + case TYPE_CODE_PTR: + printf_filtered ("(TYPE_CODE_PTR)"); + break; + case TYPE_CODE_ARRAY: + printf_filtered ("(TYPE_CODE_ARRAY)"); + break; + case TYPE_CODE_STRUCT: + printf_filtered ("(TYPE_CODE_STRUCT)"); + break; + case TYPE_CODE_UNION: + printf_filtered ("(TYPE_CODE_UNION)"); + break; + case TYPE_CODE_ENUM: + printf_filtered ("(TYPE_CODE_ENUM)"); + break; + case TYPE_CODE_FUNC: + printf_filtered ("(TYPE_CODE_FUNC)"); + break; + case TYPE_CODE_INT: + printf_filtered ("(TYPE_CODE_INT)"); + break; + case TYPE_CODE_FLT: + printf_filtered ("(TYPE_CODE_FLT)"); + break; + case TYPE_CODE_VOID: + printf_filtered ("(TYPE_CODE_VOID)"); + break; + case TYPE_CODE_SET: + printf_filtered ("(TYPE_CODE_SET)"); + break; + case TYPE_CODE_RANGE: + printf_filtered ("(TYPE_CODE_RANGE)"); + break; + case TYPE_CODE_STRING: + printf_filtered ("(TYPE_CODE_STRING)"); + break; + case TYPE_CODE_ERROR: + printf_filtered ("(TYPE_CODE_ERROR)"); + break; + case TYPE_CODE_MEMBER: + printf_filtered ("(TYPE_CODE_MEMBER)"); + break; + case TYPE_CODE_METHOD: + printf_filtered ("(TYPE_CODE_METHOD)"); + break; + case TYPE_CODE_REF: + printf_filtered ("(TYPE_CODE_REF)"); + break; + case TYPE_CODE_CHAR: + printf_filtered ("(TYPE_CODE_CHAR)"); + break; + case TYPE_CODE_BOOL: + printf_filtered ("(TYPE_CODE_BOOL)"); + break; + case TYPE_CODE_TYPEDEF: + printf_filtered ("(TYPE_CODE_TYPEDEF)"); + break; + default: + printf_filtered ("(UNKNOWN TYPE CODE)"); + break; + } + puts_filtered ("\n"); + printfi_filtered (spaces, "length %d\n", TYPE_LENGTH (type)); + printfi_filtered (spaces, "objfile "); + gdb_print_address (TYPE_OBJFILE (type), gdb_stdout); + printf_filtered ("\n"); + printfi_filtered (spaces, "target_type "); + gdb_print_address (TYPE_TARGET_TYPE (type), gdb_stdout); + printf_filtered ("\n"); + if (TYPE_TARGET_TYPE (type) != NULL) + { + recursive_dump_type (TYPE_TARGET_TYPE (type), spaces + 2); + } + printfi_filtered (spaces, "pointer_type "); + gdb_print_address (TYPE_POINTER_TYPE (type), gdb_stdout); + printf_filtered ("\n"); + printfi_filtered (spaces, "reference_type "); + gdb_print_address (TYPE_REFERENCE_TYPE (type), gdb_stdout); + printf_filtered ("\n"); + printfi_filtered (spaces, "flags 0x%x", TYPE_FLAGS (type)); + if (TYPE_FLAGS (type) & TYPE_FLAG_UNSIGNED) + { + puts_filtered (" TYPE_FLAG_UNSIGNED"); + } + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + puts_filtered (" TYPE_FLAG_STUB"); + } + puts_filtered ("\n"); + printfi_filtered (spaces, "nfields %d ", TYPE_NFIELDS (type)); + gdb_print_address (TYPE_FIELDS (type), gdb_stdout); + puts_filtered ("\n"); + for (idx = 0; idx < TYPE_NFIELDS (type); idx++) + { + printfi_filtered (spaces + 2, + "[%d] bitpos %d bitsize %d type ", + idx, TYPE_FIELD_BITPOS (type, idx), + TYPE_FIELD_BITSIZE (type, idx)); + gdb_print_address (TYPE_FIELD_TYPE (type, idx), gdb_stdout); + printf_filtered (" name '%s' (", + TYPE_FIELD_NAME (type, idx) != NULL + ? TYPE_FIELD_NAME (type, idx) + : ""); + gdb_print_address (TYPE_FIELD_NAME (type, idx), gdb_stdout); + printf_filtered (")\n"); + if (TYPE_FIELD_TYPE (type, idx) != NULL) + { + recursive_dump_type (TYPE_FIELD_TYPE (type, idx), spaces + 4); + } + } + printfi_filtered (spaces, "vptr_basetype "); + gdb_print_address (TYPE_VPTR_BASETYPE (type), gdb_stdout); + puts_filtered ("\n"); + if (TYPE_VPTR_BASETYPE (type) != NULL) + { + recursive_dump_type (TYPE_VPTR_BASETYPE (type), spaces + 2); + } + printfi_filtered (spaces, "vptr_fieldno %d\n", TYPE_VPTR_FIELDNO (type)); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_METHOD: + case TYPE_CODE_FUNC: + printfi_filtered (spaces, "arg_types "); + gdb_print_address (TYPE_ARG_TYPES (type), gdb_stdout); + puts_filtered ("\n"); + print_arg_types (TYPE_ARG_TYPES (type), spaces); + break; + + case TYPE_CODE_STRUCT: + printfi_filtered (spaces, "cplus_stuff "); + gdb_print_address (TYPE_CPLUS_SPECIFIC (type), gdb_stdout); + puts_filtered ("\n"); + print_cplus_stuff (type, spaces); + break; + + default: + /* We have to pick one of the union types to be able print and test + the value. Pick cplus_struct_type, even though we know it isn't + any particular one. */ + printfi_filtered (spaces, "type_specific "); + gdb_print_address (TYPE_CPLUS_SPECIFIC (type), gdb_stdout); + if (TYPE_CPLUS_SPECIFIC (type) != NULL) + { + printf_filtered (" (unknown data form)"); + } + printf_filtered ("\n"); + break; + + } + if (spaces == 0) + obstack_free (&dont_print_type_obstack, NULL); +} + +#endif /* MAINTENANCE_CMDS */ + +void +_initialize_gdbtypes () +{ + builtin_type_void = + init_type (TYPE_CODE_VOID, 1, + 0, + "void", (struct objfile *) NULL); + builtin_type_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "char", (struct objfile *) NULL); + builtin_type_signed_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "signed char", (struct objfile *) NULL); + builtin_type_unsigned_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned char", (struct objfile *) NULL); + builtin_type_short = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, + "short", (struct objfile *) NULL); + builtin_type_unsigned_short = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned short", (struct objfile *) NULL); + builtin_type_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "int", (struct objfile *) NULL); + builtin_type_unsigned_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned int", (struct objfile *) NULL); + builtin_type_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long", (struct objfile *) NULL); + builtin_type_unsigned_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned long", (struct objfile *) NULL); + builtin_type_long_long = + init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long long", (struct objfile *) NULL); + builtin_type_unsigned_long_long = + init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "unsigned long long", (struct objfile *) NULL); + builtin_type_float = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "float", (struct objfile *) NULL); + builtin_type_double = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "double", (struct objfile *) NULL); + builtin_type_long_double = + init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "long double", (struct objfile *) NULL); + builtin_type_complex = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "complex", (struct objfile *) NULL); + TYPE_TARGET_TYPE (builtin_type_complex) = builtin_type_float; + builtin_type_double_complex = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "double complex", (struct objfile *) NULL); + TYPE_TARGET_TYPE (builtin_type_double_complex) = builtin_type_double; + builtin_type_string = + init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "string", (struct objfile *) NULL); +} diff --git a/contrib/gdb/gdb/gdbtypes.h b/contrib/gdb/gdb/gdbtypes.h new file mode 100644 index 000000000000..59313d799fd4 --- /dev/null +++ b/contrib/gdb/gdb/gdbtypes.h @@ -0,0 +1,789 @@ +/* Internal type definitions for GDB. + Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (GDBTYPES_H) +#define GDBTYPES_H 1 + +/* Codes for `fundamental types'. This is a monstrosity based on the + bogus notion that there are certain compiler-independent + `fundamental types'. None of these is well-defined (how big is + FT_SHORT? Does it depend on the language? How does the + language-specific code know which type to correlate to FT_SHORT?) */ + +#define FT_VOID 0 +#define FT_BOOLEAN 1 +#define FT_CHAR 2 +#define FT_SIGNED_CHAR 3 +#define FT_UNSIGNED_CHAR 4 +#define FT_SHORT 5 +#define FT_SIGNED_SHORT 6 +#define FT_UNSIGNED_SHORT 7 +#define FT_INTEGER 8 +#define FT_SIGNED_INTEGER 9 +#define FT_UNSIGNED_INTEGER 10 +#define FT_LONG 11 +#define FT_SIGNED_LONG 12 +#define FT_UNSIGNED_LONG 13 +#define FT_LONG_LONG 14 +#define FT_SIGNED_LONG_LONG 15 +#define FT_UNSIGNED_LONG_LONG 16 +#define FT_FLOAT 17 +#define FT_DBL_PREC_FLOAT 18 +#define FT_EXT_PREC_FLOAT 19 +#define FT_COMPLEX 20 +#define FT_DBL_PREC_COMPLEX 21 +#define FT_EXT_PREC_COMPLEX 22 +#define FT_STRING 23 +#define FT_FIXED_DECIMAL 24 +#define FT_FLOAT_DECIMAL 25 +#define FT_BYTE 26 +#define FT_UNSIGNED_BYTE 27 + +#define FT_NUM_MEMBERS 28 /* Highest FT_* above, plus one. */ + +/* Some macros for char-based bitfields. */ + +#define B_SET(a,x) ((a)[(x)>>3] |= (1 << ((x)&7))) +#define B_CLR(a,x) ((a)[(x)>>3] &= ~(1 << ((x)&7))) +#define B_TST(a,x) ((a)[(x)>>3] & (1 << ((x)&7))) +#define B_TYPE unsigned char +#define B_BYTES(x) ( 1 + ((x)>>3) ) +#define B_CLRALL(a,x) memset ((a), 0, B_BYTES(x)) + +/* Different kinds of data types are distinguished by the `code' field. */ + +enum type_code +{ + TYPE_CODE_UNDEF, /* Not used; catches errors */ + TYPE_CODE_PTR, /* Pointer type */ + TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */ + TYPE_CODE_STRUCT, /* C struct or Pascal record */ + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ + TYPE_CODE_FUNC, /* Function type */ + TYPE_CODE_INT, /* Integer type */ + + /* Floating type. This is *NOT* a complex type. Beware, there are parts + of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */ + TYPE_CODE_FLT, + + /* Void type. The length field specifies the length (probably always + one) which is used in pointer arithmetic involving pointers to + this type, but actually dereferencing such a pointer is invalid; + a void type has no length and no actual representation in memory + or registers. A pointer to a void type is a generic pointer. */ + TYPE_CODE_VOID, + + TYPE_CODE_SET, /* Pascal sets */ + TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ + + /* A string type which is like an array of character but prints + differently (at least for CHILL). It does not contain a length + field as Pascal strings (for many Pascals, anyway) do; if we want + to deal with such strings, we should use a new type code. */ + TYPE_CODE_STRING, + + /* String of bits; like TYPE_CODE_SET but prints differently (at least + for CHILL). */ + TYPE_CODE_BITSTRING, + + /* Unknown type. The length field is valid if we were able to + deduce that much about the type, or 0 if we don't even know that. */ + TYPE_CODE_ERROR, + + /* C++ */ + TYPE_CODE_MEMBER, /* Member type */ + TYPE_CODE_METHOD, /* Method type */ + TYPE_CODE_REF, /* C++ Reference types */ + + TYPE_CODE_CHAR, /* *real* character type */ + + /* Boolean type. 0 is false, 1 is true, and other values are non-boolean + (e.g. FORTRAN "logical" used as unsigned int). */ + TYPE_CODE_BOOL, + + /* Fortran */ + TYPE_CODE_COMPLEX, /* Complex float */ + + TYPE_CODE_TYPEDEF +}; + +/* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an + alias for TYPE_CODE_STRUCT. This is for DWARF, which has a distinct + "class" attribute. Perhaps we should actually have a separate TYPE_CODE + so that we can print "class" or "struct" depending on what the debug + info said. It's not clear we should bother. */ + +#define TYPE_CODE_CLASS TYPE_CODE_STRUCT + +/* Some bits for the type's flags word. */ + +/* Unsigned integer type. If this is not set for a TYPE_CODE_INT, the + type is signed. */ + +#define TYPE_FLAG_UNSIGNED (1 << 0) + +/* This appears in a type's flags word if it is a stub type (e.g., if + someone referenced a type that wasn't defined in a source file + via (struct sir_not_appearing_in_this_film *)). */ + +#define TYPE_FLAG_STUB (1 << 2) + +/* The target type of this type is a stub type, and this type needs to + be updated if it gets un-stubbed in check_typedef. + Used for arrays and ranges, in which TYPE_LENGTH of the array/range + gets set based on the TYPE_LENGTH of the target type. + Also, set for TYPE_CODE_TYPEDEF. */ + +#define TYPE_FLAG_TARGET_STUB (1 << 3) + +struct type +{ + + /* Code for kind of type */ + + enum type_code code; + + /* Name of this type, or NULL if none. + + This is used for printing only, except by poorly designed C++ code. + For looking up a name, look for a symbol in the VAR_NAMESPACE. */ + + char *name; + + /* Tag name for this type, or NULL if none. This means that the + name of the type consists of a keyword followed by the tag name. + Which keyword is determined by the type code ("struct" for + TYPE_CODE_STRUCT, etc.). As far as I know C/C++ are the only languages + with this feature. + + This is used for printing only, except by poorly designed C++ code. + For looking up a name, look for a symbol in the STRUCT_NAMESPACE. + One more legitimate use is that if TYPE_FLAG_STUB is set, this is + the name to use to look for definitions in other files. */ + + char *tag_name; + + /* Length of storage for a value of this type. Various places pass + this to memcpy and such, meaning it must be in units of + HOST_CHAR_BIT. Various other places expect they can calculate + addresses by adding it and such, meaning it must be in units of + TARGET_CHAR_BIT. For some DSP targets, in which HOST_CHAR_BIT + will (presumably) be 8 and TARGET_CHAR_BIT will be (say) 32, this + is a problem. One fix would be to make this field in bits + (requiring that it always be a multiple of HOST_CHAR_BIT and + TARGET_CHAR_BIT)--the other choice would be to make it + consistently in units of HOST_CHAR_BIT. */ + + unsigned length; + + /* FIXME, these should probably be restricted to a Fortran-specific + field in some fashion. */ +#define BOUND_CANNOT_BE_DETERMINED 5 +#define BOUND_BY_REF_ON_STACK 4 +#define BOUND_BY_VALUE_ON_STACK 3 +#define BOUND_BY_REF_IN_REG 2 +#define BOUND_BY_VALUE_IN_REG 1 +#define BOUND_SIMPLE 0 + int upper_bound_type; + int lower_bound_type; + + /* Every type is now associated with a particular objfile, and the + type is allocated on the type_obstack for that objfile. One problem + however, is that there are times when gdb allocates new types while + it is not in the process of reading symbols from a particular objfile. + Fortunately, these happen when the type being created is a derived + type of an existing type, such as in lookup_pointer_type(). So + we can just allocate the new type using the same objfile as the + existing type, but to do this we need a backpointer to the objfile + from the existing type. Yes this is somewhat ugly, but without + major overhaul of the internal type system, it can't be avoided + for now. */ + + struct objfile *objfile; + + /* For a pointer type, describes the type of object pointed to. + For an array type, describes the type of the elements. + For a function or method type, describes the type of the return value. + For a range type, describes the type of the full range. + For a complex type, describes the type of each coordinate. + Unused otherwise. */ + + struct type *target_type; + + /* Type that is a pointer to this type. + NULL if no such pointer-to type is known yet. + The debugger may add the address of such a type + if it has to construct one later. */ + + struct type *pointer_type; + + /* C++: also need a reference type. */ + + struct type *reference_type; + + /* Flags about this type. */ + + short flags; + + /* Number of fields described for this type */ + + short nfields; + + /* For structure and union types, a description of each field. + For set and pascal array types, there is one "field", + whose type is the domain type of the set or array. + For range types, there are two "fields", + the minimum and maximum values (both inclusive). + For enum types, each possible value is described by one "field". + For a function type, a "field" for each parameter type. + For C++ classes, there is one field for each base class (if it is + a derived class) plus one field for each class data member. Member + functions are recorded elsewhere. + + Using a pointer to a separate array of fields + allows all types to have the same size, which is useful + because we can allocate the space for a type before + we know what to put in it. */ + + struct field + { + + /* Position of this field, counting in bits from start of + containing structure. For a function type, this is the + position in the argument list of this argument. + For a range bound or enum value, this is the value itself. + (FIXME: What about ranges larger than host int size?) + For BITS_BIG_ENDIAN=1 targets, it is the bit offset to the MSB. + For BITS_BIG_ENDIAN=0 targets, it is the bit offset to the LSB. */ + + int bitpos; + + /* Size of this field, in bits, or zero if not packed. + For an unpacked field, the field's type's length + says how many bytes the field occupies. */ + /* FIXME: This is abused by TYPE_FIELD_STATIC_PHYSNAME to contain + a pointer, so it has to be long. */ + + long bitsize; + + /* In a struct or enum type, type of this field. + In a function type, type of this argument. + In an array type, the domain-type of the array. */ + + struct type *type; + + /* Name of field, value or argument. + NULL for range bounds and array domains. */ + + char *name; + + } *fields; + + /* For types with virtual functions, VPTR_BASETYPE is the base class which + defined the virtual function table pointer. + + For types that are pointer to member types, VPTR_BASETYPE + is the type that this pointer is a member of. + + Unused otherwise. */ + + struct type *vptr_basetype; + + /* Field number of the virtual function table pointer in + VPTR_BASETYPE. If -1, we were unable to find the virtual + function table pointer in initial symbol reading, and + fill_in_vptr_fieldno should be called to find it if possible. + + Unused if this type does not have virtual functions. */ + + int vptr_fieldno; + + /* Slot to point to additional language-specific fields of this type. */ + + union type_specific + { + + /* ARG_TYPES is for TYPE_CODE_METHOD and TYPE_CODE_FUNC. */ + + struct type **arg_types; + + /* CPLUS_STUFF is for TYPE_CODE_STRUCT. It is initialized to point to + cplus_struct_default, a default static instance of a struct + cplus_struct_type. */ + + struct cplus_struct_type *cplus_stuff; + + } type_specific; +}; + +#define NULL_TYPE ((struct type *) 0) + +/* C++ language-specific information for TYPE_CODE_STRUCT and TYPE_CODE_UNION + nodes. */ + +struct cplus_struct_type +{ + /* Number of base classes this type derives from. The baseclasses are + stored in the first N_BASECLASSES fields (i.e. the `fields' field of + the struct type). I think only the `type' field of such a field has + any meaning. */ + + short n_baseclasses; + + /* Number of methods with unique names. All overloaded methods with + the same name count only once. */ + + short nfn_fields; + + /* Number of methods described for this type, not including the + methods that it derives from. */ + + int nfn_fields_total; + + /* For derived classes, the number of base classes is given by n_baseclasses + and virtual_field_bits is a bit vector containing one bit per base class. + If the base class is virtual, the corresponding bit will be set. + I.E, given: + + class A{}; + class B{}; + class C : public B, public virtual A {}; + + B is a baseclass of C; A is a virtual baseclass for C. + This is a C++ 2.0 language feature. */ + + B_TYPE *virtual_field_bits; + + /* For classes with private fields, the number of fields is given by + nfields and private_field_bits is a bit vector containing one bit + per field. + If the field is private, the corresponding bit will be set. */ + + B_TYPE *private_field_bits; + + /* For classes with protected fields, the number of fields is given by + nfields and protected_field_bits is a bit vector containing one bit + per field. + If the field is private, the corresponding bit will be set. */ + + B_TYPE *protected_field_bits; + + /* for classes with fields to be ignored, either this is optimized out + or this field has length 0 */ + + B_TYPE *ignore_field_bits; + + /* For classes, structures, and unions, a description of each field, + which consists of an overloaded name, followed by the types of + arguments that the method expects, and then the name after it + has been renamed to make it distinct. + + fn_fieldlists points to an array of nfn_fields of these. */ + + struct fn_fieldlist + { + + /* The overloaded name. */ + + char *name; + + /* The number of methods with this name. */ + + int length; + + /* The list of methods. */ + + struct fn_field + { + + /* If is_stub is clear, this is the mangled name which we can + look up to find the address of the method (FIXME: it would + be cleaner to have a pointer to the struct symbol here + instead). */ + + /* If is_stub is set, this is the portion of the mangled + name which specifies the arguments. For example, "ii", + if there are two int arguments, or "" if there are no + arguments. See gdb_mangle_name for the conversion from this + format to the one used if is_stub is clear. */ + + char *physname; + + /* The return value of the method */ + + struct type *type; + + /* The argument list. Only valid if is_stub is clear. Contains + the type of each argument, including `this', and ending with + a NULL pointer after the last argument. Should not contain + a `this' pointer for static member functions. */ + + struct type **args; + + /* For virtual functions. + First baseclass that defines this virtual function. */ + + struct type *fcontext; + + /* Attributes. */ + + unsigned int is_const : 1; + unsigned int is_volatile : 1; + unsigned int is_private : 1; + unsigned int is_protected : 1; + + /* A stub method only has some fields valid (but they are enough + to reconstruct the rest of the fields). */ + unsigned int is_stub : 1; + + /* Unused. */ + unsigned int dummy : 3; + + /* Index into that baseclass's virtual function table, + minus 2; else if static: VOFFSET_STATIC; else: 0. */ + + unsigned int voffset : 24; + +# define VOFFSET_STATIC 1 + + } *fn_fields; + + } *fn_fieldlists; + +}; + +/* The default value of TYPE_CPLUS_SPECIFIC(T) points to the + this shared static structure. */ + +extern const struct cplus_struct_type cplus_struct_default; + +extern void +allocate_cplus_struct_type PARAMS ((struct type *)); + +#define INIT_CPLUS_SPECIFIC(type) \ + (TYPE_CPLUS_SPECIFIC(type)=(struct cplus_struct_type*)&cplus_struct_default) +#define ALLOCATE_CPLUS_STRUCT_TYPE(type) allocate_cplus_struct_type (type) +#define HAVE_CPLUS_STRUCT(type) \ + (TYPE_CPLUS_SPECIFIC(type) != &cplus_struct_default) + +#define TYPE_NAME(thistype) (thistype)->name +#define TYPE_TAG_NAME(type) ((type)->tag_name) +#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type +#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type +#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type +/* Note that if thistype is a TYPEDEF type, you have to call check_typedef. + But check_typedef does set the TYPE_LENGTH of the TYPEDEF type, + so you only have to call check_typedef once. Since allocate_value + calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */ +#define TYPE_LENGTH(thistype) (thistype)->length +#define TYPE_OBJFILE(thistype) (thistype)->objfile +#define TYPE_FLAGS(thistype) (thistype)->flags +#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED) +/* Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you wan the real + type, you need to do TYPE_CODE (check_type (this_type)). */ +#define TYPE_CODE(thistype) (thistype)->code +#define TYPE_NFIELDS(thistype) (thistype)->nfields +#define TYPE_FIELDS(thistype) (thistype)->fields + +#define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0) +#define TYPE_LOW_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 0) +#define TYPE_HIGH_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 1) + +/* Moto-specific stuff for FORTRAN arrays */ + +#define TYPE_ARRAY_UPPER_BOUND_TYPE(thistype) (thistype)->upper_bound_type +#define TYPE_ARRAY_LOWER_BOUND_TYPE(thistype) (thistype)->lower_bound_type + +#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ + (TYPE_FIELD_BITPOS((TYPE_FIELD_TYPE((arraytype),0)),1)) + +#define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \ + (TYPE_FIELD_BITPOS((TYPE_FIELD_TYPE((arraytype),0)),0)) + +/* C++ */ + +#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype +#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype +#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno +#define TYPE_FN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fields +#define TYPE_NFN_FIELDS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields +#define TYPE_NFN_FIELDS_TOTAL(thistype) TYPE_CPLUS_SPECIFIC(thistype)->nfn_fields_total +#define TYPE_TYPE_SPECIFIC(thistype) (thistype)->type_specific +#define TYPE_ARG_TYPES(thistype) (thistype)->type_specific.arg_types +#define TYPE_CPLUS_SPECIFIC(thistype) (thistype)->type_specific.cplus_stuff +#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type +#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses +#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name +#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos +#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index)) +#define BASETYPE_VIA_VIRTUAL(thistype, index) \ + B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)) + +#define TYPE_FIELD(thistype, n) (thistype)->fields[n] +#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type +#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name +#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type) +#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos +#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize +#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize + +#define TYPE_FIELD_PRIVATE_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits +#define TYPE_FIELD_PROTECTED_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits +#define TYPE_FIELD_IGNORE_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits +#define TYPE_FIELD_VIRTUAL_BITS(thistype) \ + TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits +#define SET_TYPE_FIELD_PRIVATE(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n)) +#define SET_TYPE_FIELD_PROTECTED(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n)) +#define SET_TYPE_FIELD_IGNORE(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits, (n)) +#define SET_TYPE_FIELD_VIRTUAL(thistype, n) \ + B_SET (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)) +#define TYPE_FIELD_PRIVATE(thistype, n) \ + (TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits == NULL ? 0 \ + : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->private_field_bits, (n))) +#define TYPE_FIELD_PROTECTED(thistype, n) \ + (TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits == NULL ? 0 \ + : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->protected_field_bits, (n))) +#define TYPE_FIELD_IGNORE(thistype, n) \ + (TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits == NULL ? 0 \ + : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->ignore_field_bits, (n))) +#define TYPE_FIELD_VIRTUAL(thistype, n) \ + B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)) + +#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1) +#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize) + +#define TYPE_FN_FIELDLISTS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists +#define TYPE_FN_FIELDLIST(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n] +#define TYPE_FN_FIELDLIST1(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].fn_fields +#define TYPE_FN_FIELDLIST_NAME(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].name +#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists[n].length + +#define TYPE_FN_FIELD(thisfn, n) (thisfn)[n] +#define TYPE_FN_FIELD_PHYSNAME(thisfn, n) (thisfn)[n].physname +#define TYPE_FN_FIELD_TYPE(thisfn, n) (thisfn)[n].type +#define TYPE_FN_FIELD_ARGS(thisfn, n) TYPE_ARG_TYPES ((thisfn)[n].type) +#define TYPE_FN_FIELD_CONST(thisfn, n) ((thisfn)[n].is_const) +#define TYPE_FN_FIELD_VOLATILE(thisfn, n) ((thisfn)[n].is_volatile) +#define TYPE_FN_FIELD_PRIVATE(thisfn, n) ((thisfn)[n].is_private) +#define TYPE_FN_FIELD_PROTECTED(thisfn, n) ((thisfn)[n].is_protected) +#define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub) +#define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext) +#define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2) +#define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1) +#define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC) + +extern struct type *builtin_type_void; +extern struct type *builtin_type_char; +extern struct type *builtin_type_short; +extern struct type *builtin_type_int; +extern struct type *builtin_type_long; +extern struct type *builtin_type_signed_char; +extern struct type *builtin_type_unsigned_char; +extern struct type *builtin_type_unsigned_short; +extern struct type *builtin_type_unsigned_int; +extern struct type *builtin_type_unsigned_long; +extern struct type *builtin_type_float; +extern struct type *builtin_type_double; +extern struct type *builtin_type_long_double; +extern struct type *builtin_type_complex; +extern struct type *builtin_type_double_complex; +extern struct type *builtin_type_string; + +/* This type represents a type that was unrecognized in symbol + read-in. */ + +extern struct type *builtin_type_error; + +extern struct type *builtin_type_long_long; +extern struct type *builtin_type_unsigned_long_long; + +/* Modula-2 types */ + +extern struct type *builtin_type_m2_char; +extern struct type *builtin_type_m2_int; +extern struct type *builtin_type_m2_card; +extern struct type *builtin_type_m2_real; +extern struct type *builtin_type_m2_bool; + +/* Chill types */ + +extern struct type *builtin_type_chill_bool; +extern struct type *builtin_type_chill_char; +extern struct type *builtin_type_chill_long; +extern struct type *builtin_type_chill_ulong; +extern struct type *builtin_type_chill_real; + +/* Fortran (F77) types */ + +extern struct type *builtin_type_f_character; +extern struct type *builtin_type_f_integer; +extern struct type *builtin_type_f_logical; +extern struct type *builtin_type_f_logical_s1; +extern struct type *builtin_type_f_logical_s2; +extern struct type *builtin_type_f_integer; +extern struct type *builtin_type_f_integer_s2; +extern struct type *builtin_type_f_real; +extern struct type *builtin_type_f_real_s8; +extern struct type *builtin_type_f_real_s16; +extern struct type *builtin_type_f_complex_s8; +extern struct type *builtin_type_f_complex_s16; +extern struct type *builtin_type_f_complex_s32; +extern struct type *builtin_type_f_void; + +/* Maximum and minimum values of built-in types */ + +#define MAX_OF_TYPE(t) \ + TYPE_UNSIGNED(t) ? UMAX_OF_SIZE(TYPE_LENGTH(t)) \ + : MAX_OF_SIZE(TYPE_LENGTH(t)) + +#define MIN_OF_TYPE(t) \ + TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \ + : MIN_OF_SIZE(TYPE_LENGTH(t)) + +/* Allocate space for storing data associated with a particular type. + We ensure that the space is allocated using the same mechanism that + was used to allocate the space for the type structure itself. I.E. + if the type is on an objfile's type_obstack, then the space for data + associated with that type will also be allocated on the type_obstack. + If the type is not associated with any particular objfile (such as + builtin types), then the data space will be allocated with xmalloc, + the same as for the type structure. */ + +#define TYPE_ALLOC(t,size) \ + (TYPE_OBJFILE (t) != NULL \ + ? obstack_alloc (&TYPE_OBJFILE (t) -> type_obstack, size) \ + : xmalloc (size)) + +extern struct type * +alloc_type PARAMS ((struct objfile *)); + +extern struct type * +init_type PARAMS ((enum type_code, int, int, char *, struct objfile *)); + +extern struct type * +lookup_reference_type PARAMS ((struct type *)); + +extern struct type * +make_reference_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_member_type PARAMS ((struct type *, struct type *)); + +extern void +smash_to_method_type PARAMS ((struct type *, struct type *, struct type *, + struct type **)); + +extern void +smash_to_member_type PARAMS ((struct type *, struct type *, struct type *)); + +extern struct type * +allocate_stub_method PARAMS ((struct type *)); + +extern char * +type_name_no_tag PARAMS ((const struct type *)); + +extern struct type * +lookup_struct_elt_type PARAMS ((struct type *, char *, int)); + +extern struct type * +make_pointer_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_pointer_type PARAMS ((struct type *)); + +extern struct type * +make_function_type PARAMS ((struct type *, struct type **)); + +extern struct type * +lookup_function_type PARAMS ((struct type *)); + +extern struct type * +create_range_type PARAMS ((struct type *, struct type *, int, int)); + +extern struct type * +create_array_type PARAMS ((struct type *, struct type *, struct type *)); + +extern struct type * +create_string_type PARAMS ((struct type *, struct type *)); + +extern struct type *create_set_type PARAMS ((struct type *, struct type *)); + +extern int chill_varying_type PARAMS ((struct type*)); + +extern struct type * +lookup_unsigned_typename PARAMS ((char *)); + +extern struct type * +lookup_signed_typename PARAMS ((char *)); + +extern struct type * +check_typedef PARAMS ((struct type *)); + +#define CHECK_TYPEDEF(TYPE) (TYPE) = check_typedef (TYPE) + +extern void +check_stub_method PARAMS ((struct type *, int, int)); + +extern struct type * +lookup_primitive_typename PARAMS ((char *)); + +extern char * +gdb_mangle_name PARAMS ((struct type *, int, int)); + +extern struct type * +builtin_type PARAMS ((char **)); + +extern struct type * +lookup_typename PARAMS ((char *, struct block *, int)); + +extern struct type * +lookup_template_type PARAMS ((char *, struct type *, struct block *)); + +extern struct type * +lookup_fundamental_type PARAMS ((struct objfile *, int)); + +extern void +fill_in_vptr_fieldno PARAMS ((struct type *)); + +extern int get_discrete_bounds PARAMS ((struct type*, LONGEST*, LONGEST*)); + +#if MAINTENANCE_CMDS +extern void recursive_dump_type PARAMS ((struct type *, int)); +#endif + +/* printcmd.c */ + +extern void +print_scalar_formatted PARAMS ((char *, struct type *, int, int, GDB_FILE *)); + +extern int can_dereference PARAMS ((struct type *)); + +#if MAINTENANCE_CMDS +extern void maintenance_print_type PARAMS ((char *, int)); +#endif + +#endif /* GDBTYPES_H */ diff --git a/contrib/gdb/gdb/gnu-nat.c b/contrib/gdb/gdb/gnu-nat.c new file mode 100644 index 000000000000..2d9cbed9f9d1 --- /dev/null +++ b/contrib/gdb/gdb/gnu-nat.c @@ -0,0 +1,2814 @@ +/* Interface GDB to the GNU Hurd + Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc. + + This file is part of GDB. + + Written by Miles Bader + + Some code and ideas from m3-nat.c by Jukka Virtanen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* We include this because we don't need the access macros and they conflict + with gdb's definitions (ick). This is very non standard! */ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "language.h" +#include "target.h" +#include "wait.h" +#include "gdbcmd.h" +#include "gdbcore.h" + +#include "gnu-nat.h" + +#include "exc_request_S.h" +#include "notify_S.h" +#include "process_reply_S.h" +#include "msg_reply_S.h" + +#include "exc_request_U.h" +#include "msg_U.h" + +static process_t proc_server = MACH_PORT_NULL; + +/* If we've sent a proc_wait_request to the proc server, the pid of the + process we asked about. We can only ever have one outstanding. */ +int proc_wait_pid = 0; + +/* The number of wait requests we've sent, and expect replies from. */ +int proc_waits_pending = 0; + +int gnu_debug_flag = 0; + +/* Forward decls */ + +extern struct target_ops gnu_ops; + +struct inf *make_inf (); +void inf_clear_wait (struct inf *inf); +void inf_cleanup (struct inf *inf); +void inf_startup (struct inf *inf, int pid, task_t task); +int inf_update_suspends (struct inf *inf); +void inf_set_task (struct inf *inf, task_t port); +void inf_validate_procs (struct inf *inf); +void inf_steal_exc_ports (struct inf *inf); +void inf_restore_exc_ports (struct inf *inf); +int inf_update_procs (struct inf *inf); +struct proc *inf_tid_to_proc (struct inf *inf, int tid); +inline void inf_set_threads_resume_sc (struct inf *inf, struct proc + *run_thread, int run_others); +inline int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf); +inline void inf_suspend (struct inf *inf); +inline void inf_resume (struct inf *inf); +void inf_set_step_thread (struct inf *inf, struct proc *proc); +void inf_detach (struct inf *inf); +void inf_attach (struct inf *inf, int pid); +void inf_signal (struct inf *inf, enum target_signal sig); + +#define inf_debug(_inf, msg, args...) \ + do { struct inf *__inf = (_inf); \ + debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0) + +struct proc *make_proc (struct inf *inf, mach_port_t port, int tid); +struct proc *_proc_free (struct proc *proc); +int proc_update_sc (struct proc *proc); +void proc_abort (struct proc *proc, int force); +thread_state_t proc_get_state (struct proc *proc, int force); +error_t proc_get_exception_port (struct proc *proc, mach_port_t *port); +error_t proc_set_exception_port (struct proc *proc, mach_port_t port); +static mach_port_t _proc_get_exc_port (struct proc *proc); +void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port); +void proc_restore_exc_port (struct proc *proc); +int proc_trace (struct proc *proc, int set); +char *proc_string (struct proc *proc); + +/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound + to INF's msg port and task port respectively. If it has no msg port, + EIEIO is returned. INF must refer to a running process! */ +#define INF_MSGPORT_RPC(inf, rpc_expr) \ + HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \ + (refport = inf->task->port, 0), 0, \ + msgport ? (rpc_expr) : EIEIO) + +/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure + there's someone around to deal with the RPC (and resuspend things + afterwards). This effects INF's threads' resume_sc count. */ +#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \ + (inf_set_threads_resume_sc_for_signal_thread (inf) \ + ? ({ error_t __e; \ + inf_resume (inf); \ + __e = INF_MSGPORT_RPC (inf, rpc_expr); \ + inf_suspend (inf); \ + __e; }) \ + : EIEIO) + +#define MIG_SERVER_DIED EMIG_SERVER_DIED /* XXX */ + +/* The state passed by an exception message. */ +struct exc_state +{ + int exception; /* The exception code */ + int code, subcode; + mach_port_t handler; /* The real exception port to handle this. */ + mach_port_t reply; /* The reply port from the exception call. */ +}; + +/* The results of the last wait an inf did. */ +struct inf_wait +{ + struct target_waitstatus status; /* The status returned to gdb. */ + struct exc_state exc; /* The exception that caused us to return. */ + struct proc *thread; /* The thread in question. */ + int suppress; /* Something trivial happened. */ +}; + +/* The state of an inferior. */ +struct inf +{ + /* Fields describing the current inferior. */ + + struct proc *task; /* The mach task. */ + struct proc *threads; /* A linked list of all threads in TASK. */ + + /* True if THREADS needn't be validated by querying the task. We assume that + we and the task in question are the only ones frobbing the thread list, + so as long as we don't let any code run, we don't have to worry about + THREADS changing. */ + int threads_up_to_date; + + pid_t pid; /* The real system PID. */ + + struct inf_wait wait; /* What to return from target_wait. */ + + /* One thread proc in INF may be in `single-stepping mode'. This is it. */ + struct proc *step_thread; + + /* The thread we think is the signal thread. */ + struct proc *signal_thread; + + mach_port_t event_port; /* Where we receive various msgs. */ + + /* True if we think at least one thread in the inferior could currently be + running. */ + int running : 1; + + /* True if the process has stopped (in the proc server sense). Note that + since a proc server `stop' leaves the signal thread running, the inf can + be RUNNING && STOPPED... */ + int stopped : 1; + + /* True if the inferior is traced. */ + int traced : 1; + + /* True if we shouldn't try waiting for the inferior, usually because we + can't for some reason. */ + int no_wait : 1; + + /* When starting a new inferior, we don't try to validate threads until all + the proper execs have been done. This is a count of how many execs we + expect to happen. */ + unsigned pending_execs; + + /* Fields describing global state */ + + /* The task suspend count used when gdb has control. This is normally 1 to + make things easier for us, but sometimes (like when attaching to vital + system servers) it may be desirable to let the task continue to run + (pausing individual threads as necessary). */ + int pause_sc; + + /* The initial values used for the run_sc and pause_sc of newly discovered + threads -- see the definition of those fields in struct proc. */ + int default_thread_run_sc; + int default_thread_pause_sc; + + /* True if the process should be traced when started/attached. Newly + started processes *must* be traced at first to exec them properly, but + if this is false, tracing is turned off as soon it has done so. */ + int want_signals; + + /* True if exceptions from the inferior process should be trapped. This + must be on to use breakpoints. */ + int want_exceptions; +}; + +int __proc_pid (struct proc *proc) +{ + return proc->inf->pid; +} + +/* Update PROC's real suspend count to match it's desired one. Returns true + if we think PROC is now in a runnable state. */ +int +proc_update_sc (struct proc *proc) +{ + int running; + int err = 0; + int delta = proc->sc - proc->cur_sc; + + if (delta) + proc_debug (proc, "sc: %d --> %d", proc->cur_sc, proc->sc); + + if (proc->sc == 0 && proc->state_changed) + /* Since PROC may start running, we must write back any state changes. */ + { + assert (proc_is_thread (proc)); + proc_debug (proc, "storing back changed thread state"); + err = thread_set_state (proc->port, THREAD_STATE_FLAVOR, + &proc->state, THREAD_STATE_SIZE); + if (! err) + proc->state_changed = 0; + } + + if (delta > 0) + while (delta-- > 0 && !err) + if (proc_is_task (proc)) + err = task_suspend (proc->port); + else + err = thread_suspend (proc->port); + else + while (delta++ < 0 && !err) + if (proc_is_task (proc)) + err = task_resume (proc->port); + else + err = thread_resume (proc->port); + + if (! err) + proc->cur_sc = proc->sc; + + /* If we got an error, then the task/thread has disappeared. */ + running = !err && proc->sc == 0; + + proc_debug (proc, "is %s", err ? "dead" : running ? "running" : "suspended"); + if (err) + proc_debug (proc, "err = %s", strerror (err)); + + if (running) + { + proc->aborted = 0; + proc->state_valid = proc->state_changed = 0; + proc->fetched_regs = 0; + } + + return running; +} + +/* Thread_abort is called on PROC if needed. PROC must be a thread proc. + If PROC is deemed `precious', then nothing is done unless FORCE is true. + In particular, a thread is precious if it's running (in which case forcing + it includes suspending it first), or if it has an exception pending. */ +void +proc_abort (struct proc *proc, int force) +{ + assert (proc_is_thread (proc)); + + if (! proc->aborted) + { + struct inf *inf = proc->inf; + int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0); + + if (running && force) + { + proc->sc = 1; + inf_update_suspends (proc->inf); + running = 0; + warning ("Stopped %s.", proc_string (proc)); + } + else if (proc == inf->wait.thread && inf->wait.exc.reply && !force) + /* An exception is pending on PROC, which don't mess with. */ + running = 1; + + if (! running) + /* We only abort the thread if it's not actually running. */ + { + thread_abort (proc->port); + proc_debug (proc, "aborted"); + proc->aborted = 1; + } + else + proc_debug (proc, "not aborting"); + } +} + +/* Make sure that the state field in PROC is up to date, and return a pointer + to it, or 0 if something is wrong. If WILL_MODIFY is true, makes sure + that the thread is stopped and aborted first, and sets the state_changed + field in PROC to true. */ +thread_state_t +proc_get_state (struct proc *proc, int will_modify) +{ + int was_aborted = proc->aborted; + + proc_debug (proc, "updating state info%s", + will_modify ? " (with intention to modify)" : ""); + + proc_abort (proc, will_modify); + + if (! was_aborted && proc->aborted) + /* PROC's state may have changed since we last fetched it. */ + proc->state_valid = 0; + + if (! proc->state_valid) + { + mach_msg_type_number_t state_size = THREAD_STATE_SIZE; + error_t err = + thread_get_state (proc->port, THREAD_STATE_FLAVOR, + &proc->state, &state_size); + proc_debug (proc, "getting thread state"); + proc->state_valid = !err; + } + + if (proc->state_valid) + { + if (will_modify) + proc->state_changed = 1; + return &proc->state; + } + else + return 0; +} + +error_t +proc_get_exception_port (struct proc *proc, mach_port_t *port) +{ + if (proc_is_task (proc)) + return task_get_exception_port (proc->port, port); + else + return thread_get_exception_port (proc->port, port); +} + +error_t +proc_set_exception_port (struct proc *proc, mach_port_t port) +{ + proc_debug (proc, "setting exception port: %d", port); + if (proc_is_task (proc)) + return task_set_exception_port (proc->port, port); + else + return thread_set_exception_port (proc->port, port); +} + +/* Get PROC's exception port, cleaning up a bit if proc has died. */ +static mach_port_t +_proc_get_exc_port (struct proc *proc) +{ + mach_port_t exc_port; + error_t err = proc_get_exception_port (proc, &exc_port); + + if (err) + /* PROC must be dead. */ + { + if (proc->exc_port) + mach_port_deallocate (mach_task_self (), proc->exc_port); + proc->exc_port = MACH_PORT_NULL; + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = MACH_PORT_NULL; + } + + return exc_port; +} + +/* Replace PROC's exception port with EXC_PORT, unless it's already been + done. Stash away any existing exception port so we can restore it later. */ +void +proc_steal_exc_port (struct proc *proc, mach_port_t exc_port) +{ + mach_port_t cur_exc_port = _proc_get_exc_port (proc); + + if (cur_exc_port) + { + error_t err; + + proc_debug (proc, "inserting exception port: %d", exc_port); + + if (cur_exc_port != exc_port) + /* Put in our exception port. */ + err = proc_set_exception_port (proc, exc_port); + + if (err || cur_exc_port == proc->exc_port) + /* We previously set the exception port, and it's still set. So we + just keep the old saved port which is what the proc set. */ + { + if (cur_exc_port) + mach_port_deallocate (mach_task_self (), cur_exc_port); + } + else + /* Keep a copy of PROC's old exception port so it can be restored. */ + { + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = cur_exc_port; + } + + proc_debug (proc, "saved exception port: %d", proc->saved_exc_port); + + if (!err) + proc->exc_port = exc_port; + else + warning ("Error setting exception port for %s: %s", + proc_string (proc), strerror (err)); + } +} + +/* If we previously replaced PROC's exception port, put back what we found + there at the time, unless *our* exception port has since be overwritten, + in which case who knows what's going on. */ +void +proc_restore_exc_port (struct proc *proc) +{ + mach_port_t cur_exc_port = _proc_get_exc_port (proc); + + if (cur_exc_port) + { + error_t err = 0; + + proc_debug (proc, "restoring real exception port"); + + if (proc->exc_port == cur_exc_port) + /* Our's is still there. */ + err = proc_set_exception_port (proc, proc->saved_exc_port); + + if (proc->saved_exc_port) + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + proc->saved_exc_port = MACH_PORT_NULL; + + if (!err) + proc->exc_port = MACH_PORT_NULL; + else + warning ("Error setting exception port for %s: %s", + proc_string (proc), strerror (err)); + } +} + +/* Turns hardware tracing in PROC on or off when SET is true or fals, + respectively. Returns true on success. */ +int +proc_trace (struct proc *proc, int set) +{ + thread_state_t state = proc_get_state (proc, 1); + + if (! state) + return 0; /* the thread must be dead. */ + + proc_debug (proc, "tracing %s", set ? "on" : "off"); + + if (set) + { + /* XXX We don't get the exception unless the thread has its own + exception port???? */ + if (proc->exc_port == MACH_PORT_NULL) + proc_steal_exc_port (proc, proc->inf->event_port); + THREAD_STATE_SET_TRACED (state); + } + else + THREAD_STATE_CLEAR_TRACED (state); + + return 1; +} + +/* A variable from which to assign new TIDs. */ +static int next_thread_id = 1; + +/* Returns a new proc structure with the given fields. Also adds a + notification for PORT becoming dead to be sent to INF's notify port. */ +struct proc * +make_proc (struct inf *inf, mach_port_t port, int tid) +{ + error_t err; + mach_port_t prev_port = MACH_PORT_NULL; + struct proc *proc = malloc (sizeof (struct proc)); + + proc->port = port; + proc->tid = tid; + proc->inf = inf; + proc->next = 0; + proc->saved_exc_port = MACH_PORT_NULL; + proc->exc_port = MACH_PORT_NULL; + proc->sc = 0; + proc->cur_sc = 0; + proc->run_sc = inf->default_thread_run_sc; + proc->pause_sc = inf->default_thread_pause_sc; + proc->resume_sc = proc->run_sc; + proc->aborted = 0; + proc->state_valid = 0; + proc->state_changed = 0; + + proc_debug (proc, "is new"); + + /* Get notified when things die. */ + err = + mach_port_request_notification (mach_task_self(), port, + MACH_NOTIFY_DEAD_NAME, 1, + inf->event_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &prev_port); + if (err) + warning ("Couldn't request notification for port %d: %s", + port, strerror (err)); + else + { + proc_debug (proc, "notifications to: %d", inf->event_port); + if (prev_port != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), prev_port); + } + + if (inf->want_exceptions) + if (proc_is_task (proc)) + /* Make the task exception port point to us. */ + proc_steal_exc_port (proc, inf->event_port); + else + /* Just clear thread exception ports -- they default to the task one. */ + proc_steal_exc_port (proc, MACH_PORT_NULL); + + return proc; +} + +/* Frees PROC and any resources it uses, and returns the value of PROC's next + field. */ +struct proc * +_proc_free (struct proc *proc) +{ + struct inf *inf = proc->inf; + struct proc *next = proc->next; + + proc_debug (proc, "freeing..."); + + if (proc == inf->step_thread) + /* Turn off single stepping. */ + inf_set_step_thread (inf, 0); + if (proc == inf->wait.thread) + inf_clear_wait (inf); + if (proc == inf->signal_thread) + inf->signal_thread = 0; + + if (proc->port != MACH_PORT_NULL) + { + if (proc->exc_port != MACH_PORT_NULL) + /* Restore the original exception port. */ + proc_restore_exc_port (proc); + if (proc->cur_sc != 0) + /* Resume the thread/task. */ + { + proc->sc = 0; + proc_update_sc (proc); + } + mach_port_deallocate (mach_task_self (), proc->port); + } + + free (proc); + return next; +} + +struct inf *make_inf () +{ + struct inf *inf = malloc (sizeof (struct inf)); + + if (!inf) + return 0; + + inf->task = 0; + inf->threads = 0; + inf->threads_up_to_date = 0; + inf->pid = 0; + inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS; + inf->wait.thread = 0; + inf->wait.exc.handler = MACH_PORT_NULL; + inf->wait.exc.reply = MACH_PORT_NULL; + inf->step_thread = 0; + inf->signal_thread = 0; + inf->event_port = MACH_PORT_NULL; + inf->stopped = 0; + inf->running = 0; + inf->traced = 0; + inf->no_wait = 0; + inf->pending_execs = 0; + inf->pause_sc = 1; + inf->default_thread_run_sc = 0; + inf->default_thread_pause_sc = 0; + inf->want_signals = 1; /* By default */ + inf->want_exceptions = 1; /* By default */ + + return inf; +} + +void +inf_clear_wait (struct inf *inf) +{ + inf_debug (inf, "clearing wait"); + inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS; + inf->wait.thread = 0; + inf->wait.suppress = 0; + if (inf->wait.exc.handler != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), inf->wait.exc.handler); + inf->wait.exc.handler = MACH_PORT_NULL; + } + if (inf->wait.exc.reply != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), inf->wait.exc.reply); + inf->wait.exc.reply = MACH_PORT_NULL; + } +} + +void +inf_cleanup (struct inf *inf) +{ + inf_debug (inf, "cleanup"); + + inf_clear_wait (inf); + + inf_set_task (inf, MACH_PORT_NULL); + inf->pid = 0; + inf->traced = 0; + inf->no_wait = 0; + inf->stopped = 0; + inf->running = 0; + inf->pending_execs = 0; + + if (inf->event_port) + { + mach_port_destroy (mach_task_self (), inf->event_port); + inf->event_port = MACH_PORT_NULL; + } +} + +void +inf_startup (struct inf *inf, int pid, task_t task) +{ + error_t err; + + inf_debug (inf, "startup: pid = %d, task = %d", pid, task); + + inf_cleanup (inf); + + /* Make the port on which we receive all events. */ + err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &inf->event_port); + if (err) + error ("Error allocating event port: %s", strerror (err)); + + /* Make a send right for it, so we can easily copy it for other people. */ + mach_port_insert_right (mach_task_self (), inf->event_port, + inf->event_port, MACH_MSG_TYPE_MAKE_SEND); + + if (inf->pause_sc) + task_suspend (task); + + inf_set_task (inf, task); + + if (inf->task) + { + inf->pid = pid; + if (inf->pause_sc) + inf->task->sc = inf->task->cur_sc = 1; /* Reflect task_suspend above */ + } +} + +void +inf_set_task (struct inf *inf, mach_port_t port) +{ + struct proc *task = inf->task; + + inf_debug (inf, "setting task: %d", port); + + if (task && task->port != port) + { + inf->task = 0; + inf_validate_procs (inf); /* Trash all the threads. */ + _proc_free (task); /* And the task. */ + } + + if (port != MACH_PORT_NULL) + { + inf->task = make_proc (inf, port, PROC_TID_TASK); + inf->threads_up_to_date = 0; + } +} + +/* Validates INF's stopped field from the actual proc server state. */ +static void +inf_validate_stopped (struct inf *inf) +{ + char *noise; + mach_msg_type_number_t noise_len = 0; + struct procinfo *pi; + mach_msg_type_number_t pi_len = 0; + error_t err = + proc_getprocinfo (proc_server, inf->pid, 0, + (procinfo_t *)&pi, &pi_len, &noise, &noise_len); + + if (! err) + { + inf->stopped = !!(pi->state & PI_STOPPED); + vm_deallocate (mach_task_self (), (vm_address_t)pi, pi_len); + if (noise_len > 0) + vm_deallocate (mach_task_self (), (vm_address_t)noise, noise_len); + } +} + +/* Validates INF's task suspend count. */ +static void +inf_validate_task_sc (struct inf *inf) +{ + struct task_basic_info info; + mach_msg_type_number_t info_len = TASK_BASIC_INFO_COUNT; + error_t err = task_info (inf->task->port, TASK_BASIC_INFO, &info, &info_len); + if (! err) + { + if (inf->task->cur_sc < info.suspend_count) + warning ("Pid %d is suspended; continuing will clear existing suspend count.", inf->pid); + inf->task->cur_sc = info.suspend_count; + } +} + +/* Turns tracing for INF on or off, depending on ON, unless it already is. + If INF is running, the resume_sc count of INF's threads will be modified, + and the signal thread will briefly be run to change the trace state. */ +void +inf_set_traced (struct inf *inf, int on) +{ + if (on != inf->traced) + if (inf->task) + /* Make it take effect immediately. */ + { + error_t (*f)(mach_port_t, mach_port_t, int) = + on ? msg_set_some_exec_flags : msg_clear_some_exec_flags; + error_t err = + INF_RESUME_MSGPORT_RPC (inf, (*f)(msgport, refport, EXEC_TRACED)); + if (err == EIEIO) + warning ("Can't modify tracing state for pid %d: No signal thread", + inf->pid); + else if (err) + warning ("Can't modify tracing state for pid %d: %s", + inf->pid, strerror (err)); + else + inf->traced = on; + } + else + inf->traced = on; +} + +/* Makes all the real suspend count deltas of all the procs in INF match the + desired values. Careful to always do thread/task suspend counts in the + safe order. Returns true if at least one thread is thought to be running.*/ +int +inf_update_suspends (struct inf *inf) +{ + struct proc *task = inf->task; + /* We don't have to update INF->threads even though we're iterating over it + because we'll change a thread only if it already has an existing proc + entry. */ + + inf_debug (inf, "updating suspend counts"); + + if (task) + { + struct proc *thread; + int task_running = (task->sc == 0), thread_running = 0; + + if (task->sc > task->cur_sc) + /* The task is becoming _more_ suspended; do before any threads. */ + task_running = proc_update_sc (task); + + if (inf->pending_execs) + /* When we're waiting for an exec, things may be happening behind our + back, so be conservative. */ + thread_running = 1; + + /* Do all the thread suspend counts. */ + for (thread = inf->threads; thread; thread = thread->next) + thread_running |= proc_update_sc (thread); + + if (task->sc != task->cur_sc) + /* We didn't do the task first, because we wanted to wait for the + threads; do it now. */ + task_running = proc_update_sc (task); + + inf_debug (inf, "%srunning...", + (thread_running && task_running) ? "" : "not "); + + inf->running = thread_running && task_running; + + /* Once any thread has executed some code, we can't depend on the + threads list any more. */ + if (inf->running) + inf->threads_up_to_date = 0; + + return inf->running; + } + + return 0; +} + +/* Converts a GDB pid to a struct proc. */ +struct proc * +inf_tid_to_thread (struct inf *inf, int tid) +{ + struct proc *thread = inf->threads; + while (thread) + if (thread->tid == tid) + return thread; + else + thread = thread->next; + return 0; +} + +/* Converts a thread port to a struct proc. */ +struct proc * +inf_port_to_thread (struct inf *inf, mach_port_t port) +{ + struct proc *thread = inf->threads; + while (thread) + if (thread->port == port) + return thread; + else + thread = thread->next; + return 0; +} + +/* Make INF's list of threads be consistent with reality of TASK. */ +void +inf_validate_procs (struct inf *inf) +{ + int i; + thread_array_t threads; + unsigned num_threads; + struct proc *task = inf->task; + + inf->threads_up_to_date = !inf->running; + + if (task) + { + error_t err = task_threads (task->port, &threads, &num_threads); + inf_debug (inf, "fetching threads"); + if (err) + /* TASK must be dead. */ + { + task->port = MACH_PORT_NULL; + _proc_free (task); + task = inf->task = 0; + } + } + + if (!task) + { + num_threads = 0; + inf_debug (inf, "no task"); + } + + { + unsigned search_start = 0; /* Make things normally linear. */ + /* Which thread in PROCS corresponds to each task thread, & the task. */ + struct proc *matched[num_threads + 1]; + /* The last thread in INF->threads, so we can add to the end. */ + struct proc *last = 0; + /* The current thread we're considering. */ + struct proc *thread = inf->threads; + + bzero (matched, sizeof (matched)); + + while (thread) + { + unsigned left; + + for (i = search_start, left = num_threads; left; i++, left--) + { + if (i >= num_threads) + i -= num_threads; /* I wrapped around. */ + if (thread->port == threads[i]) + /* We already know about this thread. */ + { + matched[i] = thread; + last = thread; + thread = thread->next; + search_start++; + break; + } + } + + if (! left) + { + proc_debug (thread, "died!"); + thread->port = MACH_PORT_NULL; + thread = _proc_free (thread); /* THREAD is dead. */ + (last ? last->next : inf->threads) = thread; + } + } + + for (i = 0; i < num_threads; i++) + if (matched[i]) + /* Throw away the duplicate send right. */ + mach_port_deallocate (mach_task_self (), threads[i]); + else + /* THREADS[I] is a thread we don't know about yet! */ + { + thread = make_proc (inf, threads[i], next_thread_id++); + (last ? last->next : inf->threads) = thread; + last = thread; + proc_debug (thread, "new thread: %d", threads[i]); + add_thread (thread->tid); /* Tell GDB's generic thread code. */ + } + + vm_deallocate(mach_task_self(), + (vm_address_t)threads, (num_threads * sizeof(thread_t))); + } +} + +/* Makes sure that INF's thread list is synced with the actual process. */ +inline int +inf_update_procs (struct inf *inf) +{ + if (! inf->task) + return 0; + if (! inf->threads_up_to_date) + inf_validate_procs (inf); + return !!inf->task; +} + +/* Sets the resume_sc of each thread in inf. That of RUN_THREAD is set to 0, + and others are set to their run_sc if RUN_OTHERS is true, and otherwise + their pause_sc. */ +inline void +inf_set_threads_resume_sc (struct inf *inf, + struct proc *run_thread, int run_others) +{ + struct proc *thread; + inf_update_procs (inf); + for (thread = inf->threads; thread; thread = thread->next) + if (thread == run_thread) + thread->resume_sc = 0; + else if (run_others) + thread->resume_sc = thread->run_sc; + else + thread->resume_sc = thread->pause_sc; +} + +/* Cause INF to continue execution immediately; individual threads may still + be suspended (but their suspend counts will be updated). */ +inline void +inf_resume (struct inf *inf) +{ + struct proc *thread; + + inf_update_procs (inf); + + for (thread = inf->threads; thread; thread = thread->next) + thread->sc = thread->resume_sc; + + if (inf->task) + inf->task->sc = 0; + + inf_update_suspends (inf); +} + +/* Cause INF to stop execution immediately; individual threads may still + be running. */ +inline void +inf_suspend (struct inf *inf) +{ + struct proc *thread; + + inf_update_procs (inf); + + for (thread = inf->threads; thread; thread = thread->next) + thread->sc = thread->pause_sc; + + if (inf->task) + inf->task->sc = inf->pause_sc; + + inf_update_suspends (inf); +} + +/* INF has one thread PROC that is in single-stepping mode. This functions + changes it to be PROC, changing any old step_thread to be a normal one. A + PROC of 0 clears an any existing value. */ +void +inf_set_step_thread (struct inf *inf, struct proc *thread) +{ + assert (!thread || proc_is_thread (thread)); + + if (thread) + inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid); + else + inf_debug (inf, "clearing step thread"); + + if (inf->step_thread != thread) + { + if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL) + if (! proc_trace (inf->step_thread, 0)) + return; + if (thread && proc_trace (thread, 1)) + inf->step_thread = thread; + else + inf->step_thread = 0; + } +} + +/* Set up the thread resume_sc's so that only the signal thread is running + (plus whatever other thread are set to always run). Returns true if we + did so, or false if we can't find a signal thread. */ +inline int +inf_set_threads_resume_sc_for_signal_thread (struct inf *inf) +{ + if (inf->signal_thread) + { + inf_set_threads_resume_sc (inf, inf->signal_thread, 0); + return 1; + } + else + return 0; +} + +static void +inf_update_signal_thread (struct inf *inf) +{ + /* XXX for now we assume that if there's a msgport, the 2nd thread is + the signal thread. */ + inf->signal_thread = inf->threads ? inf->threads->next : 0; +} + +/* Detachs from INF's inferior task, letting it run once again... */ +void +inf_detach (struct inf *inf) +{ + struct proc *task = inf->task; + + inf_debug (inf, "detaching..."); + + inf_clear_wait (inf); + inf_set_step_thread (inf, 0); + + if (task) + { + struct proc *thread; + + inf_set_traced (inf, 0); + if (inf->stopped) + inf_signal (inf, TARGET_SIGNAL_0); + + proc_restore_exc_port (task); + task->sc = 0; + + for (thread = inf->threads; thread; thread = thread->next) + { + proc_restore_exc_port (thread); + thread->sc = 0; + } + + inf_update_suspends (inf); + } + + inf_cleanup (inf); +} + +/* Attaches INF to the process with process id PID, returning it in a suspended + state suitable for debugging. */ +void +inf_attach (struct inf *inf, int pid) +{ + error_t err; + task_t task; + + inf_debug (inf, "attaching: %d", pid); + + err = proc_pid2task (proc_server, pid, &task); + if (err) + error ("Error getting task for pid %d: %s", pid, strerror (err)); + + if (inf->pid) + inf_detach (inf); + + inf_startup (inf, pid, task); +} + +/* Makes sure that we've got our exception ports entrenched in the process. */ +void inf_steal_exc_ports (struct inf *inf) +{ + struct proc *thread; + + inf_debug (inf, "stealing exception ports"); + + inf_set_step_thread (inf, 0); /* The step thread is special. */ + + proc_steal_exc_port (inf->task, inf->event_port); + for (thread = inf->threads; thread; thread = thread->next) + proc_steal_exc_port (thread, MACH_PORT_NULL); +} + +/* Makes sure the process has its own exception ports. */ +void inf_restore_exc_ports (struct inf *inf) +{ + struct proc *thread; + + inf_debug (inf, "restoring exception ports"); + + inf_set_step_thread (inf, 0); /* The step thread is special. */ + + proc_restore_exc_port (inf->task); + for (thread = inf->threads; thread; thread = thread->next) + proc_restore_exc_port (thread); +} + +/* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even + signal 0, will continue it. INF is assumed to be in a paused state, and + the resume_sc's of INF's threads may be affected. */ +void +inf_signal (struct inf *inf, enum target_signal sig) +{ + error_t err = 0; + int host_sig = target_signal_to_host (sig); + +#define NAME target_signal_to_name (sig) + + if (host_sig >= _NSIG) + /* A mach exception. Exceptions are encoded in the signal space by + putting them after _NSIG; this assumes they're positive (and not + extremely large)! */ + { + struct inf_wait *w = &inf->wait; + if (w->status.kind == TARGET_WAITKIND_STOPPED + && w->status.value.sig == sig + && w->thread && !w->thread->aborted) + /* We're passing through the last exception we received. This is + kind of bogus, because exceptions are per-thread whereas gdb + treats signals as per-process. We just forward the exception to + the correct handler, even it's not for the same thread as TID -- + i.e., we pretend it's global. */ + { + struct exc_state *e = &w->exc; + inf_debug (inf, "passing through exception:" + " task = %d, thread = %d, exc = %d" + ", code = %d, subcode = %d", + w->thread->port, inf->task->port, + e->exception, e->code, e->subcode); + err = + exception_raise_request (e->handler, + e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE, + w->thread->port, inf->task->port, + e->exception, e->code, e->subcode); + } + else + warning ("Can't forward spontaneous exception (%s).", NAME); + } + else + /* A Unix signal. */ + if (inf->stopped) + /* The process is stopped an expecting a signal. Just send off a + request and let it get handled when we resume everything. */ + { + inf_debug (inf, "sending %s to stopped process", NAME); + err = + INF_MSGPORT_RPC (inf, + msg_sig_post_untraced_request (msgport, + inf->event_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + host_sig, + refport)); + if (! err) + /* Posting an untraced signal automatically continues it. + We clear this here rather than when we get the reply + because we'd rather assume it's not stopped when it + actually is, than the reverse. */ + inf->stopped = 0; + } + else + /* It's not expecting it. We have to let just the signal thread + run, and wait for it to get into a reasonable state before we + can continue the rest of the process. When we finally resume the + process the signal we request will be the very first thing that + happens. */ + { + inf_debug (inf, "sending %s to unstopped process (so resuming signal thread)", NAME); + err = + INF_RESUME_MSGPORT_RPC (inf, + msg_sig_post_untraced (msgport, + host_sig, refport)); + } + + if (err == EIEIO) + /* Can't do too much... */ + warning ("Can't deliver signal %s: No signal thread.", NAME); + else if (err) + warning ("Delivering signal %s: %s", NAME, strerror (err)); + +#undef NAME +} + +/* The inferior used for all gdb target ops. */ +struct inf *current_inferior = 0; + +/* The inferior being waited for by gnu_wait. Since GDB is decidely not + multi-threaded, we don't bother to lock this. */ +struct inf *waiting_inf; + +/* Wait for something to happen in the inferior, returning what in STATUS. */ +static int +gnu_wait (int tid, struct target_waitstatus *status) +{ + struct msg { + mach_msg_header_t hdr; + mach_msg_type_t type; + int data[8000]; + } msg; + error_t err; + struct proc *thread; + struct inf *inf = current_inferior; + + waiting_inf = inf; + + inf_debug (inf, "waiting for: %d", tid); + + rewait: + if (proc_wait_pid != inf->pid && !inf->no_wait) + /* Always get information on events from the proc server. */ + { + inf_debug (inf, "requesting wait on pid %d", inf->pid); + + if (proc_wait_pid) + /* The proc server is single-threaded, and only allows a single + outstanding wait request, so we have to cancel the previous one. */ + { + inf_debug (inf, "cancelling previous wait on pid %d", proc_wait_pid); + interrupt_operation (proc_server); + } + + err = + proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED); + if (err) + warning ("wait request failed: %s", strerror (err)); + else + { + inf_debug (inf, "waits pending: %d", proc_waits_pending); + proc_wait_pid = inf->pid; + /* Even if proc_waits_pending was > 0 before, we still won't get + any other replies, because it was either from a different INF, + or a different process attached to INF -- and the event port, + which is the wait reply port, changes when you switch processes.*/ + proc_waits_pending = 1; + } + } + + inf_clear_wait (inf); + + /* What can happen? (1) Dead name notification; (2) Exceptions arrive; + (3) wait reply from the proc server. */ + + inf_debug (inf, "waiting for an event..."); + err = _hurd_intr_rpc_mach_msg (&msg.hdr, MACH_RCV_MSG, 0, + sizeof (struct msg), + inf->event_port, MACH_PORT_NULL); + + /* Re-suspend the task. */ + inf_suspend (inf); + + if (err == EINTR) + inf_debug (inf, "interrupted"); + else if (err) + error ("Couldn't wait for an event: %s", strerror (err)); + else + { + struct { + mach_msg_header_t hdr; + mach_msg_type_t err_type; + kern_return_t err; + char noise[200]; + } reply; + + inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id); + + /* Handle what we got. */ + if (! notify_server (&msg.hdr, &reply.hdr) + && ! exc_server (&msg.hdr, &reply.hdr) + && ! process_reply_server (&msg.hdr, &reply.hdr) + && ! msg_reply_server (&msg.hdr, &reply.hdr)) + /* Whatever it is, it's something strange. */ + error ("Got a strange event, msg id = %d.", msg.hdr.msgh_id); + + if (reply.err) + error ("Handling event, msgid = %d: %s", + msg.hdr.msgh_id, strerror (reply.err)); + } + + if (inf->pending_execs) + /* We're waiting for the inferior to finish execing. */ + { + struct inf_wait *w = &inf->wait; + enum target_waitkind kind = w->status.kind; + + if (kind == TARGET_WAITKIND_SPURIOUS) + /* Since gdb is actually counting the number of times the inferior + stops, expecting one stop per exec, we only return major events + while execing. */ + w->suppress = 1; + else if (kind == TARGET_WAITKIND_STOPPED + && w->status.value.sig == TARGET_SIGNAL_TRAP) + /* Ah hah! A SIGTRAP from the inferior while starting up probably + means we've succesfully completed an exec! */ + if (--inf->pending_execs == 0) + /* We're done! */ + { + prune_threads (1); /* Get rid of the old shell threads */ + renumber_threads (0); /* Give our threads reasonable names. */ + } + } + + if (inf->wait.suppress) + /* Some totally spurious event happened that we don't consider + worth returning to gdb. Just keep waiting. */ + { + inf_debug (inf, "suppressing return, rewaiting..."); + inf_resume (inf); + goto rewait; + } + + /* Pass back out our results. */ + bcopy (&inf->wait.status, status, sizeof (*status)); + + thread = inf->wait.thread; + if (thread) + tid = thread->tid; + else + thread = inf_tid_to_thread (inf, tid); + + if (!thread || thread->port == MACH_PORT_NULL) + /* TID is dead; try and find a new thread. */ + if (inf_update_procs (inf) && inf->threads) + tid = inf->threads->tid; /* The first available thread. */ + else + tid = -1; + + if (thread && tid >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS + && inf->pause_sc == 0 && thread->pause_sc == 0) + /* If something actually happened to THREAD, make sure we suspend it. */ + { + thread->sc = 1; + inf_update_suspends (inf); + } + + inf_debug (inf, "returning tid = %d, status = %s (%d)", tid, + status->kind == TARGET_WAITKIND_EXITED ? "EXITED" + : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED" + : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED" + : status->kind == TARGET_WAITKIND_LOADED ? "LOADED" + : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS" + : "?", + status->value.integer); + + return tid; +} + +/* The rpc handler called by exc_server. */ +error_t +S_exception_raise_request (mach_port_t port, mach_port_t reply_port, + thread_t thread_port, task_t task_port, + int exception, int code, int subcode) +{ + struct inf *inf = waiting_inf; + struct proc *thread = inf_port_to_thread (inf, thread_port); + + inf_debug (waiting_inf, + "thread = %d, task = %d, exc = %d, code = %d, subcode = %d", + thread_port, task_port, exception, code); + + if (!thread) + /* We don't know about thread? */ + { + inf_update_procs (inf); + thread = inf_port_to_thread (inf, thread_port); + if (!thread) + /* Give up, the generating thread is gone. */ + return 0; + } + + mach_port_deallocate (mach_task_self (), thread_port); + mach_port_deallocate (mach_task_self (), task_port); + + if (! thread->aborted) + /* THREAD hasn't been aborted since this exception happened (abortion + clears any exception state), so it must be real. */ + { + /* Store away the details; this will destroy any previous info. */ + inf->wait.thread = thread; + + inf->wait.status.kind = TARGET_WAITKIND_STOPPED; + + if (exception == EXC_BREAKPOINT) + /* GDB likes to get SIGTRAP for breakpoints. */ + { + inf->wait.status.value.sig = TARGET_SIGNAL_TRAP; + mach_port_deallocate (mach_task_self (), reply_port); + } + else + /* Record the exception so that we can forward it later. */ + { + if (thread->exc_port == port) + inf->wait.exc.handler = thread->saved_exc_port; + else + { + inf->wait.exc.handler = inf->task->saved_exc_port; + assert (inf->task->exc_port == port); + } + if (inf->wait.exc.handler != MACH_PORT_NULL) + /* Add a reference to the exception handler. */ + mach_port_mod_refs (mach_task_self (), + inf->wait.exc.handler, MACH_PORT_RIGHT_SEND, + 1); + + inf->wait.exc.exception = exception; + inf->wait.exc.code = code; + inf->wait.exc.subcode = subcode; + inf->wait.exc.reply = reply_port; + + /* Exceptions are encoded in the signal space by putting them after + _NSIG; this assumes they're positive (and not extremely large)! */ + inf->wait.status.value.sig = + target_signal_from_host (_NSIG + exception); + } + } + else + /* A supppressed exception, which ignore. */ + { + inf->wait.suppress = 1; + mach_port_deallocate (mach_task_self (), reply_port); + } + + return 0; +} + +/* Fill in INF's wait field after a task has died without giving us more + detailed information. */ +void +inf_task_died_status (struct inf *inf) +{ + warning ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid); + inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED; + inf->wait.status.value.sig = TARGET_SIGNAL_KILL; +} + +/* Notify server routines. The only real one is dead name notification. */ + +error_t +do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port) +{ + struct inf *inf = waiting_inf; + + inf_debug (waiting_inf, "port = %d", dead_port); + + if (inf->task && inf->task->port == dead_port) + { + proc_debug (inf->task, "is dead"); + inf->task->port = MACH_PORT_NULL; + if (proc_wait_pid == inf->pid) + /* We have a wait outstanding on the process, which will return more + detailed information, so delay until we get that. */ + inf->wait.suppress = 1; + else + /* We never waited for the process (maybe it wasn't a child), so just + pretend it got a SIGKILL. */ + inf_task_died_status (inf); + } + else + { + struct proc *thread = inf_port_to_thread (inf, dead_port); + if (thread) + { + proc_debug (thread, "is dead"); + thread->port = MACH_PORT_NULL; + } + } + + mach_port_deallocate (mach_task_self (), dead_port); + inf->threads_up_to_date = 0; /* Just in case */ + + return 0; +} + +static error_t +ill_rpc (char *fun) +{ + warning ("illegal rpc: %s", fun); + return 0; +} + +error_t +do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count) +{ + return ill_rpc (__FUNCTION__); +} + +error_t +do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name) +{ + return ill_rpc (__FUNCTION__); +} + +error_t +do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name) +{ + return ill_rpc (__FUNCTION__); +} + +error_t +do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name) +{ + return ill_rpc (__FUNCTION__); +} + +error_t +do_mach_notify_send_once (mach_port_t notify) +{ + return ill_rpc (__FUNCTION__); +} + +/* Process_reply server routines. We only use process_wait_reply. */ + +error_t +S_proc_wait_reply (mach_port_t reply, error_t err, + int status, rusage_t rusage, pid_t pid) +{ + struct inf *inf = waiting_inf; + + inf_debug (inf, "err = %s, pid = %d, status = 0x%x", + err ? strerror (err) : "0", pid, status); + + if (err && proc_wait_pid && (!inf->task || !inf->task->port)) + /* Ack. The task has died, but the task-died notification code didn't + tell anyone because it thought a more detailed reply from the + procserver was forthcoming. However, we now learn that won't + happen... So we have to act like the task just died, and this time, + tell the world. */ + inf_task_died_status (inf); + + if (--proc_waits_pending == 0) + /* PROC_WAIT_PID represents the most recent wait. We will always get + replies in order because the proc server is single threaded. */ + proc_wait_pid = 0; + + inf_debug (inf, "waits pending now: %d", proc_waits_pending); + + if (err) + { + if (err != EINTR) + { + warning ("Can't wait for pid %d: %s", inf->pid, strerror (err)); + inf->no_wait = 1; + + /* Since we can't see the inferior's signals, don't trap them. */ + inf_set_traced (inf, 0); + } + } + else if (pid == inf->pid) + { + store_waitstatus (&inf->wait.status, status); + if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED) + /* The process has sent us a signal, and stopped itself in a sane + state pending our actions. */ + { + inf_debug (inf, "process has stopped itself"); + inf->stopped = 1; + + /* We recheck the task suspend count here because the crash server + messes with it in an unfriendly way, right before `stopping'. */ + inf_validate_task_sc (inf); + } + } + else + inf->wait.suppress = 1; /* Something odd happened. Ignore. */ + + return 0; +} + +error_t +S_proc_setmsgport_reply (mach_port_t reply, error_t err, + mach_port_t old_msg_port) +{ + return ill_rpc (__FUNCTION__); +} + +error_t +S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port) +{ + return ill_rpc (__FUNCTION__); +} + +/* Msg_reply server routines. We only use msg_sig_post_untraced_reply. */ + +error_t +S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err) +{ + struct inf *inf = waiting_inf; + + if (err == EBUSY) + /* EBUSY is what we get when the crash server has grabbed control of the + process and doesn't like what signal we tried to send it. Just act + like the process stopped (using a signal of 0 should mean that the + *next* time the user continues, it will pass signal 0, which the crash + server should like). */ + { + inf->wait.status.kind = TARGET_WAITKIND_STOPPED; + inf->wait.status.value.sig = TARGET_SIGNAL_0; + } + else if (err) + warning ("Signal delivery failed: %s", strerror (err)); + + if (err) + /* We only get this reply when we've posted a signal to a process which we + thought was stopped, and which we expected to continue after the signal. + Given that the signal has failed for some reason, it's reasonable to + assume it's still stopped. */ + inf->stopped = 1; + else + inf->wait.suppress = 1; + + return 0; +} + +error_t +S_msg_sig_post_reply (mach_port_t reply, error_t err) +{ + return ill_rpc (__FUNCTION__); +} + +/* Returns the number of messages queued for the receive right PORT. */ +static mach_port_msgcount_t +port_msgs_queued (mach_port_t port) +{ + struct mach_port_status status; + error_t err = + mach_port_get_receive_status (mach_task_self (), port, &status); + + if (err) + return 0; + else + return status.mps_msgcount; +} + +/* Resume execution of the inferior process. + + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. + + TID STEP: + -1 true Single step the current thread allowing other threads to run. + -1 false Continue the current thread allowing other threads to run. + X true Single step the given thread, don't allow any others to run. + X false Continue the given thread, do not allow any others to run. + (Where X, of course, is anything except -1) + + Note that a resume may not `take' if there are pending exceptions/&c + still unprocessed from the last resume we did (any given resume may result + in multiple events returned by wait). +*/ +static void +gnu_resume (int tid, int step, enum target_signal sig) +{ + struct proc *step_thread = 0; + struct inf *inf = current_inferior; + + inf_debug (inf, "tid = %d, step = %d, sig = %d", tid, step, sig); + + if (sig != TARGET_SIGNAL_0 || inf->stopped) + inf_signal (inf, sig); + else if (inf->wait.exc.reply != MACH_PORT_NULL) + /* We received an exception to which we have chosen not to forward, so + abort the faulting thread, which will perhaps retake it. */ + { + proc_abort (inf->wait.thread, 1); + warning ("Aborting %s with unforwarded exception %s.", + proc_string (inf->wait.thread), + target_signal_to_name (inf->wait.status.value.sig)); + } + + if (port_msgs_queued (inf->event_port)) + /* If there are still messages in our event queue, don't bother resuming + the process, as we're just going to stop it right away anyway. */ + return; + + if (tid < 0) + /* Allow all threads to run, except perhaps single-stepping one. */ + { + inf_debug (inf, "running all threads; tid = %d", inferior_pid); + tid = inferior_pid; /* What to step. */ + inf_set_threads_resume_sc (inf, 0, 1); + } + else + /* Just allow a single thread to run. */ + { + struct proc *thread = inf_tid_to_thread (inf, tid); + assert (thread); + + inf_debug (inf, "running one thread: %d/%d", inf->pid, thread->tid); + inf_set_threads_resume_sc (inf, thread, 0); + } + + if (step) + { + step_thread = inf_tid_to_thread (inf, tid); + assert (step_thread); + inf_debug (inf, "stepping thread: %d/%d", inf->pid, step_thread->tid); + } + if (step_thread != inf->step_thread) + inf_set_step_thread (inf, step_thread); + + inf_debug (inf, "here we go..."); + inf_resume (inf); +} + +static void +gnu_kill_inferior () +{ + struct proc *task = current_inferior->task; + if (task) + { + proc_debug (task, "terminating..."); + task_terminate (task->port); + task->port = MACH_PORT_NULL; + inf_validate_procs (current_inferior); /* Clear out the thread list &c */ + } + target_mourn_inferior (); +} + +/* Clean up after the inferior dies. */ + +static void +gnu_mourn_inferior () +{ + inf_debug (current_inferior, "rip"); + inf_detach (current_inferior); + unpush_target (&gnu_ops); + generic_mourn_inferior (); +} + +/* Fork an inferior process, and start debugging it. */ + +/* Set INFERIOR_PID to the first thread available in the child, if any. */ +static void +pick_first_thread () +{ + if (current_inferior->task && current_inferior->threads) + /* The first thread. */ + inferior_pid = current_inferior->threads->tid; + else + /* What may be the next thread. */ + inferior_pid = next_thread_id; +} + +static struct inf * +cur_inf () +{ + if (! current_inferior) + current_inferior = make_inf (); + return current_inferior; +} + +static void +gnu_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + struct inf *inf = cur_inf (); + + void trace_me () + { + /* We're in the child; make this process stop as soon as it execs. */ + inf_debug (inf, "tracing self"); + ptrace (PTRACE_TRACEME, 0, 0, 0); + } + void attach_to_child (int pid) + { + /* Attach to the now stopped child, which is actually a shell... */ + inf_debug (inf, "attaching to child: %d", pid); + + inf_attach (inf, pid); + pick_first_thread (); + + attach_flag = 0; + push_target (&gnu_ops); + + inf->pending_execs = 2; + inf->traced = 1; + + /* Now let the child run again, knowing that it will stop immediately + because of the ptrace. */ + inf_resume (inf); + + startup_inferior (pid, inf->pending_execs); + } + + inf_debug (inf, "creating inferior"); + + fork_inferior (exec_file, allargs, env, trace_me, attach_to_child, NULL); + + inf_update_signal_thread (inf); + inf_set_traced (inf, inf->want_signals); + + /* Execing the process will have trashed our exception ports; steal them + back (or make sure they're restored if the user wants that). */ + if (inf->want_exceptions) + inf_steal_exc_ports (inf); + else + inf_restore_exc_ports (inf); + + /* Here we go! */ + proceed ((CORE_ADDR) -1, 0, 0); +} + +/* Mark our target-struct as eligible for stray "run" and "attach" + commands. */ +static int +gnu_can_run () +{ + return 1; +} + +#ifdef ATTACH_DETACH + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ +static void +gnu_attach (args, from_tty) + char *args; + int from_tty; +{ + int pid; + char *exec_file; + struct inf *inf = cur_inf (); + + if (!args) + error_no_arg ("PID to attach"); + + pid = atoi (args); + + if (pid == getpid()) /* Trying to masturbate? */ + error ("I refuse to debug myself!"); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf_unfiltered ("Attaching to program `%s', pid %d\n", + exec_file, pid); + else + printf_unfiltered ("Attaching to pid %d\n", pid); + + gdb_flush (gdb_stdout); + } + + inf_debug (inf, "attaching to pid: %d", pid); + + inf_attach (inf, pid); + inf_update_procs (inf); + + pick_first_thread (); + + attach_flag = 1; + push_target (&gnu_ops); + + inf_update_signal_thread (inf); + inf_set_traced (inf, inf->want_signals); + + /* If the process was stopped before we attached, make it continue the next + time the user does a continue. */ + inf_validate_stopped (inf); + inf_validate_task_sc (inf); +} + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via fork. */ +static void +gnu_detach (args, from_tty) + char *args; + int from_tty; +{ + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file) + printf_unfiltered ("Detaching from program `%s' pid %d\n", + exec_file, current_inferior->pid); + else + printf_unfiltered ("Detaching from pid %d\n", current_inferior->pid); + gdb_flush (gdb_stdout); + } + + inf_detach (current_inferior); + + inferior_pid = 0; + + unpush_target (&gnu_ops); /* Pop out of handling an inferior */ +} +#endif /* ATTACH_DETACH */ + +static void +gnu_terminal_init_inferior () +{ + assert (current_inferior); + terminal_init_inferior_with_pgrp (current_inferior->pid); +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +gnu_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +static void +gnu_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a Unix child process."); +} + +static void +gnu_stop () +{ + error ("to_stop target function not implemented"); +} + +static int +gnu_thread_alive (int tid) +{ + inf_update_procs (current_inferior); + return !!inf_tid_to_thread (current_inferior, tid); +} + +/* + * Read inferior task's LEN bytes from ADDR and copy it to MYADDR + * in gdb's address space. + * + * Return 0 on failure; number of bytes read otherwise. + */ +int +gnu_read_inferior (task, addr, myaddr, length) + task_t task; + CORE_ADDR addr; + char *myaddr; + int length; +{ + error_t err; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr+length) - low_address; + pointer_t copied; + int copy_count; + + /* Get memory from inferior with page aligned addresses */ + err = vm_read (task, low_address, aligned_length, &copied, ©_count); + if (err) + return 0; + + err = hurd_safe_copyin (myaddr, (void*)addr - low_address + copied, length); + if (err) + { + warning ("Read from inferior faulted: %s", strerror (err)); + length = 0; + } + + err = vm_deallocate (mach_task_self (), copied, copy_count); + if (err) + warning ("gnu_read_inferior vm_deallocate failed: %s", strerror (err)); + + return length; +} + +#define CHK_GOTO_OUT(str,ret) \ + do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0) + +struct vm_region_list { + struct vm_region_list *next; + vm_prot_t protection; + vm_address_t start; + vm_size_t length; +}; + +struct obstack region_obstack; + +/* + * Write inferior task's LEN bytes from ADDR and copy it to MYADDR + * in gdb's address space. + */ +int +gnu_write_inferior (task, addr, myaddr, length) + task_t task; + CORE_ADDR addr; + char *myaddr; + int length; +{ + error_t err = 0; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr+length) - low_address; + pointer_t copied; + int copy_count; + int deallocate = 0; + + char *errstr = "Bug in gnu_write_inferior"; + + struct vm_region_list *region_element; + struct vm_region_list *region_head = (struct vm_region_list *)NULL; + + /* Get memory from inferior with page aligned addresses */ + err = vm_read (task, + low_address, + aligned_length, + &copied, + ©_count); + CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err); + + deallocate++; + + err = hurd_safe_copyout ((void*)addr - low_address + copied, myaddr, length); + CHK_GOTO_OUT ("Write to inferior faulted", err); + + obstack_init (®ion_obstack); + + /* Do writes atomically. + * First check for holes and unwritable memory. + */ + { + vm_size_t remaining_length = aligned_length; + vm_address_t region_address = low_address; + + struct vm_region_list *scan; + + while(region_address < low_address + aligned_length) + { + vm_prot_t protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; + boolean_t shared; + mach_port_t object_name; + vm_offset_t offset; + vm_size_t region_length = remaining_length; + vm_address_t old_address = region_address; + + err = vm_region (task, + ®ion_address, + ®ion_length, + &protection, + &max_protection, + &inheritance, + &shared, + &object_name, + &offset); + CHK_GOTO_OUT ("vm_region failed", err); + + /* Check for holes in memory */ + if (old_address != region_address) + { + warning ("No memory at 0x%x. Nothing written", + old_address); + err = KERN_SUCCESS; + length = 0; + goto out; + } + + if (!(max_protection & VM_PROT_WRITE)) + { + warning ("Memory at address 0x%x is unwritable. Nothing written", + old_address); + err = KERN_SUCCESS; + length = 0; + goto out; + } + + /* Chain the regions for later use */ + region_element = + (struct vm_region_list *) + obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); + + region_element->protection = protection; + region_element->start = region_address; + region_element->length = region_length; + + /* Chain the regions along with protections */ + region_element->next = region_head; + region_head = region_element; + + region_address += region_length; + remaining_length = remaining_length - region_length; + } + + /* If things fail after this, we give up. + * Somebody is messing up inferior_task's mappings. + */ + + /* Enable writes to the chained vm regions */ + for (scan = region_head; scan; scan = scan->next) + { + boolean_t protection_changed = FALSE; + + if (!(scan->protection & VM_PROT_WRITE)) + { + err = vm_protect (task, + scan->start, + scan->length, + FALSE, + scan->protection | VM_PROT_WRITE); + CHK_GOTO_OUT ("vm_protect: enable write failed", err); + } + } + + err = vm_write (task, + low_address, + copied, + aligned_length); + CHK_GOTO_OUT ("vm_write failed", err); + + /* Set up the original region protections, if they were changed */ + for (scan = region_head; scan; scan = scan->next) + { + boolean_t protection_changed = FALSE; + + if (!(scan->protection & VM_PROT_WRITE)) + { + err = vm_protect (task, + scan->start, + scan->length, + FALSE, + scan->protection); + CHK_GOTO_OUT ("vm_protect: enable write failed", err); + } + } + } + + out: + if (deallocate) + { + obstack_free (®ion_obstack, 0); + + (void) vm_deallocate (mach_task_self (), + copied, + copy_count); + } + + if (err != KERN_SUCCESS) + { + warning ("%s: %s", errstr, mach_error_string (err)); + return 0; + } + + return length; +} + +/* Return 0 on failure, number of bytes handled otherwise. */ +static int +gnu_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* IGNORED */ +{ + int result; + task_t task = + current_inferior + ? (current_inferior->task ? current_inferior->task->port : 0) + : 0; + + if (task == MACH_PORT_NULL) + return 0; + else + { + inf_debug (current_inferior, "%s %p[%d] %s %p", + write ? "writing" : "reading", memaddr, len, + write ? "<--" : "-->", myaddr); + if (write) + return gnu_write_inferior (task, memaddr, myaddr, len); + else + return gnu_read_inferior (task, memaddr, myaddr, len); + } +} + +extern void gnu_store_registers (int regno); +extern void gnu_fetch_registers (int regno); + +struct target_ops gnu_ops = { + "GNU", /* to_shortname */ + "GNU Hurd process", /* to_longname */ + "GNU Hurd process", /* to_doc */ + gnu_open, /* to_open */ + 0, /* to_close */ + gnu_attach, /* to_attach */ + gnu_detach, /* to_detach */ + gnu_resume, /* to_resume */ + gnu_wait, /* to_wait */ + gnu_fetch_registers, /* to_fetch_registers */ + gnu_store_registers, /* to_store_registers */ + gnu_prepare_to_store, /* to_prepare_to_store */ + gnu_xfer_memory, /* to_xfer_memory */ + 0, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + gnu_terminal_init_inferior, /* to_terminal_init */ + terminal_inferior, /* to_terminal_inferior */ + terminal_ours_for_output, /* to_terminal_ours_for_output */ + terminal_ours, /* to_terminal_ours */ + child_terminal_info, /* to_terminal_info */ + gnu_kill_inferior, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + + gnu_create_inferior, /* to_create_inferior */ + gnu_mourn_inferior, /* to_mourn_inferior */ + gnu_can_run, /* to_can_run */ + 0, /* to_notice_signals */ + gnu_thread_alive, /* to_thread_alive */ + gnu_stop, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +char *proc_string (struct proc *proc) +{ + static char tid_str[80]; + if (proc_is_task (proc)) + sprintf (tid_str, "process %d", proc->inf->pid); + else + sprintf (tid_str, "thread %d.%d", + proc->inf->pid, + pid_to_thread_id (proc->tid)); + return tid_str; +} + +char * +gnu_target_pid_to_str (int tid) +{ + struct inf *inf = current_inferior; + struct proc *thread = inf_tid_to_thread (inf, tid); + + if (thread) + return proc_string (thread); + else + { + static char tid_str[80]; + sprintf (tid_str, "bogus thread id %d", tid); + return tid_str; + } +} + +/* User task commands. */ + +struct cmd_list_element *set_task_cmd_list = 0; +struct cmd_list_element *show_task_cmd_list = 0; + +extern struct cmd_list_element *set_thread_default_cmd_list; +extern struct cmd_list_element *show_thread_default_cmd_list; + +static int +_parse_bool_arg (char *args, char *t_val, char *f_val, char *cmd_prefix) +{ + if (!args || strcmp (args, t_val) == 0) + return 1; + else if (strcmp (args, f_val) == 0) + return 0; + else + error ("Illegal argument for \"%s\" command, should be \"%s\" or \"%s\".", + cmd_prefix, t_val, f_val); +} + +#define parse_bool_arg(args, cmd_prefix) \ + _parse_bool_arg (args, "on", "off", cmd_prefix) + +static void +check_empty (char *args, char *cmd_prefix) +{ + if (args) + error ("Garbage after \"%s\" command: `%s'", cmd_prefix, args); +} + +/* Returns the alive thread named by INFERIOR_PID, or signals an error. */ +static struct proc * +cur_thread () +{ + struct inf *inf = cur_inf (); + struct proc *thread = inf_tid_to_thread (inf, inferior_pid); + if (!thread) + error ("No current thread."); + return thread; +} + +static void +set_task_pause_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + int old_sc = inf->pause_sc; + + inf->pause_sc = parse_bool_arg (args, "set task pause"); + + if (old_sc == 0 && inf->pause_sc != 0) + /* If the task is currently unsuspended, immediately suspend it, + otherwise wait until the next time it gets control. */ + inf_suspend (inf); +} + +static void +show_task_pause_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show task pause"); + printf_unfiltered ("The inferior task %s suspended while gdb has control.\n", + inf->task + ? (inf->pause_sc == 0 ? "isn't" : "is") + : (inf->pause_sc == 0 ? "won't be" : "will be")); +} + +static void +set_thread_default_pause_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + inf->default_thread_pause_sc = + parse_bool_arg (args, "set thread default pause") ? 0 : 1; +} + +static void +show_thread_default_pause_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + int sc = inf->default_thread_pause_sc; + check_empty (args, "show thread default pause"); + printf_unfiltered ("New threads %s suspended while gdb has control%s.\n", + sc ? "are" : "aren't", + !sc && inf->pause_sc ? "(but the task is)" : ""); +} + +static void +set_thread_default_run_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + inf->default_thread_run_sc = + parse_bool_arg (args, "set thread default run") ? 0 : 1; +} + +static void +show_thread_default_run_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show thread default run"); + printf_unfiltered ("New threads %s allowed to run.\n", + inf->default_thread_run_sc == 0 ? "are" : "aren't"); +} + +/* Steal a send right called NAME in the inferior task, and make it PROC's + saved exception port. */ +static void +steal_exc_port (struct proc *proc, mach_port_t name) +{ + error_t err; + mach_port_t port; + mach_msg_type_name_t port_type; + + if (!proc || !proc->inf->task) + error ("No inferior task."); + + err = mach_port_extract_right (proc->inf->task->port, + name, MACH_MSG_TYPE_COPY_SEND, + &port, &port_type); + if (err) + error ("Couldn't extract send right %d from inferior: %s", + name, strerror (err)); + + if (proc->saved_exc_port) + /* Get rid of our reference to the old one. */ + mach_port_deallocate (mach_task_self (), proc->saved_exc_port); + + proc->saved_exc_port = port; + + if (! proc->exc_port) + /* If PROC is a thread, we may not have set its exception port before. + We can't use proc_steal_exc_port because it also sets saved_exc_port. */ + { + proc->exc_port = proc->inf->event_port; + err = proc_set_exception_port (proc, proc->exc_port); + error ("Can't set exception port for %s: %s", + proc_string (proc), strerror (err)); + } +} + +static void +set_task_exc_port_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + if (!args) + error ("No argument to \"set task exception-port\" command."); + steal_exc_port (inf->task, parse_and_eval_address (args)); +} + +static void +set_signals_cmd (char *args, int from_tty) +{ + int trace; + struct inf *inf = cur_inf (); + + inf->want_signals = parse_bool_arg (args, "set signals"); + + if (inf->task && inf->want_signals != inf->traced) + /* Make this take effect immediately in a running process. */ + inf_set_traced (inf, inf->want_signals); +} + +static void +show_signals_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show signals"); + printf_unfiltered ("The inferior process's signals %s intercepted.\n", + inf->task + ? (inf->traced ? "are" : "aren't") + : (inf->want_signals ? "will be" : "won't be")); +} + +static void +set_stopped_cmd (char *args, int from_tty) +{ + cur_inf ()->stopped = _parse_bool_arg (args, "yes", "no", "set stopped"); +} + +static void +show_stopped_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show stopped"); + if (! inf->task) + error ("No current process."); + printf_unfiltered ("The inferior process %s stopped.\n", + inf->stopped ? "is" : "isn't"); +} + +static void +set_sig_thread_cmd (char *args, int from_tty) +{ + int tid; + struct inf *inf = cur_inf (); + + if (!args || (! isdigit (*args) && strcmp (args, "none") != 0)) + error ("Illegal argument to \"set signal-thread\" command.\n" + "Should be an integer thread ID, or `none'."); + + if (strcmp (args, "none") == 0) + inf->signal_thread = 0; + else + { + int tid = thread_id_to_pid (atoi (args)); + if (tid < 0) + error ("Thread ID %s not known. Use the \"info threads\" command to\n" + "see the IDs of currently known threads.", args); + inf->signal_thread = inf_tid_to_thread (inf, tid); + } +} + +static void +show_sig_thread_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show signal-thread"); + if (! inf->task) + error ("No current process."); + if (inf->signal_thread) + printf_unfiltered ("The signal thread is %s.\n", + proc_string (inf->signal_thread)); + else + printf_unfiltered ("There is no signal thread.\n"); +} + +static void +set_exceptions_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + int val = parse_bool_arg (args, "set exceptions"); + + if (inf->task && inf->want_exceptions != val) + /* Make this take effect immediately in a running process. */ + /* XXX */; + + inf->want_exceptions = val; +} + +static void +show_exceptions_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + check_empty (args, "show exceptions"); + printf_unfiltered ("Exceptions in the inferior %s trapped.\n", + inf->task + ? (inf->want_exceptions ? "are" : "aren't") + : (inf->want_exceptions ? "will be" : "won't be")); +} + +static void +set_task_cmd (char *args, int from_tty) +{ + printf_unfiltered ("\"set task\" must be followed by the name of a task property.\n"); +} + +static void +show_task_cmd (char *args, int from_tty) +{ + struct inf *inf = cur_inf (); + + check_empty (args, "show task"); + + show_signals_cmd (0, from_tty); + show_exceptions_cmd (0, from_tty); + show_task_pause_cmd (0, from_tty); + + if (inf->pause_sc == 0) + show_thread_default_pause_cmd (0, from_tty); + show_thread_default_run_cmd (0, from_tty); + + if (inf->task) + { + show_stopped_cmd (0, from_tty); + show_sig_thread_cmd (0, from_tty); + } +} + +static void add_task_commands () +{ + add_cmd ("pause", class_run, set_thread_default_pause_cmd, + "Set whether the new threads are suspended while gdb has control.\n" + "This property normally has no effect because the whole task is\n" + "suspended, however, that may be disabled with \"set task pause off\".\n" + "The default value is \"off\".", + &set_thread_default_cmd_list); + add_cmd ("pause", no_class, show_thread_default_pause_cmd, + "Show whether new threads are suspended while gdb has control.", + &show_thread_default_cmd_list); + add_cmd ("run", class_run, set_thread_default_run_cmd, + "Set whether new threads are allowed to run (once gdb has noticed them).", + &set_thread_default_cmd_list); + add_cmd ("run", no_class, show_thread_default_run_cmd, + "Show whether new threads are allowed to run (once gdb has noticed +them).", + &show_thread_default_cmd_list); + + add_cmd ("signals", class_run, set_signals_cmd, + "Set whether the inferior process's signals will be intercepted.\n" + "Mach exceptions (such as breakpoint traps) are not affected.", + &setlist); + add_alias_cmd ("sigs", "signals", class_run, 1, &setlist); + add_cmd ("signals", no_class, show_signals_cmd, + "Show whether the inferior process's signals will be intercepted.", + &showlist); + add_alias_cmd ("sigs", "signals", no_class, 1, &showlist); + + add_cmd ("signal-thread", class_run, set_sig_thread_cmd, + "Set the thread that gdb thinks is the libc signal thread.\n" + "This thread is run when delivering a signal to a non-stopped process.", + &setlist); + add_alias_cmd ("sigthread", "signal-thread", class_run, 1, &setlist); + add_cmd ("signal-thread", no_class, show_sig_thread_cmd, + "Set the thread that gdb thinks is the libc signal thread.", + &showlist); + add_alias_cmd ("sigthread", "signal-thread", no_class, 1, &showlist); + + add_cmd ("stopped", class_run, set_stopped_cmd, + "Set whether gdb thinks the inferior process is stopped as with SIGSTOP.\n" + "Stopped process will be continued by sending them a signal.", + &setlist); + add_cmd ("stopped", no_class, show_signals_cmd, + "Show whether gdb thinks the inferior process is stopped as with SIGSTOP.", + &showlist); + + add_cmd ("exceptions", class_run, set_exceptions_cmd, + "Set whether exceptions in the inferior process will be trapped.\n" + "When exceptions are turned off, neither breakpoints nor single-stepping\n" + "will work.", + &setlist); + /* Allow `set exc' despite conflict with `set exception-port'. */ + add_alias_cmd ("exc", "exceptions", class_run, 1, &setlist); + add_cmd ("exceptions", no_class, show_exceptions_cmd, + "Show whether exceptions in the inferior process will be trapped.", + &showlist); + + + + add_prefix_cmd ("task", no_class, set_task_cmd, + "Command prefix for setting task attributes.", + &set_task_cmd_list, "set task ", 0, &setlist); + add_prefix_cmd ("task", no_class, show_task_cmd, + "Command prefix for showing task attributes.", + &show_task_cmd_list, "show task ", 0, &showlist); + + add_cmd ("pause", class_run, set_task_pause_cmd, + "Set whether the task is suspended while gdb has control.\n" + "A value of \"on\" takes effect immediately, otherwise nothing\n" + "happens until the next time the program is continued.\n" + "When setting this to \"off\", \"set thread default pause on\"\n" + "can be used to pause individual threads by default instead.", + &set_task_cmd_list); + add_cmd ("pause", no_class, show_task_pause_cmd, + "Show whether the task is suspended while gdb has control.", + &show_task_cmd_list); + + add_cmd ("exception-port", no_class, set_task_exc_port_cmd, + "Set the task exception port to which we forward exceptions.\n" + "The argument should be the value of the send right in the task.", + &set_task_cmd_list); + add_alias_cmd ("excp", "exception-port", no_class, 1, &set_task_cmd_list); + add_alias_cmd ("exc-port", "exception-port", no_class, 1, &set_task_cmd_list); +} + +/* User thread commands. */ + +extern struct cmd_list_element *set_thread_cmd_list; +extern struct cmd_list_element *show_thread_cmd_list; + +static void +set_thread_pause_cmd (char *args, int from_tty) +{ + struct proc *thread = cur_thread (); + int old_sc = thread->pause_sc; + thread->pause_sc = parse_bool_arg (args, "set thread pause"); + if (old_sc == 0 && thread->pause_sc != 0 && thread->inf->pause_sc == 0) + /* If the task is currently unsuspended, immediately suspend it, + otherwise wait until the next time it gets control. */ + inf_suspend (thread->inf); +} + +static void +show_thread_pause_cmd (char *args, int from_tty) +{ + struct proc *thread = cur_thread (); + int sc = thread->pause_sc; + check_empty (args, "show task pause"); + printf_unfiltered ("Thread %s %s suspended while gdb has control%s.\n", + proc_string (thread), + sc ? "is" : "isn't", + !sc && thread->inf->pause_sc ? "(but the task is)" : ""); +} + +static void +set_thread_run_cmd (char *args, int from_tty) +{ + struct proc *thread = cur_thread (); + thread->run_sc = parse_bool_arg (args, "set thread run") ? 0 : 1; +} + +static void +show_thread_run_cmd (char *args, int from_tty) +{ + struct proc *thread = cur_thread (); + check_empty (args, "show thread run"); + printf_unfiltered ("Thread %s allowed to run.", + proc_string (thread), + thread->run_sc == 0 ? "is" : "isn't"); +} + +static void +set_thread_exc_port_cmd (char *args, int from_tty) +{ + struct proc *thread = cur_thread (); + if (!args) + error ("No argument to \"set thread exception-port\" command."); + steal_exc_port (thread, parse_and_eval_address (args)); +} + +static void +set_thread_cmd (char *args, int from_tty) +{ + printf_unfiltered ("\"set thread\" must be followed by the name of a thread property.\n"); +} + +static void +show_thread_cmd (char *args, int from_tty) +{ + check_empty (args, "show thread"); + show_thread_run_cmd (0, from_tty); + show_thread_pause_cmd (0, from_tty); +} + +add_thread_commands () +{ + add_cmd ("pause", class_run, set_thread_pause_cmd, + "Set whether the current thread is suspended while gdb has control.\n" + "A value of \"on\" takes effect immediately, otherwise nothing\n" + "happens until the next time the program is continued. This\n" + "property normally has no effect because the whole task is suspended,\n" + "however, that may be disabled with \"set task pause off\".\n" + "The default value is \"off\".", + &set_thread_cmd_list); + add_cmd ("pause", no_class, show_thread_pause_cmd, + "Show whether the current thread is suspended while gdb has control.", + &show_thread_cmd_list); + + add_cmd ("run", class_run, set_thread_run_cmd, + "Set whether the current thread is allowed to run.", + &set_thread_cmd_list); + add_cmd ("run", no_class, show_thread_run_cmd, + "Show whether the current thread is allowed to run.", + &show_thread_cmd_list); + + add_cmd ("exception-port", no_class, set_thread_exc_port_cmd, + "Set the exception port to which we forward exceptions for the\n" + "current thread, overriding the task exception port.\n" + "The argument should be the value of the send right in the task.", + &set_thread_cmd_list); + add_alias_cmd ("excp", "exception-port", no_class, 1, &set_thread_cmd_list); + add_alias_cmd ("exc-port", "exception-port", no_class, 1, &set_thread_cmd_list); +} + +void +_initialize_gnu_nat () +{ + proc_server = getproc (); + + add_target (&gnu_ops); + + add_task_commands (); + add_thread_commands (); + +#if MAINTENANCE_CMDS + add_set_cmd ("gnu-debug", class_maintenance, + var_boolean, (char *)&gnu_debug_flag, + "Set debugging output for the gnu backend.", &maintenancelist); +#endif +} + +#ifdef FLUSH_INFERIOR_CACHE + +/* When over-writing code on some machines the I-Cache must be flushed + explicitly, because it is not kept coherent by the lazy hardware. + This definitely includes breakpoints, for instance, or else we + end up looping in mysterious Bpt traps */ + +void +flush_inferior_icache(pc, amount) + CORE_ADDR pc; +{ + vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH; + error_t ret; + + ret = vm_machine_attribute (current_inferior->task->port, + pc, + amount, + MATTR_CACHE, + &flush); + if (ret != KERN_SUCCESS) + warning ("Error flushing inferior's cache : %s", strerror (ret)); +} +#endif FLUSH_INFERIOR_CACHE diff --git a/contrib/gdb/gdb/gnu-nat.h b/contrib/gdb/gdb/gnu-nat.h new file mode 100644 index 000000000000..6f29b738674a --- /dev/null +++ b/contrib/gdb/gdb/gnu-nat.h @@ -0,0 +1,91 @@ +/* Common things used by the various *gnu-nat.c files + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __GNU_NAT_H__ +#define __GNU_NAT_H__ + +#include +#include + +struct inf; + +extern struct inf *current_inferior; + +/* Converts a GDB pid to a struct proc. */ +struct proc *inf_tid_to_thread (struct inf *inf, int tid); + +/* A proc is either a thread, or the task (there can only be one task proc + because it always has the same TID, PROC_TID_TASK). */ +struct proc +{ + thread_t port; /* The task or thread port. */ + int tid; /* The GDB pid (actually a thread id). */ + int num; /* An id number for threads, to print. */ + + mach_port_t saved_exc_port; /* The task/thread's real exception port. */ + mach_port_t exc_port; /* Our replacement, which for. */ + + int sc; /* Desired suspend count. */ + int cur_sc; /* Implemented suspend count. */ + int run_sc; /* Default sc when the program is running. */ + int pause_sc; /* Default sc when gdb has control. */ + int resume_sc; /* Sc resulting form the last resume. */ + + thread_state_data_t state; /* Registers, &c. */ + int state_valid : 1; /* True if STATE is up to date. */ + int state_changed : 1; + + int aborted : 1; /* True if thread_abort has been called. */ + + /* Bit mask of registers fetched by gdb. This is used when we re-fetch + STATE after aborting the thread, to detect that gdb may have out-of-date + information. */ + unsigned long fetched_regs; + + struct inf *inf; /* Where we come from. */ + + struct proc *next; +}; + +/* The task has a thread entry with this TID. */ +#define PROC_TID_TASK (-1) + +#define proc_is_task(proc) ((proc)->tid == PROC_TID_TASK) +#define proc_is_thread(proc) ((proc)->tid != PROC_TID_TASK) + +extern int __proc_pid (struct proc *proc); + +extern thread_state_t proc_get_state (struct proc *proc, int will_modify); + +#define proc_debug(_proc, msg, args...) \ + do { struct proc *__proc = (_proc); \ + debug ("{proc %d/%d %p}: " msg, \ + __proc_pid (__proc), __proc->tid, __proc , ##args); } while (0) + +#if MAINTENANCE_CMDS +extern int gnu_debug_flag; +#define debug(msg, args...) \ + do { if (gnu_debug_flag) \ + fprintf (stderr, "%s: " msg "\r\n", __FUNCTION__ , ##args); } while (0) +#else +#define debug(msg, args...) (void)0 +#endif + +#endif /* __GNU_NAT_H__ */ diff --git a/contrib/gdb/gdb/gnu-regex.c b/contrib/gdb/gdb/gnu-regex.c new file mode 100644 index 000000000000..dec0cf12f2ab --- /dev/null +++ b/contrib/gdb/gdb/gnu-regex.c @@ -0,0 +1,1759 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* To test, compile with -Dtest. + This Dtestable feature turns this into a self-contained program + which reads a pattern, describes how it compiles, + then reads a string and searches for it. */ + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "config.h" +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +#else /* not emacs */ + +#include "defs.h" +#include "gdb_string.h" +#undef malloc +#define malloc xmalloc + +/* + * Define the syntax stuff, so we can do the \<...\> things. + */ + +#ifndef Sword /* must be non-zero in some of the tests below... */ +#define Sword 1 +#endif + +#define SYNTAX(c) re_syntax_table[c] + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else + +static char re_syntax_table[256]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + memset (re_syntax_table, '\0', sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#endif /* not emacs */ + +#include "gnu-regex.h" + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif /* NFAILURES */ + +/* width of a byte in bits */ + +#define BYTEWIDTH 8 + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +static int obscure_syntax = 0; + +/* Specify the precise syntax of regexp for compilation. + This provides for compatibility for various utilities + which historically have different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask containing the two bits + RE_NO_BK_PARENS and RE_NO_BK_VBAR. */ + +int +re_set_syntax (syntax) + int syntax; +{ + int ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the struct re_pattern_buffer that bufp pointed to, + after re_compile_pattern returns. +*/ + +#define PATPUSH(ch) (*b++ = (char) (ch)) + +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate) c = translate[c]; } + +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +#define MAX_BUF_SIZE (1 << 16) + + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER \ + do { \ + char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + goto too_big; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + goto memory_exhausted; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_jump) \ + fixup_jump = (fixup_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + +static void store_jump (), insert_jump (); + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + int size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p1; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* address of the count-byte of the most recently inserted "exactn" command. + This makes it possible to tell whether a new exact-match character + can be added to that command or requires a new "exactn" command. */ + + char *pending_exact = 0; + + /* address of the place where a forward-jump should go + to the end of the containing expression. + Each alternative of an "or", except the last, ends with a forward-jump + of this sort. */ + + char *fixup_jump = 0; + + /* address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed */ + + char many_times_ok; + + /* address of beginning of regexp, or inside of last \( */ + + char *begalt = b; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* Counts \('s as they are encountered. Remembered for the matching \), + where it becomes the "register number" to put in the stop_memory command */ + + int regnum = 1; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* + * Initialize the syntax table. + */ + init_syntax_once(); +#endif +#endif + + if (bufp->allocated == 0) + { + bufp->allocated = 28; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0 */ + bufp->buffer = (char *) realloc (bufp->buffer, 28); + else + /* Caller did not allocate a buffer. Do it for him */ + bufp->buffer = (char *) malloc (28); + if (!bufp->buffer) goto memory_exhausted; + begalt = b = bufp->buffer; + } + + while (p != pend) + { + if (b - bufp->buffer > bufp->allocated - 10) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + PATFETCH (c); + + switch (c) + { + case '$': + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend) + goto normal_char; + /* Make operand of last vbar end before this `$'. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = 0; + PATPUSH (endline); + break; + } + + /* $ means succeed if at end of line, but only in special contexts. + If randomly in the middle of a pattern, it is a normal character. */ + if (p == pend || *p == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p == ')' + : *p == '\\' && p[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p == '|' + : *p == '\\' && p[1] == '|')) + { + PATPUSH (endline); + break; + } + goto normal_char; + + case '^': + /* ^ means succeed if at beg of line, but only if no preceding pattern. */ + + if (laststart && p[-2] != '\n' + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + PATPUSH (begline); + begalt = b; + } + else + PATPUSH (begline); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + /* If there is a sequence of repetition chars, + collapse it down to equivalent to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + int c1; + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether 0 matches is allowed, + and whether 2 or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, + put in a backward jump at the end. */ + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; + } + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition required: insert before the loop + a skip over the initial on-failure-jump instruction */ + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + PATPUSH (anychar); + break; + + case '[': + while (b - bufp->buffer + > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + PATPUSH (charset_not), p++; + else + PATPUSH (charset); + p1 = p; + + PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + memset (b, '\0', (1 << BYTEWIDTH) / BYTEWIDTH); + /* Read in characters and ranges, setting map bits */ + while (1) + { + PATFETCH (c); + if (c == ']' && p != p1 + 1) break; + if (*p == '-' && p[1] != ']') + { + PATFETCH (c1); + PATFETCH (c1); + while (c <= c1) + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++; + } + else + { + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH); + } + } + /* Discard any bitmap bytes that are all 0 at the end of the map. + Decrement the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + if (regnum < RE_NREGS) + { + PATPUSH (start_memory); + PATPUSH (regnum); + } + *stackp++ = b - bufp->buffer; + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + PATPUSH (stop_memory); + PATPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = 0; + if (*stackp) + fixup_jump = *stackp + bufp->buffer - 1; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if (obscure_syntax & RE_NO_BK_VBAR) + goto normal_backsl; + handle_bar: + insert_jump (on_failure_jump, begalt, b + 6, b); + pending_exact = 0; + b += 3; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = b; + b += 3; + laststart = 0; + begalt = b; + break; + +#ifdef emacs + case '=': + PATPUSH (at_dot); + break; + + case 's': + laststart = b; + PATPUSH (syntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATPUSH (notsyntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + + case 'w': + laststart = b; + PATPUSH (wordchar); + break; + + case 'W': + laststart = b; + PATPUSH (notwordchar); + break; + + case '<': + PATPUSH (wordbeg); + break; + + case '>': + PATPUSH (wordend); + break; + + case 'b': + PATPUSH (wordbound); + break; + + case 'B': + PATPUSH (notwordbound); + break; + + case '`': + PATPUSH (begbuf); + break; + + case '\'': + PATPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c - '0'; + if (c1 >= regnum) + goto normal_char; + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + PATPUSH (duplicate); + PATPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate) c = translate[c]; + goto normal_char; + } + break; + + default: + normal_char: + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact == 0177 || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?'))) + { + laststart = b; + PATPUSH (exactn); + pending_exact = b; + PATPUSH (0); + } + PATPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + +/* Store where `from' points a jump operation to jump to where `to' points. + `opcode' is the opcode to store. */ + +static void +store_jump (from, opcode, to) + char *from, *to; + char opcode; +{ + from[0] = opcode; + from[1] = (to - (from + 3)) & 0377; + from[2] = (to - (from + 3)) >> 8; +} + +/* Open up space at char FROM, and insert there a jump to TO. + CURRENT_END gives te end of the storage no in use, + so we know how much data to copy up. + OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump (op, from, to, current_end) + char op; + char *from, *to, *current_end; +{ + register char *pto = current_end + 3; + register char *pfrom = current_end; + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + +/* Given a pattern, compute a fastmap from it. + The fastmap records which of the (1 << BYTEWIDTH) possible characters + can start a string that matches the pattern. + This fastmap is used by re_search to skip quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data area + as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *pattern = (unsigned char *) bufp->buffer; + int size = bufp->used; + register char *fastmap = bufp->fastmap; + register unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + register int j; + unsigned char *translate = (unsigned char *) bufp->translate; + + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + + memset (fastmap, '\0', (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + bufp->can_be_null = 1; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + For a * loop, it has pushed its failure point already; + if so, discard that as redundant. */ + if ((enum regexpcode) *p != on_failure_jump) + continue; + p++; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *++stackp = p + j; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + return; + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; +#endif /* emacs */ + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case charset_not: + /* Chars beyond end of map must be allowed */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + case unused: + case syntaxspec: + case notsyntaxspec: + default: + break; + } + + /* Get here means we have successfully found the possible starting characters + of one path of the pattern. We need not follow this path any farther. + Instead, look at the next alternative remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } +} + +/* Like re_search_2, below, but only one string is specified. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size); +} + +/* Like re_match_2 but tries first a match starting at index STARTPOS, + then at STARTPOS + 1, and so on. + RANGE is the number of places to try before giving up. + If RANGE is negative, the starting positions tried are + STARTPOS, STARTPOS - 1, etc. + It is up to the caller to make sure that range is not so large + as to take the starting position outside of the input strings. + +The value returned is the position at which the match was found, + or -1 if no match was found, + or -2 if error (such as failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total = size1 + size2; + int val; + + /* Update the fastmap now if not correct already */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* Don't waste time in a long search for a pattern + that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters + that cannot possibly be the start of a match. + Note, however, that if the pattern can possibly match + the null string, we must test it at each starting point + so that we take the first null string we get. */ + + if (fastmap && startpos < total && pbufp->can_be_null != 1) + { + if (range > 0) + { + register int lim = 0; + register unsigned char *p; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + if (translate) + { + while (range > lim && !fastmap[translate[*p++]]) + range--; + } + else + { + while (range > lim && !fastmap[*p++]) + range--; + } + startpos += irange - range; + } + else + { + register unsigned char c; + if (startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop); + if (0 <= val) + { + if (val == -2) + return -2; + return startpos; + } + +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + + advance: + if (!range) break; + if (range > 0) range--, startpos++; else range++, startpos--; + } + return -1; +} + +#ifndef emacs /* emacs never uses this */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size); +} +#endif /* emacs */ + +/* Maximum size of failure stack. Beyond this, overflow is an error. */ + +int re_max_failures = 2000; + +static int memcmp_translate(); +/* Match the pattern described by PBUFP + against data which is the virtual concatenation of STRING1 and STRING2. + SIZE1 and SIZE2 are the sizes of the two data strings. + Start the match at position POS. + Do not consider matching past the position MSTOP. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated + is so this function can be used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is + an error (such as match stack overflow). Otherwise the value is the length + of the substring which was matched. */ + +int +re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + unsigned char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + register unsigned char *pend = p + pbufp->used; + /* End of first string */ + unsigned char *end1; + /* End of second string */ + unsigned char *end2; + /* Pointer just past last char to consider matching */ + unsigned char *end_match_1, *end_match_2; + register unsigned char *d, *dend; + register int mcnt; + unsigned char *translate = (unsigned char *) pbufp->translate; + + /* Failure point stack. Each place that can handle a failure further down the line + pushes a failure point on this stack. It consists of two char *'s. + The first one pushed is where to resume scanning the pattern; + the second pushed is where to resume scanning the strings. + If the latter is zero, the failure point is a "dummy". + If a failure happens and the innermost failure point is dormant, + it discards that failure point and tries the next one. */ + + unsigned char *initial_stack[2 * NFAILURES]; + unsigned char **stackb = initial_stack; + unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES]; + + /* Information on the "contents" of registers. + These are pointers into the input strings; they record + just what was matched (on this attempt) by some part of the pattern. + The start_memory command stores the start of a register's contents + and the stop_memory command stores the end. + + At that point, regstart[regnum] points to the first character in the register, + regend[regnum] points to the first character beyond the end of the register, + regstart_seg1[regnum] is true iff regstart[regnum] points into string1, + and regend_seg1[regnum] is true iff regend[regnum] points into string1. */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS]; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (!size2) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* Initialize \) text positions to -1 + to mark ones that no \( or \) has been seen for. */ + + for (mcnt = 0; mcnt < (int) (sizeof (regend) / sizeof (*regend)); mcnt++) + regend[mcnt] = (unsigned char *) -1; + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. + `d' is advanced into the following input string whenever necessary, + but this happens before fetching; + therefore, at the beginning of the loop, + `d' can be pointing at the end of a string, + but it cannot equal string2. */ + + if (pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + +/* Write PREFETCH; just before fetching a character with *d. */ +#define PREFETCH \ + while (d == dend) \ + { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \ + d = string2; /* end of string1 => advance to string2. */ \ + dend = end_match_2; } + + /* This loop loops over pattern commands. + It exits by returning from the function if match is complete, + or it drops through if match fails at this starting point in the input data. */ + + while (1) + { + if (p == pend) + /* End of pattern means we have succeeded! */ + { + /* If caller wants register contents data back, convert it to indices */ + if (regs) + { + regs->start[0] = pos; + if (dend == end_match_1) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *) -1) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (regstart_seg1[mcnt]) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + if (regend_seg1[mcnt]) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + if (dend == end_match_1) + return (d - string1 - pos); + else + return d - string2 + size1 - pos; + } + + /* Otherwise match next pattern command */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( is represented by a start_memory, \) by a stop_memory. + Both of those commands contain a "register number" argument. + The text matched within the \( and \) is recorded under that number. + Then, \ turns into a `duplicate' command which + is followed by the numeric value of as the register number. */ + + case start_memory: + regstart[*p] = d; + regstart_seg1[*p++] = (dend == end_match_1); + break; + + case stop_memory: + regend[*p] = d; + regend_seg1[*p++] = (dend == end_match_1); + break; + + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + d2 = regstart[regno]; + dend2 = ((regstart_seg1[regno] == regend_seg1[regno]) + ? regend[regno] : end_match_1); + while (1) + { + /* Advance to next segment in register contents, if necessary */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* Advance to next segment in data being matched, if necessary */ + PREFETCH; + + /* mcnt gets # consecutive chars to compare */ + mcnt = dend - d; + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + /* Compare that many; failure if mismatch, else skip them. */ + if (translate ? memcmp_translate (d, d2, mcnt, translate) : memcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + /* fetch a data character */ + PREFETCH; + /* Match anything but a newline. */ + if ((translate ? translate[*d++] : *d++) == '\n') + goto fail; + break; + + case charset: + case charset_not: + { + /* Nonzero for charset_not */ + int not = 0; + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + /* fetch a data character */ + PREFETCH; + + if (translate) + c = translate [*d]; + else + c = *d; + + if (c < *p * BYTEWIDTH + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + d++; + break; + } + + case begline: + if (d == string1 || d[-1] == '\n') + break; + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + break; + goto fail; + + /* "or" constructs ("|") are handled by starting each alternative + with an on_failure_jump that points to the start of the next alternative. + Each alternative except the last ends with a jump to the joining point. + (Actually, each jump except for the last one really jumps + to the following jump, because tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. + This makes a failure point so that, on failure to match a repetition, + matching restarts past as many repetitions have been found + with no way to fail and look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx; + if (stacke - stackb > re_max_failures * 2) + return -2; + stackx = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *stackp++ = mcnt + p; + *stackp++ = d; + break; + + /* The end of a smart repeat has an maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + + case maybe_finalize_jump: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + { + register unsigned char *p2 = p; + /* Compare what follows with the begining of the repeat. + If we can establish that there is nothing that they would + both match, we can change to finalize_jump */ + while (p2 != pend + && (*p2 == (unsigned char) stop_memory + || *p2 == (unsigned char) start_memory)) + p2++; + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + int not = p1[3] == (unsigned char) charset_not; + if (c < p1[4] * BYTEWIDTH + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + /* not is 1 if c would match */ + /* That means it is not safe to finalize */ + if (!not) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + + /* The end of a stupid repeat has a finalize-jump + back to the start, where another failure point will be made + which will point after all the repetitions found so far. */ + + case finalize_jump: + stackp -= 2; + + case jump: + nofinalize: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += mcnt + 1; /* The 1 compensates for missing ++ above */ + break; + + case dummy_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx + = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + memcpy (stackx, stackb, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + *stackp++ = 0; + *stackp++ = 0; + goto nofinalize; + + case wordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + break; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + break; + goto fail; + + case notwordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + goto fail; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + goto fail; + break; + + case wordbeg: + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */ + goto fail; + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + break; + goto fail; + + case wordend: + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + goto fail; + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */ + break; + goto fail; + +#ifdef emacs + case before_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + <= point) + goto fail; + break; + + case at_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + == point) + goto fail; + break; + + case after_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + >= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + break; +#else + case wordchar: + PREFETCH; + if (SYNTAX (*d++) == 0) goto fail; + break; + + case notwordchar: + PREFETCH; + if (SYNTAX (*d++) != 0) goto fail; + break; +#endif /* not emacs */ + + case begbuf: + if (d == string1) /* Note, d cannot equal string2 */ + break; /* unless string1 == string2. */ + goto fail; + + case endbuf: + if (d == end2 || (d == end1 && size2 == 0)) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + if (translate) + { + do + { + PREFETCH; + if (translate[*d++] != *p++) goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH; + if (*d++ != *p++) goto fail; + } + while (--mcnt); + } + break; + case unused: + case before_dot: + case at_dot: + case after_dot: + case syntaxspec: + case notsyntaxspec: + default: + break; + } + continue; /* Successfully matched one pattern command; keep matching */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + if (!stackp[-2]) + { /* If innermost failure point is dormant, flush it and keep looking */ + stackp -= 2; + goto fail; + } + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else break; /* Matching at this starting point really fails! */ + } + return -1; /* Failure to match */ +} + +static int +memcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + unsigned char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate [*p1++] != translate [*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points compatible with bsd4.2 regex library */ + +#ifndef emacs + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + const char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) malloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0); +} + +#endif /* emacs */ + +#ifdef test + +#include + +/* Indexed by a character, gives the upper case equivalent of the character */ + +static char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atoi (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) malloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar_unfiltered ('\n'); + + printf_unfiltered ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf_unfiltered ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar_unfiltered ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf_unfiltered ("Match value %d.\n", i); + } +} + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf_unfiltered ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf_unfiltered ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf_unfiltered ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf_unfiltered ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf_unfiltered ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf_unfiltered ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif + +printchar (c) + char c; +{ + if (c < 041 || c >= 0177) + { + putchar_unfiltered ('\\'); + putchar_unfiltered (((c >> 6) & 3) + '0'); + putchar_unfiltered (((c >> 3) & 7) + '0'); + putchar_unfiltered ((c & 7) + '0'); + } + else + putchar_unfiltered (c); +} + +error (string) + char *string; +{ + puts_unfiltered (string); + exit (1); +} + +#endif /* test */ diff --git a/contrib/gdb/gdb/gnu-regex.h b/contrib/gdb/gdb/gnu-regex.h new file mode 100644 index 000000000000..7b1a4af20cd5 --- /dev/null +++ b/contrib/gdb/gdb/gnu-regex.h @@ -0,0 +1,181 @@ +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985, 1989 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif + +extern int re_set_syntax (); diff --git a/contrib/gdb/gdb/go32-xdep.c b/contrib/gdb/gdb/go32-xdep.c new file mode 100644 index 000000000000..01c817a6b41b --- /dev/null +++ b/contrib/gdb/gdb/go32-xdep.c @@ -0,0 +1,35 @@ +/* Host-dependent code for dos running GO32 for GDB, the GNU debugger. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include + +int +sigsetmask (mask) + int mask; +{ + return 0; +} + +void +strlwr (str) + char *str; +{ + for (; *str; str++) + *str = tolower(*str); +} diff --git a/contrib/gdb/gdb/i386-stub.c b/contrib/gdb/gdb/i386-stub.c new file mode 100644 index 000000000000..ce53c48b69e1 --- /dev/null +++ b/contrib/gdb/gdb/i386-stub.c @@ -0,0 +1,915 @@ +/**************************************************************************** + + 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. + * Also, need to assign exceptionHook and oldExceptionHook. + * + * 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 + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +extern putDebugChar(); /* write a single character */ +extern getDebugChar(); /* read and return a single char */ + +extern Function exceptionHandler(); /* assign an exception handler */ +extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ + +/************************************************************************/ +/* 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 */ + +void waitabit(); + +static const char hexchars[]="0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +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[NUMREGBYTES/4]; + +#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; + +/*************************** 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); +} + + +/* scan for the sequence $# */ +void getpacket(buffer) +char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$'); + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug ) && (checksum != xmitcsum)) { + fprintf (stderr ,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum,xmitcsum,buffer); + } + + 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] ); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + +} + +/* 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]) { + if (! putDebugChar(ch)) return; + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + + } while ((getDebugChar() & 0x7f) != '+'); + +} + +char remcomInBuffer[BUFMAX]; +char remcomOutBuffer[BUFMAX]; +static short error; + + +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 () +{ + 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 (addr) + char *addr; +{ + return *addr; +} + +void +set_char (addr, val) + 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> 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=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; + 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 ); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1==1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + 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(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0); + strcpy(remcomOutBuffer,"OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm' : + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + 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"); + debug_error("malformed read memory command: %s",remcomInBuffer); + } + 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 */ + ptr = &remcomInBuffer[1]; + 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"); + debug_error("malformed write memory command: %s",remcomInBuffer); + } + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + 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 (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100; + + /* + * 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 0 + /* Don't really think we need this, except maybe for protection + exceptions. */ + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[ PC ]; /* pc may have changed */ +#endif /* 0 */ + + _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() +{ +extern void remcomHandler(); +int exception; + + 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); + + if (exceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. */ + putDebugChar ('+'); + + 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) +#if 0 + handle_exception(3); +#else + BREAKPOINT(); +#endif + waitabit(); +} + +int waitlimit = 1000000; + +#if 0 +void +bogon() +{ + waitabit(); +} +#endif + +void +waitabit() +{ + int i; + for (i = 0; i < waitlimit; i++) ; +} diff --git a/contrib/gdb/gdb/i386-tdep.c b/contrib/gdb/gdb/i386-tdep.c new file mode 100644 index 000000000000..47be4b3ad563 --- /dev/null +++ b/contrib/gdb/gdb/i386-tdep.c @@ -0,0 +1,688 @@ +/* Intel 386 target-dependent stuff. + Copyright (C) 1988, 1989, 1991, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" +#include "floatformat.h" +#include "symtab.h" + +static long i386_get_frame_setup PARAMS ((CORE_ADDR)); + +static void i386_follow_jump PARAMS ((void)); + +static void codestream_read PARAMS ((unsigned char *, int)); + +static void codestream_seek PARAMS ((CORE_ADDR)); + +static unsigned char codestream_fill PARAMS ((int)); + +/* Stdio style buffering was used to minimize calls to ptrace, but this + buffering did not take into account that the code section being accessed + may not be an even number of buffers long (even if the buffer is only + sizeof(int) long). In cases where the code section size happened to + be a non-integral number of buffers long, attempting to read the last + buffer would fail. Simply using target_read_memory and ignoring errors, + rather than read_memory, is not the correct solution, since legitimate + access errors would then be totally ignored. To properly handle this + situation and continue to use buffering would require that this code + be able to determine the minimum code section size granularity (not the + alignment of the section itself, since the actual failing case that + pointed out this problem had a section alignment of 4 but was not a + multiple of 4 bytes long), on a target by target basis, and then + adjust it's buffer size accordingly. This is messy, but potentially + feasible. It probably needs the bfd library's help and support. For + now, the buffer size is set to 1. (FIXME -fnf) */ + +#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */ +static CORE_ADDR codestream_next_addr; +static CORE_ADDR codestream_addr; +static unsigned char codestream_buf[CODESTREAM_BUFSIZ]; +static int codestream_off; +static int codestream_cnt; + +#define codestream_tell() (codestream_addr + codestream_off) +#define codestream_peek() (codestream_cnt == 0 ? \ + codestream_fill(1): codestream_buf[codestream_off]) +#define codestream_get() (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + +static unsigned char +codestream_fill (peek_flag) + int peek_flag; +{ + codestream_addr = codestream_next_addr; + codestream_next_addr += CODESTREAM_BUFSIZ; + codestream_off = 0; + codestream_cnt = CODESTREAM_BUFSIZ; + read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ); + + if (peek_flag) + return (codestream_peek()); + else + return (codestream_get()); +} + +static void +codestream_seek (place) + CORE_ADDR place; +{ + codestream_next_addr = place / CODESTREAM_BUFSIZ; + codestream_next_addr *= CODESTREAM_BUFSIZ; + codestream_cnt = 0; + codestream_fill (1); + while (codestream_tell() != place) + codestream_get (); +} + +static void +codestream_read (buf, count) + unsigned char *buf; + int count; +{ + unsigned char *p; + int i; + p = buf; + for (i = 0; i < count; i++) + *p++ = codestream_get (); +} + +/* next instruction is a jump, move to target */ + +static void +i386_follow_jump () +{ + unsigned char buf[4]; + long delta; + + int data16; + CORE_ADDR pos; + + pos = codestream_tell (); + + data16 = 0; + if (codestream_peek () == 0x66) + { + codestream_get (); + data16 = 1; + } + + switch (codestream_get ()) + { + case 0xe9: + /* relative jump: if data16 == 0, disp32, else disp16 */ + if (data16) + { + codestream_read (buf, 2); + delta = extract_signed_integer (buf, 2); + + /* include size of jmp inst (including the 0x66 prefix). */ + pos += delta + 4; + } + else + { + codestream_read (buf, 4); + delta = extract_signed_integer (buf, 4); + + pos += delta + 5; + } + break; + case 0xeb: + /* relative jump, disp8 (ignore data16) */ + codestream_read (buf, 1); + /* Sign-extend it. */ + delta = extract_signed_integer (buf, 1); + + pos += delta + 2; + break; + } + codestream_seek (pos); +} + +/* + * find & return amound a local space allocated, and advance codestream to + * first register push (if any) + * + * if entry sequence doesn't make sense, return -1, and leave + * codestream pointer random + */ + +static long +i386_get_frame_setup (pc) + CORE_ADDR pc; +{ + unsigned char op; + + codestream_seek (pc); + + i386_follow_jump (); + + op = codestream_get (); + + if (op == 0x58) /* popl %eax */ + { + /* + * this function must start with + * + * popl %eax 0x58 + * xchgl %eax, (%esp) 0x87 0x04 0x24 + * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + * + * (the system 5 compiler puts out the second xchg + * inst, and the assembler doesn't try to optimize it, + * so the 'sib' form gets generated) + * + * this sequence is used to get the address of the return + * buffer for a function that returns a structure + */ + int pos; + unsigned char buf[4]; + static unsigned char proto1[3] = { 0x87,0x04,0x24 }; + static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + pos = codestream_tell (); + codestream_read (buf, 4); + if (memcmp (buf, proto1, 3) == 0) + pos += 3; + else if (memcmp (buf, proto2, 4) == 0) + pos += 4; + + codestream_seek (pos); + op = codestream_get (); /* update next opcode */ + } + + if (op == 0x55) /* pushl %ebp */ + { + /* check for movl %esp, %ebp - can be written two ways */ + switch (codestream_get ()) + { + case 0x8b: + if (codestream_get () != 0xec) + return (-1); + break; + case 0x89: + if (codestream_get () != 0xe5) + return (-1); + break; + default: + return (-1); + } + /* check for stack adjustment + * + * subl $XXX, %esp + * + * note: you can't subtract a 16 bit immediate + * from a 32 bit reg, so we don't have to worry + * about a data16 prefix + */ + op = codestream_peek (); + if (op == 0x83) + { + /* subl with 8 bit immed */ + codestream_get (); + if (codestream_get () != 0xec) + /* Some instruction starting with 0x83 other than subl. */ + { + codestream_seek (codestream_tell () - 2); + return 0; + } + /* subl with signed byte immediate + * (though it wouldn't make sense to be negative) + */ + return (codestream_get()); + } + else if (op == 0x81) + { + char buf[4]; + /* Maybe it is subl with 32 bit immedediate. */ + codestream_get(); + if (codestream_get () != 0xec) + /* Some instruction starting with 0x81 other than subl. */ + { + codestream_seek (codestream_tell () - 2); + return 0; + } + /* It is subl with 32 bit immediate. */ + codestream_read ((unsigned char *)buf, 4); + return extract_signed_integer (buf, 4); + } + else + { + return (0); + } + } + else if (op == 0xc8) + { + char buf[2]; + /* enter instruction: arg is 16 bit unsigned immed */ + codestream_read ((unsigned char *)buf, 2); + codestream_get (); /* flush final byte of enter instruction */ + return extract_unsigned_integer (buf, 2); + } + return (-1); +} + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +int +i386_frame_num_args (fi) + struct frame_info *fi; +{ +#if 1 + return -1; +#else + /* This loses because not only might the compiler not be popping the + args right after the function call, it might be popping args from both + this call and a previous one, and we would say there are more args + than there really are. */ + + int retpc; + unsigned char op; + struct frame_info *pfi; + + /* on the 386, the instruction following the call could be: + popl %ecx - one arg + addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits + anything else - zero args */ + + int frameless; + + FRAMELESS_FUNCTION_INVOCATION (fi, frameless); + if (frameless) + /* In the absence of a frame pointer, GDB doesn't get correct values + for nameless arguments. Return -1, so it doesn't print any + nameless arguments. */ + return -1; + + pfi = get_prev_frame_info (fi); + if (pfi == 0) + { + /* Note: this can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into + start. If we have debugging symbols, that's not really + a big deal; it just means it will only show as many arguments + to main as are declared. */ + return -1; + } + else + { + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) + /* pop %ecx */ + return 1; + else if (op == 0x83) + { + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return (read_memory_integer (retpc+2,1)&0xff)/4; + else + return 0; + } + else if (op == 0x81) + { /* add with 32 bit immediate */ + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return read_memory_integer (retpc+2, 4) / 4; + else + return 0; + } + else + { + return 0; + } + } +#endif +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +void +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + long locals; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + memset (fsrp, 0, sizeof *fsrp); + + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame; + for (i = 0; i < NUM_REGS; i++) + { + adr -= REGISTER_RAW_SIZE (i); + fsrp->regs[i] = adr; + } + return; + } + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; +#ifdef I386_REGNO_TO_SYMMETRY + /* Dynix uses different internal numbering. Ick. */ + fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr; +#else + fsrp->regs[op - 0x50] = adr; +#endif + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +/* return pc of first real instruction */ + +int +i386_skip_prologue (pc) + int pc; +{ + unsigned char op; + int i; + static unsigned char pic_pat[6] = { 0xe8, 0, 0, 0, 0, /* call 0x0 */ + 0x5b, /* popl %ebx */ + }; + CORE_ADDR pos; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + /* The native cc on SVR4 in -K PIC mode inserts the following code to get + the address of the global offset table (GOT) into register %ebx. + call 0x0 + popl %ebx + movl %ebx,x(%ebp) (optional) + addl y,%ebx + This code is with the rest of the prologue (at the end of the + function), so we have to skip it to get to the first real + instruction at the start of the function. */ + + pos = codestream_tell (); + for (i = 0; i < 6; i++) + { + op = codestream_get (); + if (pic_pat [i] != op) + break; + } + if (i == 6) + { + unsigned char buf[4]; + long delta = 6; + + op = codestream_get (); + if (op == 0x89) /* movl %ebx, x(%ebp) */ + { + op = codestream_get (); + if (op == 0x5d) /* one byte offset from %ebp */ + { + delta += 3; + codestream_read (buf, 1); + } + else if (op == 0x9d) /* four byte offset from %ebp */ + { + delta += 6; + codestream_read (buf, 4); + } + else /* unexpected instruction */ + delta = -1; + op = codestream_get (); + } + /* addl y,%ebx */ + if (delta > 0 && op == 0x81 && codestream_get () == 0xc3) + { + pos += delta + 6; + } + } + codestream_seek (pos); + + i386_follow_jump (); + + return (codestream_tell ()); +} + +void +i386_push_dummy_frame () +{ + CORE_ADDR sp = read_register (SP_REGNUM); + int regnum; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + sp = push_word (sp, read_register (PC_REGNUM)); + sp = push_word (sp, read_register (FP_REGNUM)); + write_register (FP_REGNUM, sp); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + read_register_gen (regnum, regbuf); + sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum)); + } + write_register (SP_REGNUM, sp); +} + +void +i386_pop_frame () +{ + struct frame_info *frame = get_current_frame (); + CORE_ADDR fp; + int regnum; + struct frame_saved_regs fsr; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + fp = FRAME_FP (frame); + get_frame_saved_regs (frame, &fsr); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + CORE_ADDR adr; + adr = fsr.regs[regnum]; + if (adr) + { + read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum)); + write_register_bytes (REGISTER_BYTE (regnum), regbuf, + REGISTER_RAW_SIZE (regnum)); + } + } + write_register (FP_REGNUM, read_memory_integer (fp, 4)); + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); + write_register (SP_REGNUM, fp + 8); + flush_cached_frames (); +} + +#ifdef GET_LONGJMP_TARGET + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target(pc) + CORE_ADDR *pc; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + CORE_ADDR sp, jb_addr; + + sp = read_register (SP_REGNUM); + + if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */ + buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + return 1; +} + +#endif /* GET_LONGJMP_TARGET */ + +void +i386_extract_return_value(type, regbuf, valbuf) + struct type *type; + char regbuf[REGISTER_BYTES]; + char *valbuf; +{ +/* On AIX, floating point values are returned in floating point registers. */ +#ifdef I386_AIX_TARGET + if (TYPE_CODE_FLT == TYPE_CODE(type)) + { + double d; + /* 387 %st(0), gcc uses this */ + floatformat_to_double (&floatformat_i387_ext, + ®buf[REGISTER_BYTE(FP0_REGNUM)], + &d); + store_floating (valbuf, TYPE_LENGTH (type), d); + } + else +#endif /* I386_AIX_TARGET */ + { + memcpy (valbuf, regbuf, TYPE_LENGTH (type)); + } +} + +#ifdef I386V4_SIGTRAMP_SAVED_PC +/* Get saved user PC for sigtramp from the pushed ucontext on the stack + for all three variants of SVR4 sigtramps. */ + +CORE_ADDR +i386v4_sigtramp_saved_pc (frame) + struct frame_info *frame; +{ + CORE_ADDR saved_pc_offset = 4; + char *name = NULL; + + find_pc_partial_function (frame->pc, &name, NULL, NULL); + if (name) + { + if (STREQ (name, "_sigreturn")) + saved_pc_offset = 132 + 14 * 4; + else if (STREQ (name, "_sigacthandler")) + saved_pc_offset = 80 + 14 * 4; + else if (STREQ (name, "sigvechandler")) + saved_pc_offset = 120 + 14 * 4; + } + + if (frame->next) + return read_memory_integer (frame->next->frame + saved_pc_offset, 4); + return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4); +} +#endif /* I386V4_SIGTRAMP_SAVED_PC */ + + + +/* Stuff for WIN32 PE style DLL's but is pretty generic really. */ + +CORE_ADDR +skip_trampoline_code (pc, name) + CORE_ADDR pc; + char *name; +{ + if (pc && read_memory_unsigned_integer (pc, 2) == 0x25ff) /* jmp *(dest) */ + { + unsigned long indirect = read_memory_unsigned_integer (pc+2, 4); + struct minimal_symbol *indsym = + indirect ? lookup_minimal_symbol_by_pc (indirect) : 0; + char *symname = indsym ? SYMBOL_NAME(indsym) : 0; + + if (symname) + { + if (strncmp (symname,"__imp_", 6) == 0 + || strncmp (symname,"_imp_", 5) == 0) + return name ? 1 : read_memory_unsigned_integer (indirect, 4); + } + } + return 0; /* not a trampoline */ +} + +void +_initialize_i386_tdep () +{ + tm_print_insn = print_insn_i386; +} diff --git a/contrib/gdb/gdb/i386aix-nat.c b/contrib/gdb/gdb/i386aix-nat.c new file mode 100644 index 000000000000..133109e653ec --- /dev/null +++ b/contrib/gdb/gdb/i386aix-nat.c @@ -0,0 +1,360 @@ +/* Intel 386 native support. + Copyright (C) 1988, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "language.h" +#include "gdbcore.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include "gdb_stat.h" + +#include +#include + +/* Does AIX define this in ? */ +extern int errno; + +#ifndef NO_SYS_REG_H +#include +#endif + +#include "floatformat.h" + +#include "target.h" + + +/* this table must line up with REGISTER_NAMES in tm-i386v.h */ +/* symbols like 'EAX' come from */ +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + USP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ + +int +i386_register_u_addr (blockend, regnum) + int blockend; + int regnum; +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); + +} + +/* The code below only work on the aix ps/2 (i386-ibm-aix) - + * mtranle@paris - Sat Apr 11 10:34:12 1992 + */ + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf_unfiltered ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf_unfiltered ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf_unfiltered ("last exception: "); + printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode)); + printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg)); + printf_unfiltered ("%s; ", local_hex_string(ep->eip)); + printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg)); + printf_unfiltered (":%s\n", local_hex_string(ep->operand)); + + top = ((ep->status >> 11) & 7); + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> ((7 - fpreg) * 2)) & 3) + { + case 0: printf_unfiltered ("valid "); break; + case 1: printf_unfiltered ("zero "); break; + case 2: printf_unfiltered ("trap "); break; + case 3: printf_unfiltered ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf_unfiltered ("%02x", ep->regs[fpreg][i]); + + i387_to_double ((char *)ep->regs[fpreg], (char *)&val); + printf_unfiltered (" %#g\n", val); + } +} + +static struct env387 core_env387; + +void +i386_float_info () +{ + struct env387 fps; + int fpsaved = 0; + /* We need to reverse the order of the registers. Apparently AIX stores + the highest-numbered ones first. */ + struct env387 fps_fixed; + int i; + + if (inferior_pid) + { + char buf[10]; + unsigned short status; + + ptrace (PT_READ_FPR, inferior_pid, buf, offsetof(struct env387, status)); + memcpy (&status, buf, sizeof (status)); + fpsaved = status; + } + else + { + if ((fpsaved = core_env387.status) != 0) + memcpy(&fps, &core_env387, sizeof(fps)); + } + + if (fpsaved == 0) + { + printf_unfiltered ("no floating point status saved\n"); + return; + } + + if (inferior_pid) + { + int offset; + for (offset = 0; offset < sizeof(fps); offset += 10) + { + char buf[10]; + ptrace (PT_READ_FPR, inferior_pid, buf, offset); + memcpy ((char *)&fps.control + offset, buf, + MIN(10, sizeof(fps) - offset)); + } + } + fps_fixed = fps; + for (i = 0; i < 8; ++i) + memcpy (fps_fixed.regs[i], fps.regs[7 - i], 10); + print_387_status (0, &fps_fixed); +} + +/* Fetch one register. */ +static void +fetch_register (regno) + int regno; +{ + char buf[MAX_REGISTER_RAW_SIZE]; + if (regno < FP0_REGNUM) + *(int *)buf = ptrace (PT_READ_GPR, inferior_pid, + PT_REG(regmap[regno]), 0, 0); + else + ptrace (PT_READ_FPR, inferior_pid, buf, + (regno - FP0_REGNUM)*10 + offsetof(struct env387, regs)); + supply_register (regno, buf); +} + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno < 0) + for (regno = 0; regno < NUM_REGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* store one register */ +static void +store_register (regno) + int regno; +{ + char buf[80]; + extern char registers[]; + errno = 0; + if (regno < FP0_REGNUM) + ptrace (PT_WRITE_GPR, inferior_pid, PT_REG(regmap[regno]), + *(int *) ®isters[REGISTER_BYTE (regno)], 0); + else + ptrace (PT_WRITE_FPR, inferior_pid, ®isters[REGISTER_BYTE (regno)], + (regno - FP0_REGNUM)*10 + offsetof(struct env387, regs)); + + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ +void +store_inferior_registers (regno) + int regno; +{ + if (regno < 0) + for (regno = 0; regno < NUM_REGS; regno++) + store_register (regno); + else + store_register (regno); +} + +#ifndef CD_AX /* defined in sys/i386/coredump.h */ +# define CD_AX 0 +# define CD_BX 1 +# define CD_CX 2 +# define CD_DX 3 +# define CD_SI 4 +# define CD_DI 5 +# define CD_BP 6 +# define CD_SP 7 +# define CD_FL 8 +# define CD_IP 9 +# define CD_CS 10 +# define CD_DS 11 +# define CD_ES 12 +# define CD_FS 13 +# define CD_GS 14 +# define CD_SS 15 +#endif + +/* + * The order here in core_regmap[] has to be the same as in + * regmap[] above. + */ +static int core_regmap[] = +{ + CD_AX, CD_CX, CD_DX, CD_BX, + CD_SP, CD_BP, CD_SI, CD_DI, + CD_IP, CD_FL, CD_CS, CD_SS, + CD_DS, CD_ES, CD_FS, CD_GS, +}; + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int reg_addr; /* ignored */ +{ + + if (which == 0) + { + /* Integer registers */ + +#define cd_regs(n) ((int *)core_reg_sect)[n] +#define regs(n) *((int *) ®isters[REGISTER_BYTE (n)]) + + int i; + for (i = 0; i < FP0_REGNUM; i++) + regs(i) = cd_regs(core_regmap[i]); + } + else if (which == 2) + { + /* Floating point registers */ + + if (core_reg_size >= sizeof (core_env387)) + memcpy (&core_env387, core_reg_sect, core_reg_size); + else + fprintf_unfiltered (gdb_stderr, "Couldn't read float regs from core file\n"); + } +} + + +/* Register that we are able to handle i386aix core file formats. + FIXME: is this really bfd_target_unknown_flavour? */ + +static struct core_fns i386aix_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_i386aix () +{ + add_core_fns (&i386aix_core_fns); +} diff --git a/contrib/gdb/gdb/i386b-nat.c b/contrib/gdb/gdb/i386b-nat.c new file mode 100644 index 000000000000..d273cabeeb3b --- /dev/null +++ b/contrib/gdb/gdb/i386b-nat.c @@ -0,0 +1,284 @@ +/* Native-dependent code for BSD Unix running on i386's, for GDB. + Copyright 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +#ifdef FETCH_INFERIOR_REGISTERS +#include +#include +#include +#include +#include "inferior.h" + +void +fetch_inferior_registers(regno) + int regno; +{ + struct reg inferior_registers; + + ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &inferior_registers, 0); + memcpy (®isters[REGISTER_BYTE (0)], &inferior_registers, 4*NUM_REGS); + registers_fetched (); +} + +void +store_inferior_registers(regno) + int regno; +{ + struct reg inferior_registers; + + memcpy (&inferior_registers, ®isters[REGISTER_BYTE (0)], 4*NUM_REGS); + ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &inferior_registers, 0); +} + +struct md_core { + struct reg intreg; + struct fpreg freg; +}; + +void +fetch_core_registers (core_reg_sect, core_reg_size, which, ignore) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int ignore; +{ + struct md_core *core_reg = (struct md_core *)core_reg_sect; + + /* integer registers */ + memcpy(®isters[REGISTER_BYTE (0)], &core_reg->intreg, + sizeof(struct reg)); + /* floating point registers */ + /* XXX */ +} + +#else + +#include + +/* this table must line up with REGISTER_NAMES in tm-i386.h */ +/* symbols like 'tEAX' come from */ +static int tregmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS +}; + +#ifdef sEAX +static int sregmap[] = +{ + sEAX, sECX, sEDX, sEBX, + sESP, sEBP, sESI, sEDI, + sEIP, sEFLAGS, sCS, sSS +}; +#else /* No sEAX */ + +/* FreeBSD has decided to collapse the s* and t* symbols. So if the s* + ones aren't around, use the t* ones for sregmap too. */ + +static int sregmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS +}; +#endif /* No sEAX */ + +/* blockend is the value of u.u_ar0, and points to the + place where ES is stored. */ + +int +i386_register_u_addr (blockend, regnum) + int blockend; + int regnum; +{ + /* The following condition is a kludge to get at the proper register map + depending upon the state of pcb_flag. + The proper condition would be + if (u.u_pcb.pcb_flag & FM_TRAP) + but that would require a ptrace call here and wouldn't work + for corefiles. */ + + if (blockend < 0x1fcc) + return (blockend + 4 * tregmap[regnum]); + else + return (blockend + 4 * sregmap[regnum]); +} + +#endif /* !FETCH_INFERIOR_REGISTERS */ + +#ifdef FLOAT_INFO +#include "language.h" /* for local_hex_string */ +#include "floatformat.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#include +#undef curpcb +#include +#include "gdb_stat.h" +#include + +extern void print_387_control_word (); /* i387-tdep.h */ +extern void print_387_status_word (); + +#define fpstate save87 +#define U_FPSTATE(u) u.u_pcb.pcb_savefpu + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static void +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf_unfiltered ("u: "); + print_387_status_word ((unsigned int)status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf_unfiltered ("e: "); + print_387_status_word ((unsigned int)ep->status); + } + + print_387_control_word ((unsigned int)ep->control); + printf_unfiltered ("last exception: "); + printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode)); + printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg)); + printf_unfiltered ("%s; ", local_hex_string(ep->eip)); + printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg)); + printf_unfiltered (":%s\n", local_hex_string(ep->operand)); + + top = (ep->status >> 11) & 7; + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf_unfiltered ("valid "); break; + case 1: printf_unfiltered ("zero "); break; + case 2: printf_unfiltered ("trap "); break; + case 3: printf_unfiltered ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf_unfiltered ("%02x", ep->regs[fpreg][i]); + + floatformat_to_double(&floatformat_i387_ext, (char *) ep->regs[fpreg], + &val); + printf_unfiltered (" %g\n", val); + } +} + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid; + unsigned int rounded_addr; + unsigned int rounded_size; + /*extern int corechan;*/ + int skip; + extern int inferior_pid; + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (inferior_pid) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0); + rounded_addr += sizeof (int); + } + } + else + { + printf("float info: can't do a core file (yet)\n"); + return; +#if 0 + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; +#endif + } + + print_387_status (0, (struct env387 *)buf); +} + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +#endif diff --git a/contrib/gdb/gdb/i386gnu-nat.c b/contrib/gdb/gdb/i386gnu-nat.c new file mode 100644 index 000000000000..63c3bd0d7d8a --- /dev/null +++ b/contrib/gdb/gdb/i386gnu-nat.c @@ -0,0 +1,348 @@ +/* Low level interface to I386 running the GNU Hurd + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "floatformat.h" + +#include + +#include +#include +#include +#include + +#include "gnu-nat.h" + +/* Hmmm... Should this not be here? + * Now for i386_float_info() target_has_execution + */ +#include + +/* @@@ Should move print_387_status() to i387-tdep.c */ +extern void print_387_control_word (); /* i387-tdep.h */ +extern void print_387_status_word (); + +/* Find offsets to thread states at compile time. + * If your compiler does not grok this, calculate offsets + * offsets yourself and use them (or get a compatible compiler :-) + */ + +#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg) + +/* at reg_offset[i] is the offset to the i386_thread_state + * location where the gdb registers[i] is stored. + */ + +static int reg_offset[] = +{ + REG_OFFSET(eax), REG_OFFSET(ecx), REG_OFFSET(edx), REG_OFFSET(ebx), + REG_OFFSET(uesp), REG_OFFSET(ebp), REG_OFFSET(esi), REG_OFFSET(edi), + REG_OFFSET(eip), REG_OFFSET(efl), REG_OFFSET(cs), REG_OFFSET(ss), + REG_OFFSET(ds), REG_OFFSET(es), REG_OFFSET(fs), REG_OFFSET(gs) +}; + +#define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum]) + +/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM + * Caller knows that the regs handled in one transaction are of same size. + */ +#define FETCH_REGS(state, regnum, count) \ + memcpy (®isters[REGISTER_BYTE (regnum)], \ + REG_ADDR (state, regnum), \ + count * REGISTER_RAW_SIZE (regnum)) + +/* Store COUNT contiguous registers to thread STATE starting from REGNUM */ +#define STORE_REGS(state, regnum, count) \ + memcpy (REG_ADDR (state, regnum), \ + ®isters[REGISTER_BYTE (regnum)], \ + count * REGISTER_RAW_SIZE (regnum)) + +/* + * Fetch inferiors registers for gdb. + * REG specifies which (as gdb views it) register, -1 for all. + */ +void +gnu_fetch_registers (int reg) +{ + thread_state_t state; + struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid); + + if (!thread) + error ("fetch inferior registers: %d: Invalid thread", inferior_pid); + + state = proc_get_state (thread, 0); + + if (! state) + warning ("Couldn't fetch register %s.", reg_names[reg]); + else if (reg >= 0) + { + proc_debug (thread, "fetching register: %s", reg_names[reg]); + supply_register (reg, REG_ADDR(state, reg)); + thread->fetched_regs |= (1 << reg); + } + else + { + proc_debug (thread, "fetching all registers"); + for (reg = 0; reg < NUM_REGS; reg++) + supply_register (reg, REG_ADDR(state, reg)); + thread->fetched_regs = ~0; + } +} + +/* Store our register values back into the inferior. + * If REG is -1, do this for all registers. + * Otherwise, REG specifies which register + * + * On mach3 all registers are always saved in one call. + */ +void +gnu_store_registers (reg) + int reg; +{ + int was_aborted, was_valid; + thread_state_t state; + thread_state_data_t old_state; + struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid); + + if (! thread) + error ("store inferior registers: %d: Invalid thread", inferior_pid); + + proc_debug (thread, "storing register %s.", reg_names[reg]); + + was_aborted = thread->aborted; + was_valid = thread->state_valid; + if (! was_aborted && was_valid) + bcopy (&thread->state, &old_state, sizeof (old_state)); + + state = proc_get_state (thread, 1); + + if (! state) + warning ("Couldn't store register %s.", reg_names[reg]); + else + { + if (! was_aborted && was_valid) + /* See which registers have changed after aborting the thread. */ + { + int check_reg; + for (check_reg = 0; check_reg < NUM_REGS; check_reg++) + if ((thread->fetched_regs & (1 << check_reg)) + && bcmp (REG_ADDR (&old_state, check_reg), + REG_ADDR (state, check_reg), + REGISTER_RAW_SIZE (check_reg))) + /* Register CHECK_REG has changed! Ack! */ + { + warning ("Register %s changed after thread was aborted.", + reg_names [check_reg]); + if (reg >= 0 && reg != check_reg) + /* Update gdb's copy of the register. */ + supply_register (check_reg, REG_ADDR (state, check_reg)); + else + warning ("... also writing this register! Suspicious..."); + } + } + + if (reg >= 0) + { + proc_debug (thread, "storing register: %s", reg_names[reg]); + STORE_REGS (state, reg, 1); + } + else + { + proc_debug (thread, "storing all registers"); + for (reg = 0; reg < NUM_REGS; reg++) + STORE_REGS (state, reg, 1); + } + } +} + +/* jtv@hut.fi: I copied and modified this 387 code from + * gdb/i386-xdep.c. Modifications for Mach 3.0. + * + * i387 status dumper. See also i387-tdep.c + */ +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; +/* This routine is machine independent? + * Should move it to i387-tdep.c but you need to export struct env387 + */ +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf_unfiltered ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf_unfiltered ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf_unfiltered ("last exception: "); + printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode)); + printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg)); + printf_unfiltered ("%s; ", local_hex_string(ep->eip)); + printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg)); + printf_unfiltered (":%s\n", local_hex_string(ep->operand)); + + top = (ep->status >> 11) & 7; + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf_unfiltered ("valid "); break; + case 1: printf_unfiltered ("zero "); break; + case 2: printf_unfiltered ("trap "); break; + case 3: printf_unfiltered ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf_unfiltered ("%02x", ep->regs[fpreg][i]); + + floatformat_to_double (&floatformat_i387_ext, (char *)ep->regs[fpreg], + &val); + printf_unfiltered (" %g\n", val); + } + if (ep->r0) + printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string(ep->r0)); + if (ep->r1) + printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string(ep->r1)); + if (ep->r2) + printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string(ep->r2)); + if (ep->r3) + printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string(ep->r3)); +} + +/* + * values that go into fp_kind (from ) + */ +#define FP_NO 0 /* no fp chip, no emulator (no fp support) */ +#define FP_SW 1 /* no fp chip, using software emulator */ +#define FP_HW 2 /* chip present bit */ +#define FP_287 2 /* 80287 chip present */ +#define FP_387 3 /* 80387 chip present */ + +typedef struct fpstate { +#if 1 + unsigned char state[FP_STATE_BYTES]; /* "hardware" state */ +#else + struct env387 state; /* Actually this */ +#endif + int status; /* Duplicate status */ +} *fpstate_t; + +/* Mach 3 specific routines. + */ +static int +get_i387_state (fstate) + struct fpstate *fstate; +{ + error_t err; + thread_state_data_t state; + unsigned int fsCnt = i386_FLOAT_STATE_COUNT; + struct i386_float_state *fsp; + struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid); + + if (!thread) + error ("get_i387_state: Invalid thread"); + + proc_abort (thread, 0); /* Make sure THREAD's in a reasonable state. */ + + err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt); + if (err) + { + warning ("Can not get live floating point state: %s", + mach_error_string (err)); + return 0; + } + + fsp = (struct i386_float_state *)state; + /* The 387 chip (also 486 counts) or a software emulator? */ + if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW)) + return 0; + + /* Clear the target then copy thread's float state there. + Make a copy of the status word, for some reason? + */ + memset (fstate, 0, sizeof (struct fpstate)); + + fstate->status = fsp->exc_status; + + memcpy (fstate->state, (char *)&fsp->hw_state, FP_STATE_BYTES); + + return 1; +} + +/* + * This is called by "info float" command + */ +void +i386_mach3_float_info() +{ + char buf [sizeof (struct fpstate) + 2 * sizeof (int)]; + int valid = 0; + fpstate_t fps; + + if (target_has_execution) + valid = get_i387_state (buf); + + if (!valid) + { + warning ("no floating point status saved"); + return; + } + + fps = (fpstate_t) buf; + + print_387_status (fps->status, (struct env387 *)fps->state); +} diff --git a/contrib/gdb/gdb/i386ly-tdep.c b/contrib/gdb/gdb/i386ly-tdep.c new file mode 100644 index 000000000000..dcb4584f749d --- /dev/null +++ b/contrib/gdb/gdb/i386ly-tdep.c @@ -0,0 +1,42 @@ +/* Target-dependent code for Intel 386 running LynxOS. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "target.h" + +/* Return the PC of the caller from the call frame. Assumes the subr prologue + has already been executed, and the frame pointer setup. If this is the + outermost frame, we check to see if we are in a system call by examining the + previous instruction. If so, then the return PC is actually at SP+4 because + system calls use a different calling sequence. */ + +CORE_ADDR +i386lynx_saved_pc_after_call (frame) + struct frame_info *frame; +{ + char opcode[7]; + static const unsigned char call_inst[] = {0x9a, 0, 0, 0, 0, 8, 0}; /* lcall 0x8,0x0 */ + + read_memory (frame->pc - 7, opcode, 7); + if (memcmp (opcode, call_inst, 7) == 0) + return read_memory_integer (read_register (SP_REGNUM) + 4, 4); + + return read_memory_integer (read_register (SP_REGNUM), 4); +} diff --git a/contrib/gdb/gdb/i386m3-nat.c b/contrib/gdb/gdb/i386m3-nat.c new file mode 100644 index 000000000000..bbaa022f3fad --- /dev/null +++ b/contrib/gdb/gdb/i386m3-nat.c @@ -0,0 +1,421 @@ +/* Low level interface to I386 running mach 3.0. + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "floatformat.h" + +#include + +#include +#include +#include +#include + +/* Hmmm... Should this not be here? + * Now for i386_float_info() target_has_execution + */ +#include + +/* This mess is duplicated in bfd/i386mach3.h + * + * This is an ugly way to hack around the incorrect + * definition of UPAGES in i386/machparam.h. + * + * The definition should specify the size reserved + * for "struct user" in core files in PAGES, + * but instead it gives it in 512-byte core-clicks + * for i386 and i860. + */ +#include +#if UPAGES == 16 +#define UAREA_SIZE ctob(UPAGES) +#elif UPAGES == 2 +#define UAREA_SIZE (NBPG*UPAGES) +#else +FIXME!! UPAGES is neither 2 nor 16 +#endif + +/* @@@ Should move print_387_status() to i387-tdep.c */ +extern void print_387_control_word (); /* i387-tdep.h */ +extern void print_387_status_word (); + +#define private static + + +/* Find offsets to thread states at compile time. + * If your compiler does not grok this, calculate offsets + * offsets yourself and use them (or get a compatible compiler :-) + */ + +#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg) + +/* at reg_offset[i] is the offset to the i386_thread_state + * location where the gdb registers[i] is stored. + */ + +static int reg_offset[] = +{ + REG_OFFSET(eax), REG_OFFSET(ecx), REG_OFFSET(edx), REG_OFFSET(ebx), + REG_OFFSET(uesp), REG_OFFSET(ebp), REG_OFFSET(esi), REG_OFFSET(edi), + REG_OFFSET(eip), REG_OFFSET(efl), REG_OFFSET(cs), REG_OFFSET(ss), + REG_OFFSET(ds), REG_OFFSET(es), REG_OFFSET(fs), REG_OFFSET(gs) +}; + +#define REG_ADDRESS(state,regnum) ((char *)(state)+reg_offset[regnum]) + +/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM + * Caller knows that the regs handled in one transaction are of same size. + */ +#define FETCH_REGS(state, regnum, count) \ + memcpy (®isters[REGISTER_BYTE (regnum)], \ + REG_ADDRESS (state, regnum), \ + count*REGISTER_SIZE) + +/* Store COUNT contiguous registers to thread STATE starting from REGNUM */ +#define STORE_REGS(state, regnum, count) \ + memcpy (REG_ADDRESS (state, regnum), \ + ®isters[REGISTER_BYTE (regnum)], \ + count*REGISTER_SIZE) + +/* + * Fetch inferiors registers for gdb. + * REGNO specifies which (as gdb views it) register, -1 for all. + */ + +void +fetch_inferior_registers (regno) + int regno; +{ + kern_return_t ret; + thread_state_data_t state; + unsigned int stateCnt = i386_THREAD_STATE_COUNT; + int index; + + if (! MACH_PORT_VALID (current_thread)) + error ("fetch inferior registers: Invalid thread"); + + if (must_suspend_thread) + setup_thread (current_thread, 1); + + ret = thread_get_state (current_thread, + i386_THREAD_STATE, + state, + &stateCnt); + + if (ret != KERN_SUCCESS) + warning ("fetch_inferior_registers: %s ", + mach_error_string (ret)); +#if 0 + /* It may be more effective to store validate all of them, + * since we fetched them all anyway + */ + else if (regno != -1) + supply_register (regno, (char *)state+reg_offset[regno]); +#endif + else + { + for (index = 0; index < NUM_REGS; index++) + supply_register (index, (char *)state+reg_offset[index]); + } + + if (must_suspend_thread) + setup_thread (current_thread, 0); +} + +/* Store our register values back into the inferior. + * If REGNO is -1, do this for all registers. + * Otherwise, REGNO specifies which register + * + * On mach3 all registers are always saved in one call. + */ +void +store_inferior_registers (regno) + int regno; +{ + kern_return_t ret; + thread_state_data_t state; + unsigned int stateCnt = i386_THREAD_STATE_COUNT; + register int index; + + if (! MACH_PORT_VALID (current_thread)) + error ("store inferior registers: Invalid thread"); + + if (must_suspend_thread) + setup_thread (current_thread, 1); + + /* Fetch the state of the current thread */ + ret = thread_get_state (current_thread, + i386_THREAD_STATE, + state, + &stateCnt); + + if (ret != KERN_SUCCESS) + { + warning ("store_inferior_registers (get): %s", + mach_error_string (ret)); + if (must_suspend_thread) + setup_thread (current_thread, 0); + return; + } + + /* move gdb's registers to thread's state + * + * Since we save all registers anyway, save the ones + * that gdb thinks are valid (e.g. ignore the regno + * parameter) + */ +#if 0 + if (regno != -1) + STORE_REGS (state, regno, 1); + else +#endif + { + for (index = 0; index < NUM_REGS; index++) + STORE_REGS (state, index, 1); + } + + /* Write gdb's current view of register to the thread + */ + ret = thread_set_state (current_thread, + i386_THREAD_STATE, + state, + i386_THREAD_STATE_COUNT); + + if (ret != KERN_SUCCESS) + warning ("store_inferior_registers (set): %s", + mach_error_string (ret)); + + if (must_suspend_thread) + setup_thread (current_thread, 0); +} + + + +/* Return the address in the core dump or inferior of register REGNO. + * BLOCKEND should be the address of the end of the UPAGES area read + * in memory, but it's not? + * + * Currently our UX server dumps the whole thread state to the + * core file. If your UX does something else, adapt the routine + * below to return the offset to the given register. + * + * Called by core-aout.c(fetch_core_registers) + */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + unsigned int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + + /* UAREA_SIZE == 8 kB in i386 */ + addr = (unsigned int)REG_ADDRESS (UAREA_SIZE - sizeof(struct i386_thread_state), regno); + + return addr; +} + +/* jtv@hut.fi: I copied and modified this 387 code from + * gdb/i386-xdep.c. Modifications for Mach 3.0. + * + * i387 status dumper. See also i387-tdep.c + */ +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; +/* This routine is machine independent? + * Should move it to i387-tdep.c but you need to export struct env387 + */ +private +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf_unfiltered ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf_unfiltered ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf_unfiltered ("last exception: "); + printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode)); + printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg)); + printf_unfiltered ("%s; ", local_hex_string(ep->eip)); + printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg)); + printf_unfiltered (":%s\n", local_hex_string(ep->operand)); + + top = (ep->status >> 11) & 7; + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf_unfiltered ("valid "); break; + case 1: printf_unfiltered ("zero "); break; + case 2: printf_unfiltered ("trap "); break; + case 3: printf_unfiltered ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf_unfiltered ("%02x", ep->regs[fpreg][i]); + + floatformat_to_double (&floatformat_i387_ext, (char *)ep->regs[fpreg], + &val); + printf_unfiltered (" %g\n", val); + } + if (ep->r0) + printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string(ep->r0)); + if (ep->r1) + printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string(ep->r1)); + if (ep->r2) + printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string(ep->r2)); + if (ep->r3) + printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string(ep->r3)); +} + +/* + * values that go into fp_kind (from ) + */ +#define FP_NO 0 /* no fp chip, no emulator (no fp support) */ +#define FP_SW 1 /* no fp chip, using software emulator */ +#define FP_HW 2 /* chip present bit */ +#define FP_287 2 /* 80287 chip present */ +#define FP_387 3 /* 80387 chip present */ + +typedef struct fpstate { +#if 1 + unsigned char state[FP_STATE_BYTES]; /* "hardware" state */ +#else + struct env387 state; /* Actually this */ +#endif + int status; /* Duplicate status */ +} *fpstate_t; + +/* Mach 3 specific routines. + */ +private boolean_t +get_i387_state (fstate) + struct fpstate *fstate; +{ + kern_return_t ret; + thread_state_data_t state; + unsigned int fsCnt = i386_FLOAT_STATE_COUNT; + struct i386_float_state *fsp; + + ret = thread_get_state (current_thread, + i386_FLOAT_STATE, + state, + &fsCnt); + + if (ret != KERN_SUCCESS) + { + warning ("Can not get live floating point state: %s", + mach_error_string (ret)); + return FALSE; + } + + fsp = (struct i386_float_state *)state; + /* The 387 chip (also 486 counts) or a software emulator? */ + if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW)) + return FALSE; + + /* Clear the target then copy thread's float state there. + Make a copy of the status word, for some reason? + */ + memset (fstate, 0, sizeof (struct fpstate)); + + fstate->status = fsp->exc_status; + + memcpy (fstate->state, (char *)&fsp->hw_state, FP_STATE_BYTES); + + return TRUE; +} + +private boolean_t +get_i387_core_state (fstate) + struct fpstate *fstate; +{ + /* Not implemented yet. Core files do not contain float state. */ + return FALSE; +} + +/* + * This is called by "info float" command + */ +void +i386_mach3_float_info() +{ + char buf [sizeof (struct fpstate) + 2 * sizeof (int)]; + boolean_t valid = FALSE; + fpstate_t fps; + + if (target_has_execution) + valid = get_i387_state (buf); +#if 0 + else if (WE HAVE CORE FILE) /* @@@@ Core files not supported */ + valid = get_i387_core_state (buf); +#endif + + if (!valid) + { + warning ("no floating point status saved"); + return; + } + + fps = (fpstate_t) buf; + + print_387_status (fps->status, (struct env387 *)fps->state); +} diff --git a/contrib/gdb/gdb/i386mach-nat.c b/contrib/gdb/gdb/i386mach-nat.c new file mode 100644 index 000000000000..1a5904a13078 --- /dev/null +++ b/contrib/gdb/gdb/i386mach-nat.c @@ -0,0 +1,163 @@ +/* Native dependent code for Mach 386's for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "gdb_stat.h" +#include + + + +void +fetch_inferior_registers (regno) + int regno; /* Original value discarded */ +{ + struct regs inferior_registers; + struct fp_state inferior_fp_registers; + extern char registers[]; + + registers_fetched (); + + ptrace (PTRACE_GETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers); + + memcpy (registers, &inferior_registers, sizeof inferior_registers); + + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], + inferior_fp_registers.f_st, + sizeof inferior_fp_registers.f_st); + memcpy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.f_ctrl, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + struct regs inferior_registers; + struct fp_state inferior_fp_registers; + extern char registers[]; + + memcpy (&inferior_registers, registers, 20 * 4); + + memcpy (inferior_fp_registers.f_st,®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.f_st); + memcpy (&inferior_fp_registers.f_ctrl, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st); + +#ifdef PTRACE_FP_BUG + if (regno == FP_REGNUM || regno == -1) + /* Storing the frame pointer requires a gross hack, in which an + instruction that moves eax into ebp gets single-stepped. */ + { + int stack = inferior_registers.r_reg[SP_REGNUM]; + int stuff = ptrace (PTRACE_PEEKDATA, inferior_pid, + (PTRACE_ARG3_TYPE) stack); + int reg = inferior_registers.r_reg[EAX]; + inferior_registers.r_reg[EAX] = + inferior_registers.r_reg[FP_REGNUM]; + ptrace (PTRACE_SETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers); + ptrace (PTRACE_POKEDATA, inferior_pid, (PTRACE_ARG3_TYPE) stack, 0xc589); + ptrace (PTRACE_SINGLESTEP, inferior_pid, (PTRACE_ARG3_TYPE) stack, 0); + wait (0); + ptrace (PTRACE_POKEDATA, inferior_pid, (PTRACE_ARG3_TYPE) stack, stuff); + inferior_registers.r_reg[EAX] = reg; + } +#endif + ptrace (PTRACE_SETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers); + ptrace (PTRACE_SETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers); +} + + + +/* Work with core files, for GDB. */ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int reg_addr; /* Unused in this version */ +{ + int val; + extern char registers[]; + + switch (which) { + case 0: + case 1: + memcpy (registers, core_reg_sect, core_reg_size); + break; + + case 2: +#ifdef FP0_REGNUM + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], + core_reg_sect, + core_reg_size); /* FIXME, probably bogus */ +#endif +#ifdef FPC_REGNUM + memcpy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &corestr.c_fpu.f_fpstatus.f_ctrl, + sizeof corestr.c_fpu.f_fpstatus - + sizeof corestr.c_fpu.f_fpstatus.f_st); +#endif + break; + } +} + + +/* Register that we are able to handle i386mach core file formats. + FIXME: is this really bfd_target_unknown_flavour? */ + +static struct core_fns i386mach_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_i386mach () +{ + add_core_fns (&i386mach_core_fns); +} diff --git a/contrib/gdb/gdb/i386v-nat.c b/contrib/gdb/gdb/i386v-nat.c new file mode 100644 index 000000000000..38468a90277e --- /dev/null +++ b/contrib/gdb/gdb/i386v-nat.c @@ -0,0 +1,371 @@ +/* Intel 386 native support for SYSV systems (pre-SVR4). + Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "language.h" +#include "gdbcore.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS +#include +#endif + +#include +#include "gdb_stat.h" + +#ifndef NO_SYS_REG_H +#include +#endif + +#include "floatformat.h" + +#include "target.h" + + +/* this table must line up with REGISTER_NAMES in tm-i386v.h */ +/* symbols like 'EAX' come from */ +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + UESP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ + +int +i386_register_u_addr (blockend, regnum) + int blockend; + int regnum; +{ + struct user u; + int fpstate; + int ubase; + + ubase = blockend; + /* FIXME: Should have better way to test floating point range */ + if (regnum >= FP0_REGNUM && regnum <= (FP0_REGNUM + 7)) + { +#ifdef KSTKSZ /* SCO, and others? */ + ubase += 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fps.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); +#else + fpstate = ubase + ((char *)&u.i387.st_space - (char *)&u); + return (fpstate + 10 * (regnum - FP0_REGNUM)); +#endif + } + else + { + return (ubase + 4 * regmap[regnum]); + } + +} + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* Record the value of the debug control register. */ +static int debug_control_mirror; + +/* Record which address associates with which register. */ +static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1]; + +static int +i386_insert_aligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int, + int)); + +static int +i386_insert_nonaligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int, + int)); + +/* Insert a watchpoint. */ + +int +i386_insert_watchpoint (pid, addr, len, rw) + int pid; + CORE_ADDR addr; + int len; + int rw; +{ + return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw); +} + +static int +i386_insert_aligned_watchpoint (pid, waddr, addr, len, rw) + int pid; + CORE_ADDR waddr; + CORE_ADDR addr; + int len; + int rw; +{ + int i; + int read_write_bits, len_bits; + int free_debug_register; + int register_number; + + /* Look for a free debug register. */ + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + if (address_lookup[i - DR_FIRSTADDR] == 0) + break; + } + + /* No more debug registers! */ + if (i > DR_LASTADDR) + return -1; + + read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0); + + if (len == 1) + len_bits = DR_LEN_1; + else if (len == 2) + { + if (addr % 2) + return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); + len_bits = DR_LEN_2; + } + + else if (len == 4) + { + if (addr % 4) + return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); + len_bits = DR_LEN_4; + } + else + return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw); + + free_debug_register = i; + register_number = free_debug_register - DR_FIRSTADDR; + debug_control_mirror |= + ((read_write_bits | len_bits) + << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number)); + debug_control_mirror |= + (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); + debug_control_mirror |= DR_LOCAL_SLOWDOWN; + debug_control_mirror &= ~DR_CONTROL_RESERVED; + + ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), + debug_control_mirror); + ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]), + addr); + + /* Record where we came from. */ + address_lookup[register_number] = addr; + return 0; +} + +static int +i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw) + int pid; + CORE_ADDR waddr; + CORE_ADDR addr; + int len; + int rw; +{ + int align; + int size; + int rv; + + static int size_try_array[16] = { + 1, 1, 1, 1, /* trying size one */ + 2, 1, 2, 1, /* trying size two */ + 2, 1, 2, 1, /* trying size three */ + 4, 1, 2, 1 /* trying size four */ + }; + + rv = 0; + while (len > 0) + { + align = addr % 4; + /* Four is the maximum length for 386. */ + size = (len > 4) ? 3 : len - 1; + size = size_try_array[size * 4 + align]; + + rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw); + if (rv) + { + i386_remove_watchpoint (pid, waddr, size); + return rv; + } + addr += size; + len -= size; + } + return rv; +} + +/* Remove a watchpoint. */ + +int +i386_remove_watchpoint (pid, addr, len) + int pid; + CORE_ADDR addr; + int len; +{ + int i; + int register_number; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + register_number = i - DR_FIRSTADDR; + if (address_lookup[register_number] == addr) + { + debug_control_mirror &= + ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); + address_lookup[register_number] = 0; + } + } + ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), + debug_control_mirror); + ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + + return 0; +} + +/* Check if stopped by a watchpoint. */ + +CORE_ADDR +i386_stopped_by_watchpoint (pid) + int pid; +{ + int i; + int status; + + status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + if (status & (1 << (i - DR_FIRSTADDR))) + return address_lookup[i - DR_FIRSTADDR]; + } + + return 0; +} + +#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */ + +#if 0 +/* using FLOAT_INFO as is would be a problem. FLOAT_INFO is called + via a command xxx and eventually calls ptrace without ever having + traversed the target vector. This would be terribly impolite + behaviour for a sun4 hosted remote gdb. + + A fix might be to move this code into the "info registers" command. + rich@cygnus.com 15 Sept 92. */ +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid = 0; + unsigned int rounded_addr; + unsigned int rounded_size; + extern int corechan; + int skip; + + uaddr = (char *)&u.u_fpvalid - (char *)&u; + if (target_has_execution) + { + unsigned int data; + unsigned int mask; + + rounded_addr = uaddr & -sizeof (int); + data = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0); + mask = 0xff << ((uaddr - rounded_addr) * 8); + + fpvalid = ((data & mask) != 0); + } +#if 0 + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror ("seek on core file"); + if (myread (corechan, &fpvalid, 1) < 0) + perror ("read on core file"); + + } +#endif /* no core support yet */ + + if (fpvalid == 0) + { + printf_unfiltered ("no floating point status saved\n"); + return; + } + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (target_has_execution) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0); + rounded_addr += sizeof (int); + } + } +#if 0 + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; + } +#endif /* 0 */ + + fpstatep = (struct fpstate *)(buf + skip); + print_387_status (fpstatep->status, (struct env387 *)fpstatep->state); +} + +#endif /* never */ diff --git a/contrib/gdb/gdb/i386v4-nat.c b/contrib/gdb/gdb/i386v4-nat.c new file mode 100644 index 000000000000..98f736520c03 --- /dev/null +++ b/contrib/gdb/gdb/i386v4-nat.c @@ -0,0 +1,163 @@ +/* Native-dependent code for SVR4 Unix running on i386's, for GDB. + Copyright 1988, 1989, 1991, 1992, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +#ifdef HAVE_SYS_PROCFS_H + +#include + +/* The /proc interface divides the target machine's register set up into + two different sets, the general register set (gregset) and the floating + point register set (fpregset). For each set, there is an ioctl to get + the current register set and another ioctl to set the current values. + + The actual structure passed through the ioctl interface is, of course, + naturally machine dependent, and is different for each set of registers. + For the i386 for example, the general register set is typically defined + by: + + typedef int gregset_t[19]; (in ) + + #define GS 0 (in ) + #define FS 1 + ... + #define UESP 17 + #define SS 18 + + and the floating point set by: + + typedef struct fpregset + { + union + { + struct fpchip_state // fp extension state // + { + int state[27]; // 287/387 saved state // + int status; // status word saved at exception // + } fpchip_state; + struct fp_emul_space // for emulators // + { + char fp_emul[246]; + char fp_epad[2]; + } fp_emul_space; + int f_fpregs[62]; // union of the above // + } fp_reg_set; + long f_wregs[33]; // saved weitek state // + } fpregset_t; + + These routines provide the packing and unpacking of gregset_t and + fpregset_t formatted data. + + */ + +#ifdef HAVE_GREGSET_T + +/* This is a duplicate of the table in i386-xdep.c. */ + +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + UESP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + + +/* FIXME: These routine absolutely depends upon (NUM_REGS - NUM_FREGS) + being less than or equal to the number of registers that can be stored + in a gregset_t. Note that with the current scheme there will typically + be more registers actually stored in a gregset_t that what we know + about. This is bogus and should be fixed. */ + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + extern int regmap[]; + + for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++) + { + supply_register (regi, (char *) (regp + regmap[regi])); + } +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register greg_t *regp = (greg_t *) gregsetp; + extern char registers[]; + extern int regmap[]; + + for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++) + { + if ((regno == -1) || (regno == regi)) + { + *(regp + regmap[regi]) = *(int *) ®isters[REGISTER_BYTE (regi)]; + } + } +} + +#endif /* HAVE_GREGSET_T */ + +#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), unpack the register contents and supply them as gdb's + idea of the current floating point register values. */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + register int regi; + + /* FIXME: see m68k-tdep.c for an example, for the m68k. */ +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), update the register specified by REGNO from gdb's idea + of the current floating point register set. If REGNO is -1, update + them all. */ + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + int regi; + char *to; + char *from; + extern char registers[]; + + /* FIXME: see m68k-tdep.c for an example, for the m68k. */ +} + +#endif /* defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) */ + +#endif /* HAVE_SYS_PROCFS_H */ diff --git a/contrib/gdb/gdb/i387-tdep.c b/contrib/gdb/gdb/i387-tdep.c new file mode 100644 index 000000000000..6b69405a7dff --- /dev/null +++ b/contrib/gdb/gdb/i387-tdep.c @@ -0,0 +1,107 @@ +/* Intel 387 floating point stuff. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "language.h" +#include "gdbcore.h" +#include "floatformat.h" + +/* FIXME: Eliminate these routines when we have the time to change all + the callers. */ + +void +i387_to_double (from, to) + char *from; + char *to; +{ + floatformat_to_double (&floatformat_i387_ext, from, (double *)to); +} + +void +double_to_i387 (from, to) + char *from; + char *to; +{ + floatformat_from_double (&floatformat_i387_ext, (double *)from, to); +} + +void +print_387_control_word (control) + unsigned int control; +{ + printf_unfiltered ("control %s: ", local_hex_string(control)); + printf_unfiltered ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf_unfiltered ("24 bits; "); break; + case 1: printf_unfiltered ("(bad); "); break; + case 2: printf_unfiltered ("53 bits; "); break; + case 3: printf_unfiltered ("64 bits; "); break; + } + printf_unfiltered ("round "); + switch ((control >> 10) & 3) + { + case 0: printf_unfiltered ("NEAREST; "); break; + case 1: printf_unfiltered ("DOWN; "); break; + case 2: printf_unfiltered ("UP; "); break; + case 3: printf_unfiltered ("CHOP; "); break; + } + if (control & 0x3f) + { + printf_unfiltered ("mask:"); + if (control & 0x0001) printf_unfiltered (" INVALID"); + if (control & 0x0002) printf_unfiltered (" DENORM"); + if (control & 0x0004) printf_unfiltered (" DIVZ"); + if (control & 0x0008) printf_unfiltered (" OVERF"); + if (control & 0x0010) printf_unfiltered (" UNDERF"); + if (control & 0x0020) printf_unfiltered (" LOS"); + printf_unfiltered (";"); + } + printf_unfiltered ("\n"); + if (control & 0xe080) warning ("reserved bits on: %s\n", + local_hex_string(control & 0xe080)); +} + +void +print_387_status_word (status) + unsigned int status; +{ + printf_unfiltered ("status %s: ", local_hex_string (status)); + if (status & 0xff) + { + printf_unfiltered ("exceptions:"); + if (status & 0x0001) printf_unfiltered (" INVALID"); + if (status & 0x0002) printf_unfiltered (" DENORM"); + if (status & 0x0004) printf_unfiltered (" DIVZ"); + if (status & 0x0008) printf_unfiltered (" OVERF"); + if (status & 0x0010) printf_unfiltered (" UNDERF"); + if (status & 0x0020) printf_unfiltered (" LOS"); + if (status & 0x0040) printf_unfiltered (" FPSTACK"); + printf_unfiltered ("; "); + } + printf_unfiltered ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf_unfiltered ("top %d\n", (status >> 11) & 7); +} diff --git a/contrib/gdb/gdb/infcmd.c b/contrib/gdb/gdb/infcmd.c new file mode 100644 index 000000000000..bbadf92b6432 --- /dev/null +++ b/contrib/gdb/gdb/infcmd.c @@ -0,0 +1,1375 @@ +/* Memory-access and commands for "inferior" process, for GDB. + Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "target.h" +#include "language.h" + +static void continue_command PARAMS ((char *, int)); + +static void until_next_command PARAMS ((int)); + +static void until_command PARAMS ((char *, int)); + +static void path_info PARAMS ((char *, int)); + +static void path_command PARAMS ((char *, int)); + +static void unset_command PARAMS ((char *, int)); + +static void float_info PARAMS ((char *, int)); + +static void detach_command PARAMS ((char *, int)); + +static void nofp_registers_info PARAMS ((char *, int)); + +static void all_registers_info PARAMS ((char *, int)); + +static void registers_info PARAMS ((char *, int)); + +static void do_registers_info PARAMS ((int, int)); + +static void unset_environment_command PARAMS ((char *, int)); + +static void set_environment_command PARAMS ((char *, int)); + +static void environment_info PARAMS ((char *, int)); + +static void program_info PARAMS ((char *, int)); + +static void finish_command PARAMS ((char *, int)); + +static void signal_command PARAMS ((char *, int)); + +static void jump_command PARAMS ((char *, int)); + +static void step_1 PARAMS ((int, int, char *)); + +static void nexti_command PARAMS ((char *, int)); + +static void stepi_command PARAMS ((char *, int)); + +static void next_command PARAMS ((char *, int)); + +static void step_command PARAMS ((char *, int)); + +static void run_command PARAMS ((char *, int)); + +#define ERROR_NO_INFERIOR \ + if (!target_has_execution) error ("The program is not being run."); + +/* String containing arguments to give to the program, separated by spaces. + Empty string (pointer to '\0') means no args. */ + +static char *inferior_args; + +/* File name for default use for standard in/out in the inferior. */ + +char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. + Since various parts of infrun.c test this to see whether there is a program + being debugged it should be nonzero (currently 3 is used) for remote + debugging. */ + +int inferior_pid; + +/* Last signal that the inferior received (why it stopped). */ + +enum target_signal stop_signal; + +/* Address at which inferior stopped. */ + +CORE_ADDR stop_pc; + +/* Chain containing status of breakpoint(s) that we have stopped at. */ + +bpstat stop_bpstat; + +/* Flag indicating that a command has proceeded the inferior past the + current breakpoint. */ + +int breakpoint_proceeded; + +/* Nonzero if stopped due to a step command. */ + +int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +int stop_stack_dummy; + +/* Nonzero if stopped due to a random (unexpected) signal in inferior + process. */ + +int stopped_by_random_signal; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +CORE_ADDR step_range_start; /* Inclusive */ +CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +CORE_ADDR step_frame_address; + +/* Our notion of the current stack pointer. */ + +CORE_ADDR step_sp; + +/* 1 means step over all subroutine calls. + 0 means don't step over calls (used by stepi). + -1 means step over calls to undebuggable functions. */ + +int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +int step_multi; + +/* Environment to use for running inferior, + in format described in environ.h. */ + +struct environ *inferior_environ; + + +/* ARGSUSED */ +void +tty_command (file, from_tty) + char *file; + int from_tty; +{ + if (file == 0) + error_no_arg ("terminal name for running target process"); + + inferior_io_terminal = savestring (file, strlen (file)); +} + +static void +run_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + + dont_repeat (); + + if (inferior_pid) + { + if ( + !query ("The program being debugged has been started already.\n\ +Start it from the beginning? ")) + error ("Program not restarted."); + target_kill (); + } + + clear_breakpoint_hit_counts (); + + exec_file = (char *) get_exec_file (0); + + /* The exec file is re-read every time we do a generic_mourn_inferior, so + we just have to worry about the symbol file. */ + reread_symbols (); + + /* We keep symbols from add-symbol-file, on the grounds that the + user might want to add some symbols before running the program + (right?). But sometimes (dynamic loading where the user manually + introduces the new symbols with add-symbol-file), the code which + the symbols describe does not persist between runs. Currently + the user has to manually nuke all symbols between runs if they + want them to go away (PR 2207). This is probably reasonable. */ + + if (args) + { + char *cmd; + cmd = concat ("set args ", args, NULL); + make_cleanup (free, cmd); + execute_command (cmd, from_tty); + } + + if (from_tty) + { + puts_filtered("Starting program: "); + if (exec_file) + puts_filtered(exec_file); + puts_filtered(" "); + puts_filtered(inferior_args); + puts_filtered("\n"); + gdb_flush (gdb_stdout); + } + + target_create_inferior (exec_file, inferior_args, + environ_vector (inferior_environ)); +} + +static void +continue_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + ERROR_NO_INFERIOR; + + /* If have argument, set proceed count of breakpoint we stopped at. */ + + if (proc_count_exp != NULL) + { + bpstat bs = stop_bpstat; + int num = bpstat_num (&bs); + if (num == 0 && from_tty) + { + printf_filtered + ("Not stopped at any breakpoint; argument ignored.\n"); + } + while (num != 0) + { + set_ignore_count (num, + parse_and_eval_address (proc_count_exp) - 1, + from_tty); + /* set_ignore_count prints a message ending with a period. + So print two spaces before "Continuing.". */ + if (from_tty) + printf_filtered (" "); + num = bpstat_num (&bs); + } + } + + if (from_tty) + printf_filtered ("Continuing.\n"); + + clear_proceed_status (); + + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Step until outside of current statement. */ + +/* ARGSUSED */ +static void +step_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (0, 0, count_string); +} + +/* Likewise, but skip over subroutine calls as if single instructions. */ + +/* ARGSUSED */ +static void +next_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (1, 0, count_string); +} + +/* Likewise, but step only one instruction. */ + +/* ARGSUSED */ +static void +stepi_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (0, 1, count_string); +} + +/* ARGSUSED */ +static void +nexti_command (count_string, from_tty) + char *count_string; + int from_tty; +{ + step_1 (1, 1, count_string); +} + +static void +step_1 (skip_subroutines, single_inst, count_string) + int skip_subroutines; + int single_inst; + char *count_string; +{ + register int count = 1; + struct frame_info *frame; + struct cleanup *cleanups = 0; + + ERROR_NO_INFERIOR; + count = count_string ? parse_and_eval_address (count_string) : 1; + + if (!single_inst || skip_subroutines) /* leave si command alone */ + { + enable_longjmp_breakpoint(); + cleanups = make_cleanup(disable_longjmp_breakpoint, 0); + } + + for (; count > 0; count--) + { + clear_proceed_status (); + + frame = get_current_frame (); + if (!frame) /* Avoid coredump here. Why tho? */ + error ("No current frame"); + step_frame_address = FRAME_FP (frame); + step_sp = read_sp (); + + if (! single_inst) + { + find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end); + if (step_range_end == 0) + { + char *name; + if (find_pc_partial_function (stop_pc, &name, &step_range_start, + &step_range_end) == 0) + error ("Cannot find bounds of current function"); + + target_terminal_ours (); + printf_filtered ("\ +Single stepping until exit from function %s, \n\ +which has no line number information.\n", name); + } + } + else + { + /* Say we are stepping, but stop after one insn whatever it does. */ + step_range_start = step_range_end = 1; + if (!skip_subroutines) + /* It is stepi. + Don't step over function calls, not even to functions lacking + line numbers. */ + step_over_calls = 0; + } + + if (skip_subroutines) + step_over_calls = 1; + + step_multi = (count > 1); + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); + if (! stop_step) + break; + + /* FIXME: On nexti, this may have already been done (when we hit the + step resume break, I think). Probably this should be moved to + wait_for_inferior (near the top). */ +#if defined (SHIFT_INST_REGS) + SHIFT_INST_REGS(); +#endif + } + + if (!single_inst || skip_subroutines) + do_cleanups(cleanups); +} + +/* Continue program at specified address. */ + +static void +jump_command (arg, from_tty) + char *arg; + int from_tty; +{ + register CORE_ADDR addr; + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct symbol *fn; + struct symbol *sfn; + + ERROR_NO_INFERIOR; + + if (!arg) + error_no_arg ("starting address"); + + sals = decode_line_spec_1 (arg, 1); + if (sals.nelts != 1) + { + error ("Unreasonable jump request"); + } + + sal = sals.sals[0]; + free ((PTR)sals.sals); + + if (sal.symtab == 0 && sal.pc == 0) + error ("No source file has been specified."); + + resolve_sal_pc (&sal); /* May error out */ + + /* See if we are trying to jump to another function. */ + fn = get_frame_function (get_current_frame ()); + sfn = find_pc_function (sal.pc); + if (fn != NULL && sfn != fn) + { + if (!query ("Line %d is not in `%s'. Jump anyway? ", sal.line, + SYMBOL_SOURCE_NAME (fn))) + { + error ("Not confirmed."); + /* NOTREACHED */ + } + } + + addr = sal.pc; + + if (from_tty) + { + printf_filtered ("Continuing at "); + print_address_numeric (addr, 1, gdb_stdout); + printf_filtered (".\n"); + } + + clear_proceed_status (); + proceed (addr, TARGET_SIGNAL_0, 0); +} + +/* Continue program giving it specified signal. */ + +static void +signal_command (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + enum target_signal oursig; + + dont_repeat (); /* Too dangerous. */ + ERROR_NO_INFERIOR; + + if (!signum_exp) + error_no_arg ("signal number"); + + /* It would be even slicker to make signal names be valid expressions, + (the type could be "enum $signal" or some such), then the user could + assign them to convenience variables. */ + oursig = target_signal_from_name (signum_exp); + + if (oursig == TARGET_SIGNAL_UNKNOWN) + { + /* No, try numeric. */ + int num = parse_and_eval_address (signum_exp); + + if (num == 0) + oursig = TARGET_SIGNAL_0; + else + oursig = target_signal_from_command (num); + } + + if (from_tty) + { + if (oursig == TARGET_SIGNAL_0) + printf_filtered ("Continuing with no signal.\n"); + else + printf_filtered ("Continuing with signal %s.\n", + target_signal_to_name (oursig)); + } + + clear_proceed_status (); + /* "signal 0" should not get stuck if we are stopped at a breakpoint. + FIXME: Neither should "signal foo" but when I tried passing + (CORE_ADDR)-1 unconditionally I got a testsuite failure which I haven't + tried to track down yet. */ + proceed (oursig == TARGET_SIGNAL_0 ? (CORE_ADDR) -1 : stop_pc, oursig, 0); +} + +/* Call breakpoint_auto_delete on the current contents of the bpstat + pointed to by arg (which is really a bpstat *). */ +void +breakpoint_auto_delete_contents (arg) + PTR arg; +{ + breakpoint_auto_delete (*(bpstat *)arg); +} + +/* Execute a "stack dummy", a piece of code stored in the stack + by the debugger to be executed in the inferior. + + To call: first, do PUSH_DUMMY_FRAME. + Then push the contents of the dummy. It should end with a breakpoint insn. + Then call here, passing address at which to start the dummy. + + The contents of all registers are saved before the dummy frame is popped + and copied into the buffer BUFFER. + + The dummy's frame is automatically popped whenever that break is hit. + If that is the first time the program stops, run_stack_dummy + returns to its caller with that frame already gone and returns 0. + Otherwise, run_stack-dummy returns 1 (the frame will eventually be popped + when we do hit that breakpoint). */ + +/* DEBUG HOOK: 4 => return instead of letting the stack dummy run. */ + +static int stack_dummy_testing = 0; + +int +run_stack_dummy (addr, buffer) + CORE_ADDR addr; + char buffer[REGISTER_BYTES]; +{ + struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0); + + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); + if (stack_dummy_testing & 4) + { + POP_FRAME; + return(0); + } +#ifdef CALL_DUMMY_BREAKPOINT_OFFSET + { + struct breakpoint *bpt; + struct symtab_and_line sal; + +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + sal.pc = addr - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; +#else + sal.pc = CALL_DUMMY_ADDRESS (); +#endif + sal.symtab = NULL; + sal.line = 0; + + /* Set up a FRAME for the dummy frame so we can pass it to + set_momentary_breakpoint. We need to give the breakpoint a + frame in case there is only one copy of the dummy (e.g. + CALL_DUMMY_LOCATION == AFTER_TEXT_END). */ + flush_cached_frames (); + set_current_frame (create_new_frame (read_fp (), sal.pc)); + + /* If defined, CALL_DUMMY_BREAKPOINT_OFFSET is where we need to put + a breakpoint instruction. If not, the call dummy already has the + breakpoint instruction in it. + + addr is the address of the call dummy plus the CALL_DUMMY_START_OFFSET, + so we need to subtract the CALL_DUMMY_START_OFFSET. */ + bpt = set_momentary_breakpoint (sal, + get_current_frame (), + bp_call_dummy); + bpt->disposition = del; + + /* If all error()s out of proceed ended up calling normal_stop (and + perhaps they should; it already does in the special case of error + out of resume()), then we wouldn't need this. */ + make_cleanup (breakpoint_auto_delete_contents, &stop_bpstat); + } +#endif /* CALL_DUMMY_BREAKPOINT_OFFSET. */ + + proceed_to_finish = 1; /* We want stop_registers, please... */ + proceed (addr, TARGET_SIGNAL_0, 0); + + discard_cleanups (old_cleanups); + + if (!stop_stack_dummy) + return 1; + + /* On return, the stack dummy has been popped already. */ + + memcpy (buffer, stop_registers, sizeof stop_registers); + return 0; +} + +/* Proceed until we reach a different source line with pc greater than + our current one or exit the function. We skip calls in both cases. + + Note that eventually this command should probably be changed so + that only source lines are printed out when we hit the breakpoint + we set. This may involve changes to wait_for_inferior and the + proceed status code. */ + +/* ARGSUSED */ +static void +until_next_command (from_tty) + int from_tty; +{ + struct frame_info *frame; + CORE_ADDR pc; + struct symbol *func; + struct symtab_and_line sal; + + clear_proceed_status (); + + frame = get_current_frame (); + + /* Step until either exited from this function or greater + than the current line (if in symbolic section) or pc (if + not). */ + + pc = read_pc (); + func = find_pc_function (pc); + + if (!func) + { + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); + + if (msymbol == NULL) + error ("Execution is not within a known function."); + + step_range_start = SYMBOL_VALUE_ADDRESS (msymbol); + step_range_end = pc; + } + else + { + sal = find_pc_line (pc, 0); + + step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); + step_range_end = sal.end; + } + + step_over_calls = 1; + step_frame_address = FRAME_FP (frame); + step_sp = read_sp (); + + step_multi = 0; /* Only one call to proceed */ + + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); +} + +static void +until_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (!target_has_execution) + error ("The program is not running."); + if (arg) + until_break_command (arg, from_tty); + else + until_next_command (from_tty); +} + +/* "finish": Set a temporary breakpoint at the place + the selected frame will return to, then continue. */ + +static void +finish_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + register struct frame_info *frame; + register struct symbol *function; + struct breakpoint *breakpoint; + struct cleanup *old_chain; + + if (arg) + error ("The \"finish\" command does not take any arguments."); + if (!target_has_execution) + error ("The program is not running."); + if (selected_frame == NULL) + error ("No selected frame."); + + frame = get_prev_frame (selected_frame); + if (frame == 0) + error ("\"finish\" not meaningful in the outermost frame."); + + clear_proceed_status (); + + sal = find_pc_line (frame->pc, 0); + sal.pc = frame->pc; + + breakpoint = set_momentary_breakpoint (sal, frame, bp_finish); + + old_chain = make_cleanup(delete_breakpoint, breakpoint); + + /* Find the function we will return from. */ + + function = find_pc_function (selected_frame->pc); + + /* Print info on the selected frame, including level number + but not source. */ + if (from_tty) + { + printf_filtered ("Run till exit from "); + print_stack_frame (selected_frame, selected_frame_level, 0); + } + + proceed_to_finish = 1; /* We want stop_registers, please... */ + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); + + /* Did we stop at our breakpoint? */ + if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL + && function != 0) + { + struct type *value_type; + register value_ptr val; + CORE_ADDR funcaddr; + + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + fatal ("internal: finish_command: function has no target type"); + + if (TYPE_CODE (value_type) == TYPE_CODE_VOID) + return; + + funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + + val = value_being_returned (value_type, stop_registers, + using_struct_return (value_of_variable (function, NULL), + funcaddr, + check_typedef (value_type), + BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function)))); + + printf_filtered ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, gdb_stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); + } + do_cleanups(old_chain); +} + +/* ARGSUSED */ +static void +program_info (args, from_tty) + char *args; + int from_tty; +{ + bpstat bs = stop_bpstat; + int num = bpstat_num (&bs); + + if (!target_has_execution) + { + printf_filtered ("The program being debugged is not being run.\n"); + return; + } + + target_files_info (); + printf_filtered ("Program stopped at %s.\n", + local_hex_string((unsigned long) stop_pc)); + if (stop_step) + printf_filtered ("It stopped after being stepped.\n"); + else if (num != 0) + { + /* There may be several breakpoints in the same place, so this + isn't as strange as it seems. */ + while (num != 0) + { + if (num < 0) + printf_filtered ("It stopped at a breakpoint that has since been deleted.\n"); + else + printf_filtered ("It stopped at breakpoint %d.\n", num); + num = bpstat_num (&bs); + } + } + else if (stop_signal != TARGET_SIGNAL_0) + { + printf_filtered ("It stopped with signal %s, %s.\n", + target_signal_to_name (stop_signal), + target_signal_to_string (stop_signal)); + } + + if (!from_tty) + printf_filtered ("Type \"info stack\" or \"info registers\" for more information.\n"); +} + +static void +environment_info (var, from_tty) + char *var; + int from_tty; +{ + if (var) + { + register char *val = get_in_environ (inferior_environ, var); + if (val) + { + puts_filtered (var); + puts_filtered (" = "); + puts_filtered (val); + puts_filtered ("\n"); + } + else + { + puts_filtered ("Environment variable \""); + puts_filtered (var); + puts_filtered ("\" not defined.\n"); + } + } + else + { + register char **vector = environ_vector (inferior_environ); + while (*vector) + { + puts_filtered (*vector++); + puts_filtered ("\n"); + } + } +} + +static void +set_environment_command (arg, from_tty) + char *arg; + int from_tty; +{ + register char *p, *val, *var; + int nullset = 0; + + if (arg == 0) + error_no_arg ("environment variable and value"); + + /* Find seperation between variable name and value */ + p = (char *) strchr (arg, '='); + val = (char *) strchr (arg, ' '); + + if (p != 0 && val != 0) + { + /* We have both a space and an equals. If the space is before the + equals, walk forward over the spaces til we see a nonspace + (possibly the equals). */ + if (p > val) + while (*val == ' ') + val++; + + /* Now if the = is after the char following the spaces, + take the char following the spaces. */ + if (p > val) + p = val - 1; + } + else if (val != 0 && p == 0) + p = val; + + if (p == arg) + error_no_arg ("environment variable to set"); + + if (p == 0 || p[1] == 0) + { + nullset = 1; + if (p == 0) + p = arg + strlen (arg); /* So that savestring below will work */ + } + else + { + /* Not setting variable value to null */ + val = p + 1; + while (*val == ' ' || *val == '\t') + val++; + } + + while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--; + + var = savestring (arg, p - arg); + if (nullset) + { + printf_filtered ("Setting environment variable \"%s\" to null value.\n", var); + set_in_environ (inferior_environ, var, ""); + } + else + set_in_environ (inferior_environ, var, val); + free (var); +} + +static void +unset_environment_command (var, from_tty) + char *var; + int from_tty; +{ + if (var == 0) + { + /* If there is no argument, delete all environment variables. + Ask for confirmation if reading from the terminal. */ + if (!from_tty || query ("Delete all environment variables? ")) + { + free_environ (inferior_environ); + inferior_environ = make_environ (); + } + } + else + unset_in_environ (inferior_environ, var); +} + +/* Handle the execution path (PATH variable) */ + +static const char path_var_name[] = "PATH"; + +/* ARGSUSED */ +static void +path_info (args, from_tty) + char *args; + int from_tty; +{ + puts_filtered ("Executable and object file path: "); + puts_filtered (get_in_environ (inferior_environ, path_var_name)); + puts_filtered ("\n"); +} + +/* Add zero or more directories to the front of the execution path. */ + +static void +path_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + char *exec_path; + char *env; + dont_repeat (); + env = get_in_environ (inferior_environ, path_var_name); + /* Can be null if path is not set */ + if (!env) + env = ""; + exec_path = strsave (env); + mod_path (dirname, &exec_path); + set_in_environ (inferior_environ, path_var_name, exec_path); + free (exec_path); + if (from_tty) + path_info ((char *)NULL, from_tty); +} + +/* The array of register names. */ + +char *reg_names[] = REGISTER_NAMES; + +/* Print out the machine register regnum. If regnum is -1, + print all registers (fpregs == 1) or all non-float registers + (fpregs == 0). + + For most machines, having all_registers_info() print the + register(s) one per line is good enough. If a different format + is required, (eg, for MIPS or Pyramid 90x, which both have + lots of regs), or there is an existing convention for showing + all the registers, define the macro DO_REGISTERS_INFO(regnum, fp) + to provide that format. */ + +#if !defined (DO_REGISTERS_INFO) + +#define DO_REGISTERS_INFO(regnum, fp) do_registers_info(regnum, fp) + +static void +do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + register int i; + int numregs = ARCH_NUM_REGS; + + for (i = 0; i < numregs; i++) + { + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + + /* Decide between printing all regs, nonfloat regs, or specific reg. */ + if (regnum == -1) { + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT && !fpregs) + continue; + } else { + if (i != regnum) + continue; + } + + /* If the register name is empty, it is undefined for this + processor, so don't display anything. */ + if (reg_names[i] == NULL || *(reg_names[i]) == '\0') + continue; + + fputs_filtered (reg_names[i], gdb_stdout); + print_spaces_filtered (15 - strlen (reg_names[i]), gdb_stdout); + + /* Get the data in raw format. */ + if (read_relative_register_raw_bytes (i, raw_buffer)) + { + printf_filtered ("Invalid register contents\n"); + continue; + } + + /* Convert raw data to virtual format if necessary. */ +#ifdef REGISTER_CONVERTIBLE + if (REGISTER_CONVERTIBLE (i)) + { + REGISTER_CONVERT_TO_VIRTUAL (i, REGISTER_VIRTUAL_TYPE (i), + raw_buffer, virtual_buffer); + } + else +#endif + memcpy (virtual_buffer, raw_buffer, + REGISTER_VIRTUAL_SIZE (i)); + + /* If virtual format is floating, print it that way, and in raw hex. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT) + { + register int j; + +#ifdef INVALID_FLOAT + if (INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i))) + printf_filtered (""); + else +#endif + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + + printf_filtered ("\t(raw 0x"); + for (j = 0; j < REGISTER_RAW_SIZE (i); j++) + printf_filtered ("%02x", (unsigned char)raw_buffer[j]); + printf_filtered (")"); + } + +/* FIXME! val_print probably can handle all of these cases now... */ + + /* Else if virtual format is too long for printf, + print in hex a byte at a time. */ + else if (REGISTER_VIRTUAL_SIZE (i) > (int) sizeof (long)) + { + register int j; + printf_filtered ("0x"); + for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++) + printf_filtered ("%02x", (unsigned char)virtual_buffer[j]); + } + /* Else print as integer in hex and in decimal. */ + else + { + val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0, + gdb_stdout, 'x', 1, 0, Val_pretty_default); + printf_filtered ("\t"); + val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + } + + /* The SPARC wants to print even-numbered float regs as doubles + in addition to printing them as floats. */ +#ifdef PRINT_REGISTER_HOOK + PRINT_REGISTER_HOOK (i); +#endif + + printf_filtered ("\n"); + } +} +#endif /* no DO_REGISTERS_INFO. */ + +static void +registers_info (addr_exp, fpregs) + char *addr_exp; + int fpregs; +{ + int regnum, numregs; + register char *end; + + if (!target_has_registers) + error ("The program has no registers now."); + if (selected_frame == NULL) + error ("No selected frame."); + + if (!addr_exp) + { + DO_REGISTERS_INFO(-1, fpregs); + return; + } + + do + { + if (addr_exp[0] == '$') + addr_exp++; + end = addr_exp; + while (*end != '\0' && *end != ' ' && *end != '\t') + ++end; + numregs = ARCH_NUM_REGS; + for (regnum = 0; regnum < numregs; regnum++) + if (!strncmp (addr_exp, reg_names[regnum], end - addr_exp) + && strlen (reg_names[regnum]) == end - addr_exp) + goto found; + if (*addr_exp >= '0' && *addr_exp <= '9') + regnum = atoi (addr_exp); /* Take a number */ + if (regnum >= numregs) /* Bad name, or bad number */ + error ("%.*s: invalid register", end - addr_exp, addr_exp); + +found: + DO_REGISTERS_INFO(regnum, fpregs); + + addr_exp = end; + while (*addr_exp == ' ' || *addr_exp == '\t') + ++addr_exp; + } while (*addr_exp != '\0'); +} + +static void +all_registers_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + registers_info (addr_exp, 1); +} + +static void +nofp_registers_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + registers_info (addr_exp, 0); +} + +/* + * TODO: + * Should save/restore the tty state since it might be that the + * program to be debugged was started on this tty and it wants + * the tty in some state other than what we want. If it's running + * on another terminal or without a terminal, then saving and + * restoring the tty state is a harmless no-op. + * This only needs to be done if we are attaching to a process. + */ + +/* + attach_command -- + takes a program started up outside of gdb and ``attaches'' to it. + This stops it cold in its tracks and allows us to start debugging it. + and wait for the trace-trap that results from attaching. */ + +void +attach_command (args, from_tty) + char *args; + int from_tty; +{ + extern int auto_solib_add; + + dont_repeat (); /* Not for the faint of heart */ + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill (); + else + error ("Not killed."); + } + + target_attach (args, from_tty); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* Set up execution context to know that we should return from + wait_for_inferior as soon as the target reports a stop. */ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + + /* No traps are generated when attaching to inferior under Mach 3 + or GNU hurd. */ +#ifndef ATTACH_NO_WAIT + wait_for_inferior (); +#endif + +#ifdef SOLIB_ADD + if (auto_solib_add) + { + /* Add shared library symbols from the newly attached process, if any. */ + SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0); + re_enable_breakpoints_in_shlibs (); + } +#endif + + normal_stop (); +} + +/* + * detach_command -- + * takes a program previously attached to and detaches it. + * The program resumes execution and will no longer stop + * on signals, etc. We better not have left any breakpoints + * in the program or it'll die when it hits one. For this + * to work, it may be necessary for the process to have been + * previously attached. It *might* work if the program was + * started via the normal ptrace (PTRACE_TRACEME). + */ + +static void +detach_command (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); /* Not for the faint of heart */ + target_detach (args, from_tty); +} + +/* ARGSUSED */ +static void +float_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ +#ifdef FLOAT_INFO + FLOAT_INFO; +#else + printf_filtered ("No floating point info available for this processor.\n"); +#endif +} + +/* ARGSUSED */ +static void +unset_command (args, from_tty) + char *args; + int from_tty; +{ + printf_filtered ("\"unset\" must be followed by the name of an unset subcommand.\n"); + help_list (unsetlist, "unset ", -1, gdb_stdout); +} + +void +_initialize_infcmd () +{ + struct cmd_list_element *c; + + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_show_from_set + (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args, + +"Set arguments to give program being debugged when it is started.\n\ +Follow this command with any number of args, to be passed to the program.", + &setlist), + &showlist); + + c = add_cmd + ("environment", no_class, environment_info, + "The environment to give the program, or one variable's value.\n\ +With an argument VAR, prints the value of environment variable VAR to\n\ +give the program being debugged. With no arguments, prints the entire\n\ +environment to be given to the program.", &showlist); + c->completer = noop_completer; + + add_prefix_cmd ("unset", no_class, unset_command, + "Complement to certain \"set\" commands", + &unsetlist, "unset ", 0, &cmdlist); + + c = add_cmd ("environment", class_run, unset_environment_command, + "Cancel environment variable VAR for the program.\n\ +This does not affect the program until the next \"run\" command.", + &unsetlist); + c->completer = noop_completer; + + c = add_cmd ("environment", class_run, set_environment_command, + "Set environment variable value to give the program.\n\ +Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\ +VALUES of environment variables are uninterpreted strings.\n\ +This does not affect the program until the next \"run\" command.", + &setlist); + c->completer = noop_completer; + + add_com ("path", class_files, path_command, + "Add directory DIR(s) to beginning of search path for object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed."); + + c = add_cmd ("paths", no_class, path_info, + "Current search path for finding object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed.", &showlist); + c->completer = noop_completer; + + add_com ("attach", class_run, attach_command, + "Attach to a process or file outside of GDB.\n\ +This command attaches to another target, of the same type as your last\n\ +`target' command (`info files' will show your target stack).\n\ +The command may take as argument a process id or a device file.\n\ +For a process id, you must have permission to send the process a signal,\n\ +and it must have the same effective uid as the debugger.\n\ +When using \"attach\", you should use the \"file\" command to specify\n\ +the program running in the process, and to load its symbol table."); + + add_com ("detach", class_run, detach_command, + "Detach a process or file previously attached.\n\ +If a process, it is no longer traced, and it continues its execution. If you\n\ +were debugging a file, the file is closed and gdb no longer accesses it."); + + add_com ("signal", class_run, signal_command, + "Continue program giving it signal specified by the argument.\n\ +An argument of \"0\" means continue program without giving it a signal."); + + add_com ("stepi", class_run, stepi_command, + "Step one instruction exactly.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("si", "stepi", class_alias, 0); + + add_com ("nexti", class_run, nexti_command, + "Step one instruction, but proceed through subroutine calls.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("ni", "nexti", class_alias, 0); + + add_com ("finish", class_run, finish_command, + "Execute until selected stack frame returns.\n\ +Upon return, the value returned is printed and put in the value history."); + + add_com ("next", class_run, next_command, + "Step program, proceeding through subroutine calls.\n\ +Like the \"step\" command as long as subroutine calls do not happen;\n\ +when they do, the call is treated as one instruction.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("n", "next", class_run, 1); + + add_com ("step", class_run, step_command, + "Step program until it reaches a different source line.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("s", "step", class_run, 1); + + add_com ("until", class_run, until_command, + "Execute until the program reaches a source line greater than the current\n\ +or a specified line or address or function (same args as break command).\n\ +Execution will also stop upon exit from the current stack frame."); + add_com_alias ("u", "until", class_run, 1); + + add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ +Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ +for an address to start at."); + + add_com ("continue", class_run, continue_command, + "Continue program being debugged, after signal or breakpoint.\n\ +If proceeding from breakpoint, a number N may be used as an argument,\n\ +which means to set the ignore count of that breakpoint to N - 1 (so that\n\ +the breakpoint won't break until the Nth time it is reached)."); + add_com_alias ("c", "cont", class_run, 1); + add_com_alias ("fg", "cont", class_run, 1); + + add_com ("run", class_run, run_command, + "Start debugged program. You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ +Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\ +With no arguments, uses arguments last specified (with \"run\" or \"set args\").\n\ +To cancel previous arguments and run with no arguments,\n\ +use \"set args\" without arguments."); + add_com_alias ("r", "run", class_run, 1); + + add_info ("registers", nofp_registers_info, + "List of integer registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("all-registers", all_registers_info, +"List of all registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("program", program_info, + "Execution status of the program."); + + add_info ("float", float_info, + "Print the status of the floating point unit\n"); + + inferior_args = savestring ("", 1); /* Initially no args */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} diff --git a/contrib/gdb/gdb/inferior.h b/contrib/gdb/gdb/inferior.h new file mode 100644 index 000000000000..e39f8b9d6bc0 --- /dev/null +++ b/contrib/gdb/gdb/inferior.h @@ -0,0 +1,382 @@ +/* Variables that describe the inferior process running under GDB: + Where it is, why it stopped, and how to step it. + Copyright 1986, 1989, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (INFERIOR_H) +#define INFERIOR_H 1 + +/* For bpstat. */ +#include "breakpoint.h" + +/* For enum target_signal. */ +#include "target.h" + +/* Structure in which to save the status of the inferior. Save + through "save_inferior_status", restore through + "restore_inferior_status". + This pair of routines should be called around any transfer of + control to the inferior which you don't want showing up in your + control variables. */ + +struct inferior_status { + enum target_signal stop_signal; + CORE_ADDR stop_pc; + bpstat stop_bpstat; + int stop_step; + int stop_stack_dummy; + int stopped_by_random_signal; + int trap_expected; + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + CORE_ADDR step_frame_address; + int step_over_calls; + CORE_ADDR step_resume_break_address; + int stop_after_trap; + int stop_soon_quietly; + CORE_ADDR selected_frame_address; + int selected_level; + char stop_registers[REGISTER_BYTES]; + + /* These are here because if call_function_by_hand has written some + registers and then decides to call error(), we better not have changed + any registers. */ + char registers[REGISTER_BYTES]; + + int breakpoint_proceeded; + int restore_stack_info; + int proceed_to_finish; +}; + +/* This macro gives the number of registers actually in use by the + inferior. This may be less than the total number of registers, + perhaps depending on the actual CPU in use or program being run. */ + +#ifndef ARCH_NUM_REGS +#define ARCH_NUM_REGS NUM_REGS +#endif + +extern void save_inferior_status PARAMS ((struct inferior_status *, int)); + +extern void restore_inferior_status PARAMS ((struct inferior_status *)); + +extern void set_sigint_trap PARAMS ((void)); + +extern void clear_sigint_trap PARAMS ((void)); + +extern void set_sigio_trap PARAMS ((void)); + +extern void clear_sigio_trap PARAMS ((void)); + +/* File name for default use for standard in/out in the inferior. */ + +extern char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +extern int inferior_pid; + +/* Inferior environment. */ + +extern struct environ *inferior_environ; + +/* Character array containing an image of the inferior programs' registers. */ + +extern char registers[]; + +/* Array of validity bits (one per register). Nonzero at position XXX_REGNUM + means that `registers' contains a valid copy of inferior register XXX. */ + +extern char register_valid[NUM_REGS]; + +extern void clear_proceed_status PARAMS ((void)); + +extern void proceed PARAMS ((CORE_ADDR, enum target_signal, int)); + +extern void kill_inferior PARAMS ((void)); + +extern void generic_mourn_inferior PARAMS ((void)); + +extern void terminal_ours PARAMS ((void)); + +extern int run_stack_dummy PARAMS ((CORE_ADDR, char [REGISTER_BYTES])); + +extern CORE_ADDR read_pc PARAMS ((void)); + +extern CORE_ADDR read_pc_pid PARAMS ((int)); + +extern void write_pc PARAMS ((CORE_ADDR)); + +extern CORE_ADDR read_sp PARAMS ((void)); + +extern void write_sp PARAMS ((CORE_ADDR)); + +extern CORE_ADDR read_fp PARAMS ((void)); + +extern void write_fp PARAMS ((CORE_ADDR)); + +extern void wait_for_inferior PARAMS ((void)); + +extern void init_wait_for_inferior PARAMS ((void)); + +extern void close_exec_file PARAMS ((void)); + +extern void reopen_exec_file PARAMS ((void)); + +/* The `resume' routine should only be called in special circumstances. + Normally, use `proceed', which handles a lot of bookkeeping. */ + +extern void resume PARAMS ((int, enum target_signal)); + +/* From misc files */ + +extern void store_inferior_registers PARAMS ((int)); + +extern void fetch_inferior_registers PARAMS ((int)); + +extern void solib_create_inferior_hook PARAMS ((void)); + +extern void child_terminal_info PARAMS ((char *, int)); + +extern void term_info PARAMS ((char *, int)); + +extern void terminal_ours_for_output PARAMS ((void)); + +extern void terminal_inferior PARAMS ((void)); + +extern void terminal_init_inferior PARAMS ((void)); + +/* From infptrace.c */ + +extern int attach PARAMS ((int)); + +void detach PARAMS ((int)); + +extern void child_resume PARAMS ((int, int, enum target_signal)); + +#ifndef PTRACE_ARG3_TYPE +#define PTRACE_ARG3_TYPE int /* Correct definition for most systems. */ +#endif + +extern int call_ptrace PARAMS ((int, int, PTRACE_ARG3_TYPE, int)); + +/* From procfs.c */ + +extern int proc_iterate_over_mappings PARAMS ((int (*) (int, CORE_ADDR))); + +/* From fork-child.c */ + +extern void fork_inferior PARAMS ((char *, char *, char **, + void (*) (void), + void (*) (int), char *)); + +extern void startup_inferior PARAMS ((int)); + +/* From inflow.c */ + +extern void new_tty_prefork PARAMS ((char *)); + +extern int gdb_has_a_terminal PARAMS ((void)); + +/* From infrun.c */ + +extern void start_remote PARAMS ((void)); + +extern void normal_stop PARAMS ((void)); + +extern int signal_stop_state PARAMS ((int)); + +extern int signal_print_state PARAMS ((int)); + +extern int signal_pass_state PARAMS ((int)); + +/* From infcmd.c */ + +extern void tty_command PARAMS ((char *, int)); + +extern void attach_command PARAMS ((char *, int)); + +/* Last signal that the inferior received (why it stopped). */ + +extern enum target_signal stop_signal; + +/* Address at which inferior stopped. */ + +extern CORE_ADDR stop_pc; + +/* Chain containing status of breakpoint(s) that we have stopped at. */ + +extern bpstat stop_bpstat; + +/* Flag indicating that a command has proceeded the inferior past the + current breakpoint. */ + +extern int breakpoint_proceeded; + +/* Nonzero if stopped due to a step command. */ + +extern int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +extern int stop_stack_dummy; + +/* Nonzero if program stopped due to a random (unexpected) signal in + inferior process. */ + +extern int stopped_by_random_signal; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. + + If step_range_start and step_range_end are both 1, it means to step for + a single instruction (FIXME: it might clean up wait_for_inferior in a + minor way if this were changed to the address of the instruction and + that address plus one. But maybe not.). */ + +extern CORE_ADDR step_range_start; /* Inclusive */ +extern CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +extern CORE_ADDR step_frame_address; + +/* Our notion of the current stack pointer. */ + +extern CORE_ADDR step_sp; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +extern int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +extern int step_multi; + +/* Nonzero means expecting a trap and caller will handle it themselves. + It is used after attach, due to attaching to a process; + when running in the shell before the child program has been exec'd; + and when running some kinds of remote stuff (FIXME?). */ + +extern int stop_soon_quietly; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +extern int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +extern char stop_registers[REGISTER_BYTES]; + +/* Nonzero if the child process in inferior_pid was attached rather + than forked. */ + +extern int attach_flag; + +/* Sigtramp is a routine that the kernel calls (which then calls the + signal handler). On most machines it is a library routine that + is linked into the executable. + + This macro, given a program counter value and the name of the + function in which that PC resides (which can be null if the + name is not known), returns nonzero if the PC and name show + that we are in sigtramp. + + On most machines just see if the name is sigtramp (and if we have + no name, assume we are not in sigtramp). */ +#if !defined (IN_SIGTRAMP) +# if defined (SIGTRAMP_START) +# define IN_SIGTRAMP(pc, name) \ + ((pc) >= SIGTRAMP_START \ + && (pc) < SIGTRAMP_END \ + ) +# else +# define IN_SIGTRAMP(pc, name) \ + (name && STREQ ("_sigtramp", name)) +# endif +#endif + +/* Possible values for CALL_DUMMY_LOCATION. */ +#define ON_STACK 1 +#define BEFORE_TEXT_END 2 +#define AFTER_TEXT_END 3 +#define AT_ENTRY_POINT 4 + +#if !defined (CALL_DUMMY_LOCATION) +#define CALL_DUMMY_LOCATION ON_STACK +#endif /* No CALL_DUMMY_LOCATION. */ + +/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK + below is for infrun.c, which may give the macro a pc without that + subtracted out. */ +#if !defined (PC_IN_CALL_DUMMY) +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END +extern CORE_ADDR text_end; +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end - CALL_DUMMY_LENGTH \ + && (pc) <= text_end + DECR_PC_AFTER_BREAK) +#endif /* Before text_end. */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END +extern CORE_ADDR text_end; +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end \ + && (pc) <= text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK) +#endif /* After text_end. */ + +#if CALL_DUMMY_LOCATION == ON_STACK +/* Is the PC in a call dummy? SP and FRAME_ADDRESS are the bottom and + top of the stack frame which we are checking, where "bottom" and + "top" refer to some section of memory which contains the code for + the call dummy. Calls to this macro assume that the contents of + SP_REGNUM and FP_REGNUM (or the saved values thereof), respectively, + are the things to pass. + + This won't work on the 29k, where SP_REGNUM and FP_REGNUM don't + have that meaning, but the 29k doesn't use ON_STACK. This could be + fixed by generalizing this scheme, perhaps by passing in a frame + and adding a few fields, at least on machines which need them for + PC_IN_CALL_DUMMY. + + Something simpler, like checking for the stack segment, doesn't work, + since various programs (threads implementations, gcc nested function + stubs, etc) may either allocate stack frames in another segment, or + allocate other kinds of code on the stack. */ + +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((sp) INNER_THAN (pc) && (frame_address != 0) && (pc) INNER_THAN (frame_address)) +#endif /* On stack. */ + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= CALL_DUMMY_ADDRESS () \ + && (pc) <= (CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK)) +#endif /* At entry point. */ +#endif /* No PC_IN_CALL_DUMMY. */ + +#endif /* !defined (INFERIOR_H) */ diff --git a/contrib/gdb/gdb/inflow.c b/contrib/gdb/gdb/inflow.c new file mode 100644 index 000000000000..62daa65cf09b --- /dev/null +++ b/contrib/gdb/gdb/inflow.c @@ -0,0 +1,718 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "command.h" +#include "signals.h" +#include "serial.h" +#include "terminal.h" +#include "target.h" +#include "thread.h" + +#include "gdb_string.h" +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_TERMIOS +#define PROCESS_GROUP_TYPE pid_t +#endif + +#ifdef HAVE_SGTTY +#ifdef SHORT_PGRP +/* This is only used for the ultra. Does it have pid_t? */ +#define PROCESS_GROUP_TYPE short +#else +#define PROCESS_GROUP_TYPE int +#endif +#endif /* sgtty */ + +static void +kill_command PARAMS ((char *, int)); + +static void +terminal_ours_1 PARAMS ((int)); + +/* Record terminal status separately for debugger and inferior. */ + +static serial_t stdin_serial; + +/* TTY state for the inferior. We save it whenever the inferior stops, and + restore it when it resumes. */ +static serial_ttystate inferior_ttystate; + +/* Our own tty state, which we restore every time we need to deal with the + terminal. We only set it once, when GDB first starts. The settings of + flags which readline saves and restores and unimportant. */ +static serial_ttystate our_ttystate; + +/* fcntl flags for us and the inferior. Saved and restored just like + {our,inferior}_ttystate. */ +static int tflags_inferior; +static int tflags_ours; + +#ifdef PROCESS_GROUP_TYPE +/* Process group for us and the inferior. Saved and restored just like + {our,inferior}_ttystate. */ +PROCESS_GROUP_TYPE our_process_group; +PROCESS_GROUP_TYPE inferior_process_group; +#endif + +/* While the inferior is running, we want SIGINT and SIGQUIT to go to the + inferior only. If we have job control, that takes care of it. If not, + we save our handlers in these two variables and set SIGINT and SIGQUIT + to SIG_IGN. */ +static void (*sigint_ours) (); +static void (*sigquit_ours) (); + +/* The name of the tty (from the `tty' command) that we gave to the inferior + when it was last started. */ + +static char *inferior_thisrun_terminal; + +/* Nonzero if our terminal settings are in effect. Zero if the + inferior's settings are in effect. Ignored if !gdb_has_a_terminal + (). */ + +static int terminal_is_ours; + +enum {yes, no, have_not_checked} gdb_has_a_terminal_flag = have_not_checked; + +/* Does GDB have a terminal (on stdin)? */ +int +gdb_has_a_terminal () +{ + switch (gdb_has_a_terminal_flag) + { + case yes: + return 1; + case no: + return 0; + case have_not_checked: + /* Get all the current tty settings (including whether we have a tty at + all!). Can't do this in _initialize_inflow because SERIAL_FDOPEN + won't work until the serial_ops_list is initialized. */ + +#ifdef F_GETFL + tflags_ours = fcntl (0, F_GETFL, 0); +#endif + + gdb_has_a_terminal_flag = no; + stdin_serial = SERIAL_FDOPEN (0); + if (stdin_serial != NULL) + { + our_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); + + if (our_ttystate != NULL) + { + gdb_has_a_terminal_flag = yes; +#ifdef HAVE_TERMIOS + our_process_group = tcgetpgrp (0); +#endif +#ifdef HAVE_SGTTY + ioctl (0, TIOCGPGRP, &our_process_group); +#endif + } + } + + return gdb_has_a_terminal_flag == yes; + default: + /* "Can't happen". */ + return 0; + } +} + +/* Macro for printing errors from ioctl operations */ + +#define OOPSY(what) \ + if (result == -1) \ + fprintf_unfiltered(gdb_stderr, "[%s failed in terminal_inferior: %s]\n", \ + what, strerror (errno)) + +static void terminal_ours_1 PARAMS ((int)); + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +void +terminal_init_inferior () +{ + if (gdb_has_a_terminal ()) + { + /* We could just as well copy our_ttystate (if we felt like adding + a new function SERIAL_COPY_TTY_STATE). */ + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); +#ifdef PROCESS_GROUP_TYPE +#ifdef PIDGET + /* This is for Lynx, and should be cleaned up by having Lynx be + a separate debugging target with a version of + target_terminal_init_inferior which passes in the process + group to a generic routine which does all the work (and the + non-threaded child_terminal_init_inferior can just pass in + inferior_pid to the same routine). */ + inferior_process_group = PIDGET (inferior_pid); +#else + inferior_process_group = inferior_pid; +#endif +#endif + + /* Make sure that next time we call terminal_inferior (which will be + before the program runs, as it needs to be), we install the new + process group. */ + terminal_is_ours = 1; + } +} + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +void +terminal_inferior () +{ + if (gdb_has_a_terminal () && terminal_is_ours + && inferior_thisrun_terminal == 0) + { + int result; + +#ifdef F_GETFL + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_inferior); + result = fcntl (0, F_SETFL, tflags_inferior); + OOPSY ("fcntl F_SETFL"); +#endif + + /* Because we were careful to not change in or out of raw mode in + terminal_ours, we will not change in our out of raw mode with + this call, so we don't flush any input. */ + result = SERIAL_SET_TTY_STATE (stdin_serial, inferior_ttystate); + OOPSY ("setting tty state"); + + if (!job_control) + { + sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN); + sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN); + } + + /* If attach_flag is set, we don't know whether we are sharing a + terminal with the inferior or not. (attaching a process + without a terminal is one case where we do not; attaching a + process which we ran from the same shell as GDB via `&' is + one case where we do, I think (but perhaps this is not + `sharing' in the sense that we need to save and restore tty + state)). I don't know if there is any way to tell whether we + are sharing a terminal. So what we do is to go through all + the saving and restoring of the tty state, but ignore errors + setting the process group, which will happen if we are not + sharing a terminal). */ + + if (job_control) + { +#ifdef HAVE_TERMIOS + result = tcsetpgrp (0, inferior_process_group); + if (!attach_flag) + OOPSY ("tcsetpgrp"); +#endif + +#ifdef HAVE_SGTTY + result = ioctl (0, TIOCSPGRP, &inferior_process_group); + if (!attach_flag) + OOPSY ("TIOCSPGRP"); +#endif + } + + } + terminal_is_ours = 0; +} + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +void +terminal_ours_for_output () +{ + terminal_ours_1 (1); +} + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +void +terminal_ours () +{ + terminal_ours_1 (0); +} + +/* output_only is not used, and should not be used unless we introduce + separate terminal_is_ours and terminal_is_ours_for_output + flags. */ + +static void +terminal_ours_1 (output_only) + int output_only; +{ + /* Checking inferior_thisrun_terminal is necessary so that + if GDB is running in the background, it won't block trying + to do the ioctl()'s below. Checking gdb_has_a_terminal + avoids attempting all the ioctl's when running in batch. */ + if (inferior_thisrun_terminal != 0 || gdb_has_a_terminal () == 0) + return; + + if (!terminal_is_ours) + { + /* Ignore this signal since it will happen when we try to set the + pgrp. */ + void (*osigttou) (); + int result; + + terminal_is_ours = 1; + +#ifdef SIGTTOU + if (job_control) + osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN); +#endif + + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); +#ifdef HAVE_TERMIOS + inferior_process_group = tcgetpgrp (0); +#endif +#ifdef HAVE_SGTTY + ioctl (0, TIOCGPGRP, &inferior_process_group); +#endif + + /* Here we used to set ICANON in our ttystate, but I believe this + was an artifact from before when we used readline. Readline sets + the tty state when it needs to. + FIXME-maybe: However, query() expects non-raw mode and doesn't + use readline. Maybe query should use readline (on the other hand, + this only matters for HAVE_SGTTY, not termio or termios, I think). */ + + /* Set tty state to our_ttystate. We don't change in our out of raw + mode, to avoid flushing input. We need to do the same thing + regardless of output_only, because we don't have separate + terminal_is_ours and terminal_is_ours_for_output flags. It's OK, + though, since readline will deal with raw mode when/if it needs to. + */ + + SERIAL_NOFLUSH_SET_TTY_STATE (stdin_serial, our_ttystate, + inferior_ttystate); + + if (job_control) + { +#ifdef HAVE_TERMIOS + result = tcsetpgrp (0, our_process_group); +#if 0 + /* This fails on Ultrix with EINVAL if you run the testsuite + in the background with nohup, and then log out. GDB never + used to check for an error here, so perhaps there are other + such situations as well. */ + if (result == -1) + fprintf_unfiltered (gdb_stderr, "[tcsetpgrp failed in terminal_ours: %s]\n", + strerror (errno)); +#endif +#endif /* termios */ + +#ifdef HAVE_SGTTY + result = ioctl (0, TIOCSPGRP, &our_process_group); +#endif + } + +#ifdef SIGTTOU + if (job_control) + signal (SIGTTOU, osigttou); +#endif + + if (!job_control) + { + signal (SIGINT, sigint_ours); + signal (SIGQUIT, sigquit_ours); + } + +#ifdef F_GETFL + tflags_inferior = fcntl (0, F_GETFL, 0); + + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_ours); + result = fcntl (0, F_SETFL, tflags_ours); +#endif + + result = result; /* lint */ + } +} + +/* ARGSUSED */ +void +term_info (arg, from_tty) + char *arg; + int from_tty; +{ + target_terminal_info (arg, from_tty); +} + +/* ARGSUSED */ +void +child_terminal_info (args, from_tty) + char *args; + int from_tty; +{ + if (!gdb_has_a_terminal ()) + { + printf_filtered ("This GDB does not control a terminal.\n"); + return; + } + + printf_filtered ("Inferior's terminal status (currently saved by GDB):\n"); + + /* First the fcntl flags. */ + { + int flags; + + flags = tflags_inferior; + + printf_filtered ("File descriptor flags = "); + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (flags & (O_ACCMODE)) + { + case O_RDONLY: printf_filtered ("O_RDONLY"); break; + case O_WRONLY: printf_filtered ("O_WRONLY"); break; + case O_RDWR: printf_filtered ("O_RDWR"); break; + } + flags &= ~(O_ACCMODE); + +#ifdef O_NONBLOCK + if (flags & O_NONBLOCK) + printf_filtered (" | O_NONBLOCK"); + flags &= ~O_NONBLOCK; +#endif + +#if defined (O_NDELAY) + /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will + print it as O_NONBLOCK, which is good cause that is what POSIX + has, and the flag will already be cleared by the time we get here. */ + if (flags & O_NDELAY) + printf_filtered (" | O_NDELAY"); + flags &= ~O_NDELAY; +#endif + + if (flags & O_APPEND) + printf_filtered (" | O_APPEND"); + flags &= ~O_APPEND; + +#if defined (O_BINARY) + if (flags & O_BINARY) + printf_filtered (" | O_BINARY"); + flags &= ~O_BINARY; +#endif + + if (flags) + printf_filtered (" | 0x%x", flags); + printf_filtered ("\n"); + } + +#ifdef PROCESS_GROUP_TYPE + printf_filtered ("Process group = %d\n", inferior_process_group); +#endif + + SERIAL_PRINT_TTY_STATE (stdin_serial, inferior_ttystate); +} + +/* NEW_TTY_PREFORK is called before forking a new child process, + so we can record the state of ttys in the child to be formed. + TTYNAME is null if we are to share the terminal with gdb; + or points to a string containing the name of the desired tty. + + NEW_TTY is called in new child processes under Unix, which will + become debugger target processes. This actually switches to + the terminal specified in the NEW_TTY_PREFORK call. */ + +void +new_tty_prefork (ttyname) + char *ttyname; +{ + /* Save the name for later, for determining whether we and the child + are sharing a tty. */ + inferior_thisrun_terminal = ttyname; +} + +void +new_tty () +{ + register int tty; + + if (inferior_thisrun_terminal == 0) + return; +#if !defined(__GO32__) && !defined(__WIN32__) +#ifdef TIOCNOTTY + /* Disconnect the child process from our controlling terminal. On some + systems (SVR4 for example), this may cause a SIGTTOU, so temporarily + ignore SIGTTOU. */ + tty = open("/dev/tty", O_RDWR); + if (tty > 0) + { + void (*osigttou) (); + + osigttou = (void (*)()) signal(SIGTTOU, SIG_IGN); + ioctl(tty, TIOCNOTTY, 0); + close(tty); + signal(SIGTTOU, osigttou); + } +#endif + + /* Now open the specified new terminal. */ + +#ifdef USE_O_NOCTTY + tty = open(inferior_thisrun_terminal, O_RDWR | O_NOCTTY); +#else + tty = open(inferior_thisrun_terminal, O_RDWR); +#endif + if (tty == -1) + { + print_sys_errmsg (inferior_thisrun_terminal, errno); + _exit(1); + } + + /* Avoid use of dup2; doesn't exist on all systems. */ + if (tty != 0) + { close (0); dup (tty); } + if (tty != 1) + { close (1); dup (tty); } + if (tty != 2) + { close (2); dup (tty); } + if (tty > 2) + close(tty); +#endif /* !go32 && !win32*/ +} + +/* Kill the inferior process. Make us have no inferior. */ + +/* ARGSUSED */ +static void +kill_command (arg, from_tty) + char *arg; + int from_tty; +{ + /* FIXME: This should not really be inferior_pid (or target_has_execution). + It should be a distinct flag that indicates that a target is active, cuz + some targets don't have processes! */ + + if (inferior_pid == 0) + error ("The program is not being run."); + if (!query ("Kill the program being debugged? ")) + error ("Not confirmed."); + target_kill (); + + init_thread_list(); /* Destroy thread info */ + + /* Killing off the inferior can leave us with a core file. If so, + print the state we are left in. */ + if (target_has_stack) { + printf_filtered ("In %s,\n", target_longname); + if (selected_frame == NULL) + fputs_filtered ("No selected stack frame.\n", gdb_stdout); + else + print_stack_frame (selected_frame, selected_frame_level, 1); + } +} + +/* Call set_sigint_trap when you need to pass a signal on to an attached + process when handling SIGINT */ + +/* ARGSUSED */ +static void +pass_signal (signo) + int signo; +{ + kill (inferior_pid, SIGINT); +} + +static void (*osig)(); + +void +set_sigint_trap() +{ + if (attach_flag || inferior_thisrun_terminal) + { + osig = (void (*) ()) signal (SIGINT, pass_signal); + } +} + +void +clear_sigint_trap() +{ + if (attach_flag || inferior_thisrun_terminal) + { + signal (SIGINT, osig); + } +} + +#if defined (SIGIO) && defined (FASYNC) && defined (FD_SET) && defined (F_SETOWN) +static void (*old_sigio) (); + +static void +handle_sigio (signo) + int signo; +{ + int numfds; + fd_set readfds; + + signal (SIGIO, handle_sigio); + + FD_ZERO (&readfds); + FD_SET (target_activity_fd, &readfds); + numfds = select (target_activity_fd + 1, &readfds, NULL, NULL, NULL); + if (numfds >= 0 && FD_ISSET (target_activity_fd, &readfds)) + { + if ((*target_activity_function) ()) + kill (inferior_pid, SIGINT); + } +} + +static int old_fcntl_flags; + +void +set_sigio_trap () +{ + if (target_activity_function) + { + old_sigio = (void (*) ()) signal (SIGIO, handle_sigio); + fcntl (target_activity_fd, F_SETOWN, getpid()); + old_fcntl_flags = fcntl (target_activity_fd, F_GETFL, 0); + fcntl (target_activity_fd, F_SETFL, old_fcntl_flags | FASYNC); + } +} + +void +clear_sigio_trap () +{ + if (target_activity_function) + { + signal (SIGIO, old_sigio); + fcntl (target_activity_fd, F_SETFL, old_fcntl_flags); + } +} +#else /* No SIGIO. */ +void +set_sigio_trap () +{ + if (target_activity_function) + abort (); +} + +void +clear_sigio_trap () +{ + if (target_activity_function) + abort (); +} +#endif /* No SIGIO. */ + + +/* This is here because this is where we figure out whether we (probably) + have job control. Just using job_control only does part of it because + setpgid or setpgrp might not exist on a system without job control. + It might be considered misplaced (on the other hand, process groups and + job control are closely related to ttys). + + For a more clean implementation, in libiberty, put a setpgid which merely + calls setpgrp and a setpgrp which does nothing (any system with job control + will have one or the other). */ +int +gdb_setpgid () +{ + int retval = 0; + + if (job_control) + { +#if defined (NEED_POSIX_SETPGID) || (defined (HAVE_TERMIOS) && defined (HAVE_SETPGID)) + /* setpgid (0, 0) is supposed to work and mean the same thing as + this, but on Ultrix 4.2A it fails with EPERM (and + setpgid (getpid (), getpid ()) succeeds). */ + retval = setpgid (getpid (), getpid ()); +#else +#if defined (TIOCGPGRP) +#if defined(USG) && !defined(SETPGRP_ARGS) + retval = setpgrp (); +#else + retval = setpgrp (getpid (), getpid ()); +#endif /* USG */ +#endif /* TIOCGPGRP. */ +#endif /* NEED_POSIX_SETPGID */ + } + return retval; +} + +void +_initialize_inflow () +{ + add_info ("terminal", term_info, + "Print inferior's saved terminal status."); + + add_com ("kill", class_run, kill_command, + "Kill execution of program being debugged."); + + inferior_pid = 0; + + terminal_is_ours = 1; + + /* OK, figure out whether we have job control. If neither termios nor + sgtty (i.e. termio or go32), leave job_control 0. */ + +#if defined (HAVE_TERMIOS) + /* Do all systems with termios have the POSIX way of identifying job + control? I hope so. */ +#ifdef _POSIX_JOB_CONTROL + job_control = 1; +#else +#ifdef _SC_JOB_CONTROL + job_control = sysconf (_SC_JOB_CONTROL); +#else + job_control = 0; /* have to assume the worst */ +#endif /* _SC_JOB_CONTROL */ +#endif /* _POSIX_JOB_CONTROL */ +#endif /* HAVE_TERMIOS */ + +#ifdef HAVE_SGTTY +#ifdef TIOCGPGRP + job_control = 1; +#else + job_control = 0; +#endif /* TIOCGPGRP */ +#endif /* sgtty */ +} diff --git a/contrib/gdb/gdb/infptrace.c b/contrib/gdb/gdb/infptrace.c new file mode 100644 index 000000000000..28210e49e39f --- /dev/null +++ b/contrib/gdb/gdb/infptrace.c @@ -0,0 +1,534 @@ +/* Low level Unix child interface to ptrace, for GDB when running under Unix. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "gdb_string.h" +#include "wait.h" +#include "command.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#ifndef NO_PTRACE_H +#ifdef PTRACE_IN_WRONG_PLACE +#include +#else +#include +#endif +#endif /* NO_PTRACE_H */ + +#if !defined (PT_READ_I) +#define PT_READ_I 1 /* Read word from text space */ +#endif +#if !defined (PT_READ_D) +#define PT_READ_D 2 /* Read word from data space */ +#endif +#if !defined (PT_READ_U) +#define PT_READ_U 3 /* Read word from kernel user struct */ +#endif +#if !defined (PT_WRITE_I) +#define PT_WRITE_I 4 /* Write word to text space */ +#endif +#if !defined (PT_WRITE_D) +#define PT_WRITE_D 5 /* Write word to data space */ +#endif +#if !defined (PT_WRITE_U) +#define PT_WRITE_U 6 /* Write word to kernel user struct */ +#endif +#if !defined (PT_CONTINUE) +#define PT_CONTINUE 7 /* Continue after signal */ +#endif +#if !defined (PT_STEP) +#define PT_STEP 9 /* Set flag for single stepping */ +#endif +#if !defined (PT_KILL) +#define PT_KILL 8 /* Send child a SIGKILL signal */ +#endif + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_DETACH +#define PT_DETACH PTRACE_DETACH +#endif + +#include "gdbcore.h" +#ifndef NO_SYS_FILE +#include +#endif +#if 0 +/* Don't think this is used anymore. On the sequent (not sure whether it's + dynix or ptx or both), it is included unconditionally by sys/user.h and + not protected against multiple inclusion. */ +#include "gdb_stat.h" +#endif + +#if !defined (FETCH_INFERIOR_REGISTERS) +#include /* Probably need to poke the user structure */ +#if defined (KERNEL_U_ADDR_BSD) +#include /* For struct nlist */ +#endif /* KERNEL_U_ADDR_BSD. */ +#endif /* !FETCH_INFERIOR_REGISTERS */ + + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return ptrace (request, pid, addr, data +#if defined (FIVE_ARG_PTRACE) + /* Deal with HPUX 8.0 braindamage. We never use the + calls which require the fifth argument. */ + , 0 +#endif + ); +} + +#if defined (DEBUG_PTRACE) || defined (FIVE_ARG_PTRACE) +/* For the rest of the file, use an extra level of indirection */ +/* This lets us breakpoint usefully on call_ptrace. */ +#define ptrace call_ptrace +#endif + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + /* ptrace PT_KILL only works if process is stopped!!! So stop it with + a real signal first, if we can. FIXME: This is bogus. When the inferior + is not stopped, GDB should just be waiting for it. Either the following + line is unecessary, or there is some problem elsewhere in GDB which + causes us to get here when the inferior is not stopped. */ + kill (inferior_pid, SIGKILL); + ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0); + wait ((int *)0); + target_mourn_inferior (); +} + +#ifndef CHILD_RESUME + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (pid, step, signal) + int pid; + int step; + enum target_signal signal; +{ + errno = 0; + + if (pid == -1) + /* Resume all threads. */ + /* I think this only gets used in the non-threaded case, where "resume + all threads" and "resume inferior_pid" are the same. */ + pid = inferior_pid; + + /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) + + If this system does not support PT_STEP, a higher level function will + have called single_step() to transmute the step request into a + continue request (by setting breakpoints on all possible successor + instructions), so we don't have to worry about that here. */ + + if (step) + ptrace (PT_STEP, pid, (PTRACE_ARG3_TYPE) 1, + target_signal_to_host (signal)); + else + ptrace (PT_CONTINUE, pid, (PTRACE_ARG3_TYPE) 1, + target_signal_to_host (signal)); + + if (errno) + perror_with_name ("ptrace"); +} +#endif /* CHILD_RESUME */ + + +#ifdef ATTACH_DETACH +/* Start debugging the process whose number is PID. */ +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif + +/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS) +/* Get kernel_u_addr using BSD-style nlist(). */ +CORE_ADDR kernel_u_addr; +#endif /* KERNEL_U_ADDR_BSD. */ + +void +_initialize_kernel_u_addr () +{ +#if defined (KERNEL_U_ADDR_BSD) && !defined (FETCH_INFERIOR_REGISTERS) + struct nlist names[2]; + + names[0].n_un.n_name = "_u"; + names[1].n_un.n_name = NULL; + if (nlist ("/vmunix", names) == 0) + kernel_u_addr = names[0].n_value; + else + fatal ("Unable to get kernel u area address."); +#endif /* KERNEL_U_ADDR_BSD. */ +} + +#if !defined (FETCH_INFERIOR_REGISTERS) + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +/* Registers we shouldn't try to fetch. */ +#if !defined (CANNOT_FETCH_REGISTER) +#define CANNOT_FETCH_REGISTER(regno) 0 +#endif + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + CORE_ADDR regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + char mess[128]; /* For messages */ + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + if (CANNOT_FETCH_REGISTER (regno)) + { + memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + int numregs; + + if (regno == -1) + { + numregs = ARCH_NUM_REGS; + for (regno = 0; regno < numregs; regno++) + fetch_register (regno); + } + else + fetch_register (regno); +} + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + CORE_ADDR regaddr; + char buf[80]; + register int i, numregs; + + unsigned int offset = U_REGS_OFFSET; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(PTRACE_XFER_TYPE); + } + } + else + { + numregs = ARCH_NUM_REGS; + for (regno = 0; regno < numregs; regno++) + { + if (CANNOT_STORE_REGISTER (regno)) + continue; + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(PTRACE_XFER_TYPE); + } + } + } +} +#endif /* !defined (FETCH_INFERIOR_REGISTERS). */ + + +#if !defined (CHILD_XFER_MEMORY) +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); + /* Allocate buffer of that many longwords. */ + register PTRACE_XFER_TYPE *buffer + = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_READ_I, inferior_pid, + ((PTRACE_ARG3_TYPE) + (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), + 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, + len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + buffer[i] = ptrace (PT_READ_I, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + len); + } + return len; +} + + +static void +udot_info () +{ + int udot_off; /* Offset into user struct */ + int udot_val; /* Value from user struct at udot_off */ + char mess[128]; /* For messages */ + + if (!target_has_execution) + { + error ("The program is not being run."); + } + +#if !defined (KERNEL_U_SIZE) + + /* Adding support for this command is easy. Typically you just add a + routine, called "kernel_u_size" that returns the size of the user + struct, to the appropriate *-nat.c file and then add to the native + config file "#define KERNEL_U_SIZE kernel_u_size()" */ + error ("Don't know how large ``struct user'' is in this version of gdb."); + +#else + + for (udot_off = 0; udot_off < KERNEL_U_SIZE; udot_off += sizeof (udot_val)) + { + if ((udot_off % 24) == 0) + { + if (udot_off > 0) + { + printf_filtered ("\n"); + } + printf_filtered ("%04x:", udot_off); + } + udot_val = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) udot_off, 0); + if (errno != 0) + { + sprintf (mess, "\nreading user struct at offset 0x%x", udot_off); + perror_with_name (mess); + } + /* Avoid using nonportable (?) "*" in print specs */ + printf_filtered (sizeof (int) == 4 ? " 0x%08x" : " 0x%16x", udot_val); + } + printf_filtered ("\n"); + +#endif +} +#endif /* !defined (CHILD_XFER_MEMORY). */ + + +void +_initialize_infptrace () +{ +#if !defined (CHILD_XFER_MEMORY) + add_info ("udot", udot_info, + "Print contents of kernel ``struct user'' for current child."); +#endif +} diff --git a/contrib/gdb/gdb/infrun.c b/contrib/gdb/gdb/infrun.c new file mode 100644 index 000000000000..90dbd8ebe2ff --- /dev/null +++ b/contrib/gdb/gdb/infrun.c @@ -0,0 +1,2224 @@ +/* Target-struct-independent code to start (run) and stop an inferior process. + Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "breakpoint.h" +#include "wait.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" +#include "thread.h" +#include "annotate.h" + +#include + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +/* Prototypes for local functions */ + +static void signals_info PARAMS ((char *, int)); + +static void handle_command PARAMS ((char *, int)); + +static void sig_print_info PARAMS ((enum target_signal)); + +static void sig_print_header PARAMS ((void)); + +static void resume_cleanups PARAMS ((int)); + +static int hook_stop_stub PARAMS ((char *)); + +/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the + program. It needs to examine the jmp_buf argument and extract the PC + from it. The return value is non-zero on success, zero otherwise. */ + +#ifndef GET_LONGJMP_TARGET +#define GET_LONGJMP_TARGET(PC_ADDR) 0 +#endif + + +/* Some machines have trampoline code that sits between function callers + and the actual functions themselves. If this machine doesn't have + such things, disable their processing. */ + +#ifndef SKIP_TRAMPOLINE_CODE +#define SKIP_TRAMPOLINE_CODE(pc) 0 +#endif + +/* Dynamic function trampolines are similar to solib trampolines in that they + are between the caller and the callee. The difference is that when you + enter a dynamic trampoline, you can't determine the callee's address. Some + (usually complex) code needs to run in the dynamic trampoline to figure out + the callee's address. This macro is usually called twice. First, when we + enter the trampoline (looks like a normal function call at that point). It + should return the PC of a point within the trampoline where the callee's + address is known. Second, when we hit the breakpoint, this routine returns + the callee's address. At that point, things proceed as per a step resume + breakpoint. */ + +#ifndef DYNAMIC_TRAMPOLINE_NEXTPC +#define DYNAMIC_TRAMPOLINE_NEXTPC(pc) 0 +#endif + +/* For SVR4 shared libraries, each call goes through a small piece of + trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates + to nonzero if we are current stopped in one of these. */ + +#ifndef IN_SOLIB_CALL_TRAMPOLINE +#define IN_SOLIB_CALL_TRAMPOLINE(pc,name) 0 +#endif + +/* In some shared library schemes, the return path from a shared library + call may need to go through a trampoline too. */ + +#ifndef IN_SOLIB_RETURN_TRAMPOLINE +#define IN_SOLIB_RETURN_TRAMPOLINE(pc,name) 0 +#endif + +/* On some systems, the PC may be left pointing at an instruction that won't + actually be executed. This is usually indicated by a bit in the PSW. If + we find ourselves in such a state, then we step the target beyond the + nullified instruction before returning control to the user so as to avoid + confusion. */ + +#ifndef INSTRUCTION_NULLIFIED +#define INSTRUCTION_NULLIFIED 0 +#endif + +/* Tables of how to react to signals; the user sets them. */ + +static unsigned char *signal_stop; +static unsigned char *signal_print; +static unsigned char *signal_program; + +#define SET_SIGS(nsigs,sigs,flags) \ + do { \ + int signum = (nsigs); \ + while (signum-- > 0) \ + if ((sigs)[signum]) \ + (flags)[signum] = 1; \ + } while (0) + +#define UNSET_SIGS(nsigs,sigs,flags) \ + do { \ + int signum = (nsigs); \ + while (signum-- > 0) \ + if ((sigs)[signum]) \ + (flags)[signum] = 0; \ + } while (0) + + +/* Command list pointer for the "stop" placeholder. */ + +static struct cmd_list_element *stop_command; + +/* Nonzero if breakpoints are now inserted in the inferior. */ + +static int breakpoints_inserted; + +/* Function inferior was in as of last step command. */ + +static struct symbol *step_start_function; + +/* Nonzero if we are expecting a trace trap and should proceed from it. */ + +static int trap_expected; + +/* Nonzero if we want to give control to the user when we're notified + of shared library events by the dynamic linker. */ +static int stop_on_solib_events; + +#ifdef HP_OS_BUG +/* Nonzero if the next time we try to continue the inferior, it will + step one instruction and generate a spurious trace trap. + This is used to compensate for a bug in HP-UX. */ + +static int trap_expected_after_continue; +#endif + +/* Nonzero means expecting a trace trap + and should stop the inferior and return silently when it happens. */ + +int stop_after_trap; + +/* Nonzero means expecting a trap and caller will handle it themselves. + It is used after attach, due to attaching to a process; + when running in the shell before the child program has been exec'd; + and when running some kinds of remote stuff (FIXME?). */ + +int stop_soon_quietly; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +char stop_registers[REGISTER_BYTES]; + +/* Nonzero if program stopped due to error trying to insert breakpoints. */ + +static int breakpoints_failed; + +/* Nonzero after stop if current stack frame should be printed. */ + +static int stop_print_frame; + +#ifdef NO_SINGLE_STEP +extern int one_stepped; /* From machine dependent code */ +extern void single_step (); /* Same. */ +#endif /* NO_SINGLE_STEP */ + +extern void write_pc_pid PARAMS ((CORE_ADDR, int)); + + +/* Things to clean up if we QUIT out of resume (). */ +/* ARGSUSED */ +static void +resume_cleanups (arg) + int arg; +{ + normal_stop (); +} + +/* Resume the inferior, but allow a QUIT. This is useful if the user + wants to interrupt some lengthy single-stepping operation + (for child processes, the SIGINT goes to the inferior, and so + we get a SIGINT random_signal, but for remote debugging and perhaps + other targets, that's not true). + + STEP nonzero if we should step (zero to continue instead). + SIG is the signal to give the inferior (zero for none). */ +void +resume (step, sig) + int step; + enum target_signal sig; +{ + struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); + QUIT; + +#ifdef CANNOT_STEP_BREAKPOINT + /* Most targets can step a breakpoint instruction, thus executing it + normally. But if this one cannot, just continue and we will hit + it anyway. */ + if (step && breakpoints_inserted && breakpoint_here_p (read_pc ())) + step = 0; +#endif + +#ifdef NO_SINGLE_STEP + if (step) { + single_step(sig); /* Do it the hard way, w/temp breakpoints */ + step = 0; /* ...and don't ask hardware to do it. */ + } +#endif + + /* Handle any optimized stores to the inferior NOW... */ +#ifdef DO_DEFERRED_STORES + DO_DEFERRED_STORES; +#endif + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + target_resume (-1, step, sig); + discard_cleanups (old_cleanups); +} + + +/* Clear out all variables saying what to do when inferior is continued. + First do this, then set the ones you want, then call `proceed'. */ + +void +clear_proceed_status () +{ + trap_expected = 0; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + step_over_calls = -1; + stop_after_trap = 0; + stop_soon_quietly = 0; + proceed_to_finish = 0; + breakpoint_proceeded = 1; /* We're about to proceed... */ + + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&stop_bpstat); +} + +/* Basic routine for continuing the program in various fashions. + + ADDR is the address to resume at, or -1 for resume where stopped. + SIGGNAL is the signal to give it, or 0 for none, + or -1 for act according to how it stopped. + STEP is nonzero if should trap after one instruction. + -1 means return after that and print nothing. + You should probably set various step_... variables + before calling here, if you are stepping. + + You should call clear_proceed_status before calling proceed. */ + +void +proceed (addr, siggnal, step) + CORE_ADDR addr; + enum target_signal siggnal; + int step; +{ + int oneproc = 0; + + if (step > 0) + step_start_function = find_pc_function (read_pc ()); + if (step < 0) + stop_after_trap = 1; + + if (addr == (CORE_ADDR)-1) + { + /* If there is a breakpoint at the address we will resume at, + step one instruction before inserting breakpoints + so that we do not stop right away. */ + + if (breakpoint_here_p (read_pc ())) + oneproc = 1; + +#ifdef STEP_SKIPS_DELAY + /* Check breakpoint_here_p first, because breakpoint_here_p is fast + (it just checks internal GDB data structures) and STEP_SKIPS_DELAY + is slow (it needs to read memory from the target). */ + if (breakpoint_here_p (read_pc () + 4) + && STEP_SKIPS_DELAY (read_pc ())) + oneproc = 1; +#endif /* STEP_SKIPS_DELAY */ + } + else + write_pc (addr); + +#ifdef PREPARE_TO_PROCEED + /* In a multi-threaded task we may select another thread and then continue. + + In this case the thread that stopped at a breakpoint will immediately + cause another stop, if it is not stepped over first. On the other hand, + if (ADDR != -1) we only want to single step over the breakpoint if we did + switch to another thread. + + If we are single stepping, don't do any of the above. + (Note that in the current implementation single stepping another + thread after a breakpoint and then continuing will cause the original + breakpoint to be hit again, but you can always continue, so it's not + a big deal.) */ + + if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ())) + oneproc = 1; +#endif /* PREPARE_TO_PROCEED */ + +#ifdef HP_OS_BUG + if (trap_expected_after_continue) + { + /* If (step == 0), a trap will be automatically generated after + the first instruction is executed. Force step one + instruction to clear this condition. This should not occur + if step is nonzero, but it is harmless in that case. */ + oneproc = 1; + trap_expected_after_continue = 0; + } +#endif /* HP_OS_BUG */ + + if (oneproc) + /* We will get a trace trap after one instruction. + Continue it automatically and insert breakpoints then. */ + trap_expected = 1; + else + { + int temp = insert_breakpoints (); + if (temp) + { + print_sys_errmsg ("ptrace", temp); + error ("Cannot insert breakpoints.\n\ +The same program may be running in another process."); + } + breakpoints_inserted = 1; + } + + if (siggnal != TARGET_SIGNAL_DEFAULT) + stop_signal = siggnal; + /* If this signal should not be seen by program, + give it zero. Used for debugging signals. */ + else if (!signal_program[stop_signal]) + stop_signal = TARGET_SIGNAL_0; + + annotate_starting (); + + /* Make sure that output from GDB appears before output from the + inferior. */ + gdb_flush (gdb_stdout); + + /* Resume inferior. */ + resume (oneproc || step || bpstat_should_step (), stop_signal); + + /* Wait for it to stop (if not standalone) + and in any case decode why it stopped, and act accordingly. */ + + wait_for_inferior (); + normal_stop (); +} + +/* Record the pc and sp of the program the last time it stopped. + These are just used internally by wait_for_inferior, but need + to be preserved over calls to it and cleared when the inferior + is started. */ +static CORE_ADDR prev_pc; +static CORE_ADDR prev_func_start; +static char *prev_func_name; + + +/* Start remote-debugging of a machine over a serial link. */ + +void +start_remote () +{ + init_thread_list (); + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + trap_expected = 0; + wait_for_inferior (); + normal_stop (); +} + +/* Initialize static vars when a new inferior begins. */ + +void +init_wait_for_inferior () +{ + /* These are meaningless until the first time through wait_for_inferior. */ + prev_pc = 0; + prev_func_start = 0; + prev_func_name = NULL; + +#ifdef HP_OS_BUG + trap_expected_after_continue = 0; +#endif + breakpoints_inserted = 0; + breakpoint_init_inferior (); + + /* Don't confuse first call to proceed(). */ + stop_signal = TARGET_SIGNAL_0; +} + +static void +delete_breakpoint_current_contents (arg) + PTR arg; +{ + struct breakpoint **breakpointp = (struct breakpoint **)arg; + if (*breakpointp != NULL) + delete_breakpoint (*breakpointp); +} + +/* Wait for control to return from inferior to debugger. + If inferior gets a signal, we may decide to start it up again + instead of returning. That is why there is a loop in this function. + When this function actually returns it means the inferior + should be left stopped and GDB should read more commands. */ + +void +wait_for_inferior () +{ + struct cleanup *old_cleanups; + struct target_waitstatus w; + int another_trap; + int random_signal; + CORE_ADDR stop_func_start; + CORE_ADDR stop_func_end; + char *stop_func_name; +#if 0 + CORE_ADDR prologue_pc = 0; +#endif + CORE_ADDR tmp; + struct symtab_and_line sal; + int remove_breakpoints_on_following_step = 0; + int current_line; + struct symtab *current_symtab; + int handling_longjmp = 0; /* FIXME */ + struct breakpoint *step_resume_breakpoint = NULL; + struct breakpoint *through_sigtramp_breakpoint = NULL; + int pid; + int update_step_sp = 0; + + old_cleanups = make_cleanup (delete_breakpoint_current_contents, + &step_resume_breakpoint); + make_cleanup (delete_breakpoint_current_contents, + &through_sigtramp_breakpoint); + sal = find_pc_line(prev_pc, 0); + current_line = sal.line; + current_symtab = sal.symtab; + + /* Are we stepping? */ +#define CURRENTLY_STEPPING() \ + ((through_sigtramp_breakpoint == NULL \ + && !handling_longjmp \ + && ((step_range_end && step_resume_breakpoint == NULL) \ + || trap_expected)) \ + || bpstat_should_step ()) + + while (1) + { + /* We have to invalidate the registers BEFORE calling target_wait because + they can be loaded from the target while in target_wait. This makes + remote debugging a bit more efficient for those targets that provide + critical registers as part of their normal status mechanism. */ + + registers_changed (); + + if (target_wait_hook) + pid = target_wait_hook (-1, &w); + else + pid = target_wait (-1, &w); + +#ifdef HAVE_NONSTEPPABLE_WATCHPOINT + have_waited: +#endif + + flush_cached_frames (); + + /* If it's a new process, add it to the thread database */ + + if (pid != inferior_pid + && !in_thread_list (pid)) + { + fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); + add_thread (pid); + + /* We may want to consider not doing a resume here in order to give + the user a chance to play with the new thread. It might be good + to make that a user-settable option. */ + + /* At this point, all threads are stopped (happens automatically in + either the OS or the native code). Therefore we need to continue + all threads in order to make progress. */ + + target_resume (-1, 0, TARGET_SIGNAL_0); + continue; + } + + switch (w.kind) + { + case TARGET_WAITKIND_LOADED: + /* Ignore it gracefully. */ + if (breakpoints_inserted) + { + mark_breakpoints_out (); + insert_breakpoints (); + } + resume (0, TARGET_SIGNAL_0); + continue; + + case TARGET_WAITKIND_SPURIOUS: + resume (0, TARGET_SIGNAL_0); + continue; + + case TARGET_WAITKIND_EXITED: + target_terminal_ours (); /* Must do this before mourn anyway */ + annotate_exited (w.value.integer); + if (w.value.integer) + printf_filtered ("\nProgram exited with code 0%o.\n", + (unsigned int)w.value.integer); + else + printf_filtered ("\nProgram exited normally.\n"); + + /* Record the exit code in the convenience variable $_exitcode, so + that the user can inspect this again later. */ + set_internalvar (lookup_internalvar ("_exitcode"), + value_from_longest (builtin_type_int, + (LONGEST) w.value.integer)); + gdb_flush (gdb_stdout); + target_mourn_inferior (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + stop_print_frame = 0; + goto stop_stepping; + + case TARGET_WAITKIND_SIGNALLED: + stop_print_frame = 0; + stop_signal = w.value.sig; + target_terminal_ours (); /* Must do this before mourn anyway */ + annotate_signalled (); + + /* This looks pretty bogus to me. Doesn't TARGET_WAITKIND_SIGNALLED + mean it is already dead? This has been here since GDB 2.8, so + perhaps it means rms didn't understand unix waitstatuses? + For the moment I'm just kludging around this in remote.c + rather than trying to change it here --kingdon, 5 Dec 1994. */ + target_kill (); /* kill mourns as well */ + + printf_filtered ("\nProgram terminated with signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_signal)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_signal)); + annotate_signal_string_end (); + printf_filtered (".\n"); + + printf_filtered ("The program no longer exists.\n"); + gdb_flush (gdb_stdout); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + goto stop_stepping; + + case TARGET_WAITKIND_STOPPED: + /* This is the only case in which we keep going; the above cases + end in a continue or goto. */ + break; + } + + stop_signal = w.value.sig; + + stop_pc = read_pc_pid (pid); + + /* See if a thread hit a thread-specific breakpoint that was meant for + another thread. If so, then step that thread past the breakpoint, + and continue it. */ + + if (stop_signal == TARGET_SIGNAL_TRAP + && breakpoints_inserted + && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) + { + random_signal = 0; + if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid)) + { + /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ + write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, pid); + + remove_breakpoints (); + target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ + /* FIXME: What if a signal arrives instead of the single-step + happening? */ + + if (target_wait_hook) + target_wait_hook (pid, &w); + else + target_wait (pid, &w); + insert_breakpoints (); + + /* We need to restart all the threads now. */ + target_resume (-1, 0, TARGET_SIGNAL_0); + continue; + } + } + else + random_signal = 1; + + /* See if something interesting happened to the non-current thread. If + so, then switch to that thread, and eventually give control back to + the user. */ + + if (pid != inferior_pid) + { + int printed = 0; + + /* If it's a random signal for a non-current thread, notify user + if he's expressed an interest. */ + + if (random_signal + && signal_print[stop_signal]) + { + printed = 1; + target_terminal_ours_for_output (); + printf_filtered ("\nProgram received signal %s, %s.\n", + target_signal_to_name (stop_signal), + target_signal_to_string (stop_signal)); + gdb_flush (gdb_stdout); + } + + /* If it's not SIGTRAP and not a signal we want to stop for, then + continue the thread. */ + + if (stop_signal != TARGET_SIGNAL_TRAP + && !signal_stop[stop_signal]) + { + if (printed) + target_terminal_inferior (); + + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = TARGET_SIGNAL_0; + + target_resume (pid, 0, stop_signal); + continue; + } + + /* It's a SIGTRAP or a signal we're interested in. Switch threads, + and fall into the rest of wait_for_inferior(). */ + + /* Save infrun state for the old thread. */ + save_infrun_state (inferior_pid, prev_pc, + prev_func_start, prev_func_name, + trap_expected, step_resume_breakpoint, + through_sigtramp_breakpoint, + step_range_start, step_range_end, + step_frame_address, handling_longjmp, + another_trap); + + inferior_pid = pid; + + /* Load infrun state for the new thread. */ + load_infrun_state (inferior_pid, &prev_pc, + &prev_func_start, &prev_func_name, + &trap_expected, &step_resume_breakpoint, + &through_sigtramp_breakpoint, + &step_range_start, &step_range_end, + &step_frame_address, &handling_longjmp, + &another_trap); + printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); + + flush_cached_frames (); + } + +#ifdef NO_SINGLE_STEP + if (one_stepped) + single_step (0); /* This actually cleans up the ss */ +#endif /* NO_SINGLE_STEP */ + + /* If PC is pointing at a nullified instruction, then step beyond + it so that the user won't be confused when GDB appears to be ready + to execute it. */ + + if (INSTRUCTION_NULLIFIED) + { + resume (1, 0); + continue; + } + +#ifdef HAVE_STEPPABLE_WATCHPOINT + /* It may not be necessary to disable the watchpoint to stop over + it. For example, the PA can (with some kernel cooperation) + single step over a watchpoint without disabling the watchpoint. */ + if (STOPPED_BY_WATCHPOINT (w)) + { + resume (1, 0); + continue; + } +#endif + +#ifdef HAVE_NONSTEPPABLE_WATCHPOINT + /* It is far more common to need to disable a watchpoint + to step the inferior over it. FIXME. What else might + a debug register or page protection watchpoint scheme need + here? */ + if (STOPPED_BY_WATCHPOINT (w)) + { +/* At this point, we are stopped at an instruction which has attempted to write + to a piece of memory under control of a watchpoint. The instruction hasn't + actually executed yet. If we were to evaluate the watchpoint expression + now, we would get the old value, and therefore no change would seem to have + occurred. + + In order to make watchpoints work `right', we really need to complete the + memory write, and then evaluate the watchpoint expression. The following + code does that by removing the watchpoint (actually, all watchpoints and + breakpoints), single-stepping the target, re-inserting watchpoints, and then + falling through to let normal single-step processing handle proceed. Since + this includes evaluating watchpoints, things will come to a stop in the + correct manner. */ + + write_pc (stop_pc - DECR_PC_AFTER_BREAK); + + remove_breakpoints (); + target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ + + if (target_wait_hook) + target_wait_hook (pid, &w); + else + target_wait (pid, &w); + insert_breakpoints (); + /* FIXME-maybe: is this cleaner than setting a flag? Does it + handle things like signals arriving and other things happening + in combination correctly? */ + goto have_waited; + } +#endif + +#ifdef HAVE_CONTINUABLE_WATCHPOINT + /* It may be possible to simply continue after a watchpoint. */ + STOPPED_BY_WATCHPOINT (w); +#endif + + stop_func_start = 0; + stop_func_name = 0; + /* Don't care about return value; stop_func_start and stop_func_name + will both be 0 if it doesn't work. */ + find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start, + &stop_func_end); + stop_func_start += FUNCTION_START_OFFSET; + another_trap = 0; + bpstat_clear (&stop_bpstat); + stop_step = 0; + stop_stack_dummy = 0; + stop_print_frame = 1; + random_signal = 0; + stopped_by_random_signal = 0; + breakpoints_failed = 0; + + /* Look at the cause of the stop, and decide what to do. + The alternatives are: + 1) break; to really stop and return to the debugger, + 2) drop through to start up again + (set another_trap to 1 to single step once) + 3) set random_signal to 1, and the decision between 1 and 2 + will be made according to the signal handling tables. */ + + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. + Note that breakpoint insns may cause SIGTRAP or SIGILL + or SIGEMT, depending on the operating system version. + Here we detect when a SIGILL or SIGEMT is really a breakpoint + and change it to SIGTRAP. */ + + if (stop_signal == TARGET_SIGNAL_TRAP + || (breakpoints_inserted && + (stop_signal == TARGET_SIGNAL_ILL + || stop_signal == TARGET_SIGNAL_EMT + )) + || stop_soon_quietly) + { + if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap) + { + stop_print_frame = 0; + break; + } + if (stop_soon_quietly) + break; + + /* Don't even think about breakpoints + if just proceeded over a breakpoint. + + However, if we are trying to proceed over a breakpoint + and end up in sigtramp, then through_sigtramp_breakpoint + will be set and we should check whether we've hit the + step breakpoint. */ + if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected + && through_sigtramp_breakpoint == NULL) + bpstat_clear (&stop_bpstat); + else + { + /* See if there is a breakpoint at the current PC. */ + stop_bpstat = bpstat_stop_status + (&stop_pc, +#if DECR_PC_AFTER_BREAK + /* Notice the case of stepping through a jump + that lands just after a breakpoint. + Don't confuse that with hitting the breakpoint. + What we check for is that 1) stepping is going on + and 2) the pc before the last insn does not match + the address of the breakpoint before the current pc. */ + (prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && CURRENTLY_STEPPING ()) +#else /* DECR_PC_AFTER_BREAK zero */ + 0 +#endif /* DECR_PC_AFTER_BREAK zero */ + ); + /* Following in case break condition called a + function. */ + stop_print_frame = 1; + } + + if (stop_signal == TARGET_SIGNAL_TRAP) + random_signal + = !(bpstat_explains_signal (stop_bpstat) + || trap_expected +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + || (step_range_end && step_resume_breakpoint == NULL)); + else + { + random_signal + = !(bpstat_explains_signal (stop_bpstat) + /* End of a stack dummy. Some systems (e.g. Sony + news) give another signal besides SIGTRAP, + so check here as well as above. */ +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + ); + if (!random_signal) + stop_signal = TARGET_SIGNAL_TRAP; + } + } + else + random_signal = 1; + + /* For the program's own signals, act according to + the signal handling tables. */ + + if (random_signal) + { + /* Signal not for debugging purposes. */ + int printed = 0; + + stopped_by_random_signal = 1; + + if (signal_print[stop_signal]) + { + printed = 1; + target_terminal_ours_for_output (); + annotate_signal (); + printf_filtered ("\nProgram received signal "); + annotate_signal_name (); + printf_filtered ("%s", target_signal_to_name (stop_signal)); + annotate_signal_name_end (); + printf_filtered (", "); + annotate_signal_string (); + printf_filtered ("%s", target_signal_to_string (stop_signal)); + annotate_signal_string_end (); + printf_filtered (".\n"); + gdb_flush (gdb_stdout); + } + if (signal_stop[stop_signal]) + break; + /* If not going to stop, give terminal back + if we took it away. */ + else if (printed) + target_terminal_inferior (); + + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = TARGET_SIGNAL_0; + + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + goto check_sigtramp2; + } + + /* Handle cases caused by hitting a breakpoint. */ + { + CORE_ADDR jmp_buf_pc; + struct bpstat_what what; + + what = bpstat_what (stop_bpstat); + + if (what.call_dummy) + { + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + } + + switch (what.main_action) + { + case BPSTAT_WHAT_SET_LONGJMP_RESUME: + /* If we hit the breakpoint at longjmp, disable it for the + duration of this command. Then, install a temporary + breakpoint at the target of the jmp_buf. */ + disable_longjmp_breakpoint(); + remove_breakpoints (); + breakpoints_inserted = 0; + if (!GET_LONGJMP_TARGET(&jmp_buf_pc)) goto keep_going; + + /* Need to blow away step-resume breakpoint, as it + interferes with us */ + if (step_resume_breakpoint != NULL) + { + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + } + /* Not sure whether we need to blow this away too, but probably + it is like the step-resume breakpoint. */ + if (through_sigtramp_breakpoint != NULL) + { + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; + } + +#if 0 + /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls > 0) + set_longjmp_resume_breakpoint(jmp_buf_pc, + get_current_frame()); + else +#endif /* 0 */ + set_longjmp_resume_breakpoint(jmp_buf_pc, NULL); + handling_longjmp = 1; /* FIXME */ + goto keep_going; + + case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: + case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE: + remove_breakpoints (); + breakpoints_inserted = 0; +#if 0 + /* FIXME - Need to implement nested temporary breakpoints */ + if (step_over_calls + && (FRAME_FP (get_current_frame ()) + INNER_THAN step_frame_address)) + { + another_trap = 1; + goto keep_going; + } +#endif /* 0 */ + disable_longjmp_breakpoint(); + handling_longjmp = 0; /* FIXME */ + if (what.main_action == BPSTAT_WHAT_CLEAR_LONGJMP_RESUME) + break; + /* else fallthrough */ + + case BPSTAT_WHAT_SINGLE: + if (breakpoints_inserted) + remove_breakpoints (); + breakpoints_inserted = 0; + another_trap = 1; + /* Still need to check other stuff, at least the case + where we are stepping and step out of the right range. */ + break; + + case BPSTAT_WHAT_STOP_NOISY: + stop_print_frame = 1; + + /* We are about to nuke the step_resume_breakpoint and + through_sigtramp_breakpoint via the cleanup chain, so + no need to worry about it here. */ + + goto stop_stepping; + + case BPSTAT_WHAT_STOP_SILENT: + stop_print_frame = 0; + + /* We are about to nuke the step_resume_breakpoint and + through_sigtramp_breakpoint via the cleanup chain, so + no need to worry about it here. */ + + goto stop_stepping; + + case BPSTAT_WHAT_STEP_RESUME: + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; + break; + + case BPSTAT_WHAT_THROUGH_SIGTRAMP: + if (through_sigtramp_breakpoint) + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; + + /* If were waiting for a trap, hitting the step_resume_break + doesn't count as getting it. */ + if (trap_expected) + another_trap = 1; + break; + +#ifdef SOLIB_ADD + case BPSTAT_WHAT_CHECK_SHLIBS: + { + extern int auto_solib_add; + + /* Remove breakpoints, we eventually want to step over the + shlib event breakpoint, and SOLIB_ADD might adjust + breakpoint addresses via breakpoint_re_set. */ + if (breakpoints_inserted) + remove_breakpoints (); + breakpoints_inserted = 0; + + /* Check for any newly added shared libraries if we're + supposed to be adding them automatically. */ + if (auto_solib_add) + { + /* Switch terminal for any messages produced by + breakpoint_re_set. */ + target_terminal_ours_for_output (); + SOLIB_ADD (NULL, 0, NULL); + re_enable_breakpoints_in_shlibs (); + target_terminal_inferior (); + } + + /* 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) + { + stop_print_frame = 0; + goto stop_stepping; + } + else + { + /* We want to step over this breakpoint, then keep going. */ + another_trap = 1; + break; + } + } +#endif + + case BPSTAT_WHAT_LAST: + /* Not a real code, but listed here to shut up gcc -Wall. */ + + case BPSTAT_WHAT_KEEP_CHECKING: + break; + } + } + + /* We come here if we hit a breakpoint but should not + stop for it. Possibly we also were stepping + and should stop for that. So fall through and + test for stepping. But, if not stepping, + do not stop. */ + +#ifndef CALL_DUMMY_BREAKPOINT_OFFSET + /* This is the old way of detecting the end of the stack dummy. + An architecture which defines CALL_DUMMY_BREAKPOINT_OFFSET gets + handled above. As soon as we can test it on all of them, all + architectures should define it. */ + + /* If this is the breakpoint at the end of a stack dummy, + just stop silently, unless the user was doing an si/ni, in which + case she'd better know what she's doing. */ + + if (PC_IN_CALL_DUMMY (stop_pc, read_sp (), FRAME_FP (get_current_frame ())) + && !step_range_end) + { + stop_print_frame = 0; + stop_stack_dummy = 1; +#ifdef HP_OS_BUG + trap_expected_after_continue = 1; +#endif + break; + } +#endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ + + if (step_resume_breakpoint) + /* Having a step-resume breakpoint overrides anything + else having to do with stepping commands until + that breakpoint is reached. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + goto check_sigtramp2; + + if (step_range_end == 0) + /* Likewise if we aren't even stepping. */ + /* I'm not sure whether this needs to be check_sigtramp2 or + whether it could/should be keep_going. */ + goto check_sigtramp2; + + /* If stepping through a line, keep going if still within it. */ + if (stop_pc >= step_range_start + && stop_pc < step_range_end +#if 0 +/* I haven't a clue what might trigger this clause, and it seems wrong anyway, + so I've disabled it until someone complains. -Stu 10/24/95 */ + + /* The step range might include the start of the + function, so if we are at the start of the + step range and either the stack or frame pointers + just changed, we've stepped outside */ + && !(stop_pc == step_range_start + && FRAME_FP (get_current_frame ()) + && (read_sp () INNER_THAN step_sp + || FRAME_FP (get_current_frame ()) != step_frame_address)) +#endif +) + { + /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal. + So definately need to check for sigtramp here. */ + goto check_sigtramp2; + } + + /* We stepped out of the stepping range. */ + + /* We can't update step_sp every time through the loop, because + reading the stack pointer would slow down stepping too much. + But we can update it every time we leave the step range. */ + update_step_sp = 1; + + /* Did we just take a signal? */ + if (IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* We've just taken a signal; go until we are back to + the point where we took it and one more. */ + + /* This code is needed at least in the following case: + The user types "next" and then a signal arrives (before + the "next" is done). */ + + /* Note that if we are stopped at a breakpoint, then we need + the step_resume breakpoint to override any breakpoints at + the same location, so that we will still step over the + breakpoint even though the signal happened. */ + + { + struct symtab_and_line sr_sal; + + sr_sal.pc = prev_pc; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* We could probably be setting the frame to + step_frame_address; I don't think anyone thought to try it. */ + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + } + + /* If this is stepi or nexti, make sure that the stepping range + gets us past that instruction. */ + if (step_range_end == 1) + /* FIXME: Does this run afoul of the code below which, if + we step into the middle of a line, resets the stepping + range? */ + step_range_end = (step_range_start = prev_pc) + 1; + + remove_breakpoints_on_following_step = 1; + goto keep_going; + } + +#if 0 + /* I disabled this test because it was too complicated and slow. The + SKIP_PROLOGUE was especially slow, because it caused unnecessary + prologue examination on various architectures. The code in the #else + clause has been tested on the Sparc, Mips, PA, and Power + architectures, so it's pretty likely to be correct. -Stu 10/24/95 */ + + /* See if we left the step range due to a subroutine call that + we should proceed to the end of. */ + + if (stop_func_start) + { + struct symtab *s; + + /* Do this after the IN_SIGTRAMP check; it might give + an error. */ + prologue_pc = stop_func_start; + + /* Don't skip the prologue if this is assembly source */ + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + SKIP_PROLOGUE (prologue_pc); + } + + if ((/* Might be a non-recursive call. If the symbols are missing + enough that stop_func_start == prev_func_start even though + they are really two functions, we will treat some calls as + jumps. */ + stop_func_start != prev_func_start + + /* Might be a recursive call if either we have a prologue + or the call instruction itself saves the PC on the stack. */ + || prologue_pc != stop_func_start + || read_sp () != step_sp) + && (/* PC is completely out of bounds of any known objfiles. Treat + like a subroutine call. */ + ! stop_func_start + + /* If we do a call, we will be at the start of a function... */ + || stop_pc == stop_func_start + + /* ...except on the Alpha with -O (and also Irix 5 and + perhaps others), in which we might call the address + after the load of gp. Since prologues don't contain + calls, we can't return to within one, and we don't + jump back into them, so this check is OK. */ + + || stop_pc < prologue_pc + + /* ...and if it is a leaf function, the prologue might + consist of gp loading only, so the call transfers to + the first instruction after the prologue. */ + || (stop_pc == prologue_pc + + /* Distinguish this from the case where we jump back + to the first instruction after the prologue, + within a function. */ + && stop_func_start != prev_func_start) + + /* If we end up in certain places, it means we did a subroutine + call. I'm not completely sure this is necessary now that we + have the above checks with stop_func_start (and now that + find_pc_partial_function is pickier). */ + || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name) + + /* If none of the above apply, it is a jump within a function, + or a return from a subroutine. The other case is longjmp, + which can no longer happen here as long as the + handling_longjmp stuff is working. */ + )) +#else + /* This test is a much more streamlined, (but hopefully correct) + replacement for the code above. It's been tested on the Sparc, + Mips, PA, and Power architectures with good results. */ + + if (stop_pc == stop_func_start /* Quick test */ + || in_prologue (stop_pc, stop_func_start) + || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name) + || stop_func_start == 0) +#endif + + { + /* It's a subroutine call. */ + + if (step_over_calls == 0) + { + /* I presume that step_over_calls is only 0 when we're + supposed to be stepping at the assembly language level + ("stepi"). Just stop. */ + stop_step = 1; + break; + } + + if (step_over_calls > 0) + /* We're doing a "next". */ + goto step_over_function; + + /* If we are in a function call trampoline (a stub between + the calling routine and the real function), locate the real + function. That's what tells us (a) whether we want to step + into it at all, and (b) what prologue we want to run to + the end of, if we do step into it. */ + tmp = SKIP_TRAMPOLINE_CODE (stop_pc); + if (tmp != 0) + stop_func_start = tmp; + else + { + tmp = DYNAMIC_TRAMPOLINE_NEXTPC (stop_pc); + if (tmp) + { + struct symtab_and_line xxx; + + xxx.pc = tmp; + xxx.symtab = NULL; + xxx.line = 0; + step_resume_breakpoint = + set_momentary_breakpoint (xxx, NULL, bp_step_resume); + insert_breakpoints (); + goto keep_going; + } + } + + /* If we have line number information for the function we + are thinking of stepping into, step into it. + + If there are several symtabs at that PC (e.g. with include + files), just want to know whether *any* of them have line + numbers. find_pc_line handles this. */ + { + struct symtab_and_line tmp_sal; + + tmp_sal = find_pc_line (stop_func_start, 0); + if (tmp_sal.line != 0) + goto step_into_function; + } + +step_over_function: + /* A subroutine call has happened. */ + { + /* Set a special breakpoint after the return */ + struct symtab_and_line sr_sal; + sr_sal.pc = + ADDR_BITS_REMOVE + (SAVED_PC_AFTER_CALL (get_current_frame ())); + sr_sal.symtab = NULL; + sr_sal.line = 0; + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, get_current_frame (), + bp_step_resume); + step_resume_breakpoint->frame = step_frame_address; + if (breakpoints_inserted) + insert_breakpoints (); + } + goto keep_going; + +step_into_function: + /* Subroutine call with source code we should not step over. + Do step to the first line of code in it. */ + { + struct symtab *s; + + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + SKIP_PROLOGUE (stop_func_start); + } + sal = find_pc_line (stop_func_start, 0); + /* Use the step_resume_break to step until + the end of the prologue, even if that involves jumps + (as it seems to on the vax under 4.2). */ + /* If the prologue ends in the middle of a source line, + continue to the end of that source line (if it is still + within the function). Otherwise, just go to end of prologue. */ +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* no, don't either. It skips any code that's + legitimately on the first line. */ +#else + if (sal.end && sal.pc != stop_func_start && sal.end < stop_func_end) + stop_func_start = sal.end; +#endif + + if (stop_func_start == stop_pc) + { + /* We are already there: stop now. */ + stop_step = 1; + break; + } + else + /* Put the step-breakpoint there and go until there. */ + { + struct symtab_and_line sr_sal; + + sr_sal.pc = stop_func_start; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* Do not specify what the fp should be when we stop + since on some machines the prologue + is where the new fp value is established. */ + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + + /* And make sure stepping stops right away then. */ + step_range_end = step_range_start; + } + goto keep_going; + } + + /* We've wandered out of the step range. */ + + sal = find_pc_line(stop_pc, 0); + + if (step_range_end == 1) + { + /* It is stepi or nexti. We always want to stop stepping after + one instruction. */ + stop_step = 1; + break; + } + + /* If we're in the return path from a shared library trampoline, + we want to proceed through the trampoline when stepping. */ + if (IN_SOLIB_RETURN_TRAMPOLINE(stop_pc, stop_func_name)) + { + CORE_ADDR tmp; + + /* Determine where this trampoline returns. */ + tmp = SKIP_TRAMPOLINE_CODE (stop_pc); + + /* Only proceed through if we know where it's going. */ + if (tmp) + { + /* And put the step-breakpoint there and go until there. */ + struct symtab_and_line sr_sal; + + sr_sal.pc = tmp; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* Do not specify what the fp should be when we stop + since on some machines the prologue + is where the new fp value is established. */ + step_resume_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); + if (breakpoints_inserted) + insert_breakpoints (); + + /* Restart without fiddling with the step ranges or + other state. */ + goto keep_going; + } + } + + if (sal.line == 0) + { + /* We have no line number information. That means to stop + stepping (does this always happen right after one instruction, + when we do "s" in a function with no line numbers, + or can this happen as a result of a return or longjmp?). */ + stop_step = 1; + break; + } + + if (stop_pc == sal.pc + && (current_line != sal.line || current_symtab != sal.symtab)) + { + /* We are at the start of a different line. So stop. Note that + we don't stop if we step into the middle of a different line. + That is said to make things like for (;;) statements work + better. */ + stop_step = 1; + break; + } + + /* We aren't done stepping. + + Optimize by setting the stepping range to the line. + (We might not be in the original line, but if we entered a + new line in mid-statement, we continue stepping. This makes + things like for(;;) statements work better.) */ + + if (stop_func_end && sal.end >= stop_func_end) + { + /* If this is the last line of the function, don't keep stepping + (it would probably step us out of the function). + This is particularly necessary for a one-line function, + in which after skipping the prologue we better stop even though + we will be in mid-line. */ + stop_step = 1; + break; + } + step_range_start = sal.pc; + step_range_end = sal.end; + goto keep_going; + + check_sigtramp2: + if (trap_expected + && IN_SIGTRAMP (stop_pc, stop_func_name) + && !IN_SIGTRAMP (prev_pc, prev_func_name)) + { + /* What has happened here is that we have just stepped the inferior + with a signal (because it is a signal which shouldn't make + us stop), thus stepping into sigtramp. + + So we need to set a step_resume_break_address breakpoint + and continue until we hit it, and then step. FIXME: This should + be more enduring than a step_resume breakpoint; we should know + that we will later need to keep going rather than re-hitting + the breakpoint here (see testsuite/gdb.t06/signals.exp where + it says "exceedingly difficult"). */ + struct symtab_and_line sr_sal; + + sr_sal.pc = prev_pc; + sr_sal.symtab = NULL; + sr_sal.line = 0; + /* We perhaps could set the frame if we kept track of what + the frame corresponding to prev_pc was. But we don't, + so don't. */ + through_sigtramp_breakpoint = + set_momentary_breakpoint (sr_sal, NULL, bp_through_sigtramp); + if (breakpoints_inserted) + insert_breakpoints (); + + remove_breakpoints_on_following_step = 1; + another_trap = 1; + } + + keep_going: + /* Come to this label when you need to resume the inferior. + It's really much cleaner to do a goto than a maze of if-else + conditions. */ + + /* Save the pc before execution, to compare with pc after stop. */ + prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */ + prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER + BREAK is defined, the + original pc would not have + been at the start of a + function. */ + prev_func_name = stop_func_name; + + if (update_step_sp) + step_sp = read_sp (); + update_step_sp = 0; + + /* If we did not do break;, it means we should keep + running the inferior and not return to debugger. */ + + if (trap_expected && stop_signal != TARGET_SIGNAL_TRAP) + { + /* We took a signal (which we are supposed to pass through to + the inferior, else we'd have done a break above) and we + haven't yet gotten our trap. Simply continue. */ + resume (CURRENTLY_STEPPING (), stop_signal); + } + else + { + /* Either the trap was not expected, but we are continuing + anyway (the user asked that this signal be passed to the + child) + -- or -- + The signal was SIGTRAP, e.g. it was our signal, but we + decided we should resume from it. + + We're going to run this baby now! + + Insert breakpoints now, unless we are trying + to one-proceed past a breakpoint. */ + /* If we've just finished a special step resume and we don't + want to hit a breakpoint, pull em out. */ + if (step_resume_breakpoint == NULL + && through_sigtramp_breakpoint == NULL + && remove_breakpoints_on_following_step) + { + remove_breakpoints_on_following_step = 0; + remove_breakpoints (); + breakpoints_inserted = 0; + } + else if (!breakpoints_inserted && + (through_sigtramp_breakpoint != NULL || !another_trap)) + { + breakpoints_failed = insert_breakpoints (); + if (breakpoints_failed) + break; + breakpoints_inserted = 1; + } + + trap_expected = another_trap; + + if (stop_signal == TARGET_SIGNAL_TRAP) + stop_signal = TARGET_SIGNAL_0; + +#ifdef SHIFT_INST_REGS + /* I'm not sure when this following segment applies. I do know, now, + that we shouldn't rewrite the regs when we were stopped by a + random signal from the inferior process. */ + /* FIXME: Shouldn't this be based on the valid bit of the SXIP? + (this is only used on the 88k). */ + + if (!bpstat_explains_signal (stop_bpstat) + && (stop_signal != TARGET_SIGNAL_CHLD) + && !stopped_by_random_signal) + SHIFT_INST_REGS(); +#endif /* SHIFT_INST_REGS */ + + resume (CURRENTLY_STEPPING (), stop_signal); + } + } + + stop_stepping: + if (target_has_execution) + { + /* Assuming the inferior still exists, set these up for next + time, just like we did above if we didn't break out of the + loop. */ + prev_pc = read_pc (); + prev_func_start = stop_func_start; + prev_func_name = stop_func_name; + } + do_cleanups (old_cleanups); +} + +/* Here to return control to GDB when the inferior stops for real. + Print appropriate messages, remove breakpoints, give terminal our modes. + + STOP_PRINT_FRAME nonzero means print the executing frame + (pc, function, args, file, line number and line text). + BREAKPOINTS_FAILED nonzero means stop was due to error + attempting to insert breakpoints. */ + +void +normal_stop () +{ + /* Make sure that the current_frame's pc is correct. This + is a correction for setting up the frame info before doing + DECR_PC_AFTER_BREAK */ + if (target_has_execution && get_current_frame()) + (get_current_frame ())->pc = read_pc (); + + if (breakpoints_failed) + { + target_terminal_ours_for_output (); + print_sys_errmsg ("ptrace", breakpoints_failed); + printf_filtered ("Stopped; cannot insert breakpoints.\n\ +The same program may be running in another process.\n"); + } + + if (target_has_execution && breakpoints_inserted) + if (remove_breakpoints ()) + { + target_terminal_ours_for_output (); + printf_filtered ("Cannot remove breakpoints because program is no longer writable.\n\ +It might be running in another process.\n\ +Further execution is probably impossible.\n"); + } + + breakpoints_inserted = 0; + + /* Delete the breakpoint we stopped at, if it wants to be deleted. + Delete any breakpoint that is to be deleted at the next stop. */ + + breakpoint_auto_delete (stop_bpstat); + + /* If an auto-display called a function and that got a signal, + delete that auto-display to avoid an infinite recursion. */ + + if (stopped_by_random_signal) + disable_current_display (); + + if (step_multi && stop_step) + goto done; + + target_terminal_ours (); + + if (stop_bpstat + && stop_bpstat->breakpoint_at + && stop_bpstat->breakpoint_at->type == bp_shlib_event) + printf_filtered ("Stopped due to shared library event\n"); + + /* Look up the hook_stop and run it if it exists. */ + + if (stop_command->hook) + { + catch_errors (hook_stop_stub, (char *)stop_command->hook, + "Error while running hook_stop:\n", RETURN_MASK_ALL); + } + + if (!target_has_stack) + goto done; + + /* Select innermost stack frame except on return from a stack dummy routine, + or if the program has exited. Print it without a level number if + we have changed functions or hit a breakpoint. Print source line + if we have one. */ + if (!stop_stack_dummy) + { + select_frame (get_current_frame (), 0); + + if (stop_print_frame) + { + int source_only; + + source_only = bpstat_print (stop_bpstat); + source_only = source_only || + ( stop_step + && step_frame_address == FRAME_FP (get_current_frame ()) + && step_start_function == find_pc_function (stop_pc)); + + print_stack_frame (selected_frame, -1, source_only? -1: 1); + + /* Display the auto-display expressions. */ + do_displays (); + } + } + + /* Save the function value return registers, if we care. + We might be about to restore their previous contents. */ + if (proceed_to_finish) + read_register_bytes (0, stop_registers, REGISTER_BYTES); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. + POP_FRAME ends with a setting of the current frame, so we + can use that next. */ + POP_FRAME; + /* Set stop_pc to what it was before we called the function. Can't rely + on restore_inferior_status because that only gets called if we don't + stop in the called function. */ + stop_pc = read_pc(); + select_frame (get_current_frame (), 0); + } + done: + annotate_stopped (); +} + +static int +hook_stop_stub (cmd) + char *cmd; +{ + execute_user_command ((struct cmd_list_element *)cmd, 0); + return (0); +} + +int signal_stop_state (signo) + int signo; +{ + return signal_stop[signo]; +} + +int signal_print_state (signo) + int signo; +{ + return signal_print[signo]; +} + +int signal_pass_state (signo) + int signo; +{ + return signal_program[signo]; +} + +static void +sig_print_header () +{ + printf_filtered ("\ +Signal Stop\tPrint\tPass to program\tDescription\n"); +} + +static void +sig_print_info (oursig) + enum target_signal oursig; +{ + char *name = target_signal_to_name (oursig); + printf_filtered ("%s", name); + printf_filtered ("%*.*s ", 13 - strlen (name), 13 - strlen (name), + " "); + printf_filtered ("%s\t", signal_stop[oursig] ? "Yes" : "No"); + printf_filtered ("%s\t", signal_print[oursig] ? "Yes" : "No"); + printf_filtered ("%s\t\t", signal_program[oursig] ? "Yes" : "No"); + printf_filtered ("%s\n", target_signal_to_string (oursig)); +} + +/* Specify how various signals in the inferior should be handled. */ + +static void +handle_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + int digits, wordlen; + int sigfirst, signum, siglast; + enum target_signal oursig; + int allsigs; + int nsigs; + unsigned char *sigs; + struct cleanup *old_chain; + + if (args == NULL) + { + error_no_arg ("signal to handle"); + } + + /* Allocate and zero an array of flags for which signals to handle. */ + + nsigs = (int)TARGET_SIGNAL_LAST; + sigs = (unsigned char *) alloca (nsigs); + memset (sigs, 0, nsigs); + + /* Break the command line up into args. */ + + argv = buildargv (args); + if (argv == NULL) + { + nomem (0); + } + old_chain = make_cleanup (freeargv, (char *) argv); + + /* Walk through the args, looking for signal oursigs, signal names, and + actions. Signal numbers and signal names may be interspersed with + actions, with the actions being performed for all signals cumulatively + specified. Signal ranges can be specified as -. */ + + while (*argv != NULL) + { + wordlen = strlen (*argv); + for (digits = 0; isdigit ((*argv)[digits]); digits++) {;} + allsigs = 0; + sigfirst = siglast = -1; + + if (wordlen >= 1 && !strncmp (*argv, "all", wordlen)) + { + /* Apply action to all signals except those used by the + debugger. Silently skip those. */ + allsigs = 1; + sigfirst = 0; + siglast = nsigs - 1; + } + else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_stop); + SET_SIGS (nsigs, sigs, signal_print); + } + else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_print); + } + else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_stop); + } + else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen)) + { + SET_SIGS (nsigs, sigs, signal_program); + } + else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_print); + UNSET_SIGS (nsigs, sigs, signal_stop); + } + else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen)) + { + UNSET_SIGS (nsigs, sigs, signal_program); + } + else if (digits > 0) + { + /* It is numeric. The numeric signal refers to our own internal + signal numbering from target.h, not to host/target signal number. + This is a feature; users really should be using symbolic names + anyway, and the common ones like SIGHUP, SIGINT, SIGALRM, etc. + will work right anyway. */ + + sigfirst = siglast = (int) target_signal_from_command (atoi (*argv)); + if ((*argv)[digits] == '-') + { + siglast = + (int) target_signal_from_command (atoi ((*argv) + digits + 1)); + } + if (sigfirst > siglast) + { + /* Bet he didn't figure we'd think of this case... */ + signum = sigfirst; + sigfirst = siglast; + siglast = signum; + } + } + else + { + oursig = target_signal_from_name (*argv); + if (oursig != TARGET_SIGNAL_UNKNOWN) + { + sigfirst = siglast = (int)oursig; + } + else + { + /* Not a number and not a recognized flag word => complain. */ + error ("Unrecognized or ambiguous flag word: \"%s\".", *argv); + } + } + + /* If any signal numbers or symbol names were found, set flags for + which signals to apply actions to. */ + + for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++) + { + switch ((enum target_signal)signum) + { + case TARGET_SIGNAL_TRAP: + case TARGET_SIGNAL_INT: + if (!allsigs && !sigs[signum]) + { + if (query ("%s is used by the debugger.\n\ +Are you sure you want to change it? ", + target_signal_to_name + ((enum target_signal)signum))) + { + sigs[signum] = 1; + } + else + { + printf_unfiltered ("Not confirmed, unchanged.\n"); + gdb_flush (gdb_stdout); + } + } + break; + case TARGET_SIGNAL_0: + case TARGET_SIGNAL_DEFAULT: + case TARGET_SIGNAL_UNKNOWN: + /* Make sure that "all" doesn't print these. */ + break; + default: + sigs[signum] = 1; + break; + } + } + + argv++; + } + + target_notice_signals(inferior_pid); + + if (from_tty) + { + /* Show the results. */ + sig_print_header (); + for (signum = 0; signum < nsigs; signum++) + { + if (sigs[signum]) + { + sig_print_info (signum); + } + } + } + + do_cleanups (old_chain); +} + +/* Print current contents of the tables set by the handle command. + It is possible we should just be printing signals actually used + by the current target (but for things to work right when switching + targets, all signals should be in the signal tables). */ + +static void +signals_info (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + enum target_signal oursig; + sig_print_header (); + + if (signum_exp) + { + /* First see if this is a symbol name. */ + oursig = target_signal_from_name (signum_exp); + if (oursig == TARGET_SIGNAL_UNKNOWN) + { + /* No, try numeric. */ + oursig = + target_signal_from_command (parse_and_eval_address (signum_exp)); + } + sig_print_info (oursig); + return; + } + + printf_filtered ("\n"); + /* These ugly casts brought to you by the native VAX compiler. */ + for (oursig = TARGET_SIGNAL_FIRST; + (int)oursig < (int)TARGET_SIGNAL_LAST; + oursig = (enum target_signal)((int)oursig + 1)) + { + QUIT; + + if (oursig != TARGET_SIGNAL_UNKNOWN + && oursig != TARGET_SIGNAL_DEFAULT + && oursig != TARGET_SIGNAL_0) + sig_print_info (oursig); + } + + printf_filtered ("\nUse the \"handle\" command to change these tables.\n"); +} + +/* Save all of the information associated with the inferior<==>gdb + connection. INF_STATUS is a pointer to a "struct inferior_status" + (defined in inferior.h). */ + +void +save_inferior_status (inf_status, restore_stack_info) + struct inferior_status *inf_status; + int restore_stack_info; +{ + inf_status->stop_signal = stop_signal; + inf_status->stop_pc = stop_pc; + inf_status->stop_step = stop_step; + inf_status->stop_stack_dummy = stop_stack_dummy; + inf_status->stopped_by_random_signal = stopped_by_random_signal; + inf_status->trap_expected = trap_expected; + inf_status->step_range_start = step_range_start; + inf_status->step_range_end = step_range_end; + inf_status->step_frame_address = step_frame_address; + inf_status->step_over_calls = step_over_calls; + inf_status->stop_after_trap = stop_after_trap; + inf_status->stop_soon_quietly = stop_soon_quietly; + /* Save original bpstat chain here; replace it with copy of chain. + If caller's caller is walking the chain, they'll be happier if we + hand them back the original chain when restore_i_s is called. */ + inf_status->stop_bpstat = stop_bpstat; + stop_bpstat = bpstat_copy (stop_bpstat); + inf_status->breakpoint_proceeded = breakpoint_proceeded; + inf_status->restore_stack_info = restore_stack_info; + inf_status->proceed_to_finish = proceed_to_finish; + + memcpy (inf_status->stop_registers, stop_registers, REGISTER_BYTES); + + read_register_bytes (0, inf_status->registers, REGISTER_BYTES); + + record_selected_frame (&(inf_status->selected_frame_address), + &(inf_status->selected_level)); + return; +} + +struct restore_selected_frame_args { + CORE_ADDR frame_address; + int level; +}; + +static int restore_selected_frame PARAMS ((char *)); + +/* Restore the selected frame. args is really a struct + restore_selected_frame_args * (declared as char * for catch_errors) + telling us what frame to restore. Returns 1 for success, or 0 for + failure. An error message will have been printed on error. */ + +static int +restore_selected_frame (args) + char *args; +{ + struct restore_selected_frame_args *fr = + (struct restore_selected_frame_args *) args; + struct frame_info *frame; + int level = fr->level; + + frame = find_relative_frame (get_current_frame (), &level); + + /* If inf_status->selected_frame_address is NULL, there was no + previously selected frame. */ + if (frame == NULL || + FRAME_FP (frame) != fr->frame_address || + level != 0) + { + warning ("Unable to restore previously selected frame.\n"); + return 0; + } + select_frame (frame, fr->level); + return(1); +} + +void +restore_inferior_status (inf_status) + struct inferior_status *inf_status; +{ + stop_signal = inf_status->stop_signal; + stop_pc = inf_status->stop_pc; + stop_step = inf_status->stop_step; + stop_stack_dummy = inf_status->stop_stack_dummy; + stopped_by_random_signal = inf_status->stopped_by_random_signal; + trap_expected = inf_status->trap_expected; + step_range_start = inf_status->step_range_start; + step_range_end = inf_status->step_range_end; + step_frame_address = inf_status->step_frame_address; + step_over_calls = inf_status->step_over_calls; + stop_after_trap = inf_status->stop_after_trap; + stop_soon_quietly = inf_status->stop_soon_quietly; + bpstat_clear (&stop_bpstat); + stop_bpstat = inf_status->stop_bpstat; + breakpoint_proceeded = inf_status->breakpoint_proceeded; + proceed_to_finish = inf_status->proceed_to_finish; + + memcpy (stop_registers, inf_status->stop_registers, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (target_has_execution) + write_register_bytes (0, inf_status->registers, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + + /* FIXME: If we are being called after stopping in a function which + is called from gdb, we should not be trying to restore the + selected frame; it just prints a spurious error message (The + message is useful, however, in detecting bugs in gdb (like if gdb + clobbers the stack)). In fact, should we be restoring the + inferior status at all in that case? . */ + + if (target_has_stack && inf_status->restore_stack_info) + { + struct restore_selected_frame_args fr; + fr.level = inf_status->selected_level; + fr.frame_address = inf_status->selected_frame_address; + /* The point of catch_errors is that if the stack is clobbered, + walking the stack might encounter a garbage pointer and error() + trying to dereference it. */ + if (catch_errors (restore_selected_frame, &fr, + "Unable to restore previously selected frame:\n", + RETURN_MASK_ERROR) == 0) + /* Error in restoring the selected frame. Select the innermost + frame. */ + select_frame (get_current_frame (), 0); + } +} + + +void +_initialize_infrun () +{ + register int i; + register int numsigs; + + add_info ("signals", signals_info, + "What debugger does when program gets various signals.\n\ +Specify a signal as argument to print info on that signal only."); + add_info_alias ("handle", "signals", 0); + + add_com ("handle", class_run, handle_command, + concat ("Specify how to handle a signal.\n\ +Args are signals and actions to apply to those signals.\n\ +Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\ +from 1-15 are allowed for compatibility with old versions of GDB.\n\ +Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\ +The special arg \"all\" is recognized to mean all signals except those\n\ +used by the debugger, typically SIGTRAP and SIGINT.\n", +"Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\ +\"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\ +Stop means reenter debugger if this signal happens (implies print).\n\ +Print means print a message if this signal happens.\n\ +Pass means let program see this signal; otherwise program doesn't know.\n\ +Ignore is a synonym for nopass and noignore is a synonym for pass.\n\ +Pass and Stop may be combined.", NULL)); + + stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command, + "There is no `stop' command, but you can set a hook on `stop'.\n\ +This allows you to set a list of commands to be run each time execution\n\ +of the program stops.", &cmdlist); + + numsigs = (int)TARGET_SIGNAL_LAST; + signal_stop = (unsigned char *) + xmalloc (sizeof (signal_stop[0]) * numsigs); + signal_print = (unsigned char *) + xmalloc (sizeof (signal_print[0]) * numsigs); + signal_program = (unsigned char *) + xmalloc (sizeof (signal_program[0]) * numsigs); + for (i = 0; i < numsigs; i++) + { + signal_stop[i] = 1; + signal_print[i] = 1; + signal_program[i] = 1; + } + + /* Signals caused by debugger's own actions + should not be given to the program afterwards. */ + signal_program[TARGET_SIGNAL_TRAP] = 0; + signal_program[TARGET_SIGNAL_INT] = 0; + + /* Signals that are not errors should not normally enter the debugger. */ + signal_stop[TARGET_SIGNAL_ALRM] = 0; + signal_print[TARGET_SIGNAL_ALRM] = 0; + signal_stop[TARGET_SIGNAL_VTALRM] = 0; + signal_print[TARGET_SIGNAL_VTALRM] = 0; + signal_stop[TARGET_SIGNAL_PROF] = 0; + signal_print[TARGET_SIGNAL_PROF] = 0; + signal_stop[TARGET_SIGNAL_CHLD] = 0; + signal_print[TARGET_SIGNAL_CHLD] = 0; + signal_stop[TARGET_SIGNAL_IO] = 0; + signal_print[TARGET_SIGNAL_IO] = 0; + signal_stop[TARGET_SIGNAL_POLL] = 0; + signal_print[TARGET_SIGNAL_POLL] = 0; + signal_stop[TARGET_SIGNAL_URG] = 0; + signal_print[TARGET_SIGNAL_URG] = 0; + +#ifdef SOLIB_ADD + add_show_from_set + (add_set_cmd ("stop-on-solib-events", class_support, var_zinteger, + (char *) &stop_on_solib_events, + "Set stopping for shared library events.\n\ +If nonzero, gdb will give control to the user when the dynamic linker\n\ +notifies gdb of shared library events. The most common event of interest\n\ +to the user would be loading/unloading of a new library.\n", + &setlist), + &showlist); +#endif +} diff --git a/contrib/gdb/gdb/inftarg.c b/contrib/gdb/gdb/inftarg.c new file mode 100644 index 000000000000..6e0e50a45beb --- /dev/null +++ b/contrib/gdb/gdb/inftarg.c @@ -0,0 +1,390 @@ +/* Target-vector operations for controlling Unix child processes, for GDB. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + Contributed by 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "gdbcore.h" +#include "command.h" +#include +#include +#include + +static void +child_prepare_to_store PARAMS ((void)); + +#ifndef CHILD_WAIT +static int child_wait PARAMS ((int, struct target_waitstatus *)); +#endif /* CHILD_WAIT */ + +static void child_open PARAMS ((char *, int)); + +static void +child_files_info PARAMS ((struct target_ops *)); + +static void +child_detach PARAMS ((char *, int)); + +static void +child_attach PARAMS ((char *, int)); + +static void +ptrace_me PARAMS ((void)); + +static void +ptrace_him PARAMS ((int)); + +static void child_create_inferior PARAMS ((char *, char *, char **)); + +static void +child_mourn_inferior PARAMS ((void)); + +static int +child_can_run PARAMS ((void)); + +static int child_thread_alive PARAMS ((int)); + +extern char **environ; + +/* Forward declaration */ +extern struct target_ops child_ops; + +static int +proc_wait (pid, status) + int pid; + int *status; +{ +#ifndef __GO32__ + return wait (status); +#endif +} + +#ifndef CHILD_WAIT + +/* Wait for child to do something. Return pid of child, or -1 in case + of error; store status through argument pointer OURSTATUS. */ + +static int +child_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + int save_errno; + int status; + + do { + set_sigint_trap(); /* Causes SIGINT to be passed on to the + attached process. */ + set_sigio_trap (); + + pid = proc_wait (inferior_pid, &status); + save_errno = errno; + + clear_sigio_trap (); + + clear_sigint_trap(); + + if (pid == -1) + { + if (save_errno == EINTR) + continue; + fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n", + safe_strerror (save_errno)); + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return -1; + } + } while (pid != inferior_pid); /* Some other child died or stopped */ + store_waitstatus (ourstatus, status); + return pid; +} +#endif /* CHILD_WAIT */ + +#ifndef CHILD_THREAD_ALIVE + +/* Check to see if the given thread is alive. + + FIXME: Is kill() ever the right way to do this? I doubt it, but + for now we're going to try and be compatable with the old thread + code. */ +static int +child_thread_alive (pid) + int pid; +{ + return (kill (pid, 0) != -1); +} + +#endif + +/* Attach to process PID, then initialize for debugging it. */ + +static void +child_attach (args, from_tty) + char *args; + int from_tty; +{ + if (!args) + error_no_arg ("process-id to attach"); + +#ifndef ATTACH_DETACH + error ("Can't attach to a process on this machine."); +#else + { + char *exec_file; + int pid; + + pid = atoi (args); + + if (pid == getpid()) /* Trying to masturbate? */ + error ("I refuse to debug myself!"); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, + target_pid_to_str (pid)); + else + printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid)); + + gdb_flush (gdb_stdout); + } + + attach (pid); + inferior_pid = pid; + push_target (&child_ops); + } +#endif /* ATTACH_DETACH */ +} + + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +child_detach (args, from_tty) + char *args; + int from_tty; +{ +#ifdef ATTACH_DETACH + { + int siggnal = 0; + + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf_unfiltered ("Detaching from program: %s %s\n", exec_file, + target_pid_to_str (inferior_pid)); + gdb_flush (gdb_stdout); + } + if (args) + siggnal = atoi (args); + + detach (siggnal); + inferior_pid = 0; + unpush_target (&child_ops); + } +#else + error ("This version of Unix does not support detaching a process."); +#endif +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +child_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +/* Print status information about what we're accessing. */ + +static void +child_files_info (ignore) + struct target_ops *ignore; +{ + printf_unfiltered ("\tUsing the running image of %s %s.\n", + attach_flag? "attached": "child", target_pid_to_str (inferior_pid)); +} + +/* ARGSUSED */ +static void +child_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a Unix child process."); +} + +/* Stub function which causes the inferior that runs it, to be ptrace-able + by its parent process. */ + +static void +ptrace_me () +{ + /* "Trace me, Dr. Memory!" */ + call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0); +} + +/* Stub function which causes the GDB that runs it, to start ptrace-ing + the child process. */ + +static void +ptrace_him (pid) + int pid; +{ + push_target (&child_ops); + +#ifdef START_INFERIOR_TRAPS_EXPECTED + startup_inferior (START_INFERIOR_TRAPS_EXPECTED); +#else + /* One trap to exec the shell, one to exec the program being debugged. */ + startup_inferior (2); +#endif +} + +/* Start an inferior Unix child process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). */ + +static void +child_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, NULL); + /* We are at the first instruction we care about. */ + /* Pedal to the metal... */ + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); +} + +static void +child_mourn_inferior () +{ + unpush_target (&child_ops); + proc_remove_foreign (inferior_pid); + generic_mourn_inferior (); +} + +static int +child_can_run () +{ + return(1); +} + +/* Send a SIGINT to the process group. This acts just like the user typed a + ^C on the controlling terminal. + + XXX - This may not be correct for all systems. Some may want to use + killpg() instead of kill (-pgrp). */ + +void +child_stop () +{ + extern pid_t inferior_process_group; + + kill (-inferior_process_group, SIGINT); +} + +struct target_ops child_ops = { + "child", /* to_shortname */ + "Unix child process", /* to_longname */ + "Unix child process (started by the \"run\" command).", /* to_doc */ + child_open, /* to_open */ + 0, /* to_close */ + child_attach, /* to_attach */ + child_detach, /* to_detach */ + child_resume, /* to_resume */ + child_wait, /* to_wait */ + fetch_inferior_registers, /* to_fetch_registers */ + store_inferior_registers, /* to_store_registers */ + child_prepare_to_store, /* to_prepare_to_store */ + child_xfer_memory, /* to_xfer_memory */ + child_files_info, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + terminal_init_inferior, /* to_terminal_init */ + terminal_inferior, /* to_terminal_inferior */ + terminal_ours_for_output, /* to_terminal_ours_for_output */ + terminal_ours, /* to_terminal_ours */ + child_terminal_info, /* to_terminal_info */ + kill_inferior, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + child_create_inferior, /* to_create_inferior */ + child_mourn_inferior, /* to_mourn_inferior */ + child_can_run, /* to_can_run */ + 0, /* to_notice_signals */ + child_thread_alive, /* to_thread_alive */ + child_stop, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* to_sections */ + 0, /* to_sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_inftarg () +{ +#ifdef HAVE_OPTIONAL_PROC_FS + char procname[32]; + int fd; + + /* If we have an optional /proc filesystem (e.g. under OSF/1), + don't add ptrace support if we can access the running GDB via /proc. */ +#ifndef PROC_NAME_FMT +#define PROC_NAME_FMT "/proc/%05d" +#endif + sprintf (procname, PROC_NAME_FMT, getpid ()); + if ((fd = open (procname, O_RDONLY)) >= 0) + { + close (fd); + return; + } +#endif + + add_target (&child_ops); +} diff --git a/contrib/gdb/gdb/irix4-nat.c b/contrib/gdb/gdb/irix4-nat.c new file mode 100644 index 000000000000..8cd9b4c998db --- /dev/null +++ b/contrib/gdb/gdb/irix4-nat.c @@ -0,0 +1,192 @@ +/* Native support for the SGI Iris running IRIX version 4, for GDB. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1995 + Free Software Foundation, Inc. + Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU + and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. + Implemented for Irix 4.x by Garrett A. Wollman. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" + +#include +#include +#include /* For JB_XXX. */ + +/* Size of elements in jmpbuf */ + +#define JB_ELEMENT_SIZE 4 + +typedef unsigned int greg_t; /* why isn't this defined? */ + +/* + * See the comment in m68k-tdep.c regarding the utility of these functions. + */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *)(gregsetp->gp_regs); + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + /* FIXME: somewhere, there should be a #define for the meaning + of this magic number 32; we should use that. */ + for(regi = 0; regi < 32; regi++) + supply_register (regi, (char *)(regp + regi)); + + supply_register (PC_REGNUM, (char *)&(gregsetp->gp_pc)); + supply_register (HI_REGNUM, (char *)&(gregsetp->gp_mdhi)); + supply_register (LO_REGNUM, (char *)&(gregsetp->gp_mdlo)); + supply_register (CAUSE_REGNUM, (char *)&(gregsetp->gp_cause)); + + /* Fill inaccessible registers with zero. */ + supply_register (BADVADDR_REGNUM, zerobuf); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register greg_t *regp = (greg_t *)(gregsetp->gp_regs); + + /* same FIXME as above wrt 32*/ + for (regi = 0; regi < 32; regi++) + if ((regno == -1) || (regno == regi)) + *(regp + regi) = *(greg_t *) ®isters[REGISTER_BYTE (regi)]; + + if ((regno == -1) || (regno == PC_REGNUM)) + gregsetp->gp_pc = *(greg_t *) ®isters[REGISTER_BYTE (PC_REGNUM)]; + + if ((regno == -1) || (regno == CAUSE_REGNUM)) + gregsetp->gp_cause = *(greg_t *) ®isters[REGISTER_BYTE (CAUSE_REGNUM)]; + + if ((regno == -1) || (regno == HI_REGNUM)) + gregsetp->gp_mdhi = *(greg_t *) ®isters[REGISTER_BYTE (HI_REGNUM)]; + + if ((regno == -1) || (regno == LO_REGNUM)) + gregsetp->gp_mdlo = *(greg_t *) ®isters[REGISTER_BYTE (LO_REGNUM)]; +} + +/* + * Now we do the same thing for floating-point registers. + * We don't bother to condition on FP0_REGNUM since any + * reasonable MIPS configuration has an R3010 in it. + * + * Again, see the comments in m68k-tdep.c. + */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + register int regi; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for (regi = 0; regi < 32; regi++) + supply_register (FP0_REGNUM + regi, + (char *)&fpregsetp->fp_r.fp_regs[regi]); + + supply_register (FCRCS_REGNUM, (char *)&fpregsetp->fp_csr); + + /* FIXME: how can we supply FCRIR_REGNUM? SGI doesn't tell us. */ + supply_register (FCRIR_REGNUM, zerobuf); +} + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + int regi; + char *from, *to; + + for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++) + { + if ((regno == -1) || (regno == regi)) + { + from = (char *) ®isters[REGISTER_BYTE (regi)]; + to = (char *) &(fpregsetp->fp_r.fp_regs[regi - FP0_REGNUM]); + memcpy(to, from, REGISTER_RAW_SIZE (regi)); + } + } + + if ((regno == -1) || (regno == FCRCS_REGNUM)) + fpregsetp->fp_csr = *(unsigned *) ®isters[REGISTER_BYTE(FCRCS_REGNUM)]; +} + + +/* Figure out where the longjmp will land. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target (pc) + CORE_ADDR *pc; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + CORE_ADDR jb_addr; + + jb_addr = read_register (A0_REGNUM); + + if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + return 1; +} + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; /* Unused */ + unsigned int reg_addr; /* Unused */ +{ + if (core_reg_size != REGISTER_BYTES) + { + warning ("wrong size gregset struct in core file"); + return; + } + + memcpy ((char *)registers, core_reg_sect, core_reg_size); +} + + +/* Register that we are able to handle irix4 core file formats. + FIXME: is this really bfd_target_unknown_flavour? */ + +static struct core_fns irix4_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_irix4 () +{ + add_core_fns (&irix4_core_fns); +} diff --git a/contrib/gdb/gdb/irix5-nat.c b/contrib/gdb/gdb/irix5-nat.c new file mode 100644 index 000000000000..fc4c8cb10425 --- /dev/null +++ b/contrib/gdb/gdb/irix5-nat.c @@ -0,0 +1,1067 @@ +/* Native support for the SGI Iris running IRIX version 5, for GDB. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU + and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. + Implemented for Irix 4.x by Garrett A. Wollman. + Modified for Irix 5.x by Ian Lance Taylor. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" + +#include "gdb_string.h" +#include +#include +#include /* For JB_XXX. */ + +/* Size of elements in jmpbuf */ + +#define JB_ELEMENT_SIZE 4 + +/* + * See the comment in m68k-tdep.c regarding the utility of these functions. + * + * These definitions are from the MIPS SVR4 ABI, so they may work for + * any MIPS SVR4 target. + */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = &(*gregsetp)[0]; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for(regi = 0; regi <= CTX_RA; regi++) + supply_register (regi, (char *)(regp + regi)); + + supply_register (PC_REGNUM, (char *)(regp + CTX_EPC)); + supply_register (HI_REGNUM, (char *)(regp + CTX_MDHI)); + supply_register (LO_REGNUM, (char *)(regp + CTX_MDLO)); + supply_register (CAUSE_REGNUM, (char *)(regp + CTX_CAUSE)); + + /* Fill inaccessible registers with zero. */ + supply_register (BADVADDR_REGNUM, zerobuf); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register greg_t *regp = &(*gregsetp)[0]; + + for (regi = 0; regi <= CTX_RA; regi++) + if ((regno == -1) || (regno == regi)) + *(regp + regi) = *(greg_t *) ®isters[REGISTER_BYTE (regi)]; + + if ((regno == -1) || (regno == PC_REGNUM)) + *(regp + CTX_EPC) = *(greg_t *) ®isters[REGISTER_BYTE (PC_REGNUM)]; + + if ((regno == -1) || (regno == CAUSE_REGNUM)) + *(regp + CTX_CAUSE) = *(greg_t *) ®isters[REGISTER_BYTE (CAUSE_REGNUM)]; + + if ((regno == -1) || (regno == HI_REGNUM)) + *(regp + CTX_MDHI) = *(greg_t *) ®isters[REGISTER_BYTE (HI_REGNUM)]; + + if ((regno == -1) || (regno == LO_REGNUM)) + *(regp + CTX_MDLO) = *(greg_t *) ®isters[REGISTER_BYTE (LO_REGNUM)]; +} + +/* + * Now we do the same thing for floating-point registers. + * We don't bother to condition on FP0_REGNUM since any + * reasonable MIPS configuration has an R3010 in it. + * + * Again, see the comments in m68k-tdep.c. + */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + register int regi; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + + for (regi = 0; regi < 32; regi++) + supply_register (FP0_REGNUM + regi, + (char *)&fpregsetp->fp_r.fp_regs[regi]); + + supply_register (FCRCS_REGNUM, (char *)&fpregsetp->fp_csr); + + /* FIXME: how can we supply FCRIR_REGNUM? SGI doesn't tell us. */ + supply_register (FCRIR_REGNUM, zerobuf); +} + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + int regi; + char *from, *to; + + for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++) + { + if ((regno == -1) || (regno == regi)) + { + from = (char *) ®isters[REGISTER_BYTE (regi)]; + to = (char *) &(fpregsetp->fp_r.fp_regs[regi - FP0_REGNUM]); + memcpy(to, from, REGISTER_RAW_SIZE (regi)); + } + } + + if ((regno == -1) || (regno == FCRCS_REGNUM)) + fpregsetp->fp_csr = *(unsigned *) ®isters[REGISTER_BYTE(FCRCS_REGNUM)]; +} + + +/* Figure out where the longjmp will land. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target (pc) + CORE_ADDR *pc; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + CORE_ADDR jb_addr; + + jb_addr = read_register (A0_REGNUM); + + if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + return 1; +} + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; /* Unused */ + unsigned int reg_addr; /* Unused */ +{ + if (core_reg_size != REGISTER_BYTES) + { + warning ("wrong size gregset struct in core file"); + return; + } + + memcpy ((char *)registers, core_reg_sect, core_reg_size); +} + +/* Irix 5 uses what appears to be a unique form of shared library + support. This is a copy of solib.c modified for Irix 5. */ + +#include +#include +#include +#include + +/* includes and , which causes conflicts + with our versions of those files included by tm-mips.h. Prevent + from including them with some appropriate defines. */ +#define __SYM_H__ +#define __SYMCONST_H__ +#include + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "command.h" +#include "frame.h" +#include "gnu-regex.h" +#include "inferior.h" +#include "language.h" +#include "gdbcmd.h" + +/* The symbol which starts off the list of shared libraries. */ +#define DEBUG_BASE "__rld_obj_head" + +/* How to get the loaded address of a shared library. */ +#define LM_ADDR(so) ((so)->lm.o_praw) + +char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ + +struct so_list { + struct so_list *next; /* next structure in linked list */ + struct obj_list ll; + struct obj lm; /* copy of link map from inferior */ + struct obj_list *lladdr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *abfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ +static CORE_ADDR debug_base; /* Base of dynamic linker structures */ +static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ + +/* Local function prototypes */ + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static int +enable_break PARAMS ((void)); + +static int +disable_break PARAMS ((void)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +static struct obj_list * +first_link_map_member PARAMS ((void)); + +static CORE_ADDR +locate_base PARAMS ((void)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + CORE_ADDR offset; + + filename = tilde_expand (so -> lm.o_path); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. abfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> abfd = abfd; + abfd -> cacheable = true; + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (exec_bfd), bfd_errmsg (bfd_get_error ())); + } + + /* Irix 5 shared objects are pre-linked to particular addresses + although the dynamic linker may have to relocate them if the + address ranges of the libraries used by the main program clash. + The offset is the difference between the address where the object + is mapped and the binding address of the shared library. */ + offset = (CORE_ADDR) LM_ADDR (so) - so -> lm.o_base_address; + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the offset to get the address to which the + object was actually mapped. */ + p -> addr += offset; + p -> endaddr += offset; + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> the_bfd_section -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +/* + +LOCAL FUNCTION + + locate_base -- locate the base address of dynamic linker structs + +SYNOPSIS + + CORE_ADDR locate_base (void) + +DESCRIPTION + + For both the SunOS and SVR4 shared library implementations, if the + inferior executable has been linked dynamically, there is a single + address somewhere in the inferior's data space which is the key to + locating all of the dynamic linker's runtime structures. This + address is the value of the symbol defined by the macro DEBUG_BASE. + The job of this function is to find and return that address, or to + return 0 if there is no such address (the executable is statically + linked for example). + + For SunOS, the job is almost trivial, since the dynamic linker and + all of it's structures are statically linked to the executable at + link time. Thus the symbol for the address we are looking for has + already been added to the minimal symbol table for the executable's + objfile at the time the symbol file's symbols were read, and all we + have to do is look it up there. Note that we explicitly do NOT want + to find the copies in the shared library. + + The SVR4 version is much more complicated because the dynamic linker + and it's structures are located in the shared C library, which gets + run as the executable's "interpreter" by the kernel. We have to go + to a lot more work to discover the address of DEBUG_BASE. Because + of this complexity, we cache the value we find and return that value + on subsequent invocations. Note there is no copy in the executable + symbol tables. + + Irix 5 is basically like SunOS. + + Note that we can assume nothing about the process state at the time + we need to find this address. We may be stopped on the first instruc- + tion of the interpreter (C shared library), the first instruction of + the executable itself, or somewhere else entirely (if we attached + to the process for example). + + */ + +static CORE_ADDR +locate_base () +{ + struct minimal_symbol *msymbol; + CORE_ADDR address = 0; + + msymbol = lookup_minimal_symbol (DEBUG_BASE, NULL, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + address = SYMBOL_VALUE_ADDRESS (msymbol); + } + return (address); +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +static struct obj_list * +first_link_map_member () +{ + struct obj_list *lm; + struct obj_list s; + + read_memory (debug_base, (char *) &lm, sizeof (struct obj_list *)); + + if (lm == NULL) + return NULL; + + /* The first entry in the list is the object file we are debugging, + so skip it. */ + read_memory ((CORE_ADDR) lm, (char *) &s, sizeof (struct obj_list)); + + return s.next; +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct obj_list *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* We have not already read in the dynamic linking structures + from the inferior, lookup the address of the base structure. */ + debug_base = locate_base (); + if (debug_base != 0) + { + /* Read the base structure in and find the address of the first + link map list member. */ + lm = first_link_map_member (); + } + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + if ((lm = so_list_ptr->ll.next) == NULL) + { + /* We have hit the end of the list, so check to see if any were + added, but be quiet if we can't read from the target any more. */ + int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lladdr, + (char *) &(so_list_ptr -> ll), + sizeof (struct obj_list)); + if (status == 0) + { + lm = so_list_ptr->ll.next; + } + else + { + lm = NULL; + } + } + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + int errcode; + char *buffer; + + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lladdr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + read_memory ((CORE_ADDR) lm, (char *) &(new -> ll), + sizeof (struct obj_list)); + read_memory ((CORE_ADDR) new->ll.data, (char *) &(new -> lm), + sizeof (struct obj)); + target_read_string ((CORE_ADDR)new->lm.o_path, &buffer, + INT_MAX, &errcode); + if (errcode != 0) + memory_error (errcode, (CORE_ADDR)new->lm.o_path); + new->lm.o_path = buffer; + solib_map_sections (new); + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = symbol_file_add (so -> lm.o_path, so -> from_tty, + (unsigned int) so -> textsection -> addr, + 0, 0, 0); + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + /* Add the shared library sections to the section table of the + specified target, if any. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> lm.o_path[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + int update_coreops; + + /* We must update the to_sections field in the core_ops structure + here, otherwise we dereference a potential dangling pointer + for each call to target_read/write_memory within this routine. */ + update_coreops = core_ops.to_sections == target->to_sections; + + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Update the to_sections field in the core_ops structure + if needed. */ + if (update_coreops) + { + core_ops.to_sections = target->to_sections; + core_ops.to_sections_end = target->to_sections_end; + } + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> lm.o_path[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Now add the symbol files. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> lm.o_path[0] && re_exec (so -> lm.o_path)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf_unfiltered ("Symbols already loaded for %s\n", so -> lm.o_path); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + if (so_last) + reinit_frame_cache (); +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf_unfiltered ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> lm.o_path[0]) + { + if (!header_done) + { + printf_unfiltered("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) LM_ADDR (so), + "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) so -> lmend, + "08l")); + printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf_unfiltered ("%s\n", so -> lm.o_path); + } + } + if (so_list_head == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + char *solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +char * +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> lm.o_path[0]) + { + if ((address >= (CORE_ADDR) LM_ADDR (so)) && + (address < (CORE_ADDR) so -> lmend)) + return (so->lm.o_path); + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> abfd) + { + bfd_filename = bfd_get_filename (so_list_head -> abfd); + if (!bfd_close (so_list_head -> abfd)) + warning ("cannot close \"%s\": %s", + bfd_filename, bfd_errmsg (bfd_get_error ())); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free (so_list_head->lm.o_path); + free ((PTR)so_list_head); + so_list_head = next; + } + debug_base = 0; +} + +/* + +LOCAL FUNCTION + + disable_break -- remove the "mapping changed" breakpoint + +SYNOPSIS + + static int disable_break () + +DESCRIPTION + + Removes the breakpoint that gets hit when the dynamic linker + completes a mapping change. + +*/ + +static int +disable_break () +{ + int status = 1; + + + /* Note that breakpoint address and original contents are in our address + space, so we just need to write the original contents back. */ + + if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + status = 0; + } + + /* For the SVR4 version, we always know the breakpoint address. For the + SunOS version we don't know it until the above code is executed. + Grumble if we are stopped anywhere besides the breakpoint address. */ + + if (stop_pc != breakpoint_addr) + { + warning ("stopped at unknown breakpoint while handling shared libraries"); + } + + return (status); +} + +/* + +LOCAL FUNCTION + + enable_break -- arrange for dynamic linker to hit breakpoint + +SYNOPSIS + + int enable_break (void) + +DESCRIPTION + + This functions inserts a breakpoint at the entry point of the + main executable, where all shared libraries are mapped in. +*/ + +static int +enable_break () +{ + if (symfile_objfile != NULL + && target_insert_breakpoint (symfile_objfile->ei.entry_point, + shadow_contents) == 0) + { + breakpoint_addr = symfile_objfile->ei.entry_point; + return 1; + } + + return 0; +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + + For SunOS executables, this first instruction is typically the + one at "_start", or a similar text label, regardless of whether + the executable is statically or dynamically linked. The runtime + startup code takes care of dynamically linking in any shared + libraries, once gdb allows the inferior to continue. + + For SVR4 executables, this first instruction is either the first + instruction in the dynamic linker (for dynamically linked + executables) or the instruction at "start" for statically linked + executables. For dynamically linked executables, the system + first exec's /lib/libc.so.N, which contains the dynamic linker, + and starts it running. The dynamic linker maps in any needed + shared libraries, maps in the actual user executable, and then + jumps to "start" in the user executable. + + For both SunOS shared libraries, and SVR4 shared libraries, we + can arrange to cooperate with the dynamic linker to discover the + names of shared libraries that are dynamically linked, and the + base addresses to which they are linked. + + 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. + */ + +void +solib_create_inferior_hook() +{ + if (!enable_break ()) + { + warning ("shared library handler failed to enable breakpoint"); + return; + } + + /* 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. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = 0; + do + { + target_resume (-1, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != SIGTRAP); + + /* We are now either at the "mapping complete" breakpoint (or somewhere + else, a condition we aren't prepared to deal with anyway), so adjust + the PC as necessary after a breakpoint, disable the breakpoint, and + add any shared libraries that were mapped in. */ + + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + } + + if (!disable_break ()) + { + warning ("shared library handler failed to disable breakpoint"); + } + + /* solib_add will call reinit_frame_cache. + But we are stopped in the startup code and we might not have symbols + for the startup code, so heuristic_proc_start could be called + and will put out an annoying warning. + Delaying the resetting of stop_soon_quietly until after symbol loading + suppresses the warning. */ + if (auto_solib_add) + solib_add ((char *) 0, 0, (struct target_ops *) 0); + stop_soon_quietly = 0; +} + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_solib() +{ + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); + + add_show_from_set + (add_set_cmd ("auto-solib-add", class_support, var_zinteger, + (char *) &auto_solib_add, + "Set autoloading of shared library symbols.\n\ +If nonzero, symbols from all shared object libraries will be loaded\n\ +automatically when the inferior begins execution or when the dynamic linker\n\ +informs gdb that a new library has been loaded. Otherwise, symbols\n\ +must be loaded manually, using `sharedlibrary'.", + &setlist), + &showlist); +} + + +/* Register that we are able to handle irix5 core file formats. + This really is bfd_target_unknown_flavour */ + +static struct core_fns irix5_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_irix5 () +{ + add_core_fns (&irix5_core_fns); +} diff --git a/contrib/gdb/gdb/isi-xdep.c b/contrib/gdb/gdb/isi-xdep.c new file mode 100644 index 000000000000..8773c83ea7a9 --- /dev/null +++ b/contrib/gdb/gdb/isi-xdep.c @@ -0,0 +1,20 @@ +/* Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +int rloc[] = { + R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, FP, SP, PS, PC +}; diff --git a/contrib/gdb/gdb/kdb-start.c b/contrib/gdb/gdb/kdb-start.c new file mode 100644 index 000000000000..bec558f635da --- /dev/null +++ b/contrib/gdb/gdb/kdb-start.c @@ -0,0 +1,35 @@ +/* Main loop for the standalone kernel debugger, for GDB, the GNU Debugger. + Copyright 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +static char *args[] = {"kdb", "kdb-symbols", 0}; + +static char *environment[] = {0}; + +char **environ; + +start () +{ + INIT_STACK (kdb_stack_beg, kdb_stack_end); + + environ = environment; + + main (2, args, environment); +} diff --git a/contrib/gdb/gdb/language.c b/contrib/gdb/gdb/language.c new file mode 100644 index 000000000000..51ce181900b2 --- /dev/null +++ b/contrib/gdb/gdb/language.c @@ -0,0 +1,1400 @@ +/* Multiple source language support for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Contributed by the Department of Computer Science at the State University + of New York at Buffalo. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains functions that return things that are specific + to languages. Each function should examine current_language if necessary, + and return the appropriate result. */ + +/* FIXME: Most of these would be better organized as macros which + return data out of a "language-specific" struct pointer that is set + whenever the working language changes. That would be a lot faster. */ + +#include "defs.h" +#include +#include "gdb_string.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcmd.h" +#include "frame.h" +#include "expression.h" +#include "language.h" +#include "target.h" +#include "parser-defs.h" + +static void +show_language_command PARAMS ((char *, int)); + +static void +set_language_command PARAMS ((char *, int)); + +static void +show_type_command PARAMS ((char *, int)); + +static void +set_type_command PARAMS ((char *, int)); + +static void +show_range_command PARAMS ((char *, int)); + +static void +set_range_command PARAMS ((char *, int)); + +static void +set_range_str PARAMS ((void)); + +static void +set_type_str PARAMS ((void)); + +static void +set_lang_str PARAMS ((void)); + +static void +unk_lang_error PARAMS ((char *)); + +static int +unk_lang_parser PARAMS ((void)); + +static void +show_check PARAMS ((char *, int)); + +static void +set_check PARAMS ((char *, int)); + +static void +set_type_range PARAMS ((void)); + +/* Forward declaration */ +extern const struct language_defn unknown_language_defn; +extern char *warning_pre_print; + +/* The current (default at startup) state of type and range checking. + (If the modes are set to "auto", though, these are changed based + on the default language at startup, and then again based on the + language of the first source file. */ + +enum range_mode range_mode = range_mode_auto; +enum range_check range_check = range_check_off; +enum type_mode type_mode = type_mode_auto; +enum type_check type_check = type_check_off; + +/* The current language and language_mode (see language.h) */ + +const struct language_defn *current_language = &unknown_language_defn; +enum language_mode language_mode = language_mode_auto; + +/* The language that the user expects to be typing in (the language + of main(), or the last language we notified them about, or C). */ + +const struct language_defn *expected_language; + +/* The list of supported languages. The list itself is malloc'd. */ + +static const struct language_defn **languages; +static unsigned languages_size; +static unsigned languages_allocsize; +#define DEFAULT_ALLOCSIZE 4 + +/* The "set language/type/range" commands all put stuff in these + buffers. This is to make them work as set/show commands. The + user's string is copied here, then the set_* commands look at + them and update them to something that looks nice when it is + printed out. */ + +static char *language; +static char *type; +static char *range; + +/* Warning issued when current_language and the language of the current + frame do not match. */ +char lang_frame_mismatch_warn[] = + "Warning: the current language does not match this frame."; + + +/* This page contains the functions corresponding to GDB commands + and their helpers. */ + +/* Show command. Display a warning if the language set + does not match the frame. */ +static void +show_language_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + enum language flang; /* The language of the current frame */ + + flang = get_frame_language(); + if (flang != language_unknown && + language_mode == language_mode_manual && + current_language->la_language != flang) + printf_filtered("%s\n",lang_frame_mismatch_warn); +} + +/* Set command. Change the current working language. */ +static void +set_language_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + int i; + enum language flang; + char *err_lang; + + if (!language || !language[0]) + { + printf_unfiltered("The currently understood settings are:\n\n"); + printf_unfiltered ("local or auto Automatic setting based on source file\n"); + + for (i = 0; i < languages_size; ++i) + { + /* Already dealt with these above. */ + if (languages[i]->la_language == language_unknown + || languages[i]->la_language == language_auto) + continue; + + /* FIXME for now assume that the human-readable name is just + a capitalization of the internal name. */ + printf_unfiltered ("%-16s Use the %c%s language\n", + languages[i]->la_name, + /* Capitalize first letter of language + name. */ + toupper (languages[i]->la_name[0]), + languages[i]->la_name + 1); + } + /* Restore the silly string. */ + set_language(current_language->la_language); + return; + } + + /* Search the list of languages for a match. */ + for (i = 0; i < languages_size; i++) { + if (STREQ (languages[i]->la_name, language)) { + /* Found it! Go into manual mode, and use this language. */ + if (languages[i]->la_language == language_auto) { + /* Enter auto mode. Set to the current frame's language, if known. */ + language_mode = language_mode_auto; + flang = get_frame_language(); + if (flang!=language_unknown) + set_language(flang); + expected_language = current_language; + return; + } else { + /* Enter manual mode. Set the specified language. */ + language_mode = language_mode_manual; + current_language = languages[i]; + set_type_range (); + set_lang_str(); + expected_language = current_language; + return; + } + } + } + + /* Reset the language (esp. the global string "language") to the + correct values. */ + err_lang=savestring(language,strlen(language)); + make_cleanup (free, err_lang); /* Free it after error */ + set_language(current_language->la_language); + error ("Unknown language `%s'.",err_lang); +} + +/* Show command. Display a warning if the type setting does + not match the current language. */ +static void +show_type_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (type_check != current_language->la_type_check) + printf_unfiltered( +"Warning: the current type check setting does not match the language.\n"); +} + +/* Set command. Change the setting for type checking. */ +static void +set_type_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (STREQ(type,"on")) + { + type_check = type_check_on; + type_mode = type_mode_manual; + } + else if (STREQ(type,"warn")) + { + type_check = type_check_warn; + type_mode = type_mode_manual; + } + else if (STREQ(type,"off")) + { + type_check = type_check_off; + type_mode = type_mode_manual; + } + else if (STREQ(type,"auto")) + { + type_mode = type_mode_auto; + set_type_range(); + /* Avoid hitting the set_type_str call below. We + did it in set_type_range. */ + return; + } + set_type_str(); + show_type_command((char *)NULL, from_tty); +} + +/* Show command. Display a warning if the range setting does + not match the current language. */ +static void +show_range_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + + if (range_check != current_language->la_range_check) + printf_unfiltered( +"Warning: the current range check setting does not match the language.\n"); +} + +/* Set command. Change the setting for range checking. */ +static void +set_range_command(ignore, from_tty) + char *ignore; + int from_tty; +{ + if (STREQ(range,"on")) + { + range_check = range_check_on; + range_mode = range_mode_manual; + } + else if (STREQ(range,"warn")) + { + range_check = range_check_warn; + range_mode = range_mode_manual; + } + else if (STREQ(range,"off")) + { + range_check = range_check_off; + range_mode = range_mode_manual; + } + else if (STREQ(range,"auto")) + { + range_mode = range_mode_auto; + set_type_range(); + /* Avoid hitting the set_range_str call below. We + did it in set_type_range. */ + return; + } + set_range_str(); + show_range_command((char *)0, from_tty); +} + +/* Set the status of range and type checking based on + the current modes and the current language. + If SHOW is non-zero, then print out the current language, + type and range checking status. */ +static void +set_type_range() +{ + + if (range_mode == range_mode_auto) + range_check = current_language->la_range_check; + + if (type_mode == type_mode_auto) + type_check = current_language->la_type_check; + + set_type_str(); + set_range_str(); +} + +/* Set current language to (enum language) LANG. */ + +void +set_language(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + current_language = languages[i]; + set_type_range (); + set_lang_str(); + break; + } + } +} + +/* This page contains functions that update the global vars + language, type and range. */ +static void +set_lang_str() +{ + char *prefix = ""; + + free (language); + if (language_mode == language_mode_auto) + prefix = "auto; currently "; + + language = concat(prefix, current_language->la_name, NULL); +} + +static void +set_type_str() +{ + char *tmp, *prefix = ""; + + free (type); + if (type_mode==type_mode_auto) + prefix = "auto; currently "; + + switch(type_check) + { + case type_check_on: + tmp = "on"; + break; + case type_check_off: + tmp = "off"; + break; + case type_check_warn: + tmp = "warn"; + break; + default: + error ("Unrecognized type check setting."); + } + + type = concat(prefix,tmp,NULL); +} + +static void +set_range_str() +{ + char *tmp, *pref = ""; + + free (range); + if (range_mode==range_mode_auto) + pref = "auto; currently "; + + switch(range_check) + { + case range_check_on: + tmp = "on"; + break; + case range_check_off: + tmp = "off"; + break; + case range_check_warn: + tmp = "warn"; + break; + default: + error ("Unrecognized range check setting."); + } + + range = concat(pref,tmp,NULL); +} + + +/* Print out the current language settings: language, range and + type checking. If QUIETLY, print only what has changed. */ + +void +language_info (quietly) + int quietly; +{ + if (quietly && expected_language == current_language) + return; + + expected_language = current_language; + printf_unfiltered("Current language: %s\n",language); + show_language_command((char *)0, 1); + + if (!quietly) + { + printf_unfiltered("Type checking: %s\n",type); + show_type_command((char *)0, 1); + printf_unfiltered("Range checking: %s\n",range); + show_range_command((char *)0, 1); + } +} + +/* Return the result of a binary operation. */ + +#if 0 /* Currently unused */ + +struct type * +binop_result_type (v1, v2) + value_ptr v1, v2; +{ + int size,uns; + struct type *t1 = check_typedef (VALUE_TYPE (v1)); + struct type *t2 = check_typedef (VALUE_TYPE (v2)); + + int l1 = TYPE_LENGTH (t1); + int l2 = TYPE_LENGTH (t2); + + switch(current_language->la_language) + { + case language_c: + case language_cplus: + if (TYPE_CODE (t1)==TYPE_CODE_FLT) + return TYPE_CODE(t2) == TYPE_CODE_FLT && l2 > l1 ? + VALUE_TYPE(v2) : VALUE_TYPE(v1); + else if (TYPE_CODE(t2)==TYPE_CODE_FLT) + return TYPE_CODE(t1)) == TYPE_CODE_FLT && l1 > l2 ? + VALUE_TYPE(v1) : VALUE_TYPE(v2); + else if (TYPE_UNSIGNED(t1) && l1 > l2) + return VALUE_TYPE(v1); + else if (TYPE_UNSIGNED(t2) && l2 > l1) + return VALUE_TYPE(v2); + else /* Both are signed. Result is the longer type */ + return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2); + break; + case language_m2: + /* If we are doing type-checking, l1 should equal l2, so this is + not needed. */ + return l1 > l2 ? VALUE_TYPE(v1) : VALUE_TYPE(v2); + break; + case language_chill: + error ("Missing Chill support in function binop_result_check.");/*FIXME*/ + } + abort(); + return (struct type *)0; /* For lint */ +} + +#endif /* 0 */ + + +/* This page contains functions that return format strings for + printf for printing out numbers in different formats */ + +/* Returns the appropriate printf format for hexadecimal + numbers. */ +char * +local_hex_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_hex_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_hex_format_specifier ()); + strcat (form, local_hex_format_suffix ()); + return form; +} + +/* Converts a number to hexadecimal and stores it in a static + string. Returns a pointer to this string. */ +char * +local_hex_string (num) + unsigned long num; +{ + static char res[50]; + + sprintf (res, local_hex_format(), num); + return res; +} + +/* Converts a number to custom hexadecimal and stores it in a static + string. Returns a pointer to this string. */ +char * +local_hex_string_custom(num,pre) + unsigned long num; + char *pre; +{ + static char res[50]; + + sprintf (res, local_hex_format_custom(pre), num); + return res; +} + +/* Returns the appropriate printf format for octal + numbers. */ +char * +local_octal_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_octal_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_octal_format_specifier ()); + strcat (form, local_octal_format_suffix ()); + return form; +} + +/* Returns the appropriate printf format for decimal numbers. */ +char * +local_decimal_format_custom(pre) + char *pre; +{ + static char form[50]; + + strcpy (form, local_decimal_format_prefix ()); + strcat (form, "%"); + strcat (form, pre); + strcat (form, local_decimal_format_specifier ()); + strcat (form, local_decimal_format_suffix ()); + return form; +} + +#if 0 +/* This page contains functions that are used in type/range checking. + They all return zero if the type/range check fails. + + It is hoped that these will make extending GDB to parse different + languages a little easier. These are primarily used in eval.c when + evaluating expressions and making sure that their types are correct. + Instead of having a mess of conjucted/disjuncted expressions in an "if", + the ideas of type can be wrapped up in the following functions. + + Note that some of them are not currently dependent upon which language + is currently being parsed. For example, floats are the same in + C and Modula-2 (ie. the only floating point type has TYPE_CODE of + TYPE_CODE_FLT), while booleans are different. */ + +/* Returns non-zero if its argument is a simple type. This is the same for + both Modula-2 and for C. In the C case, TYPE_CODE_CHAR will never occur, + and thus will never cause the failure of the test. */ +int +simple_type(type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLT: + case TYPE_CODE_RANGE: + case TYPE_CODE_BOOL: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if its argument is of an ordered type. + An ordered type is one in which the elements can be tested for the + properties of "greater than", "less than", etc, or for which the + operations "increment" or "decrement" make sense. */ +int +ordered_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLT: + case TYPE_CODE_RANGE: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if the two types are the same */ +int +same_type (arg1, arg2) + struct type *arg1, *arg2; +{ + CHECK_TYPEDEF (type); + if (structured_type(arg1) ? !structured_type(arg2) : structured_type(arg2)) + /* One is structured and one isn't */ + return 0; + else if (structured_type(arg1) && structured_type(arg2)) + return arg1 == arg2; + else if (numeric_type(arg1) && numeric_type(arg2)) + return (TYPE_CODE(arg2) == TYPE_CODE(arg1)) && + (TYPE_UNSIGNED(arg1) == TYPE_UNSIGNED(arg2)) + ? 1 : 0; + else + return arg1==arg2; +} + +/* Returns non-zero if the type is integral */ +int +integral_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch(current_language->la_language) + { + case language_c: + case language_cplus: + return (TYPE_CODE(type) != TYPE_CODE_INT) && + (TYPE_CODE(type) != TYPE_CODE_ENUM) ? 0 : 1; + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_INT ? 0 : 1; + case language_chill: + error ("Missing Chill support in function integral_type."); /*FIXME*/ + default: + error ("Language not supported."); + } +} + +/* Returns non-zero if the value is numeric */ +int +numeric_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + return 1; + + default: + return 0; + } +} + +/* Returns non-zero if the value is a character type */ +int +character_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch(current_language->la_language) + { + case language_chill: + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_CHAR ? 0 : 1; + + case language_c: + case language_cplus: + return (TYPE_CODE(type) == TYPE_CODE_INT) && + TYPE_LENGTH(type) == sizeof(char) + ? 1 : 0; + default: + return (0); + } +} + +/* Returns non-zero if the value is a string type */ +int +string_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch(current_language->la_language) + { + case language_chill: + case language_m2: + return TYPE_CODE(type) != TYPE_CODE_STRING ? 0 : 1; + + case language_c: + case language_cplus: + /* C does not have distinct string type. */ + return (0); + default: + return (0); + } +} + +/* Returns non-zero if the value is a boolean type */ +int +boolean_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) == TYPE_CODE_BOOL) + return 1; + switch(current_language->la_language) + { + case language_c: + case language_cplus: + /* Might be more cleanly handled by having a TYPE_CODE_INT_NOT_BOOL + for CHILL and such languages, or a TYPE_CODE_INT_OR_BOOL for C. */ + if (TYPE_CODE (type) == TYPE_CODE_INT) + return 1; + default: + break; + } + return 0; +} + +/* Returns non-zero if the value is a floating-point type */ +int +float_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + return TYPE_CODE(type) == TYPE_CODE_FLT; +} + +/* Returns non-zero if the value is a pointer type */ +int +pointer_type(type) + struct type *type; +{ + return TYPE_CODE(type) == TYPE_CODE_PTR || + TYPE_CODE(type) == TYPE_CODE_REF; +} + +/* Returns non-zero if the value is a structured type */ +int +structured_type(type) + struct type *type; +{ + CHECK_TYPEDEF (type); + switch(current_language->la_language) + { + case language_c: + case language_cplus: + return (TYPE_CODE(type) == TYPE_CODE_STRUCT) || + (TYPE_CODE(type) == TYPE_CODE_UNION) || + (TYPE_CODE(type) == TYPE_CODE_ARRAY); + case language_m2: + return (TYPE_CODE(type) == TYPE_CODE_STRUCT) || + (TYPE_CODE(type) == TYPE_CODE_SET) || + (TYPE_CODE(type) == TYPE_CODE_ARRAY); + case language_chill: + error ("Missing Chill support in function structured_type."); /*FIXME*/ + default: + return (0); + } +} +#endif + +struct type * +lang_bool_type () +{ + struct symbol *sym; + struct type *type; + switch(current_language->la_language) + { + case language_chill: + return builtin_type_chill_bool; + case language_fortran: + sym = lookup_symbol ("logical", NULL, VAR_NAMESPACE, NULL, NULL); + if (sym) + { + type = SYMBOL_TYPE (sym); + if (type && TYPE_CODE (type) == TYPE_CODE_BOOL) + return type; + } + return builtin_type_f_logical_s2; + case language_cplus: + sym = lookup_symbol ("bool", NULL, VAR_NAMESPACE, NULL, NULL); + if (sym) + { + type = SYMBOL_TYPE (sym); + if (type && TYPE_CODE (type) == TYPE_CODE_BOOL) + return type; + } + /* ... else fall through ... */ + default: + return builtin_type_int; + } +} + +/* This page contains functions that return info about + (struct value) values used in GDB. */ + +/* Returns non-zero if the value VAL represents a true value. */ +int +value_true (val) + value_ptr val; +{ + /* It is possible that we should have some sort of error if a non-boolean + value is used in this context. Possibly dependent on some kind of + "boolean-checking" option like range checking. But it should probably + not depend on the language except insofar as is necessary to identify + a "boolean" value (i.e. in C using a float, pointer, etc., as a boolean + should be an error, probably). */ + return !value_logical_not (val); +} + +/* Returns non-zero if the operator OP is defined on + the values ARG1 and ARG2. */ + +#if 0 /* Currently unused */ + +void +binop_type_check(arg1,arg2,op) + value_ptr arg1,arg2; + int op; +{ + struct type *t1, *t2; + + /* If we're not checking types, always return success. */ + if (!STRICT_TYPE) + return; + + t1=VALUE_TYPE(arg1); + if (arg2 != NULL) + t2=VALUE_TYPE(arg2); + else + t2=NULL; + + switch(op) + { + case BINOP_ADD: + case BINOP_SUB: + if ((numeric_type(t1) && pointer_type(t2)) || + (pointer_type(t1) && numeric_type(t2))) + { + warning ("combining pointer and integer.\n"); + break; + } + case BINOP_MUL: + case BINOP_LSH: + case BINOP_RSH: + if (!numeric_type(t1) || !numeric_type(t2)) + type_op_error ("Arguments to %s must be numbers.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_LOGICAL_AND: + case BINOP_LOGICAL_OR: + if (!boolean_type(t1) || !boolean_type(t2)) + type_op_error ("Arguments to %s must be of boolean type.",op); + break; + + case BINOP_EQUAL: + if ((pointer_type(t1) && !(pointer_type(t2) || integral_type(t2))) || + (pointer_type(t2) && !(pointer_type(t1) || integral_type(t1)))) + type_op_error ("A pointer can only be compared to an integer or pointer.",op); + else if ((pointer_type(t1) && integral_type(t2)) || + (integral_type(t1) && pointer_type(t2))) + { + warning ("combining integer and pointer.\n"); + break; + } + else if (!simple_type(t1) || !simple_type(t2)) + type_op_error ("Arguments to %s must be of simple type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_REM: + case BINOP_MOD: + if (!integral_type(t1) || !integral_type(t2)) + type_op_error ("Arguments to %s must be of integral type.",op); + break; + + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + if (!ordered_type(t1) || !ordered_type(t2)) + type_op_error ("Arguments to %s must be of ordered type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_ASSIGN: + if (pointer_type(t1) && !integral_type(t2)) + type_op_error ("A pointer can only be assigned an integer.",op); + else if (pointer_type(t1) && integral_type(t2)) + { + warning ("combining integer and pointer."); + break; + } + else if (!simple_type(t1) || !simple_type(t2)) + type_op_error ("Arguments to %s must be of simple type.",op); + else if (!same_type(t1,t2)) + type_op_error ("Arguments to %s must be of the same type.",op); + break; + + case BINOP_CONCAT: + /* FIXME: Needs to handle bitstrings as well. */ + if (!(string_type(t1) || character_type(t1) || integral_type(t1)) + || !(string_type(t2) || character_type(t2) || integral_type(t2))) + type_op_error ("Arguments to %s must be strings or characters.", op); + break; + + /* Unary checks -- arg2 is null */ + + case UNOP_LOGICAL_NOT: + if (!boolean_type(t1)) + type_op_error ("Argument to %s must be of boolean type.",op); + break; + + case UNOP_PLUS: + case UNOP_NEG: + if (!numeric_type(t1)) + type_op_error ("Argument to %s must be of numeric type.",op); + break; + + case UNOP_IND: + if (integral_type(t1)) + { + warning ("combining pointer and integer.\n"); + break; + } + else if (!pointer_type(t1)) + type_op_error ("Argument to %s must be a pointer.",op); + break; + + case UNOP_PREINCREMENT: + case UNOP_POSTINCREMENT: + case UNOP_PREDECREMENT: + case UNOP_POSTDECREMENT: + if (!ordered_type(t1)) + type_op_error ("Argument to %s must be of an ordered type.",op); + break; + + default: + /* Ok. The following operators have different meanings in + different languages. */ + switch(current_language->la_language) + { +#ifdef _LANG_c + case language_c: + case language_cplus: + switch(op) + { + case BINOP_DIV: + if (!numeric_type(t1) || !numeric_type(t2)) + type_op_error ("Arguments to %s must be numbers.",op); + break; + } + break; +#endif + +#ifdef _LANG_m2 + case language_m2: + switch(op) + { + case BINOP_DIV: + if (!float_type(t1) || !float_type(t2)) + type_op_error ("Arguments to %s must be floating point numbers.",op); + break; + case BINOP_INTDIV: + if (!integral_type(t1) || !integral_type(t2)) + type_op_error ("Arguments to %s must be of integral type.",op); + break; + } +#endif + +#ifdef _LANG_chill + case language_chill: + error ("Missing Chill support in function binop_type_check.");/*FIXME*/ +#endif + + } + } +} + +#endif /* 0 */ + + +/* This page contains functions for the printing out of + error messages that occur during type- and range- + checking. */ + +/* Prints the format string FMT with the operator as a string + corresponding to the opcode OP. If FATAL is non-zero, then + this is an error and error () is called. Otherwise, it is + a warning and printf() is called. */ +void +op_error (fmt,op,fatal) + char *fmt; + enum exp_opcode op; + int fatal; +{ + if (fatal) + error (fmt,op_string(op)); + else + { + warning (fmt,op_string(op)); + } +} + +/* These are called when a language fails a type- or range-check. + The first argument should be a printf()-style format string, and + the rest of the arguments should be its arguments. If + [type|range]_check is [type|range]_check_on, then return_to_top_level() + is called in the style of error (). Otherwise, the message is prefixed + by the value of warning_pre_print and we do not return to the top level. */ + +void +#ifdef ANSI_PROTOTYPES +type_error (char *string, ...) +#else +type_error (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + va_start (args); + string = va_arg (args, char *); +#endif + + if (type_check == type_check_warn) + fprintf_filtered (gdb_stderr, warning_pre_print); + else + error_begin (); + + vfprintf_filtered (gdb_stderr, string, args); + fprintf_filtered (gdb_stderr, "\n"); + va_end (args); + if (type_check == type_check_on) + return_to_top_level (RETURN_ERROR); +} + +void +#ifdef ANSI_PROTOTYPES +range_error (char *string, ...) +#else +range_error (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + va_start (args); + string = va_arg (args, char *); +#endif + + if (range_check == range_check_warn) + fprintf_filtered (gdb_stderr, warning_pre_print); + else + error_begin (); + + vfprintf_filtered (gdb_stderr, string, args); + fprintf_filtered (gdb_stderr, "\n"); + va_end (args); + if (range_check == range_check_on) + return_to_top_level (RETURN_ERROR); +} + + +/* This page contains miscellaneous functions */ + +/* Return the language struct for a given language enum. */ + +const struct language_defn * +language_def(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + return languages[i]; + } + } + return NULL; +} + +/* Return the language as a string */ +char * +language_str(lang) + enum language lang; +{ + int i; + + for (i = 0; i < languages_size; i++) { + if (languages[i]->la_language == lang) { + return languages[i]->la_name; + } + } + return "Unknown"; +} + +static void +set_check (ignore, from_tty) + char *ignore; + int from_tty; +{ + printf_unfiltered( +"\"set check\" must be followed by the name of a check subcommand.\n"); + help_list(setchecklist, "set check ", -1, gdb_stdout); +} + +static void +show_check (ignore, from_tty) + char *ignore; + int from_tty; +{ + cmd_show_list(showchecklist, from_tty, ""); +} + +/* Add a language to the set of known languages. */ + +void +add_language (lang) + const struct language_defn *lang; +{ + if (lang->la_magic != LANG_MAGIC) + { + fprintf_unfiltered(gdb_stderr, "Magic number of %s language struct wrong\n", + lang->la_name); + abort(); + } + + if (!languages) + { + languages_allocsize = DEFAULT_ALLOCSIZE; + languages = (const struct language_defn **) xmalloc + (languages_allocsize * sizeof (*languages)); + } + if (languages_size >= languages_allocsize) + { + languages_allocsize *= 2; + languages = (const struct language_defn **) xrealloc ((char *) languages, + languages_allocsize * sizeof (*languages)); + } + languages[languages_size++] = lang; +} + +/* Define the language that is no language. */ + +static int +unk_lang_parser () +{ + return 1; +} + +static void +unk_lang_error (msg) + char *msg; +{ + error ("Attempted to parse an expression with unknown language"); +} + +static void +unk_lang_printchar (c, stream) + register int c; + GDB_FILE *stream; +{ + error ("internal error - unimplemented function unk_lang_printchar called."); +} + +static void +unk_lang_printstr (stream, string, length, force_ellipses) + GDB_FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + error ("internal error - unimplemented function unk_lang_printstr called."); +} + +static struct type * +unk_lang_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + error ("internal error - unimplemented function unk_lang_create_fundamental_type called."); +} + +void +unk_lang_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + GDB_FILE *stream; + int show; + int level; +{ + error ("internal error - unimplemented function unk_lang_print_type called."); +} + +int +unk_lang_val_print (type, valaddr, address, stream, format, deref_ref, + recurse, pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + error ("internal error - unimplemented function unk_lang_val_print called."); +} + +int +unk_lang_value_print (val, stream, format, pretty) + value_ptr val; + GDB_FILE *stream; + int format; + enum val_prettyprint pretty; +{ + error ("internal error - unimplemented function unk_lang_value_print called."); +} + +static struct type ** const (unknown_builtin_types[]) = { 0 }; +static const struct op_print unk_op_print_tab[] = { + {NULL, OP_NULL, PREC_NULL, 0} +}; + +const struct language_defn unknown_language_defn = { + "unknown", + language_unknown, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + evaluate_subexp_standard, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + unk_lang_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +/* These two structs define fake entries for the "local" and "auto" options. */ +const struct language_defn auto_language_defn = { + "auto", + language_auto, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + evaluate_subexp_standard, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + unk_lang_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +const struct language_defn local_language_defn = { + "local", + language_auto, + &unknown_builtin_types[0], + range_check_off, + type_check_off, + unk_lang_parser, + unk_lang_error, + evaluate_subexp_standard, + unk_lang_printchar, /* Print character constant */ + unk_lang_printstr, + unk_lang_create_fundamental_type, + unk_lang_print_type, /* Print a type using appropriate syntax */ + unk_lang_val_print, /* Print a value using appropriate syntax */ + unk_lang_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + unk_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +/* Initialize the language routines */ + +void +_initialize_language() +{ + struct cmd_list_element *set, *show; + + /* GDB commands for language specific stuff */ + + set = add_set_cmd ("language", class_support, var_string_noescape, + (char *)&language, + "Set the current source language.", + &setlist); + show = add_show_from_set (set, &showlist); + set->function.cfunc = set_language_command; + show->function.cfunc = show_language_command; + + add_prefix_cmd ("check", no_class, set_check, + "Set the status of the type/range checker", + &setchecklist, "set check ", 0, &setlist); + add_alias_cmd ("c", "check", no_class, 1, &setlist); + add_alias_cmd ("ch", "check", no_class, 1, &setlist); + + add_prefix_cmd ("check", no_class, show_check, + "Show the status of the type/range checker", + &showchecklist, "show check ", 0, &showlist); + add_alias_cmd ("c", "check", no_class, 1, &showlist); + add_alias_cmd ("ch", "check", no_class, 1, &showlist); + + set = add_set_cmd ("type", class_support, var_string_noescape, + (char *)&type, + "Set type checking. (on/warn/off/auto)", + &setchecklist); + show = add_show_from_set (set, &showchecklist); + set->function.cfunc = set_type_command; + show->function.cfunc = show_type_command; + + set = add_set_cmd ("range", class_support, var_string_noescape, + (char *)&range, + "Set range checking. (on/warn/off/auto)", + &setchecklist); + show = add_show_from_set (set, &showchecklist); + set->function.cfunc = set_range_command; + show->function.cfunc = show_range_command; + + add_language (&unknown_language_defn); + add_language (&local_language_defn); + add_language (&auto_language_defn); + + language = savestring ("auto",strlen("auto")); + range = savestring ("auto",strlen("auto")); + type = savestring ("auto",strlen("auto")); + + /* Have the above take effect */ + + set_language_command (language, 0); + set_type_command (NULL, 0); + set_range_command (NULL, 0); +} diff --git a/contrib/gdb/gdb/language.h b/contrib/gdb/gdb/language.h new file mode 100644 index 000000000000..941943b74335 --- /dev/null +++ b/contrib/gdb/gdb/language.h @@ -0,0 +1,431 @@ +/* Source-language-related definitions for GDB. + Copyright 1991, 1992 Free Software Foundation, Inc. + Contributed by the Department of Computer Science at the State University + of New York at Buffalo. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (LANGUAGE_H) +#define LANGUAGE_H 1 + +#ifdef __STDC__ /* Forward decls for prototypes */ +struct value; +struct objfile; +struct expression; +/* enum exp_opcode; ANSI's `wisdom' didn't include forward enum decls. */ +#endif + +/* This used to be included to configure GDB for one or more specific + languages. Now it is shortcutted to configure for all of them. FIXME. */ +/* #include "lang_def.h" */ +#define _LANG_c +#define _LANG_m2 +#define _LANG_chill +#define _LANG_fortran + +#define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims */ + +/* range_mode == + range_mode_auto: range_check set automatically to default of language. + range_mode_manual: range_check set manually by user. */ + +extern enum range_mode {range_mode_auto, range_mode_manual} range_mode; + +/* range_check == + range_check_on: Ranges are checked in GDB expressions, producing errors. + range_check_warn: Ranges are checked, producing warnings. + range_check_off: Ranges are not checked in GDB expressions. */ + +extern enum range_check + {range_check_off, range_check_warn, range_check_on} range_check; + +/* type_mode == + type_mode_auto: type_check set automatically to default of language + type_mode_manual: type_check set manually by user. */ + +extern enum type_mode {type_mode_auto, type_mode_manual} type_mode; + +/* type_check == + type_check_on: Types are checked in GDB expressions, producing errors. + type_check_warn: Types are checked, producing warnings. + type_check_off: Types are not checked in GDB expressions. */ + +extern enum type_check + {type_check_off, type_check_warn, type_check_on} type_check; + +/* Information for doing language dependent formatting of printed values. */ + +struct language_format_info +{ + /* The format that can be passed directly to standard C printf functions + to generate a completely formatted value in the format appropriate for + the language. */ + + char *la_format; + + /* The prefix to be used when directly printing a value, or constructing + a standard C printf format. This generally is everything up to the + conversion specification (the part introduced by the '%' character + and terminated by the conversion specifier character). */ + + char *la_format_prefix; + + /* The conversion specifier. This is generally everything after the + field width and precision, typically only a single character such + as 'o' for octal format or 'x' for hexadecimal format. */ + + char *la_format_specifier; + + /* The suffix to be used when directly printing a value, or constructing + a standard C printf format. This generally is everything after the + conversion specification (the part introduced by the '%' character + and terminated by the conversion specifier character). */ + + char *la_format_suffix; /* Suffix for custom format string */ +}; + +/* Structure tying together assorted information about a language. */ + +struct language_defn +{ + /* Name of the language */ + + char *la_name; + + /* its symtab language-enum (defs.h) */ + + enum language la_language; + + /* Its builtin types. This is a vector ended by a NULL pointer. These + types can be specified by name in parsing types in expressions, + regardless of whether the program being debugged actually defines + such a type. */ + + struct type ** const *la_builtin_type_vector; + + /* Default range checking */ + + enum range_check la_range_check; + + /* Default type checking */ + + enum type_check la_type_check; + + /* Parser function. */ + + int (*la_parser) PARAMS((void)); + + /* Parser error function */ + + void (*la_error) PARAMS ((char *)); + + /* Evaluate an expression. */ + struct value * (*evaluate_exp) PARAMS ((struct type*, struct expression *, + int *, enum noside)); + + void (*la_printchar) PARAMS ((int, GDB_FILE *)); + + void (*la_printstr) PARAMS ((GDB_FILE *, char *, unsigned int, int)); + + struct type *(*la_fund_type) PARAMS ((struct objfile *, int)); + + /* Print a type using syntax appropriate for this language. */ + + void (*la_print_type) PARAMS ((struct type *, char *, GDB_FILE *, int, int)); + + /* Print a value using syntax appropriate for this language. */ + + int (*la_val_print) PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, + int, int, int, enum val_prettyprint)); + + /* Print a top-level value using syntax appropriate for this language. */ + + int (*la_value_print) PARAMS ((struct value *, GDB_FILE *, + int, enum val_prettyprint)); + + /* Base 2 (binary) formats. */ + + struct language_format_info la_binary_format; + + /* Base 8 (octal) formats. */ + + struct language_format_info la_octal_format; + + /* Base 10 (decimal) formats */ + + struct language_format_info la_decimal_format; + + /* Base 16 (hexadecimal) formats */ + + struct language_format_info la_hex_format; + + /* Table for printing expressions */ + + const struct op_print *la_op_print_tab; + + /* Zero if the language has first-class arrays. True if there are no + array values, and array objects decay to pointers, as in C. */ + + char c_style_arrays; + + /* Index to use for extracting the first element of a string. */ + char string_lower_bound; + + /* Type of elements of strings. */ + struct type **string_char_type; + + /* Add fields above this point, so the magic number is always last. */ + /* Magic number for compat checking */ + + long la_magic; + +}; + +#define LANG_MAGIC 910823L + +/* Pointer to the language_defn for our current language. This pointer + always points to *some* valid struct; it can be used without checking + it for validity. + + The current language affects expression parsing and evaluation + (FIXME: it might be cleaner to make the evaluation-related stuff + separate exp_opcodes for each different set of semantics. We + should at least think this through more clearly with respect to + what happens if the language is changed between parsing and + evaluation) and printing of things like types and arrays. It does + *not* affect symbol-reading-- each source file in a symbol-file has + its own language and we should keep track of that regardless of the + language when symbols are read. If we want some manual setting for + the language of symbol files (e.g. detecting when ".c" files are + C++), it should be a seprate setting from the current_language. */ + +extern const struct language_defn *current_language; + +/* Pointer to the language_defn expected by the user, e.g. the language + of main(), or the language we last mentioned in a message, or C. */ + +extern const struct language_defn *expected_language; + +/* language_mode == + language_mode_auto: current_language automatically set upon selection + of scope (e.g. stack frame) + language_mode_manual: current_language set only by user. */ + +extern enum language_mode + {language_mode_auto, language_mode_manual} language_mode; + +/* These macros define the behaviour of the expression + evaluator. */ + +/* Should we strictly type check expressions? */ +#define STRICT_TYPE (type_check != type_check_off) + +/* Should we range check values against the domain of their type? */ +#define RANGE_CHECK (range_check != range_check_off) + +/* "cast" really means conversion */ +/* FIXME -- should be a setting in language_defn */ +#define CAST_IS_CONVERSION (current_language->la_language == language_c || \ + current_language->la_language == language_cplus) + +extern void +language_info PARAMS ((int)); + +extern void +set_language PARAMS ((enum language)); + + +/* This page contains functions that return things that are + specific to languages. Each of these functions is based on + the current setting of working_lang, which the user sets + with the "set language" command. */ + +#define create_fundamental_type(objfile,typeid) \ + (current_language->la_fund_type(objfile, typeid)) + +#define LA_PRINT_TYPE(type,varstring,stream,show,level) \ + (current_language->la_print_type(type,varstring,stream,show,level)) + +#define LA_VAL_PRINT(type,valaddr,addr,stream,fmt,deref,recurse,pretty) \ + (current_language->la_val_print(type,valaddr,addr,stream,fmt,deref, \ + recurse,pretty)) +#define LA_VALUE_PRINT(val,stream,fmt,pretty) \ + (current_language->la_value_print(val,stream,fmt,pretty)) + +/* Return a format string for printf that will print a number in one of + the local (language-specific) formats. Result is static and is + overwritten by the next call. Takes printf options like "08" or "l" + (to produce e.g. %08x or %lx). */ + +#define local_binary_format() \ + (current_language->la_binary_format.la_format) +#define local_binary_format_prefix() \ + (current_language->la_binary_format.la_format_prefix) +#define local_binary_format_specifier() \ + (current_language->la_binary_format.la_format_specifier) +#define local_binary_format_suffix() \ + (current_language->la_binary_format.la_format_suffix) + +#define local_octal_format() \ + (current_language->la_octal_format.la_format) +#define local_octal_format_prefix() \ + (current_language->la_octal_format.la_format_prefix) +#define local_octal_format_specifier() \ + (current_language->la_octal_format.la_format_specifier) +#define local_octal_format_suffix() \ + (current_language->la_octal_format.la_format_suffix) + +#define local_decimal_format() \ + (current_language->la_decimal_format.la_format) +#define local_decimal_format_prefix() \ + (current_language->la_decimal_format.la_format_prefix) +#define local_decimal_format_specifier() \ + (current_language->la_decimal_format.la_format_specifier) +#define local_decimal_format_suffix() \ + (current_language->la_decimal_format.la_format_suffix) + +#define local_hex_format() \ + (current_language->la_hex_format.la_format) +#define local_hex_format_prefix() \ + (current_language->la_hex_format.la_format_prefix) +#define local_hex_format_specifier() \ + (current_language->la_hex_format.la_format_specifier) +#define local_hex_format_suffix() \ + (current_language->la_hex_format.la_format_suffix) + +#define LA_PRINT_CHAR(ch, stream) \ + (current_language->la_printchar(ch, stream)) +#define LA_PRINT_STRING(stream, string, length, force_ellipses) \ + (current_language->la_printstr(stream, string, length, force_ellipses)) + +/* Test a character to decide whether it can be printed in literal form + or needs to be printed in another representation. For example, + in C the literal form of the character with octal value 141 is 'a' + and the "other representation" is '\141'. The "other representation" + is program language dependent. */ + +#define PRINT_LITERAL_FORM(c) \ + ((c)>=0x20 && ((c)<0x7F || (c)>=0xA0) && (!sevenbit_strings || (c)<0x80)) + +/* Return a format string for printf that will print a number in one of + the local (language-specific) formats. Result is static and is + overwritten by the next call. Takes printf options like "08" or "l" + (to produce e.g. %08x or %lx). */ + +extern char * +local_decimal_format_custom PARAMS ((char *)); /* language.c */ + +extern char * +local_octal_format_custom PARAMS ((char *)); /* language.c */ + +extern char * +local_hex_format_custom PARAMS ((char *)); /* language.c */ + +/* Return a string that contains a number formatted in one of the local + (language-specific) formats. Result is static and is overwritten by + the next call. Takes printf options like "08" or "l". */ + +extern char * +local_hex_string PARAMS ((unsigned long)); /* language.c */ + +extern char * +local_hex_string_custom PARAMS ((unsigned long, char *)); /* language.c */ + +/* Type predicates */ + +extern int +simple_type PARAMS ((struct type *)); + +extern int +ordered_type PARAMS ((struct type *)); + +extern int +same_type PARAMS ((struct type *, struct type *)); + +extern int +integral_type PARAMS ((struct type *)); + +extern int +numeric_type PARAMS ((struct type *)); + +extern int +character_type PARAMS ((struct type *)); + +extern int +boolean_type PARAMS ((struct type *)); + +extern int +float_type PARAMS ((struct type *)); + +extern int +pointer_type PARAMS ((struct type *)); + +extern int +structured_type PARAMS ((struct type *)); + +/* Checks Binary and Unary operations for semantic type correctness */ +/* FIXME: Does not appear to be used */ +#define unop_type_check(v,o) binop_type_check((v),NULL,(o)) + +extern void +binop_type_check PARAMS ((struct value *, struct value *, int)); + +/* Error messages */ + +extern void +op_error PARAMS ((char *fmt, enum exp_opcode, int)); + +#define type_op_error(f,o) \ + op_error((f),(o),type_check==type_check_on ? 1 : 0) +#define range_op_error(f,o) \ + op_error((f),(o),range_check==range_check_on ? 1 : 0) + +extern void +type_error PARAMS ((char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +void +range_error PARAMS ((char *, ...)) + ATTR_FORMAT(printf, 1, 2); + +/* Data: Does this value represent "truth" to the current language? */ + +extern int +value_true PARAMS ((struct value *)); + +extern struct type * lang_bool_type PARAMS ((void)); + +/* The type used for Boolean values in the current language. */ +#define LA_BOOL_TYPE lang_bool_type () + +/* Misc: The string representing a particular enum language. */ + +extern const struct language_defn * +language_def PARAMS ((enum language)); + +extern char * +language_str PARAMS ((enum language)); + +/* Add a language to the set known by GDB (at initialization time). */ + +extern void +add_language PARAMS ((const struct language_defn *)); + +extern enum language +get_frame_language PARAMS ((void)); /* In stack.c */ + +#endif /* defined (LANGUAGE_H) */ diff --git a/contrib/gdb/gdb/lynx-nat.c b/contrib/gdb/gdb/lynx-nat.c new file mode 100644 index 000000000000..78716e02ab3f --- /dev/null +++ b/contrib/gdb/gdb/lynx-nat.c @@ -0,0 +1,838 @@ +/* Native-dependent code for LynxOS. + Copyright 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "gdbcore.h" + +#include +#include +#include + +static unsigned long registers_addr PARAMS ((int pid)); + +#define X(ENTRY)(offsetof(struct econtext, ENTRY)) + +#ifdef I386 +/* Mappings from tm-i386v.h */ + +static int regmap[] = +{ + X(eax), + X(ecx), + X(edx), + X(ebx), + X(esp), /* sp */ + X(ebp), /* fp */ + X(esi), + X(edi), + X(eip), /* pc */ + X(flags), /* ps */ + X(cs), + X(ss), + X(ds), + X(es), + X(ecode), /* Lynx doesn't give us either fs or gs, so */ + X(fault), /* we just substitute these two in the hopes + that they are useful. */ +}; +#endif /* I386 */ + +#ifdef M68K +/* Mappings from tm-m68k.h */ + +static int regmap[] = +{ + X(regs[0]), /* d0 */ + X(regs[1]), /* d1 */ + X(regs[2]), /* d2 */ + X(regs[3]), /* d3 */ + X(regs[4]), /* d4 */ + X(regs[5]), /* d5 */ + X(regs[6]), /* d6 */ + X(regs[7]), /* d7 */ + X(regs[8]), /* a0 */ + X(regs[9]), /* a1 */ + X(regs[10]), /* a2 */ + X(regs[11]), /* a3 */ + X(regs[12]), /* a4 */ + X(regs[13]), /* a5 */ + X(regs[14]), /* fp */ + offsetof (st_t, usp) - offsetof (st_t, ec), /* sp */ + X(status), /* ps */ + X(pc), + + X(fregs[0*3]), /* fp0 */ + X(fregs[1*3]), /* fp1 */ + X(fregs[2*3]), /* fp2 */ + X(fregs[3*3]), /* fp3 */ + X(fregs[4*3]), /* fp4 */ + X(fregs[5*3]), /* fp5 */ + X(fregs[6*3]), /* fp6 */ + X(fregs[7*3]), /* fp7 */ + + X(fcregs[0]), /* fpcontrol */ + X(fcregs[1]), /* fpstatus */ + X(fcregs[2]), /* fpiaddr */ + X(ssw), /* fpcode */ + X(fault), /* fpflags */ +}; +#endif /* M68K */ + +#ifdef SPARC +/* Mappings from tm-sparc.h */ + +#define FX(ENTRY)(offsetof(struct fcontext, ENTRY)) + +static int regmap[] = +{ + -1, /* g0 */ + X(g1), + X(g2), + X(g3), + X(g4), + -1, /* g5->g7 aren't saved by Lynx */ + -1, + -1, + + X(o[0]), + X(o[1]), + X(o[2]), + X(o[3]), + X(o[4]), + X(o[5]), + X(o[6]), /* sp */ + X(o[7]), /* ra */ + + -1,-1,-1,-1,-1,-1,-1,-1, /* l0 -> l7 */ + + -1,-1,-1,-1,-1,-1,-1,-1, /* i0 -> i7 */ + + FX(f.fregs[0]), /* f0 */ + FX(f.fregs[1]), + FX(f.fregs[2]), + FX(f.fregs[3]), + FX(f.fregs[4]), + FX(f.fregs[5]), + FX(f.fregs[6]), + FX(f.fregs[7]), + FX(f.fregs[8]), + FX(f.fregs[9]), + FX(f.fregs[10]), + FX(f.fregs[11]), + FX(f.fregs[12]), + FX(f.fregs[13]), + FX(f.fregs[14]), + FX(f.fregs[15]), + FX(f.fregs[16]), + FX(f.fregs[17]), + FX(f.fregs[18]), + FX(f.fregs[19]), + FX(f.fregs[20]), + FX(f.fregs[21]), + FX(f.fregs[22]), + FX(f.fregs[23]), + FX(f.fregs[24]), + FX(f.fregs[25]), + FX(f.fregs[26]), + FX(f.fregs[27]), + FX(f.fregs[28]), + FX(f.fregs[29]), + FX(f.fregs[30]), + FX(f.fregs[31]), + + X(y), + X(psr), + X(wim), + X(tbr), + X(pc), + X(npc), + FX(fsr), /* fpsr */ + -1, /* cpsr */ +}; +#endif /* SPARC */ + +#ifdef rs6000 + +static int regmap[] = +{ + X(iregs[0]), /* r0 */ + X(iregs[1]), + X(iregs[2]), + X(iregs[3]), + X(iregs[4]), + X(iregs[5]), + X(iregs[6]), + X(iregs[7]), + X(iregs[8]), + X(iregs[9]), + X(iregs[10]), + X(iregs[11]), + X(iregs[12]), + X(iregs[13]), + X(iregs[14]), + X(iregs[15]), + X(iregs[16]), + X(iregs[17]), + X(iregs[18]), + X(iregs[19]), + X(iregs[20]), + X(iregs[21]), + X(iregs[22]), + X(iregs[23]), + X(iregs[24]), + X(iregs[25]), + X(iregs[26]), + X(iregs[27]), + X(iregs[28]), + X(iregs[29]), + X(iregs[30]), + X(iregs[31]), + + X(fregs[0]), /* f0 */ + X(fregs[1]), + X(fregs[2]), + X(fregs[3]), + X(fregs[4]), + X(fregs[5]), + X(fregs[6]), + X(fregs[7]), + X(fregs[8]), + X(fregs[9]), + X(fregs[10]), + X(fregs[11]), + X(fregs[12]), + X(fregs[13]), + X(fregs[14]), + X(fregs[15]), + X(fregs[16]), + X(fregs[17]), + X(fregs[18]), + X(fregs[19]), + X(fregs[20]), + X(fregs[21]), + X(fregs[22]), + X(fregs[23]), + X(fregs[24]), + X(fregs[25]), + X(fregs[26]), + X(fregs[27]), + X(fregs[28]), + X(fregs[29]), + X(fregs[30]), + X(fregs[31]), + + X(srr0), /* IAR (PC) */ + X(srr1), /* MSR (PS) */ + X(cr), /* CR */ + X(lr), /* LR */ + X(ctr), /* CTR */ + X(xer), /* XER */ + X(mq) /* MQ */ +}; + +#endif /* rs6000 */ + +#ifdef SPARC + +/* This routine handles some oddball cases for Sparc registers and LynxOS. + In partucular, it causes refs to G0, g5->7, and all fp regs to return zero. + It also handles knows where to find the I & L regs on the stack. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + int whatregs = 0; + +#define WHATREGS_FLOAT 1 +#define WHATREGS_GEN 2 +#define WHATREGS_STACK 4 + + if (regno == -1) + whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK; + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + whatregs = WHATREGS_STACK; + else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + whatregs = WHATREGS_FLOAT; + else + whatregs = WHATREGS_GEN; + + if (whatregs & WHATREGS_GEN) + { + struct econtext ec; /* general regs */ + char buf[MAX_REGISTER_RAW_SIZE]; + int retval; + int i; + + errno = 0; + retval = ptrace (PTRACE_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &ec, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_GETREGS)"); + + memset (buf, 0, REGISTER_RAW_SIZE (G0_REGNUM)); + supply_register (G0_REGNUM, buf); + supply_register (TBR_REGNUM, (char *)&ec.tbr); + + memcpy (®isters[REGISTER_BYTE (G1_REGNUM)], &ec.g1, + 4 * REGISTER_RAW_SIZE (G1_REGNUM)); + for (i = G1_REGNUM; i <= G1_REGNUM + 3; i++) + register_valid[i] = 1; + + supply_register (PS_REGNUM, (char *)&ec.psr); + supply_register (Y_REGNUM, (char *)&ec.y); + supply_register (PC_REGNUM, (char *)&ec.pc); + supply_register (NPC_REGNUM, (char *)&ec.npc); + supply_register (WIM_REGNUM, (char *)&ec.wim); + + memcpy (®isters[REGISTER_BYTE (O0_REGNUM)], ec.o, + 8 * REGISTER_RAW_SIZE (O0_REGNUM)); + for (i = O0_REGNUM; i <= O0_REGNUM + 7; i++) + register_valid[i] = 1; + } + + if (whatregs & WHATREGS_STACK) + { + CORE_ADDR sp; + int i; + + sp = read_register (SP_REGNUM); + + target_xfer_memory (sp + FRAME_SAVED_I0, + ®isters[REGISTER_BYTE(I0_REGNUM)], + 8 * REGISTER_RAW_SIZE (I0_REGNUM), 0); + for (i = I0_REGNUM; i <= I7_REGNUM; i++) + register_valid[i] = 1; + + target_xfer_memory (sp + FRAME_SAVED_L0, + ®isters[REGISTER_BYTE(L0_REGNUM)], + 8 * REGISTER_RAW_SIZE (L0_REGNUM), 0); + for (i = L0_REGNUM; i <= L0_REGNUM + 7; i++) + register_valid[i] = 1; + } + + if (whatregs & WHATREGS_FLOAT) + { + struct fcontext fc; /* fp regs */ + int retval; + int i; + + errno = 0; + retval = ptrace (PTRACE_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_GETFPREGS)"); + + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], fc.f.fregs, + 32 * REGISTER_RAW_SIZE (FP0_REGNUM)); + for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++) + register_valid[i] = 1; + + supply_register (FPS_REGNUM, (char *)&fc.fsr); + } +} + +/* This routine handles storing of the I & L regs for the Sparc. The trick + here is that they actually live on the stack. The really tricky part is + that when changing the stack pointer, the I & L regs must be written to + where the new SP points, otherwise the regs will be incorrect when the + process is started up again. We assume that the I & L regs are valid at + this point. */ + +void +store_inferior_registers (regno) + int regno; +{ + int whatregs = 0; + + if (regno == -1) + whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK; + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + whatregs = WHATREGS_STACK; + else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + whatregs = WHATREGS_FLOAT; + else if (regno == SP_REGNUM) + whatregs = WHATREGS_STACK | WHATREGS_GEN; + else + whatregs = WHATREGS_GEN; + + if (whatregs & WHATREGS_GEN) + { + struct econtext ec; /* general regs */ + int retval; + + ec.tbr = read_register (TBR_REGNUM); + memcpy (&ec.g1, ®isters[REGISTER_BYTE (G1_REGNUM)], + 4 * REGISTER_RAW_SIZE (G1_REGNUM)); + + ec.psr = read_register (PS_REGNUM); + ec.y = read_register (Y_REGNUM); + ec.pc = read_register (PC_REGNUM); + ec.npc = read_register (NPC_REGNUM); + ec.wim = read_register (WIM_REGNUM); + + memcpy (ec.o, ®isters[REGISTER_BYTE (O0_REGNUM)], + 8 * REGISTER_RAW_SIZE (O0_REGNUM)); + + errno = 0; + retval = ptrace (PTRACE_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &ec, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_SETREGS)"); + } + + if (whatregs & WHATREGS_STACK) + { + int regoffset; + CORE_ADDR sp; + + sp = read_register (SP_REGNUM); + + if (regno == -1 || regno == SP_REGNUM) + { + if (!register_valid[L0_REGNUM+5]) + abort(); + target_xfer_memory (sp + FRAME_SAVED_I0, + ®isters[REGISTER_BYTE (I0_REGNUM)], + 8 * REGISTER_RAW_SIZE (I0_REGNUM), 1); + + target_xfer_memory (sp + FRAME_SAVED_L0, + ®isters[REGISTER_BYTE (L0_REGNUM)], + 8 * REGISTER_RAW_SIZE (L0_REGNUM), 1); + } + else if (regno >= L0_REGNUM && regno <= I7_REGNUM) + { + if (!register_valid[regno]) + abort(); + if (regno >= L0_REGNUM && regno <= L0_REGNUM + 7) + regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM) + + FRAME_SAVED_L0; + else + regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (I0_REGNUM) + + FRAME_SAVED_I0; + target_xfer_memory (sp + regoffset, ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno), 1); + } + } + + if (whatregs & WHATREGS_FLOAT) + { + struct fcontext fc; /* fp regs */ + int retval; + +/* We read fcontext first so that we can get good values for fq_t... */ + errno = 0; + retval = ptrace (PTRACE_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_GETFPREGS)"); + + memcpy (fc.f.fregs, ®isters[REGISTER_BYTE (FP0_REGNUM)], + 32 * REGISTER_RAW_SIZE (FP0_REGNUM)); + + fc.fsr = read_register (FPS_REGNUM); + + errno = 0; + retval = ptrace (PTRACE_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_SETFPREGS)"); + } +} +#endif /* SPARC */ + +#if defined (I386) || defined (M68K) || defined (rs6000) + +/* Return the offset relative to the start of the per-thread data to the + saved context block. */ + +static unsigned long +registers_addr(pid) + int pid; +{ + CORE_ADDR stblock; + int ecpoff = offsetof(st_t, ecp); + CORE_ADDR ecp; + + errno = 0; + stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, pid, (PTRACE_ARG3_TYPE)0, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_THREADUSER)"); + + ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, pid, (PTRACE_ARG3_TYPE)ecpoff, + 0); + if (errno) + perror_with_name ("ptrace(PTRACE_PEEKTHREAD)"); + + return ecp - stblock; +} + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + int reglo, reghi; + int i; + unsigned long ecp; + + if (regno == -1) + { + reglo = 0; + reghi = NUM_REGS - 1; + } + else + reglo = reghi = regno; + + ecp = registers_addr (inferior_pid); + + for (regno = reglo; regno <= reghi; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + int ptrace_fun = PTRACE_PEEKTHREAD; + +#ifdef M68K + ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD; +#endif + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + unsigned int reg; + + errno = 0; + reg = ptrace (ptrace_fun, inferior_pid, + (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), 0); + if (errno) + perror_with_name ("ptrace(PTRACE_PEEKUSP)"); + + *(int *)&buf[i] = reg; + } + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +void +store_inferior_registers (regno) + int regno; +{ + int reglo, reghi; + int i; + unsigned long ecp; + + if (regno == -1) + { + reglo = 0; + reghi = NUM_REGS - 1; + } + else + reglo = reghi = regno; + + ecp = registers_addr (inferior_pid); + + for (regno = reglo; regno <= reghi; regno++) + { + int ptrace_fun = PTRACE_POKEUSER; + + if (CANNOT_STORE_REGISTER (regno)) + continue; + +#ifdef M68K + ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER; +#endif + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + unsigned int reg; + + reg = *(unsigned int *)®isters[REGISTER_BYTE (regno) + i]; + + errno = 0; + ptrace (ptrace_fun, inferior_pid, + (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), reg); + if (errno) + perror_with_name ("ptrace(PTRACE_POKEUSP)"); + } + } +} +#endif /* defined (I386) || defined (M68K) || defined (rs6000) */ + +/* Wait for child to do something. Return pid of child, or -1 in case + of error; store status through argument pointer OURSTATUS. */ + +int +child_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + int save_errno; + int thread; + union wait status; + + while (1) + { + int sig; + + set_sigint_trap(); /* Causes SIGINT to be passed on to the + attached process. */ + pid = wait (&status); + + save_errno = errno; + + clear_sigint_trap(); + + if (pid == -1) + { + if (save_errno == EINTR) + continue; + fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n", + safe_strerror (save_errno)); + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return -1; + } + + if (pid != PIDGET (inferior_pid)) /* Some other process?!? */ + continue; + + thread = status.w_tid; /* Get thread id from status */ + + /* Initial thread value can only be acquired via wait, so we have to + resort to this hack. */ + + if (TIDGET (inferior_pid) == 0 && thread != 0) + { + inferior_pid = BUILDPID (inferior_pid, thread); + add_thread (inferior_pid); + } + + pid = BUILDPID (pid, thread); + + /* We've become a single threaded process again. */ + if (thread == 0) + inferior_pid = pid; + + /* Check for thread creation. */ + if (WIFSTOPPED(status) + && WSTOPSIG(status) == SIGTRAP + && !in_thread_list (pid)) + { + int realsig; + + realsig = ptrace (PTRACE_GETTRACESIG, pid, (PTRACE_ARG3_TYPE)0, 0); + + if (realsig == SIGNEWTHREAD) + { + /* It's a new thread notification. Nothing to do here since + the machine independent code in wait_for_inferior will + add the thread to the thread list and restart the thread + when pid != inferior_pid and pid is not in the thread + list. We don't even want to much with realsig -- the + code in wait_for_inferior expects SIGTRAP. */ + ; + } + else + error ("Signal for unknown thread was not SIGNEWTHREAD"); + } + + /* Check for thread termination. */ + else if (WIFSTOPPED(status) + && WSTOPSIG(status) == SIGTRAP + && in_thread_list (pid)) + { + int realsig; + + realsig = ptrace (PTRACE_GETTRACESIG, pid, (PTRACE_ARG3_TYPE)0, 0); + + if (realsig == SIGTHREADEXIT) + { + ptrace (PTRACE_CONT, PIDGET (pid), (PTRACE_ARG3_TYPE)0, 0); + continue; + } + } + +#ifdef SPARC + /* SPARC Lynx uses an byte reversed wait status; we must use the + host macros to access it. These lines just a copy of + store_waitstatus. We can't use CHILD_SPECIAL_WAITSTATUS + because target.c can't include the Lynx . */ + if (WIFEXITED (status)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (status); + } + else if (!WIFSTOPPED (status)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = + target_signal_from_host (WTERMSIG (status)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = + target_signal_from_host (WSTOPSIG (status)); + } +#else + store_waitstatus (ourstatus, status.w_status); +#endif + + return pid; + } +} + +/* Return nonzero if the given thread is still alive. */ +int +child_thread_alive (pid) + int pid; +{ + /* Arggh. Apparently pthread_kill only works for threads within + the process that calls pthread_kill. + + We want to avoid the lynx signal extensions as they simply don't + map well to the generic gdb interface we want to keep. + + All we want to do is determine if a particular thread is alive; + it appears as if we can just make a harmless thread specific + ptrace call to do that. */ + return (ptrace (PTRACE_THREADUSER, pid, 0, 0) != -1); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (pid, step, signal) + int pid; + int step; + enum target_signal signal; +{ + int func; + + errno = 0; + + /* If pid == -1, then we want to step/continue all threads, else + we only want to step/continue a single thread. */ + if (pid == -1) + { + pid = inferior_pid; + func = step ? PTRACE_SINGLESTEP : PTRACE_CONT; + } + else + func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT_ONE; + + + /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) + + If this system does not support PT_STEP, a higher level function will + have called single_step() to transmute the step request into a + continue request (by setting breakpoints on all possible successor + instructions), so we don't have to worry about that here. */ + + ptrace (func, pid, (PTRACE_ARG3_TYPE) 1, target_signal_to_host (signal)); + + if (errno) + perror_with_name ("ptrace"); +} + +/* Convert a Lynx process ID to a string. Returns the string in a static + buffer. */ + +char * +lynx_pid_to_str (pid) + int pid; +{ + static char buf[40]; + + sprintf (buf, "process %d thread %d", PIDGET (pid), TIDGET (pid)); + + return buf; +} + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + struct st_entry s; + unsigned int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + if (regmap[regno] != -1) + supply_register (regno, core_reg_sect + offsetof (st_t, ec) + + regmap[regno]); + +#ifdef SPARC +/* Fetching this register causes all of the I & L regs to be read from the + stack and validated. */ + + fetch_inferior_registers (I0_REGNUM); +#endif +} + + +/* Register that we are able to handle lynx core file formats. + FIXME: is this really bfd_target_unknown_flavour? */ + +static struct core_fns lynx_core_fns = +{ + bfd_target_unknown_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_core_lynx () +{ + add_core_fns (&lynx_core_fns); +} diff --git a/contrib/gdb/gdb/m2-exp.tab.c b/contrib/gdb/gdb/m2-exp.tab.c new file mode 100644 index 000000000000..0ad36c3c11cf --- /dev/null +++ b/contrib/gdb/gdb/m2-exp.tab.c @@ -0,0 +1,2095 @@ + +/* A Bison parser, made from ./m2-exp.y with Bison version GNU Bison version 1.24 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define INT 258 +#define HEX 259 +#define ERROR 260 +#define UINT 261 +#define M2_TRUE 262 +#define M2_FALSE 263 +#define CHAR 264 +#define FLOAT 265 +#define STRING 266 +#define NAME 267 +#define BLOCKNAME 268 +#define IDENT 269 +#define VARNAME 270 +#define TYPENAME 271 +#define SIZE 272 +#define CAP 273 +#define ORD 274 +#define HIGH 275 +#define ABS 276 +#define MIN_FUNC 277 +#define MAX_FUNC 278 +#define FLOAT_FUNC 279 +#define VAL 280 +#define CHR 281 +#define ODD 282 +#define TRUNC 283 +#define INC 284 +#define DEC 285 +#define INCL 286 +#define EXCL 287 +#define COLONCOLON 288 +#define INTERNAL_VAR 289 +#define ABOVE_COMMA 290 +#define ASSIGN 291 +#define LEQ 292 +#define GEQ 293 +#define NOTEQUAL 294 +#define IN 295 +#define OROR 296 +#define LOGICAL_AND 297 +#define DIV 298 +#define MOD 299 +#define UNARY 300 +#define DOT 301 +#define NOT 302 +#define QID 303 + +#line 40 "./m2-exp.y" + + +#include "defs.h" +#include "gdb_string.h" +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "m2-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 */ + +/* 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 m2_maxdepth +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yylval m2_lval +#define yychar m2_char +#define yydebug m2_debug +#define yypact m2_pact +#define yyr1 m2_r1 +#define yyr2 m2_r2 +#define yydef m2_def +#define yychk m2_chk +#define yypgo m2_pgo +#define yyact m2_act +#define yyexca m2_exca +#define yyerrflag m2_errflag +#define yynerrs m2_nerrs +#define yyps m2_ps +#define yypv m2_pv +#define yys m2_s +#define yy_yys m2_yys +#define yystate m2_state +#define yytmp m2_tmp +#define yyv m2_v +#define yy_yyv m2_yyv +#define yyval m2_val +#define yylloc m2_lloc +#define yyreds m2_reds /* With YYDEBUG defined */ +#define yytoks m2_toks /* With YYDEBUG defined */ +#define yylhs m2_yylhs +#define yylen m2_yylen +#define yydefred m2_yydefred +#define yydgoto m2_yydgoto +#define yysindex m2_yysindex +#define yyrindex m2_yyrindex +#define yygindex m2_yygindex +#define yytable m2_yytable +#define yycheck m2_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#if 0 +static char * +make_qualname PARAMS ((char *, char *)); +#endif + +static int +parse_number PARAMS ((int)); + +/* The sign of the number being parsed. */ +static int number_sign = 1; + +/* The block that the module specified by the qualifer on an identifer is + contained in, */ +#if 0 +static struct block *modblock=0; +#endif + + +#line 135 "./m2-exp.y" +typedef union + { + LONGEST lval; + unsigned LONGEST ulval; + DOUBLEST dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } YYSTYPE; + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 181 +#define YYFLAG -32768 +#define YYNTBASE 68 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 303 ? yytranslate[x] : 82) + +static const char 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, 44, 2, 2, 48, 2, 60, + 64, 52, 50, 35, 51, 2, 53, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, + 42, 39, 2, 49, 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, 67, 57, 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, 65, 2, 66, 62, 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, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, + 37, 40, 41, 43, 45, 46, 47, 54, 55, 56, + 58, 61, 63 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 2, 4, 6, 9, 10, 14, 17, 20, 22, + 24, 29, 34, 39, 44, 49, 54, 59, 66, 71, + 76, 81, 84, 89, 96, 101, 108, 112, 114, 118, + 125, 132, 136, 141, 142, 148, 149, 155, 156, 158, + 162, 164, 168, 173, 178, 182, 186, 190, 194, 198, + 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, + 242, 246, 250, 252, 254, 256, 258, 260, 262, 264, + 269, 271, 273, 275, 279, 281, 283, 287, 289 +}; + +static const short yyrhs[] = { 70, + 0, 69, 0, 81, 0, 70, 57, 0, 0, 51, + 71, 70, 0, 50, 70, 0, 72, 70, 0, 61, + 0, 62, 0, 18, 60, 70, 64, 0, 19, 60, + 70, 64, 0, 21, 60, 70, 64, 0, 20, 60, + 70, 64, 0, 22, 60, 81, 64, 0, 23, 60, + 81, 64, 0, 24, 60, 70, 64, 0, 25, 60, + 81, 35, 70, 64, 0, 26, 60, 70, 64, 0, + 27, 60, 70, 64, 0, 28, 60, 70, 64, 0, + 17, 70, 0, 29, 60, 70, 64, 0, 29, 60, + 70, 35, 70, 64, 0, 30, 60, 70, 64, 0, + 30, 60, 70, 35, 70, 64, 0, 70, 58, 12, + 0, 73, 0, 70, 45, 73, 0, 31, 60, 70, + 35, 70, 64, 0, 32, 60, 70, 35, 70, 64, + 0, 65, 76, 66, 0, 81, 65, 76, 66, 0, + 0, 70, 59, 74, 77, 67, 0, 0, 70, 60, + 75, 76, 64, 0, 0, 70, 0, 76, 35, 70, + 0, 70, 0, 77, 35, 70, 0, 65, 81, 66, + 70, 0, 81, 60, 70, 64, 0, 60, 70, 64, + 0, 70, 49, 70, 0, 70, 52, 70, 0, 70, + 53, 70, 0, 70, 54, 70, 0, 70, 55, 70, + 0, 70, 50, 70, 0, 70, 51, 70, 0, 70, + 42, 70, 0, 70, 43, 70, 0, 70, 44, 70, + 0, 70, 40, 70, 0, 70, 41, 70, 0, 70, + 38, 70, 0, 70, 39, 70, 0, 70, 47, 70, + 0, 70, 46, 70, 0, 70, 37, 70, 0, 7, + 0, 8, 0, 3, 0, 6, 0, 9, 0, 10, + 0, 80, 0, 17, 60, 81, 64, 0, 11, 0, + 79, 0, 13, 0, 78, 33, 13, 0, 79, 0, + 34, 0, 78, 33, 12, 0, 12, 0, 16, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 204, 205, 208, 217, 220, 222, 227, 231, 235, 236, + 239, 243, 247, 251, 255, 261, 267, 271, 277, 281, + 285, 289, 294, 298, 304, 308, 314, 320, 323, 327, + 331, 334, 336, 342, 347, 353, 357, 363, 366, 370, + 375, 380, 385, 391, 397, 405, 409, 413, 417, 421, + 425, 429, 433, 437, 439, 443, 447, 451, 455, 459, + 463, 467, 474, 480, 486, 493, 502, 510, 517, 520, + 527, 534, 538, 547, 559, 567, 571, 587, 638 +}; + +static const char * const yytname[] = { "$","error","$undefined.","INT","HEX", +"ERROR","UINT","M2_TRUE","M2_FALSE","CHAR","FLOAT","STRING","NAME","BLOCKNAME", +"IDENT","VARNAME","TYPENAME","SIZE","CAP","ORD","HIGH","ABS","MIN_FUNC","MAX_FUNC", +"FLOAT_FUNC","VAL","CHR","ODD","TRUNC","INC","DEC","INCL","EXCL","COLONCOLON", +"INTERNAL_VAR","','","ABOVE_COMMA","ASSIGN","'<'","'>'","LEQ","GEQ","'='","NOTEQUAL", +"'#'","IN","OROR","LOGICAL_AND","'&'","'@'","'+'","'-'","'*'","'/'","DIV","MOD", +"UNARY","'^'","DOT","'['","'('","NOT","'~'","QID","')'","'{'","'}'","']'","start", +"type_exp","exp","@1","not_exp","set","@2","@3","arglist","non_empty_arglist", +"block","fblock","variable","type","" +}; +#endif + +static const short yyr1[] = { 0, + 68, 68, 69, 70, 71, 70, 70, 70, 72, 72, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 73, 73, 74, 70, 75, 70, 76, 76, 76, + 77, 77, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 78, 79, 79, 80, 80, 80, 80, 81 +}; + +static const short yyr2[] = { 0, + 1, 1, 1, 2, 0, 3, 2, 2, 1, 1, + 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, + 4, 2, 4, 6, 4, 6, 3, 1, 3, 6, + 6, 3, 4, 0, 5, 0, 5, 0, 1, 3, + 1, 3, 4, 4, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, 1, 4, + 1, 1, 1, 3, 1, 1, 3, 1, 1 +}; + +static const short yydefact[] = { 0, + 65, 66, 63, 64, 67, 68, 71, 78, 73, 79, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 76, 0, 5, 0, + 9, 10, 38, 2, 1, 0, 28, 0, 75, 69, + 3, 0, 22, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 34, 36, 8, 0, 0, + 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 45, 0, + 32, 0, 62, 58, 59, 56, 57, 53, 54, 55, + 38, 29, 0, 61, 60, 46, 51, 52, 47, 48, + 49, 50, 27, 0, 38, 77, 74, 0, 0, 70, + 11, 12, 14, 13, 15, 16, 17, 0, 19, 20, + 21, 0, 23, 0, 25, 0, 0, 40, 43, 41, + 0, 0, 44, 33, 0, 0, 0, 0, 0, 0, + 35, 37, 18, 24, 26, 30, 31, 42, 0, 0, + 0 +}; + +static const short yydefgoto[] = { 179, + 34, 63, 61, 36, 37, 134, 135, 64, 161, 38, + 39, 40, 44 +}; + +static const short yypact[] = { 155, +-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 215, -27, -22, -20, -19, 14, 24, 26, 27, 28, + 29, 31, 32, 33, 35, 36,-32768, 155,-32768, 155, +-32768,-32768, 155,-32768, 742, 155,-32768, -6, -4,-32768, + -34, 155, 5, -34, 155, 155, 155, 155, 44, 44, + 155, 44, 155, 155, 155, 155, 155, 155, 155, 5, + 155, 272, 742, -31, -41, 155, 155, 155, 155, 155, + 155, 155, 155, -15, 155, 155, 155, 155, 155, 155, + 155, 155, 155,-32768, 85,-32768,-32768, 5, -5, 155, + 155, -21, 300, 328, 356, 384, 34, 39, 412, 64, + 440, 468, 496, 78, 244, 692, 718, 5,-32768, 155, +-32768, 155, 766, -37, -37, -37, -37, -37, -37, -37, + 155,-32768, 40, 141, 201, 777, 786, 786, 5, 5, + 5, 5,-32768, 155, 155,-32768,-32768, 524, -29,-32768, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 155,-32768,-32768, +-32768, 155,-32768, 155,-32768, 155, 155, 742, 5, 742, + -33, -32,-32768,-32768, 552, 580, 608, 636, 664, 155, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 742, 100, 106, +-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, 0,-32768,-32768, 37,-32768,-32768, -86,-32768,-32768, +-32768,-32768, 52 +}; + + +#define YYLAST 846 + + +static const short yytable[] = { 35, + 10, 170, 110, 110, 139, 110, 136, 137, 75, 76, + 43, 77, 78, 79, 80, 81, 82, 83, 90, 84, + 85, 86, 87, 91, 112, 90, 89, 60, -72, 62, + 91, 172, 45, 171, 111, 88, 164, 46, 90, 47, + 48, 62, 140, 91, 93, 94, 95, 96, 162, 121, + 99, 41, 101, 102, 103, 104, 105, 106, 107, 10, + 108, 84, 85, 86, 87, 113, 114, 115, 116, 117, + 118, 119, 120, 49, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 50, 65, 51, 52, 53, 54, 138, + 55, 56, 57, 92, 58, 59, 133, 145, 148, 180, + 97, 98, 146, 100, 91, 181, 0, 0, 0, 158, + 122, 159, 152, 0, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 123, 77, 78, 79, 80, + 81, 82, 83, 160, 84, 85, 86, 87, 0, 0, + 0, 153, 0, 0, 0, 0, 0, 165, 0, 0, + 0, 166, 0, 167, 0, 168, 169, 1, 0, 0, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 178, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 76, 27, 77, + 78, 79, 80, 81, 82, 83, 0, 84, 85, 86, + 87, 0, 0, 0, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 31, 32, 1, 0, 33, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 27, 77, + 78, 79, 80, 81, 82, 83, 0, 84, 85, 86, + 87, 0, 0, 0, 28, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 31, 32, 0, 154, 33, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 0, 77, 78, 79, 80, 81, 82, 83, 0, + 84, 85, 86, 87, 0, 0, 0, 155, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, + 77, 78, 79, 80, 81, 82, 83, 0, 84, 85, + 86, 87, 0, 0, 0, 109, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 0, 77, 78, + 79, 80, 81, 82, 83, 0, 84, 85, 86, 87, + 0, 0, 0, 141, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 0, 77, 78, 79, 80, + 81, 82, 83, 0, 84, 85, 86, 87, 0, 0, + 0, 142, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 0, 77, 78, 79, 80, 81, 82, + 83, 0, 84, 85, 86, 87, 0, 0, 0, 143, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 0, 77, 78, 79, 80, 81, 82, 83, 0, + 84, 85, 86, 87, 0, 0, 0, 144, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, + 77, 78, 79, 80, 81, 82, 83, 0, 84, 85, + 86, 87, 0, 0, 0, 147, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 0, 77, 78, + 79, 80, 81, 82, 83, 0, 84, 85, 86, 87, + 0, 0, 0, 149, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 0, 77, 78, 79, 80, + 81, 82, 83, 0, 84, 85, 86, 87, 0, 0, + 0, 150, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 0, 77, 78, 79, 80, 81, 82, + 83, 0, 84, 85, 86, 87, 0, 0, 0, 151, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 0, 77, 78, 79, 80, 81, 82, 83, 0, + 84, 85, 86, 87, 0, 0, 0, 163, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, + 77, 78, 79, 80, 81, 82, 83, 0, 84, 85, + 86, 87, 0, 0, 0, 173, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 0, 77, 78, + 79, 80, 81, 82, 83, 0, 84, 85, 86, 87, + 0, 0, 0, 174, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 0, 77, 78, 79, 80, + 81, 82, 83, 0, 84, 85, 86, 87, 0, 0, + 0, 175, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 0, 77, 78, 79, 80, 81, 82, + 83, 0, 84, 85, 86, 87, 0, 0, 0, 176, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 0, 77, 78, 79, 80, 81, 82, 83, 0, + 84, 85, 86, 87, 0, 0, 156, 177, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, + 77, 78, 79, 80, 81, 82, 83, 0, 84, 85, + 86, 87, 157, 0, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 0, 77, 78, 79, 80, + 81, 82, 83, 0, 84, 85, 86, 87, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, + 77, 78, 79, 80, 81, 82, 83, 0, 84, 85, + 86, 87,-32768, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 0, 77, 78, 79, 80, 81, 82, + 83, 0, 84, 85, 86, 87, 78, 79, 80, 81, + 82, 83, 0, 84, 85, 86, 87, 80, 81, 82, + 83, 0, 84, 85, 86, 87 +}; + +static const short yycheck[] = { 0, + 16, 35, 35, 35, 91, 35, 12, 13, 46, 47, + 11, 49, 50, 51, 52, 53, 54, 55, 60, 57, + 58, 59, 60, 65, 66, 60, 33, 28, 33, 30, + 65, 64, 60, 67, 66, 36, 66, 60, 60, 60, + 60, 42, 64, 65, 45, 46, 47, 48, 135, 65, + 51, 0, 53, 54, 55, 56, 57, 58, 59, 16, + 61, 57, 58, 59, 60, 66, 67, 68, 69, 70, + 71, 72, 73, 60, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 60, 33, 60, 60, 60, 60, 90, + 60, 60, 60, 42, 60, 60, 12, 64, 35, 0, + 49, 50, 64, 52, 65, 0, -1, -1, -1, 110, + 74, 112, 35, -1, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 74, 49, 50, 51, 52, + 53, 54, 55, 134, 57, 58, 59, 60, -1, -1, + -1, 64, -1, -1, -1, -1, -1, 148, -1, -1, + -1, 152, -1, 154, -1, 156, 157, 3, -1, -1, + 6, 7, 8, 9, 10, 11, 12, 13, -1, 170, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 47, 34, 49, + 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, + 60, -1, -1, -1, 50, 51, -1, -1, -1, -1, + -1, -1, -1, -1, 60, 61, 62, 3, -1, 65, + 6, 7, 8, 9, 10, 11, 12, 13, -1, -1, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, -1, 34, 49, + 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, + 60, -1, -1, -1, 50, 51, -1, -1, -1, -1, + -1, -1, -1, -1, 60, 61, 62, -1, 35, 65, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, -1, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, -1, -1, -1, 64, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, -1, + 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, + 59, 60, -1, -1, -1, 64, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, -1, 49, 50, + 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, + -1, -1, -1, 64, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, -1, 49, 50, 51, 52, + 53, 54, 55, -1, 57, 58, 59, 60, -1, -1, + -1, 64, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, -1, 49, 50, 51, 52, 53, 54, + 55, -1, 57, 58, 59, 60, -1, -1, -1, 64, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, -1, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, -1, -1, -1, 64, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, -1, + 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, + 59, 60, -1, -1, -1, 64, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, -1, 49, 50, + 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, + -1, -1, -1, 64, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, -1, 49, 50, 51, 52, + 53, 54, 55, -1, 57, 58, 59, 60, -1, -1, + -1, 64, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, -1, 49, 50, 51, 52, 53, 54, + 55, -1, 57, 58, 59, 60, -1, -1, -1, 64, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, -1, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, -1, -1, -1, 64, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, -1, + 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, + 59, 60, -1, -1, -1, 64, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, -1, 49, 50, + 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, + -1, -1, -1, 64, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, -1, 49, 50, 51, 52, + 53, 54, 55, -1, 57, 58, 59, 60, -1, -1, + -1, 64, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, -1, 49, 50, 51, 52, 53, 54, + 55, -1, 57, 58, 59, 60, -1, -1, -1, 64, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, -1, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, -1, -1, 35, 64, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, -1, + 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, + 59, 60, 35, -1, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, -1, 49, 50, 51, 52, + 53, 54, 55, -1, 57, 58, 59, 60, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, -1, + 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, + 59, 60, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, -1, 49, 50, 51, 52, 53, 54, + 55, -1, 57, 58, 59, 60, 50, 51, 52, 53, + 54, 55, -1, 57, 58, 59, 60, 52, 53, 54, + 55, -1, 57, 58, 59, 60 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/unsupported/share/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* 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); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (from, to, count) + char *from; + char *to; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *from, char *to, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 192 "/usr/unsupported/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#else +#define YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#endif + +int +yyparse(YYPARSE_PARAM) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to xreallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + 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 - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* 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; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +#line 209 "./m2-exp.y" +{ write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type(yyvsp[0].tval); + write_exp_elt_opcode(OP_TYPE); + ; + break;} +case 4: +#line 218 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_IND); ; + break;} +case 5: +#line 221 "./m2-exp.y" +{ number_sign = -1; ; + break;} +case 6: +#line 223 "./m2-exp.y" +{ number_sign = 1; + write_exp_elt_opcode (UNOP_NEG); ; + break;} +case 7: +#line 228 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PLUS); ; + break;} +case 8: +#line 232 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); ; + break;} +case 11: +#line 240 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CAP); ; + break;} +case 12: +#line 244 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ORD); ; + break;} +case 13: +#line 248 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ABS); ; + break;} +case 14: +#line 252 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_HIGH); ; + break;} +case 15: +#line 256 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MIN); + write_exp_elt_type (yyvsp[-1].tval); + write_exp_elt_opcode (UNOP_MIN); ; + break;} +case 16: +#line 262 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MAX); + write_exp_elt_type (yyvsp[-1].tval); + write_exp_elt_opcode (UNOP_MIN); ; + break;} +case 17: +#line 268 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_FLOAT); ; + break;} +case 18: +#line 272 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_VAL); + write_exp_elt_type (yyvsp[-3].tval); + write_exp_elt_opcode (BINOP_VAL); ; + break;} +case 19: +#line 278 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CHR); ; + break;} +case 20: +#line 282 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_ODD); ; + break;} +case 21: +#line 286 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_TRUNC); ; + break;} +case 22: +#line 290 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_SIZEOF); ; + break;} +case 23: +#line 295 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PREINCREMENT); ; + break;} +case 24: +#line 299 "./m2-exp.y" +{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_ADD); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); ; + break;} +case 25: +#line 305 "./m2-exp.y" +{ write_exp_elt_opcode(UNOP_PREDECREMENT);; + break;} +case 26: +#line 309 "./m2-exp.y" +{ write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_SUB); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); ; + break;} +case 27: +#line 315 "./m2-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (STRUCTOP_STRUCT); ; + break;} +case 29: +#line 324 "./m2-exp.y" +{ error("Sets are not implemented.");; + break;} +case 30: +#line 328 "./m2-exp.y" +{ error("Sets are not implemented.");; + break;} +case 31: +#line 332 "./m2-exp.y" +{ error("Sets are not implemented.");; + break;} +case 32: +#line 335 "./m2-exp.y" +{ error("Sets are not implemented.");; + break;} +case 33: +#line 337 "./m2-exp.y" +{ error("Sets are not implemented.");; + break;} +case 34: +#line 346 "./m2-exp.y" +{ start_arglist(); ; + break;} +case 35: +#line 348 "./m2-exp.y" +{ write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); ; + break;} +case 36: +#line 356 "./m2-exp.y" +{ start_arglist (); ; + break;} +case 37: +#line 358 "./m2-exp.y" +{ write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); ; + break;} +case 39: +#line 367 "./m2-exp.y" +{ arglist_len = 1; ; + break;} +case 40: +#line 371 "./m2-exp.y" +{ arglist_len++; ; + break;} +case 41: +#line 376 "./m2-exp.y" +{ arglist_len = 1; ; + break;} +case 42: +#line 381 "./m2-exp.y" +{ arglist_len++; ; + break;} +case 43: +#line 386 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); ; + break;} +case 44: +#line 392 "./m2-exp.y" +{ write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-3].tval); + write_exp_elt_opcode (UNOP_CAST); ; + break;} +case 45: +#line 398 "./m2-exp.y" +{ ; + break;} +case 46: +#line 406 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); ; + break;} +case 47: +#line 410 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); ; + break;} +case 48: +#line 414 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); ; + break;} +case 49: +#line 418 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_INTDIV); ; + break;} +case 50: +#line 422 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_REM); ; + break;} +case 51: +#line 426 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); ; + break;} +case 52: +#line 430 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); ; + break;} +case 53: +#line 434 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); ; + break;} +case 54: +#line 438 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); ; + break;} +case 55: +#line 440 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); ; + break;} +case 56: +#line 444 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); ; + break;} +case 57: +#line 448 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); ; + break;} +case 58: +#line 452 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); ; + break;} +case 59: +#line 456 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); ; + break;} +case 60: +#line 460 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); ; + break;} +case 61: +#line 464 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); ; + break;} +case 62: +#line 468 "./m2-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); ; + break;} +case 63: +#line 475 "./m2-exp.y" +{ write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_BOOL); ; + break;} +case 64: +#line 481 "./m2-exp.y" +{ write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_BOOL); ; + break;} +case 65: +#line 487 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_int); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 66: +#line 494 "./m2-exp.y" +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_card); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_LONG); + ; + break;} +case 67: +#line 503 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_char); + write_exp_elt_longcst ((LONGEST) yyvsp[0].ulval); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 68: +#line 511 "./m2-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_m2_real); + write_exp_elt_dblcst (yyvsp[0].dval); + write_exp_elt_opcode (OP_DOUBLE); ; + break;} +case 70: +#line 521 "./m2-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH (yyvsp[-1].tval)); + write_exp_elt_opcode (OP_LONG); ; + break;} +case 71: +#line 528 "./m2-exp.y" +{ write_exp_elt_opcode (OP_M2_STRING); + write_exp_string (yyvsp[0].sval); + write_exp_elt_opcode (OP_M2_STRING); ; + break;} +case 72: +#line 535 "./m2-exp.y" +{ yyval.bval = SYMBOL_BLOCK_VALUE(yyvsp[0].sym); ; + break;} +case 73: +#line 539 "./m2-exp.y" +{ struct symbol *sym + = lookup_symbol (copy_name (yyvsp[0].sval), expression_context_block, + VAR_NAMESPACE, 0, NULL); + yyval.sym = sym;; + break;} +case 74: +#line 548 "./m2-exp.y" +{ struct symbol *tem + = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + yyval.sym = tem; + ; + break;} +case 75: +#line 560 "./m2-exp.y" +{ write_exp_elt_opcode(OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym (yyvsp[0].sym); + write_exp_elt_opcode (OP_VAR_VALUE); ; + break;} +case 77: +#line 572 "./m2-exp.y" +{ struct symbol *sym; + sym = lookup_symbol (copy_name (yyvsp[0].sval), yyvsp[-2].bval, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name (yyvsp[0].sval)); + + 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); ; + break;} +case 78: +#line 588 "./m2-exp.y" +{ struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name (yyvsp[0].sval), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this, + NULL); + 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 + { + struct minimal_symbol *msymbol; + register char *arg = copy_name (yyvsp[0].sval); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol + (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name (yyvsp[0].sval)); + } + ; + break;} +case 79: +#line 639 "./m2-exp.y" +{ yyval.tval = lookup_typename (copy_name (yyvsp[0].sval), + expression_context_block, 0); ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 487 "/usr/unsupported/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* 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 - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) xmalloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 644 "./m2-exp.y" + + +#if 0 /* FIXME! */ +int +overflow(a,b) + long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a; +} + +int +uoverflow(a,b) + unsigned long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a; +} +#endif /* FIXME */ + +/* 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 (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register LONGEST prevn = 0; + register int c,i,ischar=0; + register int base = input_radix; + register int len = olen; + int unsigned_p = number_sign == 1 ? 1 : 0; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error("Floating point numbers must be base 10."); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error("Invalid digit \'%c\' in number.",p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error("Invalid digit \'%c\' in octal number.",c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if(!unsigned_p && number_sign == 1 && (prevn >= n)) + unsigned_p=1; /* Try something unsigned */ + /* Don't do the range check if n==i and i==0, since that special + case will give an overflow error. */ + if(RANGE_CHECK && n!=i && i) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n) || + ((!unsigned_p && number_sign==-1) && -prevn <= -n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + yylval.ulval = n; + return CHAR; + } + else if ( unsigned_p && number_sign == 1) + { + yylval.ulval = n; + return UINT; + } + else if((unsigned_p && (n<0))) { + range_error("Overflow on numeric constant -- number too large."); + /* But, this can return if range_check == range_warn. */ + } + yylval.lval = n; + return INT; +} + + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, +}; + + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the operators used are + compatible */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + register char quote; + + retry: + + tokstart = lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++) + if(STREQN(tokentab2[i].name, tokstart, 2)) + { + lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error("Unterminated string or character constant."); + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + 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; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + 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; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= '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 = 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; + + /* Lookup special keywords */ + for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++) + if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen)) + return keytab[i].token; + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + if (*tokstart == '$') + { + write_dollar_variable (yylval.sval); + return INTERNAL_VAR; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. 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; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0, NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->aclass) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error("internal: Undefined class in m2lex()"); + + case LOC_LABEL: + case LOC_UNRESOLVED: + error("internal: Unforseen case in m2lex()"); + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if(STREQN(tokstart,"TRUE",4)) + { + yylval.ulval = 1; + return M2_TRUE; + } + else if(STREQN(tokstart,"FALSE",5)) + { + yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +#if 0 /* Unused */ +static char * +make_qualname(mod,ident) + char *mod, *ident; +{ + char *new = xmalloc(strlen(mod)+strlen(ident)+2); + + strcpy(new,mod); + strcat(new,"."); + strcat(new,ident); + return new; +} +#endif /* 0 */ + +void +yyerror (msg) + char *msg; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/m2-exp.y b/contrib/gdb/gdb/m2-exp.y new file mode 100644 index 000000000000..08a11ce2c3c8 --- /dev/null +++ b/contrib/gdb/gdb/m2-exp.y @@ -0,0 +1,1094 @@ +/* YACC grammar for Modula-2 expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1995 + Free Software Foundation, Inc. + Generated from expread.y (now c-exp.y) and contributed by the Department + of Computer Science at the State University of New York at Buffalo, 1991. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Parse a Modula-2 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 "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "m2-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 */ + +/* 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 m2_maxdepth +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yylval m2_lval +#define yychar m2_char +#define yydebug m2_debug +#define yypact m2_pact +#define yyr1 m2_r1 +#define yyr2 m2_r2 +#define yydef m2_def +#define yychk m2_chk +#define yypgo m2_pgo +#define yyact m2_act +#define yyexca m2_exca +#define yyerrflag m2_errflag +#define yynerrs m2_nerrs +#define yyps m2_ps +#define yypv m2_pv +#define yys m2_s +#define yy_yys m2_yys +#define yystate m2_state +#define yytmp m2_tmp +#define yyv m2_v +#define yy_yyv m2_yyv +#define yyval m2_val +#define yylloc m2_lloc +#define yyreds m2_reds /* With YYDEBUG defined */ +#define yytoks m2_toks /* With YYDEBUG defined */ +#define yylhs m2_yylhs +#define yylen m2_yylen +#define yydefred m2_yydefred +#define yydgoto m2_yydgoto +#define yysindex m2_yysindex +#define yyrindex m2_yyrindex +#define yygindex m2_yygindex +#define yytable m2_yytable +#define yycheck m2_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#if 0 +static char * +make_qualname PARAMS ((char *, char *)); +#endif + +static int +parse_number PARAMS ((int)); + +/* The sign of the number being parsed. */ +static int number_sign = 1; + +/* The block that the module specified by the qualifer on an identifer is + contained in, */ +#if 0 +static struct block *modblock=0; +#endif + +%} + +/* 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; + unsigned LONGEST ulval; + DOUBLEST dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%type exp type_exp start set +%type variable +%type type +%type block +%type fblock + +%token INT HEX ERROR +%token UINT M2_TRUE M2_FALSE CHAR +%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 NAME BLOCKNAME IDENT VARNAME +%token TYPENAME + +%token SIZE CAP ORD HIGH ABS MIN_FUNC MAX_FUNC FLOAT_FUNC VAL CHR ODD TRUNC +%token INC DEC INCL EXCL + +/* The GDB scope operator */ +%token COLONCOLON + +%token INTERNAL_VAR + +/* M2 tokens */ +%left ',' +%left ABOVE_COMMA +%nonassoc ASSIGN +%left '<' '>' LEQ GEQ '=' NOTEQUAL '#' IN +%left OROR +%left LOGICAL_AND '&' +%left '@' +%left '+' '-' +%left '*' '/' DIV MOD +%right UNARY +%right '^' DOT '[' '(' +%right NOT '~' +%left COLONCOLON QID +/* This is not an actual token ; it is used for precedence. +%right QID +*/ + + +%% + +start : exp + | type_exp + ; + +type_exp: type + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1); + write_exp_elt_opcode(OP_TYPE); + } + ; + +/* Expressions */ + +exp : exp '^' %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '-' + { number_sign = -1; } + exp %prec UNARY + { number_sign = 1; + write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '+' exp %prec UNARY + { write_exp_elt_opcode(UNOP_PLUS); } + ; + +exp : not_exp exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +not_exp : NOT + | '~' + ; + +exp : CAP '(' exp ')' + { write_exp_elt_opcode (UNOP_CAP); } + ; + +exp : ORD '(' exp ')' + { write_exp_elt_opcode (UNOP_ORD); } + ; + +exp : ABS '(' exp ')' + { write_exp_elt_opcode (UNOP_ABS); } + ; + +exp : HIGH '(' exp ')' + { write_exp_elt_opcode (UNOP_HIGH); } + ; + +exp : MIN_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MIN); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : MAX_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MAX); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : FLOAT_FUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_FLOAT); } + ; + +exp : VAL '(' type ',' exp ')' + { write_exp_elt_opcode (BINOP_VAL); + write_exp_elt_type ($3); + write_exp_elt_opcode (BINOP_VAL); } + ; + +exp : CHR '(' exp ')' + { write_exp_elt_opcode (UNOP_CHR); } + ; + +exp : ODD '(' exp ')' + { write_exp_elt_opcode (UNOP_ODD); } + ; + +exp : TRUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_TRUNC); } + ; + +exp : SIZE exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + + +exp : INC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREINCREMENT); } + ; + +exp : INC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_ADD); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : DEC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREDECREMENT);} + ; + +exp : DEC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_SUB); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : exp DOT NAME + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : set + ; + +exp : exp IN set + { error("Sets are not implemented.");} + ; + +exp : INCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + ; + +exp : EXCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + +set : '{' arglist '}' + { error("Sets are not implemented.");} + | type '{' arglist '}' + { error("Sets are not implemented.");} + ; + + +/* Modula-2 array subscript notation [a,b,c...] */ +exp : exp '[' + /* This function just saves the number of arguments + that follow in the list. It is *not* specific to + function types */ + { start_arglist(); } + non_empty_arglist ']' %prec DOT + { write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec DOT + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +non_empty_arglist + : exp + { arglist_len = 1; } + ; + +non_empty_arglist + : non_empty_arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +/* GDB construct */ +exp : '{' type '}' 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 ($1); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp ')' + { } + ; + +/* Binary operators in order of decreasing precedence. Note that some + of these operators are overloaded! (ie. sets) */ + +/* GDB construct */ +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 DIV exp + { write_exp_elt_opcode (BINOP_INTDIV); } + ; + +exp : exp MOD 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 '=' exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + | exp '#' 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 LOGICAL_AND exp + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + +exp : exp OROR exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +exp : exp ASSIGN exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + + +/* Constants */ + +exp : M2_TRUE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : M2_FALSE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_int); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : UINT + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_card); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHAR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_char); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_m2_real); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : SIZE '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { write_exp_elt_opcode (OP_M2_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_M2_STRING); } + ; + +/* This will be used for extensions later. Like adding modules. */ +block : fblock + { $$ = SYMBOL_BLOCK_VALUE($1); } + ; + +fblock : BLOCKNAME + { struct symbol *sym + = lookup_symbol (copy_name ($1), expression_context_block, + VAR_NAMESPACE, 0, NULL); + $$ = sym;} + ; + + +/* GDB scope operator */ +fblock : block COLONCOLON BLOCKNAME + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = tem; + } + ; + +/* Useful for assigning to PROCEDURE variables */ +variable: fblock + { write_exp_elt_opcode(OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym ($1); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +/* GDB internal ($foo) variable */ +variable: INTERNAL_VAR + ; + +/* GDB scope operator */ +variable: block COLONCOLON NAME + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, 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); } + ; + +/* Base case for variables. */ +variable: NAME + { struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this, + NULL); + 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 + { + struct minimal_symbol *msymbol; + register char *arg = copy_name ($1); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol + (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1)); + } + } + ; + +type + : TYPENAME + { $$ = lookup_typename (copy_name ($1), + expression_context_block, 0); } + + ; + +%% + +#if 0 /* FIXME! */ +int +overflow(a,b) + long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a; +} + +int +uoverflow(a,b) + unsigned long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a; +} +#endif /* FIXME */ + +/* 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 (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register LONGEST prevn = 0; + register int c,i,ischar=0; + register int base = input_radix; + register int len = olen; + int unsigned_p = number_sign == 1 ? 1 : 0; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error("Floating point numbers must be base 10."); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error("Invalid digit \'%c\' in number.",p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error("Invalid digit \'%c\' in octal number.",c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if(!unsigned_p && number_sign == 1 && (prevn >= n)) + unsigned_p=1; /* Try something unsigned */ + /* Don't do the range check if n==i and i==0, since that special + case will give an overflow error. */ + if(RANGE_CHECK && n!=i && i) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n) || + ((!unsigned_p && number_sign==-1) && -prevn <= -n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + yylval.ulval = n; + return CHAR; + } + else if ( unsigned_p && number_sign == 1) + { + yylval.ulval = n; + return UINT; + } + else if((unsigned_p && (n<0))) { + range_error("Overflow on numeric constant -- number too large."); + /* But, this can return if range_check == range_warn. */ + } + yylval.lval = n; + return INT; +} + + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, +}; + + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the operators used are + compatible */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + register char quote; + + retry: + + tokstart = lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++) + if(STREQN(tokentab2[i].name, tokstart, 2)) + { + lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error("Unterminated string or character constant."); + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + 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; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + 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; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= '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 = 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; + + /* Lookup special keywords */ + for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++) + if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen)) + return keytab[i].token; + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + if (*tokstart == '$') + { + write_dollar_variable (yylval.sval); + return INTERNAL_VAR; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. 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; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0, NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->aclass) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error("internal: Undefined class in m2lex()"); + + case LOC_LABEL: + case LOC_UNRESOLVED: + error("internal: Unforseen case in m2lex()"); + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if(STREQN(tokstart,"TRUE",4)) + { + yylval.ulval = 1; + return M2_TRUE; + } + else if(STREQN(tokstart,"FALSE",5)) + { + yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +#if 0 /* Unused */ +static char * +make_qualname(mod,ident) + char *mod, *ident; +{ + char *new = malloc(strlen(mod)+strlen(ident)+2); + + strcpy(new,mod); + strcat(new,"."); + strcat(new,ident); + return new; +} +#endif /* 0 */ + +void +yyerror (msg) + char *msg; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} diff --git a/contrib/gdb/gdb/m2-lang.c b/contrib/gdb/gdb/m2-lang.c new file mode 100644 index 000000000000..75020336c024 --- /dev/null +++ b/contrib/gdb/gdb/m2-lang.c @@ -0,0 +1,465 @@ +/* Modula 2 language support routines for GDB, the GNU debugger. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "m2-lang.h" +#include "c-lang.h" + +/* 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. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. + */ + +static void +emit_char (c, stream, quoter) + register int c; + GDB_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; + } + } +} + +/* FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. */ + +static void +m2_printchar (c, stream) + int c; + GDB_FILE *stream; +{ + fputs_filtered ("'", stream); + emit_char (c, 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. + FIXME: This is a copy of the same function from c-exp.y. It should + be replaced with a true Modula version. */ + +static void +m2_printstr (stream, string, length, force_ellipses) + GDB_FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + register unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + extern int inspect_it; + extern int repeat_count_threshold; + extern int print_max; + + if (length == 0) + { + fputs_filtered ("\"\"", gdb_stdout); + return; + } + + for (i = 0; i < length && things_printed < 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 > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\", ", stream); + else + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + m2_printchar (string[i], stream); + fprintf_filtered (stream, " ", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + in_quotes = 1; + } + emit_char (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* FIXME: This is a copy of c_create_fundamental_type(), before + all the non-C types were stripped from it. Needs to be fixed + by an experienced Modula programmer. */ + +static struct type * +m2_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + register struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "", objfile); + warning ("internal error: no Modula fundamental type %d", typeid); + break; + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "void", objfile); + break; + case FT_BOOLEAN: + type = init_type (TYPE_CODE_BOOL, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "boolean", objfile); + break; + case FT_STRING: + type = init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "char", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "signed char", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned char", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short", objfile); /* FIXME-fnf */ + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", objfile); + break; + case FT_FIXED_DECIMAL: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long long", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "signed long long", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "float", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "double", objfile); + break; + case FT_FLOAT_DECIMAL: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long double", objfile); + break; + case FT_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "complex", objfile); + TYPE_TARGET_TYPE (type) + = m2_create_fundamental_type (objfile, FT_FLOAT); + break; + case FT_DBL_PREC_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "double complex", objfile); + TYPE_TARGET_TYPE (type) + = m2_create_fundamental_type (objfile, FT_DBL_PREC_FLOAT); + break; + case FT_EXT_PREC_COMPLEX: + type = init_type (TYPE_CODE_COMPLEX, + 2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long double complex", objfile); + TYPE_TARGET_TYPE (type) + = m2_create_fundamental_type (objfile, FT_EXT_PREC_FLOAT); + break; + } + return (type); +} + + +/* Table of operators and their precedences for printing expressions. */ + +static const struct op_print m2_op_print_tab[] = { + {"+", BINOP_ADD, PREC_ADD, 0}, + {"+", UNOP_PLUS, PREC_PREFIX, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"DIV", BINOP_INTDIV, PREC_MUL, 0}, + {"MOD", BINOP_REM, PREC_MUL, 0}, + {":=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"OR", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"AND", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"NOT", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"=", BINOP_EQUAL, PREC_EQUAL, 0}, + {"<>", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {"^", UNOP_IND, PREC_PREFIX, 0}, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"CAP", UNOP_CAP, PREC_BUILTIN_FUNCTION, 0}, + {"CHR", UNOP_CHR, PREC_BUILTIN_FUNCTION, 0}, + {"ORD", UNOP_ORD, PREC_BUILTIN_FUNCTION, 0}, + {"FLOAT",UNOP_FLOAT, PREC_BUILTIN_FUNCTION, 0}, + {"HIGH", UNOP_HIGH, PREC_BUILTIN_FUNCTION, 0}, + {"MAX", UNOP_MAX, PREC_BUILTIN_FUNCTION, 0}, + {"MIN", UNOP_MIN, PREC_BUILTIN_FUNCTION, 0}, + {"ODD", UNOP_ODD, PREC_BUILTIN_FUNCTION, 0}, + {"TRUNC", UNOP_TRUNC, PREC_BUILTIN_FUNCTION, 0}, + {NULL, 0, 0, 0} +}; + +/* The built-in types of Modula-2. */ + +struct type *builtin_type_m2_char; +struct type *builtin_type_m2_int; +struct type *builtin_type_m2_card; +struct type *builtin_type_m2_real; +struct type *builtin_type_m2_bool; + +struct type ** const (m2_builtin_types[]) = +{ + &builtin_type_m2_char, + &builtin_type_m2_int, + &builtin_type_m2_card, + &builtin_type_m2_real, + &builtin_type_m2_bool, + 0 +}; + +const struct language_defn m2_language_defn = { + "modula-2", + language_m2, + m2_builtin_types, + range_check_on, + type_check_on, + m2_parse, /* parser */ + m2_error, /* parser error function */ + evaluate_subexp_standard, + m2_printchar, /* Print character constant */ + m2_printstr, /* function to print string constant */ + m2_create_fundamental_type, /* Create fundamental type in this language */ + m2_print_type, /* Print a type using appropriate syntax */ + m2_val_print, /* Print a value using appropriate syntax */ + c_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"%loB", "", "o", "B"}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0%lXH", "0", "X", "H"}, /* Hex format info */ + m2_op_print_tab, /* expression operators for printing */ + 0, /* arrays are first-class (not c-style) */ + 0, /* String lower bound */ + &builtin_type_m2_char, /* Type of string elements */ + LANG_MAGIC +}; + +/* Initialization for Modula-2 */ + +void +_initialize_m2_language () +{ + /* Modula-2 "pervasive" types. NOTE: these can be redefined!!! */ + builtin_type_m2_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "INTEGER", (struct objfile *) NULL); + builtin_type_m2_card = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CARDINAL", (struct objfile *) NULL); + builtin_type_m2_real = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "REAL", (struct objfile *) NULL); + builtin_type_m2_char = + init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "CHAR", (struct objfile *) NULL); + builtin_type_m2_bool = + init_type (TYPE_CODE_BOOL, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, + "BOOLEAN", (struct objfile *) NULL); + + add_language (&m2_language_defn); +} diff --git a/contrib/gdb/gdb/m2-lang.h b/contrib/gdb/gdb/m2-lang.h new file mode 100644 index 000000000000..36bcfc339244 --- /dev/null +++ b/contrib/gdb/gdb/m2-lang.h @@ -0,0 +1,31 @@ +/* Modula 2 language support definitions for GDB, the GNU debugger. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern int +m2_parse PARAMS ((void)); /* Defined in m2-exp.y */ + +extern void +m2_error PARAMS ((char *)); /* Defined in m2-exp.y */ + +extern void /* Defined in m2-typeprint.c */ +m2_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int)); + +extern int +m2_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int, + int, enum val_prettyprint)); diff --git a/contrib/gdb/gdb/m2-typeprint.c b/contrib/gdb/gdb/m2-typeprint.c new file mode 100644 index 000000000000..317f40189ef5 --- /dev/null +++ b/contrib/gdb/gdb/m2-typeprint.c @@ -0,0 +1,49 @@ +/* Support for printing Modula 2 types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "m2-lang.h" + +#include "gdb_string.h" +#include + +void +m2_print_type (type, varstring, stream, show, level) + struct type *type; + char *varstring; + GDB_FILE *stream; + int show; + int level; +{ + extern void c_print_type PARAMS ((struct type *, char *, GDB_FILE *, int, int)); + + c_print_type (type, varstring, stream, show, level); /* FIXME */ +} diff --git a/contrib/gdb/gdb/m2-valprint.c b/contrib/gdb/gdb/m2-valprint.c new file mode 100644 index 000000000000..28ea3b1ce74f --- /dev/null +++ b/contrib/gdb/gdb/m2-valprint.c @@ -0,0 +1,45 @@ +/* Support for printing Modula 2 values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "valprint.h" + +/* FIXME: For now, just explicitly declare c_val_print and use it instead */ + +int +m2_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + extern int + c_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int, + int, enum val_prettyprint)); + return (c_val_print (type, valaddr, address, stream, format, deref_ref, + recurse, pretty)); +} diff --git a/contrib/gdb/gdb/m3-nat.c b/contrib/gdb/gdb/m3-nat.c new file mode 100644 index 000000000000..1ea17695cce5 --- /dev/null +++ b/contrib/gdb/gdb/m3-nat.c @@ -0,0 +1,4640 @@ +/* Interface GDB to Mach 3.0 operating systems. + (Most) Mach 3.0 related routines live in this file. + + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Author: Jukka Virtanen + * Computing Centre + * Helsinki University of Technology + * Finland + * + * Thanks to my friends who helped with ideas and testing: + * + * Johannes Helander, Antti Louko, Tero Mononen, + * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi + * + * Tero Kivinen and Eamonn McManus + * kivinen@cs.hut.fi emcmanus@gr.osf.org + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "language.h" +#include "target.h" +#include "wait.h" +#include "gdbcmd.h" +#include "gdbcore.h" + +#if 0 +#include +#else +#define MACH_TYPE_TASK 1 +#define MACH_TYPE_THREAD 2 +#endif + +/* Included only for signal names and NSIG + * + * note: There are many problems in signal handling with + * gdb in Mach 3.0 in general. + */ +#include +#define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */ + +#include + +/* This is what a cproc looks like. This is here partly because + cthread_internals.h is not a header we can just #include, partly with + an eye towards perhaps getting this to work with cross-debugging + someday. Best solution is if CMU publishes a real interface to this + stuff. */ +#define CPROC_NEXT_OFFSET 0 +#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) +#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE) +#define CPROC_INCARNATION_SIZE (sizeof (cthread_t)) +#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE) +#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) +#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE) +#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) +#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE) +#define CPROC_REPLY_SIZE (sizeof (mach_port_t)) +#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE) +#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) +#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE) +#define CPROC_LOCK_SIZE (sizeof (spin_lock_t)) +#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE) +#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) +#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE) +#define CPROC_WIRED_SIZE (sizeof (mach_port_t)) +#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE) +#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) +#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE) +#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t)) +#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE) +#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) +#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE) +#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) +#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE) + +/* Values for the state field in the cproc. */ +#define CPROC_RUNNING 0 +#define CPROC_SWITCHING 1 +#define CPROC_BLOCKED 2 +#define CPROC_CONDWAIT 4 + +/* For cproc and kernel thread mapping */ +typedef struct gdb_thread { + mach_port_t name; + CORE_ADDR sp; + CORE_ADDR pc; + CORE_ADDR fp; + boolean_t in_emulator; + int slotid; + + /* This is for the mthreads list. It points to the cproc list. + Perhaps the two lists should be merged (or perhaps it was a mistake + to make them both use a struct gdb_thread). */ + struct gdb_thread *cproc; + + /* These are for the cproc list, which is linked through the next field + of the struct gdb_thread. */ + char raw_cproc[CPROC_SIZE]; + /* The cthread which is pointed to by the incarnation field from the + cproc. This points to the copy we've read into GDB. */ + cthread_t cthread; + /* Point back to the mthreads list. */ + int reverse_map; + struct gdb_thread *next; +} *gdb_thread_t; + +/* + * Actions for Mach exceptions. + * + * sigmap field maps the exception to corresponding Unix signal. + * + * I do not know how to map the exception to unix signal + * if SIG_UNKNOWN is specified. + */ + +struct exception_list { + char *name; + boolean_t forward; + boolean_t print; + int sigmap; +} exception_map[] = { + {"not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN}, + {"EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV}, + {"EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL}, + {"EXC_ARITHMETIC", FALSE, TRUE, SIGFPE}, + {"EXC_EMULATION", FALSE, TRUE, SIGEMT}, /* ??? */ + {"EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN}, + {"EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP} +}; + +/* Mach exception table size */ +int max_exception = sizeof(exception_map)/sizeof(struct exception_list) - 1; + +#define MAX_EXCEPTION max_exception + +WAITTYPE wait_status; + +/* If you define this, intercepted bsd server calls will be + * dumped while waiting the inferior to EXEC the correct + * program + */ +/* #define DUMP_SYSCALL /* debugging interceptor */ + +/* xx_debug() outputs messages if this is nonzero. + * If > 1, DUMP_SYSCALL will dump message contents. + */ +int debug_level = 0; + +/* "Temporary" debug stuff */ +void +xx_debug (fmt, a,b,c) +char *fmt; +int a,b,c; +{ + if (debug_level) + warning (fmt, a, b, c); +} + +/* This is in libmach.a */ +extern mach_port_t name_server_port; + +/* Set in catch_exception_raise */ +int stop_exception, stop_code, stop_subcode; +int stopped_in_exception; + +/* Thread that was the active thread when we stopped */ +thread_t stop_thread = MACH_PORT_NULL; + +char *hostname = ""; + +/* Set when task is attached or created */ +boolean_t emulator_present = FALSE; + +task_t inferior_task; +thread_t current_thread; + +/* Exception ports for inferior task */ +mach_port_t inferior_exception_port = MACH_PORT_NULL; +mach_port_t inferior_old_exception_port = MACH_PORT_NULL; + +/* task exceptions and notifications */ +mach_port_t inferior_wait_port_set = MACH_PORT_NULL; +mach_port_t our_notify_port = MACH_PORT_NULL; + +/* This is "inferior_wait_port_set" when not single stepping, and + * "singlestepped_thread_port" when we are single stepping. + * + * This is protected by a cleanup function: discard_single_step() + */ +mach_port_t currently_waiting_for = MACH_PORT_NULL; + +/* A port for external messages to gdb. + * External in the meaning that they do not come + * from the inferior_task, but rather from external + * tasks. + * + * As a debugging feature: + * A debugger debugging another debugger can stop the + * inferior debugger by the following command sequence + * (without running external programs) + * + * (top-gdb) set stop_inferior_gdb () + * (top-gdb) continue + */ +mach_port_t our_message_port = MACH_PORT_NULL; + +/* For single stepping */ +mach_port_t thread_exception_port = MACH_PORT_NULL; +mach_port_t thread_saved_exception_port = MACH_PORT_NULL; +mach_port_t singlestepped_thread_port = MACH_PORT_NULL; + +/* For machid calls */ +mach_port_t mid_server = MACH_PORT_NULL; +mach_port_t mid_auth = MACH_PORT_NULL; + +/* If gdb thinks the inferior task is not suspended, it + * must take suspend/abort the threads when it reads the state. + */ +int must_suspend_thread = 0; + +/* When single stepping, we switch the port that mach_really_wait() listens to. + * This cleanup is a guard to prevent the port set from being left to + * the singlestepped_thread_port when error() is called. + * This is nonzero only when we are single stepping. + */ +#define NULL_CLEANUP (struct cleanup *)0 +struct cleanup *cleanup_step = NULL_CLEANUP; + + +extern struct target_ops m3_ops; +static void m3_kill_inferior (); + +#if 0 +#define MACH_TYPE_EXCEPTION_PORT -1 +#endif + +/* Chain of ports to remember requested notifications. */ + +struct port_chain { + struct port_chain *next; + mach_port_t port; + int type; + int mid; /* Now only valid with MACH_TYPE_THREAD and */ + /* MACH_TYPE_THREAD */ +}; +typedef struct port_chain *port_chain_t; + +/* Room for chain nodes comes from pchain_obstack */ +struct obstack pchain_obstack; +struct obstack *port_chain_obstack = &pchain_obstack; + +/* For thread handling */ +struct obstack Cproc_obstack; +struct obstack *cproc_obstack = &Cproc_obstack; + +/* the list of notified ports */ +port_chain_t notify_chain = (port_chain_t) NULL; + +port_chain_t +port_chain_insert (list, name, type) + port_chain_t list; + mach_port_t name; + int type; +{ + kern_return_t ret; + port_chain_t new; + int mid; + + if (! MACH_PORT_VALID (name)) + return list; + + if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD) + { + if (! MACH_PORT_VALID (mid_server)) + { + warning ("Machid server port invalid, can not map port 0x%x to MID", + name); + mid = name; + } + else + { + ret = machid_mach_register (mid_server, mid_auth, name, type, &mid); + + if (ret != KERN_SUCCESS) + { + warning ("Can not map name (0x%x) to MID with machid", name); + mid = name; + } + } + } + else + abort (); + + new = (port_chain_t) obstack_alloc (port_chain_obstack, + sizeof (struct port_chain)); + new->next = list; + new->port = name; + new->type = type; + new->mid = mid; + + return new; +} + +port_chain_t +port_chain_delete (list, elem) + port_chain_t list; + mach_port_t elem; +{ + if (list) + if (list->port == elem) + list = list->next; + else + while (list->next) + { + if (list->next->port == elem) + list->next = list->next->next; /* GCd with obstack_free() */ + else + list = list->next; + } + return list; +} + +void +port_chain_destroy (ostack) + struct obstack *ostack; +{ + obstack_free (ostack, 0); + obstack_init (ostack); +} + +port_chain_t +port_chain_member (list, elem) + port_chain_t list; + mach_port_t elem; +{ + while (list) + { + if (list->port == elem) + return list; + list = list->next; + } + return (port_chain_t) NULL; +} + +int +map_port_name_to_mid (name, type) +mach_port_t name; +int type; +{ + port_chain_t elem; + + if (!MACH_PORT_VALID (name)) + return -1; + + elem = port_chain_member (notify_chain, name); + + if (elem && (elem->type == type)) + return elem->mid; + + if (elem) + return -1; + + if (! MACH_PORT_VALID (mid_server)) + { + warning ("Machid server port invalid, can not map port 0x%x to mid", + name); + return -1; + } + else + { + int mid; + kern_return_t ret; + + ret = machid_mach_register (mid_server, mid_auth, name, type, &mid); + + if (ret != KERN_SUCCESS) + { + warning ("Can not map name (0x%x) to mid with machid", name); + return -1; + } + return mid; + } +} + +/* Guard for currently_waiting_for and singlestepped_thread_port */ +static void +discard_single_step (thread) + thread_t thread; +{ + currently_waiting_for = inferior_wait_port_set; + + cleanup_step = NULL_CLEANUP; + if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port)) + setup_single_step (thread, FALSE); +} + +setup_single_step (thread, start_step) + thread_t thread; + boolean_t start_step; +{ + kern_return_t ret; + + if (! MACH_PORT_VALID (thread)) + error ("Invalid thread supplied to setup_single_step"); + else + { + mach_port_t teport; + + /* Get the current thread exception port */ + ret = thread_get_exception_port (thread, &teport); + CHK ("Getting thread's exception port", ret); + + if (start_step) + { + if (MACH_PORT_VALID (singlestepped_thread_port)) + { + warning ("Singlestepped_thread_port (0x%x) is still valid?", + singlestepped_thread_port); + singlestepped_thread_port = MACH_PORT_NULL; + } + + /* If we are already stepping this thread */ + if (MACH_PORT_VALID (teport) && teport == thread_exception_port) + { + ret = mach_port_deallocate (mach_task_self (), teport); + CHK ("Could not deallocate thread exception port", ret); + } + else + { + ret = thread_set_exception_port (thread, thread_exception_port); + CHK ("Setting exception port for thread", ret); +#if 0 + /* Insert thread exception port to wait port set */ + ret = mach_port_move_member (mach_task_self(), + thread_exception_port, + inferior_wait_port_set); + CHK ("Moving thread exception port to inferior_wait_port_set", + ret); +#endif + thread_saved_exception_port = teport; + } + + thread_trace (thread, TRUE); + + singlestepped_thread_port = thread_exception_port; + currently_waiting_for = singlestepped_thread_port; + cleanup_step = make_cleanup (discard_single_step, thread); + } + else + { + if (! MACH_PORT_VALID (teport)) + error ("Single stepped thread had an invalid exception port?"); + + if (teport != thread_exception_port) + error ("Single stepped thread had an unknown exception port?"); + + ret = mach_port_deallocate (mach_task_self (), teport); + CHK ("Couldn't deallocate thread exception port", ret); +#if 0 + /* Remove thread exception port from wait port set */ + ret = mach_port_move_member (mach_task_self(), + thread_exception_port, + MACH_PORT_NULL); + CHK ("Removing thread exception port from inferior_wait_port_set", + ret); +#endif + /* Restore thread's old exception port */ + ret = thread_set_exception_port (thread, + thread_saved_exception_port); + CHK ("Restoring stepped thread's exception port", ret); + + if (MACH_PORT_VALID (thread_saved_exception_port)) + (void) mach_port_deallocate (mach_task_self (), + thread_saved_exception_port); + + thread_trace (thread, FALSE); + + singlestepped_thread_port = MACH_PORT_NULL; + currently_waiting_for = inferior_wait_port_set; + if (cleanup_step) + discard_cleanups (cleanup_step); + } + } +} + +static +request_notify (name, variant, type) + mach_port_t name; + mach_msg_id_t variant; + int type; +{ + kern_return_t ret; + mach_port_t previous_port_dummy = MACH_PORT_NULL; + + if (! MACH_PORT_VALID (name)) + return; + + if (port_chain_member (notify_chain, name)) + return; + + ret = mach_port_request_notification (mach_task_self(), + name, + variant, + 1, + our_notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous_port_dummy); + CHK ("Serious: request_notify failed", ret); + + (void) mach_port_deallocate (mach_task_self (), + previous_port_dummy); + + notify_chain = port_chain_insert (notify_chain, name, type); +} + +reverse_msg_bits(msgp, type) + mach_msg_header_t *msgp; + int type; +{ + int rbits,lbits; + rbits = MACH_MSGH_BITS_REMOTE(msgp->msgh_bits); + lbits = type; + msgp->msgh_bits = + (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) | + MACH_MSGH_BITS(lbits,rbits); +} + +/* On the third day He said: + + Let this be global + and then it was global. + + When creating the inferior fork, the + child code in inflow.c sets the name of the + bootstrap_port in its address space to this + variable. + + The name is transferred to our address space + with mach3_read_inferior(). + + Thou shalt not do this with + task_get_bootstrap_port() in this task, since + the name in the inferior task is different than + the one we get. + + For blessed are the meek, as they shall inherit + the address space. + */ +mach_port_t original_server_port_name = MACH_PORT_NULL; + + +/* Called from inferior after FORK but before EXEC */ +static void +m3_trace_me () +{ + kern_return_t ret; + + /* Get the NAME of the bootstrap port in this task + so that GDB can read it */ + ret = task_get_bootstrap_port (mach_task_self (), + &original_server_port_name); + if (ret != KERN_SUCCESS) + abort (); + ret = mach_port_deallocate (mach_task_self (), + original_server_port_name); + if (ret != KERN_SUCCESS) + abort (); + + /* Suspend this task to let the parent change my ports. + Resumed by the debugger */ + ret = task_suspend (mach_task_self ()); + if (ret != KERN_SUCCESS) + abort (); +} + +/* + * Intercept system calls to Unix server. + * After EXEC_COUNTER calls to exec(), return. + * + * Pre-assertion: Child is suspended. (Not verified) + * Post-condition: Child is suspended after EXEC_COUNTER exec() calls. + */ + +void +intercept_exec_calls (exec_counter) + int exec_counter; +{ + int terminal_initted = 0; + + struct syscall_msg_t { + mach_msg_header_t header; + mach_msg_type_t type; + char room[ 2000 ]; /* Enuff space */ + }; + + struct syscall_msg_t syscall_in, syscall_out; + + mach_port_t fake_server; + mach_port_t original_server_send; + mach_port_t original_exec_reply; + mach_port_t exec_reply; + mach_port_t exec_reply_send; + mach_msg_type_name_t acquired; + mach_port_t emulator_server_port_name; + struct task_basic_info info; + mach_msg_type_number_t info_count; + + kern_return_t ret; + + if (exec_counter <= 0) + return; /* We are already set up in the correct program */ + + ret = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &fake_server); + CHK("create inferior_fake_server port failed", ret); + + /* Wait for inferior_task to suspend itself */ + while(1) + { + info_count = sizeof (info); + ret = task_info (inferior_task, + TASK_BASIC_INFO, + (task_info_t)&info, + &info_count); + CHK ("Task info", ret); + + if (info.suspend_count) + break; + + /* Note that the definition of the parameter was undefined + * at the time of this writing, so I just use an `ad hoc' value. + */ + (void) swtch_pri (42); /* Universal Priority Value */ + } + + /* Read the inferior's bootstrap port name */ + if (!mach3_read_inferior (&original_server_port_name, + &original_server_port_name, + sizeof (original_server_port_name))) + error ("Can't read inferior task bootstrap port name"); + + /* @@ BUG: If more than 1 send right GDB will FAIL!!! */ + /* Should get refs, and set them back when restoring */ + /* Steal the original bsd server send right from inferior */ + ret = mach_port_extract_right (inferior_task, + original_server_port_name, + MACH_MSG_TYPE_MOVE_SEND, + &original_server_send, + &acquired); + CHK("mach_port_extract_right (bsd server send)",ret); + + if (acquired != MACH_MSG_TYPE_PORT_SEND) + error("Incorrect right extracted, send right to bsd server excpected"); + + ret = mach_port_insert_right (inferior_task, + original_server_port_name, + fake_server, + MACH_MSG_TYPE_MAKE_SEND); + CHK("mach_port_insert_right (fake server send)",ret); + + xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n", + fake_server, + original_server_port_name, original_server_send); + + /* A receive right to the reply generated by unix server exec() request */ + ret = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &exec_reply); + CHK("create intercepted_reply_port port failed", ret); + + /* Pass this send right to Unix server so it replies to us after exec() */ + ret = mach_port_extract_right (mach_task_self (), + exec_reply, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &exec_reply_send, + &acquired); + CHK("mach_port_extract_right (exec_reply)",ret); + + if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE) + error("Incorrect right extracted, send once excpected for exec reply"); + + ret = mach_port_move_member(mach_task_self(), + fake_server, + inferior_wait_port_set); + CHK ("Moving fake syscall port to inferior_wait_port_set", ret); + + xx_debug ("syscall fake server set up, resuming inferior\n"); + + ret = task_resume (inferior_task); + CHK("task_resume (startup)", ret); + + /* Read requests from the inferior. + Pass directly through everything else except exec() calls. + */ + while(exec_counter > 0) + { + ret = mach_msg (&syscall_in.header, /* header */ + MACH_RCV_MSG, /* options */ + 0, /* send size */ + sizeof (struct syscall_msg_t), /* receive size */ + inferior_wait_port_set, /* receive_name */ + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + CHK("mach_msg (intercepted sycall)", ret); + +#ifdef DUMP_SYSCALL + print_msg (&syscall_in.header); +#endif + + /* ASSERT : msgh_local_port == fake_server */ + + if (notify_server (&syscall_in.header, &syscall_out.header)) + error ("received a notify while intercepting syscalls"); + + if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID) + { + xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter); + if (exec_counter == 1) + { + original_exec_reply = syscall_in.header.msgh_remote_port; + syscall_in.header.msgh_remote_port = exec_reply_send; + } + + if (!terminal_initted) + { + /* Now that the child has exec'd we know it has already set its + process group. On POSIX systems, tcsetpgrp will fail with + EPERM if we try it before the child's setpgid. */ + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + terminal_initted = 1; + } + + exec_counter--; + } + + syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port; + syscall_in.header.msgh_remote_port = original_server_send; + + reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_COPY_SEND); + + ret = mach_msg_send (&syscall_in.header); + CHK ("Forwarded syscall", ret); + } + + ret = mach_port_move_member(mach_task_self(), + fake_server, + MACH_PORT_NULL); + CHK ("Moving fake syscall out of inferior_wait_port_set", ret); + + ret = mach_port_move_member(mach_task_self(), + exec_reply, + inferior_wait_port_set); + CHK ("Moving exec_reply to inferior_wait_port_set", ret); + + ret = mach_msg (&syscall_in.header, /* header */ + MACH_RCV_MSG, /* options */ + 0, /* send size */ + sizeof (struct syscall_msg_t), /* receive size */ + inferior_wait_port_set, /* receive_name */ + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + CHK("mach_msg (exec reply)", ret); + + ret = task_suspend (inferior_task); + CHK ("Suspending inferior after last exec", ret); + + must_suspend_thread = 0; + + xx_debug ("Received exec reply from bsd server, suspended inferior task\n"); + +#ifdef DUMP_SYSCALL + print_msg (&syscall_in.header); +#endif + + /* Message should appear as if it came from the unix server */ + syscall_in.header.msgh_local_port = MACH_PORT_NULL; + + /* and go to the inferior task original reply port */ + syscall_in.header.msgh_remote_port = original_exec_reply; + + reverse_msg_bits(&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE); + + ret = mach_msg_send (&syscall_in.header); + CHK ("Forwarding exec reply to inferior", ret); + + /* Garbage collect */ + ret = mach_port_deallocate (inferior_task, + original_server_port_name); + CHK ("deallocating fake server send right", ret); + + ret = mach_port_insert_right (inferior_task, + original_server_port_name, + original_server_send, + MACH_MSG_TYPE_MOVE_SEND); + CHK ("Restoring the original bsd server send right", ret); + + ret = mach_port_destroy (mach_task_self (), + fake_server); + fake_server = MACH_PORT_DEAD; + CHK("mach_port_destroy (fake_server)", ret); + + ret = mach_port_destroy (mach_task_self (), + exec_reply); + exec_reply = MACH_PORT_DEAD; + CHK("mach_port_destroy (exec_reply)", ret); + + xx_debug ("Done with exec call interception\n"); +} + +void +consume_send_rights (thread_list, thread_count) + thread_array_t thread_list; + int thread_count; +{ + int index; + + if (!thread_count) + return; + + for (index = 0; index < thread_count; index++) + { + /* Since thread kill command kills threads, don't check ret */ + (void) mach_port_deallocate (mach_task_self (), + thread_list [ index ]); + } +} + +/* suspend/abort/resume a thread. */ +setup_thread (thread, what) + mach_port_t thread; + int what; +{ + kern_return_t ret; + + if (what) + { + ret = thread_suspend (thread); + CHK ("setup_thread thread_suspend", ret); + + ret = thread_abort (thread); + CHK ("setup_thread thread_abort", ret); + } + else + { + ret = thread_resume (thread); + CHK ("setup_thread thread_resume", ret); + } +} + +int +map_slot_to_mid (slot, threads, thread_count) + int slot; + thread_array_t threads; + int thread_count; +{ + kern_return_t ret; + int deallocate = 0; + int index; + int mid; + + if (! threads) + { + deallocate++; + ret = task_threads (inferior_task, &threads, &thread_count); + CHK ("Can not select a thread from a dead task", ret); + } + + if (slot < 0 || slot >= thread_count) + { + if (deallocate) + { + consume_send_rights (threads, thread_count); + (void) vm_deallocate (mach_task_self(), (vm_address_t)threads, + (thread_count * sizeof(mach_port_t))); + } + if (slot < 0) + error ("invalid slot number"); + else + return -(slot+1); + } + + mid = map_port_name_to_mid (threads [slot], MACH_TYPE_THREAD); + + if (deallocate) + { + consume_send_rights (threads, thread_count); + (void) vm_deallocate (mach_task_self(), (vm_address_t)threads, + (thread_count * sizeof(mach_port_t))); + } + + return mid; +} + +static int +parse_thread_id (arg, thread_count, slots) + char *arg; + int thread_count; + int slots; +{ + kern_return_t ret; + int mid; + int slot; + int index; + + if (arg == 0) + return 0; + + while (*arg && (*arg == ' ' || *arg == '\t')) + arg++; + + if (! *arg) + return 0; + + /* Currently parse MID and @SLOTNUMBER */ + if (*arg != '@') + { + mid = atoi (arg); + if (mid <= 0) + error ("valid thread mid expected"); + return mid; + } + + arg++; + slot = atoi (arg); + + if (slot < 0) + error ("invalid slot number"); + + /* If you want slot numbers to remain slot numbers, set slots. + * + * Well, since 0 is reserved, return the ordinal number + * of the thread rather than the slot number. Awk, this + * counts as a kludge. + */ + if (slots) + return -(slot+1); + + if (thread_count && slot >= thread_count) + return -(slot+1); + + mid = map_slot_to_mid (slot); + + return mid; +} + +/* THREAD_ID 0 is special; it selects the first kernel + * thread from the list (i.e. SLOTNUMBER 0) + * This is used when starting the program with 'run' or when attaching. + * + * If FLAG is 0 the context is not changed, and the registers, frame, etc + * will continue to describe the old thread. + * + * If FLAG is nonzero, really select the thread. + * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid. + * + */ +kern_return_t +select_thread (task, thread_id, flag) + mach_port_t task; + int thread_id; + int flag; +{ + thread_array_t thread_list; + int thread_count; + kern_return_t ret; + int index; + thread_t new_thread = MACH_PORT_NULL; + + if (thread_id < 0) + error ("Can't select cprocs without kernel thread"); + + ret = task_threads (task, &thread_list, &thread_count); + if (ret != KERN_SUCCESS) + { + warning ("Can not select a thread from a dead task"); + m3_kill_inferior (); + return KERN_FAILURE; + } + + if (thread_count == 0) + { + /* The task can not do anything anymore, but it still + * exists as a container for memory and ports. + */ + registers_changed (); + warning ("Task %d has no threads", + map_port_name_to_mid (task, MACH_TYPE_TASK)); + current_thread = MACH_PORT_NULL; + (void) vm_deallocate(mach_task_self(), + (vm_address_t) thread_list, + (thread_count * sizeof(mach_port_t))); + return KERN_FAILURE; + } + + if (! thread_id || flag == 2) + { + /* First thread or a slotnumber */ + if (! thread_id) + new_thread = thread_list[0]; + else + { + if (thread_id < thread_count) + new_thread = thread_list[ thread_id ]; + else + { + (void) vm_deallocate(mach_task_self(), + (vm_address_t) thread_list, + (thread_count * sizeof(mach_port_t))); + error ("No such thread slot number : %d", thread_id); + } + } + } + else + { + for (index = 0; index < thread_count; index++) + if (thread_id == map_port_name_to_mid (thread_list [index], + MACH_TYPE_THREAD)) + { + new_thread = thread_list [index]; + index = -1; + break; + } + + if (index != -1) + error ("No thread with mid %d", thread_id); + } + + /* Notify when the selected thread dies */ + request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD); + + ret = vm_deallocate(mach_task_self(), + (vm_address_t) thread_list, + (thread_count * sizeof(mach_port_t))); + CHK ("vm_deallocate", ret); + + if (! flag) + current_thread = new_thread; + else + { +#if 0 + if (MACH_PORT_VALID (current_thread)) + { + /* Store the gdb's view of the thread we are deselecting + * + * @@ I think gdb updates registers immediately when they are + * changed, so don't do this. + */ + ret = thread_abort (current_thread); + CHK ("Could not abort system calls when saving state of old thread", + ret); + target_prepare_to_store (); + target_store_registers (-1); + } +#endif + + registers_changed (); + + current_thread = new_thread; + + ret = thread_abort (current_thread); + CHK ("Could not abort system calls when selecting a thread", ret); + + stop_pc = read_pc(); + flush_cached_frames (); + + select_frame (get_current_frame (), 0); + } + + return KERN_SUCCESS; +} + +/* + * Switch to use thread named NEW_THREAD. + * Return it's MID + */ +int +switch_to_thread (new_thread) + thread_t new_thread; +{ + thread_t saved_thread = current_thread; + int mid; + + mid = map_port_name_to_mid (new_thread, + MACH_TYPE_THREAD); + if (mid == -1) + warning ("Can't map thread name 0x%x to mid", new_thread); + else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS) + { + if (current_thread) + current_thread = saved_thread; + error ("Could not select thread %d", mid); + } + + return mid; +} + +/* Do this in gdb after doing FORK but before STARTUP_INFERIOR. + * Note that the registers are not yet valid in the inferior task. + */ +static void +m3_trace_him (pid) + int pid; +{ + kern_return_t ret; + + push_target (&m3_ops); + + inferior_task = task_by_pid (pid); + + if (! MACH_PORT_VALID (inferior_task)) + error ("Can not map Unix pid %d to Mach task", pid); + + /* Clean up previous notifications and create new ones */ + setup_notify_port (1); + + /* When notification appears, the inferior task has died */ + request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK); + + emulator_present = have_emulator_p (inferior_task); + + /* By default, select the first thread, + * If task has no threads, gives a warning + * Does not fetch registers, since they are not yet valid. + */ + select_thread (inferior_task, 0, 0); + + inferior_exception_port = MACH_PORT_NULL; + + setup_exception_port (); + + xx_debug ("Now the debugged task is created\n"); + + /* One trap to exec the shell, one to exec the program being debugged. */ + intercept_exec_calls (2); +} + +setup_exception_port () +{ + kern_return_t ret; + + ret = mach_port_allocate (mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &inferior_exception_port); + CHK("mach_port_allocate",ret); + + /* add send right */ + ret = mach_port_insert_right (mach_task_self (), + inferior_exception_port, + inferior_exception_port, + MACH_MSG_TYPE_MAKE_SEND); + CHK("mach_port_insert_right",ret); + + ret = mach_port_move_member (mach_task_self(), + inferior_exception_port, + inferior_wait_port_set); + CHK("mach_port_move_member",ret); + + ret = task_get_special_port (inferior_task, + TASK_EXCEPTION_PORT, + &inferior_old_exception_port); + CHK ("task_get_special_port(old exc)",ret); + + ret = task_set_special_port (inferior_task, + TASK_EXCEPTION_PORT, + inferior_exception_port); + CHK("task_set_special_port",ret); + + ret = mach_port_deallocate (mach_task_self (), + inferior_exception_port); + CHK("mack_port_deallocate",ret); + +#if 0 + /* When notify appears, the inferior_task's exception + * port has been destroyed. + * + * Not used, since the dead_name_notification already + * appears when task dies. + * + */ + request_notify (inferior_exception_port, + MACH_NOTIFY_NO_SENDERS, + MACH_TYPE_EXCEPTION_PORT); +#endif +} + +/* Nonzero if gdb is waiting for a message */ +int mach_really_waiting; + +/* Wait for the inferior to stop for some reason. + - Loop on notifications until inferior_task dies. + - Loop on exceptions until stopped_in_exception comes true. + (e.g. we receive a single step trace trap) + - a message arrives to gdb's message port + + There is no other way to exit this loop. + + Returns the inferior_pid for rest of gdb. + Side effects: Set *OURSTATUS. */ +int +mach_really_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + kern_return_t ret; + int w; + + struct msg { + mach_msg_header_t header; + mach_msg_type_t foo; + int data[8000]; + } in_msg, out_msg; + + /* Either notify (death), exception or message can stop the inferior */ + stopped_in_exception = FALSE; + + while (1) + { + QUIT; + + stop_exception = stop_code = stop_subcode = -1; + stop_thread = MACH_PORT_NULL; + + mach_really_waiting = 1; + ret = mach_msg (&in_msg.header, /* header */ + MACH_RCV_MSG, /* options */ + 0, /* send size */ + sizeof (struct msg), /* receive size */ + currently_waiting_for, /* receive name */ + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + mach_really_waiting = 0; + CHK("mach_msg (receive)", ret); + + /* Check if we received a notify of the childs' death */ + if (notify_server (&in_msg.header, &out_msg.header)) + { + /* If inferior_task is null then the inferior has + gone away and we want to return to command level. + Otherwise it was just an informative message and we + need to look to see if there are any more. */ + if (inferior_task != MACH_PORT_NULL) + continue; + else + { + /* Collect Unix exit status for gdb */ + + wait3(&w, WNOHANG, 0); + + /* This mess is here to check that the rest of + * gdb knows that the inferior died. It also + * tries to hack around the fact that Mach 3.0 (mk69) + * unix server (ux28) does not always know what + * has happened to it's children when mach-magic + * is applied on them. + */ + if ((!WIFEXITED(w) && WIFSTOPPED(w)) || + (WIFEXITED(w) && WEXITSTATUS(w) > 0377)) + { + WSETEXIT(w, 0); + warning ("Using exit value 0 for terminated task"); + } + else if (!WIFEXITED(w)) + { + int sig = WTERMSIG(w); + + /* Signals cause problems. Warn the user. */ + if (sig != SIGKILL) /* Bad luck if garbage matches this */ + warning ("The terminating signal stuff may be nonsense"); + else if (sig > NSIG) + { + WSETEXIT(w, 0); + warning ("Using exit value 0 for terminated task"); + } + } + store_waitstatus (ourstatus, w); + return inferior_pid; + } + } + + /* Hmm. Check for exception, as it was not a notification. + exc_server() does an upcall to catch_exception_raise() + if this rpc is an exception. Further actions are decided + there. + */ + if (! exc_server (&in_msg.header, &out_msg.header)) + { + + /* Not an exception, check for message. + * + * Messages don't come from the inferior, or if they + * do they better be asynchronous or it will hang. + */ + if (gdb_message_server (&in_msg.header)) + continue; + + error ("Unrecognized message received in mach_really_wait"); + } + + /* Send the reply of the exception rpc to the suspended task */ + ret = mach_msg_send (&out_msg.header); + CHK ("mach_msg_send (exc reply)", ret); + + if (stopped_in_exception) + { + /* Get unix state. May be changed in mach3_exception_actions() */ + wait3(&w, WNOHANG, 0); + + mach3_exception_actions (&w, FALSE, "Task"); + + store_waitstatus (ourstatus, w); + return inferior_pid; + } + } +} + +/* Called by macro DO_QUIT() in utils.c(quit). + * This is called just before calling error() to return to command level + */ +void +mach3_quit () +{ + int mid; + kern_return_t ret; + + if (mach_really_waiting) + { + ret = task_suspend (inferior_task); + + if (ret != KERN_SUCCESS) + { + warning ("Could not suspend task for interrupt: %s", + mach_error_string (ret)); + mach_really_waiting = 0; + return; + } + } + + must_suspend_thread = 0; + mach_really_waiting = 0; + + mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); + if (mid == -1) + { + warning ("Selecting first existing kernel thread"); + mid = 0; + } + + current_thread = MACH_PORT_NULL; /* Force setup */ + select_thread (inferior_task, mid, 1); + + return; +} + +#if 0 +/* bogus bogus bogus. It is NOT OK to quit out of target_wait. */ + +/* If ^C is typed when we are waiting for a message + * and your Unix server is able to notice that we + * should quit now. + * + * Called by REQUEST_QUIT() from utils.c(request_quit) + */ +void +mach3_request_quit () +{ + if (mach_really_waiting) + immediate_quit = 1; +} +#endif + +/* + * Gdb message server. + * Currently implemented is the STOP message, that causes + * gdb to return to the command level like ^C had been typed from terminal. + */ +int +gdb_message_server (InP) + mach_msg_header_t *InP; +{ + kern_return_t ret; + int mid; + + if (InP->msgh_local_port == our_message_port) + { + /* A message coming to our_message_port. Check validity */ + switch (InP->msgh_id) { + + case GDB_MESSAGE_ID_STOP: + ret = task_suspend (inferior_task); + if (ret != KERN_SUCCESS) + warning ("Could not suspend task for stop message: %s", + mach_error_string (ret)); + + /* QUIT in mach_really_wait() loop. */ + request_quit (0); + break; + + default: + warning ("Invalid message id %d received, ignored.", + InP->msgh_id); + break; + } + + return 1; + } + + /* Message not handled by this server */ + return 0; +} + +/* NOTE: This is not an RPC call. It is a simpleroutine. + * + * This is not called from this gdb code. + * + * It may be called by another debugger to cause this + * debugger to enter command level: + * + * (gdb) set stop_inferior_gdb () + * (gdb) continue + * + * External program "stop-gdb" implements this also. + */ +void +stop_inferior_gdb () +{ + kern_return_t ret; + + /* Code generated by mig, with minor cleanups :-) + * + * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t); + */ + + typedef struct { + mach_msg_header_t Head; + } Request; + + Request Mess; + + register Request *InP = &Mess; + + InP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); + + /* msgh_size passed as argument */ + InP->Head.msgh_remote_port = our_message_port; + InP->Head.msgh_local_port = MACH_PORT_NULL; + InP->Head.msgh_seqno = 0; + InP->Head.msgh_id = GDB_MESSAGE_ID_STOP; + + ret = mach_msg (&InP->Head, + MACH_SEND_MSG|MACH_MSG_OPTION_NONE, + sizeof(Request), + 0, + MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); +} + +#ifdef THREAD_ALLOWED_TO_BREAK +/* + * Return 1 if the MID specifies the thread that caused the + * last exception. + * Since catch_exception_raise() selects the thread causing + * the last exception to current_thread, we just check that + * it is selected and the last exception was a breakpoint. + */ +int +mach_thread_for_breakpoint (mid) + int mid; +{ + int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); + + if (mid < 0) + { + mid = map_slot_to_mid (-(mid+1), 0, 0); + if (mid < 0) + return 0; /* Don't stop, no such slot */ + } + + if (! mid || cmid == -1) + return 1; /* stop */ + + return cmid == mid && stop_exception == EXC_BREAKPOINT; +} +#endif /* THREAD_ALLOWED_TO_BREAK */ + +#ifdef THREAD_PARSE_ID +/* + * Map a thread id string (MID or a @SLOTNUMBER) + * to a thread-id. + * + * 0 matches all threads. + * Otherwise the meaning is defined only in this file. + * (mach_thread_for_breakpoint uses it) + * + * @@ This allows non-existent MIDs to be specified. + * It now also allows non-existent slots to be + * specified. (Slot numbers stored are negative, + * and the magnitude is one greater than the actual + * slot index. (Since 0 is reserved)) + */ +int +mach_thread_parse_id (arg) + char *arg; +{ + int mid; + if (arg == 0) + error ("thread id excpected"); + mid = parse_thread_id (arg, 0, 1); + + return mid; +} +#endif /* THREAD_PARSE_ID */ + +#ifdef THREAD_OUTPUT_ID +char * +mach_thread_output_id (mid) + int mid; +{ + static char foobar [20]; + + if (mid > 0) + sprintf (foobar, "mid %d", mid); + else if (mid < 0) + sprintf (foobar, "@%d", -(mid+1)); + else + sprintf (foobar, "*any thread*"); + + return foobar; +} +#endif /* THREAD_OUTPUT_ID */ + +/* Called with hook PREPARE_TO_PROCEED() from infrun.c. + * + * If we have switched threads and stopped at breakpoint return 1 otherwise 0. + * + * if SELECT_IT is nonzero, reselect the thread that was active when + * we stopped at a breakpoint. + * + */ + +mach3_prepare_to_proceed (select_it) + int select_it; +{ + if (stop_thread && + stop_thread != current_thread && + stop_exception == EXC_BREAKPOINT) + { + int mid; + + if (! select_it) + return 1; + + mid = switch_to_thread (stop_thread); + + return 1; + } + + return 0; +} + +/* this stuff here is an upcall via libmach/excServer.c + and mach_really_wait which does the actual upcall. + + The code will pass the exception to the inferior if: + + - The task that signaled is not the inferior task + (e.g. when debugging another debugger) + + - The user has explicitely requested to pass on the exceptions. + (e.g to the default unix exception handler, which maps + exceptions to signals, or the user has her own exception handler) + + - If the thread that signaled is being single-stepped and it + has set it's own exception port and the exception is not + EXC_BREAKPOINT. (Maybe this is not desirable?) + */ + +kern_return_t +catch_exception_raise (port, thread, task, exception, code, subcode) + mach_port_t port; + thread_t thread; + task_t task; + int exception, code, subcode; +{ + kern_return_t ret; + boolean_t signal_thread; + int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD); + + if (! MACH_PORT_VALID (thread)) + { + /* If the exception was sent and thread dies before we + receive it, THREAD will be MACH_PORT_DEAD + */ + + current_thread = thread = MACH_PORT_NULL; + error ("Received exception from nonexistent thread"); + } + + /* Check if the task died in transit. + * @@ Isn't the thread also invalid in such case? + */ + if (! MACH_PORT_VALID (task)) + { + current_thread = thread = MACH_PORT_NULL; + error ("Received exception from nonexistent task"); + } + + if (exception < 0 || exception > MAX_EXCEPTION) + fatal ("catch_exception_raise: unknown exception code %d thread %d", + exception, + mid); + + if (! MACH_PORT_VALID (inferior_task)) + error ("got an exception, but inferior_task is null or dead"); + + stop_exception = exception; + stop_code = code; + stop_subcode = subcode; + stop_thread = thread; + + signal_thread = exception != EXC_BREAKPOINT && + port == singlestepped_thread_port && + MACH_PORT_VALID (thread_saved_exception_port); + + /* If it was not our inferior or if we want to forward + * the exception to the inferior's handler, do it here + * + * Note: If you have forwarded EXC_BREAKPOINT I trust you know why. + */ + if (task != inferior_task || + signal_thread || + exception_map [exception].forward) + { + mach_port_t eport = inferior_old_exception_port; + + if (signal_thread) + { + /* + GDB now forwards the exeption to thread's original handler, + since the user propably knows what he is doing. + Give a message, though. + */ + + mach3_exception_actions ((WAITTYPE *)NULL, TRUE, "Thread"); + eport = thread_saved_exception_port; + } + + /* Send the exception to the original handler */ + ret = exception_raise (eport, + thread, + task, + exception, + code, + subcode); + + (void) mach_port_deallocate (mach_task_self (), task); + (void) mach_port_deallocate (mach_task_self (), thread); + + /* If we come here, we don't want to trace any more, since we + * will never stop for tracing anyway. + */ + discard_single_step (thread); + + /* Do not stop the inferior */ + return ret; + } + + /* Now gdb handles the exception */ + stopped_in_exception = TRUE; + + ret = task_suspend (task); + CHK ("Error suspending inferior after exception", ret); + + must_suspend_thread = 0; + + if (current_thread != thread) + { + if (MACH_PORT_VALID (singlestepped_thread_port)) + /* Cleanup discards single stepping */ + error ("Exception from thread %d while singlestepping thread %d", + mid, + map_port_name_to_mid (current_thread, MACH_TYPE_THREAD)); + + /* Then select the thread that caused the exception */ + if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) + error ("Could not select thread %d causing exception", mid); + else + warning ("Gdb selected thread %d", mid); + } + + /* If we receive an exception that is not breakpoint + * exception, we interrupt the single step and return to + * debugger. Trace condition is cleared. + */ + if (MACH_PORT_VALID (singlestepped_thread_port)) + { + if (stop_exception != EXC_BREAKPOINT) + warning ("Single step interrupted by exception"); + else if (port == singlestepped_thread_port) + { + /* Single step exception occurred, remove trace bit + * and return to gdb. + */ + if (! MACH_PORT_VALID (current_thread)) + error ("Single stepped thread is not valid"); + + /* Resume threads, but leave the task suspended */ + resume_all_threads (0); + } + else + warning ("Breakpoint while single stepping?"); + + discard_single_step (current_thread); + } + + (void) mach_port_deallocate (mach_task_self (), task); + (void) mach_port_deallocate (mach_task_self (), thread); + + return KERN_SUCCESS; +} + +int +port_valid (port, mask) + mach_port_t port; + int mask; +{ + kern_return_t ret; + mach_port_type_t type; + + ret = mach_port_type (mach_task_self (), + port, + &type); + if (ret != KERN_SUCCESS || (type & mask) != mask) + return 0; + return 1; +} + +/* @@ No vm read cache implemented yet */ +boolean_t vm_read_cache_valid = FALSE; + +/* + * Read inferior task's LEN bytes from ADDR and copy it to MYADDR + * in gdb's address space. + * + * Return 0 on failure; number of bytes read otherwise. + */ +int +mach3_read_inferior (addr, myaddr, length) + CORE_ADDR addr; + char *myaddr; + int length; +{ + kern_return_t ret; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr+length) - low_address; + pointer_t copied_memory; + int copy_count; + + /* Get memory from inferior with page aligned addresses */ + ret = vm_read (inferior_task, + low_address, + aligned_length, + &copied_memory, + ©_count); + if (ret != KERN_SUCCESS) + { + /* the problem is that the inferior might be killed for whatever reason + * before we go to mach_really_wait. This is one place that ought to + * catch many of those errors. + * @@ A better fix would be to make all external events to GDB + * to arrive via a SINGLE port set. (Including user input!) + */ + + if (! port_valid (inferior_task, MACH_PORT_TYPE_SEND)) + { + m3_kill_inferior (); + error ("Inferior killed (task port invalid)"); + } + else + { +#ifdef OSF + extern int errno; + /* valprint.c gives nicer format if this does not + screw it. Eamonn seems to like this, so I enable + it if OSF is defined... + */ + warning ("[read inferior %x failed: %s]", + addr, mach_error_string (ret)); + errno = 0; +#endif + return 0; + } + } + + memcpy (myaddr, (char *)addr - low_address + copied_memory, length); + + ret = vm_deallocate (mach_task_self (), + copied_memory, + copy_count); + CHK("mach3_read_inferior vm_deallocate failed", ret); + + return length; +} + +#ifdef __STDC__ +#define CHK_GOTO_OUT(str,ret) \ + do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0) +#else +#define CHK_GOTO_OUT(str,ret) \ + do if (ret != KERN_SUCCESS) { errstr = str; goto out; } while(0) +#endif + +struct vm_region_list { + struct vm_region_list *next; + vm_prot_t protection; + vm_address_t start; + vm_size_t length; +}; + +struct obstack region_obstack; + +/* + * Write inferior task's LEN bytes from ADDR and copy it to MYADDR + * in gdb's address space. + */ +int +mach3_write_inferior (addr, myaddr, length) + CORE_ADDR addr; + char *myaddr; + int length; +{ + kern_return_t ret; + vm_address_t low_address = (vm_address_t) trunc_page (addr); + vm_size_t aligned_length = + (vm_size_t) round_page (addr+length) - low_address; + pointer_t copied_memory; + int copy_count; + int deallocate = 0; + + char *errstr = "Bug in mach3_write_inferior"; + + struct vm_region_list *region_element; + struct vm_region_list *region_head = (struct vm_region_list *)NULL; + + /* Get memory from inferior with page aligned addresses */ + ret = vm_read (inferior_task, + low_address, + aligned_length, + &copied_memory, + ©_count); + CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret); + + deallocate++; + + memcpy ((char *)addr - low_address + copied_memory, myaddr, length); + + obstack_init (®ion_obstack); + + /* Do writes atomically. + * First check for holes and unwritable memory. + */ + { + vm_size_t remaining_length = aligned_length; + vm_address_t region_address = low_address; + + struct vm_region_list *scan; + + while(region_address < low_address + aligned_length) + { + vm_prot_t protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; + boolean_t shared; + mach_port_t object_name; + vm_offset_t offset; + vm_size_t region_length = remaining_length; + vm_address_t old_address = region_address; + + ret = vm_region (inferior_task, + ®ion_address, + ®ion_length, + &protection, + &max_protection, + &inheritance, + &shared, + &object_name, + &offset); + CHK_GOTO_OUT ("vm_region failed", ret); + + /* Check for holes in memory */ + if (old_address != region_address) + { + warning ("No memory at 0x%x. Nothing written", + old_address); + ret = KERN_SUCCESS; + length = 0; + goto out; + } + + if (!(max_protection & VM_PROT_WRITE)) + { + warning ("Memory at address 0x%x is unwritable. Nothing written", + old_address); + ret = KERN_SUCCESS; + length = 0; + goto out; + } + + /* Chain the regions for later use */ + region_element = + (struct vm_region_list *) + obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); + + region_element->protection = protection; + region_element->start = region_address; + region_element->length = region_length; + + /* Chain the regions along with protections */ + region_element->next = region_head; + region_head = region_element; + + region_address += region_length; + remaining_length = remaining_length - region_length; + } + + /* If things fail after this, we give up. + * Somebody is messing up inferior_task's mappings. + */ + + /* Enable writes to the chained vm regions */ + for (scan = region_head; scan; scan = scan->next) + { + boolean_t protection_changed = FALSE; + + if (!(scan->protection & VM_PROT_WRITE)) + { + ret = vm_protect (inferior_task, + scan->start, + scan->length, + FALSE, + scan->protection | VM_PROT_WRITE); + CHK_GOTO_OUT ("vm_protect: enable write failed", ret); + } + } + + ret = vm_write (inferior_task, + low_address, + copied_memory, + aligned_length); + CHK_GOTO_OUT ("vm_write failed", ret); + + /* Set up the original region protections, if they were changed */ + for (scan = region_head; scan; scan = scan->next) + { + boolean_t protection_changed = FALSE; + + if (!(scan->protection & VM_PROT_WRITE)) + { + ret = vm_protect (inferior_task, + scan->start, + scan->length, + FALSE, + scan->protection); + CHK_GOTO_OUT ("vm_protect: enable write failed", ret); + } + } + } + + out: + if (deallocate) + { + obstack_free (®ion_obstack, 0); + + (void) vm_deallocate (mach_task_self (), + copied_memory, + copy_count); + } + + if (ret != KERN_SUCCESS) + { + warning ("%s %s", errstr, mach_error_string (ret)); + return 0; + } + + return length; +} + +/* Return 0 on failure, number of bytes handled otherwise. */ +static int +m3_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* IGNORED */ +{ + int result; + + if (write) + result = mach3_write_inferior (memaddr, myaddr, len); + else + result = mach3_read_inferior (memaddr, myaddr, len); + + return result; +} + + +static char * +translate_state(state) +int state; +{ + switch (state) { + case TH_STATE_RUNNING: return("R"); + case TH_STATE_STOPPED: return("S"); + case TH_STATE_WAITING: return("W"); + case TH_STATE_UNINTERRUPTIBLE: return("U"); + case TH_STATE_HALTED: return("H"); + default: return("?"); + } +} + +static char * +translate_cstate (state) + int state; +{ + switch (state) + { + case CPROC_RUNNING: return "R"; + case CPROC_SWITCHING: return "S"; + case CPROC_BLOCKED: return "B"; + case CPROC_CONDWAIT: return "C"; + case CPROC_CONDWAIT|CPROC_SWITCHING: return "CS"; + default: return "?"; + } +} + +/* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */ + +mach_port_t /* no mach_port_name_t found in include files. */ +map_inferior_port_name (inferior_name, type) + mach_port_t inferior_name; + mach_msg_type_name_t type; +{ + kern_return_t ret; + mach_msg_type_name_t acquired; + mach_port_t iport; + + ret = mach_port_extract_right (inferior_task, + inferior_name, + type, + &iport, + &acquired); + CHK("mach_port_extract_right (map_inferior_port_name)", ret); + + if (acquired != MACH_MSG_TYPE_PORT_SEND) + error("Incorrect right extracted, (map_inferior_port_name)"); + + ret = mach_port_deallocate (mach_task_self (), + iport); + CHK ("Deallocating mapped port (map_inferior_port_name)", ret); + + return iport; +} + +/* + * Naming convention: + * Always return user defined name if found. + * _K == A kernel thread with no matching CPROC + * _C == A cproc with no current cthread + * _t == A cthread with no user defined name + * + * The digits that follow the _names are the SLOT number of the + * kernel thread if there is such a thing, otherwise just a negation + * of the sequential number of such cprocs. + */ + +static char buf[7]; + +static char * +get_thread_name (one_cproc, id) + gdb_thread_t one_cproc; + int id; +{ + if (one_cproc) + if (one_cproc->cthread == NULL) + { + /* cproc not mapped to any cthread */ + sprintf(buf, "_C%d", id); + } + else if (! one_cproc->cthread->name) + { + /* cproc and cthread, but no name */ + sprintf(buf, "_t%d", id); + } + else + return (char *)(one_cproc->cthread->name); + else + { + if (id < 0) + warning ("Inconsistency in thread name id %d", id); + + /* Kernel thread without cproc */ + sprintf(buf, "_K%d", id); + } + + return buf; +} + +int +fetch_thread_info (task, mthreads_out) + mach_port_t task; + gdb_thread_t *mthreads_out; /* out */ +{ + kern_return_t ret; + thread_array_t th_table; + int th_count; + gdb_thread_t mthreads = NULL; + int index; + + ret = task_threads (task, &th_table, &th_count); + if (ret != KERN_SUCCESS) + { + warning ("Error getting inferior's thread list:%s", + mach_error_string(ret)); + m3_kill_inferior (); + return -1; + } + + mthreads = (gdb_thread_t) + obstack_alloc + (cproc_obstack, + th_count * sizeof (struct gdb_thread)); + + for (index = 0; index < th_count; index++) + { + thread_t saved_thread = MACH_PORT_NULL; + int mid; + + if (must_suspend_thread) + setup_thread (th_table[ index ], 1); + + if (th_table[index] != current_thread) + { + saved_thread = current_thread; + + mid = switch_to_thread (th_table[ index ]); + } + + mthreads[index].name = th_table[index]; + mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */ + mthreads[index].in_emulator = FALSE; + mthreads[index].slotid = index; + + mthreads[index].sp = read_register (SP_REGNUM); + mthreads[index].fp = read_register (FP_REGNUM); + mthreads[index].pc = read_pc (); + + if (MACH_PORT_VALID (saved_thread)) + mid = switch_to_thread (saved_thread); + + if (must_suspend_thread) + setup_thread (th_table[ index ], 0); + } + + consume_send_rights (th_table, th_count); + ret = vm_deallocate (mach_task_self(), (vm_address_t)th_table, + (th_count * sizeof(mach_port_t))); + if (ret != KERN_SUCCESS) + { + warning ("Error trying to deallocate thread list : %s", + mach_error_string (ret)); + } + + *mthreads_out = mthreads; + + return th_count; +} + + +/* + * Current emulator always saves the USP on top of + * emulator stack below struct emul_stack_top stuff. + */ +CORE_ADDR +fetch_usp_from_emulator_stack (sp) + CORE_ADDR sp; +{ + CORE_ADDR stack_pointer; + + sp = (sp & ~(EMULATOR_STACK_SIZE-1)) + + EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top); + + if (mach3_read_inferior (sp, + &stack_pointer, + sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) + { + warning ("Can't read user sp from emulator stack address 0x%x", sp); + return 0; + } + + return stack_pointer; +} + +#ifdef MK67 + +/* get_emulation_vector() interface was changed after mk67 */ +#define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */ + +#endif /* MK67 */ + +/* Check if the emulator exists at task's address space. + */ +boolean_t +have_emulator_p (task) + task_t task; +{ + kern_return_t ret; +#ifndef EMUL_VECTOR_COUNT + vm_offset_t *emulation_vector; + int n; +#else + vm_offset_t emulation_vector[ EMUL_VECTOR_COUNT ]; + int n = EMUL_VECTOR_COUNT; +#endif + int i; + int vector_start; + + ret = task_get_emulation_vector (task, + &vector_start, +#ifndef EMUL_VECTOR_COUNT + &emulation_vector, +#else + emulation_vector, +#endif + &n); + CHK("task_get_emulation_vector", ret); + xx_debug ("%d vectors from %d at 0x%08x\n", + n, vector_start, emulation_vector); + + for(i = 0; i < n; i++) + { + vm_offset_t entry = emulation_vector [i]; + + if (EMULATOR_BASE <= entry && entry <= EMULATOR_END) + return TRUE; + else if (entry) + { + static boolean_t informed = FALSE; + if (!informed) + { + warning("Emulation vector address 0x08%x outside emulator space", + entry); + informed = TRUE; + } + } + } + return FALSE; +} + +/* Map cprocs to kernel threads and vice versa. */ + +void +map_cprocs_to_kernel_threads (cprocs, mthreads, thread_count) + gdb_thread_t cprocs; + gdb_thread_t mthreads; + int thread_count; +{ + int index; + gdb_thread_t scan; + boolean_t all_mapped = TRUE; + LONGEST stack_base; + LONGEST stack_size; + + for (scan = cprocs; scan; scan = scan->next) + { + /* Default to: no kernel thread for this cproc */ + scan->reverse_map = -1; + + /* Check if the cproc is found by its stack */ + for (index = 0; index < thread_count; index++) + { + stack_base = + extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET, + CPROC_BASE_SIZE); + stack_size = + extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET, + CPROC_SIZE_SIZE); + if ((mthreads + index)->sp > stack_base && + (mthreads + index)->sp <= stack_base + stack_size) + { + (mthreads + index)->cproc = scan; + scan->reverse_map = index; + break; + } + } + all_mapped &= (scan->reverse_map != -1); + } + + /* Check for threads that are currently in the emulator. + * If so, they have a different stack, and the still unmapped + * cprocs may well get mapped to these threads. + * + * If: + * - cproc stack does not match any kernel thread stack pointer + * - there is at least one extra kernel thread + * that has no cproc mapped above. + * - some kernel thread stack pointer points to emulator space + * then we find the user stack pointer saved in the emulator + * stack, and try to map that to the cprocs. + * + * Also set in_emulator for kernel threads. + */ + + if (emulator_present) + { + for (index = 0; index < thread_count; index++) + { + CORE_ADDR emul_sp; + CORE_ADDR usp; + + gdb_thread_t mthread = (mthreads+index); + emul_sp = mthread->sp; + + if (mthread->cproc == NULL && + EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END) + { + mthread->in_emulator = emulator_present; + + if (!all_mapped && cprocs) + { + usp = fetch_usp_from_emulator_stack (emul_sp); + + /* @@ Could be more accurate */ + if (! usp) + error ("Zero stack pointer read from emulator?"); + + /* Try to match this stack pointer to the cprocs that + * don't yet have a kernel thread. + */ + for (scan = cprocs; scan; scan = scan->next) + { + + /* Check is this unmapped CPROC stack contains + * the user stack pointer saved in the + * emulator. + */ + if (scan->reverse_map == -1) + { + stack_base = + extract_signed_integer + (scan->raw_cproc + CPROC_BASE_OFFSET, + CPROC_BASE_SIZE); + stack_size = + extract_signed_integer + (scan->raw_cproc + CPROC_SIZE_OFFSET, + CPROC_SIZE_SIZE); + if (usp > stack_base && + usp <= stack_base + stack_size) + { + mthread->cproc = scan; + scan->reverse_map = index; + break; + } + } + } + } + } + } + } +} + +/* + * Format of the thread_list command + * + * slot mid sel name emul ks susp cstate wired address + */ +#define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s " + +#define TL_HEADER "\n@ MID Name KState CState Where\n" + +void +print_tl_address (stream, pc) + GDB_FILE *stream; + CORE_ADDR pc; +{ + if (! lookup_minimal_symbol_by_pc (pc)) + fprintf_filtered (stream, local_hex_format(), pc); + else + { + extern int addressprint; + extern int asm_demangle; + + int store = addressprint; + addressprint = 0; + print_address_symbolic (pc, stream, asm_demangle, ""); + addressprint = store; + } +} + +/* For thread names, but also for gdb_message_port external name */ +#define MAX_NAME_LEN 50 + +/* Returns the address of variable NAME or 0 if not found */ +CORE_ADDR +lookup_address_of_variable (name) + char *name; +{ + struct symbol *sym; + CORE_ADDR symaddr = 0; + struct minimal_symbol *msymbol; + + sym = lookup_symbol (name, + (struct block *)NULL, + VAR_NAMESPACE, + (int *)NULL, + (struct symtab **)NULL); + + if (sym) + symaddr = SYMBOL_VALUE (sym); + + if (! symaddr) + { + msymbol = lookup_minimal_symbol (name, NULL, NULL); + + if (msymbol && msymbol->type == mst_data) + symaddr = SYMBOL_VALUE_ADDRESS (msymbol); + } + + return symaddr; +} + +static gdb_thread_t +get_cprocs() +{ + gdb_thread_t cproc_head; + gdb_thread_t cproc_copy; + CORE_ADDR their_cprocs; + char *buf[TARGET_PTR_BIT / HOST_CHAR_BIT]; + char *name; + cthread_t cthread; + CORE_ADDR symaddr; + + symaddr = lookup_address_of_variable ("cproc_list"); + + if (! symaddr) + { + /* cproc_list is not in a file compiled with debugging + symbols, but don't give up yet */ + + symaddr = lookup_address_of_variable ("cprocs"); + + if (symaddr) + { + static int informed = 0; + if (!informed) + { + informed++; + warning ("Your program is loaded with an old threads library."); + warning ("GDB does not know the old form of threads"); + warning ("so things may not work."); + } + } + } + + /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */ + if (! symaddr) + return NULL; + + /* Get the address of the first cproc in the task */ + if (!mach3_read_inferior (symaddr, + buf, + TARGET_PTR_BIT / HOST_CHAR_BIT)) + error ("Can't read cproc master list at address (0x%x).", symaddr); + their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT); + + /* Scan the CPROCs in the task. + CPROCs are chained with LIST field, not NEXT field, which + chains mutexes, condition variables and queues */ + + cproc_head = NULL; + + while (their_cprocs != (CORE_ADDR)0) + { + CORE_ADDR cproc_copy_incarnation; + cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack, + sizeof (struct gdb_thread)); + + if (!mach3_read_inferior (their_cprocs, + &cproc_copy->raw_cproc[0], + CPROC_SIZE)) + error("Can't read next cproc at 0x%x.", their_cprocs); + + their_cprocs = + extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET, + CPROC_LIST_SIZE); + cproc_copy_incarnation = + extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET, + CPROC_INCARNATION_SIZE); + + if (cproc_copy_incarnation == (CORE_ADDR)0) + cproc_copy->cthread = NULL; + else + { + /* This CPROC has an attached CTHREAD. Get its name */ + cthread = (cthread_t)obstack_alloc (cproc_obstack, + sizeof(struct cthread)); + + if (!mach3_read_inferior (cproc_copy_incarnation, + cthread, + sizeof(struct cthread))) + error("Can't read next thread at 0x%x.", + cproc_copy_incarnation); + + cproc_copy->cthread = cthread; + + if (cthread->name) + { + name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN); + + if (!mach3_read_inferior(cthread->name, name, MAX_NAME_LEN)) + error("Can't read next thread's name at 0x%x.", cthread->name); + + cthread->name = name; + } + } + + /* insert in front */ + cproc_copy->next = cproc_head; + cproc_head = cproc_copy; + } + return cproc_head; +} + +#ifndef FETCH_CPROC_STATE +/* + * Check if your machine does not grok the way this routine + * fetches the FP,PC and SP of a cproc that is not + * currently attached to any kernel thread (e.g. its cproc.context + * field points to the place in stack where the context + * is saved). + * + * If it doesn't, define your own routine. + */ +#define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth) + +int +mach3_cproc_state (mthread) + gdb_thread_t mthread; +{ + int context; + + if (! mthread || !mthread->cproc) + return -1; + + context = extract_signed_integer + (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET, + CPROC_CONTEXT_SIZE); + if (context == 0) + return -1; + + mthread->sp = context + MACHINE_CPROC_SP_OFFSET; + + if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET, + &mthread->pc, + sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) + { + warning ("Can't read cproc pc from inferior"); + return -1; + } + + if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET, + &mthread->fp, + sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) + { + warning ("Can't read cproc fp from inferior"); + return -1; + } + + return 0; +} +#endif /* FETCH_CPROC_STATE */ + + +void +thread_list_command() +{ + thread_basic_info_data_t ths; + int thread_count; + gdb_thread_t cprocs; + gdb_thread_t scan; + int index; + char *name; + char selected; + char *wired; + int infoCnt; + kern_return_t ret; + mach_port_t mid_or_port; + gdb_thread_t their_threads; + gdb_thread_t kthread; + + int neworder = 1; + + char *fmt = "There are %d kernel threads in task %d.\n"; + + int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); + + MACH_ERROR_NO_INFERIOR; + + thread_count = fetch_thread_info (inferior_task, + &their_threads); + if (thread_count == -1) + return; + + if (thread_count == 1) + fmt = "There is %d kernel thread in task %d.\n"; + + printf_filtered (fmt, thread_count, tmid); + + puts_filtered (TL_HEADER); + + cprocs = get_cprocs(); + + map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count); + + for (scan = cprocs; scan; scan = scan->next) + { + int mid; + char buf[10]; + char slot[3]; + int cproc_state = + extract_signed_integer + (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE); + + selected = ' '; + + /* a wired cproc? */ + wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET, + CPROC_WIRED_SIZE) + ? "wired" : ""); + + if (scan->reverse_map != -1) + kthread = (their_threads + scan->reverse_map); + else + kthread = NULL; + + if (kthread) + { + /* These cprocs have a kernel thread */ + + mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD); + + infoCnt = THREAD_BASIC_INFO_COUNT; + + ret = thread_info (kthread->name, + THREAD_BASIC_INFO, + (thread_info_t)&ths, + &infoCnt); + + if (ret != KERN_SUCCESS) + { + warning ("Unable to get basic info on thread %d : %s", + mid, + mach_error_string (ret)); + continue; + } + + /* Who is the first to have more than 100 threads */ + sprintf (slot, "%d", kthread->slotid%100); + + if (kthread->name == current_thread) + selected = '*'; + + if (ths.suspend_count) + sprintf (buf, "%d", ths.suspend_count); + else + buf[0] = '\000'; + +#if 0 + if (ths.flags & TH_FLAGS_SWAPPED) + strcat (buf, "S"); +#endif + + if (ths.flags & TH_FLAGS_IDLE) + strcat (buf, "I"); + + printf_filtered (TL_FORMAT, + slot, + mid, + selected, + get_thread_name (scan, kthread->slotid), + kthread->in_emulator ? "E" : "", + translate_state (ths.run_state), + buf, + translate_cstate (cproc_state), + wired); + print_tl_address (gdb_stdout, kthread->pc); + } + else + { + /* These cprocs don't have a kernel thread. + * find out the calling frame with + * FETCH_CPROC_STATE. + */ + + struct gdb_thread state; + +#if 0 + /* jtv -> emcmanus: why do you want this here? */ + if (scan->incarnation == NULL) + continue; /* EMcM */ +#endif + + printf_filtered (TL_FORMAT, + "-", + -neworder, /* Pseudo MID */ + selected, + get_thread_name (scan, -neworder), + "", + "-", /* kernel state */ + "", + translate_cstate (cproc_state), + ""); + state.cproc = scan; + + if (FETCH_CPROC_STATE (&state) == -1) + puts_filtered ("???"); + else + print_tl_address (gdb_stdout, state.pc); + + neworder++; + } + puts_filtered ("\n"); + } + + /* Scan for kernel threads without cprocs */ + for (index = 0; index < thread_count; index++) + { + if (! their_threads[index].cproc) + { + int mid; + + char buf[10]; + char slot[3]; + + mach_port_t name = their_threads[index].name; + + mid = map_port_name_to_mid (name, MACH_TYPE_THREAD); + + infoCnt = THREAD_BASIC_INFO_COUNT; + + ret = thread_info(name, + THREAD_BASIC_INFO, + (thread_info_t)&ths, + &infoCnt); + + if (ret != KERN_SUCCESS) + { + warning ("Unable to get basic info on thread %d : %s", + mid, + mach_error_string (ret)); + continue; + } + + sprintf (slot, "%d", index%100); + + if (name == current_thread) + selected = '*'; + else + selected = ' '; + + if (ths.suspend_count) + sprintf (buf, "%d", ths.suspend_count); + else + buf[0] = '\000'; + +#if 0 + if (ths.flags & TH_FLAGS_SWAPPED) + strcat (buf, "S"); +#endif + + if (ths.flags & TH_FLAGS_IDLE) + strcat (buf, "I"); + + printf_filtered (TL_FORMAT, + slot, + mid, + selected, + get_thread_name (NULL, index), + their_threads[index].in_emulator ? "E" : "", + translate_state (ths.run_state), + buf, + "", /* No cproc state */ + ""); /* Can't be wired */ + print_tl_address (gdb_stdout, their_threads[index].pc); + puts_filtered ("\n"); + } + } + + obstack_free (cproc_obstack, 0); + obstack_init (cproc_obstack); +} + +void +thread_select_command(args, from_tty) + char *args; + int from_tty; +{ + int mid; + thread_array_t thread_list; + int thread_count; + kern_return_t ret; + int is_slot = 0; + + MACH_ERROR_NO_INFERIOR; + + if (!args) + error_no_arg ("MID or @SLOTNUMBER to specify a thread to select"); + + while (*args == ' ' || *args == '\t') + args++; + + if (*args == '@') + { + is_slot++; + args++; + } + + mid = atoi(args); + + if (mid == 0) + if (!is_slot || *args != '0') /* Rudimentary checks */ + error ("You must select threads by MID or @SLOTNUMBER"); + + if (select_thread (inferior_task, mid, is_slot?2:1) != KERN_SUCCESS) + return; + + if (from_tty) + printf_filtered ("Thread %d selected\n", + is_slot ? map_port_name_to_mid (current_thread, + MACH_TYPE_THREAD) : mid); +} + +thread_trace (thread, set) +mach_port_t thread; +boolean_t set; +{ + int flavor = TRACE_FLAVOR; + unsigned int stateCnt = TRACE_FLAVOR_SIZE; + kern_return_t ret; + thread_state_data_t state; + + if (! MACH_PORT_VALID (thread)) + { + warning ("thread_trace: invalid thread"); + return; + } + + if (must_suspend_thread) + setup_thread (thread, 1); + + ret = thread_get_state(thread, flavor, state, &stateCnt); + CHK ("thread_trace: error reading thread state", ret); + + if (set) + { + TRACE_SET (thread, state); + } + else + { + if (! TRACE_CLEAR (thread, state)) + { + if (must_suspend_thread) + setup_thread (thread, 0); + return; + } + } + + ret = thread_set_state(thread, flavor, state, stateCnt); + CHK ("thread_trace: error writing thread state", ret); + if (must_suspend_thread) + setup_thread (thread, 0); +} + +#ifdef FLUSH_INFERIOR_CACHE + +/* When over-writing code on some machines the I-Cache must be flushed + explicitly, because it is not kept coherent by the lazy hardware. + This definitely includes breakpoints, for instance, or else we + end up looping in mysterious Bpt traps */ + +flush_inferior_icache(pc, amount) + CORE_ADDR pc; +{ + vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH; + kern_return_t ret; + + ret = vm_machine_attribute (inferior_task, + pc, + amount, + MATTR_CACHE, + &flush); + if (ret != KERN_SUCCESS) + warning ("Error flushing inferior's cache : %s", + mach_error_string (ret)); +} +#endif FLUSH_INFERIOR_CACHE + + +static +suspend_all_threads (from_tty) + int from_tty; +{ + kern_return_t ret; + thread_array_t thread_list; + int thread_count, index; + int infoCnt; + thread_basic_info_data_t th_info; + + + ret = task_threads (inferior_task, &thread_list, &thread_count); + if (ret != KERN_SUCCESS) + { + warning ("Could not suspend inferior threads."); + m3_kill_inferior (); + return_to_top_level (RETURN_ERROR); + } + + for (index = 0; index < thread_count; index++) + { + int mid; + + mid = map_port_name_to_mid (thread_list[ index ], + MACH_TYPE_THREAD); + + ret = thread_suspend(thread_list[ index ]); + + if (ret != KERN_SUCCESS) + warning ("Error trying to suspend thread %d : %s", + mid, mach_error_string (ret)); + + if (from_tty) + { + infoCnt = THREAD_BASIC_INFO_COUNT; + ret = thread_info (thread_list[ index ], + THREAD_BASIC_INFO, + (thread_info_t) &th_info, + &infoCnt); + CHK ("suspend can't get thread info", ret); + + warning ("Thread %d suspend count is %d", + mid, th_info.suspend_count); + } + } + + consume_send_rights (thread_list, thread_count); + ret = vm_deallocate(mach_task_self(), + (vm_address_t)thread_list, + (thread_count * sizeof(int))); + CHK ("Error trying to deallocate thread list", ret); +} + +void +thread_suspend_command (args, from_tty) + char *args; + int from_tty; +{ + kern_return_t ret; + int mid; + mach_port_t saved_thread; + int infoCnt; + thread_basic_info_data_t th_info; + + MACH_ERROR_NO_INFERIOR; + + if (!strcasecmp (args, "all")) { + suspend_all_threads (from_tty); + return; + } + + saved_thread = current_thread; + + mid = parse_thread_id (args, 0, 0); + + if (mid < 0) + error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER"); + + if (mid == 0) + mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); + else + if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) + { + if (current_thread) + current_thread = saved_thread; + error ("Could not select thread %d", mid); + } + + ret = thread_suspend (current_thread); + if (ret != KERN_SUCCESS) + warning ("thread_suspend failed : %s", + mach_error_string (ret)); + + infoCnt = THREAD_BASIC_INFO_COUNT; + ret = thread_info (current_thread, + THREAD_BASIC_INFO, + (thread_info_t) &th_info, + &infoCnt); + CHK ("suspend can't get thread info", ret); + + warning ("Thread %d suspend count is %d", mid, th_info.suspend_count); + + current_thread = saved_thread; +} + +resume_all_threads (from_tty) + int from_tty; +{ + kern_return_t ret; + thread_array_t thread_list; + int thread_count, index; + int mid; + int infoCnt; + thread_basic_info_data_t th_info; + + ret = task_threads (inferior_task, &thread_list, &thread_count); + if (ret != KERN_SUCCESS) + { + m3_kill_inferior (); + error("task_threads", mach_error_string( ret)); + } + + for (index = 0; index < thread_count; index++) + { + infoCnt = THREAD_BASIC_INFO_COUNT; + ret = thread_info (thread_list [ index ], + THREAD_BASIC_INFO, + (thread_info_t) &th_info, + &infoCnt); + CHK ("resume_all can't get thread info", ret); + + mid = map_port_name_to_mid (thread_list[ index ], + MACH_TYPE_THREAD); + + if (! th_info.suspend_count) + { + if (mid != -1 && from_tty) + warning ("Thread %d is not suspended", mid); + continue; + } + + ret = thread_resume (thread_list[ index ]); + + if (ret != KERN_SUCCESS) + warning ("Error trying to resume thread %d : %s", + mid, mach_error_string (ret)); + else if (mid != -1 && from_tty) + warning ("Thread %d suspend count is %d", + mid, --th_info.suspend_count); + } + + consume_send_rights (thread_list, thread_count); + ret = vm_deallocate(mach_task_self(), + (vm_address_t)thread_list, + (thread_count * sizeof(int))); + CHK("Error trying to deallocate thread list", ret); +} + +void +thread_resume_command (args, from_tty) + char *args; + int from_tty; +{ + int mid; + mach_port_t saved_thread; + kern_return_t ret; + thread_basic_info_data_t th_info; + int infoCnt = THREAD_BASIC_INFO_COUNT; + + MACH_ERROR_NO_INFERIOR; + + if (!strcasecmp (args, "all")) { + resume_all_threads (from_tty); + return; + } + + saved_thread = current_thread; + + mid = parse_thread_id (args, 0, 0); + + if (mid < 0) + error ("You can resume only existing kernel threads with MID or @SLOTNUMBER"); + + if (mid == 0) + mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); + else + if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) + { + if (current_thread) + current_thread = saved_thread; + return_to_top_level (RETURN_ERROR); + } + + ret = thread_info (current_thread, + THREAD_BASIC_INFO, + (thread_info_t) &th_info, + &infoCnt); + CHK ("resume can't get thread info", ret); + + if (! th_info.suspend_count) + { + warning ("Thread %d is not suspended", mid); + goto out; + } + + ret = thread_resume (current_thread); + if (ret != KERN_SUCCESS) + warning ("thread_resume failed : %s", + mach_error_string (ret)); + else + { + th_info.suspend_count--; + warning ("Thread %d suspend count is %d", mid, th_info.suspend_count); + } + + out: + current_thread = saved_thread; +} + +void +thread_kill_command (args, from_tty) + char *args; + int from_tty; +{ + int mid; + kern_return_t ret; + int thread_count; + thread_array_t thread_table; + int index; + mach_port_t thread_to_kill = MACH_PORT_NULL; + + + MACH_ERROR_NO_INFERIOR; + + if (!args) + error_no_arg ("thread mid to kill from the inferior task"); + + mid = parse_thread_id (args, 0, 0); + + if (mid < 0) + error ("You can kill only existing kernel threads with MID or @SLOTNUMBER"); + + if (mid) + { + ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill); + CHK ("thread_kill_command: machid_mach_port map failed", ret); + } + else + mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); + + /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */ + ret = task_threads (inferior_task, &thread_table, &thread_count); + CHK ("Error getting inferior's thread list", ret); + + if (thread_to_kill == current_thread) + { + ret = thread_terminate (thread_to_kill); + CHK ("Thread could not be terminated", ret); + + if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS) + warning ("Last thread was killed, use \"kill\" command to kill task"); + } + else + for (index = 0; index < thread_count; index++) + if (thread_table [ index ] == thread_to_kill) + { + ret = thread_terminate (thread_to_kill); + CHK ("Thread could not be terminated", ret); + } + + if (thread_count > 1) + consume_send_rights (thread_table, thread_count); + + ret = vm_deallocate (mach_task_self(), (vm_address_t)thread_table, + (thread_count * sizeof(mach_port_t))); + CHK ("Error trying to deallocate thread list", ret); + + warning ("Thread %d killed", mid); +} + + +/* Task specific commands; add more if you like */ + +void +task_resume_command (args, from_tty) + char *args; + int from_tty; +{ + kern_return_t ret; + task_basic_info_data_t ta_info; + int infoCnt = TASK_BASIC_INFO_COUNT; + int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); + + MACH_ERROR_NO_INFERIOR; + + /* Would be trivial to change, but is it desirable? */ + if (args) + error ("Currently gdb can resume only it's inferior task"); + + ret = task_info (inferior_task, + TASK_BASIC_INFO, + (task_info_t) &ta_info, + &infoCnt); + CHK ("task_resume_command: task_info failed", ret); + + if (ta_info.suspend_count == 0) + error ("Inferior task %d is not suspended", mid); + else if (ta_info.suspend_count == 1 && + from_tty && + !query ("Suspend count is now 1. Do you know what you are doing? ")) + error ("Task not resumed"); + + ret = task_resume (inferior_task); + CHK ("task_resume_command: task_resume", ret); + + if (ta_info.suspend_count == 1) + { + warning ("Inferior task %d is no longer suspended", mid); + must_suspend_thread = 1; + /* @@ This is not complete: Registers change all the time when not + suspended! */ + registers_changed (); + } + else + warning ("Inferior task %d suspend count is now %d", + mid, ta_info.suspend_count-1); +} + + +void +task_suspend_command (args, from_tty) + char *args; + int from_tty; +{ + kern_return_t ret; + task_basic_info_data_t ta_info; + int infoCnt = TASK_BASIC_INFO_COUNT; + int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); + + MACH_ERROR_NO_INFERIOR; + + /* Would be trivial to change, but is it desirable? */ + if (args) + error ("Currently gdb can suspend only it's inferior task"); + + ret = task_suspend (inferior_task); + CHK ("task_suspend_command: task_suspend", ret); + + must_suspend_thread = 0; + + ret = task_info (inferior_task, + TASK_BASIC_INFO, + (task_info_t) &ta_info, + &infoCnt); + CHK ("task_suspend_command: task_info failed", ret); + + warning ("Inferior task %d suspend count is now %d", + mid, ta_info.suspend_count); +} + +static char * +get_size (bytes) + int bytes; +{ + static char size [ 30 ]; + int zz = bytes/1024; + + if (zz / 1024) + sprintf (size, "%-2.1f M", ((float)bytes)/(1024.0*1024.0)); + else + sprintf (size, "%d K", zz); + + return size; +} + +/* Does this require the target task to be suspended?? I don't think so. */ +void +task_info_command (args, from_tty) + char *args; + int from_tty; +{ + int mid = -5; + mach_port_t task; + kern_return_t ret; + task_basic_info_data_t ta_info; + int infoCnt = TASK_BASIC_INFO_COUNT; + int page_size = round_page(1); + int thread_count = 0; + + if (MACH_PORT_VALID (inferior_task)) + mid = map_port_name_to_mid (inferior_task, + MACH_TYPE_TASK); + + task = inferior_task; + + if (args) + { + int tmid = atoi (args); + + if (tmid <= 0) + error ("Invalid mid %d for task info", tmid); + + if (tmid != mid) + { + mid = tmid; + ret = machid_mach_port (mid_server, mid_auth, tmid, &task); + CHK ("task_info_command: machid_mach_port map failed", ret); + } + } + + if (mid < 0) + error ("You have to give the task MID as an argument"); + + ret = task_info (task, + TASK_BASIC_INFO, + (task_info_t) &ta_info, + &infoCnt); + CHK ("task_info_command: task_info failed", ret); + + printf_filtered ("\nTask info for task %d:\n\n", mid); + printf_filtered (" Suspend count : %d\n", ta_info.suspend_count); + printf_filtered (" Base priority : %d\n", ta_info.base_priority); + printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size)); + printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size)); + + { + thread_array_t thread_list; + + ret = task_threads (task, &thread_list, &thread_count); + CHK ("task_info_command: task_threads", ret); + + printf_filtered (" Thread count : %d\n", thread_count); + + consume_send_rights (thread_list, thread_count); + ret = vm_deallocate(mach_task_self(), + (vm_address_t)thread_list, + (thread_count * sizeof(int))); + CHK("Error trying to deallocate thread list", ret); + } + if (have_emulator_p (task)) + printf_filtered (" Emulator at : 0x%x..0x%x\n", + EMULATOR_BASE, EMULATOR_END); + else + printf_filtered (" No emulator.\n"); + + if (thread_count && task == inferior_task) + printf_filtered ("\nUse the \"thread list\" command to see the threads\n"); +} + +/* You may either FORWARD the exception to the inferior, or KEEP + * it and return to GDB command level. + * + * exception mid [ forward | keep ] + */ + +static void +exception_command (args, from_tty) + char *args; + int from_tty; +{ + char *scan = args; + int exception; + int len; + + if (!args) + error_no_arg ("exception number action"); + + while (*scan == ' ' || *scan == '\t') scan++; + + if ('0' <= *scan && *scan <= '9') + while ('0' <= *scan && *scan <= '9') + scan++; + else + error ("exception number action"); + + exception = atoi (args); + if (exception <= 0 || exception > MAX_EXCEPTION) + error ("Allowed exception numbers are in range 1..%d", + MAX_EXCEPTION); + + if (*scan != ' ' && *scan != '\t') + error ("exception number must be followed by a space"); + else + while (*scan == ' ' || *scan == '\t') scan++; + + args = scan; + len = 0; + while (*scan) + { + len++; + scan++; + } + + if (!len) + error("exception number action"); + + if (!strncasecmp (args, "forward", len)) + exception_map[ exception ].forward = TRUE; + else if (!strncasecmp (args, "keep", len)) + exception_map[ exception ].forward = FALSE; + else + error ("exception action is either \"keep\" or \"forward\""); +} + +static void +print_exception_info (exception) + int exception; +{ + boolean_t forward = exception_map[ exception ].forward; + + printf_filtered ("%s\t(%d): ", exception_map[ exception ].name, + exception); + if (!forward) + if (exception_map[ exception ].sigmap != SIG_UNKNOWN) + printf_filtered ("keep and handle as signal %d\n", + exception_map[ exception ].sigmap); + else + printf_filtered ("keep and handle as unknown signal %d\n", + exception_map[ exception ].sigmap); + else + printf_filtered ("forward exception to inferior\n"); +} + +void +exception_info (args, from_tty) + char *args; + int from_tty; +{ + int exception; + + if (!args) + for (exception = 1; exception <= MAX_EXCEPTION; exception++) + print_exception_info (exception); + else + { + exception = atoi (args); + + if (exception <= 0 || exception > MAX_EXCEPTION) + error ("Invalid exception number, values from 1 to %d allowed", + MAX_EXCEPTION); + print_exception_info (exception); + } +} + +/* Check for actions for mach exceptions. + */ +mach3_exception_actions (w, force_print_only, who) + WAITTYPE *w; + boolean_t force_print_only; + char *who; +{ + boolean_t force_print = FALSE; + + + if (force_print_only || + exception_map[stop_exception].sigmap == SIG_UNKNOWN) + force_print = TRUE; + else + WSETSTOP (*w, exception_map[stop_exception].sigmap); + + if (exception_map[stop_exception].print || force_print) + { + target_terminal_ours (); + + printf_filtered ("\n%s received %s exception : ", + who, + exception_map[stop_exception].name); + + wrap_here (" "); + + switch(stop_exception) { + case EXC_BAD_ACCESS: + printf_filtered ("referencing address 0x%x : %s\n", + stop_subcode, + mach_error_string (stop_code)); + break; + case EXC_BAD_INSTRUCTION: + printf_filtered + ("illegal or undefined instruction. code %d subcode %d\n", + stop_code, stop_subcode); + break; + case EXC_ARITHMETIC: + printf_filtered ("code %d\n", stop_code); + break; + case EXC_EMULATION: + printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode); + break; + case EXC_SOFTWARE: + printf_filtered ("%s specific, code 0x%x\n", + stop_code < 0xffff ? "hardware" : "os emulation", + stop_code); + break; + case EXC_BREAKPOINT: + printf_filtered ("type %d (machine dependent)\n", + stop_code); + break; + default: + fatal ("Unknown exception"); + } + } +} + +setup_notify_port (create_new) + int create_new; +{ + kern_return_t ret; + + if (MACH_PORT_VALID (our_notify_port)) + { + ret = mach_port_destroy (mach_task_self (), our_notify_port); + CHK ("Could not destroy our_notify_port", ret); + } + + our_notify_port = MACH_PORT_NULL; + notify_chain = (port_chain_t) NULL; + port_chain_destroy (port_chain_obstack); + + if (create_new) + { + ret = mach_port_allocate (mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &our_notify_port); + if (ret != KERN_SUCCESS) + fatal("Creating notify port %s", mach_error_string(ret)); + + ret = mach_port_move_member(mach_task_self(), + our_notify_port, + inferior_wait_port_set); + if (ret != KERN_SUCCESS) + fatal("initial move member %s",mach_error_string(ret)); + } +} + +/* + * Register our message port to the net name server + * + * Currently used only by the external stop-gdb program + * since ^C does not work if you would like to enter + * gdb command level while debugging your program. + * + * NOTE: If the message port is sometimes used for other + * purposes also, the NAME must not be a guessable one. + * Then, there should be a way to change it. + */ + +char registered_name[ MAX_NAME_LEN ]; + +void +message_port_info (args, from_tty) + char *args; + int from_tty; +{ + if (registered_name[0]) + printf_filtered ("gdb's message port name: '%s'\n", + registered_name); + else + printf_filtered ("gdb's message port is not currently registered\n"); +} + +void +gdb_register_port (name, port) + char *name; + mach_port_t port; +{ + kern_return_t ret; + static int already_signed = 0; + int len; + + if (! MACH_PORT_VALID (port) || !name || !*name) + { + warning ("Invalid registration request"); + return; + } + + if (! already_signed) + { + ret = mach_port_insert_right (mach_task_self (), + our_message_port, + our_message_port, + MACH_MSG_TYPE_MAKE_SEND); + CHK ("Failed to create a signature to our_message_port", ret); + already_signed = 1; + } + else if (already_signed > 1) + { + ret = netname_check_out (name_server_port, + registered_name, + our_message_port); + CHK ("Failed to check out gdb's message port", ret); + registered_name[0] = '\000'; + already_signed = 1; + } + + ret = netname_check_in (name_server_port, /* Name server port */ + name, /* Name of service */ + our_message_port, /* Signature */ + port); /* Creates a new send right */ + CHK("Failed to check in the port", ret); + + len = 0; + while(len < MAX_NAME_LEN && *(name+len)) + { + registered_name[len] = *(name+len); + len++; + } + registered_name[len] = '\000'; + already_signed = 2; +} + +struct cmd_list_element *cmd_thread_list; +struct cmd_list_element *cmd_task_list; + +/*ARGSUSED*/ +static void +thread_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n"); + help_list (cmd_thread_list, "thread ", -1, gdb_stdout); +} + +/*ARGSUSED*/ +static void +task_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"task\" must be followed by the name of a task command.\n"); + help_list (cmd_task_list, "task ", -1, gdb_stdout); +} + +add_mach_specific_commands () +{ + /* Thread handling commands */ + + /* FIXME: Move our thread support into the generic thread.c stuff so we + can share that code. */ + add_prefix_cmd ("mthread", class_stack, thread_command, + "Generic command for handling Mach threads in the debugged task.", + &cmd_thread_list, "thread ", 0, &cmdlist); + + add_com_alias ("th", "mthread", class_stack, 1); + + add_cmd ("select", class_stack, thread_select_command, + "Select and print MID of the selected thread", + &cmd_thread_list); + add_cmd ("list", class_stack, thread_list_command, + "List info of task's threads. Selected thread is marked with '*'", + &cmd_thread_list); + add_cmd ("suspend", class_run, thread_suspend_command, + "Suspend one or all of the threads in the selected task.", + &cmd_thread_list); + add_cmd ("resume", class_run, thread_resume_command, + "Resume one or all of the threads in the selected task.", + &cmd_thread_list); + add_cmd ("kill", class_run, thread_kill_command, + "Kill the specified thread MID from inferior task.", + &cmd_thread_list); +#if 0 + /* The rest of this support (condition_thread) was not merged. It probably + should not be merged in this form, but instead added to the generic GDB + thread support. */ + add_cmd ("break", class_breakpoint, condition_thread, + "Breakpoint N will only be effective for thread MID or @SLOT\n\ + If MID/@SLOT is omitted allow all threads to break at breakpoint", + &cmd_thread_list); +#endif + /* Thread command shorthands (for backward compatibility) */ + add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist); + add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist); + + /* task handling commands */ + + add_prefix_cmd ("task", class_stack, task_command, + "Generic command for handling debugged task.", + &cmd_task_list, "task ", 0, &cmdlist); + + add_com_alias ("ta", "task", class_stack, 1); + + add_cmd ("suspend", class_run, task_suspend_command, + "Suspend the inferior task.", + &cmd_task_list); + add_cmd ("resume", class_run, task_resume_command, + "Resume the inferior task.", + &cmd_task_list); + add_cmd ("info", no_class, task_info_command, + "Print information about the specified task.", + &cmd_task_list); + + /* Print my message port name */ + + add_info ("message-port", message_port_info, + "Returns the name of gdb's message port in the netnameserver"); + + /* Exception commands */ + + add_info ("exceptions", exception_info, + "What debugger does when program gets various exceptions.\n\ +Specify an exception number as argument to print info on that\n\ +exception only."); + + add_com ("exception", class_run, exception_command, + "Specify how to handle an exception.\n\ +Args are exception number followed by \"forward\" or \"keep\".\n\ +`Forward' means forward the exception to the program's normal exception\n\ +handler.\n\ +`Keep' means reenter debugger if this exception happens, and GDB maps\n\ +the exception to some signal (see info exception)\n\ +Normally \"keep\" is used to return to GDB on exception."); +} + +kern_return_t +do_mach_notify_dead_name (notify, name) + mach_port_t notify; + mach_port_t name; +{ + kern_return_t kr = KERN_SUCCESS; + + /* Find the thing that notified */ + port_chain_t element = port_chain_member (notify_chain, name); + + /* Take name of from unreceived dead name notification list */ + notify_chain = port_chain_delete (notify_chain, name); + + if (! element) + error ("Received a dead name notify from unchained port (0x%x)", name); + + switch (element->type) { + + case MACH_TYPE_THREAD: + target_terminal_ours_for_output (); + if (name == current_thread) + { + printf_filtered ("\nCurrent thread %d died", element->mid); + current_thread = MACH_PORT_NULL; + } + else + printf_filtered ("\nThread %d died", element->mid); + + break; + + case MACH_TYPE_TASK: + target_terminal_ours_for_output (); + if (name != inferior_task) + printf_filtered ("Task %d died, but it was not the selected task", + element->mid); + else + { + printf_filtered ("Current task %d died", element->mid); + + mach_port_destroy (mach_task_self(), name); + inferior_task = MACH_PORT_NULL; + + if (notify_chain) + warning ("There were still unreceived dead_name_notifications???"); + + /* Destroy the old notifications */ + setup_notify_port (0); + + } + break; + + default: + error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x", + name, element->type, element->mid); + break; + } + + return KERN_SUCCESS; +} + +kern_return_t +do_mach_notify_msg_accepted (notify, name) + mach_port_t notify; + mach_port_t name; +{ + warning ("do_mach_notify_msg_accepted : notify %x, name %x", + notify, name); + return KERN_SUCCESS; +} + +kern_return_t +do_mach_notify_no_senders (notify, mscount) + mach_port_t notify; + mach_port_mscount_t mscount; +{ + warning ("do_mach_notify_no_senders : notify %x, mscount %x", + notify, mscount); + return KERN_SUCCESS; +} + +kern_return_t +do_mach_notify_port_deleted (notify, name) + mach_port_t notify; + mach_port_t name; +{ + warning ("do_mach_notify_port_deleted : notify %x, name %x", + notify, name); + return KERN_SUCCESS; +} + +kern_return_t +do_mach_notify_port_destroyed (notify, rights) + mach_port_t notify; + mach_port_t rights; +{ + warning ("do_mach_notify_port_destroyed : notify %x, rights %x", + notify, rights); + return KERN_SUCCESS; +} + +kern_return_t +do_mach_notify_send_once (notify) + mach_port_t notify; +{ +#ifdef DUMP_SYSCALL + /* MANY of these are generated. */ + warning ("do_mach_notify_send_once : notify %x", + notify); +#endif + return KERN_SUCCESS; +} + +/* Kills the inferior. It's gone when you call this */ +static void +kill_inferior_fast () +{ + WAITTYPE w; + + if (inferior_pid == 0 || inferior_pid == 1) + return; + + /* kill() it, since the Unix server does not otherwise notice when + * killed with task_terminate(). + */ + if (inferior_pid > 0) + kill (inferior_pid, SIGKILL); + + /* It's propably terminate already */ + (void) task_terminate (inferior_task); + + inferior_task = MACH_PORT_NULL; + current_thread = MACH_PORT_NULL; + + wait3 (&w, WNOHANG, 0); + + setup_notify_port (0); +} + +static void +m3_kill_inferior () +{ + kill_inferior_fast (); + target_mourn_inferior (); +} + +/* Clean up after the inferior dies. */ + +static void +m3_mourn_inferior () +{ + unpush_target (&m3_ops); + generic_mourn_inferior (); +} + + +/* Fork an inferior process, and start debugging it. */ + +static void +m3_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL); + /* We are at the first instruction we care about. */ + /* Pedal to the metal... */ + proceed ((CORE_ADDR) -1, 0, 0); +} + +/* Mark our target-struct as eligible for stray "run" and "attach" + commands. */ +static int +m3_can_run () +{ + return 1; +} + +/* Mach 3.0 does not need ptrace for anything + * Make sure nobody uses it on mach. + */ +ptrace (a,b,c,d) +int a,b,c,d; +{ + error ("Lose, Lose! Somebody called ptrace\n"); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +m3_resume (pid, step, signal) + int pid; + int step; + enum target_signal signal; +{ + kern_return_t ret; + + if (step) + { + thread_basic_info_data_t th_info; + unsigned int infoCnt = THREAD_BASIC_INFO_COUNT; + + /* There is no point in single stepping when current_thread + * is dead. + */ + if (! MACH_PORT_VALID (current_thread)) + error ("No thread selected; can not single step"); + + /* If current_thread is suspended, tracing it would never return. + */ + ret = thread_info (current_thread, + THREAD_BASIC_INFO, + (thread_info_t) &th_info, + &infoCnt); + CHK ("child_resume: can't get thread info", ret); + + if (th_info.suspend_count) + error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it"); + } + + vm_read_cache_valid = FALSE; + + if (signal && inferior_pid > 0) /* Do not signal, if attached by MID */ + kill (inferior_pid, target_signal_to_host (signal)); + + if (step) + { + suspend_all_threads (0); + + setup_single_step (current_thread, TRUE); + + ret = thread_resume (current_thread); + CHK ("thread_resume", ret); + } + + ret = task_resume (inferior_task); + if (ret == KERN_FAILURE) + warning ("Task was not suspended"); + else + CHK ("Resuming task", ret); + + /* HACK HACK This is needed by the multiserver system HACK HACK */ + while ((ret = task_resume(inferior_task)) == KERN_SUCCESS) + /* make sure it really runs */; + /* HACK HACK This is needed by the multiserver system HACK HACK */ +} + +#ifdef ATTACH_DETACH + +/* Start debugging the process with the given task */ +void +task_attach (tid) + task_t tid; +{ + kern_return_t ret; + inferior_task = tid; + + ret = task_suspend (inferior_task); + CHK("task_attach: task_suspend", ret); + + must_suspend_thread = 0; + + setup_notify_port (1); + + request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK); + + setup_exception_port (); + + emulator_present = have_emulator_p (inferior_task); + + attach_flag = 1; +} + +/* Well, we can call error also here and leave the + * target stack inconsistent. Sigh. + * Fix this sometime (the only way to fail here is that + * the task has no threads at all, which is rare, but + * possible; or if the target task has died, which is also + * possible, but unlikely, since it has been suspended. + * (Someone must have killed it)) + */ +void +attach_to_thread () +{ + if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS) + error ("Could not select any threads to attach to"); +} + +mid_attach (mid) + int mid; +{ + kern_return_t ret; + + ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task); + CHK("mid_attach: machid_mach_port", ret); + + task_attach (inferior_task); + + return mid; +} + +/* + * Start debugging the process whose unix process-id is PID. + * A negative "pid" value is legal and signifies a mach_id not a unix pid. + * + * Prevent (possible unwanted) dangerous operations by enabled users + * like "atta 0" or "atta foo" (equal to the previous :-) and + * "atta pidself". Anyway, the latter is allowed by specifying a MID. + */ +static int +m3_do_attach (pid) + int pid; +{ + kern_return_t ret; + + if (pid == 0) + error("MID=0, Debugging the master unix server does not compute"); + + /* Foo. This assumes gdb has a unix pid */ + if (pid == getpid()) + error ("I will debug myself only by mid. (Gdb would suspend itself!)"); + + if (pid < 0) + { + mid_attach (-(pid)); + + /* inferior_pid will be NEGATIVE! */ + inferior_pid = pid; + + return inferior_pid; + } + + inferior_task = task_by_pid (pid); + if (! MACH_PORT_VALID (inferior_task)) + error("Cannot map Unix pid %d to Mach task port", pid); + + task_attach (inferior_task); + + inferior_pid = pid; + + return inferior_pid; +} + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +static void +m3_attach (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + if (!args) + error_no_arg ("process-id to attach"); + + pid = atoi (args); + + if (pid == getpid()) /* Trying to masturbate? */ + error ("I refuse to debug myself!"); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid)); + else + printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid)); + + gdb_flush (gdb_stdout); + } + + m3_do_attach (pid); + inferior_pid = pid; + push_target (&m3_ops); +} + +void +deallocate_inferior_ports () +{ + kern_return_t ret; + thread_array_t thread_list; + int thread_count, index; + + if (!MACH_PORT_VALID (inferior_task)) + return; + + ret = task_threads (inferior_task, &thread_list, &thread_count); + if (ret != KERN_SUCCESS) + { + warning ("deallocate_inferior_ports: task_threads", + mach_error_string(ret)); + return; + } + + /* Get rid of send rights to task threads */ + for (index = 0; index < thread_count; index++) + { + int rights; + ret = mach_port_get_refs (mach_task_self (), + thread_list[index], + MACH_PORT_RIGHT_SEND, + &rights); + CHK("deallocate_inferior_ports: get refs", ret); + + if (rights > 0) + { + ret = mach_port_mod_refs (mach_task_self (), + thread_list[index], + MACH_PORT_RIGHT_SEND, + -rights); + CHK("deallocate_inferior_ports: mod refs", ret); + } + } + + ret = mach_port_mod_refs (mach_task_self (), + inferior_exception_port, + MACH_PORT_RIGHT_RECEIVE, + -1); + CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret); + + ret = mach_port_deallocate (mach_task_self (), + inferior_task); + CHK ("deallocate_task_port: deallocating inferior_task", ret); + + current_thread = MACH_PORT_NULL; + inferior_task = MACH_PORT_NULL; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +static void +m3_do_detach (signal) + int signal; +{ + kern_return_t ret; + + MACH_ERROR_NO_INFERIOR; + + if (current_thread != MACH_PORT_NULL) + { + /* Store the gdb's view of the thread we are deselecting + * before we detach. + * @@ I am really not sure if this is ever needeed. + */ + target_prepare_to_store (); + target_store_registers (-1); + } + + ret = task_set_special_port (inferior_task, + TASK_EXCEPTION_PORT, + inferior_old_exception_port); + CHK ("task_set_special_port", ret); + + /* Discard all requested notifications */ + setup_notify_port (0); + + if (remove_breakpoints ()) + warning ("Could not remove breakpoints when detaching"); + + if (signal && inferior_pid > 0) + kill (inferior_pid, signal); + + /* the task might be dead by now */ + (void) task_resume (inferior_task); + + deallocate_inferior_ports (); + + attach_flag = 0; +} + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via fork. */ + +static void +m3_detach (args, from_tty) + char *args; + int from_tty; +{ + int siggnal = 0; + + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf_unfiltered ("Detaching from program: %s %s\n", + exec_file, target_pid_to_str (inferior_pid)); + gdb_flush (gdb_stdout); + } + if (args) + siggnal = atoi (args); + + m3_do_detach (siggnal); + inferior_pid = 0; + unpush_target (&m3_ops); /* Pop out of handling an inferior */ +} +#endif /* ATTACH_DETACH */ + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +m3_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +/* Print status information about what we're accessing. */ + +static void +m3_files_info (ignore) + struct target_ops *ignore; +{ + /* FIXME: should print MID and all that crap. */ + printf_unfiltered ("\tUsing the running image of %s %s.\n", + attach_flag? "attached": "child", target_pid_to_str (inferior_pid)); +} + +static void +m3_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a Unix child process."); +} + +#ifdef DUMP_SYSCALL +#ifdef __STDC__ +#define STR(x) #x +#else +#define STR(x) "x" +#endif + +char *bsd1_names[] = { + "execve", + "fork", + "take_signal", + "sigreturn", + "getrusage", + "chdir", + "chroot", + "open", + "creat", + "mknod", + "link", + "symlink", + "unlink", + "access", + "stat", + "readlink", + "chmod", + "chown", + "utimes", + "truncate", + "rename", + "mkdir", + "rmdir", + "xutimes", + "mount", + "umount", + "acct", + "setquota", + "write_short", + "write_long", + "send_short", + "send_long", + "sendto_short", + "sendto_long", + "select", + "task_by_pid", + "recvfrom_short", + "recvfrom_long", + "setgroups", + "setrlimit", + "sigvec", + "sigstack", + "settimeofday", + "adjtime", + "setitimer", + "sethostname", + "bind", + "accept", + "connect", + "setsockopt", + "getsockopt", + "getsockname", + "getpeername", + "init_process", + "table_set", + "table_get", + "pioctl", + "emulator_error", + "readwrite", + "share_wakeup", + 0, + "maprw_request_it", + "maprw_release_it", + "maprw_remap", + "pid_by_task", +}; + +int bsd1_nnames = sizeof(bsd1_names)/sizeof(bsd1_names[0]); + +char* +name_str(name,buf) + +int name; +char *buf; + +{ + switch (name) { + case MACH_MSG_TYPE_BOOLEAN: + return "boolean"; + case MACH_MSG_TYPE_INTEGER_16: + return "short"; + case MACH_MSG_TYPE_INTEGER_32: + return "long"; + case MACH_MSG_TYPE_CHAR: + return "char"; + case MACH_MSG_TYPE_BYTE: + return "byte"; + case MACH_MSG_TYPE_REAL: + return "real"; + case MACH_MSG_TYPE_STRING: + return "string"; + default: + sprintf(buf,"%d",name); + return buf; + } +} + +char * +id_str(id,buf) + +int id; +char *buf; + +{ + char *p; + if (id >= 101000 && id < 101000+bsd1_nnames) { + if (p = bsd1_names[id-101000]) + return p; + } + if (id == 102000) + return "psignal_retry"; + if (id == 100000) + return "syscall"; + sprintf(buf,"%d",id); + return buf; +} + +print_msg(mp) +mach_msg_header_t *mp; +{ + char *fmt_x = "%20s : 0x%08x\n"; + char *fmt_d = "%20s : %10d\n"; + char *fmt_s = "%20s : %s\n"; + char buf[100]; + + puts_filtered ("\n"); +#define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x) + pr(fmt_x,(*mp),msgh_bits); + pr(fmt_d,(*mp),msgh_size); + pr(fmt_x,(*mp),msgh_remote_port); + pr(fmt_x,(*mp),msgh_local_port); + pr(fmt_d,(*mp),msgh_kind); + printf_filtered(fmt_s,STR(msgh_id),id_str(mp->msgh_id,buf)); + + if (debug_level > 1) + { + char *p,*ep,*dp; + int plen; + p = (char*)mp; + ep = p+mp->msgh_size; + p += sizeof(*mp); + for(; p < ep; p += plen) { + mach_msg_type_t *tp; + mach_msg_type_long_t *tlp; + int name,size,number; + tp = (mach_msg_type_t*)p; + if (tp->msgt_longform) { + tlp = (mach_msg_type_long_t*)tp; + name = tlp->msgtl_name; + size = tlp->msgtl_size; + number = tlp->msgtl_number; + plen = sizeof(*tlp); + } else { + name = tp->msgt_name; + size = tp->msgt_size; + number = tp->msgt_number; + plen = sizeof(*tp); + } + printf_filtered("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n", + name_str(name,buf),size,number,tp->msgt_inline, + tp->msgt_longform, tp->msgt_deallocate); + dp = p+plen; + if (tp->msgt_inline) { + int l; + l = size*number/8; + l = (l+sizeof(long)-1)&~((sizeof(long))-1); + plen += l; + print_data(dp,size,number); + } else { + plen += sizeof(int*); + } + printf_filtered("plen=%d\n",plen); + } + } +} + +print_data(p,size,number) + +char *p; + +{ + int *ip; + short *sp; + int i; + + switch (size) { + case 8: + for(i = 0; i < number; i++) { + printf_filtered(" %02x",p[i]); + } + break; + case 16: + sp = (short*)p; + for(i = 0; i < number; i++) { + printf_filtered(" %04x",sp[i]); + } + break; + case 32: + ip = (int*)p; + for(i = 0; i < number; i++) { + printf_filtered(" %08x",ip[i]); + } + break; + } + puts_filtered("\n"); +} +#endif DUMP_SYSCALL + +static void +m3_stop () +{ + error ("to_stop target function not implemented"); +} + +struct target_ops m3_ops = { + "mach", /* to_shortname */ + "Mach child process", /* to_longname */ + "Mach child process (started by the \"run\" command).", /* to_doc */ + m3_open, /* to_open */ + 0, /* to_close */ + m3_attach, /* to_attach */ + m3_detach, /* to_detach */ + m3_resume, /* to_resume */ + mach_really_wait, /* to_wait */ + fetch_inferior_registers, /* to_fetch_registers */ + store_inferior_registers, /* to_store_registers */ + m3_prepare_to_store, /* to_prepare_to_store */ + m3_xfer_memory, /* to_xfer_memory */ + m3_files_info, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + terminal_init_inferior, /* to_terminal_init */ + terminal_inferior, /* to_terminal_inferior */ + terminal_ours_for_output, /* to_terminal_ours_for_output */ + terminal_ours, /* to_terminal_ours */ + child_terminal_info, /* to_terminal_info */ + m3_kill_inferior, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + + m3_create_inferior, /* to_create_inferior */ + m3_mourn_inferior, /* to_mourn_inferior */ + m3_can_run, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + m3_stop, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_m3_nat () +{ + kern_return_t ret; + + add_target (&m3_ops); + + ret = mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_PORT_SET, + &inferior_wait_port_set); + if (ret != KERN_SUCCESS) + fatal("initial port set %s",mach_error_string(ret)); + + /* mach_really_wait now waits for this */ + currently_waiting_for = inferior_wait_port_set; + + ret = netname_look_up(name_server_port, hostname, "MachID", &mid_server); + if (ret != KERN_SUCCESS) + { + mid_server = MACH_PORT_NULL; + + warning ("initialize machid: netname_lookup_up(MachID) : %s", + mach_error_string(ret)); + warning ("Some (most?) features disabled..."); + } + + mid_auth = mach_privileged_host_port(); + if (mid_auth == MACH_PORT_NULL) + mid_auth = mach_task_self(); + + obstack_init (port_chain_obstack); + + ret = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, + &thread_exception_port); + CHK ("Creating thread_exception_port for single stepping", ret); + + ret = mach_port_insert_right (mach_task_self (), + thread_exception_port, + thread_exception_port, + MACH_MSG_TYPE_MAKE_SEND); + CHK ("Inserting send right to thread_exception_port", ret); + + /* Allocate message port */ + ret = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, + &our_message_port); + if (ret != KERN_SUCCESS) + warning ("Creating message port %s", mach_error_string (ret)); + else + { + char buf[ MAX_NAME_LEN ]; + ret = mach_port_move_member(mach_task_self (), + our_message_port, + inferior_wait_port_set); + if (ret != KERN_SUCCESS) + warning ("message move member %s", mach_error_string (ret)); + + + /* @@@@ No way to change message port name currently */ + /* Foo. This assumes gdb has a unix pid */ + sprintf (buf, "gdb-%d", getpid ()); + gdb_register_port (buf, our_message_port); + } + + /* Heap for thread commands */ + obstack_init (cproc_obstack); + + add_mach_specific_commands (); +} diff --git a/contrib/gdb/gdb/m68k-stub.c b/contrib/gdb/gdb/m68k-stub.c new file mode 100644 index 000000000000..009cba332585 --- /dev/null +++ b/contrib/gdb/gdb/m68k-stub.c @@ -0,0 +1,1014 @@ +/**************************************************************************** + + 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 putDebugChar(); /* write a single character */ +extern 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); +} + + +/* scan for the sequence $# */ +void getpacket(buffer) +char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$'); + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug ) && (checksum != xmitcsum)) { + fprintf (stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum,xmitcsum,buffer); + } + + 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] ); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + +} + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + + +void putpacket(buffer) +char * buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do { + putDebugChar('$'); + checksum = 0; + count = 0; + + while (ch=buffer[count]) { + if (! putDebugChar(ch)) return; + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + + } while (1 == 0); /* (getDebugChar() != '+'); */ + +} + +char remcomInBuffer[BUFMAX]; +char remcomOutBuffer[BUFMAX]; +static short error; + + +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> 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=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; + 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); + + while (1==1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + 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(&remcomInBuffer[1], (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 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + if (*(ptr++) == ',') + if (hexToInt(&ptr,&length)) + { + ptr = 0; + mem2hex((char*) addr, remcomOutBuffer, length); + } + + if (ptr) + { + strcpy(remcomOutBuffer,"E01"); + debug_error("malformed read memory command: %s",remcomInBuffer); + } + } + 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 */ + ptr = &remcomInBuffer[1]; + 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"); + debug_error("malformed write memory command: %s",remcomInBuffer); + } + } + 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 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + 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 (remcomInBuffer[0] == 's') 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() +{ + 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/gdb/m68k-tdep.c b/contrib/gdb/gdb/m68k-tdep.c new file mode 100644 index 000000000000..f5cc3b0e7435 --- /dev/null +++ b/contrib/gdb/gdb/m68k-tdep.c @@ -0,0 +1,514 @@ +/* Target dependent code for the Motorola 68000 series. + Copyright (C) 1990, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "symtab.h" + + +/* Push an empty stack frame, to record the current PC, etc. */ + +void +m68k_push_dummy_frame () +{ + register CORE_ADDR sp = read_register (SP_REGNUM); + register int regnum; + char raw_buffer[12]; + + sp = push_word (sp, read_register (PC_REGNUM)); + sp = push_word (sp, read_register (FP_REGNUM)); + write_register (FP_REGNUM, sp); + + /* Always save the floating-point registers, whether they exist on + this target or not. */ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) + { + read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); + sp = push_bytes (sp, raw_buffer, 12); + } + + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) + { + sp = push_word (sp, read_register (regnum)); + } + sp = push_word (sp, read_register (PS_REGNUM)); + write_register (SP_REGNUM, sp); +} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +void +m68k_pop_frame () +{ + register struct frame_info *frame = get_current_frame (); + register CORE_ADDR fp; + register int regnum; + struct frame_saved_regs fsr; + struct frame_info *fi; + char raw_buffer[12]; + + fp = FRAME_FP (frame); + get_frame_saved_regs (frame, &fsr); + for (regnum = FP0_REGNUM + 7 ; regnum >= FP0_REGNUM ; regnum--) + { + if (fsr.regs[regnum]) + { + read_memory (fsr.regs[regnum], raw_buffer, 12); + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); + } + } + for (regnum = FP_REGNUM - 1 ; regnum >= 0 ; regnum--) + { + if (fsr.regs[regnum]) + { + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); + } + } + if (fsr.regs[PS_REGNUM]) + { + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); + } + write_register (FP_REGNUM, read_memory_integer (fp, 4)); + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); + write_register (SP_REGNUM, fp + 8); + flush_cached_frames (); +} + + +/* Given an ip value corresponding to the start of a function, + return the ip of the first instruction after the function + prologue. This is the generic m68k support. Machines which + require something different can override the SKIP_PROLOGUE + macro to point elsewhere. + + Some instructions which typically may appear in a function + prologue include: + + A link instruction, word form: + + link.w %a6,&0 4e56 XXXX + + A link instruction, long form: + + link.l %fp,&F%1 480e XXXX XXXX + + A movm instruction to preserve integer regs: + + movm.l &M%1,(4,%sp) 48ef XXXX XXXX + + A fmovm instruction to preserve float regs: + + fmovm &FPM%1,(FPO%1,%sp) f237 XXXX XXXX XXXX XXXX + + Some profiling setup code (FIXME, not recognized yet): + + lea.l (.L3,%pc),%a1 43fb XXXX XXXX XXXX + bsr _mcount 61ff XXXX XXXX + + */ + +#define P_LINK_L 0x480e +#define P_LINK_W 0x4e56 +#define P_MOV_L 0x207c +#define P_JSR 0x4eb9 +#define P_BSR 0x61ff +#define P_LEA_L 0x43fb +#define P_MOVM_L 0x48ef +#define P_FMOVM 0xf237 +#define P_TRAP 0x4e40 + +CORE_ADDR +m68k_skip_prologue (ip) +CORE_ADDR ip; +{ + register CORE_ADDR limit; + struct symtab_and_line sal; + register int op; + + /* Find out if there is a known limit for the extent of the prologue. + If so, ensure we don't go past it. If not, assume "infinity". */ + + sal = find_pc_line (ip, 0); + limit = (sal.end) ? sal.end : (CORE_ADDR) ~0; + + while (ip < limit) + { + op = read_memory_integer (ip, 2); + op &= 0xFFFF; + + if (op == P_LINK_W) + { + ip += 4; /* Skip link.w */ + } + else if (op == 0x4856) + ip += 2; /* Skip pea %fp */ + else if (op == 0x2c4f) + ip += 2; /* Skip move.l %sp, %fp */ + else if (op == P_LINK_L) + { + ip += 6; /* Skip link.l */ + } + else if (op == P_MOVM_L) + { + ip += 6; /* Skip movm.l */ + } + else if (op == P_FMOVM) + { + ip += 10; /* Skip fmovm */ + } + else + { + break; /* Found unknown code, bail out. */ + } + } + return (ip); +} + +void +m68k_find_saved_regs (frame_info, saved_regs) + struct frame_info *frame_info; + struct frame_saved_regs *saved_regs; +{ + register int regnum; + register int regmask; + register CORE_ADDR next_addr; + register CORE_ADDR pc; + + /* First possible address for a pc in a call dummy for this frame. */ + CORE_ADDR possible_call_dummy_start = + (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 - 8*12; + + int nextinsn; + memset (saved_regs, 0, sizeof (*saved_regs)); + if ((frame_info)->pc >= possible_call_dummy_start + && (frame_info)->pc <= (frame_info)->frame) + { + + /* It is a call dummy. We could just stop now, since we know + what the call dummy saves and where. But this code proceeds + to parse the "prologue" which is part of the call dummy. + This is needlessly complex and confusing. FIXME. */ + + next_addr = (frame_info)->frame; + pc = possible_call_dummy_start; + } + else + { + pc = get_pc_function_start ((frame_info)->pc); + + if (0x4856 == read_memory_integer (pc, 2) + && 0x2c4f == read_memory_integer (pc + 2, 2)) + { + /* + pea %fp + move.l %sp, %fp */ + + pc += 4; + next_addr = frame_info->frame; + } + else if (044016 == read_memory_integer (pc, 2)) + /* link.l %fp */ + /* Find the address above the saved + regs using the amount of storage from the link instruction. */ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4; + else if (047126 == read_memory_integer (pc, 2)) + /* link.w %fp */ + /* Find the address above the saved + regs using the amount of storage from the link instruction. */ + next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2; + else goto lose; + + /* If have an addal #-n, sp next, adjust next_addr. */ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) + next_addr += read_memory_integer (pc += 2, 4), pc += 4; + } + regmask = read_memory_integer (pc + 2, 2); + + /* Here can come an fmovem. Check for it. */ + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf227 == nextinsn + && (regmask & 0xff00) == 0xe000) + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) + if (regmask & 1) + saved_regs->regs[regnum] = (next_addr -= 12); + regmask = read_memory_integer (pc + 2, 2); } + + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ + if (0044327 == read_memory_integer (pc, 2)) + { pc += 4; /* Regmask's low bit is for register 0, the first written */ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) + if (regmask & 1) + saved_regs->regs[regnum] = (next_addr += 4) - 4; } + else if (0044347 == read_memory_integer (pc, 2)) + { + pc += 4; /* Regmask's low bit is for register 15, the first pushed */ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) + if (regmask & 1) + saved_regs->regs[regnum] = (next_addr -= 4); + } + else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) + { + regnum = 0xf & read_memory_integer (pc, 2); pc += 2; + saved_regs->regs[regnum] = (next_addr -= 4); + /* gcc, at least, may use a pair of movel instructions when saving + exactly 2 registers. */ + if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2))) + { + regnum = 0xf & read_memory_integer (pc, 2); + pc += 2; + saved_regs->regs[regnum] = (next_addr -= 4); + } + } + + /* fmovemx to index of sp may follow. */ + regmask = read_memory_integer (pc + 2, 2); + nextinsn = 0xffff & read_memory_integer (pc, 2); + if (0xf236 == nextinsn + && (regmask & 0xff00) == 0xf000) + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) + if (regmask & 1) + saved_regs->regs[regnum] = (next_addr += 12) - 12; + regmask = read_memory_integer (pc + 2, 2); } + + /* clrw -(sp); movw ccr,-(sp) may follow. */ + if (0x426742e7 == read_memory_integer (pc, 4)) + saved_regs->regs[PS_REGNUM] = (next_addr -= 4); + lose: ; + saved_regs->regs[SP_REGNUM] = (frame_info)->frame + 8; + saved_regs->regs[FP_REGNUM] = (frame_info)->frame; + saved_regs->regs[PC_REGNUM] = (frame_info)->frame + 4; +#ifdef SIG_SP_FP_OFFSET + /* Adjust saved SP_REGNUM for fake _sigtramp frames. */ + if (frame_info->signal_handler_caller && frame_info->next) + saved_regs->regs[SP_REGNUM] = frame_info->next->frame + SIG_SP_FP_OFFSET; +#endif +} + + +#ifdef USE_PROC_FS /* Target dependent support for /proc */ + +#include + +/* The /proc interface divides the target machine's register set up into + two different sets, the general register set (gregset) and the floating + point register set (fpregset). For each set, there is an ioctl to get + the current register set and another ioctl to set the current values. + + The actual structure passed through the ioctl interface is, of course, + naturally machine dependent, and is different for each set of registers. + For the m68k for example, the general register set is typically defined + by: + + typedef int gregset_t[18]; + + #define R_D0 0 + ... + #define R_PS 17 + + and the floating point set by: + + typedef struct fpregset { + int f_pcr; + int f_psr; + int f_fpiaddr; + int f_fpregs[8][3]; (8 regs, 96 bits each) + } fpregset_t; + + These routines provide the packing and unpacking of gregset_t and + fpregset_t formatted data. + + */ + +/* Atari SVR4 has R_SR but not R_PS */ + +#if !defined (R_PS) && defined (R_SR) +#define R_PS R_SR +#endif + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) +gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + + for (regi = 0 ; regi < R_PC ; regi++) + { + supply_register (regi, (char *) (regp + regi)); + } + supply_register (PS_REGNUM, (char *) (regp + R_PS)); + supply_register (PC_REGNUM, (char *) (regp + R_PC)); +} + +void +fill_gregset (gregsetp, regno) +gregset_t *gregsetp; +int regno; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + extern char registers[]; + + for (regi = 0 ; regi < R_PC ; regi++) + { + if ((regno == -1) || (regno == regi)) + { + *(regp + regi) = *(int *) ®isters[REGISTER_BYTE (regi)]; + } + } + if ((regno == -1) || (regno == PS_REGNUM)) + { + *(regp + R_PS) = *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)]; + } + if ((regno == -1) || (regno == PC_REGNUM)) + { + *(regp + R_PC) = *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)]; + } +} + +#if defined (FP0_REGNUM) + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), unpack the register contents and supply them as gdb's + idea of the current floating point register values. */ + +void +supply_fpregset (fpregsetp) +fpregset_t *fpregsetp; +{ + register int regi; + char *from; + + for (regi = FP0_REGNUM ; regi < FPC_REGNUM ; regi++) + { + from = (char *) &(fpregsetp -> f_fpregs[regi-FP0_REGNUM][0]); + supply_register (regi, from); + } + supply_register (FPC_REGNUM, (char *) &(fpregsetp -> f_pcr)); + supply_register (FPS_REGNUM, (char *) &(fpregsetp -> f_psr)); + supply_register (FPI_REGNUM, (char *) &(fpregsetp -> f_fpiaddr)); +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), update the register specified by REGNO from gdb's idea + of the current floating point register set. If REGNO is -1, update + them all. */ + +void +fill_fpregset (fpregsetp, regno) +fpregset_t *fpregsetp; +int regno; +{ + int regi; + char *to; + char *from; + extern char registers[]; + + for (regi = FP0_REGNUM ; regi < FPC_REGNUM ; regi++) + { + if ((regno == -1) || (regno == regi)) + { + from = (char *) ®isters[REGISTER_BYTE (regi)]; + to = (char *) &(fpregsetp -> f_fpregs[regi-FP0_REGNUM][0]); + memcpy (to, from, REGISTER_RAW_SIZE (regi)); + } + } + if ((regno == -1) || (regno == FPC_REGNUM)) + { + fpregsetp -> f_pcr = *(int *) ®isters[REGISTER_BYTE (FPC_REGNUM)]; + } + if ((regno == -1) || (regno == FPS_REGNUM)) + { + fpregsetp -> f_psr = *(int *) ®isters[REGISTER_BYTE (FPS_REGNUM)]; + } + if ((regno == -1) || (regno == FPI_REGNUM)) + { + fpregsetp -> f_fpiaddr = *(int *) ®isters[REGISTER_BYTE (FPI_REGNUM)]; + } +} + +#endif /* defined (FP0_REGNUM) */ + +#endif /* USE_PROC_FS */ + +#ifdef GET_LONGJMP_TARGET +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into PC. + This routine returns true on success. */ + +int +get_longjmp_target(pc) + CORE_ADDR *pc; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + CORE_ADDR sp, jb_addr; + + sp = read_register(SP_REGNUM); + + if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */ + buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf, + TARGET_PTR_BIT / TARGET_CHAR_BIT)) + return 0; + + *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT); + + return 1; +} +#endif /* GET_LONGJMP_TARGET */ + +/* Immediately after a function call, return the saved pc before the frame + is setup. For sun3's, we check for the common case of being inside of a + system call, and if so, we know that Sun pushes the call # on the stack + prior to doing the trap. */ + +CORE_ADDR +m68k_saved_pc_after_call(frame) + struct frame_info *frame; +{ +#ifdef SYSCALL_TRAP + int op; + + op = read_memory_integer (frame->pc - SYSCALL_TRAP_OFFSET, 2); + + if (op == SYSCALL_TRAP) + return read_memory_integer (read_register (SP_REGNUM) + 4, 4); + else +#endif /* SYSCALL_TRAP */ + return read_memory_integer (read_register (SP_REGNUM), 4); +} + +void +_initialize_m68k_tdep () +{ + tm_print_insn = print_insn_m68k; +} diff --git a/contrib/gdb/gdb/m68knbsd-nat.c b/contrib/gdb/gdb/m68knbsd-nat.c new file mode 100644 index 000000000000..7f981472ba60 --- /dev/null +++ b/contrib/gdb/gdb/m68knbsd-nat.c @@ -0,0 +1,86 @@ +/* Native-dependent code for Motorola m68k's running NetBSD, for GDB. + Copyright 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +#include "defs.h" +#include "inferior.h" + +void +fetch_inferior_registers(regno) + int regno; +{ + struct reg inferior_registers; + struct fpreg inferior_fp_registers; + + ptrace (PT_GETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers, 0); + memcpy (®isters[REGISTER_BYTE (0)], &inferior_registers, + sizeof(inferior_registers)); + + ptrace (PT_GETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0); + memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof(inferior_fp_registers)); + + registers_fetched (); +} + +void +store_inferior_registers(regno) + int regno; +{ + struct reg inferior_registers; + struct fpreg inferior_fp_registers; + + memcpy (&inferior_registers, ®isters[REGISTER_BYTE (0)], + sizeof(inferior_registers)); + ptrace (PT_SETREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_registers, 0); + + memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof(inferior_fp_registers)); + ptrace (PT_SETFPREGS, inferior_pid, + (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0); +} + +struct md_core { + struct reg intreg; + struct fpreg freg; +}; + +void +fetch_core_registers (core_reg_sect, core_reg_size, which, ignore) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned int ignore; +{ + struct md_core *core_reg = (struct md_core *)core_reg_sect; + + /* Integer registers */ + memcpy(®isters[REGISTER_BYTE (0)], + &core_reg->intreg, sizeof(struct reg)); + /* Floating point registers */ + memcpy(®isters[REGISTER_BYTE (FP0_REGNUM)], + &core_reg->freg, sizeof(struct fpreg)); +} diff --git a/contrib/gdb/gdb/m88k-nat.c b/contrib/gdb/gdb/m88k-nat.c new file mode 100644 index 000000000000..19e9392ea666 --- /dev/null +++ b/contrib/gdb/gdb/m88k-nat.c @@ -0,0 +1,285 @@ +/* Native-dependent Motorola 88xxx support for GDB, the GNU Debugger. + Copyright 1988, 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include "gdbcore.h" +#include + +#ifndef USER /* added to support BCS ptrace_user */ +#define USER ptrace_user +#endif +#include +#include +#include +#include "gdb_stat.h" + +#include "symtab.h" +#include "setjmp.h" +#include "value.h" + +#ifdef DELTA88 +#include + +/* define offsets to the pc instruction offsets in ptrace_user struct */ +#define SXIP_OFFSET ((char *)&u.pt_sigframe.sig_sxip - (char *)&u) +#define SNIP_OFFSET ((char *)&u.pt_sigframe.sig_snip - (char *)&u) +#define SFIP_OFFSET ((char *)&u.pt_sigframe.sig_sfip - (char *)&u) +#else +/* define offsets to the pc instruction offsets in ptrace_user struct */ +#define SXIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_sxip - (char *)&u) +#define SNIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_snip - (char *)&u) +#define SFIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_sfip - (char *)&u) +#endif + +extern int have_symbol_file_p(); + +extern jmp_buf stack_jmp; + +extern int errno; +extern char registers[REGISTER_BYTES]; + +void +fetch_inferior_registers (regno) + int regno; /* Original value discarded */ +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct USER u; + unsigned int offset; + + offset = (char *) &u.pt_r0 - (char *) &u; + regaddr = offset; /* byte offset to r0;*/ + +/* offset = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) - KERNEL_U_ADDR; */ + for (regno = 0; regno < NUM_REGS; regno++) + { + /*regaddr = register_addr (regno, offset);*/ + /* 88k enhancement */ + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } + /* now load up registers 36 - 38; special pc registers */ + *(int *) &buf[0] = ptrace (3,inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET ,0); + supply_register (SXIP_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET,0); + supply_register (SNIP_REGNUM, buf); + *(int *) &buf[0] = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET,0); + supply_register (SFIP_REGNUM, buf); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + struct USER u; + + unsigned int offset = (char *) &u.pt_r0 - (char *) &u; + + regaddr = offset; + + /* Don't try to deal with EXIP_REGNUM or ENIP_REGNUM, because I think either + svr3 doesn't run on an 88110, or the kernel isolates the different (not + completely sure this is true, but seems to be. */ + if (regno >= 0) + { + /* regaddr = register_addr (regno, offset); */ + if (regno < PC_REGNUM) + { + regaddr = offset + regno * sizeof (int); + errno = 0; + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else if (regno == SXIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET, read_register(regno)); + else if (regno == SNIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET, read_register(regno)); + else if (regno == SFIP_REGNUM) + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET, read_register(regno)); + else + printf_unfiltered ("Bad register number for store_inferior routine\n"); + } + else + { + for (regno = 0; regno < PC_REGNUM; regno++) + { + /* regaddr = register_addr (regno, offset); */ + errno = 0; + regaddr = offset + regno * sizeof (int); + ptrace (6, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SXIP_OFFSET,read_register(SXIP_REGNUM)); + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SNIP_OFFSET,read_register(SNIP_REGNUM)); + ptrace (6,inferior_pid, + (PTRACE_ARG3_TYPE) SFIP_OFFSET,read_register(SFIP_REGNUM)); + } +} + + +/* blockend is the address of the end of the user structure */ +m88k_register_u_addr (blockend, regnum) +{ + struct USER u; + int ustart = blockend - sizeof (struct USER); + switch (regnum) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + return (ustart + ((int) &u.pt_r0 - (int) &u) + REGISTER_SIZE * regnum); + case PSR_REGNUM: return (ustart + ((int) &u.pt_psr - (int) &u)); + case FPSR_REGNUM: return (ustart + ((int) &u.pt_fpsr - (int) &u)); + case FPCR_REGNUM: return (ustart + ((int) &u.pt_fpcr - (int) &u)); + case SXIP_REGNUM: return (ustart + SXIP_OFFSET); + case SNIP_REGNUM: return (ustart + SNIP_OFFSET); + case SFIP_REGNUM: return (ustart + SFIP_OFFSET); + default: + if (regnum < NUM_REGS) + /* The register is one of those which is not defined... + give it zero */ + return (ustart + ((int) &u.pt_r0 - (int) &u)); + else + return (blockend + REGISTER_SIZE * regnum); + } +} + +#ifdef USE_PROC_FS + +#include + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + register int regi; + register greg_t *regp = (greg_t *) gregsetp; + + for (regi=0; regi <= SP_REGNUM; regi++) + supply_register (regi, (char *) (regp + regi)); + + supply_register (SXIP_REGNUM, (char *) (regp + R_XIP)); + supply_register (SNIP_REGNUM, (char *) (regp + R_NIP)); + supply_register (SFIP_REGNUM, (char *) (regp + R_FIP)); + supply_register (PSR_REGNUM, (char *) (regp + R_PSR)); + supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR)); + supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR)); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + register greg_t *regp = (greg_t *) gregsetp; + extern char registers[]; + + for (regi = 0 ; regi <= R_R31 ; regi++) + if ((regno == -1) || (regno == regi)) + *(regp + regi) = *(int *) ®isters[REGISTER_BYTE(regi)]; + + if ((regno == -1) || (regno == SXIP_REGNUM)) + *(regp + R_XIP) = *(int *) ®isters[REGISTER_BYTE(SXIP_REGNUM)]; + if ((regno == -1) || (regno == SNIP_REGNUM)) + *(regp + R_NIP) = *(int *) ®isters[REGISTER_BYTE(SNIP_REGNUM)]; + if ((regno == -1) || (regno == SFIP_REGNUM)) + *(regp + R_FIP) = *(int *) ®isters[REGISTER_BYTE(SFIP_REGNUM)]; + if ((regno == -1) || (regno == PSR_REGNUM)) + *(regp + R_PSR) = *(int *) ®isters[REGISTER_BYTE(PSR_REGNUM)]; + if ((regno == -1) || (regno == FPSR_REGNUM)) + *(regp + R_FPSR) = *(int *) ®isters[REGISTER_BYTE(FPSR_REGNUM)]; + if ((regno == -1) || (regno == FPCR_REGNUM)) + *(regp + R_FPCR) = *(int *) ®isters[REGISTER_BYTE(FPCR_REGNUM)]; +} + +#endif /* USE_PROC_FS */ diff --git a/contrib/gdb/gdb/m88k-tdep.c b/contrib/gdb/gdb/m88k-tdep.c new file mode 100644 index 000000000000..a21bd96256e0 --- /dev/null +++ b/contrib/gdb/gdb/m88k-tdep.c @@ -0,0 +1,616 @@ +/* Target-machine dependent code for Motorola 88000 series, for GDB. + Copyright 1988, 1990, 1991, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" +#include "gdbcore.h" +#include "symtab.h" +#include "setjmp.h" +#include "value.h" + +/* Size of an instruction */ +#define BYTES_PER_88K_INSN 4 + +void frame_find_saved_regs (); + +/* Is this target an m88110? Otherwise assume m88100. This has + relevance for the ways in which we screw with instruction pointers. */ + +int target_is_m88110 = 0; + +/* Given a GDB frame, determine the address of the calling function's frame. + This will be used to create a new GDB frame struct, and then + INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. + + For us, the frame address is its stack pointer value, so we look up + the function prologue to determine the caller's sp value, and return it. */ + +CORE_ADDR +frame_chain (thisframe) + struct frame_info *thisframe; +{ + + frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0); + /* NOTE: this depends on frame_find_saved_regs returning the VALUE, not + the ADDRESS, of SP_REGNUM. It also depends on the cache of + frame_find_saved_regs results. */ + if (thisframe->fsr->regs[SP_REGNUM]) + return thisframe->fsr->regs[SP_REGNUM]; + else + return thisframe->frame; /* Leaf fn -- next frame up has same SP. */ +} + +int +frameless_function_invocation (frame) + struct frame_info *frame; +{ + + frame_find_saved_regs (frame, (struct frame_saved_regs *) 0); + /* NOTE: this depends on frame_find_saved_regs returning the VALUE, not + the ADDRESS, of SP_REGNUM. It also depends on the cache of + frame_find_saved_regs results. */ + if (frame->fsr->regs[SP_REGNUM]) + return 0; /* Frameful -- return addr saved somewhere */ + else + return 1; /* Frameless -- no saved return address */ +} + +void +init_extra_frame_info (fromleaf, frame) + int fromleaf; + struct frame_info *frame; +{ + frame->fsr = 0; /* Not yet allocated */ + frame->args_pointer = 0; /* Unknown */ + frame->locals_pointer = 0; /* Unknown */ +} + +/* Examine an m88k function prologue, recording the addresses at which + registers are saved explicitly by the prologue code, and returning + the address of the first instruction after the prologue (but not + after the instruction at address LIMIT, as explained below). + + LIMIT places an upper bound on addresses of the instructions to be + examined. If the prologue code scan reaches LIMIT, the scan is + aborted and LIMIT is returned. This is used, when examining the + prologue for the current frame, to keep examine_prologue () from + claiming that a given register has been saved when in fact the + instruction that saves it has not yet been executed. LIMIT is used + at other times to stop the scan when we hit code after the true + function prologue (e.g. for the first source line) which might + otherwise be mistaken for function prologue. + + The format of the function prologue matched by this routine is + derived from examination of the source to gcc 1.95, particularly + the routine output_prologue () in config/out-m88k.c. + + subu r31,r31,n # stack pointer update + + (st rn,r31,offset)? # save incoming regs + (st.d rn,r31,offset)? + + (addu r30,r31,n)? # frame pointer update + + (pic sequence)? # PIC code prologue + + (or rn,rm,0)? # Move parameters to other regs +*/ + +/* Macros for extracting fields from instructions. */ + +#define BITMASK(pos, width) (((0x1 << (width)) - 1) << (pos)) +#define EXTRACT_FIELD(val, pos, width) ((val) >> (pos) & BITMASK (0, width)) +#define SUBU_OFFSET(x) ((unsigned)(x & 0xFFFF)) +#define ST_OFFSET(x) ((unsigned)((x) & 0xFFFF)) +#define ST_SRC(x) EXTRACT_FIELD ((x), 21, 5) +#define ADDU_OFFSET(x) ((unsigned)(x & 0xFFFF)) + +/* + * prologue_insn_tbl is a table of instructions which may comprise a + * function prologue. Associated with each table entry (corresponding + * to a single instruction or group of instructions), is an action. + * This action is used by examine_prologue (below) to determine + * the state of certain machine registers and where the stack frame lives. + */ + +enum prologue_insn_action { + PIA_SKIP, /* don't care what the instruction does */ + PIA_NOTE_ST, /* note register stored and where */ + PIA_NOTE_STD, /* note pair of registers stored and where */ + PIA_NOTE_SP_ADJUSTMENT, /* note stack pointer adjustment */ + PIA_NOTE_FP_ASSIGNMENT, /* note frame pointer assignment */ + PIA_NOTE_PROLOGUE_END, /* no more prologue */ +}; + +struct prologue_insns { + unsigned long insn; + unsigned long mask; + enum prologue_insn_action action; +}; + +struct prologue_insns prologue_insn_tbl[] = { + /* Various register move instructions */ + { 0x58000000, 0xf800ffff, PIA_SKIP }, /* or/or.u with immed of 0 */ + { 0xf4005800, 0xfc1fffe0, PIA_SKIP }, /* or rd, r0, rs */ + { 0xf4005800, 0xfc00ffff, PIA_SKIP }, /* or rd, rs, r0 */ + + /* Stack pointer setup: "subu sp, sp, n" where n is a multiple of 8 */ + { 0x67ff0000, 0xffff0007, PIA_NOTE_SP_ADJUSTMENT }, + + /* Frame pointer assignment: "addu r30, r31, n" */ + { 0x63df0000, 0xffff0000, PIA_NOTE_FP_ASSIGNMENT }, + + /* Store to stack instructions; either "st rx, sp, n" or "st.d rx, sp, n" */ + { 0x241f0000, 0xfc1f0000, PIA_NOTE_ST }, /* st rx, sp, n */ + { 0x201f0000, 0xfc1f0000, PIA_NOTE_STD }, /* st.d rs, sp, n */ + + /* Instructions needed for setting up r25 for pic code. */ + { 0x5f200000, 0xffff0000, PIA_SKIP }, /* or.u r25, r0, offset_high */ + { 0xcc000002, 0xffffffff, PIA_SKIP }, /* bsr.n Lab */ + { 0x5b390000, 0xffff0000, PIA_SKIP }, /* or r25, r25, offset_low */ + { 0xf7396001, 0xffffffff, PIA_SKIP }, /* Lab: addu r25, r25, r1 */ + + /* Various branch or jump instructions which have a delay slot -- these + do not form part of the prologue, but the instruction in the delay + slot might be a store instruction which should be noted. */ + { 0xc4000000, 0xe4000000, PIA_NOTE_PROLOGUE_END }, + /* br.n, bsr.n, bb0.n, or bb1.n */ + { 0xec000000, 0xfc000000, PIA_NOTE_PROLOGUE_END }, /* bcnd.n */ + { 0xf400c400, 0xfffff7e0, PIA_NOTE_PROLOGUE_END } /* jmp.n or jsr.n */ + +}; + + +/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or + is not the address of a valid instruction, the address of the next + instruction beyond ADDR otherwise. *PWORD1 receives the first word + of the instruction. */ + +#define NEXT_PROLOGUE_INSN(addr, lim, pword1) \ + (((addr) < (lim)) ? next_insn (addr, pword1) : 0) + +/* Read the m88k instruction at 'memaddr' and return the address of + the next instruction after that, or 0 if 'memaddr' is not the + address of a valid instruction. The instruction + is stored at 'pword1'. */ + +CORE_ADDR +next_insn (memaddr, pword1) + unsigned long *pword1; + CORE_ADDR memaddr; +{ + *pword1 = read_memory_integer (memaddr, BYTES_PER_88K_INSN); + return memaddr + BYTES_PER_88K_INSN; +} + +/* Read a register from frames called by us (or from the hardware regs). */ + +static int +read_next_frame_reg(frame, regno) + struct frame_info *frame; + int regno; +{ + for (; frame; frame = frame->next) { + if (regno == SP_REGNUM) + return FRAME_FP (frame); + else if (frame->fsr->regs[regno]) + return read_memory_integer(frame->fsr->regs[regno], 4); + } + return read_register(regno); +} + +/* Examine the prologue of a function. `ip' points to the first instruction. + `limit' is the limit of the prologue (e.g. the addr of the first + linenumber, or perhaps the program counter if we're stepping through). + `frame_sp' is the stack pointer value in use in this frame. + `fsr' is a pointer to a frame_saved_regs structure into which we put + info about the registers saved by this frame. + `fi' is a struct frame_info pointer; we fill in various fields in it + to reflect the offsets of the arg pointer and the locals pointer. */ + +static CORE_ADDR +examine_prologue (ip, limit, frame_sp, fsr, fi) + register CORE_ADDR ip; + register CORE_ADDR limit; + CORE_ADDR frame_sp; + struct frame_saved_regs *fsr; + struct frame_info *fi; +{ + register CORE_ADDR next_ip; + register int src; + unsigned int insn; + int size, offset; + char must_adjust[32]; /* If set, must adjust offsets in fsr */ + int sp_offset = -1; /* -1 means not set (valid must be mult of 8) */ + int fp_offset = -1; /* -1 means not set */ + CORE_ADDR frame_fp; + CORE_ADDR prologue_end = 0; + + memset (must_adjust, '\0', sizeof (must_adjust)); + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn); + + while (next_ip) + { + struct prologue_insns *pip; + + for (pip=prologue_insn_tbl; (insn & pip->mask) != pip->insn; ) + if (++pip >= prologue_insn_tbl + sizeof prologue_insn_tbl) + goto end_of_prologue_found; /* not a prologue insn */ + + switch (pip->action) + { + case PIA_NOTE_ST: + case PIA_NOTE_STD: + if (sp_offset != -1) { + src = ST_SRC (insn); + offset = ST_OFFSET (insn); + must_adjust[src] = 1; + fsr->regs[src++] = offset; /* Will be adjusted later */ + if (pip->action == PIA_NOTE_STD && src < 32) + { + offset += 4; + must_adjust[src] = 1; + fsr->regs[src++] = offset; + } + } + else + goto end_of_prologue_found; + break; + case PIA_NOTE_SP_ADJUSTMENT: + if (sp_offset == -1) + sp_offset = -SUBU_OFFSET (insn); + else + goto end_of_prologue_found; + break; + case PIA_NOTE_FP_ASSIGNMENT: + if (fp_offset == -1) + fp_offset = ADDU_OFFSET (insn); + else + goto end_of_prologue_found; + break; + case PIA_NOTE_PROLOGUE_END: + if (!prologue_end) + prologue_end = ip; + break; + case PIA_SKIP: + default : + /* Do nothing */ + break; + } + + ip = next_ip; + next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn); + } + +end_of_prologue_found: + + if (prologue_end) + ip = prologue_end; + + /* We're done with the prologue. If we don't care about the stack + frame itself, just return. (Note that fsr->regs has been trashed, + but the one caller who calls with fi==0 passes a dummy there.) */ + + if (fi == 0) + return ip; + + /* + OK, now we have: + + sp_offset original (before any alloca calls) displacement of SP + (will be negative). + + fp_offset displacement from original SP to the FP for this frame + or -1. + + fsr->regs[0..31] displacement from original SP to the stack + location where reg[0..31] is stored. + + must_adjust[0..31] set if corresponding offset was set. + + If alloca has been called between the function prologue and the current + IP, then the current SP (frame_sp) will not be the original SP as set by + the function prologue. If the current SP is not the original SP, then the + compiler will have allocated an FP for this frame, fp_offset will be set, + and we can use it to calculate the original SP. + + Then, we figure out where the arguments and locals are, and relocate the + offsets in fsr->regs to absolute addresses. */ + + if (fp_offset != -1) { + /* We have a frame pointer, so get it, and base our calc's on it. */ + frame_fp = (CORE_ADDR) read_next_frame_reg (fi->next, ACTUAL_FP_REGNUM); + frame_sp = frame_fp - fp_offset; + } else { + /* We have no frame pointer, therefore frame_sp is still the same value + as set by prologue. But where is the frame itself? */ + if (must_adjust[SRP_REGNUM]) { + /* Function header saved SRP (r1), the return address. Frame starts + 4 bytes down from where it was saved. */ + frame_fp = frame_sp + fsr->regs[SRP_REGNUM] - 4; + fi->locals_pointer = frame_fp; + } else { + /* Function header didn't save SRP (r1), so we are in a leaf fn or + are otherwise confused. */ + frame_fp = -1; + } + } + + /* The locals are relative to the FP (whether it exists as an allocated + register, or just as an assumed offset from the SP) */ + fi->locals_pointer = frame_fp; + + /* The arguments are just above the SP as it was before we adjusted it + on entry. */ + fi->args_pointer = frame_sp - sp_offset; + + /* Now that we know the SP value used by the prologue, we know where + it saved all the registers. */ + for (src = 0; src < 32; src++) + if (must_adjust[src]) + fsr->regs[src] += frame_sp; + + /* The saved value of the SP is always known. */ + /* (we hope...) */ + if (fsr->regs[SP_REGNUM] != 0 + && fsr->regs[SP_REGNUM] != frame_sp - sp_offset) + fprintf_unfiltered(gdb_stderr, "Bad saved SP value %x != %x, offset %x!\n", + fsr->regs[SP_REGNUM], + frame_sp - sp_offset, sp_offset); + + fsr->regs[SP_REGNUM] = frame_sp - sp_offset; + + return (ip); +} + +/* Given an ip value corresponding to the start of a function, + return the ip of the first instruction after the function + prologue. */ + +CORE_ADDR +skip_prologue (ip) + CORE_ADDR (ip); +{ + struct frame_saved_regs saved_regs_dummy; + struct symtab_and_line sal; + CORE_ADDR limit; + + sal = find_pc_line (ip, 0); + limit = (sal.end) ? sal.end : 0xffffffff; + + return (examine_prologue (ip, limit, (CORE_ADDR) 0, &saved_regs_dummy, + (struct frame_info *)0 )); +} + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. + + We cache the result of doing this in the frame_cache_obstack, since + it is fairly expensive. */ + +void +frame_find_saved_regs (fi, fsr) + struct frame_info *fi; + struct frame_saved_regs *fsr; +{ + register struct frame_saved_regs *cache_fsr; + extern struct obstack frame_cache_obstack; + CORE_ADDR ip; + struct symtab_and_line sal; + CORE_ADDR limit; + + if (!fi->fsr) + { + cache_fsr = (struct frame_saved_regs *) + obstack_alloc (&frame_cache_obstack, + sizeof (struct frame_saved_regs)); + memset (cache_fsr, '\0', sizeof (struct frame_saved_regs)); + fi->fsr = cache_fsr; + + /* Find the start and end of the function prologue. If the PC + is in the function prologue, we only consider the part that + has executed already. In the case where the PC is not in + the function prologue, we set limit to two instructions beyond + where the prologue ends in case if any of the prologue instructions + were moved into a delay slot of a branch instruction. */ + + ip = get_pc_function_start (fi->pc); + sal = find_pc_line (ip, 0); + limit = (sal.end && sal.end < fi->pc) ? sal.end + 2 * BYTES_PER_88K_INSN + : fi->pc; + + /* This will fill in fields in *fi as well as in cache_fsr. */ +#ifdef SIGTRAMP_FRAME_FIXUP + if (fi->signal_handler_caller) + SIGTRAMP_FRAME_FIXUP(fi->frame); +#endif + examine_prologue (ip, limit, fi->frame, cache_fsr, fi); +#ifdef SIGTRAMP_SP_FIXUP + if (fi->signal_handler_caller && fi->fsr->regs[SP_REGNUM]) + SIGTRAMP_SP_FIXUP(fi->fsr->regs[SP_REGNUM]); +#endif + } + + if (fsr) + *fsr = *fi->fsr; +} + +/* Return the address of the locals block for the frame + described by FI. Returns 0 if the address is unknown. + NOTE! Frame locals are referred to by negative offsets from the + argument pointer, so this is the same as frame_args_address(). */ + +CORE_ADDR +frame_locals_address (fi) + struct frame_info *fi; +{ + struct frame_saved_regs fsr; + + if (fi->args_pointer) /* Cached value is likely there. */ + return fi->args_pointer; + + /* Nope, generate it. */ + + get_frame_saved_regs (fi, &fsr); + + return fi->args_pointer; +} + +/* Return the address of the argument block for the frame + described by FI. Returns 0 if the address is unknown. */ + +CORE_ADDR +frame_args_address (fi) + struct frame_info *fi; +{ + struct frame_saved_regs fsr; + + if (fi->args_pointer) /* Cached value is likely there. */ + return fi->args_pointer; + + /* Nope, generate it. */ + + get_frame_saved_regs (fi, &fsr); + + return fi->args_pointer; +} + +/* Return the saved PC from this frame. + + If the frame has a memory copy of SRP_REGNUM, use that. If not, + just use the register SRP_REGNUM itself. */ + +CORE_ADDR +frame_saved_pc (frame) + struct frame_info *frame; +{ + return read_next_frame_reg(frame, SRP_REGNUM); +} + + +#define DUMMY_FRAME_SIZE 192 + +static void +write_word (sp, word) + CORE_ADDR sp; + unsigned LONGEST word; +{ + register int len = REGISTER_SIZE; + char buffer[MAX_REGISTER_RAW_SIZE]; + + store_unsigned_integer (buffer, len, word); + write_memory (sp, buffer, len); +} + +void +m88k_push_dummy_frame() +{ + register CORE_ADDR sp = read_register (SP_REGNUM); + register int rn; + int offset; + + sp -= DUMMY_FRAME_SIZE; /* allocate a bunch of space */ + + for (rn = 0, offset = 0; rn <= SP_REGNUM; rn++, offset+=4) + write_word (sp+offset, read_register(rn)); + + write_word (sp+offset, read_register (SXIP_REGNUM)); + offset += 4; + + write_word (sp+offset, read_register (SNIP_REGNUM)); + offset += 4; + + write_word (sp+offset, read_register (SFIP_REGNUM)); + offset += 4; + + write_word (sp+offset, read_register (PSR_REGNUM)); + offset += 4; + + write_word (sp+offset, read_register (FPSR_REGNUM)); + offset += 4; + + write_word (sp+offset, read_register (FPCR_REGNUM)); + offset += 4; + + write_register (SP_REGNUM, sp); + write_register (ACTUAL_FP_REGNUM, sp); +} + +void +pop_frame () +{ + register struct frame_info *frame = get_current_frame (); + register CORE_ADDR fp; + register int regnum; + struct frame_saved_regs fsr; + + fp = FRAME_FP (frame); + get_frame_saved_regs (frame, &fsr); + + if (PC_IN_CALL_DUMMY (read_pc (), read_register (SP_REGNUM), FRAME_FP (fi))) + { + /* FIXME: I think get_frame_saved_regs should be handling this so + that we can deal with the saved registers properly (e.g. frame + 1 is a call dummy, the user types "frame 2" and then "print $ps"). */ + register CORE_ADDR sp = read_register (ACTUAL_FP_REGNUM); + int offset; + + for (regnum = 0, offset = 0; regnum <= SP_REGNUM; regnum++, offset+=4) + (void) write_register (regnum, read_memory_integer (sp+offset, 4)); + + write_register (SXIP_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + write_register (SNIP_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + write_register (SFIP_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + write_register (PSR_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + write_register (FPSR_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + write_register (FPCR_REGNUM, read_memory_integer (sp+offset, 4)); + offset += 4; + + } + else + { + for (regnum = FP_REGNUM ; regnum > 0 ; regnum--) + if (fsr.regs[regnum]) + write_register (regnum, + read_memory_integer (fsr.regs[regnum], 4)); + write_pc (frame_saved_pc (frame)); + } + reinit_frame_cache (); +} + +void +_initialize_m88k_tdep () +{ + tm_print_insn = print_insn_m88k; +} diff --git a/contrib/gdb/gdb/main.c b/contrib/gdb/gdb/main.c new file mode 100644 index 000000000000..c440217d49df --- /dev/null +++ b/contrib/gdb/gdb/main.c @@ -0,0 +1,627 @@ +/* Top level stuff for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "top.h" +#include "target.h" +#include "inferior.h" +#include "call-cmds.h" + +#include "getopt.h" + +#include +#include "gdb_stat.h" +#include + +#include "gdb_string.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef NO_SYS_FILE +#include +#endif + +/* Temporary variable for SET_TOP_LEVEL. */ + +static int top_level_val; + +/* Do a setjmp on error_return and quit_return. catch_errors is + generally a cleaner way to do this, but main() would look pretty + ugly if it had to use catch_errors each time. */ + +#define SET_TOP_LEVEL() \ + (((top_level_val = setjmp (error_return)) \ + ? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \ + , top_level_val) + +/* If nonzero, display time usage both at startup and for each command. */ + +int display_time; + +/* If nonzero, display space usage both at startup and for each command. */ + +int display_space; + +extern void gdb_init PARAMS ((void)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int count; + static int quiet = 0; + static int batch = 0; + + /* Pointers to various arguments from command line. */ + char *symarg = NULL; + char *execarg = NULL; + char *corearg = NULL; + char *cdarg = NULL; + char *ttyarg = NULL; + + /* These are static so that we can take their address in an initializer. */ + static int print_help; + static int print_version; + + /* Pointers to all arguments of --command option. */ + char **cmdarg; + /* Allocated size of cmdarg. */ + int cmdsize; + /* Number of elements of cmdarg used. */ + int ncmd; + + /* Indices of all arguments of --directory option. */ + char **dirarg; + /* Allocated size. */ + int dirsize; + /* Number of elements used. */ + int ndir; + + struct stat homebuf, cwdbuf; + char *homedir, *homeinit; + + register int i; + + long time_at_startup = get_run_time (); + + START_PROGRESS (argv[0], 0); + +#ifdef MPW + /* Do all Mac-specific setup. */ + mac_init (); +#endif /* MPW */ + + /* This needs to happen before the first use of malloc. */ + init_malloc ((PTR) NULL); + +#if defined (ALIGN_STACK_ON_STARTUP) + i = (int) &count & 0x3; + if (i != 0) + alloca (4 - i); +#endif + + /* If error() is called from initialization code, just exit */ + if (SET_TOP_LEVEL ()) { + exit(1); + } + + cmdsize = 1; + cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg)); + ncmd = 0; + dirsize = 1; + dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg)); + ndir = 0; + + quit_flag = 0; + line = (char *) xmalloc (linesize); + line[0] = '\0'; /* Terminate saved (now empty) cmd line */ + instream = stdin; + + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + current_directory = gdb_dirbuf; + + /* Parse arguments and options. */ +#ifndef WINGDB + { + int c; + /* When var field is 0, use flag field to record the equivalent + short option (or arbitrary numbers starting at 10 for those + with no equivalent). */ + static struct option long_options[] = + { + {"readnow", no_argument, &readnow_symbol_files, 1}, + {"r", no_argument, &readnow_symbol_files, 1}, + {"mapped", no_argument, &mapped_symbol_files, 1}, + {"m", no_argument, &mapped_symbol_files, 1}, + {"quiet", no_argument, &quiet, 1}, + {"q", no_argument, &quiet, 1}, + {"silent", no_argument, &quiet, 1}, + {"nx", no_argument, &inhibit_gdbinit, 1}, + {"n", no_argument, &inhibit_gdbinit, 1}, + {"batch", no_argument, &batch, 1}, + {"epoch", no_argument, &epoch_interface, 1}, + + /* This is a synonym for "--annotate=1". --annotate is now preferred, + but keep this here for a long time because people will be running + emacses which use --fullname. */ + {"fullname", no_argument, 0, 'f'}, + {"f", no_argument, 0, 'f'}, + + {"annotate", required_argument, 0, 12}, + {"help", no_argument, &print_help, 1}, + {"se", required_argument, 0, 10}, + {"symbols", required_argument, 0, 's'}, + {"s", required_argument, 0, 's'}, + {"exec", required_argument, 0, 'e'}, + {"e", required_argument, 0, 'e'}, + {"core", required_argument, 0, 'c'}, + {"c", required_argument, 0, 'c'}, + {"command", required_argument, 0, 'x'}, + {"version", no_argument, &print_version, 1}, + {"x", required_argument, 0, 'x'}, + {"directory", required_argument, 0, 'd'}, + {"cd", required_argument, 0, 11}, + {"tty", required_argument, 0, 't'}, + {"baud", required_argument, 0, 'b'}, + {"b", required_argument, 0, 'b'}, + {"nw", no_argument, &use_windows, 0}, + {"nowindows", no_argument, &use_windows, 0}, + {"w", no_argument, &use_windows, 1}, + {"windows", no_argument, &use_windows, 1}, + {"statistics", no_argument, 0, 13}, +/* Allow machine descriptions to add more options... */ +#ifdef ADDITIONAL_OPTIONS + ADDITIONAL_OPTIONS +#endif + {0, no_argument, 0, 0} + }; + + while (1) + { + int option_index; + + c = getopt_long_only (argc, argv, "", + long_options, &option_index); + if (c == EOF) + break; + + /* Long option that takes an argument. */ + if (c == 0 && long_options[option_index].flag == 0) + c = long_options[option_index].val; + + switch (c) + { + case 0: + /* Long option that just sets a flag. */ + break; + case 10: + symarg = optarg; + execarg = optarg; + break; + case 11: + cdarg = optarg; + break; + case 12: + /* FIXME: what if the syntax is wrong (e.g. not digits)? */ + annotation_level = atoi (optarg); + break; + case 13: + /* Enable the display of both time and space usage. */ + display_time = 1; + display_space = 1; + break; + case 'f': + annotation_level = 1; +/* We have probably been invoked from emacs. Disable window interface. */ + use_windows = 0; + break; + case 's': + symarg = optarg; + break; + case 'e': + execarg = optarg; + break; + case 'c': + corearg = optarg; + break; + case 'x': + cmdarg[ncmd++] = optarg; + if (ncmd >= cmdsize) + { + cmdsize *= 2; + cmdarg = (char **) xrealloc ((char *)cmdarg, + cmdsize * sizeof (*cmdarg)); + } + break; + case 'd': + dirarg[ndir++] = optarg; + if (ndir >= dirsize) + { + dirsize *= 2; + dirarg = (char **) xrealloc ((char *)dirarg, + dirsize * sizeof (*dirarg)); + } + break; + case 't': + ttyarg = optarg; + break; + case 'q': + quiet = 1; + break; + case 'b': + { + int i; + char *p; + + i = strtol (optarg, &p, 0); + if (i == 0 && p == optarg) + + /* Don't use *_filtered or warning() (which relies on + current_target) until after initialize_all_files(). */ + + fprintf_unfiltered + (gdb_stderr, + "warning: could not set baud rate to `%s'.\n", optarg); + else + baud_rate = i; + } + break; + +#ifdef ADDITIONAL_OPTION_CASES + ADDITIONAL_OPTION_CASES +#endif + case '?': + fprintf_unfiltered (gdb_stderr, + "Use `%s --help' for a complete list of options.\n", + argv[0]); + exit (1); + } + } + + /* If --help or --version, disable window interface. */ + if (print_help || print_version) + use_windows = 0; + + /* OK, that's all the options. The other arguments are filenames. */ + count = 0; + for (; optind < argc; optind++) + switch (++count) + { + case 1: + symarg = argv[optind]; + execarg = argv[optind]; + break; + case 2: + corearg = argv[optind]; + break; + case 3: + fprintf_unfiltered (gdb_stderr, + "Excess command line arguments ignored. (%s%s)\n", + argv[optind], (optind == argc - 1) ? "" : " ..."); + break; + } + if (batch) + quiet = 1; + } + +#endif + gdb_init (); + + /* Do these (and anything which might call wrap_here or *_filtered) + after initialize_all_files. */ + if (print_version) + { + print_gdb_version (gdb_stdout); + wrap_here (""); + printf_filtered ("\n"); + exit (0); + } + + if (print_help) + { + /* --version is intentionally not documented here, because we + are printing the version here, and the help is long enough + already. */ + + print_gdb_version (gdb_stdout); + /* Make sure the output gets printed. */ + wrap_here (""); + printf_filtered ("\n"); + + /* But don't use *_filtered here. We don't want to prompt for continue + no matter how small the screen or how much we're going to print. */ + fputs_unfiltered ("\ +This is the GNU debugger. Usage:\n\ + gdb [options] [executable-file [core-file or process-id]]\n\ +Options:\n\ + --help Print this message.\n\ + --quiet Do not print version number on startup.\n\ + --fullname Output information used by emacs-GDB interface.\n\ + --epoch Output information used by epoch emacs-GDB interface.\n\ +", gdb_stdout); + fputs_unfiltered ("\ + --batch Exit after processing options.\n\ + --nx Do not read .gdbinit file.\n\ + --tty=TTY Use TTY for input/output by the program being debugged.\n\ + --cd=DIR Change current directory to DIR.\n\ + --directory=DIR Search for source files in DIR.\n\ +", gdb_stdout); + fputs_unfiltered ("\ + --command=FILE Execute GDB commands from FILE.\n\ + --symbols=SYMFILE Read symbols from SYMFILE.\n\ + --exec=EXECFILE Use EXECFILE as the executable.\n\ + --se=FILE Use FILE as symbol file and executable file.\n\ +", gdb_stdout); + fputs_unfiltered ("\ + --core=COREFILE Analyze the core dump COREFILE.\n\ + -b BAUDRATE Set serial port baud rate used for remote debugging.\n\ + --mapped Use mapped symbol files if supported on this system.\n\ + --readnow Fully read symbol files on first access.\n\ + --nw Do not use a window interface.\n\ +", gdb_stdout); +#ifdef ADDITIONAL_OPTION_HELP + fputs_unfiltered (ADDITIONAL_OPTION_HELP, gdb_stdout); +#endif + fputs_unfiltered ("\n\ +For more information, type \"help\" from within GDB, or consult the\n\ +GDB manual (available as on-line info or a printed manual).\n", gdb_stdout); + exit (0); + } + + if (!quiet) + { + /* Print all the junk at the top, with trailing "..." if we are about + to read a symbol file (possibly slowly). */ + print_gnu_advertisement (); + print_gdb_version (gdb_stdout); + if (symarg) + printf_filtered (".."); + wrap_here(""); + gdb_flush (gdb_stdout); /* Force to screen during slow operations */ + } + + error_pre_print = "\n\n"; + quit_pre_print = error_pre_print; + + /* We may get more than one warning, don't double space all of them... */ + warning_pre_print = "\nwarning: "; + + /* Read and execute $HOME/.gdbinit file, if it exists. This is done + *before* all the command line arguments are processed; it sets + global parameters, which are independent of what file you are + debugging or what directory you are in. */ + homedir = getenv ("HOME"); + if (homedir) + { + homeinit = (char *) alloca (strlen (getenv ("HOME")) + + strlen (gdbinit) + 10); + strcpy (homeinit, getenv ("HOME")); + strcat (homeinit, "/"); + strcat (homeinit, gdbinit); + + if (!inhibit_gdbinit && access (homeinit, R_OK) == 0) + { + if (!SET_TOP_LEVEL ()) + source_command (homeinit, 0); + } + do_cleanups (ALL_CLEANUPS); + + /* Do stats; no need to do them elsewhere since we'll only + need them if homedir is set. Make sure that they are + zero in case one of them fails (this guarantees that they + won't match if either exists). */ + + memset (&homebuf, 0, sizeof (struct stat)); + memset (&cwdbuf, 0, sizeof (struct stat)); + + stat (homeinit, &homebuf); + stat (gdbinit, &cwdbuf); /* We'll only need this if + homedir was set. */ + } + + /* Now perform all the actions indicated by the arguments. */ + if (cdarg != NULL) + { + if (!SET_TOP_LEVEL ()) + { + cd_command (cdarg, 0); + } + } + do_cleanups (ALL_CLEANUPS); + + for (i = 0; i < ndir; i++) + if (!SET_TOP_LEVEL ()) + directory_command (dirarg[i], 0); + free ((PTR)dirarg); + do_cleanups (ALL_CLEANUPS); + + if (execarg != NULL + && symarg != NULL + && STREQ (execarg, symarg)) + { + /* The exec file and the symbol-file are the same. If we can't open + it, better only print one error message. */ + if (!SET_TOP_LEVEL ()) + { + exec_file_command (execarg, !batch); + symbol_file_command (symarg, 0); + } + } + else + { + if (execarg != NULL) + if (!SET_TOP_LEVEL ()) + exec_file_command (execarg, !batch); + if (symarg != NULL) + if (!SET_TOP_LEVEL ()) + symbol_file_command (symarg, 0); + } + do_cleanups (ALL_CLEANUPS); + + /* After the symbol file has been read, print a newline to get us + beyond the copyright line... But errors should still set off + the error message with a (single) blank line. */ + if (!quiet) + printf_filtered ("\n"); + error_pre_print = "\n"; + quit_pre_print = error_pre_print; + warning_pre_print = "\nwarning: "; + + if (corearg != NULL) + if (!SET_TOP_LEVEL ()) + core_file_command (corearg, !batch); + else if (isdigit (corearg[0]) && !SET_TOP_LEVEL ()) + attach_command (corearg, !batch); + do_cleanups (ALL_CLEANUPS); + + if (ttyarg != NULL) + if (!SET_TOP_LEVEL ()) + tty_command (ttyarg, !batch); + do_cleanups (ALL_CLEANUPS); + +#ifdef ADDITIONAL_OPTION_HANDLER + ADDITIONAL_OPTION_HANDLER; +#endif + + /* Error messages should no longer be distinguished with extra output. */ + error_pre_print = NULL; + quit_pre_print = NULL; + warning_pre_print = "warning: "; + + /* Read the .gdbinit file in the current directory, *if* it isn't + the same as the $HOME/.gdbinit file (it should exist, also). */ + + if (!homedir + || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat))) + if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0) + { + if (!SET_TOP_LEVEL ()) + source_command (gdbinit, 0); + } + do_cleanups (ALL_CLEANUPS); + + for (i = 0; i < ncmd; i++) + { + if (!SET_TOP_LEVEL ()) + { + if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0') + read_command_file (stdin); + else + source_command (cmdarg[i], !batch); + do_cleanups (ALL_CLEANUPS); + } + } + free ((PTR)cmdarg); + + /* Read in the old history after all the command files have been read. */ + init_history(); + + if (batch) + { + /* We have hit the end of the batch file. */ + exit (0); + } + + /* Do any host- or target-specific hacks. This is used for i960 targets + to force the user to set a nindy target and spec its parameters. */ + +#ifdef BEFORE_MAIN_LOOP_HOOK + BEFORE_MAIN_LOOP_HOOK; +#endif + + END_PROGRESS (argv[0]); + + /* Show time and/or space usage. */ + + if (display_time) + { + long init_time = get_run_time () - time_at_startup; + + printf_unfiltered ("Startup time: %ld.%06ld\n", + init_time / 1000000, init_time % 1000000); + } + + if (display_space) + { +#ifdef HAVE_SBRK + extern char **environ; + char *lim = (char *) sbrk (0); + + printf_unfiltered ("Startup size: data size %ld\n", + (long) (lim - (char *) &environ)); +#endif + } + + /* The default command loop. + The WIN32 Gui calls this main to set up gdb's state, and + has its own command loop. */ +#if !defined (WINGDB) + while (1) + { + if (!SET_TOP_LEVEL ()) + { + do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */ + /* GUIs generally have their own command loop, mainloop, or whatever. + This is a good place to gain control because many error + conditions will end up here via longjmp(). */ + if (command_loop_hook) + command_loop_hook (); + else + command_loop (); + quit_command ((char *)0, instream == stdin); + } + } + + /* No exit -- exit is through quit_command. */ +#endif + +} + +void +init_proc () +{ +} + +void +proc_remove_foreign (pid) + int pid; +{ +} + +void +fputs_unfiltered (linebuffer, stream) + const char *linebuffer; + FILE *stream; +{ + if (fputs_unfiltered_hook) + { + /* FIXME: I think we should only be doing this for stdout or stderr. + Either that or we should be passing stream to the hook so it can + deal with it. If that is cleaned up, this function can go back + into utils.c and the fputs_unfiltered_hook can replace the current + ability to avoid this function by not linking with main.c. */ + fputs_unfiltered_hook (linebuffer, stream); + return; + } + + fputs (linebuffer, stream); +} diff --git a/contrib/gdb/gdb/maint.c b/contrib/gdb/gdb/maint.c new file mode 100644 index 000000000000..9ce342c2e6a7 --- /dev/null +++ b/contrib/gdb/gdb/maint.c @@ -0,0 +1,370 @@ +/* Support for GDB maintenance commands. + Copyright 1992, 1993, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "defs.h" + +#if MAINTENANCE_CMDS /* Entire rest of file goes away if not including maint cmds */ + +#include +#include "command.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "demangle.h" +#include "gdbcore.h" +#include "expression.h" /* For language.h */ +#include "language.h" +#include "symfile.h" +#include "objfiles.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +static void maintenance_command PARAMS ((char *, int)); + +static void maintenance_dump_me PARAMS ((char *, int)); + +static void maintenance_demangle PARAMS ((char *, int)); + +static void maintenance_time_display PARAMS ((char *, int)); + +static void maintenance_space_display PARAMS ((char *, int)); + +/* Set this to the maximum number of seconds to wait instead of waiting forever + in target_wait(). If this timer times out, then it generates an error and + the command is aborted. This replaces most of the need for timeouts in the + GDB test suite, and makes it possible to distinguish between a hung target + and one with slow communications. */ + +int watchdog = 0; + +/* + +LOCAL FUNCTION + + maintenance_command -- access the maintenance subcommands + +SYNOPSIS + + void maintenance_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +maintenance_command (args, from_tty) + char *args; + int from_tty; +{ + printf_unfiltered ("\"maintenance\" must be followed by the name of a maintenance command.\n"); + help_list (maintenancelist, "maintenance ", -1, gdb_stdout); +} + + +/* ARGSUSED */ +static void +maintenance_dump_me (args, from_tty) + char *args; + int from_tty; +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + +/* Someday we should allow demangling for things other than just + explicit strings. For example, we might want to be able to + specify the address of a string in either GDB's process space + or the debuggee's process space, and have gdb fetch and demangle + that string. If we have a char* pointer "ptr" that points to + a string, we might want to be able to given just the name and + have GDB demangle and print what it points to, etc. (FIXME) */ + +static void +maintenance_demangle (args, from_tty) + char *args; + int from_tty; +{ + char *demangled; + + if (args == NULL || *args == '\0') + { + printf_unfiltered ("\"maintenance demangle\" takes an argument to demangle.\n"); + } + else + { + demangled = cplus_demangle (args, DMGL_ANSI | DMGL_PARAMS); + if (demangled != NULL) + { + printf_unfiltered ("%s\n", demangled); + free (demangled); + } + else + { + printf_unfiltered ("Can't demangle \"%s\"\n", args); + } + } +} + +static void +maintenance_time_display (args, from_tty) + char *args; + int from_tty; +{ + extern int display_time; + + if (args == NULL || *args == '\0') + printf_unfiltered ("\"maintenance time\" takes a numeric argument.\n"); + else + display_time = strtol (args, NULL, 10); +} + +static void +maintenance_space_display (args, from_tty) + char *args; + int from_tty; +{ + extern int display_space; + + if (args == NULL || *args == '\0') + printf_unfiltered ("\"maintenance space\" takes a numeric argument.\n"); + else + display_space = strtol (args, NULL, 10); +} + +/* The "maintenance info" command is defined as a prefix, with allow_unknown 0. + Therefore, its own definition is called only for "maintenance info" with + no args. */ + +/* ARGSUSED */ +static void +maintenance_info_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"maintenance info\" must be followed by the name of an info command.\n"); + help_list (maintenanceinfolist, "maintenance info ", -1, gdb_stdout); +} + +static void +print_section_table (abfd, asect, ignore) + bfd *abfd; + asection *asect; + PTR ignore; +{ + flagword flags; + + flags = bfd_get_section_flags (abfd, asect); + + /* FIXME-32x64: Need print_address_numeric with field width. */ + printf_filtered (" %s", + local_hex_string_custom + ((unsigned long) bfd_section_vma (abfd, asect), "08l")); + printf_filtered ("->%s", + local_hex_string_custom + ((unsigned long) (bfd_section_vma (abfd, asect) + + bfd_section_size (abfd, asect)), + "08l")); + printf_filtered (" at %s", + local_hex_string_custom + ((unsigned long) asect->filepos, "08l")); + printf_filtered (": %s", bfd_section_name (abfd, asect)); + + if (flags & SEC_ALLOC) + printf_filtered (" ALLOC"); + if (flags & SEC_LOAD) + printf_filtered (" LOAD"); + if (flags & SEC_RELOC) + printf_filtered (" RELOC"); + if (flags & SEC_READONLY) + printf_filtered (" READONLY"); + if (flags & SEC_CODE) + printf_filtered (" CODE"); + if (flags & SEC_DATA) + printf_filtered (" DATA"); + if (flags & SEC_ROM) + printf_filtered (" ROM"); + if (flags & SEC_CONSTRUCTOR) + printf_filtered (" CONSTRUCTOR"); + if (flags & SEC_HAS_CONTENTS) + printf_filtered (" HAS_CONTENTS"); + if (flags & SEC_NEVER_LOAD) + printf_filtered (" NEVER_LOAD"); + if (flags & SEC_COFF_SHARED_LIBRARY) + printf_filtered (" COFF_SHARED_LIBRARY"); + if (flags & SEC_IS_COMMON) + printf_filtered (" IS_COMMON"); + + printf_filtered ("\n"); +} + +/* ARGSUSED */ +static void +maintenance_info_sections (arg, from_tty) + char *arg; + int from_tty; +{ + if (exec_bfd) + { + printf_filtered ("Exec file:\n"); + printf_filtered (" `%s', ", bfd_get_filename(exec_bfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(exec_bfd)); + bfd_map_over_sections(exec_bfd, print_section_table, 0); + } + + if (core_bfd) + { + printf_filtered ("Core file:\n"); + printf_filtered (" `%s', ", bfd_get_filename(core_bfd)); + wrap_here (" "); + printf_filtered ("file type %s.\n", bfd_get_target(core_bfd)); + bfd_map_over_sections(core_bfd, print_section_table, 0); + } +} + +/* ARGSUSED */ +void +maintenance_print_statistics (args, from_tty) + char *args; + int from_tty; +{ + print_objfile_statistics (); + print_symbol_bcache_statistics (); +} + +/* The "maintenance print" command is defined as a prefix, with allow_unknown + 0. Therefore, its own definition is called only for "maintenance print" + with no args. */ + +/* ARGSUSED */ +static void +maintenance_print_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"maintenance print\" must be followed by the name of a print command.\n"); + help_list (maintenanceprintlist, "maintenance print ", -1, gdb_stdout); +} + +#endif /* MAINTENANCE_CMDS */ + +void +_initialize_maint_cmds () +{ +#if MAINTENANCE_CMDS /* Entire file goes away if not including maint cmds */ + add_prefix_cmd ("maintenance", class_maintenance, maintenance_command, + "Commands for use by GDB maintainers.\n\ +Includes commands to dump specific internal GDB structures in\n\ +a human readable form, to cause GDB to deliberately dump core,\n\ +to test internal functions such as the C++ demangler, etc.", + &maintenancelist, "maintenance ", 0, + &cmdlist); + + add_com_alias ("mt", "maintenance", class_maintenance, 1); + + add_prefix_cmd ("info", class_maintenance, maintenance_info_command, + "Commands for showing internal info about the program being debugged.", + &maintenanceinfolist, "maintenance info ", 0, + &maintenancelist); + + add_cmd ("sections", class_maintenance, maintenance_info_sections, + "List the BFD sections of the exec and core files.", + &maintenanceinfolist); + + add_prefix_cmd ("print", class_maintenance, maintenance_print_command, + "Maintenance command for printing GDB internal state.", + &maintenanceprintlist, "maintenance print ", 0, + &maintenancelist); + + add_cmd ("dump-me", class_maintenance, maintenance_dump_me, + "Get fatal error; make debugger dump its core.\n\ +GDB sets it's handling of SIGQUIT back to SIG_DFL and then sends\n\ +itself a SIGQUIT signal.", + &maintenancelist); + + add_cmd ("demangle", class_maintenance, maintenance_demangle, + "Demangle a C++ mangled name.\n\ +Call internal GDB demangler routine to demangle a C++ link name\n\ +and prints the result.", + &maintenancelist); + + add_cmd ("time", class_maintenance, maintenance_time_display, + "Set the display of time usage.\n\ +If nonzero, will cause the execution time for each command to be\n\ +displayed, following the command's output.", + &maintenancelist); + + add_cmd ("space", class_maintenance, maintenance_space_display, + "Set the display of space usage.\n\ +If nonzero, will cause the execution space for each command to be\n\ +displayed, following the command's output.", + &maintenancelist); + + add_cmd ("type", class_maintenance, maintenance_print_type, + "Print a type chain for a given symbol.\n\ +For each node in a type chain, print the raw data for each member of\n\ +the type structure, and the interpretation of the data.", + &maintenanceprintlist); + + 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 ("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 ("objfiles", class_maintenance, maintenance_print_objfiles, + "Print dump of current object file definitions.", + &maintenanceprintlist); + + add_cmd ("statistics", class_maintenance, maintenance_print_statistics, + "Print statistics about internal gdb state.", + &maintenanceprintlist); + + add_cmd ("check-symtabs", class_maintenance, maintenance_check_symtabs, + "Check consistency of psymtabs and symtabs.", + &maintenancelist); + + add_show_from_set ( + add_set_cmd ("watchdog", class_maintenance, var_zinteger, (char *)&watchdog, + "Set watchdog timer.\n\ +When non-zero, this timeout is used instead of waiting forever for a target to\n\ +finish a low-level step or continue operation. If the specified amount of time\n\ +passes without a response from the target, an error occurs.", &setlist), + &showlist); +#endif /* MAINTENANCE_CMDS */ +} diff --git a/contrib/gdb/gdb/mdebugread.c b/contrib/gdb/gdb/mdebugread.c new file mode 100644 index 000000000000..3fe4f962c88b --- /dev/null +++ b/contrib/gdb/gdb/mdebugread.c @@ -0,0 +1,4368 @@ +/* Read a symbol table in ECOFF format (Third-Eye). + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + Original version contributed by Alessandro Forin (af@cs.cmu.edu) at + CMU. Major work by Per Bothner, John Gilmore and Ian Lance Taylor + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This module provides the function mdebug_build_psymtabs. It reads + ECOFF debugging information into partial symbol tables. The + debugging information is read from two structures. A struct + ecoff_debug_swap includes the sizes of each ECOFF structure and + swapping routines; these are fixed for a particular target. A + struct ecoff_debug_info points to the debugging information for a + particular object file. + + ECOFF symbol tables are mostly written in the byte order of the + target machine. However, one section of the table (the auxiliary + symbol information) is written in the host byte order. There is a + bit in the other symbol info which describes which host byte order + was used. ECOFF thereby takes the trophy from Intel `b.out' for + the most brain-dead adaptation of a file format to byte order. + + This module can read all four of the known byte-order combinations, + on any type of host. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" +#include "obstack.h" +#include "buildsym.h" +#include "stabsread.h" +#include "complaints.h" +#include "demangle.h" + +/* These are needed if the tm.h file does not contain the necessary + mips specific definitions. */ + +#ifndef MIPS_EFI_SYMBOL_NAME +#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__" +#include "coff/sym.h" +#include "coff/symconst.h" +typedef struct mips_extra_func_info { + long numargs; + PDR pdr; +} *mips_extra_func_info_t; +#ifndef RA_REGNUM +#define RA_REGNUM 0 +#endif +#endif + +#ifdef USG +#include +#endif + +#include +#include +#include "gdb_stat.h" +#include "gdb_string.h" + +#include "gdb-stabs.h" + +#include "bfd.h" + +#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */ + +#include "libaout.h" /* Private BFD a.out information. */ +#include "aout/aout64.h" +#include "aout/stab_gnu.h" /* STABS information */ + +#include "expression.h" +#include "language.h" /* Needed inside partial-stab.h */ + +/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */ +#ifndef ECOFF_REG_TO_REGNUM +#define ECOFF_REG_TO_REGNUM(num) (num) +#endif + +/* We put a pointer to this structure in the read_symtab_private field + of the psymtab. */ + +struct symloc +{ + /* Index of the FDR that this psymtab represents. */ + int fdr_idx; + /* The BFD that the psymtab was created from. */ + bfd *cur_bfd; + const struct ecoff_debug_swap *debug_swap; + struct ecoff_debug_info *debug_info; + struct mdebug_pending **pending_list; + /* Pointer to external symbols for this file. */ + EXTR *extern_tab; + /* Size of extern_tab. */ + int extern_count; + enum language pst_language; +}; + +#define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private) +#define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx) +#define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd) +#define DEBUG_SWAP(p) (PST_PRIVATE(p)->debug_swap) +#define DEBUG_INFO(p) (PST_PRIVATE(p)->debug_info) +#define PENDING_LIST(p) (PST_PRIVATE(p)->pending_list) + +/* Things we import explicitly from other modules */ + +extern int info_verbose; + +/* Various complaints about symbol reading that don't abort the process */ + +static struct complaint bad_file_number_complaint = +{"bad file number %d", 0, 0}; + +static struct complaint index_complaint = +{"bad aux index at symbol %s", 0, 0}; + +static struct complaint aux_index_complaint = +{"bad proc end in aux found from symbol %s", 0, 0}; + +static struct complaint block_index_complaint = +{"bad aux index at block symbol %s", 0, 0}; + +static struct complaint unknown_ext_complaint = +{"unknown external symbol %s", 0, 0}; + +static struct complaint unknown_sym_complaint = +{"unknown local symbol %s", 0, 0}; + +static struct complaint unknown_st_complaint = +{"with type %d", 0, 0}; + +static struct complaint block_overflow_complaint = +{"block containing %s overfilled", 0, 0}; + +static struct complaint basic_type_complaint = +{"cannot map ECOFF basic type 0x%x for %s", 0, 0}; + +static struct complaint unknown_type_qual_complaint = +{"unknown type qualifier 0x%x", 0, 0}; + +static struct complaint array_index_type_complaint = +{"illegal array index type for %s, assuming int", 0, 0}; + +static struct complaint bad_tag_guess_complaint = +{"guessed tag type of %s incorrectly", 0, 0}; + +static struct complaint block_member_complaint = +{"declaration block contains unhandled symbol type %d", 0, 0}; + +static struct complaint stEnd_complaint = +{"stEnd with storage class %d not handled", 0, 0}; + +static struct complaint unknown_mdebug_symtype_complaint = +{"unknown symbol type 0x%x", 0, 0}; + +static struct complaint stab_unknown_complaint = +{"unknown stabs symbol %s", 0, 0}; + +static struct complaint pdr_for_nonsymbol_complaint = +{"PDR for %s, but no symbol", 0, 0}; + +static struct complaint pdr_static_symbol_complaint = +{"can't handle PDR for static proc at 0x%lx", 0, 0}; + +static struct complaint bad_setjmp_pdr_complaint = +{"fixing bad setjmp PDR from libc", 0, 0}; + +static struct complaint bad_fbitfield_complaint = +{"can't handle TIR fBitfield for %s", 0, 0}; + +static struct complaint bad_continued_complaint = +{"illegal TIR continued for %s", 0, 0}; + +static struct complaint bad_rfd_entry_complaint = +{"bad rfd entry for %s: file %d, index %d", 0, 0}; + +static struct complaint unexpected_type_code_complaint = +{"unexpected type code for %s", 0, 0}; + +static struct complaint unable_to_cross_ref_complaint = +{"unable to cross ref btTypedef for %s", 0, 0}; + +static struct complaint bad_indirect_xref_complaint = +{"unable to cross ref btIndirect for %s", 0, 0}; + +static struct complaint illegal_forward_tq0_complaint = +{"illegal tq0 in forward typedef for %s", 0, 0}; + +static struct complaint illegal_forward_bt_complaint = +{"illegal bt %d in forward typedef for %s", 0, 0}; + +static struct complaint bad_linetable_guess_complaint = +{"guessed size of linetable for %s incorrectly", 0, 0}; + +static struct complaint bad_ext_ifd_complaint = +{"bad ifd for external symbol: %d (max %d)", 0, 0}; + +static struct complaint bad_ext_iss_complaint = +{"bad iss for external symbol: %ld (max %ld)", 0, 0}; + +/* Macros and extra defs */ + +/* Puns: hard to find whether -g was used and how */ + +#define MIN_GLEVEL GLEVEL_0 +#define compare_glevel(a,b) \ + (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \ + ((b) == GLEVEL_3) ? -1 : (int)((b) - (a))) + +/* Things that really are local to this module */ + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + +/* Current BFD. */ + +static bfd *cur_bfd; + +/* How to parse debugging information for CUR_BFD. */ + +static const struct ecoff_debug_swap *debug_swap; + +/* Pointers to debugging information for CUR_BFD. */ + +static struct ecoff_debug_info *debug_info; + +/* Pointer to current file decriptor record, and its index */ + +static FDR *cur_fdr; +static int cur_fd; + +/* Index of current symbol */ + +static int cur_sdx; + +/* Note how much "debuggable" this image is. We would like + to see at least one FDR with full symbols */ + +static max_gdbinfo; +static max_glevel; + +/* When examining .o files, report on undefined symbols */ + +static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs; + +/* Pseudo symbol to use when putting stabs into the symbol table. */ + +static char stabs_symbol[] = STABS_SYMBOL; + +/* Types corresponding to mdebug format bt* basic types. */ + +static struct type *mdebug_type_void; +static struct type *mdebug_type_char; +static struct type *mdebug_type_short; +static struct type *mdebug_type_int_32; +#define mdebug_type_int mdebug_type_int_32 +static struct type *mdebug_type_int_64; +static struct type *mdebug_type_long_32; +static struct type *mdebug_type_long_64; +static struct type *mdebug_type_long_long_64; +static struct type *mdebug_type_unsigned_char; +static struct type *mdebug_type_unsigned_short; +static struct type *mdebug_type_unsigned_int_32; +static struct type *mdebug_type_unsigned_int_64; +static struct type *mdebug_type_unsigned_long_32; +static struct type *mdebug_type_unsigned_long_64; +static struct type *mdebug_type_unsigned_long_long_64; +static struct type *mdebug_type_adr_32; +static struct type *mdebug_type_adr_64; +static struct type *mdebug_type_float; +static struct type *mdebug_type_double; +static struct type *mdebug_type_complex; +static struct type *mdebug_type_double_complex; +static struct type *mdebug_type_fixed_dec; +static struct type *mdebug_type_float_dec; +static struct type *mdebug_type_string; + +/* Types for symbols from files compiled without debugging info. */ + +static struct type *nodebug_func_symbol_type; +static struct type *nodebug_var_symbol_type; + +/* Nonzero if we have seen ecoff debugging info for a file. */ + +static int found_ecoff_debugging_info; + +/* Forward declarations */ + +static int +upgrade_type PARAMS ((int, struct type **, int, union aux_ext *, int, char *)); + +static void +parse_partial_symbols PARAMS ((struct objfile *, + struct section_offsets *)); + +static FDR +*get_rfd PARAMS ((int, int)); + +static int +has_opaque_xref PARAMS ((FDR *, SYMR *)); + +static int +cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code, + char **, int, char *)); + +static struct symbol * +new_symbol PARAMS ((char *)); + +static struct type * +new_type PARAMS ((char *)); + +static struct block * +new_block PARAMS ((int)); + +static struct symtab * +new_symtab PARAMS ((char *, int, int, struct objfile *)); + +static struct linetable * +new_linetable PARAMS ((int)); + +static struct blockvector * +new_bvect PARAMS ((int)); + +static int +parse_symbol PARAMS ((SYMR *, union aux_ext *, char *, int, struct section_offsets *)); + +static struct type * +parse_type PARAMS ((int, union aux_ext *, unsigned int, int *, int, char *)); + +static struct symbol * +mylookup_symbol PARAMS ((char *, struct block *, namespace_enum, + enum address_class)); + +static struct block * +shrink_block PARAMS ((struct block *, struct symtab *)); + +static PTR +xzalloc PARAMS ((unsigned int)); + +static void +sort_blocks PARAMS ((struct symtab *)); + +static int +compare_blocks PARAMS ((const void *, const void *)); + +static struct partial_symtab * +new_psymtab PARAMS ((char *, struct objfile *, struct section_offsets *)); + +static void +psymtab_to_symtab_1 PARAMS ((struct partial_symtab *, char *)); + +static void +add_block PARAMS ((struct block *, struct symtab *)); + +static void +add_symbol PARAMS ((struct symbol *, struct block *)); + +static int +add_line PARAMS ((struct linetable *, int, CORE_ADDR, int)); + +static struct linetable * +shrink_linetable PARAMS ((struct linetable *)); + +static void +handle_psymbol_enumerators PARAMS ((struct objfile *, FDR *, int, CORE_ADDR)); + +static char * +mdebug_next_symbol_text PARAMS ((struct objfile *)); + +/* Address bounds for the signal trampoline in inferior, if any */ + +CORE_ADDR sigtramp_address, sigtramp_end; + +/* Allocate zeroed memory */ + +static PTR +xzalloc (size) + unsigned int size; +{ + PTR p = xmalloc (size); + + memset (p, 0, size); + return p; +} + +/* Exported procedure: Builds a symtab from the PST partial one. + Restores the environment in effect when PST was created, delegates + most of the work to an ancillary procedure, and sorts + and reorders the symtab list at the end */ + +static void +mdebug_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + + if (!pst) + return; + + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", pst->filename); + gdb_flush (gdb_stdout); + } + + next_symbol_text_func = mdebug_next_symbol_text; + + psymtab_to_symtab_1 (pst, pst->filename); + + /* 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); + + if (info_verbose) + printf_filtered ("done.\n"); +} + +/* File-level interface functions */ + +/* Find a file descriptor given its index RF relative to a file CF */ + +static FDR * +get_rfd (cf, rf) + int cf, rf; +{ + FDR *fdrs; + register FDR *f; + RFDT rfd; + + fdrs = debug_info->fdr; + f = fdrs + cf; + /* Object files do not have the RFD table, all refs are absolute */ + if (f->rfdBase == 0) + return fdrs + rf; + (*debug_swap->swap_rfd_in) (cur_bfd, + ((char *) debug_info->external_rfd + + ((f->rfdBase + rf) + * debug_swap->external_rfd_size)), + &rfd); + return fdrs + rfd; +} + +/* Return a safer print NAME for a file descriptor */ + +static char * +fdr_name (f) + FDR *f; +{ + if (f->rss == -1) + return ""; + if (f->rss == 0) + return ""; + return debug_info->ss + f->issBase + f->rss; +} + + +/* Read in and parse the symtab of the file OBJFILE. Symbols from + different sections are relocated via the SECTION_OFFSETS. */ + +void +mdebug_build_psymtabs (objfile, swap, info, section_offsets) + struct objfile *objfile; + const struct ecoff_debug_swap *swap; + struct ecoff_debug_info *info; + struct section_offsets *section_offsets; +{ + cur_bfd = objfile->obfd; + debug_swap = swap; + debug_info = info; + + /* Make sure all the FDR information is swapped in. */ + if (info->fdr == (FDR *) NULL) + { + char *fdr_src; + char *fdr_end; + FDR *fdr_ptr; + + info->fdr = (FDR *) obstack_alloc (&objfile->psymbol_obstack, + (info->symbolic_header.ifdMax + * sizeof (FDR))); + fdr_src = info->external_fdr; + fdr_end = (fdr_src + + info->symbolic_header.ifdMax * swap->external_fdr_size); + fdr_ptr = info->fdr; + for (; fdr_src < fdr_end; fdr_src += swap->external_fdr_size, fdr_ptr++) + (*swap->swap_fdr_in) (objfile->obfd, fdr_src, fdr_ptr); + } + + parse_partial_symbols (objfile, section_offsets); + +#if 0 + /* Check to make sure file was compiled with -g. If not, warn the + user of this limitation. */ + if (compare_glevel (max_glevel, GLEVEL_2) < 0) + { + if (max_gdbinfo == 0) + printf_unfiltered ("\n%s not compiled with -g, debugging support is limited.\n", + objfile->name); + printf_unfiltered ("You should compile with -g2 or -g3 for best debugging support.\n"); + gdb_flush (gdb_stdout); + } +#endif +} + +/* Local utilities */ + +/* Map of FDR indexes to partial symtabs */ + +struct pst_map +{ + struct partial_symtab *pst; /* the psymtab proper */ + long n_globals; /* exported globals (external symbols) */ + long globals_offset; /* cumulative */ +}; + + +/* Utility stack, used to nest procedures and blocks properly. + It is a doubly linked list, to avoid too many alloc/free. + Since we might need it quite a few times it is NOT deallocated + after use. */ + +static struct parse_stack +{ + struct parse_stack *next, *prev; + struct symtab *cur_st; /* Current symtab. */ + struct block *cur_block; /* Block in it. */ + + /* What are we parsing. stFile, or stBlock are for files and + blocks. stProc or stStaticProc means we have seen the start of a + procedure, but not the start of the block within in. When we see + the start of that block, we change it to stNil, without pushing a + new block, i.e. stNil means both a procedure and a block. */ + + int blocktype; + + int maxsyms; /* Max symbols in this block. */ + struct type *cur_type; /* Type we parse fields for. */ + int cur_field; /* Field number in cur_type. */ + CORE_ADDR procadr; /* Start addres of this procedure */ + int numargs; /* Its argument count */ +} + + *top_stack; /* Top stack ptr */ + + +/* Enter a new lexical context */ + +static void +push_parse_stack () +{ + struct parse_stack *new; + + /* Reuse frames if possible */ + if (top_stack && top_stack->prev) + new = top_stack->prev; + else + new = (struct parse_stack *) xzalloc (sizeof (struct parse_stack)); + /* Initialize new frame with previous content */ + if (top_stack) + { + register struct parse_stack *prev = new->prev; + + *new = *top_stack; + top_stack->prev = new; + new->prev = prev; + new->next = top_stack; + } + top_stack = new; +} + +/* Exit a lexical context */ + +static void +pop_parse_stack () +{ + if (!top_stack) + return; + if (top_stack->next) + top_stack = top_stack->next; +} + + +/* Cross-references might be to things we haven't looked at + yet, e.g. type references. To avoid too many type + duplications we keep a quick fixup table, an array + of lists of references indexed by file descriptor */ + +struct mdebug_pending +{ + struct mdebug_pending *next; /* link */ + char *s; /* the unswapped symbol */ + struct type *t; /* its partial type descriptor */ +}; + + +/* The pending information is kept for an entire object file, and used + to be in the sym_private field. I took it out when I split + mdebugread from mipsread, because this might not be the only type + of symbols read from an object file. Instead, we allocate the + pending information table when we create the partial symbols, and + we store a pointer to the single table in each psymtab. */ + +static struct mdebug_pending **pending_list; + +/* Check whether we already saw symbol SH in file FH */ + +static struct mdebug_pending * +is_pending_symbol (fh, sh) + FDR *fh; + char *sh; +{ + int f_idx = fh - debug_info->fdr; + register struct mdebug_pending *p; + + /* Linear search is ok, list is typically no more than 10 deep */ + for (p = pending_list[f_idx]; p; p = p->next) + if (p->s == sh) + break; + return p; +} + +/* Add a new symbol SH of type T */ + +static void +add_pending (fh, sh, t) + FDR *fh; + char *sh; + struct type *t; +{ + int f_idx = fh - debug_info->fdr; + struct mdebug_pending *p = is_pending_symbol (fh, sh); + + /* Make sure we do not make duplicates */ + if (!p) + { + p = ((struct mdebug_pending *) + obstack_alloc (¤t_objfile->psymbol_obstack, + sizeof (struct mdebug_pending))); + p->s = sh; + p->t = t; + p->next = pending_list[f_idx]; + pending_list[f_idx] = p; + } +} + + +/* Parsing Routines proper. */ + +/* Parse a single symbol. Mostly just make up a GDB symbol for it. + For blocks, procedures and types we open a new lexical context. + This is basically just a big switch on the symbol's type. Argument + AX is the base pointer of aux symbols for this file (fh->iauxBase). + EXT_SH points to the unswapped symbol, which is needed for struct, + union, etc., types; it is NULL for an EXTR. BIGEND says whether + aux symbols are big-endian or little-endian. Return count of + SYMR's handled (normally one). */ + +static int +parse_symbol (sh, ax, ext_sh, bigend, section_offsets) + SYMR *sh; + union aux_ext *ax; + char *ext_sh; + int bigend; + struct section_offsets *section_offsets; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) = + debug_swap->swap_sym_in; + char *name; + struct symbol *s; + struct block *b; + struct mdebug_pending *pend; + struct type *t; + struct field *f; + int count = 1; + enum address_class class; + TIR tir; + long svalue = sh->value; + int bitsize; + + if (ext_sh == (char *) NULL) + name = debug_info->ssext + sh->iss; + else + name = debug_info->ss + cur_fdr->issBase + sh->iss; + + switch (sh->sc) + { + case scText: + /* Do not relocate relative values. + The value of a stEnd symbol is the displacement from the + corresponding start symbol value. + The value of a stBlock symbol is the displacement from the + procedure address. */ + if (sh->st != stEnd && sh->st != stBlock) + sh->value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + sh->value += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + sh->value += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (sh->st) + { + case stNil: + break; + + case stGlobal: /* external symbol, goes into global block */ + class = LOC_STATIC; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + s = new_symbol (name); + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stStatic: /* static data, goes into current block. */ + class = LOC_STATIC; + b = top_stack->cur_block; + s = new_symbol (name); + if (sh->sc == scCommon || sh->sc == scSCommon) + { + /* It is a FORTRAN common block. At least for SGI Fortran the + address is not in the symbol; we need to fix it later in + scan_file_globals. */ + int bucket = hashname (SYMBOL_NAME (s)); + SYMBOL_VALUE_CHAIN (s) = global_sym_chain[bucket]; + global_sym_chain[bucket] = s; + } + else + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stLocal: /* local variable, goes into current block */ + if (sh->sc == scRegister) + { + class = LOC_REGISTER; + svalue = ECOFF_REG_TO_REGNUM (svalue); + } + else + class = LOC_LOCAL; + b = top_stack->cur_block; + s = new_symbol (name); + SYMBOL_VALUE (s) = svalue; + + data: /* Common code for symbols describing data */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = class; + add_symbol (s, b); + + /* Type could be missing if file is compiled without debugging info. */ + if (sh->sc == scUndefined || sh->sc == scNil || sh->index == indexNil) + SYMBOL_TYPE (s) = nodebug_var_symbol_type; + else + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + /* Value of a data symbol is its memory address */ + break; + + case stParam: /* arg to procedure, goes into current block */ + max_gdbinfo++; + found_ecoff_debugging_info = 1; + top_stack->numargs++; + + /* Special GNU C++ name. */ + if (is_cplus_marker (name[0]) && name[1] == 't' && name[2] == 0) + name = "this"; /* FIXME, not alloc'd in obstack */ + s = new_symbol (name); + + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + switch (sh->sc) + { + case scRegister: + /* Pass by value in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + case scVar: + /* Pass by reference on stack. */ + SYMBOL_CLASS(s) = LOC_REF_ARG; + break; + case scVarRegister: + /* Pass by reference in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM_ADDR; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + default: + /* Pass by value on stack. */ + SYMBOL_CLASS(s) = LOC_ARG; + break; + } + SYMBOL_VALUE (s) = svalue; + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + add_symbol (s, top_stack->cur_block); + break; + + case stLabel: /* label, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; /* so that it can be used */ + SYMBOL_CLASS (s) = LOC_LABEL; /* but not misused */ + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + SYMBOL_TYPE (s) = mdebug_type_int; + add_symbol (s, top_stack->cur_block); + break; + + case stProc: /* Procedure, usually goes into global block */ + case stStaticProc: /* Static procedure, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Type of the return value */ + if (sh->sc == scUndefined || sh->sc == scNil) + t = mdebug_type_int; + else + t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name); + b = top_stack->cur_block; + if (sh->st == stProc) + { + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + /* The next test should normally be true, but provides a + hook for nested functions (which we don't want to make + global). */ + if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + /* Irix 5 sometimes has duplicate names for the same + function. We want to add such names up at the global + level, not as a nested function. */ + else if (sh->value == top_stack->procadr) + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + } + add_symbol (s, b); + + /* Make a type for the procedure itself */ + SYMBOL_TYPE (s) = lookup_function_type (t); + + /* Create and enter a new lexical context */ + b = new_block (top_stack->maxsyms); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = BLOCK_END (b) = sh->value; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); + + /* Not if we only have partial info */ + if (sh->sc == scUndefined || sh->sc == scNil) + break; + + push_parse_stack (); + top_stack->cur_block = b; + top_stack->blocktype = sh->st; + top_stack->cur_type = SYMBOL_TYPE (s); + top_stack->cur_field = -1; + top_stack->procadr = sh->value; + top_stack->numargs = 0; + break; + + /* Beginning of code for structure, union, and enum definitions. + They all share a common set of local variables, defined here. */ + { + enum type_code type_code; + char *ext_tsym; + int nfields; + long max_value; + struct field *f; + + case stStruct: /* Start a block defining a struct type */ + type_code = TYPE_CODE_STRUCT; + goto structured_common; + + case stUnion: /* Start a block defining a union type */ + type_code = TYPE_CODE_UNION; + goto structured_common; + + case stEnum: /* Start a block defining an enum type */ + type_code = TYPE_CODE_ENUM; + goto structured_common; + + case stBlock: /* Either a lexical block, or some type */ + if (sh->sc != scInfo && sh->sc != scCommon && sh->sc != scSCommon) + goto case_stBlock_code; /* Lexical block */ + + type_code = TYPE_CODE_UNDEF; /* We have a type. */ + + /* Common code for handling struct, union, enum, and/or as-yet- + unknown-type blocks of info about structured data. `type_code' + has been set to the proper TYPE_CODE, if we know it. */ + structured_common: + found_ecoff_debugging_info = 1; + push_parse_stack (); + top_stack->blocktype = stBlock; + + /* First count the number of fields and the highest value. */ + nfields = 0; + max_value = 0; + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + switch (tsym.st) + { + case stEnd: + goto end_of_fields; + + case stMember: + if (nfields == 0 && type_code == TYPE_CODE_UNDEF) + /* If the type of the member is Nil (or Void), + without qualifiers, assume the tag is an + enumeration. + Alpha cc -migrate enums are recognized by a zero + index and a zero symbol value. */ + if (tsym.index == indexNil + || (tsym.index == 0 && sh->value == 0)) + type_code = TYPE_CODE_ENUM; + else + { + (*debug_swap->swap_tir_in) (bigend, + &ax[tsym.index].a_ti, + &tir); + if ((tir.bt == btNil || tir.bt == btVoid) + && tir.tq0 == tqNil) + type_code = TYPE_CODE_ENUM; + } + nfields++; + if (tsym.value > max_value) + max_value = tsym.value; + break; + + case stBlock: + case stUnion: + case stEnum: + case stStruct: + { +#if 0 + /* This is a no-op; is it trying to tell us something + we should be checking? */ + if (tsym.sc == scVariant); /*UNIMPLEMENTED*/ +#endif + if (tsym.index != 0) + { + /* This is something like a struct within a + struct. Skip over the fields of the inner + struct. The -1 is because the for loop will + increment ext_tsym. */ + ext_tsym = ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + tsym.index - 1) + * external_sym_size)); + } + } + break; + + case stTypedef: + /* mips cc puts out a typedef for struct x if it is not yet + defined when it encounters + struct y { struct x *xp; }; + Just ignore it. */ + break; + + case stIndirect: + /* Irix5 cc puts out a stIndirect for struct x if it is not + yet defined when it encounters + struct y { struct x *xp; }; + Just ignore it. */ + break; + + default: + complain (&block_member_complaint, tsym.st); + } + } + end_of_fields:; + + /* In an stBlock, there is no way to distinguish structs, + unions, and enums at this point. This is a bug in the + original design (that has been fixed with the recent + addition of the stStruct, stUnion, and stEnum symbol + types.) The way you can tell is if/when you see a variable + or field of that type. In that case the variable's type + (in the AUX table) says if the type is struct, union, or + enum, and points back to the stBlock here. So you can + patch the tag kind up later - but only if there actually is + a variable or field of that type. + + So until we know for sure, we will guess at this point. + The heuristic is: + If the first member has index==indexNil or a void type, + assume we have an enumeration. + Otherwise, if there is more than one member, and all + the members have offset 0, assume we have a union. + Otherwise, assume we have a struct. + + The heuristic could guess wrong in the case of of an + enumeration with no members or a union with one (or zero) + members, or when all except the last field of a struct have + width zero. These are uncommon and/or illegal situations, + and in any case guessing wrong probably doesn't matter + much. + + But if we later do find out we were wrong, we fixup the tag + kind. Members of an enumeration must be handled + differently from struct/union fields, and that is harder to + patch up, but luckily we shouldn't need to. (If there are + any enumeration members, we can tell for sure it's an enum + here.) */ + + if (type_code == TYPE_CODE_UNDEF) + if (nfields > 1 && max_value == 0) + type_code = TYPE_CODE_UNION; + else + type_code = TYPE_CODE_STRUCT; + + /* Create a new type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mdebug_pending *) NULL) + { + t = new_type (NULL); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* Do not set the tag name if it is a compiler generated tag name + (.Fxx or .xxfake or empty) for unnamed struct/union/enums. + Alpha cc puts out an sh->iss of zero for those. */ + if (sh->iss == 0 || name[0] == '.' || name[0] == '\0') + TYPE_TAG_NAME (t) = NULL; + else + TYPE_TAG_NAME (t) = obconcat (¤t_objfile->symbol_obstack, + "", "", name); + + TYPE_CODE (t) = type_code; + TYPE_LENGTH (t) = sh->value; + TYPE_NFIELDS (t) = nfields; + TYPE_FIELDS (t) = f = ((struct field *) + TYPE_ALLOC (t, + nfields * sizeof (struct field))); + + if (type_code == TYPE_CODE_ENUM) + { + int unsigned_enum = 1; + + /* This is a non-empty enum. */ + + /* DEC c89 has the number of enumerators in the sh.value field, + not the type length, so we have to compensate for that + incompatibility quirk. + This might do the wrong thing for an enum with one or two + enumerators and gcc -gcoff -fshort-enums, but these cases + are hopefully rare enough. + Alpha cc -migrate has a sh.value field of zero, we adjust + that too. */ + if (TYPE_LENGTH (t) == TYPE_NFIELDS (t) + || TYPE_LENGTH (t) == 0) + TYPE_LENGTH (t) = TARGET_INT_BIT / HOST_CHAR_BIT; + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + struct symbol *enum_sym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + if (tsym.st != stMember) + break; + + f->bitpos = tsym.value; + f->type = t; + f->name = debug_info->ss + cur_fdr->issBase + tsym.iss; + f->bitsize = 0; + + enum_sym = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + memset ((PTR) enum_sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (enum_sym) = f->name; + SYMBOL_CLASS (enum_sym) = LOC_CONST; + SYMBOL_TYPE (enum_sym) = t; + SYMBOL_NAMESPACE (enum_sym) = VAR_NAMESPACE; + SYMBOL_VALUE (enum_sym) = tsym.value; + if (SYMBOL_VALUE (enum_sym) < 0) + unsigned_enum = 0; + add_symbol (enum_sym, top_stack->cur_block); + + /* Skip the stMembers that we've handled. */ + count++; + f++; + } + if (unsigned_enum) + TYPE_FLAGS (t) |= TYPE_FLAG_UNSIGNED; + } + /* make this the current type */ + top_stack->cur_type = t; + top_stack->cur_field = 0; + + /* Do not create a symbol for alpha cc unnamed structs. */ + if (sh->iss == 0) + break; + + /* gcc puts out an empty struct for an opaque struct definitions, + do not create a symbol for it either. */ + if (TYPE_NFIELDS (t) == 0) + { + TYPE_FLAGS (t) |= TYPE_FLAG_STUB; + break; + } + + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_VALUE (s) = 0; + SYMBOL_TYPE (s) = t; + add_symbol (s, top_stack->cur_block); + break; + + /* End of local variables shared by struct, union, enum, and + block (as yet unknown struct/union/enum) processing. */ + } + + case_stBlock_code: + found_ecoff_debugging_info = 1; + /* beginnning of (code) block. Value of symbol + is the displacement from procedure start */ + push_parse_stack (); + + /* Do not start a new block if this is the outermost block of a + procedure. This allows the LOC_BLOCK symbol to point to the + block with the local variables, so funcname::var works. */ + if (top_stack->blocktype == stProc + || top_stack->blocktype == stStaticProc) + { + top_stack->blocktype = stNil; + break; + } + + top_stack->blocktype = stBlock; + b = new_block (top_stack->maxsyms); + BLOCK_START (b) = sh->value + top_stack->procadr; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + top_stack->cur_block = b; + add_block (b, top_stack->cur_st); + break; + + case stEnd: /* end (of anything) */ + if (sh->sc == scInfo || sh->sc == scCommon || sh->sc == scSCommon) + { + /* Finished with type */ + top_stack->cur_type = 0; + } + else if (sh->sc == scText && + (top_stack->blocktype == stProc || + top_stack->blocktype == stStaticProc)) + { + /* Finished with procedure */ + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + struct mips_extra_func_info *e; + struct block *b; + struct type *ftype = top_stack->cur_type; + int i; + + BLOCK_END (top_stack->cur_block) += sh->value; /* size */ + + /* Make up special symbol to contain procedure specific info */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = mdebug_type_void; + e = ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + memset ((PTR) e, 0, sizeof (struct mips_extra_func_info)); + SYMBOL_VALUE (s) = (long) e; + e->numargs = top_stack->numargs; + e->pdr.framereg = -1; + add_symbol (s, top_stack->cur_block); + + /* Reallocate symbols, saving memory */ + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* f77 emits proc-level with address bounds==[0,0], + So look for such child blocks, and patch them. */ + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + { + struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SUPERBLOCK (b_bad) == b + && BLOCK_START (b_bad) == top_stack->procadr + && BLOCK_END (b_bad) == top_stack->procadr) + { + BLOCK_START (b_bad) = BLOCK_START (b); + BLOCK_END (b_bad) = BLOCK_END (b); + } + } + + if (TYPE_NFIELDS (ftype) <= 0) + { + /* No parameter type information is recorded with the function's + type. Set that from the type of the parameter symbols. */ + int nparams = top_stack->numargs; + int iparams; + struct symbol *sym; + + if (nparams > 0) + { + TYPE_NFIELDS (ftype) = nparams; + TYPE_FIELDS (ftype) = (struct field *) + TYPE_ALLOC (ftype, nparams * sizeof (struct field)); + + for (i = iparams = 0; iparams < nparams; i++) + { + sym = BLOCK_SYM (b, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym); + iparams++; + break; + default: + break; + } + } + } + } + } + else if (sh->sc == scText && top_stack->blocktype == stBlock) + { + /* End of (code) block. The value of the symbol is the + displacement from the procedure`s start address of the + end of this block. */ + BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr; + shrink_block (top_stack->cur_block, top_stack->cur_st); + } + else if (sh->sc == scText && top_stack->blocktype == stNil) + { + /* End of outermost block. Pop parse stack and ignore. The + following stEnd of stProc will take care of the block. */ + ; + } + else if (sh->sc == scText && top_stack->blocktype == stFile) + { + /* End of file. Pop parse stack and ignore. Higher + level code deals with this. */ + ; + } + else + complain (&stEnd_complaint, sh->sc); + + pop_parse_stack (); /* restore previous lexical context */ + break; + + case stMember: /* member of struct or union */ + f = &TYPE_FIELDS (top_stack->cur_type)[top_stack->cur_field++]; + f->name = name; + f->bitpos = sh->value; + bitsize = 0; + f->type = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name); + f->bitsize = bitsize; + break; + + case stIndirect: /* forward declaration on Irix5 */ + /* Forward declarations from Irix5 cc are handled by cross_ref, + skip them. */ + break; + + case stTypedef: /* type definition */ + found_ecoff_debugging_info = 1; + + /* Typedefs for forward declarations and opaque structs from alpha cc + are handled by cross_ref, skip them. */ + if (sh->iss == 0) + break; + + /* Parse the type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mdebug_pending *) NULL) + { + t = parse_type (cur_fd, ax, sh->index, (int *)NULL, bigend, name); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* mips cc puts out a typedef with the name of the struct for forward + declarations. These should not go into the symbol table and + TYPE_NAME should not be set for them. + They can't be distinguished from an intentional typedef to + the same name however: + x.h: + struct x { int ix; int jx; }; + struct xx; + x.c: + typedef struct x x; + struct xx {int ixx; int jxx; }; + generates a cross referencing stTypedef for x and xx. + The user visible effect of this is that the type of a pointer + to struct foo sometimes is given as `foo *' instead of `struct foo *'. + The problem is fixed with alpha cc and Irix5 cc. */ + + /* However if the typedef cross references to an opaque aggregate, it + is safe to omit it from the symbol table. */ + + if (has_opaque_xref (cur_fdr, sh)) + break; + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_BLOCK_VALUE (s) = top_stack->cur_block; + SYMBOL_TYPE (s) = t; + add_symbol (s, top_stack->cur_block); + + /* Incomplete definitions of structs should not get a name. */ + if (TYPE_NAME (SYMBOL_TYPE (s)) == NULL + && (TYPE_NFIELDS (SYMBOL_TYPE (s)) != 0 + || (TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_STRUCT + && TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_UNION))) + { + if (TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; CC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type + refering to the stTypedef symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + } + else + TYPE_NAME (SYMBOL_TYPE (s)) = SYMBOL_NAME (s); + } + break; + + case stFile: /* file name */ + push_parse_stack (); + top_stack->blocktype = sh->st; + break; + + /* I`ve never seen these for C */ + case stRegReloc: + break; /* register relocation */ + case stForward: + break; /* forwarding address */ + case stConstant: + break; /* constant */ + default: + complain (&unknown_mdebug_symtype_complaint, sh->st); + break; + } + + return count; +} + +/* Parse the type information provided in the raw AX entries for + the symbol SH. Return the bitfield size in BS, in case. + We must byte-swap the AX entries before we use them; BIGEND says whether + they are big-endian or little-endian (from fh->fBigendian). */ + +static struct type * +parse_type (fd, ax, aux_index, bs, bigend, sym_name) + int fd; + union aux_ext *ax; + unsigned int aux_index; + int *bs; + int bigend; + char *sym_name; +{ + /* Null entries in this map are treated specially */ + static struct type **map_bt[] = + { + &mdebug_type_void, /* btNil */ + &mdebug_type_adr_32, /* btAdr */ + &mdebug_type_char, /* btChar */ + &mdebug_type_unsigned_char, /* btUChar */ + &mdebug_type_short, /* btShort */ + &mdebug_type_unsigned_short, /* btUShort */ + &mdebug_type_int_32, /* btInt */ + &mdebug_type_unsigned_int_32, /* btUInt */ + &mdebug_type_long_32, /* btLong */ + &mdebug_type_unsigned_long_32, /* btULong */ + &mdebug_type_float, /* btFloat */ + &mdebug_type_double, /* btDouble */ + 0, /* btStruct */ + 0, /* btUnion */ + 0, /* btEnum */ + 0, /* btTypedef */ + 0, /* btRange */ + 0, /* btSet */ + &mdebug_type_complex, /* btComplex */ + &mdebug_type_double_complex, /* btDComplex */ + 0, /* btIndirect */ + &mdebug_type_fixed_dec, /* btFixedDec */ + &mdebug_type_float_dec, /* btFloatDec */ + &mdebug_type_string, /* btString */ + 0, /* btBit */ + 0, /* btPicture */ + &mdebug_type_void, /* btVoid */ + 0, /* DEC C++: Pointer to member */ + 0, /* DEC C++: Virtual function table */ + 0, /* DEC C++: Class (Record) */ + &mdebug_type_long_64, /* btLong64 */ + &mdebug_type_unsigned_long_64, /* btULong64 */ + &mdebug_type_long_long_64, /* btLongLong64 */ + &mdebug_type_unsigned_long_long_64, /* btULongLong64 */ + &mdebug_type_adr_64, /* btAdr64 */ + &mdebug_type_int_64, /* btInt64 */ + &mdebug_type_unsigned_int_64, /* btUInt64 */ + }; + + TIR t[1]; + struct type *tp = 0; + enum type_code type_code = TYPE_CODE_UNDEF; + + /* Handle undefined types, they have indexNil. */ + if (aux_index == indexNil) + return mdebug_type_int; + + /* Handle corrupt aux indices. */ + if (aux_index >= (debug_info->fdr + fd)->caux) + { + complain (&index_complaint, sym_name); + return mdebug_type_int; + } + ax += aux_index; + + /* Use aux as a type information record, map its basic type. */ + (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); + if (t->bt >= (sizeof (map_bt) / sizeof (*map_bt))) + { + complain (&basic_type_complaint, t->bt, sym_name); + return mdebug_type_int; + } + if (map_bt[t->bt]) + { + tp = *map_bt[t->bt]; + } + else + { + tp = NULL; + /* Cannot use builtin types -- build our own */ + switch (t->bt) + { + case btStruct: + type_code = TYPE_CODE_STRUCT; + break; + case btUnion: + type_code = TYPE_CODE_UNION; + break; + case btEnum: + type_code = TYPE_CODE_ENUM; + break; + case btRange: + type_code = TYPE_CODE_RANGE; + break; + case btSet: + type_code = TYPE_CODE_SET; + break; + case btIndirect: + /* alpha cc -migrate uses this for typedefs. The true type will + be obtained by crossreferencing below. */ + type_code = TYPE_CODE_ERROR; + break; + case btTypedef: + /* alpha cc uses this for typedefs. The true type will be + obtained by crossreferencing below. */ + type_code = TYPE_CODE_ERROR; + break; + default: + complain (&basic_type_complaint, t->bt, sym_name); + return mdebug_type_int; + } + } + + /* Move on to next aux */ + ax++; + + if (t->fBitfield) + { + int width = AUX_GET_WIDTH (bigend, ax); + + /* Inhibit core dumps with some cfront generated objects that + corrupt the TIR. */ + if (bs == (int *)NULL) + { + /* Alpha cc -migrate encodes char and unsigned char types + as short and unsigned short types with a field width of 8. + Enum types also have a field width which we ignore for now. */ + if (t->bt == btShort && width == 8) + tp = mdebug_type_char; + else if (t->bt == btUShort && width == 8) + tp = mdebug_type_unsigned_char; + else if (t->bt == btEnum) + ; + else + complain (&bad_fbitfield_complaint, sym_name); + } + else + *bs = width; + ax++; + } + + /* A btIndirect entry cross references to an aux entry containing + the type. */ + if (t->bt == btIndirect) + { + RNDXR rn[1]; + int rf; + FDR *xref_fh; + int xref_fd; + + (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn); + ax++; + if (rn->rfd == 0xfff) + { + rf = AUX_GET_ISYM (bigend, ax); + ax++; + } + else + rf = rn->rfd; + + if (rf == -1) + { + complain (&bad_indirect_xref_complaint, sym_name); + return mdebug_type_int; + } + xref_fh = get_rfd (fd, rf); + xref_fd = xref_fh - debug_info->fdr; + tp = parse_type (xref_fd, debug_info->external_aux + xref_fh->iauxBase, + rn->index, (int *) NULL, xref_fh->fBigendian, sym_name); + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. */ + if (t->bt == btStruct || + t->bt == btUnion || + t->bt == btEnum || + + /* btSet (I think) implies that the name is a tag name, not a typedef + name. This apparently is a MIPS extension for C sets. */ + t->bt == btSet) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* DEC c89 produces cross references to qualified aggregate types, + dereference them. */ + while (TYPE_CODE (tp) == TYPE_CODE_PTR + || TYPE_CODE (tp) == TYPE_CODE_ARRAY) + tp = tp->target_type; + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_STRUCT + && TYPE_CODE (tp) != TYPE_CODE_UNION + && TYPE_CODE (tp) != TYPE_CODE_ENUM) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. + But for struct vs. union a wrong guess is harmless, so + don't complain(). */ + if ((TYPE_CODE (tp) == TYPE_CODE_ENUM + && type_code != TYPE_CODE_ENUM) + || (TYPE_CODE (tp) != TYPE_CODE_ENUM + && type_code == TYPE_CODE_ENUM)) + { + complain (&bad_tag_guess_complaint, sym_name); + } + + if (TYPE_CODE (tp) != type_code) + { + TYPE_CODE (tp) = type_code; + } + + /* Do not set the tag name if it is a compiler generated tag name + (.Fxx or .xxfake or empty) for unnamed struct/union/enums. */ + if (name[0] == '.' || name[0] == '\0') + TYPE_TAG_NAME (tp) = NULL; + else if (TYPE_TAG_NAME (tp) == NULL + || !STREQ (TYPE_TAG_NAME (tp), name)) + TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. + FIXME: We are not doing any guessing on range types. */ + if (t->bt == btRange) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_RANGE) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. */ + if (TYPE_CODE (tp) != type_code) + { + complain (&bad_tag_guess_complaint, sym_name); + TYPE_CODE (tp) = type_code; + } + if (TYPE_NAME (tp) == NULL || !STREQ (TYPE_NAME (tp), name)) + TYPE_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + if (t->bt == btTypedef) + { + char *name; + + /* Try to cross reference this type, it should succeed. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + { + complain (&unable_to_cross_ref_complaint, sym_name); + tp = mdebug_type_int; + } + } + + /* Deal with range types */ + if (t->bt == btRange) + { + TYPE_NFIELDS (tp) = 2; + TYPE_FIELDS (tp) = ((struct field *) + TYPE_ALLOC (tp, 2 * sizeof (struct field))); + TYPE_FIELD_NAME (tp, 0) = obsavestring ("Low", strlen ("Low"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax); + ax++; + TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 1) = AUX_GET_DNHIGH (bigend, ax); + ax++; + } + + /* Parse all the type qualifiers now. If there are more + than 6 the game will continue in the next aux */ + + while (1) + { +#define PARSE_TQ(tq) \ + if (t->tq != tqNil) \ + ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \ + else \ + break; + + PARSE_TQ (tq0); + PARSE_TQ (tq1); + PARSE_TQ (tq2); + PARSE_TQ (tq3); + PARSE_TQ (tq4); + PARSE_TQ (tq5); +#undef PARSE_TQ + + /* mips cc 2.x and gcc never put out continued aux entries. */ + if (!t->continued) + break; + + (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); + ax++; + } + + /* Complain for illegal continuations due to corrupt aux entries. */ + if (t->continued) + complain (&bad_continued_complaint, sym_name); + + return tp; +} + +/* Make up a complex type from a basic one. Type is passed by + reference in TPP and side-effected as necessary. The type + qualifier TQ says how to handle the aux symbols at AX for + the symbol SX we are currently analyzing. BIGEND says whether + aux symbols are big-endian or little-endian. + Returns the number of aux symbols we parsed. */ + +static int +upgrade_type (fd, tpp, tq, ax, bigend, sym_name) + int fd; + struct type **tpp; + int tq; + union aux_ext *ax; + int bigend; + char *sym_name; +{ + int off; + struct type *t; + + /* Used in array processing */ + int rf, id; + FDR *fh; + struct type *range; + struct type *indx; + int lower, upper; + RNDXR rndx; + + switch (tq) + { + case tqPtr: + t = lookup_pointer_type (*tpp); + *tpp = t; + return 0; + + case tqProc: + t = lookup_function_type (*tpp); + *tpp = t; + return 0; + + case tqArray: + off = 0; + + /* Determine and record the domain type (type of index) */ + (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, &rndx); + id = rndx.index; + rf = rndx.rfd; + if (rf == 0xfff) + { + ax++; + rf = AUX_GET_ISYM (bigend, ax); + off++; + } + fh = get_rfd (fd, rf); + + indx = parse_type (fh - debug_info->fdr, + debug_info->external_aux + fh->iauxBase, + id, (int *) NULL, bigend, sym_name); + + /* The bounds type should be an integer type, but might be anything + else due to corrupt aux entries. */ + if (TYPE_CODE (indx) != TYPE_CODE_INT) + { + complain (&array_index_type_complaint, sym_name); + indx = mdebug_type_int; + } + + /* Get the bounds, and create the array type. */ + ax++; + lower = AUX_GET_DNLOW (bigend, ax); + ax++; + upper = AUX_GET_DNHIGH (bigend, ax); + ax++; + rf = AUX_GET_WIDTH (bigend, ax); /* bit size of array element */ + + range = create_range_type ((struct type *) NULL, indx, + lower, upper); + + t = create_array_type ((struct type *) NULL, *tpp, range); + + /* We used to fill in the supplied array element bitsize + here if the TYPE_LENGTH of the target type was zero. + This happens for a `pointer to an array of anonymous structs', + but in this case the array element bitsize is also zero, + so nothing is gained. + And we used to check the TYPE_LENGTH of the target type against + the supplied array element bitsize. + gcc causes a mismatch for `pointer to array of object', + since the sdb directives it uses do not have a way of + specifying the bitsize, but it does no harm (the + TYPE_LENGTH should be correct) and we should be able to + ignore the erroneous bitsize from the auxiliary entry safely. + dbx seems to ignore it too. */ + + /* TYPE_FLAG_TARGET_STUB now takes care of the zero TYPE_LENGTH + problem. */ + if (TYPE_LENGTH (*tpp) == 0) + { + TYPE_FLAGS (t) |= TYPE_FLAG_TARGET_STUB; + } + + *tpp = t; + return 4 + off; + + case tqVol: + /* Volatile -- currently ignored */ + return 0; + + case tqConst: + /* Const -- currently ignored */ + return 0; + + default: + complain (&unknown_type_qual_complaint, tq); + return 0; + } +} + + +/* Parse a procedure descriptor record PR. Note that the procedure is + parsed _after_ the local symbols, now we just insert the extra + information we need into a MIPS_EFI_SYMBOL_NAME symbol that has + already been placed in the procedure's main block. Note also that + images that have been partially stripped (ld -x) have been deprived + of local symbols, and we have to cope with them here. FIRST_OFF is + the offset of the first procedure for this FDR; we adjust the + address by this amount, but I don't know why. SEARCH_SYMTAB is the symtab + to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol + in question, or NULL to use top_stack->cur_block. */ + +static void parse_procedure PARAMS ((PDR *, struct symtab *, CORE_ADDR, + struct partial_symtab *)); + +static void +parse_procedure (pr, search_symtab, lowest_pdr_addr, pst) + PDR *pr; + struct symtab *search_symtab; + CORE_ADDR lowest_pdr_addr; + struct partial_symtab *pst; +{ + struct symbol *s, *i; + struct block *b; + struct mips_extra_func_info *e; + char *sh_name; + + /* Simple rule to find files linked "-x" */ + if (cur_fdr->rss == -1) + { + if (pr->isym == -1) + { + /* Static procedure at address pr->adr. Sigh. */ + /* FIXME-32x64. assuming pr->adr fits in long. */ + complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr); + return; + } + else + { + /* external */ + EXTR she; + + (*debug_swap->swap_ext_in) (cur_bfd, + ((char *) debug_info->external_ext + + (pr->isym + * debug_swap->external_ext_size)), + &she); + sh_name = debug_info->ssext + she.asym.iss; + } + } + else + { + /* Full symbols */ + SYMR sh; + + (*debug_swap->swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + pr->isym) + * debug_swap->external_sym_size)), + &sh); + sh_name = debug_info->ss + cur_fdr->issBase + sh.iss; + } + + if (search_symtab != NULL) + { +#if 0 + /* This loses both in the case mentioned (want a static, find a global), + but also if we are looking up a non-mangled name which happens to + match the name of a mangled function. */ + /* We have to save the cur_fdr across the call to lookup_symbol. + If the pdr is for a static function and if a global function with + the same name exists, lookup_symbol will eventually read in the symtab + for the global function and clobber cur_fdr. */ + FDR *save_cur_fdr = cur_fdr; + s = lookup_symbol (sh_name, NULL, VAR_NAMESPACE, 0, NULL); + cur_fdr = save_cur_fdr; +#else + s = mylookup_symbol + (sh_name, + BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK), + VAR_NAMESPACE, + LOC_BLOCK); +#endif + } + else + s = mylookup_symbol (sh_name, top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK); + + if (s != 0) + { + b = SYMBOL_BLOCK_VALUE (s); + } + else + { + complain (&pdr_for_nonsymbol_complaint, sh_name); +#if 1 + return; +#else +/* FIXME -- delete. We can't do symbol allocation now; it's all done. */ + s = new_symbol (sh_name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Donno its type, hope int is ok */ + SYMBOL_TYPE (s) = lookup_function_type (mdebug_type_int); + add_symbol (s, top_stack->cur_block); + /* Wont have symbols for this one */ + b = new_block (2); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = pr->adr; + /* BOUND used to be the end of procedure's text, but the + argument is no longer passed in. */ + BLOCK_END (b) = bound; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); +#endif + } + + i = mylookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, LOC_CONST); + + if (i) + { + e = (struct mips_extra_func_info *) SYMBOL_VALUE (i); + e->pdr = *pr; + e->pdr.isym = (long) s; + e->pdr.adr += pst->textlow - lowest_pdr_addr; + + /* Correct incorrect setjmp procedure descriptor from the library + to make backtrace through setjmp work. */ + if (e->pdr.pcreg == 0 && STREQ (sh_name, "setjmp")) + { + complain (&bad_setjmp_pdr_complaint, 0); + e->pdr.pcreg = RA_REGNUM; + e->pdr.regmask = 0x80000000; + e->pdr.regoffset = -4; + } + } + + /* It would be reasonable that functions that have been compiled + without debugging info have a btNil type for their return value, + and functions that are void and are compiled with debugging info + have btVoid. + gcc and DEC f77 put out btNil types for both cases, so btNil is mapped + to TYPE_CODE_VOID in parse_type to get the `compiled with debugging info' + case right. + The glevel field in cur_fdr could be used to determine the presence + of debugging info, but GCC doesn't always pass the -g switch settings + to the assembler and GAS doesn't set the glevel field from the -g switch + settings. + To work around these problems, the return value type of a TYPE_CODE_VOID + function is adjusted accordingly if no debugging info was found in the + compilation unit. */ + + if (processing_gcc_compilation == 0 + && found_ecoff_debugging_info == 0 + && TYPE_CODE (TYPE_TARGET_TYPE (SYMBOL_TYPE (s))) == TYPE_CODE_VOID) + SYMBOL_TYPE (s) = nodebug_func_symbol_type; +} + +/* Relocate the extra function info pointed to by the symbol table. */ + +void +ecoff_relocate_efi (sym, delta) + struct symbol *sym; + CORE_ADDR delta; +{ + struct mips_extra_func_info *e; + + e = (struct mips_extra_func_info *) SYMBOL_VALUE (sym); + + e->pdr.adr += delta; +} + +/* Parse the external symbol ES. Just call parse_symbol() after + making sure we know where the aux are for it. + BIGEND says whether aux entries are big-endian or little-endian. + + This routine clobbers top_stack->cur_block and ->cur_st. */ + +static void parse_external PARAMS ((EXTR *, int, struct section_offsets *)); + +static void +parse_external (es, bigend, section_offsets) + EXTR *es; + int bigend; + struct section_offsets *section_offsets; +{ + union aux_ext *ax; + + if (es->ifd != ifdNil) + { + cur_fd = es->ifd; + cur_fdr = debug_info->fdr + cur_fd; + ax = debug_info->external_aux + cur_fdr->iauxBase; + } + else + { + cur_fdr = debug_info->fdr; + ax = 0; + } + + /* Reading .o files */ + if (es->asym.sc == scUndefined || es->asym.sc == scNil) + { + char *what; + switch (es->asym.st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + return; + case stStaticProc: + case stProc: + what = "procedure"; + n_undef_procs++; + break; + case stGlobal: + what = "variable"; + n_undef_vars++; + break; + case stLabel: + what = "label"; + n_undef_labels++; + break; + default: + what = "symbol"; + break; + } + n_undef_symbols++; + /* FIXME: Turn this into a complaint? */ + if (info_verbose) + printf_filtered ("Warning: %s `%s' is undefined (in %s)\n", + what, debug_info->ssext + es->asym.iss, + fdr_name (cur_fdr)); + return; + } + + switch (es->asym.st) + { + case stProc: + case stStaticProc: + /* There is no need to parse the external procedure symbols. + If they are from objects compiled without -g, their index will + be indexNil, and the symbol definition from the minimal symbol + is preferrable (yielding a function returning int instead of int). + If the index points to a local procedure symbol, the local + symbol already provides the correct type. + Note that the index of the external procedure symbol points + to the local procedure symbol in the local symbol table, and + _not_ to the auxiliary symbol info. */ + break; + case stGlobal: + case stLabel: + /* Global common symbols are resolved by the runtime loader, + ignore them. */ + if (es->asym.sc == scCommon || es->asym.sc == scSCommon) + break; + + /* Note that the case of a symbol with indexNil must be handled + anyways by parse_symbol(). */ + parse_symbol (&es->asym, ax, (char *) NULL, bigend, section_offsets); + break; + default: + break; + } +} + +/* Parse the line number info for file descriptor FH into + GDB's linetable LT. MIPS' encoding requires a little bit + of magic to get things out. Note also that MIPS' line + numbers can go back and forth, apparently we can live + with that and do not need to reorder our linetables */ + +static void parse_lines PARAMS ((FDR *, PDR *, struct linetable *, int, + struct partial_symtab *, CORE_ADDR)); + +static void +parse_lines (fh, pr, lt, maxlines, pst, lowest_pdr_addr) + FDR *fh; + PDR *pr; + struct linetable *lt; + int maxlines; + struct partial_symtab *pst; + CORE_ADDR lowest_pdr_addr; +{ + unsigned char *base; + int j, k; + int delta, count, lineno = 0; + + if (fh->cbLine == 0) + return; + + /* Scan by procedure descriptors */ + k = 0; + for (j = 0; j < fh->cpd; j++, pr++) + { + CORE_ADDR l; + CORE_ADDR adr; + unsigned char *halt; + + /* No code for this one */ + if (pr->iline == ilineNil || + pr->lnLow == -1 || pr->lnHigh == -1) + continue; + + /* Determine start and end address of compressed line bytes for + this procedure. */ + base = debug_info->line + fh->cbLineOffset; + if (j != (fh->cpd - 1)) + halt = base + pr[1].cbLineOffset; + else + halt = base + fh->cbLine; + base += pr->cbLineOffset; + + adr = pst->textlow + pr->adr - lowest_pdr_addr; + + l = adr >> 2; /* in words */ + for (lineno = pr->lnLow; base < halt; ) + { + count = *base & 0x0f; + delta = *base++ >> 4; + if (delta >= 8) + delta -= 16; + if (delta == -8) + { + delta = (base[0] << 8) | base[1]; + if (delta >= 0x8000) + delta -= 0x10000; + base += 2; + } + lineno += delta; /* first delta is 0 */ + + /* Complain if the line table overflows. Could happen + with corrupt binaries. */ + if (lt->nitems >= maxlines) + { + complain (&bad_linetable_guess_complaint, fdr_name (fh)); + break; + } + k = add_line (lt, lineno, l, k); + l += count + 1; + } + } +} + +/* Master parsing procedure for first-pass reading of file symbols + into a partial_symtab. */ + +static void +parse_partial_symbols (objfile, section_offsets) + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + const bfd_size_type external_rfd_size = debug_swap->external_rfd_size; + const bfd_size_type external_ext_size = debug_swap->external_ext_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = debug_swap->swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = debug_swap->swap_sym_in; + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = debug_swap->swap_rfd_in; + int f_idx, s_idx; + HDRR *hdr = &debug_info->symbolic_header; + /* Running pointers */ + FDR *fh; + char *ext_out; + char *ext_out_end; + EXTR *ext_block; + register EXTR *ext_in; + EXTR *ext_in_end; + SYMR sh; + struct partial_symtab *pst; + + int past_first_source_file = 0; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + EXTR *extern_tab; + struct pst_map *fdr_to_pst; + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + struct cleanup *old_chain; + char *name; + enum language prev_language; + asection *text_sect; + int relocatable = 0; + + /* Irix 5.2 shared libraries have a fh->adr field of zero, but + the shared libraries are prelinked at a high memory address. + We have to adjust the start address of the object file for this case, + by setting it to the start address of the first procedure in the file. + But we should do no adjustments if we are debugging a .o file, where + the text section (and fh->adr) really starts at zero. */ + text_sect = bfd_get_section_by_name (cur_bfd, ".text"); + if (text_sect != NULL + && (bfd_get_section_flags (cur_bfd, text_sect) & SEC_RELOC)) + relocatable = 1; + + extern_tab = (EXTR *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (EXTR) * hdr->iextMax); + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + next_symbol_text_func = mdebug_next_symbol_text; + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + last_source_file = NULL; + + /* + * Big plan: + * + * Only parse the Local and External symbols, and the Relative FDR. + * Fixup enough of the loader symtab to be able to use it. + * Allocate space only for the file's portions we need to + * look at. (XXX) + */ + + max_gdbinfo = 0; + max_glevel = MIN_GLEVEL; + + /* Allocate the map FDR -> PST. + Minor hack: -O3 images might claim some global data belongs + to FDR -1. We`ll go along with that */ + fdr_to_pst = (struct pst_map *) xzalloc ((hdr->ifdMax + 1) * sizeof *fdr_to_pst); + old_chain = make_cleanup (free, fdr_to_pst); + fdr_to_pst++; + { + struct partial_symtab *pst = new_psymtab ("", objfile, section_offsets); + fdr_to_pst[-1].pst = pst; + FDR_IDX (pst) = -1; + } + + /* Allocate the global pending list. */ + pending_list = + ((struct mdebug_pending **) + obstack_alloc (&objfile->psymbol_obstack, + hdr->ifdMax * sizeof (struct mdebug_pending *))); + memset ((PTR) pending_list, 0, + hdr->ifdMax * sizeof (struct mdebug_pending *)); + + /* Pass 0 over external syms: swap them in. */ + ext_block = (EXTR *) xmalloc (hdr->iextMax * sizeof (EXTR)); + make_cleanup (free, ext_block); + + ext_out = (char *) debug_info->external_ext; + ext_out_end = ext_out + hdr->iextMax * external_ext_size; + ext_in = ext_block; + for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++) + (*swap_ext_in) (cur_bfd, ext_out, ext_in); + + /* Pass 1 over external syms: Presize and partition the list */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + { + /* See calls to complain below. */ + if (ext_in->ifd >= -1 + && ext_in->ifd < hdr->ifdMax + && ext_in->asym.iss >= 0 + && ext_in->asym.iss < hdr->issExtMax) + fdr_to_pst[ext_in->ifd].n_globals++; + } + + /* Pass 1.5 over files: partition out global symbol space */ + s_idx = 0; + for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) + { + fdr_to_pst[f_idx].globals_offset = s_idx; + s_idx += fdr_to_pst[f_idx].n_globals; + fdr_to_pst[f_idx].n_globals = 0; + } + + /* Pass 2 over external syms: fill in external symbols */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + { + enum minimal_symbol_type ms_type = mst_text; + CORE_ADDR svalue = ext_in->asym.value; + + /* The Irix 5 native tools seem to sometimes generate bogus + external symbols. */ + if (ext_in->ifd < -1 || ext_in->ifd >= hdr->ifdMax) + { + complain (&bad_ext_ifd_complaint, ext_in->ifd, hdr->ifdMax); + continue; + } + if (ext_in->asym.iss < 0 || ext_in->asym.iss >= hdr->issExtMax) + { + complain (&bad_ext_iss_complaint, ext_in->asym.iss, + hdr->issExtMax); + continue; + } + + extern_tab[fdr_to_pst[ext_in->ifd].globals_offset + + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in; + + if (ext_in->asym.sc == scUndefined || ext_in->asym.sc == scNil) + continue; + + name = debug_info->ssext + ext_in->asym.iss; + switch (ext_in->asym.st) + { + case stProc: + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case stStaticProc: + ms_type = mst_file_text; + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case stGlobal: + if (ext_in->asym.sc == scCommon || ext_in->asym.sc == scSCommon) + { + /* The value of a common symbol is its size, not its address. + Ignore it. */ + continue; + } + else if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData + || ext_in->asym.sc == scPData + || ext_in->asym.sc == scXData) + { + ms_type = mst_data; + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + } + else + { + ms_type = mst_bss; + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + } + break; + case stLabel: + if (ext_in->asym.sc == scAbs) + ms_type = mst_abs; + else if (ext_in->asym.sc == scText + || ext_in->asym.sc == scInit + || ext_in->asym.sc == scFini) + { + ms_type = mst_file_text; + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + } + else if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData + || ext_in->asym.sc == scPData + || ext_in->asym.sc == scXData) + { + ms_type = mst_file_data; + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + } + else + { + ms_type = mst_file_bss; + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + } + break; + case stLocal: + /* The alpha has the section start addresses in stLocal symbols + whose name starts with a `.'. Skip those but complain for all + other stLocal symbols. */ + if (name[0] == '.') + continue; + /* Fall through. */ + default: + ms_type = mst_unknown; + complain (&unknown_ext_complaint, name); + } + prim_record_minimal_symbol (name, svalue, ms_type, objfile); + } + + /* Pass 3 over files, over local syms: fill in static symbols */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + struct partial_symtab *save_pst; + EXTR *ext_ptr; + CORE_ADDR textlow; + + cur_fdr = fh = debug_info->fdr + f_idx; + + if (fh->csym == 0) + { + fdr_to_pst[f_idx].pst = NULL; + continue; + } + + /* Determine the start address for this object file from the + file header and relocate it, except for Irix 5.2 zero fh->adr. */ + if (fh->cpd) + { + textlow = fh->adr; + if (relocatable || textlow != 0) + textlow += ANOFFSET (section_offsets, SECT_OFF_TEXT); + } + else + textlow = 0; + pst = start_psymtab_common (objfile, section_offsets, + fdr_name (fh), + textlow, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + pst->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) pst->read_symtab_private, 0, sizeof (struct symloc)); + + save_pst = pst; + FDR_IDX (pst) = f_idx; + CUR_BFD (pst) = cur_bfd; + DEBUG_SWAP (pst) = debug_swap; + DEBUG_INFO (pst) = debug_info; + PENDING_LIST (pst) = pending_list; + + /* The way to turn this into a symtab is to call... */ + pst->read_symtab = mdebug_psymtab_to_symtab; + + /* Set up language for the pst. + The language from the FDR is used if it is unambigious (e.g. cfront + with native cc and g++ will set the language to C). + Otherwise we have to deduce the language from the filename. + Native ecoff has every header file in a separate FDR, so + deduce_language_from_filename will return language_unknown for + a header file, which is not what we want. + But the FDRs for the header files are after the FDR for the source + file, so we can assign the language of the source file to the + following header files. Then we save the language in the private + pst data so that we can reuse it when building symtabs. */ + prev_language = psymtab_language; + + switch (fh->lang) + { + case langCplusplusV2: + psymtab_language = language_cplus; + break; + default: + psymtab_language = deduce_language_from_filename (fdr_name (fh)); + break; + } + if (psymtab_language == language_unknown) + psymtab_language = prev_language; + PST_PRIVATE (pst)->pst_language = psymtab_language; + + pst->texthigh = pst->textlow; + + /* For stabs-in-ecoff files, the second symbol must be @stab. + This symbol is emitted by mips-tfile to signal that the + current object file uses encapsulated stabs instead of mips + ecoff for local symbols. (It is the second symbol because + the first symbol is the stFile used to signal the start of a + file). */ + processing_gcc_compilation = 0; + if (fh->csym >= 2) + { + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (debug_info->ss + fh->issBase + sh.iss, stabs_symbol)) + processing_gcc_compilation = 2; + } + + if (processing_gcc_compilation != 0) + { + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + int type_code; + char *namestring; + + (*swap_sym_in) (cur_bfd, + (((char *) debug_info->external_sym) + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + type_code = ECOFF_UNMARK_STAB (sh.index); + if (!ECOFF_IS_STAB (&sh)) + { + if (sh.st == stProc || sh.st == stStaticProc) + { + long procaddr; + long isym; + + sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + if (sh.st == stStaticProc) + { + namestring = debug_info->ss + fh->issBase + sh.iss; + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_text, + NULL, + SECT_OFF_TEXT, + objfile); + } + procaddr = sh.value; + + isym = AUX_GET_ISYM (fh->fBigendian, + (debug_info->external_aux + + fh->iauxBase + + sh.index)); + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + isym - 1) + * external_sym_size)), + &sh); + if (sh.st == stEnd) + { + long high = procaddr + sh.value; + + /* Kludge for Irix 5.2 zero fh->adr. */ + if (!relocatable + && (pst->textlow == 0 || procaddr < pst->textlow)) + pst->textlow = procaddr; + if (high > pst->texthigh) + pst->texthigh = high; + } + } + else if (sh.st == stStatic) + { + switch (sh.sc) + { + case scUndefined: + case scNil: + case scAbs: + break; + + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + namestring = debug_info->ss + fh->issBase + sh.iss; + sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA); + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_data, + NULL, + SECT_OFF_DATA, + objfile); + break; + + default: + namestring = debug_info->ss + fh->issBase + sh.iss; + sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS); + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_bss, + NULL, + SECT_OFF_BSS, + objfile); + break; + } + } + continue; + } +#define SET_NAMESTRING() \ + namestring = debug_info->ss + fh->issBase + sh.iss +#define CUR_SYMBOL_TYPE type_code +#define CUR_SYMBOL_VALUE sh.value +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ + pst = save_pst +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) (void)0 +#define HANDLE_RBRAC(val) \ + if ((val) > save_pst->texthigh) save_pst->texthigh = (val); +#include "partial-stab.h" + } + } + else + { + for (cur_sdx = 0; cur_sdx < fh->csym;) + { + char *name; + enum address_class class; + + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx) + * external_sym_size)), + &sh); + + if (ECOFF_IS_STAB (&sh)) + { + cur_sdx++; + continue; + } + + /* Non absolute static symbols go into the minimal table. */ + if (sh.sc == scUndefined || sh.sc == scNil + || (sh.index == indexNil + && (sh.st != stStatic || sh.sc == scAbs))) + { + /* FIXME, premature? */ + cur_sdx++; + continue; + } + + name = debug_info->ss + fh->issBase + sh.iss; + + switch (sh.sc) + { + case scText: + /* The value of a stEnd symbol is the displacement from the + corresponding start symbol value, do not relocate it. */ + if (sh.st != stEnd) + sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (sh.st) + { + long high; + long procaddr; + int new_sdx; + + case stStaticProc: + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_text, NULL, + SECT_OFF_TEXT, objfile); + + /* FALLTHROUGH */ + + case stProc: + /* Usually there is a local and a global stProc symbol + for a function. This means that the function name + has already been entered into the mimimal symbol table + while processing the global symbols in pass 2 above. + One notable exception is the PROGRAM name from + f77 compiled executables, it is only put out as + local stProc symbol, and a global MAIN__ stProc symbol + points to it. It doesn't matter though, as gdb is + still able to find the PROGRAM name via the partial + symbol table, and the MAIN__ symbol via the minimal + symbol table. */ + if (sh.st == stProc) + add_psymbol_to_list (name, strlen (name), + VAR_NAMESPACE, LOC_BLOCK, + &objfile->global_psymbols, + sh.value, 0, psymtab_language, objfile); + else + add_psymbol_to_list (name, strlen (name), + VAR_NAMESPACE, LOC_BLOCK, + &objfile->static_psymbols, + sh.value, 0, psymtab_language, objfile); + + /* Skip over procedure to next one. */ + if (sh.index >= hdr->iauxMax) + { + /* Should not happen, but does when cross-compiling + with the MIPS compiler. FIXME -- pull later. */ + complain (&index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip at all */ + } + else + new_sdx = AUX_GET_ISYM (fh->fBigendian, + (debug_info->external_aux + + fh->iauxBase + + sh.index)); + procaddr = sh.value; + + if (new_sdx <= cur_sdx) + { + /* This should not happen either... FIXME. */ + complain (&aux_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + + cur_sdx = new_sdx; + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx - 1) + * external_sym_size)), + &sh); + if (sh.st != stEnd) + continue; + + /* Kludge for Irix 5.2 zero fh->adr. */ + if (!relocatable + && (pst->textlow == 0 || procaddr < pst->textlow)) + pst->textlow = procaddr; + + high = procaddr + sh.value; + if (high > pst->texthigh) + pst->texthigh = high; + continue; + + case stStatic: /* Variable */ + if (sh.sc == scData + || sh.sc == scSData + || sh.sc == scRData + || sh.sc == scPData + || sh.sc == scXData) + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_data, NULL, + SECT_OFF_DATA, + objfile); + else + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_bss, NULL, + SECT_OFF_BSS, + objfile); + class = LOC_STATIC; + break; + + case stIndirect:/* Irix5 forward declaration */ + /* Skip forward declarations from Irix5 cc */ + goto skip; + + case stTypedef:/* Typedef */ + /* Skip typedefs for forward declarations and opaque + structs from alpha and mips cc. */ + if (sh.iss == 0 || has_opaque_xref (fh, &sh)) + goto skip; + class = LOC_TYPEDEF; + break; + + case stConstant: /* Constant decl */ + class = LOC_CONST; + break; + + case stUnion: + case stStruct: + case stEnum: + case stBlock: /* { }, str, un, enum*/ + /* Do not create a partial symbol for cc unnamed aggregates + and gcc empty aggregates. */ + if ((sh.sc == scInfo + || sh.sc == scCommon || sh.sc == scSCommon) + && sh.iss != 0 + && sh.index != cur_sdx + 2) + { + add_psymbol_to_list (name, strlen (name), + STRUCT_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + sh.value, 0, + psymtab_language, objfile); + } + handle_psymbol_enumerators (objfile, fh, sh.st, sh.value); + + /* Skip over the block */ + new_sdx = sh.index; + if (new_sdx <= cur_sdx) + { + /* This happens with the Ultrix kernel. */ + complain (&block_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + cur_sdx = new_sdx; + continue; + + case stFile: /* File headers */ + case stLabel: /* Labels */ + case stEnd: /* Ends of files */ + goto skip; + + case stLocal: /* Local variables */ + /* Normally these are skipped because we skip over + all blocks we see. However, these can occur + as visible symbols in a .h file that contains code. */ + goto skip; + + default: + /* Both complaints are valid: one gives symbol name, + the other the offending symbol type. */ + complain (&unknown_sym_complaint, name); + complain (&unknown_st_complaint, sh.st); + cur_sdx++; + continue; + } + /* Use this gdb symbol */ + add_psymbol_to_list (name, strlen (name), + VAR_NAMESPACE, class, + &objfile->static_psymbols, sh.value, + 0, psymtab_language, objfile); + skip: + cur_sdx++; /* Go to next file symbol */ + } + + /* Now do enter the external symbols. */ + ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset]; + cur_sdx = fdr_to_pst[f_idx].n_globals; + PST_PRIVATE (save_pst)->extern_count = cur_sdx; + PST_PRIVATE (save_pst)->extern_tab = ext_ptr; + for (; --cur_sdx >= 0; ext_ptr++) + { + enum address_class class; + SYMR *psh; + char *name; + CORE_ADDR svalue; + + if (ext_ptr->ifd != f_idx) + abort (); + psh = &ext_ptr->asym; + + /* Do not add undefined symbols to the partial symbol table. */ + if (psh->sc == scUndefined || psh->sc == scNil) + continue; + + svalue = psh->value; + switch (psh->sc) + { + case scText: + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (psh->st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + continue; + case stProc: + case stStaticProc: + /* External procedure symbols have been entered + into the minimal symbol table in pass 2 above. + Ignore them, as parse_external will ignore them too. */ + continue; + case stLabel: + class = LOC_LABEL; + break; + default: + complain (&unknown_ext_complaint, + debug_info->ssext + psh->iss); + /* Fall through, pretend it's global. */ + case stGlobal: + /* Global common symbols are resolved by the runtime loader, + ignore them. */ + if (psh->sc == scCommon || psh->sc == scSCommon) + continue; + + class = LOC_STATIC; + break; + } + name = debug_info->ssext + psh->iss; + add_psymbol_to_list (name, strlen (name), + VAR_NAMESPACE, class, + &objfile->global_psymbols, + 0, svalue, + psymtab_language, objfile); + } + } + + /* Link pst to FDR. end_psymtab returns NULL if the psymtab was + empty and put on the free list. */ + fdr_to_pst[f_idx].pst = end_psymtab (save_pst, + psymtab_include_list, includes_used, + -1, save_pst->texthigh, + dependency_list, dependencies_used); + includes_used = 0; + dependencies_used = 0; + + if (objfile->ei.entry_point >= save_pst->textlow && + objfile->ei.entry_point < save_pst->texthigh) + { + objfile->ei.entry_file_lowpc = save_pst->textlow; + objfile->ei.entry_file_highpc = save_pst->texthigh; + } + + /* The objfile has its functions reordered if this partial symbol + table overlaps any other partial symbol table. + We cannot assume a reordered objfile if a partial symbol table + is contained within another partial symbol table, as partial symbol + tables for include files with executable code are contained + within the partial symbol table for the including source file, + and we do not want to flag the objfile reordered for these cases. + + This strategy works well for Irix-5.2 shared libraries, but we + might have to use a more elaborate (and slower) algorithm for + other cases. */ + save_pst = fdr_to_pst[f_idx].pst; + if (save_pst != NULL + && save_pst->textlow != 0 + && !(objfile->flags & OBJF_REORDERED)) + { + ALL_OBJFILE_PSYMTABS (objfile, pst) + { + if (save_pst != pst + && save_pst->textlow >= pst->textlow + && save_pst->textlow < pst->texthigh + && save_pst->texthigh > pst->texthigh) + { + objfile->flags |= OBJF_REORDERED; + break; + } + } + } + } + + /* Now scan the FDRs for dependencies */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + fh = f_idx + debug_info->fdr; + pst = fdr_to_pst[f_idx].pst; + + if (pst == (struct partial_symtab *)NULL) + continue; + + /* This should catch stabs-in-ecoff. */ + if (fh->crfd <= 1) + continue; + + /* Skip the first file indirect entry as it is a self dependency + for source files or a reverse .h -> .c dependency for header files. */ + pst->number_of_dependencies = 0; + pst->dependencies = + ((struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + ((fh->crfd - 1) + * sizeof (struct partial_symtab *)))); + for (s_idx = 1; s_idx < fh->crfd; s_idx++) + { + RFDT rh; + + (*swap_rfd_in) (cur_bfd, + ((char *) debug_info->external_rfd + + (fh->rfdBase + s_idx) * external_rfd_size), + &rh); + if (rh < 0 || rh >= hdr->ifdMax) + { + complain (&bad_file_number_complaint, rh); + continue; + } + + /* Skip self dependencies of header files. */ + if (rh == f_idx) + continue; + + /* Do not add to dependeny list if psymtab was empty. */ + if (fdr_to_pst[rh].pst == (struct partial_symtab *)NULL) + continue; + pst->dependencies[pst->number_of_dependencies++] = fdr_to_pst[rh].pst; + } + } + + /* Remove the dummy psymtab created for -O3 images above, if it is + still empty, to enable the detection of stripped executables. */ + if (objfile->psymtabs->next == NULL + && objfile->psymtabs->number_of_dependencies == 0 + && objfile->psymtabs->n_global_syms == 0 + && objfile->psymtabs->n_static_syms == 0) + objfile->psymtabs = NULL; + do_cleanups (old_chain); +} + +/* If the current psymbol has an enumerated type, we need to add + all the the enum constants to the partial symbol table. */ + +static void +handle_psymbol_enumerators (objfile, fh, stype, svalue) + struct objfile *objfile; + FDR *fh; + int stype; + CORE_ADDR svalue; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = debug_swap->swap_sym_in; + char *ext_sym = ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx + 1) * external_sym_size)); + SYMR sh; + TIR tir; + + switch (stype) + { + case stEnum: + break; + + case stBlock: + /* It is an enumerated type if the next symbol entry is a stMember + and its auxiliary index is indexNil or its auxiliary entry + is a plain btNil or btVoid. + Alpha cc -migrate enums are recognized by a zero index and + a zero symbol value. */ + (*swap_sym_in) (cur_bfd, ext_sym, &sh); + if (sh.st != stMember) + return; + + if (sh.index == indexNil + || (sh.index == 0 && svalue == 0)) + break; + (*debug_swap->swap_tir_in) (fh->fBigendian, + &(debug_info->external_aux + + fh->iauxBase + sh.index)->a_ti, + &tir); + if ((tir.bt != btNil && tir.bt != btVoid) || tir.tq0 != tqNil) + return; + break; + + default: + return; + } + + for (;;) + { + char *name; + + (*swap_sym_in) (cur_bfd, ext_sym, &sh); + if (sh.st != stMember) + break; + name = debug_info->ss + cur_fdr->issBase + sh.iss; + + /* Note that the value doesn't matter for enum constants + in psymtabs, just in symtabs. */ + add_psymbol_to_list (name, strlen (name), + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, 0, + 0, psymtab_language, objfile); + ext_sym += external_sym_size; + } +} + +static char * +mdebug_next_symbol_text (objfile) + struct objfile *objfile; /* argument objfile is currently unused */ +{ + SYMR sh; + + cur_sdx++; + (*debug_swap->swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + cur_sdx) + * debug_swap->external_sym_size)), + &sh); + return debug_info->ss + cur_fdr->issBase + sh.iss; +} + +/* Ancillary function to psymtab_to_symtab(). Does all the work + for turning the partial symtab PST into a symtab, recurring + first on all dependent psymtabs. The argument FILENAME is + only passed so we can see in debug stack traces what file + is being read. + + This function has a split personality, based on whether the + symbol table contains ordinary ecoff symbols, or stabs-in-ecoff. + The flow of control and even the memory allocation differs. FIXME. */ + +static void +psymtab_to_symtab_1 (pst, filename) + struct partial_symtab *pst; + char *filename; +{ + bfd_size_type external_sym_size; + bfd_size_type external_pdr_size; + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + int i; + struct symtab *st; + FDR *fh; + struct linetable *lines; + CORE_ADDR lowest_pdr_addr = 0; + + if (pst->readin) + return; + pst->readin = 1; + + /* Read in all partial symbtabs on which this one is dependent. + NOTE that we do have circular dependencies, sigh. We solved + that by setting pst->readin before this point. */ + + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin) + { + /* Inform about additional files to be read in. */ + if (info_verbose) + { + 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); + } + /* We only pass the filename for debug purposes */ + psymtab_to_symtab_1 (pst->dependencies[i], + pst->dependencies[i]->filename); + } + + /* Do nothing if this is a dummy psymtab. */ + + if (pst->n_global_syms == 0 && pst->n_static_syms == 0 + && pst->textlow == 0 && pst->texthigh == 0) + return; + + /* Now read the symbols for this symtab */ + + cur_bfd = CUR_BFD (pst); + debug_swap = DEBUG_SWAP (pst); + debug_info = DEBUG_INFO (pst); + pending_list = PENDING_LIST (pst); + external_sym_size = debug_swap->external_sym_size; + external_pdr_size = debug_swap->external_pdr_size; + swap_sym_in = debug_swap->swap_sym_in; + swap_pdr_in = debug_swap->swap_pdr_in; + current_objfile = pst->objfile; + cur_fd = FDR_IDX (pst); + fh = ((cur_fd == -1) + ? (FDR *) NULL + : debug_info->fdr + cur_fd); + cur_fdr = fh; + + /* See comment in parse_partial_symbols about the @stabs sentinel. */ + processing_gcc_compilation = 0; + if (fh != (FDR *) NULL && fh->csym >= 2) + { + SYMR sh; + + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (debug_info->ss + fh->issBase + sh.iss, + stabs_symbol)) + { + /* We indicate that this is a GCC compilation so that certain + features will be enabled in stabsread/dbxread. */ + processing_gcc_compilation = 2; + } + } + + if (processing_gcc_compilation != 0) + { + + /* This symbol table contains stabs-in-ecoff entries. */ + + /* Parse local symbols first */ + + if (fh->csym <= 2) /* FIXME, this blows psymtab->symtab ptr */ + { + current_objfile = NULL; + return; + } + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + SYMR sh; + char *name; + CORE_ADDR valu; + + (*swap_sym_in) (cur_bfd, + (((char *) debug_info->external_sym) + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + name = debug_info->ss + fh->issBase + sh.iss; + valu = sh.value; + if (ECOFF_IS_STAB (&sh)) + { + int type_code = ECOFF_UNMARK_STAB (sh.index); + + /* We should never get non N_STAB symbols here, but they + should be harmless, so keep process_one_symbol from + complaining about them. */ + if (type_code & N_STAB) + { + process_one_symbol (type_code, 0, valu, name, + pst->section_offsets, pst->objfile); + } + if (type_code == N_FUN) + { + /* Make up special symbol to contain + procedure specific info */ + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME); + + memset ((PTR) e, 0, sizeof (struct mips_extra_func_info)); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = mdebug_type_void; + SYMBOL_VALUE (s) = (long) e; + e->pdr.framereg = -1; + add_symbol_to_list (s, &local_symbols); + } + } + else if (sh.st == stLabel) + { + if (sh.index == indexNil) + { + /* This is what the gcc2_compiled and __gnu_compiled_* + show up as. So don't complain. */ + ; + } + else + { + /* Handle encoded stab line number. */ + valu += ANOFFSET (pst->section_offsets, SECT_OFF_TEXT); + record_line (current_subfile, sh.index, valu); + } + } + else if (sh.st == stProc || sh.st == stStaticProc + || sh.st == stStatic || sh.st == stEnd) + /* These are generated by gcc-2.x, do not complain */ + ; + else + complain (&stab_unknown_complaint, name); + } + st = end_symtab (pst->texthigh, pst->objfile, SECT_OFF_TEXT); + end_stabs (); + + /* Sort the symbol table now, we are done adding symbols to it. + We must do this before parse_procedure calls lookup_symbol. */ + sort_symtab_syms (st); + + /* There used to be a call to sort_blocks here, but this should not + be necessary for stabs symtabs. And as sort_blocks modifies the + start address of the GLOBAL_BLOCK to the FIRST_LOCAL_BLOCK, + it did the wrong thing if the first procedure in a file was + generated via asm statements. */ + + /* Fill in procedure info next. */ + if (fh->cpd > 0) + { + PDR *pr_block; + struct cleanup *old_chain; + char *pdr_ptr; + char *pdr_end; + PDR *pdr_in; + PDR *pdr_in_end; + + pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR)); + old_chain = make_cleanup (free, pr_block); + + pdr_ptr = ((char *) debug_info->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + pdr_in = pr_block; + for (; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size, pdr_in++) + { + (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); + + /* Determine lowest PDR address, the PDRs are not always + sorted. */ + if (pdr_in == pr_block) + lowest_pdr_addr = pdr_in->adr; + else if (pdr_in->adr < lowest_pdr_addr) + lowest_pdr_addr = pdr_in->adr; + } + + pdr_in = pr_block; + pdr_in_end = pdr_in + fh->cpd; + for (; pdr_in < pdr_in_end; pdr_in++) + parse_procedure (pdr_in, st, lowest_pdr_addr, pst); + + do_cleanups (old_chain); + } + } + else + { + /* This symbol table contains ordinary ecoff entries. */ + + int f_max; + int maxlines; + EXTR *ext_ptr; + + /* How many symbols will we need */ + /* FIXME, this does not count enum values. */ + f_max = pst->n_global_syms + pst->n_static_syms; + if (fh == 0) + { + maxlines = 0; + st = new_symtab ("unknown", f_max, 0, pst->objfile); + } + else + { + f_max += fh->csym + fh->cpd; + maxlines = 2 * fh->cline; + st = new_symtab (pst->filename, 2 * f_max, maxlines, pst->objfile); + + /* The proper language was already determined when building + the psymtab, use it. */ + st->language = PST_PRIVATE (pst)->pst_language; + } + + psymtab_language = st->language; + + lines = LINETABLE (st); + + /* Get a new lexical context */ + + push_parse_stack (); + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (st), + STATIC_BLOCK); + BLOCK_START (top_stack->cur_block) = pst->textlow; + BLOCK_END (top_stack->cur_block) = 0; + top_stack->blocktype = stFile; + top_stack->maxsyms = 2 * f_max; + top_stack->cur_type = 0; + top_stack->procadr = 0; + top_stack->numargs = 0; + found_ecoff_debugging_info = 0; + + if (fh) + { + char *sym_ptr; + char *sym_end; + + /* Parse local symbols first */ + sym_ptr = ((char *) debug_info->external_sym + + fh->isymBase * external_sym_size); + sym_end = sym_ptr + fh->csym * external_sym_size; + while (sym_ptr < sym_end) + { + SYMR sh; + int c; + + (*swap_sym_in) (cur_bfd, sym_ptr, &sh); + c = parse_symbol (&sh, + debug_info->external_aux + fh->iauxBase, + sym_ptr, fh->fBigendian, pst->section_offsets); + sym_ptr += c * external_sym_size; + } + + /* Linenumbers. At the end, check if we can save memory. + parse_lines has to look ahead an arbitrary number of PDR + structures, so we swap them all first. */ + if (fh->cpd > 0) + { + PDR *pr_block; + struct cleanup *old_chain; + char *pdr_ptr; + char *pdr_end; + PDR *pdr_in; + PDR *pdr_in_end; + + pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR)); + + old_chain = make_cleanup (free, pr_block); + + pdr_ptr = ((char *) debug_info->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + pdr_in = pr_block; + for (; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size, pdr_in++) + { + (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); + + /* Determine lowest PDR address, the PDRs are not always + sorted. */ + if (pdr_in == pr_block) + lowest_pdr_addr = pdr_in->adr; + else if (pdr_in->adr < lowest_pdr_addr) + lowest_pdr_addr = pdr_in->adr; + } + + parse_lines (fh, pr_block, lines, maxlines, pst, lowest_pdr_addr); + if (lines->nitems < fh->cline) + lines = shrink_linetable (lines); + + /* Fill in procedure info next. */ + pdr_in = pr_block; + pdr_in_end = pdr_in + fh->cpd; + for (; pdr_in < pdr_in_end; pdr_in++) + parse_procedure (pdr_in, 0, lowest_pdr_addr, pst); + + do_cleanups (old_chain); + } + } + + LINETABLE (st) = lines; + + /* .. and our share of externals. + XXX use the global list to speed up things here. how? + FIXME, Maybe quit once we have found the right number of ext's? */ + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + top_stack->blocktype = stFile; + top_stack->maxsyms + = (debug_info->symbolic_header.isymMax + + debug_info->symbolic_header.ipdMax + + debug_info->symbolic_header.iextMax); + + ext_ptr = PST_PRIVATE (pst)->extern_tab; + for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++) + parse_external (ext_ptr, fh->fBigendian, pst->section_offsets); + + /* If there are undefined symbols, tell the user. + The alpha has an undefined symbol for every symbol that is + from a shared library, so tell the user only if verbose is on. */ + if (info_verbose && n_undef_symbols) + { + printf_filtered ("File %s contains %d unresolved references:", + st->filename, n_undef_symbols); + printf_filtered ("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n", + n_undef_vars, n_undef_procs, n_undef_labels); + n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0; + + } + pop_parse_stack (); + + st->primary = 1; + + /* Sort the symbol table now, we are done adding symbols to it.*/ + sort_symtab_syms (st); + + sort_blocks (st); + } + + /* Now link the psymtab and the symtab. */ + pst->symtab = st; + + current_objfile = NULL; +} + +/* Ancillary parsing procedures. */ + +/* Return 1 if the symbol pointed to by SH has a cross reference + to an opaque aggregate type, else 0. */ + +static int +has_opaque_xref (fh, sh) + FDR *fh; + SYMR *sh; +{ + TIR tir; + union aux_ext *ax; + RNDXR rn[1]; + unsigned int rf; + + if (sh->index == indexNil) + return 0; + + ax = debug_info->external_aux + fh->iauxBase + sh->index; + (*debug_swap->swap_tir_in) (fh->fBigendian, &ax->a_ti, &tir); + if (tir.bt != btStruct && tir.bt != btUnion && tir.bt != btEnum) + return 0; + + ax++; + (*debug_swap->swap_rndx_in) (fh->fBigendian, &ax->a_rndx, rn); + if (rn->rfd == 0xfff) + rf = AUX_GET_ISYM (fh->fBigendian, ax + 1); + else + rf = rn->rfd; + if (rf != -1) + return 0; + return 1; +} + +/* Lookup the type at relative index RN. Return it in TPP + if found and in any event come up with its name PNAME. + BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian). + Return value says how many aux symbols we ate. */ + +static int +cross_ref (fd, ax, tpp, type_code, pname, bigend, sym_name) + int fd; + union aux_ext *ax; + struct type **tpp; + enum type_code type_code; /* Use to alloc new type if none is found. */ + char **pname; + int bigend; + char *sym_name; +{ + RNDXR rn[1]; + unsigned int rf; + int result = 1; + FDR *fh; + char *esh; + SYMR sh; + int xref_fd; + struct mdebug_pending *pend; + + *tpp = (struct type *)NULL; + + (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn); + + /* Escape index means 'the next one' */ + if (rn->rfd == 0xfff) + { + result++; + rf = AUX_GET_ISYM (bigend, ax + 1); + } + else + { + rf = rn->rfd; + } + + /* mips cc uses a rf of -1 for opaque struct definitions. + Set TYPE_FLAG_STUB for these types so that check_typedef will + resolve them if the struct gets defined in another compilation unit. */ + if (rf == -1) + { + *pname = ""; + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + TYPE_FLAGS (*tpp) |= TYPE_FLAG_STUB; + return result; + } + + /* mips cc uses an escaped rn->index of 0 for struct return types + of procedures that were compiled without -g. These will always remain + undefined. */ + if (rn->rfd == 0xfff && rn->index == 0) + { + *pname = ""; + return result; + } + + /* Find the relative file descriptor and the symbol in it. */ + fh = get_rfd (fd, rf); + xref_fd = fh - debug_info->fdr; + + if (rn->index >= fh->csym) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + /* If we have processed this symbol then we left a forwarding + pointer to the type in the pending list. If not, we`ll put + it in a list of pending types, to be processed later when + the file will be. In any event, we collect the name for the + type here. */ + + esh = ((char *) debug_info->external_sym + + ((fh->isymBase + rn->index) + * debug_swap->external_sym_size)); + (*debug_swap->swap_sym_in) (cur_bfd, esh, &sh); + + /* Make sure that this type of cross reference can be handled. */ + if ((sh.sc != scInfo + || (sh.st != stBlock && sh.st != stTypedef && sh.st != stIndirect + && sh.st != stStruct && sh.st != stUnion + && sh.st != stEnum)) + && (sh.st != stBlock || (sh.sc != scCommon && sh.sc != scSCommon))) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + *pname = debug_info->ss + fh->issBase + sh.iss; + + pend = is_pending_symbol (fh, esh); + if (pend) + *tpp = pend->t; + else + { + /* We have not yet seen this type. */ + + if ((sh.iss == 0 && sh.st == stTypedef) || sh.st == stIndirect) + { + TIR tir; + + /* alpha cc puts out a stTypedef with a sh.iss of zero for + two cases: + a) forward declarations of structs/unions/enums which are not + defined in this compilation unit. + For these the type will be void. This is a bad design decision + as cross referencing across compilation units is impossible + due to the missing name. + b) forward declarations of structs/unions/enums/typedefs which + are defined later in this file or in another file in the same + compilation unit. Irix5 cc uses a stIndirect symbol for this. + Simply cross reference those again to get the true type. + The forward references are not entered in the pending list and + in the symbol table. */ + + (*debug_swap->swap_tir_in) (bigend, + &(debug_info->external_aux + + fh->iauxBase + sh.index)->a_ti, + &tir); + if (tir.tq0 != tqNil) + complain (&illegal_forward_tq0_complaint, sym_name); + switch (tir.bt) + { + case btVoid: + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + *pname = ""; + break; + + case btStruct: + case btUnion: + case btEnum: + cross_ref (xref_fd, + (debug_info->external_aux + + fh->iauxBase + sh.index + 1), + tpp, type_code, pname, + fh->fBigendian, sym_name); + break; + + case btTypedef: + /* Follow a forward typedef. This might recursively + call cross_ref till we get a non typedef'ed type. + FIXME: This is not correct behaviour, but gdb currently + cannot handle typedefs without type copying. Type + copying is impossible as we might have mutual forward + references between two files and the copied type would not + get filled in when we later parse its definition. */ + *tpp = parse_type (xref_fd, + debug_info->external_aux + fh->iauxBase, + sh.index, + (int *)NULL, + fh->fBigendian, + debug_info->ss + fh->issBase + sh.iss); + add_pending (fh, esh, *tpp); + break; + + default: + complain (&illegal_forward_bt_complaint, tir.bt, sym_name); + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + break; + } + return result; + } + else if (sh.st == stTypedef) + { + /* Parse the type for a normal typedef. This might recursively call + cross_ref till we get a non typedef'ed type. + FIXME: This is not correct behaviour, but gdb currently + cannot handle typedefs without type copying. But type copying is + impossible as we might have mutual forward references between + two files and the copied type would not get filled in when + we later parse its definition. */ + *tpp = parse_type (xref_fd, + debug_info->external_aux + fh->iauxBase, + sh.index, + (int *)NULL, + fh->fBigendian, + debug_info->ss + fh->issBase + sh.iss); + } + else + { + /* Cross reference to a struct/union/enum which is defined + in another file in the same compilation unit but that file + has not been parsed yet. + Initialize the type only, it will be filled in when + it's definition is parsed. */ + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + } + add_pending (fh, esh, *tpp); + } + + /* We used one auxent normally, two if we got a "next one" rf. */ + return result; +} + + +/* Quick&dirty lookup procedure, to avoid the MI ones that require + keeping the symtab sorted */ + +static struct symbol * +mylookup_symbol (name, block, namespace, class) + char *name; + register struct block *block; + namespace_enum namespace; + enum address_class class; +{ + register int bot, top, inc; + register struct symbol *sym; + + bot = 0; + top = BLOCK_NSYMS (block); + inc = name[0]; + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + if (SYMBOL_NAME (sym)[0] == inc + && SYMBOL_NAMESPACE (sym) == namespace + && SYMBOL_CLASS (sym) == class + && strcmp (SYMBOL_NAME (sym), name) == 0) + return sym; + bot++; + } + block = BLOCK_SUPERBLOCK (block); + if (block) + return mylookup_symbol (name, block, namespace, class); + return 0; +} + + +/* Add a new symbol S to a block B. + Infrequently, we will need to reallocate the block to make it bigger. + We only detect this case when adding to top_stack->cur_block, since + that's the only time we know how big the block is. FIXME. */ + +static void +add_symbol (s, b) + struct symbol *s; + struct block *b; +{ + int nsyms = BLOCK_NSYMS (b)++; + struct block *origb; + struct parse_stack *stackp; + + if (b == top_stack->cur_block && + nsyms >= top_stack->maxsyms) + { + complain (&block_overflow_complaint, SYMBOL_NAME (s)); + /* In this case shrink_block is actually grow_block, since + BLOCK_NSYMS(b) is larger than its current size. */ + origb = b; + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* Now run through the stack replacing pointers to the + original block. shrink_block has already done this + for the blockvector and BLOCK_FUNCTION. */ + for (stackp = top_stack; stackp; stackp = stackp->next) + { + if (stackp->cur_block == origb) + { + stackp->cur_block = b; + stackp->maxsyms = BLOCK_NSYMS (b); + } + } + } + BLOCK_SYM (b, nsyms) = s; +} + +/* Add a new block B to a symtab S */ + +static void +add_block (b, s) + struct block *b; + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + bv = (struct blockvector *) xrealloc ((PTR) bv, + (sizeof (struct blockvector) + + BLOCKVECTOR_NBLOCKS (bv) + * sizeof (bv->block))); + if (bv != BLOCKVECTOR (s)) + BLOCKVECTOR (s) = bv; + + BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b; +} + +/* Add a new linenumber entry (LINENO,ADR) to a linevector LT. + MIPS' linenumber encoding might need more than one byte + to describe it, LAST is used to detect these continuation lines. + + Combining lines with the same line number seems like a bad idea. + E.g: There could be a line number entry with the same line number after the + prologue and GDB should not ignore it (this is a better way to find + a prologue than mips_skip_prologue). + But due to the compressed line table format there are line number entries + for the same line which are needed to bridge the gap to the next + line number entry. These entries have a bogus address info with them + and we are unable to tell them from intended duplicate line number + entries. + This is another reason why -ggdb debugging format is preferable. */ + +static int +add_line (lt, lineno, adr, last) + struct linetable *lt; + int lineno; + CORE_ADDR adr; + int last; +{ + /* DEC c89 sometimes produces zero linenos which confuse gdb. + Change them to something sensible. */ + if (lineno == 0) + lineno = 1; + if (last == 0) + last = -2; /* make sure we record first line */ + + if (last == lineno) /* skip continuation lines */ + return lineno; + + lt->item[lt->nitems].line = lineno; + lt->item[lt->nitems++].pc = adr << 2; + return lineno; +} + +/* Sorting and reordering procedures */ + +/* Blocks with a smaller low bound should come first */ + +static int +compare_blocks (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + register int addr_diff; + struct block **b1 = (struct block **) arg1; + struct block **b2 = (struct block **) arg2; + + addr_diff = (BLOCK_START ((*b1))) - (BLOCK_START ((*b2))); + if (addr_diff == 0) + return (BLOCK_END ((*b2))) - (BLOCK_END ((*b1))); + return addr_diff; +} + +/* Sort the blocks of a symtab S. + Reorder the blocks in the blockvector by code-address, + as required by some MI search routines */ + +static void +sort_blocks (s) + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + if (BLOCKVECTOR_NBLOCKS (bv) <= 2) + { + /* Cosmetic */ + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0; + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0; + return; + } + /* + * This is very unfortunate: normally all functions are compiled in + * the order they are found, but if the file is compiled -O3 things + * are very different. It would be nice to find a reliable test + * to detect -O3 images in advance. + */ + if (BLOCKVECTOR_NBLOCKS (bv) > 3) + qsort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK), + BLOCKVECTOR_NBLOCKS (bv) - FIRST_LOCAL_BLOCK, + sizeof (struct block *), + compare_blocks); + + { + register CORE_ADDR high = 0; + register int i, j = BLOCKVECTOR_NBLOCKS (bv); + + for (i = FIRST_LOCAL_BLOCK; i < j; i++) + if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i))) + high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high; + } + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK)); + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); +} + + +/* Constructor/restructor/destructor procedures */ + +/* Allocate a new symtab for NAME. Needs an estimate of how many symbols + MAXSYMS and linenumbers MAXLINES we'll put in it */ + +static struct symtab * +new_symtab (name, maxsyms, maxlines, objfile) + char *name; + int maxsyms; + int maxlines; + struct objfile *objfile; +{ + struct symtab *s = allocate_symtab (name, objfile); + + LINETABLE (s) = new_linetable (maxlines); + + /* All symtabs must have at least two blocks */ + BLOCKVECTOR (s) = new_bvect (2); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK) = new_block (maxsyms); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) = new_block (maxsyms); + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) = + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + + s->free_code = free_linetable; + + return (s); +} + +/* Allocate a new partial_symtab NAME */ + +static struct partial_symtab * +new_psymtab (name, objfile, section_offsets) + char *name; + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (name, objfile); + psymtab->section_offsets = section_offsets; + + /* Keep a backpointer to the file's symbols */ + + psymtab->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) psymtab->read_symtab_private, 0, sizeof (struct symloc)); + CUR_BFD (psymtab) = cur_bfd; + DEBUG_SWAP (psymtab) = debug_swap; + DEBUG_INFO (psymtab) = debug_info; + PENDING_LIST (psymtab) = pending_list; + + /* The way to turn this into a symtab is to call... */ + psymtab->read_symtab = mdebug_psymtab_to_symtab; + return (psymtab); +} + + +/* Allocate a linetable array of the given SIZE. Since the struct + already includes one item, we subtract one when calculating the + proper size to allocate. */ + +static struct linetable * +new_linetable (size) + int size; +{ + struct linetable *l; + + size = (size - 1) * sizeof (l->item) + sizeof (struct linetable); + l = (struct linetable *) xmalloc (size); + l->nitems = 0; + return l; +} + +/* Oops, too big. Shrink it. This was important with the 2.4 linetables, + I am not so sure about the 3.4 ones. + + Since the struct linetable already includes one item, we subtract one when + calculating the proper size to allocate. */ + +static struct linetable * +shrink_linetable (lt) + struct linetable *lt; +{ + + return (struct linetable *) xrealloc ((PTR) lt, + (sizeof (struct linetable) + + ((lt->nitems - 1) + * sizeof (lt->item)))); +} + +/* Allocate and zero a new blockvector of NBLOCKS blocks. */ + +static struct blockvector * +new_bvect (nblocks) + int nblocks; +{ + struct blockvector *bv; + int size; + + size = sizeof (struct blockvector) + nblocks * sizeof (struct block *); + bv = (struct blockvector *) xzalloc (size); + + BLOCKVECTOR_NBLOCKS (bv) = nblocks; + + return bv; +} + +/* Allocate and zero a new block of MAXSYMS symbols */ + +static struct block * +new_block (maxsyms) + int maxsyms; +{ + int size = sizeof (struct block) + (maxsyms - 1) * sizeof (struct symbol *); + + return (struct block *) xzalloc (size); +} + +/* Ooops, too big. Shrink block B in symtab S to its minimal size. + Shrink_block can also be used by add_symbol to grow a block. */ + +static struct block * +shrink_block (b, s) + struct block *b; + struct symtab *s; +{ + struct block *new; + struct blockvector *bv = BLOCKVECTOR (s); + int i; + + /* Just reallocate it and fix references to the old one */ + + new = (struct block *) xrealloc ((PTR) b, + (sizeof (struct block) + + ((BLOCK_NSYMS (b) - 1) + * sizeof (struct symbol *)))); + + /* Should chase pointers to old one. Fortunately, that`s just + the block`s function and inferior blocks */ + if (BLOCK_FUNCTION (new) && SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) == b) + SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) = new; + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + if (BLOCKVECTOR_BLOCK (bv, i) == b) + BLOCKVECTOR_BLOCK (bv, i) = new; + else if (BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) == b) + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) = new; + return new; +} + +/* Create a new symbol with printname NAME */ + +static struct symbol * +new_symbol (name) + char *name; +{ + struct symbol *s = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + + memset ((PTR) s, 0, sizeof (*s)); + SYMBOL_NAME (s) = name; + SYMBOL_LANGUAGE (s) = psymtab_language; + SYMBOL_INIT_DEMANGLED_NAME (s, ¤t_objfile->symbol_obstack); + return s; +} + +/* Create a new type with printname NAME */ + +static struct type * +new_type (name) + char *name; +{ + struct type *t; + + t = alloc_type (current_objfile); + TYPE_NAME (t) = name; + TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; + return t; +} + +/* Read ECOFF debugging information from a BFD section. This is + called from elfread.c. It parses the section into a + ecoff_debug_info struct, and then lets the rest of the file handle + it as normal. */ + +void +elfmdebug_build_psymtabs (objfile, swap, sec, section_offsets) + struct objfile *objfile; + const struct ecoff_debug_swap *swap; + asection *sec; + struct section_offsets *section_offsets; +{ + bfd *abfd = objfile->obfd; + struct ecoff_debug_info *info; + + info = ((struct ecoff_debug_info *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct ecoff_debug_info))); + + if (!(*swap->read_debug_info) (abfd, sec, info)) + error ("Error reading ECOFF debugging information: %s", + bfd_errmsg (bfd_get_error ())); + + mdebug_build_psymtabs (objfile, swap, info, section_offsets); +} + + +/* Things used for calling functions in the inferior. + These functions are exported to our companion + mips-tdep.c file and are here because they play + with the symbol-table explicitly. */ + +/* Sigtramp: make sure we have all the necessary information + about the signal trampoline code. Since the official code + from MIPS does not do so, we make up that information ourselves. + If they fix the library (unlikely) this code will neutralize itself. */ + +/* FIXME: This function is called only by mips-tdep.c. It needs to be + here because it calls functions defined in this file, but perhaps + this could be handled in a better way. */ + +void +fixup_sigtramp () +{ + struct symbol *s; + struct symtab *st; + struct block *b, *b0 = NULL; + + sigtramp_address = -1; + + /* We have to handle the following cases here: + a) The Mips library has a sigtramp label within sigvec. + b) Irix has a _sigtramp which we want to use, but it also has sigvec. */ + s = lookup_symbol ("sigvec", 0, VAR_NAMESPACE, 0, NULL); + if (s != 0) + { + b0 = SYMBOL_BLOCK_VALUE (s); + s = lookup_symbol ("sigtramp", b0, VAR_NAMESPACE, 0, NULL); + } + if (s == 0) + { + /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */ + s = lookup_symbol ("_sigtramp", 0, VAR_NAMESPACE, 0, NULL); + } + + /* But maybe this program uses its own version of sigvec */ + if (s == 0) + return; + + /* Did we or MIPSco fix the library ? */ + if (SYMBOL_CLASS (s) == LOC_BLOCK) + { + sigtramp_address = BLOCK_START (SYMBOL_BLOCK_VALUE (s)); + sigtramp_end = BLOCK_END (SYMBOL_BLOCK_VALUE (s)); + return; + } + + sigtramp_address = SYMBOL_VALUE (s); + sigtramp_end = sigtramp_address + 0x88; /* black magic */ + + /* But what symtab does it live in ? */ + st = find_pc_symtab (SYMBOL_VALUE (s)); + + /* + * Ok, there goes the fix: turn it into a procedure, with all the + * needed info. Note we make it a nested procedure of sigvec, + * which is the way the (assembly) code is actually written. + */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + SYMBOL_TYPE (s) = init_type (TYPE_CODE_FUNC, 4, 0, (char *) NULL, + st->objfile); + TYPE_TARGET_TYPE (SYMBOL_TYPE (s)) = mdebug_type_void; + + /* Need a block to allocate MIPS_EFI_SYMBOL_NAME in */ + b = new_block (1); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_START (b) = sigtramp_address; + BLOCK_END (b) = sigtramp_end; + BLOCK_FUNCTION (b) = s; + BLOCK_SUPERBLOCK (b) = BLOCK_SUPERBLOCK (b0); + add_block (b, st); + sort_blocks (st); + + /* Make a MIPS_EFI_SYMBOL_NAME entry for it */ + { + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + xzalloc (sizeof (struct mips_extra_func_info))); + + e->numargs = 0; /* the kernel thinks otherwise */ + e->pdr.frameoffset = 32; + e->pdr.framereg = SP_REGNUM; + /* Note that setting pcreg is no longer strictly necessary as + mips_frame_saved_pc is now aware of signal handler frames. */ + e->pdr.pcreg = PC_REGNUM; + e->pdr.regmask = -2; + /* Offset to saved r31, in the sigtramp case the saved registers + are above the frame in the sigcontext. + We have 4 alignment bytes, 12 bytes for onstack, mask and pc, + 32 * 4 bytes for the general registers, 12 bytes for mdhi, mdlo, ownedfp + and 32 * 4 bytes for the floating point registers. */ + e->pdr.regoffset = 4 + 12 + 31 * 4; + e->pdr.fregmask = -1; + /* Offset to saved f30 (first saved *double* register). */ + e->pdr.fregoffset = 4 + 12 + 32 * 4 + 12 + 30 * 4; + e->pdr.isym = (long) s; + e->pdr.adr = sigtramp_address; + + current_objfile = st->objfile; /* Keep new_symbol happy */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_VALUE (s) = (long) e; + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = mdebug_type_void; + current_objfile = NULL; + } + + BLOCK_SYM (b, BLOCK_NSYMS (b)++) = s; +} + +void +_initialize_mdebugread () +{ + mdebug_type_void = + init_type (TYPE_CODE_VOID, 1, + 0, + "void", (struct objfile *) NULL); + mdebug_type_char = + init_type (TYPE_CODE_INT, 1, + 0, + "char", (struct objfile *) NULL); + mdebug_type_unsigned_char = + init_type (TYPE_CODE_INT, 1, + TYPE_FLAG_UNSIGNED, + "unsigned char", (struct objfile *) NULL); + mdebug_type_short = + init_type (TYPE_CODE_INT, 2, + 0, + "short", (struct objfile *) NULL); + mdebug_type_unsigned_short = + init_type (TYPE_CODE_INT, 2, + TYPE_FLAG_UNSIGNED, + "unsigned short", (struct objfile *) NULL); + mdebug_type_int_32 = + init_type (TYPE_CODE_INT, 4, + 0, + "int", (struct objfile *) NULL); + mdebug_type_unsigned_int_32 = + init_type (TYPE_CODE_INT, 4, + TYPE_FLAG_UNSIGNED, + "unsigned int", (struct objfile *) NULL); + mdebug_type_int_64 = + init_type (TYPE_CODE_INT, 8, + 0, + "int", (struct objfile *) NULL); + mdebug_type_unsigned_int_64 = + init_type (TYPE_CODE_INT, 8, + TYPE_FLAG_UNSIGNED, + "unsigned int", (struct objfile *) NULL); + mdebug_type_long_32 = + init_type (TYPE_CODE_INT, 4, + 0, + "long", (struct objfile *) NULL); + mdebug_type_unsigned_long_32 = + init_type (TYPE_CODE_INT, 4, + TYPE_FLAG_UNSIGNED, + "unsigned long", (struct objfile *) NULL); + mdebug_type_long_64 = + init_type (TYPE_CODE_INT, 8, + 0, + "long", (struct objfile *) NULL); + mdebug_type_unsigned_long_64 = + init_type (TYPE_CODE_INT, 8, + TYPE_FLAG_UNSIGNED, + "unsigned long", (struct objfile *) NULL); + mdebug_type_long_long_64 = + init_type (TYPE_CODE_INT, 8, + 0, + "long long", (struct objfile *) NULL); + mdebug_type_unsigned_long_long_64 = + init_type (TYPE_CODE_INT, 8, + TYPE_FLAG_UNSIGNED, + "unsigned long long", (struct objfile *) NULL); + mdebug_type_adr_32 = + init_type (TYPE_CODE_PTR, 4, + TYPE_FLAG_UNSIGNED, + "adr_32", (struct objfile *) NULL); + TYPE_TARGET_TYPE (mdebug_type_adr_32) = mdebug_type_void; + mdebug_type_adr_64 = + init_type (TYPE_CODE_PTR, 8, + TYPE_FLAG_UNSIGNED, + "adr_64", (struct objfile *) NULL); + TYPE_TARGET_TYPE (mdebug_type_adr_64) = mdebug_type_void; + mdebug_type_float = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "float", (struct objfile *) NULL); + mdebug_type_double = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "double", (struct objfile *) NULL); + mdebug_type_complex = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "complex", (struct objfile *) NULL); + TYPE_TARGET_TYPE (mdebug_type_complex) = mdebug_type_float; + mdebug_type_double_complex = + init_type (TYPE_CODE_COMPLEX, 2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "double complex", (struct objfile *) NULL); + TYPE_TARGET_TYPE (mdebug_type_double_complex) = mdebug_type_double; + + /* Is a "string" the way btString means it the same as TYPE_CODE_STRING? + FIXME. */ + mdebug_type_string = + init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", + (struct objfile *) NULL); + + /* We use TYPE_CODE_INT to print these as integers. Does this do any + good? Would we be better off with TYPE_CODE_ERROR? Should + TYPE_CODE_ERROR print things in hex if it knows the size? */ + mdebug_type_fixed_dec = + init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", + (struct objfile *) NULL); + + mdebug_type_float_dec = + init_type (TYPE_CODE_ERROR, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", + (struct objfile *) NULL); + + nodebug_func_symbol_type = init_type (TYPE_CODE_FUNC, 1, 0, + "", NULL); + TYPE_TARGET_TYPE (nodebug_func_symbol_type) = mdebug_type_int; + nodebug_var_symbol_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0, + "", NULL); +} diff --git a/contrib/gdb/gdb/mem-break.c b/contrib/gdb/gdb/mem-break.c new file mode 100644 index 000000000000..f31e2fbd46b1 --- /dev/null +++ b/contrib/gdb/gdb/mem-break.c @@ -0,0 +1,121 @@ +/* Simulate breakpoints by patching locations in the target system, for GDB. + Copyright 1990, 1991, 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +/* Either BREAKPOINT should be defined, or both of LITTLE_BREAKPOINT, + BIG_BREAKPOINT should be defined. */ + +#if defined (BREAKPOINT) || (defined (LITTLE_BREAKPOINT) && defined (BIG_BREAKPOINT)) + +/* This file is only useful if BREAKPOINT is set. If not, we punt. */ + +#include "symtab.h" +#include "breakpoint.h" +#include "inferior.h" +#include "target.h" + +/* If the target isn't bi-endian, just pretend it is. */ +#if defined(BREAKPOINT) && !defined (LITTLE_BREAKPOINT) && !defined (BIG_BREAKPOINT) +#define LITTLE_BREAKPOINT BREAKPOINT +#define BIG_BREAKPOINT BREAKPOINT +#endif + +/* This is the sequence of bytes we insert for a breakpoint. On some + machines, breakpoints are handled by the target environment and we + don't have to worry about them here. */ + +static unsigned char big_break_insn[] = BIG_BREAKPOINT; +static unsigned char little_break_insn[] = LITTLE_BREAKPOINT; + +/* FIXME: We assume big and little breakpoints are the same size. */ +#define BREAKPOINT_LEN (sizeof (big_break_insn)) + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save BREAKPOINT_LEN bytes (this + is accomplished via BREAKPOINT_MAX). */ + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, BREAKPOINT_LEN); + + if (val == 0) + { + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + val = target_write_memory (addr, (char *)big_break_insn, + BREAKPOINT_LEN); + else + val = target_write_memory (addr, (char *)little_break_insn, + BREAKPOINT_LEN); + } + + return val; +} + + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, BREAKPOINT_LEN); +} + + +/* FIXME: This is a hack and should depend on the debugging target. + See comment in breakpoint.c where this is used. */ + +int memory_breakpoint_size = BREAKPOINT_LEN; + + +#else /* BREAKPOINT */ + +char nogo[] = "Breakpoints not implemented for this target."; + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +int memory_breakpoint_size = -1; + +#endif /* BREAKPOINT */ diff --git a/contrib/gdb/gdb/minimon.h b/contrib/gdb/gdb/minimon.h new file mode 100644 index 000000000000..f60c4176f1cd --- /dev/null +++ b/contrib/gdb/gdb/minimon.h @@ -0,0 +1,562 @@ +/* Definitions and macros for support of AMD's remote debugger, MiniMON. + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Some basic types. FIXME, this should be done by declaring bitfield + * sizes in the structs. We can't portably depend on a "long int" being + * 32 bits, etc. + */ +typedef long int INT32; /* 32 bit integer */ +typedef unsigned long int UINT32; /* 32 bit integer (unsigned) */ +typedef unsigned long int ADDR32; /* 32 bit address */ +typedef unsigned long int INST32; /* 32 bit instruction */ +typedef long int BOOLEAN; /* Boolean value (32 bit) */ +typedef unsigned char BYTE; /* byte (8 bit) */ +typedef short int INT16; /* 16 bit integer */ +typedef unsigned short int UINT16; /* 16 bit integer (unsigned) */ + +/****************************************************************************/ +/************************* Message Information ******************************/ +/****************************************************************************/ + +/* + * Error codes + */ + +/* General errors */ +#define EMUSAGE 1 /* Bad args / flags */ +#define EMFAIL 2 /* Unrecoverable error */ +#define EMBADADDR 3 /* Illegal address */ +#define EMBADREG 4 /* Illegal register */ +#define EMSYNTAX 5 /* Illegal command syntax */ +#define EMACCESS 6 /* Could not access memory */ +#define EMALLOC 7 /* Could not allocate memory */ +#define EMTARGET 8 /* Unknown target type */ +#define EMHINIT 9 /* Could not initialize host */ +#define EMCOMM 10 /* Could not open communication channel */ + +/* Message errors */ +#define EMBADMSG 11 /* Unknown message type */ +#define EMMSG2BIG 12 /* Message to large for buffer */ +#define EMNOSEND 13 /* Could not send message */ +#define EMNORECV 14 /* Could not receive message */ + +#define EMRESET 15 /* Could not RESET target */ +#define EMCONFIG 16 /* Could not get target CONFIG */ +#define EMSTATUS 17 /* Could not get target STATUS */ +#define EMREAD 18 /* Could not READ target memory */ +#define EMWRITE 19 /* Could not WRITE target memory */ +#define EMBKPTSET 20 /* Could not set breakpoint */ +#define EMBKPTRM 21 /* Could not remove breakpoint */ +#define EMBKPTSTAT 22 /* Could not get breakpoint status */ +#define EMBKPTNONE 23 /* All breakpoints in use */ +#define EMBKPTUSED 24 /* Breakpoints already in use */ +#define EMCOPY 25 /* Could not COPY target memory */ +#define EMFILL 26 /* Could not FILL target memory */ +#define EMINIT 27 /* Could not initialize target memory */ +#define EMGO 28 /* Could not start execution */ +#define EMSTEP 29 /* Could not single step */ +#define EMBREAK 30 /* Could not BREAK */ +#define EMHIF 31 /* Could not perform HIF service */ +#define EMCHANNEL0 32 /* Could not read CHANNEL0 */ +#define EMCHANNEL1 33 /* Could not write CHANNEL1 */ + +/* COFF file loader errors */ +#define EMOPEN 34 /* Could not open COFF file */ +#define EMHDR 35 /* Could not read COFF header */ +#define EMMAGIC 36 /* Bad magic number */ +#define EMAOUT 37 /* Could not read COFF a.out header */ +#define EMSCNHDR 38 /* Could not read COFF section header */ +#define EMSCN 39 /* Could not read COFF section */ +#define EMCLOSE 40 /* Could not close COFF file */ + +/* Log file errors */ +#define EMLOGOPEN 41 /* Could not open log file */ +#define EMLOGREAD 42 /* Could not read log file */ +#define EMLOGWRITE 43 /* Could not write to log file */ +#define EMLOGCLOSE 44 /* Could not close log file */ + +/* Command file errors */ +#define EMCMDOPEN 45 /* Could not open command file */ +#define EMCMDREAD 46 /* Could not read command file */ +#define EMCMDWRITE 47 /* Could not write to command file */ +#define EMCMDCLOSE 48 /* Could not close comand file */ + +#define EMTIMEOUT 49 /* Host timed out waiting for a message */ +#define EMCOMMTYPE 50 /* A '-t' flag must be specified */ +#define EMCOMMERR 51 /* Communication error */ +#define EMBAUD 52 /* Invalid baud rate specified */ +/* + * Memory Spaces + */ +#define LOCAL_REG 0 /* Local processor register */ +#define GLOBAL_REG 1 /* Global processor register */ +#define SPECIAL_REG 2 /* Special processor register */ +#define TLB_REG 3 /* Translation Lookaside Buffer */ +#define COPROC_REG 4 /* Coprocessor register */ +#define I_MEM 5 /* Instruction Memory */ +#define D_MEM 6 /* Data Memory */ +#define I_ROM 7 /* Instruction ROM */ +#define D_ROM 8 /* Data ROM */ +#define I_O 9 /* Input/Output */ +#define I_CACHE 10 /* Instruction Cache */ +#define D_CACHE 11 /* Data Cache */ + +/* To supress warnings for zero length array definitions */ +#define DUMMY 1 + +/* +** Host to target definitions +*/ + +#define RESET 0 +#define CONFIG_REQ 1 +#define STATUS_REQ 2 +#define READ_REQ 3 +#define WRITE_REQ 4 +#define BKPT_SET 5 +#define BKPT_RM 6 +#define BKPT_STAT 7 +#define COPY 8 +#define FILL 9 +#define INIT 10 +#define GO 11 +#define STEP 12 +#define BREAK 13 + +#define HIF_CALL_RTN 64 +#define CHANNEL0 65 +#define CHANNEL1_ACK 66 + + +/* +** Target to host definitions +*/ + +#define RESET_ACK 32 +#define CONFIG 33 +#define STATUS 34 +#define READ_ACK 35 +#define WRITE_ACK 36 +#define BKPT_SET_ACK 37 +#define BKPT_RM_ACK 38 +#define BKPT_STAT_ACK 39 +#define COPY_ACK 40 +#define FILL_ACK 41 +#define INIT_ACK 42 +#define HALT 43 + +#define ERROR 63 + +#define HIF_CALL 96 +#define CHANNEL0_ACK 97 +#define CHANNEL1 98 + + +/* A "generic" message */ +struct generic_msg_t { + INT32 code; /* generic */ + INT32 length; + BYTE byte[DUMMY]; +}; + + +/* A "generic" message (with an INT32 array) */ +struct generic_int32_msg_t { + INT32 code; /* generic */ + INT32 length; + INT32 int32[DUMMY]; +}; + + +/* +** Host to target messages +*/ + +struct reset_msg_t { + INT32 code; /* 0 */ + INT32 length; +}; + + +struct config_req_msg_t { + INT32 code; /* 1 */ + INT32 length; +}; + + +struct status_req_msg_t { + INT32 code; /* 2 */ + INT32 length; +}; + + +struct read_req_msg_t { + INT32 code; /* 3 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; +}; + + +struct write_req_msg_t { + INT32 code; /* 4 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; + BYTE data[DUMMY]; +}; + + +struct write_r_msg_t { + INT32 code; /* 4 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; + INT32 data[DUMMY]; +}; + + +struct bkpt_set_msg_t { + INT32 code; /* 5 */ + INT32 length; + INT32 memory_space; + ADDR32 bkpt_addr; + INT32 pass_count; + INT32 bkpt_type; +}; + + +struct bkpt_rm_msg_t { + INT32 code; /* 6 */ + INT32 length; + INT32 memory_space; + ADDR32 bkpt_addr; +}; + + +struct bkpt_stat_msg_t { + INT32 code; /* 7 */ + INT32 length; + INT32 memory_space; + ADDR32 bkpt_addr; +}; + + +struct copy_msg_t { + INT32 code; /* 8 */ + INT32 length; + INT32 source_space; + ADDR32 source_addr; + INT32 dest_space; + ADDR32 dest_addr; + INT32 byte_count; +}; + + +struct fill_msg_t { + INT32 code; /* 9 */ + INT32 length; + INT32 memory_space; + ADDR32 start_addr; + INT32 fill_count; + INT32 byte_count; + BYTE fill_data[DUMMY]; +}; + + +struct init_msg_t { + INT32 code; /* 10 */ + INT32 length; + ADDR32 text_start; + ADDR32 text_end; + ADDR32 data_start; + ADDR32 data_end; + ADDR32 entry_point; + INT32 mem_stack_size; + INT32 reg_stack_size; + ADDR32 arg_start; + INT32 os_control; +}; + + +struct go_msg_t { + INT32 code; /* 11 */ + INT32 length; +}; + + +struct step_msg_t { + INT32 code; /* 12 */ + INT32 length; + INT32 count; +}; + + +struct break_msg_t { + INT32 code; /* 13 */ + INT32 length; +}; + + +struct hif_call_rtn_msg_t { + INT32 code; /* 64 */ + INT32 length; + INT32 service_number; + INT32 gr121; + INT32 gr96; + INT32 gr97; +}; + + +struct channel0_msg_t { + INT32 code; /* 65 */ + INT32 length; + BYTE data; +}; + + +struct channel1_ack_msg_t { + INT32 code; /* 66 */ + INT32 length; +}; + + +/* +** Target to host messages +*/ + + +struct reset_ack_msg_t { + INT32 code; /* 32 */ + INT32 length; +}; + + +struct config_msg_t { + INT32 code; /* 33 */ + INT32 length; + INT32 processor_id; + INT32 version; + ADDR32 I_mem_start; + INT32 I_mem_size; + ADDR32 D_mem_start; + INT32 D_mem_size; + ADDR32 ROM_start; + INT32 ROM_size; + INT32 max_msg_size; + INT32 max_bkpts; + INT32 coprocessor; + INT32 reserved; +}; + + +struct status_msg_t { + INT32 code; /* 34 */ + INT32 length; + INT32 msgs_sent; + INT32 msgs_received; + INT32 errors; + INT32 bkpts_hit; + INT32 bkpts_free; + INT32 traps; + INT32 fills; + INT32 spills; + INT32 cycles; + INT32 reserved; +}; + + +struct read_ack_msg_t { + INT32 code; /* 35 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; + BYTE data[DUMMY]; +}; + +struct read_r_ack_msg_t { + INT32 code; /* 35 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; + INT32 data[DUMMY]; +}; + + +struct write_ack_msg_t { + INT32 code; /* 36 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 byte_count; +}; + + +struct bkpt_set_ack_msg_t { + INT32 code; /* 37 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 pass_count; + INT32 bkpt_type; +}; + + +struct bkpt_rm_ack_msg_t { + INT32 code; /* 38 */ + INT32 length; + INT32 memory_space; + ADDR32 address; +}; + + +struct bkpt_stat_ack_msg_t { + INT32 code; /* 39 */ + INT32 length; + INT32 memory_space; + ADDR32 address; + INT32 pass_count; + INT32 bkpt_type; +}; + + +struct copy_ack_msg_t { + INT32 code; /* 40 */ + INT32 length; + INT32 source_space; + ADDR32 source_addr; + INT32 dest_space; + ADDR32 dest_addr; + INT32 byte_count; +}; + + +struct fill_ack_msg_t { + INT32 code; /* 41 */ + INT32 length; + INT32 memory_space; + ADDR32 start_addr; + INT32 fill_count; + INT32 byte_count; +}; + + +struct init_ack_msg_t { + INT32 code; /* 42 */ + INT32 length; +}; + + +struct halt_msg_t { + INT32 code; /* 43 */ + INT32 length; + INT32 memory_space; + ADDR32 pc0; + ADDR32 pc1; + INT32 trap_number; +}; + + +struct error_msg_t { + INT32 code; /* 63 */ + INT32 length; + INT32 error_code; + INT32 memory_space; + ADDR32 address; +}; + + +struct hif_call_msg_t { + INT32 code; /* 96 */ + INT32 length; + INT32 service_number; + INT32 lr2; + INT32 lr3; + INT32 lr4; +}; + + +struct channel0_ack_msg_t { + INT32 code; /* 97 */ + INT32 length; +}; + + +struct channel1_msg_t { + INT32 code; /* 98 */ + INT32 length; + BYTE data[DUMMY]; +}; + + + +/* +** Union all of the message types together +*/ + +union msg_t { + struct generic_msg_t generic_msg; + struct generic_int32_msg_t generic_int32_msg; + + struct reset_msg_t reset_msg; + struct config_req_msg_t config_req_msg; + struct status_req_msg_t status_req_msg; + struct read_req_msg_t read_req_msg; + struct write_req_msg_t write_req_msg; + struct write_r_msg_t write_r_msg; + struct bkpt_set_msg_t bkpt_set_msg; + struct bkpt_rm_msg_t bkpt_rm_msg; + struct bkpt_stat_msg_t bkpt_stat_msg; + struct copy_msg_t copy_msg; + struct fill_msg_t fill_msg; + struct init_msg_t init_msg; + struct go_msg_t go_msg; + struct step_msg_t step_msg; + struct break_msg_t break_msg; + + struct hif_call_rtn_msg_t hif_call_rtn_msg; + struct channel0_msg_t channel0_msg; + struct channel1_ack_msg_t channel1_ack_msg; + + struct reset_ack_msg_t reset_ack_msg; + struct config_msg_t config_msg; + struct status_msg_t status_msg; + struct read_ack_msg_t read_ack_msg; + struct read_r_ack_msg_t read_r_ack_msg; + struct write_ack_msg_t write_ack_msg; + struct bkpt_set_ack_msg_t bkpt_set_ack_msg; + struct bkpt_rm_ack_msg_t bkpt_rm_ack_msg; + struct bkpt_stat_ack_msg_t bkpt_stat_ack_msg; + struct copy_ack_msg_t copy_ack_msg; + struct fill_ack_msg_t fill_ack_msg; + struct init_ack_msg_t init_ack_msg; + struct halt_msg_t halt_msg; + + struct error_msg_t error_msg; + + struct hif_call_msg_t hif_call_msg; + struct channel0_ack_msg_t channel0_ack_msg; + struct channel1_msg_t channel1_msg; +}; diff --git a/contrib/gdb/gdb/minsyms.c b/contrib/gdb/gdb/minsyms.c new file mode 100644 index 000000000000..6c22d6cd8512 --- /dev/null +++ b/contrib/gdb/gdb/minsyms.c @@ -0,0 +1,855 @@ +/* GDB routines for manipulating the minimal symbol tables. + Copyright 1992, 1993, 1994, 1996, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file contains support routines for creating, manipulating, and + destroying minimal symbol tables. + + Minimal symbol tables are used to hold some very basic information about + all defined global symbols (text, data, bss, abs, etc). The only two + required pieces of information are the symbol's name and the address + associated with that symbol. + + In many cases, even if a file was compiled with no special options for + debugging at all, as long as was not stripped it will contain sufficient + information to build useful minimal symbol tables using this structure. + + Even when a file contains enough debugging information to build a full + symbol table, these minimal symbols are still useful for quickly mapping + between names and addresses, and vice versa. They are also sometimes used + to figure out what full symbol table entries need to be read in. */ + + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "demangle.h" +#include "gdb-stabs.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 + symbol obstack. */ + +#define BUNCH_SIZE 127 + +struct msym_bunch +{ + struct msym_bunch *next; + struct minimal_symbol contents[BUNCH_SIZE]; +}; + +/* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + +static struct msym_bunch *msym_bunch; + +/* Number of slots filled in current bunch. */ + +static int msym_bunch_index; + +/* Total number of minimal symbols recorded so far for the objfile. */ + +static int msym_count; + +/* Prototypes for local functions. */ + +static int +compare_minimal_symbols PARAMS ((const void *, const void *)); + +static int +compact_minimal_symbols PARAMS ((struct minimal_symbol *, int)); + +/* 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, limit the search + to that source file. Returns a pointer to the minimal symbol that + matches, or NULL if no match is found. + + Note: One instance where there may be duplicate minimal symbols with + the same name is when the symbol tables for a shared library and the + symbol tables for an executable contain global symbols with the same + names (the dynamic linker deals with the duplication). */ + +struct minimal_symbol * +lookup_minimal_symbol (name, sfile, objf) + register const char *name; + const char *sfile; + struct objfile *objf; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *found_symbol = NULL; + struct minimal_symbol *found_file_symbol = NULL; + struct minimal_symbol *trampoline_symbol = NULL; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (sfile != NULL) + { + char *p = strrchr (sfile, '/'); + if (p != NULL) + sfile = p + 1; + } +#endif + + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile -> next) + { + if (objf == NULL || objf == objfile) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && SYMBOL_NAME (msymbol) != NULL && + found_symbol == NULL; + msymbol++) + { + if (SYMBOL_MATCHES_NAME (msymbol, name)) + { + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_file_text: + case mst_file_data: + case mst_file_bss: +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (sfile == NULL || STREQ (msymbol->filename, sfile)) + found_file_symbol = msymbol; +#else + /* We have neither the ability nor the need to + deal with the SFILE parameter. If we find + more than one symbol, just return the latest + one (the user can't expect useful behavior in + that case). */ + found_file_symbol = msymbol; +#endif + break; + + case mst_solib_trampoline: + + /* If a trampoline symbol is found, we prefer to + keep looking for the *real* symbol. If the + actual symbol is not found, then we'll use the + trampoline entry. */ + if (trampoline_symbol == NULL) + trampoline_symbol = msymbol; + break; + + case mst_unknown: + default: + found_symbol = msymbol; + break; + } + } + } + } + } + /* External symbols are best. */ + if (found_symbol) + return found_symbol; + + /* File-local symbols are next best. */ + if (found_file_symbol) + return found_file_symbol; + + /* Symbols for shared library trampolines are next best. */ + if (trampoline_symbol) + return trampoline_symbol; + + return NULL; +} + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME and of text type. + If OBJF is non-NULL, limit + the search to that objfile. If SFILE is non-NULL, limit the search + to that source file. Returns a pointer to the minimal symbol that + matches, or NULL if no match is found. +*/ + +struct minimal_symbol * +lookup_minimal_symbol_text (name, sfile, objf) + register const char *name; + const char *sfile; + struct objfile *objf; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *found_symbol = NULL; + struct minimal_symbol *found_file_symbol = NULL; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (sfile != NULL) + { + char *p = strrchr (sfile, '/'); + if (p != NULL) + sfile = p + 1; + } +#endif + + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile -> next) + { + if (objf == NULL || objf == objfile) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && SYMBOL_NAME (msymbol) != NULL && + found_symbol == NULL; + msymbol++) + { + if (SYMBOL_MATCHES_NAME (msymbol, name) && + (MSYMBOL_TYPE (msymbol) == mst_text || + MSYMBOL_TYPE (msymbol) == mst_file_text)) + { + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_file_text: +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (sfile == NULL || STREQ (msymbol->filename, sfile)) + found_file_symbol = msymbol; +#else + /* We have neither the ability nor the need to + deal with the SFILE parameter. If we find + more than one symbol, just return the latest + one (the user can't expect useful behavior in + that case). */ + found_file_symbol = msymbol; +#endif + break; + default: + found_symbol = msymbol; + break; + } + } + } + } + } + /* External symbols are best. */ + if (found_symbol) + return found_symbol; + + /* File-local symbols are next best. */ + if (found_file_symbol) + return found_file_symbol; + + return NULL; +} + +/* Look through all the current minimal symbol tables and find the + first minimal symbol that matches NAME and of solib trampoline type. + If OBJF is non-NULL, limit + the search to that objfile. If SFILE is non-NULL, limit the search + to that source file. Returns a pointer to the minimal symbol that + matches, or NULL if no match is found. +*/ + +struct minimal_symbol * +lookup_minimal_symbol_solib_trampoline (name, sfile, objf) + register const char *name; + const char *sfile; + struct objfile *objf; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *found_symbol = NULL; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (sfile != NULL) + { + char *p = strrchr (sfile, '/'); + if (p != NULL) + sfile = p + 1; + } +#endif + + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile -> next) + { + if (objf == NULL || objf == objfile) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && SYMBOL_NAME (msymbol) != NULL && + found_symbol == NULL; + msymbol++) + { + if (SYMBOL_MATCHES_NAME (msymbol, name) && + MSYMBOL_TYPE (msymbol) == mst_solib_trampoline) + return msymbol; + } + } + } + + return NULL; +} + + +/* 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. Returns a pointer to the minimal symbol if such a symbol + is found, or NULL if PC is not in a suitable range. Note that we need + to look through ALL the minimal symbol tables before deciding on the + symbol that comes closest to the specified PC. This is because objfiles + can overlap, for example objfile A has .text at 0x100 and .data at 0x40000 + and objfile B has .text at 0x234 and .data at 0x40048. */ + +struct minimal_symbol * +lookup_minimal_symbol_by_pc (pc) + register CORE_ADDR pc; +{ + register int lo; + register int hi; + register int new; + register struct objfile *objfile; + register struct minimal_symbol *msymbol; + register struct minimal_symbol *best_symbol = NULL; + + for (objfile = object_files; + objfile != NULL; + objfile = objfile -> next) + { + /* If this objfile has a minimal symbol table, go search it using + a binary search. Note that a minimal symbol table always consists + of at least two symbols, a "real" symbol and the terminating + "null symbol". If there are no real symbols, then there is no + minimal symbol table at all. */ + + if ((msymbol = objfile -> msymbols) != NULL) + { + lo = 0; + hi = objfile -> minimal_symbol_count - 1; + + /* This code assumes that the minimal symbols are sorted by + ascending address values. If the pc value is greater than or + equal to the first symbol's address, then some symbol in this + minimal symbol table is a suitable candidate for being the + "best" symbol. This includes the last real symbol, for cases + where the pc value is larger than any address in this vector. + + By iterating until the address associated with the current + hi index (the endpoint of the test interval) is less than + or equal to the desired pc value, we accomplish two things: + (1) the case where the pc value is larger than any minimal + symbol address is trivially solved, (2) the address associated + with the hi index is always the one we want when the interation + terminates. In essence, we are iterating the test interval + down until the pc value is pushed out of it from the high end. + + Warning: this code is trickier than it would appear at first. */ + + /* Should also requires that pc is <= end of objfile. FIXME! */ + if (pc >= SYMBOL_VALUE_ADDRESS (&msymbol[lo])) + { + while (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) > pc) + { + /* pc is still strictly less than highest address */ + /* Note "new" will always be >= lo */ + new = (lo + hi) / 2; + if ((SYMBOL_VALUE_ADDRESS (&msymbol[new]) >= pc) || + (lo == new)) + { + hi = new; + } + else + { + lo = new; + } + } + + /* If we have multiple symbols at the same address, we want + hi to point to the last one. That way we can find the + right symbol if it has an index greater than hi. */ + while (hi < objfile -> minimal_symbol_count - 1 + && (SYMBOL_VALUE_ADDRESS (&msymbol[hi]) + == SYMBOL_VALUE_ADDRESS (&msymbol[hi+1]))) + hi++; + + /* The minimal symbol indexed by hi now is the best one in this + objfile's minimal symbol table. See if it is the best one + overall. */ + + /* Skip any absolute symbols. This is apparently what adb + and dbx do, and is needed for the CM-5. There are two + known possible problems: (1) on ELF, apparently end, edata, + etc. are absolute. Not sure ignoring them here is a big + deal, but if we want to use them, the fix would go in + elfread.c. (2) I think shared library entry points on the + NeXT are absolute. If we want special handling for this + it probably should be triggered by a special + mst_abs_or_lib or some such. */ + while (hi >= 0 + && msymbol[hi].type == mst_abs) + --hi; + + if (hi >= 0 + && ((best_symbol == NULL) || + (SYMBOL_VALUE_ADDRESS (best_symbol) < + SYMBOL_VALUE_ADDRESS (&msymbol[hi])))) + { + best_symbol = &msymbol[hi]; + } + } + } + } + return (best_symbol); +} + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING +CORE_ADDR +find_stab_function_addr (namestring, pst, objfile) + char *namestring; + struct partial_symtab *pst; + struct objfile *objfile; +{ + struct minimal_symbol *msym; + char *p; + int n; + + p = strchr (namestring, ':'); + if (p == NULL) + p = namestring; + n = p - namestring; + p = alloca (n + 1); + strncpy (p, namestring, n); + p[n] = 0; + + msym = lookup_minimal_symbol (p, pst->filename, objfile); + return msym == NULL ? 0 : SYMBOL_VALUE_ADDRESS (msym); +} +#endif /* SOFUN_ADDRESS_MAYBE_MISSING */ + + +/* Return leading symbol character for a BFD. If BFD is NULL, + return the leading symbol character from the main objfile. */ + +static int get_symbol_leading_char PARAMS ((bfd *)); + +static int +get_symbol_leading_char (abfd) + bfd * abfd; +{ + if (abfd != NULL) + return bfd_get_symbol_leading_char (abfd); + if (symfile_objfile != NULL && symfile_objfile->obfd != NULL) + return bfd_get_symbol_leading_char (symfile_objfile->obfd); + 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. */ + +void +init_minimal_symbol_collection () +{ + msym_count = 0; + msym_bunch = NULL; + msym_bunch_index = BUNCH_SIZE; +} + +void +prim_record_minimal_symbol (name, address, ms_type, objfile) + const char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + struct objfile *objfile; +{ + int section; + + switch (ms_type) + { + case mst_text: + case mst_file_text: + case mst_solib_trampoline: + section = SECT_OFF_TEXT; + break; + case mst_data: + case mst_file_data: + section = SECT_OFF_DATA; + break; + case mst_bss: + case mst_file_bss: + section = SECT_OFF_BSS; + break; + default: + section = -1; + } + + prim_record_minimal_symbol_and_info (name, address, ms_type, + NULL, section, objfile); +} + +/* Record a minimal symbol in the msym bunches. Returns the symbol + newly created. */ +struct minimal_symbol * +prim_record_minimal_symbol_and_info (name, address, ms_type, info, section, + objfile) + const char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + char *info; + int section; + struct objfile *objfile; +{ + register struct msym_bunch *new; + register struct minimal_symbol *msymbol; + + if (ms_type == mst_file_text) + { + /* Don't put gcc_compiled, __gnu_compiled_cplus, and friends into + the minimal symbols, because if there is also another symbol + at the same address (e.g. the first function of the file), + lookup_minimal_symbol_by_pc would have no way of getting the + right one. */ + if (name[0] == 'g' + && (strcmp (name, GCC_COMPILED_FLAG_SYMBOL) == 0 + || strcmp (name, GCC2_COMPILED_FLAG_SYMBOL) == 0)) + return (NULL); + + { + const char *tempstring = name; + if (tempstring[0] == get_symbol_leading_char (objfile->obfd)) + ++tempstring; + if (STREQN (tempstring, "__gnu_compiled", 14)) + return (NULL); + } + } + + if (msym_bunch_index == BUNCH_SIZE) + { + new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch)); + msym_bunch_index = 0; + new -> next = msym_bunch; + msym_bunch = new; + } + msymbol = &msym_bunch -> contents[msym_bunch_index]; + SYMBOL_NAME (msymbol) = (char *) name; + SYMBOL_INIT_LANGUAGE_SPECIFIC (msymbol, language_unknown); + SYMBOL_VALUE_ADDRESS (msymbol) = address; + SYMBOL_SECTION (msymbol) = section; + + MSYMBOL_TYPE (msymbol) = ms_type; + /* FIXME: This info, if it remains, needs its own field. */ + MSYMBOL_INFO (msymbol) = info; /* FIXME! */ + msym_bunch_index++; + msym_count++; + OBJSTAT (objfile, n_minsyms++); + return msymbol; +} + +/* Compare two minimal symbols by address and return a signed result based + on unsigned comparisons, so that we sort into unsigned numeric order. */ + +static int +compare_minimal_symbols (fn1p, fn2p) + const PTR fn1p; + const PTR fn2p; +{ + register const struct minimal_symbol *fn1; + register const struct minimal_symbol *fn2; + + fn1 = (const struct minimal_symbol *) fn1p; + fn2 = (const struct minimal_symbol *) fn2p; + + if (SYMBOL_VALUE_ADDRESS (fn1) < SYMBOL_VALUE_ADDRESS (fn2)) + { + return (-1); + } + else if (SYMBOL_VALUE_ADDRESS (fn1) > SYMBOL_VALUE_ADDRESS (fn2)) + { + return (1); + } + else + { + return (0); + } +} + +/* Discard the currently collected minimal symbols, if any. If we wish + to save them for later use, we must have already copied them somewhere + else before calling this function. + + FIXME: We could allocate the minimal symbol bunches on their own + obstack and then simply blow the obstack away when we are done with + it. Is it worth the extra trouble though? */ + +/* ARGSUSED */ +void +discard_minimal_symbols (foo) + int foo; +{ + register struct msym_bunch *next; + + while (msym_bunch != NULL) + { + next = msym_bunch -> next; + free ((PTR)msym_bunch); + msym_bunch = next; + } +} + +/* Compact duplicate entries out of a minimal symbol table by walking + through the table and compacting out entries with duplicate addresses + and matching names. Return the number of entries remaining. + + On entry, the table resides between msymbol[0] and msymbol[mcount]. + On exit, it resides between msymbol[0] and msymbol[result_count]. + + When files contain multiple sources of symbol information, it is + possible for the minimal symbol table to contain many duplicate entries. + As an example, SVR4 systems use ELF formatted object files, which + usually contain at least two different types of symbol tables (a + standard ELF one and a smaller dynamic linking table), as well as + DWARF debugging information for files compiled with -g. + + Without compacting, the minimal symbol table for gdb itself contains + over a 1000 duplicates, about a third of the total table size. Aside + from the potential trap of not noticing that two successive entries + identify the same location, this duplication impacts the time required + to linearly scan the table, which is done in a number of places. So we + just do one linear scan here and toss out the duplicates. + + Note that we are not concerned here about recovering the space that + is potentially freed up, because the strings themselves are allocated + on the symbol_obstack, and will get automatically freed when the symbol + table is freed. The caller can free up the unused minimal symbols at + the end of the compacted region if their allocation strategy allows it. + + Also note we only go up to the next to last entry within the loop + and then copy the last entry explicitly after the loop terminates. + + Since the different sources of information for each symbol may + have different levels of "completeness", we may have duplicates + that have one entry with type "mst_unknown" and the other with a + known type. So if the one we are leaving alone has type mst_unknown, + overwrite its type with the type from the one we are compacting out. */ + +static int +compact_minimal_symbols (msymbol, mcount) + struct minimal_symbol *msymbol; + int mcount; +{ + struct minimal_symbol *copyfrom; + struct minimal_symbol *copyto; + + if (mcount > 0) + { + copyfrom = copyto = msymbol; + while (copyfrom < msymbol + mcount - 1) + { + if (SYMBOL_VALUE_ADDRESS (copyfrom) == + SYMBOL_VALUE_ADDRESS ((copyfrom + 1)) && + (STREQ (SYMBOL_NAME (copyfrom), SYMBOL_NAME ((copyfrom + 1))))) + { + if (MSYMBOL_TYPE((copyfrom + 1)) == mst_unknown) + { + MSYMBOL_TYPE ((copyfrom + 1)) = MSYMBOL_TYPE (copyfrom); + } + copyfrom++; + } + else + { + *copyto++ = *copyfrom++; + } + } + *copyto++ = *copyfrom++; + mcount = copyto - msymbol; + } + return (mcount); +} + +/* Add the minimal symbols in the existing bunches to the objfile's official + minimal symbol table. In most cases there is no minimal symbol table yet + for this objfile, and the existing bunches are used to create one. Once + in a while (for shared libraries for example), we add symbols (e.g. common + symbols) to an existing objfile. + + Because of the way minimal symbols are collected, we generally have no way + of knowing what source language applies to any particular minimal symbol. + Specifically, we have no way of knowing if the minimal symbol comes from a + C++ compilation unit or not. So for the sake of supporting cached + demangled C++ names, we have no choice but to try and demangle each new one + that comes in. If the demangling succeeds, then we assume it is a C++ + symbol and set the symbol's language and demangled name fields + appropriately. Note that in order to avoid unnecessary demanglings, and + allocating obstack space that subsequently can't be freed for the demangled + names, we mark all newly added symbols with language_auto. After + compaction of the minimal symbols, we go back and scan the entire minimal + symbol table looking for these new symbols. For each new symbol we attempt + to demangle it, and if successful, record it as a language_cplus symbol + and cache the demangled form on the symbol obstack. Symbols which don't + demangle are marked as language_unknown symbols, which inhibits future + attempts to demangle them if we later add more minimal symbols. */ + +void +install_minimal_symbols (objfile) + struct objfile *objfile; +{ + register int bindex; + register int mcount; + register struct msym_bunch *bunch; + register struct minimal_symbol *msymbols; + int alloc_count; + register char leading_char; + + if (msym_count > 0) + { + /* 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, + we will give back the excess space. */ + + alloc_count = msym_count + objfile->minimal_symbol_count + 1; + obstack_blank (&objfile->symbol_obstack, + alloc_count * sizeof (struct minimal_symbol)); + msymbols = (struct minimal_symbol *) + obstack_base (&objfile->symbol_obstack); + + /* Copy in the existing minimal symbols, if there are any. */ + + if (objfile->minimal_symbol_count) + memcpy ((char *)msymbols, (char *)objfile->msymbols, + objfile->minimal_symbol_count * sizeof (struct minimal_symbol)); + + /* Walk through the list of minimal symbol bunches, adding each symbol + to the new contiguous array of symbols. Note that we start with the + current, possibly partially filled bunch (thus we use the current + msym_bunch_index for the first bunch we copy over), and thereafter + each bunch is full. */ + + mcount = objfile->minimal_symbol_count; + leading_char = get_symbol_leading_char (objfile->obfd); + + for (bunch = msym_bunch; bunch != NULL; bunch = bunch -> next) + { + for (bindex = 0; bindex < msym_bunch_index; bindex++, mcount++) + { + msymbols[mcount] = bunch -> contents[bindex]; + SYMBOL_LANGUAGE (&msymbols[mcount]) = language_auto; + if (SYMBOL_NAME (&msymbols[mcount])[0] == leading_char) + { + SYMBOL_NAME(&msymbols[mcount])++; + } + } + msym_bunch_index = BUNCH_SIZE; + } + + /* Sort the minimal symbols by address. */ + + qsort (msymbols, mcount, sizeof (struct minimal_symbol), + compare_minimal_symbols); + + /* Compact out any duplicates, and free up whatever space we are + no longer using. */ + + mcount = compact_minimal_symbols (msymbols, mcount); + + obstack_blank (&objfile->symbol_obstack, + (mcount + 1 - alloc_count) * sizeof (struct minimal_symbol)); + msymbols = (struct minimal_symbol *) + obstack_finish (&objfile->symbol_obstack); + + /* We also terminate the minimal symbol table with a "null symbol", + which is *not* included in the size of the table. This makes it + easier to find the end of the table when we are handed a pointer + to some symbol in the middle of it. Zero out the fields in the + "null symbol" allocated at the end of the array. Note that the + symbol count does *not* include this null symbol, which is why it + is indexed by mcount and not mcount-1. */ + + SYMBOL_NAME (&msymbols[mcount]) = NULL; + SYMBOL_VALUE_ADDRESS (&msymbols[mcount]) = 0; + MSYMBOL_INFO (&msymbols[mcount]) = NULL; + MSYMBOL_TYPE (&msymbols[mcount]) = mst_unknown; + SYMBOL_INIT_LANGUAGE_SPECIFIC (&msymbols[mcount], language_unknown); + + /* Attach the minimal symbol table to the specified objfile. + The strings themselves are also located in the symbol_obstack + of this objfile. */ + + objfile -> minimal_symbol_count = mcount; + objfile -> msymbols = msymbols; + + /* Now walk through all the minimal symbols, selecting the newly added + ones and attempting to cache their C++ demangled names. */ + + for ( ; mcount-- > 0 ; msymbols++) + { + SYMBOL_INIT_DEMANGLED_NAME (msymbols, &objfile->symbol_obstack); + } + } +} + +/* Sort all the minimal symbols in OBJFILE. */ + +void +msymbols_sort (objfile) + struct objfile *objfile; +{ + qsort (objfile->msymbols, objfile->minimal_symbol_count, + sizeof (struct minimal_symbol), compare_minimal_symbols); +} + +/* Check if PC is in a shared library trampoline code stub. + Return minimal symbol for the trampoline entry or NULL if PC is not + in a trampoline code stub. */ + +struct minimal_symbol * +lookup_solib_trampoline_symbol_by_pc (pc) + CORE_ADDR pc; +{ + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); + + if (msymbol != NULL && MSYMBOL_TYPE (msymbol) == mst_solib_trampoline) + return msymbol; + return NULL; +} + +/* If PC is in a shared library trampoline code stub, return the + address of the `real' function belonging to the stub. + Return 0 if PC is not in a trampoline code stub or if the real + function is not found in the minimal symbol table. + + We may fail to find the right function if a function with the + same name is defined in more than one shared library, but this + is considered bad programming style. We could return 0 if we find + a duplicate function in case this matters someday. */ + +CORE_ADDR +find_solib_trampoline_target (pc) + CORE_ADDR pc; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *tsymbol = lookup_solib_trampoline_symbol_by_pc (pc); + + if (tsymbol != NULL) + { + ALL_MSYMBOLS (objfile, msymbol) + { + if (MSYMBOL_TYPE (msymbol) == mst_text + && STREQ (SYMBOL_NAME (msymbol), SYMBOL_NAME (tsymbol))) + return SYMBOL_VALUE_ADDRESS (msymbol); + } + } + return 0; +} + diff --git a/contrib/gdb/gdb/mipsread.c b/contrib/gdb/gdb/mipsread.c new file mode 100644 index 000000000000..e02e4b1bdfbc --- /dev/null +++ b/contrib/gdb/gdb/mipsread.c @@ -0,0 +1,477 @@ +/* Read a symbol table in MIPS' format (Third-Eye). + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + 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. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Read symbols from an ECOFF file. Most of the work is done in + mdebugread.c. */ + +#include "defs.h" +#include "gdb_string.h" +#include "bfd.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "gdb-stabs.h" + +#include "coff/sym.h" +#include "coff/internal.h" +#include "coff/ecoff.h" +#include "libcoff.h" /* Private BFD COFF information. */ +#include "libecoff.h" /* Private BFD ECOFF information. */ +#include "elf/common.h" +#include "elf/mips.h" + +static void +mipscoff_new_init PARAMS ((struct objfile *)); + +static void +mipscoff_symfile_init PARAMS ((struct objfile *)); + +static void +mipscoff_symfile_read PARAMS ((struct objfile *, struct section_offsets *, + int)); + +static void +mipscoff_symfile_finish PARAMS ((struct objfile *)); + +static struct section_offsets * +mipscoff_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +read_alphacoff_dynamic_symtab PARAMS ((struct section_offsets *, + struct objfile *objfile)); + +/* 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). */ + +extern CORE_ADDR sigtramp_address; + +static void +mipscoff_new_init (ignore) + struct objfile *ignore; +{ + sigtramp_address = 0; + stabsread_new_init (); + buildsym_new_init (); +} + +/* Initialize to read a symbol file (nothing to do). */ + +static void +mipscoff_symfile_init (objfile) + struct objfile *objfile; +{ +} + +/* Read a symbol file from a file. */ + +static void +mipscoff_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile->obfd; + struct cleanup * back_to; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + if (!((*ecoff_backend (abfd)->debug_swap.read_debug_info) + (abfd, (asection *) NULL, &ecoff_data (abfd)->debug_info))) + error ("Error reading symbol table: %s", bfd_errmsg (bfd_get_error ())); + + mdebug_build_psymtabs (objfile, &ecoff_backend (abfd)->debug_swap, + &ecoff_data (abfd)->debug_info, section_offsets); + + /* Add alpha coff dynamic symbols. */ + + read_alphacoff_dynamic_symtab (section_offsets, objfile); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + /* If the entry_file bounds are still unknown after processing the + partial symbols, then try to set them from the minimal symbols + surrounding the entry_point. */ + + if (mainline + && objfile->ei.entry_point != INVALID_ENTRY_POINT + && objfile->ei.entry_file_lowpc == INVALID_ENTRY_LOWPC) + { + struct minimal_symbol *m; + + m = lookup_minimal_symbol_by_pc (objfile->ei.entry_point); + if (m && SYMBOL_NAME (m + 1)) + { + objfile->ei.entry_file_lowpc = SYMBOL_VALUE_ADDRESS (m); + objfile->ei.entry_file_highpc = SYMBOL_VALUE_ADDRESS (m + 1); + } + } + + do_cleanups (back_to); +} + +/* Perform any local cleanups required when we are done with a + particular objfile. */ + +static void +mipscoff_symfile_finish (objfile) + struct objfile *objfile; +{ +} + +/* Fake up identical offsets for all sections. */ + +static struct section_offsets * +mipscoff_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = ((struct section_offsets *) + obstack_alloc (&objfile->psymbol_obstack, + (sizeof (struct section_offsets) + + (sizeof (section_offsets->offsets) + * (SECT_OFF_MAX - 1))))); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +/* Alpha OSF/1 encapsulates the dynamic symbols in ELF format in a + standard coff section. The ELF format for the symbols differs from + the format defined in elf/external.h. It seems that a normal ELF 32 bit + format is used, and the representation only changes because longs are + 64 bit on the alpha. In addition, the handling of text/data section + indices for symbols is different from the ELF ABI. + As the BFD linker currently does not support dynamic linking on the alpha, + there seems to be no reason to pollute BFD with another mixture of object + file formats for now. */ + +/* Format of an alpha external ELF symbol. */ + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_pad[4]; /* Pad to long word boundary */ + unsigned char st_value[8]; /* Value of the symbol */ + unsigned char st_size[4]; /* Associated symbol size */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ +} Elfalpha_External_Sym; + +/* Format of an alpha external ELF dynamic info structure. */ + +typedef struct { + unsigned char d_tag[4]; /* Tag */ + unsigned char d_pad[4]; /* Pad to long word boundary */ + union { + unsigned char d_ptr[8]; /* Pointer value */ + unsigned char d_val[4]; /* Integer value */ + } d_un; +} Elfalpha_External_Dyn; + +/* Struct to obtain the section pointers for alpha dynamic symbol info. */ + +struct alphacoff_dynsecinfo { + asection *sym_sect; /* Section pointer for .dynsym section */ + asection *str_sect; /* Section pointer for .dynstr section */ + asection *dyninfo_sect; /* Section pointer for .dynamic section */ + asection *got_sect; /* Section pointer for .got section */ +}; + +static void +alphacoff_locate_sections PARAMS ((bfd *, asection *, void *)); + +/* We are called once per section from read_alphacoff_dynamic_symtab. + We need to examine each section we are passed, check to see + if it is something we are interested in processing, and + if so, stash away some access information for the section. */ + +static void +alphacoff_locate_sections (ignore_abfd, sectp, sip) + bfd *ignore_abfd; + asection *sectp; + PTR sip; +{ + register struct alphacoff_dynsecinfo *si; + + si = (struct alphacoff_dynsecinfo *) sip; + + if (STREQ (sectp->name, ".dynsym")) + { + si->sym_sect = sectp; + } + else if (STREQ (sectp->name, ".dynstr")) + { + si->str_sect = sectp; + } + else if (STREQ (sectp->name, ".dynamic")) + { + si->dyninfo_sect = sectp; + } + else if (STREQ (sectp->name, ".got")) + { + si->got_sect = sectp; + } +} + +/* Scan an alpha dynamic symbol table for symbols of interest and + add them to the minimal symbol table. */ + +static void +read_alphacoff_dynamic_symtab (section_offsets, objfile) + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + bfd *abfd = objfile->obfd; + struct alphacoff_dynsecinfo si; + char *sym_secptr; + char *str_secptr; + char *dyninfo_secptr; + char *got_secptr; + bfd_size_type sym_secsize; + bfd_size_type str_secsize; + bfd_size_type dyninfo_secsize; + bfd_size_type got_secsize; + int sym_count; + int i; + int stripped; + Elfalpha_External_Sym *x_symp; + char *dyninfo_p; + char *dyninfo_end; + int got_entry_size = 8; + int dt_mips_local_gotno = -1; + int dt_mips_gotsym = -1; + + + /* We currently only know how to handle alpha dynamic symbols. */ + if (bfd_get_arch (abfd) != bfd_arch_alpha) + return; + + /* Locate the dynamic symbols sections and read them in. */ + memset ((char *) &si, 0, sizeof (si)); + bfd_map_over_sections (abfd, alphacoff_locate_sections, (PTR) &si); + if (si.sym_sect == NULL + || si.str_sect == NULL + || si.dyninfo_sect == NULL + || si.got_sect == NULL) + return; + + sym_secsize = bfd_get_section_size_before_reloc (si.sym_sect); + str_secsize = bfd_get_section_size_before_reloc (si.str_sect); + dyninfo_secsize = bfd_get_section_size_before_reloc (si.dyninfo_sect); + got_secsize = bfd_get_section_size_before_reloc (si.got_sect); + sym_secptr = alloca (sym_secsize); + str_secptr = alloca (str_secsize); + dyninfo_secptr = alloca (dyninfo_secsize); + got_secptr = alloca (got_secsize); + + if (!bfd_get_section_contents (abfd, si.sym_sect, sym_secptr, + (file_ptr)0, sym_secsize)) + return; + if (!bfd_get_section_contents (abfd, si.str_sect, str_secptr, + (file_ptr)0, str_secsize)) + return; + if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_secptr, + (file_ptr)0, dyninfo_secsize)) + return; + if (!bfd_get_section_contents (abfd, si.got_sect, got_secptr, + (file_ptr)0, got_secsize)) + return; + + /* Find the number of local GOT entries and the index for the + the first dynamic symbol in the GOT. */ + for (dyninfo_p = dyninfo_secptr, dyninfo_end = dyninfo_p + dyninfo_secsize; + dyninfo_p < dyninfo_end; + dyninfo_p += sizeof (Elfalpha_External_Dyn)) + { + Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *)dyninfo_p; + long dyn_tag; + + dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag); + if (dyn_tag == DT_NULL) + break; + else if (dyn_tag == DT_MIPS_LOCAL_GOTNO) + { + if (dt_mips_local_gotno < 0) + dt_mips_local_gotno + = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); + } + else if (dyn_tag == DT_MIPS_GOTSYM) + { + if (dt_mips_gotsym < 0) + dt_mips_gotsym + = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val); + } + } + if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0) + return; + + /* Scan all dynamic symbols and enter them into the minimal symbol table + if appropriate. */ + sym_count = sym_secsize / sizeof (Elfalpha_External_Sym); + stripped = (bfd_get_symcount (abfd) == 0); + + /* Skip first symbol, which is a null dummy. */ + for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_secptr + 1; + i < sym_count; + i++, x_symp++) + { + unsigned long strx; + char *name; + bfd_vma sym_value; + unsigned char sym_info; + unsigned int sym_shndx; + int isglobal; + enum minimal_symbol_type ms_type; + + strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name); + if (strx >= str_secsize) + continue; + name = str_secptr + strx; + if (*name == '\0' || *name == '.') + continue; + + sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value); + sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info); + sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx); + isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL); + + if (sym_shndx == SHN_UNDEF) + { + /* Handle undefined functions which are defined in a shared + library. */ + if (ELF_ST_TYPE (sym_info) != STT_FUNC + || ELF_ST_BIND (sym_info) != STB_GLOBAL) + continue; + + ms_type = mst_solib_trampoline; + + /* If sym_value is nonzero, it points to the shared library + trampoline entry, which is what we are looking for. + + If sym_value is zero, then we have to get the GOT entry + for the symbol. + If the GOT entry is nonzero, it represents the quickstart + address of the function and we use that as the symbol value. + + If the GOT entry is zero, the function address has to be resolved + by the runtime loader before the executable is started. + We are unable to find any meaningful address for these + functions in the executable file, so we skip them. */ + if (sym_value == 0) + { + int got_entry_offset = + (i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size; + + if (got_entry_offset < 0 || got_entry_offset >= got_secsize) + continue; + sym_value = + bfd_h_get_64 (abfd, + (bfd_byte *) (got_secptr + got_entry_offset)); + if (sym_value == 0) + continue; + } + } + else + { + /* Symbols defined in the executable itself. We only care about + them if this is a stripped executable, otherwise they have + been retrieved from the normal symbol table already. */ + if (!stripped) + continue; + + if (sym_shndx == SHN_MIPS_TEXT) + { + if (isglobal) + ms_type = mst_text; + else + ms_type = mst_file_text; + sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + } + else if (sym_shndx == SHN_MIPS_DATA) + { + if (isglobal) + ms_type = mst_data; + else + ms_type = mst_file_data; + sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA); + } + else if (sym_shndx == SHN_MIPS_ACOMMON) + { + if (isglobal) + ms_type = mst_bss; + else + ms_type = mst_file_bss; + sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS); + } + else if (sym_shndx == SHN_ABS) + { + ms_type = mst_abs; + } + else + { + continue; + } + } + + prim_record_minimal_symbol (obsavestring (name, + strlen (name), + &objfile -> symbol_obstack), + sym_value, + ms_type, + objfile); + } +} + +/* Initialization */ + +static struct sym_fns ecoff_sym_fns = +{ + bfd_target_ecoff_flavour, + mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */ + mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */ + mipscoff_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_mipsread () +{ + add_symtab_fns (&ecoff_sym_fns); +} diff --git a/contrib/gdb/gdb/mon960-rom.c b/contrib/gdb/gdb/mon960-rom.c new file mode 100644 index 000000000000..5a79923a18fa --- /dev/null +++ b/contrib/gdb/gdb/mon960-rom.c @@ -0,0 +1,270 @@ +/* Remote target glue for the Intel 960 ROM monitor. + Copyright 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" +#include "srec.h" +#include "xmodem.h" + +#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) +#define HAVE_SGTTY +#endif + +#ifdef HAVE_SGTTY +#include +#endif + +#include /* Needed by file.h on Sys V */ +#include +#include +#include + +#define USE_GENERIC_LOAD + +int quiet = 0; /* 1 => stifle unnecessary messages */ +serial_t mon960_serial; +char *mon960_ttyname; /* name of tty to talk to mon960 on, or null */ +static struct monitor_ops mon960_cmds; + +#ifdef USE_GENERIC_LOAD +extern void generic_load PARAMS ((char* filename, int from_tty)); +#endif +static void mon960_open PARAMS ((char *args, int from_tty)); + +#ifdef USE_GENERIC_LOAD +static void +mon960_load_gen (filename, from_tty) + char *filename; + int from_tty; +{ + extern int inferior_pid; + generic_load (filename, from_tty); + /* Finally, make the PC point at the start address */ + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_pid = 0; /* No process now */ +} + +#else +static void +mon960_load (desc, file, hashmark) + serial_t desc; + char *file; + int hashmark; +{ + bfd *abfd; + asection *s; + char *buffer; + int i; + + buffer = alloca (XMODEM_PACKETSIZE); + abfd = bfd_openr (file, 0); + if (!abfd) + { + printf_filtered ("Unable to open file %s\n", file); + return; + } + if (bfd_check_format (abfd, bfd_object) == 0) + { + printf_filtered ("File is not an object file\n"); + return; + } + for (s = abfd->sections; s; s = s->next) + if (s->flags & SEC_LOAD) + { + bfd_size_type section_size; + printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, + s->vma + s->_raw_size); + gdb_flush (gdb_stdout); + monitor_printf (mon960_cmds.load, s->vma); + if (mon960_cmds.loadresp) + monitor_expect (mon960_cmds.loadresp, NULL, 0); + xmodem_init_xfer (desc); + section_size = bfd_section_size (abfd, s); + for (i = 0; i < section_size; i += XMODEM_DATASIZE) + { + int numbytes; + numbytes = min (XMODEM_DATASIZE, section_size - i); + bfd_get_section_contents (abfd, s, buffer + XMODEM_DATAOFFSET, i, + numbytes); + xmodem_send_packet (desc, buffer, numbytes, hashmark); + if (hashmark) + { + putchar_unfiltered ('#'); + gdb_flush (gdb_stdout); + } + } /* Per-packet (or S-record) loop */ + xmodem_finish_xfer (desc); + monitor_expect_prompt (NULL, 0); + putchar_unfiltered ('\n'); + } /* Loadable sections */ + if (hashmark) + putchar_unfiltered ('\n'); +} +#endif + +/* This array of registers need to match the indexes used by GDB. + This exists because the various ROM monitors use different strings + than does GDB, and don't necessarily support all the registers + either. So, typing "info reg sp" becomes a "r30". */ + +/* these correspond to the offsets from tm-* files from config directories */ +/* g0-g14, fp, pfp, sp, rip,r3-15, pc, ac, tc, fp0-3 */ +/* NOTE: "ip" is documented as "ir" in the Mon960 UG. */ +/* NOTE: "ir" can't be accessed... but there's an ip and rip. */ +static char *mon960_regnames[NUM_REGS] = { + /* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7", \ + /* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",\ + /* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \ + /* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp", \ + /* 32 */ "pc", "ac", "tc", "ip", "fp0", "fp1", "fp2", "fp3",\ + }; + +/* Define the monitor command strings. Since these are passed directly + through to a printf style function, we may include formatting + strings. We also need a CR or LF on the end. */ + +static struct target_ops mon960_ops; + +/* need to pause the monitor for timing reasons, so slow it down */ +static char *mon960_inits[] = {"\n\r\r\r\r\r\r\r\r\r\r\r\r\r\r\n\r\n\r\n", NULL}; /* Exits sub-command mode & download cmds */ + +static struct monitor_ops mon960_cmds = +{ + MO_CLR_BREAK_USES_ADDR + | MO_NO_ECHO_ON_OPEN + | MO_SEND_BREAK_ON_STOP + | MO_GETMEM_READ_SINGLE, /* flags */ + mon960_inits, /* Init strings */ + "go\n\r", /* continue command */ + "st\n\r", /* single step */ + "\n\r", /* break interrupts the program */ + NULL, /* set a breakpoint */ + /* can't use "br" because only 2 hw bps are supported */ + NULL, /* clear a breakpoint - "de" is for hw bps */ + NULL, /* clear all breakpoints */ + NULL, /* fill (start end val) */ + /* can't use "fi" because it takes words, not bytes */ + { + /* can't use "mb", "md" or "mo" because they require interaction */ + NULL, /* setmem.cmdb (addr, value) */ + "md %x %x\n\r", /* setmem.cmdw (addr, value) */ + NULL, /* setmem.cmdl (addr, value) */ + NULL, /* setmem.cmdll (addr, value) */ + NULL, /* setmem.resp_delim */ + NULL, /* setmem.term */ + NULL, /* setmem.term_cmd */ + }, + { + /* since the parsing of multiple bytes is difficult due to + interspersed addresses, we'll only read 1 value at a time, + even tho these can handle a count */ + "db %x\n\r", /* getmem.cmdb (addr, #bytes) */ + "ds %x\n\r", /* getmem.cmdw (addr, #swords) */ + "di %x\n\r", /* getmem.cmdl (addr, #words) */ + "dd %x\n\r", /* getmem.cmdll (addr, #dwords) */ + " : ", /* getmem.resp_delim */ + NULL, /* getmem.term */ + NULL, /* getmem.term_cmd */ + }, + { + "md %s %x\n\r", /* setreg.cmd (name, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL /* setreg.term_cmd */ + }, + { + "di %s\n\r", /* getreg.cmd (name) */ + " : ", /* getreg.resp_delim */ + NULL, /* getreg.term */ + NULL, /* getreg.term_cmd */ + }, + "re\n\r", /* dump_registers */ + "\\(\\w+\\)=\\([0-9a-fA-F]+\\)", /* register_pattern */ + NULL, /* supply_register */ +#ifdef USE_GENERIC_LOAD + NULL, /* load_routine (defaults to SRECs) */ + NULL, /* download command */ + NULL, /* load response */ +#else + mon960_load, /* load_routine (defaults to SRECs) */ + "do\n\r", /* download command */ + "Downloading\n\r", /* load response */ +#endif + "=>", /* monitor command prompt */ + "\n\r", /* end-of-command delimitor */ + NULL, /* optional command terminator */ + &mon960_ops, /* target operations */ + SERIAL_1_STOPBITS, /* number of stop bits */ + mon960_regnames, /* registers names */ + MONITOR_OPS_MAGIC /* magic */ +}; + +/* invoked from monitor.c - opens the serial port */ +static void +mon960_open (args, from_tty) + char *args; + int from_tty; +{ + char *serial_port_name = args; + if (args) + { + char *cursor = serial_port_name = strsave (args); + + while (*cursor && *cursor != ' ') + cursor++; + + if (*cursor) + *cursor++ = 0; + + while (*cursor == ' ') + cursor++; + + } + monitor_open (serial_port_name, &mon960_cmds, from_tty); +} + + +void +_initialize_mon960 () +{ + init_monitor_ops (&mon960_ops); + + mon960_ops.to_shortname = "mon960"; /* for the target command */ + mon960_ops.to_longname = "Intel 960 rom monitor"; +#ifdef USE_GENERIC_LOAD + mon960_ops.to_load = mon960_load_gen; /* FIXME - should go back and try "do" */ +#endif + /* use SW breaks; target only supports 2 HW breakpoints */ + mon960_ops.to_insert_breakpoint = memory_insert_breakpoint; + mon960_ops.to_remove_breakpoint = memory_remove_breakpoint; + + mon960_ops.to_doc = + "Debug on an Intel 960 eval board running the Mon960 rom monitor.\n" + "Specify the serial device it is connected to (e.g. /dev/ttya)."; + + mon960_ops.to_open = mon960_open; + add_target (&mon960_ops); +} + diff --git a/contrib/gdb/gdb/monitor.c b/contrib/gdb/gdb/monitor.c new file mode 100644 index 000000000000..db8913c8c344 --- /dev/null +++ b/contrib/gdb/gdb/monitor.c @@ -0,0 +1,1541 @@ +/* Remote debugging interface for boot monitors, for GDB. + Copyright 1990, 1991, 1992, 1993, 1995, 1996 + Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Rob Savoye for Cygnus. + Resurrected from the ashes by Stu Grossman. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file was derived from various remote-* modules. It is a collection + of generic support functions so GDB can talk directly to a ROM based + monitor. This saves use from having to hack an exception based handler + into existance, and makes for quick porting. + + This module talks to a debug monitor called 'MONITOR', which + We communicate with MONITOR via either a direct serial line, or a TCP + (or possibly TELNET) stream to a terminal multiplexor, + which in turn talks to the target board. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "wait.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include +#include "gdb_string.h" +#include +#include "command.h" +#include "serial.h" +#include "monitor.h" +#include "gdbcmd.h" +#include "inferior.h" +#include "gnu-regex.h" +#include "dcache.h" +#include "srec.h" + +static int readchar PARAMS ((int timeout)); + +static void monitor_command PARAMS ((char *args, int fromtty)); + +static void monitor_fetch_register PARAMS ((int regno)); +static void monitor_store_register PARAMS ((int regno)); + +static void monitor_detach PARAMS ((char *args, int from_tty)); +static void monitor_resume PARAMS ((int pid, int step, enum target_signal sig)); +static void monitor_interrupt PARAMS ((int signo)); +static void monitor_interrupt_twice PARAMS ((int signo)); +static void monitor_interrupt_query PARAMS ((void)); +static void monitor_wait_cleanup PARAMS ((int old_timeout)); + +static int monitor_wait PARAMS ((int pid, struct target_waitstatus *status)); +static void monitor_fetch_registers PARAMS ((int regno)); +static void monitor_store_registers PARAMS ((int regno)); +static void monitor_prepare_to_store PARAMS ((void)); +static int monitor_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len, int write, struct target_ops *target)); +static void monitor_files_info PARAMS ((struct target_ops *ops)); +static int monitor_insert_breakpoint PARAMS ((CORE_ADDR addr, char *shadow)); +static int monitor_remove_breakpoint PARAMS ((CORE_ADDR addr, char *shadow)); +static void monitor_kill PARAMS ((void)); +static void monitor_load PARAMS ((char *file, int from_tty)); +static void monitor_mourn_inferior PARAMS ((void)); +static void monitor_stop PARAMS ((void)); +static void monitor_debug PARAMS ((char *prefix, char *string, char *suffix)); + +static int monitor_read_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len)); +static int monitor_write_memory PARAMS ((CORE_ADDR addr, char *myaddr,int len)); + +static int monitor_expect_regexp PARAMS ((struct re_pattern_buffer *pat, + char *buf, int buflen)); +static int from_hex PARAMS ((int a)); +static unsigned long get_hex_word PARAMS ((void)); + +static struct monitor_ops *current_monitor; + +static int hashmark; /* flag set by "set hash" */ + +static int timeout = 30; + +static int in_monitor_wait = 0; /* Non-zero means we are in monitor_wait() */ + +static void (*ofunc)(); /* Old SIGINT signal handler */ + +/* Descriptor for I/O to remote machine. Initialize it to NULL so + that monitor_open knows that we don't have a file open when the + program starts. */ + +static serial_t monitor_desc = NULL; + +/* Pointer to regexp pattern matching data */ + +static struct re_pattern_buffer register_pattern; +static char register_fastmap[256]; + +static struct re_pattern_buffer getmem_resp_delim_pattern; +static char getmem_resp_delim_fastmap[256]; + +static int dump_reg_flag; /* Non-zero means do a dump_registers cmd when + monitor_wait wakes up. */ + +static DCACHE *remote_dcache; + +/* monitor_debug is like fputs_unfiltered, except it prints special + characters in printable fashion. */ + +static void +monitor_debug (prefix, string, suffix) + char *prefix; + char *string; + char *suffix; +{ + int ch; + + /* print prefix and suffix after each line */ + static int new_line=1; + if (new_line==1) { /* print prefix if last char was a newline */ + fputs_unfiltered (prefix, gdb_stderr); + new_line=0; + } + if (strchr(string,'\n')) /* save state for next call */ + new_line=1; + + while ((ch = *string++) != '\0') + { + switch (ch) { + default: + if (isprint (ch)) + fputc_unfiltered (ch, gdb_stderr); + + else + fprintf_unfiltered (gdb_stderr, "\\%03o", ch); + + break; + + case '\\': fputs_unfiltered ("\\\\", gdb_stderr); break; + case '\b': fputs_unfiltered ("\\b", gdb_stderr); break; + case '\f': fputs_unfiltered ("\\f", gdb_stderr); break; + case '\n': fputs_unfiltered ("\\n", gdb_stderr); break; + case '\r': fputs_unfiltered ("\\r", gdb_stderr); break; + case '\t': fputs_unfiltered ("\\t", gdb_stderr); break; + case '\v': fputs_unfiltered ("\\v", gdb_stderr); break; + } + } + + if (new_line==1) { /* print suffix if last char was a newline */ + fputs_unfiltered (suffix, gdb_stderr); + fputs_unfiltered ("\n", gdb_stderr); + } +} + +/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo. + Works just like printf. */ + +void +#ifdef ANSI_PROTOTYPES +monitor_printf_noecho (char *pattern, ...) +#else +monitor_printf_noecho (va_alist) + va_dcl +#endif +{ + va_list args; + char sndbuf[2000]; + int len; + +#if ANSI_PROTOTYPES + va_start (args, pattern); +#else + char *pattern; + va_start (args); + pattern = va_arg (args, char *); +#endif + + vsprintf (sndbuf, pattern, args); + + if (remote_debug > 0) + monitor_debug ("sent -->", sndbuf, "<--"); + + len = strlen (sndbuf); + + if (len + 1 > sizeof sndbuf) + abort (); + + if (SERIAL_WRITE(monitor_desc, sndbuf, len)) + fprintf_unfiltered (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno)); +} + +/* monitor_printf -- Send data to monitor and check the echo. Works just like + printf. */ + +void +#ifdef ANSI_PROTOTYPES +monitor_printf (char *pattern, ...) +#else +monitor_printf (va_alist) + va_dcl +#endif +{ + va_list args; + char sndbuf[2000]; + int len; + +#ifdef ANSI_PROTOTYPES + va_start (args, pattern); +#else + char *pattern; + va_start (args); + pattern = va_arg (args, char *); +#endif + + vsprintf (sndbuf, pattern, args); + + if (remote_debug > 0) + monitor_debug ("sent -->", sndbuf, "<--"); + + len = strlen (sndbuf); + + if (len + 1 > sizeof sndbuf) + abort (); + + if (SERIAL_WRITE(monitor_desc, sndbuf, len)) + fprintf_unfiltered (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno)); + + /* We used to expect that the next immediate output was the characters we + just output, but sometimes some extra junk appeared before the characters + we expected, like an extra prompt, or a portmaster sending telnet negotiations. + So, just start searching for what we sent, and skip anything unknown. */ + monitor_expect (sndbuf, (char *)0, 0); +} + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ + +static int +readchar (timeout) + int timeout; +{ + int c; + static enum { last_random, last_nl, last_cr, last_crnl } state = last_random; + int looping; + + do + { + looping = 0; + c = SERIAL_READCHAR (monitor_desc, timeout); + + if (c >= 0) + { + c &= 0x7f; + if (remote_debug > 0) + { + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + monitor_debug ("read -->", buf, "<--"); + } + } + + /* Canonicialize \n\r combinations into one \r */ + if ((current_monitor->flags & MO_HANDLE_NL) != 0) + { + if ((c == '\r' && state == last_nl) + || (c == '\n' && state == last_cr)) + { + state = last_crnl; + looping = 1; + } + else if (c == '\r') + state = last_cr; + else if (c != '\n') + state = last_random; + else + { + state = last_nl; + c = '\r'; + } + } + } + while (looping); + + if (c >= 0) + return c; + + if (c == SERIAL_TIMEOUT) +#ifdef MAINTENANCE_CMDS + if (in_monitor_wait) /* Watchdog went off */ + { + target_mourn_inferior (); + error ("Watchdog has expired. Target detached.\n"); + } + else +#endif + error ("Timeout reading from remote system."); + + perror_with_name ("remote-monitor"); +} + +/* Scan input from the remote system, until STRING is found. If BUF is non- + zero, then collect input until we have collected either STRING or BUFLEN-1 + chars. In either case we terminate BUF with a 0. If input overflows BUF + because STRING can't be found, return -1, else return number of chars in BUF + (minus the terminating NUL). Note that in the non-overflow case, STRING + will be at the end of BUF. */ + +int +monitor_expect (string, buf, buflen) + char *string; + char *buf; + int buflen; +{ + char *p = string; + int obuflen = buflen; + int c; + + immediate_quit = 1; + while (1) + { + if (buf) + { + if (buflen < 2) + { + *buf = '\000'; + immediate_quit = 0; + return -1; + } + + c = readchar (timeout); + if (c == '\000') + continue; + *buf++ = c; + buflen--; + } + else + c = readchar (timeout); + + /* Don't expect any ^C sent to be echoed */ + + if (*p == '\003' || c == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + + if (buf) + { + *buf++ = '\000'; + return obuflen - buflen; + } + else + return 0; + } + } + else + { + p = string; + if (c == *p) + p++; + } + } +} + +/* Search for a regexp. */ + +static int +monitor_expect_regexp (pat, buf, buflen) + struct re_pattern_buffer *pat; + char *buf; + int buflen; +{ + char *mybuf; + char *p; + + if (buf) + mybuf = buf; + else + { + mybuf = alloca (1024); + buflen = 1024; + } + + p = mybuf; + while (1) + { + int retval; + + if (p - mybuf >= buflen) + { /* Buffer about to overflow */ + +/* On overflow, we copy the upper half of the buffer to the lower half. Not + great, but it usually works... */ + + memcpy (mybuf, mybuf + buflen / 2, buflen / 2); + p = mybuf + buflen / 2; + } + + *p++ = readchar (timeout); + + retval = re_search (pat, mybuf, p - mybuf, 0, p - mybuf, NULL); + if (retval >= 0) + return 1; + } +} + +/* Keep discarding input until we see the MONITOR prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an monitor_expect_prompt(). Exception: monitor_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a monitor_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ + +int +monitor_expect_prompt (buf, buflen) + char *buf; + int buflen; +{ + return monitor_expect (PROMPT, buf, buflen); +} + +/* Get N 32-bit words from remote, each preceded by a space, and put + them in registers starting at REGNO. */ + +static unsigned long +get_hex_word () +{ + unsigned long val; + int i; + int ch; + + do + ch = readchar (timeout); + while (isspace(ch)); + + val = from_hex (ch); + + for (i = 7; i >= 1; i--) + { + ch = readchar (timeout); + if (!isxdigit (ch)) + break; + val = (val << 4) | from_hex (ch); + } + + return val; +} + +static void +compile_pattern (pattern, compiled_pattern, fastmap) + char *pattern; + struct re_pattern_buffer *compiled_pattern; + char *fastmap; +{ + int tmp; + char *val; + + compiled_pattern->fastmap = fastmap; + + tmp = re_set_syntax (RE_SYNTAX_EMACS); + val = re_compile_pattern (pattern, + strlen (pattern), + compiled_pattern); + re_set_syntax (tmp); + + if (val) + error ("compile_pattern: Can't compile pattern string `%s': %s!", pattern, val); + + if (fastmap) + re_compile_fastmap (compiled_pattern); +} + +/* Open a connection to a remote debugger. NAME is the filename used + for communication. */ + +static char *dev_name; +static struct target_ops *targ_ops; + +void +monitor_open (args, mon_ops, from_tty) + char *args; + struct monitor_ops *mon_ops; + int from_tty; +{ + char *name; + int i; + char **p; + + if (mon_ops->magic != MONITOR_OPS_MAGIC) + error ("Magic number of monitor_ops struct wrong."); + + targ_ops = mon_ops->target; + name = targ_ops->to_shortname; + + if (!args) + error ("Use `target %s DEVICE-NAME' to use a serial port, or \n\ +`target %s HOST-NAME:PORT-NUMBER' to use a network connection.", name, name); + + target_preopen (from_tty); + + /* Setup pattern for register dump */ + + if (mon_ops->register_pattern) + compile_pattern (mon_ops->register_pattern, ®ister_pattern, + register_fastmap); + + if (mon_ops->getmem.resp_delim) + compile_pattern (mon_ops->getmem.resp_delim, &getmem_resp_delim_pattern, + getmem_resp_delim_fastmap); + + unpush_target (targ_ops); + + if (dev_name) + free (dev_name); + dev_name = strsave (args); + + monitor_desc = SERIAL_OPEN (dev_name); + + if (!monitor_desc) + perror_with_name (dev_name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (monitor_desc, baud_rate)) + { + SERIAL_CLOSE (monitor_desc); + perror_with_name (dev_name); + } + } + + SERIAL_RAW (monitor_desc); + + SERIAL_FLUSH_INPUT (monitor_desc); + + /* some systems only work with 2 stop bits */ + + SERIAL_SETSTOPBITS (monitor_desc, mon_ops->stopbits); + + current_monitor = mon_ops; + + /* See if we can wake up the monitor. First, try sending a stop sequence, + then send the init strings. Last, remove all breakpoints. */ + + if (current_monitor->stop) + { + monitor_stop (); + if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0) + { + monitor_expect_prompt (NULL, 0); + } + } + + /* wake up the monitor and see if it's alive */ + for (p = mon_ops->init; *p != NULL; p++) + { + /* Some of the characters we send may not be echoed, + but we hope to get a prompt at the end of it all. */ + + if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0) + monitor_printf(*p); + else + monitor_printf_noecho (*p); + monitor_expect_prompt (NULL, 0); + } + + SERIAL_FLUSH_INPUT (monitor_desc); + + /* Remove all breakpoints */ + + if (mon_ops->clr_all_break) + { + monitor_printf (mon_ops->clr_all_break); + monitor_expect_prompt (NULL, 0); + } + + if (from_tty) + printf_unfiltered ("Remote target %s connected to %s\n", name, dev_name); + + push_target (targ_ops); + + inferior_pid = 42000; /* Make run command think we are busy... */ + + /* Give monitor_wait something to read */ + + monitor_printf (current_monitor->line_term); + + remote_dcache = dcache_init (monitor_read_memory, monitor_write_memory); + + start_remote (); +} + +/* Close out all files and local state before this target loses + control. */ + +void +monitor_close (quitting) + int quitting; +{ + if (monitor_desc) + SERIAL_CLOSE (monitor_desc); + monitor_desc = NULL; +} + +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ + +static void +monitor_detach (args, from_tty) + char *args; + int from_tty; +{ + pop_target (); /* calls monitor_close to do the real work */ + if (from_tty) + printf_unfiltered ("Ending remote %s debugging\n", target_shortname); +} + +/* Convert VALSTR into the target byte-ordered value of REGNO and store it. */ + +char * +monitor_supply_register (regno, valstr) + int regno; + char *valstr; +{ + unsigned LONGEST val; + unsigned char regbuf[MAX_REGISTER_RAW_SIZE]; + char *p; + + val = strtoul (valstr, &p, 16); + + if (val == 0 && valstr == p) + error ("monitor_supply_register (%d): bad value from monitor: %s.", + regno, valstr); + + /* supply register stores in target byte order, so swap here */ + + store_unsigned_integer (regbuf, REGISTER_RAW_SIZE (regno), val); + + supply_register (regno, regbuf); + + return p; +} + +/* Tell the remote machine to resume. */ + +static void +monitor_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + dcache_flush (remote_dcache); + if (step) + monitor_printf (STEP_CMD); + else + { + monitor_printf (CONT_CMD); + if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT) + dump_reg_flag = 1; + } +} + +/* Parse the output of a register dump command. A monitor specific + regexp is used to extract individual register descriptions of the + form REG=VAL. Each description is split up into a name and a value + string which are passed down to monitor specific code. */ + +static char * +parse_register_dump (buf, len) + char *buf; + int len; +{ + while (1) + { + int regnamelen, vallen; + char *regname, *val; + /* Element 0 points to start of register name, and element 1 + points to the start of the register value. */ + struct re_registers register_strings; + + if (re_search (®ister_pattern, buf, len, 0, len, + ®ister_strings) == -1) + break; + + regnamelen = register_strings.end[1] - register_strings.start[1]; + regname = buf + register_strings.start[1]; + vallen = register_strings.end[2] - register_strings.start[2]; + val = buf + register_strings.start[2]; + + current_monitor->supply_register (regname, regnamelen, val, vallen); + + buf += register_strings.end[0]; + len -= register_strings.end[0]; + } +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +monitor_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, monitor_interrupt_twice); + + if (remote_debug) + printf_unfiltered ("monitor_interrupt called\n"); + + target_stop (); +} + +/* The user typed ^C twice. */ + +static void +monitor_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + monitor_interrupt_query (); + + signal (signo, monitor_interrupt); +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +monitor_interrupt_query () +{ + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); +} + +static void +monitor_wait_cleanup (old_timeout) + int old_timeout; +{ + timeout = old_timeout; + signal (SIGINT, ofunc); + in_monitor_wait = 0; +} + +/* Wait until the remote machine stops, then return, storing status in + status just as `wait' would. */ + +static int +monitor_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int old_timeout = timeout; + char buf[1024]; + int resp_len; + struct cleanup *old_chain; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + old_chain = make_cleanup (monitor_wait_cleanup, old_timeout); + +#ifdef MAINTENANCE_CMDS + in_monitor_wait = 1; + timeout = watchdog > 0 ? watchdog : -1; +#else + timeout = -1; /* Don't time out -- user program is running. */ +#endif + + ofunc = (void (*)()) signal (SIGINT, monitor_interrupt); + + do + { + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + + if (resp_len <= 0) + fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf); + } + while (resp_len < 0); + + signal (SIGINT, ofunc); + + timeout = old_timeout; + + if (dump_reg_flag && current_monitor->dump_registers) + { + dump_reg_flag = 0; + + monitor_printf (current_monitor->dump_registers); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + } + + if (current_monitor->register_pattern) + parse_register_dump (buf, resp_len); + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + + discard_cleanups (old_chain); + + in_monitor_wait = 0; + + return inferior_pid; +} + +/* Fetch register REGNO, or all registers if REGNO is -1. Returns + errno value. */ + +static void +monitor_fetch_register (regno) + int regno; +{ + char *name; + static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0}; + char regbuf[MAX_REGISTER_RAW_SIZE * 2 + 1]; + int i; + + name = REGNAMES (regno); + + if (!name) + { + supply_register (regno, zerobuf); + return; + } + + /* send the register examine command */ + + monitor_printf (current_monitor->getreg.cmd, name); + + /* If RESP_DELIM is specified, we search for that as a leading + delimiter for the register value. Otherwise, we just start + searching from the start of the buf. */ + + if (current_monitor->getreg.resp_delim) + monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); + + /* Read upto the maximum number of hex digits for this register, skipping + spaces, but stop reading if something else is seen. Some monitors + like to drop leading zeros. */ + + for (i = 0; i < REGISTER_RAW_SIZE (regno) * 2; i++) + { + int c; + c = readchar (timeout); + while (c == ' ') + c = readchar (timeout); + + if (!isxdigit (c)) + break; + + regbuf[i] = c; + } + + regbuf[i] = '\000'; /* terminate the number */ + + /* If TERM is present, we wait for that to show up. Also, (if TERM + is present), we will send TERM_CMD if that is present. In any + case, we collect all of the output into buf, and then wait for + the normal prompt. */ + + if (current_monitor->getreg.term) + { + monitor_expect (current_monitor->getreg.term, NULL, 0); /* get response */ + + if (current_monitor->getreg.term_cmd) + { + monitor_printf (current_monitor->getreg.term_cmd); + monitor_expect_prompt (NULL, 0); + } + } + else + monitor_expect_prompt (NULL, 0); /* get response */ + + monitor_supply_register (regno, regbuf); +} + +/* Read the remote registers into the block regs. */ + +static void monitor_dump_regs () +{ + if (current_monitor->dump_registers) + { + char buf[200]; + int resp_len; + + monitor_printf (current_monitor->dump_registers); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + parse_register_dump (buf, resp_len); + } + else + abort(); /* Need some way to read registers */ +} + +static void +monitor_fetch_registers (regno) + int regno; +{ + if (current_monitor->getreg.cmd) + { + if (regno >= 0) + { + monitor_fetch_register (regno); + return; + } + + for (regno = 0; regno < NUM_REGS; regno++) + monitor_fetch_register (regno); + } + else { + monitor_dump_regs (); + } +} + +/* Store register REGNO, or all if REGNO == 0. Return errno value. */ + +static void +monitor_store_register (regno) + int regno; +{ + char *name; + unsigned LONGEST val; + + name = REGNAMES (regno); + if (!name) + return; + + val = read_register (regno); + + /* send the register deposit command */ + + monitor_printf (current_monitor->setreg.cmd, name, val); + +/* It's possible that there are actually some monitors out there that + will prompt you when you set a register. In that case, you may + need to add some code here to deal with TERM and TERM_CMD (see + monitor_fetch_register to get an idea of what's needed...) */ + + monitor_expect_prompt (NULL, 0); +} + +/* Store the remote registers. */ + +static void +monitor_store_registers (regno) + int regno; +{ + if (regno >= 0) + { + monitor_store_register (regno); + return; + } + + for (regno = 0; regno < NUM_REGS; regno++) + monitor_store_register (regno); +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +monitor_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static void +monitor_files_info (ops) + struct target_ops *ops; +{ + printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baud_rate); +} + +static int +monitor_write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + unsigned LONGEST val; + char *cmd; + int i; + + /* Use memory fill command for leading 0 bytes. */ + + if (current_monitor->fill) + { + for (i = 0; i < len; i++) + if (myaddr[i] != 0) + break; + + if (i > 4) /* More than 4 zeros is worth doing */ + { + if (current_monitor->flags & MO_FILL_USES_ADDR) + monitor_printf (current_monitor->fill, memaddr, memaddr + i, 0); + else + monitor_printf (current_monitor->fill, memaddr, i, 0); + + monitor_expect_prompt (NULL, 0); + + return i; + } + } + + if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->setmem.cmdll) + { + len = 8; + cmd = current_monitor->setmem.cmdll; + } + else if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->setmem.cmdl) + { + len = 4; + cmd = current_monitor->setmem.cmdl; + } + else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->setmem.cmdw) + { + len = 2; + cmd = current_monitor->setmem.cmdw; + } + else + { + len = 1; + cmd = current_monitor->setmem.cmdb; + } + + val = extract_unsigned_integer (myaddr, len); + + monitor_printf (cmd, memaddr, val); + + monitor_expect_prompt (NULL, 0); + + return len; +} + +/* This is an alternate form of monitor_read_memory which is used for monitors + which can only read a single byte/word/etc. at a time. */ + +static int +monitor_read_memory_single (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + unsigned LONGEST val; + char membuf[sizeof(LONGEST) * 2 + 1]; + char *p; + char *cmd; + int i; + + if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->getmem.cmdll) + { + len = 8; + cmd = current_monitor->getmem.cmdll; + } + else if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->getmem.cmdl) + { + len = 4; + cmd = current_monitor->getmem.cmdl; + } + else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->getmem.cmdw) + { + len = 2; + cmd = current_monitor->getmem.cmdw; + } + else + { + len = 1; + cmd = current_monitor->getmem.cmdb; + } + +/* Send the examine command. */ + + monitor_printf (cmd, memaddr); + +/* If RESP_DELIM is specified, we search for that as a leading delimiter for + the register value. Otherwise, we just start searching from the start of + the buf. */ + + if (current_monitor->getmem.resp_delim) + monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0); + +/* Now, read the appropriate number of hex digits for this loc, skipping + spaces. */ + + for (i = 0; i < len * 2; i++) + { + int c; + + while (1) + { + c = readchar (timeout); + if (isxdigit (c)) + break; + if (c == ' ') + continue; + + error ("monitor_read_memory_single (0x%x): bad response from monitor: %.*s%c.", + memaddr, i, membuf, c); + } + + membuf[i] = c; + } + + membuf[i] = '\000'; /* terminate the number */ + +/* If TERM is present, we wait for that to show up. Also, (if TERM is + present), we will send TERM_CMD if that is present. In any case, we collect + all of the output into buf, and then wait for the normal prompt. */ + + if (current_monitor->getmem.term) + { + monitor_expect (current_monitor->getmem.term, NULL, 0); /* get response */ + + if (current_monitor->getmem.term_cmd) + { + monitor_printf (current_monitor->getmem.term_cmd); + monitor_expect_prompt (NULL, 0); + } + } + else + monitor_expect_prompt (NULL, 0); /* get response */ + + p = membuf; + val = strtoul (membuf, &p, 16); + + if (val == 0 && membuf == p) + error ("monitor_read_memory_single (0x%x): bad value from monitor: %s.", + memaddr, membuf); + + /* supply register stores in target byte order, so swap here */ + + store_unsigned_integer (myaddr, len, val); + + return len; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory + at MEMADDR. Returns length moved. Currently, we only do one byte at a + time. */ + +static int +monitor_read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + unsigned LONGEST val; + unsigned char regbuf[MAX_REGISTER_RAW_SIZE]; + char buf[512]; + char *p, *p1; + char *name; + int resp_len; + int i; + + if (current_monitor->flags & MO_GETMEM_READ_SINGLE) + return monitor_read_memory_single (memaddr, myaddr, len); + + len = min (len, 16); + +/* See if xfer would cross a 16 byte boundary. If so, clip it. */ + if (((memaddr ^ (memaddr + len - 1)) & ~0xf) != 0) + len = ((memaddr + len) & ~0xf) - memaddr; + + /* send the memory examine command */ + + if (current_monitor->flags & MO_GETMEM_NEEDS_RANGE) + monitor_printf (current_monitor->getmem.cmdb, memaddr, memaddr + len - 1); + else + monitor_printf (current_monitor->getmem.cmdb, memaddr, len); + +/* If TERM is present, we wait for that to show up. Also, (if TERM is + present), we will send TERM_CMD if that is present. In any case, we collect + all of the output into buf, and then wait for the normal prompt. */ + + if (current_monitor->getmem.term) + { + resp_len = monitor_expect (current_monitor->getmem.term, buf, sizeof buf); /* get response */ + + if (resp_len <= 0) + error ("monitor_read_memory (0x%x): excessive response from monitor: %.*s.", + memaddr, resp_len, buf); + + if (current_monitor->getmem.term_cmd) + { + SERIAL_WRITE (monitor_desc, current_monitor->getmem.term_cmd, + strlen (current_monitor->getmem.term_cmd)); + monitor_expect_prompt (NULL, 0); + } + } + else + resp_len = monitor_expect_prompt (buf, sizeof buf); /* get response */ + + p = buf; + + /* If RESP_DELIM is specified, we search for that as a leading delimiter for + the values. Otherwise, we just start searching from the start of the buf. + */ + + if (current_monitor->getmem.resp_delim) + { + int retval, tmp; + struct re_registers resp_strings; + + tmp = strlen (p); + retval = re_search (&getmem_resp_delim_pattern, p, tmp, 0, tmp, + &resp_strings); + + if (retval < 0) + error ("monitor_read_memory (0x%x): bad response from monitor: %.*s.", + memaddr, resp_len, buf); + + p += resp_strings.end[0]; +#if 0 + p = strstr (p, current_monitor->getmem.resp_delim); + if (!p) + error ("monitor_read_memory (0x%x): bad response from monitor: %.*s.", + memaddr, resp_len, buf); + p += strlen (current_monitor->getmem.resp_delim); +#endif + } + + for (i = len; i > 0; i--) + { + /* Skip non-hex chars, but bomb on end of string and newlines */ + + while (1) + { + if (isxdigit (*p)) + break; + if (*p == '\000' || *p == '\n' || *p == '\r') + error ("monitor_read_memory (0x%x): badly terminated response from monitor: %.*s", memaddr, resp_len, buf); + p++; + } + + val = strtoul (p, &p1, 16); + + if (val == 0 && p == p1) + error ("monitor_read_memory (0x%x): bad value from monitor: %.*s.", memaddr, + resp_len, buf); + + *myaddr++ = val; + + if (i == 1) + break; + + p = p1; + } + + return len; +} + +static int +monitor_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, write); +} + +static void +monitor_kill () +{ + return; /* ignore attempts to kill target system */ +} + +/* All we actually do is set the PC to the start address of exec_bfd, and start + the program at that point. */ + +static void +monitor_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + if (args && (*args != '\000')) + error ("Args are not supported by the monitor."); + + clear_proceed_status (); + proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0); +} + +/* Clean up when a program exits. + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +static void +monitor_mourn_inferior () +{ + unpush_target (targ_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +#define NUM_MONITOR_BREAKPOINTS 8 + +static CORE_ADDR breakaddr[NUM_MONITOR_BREAKPOINTS] = {0}; + +/* Tell the monitor to add a breakpoint. */ + +static int +monitor_insert_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + static unsigned char break_insn[] = BREAKPOINT; + + for (i = 0; i < NUM_MONITOR_BREAKPOINTS; i++) + { + if (breakaddr[i] == 0) + { + breakaddr[i] = addr; + monitor_read_memory (addr, shadow, sizeof (break_insn)); + monitor_printf (SET_BREAK_CMD, addr); + monitor_expect_prompt (NULL, 0); + return 0; + } + } + + error ("Too many breakpoints (> %d) for monitor.", NUM_MONITOR_BREAKPOINTS); +} + +/* Tell the monitor to remove a breakpoint. */ + +static int +monitor_remove_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + for (i = 0; i < NUM_MONITOR_BREAKPOINTS; i++) + { + if (breakaddr[i] == addr) + { + breakaddr[i] = 0; + /* some monitors remove breakpoints based on the address */ + if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR) + monitor_printf (CLR_BREAK_CMD, addr); + else + monitor_printf (CLR_BREAK_CMD, i); + monitor_expect_prompt (NULL, 0); + return 0; + } + } + fprintf_unfiltered (stderr, "Can't find breakpoint associated with 0x%x\n", addr); + return 1; +} + +/* monitor_load -- download a file. */ + +static void +monitor_load (file, from_tty) + char *file; + int from_tty; +{ + dcache_flush (remote_dcache); + + if (current_monitor->load_routine) + current_monitor->load_routine (monitor_desc, file, hashmark); + else + { /* The default is ascii S-records */ + monitor_printf (LOAD_CMD); /* tell the monitor to load */ + if (current_monitor->loadresp) + monitor_expect (current_monitor->loadresp, NULL, 0); + + load_srec (monitor_desc, file, 32, SREC_ALL, hashmark); + + monitor_expect_prompt (NULL, 0); + } + +/* Finally, make the PC point at the start address */ + + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_pid = 0; /* No process now */ + +/* This is necessary because many things were based on the PC at the time that + we attached to the monitor, which is no longer valid now that we have loaded + new code (and just changed the PC). Another way to do this might be to call + normal_stop, except that the stack may not be valid, and things would get + horribly confused... */ + + clear_symtab_users (); +} + +static void +monitor_stop () +{ + if ((current_monitor->flags & MO_SEND_BREAK_ON_STOP) != 0) + SERIAL_SEND_BREAK (monitor_desc); + if (current_monitor->stop) + monitor_printf_noecho (current_monitor->stop); +} + +/* Put a command string, in args, out to MONITOR. Output from MONITOR + is placed on the users terminal until the prompt is seen. FIXME: We + read the characters ourseleves here cause of a nasty echo. */ + +static void +monitor_command (args, from_tty) + char *args; + int from_tty; +{ + char *p; + int resp_len; + char buf[1000]; + + if (monitor_desc == NULL) + error ("monitor target not open."); + + p = PROMPT; + + /* Send the command. Note that if no args were supplied, then we're + just sending the monitor a newline, which is sometimes useful. */ + + monitor_printf ("%s\r", (args ? args : "")); + + resp_len = monitor_expect_prompt (buf, sizeof buf); + + fputs_unfiltered (buf, gdb_stdout); /* Output the response */ +} + +/* Convert hex digit A to a number. */ + +static int +from_hex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + + error ("Reply contains invalid hex digit 0x%x", a); +} + +static struct target_ops monitor_ops = +{ + NULL, /* to_shortname */ + NULL, /* to_longname */ + NULL, /* to_doc */ + NULL, /* to_open */ + monitor_close, /* to_close */ + NULL, /* to_attach */ + monitor_detach, /* to_detach */ + monitor_resume, /* to_resume */ + monitor_wait, /* to_wait */ + monitor_fetch_registers, /* to_fetch_registers */ + monitor_store_registers, /* to_store_registers */ + monitor_prepare_to_store, /* to_prepare_to_store */ + monitor_xfer_memory, /* to_xfer_memory */ + monitor_files_info, /* to_files_info */ + monitor_insert_breakpoint, /* to_insert_breakpoint */ + monitor_remove_breakpoint, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + monitor_kill, /* to_kill */ + monitor_load, /* to_load */ + 0, /* to_lookup_symbol */ + monitor_create_inferior, /* to_create_inferior */ + monitor_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + monitor_stop, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +/* Init the target_ops structure pointed at by OPS */ + +void +init_monitor_ops (ops) + struct target_ops *ops; +{ + memcpy (ops, &monitor_ops, sizeof monitor_ops); +} + +/* Define additional commands that are usually only used by monitors. */ + +void +_initialize_remote_monitors () +{ + add_show_from_set (add_set_cmd ("hash", no_class, var_boolean, + (char *)&hashmark, + "Set display of activity while downloading a file.\n\ +When enabled, a hashmark \'#\' is displayed.", + &setlist), + &showlist); + + add_com ("monitor", class_obscure, monitor_command, + "Send a command to the debug monitor."); +} diff --git a/contrib/gdb/gdb/monitor.h b/contrib/gdb/gdb/monitor.h new file mode 100644 index 000000000000..daad1caf8388 --- /dev/null +++ b/contrib/gdb/gdb/monitor.h @@ -0,0 +1,177 @@ +/* Remote debugging interface ROM monitors. + * Copyright 1990, 1991, 1992, 1996 Free Software Foundation, Inc. + * Contributed by Cygnus Support. Written by Rob Savoye for Cygnus. + * + * This file is part of GDB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "serial.h" + +/* This structure describes the strings necessary to give small command + sequences to the monitor, and parse the response. + + CMD is the actual command typed at the monitor. Usually this has embedded + sequences ala printf, which are substituted with the arguments appropriate + to that type of command. Ie: to examine a register, we substitute the + register name for the first arg. To modify memory, we substitute the memory + location and the new contents for the first and second args, etc... + + RESP_DELIM used to home in on the response string, and is used to + disambiguate the answer within the pile of text returned by the monitor. + This should be a unique string that immediately precedes the answer. Ie: if + your monitor prints out `PC: 00000001= ' in response to asking for the PC, + you should use `: ' as the RESP_DELIM. RESP_DELIM may be NULL if the res- + ponse is going to be ignored, or has no particular leading text. + + TERM is the string that the monitor outputs to indicate that it is idle, and + waiting for input. This is usually a prompt of some sort. In the previous + example, it would be `= '. It is important that TERM really means that the + monitor is idle, otherwise GDB may try to type at it when it isn't ready for + input. This is a problem because many monitors cannot deal with type-ahead. + TERM may be NULL if the normal prompt is output. + + TERM_CMD is used to quit out of the subcommand mode and get back to the main + prompt. TERM_CMD may be NULL if it isn't necessary. It will also be + ignored if TERM is NULL. +*/ + +struct memrw_cmd +{ + char *cmdb; /* Command to send for byte read/write */ + char *cmdw; /* Command for word (16 bit) read/write */ + char *cmdl; /* Command for long (32 bit) read/write */ + char *cmdll; /* Command for long long (64 bit) read/write */ + char *resp_delim; /* String just prior to the desired value */ + char *term; /* Terminating string to search for */ + char *term_cmd; /* String to get out of sub-mode (if necessary) */ +}; + +struct regrw_cmd +{ + char *cmd; /* Command to send for reg read/write */ + char *resp_delim; /* String (actually a regexp if getmem) just + prior to the desired value */ + char *term; /* Terminating string to search for */ + char *term_cmd; /* String to get out of sub-mode (if necessary) */ +}; + +struct monitor_ops +{ + int flags; /* See below */ + char **init; /* List of init commands. NULL terminated. */ + char *cont; /* continue command */ + char *step; /* single step */ + char *stop; /* Interrupt program string */ + char *set_break; /* set a breakpoint */ + char *clr_break; /* clear a breakpoint */ + char *clr_all_break; /* Clear all breakpoints */ + char *fill; /* Memory fill cmd (addr len val) */ + struct memrw_cmd setmem; /* set memory to a value */ + struct memrw_cmd getmem; /* display memory */ + struct regrw_cmd setreg; /* set a register */ + struct regrw_cmd getreg; /* get a register */ + /* Some commands can dump a bunch of registers + at once. This comes as a set of REG=VAL + pairs. This should be called for each pair + of registers that we can parse to supply + GDB with the value of a register. */ + char *dump_registers; /* Command to dump all regs at once */ + char *register_pattern; /* Pattern that picks out register from reg dump */ + void (*supply_register) PARAMS ((char *name, int namelen, char *val, int vallen)); + void (*load_routine) PARAMS ((serial_t desc, char *file, int hashmark)); /* Download routine */ + char *load; /* load command */ + char *loadresp; /* Response to load command */ + char *prompt; /* monitor command prompt */ + char *line_term; /* end-of-command delimitor */ + char *cmd_end; /* optional command terminator */ + struct target_ops *target; /* target operations */ + int stopbits; /* number of stop bits */ + char **regnames; /* array of register names in ascii */ + int magic; /* Check value */ +}; + +#define MONITOR_OPS_MAGIC 600925 + +/* Flag defintions */ + +#define MO_CLR_BREAK_USES_ADDR 0x1 /* If set, then clear breakpoint command + uses address, otherwise it uses an index + returned by the monitor. */ +#define MO_FILL_USES_ADDR 0x2 /* If set, then memory fill command uses + STARTADDR, ENDADDR+1, VALUE as args, else it + uses STARTADDR, LENGTH, VALUE as args. */ +#define MO_NEED_REGDUMP_AFTER_CONT 0x4 /* If set, then monitor doesn't auto- + matically supply register dump when + coming back after a continue. */ +#define MO_GETMEM_NEEDS_RANGE 0x8 /* getmem needs start addr and end addr */ +#define MO_GETMEM_READ_SINGLE 0x10 /* getmem can only read one loc at a time */ +#define MO_HANDLE_NL 0x20 /* handle \r\n combinations */ + +#define MO_NO_ECHO_ON_OPEN 0x40 /* don't expect echos in monitor_open */ + +#define MO_SEND_BREAK_ON_STOP 0x80 /* If set, send break to stop monitor */ + +extern struct monitor_ops *current_monitor; + +#define LOADTYPES (current_monitor->loadtypes) +#define LOADPROTOS (current_monitor->loadprotos) +#define INIT_CMD (current_monitor->init) +#define CONT_CMD (current_monitor->cont) +#define STEP_CMD (current_monitor->step) +#define SET_BREAK_CMD (current_monitor->set_break) +#define CLR_BREAK_CMD (current_monitor->clr_break) +#define SET_MEM (current_monitor->setmem) +#define GET_MEM (current_monitor->getmem) +#define LOAD_CMD (current_monitor->load) +#define GET_REG (current_monitor->regget) +#define SET_REG (current_monitor->regset) +#define CMD_END (current_monitor->cmd_end) +#define CMD_DELIM (current_monitor->cmd_delim) +#define PROMPT (current_monitor->prompt) +#define TARGET_OPS (current_monitor->target) +#define TARGET_NAME (current_monitor->target->to_shortname) +#define BAUDRATES (current_monitor->baudrates) +#define STOPBITS (current_monitor->stopbits) +#define REGNAMES(x) (current_monitor->regnames[x]) +#define ROMCMD(x) (x.cmd) +#define ROMDELIM(x) (x.delim) +#define ROMRES(x) (x.result) + +#define push_monitor(x) current_monitor = x; + +#define SREC_SIZE 160 + +/* + * FIXME: These are to temporarily maintain compatability with the + * old monitor structure till remote-mon.c is fixed to work + * like the *-rom.c files. + */ +#define MEM_PROMPT (current_monitor->loadtypes) +#define MEM_SET_CMD (current_monitor->setmem) +#define MEM_DIS_CMD (current_monitor->getmem) +#define REG_DELIM (current_monitor->regset.delim) + +extern void monitor_open PARAMS ((char *args, struct monitor_ops *ops, int from_tty)); +extern void monitor_close PARAMS ((int quitting)); +extern char *monitor_supply_register PARAMS ((int regno, char *valstr)); +extern int monitor_expect PARAMS ((char *prompt, char *buf, int buflen)); +extern int monitor_expect_prompt PARAMS ((char *buf, int buflen)); +extern void monitor_printf PARAMS ((char *, ...)) + ATTR_FORMAT(printf, 1, 2); +extern void monitor_printf_noecho PARAMS ((char *, ...)) + ATTR_FORMAT(printf, 1, 2); +extern void init_monitor_ops PARAMS ((struct target_ops *)); diff --git a/contrib/gdb/gdb/mpw-config.in b/contrib/gdb/gdb/mpw-config.in new file mode 100644 index 000000000000..47e71868f766 --- /dev/null +++ b/contrib/gdb/gdb/mpw-config.in @@ -0,0 +1,82 @@ +# Configuration fragment for GDB. + +If "{host_canonical}" =~ /m68k-apple-mpw/ + forward-include "{srcdir}"config:m68k:xm-mpw.h xm.h + Set siow_lib '"{Libraries}"SIOW.o' + +Else If "{host_canonical}" =~ /powerpc-apple-mpw/ + forward-include "{srcdir}"config:powerpc:xm-mpw.h xm.h + Set siow_lib '"{PPCLibraries}"PPCSIOW.o' + +End If + +Set xdepfiles '"{o}"mac-xdep.c.o' + +Set enable_cflags "" + +# Make a copy of this file and give it a different name, so it +# won't be confused with GDB's serial.h. + +Duplicate -y "{CIncludes}"Serial.h MacSerial.h + +Echo "/* dummy */" >termio.h + +If "{target_canonical}" =~ /m68k-apple-macos/ + forward-include "{srcdir}"config:m68k:tm-mac.h tm.h + forward-include "{srcdir}"config:m68k:tm-m68k.h 'm68k/tm-m68k.h' + Set tdepfiles '"{o}"m68k-tdep.c.o' + +Else If "{target_canonical}" =~ /powerpc-apple-macos/ + forward-include "{srcdir}"config:powerpc:tm-macos.h tm.h + forward-include "{srcdir}"config:rs6000:tm-rs6000.h 'rs6000/tm-rs6000.h' + Set tdepfiles '"{o}"rs6000-tdep.c.o "{o}"xcoffread.c.o' + +Else If "{target_canonical}" =~ /i386-unknown-go32/ + forward-include "{srcdir}"config:i386:tm-i386v.h tm.h + Set tdepfiles '"{o}"i386-tdep.c.o' + +Else If "{target_canonical}" =~ /mips-idt-ecoff/ + forward-include "{srcdir}"config:mips:tm-embed.h tm.h + forward-include "{srcdir}"config:mips:tm-bigmips.h 'mips/tm-bigmips.h' + forward-include "{srcdir}"config:mips:tm-mips.h 'mips/tm-mips.h' + Set tdepfiles '"{o}"mips-tdep.c.o "{o}"remote-mips.c.o' + + +Else If "{target_canonical}" =~ /sh-hitachi-hms/ + forward-include "{srcdir}"config:sh:tm-sh.h tm.h + Set tdepfiles '"{o}"sh-tdep.c.o' + +End If + +If "{target_canonical}" =~ /m68k-apple-macos/ + forward-include "{srcdir}"config:m68k:nm-macos.h nm.h + Set natdepfiles '"{o}"mac-nat.c.o' + +Else If "{target_canonical}" =~ /powerpc-apple-macos/ + forward-include "{srcdir}"config:powerpc:nm-macos.h nm.h + Set natdepfiles '"{o}"mac-nat.c.o' + +Else + forward-include "{srcdir}"config:nm-empty.h nm.h + Set natdepfiles ' ' + +End If + +Echo '# From mpw-config.in' > "{o}"mk.tmp +Echo "TDEPFILES = " {tdepfiles} >> "{o}"mk.tmp +Echo "XDEPFILES = " {xdepfiles} >> "{o}"mk.tmp +Echo "NATDEPFILES = " {natdepfiles} >> "{o}"mk.tmp +Echo "XM_ADD_FILES = " >> "{o}"mk.tmp +Echo "TM_ADD_FILES = " >> "{o}"mk.tmp +Echo "NAT_ADD_FILES = " >> "{o}"mk.tmp +Echo "XM_CDEPS = " >> "{o}"mk.tmp +Echo "TM_CDEPS = " >> "{o}"mk.tmp +Echo "NAT_CDEPS = " >> "{o}"mk.tmp +Echo "SIOW_LIB = " {siow_lib} >> "{o}"mk.tmp +Echo "ENABLE_CFLAGS = " {enable_cflags} >> "{o}"mk.tmp +Echo '# End from mpw-config.in' >> "{o}"mk.tmp + +Echo '/* config.h. Generated by mpw-configure. */' > "{o}"config.new +Echo '#include "mpw.h"' >> "{o}"config.new + +MoveIfChange "{o}"config.new "{o}"config.h diff --git a/contrib/gdb/gdb/mpw-make.sed b/contrib/gdb/gdb/mpw-make.sed new file mode 100644 index 000000000000..9cfaaa3aa9f3 --- /dev/null +++ b/contrib/gdb/gdb/mpw-make.sed @@ -0,0 +1,167 @@ +# Sed commands that finish translating the GDB Unix Makefile to MPW syntax. + +/^host_alias =/s/^/#/ +/^target_alias =/s/^/#/ + +/^host_makefile_frag@$/d +/^target_makefile_frag@$/d + +/@ENABLE_CFLAGS@/s/@ENABLE_CFLAGS@/{ENABLE_CFLAGS}/g +/^ENABLE_CFLAGS=/s/^/#/ + +# Edit all the symbolic definitions pointing to various libraries and such. + +/^INCLUDE_DIR = /s/"{srcdir}":include/"{topsrcdir}"include:/ + +/^MMALLOC_DIR = /s/::mmalloc/mmalloc:/ +/^MMALLOC_SRC = /s/"{srcdir}"/"{topsrcdir}"/ +/^MMALLOC =/s/=.*$/=/ +/#MMALLOC_DISABLE/s/^#// + +/^BFD_DIR = /s/::bfd/bfd:/ +/^BFD = /s/{BFD_DIR}:libbfd/{BFD_DIR}libbfd/ +/^BFD_SRC = /s/"{srcdir}"/"{topsrcdir}"/ + +/^READLINE_DIR = /s/::readline/readline:/ +/^READLINE =/s/=.*$/=/ +/^READLINE_SRC = /s/"{srcdir}"/"{topsrcdir}"/ + +/^INCLUDE_CFLAGS = /s/$/ -i "{topsrcdir}"include:mpw: -i ::extra-include:/ + +/^SER_HARDWIRE =/s/ser-unix/ser-mac/ + +/^TERMCAP =/s/ =.*$/ =/ + +/@DEFS@/s/@DEFS@//g + +/@YACC@/s/@YACC@/byacc/g + +/@ENABLE_OBS@/s/@ENABLE_OBS@//g + +/@ENABLE_CLIBS@/s/@ENABLE_CLIBS@//g + +/@LIBS@/s/@LIBS@//g + +/INCLUDE_DIR/s/"{s}"{INCLUDE_DIR}/{INCLUDE_DIR}/g +/INCLUDE_DIR/s/{INCLUDE_DIR}:/{INCLUDE_DIR}/g +/INCLUDE_DIR/s/"{INCLUDE_DIR}":/"{INCLUDE_DIR}"/g + +/{BFD_DIR}/s/"{BFD_DIR}":/"{BFD_DIR}"/g +/{BFD_DIR}/s/\([ ]\){BFD_DIR}/\1::{BFD_DIR}/g +/{BFD_DIR}/s/\([ ]\)"{BFD_DIR}"/\1::"{BFD_DIR}"/g + +/{BFD_SRC}/s/"{s}"{BFD_SRC}/{BFD_SRC}/g +/{BFD_SRC}/s/{BFD_SRC}:/{BFD_SRC}/g + +/{READLINE_SRC}/s/"{s}"{READLINE_SRC}/{READLINE_SRC}/g + +/^readline_headers =/,/^$/c\ +readline_headers =\ + + +/{MMALLOC_CHECK}/s/{MMALLOC_CHECK}//g + +# This isn't really useful, and seems to cause nonsensical complaints. +/{ALLDEPFILES}/s/{ALLDEPFILES}//g + +/^copying.c \\Option-f /,/^$/d + +# Fix the syntax of bits of C code that go into version.c. +/char /s/'char .Option-x/'char */ + +/version/s/"{s}"version\.c/"{o}"version.c/g +/version/s/^version\.c/"{o}"version.c/ +/config/s/"{s}"config\.h/"{o}"config.h/g +/config/s/^config\.h/"{o}"config.h/ +/xm/s/"{s}"xm\.h/"{o}"xm.h/g +/xm/s/^xm\.h/"{o}"xm.h/ +/tm/s/"{s}"tm\.h/"{o}"tm.h/g +/tm/s/^tm\.h/"{o}"tm.h/ +/nm/s/"{s}"nm\.h/"{o}"nm.h/g +/nm/s/^nm\.h/"{o}"nm.h/ + +/exp.tab.c/s/"{s}"\([a-z0-9]*\)-exp\.tab\.c/"{o}"\1-exp.tab.c/g +/exp.tab.c/s/^\([a-z0-9]*\)-exp\.tab\.c/"{o}"\1-exp.tab.c/ + +/y.tab/s/"{s}"y.tab\.c/"{o}"y.tab.c/g +/y.tab/s/^y.tab\.c/"{o}"y.tab.c/ + +/init/s/"{s}"init\.c-tmp/"{o}"init.c-tmp/g +/init/s/^init\.c-tmp/"{o}"init.c-tmp/ +/init/s/"{s}"init\.c/"{o}"init.c/g +/init/s/^init\.c/"{o}"init.c/ + +/"{o}"version.c \\Option-f Makefile/,/^$/c\ +"{o}"version.c \\Option-f Makefile\ + echo -n 'char *version = "' >"{o}"version.c\ + echo -n "{VERSION}" >>"{o}"version.c\ + echo '";' >>"{o}"version.c\ + echo -n 'char *host_name = "' >>"{o}"version.c\ + echo -n "{host_alias}" >>"{o}"version.c\ + echo '";' >>"{o}"version.c\ + echo -n 'char *target_name = "' >>"{o}"version.c\ + echo -n "{target_alias}" >>"{o}"version.c\ + echo '";' >>"{o}"version.c\ + + +# Open-brace in a command causes much confusion; replace with the +# result from a script. +/initialize_all_files ()/c\ + Echo -n 'void initialize_all_files () ' >> "{o}"init.c-tmp\ + open-brace >> "{o}"init.c-tmp + +# Replace the whole sed bit for init.c; it's simpler that way... +/filename=`echo $i | sed/,/esac/c\ + set filename "`Echo {i} | sed \\Option-d\ + -e '/^Onindy.c.o/d' \\Option-d\ + -e '/^nindy.c.o/d' \\Option-d\ + -e '/ttyflush.c.o/d' \\Option-d\ + -e '/xdr_ld.c.o/d' \\Option-d\ + -e '/xdr_ptrace.c.o/d' \\Option-d\ + -e '/xdr_rdb.c.o/d' \\Option-d\ + -e '/udr.c.o/d' \\Option-d\ + -e '/udip2soc.c.o/d' \\Option-d\ + -e '/udi2go32.c.o/d' \\Option-d\ + -e '/version.c.o/d' \\Option-d\ + -e '/[a-z0-9A-Z_]*-exp.tab.c.o/d' \\Option-d\ + -e 's/\\.c\\.o/.c/' \\Option-d\ + -e 's/^://'`"\ + If "{filename}" != ""\ + sed <"{s}""{filename}" >>"{o}"init.c-tmp -n \\Option-d\ + -e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\\([a-z_0-9A-Z]*\\).*/ {extern void \\1 (); \\1 ();}/p'\ + End If + +# Fix the main compile/link command. +/{CC_LD} {INTERNAL_LDFLAGS} -o gdb/,/"{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {LOADLIBES}/c\ + {CC_LD} {INTERNAL_LDFLAGS} -o gdb{PROG_EXT} "{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {LOADLIBES} {EXTRALIBS}\ + {MAKEPEF} gdb{PROG_EXT} -o gdb {MAKEPEF_TOOL_FLAGS} {MAKEPEF_FLAGS}\ + {REZ} "{s}"mac-gdb.r -o gdb -append -d PROG_NAME='"'gdb'"' -d VERSION_STRING='"'{version}'"'\ + +/^install \\Option-f /,/^$/c\ +install \\Option-f all install-only\ +\ +install-only \\Option-f \ + Duplicate -y gdb "{bindir}"gdb\ + If "`Exists SiowGDB`" != ""\ + Duplicate -y SiowGDB "{bindir}"SiowGDB\ + End If\ + + +# Don't do any recursive subdir stuff. +/ subdir_do/s/{MAKE}/null-command/ + +# Edit out actions that only confuse MPW Make. +/^config.status \\Option-f/,/^$/d +/^Makefile \\Option-f/,/^$/d + +/^"{o}"config.h \\Option-f/s/^/#/ + +# Add an action to build SIOWgdb. +$a\ +SIOWgdb \\Option-f {OBS} {TSOBS} {ADD_DEPS} {CDEPS} "{o}"init.c.o\ + Delete -i -y SIOWgdb\ + {CC_LD} {INTERNAL_LDFLAGS} -t 'APPL' -c 'gdb ' -o SIOWgdb{PROG_EXT} "{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {SIOW_LIB} {LOADLIBES} {EXTRALIBS}\ + {MAKEPEF} SIOWgdb{PROG_EXT} -o SIOWgdb -ft 'APPL' -fc 'gdb ' {MAKEPEF_FLAGS} \ + {REZ} -o SIOWgdb "{RIncludes}"siow.r -append -d __kPrefSize=5000 -d __kMinSize=2000 -d APPNAME='"'SIOWgdb'"' \ + {REZ} "{s}"mac-gdb.r -o SIOWgdb -append -d VERSION_STRING='"'{version}'"'\ + diff --git a/contrib/gdb/gdb/msg.defs b/contrib/gdb/gdb/msg.defs new file mode 100644 index 000000000000..7c9fcd15f541 --- /dev/null +++ b/contrib/gdb/gdb/msg.defs @@ -0,0 +1 @@ +#include diff --git a/contrib/gdb/gdb/msg_reply.defs b/contrib/gdb/gdb/msg_reply.defs new file mode 100644 index 000000000000..049bfa87cfaa --- /dev/null +++ b/contrib/gdb/gdb/msg_reply.defs @@ -0,0 +1 @@ +#include diff --git a/contrib/gdb/gdb/news-xdep.c b/contrib/gdb/gdb/news-xdep.c new file mode 100644 index 000000000000..7f57aeb1d46a --- /dev/null +++ b/contrib/gdb/gdb/news-xdep.c @@ -0,0 +1,65 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __GNUC__ +/* Bad implement execle(3). It's depend for "/bin/cc". + + main() + { + printf("execle:\n"); + execle(FILE, ARGS, envp); + exit(1); + } + + GCC: + link a6,#0 + pea LC5 ; call printf + jbsr _printf + ; ; (not popd stack) + pea _envp ; call execle + clrl sp@- + pea LC4 + pea LC4 + pea LC4 + pea LC3 + pea LC6 + jbsr _execle + addw #32,sp ; delayed pop !! + + /bin/cc: + link.l fp,#L23 + movem.l #L24,(sp) + pea L26 ; call printf + jbsr _printf + addq.l #4,sp ; <--- popd stack !! + pea _envp ; call execle + clr.l -(sp) + pea L32 + + */ + +execle(name, args) + char *name, *args; +{ + register char **env = &args; + while (*env++) + ; + execve(name, (char **)&args, (char **)*env); +} +#endif diff --git a/contrib/gdb/gdb/nindy-tdep.c b/contrib/gdb/gdb/nindy-tdep.c new file mode 100644 index 000000000000..76f04e4b5ea8 --- /dev/null +++ b/contrib/gdb/gdb/nindy-tdep.c @@ -0,0 +1,73 @@ +/* Target-machine dependent code for the NINDY monitor running on the Intel 960 + Copyright (C) 1991 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Miscellaneous NINDY-dependent routines. + Some replace macros normally defined in "tm.h". */ + +#include "defs.h" +#include "symtab.h" +#include "frame.h" + +/* 'start_frame' is a variable in the NINDY runtime startup routine + that contains the frame pointer of the 'start' routine (the routine + that calls 'main'). By reading its contents out of remote memory, + we can tell where the frame chain ends: backtraces should halt before + they display this frame. */ + +int +nindy_frame_chain_valid (chain, curframe) + unsigned int chain; + struct frame_info *curframe; +{ + struct symbol *sym; + struct minimal_symbol *msymbol; + + /* crtnindy.o is an assembler module that is assumed to be linked + * first in an i80960 executable. It contains the true entry point; + * it performs startup up initialization and then calls 'main'. + * + * 'sf' is the name of a variable in crtnindy.o that is set + * during startup to the address of the first frame. + * + * 'a' is the address of that variable in 80960 memory. + */ + static char sf[] = "start_frame"; + CORE_ADDR a; + + + chain &= ~0x3f; /* Zero low 6 bits because previous frame pointers + contain return status info in them. */ + if ( chain == 0 ){ + return 0; + } + + sym = lookup_symbol(sf, 0, VAR_NAMESPACE, (int *)NULL, + (struct symtab **)NULL); + if ( sym != 0 ){ + a = SYMBOL_VALUE (sym); + } else { + msymbol = lookup_minimal_symbol (sf, NULL, NULL); + if (msymbol == NULL) + return 0; + a = SYMBOL_VALUE_ADDRESS (msymbol); + } + + return ( chain != read_memory_integer(a,4) ); +} diff --git a/contrib/gdb/gdb/nlm/Makefile.in b/contrib/gdb/gdb/nlm/Makefile.in new file mode 100644 index 000000000000..c17bcffb258f --- /dev/null +++ b/contrib/gdb/gdb/nlm/Makefile.in @@ -0,0 +1,173 @@ +#Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(libdir)/$(target_alias) + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC_FOR_TARGET = ` \ + if [ -f ../../gcc/xgcc ] ; then \ + echo ../../gcc/xgcc -B../../gcc/; \ + else \ + t='$(program_transform_name)'; echo gcc | sed -e '' $$t; \ + fi` + +NLMCONV_FOR_TARGET = ` \ + if [ -f ../../binutils/nlmconv ] ; then \ + echo ../../binutils/nlmconv; \ + else \ + t='$(program_transform_name)'; echo nlmconv | sed -e '' $$t; \ + fi` + +# All the includes used for CFLAGS and for lint. +INCLUDE_CFLAGS = -I. -I${srcdir} + +# CFLAGS is specifically reserved for setting from the command line +# when running make. I.E. "make CFLAGS=-Wmissing-prototypes". +CFLAGS = -g +# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros. +INTERNAL_CFLAGS = ${CFLAGS} ${INCLUDE_CFLAGS} ${USER_CFLAGS} +LDFLAGS = $(CFLAGS) + +# Perhaps should come from parent Makefile +VERSION = gdbserve-4.12 +DIST=gdb + +# target-dependent makefile fragment come in here. +@target_makefile_frag@ +# End target-dependent makefile fragment + +# All source files that go into linking GDB remote server. + +DEPFILES = $(GDBSERVE_DEPFILES) + +SOURCES = $(ALLDEPFILES) +TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} + +# Prevent Sun make from putting in the machine type. Setting +# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1. +.c.o: + ${CC_FOR_TARGET} -c ${INTERNAL_CFLAGS} $< + +.S.o: + ${CC_FOR_TARGET} -c ${INTERNAL_CFLAGS} $< + +all: gdbserve.nlm + +# Traditionally "install" depends on "all". But it may be useful +# not to; for example, if the user has made some trivial change to a +# source file and doesn't care about rebuilding or just wants to save the +# time it takes for make to check that all is up to date. +# install-only is intended to address that need. +install: all install-only +install-only: + $(INSTALL) gdbserve.nlm $(bindir)/gdbserve.nlm + +uninstall: force + rm -f $(bindir)/gdbserve.nlm + +installcheck: +check: +info dvi: +install-info: +clean-info: + +gdbserve.nlm: gdbserve.O $(srcdir)/gdbserve.def + ${NLMCONV_FOR_TARGET} -T $(srcdir)/gdbserve.def + +gdbserve.O: prelude.o gdbserve.o $(TDEPFILES) + ${CC_FOR_TARGET} $(LDFLAGS) -r -o gdbserve.O prelude.o gdbserve.o ${TDEPFILES} + +# Put the proper machine-specific files first, so M-. on a machine +# specific routine gets the one for the correct machine. +# The xyzzy stuff below deals with empty DEPFILES +TAGS: ${TAGFILES} + etags `find ${srcdir}/../config -name $(TM_FILE) -print` \ + `find ${srcdir}/../config -name ${XM_FILE} -print` \ + `find ${srcdir}/../config -name ${NAT_FILE} -print` \ + `for i in yzzy ${DEPFILES}; do \ + if [ x$$i != xyzzy ]; then \ + echo ${srcdir}/$$i | sed -e 's/\.o$$/\.c/' ; \ + fi; \ + done` \ + ${TAGFILES} +tags: TAGS + +clean: + rm -f *.o ${ADD_FILES} *~ + rm -f gdbserve.O gdbserve.nlm core make.log + +distclean: clean TAGS + rm -f config.log config.cache config.status + rm -f Makefile + +maintainer-clean realclean: clean + rm -f TAGS + rm -f config.log config.cache config.status + rm -f Makefile + +Makefile: Makefile.in config.status @target_makefile_frag_path@ + $(SHELL) config.status + +config.status: configure + $(SHELL) config.status --recheck + +force: + +# GNU Make has an annoying habit of putting *all* the Makefile variables +# into the environment, unless you include this target as a circumvention. +# Rumor is that this will be fixed (and this target can be removed) +# in GNU Make 4.0. +.NOEXPORT: + +# GNU Make 3.63 has a different problem: it keeps tacking command line +# overrides onto the definition of $(MAKE). This variable setting +# will remove them. +MAKEOVERRIDES= + +# This is the end of "Makefile.in". diff --git a/contrib/gdb/gdb/nlm/configure b/contrib/gdb/gdb/nlm/configure new file mode 100644 index 000000000000..0b62dc122dbb --- /dev/null +++ b/contrib/gdb/gdb/nlm/configure @@ -0,0 +1,864 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.3 +# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE + +# Initialize some other variables. +subdirs= + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -build | --build | --buil | --bui | --bu | --b) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=PREFIX install architecture-dependent files in PREFIX + [same as prefix] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +--enable and --with options recognized:$ac_help +EOF + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.3" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=gdbserve.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5' + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`$ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`$ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. + echo 's,\\,\\\\,g; s,\$,$$,g' > conftestsed + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_ifs" + # As a last resort, use the slow shell script. + test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" +fi + INSTALL="$ac_cv_path_install" +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. +case "${target_cpu}" in +alpha) gdb_target_cpu=alpha ;; +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[345]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +np1) gdb_target_cpu=gould ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; +esac + +target_makefile_frag=${srcdir}/../config/${gdb_target_cpu}/gdbserve.mt +if ! -f ${target_makefile_frag} ; then + { echo "configure: error: "*** GDBSERVE does not support target ${target}"" 1>&2; exit 1; } +fi + +target_makefile_frag_path=$target_makefile_frag + + + +cpufile=`sed -n ' +s/CPU_FILE *= *\(^ *\)/\1/p +' ${target_makefile_frag} + +files= +links= +rm -f cpu.h +if "${cpufile}" != "" ; then + files="${files} ${cpufile}.h" + links="${links} cpu.h" +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ + >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.3" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@target_makefile_frag_path@%$target_makefile_frag_path%g +/@target_makefile_frag@/r $target_makefile_frag +s%@target_makefile_frag@%%g + +CEOF +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust relative srcdir, etc. for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file +fi; done +rm -f conftest.subs + +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +srcdir=$ac_given_srcdir +while test -n "$ac_sources"; do + set $ac_dests; ac_dest=$1; shift; ac_dests=$* + set $ac_sources; ac_source=$1; shift; ac_sources=$* + + echo "linking $srcdir/$ac_source to $ac_dest" + + if test ! -r $srcdir/$ac_source; then + { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; } + fi + rm -f $ac_dest + + # Make relative symlinks. + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'` + if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then + # The dest file is in a subdirectory. + test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir" + ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dest_dir_suffix. + ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dest_dir_suffix= ac_dots= + fi + + case "$srcdir" in + [/$]*) ac_rel_source="$srcdir/$ac_source" ;; + *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;; + esac + + # Make a symlink if possible; otherwise try a hard link. + if ln -s $ac_rel_source $ac_dest 2>/dev/null || + ln $srcdir/$ac_source $ac_dest; then : + else + { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; } + fi +done + + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + diff --git a/contrib/gdb/gdb/nlm/configure.in b/contrib/gdb/gdb/nlm/configure.in new file mode 100644 index 000000000000..f70be82e40b2 --- /dev/null +++ b/contrib/gdb/gdb/nlm/configure.in @@ -0,0 +1,55 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.3)dnl +AC_INIT(gdbserve.c) + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +AC_PROG_INSTALL + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. +changequote(,)dnl +case "${target_cpu}" in +alpha) gdb_target_cpu=alpha ;; +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[345]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +np1) gdb_target_cpu=gould ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; +esac +changequote([,])dnl + +target_makefile_frag=${srcdir}/../config/${gdb_target_cpu}/gdbserve.mt +if [ ! -f ${target_makefile_frag} ]; then + AC_MSG_ERROR("*** GDBSERVE does not support target ${target}") +fi + +dnl We have to assign the same value to other variables because autoconf +dnl doesn't provide a mechanism to substitute a replacement keyword with +dnl arbitrary data or pathnames. +dnl +target_makefile_frag_path=$target_makefile_frag +AC_SUBST(target_makefile_frag_path) +AC_SUBST_FILE(target_makefile_frag) + +cpufile=`sed -n ' +s/CPU_FILE[ ]*=[ ]*\([^ ]*\)/\1/p +' ${target_makefile_frag} + +files= +links= +rm -f cpu.h +if [ "${cpufile}" != "" ]; then + files="${files} ${cpufile}.h" + links="${links} cpu.h" +fi + +AC_LINK_FILES($files, $links) +AC_OUTPUT(Makefile) + diff --git a/contrib/gdb/gdb/nlm/gdbserve.c b/contrib/gdb/gdb/nlm/gdbserve.c new file mode 100644 index 000000000000..62adf3a8d1bc --- /dev/null +++ b/contrib/gdb/gdb/nlm/gdbserve.c @@ -0,0 +1,1056 @@ +/* gdbserve.c -- NLM debugging stub for Novell NetWare. + + This is originally based on an m68k software stub written by Glenn + Engel at HP, but has changed quite a bit. It was modified for the + i386 by Jim Kingdon, Cygnus Support. It was modified to run under + NetWare by Ian Lance Taylor, Cygnus Support. + + This code is intended to produce an NLM (a NetWare Loadable Module) + to run under Novell NetWare. To create the NLM, compile this code + into an object file using the NLM SDK on any i386 host, and use the + nlmconv program (available in the GNU binutils) to transform the + resulting object file into an NLM. */ + +/**************************************************************************** + + 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. + +****************************************************************************/ + +/**************************************************************************** + * + * 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 +#include +#include +#include + +#ifdef __i386__ +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +#include +#include "cpu.h" + + +/****************************************************/ +/* This information is from Novell. It is not in any of the standard + NetWare header files. */ + +struct DBG_LoadDefinitionStructure +{ + void *reserved1[4]; + LONG reserved5; + LONG LDCodeImageOffset; + LONG LDCodeImageLength; + LONG LDDataImageOffset; + LONG LDDataImageLength; + LONG LDUninitializedDataLength; + LONG LDCustomDataOffset; + LONG LDCustomDataSize; + LONG reserved6[2]; + LONG (*LDInitializationProcedure)(void); +}; + +#define LO_NORMAL 0x0000 +#define LO_STARTUP 0x0001 +#define LO_PROTECT 0x0002 +#define LO_DEBUG 0x0004 +#define LO_AUTO_LOAD 0x0008 + +/* Loader returned error codes */ +#define LOAD_COULD_NOT_FIND_FILE 1 +#define LOAD_ERROR_READING_FILE 2 +#define LOAD_NOT_NLM_FILE_FORMAT 3 +#define LOAD_WRONG_NLM_FILE_VERSION 4 +#define LOAD_REENTRANT_INITIALIZE_FAILURE 5 +#define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6 +#define LOAD_ALREADY_IN_PROGRESS 7 +#define LOAD_NOT_ENOUGH_MEMORY 8 +#define LOAD_INITIALIZE_FAILURE 9 +#define LOAD_INCONSISTENT_FILE_FORMAT 10 +#define LOAD_CAN_NOT_LOAD_AT_STARTUP 11 +#define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12 +#define LOAD_UNRESOLVED_EXTERNAL 13 +#define LOAD_PUBLIC_ALREADY_DEFINED 14 +/****************************************************/ + +/* The main thread ID. */ +static int mainthread; + +/* An error message for the main thread to print. */ +static char *error_message; + +/* The AIO port handle. */ +static int AIOhandle; + +/* BUFMAX defines the maximum number of characters in inbound/outbound + buffers. At least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX (REGISTER_BYTES * 2 + 16) + +/* remote_debug > 0 prints ill-formed commands in valid packets and + checksum errors. */ +static int remote_debug = 1; + +static const char hexchars[] = "0123456789abcdef"; + +unsigned char breakpoint_insn[] = BREAKPOINT; + +char *mem2hex (void *mem, char *buf, int count, int may_fault); +char *hex2mem (char *buf, void *mem, int count, int may_fault); +extern void set_step_traps (struct StackFrame *); +extern void clear_step_traps (struct StackFrame *); + +static int __main() {}; + +/* Read a character from the serial port. This must busy wait, but + that's OK because we will be the only thread running anyhow. */ + +static int +getDebugChar () +{ + int err; + LONG got; + unsigned char ret; + + do + { + err = AIOReadData (AIOhandle, (char *) &ret, 1, &got); + if (err != 0) + { + error_message = "AIOReadData failed"; + ResumeThread (mainthread); + return -1; + } + } + while (got == 0); + + return ret; +} + +/* Write a character to the serial port. Returns 0 on failure, + non-zero on success. */ + +static int +putDebugChar (c) + unsigned char c; +{ + int err; + LONG put; + + put = 0; + while (put < 1) + { + err = AIOWriteData (AIOhandle, (char *) &c, 1, &put); + if (err != 0) + ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put); + } + return 1; +} + +/* Turn a hex character into a number. */ + +static 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); +} + +/* Scan for the sequence $#. Returns 0 on failure, + non-zero on success. */ + +static int +getpacket (buffer) + char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + int ch; + + do + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar()) != '$') + if (ch == -1) + return 0; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) + { + ch = getDebugChar(); + if (ch == -1) + return 0; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + if (ch == -1) + return 0; + xmitcsum = hex(ch) << 4; + ch = getDebugChar (); + if (ch == -1) + return 0; + xmitcsum += hex(ch); + + if (checksum != xmitcsum) + { + if (remote_debug) + ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum,xmitcsum,buffer); + /* failed checksum */ + if (! putDebugChar('-')) + return 0; + return 1; + } + else + { + /* successful transfer */ + if (! putDebugChar('+')) + return 0; + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + if (! putDebugChar (buffer[0]) + || ! putDebugChar (buffer[1])) + return 0; + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + } + } + } + while (checksum != xmitcsum); + + if (remote_debug) + ConsolePrintf ("Received packet \"%s\"\r\n", buffer); + + return 1; +} + +/* Send the packet in buffer. Returns 0 on failure, non-zero on + success. */ + +static int +putpacket (buffer) + char * buffer; +{ + unsigned char checksum; + int count; + int ch; + + if (remote_debug) + ConsolePrintf ("Sending packet \"%s\"\r\n", buffer); + + /* $#. */ + do + { + if (! putDebugChar('$')) + return 0; + checksum = 0; + count = 0; + + while (ch=buffer[count]) + { + if (! putDebugChar(ch)) + return 0; + checksum += ch; + count += 1; + } + + if (! putDebugChar('#') + || ! putDebugChar(hexchars[checksum >> 4]) + || ! putDebugChar(hexchars[checksum % 16])) + return 0; + + ch = getDebugChar (); + if (ch == -1) + return 0; + } + while (ch != '+'); + + return 1; +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + +static void +debug_error (format, parm) + char *format; + char *parm; +{ + if (remote_debug) + { + ConsolePrintf (format, parm); + ConsolePrintf ("\n"); + } +} + +/* This is set if we could get a memory access fault. */ +static int mem_may_fault; + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +volatile int mem_err = 0; + +#ifndef ALTERNATE_MEM_FUNCS +/* 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 (addr) + char *addr; +{ + return *addr; +} + +void +set_char (addr, val) + char *addr; + int val; +{ + *addr = val; +} +#endif /* ALTERNATE_MEM_FUNCS */ + +/* 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) + void *mem; + char *buf; + int count; + int may_fault; +{ + int i; + unsigned char ch; + char *ptr = mem; + + mem_may_fault = may_fault; + for (i = 0; i < count; i++) + { + ch = get_char (ptr++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + mem_may_fault = 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, may_fault) + char *buf; + void *mem; + int count; + int may_fault; +{ + int i; + unsigned char ch; + char *ptr = mem; + + mem_may_fault = may_fault; + for (i=0;i=0) + { + *intValue = (*intValue <<4) | hexValue; + numChars ++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* This function does all command processing for interfacing to gdb. + It is called whenever an exception occurs in the module being + debugged. */ + +static LONG +handle_exception (frame) + struct StackFrame *frame; +{ + int addr, length; + char *ptr; + static struct DBG_LoadDefinitionStructure *ldinfo = 0; + static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program. */ + +#if 0 + /* According to some documentation from Novell, the bell sometimes + may be ringing at this point. This can be stopped on Netware 4 + systems by calling the undocumented StopBell() function. */ + + StopBell (); +#endif + + if (remote_debug) + { + ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n", + frame->ExceptionNumber, + frame->ExceptionDescription, + frame->ExceptionPC, + GetThreadID ()); + } + + switch (frame->ExceptionNumber) + { + case START_NLM_EVENT: + /* If the NLM just started, we record the module load information + and the thread ID, and set a breakpoint at the first instruction + in the program. */ + + ldinfo = ((struct DBG_LoadDefinitionStructure *) + frame->ExceptionErrorCode); + memcpy (first_insn, ldinfo->LDInitializationProcedure, + BREAKPOINT_SIZE); + memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn, + BREAKPOINT_SIZE); + flush_i_cache (); + return RETURN_TO_PROGRAM; + + case ENTER_DEBUGGER_EVENT: + case KEYBOARD_BREAK_EVENT: + /* Pass some events on to the next debugger, in case it will handle + them. */ + return RETURN_TO_NEXT_DEBUGGER; + + case 3: /* Breakpoint */ + /* After we've reached the initial breakpoint, reset it. */ + if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure + && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn, + BREAKPOINT_SIZE) == 0) + { + memcpy (ldinfo->LDInitializationProcedure, first_insn, + BREAKPOINT_SIZE); + frame->ExceptionPC -= DECR_PC_AFTER_BREAK; + flush_i_cache (); + } + /* Normal breakpoints end up here */ + do_status (remcomOutBuffer, frame); + break; + + default: + /* At the moment, we don't care about most of the unusual NetWare + exceptions. */ + if (frame->ExceptionNumber > 31) + return RETURN_TO_PROGRAM; + + /* Most machine level exceptions end up here */ + do_status (remcomOutBuffer, frame); + break; + + case 11: /* Segment not present */ + case 13: /* General protection */ + case 14: /* Page fault */ + /* If we get a GP fault, and mem_may_fault is set, and the + instruction pointer is near set_char or get_char, then we caused + the fault ourselves accessing an illegal memory location. */ + if (mem_may_fault + && ((frame->ExceptionPC >= (long) &set_char + && frame->ExceptionPC < (long) &set_char + 50) + || (frame->ExceptionPC >= (long) &get_char + && frame->ExceptionPC < (long) &get_char + 50))) + { + mem_err = 1; + /* Point the instruction pointer at an assembly language stub + which just returns from the function. */ + + frame->ExceptionPC += 4; /* Skip the load or store */ + + /* Keep going. This will act as though it returned from + set_char or get_char. The calling routine will check + mem_err, and do the right thing. */ + return RETURN_TO_PROGRAM; + } + /* Random mem fault, report it */ + do_status (remcomOutBuffer, frame); + break; + + case TERMINATE_NLM_EVENT: + /* There is no way to get the exit status. */ + sprintf (remcomOutBuffer, "W%02x", 0); + break; /* We generate our own status */ + } + + /* FIXME: How do we know that this exception has anything to do with + the program we are debugging? We can check whether the PC is in + the range of the module we are debugging, but that doesn't help + much since an error could occur in a library routine. */ + + clear_step_traps (frame); + + if (! putpacket(remcomOutBuffer)) + return RETURN_TO_NEXT_DEBUGGER; + + if (frame->ExceptionNumber == TERMINATE_NLM_EVENT) + { + ResumeThread (mainthread); + return RETURN_TO_PROGRAM; + } + + while (1) + { + error = 0; + remcomOutBuffer[0] = 0; + if (! getpacket (remcomInBuffer)) + return RETURN_TO_NEXT_DEBUGGER; + switch (remcomInBuffer[0]) + { + case '?': + do_status (remcomOutBuffer, frame); + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': + /* return the value of the CPU registers */ + frame_to_registers (frame, remcomOutBuffer); + break; + case 'G': + /* set the value of the CPU registers - return OK */ + registers_to_frame (&remcomInBuffer[1], frame); + strcpy(remcomOutBuffer,"OK"); + break; + + case 'm': + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + 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"); + debug_error("malformed read memory command: %s",remcomInBuffer); + } + break; + + case 'M': + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + 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"); + debug_error("malformed write memory command: %s",remcomInBuffer); + } + break; + + case 'c': + case 's': + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + { +/* registers[PC_REGNUM].lo = addr;*/ + fprintf (stderr, "Setting PC to 0x%x\n", addr); + while (1); + } + + if (remcomInBuffer[0] == 's') + set_step_traps (frame); + + flush_i_cache (); + return RETURN_TO_PROGRAM; + + case 'k': + /* kill the program */ + KillMe (ldinfo); + ResumeThread (mainthread); + return RETURN_TO_PROGRAM; + + case 'q': /* Query message */ + if (strcmp (&remcomInBuffer[1], "Offsets") == 0) + { + sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x", + ldinfo->LDCodeImageOffset, + ldinfo->LDDataImageOffset, + ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength); + } + else + sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]); + break; + } + + /* reply to the request */ + if (! putpacket(remcomOutBuffer)) + return RETURN_TO_NEXT_DEBUGGER; + } +} + +char *progname; + +struct bitRate { + BYTE bitRate; + const char *bitRateString; +}; + +struct bitRate bitRateTable[] = +{ + { AIO_BAUD_50 , "50" }, + { AIO_BAUD_75 , "75" }, + { AIO_BAUD_110 , "110" }, + { AIO_BAUD_134p5 , "134.5" }, + { AIO_BAUD_150 , "150" }, + { AIO_BAUD_300 , "300" }, + { AIO_BAUD_600 , "600" }, + { AIO_BAUD_1200 , "1200" }, + { AIO_BAUD_1800 , "1800" }, + { AIO_BAUD_2000 , "2000" }, + { AIO_BAUD_2400 , "2400" }, + { AIO_BAUD_3600 , "3600" }, + { AIO_BAUD_4800 , "4800" }, + { AIO_BAUD_7200 , "7200" }, + { AIO_BAUD_9600 , "9600" }, + { AIO_BAUD_19200 , "19200" }, + { AIO_BAUD_38400 , "38400" }, + { AIO_BAUD_57600 , "57600" }, + { AIO_BAUD_115200, "115200" }, + { -1, NULL } +}; + +char dataBitsTable[] = "5678"; + +char *stopBitsTable[] = { "1", "1.5", "2" }; + +char parity[] = "NOEMS"; + +/* Start up. The main thread opens the named serial I/O port, loads + the named NLM module and then goes to sleep. The serial I/O port + is named as a board number and a port number. It would be more DOS + like to provide a menu of available serial ports, but I don't want + to have to figure out how to do that. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int hardware, board, port; + BYTE bitRate; + BYTE dataBits; + BYTE stopBits; + BYTE parityMode; + LONG err; + struct debuggerStructure s; + int cmdindx; + char *cmdlin; + int i; + + /* set progname */ + progname = "gdbserve"; + + /* set default serial line */ + hardware = -1; + board = 0; + port = 0; + + /* set default serial line characteristics */ + bitRate = AIO_BAUD_9600; + dataBits = AIO_DATA_BITS_8; + stopBits = AIO_STOP_BITS_1; + parityMode = AIO_PARITY_NONE; + + cmdindx = 0; + for (argc--, argv++; *argv; argc--, argv++) + { + char *bp; + char *ep; + + if (strnicmp(*argv, "BAUD=", 5) == 0) + { + struct bitRate *brp; + + bp = *argv + 5; + for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++) + { + if (strcmp(brp->bitRateString, bp) == 0) + { + bitRate = brp->bitRate; + break; + } + } + + if (brp->bitRateString == NULL) + { + fprintf(stderr, "%s: %s: unknown or unsupported bit rate", + progname, bp); + exit (1); + } + } + else if (strnicmp(*argv, "BOARD=", 6) == 0) + { + bp = *argv + 6; + board = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') + { + fprintf (stderr, "%s: %s: expected integer argument\n", + progname, bp); + exit(1); + } + } +#if 1 /* FIXME: this option has been depricated */ + else if (strnicmp(*argv, "NODE=", 5) == 0) + { + bp = *argv + 5; + board = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') + { + fprintf (stderr, "%s: %s: expected integer argument\n", + progname, bp); + exit(1); + } + } +#endif + else if (strnicmp(*argv, "PORT=", 5) == 0) + { + bp = *argv + 5; + port = strtol (bp, &ep, 0); + if (ep == bp || *ep != '\0') + { + fprintf (stderr, "%s: %s: expected integer argument\n", + progname, bp); + exit(1); + } + } + else + { + break; + } + + cmdindx++; + } + + if (argc == 0) + { + fprintf (stderr, + "Usage: load %s [options] program [arguments]\n", progname); + exit (1); + } + + err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle); + if (err != AIO_SUCCESS) + { + switch (err) + { + case AIO_PORT_NOT_AVAILABLE: + fprintf (stderr, "Port not available\n"); + break; + + case AIO_BOARD_NUMBER_INVALID: + case AIO_PORT_NUMBER_INVALID: + fprintf (stderr, "No such port\n"); + break; + + default: + fprintf (stderr, "Could not open port: %d\n", err); + break; + } + + exit (1); + } + + err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode, + AIO_HARDWARE_FLOW_CONTROL_OFF); + + if (err == AIO_QUALIFIED_SUCCESS) + { + AIOPORTCONFIG portConfig; + + fprintf (stderr, "Port configuration changed!\n"); + + portConfig.returnLength = sizeof(portConfig); + AIOGetPortConfiguration (AIOhandle, &portConfig, NULL); + + fprintf (stderr, + " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\ + Flow:%s\n", + bitRateTable[portConfig.bitRate].bitRateString, + dataBitsTable[portConfig.dataBits], + stopBitsTable[portConfig.stopBits], + parity[portConfig.parityMode], + portConfig.flowCtrlMode ? "ON" : "OFF"); + } + else if (err != AIO_SUCCESS) + { + fprintf (stderr, "Could not configure port: %d\n", err); + AIOReleasePort (AIOhandle); + exit (1); + } + + if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL, + (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS)) + != AIO_SUCCESS) + { + LONG extStatus, chgdExtStatus; + + fprintf (stderr, "Could not set desired port controls!\n"); + AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus); + fprintf (stderr, "Port controls now: %d, %d\n", extStatus, + chgdExtStatus); + } + + /* Register ourselves as an alternate debugger. */ + memset (&s, 0, sizeof s); + s.DDSResourceTag = ((struct ResourceTagStructure *) + AllocateResourceTag (GetNLMHandle (), + (BYTE *)"gdbserver", + DebuggerSignature)); + if (s.DDSResourceTag == 0) + { + fprintf (stderr, "AllocateResourceTag failed\n"); + AIOReleasePort (AIOhandle); + exit (1); + } + s.DDSdebuggerEntry = handle_exception; + s.DDSFlags = TSS_FRAME_BIT; + + err = RegisterDebuggerRTag (&s, AT_FIRST); + if (err != 0) + { + fprintf (stderr, "RegisterDebuggerRTag failed\n"); + AIOReleasePort (AIOhandle); + exit (1); + } + + /* Get the command line we were invoked with, and advance it past + our name and the board and port arguments. */ + cmdlin = getcmd ((char *) NULL); + for (i = 0; i < cmdindx; i++) + { + while (! isspace (*cmdlin)) + ++cmdlin; + while (isspace (*cmdlin)) + ++cmdlin; + } + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. */ + if (! putDebugChar ('+')) + { + fprintf (stderr, "putDebugChar failed\n"); + UnRegisterDebugger (&s); + AIOReleasePort (AIOhandle); + exit (1); + } + + mainthread = GetThreadID (); + + if (remote_debug > 0) + ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n", + cmdlin, __GetScreenID (GetCurrentScreen())); + + /* Start up the module to be debugged. */ + err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()), + (BYTE *)cmdlin, LO_DEBUG); + if (err != 0) + { + fprintf (stderr, "LoadModule failed: %d\n", err); + UnRegisterDebugger (&s); + AIOReleasePort (AIOhandle); + exit (1); + } + + /* Wait for the debugger to wake us up. */ + if (remote_debug > 0) + ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread); + SuspendThread (mainthread); + if (remote_debug > 0) + ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread); + + /* If we are woken up, print an optional error message, deregister + ourselves and exit. */ + if (error_message != NULL) + fprintf (stderr, "%s\n", error_message); + UnRegisterDebugger (&s); + AIOReleasePort (AIOhandle); + exit (0); +} diff --git a/contrib/gdb/gdb/nlm/gdbserve.def b/contrib/gdb/gdb/nlm/gdbserve.def new file mode 100644 index 000000000000..588028d6f334 --- /dev/null +++ b/contrib/gdb/gdb/nlm/gdbserve.def @@ -0,0 +1,42 @@ +description "GDB debugger stub" +version 1,2 +debug +module clib +screenname "System Console" +input gdbserve.O +output gdbserve.nlm +start _Prelude +exit _Stop +import + AllocateResourceTag + ConsolePrintf + GetCurrentScreen + GetNLMHandle + GetThreadID + KillMe + LoadModule + ReadByteAltDebugger + RegisterDebuggerRTag + ResumeThread + SuspendThread + UnRegisterDebugger + WriteByteAltDebugger + _GetCLibNLMLibHandle + _NWRegisterNLMLibraryUser + _SetupArgv + _StartNLM + _TerminateNLM + __GetScreenID + __get_errno_ptr + exit + fprintf + getcmd + memcmp + memcpy + memset + sprintf + strcmp + strcpy + strlen + strnicmp + strtol diff --git a/contrib/gdb/gdb/nlm/i386.c b/contrib/gdb/gdb/nlm/i386.c new file mode 100644 index 000000000000..560198e37023 --- /dev/null +++ b/contrib/gdb/gdb/nlm/i386.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i386.h" + +extern char *mem2hex (void *mem, char *buf, int count, int may_fault); +extern char *hex2mem (char *buf, void *mem, int count, int may_fault); +extern int computeSignal (int exceptionVector); + +void +flush_i_cache() +{ +} + +/* Get the registers out of the frame information. */ + +void +frame_to_registers (frame, regs) + struct StackFrame *frame; + char *regs; +{ + /* Copy EAX -> EDI */ + mem2hex (&frame->ExceptionEAX, ®s[0 * 4 * 2], 4 * 8, 0); + + /* Copy EIP & PS */ + mem2hex (&frame->ExceptionPC, ®s[8 * 4 * 2], 4 * 2, 0); + + /* Copy CS, SS, DS */ + mem2hex (&frame->ExceptionCS, ®s[10 * 4 * 2], 4 * 3, 0); + + /* Copy ES */ + mem2hex (&frame->ExceptionES, ®s[13 * 4 * 2], 4 * 1, 0); + + /* Copy FS & GS */ + mem2hex (&frame->ExceptionFS, ®s[14 * 4 * 2], 4 * 2, 0); +} + +/* Put the registers back into the frame information. */ + +void +registers_to_frame (regs, frame) + char *regs; + struct StackFrame *frame; +{ + /* Copy EAX -> EDI */ + hex2mem (®s[0 * 4 * 2], &frame->ExceptionEAX, 4 * 8, 0); + + /* Copy EIP & PS */ + hex2mem (®s[8 * 4 * 2], &frame->ExceptionPC, 4 * 2, 0); + + /* Copy CS, SS, DS */ + hex2mem (®s[10 * 4 * 2], &frame->ExceptionCS, 4 * 3, 0); + + /* Copy ES */ + hex2mem (®s[13 * 4 * 2], &frame->ExceptionES, 4 * 1, 0); + + /* Copy FS & GS */ + hex2mem (®s[14 * 4 * 2], &frame->ExceptionFS, 4 * 2, 0); +} + +void +set_step_traps (frame) + struct StackFrame *frame; +{ + frame->ExceptionSystemFlags |= 0x100; +} + +void +clear_step_traps (frame) + struct StackFrame *frame; +{ + frame->ExceptionSystemFlags &= ~0x100; +} + +void +do_status (ptr, frame) + char *ptr; + struct StackFrame *frame; +{ + int sigval; + + sigval = computeSignal (frame->ExceptionNumber); + + sprintf (ptr, "T%02x", sigval); + ptr += 3; + + sprintf (ptr, "%02x:", PC_REGNUM); + ptr = mem2hex (&frame->ExceptionPC, ptr + 3, 4, 0); + *ptr++ = ';'; + + sprintf (ptr, "%02x:", SP_REGNUM); + ptr = mem2hex (&frame->ExceptionESP, ptr + 3, 4, 0); + *ptr++ = ';'; + + sprintf (ptr, "%02x:", FP_REGNUM); + ptr = mem2hex (&frame->ExceptionEBP, ptr + 3, 4, 0); + *ptr++ = ';'; + + *ptr = '\000'; +} diff --git a/contrib/gdb/gdb/nlm/i386.h b/contrib/gdb/gdb/nlm/i386.h new file mode 100644 index 000000000000..155702bd5032 --- /dev/null +++ b/contrib/gdb/gdb/nlm/i386.h @@ -0,0 +1,13 @@ +/* Register values. All of these values *MUST* agree with tm.h */ +#define SP_REGNUM 4 /* Contains address of top of stack */ +#define PC_REGNUM 8 /* Contains program counter */ +#define FP_REGNUM 5 /* Virtual frame pointer */ +#define NUM_REGS 16 /* Number of machine registers */ +#define REGISTER_BYTES (NUM_REGS * 4) /* Total size of registers array */ + +#define ExceptionPC ExceptionEIP +#define DECR_PC_AFTER_BREAK 1 /* int 3 leaves PC pointing after insn */ +#define BREAKPOINT {0xcc} +#define BREAKPOINT_SIZE (sizeof breakpoint_insn) + +#define StackFrame T_TSS_StackFrame diff --git a/contrib/gdb/gdb/nlm/ppc.c b/contrib/gdb/gdb/nlm/ppc.c new file mode 100644 index 000000000000..e68397bc96b3 --- /dev/null +++ b/contrib/gdb/gdb/nlm/ppc.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "ppc.h" + +extern char *mem2hex (void *mem, char *buf, int count, int may_fault); +extern char *hex2mem (char *buf, void *mem, int count, int may_fault); +extern int computeSignal (int exceptionVector); + +void +flush_i_cache (void) +{ +} + +/* Get the registers out of the frame information. */ + +void +frame_to_registers (frame, regs) + struct StackFrame *frame; + char *regs; +{ + mem2hex (&frame->ExceptionState.CsavedRegs, ®s[GP0_REGNUM * 4 * 2], 4 * 32, 0); + + mem2hex (&frame->ExceptionState.CSavedFPRegs, ®s[FP0_REGNUM * 4 * 2], 4 * 32, 0); + + mem2hex (&frame->ExceptionPC, ®s[PC_REGNUM * 4 * 2], 4 * 1, 0); + + mem2hex (&frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedSRR1, ®s[CR_REGNUM * 4 * 2], 4 * 1, 0); + mem2hex (&frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedLR, ®s[LR_REGNUM * 4 * 2], 4 * 1, 0); + mem2hex (&frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedCTR, ®s[CTR_REGNUM * 4 * 2], 4 * 1, 0); + mem2hex (&frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedXER, ®s[XER_REGNUM * 4 * 2], 4 * 1, 0); + mem2hex (&frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedMQ, ®s[MQ_REGNUM * 4 * 2], 4 * 1, 0); +} + +/* Put the registers back into the frame information. */ + +void +registers_to_frame (regs, frame) + char *regs; + struct StackFrame *frame; +{ + hex2mem (®s[GP0_REGNUM * 4 * 2], &frame->ExceptionState.CsavedRegs, 4 * 32, 0); + + hex2mem (®s[FP0_REGNUM * 4 * 2], &frame->ExceptionState.CSavedFPRegs, 4 * 32, 0); + + hex2mem (®s[PC_REGNUM * 4 * 2], &frame->ExceptionPC, 4 * 1, 0); + + hex2mem (®s[CR_REGNUM * 4 * 2], &frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedSRR1, 4 * 1, 0); + hex2mem (®s[LR_REGNUM * 4 * 2], &frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedLR, 4 * 1, 0); + hex2mem (®s[CTR_REGNUM * 4 * 2], &frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedCTR, 4 * 1, 0); + hex2mem (®s[XER_REGNUM * 4 * 2], &frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedXER, 4 * 1, 0); + hex2mem (®s[MQ_REGNUM * 4 * 2], &frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedMQ, 4 * 1, 0); +} + + +extern volatile int mem_err; + +#ifdef ALTERNATE_MEM_FUNCS +extern int ReadByteAltDebugger (char* addr, char *theByte); +extern int WriteByteAltDebugger (char* addr, char theByte); +int +get_char (addr) + char *addr; +{ + char c; + + if (!ReadByteAltDebugger (addr, &c)) + mem_err = 1; + + return c; +} + +void +set_char (addr, val) + char *addr; + int val; +{ + if (!WriteByteAltDebugger (addr, val)) + mem_err = 1; +} +#endif + +int +mem_write (dst, src, len) + char *dst, *src; + int len; +{ + while (len-- && !mem_err) + set_char (dst++, *src++); + + return mem_err; +} + +union inst +{ + LONG l; + + struct + { + union + { + struct /* Unconditional branch */ + { + unsigned opcode : 6; /* 18 */ + signed li : 24; + unsigned aa : 1; + unsigned lk : 1; + } b; + struct /* Conditional branch */ + { + unsigned opcode : 6; /* 16 */ + unsigned bo : 5; + unsigned bi : 5; + signed bd : 14; + unsigned aa : 1; + unsigned lk : 1; + } bc; + struct /* Conditional branch to ctr or lr reg */ + { + unsigned opcode : 6; /* 19 */ + unsigned bo : 5; + unsigned bi : 5; + unsigned type : 15; /* 528 = ctr, 16 = lr */ + unsigned lk : 1; + } bclr; + } variant; + } inst; +}; + +static LONG saved_inst; +static LONG *saved_inst_pc = 0; +static LONG saved_target_inst; +static LONG *saved_target_inst_pc = 0; + +void +set_step_traps (frame) + struct StackFrame *frame; +{ + union inst inst; + LONG *target; + int opcode; + int ra, rb; + LONG *pc = (LONG *)frame->ExceptionPC; + + inst.l = *pc++; + + opcode = inst.inst.variant.b.opcode; + + target = pc; + + switch (opcode) + { + case 18: /* Unconditional branch */ + + if (inst.inst.variant.b.aa) /* Absolute? */ + target = 0; + target += inst.inst.variant.b.li; + + break; + case 16: /* Conditional branch */ + + if (!inst.inst.variant.bc.aa) /* Absolute? */ + target = 0; + target += inst.inst.variant.bc.bd; + + break; + case 19: /* Cond. branch via ctr or lr reg */ + switch (inst.inst.variant.bclr.type) + { + case 528: /* ctr */ + target = (LONG *)frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedCTR; + break; + case 16: /* lr */ + target = (LONG *)frame->ExceptionState.u.SpecialRegistersEnumerated.CsavedLR; + break; + } + break; + } + + saved_inst = *pc; + mem_write (pc, breakpoint_insn, BREAKPOINT_SIZE); + saved_inst_pc = pc; + + if (target != pc) + { + saved_target_inst = *target; + mem_write (target, breakpoint_insn, BREAKPOINT_SIZE); + saved_target_inst_pc = target; + } +} + +/* Remove step breakpoints. Returns non-zero if pc was at a step breakpoint, + zero otherwise. This routine works even if there were no step breakpoints + set. */ + +int +clear_step_traps (frame) + struct StackFrame *frame; +{ + int retcode; + LONG *pc = (LONG *)frame->ExceptionPC; + + if (saved_inst_pc == pc || saved_target_inst_pc == pc) + retcode = 1; + else + retcode = 0; + + if (saved_inst_pc) + { + mem_write (saved_inst_pc, saved_inst, BREAKPOINT_SIZE); + saved_inst_pc = 0; + } + + if (saved_target_inst_pc) + { + mem_write (saved_target_inst_pc, saved_target_inst, BREAKPOINT_SIZE); + saved_target_inst_pc = 0; + } + + return retcode; +} + +void +do_status (ptr, frame) + char *ptr; + struct StackFrame *frame; +{ + int sigval; + + sigval = computeSignal (frame->ExceptionNumber); + + sprintf (ptr, "T%02x", sigval); + ptr += 3; + + sprintf (ptr, "%02x:", PC_REGNUM); + ptr = mem2hex (&frame->ExceptionPC, ptr + 3, 4, 0); + *ptr++ = ';'; + + sprintf (ptr, "%02x:", SP_REGNUM); + ptr = mem2hex (&frame->ExceptionState.CsavedRegs[SP_REGNUM], ptr + 3, 4, 0); + *ptr++ = ';'; + + sprintf (ptr, "%02x:", LR_REGNUM); + ptr = mem2hex (&frame->ExceptionState.CsavedRegs[LR_REGNUM], ptr + 3, 4, 0); + *ptr++ = ';'; + + *ptr = '\000'; +} diff --git a/contrib/gdb/gdb/nlm/ppc.h b/contrib/gdb/gdb/nlm/ppc.h new file mode 100644 index 000000000000..84cee6b11a38 --- /dev/null +++ b/contrib/gdb/gdb/nlm/ppc.h @@ -0,0 +1,165 @@ +typedef long Long; + +/* The following enum is used to access the special registers in + the saved machine state. */ + +typedef enum +{ + kDc_SavedPC = 0, /* really SRR0 */ + kDc_SavedMSR = 1, /* really SRR1 */ + kDc_SavedCR = 2, + kDc_SavedLR = 3, + kDc_SavedDSISR = 4, + kDc_SavedDAR = 5, + kDc_SavedXER = 6, + kDc_SavedCTR = 7, + kDc_SavedSDR1 = 8, + kDc_SavedRTCU = 9, + kDc_SavedRTCL = 10, + kDc_SavedDEC = 11, + kDc_SavedSR00 = 12, /* The Segement Registers are consecutive */ + kDc_SavedSR01 = 13, /* kDc_SavedSR00 + n is supported */ + kDc_SavedSR02 = 14, + kDc_SavedSR03 = 15, + kDc_SavedSR04 = 16, + kDc_SavedSR05 = 17, + kDc_SavedSR06 = 18, + kDc_SavedSR07 = 19, + kDc_SavedSR08 = 20, + kDc_SavedSR09 = 21, + kDc_SavedSR10 = 22, + kDc_SavedSR11 = 23, + kDc_SavedSR12 = 24, + kDc_SavedSR13 = 25, + kDc_SavedSR14 = 26, + kDc_SavedSR15 = 27, + kDc_SavedFPSCR = 29, + kDc_SavedMQ = 30, + kDc_SavedBAT0U = 31, + kDc_SavedBAT0L = 32, + kDc_SavedBAT1U = 33, + kDc_SavedBAT1L = 34, + kDc_SavedBAT2U = 35, + kDc_SavedBAT2L = 36, + kDc_SavedBAT3U = 37, + kDc_SavedBAT3L = 38, + + kNumberSpecialRegisters = 39 +} Dc_SavedRegisterName; + +/* Access to floating points is not very easy. This allows the number to be + accessed both as a floating number and as a pair of Longs. */ + +typedef union +{ + double asfloat; /* access the variable as a floating number */ + struct + { + Long high; + Long low; + } + asLONG; /* access the variable as two Longs */ +} FloatingPoints; + +/* The following is the standard record for Saving a machine state */ + +struct SavedMachineState +{ + FloatingPoints CSavedFPRegs[32]; /* The floating point registers [0->31] */ + /* ***32bit assumption*** */ + Long CsavedRegs[32]; /* space to save the General Registers */ + /* These are saved 0->31 */ + Long CexReason; + Long SavedDomainID; + union + { /* must be 8-byte aligned, so doubleFPSCR is 8-byte aligned */ + struct + { + Long CsavedSRR0; /* Index 0 - The saved PC */ + Long CsavedSRR1; /* 1 saved MSR */ + Long CsavedCR; /* 2 */ + Long CsavedLR; /* 3 */ + Long CsavedDSISR; /* 4 */ + Long CsavedDAR; /* 5 */ + + Long CsavedXER; /* 6 */ + Long CsavedCTR; /* 7 */ + Long CsavedSDR1; /* 8 */ + Long CsavedRTCU; /* 9 */ + Long CsavedRTCL; /* 10 */ + Long CsavedDEC; /* 11 */ + Long CsavedSR0; /* 12 */ + Long CsavedSR1; /* 13 */ + Long CsavedSR2; /* 14 */ + Long CsavedSR3; /* 15 */ + Long CsavedSR4; /* 16 */ + Long CsavedSR5; /* 17 */ + Long CsavedSR6; /* 18 */ + Long CsavedSR7; /* 19 */ + Long CsavedSR8; /* 20 */ + Long CsavedSR9; /* 21 */ + Long CsavedSR10; /* 22 */ + Long CsavedSR11; /* 23 */ + Long CsavedSR12; /* 24 */ + Long CsavedSR13; /* 25 */ + Long CsavedSR14; /* 26 */ + Long CsavedSR15; /* 27 */ + /* CdoubleFPSCR must be double word aligned */ + Long CdoubleFPSCR; /* 28 this is the upper part of the store and has + no meaning */ + Long CsavedFPSCR; /* 29 */ + Long CsavedMQ; /* 30 */ + Long CsavedBAT0U; /* 31 */ + Long CsavedBAT0L; /* 32 */ + Long CsavedBAT1U; /* 33 */ + Long CsavedBAT1L; /* 34 */ + Long CsavedBAT2U; /* 35 */ + Long CsavedBAT2L; /* 36 */ + Long CsavedBAT3U; /* 37 */ + Long CsavedBAT3L; /* 38 */ + } + SpecialRegistersEnumerated; + + Long SpecialRegistersIndexed[kNumberSpecialRegisters]; + } u; + + Long Padding[3]; /* Needed for quad-word alignment */ +}; + +struct StackFrame +{ + LONG *ExceptionDomainID; + /*ProcessorStructure*/ int *ExceptionProcessorID; + BYTE *ExceptionDescription; + LONG ExceptionFlags; + LONG ExceptionErrorCode; + LONG ExceptionNumber; + struct SavedMachineState ExceptionState; +}; + +/* Register values. All of these values *MUST* agree with tm.h */ +#define GP0_REGNUM 0 /* GPR register 0 */ +#define SP_REGNUM 1 /* Contains address of top of stack */ +#define FP0_REGNUM 32 /* FPR (Floating point) register 0 */ +#define PC_REGNUM 64 /* Contains program counter */ +#define PS_REGNUM 65 /* Processor (or machine) status (%msr) */ +#define CR_REGNUM 66 /* Condition register */ +#define LR_REGNUM 67 /* Link register */ +#define CTR_REGNUM 68 /* Count register */ +#define XER_REGNUM 69 /* Fixed point exception registers */ +#define MQ_REGNUM 70 /* Multiply/quotient register */ +#define NUM_REGS 71 /* Number of machine registers */ +#define REGISTER_BYTES (420) /* Total size of registers array */ + +#define ExceptionPC ExceptionState.u.SpecialRegistersEnumerated.CsavedSRR0 +#define DECR_PC_AFTER_BREAK 0 /* PPCs get this right! */ +#define BREAKPOINT {0x7d, 0x82, 0x10, 0x08} +extern unsigned char breakpoint_insn[]; +#define BREAKPOINT_SIZE 4 + +#if 0 +#define ALTERNATE_MEM_FUNCS /* We need our own get_char/set_char */ +#endif + +extern int get_char (char *addr); +extern void set_char (char *addr, int val); diff --git a/contrib/gdb/gdb/nlm/prelude.c b/contrib/gdb/gdb/nlm/prelude.c new file mode 100644 index 000000000000..37e12c89a2bb --- /dev/null +++ b/contrib/gdb/gdb/nlm/prelude.c @@ -0,0 +1,67 @@ +/*=========================================================================== += Novell Standard C Library for NetWare Loadable Modules += += Unpublished Copyright (C) 1993 by Novell, Inc. All rights reserved. += += No part of this file may be duplicated, revised, translated, localized or += modified in any manner or compiled, linked or uploaded or downloaded to or += from any computer system without the prior written consent of Novell, Inc. +============================================================================== += The object produced by compiling this file is for use by the client of this += library and is not linked in; Prelude.Obj is therefore one of the files to += be distributed with CLib.NLM and its headers. +============================================================================== +*/ + +#include +#if defined(__netware__) && defined(__i386__) +#define TERMINATE_BY_UNLOAD 5 +#else +#include +#endif +/*#include "libhooks.h"*/ + +extern int main (int, char **); + +static int NLMID; + + +void _Stop( void ) +{ + _TerminateNLM(NLMID, NULL, TERMINATE_BY_UNLOAD); +} + +int _cstart_( void ) +{ + return _SetupArgv(main); +} + +int _Prelude +( + int NLMHandle, + int initErrorScreenID, + char *commandLine, + char *loadDirectoryPath, + int uninitializedDataLength, + int NLMFileHandle, + int (*readRoutineP)(), + int customDataOffset, + int customDataSize +) +{ + int rc; + + rc = _StartNLM(NLMHandle, + initErrorScreenID, + commandLine, + loadDirectoryPath, + uninitializedDataLength, + NLMFileHandle, + readRoutineP, + customDataOffset, + customDataSize, + &NLMID, + _cstart_); + + return rc; +} diff --git a/contrib/gdb/gdb/nlmread.c b/contrib/gdb/gdb/nlmread.c new file mode 100644 index 000000000000..b61dc97d94d6 --- /dev/null +++ b/contrib/gdb/gdb/nlmread.c @@ -0,0 +1,308 @@ +/* Read NLM (NetWare Loadable Module) format executable files for GDB. + Copyright 1993, 1994 Free Software Foundation, Inc. + Written by Fred Fish at Cygnus Support (fnf@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "bfd.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "buildsym.h" +#include "stabsread.h" + +static void +nlm_new_init PARAMS ((struct objfile *)); + +static void +nlm_symfile_init PARAMS ((struct objfile *)); + +static void +nlm_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +nlm_symfile_finish PARAMS ((struct objfile *)); + +static void +nlm_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *)); + +static struct section_offsets * +nlm_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type, + struct objfile *)); + + +/* 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 gdb will be able to read stabs from an NLM + file at some point in the near future. */ + +static void +nlm_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); +} + + +/* NLM specific initialization routine for reading symbols. + + It is passed a pointer to a struct sym_fns which contains, among other + things, the BFD for the file whose symbols are being read, and a slot for + a pointer to "private data" which we can fill with goodies. + + For now at least, we have nothing in particular to do, so this function is + just a stub. */ + +static void +nlm_symfile_init (ignore) + struct objfile *ignore; +{ +} + +static void +record_minimal_symbol (name, address, ms_type, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + struct objfile *objfile; +{ + name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); + prim_record_minimal_symbol (name, address, ms_type, objfile); +} + + +/* + +LOCAL FUNCTION + + nlm_symtab_read -- read the symbol table of an NLM file + +SYNOPSIS + + void nlm_symtab_read (bfd *abfd, CORE_ADDR addr, + struct objfile *objfile) + +DESCRIPTION + + 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 +nlm_symtab_read (abfd, addr, objfile) + bfd *abfd; + CORE_ADDR addr; + struct objfile *objfile; +{ + long storage_needed; + asymbol *sym; + asymbol **symbol_table; + long number_of_symbols; + long i; + struct cleanup *back_to; + CORE_ADDR symaddr; + enum minimal_symbol_type ms_type; + + storage_needed = bfd_get_symtab_upper_bound (abfd); + if (storage_needed < 0) + error ("Can't read symbols from %s: %s", bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + if (number_of_symbols < 0) + error ("Can't read symbols from %s: %s", bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + + for (i = 0; i < number_of_symbols; i++) + { + sym = symbol_table[i]; + if (/*sym -> flags & BSF_GLOBAL*/ 1) + { + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + symaddr += addr; + + /* 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 -> flags & SEC_CODE) + ms_type = mst_text; + else if (sym -> section -> flags & SEC_DATA) + ms_type = mst_data; + else + ms_type = mst_unknown; + + record_minimal_symbol ((char *) sym -> name, symaddr, ms_type, + objfile); + } + } + do_cleanups (back_to); + } +} + + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to nlm_symfile_init, which + currently does nothing. + + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. We simplify it down to a single offset for all + symbols. FIXME. + + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + 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. + + Note that NLM files have two sets of information that is potentially + useful for building gdb's minimal symbol table. The first is a list + of the publically exported symbols, and is currently used to build + bfd's canonical symbol table. The second is an optional native debugging + format which contains additional symbols (and possibly duplicates of + the publically exported symbols). The optional native debugging format + is not currently used. */ + +static void +nlm_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile -> obfd; + struct cleanup *back_to; + CORE_ADDR offset; + struct symbol *mainsym; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + /* FIXME, should take a section_offsets param, not just an offset. */ + + offset = ANOFFSET (section_offsets, 0); + + /* Process the NLM export records, which become the bfd's canonical symbol + table. */ + + nlm_symtab_read (abfd, offset, objfile); + + stabsect_build_psymtabs (objfile, section_offsets, mainline, ".stab", + ".stabstr", ".text"); + + mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL); + + if (mainsym + && SYMBOL_CLASS(mainsym) == LOC_BLOCK) + { + objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym)); + objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym)); + } + + /* FIXME: We could locate and read the optional native debugging format + here and add the symbols to the minimal symbol table. */ + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + + +/* 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 +nlm_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_private != NULL) + { + mfree (objfile -> md, objfile -> sym_private); + } +} + +/* NLM specific parsing routine for section offsets. + FIXME: This may or may not be necessary. All the symbol readers seem + to have similar code. See if it can be generalized and moved elsewhere. */ + +static +struct section_offsets * +nlm_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + { + ANOFFSET (section_offsets, i) = addr; + } + + return (section_offsets); +} + + +/* Register that we are able to handle NLM file format. */ + +static struct sym_fns nlm_sym_fns = +{ + bfd_target_nlm_flavour, + nlm_new_init, /* sym_new_init: init anything gbl to entire symtab */ + nlm_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + nlm_symfile_read, /* sym_read: read a symbol file into symtab */ + nlm_symfile_finish, /* sym_finish: finished with file, cleanup */ + nlm_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_nlmread () +{ + add_symtab_fns (&nlm_sym_fns); +} diff --git a/contrib/gdb/gdb/notify.defs b/contrib/gdb/gdb/notify.defs new file mode 100644 index 000000000000..2014be5ca441 --- /dev/null +++ b/contrib/gdb/gdb/notify.defs @@ -0,0 +1 @@ +#include diff --git a/contrib/gdb/gdb/ns32k-tdep.c b/contrib/gdb/gdb/ns32k-tdep.c new file mode 100644 index 000000000000..58a0860bbe6d --- /dev/null +++ b/contrib/gdb/gdb/ns32k-tdep.c @@ -0,0 +1,27 @@ +/* Print NS 32000 instructions for GDB, the GNU debugger. + Copyright 1986, 1988, 1991, 1992, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +void +_initialize_ns32k_tdep () +{ + tm_print_insn = print_insn_ns32k; +} diff --git a/contrib/gdb/gdb/ns32km3-nat.c b/contrib/gdb/gdb/ns32km3-nat.c new file mode 100644 index 000000000000..89696ba0fcab --- /dev/null +++ b/contrib/gdb/gdb/ns32km3-nat.c @@ -0,0 +1,181 @@ +/* Low level interface to ns532 running mach 3.0. + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" + +#include + +#include +#include +#include +#include + +#define private static + + +/* Find offsets to thread states at compile time. + * If your compiler does not grok this, calculate offsets + * offsets yourself and use them (or get a compatible compiler :-) + */ + +#define REG_N_OFFSET(reg) (int)(&((struct ns532_combined_state *)0)->ts.reg) +#define REG_F_OFFSET(reg) (int)(&((struct ns532_combined_state *)0)->fs.reg) + +/* at reg_offset[i] is the offset to the ns532_combined_state + * location where the gdb registers[i] is stored. + */ + +static int reg_offset[] = +{ + REG_N_OFFSET(r0), REG_N_OFFSET(r1), REG_N_OFFSET(r2), REG_N_OFFSET(r3), + REG_N_OFFSET(r4), REG_N_OFFSET(r5), REG_N_OFFSET(r6), REG_N_OFFSET(r7), + REG_F_OFFSET(l0a), REG_F_OFFSET(l1a),REG_F_OFFSET(l2a),REG_F_OFFSET(l3a), + REG_F_OFFSET(l4a), REG_F_OFFSET(l5a),REG_F_OFFSET(l6a),REG_F_OFFSET(l7a), + REG_N_OFFSET(sp), REG_N_OFFSET(fp), REG_N_OFFSET(pc), REG_N_OFFSET(psr), + REG_F_OFFSET(fsr), + REG_F_OFFSET(l0a), REG_F_OFFSET(l2a),REG_F_OFFSET(l4a),REG_F_OFFSET(l6a) + /* @@@ 532 has more double length floating point regs, not accessed currently */ +}; + +/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM + * Caller knows that the regs handled in one transaction are of same size. + */ +#define FETCH_REGS(state, regnum, count) \ + memcpy (®isters[REGISTER_BYTE (regnum)], \ + (char *)state+reg_offset[ regnum ], \ + count*REGISTER_SIZE) + +/* Store COUNT contiguous registers to thread STATE starting from REGNUM */ +#define STORE_REGS(state, regnum, count) \ + memcpy ((char *)state+reg_offset[ regnum ], \ + ®isters[REGISTER_BYTE (regnum)], \ + count*REGISTER_SIZE) + +/* + * Fetch inferiors registers for gdb. + * REGNO specifies which (as gdb views it) register, -1 for all. + */ + +void +fetch_inferior_registers (regno) + int regno; +{ + kern_return_t ret; + thread_state_data_t state; + unsigned int stateCnt = NS532_COMBINED_STATE_COUNT; + int index; + + if (! MACH_PORT_VALID (current_thread)) + error ("fetch inferior registers: Invalid thread"); + + if (must_suspend_thread) + setup_thread (current_thread, 1); + + ret = thread_get_state (current_thread, + NS532_COMBINED_STATE, + state, + &stateCnt); + + if (ret != KERN_SUCCESS) + message ("fetch_inferior_registers: %s ", + mach_error_string (ret)); +#if 0 + /* It may be more effective to store validate all of them, + * since we fetched them all anyway + */ + else if (regno != -1) + supply_register (regno, (char *)state+reg_offset[regno]); +#endif + else + { + for (index = 0; index < NUM_REGS; index++) + supply_register (index, (char *)state+reg_offset[index]); + } + + if (must_suspend_thread) + setup_thread (current_thread, 0); +} + +/* Store our register values back into the inferior. + * If REGNO is -1, do this for all registers. + * Otherwise, REGNO specifies which register + * + * On mach3 all registers are always saved in one call. + */ +void +store_inferior_registers (regno) + int regno; +{ + kern_return_t ret; + thread_state_data_t state; + unsigned int stateCnt = NS532_COMBINED_STATE_COUNT; + register int index; + + if (! MACH_PORT_VALID (current_thread)) + error ("store inferior registers: Invalid thread"); + + if (must_suspend_thread) + setup_thread (current_thread, 1); + + /* Fetch the state of the current thread */ + ret = thread_get_state (current_thread, + NS532_COMBINED_STATE, + state, + &stateCnt); + + if (ret != KERN_SUCCESS) + { + message ("store_inferior_registers (get): %s", + mach_error_string (ret)); + if (must_suspend_thread) + setup_thread (current_thread, 0); + return; + } + + /* move gdb's registers to thread's state + * + * Since we save all registers anyway, save the ones + * that gdb thinks are valid (e.g. ignore the regno + * parameter) + */ +#if 0 + if (regno != -1) + STORE_REGS (state, regno, 1); + else +#endif + { + for (index = 0; index < NUM_REGS; index++) + STORE_REGS (state, index, 1); + } + + /* Write gdb's current view of register to the thread + */ + ret = thread_set_state (current_thread, + NS532_COMBINED_STATE, + state, + NS532_COMBINED_STATE_COUNT); + + if (ret != KERN_SUCCESS) + message ("store_inferior_registers (set): %s", + mach_error_string (ret)); + + if (must_suspend_thread) + setup_thread (current_thread, 0); +} diff --git a/contrib/gdb/gdb/objfiles.c b/contrib/gdb/gdb/objfiles.c new file mode 100644 index 000000000000..97b05dce3f1b --- /dev/null +++ b/contrib/gdb/gdb/objfiles.c @@ -0,0 +1,911 @@ +/* GDB routines for manipulating objfiles. + Copyright 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains support routines for creating, manipulating, and + destroying objfile structures. */ + +#include "defs.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "target.h" + +#include +#include "gdb_stat.h" +#include +#include "obstack.h" +#include "gdb_string.h" + +/* Prototypes for local functions */ + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + +static int +open_existing_mapped_file PARAMS ((char *, long, int)); + +static int +open_mapped_file PARAMS ((char *filename, long mtime, int mapped)); + +static CORE_ADDR +map_to_address PARAMS ((void)); + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + +/* Externally visible variables that are owned by this module. + See declarations in objfile.h for more info. */ + +struct objfile *object_files; /* Linked list of all objfiles */ +struct objfile *current_objfile; /* For symbol file being read in */ +struct objfile *symfile_objfile; /* Main symbol table loaded from */ +struct objfile *rt_common_objfile; /* For runtime common symbols */ + +int mapped_symbol_files; /* Try to use mapped symbol files */ + +/* 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. */ + +static void +add_to_objfile_sections (abfd, asect, objfile_p_char) + bfd *abfd; + sec_ptr asect; + PTR objfile_p_char; +{ + struct objfile *objfile = (struct objfile *) objfile_p_char; + 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)) + return; + section.offset = 0; + section.objfile = objfile; + section.the_bfd_section = asect; + section.addr = bfd_section_vma (abfd, asect); + section.endaddr = section.addr + bfd_section_size (abfd, asect); + obstack_grow (&objfile->psymbol_obstack, (char *) §ion, sizeof(section)); + objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1); +} + +/* Builds a section table for OBJFILE. + Returns 0 if OK, 1 on error (in which case bfd_error contains the + error). */ + +int +build_objfile_section_table (objfile) + struct objfile *objfile; +{ + /* objfile->sections can be already set when reading a mapped symbol + file. I believe that we do need to rebuild the section table in + this case (we rebuild other things derived from the bfd), but we + can't free the old one (it's in the psymbol_obstack). So we just + waste some memory. */ + + objfile->sections_end = 0; + bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *)objfile); + objfile->sections = (struct obj_section *) + obstack_finish (&objfile->psymbol_obstack); + objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end; + return(0); +} + +/* Given a pointer to an initialized bfd (ABFD) and a flag that indicates + whether or not an objfile is to be mapped (MAPPED), allocate a new objfile + struct, fill it in as best we can, link it into the list of all known + objfiles, and return a pointer to the new objfile struct. */ + +struct objfile * +allocate_objfile (abfd, mapped) + bfd *abfd; + int mapped; +{ + struct objfile *objfile = NULL; + struct objfile *last_one = NULL; + + mapped |= mapped_symbol_files; + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + { + + /* If we can support mapped symbol files, try to open/reopen the + mapped file that corresponds to the file from which we wish to + read symbols. If the objfile is to be mapped, we must malloc + the structure itself using the mmap version, and arrange that + all memory allocation for the objfile uses the mmap routines. + If we are reusing an existing mapped file, from which we get + our objfile pointer, we have to make sure that we update the + pointers to the alloc/free functions in the obstack, in case + these functions have moved within the current gdb. */ + + int fd; + + fd = open_mapped_file (bfd_get_filename (abfd), bfd_get_mtime (abfd), + mapped); + if (fd >= 0) + { + CORE_ADDR mapto; + PTR md; + + if (((mapto = map_to_address ()) == 0) || + ((md = mmalloc_attach (fd, (PTR) mapto)) == NULL)) + { + close (fd); + } + else if ((objfile = (struct objfile *) mmalloc_getkey (md, 0)) != NULL) + { + /* Update memory corruption handler function addresses. */ + init_malloc (md); + objfile -> md = md; + objfile -> mmfd = fd; + /* Update pointers to functions to *our* copies */ + obstack_chunkfun (&objfile -> psymbol_cache.cache, xmmalloc); + obstack_freefun (&objfile -> psymbol_cache.cache, mfree); + obstack_chunkfun (&objfile -> psymbol_obstack, xmmalloc); + obstack_freefun (&objfile -> psymbol_obstack, mfree); + obstack_chunkfun (&objfile -> symbol_obstack, xmmalloc); + obstack_freefun (&objfile -> symbol_obstack, mfree); + obstack_chunkfun (&objfile -> type_obstack, xmmalloc); + obstack_freefun (&objfile -> type_obstack, mfree); + /* If already in objfile list, unlink it. */ + unlink_objfile (objfile); + /* Forget things specific to a particular gdb, may have changed. */ + objfile -> sf = NULL; + } + else + { + + /* Set up to detect internal memory corruption. MUST be + done before the first malloc. See comments in + init_malloc() and mmcheck(). */ + + init_malloc (md); + + objfile = (struct objfile *) + xmmalloc (md, sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile -> md = md; + objfile -> mmfd = fd; + objfile -> flags |= OBJF_MAPPED; + mmalloc_setkey (objfile -> md, 0, objfile); + obstack_specify_allocation_with_arg (&objfile -> psymbol_cache.cache, + 0, 0, xmmalloc, mfree, + objfile -> md); + obstack_specify_allocation_with_arg (&objfile -> psymbol_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + obstack_specify_allocation_with_arg (&objfile -> symbol_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + obstack_specify_allocation_with_arg (&objfile -> type_obstack, + 0, 0, xmmalloc, mfree, + objfile -> md); + } + } + + if (mapped && (objfile == NULL)) + { + warning ("symbol table for '%s' will not be mapped", + bfd_get_filename (abfd)); + } + } +#else /* defined(NO_MMALLOC) || !defined(HAVE_MMAP) */ + + if (mapped) + { + warning ("mapped symbol tables are not supported on this machine; missing or broken mmap()."); + + /* Turn off the global flag so we don't try to do mapped symbol tables + any more, which shuts up gdb unless the user specifically gives the + "mapped" keyword again. */ + + mapped_symbol_files = 0; + } + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + + /* If we don't support mapped symbol files, didn't ask for the file to be + mapped, or failed to open the mapped file for some reason, then revert + back to an unmapped objfile. */ + + if (objfile == NULL) + { + objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile -> md = NULL; + obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0, + xmalloc, free); + obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc, + free); + } + + /* Update the per-objfile information that comes from the bfd, ensuring + that any data that is reference is saved in the per-objfile data + region. */ + + objfile -> obfd = abfd; + if (objfile -> name != NULL) + { + mfree (objfile -> md, objfile -> name); + } + objfile -> name = mstrsave (objfile -> md, 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 ())); + } + + /* Add this file onto the tail of the linked list of other such files. */ + + objfile -> next = NULL; + if (object_files == NULL) + object_files = objfile; + else + { + for (last_one = object_files; + last_one -> next; + last_one = last_one -> next); + last_one -> next = objfile; + } + return (objfile); +} + +/* Put OBJFILE at the front of the list. */ + +void +objfile_to_front (objfile) + struct objfile *objfile; +{ + struct objfile **objp; + for (objp = &object_files; *objp != NULL; objp = &((*objp)->next)) + { + if (*objp == objfile) + { + /* Unhook it from where it is. */ + *objp = objfile->next; + /* Put it in the front. */ + objfile->next = object_files; + object_files = objfile; + break; + } + } +} + +/* Unlink OBJFILE from the list of known objfiles, if it is found in the + list. + + It is not a bug, or error, to call this function if OBJFILE is not known + to be in the current list. This is done in the case of mapped objfiles, + for example, just to ensure that the mapped objfile doesn't appear twice + in the list. Since the list is threaded, linking in a mapped objfile + twice would create a circular list. + + If OBJFILE turns out to be in the list, we zap it's NEXT pointer after + unlinking it, just to ensure that we have completely severed any linkages + between the OBJFILE and the list. */ + +void +unlink_objfile (objfile) + struct objfile *objfile; +{ + struct objfile** objpp; + + for (objpp = &object_files; *objpp != NULL; objpp = &((*objpp) -> next)) + { + if (*objpp == objfile) + { + *objpp = (*objpp) -> next; + objfile -> next = NULL; + break; + } + } +} + + +/* Destroy an objfile and all the symtabs and psymtabs under it. Note + that as much as possible is allocated on the symbol_obstack and + psymbol_obstack, so that the memory can be efficiently freed. + + Things which we do NOT free because they are not in malloc'd memory + or not in memory specific to the objfile include: + + objfile -> sf + + FIXME: If the objfile is using reusable symbol information (via mmalloc), + then we need to take into account the fact that more than one process + may be using the symbol information at the same time (when mmalloc is + extended to support cooperative locking). When more than one process + is using the mapped symbol info, we need to be more careful about when + we free objects in the reusable area. */ + +void +free_objfile (objfile) + struct 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 + these routines is responsible for doing the correct thing, either + freeing things which are valid only during this particular gdb + execution, or leaving them to be reused during the next one. */ + + if (objfile -> sf != NULL) + { + (*objfile -> sf -> sym_finish) (objfile); + } + + /* We always close the bfd. */ + + if (objfile -> obfd != NULL) + { + char *name = bfd_get_filename (objfile->obfd); + if (!bfd_close (objfile -> obfd)) + warning ("cannot close \"%s\": %s", + name, bfd_errmsg (bfd_get_error ())); + free (name); + } + + /* Remove it from the chain of all objfiles. */ + + unlink_objfile (objfile); + + /* If we are going to free the runtime common objfile, mark it + as unallocated. */ + + if (objfile == rt_common_objfile) + rt_common_objfile = NULL; + + /* Before the symbol table code was redone to make it easier to + selectively load and remove information particular to a specific + linkage unit, gdb used to do these things whenever the monolithic + symbol table was blown away. How much still needs to be done + is unknown, but we play it safe for now and keep each action until + it is shown to be no longer needed. */ + +#if defined (CLEAR_SOLIB) + CLEAR_SOLIB (); + /* CLEAR_SOLIB closes the bfd's for any shared libraries. But + the to_sections for a core file might refer to those bfd's. So + detach any core file. */ + { + struct target_ops *t = find_core_target (); + if (t != NULL) + (t->to_detach) (NULL, 0); + } +#endif + /* I *think* all our callers call clear_symtab_users. If so, no need + to call this here. */ + clear_pc_function_cache (); + + /* The last thing we do is free the objfile struct itself for the + non-reusable case, or detach from the mapped file for the reusable + case. Note that the mmalloc_detach or the mfree is the last thing + we can do with this objfile. */ + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + + if (objfile -> flags & OBJF_MAPPED) + { + /* Remember the fd so we can close it. We can't close it before + doing the detach, and after the detach the objfile is gone. */ + int mmfd; + + mmfd = objfile -> mmfd; + mmalloc_detach (objfile -> md); + objfile = NULL; + close (mmfd); + } + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + + /* If we still have an objfile, then either we don't support reusable + objfiles or this one was not reusable. So free it normally. */ + + if (objfile != NULL) + { + if (objfile -> name != NULL) + { + mfree (objfile -> md, objfile -> name); + } + if (objfile->global_psymbols.list) + mfree (objfile->md, objfile->global_psymbols.list); + if (objfile->static_psymbols.list) + mfree (objfile->md, objfile->static_psymbols.list); + /* Free the obstacks for non-reusable objfiles */ + obstack_free (&objfile -> psymbol_cache.cache, 0); + obstack_free (&objfile -> psymbol_obstack, 0); + obstack_free (&objfile -> symbol_obstack, 0); + obstack_free (&objfile -> type_obstack, 0); + mfree (objfile -> md, objfile); + objfile = NULL; + } +} + + +/* Free all the object files at once and clean up their users. */ + +void +free_all_objfiles () +{ + struct objfile *objfile, *temp; + + ALL_OBJFILES_SAFE (objfile, temp) + { + free_objfile (objfile); + } + clear_symtab_users (); +} + +/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS + entries in new_offsets. */ +void +objfile_relocate (objfile, new_offsets) + struct objfile *objfile; + struct section_offsets *new_offsets; +{ + struct section_offsets *delta = (struct section_offsets *) alloca + (sizeof (struct section_offsets) + + objfile->num_sections * sizeof (delta->offsets)); + + { + int i; + int something_changed = 0; + for (i = 0; i < objfile->num_sections; ++i) + { + ANOFFSET (delta, i) = + ANOFFSET (new_offsets, i) - ANOFFSET (objfile->section_offsets, i); + if (ANOFFSET (delta, i) != 0) + something_changed = 1; + } + if (!something_changed) + return; + } + + /* OK, get all the symtabs. */ + { + struct symtab *s; + + ALL_OBJFILE_SYMTABS (objfile, s) + { + struct linetable *l; + struct blockvector *bv; + int i; + + /* First the line table. */ + l = LINETABLE (s); + if (l) + { + for (i = 0; i < l->nitems; ++i) + l->item[i].pc += ANOFFSET (delta, s->block_line_section); + } + + /* Don't relocate a shared blockvector more than once. */ + if (!s->primary) + continue; + + bv = BLOCKVECTOR (s); + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i) + { + struct block *b; + int j; + + b = BLOCKVECTOR_BLOCK (bv, i); + BLOCK_START (b) += ANOFFSET (delta, s->block_line_section); + BLOCK_END (b) += ANOFFSET (delta, s->block_line_section); + + for (j = 0; j < BLOCK_NSYMS (b); ++j) + { + struct symbol *sym = BLOCK_SYM (b, j); + /* The RS6000 code from which this was taken skipped + any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE. + But I'm leaving out that test, on the theory that + they can't possibly pass the tests below. */ + if ((SYMBOL_CLASS (sym) == LOC_LABEL + || SYMBOL_CLASS (sym) == LOC_STATIC) + && SYMBOL_SECTION (sym) >= 0) + { + SYMBOL_VALUE_ADDRESS (sym) += + ANOFFSET (delta, SYMBOL_SECTION (sym)); + } +#ifdef MIPS_EFI_SYMBOL_NAME + /* Relocate Extra Function Info for ecoff. */ + + else + if (SYMBOL_CLASS (sym) == LOC_CONST + && SYMBOL_NAMESPACE (sym) == LABEL_NAMESPACE + && STRCMP (SYMBOL_NAME (sym), MIPS_EFI_SYMBOL_NAME) == 0) + ecoff_relocate_efi (sym, ANOFFSET (delta, s->block_line_section)); +#endif + } + } + } + } + + { + struct partial_symtab *p; + + ALL_OBJFILE_PSYMTABS (objfile, p) + { + p->textlow += ANOFFSET (delta, SECT_OFF_TEXT); + p->texthigh += ANOFFSET (delta, SECT_OFF_TEXT); + } + } + + { + struct partial_symbol **psym; + + for (psym = objfile->global_psymbols.list; + psym < objfile->global_psymbols.next; + psym++) + if (SYMBOL_SECTION (*psym) >= 0) + SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, SYMBOL_SECTION (*psym)); + for (psym = objfile->static_psymbols.list; + psym < objfile->static_psymbols.next; + psym++) + if (SYMBOL_SECTION (*psym) >= 0) + SYMBOL_VALUE_ADDRESS (*psym) += ANOFFSET (delta, SYMBOL_SECTION (*psym)); + } + + { + struct minimal_symbol *msym; + ALL_OBJFILE_MSYMBOLS (objfile, msym) + if (SYMBOL_SECTION (msym) >= 0) + SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym)); + } + /* Relocating different sections by different amounts may cause the symbols + to be out of order. */ + msymbols_sort (objfile); + + { + int i; + for (i = 0; i < objfile->num_sections; ++i) + ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i); + } + + { + struct obj_section *s; + bfd *abfd; + + abfd = objfile->obfd; + + for (s = objfile->sections; + s < objfile->sections_end; ++s) + { + flagword flags; + + flags = bfd_get_section_flags (abfd, s->the_bfd_section); + + if (flags & SEC_CODE) + { + s->addr += ANOFFSET (delta, SECT_OFF_TEXT); + s->endaddr += ANOFFSET (delta, SECT_OFF_TEXT); + } + else if (flags & (SEC_DATA | SEC_LOAD)) + { + s->addr += ANOFFSET (delta, SECT_OFF_DATA); + s->endaddr += ANOFFSET (delta, SECT_OFF_DATA); + } + else if (flags & SEC_ALLOC) + { + s->addr += ANOFFSET (delta, SECT_OFF_BSS); + s->endaddr += ANOFFSET (delta, SECT_OFF_BSS); + } + } + } + + if (objfile->ei.entry_point != ~0) + objfile->ei.entry_point += ANOFFSET (delta, SECT_OFF_TEXT); + + if (objfile->ei.entry_func_lowpc != INVALID_ENTRY_LOWPC) + { + objfile->ei.entry_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.entry_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + } + + if (objfile->ei.entry_file_lowpc != INVALID_ENTRY_LOWPC) + { + objfile->ei.entry_file_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.entry_file_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + } + + if (objfile->ei.main_func_lowpc != INVALID_ENTRY_LOWPC) + { + objfile->ei.main_func_lowpc += ANOFFSET (delta, SECT_OFF_TEXT); + objfile->ei.main_func_highpc += ANOFFSET (delta, SECT_OFF_TEXT); + } +} + +/* Many places in gdb want to test just to see if we have any partial + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_partial_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> psymtabs != NULL) + { + return 1; + } + } + return 0; +} + +/* Many places in gdb want to test just to see if we have any full + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_full_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> symtabs != NULL) + { + return 1; + } + } + return 0; +} + +/* Many places in gdb want to test just to see if we have any minimal + symbols available. This function returns zero if none are currently + available, nonzero otherwise. */ + +int +have_minimal_symbols () +{ + struct objfile *ofp; + + ALL_OBJFILES (ofp) + { + if (ofp -> msymbols != NULL) + { + return 1; + } + } + return 0; +} + +#if !defined(NO_MMALLOC) && defined(HAVE_MMAP) + +/* Given the name of a mapped symbol file in SYMSFILENAME, and the timestamp + of the corresponding symbol file in MTIME, try to open an existing file + with the name SYMSFILENAME and verify it is more recent than the base + file by checking it's timestamp against MTIME. + + If SYMSFILENAME does not exist (or can't be stat'd), simply returns -1. + + If SYMSFILENAME does exist, but is out of date, we check to see if the + user has specified creation of a mapped file. If so, we don't issue + any warning message because we will be creating a new mapped file anyway, + overwriting the old one. If not, then we issue a warning message so that + the user will know why we aren't using this existing mapped symbol file. + In either case, we return -1. + + If SYMSFILENAME does exist and is not out of date, but can't be opened for + some reason, then prints an appropriate system error message and returns -1. + + Otherwise, returns the open file descriptor. */ + +static int +open_existing_mapped_file (symsfilename, mtime, mapped) + char *symsfilename; + long mtime; + int mapped; +{ + int fd = -1; + struct stat sbuf; + + if (stat (symsfilename, &sbuf) == 0) + { + if (sbuf.st_mtime < mtime) + { + if (!mapped) + { + warning ("mapped symbol file `%s' is out of date, ignored it", + symsfilename); + } + } + else if ((fd = open (symsfilename, O_RDWR)) < 0) + { + if (error_pre_print) + { + printf_unfiltered (error_pre_print); + } + print_sys_errmsg (symsfilename, errno); + } + } + return (fd); +} + +/* Look for a mapped symbol file that corresponds to FILENAME and is more + recent than MTIME. If MAPPED is nonzero, the user has asked that gdb + use a mapped symbol file for this file, so create a new one if one does + not currently exist. + + If found, then return an open file descriptor for the file, otherwise + return -1. + + This routine is responsible for implementing the policy that generates + the name of the mapped symbol file from the name of a file containing + symbols that gdb would like to read. Currently this policy is to append + ".syms" to the name of the file. + + This routine is also responsible for implementing the policy that + determines where the mapped symbol file is found (the search path). + This policy is that when reading an existing mapped file, a file of + the correct name in the current directory takes precedence over a + file of the correct name in the same directory as the symbol file. + When creating a new mapped file, it is always created in the current + directory. This helps to minimize the chances of a user unknowingly + creating big mapped files in places like /bin and /usr/local/bin, and + allows a local copy to override a manually installed global copy (in + /bin for example). */ + +static int +open_mapped_file (filename, mtime, mapped) + char *filename; + long mtime; + int mapped; +{ + int fd; + char *symsfilename; + + /* First try to open an existing file in the current directory, and + then try the directory where the symbol file is located. */ + + symsfilename = concat ("./", basename (filename), ".syms", (char *) NULL); + if ((fd = open_existing_mapped_file (symsfilename, mtime, mapped)) < 0) + { + free (symsfilename); + symsfilename = concat (filename, ".syms", (char *) NULL); + fd = open_existing_mapped_file (symsfilename, mtime, mapped); + } + + /* If we don't have an open file by now, then either the file does not + already exist, or the base file has changed since it was created. In + either case, if the user has specified use of a mapped file, then + create a new mapped file, truncating any existing one. If we can't + create one, print a system error message saying why we can't. + + By default the file is rw for everyone, with the user's umask taking + care of turning off the permissions the user wants off. */ + + if ((fd < 0) && mapped) + { + free (symsfilename); + symsfilename = concat ("./", basename (filename), ".syms", + (char *) NULL); + if ((fd = open (symsfilename, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) + { + if (error_pre_print) + { + printf_unfiltered (error_pre_print); + } + print_sys_errmsg (symsfilename, errno); + } + } + + free (symsfilename); + return (fd); +} + +/* Return the base address at which we would like the next objfile's + mapped data to start. + + For now, we use the kludge that the configuration specifies a base + address to which it is safe to map the first mmalloc heap, and an + increment to add to this address for each successive heap. There are + a lot of issues to deal with here to make this work reasonably, including: + + Avoid memory collisions with existing mapped address spaces + + Reclaim address spaces when their mmalloc heaps are unmapped + + When mmalloc heaps are shared between processes they have to be + mapped at the same addresses in each + + Once created, a mmalloc heap that is to be mapped back in must be + mapped at the original address. I.E. each objfile will expect to + be remapped at it's original address. This becomes a problem if + the desired address is already in use. + + etc, etc, etc. + + */ + + +static CORE_ADDR +map_to_address () +{ + +#if defined(MMAP_BASE_ADDRESS) && defined (MMAP_INCREMENT) + + static CORE_ADDR next = MMAP_BASE_ADDRESS; + CORE_ADDR mapto = next; + + next += MMAP_INCREMENT; + return (mapto); + +#else + + warning ("need to recompile gdb with MMAP_BASE_ADDRESS and MMAP_INCREMENT defined"); + return (0); + +#endif + +} + +#endif /* !defined(NO_MMALLOC) && defined(HAVE_MMAP) */ + +/* Returns a section whose range includes PC or NULL if none found. */ + +struct obj_section * +find_pc_section(pc) + CORE_ADDR pc; +{ + struct obj_section *s; + struct objfile *objfile; + + ALL_OBJFILES (objfile) + for (s = objfile->sections; s < objfile->sections_end; ++s) + if (s->addr <= pc + && pc < s->endaddr) + return(s); + + return(NULL); +} + +/* In SVR4, we recognize a trampoline by it's section name. + That is, if the pc is in a section named ".plt" then we are in + a trampoline. */ + +int +in_plt_section(pc, name) + CORE_ADDR pc; + char *name; +{ + struct obj_section *s; + int retval = 0; + + s = find_pc_section(pc); + + retval = (s != NULL + && s->the_bfd_section->name != NULL + && STREQ (s->the_bfd_section->name, ".plt")); + return(retval); +} diff --git a/contrib/gdb/gdb/objfiles.h b/contrib/gdb/gdb/objfiles.h new file mode 100644 index 000000000000..b98b7088fe7e --- /dev/null +++ b/contrib/gdb/gdb/objfiles.h @@ -0,0 +1,502 @@ +/* Definitions for symbol file management in GDB. + Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (OBJFILES_H) +#define OBJFILES_H + +/* This structure maintains information on a per-objfile basis about the + "entry point" of the objfile, and the scope within which the entry point + exists. It is possible that gdb will see more than one objfile that is + executable, each with its own entry point. + + For example, for dynamically linked executables in SVR4, the dynamic linker + code is contained within the shared C library, which is actually executable + and is run by the kernel first when an exec is done of a user executable + that is dynamically linked. The dynamic linker within the shared C library + then maps in the various program segments in the user executable and jumps + to the user executable's recorded entry point, as if the call had been made + directly by the kernel. + + The traditional gdb method of using this info is to use the recorded entry + point to set the variables entry_file_lowpc and entry_file_highpc from + the debugging information, where these values are the starting address + (inclusive) and ending address (exclusive) of the instruction space in the + executable which correspond to the "startup file", I.E. crt0.o in most + cases. This file is assumed to be a startup file and frames with pc's + inside it are treated as nonexistent. Setting these variables is necessary + so that backtraces do not fly off the bottom of the stack. + + Gdb also supports an alternate method to avoid running off the bottom + of the stack. + + There are two frames that are "special", the frame for the function + containing the process entry point, since it has no predecessor frame, + and the frame for the function containing the user code entry point + (the main() function), since all the predecessor frames are for the + process startup code. Since we have no guarantee that the linked + in startup modules have any debugging information that gdb can use, + we need to avoid following frame pointers back into frames that might + have been built in the startup code, as we might get hopelessly + confused. However, we almost always have debugging information + available for main(). + + These variables are used to save the range of PC values which are valid + within the main() function and within the function containing the process + entry point. If we always consider the frame for main() as the outermost + frame when debugging user code, and the frame for the process entry + point function as the outermost frame when debugging startup code, then + all we have to do is have FRAME_CHAIN_VALID return false whenever a + frame's current PC is within the range specified by these variables. + In essence, we set "ceilings" in the frame chain beyond which we will + not proceed when following the frame chain back up the stack. + + A nice side effect is that we can still debug startup code without + running off the end of the frame chain, assuming that we have usable + debugging information in the startup modules, and if we choose to not + use the block at main, or can't find it for some reason, everything + still works as before. And if we have no startup code debugging + information but we do have usable information for main(), backtraces + from user code don't go wandering off into the startup code. + + To use this method, define your FRAME_CHAIN_VALID macro like: + + #define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 \ + && !(inside_main_func ((thisframe)->pc)) \ + && !(inside_entry_func ((thisframe)->pc))) + + and add initializations of the four scope controlling variables inside + the object file / debugging information processing modules. */ + +struct entry_info +{ + + /* The value we should use for this objects entry point. + The illegal/unknown value needs to be something other than 0, ~0 + for instance, which is much less likely than 0. */ + + CORE_ADDR entry_point; + +#define INVALID_ENTRY_POINT (~0) /* ~0 will not be in any file, we hope. */ + + /* Start (inclusive) and end (exclusive) of function containing the + entry point. */ + + CORE_ADDR entry_func_lowpc; + CORE_ADDR entry_func_highpc; + + /* Start (inclusive) and end (exclusive) of object file containing the + entry point. */ + + CORE_ADDR entry_file_lowpc; + CORE_ADDR entry_file_highpc; + + /* Start (inclusive) and end (exclusive) of the user code main() function. */ + + CORE_ADDR main_func_lowpc; + CORE_ADDR main_func_highpc; + +/* Use these values when any of the above ranges is invalid. */ + +/* We use these values because it guarantees that there is no number that is + both >= LOWPC && < HIGHPC. It is also highly unlikely that 3 is a valid + module or function start address (as opposed to 0). */ + +#define INVALID_ENTRY_LOWPC (3) +#define INVALID_ENTRY_HIGHPC (1) + +}; + +/* Sections in an objfile. + + It is strange that we have both this notion of "sections" + and the one used by section_offsets. Section as used + here, (currently at least) means a BFD section, and the sections + are set up from the BFD sections in allocate_objfile. + + The sections in section_offsets have their meaning determined by + the symbol format, and they are set up by the sym_offsets function + for that symbol file format. + + I'm not sure this could or should be changed, however. */ + +struct obj_section { + CORE_ADDR addr; /* lowest address in section */ + CORE_ADDR endaddr; /* 1+highest address in section */ + + /* This field is being used for nefarious purposes by syms_from_objfile. + It is said to be redundant with section_offsets; it's not really being + used that way, however, it's some sort of hack I don't understand + and am not going to try to eliminate (yet, anyway). FIXME. + + It was documented as "offset between (end)addr and actual memory + addresses", but that's not true; addr & endaddr are actual memory + addresses. */ + CORE_ADDR offset; + + sec_ptr the_bfd_section; /* BFD section pointer */ + + /* Objfile this section is part of. */ + struct objfile *objfile; +}; + +/* The "objstats" structure provides a place for gdb to record some + interesting information about its internal state at runtime, on a + per objfile basis, such as information about the number of symbols + read, size of string table (if any), etc. */ + +#if MAINTENANCE_CMDS + +struct objstats { + int n_minsyms; /* Number of minimal symbols read */ + int n_psyms; /* Number of partial symbols read */ + int n_syms; /* Number of full symbols read */ + int n_stabs; /* Number of ".stabs" read (if applicable) */ + int n_types; /* Number of types */ + int sz_strtab; /* Size of stringtable, (if applicable) */ +}; + +#define OBJSTAT(objfile, expr) (objfile -> stats.expr) +#define OBJSTATS struct objstats stats +extern void print_objfile_statistics PARAMS ((void)); +extern void print_symbol_bcache_statistics PARAMS ((void)); + +#else + +#define OBJSTAT(objfile, expr) /* Nothing */ +#define OBJSTATS /* Nothing */ + +#endif /* MAINTENANCE_CMDS */ + +/* 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, + 2. Additional symbol files added by the add-symbol-file command, + 3. Shared library objfiles, added by ADD_SOLIB, 4. symbol files + for modules that were loaded when GDB attached to a remote system + (see remote-vx.c). */ + +struct objfile +{ + + /* All struct objfile's are chained together by their next pointers. + The global variable "object_files" points to the first link in this + chain. + + FIXME: There is a problem here if the objfile is reusable, and if + multiple users are to be supported. The problem is that the objfile + list is linked through a member of the objfile struct itself, which + is only valid for one gdb process. The list implementation needs to + be changed to something like: + + struct list {struct list *next; struct objfile *objfile}; + + where the list structure is completely maintained separately within + each gdb process. */ + + struct objfile *next; + + /* The object file's name. Malloc'd; free it if you free this struct. */ + + char *name; + + /* Some flag bits for this objfile. */ + + unsigned short flags; + + /* Each objfile points to a linked list of symtabs derived from this file, + one symtab structure for each compilation unit (source file). Each link + in the symtab list contains a backpointer to this objfile. */ + + struct symtab *symtabs; + + /* Each objfile points to a linked list of partial symtabs derived from + this file, one partial symtab structure for each compilation unit + (source file). */ + + struct partial_symtab *psymtabs; + + /* List of freed partial symtabs, available for re-use */ + + struct partial_symtab *free_psymtabs; + + /* The object file's BFD. Can be null if the objfile contains only + minimal symbols, e.g. the run time common symbols for SunOS4. */ + + bfd *obfd; + + /* The modification timestamp of the object file, as of the last time + we read its symbols. */ + + long mtime; + + /* Obstacks to hold objects that should be freed when we load a new symbol + table from this object file. */ + + struct obstack psymbol_obstack; /* Partial symbols */ + struct obstack symbol_obstack; /* Full symbols */ + struct obstack type_obstack; /* Types */ + + /* A byte cache where we can stash arbitrary "chunks" of bytes that + will not change. */ + + struct bcache psymbol_cache; /* Byte cache for partial syms */ + + /* Vectors of all partial symbols read in from file. The actual data + is stored in the psymbol_obstack. */ + + struct psymbol_allocation_list global_psymbols; + struct psymbol_allocation_list static_psymbols; + + /* Each file contains a pointer to an array of minimal symbols for all + global symbols that are defined within the file. The array is terminated + by a "null symbol", one that has a NULL pointer for the name and a zero + value for the address. This makes it easy to walk through the array + when passed a pointer to somewhere in the middle of it. There is also + a count of the number of symbols, which does not include the terminating + null symbol. The array itself, as well as all the data that it points + to, should be allocated on the symbol_obstack for this file. */ + + struct minimal_symbol *msymbols; + int minimal_symbol_count; + + /* For object file formats which don't specify fundamental types, gdb + can create such types. For now, it maintains a vector of pointers + to these internally created fundamental types on a per objfile basis, + however it really should ultimately keep them on a per-compilation-unit + basis, to account for linkage-units that consist of a number of + compilation units that may have different fundamental types, such as + linking C modules with ADA modules, or linking C modules that are + compiled with 32-bit ints with C modules that are compiled with 64-bit + ints (not inherently evil with a smarter linker). */ + + struct type **fundamental_types; + + /* The mmalloc() malloc-descriptor for this objfile if we are using + the memory mapped malloc() package to manage storage for this objfile's + data. NULL if we are not. */ + + PTR md; + + /* The file descriptor that was used to obtain the mmalloc descriptor + for this objfile. If we call mmalloc_detach with the malloc descriptor + we should then close this file descriptor. */ + + int mmfd; + + /* Structure which keeps track of functions that manipulate objfile's + of the same type as this objfile. I.E. the function to read partial + symbols for example. Note that this structure is in statically + allocated memory, and is shared by all objfiles that use the + object module reader of this type. */ + + struct sym_fns *sf; + + /* The per-objfile information about the entry point, the scope (file/func) + containing the entry point, and the scope of the user's main() func. */ + + struct entry_info ei; + + /* Information about stabs. Will be filled in with a dbx_symfile_info + struct by those readers that need it. */ + + PTR 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. */ + + PTR sym_private; + + /* Hook for target-architecture-specific information. This must + point to memory allocated on one of the obstacks in this objfile, + so that it gets freed automatically when reading a new object + file. */ + + PTR obj_private; + + /* Set of relocation offsets to apply to each section. + Currently on the psymbol_obstack (which makes no sense, but I'm + not sure it's harming anything). + + 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. */ + + struct section_offsets *section_offsets; + int num_sections; + + /* set of section begin and end addresses used to map pc addresses + into sections. Currently on the psymbol_obstack (which makes no + sense, but I'm not sure it's harming anything). */ + + struct obj_section + *sections, + *sections_end; + + /* two auxiliary fields, used to hold the fp of separate symbol files */ + FILE *auxf1, *auxf2; + + /* Place to stash various statistics about this objfile */ + OBJSTATS; +}; + +/* Defines for the objfile flag word. */ + +/* Gdb can arrange to allocate storage for all objects related to a + particular objfile in a designated section of its address space, + managed at a low level by mmap() and using a special version of + malloc that handles malloc/free/realloc on top of the mmap() interface. + This allows the "internal gdb state" for a particular objfile to be + dumped to a gdb state file and subsequently reloaded at a later time. */ + +#define OBJF_MAPPED (1 << 0) /* Objfile data is mmap'd */ + +/* When using mapped/remapped predigested gdb symbol information, we need + a flag that indicates that we have previously done an initial symbol + table read from this particular objfile. We can't just look for the + absence of any of the three symbol tables (msymbols, psymtab, symtab) + because if the file has no symbols for example, none of these will + exist. */ + +#define OBJF_SYMS (1 << 1) /* Have tried to read symbols */ + +/* When an object file has its functions reordered (currently Irix-5.2 + shared libraries exhibit this behaviour), we will need an expensive + algorithm to locate a partial symtab or symtab via an address. + To avoid this penalty for normal object files, we use this flag, + whose setting is determined upon symbol table read in. */ + +#define OBJF_REORDERED (2 << 1) /* Functions are reordered */ + +/* The object file that the main symbol table was loaded from (e.g. the + argument to the "symbol-file" or "file" command). */ + +extern struct objfile *symfile_objfile; + +/* The object file that contains the runtime common minimal symbols + for SunOS4. Note that this objfile has no associated BFD. */ + +extern struct objfile *rt_common_objfile; + +/* When we need to allocate a new type, we need to know which type_obstack + to allocate the type on, since there is one for each objfile. The places + where types are allocated are deeply buried in function call hierarchies + which know nothing about objfiles, so rather than trying to pass a + particular objfile down to them, we just do an end run around them and + set current_objfile to be whatever objfile we expect to be using at the + time types are being allocated. For instance, when we start reading + symbols for a particular objfile, we set current_objfile to point to that + objfile, and when we are done, we set it back to NULL, to ensure that we + never put a type someplace other than where we are expecting to put it. + FIXME: Maybe we should review the entire type handling system and + see if there is a better way to avoid this problem. */ + +extern struct objfile *current_objfile; + +/* All known objfiles are kept in a linked list. This points to the + root of this list. */ + +extern struct objfile *object_files; + +/* Declarations for functions defined in objfiles.c */ + +extern struct objfile * +allocate_objfile PARAMS ((bfd *, int)); + +extern int +build_objfile_section_table PARAMS ((struct objfile *)); + +extern void objfile_to_front PARAMS ((struct objfile *)); + +extern void +unlink_objfile PARAMS ((struct objfile *)); + +extern void +free_objfile PARAMS ((struct objfile *)); + +extern void +free_all_objfiles PARAMS ((void)); + +extern void +objfile_relocate PARAMS ((struct objfile *, struct section_offsets *)); + +extern int +have_partial_symbols PARAMS ((void)); + +extern int +have_full_symbols PARAMS ((void)); + +/* Functions for dealing with the minimal symbol table, really a misc + address<->symbol mapping for things we don't have debug symbols for. */ + +extern int +have_minimal_symbols PARAMS ((void)); + +extern struct obj_section * +find_pc_section PARAMS((CORE_ADDR pc)); + +/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete + the objfile during the traversal. */ + +#define ALL_OBJFILES(obj) \ + for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next) + +#define ALL_OBJFILES_SAFE(obj,nxt) \ + for ((obj) = object_files; \ + (obj) != NULL? ((nxt)=(obj)->next,1) :0; \ + (obj) = (nxt)) + +/* Traverse all symtabs in one objfile. */ + +#define ALL_OBJFILE_SYMTABS(objfile, s) \ + for ((s) = (objfile) -> symtabs; (s) != NULL; (s) = (s) -> next) + +/* Traverse all psymtabs in one objfile. */ + +#define ALL_OBJFILE_PSYMTABS(objfile, p) \ + for ((p) = (objfile) -> psymtabs; (p) != NULL; (p) = (p) -> next) + +/* Traverse all minimal symbols in one objfile. */ + +#define ALL_OBJFILE_MSYMBOLS(objfile, m) \ + for ((m) = (objfile) -> msymbols; SYMBOL_NAME(m) != NULL; (m)++) + +/* Traverse all symtabs in all objfiles. */ + +#define ALL_SYMTABS(objfile, s) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_SYMTABS (objfile, s) + +/* Traverse all psymtabs in all objfiles. */ + +#define ALL_PSYMTABS(objfile, p) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_PSYMTABS (objfile, p) + +/* Traverse all minimal symbols in all objfiles. */ + +#define ALL_MSYMBOLS(objfile, m) \ + ALL_OBJFILES (objfile) \ + if ((objfile)->msymbols) \ + ALL_OBJFILE_MSYMBOLS (objfile, m) + +#endif /* !defined (OBJFILES_H) */ diff --git a/contrib/gdb/gdb/op50-rom.c b/contrib/gdb/gdb/op50-rom.c new file mode 100644 index 000000000000..f8cb7fafe199 --- /dev/null +++ b/contrib/gdb/gdb/op50-rom.c @@ -0,0 +1,146 @@ +/* Remote target glue for the Oki op50n based eval board. + + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void op50n_open PARAMS ((char *args, int from_tty)); + +/* + * this array of registers need to match the indexes used by GDB. The + * whole reason this exists is cause the various ROM monitors use + * different strings than GDB does, and doesn't support all the + * registers either. So, typing "info reg sp" becomes a "r30". + */ + +static char *op50n_regnames[NUM_REGS] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "cr11", "p", NULL, NULL, NULL, "cr15", "cr19", "cr20", + "cr21", "cr22", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "cr0", "cr8", "cr9", "cr10","cr12", + "cr13", "cr24", "cr25", "cr26", +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops op50n_ops; + +static char *op50n_inits[] = {".\r", NULL}; + +static struct monitor_ops op50n_cmds = +{ + MO_CLR_BREAK_USES_ADDR /*| MO_GETMEM_READ_SINGLE*/, /* flags */ + op50n_inits, /* Init strings */ + "g\r", /* continue command */ + "t\r", /* single step */ + "\003.\r", /* Interrupt char */ + "b %x\r", /* set a breakpoint */ + "b %x,0\r", /* clear breakpoint at addr */ + "bx\r", /* clear all breakpoints */ + "fx %x s%x %x\r", /* memory fill cmd (addr, len, val) */ + { + "sx %x %x\r", /* setmem.cmdb (addr, value) */ + "sh %x %x\r", /* setmem.cmdw (addr, value) */ + "s %x %x\r", /* setmem.cmdl (addr, value) */ + NULL, /* setmem.cmdll (addr, value) */ + NULL, /* setmem.resp_delim */ + NULL, /* setmem.term */ + NULL, /* setmem.term_cmd */ + }, +#if 0 + { + "sx %x\r", /* getmem.cmdb (addr, len) */ + "sh %x\r", /* getmem.cmdw (addr, len) */ + "s %x\r", /* getmem.cmdl (addr, len) */ + NULL, /* getmem.cmdll (addr, len) */ + " : ", /* getmem.resp_delim */ + " ", /* getmem.term */ + ".\r", /* getmem.term_cmd */ + }, +#else + { + "dx %x s%x\r", /* getmem.cmdb (addr, len) */ + NULL, /* getmem.cmdw (addr, len) */ + NULL, /* getmem.cmdl (addr, len) */ + NULL, /* getmem.cmdll (addr, len) */ + " : ", /* getmem.resp_delim */ + NULL, /* getmem.term */ + NULL, /* getmem.term_cmd */ + }, +#endif + { + "x %s %x\r", /* setreg.cmd (name, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL, /* setreg.term_cmd */ + }, + { + "x %s\r", /* getreg.cmd (name) */ + "=", /* getreg.resp_delim */ + " ", /* getreg.term */ + ".\r", /* getreg.term_cmd */ + }, + NULL, /* dump_registers */ + NULL, /* register_pattern */ + NULL, /* supply_register */ + NULL, /* load routine */ + "r 0\r", /* download command */ + NULL, /* load response */ + "\n#", /* monitor command prompt */ + "\r", /* end-of-command delimitor */ + NULL, /* optional command terminator */ + &op50n_ops, /* target operations */ + SERIAL_1_STOPBITS, /* number of stop bits */ + op50n_regnames, /* register names */ + MONITOR_OPS_MAGIC /* magic */ + }; + +static void +op50n_open (args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &op50n_cmds, from_tty); +} + +void +_initialize_op50n () +{ + init_monitor_ops (&op50n_ops); + + op50n_ops.to_shortname = "op50n"; + op50n_ops.to_longname = "Oki's debug monitor for the Op50n Eval board"; + op50n_ops.to_doc = "Debug on a Oki OP50N eval board.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + op50n_ops.to_open = op50n_open; + + add_target (&op50n_ops); +} diff --git a/contrib/gdb/gdb/os9kread.c b/contrib/gdb/gdb/os9kread.c new file mode 100644 index 000000000000..f80cb1b86beb --- /dev/null +++ b/contrib/gdb/gdb/os9kread.c @@ -0,0 +1,1659 @@ +/* Read os9/os9k symbol tables and convert to internal format, for GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This module provides three functions: os9k_symfile_init, + which initializes to read a symbol file; os9k_new_init, which + discards existing cached information when all symbols are being + discarded; and os9k_symfile_read, which reads a symbol table + from a file. + + os9k_symfile_read 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. os9k_psymtab_to_symtab() is the function that does this */ + +#include "defs.h" +#include "gdb_string.h" +#include + +#if defined(USG) || defined(__CYGNUSCLIB__) +#include +#include +#endif + +#include "obstack.h" +#include +#ifndef NO_SYS_FILE +#include +#endif +#include "gdb_stat.h" +#include +#include "symtab.h" +#include "breakpoint.h" +#include "command.h" +#include "target.h" +#include "gdbcore.h" /* for bfd stuff */ +#include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "gdb-stabs.h" +#include "demangle.h" +#include "language.h" /* Needed inside partial-stab.h */ +#include "complaints.h" +#include "os9k.h" +#include "stabsread.h" + +/* Each partial symbol table entry contains a pointer to private data for the + read_symtab() function to use when expanding a partial symbol table entry + to a full symbol table entry. + + For dbxread this structure contains the offset within the file symbol table + of first local symbol for this file, and count of the section + of the symbol table devoted to this file's symbols (actually, the section + bracketed may contain more than just this file's symbols). It also contains + further information needed to locate the symbols if they are in an ELF file. + + If ldsymcnt is 0, the only reason for this thing's existence is the + dependency list. Nothing else will happen when it is read in. */ + +#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff) +#define LDSYMCNT(p) (((struct symloc *)((p)->read_symtab_private))->ldsymnum) + +struct symloc { + int ldsymoff; + int ldsymnum; +}; + +/* Remember what we deduced to be the source language of this psymtab. */ +static enum language psymtab_language = language_unknown; + +/* keep partial symbol table file nested depth */ +static int psymfile_depth = 0; + +/* keep symbol table file nested depth */ +static int symfile_depth = 0; + +/* Nonzero means give verbose info on gdb action. From main.c. */ +extern int info_verbose; + +extern int previous_stab_code; + +/* Name of last function encountered. Used in Solaris to approximate + object file boundaries. */ +static char *last_function_name; + +/* Complaints about the symbols we have encountered. */ +extern struct complaint lbrac_complaint; + +extern struct complaint unknown_symtype_complaint; + +extern struct complaint unknown_symchar_complaint; + +extern struct complaint lbrac_rbrac_complaint; + +extern struct complaint repeated_header_complaint; + +extern struct complaint repeated_header_name_complaint; + +#if 0 +static struct complaint lbrac_unmatched_complaint = + {"unmatched Increment Block Entry before symtab pos %d", 0, 0}; + +static struct complaint lbrac_mismatch_complaint = + {"IBE/IDE symbol mismatch at symtab pos %d", 0, 0}; +#endif + +/* Local function prototypes */ +static void +os9k_read_ofile_symtab PARAMS ((struct partial_symtab *)); + +static void +os9k_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +static void +os9k_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +read_os9k_psymtab PARAMS ((struct section_offsets *, struct objfile *, + CORE_ADDR, int)); + +static int +fill_sym PARAMS ((FILE *, bfd *)); + +static void +os9k_symfile_init PARAMS ((struct objfile *)); + +static void +os9k_new_init PARAMS ((struct objfile *)); + +static void +os9k_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +os9k_symfile_finish PARAMS ((struct objfile *)); + +static void +os9k_process_one_symbol PARAMS ((int, int, CORE_ADDR, char *, + struct section_offsets *, struct objfile *)); + +static struct partial_symtab * +os9k_start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *, + CORE_ADDR, int, int, struct partial_symbol **, + struct partial_symbol **)); + +static struct partial_symtab * +os9k_end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR, + struct partial_symtab **, int)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *, + struct section_offsets *)); + +#define HANDLE_RBRAC(val) \ + if ((val) > pst->texthigh) pst->texthigh = (val); + +#define SWAP_STBHDR(hdrp, abfd) \ + { \ + (hdrp)->fmtno = bfd_get_16(abfd, (unsigned char *)&(hdrp)->fmtno); \ + (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \ + (hdrp)->offset = bfd_get_32(abfd, (unsigned char *)&(hdrp)->offset); \ + (hdrp)->nsym = bfd_get_32(abfd, (unsigned char *)&(hdrp)->nsym); \ + } +#define SWAP_STBSYM(symp, abfd) \ + { \ + (symp)->value = bfd_get_32(abfd, (unsigned char *)&(symp)->value); \ + (symp)->type = bfd_get_16(abfd, (unsigned char *)&(symp)->type); \ + (symp)->stroff = bfd_get_32(abfd, (unsigned char *)&(symp)->stroff); \ + } +#define N_DATA 0 +#define N_BSS 1 +#define N_RDATA 2 +#define N_IDATA 3 +#define N_TEXT 4 +#define N_ABS 6 + +static void +record_minimal_symbol (name, address, type, objfile, section_offsets) + char *name; + CORE_ADDR address; + int type; + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + enum minimal_symbol_type ms_type; + + switch (type) + { + case N_TEXT: + ms_type = mst_text; + address += ANOFFSET(section_offsets, SECT_OFF_TEXT); + break; + case N_DATA: + ms_type = mst_data; + break; + case N_BSS: + ms_type = mst_bss; + break; + case N_RDATA: + ms_type = mst_bss; + break; + case N_IDATA: + ms_type = mst_data; + break; + case N_ABS: + ms_type = mst_abs; + break; + default: + ms_type = mst_unknown; break; + } + + prim_record_minimal_symbol + (obsavestring (name, strlen(name), &objfile->symbol_obstack), + address, ms_type, objfile); +} + +/* read and process .stb file and store in minimal symbol table */ +typedef char mhhdr[80]; +struct stbhdr { + mhhdr comhdr; + char * name; + short fmtno; + int crc; + int offset; + int nsym; + char *pad; +}; +struct stbsymbol { + int value; + short type; + int stroff; +}; +#define STBSYMSIZE 10 + +static void +read_minimal_symbols(objfile, section_offsets) + struct objfile *objfile; + struct section_offsets *section_offsets; +{ +FILE *fp; +bfd *abfd; +struct stbhdr hdr; +struct stbsymbol sym; +int ch, i, j, off; +char buf[64], buf1[128]; + + fp = objfile->auxf1; + if (fp == NULL) return; + abfd = objfile->obfd; + fread(&hdr.comhdr[0], sizeof(mhhdr), 1, fp); + i = 0; + ch = getc(fp); + while (ch != -1) { + buf[i] = (char)ch; + i++; + if (ch == 0) break; + ch = getc(fp); + }; + if (i%2) ch=getc(fp); + hdr.name = &buf[0]; + + fread(&hdr.fmtno, sizeof(hdr.fmtno), 1, fp); + fread(&hdr.crc, sizeof(hdr.crc), 1, fp); + fread(&hdr.offset, sizeof(hdr.offset), 1, fp); + fread(&hdr.nsym, sizeof(hdr.nsym), 1, fp); + SWAP_STBHDR(&hdr, abfd); + + /* read symbols */ + init_minimal_symbol_collection(); + off = hdr.offset; + for (i = hdr.nsym; i > 0; i--) { + fseek(fp, (long)off, 0); + fread(&sym.value, sizeof(sym.value), 1, fp); + fread(&sym.type, sizeof(sym.type), 1, fp); + fread(&sym.stroff, sizeof(sym.stroff), 1, fp); + SWAP_STBSYM (&sym, abfd); + fseek(fp, (long)sym.stroff, 0); + j = 0; + ch = getc(fp); + while (ch != -1) { + buf1[j] = (char)ch; + j++; + if (ch == 0) break; + ch = getc(fp); + }; + record_minimal_symbol(buf1, sym.value, sym.type&7, objfile, section_offsets); + off += STBSYMSIZE; + }; + install_minimal_symbols (objfile); + return; +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to os9k_symfile_init, which + put all the relevant info into a "struct os9k_symfile_info", + hung off the objfile structure. + + SECTION_OFFSETS contains offsets relative to which the symbols in the + various sections are (depending where the sections were actually loaded). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). */ + +static void +os9k_symfile_read (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; /* FIXME comments above */ +{ + bfd *sym_bfd; + struct cleanup *back_to; + + sym_bfd = objfile->obfd; + /* If we are reinitializing, or if we have never loaded syms yet, init */ + if (mainline || objfile->global_psymbols.size == 0 || + objfile->static_psymbols.size == 0) + init_psymbol_list (objfile, DBX_SYMCOUNT (objfile)); + + pending_blocks = 0; + back_to = make_cleanup (really_free_pendings, 0); + + make_cleanup (discard_minimal_symbols, 0); + read_minimal_symbols (objfile, section_offsets); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. */ + read_os9k_psymtab (section_offsets, objfile, + DBX_TEXT_ADDR (objfile), + DBX_TEXT_SIZE (objfile)); + + do_cleanups (back_to); +} + +/* 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). */ + +static void +os9k_new_init (ignore) + struct objfile *ignore; +{ + stabsread_new_init (); + buildsym_new_init (); + psymfile_depth = 0; +/* + init_header_files (); +*/ +} + +/* os9k_symfile_init () + It is passed a struct objfile which contains, among other things, + the BFD for the file whose symbols are being read, and a slot for a pointer + to "private data" which we fill with goodies. + + Since BFD doesn't know how to read debug symbols in a format-independent + way (and may never do so...), we have to do it ourselves. We will never + be called unless this is an a.out (or very similar) file. + FIXME, there should be a cleaner peephole into the BFD environment here. */ + +static void +os9k_symfile_init (objfile) + struct objfile *objfile; +{ + bfd *sym_bfd = objfile->obfd; + char *name = bfd_get_filename (sym_bfd); + char dbgname[512], stbname[512]; + FILE *symfile = 0; + FILE *minfile = 0; + asection *text_sect; + + strcpy(dbgname, name); + strcat(dbgname, ".dbg"); + strcpy(stbname, name); + strcat(stbname, ".stb"); + + if ((symfile = fopen(dbgname, "r")) == NULL) { + warning("Symbol file %s not found", dbgname); + } + objfile->auxf2 = symfile; + + if ((minfile = fopen(stbname, "r")) == NULL) { + warning("Symbol file %s not found", stbname); + } + objfile->auxf1 = minfile; + + /* Allocate struct to keep track of the symfile */ + objfile->sym_stab_info = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL; + + text_sect = bfd_get_section_by_name (sym_bfd, ".text"); + if (!text_sect) + error ("Can't find .text section in file"); + DBX_TEXT_ADDR (objfile) = bfd_section_vma (sym_bfd, text_sect); + DBX_TEXT_SIZE (objfile) = bfd_section_size (sym_bfd, text_sect); + + DBX_SYMBOL_SIZE (objfile) = 0; /* variable size symbol */ + DBX_SYMCOUNT (objfile) = 0; /* used to be bfd_get_symcount(sym_bfd) */ + DBX_SYMTAB_OFFSET (objfile) = 0; /* used to be SYMBOL_TABLE_OFFSET */ +} + +/* 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 +os9k_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile->sym_stab_info != NULL) + { + mfree (objfile -> md, objfile->sym_stab_info); + } +/* + free_header_files (); +*/ +} + + +struct st_dbghdr { + int sync; + short rev; + int crc; + short os; + short cpu; +}; +#define SYNC (int)0xefbefeca + +#define SWAP_DBGHDR(hdrp, abfd) \ + { \ + (hdrp)->sync = bfd_get_32(abfd, (unsigned char *)&(hdrp)->sync); \ + (hdrp)->rev = bfd_get_16(abfd, (unsigned char *)&(hdrp)->rev); \ + (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \ + (hdrp)->os = bfd_get_16(abfd, (unsigned char *)&(hdrp)->os); \ + (hdrp)->cpu = bfd_get_16(abfd, (unsigned char *)&(hdrp)->cpu); \ + } + +#define N_SYM_CMPLR 0 +#define N_SYM_SLINE 1 +#define N_SYM_SYM 2 +#define N_SYM_LBRAC 3 +#define N_SYM_RBRAC 4 +#define N_SYM_SE 5 + +struct internal_symstruct { + short n_type; + short n_desc; + long n_value; + char * n_strx; +}; +static struct internal_symstruct symbol; +static struct internal_symstruct *symbuf = &symbol; +static char strbuf[4096]; +static struct st_dbghdr dbghdr; +static short cmplrid; + +#define VER_PRE_ULTRAC ((short)4) +#define VER_ULTRAC ((short)5) + +static int +fill_sym (dbg_file, abfd) + FILE *dbg_file; + bfd *abfd; +{ +short si, nmask; +long li; +int ii; +char *p; + + int nbytes = fread(&si, sizeof(si), 1, dbg_file); + if (nbytes == 0) + return 0; + if (nbytes < 0) + perror_with_name ("reading .dbg file."); + symbuf->n_desc = 0; + symbuf->n_value = 0; + symbuf->n_strx = NULL; + symbuf->n_type = bfd_get_16 (abfd, (unsigned char *)&si); + symbuf->n_type = 0xf & symbuf->n_type; + switch (symbuf->n_type) + { + case N_SYM_CMPLR: + fread(&si, sizeof(si), 1, dbg_file); + symbuf->n_desc = bfd_get_16(abfd, (unsigned char *)&si); + cmplrid = symbuf->n_desc & 0xff; + break; + case N_SYM_SLINE: + fread(&li, sizeof(li), 1, dbg_file); + symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li); + fread(&li, sizeof(li), 1, dbg_file); + li = bfd_get_32(abfd, (unsigned char *)&li); + symbuf->n_strx = (char *)(li >> 12); + symbuf->n_desc = li & 0xfff; + break; + case N_SYM_SYM: + fread(&li, sizeof(li), 1, dbg_file); + symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li); + si = 0; + do { + ii = getc(dbg_file); + strbuf[si++] = (char) ii; + } while (ii != 0 || si % 2 != 0); + symbuf->n_strx = strbuf; + p = (char *) strchr (strbuf, ':'); + if (!p) break; + if ((p[1] == 'F' || p[1] == 'f') && cmplrid == VER_PRE_ULTRAC) + { + fread(&si, sizeof(si), 1, dbg_file); + nmask = bfd_get_16(abfd, (unsigned char *)&si); + for (ii=0; iin_value = bfd_get_32(abfd, (unsigned char *)&li); + break; + case N_SYM_RBRAC: + fread(&li, sizeof(li), 1, dbg_file); + symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li); + break; + case N_SYM_SE: + break; + } + return 1; +} + +/* Given pointers to an a.out symbol table in core containing dbx + style data, setup partial_symtab's describing each source file for + which debugging information is available. + SYMFILE_NAME is the name of the file we are reading from + and SECTION_OFFSETS is the set of offsets for the various sections + of the file (a set of zeros if the mainline program). */ + +static void +read_os9k_psymtab (section_offsets, objfile, text_addr, text_size) + struct section_offsets *section_offsets; + struct objfile *objfile; + CORE_ADDR text_addr; + int text_size; +{ + register struct internal_symstruct *bufp = 0; /* =0 avoids gcc -Wall glitch*/ + register char *namestring; + int past_first_source_file = 0; + CORE_ADDR last_o_file_start = 0; +#if 0 + struct cleanup *back_to; +#endif + bfd *abfd; + FILE *fp; + + /* End of the text segment of the executable file. */ + static CORE_ADDR end_of_text_addr; + + /* Current partial symtab */ + static struct partial_symtab *pst = 0; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + last_source_file = NULL; + +#ifdef END_OF_TEXT_DEFAULT + end_of_text_addr = END_OF_TEXT_DEFAULT; +#else + end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT] + + text_size; /* Relocate */ +#endif + + abfd = objfile->obfd; + fp = objfile->auxf2; + if (!fp) return; + + fread(&dbghdr.sync, sizeof(dbghdr.sync), 1, fp); + fread(&dbghdr.rev, sizeof(dbghdr.rev), 1, fp); + fread(&dbghdr.crc, sizeof(dbghdr.crc), 1, fp); + fread(&dbghdr.os, sizeof(dbghdr.os), 1, fp); + fread(&dbghdr.cpu, sizeof(dbghdr.cpu), 1, fp); + SWAP_DBGHDR(&dbghdr, abfd); + + symnum = 0; + while(1) + { + int ret; + long cursymoffset; + + /* Get the symbol for this run and pull out some info */ + QUIT; /* allow this to be interruptable */ + cursymoffset = ftell(objfile->auxf2); + ret = fill_sym(objfile->auxf2, abfd); + if (ret <= 0) break; + else symnum++; + bufp = symbuf; + + /* Special case to speed up readin. */ + if (bufp->n_type == (short)N_SYM_SLINE) continue; + +#define CUR_SYMBOL_VALUE bufp->n_value + /* partial-stab.h */ + + switch (bufp->n_type) + { + char *p; + + case N_SYM_CMPLR: + continue; + + case N_SYM_SE: + CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT); + if (psymfile_depth == 1 && pst) + { + os9k_end_psymtab (pst, psymtab_include_list, includes_used, + symnum, CUR_SYMBOL_VALUE, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + psymfile_depth--; + continue; + + case N_SYM_SYM: /* Typedef or automatic variable. */ + namestring = bufp->n_strx; + p = (char *) strchr (namestring, ':'); + if (!p) + continue; /* Not a debugging symbol. */ + + /* Main processing section for debugging symbols which + the initial read through the symbol tables needs to worry + about. If we reach this point, the symbol which we are + considering is definitely one we are interested in. + p must also contain the (valid) index into the namestring + which indicates the debugging type symbol. */ + + switch (p[1]) + { + case 'S' : + { + unsigned long valu; + enum language tmp_language; + char *str, *p; + int n; + + valu = CUR_SYMBOL_VALUE; + if (valu) + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + past_first_source_file = 1; + + p = strchr(namestring, ':'); + if (p) n = p-namestring; + else n = strlen(namestring); + str = alloca(n+1); + strncpy(str, namestring, n); + str[n] = '\0'; + + if (psymfile_depth == 0) { + if (!pst) + pst = os9k_start_psymtab (objfile, section_offsets, + str, valu, + cursymoffset, + symnum-1, + objfile -> global_psymbols.next, + objfile -> static_psymbols.next); + } else { /* this is a include file */ + tmp_language = deduce_language_from_filename (str); + if (tmp_language != language_unknown + && (tmp_language != language_c + || psymtab_language != language_cplus)) + psymtab_language = tmp_language; + +/* + if (pst && STREQ (str, pst->filename)) + continue; + { + register int i; + for (i = 0; i < includes_used; i++) + if (STREQ (str, psymtab_include_list[i])) + { + i = -1; + break; + } + if (i == -1) + continue; + } +*/ + + psymtab_include_list[includes_used++] = str; + if (includes_used >= includes_allocated) + { + char **orig = psymtab_include_list; + + psymtab_include_list = (char **) + alloca ((includes_allocated *= 2) * sizeof (char *)); + memcpy ((PTR)psymtab_include_list, (PTR)orig, + includes_used * sizeof (char *)); + } + + } + psymfile_depth++; + continue; + } + + case 'v': + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->static_psymbols, + 0, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + case 'V': + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->global_psymbols, + 0, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + case 'T': + if (p != namestring) /* a name is there, not just :T... */ + { + add_psymbol_to_list (namestring, p - namestring, + STRUCT_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + if (p[2] == 't') + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, psymtab_language, + objfile); + p += 1; + } + /* The semantics of C++ state that "struct foo { ... }" + also defines a typedef for "foo". Unfortuantely, cfront + never makes the typedef when translating from C++ to C. + We make the typedef here so that "ptype foo" works as + expected for cfront translated code. */ + else if (psymtab_language == language_cplus) + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, psymtab_language, + objfile); + } + } + goto check_enum; + case 't': + if (p != namestring) /* a name is there, not just :T... */ + { + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + } + check_enum: + /* If this is an enumerated type, we need to + add all the enum constants to the partial symbol + table. This does not cover enums without names, e.g. + "enum {a, b} c;" in C, but fortunately those are + rare. There is no way for GDB to find those from the + enum type without spending too much time on it. Thus + to solve this problem, the compiler needs to put out the + enum in a nameless type. GCC2 does this. */ + + /* We are looking for something of the form + ":" ("t" | "T") [ "="] "e" + { ":" ","} ";". */ + + /* Skip over the colon and the 't' or 'T'. */ + p += 2; + /* This type may be given a number. Also, numbers can come + in pairs like (0,26). Skip over it. */ + while ((*p >= '0' && *p <= '9') + || *p == '(' || *p == ',' || *p == ')' + || *p == '=') + p++; + + if (*p++ == 'e') + { + /* We have found an enumerated type. skip size */ + while (*p >= '0' && *p <= '9') p++; + /* According to comments in read_enum_type + a comma could end it instead of a semicolon. + I don't know where that happens. + Accept either. */ + while (*p && *p != ';' && *p != ',') + { + char *q; + + /* Check for and handle cretinous dbx symbol name + continuation! + if (*p == '\\') + p = next_symbol_text (objfile); + */ + + /* Point to the character after the name + of the enum constant. */ + for (q = p; *q && *q != ':'; q++) + ; + /* Note that the value doesn't matter for + enum constants in psymtabs, just in symtabs. */ + add_psymbol_to_list (p, q - p, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, 0, + 0, psymtab_language, objfile); + /* Point past the name. */ + p = q; + /* Skip over the value. */ + while (*p && *p != ',') + p++; + /* Advance past the comma. */ + if (*p) + p++; + } + } + continue; + case 'c': + /* Constant, e.g. from "const" in Pascal. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + case 'f': + CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT); + if (pst && pst->textlow == 0) + pst->textlow = CUR_SYMBOL_VALUE; + + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->static_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + case 'F': + CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT); + if (pst && pst->textlow == 0) + pst->textlow = CUR_SYMBOL_VALUE; + + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->global_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + case 'p': + case 'l': + case 's': + continue; + + case ':': + /* It is a C++ nested symbol. We don't need to record it + (I don't think); if we try to look up foo::bar::baz, + then symbols for the symtab containing foo should get + read in, I think. */ + /* Someone says sun cc puts out symbols like + /foo/baz/maclib::/usr/local/bin/maclib, + which would get here with a symbol type of ':'. */ + continue; + + default: + /* Unexpected symbol descriptor. The second and subsequent stabs + of a continued stab can show up here. The question is + whether they ever can mimic a normal stab--it would be + nice if not, since we certainly don't want to spend the + time searching to the end of every string looking for + a backslash. */ + + complain (&unknown_symchar_complaint, p[1]); + continue; + } + + case N_SYM_RBRAC: + CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT); +#ifdef HANDLE_RBRAC + HANDLE_RBRAC(CUR_SYMBOL_VALUE); + continue; +#endif + case N_SYM_LBRAC: + continue; + + default: + /* If we haven't found it yet, ignore it. It's probably some + new type we don't know about yet. */ + complain (&unknown_symtype_complaint, + local_hex_string ((unsigned long) bufp->n_type)); + continue; + } + } + + DBX_SYMCOUNT (objfile) = symnum; + + /* If there's stuff to be cleaned up, clean it up. */ + if (DBX_SYMCOUNT (objfile) > 0 +/*FIXME, does this have a bug at start address 0? */ + && last_o_file_start + && objfile -> ei.entry_point < bufp->n_value + && objfile -> ei.entry_point >= last_o_file_start) + { + objfile -> ei.entry_file_lowpc = last_o_file_start; + objfile -> ei.entry_file_highpc = bufp->n_value; + } + + if (pst) + { + os9k_end_psymtab (pst, psymtab_include_list, includes_used, + symnum, end_of_text_addr, + dependency_list, dependencies_used); + } +/* + do_cleanups (back_to); +*/ +} + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + + +static struct partial_symtab * +os9k_start_psymtab (objfile, section_offsets, + filename, textlow, ldsymoff,ldsymcnt, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + CORE_ADDR textlow; + int ldsymoff; + int ldsymcnt; + struct partial_symbol **global_syms; + struct partial_symbol **static_syms; +{ + struct partial_symtab *result = + start_psymtab_common(objfile, section_offsets, + filename, textlow, global_syms, static_syms); + + result->read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc)); + + LDSYMOFF(result) = ldsymoff; + LDSYMCNT(result) = ldsymcnt; + result->read_symtab = os9k_psymtab_to_symtab; + + /* Deduce the source language from the filename for this psymtab. */ + psymtab_language = deduce_language_from_filename (filename); + return result; +} + +/* Close off the current usage of PST. + Returns PST or NULL if the partial symtab was empty and thrown away. + FIXME: List variables and peculiarities of same. */ + +static struct partial_symtab * +os9k_end_psymtab (pst, include_list, num_includes, capping_symbol_cnt, + capping_text, dependency_list, number_dependencies) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_cnt; + CORE_ADDR capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; +/* struct partial_symbol *capping_global, *capping_static;*/ +{ + int i; + struct partial_symtab *p1; + struct objfile *objfile = pst -> objfile; + + if (capping_symbol_cnt != -1) + LDSYMCNT(pst) = capping_symbol_cnt - LDSYMCNT(pst); + + /* Under Solaris, the N_SO symbols always have a value of 0, + instead of the usual address of the .o file. Therefore, + we have to do some tricks to fill in texthigh and textlow. + The first trick is in partial-stab.h: if we see a static + or global function, and the textlow for the current pst + is still 0, then we use that function's address for + the textlow of the pst. + + Now, to fill in texthigh, we remember the last function seen + in the .o file (also in partial-stab.h). Also, there's a hack in + bfd/elf.c and gdb/elfread.c to pass the ELF st_size field + to here via the misc_info field. Therefore, we can fill in + a reliable texthigh by taking the address plus size of the + last function in the file. + + Unfortunately, that does not cover the case where the last function + in the file is static. See the paragraph below for more comments + on this situation. + + Finally, if we have a valid textlow for the current file, we run + down the partial_symtab_list filling in previous texthighs that + are still unknown. */ + + if (pst->texthigh == 0 && last_function_name) { + char *p; + int n; + struct minimal_symbol *minsym; + + p = strchr (last_function_name, ':'); + if (p == NULL) + p = last_function_name; + n = p - last_function_name; + p = alloca (n + 1); + strncpy (p, last_function_name, n); + p[n] = 0; + + minsym = lookup_minimal_symbol (p, NULL, objfile); + + if (minsym) { + pst->texthigh = SYMBOL_VALUE_ADDRESS(minsym)+(long)MSYMBOL_INFO(minsym); + } else { + /* This file ends with a static function, and it's + difficult to imagine how hard it would be to track down + the elf symbol. Luckily, most of the time no one will notice, + since the next file will likely be compiled with -g, so + the code below will copy the first fuction's start address + back to our texthigh variable. (Also, if this file is the + last one in a dynamically linked program, texthigh already + has the right value.) If the next file isn't compiled + with -g, then the last function in this file winds up owning + all of the text space up to the next -g file, or the end (minus + shared libraries). This only matters for single stepping, + and even then it will still work, except that it will single + step through all of the covered functions, instead of setting + breakpoints around them as it usualy does. This makes it + pretty slow, but at least it doesn't fail. + + We can fix this with a fairly big change to bfd, but we need + to coordinate better with Cygnus if we want to do that. FIXME. */ + } + last_function_name = NULL; + } + + /* this test will be true if the last .o file is only data */ + if (pst->textlow == 0) + pst->textlow = pst->texthigh; + + /* If we know our own starting text address, then walk through all other + psymtabs for this objfile, and if any didn't know their ending text + address, set it to our starting address. Take care to not set our + own ending address to our starting address, nor to set addresses on + `dependency' files that have both textlow and texthigh zero. */ + if (pst->textlow) { + ALL_OBJFILE_PSYMTABS (objfile, p1) { + if (p1->texthigh == 0 && p1->textlow != 0 && p1 != pst) { + p1->texthigh = pst->textlow; + /* if this file has only data, then make textlow match texthigh */ + if (p1->textlow == 0) + p1->textlow = p1->texthigh; + } + } + } + + /* End of kludge for patching Solaris textlow and texthigh. */ + + 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); + + pst->number_of_dependencies = number_dependencies; + if (number_dependencies) + { + pst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + number_dependencies * sizeof (struct partial_symtab *)); + memcpy (pst->dependencies, dependency_list, + number_dependencies * sizeof (struct partial_symtab *)); + } + else + pst->dependencies = 0; + + for (i = 0; i < num_includes; i++) + { + struct partial_symtab *subpst = + allocate_psymtab (include_list[i], objfile); + + subpst->section_offsets = pst->section_offsets; + subpst->read_symtab_private = + (char *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc)); + LDSYMOFF(subpst) = + LDSYMCNT(subpst) = + subpst->textlow = + subpst->texthigh = 0; + + /* We could save slight bits of space by only making one of these, + shared by the entire set of include files. FIXME-someday. */ + subpst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct partial_symtab *)); + subpst->dependencies[0] = pst; + subpst->number_of_dependencies = 1; + + subpst->globals_offset = + subpst->n_global_syms = + subpst->statics_offset = + subpst->n_static_syms = 0; + + subpst->readin = 0; + subpst->symtab = 0; + subpst->read_symtab = pst->read_symtab; + } + + sort_pst_symbols (pst); + + /* If there is already a psymtab or symtab for a file of this name, + remove it. + (If there is a symtab, more drastic things also happen.) + This happens in VxWorks. */ + free_named_symtabs (pst->filename); + + if (num_includes == 0 + && number_dependencies == 0 + && pst->n_global_syms == 0 + && pst->n_static_syms == 0) { + /* Throw away this psymtab, it's empty. We can't deallocate it, since + it is on the obstack, but we can forget to chain it on the list. */ + struct partial_symtab *prev_pst; + + /* First, snip it out of the psymtab chain */ + + if (pst->objfile->psymtabs == pst) + pst->objfile->psymtabs = pst->next; + else + for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next) + if (prev_pst->next == pst) + prev_pst->next = pst->next; + + /* Next, put it on a free list for recycling */ + pst->next = pst->objfile->free_psymtabs; + pst->objfile->free_psymtabs = pst; + + /* Indicate that psymtab was thrown away. */ + pst = (struct partial_symtab *)NULL; + } + return pst; +} + +static void +os9k_psymtab_to_symtab_1 (pst) + 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. Shouldn't happen.\n", + pst->filename); + return; + } + + /* Read in all partial symtabs on which this one is dependent */ + 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) + { + 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); + } + os9k_psymtab_to_symtab_1 (pst->dependencies[i]); + } + + if (LDSYMCNT(pst)) /* Otherwise it's a dummy */ + { + /* Init stuff necessary for reading in symbols */ + stabsread_init (); + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + + /* Read in this file's symbols */ + os9k_read_ofile_symtab (pst); + sort_symtab_syms (pst->symtab); + do_cleanups (old_chain); + } + + pst->readin = 1; +} + +/* Read in all of the symbols for a given psymtab for real. + Be verbose about it if the user wants that. */ + +static void +os9k_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + bfd *sym_bfd; + + if (!pst) + return; + + if (pst->readin) + { + fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return; + } + + if (LDSYMCNT(pst) || pst->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); + gdb_flush (gdb_stdout); + } + + sym_bfd = pst->objfile->obfd; + os9k_psymtab_to_symtab_1 (pst); + + /* 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); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered ("done.\n"); + } +} + +/* Read in a defined section of a specific object file's symbols. */ +static void +os9k_read_ofile_symtab (pst) + struct partial_symtab *pst; +{ + register struct internal_symstruct *bufp; + unsigned char type; + unsigned max_symnum; + register bfd *abfd; + struct objfile *objfile; + int sym_offset; /* Offset to start 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; + FILE *dbg_file; + + objfile = pst->objfile; + sym_offset = LDSYMOFF(pst); + max_symnum = LDSYMCNT(pst); + text_offset = pst->textlow; + text_size = pst->texthigh - pst->textlow; + section_offsets = pst->section_offsets; + + current_objfile = objfile; + subfile_stack = NULL; + last_source_file = NULL; + + abfd = objfile->obfd; + dbg_file = objfile->auxf2; + +#if 0 + /* It is necessary to actually read one symbol *before* the start + of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL + occurs before the N_SO symbol. + Detecting this in read_dbx_symtab + would slow down initial readin, so we look for it here instead. */ + if (!processing_acc_compilation && sym_offset >= (int)symbol_size) + { + fseek (objefile->auxf2, sym_offset, SEEK_CUR); + fill_sym(objfile->auxf2, abfd); + bufp = symbuf; + + processing_gcc_compilation = 0; + if (bufp->n_type == N_TEXT) + { + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + } + + /* Try to select a C++ demangling based on the compilation unit + producer. */ + + if (processing_gcc_compilation) + { + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + } + else + { + /* The N_SO starting this symtab is the first symbol, so we + better not check the symbol before it. I'm not this can + happen, but it doesn't hurt to check for it. */ + bfd_seek (symfile_bfd, sym_offset, SEEK_CUR); + processing_gcc_compilation = 0; + } +#endif /* 0 */ + + fseek(dbg_file, (long)sym_offset, 0); +/* + if (bufp->n_type != (unsigned char)N_SYM_SYM) + error("First symbol in segment of executable not a source symbol"); +*/ + + for (symnum = 0; symnum < max_symnum; symnum++) + { + QUIT; /* Allow this to be interruptable */ + fill_sym(dbg_file, abfd); + bufp = symbuf; + type = bufp->n_type; + + os9k_process_one_symbol ((int)type, (int)bufp->n_desc, + (CORE_ADDR)bufp->n_value, bufp->n_strx, section_offsets, objfile); + + /* We skip checking for a new .o or -l file; that should never + happen in this routine. */ +#if 0 + else if (type == N_TEXT) + { + /* I don't think this code will ever be executed, because + the GCC_COMPILED_FLAG_SYMBOL usually is right before + the N_SO symbol which starts this source file. + However, there is no reason not to accept + the GCC_COMPILED_FLAG_SYMBOL anywhere. */ + + if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 1; + else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL)) + processing_gcc_compilation = 2; + + if (AUTO_DEMANGLING) + { + set_demangling_style (GNU_DEMANGLING_STYLE_STRING); + } + } + else if (type & N_EXT || type == (unsigned char)N_TEXT + || type == (unsigned char)N_NBTEXT + ) { + /* Global symbol: see if we came across a dbx defintion for + a corresponding symbol. If so, store the value. Remove + syms from the chain when their values are stored, but + search the whole chain, as there may be several syms from + different files with the same name. */ + /* This is probably not true. Since the files will be read + in one at a time, each reference to a global symbol will + be satisfied in each file as it appears. So we skip this + section. */ + ; + } +#endif /* 0 */ + } + + current_objfile = NULL; + + /* In a Solaris elf file, this variable, which comes from the + value of the N_SO symbol, will still be 0. Luckily, text_offset, + which comes from pst->textlow is correct. */ + if (last_source_start_addr == 0) + last_source_start_addr = text_offset; + pst->symtab = end_symtab (text_offset + text_size, objfile, SECT_OFF_TEXT); + end_stabs (); +} + + +/* This handles a single symbol from the symbol-file, building symbols + into a GDB symtab. It takes these arguments and an implicit argument. + + TYPE is the type field of the ".stab" symbol entry. + DESC is the desc field of the ".stab" entry. + VALU is the value field of the ".stab" entry. + NAME is the symbol name, in our address space. + SECTION_OFFSETS is a set of amounts by which the sections of this object + file were relocated when it was loaded into memory. + All symbols that refer + to memory locations need to be offset by these amounts. + OBJFILE is the object file from which we are reading symbols. + It is used in end_symtab. */ + +static void +os9k_process_one_symbol (type, desc, valu, name, section_offsets, objfile) + int type, desc; + CORE_ADDR valu; + char *name; + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + register struct context_stack *new; + /* The stab type used for the definition of the last function. + N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers. */ + static int function_stab_type = 0; + +#if 0 + /* Something is wrong if we see real data before + seeing a source file name. */ + if (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 gracefully with the + case. A complain()t might be in order (if !IGNORE_SYMBOL (type)), + but this should not be an error (). */ + return; + } +#endif /* 0 */ + + switch (type) + { + case N_SYM_LBRAC: + /* On most machines, the block addresses are relative to the + N_SO, the linker did not relocate them (sigh). */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + new = push_context (desc, valu); + break; + + case N_SYM_RBRAC: + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + new = pop_context(); + +#if !defined (OS9K_VARIABLES_INSIDE_BLOCK) +#define OS9K_VARIABLES_INSIDE_BLOCK(desc, gcc_p) 1 +#endif + + if (!OS9K_VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + local_symbols = new->locals; + + if (context_stack_depth > 1) + { + /* This is not the outermost LBRAC...RBRAC pair in the function, + its local symbols preceded it, and are the ones just recovered + from the context stack. Define the block for them (but don't + bother if the block contains no symbols. Should we complain + on blocks without symbols? I can't think of any useful purpose + for them). */ + if (local_symbols != NULL) + { + /* Muzzle a compiler bug that makes end < start. (which + compilers? Is this ever harmful?). */ + if (new->start_addr > valu) + { + complain (&lbrac_rbrac_complaint); + new->start_addr = valu; + } + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + } + else + { + if (context_stack_depth == 0) + { + within_function = 0; + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, valu, objfile); + } + else + { + /* attach local_symbols to the end of new->locals */ + if (!new->locals) new->locals = local_symbols; + else { + struct pending *p; + + p = new->locals; + while (p->next) p = p->next; + p->next = local_symbols; + } + } + } + + if (OS9K_VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)) + /* Now pop locals of block just finished. */ + local_symbols = new->locals; + break; + + + case N_SYM_SLINE: + /* This type of "symbol" really just records + one line-number -- core-address correspondence. + Enter it in the line list for this symbol table. */ + /* Relocate for dynamic loading and for ELF acc fn-relative syms. */ + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + /* FIXME: loses if sizeof (char *) > sizeof (int) */ + record_line (current_subfile, (int)name, valu); + break; + + /* The following symbol types need to have the appropriate offset added + to their value; then we process symbol definitions in the name. */ + case N_SYM_SYM: + + if (name) + { + char deftype; + char *dirn, *n; + char *p = strchr (name, ':'); + if (p == NULL) + deftype = '\0'; + else + deftype = p[1]; + + + switch (deftype) + { + case 'S': + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + n = strrchr(name, '/'); + if (n != NULL) { + *n = '\0'; + n++; + dirn = name; + } else { + n = name; + dirn = NULL; + } + *p = '\0'; + if (symfile_depth++ == 0) { + if (last_source_file) { + end_symtab (valu, objfile, SECT_OFF_TEXT); + end_stabs (); + } + start_stabs (); + os9k_stabs = 1; + start_symtab (n, dirn, valu); + } else { + push_subfile(); + start_subfile (n, dirn!=NULL ? dirn : current_subfile->dirname); + } + break; + + case 'f': + case 'F': + valu += ANOFFSET (section_offsets, SECT_OFF_TEXT); + function_stab_type = type; + + within_function = 1; + new = push_context (0, valu); + new->name = define_symbol (valu, name, desc, type, objfile); + break; + + case 'V': + case 'v': + valu += ANOFFSET (section_offsets, SECT_OFF_DATA); + define_symbol (valu, name, desc, type, objfile); + break; + + default: + define_symbol (valu, name, desc, type, objfile); + break; + } + } + break; + + case N_SYM_SE: + if (--symfile_depth != 0) + start_subfile(pop_subfile(), current_subfile->dirname); + break; + + default: + complain (&unknown_symtype_complaint, + local_hex_string((unsigned long) type)); + /* FALLTHROUGH */ + break; + + case N_SYM_CMPLR: + break; + } + previous_stab_code = type; +} + +/* Parse the user's idea of an offset for dynamic linking, into our idea + of how to represent it for fast symbol reading. */ + +static struct section_offsets * +os9k_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; +} + +static struct sym_fns os9k_sym_fns = +{ + bfd_target_os9k_flavour, + os9k_new_init, /* sym_new_init: init anything gbl to entire symtab */ + os9k_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + os9k_symfile_read, /* sym_read: read a symbol file into symtab */ + os9k_symfile_finish, /* sym_finish: finished with file, cleanup */ + os9k_symfile_offsets, /* sym_offsets: parse user's offsets to internal form*/ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_os9kread () +{ + add_symtab_fns(&os9k_sym_fns); +} diff --git a/contrib/gdb/gdb/osfsolib.c b/contrib/gdb/gdb/osfsolib.c new file mode 100644 index 000000000000..85afa24211c7 --- /dev/null +++ b/contrib/gdb/gdb/osfsolib.c @@ -0,0 +1,955 @@ +/* Handle OSF/1 shared libraries for GDB, the GNU Debugger. + Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* FIXME: Most of this code could be merged with solib.c by using + next_link_map_member and xfer_link_map_member in solib.c. */ + +#include "defs.h" + +#include +#include +#include "gdb_string.h" +#include + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "command.h" +#include "target.h" +#include "frame.h" +#include "gnu-regex.h" +#include "inferior.h" +#include "language.h" +#include "gdbcmd.h" + +#define MAX_PATH_SIZE 1024 /* FIXME: Should be dynamic */ + +/* When handling shared libraries, GDB has to find out the pathnames + of all shared libraries that are currently loaded (to read in their + symbols) and where the shared libraries are loaded in memory + (to relocate them properly from their prelinked addresses to the + current load address). + + Under OSF/1 there are two possibilities to get at this information: + 1) Peek around in the runtime loader structures. + These are not documented, and they are not defined in the system + header files. The definitions below were obtained by experimentation, + but they seem stable enough. + 2) Use the undocumented libxproc.a library, which contains the + equivalent ldr_* routines. + This approach is somewhat cleaner, but it requires that the GDB + executable is dynamically linked. In addition it requires a + NAT_CLIBS= -lxproc -Wl,-expect_unresolved,ldr_process_context + linker specification for GDB and all applications that are using + libgdb. + We will use the peeking approach until it becomes unwieldy. */ + +#ifndef USE_LDR_ROUTINES + +/* Definition of runtime loader structures, found by experimentation. */ +#define RLD_CONTEXT_ADDRESS 0x3ffc0000000 + +typedef struct +{ + CORE_ADDR next; + CORE_ADDR previous; + CORE_ADDR unknown1; + char *module_name; + CORE_ADDR modinfo_addr; + long module_id; + CORE_ADDR unknown2; + CORE_ADDR unknown3; + long region_count; + CORE_ADDR regioninfo_addr; +} ldr_module_info_t; + +typedef struct +{ + long unknown1; + CORE_ADDR regionname_addr; + long protection; + CORE_ADDR vaddr; + CORE_ADDR mapaddr; + long size; + long unknown2[5]; +} ldr_region_info_t; + +typedef struct +{ + CORE_ADDR unknown1; + CORE_ADDR unknown2; + CORE_ADDR head; + CORE_ADDR tail; +} ldr_context_t; + +static ldr_context_t ldr_context; + +#else + +#include +static ldr_process_t fake_ldr_process; + +/* Called by ldr_* routines to read memory from the current target. */ + +static int ldr_read_memory PARAMS ((CORE_ADDR, char *, int, int)); + +static int +ldr_read_memory (memaddr, myaddr, len, readstring) + CORE_ADDR memaddr; + char *myaddr; + int len; + int readstring; +{ + int result; + char *buffer; + + if (readstring) + { + target_read_string (memaddr, &buffer, len, &result); + if (result == 0) + strcpy (myaddr, buffer); + free (buffer); + } + else + result = target_read_memory (memaddr, myaddr, len); + + if (result != 0) + result = -result; + return result; +} + +#endif + +/* Define our own link_map structure. + This will help to share code with solib.c. */ + +struct link_map { + CORE_ADDR l_offset; /* prelink to load address offset */ + char *l_name; /* full name of loaded object */ + ldr_module_info_t module_info; /* corresponding module info */ +}; + +#define LM_OFFSET(so) ((so) -> lm.l_offset) +#define LM_NAME(so) ((so) -> lm.l_name) + +struct so_list { + struct so_list *next; /* next structure in linked list */ + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *abfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ + +extern int +fdmatch PARAMS ((int, int)); /* In libiberty */ + +/* Local function prototypes */ + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +static struct link_map * +first_link_map_member PARAMS ((void)); + +static struct link_map * +next_link_map_member PARAMS ((struct so_list *)); + +static void +xfer_link_map_member PARAMS ((struct so_list *, struct link_map *)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + + filename = tilde_expand (so -> so_name); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. bfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> abfd = abfd; + abfd -> cacheable = true; + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (exec_bfd), bfd_errmsg (bfd_get_error ())); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the offset to get the address to which the + object was actually mapped. */ + p -> addr += LM_OFFSET (so); + p -> endaddr += LM_OFFSET (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> the_bfd_section -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +static struct link_map * +first_link_map_member () +{ + struct link_map *lm = NULL; + static struct link_map first_lm; + +#ifdef USE_LDR_ROUTINES + ldr_module_t mod_id = LDR_NULL_MODULE; + size_t retsize; + + fake_ldr_process = ldr_core_process (); + ldr_set_core_reader (ldr_read_memory); + ldr_xdetach (fake_ldr_process); + if (ldr_xattach (fake_ldr_process) != 0 + || ldr_next_module(fake_ldr_process, &mod_id) != 0 + || mod_id == LDR_NULL_MODULE + || ldr_inq_module(fake_ldr_process, mod_id, + &first_lm.module_info, sizeof(ldr_module_info_t), + &retsize) != 0) + return lm; +#else + CORE_ADDR ldr_context_addr; + + if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS, + (char *) &ldr_context_addr, + sizeof (CORE_ADDR)) != 0 + || target_read_memory (ldr_context_addr, + (char *) &ldr_context, + sizeof (ldr_context_t)) != 0 + || target_read_memory ((CORE_ADDR) ldr_context.head, + (char *) &first_lm.module_info, + sizeof (ldr_module_info_t)) != 0) + return lm; +#endif + + lm = &first_lm; + + /* The first entry is for the main program and should be skipped. */ + lm->l_name = NULL; + + return lm; +} + +static struct link_map * +next_link_map_member (so_list_ptr) + struct so_list *so_list_ptr; +{ + struct link_map *lm = NULL; + static struct link_map next_lm; +#ifdef USE_LDR_ROUTINES + ldr_module_t mod_id = so_list_ptr->lm.module_info.lmi_modid; + size_t retsize; + + if (ldr_next_module(fake_ldr_process, &mod_id) != 0 + || mod_id == LDR_NULL_MODULE + || ldr_inq_module(fake_ldr_process, mod_id, + &next_lm.module_info, sizeof(ldr_module_info_t), + &retsize) != 0) + return lm; + + lm = &next_lm; + lm->l_name = lm->module_info.lmi_name; +#else + CORE_ADDR ldr_context_addr; + + /* Reread context in case ldr_context.tail was updated. */ + + if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS, + (char *) &ldr_context_addr, + sizeof (CORE_ADDR)) != 0 + || target_read_memory (ldr_context_addr, + (char *) &ldr_context, + sizeof (ldr_context_t)) != 0 + || so_list_ptr->lm.module_info.modinfo_addr == ldr_context.tail + || target_read_memory (so_list_ptr->lm.module_info.next, + (char *) &next_lm.module_info, + sizeof (ldr_module_info_t)) != 0) + return lm; + + lm = &next_lm; + lm->l_name = lm->module_info.module_name; +#endif + return lm; +} + +static void +xfer_link_map_member (so_list_ptr, lm) + struct so_list *so_list_ptr; + struct link_map *lm; +{ + int i; + so_list_ptr->lm = *lm; + + /* OSF/1 shared libraries are pre-linked to particular addresses, + but the runtime loader may have to relocate them if the + address ranges of the libraries used by the target executable clash, + or if the target executable is linked with the -taso option. + The offset is the difference between the address where the shared + library is mapped and the pre-linked address of the shared library. + + FIXME: GDB is currently unable to relocate the shared library + sections by different offsets. If sections are relocated by + different offsets, put out a warning and use the offset of the + first section for all remaining sections. */ + LM_OFFSET (so_list_ptr) = 0; + + /* There is one entry that has no name (for the inferior executable) + since it is not a shared object. */ + if (LM_NAME (so_list_ptr) != 0) + { + +#ifdef USE_LDR_ROUTINES + int len = strlen (LM_NAME (so_list_ptr) + 1); + + if (len > MAX_PATH_SIZE) + len = MAX_PATH_SIZE; + strncpy (so_list_ptr->so_name, LM_NAME (so_list_ptr), MAX_PATH_SIZE); + so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0'; + + for (i = 0; i < lm->module_info.lmi_nregion; i++) + { + ldr_region_info_t region_info; + size_t retsize; + CORE_ADDR region_offset; + + if (ldr_inq_region (fake_ldr_process, lm->module_info.lmi_modid, + i, ®ion_info, sizeof (region_info), + &retsize) != 0) + break; + region_offset = (CORE_ADDR) region_info.lri_mapaddr + - (CORE_ADDR) region_info.lri_vaddr; + if (i == 0) + LM_OFFSET (so_list_ptr) = region_offset; + else if (LM_OFFSET (so_list_ptr) != region_offset) + warning ("cannot handle shared library relocation for %s (%s)", + so_list_ptr->so_name, region_info.lri_name); + } +#else + int errcode; + char *buffer; + target_read_string ((CORE_ADDR) LM_NAME (so_list_ptr), &buffer, + MAX_PATH_SIZE - 1, &errcode); + if (errcode != 0) + error ("xfer_link_map_member: Can't read pathname for load map: %s\n", + safe_strerror (errcode)); + strncpy (so_list_ptr->so_name, buffer, MAX_PATH_SIZE - 1); + free (buffer); + so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0'; + + for (i = 0; i < lm->module_info.region_count; i++) + { + ldr_region_info_t region_info; + CORE_ADDR region_offset; + + if (target_read_memory (lm->module_info.regioninfo_addr + + i * sizeof (region_info), + (char *) ®ion_info, + sizeof (region_info)) != 0) + break; + region_offset = region_info.mapaddr - region_info.vaddr; + if (i == 0) + LM_OFFSET (so_list_ptr) = region_offset; + else if (LM_OFFSET (so_list_ptr) != region_offset) + { + char *region_name; + target_read_string (region_info.regionname_addr, &buffer, + MAX_PATH_SIZE - 1, &errcode); + if (errcode == 0) + region_name = buffer; + else + region_name = "??"; + warning ("cannot handle shared library relocation for %s (%s)", + so_list_ptr->so_name, region_name); + free (buffer); + } + } +#endif + + solib_map_sections (so_list_ptr); + } +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + + The arg and return value are "struct link_map" pointers, as defined + in . + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct link_map *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* Find the first link map list member. */ + lm = first_link_map_member (); + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + lm = next_link_map_member (so_list_ptr); + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + xfer_link_map_member (new, lm); + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = symbol_file_add (so -> so_name, so -> from_tty, + so -> textsection -> addr, + 0, 0, 0); + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + + /* Add the shared library sections to the section table of the + specified target, if any. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + int update_coreops; + + /* We must update the to_sections field in the core_ops structure + here, otherwise we dereference a potential dangling pointer + for each call to target_read/write_memory within this routine. */ + update_coreops = core_ops.to_sections == target->to_sections; + + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Update the to_sections field in the core_ops structure + if needed. */ + if (update_coreops) + { + core_ops.to_sections = target->to_sections; + core_ops.to_sections_end = target->to_sections_end; + } + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Now add the symbol files. */ + so = NULL; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + if (so_last) + reinit_frame_cache (); +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf_unfiltered ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + unsigned long txt_start = 0; + unsigned long txt_end = 0; + + if (!header_done) + { + printf_unfiltered("%-20s%-20s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + if (so -> textsection) + { + txt_start = (unsigned long) so -> textsection -> addr; + txt_end = (unsigned long) so -> textsection -> endaddr; + } + printf_unfiltered ("%-20s", local_hex_string_custom (txt_start, "08l")); + printf_unfiltered ("%-20s", local_hex_string_custom (txt_end, "08l")); + printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf_unfiltered ("%s\n", so -> so_name); + } + } + if (so_list_head == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + char *solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +char * +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && so -> textsection) + { + if ((address >= (CORE_ADDR) so -> textsection -> addr) && + (address < (CORE_ADDR) so -> textsection -> endaddr)) + return (so->so_name); + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> abfd) + { + bfd_filename = bfd_get_filename (so_list_head -> abfd); + if (!bfd_close (so_list_head -> abfd)) + warning ("cannot close \"%s\": %s", + bfd_filename, bfd_errmsg (bfd_get_error ())); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free ((PTR)so_list_head); + so_list_head = next; + } +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + For a statically bound executable, this first instruction is the + one at "_start", or a similar text label. No further processing is + needed in that case. + For a dynamically bound executable, this first instruction is somewhere + in the rld, and the actual user executable is not yet mapped in. + We continue the inferior again, rld then maps in the actual user + executable and any needed shared libraries and then sends + itself a SIGTRAP. + At that point we discover the names of all shared libraries and + read their symbols in. + +FIXME + + This code does not properly handle hitting breakpoints which the + user might have set in the rld itself. Proper handling would have + to check if the SIGTRAP happened due to a kill call. + + Also, what if child has exit()ed? Must exit loop somehow. + */ + +void +solib_create_inferior_hook() +{ + + /* Nothing to do for statically bound executables. */ + + if (symfile_objfile == NULL + || symfile_objfile->obfd == NULL + || ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0)) + return; + + /* Now run the target. It will eventually get a SIGTRAP, at + which point all of the libraries will have been mapped in and we + can go groveling around in the rld structures to find + out what we need to know about them. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = TARGET_SIGNAL_0; + do + { + target_resume (-1, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != TARGET_SIGNAL_TRAP); + + /* solib_add will call reinit_frame_cache. + But we are stopped in the runtime loader and we do not have symbols + for the runtime loader. So heuristic_proc_start will be called + and will put out an annoying warning. + Delaying the resetting of stop_soon_quietly until after symbol loading + suppresses the warning. */ + if (auto_solib_add) + solib_add ((char *) 0, 0, (struct target_ops *) 0); + stop_soon_quietly = 0; +} + + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_solib() +{ + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); + + add_show_from_set + (add_set_cmd ("auto-solib-add", class_support, var_zinteger, + (char *) &auto_solib_add, + "Set autoloading of shared library symbols.\n\ +If nonzero, symbols from all shared object libraries will be loaded\n\ +automatically when the inferior begins execution or when the dynamic linker\n\ +informs gdb that a new library has been loaded. Otherwise, symbols\n\ +must be loaded manually, using `sharedlibrary'.", + &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/parse.c b/contrib/gdb/gdb/parse.c new file mode 100644 index 000000000000..92f94657da87 --- /dev/null +++ b/contrib/gdb/gdb/parse.c @@ -0,0 +1,1013 @@ +/* Parse expressions for GDB. + Copyright (C) 1986, 1989, 1990, 1991, 1994 Free Software Foundation, Inc. + Modified from expread.y by the Department of Computer Science at the + State University of New York at Buffalo, 1991. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Parse an 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. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "frame.h" +#include "expression.h" +#include "value.h" +#include "command.h" +#include "language.h" +#include "parser-defs.h" + +/* Global variables declared in parser-defs.h (and commented there). */ +struct expression *expout; +int expout_size; +int expout_ptr; +struct block *expression_context_block; +struct block *innermost_block; +int arglist_len; +union type_stack_elt *type_stack; +int type_stack_depth, type_stack_size; +char *lexptr; +char *namecopy; +int paren_depth; +int comma_terminates; + +static void +free_funcalls PARAMS ((void)); + +static void +prefixify_expression PARAMS ((struct expression *)); + +static int +length_of_subexp PARAMS ((struct expression *, int)); + +static void +prefixify_subexp PARAMS ((struct expression *, struct expression *, int, int)); + +/* Data structure for saving values of arglist_len for function calls whose + arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +static struct funcall *funcall_chain; + +/* Assign machine-independent names to certain registers + (unless overridden by the REGISTER_NAMES table) */ + +#ifdef NO_STD_REGS +unsigned num_std_regs = 0; +struct std_regs std_regs[1]; +#else +struct std_regs std_regs[] = { + +#ifdef PC_REGNUM + { "pc", PC_REGNUM }, +#endif +#ifdef FP_REGNUM + { "fp", FP_REGNUM }, +#endif +#ifdef SP_REGNUM + { "sp", SP_REGNUM }, +#endif +#ifdef PS_REGNUM + { "ps", PS_REGNUM }, +#endif + +}; + +unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]); + +#endif + + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +void +start_arglist () +{ + register struct funcall *new; + + new = (struct funcall *) xmalloc (sizeof (struct funcall)); + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free ((PTR)call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free ((PTR)call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* 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 + a register through here */ + +void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) + xrealloc ((char *) expout, sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size)); + } + expout->elts[expout_ptr++] = expelt; +} + +void +write_exp_elt_opcode (expelt) + enum exp_opcode expelt; +{ + union exp_element tmp; + + tmp.opcode = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_sym (expelt) + struct symbol *expelt; +{ + union exp_element tmp; + + tmp.symbol = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_block (b) + struct block *b; +{ + union exp_element tmp; + tmp.block = b; + write_exp_elt (tmp); +} + +void +write_exp_elt_longcst (expelt) + LONGEST expelt; +{ + union exp_element tmp; + + tmp.longconst = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_dblcst (expelt) + DOUBLEST expelt; +{ + union exp_element tmp; + + tmp.doubleconst = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_type (expelt) + struct type *expelt; +{ + union exp_element tmp; + + tmp.type = expelt; + + write_exp_elt (tmp); +} + +void +write_exp_elt_intern (expelt) + struct internalvar *expelt; +{ + union exp_element tmp; + + tmp.internalvar = expelt; + + write_exp_elt (tmp); +} + +/* Add a string constant to the end of the expression. + + String constants are stored by first writing an expression element + that contains the length of the string, then stuffing the string + constant itself into however many expression elements are needed + to hold it, and then writing another expression element that contains + the length of the string. I.E. an expression element at each end of + the string records the string length, so you can skip over the + expression elements containing the actual string bytes from either + end of the string. Note that this also allows gdb to handle + strings with embedded null bytes, as is required for some languages. + + Don't be fooled by the fact that the string is null byte terminated, + this is strictly for the convenience of debugging gdb itself. Gdb + Gdb does not depend up the string being null terminated, since the + actual length is recorded in expression elements at each end of the + string. The null byte is taken into consideration when computing how + many expression elements are required to hold the string constant, of + course. */ + + +void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt; + register char *strdata; + + /* Compute the number of expression elements required to hold the string + (including a null byte terminator), along with one expression element + at each end to record the actual string length (not including the + null byte terminator). */ + + lenelt = 2 + BYTES_TO_EXP_ELEM (len + 1); + + /* Ensure that we have enough available expression elements to store + everything. */ + + if ((expout_ptr + lenelt) >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + lenelt + 10); + expout = (struct expression *) + xrealloc ((char *) expout, (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size))); + } + + /* Write the leading length expression element (which advances the current + expression element index), then write the string constant followed by a + terminating null byte, and then write the trailing length expression + element. */ + + write_exp_elt_longcst ((LONGEST) len); + strdata = (char *) &expout->elts[expout_ptr]; + memcpy (strdata, str.ptr, len); + *(strdata + len) = '\0'; + expout_ptr += lenelt - 2; + write_exp_elt_longcst ((LONGEST) len); +} + +/* Add a bitstring constant to the end of the expression. + + Bitstring constants are stored by first writing an expression element + that contains the length of the bitstring (in bits), then stuffing the + bitstring constant itself into however many expression elements are + needed to hold it, and then writing another expression element that + contains the length of the bitstring. I.E. an expression element at + each end of the bitstring records the bitstring length, so you can skip + over the expression elements containing the actual bitstring bytes from + either end of the bitstring. */ + +void +write_exp_bitstring (str) + struct stoken str; +{ + register int bits = str.length; /* length in bits */ + register int len = (bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; + register int lenelt; + register char *strdata; + + /* Compute the number of expression elements required to hold the bitstring, + along with one expression element at each end to record the actual + bitstring length in bits. */ + + lenelt = 2 + BYTES_TO_EXP_ELEM (len); + + /* Ensure that we have enough available expression elements to store + everything. */ + + if ((expout_ptr + lenelt) >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + lenelt + 10); + expout = (struct expression *) + xrealloc ((char *) expout, (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size))); + } + + /* Write the leading length expression element (which advances the current + expression element index), then write the bitstring constant, and then + write the trailing length expression element. */ + + write_exp_elt_longcst ((LONGEST) bits); + strdata = (char *) &expout->elts[expout_ptr]; + memcpy (strdata, str.ptr, len); + expout_ptr += lenelt - 2; + write_exp_elt_longcst ((LONGEST) bits); +} + +/* Add the appropriate elements for a minimal symbol to the end of + the expression. The rationale behind passing in text_symbol_type and + data_symbol_type was so that Modula-2 could pass in WORD for + data_symbol_type. Perhaps it still is useful to have those types vary + based on the language, but they no longer have names like "int", so + the initial rationale is gone. */ + +static struct type *msym_text_symbol_type; +static struct type *msym_data_symbol_type; +static struct type *msym_unknown_symbol_type; + +void +write_exp_msymbol (msymbol, text_symbol_type, data_symbol_type) + struct minimal_symbol *msymbol; + struct type *text_symbol_type; + struct type *data_symbol_type; +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (lookup_pointer_type (builtin_type_void)); + write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol)); + write_exp_elt_opcode (OP_LONG); + + write_exp_elt_opcode (UNOP_MEMVAL); + switch (msymbol -> type) + { + case mst_text: + case mst_file_text: + case mst_solib_trampoline: + write_exp_elt_type (msym_text_symbol_type); + break; + + case mst_data: + case mst_file_data: + case mst_bss: + case mst_file_bss: + write_exp_elt_type (msym_data_symbol_type); + break; + + default: + write_exp_elt_type (msym_unknown_symbol_type); + break; + } + write_exp_elt_opcode (UNOP_MEMVAL); +} + +/* Recognize tokens that start with '$'. These include: + + $regname A native register name or a "standard + register name". + + $variable A convenience variable with a name chosen + by the user. + + $digits Value history with index , starting + from the first value which has index 1. + + $$digits Value history with index relative + to the last value. I.E. $$0 is the last + value, $$1 is the one previous to that, $$2 + is the one previous to $$1, etc. + + $ | $0 | $$0 The last value in the value history. + + $$ An abbreviation for the second to the last + value in the value history, I.E. $$1 + + */ + +void +write_dollar_variable (str) + struct stoken str; +{ + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). */ + + int negate = 0; + int i = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (str.length >= 2 && str.ptr[1] == '$') + { + negate = 1; + i = 2; + } + if (i == str.length) + { + /* Just dollars (one or two) */ + i = - negate; + goto handle_last; + } + /* Is the rest of the token digits? */ + for (; i < str.length; i++) + if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9')) + break; + if (i == str.length) + { + i = atoi (str.ptr + 1 + negate); + if (negate) + i = - i; + goto handle_last; + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + for (i = 0; i < NUM_REGS; i++) + if (str.length - 1 == strlen (reg_names[i]) + && STREQN (str.ptr + 1, reg_names[i], str.length - 1)) + { + goto handle_register; + } + for (i = 0; i < num_std_regs; i++) + if (str.length - 1 == strlen (std_regs[i].name) + && STREQN (str.ptr + 1, std_regs[i].name, str.length - 1)) + { + i = std_regs[i].regnum; + goto handle_register; + } + + /* Any other names starting in $ are debugger internal variables. */ + + write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (lookup_internalvar (copy_name (str) + 1)); + write_exp_elt_opcode (OP_INTERNALVAR); + return; + handle_last: + write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) i); + write_exp_elt_opcode (OP_LAST); + return; + handle_register: + write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst (i); + write_exp_elt_opcode (OP_REGISTER); + return; +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +char * +copy_name (token) + struct stoken token; +{ + memcpy (namecopy, token.ptr, token.length); + namecopy[token.length] = 0; + 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). */ + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = + sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + memcpy (temp, expr, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + if (endpos < 1) + error ("?error in length_of_subexp"); + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + /* C++ */ + case OP_SCOPE: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_LONG: + case OP_DOUBLE: + case OP_VAR_VALUE: + oplen = 4; + break; + + case OP_TYPE: + case OP_BOOL: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_COMPLEX: + oplen = 1; + args = 2; + break; + + case OP_FUNCALL: + case OP_F77_UNDETERMINED_ARGLIST: + oplen = 3; + args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); + break; + + case UNOP_MAX: + case UNOP_MIN: + oplen = 3; + break; + + case BINOP_VAL: + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case UNOP_ABS: + case UNOP_CAP: + case UNOP_CHR: + case UNOP_FLOAT: + case UNOP_HIGH: + case UNOP_ODD: + case UNOP_ORD: + case UNOP_TRUNC: + oplen = 1; + args = 1; + break; + + case OP_LABELED: + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + /* fall through */ + case OP_M2_STRING: + case OP_STRING: + case OP_NAME: + case OP_EXPRSTRING: + oplen = longest_to_int (expr->elts[endpos - 2].longconst); + 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); + args -= longest_to_int (expr->elts[endpos - 3].longconst); + args += 1; + break; + + case TERNOP_COND: + case TERNOP_SLICE: + case TERNOP_SLICE_COUNT: + args = 3; + break; + + /* Modula-2 */ + case MULTI_SUBSCRIPT: + oplen = 3; + args = 1 + longest_to_int (expr->elts[endpos- 2].longconst); + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + /* C++ */ + case OP_SCOPE: + oplen = longest_to_int (inexpr->elts[inend - 2].longconst); + oplen = 5 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_LONG: + case OP_DOUBLE: + case OP_VAR_VALUE: + oplen = 4; + break; + + case OP_TYPE: + case OP_BOOL: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_COMPLEX: + oplen = 1; + args = 2; + break; + + case OP_FUNCALL: + case OP_F77_UNDETERMINED_ARGLIST: + oplen = 3; + args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst); + break; + + case UNOP_MIN: + case UNOP_MAX: + oplen = 3; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case UNOP_ABS: + case UNOP_CAP: + case UNOP_CHR: + case UNOP_FLOAT: + case UNOP_HIGH: + case UNOP_ODD: + case UNOP_ORD: + case UNOP_TRUNC: + oplen=1; + args=1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + case OP_LABELED: + args = 1; + /* fall through */ + case OP_M2_STRING: + case OP_STRING: + case OP_NAME: + case OP_EXPRSTRING: + oplen = longest_to_int (inexpr->elts[inend - 2].longconst); + oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1); + break; + + case OP_BITSTRING: + oplen = longest_to_int (inexpr->elts[inend - 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 (inexpr->elts[inend - 2].longconst); + args -= longest_to_int (inexpr->elts[inend - 3].longconst); + args += 1; + break; + + case TERNOP_COND: + case TERNOP_SLICE: + case TERNOP_SLICE_COUNT: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* Modula-2 */ + case MULTI_SUBSCRIPT: + oplen = 3; + args = 1 + longest_to_int (inexpr->elts[inend - 2].longconst); + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + memcpy (&outexpr->elts[outbeg], &inexpr->elts[inend], + EXP_ELEM_TO_BYTES (oplen)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read an expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). + + If COMMA is nonzero, stop if a comma is reached. */ + +struct expression * +parse_exp_1 (stringptr, block, comma) + char **stringptr; + struct block *block; + int comma; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + paren_depth = 0; + type_stack_depth = 0; + + comma_terminates = comma; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) + xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size)); + expout->language_defn = current_language; + make_cleanup (free_current_contents, &expout); + + if (current_language->la_parser ()) + current_language->la_error (NULL); + + 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));; + + /* Convert expression from postfix form as generated by yacc + parser, to a prefix form. */ + + DUMP_EXPRESSION (expout, gdb_stdout, "before conversion to prefix form"); + prefixify_expression (expout); + DUMP_EXPRESSION (expout, gdb_stdout, "after conversion to prefix form"); + + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_exp_1 (&string, 0, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} + +/* Stuff for maintaining a stack of types. Currently just used by C, but + probably useful for any language which declares its types "backwards". */ + +void +push_type (tp) + enum type_pieces tp; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (union type_stack_elt *) + xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack)); + } + type_stack[type_stack_depth++].piece = tp; +} + +void +push_type_int (n) + int n; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (union type_stack_elt *) + xrealloc ((char *) type_stack, type_stack_size * sizeof (*type_stack)); + } + type_stack[type_stack_depth++].int_val = n; +} + +enum type_pieces +pop_type () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth].piece; + return tp_end; +} + +int +pop_type_int () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth].int_val; + /* "Can't happen". */ + return 0; +} + +/* Pop the type stack and return the type which corresponds to FOLLOW_TYPE + as modified by all the stuff on the stack. */ +struct type * +follow_types (follow_type) + struct type *follow_type; +{ + int done = 0; + int array_size; + struct type *range_type; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = pop_type_int (); + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + range_type = + create_range_type ((struct type *) NULL, + builtin_type_int, 0, + array_size >= 0 ? array_size - 1 : 0); + follow_type = + create_array_type ((struct type *) NULL, + follow_type, range_type); + if (array_size < 0) + TYPE_ARRAY_UPPER_BOUND_TYPE(follow_type) + = BOUND_CANNOT_BE_DETERMINED; + break; + case tp_function: + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + follow_type = lookup_function_type (follow_type); + break; + } + return follow_type; +} + +void +_initialize_parse () +{ + type_stack_size = 80; + type_stack_depth = 0; + type_stack = (union type_stack_elt *) + xmalloc (type_stack_size * sizeof (*type_stack)); + + msym_text_symbol_type = + init_type (TYPE_CODE_FUNC, 1, 0, "", NULL); + TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_int; + msym_data_symbol_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0, + "", NULL); + msym_unknown_symbol_type = + init_type (TYPE_CODE_INT, 1, 0, + "", + NULL); +} diff --git a/contrib/gdb/gdb/parser-defs.h b/contrib/gdb/gdb/parser-defs.h new file mode 100644 index 000000000000..60c12e6a356f --- /dev/null +++ b/contrib/gdb/gdb/parser-defs.h @@ -0,0 +1,191 @@ +/* Parser definitions for GDB. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + Modified from expread.y by the Department of Computer Science at the + State University of New York at Buffalo. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (PARSER_DEFS_H) +#define PARSER_DEFS_H 1 + +struct std_regs { + char *name; + int regnum; +}; + +extern struct std_regs std_regs[]; +extern unsigned num_std_regs; + +extern struct expression *expout; +extern int expout_size; +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; + +/* The innermost context required by the stack and register variables + we've encountered so far. */ +extern 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; + +/* Number of arguments seen so far in innermost function call. */ +extern int arglist_len; + +/* A string token, either a char-string or bit-string. Char-strings are + used, for example, for the names of symbols. */ + +struct stoken + { + /* Pointer to first byte of char-string or first bit of bit-string */ + char *ptr; + /* Length of string in bytes for char-string or bits for bit-string */ + int length; + }; + +struct ttype + { + struct stoken stoken; + struct type *type; + }; + +struct symtoken + { + struct stoken stoken; + struct symbol *sym; + int is_a_field_of_this; + }; + +/* For parsing of complicated types. + An array should be preceded in the list by the size of the array. */ +enum type_pieces + {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function}; +/* The stack can contain either an enum type_pieces or an int. */ +union type_stack_elt { + enum type_pieces piece; + int int_val; +}; +extern union type_stack_elt *type_stack; +extern int type_stack_depth, type_stack_size; + +extern void write_exp_elt PARAMS ((union exp_element)); + +extern void write_exp_elt_opcode PARAMS ((enum exp_opcode)); + +extern void write_exp_elt_sym PARAMS ((struct symbol *)); + +extern void write_exp_elt_longcst PARAMS ((LONGEST)); + +extern void write_exp_elt_dblcst PARAMS ((DOUBLEST)); + +extern void write_exp_elt_type PARAMS ((struct type *)); + +extern void write_exp_elt_intern PARAMS ((struct internalvar *)); + +extern void write_exp_string PARAMS ((struct stoken)); + +extern void write_exp_bitstring PARAMS ((struct stoken)); + +extern void write_exp_elt_block PARAMS ((struct block *)); + +extern void write_exp_msymbol PARAMS ((struct minimal_symbol *, + struct type *, struct type *)); + +extern void write_dollar_variable PARAMS ((struct stoken str)); + +extern void +start_arglist PARAMS ((void)); + +extern int +end_arglist PARAMS ((void)); + +extern char * +copy_name PARAMS ((struct stoken)); + +extern void +push_type PARAMS ((enum type_pieces)); + +extern void +push_type_int PARAMS ((int)); + +extern enum type_pieces +pop_type PARAMS ((void)); + +extern int +pop_type_int PARAMS ((void)); + +extern struct type *follow_types PARAMS ((struct type *)); + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +extern char *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; + +/* Nonzero means stop parsing on first comma (if not within parentheses). */ + +extern int comma_terminates; + +/* These codes indicate operator precedences for expression printing, + least tightly binding first. */ +/* Adding 1 to a precedence value is done for binary operators, + on the operand which is more tightly bound, so that operators + of equal precedence within that operand will get parentheses. */ +/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator; + they are used as the "surrounding precedence" to force + various kinds of things to be parenthesized. */ +enum precedence +{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_LOGICAL_OR, + PREC_LOGICAL_AND, PREC_BITWISE_IOR, PREC_BITWISE_AND, PREC_BITWISE_XOR, + PREC_EQUAL, PREC_ORDER, PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT, + PREC_HYPER, PREC_PREFIX, PREC_SUFFIX, PREC_BUILTIN_FUNCTION }; + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +struct op_print +{ + char *string; + enum exp_opcode opcode; + /* Precedence of operator. These values are used only by comparisons. */ + enum precedence precedence; + + /* For a binary operator: 1 iff right associate. + For a unary operator: 1 iff postfix. */ + int right_assoc; +}; + +#endif /* PARSER_DEFS_H */ diff --git a/contrib/gdb/gdb/partial-stab.h b/contrib/gdb/gdb/partial-stab.h new file mode 100644 index 000000000000..d00680909f65 --- /dev/null +++ b/contrib/gdb/gdb/partial-stab.h @@ -0,0 +1,774 @@ +/* Shared code to pre-read a stab (dbx-style), when building a psymtab. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The following need to be defined: + SET_NAMESTRING() --Set namestring to name of symbol. + CUR_SYMBOL_TYPE --Type code of current symbol. + CUR_SYMBOL_VALUE --Value field of current symbol. May be adjusted here. + namestring - variable pointing to the name of the stab. + section_offsets - variable pointing to the section offsets. + pst - the partial symbol table being built. + + psymtab_include_list, includes_used, includes_allocated - list of include + file names (N_SOL) seen so far. + dependency_list, dependencies_used, dependencies_allocated - list of + N_EXCL stabs seen so far. + + END_PSYMTAB -- end a partial symbol table. + START_PSYMTAB -- start a partial symbol table. + */ + +/* End of macro definitions, now let's handle them symbols! */ + + switch (CUR_SYMBOL_TYPE) + { + char *p; + /* + * Standard, external, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + case N_NBTEXT | N_EXT: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); + goto record_it; + + case N_DATA | N_EXT: + case N_NBDATA | N_EXT: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto record_it; + + case N_BSS: + case N_BSS | N_EXT: + case N_NBBSS | N_EXT: + case N_SETV | N_EXT: /* FIXME, is this in BSS? */ + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_BSS); + goto record_it; + + case N_ABS | N_EXT: + record_it: +#ifdef DBXREAD_ONLY + SET_NAMESTRING(); + + bss_ext_symbol: + record_minimal_symbol (namestring, CUR_SYMBOL_VALUE, + CUR_SYMBOL_TYPE, objfile); /* Always */ +#endif /* DBXREAD_ONLY */ + continue; + + /* Standard, local, non-debugger, symbols */ + + case N_NBTEXT: + + /* We need to be able to deal with both N_FN or N_TEXT, + because we have no way of knowing whether the sys-supplied ld + or GNU ld was used to make the executable. Sequents throw + in another wrinkle -- they renumbered N_FN. */ + + case N_FN: + case N_FN_SEQ: + case N_TEXT: +#ifdef DBXREAD_ONLY + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); + SET_NAMESTRING(); + if ((namestring[0] == '-' && namestring[1] == 'l') + || (namestring [(nsl = strlen (namestring)) - 1] == 'o' + && namestring [nsl - 2] == '.')) + { + if (objfile -> ei.entry_point < CUR_SYMBOL_VALUE && + objfile -> ei.entry_point >= last_o_file_start) + { + objfile -> ei.entry_file_lowpc = last_o_file_start; + objfile -> ei.entry_file_highpc = CUR_SYMBOL_VALUE; + } + if (past_first_source_file && pst + /* The gould NP1 uses low values for .o and -l symbols + which are not the address. */ + && CUR_SYMBOL_VALUE >= pst->textlow) + { + END_PSYMTAB (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + CUR_SYMBOL_VALUE > pst->texthigh + ? CUR_SYMBOL_VALUE : pst->texthigh, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + else + past_first_source_file = 1; + last_o_file_start = CUR_SYMBOL_VALUE; + } + else + goto record_it; +#endif /* DBXREAD_ONLY */ + continue; + + case N_DATA: + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + goto record_it; + + case N_UNDF | N_EXT: +#ifdef DBXREAD_ONLY + if (CUR_SYMBOL_VALUE != 0) { + /* This is a "Fortran COMMON" symbol. See if the target + environment knows where it has been relocated to. */ + + CORE_ADDR reladdr; + + SET_NAMESTRING(); + if (target_lookup_symbol (namestring, &reladdr)) { + continue; /* Error in lookup; ignore symbol for now. */ + } + CUR_SYMBOL_TYPE ^= (N_BSS^N_UNDF); /* Define it as a bss-symbol */ + CUR_SYMBOL_VALUE = reladdr; + goto bss_ext_symbol; + } +#endif /* DBXREAD_ONLY */ + continue; /* Just undefined, not COMMON */ + + case N_UNDF: +#ifdef DBXREAD_ONLY + if (processing_acc_compilation && bufp->n_strx == 1) { + /* Deal with relative offsets in the string table + used in ELF+STAB under Solaris. If we want to use the + n_strx field, which contains the name of the file, + we must adjust file_string_table_offset *before* calling + SET_NAMESTRING(). */ + past_first_source_file = 1; + file_string_table_offset = next_file_string_table_offset; + next_file_string_table_offset = + file_string_table_offset + bufp->n_value; + if (next_file_string_table_offset < file_string_table_offset) + error ("string table offset backs up at %d", symnum); + /* FIXME -- replace error() with complaint. */ + continue; + } +#endif /* DBXREAD_ONLY */ + continue; + + /* Lots of symbol types we can just ignore. */ + + case N_ABS: + case N_NBDATA: + case N_NBBSS: + continue; + + /* Keep going . . .*/ + + /* + * Special symbol types for GNU + */ + case N_INDR: + case N_INDR | N_EXT: + case N_SETA: + case N_SETA | N_EXT: + case N_SETT: + case N_SETT | N_EXT: + case N_SETD: + case N_SETD | N_EXT: + case N_SETB: + case N_SETB | N_EXT: + case N_SETV: + continue; + + /* + * Debugger symbols + */ + + case N_SO: { + unsigned long valu; + static int prev_so_symnum = -10; + static int first_so_symnum; + char *p; + + valu = CUR_SYMBOL_VALUE + ANOFFSET (section_offsets, SECT_OFF_TEXT); +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* A zero value is probably an indication for the SunPRO 3.0 + compiler. end_psymtab explicitly tests for zero, so + don't relocate it. */ + if (CUR_SYMBOL_VALUE == 0) + valu = 0; +#endif + + past_first_source_file = 1; + + if (prev_so_symnum != symnum - 1) + { /* Here if prev stab wasn't N_SO */ + first_so_symnum = symnum; + + if (pst) + { + END_PSYMTAB (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + valu > pst->texthigh ? valu : pst->texthigh, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } + } + + prev_so_symnum = symnum; + + /* End the current partial symtab and start a new one */ + + SET_NAMESTRING(); + + /* Null name means end of .o file. Don't start a new one. */ + if (*namestring == '\000') + continue; + + /* Some compilers (including gcc) emit a pair of initial N_SOs. + The first one is a directory name; the second the file name. + If pst exists, is empty, and has a filename ending in '/', + we assume the previous N_SO was a directory name. */ + + p = strrchr (namestring, '/'); + if (p && *(p+1) == '\000') + continue; /* Simply ignore directory name SOs */ + + /* Some other compilers (C++ ones in particular) emit useless + SOs for non-existant .c files. We ignore all subsequent SOs that + immediately follow the first. */ + + if (!pst) + pst = START_PSYMTAB (objfile, section_offsets, + namestring, valu, + first_so_symnum * symbol_size, + objfile -> global_psymbols.next, + objfile -> static_psymbols.next); + continue; + } + + case N_BINCL: + { +#ifdef DBXREAD_ONLY + enum language tmp_language; + /* Add this bincl to the bincl_list for future EXCLs. No + need to save the string; it'll be around until + read_dbx_symtab function returns */ + + SET_NAMESTRING(); + + tmp_language = deduce_language_from_filename (namestring); + + /* Only change the psymtab's language if we've learned + something useful (eg. tmp_language is not language_unknown). + In addition, to match what start_subfile does, never change + from C++ to C. */ + if (tmp_language != language_unknown + && (tmp_language != language_c + || psymtab_language != language_cplus)) + psymtab_language = tmp_language; + + add_bincl_to_list (pst, namestring, CUR_SYMBOL_VALUE); + + /* Mark down an include file in the current psymtab */ + + goto record_include_file; + +#else /* DBXREAD_ONLY */ + continue; +#endif + } + + case N_SOL: + { + enum language tmp_language; + /* Mark down an include file in the current psymtab */ + + SET_NAMESTRING(); + + tmp_language = deduce_language_from_filename (namestring); + + /* Only change the psymtab's language if we've learned + something useful (eg. tmp_language is not language_unknown). + In addition, to match what start_subfile does, never change + from C++ to C. */ + if (tmp_language != language_unknown + && (tmp_language != language_c + || psymtab_language != language_cplus)) + psymtab_language = tmp_language; + + /* In C++, one may expect the same filename to come round many + times, when code is coming alternately from the main file + and from inline functions in other files. So I check to see + if this is a file we've seen before -- either the main + source file, or a previously included file. + + This seems to be a lot of time to be spending on N_SOL, but + things like "break c-exp.y:435" need to work (I + suppose the psymtab_include_list could be hashed or put + in a binary tree, if profiling shows this is a major hog). */ + if (pst && STREQ (namestring, pst->filename)) + continue; + { + register int i; + for (i = 0; i < includes_used; i++) + if (STREQ (namestring, psymtab_include_list[i])) + { + i = -1; + break; + } + if (i == -1) + continue; + } + +#ifdef DBXREAD_ONLY + record_include_file: +#endif + + psymtab_include_list[includes_used++] = namestring; + if (includes_used >= includes_allocated) + { + char **orig = psymtab_include_list; + + psymtab_include_list = (char **) + alloca ((includes_allocated *= 2) * + sizeof (char *)); + memcpy ((PTR)psymtab_include_list, (PTR)orig, + includes_used * sizeof (char *)); + } + continue; + } + case N_LSYM: /* Typedef or automatic variable. */ + case N_STSYM: /* Data seg var -- static */ + case N_LCSYM: /* BSS " */ + case N_ROSYM: /* Read-only data seg var -- static. */ + case N_NBSTS: /* Gould nobase. */ + case N_NBLCS: /* symbols. */ + case N_FUN: + case N_GSYM: /* Global (extern) variable; can be + data or bss (sigh FIXME). */ + + /* Following may probably be ignored; I'll leave them here + for now (until I do Pascal and Modula 2 extensions). */ + + case N_PC: /* I may or may not need this; I + suspect not. */ + case N_M2C: /* I suspect that I can ignore this here. */ + case N_SCOPE: /* Same. */ + + SET_NAMESTRING(); + +#ifdef DBXREAD_ONLY + /* See if this is an end of function stab. */ + if (CUR_SYMBOL_TYPE == N_FUN && ! strcmp (namestring, "")) + { + unsigned long valu; + + /* It's value is the size (in bytes) of the function for + function relative stabs, or the address of the function's + end for old style stabs. */ + valu = CUR_SYMBOL_VALUE + last_function_start; + if (pst->texthigh == 0 || valu > pst->texthigh) + pst->texthigh = valu; + break; + } +#endif + + p = (char *) strchr (namestring, ':'); + if (!p) + continue; /* Not a debugging symbol. */ + + + + /* Main processing section for debugging symbols which + the initial read through the symbol tables needs to worry + about. If we reach this point, the symbol which we are + considering is definitely one we are interested in. + p must also contain the (valid) index into the namestring + which indicates the debugging type symbol. */ + + switch (p[1]) + { + case 'S': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); +#ifdef STATIC_TRANSFORM_NAME + namestring = STATIC_TRANSFORM_NAME (namestring); +#endif + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->static_psymbols, + 0, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + case 'G': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_DATA); + /* The addresses in these entries are reported to be + wrong. See the code that reads 'G's for symtabs. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + &objfile->global_psymbols, + 0, CUR_SYMBOL_VALUE, + psymtab_language, objfile); + continue; + + case 'T': + if (p != namestring) /* a name is there, not just :T... */ + { + add_psymbol_to_list (namestring, p - namestring, + STRUCT_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + if (p[2] == 't') + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + p += 1; + } + /* The semantics of C++ state that "struct foo { ... }" + also defines a typedef for "foo". Unfortuantely, cfront + never makes the typedef when translating from C++ to C. + We make the typedef here so that "ptype foo" works as + expected for cfront translated code. */ + else if (psymtab_language == language_cplus) + { + /* Also a typedef with the same name. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + } + } + goto check_enum; + case 't': + if (p != namestring) /* a name is there, not just :T... */ + { + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_TYPEDEF, + &objfile->static_psymbols, + CUR_SYMBOL_VALUE, 0, + psymtab_language, objfile); + } + check_enum: + /* If this is an enumerated type, we need to + add all the enum constants to the partial symbol + table. This does not cover enums without names, e.g. + "enum {a, b} c;" in C, but fortunately those are + rare. There is no way for GDB to find those from the + enum type without spending too much time on it. Thus + to solve this problem, the compiler needs to put out the + enum in a nameless type. GCC2 does this. */ + + /* We are looking for something of the form + ":" ("t" | "T") [ "="] "e" + { ":" ","} ";". */ + + /* Skip over the colon and the 't' or 'T'. */ + p += 2; + /* This type may be given a number. Also, numbers can come + in pairs like (0,26). Skip over it. */ + while ((*p >= '0' && *p <= '9') + || *p == '(' || *p == ',' || *p == ')' + || *p == '=') + p++; + + if (*p++ == 'e') + { + /* The aix4 compiler emits extra crud before the members. */ + if (*p == '-') + { + /* Skip over the type (?). */ + while (*p != ':') + p++; + + /* Skip over the colon. */ + p++; + } + + /* We have found an enumerated type. */ + /* According to comments in read_enum_type + a comma could end it instead of a semicolon. + I don't know where that happens. + Accept either. */ + while (*p && *p != ';' && *p != ',') + { + char *q; + + /* Check for and handle cretinous dbx symbol name + continuation! */ + if (*p == '\\' || (*p == '?' && p[1] == '\0')) + p = next_symbol_text (objfile); + + /* Point to the character after the name + of the enum constant. */ + for (q = p; *q && *q != ':'; q++) + ; + /* Note that the value doesn't matter for + enum constants in psymtabs, just in symtabs. */ + add_psymbol_to_list (p, q - p, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, 0, + 0, psymtab_language, objfile); + /* Point past the name. */ + p = q; + /* Skip over the value. */ + while (*p && *p != ',') + p++; + /* Advance past the comma. */ + if (*p) + p++; + } + } + continue; + case 'c': + /* Constant, e.g. from "const" in Pascal. */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_CONST, + &objfile->static_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + case 'f': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); +#ifdef DBXREAD_ONLY + /* Keep track of the start of the last function so we + can handle end of function symbols. */ + last_function_start = CUR_SYMBOL_VALUE; + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit + value for the bottom of the text seg in those cases. */ + if (pst && pst->textlow == 0 && !symfile_relocatable) + pst->textlow = + find_stab_function_addr (namestring, pst, objfile); +#endif +#if 0 + if (startup_file_end == 0) + startup_file_end = CUR_SYMBOL_VALUE; +#endif + /* End kludge. */ + + /* In reordered executables this function may lie outside + the bounds created by N_SO symbols. If that's the case + use the address of this function as the low bound for + the partial symbol table. */ + if (pst->textlow == 0 + || (CUR_SYMBOL_VALUE < pst->textlow + && CUR_SYMBOL_VALUE + != ANOFFSET (section_offsets, SECT_OFF_TEXT))) + pst->textlow = CUR_SYMBOL_VALUE; +#endif /* DBXREAD_ONLY */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->static_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + /* Global functions were ignored here, but now they + are put into the global psymtab like one would expect. + They're also in the minimal symbol table. */ + case 'F': + CUR_SYMBOL_VALUE += ANOFFSET (section_offsets, SECT_OFF_TEXT); +#ifdef DBXREAD_ONLY + /* Keep track of the start of the last function so we + can handle end of function symbols. */ + last_function_start = CUR_SYMBOL_VALUE; + /* Kludges for ELF/STABS with Sun ACC */ + last_function_name = namestring; +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Do not fix textlow==0 for .o or NLM files, as 0 is a legit + value for the bottom of the text seg in those cases. */ + if (pst && pst->textlow == 0 && !symfile_relocatable) + pst->textlow = + find_stab_function_addr (namestring, pst, objfile); +#endif +#if 0 + if (startup_file_end == 0) + startup_file_end = CUR_SYMBOL_VALUE; +#endif + /* End kludge. */ + /* In reordered executables this function may lie outside + the bounds created by N_SO symbols. If that's the case + use the address of this function as the low bound for + the partial symbol table. */ + if (pst->textlow == 0 + || (CUR_SYMBOL_VALUE < pst->textlow + && CUR_SYMBOL_VALUE + != ANOFFSET (section_offsets, SECT_OFF_TEXT))) + pst->textlow = CUR_SYMBOL_VALUE; +#endif /* DBXREAD_ONLY */ + add_psymbol_to_list (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + &objfile->global_psymbols, CUR_SYMBOL_VALUE, + 0, psymtab_language, objfile); + continue; + + /* Two things show up here (hopefully); static symbols of + local scope (static used inside braces) or extensions + of structure symbols. We can ignore both. */ + case 'V': + case '(': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + continue; + + case ':': + /* It is a C++ nested symbol. We don't need to record it + (I don't think); if we try to look up foo::bar::baz, + then symbols for the symtab containing foo should get + read in, I think. */ + /* Someone says sun cc puts out symbols like + /foo/baz/maclib::/usr/local/bin/maclib, + which would get here with a symbol type of ':'. */ + continue; + + default: + /* Unexpected symbol descriptor. The second and subsequent stabs + of a continued stab can show up here. The question is + whether they ever can mimic a normal stab--it would be + nice if not, since we certainly don't want to spend the + time searching to the end of every string looking for + a backslash. */ + + complain (&unknown_symchar_complaint, p[1]); + + /* Ignore it; perhaps it is an extension that we don't + know about. */ + continue; + } + + case N_EXCL: +#ifdef DBXREAD_ONLY + + SET_NAMESTRING(); + + /* Find the corresponding bincl and mark that psymtab on the + psymtab dependency list */ + { + struct partial_symtab *needed_pst = + find_corresponding_bincl_psymtab (namestring, CUR_SYMBOL_VALUE); + + /* If this include file was defined earlier in this file, + leave it alone. */ + if (needed_pst == pst) continue; + + if (needed_pst) + { + int i; + int found = 0; + + for (i = 0; i < dependencies_used; i++) + if (dependency_list[i] == needed_pst) + { + found = 1; + break; + } + + /* If it's already in the list, skip the rest. */ + if (found) continue; + + dependency_list[dependencies_used++] = needed_pst; + if (dependencies_used >= dependencies_allocated) + { + struct partial_symtab **orig = dependency_list; + dependency_list = + (struct partial_symtab **) + alloca ((dependencies_allocated *= 2) + * sizeof (struct partial_symtab *)); + memcpy ((PTR)dependency_list, (PTR)orig, + (dependencies_used + * sizeof (struct partial_symtab *))); +#ifdef DEBUG_INFO + fprintf_unfiltered (gdb_stderr, "Had to reallocate dependency list.\n"); + fprintf_unfiltered (gdb_stderr, "New dependencies allocated: %d\n", + dependencies_allocated); +#endif + } + } + } +#endif /* DBXREAD_ONLY */ + continue; + + case N_ENDM: +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Solaris 2 end of module, finish current partial symbol table. + END_PSYMTAB will set pst->texthigh to the proper value, which + is necessary if a module compiled without debugging info + follows this module. */ + if (pst) + { + END_PSYMTAB (pst, psymtab_include_list, includes_used, + symnum * symbol_size, + (CORE_ADDR) 0, + dependency_list, dependencies_used); + pst = (struct partial_symtab *) 0; + includes_used = 0; + dependencies_used = 0; + } +#endif + continue; + + case N_RBRAC: +#ifdef HANDLE_RBRAC + HANDLE_RBRAC(CUR_SYMBOL_VALUE); + continue; +#endif + case N_EINCL: + case N_DSLINE: + case N_BSLINE: + case N_SSYM: /* Claim: Structure or union element. + Hopefully, I can ignore this. */ + case N_ENTRY: /* Alternate entry point; can ignore. */ + case N_MAIN: /* Can definitely ignore this. */ + case N_CATCH: /* These are GNU C++ extensions */ + case N_EHDECL: /* that can safely be ignored here. */ + case N_LENG: + case N_BCOMM: + case N_ECOMM: + case N_ECOML: + case N_FNAME: + case N_SLINE: + case N_RSYM: + case N_PSYM: + case N_LBRAC: + case N_NSYMS: /* Ultrix 4.0: symbol count */ + case N_DEFD: /* GNU Modula-2 */ + + case N_OBJ: /* useless types from Solaris */ + case N_OPT: + /* These symbols aren't interesting; don't worry about them */ + + continue; + + default: + /* If we haven't found it yet, ignore it. It's probably some + new type we don't know about yet. */ + complain (&unknown_symtype_complaint, + local_hex_string (CUR_SYMBOL_TYPE)); + continue; + } diff --git a/contrib/gdb/gdb/ppcbug-rom.c b/contrib/gdb/gdb/ppcbug-rom.c new file mode 100644 index 000000000000..6c7432be7b45 --- /dev/null +++ b/contrib/gdb/gdb/ppcbug-rom.c @@ -0,0 +1,233 @@ +/* Remote debugging interface for PPCbug (PowerPC) Rom monitor + for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + + Written by Stu Grossman of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void ppcbug_open PARAMS ((char *args, int from_tty)); + +static void +ppcbug_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno = 0, base = 0; + + if (regnamelen < 2 || regnamelen > 4) + return; + + switch (regname[0]) + { + case 'R': + if (regname[1] < '0' || regname[1] > '9') + return; + if (regnamelen == 2) + regno = regname[1] - '0'; + else if (regnamelen == 3 && regname[2] >= '0' && regname[2] <= '9') + regno = (regname[1] - '0') * 10 + (regname[2] - '0'); + else + return; + break; + case 'F': + if (regname[1] != 'R' || regname[2] < '0' || regname[2] > '9') + return; + if (regnamelen == 3) + regno = 32 + regname[2] - '0'; + else if (regnamelen == 4 && regname[3] >= '0' && regname[3] <= '9') + regno = 32 + (regname[2] - '0') * 10 + (regname[3] - '0'); + else + return; + break; + case 'I': + if (regnamelen != 2 || regname[1] != 'P') + return; + regno = 64; + break; + case 'M': + if (regnamelen != 3 || regname[1] != 'S' || regname[2] != 'R') + return; + regno = 65; + break; + case 'C': + if (regnamelen != 2 || regname[1] != 'R') + return; + regno = 66; + break; + case 'S': + if (regnamelen != 4 || regname[1] != 'P' || regname[2] != 'R') + return; + else if (regname[3] == '8') + regno = 67; + else if (regname[3] == '9') + regno = 68; + else if (regname[3] == '1') + regno = 69; + else if (regname[3] == '0') + regno = 70; + else + return; + break; + default: + return; + } + + monitor_supply_register (regno, val); +} + +/* + * This array of registers needs to match the indexes used by GDB. The + * whole reason this exists is because the various ROM monitors use + * different names than GDB does, and don't support all the + * registers either. So, typing "info reg sp" becomes an "A7". + */ + +static char *ppcbug_regnames[NUM_REGS] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + + "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", + "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", + "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", + "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", + +/* pc ps cnd lr cnt xer mq */ + "ip", "msr", "cr", "spr8", "spr9", "spr1", "spr0" +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops ppcbug_ops0; +static struct target_ops ppcbug_ops1; + +static char *ppcbug_inits[] = {"\r", NULL}; + +#define PPC_CMDS(LOAD_CMD, OPS) \ +{ \ + MO_CLR_BREAK_USES_ADDR | MO_HANDLE_NL, \ + ppcbug_inits, /* Init strings */ \ + "g\r", /* continue command */ \ + "t\r", /* single step */ \ + NULL, /* interrupt command */ \ + "br %x\r", /* set a breakpoint */ \ + "nobr %x\r", /* clear a breakpoint */ \ + "nobr\r", /* clear all breakpoints */ \ + "bf %x:%x %x;b\r", /* fill (start count val) */ \ + { \ + "ms %x %02x\r", /* setmem.cmdb (addr, value) */ \ + "ms %x %04x\r", /* setmem.cmdw (addr, value) */ \ + "ms %x %08x\r", /* setmem.cmdl (addr, value) */ \ + NULL, /* setmem.cmdll (addr, value) */ \ + NULL, /* setreg.resp_delim */ \ + NULL, /* setreg.term */ \ + NULL, /* setreg.term_cmd */ \ + }, \ + { \ + "md %x:%x;b\r", /* getmem.cmdb (addr, len) */ \ + "md %x:%x;b\r", /* getmem.cmdw (addr, len) */ \ + "md %x:%x;b\r", /* getmem.cmdl (addr, len) */ \ + NULL, /* getmem.cmdll (addr, len) */ \ + " ", /* getmem.resp_delim */ \ + NULL, /* getmem.term */ \ + NULL, /* getmem.term_cmd */ \ + }, \ + { \ + "rs %s %x\r", /* setreg.cmd (name, value) */ \ + NULL, /* setreg.resp_delim */ \ + NULL, /* setreg.term */ \ + NULL /* setreg.term_cmd */ \ + }, \ + { \ + "rs %s\r", /* getreg.cmd (name) */ \ + "=", /* getreg.resp_delim */ \ + NULL, /* getreg.term */ \ + NULL /* getreg.term_cmd */ \ + }, \ + "rd\r", /* dump_registers */ \ + "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)", /* register_pattern */ \ + ppcbug_supply_register, /* supply_register */ \ + NULL, /* load_routine (defaults to SRECs) */ \ + LOAD_CMD, /* download command */ \ + NULL, /* load response */ \ + "PPC1-Bug>", /* monitor command prompt */ \ + "\r", /* end-of-line terminator */ \ + NULL, /* optional command terminator */ \ + &OPS, /* target operations */ \ + SERIAL_1_STOPBITS, /* number of stop bits */ \ + ppcbug_regnames, /* registers names */ \ + MONITOR_OPS_MAGIC /* magic */ \ +} + + +static struct monitor_ops ppcbug_cmds0 = PPC_CMDS("lo 0\r", ppcbug_ops0); +static struct monitor_ops ppcbug_cmds1 = PPC_CMDS("lo 1\r", ppcbug_ops1); + +static void +ppcbug_open0(args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &ppcbug_cmds0, from_tty); +} + +static void +ppcbug_open1(args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &ppcbug_cmds1, from_tty); +} + +void +_initialize_ppcbug_rom () +{ + init_monitor_ops (&ppcbug_ops0); + + ppcbug_ops0.to_shortname = "ppcbug"; + ppcbug_ops0.to_longname = "PowerPC PPCBug monitor on port 0"; + ppcbug_ops0.to_doc = "Debug via the PowerPC PPCBug monitor using port 0.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + ppcbug_ops0.to_open = ppcbug_open0; + + add_target (&ppcbug_ops0); + + init_monitor_ops (&ppcbug_ops1); + + ppcbug_ops1.to_shortname = "ppcbug1"; + ppcbug_ops1.to_longname = "PowerPC PPCBug monitor on port 1"; + ppcbug_ops1.to_doc = "Debug via the PowerPC PPCBug monitor using port 1.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + ppcbug_ops1.to_open = ppcbug_open1; + + add_target (&ppcbug_ops1); +} diff --git a/contrib/gdb/gdb/printcmd.c b/contrib/gdb/gdb/printcmd.c new file mode 100644 index 000000000000..29f05726ff55 --- /dev/null +++ b/contrib/gdb/gdb/printcmd.c @@ -0,0 +1,2248 @@ +/* Print values for GNU debugger GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "frame.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "language.h" +#include "expression.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" +#include "breakpoint.h" +#include "demangle.h" +#include "valprint.h" +#include "annotate.h" + +extern int asm_demangle; /* Whether to demangle syms in asm printouts */ +extern int addressprint; /* Whether to print hex addresses in HLL " */ + +struct format_data +{ + int count; + char format; + char size; +}; + +/* Last specified output format. */ + +static char last_format = 'x'; + +/* Last specified examination size. 'b', 'h', 'w' or `q'. */ + +static char last_size = 'w'; + +/* Default address to examine next. */ + +static CORE_ADDR next_address; + +/* Last address examined. */ + +static CORE_ADDR last_examine_address; + +/* Contents of last address examined. + This is not valid past the end of the `x' command! */ + +static value_ptr last_examine_value; + +/* Largest offset between a symbolic value and an address, that will be + printed as `0x1234 '. */ + +static unsigned int max_symbolic_offset = UINT_MAX; + +/* Append the source filename and linenumber of the symbol when + printing a symbolic value as `' if set. */ +static int print_symbol_filename = 0; + +/* Number of auto-display expression currently being displayed. + So that we can disable it if we get an error or a signal within it. + -1 when not doing one. */ + +int current_display_number; + +/* Flag to low-level print routines that this value is being printed + in an epoch window. We'd like to pass this as a parameter, but + every routine would need to take it. Perhaps we can encapsulate + this in the I/O stream once we have GNU stdio. */ + +int inspect_it = 0; + +struct display +{ + /* Chain link to next auto-display item. */ + struct display *next; + /* Expression to be evaluated and displayed. */ + struct expression *exp; + /* Item number of this auto-display item. */ + int number; + /* Display format specified. */ + struct format_data format; + /* Innermost block required by this expression when evaluated */ + struct block *block; + /* Status of this display (enabled or disabled) */ + enum enable status; +}; + +/* Chain of expressions whose values should be displayed + automatically each time the program stops. */ + +static struct display *display_chain; + +static int display_number; + +/* Pointer to the target-dependent disassembly function. */ + +int (*tm_print_insn) PARAMS ((bfd_vma, disassemble_info *)); + +/* Prototypes for local functions. */ + +static void delete_display PARAMS ((int)); + +static void enable_display PARAMS ((char *, int)); + +static void disable_display_command PARAMS ((char *, int)); + +static void disassemble_command PARAMS ((char *, int)); + +static void printf_command PARAMS ((char *, int)); + +static void print_frame_nameless_args PARAMS ((struct frame_info *, long, + int, int, GDB_FILE *)); + +static void display_info PARAMS ((char *, int)); + +static void do_one_display PARAMS ((struct display *)); + +static void undisplay_command PARAMS ((char *, int)); + +static void free_display PARAMS ((struct display *)); + +static void display_command PARAMS ((char *, int)); + +static void x_command PARAMS ((char *, int)); + +static void address_info PARAMS ((char *, int)); + +static void set_command PARAMS ((char *, int)); + +static void output_command PARAMS ((char *, int)); + +static void call_command PARAMS ((char *, int)); + +static void inspect_command PARAMS ((char *, int)); + +static void print_command PARAMS ((char *, int)); + +static void print_command_1 PARAMS ((char *, int, int)); + +static void validate_format PARAMS ((struct format_data, char *)); + +static void do_examine PARAMS ((struct format_data, CORE_ADDR)); + +static void print_formatted PARAMS ((value_ptr, int, int)); + +static struct format_data decode_format PARAMS ((char **, int, int)); + +static int print_insn PARAMS ((CORE_ADDR, GDB_FILE *)); + + +/* Decode a format specification. *STRING_PTR should point to it. + OFORMAT and OSIZE are used as defaults for the format and size + if none are given in the format specification. + If OSIZE is zero, then the size field of the returned value + should be set only if a size is explicitly specified by the + user. + The structure returned describes all the data + found in the specification. In addition, *STRING_PTR is advanced + past the specification and past all whitespace following it. */ + +static struct format_data +decode_format (string_ptr, oformat, osize) + char **string_ptr; + int oformat; + int osize; +{ + struct format_data val; + register char *p = *string_ptr; + + val.format = '?'; + val.size = '?'; + val.count = 1; + + if (*p >= '0' && *p <= '9') + val.count = atoi (p); + while (*p >= '0' && *p <= '9') p++; + + /* Now process size or format letters that follow. */ + + while (1) + { + if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') + val.size = *p++; + else if (*p >= 'a' && *p <= 'z') + val.format = *p++; + else + break; + } + + while (*p == ' ' || *p == '\t') p++; + *string_ptr = p; + + /* Set defaults for format and size if not specified. */ + if (val.format == '?') + { + if (val.size == '?') + { + /* Neither has been specified. */ + val.format = oformat; + val.size = osize; + } + else + /* If a size is specified, any format makes a reasonable + default except 'i'. */ + val.format = oformat == 'i' ? 'x' : oformat; + } + else if (val.size == '?') + switch (val.format) + { + case 'a': + case 's': + /* Pick the appropriate size for an address. */ + if (TARGET_PTR_BIT == 64) + val.size = osize ? 'g' : osize; + else if (TARGET_PTR_BIT == 32) + val.size = osize ? 'w' : osize; + else if (TARGET_PTR_BIT == 16) + val.size = osize ? 'h' : osize; + else + /* Bad value for TARGET_PTR_BIT */ + abort (); + break; + case 'f': + /* Floating point has to be word or giantword. */ + if (osize == 'w' || osize == 'g') + val.size = osize; + else + /* Default it to giantword if the last used size is not + appropriate. */ + val.size = osize ? 'g' : osize; + break; + case 'c': + /* Characters default to one byte. */ + val.size = osize ? 'b' : osize; + break; + default: + /* The default is the size most recently specified. */ + val.size = osize; + } + + return val; +} + +/* Print value VAL on gdb_stdout according to FORMAT, a letter or 0. + Do not end with a newline. + 0 means print VAL according to its own type. + SIZE is the letter for the size of datum being printed. + This is used to pad hex numbers so they line up. */ + +static void +print_formatted (val, format, size) + register value_ptr val; + register int format; + int size; +{ + struct type *type = check_typedef (VALUE_TYPE (val)); + int len = TYPE_LENGTH (type); + + if (VALUE_LVAL (val) == lval_memory) + next_address = VALUE_ADDRESS (val) + len; + + switch (format) + { + case 's': + next_address = VALUE_ADDRESS (val) + + val_print_string (VALUE_ADDRESS (val), 0, gdb_stdout); + break; + + case 'i': + /* The old comment says + "Force output out, print_insn not using _filtered". + I'm not completely sure what that means, I suspect most print_insn + now do use _filtered, so I guess it's obsolete. */ + /* We often wrap here if there are long symbolic names. */ + wrap_here (" "); + next_address = VALUE_ADDRESS (val) + + print_insn (VALUE_ADDRESS (val), gdb_stdout); + break; + + default: + if (format == 0 + || TYPE_CODE (type) == TYPE_CODE_ARRAY + || TYPE_CODE (type) == TYPE_CODE_STRING + || TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION) + value_print (val, gdb_stdout, format, Val_pretty_default); + else + print_scalar_formatted (VALUE_CONTENTS (val), type, + format, size, gdb_stdout); + } +} + +/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR, + according to letters FORMAT and SIZE on STREAM. + FORMAT may not be zero. Formats s and i are not supported at this level. + + This is how the elements of an array or structure are printed + with a format. */ + +void +print_scalar_formatted (valaddr, type, format, size, stream) + char *valaddr; + struct type *type; + int format; + int size; + GDB_FILE *stream; +{ + LONGEST val_long; + unsigned int len = TYPE_LENGTH (type); + + if (len > sizeof (LONGEST) + && (format == 't' + || format == 'c' + || format == 'o' + || format == 'u' + || format == 'd' + || format == 'x')) + { + if (! TYPE_UNSIGNED (type) + || ! extract_long_unsigned_integer (valaddr, len, &val_long)) + { + /* We can't print it normally, but we can print it in hex. + Printing it in the wrong radix is more useful than saying + "use /x, you dummy". */ + /* FIXME: we could also do octal or binary if that was the + desired format. */ + /* FIXME: we should be using the size field to give us a + minimum field width to print. */ + val_print_type_code_int (type, valaddr, stream); + return; + } + + /* If we get here, extract_long_unsigned_integer set val_long. */ + } + else if (format != 'f') + val_long = unpack_long (type, valaddr); + + /* If we are printing it as unsigned, truncate it in case it is actually + a negative signed value (e.g. "print/u (short)-1" should print 65535 + (if shorts are 16 bits) instead of 4294967295). */ + if (format != 'd') + { + if (len < sizeof (LONGEST)) + val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1; + } + + switch (format) + { + case 'x': + if (!size) + { + /* no size specified, like in print. Print varying # of digits. */ + print_longest (stream, 'x', 1, val_long); + } + else + switch (size) + { + case 'b': + case 'h': + case 'w': + case 'g': + print_longest (stream, size, 1, val_long); + break; + default: + error ("Undefined output size \"%c\".", size); + } + break; + + case 'd': + print_longest (stream, 'd', 1, val_long); + break; + + case 'u': + print_longest (stream, 'u', 0, val_long); + break; + + case 'o': + if (val_long) + print_longest (stream, 'o', 1, val_long); + else + fprintf_filtered (stream, "0"); + break; + + case 'a': + print_address (unpack_pointer (type, valaddr), stream); + break; + + case 'c': + value_print (value_from_longest (builtin_type_char, val_long), stream, 0, + Val_pretty_default); + break; + + case 'f': + if (len == sizeof (float)) + type = builtin_type_float; + else if (len == sizeof (double)) + type = builtin_type_double; + print_floating (valaddr, type, stream); + break; + + case 0: + abort (); + + case 't': + /* Binary; 't' stands for "two". */ + { + char bits[8*(sizeof val_long) + 1]; + char *cp = bits; + int width; + + if (!size) + width = 8*(sizeof val_long); + else + switch (size) + { + case 'b': + width = 8; + break; + case 'h': + width = 16; + break; + case 'w': + width = 32; + break; + case 'g': + width = 64; + break; + default: + error ("Undefined output size \"%c\".", size); + } + + bits[width] = '\0'; + while (width-- > 0) + { + bits[width] = (val_long & 1) ? '1' : '0'; + val_long >>= 1; + } + if (!size) + { + while (*cp && *cp == '0') + cp++; + if (*cp == '\0') + cp--; + } + fprintf_filtered (stream, local_binary_format_prefix()); + fprintf_filtered (stream, cp); + fprintf_filtered (stream, local_binary_format_suffix()); + } + break; + + default: + error ("Undefined output format \"%c\".", format); + } +} + +/* Specify default address for `x' command. + `info lines' uses this. */ + +void +set_next_address (addr) + CORE_ADDR addr; +{ + next_address = addr; + + /* Make address available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_longest (lookup_pointer_type (builtin_type_void), + (LONGEST) addr)); +} + +/* Optionally print address ADDR symbolically as on STREAM, + after LEADIN. Print nothing if no symbolic name is found nearby. + Optionally also print source file and line number, if available. + 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. */ + +void +print_address_symbolic (addr, stream, do_demangle, leadin) + CORE_ADDR addr; + GDB_FILE *stream; + int do_demangle; + char *leadin; +{ + struct minimal_symbol *msymbol; + struct symbol *symbol; + struct symtab *symtab = 0; + CORE_ADDR name_location = 0; + char *name = ""; + + /* First try to find the address in the symbol table, then + in the minsyms. Take the closest one. */ + + /* This is defective in the sense that it only finds text symbols. So + really this is kind of pointless--we should make sure that the + minimal symbols have everything we need (by changing that we could + save some memory, but for many debug format--ELF/DWARF or + anything/stabs--it would be inconvenient to eliminate those minimal + symbols anyway). */ + symbol = find_pc_function (addr); + if (symbol) + name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)); + + if (symbol) + { + if (do_demangle) + name = SYMBOL_SOURCE_NAME (symbol); + else + name = SYMBOL_LINKAGE_NAME (symbol); + } + + msymbol = lookup_minimal_symbol_by_pc (addr); + if (msymbol != NULL) + { + if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL) + { + /* The msymbol is closer to the address than the symbol; + use the msymbol instead. */ + symbol = 0; + symtab = 0; + name_location = SYMBOL_VALUE_ADDRESS (msymbol); + if (do_demangle) + name = SYMBOL_SOURCE_NAME (msymbol); + else + name = SYMBOL_LINKAGE_NAME (msymbol); + } + } + if (symbol == NULL && msymbol == NULL) + return; + + /* If the nearest symbol is too far away, don't print anything symbolic. */ + + /* For when CORE_ADDR is larger than unsigned int, we do math in + CORE_ADDR. But when we detect unsigned wraparound in the + CORE_ADDR math, we ignore this test and print the offset, + because addr+max_symbolic_offset has wrapped through the end + of the address space back to the beginning, giving bogus comparison. */ + if (addr > name_location + max_symbolic_offset + && name_location + max_symbolic_offset > name_location) + return; + + fputs_filtered (leadin, stream); + fputs_filtered ("<", stream); + fputs_filtered (name, stream); + if (addr != name_location) + fprintf_filtered (stream, "+%u", (unsigned int)(addr - name_location)); + + /* Append source filename and line number if desired. Give specific + line # of this addr, if we have it; else line # of the nearest symbol. */ + if (print_symbol_filename) + { + struct symtab_and_line sal; + + sal = find_pc_line (addr, 0); + if (sal.symtab) + fprintf_filtered (stream, " at %s:%d", sal.symtab->filename, sal.line); + else if (symtab && symbol && symbol->line) + fprintf_filtered (stream, " at %s:%d", symtab->filename, symbol->line); + else if (symtab) + fprintf_filtered (stream, " in %s", symtab->filename); + } + fputs_filtered (">", stream); +} + +/* Print address ADDR on STREAM. USE_LOCAL means the same thing as for + print_longest. */ +void +print_address_numeric (addr, use_local, stream) + CORE_ADDR addr; + int use_local; + GDB_FILE *stream; +{ + /* This assumes a CORE_ADDR can fit in a LONGEST. Probably a safe + assumption. */ + print_longest (stream, 'x', use_local, (unsigned LONGEST) addr); +} + +/* Print address ADDR symbolically on STREAM. + First print it as a number. Then perhaps print + after the number. */ + +void +print_address (addr, stream) + CORE_ADDR addr; + GDB_FILE *stream; +{ + print_address_numeric (addr, 1, stream); + print_address_symbolic (addr, stream, asm_demangle, " "); +} + +/* 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. */ + +void +print_address_demangle (addr, stream, do_demangle) + CORE_ADDR addr; + GDB_FILE *stream; + int do_demangle; +{ + if (addr == 0) + { + fprintf_filtered (stream, "0"); + } + else if (addressprint) + { + print_address_numeric (addr, 1, stream); + print_address_symbolic (addr, stream, do_demangle, " "); + } + else + { + print_address_symbolic (addr, stream, do_demangle, ""); + } +} + + +/* These are the types that $__ will get after an examine command of one + of these sizes. */ + +static struct type *examine_b_type; +static struct type *examine_h_type; +static struct type *examine_w_type; +static struct type *examine_g_type; + +/* Examine data at address ADDR in format FMT. + Fetch it from memory and print on gdb_stdout. */ + +static void +do_examine (fmt, addr) + struct format_data fmt; + CORE_ADDR addr; +{ + register char format = 0; + register char size; + register int count = 1; + struct type *val_type = NULL; + register int i; + register int maxelts; + + format = fmt.format; + size = fmt.size; + count = fmt.count; + next_address = addr; + + /* String or instruction format implies fetch single bytes + regardless of the specified size. */ + if (format == 's' || format == 'i') + size = 'b'; + + if (size == 'b') + val_type = examine_b_type; + else if (size == 'h') + val_type = examine_h_type; + else if (size == 'w') + val_type = examine_w_type; + else if (size == 'g') + val_type = examine_g_type; + + maxelts = 8; + if (size == 'w') + maxelts = 4; + if (size == 'g') + maxelts = 2; + if (format == 's' || format == 'i') + maxelts = 1; + + /* Print as many objects as specified in COUNT, at most maxelts per line, + with the address of the next one at the start of each line. */ + + while (count > 0) + { + QUIT; + print_address (next_address, gdb_stdout); + printf_filtered (":"); + for (i = maxelts; + i > 0 && count > 0; + i--, count--) + { + printf_filtered ("\t"); + /* Note that print_formatted sets next_address for the next + object. */ + last_examine_address = next_address; + last_examine_value = value_at (val_type, next_address); + print_formatted (last_examine_value, format, size); + } + printf_filtered ("\n"); + gdb_flush (gdb_stdout); + } +} + +static void +validate_format (fmt, cmdname) + struct format_data fmt; + char *cmdname; +{ + if (fmt.size != 0) + error ("Size letters are meaningless in \"%s\" command.", cmdname); + if (fmt.count != 1) + error ("Item count other than 1 is meaningless in \"%s\" command.", + cmdname); + if (fmt.format == 'i' || fmt.format == 's') + error ("Format letter \"%c\" is meaningless in \"%s\" command.", + fmt.format, cmdname); +} + +/* Evaluate string EXP as an expression in the current language and + print the resulting value. EXP may contain a format specifier as the + first argument ("/x myvar" for example, to print myvar in hex). + */ + +static void +print_command_1 (exp, inspect, voidprint) + char *exp; + int inspect; + int voidprint; +{ + struct expression *expr; + register struct cleanup *old_chain = 0; + register char format = 0; + register value_ptr val; + struct format_data fmt; + int cleanup = 0; + + /* Pass inspect flag to the rest of the print routines in a global (sigh). */ + inspect_it = inspect; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, 0); + validate_format (fmt, "print"); + last_format = format = fmt.format; + } + else + { + fmt.count = 1; + fmt.format = 0; + fmt.size = 0; + } + + if (exp && *exp) + { + extern int objectprint; + struct type *type; + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + cleanup = 1; + val = evaluate_expression (expr); + + /* C++: figure out what type we actually want to print it as. */ + type = VALUE_TYPE (val); + + if (objectprint + && ( TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF) + && ( TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT + || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_UNION)) + { + value_ptr v; + + v = value_from_vtable_info (val, TYPE_TARGET_TYPE (type)); + if (v != 0) + { + val = v; + type = VALUE_TYPE (val); + } + } + } + else + val = access_value_history (0); + + if (voidprint || (val && VALUE_TYPE (val) && + TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID)) + { + int histindex = record_latest_value (val); + + if (histindex >= 0) + annotate_value_history_begin (histindex, VALUE_TYPE (val)); + else + annotate_value_begin (VALUE_TYPE (val)); + + if (inspect) + printf_unfiltered ("\031(gdb-makebuffer \"%s\" %d '(\"", exp, histindex); + else + if (histindex >= 0) printf_filtered ("$%d = ", histindex); + + if (histindex >= 0) + annotate_value_history_value (); + + print_formatted (val, format, fmt.size); + printf_filtered ("\n"); + + if (histindex >= 0) + annotate_value_history_end (); + else + annotate_value_end (); + + if (inspect) + printf_unfiltered("\") )\030"); + } + + if (cleanup) + do_cleanups (old_chain); + inspect_it = 0; /* Reset print routines to normal */ +} + +/* ARGSUSED */ +static void +print_command (exp, from_tty) + char *exp; + int from_tty; +{ + print_command_1 (exp, 0, 1); +} + +/* Same as print, except in epoch, it gets its own window */ +/* ARGSUSED */ +static void +inspect_command (exp, from_tty) + char *exp; + int from_tty; +{ + extern int epoch_interface; + + print_command_1 (exp, epoch_interface, 1); +} + +/* Same as print, except it doesn't print void results. */ +/* ARGSUSED */ +static void +call_command (exp, from_tty) + char *exp; + int from_tty; +{ + print_command_1 (exp, 0, 0); +} + +/* ARGSUSED */ +static void +output_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr; + register struct cleanup *old_chain; + register char format = 0; + register value_ptr val; + struct format_data fmt; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + validate_format (fmt, "output"); + format = fmt.format; + } + + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + + annotate_value_begin (VALUE_TYPE (val)); + + print_formatted (val, format, fmt.size); + + annotate_value_end (); + + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +set_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr = parse_expression (exp); + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + evaluate_expression (expr); + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +address_info (exp, from_tty) + char *exp; + int from_tty; +{ + register struct symbol *sym; + register struct minimal_symbol *msymbol; + register long val; + register long basereg; + int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero + if exp is a field of `this'. */ + + if (exp == 0) + error ("Argument required."); + + sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE, + &is_a_field_of_this, (struct symtab **)NULL); + if (sym == NULL) + { + if (is_a_field_of_this) + { + printf_filtered ("Symbol \""); + fprintf_symbol_filtered (gdb_stdout, exp, + current_language->la_language, DMGL_ANSI); + printf_filtered ("\" is a field of the local class variable `this'\n"); + return; + } + + msymbol = lookup_minimal_symbol (exp, NULL, NULL); + + if (msymbol != NULL) + { + printf_filtered ("Symbol \""); + fprintf_symbol_filtered (gdb_stdout, exp, + current_language->la_language, DMGL_ANSI); + printf_filtered ("\" is at "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (msymbol), 1, + gdb_stdout); + printf_filtered (" in a file compiled without debugging.\n"); + } + else + error ("No symbol \"%s\" in current context.", exp); + return; + } + + printf_filtered ("Symbol \""); + fprintf_symbol_filtered (gdb_stdout, SYMBOL_NAME (sym), + current_language->la_language, DMGL_ANSI); + printf_filtered ("\" is "); + val = SYMBOL_VALUE (sym); + basereg = SYMBOL_BASEREG (sym); + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_CONST_BYTES: + printf_filtered ("constant"); + break; + + case LOC_LABEL: + printf_filtered ("a label at address "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout); + break; + + case LOC_REGISTER: + printf_filtered ("a variable in register %s", reg_names[val]); + break; + + case LOC_STATIC: + printf_filtered ("static storage at address "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout); + break; + + case LOC_REGPARM: + printf_filtered ("an argument in register %s", reg_names[val]); + break; + + case LOC_REGPARM_ADDR: + printf_filtered ("address of an argument in register %s", reg_names[val]); + break; + + case LOC_ARG: + printf_filtered ("an argument at offset %ld", val); + break; + + case LOC_LOCAL_ARG: + printf_filtered ("an argument at frame offset %ld", val); + break; + + case LOC_LOCAL: + printf_filtered ("a local variable at frame offset %ld", val); + break; + + case LOC_REF_ARG: + printf_filtered ("a reference argument at offset %ld", val); + break; + + case LOC_BASEREG: + printf_filtered ("a variable at offset %ld from register %s", + val, reg_names[basereg]); + break; + + case LOC_BASEREG_ARG: + printf_filtered ("an argument at offset %ld from register %s", + val, reg_names[basereg]); + break; + + case LOC_TYPEDEF: + printf_filtered ("a typedef"); + break; + + case LOC_BLOCK: + printf_filtered ("a function at address "); + print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), 1, + gdb_stdout); + break; + + case LOC_UNRESOLVED: + { + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, NULL); + if (msym == NULL) + printf_filtered ("unresolved"); + else + { + printf_filtered ("static storage at address "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (msym), 1, gdb_stdout); + } + } + break; + + case LOC_OPTIMIZED_OUT: + printf_filtered ("optimized out"); + break; + + default: + printf_filtered ("of unknown (botched) type"); + break; + } + printf_filtered (".\n"); +} + +static void +x_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr; + struct format_data fmt; + struct cleanup *old_chain; + struct value *val; + + fmt.format = last_format; + fmt.size = last_size; + fmt.count = 1; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, last_size); + } + + /* If we have an expression, evaluate it and use it as the address. */ + + if (exp != 0 && *exp != 0) + { + expr = parse_expression (exp); + /* Cause expression not to be there any more + if this command is repeated with Newline. + But don't clobber a user-defined command's definition. */ + if (from_tty) + *exp = 0; + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_expression (expr); + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF) + val = value_ind (val); + /* In rvalue contexts, such as this, functions are coerced into + pointers to functions. This makes "x/i main" work. */ + if (/* last_format == 'i' + && */ TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC + && VALUE_LVAL (val) == lval_memory) + next_address = VALUE_ADDRESS (val); + else + next_address = value_as_pointer (val); + do_cleanups (old_chain); + } + + do_examine (fmt, next_address); + + /* If the examine succeeds, we remember its size and format for next time. */ + last_size = fmt.size; + last_format = fmt.format; + + /* Set a couple of internal variables if appropriate. */ + if (last_examine_value) + { + /* Make last address examined available to the user as $_. Use + the correct pointer type. */ + set_internalvar (lookup_internalvar ("_"), + value_from_longest ( + lookup_pointer_type (VALUE_TYPE (last_examine_value)), + (LONGEST) last_examine_address)); + + /* Make contents of last address examined available to the user as $__.*/ + set_internalvar (lookup_internalvar ("__"), last_examine_value); + } +} + + +/* Add an expression to the auto-display chain. + Specify the expression. */ + +static void +display_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct format_data fmt; + register struct expression *expr; + register struct display *new; + + if (exp == 0) + { + do_displays (); + return; + } + + if (*exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + if (fmt.size && fmt.format == 0) + fmt.format = 'x'; + if (fmt.format == 'i' || fmt.format == 's') + fmt.size = 'b'; + } + else + { + fmt.format = 0; + fmt.size = 0; + fmt.count = 0; + } + + innermost_block = 0; + expr = parse_expression (exp); + + new = (struct display *) xmalloc (sizeof (struct display)); + + new->exp = expr; + new->block = innermost_block; + new->next = display_chain; + new->number = ++display_number; + new->format = fmt; + new->status = enabled; + display_chain = new; + + if (from_tty && target_has_execution) + do_one_display (new); + + dont_repeat (); +} + +static void +free_display (d) + struct display *d; +{ + free ((PTR)d->exp); + free ((PTR)d); +} + +/* Clear out the display_chain. + Done when new symtabs are loaded, since this invalidates + the types stored in many expressions. */ + +void +clear_displays () +{ + register struct display *d; + + while ((d = display_chain) != NULL) + { + free ((PTR)d->exp); + display_chain = d->next; + free ((PTR)d); + } +} + +/* Delete the auto-display number NUM. */ + +static void +delete_display (num) + int num; +{ + register struct display *d1, *d; + + if (!display_chain) + error ("No display number %d.", num); + + if (display_chain->number == num) + { + d1 = display_chain; + display_chain = d1->next; + free_display (d1); + } + else + for (d = display_chain; ; d = d->next) + { + if (d->next == 0) + error ("No display number %d.", num); + if (d->next->number == num) + { + d1 = d->next; + d->next = d1->next; + free_display (d1); + break; + } + } +} + +/* Delete some values from the auto-display chain. + Specify the element numbers. */ + +static void +undisplay_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register int num; + + if (args == 0) + { + if (query ("Delete all auto-display expressions? ")) + clear_displays (); + dont_repeat (); + return; + } + + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + num = atoi (p); + + delete_display (num); + + p = p1; + while (*p == ' ' || *p == '\t') p++; + } + dont_repeat (); +} + +/* Display a single auto-display. + Do nothing if the display cannot be printed in the current context, + or if the display is disabled. */ + +static void +do_one_display (d) + struct display *d; +{ + int within_current_scope; + + if (d->status == disabled) + return; + + if (d->block) + within_current_scope = contained_in (get_selected_block (), d->block); + else + within_current_scope = 1; + if (!within_current_scope) + return; + + current_display_number = d->number; + + annotate_display_begin (); + printf_filtered ("%d", d->number); + annotate_display_number_end (); + printf_filtered (": "); + if (d->format.size) + { + CORE_ADDR addr; + + annotate_display_format (); + + printf_filtered ("x/"); + if (d->format.count != 1) + printf_filtered ("%d", d->format.count); + printf_filtered ("%c", d->format.format); + if (d->format.format != 'i' && d->format.format != 's') + printf_filtered ("%c", d->format.size); + printf_filtered (" "); + + annotate_display_expression (); + + print_expression (d->exp, gdb_stdout); + annotate_display_expression_end (); + + if (d->format.count != 1) + printf_filtered ("\n"); + else + printf_filtered (" "); + + addr = value_as_pointer (evaluate_expression (d->exp)); + if (d->format.format == 'i') + addr = ADDR_BITS_REMOVE (addr); + + annotate_display_value (); + + do_examine (d->format, addr); + } + else + { + annotate_display_format (); + + if (d->format.format) + printf_filtered ("/%c ", d->format.format); + + annotate_display_expression (); + + print_expression (d->exp, gdb_stdout); + annotate_display_expression_end (); + + printf_filtered (" = "); + + annotate_display_expression (); + + print_formatted (evaluate_expression (d->exp), + d->format.format, d->format.size); + printf_filtered ("\n"); + } + + annotate_display_end (); + + gdb_flush (gdb_stdout); + current_display_number = -1; +} + +/* Display all of the values on the auto-display chain which can be + evaluated in the current scope. */ + +void +do_displays () +{ + register struct display *d; + + for (d = display_chain; d; d = d->next) + do_one_display (d); +} + +/* Delete the auto-display which we were in the process of displaying. + This is done when there is an error or a signal. */ + +void +disable_display (num) + int num; +{ + register struct display *d; + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = disabled; + return; + } + printf_unfiltered ("No display number %d.\n", num); +} + +void +disable_current_display () +{ + if (current_display_number >= 0) + { + disable_display (current_display_number); + fprintf_unfiltered (gdb_stderr, "Disabling display %d to avoid infinite recursion.\n", + current_display_number); + } + current_display_number = -1; +} + +static void +display_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct display *d; + + if (!display_chain) + printf_unfiltered ("There are no auto-display expressions now.\n"); + else + printf_filtered ("Auto-display expressions now in effect:\n\ +Num Enb Expression\n"); + + for (d = display_chain; d; d = d->next) + { + printf_filtered ("%d: %c ", d->number, "ny"[(int)d->status]); + if (d->format.size) + printf_filtered ("/%d%c%c ", d->format.count, d->format.size, + d->format.format); + else if (d->format.format) + printf_filtered ("/%c ", d->format.format); + print_expression (d->exp, gdb_stdout); + if (d->block && !contained_in (get_selected_block (), d->block)) + printf_filtered (" (cannot be evaluated in the current context)"); + printf_filtered ("\n"); + gdb_flush (gdb_stdout); + } +} + +static void +enable_display (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register int num; + register struct display *d; + + if (p == 0) + { + for (d = display_chain; d; d = d->next) + d->status = enabled; + } + else + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') + p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + num = atoi (p); + + for (d = display_chain; d; d = d->next) + if (d->number == num) + { + d->status = enabled; + goto win; + } + printf_unfiltered ("No display number %d.\n", num); + win: + p = p1; + while (*p == ' ' || *p == '\t') + p++; + } +} + +/* ARGSUSED */ +static void +disable_display_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + register char *p1; + register struct display *d; + + if (p == 0) + { + for (d = display_chain; d; d = d->next) + d->status = disabled; + } + else + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') + p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + disable_display (atoi (p)); + + p = p1; + while (*p == ' ' || *p == '\t') + p++; + } +} + + +/* Print the value in stack frame FRAME of a variable + specified by a struct symbol. */ + +void +print_variable_value (var, frame, stream) + struct symbol *var; + struct frame_info *frame; + GDB_FILE *stream; +{ + value_ptr val = read_var_value (var, frame); + + value_print (val, stream, 0, Val_pretty_default); +} + +/* Print the arguments of a stack frame, given the function FUNC + running in that frame (as a symbol), the info on the frame, + and the number of args according to the stack frame (or -1 if unknown). */ + +/* References here and elsewhere to "number of args according to the + stack frame" appear in all cases to refer to "number of ints of args + according to the stack frame". At least for VAX, i386, isi. */ + +void +print_frame_args (func, fi, num, stream) + struct symbol *func; + struct frame_info *fi; + int num; + GDB_FILE *stream; +{ + struct block *b = NULL; + int nsyms = 0; + int first = 1; + register int i; + register struct symbol *sym; + register value_ptr val; + /* Offset of next stack argument beyond the one we have seen that is + at the highest offset. + -1 if we haven't come to a stack argument yet. */ + long highest_offset = -1; + int arg_size; + /* Number of ints of arguments that we have printed so far. */ + int args_printed = 0; + + if (func) + { + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + } + + for (i = 0; i < nsyms; i++) + { + QUIT; + sym = BLOCK_SYM (b, i); + + /* Keep track of the highest stack argument offset seen, and + skip over any kinds of symbols we don't care about. */ + + switch (SYMBOL_CLASS (sym)) { + case LOC_ARG: + case LOC_REF_ARG: + { + long current_offset = SYMBOL_VALUE (sym); + arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym)); + + /* Compute address of next argument by adding the size of + this argument and rounding to an int boundary. */ + current_offset + = ((current_offset + arg_size + sizeof (int) - 1) + & ~(sizeof (int) - 1)); + + /* If this is the highest offset seen yet, set highest_offset. */ + if (highest_offset == -1 + || (current_offset > highest_offset)) + highest_offset = current_offset; + + /* Add the number of ints we're about to print to args_printed. */ + args_printed += (arg_size + sizeof (int) - 1) / sizeof (int); + } + + /* We care about types of symbols, but don't need to keep track of + stack offsets in them. */ + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL_ARG: + case LOC_BASEREG_ARG: + break; + + /* Other types of symbols we just skip over. */ + default: + continue; + } + + /* We have to look up the symbol because arguments can have + two entries (one a parameter, one a local) and the one we + want is the local, which lookup_symbol will find for us. + This includes gcc1 (not gcc2) on the sparc when passing a + small structure and gcc2 when the argument type is float + and it is passed as a double and converted to float by + the prologue (in the latter case the type of the LOC_ARG + symbol is double and the type of the LOC_LOCAL symbol is + float). */ + /* But if the parameter name is null, don't try it. + Null parameter names occur on the RS/6000, for traceback tables. + FIXME, should we even print them? */ + + if (*SYMBOL_NAME (sym)) + { + struct symbol *nsym; + nsym = lookup_symbol + (SYMBOL_NAME (sym), + b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL); + if (SYMBOL_CLASS (nsym) == LOC_REGISTER) + { + /* There is a LOC_ARG/LOC_REGISTER pair. This means that + it was passed on the stack and loaded into a register, + or passed in a register and stored in a stack slot. + GDB 3.x used the LOC_ARG; GDB 4.0-4.11 used the LOC_REGISTER. + + Reasons for using the LOC_ARG: + (1) because find_saved_registers may be slow for remote + debugging, + (2) because registers are often re-used and stack slots + rarely (never?) are. Therefore using the stack slot is + much less likely to print garbage. + + Reasons why we might want to use the LOC_REGISTER: + (1) So that the backtrace prints the same value as + "print foo". I see no compelling reason why this needs + to be the case; having the backtrace print the value which + was passed in, and "print foo" print the value as modified + within the called function, makes perfect sense to me. + + Additional note: It might be nice if "info args" displayed + both values. + One more note: There is a case with sparc structure passing + where we need to use the LOC_REGISTER, but this is dealt with + by creating a single LOC_REGPARM in symbol reading. */ + + /* Leave sym (the LOC_ARG) alone. */ + ; + } + else + sym = nsym; + } + + /* Print the current arg. */ + if (! first) + fprintf_filtered (stream, ", "); + wrap_here (" "); + + annotate_arg_begin (); + + fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym), + SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI); + annotate_arg_name_end (); + fputs_filtered ("=", stream); + + /* Avoid value_print because it will deref ref parameters. We just + want to print their addresses. Print ??? for args whose address + we do not know. We pass 2 as "recurse" to val_print because our + standard indentation here is 4 spaces, and val_print indents + 2 for each recurse. */ + val = read_var_value (sym, fi); + + annotate_arg_value (val == NULL ? NULL : VALUE_TYPE (val)); + + if (val) + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val), + stream, 0, 0, 2, Val_no_prettyprint); + else + fputs_filtered ("???", stream); + + annotate_arg_end (); + + first = 0; + } + + /* Don't print nameless args in situations where we don't know + enough about the stack to find them. */ + if (num != -1) + { + long start; + + if (highest_offset == -1) + start = FRAME_ARGS_SKIP; + else + start = highest_offset; + + print_frame_nameless_args (fi, start, num - args_printed, + first, stream); + } +} + +/* Print nameless args on STREAM. + FI is the frameinfo for this frame, START is the offset + of the first nameless arg, and NUM is the number of nameless args to + print. FIRST is nonzero if this is the first argument (not just + the first nameless arg). */ + +static void +print_frame_nameless_args (fi, start, num, first, stream) + struct frame_info *fi; + long start; + int num; + int first; + GDB_FILE *stream; +{ + int i; + CORE_ADDR argsaddr; + long arg_value; + + for (i = 0; i < num; i++) + { + QUIT; +#ifdef NAMELESS_ARG_VALUE + NAMELESS_ARG_VALUE (fi, start, &arg_value); +#else + argsaddr = FRAME_ARGS_ADDRESS (fi); + if (!argsaddr) + return; + + arg_value = read_memory_integer (argsaddr + start, sizeof (int)); +#endif + + if (!first) + fprintf_filtered (stream, ", "); + +#ifdef PRINT_NAMELESS_INTEGER + PRINT_NAMELESS_INTEGER (stream, arg_value); +#else +#ifdef PRINT_TYPELESS_INTEGER + PRINT_TYPELESS_INTEGER (stream, builtin_type_int, (LONGEST) arg_value); +#else + fprintf_filtered (stream, "%ld", arg_value); +#endif /* PRINT_TYPELESS_INTEGER */ +#endif /* PRINT_NAMELESS_INTEGER */ + first = 0; + start += sizeof (int); + } +} + +/* ARGSUSED */ +static void +printf_command (arg, from_tty) + char *arg; + int from_tty; +{ + register char *f; + register char *s = arg; + char *string; + value_ptr *val_args; + char *substrings; + char *current_substring; + int nargs = 0; + int allocated_args = 20; + struct cleanup *old_cleanups; + + val_args = (value_ptr *) xmalloc (allocated_args * sizeof (value_ptr)); + old_cleanups = make_cleanup (free_current_contents, &val_args); + + if (s == 0) + error_no_arg ("format-control string and values to print"); + + /* Skip white space before format string */ + while (*s == ' ' || *s == '\t') s++; + + /* A format string should follow, enveloped in double quotes */ + if (*s++ != '"') + error ("Bad format string, missing '\"'."); + + /* 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 != '"') + { + int c = *s++; + switch (c) + { + case '\0': + error ("Bad format string, non-terminated '\"'."); + + case '\\': + switch (c = *s++) + { + case '\\': + *f++ = '\\'; + break; + case 'a': +#ifdef __STDC__ + *f++ = '\a'; +#else + *f++ = '\007'; /* Bell */ +#endif + 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; + } + } + + /* Skip over " and following space and comma. */ + s++; + *f++ = '\0'; + while (*s == ' ' || *s == '\t') s++; + + if (*s != ',' && *s != 0) + error ("Invalid argument syntax"); + + if (*s == ',') s++; + while (*s == ' ' || *s == '\t') s++; + + /* Need extra space for the '\0's. Doubling the size is sufficient. */ + substrings = alloca (strlen (string) * 2); + current_substring = substrings; + + { + /* 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. */ + + enum argclass {no_arg, int_arg, string_arg, double_arg, long_long_arg}; + enum argclass *argclass; + enum argclass this_argclass; + char *last_arg; + int nargs_wanted; + int lcount; + int i; + + argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass); + nargs_wanted = 0; + f = string; + last_arg = string; + while (*f) + if (*f++ == '%') + { + lcount = 0; + while (strchr ("0123456789.hlL-+ #", *f)) + { + if (*f == 'l' || *f == 'L') + lcount++; + f++; + } + switch (*f) + { + case 's': + this_argclass = string_arg; + break; + + case 'e': + case 'f': + case 'g': + this_argclass = double_arg; + break; + + case '*': + error ("`*' not supported for precision or width in printf"); + + case 'n': + error ("Format specifier `n' not supported in printf"); + + case '%': + this_argclass = no_arg; + break; + + default: + if (lcount > 1) + this_argclass = long_long_arg; + else + this_argclass = int_arg; + break; + } + f++; + if (this_argclass != no_arg) + { + strncpy (current_substring, last_arg, f - last_arg); + current_substring += f - last_arg; + *current_substring++ = '\0'; + last_arg = f; + argclass[nargs_wanted++] = this_argclass; + } + } + + /* Now, parse all arguments and evaluate them. + Store the VALUEs in VAL_ARGS. */ + + while (*s != '\0') + { + char *s1; + if (nargs == allocated_args) + val_args = (value_ptr *) xrealloc ((char *) val_args, + (allocated_args *= 2) + * sizeof (value_ptr)); + s1 = s; + val_args[nargs] = parse_to_comma_and_eval (&s1); + + /* If format string wants a float, unchecked-convert the value to + floating point of the same size */ + + if (argclass[nargs] == double_arg) + { + struct type *type = VALUE_TYPE (val_args[nargs]); + if (TYPE_LENGTH (type) == sizeof (float)) + VALUE_TYPE (val_args[nargs]) = builtin_type_float; + if (TYPE_LENGTH (type) == sizeof (double)) + VALUE_TYPE (val_args[nargs]) = builtin_type_double; + } + nargs++; + s = s1; + if (*s == ',') + s++; + } + + if (nargs != nargs_wanted) + error ("Wrong number of arguments for specified format-string"); + + /* Now actually print them. */ + current_substring = substrings; + for (i = 0; i < nargs; i++) + { + switch (argclass[i]) + { + case string_arg: + { + char *str; + CORE_ADDR tem; + int j; + tem = value_as_pointer (val_args[i]); + + /* This is a %s argument. Find the length of the string. */ + for (j = 0; ; j++) + { + char c; + QUIT; + read_memory (tem + j, &c, 1); + if (c == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + str = (char *) alloca (j + 1); + read_memory (tem, str, j); + str[j] = 0; + + printf_filtered (current_substring, str); + } + break; + case double_arg: + { + double val = value_as_double (val_args[i]); + printf_filtered (current_substring, val); + break; + } + case long_long_arg: +#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) + { + long long val = value_as_long (val_args[i]); + printf_filtered (current_substring, val); + break; + } +#else + error ("long long not supported in printf"); +#endif + case int_arg: + { + /* FIXME: there should be separate int_arg and long_arg. */ + long val = value_as_long (val_args[i]); + printf_filtered (current_substring, val); + break; + } + default: + error ("internal error in printf_command"); + } + /* Skip to the next substring. */ + current_substring += strlen (current_substring) + 1; + } + /* Print the portion of the format string after the last argument. */ + printf_filtered (last_arg); + } + do_cleanups (old_cleanups); +} + +/* Dump a specified section of assembly code. With no command line + arguments, this command will dump the assembly code for the + function surrounding the pc value in the selected frame. With one + argument, it will dump the assembly code surrounding that pc value. + Two arguments are interpeted as bounds within which to dump + assembly. */ + +/* ARGSUSED */ +static void +disassemble_command (arg, from_tty) + char *arg; + int from_tty; +{ + CORE_ADDR low, high; + char *name; + CORE_ADDR pc; + char *space_index; + + name = NULL; + if (!arg) + { + if (!selected_frame) + error ("No frame selected.\n"); + + pc = get_frame_pc (selected_frame); + if (find_pc_partial_function (pc, &name, &low, &high) == 0) + error ("No function contains program counter for selected frame.\n"); + } + else if (!(space_index = (char *) strchr (arg, ' '))) + { + /* One argument. */ + pc = parse_and_eval_address (arg); + if (find_pc_partial_function (pc, &name, &low, &high) == 0) + error ("No function contains specified address.\n"); + } + else + { + /* Two arguments. */ + *space_index = '\0'; + low = parse_and_eval_address (arg); + high = parse_and_eval_address (space_index + 1); + } + + printf_filtered ("Dump of assembler code "); + if (name != NULL) + { + printf_filtered ("for function %s:\n", name); + } + else + { + printf_filtered ("from "); + print_address_numeric (low, 1, gdb_stdout); + printf_filtered (" to "); + print_address_numeric (high, 1, gdb_stdout); + printf_filtered (":\n"); + } + + /* Dump the specified range. */ + for (pc = low; pc < high; ) + { + QUIT; + print_address (pc, gdb_stdout); + printf_filtered (":\t"); + /* We often wrap here if there are long symbolic names. */ + wrap_here (" "); + pc += print_insn (pc, gdb_stdout); + printf_filtered ("\n"); + } + printf_filtered ("End of assembler dump.\n"); + gdb_flush (gdb_stdout); +} + +/* Print the instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +static int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + GDB_FILE *stream; +{ + disassemble_info info; + + INIT_DISASSEMBLE_INFO (info, stream, (fprintf_ftype)fprintf_filtered); + info.read_memory_func = dis_asm_read_memory; + info.memory_error_func = dis_asm_memory_error; + info.print_address_func = dis_asm_print_address; + + /* If there's no disassembler, something is very wrong. */ + if (tm_print_insn == NULL) + abort (); + + return (*tm_print_insn) (memaddr, &info); +} + + +void +_initialize_printcmd () +{ + current_display_number = -1; + + add_info ("address", address_info, + "Describe where variable VAR is stored."); + + add_com ("x", class_vars, x_command, + concat ("Examine memory: x/FMT ADDRESS.\n\ +ADDRESS is an expression for the memory address to examine.\n\ +FMT is a repeat count followed by a format letter and a size letter.\n\ +Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\ + t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n", +"Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\ +The specified number of objects of the specified size are printed\n\ +according to the format.\n\n\ +Defaults for format and size letters are those previously used.\n\ +Default count is 1. Default address is following last thing printed\n\ +with this command or \"print\".", NULL)); + + add_com ("disassemble", class_vars, disassemble_command, + "Disassemble a specified section of memory.\n\ +Default is the function surrounding the pc of the selected frame.\n\ +With a single argument, the function surrounding that address is dumped.\n\ +Two arguments are taken as a range of memory to dump."); + +#if 0 + add_com ("whereis", class_vars, whereis_command, + "Print line number and file of definition of variable."); +#endif + + add_info ("display", display_info, + "Expressions to display when program stops, with code numbers."); + + add_cmd ("undisplay", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +\"delete display\" has the same effect as this command.\n\ +Do \"info display\" to see current list of code numbers.", + &cmdlist); + + add_com ("display", class_vars, display_command, + "Print value of expression EXP each time the program stops.\n\ +/FMT may be used before EXP as in the \"print\" command.\n\ +/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\ +as in the \"x\" command, and then EXP is used to get the address to examine\n\ +and examining is done as in the \"x\" command.\n\n\ +With no argument, display all currently requested auto-display expressions.\n\ +Use \"undisplay\" to cancel display requests previously made." +); + + add_cmd ("display", class_vars, enable_display, + "Enable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to resume displaying.\n\ +No argument means enable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &enablelist); + + add_cmd ("display", class_vars, disable_display_command, + "Disable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means disable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &disablelist); + + add_cmd ("display", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &deletelist); + + add_com ("printf", class_vars, printf_command, + "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\ +This is useful for formatted output in user-defined commands."); + + add_com ("output", class_vars, output_command, + "Like \"print\" but don't put in value history and don't print newline.\n\ +This is useful in user-defined commands."); + + add_prefix_cmd ("set", class_vars, set_command, +concat ("Evaluate expression EXP and assign result to variable VAR, using assignment\n\ +syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\ +example). VAR may be a debugger \"convenience\" variable (names starting\n\ +with $), a register (a few standard names starting with $), or an actual\n\ +variable in the program being debugged. EXP is any valid expression.\n", +"Use \"set variable\" for variables with names identical to set subcommands.\n\ +\nWith a subcommand, this command modifies parts of the gdb environment.\n\ +You can see these environment settings with the \"show\" command.", NULL), + &setlist, "set ", 1, &cmdlist); + + /* "call" is the same as "set", but handy for dbx users to call fns. */ + add_com ("call", class_vars, call_command, + "Call a function in the program.\n\ +The argument is the function name and arguments, in the notation of the\n\ +current working language. The result is printed and saved in the value\n\ +history, if it is not void."); + + add_cmd ("variable", class_vars, set_command, +"Evaluate expression EXP and assign result to variable VAR, using assignment\n\ +syntax appropriate for the current language (VAR = EXP or VAR := EXP for\n\ +example). VAR may be a debugger \"convenience\" variable (names starting\n\ +with $), a register (a few standard names starting with $), or an actual\n\ +variable in the program being debugged. EXP is any valid expression.\n\ +This may usually be abbreviated to simply \"set\".", + &setlist); + + add_com ("print", class_vars, print_command, + concat ("Print value of expression EXP.\n\ +Variables accessible are those of the lexical environment of the selected\n\ +stack frame, plus all those whose scope is global or an entire file.\n\ +\n\ +$NUM gets previous value number NUM. $ and $$ are the last two values.\n\ +$$NUM refers to NUM'th value back from the last one.\n\ +Names starting with $ refer to registers (with the values they would have\n", +"if the program were to return to the stack frame now selected, restoring\n\ +all registers saved by frames farther in) or else to debugger\n\ +\"convenience\" variables (any such name not a known register).\n\ +Use assignment expressions to give values to convenience variables.\n", + "\n\ +{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\ +@ is a binary operator for treating consecutive data objects\n\ +anywhere in memory as an array. FOO@NUM gives an array whose first\n\ +element is FOO, whose second element is stored in the space following\n\ +where FOO is stored, etc. FOO must be an expression whose value\n\ +resides in memory.\n", + "\n\ +EXP may be preceded with /FMT, where FMT is a format letter\n\ +but no count or size letter (see \"x\" command).", NULL)); + add_com_alias ("p", "print", class_vars, 1); + + 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."); + + add_show_from_set ( + add_set_cmd ("max-symbolic-offset", no_class, var_uinteger, + (char *)&max_symbolic_offset, + "Set the largest offset that will be printed in form.", + &setprintlist), + &showprintlist); + add_show_from_set ( + add_set_cmd ("symbol-filename", no_class, var_boolean, + (char *)&print_symbol_filename, + "Set printing of source filename and line number with .", + &setprintlist), + &showprintlist); + + examine_b_type = init_type (TYPE_CODE_INT, 1, 0, "examine_b_type", NULL); + examine_h_type = init_type (TYPE_CODE_INT, 2, 0, "examine_h_type", NULL); + examine_w_type = init_type (TYPE_CODE_INT, 4, 0, "examine_w_type", NULL); + examine_g_type = init_type (TYPE_CODE_INT, 8, 0, "examine_g_type", NULL); +} diff --git a/contrib/gdb/gdb/process_reply.defs b/contrib/gdb/gdb/process_reply.defs new file mode 100644 index 000000000000..824b5c65c2e1 --- /dev/null +++ b/contrib/gdb/gdb/process_reply.defs @@ -0,0 +1 @@ +#include diff --git a/contrib/gdb/gdb/procfs.c b/contrib/gdb/gdb/procfs.c new file mode 100644 index 000000000000..edc062bfd000 --- /dev/null +++ b/contrib/gdb/gdb/procfs.c @@ -0,0 +1,3815 @@ +/* Machine independent support for SVR4 /proc (process file system) for GDB. + Copyright 1991, 1992, 1993, 1994, 1995, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* N O T E S + +For information on the details of using /proc consult section proc(4) +in the UNIX System V Release 4 System Administrator's Reference Manual. + +The general register and floating point register sets are manipulated by +separate ioctl's. This file makes the assumption that if FP0_REGNUM is +defined, then support for the floating point register set is desired, +regardless of whether or not the actual target has floating point hardware. + + */ + + +#include "defs.h" + +#include +#include +#include +#include +#include +#include +#include +#include "gdb_string.h" +#include +#include +#include +#include "gdb_stat.h" + +#include "inferior.h" +#include "target.h" +#include "command.h" +#include "gdbcore.h" +#include "thread.h" + +#define MAX_SYSCALLS 256 /* Maximum number of syscalls for table */ + +#ifndef PROC_NAME_FMT +#define PROC_NAME_FMT "/proc/%05d" +#endif + +extern struct target_ops procfs_ops; /* Forward declaration */ + +#if 1 /* FIXME: Gross and ugly hack to resolve coredep.c global */ +CORE_ADDR kernel_u_addr; +#endif + +#ifdef BROKEN_SIGINFO_H /* Workaround broken SGS */ +#undef si_pid +#define si_pid _data._proc.pid +#undef si_uid +#define si_uid _data._proc._pdata._kill.uid +#endif /* BROKEN_SIGINFO_H */ + +/* All access to the inferior, either one started by gdb or one that has + been attached to, is controlled by an instance of a procinfo structure, + defined below. Since gdb currently only handles one inferior at a time, + the procinfo structure for the inferior is statically allocated and + only one exists at any given time. There is a separate procinfo + structure for use by the "info proc" command, so that we can print + useful information about any random process without interfering with + the inferior's procinfo information. */ + +struct procinfo { + struct procinfo *next; + int pid; /* Process ID of inferior */ + int fd; /* File descriptor for /proc entry */ + char *pathname; /* Pathname to /proc entry */ + int had_event; /* poll/select says something happened */ + int was_stopped; /* Nonzero if was stopped prior to attach */ + int nopass_next_sigstop; /* Don't pass a sigstop on next resume */ + prrun_t prrun; /* Control state when it is run */ + prstatus_t prstatus; /* Current process status info */ + gregset_t gregset; /* General register set */ + fpregset_t fpregset; /* Floating point register set */ + fltset_t fltset; /* Current traced hardware fault set */ + sigset_t trace; /* Current traced signal set */ + sysset_t exitset; /* Current traced system call exit set */ + sysset_t entryset; /* Current traced system call entry set */ + fltset_t saved_fltset; /* Saved traced hardware fault set */ + sigset_t saved_trace; /* Saved traced signal set */ + sigset_t saved_sighold; /* Saved held signal set */ + sysset_t saved_exitset; /* Saved traced system call exit set */ + sysset_t saved_entryset; /* Saved traced system call entry set */ +}; + +/* List of inferior process information */ +static struct procinfo *procinfo_list = NULL; + +static struct pollfd *poll_list; /* pollfds used for waiting on /proc */ + +static int num_poll_list = 0; /* Number of entries in poll_list */ + +static int last_resume_pid = -1; /* Last pid used with procfs_resume */ + +/* Much of the information used in the /proc interface, particularly for + printing status information, is kept as tables of structures of the + following form. These tables can be used to map numeric values to + their symbolic names and to a string that describes their specific use. */ + +struct trans { + int value; /* The numeric value */ + char *name; /* The equivalent symbolic value */ + char *desc; /* Short description of value */ +}; + +/* Translate bits in the pr_flags member of the prstatus structure, into the + names and desc information. */ + +static struct trans pr_flag_table[] = +{ +#if defined (PR_STOPPED) + { PR_STOPPED, "PR_STOPPED", "Process is stopped" }, +#endif +#if defined (PR_ISTOP) + { PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest" }, +#endif +#if defined (PR_DSTOP) + { PR_DSTOP, "PR_DSTOP", "A stop directive is in effect" }, +#endif +#if defined (PR_ASLEEP) + { PR_ASLEEP, "PR_ASLEEP", "Sleeping in an interruptible system call" }, +#endif +#if defined (PR_FORK) + { PR_FORK, "PR_FORK", "Inherit-on-fork is in effect" }, +#endif +#if defined (PR_RLC) + { PR_RLC, "PR_RLC", "Run-on-last-close is in effect" }, +#endif +#if defined (PR_PTRACE) + { PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace" }, +#endif +#if defined (PR_PCINVAL) + { PR_PCINVAL, "PR_PCINVAL", "PC refers to an invalid virtual address" }, +#endif +#if defined (PR_ISSYS) + { PR_ISSYS, "PR_ISSYS", "Is a system process" }, +#endif +#if defined (PR_STEP) + { PR_STEP, "PR_STEP", "Process has single step pending" }, +#endif +#if defined (PR_KLC) + { PR_KLC, "PR_KLC", "Kill-on-last-close is in effect" }, +#endif +#if defined (PR_ASYNC) + { PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect" }, +#endif +#if defined (PR_PCOMPAT) + { PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect" }, +#endif + { 0, NULL, NULL } +}; + +/* Translate values in the pr_why field of the prstatus struct. */ + +static struct trans pr_why_table[] = +{ +#if defined (PR_REQUESTED) + { PR_REQUESTED, "PR_REQUESTED", "Directed to stop via PIOCSTOP/PIOCWSTOP" }, +#endif +#if defined (PR_SIGNALLED) + { PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" }, +#endif +#if defined (PR_FAULTED) + { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" }, +#endif +#if defined (PR_SYSENTRY) + { PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" }, +#endif +#if defined (PR_SYSEXIT) + { PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call" }, +#endif +#if defined (PR_JOBCONTROL) + { PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action" }, +#endif +#if defined (PR_SUSPENDED) + { PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" }, +#endif + { 0, NULL, NULL } +}; + +/* Hardware fault translation table. */ + +static struct trans faults_table[] = +{ +#if defined (FLTILL) + { FLTILL, "FLTILL", "Illegal instruction" }, +#endif +#if defined (FLTPRIV) + { FLTPRIV, "FLTPRIV", "Privileged instruction" }, +#endif +#if defined (FLTBPT) + { FLTBPT, "FLTBPT", "Breakpoint trap" }, +#endif +#if defined (FLTTRACE) + { FLTTRACE, "FLTTRACE", "Trace trap" }, +#endif +#if defined (FLTACCESS) + { FLTACCESS, "FLTACCESS", "Memory access fault" }, +#endif +#if defined (FLTBOUNDS) + { FLTBOUNDS, "FLTBOUNDS", "Memory bounds violation" }, +#endif +#if defined (FLTIOVF) + { FLTIOVF, "FLTIOVF", "Integer overflow" }, +#endif +#if defined (FLTIZDIV) + { FLTIZDIV, "FLTIZDIV", "Integer zero divide" }, +#endif +#if defined (FLTFPE) + { FLTFPE, "FLTFPE", "Floating-point exception" }, +#endif +#if defined (FLTSTACK) + { FLTSTACK, "FLTSTACK", "Unrecoverable stack fault" }, +#endif +#if defined (FLTPAGE) + { FLTPAGE, "FLTPAGE", "Recoverable page fault" }, +#endif + { 0, NULL, NULL } +}; + +/* Translation table for signal generation information. See UNIX System + V Release 4 Programmer's Reference Manual, siginfo(5). */ + +static struct sigcode { + int signo; + int code; + char *codename; + char *desc; +} siginfo_table[] = { +#if defined (SIGILL) && defined (ILL_ILLOPC) + { SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode" }, +#endif +#if defined (SIGILL) && defined (ILL_ILLOPN) + { SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand", }, +#endif +#if defined (SIGILL) && defined (ILL_ILLADR) + { SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode" }, +#endif +#if defined (SIGILL) && defined (ILL_ILLTRP) + { SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap" }, +#endif +#if defined (SIGILL) && defined (ILL_PRVOPC) + { SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode" }, +#endif +#if defined (SIGILL) && defined (ILL_PRVREG) + { SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register" }, +#endif +#if defined (SIGILL) && defined (ILL_COPROC) + { SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error" }, +#endif +#if defined (SIGILL) && defined (ILL_BADSTK) + { SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error" }, +#endif +#if defined (SIGFPE) && defined (FPE_INTDIV) + { SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero" }, +#endif +#if defined (SIGFPE) && defined (FPE_INTOVF) + { SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTDIV) + { SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating point divide by zero" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTOVF) + { SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating point overflow" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTUND) + { SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating point underflow" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTRES) + { SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating point inexact result" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTINV) + { SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating point operation" }, +#endif +#if defined (SIGFPE) && defined (FPE_FLTSUB) + { SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range" }, +#endif +#if defined (SIGSEGV) && defined (SEGV_MAPERR) + { SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object" }, +#endif +#if defined (SIGSEGV) && defined (SEGV_ACCERR) + { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for object" }, +#endif +#if defined (SIGBUS) && defined (BUS_ADRALN) + { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment" }, +#endif +#if defined (SIGBUS) && defined (BUS_ADRERR) + { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Non-existent physical address" }, +#endif +#if defined (SIGBUS) && defined (BUS_OBJERR) + { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object specific hardware error" }, +#endif +#if defined (SIGTRAP) && defined (TRAP_BRKPT) + { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint" }, +#endif +#if defined (SIGTRAP) && defined (TRAP_TRACE) + { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap" }, +#endif +#if defined (SIGCLD) && defined (CLD_EXITED) + { SIGCLD, CLD_EXITED, "CLD_EXITED", "Child has exited" }, +#endif +#if defined (SIGCLD) && defined (CLD_KILLED) + { SIGCLD, CLD_KILLED, "CLD_KILLED", "Child was killed" }, +#endif +#if defined (SIGCLD) && defined (CLD_DUMPED) + { SIGCLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally" }, +#endif +#if defined (SIGCLD) && defined (CLD_TRAPPED) + { SIGCLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped" }, +#endif +#if defined (SIGCLD) && defined (CLD_STOPPED) + { SIGCLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped" }, +#endif +#if defined (SIGCLD) && defined (CLD_CONTINUED) + { SIGCLD, CLD_CONTINUED, "CLD_CONTINUED", "Stopped child had continued" }, +#endif +#if defined (SIGPOLL) && defined (POLL_IN) + { SIGPOLL, POLL_IN, "POLL_IN", "Input input available" }, +#endif +#if defined (SIGPOLL) && defined (POLL_OUT) + { SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available" }, +#endif +#if defined (SIGPOLL) && defined (POLL_MSG) + { SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available" }, +#endif +#if defined (SIGPOLL) && defined (POLL_ERR) + { SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error" }, +#endif +#if defined (SIGPOLL) && defined (POLL_PRI) + { SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available" }, +#endif +#if defined (SIGPOLL) && defined (POLL_HUP) + { SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected" }, +#endif + { 0, 0, NULL, NULL } +}; + +static char *syscall_table[MAX_SYSCALLS]; + +/* Prototypes for local functions */ + +static void set_proc_siginfo PARAMS ((struct procinfo *, int)); + +static void init_syscall_table PARAMS ((void)); + +static char *syscallname PARAMS ((int)); + +static char *signalname PARAMS ((int)); + +static char *errnoname PARAMS ((int)); + +static int proc_address_to_fd PARAMS ((struct procinfo *, CORE_ADDR, int)); + +static int open_proc_file PARAMS ((int, struct procinfo *, int)); + +static void close_proc_file PARAMS ((struct procinfo *)); + +static void unconditionally_kill_inferior PARAMS ((struct procinfo *)); + +static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *)) ATTR_NORETURN; + +static void info_proc PARAMS ((char *, int)); + +static void info_proc_flags PARAMS ((struct procinfo *, int)); + +static void info_proc_stop PARAMS ((struct procinfo *, int)); + +static void info_proc_siginfo PARAMS ((struct procinfo *, int)); + +static void info_proc_syscalls PARAMS ((struct procinfo *, int)); + +static void info_proc_mappings PARAMS ((struct procinfo *, int)); + +static void info_proc_signals PARAMS ((struct procinfo *, int)); + +static void info_proc_faults PARAMS ((struct procinfo *, int)); + +static char *mappingflags PARAMS ((long)); + +static char *lookupname PARAMS ((struct trans *, unsigned int, char *)); + +static char *lookupdesc PARAMS ((struct trans *, unsigned int)); + +static int do_attach PARAMS ((int pid)); + +static void do_detach PARAMS ((int siggnal)); + +static void procfs_create_inferior PARAMS ((char *, char *, char **)); + +static void procfs_notice_signals PARAMS ((int pid)); + +static struct procinfo *find_procinfo PARAMS ((pid_t pid, int okfail)); + +/* External function prototypes that can't be easily included in any + header file because the args are typedefs in system include files. */ + +extern void supply_gregset PARAMS ((gregset_t *)); + +extern void fill_gregset PARAMS ((gregset_t *, int)); + +extern void supply_fpregset PARAMS ((fpregset_t *)); + +extern void fill_fpregset PARAMS ((fpregset_t *, int)); + +/* + +LOCAL FUNCTION + + find_procinfo -- convert a process id to a struct procinfo + +SYNOPSIS + + static struct procinfo * find_procinfo (pid_t pid, int okfail); + +DESCRIPTION + + Given a process id, look it up in the procinfo chain. Returns + a struct procinfo *. If can't find pid, then call error(), + unless okfail is set, in which case, return NULL; + */ + +static struct procinfo * +find_procinfo (pid, okfail) + pid_t pid; + int okfail; +{ + struct procinfo *procinfo; + + for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + if (procinfo->pid == pid) + return procinfo; + + if (okfail) + return NULL; + + error ("procfs (find_procinfo): Couldn't locate pid %d", pid); +} + +/* + +LOCAL MACRO + + current_procinfo -- convert inferior_pid to a struct procinfo + +SYNOPSIS + + static struct procinfo * current_procinfo; + +DESCRIPTION + + Looks up inferior_pid in the procinfo chain. Always returns a + struct procinfo *. If process can't be found, we error() out. + */ + +#define current_procinfo find_procinfo (inferior_pid, 0) + +/* + +LOCAL FUNCTION + + add_fd -- Add the fd to the poll/select list + +SYNOPSIS + + static void add_fd (struct procinfo *); + +DESCRIPTION + + Add the fd of the supplied procinfo to the list of fds used for + poll/select operations. + */ + +static void +add_fd (pi) + struct procinfo *pi; +{ + if (num_poll_list <= 0) + poll_list = (struct pollfd *) xmalloc (sizeof (struct pollfd)); + else + poll_list = (struct pollfd *) xrealloc (poll_list, + (num_poll_list + 1) + * sizeof (struct pollfd)); + poll_list[num_poll_list].fd = pi->fd; + poll_list[num_poll_list].events = POLLPRI; + + num_poll_list++; +} + +static void +remove_fd (pi) + struct procinfo *pi; +{ + int i; + + for (i = 0; i < num_poll_list; i++) + { + if (poll_list[i].fd == pi->fd) + { + if (i != num_poll_list - 1) + memcpy (poll_list, poll_list + i + 1, + (num_poll_list - i - 1) * sizeof (struct pollfd)); + + num_poll_list--; + + if (num_poll_list == 0) + free (poll_list); + else + poll_list = (struct pollfd *) xrealloc (poll_list, + num_poll_list + * sizeof (struct pollfd)); + return; + } + } +} + +#define LOSING_POLL unixware_sux + +static struct procinfo * +wait_fd () +{ + struct procinfo *pi; + int num_fds; + int i; + + set_sigint_trap (); /* Causes SIGINT to be passed on to the + attached process. */ + set_sigio_trap (); + +#ifndef LOSING_POLL + num_fds = poll (poll_list, num_poll_list, -1); +#else + pi = current_procinfo; + + while (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) + { + if (errno == ENOENT) + { + /* Process exited. */ + pi->prstatus.pr_flags = 0; + break; + } + else if (errno != EINTR) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCWSTOP failed"); + } + } + pi->had_event = 1; +#endif + + clear_sigint_trap (); + clear_sigio_trap (); + +#ifndef LOSING_POLL + + if (num_fds <= 0) + { + print_sys_errmsg ("poll failed\n", errno); + error ("Poll failed, returned %d", num_fds); + } + + for (i = 0; i < num_poll_list && num_fds > 0; i++) + { + if ((poll_list[i].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL)) == 0) + continue; + for (pi = procinfo_list; pi; pi = pi->next) + { + if (poll_list[i].fd == pi->fd) + { + if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSTATUS failed"); + } + num_fds--; + pi->had_event = 1; + break; + } + } + if (!pi) + error ("procfs_wait: Couldn't find procinfo for fd %d\n", + poll_list[i].fd); + } +#endif /* LOSING_POLL */ + + return pi; +} + +/* + +LOCAL FUNCTION + + lookupdesc -- translate a value to a summary desc string + +SYNOPSIS + + static char *lookupdesc (struct trans *transp, unsigned int val); + +DESCRIPTION + + Given a pointer to a translation table and a value to be translated, + lookup the desc string and return it. + */ + +static char * +lookupdesc (transp, val) + struct trans *transp; + unsigned int val; +{ + char *desc; + + for (desc = NULL; transp -> name != NULL; transp++) + { + if (transp -> value == val) + { + desc = transp -> desc; + break; + } + } + + /* Didn't find a translation for the specified value, set a default one. */ + + if (desc == NULL) + { + desc = "Unknown"; + } + return (desc); +} + +/* + +LOCAL FUNCTION + + lookupname -- translate a value to symbolic name + +SYNOPSIS + + static char *lookupname (struct trans *transp, unsigned int val, + char *prefix); + +DESCRIPTION + + Given a pointer to a translation table, a value to be translated, + and a default prefix to return if the value can't be translated, + match the value with one of the translation table entries and + return a pointer to the symbolic name. + + If no match is found it just returns the value as a printable string, + with the given prefix. The previous such value, if any, is freed + at this time. + */ + +static char * +lookupname (transp, val, prefix) + struct trans *transp; + unsigned int val; + char *prefix; +{ + static char *locbuf; + char *name; + + for (name = NULL; transp -> name != NULL; transp++) + { + if (transp -> value == val) + { + name = transp -> name; + break; + } + } + + /* Didn't find a translation for the specified value, build a default + one using the specified prefix and return it. The lifetime of + the value is only until the next one is needed. */ + + if (name == NULL) + { + if (locbuf != NULL) + { + free (locbuf); + } + locbuf = xmalloc (strlen (prefix) + 16); + sprintf (locbuf, "%s %u", prefix, val); + name = locbuf; + } + return (name); +} + +static char * +sigcodename (sip) + siginfo_t *sip; +{ + struct sigcode *scp; + char *name = NULL; + static char locbuf[32]; + + for (scp = siginfo_table; scp -> codename != NULL; scp++) + { + if ((scp -> signo == sip -> si_signo) && + (scp -> code == sip -> si_code)) + { + name = scp -> codename; + break; + } + } + if (name == NULL) + { + sprintf (locbuf, "sigcode %u", sip -> si_signo); + name = locbuf; + } + return (name); +} + +static char * +sigcodedesc (sip) + siginfo_t *sip; +{ + struct sigcode *scp; + char *desc = NULL; + + for (scp = siginfo_table; scp -> codename != NULL; scp++) + { + if ((scp -> signo == sip -> si_signo) && + (scp -> code == sip -> si_code)) + { + desc = scp -> desc; + break; + } + } + if (desc == NULL) + { + desc = "Unrecognized signal or trap use"; + } + return (desc); +} + +/* + +LOCAL FUNCTION + + syscallname - translate a system call number into a system call name + +SYNOPSIS + + char *syscallname (int syscallnum) + +DESCRIPTION + + Given a system call number, translate it into the printable name + of a system call, or into "syscall " if it is an unknown + number. + */ + +static char * +syscallname (syscallnum) + int syscallnum; +{ + static char locbuf[32]; + char *rtnval; + + if (syscallnum >= 0 && syscallnum < MAX_SYSCALLS) + { + rtnval = syscall_table[syscallnum]; + } + else + { + sprintf (locbuf, "syscall %u", syscallnum); + rtnval = locbuf; + } + return (rtnval); +} + +/* + +LOCAL FUNCTION + + init_syscall_table - initialize syscall translation table + +SYNOPSIS + + void init_syscall_table (void) + +DESCRIPTION + + Dynamically initialize the translation table to convert system + call numbers into printable system call names. Done once per + gdb run, on initialization. + +NOTES + + This is awfully ugly, but preprocessor tricks to make it prettier + tend to be nonportable. + */ + +static void +init_syscall_table () +{ +#if defined (SYS_exit) + syscall_table[SYS_exit] = "exit"; +#endif +#if defined (SYS_fork) + syscall_table[SYS_fork] = "fork"; +#endif +#if defined (SYS_read) + syscall_table[SYS_read] = "read"; +#endif +#if defined (SYS_write) + syscall_table[SYS_write] = "write"; +#endif +#if defined (SYS_open) + syscall_table[SYS_open] = "open"; +#endif +#if defined (SYS_close) + syscall_table[SYS_close] = "close"; +#endif +#if defined (SYS_wait) + syscall_table[SYS_wait] = "wait"; +#endif +#if defined (SYS_creat) + syscall_table[SYS_creat] = "creat"; +#endif +#if defined (SYS_link) + syscall_table[SYS_link] = "link"; +#endif +#if defined (SYS_unlink) + syscall_table[SYS_unlink] = "unlink"; +#endif +#if defined (SYS_exec) + syscall_table[SYS_exec] = "exec"; +#endif +#if defined (SYS_execv) + syscall_table[SYS_execv] = "execv"; +#endif +#if defined (SYS_execve) + syscall_table[SYS_execve] = "execve"; +#endif +#if defined (SYS_chdir) + syscall_table[SYS_chdir] = "chdir"; +#endif +#if defined (SYS_time) + syscall_table[SYS_time] = "time"; +#endif +#if defined (SYS_mknod) + syscall_table[SYS_mknod] = "mknod"; +#endif +#if defined (SYS_chmod) + syscall_table[SYS_chmod] = "chmod"; +#endif +#if defined (SYS_chown) + syscall_table[SYS_chown] = "chown"; +#endif +#if defined (SYS_brk) + syscall_table[SYS_brk] = "brk"; +#endif +#if defined (SYS_stat) + syscall_table[SYS_stat] = "stat"; +#endif +#if defined (SYS_lseek) + syscall_table[SYS_lseek] = "lseek"; +#endif +#if defined (SYS_getpid) + syscall_table[SYS_getpid] = "getpid"; +#endif +#if defined (SYS_mount) + syscall_table[SYS_mount] = "mount"; +#endif +#if defined (SYS_umount) + syscall_table[SYS_umount] = "umount"; +#endif +#if defined (SYS_setuid) + syscall_table[SYS_setuid] = "setuid"; +#endif +#if defined (SYS_getuid) + syscall_table[SYS_getuid] = "getuid"; +#endif +#if defined (SYS_stime) + syscall_table[SYS_stime] = "stime"; +#endif +#if defined (SYS_ptrace) + syscall_table[SYS_ptrace] = "ptrace"; +#endif +#if defined (SYS_alarm) + syscall_table[SYS_alarm] = "alarm"; +#endif +#if defined (SYS_fstat) + syscall_table[SYS_fstat] = "fstat"; +#endif +#if defined (SYS_pause) + syscall_table[SYS_pause] = "pause"; +#endif +#if defined (SYS_utime) + syscall_table[SYS_utime] = "utime"; +#endif +#if defined (SYS_stty) + syscall_table[SYS_stty] = "stty"; +#endif +#if defined (SYS_gtty) + syscall_table[SYS_gtty] = "gtty"; +#endif +#if defined (SYS_access) + syscall_table[SYS_access] = "access"; +#endif +#if defined (SYS_nice) + syscall_table[SYS_nice] = "nice"; +#endif +#if defined (SYS_statfs) + syscall_table[SYS_statfs] = "statfs"; +#endif +#if defined (SYS_sync) + syscall_table[SYS_sync] = "sync"; +#endif +#if defined (SYS_kill) + syscall_table[SYS_kill] = "kill"; +#endif +#if defined (SYS_fstatfs) + syscall_table[SYS_fstatfs] = "fstatfs"; +#endif +#if defined (SYS_pgrpsys) + syscall_table[SYS_pgrpsys] = "pgrpsys"; +#endif +#if defined (SYS_xenix) + syscall_table[SYS_xenix] = "xenix"; +#endif +#if defined (SYS_dup) + syscall_table[SYS_dup] = "dup"; +#endif +#if defined (SYS_pipe) + syscall_table[SYS_pipe] = "pipe"; +#endif +#if defined (SYS_times) + syscall_table[SYS_times] = "times"; +#endif +#if defined (SYS_profil) + syscall_table[SYS_profil] = "profil"; +#endif +#if defined (SYS_plock) + syscall_table[SYS_plock] = "plock"; +#endif +#if defined (SYS_setgid) + syscall_table[SYS_setgid] = "setgid"; +#endif +#if defined (SYS_getgid) + syscall_table[SYS_getgid] = "getgid"; +#endif +#if defined (SYS_signal) + syscall_table[SYS_signal] = "signal"; +#endif +#if defined (SYS_msgsys) + syscall_table[SYS_msgsys] = "msgsys"; +#endif +#if defined (SYS_sys3b) + syscall_table[SYS_sys3b] = "sys3b"; +#endif +#if defined (SYS_acct) + syscall_table[SYS_acct] = "acct"; +#endif +#if defined (SYS_shmsys) + syscall_table[SYS_shmsys] = "shmsys"; +#endif +#if defined (SYS_semsys) + syscall_table[SYS_semsys] = "semsys"; +#endif +#if defined (SYS_ioctl) + syscall_table[SYS_ioctl] = "ioctl"; +#endif +#if defined (SYS_uadmin) + syscall_table[SYS_uadmin] = "uadmin"; +#endif +#if defined (SYS_utssys) + syscall_table[SYS_utssys] = "utssys"; +#endif +#if defined (SYS_fsync) + syscall_table[SYS_fsync] = "fsync"; +#endif +#if defined (SYS_umask) + syscall_table[SYS_umask] = "umask"; +#endif +#if defined (SYS_chroot) + syscall_table[SYS_chroot] = "chroot"; +#endif +#if defined (SYS_fcntl) + syscall_table[SYS_fcntl] = "fcntl"; +#endif +#if defined (SYS_ulimit) + syscall_table[SYS_ulimit] = "ulimit"; +#endif +#if defined (SYS_rfsys) + syscall_table[SYS_rfsys] = "rfsys"; +#endif +#if defined (SYS_rmdir) + syscall_table[SYS_rmdir] = "rmdir"; +#endif +#if defined (SYS_mkdir) + syscall_table[SYS_mkdir] = "mkdir"; +#endif +#if defined (SYS_getdents) + syscall_table[SYS_getdents] = "getdents"; +#endif +#if defined (SYS_sysfs) + syscall_table[SYS_sysfs] = "sysfs"; +#endif +#if defined (SYS_getmsg) + syscall_table[SYS_getmsg] = "getmsg"; +#endif +#if defined (SYS_putmsg) + syscall_table[SYS_putmsg] = "putmsg"; +#endif +#if defined (SYS_poll) + syscall_table[SYS_poll] = "poll"; +#endif +#if defined (SYS_lstat) + syscall_table[SYS_lstat] = "lstat"; +#endif +#if defined (SYS_symlink) + syscall_table[SYS_symlink] = "symlink"; +#endif +#if defined (SYS_readlink) + syscall_table[SYS_readlink] = "readlink"; +#endif +#if defined (SYS_setgroups) + syscall_table[SYS_setgroups] = "setgroups"; +#endif +#if defined (SYS_getgroups) + syscall_table[SYS_getgroups] = "getgroups"; +#endif +#if defined (SYS_fchmod) + syscall_table[SYS_fchmod] = "fchmod"; +#endif +#if defined (SYS_fchown) + syscall_table[SYS_fchown] = "fchown"; +#endif +#if defined (SYS_sigprocmask) + syscall_table[SYS_sigprocmask] = "sigprocmask"; +#endif +#if defined (SYS_sigsuspend) + syscall_table[SYS_sigsuspend] = "sigsuspend"; +#endif +#if defined (SYS_sigaltstack) + syscall_table[SYS_sigaltstack] = "sigaltstack"; +#endif +#if defined (SYS_sigaction) + syscall_table[SYS_sigaction] = "sigaction"; +#endif +#if defined (SYS_sigpending) + syscall_table[SYS_sigpending] = "sigpending"; +#endif +#if defined (SYS_context) + syscall_table[SYS_context] = "context"; +#endif +#if defined (SYS_evsys) + syscall_table[SYS_evsys] = "evsys"; +#endif +#if defined (SYS_evtrapret) + syscall_table[SYS_evtrapret] = "evtrapret"; +#endif +#if defined (SYS_statvfs) + syscall_table[SYS_statvfs] = "statvfs"; +#endif +#if defined (SYS_fstatvfs) + syscall_table[SYS_fstatvfs] = "fstatvfs"; +#endif +#if defined (SYS_nfssys) + syscall_table[SYS_nfssys] = "nfssys"; +#endif +#if defined (SYS_waitsys) + syscall_table[SYS_waitsys] = "waitsys"; +#endif +#if defined (SYS_sigsendsys) + syscall_table[SYS_sigsendsys] = "sigsendsys"; +#endif +#if defined (SYS_hrtsys) + syscall_table[SYS_hrtsys] = "hrtsys"; +#endif +#if defined (SYS_acancel) + syscall_table[SYS_acancel] = "acancel"; +#endif +#if defined (SYS_async) + syscall_table[SYS_async] = "async"; +#endif +#if defined (SYS_priocntlsys) + syscall_table[SYS_priocntlsys] = "priocntlsys"; +#endif +#if defined (SYS_pathconf) + syscall_table[SYS_pathconf] = "pathconf"; +#endif +#if defined (SYS_mincore) + syscall_table[SYS_mincore] = "mincore"; +#endif +#if defined (SYS_mmap) + syscall_table[SYS_mmap] = "mmap"; +#endif +#if defined (SYS_mprotect) + syscall_table[SYS_mprotect] = "mprotect"; +#endif +#if defined (SYS_munmap) + syscall_table[SYS_munmap] = "munmap"; +#endif +#if defined (SYS_fpathconf) + syscall_table[SYS_fpathconf] = "fpathconf"; +#endif +#if defined (SYS_vfork) + syscall_table[SYS_vfork] = "vfork"; +#endif +#if defined (SYS_fchdir) + syscall_table[SYS_fchdir] = "fchdir"; +#endif +#if defined (SYS_readv) + syscall_table[SYS_readv] = "readv"; +#endif +#if defined (SYS_writev) + syscall_table[SYS_writev] = "writev"; +#endif +#if defined (SYS_xstat) + syscall_table[SYS_xstat] = "xstat"; +#endif +#if defined (SYS_lxstat) + syscall_table[SYS_lxstat] = "lxstat"; +#endif +#if defined (SYS_fxstat) + syscall_table[SYS_fxstat] = "fxstat"; +#endif +#if defined (SYS_xmknod) + syscall_table[SYS_xmknod] = "xmknod"; +#endif +#if defined (SYS_clocal) + syscall_table[SYS_clocal] = "clocal"; +#endif +#if defined (SYS_setrlimit) + syscall_table[SYS_setrlimit] = "setrlimit"; +#endif +#if defined (SYS_getrlimit) + syscall_table[SYS_getrlimit] = "getrlimit"; +#endif +#if defined (SYS_lchown) + syscall_table[SYS_lchown] = "lchown"; +#endif +#if defined (SYS_memcntl) + syscall_table[SYS_memcntl] = "memcntl"; +#endif +#if defined (SYS_getpmsg) + syscall_table[SYS_getpmsg] = "getpmsg"; +#endif +#if defined (SYS_putpmsg) + syscall_table[SYS_putpmsg] = "putpmsg"; +#endif +#if defined (SYS_rename) + syscall_table[SYS_rename] = "rename"; +#endif +#if defined (SYS_uname) + syscall_table[SYS_uname] = "uname"; +#endif +#if defined (SYS_setegid) + syscall_table[SYS_setegid] = "setegid"; +#endif +#if defined (SYS_sysconfig) + syscall_table[SYS_sysconfig] = "sysconfig"; +#endif +#if defined (SYS_adjtime) + syscall_table[SYS_adjtime] = "adjtime"; +#endif +#if defined (SYS_systeminfo) + syscall_table[SYS_systeminfo] = "systeminfo"; +#endif +#if defined (SYS_seteuid) + syscall_table[SYS_seteuid] = "seteuid"; +#endif +#if defined (SYS_sproc) + syscall_table[SYS_sproc] = "sproc"; +#endif +} + +/* + +LOCAL FUNCTION + + procfs_kill_inferior - kill any currently inferior + +SYNOPSIS + + void procfs_kill_inferior (void) + +DESCRIPTION + + Kill any current inferior. + +NOTES + + Kills even attached inferiors. Presumably the user has already + been prompted that the inferior is an attached one rather than + one started by gdb. (FIXME?) + +*/ + +static void +procfs_kill_inferior () +{ + target_mourn_inferior (); +} + +/* + +LOCAL FUNCTION + + unconditionally_kill_inferior - terminate the inferior + +SYNOPSIS + + static void unconditionally_kill_inferior (struct procinfo *) + +DESCRIPTION + + Kill the specified inferior. + +NOTE + + A possibly useful enhancement would be to first try sending + the inferior a terminate signal, politely asking it to commit + suicide, before we murder it (we could call that + politely_kill_inferior()). + +*/ + +static void +unconditionally_kill_inferior (pi) + struct procinfo *pi; +{ + int signo; + int ppid; + + ppid = pi->prstatus.pr_ppid; + + signo = SIGKILL; + +#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL + /* Alpha OSF/1-3.x procfs needs a clear of the current signal + before the PIOCKILL, otherwise it might generate a corrupted core + file for the inferior. */ + ioctl (pi->fd, PIOCSSIG, NULL); +#endif +#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL + /* Alpha OSF/1-2.x procfs needs a PIOCSSIG call with a SIGKILL signal + to kill the inferior, otherwise it might remain stopped with a + pending SIGKILL. + We do not check the result of the PIOCSSIG, the inferior might have + died already. */ + { + struct siginfo newsiginfo; + + memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); + newsiginfo.si_signo = signo; + newsiginfo.si_code = 0; + newsiginfo.si_errno = 0; + newsiginfo.si_pid = getpid (); + newsiginfo.si_uid = getuid (); + ioctl (pi->fd, PIOCSSIG, &newsiginfo); + } +#else + ioctl (pi->fd, PIOCKILL, &signo); +#endif + + close_proc_file (pi); + +/* Only wait() for our direct children. Our grandchildren zombies are killed + by the death of their parents. */ + + if (ppid == getpid()) + wait ((int *) 0); +} + +/* + +LOCAL FUNCTION + + procfs_xfer_memory -- copy data to or from inferior memory space + +SYNOPSIS + + int procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, + int dowrite, struct target_ops target) + +DESCRIPTION + + Copy LEN bytes to/from inferior's memory starting at MEMADDR + from/to debugger memory starting at MYADDR. Copy from inferior + if DOWRITE is zero or to inferior if DOWRITE is nonzero. + + Returns the length copied, which is either the LEN argument or + zero. This xfer function does not do partial moves, since procfs_ops + doesn't allow memory operations to cross below us in the target stack + anyway. + +NOTES + + The /proc interface makes this an almost trivial task. + */ + +static int +procfs_xfer_memory (memaddr, myaddr, len, dowrite, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int dowrite; + struct target_ops *target; /* ignored */ +{ + int nbytes = 0; + struct procinfo *pi; + + pi = current_procinfo; + + if (lseek(pi->fd, (off_t) memaddr, 0) == (off_t) memaddr) + { + if (dowrite) + { + nbytes = write (pi->fd, myaddr, len); + } + else + { + nbytes = read (pi->fd, myaddr, len); + } + if (nbytes < 0) + { + nbytes = 0; + } + } + return (nbytes); +} + +/* + +LOCAL FUNCTION + + procfs_store_registers -- copy register values back to inferior + +SYNOPSIS + + void procfs_store_registers (int regno) + +DESCRIPTION + + Store our current register values back into the inferior. If + REGNO is -1 then store all the register, otherwise store just + the value specified by REGNO. + +NOTES + + If we are storing only a single register, we first have to get all + the current values from the process, overwrite the desired register + in the gregset with the one we want from gdb's registers, and then + send the whole set back to the process. For writing all the + registers, all we have to do is generate the gregset and send it to + the process. + + Also note that the process has to be stopped on an event of interest + for this to work, which basically means that it has to have been + run under the control of one of the other /proc ioctl calls and not + ptrace. Since we don't use ptrace anyway, we don't worry about this + fine point, but it is worth noting for future reference. + + Gdb is confused about what this function is supposed to return. + Some versions return a value, others return nothing. Some are + declared to return a value and actually return nothing. Gdb ignores + anything returned. (FIXME) + + */ + +static void +procfs_store_registers (regno) + int regno; +{ + struct procinfo *pi; + + pi = current_procinfo; + + if (regno != -1) + { + ioctl (pi->fd, PIOCGREG, &pi->gregset); + } + fill_gregset (&pi->gregset, regno); + ioctl (pi->fd, PIOCSREG, &pi->gregset); + +#if defined (FP0_REGNUM) + + /* Now repeat everything using the floating point register set, if the + target has floating point hardware. Since we ignore the returned value, + we'll never know whether it worked or not anyway. */ + + if (regno != -1) + { + ioctl (pi->fd, PIOCGFPREG, &pi->fpregset); + } + fill_fpregset (&pi->fpregset, regno); + ioctl (pi->fd, PIOCSFPREG, &pi->fpregset); + +#endif /* FP0_REGNUM */ + +} + +/* + +LOCAL FUNCTION + + create_procinfo - initialize access to a /proc entry + +SYNOPSIS + + struct procinfo * create_procinfo (int pid) + +DESCRIPTION + + Allocate a procinfo structure, open the /proc file and then set up the + set of signals and faults that are to be traced. Returns a pointer to + the new procinfo structure. + +NOTES + + If proc_init_failed ever gets called, control returns to the command + processing loop via the standard error handling code. + + */ + +static struct procinfo * +create_procinfo (pid) + int pid; +{ + struct procinfo *pi; + + pi = find_procinfo (pid, 1); + if (pi != NULL) + return pi; /* All done! It already exists */ + + pi = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + + if (!open_proc_file (pid, pi, O_RDWR)) + proc_init_failed (pi, "can't open process file"); + + /* Add new process to process info list */ + + pi->next = procinfo_list; + procinfo_list = pi; + + add_fd (pi); /* Add to list for poll/select */ + + memset ((char *) &pi->prrun, 0, sizeof (pi->prrun)); + prfillset (&pi->prrun.pr_trace); + procfs_notice_signals (pid); + prfillset (&pi->prrun.pr_fault); + prdelset (&pi->prrun.pr_fault, FLTPAGE); + +#ifdef PROCFS_DONT_TRACE_FAULTS + premptyset (&pi->prrun.pr_fault); +#endif + + if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) + proc_init_failed (pi, "PIOCWSTOP failed"); + + if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0) + proc_init_failed (pi, "PIOCSFAULT failed"); + + return pi; +} + +/* + +LOCAL FUNCTION + + procfs_init_inferior - initialize target vector and access to a + /proc entry + +SYNOPSIS + + void procfs_init_inferior (int pid) + +DESCRIPTION + + When gdb starts an inferior, this function is called in the parent + process immediately after the fork. It waits for the child to stop + on the return from the exec system call (the child itself takes care + of ensuring that this is set up), then sets up the set of signals + and faults that are to be traced. + +NOTES + + If proc_init_failed ever gets called, control returns to the command + processing loop via the standard error handling code. + + */ + +static void +procfs_init_inferior (pid) + int pid; +{ + push_target (&procfs_ops); + + create_procinfo (pid); + add_thread (pid); /* Setup initial thread */ + +#ifdef START_INFERIOR_TRAPS_EXPECTED + startup_inferior (START_INFERIOR_TRAPS_EXPECTED); +#else + /* One trap to exec the shell, one to exec the program being debugged. */ + startup_inferior (2); +#endif +} + +/* + +GLOBAL FUNCTION + + procfs_notice_signals + +SYNOPSIS + + static void procfs_notice_signals (int pid); + +DESCRIPTION + + When the user changes the state of gdb's signal handling via the + "handle" command, this function gets called to see if any change + in the /proc interface is required. It is also called internally + by other /proc interface functions to initialize the state of + the traced signal set. + + One thing it does is that signals for which the state is "nostop", + "noprint", and "pass", have their trace bits reset in the pr_trace + field, so that they are no longer traced. This allows them to be + delivered directly to the inferior without the debugger ever being + involved. + */ + +static void +procfs_notice_signals (pid) + int pid; +{ + int signo; + struct procinfo *pi; + + pi = find_procinfo (pid, 0); + + for (signo = 0; signo < NSIG; signo++) + { + if (signal_stop_state (target_signal_from_host (signo)) == 0 && + signal_print_state (target_signal_from_host (signo)) == 0 && + signal_pass_state (target_signal_from_host (signo)) == 1) + { + prdelset (&pi->prrun.pr_trace, signo); + } + else + { + praddset (&pi->prrun.pr_trace, signo); + } + } + if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace)) + { + print_sys_errmsg ("PIOCSTRACE failed", errno); + } +} + +/* + +LOCAL FUNCTION + + proc_set_exec_trap -- arrange for exec'd child to halt at startup + +SYNOPSIS + + void proc_set_exec_trap (void) + +DESCRIPTION + + This function is called in the child process when starting up + an inferior, prior to doing the exec of the actual inferior. + It sets the child process's exitset to make exit from the exec + system call an event of interest to stop on, and then simply + returns. The child does the exec, the system call returns, and + the child stops at the first instruction, ready for the gdb + parent process to take control of it. + +NOTE + + We need to use all local variables since the child may be sharing + it's data space with the parent, if vfork was used rather than + fork. + + Also note that we want to turn off the inherit-on-fork flag in + the child process so that any grand-children start with all + tracing flags cleared. + */ + +static void +proc_set_exec_trap () +{ + sysset_t exitset; + sysset_t entryset; + auto char procname[32]; + int fd; + + sprintf (procname, PROC_NAME_FMT, getpid ()); + if ((fd = open (procname, O_RDWR)) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } + premptyset (&exitset); + premptyset (&entryset); + +#ifdef PIOCSSPCACT + /* Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace + exits from exec system calls because of the user level loader. */ + { + int prfs_flags; + + if (ioctl (fd, PIOCGSPCACT, &prfs_flags) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } + prfs_flags |= PRFS_STOPEXEC; + if (ioctl (fd, PIOCSSPCACT, &prfs_flags) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } + } +#else + /* GW: Rationale... + Not all systems with /proc have all the exec* syscalls with the same + names. On the SGI, for example, there is no SYS_exec, but there + *is* a SYS_execv. So, we try to account for that. */ + +#ifdef SYS_exec + praddset (&exitset, SYS_exec); +#endif +#ifdef SYS_execve + praddset (&exitset, SYS_execve); +#endif +#ifdef SYS_execv + praddset (&exitset, SYS_execv); +#endif + + if (ioctl (fd, PIOCSEXIT, &exitset) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (127); + } +#endif + + praddset (&entryset, SYS_exit); + + if (ioctl (fd, PIOCSENTRY, &entryset) < 0) + { + perror (procname); + gdb_flush (gdb_stderr); + _exit (126); + } + + /* Turn off inherit-on-fork flag so that all grand-children of gdb + start with tracing flags cleared. */ + +#if defined (PIOCRESET) /* New method */ + { + long pr_flags; + pr_flags = PR_FORK; + ioctl (fd, PIOCRESET, &pr_flags); + } +#else +#if defined (PIOCRFORK) /* Original method */ + ioctl (fd, PIOCRFORK, NULL); +#endif +#endif + + /* Turn on run-on-last-close flag so that this process will not hang + if GDB goes away for some reason. */ + +#if defined (PIOCSET) /* New method */ + { + long pr_flags; + pr_flags = PR_RLC; + (void) ioctl (fd, PIOCSET, &pr_flags); + } +#else +#if defined (PIOCSRLC) /* Original method */ + (void) ioctl (fd, PIOCSRLC, 0); +#endif +#endif +} + +/* + +GLOBAL FUNCTION + + proc_iterate_over_mappings -- call function for every mapped space + +SYNOPSIS + + int proc_iterate_over_mappings (int (*func)()) + +DESCRIPTION + + Given a pointer to a function, call that function for every + mapped address space, passing it an open file descriptor for + the file corresponding to that mapped address space (if any) + and the base address of the mapped space. Quit when we hit + the end of the mappings or the function returns nonzero. + */ + +int +proc_iterate_over_mappings (func) + int (*func) PARAMS ((int, CORE_ADDR)); +{ + int nmap; + int fd; + int funcstat = 0; + struct prmap *prmaps; + struct prmap *prmap; + struct procinfo *pi; + + pi = current_procinfo; + + if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0) + { + prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); + if (ioctl (pi->fd, PIOCMAP, prmaps) == 0) + { + for (prmap = prmaps; prmap -> pr_size && funcstat == 0; ++prmap) + { + fd = proc_address_to_fd (pi, (CORE_ADDR) prmap -> pr_vaddr, 0); + funcstat = (*func) (fd, (CORE_ADDR) prmap -> pr_vaddr); + close (fd); + } + } + } + return (funcstat); +} + +#if 0 /* Currently unused */ +/* + +GLOBAL FUNCTION + + proc_base_address -- find base address for segment containing address + +SYNOPSIS + + CORE_ADDR proc_base_address (CORE_ADDR addr) + +DESCRIPTION + + Given an address of a location in the inferior, find and return + the base address of the mapped segment containing that address. + + This is used for example, by the shared library support code, + where we have the pc value for some location in the shared library + where we are stopped, and need to know the base address of the + segment containing that address. +*/ + +CORE_ADDR +proc_base_address (addr) + CORE_ADDR addr; +{ + int nmap; + struct prmap *prmaps; + struct prmap *prmap; + CORE_ADDR baseaddr = 0; + struct procinfo *pi; + + pi = current_procinfo; + + if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0) + { + prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); + if (ioctl (pi->fd, PIOCMAP, prmaps) == 0) + { + for (prmap = prmaps; prmap -> pr_size; ++prmap) + { + if ((prmap -> pr_vaddr <= (caddr_t) addr) && + (prmap -> pr_vaddr + prmap -> pr_size > (caddr_t) addr)) + { + baseaddr = (CORE_ADDR) prmap -> pr_vaddr; + break; + } + } + } + } + return (baseaddr); +} + +#endif /* 0 */ + +/* + +LOCAL FUNCTION + + proc_address_to_fd -- return open fd for file mapped to address + +SYNOPSIS + + int proc_address_to_fd (struct procinfo *pi, CORE_ADDR addr, complain) + +DESCRIPTION + + Given an address in the current inferior's address space, use the + /proc interface to find an open file descriptor for the file that + this address was mapped in from. Return -1 if there is no current + inferior. Print a warning message if there is an inferior but + the address corresponds to no file (IE a bogus address). + +*/ + +static int +proc_address_to_fd (pi, addr, complain) + struct procinfo *pi; + CORE_ADDR addr; + int complain; +{ + int fd = -1; + + if ((fd = ioctl (pi->fd, PIOCOPENM, (caddr_t *) &addr)) < 0) + { + if (complain) + { + print_sys_errmsg (pi->pathname, errno); + warning ("can't find mapped file for address 0x%x", addr); + } + } + return (fd); +} + + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +static void +procfs_attach (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + if (!args) + error_no_arg ("process-id to attach"); + + pid = atoi (args); + + if (pid == getpid()) /* Trying to masturbate? */ + error ("I refuse to debug myself!"); + + if (from_tty) + { + exec_file = (char *) get_exec_file (0); + + if (exec_file) + printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid)); + else + printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid)); + + gdb_flush (gdb_stdout); + } + + do_attach (pid); + inferior_pid = pid; + push_target (&procfs_ops); +} + + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +procfs_detach (args, from_tty) + char *args; + int from_tty; +{ + int siggnal = 0; + + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf_unfiltered ("Detaching from program: %s %s\n", + exec_file, target_pid_to_str (inferior_pid)); + gdb_flush (gdb_stdout); + } + if (args) + siggnal = atoi (args); + + do_detach (siggnal); + inferior_pid = 0; + unpush_target (&procfs_ops); /* Pop out of handling an inferior */ +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +procfs_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +/* Print status information about what we're accessing. */ + +static void +procfs_files_info (ignore) + struct target_ops *ignore; +{ + printf_unfiltered ("\tUsing the running image of %s %s via /proc.\n", + attach_flag? "attached": "child", target_pid_to_str (inferior_pid)); +} + +/* ARGSUSED */ +static void +procfs_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a Unix child process."); +} + +/* + +LOCAL FUNCTION + + do_attach -- attach to an already existing process + +SYNOPSIS + + int do_attach (int pid) + +DESCRIPTION + + Attach to an already existing process with the specified process + id. If the process is not already stopped, query whether to + stop it or not. + +NOTES + + The option of stopping at attach time is specific to the /proc + versions of gdb. Versions using ptrace force the attachee + to stop. (I have changed this version to do so, too. All you + have to do is "continue" to make it go on. -- gnu@cygnus.com) + +*/ + +static int +do_attach (pid) + int pid; +{ + int result; + struct procinfo *pi; + + pi = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + + if (!open_proc_file (pid, pi, O_RDWR)) + { + free (pi); + perror_with_name (pi->pathname); + /* NOTREACHED */ + } + + /* Add new process to process info list */ + + pi->next = procinfo_list; + procinfo_list = pi; + + add_fd (pi); /* Add to list for poll/select */ + + /* Get current status of process and if it is not already stopped, + then stop it. Remember whether or not it was stopped when we first + examined it. */ + + if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) + { + print_sys_errmsg (pi->pathname, errno); + close_proc_file (pi); + error ("PIOCSTATUS failed"); + } + if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + { + pi->was_stopped = 1; + } + else + { + pi->was_stopped = 0; + if (1 || query ("Process is currently running, stop it? ")) + { + /* Make it run again when we close it. */ +#if defined (PIOCSET) /* New method */ + { + long pr_flags; + pr_flags = PR_RLC; + result = ioctl (pi->fd, PIOCSET, &pr_flags); + } +#else +#if defined (PIOCSRLC) /* Original method */ + result = ioctl (pi->fd, PIOCSRLC, 0); +#endif +#endif + if (result < 0) + { + print_sys_errmsg (pi->pathname, errno); + close_proc_file (pi); + error ("PIOCSRLC or PIOCSET failed"); + } + if (ioctl (pi->fd, PIOCSTOP, &pi->prstatus) < 0) + { + print_sys_errmsg (pi->pathname, errno); + close_proc_file (pi); + error ("PIOCSTOP failed"); + } + pi->nopass_next_sigstop = 1; + } + else + { + printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid)); + } + } + + /* Remember some things about the inferior that we will, or might, change + so that we can restore them when we detach. */ + + ioctl (pi->fd, PIOCGTRACE, &pi->saved_trace); + ioctl (pi->fd, PIOCGHOLD, &pi->saved_sighold); + ioctl (pi->fd, PIOCGFAULT, &pi->saved_fltset); + ioctl (pi->fd, PIOCGENTRY, &pi->saved_entryset); + ioctl (pi->fd, PIOCGEXIT, &pi->saved_exitset); + + /* Set up trace and fault sets, as gdb expects them. */ + + memset (&pi->prrun, 0, sizeof (pi->prrun)); + prfillset (&pi->prrun.pr_trace); + procfs_notice_signals (pid); + prfillset (&pi->prrun.pr_fault); + prdelset (&pi->prrun.pr_fault, FLTPAGE); + +#ifdef PROCFS_DONT_TRACE_FAULTS + premptyset (&pi->prrun.pr_fault); +#endif + + if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault)) + { + print_sys_errmsg ("PIOCSFAULT failed", errno); + } + if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace)) + { + print_sys_errmsg ("PIOCSTRACE failed", errno); + } + attach_flag = 1; + return (pid); +} + +/* + +LOCAL FUNCTION + + do_detach -- detach from an attached-to process + +SYNOPSIS + + void do_detach (int signal) + +DESCRIPTION + + Detach from the current attachee. + + If signal is non-zero, the attachee is started running again and sent + the specified signal. + + If signal is zero and the attachee was not already stopped when we + attached to it, then we make it runnable again when we detach. + + Otherwise, we query whether or not to make the attachee runnable + again, since we may simply want to leave it in the state it was in + when we attached. + + We report any problems, but do not consider them errors, since we + MUST detach even if some things don't seem to go right. This may not + be the ideal situation. (FIXME). + */ + +static void +do_detach (signal) + int signal; +{ + int result; + struct procinfo *pi; + + pi = current_procinfo; + + if (signal) + { + set_proc_siginfo (pi, signal); + } + if (ioctl (pi->fd, PIOCSEXIT, &pi->saved_exitset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSEXIT failed.\n"); + } + if (ioctl (pi->fd, PIOCSENTRY, &pi->saved_entryset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSENTRY failed.\n"); + } + if (ioctl (pi->fd, PIOCSTRACE, &pi->saved_trace) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSTRACE failed.\n"); + } + if (ioctl (pi->fd, PIOCSHOLD, &pi->saved_sighold) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOSCHOLD failed.\n"); + } + if (ioctl (pi->fd, PIOCSFAULT, &pi->saved_fltset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSFAULT failed.\n"); + } + if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSTATUS failed.\n"); + } + else + { + if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) + { + if (signal || !pi->was_stopped || + query ("Was stopped when attached, make it runnable again? ")) + { + /* Clear any pending signal if we want to detach without + a signal. */ + if (signal == 0) + set_proc_siginfo (pi, signal); + + /* Clear any fault that might have stopped it. */ + if (ioctl (pi->fd, PIOCCFAULT, 0)) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCCFAULT failed.\n"); + } + + /* Make it run again when we close it. */ +#if defined (PIOCSET) /* New method */ + { + long pr_flags; + pr_flags = PR_RLC; + result = ioctl (pi->fd, PIOCSET, &pr_flags); + } +#else +#if defined (PIOCSRLC) /* Original method */ + result = ioctl (pi->fd, PIOCSRLC, 0); +#endif +#endif + if (result) + { + print_sys_errmsg (pi->pathname, errno); + printf_unfiltered ("PIOCSRLC or PIOCSET failed.\n"); + } + } + } + } + close_proc_file (pi); + attach_flag = 0; +} + +/* emulate wait() as much as possible. + Wait for child to do something. Return pid of child, or -1 in case + of error; store status in *OURSTATUS. + + Not sure why we can't + just use wait(), but it seems to have problems when applied to a + process being controlled with the /proc interface. + + We have a race problem here with no obvious solution. We need to let + the inferior run until it stops on an event of interest, which means + that we need to use the PIOCWSTOP ioctl. However, we cannot use this + ioctl if the process is already stopped on something that is not an + event of interest, or the call will hang indefinitely. Thus we first + use PIOCSTATUS to see if the process is not stopped. If not, then we + use PIOCWSTOP. But during the window between the two, if the process + stops for any reason that is not an event of interest (such as a job + control signal) then gdb will hang. One possible workaround is to set + an alarm to wake up every minute of so and check to see if the process + is still running, and if so, then reissue the PIOCWSTOP. But this is + a real kludge, so has not been implemented. FIXME: investigate + alternatives. + + FIXME: Investigate why wait() seems to have problems with programs + being control by /proc routines. */ + +static int +procfs_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + short what; + short why; + int statval = 0; + int checkerr = 0; + int rtnval = -1; + struct procinfo *pi; + + if (pid != -1) /* Non-specific process? */ + pi = NULL; + else + for (pi = procinfo_list; pi; pi = pi->next) + if (pi->had_event) + break; + + if (!pi) + { + wait_again: + + pi = wait_fd (); + } + + if (pid != -1) + for (pi = procinfo_list; pi; pi = pi->next) + if (pi->pid == pid && pi->had_event) + break; + + if (!pi && !checkerr) + goto wait_again; + + if (!checkerr && !(pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) + { + if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0) + { + checkerr++; + } + } + if (checkerr) + { + if (errno == ENOENT) + { + rtnval = wait (&statval); + if (rtnval != inferior_pid) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCWSTOP, wait failed, returned %d", rtnval); + /* NOTREACHED */ + } + } + else + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSTATUS or PIOCWSTOP failed."); + /* NOTREACHED */ + } + } + else if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + { + rtnval = pi->prstatus.pr_pid; + why = pi->prstatus.pr_why; + what = pi->prstatus.pr_what; + + switch (why) + { + case PR_SIGNALLED: + statval = (what << 8) | 0177; + break; + case PR_SYSENTRY: + if (what != SYS_exit) + error ("PR_SYSENTRY, unknown system call %d", what); + + pi->prrun.pr_flags = PRCFAULT; + + if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) + perror_with_name (pi->pathname); + + rtnval = wait (&statval); + + break; + case PR_SYSEXIT: + switch (what) + { +#ifdef SYS_exec + case SYS_exec: +#endif +#ifdef SYS_execve + case SYS_execve: +#endif +#ifdef SYS_execv + case SYS_execv: +#endif + statval = (SIGTRAP << 8) | 0177; + break; +#ifdef SYS_sproc + case SYS_sproc: +/* We've just detected the completion of an sproc system call. Now we need to + setup a procinfo struct for this thread, and notify the thread system of the + new arrival. */ + +/* If sproc failed, then nothing interesting happened. Continue the process and + go back to sleep. */ + + if (pi->prstatus.pr_errno != 0) + { + pi->prrun.pr_flags &= PRSTEP; + pi->prrun.pr_flags |= PRCFAULT; + + if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) + perror_with_name (pi->pathname); + + goto wait_again; + } + +/* At this point, the new thread is stopped at it's first instruction, and + the parent is stopped at the exit from sproc. */ + +/* Notify the caller of the arrival of a new thread. */ + create_procinfo (pi->prstatus.pr_rval1); + + rtnval = pi->prstatus.pr_rval1; + statval = (SIGTRAP << 8) | 0177; + + break; + case SYS_fork: +#ifdef SYS_vfork + case SYS_vfork: +#endif +/* At this point, we've detected the completion of a fork (or vfork) call in + our child. The grandchild is also stopped because we set inherit-on-fork + earlier. (Note that nobody has the grandchilds' /proc file open at this + point.) We will release the grandchild from the debugger by opening it's + /proc file and then closing it. Since run-on-last-close is set, the + grandchild continues on its' merry way. */ + + { + struct procinfo *pitemp; + + pitemp = create_procinfo (pi->prstatus.pr_rval1); + if (pitemp) + close_proc_file (pitemp); + + if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) + perror_with_name (pi->pathname); + } + goto wait_again; +#endif /* SYS_sproc */ + + default: + error ("PIOCSTATUS (PR_SYSEXIT): Unknown system call %d", what); + } + break; + case PR_REQUESTED: + statval = (SIGSTOP << 8) | 0177; + break; + case PR_JOBCONTROL: + statval = (what << 8) | 0177; + break; + case PR_FAULTED: + switch (what) + { +#ifdef FLTWATCH + case FLTWATCH: + statval = (SIGTRAP << 8) | 0177; + break; +#endif +#ifdef FLTKWATCH + case FLTKWATCH: + statval = (SIGTRAP << 8) | 0177; + break; +#endif +#ifndef FAULTED_USE_SIGINFO + /* Irix, contrary to the documentation, fills in 0 for si_signo. + Solaris fills in si_signo. I'm not sure about others. */ + case FLTPRIV: + case FLTILL: + statval = (SIGILL << 8) | 0177; + break; + case FLTBPT: + case FLTTRACE: + statval = (SIGTRAP << 8) | 0177; + break; + case FLTSTACK: + case FLTACCESS: + case FLTBOUNDS: + statval = (SIGSEGV << 8) | 0177; + break; + case FLTIOVF: + case FLTIZDIV: + case FLTFPE: + statval = (SIGFPE << 8) | 0177; + break; + case FLTPAGE: /* Recoverable page fault */ +#endif /* not FAULTED_USE_SIGINFO */ + default: + /* Use the signal which the kernel assigns. This is better than + trying to second-guess it from the fault. In fact, I suspect + that FLTACCESS can be either SIGSEGV or SIGBUS. */ + statval = ((pi->prstatus.pr_info.si_signo) << 8) | 0177; + break; + } + break; + default: + error ("PIOCWSTOP, unknown why %d, what %d", why, what); + } +/* Stop all the other threads when any of them stops. */ + + { + struct procinfo *procinfo; + + for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + { + if (!procinfo->had_event) + if (ioctl (procinfo->fd, PIOCSTOP, &procinfo->prstatus) < 0) + { + print_sys_errmsg (procinfo->pathname, errno); + error ("PIOCSTOP failed"); + } + } + } + } + else + { + error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x", + pi->prstatus.pr_flags); + } + + store_waitstatus (ourstatus, statval); + + if (rtnval == -1) /* No more children to wait for */ + { + fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing.\n"); + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return rtnval; + } + + pi->had_event = 0; /* Indicate that we've seen this one */ + return (rtnval); +} + +/* + +LOCAL FUNCTION + + set_proc_siginfo - set a process's current signal info + +SYNOPSIS + + void set_proc_siginfo (struct procinfo *pip, int signo); + +DESCRIPTION + + Given a pointer to a process info struct in PIP and a signal number + in SIGNO, set the process's current signal and its associated signal + information. The signal will be delivered to the process immediately + after execution is resumed, even if it is being held. In addition, + this particular delivery will not cause another PR_SIGNALLED stop + even if the signal is being traced. + + If we are not delivering the same signal that the prstatus siginfo + struct contains information about, then synthesize a siginfo struct + to match the signal we are doing to deliver, make it of the type + "generated by a user process", and send this synthesized copy. When + used to set the inferior's signal state, this will be required if we + are not currently stopped because of a traced signal, or if we decide + to continue with a different signal. + + Note that when continuing the inferior from a stop due to receipt + of a traced signal, we either have set PRCSIG to clear the existing + signal, or we have to call this function to do a PIOCSSIG with either + the existing siginfo struct from pr_info, or one we have synthesized + appropriately for the signal we want to deliver. Otherwise if the + signal is still being traced, the inferior will immediately stop + again. + + See siginfo(5) for more details. +*/ + +static void +set_proc_siginfo (pip, signo) + struct procinfo *pip; + int signo; +{ + struct siginfo newsiginfo; + struct siginfo *sip; + +#ifdef PROCFS_DONT_PIOCSSIG_CURSIG + /* With Alpha OSF/1 procfs, the kernel gets really confused if it + receives a PIOCSSIG with a signal identical to the current signal, + it messes up the current signal. Work around the kernel bug. */ + if (signo == pip -> prstatus.pr_cursig) + return; +#endif + + if (signo == pip -> prstatus.pr_info.si_signo) + { + sip = &pip -> prstatus.pr_info; + } + else + { + memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); + sip = &newsiginfo; + sip -> si_signo = signo; + sip -> si_code = 0; + sip -> si_errno = 0; + sip -> si_pid = getpid (); + sip -> si_uid = getuid (); + } + if (ioctl (pip -> fd, PIOCSSIG, sip) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + warning ("PIOCSSIG failed"); + } +} + +/* Resume execution of process PID. If STEP is nozero, then + just single step it. If SIGNAL is nonzero, restart it with that + signal activated. */ + +static void +procfs_resume (pid, step, signo) + int pid; + int step; + enum target_signal signo; +{ + int signal_to_pass; + struct procinfo *pi, *procinfo; + + pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0); + + errno = 0; + pi->prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT; + +#if 0 + /* It should not be necessary. If the user explicitly changes the value, + value_assign calls write_register_bytes, which writes it. */ +/* It may not be absolutely necessary to specify the PC value for + restarting, but to be safe we use the value that gdb considers + to be current. One case where this might be necessary is if the + user explicitly changes the PC value that gdb considers to be + current. FIXME: Investigate if this is necessary or not. */ + +#ifdef PRSVADDR_BROKEN +/* Can't do this under Solaris running on a Sparc, as there seems to be no + place to put nPC. In fact, if you use this, nPC seems to be set to some + random garbage. We have to rely on the fact that PC and nPC have been + written previously via PIOCSREG during a register flush. */ + + pi->prrun.pr_vaddr = (caddr_t) *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)]; + pi->prrun.pr_flags != PRSVADDR; +#endif +#endif + + if (signo == TARGET_SIGNAL_STOP && pi->nopass_next_sigstop) + /* When attaching to a child process, if we forced it to stop with + a PIOCSTOP, then we will have set the nopass_next_sigstop flag. + Upon resuming the first time after such a stop, we explicitly + inhibit sending it another SIGSTOP, which would be the normal + result of default signal handling. One potential drawback to + this is that we will also ignore any attempt to by the user + to explicitly continue after the attach with a SIGSTOP. Ultimately + this problem should be dealt with by making the routines that + deal with the inferior a little smarter, and possibly even allow + an inferior to continue running at the same time as gdb. (FIXME?) */ + signal_to_pass = 0; + else if (signo == TARGET_SIGNAL_TSTP + && pi->prstatus.pr_cursig == SIGTSTP + && pi->prstatus.pr_action.sa_handler == SIG_DFL) + + /* We are about to pass the inferior a SIGTSTP whose action is + SIG_DFL. The SIG_DFL action for a SIGTSTP is to stop + (notifying the parent via wait()), and then keep going from the + same place when the parent is ready for you to keep going. So + under the debugger, it should do nothing (as if the program had + been stopped and then later resumed. Under ptrace, this + happens for us, but under /proc, the system obligingly stops + the process, and wait_for_inferior would have no way of + distinguishing that type of stop (which indicates that we + should just start it again), with a stop due to the pr_trace + field of the prrun_t struct. + + Note that if the SIGTSTP is being caught, we *do* need to pass it, + because the handler needs to get executed. */ + signal_to_pass = 0; + else + signal_to_pass = target_signal_to_host (signo); + + if (signal_to_pass) + { + set_proc_siginfo (pi, signal_to_pass); + } + else + { + pi->prrun.pr_flags |= PRCSIG; + } + pi->nopass_next_sigstop = 0; + if (step) + { + pi->prrun.pr_flags |= PRSTEP; + } + if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0) + { + perror_with_name (pi->pathname); + /* NOTREACHED */ + } + + pi->had_event = 0; + + /* Continue all the other threads that haven't had an event of + interest. */ + + if (pid == -1) + for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + { + if (pi != procinfo && !procinfo->had_event) + { + procinfo->prrun.pr_flags &= PRSTEP; + procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG; + ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus); + if (ioctl (procinfo->fd, PIOCRUN, &procinfo->prrun) < 0) + { + if (ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus) < 0) + { + fprintf_unfiltered(gdb_stderr, "PIOCSTATUS failed, errno=%d\n", errno); + } + print_sys_errmsg (procinfo->pathname, errno); + error ("PIOCRUN failed"); + } + ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus); + } + } +} + +/* + +LOCAL FUNCTION + + procfs_fetch_registers -- fetch current registers from inferior + +SYNOPSIS + + void procfs_fetch_registers (int regno) + +DESCRIPTION + + Read the current values of the inferior's registers, both the + general register set and floating point registers (if supported) + and update gdb's idea of their current values. + +*/ + +static void +procfs_fetch_registers (regno) + int regno; +{ + struct procinfo *pi; + + pi = current_procinfo; + + if (ioctl (pi->fd, PIOCGREG, &pi->gregset) != -1) + { + supply_gregset (&pi->gregset); + } +#if defined (FP0_REGNUM) + if (ioctl (pi->fd, PIOCGFPREG, &pi->fpregset) != -1) + { + supply_fpregset (&pi->fpregset); + } +#endif +} + +/* + +LOCAL FUNCTION + + proc_init_failed - called whenever /proc access initialization +fails + +SYNOPSIS + + static void proc_init_failed (struct procinfo *pi, char *why) + +DESCRIPTION + + This function is called whenever initialization of access to a /proc + entry fails. It prints a suitable error message, does some cleanup, + and then invokes the standard error processing routine which dumps + us back into the command loop. + */ + +static void +proc_init_failed (pi, why) + struct procinfo *pi; + char *why; +{ + print_sys_errmsg (pi->pathname, errno); + kill (pi->pid, SIGKILL); + close_proc_file (pi); + error (why); + /* NOTREACHED */ +} + +/* + +LOCAL FUNCTION + + close_proc_file - close any currently open /proc entry + +SYNOPSIS + + static void close_proc_file (struct procinfo *pip) + +DESCRIPTION + + Close any currently open /proc entry and mark the process information + entry as invalid. In order to ensure that we don't try to reuse any + stale information, the pid, fd, and pathnames are explicitly + invalidated, which may be overkill. + + */ + +static void +close_proc_file (pip) + struct procinfo *pip; +{ + struct procinfo *procinfo; + + remove_fd (pip); /* Remove fd from poll/select list */ + + close (pip -> fd); + + free (pip -> pathname); + + /* Unlink pip from the procinfo chain. Note pip might not be on the list. */ + + if (procinfo_list == pip) + procinfo_list = pip->next; + else + for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next) + if (procinfo->next == pip) + procinfo->next = pip->next; + + free (pip); +} + +/* + +LOCAL FUNCTION + + open_proc_file - open a /proc entry for a given process id + +SYNOPSIS + + static int open_proc_file (int pid, struct procinfo *pip, int mode) + +DESCRIPTION + + Given a process id and a mode, close the existing open /proc + entry (if any) and open one for the new process id, in the + specified mode. Once it is open, then mark the local process + information structure as valid, which guarantees that the pid, + fd, and pathname fields match an open /proc entry. Returns + zero if the open fails, nonzero otherwise. + + Note that the pathname is left intact, even when the open fails, + so that callers can use it to construct meaningful error messages + rather than just "file open failed". + */ + +static int +open_proc_file (pid, pip, mode) + int pid; + struct procinfo *pip; + int mode; +{ + pip -> next = NULL; + pip -> had_event = 0; + pip -> pathname = xmalloc (32); + pip -> pid = pid; + + sprintf (pip -> pathname, PROC_NAME_FMT, pid); + if ((pip -> fd = open (pip -> pathname, mode)) < 0) + return 0; + + return 1; +} + +static char * +mappingflags (flags) + long flags; +{ + static char asciiflags[8]; + + strcpy (asciiflags, "-------"); +#if defined (MA_PHYS) + if (flags & MA_PHYS) asciiflags[0] = 'd'; +#endif + if (flags & MA_STACK) asciiflags[1] = 's'; + if (flags & MA_BREAK) asciiflags[2] = 'b'; + if (flags & MA_SHARED) asciiflags[3] = 's'; + if (flags & MA_READ) asciiflags[4] = 'r'; + if (flags & MA_WRITE) asciiflags[5] = 'w'; + if (flags & MA_EXEC) asciiflags[6] = 'x'; + return (asciiflags); +} + +static void +info_proc_flags (pip, summary) + struct procinfo *pip; + int summary; +{ + struct trans *transp; + + printf_filtered ("%-32s", "Process status flags:"); + if (!summary) + { + printf_filtered ("\n\n"); + } + for (transp = pr_flag_table; transp -> name != NULL; transp++) + { + if (pip -> prstatus.pr_flags & transp -> value) + { + if (summary) + { + printf_filtered ("%s ", transp -> name); + } + else + { + printf_filtered ("\t%-16s %s.\n", transp -> name, transp -> desc); + } + } + } + printf_filtered ("\n"); +} + +static void +info_proc_stop (pip, summary) + struct procinfo *pip; + int summary; +{ + struct trans *transp; + int why; + int what; + + why = pip -> prstatus.pr_why; + what = pip -> prstatus.pr_what; + + if (pip -> prstatus.pr_flags & PR_STOPPED) + { + printf_filtered ("%-32s", "Reason for stopping:"); + if (!summary) + { + printf_filtered ("\n\n"); + } + for (transp = pr_why_table; transp -> name != NULL; transp++) + { + if (why == transp -> value) + { + if (summary) + { + printf_filtered ("%s ", transp -> name); + } + else + { + printf_filtered ("\t%-16s %s.\n", + transp -> name, transp -> desc); + } + break; + } + } + + /* Use the pr_why field to determine what the pr_what field means, and + print more information. */ + + switch (why) + { + case PR_REQUESTED: + /* pr_what is unused for this case */ + break; + case PR_JOBCONTROL: + case PR_SIGNALLED: + if (summary) + { + printf_filtered ("%s ", signalname (what)); + } + else + { + printf_filtered ("\t%-16s %s.\n", signalname (what), + safe_strsignal (what)); + } + break; + case PR_SYSENTRY: + if (summary) + { + printf_filtered ("%s ", syscallname (what)); + } + else + { + printf_filtered ("\t%-16s %s.\n", syscallname (what), + "Entered this system call"); + } + break; + case PR_SYSEXIT: + if (summary) + { + printf_filtered ("%s ", syscallname (what)); + } + else + { + printf_filtered ("\t%-16s %s.\n", syscallname (what), + "Returned from this system call"); + } + break; + case PR_FAULTED: + if (summary) + { + printf_filtered ("%s ", + lookupname (faults_table, what, "fault")); + } + else + { + printf_filtered ("\t%-16s %s.\n", + lookupname (faults_table, what, "fault"), + lookupdesc (faults_table, what)); + } + break; + } + printf_filtered ("\n"); + } +} + +static void +info_proc_siginfo (pip, summary) + struct procinfo *pip; + int summary; +{ + struct siginfo *sip; + + if ((pip -> prstatus.pr_flags & PR_STOPPED) && + (pip -> prstatus.pr_why == PR_SIGNALLED || + pip -> prstatus.pr_why == PR_FAULTED)) + { + printf_filtered ("%-32s", "Additional signal/fault info:"); + sip = &pip -> prstatus.pr_info; + if (summary) + { + printf_filtered ("%s ", signalname (sip -> si_signo)); + if (sip -> si_errno > 0) + { + printf_filtered ("%s ", errnoname (sip -> si_errno)); + } + if (sip -> si_code <= 0) + { + printf_filtered ("sent by %s, uid %d ", + target_pid_to_str (sip -> si_pid), + sip -> si_uid); + } + else + { + printf_filtered ("%s ", sigcodename (sip)); + if ((sip -> si_signo == SIGILL) || + (sip -> si_signo == SIGFPE) || + (sip -> si_signo == SIGSEGV) || + (sip -> si_signo == SIGBUS)) + { + printf_filtered ("addr=%#lx ", + (unsigned long) sip -> si_addr); + } + else if ((sip -> si_signo == SIGCHLD)) + { + printf_filtered ("child %s, status %u ", + target_pid_to_str (sip -> si_pid), + sip -> si_status); + } + else if ((sip -> si_signo == SIGPOLL)) + { + printf_filtered ("band %u ", sip -> si_band); + } + } + } + else + { + printf_filtered ("\n\n"); + printf_filtered ("\t%-16s %s.\n", signalname (sip -> si_signo), + safe_strsignal (sip -> si_signo)); + if (sip -> si_errno > 0) + { + printf_filtered ("\t%-16s %s.\n", + errnoname (sip -> si_errno), + safe_strerror (sip -> si_errno)); + } + if (sip -> si_code <= 0) + { + printf_filtered ("\t%-16u %s\n", sip -> si_pid, /* XXX need target_pid_to_str() */ + "PID of process sending signal"); + printf_filtered ("\t%-16u %s\n", sip -> si_uid, + "UID of process sending signal"); + } + else + { + printf_filtered ("\t%-16s %s.\n", sigcodename (sip), + sigcodedesc (sip)); + if ((sip -> si_signo == SIGILL) || + (sip -> si_signo == SIGFPE)) + { + printf_filtered ("\t%#-16lx %s.\n", + (unsigned long) sip -> si_addr, + "Address of faulting instruction"); + } + else if ((sip -> si_signo == SIGSEGV) || + (sip -> si_signo == SIGBUS)) + { + printf_filtered ("\t%#-16lx %s.\n", + (unsigned long) sip -> si_addr, + "Address of faulting memory reference"); + } + else if ((sip -> si_signo == SIGCHLD)) + { + printf_filtered ("\t%-16u %s.\n", sip -> si_pid, /* XXX need target_pid_to_str() */ + "Child process ID"); + printf_filtered ("\t%-16u %s.\n", sip -> si_status, + "Child process exit value or signal"); + } + else if ((sip -> si_signo == SIGPOLL)) + { + printf_filtered ("\t%-16u %s.\n", sip -> si_band, + "Band event for POLL_{IN,OUT,MSG}"); + } + } + } + printf_filtered ("\n"); + } +} + +static void +info_proc_syscalls (pip, summary) + struct procinfo *pip; + int summary; +{ + int syscallnum; + + if (!summary) + { + +#if 0 /* FIXME: Needs to use gdb-wide configured info about system calls. */ + if (pip -> prstatus.pr_flags & PR_ASLEEP) + { + int syscallnum = pip -> prstatus.pr_reg[R_D0]; + if (summary) + { + printf_filtered ("%-32s", "Sleeping in system call:"); + printf_filtered ("%s", syscallname (syscallnum)); + } + else + { + printf_filtered ("Sleeping in system call '%s'.\n", + syscallname (syscallnum)); + } + } +#endif + + if (ioctl (pip -> fd, PIOCGENTRY, &pip -> entryset) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCGENTRY failed"); + } + + if (ioctl (pip -> fd, PIOCGEXIT, &pip -> exitset) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCGEXIT failed"); + } + + printf_filtered ("System call tracing information:\n\n"); + + printf_filtered ("\t%-12s %-8s %-8s\n", + "System call", + "Entry", + "Exit"); + for (syscallnum = 0; syscallnum < MAX_SYSCALLS; syscallnum++) + { + QUIT; + if (syscall_table[syscallnum] != NULL) + { + printf_filtered ("\t%-12s ", syscall_table[syscallnum]); + printf_filtered ("%-8s ", + prismember (&pip -> entryset, syscallnum) + ? "on" : "off"); + printf_filtered ("%-8s ", + prismember (&pip -> exitset, syscallnum) + ? "on" : "off"); + printf_filtered ("\n"); + } + } + printf_filtered ("\n"); + } +} + +static char * +signalname (signo) + int signo; +{ + const char *name; + static char locbuf[32]; + + name = strsigno (signo); + if (name == NULL) + { + sprintf (locbuf, "Signal %d", signo); + } + else + { + sprintf (locbuf, "%s (%d)", name, signo); + } + return (locbuf); +} + +static char * +errnoname (errnum) + int errnum; +{ + const char *name; + static char locbuf[32]; + + name = strerrno (errnum); + if (name == NULL) + { + sprintf (locbuf, "Errno %d", errnum); + } + else + { + sprintf (locbuf, "%s (%d)", name, errnum); + } + return (locbuf); +} + +static void +info_proc_signals (pip, summary) + struct procinfo *pip; + int summary; +{ + int signo; + + if (!summary) + { + if (ioctl (pip -> fd, PIOCGTRACE, &pip -> trace) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCGTRACE failed"); + } + + printf_filtered ("Disposition of signals:\n\n"); + printf_filtered ("\t%-15s %-8s %-8s %-8s %s\n\n", + "Signal", "Trace", "Hold", "Pending", "Description"); + for (signo = 0; signo < NSIG; signo++) + { + QUIT; + printf_filtered ("\t%-15s ", signalname (signo)); + printf_filtered ("%-8s ", + prismember (&pip -> trace, signo) + ? "on" : "off"); + printf_filtered ("%-8s ", + prismember (&pip -> prstatus.pr_sighold, signo) + ? "on" : "off"); + +#ifdef PROCFS_SIGPEND_OFFSET + /* Alpha OSF/1 numbers the pending signals from 1. */ + printf_filtered ("%-8s ", + (signo ? prismember (&pip -> prstatus.pr_sigpend, + signo - 1) + : 0) + ? "yes" : "no"); +#else + printf_filtered ("%-8s ", + prismember (&pip -> prstatus.pr_sigpend, signo) + ? "yes" : "no"); +#endif + printf_filtered (" %s\n", safe_strsignal (signo)); + } + printf_filtered ("\n"); + } +} + +static void +info_proc_faults (pip, summary) + struct procinfo *pip; + int summary; +{ + struct trans *transp; + + if (!summary) + { + if (ioctl (pip -> fd, PIOCGFAULT, &pip -> fltset) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCGFAULT failed"); + } + + printf_filtered ("Current traced hardware fault set:\n\n"); + printf_filtered ("\t%-12s %-8s\n", "Fault", "Trace"); + + for (transp = faults_table; transp -> name != NULL; transp++) + { + QUIT; + printf_filtered ("\t%-12s ", transp -> name); + printf_filtered ("%-8s", prismember (&pip -> fltset, transp -> value) + ? "on" : "off"); + printf_filtered ("\n"); + } + printf_filtered ("\n"); + } +} + +static void +info_proc_mappings (pip, summary) + struct procinfo *pip; + int summary; +{ + int nmap; + struct prmap *prmaps; + struct prmap *prmap; + + if (!summary) + { + printf_filtered ("Mapped address spaces:\n\n"); +#ifdef BFD_HOST_64_BIT + printf_filtered (" %18s %18s %10s %10s %7s\n", +#else + printf_filtered ("\t%10s %10s %10s %10s %7s\n", +#endif + "Start Addr", + " End Addr", + " Size", + " Offset", + "Flags"); + if (ioctl (pip -> fd, PIOCNMAP, &nmap) == 0) + { + prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); + if (ioctl (pip -> fd, PIOCMAP, prmaps) == 0) + { + for (prmap = prmaps; prmap -> pr_size; ++prmap) + { +#ifdef BFD_HOST_64_BIT + printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n", +#else + printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", +#endif + (unsigned long)prmap -> pr_vaddr, + (unsigned long)prmap -> pr_vaddr + + prmap -> pr_size - 1, + prmap -> pr_size, + prmap -> pr_off, + mappingflags (prmap -> pr_mflags)); + } + } + } + printf_filtered ("\n"); + } +} + +/* + +LOCAL FUNCTION + + info_proc -- implement the "info proc" command + +SYNOPSIS + + void info_proc (char *args, int from_tty) + +DESCRIPTION + + Implement gdb's "info proc" command by using the /proc interface + to print status information about any currently running process. + + Examples of the use of "info proc" are: + + info proc (prints summary info for current inferior) + info proc 123 (prints summary info for process with pid 123) + info proc mappings (prints address mappings) + info proc times (prints process/children times) + info proc id (prints pid, ppid, gid, sid, etc) + FIXME: i proc id not implemented. + info proc status (prints general process state info) + FIXME: i proc status not implemented. + info proc signals (prints info about signal handling) + info proc all (prints all info) + + */ + +static void +info_proc (args, from_tty) + char *args; + int from_tty; +{ + int pid; + struct procinfo *pip; + struct cleanup *old_chain; + char **argv; + int argsize; + int summary = 1; + int flags = 0; + int syscalls = 0; + int signals = 0; + int faults = 0; + int mappings = 0; + int times = 0; + int id = 0; + int status = 0; + int all = 0; + + old_chain = make_cleanup (null_cleanup, 0); + + /* Default to using the current inferior if no pid specified. Note + that inferior_pid may be 0, hence we set okerr. */ + + pip = find_procinfo (inferior_pid, 1); + + if (args != NULL) + { + if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + make_cleanup (freeargv, (char *) argv); + + while (*argv != NULL) + { + argsize = strlen (*argv); + if (argsize >= 1 && strncmp (*argv, "all", argsize) == 0) + { + summary = 0; + all = 1; + } + else if (argsize >= 2 && strncmp (*argv, "faults", argsize) == 0) + { + summary = 0; + faults = 1; + } + else if (argsize >= 2 && strncmp (*argv, "flags", argsize) == 0) + { + summary = 0; + flags = 1; + } + else if (argsize >= 1 && strncmp (*argv, "id", argsize) == 0) + { + summary = 0; + id = 1; + } + else if (argsize >= 1 && strncmp (*argv, "mappings", argsize) == 0) + { + summary = 0; + mappings = 1; + } + else if (argsize >= 2 && strncmp (*argv, "signals", argsize) == 0) + { + summary = 0; + signals = 1; + } + else if (argsize >= 2 && strncmp (*argv, "status", argsize) == 0) + { + summary = 0; + status = 1; + } + else if (argsize >= 2 && strncmp (*argv, "syscalls", argsize) == 0) + { + summary = 0; + syscalls = 1; + } + else if (argsize >= 1 && strncmp (*argv, "times", argsize) == 0) + { + summary = 0; + times = 1; + } + else if ((pid = atoi (*argv)) > 0) + { + pip = (struct procinfo *) xmalloc (sizeof (struct procinfo)); + memset (pip, 0, sizeof (*pip)); + + pip->pid = pid; + if (!open_proc_file (pid, pip, O_RDONLY)) + { + perror_with_name (pip -> pathname); + /* NOTREACHED */ + } + make_cleanup (close_proc_file, pip); + } + else if (**argv != '\000') + { + error ("Unrecognized or ambiguous keyword `%s'.", *argv); + } + argv++; + } + } + + /* If we don't have a valid open process at this point, then we have no + inferior or didn't specify a specific pid. */ + + if (!pip) + { + error ("\ +No process. Start debugging a program or specify an explicit process ID."); + } + if (ioctl (pip -> fd, PIOCSTATUS, &(pip -> prstatus)) < 0) + { + print_sys_errmsg (pip -> pathname, errno); + error ("PIOCSTATUS failed"); + } + + /* Print verbose information of the requested type(s), or just a summary + of the information for all types. */ + + printf_filtered ("\nInformation for %s:\n\n", pip -> pathname); + if (summary || all || flags) + { + info_proc_flags (pip, summary); + } + if (summary || all) + { + info_proc_stop (pip, summary); + } + if (summary || all || signals || faults) + { + info_proc_siginfo (pip, summary); + } + if (summary || all || syscalls) + { + info_proc_syscalls (pip, summary); + } + if (summary || all || mappings) + { + info_proc_mappings (pip, summary); + } + if (summary || all || signals) + { + info_proc_signals (pip, summary); + } + if (summary || all || faults) + { + info_proc_faults (pip, summary); + } + printf_filtered ("\n"); + + /* All done, deal with closing any temporary process info structure, + freeing temporary memory , etc. */ + + do_cleanups (old_chain); +} + +/* + +LOCAL FUNCTION + + procfs_set_sproc_trap -- arrange for child to stop on sproc(). + +SYNOPSIS + + void procfs_set_sproc_trap (struct procinfo *) + +DESCRIPTION + + This function sets up a trap on sproc system call exits so that we can + detect the arrival of a new thread. We are called with the new thread + stopped prior to it's first instruction. + + Also note that we turn on the inherit-on-fork flag in the child process + so that any grand-children start with all tracing flags set. + */ + +#ifdef SYS_sproc + +static void +procfs_set_sproc_trap (pi) + struct procinfo *pi; +{ + sysset_t exitset; + + if (ioctl (pi->fd, PIOCGEXIT, &exitset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCGEXIT failed"); + } + + praddset (&exitset, SYS_sproc); + + /* We trap on fork() and vfork() in order to disable debugging in our grand- + children and descendant processes. At this time, GDB can only handle + threads (multiple processes, one address space). forks (and execs) result + in the creation of multiple address spaces, which GDB can't handle yet. */ + + praddset (&exitset, SYS_fork); +#ifdef SYS_vfork + praddset (&exitset, SYS_vfork); +#endif + + if (ioctl (pi->fd, PIOCSEXIT, &exitset) < 0) + { + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSEXIT failed"); + } + + /* Turn on inherit-on-fork flag so that all grand-children of gdb start with + tracing flags set. */ + +#ifdef PIOCSET /* New method */ + { + long pr_flags; + pr_flags = PR_FORK; + ioctl (pi->fd, PIOCSET, &pr_flags); + } +#else +#ifdef PIOCSFORK /* Original method */ + ioctl (pi->fd, PIOCSFORK, NULL); +#endif +#endif +} +#endif /* SYS_sproc */ + +/* Fork an inferior process, and start debugging it with /proc. */ + +static void +procfs_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + char *shell_file = getenv ("SHELL"); + char *tryname; + if (shell_file != NULL && strchr (shell_file, '/') == NULL) + { + + /* We will be looking down the PATH to find shell_file. If we + just do this the normal way (via execlp, which operates by + attempting an exec for each element of the PATH until it + finds one which succeeds), then there will be an exec for + each failed attempt, each of which will cause a PR_SYSEXIT + stop, and we won't know how to distinguish the PR_SYSEXIT's + for these failed execs with the ones for successful execs + (whether the exec has succeeded is stored at that time in the + carry bit or some such architecture-specific and + non-ABI-specified place). + + So I can't think of anything better than to search the PATH + now. This has several disadvantages: (1) There is a race + condition; if we find a file now and it is deleted before we + exec it, we lose, even if the deletion leaves a valid file + further down in the PATH, (2) there is no way to know exactly + what an executable (in the sense of "capable of being + exec'd") file is. Using access() loses because it may lose + if the caller is the superuser; failing to use it loses if + there are ACLs or some such. */ + + char *p; + char *p1; + /* FIXME-maybe: might want "set path" command so user can change what + path is used from within GDB. */ + char *path = getenv ("PATH"); + int len; + struct stat statbuf; + + if (path == NULL) + path = "/bin:/usr/bin"; + + tryname = alloca (strlen (path) + strlen (shell_file) + 2); + for (p = path; p != NULL; p = p1 ? p1 + 1: NULL) + { + p1 = strchr (p, ':'); + if (p1 != NULL) + len = p1 - p; + else + len = strlen (p); + strncpy (tryname, p, len); + tryname[len] = '\0'; + strcat (tryname, "/"); + strcat (tryname, shell_file); + if (access (tryname, X_OK) < 0) + continue; + if (stat (tryname, &statbuf) < 0) + continue; + if (!S_ISREG (statbuf.st_mode)) + /* We certainly need to reject directories. I'm not quite + as sure about FIFOs, sockets, etc., but I kind of doubt + that people want to exec() these things. */ + continue; + break; + } + if (p == NULL) + /* Not found. This must be an error rather than merely passing + the file to execlp(), because execlp() would try all the + exec()s, causing GDB to get confused. */ + error ("Can't find shell %s in PATH", shell_file); + + shell_file = tryname; + } + + fork_inferior (exec_file, allargs, env, + proc_set_exec_trap, procfs_init_inferior, shell_file); + + /* We are at the first instruction we care about. */ + /* Pedal to the metal... */ + + /* Setup traps on exit from sproc() */ + +#ifdef SYS_sproc + procfs_set_sproc_trap (current_procinfo); +#endif + + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); +} + +/* Clean up after the inferior dies. */ + +static void +procfs_mourn_inferior () +{ + struct procinfo *pi; + struct procinfo *next_pi; + + for (pi = procinfo_list; pi; pi = next_pi) + { + next_pi = pi->next; + unconditionally_kill_inferior (pi); + } + + unpush_target (&procfs_ops); + generic_mourn_inferior (); +} + + +/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ +static int +procfs_can_run () +{ + return(1); +} +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS + +/* Insert a watchpoint */ +int +procfs_set_watchpoint(pid, addr, len, rw) + int pid; + CORE_ADDR addr; + int len; + int rw; +{ + struct procinfo *pi; + prwatch_t wpt; + + pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0); + wpt.pr_vaddr = (caddr_t)addr; + wpt.pr_size = len; + wpt.pr_wflags = ((rw & 1) ? MA_READ : 0) | ((rw & 2) ? MA_WRITE : 0); + if (ioctl (pi->fd, PIOCSWATCH, &wpt) < 0) + { + if (errno == E2BIG) + return -1; + /* Currently it sometimes happens that the same watchpoint gets + deleted twice - don't die in this case (FIXME please) */ + if (errno == ESRCH && len == 0) + return 0; + print_sys_errmsg (pi->pathname, errno); + error ("PIOCSWATCH failed"); + } + return 0; +} + +int +procfs_stopped_by_watchpoint(pid) + int pid; +{ + struct procinfo *pi; + short what; + short why; + + pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0); + if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) + { + why = pi->prstatus.pr_why; + what = pi->prstatus.pr_what; + if (why == PR_FAULTED +#if defined (FLTWATCH) && defined (FLTKWATCH) + && (what == FLTWATCH || what == FLTKWATCH) +#else +#ifdef FLTWATCH + && (what == FLTWATCH) +#endif +#ifdef FLTKWATCH + && (what == FLTKWATCH) +#endif +#endif + ) + return what; + } + return 0; +} +#endif + +/* Send a SIGINT to the process group. This acts just like the user typed a + ^C on the controlling terminal. + + XXX - This may not be correct for all systems. Some may want to use + killpg() instead of kill (-pgrp). */ + +void +procfs_stop () +{ + extern pid_t inferior_process_group; + + kill (-inferior_process_group, SIGINT); +} + + +struct target_ops procfs_ops = { + "procfs", /* to_shortname */ + "Unix /proc child process", /* to_longname */ + "Unix /proc child process (started by the \"run\" command).", /* to_doc */ + procfs_open, /* to_open */ + 0, /* to_close */ + procfs_attach, /* to_attach */ + procfs_detach, /* to_detach */ + procfs_resume, /* to_resume */ + procfs_wait, /* to_wait */ + procfs_fetch_registers, /* to_fetch_registers */ + procfs_store_registers, /* to_store_registers */ + procfs_prepare_to_store, /* to_prepare_to_store */ + procfs_xfer_memory, /* to_xfer_memory */ + procfs_files_info, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + terminal_init_inferior, /* to_terminal_init */ + terminal_inferior, /* to_terminal_inferior */ + terminal_ours_for_output, /* to_terminal_ours_for_output */ + terminal_ours, /* to_terminal_ours */ + child_terminal_info, /* to_terminal_info */ + procfs_kill_inferior, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + procfs_create_inferior, /* to_create_inferior */ + procfs_mourn_inferior, /* to_mourn_inferior */ + procfs_can_run, /* to_can_run */ + procfs_notice_signals, /* to_notice_signals */ + 0, /* to_thread_alive */ + procfs_stop, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_procfs () +{ +#ifdef HAVE_OPTIONAL_PROC_FS + char procname[32]; + int fd; + + /* If we have an optional /proc filesystem (e.g. under OSF/1), + don't add procfs support if we cannot access the running + GDB via /proc. */ + sprintf (procname, PROC_NAME_FMT, getpid ()); + if ((fd = open (procname, O_RDONLY)) < 0) + return; + close (fd); +#endif + + add_target (&procfs_ops); + + add_info ("proc", info_proc, +"Show process status information using /proc entry.\n\ +Specify process id or use current inferior by default.\n\ +Specify keywords for detailed information; default is summary.\n\ +Keywords are: `all', `faults', `flags', `id', `mappings', `signals',\n\ +`status', `syscalls', and `times'.\n\ +Unambiguous abbreviations may be used."); + + init_syscall_table (); +} diff --git a/contrib/gdb/gdb/ptx4-nat.c b/contrib/gdb/gdb/ptx4-nat.c new file mode 100644 index 000000000000..564b79917284 --- /dev/null +++ b/contrib/gdb/gdb/ptx4-nat.c @@ -0,0 +1,209 @@ +/* Native-dependent code for ptx 4.0 + Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include +#include +#include +#include + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + supply_register(EAX_REGNUM, (char *)&(*gregsetp)[EAX]); + supply_register(EDX_REGNUM, (char *)&(*gregsetp)[EDX]); + supply_register(ECX_REGNUM, (char *)&(*gregsetp)[ECX]); + supply_register(EBX_REGNUM, (char *)&(*gregsetp)[EBX]); + supply_register(ESI_REGNUM, (char *)&(*gregsetp)[ESI]); + supply_register(EDI_REGNUM, (char *)&(*gregsetp)[EDI]); + supply_register(ESP_REGNUM, (char *)&(*gregsetp)[UESP]); + supply_register(EBP_REGNUM, (char *)&(*gregsetp)[EBP]); + supply_register(EIP_REGNUM, (char *)&(*gregsetp)[EIP]); + supply_register(EFLAGS_REGNUM, (char *)&(*gregsetp)[EFL]); +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + int regi; + extern char registers[]; + + for (regi = 0 ; regi < NUM_REGS ; regi++) + { + if ((regno == -1) || (regno == regi)) + { + (*gregsetp)[regi] = *(greg_t *)®isters[REGISTER_BYTE (regi)]; + } + } +} + +#if defined (FP0_REGNUM) + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), unpack the register contents and supply them as gdb's + idea of the current floating point register values. */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + supply_fpu_registers((struct fpusave *)&fpregsetp->fp_reg_set); + supply_fpa_registers((struct fpasave *)&fpregsetp->f_wregs); +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), update the register specified by REGNO from gdb's idea + of the current floating point register set. If REGNO is -1, update + them all. */ + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + int regi; + char *to; + char *from; + extern char registers[]; + + /* FIXME: see m68k-tdep.c for an example, for the m68k. */ +} + +#endif /* defined (FP0_REGNUM) */ + +/* + * This doesn't quite do the same thing as the procfs.c version, but give + * it the same name so we don't have to put an ifdef in solib.c. + */ +/* this could use elf_interpreter() from elfread.c */ +int +proc_iterate_over_mappings(func) + int (*func) PARAMS ((int, CORE_ADDR)); +{ + vaddr_t curseg, memptr; + pt_vseg_t pv; + int rv, cmperr; + sec_ptr interp_sec; + char *interp_content; + int interp_fd, funcstat; + unsigned int size; + char buf1[NBPG], buf2[NBPG]; + + /* + * The following is really vile. We can get the name of the + * shared library from the exec_bfd, and we can get a list of + * each virtual memory segment, but there is no simple way to + * find the mapped segment from the shared library (ala + * procfs's PIOCOPENMEM). As a pretty nasty kludge, we + * compare the virtual memory segment to the contents of the + * .interp file. If they match, we assume that we've got the + * right one. + */ + + /* + * TODO: for attach, use XPT_OPENT to get the executable, in + * case we're attached without knowning the executable's + * filename. + */ + +#ifdef VERBOSE_DEBUG + printf("proc_iter\n"); +#endif + interp_sec = bfd_get_section_by_name(exec_bfd, ".interp"); + if (!interp_sec) { + return 0; + } + + size = bfd_section_size(exec_bfd, interp_sec); + interp_content = alloca(size); + if (0 == bfd_get_section_contents(exec_bfd, interp_sec, + interp_content, (file_ptr)0, size)) { + return 0; + } + +#ifdef VERBOSE_DEBUG + printf("proc_iter: \"%s\"\n", interp_content); +#endif + interp_fd = open(interp_content, O_RDONLY, 0); + if (-1 == interp_fd) { + return 0; + } + + curseg = 0; + while (1) { + rv = ptrace(PT_NEXT_VSEG, inferior_pid, &pv, curseg); +#ifdef VERBOSE_DEBUG + printf("PT_NEXT_VSEG: rv %d errno %d\n", rv, errno); +#endif + if (-1 == rv) + break; + if (0 == rv) + break; +#ifdef VERBOSE_DEBUG + printf("pv.pv_start 0x%x pv_size 0x%x pv_prot 0x%x\n", + pv.pv_start, pv.pv_size, pv.pv_prot); +#endif + curseg = pv.pv_start + pv.pv_size; + + rv = lseek(interp_fd, 0, SEEK_SET); + if (-1 == rv) { + perror("lseek"); + close(interp_fd); + return 0; + } + for (memptr = pv.pv_start; memptr < pv.pv_start + pv.pv_size; + memptr += NBPG) { +#ifdef VERBOSE_DEBUG + printf("memptr 0x%x\n", memptr); +#endif + rv = read(interp_fd, buf1, NBPG); + if (-1 == rv) { + perror("read"); + close(interp_fd); + return 0; + } + rv = ptrace(PT_RDATA_PAGE, inferior_pid, buf2, + memptr); + if (-1 == rv) { + perror("ptrace"); + close(interp_fd); + return 0; + } + cmperr = memcmp(buf1, buf2, NBPG); + if (cmperr) + break; + } + if (0 == cmperr) { + /* this is it */ + funcstat = (*func)(interp_fd, pv.pv_start); + break; + } + } + close(interp_fd); + return 0; +} diff --git a/contrib/gdb/gdb/pyr-tdep.c b/contrib/gdb/gdb/pyr-tdep.c new file mode 100644 index 000000000000..b9abc0f581c0 --- /dev/null +++ b/contrib/gdb/gdb/pyr-tdep.c @@ -0,0 +1,452 @@ +/* Pyramid target-dependent code for GDB. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +/*** Prettier register printing. ***/ + +/* Print registers in the same format as pyramid's dbx, adb, sdb. */ +pyr_print_registers(reg_buf, regnum) + long *reg_buf[]; +{ + register int regno; + int usp, ksp; + struct user u; + + for (regno = 0; regno < 16; regno++) { + printf_unfiltered/*_filtered*/ ("%6.6s: %8x %6.6s: %8x %6s: %8x %6s: %8x\n", + reg_names[regno], reg_buf[regno], + reg_names[regno+16], reg_buf[regno+16], + reg_names[regno+32], reg_buf[regno+32], + reg_names[regno+48], reg_buf[regno+48]); + } + usp = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) ((char *)&u.u_pcb.pcb_usp) - + ((char *)&u), 0); + ksp = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) ((char *)&u.u_pcb.pcb_ksp) - + ((char *)&u), 0); + printf_unfiltered/*_filtered*/ ("\n%6.6s: %8x %6.6s: %8x (%08x) %6.6s %8x\n", + reg_names[CSP_REGNUM],reg_buf[CSP_REGNUM], + reg_names[KSP_REGNUM], reg_buf[KSP_REGNUM], ksp, + "usp", usp); +} + +/* Print the register regnum, or all registers if regnum is -1. + fpregs is currently ignored. */ + +pyr_do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + /* On a pyr, we know a virtual register can always fit in an long. + Here (and elsewhere) we take advantage of that. Yuk. */ + long raw_regs[MAX_REGISTER_RAW_SIZE*NUM_REGS]; + register int i; + + for (i = 0 ; i < 64 ; i++) { + read_relative_register_raw_bytes(i, raw_regs+i); + } + if (regnum == -1) + pyr_print_registers (raw_regs, regnum); + else + for (i = 0; i < NUM_REGS; i++) + if (i == regnum) { + long val = raw_regs[i]; + + fputs_filtered (reg_names[i], stdout); + printf_filtered(":"); + print_spaces_filtered (6 - strlen (reg_names[i]), stdout); + if (val == 0) + printf_filtered ("0"); + else + printf_filtered ("%s %d", local_hex_string_custom(val,"08"), val); + printf_filtered("\n"); + } +} + +/*** Debugging editions of various macros from m-pyr.h ****/ + +CORE_ADDR frame_locals_address (frame) + struct frame_info *frame; +{ + register int addr = find_saved_register (frame,CFP_REGNUM); + register int result = read_memory_integer (addr, 4); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + fprintf_unfiltered (stderr, + "\t[[..frame_locals:%8x, %s= %x @%x fcfp= %x foo= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n", + frame->frame, + reg_names[CFP_REGNUM], + result, addr, + frame->frame_cfp, (CFP_REGNUM), + + + read_register(13), read_register(29), read_register(61), + find_saved_register(frame, 61)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + /* FIXME: I thought read_register (CFP_REGNUM) should be the right answer; + or at least CFP_REGNUM relative to FRAME (ie, result). + There seems to be a bug in the way the innermost frame is set up. */ + + return ((frame->next) ? result: frame->frame_cfp); +} + +CORE_ADDR frame_args_addr (frame) + struct frame_info *frame; +{ + register int addr = find_saved_register (frame,CFP_REGNUM); + register int result = read_memory_integer (addr, 4); + +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + fprintf_unfiltered (stderr, + "\t[[..frame_args:%8x, %s= %x @%x fcfp= %x r_r= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n", + frame->frame, + reg_names[CFP_REGNUM], + result, addr, + frame->frame_cfp, read_register(CFP_REGNUM), + + read_register(13), read_register(29), read_register(61), + find_saved_register(frame, 61)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + /* FIXME: I thought read_register (CFP_REGNUM) should be the right answer; + or at least CFP_REGNUM relative to FRAME (ie, result). + There seems to be a bug in the way the innermost frame is set up. */ + return ((frame->next) ? result: frame->frame_cfp); +} + +#include "symtab.h" +#include "opcode/pyr.h" +#include "gdbcore.h" + + +/* A couple of functions used for debugging frame-handling on + Pyramids. (The Pyramid-dependent handling of register values for + windowed registers is known to be buggy.) + + When debugging, these functions can supplant the normal definitions of some + of the macros in tm-pyramid.h The quantity of information produced + when these functions are used makes the gdb unusable as a + debugger for user programs. */ + +extern unsigned pyr_saved_pc(), pyr_frame_chain(); + +CORE_ADDR pyr_frame_chain(frame) + CORE_ADDR frame; +{ + int foo=frame - CONTROL_STACK_FRAME_SIZE; + /* printf_unfiltered ("...following chain from %x: got %x\n", frame, foo);*/ + return foo; +} + +CORE_ADDR pyr_saved_pc(frame) + CORE_ADDR frame; +{ + int foo=0; + foo = read_memory_integer (((CORE_ADDR)(frame))+60, 4); + printf_unfiltered ("..reading pc from frame 0x%0x+%d regs: got %0x\n", + frame, 60/4, foo); + return foo; +} + +/* Pyramid instructions are never longer than this many bytes. */ +#define MAXLEN 24 + +/* Number of elements in the opcode table. */ +/*const*/ static int nopcodes = (sizeof (pyr_opcodes) / sizeof( pyr_opcodes[0])); +#define NOPCODES (nopcodes) + +/* Let's be byte-independent so we can use this as a cross-assembler. */ + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + +/* Print one instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +pyr_print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i, nargs, insn_size =4; + register unsigned char *p; + register char *d; + register int insn_opcode, operand_mode; + register int index_multiplier, index_reg_regno, op_1_regno, op_2_regno ; + long insn; /* first word of the insn, not broken down. */ + pyr_insn_format insn_decode; /* the same, broken out into op{code,erands} */ + long extra_1, extra_2; + + read_memory (memaddr, buffer, MAXLEN); + insn_decode = *((pyr_insn_format *) buffer); + insn = * ((int *) buffer); + insn_opcode = insn_decode.operator; + operand_mode = insn_decode.mode; + index_multiplier = insn_decode.index_scale; + index_reg_regno = insn_decode.index_reg; + op_1_regno = insn_decode.operand_1; + op_2_regno = insn_decode.operand_2; + + + if (*((int *)buffer) == 0x0) { + /* "halt" looks just like an invalid "jump" to the insn decoder, + so is dealt with as a special case */ + fprintf_unfiltered (stream, "halt"); + return (4); + } + + for (i = 0; i < NOPCODES; i++) + if (pyr_opcodes[i].datum.code == insn_opcode) + break; + + if (i == NOPCODES) + /* FIXME: Handle unrecognised instructions better. */ + fprintf_unfiltered (stream, "???\t#%08x\t(op=%x mode =%x)", + insn, insn_decode.operator, insn_decode.mode); + else + { + /* Print the mnemonic for the instruction. Pyramid insn operands + are so regular that we can deal with almost all of them + separately. + Unconditional branches are an exception: they are encoded as + conditional branches (branch if false condition, I think) + with no condition specified. The average user will not be + aware of this. To maintain their illusion that an + unconditional branch insn exists, we will have to FIXME to + treat the insn mnemnonic of all branch instructions here as a + special case: check the operands of branch insn and print an + appropriate mnemonic. */ + + fprintf_unfiltered (stream, "%s\t", pyr_opcodes[i].name); + + /* Print the operands of the insn (as specified in + insn.operand_mode). + Branch operands of branches are a special case: they are a word + offset, not a byte offset. */ + + if (insn_decode.operator == 0x01 || insn_decode.operator == 0x02) { + register int bit_codes=(insn >> 16)&0xf; + register int i; + register int displacement = (insn & 0x0000ffff) << 2; + + static char cc_bit_names[] = "cvzn"; /* z,n,c,v: strange order? */ + + /* Is bfc and no bits specified an unconditional branch?*/ + for (i=0;i<4;i++) { + if ((bit_codes) & 0x1) + fputc_unfiltered (cc_bit_names[i], stream); + bit_codes >>= 1; + } + + fprintf_unfiltered (stream, ",%0x", + displacement + memaddr); + return (insn_size); + } + + switch (operand_mode) { + case 0: + fprintf_unfiltered (stream, "%s,%s", + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + case 1: + fprintf_unfiltered (stream, " 0x%0x,%s", + op_1_regno, + reg_names [op_2_regno]); + break; + + case 2: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, " $0x%0x,%s", + extra_1, + reg_names [op_2_regno]); + break; + case 3: + fprintf_unfiltered (stream, " (%s),%s", + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + case 4: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, " 0x%0x(%s),%s", + extra_1, + reg_names [op_1_regno], + reg_names [op_2_regno]); + break; + + /* S1 destination mode */ + case 5: + fprintf_unfiltered (stream, + ((index_reg_regno) ? "%s,(%s)[%s*%1d]" : "%s,(%s)"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 6: + fprintf_unfiltered (stream, + ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" + : " $%#0x,(%s)"), + op_1_regno, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 7: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" + : " $%#0x,(%s)"), + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 8: + fprintf_unfiltered (stream, + ((index_reg_regno) ? " (%s),(%s)[%s*%1d]" : " (%s),(%s)"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 9: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) + ? "%#0x(%s),(%s)[%s*%1d]" + : "%#0x(%s),(%s)"), + extra_1, + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + /* S2 destination mode */ + case 10: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) ? "%s,%#0x(%s)[%s*%1d]" : "%s,%#0x(%s)"), + reg_names [op_1_regno], + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 11: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) ? + " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), + op_1_regno, + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 12: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + read_memory (memaddr+8, buffer, MAXLEN); + insn_size += 4; + extra_2 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) ? + " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), + extra_1, + extra_2, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + case 13: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) + ? " (%s),%#0x(%s)[%s*%1d]" + : " (%s),%#0x(%s)"), + reg_names [op_1_regno], + extra_1, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + case 14: + read_memory (memaddr+4, buffer, MAXLEN); + insn_size += 4; + extra_1 = * ((int *) buffer); + read_memory (memaddr+8, buffer, MAXLEN); + insn_size += 4; + extra_2 = * ((int *) buffer); + fprintf_unfiltered (stream, + ((index_reg_regno) ? "%#0x(%s),%#0x(%s)[%s*%1d]" + : "%#0x(%s),%#0x(%s) "), + extra_1, + reg_names [op_1_regno], + extra_2, + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + break; + + default: + fprintf_unfiltered (stream, + ((index_reg_regno) ? "%s,%s [%s*%1d]" : "%s,%s"), + reg_names [op_1_regno], + reg_names [op_2_regno], + reg_names [index_reg_regno], + index_multiplier); + fprintf_unfiltered (stream, + "\t\t# unknown mode in %08x", + insn); + break; + } /* switch */ + } + + { + return insn_size; + } + abort (); +} diff --git a/contrib/gdb/gdb/pyr-xdep.c b/contrib/gdb/gdb/pyr-xdep.c new file mode 100644 index 000000000000..e205b50a87d1 --- /dev/null +++ b/contrib/gdb/gdb/pyr-xdep.c @@ -0,0 +1,370 @@ +/* Low level Pyramid interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +/* #include Can we live without this? */ + +#include "gdbcore.h" +#include /* After a.out.h */ +#include +#include "gdb_stat.h" + + +void +fetch_inferior_registers (regno) + int regno; +{ + register int datum; + register unsigned int regaddr; + int reg_buf[NUM_REGS+1]; + struct user u; + register int skipped_frames = 0; + + registers_fetched (); + + for (regno = 0; regno < 64; regno++) { + reg_buf[regno] = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) regno, 0); + +#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf_unfiltered ("Fetching register %s, got %0x\n", + reg_names[regno], + reg_buf[regno]); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + + if (reg_buf[regno] == -1 && errno == EIO) { + printf_unfiltered("fetch_interior_registers: fetching register %s\n", + reg_names[regno]); + errno = 0; + } + supply_register (regno, reg_buf+regno); + } + /* that leaves regs 64, 65, and 66 */ + datum = ptrace (3, inferior_pid, + (PTRACE_ARG3_TYPE) (((char *)&u.u_pcb.pcb_csp) - + ((char *)&u)), 0); + + + + /* FIXME: Find the Current Frame Pointer (CFP). CFP is a global + register (ie, NOT windowed), that gets saved in a frame iff + the code for that frame has a prologue (ie, "adsf N"). If + there is a prologue, the adsf insn saves the old cfp in + pr13, cfp is set to sp, and N bytes of locals are allocated + (sp is decremented by n). + This makes finding CFP hard. I guess the right way to do it + is: + - If this is the innermost frame, believe ptrace() or + the core area. + - Otherwise: + Find the first insn of the current frame. + - find the saved pc; + - find the call insn that saved it; + - figure out where the call is to; + - if the first insn is an adsf, we got a frame + pointer. */ + + + /* Normal processors have separate stack pointers for user and + kernel mode. Getting the last user mode frame on such + machines is easy: the kernel context of the ptrace()'d + process is on the kernel stack, and the USP points to what + we want. But Pyramids only have a single cfp for both user and + kernel mode. And processes being ptrace()'d have some + kernel-context control frames on their stack. + To avoid tracing back into the kernel context of an inferior, + we skip 0 or more contiguous control frames where the pc is + in the kernel. */ + + while (1) { + register int inferior_saved_pc; + inferior_saved_pc = ptrace (1, inferior_pid, + (PTRACE_ARG3_TYPE) (datum+((32+15)*4)), 0); + if (inferior_saved_pc > 0) break; +#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf_unfiltered("skipping kernel frame %08x, pc=%08x\n", datum, + inferior_saved_pc); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + skipped_frames++; + datum -= CONTROL_STACK_FRAME_SIZE; + } + + reg_buf[CSP_REGNUM] = datum; + supply_register(CSP_REGNUM, reg_buf+CSP_REGNUM); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + if (skipped_frames) { + fprintf_unfiltered (stderr, + "skipped %d frames from %x to %x; cfp was %x, now %x\n", + skipped_frames, reg_buf[CSP_REGNUM]); + } +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + if (regno >= 0) + { + if ((0 <= regno) && (regno < 64)) { + /*regaddr = register_addr (regno, offset);*/ + regaddr = regno; + errno = 0; + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + /*regaddr = register_addr (regno, offset);*/ + regaddr = regno; + errno = 0; + ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } +} + +/*** Extensions to core and dump files, for GDB. */ + +extern unsigned int last_frame_offset; + +#ifdef PYRAMID_CORE + +/* Can't make definitions here static, since corefile.c needs them + to do bounds checking on the core-file areas. O well. */ + +/* have two stacks: one for data, one for register windows. */ +extern CORE_ADDR reg_stack_start; +extern CORE_ADDR reg_stack_end; + +/* need this so we can find the global registers: they never get saved. */ +CORE_ADDR global_reg_offset; +static CORE_ADDR last_frame_address; +CORE_ADDR last_frame_offset; + + +/* Address in core file of start of register window stack area. + Don't know if is this any of meaningful, useful or necessary. */ +extern int reg_stack_offset; + +#endif /* PYRAMID_CORE */ + + +/* Work with core dump and executable files, for GDB. + This code would be in corefile.c if it weren't machine-dependent. */ + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + +#ifdef PYRAMID_CORE + reg_stack_start = CONTROL_STACK_ADDR; + reg_stack_end = CONTROL_STACK_ADDR; /* this isn't strictly true...*/ +#endif /* PYRAMID_CORE */ + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the program with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* find registers in core file */ +#ifdef PYRAMID_PTRACE + stack_start = stack_end - NBPG * u.u_ussize; + reg_stack_offset = stack_offset + (NBPG *u.u_ussize); + reg_stack_end = reg_stack_start + NBPG * u.u_cssize; + + last_frame_address = ((int) u.u_pcb.pcb_csp); + last_frame_offset = reg_stack_offset + last_frame_address + - CONTROL_STACK_ADDR ; + global_reg_offset = (char *)&u - (char *)&u.u_pcb.pcb_gr0 ; + + /* skip any control-stack frames that were executed in the + kernel. */ + + while (1) { + char buf[4]; + val = lseek (corechan, last_frame_offset+(47*4), 0); + if (val < 0) + perror_with_name (filename); + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + + if (*(int *)buf >= 0) + break; + printf_unfiltered ("skipping frame %s\n", local_hex_string (last_frame_address)); + last_frame_offset -= CONTROL_STACK_FRAME_SIZE; + last_frame_address -= CONTROL_STACK_FRAME_SIZE; + } + reg_offset = last_frame_offset; + +#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf_unfiltered ("Control stack pointer = %s\n", + local_hex_string (u.u_pcb.pcb_csp)); + printf_unfiltered ("offset to control stack %d outermost frame %d (%s)\n", + reg_stack_offset, reg_offset, local_hex_string (last_frame_address)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + +#else /* not PYRAMID_CORE */ + stack_start = stack_end - NBPG * u.u_ssize; + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +#endif /* not PYRAMID_CORE */ + +#ifdef __not_on_pyr_yet + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; +#endif + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + N_SET_MAGIC (core_aouthdr, 0); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < 64; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + if (val < 0) + perror_with_name (filename); +#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING + printf_unfiltered ("[reg %s(%d), offset in file %s=0x%0x, addr =0x%0x, =%0x]\n", + reg_names[regno], regno, filename, + register_addr(regno, reg_offset), + regno * 4 + last_frame_address, + *((int *)buf)); +#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */ + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename, NULL); + } + +#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING) + printf_unfiltered ("Providing CSP (%s) as nominal address of current frame.\n", + local_hex_string(last_frame_address)); +#endif PYRAMID_CONTROL_FRAME_DEBUGGING + /* FIXME: Which of the following is correct? */ +#if 0 + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +#else + set_current_frame ( create_new_frame (last_frame_address, + read_pc ())); +#endif + + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf_unfiltered ("No core file now.\n"); +} diff --git a/contrib/gdb/gdb/remote-adapt.c b/contrib/gdb/gdb/remote-adapt.c new file mode 100644 index 000000000000..8fcb1f70ac98 --- /dev/null +++ b/contrib/gdb/gdb/remote-adapt.c @@ -0,0 +1,1359 @@ +/* Remote debugging interface for AMD 290*0 Adapt Monitor Version 2.1d18. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by David Wood at New York University (wood@lab.ultra.nyu.edu). + Adapted from work done at Cygnus Support in remote-eb.c. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is like remote.c but is for an esoteric situation-- + having a 29k board attached to an Adapt inline monitor. + The monitor is connected via serial line to a unix machine + running gdb. + + 3/91 - developed on Sun3 OS 4.1, by David Wood + o - I can't get binary coff to load. + o - I can't get 19200 baud rate to work. + 7/91 o - Freeze mode tracing can be done on a 29050. */ + +#include "defs.h" +#include "gdb_string.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include +#include +#include +#include +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" + +/* External data declarations */ +extern int stop_soon_quietly; /* for wait_for_inferior */ + +/* Forward data declarations */ +extern struct target_ops adapt_ops; /* Forward declaration */ + +/* Forward function declarations */ +static void adapt_fetch_registers (); +static void adapt_store_registers (); +static void adapt_close (); +static int adapt_clear_breakpoints(); + +#define FREEZE_MODE (read_register(CPS_REGNUM) && 0x400) +#define USE_SHADOW_PC ((processor_type == a29k_freeze_mode) && FREEZE_MODE) + +/* Can't seem to get binary coff working */ +#define ASCII_COFF /* Adapt will be downloaded with ascii coff */ + +/* FIXME: Replace with `set remotedebug'. */ +#define LOG_FILE "adapt.log" +#if defined (LOG_FILE) +FILE *log_file=NULL; +#endif + +static int timeout = 5; +static char *dev_name; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + adapt_open knows that we don't have a file open when the program + starts. */ +int adapt_desc = -1; + +/* stream which is fdopen'd from adapt_desc. Only valid when + adapt_desc != -1. */ +FILE *adapt_stream; + +#define ON 1 +#define OFF 0 +static void +rawmode(desc, turnon) +int desc; +int turnon; +{ + TERMINAL sg; + + if (desc < 0) + return; + + ioctl (desc, TIOCGETP, &sg); + + if (turnon) { +#ifdef HAVE_TERMIO + sg.c_lflag &= ~(ICANON); +#else + sg.sg_flags |= RAW; +#endif + } else { +#ifdef HAVE_TERMIO + sg.c_lflag |= ICANON; +#else + sg.sg_flags &= ~(RAW); +#endif + } + ioctl (desc, TIOCSETP, &sg); +} + +/* Suck up all the input from the adapt */ +slurp_input() +{ + char buf[8]; + +#ifdef HAVE_TERMIO + /* termio does the timeout for us. */ + while (read (adapt_desc, buf, 8) > 0); +#else + alarm (timeout); + while (read (adapt_desc, buf, 8) > 0); + alarm (0); +#endif +} + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ +static int +readchar () +{ + char buf; + + buf = '\0'; +#ifdef HAVE_TERMIO + /* termio does the timeout for us. */ + read (adapt_desc, &buf, 1); +#else + alarm (timeout); + if (read (adapt_desc, &buf, 1) < 0) + { + if (errno == EINTR) + error ("Timeout reading from remote system."); + else + perror_with_name ("remote"); + } + alarm (0); +#endif + + if (buf == '\0') + error ("Timeout reading from remote system."); +#if defined (LOG_FILE) + putc (buf & 0x7f, log_file); +#endif + return buf & 0x7f; +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +static void +expect (string) + char *string; +{ + char *p = string; + + fflush(adapt_stream); + immediate_quit = 1; + while (1) + { + if (readchar() == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + p = string; + } +} + +/* Keep discarding input until we see the adapt prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: adapt_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a adapt_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt () +{ +#if defined (LOG_FILE) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush (log_file); +#endif + fflush(adapt_stream); + expect ("\n# "); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + while (1) + { + ch = readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from adapt_desc and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Read a 32-bit hex word from the adapt, preceded by a space */ +static long +get_hex_word() +{ + long val; + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + return val; +} +/* Get N 32-bit hex words from remote, each preceded by a space + and put them in registers starting at REGNO. */ +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + while (n--) { + val = get_hex_word(); + supply_register(regno++,(char *) &val); + } +} +/* Called when SIGALRM signal sent due to alarm() timeout. */ +#ifndef HAVE_TERMIO + +#ifndef __STDC__ +# ifndef volatile +# define volatile /**/ +# endif +#endif +volatile int n_alarms; + +void +adapt_timer () +{ +#if 0 + if (kiodebug) + printf ("adapt_timer called\n"); +#endif + n_alarms++; +} +#endif + +/* malloc'd name of the program on the remote system. */ +static char *prog_name = NULL; + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to adapt_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +void +adapt_kill(arg,from_tty) +char *arg; +int from_tty; +{ + fprintf (adapt_stream, "K"); + fprintf (adapt_stream, "\r"); + expect_prompt (); +} +/* + * Download a file specified in 'args', to the adapt. + * FIXME: Assumes the file to download is a binary coff file. + */ +static void +adapt_load(args,fromtty) +char *args; +int fromtty; +{ + FILE *fp; + int n; + char buffer[1024]; + + if (!adapt_stream) { + printf_filtered("Adapt not open. Use 'target' command to open adapt\n"); + return; + } + + /* OK, now read in the file. Y=read, C=COFF, T=dTe port + 0=start address. */ + +#ifdef ASCII_COFF /* Ascii coff */ + fprintf (adapt_stream, "YA T,0\r"); + fflush(adapt_stream); /* Just in case */ + /* FIXME: should check args for only 1 argument */ + sprintf(buffer,"cat %s | btoa > /tmp/#adapt-btoa",args); + system(buffer); + fp = fopen("/tmp/#adapt-btoa","r"); + rawmode(adapt_desc,OFF); + while (n=fread(buffer,1,1024,fp)) { + do { n -= write(adapt_desc,buffer,n); } while (n>0); + if (n<0) { perror("writing ascii coff"); break; } + } + fclose(fp); + rawmode(adapt_desc,ON); + system("rm /tmp/#adapt-btoa"); +#else /* Binary coff - can't get it to work .*/ + fprintf (adapt_stream, "YC T,0\r"); + fflush(adapt_stream); /* Just in case */ + if (!(fp = fopen(args,"r"))) { + printf_filtered("Can't open %s\n",args); + return; + } + while (n=fread(buffer,1,512,fp)) { + do { n -= write(adapt_desc,buffer,n); } while (n>0); + if (n<0) { perror("writing ascii coff"); break; } + } + fclose(fp); +#endif + expect_prompt (); /* Skip garbage that comes out */ + fprintf (adapt_stream, "\r"); + expect_prompt (); +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +adapt_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error ("Can't pass arguments to remote adapt process."); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + + if (adapt_stream) { + adapt_kill(NULL,NULL); + adapt_clear_breakpoints(); + init_wait_for_inferior (); + /* Clear the input because what the adapt sends back is different + * depending on whether it was running or not. + */ + slurp_input(); /* After this there should be a prompt */ + fprintf(adapt_stream,"\r"); + expect_prompt(); + printf_filtered("Do you want to download '%s' (y/n)? [y] : ",prog_name); + { + char buffer[10]; + gets(buffer); + if (*buffer != 'n') { + adapt_load(prog_name,0); + } + } + +#ifdef NOTDEF + /* Set the PC and wait for a go/cont */ + fprintf (adapt_stream, "G %x,N\r",entry_pt); + printf_filtered("Now use the 'continue' command to start.\n"); + expect_prompt (); +#else + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed(entry_pt, TARGET_SIGNAL_DEFAULT, 0); +#endif + + } else { + printf_filtered("Adapt not open yet.\n"); + } +} + +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +#ifndef B19200 +#define B19200 EXTA +#endif +#ifndef B38400 +#define B38400 EXTB +#endif + +static struct {int rate, damn_b;} baudtab[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +static int damn_b (rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) return baudtab[i].damn_b; + return B38400; /* Random */ +} + + +/* Open a connection to a remote debugger. + NAME is the filename used for communication, then a space, + then the baud rate. + */ + +static int baudrate = 9600; +static void +adapt_open (name, from_tty) + char *name; + int from_tty; +{ + TERMINAL sg; + unsigned int prl; + char *p; + + /* Find the first whitespace character, it separates dev_name from + prog_name. */ + if (name == 0) + goto erroid; + + for (p = name; + *p != '\0' && !isspace (*p); p++) + ; + if (*p == '\0') +erroid: + error ("\ +Please include the name of the device for the serial port,\n\ +the baud rate, and the name of the program to run on the remote system."); + dev_name = (char*)xmalloc(p - name + 1); + strncpy (dev_name, name, p - name); + dev_name[p - name] = '\0'; + + /* Skip over the whitespace after dev_name */ + for (; isspace (*p); p++) + /*EMPTY*/; + + if (1 != sscanf (p, "%d ", &baudrate)) + goto erroid; + + /* Skip the number and then the spaces */ + for (; isdigit (*p); p++) + /*EMPTY*/; + for (; isspace (*p); p++) + /*EMPTY*/; + + if (prog_name != NULL) + free (prog_name); + prog_name = savestring (p, strlen (p)); + + adapt_close (0); + + adapt_desc = open (dev_name, O_RDWR); + if (adapt_desc < 0) + perror_with_name (dev_name); + ioctl (adapt_desc, TIOCGETP, &sg); +#ifdef HAVE_TERMIO + sg.c_cc[VMIN] = 0; /* read with timeout. */ + sg.c_cc[VTIME] = timeout * 10; + sg.c_lflag &= ~(ICANON | ECHO); + sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate); +#else + sg.sg_ispeed = damn_b (baudrate); + sg.sg_ospeed = damn_b (baudrate); + sg.sg_flags |= RAW | ANYP; + sg.sg_flags &= ~ECHO; +#endif + + ioctl (adapt_desc, TIOCSETP, &sg); + adapt_stream = fdopen (adapt_desc, "r+"); + + push_target (&adapt_ops); + +#ifndef HAVE_TERMIO +#ifndef NO_SIGINTERRUPT + /* Cause SIGALRM's to make reads fail with EINTR instead of resuming + the read. */ + if (siginterrupt (SIGALRM, 1) != 0) + perror ("adapt_open: error in siginterrupt"); +#endif + + /* Set up read timeout timer. */ + if ((void (*)) signal (SIGALRM, adapt_timer) == (void (*)) -1) + perror ("adapt_open: error in signal"); +#endif + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); +#endif + + /* Put this port into NORMAL mode, send the 'normal' character */ + write(adapt_desc, "", 1); /* Control A */ + write(adapt_desc, "\r", 1); + expect_prompt (); + + /* Hello? Are you there? */ + write (adapt_desc, "\r", 1); + + expect_prompt (); + + /* Clear any break points */ + adapt_clear_breakpoints(); + + /* Print out some stuff, letting the user now what's going on */ + printf_filtered("Connected to an Adapt via %s.\n", dev_name); + /* FIXME: can this restriction be removed? */ + printf_filtered("Remote debugging using virtual addresses works only\n"); + printf_filtered("\twhen virtual addresses map 1:1 to physical addresses.\n"); + if (processor_type != a29k_freeze_mode) { + fprintf_filtered(stderr, + "Freeze-mode debugging not available, and can only be done on an A29050.\n"); + } +} + +/* Close out all files and local state before this target loses control. */ + +static void +adapt_close (quitting) + int quitting; +{ + + /* Clear any break points */ + adapt_clear_breakpoints(); + + /* Put this port back into REMOTE mode */ + if (adapt_stream) { + fflush(adapt_stream); + sleep(1); /* Let any output make it all the way back */ + write(adapt_desc, "R\r", 2); + } + + /* Due to a bug in Unix, fclose closes not only the stdio stream, + but also the file descriptor. So we don't actually close + adapt_desc. */ + if (adapt_stream) + fclose (adapt_stream); /* This also closes adapt_desc */ + if (adapt_desc >= 0) + /* close (adapt_desc); */ + + /* Do not try to close adapt_desc again, later in the program. */ + adapt_stream = NULL; + adapt_desc = -1; + +#if defined (LOG_FILE) + if (log_file) { + if (ferror (log_file)) + printf_filtered ("Error writing log file.\n"); + if (fclose (log_file) != 0) + printf_filtered ("Error closing log file.\n"); + log_file = NULL; + } +#endif +} + +/* Attach to the target that is already loaded and possibly running */ +static void +adapt_attach (args, from_tty) + char *args; + int from_tty; +{ + + if (from_tty) + printf_filtered ("Attaching to remote program %s.\n", prog_name); + + /* Send the adapt a kill. It is ok if it is not already running */ + fprintf(adapt_stream, "K\r"); fflush(adapt_stream); + expect_prompt(); /* Slurp the echo */ +} + + +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +void +adapt_detach (args,from_tty) + char *args; + int from_tty; +{ + + if (adapt_stream) { /* Send it on its way (tell it to continue) */ + adapt_clear_breakpoints(); + fprintf(adapt_stream,"G\r"); + } + + pop_target(); /* calls adapt_close to do the real work */ + if (from_tty) + printf_filtered ("Ending remote %s debugging\n", target_shortname); +} + +/* Tell the remote machine to resume. */ + +void +adapt_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + if (step) + { + write (adapt_desc, "t 1,s\r", 6); + /* Wait for the echo. */ + expect ("t 1,s\r\n"); + /* Then comes a line containing the instruction we stepped to. */ + expect ("@"); + /* Then we get the prompt. */ + expect_prompt (); + + /* Force the next adapt_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type + "continue" to see any. FIXME, this should be fixed. */ + need_artificial_trap = 1; + } + else + { + write (adapt_desc, "G\r", 2); + /* Swallow the echo. */ + expect_prompt(); + } +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +int +adapt_wait (status) + struct target_waitstatus *status; +{ + /* Strings to look for. '?' means match any single character. + Note that with the algorithm we use, the initial character + of the string cannot recur in the string, or we will not + find some cases of the string in the input. */ + + static char bpt[] = "@"; + /* It would be tempting to look for "\n[__exit + 0x8]\n" + but that requires loading symbols with "yc i" and even if + we did do that we don't know that the file has symbols. */ + static char exitmsg[] = "@????????I JMPTI GR121,LR0"; + char *bp = bpt; + char *ep = exitmsg; + + /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */ + char swallowed[50]; + /* Current position in swallowed. */ + char *swallowed_p = swallowed; + + int ch; + int ch_handled; + int old_timeout = timeout; + int old_immediate_quit = immediate_quit; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + if (need_artificial_trap != 0) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + need_artificial_trap--; + return 0; + } + + timeout = 0; /* Don't time out -- user program is running. */ + immediate_quit = 1; /* Helps ability to QUIT */ + while (1) { + QUIT; /* Let user quit and leave process running */ + ch_handled = 0; + ch = readchar (); + if (ch == *bp) { + bp++; + if (*bp == '\0') + break; + ch_handled = 1; + + *swallowed_p++ = ch; + } else + bp = bpt; + if (ch == *ep || *ep == '?') { + ep++; + if (*ep == '\0') + break; + + if (!ch_handled) + *swallowed_p++ = ch; + ch_handled = 1; + } else + ep = exitmsg; + if (!ch_handled) { + char *p; + /* Print out any characters which have been swallowed. */ + for (p = swallowed; p < swallowed_p; ++p) + putc (*p, stdout); + swallowed_p = swallowed; + putc (ch, stdout); + } + } + expect_prompt (); + if (*bp== '\0') + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + } + else + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + } + timeout = old_timeout; + immediate_quit = old_immediate_quit; + return 0; +} + +/* Return the name of register number REGNO + in the form input and output by adapt. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char buf[80]; + if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32 ) + sprintf (buf, "GR%03d", regno - GR96_REGNUM + 96); +#if defined(GR64_REGNUM) + else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 ) + sprintf (buf, "GR%03d", regno - GR64_REGNUM + 64); +#endif + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + sprintf (buf, "LR%03d", regno - LR0_REGNUM); + else if (regno == Q_REGNUM) + strcpy (buf, "SR131"); + else if (regno >= BP_REGNUM && regno <= CR_REGNUM) + sprintf (buf, "SR%03d", regno - BP_REGNUM + 133); + else if (regno == ALU_REGNUM) + strcpy (buf, "SR132"); + else if (regno >= IPC_REGNUM && regno <= IPB_REGNUM) + sprintf (buf, "SR%03d", regno - IPC_REGNUM + 128); + else if (regno >= VAB_REGNUM && regno <= LRU_REGNUM) { + /* When a 29050 is in freeze-mode, read shadow pcs instead */ + if ((regno >= NPC_REGNUM && regno <= PC2_REGNUM) && USE_SHADOW_PC) + sprintf (buf, "SR%03d", regno - NPC_REGNUM + 20); + else + sprintf (buf, "SR%03d", regno - VAB_REGNUM); + } + else if (regno == GR1_REGNUM) + strcpy (buf, "GR001"); + return buf; +} + +/* Read the remote registers. */ + +static void +adapt_fetch_registers () +{ + int reg_index; + int regnum_index; + char tempbuf[10]; + int sreg_buf[16]; + int i,j; + +/* + * Global registers + */ +#if defined(GR64_REGNUM) + write (adapt_desc, "dw gr64,gr95\r", 13); + for (reg_index = 64, regnum_index = GR64_REGNUM; + reg_index < 96; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "GR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } +#endif + write (adapt_desc, "dw gr96,gr127\r", 14); + for (reg_index = 96, regnum_index = GR96_REGNUM; + reg_index < 128; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "GR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + +/* + * Local registers + */ + for (i = 0; i < 128; i += 32) + { + /* The PC has a tendency to hang if we get these + all in one fell swoop ("dw lr0,lr127"). */ + sprintf (tempbuf, "dw lr%d\r", i); + write (adapt_desc, tempbuf, strlen (tempbuf)); + for (reg_index = i, regnum_index = LR0_REGNUM + i; + reg_index < i + 32; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "LR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + } + +/* + * Special registers + */ + sprintf (tempbuf, "dw sr0\r"); + write (adapt_desc, tempbuf, strlen (tempbuf)); + for (i=0 ; i<4 ; i++) { /* SR0 - SR14 */ + sprintf (tempbuf, "SR%3d",i*4); + expect(tempbuf); + for (j=0 ; j < (i==3 ? 3 : 4) ; j++) + sreg_buf[i*4 + j] = get_hex_word(); + } + expect_prompt(); + /* + * Read the pcs individually if we are in freeze mode. + * See get_reg_name(), it translates the register names for the pcs to + * the names of the shadow pcs. + */ + if (USE_SHADOW_PC) { + sreg_buf[10] = read_register(NPC_REGNUM); /* pc0 */ + sreg_buf[11] = read_register(PC_REGNUM); /* pc1 */ + sreg_buf[12] = read_register(PC2_REGNUM); /* pc2 */ + } + for (i=0 ; i<14 ; i++) /* Supply vab -> lru */ + supply_register(VAB_REGNUM+i, (char *) &sreg_buf[i]); + sprintf (tempbuf, "dw sr128\r"); + write (adapt_desc, tempbuf, strlen (tempbuf)); + for (i=0 ; i<2 ; i++) { /* SR128 - SR135 */ + sprintf (tempbuf, "SR%3d",128 + i*4); + expect(tempbuf); + for (j=0 ; j<4 ; j++) + sreg_buf[i*4 + j] = get_hex_word(); + } + expect_prompt(); + supply_register(IPC_REGNUM,(char *) &sreg_buf[0]); + supply_register(IPA_REGNUM,(char *) &sreg_buf[1]); + supply_register(IPB_REGNUM,(char *) &sreg_buf[2]); + supply_register(Q_REGNUM, (char *) &sreg_buf[3]); + /* Skip ALU */ + supply_register(BP_REGNUM, (char *) &sreg_buf[5]); + supply_register(FC_REGNUM, (char *) &sreg_buf[6]); + supply_register(CR_REGNUM, (char *) &sreg_buf[7]); + + /* There doesn't seem to be any way to get these. */ + { + int val = -1; + supply_register (FPE_REGNUM, (char *) &val); + supply_register (INTE_REGNUM, (char *) &val); + supply_register (FPS_REGNUM, (char *) &val); + supply_register (EXO_REGNUM, (char *) &val); + } + + write (adapt_desc, "dw gr1,gr1\r", 11); + expect ("GR001 "); + get_hex_regs (1, GR1_REGNUM); + expect_prompt (); +} + +/* Fetch register REGNO, or all registers if REGNO is -1. + */ +static void +adapt_fetch_register (regno) + int regno; +{ + if (regno == -1) + adapt_fetch_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (adapt_stream, "dw %s,%s\r", name, name); + expect (name); + expect (" "); + get_hex_regs (1, regno); + expect_prompt (); + } +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +adapt_store_registers () +{ + int i, j; + + fprintf (adapt_stream, "s gr1,%x\r", read_register (GR1_REGNUM)); + expect_prompt (); + +#if defined(GR64_REGNUM) + for (j = 0; j < 32; j += 16) + { + fprintf (adapt_stream, "s gr%d,", j + 64); + for (i = 0; i < 15; ++i) + fprintf (adapt_stream, "%x,", read_register (GR64_REGNUM + j + i)); + fprintf (adapt_stream, "%x\r", read_register (GR64_REGNUM + j + 15)); + expect_prompt (); + } +#endif + for (j = 0; j < 32; j += 16) + { + fprintf (adapt_stream, "s gr%d,", j + 96); + for (i = 0; i < 15; ++i) + fprintf (adapt_stream, "%x,", read_register (GR96_REGNUM + j + i)); + fprintf (adapt_stream, "%x\r", read_register (GR96_REGNUM + j + 15)); + expect_prompt (); + } + + for (j = 0; j < 128; j += 16) + { + fprintf (adapt_stream, "s lr%d,", j); + for (i = 0; i < 15; ++i) + fprintf (adapt_stream, "%x,", read_register (LR0_REGNUM + j + i)); + fprintf (adapt_stream, "%x\r", read_register (LR0_REGNUM + j + 15)); + expect_prompt (); + } + + fprintf (adapt_stream, "s sr128,%x,%x,%x\r", read_register (IPC_REGNUM), + read_register (IPA_REGNUM), read_register (IPB_REGNUM)); + expect_prompt (); + fprintf (adapt_stream, "s sr133,%x,%x,%x\r", read_register (BP_REGNUM), + read_register (FC_REGNUM), read_register (CR_REGNUM)); + expect_prompt (); + fprintf (adapt_stream, "s sr131,%x\r", read_register (Q_REGNUM)); + expect_prompt (); + fprintf (adapt_stream, "s sr0,"); + for (i=0 ; i<7 ; ++i) + fprintf (adapt_stream, "%x,", read_register (VAB_REGNUM + i)); + expect_prompt (); + fprintf (adapt_stream, "s sr7,"); + for (i=7; i<14 ; ++i) + fprintf (adapt_stream, "%x,", read_register (VAB_REGNUM + i)); + expect_prompt (); +} + +/* Store register REGNO, or all if REGNO == -1. + Return errno value. */ +void +adapt_store_register (regno) + int regno; +{ + /* printf("adapt_store_register() called.\n"); fflush(stdout); /* */ + if (regno == -1) + adapt_store_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (adapt_stream, "s %s,%x\r", name, read_register (regno)); + /* Setting GR1 changes the numbers of all the locals, so + invalidate the register cache. Do this *after* calling + read_register, because we want read_register to return the + value that write_register has just stuffed into the registers + array, not the value of the register fetched from the + inferior. */ + if (regno == GR1_REGNUM) + registers_changed (); + expect_prompt (); + } +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +adapt_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static CORE_ADDR +translate_addr(addr) +CORE_ADDR addr; +{ +#if defined(KERNEL_DEBUGGING) + /* Check for a virtual address in the kernel */ + /* Assume physical address of ublock is in paddr_u register */ + if (addr >= UVADDR) { + /* PADDR_U register holds the physical address of the ublock */ + CORE_ADDR i = (CORE_ADDR)read_register(PADDR_U_REGNUM); + return(i + addr - (CORE_ADDR)UVADDR); + } else { + return(addr); + } +#else + return(addr); +#endif +} + + +/* FIXME! Merge these two. */ +int +adapt_xfer_inferior_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + + memaddr = translate_addr(memaddr); + + if (write) + return adapt_write_inferior_memory (memaddr, myaddr, len); + else + return adapt_read_inferior_memory (memaddr, myaddr, len); +} + +void +adapt_files_info () +{ + printf_filtered("\tAttached to %s at %d baud and running program %s\n", + dev_name, baudrate, prog_name); + printf_filtered("\ton an %s processor.\n", processor_name[processor_type]); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. + * sb/sh instructions don't work on unaligned addresses, when TU=1. + */ +int +adapt_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + unsigned int cps; + + /* Turn TU bit off so we can do 'sb' commands */ + cps = read_register(CPS_REGNUM); + if (cps & 0x00000800) + write_register(CPS_REGNUM,cps&~(0x00000800)); + + for (i = 0; i < len; i++) + { + if ((i % 16) == 0) + fprintf (adapt_stream, "sb %x,", memaddr + i); + if ((i % 16) == 15 || i == len - 1) + { + fprintf (adapt_stream, "%x\r", ((unsigned char *)myaddr)[i]); + expect_prompt (); + } + else + fprintf (adapt_stream, "%x,", ((unsigned char *)myaddr)[i]); + } + /* Restore the old value of cps if the TU bit was on */ + if (cps & 0x00000800) + write_register(CPS_REGNUM,cps); + return len; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +int +adapt_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + /* Number of bytes read so far. */ + int count; + + /* Starting address of this pass. */ + unsigned long startaddr; + + /* Number of bytes to read in this pass. */ + int len_this_pass; + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + adapt_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len to memaddr and gets 0. */ + /* However, something like + adapt_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + + if (((memaddr - 1) + len) < memaddr) + return EIO; + + startaddr = memaddr; + count = 0; + while (count < len) + { + len_this_pass = 16; + if ((startaddr % 16) != 0) + len_this_pass -= startaddr % 16; + if (len_this_pass > (len - count)) + len_this_pass = (len - count); + + fprintf (adapt_stream, "db %x,%x\r", startaddr, + (startaddr - 1) + len_this_pass); + +#ifdef NOTDEF /* Why do this */ + expect ("\n"); + /* Look for 8 hex digits. */ + i = 0; + while (1) + { + if (isxdigit (readchar ())) + ++i; + else + { + expect_prompt (); + error ("Hex digit expected from remote system."); + } + if (i >= 8) + break; + } +#endif /* NOTDEF */ + + expect (" "); + + for (i = 0; i < len_this_pass; i++) + get_hex_byte (&myaddr[count++]); + + expect_prompt (); + + startaddr += len_this_pass; + } + return count; +} + +#define MAX_BREAKS 8 +static int num_brkpts=0; +static int +adapt_insert_breakpoint(addr, save) +CORE_ADDR addr; +char *save; /* Throw away, let adapt save instructions */ +{ + if (num_brkpts < MAX_BREAKS) { + num_brkpts++; + fprintf (adapt_stream, "B %x", addr); + fprintf (adapt_stream, "\r"); + expect_prompt (); + return(0); /* Success */ + } else { + fprintf_filtered(stderr, + "Too many break points, break point not installed\n"); + return(1); /* Failure */ + } + +} +static int +adapt_remove_breakpoint(addr, save) +CORE_ADDR addr; +char *save; /* Throw away, let adapt save instructions */ +{ + if (num_brkpts > 0) { + num_brkpts--; + fprintf (adapt_stream, "BR %x", addr); + fprintf (adapt_stream, "\r"); + fflush (adapt_stream); + expect_prompt (); + } + return(0); +} + +/* Clear the adapts notion of what the break points are */ +static int +adapt_clear_breakpoints() +{ + if (adapt_stream) { + fprintf (adapt_stream, "BR"); /* Clear all break points */ + fprintf (adapt_stream, "\r"); + fflush(adapt_stream); + expect_prompt (); + } + num_brkpts = 0; +} +static void +adapt_mourn() +{ + adapt_clear_breakpoints(); + pop_target (); /* Pop back to no-child state */ + generic_mourn_inferior (); +} + +/* Display everthing we read in from the adapt until we match/see the + * specified string + */ +static int +display_until(str) +char *str; +{ + int i=0,j,c; + + while (c=readchar()) { + if (c==str[i]) { + i++; + if (i == strlen(str)) return; + } else { + if (i) { + for (j=0 ; j", class_obscure, adapt_com, + "Send a command to the AMD Adapt remote monitor."); +} diff --git a/contrib/gdb/gdb/remote-array.c b/contrib/gdb/gdb/remote-array.c new file mode 100644 index 000000000000..0ed84cade2c3 --- /dev/null +++ b/contrib/gdb/gdb/remote-array.c @@ -0,0 +1,1465 @@ +/* Remote debugging interface for Array Tech RAID controller.. + Copyright 90, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Rob Savoye for Cygnus. + + This module talks to a debug monitor called 'MONITOR', which + We communicate with MONITOR via either a direct serial line, or a TCP + (or possibly TELNET) stream to a terminal multiplexor, + which in turn talks to the target board. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "wait.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include +#include "gdb_string.h" +#include "command.h" +#include "serial.h" +#include "monitor.h" +#include "remote-utils.h" + +extern int baud_rate; + +#define ARRAY_PROMPT ">> " + +#define SWAP_TARGET_AND_HOST(buffer,len) \ + do \ + { \ + if (TARGET_BYTE_ORDER != HOST_BYTE_ORDER) \ + { \ + char tmp; \ + char *p = (char *)(buffer); \ + char *q = ((char *)(buffer)) + len - 1; \ + for (; p < q; p++, q--) \ + { \ + tmp = *q; \ + *q = *p; \ + *p = tmp; \ + } \ + } \ + } \ + while (0) + +static void debuglogs PARAMS((int, char *, ...)); +static void array_open(); +static void array_close(); +static void array_detach(); +static void array_attach(); +static void array_resume(); +static void array_fetch_register(); +static void array_store_register(); +static void array_fetch_registers(); +static void array_store_registers(); +static void array_prepare_to_store(); +static void array_files_info(); +static void array_kill(); +static void array_create_inferior(); +static void array_mourn_inferior(); +static void make_gdb_packet(); +static int array_xfer_memory(); +static int array_wait(); +static int array_insert_breakpoint(); +static int array_remove_breakpoint(); +static int tohex(); +static int to_hex(); +static int from_hex(); +static int array_send_packet(); +static int array_get_packet(); +static unsigned long ascii2hexword(); +static char *hexword2ascii(); + +extern char *version; + +#define LOG_FILE "monitor.log" +#if defined (LOG_FILE) +FILE *log_file; +#endif + +static int timeout = 30; +/* Having this larger than 400 causes us to be incompatible with m68k-stub.c + and i386-stub.c. Normally, no one would notice because it only matters + for writing large chunks of memory (e.g. in downloads). Also, this needs + to be more than 400 if required to hold the registers (see below, where + we round it up based on REGISTER_BYTES). */ +#define PBUFSIZ 400 + +/* + * Descriptor for I/O to remote machine. Initialize it to NULL so that + * array_open knows that we don't have a file open when the program starts. + */ +serial_t array_desc = NULL; + +/* + * this array of registers need to match the indexes used by GDB. The + * whole reason this exists is cause the various ROM monitors use + * different strings than GDB does, and doesn't support all the + * registers either. So, typing "info reg sp" becomes a "r30". + */ +extern char *tmp_mips_processor_type; +extern int mips_set_processor_type(); + +static struct target_ops array_ops = { + "array", /* to_shortname */ + /* to_longname */ + "Debug using the standard GDB remote protocol for the Array Tech target.", + /* to_doc */ + "Debug using the standard GDB remote protocol for the Array Tech target.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + array_open, /* to_open */ + array_close, /* to_close */ + NULL, /* to_attach */ + array_detach, /* to_detach */ + array_resume, /* to_resume */ + array_wait, /* to_wait */ + array_fetch_registers, /* to_fetch_registers */ + array_store_registers, /* to_store_registers */ + array_prepare_to_store, /* to_prepare_to_store */ + array_xfer_memory, /* to_xfer_memory */ + array_files_info, /* to_files_info */ + array_insert_breakpoint, /* to_insert_breakpoint */ + array_remove_breakpoint, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + array_kill, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + array_create_inferior, /* to_create_inferior */ + array_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +/* + * printf_monitor -- send data to monitor. Works just like printf. + */ +static void +#ifdef ANSI_PROTOTYPES +printf_monitor(char *pattern, ...) +#else +printf_monitor(va_alist) + va_dcl +#endif +{ + va_list args; + char buf[PBUFSIZ]; + int i; + +#ifdef ANSI_PROTOTYPES + va_start(args, pattern); +#else + char *pattern; + va_start(args); + pattern = va_arg(args, char *); +#endif + + vsprintf(buf, pattern, args); + + debuglogs (1, "printf_monitor(), Sending: \"%s\".", buf); + + if (strlen(buf) > PBUFSIZ) + error ("printf_monitor(): string too long"); + if (SERIAL_WRITE(array_desc, buf, strlen(buf))) + fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno)); +} +/* + * write_monitor -- send raw data to monitor. + */ +static void +write_monitor(data, len) + char data[]; + int len; +{ + if (SERIAL_WRITE(array_desc, data, len)) + fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno)); + + *(data + len+1) = '\0'; + debuglogs (1, "write_monitor(), Sending: \"%s\".", data); + +} + +/* + * debuglogs -- deal with debugging info to multiple sources. This takes + * two real args, the first one is the level to be compared against + * the sr_get_debug() value, the second arg is a printf buffer and args + * to be formatted and printed. A CR is added after each string is printed. + */ +static void +#ifdef ANSI_PROTOTYPES +debuglogs(int level, char *pattern, ...) +#else +debuglogs(va_alist) + va_dcl +#endif +{ + va_list args; + char *p; + unsigned char buf[PBUFSIZ]; + char newbuf[PBUFSIZ]; + int i; + +#ifdef ANSI_PROTOTYPES + va_start(args, pattern); +#else + char *pattern; + int level; + va_start(args); + level = va_arg(args, int); /* get the debug level */ + pattern = va_arg(args, char *); /* get the printf style pattern */ +#endif + + if ((level <0) || (level > 100)) { + error ("Bad argument passed to debuglogs(), needs debug level"); + return; + } + + vsprintf(buf, pattern, args); /* format the string */ + + /* convert some characters so it'll look right in the log */ + p = newbuf; + for (i = 0 ; buf[i] != '\0'; i++) { + if (i > PBUFSIZ) + error ("Debug message too long"); + switch (buf[i]) { + case '\n': /* newlines */ + *p++ = '\\'; + *p++ = 'n'; + continue; + case '\r': /* carriage returns */ + *p++ = '\\'; + *p++ = 'r'; + continue; + case '\033': /* escape */ + *p++ = '\\'; + *p++ = 'e'; + continue; + case '\t': /* tab */ + *p++ = '\\'; + *p++ = 't'; + continue; + case '\b': /* backspace */ + *p++ = '\\'; + *p++ = 'b'; + continue; + default: /* no change */ + *p++ = buf[i]; + } + + if (buf[i] < 26) { /* modify control characters */ + *p++ = '^'; + *p++ = buf[i] + 'A'; + continue; + } + if (buf[i] >= 128) { /* modify control characters */ + *p++ = '!'; + *p++ = buf[i] + 'A'; + continue; + } + } + *p = '\0'; /* terminate the string */ + + if (sr_get_debug() > level) + printf_unfiltered ("%s\n", newbuf); + +#ifdef LOG_FILE /* write to the monitor log */ + if (log_file != 0x0) { + fputs (newbuf, log_file); + fputc ('\n', log_file); + fflush (log_file); + } +#endif +} + +/* readchar -- read a character from the remote system, doing all the fancy + * timeout stuff. + */ +static int +readchar(timeout) + int timeout; +{ + int c; + + c = SERIAL_READCHAR(array_desc, abs(timeout)); + + if (sr_get_debug() > 5) { + putchar(c & 0x7f); + debuglogs (5, "readchar: timeout = %d\n", timeout); + } + +#ifdef LOG_FILE + if (isascii (c)) + putc(c & 0x7f, log_file); +#endif + + if (c >= 0) + return c & 0x7f; + + if (c == SERIAL_TIMEOUT) { + if (timeout <= 0) + return c; /* Polls shouldn't generate timeout errors */ + error("Timeout reading from remote system."); +#ifdef LOG_FILE + fputs ("ERROR: Timeout reading from remote system", log_file); +#endif + } + perror_with_name("readchar"); +} + +/* + * expect -- scan input from the remote system, until STRING is found. + * If DISCARD is non-zero, then discard non-matching input, else print + * it out. Let the user break out immediately. + */ +static void +expect (string, discard) + char *string; + int discard; +{ + char *p = string; + int c; + + + debuglogs (1, "Expecting \"%s\".", string); + + immediate_quit = 1; + while (1) { + c = readchar(timeout); + if (!isascii (c)) + continue; + if (c == *p++) { + if (*p == '\0') { + immediate_quit = 0; + debuglogs (4, "Matched"); + return; + } + } else { + if (!discard) { + fputc_unfiltered (c, gdb_stdout); + } + p = string; + } + } +} + +/* Keep discarding input until we see the MONITOR array_cmds->prompt. + + The convention for dealing with the expect_prompt is that you + o give your command + o *then* wait for the expect_prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: array_resume does not + wait for the expect_prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a array_wait which does wait for the expect_prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt(discard) + int discard; +{ + expect (ARRAY_PROMPT, discard); +} + +/* + * junk -- ignore junk characters. Returns a 1 if junk, 0 otherwise + */ +static int +junk(ch) + char ch; +{ + switch (ch) { + case '\0': + case ' ': + case '-': + case '\t': + case '\r': + case '\n': + if (sr_get_debug() > 5) + debuglogs (5, "Ignoring \'%c\'.", ch); + return 1; + default: + if (sr_get_debug() > 5) + debuglogs (5, "Accepting \'%c\'.", ch); + return 0; + } +} + +/* + * get_hex_digit -- Get a hex digit from the remote system & return its value. + * If ignore is nonzero, ignore spaces, newline & tabs. + */ +static int +get_hex_digit(ignore) + int ignore; +{ + static int ch; + while (1) { + ch = readchar(timeout); + if (junk(ch)) + continue; + if (sr_get_debug() > 4) { + debuglogs (4, "get_hex_digit() got a 0x%x(%c)", ch, ch); + } else { +#ifdef LOG_FILE /* write to the monitor log */ + if (log_file != 0x0) { + fputs ("get_hex_digit() got a 0x", log_file); + fputc (ch, log_file); + fputc ('\n', log_file); + fflush (log_file); + } +#endif + } + + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore) + ; + else { + expect_prompt(1); + debuglogs (4, "Invalid hex digit from remote system. (0x%x)", ch); + error("Invalid hex digit from remote system. (0x%x)", ch); + } + } +} + +/* get_hex_byte -- Get a byte from monitor and put it in *BYT. + * Accept any number leading spaces. + */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + debuglogs (4, "get_hex_byte() -- Read first nibble 0x%x", val); + + val |= get_hex_digit (0); + debuglogs (4, "get_hex_byte() -- Read second nibble 0x%x", val); + *byt = val; + + debuglogs (4, "get_hex_byte() -- Read a 0x%x", val); +} + +/* + * get_hex_word -- Get N 32-bit words from remote, each preceded by a space, + * and put them in registers starting at REGNO. + */ +static int +get_hex_word () +{ + long val, newval; + int i; + + val = 0; + +#if 0 + if (HOST_BYTE_ORDER == BIG_ENDIAN) { +#endif + for (i = 0; i < 8; i++) + val = (val << 4) + get_hex_digit (i == 0); +#if 0 + } else { + for (i = 7; i >= 0; i--) + val = (val << 4) + get_hex_digit (i == 0); + } +#endif + + debuglogs (4, "get_hex_word() got a 0x%x for a %s host.", val, (HOST_BYTE_ORDER == BIG_ENDIAN) ? "big endian" : "little endian"); + + return val; +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +static void +array_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error("Can't pass arguments to remote MONITOR process"); + + if (execfile == 0 || exec_bfd == 0) + error("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + +/* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* insert_step_breakpoint (); FIXME, do we need this? */ + + /* Let 'er rip... */ + proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* + * array_open -- open a connection to a remote debugger. + * NAME is the filename used for communication. + */ +static int baudrate = 9600; +static char dev_name[100]; + +static void +array_open(args, name, from_tty) + char *args; + char *name; + int from_tty; +{ + char packet[PBUFSIZ]; + + if (args == NULL) + error ("Use `target %s DEVICE-NAME' to use a serial port, or \n\ +`target %s HOST-NAME:PORT-NUMBER' to use a network connection.", name, name); + +/* if (is_open) */ + array_close(0); + + target_preopen (from_tty); + unpush_target (&array_ops); + + tmp_mips_processor_type = "lsi33k"; /* change the default from r3051 */ + mips_set_processor_type_command ("lsi33k", 0); + + strcpy(dev_name, args); + array_desc = SERIAL_OPEN(dev_name); + + if (array_desc == NULL) + perror_with_name(dev_name); + + if (baud_rate != -1) { + if (SERIAL_SETBAUDRATE (array_desc, baud_rate)) { + SERIAL_CLOSE (array_desc); + perror_with_name (name); + } + } + + SERIAL_RAW(array_desc); + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); + fprintf_filtered (log_file, "GDB %s (%s", version); + fprintf_filtered (log_file, " --target %s)\n", array_ops.to_shortname); + fprintf_filtered (log_file, "Remote target %s connected to %s\n\n", array_ops.to_shortname, dev_name); +#endif + + /* see if the target is alive. For a ROM monitor, we can just try to force the + expect_prompt to print a few times. For the GDB remote protocol, the application + being debugged is sitting at a breakpoint and waiting for GDB to initialize + the connection. We force it to give us an empty packet to see if it's alive. + */ + debuglogs (3, "Trying to ACK the target's debug stub"); + /* unless your are on the new hardware, the old board won't initialize + because the '@' doesn't flush output like it does on the new ROMS. + */ + printf_monitor ("@"); /* ask for the last signal */ + expect_prompt(1); /* See if we get a expect_prompt */ +#ifdef TEST_ARRAY /* skip packet for testing */ + make_gdb_packet (packet, "?"); /* ask for a bogus packet */ + if (array_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + printf_monitor ("@\n"); /* force it to flush stdout */ + expect_prompt(1); /* See if we get a expect_prompt */ +#endif + push_target (&array_ops); + if (from_tty) + printf("Remote target %s connected to %s\n", array_ops.to_shortname, dev_name); +} + +/* + * array_close -- Close out all files and local state before this + * target loses control. + */ + +static void +array_close (quitting) + int quitting; +{ + SERIAL_CLOSE(array_desc); + array_desc = NULL; + + debuglogs (1, "array_close (quitting=%d)", quitting); + +#if defined (LOG_FILE) + if (log_file) { + if (ferror(log_file)) + printf_filtered ("Error writing log file.\n"); + if (fclose(log_file) != 0) + printf_filtered ("Error closing log file.\n"); + } +#endif +} + +/* + * array_detach -- terminate the open connection to the remote + * debugger. Use this when you want to detach and do something + * else with your gdb. + */ +static void +array_detach (from_tty) + int from_tty; +{ + + debuglogs (1, "array_detach ()"); + + pop_target(); /* calls array_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* + * array_attach -- attach GDB to the target. + */ +static void +array_attach (args, from_tty) + char *args; + int from_tty; +{ + if (from_tty) + printf ("Starting remote %s debugging\n", target_shortname); + + debuglogs (1, "array_attach (args=%s)", args); + + printf_monitor ("go %x\n"); + /* swallow the echo. */ + expect ("go %x\n", 1); +} + +/* + * array_resume -- Tell the remote machine to resume. + */ +static void +array_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + debuglogs (1, "array_resume (step=%d, sig=%d)", step, sig); + + if (step) { + printf_monitor ("s\n"); + } else { + printf_monitor ("go\n"); + } +} + +#define TMPBUFSIZ 5 + +/* + * array_wait -- Wait until the remote machine stops, then return, + * storing status in status just as `wait' would. + */ +static int +array_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int old_timeout = timeout; + int result, i; + char c; + serial_t tty_desc; + serial_ttystate ttystate; + + debuglogs(1, "array_wait (), printing extraneous text."); + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + timeout = 0; /* Don't time out -- user program is running. */ + +#if !defined(__GO32__) && !defined(__MSDOS__) && !defined(__WIN32__) + tty_desc = SERIAL_FDOPEN (0); + ttystate = SERIAL_GET_TTY_STATE (tty_desc); + SERIAL_RAW (tty_desc); + + i = 0; + /* poll on the serial port and the keyboard. */ + while (1) { + c = readchar(timeout); + if (c > 0) { + if (c == *(ARRAY_PROMPT + i)) { + if (++i >= strlen (ARRAY_PROMPT)) { /* matched the prompt */ + debuglogs (4, "array_wait(), got the expect_prompt."); + break; + } + } else { /* not the prompt */ + i = 0; + } + fputc_unfiltered (c, gdb_stdout); + fflush (stdout); + } + c = SERIAL_READCHAR(tty_desc, timeout); + if (c > 0) { + SERIAL_WRITE(array_desc, &c, 1); + /* do this so it looks like there's keyboard echo */ + if (c == 3) /* exit on Control-C */ + break; +#if 0 + fputc_unfiltered (c, gdb_stdout); + fflush (stdout); +#endif + } + } + SERIAL_SET_TTY_STATE (tty_desc, ttystate); +#else + expect_prompt(1); + debuglogs (4, "array_wait(), got the expect_prompt."); +#endif + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + + timeout = old_timeout; + + return 0; +} + +/* + * array_fetch_registers -- read the remote registers into the + * block regs. + */ +static void +array_fetch_registers (ignored) + int ignored; +{ + int regno, i; + char *p; + unsigned char packet[PBUFSIZ]; + char regs[REGISTER_BYTES]; + + debuglogs (1, "array_fetch_registers (ignored=%d)\n", ignored); + + memset (packet, 0, PBUFSIZ); + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + make_gdb_packet (packet, "g"); + if (array_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (array_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + /* FIXME: read bytes from packet */ + debuglogs (4, "array_fetch_registers: Got a \"%s\" back\n", packet); + for (regno = 0; regno <= PC_REGNUM+4; regno++) { + /* supply register stores in target byte order, so swap here */ + /* FIXME: convert from ASCII hex to raw bytes */ + i = ascii2hexword (packet + (regno * 8)); + debuglogs (5, "Adding register %d = %x\n", regno, i); + SWAP_TARGET_AND_HOST (&i, 4); + supply_register (regno, (char *)&i); + } +} + +/* + * This is unused by targets like this one that use a + * protocol based on GDB's remote protocol. + */ +static void +array_fetch_register (ignored) + int ignored; +{ + array_fetch_registers (); +} + +/* + * Get all the registers from the targets. They come back in a large array. + */ +static void +array_store_registers (ignored) + int ignored; +{ + int regno; + unsigned long i; + char packet[PBUFSIZ]; + char buf[PBUFSIZ]; + char num[9]; + + debuglogs (1, "array_store_registers()"); + + memset (packet, 0, PBUFSIZ); + memset (buf, 0, PBUFSIZ); + buf[0] = 'G'; + + /* Unimplemented registers read as all bits zero. */ + /* FIXME: read bytes from packet */ + for (regno = 0; regno < 41; regno++) { /* FIXME */ + /* supply register stores in target byte order, so swap here */ + /* FIXME: convert from ASCII hex to raw bytes */ + i = (unsigned long)read_register (regno); + hexword2ascii (num, i); + strcpy (buf+(regno * 8)+1, num); + } + *(buf + (regno * 8) + 2) = 0; + make_gdb_packet (packet, buf); + if (array_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (array_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + + registers_changed (); +} + +/* + * This is unused by targets like this one that use a + * protocol based on GDB's remote protocol. + */ +static void +array_store_register (ignored) + int ignored; +{ + array_store_registers (); +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +array_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static void +array_files_info () +{ + printf ("\tAttached to %s at %d baud.\n", + dev_name, baudrate); +} + +/* + * array_write_inferior_memory -- Copy LEN bytes of data from debugger + * memory at MYADDR to inferior's memory at MEMADDR. Returns length moved. + */ +static int +array_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + unsigned long i; + int j; + char packet[PBUFSIZ]; + char buf[PBUFSIZ]; + char num[9]; + char *p; + + debuglogs (1, "array_write_inferior_memory (memaddr=0x%x, myaddr=0x%x, len=%d)", memaddr, myaddr, len); + memset (buf, '\0', PBUFSIZ); /* this also sets the string terminator */ + p = buf; + + *p++ = 'M'; /* The command to write memory */ + hexword2ascii (num, memaddr); /* convert the address */ + strcpy (p, num); /* copy the address */ + p += 8; + *p++ = ','; /* add comma delimeter */ + hexword2ascii (num, len); /* Get the length as a 4 digit number */ + *p++ = num[4]; + *p++ = num[5]; + *p++ = num[6]; + *p++ = num[7]; + *p++ = ':'; /* add the colon delimeter */ + for (j = 0; j < len; j++) { /* copy the data in after converting it */ + *p++ = tohex ((myaddr[j] >> 4) & 0xf); + *p++ = tohex (myaddr[j] & 0xf); + } + + make_gdb_packet (packet, buf); + if (array_send_packet (packet) == 0) + error ("Couldn't transmit packet\n"); + if (array_get_packet (packet) == 0) + error ("Couldn't receive packet\n"); + + return len; +} + +/* + * array_read_inferior_memory -- read LEN bytes from inferior memory + * at MEMADDR. Put the result at debugger address MYADDR. Returns + * length moved. + */ +static int +array_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int j; + char buf[20]; + char packet[PBUFSIZ]; + int count; /* Number of bytes read so far. */ + unsigned long startaddr; /* Starting address of this pass. */ + int len_this_pass; /* Number of bytes to read in this pass. */ + + debuglogs (1, "array_read_inferior_memory (memaddr=0x%x, myaddr=0x%x, len=%d)", memaddr, myaddr, len); + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + array_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len To memaddr and gets 0. */ + /* However, something like + array_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + if (((memaddr - 1) + len) < memaddr) { + errno = EIO; + return 0; + } + + for (count = 0, startaddr = memaddr; count < len; startaddr += len_this_pass) + { + /* Try to align to 16 byte boundry (why?) */ + len_this_pass = 16; + if ((startaddr % 16) != 0) + { + len_this_pass -= startaddr % 16; + } + /* Only transfer bytes we need */ + if (len_this_pass > (len - count)) + { + len_this_pass = (len - count); + } + /* Fetch the bytes */ + debuglogs (3, "read %d bytes from inferior address %x", len_this_pass, + startaddr); + sprintf (buf, "m%08x,%04x", startaddr, len_this_pass); + make_gdb_packet (packet, buf); + if (array_send_packet (packet) == 0) + { + error ("Couldn't transmit packet\n"); + } + if (array_get_packet (packet) == 0) + { + error ("Couldn't receive packet\n"); + } + if (*packet == 0) + { + error ("Got no data in the GDB packet\n"); + } + /* Pick packet apart and xfer bytes to myaddr */ + debuglogs (4, "array_read_inferior_memory: Got a \"%s\" back\n", packet); + for (j = 0; j < len_this_pass ; j++) + { + /* extract the byte values */ + myaddr[count++] = from_hex (*(packet+(j*2))) * 16 + from_hex (*(packet+(j*2)+1)); + debuglogs (5, "myaddr[%d] set to %x\n", count-1, myaddr[count-1]); + } + } + return (count); +} + +/* FIXME-someday! merge these two. */ +static int +array_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (write) + return array_write_inferior_memory (memaddr, myaddr, len); + else + return array_read_inferior_memory (memaddr, myaddr, len); +} + +static void +array_kill (args, from_tty) + char *args; + int from_tty; +{ + return; /* ignore attempts to kill target system */ +} + +/* Clean up when a program exits. + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +static void +array_mourn_inferior () +{ + remove_breakpoints (); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +#define MAX_ARRAY_BREAKPOINTS 16 + +extern int memory_breakpoint_size; +static CORE_ADDR breakaddr[MAX_ARRAY_BREAKPOINTS] = {0}; + +/* + * array_insert_breakpoint -- add a breakpoint + */ +static int +array_insert_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + debuglogs (1, "array_insert_breakpoint() addr = 0x%x", addr); + + for (i = 0; i <= MAX_ARRAY_BREAKPOINTS; i++) { + if (breakaddr[i] == 0) { + breakaddr[i] = addr; + if (sr_get_debug() > 4) + printf ("Breakpoint at %x\n", addr); + array_read_inferior_memory(addr, shadow, memory_breakpoint_size); + printf_monitor("b 0x%x\n", addr); + expect_prompt(1); + return 0; + } + } + + fprintf(stderr, "Too many breakpoints (> 16) for monitor\n"); + return 1; +} + +/* + * _remove_breakpoint -- Tell the monitor to remove a breakpoint + */ +static int +array_remove_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + debuglogs (1, "array_remove_breakpoint() addr = 0x%x", addr); + + for (i = 0; i < MAX_ARRAY_BREAKPOINTS; i++) { + if (breakaddr[i] == addr) { + breakaddr[i] = 0; + /* some monitors remove breakpoints based on the address */ + printf_monitor("bd %x\n", i); + expect_prompt(1); + return 0; + } + } + fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr); + return 1; +} + +static void +array_stop () +{ + debuglogs (1, "array_stop()"); + printf_monitor("\003"); + expect_prompt(1); +} + +/* + * array_command -- put a command string, in args, out to MONITOR. + * Output from MONITOR is placed on the users terminal until the + * expect_prompt is seen. FIXME + */ +static void +monitor_command (args, fromtty) + char *args; + int fromtty; +{ + debuglogs (1, "monitor_command (args=%s)", args); + + if (array_desc == NULL) + error("monitor target not open."); + + if (!args) + error("Missing command."); + + printf_monitor ("%s\n", args); + expect_prompt(0); +} + +/* + * make_gdb_packet -- make a GDB packet. The data is always ASCII. + * 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. + * + */ +static void +make_gdb_packet (buf, data) + char *buf, *data; +{ + int i; + unsigned char csum = 0; + int cnt; + char *p; + + debuglogs (3, "make_gdb_packet(%s)\n", data); + cnt = strlen (data); + if (cnt > PBUFSIZ) + error ("make_gdb_packet(): to much data\n"); + + /* start with the packet header */ + p = buf; + *p++ = '$'; + + /* calculate the checksum */ + for (i = 0; i < cnt; i++) { + csum += data[i]; + *p++ = data[i]; + } + + /* terminate the data with a '#' */ + *p++ = '#'; + + /* add the checksum as two ascii digits */ + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + *p = 0x0; /* Null terminator on string */ +} + +/* + * array_send_packet -- send a GDB packet to the target with error handling. We + * get a '+' (ACK) back if the packet is received and the checksum + * matches. Otherwise a '-' (NAK) is returned. It returns a 1 for a + * successful transmition, or a 0 for a failure. + */ +static int +array_send_packet (packet) + char *packet; +{ + int c, retries, i; + char junk[PBUFSIZ]; + + retries = 0; + +#if 0 + /* scan the packet to make sure it only contains valid characters. + this may sound silly, but sometimes a garbled packet will hang + the target board. We scan the whole thing, then print the error + message. + */ + for (i = 0; i < strlen(packet); i++) { + debuglogs (5, "array_send_packet(): Scanning \'%c\'\n", packet[i]); + /* legit hex numbers or command */ + if ((isxdigit(packet[i])) || (isalpha(packet[i]))) + continue; + switch (packet[i]) { + case '+': /* ACK */ + case '-': /* NAK */ + case '#': /* end of packet */ + case '$': /* start of packet */ + continue; + default: /* bogus character */ + retries++; + debuglogs (4, "array_send_packet(): Found a non-ascii digit \'%c\' in the packet.\n", packet[i]); + } + } +#endif + + if (retries > 0) + error ("Can't send packet, found %d non-ascii characters", retries); + + /* ok, try to send the packet */ + retries = 0; + while (retries++ <= 10) { + printf_monitor ("%s", packet); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (retries <= 10) { + c = readchar (-timeout); + debuglogs (3, "Reading a GDB protocol packet... Got a '%c'\n", c); + switch (c) { + case '+': + debuglogs (3, "Got Ack\n"); + return 1; + case SERIAL_TIMEOUT: + debuglogs (3, "Timed out reading serial port\n"); + printf_monitor("@"); /* resync with the monitor */ + expect_prompt(1); /* See if we get a expect_prompt */ + break; /* Retransmit buffer */ + case '-': + debuglogs (3, "Got NAK\n"); + printf_monitor("@"); /* resync with the monitor */ + expect_prompt(1); /* See if we get a expect_prompt */ + break; + case '$': + /* it's probably an old response, or the echo of our command. + * just gobble up the packet and ignore it. + */ + debuglogs (3, "Got a junk packet\n"); + i = 0; + do { + c = readchar (timeout); + junk[i++] = c; + } while (c != '#'); + c = readchar (timeout); + junk[i++] = c; + c = readchar (timeout); + junk[i++] = c; + junk[i++] = '\0'; + debuglogs (3, "Reading a junk packet, got a \"%s\"\n", junk); + continue; /* Now, go look for next packet */ + default: + continue; + } + retries++; + debuglogs (3, "Retransmitting packet \"%s\"\n", packet); + break; /* Here to retransmit */ + } + } /* outer while */ + return 0; +} + +/* + * array_get_packet -- get a GDB packet from the target. Basically we read till we + * see a '#', then check the checksum. It returns a 1 if it's gotten a + * packet, or a 0 it the packet wasn't transmitted correctly. + */ +static int +array_get_packet (packet) + char *packet; +{ + int c; + int retries; + unsigned char csum; + unsigned char pktcsum; + char *bp; + + csum = 0; + bp = packet; + + memset (packet, 1, PBUFSIZ); + retries = 0; + while (retries <= 10) { + do { + c = readchar (timeout); + if (c == SERIAL_TIMEOUT) { + debuglogs (3, "array_get_packet: got time out from serial port.\n"); + } + debuglogs (3, "Waiting for a '$', got a %c\n", c); + } while (c != '$'); + + retries = 0; + while (retries <= 10) { + c = readchar (timeout); + debuglogs (3, "array_get_packet: got a '%c'\n", c); + switch (c) { + case SERIAL_TIMEOUT: + debuglogs (3, "Timeout in mid-packet, retrying\n"); + return 0; + case '$': + debuglogs (3, "Saw new packet start in middle of old one\n"); + return 0; /* Start a new packet, count retries */ + case '#': + *bp = '\0'; + pktcsum = from_hex (readchar (timeout)) << 4; + pktcsum |= from_hex (readchar (timeout)); + if (csum == 0) + debuglogs (3, "\nGDB packet checksum zero, must be a bogus packet\n"); + if (csum == pktcsum) { + debuglogs (3, "\nGDB packet checksum correct, packet data is \"%s\",\n", packet); + printf_monitor ("@"); + expect_prompt (1); + return 1; + } + debuglogs (3, "Bad checksum, sentsum=0x%x, csum=0x%x\n", pktcsum, csum); + return 0; + case '*': /* Run length encoding */ + debuglogs (5, "Run length encoding in packet\n"); + csum += c; + c = readchar (timeout); + csum += c; + c = c - ' ' + 3; /* Compute repeat count */ + + if (c > 0 && c < 255 && bp + c - 1 < packet + PBUFSIZ - 1) { + memset (bp, *(bp - 1), c); + bp += c; + continue; + } + *bp = '\0'; + printf_filtered ("Repeat count %d too large for buffer.\n", c); + return 0; + + default: + if ((!isxdigit(c)) && (!ispunct(c))) + debuglogs (4, "Got a non-ascii digit \'%c\'.\\n", c); + if (bp < packet + PBUFSIZ - 1) { + *bp++ = c; + csum += c; + continue; + } + + *bp = '\0'; + puts_filtered ("Remote packet too long.\n"); + return 0; + } + } + } +} + +/* + * ascii2hexword -- convert an ascii number represented by 8 digits to a hex value. + */ +static unsigned long +ascii2hexword (mem) + unsigned char *mem; +{ + unsigned long val; + int i; + char buf[9]; + + val = 0; + for (i = 0; i < 8; i++) { + val <<= 4; + if (mem[i] >= 'A' && mem[i] <= 'F') + val = val + mem[i] - 'A' + 10; + if (mem[i] >= 'a' && mem[i] <= 'f') + val = val + mem[i] - 'a' + 10; + if (mem[i] >= '0' && mem[i] <= '9') + val = val + mem[i] - '0'; + buf[i] = mem[i]; + } + buf[8] = '\0'; + debuglogs (4, "ascii2hexword() got a 0x%x from %s(%x).\n", val, buf, mem); + return val; +} + +/* + * ascii2hexword -- convert a hex value to an ascii number represented by 8 + * digits. + */ +static char* +hexword2ascii (mem, num) + unsigned char *mem; + unsigned long num; +{ + int i; + unsigned char ch; + + debuglogs (4, "hexword2ascii() converting %x ", num); + for (i = 7; i >= 0; i--) { + mem[i] = tohex ((num >> 4) & 0xf); + mem[i] = tohex (num & 0xf); + num = num >> 4; + } + mem[8] = '\0'; + debuglogs (4, "\tto a %s", mem); +} + +/* Convert hex digit A to a number. */ +static int +from_hex (a) + int a; +{ + if (a == 0) + return 0; + + debuglogs (4, "from_hex got a 0x%x(%c)\n",a,a); + if (a >= '0' && a <= '9') + return a - '0'; + if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else { + error ("Reply contains invalid hex digit 0x%x", a); + } +} + +/* Convert number NIB to a hex digit. */ +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* + * _initialize_remote_monitors -- setup a few addtitional commands that + * are usually only used by monitors. + */ +void +_initialize_remote_monitors () +{ + /* generic monitor command */ + add_com ("monitor", class_obscure, monitor_command, + "Send a command to the debug monitor."); + +} + +/* + * _initialize_array -- do any special init stuff for the target. + */ +void +_initialize_array () +{ + add_target (&array_ops); +} diff --git a/contrib/gdb/gdb/remote-bug.c b/contrib/gdb/gdb/remote-bug.c new file mode 100644 index 000000000000..cd3b798c07d3 --- /dev/null +++ b/contrib/gdb/gdb/remote-bug.c @@ -0,0 +1,1053 @@ +/* Remote debugging interface for Motorola's MVME187BUG monitor, an embedded + monitor for the m88k. + + Copyright 1992, 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by K. Richard Pixley. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "wait.h" + +#include "gdb_string.h" +#include +#include +#include +#include +#include + +#include "terminal.h" +#include "gdbcore.h" +#include "gdbcmd.h" + +#include "remote-utils.h" + +extern int sleep(); + +/* External data declarations */ +extern int stop_soon_quietly; /* for wait_for_inferior */ + +/* Forward data declarations */ +extern struct target_ops bug_ops; /* Forward declaration */ + +/* Forward function declarations */ +static int bug_clear_breakpoints PARAMS((void)); + +static int bug_read_memory PARAMS((CORE_ADDR memaddr, + unsigned char *myaddr, + int len)); + +static int bug_write_memory PARAMS((CORE_ADDR memaddr, + unsigned char *myaddr, + int len)); + +/* This variable is somewhat arbitrary. It's here so that it can be + set from within a running gdb. */ + +static int srec_max_retries = 3; + +/* Each S-record download to the target consists of an S0 header + record, some number of S3 data records, and one S7 termination + record. I call this download a "frame". Srec_frame says how many + bytes will be represented in each frame. */ + +#define SREC_SIZE 160 +static int srec_frame = SREC_SIZE; + +/* This variable determines how many bytes will be represented in each + S3 s-record. */ + +static int srec_bytes = 40; + +/* At one point it appeared to me as though the bug monitor could not + really be expected to receive two sequential characters at 9600 + baud reliably. Echo-pacing is an attempt to force data across the + line even in this condition. Specifically, in echo-pace mode, each + character is sent one at a time and we look for the echo before + sending the next. This is excruciatingly slow. */ + +static int srec_echo_pace = 0; + +/* How long to wait after an srec for a possible error message. + Similar to the above, I tried sleeping after sending each S3 record + in hopes that I might actually see error messages from the bug + monitor. This might actually work if we were to use sleep + intervals smaller than 1 second. */ + +static int srec_sleep = 0; + +/* Every srec_noise records, flub the checksum. This is a debugging + feature. Set the variable to something other than 1 in order to + inject *deliberate* checksum errors. One might do this if one + wanted to test error handling and recovery. */ + +static int srec_noise = 0; + +/* Called when SIGALRM signal sent due to alarm() timeout. */ + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to bug_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +/* + * Download a file specified in 'args', to the bug. + */ + +static void +bug_load (args, fromtty) + char *args; + int fromtty; +{ + bfd *abfd; + asection *s; + char buffer[1024]; + + sr_check_open (); + + dcache_flush (gr_get_dcache()); + inferior_pid = 0; + abfd = bfd_openr (args, 0); + if (!abfd) + { + printf_filtered ("Unable to open file %s\n", args); + return; + } + + if (bfd_check_format (abfd, bfd_object) == 0) + { + printf_filtered ("File is not an object file\n"); + return; + } + + s = abfd->sections; + while (s != (asection *) NULL) + { + srec_frame = SREC_SIZE; + if (s->flags & SEC_LOAD) + { + int i; + + char *buffer = xmalloc (srec_frame); + + printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, s->vma + s->_raw_size); + fflush (stdout); + for (i = 0; i < s->_raw_size; i += srec_frame) + { + if (srec_frame > s->_raw_size - i) + srec_frame = s->_raw_size - i; + + bfd_get_section_contents (abfd, s, buffer, i, srec_frame); + bug_write_memory (s->vma + i, buffer, srec_frame); + printf_filtered ("*"); + fflush (stdout); + } + printf_filtered ("\n"); + free (buffer); + } + s = s->next; + } + sprintf (buffer, "rs ip %lx", (unsigned long) abfd->start_address); + sr_write_cr (buffer); + gr_expect_prompt (); +} + +#if 0 +static char * +get_word (p) + char **p; +{ + char *s = *p; + char *word; + char *copy; + size_t len; + + while (isspace (*s)) + s++; + + word = s; + + len = 0; + + while (*s && !isspace (*s)) + { + s++; + len++; + + } + copy = xmalloc (len + 1); + memcpy (copy, word, len); + copy[len] = 0; + *p = s; + return copy; +} +#endif + +static struct gr_settings bug_settings = { + NULL, /* dcache */ + "Bug>", /* prompt */ + &bug_ops, /* ops */ + bug_clear_breakpoints, /* clear_all_breakpoints */ + bug_read_memory, /* readfunc */ + bug_write_memory, /* writefunc */ + gr_generic_checkin, /* checkin */ +}; + +static char *cpu_check_strings[] = { + "=", + "Invalid Register", +}; + +static void +bug_open (args, from_tty) + char *args; + int from_tty; +{ + if (args == NULL) + args = ""; + + gr_open(args, from_tty, &bug_settings); + /* decide *now* whether we are on an 88100 or an 88110 */ + sr_write_cr("rs cr06"); + sr_expect("rs cr06"); + + switch (gr_multi_scan(cpu_check_strings, 0)) + { + case 0: /* this is an m88100 */ + target_is_m88110 = 0; + break; + case 1: /* this is an m88110 */ + target_is_m88110 = 1; + break; + default: + abort(); + } +} + +/* Tell the remote machine to resume. */ + +void +bug_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + dcache_flush (gr_get_dcache()); + + if (step) + { + sr_write_cr("t"); + + /* Force the next bug_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type + "continue" to see any. FIXME, this should be fixed. */ + need_artificial_trap = 1; + } + else + sr_write_cr ("g"); + + return; +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +static char *wait_strings[] = { + "At Breakpoint", + "Exception: Data Access Fault (Local Bus Timeout)", + "\r8???-Bug>", + "\r197-Bug>", + NULL, +}; + +int +bug_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int old_timeout = sr_get_timeout(); + int old_immediate_quit = immediate_quit; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + /* read off leftovers from resume so that the rest can be passed + back out as stdout. */ + if (need_artificial_trap == 0) + { + sr_expect("Effective address: "); + (void) sr_get_hex_word(); + sr_expect ("\r\n"); + } + + sr_set_timeout(-1); /* Don't time out -- user program is running. */ + immediate_quit = 1; /* Helps ability to QUIT */ + + switch (gr_multi_scan(wait_strings, need_artificial_trap == 0)) + { + case 0: /* breakpoint case */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + /* user output from the target can be discarded here. (?) */ + gr_expect_prompt(); + break; + + case 1: /* bus error */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_BUS; + /* user output from the target can be discarded here. (?) */ + gr_expect_prompt(); + break; + + case 2: /* normal case */ + case 3: + if (need_artificial_trap != 0) + { + /* stepping */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + need_artificial_trap--; + break; + } + else + { + /* exit case */ + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + break; + } + + case -1: /* trouble */ + default: + fprintf_filtered (stderr, + "Trouble reading target during wait\n"); + break; + } + + sr_set_timeout(old_timeout); + immediate_quit = old_immediate_quit; + return 0; +} + +/* Return the name of register number REGNO + in the form input and output by bug. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char *rn[] = { + "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", + "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + + /* these get confusing because we omit a few and switch some ordering around. */ + + "cr01", /* 32 = psr */ + "fcr62", /* 33 = fpsr*/ + "fcr63", /* 34 = fpcr */ + "ip", /* this is something of a cheat. */ + /* 35 = sxip */ + "cr05", /* 36 = snip */ + "cr06", /* 37 = sfip */ + + "x00", "x01", "x02", "x03", "x04", "x05", "x06", "x07", + "x08", "x09", "x10", "x11", "x12", "x13", "x14", "x15", + "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", + }; + + return rn[regno]; +} + +#if 0 /* not currently used */ +/* Read from remote while the input matches STRING. Return zero on + success, -1 on failure. */ + +static int +bug_scan (s) + char *s; +{ + int c; + + while (*s) + { + c = sr_readchar(); + if (c != *s++) + { + fflush(stdout); + printf("\nNext character is '%c' - %d and s is \"%s\".\n", c, c, --s); + return(-1); + } + } + + return(0); +} +#endif /* never */ + +static int +bug_srec_write_cr (s) + char *s; +{ + char *p = s; + + if (srec_echo_pace) + for (p = s; *p; ++p) + { + if (sr_get_debug() > 0) + printf ("%c", *p); + + do + SERIAL_WRITE(sr_get_desc(), p, 1); + while (sr_pollchar() != *p); + } + else + { + sr_write_cr (s); +/* return(bug_scan (s) || bug_scan ("\n")); */ + } + + return(0); +} + +/* Store register REGNO, or all if REGNO == -1. */ + +static void +bug_fetch_register(regno) + int regno; +{ + sr_check_open(); + + if (regno == -1) + { + int i; + + for (i = 0; i < NUM_REGS; ++i) + bug_fetch_register(i); + } + else if (target_is_m88110 && regno == SFIP_REGNUM) + { + /* m88110 has no sfip. */ + long l = 0; + supply_register(regno, (char *) &l); + } + else if (regno < XFP_REGNUM) + { + char buffer[MAX_REGISTER_RAW_SIZE]; + + sr_write ("rs ", 3); + sr_write_cr (get_reg_name(regno)); + sr_expect ("="); + store_unsigned_integer (buffer, REGISTER_RAW_SIZE (regno), + sr_get_hex_word()); + gr_expect_prompt (); + supply_register (regno, buffer); + } + else + { + /* Float register so we need to parse a strange data format. */ + long p; + unsigned char fpreg_buf[10]; + + sr_write("rs ", 3); + sr_write(get_reg_name(regno), strlen(get_reg_name(regno))); + sr_write_cr(";d"); + sr_expect("rs"); + sr_expect(get_reg_name(regno)); + sr_expect(";d"); + sr_expect("="); + + /* sign */ + p = sr_get_hex_digit(1); + fpreg_buf[0] = p << 7; + + /* exponent */ + sr_expect("_"); + p = sr_get_hex_digit(1); + fpreg_buf[0] += (p << 4); + fpreg_buf[0] += sr_get_hex_digit(1); + + fpreg_buf[1] = sr_get_hex_digit(1) << 4; + + /* fraction */ + sr_expect("_"); + fpreg_buf[1] += sr_get_hex_digit(1); + + fpreg_buf[2] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[3] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[4] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[5] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[6] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[7] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1); + fpreg_buf[8] = 0; + fpreg_buf[9] = 0; + + gr_expect_prompt(); + supply_register(regno, fpreg_buf); + } + + return; +} + +/* Store register REGNO, or all if REGNO == -1. */ + +static void +bug_store_register (regno) + int regno; +{ + char buffer[1024]; + sr_check_open(); + + if (regno == -1) + { + int i; + + for (i = 0; i < NUM_REGS; ++i) + bug_store_register(i); + } + else + { + char *regname; + + regname = get_reg_name(regno); + + if (target_is_m88110 && regno == SFIP_REGNUM) + return; + else if (regno < XFP_REGNUM) + sprintf(buffer, "rs %s %08x", + regname, + read_register(regno)); + else + { + unsigned char *fpreg_buf = + (unsigned char *)®isters[REGISTER_BYTE(regno)]; + + sprintf(buffer, "rs %s %1x_%02x%1x_%1x%02x%02x%02x%02x%02x%02x;d", + regname, + /* sign */ + (fpreg_buf[0] >> 7) & 0xf, + /* exponent */ + fpreg_buf[0] & 0x7f, + (fpreg_buf[1] >> 8) & 0xf, + /* fraction */ + fpreg_buf[1] & 0xf, + fpreg_buf[2], + fpreg_buf[3], + fpreg_buf[4], + fpreg_buf[5], + fpreg_buf[6], + fpreg_buf[7]); + } + + sr_write_cr(buffer); + gr_expect_prompt(); + } + + return; +} + +int +bug_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr; + + /* Round ending address up; get number of longwords that makes. */ + register int count; + + /* Allocate buffer of that many longwords. */ + register int *buffer; + + addr = memaddr & -sizeof (int); + count = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + + buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int) sizeof (int)) + { + /* Need part of initial word -- fetch it. */ + buffer[0] = gr_fetch_word (addr); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = gr_fetch_word (addr + (count - 1) * sizeof (int)); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + gr_store_word (addr, buffer[i]); + if (errno) + { + + return 0; + } + + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = gr_fetch_word (addr); + if (errno) + { + return 0; + } + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + } + + return len; +} + +static void +start_load() +{ + char *command; + + command = (srec_echo_pace ? "lo 0 ;x" : "lo 0"); + + sr_write_cr (command); + sr_expect (command); + sr_expect ("\r\n"); + bug_srec_write_cr ("S0030000FC"); + return; +} + +/* This is an extremely vulnerable and fragile function. I've made + considerable attempts to make this deterministic, but I've + certainly forgotten something. The trouble is that S-records are + only a partial file format, not a protocol. Worse, apparently the + m88k bug monitor does not run in real time while receiving + S-records. Hence, we must pay excruciating attention to when and + where error messages are returned, and what has actually been sent. + + Each call represents a chunk of memory to be sent to the target. + We break that chunk into an S0 header record, some number of S3 + data records each containing srec_bytes, and an S7 termination + record. */ + +static char *srecord_strings[] = { + "S-RECORD", + "-Bug>", + NULL, +}; + +static int +bug_write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int done; + int checksum; + int x; + int retries; + char *buffer = alloca ((srec_bytes + 8) << 1); + + retries = 0; + + do + { + done = 0; + + if (retries > srec_max_retries) + return(-1); + + if (retries > 0) + { + if (sr_get_debug() > 0) + printf("\n\n"); + + /* This gr_expect_prompt call is extremely important. Without + it, we will tend to resend our packet so fast that it + will arrive before the bug monitor is ready to receive + it. This would lead to a very ugly resend loop. */ + + gr_expect_prompt(); + } + + start_load(); + + while (done < len) + { + int thisgo; + int idx; + char *buf = buffer; + CORE_ADDR address; + + checksum = 0; + thisgo = len - done; + if (thisgo > srec_bytes) + thisgo = srec_bytes; + + address = memaddr + done; + sprintf (buf, "S3%02X%08X", thisgo + 4 + 1, address); + buf += 12; + + checksum += (thisgo + 4 + 1 + + (address & 0xff) + + ((address >> 8) & 0xff) + + ((address >> 16) & 0xff) + + ((address >> 24) & 0xff)); + + for (idx = 0; idx < thisgo; idx++) + { + sprintf (buf, "%02X", myaddr[idx + done]); + checksum += myaddr[idx + done]; + buf += 2; + } + + if (srec_noise > 0) + { + /* FIXME-NOW: insert a deliberate error every now and then. + This is intended for testing/debugging the error handling + stuff. */ + static int counter = 0; + if (++counter > srec_noise) + { + counter = 0; + ++checksum; + } + } + + sprintf(buf, "%02X", ~checksum & 0xff); + bug_srec_write_cr (buffer); + + if (srec_sleep != 0) + sleep(srec_sleep); + + /* This pollchar is probably redundant to the gr_multi_scan + below. Trouble is, we can't be sure when or where an + error message will appear. Apparently, when running at + full speed from a typical sun4, error messages tend to + appear to arrive only *after* the s7 record. */ + + if ((x = sr_pollchar()) != 0) + { + if (sr_get_debug() > 0) + printf("\n\n"); + + ++retries; + + /* flush any remaining input and verify that we are back + at the prompt level. */ + gr_expect_prompt(); + /* start all over again. */ + start_load(); + done = 0; + continue; + } + + done += thisgo; + } + + bug_srec_write_cr("S7060000000000F9"); + ++retries; + + /* Having finished the load, we need to figure out whether we + had any errors. */ + } while (gr_multi_scan(srecord_strings, 0) == 0);; + + return(0); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. + * sb/sh instructions don't work on unaligned addresses, when TU=1. + */ + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +static int +bug_read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + char request[100]; + char *buffer; + char *p; + char type; + char size; + unsigned char c; + unsigned int inaddr; + unsigned int checksum; + + sprintf(request, "du 0 %x:&%d", memaddr, len); + sr_write_cr(request); + + p = buffer = alloca(len); + + /* scan up through the header */ + sr_expect("S0030000FC"); + + while (p < buffer + len) + { + /* scan off any white space. */ + while (sr_readchar() != 'S') ;; + + /* what kind of s-rec? */ + type = sr_readchar(); + + /* scan record size */ + sr_get_hex_byte(&size); + checksum = size; + --size; + inaddr = 0; + + switch (type) + { + case '7': + case '8': + case '9': + goto done; + + case '3': + sr_get_hex_byte(&c); + inaddr = (inaddr << 8) + c; + checksum += c; + --size; + /* intentional fall through */ + case '2': + sr_get_hex_byte(&c); + inaddr = (inaddr << 8) + c; + checksum += c; + --size; + /* intentional fall through */ + case '1': + sr_get_hex_byte(&c); + inaddr = (inaddr << 8) + c; + checksum += c; + --size; + sr_get_hex_byte(&c); + inaddr = (inaddr << 8) + c; + checksum += c; + --size; + break; + + default: + /* bonk */ + error("reading s-records."); + } + + if (inaddr < memaddr + || (memaddr + len) < (inaddr + size)) + error("srec out of memory range."); + + if (p != buffer + inaddr - memaddr) + error("srec out of sequence."); + + for (; size; --size, ++p) + { + sr_get_hex_byte(p); + checksum += *p; + } + + sr_get_hex_byte(&c); + if (c != (~checksum & 0xff)) + error("bad s-rec checksum"); + } + + done: + gr_expect_prompt(); + if (p != buffer + len) + return(1); + + memcpy(myaddr, buffer, len); + return(0); +} + +#define MAX_BREAKS 16 +static int num_brkpts = 0; +static int +bug_insert_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let bug save instructions */ +{ + sr_check_open (); + + if (num_brkpts < MAX_BREAKS) + { + char buffer[100]; + + num_brkpts++; + sprintf (buffer, "br %x", addr); + sr_write_cr (buffer); + gr_expect_prompt (); + return(0); + } + else + { + fprintf_filtered (stderr, + "Too many break points, break point not installed\n"); + return(1); + } + +} +static int +bug_remove_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let bug save instructions */ +{ + if (num_brkpts > 0) + { + char buffer[100]; + + num_brkpts--; + sprintf (buffer, "nobr %x", addr); + sr_write_cr (buffer); + gr_expect_prompt (); + + } + return (0); +} + +/* Clear the bugs notion of what the break points are */ +static int +bug_clear_breakpoints () +{ + + if (sr_is_open()) + { + sr_write_cr ("nobr"); + sr_expect("nobr"); + gr_expect_prompt (); + } + num_brkpts = 0; + return(0); +} + +struct target_ops bug_ops = +{ + "bug", "Remote BUG monitor", + "Use the mvme187 board running the BUG monitor connected by a serial line.", + + bug_open, gr_close, + 0, gr_detach, bug_resume, bug_wait, /* attach */ + bug_fetch_register, bug_store_register, + gr_prepare_to_store, + bug_xfer_memory, + gr_files_info, + bug_insert_breakpoint, bug_remove_breakpoint, /* Breakpoints */ + 0, 0, 0, 0, 0, /* Terminal handling */ + gr_kill, /* FIXME, kill */ + bug_load, + 0, /* lookup_symbol */ + gr_create_inferior, /* create_inferior */ + gr_mourn, /* mourn_inferior FIXME */ + 0, /* can_run */ + 0, /* notice_signals */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_bug () +{ + add_target (&bug_ops); + + add_show_from_set + (add_set_cmd ("srec-bytes", class_support, var_uinteger, + (char *) &srec_bytes, + "\ +Set the number of bytes represented in each S-record.\n\ +This affects the communication protocol with the remote target.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("srec-max-retries", class_support, var_uinteger, + (char *) &srec_max_retries, + "\ +Set the number of retries for shipping S-records.\n\ +This affects the communication protocol with the remote target.", + &setlist), + &showlist); + +#if 0 + /* This needs to set SREC_SIZE, not srec_frame which gets changed at the + end of a download. But do we need the option at all? */ + add_show_from_set + (add_set_cmd ("srec-frame", class_support, var_uinteger, + (char *) &srec_frame, + "\ +Set the number of bytes in an S-record frame.\n\ +This affects the communication protocol with the remote target.", + &setlist), + &showlist); +#endif /* 0 */ + + add_show_from_set + (add_set_cmd ("srec-noise", class_support, var_zinteger, + (char *) &srec_noise, + "\ +Set number of S-record to send before deliberately flubbing a checksum.\n\ +Zero means flub none at all. This affects the communication protocol\n\ +with the remote target.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("srec-sleep", class_support, var_zinteger, + (char *) &srec_sleep, + "\ +Set number of seconds to sleep after an S-record for a possible error message to arrive.\n\ +This affects the communication protocol with the remote target.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("srec-echo-pace", class_support, var_boolean, + (char *) &srec_echo_pace, + "\ +Set echo-verification.\n\ +When on, use verification by echo when downloading S-records. This is\n\ +much slower, but generally more reliable.", + &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/remote-e7000.c b/contrib/gdb/gdb/remote-e7000.c new file mode 100644 index 000000000000..d18891395aff --- /dev/null +++ b/contrib/gdb/gdb/remote-e7000.c @@ -0,0 +1,2066 @@ +/* Remote debugging interface for Hitachi E7000 ICE, for GDB + Copyright 1993, 1994, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + + Written by Steve Chamberlain for 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The E7000 is an in-circuit emulator for the Hitachi H8/300-H and + Hitachi-SH processor. It has serial port and a lan port. + + The monitor command set makes it difficult to load large ammounts of + data over the lan without using ftp - so try not to issue load + commands when communicating over ethernet; use the ftpload command. + + The monitor pauses for a second when dumping srecords to the serial + line too, so we use a slower per byte mechanism but without the + startup overhead. Even so, it's pretty slow... */ + +#include "defs.h" +#include "gdbcore.h" +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "value.h" +#include "command.h" +#include +#include "gdb_string.h" +#include +#include "serial.h" +#include "remote-utils.h" +#include "symfile.h" +#include + +#if 0 +#define HARD_BREAKPOINTS +#define BC_BREAKPOINTS 0 +#endif + +#define CTRLC 0x03 +#define ENQ 0x05 +#define ACK 0x06 +#define CTRLZ 0x1a + +extern void notice_quit PARAMS ((void)); + +/* Local function declarations. */ + +static void e7000_close PARAMS ((int)); + +static void e7000_fetch_register PARAMS ((int)); + +static void e7000_store_register PARAMS ((int)); + +static void e7000_command PARAMS ((char *, int)); + +static void e7000_login_command PARAMS ((char *, int)); + +static void e7000_ftp_command PARAMS ((char *, int)); + +static void e7000_drain_command PARAMS ((char *, int)); + +static void expect PARAMS ((char *)); + +static void expect_full_prompt PARAMS ((void)); + +static void expect_prompt PARAMS ((void)); + +/* Variables. */ + +static serial_t e7000_desc; + +/* Nonzero if using the tcp serial driver. */ + +static int using_tcp; + +/* Nonzero if using the pc isa card. */ + +static int using_pc; + +extern struct target_ops e7000_ops; /* Forward declaration */ + +char *ENQSTRING = "\005"; + +/* Nonzero if some routine (as opposed to the user) wants echoing. + FIXME: Do this reentrantly with an extra parameter. */ + +static int echo; + +static int ctrl_c; + +static int timeout = 5; + +/* Send data to e7000debug. */ + +static void +puts_e7000debug (buf) + char *buf; +{ + if (!e7000_desc) + error ("Use \"target e7000 ...\" first."); + + if (remote_debug) + printf("Sending %s\n", buf); + + if (SERIAL_WRITE (e7000_desc, buf, strlen (buf))) + fprintf (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno)); + + /* And expect to see it echoed, unless using the pc interface */ +#if 0 + if (!using_pc) +#endif + expect (buf); +} + +static void +putchar_e7000 (x) + int x; +{ + char b[1]; + + b[0] = x; + SERIAL_WRITE (e7000_desc, b, 1); +} + +static void +write_e7000 (s) + char *s; +{ + SERIAL_WRITE (e7000_desc, s, strlen (s)); +} + +static int +normal (x) + int x; +{ + if (x == '\n') + return '\r'; + return x; +} + +/* Read a character from the remote system, doing all the fancy timeout + stuff. */ + +static int +readchar (timeout) + int timeout; +{ + int c; + + do + { + c = SERIAL_READCHAR (e7000_desc, timeout); + } + while (c > 127); + + if (c == SERIAL_TIMEOUT) + { + if (timeout == 0) + return -1; + echo = 0; + error ("Timeout reading from remote system."); + } + if (remote_debug) + { + putchar (c); + fflush (stdout); + } + + return normal (c); +} + +#if 0 +char * +tl (x) +{ + static char b[8][10]; + static int p; + + p++; + p &= 7; + if (x >= ' ') + { + b[p][0] = x; + b[p][1] = 0; + } + else + { + sprintf(b[p], "<%d>", x); + } + + return b[p]; +} +#endif + +/* Scan input from the remote system, until STRING is found. If + DISCARD is non-zero, then discard non-matching input, else print it + out. Let the user break out immediately. */ + +static void +expect (string) + char *string; +{ + char *p = string; + int c; + int nl = 0; + + while (1) + { + c = readchar (timeout); + notice_quit (); + if (quit_flag == 1) + { + if (ctrl_c) + { + putchar_e7000(CTRLC); + --ctrl_c; + } + else + { + quit (); + } + } + + if (c == SERIAL_ERROR) + { + error ("Serial communication error"); + } + if (echo || remote_debug) + { + if (c == '\r' || c == '\n') + { + if (!nl) + putchar ('\n'); + nl = 1; + } + else + { + nl = 0; + putchar (c); + } + fflush (stdout); + } + if (normal (c) == normal (*p++)) + { + if (*p == '\0') + return; + } + else + { + p = string; + + if (normal (c) == normal (string[0])) + p++; + } + } +} + +/* Keep discarding input until we see the e7000 prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line will + be an expect_prompt(). Exception: e7000_resume does not wait for + the prompt, because the terminal is being handed over to the + inferior. However, the next thing which happens after that is a + e7000_wait which does wait for the prompt. Note that this includes + abnormal exit, e.g. error(). This is necessary to prevent getting + into states from which we can't recover. */ + +static void +expect_prompt () +{ + expect (":"); +} + +static void +expect_full_prompt () +{ + expect ("\r:"); +} + +static int +convert_hex_digit (ch) + int ch; +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + return -1; +} + +static int +get_hex (start) + int *start; +{ + int value = convert_hex_digit (*start); + int try; + + *start = readchar (timeout); + while ((try = convert_hex_digit (*start)) >= 0) + { + value <<= 4; + value += try; + *start = readchar (timeout); + } + return value; +} + +#if 0 +/* Get N 32-bit words from remote, each preceded by a space, and put + them in registers starting at REGNO. */ + +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + int i; + + for (i = 0; i < n; i++) + { + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + supply_register (regno++, (char *) &val); + } +} +#endif + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ + +static void +e7000_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error ("Can't pass arguments to remote E7000DEBUG process"); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + +#ifdef CREATE_INFERIOR_HOOK + CREATE_INFERIOR_HOOK (0); /* No process-ID */ +#endif + + /* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* insert_step_breakpoint (); FIXME, do we need this? */ + proceed ((CORE_ADDR) entry_pt, -1, 0); /* Let 'er rip... */ +} + +/* Open a connection to a remote debugger. NAME is the filename used + for communication. */ + +static int baudrate = 9600; +static char dev_name[100]; + +static char *machine = ""; +static char *user = ""; +static char *passwd = ""; +static char *dir = ""; + +/* Grab the next token and buy some space for it */ + +static char * +next (ptr) + char **ptr; +{ + char *p = *ptr; + char *s; + char *r; + int l = 0; + + while (*p && *p == ' ') + p++; + s = p; + while (*p && (*p != ' ' && *p != '\t')) + { + l++; + p++; + } + r = xmalloc (l + 1); + memcpy (r, s, l); + r[l] = 0; + *ptr = p; + return r; +} + +static void +e7000_login_command (args, from_tty) + char *args; + int from_tty; +{ + if (args) + { + machine = next (&args); + user = next (&args); + passwd = next (&args); + dir = next (&args); + if (from_tty) + { + printf ("Set info to %s %s %s %s\n", machine, user, passwd, dir); + } + } + else + { + error ("Syntax is ftplogin "); + } +} + +/* Start an ftp transfer from the E7000 to a host */ + +static void +e7000_ftp_command (args, from_tty) + char *args; + int from_tty; +{ + /* FIXME: arbitrary limit on machine names and such. */ + char buf[200]; + + int oldtimeout = timeout; + timeout = 10; + + sprintf (buf, "ftp %s\r", machine); + puts_e7000debug (buf); + expect (" Username : "); + sprintf (buf, "%s\r", user); + puts_e7000debug (buf); + expect (" Password : "); + write_e7000 (passwd); + write_e7000 ("\r"); + expect ("success\r"); + expect ("FTP>"); + sprintf (buf, "cd %s\r", dir); + puts_e7000debug (buf); + expect ("FTP>"); + sprintf (buf, "ll 0;s:%s\r", args); + puts_e7000debug (buf); + expect ("FTP>"); + puts_e7000debug ("bye\r"); + expect (":"); + timeout = oldtimeout; +} + +static void +e7000_open (args, from_tty) + char *args; + int from_tty; +{ + int n; + int loop; + char junk[100]; + int sync; + target_preopen (from_tty); + + n = 0; + if (args && strcasecmp (args, "pc") == 0) + { + strcpy (dev_name, args); + } + else + { + if (args) + { + n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk); + } + + if (n != 1 && n != 2) + { + error ("Bad arguments. Usage:\ttarget e7000 \n\ +or \t\ttarget e7000 [:]\n\ +or \t\ttarget e7000 pc\n"); + } + +#ifndef __GO32__ + if (n == 1 && strchr (dev_name, ':') == 0) + { + /* Default to normal telnet port */ + strcat (dev_name, ":23"); + } +#endif + } + + push_target (&e7000_ops); + + e7000_desc = SERIAL_OPEN (dev_name); + + if (!e7000_desc) + perror_with_name (dev_name); + + using_tcp = strcmp (e7000_desc->ops->name, "tcp") == 0; + using_pc = strcmp (e7000_desc->ops->name, "pc") == 0; + + SERIAL_SETBAUDRATE (e7000_desc, baudrate); + SERIAL_RAW (e7000_desc); + + /* Hello? Are you there? */ + sync = 0; + loop = 0; + putchar_e7000 (CTRLC); + while (!sync) + { + int c; + + if (from_tty) + printf_unfiltered ("[waiting for e7000...]\n"); + + write_e7000 ("\r"); + c = SERIAL_READCHAR (e7000_desc, 1); + while (c != SERIAL_TIMEOUT) + { + /* Dont echo cr's */ + if (from_tty && c != '\r') + { + putchar (c); + fflush (stdout); + } + if (c == ':') + sync = 1; + + if (loop++ == 20) + { + putchar_e7000 (CTRLC); + loop = 0; + } + + QUIT ; + + + if (quit_flag) + { + putchar_e7000 (CTRLC); + quit_flag = 0; + } + c = SERIAL_READCHAR (e7000_desc, 1); + } + } + puts_e7000debug ("\r"); + + expect_prompt (); + + puts_e7000debug ("b -\r"); + + expect_prompt (); + + if (from_tty) + printf_filtered ("Remote target %s connected to %s\n", target_shortname, + dev_name); + +#ifdef GDB_TARGET_IS_H8300 + h8300hmode = 1; +#endif +} + +/* Close out all files and local state before this target loses control. */ + +static void +e7000_close (quitting) + int quitting; +{ + if (e7000_desc) + { + SERIAL_CLOSE (e7000_desc); + e7000_desc = 0; + } +} + +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ + +static void +e7000_detach (from_tty) + int from_tty; +{ + pop_target (); /* calls e7000_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* Tell the remote machine to resume. */ + +static void +e7000_resume (pid, step, sig) + int pid, step, sig; +{ + if (step) + puts_e7000debug ("S\r"); + else + puts_e7000debug ("G\r"); +} + +/* Read the remote registers into the block REGS. + + For the H8/300 a register dump looks like: + + PC=00021A CCR=80:I******* + ER0 - ER3 0000000A 0000002E 0000002E 00000000 + ER4 - ER7 00000000 00000000 00000000 00FFEFF6 + 000218 MOV.B R1L,R2L + STEP NORMAL END or + BREAK POINT + */ + +#ifdef GDB_TARGET_IS_H8300 + +char *want = "PC=%p CCR=%c\n\ + ER0 - ER3 %0 %1 %2 %3\n\ + ER4 - ER7 %4 %5 %6 %7\n"; + +char *want_nopc = "%p CCR=%c\n\ + ER0 - ER3 %0 %1 %2 %3\n\ + ER4 - ER7 %4 %5 %6 %7"; + +#endif + +#ifdef GDB_TARGET_IS_SH + +char *want = "PC=%16 SR=%22\n\ +PR=%17 GBR=%18 VBR=%19\n\ +MACH=%20 MACL=%21\n\ +R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ +R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n"; + +char *want_nopc = "%16 SR=%22\n\ + PR=%17 GBR=%18 VBR=%19\n\ + MACH=%20 MACL=%21\n\ + R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ + R8-15 %8 %9 %10 %11 %12 %13 %14 %15"; + +#endif + +static int +gch () +{ + int c = readchar (timeout); + + if (remote_debug) + { + if (c >= ' ') + printf ("%c", c); + else if (c == '\n') + printf ("\n"); + } + return c; +} + +static unsigned int +gbyte () +{ + int high = convert_hex_digit (gch ()); + int low = convert_hex_digit (gch ()); + + return (high << 4) + low; +} + +void +fetch_regs_from_dump (nextchar, want) + int (*nextchar)(); + char *want; +{ + int regno; + char buf[MAX_REGISTER_RAW_SIZE]; + + int thischar = nextchar (); + + while (*want) + { + switch (*want) + { + case '\n': + /* Skip to end of line and then eat all new line type stuff */ + while (thischar != '\n' && thischar != '\r') + thischar = nextchar (); + while (thischar == '\n' || thischar == '\r') + thischar = nextchar (); + want++; + break; + + case ' ': + while (thischar == ' ' + || thischar == '\t' + || thischar == '\r' + || thischar == '\n') + thischar = nextchar (); + want++; + break; + + default: + if (*want == thischar) + { + want++; + if (*want) + thischar = nextchar (); + + } + else if (thischar == ' ' || thischar == '\n' || thischar == '\r') + { + thischar = nextchar (); + } + else { + error ("out of sync in fetch registers wanted <%s>, got <%c 0x%x>", + want, thischar, thischar); + } + + break; + case '%': + /* Got a register command */ + want++; + switch (*want) + { +#ifdef PC_REGNUM + case 'p': + regno = PC_REGNUM; + want++; + break; +#endif +#ifdef CCR_REGNUM + case 'c': + regno = CCR_REGNUM; + want++; + break; +#endif +#ifdef SP_REGNUM + case 's': + regno = SP_REGNUM; + want++; + break; +#endif +#ifdef FP_REGNUM + case 'f': + regno = FP_REGNUM; + want++; + break; +#endif + + default: + if (isdigit (want[0])) + { + if (isdigit (want[1])) + { + regno = (want[0] - '0') * 10 + want[1] - '0'; + want += 2; + } + else + { + regno = want[0] - '0'; + want++; + } + } + + else + abort (); + } + store_signed_integer (buf, + REGISTER_RAW_SIZE(regno), + (LONGEST) get_hex (&thischar, nextchar)); + supply_register (regno, buf); + break; + } + } +} + +static void +e7000_fetch_registers () +{ + int regno; + + puts_e7000debug ("R\r"); + fetch_regs_from_dump (gch, want); + + /* And supply the extra ones the simulator uses */ + for (regno = NUM_REALREGS; regno < NUM_REGS; regno++) + { + int buf = 0; + + supply_register (regno, (char *) (&buf)); + } +} + +/* Fetch register REGNO, or all registers if REGNO is -1. Returns + errno value. */ + +static void +e7000_fetch_register (regno) + int regno; +{ + e7000_fetch_registers (); +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +e7000_store_registers () +{ + int regno; + + for (regno = 0; regno < NUM_REALREGS; regno++) + e7000_store_register (regno); + + registers_changed (); +} + +/* Store register REGNO, or all if REGNO == 0. Return errno value. */ + +static void +e7000_store_register (regno) + int regno; +{ + char buf[200]; + + if (regno == -1) + { + e7000_store_registers (); + return; + } + +#ifdef GDB_TARGET_IS_H8300 + if (regno <= 7) + { + sprintf (buf, ".ER%d %x\r", regno, read_register (regno)); + puts_e7000debug (buf); + } + else if (regno == PC_REGNUM) + { + sprintf (buf, ".PC %x\r", read_register (regno)); + puts_e7000debug (buf); + } + else if (regno == CCR_REGNUM) + { + sprintf (buf, ".CCR %x\r", read_register (regno)); + puts_e7000debug (buf); + } +#endif /* GDB_TARGET_IS_H8300 */ + +#ifdef GDB_TARGET_IS_SH + switch (regno) + { + default: + sprintf (buf, ".R%d %x\r", regno, read_register (regno)); + puts_e7000debug (buf); + break; + + case PC_REGNUM: + sprintf (buf, ".PC %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case SR_REGNUM: + sprintf (buf, ".SR %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case PR_REGNUM: + sprintf (buf, ".PR %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case GBR_REGNUM: + sprintf (buf, ".GBR %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case VBR_REGNUM: + sprintf (buf, ".VBR %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case MACH_REGNUM: + sprintf (buf, ".MACH %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + + case MACL_REGNUM: + sprintf (buf, ".MACL %x\r", read_register (regno)); + puts_e7000debug (buf); + break; + } + +#endif /* GDB_TARGET_IS_SH */ + + expect_prompt (); +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +e7000_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static void +e7000_files_info () +{ + printf ("\tAttached to %s at %d baud.\n", dev_name, baudrate); +} + +static int +stickbyte (where, what) + char *where; + unsigned int what; +{ + static CONST char digs[] = "0123456789ABCDEF"; + + where[0] = digs[(what >> 4) & 0xf]; + where[1] = digs[(what & 0xf) & 0xf]; + + return what; +} + +/* Write a small ammount of memory. */ + +static int +write_small (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int i; + char buf[200]; + + for (i = 0; i < len; i++) + { + if (((memaddr + i) & 3) == 0 && (i + 3 < len)) + { + /* Can be done with a long word */ + sprintf (buf, "m %x %x%02x%02x%02x;l\r", + memaddr + i, + myaddr[i], myaddr[i + 1], myaddr[i + 2], myaddr[i + 3]); + puts_e7000debug (buf); + i += 3; + } + else + { + sprintf (buf, "m %x %x\r", memaddr + i, myaddr[i]); + puts_e7000debug (buf); + } + } + + expect_prompt (); + + return len; +} + +/* Write a large ammount of memory, this only works with the serial + mode enabled. Command is sent as + + il ;s:s\r -> + <- il ;s:s\r + <- ENQ + ACK -> + <- LO s\r + Srecords... + ^Z -> + <- ENQ + ACK -> + <- : + */ + +static int +write_large (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int i; +#define maxstride 128 + int stride; + + puts_e7000debug ("IL ;S:FK\r"); + expect (ENQSTRING); + putchar_e7000 (ACK); + expect ("LO FK\r"); + + for (i = 0; i < len; i += stride) + { + char compose[maxstride * 2 + 50]; + int address = i + memaddr; + int j; + int check_sum; + int where = 0; + int alen; + + stride = len - i; + if (stride > maxstride) + stride = maxstride; + + compose[where++] = 'S'; + check_sum = 0; + if (address >= 0xffffff) + alen = 4; + else if (address >= 0xffff) + alen = 3; + else + alen = 2; + /* Insert type. */ + compose[where++] = alen - 1 + '0'; + /* Insert length. */ + check_sum += stickbyte (compose + where, alen + stride + 1); + where += 2; + while (alen > 0) + { + alen--; + check_sum += stickbyte (compose + where, address >> (8 * (alen))); + where += 2; + } + + for (j = 0; j < stride; j++) + { + check_sum += stickbyte (compose + where, myaddr[i + j]); + where += 2; + } + stickbyte (compose + where, ~check_sum); + where += 2; + compose[where++] = '\r'; + compose[where++] = '\n'; + compose[where++] = 0; + + SERIAL_WRITE (e7000_desc, compose, where); + j = SERIAL_READCHAR (e7000_desc, 0); + if (j == SERIAL_TIMEOUT) + { + /* This is ok - nothing there */ + } + else if (j == ENQ) + { + /* Hmm, it's trying to tell us something */ + expect (":"); + error ("Error writing memory"); + } + else + { + printf ("@%d}@", j); + while ((j = SERIAL_READCHAR(e7000_desc,0)) > 0) + { + printf ("@{%d}@",j); + } + } + } + + /* Send the trailer record */ + write_e7000 ("S70500000000FA\r"); + putchar_e7000 (CTRLZ); + expect (ENQSTRING); + putchar_e7000 (ACK); + expect (":"); + + return len; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's + memory at MEMADDR. Returns length moved. + + Can't use the Srecord load over ethernet, so don't use fast method + then. */ + +static int +e7000_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + if (len < 16 || using_tcp || using_pc) + return write_small (memaddr, myaddr, len); + else + return write_large (memaddr, myaddr, len); +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns length moved. + + Small transactions we send + m ;l + and receive + 00000000 12345678 ? + */ + +static int +e7000_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int count; + int c; + int i; + char buf[200]; + /* Starting address of this pass. */ + +/* printf("READ INF %x %x %d\n", memaddr, myaddr, len);*/ + if (((memaddr - 1) + len) < memaddr) + { + errno = EIO; + return 0; + } + + sprintf (buf, "m %x;l\r", memaddr); + puts_e7000debug (buf); + + for (count = 0; count < len; count += 4) + { + /* Suck away the address */ + c = gch (); + while (c != ' ') + c = gch (); + c = gch (); + if (c == '*') + { /* Some kind of error */ + expect_prompt(); + return -1; + } + while (c != ' ') + c = gch (); + + /* Now read in the data */ + for (i = 0; i < 4; i++) + { + int b = gbyte(); + if (count + i < len) { + myaddr[count + i] = b; + } + } + + /* Skip the trailing ? and send a . to end and a cr for more */ + gch (); + gch (); + if (count + 4 >= len) + puts_e7000debug(".\r"); + else + puts_e7000debug("\r"); + + } + expect_prompt(); + return len; +} + + +#if 0 +/* + For large transfers we used to send + + + d \r + + and receive + < D A T A > < ASCII CODE > + 000000 5F FD FD FF DF 7F DF FF 01 00 01 00 02 00 08 04 "_..............." + 000010 FF D7 FF 7F D7 F1 7F FF 00 05 00 00 08 00 40 00 "..............@." + 000020 7F FD FF F7 7F FF FF F7 00 00 00 00 00 00 00 00 "................" + + A cost in chars for each transaction of 80 + 5*n-bytes. + + Large transactions could be done with the srecord load code, but + there is a pause for a second before dumping starts, which slows the + average rate down! +*/ + +static int +e7000_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int count; + int c; + char buf[200]; + + /* Starting address of this pass. */ + + if (((memaddr - 1) + len) < memaddr) + { + errno = EIO; + return 0; + } + + sprintf (buf, "d %x %x\r", memaddr, memaddr + len - 1); + puts_e7000debug (buf); + + count = 0; + c = gch (); + + /* First skip the command */ + while (c == '\n') + c = gch (); + + while (c == ' ') + c = gch (); + if (c == '*') + { + expect ("\r"); + return -1; + } + + /* Skip the title line */ + while (c != '\n') + c = gch (); + c = gch (); + while (count < len) + { + /* Skip the address */ + while (c <= ' ') + c = gch (); + + get_hex (&c); + + /* read in the bytes on the line */ + while (c != '"' && count < len) + { + if (c == ' ') + c = gch (); + else + { + myaddr[count++] = get_hex (&c); + } + } + + while (c != '\n') + c = gch (); + } + + while (c != ':') + c = gch (); + + return len; +} + +static int +fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int loop; + int c; + char buf[200]; + + if (((memaddr - 1) + len) < memaddr) + { + errno = EIO; + return 0; + } + + sprintf (buf, "is %x@%x:s\r", memaddr, len); + puts_e7000debug (buf); + gch (); + c = gch (); + if (c != ENQ) + { + /* Got an error */ + error ("Memory read error"); + } + putchar_e7000 (ACK); + expect ("SV s"); + loop = 1; + while (loop) + { + int type; + int length; + int addr; + int i; + + c = gch (); + switch (c) + { + case ENQ: /* ENQ, at the end */ + loop = 0; + break; + case 'S': + /* Start of an Srecord */ + type = gch (); + length = gbyte (); + switch (type) + { + case '7': /* Termination record, ignore */ + case '0': + case '8': + case '9': + /* Header record - ignore it */ + while (length--) + { + gbyte (); + } + break; + case '1': + case '2': + case '3': + { + int alen; + + alen = type - '0' + 1; + addr = 0; + while (alen--) + { + addr = (addr << 8) + gbyte (); + length--; + } + + for (i = 0; i < length - 1; i++) + myaddr[i + addr - memaddr] = gbyte (); + + gbyte (); /* Ignore checksum */ + } + } + } + } + + putchar_e7000 (ACK); + expect ("TOP ADDRESS ="); + expect ("END ADDRESS ="); + expect (":"); + + return len; +} + +#endif + +static int +e7000_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (write) + return e7000_write_inferior_memory( memaddr, myaddr, len); + else + return e7000_read_inferior_memory( memaddr, myaddr, len); +} + +static void +e7000_kill (args, from_tty) + char *args; + int from_tty; +{ +} + +static void +e7000_load (args, from_tty) + char *args; + int from_tty; +{ + struct cleanup *old_chain; + asection *section; + bfd *pbfd; + bfd_vma entry; + int i; +#define WRITESIZE 0x1000 + char buf[2 + 4 + 4 + WRITESIZE]; /* `DT' + + + */ + char *filename; + int quiet; + int nostart; + time_t start_time, end_time; /* Start and end times of download */ + unsigned long data_count; /* Number of bytes transferred to memory */ + + if (!strchr (dev_name, ':')) + { + generic_load (args, from_tty); + return; + } + + buf[0] = 'D'; + buf[1] = 'T'; + quiet = 0; + nostart = 0; + filename = NULL; + + while (*args != '\000') + { + char *arg; + + while (isspace (*args)) args++; + + arg = args; + + while ((*args != '\000') && !isspace (*args)) args++; + + if (*args != '\000') + *args++ = '\000'; + + if (*arg != '-') + filename = arg; + else if (strncmp (arg, "-quiet", strlen (arg)) == 0) + quiet = 1; + else if (strncmp (arg, "-nostart", strlen (arg)) == 0) + nostart = 1; + else + error ("unknown option `%s'", arg); + } + + if (!filename) + filename = get_exec_file (1); + + pbfd = bfd_openr (filename, gnutarget); + if (pbfd == NULL) + { + perror_with_name (filename); + return; + } + old_chain = make_cleanup (bfd_close, pbfd); + + if (!bfd_check_format (pbfd, bfd_object)) + error ("\"%s\" is not an object file: %s", filename, + bfd_errmsg (bfd_get_error ())); + + start_time = time (NULL); + data_count = 0; + + puts_e7000debug ("mw\r"); + + expect ("\nOK"); + + for (section = pbfd->sections; section; section = section->next) + { + if (bfd_get_section_flags (pbfd, section) & SEC_LOAD) + { + bfd_vma section_address; + bfd_size_type section_size; + file_ptr fptr; + + section_address = bfd_get_section_vma (pbfd, section); + section_size = bfd_get_section_size_before_reloc (section); + + if (!quiet) + printf_filtered ("[Loading section %s at 0x%x (%d bytes)]\n", + bfd_get_section_name (pbfd, section), + section_address, + section_size); + + fptr = 0; + + data_count += section_size; + + while (section_size > 0) + { + int count; + static char inds[] = "|/-\\"; + static int k = 0; + + QUIT; + + count = min (section_size, WRITESIZE); + + buf[2] = section_address >> 24; + buf[3] = section_address >> 16; + buf[4] = section_address >> 8; + buf[5] = section_address; + + buf[6] = count >> 24; + buf[7] = count >> 16; + buf[8] = count >> 8; + buf[9] = count; + + bfd_get_section_contents (pbfd, section, buf + 10, fptr, count); + + if (SERIAL_WRITE (e7000_desc, buf, count + 10)) + fprintf_unfiltered (gdb_stderr, + "e7000_load: SERIAL_WRITE failed: %s\n", + safe_strerror(errno)); + + expect ("OK"); + + if (!quiet) + { + printf_unfiltered ("\r%c", inds[k++ % 4]); + gdb_flush (gdb_stdout); + } + + section_address += count; + fptr += count; + section_size -= count; + } + } + } + + write_e7000 ("ED"); + + expect_prompt (); + + end_time = time (NULL); + +/* Finally, make the PC point at the start address */ + + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_pid = 0; /* No process now */ + +/* This is necessary because many things were based on the PC at the time that + we attached to the monitor, which is no longer valid now that we have loaded + new code (and just changed the PC). Another way to do this might be to call + normal_stop, except that the stack may not be valid, and things would get + horribly confused... */ + + clear_symtab_users (); + + if (!nostart) + { + entry = bfd_get_start_address (pbfd); + + if (!quiet) + printf_unfiltered ("[Starting %s at 0x%x]\n", filename, entry); + +/* start_routine (entry);*/ + } + + printf_filtered ("Transfer rate: %d bits/sec.\n", + (data_count * 8)/(end_time - start_time)); + + do_cleanups (old_chain); +} + +/* Clean up when a program exits. + + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +static void +e7000_mourn_inferior () +{ + remove_breakpoints (); + unpush_target (&e7000_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +#ifdef HARD_BREAKPOINTS +#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 : 200) +#else +#define MAX_E7000DEBUG_BREAKPOINTS 200 +#endif + +extern int memory_breakpoint_size; + +static CORE_ADDR breakaddr[MAX_E7000DEBUG_BREAKPOINTS] = {0}; + +static int +e7000_insert_breakpoint (addr, shadow) + CORE_ADDR addr; + unsigned char *shadow; +{ + int i; + char buf[200]; + static char nop[2] = NOP; + + for (i = 0; i <= MAX_E7000DEBUG_BREAKPOINTS; i++) + if (breakaddr[i] == 0) + { + breakaddr[i] = addr; + /* Save old contents, and insert a nop in the space */ +#ifdef HARD_BREAKPOINTS + if (BC_BREAKPOINTS) + { + sprintf (buf, "BC%d A=%x\r", i+1, addr); + puts_e7000debug (buf); + } + else + { + sprintf (buf, "B %x\r", addr); + puts_e7000debug (buf); + } +#else +#if 0 + e7000_read_inferior_memory (addr, shadow, 2); + e7000_write_inferior_memory (addr, nop, 2); +#endif + + sprintf (buf, "B %x\r", addr); + puts_e7000debug (buf); +#endif + expect_prompt (); + return 0; + } + + error ("Too many breakpoints ( > %d) for the E7000\n", + MAX_E7000DEBUG_BREAKPOINTS); + return 1; +} + +static int +e7000_remove_breakpoint (addr, shadow) + CORE_ADDR addr; + unsigned char *shadow; +{ + int i; + char buf[200]; + + for (i = 0; i < MAX_E7000DEBUG_BREAKPOINTS; i++) + if (breakaddr[i] == addr) + { + breakaddr[i] = 0; +#ifdef HARD_BREAKPOINTS + if (BC_BREAKPOINTS) + { + sprintf (buf, "BC%d - \r", i+1); + puts_e7000debug (buf); + } + else + { + sprintf (buf, "B - %x\r", addr); + puts_e7000debug (buf); + } + expect_prompt (); +#else + sprintf (buf, "B - %x\r", addr); + puts_e7000debug (buf); + expect_prompt (); + +#if 0 + /* Replace the insn under the break */ + e7000_write_inferior_memory (addr, shadow, 2); +#endif +#endif + + return 0; + } + + warning ("Can't find breakpoint associated with 0x%x\n", addr); + return 1; +} + +/* Put a command string, in args, out to STDBUG. Output from STDBUG + is placed on the users terminal until the prompt is seen. */ + +static void +e7000_command (args, fromtty) + char *args; + int fromtty; +{ + /* FIXME: arbitrary limit on length of args. */ + char buf[200]; + + echo = 0; + + if (!e7000_desc) + error ("e7000 target not open."); + if (!args) + { + puts_e7000debug ("\r"); + } + else + { + sprintf (buf, "%s\r", args); + puts_e7000debug (buf); + } + + echo++; + ctrl_c = 2; + expect_full_prompt (); + echo--; + ctrl_c = 0; + printf_unfiltered ("\n"); + + /* Who knows what the command did... */ + registers_changed (); +} + + +static void +e7000_drain_command (args, fromtty) + char *args; + int fromtty; + +{ + int c; + + puts_e7000debug("end\r"); + putchar_e7000 (CTRLC); + + while ((c = SERIAL_READCHAR (e7000_desc, 1) != SERIAL_TIMEOUT)) + { + if (quit_flag) + { + putchar_e7000(CTRLC); + quit_flag = 0; + } + if (c > ' ' && c < 127) + printf ("%c", c & 0xff); + else + printf ("<%x>", c & 0xff); + } +} + +#define NITEMS 7 + +static int +why_stop () +{ + static char *strings[NITEMS] = { + "STEP NORMAL", + "BREAK POINT", + "BREAK KEY", + "BREAK CONDI", + "CYCLE ACCESS", + "ILLEGAL INSTRUCTION", + "WRITE PROTECT", + }; + char *p[NITEMS]; + int c; + int i; + + for (i = 0; i < NITEMS; ++i) + p[i] = strings[i]; + + c = gch (); + while (1) + { + for (i = 0; i < NITEMS; i++) + { + if (c == *(p[i])) + { + p[i]++; + if (*(p[i]) == 0) + { + /* found one of the choices */ + return i; + } + } + else + p[i] = strings[i]; + } + + c = gch (); + } +} + +/* Suck characters, if a string match, then return the strings index + otherwise echo them. */ + +int +expect_n (strings) +char **strings; +{ + char *(ptr[10]); + int n; + int c; + char saveaway[100]; + char *buffer = saveaway; + /* Count number of expect strings */ + + for (n = 0; strings[n]; n++) + { + ptr[n] = strings[n]; + } + + while (1) + { + int i; + int gotone = 0; + + c = SERIAL_READCHAR (e7000_desc, 1); + if (c == SERIAL_TIMEOUT) + { + printf_unfiltered ("[waiting for e7000...]\n"); + } +#ifdef __GO32__ + if (kbhit ()) + { + int k = getkey(); + + if (k == 1) + quit_flag = 1; + } +#endif + if (quit_flag) + { + putchar_e7000 (CTRLC); /* interrupt the running program */ + quit_flag = 0; + } + + for (i = 0; i < n; i++) + { + if (c == ptr[i][0]) + { + ptr[i]++; + if (ptr[i][0] == 0) + { + /* Gone all the way */ + return i; + } + gotone = 1; + } + else + { + ptr[i] = strings[i]; + } + } + + if (gotone) + { + /* Save it up incase we find that there was no match */ + *buffer ++ = c; + } + else + { + if (buffer != saveaway) + { + *buffer++ = 0; + printf ("%s", buffer); + buffer = saveaway; + } + if (c != SERIAL_TIMEOUT) + { + putchar (c); + fflush (stdout); + } + } + } +} + +/* We subtract two from the pc here rather than use + DECR_PC_AFTER_BREAK since the e7000 doesn't always add two to the + pc, and the simulators never do. */ + +static void +sub2_from_pc () +{ + char buf[4]; + char buf2[200]; + + store_signed_integer (buf, + REGISTER_RAW_SIZE(PC_REGNUM), + read_register (PC_REGNUM) -2); + supply_register (PC_REGNUM, buf); + sprintf (buf2, ".PC %x\r", read_register (PC_REGNUM)); + puts_e7000debug (buf2); +} + +#define WAS_SLEEP 0 +#define WAS_INT 1 +#define WAS_RUNNING 2 +#define WAS_OTHER 3 + +static char *estrings[] = { + "** SLEEP", + "BREAK !", + "** PC", + "PC", + NULL +}; + +/* Wait until the remote machine stops, then return, storing status in + STATUS just as `wait' would. */ + +static int +e7000_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int stop_reason; + int regno; + int running_count = 0; + int had_sleep = 0; + int loop = 1; + + /* Then echo chars until PC= string seen */ + gch (); /* Drop cr */ + gch (); /* and space */ + + while (loop) + { + switch (expect_n (estrings)) + { + case WAS_OTHER: + /* how did this happen ? */ + loop = 0; + break; + case WAS_SLEEP: + had_sleep = 1; + putchar_e7000 (CTRLC); + loop = 0; + break; + case WAS_INT: + loop = 0; + break; + case WAS_RUNNING: + running_count++; + if (running_count == 20) + { + printf_unfiltered ("[running...]\n"); + running_count = 0; + } + break; + default: + /* error? */ + break; + } + } + + /* Skip till the PC= */ + expect ("="); + fetch_regs_from_dump (gch, want_nopc); + + /* And supply the extra ones the simulator uses */ + for (regno = NUM_REALREGS; regno < NUM_REGS; regno++) + { + int buf = 0; + supply_register (regno, (char *) &buf); + } + + stop_reason = why_stop (); + expect_full_prompt (); + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + + switch (stop_reason) + { + case 1: /* Breakpoint */ + write_pc (read_pc ()); /* PC is always off by 2 for breakpoints */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 0: /* Single step */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 2: /* Interrupt */ + if (had_sleep) + { + status->value.sig = TARGET_SIGNAL_TRAP; + sub2_from_pc (); + } + else + { + status->value.sig = TARGET_SIGNAL_INT; + } + break; + case 3: + break; + case 4: + printf_unfiltered ("a cycle address error?\n"); + status->value.sig = TARGET_SIGNAL_UNKNOWN; + break; + case 5: + status->value.sig = TARGET_SIGNAL_ILL; + break; + case 6: + status->value.sig = TARGET_SIGNAL_SEGV; + break; + case 7: /* Anything else (NITEMS + 1) */ + printf_unfiltered ("a write protect error?\n"); + status->value.sig = TARGET_SIGNAL_UNKNOWN; + break; + default: + /* Get the user's attention - this should never happen. */ + abort (); + } + + return 0; +} + +/* Define the target subroutine names. */ + +struct target_ops e7000_ops = +{ + "e7000", + "Remote Hitachi e7000 target", + "Use a remote Hitachi e7000 ICE connected by a serial line,\n\ +or a network connection.\n\ +Arguments are the name of the device for the serial line,\n\ +the speed to connect at in bits per second.\n\ +eg\n\ +target e7000 /dev/ttya 9600\n\ +target e7000 foobar", + e7000_open, /* to_open */ + e7000_close, /* to_close */ + 0, /* to_attach */ + e7000_detach, /* to_detach */ + e7000_resume, /* to_resume */ + e7000_wait, /* to_wait */ + e7000_fetch_register, /* to_fetch_registers */ + e7000_store_register, /* to_store_registers */ + e7000_prepare_to_store, /* to_prepare_to_store */ + e7000_xfer_inferior_memory, /* to_xfer_memory */ + e7000_files_info, /* to_files_info */ + e7000_insert_breakpoint, /* to_insert_breakpoint */ + e7000_remove_breakpoint, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + e7000_kill, /* to_kill */ + e7000_load, /* to_load */ + 0, /* to_lookup_symbol */ + e7000_create_inferior, /* to_create_inferior */ + e7000_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* next (unused) */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* to_sections */ + 0, /* to_sections_end */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_e7000 () +{ + add_target (&e7000_ops); + + add_com ("e7000 ", class_obscure, e7000_command, + "Send a command to the e7000 monitor."); + + add_com ("ftplogin ", class_obscure, e7000_login_command, + "Login to machine and change to directory."); + + add_com ("ftpload ", class_obscure, e7000_ftp_command, + "Fetch and load a file from previously described place."); + + add_com ("drain", class_obscure, e7000_drain_command, + "Drain pending e7000 text buffers."); +} diff --git a/contrib/gdb/gdb/remote-eb.c b/contrib/gdb/gdb/remote-eb.c new file mode 100644 index 000000000000..baa4d24b55df --- /dev/null +++ b/contrib/gdb/gdb/remote-eb.c @@ -0,0 +1,1009 @@ +/* Remote debugging interface for AMD 29000 EBMON on IBM PC, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is like remote.c but is for an esoteric situation-- + having a a29k board in a PC hooked up to a unix machine with + a serial line, and running ctty com1 on the PC, through which + the unix machine can run ebmon. Not to mention that the PC + has PC/NFS, so it can access the same executables that gdb can, + over the net in real time. */ + +#include "defs.h" +#include "gdb_string.h" + +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "wait.h" +#include "value.h" +#include +#include +#include +#include +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" + +extern struct target_ops eb_ops; /* Forward declaration */ + +static void eb_close(); + +#define LOG_FILE "eb.log" +#if defined (LOG_FILE) +FILE *log_file; +#endif + +static int timeout = 24; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + eb_open knows that we don't have a file open when the program + starts. */ +int eb_desc = -1; + +/* stream which is fdopen'd from eb_desc. Only valid when + eb_desc != -1. */ +FILE *eb_stream; + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ +static int +readchar () +{ + char buf; + + buf = '\0'; +#ifdef HAVE_TERMIO + /* termio does the timeout for us. */ + read (eb_desc, &buf, 1); +#else + alarm (timeout); + if (read (eb_desc, &buf, 1) < 0) + { + if (errno == EINTR) + error ("Timeout reading from remote system."); + else + perror_with_name ("remote"); + } + alarm (0); +#endif + + if (buf == '\0') + error ("Timeout reading from remote system."); +#if defined (LOG_FILE) + putc (buf & 0x7f, log_file); +#endif + return buf & 0x7f; +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +static void +expect (string) + char *string; +{ + char *p = string; + + immediate_quit = 1; + while (1) + { + if (readchar() == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + p = string; + } +} + +/* Keep discarding input until we see the ebmon prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: eb_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a eb_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt () +{ +#if defined (LOG_FILE) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush (log_file); +#endif + expect ("\n# "); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + while (1) + { + ch = readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from eb_desc and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Get N 32-bit words from remote, each preceded by a space, + and put them in registers starting at REGNO. */ +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + int i; + + for (i = 0; i < n; i++) + { + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + supply_register (regno++, (char *) &val); + } +} + +/* Called when SIGALRM signal sent due to alarm() timeout. */ +#ifndef HAVE_TERMIO + +#ifndef __STDC__ +#define volatile /**/ +#endif +volatile int n_alarms; + +void +eb_timer () +{ +#if 0 + if (kiodebug) + printf ("eb_timer called\n"); +#endif + n_alarms++; +} +#endif + +/* malloc'd name of the program on the remote system. */ +static char *prog_name = NULL; + +/* Nonzero if we have loaded the file ("yc") and not yet issued a "gi" + command. "gi" is supposed to happen exactly once for each "yc". */ +static int need_gi = 0; + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to eb_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +static void +eb_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error ("Can't pass arguments to remote EBMON process"); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + + { + /* OK, now read in the file. Y=read, C=COFF, D=no symbols + 0=start address, %s=filename. */ + + fprintf (eb_stream, "YC D,0:%s", prog_name); + + if (args != NULL) + fprintf(eb_stream, " %s", args); + + fprintf (eb_stream, "\n"); + fflush (eb_stream); + + expect_prompt (); + + need_gi = 1; + } + +/* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* insert_step_breakpoint (); FIXME, do we need this? */ + proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0); /* Let 'er rip... */ +} + +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +#ifndef B19200 +#define B19200 EXTA +#endif +#ifndef B38400 +#define B38400 EXTB +#endif + +struct {int rate, damn_b;} baudtab[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +int damn_b (rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) return baudtab[i].damn_b; + return B38400; /* Random */ +} + + +/* Open a connection to a remote debugger. + NAME is the filename used for communication, then a space, + then the name of the program as we should name it to EBMON. */ + +static int baudrate = 9600; +static char *dev_name; +void +eb_open (name, from_tty) + char *name; + int from_tty; +{ + TERMINAL sg; + + char *p; + + target_preopen (from_tty); + + /* Find the first whitespace character, it separates dev_name from + prog_name. */ + if (name == 0) + goto erroid; + + for (p = name; + *p != '\0' && !isspace (*p); p++) + ; + if (*p == '\0') +erroid: + error ("\ +Please include the name of the device for the serial port,\n\ +the baud rate, and the name of the program to run on the remote system."); + dev_name = alloca (p - name + 1); + strncpy (dev_name, name, p - name); + dev_name[p - name] = '\0'; + + /* Skip over the whitespace after dev_name */ + for (; isspace (*p); p++) + /*EMPTY*/; + + if (1 != sscanf (p, "%d ", &baudrate)) + goto erroid; + + /* Skip the number and then the spaces */ + for (; isdigit (*p); p++) + /*EMPTY*/; + for (; isspace (*p); p++) + /*EMPTY*/; + + if (prog_name != NULL) + free (prog_name); + prog_name = savestring (p, strlen (p)); + + eb_close (0); + + eb_desc = open (dev_name, O_RDWR); + if (eb_desc < 0) + perror_with_name (dev_name); + ioctl (eb_desc, TIOCGETP, &sg); +#ifdef HAVE_TERMIO + sg.c_cc[VMIN] = 0; /* read with timeout. */ + sg.c_cc[VTIME] = timeout * 10; + sg.c_lflag &= ~(ICANON | ECHO); + sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate); +#else + sg.sg_ispeed = damn_b (baudrate); + sg.sg_ospeed = damn_b (baudrate); + sg.sg_flags |= RAW | ANYP; + sg.sg_flags &= ~ECHO; +#endif + + ioctl (eb_desc, TIOCSETP, &sg); + eb_stream = fdopen (eb_desc, "r+"); + + push_target (&eb_ops); + if (from_tty) + printf ("Remote %s debugging %s using %s\n", target_shortname, + prog_name, dev_name); + +#ifndef HAVE_TERMIO +#ifndef NO_SIGINTERRUPT + /* Cause SIGALRM's to make reads fail with EINTR instead of resuming + the read. */ + if (siginterrupt (SIGALRM, 1) != 0) + perror ("eb_open: error in siginterrupt"); +#endif + + /* Set up read timeout timer. */ + if ((void (*)) signal (SIGALRM, eb_timer) == (void (*)) -1) + perror ("eb_open: error in signal"); +#endif + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); +#endif + + /* Hello? Are you there? */ + write (eb_desc, "\n", 1); + + expect_prompt (); +} + +/* Close out all files and local state before this target loses control. */ + +static void +eb_close (quitting) + int quitting; +{ + + /* Due to a bug in Unix, fclose closes not only the stdio stream, + but also the file descriptor. So we don't actually close + eb_desc. */ + if (eb_stream) + fclose (eb_stream); /* This also closes eb_desc */ + if (eb_desc >= 0) + /* close (eb_desc); */ + + /* Do not try to close eb_desc again, later in the program. */ + eb_stream = NULL; + eb_desc = -1; + +#if defined (LOG_FILE) + if (log_file) { + if (ferror (log_file)) + printf ("Error writing log file.\n"); + if (fclose (log_file) != 0) + printf ("Error closing log file.\n"); + } +#endif +} + +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +void +eb_detach (from_tty) + int from_tty; +{ + pop_target(); /* calls eb_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* Tell the remote machine to resume. */ + +void +eb_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + if (step) + { + write (eb_desc, "t 1,s\n", 6); + /* Wait for the echo. */ + expect ("t 1,s\r"); + /* Then comes a line containing the instruction we stepped to. */ + expect ("\n@"); + /* Then we get the prompt. */ + expect_prompt (); + + /* Force the next eb_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type + "continue" to see any. This should be fixed. */ + need_artificial_trap = 1; + } + else + { + if (need_gi) + { + need_gi = 0; + write (eb_desc, "gi\n", 3); + + /* Swallow the echo of "gi". */ + expect ("gi\r"); + } + else + { + write (eb_desc, "GR\n", 3); + /* Swallow the echo. */ + expect ("GR\r"); + } + } +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +int +eb_wait (status) + struct target_waitstatus *status; +{ + /* Strings to look for. '?' means match any single character. + Note that with the algorithm we use, the initial character + of the string cannot recur in the string, or we will not + find some cases of the string in the input. */ + + static char bpt[] = "Invalid interrupt taken - #0x50 - "; + /* It would be tempting to look for "\n[__exit + 0x8]\n" + but that requires loading symbols with "yc i" and even if + we did do that we don't know that the file has symbols. */ + static char exitmsg[] = "\n@????????I JMPTI GR121,LR0"; + char *bp = bpt; + char *ep = exitmsg; + + /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */ + char swallowed[50]; + /* Current position in swallowed. */ + char *swallowed_p = swallowed; + + int ch; + int ch_handled; + + int old_timeout = timeout; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + if (need_artificial_trap != 0) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + need_artificial_trap--; + return 0; + } + + timeout = 0; /* Don't time out -- user program is running. */ + while (1) + { + ch_handled = 0; + ch = readchar (); + if (ch == *bp) + { + bp++; + if (*bp == '\0') + break; + ch_handled = 1; + + *swallowed_p++ = ch; + } + else + bp = bpt; + + if (ch == *ep || *ep == '?') + { + ep++; + if (*ep == '\0') + break; + + if (!ch_handled) + *swallowed_p++ = ch; + ch_handled = 1; + } + else + ep = exitmsg; + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + for (p = swallowed; p < swallowed_p; ++p) + putc (*p, stdout); + swallowed_p = swallowed; + + putc (ch, stdout); + } + } + expect_prompt (); + if (*bp== '\0') + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + } + else + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + } + timeout = old_timeout; + + return 0; +} + +/* Return the name of register number REGNO + in the form input and output by EBMON. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char buf[80]; + if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + sprintf (buf, "GR%03d", regno - GR96_REGNUM + 96); + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + sprintf (buf, "LR%03d", regno - LR0_REGNUM); + else if (regno == Q_REGNUM) + strcpy (buf, "SR131"); + else if (regno >= BP_REGNUM && regno <= CR_REGNUM) + sprintf (buf, "SR%03d", regno - BP_REGNUM + 133); + else if (regno == ALU_REGNUM) + strcpy (buf, "SR132"); + else if (regno >= IPC_REGNUM && regno <= IPB_REGNUM) + sprintf (buf, "SR%03d", regno - IPC_REGNUM + 128); + else if (regno >= VAB_REGNUM && regno <= LRU_REGNUM) + sprintf (buf, "SR%03d", regno - VAB_REGNUM); + else if (regno == GR1_REGNUM) + strcpy (buf, "GR001"); + return buf; +} + +/* Read the remote registers into the block REGS. */ + +static void +eb_fetch_registers () +{ + int reg_index; + int regnum_index; + char tempbuf[10]; + int i; + +#if 0 + /* This should not be necessary, because one is supposed to read the + registers only when the inferior is stopped (at least with + ptrace() and why not make it the same for remote?). */ + /* ^A is the "normal character" used to make sure we are talking to EBMON + and not to the program being debugged. */ + write (eb_desc, "\001\n"); + expect_prompt (); +#endif + + write (eb_desc, "dw gr96,gr127\n", 14); + for (reg_index = 96, regnum_index = GR96_REGNUM; + reg_index < 128; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "GR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + + for (i = 0; i < 128; i += 32) + { + /* The PC has a tendency to hang if we get these + all in one fell swoop ("dw lr0,lr127"). */ + sprintf (tempbuf, "dw lr%d\n", i); + write (eb_desc, tempbuf, strlen (tempbuf)); + for (reg_index = i, regnum_index = LR0_REGNUM + i; + reg_index < i + 32; + reg_index += 4, regnum_index += 4) + { + sprintf (tempbuf, "LR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (4, regnum_index); + expect ("\n"); + } + } + + write (eb_desc, "dw sr133,sr133\n", 15); + expect ("SR133 "); + get_hex_regs (1, BP_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr134,sr134\n", 15); + expect ("SR134 "); + get_hex_regs (1, FC_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr135,sr135\n", 15); + expect ("SR135 "); + get_hex_regs (1, CR_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr131,sr131\n", 15); + expect ("SR131 "); + get_hex_regs (1, Q_REGNUM); + expect ("\n"); + + write (eb_desc, "dw sr0,sr14\n", 12); + for (reg_index = 0, regnum_index = VAB_REGNUM; + regnum_index <= LRU_REGNUM; + regnum_index += 4, reg_index += 4) + { + sprintf (tempbuf, "SR%03d ", reg_index); + expect (tempbuf); + get_hex_regs (reg_index == 12 ? 3 : 4, regnum_index); + expect ("\n"); + } + + /* There doesn't seem to be any way to get these. */ + { + int val = -1; + supply_register (FPE_REGNUM, (char *) &val); + supply_register (INTE_REGNUM, (char *) &val); + supply_register (FPS_REGNUM, (char *) &val); + supply_register (EXO_REGNUM, (char *) &val); + } + + write (eb_desc, "dw gr1,gr1\n", 11); + expect ("GR001 "); + get_hex_regs (1, GR1_REGNUM); + expect_prompt (); +} + +/* Fetch register REGNO, or all registers if REGNO is -1. + Returns errno value. */ +void +eb_fetch_register (regno) + int regno; +{ + if (regno == -1) + eb_fetch_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (eb_stream, "dw %s,%s\n", name, name); + expect (name); + expect (" "); + get_hex_regs (1, regno); + expect_prompt (); + } + return; +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +eb_store_registers () +{ + int i, j; + fprintf (eb_stream, "s gr1,%x\n", read_register (GR1_REGNUM)); + expect_prompt (); + + for (j = 0; j < 32; j += 16) + { + fprintf (eb_stream, "s gr%d,", j + 96); + for (i = 0; i < 15; ++i) + fprintf (eb_stream, "%x,", read_register (GR96_REGNUM + j + i)); + fprintf (eb_stream, "%x\n", read_register (GR96_REGNUM + j + 15)); + expect_prompt (); + } + + for (j = 0; j < 128; j += 16) + { + fprintf (eb_stream, "s lr%d,", j); + for (i = 0; i < 15; ++i) + fprintf (eb_stream, "%x,", read_register (LR0_REGNUM + j + i)); + fprintf (eb_stream, "%x\n", read_register (LR0_REGNUM + j + 15)); + expect_prompt (); + } + + fprintf (eb_stream, "s sr133,%x,%x,%x\n", read_register (BP_REGNUM), + read_register (FC_REGNUM), read_register (CR_REGNUM)); + expect_prompt (); + fprintf (eb_stream, "s sr131,%x\n", read_register (Q_REGNUM)); + expect_prompt (); + fprintf (eb_stream, "s sr0,"); + for (i = 0; i < 11; ++i) + fprintf (eb_stream, "%x,", read_register (VAB_REGNUM + i)); + fprintf (eb_stream, "%x\n", read_register (VAB_REGNUM + 11)); + expect_prompt (); +} + +/* Store register REGNO, or all if REGNO == 0. + Return errno value. */ +void +eb_store_register (regno) + int regno; +{ + if (regno == -1) + eb_store_registers (); + else + { + char *name = get_reg_name (regno); + fprintf (eb_stream, "s %s,%x\n", name, read_register (regno)); + /* Setting GR1 changes the numbers of all the locals, so + invalidate the register cache. Do this *after* calling + read_register, because we want read_register to return the + value that write_register has just stuffed into the registers + array, not the value of the register fetched from the + inferior. */ + if (regno == GR1_REGNUM) + registers_changed (); + expect_prompt (); + } +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +eb_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + + +/* FIXME-someday! Merge these two. */ +int +eb_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (write) + return eb_write_inferior_memory (memaddr, myaddr, len); + else + return eb_read_inferior_memory (memaddr, myaddr, len); +} + +void +eb_files_info () +{ + printf ("\tAttached to %s at %d baud and running program %s.\n", + dev_name, baudrate, prog_name); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns length moved. */ +int +eb_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + for (i = 0; i < len; i++) + { + if ((i % 16) == 0) + fprintf (eb_stream, "sb %x,", memaddr + i); + if ((i % 16) == 15 || i == len - 1) + { + fprintf (eb_stream, "%x\n", ((unsigned char *)myaddr)[i]); + expect_prompt (); + } + else + fprintf (eb_stream, "%x,", ((unsigned char *)myaddr)[i]); + } + return len; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns length moved. */ +int +eb_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + /* Number of bytes read so far. */ + int count; + + /* Starting address of this pass. */ + unsigned long startaddr; + + /* Number of bytes to read in this pass. */ + int len_this_pass; + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + eb_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len to memaddr and gets 0. */ + /* However, something like + eb_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + if (((memaddr - 1) + len) < memaddr) { + errno = EIO; + return 0; + } + + startaddr = memaddr; + count = 0; + while (count < len) + { + len_this_pass = 16; + if ((startaddr % 16) != 0) + len_this_pass -= startaddr % 16; + if (len_this_pass > (len - count)) + len_this_pass = (len - count); + + fprintf (eb_stream, "db %x,%x\n", startaddr, + (startaddr - 1) + len_this_pass); + expect ("\n"); + + /* Look for 8 hex digits. */ + i = 0; + while (1) + { + if (isxdigit (readchar ())) + ++i; + else + { + expect_prompt (); + error ("Hex digit expected from remote system."); + } + if (i >= 8) + break; + } + + expect (" "); + + for (i = 0; i < len_this_pass; i++) + get_hex_byte (&myaddr[count++]); + + expect_prompt (); + + startaddr += len_this_pass; + } + return len; +} + +static void +eb_kill (args, from_tty) + char *args; + int from_tty; +{ + return; /* Ignore attempts to kill target system */ +} + +/* Clean up when a program exits. + + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +void +eb_mourn_inferior () +{ + remove_breakpoints (); + unpush_target (&eb_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} +/* Define the target subroutine names */ + +struct target_ops eb_ops = { + "amd-eb", "Remote serial AMD EBMON target", + "Use a remote computer running EBMON connected by a serial line.\n\ +Arguments are the name of the device for the serial line,\n\ +the speed to connect at in bits per second, and the filename of the\n\ +executable as it exists on the remote computer. For example,\n\ + target amd-eb /dev/ttya 9600 demo", + eb_open, eb_close, + 0, eb_detach, eb_resume, eb_wait, + eb_fetch_register, eb_store_register, + eb_prepare_to_store, + eb_xfer_inferior_memory, eb_files_info, + 0, 0, /* Breakpoints */ + 0, 0, 0, 0, 0, /* Terminal handling */ + eb_kill, + generic_load, /* load */ + 0, /* lookup_symbol */ + eb_create_inferior, + eb_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_eb () +{ + add_target (&eb_ops); +} diff --git a/contrib/gdb/gdb/remote-es.c b/contrib/gdb/gdb/remote-es.c new file mode 100644 index 000000000000..b4e60ef0352d --- /dev/null +++ b/contrib/gdb/gdb/remote-es.c @@ -0,0 +1,2152 @@ +/* Memory-access and commands for remote es1800 processes, for GDB. + Copyright (C) 1988, 1992 Free Software Foundation, Inc. + + This file is added to GDB to make it possible to do debugging via an + ES-1800 emulator. The code was originally written by Johan Holmberg + TT/SJ Ericsson Telecom AB and later modified by Johan Henriksson + TT/SJ. It was modified for gdb 4.0 by TX/DK Jan Nordenand by TX/DKG + Harald Johansen. + +This file is part of GDB. + +GDB 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 1, or (at your option) +any later version. + +GDB 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. */ + + +/* Emulator communication protocol. + All values are encoded in ascii hex digits. + + Request +Command +Reply + read registers: +DR + - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - -- 6 - - 7 - +D = XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX +A = XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX + PC = XXXXXX SSP = XXXXXX USP = XXXXXX SR = XXXXXXXX + > +Each byte of register data is described by two hex digits. + + write regs +D0=XXXXXXXX + >D1=XXXXXXXX + >D2=XXXXXXXX + >D3=XXXXXXXX + >D4=XXXXXXXX + >D5=XXXXXXXX + >D6=XXXXXXXX + >D7=XXXXXXXX + >A0=XXXXXXXX + >A1=XXXXXXXX + >A2=XXXXXXXX + >A3=XXXXXXXX + >A4=XXXXXXXX + >A5=XXXXXXXX + >A6=XXXXXXXX + >A7=XXXXXXXX + >SR=XXXXXXXX + >PC=XXXXXX + > +Each byte of register data is described by two hex digits. + + read mem +@.BAA..AA +$FFFFFFXX + > +AA..AA is address, XXXXXXX is the contents + + write mem + @.BAA..AA=$XXXXXXXX + > +AA..AA is address, XXXXXXXX is data + + cont +PC=$AA..AA + >RBK +R> +AA..AA is address to resume. If AA..AA is omitted, resume at same address. + + step +PC=$AA..AA + >STP +R> +AA..AA is address to resume. If AA..AA is omitted, resume at same address. + + kill req +STP + > +*/ + + +#include +#include +#include +#include +#include +#include +#include "gdb_string.h" +#include +#include +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "command.h" +#include "remote-utils.h" +#include "gdbcore.h" +#include "serial.h" + +/* Prototypes for local functions */ + +static void +es1800_child_detach PARAMS ((char *, int)); + +static void +es1800_child_open PARAMS ((char *, int)); + +static void +es1800_transparent PARAMS ((char *, int)); + +static void +es1800_create_inferior PARAMS ((char *, char *, char **)); + +static void +es1800_load PARAMS ((char *, int)); + +static void +es1800_kill PARAMS ((void)); + +static int +verify_break PARAMS ((int)); + +static int +es1800_remove_breakpoint PARAMS ((CORE_ADDR, char *)); + +static int +es1800_insert_breakpoint PARAMS ((CORE_ADDR, char *)); + +static void +es1800_files_info PARAMS ((struct target_ops *)); + +static int +es1800_xfer_inferior_memory PARAMS ((CORE_ADDR, char *, int, int, + struct target_ops *)); + +static void +es1800_prepare_to_store PARAMS ((void)); + +static int es1800_wait PARAMS ((int, struct target_waitstatus *)); + +static void es1800_resume PARAMS ((int, int, enum target_signal)); + +static void +es1800_detach PARAMS ((char *, int)); + +static void +es1800_attach PARAMS ((char *, int)); + +static int +damn_b PARAMS ((char *)); + +static void +es1800_open PARAMS ((char *, int)); + +static void +es1800_timer PARAMS ((void)); + +static void +es1800_reset PARAMS ((char *)); + +static void +es1800_request_quit PARAMS ((void)); + +static int +readchar PARAMS ((void)); + +static void +expect PARAMS ((char *, int)); + +static void +expect_prompt PARAMS ((void)); + +static void +download PARAMS ((FILE *, int, int)); + +#if 0 +static void +bfd_copy PARAMS ((bfd *, bfd *)); +#endif + +static void +get_break_addr PARAMS ((int, CORE_ADDR *)); + +static int +fromhex PARAMS ((int)); + +static int +tohex PARAMS ((int)); + +static void +es1800_close PARAMS ((int)); + +static void +es1800_fetch_registers PARAMS ((void)); + +static void +es1800_fetch_register PARAMS ((int)); + +static void +es1800_store_register PARAMS ((int)); + +static void +es1800_read_bytes PARAMS ((CORE_ADDR, char *, int)); + +static void +es1800_write_bytes PARAMS ((CORE_ADDR, char *, int)); + +static void +send_with_reply PARAMS ((char *, char *, int)); + +static void +send_command PARAMS ((char *)); + +static void +send PARAMS ((char *)); + +static void +getmessage PARAMS ((char *, int)); + +static void +es1800_mourn_inferior PARAMS ((void)); + +static void +es1800_create_break_insn PARAMS ((char *, int)); + +static void +es1800_init_break PARAMS ((char *, int)); + +/* Local variables */ + +/* FIXME: Convert this to use "set remotedebug" instead. */ +#define LOG_FILE "es1800.log" +#if defined (LOG_FILE) +static FILE *log_file; +#endif + +extern struct target_ops es1800_ops; /* Forward decl */ +extern struct target_ops es1800_child_ops; /* Forward decl */ + +static int kiodebug; +static int timeout = 100; +static char *savename; /* Name of i/o device used */ +static serial_ttystate es1800_saved_ttystate; +static int es1800_fc_save; /* Save fcntl state */ + +/* indicates that the emulator uses 32-bit data-adress (68020-mode) + instead of 24-bit (68000 -mode) */ + +static int m68020; + +#define MODE (m68020 ? "M68020" : "M68000" ) +#define ES1800_BREAK_VEC (0xf) + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that + es1800_open knows that we don't have a file open when the program + starts. */ + +static serial_t es1800_desc = NULL; + +#define PBUFSIZ 1000 +#define HDRLEN sizeof("@.BAAAAAAAA=$VV\r") + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet. */ + +#define MAXBUFBYTES ((PBUFSIZ-150)*16/75 ) + +static int es1800_break_vec = 0; +static char es1800_break_insn[2]; +static long es1800_break_address; +static void (*old_sigint)(); /* Old signal-handler for sigint */ +static jmp_buf interrupt; + +/* Local signalhandler to allow breaking tranfers or program run. + Rely on global variables: old_sigint(), interrupt */ + +static void +es1800_request_quit () +{ + /* restore original signalhandler */ + signal (SIGINT, old_sigint); + longjmp (interrupt, 1); +} + + +/* Reset emulator. + Sending reset character(octal 32) to emulator. + quit - return to '(esgdb)' prompt or continue */ + +static void +es1800_reset (quit) + char *quit; +{ + char buf[80]; + + if (quit) + { + printf ("\nResetting emulator... "); + } + strcpy (buf, "\032"); + send (buf); + expect_prompt (); + if (quit) + { + error ("done\n"); + } +} + + +/* Open a connection to a remote debugger and push the new target + onto the stack. Check if the emulator is responding and find out + what kind of processor the emulator is connected to. + Initiate the breakpoint handling in the emulator. + + name - the filename used for communication (ex. '/dev/tta') + from_tty - says whether to be verbose or not */ + +static void +es1800_open (name, from_tty) + char *name; + int from_tty; +{ + char buf[PBUFSIZ]; + char *p; + int i, fcflag; + + m68020 = 0; + + if (!name) /* no device name given in target command */ + { + error_no_arg ("serial port device name"); + } + + target_preopen (from_tty); + es1800_close (0); + + /* open the device and configure it for communication */ + +#ifndef DEBUG_STDIN + + es1800_desc = SERIAL_OPEN (name); + if (es1800_desc == NULL) + { + perror_with_name (name); + } + savename = savestring (name, strlen (name)); + + es1800_saved_ttystate = SERIAL_GET_TTY_STATE (es1800_desc); + + if ((fcflag = fcntl (es1800_desc->fd, F_GETFL, 0)) == -1) + { + perror_with_name ("fcntl serial"); + } + es1800_fc_save = fcflag; + + fcflag = (fcflag & (FREAD | FWRITE)); /* mask out any funny stuff */ + if (fcntl (es1800_desc->fd, F_SETFL, fcflag) == -1) + { + perror_with_name ("fcntl serial"); + } + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (es1800_desc, baud_rate)) + { + SERIAL_CLOSE (es1800_desc); + perror_with_name (name); + } + } + + SERIAL_RAW (es1800_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (es1800_desc); + +#endif /* DEBUG_STDIN */ + + push_target (&es1800_ops); /* Switch to using remote target now */ + if (from_tty) + { + printf ("Remote ES1800 debugging using %s\n", name); + } + +#if defined (LOG_FILE) + + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + { + perror_with_name (LOG_FILE); + } + +#endif /* LOG_FILE */ + + /* Hello? Are you there?, also check mode */ + + /* send_with_reply( "DB 0 TO 1", buf, sizeof(buf)); */ + /* for (p = buf, i = 0; *p++ =='0';) */ /* count the number of zeros */ + /* i++; */ + + send ("\032"); + getmessage (buf, sizeof (buf)); /* send reset character */ + + if (from_tty) + { + printf ("Checking mode.... "); + } + /* m68020 = (i==8); */ /* if eight zeros then we are in m68020 mode */ + + /* What kind of processor am i talking to ?*/ + p = buf; + while (*p++ != '\n') {;} + while (*p++ != '\n') {;} + while (*p++ != '\n') {;} + for (i = 0; i < 20; i++, p++) {;} + m68020 = !strncmp (p, "68020", 5); + if (from_tty) + { + printf ("You are in %s(%c%c%c%c%c)-mode\n", MODE, p[0], p[1], p[2], + p[3], p[4]); + } + + /* if no init_break statement is present in .gdb file we have to check + whether to download a breakpoint routine or not */ + +#if 0 + if ((es1800_break_vec == 0) || (verify_break (es1800_break_vec) != 0) + && query ("No breakpoint routine in ES 1800 emulator!\nDownload a breakpoint routine to the emulator? ")) + { + CORE_ADDR memaddress; + printf ("Give the start address of the breakpoint routine: "); + scanf ("%li", &memaddress); + es1800_init_break ((es1800_break_vec ? es1800_break_vec : + ES1800_BREAK_VEC), memaddress); + } +#endif + +} + +/* Close out all files and local state before this target loses control. + quitting - are we quitting gdb now? */ + +static void +es1800_close (quitting) + int quitting; +{ + if (es1800_desc != NULL) + { + printf ("\nClosing connection to emulator...\n"); + if (SERIAL_SET_TTY_STATE (es1800_desc, es1800_saved_ttystate) < 0) + print_sys_errmsg ("warning: unable to restore tty state", errno); + fcntl (es1800_desc->fd, F_SETFL, es1800_fc_save); + SERIAL_CLOSE (es1800_desc); + es1800_desc = NULL; + } + if (savename != NULL) + { + free (savename); + } + savename = NULL; + +#if defined (LOG_FILE) + + if (log_file != NULL) + { + if (ferror (log_file)) + { + printf ("Error writing log file.\n"); + } + if (fclose (log_file) != 0) + { + printf ("Error closing log file.\n"); + } + log_file = NULL; + } + +#endif /* LOG_FILE */ + +} + +/* Attaches to a process on the target side + proc_id - the id of the process to be attached. + from_tty - says whether to be verbose or not */ + +static void +es1800_attach (args, from_tty) + char *args; + int from_tty; +{ + error ("Cannot attach to pid %s, this feature is not implemented yet.", + args); +} + + +/* Takes a program previously attached to and detaches it. + We better not have left any breakpoints + in the program or it'll die when it hits one. + Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. + + args - arguments given to the 'detach' command + from_tty - says whether to be verbose or not */ + +static void +es1800_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + { + error ("Argument given to \"detach\" when remotely debugging."); + } + pop_target (); + if (from_tty) + { + printf ("Ending es1800 remote debugging.\n"); + } +} + + +/* Tell the remote machine to resume. + step - single-step or run free + siggnal - the signal value to be given to the target (0 = no signal) */ + +static void +es1800_resume (pid, step, siggnal) + int pid; + int step; + enum target_signal siggnal; +{ + char buf[PBUFSIZ]; + + if (siggnal) + { + error ("Can't send signals to a remote system."); + } + if (step) + { + strcpy (buf,"STP\r"); + send (buf); + } + else + { + send_command ("RBK"); + } +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + status - */ + +static int +es1800_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + unsigned char buf[PBUFSIZ]; + int old_timeout = timeout; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + timeout = 0; /* Don't time out -- user program is running. */ + if (!setjmp (interrupt)) + { + old_sigint = signal (SIGINT, es1800_request_quit); + while (1) + { + getmessage (buf, sizeof(buf)); + if (strncmp ( buf, "\r\n* BREAK *", 11) == 0) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + send_command ("STP"); /* Restore stack and PC and such */ + if (m68020) + { + send_command ("STP"); + } + break; + } + if (strncmp (buf, "STP\r\n ", 6) == 0) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + } + if (buf[strlen (buf) - 2] == 'R') + { + printf ("Unexpected emulator reply: \n%s\n", buf); + } + else + { + printf ("Unexpected stop: \n%s\n", buf); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_QUIT; + break; + } + } + } + else + { + fflush (stdin); + printf ("\nStopping emulator..."); + if (!setjmp (interrupt)) + { + old_sigint = signal (SIGINT, es1800_request_quit); + send_command ("STP"); + printf (" emulator stopped\n"); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_INT; + } + else + { + fflush (stdin); + es1800_reset ((char*) 1); + } + } + signal (SIGINT, old_sigint); + timeout = old_timeout; + return (0); +} + + +/* Fetch register values from remote machine. + regno - the register to be fetched (fetch all registers if -1) */ + +static void +es1800_fetch_register (regno) + int regno; +{ + char buf[PBUFSIZ]; + int k; + int r; + char *p; + static char regtab[18][4] = + { + "D0 ", "D1 ", "D2 ", "D3 ", "D4 ", "D5 ", "D6 ", "D7 ", + "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ", "A6 ", "SSP", + "SR ", "PC " + }; + + if ((regno < 15) || (regno == 16) || (regno == 17)) + { + r = regno * 4; + send_with_reply (regtab[regno], buf, sizeof (buf)); + p = buf; + for (k = 0; k < 4; k++) + { + if ((p[k*2 + 1] == 0) || (p[k*2 + 2] == 0)) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = (fromhex (p[k*2 + 1]) * 16) + fromhex (p[k*2 + 2]); + } + } + else + { + es1800_fetch_registers (); + } +} + +/* Read the remote registers into REGISTERS. + Always fetches all registers. */ + +static void +es1800_fetch_registers () +{ + char buf[PBUFSIZ]; + char SR_buf[PBUFSIZ]; + int i; + int k; + int r; + char *p; + + send_with_reply ("DR", buf, sizeof (buf)); + + /* Reply is edited to a string that describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + r = 0; + + /* parsing row one - D0-D7-registers */ + + while (*p++ != '\n') {;} + for (i = 4; i < 70; i += (i == 39 ? 3 : 1)) + { + for (k = 0; k < 4; k++) + { + if (p[i+0] == 0 || p[i+1] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = (fromhex (p[i+0]) * 16) + fromhex (p[i+1]); + i += 2; + } + } + p += i; + + /* parsing row two - A0-A6-registers */ + + while (*p++ != '\n') {;} + for (i = 4; i < 61; i += (i == 39 ? 3 : 1)) + { + for (k = 0; k < 4; k++) + { + if (p[i+0] == 0 || p[i+1] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = (fromhex (p[i+0])) * 16 + fromhex (p[i+1]); + i += 2; + } + } + p += i; + + while (*p++ != '\n') {;} + + /* fetch SSP-, SR- and PC-registers */ + + /* first - check STATUS-word and decide which stackpointer to use */ + + send_with_reply ("SR", SR_buf, sizeof (SR_buf)); + p = SR_buf; + p += 5; + + if (m68020) + { + if (*p == '3') /* use masterstackpointer MSP */ + { + send_with_reply ("MSP", buf, sizeof (buf)); + } + else if (*p == '2') /* use interruptstackpointer ISP */ + { + send_with_reply ("ISP", buf, sizeof (buf)); + } + else /* use userstackpointer USP */ + { + send_with_reply ("USP", buf, sizeof (buf)); + } + p = buf; + for (k = 0; k<4; k++) + { + if (p[k*2+1] == 0 || p[k*2+2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = fromhex (buf[k*2+1]) * 16 + fromhex (buf[k*2+2]); + } + + p = SR_buf; + for (k = 0; k < 4; k++) + { + if (p[k*2+1] == 0 || p[k*2+2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = + fromhex (SR_buf[k*2+1]) * 16 + fromhex (SR_buf[k*2+2]); + } + send_with_reply ("PC", buf, sizeof (buf)); + p = buf; + for (k = 0; k<4; k++) + { + if (p[k*2+1] == 0 || p[k*2+2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = fromhex (buf[k*2+1]) * 16 + fromhex (buf[k*2+2]); + } + } + else /* 68000-mode */ + { + if (*p == '2') /* use supervisorstackpointer SSP */ + { + send_with_reply ("SSP", buf, sizeof (buf)); + } + else /* use userstackpointer USP */ + { + send_with_reply ("USP", buf, sizeof (buf)); + } + + /* fetch STACKPOINTER */ + + p = buf; + for (k = 0; k < 4; k++) + { + if (p[k*2 + 1] == 0 || p[k*2 + 2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = fromhex (buf[k*2+1]) * 16 + fromhex (buf[k*2+2]); + } + + /* fetch STATUS */ + + p = SR_buf; + for (k = 0; k < 4; k++) + { + if (p[k*2+1] == 0 || p[k*2+2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = + fromhex (SR_buf[k*2+1]) * 16 + fromhex (SR_buf[k*2+2]); + } + + /* fetch PC */ + + send_with_reply ("PC", buf, sizeof (buf)); + p = buf; + for (k = 0; k < 4; k++) + { + if (p[k*2+1] == 0 || p[k*2+2] == 0) + { + error ("Emulator reply is too short: %s", buf); + } + registers[r++] = fromhex (buf[k*2+1]) * 16 + fromhex (buf[k*2+2]); + } + } +} + +/* Store register value, located in REGISTER, on the target processor. + regno - the register-number of the register to store + (-1 means store them all) + FIXME: Return errno value. */ + +static void +es1800_store_register(regno) + int regno; +{ + + static char regtab[18][4] = + { + "D0 ", "D1 ", "D2 ", "D3 ", "D4 ", "D5 ", "D6 ", "D7 ", + "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ", "A6 ", "SSP", + "SR ", "PC " + }; + + char buf[PBUFSIZ]; + char SR_buf[PBUFSIZ]; + char stack_pointer[4]; + char *p; + int i; + int j; + int k; + unsigned char *r; + + r = (unsigned char *) registers; + + if (regno == -1) /* write all registers */ + { + j = 0; + k = 18; + } + else /* write one register */ + { + j = regno; + k = regno+1; + r += regno * 4; + } + + if ((regno == -1) || (regno == 15)) + { + /* fetch current status */ + send_with_reply ("SR", SR_buf, sizeof (SR_buf)); + p = SR_buf; + p += 5; + if (m68020) + { + if (*p == '3') /* use masterstackpointer MSP */ + { + strcpy (stack_pointer,"MSP"); + } + else + { + if (*p == '2') /* use interruptstackpointer ISP */ + { + strcpy (stack_pointer,"ISP"); + } + else + { + strcpy (stack_pointer,"USP"); /* use userstackpointer USP */ + } + } + } + else /* 68000-mode */ + { + if (*p == '2') /* use supervisorstackpointer SSP */ + { + strcpy (stack_pointer,"SSP"); + } + else + { + strcpy (stack_pointer,"USP");/* use userstackpointer USP */ + } + } + strcpy (regtab[15],stack_pointer); + } + + for (i = j; i> 4) & 0x0f); + buf[6] = tohex (*r++ & 0x0f); + buf[7] = tohex ((*r >> 4) & 0x0f); + buf[8] = tohex (*r++ & 0x0f); + buf[9] = tohex ((*r >> 4) & 0x0f); + buf[10] = tohex (*r++ & 0x0f); + buf[11] = tohex ((*r >> 4) & 0x0f); + buf[12] = tohex (*r++ & 0x0f); + buf[13] = 0; + + send_with_reply (buf, buf, sizeof (buf)); /* FIXME, reply not used? */ + } +} + + +/* Prepare to store registers. */ + +static void +es1800_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + { + return a - '0'; + } + else if (a >= 'a' && a <= 'f') + { + return a - 'a' + 10; + } + else if (a >= 'A' && a <= 'F') + { + return a - 'A' + 10; + } + else + { + error ("Reply contains invalid hex digit"); + } + return (-1); +} + + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + { + return ('0' + nib); + } + else + { + return ('A' + nib - 10); + } +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if WRITE is + nonzero. Returns length of data written or read; 0 for error. + + memaddr - the target's address + myaddr - gdb's address + len - number of bytes + write - write if != 0 otherwise read */ + +static int +es1800_xfer_inferior_memory (memaddr, myaddr, len, write, tops) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *tops; /* Unused */ +{ + int origlen = len; + int xfersize; + + while (len > 0) + { + xfersize = len > MAXBUFBYTES ? MAXBUFBYTES : len; + if (write) + { + es1800_write_bytes (memaddr, myaddr, xfersize); + } + else + { + es1800_read_bytes (memaddr, myaddr, xfersize); + } + memaddr += xfersize; + myaddr += xfersize; + len -= xfersize; + } + return (origlen); /* no error possible */ +} + + +/* Write memory data directly to the emulator. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + memaddr - the target's address + myaddr - gdb's address + len - number of bytes */ + +static void +es1800_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + p = myaddr; + for (i = 0; i < len; i++) + { + sprintf (buf, "@.B$%x=$%x", memaddr+i, (*p++) & 0xff); + send_with_reply (buf, buf, sizeof (buf)); /* FIXME send_command? */ + } +} + + +/* Read memory data directly from the emulator. + This does not use the data cache; the data cache uses this. + + memaddr - the target's address + myaddr - gdb's address + len - number of bytes */ + +static void +es1800_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + static int DB_tab[16] = {8,11,14,17,20,23,26,29,34,37,40,43,46,49,52,55}; + char buf[PBUFSIZ]; + int i; + int low_addr; + char *p; + char *b; + + if (len > PBUFSIZ / 2 - 1) + { + abort (); + } + + if (len == 1) /* The emulator does not like expressions like: */ + { + len = 2; /* DB.B $20018 TO $20018 */ + } + + /* Reply describes registers byte by byte, each byte encoded as two hex + characters. */ + + sprintf (buf, "DB.B $%x TO $%x", memaddr, memaddr+len-1); + send_with_reply (buf, buf, sizeof (buf)); + b = buf; + low_addr = memaddr&0x0f; + for (i = low_addr; i < low_addr + len; i++) + { + if ((!(i % 16)) && i) + { /* if (i = 16,32,48) */ + while (*p++!='\n') {;} + b = p; + } + p = b + DB_tab[i%16] + (m68020 ? 2 : 0); + if (p[0] == 32 || p[1] == 32) + { + error ("Emulator reply is too short: %s", buf); + } + myaddr[i-low_addr] = fromhex (p[0]) * 16 + fromhex (p[1]); + } +} + +/* Information about the current target */ + +static void +es1800_files_info (tops) + struct target_ops *tops; /* Unused */ +{ + printf ("ES1800 Attached to %s at %d baud in %s mode\n", savename, 19200, + MODE); +} + + +/* We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. + + addr - is the target location in the target machine. + contents_cache - is a pointer to memory allocated for saving the target contents. + It is guaranteed by the caller to be long enough to save sizeof + BREAKPOINT bytes. + + FIXME: This size is target_arch dependent and should be available in + the target_arch transfer vector, if we ever have one... */ + +static int +es1800_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof (es1800_break_insn)); + + if (val == 0) + { + val = target_write_memory (addr, es1800_break_insn, + sizeof (es1800_break_insn)); + } + + return (val); +} + + +/* Write back the stashed instruction + + addr - is the target location in the target machine. + contents_cache - is a pointer to memory allocated for saving the target contents. + It is guaranteed by the caller to be long enough to save sizeof + BREAKPOINT bytes. */ + +static int +es1800_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + + return (target_write_memory (addr, contents_cache, + sizeof (es1800_break_insn))); +} + +/* create_break_insn () + Primitive datastructures containing the es1800 breakpoint instruction */ + +static void +es1800_create_break_insn (ins, vec) + char *ins; + int vec; +{ + if (vec == 15) + { + ins[0] = 0x4e; + ins[1] = 0x4f; + } +} + + +/* verify_break () + Seach for breakpoint routine in emulator memory. + returns non-zero on failure + vec - trap vector used for breakpoints */ + +static int +verify_break (vec) + int vec; +{ + CORE_ADDR memaddress; + char buf[8]; + char *instr = "NqNqNqNs"; /* breakpoint routine */ + int status; + + get_break_addr (vec, &memaddress); + + if (memaddress) + { + status = target_read_memory (memaddress, buf, 8); + if (status != 0) + { + memory_error (status, memaddress); + } + return (STRCMP (instr, buf)); + } + return (-1); +} + + +/* get_break_addr () + find address of breakpint routine + vec - trap vector used for breakpoints + addrp - store the address here */ + +static void +get_break_addr (vec, addrp) + int vec; + CORE_ADDR *addrp; +{ + CORE_ADDR memaddress = 0; + int status; + int k; + char buf[PBUFSIZ]; + char base_addr[4]; + char *p; + + if (m68020) + { + send_with_reply ("VBR ", buf, sizeof (buf)); + p = buf; + for (k = 0; k < 4; k++) + { + if ((p[k*2 + 1] == 0) || (p[k*2 + 2] == 0)) + { + error ("Emulator reply is too short: %s", buf); + } + base_addr[k] = (fromhex (p[k*2 + 1]) * 16) + fromhex (p[k*2 + 2]); + } + /* base addr of exception vector table */ + memaddress = *((CORE_ADDR *) base_addr); + } + + memaddress += (vec + 32) * 4; /* address of trap vector */ + status = target_read_memory (memaddress, (char *) addrp, 4); + if (status != 0) + { + memory_error (status, memaddress); + } +} + + +/* Kill an inferior process */ + +static void +es1800_kill () +{ + if (inferior_pid != 0) + { + inferior_pid = 0; + es1800_mourn_inferior (); + } +} + + +/* Load a file to the ES1800 emulator. + Converts the file from a.out format into Extended Tekhex format + before the file is loaded. + Also loads the trap routine, and sets the ES1800 breakpoint on it + filename - the a.out to be loaded + from_tty - says whether to be verbose or not + FIXME Uses emulator overlay memory for trap routine */ + +static void +es1800_load (filename, from_tty) + char *filename; + int from_tty; +{ + + FILE *instream; + char loadname[15]; + char buf[160]; + struct cleanup *old_chain; + int es1800_load_format = 5; + + if (es1800_desc == NULL) + { + printf ("No emulator attached, type emulator-command first\n"); + return; + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + switch (es1800_load_format) + { + case 2: /* Extended Tekhex */ + if (from_tty) + { + printf ("Converting \"%s\" to Extended Tekhex Format\n", filename); + } + sprintf (buf, "tekhex %s", filename); + system (buf); + sprintf (loadname, "out.hex"); + break; + + case 5: /* Motorola S-rec */ + if (from_tty) + { + printf ("Converting \"%s\" to Motorola S-record format\n", + filename); + } + /* in the future the source code in copy (part of binutils-1.93) will + be included in this file */ + sprintf (buf, + "copy -s \"a.out-sunos-big\" -d \"srec\" %s /tmp/out.hex", + filename); + system (buf); + sprintf (loadname, "/tmp/out.hex"); + break; + + default: + error ("Downloading format not defined\n"); + } + + breakpoint_init_inferior (); + inferior_pid = 0; + if (from_tty) + { + printf ("Downloading \"%s\" to the ES 1800\n",filename); + } + if ((instream = fopen (loadname, "r")) == NULL) + { + perror_with_name ("fopen:"); + } + + old_chain = make_cleanup (fclose, instream); + immediate_quit++; + + es1800_reset (0); + + download (instream, from_tty, es1800_load_format); + + /* if breakpoint routine is not present anymore we have to check + whether to download a new breakpoint routine or not */ + + if ((verify_break (es1800_break_vec) != 0) + && query ("No breakpoint routine in ES 1800 emulator!\nDownload a breakpoint routine to the emulator? ")) + { + char buf[128]; + printf ("Using break vector 0x%x\n", es1800_break_vec); + sprintf (buf, "0x%x ", es1800_break_vec); + printf ("Give the start address of the breakpoint routine: "); + fgets (buf + strlen (buf), sizeof (buf) - strlen (buf), stdin); + es1800_init_break (buf, 0); + } + + do_cleanups (old_chain); + expect_prompt (); + readchar (); /* FIXME I am getting a ^G = 7 after the prompt */ + printf ("\n"); + + if (fclose (instream) == EOF) + { + ; + } + + if (es1800_load_format != 2) + { + sprintf (buf, "/usr/bin/rm %s", loadname); + system (buf); + } + + symbol_file_command (filename, from_tty); /* reading symbol table */ + immediate_quit--; +} + +#if 0 + +#define NUMCPYBYTES 20 + +static void +bfd_copy (from_bfd, to_bfd) + bfd *from_bfd; + bfd *to_bfd; +{ + asection *p, *new; + int i; + char buf[NUMCPYBYTES]; + + for (p = from_bfd->sections; p != NULL; p = p->next) + { + printf (" Copying section %s. Size = %x.\n", p->name, p->_cooked_size); + printf (" vma = %x, offset = %x, output_sec = %x\n", + p->vma, p->output_offset, p->output_section); + new = bfd_make_section (to_bfd, p->name); + if (p->_cooked_size && + !bfd_set_section_size (to_bfd, new, p->_cooked_size)) + { + error ("Wrong BFD size!\n"); + } + if (!bfd_set_section_flags (to_bfd, new, p->flags)) + { + error ("bfd_set_section_flags"); + } + new->vma = p->vma; + + for (i = 0; (i + NUMCPYBYTES) < p->_cooked_size ; i += NUMCPYBYTES) + { + if (!bfd_get_section_contents (from_bfd, p, (PTR) buf, (file_ptr) i, + (bfd_size_type) NUMCPYBYTES)) + { + error ("bfd_get_section_contents\n"); + } + if (!bfd_set_section_contents (to_bfd, new, (PTR) buf, (file_ptr) i, + (bfd_size_type) NUMCPYBYTES)) + { + error ("bfd_set_section_contents\n"); + } + } + bfd_get_section_contents (from_bfd, p, (PTR) buf, (file_ptr) i, + (bfd_size_type) (p->_cooked_size - i)); + bfd_set_section_contents (to_bfd, new, (PTR) buf,(file_ptr) i, + (bfd_size_type) (p->_cooked_size - i)); + } +} + +#endif + +/* Start an process on the es1800 and set inferior_pid to the new + process' pid. + execfile - the file to run + args - arguments passed to the program + env - the environment vector to pass */ + +static void +es1800_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + int pid; +#if 0 + struct expression *expr; + register struct cleanup *old_chain = 0; + register value val; +#endif + + if (args && *args) + { + error ("Can't pass arguments to remote ES1800 process"); + } + +#if 0 + if (query ("Use 'start' as entry point? ")) + { + expr = parse_c_expression ("start"); + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_expression (expr); + entry_pt = (val->location).address; + } + else + { + printf ("Enter the program's entry point (in hexadecimal): "); + scanf ("%x", &entry_pt); + } +#endif + + if (execfile == 0 || exec_bfd == 0) + { + error ("No exec file specified"); + } + + entry_pt = (int) bfd_get_start_address (exec_bfd); + + pid = 42; + + /* Now that we have a child process, make it our target. */ + + push_target (&es1800_child_ops); + + /* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + inferior_pid = pid; /* Needed for wait_for_inferior below */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + + target_terminal_init (); + + /* Install inferior's terminal modes. */ + + target_terminal_inferior (); + + /* remote_start (args); */ + /* trap_expected = 0; */ + /* insert_step_breakpoint (); FIXME, do we need this? */ + + /* Let 'er rip... */ + proceed ((CORE_ADDR) entry_pt, TARGET_SIGNAL_DEFAULT, 0); + +} + + +/* The process has died, clean up. */ + +static void +es1800_mourn_inferior () +{ + remove_breakpoints (); + unpush_target (&es1800_child_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +/* ES1800-protocol specific routines */ + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. + string - the string to expect + nowait - break out if string not the emulator's first respond otherwise + read until string is found (== 0) */ + +static void +expect (string, nowait) + char *string; + int nowait; +{ + char c; + char *p = string; + + immediate_quit++; + while (1) + { + c = readchar (); + if (isalpha (c)) + { + c = toupper (c); + } + if (c == toupper (*p)) + { + p++; + if (*p == '\0') + { + immediate_quit--; + return; + } + } + else if (!nowait) + { + p = string; + } + else + { + printf ("\'%s\' expected\n" , string); + printf ("char %d is %d", p - string, c); + error ("\n" ); + } + } +} + +/* Keep discarding input until we see the prompt. */ + +static void +expect_prompt () +{ + expect (">", 0); +} + + +/* Read one character */ + +#ifdef DEBUG_STDIN + +/* read from stdin */ + +static int +readchar () +{ + char buf[1]; + + buf[0] = '\0'; + printf ("readchar, give one character\n"); + read (0, buf, 1); + +#if defined (LOG_FILE) + putc (buf[0] & 0x7f, log_file); +#endif + + return (buf[0] & 0x7f); +} + +#else /* !DEBUG_STDIN */ + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ + +static int +readchar () +{ + int ch; + + ch = SERIAL_READCHAR (es1800_desc, timeout); + + /* FIXME: doing an error() here will probably cause trouble, at least if from + es1800_wait. */ + if (ch == SERIAL_TIMEOUT) + error ("Timeout reading from remote system."); + else if (ch == SERIAL_ERROR) + perror_with_name ("remote read"); + +#if defined (LOG_FILE) + putc (ch & 0x7f, log_file); + fflush (log_file); +#endif + + return (ch); +} + +#endif /* DEBUG_STDIN */ + + +/* Send a command to the emulator and save the reply. + Report an error if we get an error reply. + string - the es1800 command + buf - containing the emulator reply on return + len - size of buf */ + +static void +send_with_reply (string, buf, len) + char *string, *buf; + int len; +{ + send (string); + SERIAL_WRITE (es1800_desc, "\r", 1); + +#ifndef DEBUG_STDIN + expect (string, 1); + expect ("\r\n", 0); +#endif + + getmessage (buf, len); +} + + +/* Send the command in STR to the emulator adding \r. check + the echo for consistency. + string - the es1800 command */ + +static void +send_command (string) + char *string; +{ + send (string); + SERIAL_WRITE (es1800_desc, "\r", 1); + +#ifndef DEBUG_STDIN + expect (string, 0); + expect_prompt (); +#endif + +} + +/* Send a string + string - the es1800 command */ + +static void +send (string) + char *string; +{ + if (kiodebug) + { + fprintf (stderr, "Sending: %s\n", string); + } + SERIAL_WRITE (es1800_desc, string, strlen (string)); +} + + +/* Read a message from the emulator and store it in BUF. + buf - containing the emulator reply on return + len - size of buf */ + +static void +getmessage (buf, len) + char *buf; + int len; +{ + char *bp; + int c; + int prompt_found = 0; + extern kiodebug; + +#if defined (LOG_FILE) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush (log_file); +#endif + + bp = buf; + c = readchar (); + do + { + if (c) + { + if (len-- < 2) /* char and terminaling NULL */ + { + error ("input buffer overrun\n"); + } + *bp++ = c; + } + c = readchar (); + if ((c == '>') && (*(bp - 1) == ' ')) + { + prompt_found = 1; + } + } + while (!prompt_found); + *bp = 0; + + if (kiodebug) + { + fprintf (stderr,"message received :%s\n", buf); + } +} + +static void +download (instream, from_tty, format) +FILE *instream; + int from_tty; + int format; +{ + char c; + char buf[160]; + int i = 0; + + send_command ("SET #2,$1A"); /* reset char = ^Z */ + send_command ("SET #3,$11,$13"); /* XON XOFF */ + if (format == 2) + { + send_command ("SET #26,#2"); + } + else + { + send_command ("SET #26,#5"); /* Format=Extended Tekhex */ + } + send_command ("DFB = $10"); + send_command ("PUR"); + send_command ("CES"); + send ("DNL\r"); + expect ("DNL", 1); + if (from_tty) + { + printf (" 0 records loaded...\r"); + } + while (fgets (buf, 160, instream)) + { + send (buf); + if (from_tty) + { + printf ("%5d\b\b\b\b\b",++i); + fflush (stdout); + } + if ((c = readchar ()) != 006) + { + error ("expected ACK"); + } + } + if (from_tty) + { + printf ("- All"); + } +} + +/* Additional commands */ + +#if defined (TIOCGETP) && defined (FNDELAY) && defined (EWOULDBLOCK) +#define PROVIDE_TRANSPARENT +#endif + +#ifdef PROVIDE_TRANSPARENT +/* Talk directly to the emulator + FIXME, uses busy wait, and is SUNOS (or at least BSD) specific */ + +/*ARGSUSED*/ +static void +es1800_transparent (args, from_tty) + char *args; + int from_tty; +{ + int console; + struct sgttyb modebl; + int fcflag; + int cc; + struct sgttyb console_mode_save; + int console_fc_save; + int es1800_fc_save; + int inputcnt = 80; + char inputbuf[80]; + int consolecnt = 0; + char consolebuf[80]; + int es1800_cnt = 0; + char es1800_buf[80]; + int i; + + dont_repeat (); + if (es1800_desc == NULL) + { + printf ("No emulator attached, type emulator-command first\n"); + return; + } + + printf ("\n"); + printf ("You are now communicating directly with the ES 1800 emulator.\n"); + printf ("To leave this mode (transparent mode), press ^E.\n"); + printf ("\n"); + printf (" >"); + fflush (stdout); + + if ((console = open ("/dev/tty", O_RDWR)) == -1) + { + perror_with_name ("/dev/tty:"); + } + + if ((fcflag = fcntl (console, F_GETFL, 0)) == -1) + { + perror_with_name ("fcntl console"); + } + + console_fc_save = fcflag; + fcflag = fcflag | FNDELAY; + + if (fcntl (console, F_SETFL, fcflag) == -1) + { + perror_with_name ("fcntl console"); + } + + if (ioctl (console, TIOCGETP, &modebl)) + { + perror_with_name ("ioctl console"); + } + + console_mode_save = modebl; + modebl.sg_flags = RAW; + + if (ioctl (console, TIOCSETP, &modebl)) + { + perror_with_name ("ioctl console"); + } + + if ((fcflag = fcntl (es1800_desc->fd, F_GETFL, 0)) == -1) + { + perror_with_name ("fcntl serial"); + } + + es1800_fc_save = fcflag; + fcflag = fcflag | FNDELAY; + + if (fcntl (es1800_desc->fd, F_SETFL, fcflag) == -1) + { + perror_with_name ("fcntl serial"); + } + + while (1) + { + cc = read (console, inputbuf, inputcnt); + if (cc != -1) + { + if ((*inputbuf & 0x7f) == 0x05) + { + break; + } + for (i = 0; i < cc; ) + { + es1800_buf[es1800_cnt++] = inputbuf[i++]; + } + if ((cc = SERIAL_WRITE (es1800_desc, es1800_buf, es1800_cnt)) == -1) + { + perror_with_name ("FEL! write:"); + } + es1800_cnt -= cc; + if (es1800_cnt && cc) + { + for (i = 0; i < es1800_cnt; i++) + { + es1800_buf[i] = es1800_buf[cc+i]; + } + } + } + else if (errno != EWOULDBLOCK) + { + perror_with_name ("FEL! read:"); + } + + cc = read (es1800_desc->fd,inputbuf,inputcnt); + if (cc != -1) + { + for (i = 0; i < cc; ) + { + consolebuf[consolecnt++] = inputbuf[i++]; + } + if ((cc = write (console,consolebuf,consolecnt)) == -1) + { + perror_with_name ("FEL! write:"); + } + consolecnt -= cc; + if (consolecnt && cc) + { + for (i = 0; i < consolecnt; i++) + { + consolebuf[i] = consolebuf[cc+i]; + } + } + } + else if (errno != EWOULDBLOCK) + { + perror_with_name ("FEL! read:"); + } + } + + console_fc_save = console_fc_save & !FNDELAY; + if (fcntl (console, F_SETFL, console_fc_save) == -1) + { + perror_with_name ("FEL! fcntl"); + } + + if (ioctl (console, TIOCSETP, &console_mode_save)) + { + perror_with_name ("FEL! ioctl"); + } + + close (console); + + if (fcntl (es1800_desc->fd, F_SETFL, es1800_fc_save) == -1) + { + perror_with_name ("FEL! fcntl"); + } + + printf ("\n"); + +} +#endif /* PROVIDE_TRANSPARENT */ + +static void +es1800_init_break (args, from_tty) + char *args; + int from_tty; +{ + CORE_ADDR memaddress = 0; + char buf[PBUFSIZ]; + char base_addr[4]; + char *space_index; + char *p; + int k; + + if (args == NULL) + { + error_no_arg ("a trap vector"); + } + + if (!(space_index = strchr (args, ' '))) + { + error ("Two arguments needed (trap vector and address of break routine).\n"); + } + + *space_index = '\0'; + + es1800_break_vec = strtol (args, (char **) NULL, 0); + es1800_break_address = parse_and_eval_address (space_index + 1); + + es1800_create_break_insn (es1800_break_insn, es1800_break_vec); + + if (m68020) + { + send_with_reply ("VBR ", buf, sizeof (buf)); + p = buf; + for (k = 0; k < 4; k++) + { + if ((p[k*2 + 1] == 0) || (p[k*2 + 2] == 0)) + { + error ("Emulator reply is too short: %s", buf); + } + base_addr[k] = (fromhex (p[k*2 + 1]) * 16) + fromhex (p[k*2 + 2]); + } + /* base addr of exception vector table */ + memaddress = *((CORE_ADDR *) base_addr); + } + + memaddress += (es1800_break_vec + 32) * 4; /* address of trap vector */ + + sprintf (buf, "@.L%lx=$%lx", memaddress, es1800_break_address); + send_command (buf); /* set the address of the break routine in the */ + /* trap vector */ + + sprintf (buf, "@.L%lx=$4E714E71", es1800_break_address); /* NOP; NOP */ + send_command (buf); + sprintf (buf, "@.L%lx=$4E714E73", es1800_break_address + 4); /* NOP; RTE */ + send_command (buf); + + sprintf (buf, "AC2=$%lx", es1800_break_address + 4); + /* breakpoint at es1800-break_address */ + send_command (buf); + send_command ("WHEN AC2 THEN BRK"); /* ie in exception routine */ + + if (from_tty) + { + printf ("Breakpoint (trap $%x) routine at address: %lx\n", + es1800_break_vec, es1800_break_address); + } +} + +static void +es1800_child_open (arg, from_tty) + char *arg; + int from_tty; +{ + error ("Use the \"run\" command to start a child process."); +} + +static void +es1800_child_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + { + error ("Argument given to \"detach\" when remotely debugging."); + } + + pop_target (); + if (from_tty) + { + printf ("Ending debugging the process %d.\n", inferior_pid); + } +} + + +/* Define the target subroutine names */ + +struct target_ops es1800_ops = +{ + "es1800", /* to_shortname */ + /* to_longname */ + "Remote serial target in ES1800-emulator protocol", + /* to_doc */ + "Remote debugging on the es1800 emulator via a serial line.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + es1800_open, /* to_open */ + es1800_close, /* to_close */ + es1800_attach, /* to_attach */ + es1800_detach, /* to_detach */ + es1800_resume, /* to_resume */ + NULL, /* to_wait */ + NULL, /* to_fetch_registers */ + NULL, /* to_store_registers */ + es1800_prepare_to_store, /* to_prepare_to_store */ + es1800_xfer_inferior_memory, /* to_xfer_memory */ + es1800_files_info, /* to_files_info */ + es1800_insert_breakpoint, /* to_insert_breakpoint */ + es1800_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + NULL, /* to_kill */ + es1800_load, /* to_load */ + NULL, /* to_lookup_symbol */ + es1800_create_inferior, /* to_create_inferior */ + NULL, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + core_stratum, /* to_stratum */ + 0, /* to_next */ + 0, /* to_has_all_memory */ + 1, /* to_has_memory */ + 0, /* to_has_stack */ + 0, /* to_has_registers */ + 0, /* to_has_execution */ + NULL, /* to_sections */ + NULL, /* to_sections_end */ + OPS_MAGIC /* to_magic (always last) */ +}; + +/* Define the target subroutine names */ + +struct target_ops es1800_child_ops = +{ + "es1800_process", /* to_shortname */ + /* to_longname */ + "Remote serial target in ES1800-emulator protocol", + /* to_doc */ + "Remote debugging on the es1800 emulator via a serial line.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + es1800_child_open, /* to_open */ + NULL, /* to_close */ + es1800_attach, /* to_attach */ + es1800_child_detach, /* to_detach */ + es1800_resume, /* to_resume */ + es1800_wait, /* to_wait */ + es1800_fetch_register, /* to_fetch_registers */ + es1800_store_register, /* to_store_registers */ + es1800_prepare_to_store, /* to_prepare_to_store */ + es1800_xfer_inferior_memory, /* to_xfer_memory */ + es1800_files_info, /* to_files_info */ + es1800_insert_breakpoint, /* to_insert_breakpoint */ + es1800_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + es1800_kill, /* to_kill */ + es1800_load, /* to_load */ + NULL, /* to_lookup_symbol */ + es1800_create_inferior, /* to_create_inferior */ + es1800_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + 0, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* to_sections */ + NULL, /* to_sections_end */ + OPS_MAGIC /* to_magic (always last) */ +}; + +void +_initialize_es1800 () +{ + add_target (&es1800_ops); + add_target (&es1800_child_ops); +#ifdef PROVIDE_TRANSPARENT + add_com ("transparent", class_support, es1800_transparent, + "Start transparent communication with the ES 1800 emulator."); +#endif /* PROVIDE_TRANSPARENT */ + add_com ("init_break", class_support, es1800_init_break, + "Download break routine and initialize break facility on ES 1800"); +} diff --git a/contrib/gdb/gdb/remote-est.c b/contrib/gdb/gdb/remote-est.c new file mode 100644 index 000000000000..cfa97310b06d --- /dev/null +++ b/contrib/gdb/gdb/remote-est.c @@ -0,0 +1,174 @@ +/* Remote debugging interface for EST-300 ICE, for GDB + Copyright 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. + + Written by Steve Chamberlain for Cygnus Support. + Re-written by Stu Grossman of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void est_open PARAMS ((char *args, int from_tty)); + +static void +est_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno; + + if (regnamelen != 2) + return; + + switch (regname[0]) + { + case 'S': + if (regname[1] != 'R') + return; + regno = PS_REGNUM; + break; + case 'P': + if (regname[1] != 'C') + return; + regno = PC_REGNUM; + break; + case 'D': + if (regname[1] < '0' || regname[1] > '7') + return; + regno = regname[1] - '0' + D0_REGNUM; + break; + case 'A': + if (regname[1] < '0' || regname[1] > '7') + return; + regno = regname[1] - '0' + A0_REGNUM; + break; + default: + return; + } + + monitor_supply_register (regno, val); +} + +/* + * This array of registers needs to match the indexes used by GDB. The + * whole reason this exists is because the various ROM monitors use + * different names than GDB does, and don't support all the + * registers either. So, typing "info reg sp" becomes a "r30". + */ + +static char *est_regnames[NUM_REGS] = +{ + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", + "SR", "PC", +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops est_ops; + +static char *est_inits[] = {"he\r", /* Resets the prompt, and clears repeated cmds */ + NULL}; + +static struct monitor_ops est_cmds = +{ + MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_NEED_REGDUMP_AFTER_CONT, + est_inits, /* Init strings */ + "go\r", /* continue command */ + "sidr\r", /* single step */ + "\003", /* ^C interrupts the program */ + "sb %x\r", /* set a breakpoint */ + "rb %x\r", /* clear a breakpoint */ + "rb\r", /* clear all breakpoints */ + "bfb %x %x %x\r", /* fill (start end val) */ + { + "smb %x %x\r", /* setmem.cmdb (addr, value) */ + "smw %x %x\r", /* setmem.cmdw (addr, value) */ + "sml %x %x\r", /* setmem.cmdl (addr, value) */ + NULL, /* setmem.cmdll (addr, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL, /* setreg.term_cmd */ + }, + { + "dmb %x %x\r", /* getmem.cmdb (addr, len) */ + "dmw %x %x\r", /* getmem.cmdw (addr, len) */ + "dml %x %x\r", /* getmem.cmdl (addr, len) */ + NULL, /* getmem.cmdll (addr, len) */ + ": ", /* getmem.resp_delim */ + NULL, /* getmem.term */ + NULL, /* getmem.term_cmd */ + }, + { + "sr %s %x\r", /* setreg.cmd (name, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL /* setreg.term_cmd */ + }, + { + "dr %s\r", /* getreg.cmd (name) */ + " = ", /* getreg.resp_delim */ + NULL, /* getreg.term */ + NULL /* getreg.term_cmd */ + }, + "dr\r", /* dump_registers */ + "\\(\\w+\\) = \\([0-9a-fA-F]+\\)", /* register_pattern */ + est_supply_register, /* supply_register */ + NULL, /* load_routine (defaults to SRECs) */ + "dl\r", /* download command */ + "+", /* load response */ + ">BKM>", /* monitor command prompt */ + "\r", /* end-of-line terminator */ + NULL, /* optional command terminator */ + &est_ops, /* target operations */ + SERIAL_1_STOPBITS, /* number of stop bits */ + est_regnames, /* registers names */ + MONITOR_OPS_MAGIC /* magic */ + }; + +static void +est_open(args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &est_cmds, from_tty); +} + +void +_initialize_est () +{ + init_monitor_ops (&est_ops); + + est_ops.to_shortname = "est"; + est_ops.to_longname = "EST background debug monitor"; + est_ops.to_doc = "Debug via the EST BDM.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + est_ops.to_open = est_open; + + add_target (&est_ops); +} diff --git a/contrib/gdb/gdb/remote-hms.c b/contrib/gdb/gdb/remote-hms.c new file mode 100644 index 000000000000..2f43e2022990 --- /dev/null +++ b/contrib/gdb/gdb/remote-hms.c @@ -0,0 +1,1463 @@ +/* Remote debugging interface for Hitachi HMS Monitor Version 1.0 + Copyright 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Steve Chamberlain + (sac@cygnus.com). + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" + +static void hms_open PARAMS ((char *args, int from_tty)); + +static void +hms_supply_register (regname, regnamelen, val, vallen) + char *regname; + int regnamelen; + char *val; + int vallen; +{ + int regno; + + if (regnamelen != 2) + return; + if (regname[0] != 'P') + return; + /* We scan off all the registers in one go */ + + val = monitor_supply_register (PC_REGNUM, val); + /* Skip the ccr string */ + while (*val != '=' && *val) + val++; + + val = monitor_supply_register (CCR_REGNUM, val + 1); + + /* Skip up to rest of regs */ + while (*val != '=' && *val) + val++; + + for (regno = 0; regno < 7; regno++) + { + val = monitor_supply_register (regno, val + 1); + } +} + +/* + * This array of registers needs to match the indexes used by GDB. The + * whole reason this exists is because the various ROM monitors use + * different names than GDB does, and don't support all the + * registers either. So, typing "info reg sp" becomes a "r30". + */ + +static char *hms_regnames[NUM_REGS] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "CCR", "PC" +}; + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ + +static struct target_ops hms_ops; + +static char *hms_inits[] = +{"\003", /* Resets the prompt, and clears repeated cmds */ + NULL}; + +static struct monitor_ops hms_cmds = +{ + MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_GETMEM_NEEDS_RANGE, + hms_inits, /* Init strings */ + "g\r", /* continue command */ + "s\r", /* single step */ + "\003", /* ^C interrupts the program */ + "b %x\r", /* set a breakpoint */ + "b - %x\r", /* clear a breakpoint */ + "b -\r", /* clear all breakpoints */ + "f %x %x %x\r", /* fill (start end val) */ + { + "m.b %x=%x\r", /* setmem.cmdb (addr, value) */ + "m.w %x=%x\r", /* setmem.cmdw (addr, value) */ + NULL, /* setmem.cmdl (addr, value) */ + NULL, /* setmem.cmdll (addr, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL, /* setreg.term_cmd */ + }, + { + "m.b %x %x\r", /* getmem.cmdb (addr, addr) */ + "m.w %x %x\r", /* getmem.cmdw (addr, addr) */ + NULL, /* getmem.cmdl (addr, addr) */ + NULL, /* getmem.cmdll (addr, addr) */ + ": ", /* getmem.resp_delim */ + ">", /* getmem.term */ + "\003", /* getmem.term_cmd */ + }, + { + "r %s=%x\r", /* setreg.cmd (name, value) */ + NULL, /* setreg.resp_delim */ + NULL, /* setreg.term */ + NULL /* setreg.term_cmd */ + }, + { + "r %s\r", /* getreg.cmd (name) */ + " (", /* getreg.resp_delim */ + ":", /* getreg.term */ + "\003", /* getreg.term_cmd */ + }, + "r\r", /* dump_registers */ + "\\(\\w+\\)=\\([0-9a-fA-F]+\\)", /* register_pattern */ + hms_supply_register, /* supply_register */ + NULL, /* load_routine (defaults to SRECs) */ + "tl\r", /* download command */ + NULL, /* load response */ + ">", /* monitor command prompt */ + "\r", /* end-of-command delimitor */ + NULL, /* optional command terminator */ + &hms_ops, /* target operations */ + SERIAL_1_STOPBITS, /* number of stop bits */ + hms_regnames, /* registers names */ + MONITOR_OPS_MAGIC /* magic */ +}; + +static void +hms_open (args, from_tty) + char *args; + int from_tty; +{ + monitor_open (args, &hms_cmds, from_tty); +} + +int write_dos_tick_delay; + +void +_initialize_remote_hms () +{ + init_monitor_ops (&hms_ops); + + hms_ops.to_shortname = "hms"; + hms_ops.to_longname = "Hitachi Microsystems H8/300 debug monitor"; + hms_ops.to_doc = "Debug via the HMS monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + hms_ops.to_open = hms_open; + /* By trial and error I've found that this delay doesn't break things */ + write_dos_tick_delay = 1; + add_target (&hms_ops); +} + + +#if 0 +/* This is kept here because we used to support the H8/500 in this module, + and I haven't done the H8/500 yet */ +#include "defs.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" +#include "serial.h" +#include "remote-utils.h" +/* External data declarations */ +extern int stop_soon_quietly; /* for wait_for_inferior */ + +/* Forward data declarations */ +extern struct target_ops hms_ops; /* Forward declaration */ + +/* Forward function declarations */ +static void hms_fetch_registers (); +static int hms_store_registers (); +static void hms_close (); +static int hms_clear_breakpoints (); + +extern struct target_ops hms_ops; +static void hms_drain (); +static void add_commands (); +static void remove_commands (); + +static int quiet = 1; /* FIXME - can be removed after Dec '94 */ + + + +/*********************************************************************** + * I/O stuff stolen from remote-eb.c + ***********************************************************************/ + +static int timeout = 2; + +static const char *dev_name; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + hms_open knows that we don't have a file open when the program + starts. */ + +static int before = 0xdead; +static int is_open = 0; +static int after = 0xdead; +int +check_open () +{ + if (before != 0xdead + || after != 0xdead) + printf ("OUTCH! \n"); + if (!is_open) + { + error ("remote device not open"); + } +} + +#define ON 1 +#define OFF 0 + +/* Read a character from the remote system, doing all the fancy + timeout stuff. */ +static int +readchar () +{ + int buf; + + buf = SERIAL_READCHAR (desc, timeout); + + if (buf == SERIAL_TIMEOUT) + { + hms_write (".\r\n", 3); + error ("Timeout reading from remote system."); + } + if (buf == SERIAL_ERROR) + { + error ("Serial port error!"); + } + + if (!quiet || remote_debug) + printf_unfiltered ("%c", buf); + + return buf & 0x7f; +} + +static void +flush () +{ + while (1) + { + int b = SERIAL_READCHAR (desc, 0); + if (b == SERIAL_TIMEOUT) + return; + } +} + +static int +readchar_nofail () +{ + int buf; + + buf = SERIAL_READCHAR (desc, timeout); + if (buf == SERIAL_TIMEOUT) + buf = 0; + if (!quiet || remote_debug) + printf_unfiltered ("%c", buf); + + return buf & 0x7f; + +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +static void +expect (string) + char *string; +{ + char *p = string; + char c; + immediate_quit = 1; + while (1) + { + c = readchar (); + if (c == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + { + p = string; + if (c == *p) + p++; + } + } +} + +/* Keep discarding input until we see the hms prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: hms_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a hms_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt () +{ + expect ("HMS>"); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + + while (1) + { + ch = readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from hms_desc and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Read a 32-bit hex word from the hms, preceded by a space */ +static long +get_hex_word () +{ + long val; + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + return val; +} + +/* Called when SIGALRM signal sent due to alarm() timeout. */ + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to hms_wait should just return + SIGTRAP without actually waiting for anything. */ + +static int need_artificial_trap = 0; + +void +hms_kill (arg, from_tty) + char *arg; + int from_tty; +{ + +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +hms_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + char buffer[100]; + + if (args && *args) + error ("Can't pass arguments to remote hms process."); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + check_open (); + + hms_kill (NULL, NULL); + hms_clear_breakpoints (); + init_wait_for_inferior (); + hms_write_cr (""); + expect_prompt (); + + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication, then a space, + then the baud rate. + */ + +static char * +find_end_of_word (s) + char *s; +{ + while (*s && !isspace (*s)) + s++; + return s; +} + +static char * +get_word (p) + char **p; +{ + char *s = *p; + char *word; + char *copy; + size_t len; + + while (isspace (*s)) + s++; + + word = s; + + len = 0; + + while (*s && !isspace (*s)) + { + s++; + len++; + + } + copy = xmalloc (len + 1); + memcpy (copy, word, len); + copy[len] = 0; + *p = s; + return copy; +} + +static int baudrate = 9600; + +static int +is_baudrate_right () +{ + int ok; + + /* Put this port into NORMAL mode, send the 'normal' character */ + + hms_write ("\001", 1); /* Control A */ + hms_write ("\r\n", 2); /* Cr */ + + while (1) + { + ok = SERIAL_READCHAR (desc, timeout); + if (ok < 0) + break; + } + + hms_write ("r", 1); + + if (readchar_nofail () == 'r') + return 1; + + /* Not the right baudrate, or the board's not on */ + return 0; +} +static void +set_rate () +{ + if (!SERIAL_SETBAUDRATE (desc, baudrate)) + error ("Can't set baudrate"); +} + + + +/* Close out all files and local state before this target loses control. */ + +static void +hms_close (quitting) + int quitting; +{ + /* Clear any break points */ + remove_commands (); + hms_clear_breakpoints (); + sleep (1); /* Let any output make it all the way back */ + if (is_open) + { + SERIAL_WRITE (desc, "R\r\n", 3); + SERIAL_CLOSE (desc); + } + is_open = 0; +} + +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ void +hms_detach (args, from_tty) + char *args; + int from_tty; +{ + if (is_open) + { + hms_clear_breakpoints (); + } + + pop_target (); /* calls hms_close to do the real work + */ + if (from_tty) + printf_filtered ("Ending remote %s debugging\n", + target_shortname); +} + +/* Tell the remote machine to resume. */ + +void +hms_resume (pid, step, sig) + int pid, step; + enum target_signal + sig; +{ + if (step) + { + hms_write_cr ("s"); + expect ("Step>"); + + /* Force the next hms_wait to return a trap. Not doing anything + about I/O from the target means that the user has to type "continue" + to see any. FIXME, this should be fixed. */ + need_artificial_trap = 1; + } + else + { + hms_write_cr ("g"); + expect ("g"); + } +} + +/* Wait until the remote machine stops, then return, storing status in + STATUS just as `wait' would. */ + +int +hms_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + /* Strings to look for. '?' means match any single character. Note + that with the algorithm we use, the initial character of the string + cannot recur in the string, or we will not find some cases of the + string in the input. */ + + static char bpt[] = "At breakpoint:"; + + /* It would be tempting to look for "\n[__exit + 0x8]\n" but that + requires loading symbols with "yc i" and even if we did do that we + don't know that the file has symbols. */ + static char exitmsg[] = "HMS>"; + char *bp = bpt; + char *ep = exitmsg; + + /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. + */ + char swallowed[50]; + + /* Current position in swallowed. */ + char *swallowed_p = swallowed; + + int ch; + int ch_handled; + int old_timeout = timeout; + int + old_immediate_quit = immediate_quit; + int swallowed_cr = 0; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + if (need_artificial_trap != 0) + { + status->kind = + TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + need_artificial_trap--; + return 0; + } + + timeout = 5; /* Don't time out for a while - user program is running. + */ + immediate_quit = 1; /* Helps ability to QUIT */ + while (1) + { + QUIT; /* Let user quit and leave process running */ + ch_handled = 0; + ch = readchar (); + if (ch == *bp) + { + bp++; + if (*bp == '\0') + break; + ch_handled = 1; + + *swallowed_p++ = ch; + } + else + { + bp = bpt; + } + if + (ch == *ep || *ep == '?') + { + ep++; + if (*ep == '\0') + break; + + if (!ch_handled) + *swallowed_p++ = ch; + ch_handled = + 1; + } + else + { + ep = exitmsg; + } + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + for (p = swallowed; p < swallowed_p; ++p) + putchar_unfiltered (*p); + swallowed_p = swallowed; + + if ((ch != '\r' && ch != '\n') || swallowed_cr > 10) + { + putchar_unfiltered (ch); + swallowed_cr = 10; + } + swallowed_cr++; + + } + } + if (*bp == '\0') + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + expect_prompt (); + } + else + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = + TARGET_SIGNAL_STOP; + } + + timeout = old_timeout; + immediate_quit = old_immediate_quit; + return + 0; +} + +/* Return the name of register number REGNO in the form input and + output by hms. + + Returns a pointer to a static buffer containing the answer. */ +static char * +get_reg_name (regno) + int regno; +{ + static char *rn[] = + REGISTER_NAMES; + + return rn[regno]; +} + +/* Read the remote registers. */ + +static int +gethex (length, start, ok) + unsigned int length; + char *start; + int *ok; +{ + int result = 0; + + while (length--) + { + result <<= 4; + if (*start >= 'a' && *start <= 'f') + { + result += *start - 'a' + 10; + } + else if (*start >= 'A' && + *start <= 'F') + { + result += *start - 'A' + 10; + } + else if + (*start >= '0' && *start <= '9') + { + result += *start - '0'; + } + else + *ok = 0; + start++; + + } + return result; +} +static int +timed_read (buf, n, timeout) + char + *buf; + +{ + int i; + char c; + + i = 0; + while (i < n) + { + c = readchar (); + + if (c == 0) + return i; + buf[i] = c; + i++; + + } + return i; +} + +hms_write (a, l) + char *a; +{ + int i; + + SERIAL_WRITE (desc, a, l); + + if (!quiet || remote_debug) + { + printf_unfiltered ("<"); + for (i = 0; i < l; i++) + { + printf_unfiltered ("%c", a[i]); + } + printf_unfiltered (">"); + } +} + +hms_write_cr (s) + char *s; +{ + hms_write (s, strlen (s)); + hms_write ("\r\n", 2); +} + +#ifdef GDB_TARGET_IS_H8500 + +/* H8/500 monitor reg dump looks like: + + HMS>r + PC:8000 SR:070C .7NZ.. CP:00 DP:00 EP:00 TP:00 BR:00 + R0-R7: FF5A 0001 F4FE F500 0000 F528 F528 F4EE + HMS> + + + */ + +supply_val (n, size, ptr, segptr) + int n; + int size; + char *ptr; + char *segptr; +{ + int ok; + char raw[4]; + switch (size) + { + case 2: + raw[0] = gethex (2, ptr, &ok); + raw[1] = gethex (2, ptr + 2, &ok); + supply_register (n, raw); + break; + case 1: + raw[0] = gethex (2, ptr, &ok); + supply_register (n, raw); + break; + case 4: + { + int v = gethex (4, ptr, &ok); + v |= gethex (2, segptr, &ok) << 16; + raw[0] = 0; + raw[1] = (v >> 16) & 0xff; + raw[2] = (v >> 8) & 0xff; + raw[3] = (v >> 0) & 0xff; + supply_register (n, raw); + } + } + +} +static void +hms_fetch_register (dummy) + int dummy; +{ +#define REGREPLY_SIZE 108 + char linebuf[REGREPLY_SIZE + 1]; + int i; + int s; + int gottok; + + LONGEST reg[NUM_REGS]; + check_open (); + + do + { + + hms_write_cr ("r"); + expect ("r"); + s = timed_read (linebuf + 1, REGREPLY_SIZE, 1); + + linebuf[REGREPLY_SIZE] = 0; + gottok = 0; + if (linebuf[3] == 'P' && + linebuf[4] == 'C' && + linebuf[5] == ':' && + linebuf[105] == 'H' && + linebuf[106] == 'M' && + linebuf[107] == 'S') + { + + /* + 012 + r** + -------1---------2---------3---------4---------5----- + 345678901234567890123456789012345678901234567890123456 + PC:8000 SR:070C .7NZ.. CP:00 DP:00 EP:00 TP:00 BR:00** + ---6---------7---------8---------9--------10---- + 789012345678901234567890123456789012345678901234 + R0-R7: FF5A 0001 F4FE F500 0000 F528 F528 F4EE** + + 56789 + HMS> + */ + gottok = 1; + + + supply_val (PC_REGNUM, 4, linebuf + 6, linebuf + 29); + + supply_val (CCR_REGNUM, 2, linebuf + 14); + supply_val (SEG_C_REGNUM, 1, linebuf + 29); + supply_val (SEG_D_REGNUM, 1, linebuf + 35); + supply_val (SEG_E_REGNUM, 1, linebuf + 41); + supply_val (SEG_T_REGNUM, 1, linebuf + 47); + for (i = 0; i < 8; i++) + { + static int sr[8] = + {35, 35, 35, 35, + 41, 41, 47, 47}; + + char raw[4]; + char *src = linebuf + 64 + 5 * i; + char *segsrc = linebuf + sr[i]; + supply_val (R0_REGNUM + i, 2, src); + supply_val (PR0_REGNUM + i, 4, src, segsrc); + } + } + if (!gottok) + { + hms_write_cr (""); + expect ("HMS>"); + } + } + while (!gottok); +} +#endif + +#ifdef GDB_TARGET_IS_H8300 +static void +hms_fetch_register (dummy) + int dummy; +{ +#define REGREPLY_SIZE 79 + char linebuf[REGREPLY_SIZE + 1]; + int i; + int s; + int gottok; + + unsigned LONGEST reg[NUM_REGS]; + + check_open (); + + do + { + hms_write_cr ("r"); + + s = timed_read (linebuf, 1, 1); + + while (linebuf[0] != 'r') + s = timed_read (linebuf, 1, 1); + + s = timed_read (linebuf + 1, REGREPLY_SIZE - 1, 1); + + linebuf[REGREPLY_SIZE] = 0; + gottok = 0; + if (linebuf[0] == 'r' && + linebuf[3] == 'P' && + linebuf[4] == 'C' && + linebuf[5] == '=' && + linebuf[75] == 'H' && + linebuf[76] == 'M' && + linebuf[77] == 'S') + { + /* + PC=XXXX CCR=XX:XXXXXXXX R0-R7= XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX + 5436789012345678901234567890123456789012345678901234567890123456789012 + 0 1 2 3 4 5 6 + */ + gottok = 1; + + reg[PC_REGNUM] = gethex (4, linebuf + 6, &gottok); + reg[CCR_REGNUM] = gethex (2, linebuf + 15, &gottok); + for (i = 0; i < 8; i++) + { + reg[i] = gethex (4, linebuf + 34 + 5 * i, &gottok); + } + } + } + while (!gottok); + for (i = 0; i < NUM_REGS; i++) + { + char swapped[2]; + + swapped[1] = reg[i]; + swapped[0] = (reg[i]) >> 8; + + supply_register (i, swapped); + } +} +#endif +/* Store register REGNO, or all if REGNO == -1. + Return errno value. */ +static void +hms_store_register (regno) + int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + { + hms_store_register (regno); + } + } + else + { + char *name = get_reg_name (regno); + char buffer[100]; + /* Some regs dont really exist */ + if (!(name[0] == 'p' && name[1] == 'r') + && !(name[0] == 'c' && name[1] == 'y') + && !(name[0] == 't' && name[1] == 'i') + && !(name[0] == 'i' && name[1] == 'n')) + { + sprintf (buffer, "r %s=%x", name, read_register (regno)); + hms_write_cr (buffer); + expect_prompt (); + } + } +} + + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +hms_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static CORE_ADDR +translate_addr (addr) + CORE_ADDR addr; +{ + + return (addr); + +} + + +int +hms_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + + return len; +} + +int +hms_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + bfd_vma addr; + int done; + int todo; + char buffer[100]; + done = 0; + hms_write_cr ("."); + expect_prompt (); + while (done < len) + { + char *ptr = buffer; + int thisgo; + int idx; + + thisgo = len - done; + if (thisgo > 20) + thisgo = 20; + + sprintf (ptr, "M.B %4x =", memaddr + done); + ptr += 10; + for (idx = 0; idx < thisgo; idx++) + { + sprintf (ptr, "%2x ", myaddr[idx + done]); + ptr += 3; + } + hms_write_cr (buffer); + expect_prompt (); + done += thisgo; + } +} + +void +hms_files_info () +{ + char *file = "nothing"; + + if (exec_bfd) + file = bfd_get_filename (exec_bfd); + + if (exec_bfd) +#ifdef __GO32__ + printf_filtered ("\tAttached to DOS asynctsr and running program %s\n", file); +#else + printf_filtered ("\tAttached to %s at %d baud and running program %s\n", dev_name, baudrate, file); +#endif + printf_filtered ("\ton an H8/300 processor.\n"); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns errno value. + * sb/sh instructions don't work on unaligned addresses, when TU=1. + */ + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns errno value. */ +int +hms_read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + /* Align to nearest low 16 bits */ + int i; + + CORE_ADDR start = memaddr; + CORE_ADDR end = memaddr + len - 1; + + int ok = 1; + + /* + AAAA: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX '................' + 012345678901234567890123456789012345678901234567890123456789012345 + 0 1 2 3 4 5 6 + */ + char buffer[66]; + + if (memaddr & 0xf) + abort (); + if (len != 16) + abort (); + + sprintf (buffer, "m %4x %4x", start & 0xffff, end & 0xffff); + + flush (); + hms_write_cr (buffer); + /* drop the echo and newline */ + for (i = 0; i < 13; i++) + readchar (); + + /* Grab the lines as they come out and fill the area */ + /* Skip over cr */ + while (1) + { + int p; + int i; + int addr; + size_t idx; + + char byte[16]; + + buffer[0] = readchar (); + while (buffer[0] == '\r' + || buffer[0] == '\n') + buffer[0] = readchar (); + + if (buffer[0] == 'M') + break; + + for (i = 1; i < 50; i++) + { + buffer[i] = readchar (); + } + /* sometimes we loose characters in the ascii representation of the + data. I don't know where. So just scan for the end of line */ + i = readchar (); + while (i != '\n' && i != '\r') + i = readchar (); + + /* Now parse the line */ + + addr = gethex (4, buffer, &ok); + idx = 6; + for (p = 0; p < 16; p += 2) + { + byte[p] = gethex (2, buffer + idx, &ok); + byte[p + 1] = gethex (2, buffer + idx + 2, &ok); + idx += 5; + } + + for (p = 0; p < 16; p++) + { + if (addr + p >= memaddr && + addr + p < memaddr + len) + { + myaddr[(addr + p) - memaddr] = byte[p]; + + } + + } + } +#ifdef GDB_TARGET_IS_H8500 + expect ("ore>"); +#endif +#ifdef GDB_TARGET_IS_H8300 + expect ("emory>"); +#endif + hms_write_cr ("."); + + expect_prompt (); + return len; +} + + + +#define MAX_BREAKS 16 +static int num_brkpts = 0; +static int +hms_insert_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let hms save instructions */ +{ + check_open (); + + if (num_brkpts < MAX_BREAKS) + { + char buffer[100]; + + num_brkpts++; + sprintf (buffer, "b %x", addr & 0xffff); + hms_write_cr (buffer); + expect_prompt (); + return (0); + } + else + { + fprintf_filtered (gdb_stderr, + "Too many break points, break point not installed\n"); + return (1); + } + +} +static int +hms_remove_breakpoint (addr, save) + CORE_ADDR addr; + char *save; /* Throw away, let hms save instructions */ +{ + if (num_brkpts > 0) + { + char buffer[100]; + + num_brkpts--; + sprintf (buffer, "b - %x", addr & 0xffff); + hms_write_cr (buffer); + expect_prompt (); + + } + return (0); +} + +/* Clear the hmss notion of what the break points are */ +static int +hms_clear_breakpoints () +{ + + if (is_open) + { + hms_write_cr ("b -"); + expect_prompt (); + } + num_brkpts = 0; +} +static void +hms_mourn () +{ + hms_clear_breakpoints (); + unpush_target (&hms_ops); + generic_mourn_inferior (); +} + +/* Put a command string, in args, out to the hms. The hms is assumed to + be in raw mode, all writing/reading done through desc. + Ouput from the hms is placed on the users terminal until the + prompt from the hms is seen. + FIXME: Can't handle commands that take input. */ + +void +hms_com (args, fromtty) + char *args; + int fromtty; +{ + check_open (); + + if (!args) + return; + + /* Clear all input so only command relative output is displayed */ + + hms_write_cr (args); +/* hms_write ("\030", 1); */ + expect_prompt (); +} + +static void +hms_open (name, from_tty) + char *name; + int from_tty; +{ + unsigned int prl; + char *p; + + if (name == 0) + { + name = ""; + } + if (is_open) + hms_close (0); + dev_name = strdup (name); + + if (!(desc = SERIAL_OPEN (dev_name))) + perror_with_name ((char *) dev_name); + + SERIAL_RAW (desc); + is_open = 1; + push_target (&hms_ops); + dcache_ptr = dcache_init (hms_read_inferior_memory, + hms_write_inferior_memory); + remote_dcache = 1; + /* Hello? Are you there? */ + SERIAL_WRITE (desc, "\r\n", 2); + expect_prompt (); + + /* Clear any break points */ + hms_clear_breakpoints (); + + printf_filtered ("Connected to remote board running HMS monitor.\n"); + add_commands (); +/* hms_drain (); */ +} + +/* Define the target subroutine names */ + +struct target_ops hms_ops = +{ + "hms", "Remote HMS monitor", + "Use the H8 evaluation board running the HMS monitor connected\n\ +by a serial line.", + + hms_open, hms_close, + 0, hms_detach, hms_resume, hms_wait, /* attach */ + hms_fetch_register, hms_store_register, + hms_prepare_to_store, + hms_xfer_inferior_memory, + hms_files_info, + hms_insert_breakpoint, hms_remove_breakpoint, /* Breakpoints */ + 0, 0, 0, 0, 0, /* Terminal handling */ + hms_kill, /* FIXME, kill */ + generic_load, + 0, /* lookup_symbol */ + hms_create_inferior, /* create_inferior */ + hms_mourn, /* mourn_inferior FIXME */ + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +hms_quiet () /* FIXME - this routine can be removed after Dec '94 */ +{ + quiet = !quiet; + if (quiet) + printf_filtered ("Snoop disabled\n"); + else + printf_filtered ("Snoop enabled\n"); + + printf_filtered ("`snoop' is obsolete, please use `set remotedebug'.\n"); +} + +hms_device (s) + char *s; +{ + if (s) + { + dev_name = get_word (&s); + } +} + +static +hms_speed (s) + char *s; +{ + check_open (); + + if (s) + { + char buffer[100]; + int newrate = atoi (s); + int which = 0; + + if (SERIAL_SETBAUDRATE (desc, newrate)) + error ("Can't use %d baud\n", newrate); + + printf_filtered ("Checking target is in sync\n"); + + printf_filtered ("Sending commands to set target to %d\n", + baudrate); + + sprintf (buffer, "tm %d. N 8 1", baudrate); + hms_write_cr (buffer); + } +} + +/***********************************************************************/ + +static void +hms_drain (args, fromtty) + char *args; + int fromtty; +{ + int c; + while (1) + { + c = SERIAL_READCHAR (desc, 1); + if (c == SERIAL_TIMEOUT) + break; + if (c == SERIAL_ERROR) + break; + if (c > ' ' && c < 127) + printf ("%c", c & 0xff); + else + printf ("<%x>", c & 0xff); + } +} + +static void +add_commands () +{ + + add_com ("hms_drain", class_obscure, hms_drain, + "Drain pending hms text buffers."); +} + +static void +remove_commands () +{ + extern struct cmd_list_element *cmdlist; + delete_cmd ("hms-drain", &cmdlist); +} + + +void +_initialize_remote_hms () +{ + add_target (&hms_ops); + + add_com ("hms ", class_obscure, hms_com, + "Send a command to the HMS monitor."); + + /* FIXME - hms_quiet and `snoop' can be removed after Dec '94 */ + add_com ("snoop", class_obscure, hms_quiet, + "Show what commands are going to the monitor (OBSOLETE - see 'set remotedebug')"); + + add_com ("device", class_obscure, hms_device, + "Set the terminal line for HMS communications"); + + add_com ("speed", class_obscure, hms_speed, + "Set the terminal line speed for HMS communications"); + + dev_name = NULL; +} +#endif + diff --git a/contrib/gdb/gdb/remote-mips.c b/contrib/gdb/gdb/remote-mips.c new file mode 100644 index 000000000000..176e1be66cb0 --- /dev/null +++ b/contrib/gdb/gdb/remote-mips.c @@ -0,0 +1,2997 @@ +/* Remote debugging interface for MIPS remote debugging protocol. + Copyright 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Ian Lance Taylor + . + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "wait.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "serial.h" +#include "target.h" +#include "remote-utils.h" + +#include +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +extern char *mips_read_processor_type PARAMS ((void)); + +extern void mips_set_processor_type_command PARAMS ((char *, int)); + + +/* Prototypes for local functions. */ + +static int mips_readchar PARAMS ((int timeout)); + +static int mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage, + int ch, int timeout)); + +static int mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage, + int *pch, int timeout)); + +static int mips_cksum PARAMS ((const unsigned char *hdr, + const unsigned char *data, + int len)); + +static void mips_send_packet PARAMS ((const char *s, int get_ack)); + +static void mips_send_command PARAMS ((const char *cmd, int prompt)); + +static int mips_receive_packet PARAMS ((char *buff, int throw_error, + int timeout)); + +static int mips_request PARAMS ((int cmd, unsigned int addr, + unsigned int data, int *perr, int timeout, + char *buff)); + +static void mips_initialize PARAMS ((void)); + +static void mips_open PARAMS ((char *name, int from_tty)); + +static void pmon_open PARAMS ((char *name, int from_tty)); + +static void mips_close PARAMS ((int quitting)); + +static void mips_detach PARAMS ((char *args, int from_tty)); + +static void mips_resume PARAMS ((int pid, int step, + enum target_signal siggnal)); + +static int mips_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static int pmon_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static int mips_map_regno PARAMS ((int regno)); + +static void mips_fetch_registers PARAMS ((int regno)); + +static void mips_prepare_to_store PARAMS ((void)); + +static void mips_store_registers PARAMS ((int regno)); + +static int mips_fetch_word PARAMS ((CORE_ADDR addr)); + +static int mips_store_word PARAMS ((CORE_ADDR addr, int value, + char *old_contents)); + +static int mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len, + int write, struct target_ops *ignore)); + +static void mips_files_info PARAMS ((struct target_ops *ignore)); + +static void mips_create_inferior PARAMS ((char *execfile, char *args, + char **env)); + +static void mips_mourn_inferior PARAMS ((void)); + +static int pmon_makeb64 PARAMS ((unsigned long v, char *p, int n, int *chksum)); + +static int pmon_zeroset PARAMS ((int recsize, char **buff, int *amount, + unsigned int *chksum)); + +static int pmon_checkset PARAMS ((int recsize, char **buff, int *value)); + +static void pmon_make_fastrec PARAMS ((char **outbuf, unsigned char *inbuf, + int *inptr, int inamount, int *recsize, + unsigned int *csum, unsigned int *zerofill)); + +static int pmon_check_ack PARAMS ((void)); + +static void pmon_load_fast PARAMS ((char *file)); + +static void mips_load PARAMS ((char *file, int from_tty)); + +static int mips_make_srec PARAMS ((char *buffer, int type, CORE_ADDR memaddr, + unsigned char *myaddr, int len)); + +static int common_breakpoint PARAMS ((int cmd, CORE_ADDR addr, CORE_ADDR mask, + char *flags)); + +static void common_open PARAMS ((struct target_ops *ops, char *name, + int from_tty)); +/* Forward declarations. */ +extern struct target_ops mips_ops; +extern struct target_ops pmon_ops; + +/* The MIPS remote debugging interface is built on top of a simple + packet protocol. Each packet is organized as follows: + + SYN The first character is always a SYN (ASCII 026, or ^V). SYN + may not appear anywhere else in the packet. Any time a SYN is + seen, a new packet should be assumed to have begun. + + TYPE_LEN + This byte contains the upper five bits of the logical length + of the data section, plus a single bit indicating whether this + is a data packet or an acknowledgement. The documentation + indicates that this bit is 1 for a data packet, but the actual + board uses 1 for an acknowledgement. The value of the byte is + 0x40 + (ack ? 0x20 : 0) + (len >> 6) + (we always have 0 <= len < 1024). Acknowledgement packets do + not carry data, and must have a data length of 0. + + LEN1 This byte contains the lower six bits of the logical length of + the data section. The value is + 0x40 + (len & 0x3f) + + SEQ This byte contains the six bit sequence number of the packet. + The value is + 0x40 + seq + An acknowlegment packet contains the sequence number of the + packet being acknowledged plus 1 modulo 64. Data packets are + transmitted in sequence. There may only be one outstanding + unacknowledged data packet at a time. The sequence numbers + are independent in each direction. If an acknowledgement for + the previous packet is received (i.e., an acknowledgement with + the sequence number of the packet just sent) the packet just + sent should be retransmitted. If no acknowledgement is + received within a timeout period, the packet should be + retransmitted. This has an unfortunate failure condition on a + high-latency line, as a delayed acknowledgement may lead to an + endless series of duplicate packets. + + DATA The actual data bytes follow. The following characters are + escaped inline with DLE (ASCII 020, or ^P): + SYN (026) DLE S + DLE (020) DLE D + ^C (003) DLE C + ^S (023) DLE s + ^Q (021) DLE q + The additional DLE characters are not counted in the logical + length stored in the TYPE_LEN and LEN1 bytes. + + CSUM1 + CSUM2 + CSUM3 + These bytes contain an 18 bit checksum of the complete + contents of the packet excluding the SEQ byte and the + CSUM[123] bytes. The checksum is simply the twos complement + addition of all the bytes treated as unsigned characters. The + values of the checksum bytes are: + CSUM1: 0x40 + ((cksum >> 12) & 0x3f) + CSUM2: 0x40 + ((cksum >> 6) & 0x3f) + CSUM3: 0x40 + (cksum & 0x3f) + + It happens that the MIPS remote debugging protocol always + communicates with ASCII strings. Because of this, this + implementation doesn't bother to handle the DLE quoting mechanism, + since it will never be required. */ + +/* The SYN character which starts each packet. */ +#define SYN '\026' + +/* The 0x40 used to offset each packet (this value ensures that all of + the header and trailer bytes, other than SYN, are printable ASCII + characters). */ +#define HDR_OFFSET 0x40 + +/* The indices of the bytes in the packet header. */ +#define HDR_INDX_SYN 0 +#define HDR_INDX_TYPE_LEN 1 +#define HDR_INDX_LEN1 2 +#define HDR_INDX_SEQ 3 +#define HDR_LENGTH 4 + +/* The data/ack bit in the TYPE_LEN header byte. */ +#define TYPE_LEN_DA_BIT 0x20 +#define TYPE_LEN_DATA 0 +#define TYPE_LEN_ACK TYPE_LEN_DA_BIT + +/* How to compute the header bytes. */ +#define HDR_SET_SYN(data, len, seq) (SYN) +#define HDR_SET_TYPE_LEN(data, len, seq) \ + (HDR_OFFSET \ + + ((data) ? TYPE_LEN_DATA : TYPE_LEN_ACK) \ + + (((len) >> 6) & 0x1f)) +#define HDR_SET_LEN1(data, len, seq) (HDR_OFFSET + ((len) & 0x3f)) +#define HDR_SET_SEQ(data, len, seq) (HDR_OFFSET + (seq)) + +/* Check that a header byte is reasonable. */ +#define HDR_CHECK(ch) (((ch) & HDR_OFFSET) == HDR_OFFSET) + +/* Get data from the header. These macros evaluate their argument + multiple times. */ +#define HDR_IS_DATA(hdr) \ + (((hdr)[HDR_INDX_TYPE_LEN] & TYPE_LEN_DA_BIT) == TYPE_LEN_DATA) +#define HDR_GET_LEN(hdr) \ + ((((hdr)[HDR_INDX_TYPE_LEN] & 0x1f) << 6) + (((hdr)[HDR_INDX_LEN1] & 0x3f))) +#define HDR_GET_SEQ(hdr) ((hdr)[HDR_INDX_SEQ] & 0x3f) + +/* The maximum data length. */ +#define DATA_MAXLEN 1023 + +/* The trailer offset. */ +#define TRLR_OFFSET HDR_OFFSET + +/* The indices of the bytes in the packet trailer. */ +#define TRLR_INDX_CSUM1 0 +#define TRLR_INDX_CSUM2 1 +#define TRLR_INDX_CSUM3 2 +#define TRLR_LENGTH 3 + +/* How to compute the trailer bytes. */ +#define TRLR_SET_CSUM1(cksum) (TRLR_OFFSET + (((cksum) >> 12) & 0x3f)) +#define TRLR_SET_CSUM2(cksum) (TRLR_OFFSET + (((cksum) >> 6) & 0x3f)) +#define TRLR_SET_CSUM3(cksum) (TRLR_OFFSET + (((cksum) ) & 0x3f)) + +/* Check that a trailer byte is reasonable. */ +#define TRLR_CHECK(ch) (((ch) & TRLR_OFFSET) == TRLR_OFFSET) + +/* Get data from the trailer. This evaluates its argument multiple + times. */ +#define TRLR_GET_CKSUM(trlr) \ + ((((trlr)[TRLR_INDX_CSUM1] & 0x3f) << 12) \ + + (((trlr)[TRLR_INDX_CSUM2] & 0x3f) << 6) \ + + ((trlr)[TRLR_INDX_CSUM3] & 0x3f)) + +/* The sequence number modulos. */ +#define SEQ_MODULOS (64) + +enum mips_monitor_type { + /* IDT/SIM monitor being used: */ + MON_IDT, + /* PMON monitor being used: */ + MON_PMON, + /* Last and unused value, for sizing vectors, etc. */ + MON_LAST +}; +static enum mips_monitor_type mips_monitor = MON_LAST; + +/* The default monitor prompt text: */ +static char *mips_monitor_prompt = TARGET_MONITOR_PROMPT; +/* For the Cogent PMON world this is still not ideal. The default + prompt is "PMON> ", unfortunately the user can change the prompt + and the new prompt will survive over a power-cycle (EEPROM). This + means that the code should really force the monitor prompt to a + known value as the very first action, and that the + "mips_monitor_prompt" support is not needed... since the prompt + could be explicitly set to TARGET_MONITOR_PROMPT (even though it + may be the prompt for a different monitor). However, this will + require changing the mips_initialize reset sequence. (TODO) */ + +/* Set to 1 if the target is open. */ +static int mips_is_open; + +/* Currently active target description (if mips_is_open == 1) */ +static struct target_ops *current_ops; + +/* Set to 1 while the connection is being initialized. */ +static int mips_initializing; + +/* The next sequence number to send. */ +static unsigned int mips_send_seq; + +/* The next sequence number we expect to receive. */ +static unsigned int mips_receive_seq; + +/* The time to wait before retransmitting a packet, in seconds. */ +static int mips_retransmit_wait = 3; + +/* The number of times to try retransmitting a packet before giving up. */ +static int mips_send_retries = 10; + +/* The number of garbage characters to accept when looking for an + SYN for the next packet. */ +static int mips_syn_garbage = 1050; + +/* The time to wait for a packet, in seconds. */ +static int mips_receive_wait = 5; + +/* Set if we have sent a packet to the board but have not yet received + a reply. */ +static int mips_need_reply = 0; + +/* Handle used to access serial I/O stream. */ +static serial_t mips_desc; + +/* Counts the number of times the user tried to interrupt the target (usually + via ^C. */ +static int interrupt_count; + +/* If non-zero, means that the target is running. */ +static int mips_wait_flag = 0; + +/* If non-zero, monitor supports breakpoint commands. */ +static monitor_supports_breakpoints = 0; + +/* Data cache header. */ + +static DCACHE *mips_dcache; + +/* Non-zero means that we've just hit a read or write watchpoint */ +static int hit_watchpoint; + +/* Handle low-level error that we can't recover from. Note that just + error()ing out from target_wait or some such low-level place will cause + all hell to break loose--the rest of GDB will tend to get left in an + inconsistent state. */ + +static NORETURN void +#ifdef ANSI_PROTOTYPES +mips_error (char *string, ...) +#else +mips_error (va_alist) + va_dcl +#endif +{ + va_list args; + +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + va_start (args); + string = va_arg (args, char *); +#endif + + target_terminal_ours (); + wrap_here(""); /* Force out any buffered output */ + gdb_flush (gdb_stdout); + if (error_pre_print) + fprintf_filtered (gdb_stderr, error_pre_print); + vfprintf_filtered (gdb_stderr, string, args); + fprintf_filtered (gdb_stderr, "\n"); + va_end (args); + gdb_flush (gdb_stderr); + + /* Clean up in such a way that mips_close won't try to talk to the + board (it almost surely won't work since we weren't able to talk to + it). */ + mips_is_open = 0; + SERIAL_CLOSE (mips_desc); + + printf_unfiltered ("Ending remote MIPS debugging.\n"); + target_mourn_inferior (); + + return_to_top_level (RETURN_ERROR); +} + +/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if + timed out. */ + +int +mips_expect (string) + char *string; +{ + char *p = string; + + immediate_quit = 1; + while (1) + { + int c; + +/* Must use SERIAL_READCHAR here cuz mips_readchar would get confused if we + were waiting for the mips_monitor_prompt... */ + + c = SERIAL_READCHAR (mips_desc, 2); + + if (c == SERIAL_TIMEOUT) + return 0; + + if (c == *p++) + { + if (*p == '\0') + { + immediate_quit = 0; + return 1; + } + } + else + { + p = string; + if (c == *p) + p++; + } + } +} + +/* Read the required number of characters into the given buffer (which + is assumed to be large enough). The only failure is a timeout. */ +int +mips_getstring (string, n) + char *string; + int n; +{ + char *p = string; + int c; + + immediate_quit = 1; + while (n > 0) + { + c = SERIAL_READCHAR (mips_desc, 2); + + if (c == SERIAL_TIMEOUT) { + fprintf_unfiltered (stderr, "Failed to read %d characters from target (TIMEOUT)\n", n); + return 0; + } + + *p++ = c; + n--; + } + + return 1; +} + +/* Read a character from the remote, aborting on error. Returns + SERIAL_TIMEOUT on timeout (since that's what SERIAL_READCHAR + returns). FIXME: If we see the string mips_monitor_prompt from + the board, then we are debugging on the main console port, and we + have somehow dropped out of remote debugging mode. In this case, + we automatically go back in to remote debugging mode. This is a + hack, put in because I can't find any way for a program running on + the remote board to terminate without also ending remote debugging + mode. I assume users won't have any trouble with this; for one + thing, the IDT documentation generally assumes that the remote + debugging port is not the console port. This is, however, very + convenient for DejaGnu when you only have one connected serial + port. */ + +static int +mips_readchar (timeout) + int timeout; +{ + int ch; + static int state = 0; + static int mips_monitor_prompt_len = -1; + + /* NASTY, since we assume that the prompt does not change after the + first mips_readchar call: */ + if (mips_monitor_prompt_len = -1) + mips_monitor_prompt_len = strlen(mips_monitor_prompt); + +#ifdef MAINTENANCE_CMDS + { + int i; + + i = timeout; + if (i == -1 && watchdog > 0) + i = watchdog; + } +#endif + + if (state == mips_monitor_prompt_len) + timeout = 1; + ch = SERIAL_READCHAR (mips_desc, timeout); +#ifdef MAINTENANCE_CMDS + if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */ + { + target_mourn_inferior (); + error ("Watchdog has expired. Target detached.\n"); + } +#endif + if (ch == SERIAL_EOF) + mips_error ("End of file from remote"); + if (ch == SERIAL_ERROR) + mips_error ("Error reading from remote: %s", safe_strerror (errno)); + if (remote_debug > 1) + { + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + if (ch != SERIAL_TIMEOUT) + printf_unfiltered ("Read '%c' %d 0x%x\n", ch, ch, ch); + else + printf_unfiltered ("Timed out in read\n"); + } + + /* If we have seen mips_monitor_prompt and we either time out, or + we see a @ (which was echoed from a packet we sent), reset the + board as described above. The first character in a packet after + the SYN (which is not echoed) is always an @ unless the packet is + more than 64 characters long, which ours never are. */ + if ((ch == SERIAL_TIMEOUT || ch == '@') + && state == mips_monitor_prompt_len + && ! mips_initializing) + { + if (remote_debug > 0) + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Reinitializing MIPS debugging mode\n"); + + mips_need_reply = 0; + mips_initialize (); + + state = 0; + + /* At this point, about the only thing we can do is abort the command + in progress and get back to command level as quickly as possible. */ + + error ("Remote board reset, debug protocol re-initialized."); + } + + if (ch == mips_monitor_prompt[state]) + ++state; + else + state = 0; + + return ch; +} + +/* Get a packet header, putting the data in the supplied buffer. + PGARBAGE is a pointer to the number of garbage characters received + so far. CH is the last character received. Returns 0 for success, + or -1 for timeout. */ + +static int +mips_receive_header (hdr, pgarbage, ch, timeout) + unsigned char *hdr; + int *pgarbage; + int ch; + int timeout; +{ + int i; + + while (1) + { + /* Wait for a SYN. mips_syn_garbage is intended to prevent + sitting here indefinitely if the board sends us one garbage + character per second. ch may already have a value from the + last time through the loop. */ + while (ch != SYN) + { + ch = mips_readchar (timeout); + if (ch == SERIAL_TIMEOUT) + return -1; + if (ch != SYN) + { + /* Printing the character here lets the user of gdb see + what the program is outputting, if the debugging is + being done on the console port. Don't use _filtered; + we can't deal with a QUIT out of target_wait. */ + if (! mips_initializing || remote_debug > 0) + { + /* Note that the host's idea of newline may not + correspond to the target's idea, so recognize + newline by its actual ASCII code, but write it + out using the \n notation. */ + if (ch < 0x20 && ch != '\012') + { + putchar_unfiltered ('^'); + putchar_unfiltered (ch + 0x40); + } + else if (ch == '\012') + putchar_unfiltered ('\n'); + else + putchar_unfiltered (ch); + gdb_flush (gdb_stdout); + } + + ++*pgarbage; + if (mips_syn_garbage > 0 + && *pgarbage > mips_syn_garbage) + mips_error ("Debug protocol failure: more than %d characters before a sync.", + mips_syn_garbage); + } + } + + /* Get the packet header following the SYN. */ + for (i = 1; i < HDR_LENGTH; i++) + { + ch = mips_readchar (timeout); + if (ch == SERIAL_TIMEOUT) + return -1; + /* Make sure this is a header byte. */ + if (ch == SYN || ! HDR_CHECK (ch)) + break; + + hdr[i] = ch; + } + + /* If we got the complete header, we can return. Otherwise we + loop around and keep looking for SYN. */ + if (i >= HDR_LENGTH) + return 0; + } +} + +/* Get a packet header, putting the data in the supplied buffer. + PGARBAGE is a pointer to the number of garbage characters received + so far. The last character read is returned in *PCH. Returns 0 + for success, -1 for timeout, -2 for error. */ + +static int +mips_receive_trailer (trlr, pgarbage, pch, timeout) + unsigned char *trlr; + int *pgarbage; + int *pch; + int timeout; +{ + int i; + int ch; + + for (i = 0; i < TRLR_LENGTH; i++) + { + ch = mips_readchar (timeout); + *pch = ch; + if (ch == SERIAL_TIMEOUT) + return -1; + if (! TRLR_CHECK (ch)) + return -2; + trlr[i] = ch; + } + return 0; +} + +/* Get the checksum of a packet. HDR points to the packet header. + DATA points to the packet data. LEN is the length of DATA. */ + +static int +mips_cksum (hdr, data, len) + const unsigned char *hdr; + const unsigned char *data; + int len; +{ + register const unsigned char *p; + register int c; + register int cksum; + + cksum = 0; + + /* The initial SYN is not included in the checksum. */ + c = HDR_LENGTH - 1; + p = hdr + 1; + while (c-- != 0) + cksum += *p++; + + c = len; + p = data; + while (c-- != 0) + cksum += *p++; + + return cksum; +} + +/* Send a packet containing the given ASCII string. */ + +static void +mips_send_packet (s, get_ack) + const char *s; + int get_ack; +{ + unsigned int len; + unsigned char *packet; + register int cksum; + int try; + + len = strlen (s); + if (len > DATA_MAXLEN) + mips_error ("MIPS protocol data packet too long: %s", s); + + packet = (unsigned char *) alloca (HDR_LENGTH + len + TRLR_LENGTH + 1); + + packet[HDR_INDX_SYN] = HDR_SET_SYN (1, len, mips_send_seq); + packet[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (1, len, mips_send_seq); + packet[HDR_INDX_LEN1] = HDR_SET_LEN1 (1, len, mips_send_seq); + packet[HDR_INDX_SEQ] = HDR_SET_SEQ (1, len, mips_send_seq); + + memcpy (packet + HDR_LENGTH, s, len); + + cksum = mips_cksum (packet, packet + HDR_LENGTH, len); + packet[HDR_LENGTH + len + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); + packet[HDR_LENGTH + len + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); + packet[HDR_LENGTH + len + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); + + /* Increment the sequence number. This will set mips_send_seq to + the sequence number we expect in the acknowledgement. */ + mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS; + + /* We can only have one outstanding data packet, so we just wait for + the acknowledgement here. Keep retransmitting the packet until + we get one, or until we've tried too many times. */ + for (try = 0; try < mips_send_retries; try++) + { + int garbage; + int ch; + + if (remote_debug > 0) + { + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0'; + printf_unfiltered ("Writing \"%s\"\n", packet + 1); + } + + if (SERIAL_WRITE (mips_desc, packet, + HDR_LENGTH + len + TRLR_LENGTH) != 0) + mips_error ("write to target failed: %s", safe_strerror (errno)); + + if (! get_ack) + return; + + garbage = 0; + ch = 0; + while (1) + { + unsigned char hdr[HDR_LENGTH + 1]; + unsigned char trlr[TRLR_LENGTH + 1]; + int err; + int seq; + + /* Get the packet header. If we time out, resend the data + packet. */ + err = mips_receive_header (hdr, &garbage, ch, mips_retransmit_wait); + if (err != 0) + break; + + ch = 0; + + /* If we get a data packet, assume it is a duplicate and + ignore it. FIXME: If the acknowledgement is lost, this + data packet may be the packet the remote sends after the + acknowledgement. */ + if (HDR_IS_DATA (hdr)) { + int i; + + /* Ignore any errors raised whilst attempting to ignore + packet. */ + + len = HDR_GET_LEN (hdr); + + for (i = 0; i < len; i++) + { + int rch; + + rch = mips_readchar (2); + if (rch == SYN) + { + ch = SYN; + break; + } + if (rch == SERIAL_TIMEOUT) + break; + /* ignore the character */ + } + + if (i == len) + (void) mips_receive_trailer (trlr, &garbage, &ch, 2); + + /* We don't bother checking the checksum, or providing an + ACK to the packet. */ + continue; + } + + /* If the length is not 0, this is a garbled packet. */ + if (HDR_GET_LEN (hdr) != 0) + continue; + + /* Get the packet trailer. */ + err = mips_receive_trailer (trlr, &garbage, &ch, + mips_retransmit_wait); + + /* If we timed out, resend the data packet. */ + if (err == -1) + break; + + /* If we got a bad character, reread the header. */ + if (err != 0) + continue; + + /* If the checksum does not match the trailer checksum, this + is a bad packet; ignore it. */ + if (mips_cksum (hdr, (unsigned char *) NULL, 0) + != TRLR_GET_CKSUM (trlr)) + continue; + + if (remote_debug > 0) + { + hdr[HDR_LENGTH] = '\0'; + trlr[TRLR_LENGTH] = '\0'; + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Got ack %d \"%s%s\"\n", + HDR_GET_SEQ (hdr), hdr + 1, trlr); + } + + /* If this ack is for the current packet, we're done. */ + seq = HDR_GET_SEQ (hdr); + if (seq == mips_send_seq) + return; + + /* If this ack is for the last packet, resend the current + packet. */ + if ((seq + 1) % SEQ_MODULOS == mips_send_seq) + break; + + /* Otherwise this is a bad ack; ignore it. Increment the + garbage count to ensure that we do not stay in this loop + forever. */ + ++garbage; + } + } + + mips_error ("Remote did not acknowledge packet"); +} + +/* Receive and acknowledge a packet, returning the data in BUFF (which + should be DATA_MAXLEN + 1 bytes). The protocol documentation + implies that only the sender retransmits packets, so this code just + waits silently for a packet. It returns the length of the received + packet. If THROW_ERROR is nonzero, call error() on errors. If not, + don't print an error message and return -1. */ + +static int +mips_receive_packet (buff, throw_error, timeout) + char *buff; + int throw_error; + int timeout; +{ + int ch; + int garbage; + int len; + unsigned char ack[HDR_LENGTH + TRLR_LENGTH + 1]; + int cksum; + + ch = 0; + garbage = 0; + while (1) + { + unsigned char hdr[HDR_LENGTH]; + unsigned char trlr[TRLR_LENGTH]; + int i; + int err; + + if (mips_receive_header (hdr, &garbage, ch, timeout) != 0) + { + if (throw_error) + mips_error ("Timed out waiting for remote packet"); + else + return -1; + } + + ch = 0; + + /* An acknowledgement is probably a duplicate; ignore it. */ + if (! HDR_IS_DATA (hdr)) + { + len = HDR_GET_LEN (hdr); + /* Check if the length is valid for an ACK, we may aswell + try and read the remainder of the packet: */ + if (len == 0) + { + /* Ignore the error condition, since we are going to + ignore the packet anyway. */ + (void) mips_receive_trailer (trlr, &garbage, &ch, timeout); + } + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + if (remote_debug > 0) + printf_unfiltered ("Ignoring unexpected ACK\n"); + continue; + } + + len = HDR_GET_LEN (hdr); + for (i = 0; i < len; i++) + { + int rch; + + rch = mips_readchar (timeout); + if (rch == SYN) + { + ch = SYN; + break; + } + if (rch == SERIAL_TIMEOUT) + { + if (throw_error) + mips_error ("Timed out waiting for remote packet"); + else + return -1; + } + buff[i] = rch; + } + + if (i < len) + { + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + if (remote_debug > 0) + printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n", + i, len); + continue; + } + + err = mips_receive_trailer (trlr, &garbage, &ch, timeout); + if (err == -1) + { + if (throw_error) + mips_error ("Timed out waiting for packet"); + else + return -1; + } + if (err == -2) + { + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + if (remote_debug > 0) + printf_unfiltered ("Got SYN when wanted trailer\n"); + continue; + } + + /* If this is the wrong sequence number, ignore it. */ + if (HDR_GET_SEQ (hdr) != mips_receive_seq) + { + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + if (remote_debug > 0) + printf_unfiltered ("Ignoring sequence number %d (want %d)\n", + HDR_GET_SEQ (hdr), mips_receive_seq); + continue; + } + + if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr)) + break; + + if (remote_debug > 0) + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Bad checksum; data %d, trailer %d\n", + mips_cksum (hdr, buff, len), + TRLR_GET_CKSUM (trlr)); + + /* The checksum failed. Send an acknowledgement for the + previous packet to tell the remote to resend the packet. */ + ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq); + ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq); + ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq); + ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq); + + cksum = mips_cksum (ack, (unsigned char *) NULL, 0); + + ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); + ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); + ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); + + if (remote_debug > 0) + { + ack[HDR_LENGTH + TRLR_LENGTH] = '\0'; + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq, + ack + 1); + } + + if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0) + { + if (throw_error) + mips_error ("write to target failed: %s", safe_strerror (errno)); + else + return -1; + } + } + + if (remote_debug > 0) + { + buff[len] = '\0'; + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Got packet \"%s\"\n", buff); + } + + /* We got the packet. Send an acknowledgement. */ + mips_receive_seq = (mips_receive_seq + 1) % SEQ_MODULOS; + + ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq); + ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq); + ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq); + ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq); + + cksum = mips_cksum (ack, (unsigned char *) NULL, 0); + + ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); + ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); + ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); + + if (remote_debug > 0) + { + ack[HDR_LENGTH + TRLR_LENGTH] = '\0'; + /* Don't use _filtered; we can't deal with a QUIT out of + target_wait, and I think this might be called from there. */ + printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq, + ack + 1); + } + + if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0) + { + if (throw_error) + mips_error ("write to target failed: %s", safe_strerror (errno)); + else + return -1; + } + + return len; +} + +/* Optionally send a request to the remote system and optionally wait + for the reply. This implements the remote debugging protocol, + which is built on top of the packet protocol defined above. Each + request has an ADDR argument and a DATA argument. The following + requests are defined: + + \0 don't send a request; just wait for a reply + i read word from instruction space at ADDR + d read word from data space at ADDR + I write DATA to instruction space at ADDR + D write DATA to data space at ADDR + r read register number ADDR + R set register number ADDR to value DATA + c continue execution (if ADDR != 1, set pc to ADDR) + s single step (if ADDR != 1, set pc to ADDR) + + The read requests return the value requested. The write requests + return the previous value in the changed location. The execution + requests return a UNIX wait value (the approximate signal which + caused execution to stop is in the upper eight bits). + + If PERR is not NULL, this function waits for a reply. If an error + occurs, it sets *PERR to 1 and sets errno according to what the + target board reports. */ + +static int +mips_request (cmd, addr, data, perr, timeout, buff) + int cmd; + unsigned int addr; + unsigned int data; + int *perr; + int timeout; + char *buff; +{ + char myBuff[DATA_MAXLEN + 1]; + int len; + int rpid; + char rcmd; + int rerrflg; + int rresponse; + + if (buff == (char *) NULL) + buff = myBuff; + + if (cmd != '\0') + { + if (mips_need_reply) + fatal ("mips_request: Trying to send command before reply"); + sprintf (buff, "0x0 %c 0x%x 0x%x", cmd, addr, data); + mips_send_packet (buff, 1); + mips_need_reply = 1; + } + + if (perr == (int *) NULL) + return 0; + + if (! mips_need_reply) + fatal ("mips_request: Trying to get reply before command"); + + mips_need_reply = 0; + + len = mips_receive_packet (buff, 1, timeout); + buff[len] = '\0'; + + if (sscanf (buff, "0x%x %c 0x%x 0x%x", + &rpid, &rcmd, &rerrflg, &rresponse) != 4 + || (cmd != '\0' && rcmd != cmd)) + mips_error ("Bad response from remote board"); + + if (rerrflg != 0) + { + *perr = 1; + + /* FIXME: This will returns MIPS errno numbers, which may or may + not be the same as errno values used on other systems. If + they stick to common errno values, they will be the same, but + if they don't, they must be translated. */ + errno = rresponse; + + return 0; + } + + *perr = 0; + return rresponse; +} + +static void +mips_initialize_cleanups (arg) + PTR arg; +{ + mips_initializing = 0; +} + +static void +mips_send_command (cmd, prompt) + const char *cmd; + int prompt; +{ + SERIAL_WRITE (mips_desc, cmd, strlen(cmd)); + mips_expect (cmd); + mips_expect ("\012"); + if (prompt) + mips_expect (mips_monitor_prompt); +} + +/* Enter remote (dbx) debug mode: */ +static void +mips_enter_debug () +{ + /* Reset the sequence numbers, ready for the new debug sequence: */ + mips_send_seq = 0; + mips_receive_seq = 0; + + if (mips_monitor == MON_PMON) + mips_send_command ("debug\015", 0); + else /* assume IDT monitor by default */ + mips_send_command ("db tty0\015", 0); + + SERIAL_WRITE (mips_desc, "\015", sizeof "\015" - 1); + + /* We don't need to absorb any spurious characters here, since the + mips_receive_header will eat up a reasonable number of characters + whilst looking for the SYN, however this avoids the "garbage" + being displayed to the user. */ + if (mips_monitor == MON_PMON) + mips_expect ("\015"); + + { + char buff[DATA_MAXLEN + 1]; + if (mips_receive_packet (buff, 1, 3) < 0) + mips_error ("Failed to initialize (didn't receive packet)."); + } +} + +/* Exit remote (dbx) debug mode, returning to the monitor prompt: */ +static int +mips_exit_debug () +{ + int err; + + mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err, + mips_receive_wait, NULL); + + if (mips_monitor == MON_PMON && !mips_expect ("Exiting remote debug mode")) + return -1; + + if (!mips_expect ("\015\012")) + return -1; + + if (!mips_expect (mips_monitor_prompt)) + return -1; + + return 0; +} + +/* Initialize a new connection to the MIPS board, and make sure we are + really connected. */ + +static void +mips_initialize () +{ + int err; + struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL); + int j; + + /* What is this code doing here? I don't see any way it can happen, and + it might mean mips_initializing didn't get cleared properly. + So I'll make it a warning. */ + + if (mips_initializing) + { + warning ("internal error: mips_initialize called twice"); + return; + } + + mips_wait_flag = 0; + mips_initializing = 1; + + /* At this point, the packit protocol isn't responding. We'll try getting + into the monitor, and restarting the protocol. */ + + /* Force the system into the monitor. After this we *should* be at + the mips_monitor_prompt. */ + if (mips_monitor == MON_PMON) + j = 0; /* start by checking if we are already at the prompt */ + else + j = 1; /* start by sending a break */ + for (; j <= 4; j++) + { + switch (j) + { + case 0: /* First, try sending a CR */ + SERIAL_FLUSH_INPUT (mips_desc); + SERIAL_WRITE (mips_desc, "\015", 1); + break; + case 1: /* First, try sending a break */ + SERIAL_SEND_BREAK (mips_desc); + break; + case 2: /* Then, try a ^C */ + SERIAL_WRITE (mips_desc, "\003", 1); + break; + case 3: /* Then, try escaping from download */ + { + if (mips_monitor == MON_PMON) + { + char tbuff[7]; + + /* We shouldn't need to send multiple termination + sequences, since the target performs line (or + block) reads, and then processes those + packets. In-case we were downloading a large packet + we flush the output buffer before inserting a + termination sequence. */ + SERIAL_FLUSH_OUTPUT (mips_desc); + sprintf (tbuff, "\015/E/E\015"); + SERIAL_WRITE (mips_desc, tbuff, 6); + } + else + { + char srec[10]; + int i; + + /* We are possibly in binary download mode, having + aborted in the middle of an S-record. ^C won't + work because of binary mode. The only reliable way + out is to send enough termination packets (8 bytes) + to fill up and then overflow the largest size + S-record (255 bytes in this case). This amounts to + 256/8 + 1 packets. + */ + + mips_make_srec (srec, '7', 0, NULL, 0); + + for (i = 1; i <= 33; i++) + { + SERIAL_WRITE (mips_desc, srec, 8); + + if (SERIAL_READCHAR (mips_desc, 0) >= 0) + break; /* Break immediatly if we get something from + the board. */ + } + } + } + break; + case 4: + mips_error ("Failed to initialize."); + } + + if (mips_expect (mips_monitor_prompt)) + break; + } + + if (mips_monitor == MON_PMON) + { + /* Ensure the correct target state: */ + mips_send_command ("set regsize 64\015", -1); + mips_send_command ("set hostport tty0\015", -1); + mips_send_command ("set brkcmd \"\"\015", -1); + /* Delete all the current breakpoints: */ + mips_send_command ("db *\015", -1); + /* NOTE: PMON does not have breakpoint support through the + "debug" mode, only at the monitor command-line. */ + } + + mips_enter_debug (); + + /* Clear all breakpoints: */ + if (common_breakpoint ('b', -1, 0, NULL)) + monitor_supports_breakpoints = 0; + else + monitor_supports_breakpoints = 1; + + do_cleanups (old_cleanups); + + /* If this doesn't call error, we have connected; we don't care if + the request itself succeeds or fails. */ + + mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err, + mips_receive_wait, NULL); + set_current_frame (create_new_frame (read_fp (), read_pc ())); + select_frame (get_current_frame (), 0); +} + +/* Open a connection to the remote board. */ +static void +common_open (ops, name, from_tty) + struct target_ops *ops; + char *name; + int from_tty; +{ + char *ptype; + + if (name == 0) + error ( +"To open a MIPS remote debugging connection, you need to specify what serial\n\ +device is attached to the target board (e.g., /dev/ttya)."); + + target_preopen (from_tty); + + if (mips_is_open) + unpush_target (current_ops); + + mips_desc = SERIAL_OPEN (name); + if (mips_desc == (serial_t) NULL) + perror_with_name (name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (mips_desc, baud_rate)) + { + SERIAL_CLOSE (mips_desc); + perror_with_name (name); + } + } + + SERIAL_RAW (mips_desc); + + current_ops = ops; + mips_is_open = 1; + + mips_initialize (); + + if (from_tty) + printf_unfiltered ("Remote MIPS debugging using %s\n", name); + + /* Switch to using remote target now. */ + push_target (ops); + + /* FIXME: Should we call start_remote here? */ + + /* Try to figure out the processor model if possible. */ + ptype = mips_read_processor_type (); + if (ptype) + mips_set_processor_type_command (strsave (ptype), 0); + +/* This is really the job of start_remote however, that makes an assumption + that the target is about to print out a status message of some sort. That + doesn't happen here (in fact, it may not be possible to get the monitor to + send the appropriate packet). */ + + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc (); + set_current_frame (create_new_frame (read_fp (), stop_pc)); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, -1, 1); +} + +static void +mips_open (name, from_tty) + char *name; + int from_tty; +{ + mips_monitor = MON_IDT; + common_open (&mips_ops, name, from_tty); +} + +static void +pmon_open (name, from_tty) + char *name; + int from_tty; +{ + /* The PMON monitor has a prompt different from the default + "TARGET_MONITOR_PROMPT": */ + mips_monitor_prompt = "PMON> "; + mips_monitor = MON_PMON; + common_open (&pmon_ops, name, from_tty); +} + + +/* Close a connection to the remote board. */ + +static void +mips_close (quitting) + int quitting; +{ + if (mips_is_open) + { + int err; + + mips_is_open = 0; + + /* Get the board out of remote debugging mode. */ + (void) mips_exit_debug (); + + SERIAL_CLOSE (mips_desc); + } +} + +/* Detach from the remote board. */ + +static void +mips_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + pop_target (); + + mips_close (1); + + if (from_tty) + printf_unfiltered ("Ending remote MIPS debugging.\n"); +} + +/* Tell the target board to resume. This does not wait for a reply + from the board. */ + +static void +mips_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + + + mips_request (step ? 's' : 'c', + (unsigned int) 1, + (unsigned int) siggnal, + (int *) NULL, + mips_receive_wait, NULL); +} + +/* Return the signal corresponding to SIG, where SIG is the number which + the MIPS protocol uses for the signal. */ +enum target_signal +mips_signal_from_protocol (sig) + int sig; +{ + /* We allow a few more signals than the IDT board actually returns, on + the theory that there is at least *some* hope that perhaps the numbering + for these signals is widely agreed upon. */ + if (sig <= 0 + || sig > 31) + return TARGET_SIGNAL_UNKNOWN; + + /* Don't want to use target_signal_from_host because we are converting + from MIPS signal numbers, not host ones. Our internal numbers + match the MIPS numbers for the signals the board can return, which + are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP. */ + return (enum target_signal) sig; +} + +/* Wait until the remote stops, and return a wait status. */ + +static int +mips_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int rstatus; + int err; + char buff[DATA_MAXLEN]; + int rpc, rfp, rsp; + char flags[20]; + int nfields; + + interrupt_count = 0; + hit_watchpoint = 0; + + /* If we have not sent a single step or continue command, then the + board is waiting for us to do something. Return a status + indicating that it is stopped. */ + if (! mips_need_reply) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + return 0; + } + + /* No timeout; we sit here as long as the program continues to execute. */ + mips_wait_flag = 1; + rstatus = mips_request ('\000', (unsigned int) 0, (unsigned int) 0, &err, -1, + buff); + mips_wait_flag = 0; + if (err) + mips_error ("Remote failure: %s", safe_strerror (errno)); + + nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s", + &rpc, &rfp, &rsp, flags); + + /* See if we got back extended status. If so, pick out the pc, fp, sp, etc... */ + + if (nfields == 7 || nfields == 9) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rpc); + supply_register (PC_REGNUM, buf); + + store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rfp); + supply_register (30, buf); /* This register they are avoiding and so it is unnamed */ + + store_unsigned_integer (buf, REGISTER_RAW_SIZE (SP_REGNUM), rsp); + supply_register (SP_REGNUM, buf); + + store_unsigned_integer (buf, REGISTER_RAW_SIZE (FP_REGNUM), 0); + supply_register (FP_REGNUM, buf); + + if (nfields == 9) + { + int i; + + for (i = 0; i <= 2; i++) + if (flags[i] == 'r' || flags[i] == 'w') + hit_watchpoint = 1; + else if (flags[i] == '\000') + break; + } + } + + /* Translate a MIPS waitstatus. We use constants here rather than WTERMSIG + and so on, because the constants we want here are determined by the + MIPS protocol and have nothing to do with what host we are running on. */ + if ((rstatus & 0377) == 0) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (((rstatus) >> 8) & 0377); + } + else if ((rstatus & 0377) == 0177) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0377); + } + else + { + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = mips_signal_from_protocol (rstatus & 0177); + } + + return 0; +} + +static int +pmon_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int rstatus; + int err; + char buff[DATA_MAXLEN]; + + interrupt_count = 0; + hit_watchpoint = 0; + + /* If we have not sent a single step or continue command, then the + board is waiting for us to do something. Return a status + indicating that it is stopped. */ + if (! mips_need_reply) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + return 0; + } + + /* Sit, polling the serial until the target decides to talk to + us. NOTE: the timeout value we use is used not just for the + first character, but for all the characters. */ + mips_wait_flag = 1; + rstatus = mips_request ('\000', (unsigned int) 0, (unsigned int) 0, &err, -1, + buff); + mips_wait_flag = 0; + if (err) + mips_error ("Remote failure: %s", safe_strerror (errno)); + + /* NOTE: The following (sig) numbers are defined by PMON: + SPP_SIGTRAP 5 breakpoint + SPP_SIGINT 2 + SPP_SIGSEGV 11 + SPP_SIGBUS 10 + SPP_SIGILL 4 + SPP_SIGFPE 8 + SPP_SIGTERM 15 */ + + /* On returning from a continue, the PMON monitor seems to start + echoing back the messages we send prior to sending back the + ACK. The code can cope with this, but to try and avoid the + unnecessary serial traffic, and "spurious" characters displayed + to the user, we cheat and reset the debug protocol. The problems + seems to be caused by a check on the number of arguments, and the + command length, within the monitor causing it to echo the command + as a bad packet. */ + mips_exit_debug (); + mips_enter_debug (); + + /* Translate a MIPS waitstatus. We use constants here rather than WTERMSIG + and so on, because the constants we want here are determined by the + MIPS protocol and have nothing to do with what host we are running on. */ + if ((rstatus & 0377) == 0) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (((rstatus) >> 8) & 0377); + } + else if ((rstatus & 0377) == 0177) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0377); + } + else + { + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = mips_signal_from_protocol (rstatus & 0177); + } + + return 0; +} + +/* We have to map between the register numbers used by gdb and the + register numbers used by the debugging protocol. This function + assumes that we are using tm-mips.h. */ + +#define REGNO_OFFSET 96 + +static int +mips_map_regno (regno) + int regno; +{ + if (regno < 32) + return regno; + if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) + return regno - FP0_REGNUM + 32; + switch (regno) + { + case PC_REGNUM: + return REGNO_OFFSET + 0; + case CAUSE_REGNUM: + return REGNO_OFFSET + 1; + case HI_REGNUM: + return REGNO_OFFSET + 2; + case LO_REGNUM: + return REGNO_OFFSET + 3; + case FCRCS_REGNUM: + return REGNO_OFFSET + 4; + case FCRIR_REGNUM: + return REGNO_OFFSET + 5; + default: + /* FIXME: Is there a way to get the status register? */ + return 0; + } +} + +/* Fetch the remote registers. */ + +static void +mips_fetch_registers (regno) + int regno; +{ + unsigned LONGEST val; + int err; + + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + mips_fetch_registers (regno); + return; + } + + if (regno == FP_REGNUM || regno == ZERO_REGNUM) + /* FP_REGNUM on the mips is a hack which is just supposed to read + zero (see also mips-nat.c). */ + val = 0; + else + { +#if 0 /* Unfortunately the PMON version in the Vr4300 board has been + compiled without the 64bit register access commands. This + means we cannot get hold of the full register width. */ + if (mips_monitor == MON_PMON) + val = mips_request ('t', (unsigned int) mips_map_regno (regno), + (unsigned int) 0, &err, mips_receive_wait, NULL); + else +#endif + val = mips_request ('r', (unsigned int) mips_map_regno (regno), + (unsigned int) 0, &err, mips_receive_wait, NULL); + if (err) + mips_error ("Can't read register %d: %s", regno, + safe_strerror (errno)); + } + + { + char buf[MAX_REGISTER_RAW_SIZE]; + + /* We got the number the register holds, but gdb expects to see a + value in the target byte ordering. */ + store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val); + supply_register (regno, buf); + } +} + +/* Prepare to store registers. The MIPS protocol can store individual + registers, so this function doesn't have to do anything. */ + +static void +mips_prepare_to_store () +{ +} + +/* Store remote register(s). */ + +static void +mips_store_registers (regno) + int regno; +{ + int err; + + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + mips_store_registers (regno); + return; + } + + mips_request ('R', (unsigned int) mips_map_regno (regno), + (unsigned int) read_register (regno), + &err, mips_receive_wait, NULL); + if (err) + mips_error ("Can't write register %d: %s", regno, safe_strerror (errno)); +} + +/* Fetch a word from the target board. */ + +static int +mips_fetch_word (addr) + CORE_ADDR addr; +{ + int val; + int err; + + val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err, + mips_receive_wait, NULL); + if (err) + { + /* Data space failed; try instruction space. */ + val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err, + mips_receive_wait, NULL); + if (err) + mips_error ("Can't read address 0x%x: %s", addr, safe_strerror (errno)); + } + return val; +} + +/* Store a word to the target board. Returns errno code or zero for + success. If OLD_CONTENTS is non-NULL, put the old contents of that + memory location there. */ + +static int +mips_store_word (addr, val, old_contents) + CORE_ADDR addr; + int val; + char *old_contents; +{ + int err; + unsigned int oldcontents; + + oldcontents = mips_request ('D', (unsigned int) addr, (unsigned int) val, + &err, + mips_receive_wait, NULL); + if (err) + { + /* Data space failed; try instruction space. */ + oldcontents = mips_request ('I', (unsigned int) addr, + (unsigned int) val, &err, + mips_receive_wait, NULL); + if (err) + return errno; + } + if (old_contents != NULL) + store_unsigned_integer (old_contents, 4, oldcontents); + return 0; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, + transferring to or from debugger address MYADDR. Write to inferior + if SHOULD_WRITE is nonzero. Returns length of data written or + read; 0 for error. Note that protocol gives us the correct value + for a longword, since it transfers values in ASCII. We want the + byte values, so we have to swap the longword values. */ + +static int +mips_xfer_memory (memaddr, myaddr, len, write, ignore) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *ignore; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr &~ 3; + /* Round ending address up; get number of longwords that makes. */ + register int count = (((memaddr + len) - addr) + 3) / 4; + /* Allocate buffer of that many longwords. */ + register char *buffer = alloca (count * 4); + + int status; + + if (write) + { + /* Fill start and end extra bytes of buffer with existing data. */ + if (addr != memaddr || len < 4) + { + /* Need part of initial word -- fetch it. */ + store_unsigned_integer (&buffer[0], 4, mips_fetch_word (addr)); + } + + if (count > 1) + { + /* Need part of last word -- fetch it. FIXME: we do this even + if we don't need it. */ + store_unsigned_integer (&buffer[(count - 1) * 4], 4, + mips_fetch_word (addr + (count - 1) * 4)); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & 3), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += 4) + { + status = mips_store_word (addr, + extract_unsigned_integer (&buffer[i*4], 4), + NULL); + /* Report each kilobyte (we download 32-bit words at a time) */ + if (i % 256 == 255) + { + printf_unfiltered ("*"); + fflush (stdout); + } + if (status) + { + errno = status; + return 0; + } + /* FIXME: Do we want a QUIT here? */ + } + if (count >= 256) + printf_unfiltered ("\n"); + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += 4) + { + store_unsigned_integer (&buffer[i*4], 4, mips_fetch_word (addr)); + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, buffer + (memaddr & 3), len); + } + return len; +} + +/* Print info on this target. */ + +static void +mips_files_info (ignore) + struct target_ops *ignore; +{ + printf_unfiltered ("Debugging a MIPS board over a serial line.\n"); +} + +/* Kill the process running on the board. This will actually only + work if we are doing remote debugging over the console input. I + think that if IDT/sim had the remote debug interrupt enabled on the + right port, we could interrupt the process with a break signal. */ + +static void +mips_kill () +{ + if (!mips_wait_flag) + return; + + interrupt_count++; + + if (interrupt_count >= 2) + { + interrupt_count = 0; + + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + /* Clean up in such a way that mips_close won't try to talk to the + board (it almost surely won't work since we weren't able to talk to + it). */ + mips_wait_flag = 0; + mips_is_open = 0; + SERIAL_CLOSE (mips_desc); + + printf_unfiltered ("Ending remote MIPS debugging.\n"); + target_mourn_inferior (); + + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); + } + + if (remote_debug > 0) + printf_unfiltered ("Sending break\n"); + + SERIAL_SEND_BREAK (mips_desc); + +#if 0 + if (mips_is_open) + { + char cc; + + /* Send a ^C. */ + cc = '\003'; + SERIAL_WRITE (mips_desc, &cc, 1); + sleep (1); + target_mourn_inferior (); + } +#endif +} + +/* Start running on the target board. */ + +static void +mips_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + CORE_ADDR entry_pt; + + if (args && *args) + { + warning ("\ +Can't pass arguments to remote MIPS board; arguments ignored."); + /* And don't try to use them on the next "run" command. */ + execute_command ("set args", 0); + } + + if (execfile == 0 || exec_bfd == 0) + error ("No executable file specified"); + + entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd); + + init_wait_for_inferior (); + + /* FIXME: Should we set inferior_pid here? */ + + proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Clean up after a process. Actually nothing to do. */ + +static void +mips_mourn_inferior () +{ + if (current_ops != NULL) + unpush_target (current_ops); + generic_mourn_inferior (); +} + +/* We can write a breakpoint and read the shadow contents in one + operation. */ + +/* The IDT board uses an unusual breakpoint value, and sometimes gets + confused when it sees the usual MIPS breakpoint instruction. */ + +#define BREAK_INSN (0x00000a0d) +#define BREAK_INSN_SIZE (4) + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ + +static int +mips_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int status; + + if (monitor_supports_breakpoints) + return common_breakpoint ('B', addr, 0x3, "f"); + + return mips_store_word (addr, BREAK_INSN, contents_cache); +} + +static int +mips_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + if (monitor_supports_breakpoints) + return common_breakpoint ('b', addr, 0, NULL); + + return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE); +} + +#if 0 /* currently not used */ +/* PMON does not currently provide support for the debug mode 'b' + commands to manipulate breakpoints. However, if we wanted to use + the monitor breakpoints (rather than the GDB BREAK_INSN version) + then this code performs the work needed to leave debug mode, + set/clear the breakpoint, and then return to debug mode. */ + +#define PMON_MAX_BP (33) /* 32 SW, 1 HW */ +static CORE_ADDR mips_pmon_bp_info[PMON_MAX_BP]; +/* NOTE: The code relies on this vector being zero-initialised by the system */ + +static int +pmon_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int status; + + if (monitor_supports_breakpoints) + { + char tbuff[12]; /* space for breakpoint command */ + int bpnum; + CORE_ADDR bpaddr; + + /* PMON does not support debug level breakpoint set/remove: */ + if (mips_exit_debug ()) + mips_error ("Failed to exit debug mode"); + + sprintf (tbuff, "b %08x\015", addr); + mips_send_command (tbuff, 0); + + mips_expect ("Bpt "); + + if (!mips_getstring (tbuff, 2)) + return 1; + tbuff[2] = '\0'; /* terminate the string */ + if (sscanf (tbuff, "%d", &bpnum) != 1) + { + fprintf_unfiltered (stderr, "Invalid decimal breakpoint number from target: %s\n", tbuff); + return 1; + } + + mips_expect (" = "); + + /* Lead in the hex number we are expecting: */ + tbuff[0] = '0'; + tbuff[1] = 'x'; + + if (!mips_getstring (&tbuff[2], 8)) + return 1; + tbuff[10] = '\0'; /* terminate the string */ + + if (sscanf (tbuff, "0x%08x", &bpaddr) != 1) + { + fprintf_unfiltered (stderr, "Invalid hex address from target: %s\n", tbuff); + return 1; + } + + if (bpnum >= PMON_MAX_BP) + { + fprintf_unfiltered (stderr, "Error: Returned breakpoint number %d outside acceptable range (0..%d)\n", + bpnum, PMON_MAX_BP - 1); + return 1; + } + + if (bpaddr != addr) + fprintf_unfiltered (stderr, "Warning: Breakpoint addresses do not match: 0x%x != 0x%x\n", addr, bpaddr); + + mips_pmon_bp_info[bpnum] = bpaddr; + + mips_expect ("\015\012"); + mips_expect (mips_monitor_prompt); + + mips_enter_debug (); + + return 0; + } + + return mips_store_word (addr, BREAK_INSN, contents_cache); +} + +static int +pmon_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + if (monitor_supports_breakpoints) + { + int bpnum; + char tbuff[7]; /* enough for delete breakpoint command */ + + for (bpnum = 0; bpnum < PMON_MAX_BP; bpnum++) + if (mips_pmon_bp_info[bpnum] == addr) + break; + + if (bpnum >= PMON_MAX_BP) + { + fprintf_unfiltered (stderr, "pmon_remove_breakpoint: Failed to find breakpoint at address 0x%x\n", addr); + return 1; + } + + if (mips_exit_debug ()) + mips_error ("Failed to exit debug mode"); + + sprintf (tbuff, "db %02d\015", bpnum); + + mips_send_command (tbuff, -1); + /* NOTE: If the breakpoint does not exist then a "Bpt
not + set" message will be returned. */ + + mips_enter_debug (); + + return 0; + } + + return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE); +} +#endif + +/* Compute a don't care mask for the region bounding ADDR and ADDR + LEN - 1. + This is used for memory ref breakpoints. */ + +static unsigned long +calculate_mask (addr, len) + CORE_ADDR addr; + int len; +{ + unsigned long mask; + int i; + + mask = addr ^ (addr + len - 1); + + for (i = 32; i >= 0; i--) + if (mask == 0) + break; + else + mask >>= 1; + + mask = (unsigned long) 0xffffffff >> i; + + return mask; +} + +/* Set a data watchpoint. ADDR and LEN should be obvious. TYPE is either 1 + for a read watchpoint, or 2 for a read/write watchpoint. */ + +int +remote_mips_set_watchpoint (addr, len, type) + CORE_ADDR addr; + int len; + int type; +{ + CORE_ADDR first_addr; + unsigned long mask; + char *flags; + + mask = calculate_mask (addr, len); + + first_addr = addr & ~mask; + + switch (type) + { + case 0: /* write */ + flags = "w"; + break; + case 1: /* read */ + flags = "r"; + break; + case 2: /* read/write */ + flags = "rw"; + break; + default: + abort (); + } + + if (common_breakpoint ('B', first_addr, mask, flags)) + return -1; + + return 0; +} + +int +remote_mips_remove_watchpoint (addr, len, type) + CORE_ADDR addr; + int len; + int type; +{ + CORE_ADDR first_addr; + unsigned long mask; + + mask = calculate_mask (addr, len); + + first_addr = addr & ~mask; + + if (common_breakpoint ('b', first_addr, 0, NULL)) + return -1; + + return 0; +} + +int +remote_mips_stopped_by_watchpoint () +{ + return hit_watchpoint; +} + +/* This routine generates the a breakpoint command of the form: + + 0x0 + + Where is one of: `B' to set, or `b' to clear a breakpoint. is + the address of the breakpoint. is a don't care mask for addresses. + is any combination of `r', `w', or `f' for read/write/or fetch. */ + +static int +common_breakpoint (cmd, addr, mask, flags) + int cmd; + CORE_ADDR addr; + CORE_ADDR mask; + char *flags; +{ + int len; + char buf[DATA_MAXLEN + 1]; + char rcmd; + int rpid, rerrflg, rresponse; + int nfields; + + if (flags) + sprintf (buf, "0x0 %c 0x%x 0x%x %s", cmd, addr, mask, flags); + else + sprintf (buf, "0x0 %c 0x%x", cmd, addr); + + mips_send_packet (buf, 1); + + len = mips_receive_packet (buf, 1, mips_receive_wait); + buf[len] = '\0'; + + nfields = sscanf (buf, "0x%x %c 0x%x 0x%x", &rpid, &rcmd, &rerrflg, &rresponse); + + if (nfields != 4 + || rcmd != cmd) + mips_error ("common_breakpoint: Bad response from remote board: %s", buf); + + if (rerrflg != 0) + { + if (rresponse != EINVAL) + fprintf_unfiltered (stderr, "common_breakpoint (0x%x): Got error: 0x%x\n", + addr, rresponse); + return 1; + } + + return 0; +} + +static void +send_srec (srec, len, addr) + char *srec; + int len; + CORE_ADDR addr; +{ + while (1) + { + int ch; + + SERIAL_WRITE (mips_desc, srec, len); + + ch = mips_readchar (2); + + switch (ch) + { + case SERIAL_TIMEOUT: + error ("Timeout during download."); + break; + case 0x6: /* ACK */ + return; + case 0x15: /* NACK */ + fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %d! Retrying.\n", addr); + continue; + default: + error ("Download got unexpected ack char: 0x%x, retrying.\n", ch); + } + } +} + +/* Download a binary file by converting it to S records. */ + +static void +mips_load_srec (args) + char *args; +{ + bfd *abfd; + asection *s; + char *buffer, srec[1024]; + int i; + int srec_frame = 200; + int reclen; + static int hashmark = 1; + + buffer = alloca (srec_frame * 2 + 256); + + abfd = bfd_openr (args, 0); + if (!abfd) + { + printf_filtered ("Unable to open file %s\n", args); + return; + } + + if (bfd_check_format (abfd, bfd_object) == 0) + { + printf_filtered ("File is not an object file\n"); + return; + } + +/* This actually causes a download in the IDT binary format: */ +#define LOAD_CMD "load -b -s tty0\015" + mips_send_command (LOAD_CMD, 0); + + for (s = abfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + int numbytes; + + printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, + s->vma + s->_raw_size); + gdb_flush (gdb_stdout); + + for (i = 0; i < s->_raw_size; i += numbytes) + { + numbytes = min (srec_frame, s->_raw_size - i); + + bfd_get_section_contents (abfd, s, buffer, i, numbytes); + + reclen = mips_make_srec (srec, '3', s->vma + i, buffer, numbytes); + send_srec (srec, reclen, s->vma + i); + + if (hashmark) + { + putchar_unfiltered ('#'); + gdb_flush (gdb_stdout); + } + + } /* Per-packet (or S-record) loop */ + + putchar_unfiltered ('\n'); + } /* Loadable sections */ + } + if (hashmark) + putchar_unfiltered ('\n'); + + /* Write a type 7 terminator record. no data for a type 7, and there + is no data, so len is 0. */ + + reclen = mips_make_srec (srec, '7', abfd->start_address, NULL, 0); + + send_srec (srec, reclen, abfd->start_address); + + SERIAL_FLUSH_INPUT (mips_desc); +} + +/* + * mips_make_srec -- make an srecord. This writes each line, one at a + * time, each with it's own header and trailer line. + * An srecord looks like this: + * + * byte count-+ address + * start ---+ | | data +- checksum + * | | | | + * S01000006F6B692D746573742E73726563E4 + * S315000448600000000000000000FC00005900000000E9 + * S31A0004000023C1400037DE00F023604000377B009020825000348D + * S30B0004485A0000000000004E + * S70500040000F6 + * + * S
+ * + * Where + * - length + * is the number of bytes following upto the checksum. Note that + * this is not the number of chars following, since it takes two + * chars to represent a byte. + * - type + * is one of: + * 0) header record + * 1) two byte address data record + * 2) three byte address data record + * 3) four byte address data record + * 7) four byte address termination record + * 8) three byte address termination record + * 9) two byte address termination record + * + * - address + * is the start address of the data following, or in the case of + * a termination record, the start address of the image + * - data + * is the data. + * - checksum + * is the sum of all the raw byte data in the record, from the length + * upwards, modulo 256 and subtracted from 255. + * + * This routine returns the length of the S-record. + * + */ + +static int +mips_make_srec (buf, type, memaddr, myaddr, len) + char *buf; + int type; + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + unsigned char checksum; + int i; + + /* Create the header for the srec. addr_size is the number of bytes in the address, + and 1 is the number of bytes in the count. */ + + buf[0] = 'S'; + buf[1] = type; + buf[2] = len + 4 + 1; /* len + 4 byte address + 1 byte checksum */ + /* This assumes S3 style downloads (4byte addresses). There should + probably be a check, or the code changed to make it more + explicit. */ + buf[3] = memaddr >> 24; + buf[4] = memaddr >> 16; + buf[5] = memaddr >> 8; + buf[6] = memaddr; + memcpy (&buf[7], myaddr, len); + + /* Note that the checksum is calculated on the raw data, not the + hexified data. It includes the length, address and the data + portions of the packet. */ + checksum = 0; + buf += 2; /* Point at length byte */ + for (i = 0; i < len + 4 + 1; i++) + checksum += *buf++; + + *buf = ~checksum; + + return len + 8; +} + +/* The following manifest controls whether we enable the simple flow + control support provided by the monitor. If enabled the code will + wait for an affirmative ACK between transmitting packets. */ +#define DOETXACK (1) + +/* The PMON fast-download uses an encoded packet format constructed of + 3byte data packets (encoded as 4 printable ASCII characters), and + escape sequences (preceded by a '/'): + + 'K' clear checksum + 'C' compare checksum (12bit value, not included in checksum calculation) + 'S' define symbol name (for addr) terminated with "," and padded to 4char boundary + 'Z' zero fill multiple of 3bytes + 'B' byte (12bit encoded value, of 8bit data) + 'A' address (36bit encoded value) + 'E' define entry as original address, and exit load + + The packets are processed in 4 character chunks, so the escape + sequences that do not have any data (or variable length data) + should be padded to a 4 character boundary. The decoder will give + an error if the complete message block size is not a multiple of + 4bytes (size of record). + + The encoding of numbers is done in 6bit fields. The 6bit value is + used to index into this string to get the specific character + encoding for the value: */ +static char encoding[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,."; + +/* Convert the number of bits required into an encoded number, 6bits + at a time (range 0..63). Keep a checksum if required (passed + pointer non-NULL). The function returns the number of encoded + characters written into the buffer. */ +static int +pmon_makeb64 (v, p, n, chksum) + unsigned long v; + char *p; + int n; + int *chksum; +{ + int count = (n / 6); + + if ((n % 12) != 0) { + fprintf_unfiltered(stderr,"Fast encoding bitcount must be a multiple of 12bits: %dbit%s\n",n,(n == 1)?"":"s"); + return(0); + } + if (n > 36) { + fprintf_unfiltered(stderr,"Fast encoding cannot process more than 36bits at the moment: %dbits\n",n); + return(0); + } + + /* Deal with the checksum: */ + if (chksum != NULL) { + switch (n) { + case 36: *chksum += ((v >> 24) & 0xFFF); + case 24: *chksum += ((v >> 12) & 0xFFF); + case 12: *chksum += ((v >> 0) & 0xFFF); + } + } + + do { + n -= 6; + *p++ = encoding[(v >> n) & 0x3F]; + } while (n > 0); + + return(count); +} + +/* Shorthand function (that could be in-lined) to output the zero-fill + escape sequence into the data stream. */ +static int +pmon_zeroset (recsize, buff, amount, chksum) + int recsize; + char **buff; + int *amount; + unsigned int *chksum; +{ + int count; + + sprintf(*buff,"/Z"); + count = pmon_makeb64 (*amount, (*buff + 2), 12, chksum); + *buff += (count + 2); + *amount = 0; + return(recsize + count + 2); +} + +static int +pmon_checkset (recsize, buff, value) + int recsize; + char **buff; + int *value; +{ + int count; + + /* Add the checksum (without updating the value): */ + sprintf (*buff, "/C"); + count = pmon_makeb64 (*value, (*buff + 2), 12, NULL); + *buff += (count + 2); + sprintf (*buff, "\015"); + *buff += 2; /* include zero terminator */ + /* Forcing a checksum validation clears the sum: */ + *value = 0; + return(recsize + count + 3); +} + +/* Amount of padding we leave after at the end of the output buffer, + for the checksum and line termination characters: */ +#define CHECKSIZE (4 + 4 + 4 + 2) +/* zero-fill, checksum, transfer end and line termination space. */ + +/* The amount of binary data loaded from the object file in a single + operation: */ +#define BINCHUNK (1024) + +/* Maximum line of data accepted by the monitor: */ +#define MAXRECSIZE (550) +/* NOTE: This constant depends on the monitor being used. This value + is for PMON 5.x on the Cogent Vr4300 board. */ + +static void +pmon_make_fastrec (outbuf, inbuf, inptr, inamount, recsize, csum, zerofill) + char **outbuf; + unsigned char *inbuf; + int *inptr; + int inamount; + int *recsize; + unsigned int *csum; + unsigned int *zerofill; +{ + int count = 0; + char *p = *outbuf; + + /* This is a simple check to ensure that our data will fit within + the maximum allowable record size. Each record output is 4bytes + in length. We must allow space for a pending zero fill command, + the record, and a checksum record. */ + while ((*recsize < (MAXRECSIZE - CHECKSIZE)) && ((inamount - *inptr) > 0)) { + /* Process the binary data: */ + if ((inamount - *inptr) < 3) { + if (*zerofill != 0) + *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); + sprintf (p, "/B"); + count = pmon_makeb64 (inbuf[*inptr], &p[2], 12, csum); + p += (2 + count); + *recsize += (2 + count); + (*inptr)++; + } else { + unsigned int value = ((inbuf[*inptr + 0] << 16) | (inbuf[*inptr + 1] << 8) | inbuf[*inptr + 2]); + /* Simple check for zero data. TODO: A better check would be + to check the last, and then the middle byte for being zero + (if the first byte is not). We could then check for + following runs of zeros, and if above a certain size it is + worth the 4 or 8 character hit of the byte insertions used + to pad to the start of the zeroes. NOTE: This also depends + on the alignment at the end of the zero run. */ + if (value == 0x00000000) { + (*zerofill)++; + if (*zerofill == 0xFFF) /* 12bit counter */ + *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); + }else { + if (*zerofill != 0) + *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); + count = pmon_makeb64 (value, p, 24, csum); + p += count; + *recsize += count; + } + *inptr += 3; + } + } + + *outbuf = p; + return; +} + +#if defined(DOETXACK) +static int +pmon_check_ack() +{ + int c = SERIAL_READCHAR (mips_desc, 2); + if ((c == SERIAL_TIMEOUT) || (c != 0x06)) { + fprintf_unfiltered (gdb_stderr, "Failed to receive valid ACK\n"); + return(-1); /* terminate the download */ + } + return(0); +} +#endif /* DOETXACK */ + +static void +pmon_load_fast (file) + char *file; +{ + bfd *abfd; + asection *s; + unsigned char *binbuf; + char *buffer; + int reclen; + unsigned int csum = 0; + static int hashmark = 1; + int bintotal = 0; + int final; + int finished = 0; + + buffer = (char *)xmalloc(MAXRECSIZE + 1); + binbuf = (unsigned char *)xmalloc(BINCHUNK); + + abfd = bfd_openr(file,0); + if (!abfd) + { + printf_filtered ("Unable to open file %s\n",file); + return; + } + + if (bfd_check_format(abfd,bfd_object) == 0) + { + printf_filtered("File is not an object file\n"); + return; + } + + /* Setup the required download state: */ + mips_send_command ("set dlproto etxack\015", -1); + mips_send_command ("set dlecho off\015", -1); + /* NOTE: We get a "cannot set variable" message if the variable is + already defined to have the argument we give. The code doesn't + care, since it just scans to the next prompt anyway. */ + /* Start the download: */ + mips_send_command (LOAD_CMD, 0); + mips_expect ("Downloading from tty0, ^C to abort\015\012"); + + /* Zero the checksum */ + sprintf(buffer,"/Kxx\015"); + reclen = strlen(buffer); + SERIAL_WRITE (mips_desc, buffer, reclen); + +#if defined(DOETXACK) + finished = pmon_check_ack(); +#endif /* DOETXACK */ + + for (s = abfd->sections; s && !finished; s = s->next) + if (s->flags & SEC_LOAD) /* only deal with loadable sections */ + { + bintotal += s->_raw_size; + final = (s->vma + s->_raw_size); + + printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, + s->vma + s->_raw_size); + gdb_flush (gdb_stdout); + + /* Output the starting address */ + sprintf(buffer,"/A"); + reclen = pmon_makeb64(s->vma,&buffer[2],36,&csum); + buffer[2 + reclen] = '\015'; + buffer[3 + reclen] = '\0'; + reclen += 3; /* for the initial escape code and carriage return */ + SERIAL_WRITE (mips_desc, buffer, reclen); +#if defined(DOETXACK) + finished = pmon_check_ack(); +#endif /* DOETXACK */ + + if (!finished) + { + int binamount; + unsigned int zerofill = 0; + char *bp = buffer; + int i; + + reclen = 0; + + for (i = 0; ((i < s->_raw_size) && !finished); i += binamount) { + int binptr = 0; + + binamount = min (BINCHUNK, s->_raw_size - i); + + bfd_get_section_contents (abfd, s, binbuf, i, binamount); + + /* This keeps a rolling checksum, until we decide to output + the line: */ + for (; ((binamount - binptr) > 0);) { + pmon_make_fastrec (&bp, binbuf, &binptr, binamount, &reclen, &csum, &zerofill); + if (reclen >= (MAXRECSIZE - CHECKSIZE)) { + reclen = pmon_checkset (reclen, &bp, &csum); + SERIAL_WRITE (mips_desc, buffer, reclen); +#if defined(DOETXACK) + finished = pmon_check_ack(); + if (finished) { + zerofill = 0; /* do not transmit pending zerofills */ + break; + } +#endif /* DOETXACK */ + + if (hashmark) { + putchar_unfiltered ('#'); + gdb_flush (gdb_stdout); + } + + bp = buffer; + reclen = 0; /* buffer processed */ + } + } + } + + /* Ensure no out-standing zerofill requests: */ + if (zerofill != 0) + reclen = pmon_zeroset (reclen, &bp, &zerofill, &csum); + + /* and then flush the line: */ + if (reclen > 0) { + reclen = pmon_checkset (reclen, &bp, &csum); + /* Currently pmon_checkset outputs the line terminator by + default, so we write out the buffer so far: */ + SERIAL_WRITE (mips_desc, buffer, reclen); +#if defined(DOETXACK) + finished = pmon_check_ack(); +#endif /* DOETXACK */ + } + } + + if (hashmark) + putchar_unfiltered ('\n'); + } + + /* Terminate the transfer. We know that we have an empty output + buffer at this point. */ + sprintf (buffer, "/E/E\015"); /* include dummy padding characters */ + reclen = strlen (buffer); + SERIAL_WRITE (mips_desc, buffer, reclen); + + if (finished) { /* Ignore the termination message: */ + SERIAL_FLUSH_INPUT (mips_desc); + } else { /* Deal with termination message: */ + char hexnumber[9]; /* includes '\0' space */ + mips_expect ("Entry Address = "); + sprintf(hexnumber,"%x",final); + mips_expect (hexnumber); +#if defined(DOETXACK) + mips_expect ("\015\012\006\015\012total = 0x"); +#else /* normal termination */ + mips_expect ("\015\012\015\012total = 0x"); +#endif /* !DOETXACK */ + sprintf(hexnumber,"%x",bintotal); + mips_expect (hexnumber); + mips_expect (" bytes\015\012"); + } + + return; +} + +/* mips_load -- download a file. */ + +static void +mips_load (file, from_tty) + char *file; + int from_tty; +{ + /* Get the board out of remote debugging mode. */ + if (mips_exit_debug ()) + error ("mips_load: Couldn't get into monitor mode."); + + if (mips_monitor == MON_PMON) + pmon_load_fast (file); + else + mips_load_srec (file); + + mips_initialize (); + +/* Finally, make the PC point at the start address */ + + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_pid = 0; /* No process now */ + +/* This is necessary because many things were based on the PC at the time that + we attached to the monitor, which is no longer valid now that we have loaded + new code (and just changed the PC). Another way to do this might be to call + normal_stop, except that the stack may not be valid, and things would get + horribly confused... */ + + clear_symtab_users (); +} + +/* The target vector. */ + +struct target_ops mips_ops = +{ + "mips", /* to_shortname */ + "Remote MIPS debugging over serial line", /* to_longname */ + "\ +Debug a board using the MIPS remote debugging protocol over a serial line.\n\ +The argument is the device it is connected to or, if it contains a colon,\n\ +HOST:PORT to access a board over a network", /* to_doc */ + mips_open, /* to_open */ + mips_close, /* to_close */ + NULL, /* to_attach */ + mips_detach, /* to_detach */ + mips_resume, /* to_resume */ + mips_wait, /* to_wait */ + mips_fetch_registers, /* to_fetch_registers */ + mips_store_registers, /* to_store_registers */ + mips_prepare_to_store, /* to_prepare_to_store */ + mips_xfer_memory, /* to_xfer_memory */ + mips_files_info, /* to_files_info */ + mips_insert_breakpoint, /* to_insert_breakpoint */ + mips_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + mips_kill, /* to_kill */ + mips_load, /* to_load */ + NULL, /* to_lookup_symbol */ + mips_create_inferior, /* to_create_inferior */ + mips_mourn_inferior, /* to_mourn_inferior */ + NULL, /* to_can_run */ + NULL, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +/* An alternative target vector: */ +struct target_ops pmon_ops = +{ + "pmon", /* to_shortname */ + "Remote MIPS debugging over serial line", /* to_longname */ + "\ +Debug a board using the PMON MIPS remote debugging protocol over a serial\n\ +line. The argument is the device it is connected to or, if it contains a\n\ +colon, HOST:PORT to access a board over a network", /* to_doc */ + pmon_open, /* to_open */ + mips_close, /* to_close */ + NULL, /* to_attach */ + mips_detach, /* to_detach */ + mips_resume, /* to_resume */ + pmon_wait, /* to_wait */ + mips_fetch_registers, /* to_fetch_registers */ + mips_store_registers, /* to_store_registers */ + mips_prepare_to_store, /* to_prepare_to_store */ + mips_xfer_memory, /* to_xfer_memory */ + mips_files_info, /* to_files_info */ + mips_insert_breakpoint, /* to_insert_breakpoint */ + mips_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + mips_kill, /* to_kill */ + mips_load, /* to_load */ + NULL, /* to_lookup_symbol */ + mips_create_inferior, /* to_create_inferior */ + mips_mourn_inferior, /* to_mourn_inferior */ + NULL, /* to_can_run */ + NULL, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_mips () +{ + add_target (&mips_ops); + add_target (&pmon_ops); + + add_show_from_set ( + add_set_cmd ("timeout", no_class, var_zinteger, + (char *) &mips_receive_wait, + "Set timeout in seconds for remote MIPS serial I/O.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("retransmit-timeout", no_class, var_zinteger, + (char *) &mips_retransmit_wait, + "Set retransmit timeout in seconds for remote MIPS serial I/O.\n\ +This is the number of seconds to wait for an acknowledgement to a packet\n\ +before resending the packet.", &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("syn-garbage-limit", no_class, var_zinteger, + (char *) &mips_syn_garbage, +"Set the maximum number of characters to ignore when scanning for a SYN.\n\ +This is the maximum number of characters GDB will ignore when trying to\n\ +synchronize with the remote system. A value of -1 means that there is no limit\n\ +(Note that these characters are printed out even though they are ignored.)", + &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/remote-mm.c b/contrib/gdb/gdb/remote-mm.c new file mode 100644 index 000000000000..101d96438bd3 --- /dev/null +++ b/contrib/gdb/gdb/remote-mm.c @@ -0,0 +1,1627 @@ +/* Remote debugging interface for Am290*0 running MiniMON monitor, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Originally written by Daniel Mann at AMD. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is like remote.c but ecpects MiniMON to be running on the Am29000 + target hardware. + - David Wood (wood@lab.ultra.nyu.edu) at New York University adapted this + file to gdb 3.95. I was unable to get this working on sun3os4 + with termio, only with sgtty. Because we are only attempting to + use this module to debug our kernel, which is already loaded when + gdb is started up, I did not code up the file downloading facilities. + As a result this module has only the stubs to download files. + You should get tagged at compile time if you need to make any + changes/additions. */ + +#include "defs.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include +#include +#include +#include +#include "gdb_string.h" +#include "terminal.h" +#include "minimon.h" +#include "target.h" + +/* Offset of member MEMBER in a struct of type TYPE. */ +#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) + +#define DRAIN_INPUT() (msg_recv_serial((union msg_t*)0)) + +extern int stop_soon_quietly; /* for wait_for_inferior */ + +static void mm_resume(); +static void mm_fetch_registers (); +static int fetch_register (); +static void mm_store_registers (); +static int store_register (); +static int regnum_to_srnum(); +static void mm_close (); +static char* msg_str(); +static char* error_msg_str(); +static int expect_msg(); +static void init_target_mm(); +static int mm_memory_space(); + +#define FREEZE_MODE (read_register(CPS_REGNUM) && 0x400) +#define USE_SHADOW_PC ((processor_type == a29k_freeze_mode) && FREEZE_MODE) + +/* FIXME: Replace with `set remotedebug'. */ +#define LLOG_FILE "minimon.log" +#if defined (LOG_FILE) +FILE *log_file; +#endif + +/* + * Size of message buffers. I couldn't get memory reads to work when + * the byte_count was larger than 512 (it may be a baud rate problem). + */ +#define BUFER_SIZE 512 +/* + * Size of data area in message buffer on the TARGET (remote system). + */ +#define MAXDATA_T (target_config.max_msg_size - \ + offsetof(struct write_r_msg_t,data[0])) +/* + * Size of data area in message buffer on the HOST (gdb). + */ +#define MAXDATA_H (BUFER_SIZE - offsetof(struct write_r_msg_t,data[0])) +/* + * Defined as the minimum size of data areas of the two message buffers + */ +#define MAXDATA (MAXDATA_H < MAXDATA_T ? MAXDATA_H : MAXDATA_T) + +static char out_buf[BUFER_SIZE]; +static char in_buf[BUFER_SIZE]; + +int msg_recv_serial(); +int msg_send_serial(); + +#define MAX_RETRIES 5000 +extern struct target_ops mm_ops; /* Forward declaration */ +struct config_msg_t target_config; /* HIF needs this */ +union msg_t *out_msg_buf = (union msg_t*)out_buf; +union msg_t *in_msg_buf = (union msg_t*)in_buf; + +static int timeout = 5; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + mm_open knows that we don't have a file open when the program + starts. */ +int mm_desc = -1; + +/* stream which is fdopen'd from mm_desc. Only valid when + mm_desc != -1. */ +FILE *mm_stream; + +/* Called when SIGALRM signal sent due to alarm() timeout. */ +#ifndef HAVE_TERMIO + +#ifndef __STDC__ +# ifndef volatile +# define volatile /**/ +# endif +#endif +volatile int n_alarms; + +static void +mm_timer () +{ +#if 0 + if (kiodebug) + printf ("mm_timer called\n"); +#endif + n_alarms++; +} +#endif /* HAVE_TERMIO */ + +/* malloc'd name of the program on the remote system. */ +static char *prog_name = NULL; + + +/* Number of SIGTRAPs we need to simulate. That is, the next + NEED_ARTIFICIAL_TRAP calls to mm_wait should just return + SIGTRAP without actually waiting for anything. */ + +/**************************************************** REMOTE_CREATE_INFERIOR */ +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +static void +mm_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ +#define MAX_TOKENS 25 +#define BUFFER_SIZE 256 + int token_count; + int result; + char *token[MAX_TOKENS]; + char cmd_line[BUFFER_SIZE]; + + if (args && *args) + error ("Can't pass arguments to remote mm process (yet)."); + + if (execfile == 0 /* || exec_bfd == 0 */ ) + error ("No exec file specified"); + + if (!mm_stream) { + printf("Minimon not open yet.\n"); + return; + } + + /* On ultra3 (NYU) we assume the kernel is already running so there is + no file to download. + FIXME: Fixed required here -> load your program, possibly with mm_load(). + */ + printf_filtered ("\n\ +Assuming you are at NYU debuging a kernel, i.e., no need to download.\n\n"); + + /* We will get a task spawn event immediately. */ + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + proceed (-1, TARGET_SIGNAL_DEFAULT, 0); + normal_stop (); +} +/**************************************************** REMOTE_MOURN_INFERIOR */ +static void +mm_mourn() +{ + pop_target (); /* Pop back to no-child state */ + generic_mourn_inferior (); +} + +/********************************************************************** damn_b +*/ +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +#ifndef B19200 +#define B19200 EXTA +#endif +#ifndef B38400 +#define B38400 EXTB +#endif + +static struct {int rate, damn_b;} baudtab[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +static int damn_b (rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) return baudtab[i].damn_b; + return B38400; /* Random */ +} + + +/***************************************************************** REMOTE_OPEN +** Open a connection to remote minimon. + NAME is the filename used for communication, then a space, + then the baud rate. + 'target adapt /dev/ttya 9600 [prognam]' for example. + */ + +static char *dev_name; +int baudrate = 9600; +static void +mm_open (name, from_tty) + char *name; + int from_tty; +{ + TERMINAL sg; + unsigned int prl; + char *p; + + /* Find the first whitespace character, it separates dev_name from + prog_name. */ + for (p = name; + p && *p && !isspace (*p); p++) + ; + if (p == 0 || *p == '\0') +erroid: + error ("Usage : [progname]"); + dev_name = (char*)xmalloc (p - name + 1); + strncpy (dev_name, name, p - name); + dev_name[p - name] = '\0'; + + /* Skip over the whitespace after dev_name */ + for (; isspace (*p); p++) + /*EMPTY*/; + + if (1 != sscanf (p, "%d ", &baudrate)) + goto erroid; + + /* Skip the number and then the spaces */ + for (; isdigit (*p); p++) + /*EMPTY*/; + for (; isspace (*p); p++) + /*EMPTY*/; + + if (prog_name != NULL) + free (prog_name); + prog_name = savestring (p, strlen (p)); + + + if (mm_desc >= 0) + close (mm_desc); + + mm_desc = open (dev_name, O_RDWR); + if (mm_desc < 0) + perror_with_name (dev_name); + ioctl (mm_desc, TIOCGETP, &sg); +#ifdef HAVE_TERMIO + sg.c_cc[VMIN] = 0; /* read with timeout. */ + sg.c_cc[VTIME] = timeout * 10; + sg.c_lflag &= ~(ICANON | ECHO); + sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate); +#else + sg.sg_ispeed = damn_b (baudrate); + sg.sg_ospeed = damn_b (baudrate); + sg.sg_flags |= RAW; + sg.sg_flags |= ANYP; + sg.sg_flags &= ~ECHO; +#endif + + + ioctl (mm_desc, TIOCSETP, &sg); + mm_stream = fdopen (mm_desc, "r+"); + + push_target (&mm_ops); + +#ifndef HAVE_TERMIO +#ifndef NO_SIGINTERRUPT + /* Cause SIGALRM's to make reads fail with EINTR instead of resuming + the read. */ + if (siginterrupt (SIGALRM, 1) != 0) + perror ("mm_open: error in siginterrupt"); +#endif + + /* Set up read timeout timer. */ + if ((void (*)) signal (SIGALRM, mm_timer) == (void (*)) -1) + perror ("mm_open: error in signal"); +#endif + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); +#endif + /* + ** Initialize target configuration structure (global) + */ + DRAIN_INPUT(); + out_msg_buf->config_req_msg.code = CONFIG_REQ; + out_msg_buf->config_req_msg.length = 4*0; + msg_send_serial(out_msg_buf); /* send config request message */ + + expect_msg(CONFIG,in_msg_buf,1); + + a29k_get_processor_type (); + + /* Print out some stuff, letting the user now what's going on */ + printf_filtered("Connected to MiniMon via %s.\n", dev_name); + /* FIXME: can this restriction be removed? */ + printf_filtered("Remote debugging using virtual addresses works only\n"); + printf_filtered("\twhen virtual addresses map 1:1 to physical addresses.\n") +; + if (processor_type != a29k_freeze_mode) { + fprintf_filtered(stderr, + "Freeze-mode debugging not available, and can only be done on an A29050.\n"); + } + + target_config.code = CONFIG; + target_config.length = 0; + target_config.processor_id = in_msg_buf->config_msg.processor_id; + target_config.version = in_msg_buf->config_msg.version; + target_config.I_mem_start = in_msg_buf->config_msg.I_mem_start; + target_config.I_mem_size = in_msg_buf->config_msg.I_mem_size; + target_config.D_mem_start = in_msg_buf->config_msg.D_mem_start; + target_config.D_mem_size = in_msg_buf->config_msg.D_mem_size; + target_config.ROM_start = in_msg_buf->config_msg.ROM_start; + target_config.ROM_size = in_msg_buf->config_msg.ROM_size; + target_config.max_msg_size = in_msg_buf->config_msg.max_msg_size; + target_config.max_bkpts = in_msg_buf->config_msg.max_bkpts; + target_config.coprocessor = in_msg_buf->config_msg.coprocessor; + target_config.reserved = in_msg_buf->config_msg.reserved; + if (from_tty) { + printf("Connected to MiniMON :\n"); + printf(" Debugcore version %d.%d\n", + 0x0f & (target_config.version >> 4), + 0x0f & (target_config.version ) ); + printf(" Configuration version %d.%d\n", + 0x0f & (target_config.version >> 12), + 0x0f & (target_config.version >> 8) ); + printf(" Message system version %d.%d\n", + 0x0f & (target_config.version >> 20), + 0x0f & (target_config.version >> 16) ); + printf(" Communication driver version %d.%d\n", + 0x0f & (target_config.version >> 28), + 0x0f & (target_config.version >> 24) ); + } + + /* Leave the target running... + * The above message stopped the target in the dbg core (MiniMon), + * so restart the target out of MiniMon, + */ + out_msg_buf->go_msg.code = GO; + out_msg_buf->go_msg.length = 0; + msg_send_serial(out_msg_buf); + /* No message to expect after a GO */ +} + +/**************************************************************** REMOTE_CLOSE +** Close the open connection to the minimon debugger. + Use this when you want to detach and do something else + with your gdb. */ +static void +mm_close (quitting) /*FIXME: how is quitting used */ + int quitting; +{ + if (mm_desc < 0) + error ("Can't close remote connection: not debugging remotely."); + + /* We should never get here if there isn't something valid in + mm_desc and mm_stream. + + Due to a bug in Unix, fclose closes not only the stdio stream, + but also the file descriptor. So we don't actually close + mm_desc. */ + DRAIN_INPUT(); + fclose (mm_stream); + /* close (mm_desc); */ + + /* Do not try to close mm_desc again, later in the program. */ + mm_stream = NULL; + mm_desc = -1; + +#if defined (LOG_FILE) + if (ferror (log_file)) + printf ("Error writing log file.\n"); + if (fclose (log_file) != 0) + printf ("Error closing log file.\n"); +#endif + + printf ("Ending remote debugging\n"); +} + +/************************************************************* REMOTE_ATACH */ +/* Attach to a program that is already loaded and running + * Upon exiting the process's execution is stopped. + */ +static void +mm_attach (args, from_tty) + char *args; + int from_tty; +{ + + if (!mm_stream) + error ("MiniMon not opened yet, use the 'target minimon' command.\n"); + + if (from_tty) + printf ("Attaching to remote program %s...\n", prog_name); + + /* Make sure the target is currently running, it is supposed to be. */ + /* FIXME: is it ok to send MiniMon a BREAK if it is already stopped in + * the dbg core. If so, we don't need to send this GO. + */ + out_msg_buf->go_msg.code = GO; + out_msg_buf->go_msg.length = 0; + msg_send_serial(out_msg_buf); + sleep(2); /* At the worst it will stop, receive a message, continue */ + + /* Send the mm a break. */ + out_msg_buf->break_msg.code = BREAK; + out_msg_buf->break_msg.length = 0; + msg_send_serial(out_msg_buf); +} +/********************************************************** REMOTE_DETACH */ +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. Leave remote process running (with no breakpoints set). */ +static void +mm_detach (args,from_tty) + char *args; + int from_tty; +{ + remove_breakpoints(); /* Just in case there were any left in */ + out_msg_buf->go_msg.code = GO; + out_msg_buf->go_msg.length = 0; + msg_send_serial(out_msg_buf); + pop_target(); /* calls mm_close to do the real work */ +} + + +/*************************************************************** REMOTE_RESUME +** Tell the remote machine to resume. */ + +static void +mm_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + if (sig != TARGET_SIGNAL_0) + warning ("Can't send signals to a remote MiniMon system."); + + if (step) { + out_msg_buf->step_msg.code= STEP; + out_msg_buf->step_msg.length = 1*4; + out_msg_buf->step_msg.count = 1; /* step 1 instruction */ + msg_send_serial(out_msg_buf); + } else { + out_msg_buf->go_msg.code= GO; + out_msg_buf->go_msg.length = 0; + msg_send_serial(out_msg_buf); + } +} + +/***************************************************************** REMOTE_WAIT +** Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +static int +mm_wait (status) + struct target_waitstatus *status; +{ + int i, result; + int old_timeout = timeout; + int old_immediate_quit = immediate_quit; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + +/* wait for message to arrive. It should be: + - A HIF service request. + - A HIF exit service request. + - A CHANNEL0_ACK. + - A CHANNEL1 request. + - a debugcore HALT message. + HIF services must be responded too, and while-looping continued. + If the target stops executing, mm_wait() should return. +*/ + timeout = 0; /* Wait indefinetly for a message */ + immediate_quit = 1; /* Helps ability to QUIT */ + while(1) + { + while(msg_recv_serial(in_msg_buf)) { + QUIT; /* Let user quit if they want */ + } + switch (in_msg_buf->halt_msg.code) + { + case HIF_CALL: + i = in_msg_buf->hif_call_rtn_msg.service_number; + result=service_HIF(in_msg_buf); + if(i == 1) /* EXIT */ + goto exit; + if(result) + printf("Warning: failure during HIF service %d\n", i); + break; + case CHANNEL0_ACK: + service_HIF(in_msg_buf); + break; + case CHANNEL1: + i=in_msg_buf->channel1_msg.length; + in_msg_buf->channel1_msg.data[i] = '\0'; + printf("%s", in_msg_buf->channel1_msg.data); + gdb_flush(stdout); + /* Send CHANNEL1_ACK message */ + out_msg_buf->channel1_ack_msg.code = CHANNEL1_ACK; + out_msg_buf->channel1_ack_msg.length = 0; + result = msg_send_serial(out_msg_buf); + break; + case HALT: + goto halted; + default: + goto halted; + } + } +halted: + /* FIXME, these printfs should not be here. This is a source level + debugger, guys! */ + if (in_msg_buf->halt_msg.trap_number== 0) + { printf("Am290*0 received vector number %d (break point)\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + } + else if (in_msg_buf->halt_msg.trap_number== 1) + { + printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_BUS; + } + else if (in_msg_buf->halt_msg.trap_number== 3 + || in_msg_buf->halt_msg.trap_number== 4) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_FPE; + } + else if (in_msg_buf->halt_msg.trap_number== 5) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ILL; + } + else if (in_msg_buf->halt_msg.trap_number >= 6 + && in_msg_buf->halt_msg.trap_number <= 11) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_SEGV; + } + else if (in_msg_buf->halt_msg.trap_number== 12 + || in_msg_buf->halt_msg.trap_number== 13) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ILL; + } + else if (in_msg_buf->halt_msg.trap_number== 14) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ALRM; + } + else if (in_msg_buf->halt_msg.trap_number== 15) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + } + else if (in_msg_buf->halt_msg.trap_number >= 16 + && in_msg_buf->halt_msg.trap_number <= 21) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_INT; + } + else if (in_msg_buf->halt_msg.trap_number== 22) + { printf("Am290*0 received vector number %d\n", + in_msg_buf->halt_msg.trap_number); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ILL; + } /* BREAK message was sent */ + else if (in_msg_buf->halt_msg.trap_number== 75) + { + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + } + else +exit: + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + } + + timeout = old_timeout; /* Restore original timeout value */ + immediate_quit = old_immediate_quit; + return 0; +} + +/******************************************************* REMOTE_FETCH_REGISTERS + * Read a remote register 'regno'. + * If regno==-1 then read all the registers. + */ +static void +mm_fetch_registers (regno) +int regno; +{ + INT32 *data_p; + + if (regno >= 0) { + fetch_register(regno); + return; + } + +/* Gr1/rsp */ + out_msg_buf->read_req_msg.byte_count = 4*1; + out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = 1; + msg_send_serial(out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + supply_register (GR1_REGNUM , data_p); + +#if defined(GR64_REGNUM) /* Read gr64-127 */ +/* Global Registers gr64-gr95 */ + out_msg_buf->read_req_msg.code= READ_REQ; + out_msg_buf->read_req_msg.length = 4*3; + out_msg_buf->read_req_msg.byte_count = 4*32; + out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = 64; + msg_send_serial(out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + + for (regno=GR64_REGNUM; regnoread_req_msg.code= READ_REQ; + out_msg_buf->read_req_msg.length = 4*3; + out_msg_buf->read_req_msg.byte_count = 4 * 32; + out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = 96; + msg_send_serial(out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + + for (regno=GR96_REGNUM; regnoread_req_msg.byte_count = 4 * (128); + out_msg_buf->read_req_msg.memory_space = LOCAL_REG; + out_msg_buf->read_req_msg.address = 0; + msg_send_serial(out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + + for (regno=LR0_REGNUM; regnoread_req_msg.byte_count = 4*15; + out_msg_buf->read_req_msg.memory_space = SPECIAL_REG; + out_msg_buf->read_req_msg.address = 0; + msg_send_serial( out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + + for (regno=0; regno<=14; regno++) { + supply_register (SR_REGNUM(regno), data_p++); + } + if (USE_SHADOW_PC) { /* Let regno_to_srnum() handle the register number */ + fetch_register(NPC_REGNUM); + fetch_register(PC_REGNUM); + fetch_register(PC2_REGNUM); + } + +/* Unprotected Special Registers */ + out_msg_buf->read_req_msg.byte_count = 4*8; + out_msg_buf->read_req_msg.memory_space = SPECIAL_REG; + out_msg_buf->read_req_msg.address = 128; + msg_send_serial( out_msg_buf); + expect_msg(READ_ACK,in_msg_buf,1); + data_p = &(in_msg_buf->read_r_ack_msg.data[0]); + + for (regno=128; regno<=135; regno++) { + supply_register (SR_REGNUM(regno), data_p++); + } + + /* There doesn't seem to be any way to get these. */ + { + int val = -1; + supply_register (FPE_REGNUM, &val); + supply_register (INTE_REGNUM, &val); + supply_register (FPS_REGNUM, &val); + supply_register (EXO_REGNUM, &val); + } +} + + +/****************************************************** REMOTE_STORE_REGISTERS + * Store register regno into the target. + * If regno==-1 then store all the registers. + * Result is 0 for success, -1 for failure. + */ + +static void +mm_store_registers (regno) +int regno; +{ + int result; + + if (regno >= 0) { + store_register(regno); + return; + } + + result = 0; + + out_msg_buf->write_r_msg.code= WRITE_REQ; + +/* Gr1/rsp */ + out_msg_buf->write_r_msg.byte_count = 4*1; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.memory_space = GLOBAL_REG; + out_msg_buf->write_r_msg.address = 1; + out_msg_buf->write_r_msg.data[0] = read_register (GR1_REGNUM); + + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + +#if defined(GR64_REGNUM) +/* Global registers gr64-gr95 */ + out_msg_buf->write_r_msg.byte_count = 4* (32); + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 64; + + for (regno=GR64_REGNUM ; regnowrite_r_msg.data[regno-GR64_REGNUM] = read_register (regno); + } + msg_send_serial(out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } +#endif /* GR64_REGNUM */ + +/* Global registers gr96-gr127 */ + out_msg_buf->write_r_msg.byte_count = 4* (32); + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 96; + for (regno=GR96_REGNUM ; regnowrite_r_msg.data[regno-GR96_REGNUM] = read_register (regno); + } + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + +/* Local Registers */ + out_msg_buf->write_r_msg.memory_space = LOCAL_REG; + out_msg_buf->write_r_msg.byte_count = 4*128; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 0; + + for (regno = LR0_REGNUM ; regno < LR0_REGNUM+128 ; regno++) + { + out_msg_buf->write_r_msg.data[regno-LR0_REGNUM] = read_register (regno); + } + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + +/* Protected Special Registers */ + /* VAB through TMR */ + out_msg_buf->write_r_msg.memory_space = SPECIAL_REG; + out_msg_buf->write_r_msg.byte_count = 4* 10; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 0; + for (regno = 0 ; regno<=9 ; regno++) /* VAB through TMR */ + out_msg_buf->write_r_msg.data[regno] = read_register (SR_REGNUM(regno)); + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + + /* PC0, PC1, PC2 possibly as shadow registers */ + out_msg_buf->write_r_msg.byte_count = 4* 3; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + for (regno=10 ; regno<=12 ; regno++) /* LRU and MMU */ + out_msg_buf->write_r_msg.data[regno-10] = read_register (SR_REGNUM(regno)); + if (USE_SHADOW_PC) + out_msg_buf->write_r_msg.address = 20; /* SPC0 */ + else + out_msg_buf->write_r_msg.address = 10; /* PC0 */ + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + + /* LRU and MMU */ + out_msg_buf->write_r_msg.byte_count = 4* 2; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 13; + for (regno=13 ; regno<=14 ; regno++) /* LRU and MMU */ + out_msg_buf->write_r_msg.data[regno-13] = read_register (SR_REGNUM(regno)); + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + +/* Unprotected Special Registers */ + out_msg_buf->write_r_msg.byte_count = 4*8; + out_msg_buf->write_r_msg.length = 3*4 + out_msg_buf->write_r_msg.byte_count; + out_msg_buf->write_r_msg.address = 128; + for (regno = 128 ; regno<=135 ; regno++) + out_msg_buf->write_r_msg.data[regno-128] = read_register(SR_REGNUM(regno)); + msg_send_serial( out_msg_buf); + if (!expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = -1; + } + + registers_changed (); +} + +/*************************************************** REMOTE_PREPARE_TO_STORE */ +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +mm_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +/******************************************************* REMOTE_XFER_MEMORY */ +static CORE_ADDR +translate_addr(addr) +CORE_ADDR addr; +{ +#if defined(KERNEL_DEBUGGING) + /* Check for a virtual address in the kernel */ + /* Assume physical address of ublock is in paddr_u register */ + /* FIXME: doesn't work for user virtual addresses */ + if (addr >= UVADDR) { + /* PADDR_U register holds the physical address of the ublock */ + CORE_ADDR i = (CORE_ADDR)read_register(PADDR_U_REGNUM); + return(i + addr - (CORE_ADDR)UVADDR); + } else { + return(addr); + } +#else + return(addr); +#endif +} + +/******************************************************* REMOTE_FILES_INFO */ +static void +mm_files_info () +{ + printf ("\tAttached to %s at %d baud and running program %s.\n", + dev_name, baudrate, prog_name); +} + +/************************************************* REMOTE_INSERT_BREAKPOINT */ +static int +mm_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + out_msg_buf->bkpt_set_msg.code = BKPT_SET; + out_msg_buf->bkpt_set_msg.length = 4*4; + out_msg_buf->bkpt_set_msg.memory_space = I_MEM; + out_msg_buf->bkpt_set_msg.bkpt_addr = (ADDR32) addr; + out_msg_buf->bkpt_set_msg.pass_count = 1; + out_msg_buf->bkpt_set_msg.bkpt_type = -1; /* use illop for 29000 */ + msg_send_serial( out_msg_buf); + if (expect_msg(BKPT_SET_ACK,in_msg_buf,1)) { + return 0; /* Success */ + } else { + return 1; /* Failure */ + } +} + +/************************************************* REMOTE_DELETE_BREAKPOINT */ +static int +mm_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + out_msg_buf->bkpt_rm_msg.code = BKPT_RM; + out_msg_buf->bkpt_rm_msg.length = 4*3; + out_msg_buf->bkpt_rm_msg.memory_space = I_MEM; + out_msg_buf->bkpt_rm_msg.bkpt_addr = (ADDR32) addr; + msg_send_serial( out_msg_buf); + if (expect_msg(BKPT_RM_ACK,in_msg_buf,1)) { + return 0; /* Success */ + } else { + return 1; /* Failure */ + } +} + + +/******************************************************* REMOTE_KILL */ +static void +mm_kill(arg,from_tty) +char *arg; +int from_tty; +{ + char buf[4]; + +#if defined(KERNEL_DEBUGGING) + /* We don't ever kill the kernel */ + if (from_tty) { + printf("Kernel not killed, but left in current state.\n"); + printf("Use detach to leave kernel running.\n"); + } +#else + out_msg_buf->break_msg.code = BREAK; + out_msg_buf->bkpt_set_msg.length = 4*0; + expect_msg(HALT,in_msg_buf,from_tty); + if (from_tty) { + printf("Target has been stopped."); + printf("Would you like to do a hardware reset (y/n) [n] "); + fgets(buf,3,stdin); + if (buf[0] == 'y') { + out_msg_buf->reset_msg.code = RESET; + out_msg_buf->bkpt_set_msg.length = 4*0; + expect_msg(RESET_ACK,in_msg_buf,from_tty); + printf("Target has been reset."); + } + } + pop_target(); +#endif +} + + + +/***************************************************************************/ +/* + * Load a program into the target. + */ +static void +mm_load(arg_string,from_tty) +char *arg_string; +int from_tty; +{ + dont_repeat (); + +#if defined(KERNEL_DEBUGGING) + printf("The kernel had better be loaded already! Loading not done.\n"); +#else + if (arg_string == 0) + error ("The load command takes a file name"); + + arg_string = tilde_expand (arg_string); + make_cleanup (free, arg_string); + QUIT; + immediate_quit++; + error("File loading is not yet supported for MiniMon."); + /* FIXME, code to load your file here... */ + /* You may need to do an init_target_mm() */ + /* init_target_mm(?,?,?,?,?,?,?,?); */ + immediate_quit--; + /* symbol_file_add (arg_string, from_tty, text_addr, 0, 0); */ +#endif + +} + +/************************************************ REMOTE_WRITE_INFERIOR_MEMORY +** Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns number of bytes written. */ +static int +mm_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i,nwritten; + + out_msg_buf->write_req_msg.code= WRITE_REQ; + out_msg_buf->write_req_msg.memory_space = mm_memory_space(memaddr); + + nwritten=0; + while (nwritten < len) { + int num_to_write = len - nwritten; + if (num_to_write > MAXDATA) num_to_write = MAXDATA; + for (i=0 ; i < num_to_write ; i++) + out_msg_buf->write_req_msg.data[i] = myaddr[i+nwritten]; + out_msg_buf->write_req_msg.byte_count = num_to_write; + out_msg_buf->write_req_msg.length = 3*4 + num_to_write; + out_msg_buf->write_req_msg.address = memaddr + nwritten; + msg_send_serial(out_msg_buf); + + if (expect_msg(WRITE_ACK,in_msg_buf,1)) { + nwritten += in_msg_buf->write_ack_msg.byte_count; + } else { + break; + } + } + return(nwritten); +} + +/************************************************* REMOTE_READ_INFERIOR_MEMORY +** Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns number of bytes read. */ +static int +mm_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i,nread; + + out_msg_buf->read_req_msg.code= READ_REQ; + out_msg_buf->read_req_msg.memory_space = mm_memory_space(memaddr); + + nread=0; + while (nread < len) { + int num_to_read = (len - nread); + if (num_to_read > MAXDATA) num_to_read = MAXDATA; + out_msg_buf->read_req_msg.byte_count = num_to_read; + out_msg_buf->read_req_msg.length = 3*4 + num_to_read; + out_msg_buf->read_req_msg.address = memaddr + nread; + msg_send_serial(out_msg_buf); + + if (expect_msg(READ_ACK,in_msg_buf,1)) { + for (i=0 ; iread_ack_msg.byte_count ; i++) + myaddr[i+nread] = in_msg_buf->read_ack_msg.data[i]; + nread += in_msg_buf->read_ack_msg.byte_count; + } else { + break; + } + } + return(nread); +} + +/* FIXME! Merge these two. */ +static int +mm_xfer_inferior_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + + memaddr = translate_addr(memaddr); + + if (write) + return mm_write_inferior_memory (memaddr, myaddr, len); + else + return mm_read_inferior_memory (memaddr, myaddr, len); +} + + +/********************************************************** MSG_SEND_SERIAL +** This function is used to send a message over the +** serial line. +** +** If the message is successfully sent, a zero is +** returned. If the message was not sendable, a -1 +** is returned. This function blocks. That is, it +** does not return until the message is completely +** sent, or until an error is encountered. +** +*/ + +int +msg_send_serial(msg_ptr) + union msg_t *msg_ptr; +{ + INT32 message_size; + int byte_count; + int result; + char c; + + /* Send message header */ + byte_count = 0; + message_size = msg_ptr->generic_msg.length + (2 * sizeof(INT32)); + do { + c = *((char *)msg_ptr+byte_count); + result = write(mm_desc, &c, 1); + if (result == 1) { + byte_count = byte_count + 1; + } + } while ((byte_count < message_size) ); + + return(0); +} /* end msg_send_serial() */ + +/********************************************************** MSG_RECV_SERIAL +** This function is used to receive a message over a +** serial line. +** +** If the message is waiting in the buffer, a zero is +** returned and the buffer pointed to by msg_ptr is filled +** in. If no message was available, a -1 is returned. +** If timeout==0, wait indefinetly for a character. +** +*/ + +int +msg_recv_serial(msg_ptr) +union msg_t *msg_ptr; +{ + static INT32 length=0; + static INT32 byte_count=0; + int result; + char c; + if(msg_ptr == 0) /* re-sync request */ + { length=0; + byte_count=0; +#ifdef HAVE_TERMIO + /* The timeout here is the prevailing timeout set with VTIME */ + ->"timeout==0 semantics not supported" + read(mm_desc, in_buf, BUFER_SIZE); +#else + alarm (1); + read(mm_desc, in_buf, BUFER_SIZE); + alarm (0); +#endif + return(0); + } + /* Receive message */ +#ifdef HAVE_TERMIO +/* Timeout==0, help support the mm_wait() routine */ + ->"timeout==0 semantics not supported (and its nice if they are)" + result = read(mm_desc, &c, 1); +#else + alarm(timeout); + result = read(mm_desc, &c, 1); + alarm (0); +#endif + if ( result < 0) { + if (errno == EINTR) { + error ("Timeout reading from remote system."); + } else + perror_with_name ("remote"); + } else if (result == 1) { + *((char *)msg_ptr+byte_count) = c; + byte_count = byte_count + 1; + } + + /* Message header received. Save message length. */ + if (byte_count == (2 * sizeof(INT32))) + length = msg_ptr->generic_msg.length; + + if (byte_count >= (length + (2 * sizeof(INT32)))) { + /* Message received */ + byte_count = 0; + return(0); + } else + return (-1); + +} /* end msg_recv_serial() */ + +/********************************************************************* KBD_RAW +** This function is used to put the keyboard in "raw" +** mode for BSD Unix. The original status is saved +** so that it may be restored later. +*/ +TERMINAL kbd_tbuf; + +int +kbd_raw() { + int result; + TERMINAL tbuf; + + /* Get keyboard termio (to save to restore original modes) */ +#ifdef HAVE_TERMIO + result = ioctl(0, TCGETA, &kbd_tbuf); +#else + result = ioctl(0, TIOCGETP, &kbd_tbuf); +#endif + if (result == -1) + return (errno); + + /* Get keyboard TERMINAL (for modification) */ +#ifdef HAVE_TERMIO + result = ioctl(0, TCGETA, &tbuf); +#else + result = ioctl(0, TIOCGETP, &tbuf); +#endif + if (result == -1) + return (errno); + + /* Set up new parameters */ +#ifdef HAVE_TERMIO + tbuf.c_iflag = tbuf.c_iflag & + ~(INLCR | ICRNL | IUCLC | ISTRIP | IXON | BRKINT); + tbuf.c_lflag = tbuf.c_lflag & ~(ICANON | ISIG | ECHO); + tbuf.c_cc[4] = 0; /* MIN */ + tbuf.c_cc[5] = 0; /* TIME */ +#else + /* FIXME: not sure if this is correct (matches HAVE_TERMIO). */ + tbuf.sg_flags |= RAW; + tbuf.sg_flags |= ANYP; + tbuf.sg_flags &= ~ECHO; +#endif + + /* Set keyboard termio to new mode (RAW) */ +#ifdef HAVE_TERMIO + result = ioctl(0, TCSETAF, &tbuf); +#else + result = ioctl(0, TIOCSETP, &tbuf); +#endif + if (result == -1) + return (errno); + + return (0); +} /* end kbd_raw() */ + + + +/***************************************************************** KBD_RESTORE +** This function is used to put the keyboard back in the +** mode it was in before kbk_raw was called. Note that +** kbk_raw() must have been called at least once before +** kbd_restore() is called. +*/ + +int +kbd_restore() { + int result; + + /* Set keyboard termio to original mode */ +#ifdef HAVE_TERMIO + result = ioctl(0, TCSETAF, &kbd_tbuf); +#else + result = ioctl(0, TIOCGETP, &kbd_tbuf); +#endif + + if (result == -1) + return (errno); + + return(0); +} /* end kbd_cooked() */ + + +/*****************************************************************************/ +/* Fetch a single register indicatated by 'regno'. + * Returns 0/-1 on success/failure. + */ +static int +fetch_register (regno) + int regno; +{ + int result; + out_msg_buf->read_req_msg.code= READ_REQ; + out_msg_buf->read_req_msg.length = 4*3; + out_msg_buf->read_req_msg.byte_count = 4; + + if (regno == GR1_REGNUM) + { out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = 1; + } + else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + { out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = (regno - GR96_REGNUM) + 96; + } +#if defined(GR64_REGNUM) + else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 ) + { out_msg_buf->read_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->read_req_msg.address = (regno - GR64_REGNUM) + 64; + } +#endif /* GR64_REGNUM */ + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + { out_msg_buf->read_req_msg.memory_space = LOCAL_REG; + out_msg_buf->read_req_msg.address = (regno - LR0_REGNUM); + } + else if (regno>=FPE_REGNUM && regno<=EXO_REGNUM) + { int val = -1; + supply_register(160 + (regno - FPE_REGNUM),&val); + return 0; /* Pretend Success */ + } + else + { out_msg_buf->read_req_msg.memory_space = SPECIAL_REG; + out_msg_buf->read_req_msg.address = regnum_to_srnum(regno); + } + + msg_send_serial(out_msg_buf); + + if (expect_msg(READ_ACK,in_msg_buf,1)) { + supply_register (regno, &(in_msg_buf->read_r_ack_msg.data[0])); + result = 0; + } else { + result = -1; + } + return result; +} +/*****************************************************************************/ +/* Store a single register indicated by 'regno'. + * Returns 0/-1 on success/failure. + */ +static int +store_register (regno) + int regno; +{ + int result; + + out_msg_buf->write_req_msg.code= WRITE_REQ; + out_msg_buf->write_req_msg.length = 4*4; + out_msg_buf->write_req_msg.byte_count = 4; + out_msg_buf->write_r_msg.data[0] = read_register (regno); + + if (regno == GR1_REGNUM) + { out_msg_buf->write_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->write_req_msg.address = 1; + /* Setting GR1 changes the numbers of all the locals, so invalidate the + * register cache. Do this *after* calling read_register, because we want + * read_register to return the value that write_register has just stuffed + * into the registers array, not the value of the register fetched from + * the inferior. + */ + registers_changed (); + } +#if defined(GR64_REGNUM) + else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 ) + { out_msg_buf->write_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->write_req_msg.address = (regno - GR64_REGNUM) + 64; + } +#endif /* GR64_REGNUM */ + else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + { out_msg_buf->write_req_msg.memory_space = GLOBAL_REG; + out_msg_buf->write_req_msg.address = (regno - GR96_REGNUM) + 96; + } + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + { out_msg_buf->write_req_msg.memory_space = LOCAL_REG; + out_msg_buf->write_req_msg.address = (regno - LR0_REGNUM); + } + else if (regno>=FPE_REGNUM && regno<=EXO_REGNUM) + { + return 0; /* Pretend Success */ + } + else /* An unprotected or protected special register */ + { out_msg_buf->write_req_msg.memory_space = SPECIAL_REG; + out_msg_buf->write_req_msg.address = regnum_to_srnum(regno); + } + + msg_send_serial(out_msg_buf); + + if (expect_msg(WRITE_ACK,in_msg_buf,1)) { + result = 0; + } else { + result = -1; + } + return result; +} +/****************************************************************************/ +/* + * Convert a gdb special register number to a 29000 special register number. + */ +static int +regnum_to_srnum(regno) +int regno; +{ + switch(regno) { + case VAB_REGNUM: return(0); + case OPS_REGNUM: return(1); + case CPS_REGNUM: return(2); + case CFG_REGNUM: return(3); + case CHA_REGNUM: return(4); + case CHD_REGNUM: return(5); + case CHC_REGNUM: return(6); + case RBP_REGNUM: return(7); + case TMC_REGNUM: return(8); + case TMR_REGNUM: return(9); + case NPC_REGNUM: return(USE_SHADOW_PC ? (20) : (10)); + case PC_REGNUM: return(USE_SHADOW_PC ? (21) : (11)); + case PC2_REGNUM: return(USE_SHADOW_PC ? (22) : (12)); + case MMU_REGNUM: return(13); + case LRU_REGNUM: return(14); + case IPC_REGNUM: return(128); + case IPA_REGNUM: return(129); + case IPB_REGNUM: return(130); + case Q_REGNUM: return(131); + case ALU_REGNUM: return(132); + case BP_REGNUM: return(133); + case FC_REGNUM: return(134); + case CR_REGNUM: return(135); + case FPE_REGNUM: return(160); + case INTE_REGNUM: return(161); + case FPS_REGNUM: return(162); + case EXO_REGNUM:return(164); + default: + return(255); /* Failure ? */ + } +} +/****************************************************************************/ +/* + * Initialize the target debugger (minimon only). + */ +static void +init_target_mm(tstart,tend,dstart,dend,entry,ms_size,rs_size,arg_start) +ADDR32 tstart,tend,dstart,dend,entry; +INT32 ms_size,rs_size; +ADDR32 arg_start; +{ + out_msg_buf->init_msg.code = INIT; + out_msg_buf->init_msg.length= sizeof(struct init_msg_t)-2*sizeof(INT32); + out_msg_buf->init_msg.text_start = tstart; + out_msg_buf->init_msg.text_end = tend; + out_msg_buf->init_msg.data_start = dstart; + out_msg_buf->init_msg.data_end = dend; + out_msg_buf->init_msg.entry_point = entry; + out_msg_buf->init_msg.mem_stack_size = ms_size; + out_msg_buf->init_msg.reg_stack_size = rs_size; + out_msg_buf->init_msg.arg_start = arg_start; + msg_send_serial(out_msg_buf); + expect_msg(INIT_ACK,in_msg_buf,1); +} +/****************************************************************************/ +/* + * Return a pointer to a string representing the given message code. + * Not all messages are represented here, only the ones that we expect + * to be called with. + */ +static char* +msg_str(code) +INT32 code; +{ + static char cbuf[32]; + + switch (code) { + case BKPT_SET_ACK: sprintf(cbuf,"%s (%d)","BKPT_SET_ACK",code); break; + case BKPT_RM_ACK: sprintf(cbuf,"%s (%d)","BKPT_RM_ACK",code); break; + case INIT_ACK: sprintf(cbuf,"%s (%d)","INIT_ACK",code); break; + case READ_ACK: sprintf(cbuf,"%s (%d)","READ_ACK",code); break; + case WRITE_ACK: sprintf(cbuf,"%s (%d)","WRITE_ACK",code); break; + case ERROR: sprintf(cbuf,"%s (%d)","ERROR",code); break; + case HALT: sprintf(cbuf,"%s (%d)","HALT",code); break; + default: sprintf(cbuf,"UNKNOWN (%d)",code); break; + } + return(cbuf); +} +/****************************************************************************/ +/* + * Selected (not all of them) error codes that we might get. + */ +static char* +error_msg_str(code) +INT32 code; +{ + static char cbuf[50]; + + switch (code) { + case EMFAIL: return("EMFAIL: unrecoverable error"); + case EMBADADDR: return("EMBADADDR: Illegal address"); + case EMBADREG: return("EMBADREG: Illegal register "); + case EMACCESS: return("EMACCESS: Could not access memory"); + case EMBADMSG: return("EMBADMSG: Unknown message type"); + case EMMSG2BIG: return("EMMSG2BIG: Message to large"); + case EMNOSEND: return("EMNOSEND: Could not send message"); + case EMNORECV: return("EMNORECV: Could not recv message"); + case EMRESET: return("EMRESET: Could not RESET target"); + case EMCONFIG: return("EMCONFIG: Could not get target CONFIG"); + case EMSTATUS: return("EMSTATUS: Could not get target STATUS"); + case EMREAD: return("EMREAD: Could not READ target memory"); + case EMWRITE: return("EMWRITE: Could not WRITE target memory"); + case EMBKPTSET: return("EMBKPTSET: Could not set breakpoint"); + case EMBKPTRM: return("EMBKPTRM: Could not remove breakpoint"); + case EMBKPTSTAT:return("EMBKPTSTAT: Could not get breakpoint status"); + case EMBKPTNONE:return("EMBKPTNONE: All breakpoints in use"); + case EMBKPTUSED:return("EMBKPTUSED: Breakpoints already in use"); + case EMINIT: return("EMINIT: Could not init target memory"); + case EMGO: return("EMGO: Could not start execution"); + case EMSTEP: return("EMSTEP: Could not single step"); + case EMBREAK: return("EMBREAK: Could not BREAK"); + case EMCOMMERR: return("EMCOMMERR: Communication error"); + default: sprintf(cbuf,"error number %d",code); break; + } /* end switch */ + + return (cbuf); +} +/****************************************************************************/ +/* + * Receive a message and expect it to be of type msgcode. + * Returns 0/1 on failure/success. + */ +static int +expect_msg(msgcode,msg_buf,from_tty) +INT32 msgcode; /* Msg code we expect */ +union msg_t *msg_buf; /* Where to put the message received */ +int from_tty; /* Print message on error if non-zero */ +{ + int retries=0; + while(msg_recv_serial(msg_buf) && (retries++= MAX_RETRIES) { + printf("Expected msg %s, ",msg_str(msgcode)); + printf("no message received!\n"); + return(0); /* Failure */ + } + + if (msg_buf->generic_msg.code != msgcode) { + if (from_tty) { + printf("Expected msg %s, ",msg_str(msgcode)); + printf("got msg %s\n",msg_str(msg_buf->generic_msg.code)); + if (msg_buf->generic_msg.code == ERROR) + printf("%s\n",error_msg_str(msg_buf->error_msg.error_code)); + } + return(0); /* Failure */ + } + return(1); /* Success */ +} +/****************************************************************************/ +/* + * Determine the MiniMon memory space qualifier based on the addr. + * FIXME: Can't distinguis I_ROM/D_ROM. + * FIXME: Doesn't know anything about I_CACHE/D_CACHE. + */ +static int +mm_memory_space(addr) +CORE_ADDR *addr; +{ + ADDR32 tstart = target_config.I_mem_start; + ADDR32 tend = tstart + target_config.I_mem_size; + ADDR32 dstart = target_config.D_mem_start; + ADDR32 dend = tstart + target_config.D_mem_size; + ADDR32 rstart = target_config.ROM_start; + ADDR32 rend = tstart + target_config.ROM_size; + + if (((ADDR32)addr >= tstart) && ((ADDR32)addr < tend)) { + return I_MEM; + } else if (((ADDR32)addr >= dstart) && ((ADDR32)addr < dend)) { + return D_MEM; + } else if (((ADDR32)addr >= rstart) && ((ADDR32)addr < rend)) { + /* FIXME: how do we determine between D_ROM and I_ROM */ + return D_ROM; + } else /* FIXME: what do me do now? */ + return D_MEM; /* Hmmm! */ +} + +/****************************************************************************/ +/* + * Define the target subroutine names + */ +struct target_ops mm_ops = { + "minimon", "Remote AMD/Minimon target", + "Remote debug an AMD 290*0 using the MiniMon dbg core on the target", + mm_open, mm_close, + mm_attach, mm_detach, mm_resume, mm_wait, + mm_fetch_registers, mm_store_registers, + mm_prepare_to_store, + mm_xfer_inferior_memory, + mm_files_info, + mm_insert_breakpoint, mm_remove_breakpoint, /* Breakpoints */ + 0, 0, 0, 0, 0, /* Terminal handling */ + mm_kill, /* FIXME, kill */ + mm_load, + 0, /* lookup_symbol */ + mm_create_inferior, /* create_inferior */ + mm_mourn, /* mourn_inferior FIXME */ + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + 0,0, /* sections, sections_end */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_mm() +{ + add_target (&mm_ops); +} + +#ifdef NO_HIF_SUPPORT +service_HIF(msg) +union msg_t *msg; +{ + return(0); /* Emulate a failure */ +} +#endif diff --git a/contrib/gdb/gdb/remote-nindy.c b/contrib/gdb/gdb/remote-nindy.c new file mode 100644 index 000000000000..a3417f0ad02d --- /dev/null +++ b/contrib/gdb/gdb/remote-nindy.c @@ -0,0 +1,820 @@ +/* Memory-access and commands for remote NINDY process, for GDB. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Contributed by Intel Corporation. Modified from remote.c by Chris Benenati. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* +Except for the data cache routines, this file bears little resemblence +to remote.c. A new (although similar) protocol has been specified, and +portions of the code are entirely dependent on having an i80960 with a +NINDY ROM monitor at the other end of the line. +*/ + +/***************************************************************************** + * + * REMOTE COMMUNICATION PROTOCOL BETWEEN GDB960 AND THE NINDY ROM MONITOR. + * + * + * MODES OF OPERATION + * ----- -- --------- + * + * As far as NINDY is concerned, GDB is always in one of two modes: command + * mode or passthrough mode. + * + * In command mode (the default) pre-defined packets containing requests + * are sent by GDB to NINDY. NINDY never talks except in reponse to a request. + * + * Once the the user program is started, GDB enters passthrough mode, to give + * the user program access to the terminal. GDB remains in this mode until + * NINDY indicates that the program has stopped. + * + * + * PASSTHROUGH MODE + * ----------- ---- + * + * GDB writes all input received from the keyboard directly to NINDY, and writes + * all characters received from NINDY directly to the monitor. + * + * Keyboard input is neither buffered nor echoed to the monitor. + * + * GDB remains in passthrough mode until NINDY sends a single ^P character, + * to indicate that the user process has stopped. + * + * Note: + * GDB assumes NINDY performs a 'flushreg' when the user program stops. + * + * + * COMMAND MODE + * ------- ---- + * + * All info (except for message ack and nak) is transferred between gdb + * and the remote processor in messages of the following format: + * + * # + * + * where + * # is a literal character + * + * ASCII information; all numeric information is in the + * form of hex digits ('0'-'9' and lowercase 'a'-'f'). + * + * + * is a pair of ASCII hex digits representing an 8-bit + * checksum formed by adding together each of the + * characters in . + * + * The receiver of a message always sends a single character to the sender + * to indicate that the checksum was good ('+') or bad ('-'); the sender + * re-transmits the entire message over until a '+' is received. + * + * In response to a command NINDY always sends back either data or + * a result code of the form "Xnn", where "nn" are hex digits and "X00" + * means no errors. (Exceptions: the "s" and "c" commands don't respond.) + * + * SEE THE HEADER OF THE FILE "gdb.c" IN THE NINDY MONITOR SOURCE CODE FOR A + * FULL DESCRIPTION OF LEGAL COMMANDS. + * + * SEE THE FILE "stop.h" IN THE NINDY MONITOR SOURCE CODE FOR A LIST + * OF STOP CODES. + * + ***************************************************************************/ + +#include "defs.h" +#include +#include +#include + +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "floatformat.h" + +#include "wait.h" +#include +#include +#include "serial.h" +#include "nindy-share/env.h" +#include "nindy-share/stop.h" + +#include "dcache.h" +#include "remote-utils.h" + +static DCACHE *nindy_dcache; + +extern int unlink(); +extern char *getenv(); +extern char *mktemp(); + +extern void generic_mourn_inferior (); + +extern struct target_ops nindy_ops; +extern GDB_FILE *instream; + +extern char ninStopWhy (); +extern int ninMemGet (); +extern int ninMemPut (); + +int nindy_initial_brk; /* nonzero if want to send an initial BREAK to nindy */ +int nindy_old_protocol; /* nonzero if want to use old protocol */ +char *nindy_ttyname; /* name of tty to talk to nindy on, or null */ + +#define DLE '\020' /* Character NINDY sends to indicate user program has + * halted. */ +#define TRUE 1 +#define FALSE 0 + +/* From nindy-share/nindy.c. */ +extern serial_t nindy_serial; + +static int have_regs = 0; /* 1 iff regs read since i960 last halted */ +static int regs_changed = 0; /* 1 iff regs were modified since last read */ + +extern char *exists(); + +static void +nindy_fetch_registers PARAMS ((int)); + +static void +nindy_store_registers PARAMS ((int)); + +static char *savename; + +static void +nindy_close (quitting) + int quitting; +{ + if (nindy_serial != NULL) + SERIAL_CLOSE (nindy_serial); + nindy_serial = NULL; + + if (savename) + free (savename); + savename = 0; +} + +/* Open a connection to a remote debugger. + FIXME, there should be "set" commands for the options that are + now specified with gdb command-line options (old_protocol, + and initial_brk). */ +void +nindy_open (name, from_tty) + char *name; /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */ + int from_tty; +{ + char baudrate[1024]; + + if (!name) + error_no_arg ("serial port device name"); + + target_preopen (from_tty); + + nindy_close (0); + + have_regs = regs_changed = 0; + nindy_dcache = dcache_init(ninMemGet, ninMemPut); + + /* Allow user to interrupt the following -- we could hang if there's + no NINDY at the other end of the remote tty. */ + immediate_quit++; + /* If baud_rate is -1, then ninConnect will not recognize the baud rate + and will deal with the situation in a (more or less) reasonable + fashion. */ + sprintf(baudrate, "%d", baud_rate); + ninConnect(name, baudrate, + nindy_initial_brk, !from_tty, nindy_old_protocol); + immediate_quit--; + + if (nindy_serial == NULL) + { + perror_with_name (name); + } + + savename = savestring (name, strlen (name)); + push_target (&nindy_ops); + target_fetch_registers(-1); +} + +/* User-initiated quit of nindy operations. */ + +static void +nindy_detach (name, from_tty) + char *name; + int from_tty; +{ + if (name) + error ("Too many arguments"); + pop_target (); +} + +static void +nindy_files_info () +{ + /* FIXME: this lies about the baud rate if we autobauded. */ + printf_unfiltered("\tAttached to %s at %d bits per second%s%s.\n", savename, + baud_rate, + nindy_old_protocol? " in old protocol": "", + nindy_initial_brk? " with initial break": ""); +} + +/* Return the number of characters in the buffer before + the first DLE character. */ + +static +int +non_dle( buf, n ) + char *buf; /* Character buffer; NOT '\0'-terminated */ + int n; /* Number of characters in buffer */ +{ + int i; + + for ( i = 0; i < n; i++ ){ + if ( buf[i] == DLE ){ + break; + } + } + return i; +} + +/* Tell the remote machine to resume. */ + +void +nindy_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + if (siggnal != TARGET_SIGNAL_0 && siggnal != stop_signal) + warning ("Can't send signals to remote NINDY targets."); + + dcache_flush(nindy_dcache); + if ( regs_changed ) + { + nindy_store_registers (-1); + regs_changed = 0; + } + have_regs = 0; + ninGo( step ); +} + +/* FIXME, we can probably use the normal terminal_inferior stuff here. + We have to do terminal_inferior and then set up the passthrough + settings initially. Thereafter, terminal_ours and terminal_inferior + will automatically swap the settings around for us. */ + +struct clean_up_tty_args { + serial_ttystate state; + serial_t serial; +}; +static struct clean_up_tty_args tty_args; + +static void +clean_up_tty (ptrarg) + PTR ptrarg; +{ + struct clean_up_tty_args *args = (struct clean_up_tty_args *) ptrarg; + SERIAL_SET_TTY_STATE (args->serial, args->state); + free (args->state); + warning ("\n\nYou may need to reset the 80960 and/or reload your program.\n"); +} + +/* Recover from ^Z or ^C while remote process is running */ +static void (*old_ctrlc)(); +#ifdef SIGTSTP +static void (*old_ctrlz)(); +#endif + +static void +clean_up_int() +{ + SERIAL_SET_TTY_STATE (tty_args.serial, tty_args.state); + free (tty_args.state); + + signal(SIGINT, old_ctrlc); +#ifdef SIGTSTP + signal(SIGTSTP, old_ctrlz); +#endif + error("\n\nYou may need to reset the 80960 and/or reload your program.\n"); +} + +/* Wait until the remote machine stops. While waiting, operate in passthrough + * mode; i.e., pass everything NINDY sends to gdb_stdout, and everything from + * stdin to NINDY. + * + * Return to caller, storing status in 'status' just as `wait' would. + */ + +static int +nindy_wait( pid, status ) + int pid; + struct target_waitstatus *status; +{ + fd_set fds; + int c; + char buf[2]; + int i, n; + unsigned char stop_exit; + unsigned char stop_code; + struct cleanup *old_cleanups; + long ip_value, fp_value, sp_value; /* Reg values from stop */ + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */ + + /* Save current tty attributes, and restore them when done. */ + tty_args.serial = SERIAL_FDOPEN (0); + tty_args.state = SERIAL_GET_TTY_STATE (tty_args.serial); + old_ctrlc = signal( SIGINT, clean_up_int ); +#ifdef SIGTSTP + old_ctrlz = signal( SIGTSTP, clean_up_int ); +#endif + + old_cleanups = make_cleanup (clean_up_tty, &tty_args); + + /* Pass input from keyboard to NINDY as it arrives. NINDY will interpret + and perform echo. */ + /* This used to set CBREAK and clear ECHO and CRMOD. I hope this is close + enough. */ + SERIAL_RAW (tty_args.serial); + + while (1) + { + /* Input on remote */ + c = SERIAL_READCHAR (nindy_serial, -1); + if (c == SERIAL_ERROR) + { + error ("Cannot read from serial line"); + } + else if (c == 0x1b) /* ESC */ + { + c = SERIAL_READCHAR (nindy_serial, -1); + c &= ~0x40; + } + else if (c != 0x10) /* DLE */ + /* Write out any characters preceding DLE */ + { + buf[0] = (char)c; + write (1, buf, 1); + } + else + { + stop_exit = ninStopWhy(&stop_code, + &ip_value, &fp_value, &sp_value); + if (!stop_exit && (stop_code == STOP_SRQ)) + { + immediate_quit++; + ninSrq(); + immediate_quit--; + } + else + { + /* Get out of loop */ + supply_register (IP_REGNUM, + (char *)&ip_value); + supply_register (FP_REGNUM, + (char *)&fp_value); + supply_register (SP_REGNUM, + (char *)&sp_value); + break; + } + } + } + + SERIAL_SET_TTY_STATE (tty_args.serial, tty_args.state); + free (tty_args.state); + discard_cleanups (old_cleanups); + + if (stop_exit) + { + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = stop_code; + } + else + { + /* nindy has some special stop code need to be handled */ + if (stop_code == STOP_GDB_BPT) + stop_code = TRACE_STEP; + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = i960_fault_to_signal (stop_code); + } + return inferior_pid; +} + +/* Read the remote registers into the block REGS. */ + +/* This is the block that ninRegsGet and ninRegsPut handles. */ +struct nindy_regs { + char local_regs[16 * 4]; + char global_regs[16 * 4]; + char pcw_acw[2 * 4]; + char ip[4]; + char tcw[4]; + char fp_as_double[4 * 8]; +}; + +static void +nindy_fetch_registers(regno) + int regno; +{ + struct nindy_regs nindy_regs; + int regnum, inv; + double dub; + + immediate_quit++; + ninRegsGet( (char *) &nindy_regs ); + immediate_quit--; + + memcpy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4); + memcpy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4); + memcpy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4); + memcpy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4); + memcpy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4); + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) { + dub = unpack_double (builtin_type_double, + &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], + &inv); + /* dub now in host byte order */ + floatformat_from_double (&floatformat_i960_ext, &dub, + ®isters[REGISTER_BYTE (regnum)]); + } + + registers_fetched (); +} + +static void +nindy_prepare_to_store() +{ + /* Fetch all regs if they aren't already here. */ + read_register_bytes (0, NULL, REGISTER_BYTES); +} + +static void +nindy_store_registers(regno) + int regno; +{ + struct nindy_regs nindy_regs; + int regnum; + double dub; + + memcpy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4); + memcpy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4); + memcpy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4); + memcpy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4); + memcpy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4); + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) + { + floatformat_to_double (&floatformat_i960_ext, + ®isters[REGISTER_BYTE (regnum)], &dub); + store_floating (&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], + REGISTER_VIRTUAL_SIZE (regnum), + dub); + } + + immediate_quit++; + ninRegsPut( (char *) &nindy_regs ); + immediate_quit--; +} + +/* Read a word from remote address ADDR and return it. + * This goes through the data cache. + */ +int +nindy_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (nindy_dcache, addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +void +nindy_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (nindy_dcache, addr, word); +} + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. Returns the length copied. + + This is stolen almost directly from infptrace.c's child_xfer_memory, + which also deals with a word-oriented memory interface. Sometime, + FIXME, rewrite this to not use the word-oriented routines. */ + +int +nindy_xfer_inferior_memory(memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int)sizeof (int)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = nindy_fetch_word (addr); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = nindy_fetch_word (addr + (count - 1) * sizeof (int)); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + nindy_store_word (addr, buffer[i]); + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = nindy_fetch_word (addr); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + } + return len; +} + +static void +nindy_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + int pid; + + if (args && *args) + error ("Can't pass arguments to remote NINDY process"); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + + pid = 42; + + /* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + inferior_pid = pid; /* Needed for wait_for_inferior below */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* insert_step_breakpoint (); FIXME, do we need this? */ + /* Let 'er rip... */ + proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +static void +reset_command(args, from_tty) + char *args; + int from_tty; +{ + if (nindy_serial == NULL) + { + error( "No target system to reset -- use 'target nindy' command."); + } + if ( query("Really reset the target system?",0,0) ) + { + SERIAL_SEND_BREAK (nindy_serial); + tty_flush (nindy_serial); + } +} + +void +nindy_kill (args, from_tty) + char *args; + int from_tty; +{ + return; /* Ignore attempts to kill target system */ +} + +/* Clean up when a program exits. + + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +void +nindy_mourn_inferior () +{ + remove_breakpoints (); + unpush_target (&nindy_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +/* Pass the args the way catch_errors wants them. */ +static int +nindy_open_stub (arg) + char *arg; +{ + nindy_open (arg, 1); + return 1; +} + +static void +nindy_load( filename, from_tty ) + char *filename; + int from_tty; +{ + asection *s; + /* Can't do unix style forking on a VMS system, so we'll use bfd to do + all the work for us + */ + + bfd *file = bfd_openr(filename,0); + if (!file) + { + perror_with_name(filename); + return; + } + + if (!bfd_check_format(file, bfd_object)) + { + error("can't prove it's an object file\n"); + return; + } + + for ( s = file->sections; s; s=s->next) + { + if (s->flags & SEC_LOAD) + { + char *buffer = xmalloc(s->_raw_size); + bfd_get_section_contents(file, s, buffer, 0, s->_raw_size); + printf("Loading section %s, size %x vma %x\n", + s->name, + s->_raw_size, + s->vma); + ninMemPut(s->vma, buffer, s->_raw_size); + free(buffer); + } + } + bfd_close(file); +} + +static int +load_stub (arg) + char *arg; +{ + target_load (arg, 1); + return 1; +} + +/* This routine is run as a hook, just before the main command loop is + entered. If gdb is configured for the i960, but has not had its + nindy target specified yet, this will loop prompting the user to do so. + + Unlike the loop provided by Intel, we actually let the user get out + of this with a RETURN. This is useful when e.g. simply examining + an i960 object file on the host system. */ + +void +nindy_before_main_loop () +{ + char ttyname[100]; + char *p, *p2; + + while (target_stack->target_ops != &nindy_ops) /* What is this crap??? */ + { /* remote tty not specified yet */ + if ( instream == stdin ){ + printf_unfiltered("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: "); + gdb_flush( gdb_stdout ); + } + fgets( ttyname, sizeof(ttyname)-1, stdin ); + + /* Strip leading and trailing whitespace */ + for ( p = ttyname; isspace(*p); p++ ){ + ; + } + if ( *p == '\0' ){ + return; /* User just hit spaces or return, wants out */ + } + for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){ + ; + } + *p2= '\0'; + if ( STREQ("quit",p) ){ + exit(1); + } + + if (catch_errors (nindy_open_stub, p, "", RETURN_MASK_ALL)) + { + /* Now that we have a tty open for talking to the remote machine, + download the executable file if one was specified. */ + if (exec_bfd) + { + catch_errors (load_stub, bfd_get_filename (exec_bfd), "", + RETURN_MASK_ALL); + } + } + } +} + +/* Define the target subroutine names */ + +struct target_ops nindy_ops = { + "nindy", "Remote serial target in i960 NINDY-specific protocol", + "Use a remote i960 system running NINDY connected by a serial line.\n\ +Specify the name of the device the serial line is connected to.\n\ +The speed (baud rate), whether to use the old NINDY protocol,\n\ +and whether to send a break on startup, are controlled by options\n\ +specified when you started GDB.", + nindy_open, nindy_close, + 0, + nindy_detach, + nindy_resume, + nindy_wait, + nindy_fetch_registers, nindy_store_registers, + nindy_prepare_to_store, + nindy_xfer_inferior_memory, nindy_files_info, + memory_insert_breakpoint, + memory_remove_breakpoint, + 0, 0, 0, 0, 0, /* Terminal crud */ + nindy_kill, + nindy_load, + 0, /* lookup_symbol */ + nindy_create_inferior, + nindy_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_nindy () +{ + add_target (&nindy_ops); + add_com ("reset", class_obscure, reset_command, + "Send a 'break' to the remote target system.\n\ +Only useful if the target has been equipped with a circuit\n\ +to perform a hard reset when a break is detected."); +} diff --git a/contrib/gdb/gdb/remote-nrom.c b/contrib/gdb/gdb/remote-nrom.c new file mode 100644 index 000000000000..d67791b67bb5 --- /dev/null +++ b/contrib/gdb/gdb/remote-nrom.c @@ -0,0 +1,332 @@ +/* Remote debugging with the XLNT Designs, Inc (XDI) NetROM. + Copyright 1990, 1991, 1992, 1995 Free Software Foundation, Inc. + Contributed by: + Roger Moyers + XLNT Designs, Inc. + 15050 Avenue of Science, Suite 106 + San Diego, CA 92128 + (619)487-9320 + roger@xlnt.com + Adapted from work done at Cygnus Support in remote-nindy.c, + later merged in by Stan Shebs at Cygnus. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "serial.h" +#include "target.h" + +/* Default ports used to talk with the NetROM. */ + +#define DEFAULT_NETROM_LOAD_PORT 1236 +#define DEFAULT_NETROM_CONTROL_PORT 1237 + +static void nrom_close PARAMS ((int quitting)); + +/* New commands. */ + +static void nrom_passthru PARAMS ((char *, int)); + +/* We talk to the NetROM over these sockets. */ + +static serial_t load_desc = NULL; +static serial_t ctrl_desc = NULL; + +static int load_port = DEFAULT_NETROM_LOAD_PORT; +static int control_port = DEFAULT_NETROM_CONTROL_PORT; + +static char nrom_hostname[100]; + +/* Forward data declaration. */ + +extern struct target_ops nrom_ops; + +/* Scan input from the remote system, until STRING is found. Print chars that + don't match. */ + +static int +expect (string) + char *string; +{ + char *p = string; + int c; + + immediate_quit = 1; + + while (1) + { + c = SERIAL_READCHAR (ctrl_desc, 5); + + if (c == *p++) + { + if (*p == '\0') + { + immediate_quit = 0; + + return 0; + } + } + else + { + fputc_unfiltered (c, gdb_stdout); + p = string; + if (c == *p) + p++; + } + } +} + +static void +nrom_kill () +{ + nrom_close (0); +} + +static serial_t +open_socket (name, port) + char *name; + int port; +{ + char sockname[100]; + serial_t desc; + + sprintf (sockname, "%s:%d", name, port); + desc = SERIAL_OPEN (sockname); + if (!desc) + perror_with_name (sockname); + + return desc; +} + +static void +load_cleanup () +{ + SERIAL_CLOSE (load_desc); + load_desc = NULL; +} + +/* Download a file specified in ARGS to the netROM. */ + +static void +nrom_load (args, fromtty) + char *args; + int fromtty; +{ + int fd, rd_amt, fsize; + bfd *pbfd; + asection *section; + char *downloadstring = "download 0\n"; + struct cleanup *old_chain; + + /* Tell the netrom to get ready to download. */ + if (SERIAL_WRITE (ctrl_desc, downloadstring, strlen (downloadstring))) + error ("nrom_load: control_send() of `%s' failed", downloadstring); + + expect ("Waiting for a connection...\n"); + + load_desc = open_socket (nrom_hostname, load_port); + + old_chain = make_cleanup (load_cleanup, 0); + + pbfd = bfd_openr (args, 0); + + if (pbfd) + { + make_cleanup (bfd_close, pbfd); + + if (!bfd_check_format (pbfd, bfd_object)) + error ("\"%s\": not in executable format: %s", + args, bfd_errmsg (bfd_get_error ())); + + for (section = pbfd->sections; section; section = section->next) + { + if (bfd_get_section_flags (pbfd, section) & SEC_ALLOC) + { + bfd_vma section_address; + unsigned long section_size; + const char *section_name; + + section_name = bfd_get_section_name (pbfd, section); + section_address = bfd_get_section_vma (pbfd, section); + section_size = bfd_section_size (pbfd, section); + + if (bfd_get_section_flags (pbfd, section) & SEC_LOAD) + { + file_ptr fptr; + + printf_filtered ("[Loading section %s at %x (%d bytes)]\n", + section_name, section_address, + section_size); + + fptr = 0; + + while (section_size > 0) + { + char buffer[1024]; + int count; + + count = min (section_size, 1024); + + bfd_get_section_contents (pbfd, section, buffer, fptr, + count); + + SERIAL_WRITE (load_desc, buffer, count); + section_address += count; + fptr += count; + section_size -= count; + } + } + else /* BSS and such */ + { + printf_filtered ("[section %s: not loading]\n", + section_name); + } + } + } + } + else + error ("\"%s\": Could not open", args); + + do_cleanups (old_chain); +} + +/* Open a connection to the remote NetROM devices. */ + +static void +nrom_open (name, from_tty) + char *name; + int from_tty; +{ + int errn; + + if (!name || strchr (name, '/') || strchr (name, ':')) + error ( +"To open a NetROM connection, you must specify the hostname\n\ +or IP address of the NetROM device you wish to use."); + + strcpy (nrom_hostname, name); + + target_preopen (from_tty); + + unpush_target (&nrom_ops); + + ctrl_desc = open_socket (nrom_hostname, control_port); + + push_target (&nrom_ops); + + if (from_tty) + printf_filtered ("Connected to NetROM device \"%s\"\n", nrom_hostname); +} + +/* Close out all files and local state before this target loses control. */ + +static void +nrom_close (quitting) + int quitting; +{ + if (load_desc) + SERIAL_CLOSE (load_desc); + if (ctrl_desc) + SERIAL_CLOSE (ctrl_desc); +} + +/* Pass arguments directly to the NetROM. */ + +static void +nrom_passthru (args, fromtty) + char *args; + int fromtty; +{ + char buf[1024]; + + sprintf (buf, "%s\n", args); + if (SERIAL_WRITE (ctrl_desc, buf, strlen (buf))) + error ("nrom_reset: control_send() of `%s'failed", args); +} + +static void +nrom_mourn() +{ + unpush_target (&nrom_ops); + generic_mourn_inferior (); +} + +/* Define the target vector. */ + +struct target_ops nrom_ops = { + "nrom", /* to_shortname */ + "Remote XDI `NetROM' target", /* to_longname */ + "Remote debug using a NetROM over Ethernet", /* to_doc */ + nrom_open, /* to_open */ + nrom_close, /* to_close */ + NULL, /* to_attach */ + NULL, /* to_detach */ + NULL, /* to_resume */ + NULL, /* to_wait */ + NULL, /* to_fetch_registers */ + NULL, /* to_store_registers */ + NULL, /* to_prepare_to_store */ + NULL, /* to_xfer_memory */ + NULL, /* to_files_info */ + NULL, /* to_insert_breakpoint */ + NULL, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + nrom_kill, /* to_kill */ + nrom_load, /* to_load */ + NULL, /* to_lookup_symbol */ + NULL, /* to_create_inferior */ + nrom_mourn, /* to_mourn_inferior */ + NULL, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + download_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 0, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_nrom () +{ + add_target (&nrom_ops); + + add_show_from_set ( + add_set_cmd ("nrom_load_port", no_class, var_zinteger, (char *)&load_port, + "Set the port to use for NetROM downloads\n", &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("nrom_control_port", no_class, var_zinteger, (char *)&control_port, + "Set the port to use for NetROM debugger services\n", &setlist), + &showlist); + + add_cmd ("nrom", no_class, nrom_passthru, + "Pass arguments as command to NetROM", + &cmdlist); +} diff --git a/contrib/gdb/gdb/remote-os9k.c b/contrib/gdb/gdb/remote-os9k.c new file mode 100644 index 000000000000..fda527283cb4 --- /dev/null +++ b/contrib/gdb/gdb/remote-os9k.c @@ -0,0 +1,1230 @@ +/* Remote debugging interface for boot monitors, for GDB. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file was derived from remote-eb.c, which did a similar job, but for + an AMD-29K running EBMON. That file was in turn derived from remote.c + as mentioned in the following comment (left in for comic relief): + + "This is like remote.c but is for a different situation-- + having a PC running os9000 hook up with a unix machine with + a serial line, and running ctty com2 on the PC. os9000 has a debug + monitor called ROMBUG running. Not to mention that the PC + has PC/NFS, so it can access the same executables that gdb can, + over the net in real time." + + In reality, this module talks to a debug monitor called 'ROMBUG', which + We communicate with ROMBUG via a direct serial line, the network version + of ROMBUG is not available yet. +*/ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "wait.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include "gdb_string.h" +#include +#include "command.h" +#include "serial.h" +#include "monitor.h" +#include "remote-utils.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" + +struct monitor_ops *current_monitor; +struct cmd_list_element *showlist; +extern struct target_ops rombug_ops; /* Forward declaration */ +extern struct monitor_ops rombug_cmds; /* Forward declaration */ +extern struct cmd_list_element *setlist; +extern struct cmd_list_element *unsetlist; +extern int attach_flag; + +static void rombug_close(); +static void rombug_fetch_register(); +static void rombug_fetch_registers(); +static void rombug_store_register(); +#if 0 +static int sr_get_debug(); /* flag set by "set remotedebug" */ +#endif +static int hashmark; /* flag set by "set hash" */ +static int rombug_is_open = 0; + +/* FIXME: Replace with sr_get_debug (). */ +#define LOG_FILE "monitor.log" +FILE *log_file; +static int monitor_log = 0; +static int tty_xon = 0; +static int tty_xoff = 0; + +static int timeout = 10; +static int is_trace_mode = 0; +/* Descriptor for I/O to remote machine. Initialize it to NULL*/ +static serial_t monitor_desc = NULL; + +static CORE_ADDR bufaddr = 0; +static int buflen = 0; +static char readbuf[16]; + +/* Send data to monitor. Works just like printf. */ +static void +#ifdef ANSI_PROTOTYPES +printf_monitor(char *pattern, ...) +#else +printf_monitor(va_alist) + va_dcl +#endif +{ + va_list args; + char buf[200]; + int i; + +#ifdef ANSI_PROTOTYPES + va_start (args, pattern); +#else + char *pattern; + va_start(args); + pattern = va_arg(args, char *); +#endif + + vsprintf(buf, pattern, args); + va_end(args); + + if (SERIAL_WRITE(monitor_desc, buf, strlen(buf))) + fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno)); +} + +/* Read a character from the remote system, doing all the fancy timeout stuff*/ +static int +readchar(timeout) + int timeout; +{ + int c; + + c = SERIAL_READCHAR(monitor_desc, timeout); + + if (sr_get_debug()) + putchar(c & 0x7f); + + if (monitor_log && isascii(c)) + putc(c & 0x7f, log_file); + + if (c >= 0) + return c & 0x7f; + + if (c == SERIAL_TIMEOUT) + { + if (timeout == 0) + return c; /* Polls shouldn't generate timeout errors */ + + error("Timeout reading from remote system."); + } + + perror_with_name("remote-monitor"); +} + +/* Scan input from the remote system, until STRING is found. If DISCARD is + non-zero, then discard non-matching input, else print it out. + Let the user break out immediately. */ +static void +expect(string, discard) + char *string; + int discard; +{ + char *p = string; + int c; + + if (sr_get_debug()) + printf ("Expecting \"%s\"\n", string); + + immediate_quit = 1; + while (1) + { + c = readchar(timeout); + if (!isascii (c)) + continue; + if (c == *p++) + { + if (*p == '\0') + { + immediate_quit = 0; + if (sr_get_debug()) + printf ("\nMatched\n"); + return; + } + } + else + { + if (!discard) + { + fwrite(string, 1, (p - 1) - string, stdout); + putchar((char)c); + fflush(stdout); + } + p = string; + } + } +} + +/* Keep discarding input until we see the ROMBUG prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: rombug_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a rombug_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt(discard) + int discard; +{ + if (monitor_log) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush(log_file); + + if (is_trace_mode) { + expect("trace", discard); + } else { + expect (PROMPT, discard); + } +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit(ignore_space) + int ignore_space; +{ + int ch; + while (1) + { + ch = readchar(timeout); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt(1); + error("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from monitor and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Get N 32-bit words from remote, each preceded by a space, + and put them in registers starting at REGNO. */ +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + int i; + unsigned char b; + + for (i = 0; i < n; i++) + { + int j; + + val = 0; + for (j = 0; j < 4; j++) + { + get_hex_byte (&b); + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + val = (val << 8) + b; + else + val = val + (b << (j*8)); + } + supply_register (regno++, (char *) &val); + } +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +static void +rombug_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error("Can't pass arguments to remote ROMBUG process"); + + if (execfile == 0 || exec_bfd == 0) + error("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + + if (monitor_log) + fputs ("\nIn Create_inferior()", log_file); + + +/* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + init_wait_for_inferior (); + proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static char dev_name[100]; + +static void +rombug_open(args, from_tty) + char *args; + int from_tty; +{ + if (args == NULL) + error ("Use `target RomBug DEVICE-NAME' to use a serial port, or \n\ +`target RomBug HOST-NAME:PORT-NUMBER' to use a network connection."); + + target_preopen(from_tty); + + if (rombug_is_open) + unpush_target(&rombug_ops); + + strcpy(dev_name, args); + monitor_desc = SERIAL_OPEN(dev_name); + if (monitor_desc == NULL) + perror_with_name(dev_name); + + /* if baud rate is set by 'set remotebaud' */ + if (SERIAL_SETBAUDRATE (monitor_desc, sr_get_baud_rate())) + { + SERIAL_CLOSE (monitor_desc); + perror_with_name ("RomBug"); + } + SERIAL_RAW(monitor_desc); + if (tty_xon || tty_xoff) + { + struct hardware_ttystate { struct termios t;} *tty_s; + + tty_s =(struct hardware_ttystate *)SERIAL_GET_TTY_STATE(monitor_desc); + if (tty_xon) tty_s->t.c_iflag |= IXON; + if (tty_xoff) tty_s->t.c_iflag |= IXOFF; + SERIAL_SET_TTY_STATE(monitor_desc, (serial_ttystate) tty_s); + } + + rombug_is_open = 1; + + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); + + push_monitor (&rombug_cmds); + printf_monitor("\r"); /* CR wakes up monitor */ + expect_prompt(1); + push_target (&rombug_ops); + attach_flag = 1; + + if (from_tty) + printf("Remote %s connected to %s\n", target_shortname, + dev_name); + + rombug_fetch_registers(); + + printf_monitor ("ov e \r"); + expect_prompt(1); + bufaddr = 0; + buflen = 0; +} + +/* + * Close out all files and local state before this target loses control. + */ + +static void +rombug_close (quitting) + int quitting; +{ + if (rombug_is_open) { + SERIAL_CLOSE(monitor_desc); + monitor_desc = NULL; + rombug_is_open = 0; + } + + if (log_file) { + if (ferror(log_file)) + fprintf(stderr, "Error writing log file.\n"); + if (fclose(log_file) != 0) + fprintf(stderr, "Error closing log file.\n"); + log_file = 0; + } +} + +int +rombug_link(mod_name, text_reloc) + char *mod_name; + CORE_ADDR *text_reloc; +{ + int i, j; + unsigned long val; + unsigned char b; + + printf_monitor("l %s \r", mod_name); + expect_prompt(1); + printf_monitor(".r \r"); + expect(REG_DELIM, 1); + for (i=0; i <= 7; i++) + { + val = 0; + for (j = 0; j < 4; j++) + { + get_hex_byte(&b); + val = (val << 8) + b; + } + } + expect_prompt(1); + *text_reloc = val; + return 1; +} + +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +static void +rombug_detach (from_tty) + int from_tty; +{ + if (attach_flag) { + printf_monitor (GO_CMD); + attach_flag = 0; + } + pop_target(); /* calls rombug_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* + * Tell the remote machine to resume. + */ +static void +rombug_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + if (monitor_log) + fprintf (log_file, "\nIn Resume (step=%d, sig=%d)\n", step, sig); + + if (step) + { + is_trace_mode = 1; + printf_monitor (STEP_CMD); + /* wait for the echo. ** + expect (STEP_CMD, 1); + */ + } + else + { + printf_monitor (GO_CMD); + /* swallow the echo. ** + expect (GO_CMD, 1); + */ + } + bufaddr = 0; + buflen= 0; +} + +/* + * Wait until the remote machine stops, then return, + * storing status in status just as `wait' would. + */ + +static int +rombug_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int old_timeout = timeout; + struct section_offsets *offs; + CORE_ADDR addr, pc; + struct obj_section *obj_sec; + + if (monitor_log) + fputs ("\nIn wait ()", log_file); + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + timeout = -1; /* Don't time out -- user program is running. */ + expect ("eax:", 0); /* output any message before register display */ + expect_prompt(1); /* Wait for prompt, outputting extraneous text */ + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + timeout = old_timeout; + rombug_fetch_registers(); + bufaddr = 0; + buflen = 0; + pc = read_register(PC_REGNUM); + addr = read_register(DATABASE_REG); + obj_sec = find_pc_section (pc); + if (obj_sec != NULL) + { + if (obj_sec->objfile != symfile_objfile) + new_symfile_objfile(obj_sec->objfile, 1, 0); + offs = ((struct section_offsets *) + alloca (sizeof (struct section_offsets) + + (symfile_objfile->num_sections * sizeof (offs->offsets)))); + memcpy (offs, symfile_objfile->section_offsets, + (sizeof (struct section_offsets) + + (symfile_objfile->num_sections * sizeof (offs->offsets)))); + ANOFFSET (offs, SECT_OFF_DATA) = addr; + ANOFFSET (offs, SECT_OFF_BSS) = addr; + + objfile_relocate(symfile_objfile, offs); + } + + return 0; +} + +/* Return the name of register number regno in the form input and output by + monitor. Currently, register_names just happens to contain exactly what + monitor wants. Lets take advantage of that just as long as possible! */ + +static char * +get_reg_name (regno) + int regno; +{ + static char buf[50]; + char *p; + char *b; + + b = buf; + + if (regno < 0) + return (""); +/* + for (p = reg_names[regno]; *p; p++) + *b++ = toupper(*p); + *b = '\000'; +*/ + p = (char *)reg_names[regno]; + return p; +/* + return buf; +*/ +} + +/* read the remote registers into the block regs. */ + +static void +rombug_fetch_registers () +{ + int regno, j, i; + long val; + unsigned char b; + + printf_monitor (GET_REG); + expect("eax:", 1); + expect("\n", 1); + get_hex_regs(1, 0); + get_hex_regs(1, 3); + get_hex_regs(1, 1); + get_hex_regs(1, 2); + get_hex_regs(1, 6); + get_hex_regs(1, 7); + get_hex_regs(1, 5); + get_hex_regs(1, 4); + for (regno = 8; regno <= 15; regno++) + { + expect(REG_DELIM, 1); + if (regno >= 8 && regno <= 13) + { + val = 0; + for (j = 0; j < 2; j++) + { + get_hex_byte (&b); + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + val = (val << 8) + b; + else + val = val + (b << (j*8)); + } + + if (regno == 8) i = 10; + if (regno >= 9 && regno <= 12) i = regno + 3; + if (regno == 13) i = 11; + supply_register (i, (char *) &val); + } + else if (regno == 14) + { + get_hex_regs(1, PC_REGNUM); + } + else if (regno == 15) + { + get_hex_regs(1, 9); + } + else + { + val = 0; + supply_register(regno, (char *) &val); + } + } + is_trace_mode = 0; + expect_prompt (1); +} + +/* Fetch register REGNO, or all registers if REGNO is -1. + Returns errno value. */ +static void +rombug_fetch_register (regno) + int regno; +{ + int val, j; + unsigned char b; + + if (monitor_log) { + fprintf (log_file, "\nIn Fetch Register (reg=%s)\n", get_reg_name (regno)); + fflush (log_file); + } + + if (regno < 0) + { + rombug_fetch_registers (); + } + else + { + char *name = get_reg_name (regno); + printf_monitor (GET_REG); + if (regno >= 10 && regno <= 15) + { + expect ("\n", 1); + expect ("\n", 1); + expect (name, 1); + expect (REG_DELIM, 1); + val = 0; + for (j = 0; j < 2; j++) + { + get_hex_byte (&b); + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + val = (val << 8) + b; + else + val = val + (b << (j*8)); + } + supply_register (regno, (char *) &val); + } + else if (regno == 8 || regno == 9) + { + expect ("\n", 1); + expect ("\n", 1); + expect ("\n", 1); + expect (name, 1); + expect (REG_DELIM, 1); + get_hex_regs (1, regno); + } + else + { + expect (name, 1); + expect (REG_DELIM, 1); + expect("\n", 1); + get_hex_regs(1, 0); + get_hex_regs(1, 3); + get_hex_regs(1, 1); + get_hex_regs(1, 2); + get_hex_regs(1, 6); + get_hex_regs(1, 7); + get_hex_regs(1, 5); + get_hex_regs(1, 4); + } + expect_prompt (1); + } + return; +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +rombug_store_registers () +{ + int regno; + + for (regno = 0; regno <= PC_REGNUM; regno++) + rombug_store_register(regno); + + registers_changed (); +} + +/* Store register REGNO, or all if REGNO == 0. + return errno value. */ +static void +rombug_store_register (regno) + int regno; +{ +char *name; + + if (monitor_log) + fprintf (log_file, "\nIn Store_register (regno=%d)\n", regno); + + if (regno == -1) + rombug_store_registers (); + else + { + if (sr_get_debug()) + printf ("Setting register %s to 0x%x\n", get_reg_name (regno), read_register (regno)); + + name = get_reg_name(regno); + if (name == 0) return; + printf_monitor (SET_REG, name, read_register (regno)); + + is_trace_mode = 0; + expect_prompt (1); + } +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +rombug_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static void +rombug_files_info () +{ + printf ("\tAttached to %s at %d baud.\n", + dev_name, sr_get_baud_rate()); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns length moved. */ +static int +rombug_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int i; + char buf[10]; + + if (monitor_log) + fprintf (log_file, "\nIn Write_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len); + + printf_monitor (MEM_SET_CMD, memaddr); + for (i = 0; i < len; i++) + { + expect (CMD_DELIM, 1); + printf_monitor ("%x \r", myaddr[i]); + if (sr_get_debug()) + printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]); + } + expect (CMD_DELIM, 1); + if (CMD_END) + printf_monitor (CMD_END); + is_trace_mode = 0; + expect_prompt (1); + + bufaddr = 0; + buflen = 0; + return len; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns length moved. */ +static int +rombug_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i, j; + + /* Number of bytes read so far. */ + int count; + + /* Starting address of this pass. */ + unsigned long startaddr; + + /* Number of bytes to read in this pass. */ + int len_this_pass; + + if (monitor_log) + fprintf (log_file, "\nIn Read_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len); + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + rombug_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len To memaddr and gets 0. */ + /* However, something like + rombug_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + if (((memaddr - 1) + len) < memaddr) { + errno = EIO; + return 0; + } + if (bufaddr <= memaddr && (memaddr+len) <= (bufaddr+buflen)) + { + memcpy(myaddr, &readbuf[memaddr-bufaddr], len); + return len; + } + + startaddr = memaddr; + count = 0; + while (count < len) + { + len_this_pass = 16; + if ((startaddr % 16) != 0) + len_this_pass -= startaddr % 16; + if (len_this_pass > (len - count)) + len_this_pass = (len - count); + if (sr_get_debug()) + printf ("\nDisplay %d bytes at %x\n", len_this_pass, startaddr); + + printf_monitor (MEM_DIS_CMD, startaddr, 8); + expect ("- ", 1); + for (i = 0; i < 16; i++) + { + get_hex_byte (&readbuf[i]); + } + bufaddr = startaddr; + buflen = 16; + memcpy(&myaddr[count], readbuf, len_this_pass); + count += len_this_pass; + startaddr += len_this_pass; + expect(CMD_DELIM, 1); + } + if (CMD_END) + printf_monitor (CMD_END); + is_trace_mode = 0; + expect_prompt (1); + + return len; +} + +/* FIXME-someday! merge these two. */ +static int +rombug_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (write) + return rombug_write_inferior_memory (memaddr, myaddr, len); + else + return rombug_read_inferior_memory (memaddr, myaddr, len); +} + +static void +rombug_kill (args, from_tty) + char *args; + int from_tty; +{ + return; /* ignore attempts to kill target system */ +} + +/* Clean up when a program exits. + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +static void +rombug_mourn_inferior () +{ + remove_breakpoints (); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +#define MAX_MONITOR_BREAKPOINTS 16 + +extern int memory_breakpoint_size; +static CORE_ADDR breakaddr[MAX_MONITOR_BREAKPOINTS] = {0}; + +static int +rombug_insert_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + if (monitor_log) + fprintf (log_file, "\nIn Insert_breakpoint (addr=%x)\n", addr); + + for (i = 0; i <= MAX_MONITOR_BREAKPOINTS; i++) + if (breakaddr[i] == 0) + { + breakaddr[i] = addr; + if (sr_get_debug()) + printf ("Breakpoint at %x\n", addr); + rombug_read_inferior_memory(addr, shadow, memory_breakpoint_size); + printf_monitor(SET_BREAK_CMD, addr); + is_trace_mode = 0; + expect_prompt(1); + return 0; + } + + fprintf(stderr, "Too many breakpoints (> 16) for monitor\n"); + return 1; +} + +/* + * _remove_breakpoint -- Tell the monitor to remove a breakpoint + */ +static int +rombug_remove_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + if (monitor_log) + fprintf (log_file, "\nIn Remove_breakpoint (addr=%x)\n", addr); + + for (i = 0; i < MAX_MONITOR_BREAKPOINTS; i++) + if (breakaddr[i] == addr) + { + breakaddr[i] = 0; + printf_monitor(CLR_BREAK_CMD, addr); + is_trace_mode = 0; + expect_prompt(1); + return 0; + } + + fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr); + return 1; +} + +/* Load a file. This is usually an srecord, which is ascii. No + protocol, just sent line by line. */ + +#define DOWNLOAD_LINE_SIZE 100 +static void +rombug_load (arg) + char *arg; +{ +/* this part comment out for os9* */ +#if 0 + FILE *download; + char buf[DOWNLOAD_LINE_SIZE]; + int i, bytes_read; + + if (sr_get_debug()) + printf ("Loading %s to monitor\n", arg); + + download = fopen (arg, "r"); + if (download == NULL) + { + error (sprintf (buf, "%s Does not exist", arg)); + return; + } + + printf_monitor (LOAD_CMD); +/* expect ("Waiting for S-records from host... ", 1); */ + + while (!feof (download)) + { + bytes_read = fread (buf, sizeof (char), DOWNLOAD_LINE_SIZE, download); + if (hashmark) + { + putchar ('.'); + fflush (stdout); + } + + if (SERIAL_WRITE(monitor_desc, buf, bytes_read)) { + fprintf(stderr, "SERIAL_WRITE failed: (while downloading) %s\n", safe_strerror(errno)); + break; + } + i = 0; + while (i++ <=200000) {} ; /* Ugly HACK, probably needs flow control */ + if (bytes_read < DOWNLOAD_LINE_SIZE) + { + if (!feof (download)) + error ("Only read %d bytes\n", bytes_read); + break; + } + } + + if (hashmark) + { + putchar ('\n'); + } + if (!feof (download)) + error ("Never got EOF while downloading"); + fclose (download); +#endif 0 +} + +/* Put a command string, in args, out to MONITOR. + Output from MONITOR is placed on the users terminal until the prompt + is seen. */ + +static void +rombug_command (args, fromtty) + char *args; + int fromtty; +{ + if (monitor_desc == NULL) + error("monitor target not open."); + + if (monitor_log) + fprintf (log_file, "\nIn command (args=%s)\n", args); + + if (!args) + error("Missing command."); + + printf_monitor("%s\r", args); + expect_prompt(0); +} + +#if 0 +/* Connect the user directly to MONITOR. This command acts just like the + 'cu' or 'tip' command. Use ~. or ~^D to break out. */ + +static struct ttystate ttystate; + +static void +cleanup_tty() +{ printf("\r\n[Exiting connect mode]\r\n"); + /*SERIAL_RESTORE(0, &ttystate);*/ +} + +static void +connect_command (args, fromtty) + char *args; + int fromtty; +{ + fd_set readfds; + int numfds; + int c; + char cur_esc = 0; + + dont_repeat(); + + if (monitor_desc == NULL) + error("monitor target not open."); + + if (args) + fprintf("This command takes no args. They have been ignored.\n"); + + printf("[Entering connect mode. Use ~. or ~^D to escape]\n"); + + serial_raw(0, &ttystate); + + make_cleanup(cleanup_tty, 0); + + FD_ZERO(&readfds); + + while (1) + { + do + { + FD_SET(0, &readfds); + FD_SET(monitor_desc, &readfds); + numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0); + } + while (numfds == 0); + + if (numfds < 0) + perror_with_name("select"); + + if (FD_ISSET(0, &readfds)) + { /* tty input, send to monitor */ + c = getchar(); + if (c < 0) + perror_with_name("connect"); + + printf_monitor("%c", c); + 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 (FD_ISSET(monitor_desc, &readfds)) + { + while (1) + { + c = readchar(0); + if (c < 0) + break; + putchar(c); + } + fflush(stdout); + } + } +} +#endif + +/* + * Define the monitor command strings. Since these are passed directly + * through to a printf style function, we need can include formatting + * strings. We also need a CR or LF on the end. + */ +struct monitor_ops rombug_cmds = { + "g \r", /* execute or usually GO command */ + "g \r", /* continue command */ + "t \r", /* single step */ + "b %x\r", /* set a breakpoint */ + "k %x\r", /* clear a breakpoint */ + "c %x\r", /* set memory to a value */ + "d %x %d\r", /* display memory */ + "$%08X", /* prompt memory commands use */ + ".%s %x\r", /* set a register */ + ":", /* delimiter between registers */ + ". \r", /* read a register */ + "mf \r", /* download command */ + "RomBug: ", /* monitor command prompt */ + ": ", /* end-of-command delimitor */ + ".\r" /* optional command terminator */ +}; + +struct target_ops rombug_ops = { + "rombug", + "Microware's ROMBUG debug monitor", + "Use a remote computer running the ROMBUG debug monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + rombug_open, + rombug_close, + 0, + rombug_detach, + rombug_resume, + rombug_wait, + rombug_fetch_register, + rombug_store_register, + rombug_prepare_to_store, + rombug_xfer_inferior_memory, + rombug_files_info, + rombug_insert_breakpoint, + rombug_remove_breakpoint, /* Breakpoints */ + 0, + 0, + 0, + 0, + 0, /* Terminal handling */ + rombug_kill, + rombug_load, /* load */ + rombug_link, /* lookup_symbol */ + rombug_create_inferior, + rombug_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_stop */ + process_stratum, + 0, /* next */ + 1, + 1, + 1, + 1, + 1, /* has execution */ + 0, + 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_os9k () +{ + add_target (&rombug_ops); + + add_show_from_set ( + add_set_cmd ("hash", no_class, var_boolean, (char *)&hashmark, + "Set display of activity while downloading a file.\nWhen enabled, a period \'.\' is displayed.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("timeout", no_class, var_zinteger, + (char *) &timeout, + "Set timeout in seconds for remote MIPS serial I/O.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("remotelog", no_class, var_zinteger, + (char *) &monitor_log, + "Set monitor activity log on(=1) or off(=0).", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("remotexon", no_class, var_zinteger, + (char *) &tty_xon, + "Set remote tty line XON control", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("remotexoff", no_class, var_zinteger, + (char *) &tty_xoff, + "Set remote tty line XOFF control", + &setlist), + &showlist); + + add_com ("rombug ", class_obscure, rombug_command, + "Send a command to the debug monitor."); +#if 0 + add_com ("connect", class_obscure, connect_command, + "Connect the terminal directly up to a serial based command monitor.\nUse ~. or ~^D to break out."); +#endif +} diff --git a/contrib/gdb/gdb/remote-pa.c b/contrib/gdb/gdb/remote-pa.c new file mode 100644 index 000000000000..1121e15effaa --- /dev/null +++ b/contrib/gdb/gdb/remote-pa.c @@ -0,0 +1,1540 @@ +/* Remote target communications for serial-line targets in custom GDB protocol + Copyright 1988, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* 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 "defs.h" +#include "gdb_string.h" +#include +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "wait.h" +#include "terminal.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "remote-utils.h" +#include "dcache.h" + +#ifdef USG +#include +#endif + +#include +#include "serial.h" + +/* Prototypes for local functions */ + +static int +remote_write_bytes PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +static int +remote_read_bytes PARAMS ((CORE_ADDR memaddr, char *myaddr, int len)); + +static void +remote_files_info PARAMS ((struct target_ops *ignore)); + +static int +remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len, + int should_write, struct target_ops *target)); + +static void +remote_prepare_to_store PARAMS ((void)); + +static void +remote_fetch_registers PARAMS ((int regno)); + +static void +remote_resume PARAMS ((int pid, int step, enum target_signal siggnal)); + +static int +remote_start_remote PARAMS ((char *dummy)); + +static void +remote_open PARAMS ((char *name, int from_tty)); + +static void +remote_close PARAMS ((int quitting)); + +static void +remote_store_registers PARAMS ((int regno)); + +static void +getpkt PARAMS ((char *buf, int forever)); + +static void +putpkt PARAMS ((char *buf)); + +static void +remote_send PARAMS ((char *buf)); + +static int +readchar PARAMS ((int timeout)); + +static int +remote_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static int +tohex PARAMS ((int nib)); + +static int +fromhex PARAMS ((int a)); + +static void +remote_detach PARAMS ((char *args, int from_tty)); + +static void +remote_interrupt PARAMS ((int signo)); + +static void +remote_interrupt_twice PARAMS ((int signo)); + +static void +interrupt_query PARAMS ((void)); + +static void +hppro_load PARAMS ((char *name, int from_tty)); + +extern struct target_ops remote_ops; /* Forward decl */ + +/* This was 5 seconds, which is a long time to sit and wait. + Unless this is going though some terminal server or multiplexer or + other form of hairy serial connection, I would think 2 seconds would + be plenty. */ +static int remote_timeout = 2; + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that + remote_open knows that we don't have a file open when the program + starts. */ +extern serial_t remote_desc; + +/* Having this larger than 400 causes us to be incompatible with m68k-stub.c + and i386-stub.c. Normally, no one would notice because it only matters + for writing large chunks of memory (e.g. in downloads). Also, this needs + to be more than 400 if required to hold the registers (see below, where + we round it up based on REGISTER_BYTES). */ +#define PBUFSIZ 400 + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES ((PBUFSIZ-32)/2) + +/* Round up PBUFSIZ to hold all the registers, at least. */ +/* The blank line after the #if seems to be required to work around a + bug in HP's PA compiler. */ +#if REGISTER_BYTES > MAXBUFBYTES + +#undef PBUFSIZ +#define PBUFSIZ (REGISTER_BYTES * 2 + 32) +#endif + +/* Should we try the 'P' request? If this is set to one when the stub + doesn't support 'P', the only consequence is some unnecessary traffic. */ +static int stub_supports_P = 1; + +/* sets the download protocol, choices are srec, generic, boot */ +char *loadtype; +static char *loadtype_str; +static void set_loadtype_command +PARAMS ((char *, int, struct cmd_list_element *)); + +static void +hppro_load (file, from_tty) + char *file; + int from_tty; +{ + puts ("Loading... HA!"); +} + + +/* Clean up connection to a remote debugger. */ + +/* ARGSUSED */ +static void +remote_close (quitting) + int quitting; +{ + if (remote_desc) + SERIAL_CLOSE (remote_desc); + remote_desc = NULL; +} + +/* Query the remote side for the text, data and bss offsets. */ + +static void +get_offsets () +{ + unsigned char buf[PBUFSIZ]; + int nvals; + CORE_ADDR text_addr, data_addr, bss_addr; + struct section_offsets *offs; + + putpkt ("qOffsets"); + + getpkt (buf, 0); + + if (buf[0] == '\000') + return; /* Return silently. Stub doesn't support this + command. */ + if (buf[0] == 'E') + { + warning ("Remote failure reply: %s", buf); + return; + } + + nvals = sscanf (buf, "Text=%lx;Data=%lx;Bss=%lx", &text_addr, &data_addr, + &bss_addr); + if (nvals != 3) + error ("Malformed response to offset query, %s", buf); + + if (symfile_objfile == NULL) + return; + + offs = (struct section_offsets *) alloca (sizeof (struct section_offsets) + + symfile_objfile->num_sections + * sizeof (offs->offsets)); + memcpy (offs, symfile_objfile->section_offsets, + sizeof (struct section_offsets) + + symfile_objfile->num_sections + * sizeof (offs->offsets)); + + /* FIXME: This code assumes gdb-stabs.h is being used; it's broken + for xcoff, dwarf, sdb-coff, etc. But there is no simple + canonical representation for this stuff. (Just what does "text" + as seen by the stub mean, anyway? I think it means all sections + with SEC_CODE set, but we currently have no way to deal with that). */ + + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr; + + /* This is a temporary kludge to force data and bss to use the same offsets + because that's what nlmconv does now. The real solution requires changes + to the stub and remote.c that I don't have time to do right now. */ + + ANOFFSET (offs, SECT_OFF_DATA) = data_addr; + ANOFFSET (offs, SECT_OFF_BSS) = data_addr; + + objfile_relocate (symfile_objfile, offs); +} + +#define INBUFSIZE 10 + +void +boot_board() +{ + char c; + char buf[INBUFSIZE]; + char *ptr; + + /* See if we can connect to the boot ROM command line */ + ptr = buf; + while (1) { + SERIAL_WRITE (remote_desc, "\r\n", 2); + c = readchar (2); + if ((sr_get_debug() > 2) && (isascii(c))) + putchar (c); + if (c == SERIAL_TIMEOUT) { + if (sr_get_debug()) + puts_filtered ("Timed out.\n"); + break; + } + if (c == '&') { + if (sr_get_debug() > 2) + puts ("Got ACK from stub"); + break; + } + if (c == '>') { + if (sr_get_debug() > 2) + puts ("Got prompt from ROM monitor"); + break; + } + } + +} + +/* Stub for catch_errors. */ +static int +remote_start_remote (dummy) + char *dummy; +{ + int timeout; + + immediate_quit = 1; /* Allow user to interrupt it */ + + /* Ack any packet which the remote side has already sent. */ + + if (sr_get_debug()) + puts ("Trying a '+' to ACK the target."); + + SERIAL_WRITE (remote_desc, "+", 1); + +#if 0 + boot_board(); + + get_offsets (); /* Get text, data & bss offsets */ +#endif + + putpkt ("?"); /* initiate a query from remote machine */ + immediate_quit = 0; + + start_remote (); /* Initialize gdb process mechanisms */ + + return 1; +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static DCACHE *remote_dcache; + +static void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + if (name == 0) + error ( +"To open a remote debug connection, you need to specify what serial\n\ +device is attached to the remote system (e.g. /dev/ttya)."); + + target_preopen (from_tty); + + unpush_target (&remote_ops); + + remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); + + remote_desc = SERIAL_OPEN (name); + if (!remote_desc) + perror_with_name (name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (remote_desc, baud_rate)) + { + SERIAL_CLOSE (remote_desc); + perror_with_name (name); + } + } + + SERIAL_RAW (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + push_target (&remote_ops); /* Switch to using remote target now */ + + /* Start out by trying the 'P' request to set registers. We set this each + time that we open a new target so that if the user switches from one + stub to another, we can (if the target is closed and reopened) cope. */ + stub_supports_P = 1; + + /* 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_pid = 42000; + + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, (char *)0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + pop_target(); +} + +/* remote_detach() + takes a program previously attached to and detaches it. + We better not have left any breakpoints + in the program or it'll die when it hits one. + Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ + +static void +remote_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Tell the remote machine to resume. */ + +static void +remote_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + char buf[PBUFSIZ]; + + if (siggnal) + { + target_terminal_ours_for_output (); + printf_filtered + ("Can't send signals to a remote system. %s not sent.\n", + target_signal_to_name (siggnal)); target_terminal_inferior (); + } + + dcache_flush (remote_dcache); + + strcpy (buf, step ? "s": "c"); + + putpkt (buf); +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +remote_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, remote_interrupt_twice); + + if (remote_debug) + printf_unfiltered ("remote_interrupt called\n"); + + SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */ +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +remote_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + interrupt_query (); + + signal (signo, remote_interrupt); +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +interrupt_query () +{ + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + Returns "pid" (though it's not clear what, if anything, that + means in the case of this target). */ + +static int +remote_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + unsigned char buf[PBUFSIZ]; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + while (1) + { + unsigned char *p; + + ofunc = (void (*)()) signal (SIGINT, remote_interrupt); + getpkt ((char *) buf, 1); + signal (SIGINT, ofunc); + + switch (buf[0]) + { + case 'E': /* Error of some sort */ + warning ("Remote failure reply: %s", buf); + continue; + case 'T': /* Status with PC, SP, FP, ... */ + { + int i; + long regno; + char regs[MAX_REGISTER_RAW_SIZE]; + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + + regno = strtol (p, (char **) &p1, 16); /* Read the register number */ + + if (p1 == p) + warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n", + p1, buf); + + p = p1; + + if (*p++ != ':') + warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n", + p, buf); + + if (regno >= NUM_REGS) + warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n", + regno, p, buf); + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) + { + if (p[0] == 0 || p[1] == 0) + warning ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (*p++ != ';') + warning ("Remote register badly formatted: %s", buf); + + supply_register (regno, regs); + } + } + /* fall through */ + case 'S': /* Old style status, just signal only */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + return inferior_pid; + case 'W': /* Target exited */ + { + /* The remote process exited. */ + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]); + return inferior_pid; + } + case 'O': /* Console output */ + fputs_filtered (buf + 1, gdb_stdout); + continue; + default: + warning ("Invalid remote reply: %s", buf); + continue; + } + } + return inferior_pid; +} + +/* Number of bytes of registers this stub implements. */ +static int register_bytes_found; + +/* Read the remote registers into the block REGS. */ +/* Currently we just read all the registers, so we don't use regno. */ +/* ARGSUSED */ +static void +remote_fetch_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + char regs[REGISTER_BYTES]; + + sprintf (buf, "g"); + remote_send (buf); + + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + + /* We can get out of synch in various cases. If the first character + in the buffer is not a hex character, assume that has happened + and try to fetch another packet to read. */ + while ((buf[0] < '0' || buf[0] > '9') + && (buf[0] < 'a' || buf[0] > 'f')) + { + if (remote_debug) + printf_unfiltered ("Bad register packet; fetching a new packet\n"); + getpkt (buf, 0); + } + + /* Reply describes registers byte by byte, each byte encoded as two + hex characters. Suck them all up, then supply them to the + register cacheing/storage mechanism. */ + + p = buf; + for (i = 0; i < REGISTER_BYTES; i++) + { + if (p[0] == 0) + break; + if (p[1] == 0) + { + warning ("Remote reply is of odd length: %s", buf); + /* Don't change register_bytes_found in this case, and don't + print a second warning. */ + goto supply_them; + } + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (i != register_bytes_found) + { + register_bytes_found = i; +#ifdef REGISTER_BYTES_OK + if (!REGISTER_BYTES_OK (i)) + warning ("Remote reply is too short: %s", buf); +#endif + } + + supply_them: + for (i = 0; i < NUM_REGS; i++) + supply_register (i, ®s[REGISTER_BYTE(i)]); +} + +/* Prepare to store registers. Since we may send them all (using a + 'G' request), we have to read out the ones we don't want to change + first. */ + +static void +remote_prepare_to_store () +{ + /* Make sure the entire registers array is valid. */ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES); +} + +/* Store register REGNO, or all registers if REGNO == -1, from the contents + of REGISTERS. FIXME: ignores errors. */ + +static void +remote_store_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (regno >= 0 && stub_supports_P) + { + /* Try storing a single register. */ + char *regp; + + sprintf (buf, "P%x=", regno); + p = buf + strlen (buf); + regp = ®isters[REGISTER_BYTE (regno)]; + for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i) + { + *p++ = tohex ((regp[i] >> 4) & 0xf); + *p++ = tohex (regp[i] & 0xf); + } + *p = '\0'; + remote_send (buf); + if (buf[0] != '\0') + { + /* The stub understands the 'P' request. We are done. */ + return; + } + + /* The stub does not support the 'P' request. Use 'G' instead, + and don't try using 'P' in the future (it will just waste our + time). */ + stub_supports_P = 0; + } + + buf[0] = 'G'; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf + 1; + /* remote_prepare_to_store insures that register_bytes_found gets set. */ + for (i = 0; i < register_bytes_found; i++) + { + *p++ = tohex ((registers[i] >> 4) & 0xf); + *p++ = tohex (registers[i] & 0xf); + } + *p = '\0'; + + remote_send (buf); +} + +#if 0 + +/* Use of the data cache is disabled because it loses for looking at + and changing hardware I/O ports and the like. Accepting `volatile' + would perhaps be one way to fix it. Another idea would be to use the + executable file for the text segment (for all SEC_CODE sections? + For all SEC_READONLY sections?). This has problems if you want to + actually see what the memory contains (e.g. self-modifying code, + clobbered memory, user downloaded the wrong thing). */ + +/* Read a word from remote address ADDR and return it. + This goes through the data cache. */ + +static int +remote_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (remote_dcache, addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +static void +remote_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (remote_dcache, addr, word); +} +#endif /* 0 */ + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + /* FIXME-32x64: Need a version of print_address_numeric which puts the + result in a buffer like sprintf. */ + sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, len); + + /* We send target system values byte by byte, in increasing byte addresses, + each byte encoded as two hex characters. */ + + p = buf + strlen (buf); + for (i = 0; i < len; i++) + { + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); + } + *p = '\0'; + + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + return len; +} + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + if (len > PBUFSIZ / 2 - 1) + abort (); + + /* FIXME-32x64: Need a version of print_address_numeric which puts the + result in a buffer like sprintf. */ + sprintf (buf, "m%lx,%x", (unsigned long) memaddr, len); + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + + /* Reply describes memory byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + for (i = 0; i < len; i++) + { + if (p[0] == 0 || p[1] == 0) + /* Reply is short. This means that we were able to read only part + of what we wanted to. */ + break; + myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + return i; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is + nonzero. Returns length of data written or read; 0 for error. */ + +/* ARGSUSED */ +static int +remote_xfer_memory(memaddr, myaddr, len, should_write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; + struct target_ops *target; /* ignored */ +{ + int xfersize; + int bytes_xferred; + int total_xferred = 0; + + while (len > 0) + { + if (len > MAXBUFBYTES) + xfersize = MAXBUFBYTES; + else + xfersize = len; + + if (should_write) + bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize); + else + bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize); + + /* If we get an error, we are done xferring. */ + if (bytes_xferred == 0) + break; + + memaddr += bytes_xferred; + myaddr += bytes_xferred; + len -= bytes_xferred; + total_xferred += bytes_xferred; + } + return total_xferred; +} + +#if 0 +/* Enable after 4.12. */ + +void +remote_search (len, data, mask, startaddr, increment, lorange, hirange + addr_found, data_found) + int len; + char *data; + char *mask; + CORE_ADDR startaddr; + int increment; + CORE_ADDR lorange; + CORE_ADDR hirange; + CORE_ADDR *addr_found; + char *data_found; +{ + if (increment == -4 && len == 4) + { + long mask_long, data_long; + long data_found_long; + CORE_ADDR addr_we_found; + char buf[PBUFSIZ]; + long returned_long[2]; + char *p; + + mask_long = extract_unsigned_integer (mask, len); + data_long = extract_unsigned_integer (data, len); + sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long); + putpkt (buf); + getpkt (buf, 0); + if (buf[0] == '\0') + { + /* The stub doesn't support the 't' request. We might want to + remember this fact, but on the other hand the stub could be + switched on us. Maybe we should remember it only until + the next "target remote". */ + generic_search (len, data, mask, startaddr, increment, lorange, + hirange, addr_found, data_found); + return; + } + + if (buf[0] == 'E') + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just use EIO. */ + memory_error (EIO, startaddr); + p = buf; + addr_we_found = 0; + while (*p != '\0' && *p != ',') + addr_we_found = (addr_we_found << 4) + fromhex (*p++); + if (*p == '\0') + error ("Protocol error: short return for search"); + + data_found_long = 0; + while (*p != '\0' && *p != ',') + data_found_long = (data_found_long << 4) + fromhex (*p++); + /* Ignore anything after this comma, for future extensions. */ + + if (addr_we_found < lorange || addr_we_found >= hirange) + { + *addr_found = 0; + return; + } + + *addr_found = addr_we_found; + *data_found = store_unsigned_integer (data_we_found, len); + return; + } + generic_search (len, data, mask, startaddr, increment, lorange, + hirange, addr_found, data_found); +} +#endif /* 0 */ + +static void +remote_files_info (ignore) + struct target_ops *ignore; +{ + puts_filtered ("Debugging a target over a serial line.\n"); +} + +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ + +/* Read a single character from the remote end, masking it down to 7 bits. */ + +static int +readchar (timeout) + int timeout; +{ + int ch; + + ch = SERIAL_READCHAR (remote_desc, timeout); + + switch (ch) + { + case SERIAL_EOF: + error ("Remote connection closed"); + case SERIAL_ERROR: + perror_with_name ("Remote communication error"); + case SERIAL_TIMEOUT: + return ch; + default: + return ch & 0x7f; + } +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +static void +remote_send (buf) + char *buf; +{ + + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + error ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ +static void +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[PBUFSIZ]; + int cnt = strlen (buf); + int ch; + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + if (cnt > sizeof(buf2) - 5) /* Prosanity check */ + abort(); + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + while (1) + { + int started_error_output = 0; + + if (remote_debug) + { + *p = '\0'; + printf_unfiltered ("Sending packet: %s...", buf2); + gdb_flush(gdb_stdout); + } + if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + perror_with_name ("putpkt: write failed"); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (1) + { + ch = readchar (remote_timeout); + + if (remote_debug) + { + switch (ch) + { + case '+': + case SERIAL_TIMEOUT: + case '$': + if (started_error_output) + { + putchar_unfiltered ('\n'); + started_error_output = 0; + } + } + } + + switch (ch) + { + case '+': + if (remote_debug) + printf_unfiltered("Got Ack\n"); + return; + case SERIAL_TIMEOUT: + break; /* Retransmit buffer */ + case '$': + { + unsigned char junkbuf[PBUFSIZ]; + + /* It's probably an old response, and we're out of sync. Just + gobble up the packet and ignore it. */ + getpkt (junkbuf, 0); + continue; /* Now, go look for + */ + } + default: + if (remote_debug) + { + if (!started_error_output) + { + started_error_output = 1; + printf_unfiltered ("putpkt: Junk: "); + } + putchar_unfiltered (ch & 0177); + } + continue; + } + break; /* Here to retransmit */ + } + +#if 0 + /* This is wrong. If doing a long backtrace, the user should be + able to get out next time we call QUIT, without anything as violent + as interrupt_query. If we want to provide a way out of here + without getting to the next QUIT, it should be based on hitting + ^C twice as in remote_wait. */ + if (quit_flag) + { + quit_flag = 0; + interrupt_query (); + } +#endif + } +} + +/* Come here after finding the start of the frame. Collect the rest into BUF, + verifying the checksum, length, and handling run-length compression. + Returns 0 on any error, 1 on success. */ + +static int +read_frame (buf) + char *buf; +{ + unsigned char csum; + char *bp; + int c; + + csum = 0; + bp = buf; + + while (1) + { + c = readchar (remote_timeout); + + switch (c) + { + case SERIAL_TIMEOUT: + if (remote_debug) + puts_filtered ("Timeout in mid-packet, retrying\n"); + return 0; + case '$': + if (remote_debug) + puts_filtered ("Saw new packet start in middle of old one\n"); + return 0; /* Start a new packet, count retries */ + case '#': + { + unsigned char pktcsum; + + *bp = '\000'; + + pktcsum = fromhex (readchar (remote_timeout)) << 4; + pktcsum |= fromhex (readchar (remote_timeout)); + + if (csum == pktcsum) + return 1; + + printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + pktcsum, csum); + puts_filtered (buf); + puts_filtered ("\n"); + + return 0; + } + case '*': /* Run length encoding */ + csum += c; + c = readchar (remote_timeout); + csum += c; + c = c - ' ' + 3; /* Compute repeat count */ + + if (bp + c - 1 < buf + PBUFSIZ - 1) + { + memset (bp, *(bp - 1), c); + bp += c; + continue; + } + + *bp = '\0'; + printf_filtered ("Repeat count %d too large for buffer: ", c); + puts_filtered (buf); + puts_filtered ("\n"); + return 0; + + default: + if (bp < buf + PBUFSIZ - 1) + { + *bp++ = c; + csum += c; + continue; + } + + *bp = '\0'; + puts_filtered ("Remote packet too long: "); + puts_filtered (buf); + puts_filtered ("\n"); + + return 0; + } + } +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. BUF is expected to be of size PBUFSIZ. + If FOREVER, wait forever rather than timing out; this is used + while the target is executing user code. */ + +static void +getpkt (buf, forever) + char *buf; + int forever; +{ + char *bp; + int c; + int tries; + int timeout; + int val; + + if (forever) + timeout = -1; + else + timeout = remote_timeout; + +#define MAX_TRIES 10 + + for (tries = 1; tries <= MAX_TRIES; tries++) + { + /* This can loop forever if the remote side sends us characters + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ + + /* Note that we will only wait forever prior to the start of a packet. + After that, we expect characters to arrive at a brisk pace. They + should show up within remote_timeout intervals. */ + + do + { + c = readchar (timeout); + + if (c == SERIAL_TIMEOUT) + { + if (remote_debug) + puts_filtered ("Timed out.\n"); + goto retry; + } + } + while (c != '$'); + + /* We've found the start of a packet, now collect the data. */ + + val = read_frame (buf); + + if (val == 1) + { + if (remote_debug) + fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf); + SERIAL_WRITE (remote_desc, "+", 1); + return; + } + + /* Try the whole thing again. */ +retry: + SERIAL_WRITE (remote_desc, "-", 1); + } + + /* We have tried hard enough, and just can't receive the packet. Give up. */ + + printf_unfiltered ("Ignoring packet error, continuing...\n"); + SERIAL_WRITE (remote_desc, "+", 1); +} + +static void +remote_kill () +{ + putpkt ("k"); + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); +} + +static void +remote_mourn () +{ + unpush_target (&remote_ops); + generic_mourn_inferior (); +} + +#ifdef REMOTE_BREAKPOINT + +/* On some machines, e.g. 68k, we may use a different breakpoint instruction + than other targets. */ +static unsigned char break_insn[] = REMOTE_BREAKPOINT; + +#else /* No REMOTE_BREAKPOINT. */ + +/* Same old breakpoint instruction. This code does nothing different + than mem-break.c. */ +static unsigned char break_insn[] = BREAKPOINT; + +#endif /* No REMOTE_BREAKPOINT. */ + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ + +static int +remote_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, (char *)break_insn, sizeof break_insn); + + return val; +} + +static int +remote_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, sizeof break_insn); +} + +/* Define the target subroutine names */ + +struct target_ops remote_hppro_ops = { + "hppro", /* to_shortname */ + "Remote serial target for HP-PRO targets", /* to_longname */ + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +This is for targets that supports the HP-PRO standard.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya) or telnet port.", /* to_doc */ + remote_open, /* to_open */ + remote_close, /* to_close */ + NULL, /* to_attach */ + remote_detach, /* to_detach */ + remote_resume, /* to_resume */ + remote_wait, /* to_wait */ + remote_fetch_registers, /* to_fetch_registers */ + remote_store_registers, /* to_store_registers */ + remote_prepare_to_store, /* to_prepare_to_store */ + remote_xfer_memory, /* to_xfer_memory */ + remote_files_info, /* to_files_info */ + + remote_insert_breakpoint, /* to_insert_breakpoint */ + remote_remove_breakpoint, /* to_remove_breakpoint */ + + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + remote_kill, /* to_kill */ + hppro_load, /* to_load */ + NULL, /* to_lookup_symbol */ + NULL, /* to_create_inferior */ + remote_mourn, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_hppro () +{ + struct cmd_list_element *c; + add_target (&remote_hppro_ops); + + /* this sets the type of download protocol */ + c = add_set_cmd ("loadtype", no_class, var_string, (char *)&loadtype_str, + "Set the type of the remote load protocol.\n", &setlist); + c->function.sfunc = set_loadtype_command; + add_show_from_set (c, &showlist); + loadtype_str = savestring ("generic", 8); + + /* this adds a command to boot the board */ + add_com ("boot", class_support, boot_board, + "Boot the damn target board.\n"); +} + +static void +set_loadtype_command (ignore, from_tty, c) + char *ignore; + int from_tty; + struct cmd_list_element *c; +{ + loadtype_str = savestring (*(char **) c->var, strlen (*(char **) c->var)); +} + diff --git a/contrib/gdb/gdb/remote-rdp.c b/contrib/gdb/gdb/remote-rdp.c new file mode 100644 index 000000000000..3cc4c4eed2d3 --- /dev/null +++ b/contrib/gdb/gdb/remote-rdp.c @@ -0,0 +1,1247 @@ +/* Remote debugging for the ARM RDP interface. + Copyright 1994, 1995 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + */ + + +/* + Much of this file (in particular the SWI stuff) is based on code by + David Taylor (djt1000@uk.ac.cam.hermes). + + I hacked on and simplified it by removing a lot of sexy features he + had added, and some of the (unix specific) workarounds he'd done + for other GDB problems - which if they still exist should be fixed + in GDB, not in a remote-foo thing . I also made it conform more to + the doc I have; which may be wrong. + + Steve Chamberlain (sac@cygnus.com). + */ + + +#include "defs.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include "callback.h" +#include "command.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include +#include "symfile.h" +#include "remote-utils.h" +#include "gdb_string.h" +#ifdef HAVE_UNISTD_H +#include +#endif + + +extern struct target_ops remote_rdp_ops; +static serial_t io; +static host_callback *callback = &default_callback; + +struct + { + int step_info; + int break_info; + int model_info; + int target_info; + int can_step; + char command_line[10]; + int rdi_level; + int rdi_stopped_status; + } +ds; + + + +/* Definitions for the RDP protocol. */ + +#define RDP_MOUTHFULL (1<<6) +#define FPU_COPRO_NUMBER 1 + +#define RDP_OPEN 0 +#define RDP_OPEN_TYPE_COLD 0 +#define RDP_OPEN_TYPE_WARM 1 +#define RDP_OPEN_TYPE_BAUDRATE 2 + +#define RDP_OPEN_BAUDRATE_9600 1 +#define RDP_OPEN_BAUDRATE_19200 2 +#define RDP_OPEN_BAUDRATE_38400 3 + +#define RDP_OPEN_TYPE_RETURN_SEX (1<<3) + +#define RDP_CLOSE 1 + +#define RDP_MEM_READ 2 + +#define RDP_MEM_WRITE 3 + +#define RDP_CPU_READ 4 +#define RDP_CPU_WRITE 5 +#define RDP_CPU_READWRITE_MODE_CURRENT 255 +#define RDP_CPU_READWRITE_MASK_PC (1<<16) +#define RDP_CPU_READWRITE_MASK_CPSR (1<<17) +#define RDP_CPU_READWRITE_MASK_SPSR (1<<18) + +#define RDP_COPRO_READ 6 +#define RDP_COPRO_WRITE 7 +#define RDP_FPU_READWRITE_MASK_FPS (1<<8) + +#define RDP_SET_BREAK 0xa +#define RDP_SET_BREAK_TYPE_PC_EQUAL 0 +#define RDP_SET_BREAK_TYPE_GET_HANDLE (0x10) + +#define RDP_CLEAR_BREAK 0xb + +#define RDP_EXEC 0x10 +#define RDP_EXEC_TYPE_SYNC 0 + +#define RDP_STEP 0x11 + +#define RDP_INFO 0x12 +#define RDP_INFO_ABOUT_STEP 2 +#define RDP_INFO_ABOUT_STEP_GT_1 1 +#define RDP_INFO_ABOUT_STEP_TO_JMP 2 +#define RDP_INFO_ABOUT_STEP_1 4 +#define RDP_INFO_ABOUT_TARGET 0 +#define RDP_INFO_ABOUT_BREAK 1 +#define RDP_INFO_ABOUT_BREAK_COMP 1 +#define RDP_INFO_ABOUT_BREAK_RANGE 2 +#define RDP_INFO_ABOUT_BREAK_BYTE_READ 4 +#define RDP_INFO_ABOUT_BREAK_HALFWORD_READ 8 +#define RDP_INFO_ABOUT_BREAK_WORD_READ (1<<4) +#define RDP_INFO_ABOUT_BREAK_BYTE_WRITE (1<<5) +#define RDP_INFO_ABOUT_BREAK_HALFWORD_WRITE (1<<6) +#define RDP_INFO_ABOUT_BREAK_WORD_WRITE (1<<7) +#define RDP_INFO_ABOUT_BREAK_MASK (1<<8) +#define RDP_INFO_ABOUT_BREAK_THREAD_BREAK (1<<9) +#define RDP_INFO_ABOUT_BREAK_THREAD_WATCH (1<<10) +#define RDP_INFO_ABOUT_BREAK_COND (1<<11) + +#define RDP_RESET 0x7f + +/* Returns from RDP */ +#define RDP_RES_STOPPED 0x20 +#define RDP_RES_SWI 0x21 +#define RDP_RES_FATAL 0x5e +#define RDP_RES_VALUE 0x5f +#define RDP_RES_VALUE_LITTLE_ENDIAN 240 +#define RDP_RES_VALUE_BIG_ENDIAN 241 +#define RDP_RES_RESET 0x7f +#define RDP_RES_AT_BREAKPOINT 143 +#define RDP_RES_IDUNNO 0xe6 +#define RDP_OSOpReply 0x13 +#define RDP_OSOpWord 2 +#define RDP_OSOpNothing 0 + +static int timeout = 2; + +static int +remote_rdp_xfer_inferior_memory PARAMS ((CORE_ADDR memaddr, + char *myaddr, + int len, + int write, + struct target_ops * target)); + + +/* Stuff for talking to the serial layer. */ + +static unsigned char +get_byte () +{ + int c = SERIAL_READCHAR (io, timeout); + + if (remote_debug) + printf ("[%02x]\n", c); + + if (c == SERIAL_TIMEOUT) + { + if (timeout == 0) + return (unsigned char) c; + + error ("Timeout reading from remote_system"); + } + + return c; +} + +/* Note that the target always speaks little-endian to us, + even if it's a big endian machine. */ +static unsigned int +get_word () +{ + unsigned int val = 0; + unsigned int c; + int n; + for (n = 0; n < 4; n++) + { + c = get_byte (); + val |= c << (n * 8); + } + return val; +} + +static void +put_byte (val) + char val; +{ + if (remote_debug) + printf ("(%02x)\n", val); + SERIAL_WRITE (io, &val, 1); +} + +static void +put_word (val) + int val; +{ + /* We always send in little endian */ + unsigned char b[4]; + b[0] = val; + b[1] = val >> 8; + b[2] = val >> 16; + b[3] = val >> 24; + + if (remote_debug) + printf ("(%04x)", val); + + SERIAL_WRITE (io, b, 4); +} + + + +/* Stuff for talking to the RDP layer. */ + +/* This is a bit more fancy that need be so that it syncs even in nasty cases. + + I'be been unable to make it reliably sync up with the change + baudrate open command. It likes to sit and say it's been reset, + with no more action. So I took all that code out. I'd rather sync + reliably at 9600 than wait forever for a possible 19200 connection. + + */ +static void +rdp_init (cold, tty) + int cold; + int tty; +{ + int sync = 0; + int type = cold ? RDP_OPEN_TYPE_COLD : RDP_OPEN_TYPE_WARM; + int baudtry = 9600; + + time_t now = time (0); + time_t stop_time = now + 10; /* Try and sync for 10 seconds, then give up */ + + + while (time (0) < stop_time && !sync) + { + int restype; + QUIT; + + SERIAL_FLUSH_INPUT (io); + SERIAL_FLUSH_OUTPUT (io); + + if (tty) + printf_unfiltered ("Trying to connect at %d baud.\n", baudtry); + put_byte (RDP_OPEN); + + put_byte (type | RDP_OPEN_TYPE_RETURN_SEX); + put_word (0); + + while (!sync && (restype = SERIAL_READCHAR (io, 1)) > 0) + { + if (remote_debug) + printf_unfiltered ("[%02x]\n", restype); + + switch (restype) + { + case SERIAL_TIMEOUT: + break; + case RDP_RESET: + while ((restype = SERIAL_READCHAR (io, 1)) == RDP_RESET) + ; + while ((restype = SERIAL_READCHAR (io, 1)) > 0) + { + printf_unfiltered ("%c", isgraph (restype) ? restype : ' '); + } + while ((restype = SERIAL_READCHAR (io, 1)) > 0) + ; + if (tty) + { + printf_unfiltered ("\nThe board has sent notification that it was reset.\n"); + printf_unfiltered ("Waiting for it to settle down...\n"); + } + sleep (3); + if (tty) + printf_unfiltered ("\nTrying again.\n"); + break; + default: + break; + case RDP_RES_VALUE: + { + int resval = SERIAL_READCHAR (io, 1); + switch (resval) + { + case SERIAL_TIMEOUT: + break; + case RDP_RES_VALUE_LITTLE_ENDIAN: + target_byte_order = LITTLE_ENDIAN; + sync = 1; + break; + case RDP_RES_VALUE_BIG_ENDIAN: + target_byte_order = BIG_ENDIAN; + sync = 1; + break; + default: + break; + } + } + } + } + } + + if (!sync) + { + error ("Couldn't reset the board, try pressing the reset button"); + } +} + + +#ifdef ANSI_PROTOTYPES +void +send_rdp (char *template,...) +#else +void +send_rdp (char *template, va_alist) + va_dcl +#endif +{ + char buf[200]; + char *dst = buf; + va_list alist; +#ifdef ANSI_PROTOTYPES + va_start (alist, template); +#else + va_start (alist); +#endif + + while (*template) + { + unsigned int val; + int *pi; + int *pstat; + char *pc; + int i; + switch (*template++) + { + case 'b': + val = va_arg (alist, int); + *dst++ = val; + break; + case 'w': + val = va_arg (alist, int); + *dst++ = val; + *dst++ = val >> 8; + *dst++ = val >> 16; + *dst++ = val >> 24; + break; + case 'S': + val = get_byte (); + if (val != RDP_RES_VALUE) + { + printf_unfiltered ("got bad res value of %d, %x\n", val, val); + } + break; + case 'V': + pstat = va_arg (alist, int *); + pi = va_arg (alist, int *); + + *pstat = get_byte (); + /* Check the result was zero, if not read the syndrome */ + if (*pstat) + { + *pi = get_word (); + } + break; + case 'Z': + /* Check the result code, error if not zero */ + if (get_byte ()) + error ("Command garbled"); + break; + case 'W': + /* Read a word from the target */ + pi = va_arg (alist, int *); + *pi = get_word (); + break; + case 'P': + /* Read in some bytes from the target. */ + pc = va_arg (alist, char *); + val = va_arg (alist, int); + for (i = 0; i < val; i++) + { + pc[i] = get_byte (); + } + break; + case 'p': + /* send what's being pointed at */ + pc = va_arg (alist, char *); + val = va_arg (alist, int); + dst = buf; + SERIAL_WRITE (io, pc, val); + break; + case '-': + /* Send whats in the queue */ + if (dst != buf) + { + SERIAL_WRITE (io, buf, dst - buf); + dst = buf; + } + break; + case 'B': + pi = va_arg (alist, int *); + *pi = get_byte (); + break; + default: + abort (); + } + } + va_end (args); + + if (dst != buf) + abort (); +} + + +static int +rdp_write (memaddr, buf, len) + CORE_ADDR memaddr; + char *buf; + int len; +{ + int res; + int val; + + send_rdp ("bww-p-SV", RDP_MEM_WRITE, memaddr, len, buf, len, &res, &val); + + if (res) + { + return val; + } + return len; +} + + +static int +rdp_read (memaddr, buf, len) + CORE_ADDR memaddr; + char *buf; + int len; +{ + int res; + int val; + send_rdp ("bww-S-P-V", + RDP_MEM_READ, memaddr, len, + buf, len, + &res, &val); + if (res) + { + return val; + } + return len; +} + +static void +rdp_fetch_one_register (mask, buf) + int mask; + char *buf; +{ + int val; + send_rdp ("bbw-SWZ", RDP_CPU_READ, RDP_CPU_READWRITE_MODE_CURRENT, mask, &val); + store_signed_integer (buf, 4, val); +} + +static void +rdp_fetch_one_fpu_register (mask, buf) + int mask; + char *buf; +{ +#if 0 + /* !!! Since the PIE board doesn't work as documented, + and it doesn't have FPU hardware anyway and since it + slows everything down, I've disabled this. */ + int val; + if (mask == RDP_FPU_READWRITE_MASK_FPS) + { + /* this guy is only a word */ + send_rdp ("bbw-SWZ", RDP_COPRO_READ, FPU_COPRO_NUMBER, mask, &val); + store_signed_integer (buf, 4, val); + } + else + { + /* There are 12 bytes long + !! fixme about endianness + */ + int dummy; /* I've seen these come back as four words !! */ + send_rdp ("bbw-SWWWWZ", RDP_COPRO_READ, FPU_COPRO_NUMBER, mask, buf + 0, buf + 4, buf + 8, &dummy); + } +#endif + memset (buf, 0, MAX_REGISTER_RAW_SIZE); +} + + +static void +rdp_store_one_register (mask, buf) + int mask; + char *buf; +{ + int val = extract_unsigned_integer (buf, 4); + + send_rdp ("bbww-SZ", + RDP_CPU_WRITE, RDP_CPU_READWRITE_MODE_CURRENT, mask, val); +} + + +static void +rdp_store_one_fpu_register (mask, buf) + int mask; + char *buf; +{ +#if 0 + /* See comment in fetch_one_fpu_register */ + if (mask == RDP_FPU_READWRITE_MASK_FPS) + { + int val = extract_unsigned_integer (buf, 4); + /* this guy is only a word */ + send_rdp ("bbww-SZ", RDP_COPRO_WRITE, + FPU_COPRO_NUMBER, + mask, val); + } + else + { + /* There are 12 bytes long + !! fixme about endianness + */ + int dummy = 0; + /* I've seen these come as four words, not the three advertized !! */ + printf ("Sending mask %x\n", mask); + send_rdp ("bbwwwww-SZ", + RDP_COPRO_WRITE, + FPU_COPRO_NUMBER, + mask, + *(int *) (buf + 0), + *(int *) (buf + 4), + *(int *) (buf + 8), + 0); + + printf ("done mask %x\n", mask); + } +#endif +} + + +/* Convert between GDB requests and the RDP layer. */ + +static void +remote_rdp_fetch_register (regno) + int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + remote_rdp_fetch_register (regno); + } + else + { + char buf[MAX_REGISTER_RAW_SIZE]; + if (regno < 15) + rdp_fetch_one_register (1 << regno, buf); + else if (regno == PC_REGNUM) + rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_PC, buf); + else if (regno == PS_REGNUM) + rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_CPSR, buf); + else if (regno == FPS_REGNUM) + rdp_fetch_one_fpu_register (RDP_FPU_READWRITE_MASK_FPS, buf); + else if (regno >= F0_REGNUM && regno <= F7_REGNUM) + rdp_fetch_one_fpu_register (1 << (regno - F0_REGNUM), buf); + else + { + printf ("Help me with fetch reg %d\n", regno); + } + supply_register (regno, buf); + } +} + + +static void +remote_rdp_store_register (regno) + int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + remote_rdp_store_register (regno); + } + else + { + char tmp[MAX_REGISTER_RAW_SIZE]; + read_register_gen (regno, tmp); + if (regno < 15) + rdp_store_one_register (1 << regno, tmp); + else if (regno == PC_REGNUM) + rdp_store_one_register (RDP_CPU_READWRITE_MASK_PC, tmp); + else if (regno == PS_REGNUM) + rdp_store_one_register (RDP_CPU_READWRITE_MASK_CPSR, tmp); + else if (regno >= F0_REGNUM && regno <= F7_REGNUM) + rdp_store_one_fpu_register (1 << (regno - F0_REGNUM), tmp); + else + { + printf ("Help me with reg %d\n", regno); + } + } +} + +static void +remote_rdp_kill () +{ + callback->shutdown (callback); +} + + +static void +rdp_info () +{ + send_rdp ("bw-S-W-Z", RDP_INFO, RDP_INFO_ABOUT_STEP, + &ds.step_info); + send_rdp ("bw-S-W-Z", RDP_INFO, RDP_INFO_ABOUT_BREAK, + &ds.break_info); + send_rdp ("bw-S-WW-Z", RDP_INFO, RDP_INFO_ABOUT_TARGET, + &ds.target_info, + &ds.model_info); + + ds.can_step = ds.step_info & RDP_INFO_ABOUT_STEP_1; + + ds.rdi_level = (ds.target_info >> 5) & 3; +} + + +static void +rdp_execute_start () +{ + /* Start it off, but don't wait for it */ + send_rdp ("bb-", RDP_EXEC, RDP_EXEC_TYPE_SYNC); +} + + + +#define a_byte 1 +#define a_word 2 +#define a_string 3 + + +typedef struct +{ + CORE_ADDR n; + const char *s; +} +argsin; + +#define ABYTE 1 +#define AWORD 2 +#define ASTRING 3 +#define ADDRLEN 4 + +#define SWI_WriteC 0x0 +#define SWI_Write0 0x2 +#define SWI_ReadC 0x4 +#define SWI_CLI 0x5 +#define SWI_GetEnv 0x10 +#define SWI_Exit 0x11 +#define SWI_EnterOS 0x16 + +#define SWI_GetErrno 0x60 +#define SWI_Clock 0x61 + +#define SWI_Time 0x63 +#define SWI_Remove 0x64 +#define SWI_Rename 0x65 +#define SWI_Open 0x66 + +#define SWI_Close 0x68 +#define SWI_Write 0x69 +#define SWI_Read 0x6a +#define SWI_Seek 0x6b +#define SWI_Flen 0x6c + +#define SWI_IsTTY 0x6e +#define SWI_TmpNam 0x6f +#define SWI_InstallHandler 0x70 +#define SWI_GenerateError 0x71 + + +static int +exec_swi (swi, args) + int swi; + argsin *args; +{ + int i; + char c; + switch (swi) + { + case SWI_WriteC: + callback->write_stdout (callback, &c, 1); + return 0; + case SWI_Write0: + for (i = 0; i < args->n; i++) + callback->write_stdout (callback, args->s, strlen (args->s)); + return 0; + case SWI_ReadC: + callback->read_stdin (callback, &c, 1); + args->n = c; + return 1; + case SWI_CLI: + args->n = callback->system (callback, args->s); + return 1; + case SWI_GetErrno: + args->n = callback->get_errno (callback); + return 1; + case SWI_Time: + args->n = callback->time (callback, NULL); + return 1; + case SWI_Remove: + args->n = callback->unlink (callback, args->s); + return 1; + case SWI_Rename: + args->n = callback->rename (callback, args[0].s, args[1].s); + return 1; + case SWI_Open: + i = 0; + +#ifdef O_BINARY + if (args[1].n & 1) + i |= O_BINARY; +#endif + if (args[1].n & 2) + i |= O_RDWR; + + if (args[1].n & 4) + { + i |= O_CREAT; + } + + if (args[1].n & 8) + i |= O_APPEND; + + args->n = callback->open (callback, args->s, i); + return 1; + + case SWI_Close: + args->n = callback->close (callback, args->n); + return 1; + + case SWI_Write: + args->n = callback->write (callback, args[0].n, args[1].s, args[1].n); + return 1; + case SWI_Read: + { + char *copy = alloca (args[2].n); + int done = callback->read (callback, args[0].n, copy, args[2].n); + if (done > 0) + remote_rdp_xfer_inferior_memory (args[0].n, copy, done, 1, 0); + args->n -= done; + return 1; + } + + case SWI_Seek: + args->n = callback->lseek (callback, args[0].n, args[1].n, 0) >= 0; + return 1; + case SWI_Flen: + { + long old = callback->lseek (callback, args->n, 1, 1); + args->n = callback->lseek (callback, args->n, 2, 0); + callback->lseek (callback, args->n, old, 0); + return 1; + } + + case SWI_IsTTY: + args->n = callback->isatty (callback, args->n); + return 1; + + default: + return 0; + } +} + + +static void +handle_swi () +{ + argsin args[3]; + char *buf; + int len; + int count = 0; + + int swino = get_word (); + int type = get_byte (); + while (type != 0) + { + switch (type & 0x3) + { + case ABYTE: + args[count].n = get_byte (); + break; + + case AWORD: + args[count].n = get_word (); + break; + + case ASTRING: + /* If the word is under 32 bytes it will be sent otherwise + an address to it is passed. Also: Special case of 255 */ + + len = get_byte (); + if (len > 32) + { + if (len == 255) + { + len = get_word (); + } + buf = alloca (len); + remote_rdp_xfer_inferior_memory (get_word (), + buf, + len, + 0, + 0); + } + else + { + int i; + buf = alloca (len + 1); + for (i = 0; i < len; i++) + buf[i] = get_byte (); + buf[i] = 0; + } + args[count].n = len; + args[count].s = buf; + break; + + default: + error ("Unimplented SWI argument"); + } + + type = type >> 2; + count++; + } + + if (exec_swi (swino, args)) + { + /* We have two options here reply with either a byte or a word + which is stored in args[0].n. There is no harm in replying with + a word all the time, so thats what I do! */ + send_rdp ("bbw-", RDP_OSOpReply, RDP_OSOpWord, args[0].n); + } + else + { + send_rdp ("bb-", RDP_OSOpReply, RDP_OSOpNothing); + } +} + +static void +rdp_execute_finish () +{ + int running = 1; + + while (running) + { + int res; + res = SERIAL_READCHAR (io, 1); + while (res == SERIAL_TIMEOUT) + { + QUIT; + printf_filtered ("Waiting for target..\n"); + res = SERIAL_READCHAR (io, 1); + } + + switch (res) + { + case RDP_RES_SWI: + handle_swi (); + break; + case RDP_RES_VALUE: + send_rdp ("B", &ds.rdi_stopped_status); + running = 0; + break; + case RDP_RESET: + printf_filtered ("Target reset\n"); + running = 0; + break; + default: + printf_filtered ("Ignoring %x\n", res); + break; + } + } +} + + +static void +rdp_execute () +{ + rdp_execute_start (); + rdp_execute_finish (); +} + +static int +remote_rdp_insert_breakpoint (addr, save) + CORE_ADDR addr; + char *save; +{ + int res; + if (ds.rdi_level > 0) + { + send_rdp ("bwb-SWB", + RDP_SET_BREAK, + addr, + RDP_SET_BREAK_TYPE_PC_EQUAL | RDP_SET_BREAK_TYPE_GET_HANDLE, + save, + &res); + } + else + { + send_rdp ("bwb-SB", + RDP_SET_BREAK, + addr, + RDP_SET_BREAK_TYPE_PC_EQUAL, + &res); + } + return res; +} + +static int +remote_rdp_remove_breakpoint (addr, save) + CORE_ADDR addr; + char *save; +{ + int res; + if (ds.rdi_level > 0) + { + send_rdp ("b-p-S-B", + RDP_CLEAR_BREAK, + save, 4, + &res); + } + else + { + send_rdp ("bw-S-B", + RDP_CLEAR_BREAK, + addr, + &res); + } + return res; +} + +static void +rdp_step () +{ + if (ds.can_step && 0) + { + /* The pie board can't do steps so I can't test this, and + the other code will always work. */ + int status; + send_rdp ("bbw-S-B", + RDP_STEP, 0, 1, + &status); + } + else + { + char handle[4]; + CORE_ADDR pc = read_register (PC_REGNUM); + pc = arm_get_next_pc (pc); + remote_rdp_insert_breakpoint (pc, &handle); + rdp_execute (); + remote_rdp_remove_breakpoint (pc, &handle); + } +} + +static void +remote_rdp_open (args, from_tty) + char *args; + int from_tty; +{ + if (!args) + error_no_arg ("serial port device name"); + + baud_rate = 9600; + + target_preopen (from_tty); + + io = SERIAL_OPEN (args); + + if (!io) + perror_with_name (args); + + SERIAL_RAW (io); + + rdp_init (1, from_tty); + + + if (from_tty) + { + printf_unfiltered ("Remote RDP debugging using %s at %d baud\n", args, baud_rate); + } + + rdp_info (); + + push_target (&remote_rdp_ops); + + callback->init (callback); + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc (); + set_current_frame (create_new_frame (read_fp (), stop_pc)); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, -1, 1); +} + + + +/* Close out all files and local state before this target loses control. */ + +static void +remote_rdp_close (quitting) + int quitting; +{ + callback->shutdown (callback); + if (io) + SERIAL_CLOSE (io); + io = 0; +} + + +/* Resume execution of the target process. STEP says whether to single-step + or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given + to the target, or zero for no signal. */ + +static void +remote_rdp_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + if (step) + rdp_step (); + else + rdp_execute (); +} + +/* Wait for inferior process to do something. Return pid of child, + or -1 in case of error; store status through argument pointer STATUS, + just as `wait' would. */ + +static int +remote_rdp_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + switch (ds.rdi_stopped_status) + { + default: + case RDP_RES_RESET: + case RDP_RES_SWI: + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = read_register (0); + break; + case RDP_RES_AT_BREAKPOINT: + status->kind = TARGET_WAITKIND_STOPPED; + /* The signal in sigrc is a host signal. That probably + should be fixed. */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; +#if 0 + case rdp_signalled: + status->kind = TARGET_WAITKIND_SIGNALLED; + /* The signal in sigrc is a host signal. That probably + should be fixed. */ + status->value.sig = target_signal_from_host (sigrc); + break; +#endif + } + + return inferior_pid; +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +remote_rdp_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static int +remote_rdp_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + /* I infer from D Taylor's code that there's a limit on the amount + we can transfer in one chunk.. */ + int done = 0; + while (done < len) + { + int justdone; + int thisbite = len - done; + if (thisbite > RDP_MOUTHFULL) + thisbite = RDP_MOUTHFULL; + + QUIT; + + if (write) + { + justdone = rdp_write (memaddr + done, myaddr + done, thisbite); + } + else + { + justdone = rdp_read (memaddr + done, myaddr + done, thisbite); + } + + done += justdone; + + if (justdone != thisbite) + break; + } + return done; +} + + + +struct yn +{ + const char *name; + int bit; +}; +static struct yn stepinfo[] = +{ + {"Step more than one instruction", RDP_INFO_ABOUT_STEP_GT_1}, + {"Step to jump", RDP_INFO_ABOUT_STEP_TO_JMP}, + {"Step one instruction", RDP_INFO_ABOUT_STEP_1}, + {0} +}; + +static struct yn breakinfo[] = +{ + {"comparison breakpoints supported", RDP_INFO_ABOUT_BREAK_COMP}, + {"range breakpoints supported", RDP_INFO_ABOUT_BREAK_RANGE}, + {"watchpoints for byte reads supported", RDP_INFO_ABOUT_BREAK_BYTE_READ}, + {"watchpoints for half-word reads supported", RDP_INFO_ABOUT_BREAK_HALFWORD_READ}, + {"watchpoints for word reads supported", RDP_INFO_ABOUT_BREAK_WORD_READ}, + {"watchpoints for byte writes supported", RDP_INFO_ABOUT_BREAK_BYTE_WRITE}, + {"watchpoints for half-word writes supported", RDP_INFO_ABOUT_BREAK_HALFWORD_WRITE}, + {"watchpoints for word writes supported", RDP_INFO_ABOUT_BREAK_WORD_WRITE}, + {"mask break/watch-points supported", RDP_INFO_ABOUT_BREAK_MASK}, +{"thread-specific breakpoints supported", RDP_INFO_ABOUT_BREAK_THREAD_BREAK}, +{"thread-specific watchpoints supported", RDP_INFO_ABOUT_BREAK_THREAD_WATCH}, + {"conditional breakpoints supported", RDP_INFO_ABOUT_BREAK_COND}, + {0} +}; + + +static void +dump_bits (t, info) + struct yn *t; + int info; +{ + while (t->name) + { + printf_unfiltered (" %-45s : %s\n", t->name, (info & t->bit) ? "Yes" : "No"); + t++; + } +} + +static void +remote_rdp_files_info (target) + struct target_ops *target; +{ + printf_filtered ("Target capabilities:\n"); + dump_bits (stepinfo, ds.step_info); + dump_bits (breakinfo, ds.break_info); + printf_unfiltered ("target level RDI %x\n", (ds.target_info >> 5) & 3); +} + + +/* Define the target subroutine names */ + +struct target_ops remote_rdp_ops = +{ + "rdp", /* to_shortname */ + /* to_longname */ + "Remote Target using the RDProtocol", + /* to_doc */ + "Use a remote ARM system which uses the ARM Remote Debugging Protocol", + remote_rdp_open, /* to_open */ + remote_rdp_close, /* to_close */ + NULL, /* to_attach */ + NULL, /* to_detach */ + remote_rdp_resume, /* to_resume */ + remote_rdp_wait, /* to_wait */ + remote_rdp_fetch_register, /* to_fetch_registers */ + remote_rdp_store_register, /* to_store_registers */ + remote_rdp_prepare_to_store, /* to_prepare_to_store */ + remote_rdp_xfer_inferior_memory, /* to_xfer_memory */ + remote_rdp_files_info, /* to_files_info */ + remote_rdp_insert_breakpoint, /* to_insert_breakpoint */ + remote_rdp_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + remote_rdp_kill, /* to_kill */ + generic_load, /* to_load */ + NULL, /* to_lookup_symbol */ + NULL, /* to_create_inferior */ + generic_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC, /* to_magic */ +}; + +void +_initialize_remote_rdp () +{ + add_target (&remote_rdp_ops); +} diff --git a/contrib/gdb/gdb/remote-sim.c b/contrib/gdb/gdb/remote-sim.c new file mode 100644 index 000000000000..d0f0f50daa9a --- /dev/null +++ b/contrib/gdb/gdb/remote-sim.c @@ -0,0 +1,468 @@ +/* Generic remote debugging interface for simulators. + Copyright 1993, 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Steve Chamberlain (sac@cygnus.com). + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include "terminal.h" +#include "target.h" +#include "gdbcore.h" +#include "remote-sim.h" +#include "remote-utils.h" +#include "callback.h" + +/* Naming convention: + + sim_* are the interface to the simulator (see remote-sim.h). + sim_callback_* are the stuff which the simulator can see inside GDB. + gdbsim_* are stuff which is internal to gdb. */ + +/* Forward data declarations */ +extern struct target_ops gdbsim_ops; + +static int program_loaded = 0; + +static void +dump_mem (buf, len) + char *buf; + int len; +{ + if (len <= 8) + { + if (len == 8 || len == 4) + { + long l[2]; + memcpy (l, buf, len); + printf_filtered ("\t0x%x", l[0]); + printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]); + } + else + { + int i; + printf_filtered ("\t"); + for (i = 0; i < len; i++) + printf_filtered ("0x%x ", buf[i]); + printf_filtered ("\n"); + } + } +} + +static void +gdbsim_fetch_register (regno) +int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + gdbsim_fetch_register (regno); + } + else + { + char buf[MAX_REGISTER_RAW_SIZE]; + + sim_fetch_register (regno, buf); + supply_register (regno, buf); + if (sr_get_debug ()) + { + printf_filtered ("gdbsim_fetch_register: %d", regno); + /* FIXME: We could print something more intelligible. */ + dump_mem (buf, REGISTER_RAW_SIZE (regno)); + } + } +} + + +static void +gdbsim_store_register (regno) +int regno; +{ + if (regno == -1) + { + for (regno = 0; regno < NUM_REGS; regno++) + gdbsim_store_register (regno); + } + else + { + /* FIXME: Until read_register() returns LONGEST, we have this. */ + char tmp[MAX_REGISTER_RAW_SIZE]; + read_register_gen (regno, tmp); + sim_store_register (regno, tmp); + if (sr_get_debug ()) + { + printf_filtered ("gdbsim_store_register: %d", regno); + /* FIXME: We could print something more intelligible. */ + dump_mem (tmp, REGISTER_RAW_SIZE (regno)); + } + } +} + +/* Kill the running program. This may involve closing any open files + and releasing other resources acquired by the simulated program. */ + +static void +gdbsim_kill () +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_kill\n"); + + sim_kill (); /* close fd's, remove mappings */ + inferior_pid = 0; +} + +/* Load an executable file into the target process. This is expected to + not only bring new code into the target process, but also to update + GDB's symbol tables to match. */ + +static void +gdbsim_load (prog, fromtty) + char *prog; + int fromtty; +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_load: prog \"%s\"\n", prog); + + inferior_pid = 0; + + /* This must be done before calling gr_load_image. */ + program_loaded = 1; + + if (sim_load (prog, fromtty) != 0) + generic_load (prog, fromtty); +} + + +/* Start an inferior process and set inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). + On VxWorks and various standalone systems, we ignore exec_file. */ +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ + +static void +gdbsim_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + int len; + char *arg_buf,**argv; + CORE_ADDR entry_pt; + + if (! program_loaded) + error ("No program loaded."); + + if (sr_get_debug ()) + printf_filtered ("gdbsim_create_inferior: exec_file \"%s\", args \"%s\"\n", + exec_file, args); + + if (exec_file == 0 || exec_bfd == 0) + error ("No exec file specified."); + + entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd); + + gdbsim_kill (NULL, NULL); + remove_breakpoints (); + init_wait_for_inferior (); + + len = 5 + strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10; + arg_buf = (char *) alloca (len); + arg_buf[0] = '\0'; + strcat (arg_buf, exec_file); + strcat (arg_buf, " "); + strcat (arg_buf, args); + argv = buildargv (arg_buf); + make_cleanup (freeargv, (char *) argv); + sim_create_inferior (entry_pt, argv, env); + + inferior_pid = 42; + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* The open routine takes the rest of the parameters from the command, + and (if successful) pushes a new target onto the stack. + Targets should supply this routine, if only to provide an error message. */ +/* Called when selecting the simulator. EG: (gdb) target sim name. */ + +static void +gdbsim_open (args, from_tty) + char *args; + int from_tty; +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_open: args \"%s\"\n", args ? args : "(null)"); + + sim_set_callbacks (&default_callback); + default_callback.init (&default_callback); + + sim_open (args); + + push_target (&gdbsim_ops); + target_fetch_registers (-1); + printf_filtered ("Connected to the simulator.\n"); +} + +/* Does whatever cleanup is required for a target that we are no longer + going to be calling. Argument says whether we are quitting gdb and + should not get hung in case of errors, or whether we want a clean + termination even if it takes a while. This routine is automatically + always called just before a routine is popped off the target stack. + Closing file descriptors and freeing memory are typical things it should + do. */ +/* Close out all files and local state before this target loses control. */ + +static void +gdbsim_close (quitting) + int quitting; +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_close: quitting %d\n", quitting); + + program_loaded = 0; + + sim_close (quitting); +} + +/* Takes a program previously attached to and detaches it. + The program may resume execution (some targets do, some don't) and will + no longer stop on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. ARGS is arguments + typed by the user (e.g. a signal to send the process). FROM_TTY + says whether to be verbose or not. */ +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else with your gdb. */ + +static void +gdbsim_detach (args,from_tty) + char *args; + int from_tty; +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_detach: args \"%s\"\n", args); + + pop_target (); /* calls gdbsim_close to do the real work */ + if (from_tty) + printf_filtered ("Ending simulator %s debugging\n", target_shortname); +} + +/* Resume execution of the target process. STEP says whether to single-step + or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given + to the target, or zero for no signal. */ + +static void +gdbsim_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_resume: step %d, signal %d\n", step, siggnal); + + sim_resume (step, target_signal_to_host (siggnal)); +} + +/* Wait for inferior process to do something. Return pid of child, + or -1 in case of error; store status through argument pointer STATUS, + just as `wait' would. */ + +static int +gdbsim_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int sigrc; + enum sim_stop reason; + + if (sr_get_debug ()) + printf_filtered ("gdbsim_wait\n"); + + sim_stop_reason (&reason, &sigrc); + switch (reason) + { + case sim_exited: + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = sigrc; + break; + case sim_stopped: + status->kind = TARGET_WAITKIND_STOPPED; + /* The signal in sigrc is a host signal. That probably + should be fixed. */ + status->value.sig = target_signal_from_host (sigrc); + break; + case sim_signalled: + status->kind = TARGET_WAITKIND_SIGNALLED; + /* The signal in sigrc is a host signal. That probably + should be fixed. */ + status->value.sig = target_signal_from_host (sigrc); + break; + } + + return inferior_pid; +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +gdbsim_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static int +gdbsim_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (! program_loaded) + error ("No program loaded."); + + if (sr_get_debug ()) + { + printf_filtered ("gdbsim_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n", + myaddr, memaddr, len, write); + if (sr_get_debug () && write) + dump_mem(myaddr, len); + } + + if (write) + { + len = sim_write (memaddr, myaddr, len); + } + else + { + len = sim_read (memaddr, myaddr, len); + if (sr_get_debug () && len > 0) + dump_mem(myaddr, len); + } + return len; +} + +static void +gdbsim_files_info (target) + struct target_ops *target; +{ + char *file = "nothing"; + + if (exec_bfd) + file = bfd_get_filename (exec_bfd); + + if (sr_get_debug ()) + printf_filtered ("gdbsim_files_info: file \"%s\"\n", file); + + if (exec_bfd) + { + printf_filtered ("\tAttached to %s running program %s\n", + target_shortname, file); + sim_info (0); + } +} + +/* Clear the simulator's notion of what the break points are. */ + +static void +gdbsim_mourn_inferior () +{ + if (sr_get_debug ()) + printf_filtered ("gdbsim_mourn_inferior:\n"); + + remove_breakpoints (); + generic_mourn_inferior (); +} + +/* Put a command string, in args, out to MONITOR. Output from MONITOR + is placed on the users terminal until the prompt is seen. FIXME: We + read the characters ourseleves here cause of a nasty echo. */ + +static void +simulator_command (args, from_tty) + char *args; + int from_tty; +{ + sim_do_command (args); +} + +/* Define the target subroutine names */ + +struct target_ops gdbsim_ops = { + "sim", /* to_shortname */ + "simulator", /* to_longname */ + "Use the compiled-in simulator.", /* to_doc */ + gdbsim_open, /* to_open */ + gdbsim_close, /* to_close */ + NULL, /* to_attach */ + gdbsim_detach, /* to_detach */ + gdbsim_resume, /* to_resume */ + gdbsim_wait, /* to_wait */ + gdbsim_fetch_register, /* to_fetch_registers */ + gdbsim_store_register, /* to_store_registers */ + gdbsim_prepare_to_store, /* to_prepare_to_store */ + gdbsim_xfer_inferior_memory, /* to_xfer_memory */ + gdbsim_files_info, /* to_files_info */ + memory_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + gdbsim_kill, /* to_kill */ + gdbsim_load, /* to_load */ + NULL, /* to_lookup_symbol */ + gdbsim_create_inferior, /* to_create_inferior */ + gdbsim_mourn_inferior, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC, /* to_magic */ +}; + +void +_initialize_remote_sim () +{ + add_target (&gdbsim_ops); + + add_com ("sim ", class_obscure, simulator_command, + "Send a command to the simulator."); +} diff --git a/contrib/gdb/gdb/remote-sim.h b/contrib/gdb/gdb/remote-sim.h new file mode 100644 index 000000000000..8c106a29262a --- /dev/null +++ b/contrib/gdb/gdb/remote-sim.h @@ -0,0 +1,142 @@ +/* This file defines the interface between the simulator and gdb. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (REMOTE_SIM_H) +#define REMOTE_SIM_H 1 + +#include "callback.h" +/* This file is used when building stand-alone simulators, so isolate this + file from gdb. */ + +/* Pick up CORE_ADDR_TYPE if defined (from gdb), otherwise use same value as + gdb does (unsigned int - from defs.h). */ + +#ifndef CORE_ADDR_TYPE +typedef unsigned int SIM_ADDR; +#else +typedef CORE_ADDR_TYPE SIM_ADDR; +#endif + +/* Callbacks. + The simulator may use the following callbacks (gdb routines) which the + standalone program must provide. + + void printf_filtered (char *msg, ...); + void error /-* noreturn *-/ (char *msg, ...); + void *xmalloc (long size); + int sim_callback_write_stdout (char *, int len); + + The new way of doing I/O is to use the pointer provided by GDB + via the sim_set_callbacks call, look in callbacks.c to see what + can be done. +*/ + +/* Main simulator entry points ... + + All functions that can get an error must call the gdb routine `error', + they can only return upon success. */ + +/* Initialize the simulator. This function is called when the simulator + is selected from the command line. ARGS is passed from the command line + and can be used to select whatever run time options the simulator provides. + ARGS is the raw character string and must be parsed by the simulator, + which is trivial to do with the buildargv function in libiberty. + It is ok to do nothing. */ + +void sim_open PARAMS ((char *args)); + +/* Terminate usage of the simulator. This may involve freeing target memory + and closing any open files and mmap'd areas. You cannot assume sim_kill + has already been called. + QUITTING is non-zero if we cannot hang on errors. */ + +void sim_close PARAMS ((int quitting)); + +/* Load program PROG into the simulator. + Return non-zero if you wish the caller to handle it + (it is done this way because most simulators can use gr_load_image, + but defining it as a callback seems awkward). */ + +int sim_load PARAMS ((char *prog, int from_tty)); + +/* Prepare to run the simulated program. + START_ADDRESS is, yes, you guessed it, the start address of the program. + ARGV and ENV are NULL terminated lists of pointers. + Gdb will set the start address via sim_store_register as well, but + standalone versions of existing simulators are not set up to cleanly call + sim_store_register, so the START_ADDRESS argument is there as a + workaround. */ + +void sim_create_inferior PARAMS ((SIM_ADDR start_address, + char **argv, char **env)); + +/* Kill the running program. + This may involve closing any open files and deleting any mmap'd areas. */ + +void sim_kill PARAMS ((void)); + +/* Read LENGTH bytes of the simulated program's memory and store in BUF. + Result is number of bytes read, or zero if error. */ + +int sim_read PARAMS ((SIM_ADDR mem, unsigned char *buf, int length)); + +/* Store LENGTH bytes from BUF in the simulated program's memory. + Result is number of bytes write, or zero if error. */ + +int sim_write PARAMS ((SIM_ADDR mem, unsigned char *buf, int length)); + +/* Fetch register REGNO and store the raw value in BUF. */ + +void sim_fetch_register PARAMS ((int regno, unsigned char *buf)); + +/* Store register REGNO from BUF (in raw format). */ + +void sim_store_register PARAMS ((int regno, unsigned char *buf)); + +/* Print some interesting information about the simulator. + VERBOSE is non-zero for the wordy version. */ + +void sim_info PARAMS ((int verbose)); + +/* Fetch why the program stopped. + SIGRC will contain either the argument to exit() or the signal number. */ + +enum sim_stop { sim_exited, sim_stopped, sim_signalled }; + +void sim_stop_reason PARAMS ((enum sim_stop *reason, int *sigrc)); + +/* Run (or resume) the program. */ + +void sim_resume PARAMS ((int step, int siggnal)); + +/* Passthru for other commands that the simulator might support. */ + +void sim_do_command PARAMS ((char *cmd)); + + +/* Callbacks for the simulator to use. */ + +int sim_callback_write_stdout PARAMS ((char *, int)); + +/* Provide simulator with a standard host_callback_struct. */ + +void sim_set_callbacks PARAMS ((struct host_callback_struct *)); + + +#endif /* !defined (REMOTE_SIM_H) */ diff --git a/contrib/gdb/gdb/remote-st.c b/contrib/gdb/gdb/remote-st.c new file mode 100644 index 000000000000..117501d83a31 --- /dev/null +++ b/contrib/gdb/gdb/remote-st.c @@ -0,0 +1,847 @@ +/* Remote debugging interface for Tandem ST2000 phone switch, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file was derived from remote-eb.c, which did a similar job, but for + an AMD-29K running EBMON. That file was in turn derived from remote.c + as mentioned in the following comment (left in for comic relief): + + "This is like remote.c but is for an esoteric situation-- + having an a29k board in a PC hooked up to a unix machine with + a serial line, and running ctty com1 on the PC, through which + the unix machine can run ebmon. Not to mention that the PC + has PC/NFS, so it can access the same executables that gdb can, + over the net in real time." + + In reality, this module talks to a debug monitor called 'STDEBUG', which + runs in a phone switch. We communicate with STDEBUG via either a direct + serial line, or a TCP (or possibly TELNET) stream to a terminal multiplexor, + which in turn talks to the phone switch. */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "wait.h" +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include "gdb_string.h" +#include +#include "serial.h" + +extern struct target_ops st2000_ops; /* Forward declaration */ + +static void st2000_close(); +static void st2000_fetch_register(); +static void st2000_store_register(); + +#define LOG_FILE "st2000.log" +#if defined (LOG_FILE) +FILE *log_file; +#endif + +static int timeout = 24; + +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + st2000_open knows that we don't have a file open when the program + starts. */ + +static serial_t st2000_desc; + +/* Send data to stdebug. Works just like printf. */ + +static void +#ifdef ANSI_PROTOTYPES +printf_stdebug(char *pattern, ...) +#else +printf_stdebug(va_alist) + va_dcl +#endif +{ + va_list args; + char buf[200]; + +#ifdef ANSI_PROTOTYPES + va_start(args, pattern); +#else + char *pattern; + va_start(args); + pattern = va_arg(args, char *); +#endif + + vsprintf(buf, pattern, args); + va_end(args); + + if (SERIAL_WRITE(st2000_desc, buf, strlen(buf))) + fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno)); +} + +/* Read a character from the remote system, doing all the fancy timeout + stuff. */ + +static int +readchar(timeout) + int timeout; +{ + int c; + + c = SERIAL_READCHAR(st2000_desc, timeout); + +#ifdef LOG_FILE + putc(c & 0x7f, log_file); +#endif + + if (c >= 0) + return c & 0x7f; + + if (c == SERIAL_TIMEOUT) + { + if (timeout == 0) + return c; /* Polls shouldn't generate timeout errors */ + + error("Timeout reading from remote system."); + } + + perror_with_name("remote-st2000"); +} + +/* Scan input from the remote system, until STRING is found. If DISCARD is + non-zero, then discard non-matching input, else print it out. + Let the user break out immediately. */ +static void +expect(string, discard) + char *string; + int discard; +{ + char *p = string; + int c; + + immediate_quit = 1; + while (1) + { + c = readchar(timeout); + if (c == *p++) + { + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + { + if (!discard) + { + fwrite(string, 1, (p - 1) - string, stdout); + putchar((char)c); + fflush(stdout); + } + p = string; + } + } +} + +/* Keep discarding input until we see the STDEBUG prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an expect_prompt(). Exception: st2000_resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a st2000_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ +static void +expect_prompt(discard) + int discard; +{ +#if defined (LOG_FILE) + /* This is a convenient place to do this. The idea is to do it often + enough that we never lose much data if we terminate abnormally. */ + fflush(log_file); +#endif + expect ("dbug> ", discard); +} + +/* Get a hex digit from the remote system & return its value. + If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ +static int +get_hex_digit(ignore_space) + int ignore_space; +{ + int ch; + while (1) + { + ch = readchar(timeout); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch == ' ' && ignore_space) + ; + else + { + expect_prompt(1); + error("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from stdebug and put it in *BYT. Accept any number + leading spaces. */ +static void +get_hex_byte (byt) + char *byt; +{ + int val; + + val = get_hex_digit (1) << 4; + val |= get_hex_digit (0); + *byt = val; +} + +/* Get N 32-bit words from remote, each preceded by a space, + and put them in registers starting at REGNO. */ +static void +get_hex_regs (n, regno) + int n; + int regno; +{ + long val; + int i; + + for (i = 0; i < n; i++) + { + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + get_hex_digit (j == 0); + supply_register (regno++, (char *) &val); + } +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +static void +st2000_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error("Can't pass arguments to remote STDEBUG process"); + + if (execfile == 0 || exec_bfd == 0) + error("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + +/* The "process" (board) is already stopped awaiting our commands, and + the program is already downloaded. We just set its PC and go. */ + + clear_proceed_status (); + + /* Tell wait_for_inferior that we've started a new process. */ + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* insert_step_breakpoint (); FIXME, do we need this? */ + /* Let 'er rip... */ + proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static int baudrate = 9600; +static char dev_name[100]; + +static void +st2000_open(args, from_tty) + char *args; + int from_tty; +{ + int n; + char junk[100]; + + target_preopen(from_tty); + + n = sscanf(args, " %s %d %s", dev_name, &baudrate, junk); + + if (n != 2) + error("Bad arguments. Usage: target st2000 \n\ +or target st2000 \n"); + + st2000_close(0); + + st2000_desc = SERIAL_OPEN(dev_name); + + if (!st2000_desc) + perror_with_name(dev_name); + + SERIAL_SETBAUDRATE(st2000_desc, baudrate); + + SERIAL_RAW(st2000_desc); + + push_target(&st2000_ops); + +#if defined (LOG_FILE) + log_file = fopen (LOG_FILE, "w"); + if (log_file == NULL) + perror_with_name (LOG_FILE); +#endif + + /* Hello? Are you there? */ + printf_stdebug("\003"); /* ^C wakes up dbug */ + + expect_prompt(1); + + if (from_tty) + printf("Remote %s connected to %s\n", target_shortname, + dev_name); +} + +/* Close out all files and local state before this target loses control. */ + +static void +st2000_close (quitting) + int quitting; +{ + SERIAL_CLOSE(st2000_desc); + +#if defined (LOG_FILE) + if (log_file) { + if (ferror(log_file)) + fprintf(stderr, "Error writing log file.\n"); + if (fclose(log_file) != 0) + fprintf(stderr, "Error closing log file.\n"); + } +#endif +} + +/* Terminate the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ +static void +st2000_detach (from_tty) + int from_tty; +{ + pop_target(); /* calls st2000_close to do the real work */ + if (from_tty) + printf ("Ending remote %s debugging\n", target_shortname); +} + +/* Tell the remote machine to resume. */ + +static void +st2000_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + if (step) + { + printf_stdebug ("ST\r"); + /* Wait for the echo. */ + expect ("ST\r", 1); + } + else + { + printf_stdebug ("GO\r"); + /* Swallow the echo. */ + expect ("GO\r", 1); + } +} + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +static int +st2000_wait (status) + struct target_waitstatus *status; +{ + int old_timeout = timeout; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + timeout = 0; /* Don't time out -- user program is running. */ + + expect_prompt(0); /* Wait for prompt, outputting extraneous text */ + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + + timeout = old_timeout; + + return 0; +} + +/* Return the name of register number REGNO in the form input and output by + STDEBUG. Currently, REGISTER_NAMES just happens to contain exactly what + STDEBUG wants. Lets take advantage of that just as long as possible! */ + +static char * +get_reg_name (regno) + int regno; +{ + static char buf[50]; + const char *p; + char *b; + + b = buf; + + for (p = reg_names[regno]; *p; p++) + *b++ = toupper(*p); + *b = '\000'; + + return buf; +} + +/* Read the remote registers into the block REGS. */ + +static void +st2000_fetch_registers () +{ + int regno; + + /* Yeah yeah, I know this is horribly inefficient. But it isn't done + very often... I'll clean it up later. */ + + for (regno = 0; regno <= PC_REGNUM; regno++) + st2000_fetch_register(regno); +} + +/* Fetch register REGNO, or all registers if REGNO is -1. + Returns errno value. */ +static void +st2000_fetch_register (regno) + int regno; +{ + if (regno == -1) + st2000_fetch_registers (); + else + { + char *name = get_reg_name (regno); + printf_stdebug ("DR %s\r", name); + expect (name, 1); + expect (" : ", 1); + get_hex_regs (1, regno); + expect_prompt (1); + } + return; +} + +/* Store the remote registers from the contents of the block REGS. */ + +static void +st2000_store_registers () +{ + int regno; + + for (regno = 0; regno <= PC_REGNUM; regno++) + st2000_store_register(regno); + + registers_changed (); +} + +/* Store register REGNO, or all if REGNO == 0. + Return errno value. */ +static void +st2000_store_register (regno) + int regno; +{ + if (regno == -1) + st2000_store_registers (); + else + { + printf_stdebug ("PR %s %x\r", get_reg_name (regno), + read_register (regno)); + + expect_prompt (1); + } +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +st2000_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +static void +st2000_files_info () +{ + printf ("\tAttached to %s at %d baud.\n", + dev_name, baudrate); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns length moved. */ +static int +st2000_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + unsigned char *myaddr; + int len; +{ + int i; + + for (i = 0; i < len; i++) + { + printf_stdebug ("PM.B %x %x\r", memaddr + i, myaddr[i]); + expect_prompt (1); + } + return len; +} + +/* Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns length moved. */ +static int +st2000_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int i; + + /* Number of bytes read so far. */ + int count; + + /* Starting address of this pass. */ + unsigned long startaddr; + + /* Number of bytes to read in this pass. */ + int len_this_pass; + + /* Note that this code works correctly if startaddr is just less + than UINT_MAX (well, really CORE_ADDR_MAX if there was such a + thing). That is, something like + st2000_read_bytes (CORE_ADDR_MAX - 4, foo, 4) + works--it never adds len to memaddr and gets 0. */ + /* However, something like + st2000_read_bytes (CORE_ADDR_MAX - 3, foo, 4) + doesn't need to work. Detect it and give up if there's an attempt + to do that. */ + if (((memaddr - 1) + len) < memaddr) { + errno = EIO; + return 0; + } + + startaddr = memaddr; + count = 0; + while (count < len) + { + len_this_pass = 16; + if ((startaddr % 16) != 0) + len_this_pass -= startaddr % 16; + if (len_this_pass > (len - count)) + len_this_pass = (len - count); + + printf_stdebug ("DI.L %x %x\r", startaddr, len_this_pass); + expect (": ", 1); + + for (i = 0; i < len_this_pass; i++) + get_hex_byte (&myaddr[count++]); + + expect_prompt (1); + + startaddr += len_this_pass; + } + return len; +} + +/* FIXME-someday! Merge these two. */ +static int +st2000_xfer_inferior_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + if (write) + return st2000_write_inferior_memory (memaddr, myaddr, len); + else + return st2000_read_inferior_memory (memaddr, myaddr, len); +} + +static void +st2000_kill (args, from_tty) + char *args; + int from_tty; +{ + return; /* Ignore attempts to kill target system */ +} + +/* Clean up when a program exits. + + The program actually lives on in the remote processor's RAM, and may be + run again without a download. Don't leave it full of breakpoint + instructions. */ + +static void +st2000_mourn_inferior () +{ + remove_breakpoints (); + unpush_target (&st2000_ops); + generic_mourn_inferior (); /* Do all the proper things now */ +} + +#define MAX_STDEBUG_BREAKPOINTS 16 + +extern int memory_breakpoint_size; +static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] = {0}; + +static int +st2000_insert_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++) + if (breakaddr[i] == 0) + { + breakaddr[i] = addr; + + st2000_read_inferior_memory(addr, shadow, memory_breakpoint_size); + printf_stdebug("BR %x H\r", addr); + expect_prompt(1); + return 0; + } + + fprintf(stderr, "Too many breakpoints (> 16) for STDBUG\n"); + return 1; +} + +static int +st2000_remove_breakpoint (addr, shadow) + CORE_ADDR addr; + char *shadow; +{ + int i; + + for (i = 0; i < MAX_STDEBUG_BREAKPOINTS; i++) + if (breakaddr[i] == addr) + { + breakaddr[i] = 0; + + printf_stdebug("CB %d\r", i); + expect_prompt(1); + return 0; + } + + fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr); + return 1; +} + + +/* Put a command string, in args, out to STDBUG. Output from STDBUG is placed + on the users terminal until the prompt is seen. */ + +static void +st2000_command (args, fromtty) + char *args; + int fromtty; +{ + if (!st2000_desc) + error("st2000 target not open."); + + if (!args) + error("Missing command."); + + printf_stdebug("%s\r", args); + expect_prompt(0); +} + +/* Connect the user directly to STDBUG. This command acts just like the + 'cu' or 'tip' command. Use ~. or ~^D to break out. */ + +/*static struct ttystate ttystate;*/ + +static void +cleanup_tty() +{ + printf("\r\n[Exiting connect mode]\r\n"); +/* SERIAL_RESTORE(0, &ttystate);*/ +} + +#if 0 +/* This all should now be in serial.c */ + +static void +connect_command (args, fromtty) + char *args; + int fromtty; +{ + fd_set readfds; + int numfds; + int c; + char cur_esc = 0; + + dont_repeat(); + + if (st2000_desc < 0) + error("st2000 target not open."); + + if (args) + fprintf("This command takes no args. They have been ignored.\n"); + + printf("[Entering connect mode. Use ~. or ~^D to escape]\n"); + + serial_raw(0, &ttystate); + + make_cleanup(cleanup_tty, 0); + + FD_ZERO(&readfds); + + while (1) + { + do + { + FD_SET(0, &readfds); + FD_SET(st2000_desc, &readfds); + numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0); + } + while (numfds == 0); + + if (numfds < 0) + perror_with_name("select"); + + if (FD_ISSET(0, &readfds)) + { /* tty input, send to stdebug */ + c = getchar(); + if (c < 0) + perror_with_name("connect"); + + printf_stdebug("%c", c); + 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 (FD_ISSET(st2000_desc, &readfds)) + { + while (1) + { + c = readchar(0); + if (c < 0) + break; + putchar(c); + } + fflush(stdout); + } + } +} +#endif /* 0 */ + +/* Define the target subroutine names */ + +struct target_ops st2000_ops = { + "st2000", + "Remote serial Tandem ST2000 target", + "Use a remote computer running STDEBUG connected by a serial line,\n\ +or a network connection.\n\ +Arguments are the name of the device for the serial line,\n\ +the speed to connect at in bits per second.", + st2000_open, + st2000_close, + 0, + st2000_detach, + st2000_resume, + st2000_wait, + st2000_fetch_register, + st2000_store_register, + st2000_prepare_to_store, + st2000_xfer_inferior_memory, + st2000_files_info, + st2000_insert_breakpoint, + st2000_remove_breakpoint, /* Breakpoints */ + 0, + 0, + 0, + 0, + 0, /* Terminal handling */ + st2000_kill, + 0, /* load */ + 0, /* lookup_symbol */ + st2000_create_inferior, + st2000_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_stop */ + process_stratum, + 0, /* next */ + 1, + 1, + 1, + 1, + 1, /* all mem, mem, stack, regs, exec */ + 0, + 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_st2000 () +{ + add_target (&st2000_ops); + add_com ("st2000 ", class_obscure, st2000_command, + "Send a command to the STDBUG monitor."); + add_com ("connect", class_obscure, connect_command, + "Connect the terminal directly up to the STDBUG command monitor.\n\ +Use ~. or ~^D to break out."); +} diff --git a/contrib/gdb/gdb/remote-udi.c b/contrib/gdb/gdb/remote-udi.c new file mode 100644 index 000000000000..951202317a96 --- /dev/null +++ b/contrib/gdb/gdb/remote-udi.c @@ -0,0 +1,1689 @@ +/* Remote debugging interface for AMD 29k interfaced via UDI, for GDB. + Copyright 1990, 1992, 1995 Free Software Foundation, Inc. + Written by Daniel Mann. Contributed by AMD. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is like remote.c but uses the Universal Debug Interface (UDI) to + talk to the target hardware (or simulator). UDI is a TCP/IP based + protocol; for hardware that doesn't run TCP, an interface adapter + daemon talks UDI on one side, and talks to the hardware (typically + over a serial port) on the other side. + + - Originally written by Daniel Mann at AMD for MiniMON and gdb 3.91.6. + - David Wood (wood@lab.ultra.nyu.edu) at New York University adapted this + file to gdb 3.95. I was unable to get this working on sun3os4 + with termio, only with sgtty. + - Daniel Mann at AMD took the 3.95 adaptions above and replaced + MiniMON interface with UDI-p interface. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "value.h" +#include +#include +#include +#include +#include "gdb_string.h" +#include "terminal.h" +#include "target.h" +#include "29k-share/udi/udiproc.h" +#include "gdbcmd.h" +#include "bfd.h" +#include "gdbcore.h" /* For download function */ + +/* access the register store directly, without going through + the normal handler functions. This avoids an extra data copy. */ + +extern int stop_soon_quietly; /* for wait_for_inferior */ +extern struct value *call_function_by_hand(); +static void udi_resume PARAMS ((int pid, int step, enum target_signal sig)); +static void udi_fetch_registers PARAMS ((int regno)); +static void udi_load PARAMS ((char *args, int from_tty)); +static void fetch_register PARAMS ((int regno)); +static void udi_store_registers PARAMS ((int regno)); +static int store_register PARAMS ((int regno)); +static int regnum_to_srnum PARAMS ((int regno)); +static void udi_close PARAMS ((int quitting)); +static CPUSpace udi_memory_space PARAMS ((CORE_ADDR addr)); +static int udi_write_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len)); +static int udi_read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len)); +static void download PARAMS ((char *load_arg_string, int from_tty)); +char CoffFileName[100] = ""; + +#define FREEZE_MODE (read_register(CPS_REGNUM) & 0x400) +#define USE_SHADOW_PC ((processor_type == a29k_freeze_mode) && FREEZE_MODE) + +static int timeout = 5; +extern struct target_ops udi_ops; /* Forward declaration */ + +/* Special register enumeration. +*/ + +/******************************************************************* UDI DATA*/ +#define MAXDATA 2*1024 /* max UDI[read/write] byte size */ +/* Descriptor for I/O to remote machine. Initialize it to -1 so that + udi_open knows that we don't have a file open when the program + starts. */ + +UDISessionId udi_session_id = -1; +static char *udi_config_id; + +CPUOffset IMemStart = 0; +CPUSizeT IMemSize = 0; +CPUOffset DMemStart = 0; +CPUSizeT DMemSize = 0; +CPUOffset RMemStart = 0; +CPUSizeT RMemSize = 0; +UDIUInt32 CPUPRL; +UDIUInt32 CoProcPRL; + +UDIMemoryRange address_ranges[2]; /* Text and data */ +UDIResource entry = {0, 0}; /* Entry point */ +CPUSizeT stack_sizes[2]; /* Regular and memory stacks */ + +#define SBUF_MAX 1024 /* maximum size of string handling buffer */ +char sbuf[SBUF_MAX]; + +typedef struct bkpt_entry_str +{ + UDIResource Addr; + UDIUInt32 PassCount; + UDIBreakType Type; + unsigned int BreakId; +} bkpt_entry_t; +#define BKPT_TABLE_SIZE 40 +static bkpt_entry_t bkpt_table[BKPT_TABLE_SIZE]; +extern char dfe_errmsg[]; /* error string */ + +/* malloc'd name of the program on the remote system. */ +static char *prog_name = NULL; + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ + +static void +udi_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + char *args1; + + if (execfile) + { + if (prog_name != NULL) + free (prog_name); + prog_name = savestring (execfile, strlen (execfile)); + } + else if (entry.Offset) + execfile = ""; + else + error ("No image loaded into target."); + + if (udi_session_id < 0) + { + /* If the TIP is not open, open it. */ + if (UDIConnect (udi_config_id, &udi_session_id)) + error("UDIConnect() failed: %s\n", dfe_errmsg); + /* We will need to download the program. */ + entry.Offset = 0; + } + + inferior_pid = 40000; + + if (!entry.Offset) + download(execfile, 0); + + args1 = alloca (strlen(execfile) + strlen(args) + 2); + + if (execfile[0] == '\0') + + /* It is empty. We need to quote it somehow, or else the target + will think there is no argument being passed here. According + to the UDI spec it is quoted "according to TIP OS rules" which + I guess means quoting it like the Unix shell should work + (sounds pretty bogus to me...). In fact it doesn't work (with + isstip anyway), but passing in two quotes as the argument seems + like a reasonable enough behavior anyway (I guess). */ + + strcpy (args1, "''"); + else + strcpy (args1, execfile); + strcat (args1, " "); + strcat (args1, args); + + UDIInitializeProcess (address_ranges, /* ProcessMemory[] */ + (UDIInt)2, /* NumberOfRanges */ + entry, /* EntryPoint */ + stack_sizes, /* *StackSizes */ + (UDIInt)2, /* NumberOfStacks */ + args1); /* ArgString */ + + init_wait_for_inferior (); + clear_proceed_status (); + proceed (-1, TARGET_SIGNAL_DEFAULT, 0); +} + +static void +udi_mourn() +{ +#if 0 + /* Requiring "target udi" each time you run is a major pain. I suspect + this was just blindy copied from remote.c, in which "target" and + "run" are combined. Having a udi target without an inferior seems + to work between "target udi" and "run", so why not now? */ + pop_target (); /* Pop back to no-child state */ +#endif + /* But if we're going to want to run it again, we better remove the + breakpoints... */ + remove_breakpoints (); + generic_mourn_inferior (); +} + +/******************************************************************** UDI_OPEN +** Open a connection to remote TIP. + NAME is the socket domain used for communication with the TIP, + then a space and the socket name or TIP-host name. + '' for example. + */ + +/* XXX - need cleanups for udiconnect for various failures!!! */ + +static void +udi_open (name, from_tty) + char *name; + int from_tty; +{ + unsigned int prl; + char *p; + int cnt; + UDIMemoryRange KnownMemory[10]; + UDIUInt32 ChipVersions[10]; + UDIInt NumberOfRanges = 10; + UDIInt NumberOfChips = 10; + UDIPId PId; + UDIUInt32 TIPId, TargetId, DFEId, DFE, TIP, DFEIPCId, TIPIPCId; + + target_preopen(from_tty); + + entry.Offset = 0; + + for (cnt = 0; cnt < BKPT_TABLE_SIZE; cnt++) + bkpt_table[cnt].Type = 0; + + if (udi_config_id) + free (udi_config_id); + + if (!name) + error("Usage: target udi config_id, where config_id appears in udi_soc file"); + + udi_config_id = strdup (strtok (name, " \t")); + + if (UDIConnect (udi_config_id, &udi_session_id)) + /* FIXME: Should set udi_session_id to -1 here. */ + error("UDIConnect() failed: %s\n", dfe_errmsg); + + push_target (&udi_ops); + + /* + ** Initialize target configuration structure (global) + */ + if (UDIGetTargetConfig (KnownMemory, &NumberOfRanges, + ChipVersions, &NumberOfChips)) + error ("UDIGetTargetConfig() failed"); + if (NumberOfChips > 2) + fprintf_unfiltered(gdb_stderr,"Target has more than one processor\n"); + for (cnt=0; cnt < NumberOfRanges; cnt++) + { + switch(KnownMemory[cnt].Space) + { + default: + fprintf_unfiltered(gdb_stderr, "UDIGetTargetConfig() unknown memory space\n"); + break; + case UDI29KCP_S: + break; + case UDI29KIROMSpace: + RMemStart = KnownMemory[cnt].Offset; + RMemSize = KnownMemory[cnt].Size; + break; + case UDI29KIRAMSpace: + IMemStart = KnownMemory[cnt].Offset; + IMemSize = KnownMemory[cnt].Size; + break; + case UDI29KDRAMSpace: + DMemStart = KnownMemory[cnt].Offset; + DMemSize = KnownMemory[cnt].Size; + break; + } + } + + a29k_get_processor_type (); + + if (UDICreateProcess (&PId)) + fprintf_unfiltered(gdb_stderr, "UDICreateProcess() failed\n"); + + /* Print out some stuff, letting the user now what's going on */ + if (UDICapabilities (&TIPId, &TargetId, DFEId, DFE, &TIP, &DFEIPCId, + &TIPIPCId, sbuf)) + error ("UDICapabilities() failed"); + if (from_tty) + { + printf_filtered ("Connected via UDI socket,\n\ + DFE-IPC version %x.%x.%x TIP-IPC version %x.%x.%x TIP version %x.%x.%x\n %s\n", + (DFEIPCId>>8)&0xf, (DFEIPCId>>4)&0xf, DFEIPCId&0xf, + (TIPIPCId>>8)&0xf, (TIPIPCId>>4)&0xf, TIPIPCId&0xf, + (TargetId>>8)&0xf, (TargetId>>4)&0xf, TargetId&0xf, + sbuf); + } +} + +/******************************************************************* UDI_CLOSE + Close the open connection to the TIP process. + Use this when you want to detach and do something else + with your gdb. */ +static void +udi_close (quitting) /*FIXME: how is quitting used */ + int quitting; +{ + if (udi_session_id < 0) + return; + + /* We should never get here if there isn't something valid in + udi_session_id. */ + + if (UDIDisconnect (udi_session_id, UDITerminateSession)) + { + if (quitting) + warning ("UDIDisconnect() failed in udi_close"); + else + error ("UDIDisconnect() failed in udi_close"); + } + + /* Do not try to close udi_session_id again, later in the program. */ + udi_session_id = -1; + inferior_pid = 0; + + printf_filtered (" Ending remote debugging\n"); +} + +/**************************************************************** UDI_ATACH */ +/* Attach to a program that is already loaded and running + * Upon exiting the process's execution is stopped. + */ +static void +udi_attach (args, from_tty) + char *args; + int from_tty; +{ + UDIResource From; + UDIInt32 PC_adds; + UDICount Count = 1; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + UDIError err; + + if (args == NULL) + error_no_arg ("program to attach"); + + if (udi_session_id < 0) + error ("UDI connection not opened yet, use the 'target udi' command.\n"); + + if (from_tty) + printf_unfiltered ("Attaching to remote program %s...\n", prog_name); + + UDIStop(); + From.Space = UDI29KSpecialRegs; + From.Offset = 11; + if (err = UDIRead(From, &PC_adds, Count, Size, &CountDone, HostEndian)) + error ("UDIRead failed in udi_attach"); + printf_unfiltered ("Remote process is now halted, pc1 = 0x%x.\n", PC_adds); +} +/************************************************************* UDI_DETACH */ +/* Terminate the open connection to the TIP process. + Use this when you want to detach and do something else + with your gdb. Leave remote process running (with no breakpoints set). */ +static void +udi_detach (args,from_tty) + char *args; + int from_tty; +{ + + remove_breakpoints(); /* Just in case there were any left in */ + + if (UDIDisconnect (udi_session_id, UDIContinueSession)) + error ("UDIDisconnect() failed in udi_detach"); + + /* Don't try to UDIDisconnect it again in udi_close, which is called from + pop_target. */ + udi_session_id = -1; + inferior_pid = 0; + + pop_target(); + + if (from_tty) + printf_unfiltered ("Detaching from TIP\n"); +} + + +/****************************************************************** UDI_RESUME +** Tell the remote machine to resume. */ + +static void +udi_resume (pid, step, sig) + int pid, step; + enum target_signal sig; +{ + UDIError tip_error; + UDIUInt32 Steps = 1; + UDIStepType StepType = UDIStepNatural; + UDIRange Range; + + if (step) /* step 1 instruction */ + { + tip_error = UDIStep (Steps, StepType, Range); + if (!tip_error) + return; + + fprintf_unfiltered (gdb_stderr, "UDIStep() error = %d\n", tip_error); + error ("failed in udi_resume"); + } + + if (UDIExecute()) + error ("UDIExecute() failed in udi_resume"); +} + +/******************************************************************** UDI_WAIT +** Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. */ + +static int +udi_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + UDIInt32 MaxTime; + UDIPId PId; + UDIInt32 StopReason; + UDISizeT CountDone; + int old_timeout = timeout; + int old_immediate_quit = immediate_quit; + int i; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + +/* wait for message to arrive. It should be: + If the target stops executing, udi_wait() should return. +*/ + timeout = 0; /* Wait indefinetly for a message */ + immediate_quit = 1; /* Helps ability to QUIT */ + + while(1) + { + i = 0; + MaxTime = UDIWaitForever; + UDIWait(MaxTime, &PId, &StopReason); + QUIT; /* Let user quit if they want */ + + switch (StopReason & UDIGrossState) + { + case UDIStdoutReady: + if (UDIGetStdout (sbuf, (UDISizeT)SBUF_MAX, &CountDone)) + /* This is said to happen if the program tries to output + a whole bunch of output (more than SBUF_MAX, I would + guess). It doesn't seem to happen with the simulator. */ + warning ("UDIGetStdout() failed in udi_wait"); + fwrite (sbuf, 1, CountDone, gdb_stdout); + gdb_flush(gdb_stdout); + continue; + + case UDIStderrReady: + UDIGetStderr (sbuf, (UDISizeT)SBUF_MAX, &CountDone); + fwrite (sbuf, 1, CountDone, gdb_stderr); + gdb_flush(gdb_stderr); + continue; + + case UDIStdinNeeded: + { + int ch; + i = 0; + do + { + ch = getchar (); + if (ch == EOF) + break; + sbuf[i++] = ch; + } while (i < SBUF_MAX && ch != '\n'); + UDIPutStdin (sbuf, (UDISizeT)i, &CountDone); + continue; + } + + case UDIRunning: + /* In spite of the fact that we told UDIWait to wait forever, it will + return spuriously sometimes. */ + case UDIStdinModeX: + continue; + default: + break; + } + break; + } + + switch (StopReason & UDIGrossState) + { + case UDITrapped: + printf_unfiltered("Am290*0 received vector number %d\n", StopReason >> 24); + + switch ((StopReason >> 8 ) & 0xff) + { + case 0: /* Illegal opcode */ + printf_unfiltered(" (break point)\n"); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 1: /* Unaligned Access */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_BUS; + break; + case 3: + case 4: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_FPE; + break; + case 5: /* Protection Violation */ + status->kind = TARGET_WAITKIND_STOPPED; + /* Why not SEGV? What is a Protection Violation? */ + status->value.sig = TARGET_SIGNAL_ILL; + break; + case 6: + case 7: + case 8: /* User Instruction Mapping Miss */ + case 9: /* User Data Mapping Miss */ + case 10: /* Supervisor Instruction Mapping Miss */ + case 11: /* Supervisor Data Mapping Miss */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_SEGV; + break; + case 12: + case 13: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ILL; + break; + case 14: /* Timer */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_ALRM; + break; + case 15: /* Trace */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 16: /* INTR0 */ + case 17: /* INTR1 */ + case 18: /* INTR2 */ + case 19: /* INTR3/Internal */ + case 20: /* TRAP0 */ + case 21: /* TRAP1 */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_INT; + break; + case 22: /* Floating-Point Exception */ + status->kind = TARGET_WAITKIND_STOPPED; + /* Why not FPE? */ + status->value.sig = TARGET_SIGNAL_ILL; + break; + case 77: /* assert 77 */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + default: + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + } + break; + case UDINotExecuting: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TERM; + break; + case UDIStopped: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TSTP; + break; + case UDIWarned: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_URG; + break; + case UDIStepped: + case UDIBreak: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case UDIWaiting: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_STOP; + break; + case UDIHalted: + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_KILL; + break; + case UDIExited: + default: + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + } + + timeout = old_timeout; /* Restore original timeout value */ + immediate_quit = old_immediate_quit; + return inferior_pid; +} + +#if 0 +/* Handy for debugging */ +udi_pc() +{ + UDIResource From; + UDIUInt32 *To; + UDICount Count; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + UDIError err; + int pc[2]; + unsigned long myregs[256]; + int i; + + From.Space = UDI29KPC; + From.Offset = 0; + To = (UDIUInt32 *)pc; + Count = 2; + + err = UDIRead(From, To, Count, Size, &CountDone, HostEndian); + + printf_unfiltered ("err = %d, CountDone = %d, pc[0] = 0x%x, pc[1] = 0x%x\n", + err, CountDone, pc[0], pc[1]); + + udi_fetch_registers(-1); + + printf_unfiltered("other pc1 = 0x%x, pc0 = 0x%x\n", *(int *)®isters[4 * PC_REGNUM], + *(int *)®isters[4 * NPC_REGNUM]); + + /* Now, read all the registers globally */ + + From.Space = UDI29KGlobalRegs; + From.Offset = 0; + err = UDIRead(From, myregs, 256, 4, &CountDone, HostEndian); + + printf ("err = %d, CountDone = %d\n", err, CountDone); + + printf("\n"); + + for (i = 0; i < 256; i += 2) + printf("%d:\t%#10x\t%11d\t%#10x\t%11d\n", i, myregs[i], myregs[i], + myregs[i+1], myregs[i+1]); + printf("\n"); + + return pc[0]; +} +#endif + +/********************************************************** UDI_FETCH_REGISTERS + * Read a remote register 'regno'. + * If regno==-1 then read all the registers. + */ +static void +udi_fetch_registers (regno) +int regno; +{ + UDIResource From; + UDIUInt32 *To; + UDICount Count; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + UDIError err; + int i; + + if (regno >= 0) { + fetch_register(regno); + return; + } + +/* Gr1/rsp */ + + From.Space = UDI29KGlobalRegs; + From.Offset = 1; + To = (UDIUInt32 *)®isters[4 * GR1_REGNUM]; + Count = 1; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + register_valid[GR1_REGNUM] = 1; + +#if defined(GR64_REGNUM) /* Read gr64-127 */ + +/* Global Registers gr64-gr95 */ + + From.Space = UDI29KGlobalRegs; + From.Offset = 64; + To = (UDIUInt32 *)®isters[4 * GR64_REGNUM]; + Count = 32; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + for (i = GR64_REGNUM; i < GR64_REGNUM + 32; i++) + register_valid[i] = 1; + +#endif /* GR64_REGNUM */ + +/* Global Registers gr96-gr127 */ + + From.Space = UDI29KGlobalRegs; + From.Offset = 96; + To = (UDIUInt32 *)®isters[4 * GR96_REGNUM]; + Count = 32; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + for (i = GR96_REGNUM; i < GR96_REGNUM + 32; i++) + register_valid[i] = 1; + +/* Local Registers */ + + From.Space = UDI29KLocalRegs; + From.Offset = 0; + To = (UDIUInt32 *)®isters[4 * LR0_REGNUM]; + Count = 128; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + for (i = LR0_REGNUM; i < LR0_REGNUM + 128; i++) + register_valid[i] = 1; + +/* Protected Special Registers */ + + From.Space = UDI29KSpecialRegs; + From.Offset = 0; + To = (UDIUInt32 *)®isters[4 * SR_REGNUM(0)]; + Count = 15; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + for (i = SR_REGNUM(0); i < SR_REGNUM(0) + 15; i++) + register_valid[i] = 1; + + if (USE_SHADOW_PC) { /* Let regno_to_srnum() handle the register number */ + fetch_register(NPC_REGNUM); + fetch_register(PC_REGNUM); + fetch_register(PC2_REGNUM); + +/* Unprotected Special Registers sr128-sr135 */ + + From.Space = UDI29KSpecialRegs; + From.Offset = 128; + To = (UDIUInt32 *)®isters[4 * SR_REGNUM(128)]; + Count = 135-128 + 1; + if (err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + for (i = SR_REGNUM(128); i < SR_REGNUM(128) + 135-128+1; i++) + register_valid[i] = 1; + } + + if (remote_debug) + { + printf_unfiltered("Fetching all registers\n"); + printf_unfiltered("Fetching PC0 = 0x%x, PC1 = 0x%x, PC2 = 0x%x\n", + read_register(NPC_REGNUM), read_register(PC_REGNUM), + read_register(PC2_REGNUM)); + } + + /* There doesn't seem to be any way to get these. */ + { + int val = -1; + supply_register (FPE_REGNUM, (char *) &val); + supply_register (INTE_REGNUM, (char *) &val); + supply_register (FPS_REGNUM, (char *) &val); + supply_register (EXO_REGNUM, (char *) &val); + } +} + + +/********************************************************* UDI_STORE_REGISTERS +** Store register regno into the target. + * If regno==-1 then store all the registers. + */ + +static void +udi_store_registers (regno) +int regno; +{ + UDIUInt32 *From; + UDIResource To; + UDICount Count; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + + if (regno >= 0) + { + store_register(regno); + return; + } + + if (remote_debug) + { + printf_unfiltered("Storing all registers\n"); + printf_unfiltered("PC0 = 0x%x, PC1 = 0x%x, PC2 = 0x%x\n", read_register(NPC_REGNUM), + read_register(PC_REGNUM), read_register(PC2_REGNUM)); + } + +/* Gr1/rsp */ + + From = (UDIUInt32 *)®isters[4 * GR1_REGNUM]; + To.Space = UDI29KGlobalRegs; + To.Offset = 1; + Count = 1; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +#if defined(GR64_REGNUM) + +/* Global registers gr64-gr95 */ + + From = (UDIUInt32 *)®isters[4 * GR64_REGNUM]; + To.Space = UDI29KGlobalRegs; + To.Offset = 64; + Count = 32; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +#endif /* GR64_REGNUM */ + +/* Global registers gr96-gr127 */ + + From = (UDIUInt32 *)®isters[4 * GR96_REGNUM]; + To.Space = UDI29KGlobalRegs; + To.Offset = 96; + Count = 32; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +/* Local Registers */ + + From = (UDIUInt32 *)®isters[4 * LR0_REGNUM]; + To.Space = UDI29KLocalRegs; + To.Offset = 0; + Count = 128; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + + +/* Protected Special Registers */ /* VAB through TMR */ + + From = (UDIUInt32 *)®isters[4 * SR_REGNUM(0)]; + To.Space = UDI29KSpecialRegs; + To.Offset = 0; + Count = 10; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +/* PC0, PC1, PC2 possibly as shadow registers */ + + From = (UDIUInt32 *)®isters[4 * SR_REGNUM(10)]; + To.Space = UDI29KSpecialRegs; + Count = 3; + if (USE_SHADOW_PC) + To.Offset = 20; /* SPC0 */ + else + To.Offset = 10; /* PC0 */ + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +/* PC1 via UDI29KPC */ + + From = (UDIUInt32 *)®isters[4 * PC_REGNUM]; + To.Space = UDI29KPC; + To.Offset = 0; /* PC1 */ + Count = 1; + if (UDIWrite (From, To, Count, Size, &CountDone, HostEndian)) + error ("UDIWrite() failed in udi_store_regisetrs"); + + /* LRU and MMU */ + + From = (UDIUInt32 *)®isters[4 * SR_REGNUM(13)]; + To.Space = UDI29KSpecialRegs; + To.Offset = 13; + Count = 2; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + +/* Unprotected Special Registers */ + + From = (UDIUInt32 *)®isters[4 * SR_REGNUM(128)]; + To.Space = UDI29KSpecialRegs; + To.Offset = 128; + Count = 135-128 +1; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + error("UDIWrite() failed in udi_store_regisetrs"); + + registers_changed (); +} + +/****************************************************** UDI_PREPARE_TO_STORE */ +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +static void +udi_prepare_to_store () +{ + /* Do nothing, since we can store individual regs */ +} + +/********************************************************** TRANSLATE_ADDR */ +static CORE_ADDR +translate_addr(addr) +CORE_ADDR addr; +{ +#if defined(ULTRA3) && defined(KERNEL_DEBUGGING) + /* Check for a virtual address in the kernel */ + /* Assume physical address of ublock is in paddr_u register */ + /* FIXME: doesn't work for user virtual addresses */ + if (addr >= UVADDR) { + /* PADDR_U register holds the physical address of the ublock */ + CORE_ADDR i = (CORE_ADDR)read_register(PADDR_U_REGNUM); + return(i + addr - (CORE_ADDR)UVADDR); + } else { + return(addr); + } +#else + return(addr); +#endif +} +/************************************************* UDI_XFER_INFERIOR_MEMORY */ +/* FIXME! Merge these two. */ +static int +udi_xfer_inferior_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + + memaddr = translate_addr(memaddr); + + if (write) + return udi_write_inferior_memory (memaddr, myaddr, len); + else + return udi_read_inferior_memory (memaddr, myaddr, len); +} + +/********************************************************** UDI_FILES_INFO */ +static void +udi_files_info () +{ + printf_unfiltered ("\tAttached to UDI socket to %s", udi_config_id); + if (prog_name != NULL) + printf_unfiltered ("and running program %s", prog_name); + printf_unfiltered (".\n"); +} + +/**************************************************** UDI_INSERT_BREAKPOINT */ +static int +udi_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int cnt; + UDIError err; + + for (cnt = 0; cnt < BKPT_TABLE_SIZE; cnt++) + if (bkpt_table[cnt].Type == 0) /* Find first free slot */ + break; + + if(cnt >= BKPT_TABLE_SIZE) + error("Too many breakpoints set"); + + bkpt_table[cnt].Addr.Offset = addr; + bkpt_table[cnt].Addr.Space = UDI29KIRAMSpace; + bkpt_table[cnt].PassCount = 1; + bkpt_table[cnt].Type = UDIBreakFlagExecute; + + err = UDISetBreakpoint(bkpt_table[cnt].Addr, + bkpt_table[cnt].PassCount, + bkpt_table[cnt].Type, + &bkpt_table[cnt].BreakId); + + if (err == 0) return 0; /* Success */ + + bkpt_table[cnt].Type = 0; + error("UDISetBreakpoint returned error code %d\n", err); +} + +/**************************************************** UDI_REMOVE_BREAKPOINT */ +static int +udi_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int cnt; + UDIError err; + + for (cnt = 0; cnt < BKPT_TABLE_SIZE; cnt++) + if (bkpt_table[cnt].Addr.Offset == addr) /* Find matching breakpoint */ + break; + + if(cnt >= BKPT_TABLE_SIZE) + error("Can't find breakpoint in table"); + + bkpt_table[cnt].Type = 0; + + err = UDIClearBreakpoint(bkpt_table[cnt].BreakId); + if (err == 0) return 0; /* Success */ + + error("UDIClearBreakpoint returned error code %d\n", err); +} + +static void +udi_kill(arg,from_tty) + char *arg; + int from_tty; +{ + +#if 0 +/* +UDIStop does not really work as advertised. It causes the TIP to close it's +connection, which usually results in GDB dying with a SIGPIPE. For now, we +just invoke udi_close, which seems to get things right. +*/ + UDIStop(); + + udi_session_id = -1; + inferior_pid = 0; + + if (from_tty) + printf_unfiltered("Target has been stopped."); +#endif /* 0 */ +#if 0 + udi_close(0); + pop_target(); +#endif /* 0 */ + + /* Keep the target around, e.g. so "run" can do the right thing when + we are already debugging something. */ + + if (UDIDisconnect (udi_session_id, UDITerminateSession)) + { + warning ("UDIDisconnect() failed"); + } + + /* Do not try to close udi_session_id again, later in the program. */ + udi_session_id = -1; + inferior_pid = 0; +} + +/* + Load a program into the target. Args are: `program {options}'. The options + are used to control loading of the program, and are NOT passed onto the + loaded code as arguments. (You need to use the `run' command to do that.) + + The options are: + -ms %d Set mem stack size to %d + -rs %d Set regular stack size to %d + -i send init info (default) + -noi don't send init info + -[tT] Load Text section + -[dD] Load Data section + -[bB] Load BSS section + -[lL] Load Lit section + */ + +static void +download(load_arg_string, from_tty) + char *load_arg_string; + int from_tty; +{ +#define DEFAULT_MEM_STACK_SIZE 0x6000 +#define DEFAULT_REG_STACK_SIZE 0x2000 + + char *token; + char *filename; + asection *section; + bfd *pbfd; + UDIError err; + int load_text = 1, load_data = 1, load_bss = 1, load_lit = 1; + + address_ranges[0].Space = UDI29KIRAMSpace; + address_ranges[0].Offset = 0xffffffff; + address_ranges[0].Size = 0; + + address_ranges[1].Space = UDI29KDRAMSpace; + address_ranges[1].Offset = 0xffffffff; + address_ranges[1].Size = 0; + + stack_sizes[0] = DEFAULT_REG_STACK_SIZE; + stack_sizes[1] = DEFAULT_MEM_STACK_SIZE; + + dont_repeat (); + + filename = strtok(load_arg_string, " \t"); + if (!filename) + error ("Must specify at least a file name with the load command"); + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + while (token = strtok (NULL, " \t")) + { + if (token[0] == '-') + { + token++; + + if (STREQ (token, "ms")) + stack_sizes[1] = atol (strtok (NULL, " \t")); + else if (STREQ (token, "rs")) + stack_sizes[0] = atol (strtok (NULL, " \t")); + else + { + load_text = load_data = load_bss = load_lit = 0; + + while (*token) + { + switch (*token++) + { + case 't': + case 'T': + load_text = 1; + break; + case 'd': + case 'D': + load_data = 1; + break; + case 'b': + case 'B': + load_bss = 1; + break; + case 'l': + case 'L': + load_lit = 1; + break; + default: + error ("Unknown UDI load option -%s", token-1); + } + } + } + } + } + + pbfd = bfd_openr (filename, gnutarget); + + if (!pbfd) + /* FIXME: should be using bfd_errmsg, not assuming it was + bfd_error_system_call. */ + perror_with_name (filename); + + /* 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, pbfd); + + QUIT; + immediate_quit++; + + if (!bfd_check_format (pbfd, bfd_object)) + error ("It doesn't seem to be an object file"); + + for (section = pbfd->sections; section; section = section->next) + { + if (bfd_get_section_flags (pbfd, section) & SEC_ALLOC) + { + UDIResource To; + UDICount Count; + unsigned long section_size, section_end; + const char *section_name; + + section_name = bfd_get_section_name (pbfd, section); + if (STREQ (section_name, ".text") && !load_text) + continue; + else if (STREQ (section_name, ".data") && !load_data) + continue; + else if (STREQ (section_name, ".bss") && !load_bss) + continue; + else if (STREQ (section_name, ".lit") && !load_lit) + continue; + + To.Offset = bfd_get_section_vma (pbfd, section); + section_size = bfd_section_size (pbfd, section); + section_end = To.Offset + section_size; + + if (section_size == 0) + /* This is needed at least in the BSS case, where the code + below starts writing before it even checks the size. */ + continue; + + printf_unfiltered("[Loading section %s at %x (%d bytes)]\n", + section_name, + To.Offset, + section_size); + + if (bfd_get_section_flags (pbfd, section) & SEC_CODE) + { + To.Space = UDI29KIRAMSpace; + + address_ranges[0].Offset = min (address_ranges[0].Offset, + To.Offset); + address_ranges[0].Size = max (address_ranges[0].Size, + section_end + - address_ranges[0].Offset); + } + else + { + To.Space = UDI29KDRAMSpace; + + address_ranges[1].Offset = min (address_ranges[1].Offset, + To.Offset); + address_ranges[1].Size = max (address_ranges[1].Size, + section_end + - address_ranges[1].Offset); + } + + if (bfd_get_section_flags (pbfd, section) & SEC_LOAD) /* Text, data or lit */ + { + file_ptr fptr; + + fptr = 0; + + while (section_size > 0) + { + char buffer[1024]; + + Count = min (section_size, 1024); + + bfd_get_section_contents (pbfd, section, buffer, fptr, + Count); + + err = UDIWrite ((UDIHostMemPtr)buffer, /* From */ + To, /* To */ + Count, /* Count */ + (UDISizeT)1, /* Size */ + &Count, /* CountDone */ + (UDIBool)0); /* HostEndian */ + if (err) + error ("UDIWrite failed, error = %d", err); + + To.Offset += Count; + fptr += Count; + section_size -= Count; + } + } + else /* BSS */ + { + UDIResource From; + unsigned long zero = 0; + + /* Write a zero byte at the vma */ + /* FIXME: Broken for sections of 1-3 bytes (we test for + zero above). */ + err = UDIWrite ((UDIHostMemPtr)&zero, /* From */ + To, /* To */ + (UDICount)1, /* Count */ + (UDISizeT)4, /* Size */ + &Count, /* CountDone */ + (UDIBool)0); /* HostEndian */ + if (err) + error ("UDIWrite failed, error = %d", err); + + From = To; + To.Offset+=4; + + /* Now, duplicate it for the length of the BSS */ + err = UDICopy (From, /* From */ + To, /* To */ + (UDICount)(section_size/4 - 1), /* Count */ + (UDISizeT)4, /* Size */ + &Count, /* CountDone */ + (UDIBool)1); /* Direction */ + if (err) + { + char message[100]; + int xerr; + + xerr = UDIGetErrorMsg(err, 100, message, &Count); + if (!xerr) + fprintf_unfiltered (gdb_stderr, "Error is %s\n", message); + else + fprintf_unfiltered (gdb_stderr, "xerr is %d\n", xerr); + error ("UDICopy failed, error = %d", err); + } + } + + } + } + + entry.Space = UDI29KIRAMSpace; + entry.Offset = bfd_get_start_address (pbfd); + + immediate_quit--; +} + +/* Function to download an image into the remote target. */ + +static void +udi_load (args, from_tty) + char *args; + int from_tty; +{ + download (args, from_tty); + + /* As a convenience, pick up any symbol info that is in the program + being loaded. Note that we assume that the program is the``mainline''; + if this is not always true, then this code will need to be augmented. */ + symbol_file_add (strtok (args, " \t"), from_tty, 0, 1, 0, 0); + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); +} + +/*************************************************** UDI_WRITE_INFERIOR_MEMORY +** Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. Returns number of bytes written. */ +static int +udi_write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int nwritten = 0; + UDIUInt32 *From; + UDIResource To; + UDICount Count; + UDISizeT Size = 1; + UDICount CountDone = 0; + UDIBool HostEndian = 0; + + To.Space = udi_memory_space(memaddr); + From = (UDIUInt32*)myaddr; + + while (nwritten < len) + { Count = len - nwritten; + if (Count > MAXDATA) Count = MAXDATA; + To.Offset = memaddr + nwritten; + if(UDIWrite(From, To, Count, Size, &CountDone, HostEndian)) + { error("UDIWrite() failed in udi_write_inferior_memory"); + break; + } + else + { nwritten += CountDone; + From += CountDone; + } + } + return(nwritten); +} + +/**************************************************** UDI_READ_INFERIOR_MEMORY +** Read LEN bytes from inferior memory at MEMADDR. Put the result + at debugger address MYADDR. Returns number of bytes read. */ +static int +udi_read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + int nread = 0; + UDIResource From; + UDIUInt32 *To; + UDICount Count; + UDISizeT Size = 1; + UDICount CountDone = 0; + UDIBool HostEndian = 0; + UDIError err; + + From.Space = udi_memory_space(memaddr); + To = (UDIUInt32*)myaddr; + + while (nread < len) + { Count = len - nread; + if (Count > MAXDATA) Count = MAXDATA; + From.Offset = memaddr + nread; + if(err = UDIRead(From, To, Count, Size, &CountDone, HostEndian)) + { error("UDIRead() failed in udi_read_inferior_memory"); + break; + } + else + { nread += CountDone; + To += CountDone; + } + } + return(nread); +} + +/********************************************************************* WARNING +*/ +udi_warning(num) +int num; +{ + error ("ERROR while loading program into remote TIP: $d\n", num); +} + + +/*****************************************************************************/ +/* Fetch a single register indicatated by 'regno'. + * Returns 0/-1 on success/failure. + */ +static void +fetch_register (regno) + int regno; +{ + UDIResource From; + UDIUInt32 To; + UDICount Count = 1; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + UDIError err; + int result; + + if (regno == GR1_REGNUM) + { + From.Space = UDI29KGlobalRegs; + From.Offset = 1; + } + else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + { + From.Space = UDI29KGlobalRegs; + From.Offset = (regno - GR96_REGNUM) + 96;; + } + +#if defined(GR64_REGNUM) + + else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 ) + { + From.Space = UDI29KGlobalRegs; + From.Offset = (regno - GR64_REGNUM) + 64; + } + +#endif /* GR64_REGNUM */ + + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + { + From.Space = UDI29KLocalRegs; + From.Offset = (regno - LR0_REGNUM); + } + else if (regno>=FPE_REGNUM && regno<=EXO_REGNUM) + { + int val = -1; + /*supply_register(160 + (regno - FPE_REGNUM),(char *) &val);*/ + supply_register(regno, (char *) &val); + return; /* Pretend Success */ + } + else + { + From.Space = UDI29KSpecialRegs; + From.Offset = regnum_to_srnum(regno); + } + + if (err = UDIRead(From, &To, Count, Size, &CountDone, HostEndian)) + error("UDIRead() failed in udi_fetch_registers"); + + supply_register(regno, (char *) &To); + + if (remote_debug) + printf_unfiltered("Fetching register %s = 0x%x\n", reg_names[regno], To); +} +/*****************************************************************************/ +/* Store a single register indicated by 'regno'. + * Returns 0/-1 on success/failure. + */ +static int +store_register (regno) + int regno; +{ + int result; + UDIUInt32 From; + UDIResource To; + UDICount Count = 1; + UDISizeT Size = 4; + UDICount CountDone; + UDIBool HostEndian = 0; + + From = read_register (regno); /* get data value */ + + if (remote_debug) + printf_unfiltered("Storing register %s = 0x%x\n", reg_names[regno], From); + + if (regno == GR1_REGNUM) + { + To.Space = UDI29KGlobalRegs; + To.Offset = 1; + result = UDIWrite(&From, To, Count, Size, &CountDone, HostEndian); + /* Setting GR1 changes the numbers of all the locals, so invalidate the + * register cache. Do this *after* calling read_register, because we want + * read_register to return the value that write_register has just stuffed + * into the registers array, not the value of the register fetched from + * the inferior. + */ + registers_changed (); + } +#if defined(GR64_REGNUM) + else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 ) + { + To.Space = UDI29KGlobalRegs; + To.Offset = (regno - GR64_REGNUM) + 64; + result = UDIWrite(&From, To, Count, Size, &CountDone, HostEndian); + } +#endif /* GR64_REGNUM */ + else if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32) + { + To.Space = UDI29KGlobalRegs; + To.Offset = (regno - GR96_REGNUM) + 96; + result = UDIWrite(&From, To, Count, Size, &CountDone, HostEndian); + } + else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128) + { + To.Space = UDI29KLocalRegs; + To.Offset = (regno - LR0_REGNUM); + result = UDIWrite(&From, To, Count, Size, &CountDone, HostEndian); + } + else if (regno >= FPE_REGNUM && regno <= EXO_REGNUM) + return 0; /* Pretend Success */ + else if (regno == PC_REGNUM) + { + /* PC1 via UDI29KPC */ + + To.Space = UDI29KPC; + To.Offset = 0; /* PC1 */ + result = UDIWrite (&From, To, Count, Size, &CountDone, HostEndian); + + /* Writing to this loc actually changes the values of pc0 & pc1 */ + + register_valid[PC_REGNUM] = 0; /* pc1 */ + register_valid[NPC_REGNUM] = 0; /* pc0 */ + } + else /* An unprotected or protected special register */ + { + To.Space = UDI29KSpecialRegs; + To.Offset = regnum_to_srnum(regno); + result = UDIWrite(&From, To, Count, Size, &CountDone, HostEndian); + } + + if (result != 0) + error("UDIWrite() failed in store_registers"); + + return 0; +} +/********************************************************** REGNUM_TO_SRNUM */ +/* + * Convert a gdb special register number to a 29000 special register number. + */ +static int +regnum_to_srnum(regno) +int regno; +{ + switch(regno) { + case VAB_REGNUM: return(0); + case OPS_REGNUM: return(1); + case CPS_REGNUM: return(2); + case CFG_REGNUM: return(3); + case CHA_REGNUM: return(4); + case CHD_REGNUM: return(5); + case CHC_REGNUM: return(6); + case RBP_REGNUM: return(7); + case TMC_REGNUM: return(8); + case TMR_REGNUM: return(9); + case NPC_REGNUM: return(USE_SHADOW_PC ? (20) : (10)); + case PC_REGNUM: return(USE_SHADOW_PC ? (21) : (11)); + case PC2_REGNUM: return(USE_SHADOW_PC ? (22) : (12)); + case MMU_REGNUM: return(13); + case LRU_REGNUM: return(14); + case IPC_REGNUM: return(128); + case IPA_REGNUM: return(129); + case IPB_REGNUM: return(130); + case Q_REGNUM: return(131); + case ALU_REGNUM: return(132); + case BP_REGNUM: return(133); + case FC_REGNUM: return(134); + case CR_REGNUM: return(135); + case FPE_REGNUM: return(160); + case INTE_REGNUM: return(161); + case FPS_REGNUM: return(162); + case EXO_REGNUM:return(164); + default: + return(255); /* Failure ? */ + } +} +/****************************************************************************/ +/* + * Determine the Target memory space qualifier based on the addr. + * FIXME: Can't distinguis I_ROM/D_ROM. + * FIXME: Doesn't know anything about I_CACHE/D_CACHE. + */ +static CPUSpace +udi_memory_space(addr) +CORE_ADDR addr; +{ + UDIUInt32 tstart = IMemStart; + UDIUInt32 tend = tstart + IMemSize; + UDIUInt32 dstart = DMemStart; + UDIUInt32 dend = tstart + DMemSize; + UDIUInt32 rstart = RMemStart; + UDIUInt32 rend = tstart + RMemSize; + + if (((UDIUInt32)addr >= tstart) && ((UDIUInt32)addr < tend)) { + return UDI29KIRAMSpace; + } else if (((UDIUInt32)addr >= dstart) && ((UDIUInt32)addr < dend)) { + return UDI29KDRAMSpace; + } else if (((UDIUInt32)addr >= rstart) && ((UDIUInt32)addr < rend)) { + /* FIXME: how do we determine between D_ROM and I_ROM */ + return UDI29KIROMSpace; + } else /* FIXME: what do me do now? */ + return UDI29KDRAMSpace; /* Hmmm! */ +} +/*********************************************************************** STUBS +*/ + +void convert16() {;} +void convert32() {;} +GDB_FILE * EchoFile = 0; /* used for debugging */ +int QuietMode = 0; /* used for debugging */ + +#ifdef NO_HIF_SUPPORT +service_HIF(msg) + union msg_t *msg; +{ + return(0); /* Emulate a failure */ +} +#endif + +/* Target_ops vector. Not static because there does not seem to be + any portable way to do a forward declaration of a static variable. + The RS/6000 doesn't like "extern" followed by "static"; SunOS + /bin/cc doesn't like "static" twice. */ + +struct target_ops udi_ops = { + "udi", + "Remote UDI connected TIP", + "Remote debug an AMD 29k using UDI socket connection to TIP process.\n\ +Arguments are\n\ +`configuration-id AF_INET hostname port-number'\n\ + To connect via the network, where hostname and port-number specify the\n\ + host and port where you can connect via UDI.\n\ + configuration-id is unused.\n\ +\n\ +`configuration-id AF_UNIX socket-name tip-program'\n\ + To connect using a local connection to the \"tip.exe\" program which is\n\ + supplied by AMD. If socket-name specifies an AF_UNIX socket then the\n\ + tip program must already be started; connect to it using that socket.\n\ + If not, start up tip-program, which should be the name of the tip\n\ + program. If appropriate, the PATH environment variable is searched.\n\ + configuration-id is unused.\n\ +\n\ +`configuration-id'\n\ + Look up the configuration in ./udi_soc or /etc/udi_soc, which\n\ + are files containing lines in the above formats. configuration-id is\n\ + used to pick which line of the file to use.", + udi_open, + udi_close, + udi_attach, + udi_detach, + udi_resume, + udi_wait, + udi_fetch_registers, + udi_store_registers, + udi_prepare_to_store, + udi_xfer_inferior_memory, + udi_files_info, + udi_insert_breakpoint, + udi_remove_breakpoint, + 0, /* termial_init */ + 0, /* terminal_inferior */ + 0, /* terminal_ours_for_output */ + 0, /* terminal_ours */ + 0, /* terminal_info */ + udi_kill, /* FIXME, kill */ + udi_load, /* to_load */ + 0, /* lookup_symbol */ + udi_create_inferior, + udi_mourn, /* mourn_inferior FIXME */ + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, + 0, /* next */ + 1, /* has_all_memory */ + 1, /* has_memory */ + 1, /* has_stack */ + 1, /* has_registers */ + 1, /* has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_remote_udi () +{ + add_target (&udi_ops); +} diff --git a/contrib/gdb/gdb/remote-utils.c b/contrib/gdb/gdb/remote-utils.c new file mode 100644 index 000000000000..cbbdeaf2d018 --- /dev/null +++ b/contrib/gdb/gdb/remote-utils.c @@ -0,0 +1,646 @@ +/* Generic support for remote debugging interfaces. + + Copyright 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file actually contains two distinct logical "packages". They + are packaged together in this one file because they are typically + used together. + + The first package is an addition to the serial package. The + addition provides reading and writing with debugging output and + timeouts based on user settable variables. These routines are + intended to support serial port based remote backends. These + functions are prefixed with sr_. + + The second package is a collection of more or less generic + functions for use by remote backends. They support user settable + variables for debugging, retries, and the like. + + Todo: + + * a pass through mode a la kermit or telnet. + * autobaud. + * ask remote to change his baud rate. + */ + +#include + +#include "defs.h" +#include "gdb_string.h" +#include "gdbcmd.h" +#include "target.h" +#include "serial.h" +#include "gdbcore.h" /* for exec_bfd */ +#include "inferior.h" /* for generic_mourn_inferior */ +#include "remote-utils.h" + +struct _sr_settings sr_settings = { + 4, /* timeout: + remote-hms.c had 2 + remote-bug.c had "with a timeout of 2, we time out waiting for + the prompt after an s-record dump." + + remote.c had (2): This was 5 seconds, which is a long time to + sit and wait. Unless this is going though some terminal server + or multiplexer or other form of hairy serial connection, I + would think 2 seconds would be plenty. +*/ + + 10, /* retries */ + NULL, /* device */ + NULL, /* descriptor */ +}; + +struct gr_settings *gr_settings = NULL; + +static void +usage(proto, junk) + char *proto; + char *junk; +{ + if (junk != NULL) + fprintf_unfiltered(gdb_stderr, "Unrecognized arguments: `%s'.\n", junk); + + error ("Usage: target %s [DEVICE [SPEED [DEBUG]]]\n\ +where DEVICE is the name of a device or HOST:PORT", proto, proto); + + return; +} + +#define CHECKDONE(p, q) \ +{ \ + if (q == p) \ + { \ + if (*p == '\0') \ + return; \ + else \ + usage(proto, p); \ + } \ +} + +void +sr_scan_args(proto, args) + char *proto; + char *args; +{ + int n; + char *p, *q; + + /* if no args, then nothing to do. */ + if (args == NULL || *args == '\0') + return; + + /* scan off white space. */ + for (p = args; isspace(*p); ++p) ;; + + /* find end of device name. */ + for (q = p; *q != '\0' && !isspace(*q); ++q) ;; + + /* check for missing or empty device name. */ + CHECKDONE(p, q); + sr_set_device(savestring(p, q - p)); + + /* look for baud rate. */ + n = strtol(q, &p, 10); + + /* check for missing or empty baud rate. */ + CHECKDONE(p, q); + baud_rate = n; + + /* look for debug value. */ + n = strtol(p, &q, 10); + + /* check for missing or empty debug value. */ + CHECKDONE(p, q); + sr_set_debug(n); + + /* scan off remaining white space. */ + for (p = q; isspace(*p); ++p) ;; + + /* if not end of string, then there's unrecognized junk. */ + if (*p != '\0') + usage(proto, p); + + return; +} + +void +gr_generic_checkin() +{ + sr_write_cr(""); + gr_expect_prompt(); +} + +void +gr_open(args, from_tty, gr) + char *args; + int from_tty; + struct gr_settings *gr; +{ + target_preopen(from_tty); + sr_scan_args(gr->ops->to_shortname, args); + unpush_target(gr->ops); + + gr_settings = gr; + + gr_set_dcache(dcache_init(gr->readfunc, gr->writefunc)); + + if (sr_get_desc() != NULL) + gr_close (0); + + /* If no args are specified, then we use the device specified by a + previous command or "set remotedevice". But if there is no + device, better stop now, not dump core. */ + + if (sr_get_device () == NULL) + usage (gr->ops->to_shortname, NULL); + + sr_set_desc(SERIAL_OPEN (sr_get_device())); + if (!sr_get_desc()) + perror_with_name((char *) sr_get_device()); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE(sr_get_desc(), baud_rate) != 0) + { + SERIAL_CLOSE(sr_get_desc()); + perror_with_name(sr_get_device()); + } + } + + SERIAL_RAW (sr_get_desc()); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (sr_get_desc ()); + + /* default retries */ + if (sr_get_retries() == 0) + sr_set_retries(1); + + /* default clear breakpoint function */ + if (gr_settings->clear_all_breakpoints == NULL) + gr_settings->clear_all_breakpoints = remove_breakpoints; + + if (from_tty) + { + printf_filtered ("Remote debugging using `%s'", sr_get_device ()); + if (baud_rate != -1) + printf_filtered (" at baud rate of %d", + baud_rate); + printf_filtered ("\n"); + } + + push_target(gr->ops); + gr_checkin(); + gr_clear_all_breakpoints (); + return; +} + +/* Read a character from the remote system masking it down to 7 bits + and doing all the fancy timeout stuff. */ + +int +sr_readchar () +{ + int buf; + + buf = SERIAL_READCHAR (sr_get_desc(), sr_get_timeout()); + + if (buf == SERIAL_TIMEOUT) + error ("Timeout reading from remote system."); + + if (sr_get_debug() > 0) + printf_unfiltered ("%c", buf); + + return buf & 0x7f; +} + +int +sr_pollchar() +{ + int buf; + + buf = SERIAL_READCHAR (sr_get_desc(), 0); + if (buf == SERIAL_TIMEOUT) + buf = 0; + if (sr_get_debug() > 0) + if (buf) + printf_unfiltered ("%c", buf); + else + printf_unfiltered (""); + + return buf & 0x7f; +} + +/* Keep discarding input from the remote system, until STRING is found. + Let the user break out immediately. */ +void +sr_expect (string) + char *string; +{ + char *p = string; + + immediate_quit = 1; + while (1) + { + if (sr_readchar () == *p) + { + p++; + if (*p == '\0') + { + immediate_quit = 0; + return; + } + } + else + p = string; + } +} + +void +sr_write (a, l) + char *a; + int l; +{ + int i; + + if (SERIAL_WRITE (sr_get_desc(), a, l) != 0) + perror_with_name ("sr_write: Error writing to remote"); + + if (sr_get_debug() > 0) + for (i = 0; i < l; i++) + printf_unfiltered ("%c", a[i]); + + return; +} + +void +sr_write_cr (s) + char *s; +{ + sr_write (s, strlen (s)); + sr_write ("\r", 1); + return; +} + +int +sr_timed_read (buf, n) + char *buf; + int n; +{ + int i; + char c; + + i = 0; + while (i < n) + { + c = sr_readchar (); + + if (c == 0) + return i; + buf[i] = c; + i++; + + } + return i; +} + +/* Get a hex digit from the remote system & return its value. If + ignore_space is nonzero, ignore spaces (not newline, tab, etc). */ + +int +sr_get_hex_digit (ignore_space) + int ignore_space; +{ + int ch; + + while (1) + { + ch = sr_readchar (); + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch != ' ' || !ignore_space) + { + gr_expect_prompt (); + error ("Invalid hex digit from remote system."); + } + } +} + +/* Get a byte from the remote and put it in *BYT. Accept any number + leading spaces. */ +void +sr_get_hex_byte (byt) + char *byt; +{ + int val; + + val = sr_get_hex_digit (1) << 4; + val |= sr_get_hex_digit (0); + *byt = val; +} + +/* Read a 32-bit hex word from the remote, preceded by a space */ +long +sr_get_hex_word () +{ + long val; + int j; + + val = 0; + for (j = 0; j < 8; j++) + val = (val << 4) + sr_get_hex_digit (j == 0); + return val; +} + +/* Put a command string, in args, out to the remote. The remote is assumed to + be in raw mode, all writing/reading done through desc. + Ouput from the remote is placed on the users terminal until the + prompt from the remote is seen. + FIXME: Can't handle commands that take input. */ + +void +sr_com (args, fromtty) + char *args; + int fromtty; +{ + sr_check_open (); + + if (!args) + return; + + /* Clear all input so only command relative output is displayed */ + + sr_write_cr (args); + sr_write ("\030", 1); + registers_changed (); + gr_expect_prompt (); +} + +void +gr_close(quitting) + int quitting; +{ + gr_clear_all_breakpoints(); + + if (sr_is_open()) + { + SERIAL_CLOSE (sr_get_desc()); + sr_set_desc(NULL); + } + + return; +} + +/* gr_detach() + takes a program previously attached to and detaches it. + We better not have left any breakpoints + in the program or it'll die when it hits one. + Close the open connection to the remote debugger. + Use this when you want to detach and do something else + with your gdb. */ + +void +gr_detach(args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + if (sr_is_open()) + gr_clear_all_breakpoints (); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); + + return; +} + +void +gr_files_info (ops) + struct target_ops *ops; +{ +#ifdef __GO32__ + printf_filtered ("\tAttached to DOS asynctsr\n"); +#else + printf_filtered ("\tAttached to %s", sr_get_device()); + if (baud_rate != -1) + printf_filtered ("at %d baud", baud_rate); + printf_filtered ("\n"); +#endif + + if (exec_bfd) + { + printf_filtered ("\tand running program %s\n", + bfd_get_filename (exec_bfd)); + } + printf_filtered ("\tusing the %s protocol.\n", ops->to_shortname); +} + +void +gr_mourn () +{ + gr_clear_all_breakpoints (); + unpush_target (gr_get_ops()); + generic_mourn_inferior (); +} + +void +gr_kill () +{ + return; +} + +/* This is called not only when we first attach, but also when the + user types "run" after having attached. */ +void +gr_create_inferior (execfile, args, env) + char *execfile; + char *args; + char **env; +{ + int entry_pt; + + if (args && *args) + error ("Can't pass arguments to remote process."); + + if (execfile == 0 || exec_bfd == 0) + error ("No exec file specified"); + + entry_pt = (int) bfd_get_start_address (exec_bfd); + sr_check_open (); + + gr_kill (); + gr_clear_all_breakpoints (); + + init_wait_for_inferior (); + gr_checkin(); + + insert_breakpoints (); /* Needed to get correct instruction in cache */ + proceed (entry_pt, -1, 0); +} + +/* Given a null terminated list of strings LIST, read the input until we find one of + them. Return the index of the string found or -1 on error. '?' means match + any single character. Note that with the algorithm we use, the initial + character of the string cannot recur in the string, or we will not find some + cases of the string in the input. If PASSTHROUGH is non-zero, then + pass non-matching data on. */ + +int +gr_multi_scan (list, passthrough) + char *list[]; + int passthrough; +{ + char *swallowed = NULL; /* holding area */ + char *swallowed_p = swallowed; /* Current position in swallowed. */ + int ch; + int ch_handled; + int i; + int string_count; + int max_length; + char **plist; + + /* Look through the strings. Count them. Find the largest one so we can + allocate a holding area. */ + + for (max_length = string_count = i = 0; + list[i] != NULL; + ++i, ++string_count) + { + int length = strlen(list[i]); + + if (length > max_length) + max_length = length; + } + + /* if we have no strings, then something is wrong. */ + if (string_count == 0) + return(-1); + + /* otherwise, we will need a holding area big enough to hold almost two + copies of our largest string. */ + swallowed_p = swallowed = alloca(max_length << 1); + + /* and a list of pointers to current scan points. */ + plist = (char **) alloca (string_count * sizeof(*plist)); + + /* and initialize */ + for (i = 0; i < string_count; ++i) + plist[i] = list[i]; + + for (ch = sr_readchar(); /* loop forever */ ; ch = sr_readchar()) + { + QUIT; /* Let user quit and leave process running */ + ch_handled = 0; + + for (i = 0; i < string_count; ++i) + { + if (ch == *plist[i] || *plist[i] == '?') + { + ++plist[i]; + if (*plist[i] == '\0') + return(i); + + if (!ch_handled) + *swallowed_p++ = ch; + + ch_handled = 1; + } + else + plist[i] = list[i]; + } + + if (!ch_handled) + { + char *p; + + /* Print out any characters which have been swallowed. */ + if (passthrough) + { + for (p = swallowed; p < swallowed_p; ++p) + fputc_unfiltered (*p, gdb_stdout); + + fputc_unfiltered (ch, gdb_stdout); + } + + swallowed_p = swallowed; + } + } +#if 0 + /* Never reached. */ + return(-1); +#endif +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +gr_prepare_to_store () +{ + /* Do nothing, since we assume we can store individual regs */ +} + +/* Read a word from remote address ADDR and return it. + * This goes through the data cache. + */ +int +gr_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (gr_get_dcache(), addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +void +gr_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (gr_get_dcache(), addr, word); +} + +void +_initialize_sr_support () +{ +/* FIXME-now: if target is open... */ + add_show_from_set (add_set_cmd ("remotedevice", no_class, + var_filename, (char *)&sr_settings.device, + "Set device for remote serial I/O.\n\ +This device is used as the serial port when debugging using remote\n\ +targets.", &setlist), + &showlist); + + add_com ("remote ", class_obscure, sr_com, + "Send a command to the remote monitor."); + +} diff --git a/contrib/gdb/gdb/remote-utils.h b/contrib/gdb/gdb/remote-utils.h new file mode 100644 index 000000000000..d4fcd0eded33 --- /dev/null +++ b/contrib/gdb/gdb/remote-utils.h @@ -0,0 +1,142 @@ +/* Generic support for remote debugging interfaces. + + Copyright 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef REMOTE_UTILS_H +#define REMOTE_UTILS_H + +#include "serial.h" +#include "target.h" +#include "dcache.h" + +/* Stuff that should be shared (and handled consistently) among the various + remote targets. */ + +struct _sr_settings { + unsigned int timeout; + + int retries; + + char *device; + serial_t desc; + +}; + +extern struct _sr_settings sr_settings; + +/* get and set debug value. */ +#define sr_get_debug() (remote_debug) +#define sr_set_debug(newval) (remote_debug = (newval)) + +/* get and set timeout. */ +#define sr_get_timeout() (sr_settings.timeout) +#define sr_set_timeout(newval) (sr_settings.timeout = (newval)) + +/* get and set device. */ +#define sr_get_device() (sr_settings.device) +#define sr_set_device(newval) \ +{ \ + if (sr_settings.device) free(sr_settings.device); \ + sr_settings.device = (newval); \ +} + +/* get and set descriptor value. */ +#define sr_get_desc() (sr_settings.desc) +#define sr_set_desc(newval) (sr_settings.desc = (newval)) + +/* get and set retries. */ +#define sr_get_retries() (sr_settings.retries) +#define sr_set_retries(newval) (sr_settings.retries = (newval)) + +#define sr_is_open() (sr_settings.desc != NULL) + +#define sr_check_open() { if (!sr_is_open()) \ + error ("Remote device not open"); } + +struct gr_settings { + /* This is our data cache. */ + DCACHE *dcache; + char *prompt; + struct target_ops *ops; + int (*clear_all_breakpoints)PARAMS((void)); + memxferfunc readfunc; + memxferfunc writefunc; + void (*checkin)PARAMS((void)); +}; + +extern struct gr_settings *gr_settings; + +/* get and set dcache. */ +#define gr_get_dcache() (gr_settings->dcache) +#define gr_set_dcache(newval) (gr_settings->dcache = (newval)) + +/* get and set prompt. */ +#define gr_get_prompt() (gr_settings->prompt) +#define gr_set_prompt(newval) (gr_settings->prompt = (newval)) + +/* get and set ops. */ +#define gr_get_ops() (gr_settings->ops) +#define gr_set_ops(newval) (gr_settings->ops = (newval)) + +#define gr_clear_all_breakpoints() ((gr_settings->clear_all_breakpoints)()) +#define gr_checkin() ((gr_settings->checkin)()) + +/* Keep discarding input until we see the prompt. + + The convention for dealing with the prompt is that you + o give your command + o *then* wait for the prompt. + + Thus the last thing that a procedure does with the serial line + will be an gr_expect_prompt(). Exception: resume does not + wait for the prompt, because the terminal is being handed over + to the inferior. However, the next thing which happens after that + is a bug_wait which does wait for the prompt. + Note that this includes abnormal exit, e.g. error(). This is + necessary to prevent getting into states from which we can't + recover. */ + +#define gr_expect_prompt() sr_expect(gr_get_prompt()) + +int gr_fetch_word PARAMS((CORE_ADDR addr)); +int gr_multi_scan PARAMS((char *list[], int passthrough)); +int sr_get_hex_digit PARAMS((int ignore_space)); +int sr_pollchar PARAMS((void)); +int sr_readchar PARAMS((void)); +int sr_timed_read PARAMS((char *buf, int n)); +long sr_get_hex_word PARAMS((void)); +void gr_close PARAMS((int quitting)); +void gr_create_inferior PARAMS((char *execfile, char *args, char **env)); +void gr_detach PARAMS((char *args, int from_tty)); +void gr_files_info PARAMS((struct target_ops *ops)); +void gr_generic_checkin PARAMS((void)); +void gr_kill PARAMS((void)); +void gr_mourn PARAMS((void)); +void gr_prepare_to_store PARAMS((void)); +void gr_store_word PARAMS((CORE_ADDR addr, int word)); +void sr_expect PARAMS((char *string)); +void sr_get_hex_byte PARAMS((char *byt)); +void sr_scan_args PARAMS((char *proto, char *args)); +void sr_write PARAMS((char *a, int l)); +void sr_write_cr PARAMS((char *s)); + +void gr_open PARAMS((char *args, int from_tty, + struct gr_settings *gr_settings)); +void gr_load_image PARAMS((char*, int from_tty)); +#endif /* REMOTE_UTILS_H */ diff --git a/contrib/gdb/gdb/remote-vx.c b/contrib/gdb/gdb/remote-vx.c new file mode 100644 index 000000000000..13b6c294994c --- /dev/null +++ b/contrib/gdb/gdb/remote-vx.c @@ -0,0 +1,1488 @@ +/* Memory-access and commands for remote VxWorks processes, for GDB. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Wind River Systems and 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "complaints.h" +#include "gdbcmd.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" +#include "gdb-stabs.h" + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#define malloc bogon_malloc /* Sun claims "char *malloc()" not void * */ +#define free bogon_free /* Sun claims "int free()" not void */ +#define realloc bogon_realloc /* Sun claims "char *realloc()", not void * */ +#include +#undef malloc +#undef free +#undef realloc +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +#include + +/* Maximum number of bytes to transfer in a single + PTRACE_{READ,WRITE}DATA request. */ +#define VX_MEMXFER_MAX 4096 + +extern void vx_read_register (); +extern void vx_write_register (); +extern void symbol_file_command (); +extern int stop_soon_quietly; /* for wait_for_inferior */ + +static int net_step (); +static int net_ptrace_clnt_call (); /* Forward decl */ +static enum clnt_stat net_clnt_call (); /* Forward decl */ +extern struct target_ops vx_ops, vx_run_ops; /* Forward declaration */ + +/* Saved name of target host and called function for "info files". + Both malloc'd. */ + +static char *vx_host; +static char *vx_running; /* Called function */ + +/* Nonzero means target that is being debugged remotely has a floating + point processor. */ + +int target_has_fp; + +/* Default error message when the network is forking up. */ + +static const char rpcerr[] = "network target debugging: rpc error"; + +CLIENT *pClient; /* client used in net debugging */ +static int ptraceSock = RPC_ANYSOCK; + +enum clnt_stat net_clnt_call(); +static void parse_args (); + +static struct timeval rpcTimeout = { 10, 0 }; + +static char *skip_white_space (); +static char *find_white_space (); + +/* Tell the VxWorks target system to download a file. + The load addresses of the text, data, and bss segments are + stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively). + Returns 0 for success, -1 for failure. */ + +static int +net_load (filename, pTextAddr, pDataAddr, pBssAddr) + char *filename; + CORE_ADDR *pTextAddr; + CORE_ADDR *pDataAddr; + CORE_ADDR *pBssAddr; +{ + enum clnt_stat status; + struct ldfile ldstruct; + struct timeval load_timeout; + + memset ((char *) &ldstruct, '\0', sizeof (ldstruct)); + + /* We invoke clnt_call () here directly, instead of through + net_clnt_call (), because we need to set a large timeout value. + The load on the target side can take quite a while, easily + more than 10 seconds. The user can kill this call by typing + CTRL-C if there really is a problem with the load. + + Do not change the tv_sec value without checking -- select() imposes + a limit of 10**8 on it for no good reason that I can see... */ + + load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */ + load_timeout.tv_usec = 0; + + status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile, + &ldstruct, load_timeout); + + if (status == RPC_SUCCESS) + { + if (*ldstruct.name == 0) /* load failed on VxWorks side */ + return -1; + *pTextAddr = ldstruct.txt_addr; + *pDataAddr = ldstruct.data_addr; + *pBssAddr = ldstruct.bss_addr; + return 0; + } + else + return -1; +} + +/* returns 0 if successful, errno if RPC failed or VxWorks complains. */ + +static int +net_break (addr, procnum) + int addr; + u_long procnum; +{ + enum clnt_stat status; + int break_status; + Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace + structure. How about something smaller? */ + + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + break_status = 0; + + ptrace_in.addr = addr; + ptrace_in.pid = inferior_pid; + + status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int, + &break_status); + + if (status != RPC_SUCCESS) + return errno; + + if (break_status == -1) + return ENOMEM; + return break_status; /* probably (FIXME) zero */ +} + +/* returns 0 if successful, errno otherwise */ + +static int +vx_insert_breakpoint (addr) + int addr; +{ + return net_break (addr, VX_BREAK_ADD); +} + +/* returns 0 if successful, errno otherwise */ + +static int +vx_remove_breakpoint (addr) + int addr; +{ + return net_break (addr, VX_BREAK_DELETE); +} + +/* Start an inferior process and sets inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. + Returns process id. Errors reported with error(). + On VxWorks, we ignore exec_file. */ + +static void +vx_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + enum clnt_stat status; + arg_array passArgs; + TASK_START taskStart; + + memset ((char *) &passArgs, '\0', sizeof (passArgs)); + memset ((char *) &taskStart, '\0', sizeof (taskStart)); + + /* parse arguments, put them in passArgs */ + + parse_args (args, &passArgs); + + if (passArgs.arg_array_len == 0) + error ("You must specify a function name to run, and arguments if any"); + + status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs, + xdr_TASK_START, &taskStart); + + if ((status != RPC_SUCCESS) || (taskStart.status == -1)) + error ("Can't create process on remote target machine"); + + /* Save the name of the running function */ + vx_running = savestring (passArgs.arg_array_val[0], + strlen (passArgs.arg_array_val[0])); + + push_target (&vx_run_ops); + inferior_pid = taskStart.pid; + + /* We will get a trace trap after one instruction. + Insert breakpoints and continue. */ + + init_wait_for_inferior (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + target_terminal_init (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + stop_soon_quietly = 1; + wait_for_inferior (); /* Get the task spawn event */ + stop_soon_quietly = 0; + + /* insert_step_breakpoint (); FIXME, do we need this? */ + proceed (-1, TARGET_SIGNAL_DEFAULT, 0); +} + +/* Fill ARGSTRUCT in argc/argv form with the arguments from the + argument string ARGSTRING. */ + +static void +parse_args (arg_string, arg_struct) + register char *arg_string; + arg_array *arg_struct; +{ + register int arg_count = 0; /* number of arguments */ + register int arg_index = 0; + register char *p0; + + memset ((char *) arg_struct, '\0', sizeof (arg_array)); + + /* first count how many arguments there are */ + + p0 = arg_string; + while (*p0 != '\0') + { + if (*(p0 = skip_white_space (p0)) == '\0') + break; + p0 = find_white_space (p0); + arg_count++; + } + + arg_struct->arg_array_len = arg_count; + arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1) + * sizeof (char *)); + + /* now copy argument strings into arg_struct. */ + + while (*(arg_string = skip_white_space (arg_string))) + { + p0 = find_white_space (arg_string); + arg_struct->arg_array_val[arg_index++] = savestring (arg_string, + p0 - arg_string); + arg_string = p0; + } + + arg_struct->arg_array_val[arg_count] = NULL; +} + +/* Advance a string pointer across whitespace and return a pointer + to the first non-white character. */ + +static char * +skip_white_space (p) + register char *p; +{ + while (*p == ' ' || *p == '\t') + p++; + return p; +} + +/* Search for the first unquoted whitespace character in a string. + Returns a pointer to the character, or to the null terminator + if no whitespace is found. */ + +static char * +find_white_space (p) + register char *p; +{ + register int c; + + while ((c = *p) != ' ' && c != '\t' && c) + { + if (c == '\'' || c == '"') + { + while (*++p != c && *p) + { + if (*p == '\\') + p++; + } + if (!*p) + break; + } + p++; + } + return p; +} + +/* Poll the VxWorks target system for an event related + to the debugged task. + Returns -1 if remote wait failed, task status otherwise. */ + +static int +net_wait (pEvent) + RDB_EVENT *pEvent; +{ + int pid; + enum clnt_stat status; + + memset ((char *) pEvent, '\0', sizeof (RDB_EVENT)); + + pid = inferior_pid; + status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT, + pEvent); + + /* return (status == RPC_SUCCESS)? pEvent->status: -1; */ + if (status == RPC_SUCCESS) + return ((pEvent->status) ? 1 : 0); + else if (status == RPC_TIMEDOUT) + return (1); + else + return (-1); +} + +/* Suspend the remote task. + Returns -1 if suspend fails on target system, 0 otherwise. */ + +static int +net_quit () +{ + int pid; + int quit_status; + enum clnt_stat status; + + quit_status = 0; + + /* don't let rdbTask suspend itself by passing a pid of 0 */ + + if ((pid = inferior_pid) == 0) + return -1; + + status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int, + &quit_status); + + return (status == RPC_SUCCESS)? quit_status: -1; +} + +/* Read a register or registers from the remote system. */ + +void +net_read_registers (reg_buf, len, procnum) + char *reg_buf; + int len; + u_long procnum; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + C_bytes out_data; + char message[100]; + + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); + + /* Initialize RPC input argument structure. */ + + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = NOINFO; + + /* Initialize RPC return value structure. */ + + out_data.bytes = reg_buf; + out_data.len = len; + ptrace_out.info.more_data = (caddr_t) &out_data; + + /* Call RPC; take an error exit if appropriate. */ + + status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS) + ? "general-purpose" + : "floating-point"); + perror_with_name (message); + } +} + +/* Write register values to a VxWorks target. REG_BUF points to a buffer + containing the raw register values, LEN is the length of REG_BUF in + bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or + PTRACE_SETFPREGS). An error exit is taken if the RPC call fails or + if an error status is returned by the remote debug server. This is + a utility routine used by vx_write_register (). */ + +void +net_write_registers (reg_buf, len, procnum) + char *reg_buf; + int len; + u_long procnum; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + C_bytes in_data; + char message[100]; + + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); + + /* Initialize RPC input argument structure. */ + + in_data.bytes = reg_buf; + in_data.len = len; + + ptrace_in.pid = inferior_pid; + ptrace_in.info.ttype = DATA; + ptrace_in.info.more_data = (caddr_t) &in_data; + + /* Call RPC; take an error exit if appropriate. */ + + status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out); + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS) + ? "general-purpose" + : "floating-point"); + perror_with_name (message); + } +} + +/* Prepare to store registers. Since we will store all of them, + read out their current values now. */ + +static void +vx_prepare_to_store () +{ + /* Fetch all registers, if any of them are not yet fetched. */ + read_register_bytes (0, NULL, REGISTER_BYTES); +} + +/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. WRITE is true if writing to the + inferior. + Result is the number of bytes written or read (zero if error). The + protocol allows us to return a negative count, indicating that we can't + handle the current address but can handle one N bytes further, but + vxworks doesn't give us that information. */ + +static int +vx_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + C_bytes data; + enum ptracereq request; + int nleft, nxfer; + + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); + + ptrace_in.pid = inferior_pid; /* XXX pid unnecessary for READDATA */ + ptrace_in.addr = (int) memaddr; /* Where from */ + ptrace_in.data = len; /* How many bytes */ + + if (write) + { + ptrace_in.info.ttype = DATA; + ptrace_in.info.more_data = (caddr_t) &data; + + data.bytes = (caddr_t) myaddr; /* Where from */ + data.len = len; /* How many bytes (again, for XDR) */ + request = PTRACE_WRITEDATA; + } + else + { + ptrace_out.info.more_data = (caddr_t) &data; + request = PTRACE_READDATA; + } + /* Loop until the entire request has been satisfied, transferring + at most VX_MEMXFER_MAX bytes per iteration. Break from the loop + if an error status is returned by the remote debug server. */ + + nleft = len; + status = 0; + + while (nleft > 0 && status == 0) + { + nxfer = min (nleft, VX_MEMXFER_MAX); + + ptrace_in.addr = (int) memaddr; + ptrace_in.data = nxfer; + data.bytes = (caddr_t) myaddr; + data.len = nxfer; + + /* Request a block from the remote debug server; if RPC fails, + report an error and return to debugger command level. */ + + if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out)) + error (rpcerr); + + status = ptrace_out.status; + if (status == 0) + { + memaddr += nxfer; + myaddr += nxfer; + nleft -= nxfer; + } + else + { + /* A target-side error has ocurred. Set errno to the error + code chosen by the target so that a later perror () will + say something meaningful. */ + + errno = ptrace_out.errno; + } + } + + /* Return the number of bytes transferred. */ + + return (len - nleft); +} + +static void +vx_files_info () +{ + printf_unfiltered ("\tAttached to host `%s'", vx_host); + printf_unfiltered (", which has %sfloating point", target_has_fp? "": "no "); + printf_unfiltered (".\n"); +} + +static void +vx_run_files_info () +{ + printf_unfiltered ("\tRunning %s VxWorks process %s", + vx_running ? "child" : "attached", + local_hex_string (inferior_pid)); + if (vx_running) + printf_unfiltered (", function `%s'", vx_running); + printf_unfiltered(".\n"); +} + +static void +vx_resume (pid, step, siggnal) + int pid; + int step; + enum target_signal siggnal; +{ + int status; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + CORE_ADDR cont_addr; + + if (pid == -1) + pid = inferior_pid; + + if (siggnal != 0 && siggnal != stop_signal) + error ("Cannot send signals to VxWorks processes"); + + /* Set CONT_ADDR to the address at which we are continuing, + or to 1 if we are continuing from where the program stopped. + This conforms to traditional ptrace () usage, but at the same + time has special meaning for the VxWorks remote debug server. + If the address is not 1, the server knows that the target + program is jumping to a new address, which requires special + handling if there is a breakpoint at the new address. */ + + cont_addr = read_register (PC_REGNUM); + if (cont_addr == stop_pc) + cont_addr = 1; + + memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out)); + + ptrace_in.pid = pid; + ptrace_in.addr = cont_addr; /* Target side insists on this, or it panics. */ + + if (step) + status = net_step(); + else + status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out); + + if (status) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Resuming remote process"); + } +} + +static void +vx_mourn_inferior () +{ + pop_target (); /* Pop back to no-child state */ + generic_mourn_inferior (); +} + + +static void vx_add_symbols PARAMS ((char *, int, CORE_ADDR, CORE_ADDR, + CORE_ADDR)); + +struct find_sect_args { + CORE_ADDR text_start; + CORE_ADDR data_start; + CORE_ADDR bss_start; +}; + +static void find_sect PARAMS ((bfd *, asection *, void *)); + +static void +find_sect (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR obj; +{ + struct find_sect_args *args = (struct find_sect_args *)obj; + + if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY)) + args->text_start = bfd_get_section_vma (abfd, sect); + else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC) + { + if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) + { + /* Exclude .ctor and .dtor sections which have SEC_CODE set but not + SEC_DATA. */ + if (bfd_get_section_flags (abfd, sect) & SEC_DATA) + args->data_start = bfd_get_section_vma (abfd, sect); + } + else + args->bss_start = bfd_get_section_vma (abfd, sect); + } +} + +static void +vx_add_symbols (name, from_tty, text_addr, data_addr, bss_addr) + char *name; + int from_tty; + CORE_ADDR text_addr; + CORE_ADDR data_addr; + CORE_ADDR bss_addr; +{ + struct section_offsets *offs; + struct objfile *objfile; + struct find_sect_args ss; + + /* It might be nice to suppress the breakpoint_re_set which happens here + because we are going to do one again after the objfile_relocate. */ + objfile = symbol_file_add (name, from_tty, 0, 0, 0, 0); + + /* This is a (slightly cheesy) way of superceding the old symbols. A less + cheesy way would be to find the objfile with the same name and + free_objfile it. */ + objfile_to_front (objfile); + + offs = (struct section_offsets *) + alloca (sizeof (struct section_offsets) + + objfile->num_sections * sizeof (offs->offsets)); + memcpy (offs, objfile->section_offsets, + sizeof (struct section_offsets) + + objfile->num_sections * sizeof (offs->offsets)); + + ss.text_start = 0; + ss.data_start = 0; + ss.bss_start = 0; + bfd_map_over_sections (objfile->obfd, find_sect, &ss); + + /* Both COFF and b.out frontends use these SECT_OFF_* values. */ + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr - ss.text_start; + ANOFFSET (offs, SECT_OFF_DATA) = data_addr - ss.data_start; + ANOFFSET (offs, SECT_OFF_BSS) = bss_addr - ss.bss_start; + objfile_relocate (objfile, offs); + + /* Need to do this *after* things are relocated. */ + breakpoint_re_set (); +} + +/* This function allows the addition of incrementally linked object files. */ + +static void +vx_load_command (arg_string, from_tty) + char *arg_string; + int from_tty; +{ + CORE_ADDR text_addr; + CORE_ADDR data_addr; + CORE_ADDR bss_addr; + + if (arg_string == 0) + error ("The load command takes a file name"); + + arg_string = tilde_expand (arg_string); + make_cleanup (free, arg_string); + + dont_repeat (); + + /* Refuse to load the module if a debugged task is running. Doing so + can have a number of unpleasant consequences to the running task. */ + + if (inferior_pid != 0 && target_has_execution) + { + if (query ("You may not load a module while the target task is running.\n\ +Kill the target task? ")) + target_kill (); + else + error ("Load cancelled."); + } + + QUIT; + immediate_quit++; + if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1) + error ("Load failed on target machine"); + immediate_quit--; + + vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr); + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); +} + +/* Single step the target program at the source or machine level. + Takes an error exit if rpc fails. + Returns -1 if remote single-step operation fails, else 0. */ + +static int +net_step () +{ + enum clnt_stat status; + int step_status; + SOURCE_STEP source_step; + + source_step.taskId = inferior_pid; + + if (step_range_end) + { + source_step.startAddr = step_range_start; + source_step.endAddr = step_range_end; + } + else + { + source_step.startAddr = 0; + source_step.endAddr = 0; + } + + status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step, + xdr_int, &step_status); + + if (status == RPC_SUCCESS) + return step_status; + else + error (rpcerr); +} + +/* Emulate ptrace using RPC calls to the VxWorks target system. + Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */ + +static int +net_ptrace_clnt_call (request, pPtraceIn, pPtraceOut) + enum ptracereq request; + Rptrace *pPtraceIn; + Ptrace_return *pPtraceOut; +{ + enum clnt_stat status; + + status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return, + pPtraceOut); + + if (status != RPC_SUCCESS) + return -1; + + return 0; +} + +/* Query the target for the name of the file from which VxWorks was + booted. pBootFile is the address of a pointer to the buffer to + receive the file name; if the pointer pointed to by pBootFile is + NULL, memory for the buffer will be allocated by XDR. + Returns -1 if rpc failed, 0 otherwise. */ + +static int +net_get_boot_file (pBootFile) + char **pBootFile; +{ + enum clnt_stat status; + + status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0, + xdr_wrapstring, pBootFile); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Fetch a list of loaded object modules from the VxWorks target. + Returns -1 if rpc failed, 0 otherwise + There's no way to check if the returned loadTable is correct. + VxWorks doesn't check it. */ + +static int +net_get_symbols (pLoadTable) + ldtabl *pLoadTable; /* return pointer to ldtabl here */ +{ + enum clnt_stat status; + + memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl)); + + status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable); + return (status == RPC_SUCCESS) ? 0 : -1; +} + +/* Look up a symbol in the VxWorks target's symbol table. + Returns status of symbol read on target side (0=success, -1=fail) + Returns -1 and complain()s if rpc fails. */ + +struct complaint cant_contact_target = + {"Lost contact with VxWorks target", 0, 0}; + +static int +vx_lookup_symbol (name, pAddr) + char *name; /* symbol name */ + CORE_ADDR *pAddr; +{ + enum clnt_stat status; + SYMBOL_ADDR symbolAddr; + + *pAddr = 0; + memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr)); + + status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name, + xdr_SYMBOL_ADDR, &symbolAddr); + if (status != RPC_SUCCESS) + { + complain (&cant_contact_target); + return -1; + } + + *pAddr = symbolAddr.addr; + return symbolAddr.status; +} + +/* Check to see if the VxWorks target has a floating point coprocessor. + Returns 1 if target has floating point processor, 0 otherwise. + Calls error() if rpc fails. */ + +static int +net_check_for_fp () +{ + enum clnt_stat status; + bool_t fp = 0; /* true if fp processor is present on target board */ + + status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp); + if (status != RPC_SUCCESS) + error (rpcerr); + + return (int) fp; +} + +/* Establish an RPC connection with the VxWorks target system. + Calls error () if unable to establish connection. */ + +static void +net_connect (host) + char *host; +{ + struct sockaddr_in destAddr; + struct hostent *destHost; + unsigned long addr; + + /* Get the internet address for the given host. Allow a numeric + IP address or a hostname. */ + + addr = inet_addr (host); + if (addr == -1) + { + destHost = (struct hostent *) gethostbyname (host); + if (destHost == NULL) + /* FIXME: Probably should include hostname here in quotes. + For example if the user types "target vxworks vx960 " it should + say "Invalid host `vx960 '." not just "Invalid hostname". */ + error ("Invalid hostname. Couldn't find remote host address."); + addr = * (unsigned long *) destHost->h_addr; + } + + memset (&destAddr, '\0', sizeof (destAddr)); + + destAddr.sin_addr.s_addr = addr; + destAddr.sin_family = AF_INET; + destAddr.sin_port = 0; /* set to actual port that remote + ptrace is listening on. */ + + /* Create a tcp client transport on which to issue + calls to the remote ptrace server. */ + + ptraceSock = RPC_ANYSOCK; + pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0); + /* FIXME, here is where we deal with different version numbers of the + proto */ + + if (pClient == NULL) + { + clnt_pcreateerror ("\tnet_connect"); + error ("Couldn't connect to remote target."); + } +} + +/* Sleep for the specified number of milliseconds + * (assumed to be less than 1000). + * If select () is interrupted, returns immediately; + * takes an error exit if select () fails for some other reason. + */ + +static void +sleep_ms (ms) + long ms; +{ + struct timeval select_timeout; + int status; + + select_timeout.tv_sec = 0; + select_timeout.tv_usec = ms * 1000; + + status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, + &select_timeout); + + if (status < 0 && errno != EINTR) + perror_with_name ("select"); +} + +static int +vx_wait (pid_to_wait_for, status) + int pid_to_wait_for; + struct target_waitstatus *status; +{ + register int pid; + RDB_EVENT rdbEvent; + int quit_failed; + + do + { + /* If CTRL-C is hit during this loop, + suspend the inferior process. */ + + quit_failed = 0; + if (quit_flag) + { + quit_failed = (net_quit () == -1); + quit_flag = 0; + } + + /* If a net_quit () or net_wait () call has failed, + allow the user to break the connection with the target. + We can't simply error () out of this loop, since the + data structures representing the state of the inferior + are in an inconsistent state. */ + + if (quit_failed || net_wait (&rdbEvent) == -1) + { + terminal_ours (); + if (query ("Can't %s. Disconnect from target system? ", + (quit_failed) ? "suspend remote task" + : "get status of remote task")) + { + target_mourn_inferior(); + error ("Use the \"target\" command to reconnect."); + } + else + { + terminal_inferior (); + continue; + } + } + + pid = rdbEvent.taskId; + if (pid == 0) + { + sleep_ms (200); /* FIXME Don't kill the network too badly */ + } + else if (pid != inferior_pid) + fatal ("Bad pid for debugged task: %s\n", + local_hex_string((unsigned long) pid)); + } while (pid == 0); + + /* The mostly likely kind. */ + status->kind = TARGET_WAITKIND_STOPPED; + + switch (rdbEvent.eventType) + { + case EVENT_EXIT: + status->kind = TARGET_WAITKIND_EXITED; + /* FIXME is it possible to distinguish between a + normal vs abnormal exit in VxWorks? */ + status->value.integer = 0; + break; + + case EVENT_START: + /* Task was just started. */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + + case EVENT_STOP: + status->value.sig = TARGET_SIGNAL_TRAP; + /* XXX was it stopped by a signal? act accordingly */ + break; + + case EVENT_BREAK: /* Breakpoint was hit. */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + + case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */ + status->value.sig = TARGET_SIGNAL_INT; + break; + + case EVENT_BUS_ERR: /* Task made evil nasty reference. */ + status->value.sig = TARGET_SIGNAL_BUS; + break; + + case EVENT_ZERO_DIV: /* Division by zero */ + status->value.sig = TARGET_SIGNAL_FPE; + break; + + case EVENT_SIGNAL: +#ifdef I80960 + status->value.sig = i960_fault_to_signal (rdbEvent.sigType); +#else + /* Back in the old days, before enum target_signal, this code used + to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL + would take care of it. But PRINT_RANDOM_SIGNAL has never been + defined except on the i960, so I don't really know what we are + supposed to do on other architectures. */ + status->value.sig = TARGET_SIGNAL_UNKNOWN; +#endif + break; + } /* switch */ + return pid; +} + +static int +symbol_stub (arg) + char *arg; +{ + symbol_file_command (arg, 0); + return 1; +} + +static int +add_symbol_stub (arg) + char *arg; +{ + struct ldfile *pLoadFile = (struct ldfile *)arg; + + printf_unfiltered("\t%s: ", pLoadFile->name); + vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr, + pLoadFile->data_addr, pLoadFile->bss_addr); + printf_unfiltered ("ok\n"); + return 1; +} +/* Target command for VxWorks target systems. + + Used in vxgdb. Takes the name of a remote target machine + running vxWorks and connects to it to initialize remote network + debugging. */ + +static void +vx_open (args, from_tty) + char *args; + int from_tty; +{ + extern int close (); + char *bootFile; + extern char *source_path; + struct ldtabl loadTable; + struct ldfile *pLoadFile; + int i; + extern CLIENT *pClient; + int symbols_added = 0; + + if (!args) + error_no_arg ("target machine name"); + + target_preopen (from_tty); + + unpush_target (&vx_ops); + printf_unfiltered ("Attaching remote machine across net...\n"); + gdb_flush (gdb_stdout); + + /* Allow the user to kill the connect attempt by typing ^C. + Wait until the call to target_has_fp () completes before + disallowing an immediate quit, since even if net_connect () + is successful, the remote debug server might be hung. */ + + immediate_quit++; + + net_connect (args); + target_has_fp = net_check_for_fp (); + printf_filtered ("Connected to %s.\n", args); + + immediate_quit--; + + push_target (&vx_ops); + + /* Save a copy of the target host's name. */ + vx_host = savestring (args, strlen (args)); + + /* Find out the name of the file from which the target was booted + and load its symbol table. */ + + printf_filtered ("Looking in Unix path for all loaded modules:\n"); + bootFile = NULL; + if (!net_get_boot_file (&bootFile)) + { + if (*bootFile) + { + printf_filtered ("\t%s: ", bootFile); + /* This assumes that the kernel is never relocated. Hope that is an + accurate assumption. */ + if (catch_errors + (symbol_stub, + bootFile, + "Error while reading symbols from boot file:\n", + RETURN_MASK_ALL)) + puts_filtered ("ok\n"); + } + else if (from_tty) + printf_unfiltered ("VxWorks kernel symbols not loaded.\n"); + } + else + error ("Can't retrieve boot file name from target machine."); + + clnt_freeres (pClient, xdr_wrapstring, &bootFile); + + if (net_get_symbols (&loadTable) != 0) + error ("Can't read loaded modules from target machine"); + + i = 0-1; + while (++i < loadTable.tbl_size) + { + QUIT; /* FIXME, avoids clnt_freeres below: mem leak */ + pLoadFile = &loadTable.tbl_ent [i]; +#ifdef WRS_ORIG + { + register int desc; + struct cleanup *old_chain; + char *fullname = NULL; + + desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname); + if (desc < 0) + perror_with_name (pLoadFile->name); + old_chain = make_cleanup (close, desc); + add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr, + pLoadFile->bss_addr); + do_cleanups (old_chain); + } +#else + /* FIXME: Is there something better to search than the PATH? (probably + not the source path, since source might be in different directories + than objects. */ + + if (catch_errors (add_symbol_stub, (char *)pLoadFile, (char *)0, + RETURN_MASK_ALL)) + symbols_added = 1; +#endif + } + printf_filtered ("Done.\n"); + + clnt_freeres (pClient, xdr_ldtabl, &loadTable); + + /* Getting new symbols may change our opinion about what is + frameless. */ + if (symbols_added) + reinit_frame_cache (); +} + +/* Takes a task started up outside of gdb and ``attaches'' to it. + This stops it cold in its tracks and allows us to start tracing it. */ + +static void +vx_attach (args, from_tty) + char *args; + int from_tty; +{ + unsigned long pid; + char *cptr = 0; + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int status; + + if (!args) + error_no_arg ("process-id to attach"); + + pid = strtoul (args, &cptr, 0); + if ((cptr == args) || (*cptr != '\0')) + error ("Invalid process-id -- give a single number in decimal or 0xhex"); + + if (from_tty) + printf_unfiltered ("Attaching pid %s.\n", + local_hex_string((unsigned long) pid)); + + memset ((char *)&ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out)); + ptrace_in.pid = pid; + + status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out); + if (status == -1) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Attaching remote process"); + } + + /* It worked... */ + push_target (&vx_run_ops); + /* The unsigned long pid will get turned into a signed int here, + but it doesn't seem to matter. inferior_pid must be signed + in order for other parts of GDB to work correctly. */ + inferior_pid = pid; + vx_running = 0; +#if defined (START_INFERIOR_HOOK) + START_INFERIOR_HOOK (); +#endif + + mark_breakpoints_out (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + + target_terminal_init (); + + /* Install inferior's terminal modes. */ + + target_terminal_inferior (); + + /* We will get a task spawn event immediately. */ + + init_wait_for_inferior (); + clear_proceed_status (); + stop_soon_quietly = 1; + wait_for_inferior (); + stop_soon_quietly = 0; + normal_stop (); +} + + +/* detach_command -- + takes a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +vx_detach (args, from_tty) + char *args; + int from_tty; +{ + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int signal = 0; + int status; + + if (args) + error ("Argument given to VxWorks \"detach\"."); + + if (from_tty) + printf_unfiltered ("Detaching pid %s.\n", + local_hex_string((unsigned long) inferior_pid)); + + if (args) /* FIXME, should be possible to leave suspended */ + signal = atoi (args); + + memset ((char *)&ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out)); + ptrace_in.pid = inferior_pid; + + status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out); + if (status == -1) + error (rpcerr); + if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Detaching VxWorks process"); + } + + inferior_pid = 0; + pop_target (); /* go back to non-executing VxWorks connection */ +} + +/* vx_kill -- takes a running task and wipes it out. */ + +static void +vx_kill () +{ + Rptrace ptrace_in; + Ptrace_return ptrace_out; + int status; + + printf_unfiltered ("Killing pid %s.\n", local_hex_string((unsigned long) inferior_pid)); + + memset ((char *)&ptrace_in, '\0', sizeof (ptrace_in)); + memset ((char *)&ptrace_out, '\0', sizeof (ptrace_out)); + ptrace_in.pid = inferior_pid; + + status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out); + if (status == -1) + warning (rpcerr); + else if (ptrace_out.status == -1) + { + errno = ptrace_out.errno; + perror_with_name ("Killing VxWorks process"); + } + + /* If it gives good status, the process is *gone*, no events remain. + If the kill failed, assume the process is gone anyhow. */ + inferior_pid = 0; + pop_target (); /* go back to non-executing VxWorks connection */ +} + +/* Clean up from the VxWorks process target as it goes away. */ + +static void +vx_proc_close (quitting) + int quitting; +{ + inferior_pid = 0; /* No longer have a process. */ + if (vx_running) + free (vx_running); + vx_running = 0; +} + +/* Make an RPC call to the VxWorks target. + Returns RPC status. */ + +static enum clnt_stat +net_clnt_call (procNum, inProc, in, outProc, out) + enum ptracereq procNum; + xdrproc_t inProc; + char *in; + xdrproc_t outProc; + char *out; +{ + enum clnt_stat status; + + status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout); + + if (status != RPC_SUCCESS) + clnt_perrno (status); + + return status; +} + +/* Clean up before losing control. */ + +static void +vx_close (quitting) + int quitting; +{ + if (pClient) + clnt_destroy (pClient); /* The net connection */ + pClient = 0; + + if (vx_host) + free (vx_host); /* The hostname */ + vx_host = 0; +} + +/* A vxprocess target should be started via "run" not "target". */ +/*ARGSUSED*/ +static void +vx_proc_open (name, from_tty) + char *name; + int from_tty; +{ + error ("Use the \"run\" command to start a VxWorks process."); +} + +/* Target ops structure for accessing memory and such over the net */ + +struct target_ops vx_ops = { + "vxworks", "VxWorks target memory via RPC over TCP/IP", + "Use VxWorks target memory. \n\ +Specify the name of the machine to connect to.", + vx_open, vx_close, vx_attach, 0, /* vx_detach, */ + 0, 0, /* resume, wait */ + 0, 0, /* read_reg, write_reg */ + 0, /* prep_to_store, */ + vx_xfer_memory, vx_files_info, + 0, 0, /* insert_breakpoint, remove_breakpoint */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, /* vx_kill, */ + vx_load_command, + vx_lookup_symbol, + vx_create_inferior, 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* thread_alive */ + 0, /* to_stop */ + core_stratum, 0, /* next */ + 1, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +/* Target ops structure for accessing VxWorks child processes over the net */ + +struct target_ops vx_run_ops = { + "vxprocess", "VxWorks process", + "VxWorks process, started by the \"run\" command.", + vx_proc_open, vx_proc_close, 0, vx_detach, /* vx_attach */ + vx_resume, vx_wait, + vx_read_register, vx_write_register, + vx_prepare_to_store, + vx_xfer_memory, vx_run_files_info, + vx_insert_breakpoint, vx_remove_breakpoint, + 0, 0, 0, 0, 0, /* terminal stuff */ + vx_kill, + vx_load_command, + vx_lookup_symbol, + 0, vx_mourn_inferior, + 0, /* can_run */ + 0, /* notice_signals */ + 0, /* thread_alive */ + 0, /* to_stop */ + process_stratum, 0, /* next */ + 0, /* all_mem--off to avoid spurious msg in "i files" */ + 1, 1, 1, 1, /* mem, stack, regs, exec */ + 0, 0, /* Section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; +/* ==> Remember when reading at end of file, there are two "ops" structs here. */ + +void +_initialize_vx () +{ + add_show_from_set + (add_set_cmd ("vxworks-timeout", class_support, var_uinteger, + (char *) &rpcTimeout.tv_sec, + "Set seconds to wait for rpc calls to return.\n\ +Set the number of seconds to wait for rpc calls to return.", &setlist), + &showlist); + + add_target (&vx_ops); + add_target (&vx_run_ops); +} diff --git a/contrib/gdb/gdb/remote-vx29k.c b/contrib/gdb/gdb/remote-vx29k.c new file mode 100644 index 000000000000..02554aaa31c4 --- /dev/null +++ b/contrib/gdb/gdb/remote-vx29k.c @@ -0,0 +1,188 @@ +/* Am29k-dependent portions of the RPC protocol + used with a VxWorks target + +Contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "defs.h" + +#include "vx-share/regPacket.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include + +#ifdef _AIX /* IBM claims "void *malloc()" not char * */ +#define malloc bogon_malloc +#endif + +#include +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +/* Flag set if target has fpu */ + +extern int target_has_fp; + +/* Generic register read/write routines in remote-vx.c. */ + +extern void net_read_registers (); +extern void net_write_registers (); + +/* Read a register or registers from the VxWorks target. + REGNO is the register to read, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_read_register (regno) + int regno; +{ + char am29k_greg_packet[AM29K_GREG_PLEN]; + char am29k_fpreg_packet[AM29K_FPREG_PLEN]; + + /* Get general-purpose registers. When copying values into + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + net_read_registers (am29k_greg_packet, AM29K_GREG_PLEN, PTRACE_GETREGS); + + /* Now copy the register values into registers[]. + Note that this code depends on the ordering of the REGNUMs + as defined in "tm-29k.h". */ + + bcopy (&am29k_greg_packet[AM29K_R_GR96], + ®isters[REGISTER_BYTE (GR96_REGNUM)], 160 * AM29K_GREG_SIZE); + bcopy (&am29k_greg_packet[AM29K_R_VAB], + ®isters[REGISTER_BYTE (VAB_REGNUM)], 15 * AM29K_GREG_SIZE); + registers[REGISTER_BYTE (INTE_REGNUM)] = am29k_greg_packet[AM29K_R_INTE]; + bcopy (&am29k_greg_packet[AM29K_R_RSP], + ®isters[REGISTER_BYTE (GR1_REGNUM)], 5 * AM29K_GREG_SIZE); + + /* PAD For now, don't care about exop register */ + + memset (®isters[REGISTER_BYTE (EXO_REGNUM)], '\0', AM29K_GREG_SIZE); + + /* If the target has floating point registers, fetch them. + Otherwise, zero the floating point register values in + registers[] for good measure, even though we might not + need to. */ + + if (target_has_fp) + { + net_read_registers (am29k_fpreg_packet, AM29K_FPREG_PLEN, + PTRACE_GETFPREGS); + registers[REGISTER_BYTE (FPE_REGNUM)] = am29k_fpreg_packet[AM29K_R_FPE]; + registers[REGISTER_BYTE (FPS_REGNUM)] = am29k_fpreg_packet[AM29K_R_FPS]; + + /* PAD For now, don't care about registers (?) AI0 to q */ + + memset (®isters[REGISTER_BYTE (161)], '\0', 21 * AM29K_FPREG_SIZE); + } + else + { + memset (®isters[REGISTER_BYTE (FPE_REGNUM)], '\0', AM29K_FPREG_SIZE); + memset (®isters[REGISTER_BYTE (FPS_REGNUM)], '\0', AM29K_FPREG_SIZE); + + /* PAD For now, don't care about registers (?) AI0 to q */ + + memset (®isters[REGISTER_BYTE (161)], '\0', 21 * AM29K_FPREG_SIZE); + } + + /* Mark the register cache valid. */ + + registers_fetched (); +} + +/* Store a register or registers into the VxWorks target. + REGNO is the register to store, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_write_register (regno) + int regno; +{ + char am29k_greg_packet[AM29K_GREG_PLEN]; + char am29k_fpreg_packet[AM29K_FPREG_PLEN]; + + /* Store general purpose registers. When copying values from + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + bcopy (®isters[REGISTER_BYTE (GR96_REGNUM)], + &am29k_greg_packet[AM29K_R_GR96], 160 * AM29K_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (VAB_REGNUM)], + &am29k_greg_packet[AM29K_R_VAB], 15 * AM29K_GREG_SIZE); + am29k_greg_packet[AM29K_R_INTE] = registers[REGISTER_BYTE (INTE_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (GR1_REGNUM)], + &am29k_greg_packet[AM29K_R_RSP], 5 * AM29K_GREG_SIZE); + + net_write_registers (am29k_greg_packet, AM29K_GREG_PLEN, PTRACE_SETREGS); + + /* Store floating point registers if the target has them. */ + + if (target_has_fp) + { + am29k_fpreg_packet[AM29K_R_FPE] = registers[REGISTER_BYTE (FPE_REGNUM)]; + am29k_fpreg_packet[AM29K_R_FPS] = registers[REGISTER_BYTE (FPS_REGNUM)]; + + net_write_registers (am29k_fpreg_packet, AM29K_FPREG_PLEN, + PTRACE_SETFPREGS); + } +} + +/* VxWorks zeroes fp when the task is initialized; we use this + to terminate the frame chain. Chain means here the nominal address of + a frame, that is, the return address (lr0) address in the stack. To + obtain the frame pointer (lr1) contents, we must add 4 bytes. + Note : may be we should modify init_frame_info() to get the frame pointer + and store it into the frame_info struct rather than reading its + contents when FRAME_CHAIN_VALID is invoked. */ + +int +get_fp_contents (chain, thisframe) + CORE_ADDR chain; + struct frame_info *thisframe; /* not used here */ +{ + int fp_contents; + + read_memory ((CORE_ADDR)(chain + 4), (char *) &fp_contents, 4); + return (fp_contents != 0); +} + diff --git a/contrib/gdb/gdb/remote-vx68.c b/contrib/gdb/gdb/remote-vx68.c new file mode 100644 index 000000000000..c6ceda18e053 --- /dev/null +++ b/contrib/gdb/gdb/remote-vx68.c @@ -0,0 +1,158 @@ +/* 68k-dependent portions of the RPC protocol + used with a VxWorks target + +Contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "defs.h" + +#include "vx-share/regPacket.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include + +#ifdef _AIX /* IBM claims "void *malloc()" not char * */ +#define malloc bogon_malloc +#endif + +#include + +#ifdef _AIX +#undef malloc +#endif + +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +/* Flag set if target has fpu */ + +extern int target_has_fp; + +/* Generic register read/write routines in remote-vx.c. */ + +extern void net_read_registers (); +extern void net_write_registers (); + +/* Read a register or registers from the VxWorks target. + REGNO is the register to read, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_read_register (regno) + int regno; +{ + char mc68k_greg_packet[MC68K_GREG_PLEN]; + char mc68k_fpreg_packet[MC68K_FPREG_PLEN]; + + /* Get general-purpose registers. */ + + net_read_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_GETREGS); + + bcopy (&mc68k_greg_packet[MC68K_R_D0], registers, 16 * MC68K_GREG_SIZE); + bcopy (&mc68k_greg_packet[MC68K_R_SR], ®isters[REGISTER_BYTE (PS_REGNUM)], + MC68K_GREG_SIZE); + bcopy (&mc68k_greg_packet[MC68K_R_PC], ®isters[REGISTER_BYTE (PC_REGNUM)], + MC68K_GREG_SIZE); + + /* Get floating-point registers, if the target system has them. + Otherwise, zero them. */ + + if (target_has_fp) + { + net_read_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN, + PTRACE_GETFPREGS); + + bcopy (&mc68k_fpreg_packet[MC68K_R_FP0], + ®isters[REGISTER_BYTE (FP0_REGNUM)], + MC68K_FPREG_SIZE * 8); + bcopy (&mc68k_fpreg_packet[MC68K_R_FPCR], + ®isters[REGISTER_BYTE (FPC_REGNUM)], + MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8)); + } + else + { + bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], + MC68K_FPREG_SIZE * 8); + bzero (®isters[REGISTER_BYTE (FPC_REGNUM)], + MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8)); + } + + /* Mark the register cache valid. */ + + registers_fetched (); +} + +/* Store a register or registers into the VxWorks target. + REGNO is the register to store, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_write_register (regno) + int regno; +{ + char mc68k_greg_packet[MC68K_GREG_PLEN]; + char mc68k_fpreg_packet[MC68K_FPREG_PLEN]; + + /* Store general-purpose registers. */ + + bcopy (registers, &mc68k_greg_packet[MC68K_R_D0], 16 * MC68K_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (PS_REGNUM)], + &mc68k_greg_packet[MC68K_R_SR], MC68K_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (PC_REGNUM)], + &mc68k_greg_packet[MC68K_R_PC], MC68K_GREG_SIZE); + + net_write_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_SETREGS); + + /* Store floating point registers if the target has them. */ + + if (target_has_fp) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &mc68k_fpreg_packet[MC68K_R_FP0], + MC68K_FPREG_SIZE * 8); + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &mc68k_fpreg_packet[MC68K_R_FPCR], + MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8)); + + net_write_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN, + PTRACE_SETFPREGS); + } +} diff --git a/contrib/gdb/gdb/remote-vx960.c b/contrib/gdb/gdb/remote-vx960.c new file mode 100644 index 000000000000..bb4fbee61673 --- /dev/null +++ b/contrib/gdb/gdb/remote-vx960.c @@ -0,0 +1,163 @@ +/* i80960-dependent portions of the RPC protocol + used with a VxWorks target + +Contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "defs.h" + +#include "vx-share/regPacket.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include + +#ifdef _AIX /* IBM claims "void *malloc()" not char * */ +#define malloc bogon_malloc +#endif + +#include +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +/* Flag set if target has fpu */ + +extern int target_has_fp; + +/* 960 floating point format descriptor, from "i960-tdep.c." */ + +extern struct ext_format ext_format_i960; + +/* Generic register read/write routines in remote-vx.c. */ + +extern void net_read_registers (); +extern void net_write_registers (); + +/* Read a register or registers from the VxWorks target. + REGNO is the register to read, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_read_register (regno) + int regno; +{ + char i960_greg_packet[I960_GREG_PLEN]; + char i960_fpreg_packet[I960_FPREG_PLEN]; + + /* Get general-purpose registers. When copying values into + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + net_read_registers (i960_greg_packet, I960_GREG_PLEN, PTRACE_GETREGS); + + bcopy (&i960_greg_packet[I960_R_R0], + ®isters[REGISTER_BYTE (R0_REGNUM)], 16 * I960_GREG_SIZE); + bcopy (&i960_greg_packet[I960_R_G0], + ®isters[REGISTER_BYTE (G0_REGNUM)], 16 * I960_GREG_SIZE); + bcopy (&i960_greg_packet[I960_R_PCW], + ®isters[REGISTER_BYTE (PCW_REGNUM)], sizeof (int)); + bcopy (&i960_greg_packet[I960_R_ACW], + ®isters[REGISTER_BYTE (ACW_REGNUM)], sizeof (int)); + bcopy (&i960_greg_packet[I960_R_TCW], + ®isters[REGISTER_BYTE (TCW_REGNUM)], sizeof (int)); + + /* If the target has floating point registers, fetch them. + Otherwise, zero the floating point register values in + registers[] for good measure, even though we might not + need to. */ + + if (target_has_fp) + { + net_read_registers (i960_fpreg_packet, I960_FPREG_PLEN, + PTRACE_GETFPREGS); + bcopy (&i960_fpreg_packet[I960_R_FP0], + ®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 4); + } + else + bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 4); + + /* Mark the register cache valid. */ + + registers_fetched (); +} + +/* Store a register or registers into the VxWorks target. + REGNO is the register to store, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_write_register (regno) + int regno; +{ + char i960_greg_packet[I960_GREG_PLEN]; + char i960_fpreg_packet[I960_FPREG_PLEN]; + + /* Store floating-point registers. When copying values from + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + bcopy (®isters[REGISTER_BYTE (R0_REGNUM)], + &i960_greg_packet[I960_R_R0], 16 * I960_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], + &i960_greg_packet[I960_R_G0], 16 * I960_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)], + &i960_greg_packet[I960_R_PCW], sizeof (int)); + bcopy (®isters[REGISTER_BYTE (ACW_REGNUM)], + &i960_greg_packet[I960_R_ACW], sizeof (int)); + bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)], + &i960_greg_packet[I960_R_TCW], sizeof (int)); + + net_write_registers (i960_greg_packet, I960_GREG_PLEN, PTRACE_SETREGS); + + /* Store floating point registers if the target has them. */ + + if (target_has_fp) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &i960_fpreg_packet[I960_R_FP0], + REGISTER_RAW_SIZE (FP0_REGNUM) * 4); + + net_write_registers (i960_fpreg_packet, I960_FPREG_PLEN, + PTRACE_SETFPREGS); + } +} + diff --git a/contrib/gdb/gdb/remote-vxmips.c b/contrib/gdb/gdb/remote-vxmips.c new file mode 100644 index 000000000000..c65ac015ead7 --- /dev/null +++ b/contrib/gdb/gdb/remote-vxmips.c @@ -0,0 +1,201 @@ +/* MIPS-dependent portions of the RPC protocol + used with a VxWorks target + +Contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "defs.h" + +#include "vx-share/regPacket.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include +#include +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +/* Flag set if target has fpu */ + +extern int target_has_fp; + +/* Generic register read/write routines in remote-vx.c. */ + +extern void net_read_registers (); +extern void net_write_registers (); + +/* Read a register or registers from the VxWorks target. + REGNO is the register to read, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_read_register (regno) + int regno; +{ + char mips_greg_packet[MIPS_GREG_PLEN]; + char mips_fpreg_packet[MIPS_FPREG_PLEN]; + + /* Get general-purpose registers. */ + + net_read_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_GETREGS); + + /* this code copies the registers obtained by RPC + stored in a structure(s) like this : + + Register(s) Offset(s) + gp 0-31 0x00 + hi 0x80 + lo 0x84 + sr 0x88 + pc 0x8c + + into a stucture like this: + + 0x00 GP 0-31 + 0x80 SR + 0x84 LO + 0x88 HI + 0x8C BAD --- Not available currently + 0x90 CAUSE --- Not available currently + 0x94 PC + 0x98 FP 0-31 + 0x118 FCSR + 0x11C FIR --- Not available currently + 0x120 FP --- Not available currently + + structure is 0x124 (292) bytes in length */ + + /* Copy the general registers. */ + + bcopy (&mips_greg_packet[MIPS_R_GP0], ®isters[0], 32 * MIPS_GREG_SIZE); + + /* Copy SR, LO, HI, and PC. */ + + bcopy (&mips_greg_packet[MIPS_R_SR], + ®isters[REGISTER_BYTE (PS_REGNUM)], MIPS_GREG_SIZE); + bcopy (&mips_greg_packet[MIPS_R_LO], + ®isters[REGISTER_BYTE (LO_REGNUM)], MIPS_GREG_SIZE); + bcopy (&mips_greg_packet[MIPS_R_HI], + ®isters[REGISTER_BYTE (HI_REGNUM)], MIPS_GREG_SIZE); + bcopy (&mips_greg_packet[MIPS_R_PC], + ®isters[REGISTER_BYTE (PC_REGNUM)], MIPS_GREG_SIZE); + + /* If the target has floating point registers, fetch them. + Otherwise, zero the floating point register values in + registers[] for good measure, even though we might not + need to. */ + + if (target_has_fp) + { + net_read_registers (mips_fpreg_packet, MIPS_FPREG_PLEN, + PTRACE_GETFPREGS); + + /* Copy the floating point registers. */ + + bcopy (&mips_fpreg_packet[MIPS_R_FP0], + ®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 32); + + /* Copy the floating point control/status register (fpcsr). */ + + bcopy (&mips_fpreg_packet[MIPS_R_FPCSR], + ®isters[REGISTER_BYTE (FCRCS_REGNUM)], + REGISTER_RAW_SIZE (FCRCS_REGNUM)); + } + else + { + bzero ((char *) ®isters[REGISTER_BYTE (FP0_REGNUM)], + REGISTER_RAW_SIZE (FP0_REGNUM) * 32); + bzero ((char *) ®isters[REGISTER_BYTE (FCRCS_REGNUM)], + REGISTER_RAW_SIZE (FCRCS_REGNUM)); + } + + /* Mark the register cache valid. */ + + registers_fetched (); +} + +/* Store a register or registers into the VxWorks target. + REGNO is the register to store, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +vx_write_register (regno) + int regno; +{ + char mips_greg_packet[MIPS_GREG_PLEN]; + char mips_fpreg_packet[MIPS_FPREG_PLEN]; + + /* Store general registers. */ + + bcopy (®isters[0], &mips_greg_packet[MIPS_R_GP0], 32 * MIPS_GREG_SIZE); + + /* Copy SR, LO, HI, and PC. */ + + bcopy (®isters[REGISTER_BYTE (PS_REGNUM)], + &mips_greg_packet[MIPS_R_SR], MIPS_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (LO_REGNUM)], + &mips_greg_packet[MIPS_R_LO], MIPS_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (HI_REGNUM)], + &mips_greg_packet[MIPS_R_HI], MIPS_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (PC_REGNUM)], + &mips_greg_packet[MIPS_R_PC], MIPS_GREG_SIZE); + + net_write_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_SETREGS); + + /* Store floating point registers if the target has them. */ + + if (target_has_fp) + { + /* Copy the floating point data registers. */ + + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &mips_fpreg_packet[MIPS_R_FP0], + REGISTER_RAW_SIZE (FP0_REGNUM) * 32); + + /* Copy the floating point control/status register (fpcsr). */ + + bcopy (®isters[REGISTER_BYTE (FCRCS_REGNUM)], + &mips_fpreg_packet[MIPS_R_FPCSR], + REGISTER_RAW_SIZE (FCRCS_REGNUM)); + + net_write_registers (mips_fpreg_packet, MIPS_FPREG_PLEN, + PTRACE_SETFPREGS); + } +} diff --git a/contrib/gdb/gdb/remote-vxsparc.c b/contrib/gdb/gdb/remote-vxsparc.c new file mode 100644 index 000000000000..068254240fab --- /dev/null +++ b/contrib/gdb/gdb/remote-vxsparc.c @@ -0,0 +1,196 @@ +/* sparc-dependent portions of the RPC protocol + used with a VxWorks target + +Contributed by Wind River Systems. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "defs.h" + +#include "vx-share/regPacket.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" +#include "target.h" +#include "gdbcore.h" +#include "command.h" +#include "symtab.h" +#include "symfile.h" /* for struct complaint */ + +#include "gdb_string.h" +#include +#include +#include +#include +#include +#include + +#ifdef _AIX /* IBM claims "void *malloc()" not char * */ +#define malloc bogon_malloc +#endif + +#include +#include /* UTek's doesn't #incl this */ +#include +#include "vx-share/ptrace.h" +#include "vx-share/xdr_ptrace.h" +#include "vx-share/xdr_ld.h" +#include "vx-share/xdr_rdb.h" +#include "vx-share/dbgRpcLib.h" + +/* get rid of value.h if possible */ +#include +#include + +/* Flag set if target has fpu */ + +extern int target_has_fp; + +/* sparc floating point format descriptor, from "sparc-tdep.c." */ + +extern struct ext_format ext_format_sparc; + +/* Generic register read/write routines in remote-vx.c. */ + +extern void net_read_registers (); +extern void net_write_registers (); + +/* Read a register or registers from the VxWorks target. + REGNO is the register to read, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_read_register (regno) + int regno; +{ + char sparc_greg_packet[SPARC_GREG_PLEN]; + char sparc_fpreg_packet[SPARC_FPREG_PLEN]; + CORE_ADDR sp; + + /* Get general-purpose registers. When copying values into + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + net_read_registers (sparc_greg_packet, SPARC_GREG_PLEN, PTRACE_GETREGS); + + /* Now copy the register values into registers[]. + Note that this code depends on the ordering of the REGNUMs + as defined in "tm-sparc.h". */ + + bcopy (&sparc_greg_packet[SPARC_R_G0], + ®isters[REGISTER_BYTE (G0_REGNUM)], 32 * SPARC_GREG_SIZE); + bcopy (&sparc_greg_packet[SPARC_R_Y], + ®isters[REGISTER_BYTE (Y_REGNUM)], 6 * SPARC_GREG_SIZE); + + /* Now write the local and in registers to the register window + spill area in the frame. VxWorks does not do this for the + active frame automatically; it greatly simplifies debugging + (FRAME_FIND_SAVED_REGS, in particular, depends on this). */ + + sp = extract_address (®isters[REGISTER_BYTE (SP_REGNUM)], + REGISTER_RAW_SIZE (CORE_ADDR)); + write_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], + 16 * REGISTER_RAW_SIZE (L0_REGNUM)); + + /* If the target has floating point registers, fetch them. + Otherwise, zero the floating point register values in + registers[] for good measure, even though we might not + need to. */ + + if (target_has_fp) + { + net_read_registers (sparc_fpreg_packet, SPARC_FPREG_PLEN, + PTRACE_GETFPREGS); + bcopy (&sparc_fpreg_packet[SPARC_R_FP0], + ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * SPARC_FPREG_SIZE); + bcopy (&sparc_fpreg_packet[SPARC_R_FSR], + ®isters[REGISTER_BYTE (FPS_REGNUM)], 1 * SPARC_FPREG_SIZE); + } + else + { + bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * SPARC_FPREG_SIZE); + bzero (®isters[REGISTER_BYTE (FPS_REGNUM)], 1 * SPARC_FPREG_SIZE); + } + + /* Mark the register cache valid. */ + + registers_fetched (); +} + +/* Store a register or registers into the VxWorks target. + REGNO is the register to store, or -1 for all; currently, + it is ignored. FIXME look at regno to improve efficiency. */ + +void +vx_write_register (regno) + int regno; +{ + char sparc_greg_packet[SPARC_GREG_PLEN]; + char sparc_fpreg_packet[SPARC_FPREG_PLEN]; + int in_gp_regs; + int in_fp_regs; + CORE_ADDR sp; + + /* Store general purpose registers. When copying values from + registers [], don't assume that a location in registers [] + is properly aligned for the target data type. */ + + in_gp_regs = 1; + in_fp_regs = 1; + if (regno >= 0) + { + if ((G0_REGNUM <= regno && regno <= I7_REGNUM) + || (Y_REGNUM <= regno && regno <= NPC_REGNUM)) + in_fp_regs = 0; + else + in_gp_regs = 0; + } + if (in_gp_regs) + { + bcopy (®isters[REGISTER_BYTE (G0_REGNUM)], + &sparc_greg_packet[SPARC_R_G0], 32 * SPARC_GREG_SIZE); + bcopy (®isters[REGISTER_BYTE (Y_REGNUM)], + &sparc_greg_packet[SPARC_R_Y], 6 * SPARC_GREG_SIZE); + + net_write_registers (sparc_greg_packet, SPARC_GREG_PLEN, PTRACE_SETREGS); + + /* If this is a local or in register, or we're storing all + registers, update the register window spill area. */ + + if (regno < 0 || (L0_REGNUM <= regno && regno <= I7_REGNUM)) + { + sp = extract_address (®isters[REGISTER_BYTE (SP_REGNUM)], + REGISTER_RAW_SIZE (CORE_ADDR)); + write_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], + 16 * REGISTER_RAW_SIZE (L0_REGNUM)); + } + } + + /* Store floating point registers if the target has them. */ + + if (in_fp_regs && target_has_fp) + { + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], + &sparc_fpreg_packet[SPARC_R_FP0], 32 * SPARC_FPREG_SIZE); + bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)], + &sparc_fpreg_packet[SPARC_R_FSR], 1 * SPARC_FPREG_SIZE); + + net_write_registers (sparc_fpreg_packet, SPARC_FPREG_PLEN, + PTRACE_SETFPREGS); + } +} diff --git a/contrib/gdb/gdb/remote.c b/contrib/gdb/gdb/remote.c new file mode 100644 index 000000000000..5356e5e459b6 --- /dev/null +++ b/contrib/gdb/gdb/remote.c @@ -0,0 +1,1839 @@ +/* Remote target communications for serial-line targets in custom GDB protocol + Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* 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: + Most values are encoded in ascii hex digits. Signal numbers are according + to the numbering in target.h. + + Request Packet + + set thread Hct... Set thread for subsequent operations. + c = 'c' for thread used in step and + continue; t... can be -1 for all + threads. + c = 'g' for thread used in other + operations. If zero, pick a thread, + any thread. + reply OK for success + ENN for an error. + + 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). + + continue 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. + + continue with Csig;AA Continue with signal sig (hex signal + signal number). + + step with Ssig;AA Like 'C' but step not continue. + signal + + 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. + + detach D Reply OK. + + 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 (hex) + r... = register contents + n... = `thread' + r... = thread process ID. This is + a hex integer. + n... = other string not starting + with valid hex digit. + gdb should ignore this n,r pair + and go on to the next. This way + we can extend the protocol. + or... WAA The process exited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + or... XAA The process terminated with signal + AA. + or... OXX..XX XX..XX is hex encoding of ASCII data. This + can happen at any time while the program is + running and the debugger should + continue to wait for 'W', 'T', etc. + + thread alive TXX Find out if the thread XX is alive. + reply OK thread is still alive + ENN thread is dead + + remote restart RXX Restart the remote server + + extended ops ! Use the extended remote protocol. + Sticky -- only needs to be set once. + + 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 + + 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 "defs.h" +#include "gdb_string.h" +#include +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "wait.h" +/*#include "terminal.h"*/ +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "thread.h" + +#include "dcache.h" + +#ifdef USG +#include +#endif + +#include +#include "serial.h" + +/* Prototypes for local functions */ + +static int remote_write_bytes PARAMS ((CORE_ADDR memaddr, + char *myaddr, int len)); + +static int remote_read_bytes PARAMS ((CORE_ADDR memaddr, + char *myaddr, int len)); + +static void remote_files_info PARAMS ((struct target_ops *ignore)); + +static int remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int should_write, + struct target_ops *target)); + +static void remote_prepare_to_store PARAMS ((void)); + +static void remote_fetch_registers PARAMS ((int regno)); + +static void remote_resume PARAMS ((int pid, int step, + enum target_signal siggnal)); + +static int remote_start_remote PARAMS ((char *dummy)); + +static void remote_open PARAMS ((char *name, int from_tty)); + +static void extended_remote_open PARAMS ((char *name, int from_tty)); + +static void remote_open_1 PARAMS ((char *, int, struct target_ops *)); + +static void remote_close PARAMS ((int quitting)); + +static void remote_store_registers PARAMS ((int regno)); + +static void remote_mourn PARAMS ((void)); + +static void extended_remote_restart PARAMS ((void)); + +static void extended_remote_mourn PARAMS ((void)); + +static void extended_remote_create_inferior PARAMS ((char *, char *, char **)); + +static void remote_mourn_1 PARAMS ((struct target_ops *)); + +static void getpkt PARAMS ((char *buf, int forever)); + +static int putpkt PARAMS ((char *buf)); + +static void remote_send PARAMS ((char *buf)); + +static int readchar PARAMS ((int timeout)); + +static int remote_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static void remote_kill PARAMS ((void)); + +static int tohex PARAMS ((int nib)); + +static int fromhex PARAMS ((int a)); + +static void remote_detach PARAMS ((char *args, int from_tty)); + +static void remote_interrupt PARAMS ((int signo)); + +static void remote_interrupt_twice PARAMS ((int signo)); + +static void interrupt_query PARAMS ((void)); + +extern struct target_ops remote_ops; /* Forward decl */ +extern struct target_ops extended_remote_ops; /* Forward decl */ + +/* This was 5 seconds, which is a long time to sit and wait. + Unless this is going though some terminal server or multiplexer or + other form of hairy serial connection, I would think 2 seconds would + be plenty. */ + +static int remote_timeout = 2; + +/* This variable chooses whether to send a ^C or a break when the user + requests program interruption. Although ^C is usually what remote + systems expect, and that is the default here, sometimes a break is + preferable instead. */ + +static int remote_break; + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that + remote_open knows that we don't have a file open when the program + starts. */ +serial_t remote_desc = NULL; + +/* Having this larger than 400 causes us to be incompatible with m68k-stub.c + and i386-stub.c. Normally, no one would notice because it only matters + for writing large chunks of memory (e.g. in downloads). Also, this needs + to be more than 400 if required to hold the registers (see below, where + we round it up based on REGISTER_BYTES). */ +#define PBUFSIZ 400 + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES ((PBUFSIZ-32)/2) + +/* Round up PBUFSIZ to hold all the registers, at least. */ +/* The blank line after the #if seems to be required to work around a + bug in HP's PA compiler. */ +#if REGISTER_BYTES > MAXBUFBYTES + +#undef PBUFSIZ +#define PBUFSIZ (REGISTER_BYTES * 2 + 32) +#endif + +/* Should we try the 'P' request? If this is set to one when the stub + doesn't support 'P', the only consequence is some unnecessary traffic. */ +static int stub_supports_P = 1; + + +/* These are the threads which we last sent to the remote system. -1 for all + or -2 for not sent yet. */ +int general_thread; +int cont_thread; + +static void +set_thread (th, gen) + int th; + int gen; +{ + char buf[PBUFSIZ]; + int state = gen ? general_thread : cont_thread; + if (state == th) + return; + buf[0] = 'H'; + buf[1] = gen ? 'g' : 'c'; + if (th == 42000) + { + buf[2] = '0'; + buf[3] = '\0'; + } + else if (th < 0) + sprintf (&buf[2], "-%x", -th); + else + sprintf (&buf[2], "%x", th); + putpkt (buf); + getpkt (buf, 0); + if (gen) + general_thread = th; + else + cont_thread = th; +} + +/* Return nonzero if the thread TH is still alive on the remote system. */ + +static int +remote_thread_alive (th) + int th; +{ + char buf[PBUFSIZ]; + + buf[0] = 'T'; + if (th < 0) + sprintf (&buf[1], "-%x", -th); + else + sprintf (&buf[1], "%x", th); + putpkt (buf); + getpkt (buf, 0); + return (buf[0] == 'O' && buf[1] == 'K'); +} + +/* Restart the remote side; this is an extended protocol operation. */ + +static void +extended_remote_restart () +{ + char buf[PBUFSIZ]; + + /* Send the restart command; for reasons I don't understand the + remote side really expects a number after the "R". */ + buf[0] = 'R'; + sprintf (&buf[1], "%x", 0); + putpkt (buf); + + /* Now query for status so this looks just like we restarted + gdbserver from scratch. */ + putpkt ("?"); + getpkt (buf, 0); +} + +/* Clean up connection to a remote debugger. */ + +/* ARGSUSED */ +static void +remote_close (quitting) + int quitting; +{ + if (remote_desc) + SERIAL_CLOSE (remote_desc); + remote_desc = NULL; +} + +/* Query the remote side for the text, data and bss offsets. */ + +static void +get_offsets () +{ + char buf[PBUFSIZ]; + int nvals; + CORE_ADDR text_addr, data_addr, bss_addr; + struct section_offsets *offs; + + putpkt ("qOffsets"); + + getpkt (buf, 0); + + if (buf[0] == '\000') + return; /* Return silently. Stub doesn't support this + command. */ + if (buf[0] == 'E') + { + warning ("Remote failure reply: %s", buf); + return; + } + + nvals = sscanf (buf, "Text=%lx;Data=%lx;Bss=%lx", &text_addr, &data_addr, + &bss_addr); + if (nvals != 3) + error ("Malformed response to offset query, %s", buf); + + if (symfile_objfile == NULL) + return; + + offs = (struct section_offsets *) alloca (sizeof (struct section_offsets) + + symfile_objfile->num_sections + * sizeof (offs->offsets)); + memcpy (offs, symfile_objfile->section_offsets, + sizeof (struct section_offsets) + + symfile_objfile->num_sections + * sizeof (offs->offsets)); + + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr; + + /* This is a temporary kludge to force data and bss to use the same offsets + because that's what nlmconv does now. The real solution requires changes + to the stub and remote.c that I don't have time to do right now. */ + + ANOFFSET (offs, SECT_OFF_DATA) = data_addr; + ANOFFSET (offs, SECT_OFF_BSS) = data_addr; + + objfile_relocate (symfile_objfile, offs); +} + +/* Stub for catch_errors. */ + +static int +remote_start_remote (dummy) + char *dummy; +{ + immediate_quit = 1; /* Allow user to interrupt it */ + + /* Ack any packet which the remote side has already sent. */ + SERIAL_WRITE (remote_desc, "+", 1); + + /* Let the stub know that we want it to return the thread. */ + set_thread (-1, 0); + + get_offsets (); /* Get text, data & bss offsets */ + + putpkt ("?"); /* initiate a query from remote machine */ + immediate_quit = 0; + + start_remote (); /* Initialize gdb process mechanisms */ + return 1; +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + remote_open_1 (name, from_tty, &remote_ops); +} + +/* Open a connection to a remote debugger using the extended + remote gdb protocol. NAME is the filename used for communication. */ + +static void +extended_remote_open (name, from_tty) + char *name; + int from_tty; +{ + char buf[PBUFSIZ]; + + /* Do the basic remote open stuff. */ + remote_open_1 (name, from_tty, &extended_remote_ops); + + /* Now tell the remote that we're using the extended protocol. */ + putpkt ("!"); + getpkt (buf, 0); + +} + +/* Generic code for opening a connection to a remote target. */ +static DCACHE *remote_dcache; + +static void +remote_open_1 (name, from_tty, target) + char *name; + int from_tty; + struct target_ops *target; +{ + if (name == 0) + error ("To open a remote debug connection, you need to specify what serial\n\ +device is attached to the remote system (e.g. /dev/ttya)."); + + target_preopen (from_tty); + + unpush_target (target); + + remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); + + remote_desc = SERIAL_OPEN (name); + if (!remote_desc) + perror_with_name (name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (remote_desc, baud_rate)) + { + SERIAL_CLOSE (remote_desc); + perror_with_name (name); + } + } + + + SERIAL_RAW (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + push_target (target); /* Switch to using remote target now */ + + /* Start out by trying the 'P' request to set registers. We set this each + time that we open a new target so that if the user switches from one + stub to another, we can (if the target is closed and reopened) cope. */ + stub_supports_P = 1; + + general_thread = -2; + cont_thread = -2; + + /* 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_pid = 42000; + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, (char *)0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + pop_target(); +} + +/* This takes a program previously attached to and detaches it. After + this is done, GDB can be used to debug some other program. We + better not have left any breakpoints in the target program or it'll + die when it hits one. */ + +static void +remote_detach (args, from_tty) + char *args; + int from_tty; +{ + char buf[PBUFSIZ]; + + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + /* Tell the remote target to detach. */ + strcpy (buf, "D"); + remote_send (buf); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit %d", a); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0'+nib; + else + return 'a'+nib-10; +} + +/* Tell the remote machine to resume. */ + +static enum target_signal last_sent_signal = TARGET_SIGNAL_0; +int last_sent_step; + +static void +remote_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + char buf[PBUFSIZ]; + + if (pid == -1) + set_thread (inferior_pid, 0); + else + set_thread (pid, 0); + + dcache_flush (remote_dcache); + + last_sent_signal = siggnal; + last_sent_step = step; + + if (siggnal != TARGET_SIGNAL_0) + { + buf[0] = step ? 'S' : 'C'; + buf[1] = tohex (((int)siggnal >> 4) & 0xf); + buf[2] = tohex ((int)siggnal & 0xf); + buf[3] = '\0'; + } + else + strcpy (buf, step ? "s": "c"); + + putpkt (buf); +} + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +remote_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, remote_interrupt_twice); + + if (remote_debug) + printf_unfiltered ("remote_interrupt called\n"); + + /* Send a break or a ^C, depending on user preference. */ + if (remote_break) + SERIAL_SEND_BREAK (remote_desc); + else + SERIAL_WRITE (remote_desc, "\003", 1); +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +remote_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + interrupt_query (); + + signal (signo, remote_interrupt); +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +interrupt_query () +{ + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); +} + +/* If nonzero, ignore the next kill. */ +int kill_kludge; + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + Returns "pid" (though it's not clear what, if anything, that + means in the case of this target). */ + +static int +remote_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + unsigned char buf[PBUFSIZ]; + int thread_num = -1; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + while (1) + { + unsigned char *p; + + ofunc = (void (*)()) signal (SIGINT, remote_interrupt); + getpkt ((char *) buf, 1); + signal (SIGINT, ofunc); + + switch (buf[0]) + { + case 'E': /* Error of some sort */ + warning ("Remote failure reply: %s", buf); + continue; + case 'T': /* Status with PC, SP, FP, ... */ + { + int i; + long regno; + char regs[MAX_REGISTER_RAW_SIZE]; + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + char *p_temp; + + regno = strtol ((const char *) p, &p_temp, 16); /* Read the register number */ + p1 = (unsigned char *)p_temp; + + if (p1 == p) + { + p1 = (unsigned char *) strchr ((const char *) p, ':'); + if (p1 == NULL) + warning ("Malformed packet (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + if (strncmp ((const char *) p, "thread", p1 - p) == 0) + { + thread_num = strtol ((const char *) ++p1, &p_temp, 16); + p = (unsigned char *)p_temp; + } + } + else + { + p = p1; + + if (*p++ != ':') + warning ("Malformed packet (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + + if (regno >= NUM_REGS) + warning ("Remote sent bad register number %ld: %s\n\ +Packet: '%s'\n", + regno, p, buf); + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) + { + if (p[0] == 0 || p[1] == 0) + warning ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + supply_register (regno, regs); + } + + if (*p++ != ';') + warning ("Remote register badly formatted: %s", buf); + } + } + /* fall through */ + case 'S': /* Old style status, just signal only */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + goto got_status; + case 'W': /* Target exited */ + { + /* The remote process exited. */ + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]); + goto got_status; + } + case 'X': + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + kill_kludge = 1; + + goto got_status; + case 'O': /* Console output */ + for (p = buf + 1; *p; p +=2) + { + char tb[2]; + char c = fromhex (p[0]) * 16 + fromhex (p[1]); + tb[0] = c; + tb[1] = 0; + if (target_output_hook) + target_output_hook (tb); + else + fputs_filtered (tb, gdb_stdout); + } + continue; + case '\0': + if (last_sent_signal != TARGET_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; + target_terminal_inferior (); + + strcpy ((char *) buf, last_sent_step ? "s" : "c"); + putpkt ((char *) buf); + continue; + } + /* else fallthrough */ + default: + warning ("Invalid remote reply: %s", buf); + continue; + } + } + got_status: + if (thread_num != -1) + { + /* Initial thread value can only be acquired via wait, so deal with + this marker which is used before the first thread value is + acquired. */ + if (inferior_pid == 42000) + { + inferior_pid = thread_num; + add_thread (inferior_pid); + } + return thread_num; + } + return inferior_pid; +} + +/* Number of bytes of registers this stub implements. */ +static int register_bytes_found; + +/* Read the remote registers into the block REGS. */ +/* Currently we just read all the registers, so we don't use regno. */ +/* ARGSUSED */ +static void +remote_fetch_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + char regs[REGISTER_BYTES]; + + set_thread (inferior_pid, 1); + + sprintf (buf, "g"); + remote_send (buf); + + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + + /* We can get out of synch in various cases. If the first character + in the buffer is not a hex character, assume that has happened + and try to fetch another packet to read. */ + while ((buf[0] < '0' || buf[0] > '9') + && (buf[0] < 'a' || buf[0] > 'f')) + { + if (remote_debug) + printf_unfiltered ("Bad register packet; fetching a new packet\n"); + getpkt (buf, 0); + } + + /* Reply describes registers byte by byte, each byte encoded as two + hex characters. Suck them all up, then supply them to the + register cacheing/storage mechanism. */ + + p = buf; + for (i = 0; i < REGISTER_BYTES; i++) + { + if (p[0] == 0) + break; + if (p[1] == 0) + { + warning ("Remote reply is of odd length: %s", buf); + /* Don't change register_bytes_found in this case, and don't + print a second warning. */ + goto supply_them; + } + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (i != register_bytes_found) + { + register_bytes_found = i; +#ifdef REGISTER_BYTES_OK + if (!REGISTER_BYTES_OK (i)) + warning ("Remote reply is too short: %s", buf); +#endif + } + + supply_them: + for (i = 0; i < NUM_REGS; i++) + supply_register (i, ®s[REGISTER_BYTE(i)]); +} + +/* Prepare to store registers. Since we may send them all (using a + 'G' request), we have to read out the ones we don't want to change + first. */ + +static void +remote_prepare_to_store () +{ + /* Make sure the entire registers array is valid. */ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES); +} + +/* Store register REGNO, or all registers if REGNO == -1, from the contents + of REGISTERS. FIXME: ignores errors. */ + +static void +remote_store_registers (regno) + int regno; +{ + char buf[PBUFSIZ]; + int i; + char *p; + + set_thread (inferior_pid, 1); + + if (regno >= 0 && stub_supports_P) + { + /* Try storing a single register. */ + char *regp; + + sprintf (buf, "P%x=", regno); + p = buf + strlen (buf); + regp = ®isters[REGISTER_BYTE (regno)]; + for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i) + { + *p++ = tohex ((regp[i] >> 4) & 0xf); + *p++ = tohex (regp[i] & 0xf); + } + *p = '\0'; + remote_send (buf); + if (buf[0] != '\0') + { + /* The stub understands the 'P' request. We are done. */ + return; + } + + /* The stub does not support the 'P' request. Use 'G' instead, + and don't try using 'P' in the future (it will just waste our + time). */ + stub_supports_P = 0; + } + + buf[0] = 'G'; + + /* Command describes registers byte by byte, + each byte encoded as two hex characters. */ + + p = buf + 1; + /* remote_prepare_to_store insures that register_bytes_found gets set. */ + for (i = 0; i < register_bytes_found; i++) + { + *p++ = tohex ((registers[i] >> 4) & 0xf); + *p++ = tohex (registers[i] & 0xf); + } + *p = '\0'; + + remote_send (buf); +} + +/* + Use of the data cache *used* to be disabled because it loses for looking at + and changing hardware I/O ports and the like. Accepting `volatile' + would perhaps be one way to fix it. Another idea would be to use the + executable file for the text segment (for all SEC_CODE sections? + For all SEC_READONLY sections?). This has problems if you want to + actually see what the memory contains (e.g. self-modifying code, + clobbered memory, user downloaded the wrong thing). + + Because it speeds so much up, it's now enabled, if you're playing + with registers you turn it of (set remotecache 0) +*/ + +/* Read a word from remote address ADDR and return it. + This goes through the data cache. */ + +#if 0 /* unused? */ +static int +remote_fetch_word (addr) + CORE_ADDR addr; +{ + return dcache_fetch (remote_dcache, addr); +} + +/* Write a word WORD into remote address ADDR. + This goes through the data cache. */ + +static void +remote_store_word (addr, word) + CORE_ADDR addr; + int word; +{ + dcache_poke (remote_dcache, addr, word); +} +#endif /* 0 (unused?) */ + + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + int done; + /* Chop the transfer down if necessary */ + + done = 0; + while (done < len) + { + int todo = len - done; + int cando = PBUFSIZ /2 - 32; /* number of bytes that will fit. */ + if (todo > cando) + todo = cando; + + /* FIXME-32x64: Need a version of print_address_numeric which puts the + result in a buffer like sprintf. */ + sprintf (buf, "M%lx,%x:", (unsigned long) memaddr + done, todo); + + /* We send target system values byte by byte, in increasing byte addresses, + each byte encoded as two hex characters. */ + + p = buf + strlen (buf); + for (i = 0; i < todo; i++) + { + *p++ = tohex ((myaddr[i + done] >> 4) & 0xf); + *p++ = tohex (myaddr[i + done] & 0xf); + } + *p = '\0'; + + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + done += todo; + } + return len; +} + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +remote_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[PBUFSIZ]; + int i; + char *p; + int done; + /* Chop transfer down if neccessary */ + +#if 0 + /* FIXME: This is wrong for larger packets */ + if (len > PBUFSIZ / 2 - 1) + abort (); +#endif + done = 0; + while (done < len) + { + int todo = len - done; + int cando = PBUFSIZ / 2 - 32; /* number of bytes that will fit. */ + if (todo > cando) + todo = cando; + + /* FIXME-32x64: Need a version of print_address_numeric which puts the + result in a buffer like sprintf. */ + sprintf (buf, "m%lx,%x", (unsigned long) memaddr + done, todo); + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + + /* Reply describes memory byte by byte, + each byte encoded as two hex characters. */ + + p = buf; + for (i = 0; i < todo; i++) + { + if (p[0] == 0 || p[1] == 0) + /* Reply is short. This means that we were able to read only part + of what we wanted to. */ + return i + done; + myaddr[i + done] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + done += todo; + } + return len; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is + nonzero. Returns length of data written or read; 0 for error. */ + +/* ARGSUSED */ +static int +remote_xfer_memory(memaddr, myaddr, len, should_write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; + struct target_ops *target; /* ignored */ +{ + return dcache_xfer_memory (remote_dcache, memaddr, myaddr, len, should_write); +} + + +#if 0 +/* Enable after 4.12. */ + +void +remote_search (len, data, mask, startaddr, increment, lorange, hirange + addr_found, data_found) + int len; + char *data; + char *mask; + CORE_ADDR startaddr; + int increment; + CORE_ADDR lorange; + CORE_ADDR hirange; + CORE_ADDR *addr_found; + char *data_found; +{ + if (increment == -4 && len == 4) + { + long mask_long, data_long; + long data_found_long; + CORE_ADDR addr_we_found; + char buf[PBUFSIZ]; + long returned_long[2]; + char *p; + + mask_long = extract_unsigned_integer (mask, len); + data_long = extract_unsigned_integer (data, len); + sprintf (buf, "t%x:%x,%x", startaddr, data_long, mask_long); + putpkt (buf); + getpkt (buf, 0); + if (buf[0] == '\0') + { + /* The stub doesn't support the 't' request. We might want to + remember this fact, but on the other hand the stub could be + switched on us. Maybe we should remember it only until + the next "target remote". */ + generic_search (len, data, mask, startaddr, increment, lorange, + hirange, addr_found, data_found); + return; + } + + if (buf[0] == 'E') + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just use EIO. */ + memory_error (EIO, startaddr); + p = buf; + addr_we_found = 0; + while (*p != '\0' && *p != ',') + addr_we_found = (addr_we_found << 4) + fromhex (*p++); + if (*p == '\0') + error ("Protocol error: short return for search"); + + data_found_long = 0; + while (*p != '\0' && *p != ',') + data_found_long = (data_found_long << 4) + fromhex (*p++); + /* Ignore anything after this comma, for future extensions. */ + + if (addr_we_found < lorange || addr_we_found >= hirange) + { + *addr_found = 0; + return; + } + + *addr_found = addr_we_found; + *data_found = store_unsigned_integer (data_we_found, len); + return; + } + generic_search (len, data, mask, startaddr, increment, lorange, + hirange, addr_found, data_found); +} +#endif /* 0 */ + +static void +remote_files_info (ignore) + struct target_ops *ignore; +{ + puts_filtered ("Debugging a target over a serial line.\n"); +} + +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ + +/* Read a single character from the remote end, masking it down to 7 bits. */ + +static int +readchar (timeout) + int timeout; +{ + int ch; + + ch = SERIAL_READCHAR (remote_desc, timeout); + + switch (ch) + { + case SERIAL_EOF: + error ("Remote connection closed"); + case SERIAL_ERROR: + perror_with_name ("Remote communication error"); + case SERIAL_TIMEOUT: + return ch; + default: + return ch & 0x7f; + } +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +static void +remote_send (buf) + char *buf; +{ + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + error ("Remote failure reply: %s", buf); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +static int +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[PBUFSIZ]; + int cnt = strlen (buf); + int ch; + int tcount = 0; + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + if (cnt > (int) sizeof (buf2) - 5) /* Prosanity check */ + abort(); + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + while (1) + { + int started_error_output = 0; + + if (remote_debug) + { + *p = '\0'; + printf_unfiltered ("Sending packet: %s...", buf2); + gdb_flush(gdb_stdout); + } + if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + perror_with_name ("putpkt: write failed"); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (1) + { + ch = readchar (remote_timeout); + + if (remote_debug) + { + switch (ch) + { + case '+': + case SERIAL_TIMEOUT: + case '$': + if (started_error_output) + { + putchar_unfiltered ('\n'); + started_error_output = 0; + } + } + } + + switch (ch) + { + case '+': + if (remote_debug) + printf_unfiltered("Ack\n"); + return 1; + case SERIAL_TIMEOUT: + tcount ++; + if (tcount > 3) + return 0; + break; /* Retransmit buffer */ + case '$': + { + char junkbuf[PBUFSIZ]; + + /* It's probably an old response, and we're out of sync. Just + gobble up the packet and ignore it. */ + getpkt (junkbuf, 0); + continue; /* Now, go look for + */ + } + default: + if (remote_debug) + { + if (!started_error_output) + { + started_error_output = 1; + printf_unfiltered ("putpkt: Junk: "); + } + putchar_unfiltered (ch & 0177); + } + continue; + } + break; /* Here to retransmit */ + } + +#if 0 + /* This is wrong. If doing a long backtrace, the user should be + able to get out next time we call QUIT, without anything as violent + as interrupt_query. If we want to provide a way out of here + without getting to the next QUIT, it should be based on hitting + ^C twice as in remote_wait. */ + if (quit_flag) + { + quit_flag = 0; + interrupt_query (); + } +#endif + } +} + +/* Come here after finding the start of the frame. Collect the rest into BUF, + verifying the checksum, length, and handling run-length compression. + Returns 0 on any error, 1 on success. */ + +static int +read_frame (buf) + char *buf; +{ + unsigned char csum; + char *bp; + int c; + + csum = 0; + bp = buf; + + while (1) + { + c = readchar (remote_timeout); + + switch (c) + { + case SERIAL_TIMEOUT: + if (remote_debug) + puts_filtered ("Timeout in mid-packet, retrying\n"); + return 0; + case '$': + if (remote_debug) + puts_filtered ("Saw new packet start in middle of old one\n"); + return 0; /* Start a new packet, count retries */ + case '#': + { + unsigned char pktcsum; + + *bp = '\000'; + + pktcsum = fromhex (readchar (remote_timeout)) << 4; + pktcsum |= fromhex (readchar (remote_timeout)); + + if (csum == pktcsum) + return 1; + + if (remote_debug) + { + printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + pktcsum, csum); + puts_filtered (buf); + puts_filtered ("\n"); + } + return 0; + } + case '*': /* Run length encoding */ + csum += c; + c = readchar (remote_timeout); + csum += c; + c = c - ' ' + 3; /* Compute repeat count */ + + + if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1) + { + memset (bp, *(bp - 1), c); + bp += c; + continue; + } + + *bp = '\0'; + printf_filtered ("Repeat count %d too large for buffer: ", c); + puts_filtered (buf); + puts_filtered ("\n"); + return 0; + + default: + if (bp < buf + PBUFSIZ - 1) + { + *bp++ = c; + csum += c; + continue; + } + + *bp = '\0'; + puts_filtered ("Remote packet too long: "); + puts_filtered (buf); + puts_filtered ("\n"); + + return 0; + } + } +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. BUF is expected to be of size PBUFSIZ. + If FOREVER, wait forever rather than timing out; this is used + while the target is executing user code. */ + +static void +getpkt (buf, forever) + char *buf; + int forever; +{ + int c; + int tries; + int timeout; + int val; + + strcpy (buf,"timeout"); + + if (forever) + { +#ifdef MAINTENANCE_CMDS + timeout = watchdog > 0 ? watchdog : -1; +#else + timeout = -1; +#endif + } + + else + timeout = remote_timeout; + +#define MAX_TRIES 3 + + for (tries = 1; tries <= MAX_TRIES; tries++) + { + /* This can loop forever if the remote side sends us characters + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ + + /* Note that we will only wait forever prior to the start of a packet. + After that, we expect characters to arrive at a brisk pace. They + should show up within remote_timeout intervals. */ + + do + { + c = readchar (timeout); + + if (c == SERIAL_TIMEOUT) + { +#ifdef MAINTENANCE_CMDS + if (forever) /* Watchdog went off. Kill the target. */ + { + target_mourn_inferior (); + error ("Watchdog has expired. Target detached.\n"); + } +#endif + if (remote_debug) + puts_filtered ("Timed out.\n"); + goto retry; + } + } + while (c != '$'); + + /* We've found the start of a packet, now collect the data. */ + + val = read_frame (buf); + + if (val == 1) + { + if (remote_debug) + fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf); + SERIAL_WRITE (remote_desc, "+", 1); + return; + } + + /* Try the whole thing again. */ + retry: + SERIAL_WRITE (remote_desc, "-", 1); + } + + /* We have tried hard enough, and just can't receive the packet. Give up. */ + + printf_unfiltered ("Ignoring packet error, continuing...\n"); + SERIAL_WRITE (remote_desc, "+", 1); +} + +static void +remote_kill () +{ + /* For some mysterious reason, wait_for_inferior calls kill instead of + mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */ + if (kill_kludge) + { + kill_kludge = 0; + target_mourn_inferior (); + return; + } + + /* Use catch_errors so the user can quit from gdb even when we aren't on + speaking terms with the remote system. */ + catch_errors (putpkt, "k", "", RETURN_MASK_ERROR); + + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); +} + +static void +remote_mourn () +{ + remote_mourn_1 (&remote_ops); +} + +static void +extended_remote_mourn () +{ + /* We do _not_ want to mourn the target like this; this will + remove the extended remote target from the target stack, + and the next time the user says "run" it'll fail. + + FIXME: What is the right thing to do here? */ +#if 0 + remote_mourn_1 (&extended_remote_ops); +#endif +} + +/* Worker function for remote_mourn. */ +static void +remote_mourn_1 (target) + struct target_ops *target; +{ + unpush_target (target); + generic_mourn_inferior (); +} + +/* In the extended protocol we want to be able to do things like + "run" and have them basically work as expected. So we need + a special create_inferior function. + + FIXME: One day add support for changing the exec file + we're debugging, arguments and an environment. */ + +static void +extended_remote_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + /* Rip out the breakpoints; we'll reinsert them after restarting + the remote server. */ + remove_breakpoints (); + + /* Now restart the remote server. */ + extended_remote_restart (); + + /* Now put the breakpoints back in. This way we're safe if the + restart function works via a unix fork on the remote side. */ + insert_breakpoints (); + + /* Clean up from the last time we were running. */ + clear_proceed_status (); + + /* Let the remote process run. */ + proceed (-1, TARGET_SIGNAL_0, 0); +} + + +#ifdef REMOTE_BREAKPOINT + +/* On some machines, e.g. 68k, we may use a different breakpoint instruction + than other targets. */ +static unsigned char break_insn[] = REMOTE_BREAKPOINT; + +#else /* No REMOTE_BREAKPOINT. */ + +/* Same old breakpoint instruction. This code does nothing different + than mem-break.c. */ +static unsigned char break_insn[] = BREAKPOINT; + +#endif /* No REMOTE_BREAKPOINT. */ + +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ + +static int +remote_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, (char *)break_insn, sizeof break_insn); + + return val; +} + +static int +remote_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, sizeof break_insn); +} + +/* Define the target subroutine names */ + +struct target_ops remote_ops = { + "remote", /* to_shortname */ + "Remote serial target in gdb-specific protocol", /* to_longname */ + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */ + remote_open, /* to_open */ + remote_close, /* to_close */ + NULL, /* to_attach */ + remote_detach, /* to_detach */ + remote_resume, /* to_resume */ + remote_wait, /* to_wait */ + remote_fetch_registers, /* to_fetch_registers */ + remote_store_registers, /* to_store_registers */ + remote_prepare_to_store, /* to_prepare_to_store */ + remote_xfer_memory, /* to_xfer_memory */ + remote_files_info, /* to_files_info */ + remote_insert_breakpoint, /* to_insert_breakpoint */ + remote_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + remote_kill, /* to_kill */ + generic_load, /* to_load */ + NULL, /* to_lookup_symbol */ + NULL, /* to_create_inferior */ + remote_mourn, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + remote_thread_alive, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +struct target_ops extended_remote_ops = { + "extended-remote", /* to_shortname */ + "Extended remote serial target in gdb-specific protocol",/* to_longname */ + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", /* to_doc */ + extended_remote_open, /* to_open */ + remote_close, /* to_close */ + NULL, /* to_attach */ + remote_detach, /* to_detach */ + remote_resume, /* to_resume */ + remote_wait, /* to_wait */ + remote_fetch_registers, /* to_fetch_registers */ + remote_store_registers, /* to_store_registers */ + remote_prepare_to_store, /* to_prepare_to_store */ + remote_xfer_memory, /* to_xfer_memory */ + remote_files_info, /* to_files_info */ + + remote_insert_breakpoint, /* to_insert_breakpoint */ + remote_remove_breakpoint, /* to_remove_breakpoint */ + + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + remote_kill, /* to_kill */ + generic_load, /* to_load */ + NULL, /* to_lookup_symbol */ + extended_remote_create_inferior,/* to_create_inferior */ + extended_remote_mourn, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + remote_thread_alive, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote () +{ + add_target (&remote_ops); + add_target (&extended_remote_ops); + + add_show_from_set (add_set_cmd ("remotetimeout", no_class, + var_integer, (char *)&remote_timeout, + "Set timeout value for remote read.\n", &setlist), + &showlist); + + add_show_from_set (add_set_cmd ("remotebreak", no_class, + var_integer, (char *)&remote_break, + "Set whether to send break if interrupted.\n", &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/reply_mig_hack.awk b/contrib/gdb/gdb/reply_mig_hack.awk new file mode 100644 index 000000000000..310a40cbb9b4 --- /dev/null +++ b/contrib/gdb/gdb/reply_mig_hack.awk @@ -0,0 +1,123 @@ +# Reply server mig-output massager +# +# Copyright (C) 1995 Free Software Foundation, Inc. +# +# Written by Miles Bader +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# This awk script hacks the output of mig-generated reply server code +# so that it allows replies with just the error-code in them (as this is +# how mig returns errors). +# +# It is highly, highly, dependent on the exact format of mig output. Ick. +# + +BEGIN { parse_phase = 0; } + +/^}/ { parse_phase = 0; } + +parse_phase == 0 && /^mig_internal void _X[a-zA-Z0-9_]*_reply/ { + # The start of a mig server routine. Reset everything. Note that we only + # mess with rpcs that have the suffix `_reply'. + num_args = 0; + num_checks = 0; + parse_phase = 1; + print; next; +} + +parse_phase == 1 && /^[\t ]*typedef struct/ { + # The first structure in the server routine should describe the arguments + parse_phase = 2; + print; next; +} + +parse_phase == 2 { + # The message header field in the args structure, which skip. + parse_phase = 3; + print; next; +} + +parse_phase == 3 && /}/ { + # The args structure is over. + if (num_args > 1) + parse_phase = 5; + else + # There's no extra args that could screw up the normal mechanism for + # error returns, so we don't have to insert any new code. + parse_phase = 0; + print; next; +} + +parse_phase == 3 { + # The type field for an argument. + arg_type_code_name[num_args] = $2; + sub (/;$/, "", arg_type_code_name[num_args]) # Get rid of the semi-colon + parse_phase = 4; + print; next; +} + +parse_phase == 4 { + # The value field for an argument. + arg_name[num_args] = $2; + sub (/;$/, "", arg_name[num_args]) # Get rid of the semi-colon + arg_type[num_args] = $1; + num_args++; + parse_phase = 3; + print; next; +} + +parse_phase == 5 && /^[ \t]*static const mach_msg_type_t/ { + # The type check structure for an argument. + arg_check_name[num_checks] = $4; + num_checks++; + print; next; +} + +parse_phase == 5 && /^[ \t]*mig_external kern_return_t/ { + # The declaration of the user server function for this rpc. + user_function_name = $3; + print; next; +} + +parse_phase == 5 && /^#if[ \t]TypeCheck/ { + # The first args type checking statement; we need to insert our chunk of + # code that bypasses all the type checks if this is an error return, after + # which we're done until we get to the next function. Handily, the size + # of mig's Reply structure is also the size of the alternate Request + # structure that we want to check for. + print "\tif (In0P->Head.msgh_size == sizeof (Reply)"; + print "\t && ! (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)"; + print "\t && *(int *)&In0P->" arg_type_code_name[0] " == *(int *)&" arg_check_name[0]; + print "\t && In0P->" arg_name[0] " != 0)"; + print "\t /* Error return, only the error code argument is passed. */"; + print "\t {"; + # Force the function into a type that only takes the first two args, via + # the temp variable SFUN (is there another way to correctly do this cast?). + # This is possibly bogus, but easier than supplying bogus values for all + # the other args (we can't just pass 0 for them, as they might not be scalar). + printf ("\t kern_return_t (*sfun)(mach_port_t"); + for (i = 0; i < num_args; i++) + printf (", %s", arg_type[i]); + printf (") = %s;\n", user_function_name); + print "\t OutP->RetCode = (*(kern_return_t (*)(mach_port_t, kern_return_t))sfun) (In0P->Head.msgh_request_port, In0P->" arg_name[0] ");"; + print "\t return;"; + print "\t }"; + print ""; + parse_phase = 0; + print; next; +} + +{ print; } diff --git a/contrib/gdb/gdb/saber.suppress b/contrib/gdb/gdb/saber.suppress new file mode 100644 index 000000000000..6dda1c5f2dae --- /dev/null +++ b/contrib/gdb/gdb/saber.suppress @@ -0,0 +1,451 @@ + + +/* Options for project */ +unsetopt ansi +setopt auto_compile +unsetopt auto_reload +setopt auto_replace +unsetopt batch_load +unsetopt batch_run +unsetopt cc_prog +setopt ccargs -g +unsetopt create_file +unsetopt debug_child +unsetopt echo +setopt edit_jobs 5 +unsetopt eight_bit +setopt line_edit +setopt line_meta +setopt lint_load 2 +setopt lint_run 2 +setopt list_action +setopt load_flags -I. -g -I.. -I../vx-share +unsetopt long_not_int +unsetopt make_args +setopt make_hfiles +unsetopt make_offset +unsetopt make_prog +setopt make_symbol # +setopt mem_config 16384 +unsetopt mem_trace +setopt num_proc 1 +unsetopt page_cmds +setopt page_list 19 +unsetopt page_load +unsetopt path +setopt proto_path . /s2/saber_dir30/sun4-40/proto /s2/saber_dir30/sun4-40/../common/proto +unsetopt preprocessor +setopt program_name a.out +unsetopt print_custom +setopt print_pointer +setopt print_string 20 +unsetopt save_memory +setopt sbrk_size 1048576 +setopt src_err 3 +setopt src_step 1 +setopt src_stop 3 +setopt sys_load_flags -L/lib -L/usr/lib -L/usr/local/lib -I/usr/include -Dunix -Dsun -Dsparc +unsetopt tab_stop +unsetopt terse_suppress +unsetopt terse_where +setopt unset_value 191 +unsetopt win_fork_nodup +setopt win_no_raise +unsetopt win_message_list +unsetopt win_project_list +/* Suppressions for project */ +suppress 6 in read_huge_number +/* Over/underflow */ +suppress 8 in read_huge_number +/* Over/underflow */ +suppress 22 +/* Pointer subtraction */ +suppress 22 in free_all_psymtabs +/* Pointer subtraction */ +suppress 22 in free_all_symtabs +/* Pointer subtraction */ +suppress 56 in print_string +/* Information lost */ +suppress 65 "../bfd/bfd.c":379 +/* Too many function arguments */ +suppress 65 on printf_filtered +/* Too many function arguments */ +suppress 65 on fprintf_filtered +/* Too many function arguments */ +suppress 65 on vfprintf_filtered +/* Too many function arguments */ +suppress 65 on query +/* Too many function arguments */ +suppress 65 on fatal_dump_core +/* Too many function arguments */ +suppress 65 on fatal +/* Too many function arguments */ +suppress 65 on error +/* Too many function arguments */ +suppress 65 on noprocess +/* Too many function arguments */ +suppress 65 +/* Too many function arguments */ +suppress 66 on say +/* Too few function arguments */ +suppress 66 on printf_filtered +/* Too few function arguments */ +suppress 66 on fprintf_filtered +/* Too few function arguments */ +suppress 66 on vfprintf_filtered +/* Too few function arguments */ +suppress 66 on query +/* Too few function arguments */ +suppress 66 on fatal_dump_core +/* Too few function arguments */ +suppress 66 on fatal +/* Too few function arguments */ +suppress 66 on error +/* Too few function arguments */ +suppress 67 on printf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on fprintf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on vfprintf_filtered +/* Signed/unsigned argument mismatch */ +suppress 67 on query +/* Signed/unsigned argument mismatch */ +suppress 67 on fatal_dump_core +/* Signed/unsigned argument mismatch */ +suppress 67 on fatal +/* Signed/unsigned argument mismatch */ +suppress 67 on error +/* Signed/unsigned argument mismatch */ +suppress 67 +/* Signed/unsigned argument mismatch */ +suppress 68 on bfd_get_section_contents +/* Benign argument mismatch */ +suppress 68 on _do_getblong +/* Benign argument mismatch */ +suppress 68 on supply_register +/* Benign argument mismatch */ +suppress 68 on target_write_memory +/* Benign argument mismatch */ +suppress 68 on write_register_bytes +/* Benign argument mismatch */ +suppress 68 on read_register_bytes +/* Benign argument mismatch */ +suppress 68 on read_memory +/* Benign argument mismatch */ +suppress 68 on say +/* Benign argument mismatch */ +suppress 68 on printf_filtered +/* Benign argument mismatch */ +suppress 68 on fprintf_filtered +/* Benign argument mismatch */ +suppress 68 on vfprintf_filtered +/* Benign argument mismatch */ +suppress 68 on query +/* Benign argument mismatch */ +suppress 68 on fatal_dump_core +/* Benign argument mismatch */ +suppress 68 on fatal +/* Benign argument mismatch */ +suppress 68 on error +/* Benign argument mismatch */ +suppress 68 in find_solib +/* Benign argument mismatch */ +suppress 68 on child_wait +/* Benign argument mismatch */ +suppress 68 on xrealloc +/* Benign argument mismatch */ +suppress 68 on myread +/* Benign argument mismatch */ +suppress 68 in do_cleanups +/* Benign argument mismatch */ +suppress 68 on make_cleanup +/* Benign argument mismatch */ +suppress 68 on target_read_memory +/* Benign argument mismatch */ +suppress 69 on printf_filtered +/* Serious argument mismatch */ +suppress 69 on fprintf_filtered +/* Serious argument mismatch */ +suppress 69 on vfprintf_filtered +/* Serious argument mismatch */ +suppress 69 on query +/* Serious argument mismatch */ +suppress 69 on fatal_dump_core +/* Serious argument mismatch */ +suppress 69 on fatal +/* Serious argument mismatch */ +suppress 69 on error +/* Serious argument mismatch */ +suppress 70 on printf_filtered +/* Passing illegal enumeration value */ +suppress 70 on fprintf_filtered +/* Passing illegal enumeration value */ +suppress 70 on vfprintf_filtered +/* Passing illegal enumeration value */ +suppress 70 on query +/* Passing illegal enumeration value */ +suppress 70 on fatal_dump_core +/* Passing illegal enumeration value */ +suppress 70 on fatal +/* Passing illegal enumeration value */ +suppress 70 on error +/* Passing illegal enumeration value */ +suppress 80 on first_link_map_member +/* Returning invalid pointer */ +suppress 110 in printf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in fprintf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in vfprintf_filtered +/* Signed/unsigned memory retrieval */ +suppress 110 in query +/* Signed/unsigned memory retrieval */ +suppress 110 in fatal_dump_core +/* Signed/unsigned memory retrieval */ +suppress 110 in fatal +/* Signed/unsigned memory retrieval */ +suppress 110 in error +/* Signed/unsigned memory retrieval */ +suppress 112 in printf_filtered +/* Memory retrieval */ +suppress 112 in fprintf_filtered +/* Memory retrieval */ +suppress 112 in vfprintf_filtered +/* Memory retrieval */ +suppress 112 in query +/* Memory retrieval */ +suppress 112 in fatal_dump_core +/* Memory retrieval */ +suppress 112 in fatal +/* Memory retrieval */ +suppress 112 in error +/* Memory retrieval */ +suppress 112 +/* Memory retrieval */ +suppress 112 ../symtab.c +/* Memory retrieval */ +suppress 112 in child_xfer_memory +/* Memory retrieval */ +suppress 165 in frame_saved_pc +/* Dereference */ +suppress 165 in get_prev_frame_info +/* Dereference */ +suppress 167 in get_prev_frame_info +/* Selection */ +suppress 167 in frame_saved_pc +/* Selection */ +suppress 442 in try_baudrate +/* Escape has null value */ +suppress 529 in read_range_type +/* Statement not reached */ +suppress 529 in process_one_symbol +/* Statement not reached */ +suppress 529 in unpack_double +/* Statement not reached */ +suppress 529 in wait_for_inferior +/* Statement not reached */ +suppress 529 in do_registers_info +/* Statement not reached */ +suppress 529 in value_from_register +/* Statement not reached */ +suppress 529 in solib_create_inferior_hook +/* Constant in conditional */ +suppress 530 +/* Empty body of statement */ +suppress 546 in net_quit +/* Function exits through bottom */ +suppress 546 in net_wait +/* Function exits through bottom */ +suppress 546 in vx_remove_breakpoint +/* Function exits through bottom */ +suppress 546 in vx_insert_breakpoint +/* Function exits through bottom */ +suppress 546 in value_less +/* Function exits through bottom */ +suppress 546 in value_equal +/* Function exits through bottom */ +suppress 546 in unpack_long +/* Function exits through bottom */ +suppress 558 in solib_create_inferior_hook +/* Constant in conditional */ +suppress 558 in read_range_type +/* Constant in conditional */ +suppress 558 in process_one_symbol +/* Constant in conditional */ +suppress 558 in read_dbx_symtab +/* Constant in conditional */ +suppress 558 in vx_write_register +/* Constant in conditional */ +suppress 558 in vx_read_register +/* Constant in conditional */ +suppress 558 in unpack_double +/* Constant in conditional */ +suppress 558 in wait_for_inferior +/* Constant in conditional */ +suppress 558 in do_registers_info +/* Constant in conditional */ +suppress 558 in value_from_register +/* Constant in conditional */ +suppress 558 in add_enum_psymbol +/* Constant in conditional */ +suppress 558 in add_partial_symbol +/* Constant in conditional */ +suppress 558 mfree.c +/* Constant in conditional */ +suppress 558 mmalloc.c +/* Constant in conditional */ +suppress 558 mrealloc.c +/* Constant in conditional */ +suppress 560 in solib_address +/* Assignment within conditional */ +suppress 560 in solib_info +/* Assignment within conditional */ +suppress 560 in solib_add +/* Assignment within conditional */ +suppress 560 in read_type +/* Assignment within conditional */ +suppress 560 in type_print_base +/* Assignment within conditional */ +suppress 560 in type_print_derivation_info +/* Assignment within conditional */ +suppress 560 in block_depth +/* Assignment within conditional */ +suppress 560 in select_source_symtab +/* Assignment within conditional */ +suppress 560 in clear_value_history +/* Assignment within conditional */ +suppress 560 in clear_displays +/* Assignment within conditional */ +suppress 560 in initialize_main +/* Assignment within conditional */ +suppress 560 in echo_command +/* Assignment within conditional */ +suppress 560 in unset_in_environ +/* Assignment within conditional */ +suppress 560 in set_in_environ +/* Assignment within conditional */ +suppress 560 in get_in_environ +/* Assignment within conditional */ +suppress 560 in do_setshow_command +/* Assignment within conditional */ +suppress 560 in breakpoint_1 +/* Assignment within conditional */ +suppress 590 on sig +/* Unused formal parameter */ +suppress 590 in nindy_create_inferior +/* Unused formal parameter */ +suppress 590 in add_to_section_table +/* Unused formal parameter */ +suppress 590 in vx_create_inferior +/* Unused formal parameter */ +suppress 590 in host_convert_from_virtual +/* Unused formal parameter */ +suppress 590 in host_convert_to_virtual +/* Unused formal parameter */ +suppress 590 on siggnal +/* Unused formal parameter */ +suppress 590 in init_sig +/* Unused formal parameter */ +suppress 590 in nindy_resume +/* Unused formal parameter */ +suppress 590 in set_history_size_command +/* Unused formal parameter */ +suppress 590 in not_just_help_class_command +/* Unused formal parameter */ +suppress 590 on regno +/* Unused formal parameter */ +suppress 590 on from_tty +/* Unused formal parameter */ +suppress 590 on args +/* Unused formal parameter */ +suppress 590 in process_symbol_pair +/* Unused formal parameter */ +suppress 591 in print_scalar_formatted +/* Unused automatic variable */ +suppress 592 on rcsid +/* Unused static */ +suppress 594 in call_function_by_hand +/* Set but not used */ +suppress 594 in record_latest_value +/* Set but not used */ +suppress 594 in bpstat_stop_status +/* Set but not used */ +suppress 595 in coffstrip +/* Used before set */ +suppress 652 ../include/bfd.h +/* Declaration has no effect */ +suppress 652 /usr/include/machine/reg.h +/* Declaration has no effect */ +suppress 652 /usr/include/sun4/reg.h +/* Declaration has no effect */ +suppress 68 on complain +/* Benign type mismatch */ +suppress 3 in read_range_type +/* Over/underflow unary minus */ +suppress 442 ../bfd/archive.c +/* \0 in string */ +suppress 558 ../bfd/b.out.c +/* Conditional if always true */ +suppress 558 ../bfd/coffswap.c +/* Conditional if always true -- bfd_h_put_x */ +suppress 529 ../bfd/coffswap.c +/* Stmt unreach -- bfd_h_put_x */ +suppress 590 ../bfd/ecoff.c +/* Formal parameter not used */ +suppress 590 on ignore +/* Formal param not used */ +suppress 590 on ignore_exec_bfd +/* Formal param not used */ +suppress 590 on ignore_core_bfd +/* Formal param not used */ +suppress 590 on ignore_input_section +/* Formal param not used */ +suppress 590 on ignore_newsect +/* Formal param not used */ +suppress 590 on ignore_abfd +/* Formal param not used */ +suppress 590 on ignore_symbol +/* Formal param not used */ +suppress 590 on ignore_symbols +/* Formal param not used */ +suppress 590 on signo +/* Formal param not used */ +suppress 652 +/* The declaration has no effect */ +suppress 442 in ../bfd/archive.c +/* Escape sequence in string literal has null value */ + +/* Signals caught and ignored */ +catch HUP +catch QUIT +catch ILL +catch TRAP +catch IOT +catch EMT +catch FPE +catch KILL +catch BUS +catch SEGV +catch SYS +catch PIPE +catch TERM +catch URG +catch STOP +catch TSTP +catch TTIN +catch TTOU +catch IO +catch XCPU +catch XFSZ +catch VTALRM +catch PROF +catch LOST +catch USR1 +catch USR2 +ignore INT +ignore ALRM +ignore CONT +ignore CHLD +ignore WINCH + +/* Status of project */ diff --git a/contrib/gdb/gdb/scm-exp.c b/contrib/gdb/gdb/scm-exp.c new file mode 100644 index 000000000000..8df680353505 --- /dev/null +++ b/contrib/gdb/gdb/scm-exp.c @@ -0,0 +1,414 @@ +/* Scheme/Guile language support routines for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "value.h" +#include "c-lang.h" +#include "scm-lang.h" +#include "scm-tags.h" + +#define USE_EXPRSTRING 0 + +static void scm_lreadr PARAMS ((int)); + +LONGEST +scm_istr2int(str, len, radix) + char *str; + int len; + int radix; +{ + int j; + int i = 0; + LONGEST inum = 0; + int c; + int sign = 0; + + if (0 >= len) return SCM_BOOL_F; /* zero scm_length */ + switch (str[0]) + { /* leading sign */ + case '-': + case '+': + sign = str[0]; + if (++i==len) + return SCM_BOOL_F; /* bad if lone `+' or `-' */ + } + do { + switch (c = str[i++]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + c = c - '0'; + goto accumulate; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + c = c-'A'+10; + goto accumulate; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + c = c-'a'+10; + accumulate: + if (c >= radix) return SCM_BOOL_F; /* bad digit for radix */ + inum *= radix; + inum += c; + break; + default: + return SCM_BOOL_F; /* not a digit */ + } + } while (i < len); + if (sign == '-') + inum = -inum; + return SCM_MAKINUM (inum); +} + +LONGEST +scm_istring2number(str, len, radix) + char *str; + int len; + int radix; +{ + int i = 0; + char ex = 0; + char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */ + SCM res; + if (len==1) + if (*str=='+' || *str=='-') /* Catches lone `+' and `-' for speed */ + return SCM_BOOL_F; + + while ((len-i) >= 2 && str[i]=='#' && ++i) + switch (str[i++]) { + case 'b': case 'B': if (rx_p++) return SCM_BOOL_F; radix = 2; break; + case 'o': case 'O': if (rx_p++) return SCM_BOOL_F; radix = 8; break; + case 'd': case 'D': if (rx_p++) return SCM_BOOL_F; radix = 10; break; + case 'x': case 'X': if (rx_p++) return SCM_BOOL_F; radix = 16; break; + case 'i': case 'I': if (ex_p++) return SCM_BOOL_F; ex = 2; break; + case 'e': case 'E': if (ex_p++) return SCM_BOOL_F; ex = 1; break; + default: return SCM_BOOL_F; + } + + switch (ex) { + case 1: + return scm_istr2int(&str[i], len-i, radix); + case 0: + return scm_istr2int(&str[i], len-i, radix); +#if 0 + if NFALSEP(res) return res; +#ifdef FLOATS + case 2: return scm_istr2flo(&str[i], len-i, radix); +#endif +#endif + } + return SCM_BOOL_F; +} + +static void +scm_read_token (c, weird) + int c; + int weird; +{ + while (1) + { + c = *lexptr++; + switch (c) + { + case '[': + case ']': + case '(': + case ')': + case '\"': + case ';': + case ' ': case '\t': case '\r': case '\f': + case '\n': + if (weird) + goto default_case; + case '\0': /* End of line */ + eof_case: + --lexptr; + return; + case '\\': + if (!weird) + goto default_case; + else + { + c = *lexptr++; + if (c == '\0') + goto eof_case; + else + goto default_case; + } + case '}': + if (!weird) + goto default_case; + + c = *lexptr++; + if (c == '#') + return; + else + { + --lexptr; + c = '}'; + goto default_case; + } + + default: + default_case: + ; + } + } +} + +static int +scm_skip_ws () +{ + register int c; + while (1) + switch ((c = *lexptr++)) + { + case '\0': + goteof: + return c; + case ';': + lp: + switch ((c = *lexptr++)) + { + case '\0': + goto goteof; + default: + goto lp; + case '\n': + break; + } + case ' ': case '\t': case '\r': case '\f': case '\n': + break; + default: + return c; + } +} + +static void +scm_lreadparen (skipping) + int skipping; +{ + for (;;) + { + int c = scm_skip_ws (); + if (')' == c || ']' == c) + return; + --lexptr; + if (c == '\0') + error ("missing close paren"); + scm_lreadr (skipping); + } +} + +static void +scm_lreadr (skipping) + int skipping; +{ + int c, j; + struct stoken str; + LONGEST svalue; + tryagain: + c = *lexptr++; + switch (c) + { + case '\0': + lexptr--; + return; + case '[': + case '(': + scm_lreadparen (skipping); + return; + case ']': + case ')': + error ("unexpected #\\%c", c); + goto tryagain; + case '\'': + case '`': + str.ptr = lexptr - 1; + scm_lreadr (skipping); + if (!skipping) + { + value_ptr val = scm_evaluate_string (str.ptr, lexptr - str.ptr); + if (!is_scmvalue_type (VALUE_TYPE (val))) + error ("quoted scm form yields non-SCM value"); + svalue = extract_signed_integer (VALUE_CONTENTS (val), + TYPE_LENGTH (VALUE_TYPE (val))); + goto handle_immediate; + } + return; + case ',': + c = *lexptr++; + if ('@' != c) + lexptr--; + scm_lreadr (skipping); + return; + case '#': + c = *lexptr++; + switch (c) + { + case '[': + case '(': + scm_lreadparen (skipping); + return; + case 't': case 'T': + svalue = SCM_BOOL_T; + goto handle_immediate; + case 'f': case 'F': + svalue = SCM_BOOL_F; + goto handle_immediate; + case 'b': case 'B': + case 'o': case 'O': + case 'd': case 'D': + case 'x': case 'X': + case 'i': case 'I': + case 'e': case 'E': + lexptr--; + c = '#'; + goto num; + case '*': /* bitvector */ + scm_read_token (c, 0); + return; + case '{': + scm_read_token (c, 1); + return; + case '\\': /* character */ + c = *lexptr++; + scm_read_token (c, 0); + return; + case '|': + j = 1; /* here j is the comment nesting depth */ + lp: + c = *lexptr++; + lpc: + switch (c) + { + case '\0': + error ("unbalanced comment"); + default: + goto lp; + case '|': + if ('#' != (c = *lexptr++)) + goto lpc; + if (--j) + goto lp; + break; + case '#': + if ('|' != (c = *lexptr++)) + goto lpc; + ++j; + goto lp; + } + goto tryagain; + case '.': + default: + callshrp: + scm_lreadr (skipping); + return; + } + case '\"': + while ('\"' != (c = *lexptr++)) + { + if (c == '\\') + switch (c = *lexptr++) + { + case '\0': + error ("non-terminated string literal"); + case '\n': + continue; + case '0': + case 'f': + case 'n': + case 'r': + case 't': + case 'a': + case 'v': + break; + } + } + return; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + case '-': + case '+': + num: + { + str.ptr = lexptr-1; + scm_read_token (c, 0); + if (!skipping) + { + svalue = scm_istring2number (str.ptr, lexptr - str.ptr, 10); + if (svalue != SCM_BOOL_F) + goto handle_immediate; + goto tok; + } + } + return; + case ':': + scm_read_token ('-', 0); + return; + do_symbol: + default: + str.ptr = lexptr-1; + scm_read_token (c, 0); + tok: + if (!skipping) + { + str.length = lexptr - str.ptr; + if (str.ptr[0] == '$') + { + write_dollar_variable (str); + return; + } + write_exp_elt_opcode (OP_NAME); + write_exp_string (str); + write_exp_elt_opcode (OP_NAME); + } + return; + } + handle_immediate: + if (!skipping) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_scm); + write_exp_elt_longcst (svalue); + write_exp_elt_opcode (OP_LONG); + } +} + +int +scm_parse () +{ + char* start; + struct stoken str; + while (*lexptr == ' ') + lexptr++; + start = lexptr; + scm_lreadr (USE_EXPRSTRING); +#if USE_EXPRSTRING + str.length = lexptr - start; + str.ptr = start; + write_exp_elt_opcode (OP_EXPRSTRING); + write_exp_string (str); + write_exp_elt_opcode (OP_EXPRSTRING); +#endif + return 0; +} diff --git a/contrib/gdb/gdb/scm-lang.c b/contrib/gdb/gdb/scm-lang.c new file mode 100644 index 000000000000..b054dcf62316 --- /dev/null +++ b/contrib/gdb/gdb/scm-lang.c @@ -0,0 +1,268 @@ +/* Scheme/Guile language support routines for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "value.h" +#include "c-lang.h" +#include "scm-lang.h" +#include "scm-tags.h" +#include "gdb_string.h" + +extern struct type ** const (c_builtin_types[]); +extern value_ptr value_allocate_space_in_inferior PARAMS ((int)); +extern value_ptr find_function_in_inferior PARAMS ((char*)); + +struct type *builtin_type_scm; + +void +scm_printchar (c, stream) + int c; + GDB_FILE *stream; +{ + fprintf_filtered (stream, "#\\%c", c); +} + +static void +scm_printstr (stream, string, length, force_ellipses) + GDB_FILE *stream; + char *string; + unsigned int length; + int force_ellipses; +{ + fprintf_filtered (stream, "\"%s\"", string); +} + +int +is_scmvalue_type (type) + struct type *type; +{ + if (TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_NAME (type) && strcmp (TYPE_NAME (type), "SCM") == 0) + { + return 1; + } + return 0; +} + +/* Get the INDEX'th SCM value, assuming SVALUE is the address + of the 0'th one. */ + +LONGEST +scm_get_field (svalue, index) + LONGEST svalue; + int index; +{ + value_ptr val; + char buffer[20]; + read_memory (SCM2PTR (svalue) + index * TYPE_LENGTH (builtin_type_scm), + buffer, TYPE_LENGTH (builtin_type_scm)); + return extract_signed_integer (buffer, TYPE_LENGTH (builtin_type_scm)); +} + +/* Unpack a value of type TYPE in buffer VALADDR as an integer + (if CONTEXT == TYPE_CODE_IN), a pointer (CONTEXT == TYPE_CODE_PTR), + or Boolean (CONTEXT == TYPE_CODE_BOOL). */ + +LONGEST +scm_unpack (type, valaddr, context) + struct type *type; + char *valaddr; + enum type_code context; +{ + if (is_scmvalue_type (type)) + { + LONGEST svalue = extract_signed_integer (valaddr, TYPE_LENGTH (type)); + if (context == TYPE_CODE_BOOL) + { + if (svalue == SCM_BOOL_F) + return 0; + else + return 1; + } + switch (7 & svalue) + { + case 2: case 6: /* fixnum */ + return svalue >> 2; + case 4: /* other immediate value */ + if (SCM_ICHRP (svalue)) /* character */ + return SCM_ICHR (svalue); + else if (SCM_IFLAGP (svalue)) + { + switch (svalue) + { +#ifndef SICP + case SCM_EOL: +#endif + case SCM_BOOL_F: + return 0; + case SCM_BOOL_T: + return 1; + } + } + error ("Value can't be converted to integer."); + default: + return svalue; + } + } + else + return unpack_long (type, valaddr); +} + +/* True if we're correctly in Guile's eval.c (the evaluator and apply). */ + +static int +in_eval_c () +{ + if (current_source_symtab && current_source_symtab->filename) + { + char *filename = current_source_symtab->filename; + int len = strlen (filename); + if (len >= 6 && strcmp (filename + len - 6, "eval.c") == 0) + return 1; + } + return 0; +} + +/* Lookup a value for the variable named STR. + First lookup in Scheme context (using the scm_lookup_cstr inferior + function), then try lookup_symbol for compiled variables. */ + +value_ptr +scm_lookup_name (str) + char *str; +{ + value_ptr args[3]; + int len = strlen (str); + value_ptr symval, func, val; + struct symbol *sym; + args[0] = value_allocate_space_in_inferior (len); + args[1] = value_from_longest (builtin_type_int, len); + write_memory (value_as_long (args[0]), str, len); + + if (in_eval_c () + && (sym = lookup_symbol ("env", + expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL)) != NULL) + args[2] = value_of_variable (sym, expression_context_block); + else + /* FIXME in this case, we should try lookup_symbol first */ + args[2] = value_from_longest (builtin_type_scm, SCM_EOL); + + func = find_function_in_inferior ("scm_lookup_cstr"); + val = call_function_by_hand (func, 3, args); + if (!value_logical_not (val)) + return value_ind (val); + + sym = lookup_symbol (str, + expression_context_block, + VAR_NAMESPACE, (int *) NULL, + (struct symtab **) NULL); + if (sym) + return value_of_variable (sym, NULL); + error ("No symbol \"%s\" in current context."); +} + +value_ptr +scm_evaluate_string (str, len) + char *str; int len; +{ + value_ptr func; + value_ptr addr = value_allocate_space_in_inferior (len + 1); + LONGEST iaddr = value_as_long (addr); + write_memory (iaddr, str, len); + /* FIXME - should find and pass env */ + write_memory (iaddr + len, "", 1); + func = find_function_in_inferior ("scm_evstr"); + return call_function_by_hand (func, 1, &addr); +} + +static value_ptr +evaluate_subexp_scm (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op = exp->elts[*pos].opcode; + int len, pc; char *str; + switch (op) + { + case OP_NAME: + pc = (*pos)++; + len = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1); + if (noside == EVAL_SKIP) + goto nosideret; + str = &exp->elts[pc + 2].string; + return scm_lookup_name (str); + case OP_EXPRSTRING: + pc = (*pos)++; + len = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1); + if (noside == EVAL_SKIP) + goto nosideret; + str = &exp->elts[pc + 2].string; + return scm_evaluate_string (str, len); + default: ; + } + return evaluate_subexp_standard (expect_type, exp, pos, noside); + nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +const struct language_defn scm_language_defn = { + "scheme", /* Language name */ + language_scm, + c_builtin_types, + range_check_off, + type_check_off, + scm_parse, + c_error, + evaluate_subexp_scm, + scm_printchar, /* Print a character constant */ + scm_printstr, /* Function to print string constant */ + NULL, /* Create fundamental type in this language */ + c_print_type, /* Print a type using appropriate syntax */ + scm_val_print, /* Print a value using appropriate syntax */ + scm_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"#o%lo", "#o", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"#x%lX", "#X", "X", ""}, /* Hex format info */ + NULL, /* expression operators for printing */ + 1, /* c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +void +_initialize_scheme_language () +{ + add_language (&scm_language_defn); + builtin_type_scm = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "SCM", (struct objfile *) NULL); +} diff --git a/contrib/gdb/gdb/scm-lang.h b/contrib/gdb/gdb/scm-lang.h new file mode 100644 index 000000000000..f990d774d722 --- /dev/null +++ b/contrib/gdb/gdb/scm-lang.h @@ -0,0 +1,50 @@ +#define SICP +#include "scm-tags.h" +#undef SCM_NCELLP +#define SCM_NCELLP(x) ((SCM_SIZE-1) & (int)(x)) +#define SCM_ITAG8_DATA(X) ((X)>>8) +#define SCM_ICHR(x) ((unsigned char)SCM_ITAG8_DATA(x)) +#define SCM_ICHRP(x) (SCM_ITAG8(x) == scm_tc8_char) +#define scm_tc8_char 0xf4 +#define SCM_IFLAGP(n) ((0x87 & (int)(n))==4) +#define SCM_ISYMNUM(n) ((int)((n)>>9)) +#define SCM_ISYMCHARS(n) (scm_isymnames[SCM_ISYMNUM(n)]) +#define SCM_ILOCP(n) ((0xff & (int)(n))==0xfc) +#define SCM_ITAG8(X) ((int)(X) & 0xff) +#define SCM_TYP7(x) (0x7f & (int)SCM_CAR(x)) +#define SCM_LENGTH(x) (((unsigned long)SCM_CAR(x))>>8) +#define SCM_NCONSP(x) (1 & (int)SCM_CAR(x)) +#define SCM_NECONSP(x) (SCM_NCONSP(x) && (1 != SCM_TYP3(x))) +#define SCM_CAR(x) scm_get_field (x, 0) +#define SCM_CDR(x) scm_get_field (x, 1) +#define SCM_VELTS(x) ((SCM *)SCM_CDR(x)) +#define SCM_CLOSCAR(x) (SCM_CAR(x)-scm_tc3_closure) +#define SCM_CODE(x) SCM_CAR(SCM_CLOSCAR (x)) +#define SCM_MAKINUM(x) (((x)<<2)+2L) + +#ifdef __STDC__ /* Forward decls for prototypes */ +struct value; +#endif + +extern int scm_value_print PARAMS ((struct value *, GDB_FILE*, + int, enum val_prettyprint)); + +extern int scm_val_print PARAMS ((struct type*, char*, CORE_ADDR, GDB_FILE*, + int, int, int, enum val_prettyprint)); + +extern LONGEST scm_get_field PARAMS ((LONGEST, int)); + +extern int scm_scmval_print PARAMS ((LONGEST, GDB_FILE *, + int, int, int, enum val_prettyprint)); + +extern int is_scmvalue_type PARAMS ((struct type*)); + +extern void scm_printchar PARAMS ((int, GDB_FILE*)); + +extern struct value * scm_evaluate_string PARAMS ((char*, int)); + +extern struct type *builtin_type_scm; + +extern int scm_parse (); + +extern LONGEST scm_unpack PARAMS ((struct type *, char *, enum type_code)); diff --git a/contrib/gdb/gdb/scm-tags.h b/contrib/gdb/gdb/scm-tags.h new file mode 100644 index 000000000000..a3b736b59daa --- /dev/null +++ b/contrib/gdb/gdb/scm-tags.h @@ -0,0 +1,385 @@ +/* This is a minimally edited version of Guile's tags.h. */ +/* classes: h_files */ + +#ifndef TAGSH +#define TAGSH +/* Copyright (C) 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + + +/** This file defines the format of SCM values and cons pairs. + ** It is here that tag bits are assigned for various purposes. + **/ + + +/* Three Bit Tags + * + * 000 -- a non-immediate value. Points into the pair heap. + * + * 001 -- a gloc (i.e., a resolved global variable in a CAR in a code graph) + * or the CAR of an object handle (i.e., the tagged pointer to the + * vtable part of a user-defined object). + * + * If X has this tag, the value at CDAR(X - 1) distinguishes + * glocs from object handles. The distinction only needs + * to be made in a few places. Only a few parts of the code know + * about glocs. In most cases, when a value in the CAR of a pair + * has the tag 001, it means that the pair is an object handle. + * + * 010 -- the tag for immediate, exact integers. + * + * 011 -- in the CAR of a pair, this tag indicates that the pair is a closure. + * The remaining bits of the CAR are a pointer into the pair heap + * to the code graph for the closure. + * + * 1xy -- an extension tag which means that there is a five or six bit + * tag to the left of the low three bits. See the nice diagrams + * in ../doc/code.doc if you want to know what the bits mean. + */ + + + + + +#define scm_tc3_cons 0 +#define scm_tc3_cons_gloc 1 +#define scm_tc3_closure 3 + +#define scm_tc7_ssymbol 5 +#define scm_tc7_msymbol 7 +#define scm_tc7_string 13 +#define scm_tc7_bvect 15 +#define scm_tc7_vector 21 +#define scm_tc7_lvector 23 +#define scm_tc7_ivect 29 +#define scm_tc7_uvect 31 +/* spare 37 39 */ +#define scm_tc7_fvect 45 +#define scm_tc7_dvect 47 +#define scm_tc7_cvect 53 +#define scm_tc7_port 55 +#define scm_tc7_contin 61 +#define scm_tc7_cclo 63 +/* spare 69 71 77 79 */ +#define scm_tc7_subr_0 85 +#define scm_tc7_subr_1 87 +#define scm_tc7_cxr 93 +#define scm_tc7_subr_3 95 +#define scm_tc7_subr_2 101 +#define scm_tc7_asubr 103 +#define scm_tc7_subr_1o 109 +#define scm_tc7_subr_2o 111 +#define scm_tc7_lsubr_2 117 +#define scm_tc7_lsubr 119 +#define scm_tc7_rpsubr 125 + +#define scm_tc7_smob 127 +#define scm_tc_free_cell 127 + +#define scm_tc16_flo 0x017f +#define scm_tc_flo 0x017fL + +#define SCM_REAL_PART (1L<<16) +#define SCM_IMAG_PART (2L<<16) +#define scm_tc_dblr (scm_tc16_flo|REAL_PART) +#define scm_tc_dblc (scm_tc16_flo|REAL_PART|IMAG_PART) + +#define scm_tc16_bigpos 0x027f +#define scm_tc16_bigneg 0x037f + +#define scm_tc16_fport (scm_tc7_port + 0*256L) +#define scm_tc16_pipe (scm_tc7_port + 1*256L) +#define scm_tc16_strport (scm_tc7_port + 2*256L) +#define scm_tc16_sfport (scm_tc7_port + 3*256L) + + + +/* For cons pairs with immediate values in the CAR */ +#define scm_tcs_cons_imcar 2:case 4:case 6:case 10:\ + case 12:case 14:case 18:case 20:\ + case 22:case 26:case 28:case 30:\ + case 34:case 36:case 38:case 42:\ + case 44:case 46:case 50:case 52:\ + case 54:case 58:case 60:case 62:\ + case 66:case 68:case 70:case 74:\ + case 76:case 78:case 82:case 84:\ + case 86:case 90:case 92:case 94:\ + case 98:case 100:case 102:case 106:\ + case 108:case 110:case 114:case 116:\ + case 118:case 122:case 124:case 126 + +/* For cons pairs with non-immediate values in the CAR */ +#define scm_tcs_cons_nimcar 0:case 8:case 16:case 24:\ + case 32:case 40:case 48:case 56:\ + case 64:case 72:case 80:case 88:\ + case 96:case 104:case 112:case 120 + +/* A CONS_GLOC occurs in code. It's CAR is a pointer to the + * CDR of a variable. The low order bits of the CAR are 001. + * The CDR of the gloc is the code continuation. + */ +#define scm_tcs_cons_gloc 1:case 9:case 17:case 25:\ + case 33:case 41:case 49:case 57:\ + case 65:case 73:case 81:case 89:\ + case 97:case 105:case 113:case 121 + +#define scm_tcs_closures 3:case 11:case 19:case 27:\ + case 35:case 43:case 51:case 59:\ + case 67:case 75:case 83:case 91:\ + case 99:case 107:case 115:case 123 + +#define scm_tcs_subrs scm_tc7_asubr:case scm_tc7_subr_0:case scm_tc7_subr_1:case scm_tc7_cxr:\ + case scm_tc7_subr_3:case scm_tc7_subr_2:case scm_tc7_rpsubr:case scm_tc7_subr_1o:\ + case scm_tc7_subr_2o:case scm_tc7_lsubr_2:case scm_tc7_lsubr + +#define scm_tcs_symbols scm_tc7_ssymbol:case scm_tc7_msymbol + +#define scm_tcs_bignums tc16_bigpos:case tc16_bigneg + + + +/* References to objects are of type SCM. Values may be non-immediate + * (pointers) or immediate (encoded, immutable, scalar values that fit + * in an SCM variable). + */ + +typedef long SCM; + +/* Cray machines have pointers that are incremented once for each word, + * rather than each byte, the 3 most significant bits encode the byte + * within the word. The following macros deal with this by storing the + * native Cray pointers like the ones that looks like scm expects. This + * is done for any pointers that might appear in the car of a scm_cell, pointers + * to scm_vector elts, functions, &c are not munged. + */ +#ifdef _UNICOS +# define SCM2PTR(x) ((int)(x) >> 3) +# define PTR2SCM(x) (((SCM)(x)) << 3) +# define SCM_POINTERS_MUNGED +#else +# define SCM2PTR(x) (x) +# define PTR2SCM(x) ((SCM)(x)) +#endif /* def _UNICOS */ + + + +/* Immediate? Predicates + */ +#define SCM_IMP(x) (6 & (int)(x)) +#define SCM_NIMP(x) (!SCM_IMP(x)) + + + +enum scm_tags +{ + scm_tc8_char = 0xf4 +}; + +#define SCM_ITAG8(X) ((int)(X) & 0xff) +#define SCM_MAKE_ITAG8(X, TAG) (((X)<<8) + TAG) +#define SCM_ITAG8_DATA(X) ((X)>>8) + + + +/* Local Environment Structure + */ +#define SCM_ILOCP(n) ((0xff & (int)(n))==0xfc) +#define SCM_ILOC00 (0x000000fcL) +#define SCM_IDINC (0x00100000L) +#define SCM_ICDR (0x00080000L) +#define SCM_IFRINC (0x00000100L) +#define SCM_IDSTMSK (-SCM_IDINC) +#define SCM_IFRAME(n) ((int)((SCM_ICDR-SCM_IFRINC)>>8) & ((int)(n)>>8)) +#define SCM_IDIST(n) (((unsigned long)(n))>>20) +#define SCM_ICDRP(n) (SCM_ICDR & (n)) + + +/* Immediate Symbols, Special Symbols, Flags (various constants). + */ + +/* ISYMP tests for ISPCSYM and ISYM */ +#define SCM_ISYMP(n) ((0x187 & (int)(n))==4) + +/* IFLAGP tests for ISPCSYM, ISYM and IFLAG */ +#define SCM_IFLAGP(n) ((0x87 & (int)(n))==4) +#define SCM_ISYMNUM(n) ((int)((n)>>9)) +#define SCM_ISYMCHARS(n) (scm_isymnames[SCM_ISYMNUM(n)]) +#define SCM_MAKSPCSYM(n) (((n)<<9)+((n)<<3)+4L) +#define SCM_MAKISYM(n) (((n)<<9)+0x74L) +#define SCM_MAKIFLAG(n) (((n)<<9)+0x174L) + +/* This table must agree with the declarations + * in repl.c: {Names of immediate symbols}. + * + * These are used only in eval but their values + * have to be allocated here. + * + */ + +#define SCM_IM_AND SCM_MAKSPCSYM(0) +#define SCM_IM_BEGIN SCM_MAKSPCSYM(1) +#define SCM_IM_CASE SCM_MAKSPCSYM(2) +#define SCM_IM_COND SCM_MAKSPCSYM(3) +#define SCM_IM_DO SCM_MAKSPCSYM(4) +#define SCM_IM_IF SCM_MAKSPCSYM(5) +#define SCM_IM_LAMBDA SCM_MAKSPCSYM(6) +#define SCM_IM_LET SCM_MAKSPCSYM(7) +#define SCM_IM_LETSTAR SCM_MAKSPCSYM(8) +#define SCM_IM_LETREC SCM_MAKSPCSYM(9) +#define SCM_IM_OR SCM_MAKSPCSYM(10) +#define SCM_IM_QUOTE SCM_MAKSPCSYM(11) +#define SCM_IM_SET SCM_MAKSPCSYM(12) +#define SCM_IM_DEFINE SCM_MAKSPCSYM(13) +#define SCM_IM_APPLY SCM_MAKISYM(14) +#define SCM_IM_CONT SCM_MAKISYM(15) +#define SCM_NUM_ISYMS 16 + +/* Important immediates + */ + +#define SCM_BOOL_F SCM_MAKIFLAG(SCM_NUM_ISYMS+0) +#define SCM_BOOL_T SCM_MAKIFLAG(SCM_NUM_ISYMS+1) +#define SCM_UNDEFINED SCM_MAKIFLAG(SCM_NUM_ISYMS+2) +#define SCM_EOF_VAL SCM_MAKIFLAG(SCM_NUM_ISYMS+3) + +#ifdef SICP +#define SCM_EOL SCM_BOOL_F +#else +#define SCM_EOL SCM_MAKIFLAG(SCM_NUM_ISYMS+4) +#endif + +#define SCM_UNSPECIFIED SCM_MAKIFLAG(SCM_NUM_ISYMS+5) + + + +/* Heap Pairs and the Empty List Predicates + */ +#define SCM_NULLP(x) (SCM_EOL == (x)) +#define SCM_NNULLP(x) (SCM_EOL != (x)) +#define SCM_CELLP(x) (!SCM_NCELLP(x)) +#define SCM_NCELLP(x) ((sizeof(scm_cell)-1) & (int)(x)) + + + +#define SCM_UNBNDP(x) (SCM_UNDEFINED==(x)) + + + +/* Testing and Changing GC Marks in Various Standard Positions + */ +#define SCM_GCMARKP(x) (1 & (int)SCM_CDR(x)) +#define SCM_GC8MARKP(x) (0x80 & (int)SCM_CAR(x)) +#define SCM_SETGCMARK(x) (SCM_CDR(x) |= 1) +#define SCM_CLRGCMARK(x) (SCM_CDR(x) &= ~1L) +#define SCM_SETGC8MARK(x) (SCM_CAR(x) |= 0x80) +#define SCM_CLRGC8MARK(x) (SCM_CAR(x) &= ~0x80L) + + +/* Extracting Tag Bits, With or Without GC Safety and Optional Bits + */ +#define SCM_TYP3(x) (7 & (int)SCM_CAR(x)) +#define SCM_TYP7(x) (0x7f & (int)SCM_CAR(x)) +#define SCM_TYP7S(x) (0x7d & (int)SCM_CAR(x)) +#define SCM_TYP16(x) (0xffff & (int)SCM_CAR(x)) +#define SCM_TYP16S(x) (0xfeff & (int)SCM_CAR(x)) +#define SCM_GCTYP16(x) (0xff7f & (int)SCM_CAR(x)) + + +/* Two slightly extensible types: smobs and ptobs. + * + */ +#define SCM_SMOBNUM(x) (0x0ff & (CAR(x)>>8)); +#define SCM_PTOBNUM(x) (0x0ff & (CAR(x)>>8)); + + + + +#define SCM_DIRP(x) (SCM_NIMP(x) && (TYP16(x)==(scm_tc16_dir))) +#define SCM_OPDIRP(x) (SCM_NIMP(x) && (CAR(x)==(scm_tc16_dir | OPN))) + + + +/* Lvectors + */ +#define SCM_LVECTORP(x) (TYP7(x)==tc7_lvector) + + +#if 0 + +/* Sockets + */ +#define tc_socket (tc7_port | OPN) +#define SCM_SOCKP(x) (((0x7f | OPN | RDNG | WRTNG) & CAR(x))==(tc_socket)) +#define SCM_SOCKTYP(x) (CAR(x)>>24) + + + +extern int scm_tc16_key_vector; +#define SCM_KEYVECP(X) (scm_tc16_key_vector == TYP16 (X)) +#define SCM_KEYVECLEN(OBJ) (((unsigned long)CAR (obj)) >> 16) + + +#define SCM_MALLOCDATA(obj) ((char *)CDR(obj)) +#define SCM_MALLOCLEN(obj) (((unsigned long)CAR (obj)) >> 16) +#define SCM_WORDDATA(obj) (CDR (obj)) + + +#define SCM_BYTECODEP(X) ((TYP7 (X) == tc7_cclo) && (CCLO_SUBR (X) == rb_proc)) +#define SCM_BYTECODE_CONSTANTS(X) (VELTS(X)[1]) +#define SCM_BYTECODE_CODE(X) (VELTS(X)[2]) +#define SCM_BYTECODE_NAME(X) (VELTS(X)[3]) +#define SCM_BYTECODE_BCODE(X) (VELTS(X)[4]) +#define SCM_BYTECODE_ELTS 5 + + +#define SCM_FREEP(x) (CAR(x)==tc_free_cell) +#define SCM_NFREEP(x) (!FREEP(x)) + +#endif /* 0*/ + +#ifdef __STDC__ + +#else /* STDC */ + +#endif /* STDC */ + + +#endif /* TAGSH */ diff --git a/contrib/gdb/gdb/scm-valprint.c b/contrib/gdb/gdb/scm-valprint.c new file mode 100644 index 000000000000..8544870efab2 --- /dev/null +++ b/contrib/gdb/gdb/scm-valprint.c @@ -0,0 +1,404 @@ +/* Scheme/Guile language support routines for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "value.h" +#include "scm-lang.h" +#include "valprint.h" + +/* Prints the SCM value VALUE by invoking the inferior, if appropraite. + Returns >= 0 on succes; retunr -1 if the inferior cannot/should not + print VALUE. */ + +int +scm_inferior_print (value, stream, format, deref_ref, recurse, pretty) + LONGEST value; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + return -1; +} + +/* {Names of immediate symbols} + * This table must agree with the declarations in scm.h: {Immediate Symbols}.*/ + +static char *scm_isymnames[] = +{ + /* This table must agree with the declarations */ + "and", + "begin", + "case", + "cond", + "do", + "if", + "lambda", + "let", + "let*", + "letrec", + "or", + "quote", + "set!", + "define", +#if 0 + "literal-variable-ref", + "literal-variable-set!", +#endif + "apply", + "call-with-current-continuation", + + /* user visible ISYMS */ + /* other keywords */ + /* Flags */ + + "#f", + "#t", + "#", + "#", + "()", + "#" +}; + +static int +scm_scmlist_print (svalue, stream, format, deref_ref, recurse, pretty) + LONGEST svalue; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + unsigned int more = print_max; + if (recurse > 6) + { + fputs_filtered ("...", stream); + return 0; + } + scm_scmval_print (SCM_CAR (svalue), stream, format, + deref_ref, recurse + 1, pretty); + svalue = SCM_CDR (svalue); + for (; SCM_NIMP (svalue); svalue = SCM_CDR (svalue)) + { + if (SCM_NECONSP (svalue)) + break; + fputs_filtered (" ", stream); + if (--more == 0) + { + fputs_filtered ("...", stream); + return; + } + scm_scmval_print (SCM_CAR (svalue), stream, format, + deref_ref, recurse + 1, pretty); + } + if (SCM_NNULLP (svalue)) + { + fputs_filtered (" . ", stream); + scm_scmval_print (svalue, stream, format, + deref_ref, recurse + 1, pretty); + } +} + +static void +scm_ipruk (hdr, ptr, stream) + char *hdr; + LONGEST ptr; + GDB_FILE *stream; +{ + fprintf_filtered (stream, "#", ptr); +} + +int +scm_scmval_print (svalue, stream, format, deref_ref, recurse, pretty) + LONGEST svalue; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + taloop: + switch (7 & svalue) + { + case 2: + case 6: + print_longest (stream, format ? format : 'd', 1, svalue >> 2); + break; + case 4: + if (SCM_ICHRP (svalue)) + { + svalue = SCM_ICHR (svalue); + scm_printchar (svalue, stream); + break; + } + else if (SCM_IFLAGP (svalue) + && (SCM_ISYMNUM (svalue) + < (sizeof scm_isymnames / sizeof (char *)))) + { + fputs_filtered (SCM_ISYMCHARS (svalue), stream); + break; + } + else if (SCM_ILOCP (svalue)) + { + fprintf_filtered (stream, "#@%ld%c%ld", + (long) SCM_IFRAME (svalue), + SCM_ICDRP (svalue) ? '-' : '+', + (long) SCM_IDIST (svalue)); + break; + } + else + goto idef; + break; + case 1: + /* gloc */ + svalue = SCM_CAR (svalue - 1); + goto taloop; + default: + idef: + scm_ipruk ("immediate", svalue, stream); + break; + case 0: + + switch (SCM_TYP7 (svalue)) + { + case scm_tcs_cons_gloc: + if (SCM_CDR (SCM_CAR (svalue) - 1L) == 0) + { + SCM name; + fputs_filtered ("#", svalue); + break; + } + case scm_tcs_cons_imcar: + case scm_tcs_cons_nimcar: + fputs_filtered ("(", stream); + scm_scmlist_print (svalue, stream, format, + deref_ref, recurse + 1, pretty); + fputs_filtered (")", stream); + break; + case scm_tcs_closures: + fputs_filtered ("#", stream); + break; + case scm_tc7_string: + { + int len = SCM_LENGTH (svalue); + CORE_ADDR addr = (CORE_ADDR) SCM_CDR (svalue); + int i; + int done = 0; + int buf_size; + char buffer[64]; + int truncate = print_max && len > (int) print_max; + if (truncate) + len = print_max; + fputs_filtered ("\"", stream); + for (; done < len; done += buf_size) + { + buf_size = min (len - done, 64); + read_memory (addr + done, buffer, buf_size); + + for (i = 0; i < buf_size; ++i) + switch (buffer[i]) + { + case '\"': + case '\\': + fputs_filtered ("\\", stream); + default: + fprintf_filtered (stream, "%c", buffer[i]); + } + } + fputs_filtered (truncate ? "...\"" : "\"", stream); + break; + } + break; + case scm_tcs_symbols: + { + int len = SCM_LENGTH (svalue); + + char * str = (char*) alloca (len); + read_memory (SCM_CDR (svalue), str, len + 1); + /* Should handle weird characters FIXME */ + str[len] = '\0'; + fputs_filtered (str, stream); + break; + } + case scm_tc7_vector: + { + int len = SCM_LENGTH (svalue); + int i; + LONGEST elements = SCM_CDR(svalue); + fputs_filtered ("#(", stream); + for (i = 0; i < len; ++i) + { + if (i > 0) + fputs_filtered (" ", stream); + scm_scmval_print (scm_get_field (elements, i), stream, format, + deref_ref, recurse + 1, pretty); + } + fputs_filtered (")", stream); + } + break; +#if 0 + case tc7_lvector: + { + SCM result; + SCM hook; + hook = scm_get_lvector_hook (exp, LV_PRINT_FN); + if (hook == BOOL_F) + { + scm_puts ("#", port); + } + else + { + result + = scm_apply (hook, + scm_listify (exp, port, (writing ? BOOL_T : BOOL_F), + SCM_UNDEFINED), + EOL); + if (result == BOOL_F) + goto punk; + } + break; + } + break; + case tc7_bvect: + case tc7_ivect: + case tc7_uvect: + case tc7_fvect: + case tc7_dvect: + case tc7_cvect: + scm_raprin1 (exp, port, writing); + break; +#endif + case scm_tcs_subrs: + { + int index = SCM_CAR (svalue) >> 8; +#if 1 + char str[20]; + sprintf (str, "#%d", index); +#else + char *str = index ? SCM_CHARS (scm_heap_org+index) : ""; +#define SCM_CHARS(x) ((char *)(SCM_CDR(x))) + char *str = CHARS (SNAME (exp)); +#endif + fprintf_filtered (stream, "#", + str); + } + break; +#if 0 +#ifdef CCLO + case tc7_cclo: + scm_puts ("#', port); + break; +#endif + case tc7_contin: + fprintf_filtered (stream, "#", + LENGTH (svalue), + (long) CHARS (svalue)); + break; + case tc7_port: + i = PTOBNUM (exp); + if (i < scm_numptob && scm_ptobs[i].print && (scm_ptobs[i].print) (exp, port, writing)) + break; + goto punk; + case tc7_smob: + i = SMOBNUM (exp); + if (i < scm_numsmob && scm_smobs[i].print + && (scm_smobs[i].print) (exp, port, writing)) + break; + goto punk; +#endif + default: + punk:scm_ipruk ("type", svalue, stream); + } + break; + } +} + +int +scm_val_print (type, valaddr, address, stream, format, deref_ref, recurse, + pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + if (is_scmvalue_type (type)) + { + LONGEST svalue = extract_signed_integer (valaddr, TYPE_LENGTH (type)); + if (scm_inferior_print (svalue, stream, format, + deref_ref, recurse, pretty) >= 0) + { + } + else + { + scm_scmval_print (svalue, stream, format, + deref_ref, recurse, pretty); + } + + gdb_flush (stream); + return (0); + } + else + { + return c_val_print (type, valaddr, address, stream, format, + deref_ref, recurse, pretty); + } +} + +int +scm_value_print (val, stream, format, pretty) + value_ptr val; + GDB_FILE *stream; + int format; + enum val_prettyprint pretty; +{ + return (val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1, 0, pretty)); +} diff --git a/contrib/gdb/gdb/ser-e7kpc.c b/contrib/gdb/gdb/ser-e7kpc.c new file mode 100644 index 000000000000..9faf7ddca6de --- /dev/null +++ b/contrib/gdb/gdb/ser-e7kpc.c @@ -0,0 +1,420 @@ +/* Remote serial interface using Hitachi E7000 PC ISA card in a PC + + Copyright 1994 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __GO32__ +#include "defs.h" +#include "serial.h" +#include + + + +static int e7000pc_open PARAMS ((serial_t scb, const char *name)); +static void e7000pc_raw PARAMS ((serial_t scb)); +static int e7000pc_readchar PARAMS ((serial_t scb, int timeout)); +static int e7000pc_setbaudrate PARAMS ((serial_t scb, int rate)); +static int e7000pc_write PARAMS ((serial_t scb, const char *str, int len)); +static void e7000pc_close PARAMS ((serial_t scb)); +static serial_ttystate e7000pc_get_tty_state PARAMS ((serial_t scb)); +static int e7000pc_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); +static char *aptr PARAMS ((short p)); + +static int dos_async_init PARAMS ((int port)); +static void dos_async_tx PARAMS ((const char c)); +static int dos_async_rx PARAMS (()); + + + +#define OFF_DPD 0x0000 +#define OFF_DDP 0x1000 +#define OFF_CPD 0x2000 +#define OFF_CDP 0x2400 +#define OFF_FA 0x3000 +#define OFF_FB 0x3002 +#define OFF_FC 0x3004 +#define OFF_IRQTOD 0x3008 +#define OFF_IRQTOP 0x300a +#define OFF_READY 0x300c +#define OFF_PON 0x300e + +#define IDLE 0x0000 +#define CMD_CI 0x4349 +#define CMD_CO 0x434f +#define CMD_LO 0x4c4f +#define CMD_LS 0x4c53 +#define CMD_SV 0x5356 +#define CMD_SS 0x5353 +#define CMD_OK 0x4f4b +#define CMD_ER 0x4552 +#define CMD_NF 0x4e46 +#define CMD_AB 0x4142 +#define CMD_ED 0x4544 +#define CMD_CE 0x4345 + +static unsigned long fa; +static unsigned long irqtod; +static unsigned long ready; +static unsigned long fb; +static unsigned long cpd ; +static unsigned long cdp ; +static unsigned long ready; +static unsigned long pon; +static unsigned long irqtop; +static unsigned long board_at; + +#define SET_BYTE(x,y) { char _buf = y;dosmemput(&_buf,1, x);} +#define SET_WORD(x,y) { short _buf = y;dosmemput(&_buf,2, x);} +#define GET_BYTE(x) ( dosmemget(x,1,&bb), bb) +#define GET_WORD(x) ( dosmemget(x,2,&sb), sb) + +static unsigned char bb; +static unsigned short sb; + + +static struct sw +{ + int sw; + int addr; +} sigs[] = { + {0x14, 0xd0000}, + {0x15, 0xd4000}, + {0x16, 0xd8000}, + {0x17, 0xdc000}, + 0}; + +static int +e7000pc_init () +{ + /* Look around in memory for the board's signature */ + + int try; + + for (try = 0; sigs[try].sw; try++) + + { + int val; + board_at = sigs[try].addr; + fa = board_at + OFF_FA; + fb = board_at + OFF_FB; + cpd = board_at + OFF_CPD; + cdp = board_at + OFF_CDP; + ready =board_at + OFF_READY; + pon = board_at + OFF_PON; + irqtop = board_at + OFF_IRQTOP; + irqtod = board_at + OFF_IRQTOD; + + val = GET_WORD (ready); + + if (val == (0xaaa0 | sigs[try].sw)) + { + if (GET_BYTE (pon) & 0xf) + { + SET_BYTE(fa, 0); + SET_BYTE (fb, 0); + + SET_BYTE (irqtop, 1); /* Disable interrupts from e7000 */ + SET_WORD (ready, 1); + printf_filtered ("\nConnected to the E7000PC at address 0x%x\n", + sigs[try].addr); + return 1; + } + error ("The E7000 PC board is working, but the E7000 is turned off.\n"); + return 0; + } + } + + error ("GDB cannot connect to the E7000 PC board, check that it is installed\n\ +and that the switch settings are correct. Some other DOS programs can \n\ +stop the board from working. Try starting from a very minimal boot, \n\ +perhaps you need to disable EMM386 over the region where the board has\n\ +its I/O space, remove other unneeded cards, etc etc\n"); + return 0; + +} + +static int pbuf_size; +static int pbuf_index; + +static +int +e7000_get () +{ + static char pbuf[1000]; + char tmp[1000]; + int x; + if (pbuf_index < pbuf_size) + { + x = pbuf[pbuf_index++]; + } + else if ((GET_BYTE (fb) & 1)) + { + int i; + pbuf_size = GET_WORD(cdp + 2); + + dosmemget (cdp + 8, pbuf_size + 1, tmp); + + /* Tell the E7000 we've eaten */ + SET_BYTE(fb,0); + /* Swap it around */ + for (i = 0; i < pbuf_size; i++) + { + pbuf[i] = tmp[i^1]; + } + pbuf_index = 0; + x = pbuf[pbuf_index++]; + } + else + { + x = -1; + } + return x; +} + +static int +dosasync_read (fd, buf, len, timeout) + int fd; + char *buf; + int len; + int timeout; + +{ + long now; + long then; + int i = 0; + int p; + + /* Then look for some more if we're still hungry */ + time (&now); + then = now + timeout; + while (i < len) + { + int ch = e7000_get(); + + /* While there's room in the buffer, and we've already + read the stuff in, suck it over */ + if (ch != -1) + { + buf[i++] = ch; + while (i < len && pbuf_index < pbuf_size ) + { + ch = e7000_get(); + if (ch == -1) + break; + buf[i++] = ch; + } + } + + time (&now); + + if (timeout == 0) + return i; + if (now >= then && timeout > 0) + { + return i; + } + } + return len; +} + + +static int +dosasync_write (fd, buf, len) + int fd; + const char *buf; + int len; +{ + int i; + char dummy[1000]; + + + /* Construct copy locally */ + ((short *)dummy)[0] = CMD_CI; + ((short *)dummy)[1] = len; + ((short *)dummy)[2] = 0; + ((short *)dummy)[3] = 0; + for (i = 0; i < len ; i++) + { + dummy[8 + i ^ 1] = buf[i]; + } + + /* Wait for the card to get ready */ + while ((GET_BYTE(fa) & 1) != 0) + ; + + /* Blast onto the ISA card */ + dosmemput (dummy, 8 + len + 1, cpd); + + SET_BYTE(fa, 1); + SET_BYTE(irqtod, 1); /* Interrupt the E7000 */ + + return len; +} + +static int +e7000pc_open (scb, name) + serial_t scb; + const char *name; +{ + if (strncasecmp (name, "pc", 2) != 0) + { + errno = ENOENT; + return -1; + } + + scb->fd = e7000pc_init (); + + if (!scb->fd) + return -1; + + return 0; +} + +static int +e7000pc_noop (scb) + serial_t scb; +{ + return 0; +} + +static void +e7000pc_raw (scb) + serial_t scb; +{ + /* Always in raw mode */ +} + +static int +e7000pc_readchar (scb, timeout) + serial_t scb; + int timeout; +{ + char buf; + + top: + + if (dosasync_read (scb->fd, &buf, 1, timeout)) + { + if (buf == 0) goto top; + return buf; + } + else + return SERIAL_TIMEOUT; +} + +struct e7000pc_ttystate { + int dummy; +}; + +/* e7000pc_{get set}_tty_state() are both dummys to fill out the function + vector. Someday, they may do something real... */ + +static serial_ttystate +e7000pc_get_tty_state (scb) + serial_t scb; +{ + struct e7000pc_ttystate *state; + + state = (struct e7000pc_ttystate *) xmalloc (sizeof *state); + + return (serial_ttystate) state; +} + +static int +e7000pc_set_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + return 0; +} + +static int +e7000pc_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + return 0; +} + +static void +e7000pc_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + /* Nothing to print. */ + return; +} + +static int +e7000pc_setbaudrate (scb, rate) + serial_t scb; + int rate; +{ + return 0; +} + +static int +e7000pc_write (scb, str, len) + serial_t scb; + const char *str; + int len; +{ + dosasync_write (scb->fd, str, len); + + return 0; +} + +static void +e7000pc_close (scb) + serial_t scb; +{ +} + +static struct serial_ops e7000pc_ops = +{ + "pc", + 0, + e7000pc_open, + e7000pc_close, + e7000pc_readchar, + e7000pc_write, + e7000pc_noop, /* flush output */ + e7000pc_noop, /* flush input */ + e7000pc_noop, /* send break -- currently used only for nindy */ + e7000pc_raw, + e7000pc_get_tty_state, + e7000pc_set_tty_state, + e7000pc_print_tty_state, + e7000pc_noflush_set_tty_state, + e7000pc_setbaudrate, +}; + +void +_initialize_ser_e7000pc () +{ + serial_add_interface (&e7000pc_ops); +} +#else + +void +_initialize_ser_e7000pc () +{ + +} +#endif diff --git a/contrib/gdb/gdb/ser-go32.c b/contrib/gdb/gdb/ser-go32.c new file mode 100644 index 000000000000..4af25f14019d --- /dev/null +++ b/contrib/gdb/gdb/ser-go32.c @@ -0,0 +1,957 @@ +/* Remote serial interface for local (hardwired) serial ports for + GO32. Copyright 1992, 1993 Free Software Foundation, Inc. + + Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk). + + This version uses DPMI interrupts to handle buffered i/o + without the separate "asynctsr" program. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "serial.h" + + +/* + * NS16550 UART registers + */ + +#define COM1ADDR 0x3f8 +#define COM2ADDR 0x2f8 +#define COM3ADDR 0x3e8 +#define COM4ADDR 0x3e0 + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_fifo 2 /* FIFO control (W) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ + +/* + * Constants for computing 16 bit baud rate divisor (lower byte + * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal. Divisor is + * 1.8432 MHz / (16 * X) for X bps. If the baud rate can't be set + * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail. + */ +#define COMTICK (1843200/16) +#define SPEED_TOLERANCE 30 /* thousandths; real == desired +- 3.0% */ + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 /* int on rx ready */ +#define IER_ETXRDY 0x2 /* int on tx ready */ +#define IER_ERLS 0x4 /* int on line status change */ +#define IER_EMSC 0x8 /* int on modem status change */ + +/* interrupt identification register */ +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ +#define IIR_IMASK 0xf /* interrupt cause mask */ +#define IIR_NOPEND 0x1 /* nothing pending */ +#define IIR_RLS 0x6 /* receive line status */ +#define IIR_RXRDY 0x4 /* receive ready */ +#define IIR_RXTOUT 0xc /* receive timeout */ +#define IIR_TXRDY 0x2 /* transmit ready */ +#define IIR_MLSC 0x0 /* modem status */ + + +/* fifo control register */ +#define FIFO_ENABLE 0x01 /* enable fifo */ +#define FIFO_RCV_RST 0x02 /* reset receive fifo */ +#define FIFO_XMT_RST 0x04 /* reset transmit fifo */ +#define FIFO_DMA_MODE 0x08 /* enable dma mode */ +#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */ +#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */ +#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */ +#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */ + +/* character format control register */ +#define CFCR_DLAB 0x80 /* divisor latch */ +#define CFCR_SBREAK 0x40 /* send break */ +#define CFCR_PZERO 0x30 /* zero parity */ +#define CFCR_PONE 0x20 /* one parity */ +#define CFCR_PEVEN 0x10 /* even parity */ +#define CFCR_PODD 0x00 /* odd parity */ +#define CFCR_PENAB 0x08 /* parity enable */ +#define CFCR_STOPB 0x04 /* 2 stop bits */ +#define CFCR_8BITS 0x03 /* 8 data bits */ +#define CFCR_7BITS 0x02 /* 7 data bits */ +#define CFCR_6BITS 0x01 /* 6 data bits */ +#define CFCR_5BITS 0x00 /* 5 data bits */ + +/* modem control register */ +#define MCR_LOOPBACK 0x10 /* loopback */ +#define MCR_IENABLE 0x08 /* output 2 = int enable */ +#define MCR_DRS 0x04 /* output 1 = xxx */ +#define MCR_RTS 0x02 /* enable RTS */ +#define MCR_DTR 0x01 /* enable DTR */ + +/* line status register */ +#define LSR_RCV_FIFO 0x80 /* error in receive fifo */ +#define LSR_TSRE 0x40 /* transmitter empty */ +#define LSR_TXRDY 0x20 /* transmitter ready */ +#define LSR_BI 0x10 /* break detected */ +#define LSR_FE 0x08 /* framing error */ +#define LSR_PE 0x04 /* parity error */ +#define LSR_OE 0x02 /* overrun error */ +#define LSR_RXRDY 0x01 /* receiver ready */ +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +#include +#include +#include + +/* DPMI Communication */ +static union REGS dpmi_regs; +static struct SREGS dpmi_sregs; + +/* 16550 rx fifo trigger point */ +#define FIFO_TRIGGER FIFO_TRIGGER_4 + +/* input buffer size */ +#define CBSIZE 4096 + +/* return raw 18Hz clock count */ +extern long rawclock (void); + +#define RAWHZ 18 + +#ifdef DOS_STATS +#define CNT_RX 16 +#define CNT_TX 17 +#define CNT_STRAY 18 +#define CNT_ORUN 19 +#define NCNT 20 + +static int intrcnt; +static int cnts[NCNT]; +static char *cntnames[NCNT] = { + /* h/w interrupt counts. */ + "mlsc", "nopend", "txrdy", "?3", + "rxrdy", "?5", "rls", "?7", + "?8", "?9", "?a", "?b", + "rxtout", "?d", "?e", "?f", + /* s/w counts. */ + "rxcnt", "txcnt", "stray", "swoflo" +}; + +#define COUNT(x) cnts[x]++ +#else +#define COUNT(x) +#endif + +/* Main interrupt controller port addresses. */ +#define ICU_BASE 0x20 +#define ICU_OCW2 (ICU_BASE + 0) +#define ICU_MASK (ICU_BASE + 1) + +/* Original interrupt controller mask register. */ +unsigned char icu_oldmask; + +/* Maximum of 8 interrupts (we don't handle the slave icu yet). */ +#define NINTR 8 + +static struct intrupt +{ + char inuse; + struct dos_ttystate *port; + _go32_dpmi_seginfo old_rmhandler; + _go32_dpmi_seginfo old_pmhandler; + _go32_dpmi_seginfo new_rmhandler; + _go32_dpmi_seginfo new_pmhandler; + _go32_dpmi_registers regs; +} intrupts[NINTR]; + + +static struct dos_ttystate +{ + int base; + int irq; + int refcnt; + struct intrupt *intrupt; + int fifo; + int baudrate; + unsigned char cbuf[CBSIZE]; + unsigned int first; + unsigned int count; + int txbusy; + unsigned char old_mcr; + int ferr; + int perr; + int oflo; + int msr; +} ports[4] = { + {COM1ADDR, 4}, + {COM2ADDR, 3}, + {COM3ADDR, 4}, + {COM4ADDR, 3} +}; + +static int dos_open PARAMS ((serial_t scb, const char *name)); +static void dos_raw PARAMS ((serial_t scb)); +static int dos_readchar PARAMS ((serial_t scb, int timeout)); +static int dos_setbaudrate PARAMS ((serial_t scb, int rate)); +static int dos_write PARAMS ((serial_t scb, const char *str, int len)); +static void dos_close PARAMS ((serial_t scb)); +static serial_ttystate dos_get_tty_state PARAMS ((serial_t scb)); +static int dos_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); +static int dos_baudconv PARAMS ((int rate)); + +#define inb(p,a) inportb((p)->base + (a)) +#define outb(p,a,v) outportb((p)->base + (a), (v)) +#define disable() asm volatile ("cli"); +#define enable() asm volatile ("sti"); + + +static int +dos_getc (port) + volatile struct dos_ttystate *port; +{ + int c; + + if (port->count == 0) + return -1; + + c = port->cbuf[port->first]; + disable (); + port->first = (port->first + 1) & (CBSIZE - 1); + port->count--; + enable (); + return c; +} + + +static int +dos_putc (c, port) + int c; + struct dos_ttystate *port; +{ + if (port->count >= CBSIZE - 1) + return -1; + port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c; + port->count++; + return 0; +} + + + +static void +dos_comisr (irq) + int irq; +{ + struct dos_ttystate *port; + unsigned char iir, lsr, c; + + disable (); /* Paranoia */ + outportb (ICU_OCW2, 0x20); /* End-Of-Interrupt */ +#ifdef DOS_STATS + ++intrcnt; +#endif + + port = intrupts[irq].port; + if (!port) + { + COUNT (CNT_STRAY); + return; /* not open */ + } + + while (1) + { + iir = inb (port, com_iir) & IIR_IMASK; + switch (iir) + { + + case IIR_RLS: + lsr = inb (port, com_lsr); + goto rx; + + case IIR_RXTOUT: + case IIR_RXRDY: + lsr = 0; + + rx: + do + { + c = inb (port, com_data); + if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE)) + { + if (lsr & (LSR_BI | LSR_FE)) + port->ferr++; + else if (lsr & LSR_PE) + port->perr++; + if (lsr & LSR_OE) + port->oflo++; + } + + if (dos_putc (c, port) < 0) + { + COUNT (CNT_ORUN); + } + else + { + COUNT (CNT_RX); + } + } + while ((lsr = inb (port, com_lsr)) & LSR_RXRDY); + break; + + case IIR_MLSC: + /* could be used to flowcontrol Tx */ + port->msr = inb (port, com_msr); + break; + + case IIR_TXRDY: + port->txbusy = 0; + break; + + case IIR_NOPEND: + /* no more pending interrupts, all done */ + return; + + default: + /* unexpected interrupt, ignore */ + break; + } + COUNT (iir); + } +} + +#ifdef __STDC__ +#define ISRNAME(x) dos_comisr##x +#else +#define ISRNAME(x) dos_comisr/**/x +#endif +#define ISR(x) static void ISRNAME(x)() {dos_comisr(x);} + +ISR(0) ISR(1) ISR(2) ISR(3) +ISR(4) ISR(5) ISR(6) ISR(7) + +typedef void (*isr_t)(); + +static isr_t isrs[NINTR] = { + ISRNAME(0), ISRNAME(1), ISRNAME(2), ISRNAME(3), + ISRNAME(4), ISRNAME(5), ISRNAME(6), ISRNAME(7) +}; + + + +static struct intrupt * +dos_hookirq (irq) + unsigned int irq; +{ + struct intrupt *intr; + unsigned int vec; + isr_t isr; + + if (irq >= NINTR) + return 0; + + intr = &intrupts[irq]; + if (intr->inuse) + return 0; + + vec = 0x08 + irq; + isr = isrs[irq]; + + /* setup real mode handler */ + _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler); + + intr->new_rmhandler.pm_selector = _go32_my_cs(); + intr->new_rmhandler.pm_offset = (u_long)isr; + if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler, + &intr->regs)) + { + return 0; + } + + if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler)) + { + return 0; + } + + /* setup protected mode handler */ + _go32_dpmi_get_protected_mode_interrupt_vector(vec, &intr->old_pmhandler); + + intr->new_pmhandler.pm_selector = _go32_my_cs(); + intr->new_pmhandler.pm_offset = (u_long)isr; + _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler); + + if (_go32_dpmi_set_protected_mode_interrupt_vector(vec, &intr->new_pmhandler)) + { + return 0; + } + + /* setup interrupt controller mask */ + disable (); + outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq)); + enable (); + + intr->inuse = 1; + return intr; +} + + +static void +dos_unhookirq (intr) + struct intrupt *intr; +{ + unsigned int irq, vec; + unsigned char mask; + + irq = intr - intrupts; + vec = 0x08 + irq; + + /* restore old interrupt mask bit */ + mask = 1 << irq; + disable (); + outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask)); + enable (); + + /* remove real mode handler */ + _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler); + _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler); + + /* remove protected mode handler */ + _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler); + _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler); + intr->inuse = 0; +} + + + +static int +dos_open (scb, name) + serial_t scb; + const char *name; +{ + struct dos_ttystate *port; + int fd, i; + + if (strncasecmp (name, "/dev/", 5) == 0) + name += 5; + else if (strncasecmp (name, "\\dev\\", 5) == 0) + name += 5; + + if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0) + { + errno = ENOENT; + return -1; + } + + if (name[3] < '1' || name[3] > '4') + { + errno = ENOENT; + return -1; + } + + fd = name[3] - '1'; + port = &ports[fd]; + if (port->refcnt++ > 0) + { + /* Device already opened another user. Just point at it. */ + scb->fd = fd; + return 0; + } + + /* force access to ID reg */ + outb(port, com_cfcr, 0); + outb(port, com_iir, 0); + for (i = 0; i < 17; i++) { + if ((inb(port, com_iir) & 0x38) == 0) + goto ok; + (void) inb(port, com_data); /* clear recv */ + } + errno = ENODEV; + return -1; + +ok: + /* disable all interrupts in chip */ + outb(port, com_ier, 0); + + /* tentatively enable 16550 fifo, and see if it responds */ + outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER); + sleep(1); + port->fifo = ((inb(port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK); + + /* clear pending status reports. */ + (void) inb(port, com_lsr); + (void) inb(port, com_msr); + + /* enable external interrupt gate (to avoid floating IRQ) */ + outb(port, com_mcr, MCR_IENABLE); + + /* hook up interrupt handler and initialise icu */ + port->intrupt = dos_hookirq (port->irq); + if (!port->intrupt) + { + outb(port, com_mcr, 0); + outb(port, com_fifo, 0); + errno = ENODEV; + return -1; + } + + disable (); + + /* record port */ + port->intrupt->port = port; + scb->fd = fd; + + /* clear rx buffer, tx busy flag and overflow count */ + port->first = port->count = 0; + port->txbusy = 0; + port->oflo = 0; + + /* set default baud rate and mode: 9600,8,n,1 */ + i = dos_baudconv (port->baudrate = 9600); + outb(port, com_cfcr, CFCR_DLAB); + outb(port, com_dlbl, i & 0xff); + outb(port, com_dlbh, i >> 8); + outb(port, com_cfcr, CFCR_8BITS); + + /* enable all interrupts */ + outb(port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC); + + /* enable DTR & RTS */ + outb(port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE); + + enable (); + + return 0; +} + + +static void +dos_close (scb) + serial_t scb; +{ + struct dos_ttystate *port; + struct intrupt *intrupt; + + if (!scb) + return; + + port = &ports[scb->fd]; + + if (port->refcnt-- > 1) + return; + + if (!(intrupt = port->intrupt)) + return; + + /* disable interrupts, fifo, flow control */ + disable (); + port->intrupt = 0; + intrupt->port = 0; + outb(port, com_fifo, 0); + outb(port, com_ier, 0); + enable (); + + /* unhook handler, and disable interrupt gate */ + dos_unhookirq (intrupt); + outb(port, com_mcr, 0); + + /* Check for overflow errors */ + if (port->oflo) + { + fprintf_unfiltered (gdb_stderr, + "Serial input overruns occurred.\n"); + fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n", + port->fifo ? "cannot" : "needs a 16550 to", + port->baudrate); + } +} + + + +static int +dos_noop (scb) + serial_t scb; +{ + return 0; +} + +static void +dos_raw (scb) + serial_t scb; +{ + /* Always in raw mode */ +} + +static int +dos_readchar (scb, timeout) + serial_t scb; + int timeout; +{ + struct dos_ttystate *port = &ports[scb->fd]; + long then; + int c; + + then = rawclock() + (timeout * RAWHZ); + while ((c = dos_getc (port)) < 0) + { + if (timeout >= 0 && (rawclock () - then) >= 0) + return SERIAL_TIMEOUT; + notice_quit (); + } + + return c; +} + + +static serial_ttystate +dos_get_tty_state (scb) + serial_t scb; +{ + struct dos_ttystate *port = &ports[scb->fd]; + struct dos_ttystate *state; + + state = (struct dos_ttystate *) xmalloc (sizeof *state); + *state = *port; + return (serial_ttystate) state; +} + +static int +dos_set_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct dos_ttystate *state; + + state = (struct dos_ttystate *) ttystate; + dos_setbaudrate (scb, state->baudrate); + return 0; +} + +static int +dos_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + struct dos_ttystate *state; + + state = (struct dos_ttystate *) new_ttystate; + dos_setbaudrate (scb, state->baudrate); + return 0; +} + +static int +dos_flush_input (scb) + serial_t scb; +{ + struct dos_ttystate *port = &ports[scb->fd]; + disable(); + port->first = port->count = 0; + if (port->fifo) + outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_TRIGGER); + enable(); +} + +static void +dos_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + /* Nothing to print */ + return; +} + +static int +dos_baudconv (rate) + int rate; +{ + long x, err; + + if (rate <= 0) + return -1; + +#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* divide and round off */ + x = divrnd(COMTICK, rate); + if (x <= 0) + return -1; + + err = divrnd(1000 * COMTICK, x * rate) - 1000; + if (err < 0) + err = -err; + if (err > SPEED_TOLERANCE) + return -1; +#undef divrnd + return x; +} + + +static int +dos_setbaudrate (scb, rate) + serial_t scb; + int rate; +{ + struct dos_ttystate *port = &ports[scb->fd]; + + if (port->baudrate != rate) + { + int x; + unsigned char cfcr; + + x = dos_baudconv (rate); + if (x <= 0) + { + fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate); + errno = EINVAL; + return -1; + } + + disable (); + cfcr = inb (port, com_cfcr); + + outb(port, com_cfcr, CFCR_DLAB); + outb(port, com_dlbl, x & 0xff); + outb(port, com_dlbh, x >> 8); + outb(port, com_cfcr, cfcr); + port->baudrate = rate; + enable (); + } + + return 0; +} + +static int +dos_setstopbits (scb, num) + serial_t scb; + int num; +{ + struct dos_ttystate *port = &ports[scb->fd]; + unsigned char cfcr; + + disable (); + cfcr = inb (port, com_cfcr); + + switch (num) + { + case SERIAL_1_STOPBITS: + outb (port, com_cfcr, cfcr & ~CFCR_STOPB); + break; + case SERIAL_1_AND_A_HALF_STOPBITS: + case SERIAL_2_STOPBITS: + outb (port, com_cfcr, cfcr | CFCR_STOPB); + break; + default: + enable (); + return 1; + } + enable (); + + return 0; +} + +static int +dos_write (scb, str, len) + serial_t scb; + const char *str; + int len; +{ + volatile struct dos_ttystate *port = &ports[scb->fd]; + int fifosize = port->fifo ? 16 : 1; + long then; + int cnt; + + while (len > 0) + { + /* send the data, fifosize bytes at a time */ + cnt = fifosize > len ? len : fifosize; + port->txbusy = 1; + outportsb (port->base + com_data, str, cnt); + str += cnt; + len -= cnt; +#ifdef DOS_STATS + cnts[CNT_TX] += cnt; +#endif + /* wait for transmission to complete (max 1 sec) */ + then = rawclock() + RAWHZ; + while (port->txbusy) + { + if ((rawclock () - then) >= 0) + { + errno = EIO; + return SERIAL_ERROR; + } + } + } + return 0; +} + + +static int +dos_sendbreak (scb) + serial_t scb; +{ + volatile struct dos_ttystate *port = &ports[scb->fd]; + unsigned char cfcr; + long then; + + cfcr = inb(port, com_cfcr); + outb(port, com_cfcr, cfcr | CFCR_SBREAK); + + /* 0.25 sec delay */ + then = rawclock () + RAWHZ / 4; + while ((rawclock () - then) < 0) + continue; + + outb(port, com_cfcr, cfcr); + return 0; +} + + +static struct serial_ops dos_ops = +{ + "hardwire", + 0, + dos_open, + dos_close, + dos_readchar, + dos_write, + dos_noop, /* flush output */ + dos_flush_input, + dos_sendbreak, + dos_raw, + dos_get_tty_state, + dos_set_tty_state, + dos_print_tty_state, + dos_noflush_set_tty_state, + dos_setbaudrate, + dos_setstopbits, +}; + + +static void +dos_info (arg, from_tty) + char *arg; + int from_tty; +{ + struct dos_ttystate *port; + int i; + + for (port = ports; port < &ports[4]; port++) + { + if (port->baudrate == 0) + continue; + printf_filtered ("Port:\tCOM%d (%sactive)\n", port - ports + 1, + port->intrupt ? "" : "not "); + printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq); + printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no"); + printf_filtered ("Speed:\t%d baud\n", port->baudrate); + printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n", + port->ferr, port->perr, port->oflo); + } + +#ifdef DOS_STATS + printf_filtered ("\nTotal interrupts: %d\n", intrcnt); + for (i = 0; i < NCNT; i++) + if (cnts[i]) + printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]); +#endif +} + + +void +_initialize_ser_dos () +{ + struct cmd_list_element *c; + + serial_add_interface (&dos_ops); + + /* Save original interrupt mask register. */ + icu_oldmask = inportb (ICU_MASK); + + /* Mark fixed motherboard irqs as inuse. */ + intrupts[0].inuse = /* timer tick */ + intrupts[1].inuse = /* keyboard */ + intrupts[2].inuse = 1; /* slave icu */ + + add_show_from_set ( + add_set_cmd ("com1base", class_obscure, var_zinteger, + (char *) &ports[0].base, + "Set COM1 base i/o port address.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com1irq", class_obscure, var_zinteger, + (char *) &ports[0].irq, + "Set COM1 interrupt request.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com2base", class_obscure, var_zinteger, + (char *) &ports[1].base, + "Set COM2 base i/o port address.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com2irq", class_obscure, var_zinteger, + (char *) &ports[1].irq, + "Set COM2 interrupt request.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com3base", class_obscure, var_zinteger, + (char *) &ports[2].base, + "Set COM3 base i/o port address.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com3irq", class_obscure, var_zinteger, + (char *) &ports[2].irq, + "Set COM3 interrupt request.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com4base", class_obscure, var_zinteger, + (char *) &ports[3].base, + "Set COM4 base i/o port address.", + &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("com4irq", class_obscure, var_zinteger, + (char *) &ports[3].irq, + "Set COM4 interrupt request.", + &setlist), + &showlist); + + add_info ("serial", dos_info, + "Print DOS serial port status."); +} diff --git a/contrib/gdb/gdb/ser-mac.c b/contrib/gdb/gdb/ser-mac.c new file mode 100644 index 000000000000..e27a9dd06ce0 --- /dev/null +++ b/contrib/gdb/gdb/ser-mac.c @@ -0,0 +1,361 @@ +/* Remote serial interface for local (hardwired) serial ports for Macintosh. + Copyright 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by Stan Shebs. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "serial.h" + +#include +#include +/* This is the regular Mac Serial.h, but copied to a different name + so as not to get confused with the GDB serial.h above. */ +#include "MacSerial.h" + +/* This is unused for now. We just return a placeholder. */ + +struct mac_ttystate + { + int bogus; + }; + +static int mac_open PARAMS ((serial_t scb, const char *name)); +static void mac_raw PARAMS ((serial_t scb)); +static int mac_readchar PARAMS ((serial_t scb, int timeout)); +static int mac_setbaudrate PARAMS ((serial_t scb, int rate)); +static int mac_write PARAMS ((serial_t scb, const char *str, int len)); +static void mac_close PARAMS ((serial_t scb)); +static serial_ttystate mac_get_tty_state PARAMS ((serial_t scb)); +static int mac_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); +static char *aptr PARAMS ((short p)); + +short input_refnum; +short output_refnum; + +char *mac_input_buffer; +char *mac_output_buffer; + +static int +mac_open (scb, name) + serial_t scb; + const char *name; +{ + OSErr err; + + /* Alloc buffer space first - that way any allocation failures are + intercepted before the serial driver gets involved. */ + if (mac_input_buffer == NULL) + mac_input_buffer = (char *) xmalloc (4096); + /* Match on a name and open a port. */ + if (strcmp (name, "modem") == 0) + { + err = OpenDriver ("\p.AIn", &input_refnum); + if (err != 0) + { + return (-1); + } + err = OpenDriver ("\p.AOut", &output_refnum); + if (err != 0) + { + CloseDriver (input_refnum); + return (-1); + } + } + else if (strcmp (name, "printer") == 0) + { + err = OpenDriver ("\p.BIn", &input_refnum); + if (err != 0) + { + return (-1); + } + err = OpenDriver ("\p.BOut", &output_refnum); + if (err != 0) + { + CloseDriver (input_refnum); + return (-1); + } + /* fake */ + scb->fd = 1; + return 0; + } + else + { + error ("You must specify a valid serial port name; your choices are `modem' or `printer'."); + errno = ENOENT; + return (-1); + } + /* We got something open. */ + if (1 /* using custom buffer */) + SerSetBuf (input_refnum, mac_input_buffer, 4096); + /* Set to a GDB-preferred state. */ + SerReset (input_refnum, stop10|noParity|data8|baud9600); + SerReset (output_refnum, stop10|noParity|data8|baud9600); + { + CntrlParam cb; + struct SerShk *handshake; + + cb.ioCRefNum = output_refnum; + cb.csCode = 14; + handshake = (struct SerShk *) &cb.csParam[0]; + handshake->fXOn = 0; + handshake->fCTS = 0; + handshake->xOn = 0; + handshake->xOff = 0; + handshake->errs = 0; + handshake->evts = 0; + handshake->fInX = 0; + handshake->fDTR = 0; + err = PBControl ((ParmBlkPtr) &cb, 0); + if (err < 0) + return (-1); + } + /* fake */ + scb->fd = 1; + return 0; +} + +static int +mac_noop (scb) + serial_t scb; +{ + return 0; +} + +static void +mac_raw (scb) + serial_t scb; +{ + /* Always effectively in raw mode. */ +} + +/* 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 + dead, or -3 for any other error (see errno in that case). */ + +static int +mac_readchar (scb, timeout) + serial_t scb; + int timeout; +{ + int status, n; + /* time_t */ unsigned long start_time, now; + OSErr err; + CntrlParam cb; + IOParam pb; + + if (scb->bufcnt-- > 0) + return *scb->bufp++; + + time (&start_time); + + while (1) + { + cb.ioCRefNum = input_refnum; + cb.csCode = 2; + err = PBStatus ((ParmBlkPtr) &cb, 0); + if (err < 0) + return SERIAL_ERROR; + n = *((long *) &cb.csParam[0]); + if (n > 0) + { + pb.ioRefNum = input_refnum; + pb.ioBuffer = (Ptr) (scb->buf); + pb.ioReqCount = (n > 64 ? 64 : n); + err = PBRead ((ParmBlkPtr) &pb, 0); + if (err < 0) + return SERIAL_ERROR; + scb->bufcnt = pb.ioReqCount; + scb->bufcnt--; + scb->bufp = scb->buf; + return *scb->bufp++; + } + else if (timeout == 0) + return SERIAL_TIMEOUT; + else if (timeout == -1) + ; + else + { + time (&now); + if (now > start_time + timeout) + return SERIAL_TIMEOUT; + } + PROGRESS (1); + } +} + +/* mac_{get set}_tty_state() are both dummys to fill out the function + vector. Someday, they may do something real... */ + +static serial_ttystate +mac_get_tty_state (scb) + serial_t scb; +{ + struct mac_ttystate *state; + + state = (struct mac_ttystate *) xmalloc (sizeof *state); + + return (serial_ttystate) state; +} + +static int +mac_set_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + return 0; +} + +static int +mac_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + return 0; +} + +static void +mac_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + /* Nothing to print. */ + return; +} + +/* If there is a tricky formula to relate real baud rates + to what the serial driver wants, we should use it. Until + we get one, this table will have to do. */ + +static struct { + int real_rate; + int bits; +} mac_baud_rate_table[] = { + { 57600, baud57600 }, + { 38400, 1 }, + { 19200, baud19200 }, + { 9600, baud9600 }, + { 7200, baud7200 }, + { 4800, baud4800 }, + { 3600, baud3600 }, + { 2400, baud2400 }, + { 1800, baud1800 }, + { 1200, baud1200 }, + { 600, baud600 }, + { 300, baud300 }, + { 0, 0 } +}; + +static int +mac_set_baud_rate (scb, rate) + serial_t scb; + int rate; +{ + int i, bits; + + for (i = 0; mac_baud_rate_table[i].real_rate != 0; ++i) + { + if (mac_baud_rate_table[i].real_rate == rate) + { + bits = mac_baud_rate_table[i].bits; + break; + } + } + SerReset (input_refnum, stop10|noParity|data8|bits); + SerReset (output_refnum, stop10|noParity|data8|bits); +} + +static int +mac_set_stop_bits (scb, num) + serial_t scb; + int num; +{ + return 0; +} + +int first_mac_write = 0; + +static int +mac_write (scb, str, len) + serial_t scb; + const char *str; + int len; +{ + OSErr err; + IOParam pb; + + if (first_mac_write++ < 4) + { + sleep (1); + } + pb.ioRefNum = output_refnum; + pb.ioBuffer = (Ptr) str; + pb.ioReqCount = len; + err = PBWrite ((ParmBlkPtr) &pb, 0); + if (err < 0) + { + return 1; + } + return 0; +} + +static void +mac_close (serial_t scb) +{ + if (input_refnum) + { + if (1 /* custom buffer */) + SerSetBuf (input_refnum, mac_input_buffer, 0); + CloseDriver (input_refnum); + input_refnum = 0; + } + if (output_refnum) + { + if (0 /* custom buffer */) + SetSetBuf (input_refnum, mac_output_buffer, 0); + CloseDriver (output_refnum); + output_refnum = 0; + } +} + +static struct serial_ops mac_ops = +{ + "hardwire", + 0, + mac_open, + mac_close, + mac_readchar, + mac_write, + mac_noop, /* flush output */ + mac_noop, /* flush input */ + mac_noop, /* send break -- currently only for nindy */ + mac_raw, + mac_get_tty_state, + mac_set_tty_state, + mac_print_tty_state, + mac_noflush_set_tty_state, + mac_set_baud_rate, + mac_set_stop_bits, +}; + +void +_initialize_ser_mac () +{ + serial_add_interface (&mac_ops); +} diff --git a/contrib/gdb/gdb/ser-tcp.c b/contrib/gdb/gdb/ser-tcp.c new file mode 100644 index 000000000000..388293fa33eb --- /dev/null +++ b/contrib/gdb/gdb/ser-tcp.c @@ -0,0 +1,343 @@ +/* Serial interface for raw TCP connections on Un*x like systems + Copyright 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "serial.h" +#include +#include +#include +#include +#include +#include +#include +#include "signals.h" +#include "gdb_string.h" + +struct tcp_ttystate +{ + int bogus; +}; + +static int tcp_open PARAMS ((serial_t scb, const char *name)); +static void tcp_raw PARAMS ((serial_t scb)); +static int wait_for PARAMS ((serial_t scb, int timeout)); +static int tcp_readchar PARAMS ((serial_t scb, int timeout)); +static int tcp_setbaudrate PARAMS ((serial_t scb, int rate)); +static int tcp_setstopbits PARAMS ((serial_t scb, int num)); +static int tcp_write PARAMS ((serial_t scb, const char *str, int len)); +/* FIXME: static void tcp_restore PARAMS ((serial_t scb)); */ +static void tcp_close PARAMS ((serial_t scb)); +static serial_ttystate tcp_get_tty_state PARAMS ((serial_t scb)); +static int tcp_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); + +/* Open up a raw tcp socket */ + +static int +tcp_open(scb, name) + serial_t scb; + const char *name; +{ + char *port_str; + int port; + struct hostent *hostent; + struct sockaddr_in sockaddr; + int tmp; + char hostname[100]; + struct protoent *protoent; + int i; + + port_str = strchr (name, ':'); + + if (!port_str) + error ("tcp_open: No colon in host name!"); /* Shouldn't ever happen */ + + tmp = min (port_str - name, (int) sizeof hostname - 1); + strncpy (hostname, name, tmp); /* Don't want colon */ + hostname[tmp] = '\000'; /* Tie off host name */ + port = atoi (port_str + 1); + + hostent = gethostbyname (hostname); + + if (!hostent) + { + fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname); + errno = ENOENT; + return -1; + } + + for (i = 1; i <= 15; i++) + { + scb->fd = socket (PF_INET, SOCK_STREAM, 0); + if (scb->fd < 0) + return -1; + + /* Allow rapid reuse of this port. */ + tmp = 1; + setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp)); + + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons(port); + memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, + sizeof (struct in_addr)); + + if (!connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) + break; + + close (scb->fd); + scb->fd = -1; + +/* We retry for ECONNREFUSED because that is often a temporary condition, which + happens when the server is being restarted. */ + + if (errno != ECONNREFUSED) + return -1; + + sleep (1); + } + + protoent = getprotobyname ("tcp"); + if (!protoent) + return -1; + + tmp = 1; + if (setsockopt (scb->fd, protoent->p_proto, TCP_NODELAY, + (char *)&tmp, sizeof(tmp))) + return -1; + + signal(SIGPIPE, SIG_IGN); /* If we don't do this, then GDB simply exits + when the remote side dies. */ + + return 0; +} + +static serial_ttystate +tcp_get_tty_state(scb) + serial_t scb; +{ + struct tcp_ttystate *state; + + state = (struct tcp_ttystate *)xmalloc(sizeof *state); + + return (serial_ttystate)state; +} + +static int +tcp_set_tty_state(scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct tcp_ttystate *state; + + state = (struct tcp_ttystate *)ttystate; + + return 0; +} + +static int +tcp_return_0 (scb) + serial_t scb; +{ + return 0; +} + +static void +tcp_raw(scb) + serial_t scb; +{ + return; /* Always in raw mode */ +} + +/* Wait for input on scb, with timeout seconds. Returns 0 on success, + otherwise SERIAL_TIMEOUT or SERIAL_ERROR. + + For termio{s}, we actually just setup VTIME if necessary, and let the + timeout occur in the read() in tcp_read(). + */ + +static int +wait_for(scb, timeout) + serial_t scb; + int timeout; +{ + int numfds; + struct timeval tv; + fd_set readfds, exceptfds; + + FD_ZERO (&readfds); + FD_ZERO (&exceptfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_SET(scb->fd, &readfds); + FD_SET(scb->fd, &exceptfds); + + while (1) + { + if (timeout >= 0) + numfds = select(scb->fd+1, &readfds, 0, &exceptfds, &tv); + else + numfds = select(scb->fd+1, &readfds, 0, &exceptfds, 0); + + if (numfds <= 0) + if (numfds == 0) + return SERIAL_TIMEOUT; + else if (errno == EINTR) + continue; + else + return SERIAL_ERROR; /* Got an error from select or poll */ + + return 0; + } +} + +/* 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 + dead, or -3 for any other error (see errno in that case). */ + +static int +tcp_readchar(scb, timeout) + serial_t scb; + int timeout; +{ + int status; + + if (scb->bufcnt-- > 0) + return *scb->bufp++; + + status = wait_for(scb, timeout); + + if (status < 0) + return status; + + while (1) + { + scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ); + if (scb->bufcnt != -1 || errno != EINTR) + break; + } + + if (scb->bufcnt <= 0) + if (scb->bufcnt == 0) + return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to + distinguish between EOF & timeouts + someday] */ + else + return SERIAL_ERROR; /* Got an error from read */ + + scb->bufcnt--; + scb->bufp = scb->buf; + return *scb->bufp++; +} + +static int +tcp_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + return 0; +} + +static void +tcp_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + /* Nothing to print. */ + return; +} + +static int +tcp_setbaudrate(scb, rate) + serial_t scb; + int rate; +{ + return 0; /* Never fails! */ +} + +static int +tcp_setstopbits(scb, num) + serial_t scb; + int num; +{ + return 0; /* Never fails! */ +} + +static int +tcp_write(scb, str, len) + serial_t scb; + const char *str; + int len; +{ + int cc; + + while (len > 0) + { + cc = write(scb->fd, str, len); + + if (cc < 0) + return 1; + len -= cc; + str += cc; + } + return 0; +} + +static void +tcp_close(scb) + serial_t scb; +{ + if (scb->fd < 0) + return; + + close(scb->fd); + scb->fd = -1; +} + +static struct serial_ops tcp_ops = +{ + "tcp", + 0, + tcp_open, + tcp_close, + tcp_readchar, + tcp_write, + tcp_return_0, /* flush output */ + tcp_return_0, /* flush input */ + tcp_return_0, /* send break */ + tcp_raw, + tcp_get_tty_state, + tcp_set_tty_state, + tcp_print_tty_state, + tcp_noflush_set_tty_state, + tcp_setbaudrate, + tcp_setstopbits, +}; + +void +_initialize_ser_tcp () +{ + serial_add_interface (&tcp_ops); +} diff --git a/contrib/gdb/gdb/ser-unix.c b/contrib/gdb/gdb/ser-unix.c new file mode 100644 index 000000000000..a4a00e5d559e --- /dev/null +++ b/contrib/gdb/gdb/ser-unix.c @@ -0,0 +1,730 @@ +/* Serial interface for local (hardwired) serial ports on Un*x like systems + Copyright 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "serial.h" +#include +#include +#include "terminal.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_TERMIOS + +struct hardwire_ttystate +{ + struct termios termios; +}; +#endif /* termios */ + +#ifdef HAVE_TERMIO + +/* It is believed that all systems which have added job control to SVR3 + (e.g. sco) have also added termios. Even if not, trying to figure out + all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty + bewildering. So we don't attempt it. */ + +struct hardwire_ttystate +{ + struct termio termio; +}; +#endif /* termio */ + +#ifdef HAVE_SGTTY +/* Needed for the code which uses select(). We would include + too if it existed on all systems. */ +#include + +struct hardwire_ttystate +{ + struct sgttyb sgttyb; + struct tchars tc; + struct ltchars ltc; + /* Line discipline flags. */ + int lmode; +}; +#endif /* sgtty */ + +static int hardwire_open PARAMS ((serial_t scb, const char *name)); +static void hardwire_raw PARAMS ((serial_t scb)); +static int wait_for PARAMS ((serial_t scb, int timeout)); +static int hardwire_readchar PARAMS ((serial_t scb, int timeout)); +static int rate_to_code PARAMS ((int rate)); +static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate)); +static int hardwire_write PARAMS ((serial_t scb, const char *str, int len)); +/* FIXME: static void hardwire_restore PARAMS ((serial_t scb)); */ +static void hardwire_close PARAMS ((serial_t scb)); +static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); +static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); +static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb)); +static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); + +/* Open up a real live device for serial I/O */ + +static int +hardwire_open(scb, name) + serial_t scb; + const char *name; +{ + scb->fd = open (name, O_RDWR); + if (scb->fd < 0) + return -1; + + return 0; +} + +static int +get_tty_state(scb, state) + serial_t scb; + struct hardwire_ttystate *state; +{ +#ifdef HAVE_TERMIOS + extern int errno; + + if (tcgetattr(scb->fd, &state->termios) < 0) + return -1; + + return 0; +#endif + +#ifdef HAVE_TERMIO + if (ioctl (scb->fd, TCGETA, &state->termio) < 0) + return -1; + return 0; +#endif + +#ifdef HAVE_SGTTY + if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0) + return -1; + if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0) + return -1; + if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0) + return -1; + if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0) + return -1; + + return 0; +#endif +} + +static int +set_tty_state(scb, state) + serial_t scb; + struct hardwire_ttystate *state; +{ +#ifdef HAVE_TERMIOS + if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0) + return -1; + + return 0; +#endif + +#ifdef HAVE_TERMIO + if (ioctl (scb->fd, TCSETA, &state->termio) < 0) + return -1; + return 0; +#endif + +#ifdef HAVE_SGTTY + if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0) + return -1; + if (ioctl (scb->fd, TIOCSETC, &state->tc) < 0) + return -1; + if (ioctl (scb->fd, TIOCSLTC, &state->ltc) < 0) + return -1; + if (ioctl (scb->fd, TIOCLSET, &state->lmode) < 0) + return -1; + + return 0; +#endif +} + +static serial_ttystate +hardwire_get_tty_state(scb) + serial_t scb; +{ + struct hardwire_ttystate *state; + + state = (struct hardwire_ttystate *)xmalloc(sizeof *state); + + if (get_tty_state(scb, state)) + return NULL; + + return (serial_ttystate)state; +} + +static int +hardwire_set_tty_state(scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct hardwire_ttystate *state; + + state = (struct hardwire_ttystate *)ttystate; + + return set_tty_state(scb, state); +} + +static int +hardwire_noflush_set_tty_state (scb, new_ttystate, old_ttystate) + serial_t scb; + serial_ttystate new_ttystate; + serial_ttystate old_ttystate; +{ + struct hardwire_ttystate new_state; +#ifdef HAVE_SGTTY + struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate; +#endif + + new_state = *(struct hardwire_ttystate *)new_ttystate; + + /* Don't change in or out of raw mode; we don't want to flush input. + termio and termios have no such restriction; for them flushing input + is separate from setting the attributes. */ + +#ifdef HAVE_SGTTY + if (state->sgttyb.sg_flags & RAW) + new_state.sgttyb.sg_flags |= RAW; + else + new_state.sgttyb.sg_flags &= ~RAW; + + /* I'm not sure whether this is necessary; the manpage just mentions + RAW not CBREAK. */ + if (state->sgttyb.sg_flags & CBREAK) + new_state.sgttyb.sg_flags |= CBREAK; + else + new_state.sgttyb.sg_flags &= ~CBREAK; +#endif + + return set_tty_state (scb, &new_state); +} + +static void +hardwire_print_tty_state (scb, ttystate) + serial_t scb; + serial_ttystate ttystate; +{ + struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; + int i; + +#ifdef HAVE_TERMIOS + printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", + state->termios.c_iflag, state->termios.c_oflag); + printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n", + state->termios.c_cflag, state->termios.c_lflag); +#if 0 + /* This not in POSIX, and is not really documented by those systems + which have it (at least not Sun). */ + printf_filtered ("c_line = 0x%x.\n", state->termios.c_line); +#endif + printf_filtered ("c_cc: "); + for (i = 0; i < NCCS; i += 1) + printf_filtered ("0x%x ", state->termios.c_cc[i]); + printf_filtered ("\n"); +#endif + +#ifdef HAVE_TERMIO + printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n", + state->termio.c_iflag, state->termio.c_oflag); + printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", + state->termio.c_cflag, state->termio.c_lflag, + state->termio.c_line); + printf_filtered ("c_cc: "); + for (i = 0; i < NCC; i += 1) + printf_filtered ("0x%x ", state->termio.c_cc[i]); + printf_filtered ("\n"); +#endif + +#ifdef HAVE_SGTTY + printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags); + + printf_filtered ("tchars: "); + for (i = 0; i < (int)sizeof (struct tchars); i++) + printf_filtered ("0x%x ", ((unsigned char *)&state->tc)[i]); + printf_filtered ("\n"); + + printf_filtered ("ltchars: "); + for (i = 0; i < (int)sizeof (struct ltchars); i++) + printf_filtered ("0x%x ", ((unsigned char *)&state->ltc)[i]); + printf_filtered ("\n"); + + printf_filtered ("lmode: 0x%x\n", state->lmode); +#endif +} + +static int +hardwire_flush_output (scb) + serial_t scb; +{ +#ifdef HAVE_TERMIOS + return tcflush (scb->fd, TCOFLUSH); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCFLSH, 1); +#endif + +#ifdef HAVE_SGTTY + /* This flushes both input and output, but we can't do better. */ + return ioctl (scb->fd, TIOCFLUSH, 0); +#endif +} + +static int +hardwire_flush_input (scb) + serial_t scb; +{ + scb->bufcnt = 0; + scb->bufp = scb->buf; + +#ifdef HAVE_TERMIOS + return tcflush (scb->fd, TCIFLUSH); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCFLSH, 0); +#endif + +#ifdef HAVE_SGTTY + /* This flushes both input and output, but we can't do better. */ + return ioctl (scb->fd, TIOCFLUSH, 0); +#endif +} + +static int +hardwire_send_break (scb) + serial_t scb; +{ +#ifdef HAVE_TERMIOS + return tcsendbreak (scb->fd, 0); +#endif + +#ifdef HAVE_TERMIO + return ioctl (scb->fd, TCSBRK, 0); +#endif + +#ifdef HAVE_SGTTY + { + int status; + struct timeval timeout; + + status = ioctl (scb->fd, TIOCSBRK, 0); + + /* Can't use usleep; it doesn't exist in BSD 4.2. */ + /* Note that if this select() is interrupted by a signal it will not wait + the full length of time. I think that is OK. */ + timeout.tv_sec = 0; + timeout.tv_usec = 250000; + select (0, 0, 0, 0, &timeout); + status = ioctl (scb->fd, TIOCCBRK, 0); + return status; + } +#endif +} + +static void +hardwire_raw(scb) + serial_t scb; +{ + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + +#ifdef HAVE_TERMIOS + state.termios.c_iflag = 0; + state.termios.c_oflag = 0; + state.termios.c_lflag = 0; + state.termios.c_cflag &= ~(CSIZE|PARENB); + state.termios.c_cflag |= CLOCAL | CS8; + state.termios.c_cc[VMIN] = 0; + state.termios.c_cc[VTIME] = 0; +#endif + +#ifdef HAVE_TERMIO + state.termio.c_iflag = 0; + state.termio.c_oflag = 0; + state.termio.c_lflag = 0; + state.termio.c_cflag &= ~(CSIZE|PARENB); + state.termio.c_cflag |= CLOCAL | CS8; + state.termio.c_cc[VMIN] = 0; + state.termio.c_cc[VTIME] = 0; +#endif + +#ifdef HAVE_SGTTY + state.sgttyb.sg_flags |= RAW | ANYP; + state.sgttyb.sg_flags &= ~(CBREAK | ECHO); +#endif + + scb->current_timeout = 0; + + if (set_tty_state (scb, &state)) + fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); +} + +/* Wait for input on scb, with timeout seconds. Returns 0 on success, + otherwise SERIAL_TIMEOUT or SERIAL_ERROR. + + For termio{s}, we actually just setup VTIME if necessary, and let the + timeout occur in the read() in hardwire_read(). + */ + +static int +wait_for(scb, timeout) + serial_t scb; + int timeout; +{ + scb->timeout_remaining = 0; + +#ifdef HAVE_SGTTY + { + struct timeval tv; + fd_set readfds; + + FD_ZERO (&readfds); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_SET(scb->fd, &readfds); + + while (1) + { + int numfds; + + if (timeout >= 0) + numfds = select(scb->fd+1, &readfds, 0, 0, &tv); + else + numfds = select(scb->fd+1, &readfds, 0, 0, 0); + + if (numfds <= 0) + if (numfds == 0) + return SERIAL_TIMEOUT; + else if (errno == EINTR) + continue; + else + return SERIAL_ERROR; /* Got an error from select or poll */ + + return 0; + } + } +#endif /* HAVE_SGTTY */ + +#if defined HAVE_TERMIO || defined HAVE_TERMIOS + if (timeout == scb->current_timeout) + return 0; + + scb->current_timeout = timeout; + + { + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); + +#ifdef HAVE_TERMIOS + if (timeout < 0) + { + /* No timeout. */ + state.termios.c_cc[VTIME] = 0; + state.termios.c_cc[VMIN] = 1; + } + else + { + state.termios.c_cc[VMIN] = 0; + state.termios.c_cc[VTIME] = timeout * 10; + if (state.termios.c_cc[VTIME] != timeout * 10) + { + + /* If c_cc is an 8-bit signed character, we can't go + bigger than this. If it is always unsigned, we could use + 25. */ + + scb->current_timeout = 12; + state.termios.c_cc[VTIME] = scb->current_timeout * 10; + scb->timeout_remaining = timeout - scb->current_timeout; + } + } +#endif + +#ifdef HAVE_TERMIO + if (timeout < 0) + { + /* No timeout. */ + state.termio.c_cc[VTIME] = 0; + state.termio.c_cc[VMIN] = 1; + } + else + { + state.termio.c_cc[VMIN] = 0; + state.termio.c_cc[VTIME] = timeout * 10; + if (state.termio.c_cc[VTIME] != timeout * 10) + { + /* If c_cc is an 8-bit signed character, we can't go + bigger than this. If it is always unsigned, we could use + 25. */ + + scb->current_timeout = 12; + state.termio.c_cc[VTIME] = scb->current_timeout * 10; + scb->timeout_remaining = timeout - scb->current_timeout; + } + } +#endif + + if (set_tty_state (scb, &state)) + fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); + + return 0; + } +#endif /* HAVE_TERMIO || HAVE_TERMIOS */ +} + +/* 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 SERIAL_TIMEOUT if timeout expired, EOF if line + dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */ + +static int +hardwire_readchar(scb, timeout) + serial_t scb; + int timeout; +{ + int status; + + if (scb->bufcnt-- > 0) + return *scb->bufp++; + + while (1) + { + status = wait_for (scb, timeout); + + if (status < 0) + return status; + + scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ); + + if (scb->bufcnt <= 0) + { + if (scb->bufcnt == 0) + { + /* Zero characters means timeout (it could also be EOF, but + we don't (yet at least) distinguish). */ + if (scb->timeout_remaining > 0) + { + timeout = scb->timeout_remaining; + continue; + } + else + return SERIAL_TIMEOUT; + } + else if (errno == EINTR) + continue; + else + return SERIAL_ERROR; /* Got an error from read */ + } + + scb->bufcnt--; + scb->bufp = scb->buf; + return *scb->bufp++; + } +} + +#ifndef B19200 +#define B19200 EXTA +#endif + +#ifndef B38400 +#define B38400 EXTB +#endif + +/* Translate baud rates from integers to damn B_codes. Unix should + have outgrown this crap years ago, but even POSIX wouldn't buck it. */ + +static struct +{ + int rate; + int code; +} +baudtab[] = +{ + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {-1, -1}, +}; + +static int +rate_to_code(rate) + int rate; +{ + int i; + + for (i = 0; baudtab[i].rate != -1; i++) + if (rate == baudtab[i].rate) + return baudtab[i].code; + + return -1; +} + +static int +hardwire_setbaudrate(scb, rate) + serial_t scb; + int rate; +{ + struct hardwire_ttystate state; + + if (get_tty_state(scb, &state)) + return -1; + +#ifdef HAVE_TERMIOS + cfsetospeed (&state.termios, rate_to_code (rate)); + cfsetispeed (&state.termios, rate_to_code (rate)); +#endif + +#ifdef HAVE_TERMIO +#ifndef CIBAUD +#define CIBAUD CBAUD +#endif + + state.termio.c_cflag &= ~(CBAUD | CIBAUD); + state.termio.c_cflag |= rate_to_code (rate); +#endif + +#ifdef HAVE_SGTTY + state.sgttyb.sg_ispeed = rate_to_code (rate); + state.sgttyb.sg_ospeed = rate_to_code (rate); +#endif + + return set_tty_state (scb, &state); +} + +static int +hardwire_setstopbits(scb, num) + serial_t scb; + int num; +{ + struct hardwire_ttystate state; + int newbit; + + if (get_tty_state(scb, &state)) + return -1; + + switch (num) + { + case SERIAL_1_STOPBITS: + newbit = 0; + break; + case SERIAL_1_AND_A_HALF_STOPBITS: + case SERIAL_2_STOPBITS: + newbit = 1; + break; + default: + return 1; + } + +#ifdef HAVE_TERMIOS + if (!newbit) + state.termios.c_cflag &= ~CSTOPB; + else + state.termios.c_cflag |= CSTOPB; /* two bits */ +#endif + +#ifdef HAVE_TERMIO + if (!newbit) + state.termio.c_cflag &= ~CSTOPB; + else + state.termio.c_cflag |= CSTOPB; /* two bits */ +#endif + +#ifdef HAVE_SGTTY + return 0; /* sgtty doesn't support this */ +#endif + + return set_tty_state (scb, &state); +} + +static int +hardwire_write(scb, str, len) + serial_t scb; + const char *str; + int len; +{ + int cc; + + while (len > 0) + { + cc = write(scb->fd, str, len); + + if (cc < 0) + return 1; + len -= cc; + str += cc; + } + return 0; +} + +static void +hardwire_close(scb) + serial_t scb; +{ + if (scb->fd < 0) + return; + + close(scb->fd); + scb->fd = -1; +} + +static struct serial_ops hardwire_ops = +{ + "hardwire", + 0, + hardwire_open, + hardwire_close, + hardwire_readchar, + hardwire_write, + hardwire_flush_output, + hardwire_flush_input, + hardwire_send_break, + hardwire_raw, + hardwire_get_tty_state, + hardwire_set_tty_state, + hardwire_print_tty_state, + hardwire_noflush_set_tty_state, + hardwire_setbaudrate, + hardwire_setstopbits, +}; + +void +_initialize_ser_hardwire () +{ + serial_add_interface (&hardwire_ops); +} diff --git a/contrib/gdb/gdb/serial.c b/contrib/gdb/gdb/serial.c new file mode 100644 index 000000000000..18c6cde86665 --- /dev/null +++ b/contrib/gdb/gdb/serial.c @@ -0,0 +1,484 @@ +/* Generic serial interface routines + Copyright 1992, 1993, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include "serial.h" +#include "gdb_string.h" +#include "gdbcmd.h" + +/* 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 serial_t last_serial_opened = NULL; + +/* Pointer to list of scb's. */ + +static serial_t scb_base; + +/* Non-NULL gives filename which contains a recording of the remote session, + suitable for playback by gdbserver. */ + +char *serial_logfile = NULL; +FILE *serial_logfp = NULL; + + +static int serial_reading = 0; +static int serial_writing = 0; + +void +serial_log_command (cmd) + const char *cmd; +{ + if (serial_reading || serial_writing) + { + fputc_unfiltered ('\n', serial_logfp); + serial_reading = 0; + serial_writing = 0; + } + fprintf_unfiltered (serial_logfp, "c %s\n", cmd); + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); +} + +static void +serial_logchar (ch) + int ch; +{ + switch (ch) + { + case '\\': fputs_unfiltered ("\\\\", serial_logfp); break; + case '\b': fputs_unfiltered ("\\b", serial_logfp); break; + case '\f': fputs_unfiltered ("\\f", serial_logfp); break; + case '\n': fputs_unfiltered ("\\n", serial_logfp); break; + case '\r': fputs_unfiltered ("\\r", serial_logfp); break; + case '\t': fputs_unfiltered ("\\t", serial_logfp); break; + case '\v': fputs_unfiltered ("\\v", serial_logfp); break; + default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break; + } +} + +int +serial_write (scb, str, len) + serial_t scb; + const char *str; + int len; +{ + int count; + + if (serial_logfp != NULL) + { + if (serial_reading) + { + fputc_unfiltered ('\n', serial_logfp); + serial_reading = 0; + } + if (!serial_writing) + { + serial_logchar ('w'); + serial_logchar (' '); + serial_writing = 1; + } + for (count = 0; count < len; count++) + { + serial_logchar (str[count]); + } + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); + } + return (scb -> ops -> write (scb, str, len)); +} + +int +serial_readchar (scb, timeout) + serial_t scb; + int timeout; +{ + int ch; + + ch = scb -> ops -> readchar (scb, timeout); + if (serial_logfp != NULL) + { + if (serial_writing) + { + fputc_unfiltered ('\n', serial_logfp); + serial_writing = 0; + } + if (!serial_reading) + { + serial_logchar ('r'); + serial_logchar (' '); + serial_reading = 1; + } + serial_logchar (ch); + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); + } + return (ch); +} + +static struct serial_ops * +serial_interface_lookup (name) + char *name; +{ + struct serial_ops *ops; + + for (ops = serial_ops_list; ops; ops = ops->next) + if (strcmp (name, ops->name) == 0) + return ops; + + return NULL; +} + +void +serial_add_interface(optable) + struct serial_ops *optable; +{ + optable->next = serial_ops_list; + serial_ops_list = optable; +} + +/* Open up a device or a network socket, depending upon the syntax of NAME. */ + +serial_t +serial_open (name) + const char *name; +{ + serial_t scb; + struct serial_ops *ops; + + 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 (strchr (name, ':')) + ops = serial_interface_lookup ("tcp"); + else if (strncmp (name, "lpt", 3) == 0) + ops = serial_interface_lookup ("parallel"); + else + ops = serial_interface_lookup ("hardwire"); + + if (!ops) + return NULL; + + scb = (serial_t)xmalloc (sizeof (struct _serial_t)); + + scb->ops = ops; + + scb->bufcnt = 0; + scb->bufp = scb->buf; + + if (scb->ops->open(scb, name)) + { + free (scb); + return NULL; + } + + scb->name = strsave (name); + scb->next = scb_base; + scb->refcnt = 1; + scb_base = scb; + + last_serial_opened = scb; + + if (serial_logfile != NULL) + { + serial_logfp = fopen (serial_logfile, "w"); + if (serial_logfp == NULL) + { + perror_with_name (serial_logfile); + } + } + + return scb; +} + +serial_t +serial_fdopen (fd) + const int fd; +{ + serial_t scb; + struct serial_ops *ops; + + for (scb = scb_base; scb; scb = scb->next) + if (scb->fd == fd) + { + scb->refcnt++; + return scb; + } + + ops = serial_interface_lookup ("hardwire"); + + if (!ops) + return NULL; + + scb = (serial_t)xmalloc (sizeof (struct _serial_t)); + + scb->ops = ops; + + scb->bufcnt = 0; + scb->bufp = scb->buf; + + scb->fd = fd; + + scb->name = NULL; + scb->next = scb_base; + scb->refcnt = 1; + scb_base = scb; + + last_serial_opened = scb; + + return scb; +} + +void +serial_close(scb, really_close) + serial_t scb; + int really_close; +{ + serial_t tmp_scb; + + last_serial_opened = NULL; + + if (serial_logfp) + { + if (serial_reading || serial_writing) + { + fputc_unfiltered ('\n', serial_logfp); + serial_reading = 0; + serial_writing = 0; + } + fclose (serial_logfp); + 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; + + if (really_close) + scb->ops->close (scb); + + if (scb->name) + free (scb->name); + + if (scb_base == scb) + scb_base = scb_base->next; + else + for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next) + { + if (tmp_scb->next != scb) + continue; + + tmp_scb->next = tmp_scb->next->next; + break; + } + + free(scb); +} + +#if 0 +/* +The connect command is #if 0 because I hadn't thought of an elegant +way to wait for I/O on two serial_t'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 serial_t tty_desc; /* Controlling terminal */ + +static void +cleanup_tty(ttystate) + serial_ttystate ttystate; +{ + printf_unfiltered ("\r\n[Exiting connect mode]\r\n"); + SERIAL_SET_TTY_STATE (tty_desc, ttystate); + free (ttystate); + SERIAL_CLOSE (tty_desc); +} + +static void +connect_command (args, fromtty) + char *args; + int fromtty; +{ + int c; + char cur_esc = 0; + serial_ttystate ttystate; + serial_t 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 */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +serial_printf (serial_t desc, const char *format, ...) +#else +serial_printf (va_alist) + va_dcl +#endif +{ + va_list args; + char *buf; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + serial_t desc; + char *format; + + va_start (args); + desc = va_arg (args, serial_t); + format = va_arg (args, char *); +#endif + + vasprintf (&buf, format, args); + SERIAL_WRITE (desc, buf, strlen (buf)); + + free (buf); + va_end (args); +} + +void +_initialize_serial () +{ +#if 0 + add_com ("connect", class_obscure, connect_command, + "Connect the terminal directly up to the command monitor.\n\ +Use ~. or ~^D to break out."); +#endif /* 0 */ + + add_show_from_set (add_set_cmd ("remotelogfile", no_class, + var_filename, (char *)&serial_logfile, + "Set filename for remote session recording.\n\ +This file is used to record the remote session for future playback\n\ +by gdbserver.", &setlist), + &showlist); + +} diff --git a/contrib/gdb/gdb/serial.h b/contrib/gdb/gdb/serial.h new file mode 100644 index 000000000000..8abcb3d077b3 --- /dev/null +++ b/contrib/gdb/gdb/serial.h @@ -0,0 +1,182 @@ +/* Remote serial support interface definitions for GDB, the GNU Debugger. + Copyright 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SERIAL_H +#define SERIAL_H + +/* Terminal state pointer. This is specific to each type of interface. */ + +typedef PTR serial_ttystate; + +struct _serial_t +{ + int fd; /* File descriptor */ + struct serial_ops *ops; /* Function vector */ + serial_ttystate ttystate; /* Not used (yet) */ + int bufcnt; /* Amount of data in receive buffer */ + unsigned char *bufp; /* Current byte */ + unsigned char buf[BUFSIZ]; /* Da buffer itself */ + int current_timeout; /* (termio{s} only), last value of VTIME */ + /* ser-unix.c termio{,s} only, we still need to wait for this many more + seconds. */ + int timeout_remaining; + char *name; /* The name of the device or host */ + struct _serial_t *next; /* Pointer to the next serial_t */ + int refcnt; /* Number of pointers to this block */ +}; + +typedef struct _serial_t *serial_t; + +struct serial_ops { + char *name; + struct serial_ops *next; + int (*open) PARAMS ((serial_t, const char *name)); + void (*close) PARAMS ((serial_t)); + int (*readchar) PARAMS ((serial_t, int timeout)); + int (*write) PARAMS ((serial_t, const char *str, int len)); + int (*flush_output) PARAMS ((serial_t)); + int (*flush_input) PARAMS ((serial_t)); + int (*send_break) PARAMS ((serial_t)); + void (*go_raw) PARAMS ((serial_t)); + serial_ttystate (*get_tty_state) PARAMS ((serial_t)); + int (*set_tty_state) PARAMS ((serial_t, serial_ttystate)); + void (*print_tty_state) PARAMS ((serial_t, serial_ttystate)); + int (*noflush_set_tty_state) + PARAMS ((serial_t, serial_ttystate, serial_ttystate)); + int (*setbaudrate) PARAMS ((serial_t, int rate)); + int (*setstopbits) PARAMS ((serial_t, int num)); +}; + +/* Add a new serial interface to the interface list */ + +void serial_add_interface PARAMS ((struct serial_ops *optable)); + +serial_t serial_open PARAMS ((const char *name)); + +serial_t serial_fdopen PARAMS ((const int fd)); + +/* For most routines, if a failure is indicated, then errno should be + examined. */ + +/* Try to open NAME. Returns a new serial_t on success, NULL on failure. + */ + +#define SERIAL_OPEN(NAME) serial_open(NAME) + +/* Open a new serial stream using a file handle. */ + +#define SERIAL_FDOPEN(FD) serial_fdopen(FD) + +/* Flush pending output. Might also flush input (if this system can't flush + only output). */ + +#define SERIAL_FLUSH_OUTPUT(SERIAL_T) \ + ((SERIAL_T)->ops->flush_output((SERIAL_T))) + +/* Flush pending input. Might also flush output (if this system can't flush + only input). */ + +#define SERIAL_FLUSH_INPUT(SERIAL_T)\ + ((*(SERIAL_T)->ops->flush_input) ((SERIAL_T))) + +/* Send a break between 0.25 and 0.5 seconds long. */ + +#define SERIAL_SEND_BREAK(SERIAL_T) \ + ((*(SERIAL_T)->ops->send_break) (SERIAL_T)) + +/* Turn the port into raw mode. */ + +#define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T)) + +/* Return a pointer to a newly malloc'd ttystate containing the state + of the tty. */ +#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T)) + +/* Set the state of the tty to TTYSTATE. The change is immediate. + When changing to or from raw mode, input might be discarded. + Returns 0 for success, negative value for error (in which case errno + contains the error). */ +#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE)) + +/* printf_filtered a user-comprehensible description of ttystate. */ +#define SERIAL_PRINT_TTY_STATE(SERIAL_T, TTYSTATE) \ + ((*((SERIAL_T)->ops->print_tty_state)) ((SERIAL_T), (TTYSTATE))) + +/* Set the tty state to NEW_TTYSTATE, where OLD_TTYSTATE is the + current state (generally obtained from a recent call to + SERIAL_GET_TTY_STATE), but be careful not to discard any input. + This means that we never switch in or out of raw mode, even + if NEW_TTYSTATE specifies a switch. */ +#define SERIAL_NOFLUSH_SET_TTY_STATE(SERIAL_T, NEW_TTYSTATE, OLD_TTYSTATE) \ + ((*((SERIAL_T)->ops->noflush_set_tty_state)) \ + ((SERIAL_T), (NEW_TTYSTATE), (OLD_TTYSTATE))) + +/* Read one char from the serial device with TIMEOUT seconds to wait + or -1 to wait forever. Use timeout of 0 to effect a poll. Returns + char if ok, else one of the following codes. Note that all error + codes are guaranteed to be < 0. */ + +#define SERIAL_ERROR -1 /* General error, see errno for details */ +#define SERIAL_TIMEOUT -2 +#define SERIAL_EOF -3 + +extern int serial_readchar PARAMS ((serial_t scb, int timeout)); + +#define SERIAL_READCHAR(SERIAL_T, TIMEOUT) serial_readchar (SERIAL_T, TIMEOUT) + +/* Set the baudrate to the decimal value supplied. Returns 0 for success, + -1 for failure. */ + +#define SERIAL_SETBAUDRATE(SERIAL_T, RATE) ((SERIAL_T)->ops->setbaudrate((SERIAL_T), RATE)) + +/* Set the number of stop bits to the value specified. Returns 0 for success, + -1 for failure. */ + +#define SERIAL_1_STOPBITS 1 +#define SERIAL_1_AND_A_HALF_STOPBITS 2 /* 1.5 bits, snicker... */ +#define SERIAL_2_STOPBITS 3 + +#define SERIAL_SETSTOPBITS(SERIAL_T, NUM) ((SERIAL_T)->ops->setstopbits((SERIAL_T), NUM)) + +/* Write LEN chars from STRING to the port SERIAL_T. Returns 0 for + success, non-zero for failure. */ + +extern int serial_write PARAMS ((serial_t scb, const char *str, int len)); + +#define SERIAL_WRITE(SERIAL_T, STRING,LEN) serial_write (SERIAL_T, STRING, LEN) + +/* Push out all buffers, close the device and destroy SERIAL_T. */ + +extern void serial_close PARAMS ((serial_t, int)); + +#define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T, 1) + +/* Push out all buffers and destroy SERIAL_T without closing the device. */ + +#define SERIAL_UN_FDOPEN(SERIAL_T) serial_close(SERIAL_T, 0) + +extern void serial_printf PARAMS ((serial_t desc, const char *, ...)) + ATTR_FORMAT(printf, 2, 3); + +/* File in which to record the remote debugging session */ + +extern char *serial_logfile; +extern FILE *serial_logfp; + +#endif /* SERIAL_H */ diff --git a/contrib/gdb/gdb/signals.h b/contrib/gdb/gdb/signals.h new file mode 100644 index 000000000000..a1348b637330 --- /dev/null +++ b/contrib/gdb/gdb/signals.h @@ -0,0 +1,27 @@ +/* Signal handler definitions for GDB, the GNU Debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is almost the same as including except that it + eliminates certain signal names when job control is not supported, + (or, on some systems, when job control is there but doesn't work + the way GDB expects it to work). */ +/* This has been superceded by the job_control variable in serial.h. */ + +#include diff --git a/contrib/gdb/gdb/solib.c b/contrib/gdb/gdb/solib.c new file mode 100644 index 000000000000..3a20b55e84ad --- /dev/null +++ b/contrib/gdb/gdb/solib.c @@ -0,0 +1,1714 @@ +/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "defs.h" + +/* This file is only compilable if link.h is available. */ + +#ifdef HAVE_LINK_H + +#include +#include +#include "gdb_string.h" +#include +#include +#include + +#ifndef SVR4_SHARED_LIBS + /* SunOS shared libs need the nlist structure. */ +#include +#else +#include "elf/external.h" +#endif + +#include + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "command.h" +#include "target.h" +#include "frame.h" +#include "gnu-regex.h" +#include "inferior.h" +#include "environ.h" +#include "language.h" +#include "gdbcmd.h" + +#define MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */ + +/* On SVR4 systems, a list of symbols in the dynamic linker where + GDB can try to place a breakpoint to monitor shared library + events. + + If none of these symbols are found, or other errors occur, then + SVR4 systems will fall back to using a symbol as the "startup + mapping complete" breakpoint address. */ + +#ifdef SVR4_SHARED_LIBS +static char *solib_break_names[] = { + "r_debug_state", + "_r_debug_state", + "_dl_debug_state", + NULL +}; +#endif + +#define BKPT_AT_SYMBOL 1 + +#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS) +static char *bkpt_names[] = { +#ifdef SOLIB_BKPT_NAME + SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ +#endif + "_start", + "main", + NULL +}; +#endif + +/* Symbols which are used to locate the base of the link map structures. */ + +#ifndef SVR4_SHARED_LIBS +static char *debug_base_symbols[] = { + "_DYNAMIC", + "_DYNAMIC__MGC", + NULL +}; +#endif + +static char *main_name_list[] = { + "main_$main", + NULL +}; + +/* local data declarations */ + +#ifndef SVR4_SHARED_LIBS + +#define LM_ADDR(so) ((so) -> lm.lm_addr) +#define LM_NEXT(so) ((so) -> lm.lm_next) +#define LM_NAME(so) ((so) -> lm.lm_name) +/* Test for first link map entry; first entry is a shared library. */ +#define IGNORE_FIRST_LINK_MAP_ENTRY(x) (0) +static struct link_dynamic dynamic_copy; +static struct link_dynamic_2 ld_2_copy; +static struct ld_debug debug_copy; +static CORE_ADDR debug_addr; +static CORE_ADDR flag_addr; + +#else /* SVR4_SHARED_LIBS */ + +#define LM_ADDR(so) ((so) -> lm.l_addr) +#define LM_NEXT(so) ((so) -> lm.l_next) +#define LM_NAME(so) ((so) -> lm.l_name) +/* Test for first link map entry; first entry is the exec-file. */ +#define IGNORE_FIRST_LINK_MAP_ENTRY(x) ((x).l_prev == NULL) +static struct r_debug debug_copy; +char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ + +#endif /* !SVR4_SHARED_LIBS */ + +struct so_list { + struct so_list *next; /* next structure in linked list */ + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *abfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ +static CORE_ADDR debug_base; /* Base of dynamic linker structures */ +static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ + +extern int +fdmatch PARAMS ((int, int)); /* In libiberty */ + +/* Local function prototypes */ + +static void +special_symbol_handling PARAMS ((struct so_list *)); + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static int +enable_break PARAMS ((void)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +static struct link_map * +first_link_map_member PARAMS ((void)); + +static CORE_ADDR +locate_base PARAMS ((void)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +#ifdef SVR4_SHARED_LIBS + +static CORE_ADDR +elf_locate_base PARAMS ((void)); + +#else + +static int +disable_break PARAMS ((void)); + +static void +allocate_rt_common_objfile PARAMS ((void)); + +static void +solib_add_common_symbols PARAMS ((struct rtc_symb *)); + +#endif + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + + filename = tilde_expand (so -> so_name); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (get_in_environ (inferior_environ, "PATH"), + 1, filename, O_RDONLY, 0, &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (get_in_environ + (inferior_environ, "LD_LIBRARY_PATH"), + 1, filename, O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. abfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> abfd = abfd; + abfd -> cacheable = true; + + /* copy full path name into so_name, so that later symbol_file_add can find + it */ + if (strlen (scratch_pathname) >= MAX_PATH_SIZE) + error ("Full path name length of shared library exceeds MAX_PATH_SIZE in so_list structure."); + strcpy (so->so_name, scratch_pathname); + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the base address to which the object was actually + mapped. */ + p -> addr += (CORE_ADDR) LM_ADDR (so); + p -> endaddr += (CORE_ADDR) LM_ADDR (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> the_bfd_section -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +#ifndef SVR4_SHARED_LIBS + +/* Allocate the runtime common object file. */ + +static void +allocate_rt_common_objfile () +{ + struct objfile *objfile; + struct objfile *last_one; + + objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); + memset (objfile, 0, sizeof (struct objfile)); + objfile -> md = NULL; + obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0, + xmalloc, free); + obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, xmalloc, + free); + obstack_specify_allocation (&objfile -> type_obstack, 0, 0, xmalloc, + free); + objfile -> name = mstrsave (objfile -> md, "rt_common"); + + /* Add this file onto the tail of the linked list of other such files. */ + + objfile -> next = NULL; + if (object_files == NULL) + object_files = objfile; + else + { + for (last_one = object_files; + last_one -> next; + last_one = last_one -> next); + last_one -> next = objfile; + } + + rt_common_objfile = objfile; +} + +/* Read all dynamically loaded common symbol definitions from the inferior + and put them into the minimal symbol table for the runtime common + objfile. */ + +static void +solib_add_common_symbols (rtc_symp) + struct rtc_symb *rtc_symp; +{ + struct rtc_symb inferior_rtc_symb; + struct nlist inferior_rtc_nlist; + int len; + char *name; + char *origname; + + /* Remove any runtime common symbols from previous runs. */ + + if (rt_common_objfile != NULL && rt_common_objfile -> minimal_symbol_count) + { + obstack_free (&rt_common_objfile -> symbol_obstack, 0); + obstack_specify_allocation (&rt_common_objfile -> symbol_obstack, 0, 0, + xmalloc, free); + rt_common_objfile -> minimal_symbol_count = 0; + rt_common_objfile -> msymbols = NULL; + } + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + while (rtc_symp) + { + read_memory ((CORE_ADDR) rtc_symp, + (char *) &inferior_rtc_symb, + sizeof (inferior_rtc_symb)); + read_memory ((CORE_ADDR) inferior_rtc_symb.rtc_sp, + (char *) &inferior_rtc_nlist, + sizeof(inferior_rtc_nlist)); + if (inferior_rtc_nlist.n_type == N_COMM) + { + /* FIXME: The length of the symbol name is not available, but in the + current implementation the common symbol is allocated immediately + behind the name of the symbol. */ + len = inferior_rtc_nlist.n_value - inferior_rtc_nlist.n_un.n_strx; + + origname = name = xmalloc (len); + read_memory ((CORE_ADDR) inferior_rtc_nlist.n_un.n_name, name, len); + + /* Allocate the runtime common objfile if necessary. */ + if (rt_common_objfile == NULL) + allocate_rt_common_objfile (); + + name = obsavestring (name, strlen (name), + &rt_common_objfile -> symbol_obstack); + prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value, + mst_bss, rt_common_objfile); + free (origname); + } + rtc_symp = inferior_rtc_symb.rtc_next; + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for the runtime common objfile. */ + + install_minimal_symbols (rt_common_objfile); +} + +#endif /* SVR4_SHARED_LIBS */ + + +#ifdef SVR4_SHARED_LIBS + +static CORE_ADDR +bfd_lookup_symbol PARAMS ((bfd *, char *)); + +/* + +LOCAL FUNCTION + + bfd_lookup_symbol -- lookup the value for a specific symbol + +SYNOPSIS + + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) + +DESCRIPTION + + An expensive way to lookup the value of a single symbol for + bfd's that are only temporary anyway. This is used by the + shared library support to find the address of the debugger + interface structures in the shared library. + + Note that 0 is specifically allowed as an error return (no + such symbol). +*/ + +static CORE_ADDR +bfd_lookup_symbol (abfd, symname) + bfd *abfd; + char *symname; +{ + unsigned int storage_needed; + asymbol *sym; + asymbol **symbol_table; + unsigned int number_of_symbols; + unsigned int i; + struct cleanup *back_to; + CORE_ADDR symaddr = 0; + + storage_needed = bfd_get_symtab_upper_bound (abfd); + + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, (PTR)symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) + { + sym = *symbol_table++; + if (STREQ (sym -> name, symname)) + { + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + break; + } + } + do_cleanups (back_to); + } + return (symaddr); +} + +#ifdef HANDLE_SVR4_EXEC_EMULATORS + +/* + Solaris BCP (the part of Solaris which allows it to run SunOS4 + a.out files) throws in another wrinkle. Solaris does not fill + in the usual a.out link map structures when running BCP programs, + the only way to get at them is via groping around in the dynamic + linker. + The dynamic linker and it's structures are located in the shared + C library, which gets run as the executable's "interpreter" by + the kernel. + + Note that we can assume nothing about the process state at the time + we need to find these structures. We may be stopped on the first + instruction of the interpreter (C shared library), the first + instruction of the executable itself, or somewhere else entirely + (if we attached to the process for example). +*/ + +static char *debug_base_symbols[] = { + "r_debug", /* Solaris 2.3 */ + "_r_debug", /* Solaris 2.1, 2.2 */ + NULL +}; + +static int +look_for_base PARAMS ((int, CORE_ADDR)); + +/* + +LOCAL FUNCTION + + look_for_base -- examine file for each mapped address segment + +SYNOPSYS + + static int look_for_base (int fd, CORE_ADDR baseaddr) + +DESCRIPTION + + This function is passed to proc_iterate_over_mappings, which + causes it to get called once for each mapped address space, with + an open file descriptor for the file mapped to that space, and the + base address of that mapped space. + + Our job is to find the debug base symbol in the file that this + fd is open on, if it exists, and if so, initialize the dynamic + linker structure base address debug_base. + + Note that this is a computationally expensive proposition, since + we basically have to open a bfd on every call, so we specifically + avoid opening the exec file. + */ + +static int +look_for_base (fd, baseaddr) + int fd; + CORE_ADDR baseaddr; +{ + bfd *interp_bfd; + CORE_ADDR address = 0; + char **symbolp; + + /* If the fd is -1, then there is no file that corresponds to this + mapped memory segment, so skip it. Also, if the fd corresponds + to the exec file, skip it as well. */ + + if (fd == -1 + || (exec_bfd != NULL + && fdmatch (fileno ((GDB_FILE *)(exec_bfd -> iostream)), fd))) + { + return (0); + } + + /* Try to open whatever random file this fd corresponds to. Note that + we have no way currently to find the filename. Don't gripe about + any problems we might have, just fail. */ + + if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL) + { + return (0); + } + if (!bfd_check_format (interp_bfd, bfd_object)) + { + /* FIXME-leak: on failure, might not free all memory associated with + interp_bfd. */ + bfd_close (interp_bfd); + return (0); + } + + /* Now try to find our debug base symbol in this file, which we at + least know to be a valid ELF executable or shared library. */ + + for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) + { + address = bfd_lookup_symbol (interp_bfd, *symbolp); + if (address != 0) + { + break; + } + } + if (address == 0) + { + /* FIXME-leak: on failure, might not free all memory associated with + interp_bfd. */ + bfd_close (interp_bfd); + return (0); + } + + /* Eureka! We found the symbol. But now we may need to relocate it + by the base address. If the symbol's value is less than the base + address of the shared library, then it hasn't yet been relocated + by the dynamic linker, and we have to do it ourself. FIXME: Note + that we make the assumption that the first segment that corresponds + to the shared library has the base address to which the library + was relocated. */ + + if (address < baseaddr) + { + address += baseaddr; + } + debug_base = address; + /* FIXME-leak: on failure, might not free all memory associated with + interp_bfd. */ + bfd_close (interp_bfd); + return (1); +} +#endif /* HANDLE_SVR4_EXEC_EMULATORS */ + +/* + +LOCAL FUNCTION + + elf_locate_base -- locate the base address of dynamic linker structs + for SVR4 elf targets. + +SYNOPSIS + + CORE_ADDR elf_locate_base (void) + +DESCRIPTION + + For SVR4 elf targets the address of the dynamic linker's runtime + structure is contained within the dynamic info section in the + executable file. The dynamic section is also mapped into the + inferior address space. Because the runtime loader fills in the + real address before starting the inferior, we have to read in the + dynamic info section from the inferior address space. + If there are any errors while trying to find the address, we + silently return 0, otherwise the found address is returned. + + */ + +static CORE_ADDR +elf_locate_base () +{ + sec_ptr dyninfo_sect; + int dyninfo_sect_size; + CORE_ADDR dyninfo_addr; + char *buf; + char *bufend; + + /* Find the start address of the .dynamic section. */ + dyninfo_sect = bfd_get_section_by_name (exec_bfd, ".dynamic"); + if (dyninfo_sect == NULL) + return 0; + dyninfo_addr = bfd_section_vma (exec_bfd, dyninfo_sect); + + /* Read in .dynamic section, silently ignore errors. */ + dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect); + buf = alloca (dyninfo_sect_size); + if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) + return 0; + + /* Find the DT_DEBUG entry in the the .dynamic section. + For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has + no DT_DEBUG entries. */ + /* FIXME: In lack of a 64 bit ELF ABI the following code assumes + a 32 bit ELF ABI target. */ + for (bufend = buf + dyninfo_sect_size; + buf < bufend; + buf += sizeof (Elf32_External_Dyn)) + { + Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *)buf; + long dyn_tag; + CORE_ADDR dyn_ptr; + + dyn_tag = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_tag); + if (dyn_tag == DT_NULL) + break; + else if (dyn_tag == DT_DEBUG) + { + dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); + return dyn_ptr; + } +#ifdef DT_MIPS_RLD_MAP + else if (dyn_tag == DT_MIPS_RLD_MAP) + { + char pbuf[TARGET_PTR_BIT / HOST_CHAR_BIT]; + + /* DT_MIPS_RLD_MAP contains a pointer to the address + of the dynamic link structure. */ + dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); + if (target_read_memory (dyn_ptr, pbuf, sizeof (pbuf))) + return 0; + return extract_unsigned_integer (pbuf, sizeof (pbuf)); + } +#endif + } + + /* DT_DEBUG entry not found. */ + return 0; +} + +#endif /* SVR4_SHARED_LIBS */ + +/* + +LOCAL FUNCTION + + locate_base -- locate the base address of dynamic linker structs + +SYNOPSIS + + CORE_ADDR locate_base (void) + +DESCRIPTION + + For both the SunOS and SVR4 shared library implementations, if the + inferior executable has been linked dynamically, there is a single + address somewhere in the inferior's data space which is the key to + locating all of the dynamic linker's runtime structures. This + address is the value of the debug base symbol. The job of this + function is to find and return that address, or to return 0 if there + is no such address (the executable is statically linked for example). + + For SunOS, the job is almost trivial, since the dynamic linker and + all of it's structures are statically linked to the executable at + link time. Thus the symbol for the address we are looking for has + already been added to the minimal symbol table for the executable's + objfile at the time the symbol file's symbols were read, and all we + have to do is look it up there. Note that we explicitly do NOT want + to find the copies in the shared library. + + The SVR4 version is a bit more complicated because the address + is contained somewhere in the dynamic info section. We have to go + to a lot more work to discover the address of the debug base symbol. + Because of this complexity, we cache the value we find and return that + value on subsequent invocations. Note there is no copy in the + executable symbol tables. + + */ + +static CORE_ADDR +locate_base () +{ + +#ifndef SVR4_SHARED_LIBS + + struct minimal_symbol *msymbol; + CORE_ADDR address = 0; + char **symbolp; + + /* For SunOS, we want to limit the search for the debug base symbol to the + executable being debugged, since there is a duplicate named symbol in the + shared library. We don't want the shared library versions. */ + + for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) + { + msymbol = lookup_minimal_symbol (*symbolp, NULL, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + address = SYMBOL_VALUE_ADDRESS (msymbol); + return (address); + } + } + return (0); + +#else /* SVR4_SHARED_LIBS */ + + /* Check to see if we have a currently valid address, and if so, avoid + doing all this work again and just return the cached address. If + we have no cached address, try to locate it in the dynamic info + section for ELF executables. */ + + if (debug_base == 0) + { + if (exec_bfd != NULL + && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour) + debug_base = elf_locate_base (); +#ifdef HANDLE_SVR4_EXEC_EMULATORS + /* Try it the hard way for emulated executables. */ + else if (inferior_pid != 0) + proc_iterate_over_mappings (look_for_base); +#endif + } + return (debug_base); + +#endif /* !SVR4_SHARED_LIBS */ + +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +static struct link_map * +first_link_map_member () +{ + struct link_map *lm = NULL; + +#ifndef SVR4_SHARED_LIBS + + read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy)); + if (dynamic_copy.ld_version >= 2) + { + /* It is a version that we can deal with, so read in the secondary + structure and find the address of the link map list from it. */ + read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy, + sizeof (struct link_dynamic_2)); + lm = ld_2_copy.ld_loaded; + } + +#else /* SVR4_SHARED_LIBS */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug)); + /* FIXME: Perhaps we should validate the info somehow, perhaps by + checking r_version for a known version number, or r_state for + RT_CONSISTENT. */ + lm = debug_copy.r_map; + +#endif /* !SVR4_SHARED_LIBS */ + + return (lm); +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + + The arg and return value are "struct link_map" pointers, as defined + in . + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct link_map *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* We have not already read in the dynamic linking structures + from the inferior, lookup the address of the base structure. */ + debug_base = locate_base (); + if (debug_base != 0) + { + /* Read the base structure in and find the address of the first + link map list member. */ + lm = first_link_map_member (); + } + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + if ((lm = LM_NEXT (so_list_ptr)) == NULL) + { + /* We have hit the end of the list, so check to see if any were + added, but be quiet if we can't read from the target any more. */ + int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr, + (char *) &(so_list_ptr -> lm), + sizeof (struct link_map)); + if (status == 0) + { + lm = LM_NEXT (so_list_ptr); + } + else + { + lm = NULL; + } + } + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + read_memory ((CORE_ADDR) lm, (char *) &(new -> lm), + sizeof (struct link_map)); + /* For SVR4 versions, the first entry in the link map is for the + inferior executable, so we must ignore it. For some versions of + SVR4, it has no name. For others (Solaris 2.3 for example), it + does have a name, so we can no longer use a missing name to + decide when to ignore it. */ + if (!IGNORE_FIRST_LINK_MAP_ENTRY (new -> lm)) + { + int errcode; + char *buffer; + target_read_string ((CORE_ADDR) LM_NAME (new), &buffer, + MAX_PATH_SIZE - 1, &errcode); + if (errcode != 0) + error ("find_solib: Can't read pathname for load map: %s\n", + safe_strerror (errcode)); + strncpy (new -> so_name, buffer, MAX_PATH_SIZE - 1); + new -> so_name[MAX_PATH_SIZE - 1] = '\0'; + free (buffer); + solib_map_sections (new); + } + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = + symbol_file_add (so -> so_name, so -> from_tty, + (so->textsection == NULL + ? 0 + : (unsigned int) so -> textsection -> addr), + 0, 0, 0); + return (1); +} + +/* This function will check the so name to see if matches the main list. + In some system the main object is in the list, which we want to exclude */ + +static int match_main (soname) + char *soname; +{ + char **mainp; + + for (mainp = main_name_list; *mainp != NULL; mainp++) + { + if (strcmp (soname, *mainp) == 0) + return (1); + } + + return (0); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + /* Add the shared library sections to the section table of the + specified target, if any. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && !match_main (so -> so_name)) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + int update_coreops; + + /* We must update the to_sections field in the core_ops structure + here, otherwise we dereference a potential dangling pointer + for each call to target_read/write_memory within this routine. */ + update_coreops = core_ops.to_sections == target->to_sections; + + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Update the to_sections field in the core_ops structure + if needed. */ + if (update_coreops) + { + core_ops.to_sections = target->to_sections; + core_ops.to_sections_end = target->to_sections_end; + } + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Now add the symbol files. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name) && + !match_main (so -> so_name)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + if (so_last) + reinit_frame_cache (); + + if (so_last) + special_symbol_handling (so_last); +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf_unfiltered ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if (!header_done) + { + printf_unfiltered("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + /* FIXME-32x64: need print_address_numeric with field width or + some such. */ + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) LM_ADDR (so), + "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) so -> lmend, + "08l")); + printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf_unfiltered ("%s\n", so -> so_name); + } + } + if (so_list_head == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + char * solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +char * +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if ((address >= (CORE_ADDR) LM_ADDR (so)) && + (address < (CORE_ADDR) so -> lmend)) + return (so->so_name); + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> abfd) + { + bfd_filename = bfd_get_filename (so_list_head -> abfd); + if (!bfd_close (so_list_head -> abfd)) + warning ("cannot close \"%s\": %s", + bfd_filename, bfd_errmsg (bfd_get_error ())); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free ((PTR)so_list_head); + so_list_head = next; + } + debug_base = 0; +} + +/* + +LOCAL FUNCTION + + disable_break -- remove the "mapping changed" breakpoint + +SYNOPSIS + + static int disable_break () + +DESCRIPTION + + Removes the breakpoint that gets hit when the dynamic linker + completes a mapping change. + +*/ + +#ifndef SVR4_SHARED_LIBS + +static int +disable_break () +{ + int status = 1; + +#ifndef SVR4_SHARED_LIBS + + int in_debugger = 0; + + /* Read the debugger structure from the inferior to retrieve the + address of the breakpoint and the original contents of the + breakpoint address. Remove the breakpoint by writing the original + contents back. */ + + read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set `in_debugger' to zero now. */ + + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + + breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr; + write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst, + sizeof (debug_copy.ldd_bp_inst)); + +#else /* SVR4_SHARED_LIBS */ + + /* Note that breakpoint address and original contents are in our address + space, so we just need to write the original contents back. */ + + if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + status = 0; + } + +#endif /* !SVR4_SHARED_LIBS */ + + /* For the SVR4 version, we always know the breakpoint address. For the + SunOS version we don't know it until the above code is executed. + Grumble if we are stopped anywhere besides the breakpoint address. */ + + if (stop_pc != breakpoint_addr) + { + warning ("stopped at unknown breakpoint while handling shared libraries"); + } + + return (status); +} + +#endif /* #ifdef SVR4_SHARED_LIBS */ + +/* + +LOCAL FUNCTION + + enable_break -- arrange for dynamic linker to hit breakpoint + +SYNOPSIS + + int enable_break (void) + +DESCRIPTION + + Both the SunOS and the SVR4 dynamic linkers have, as part of their + debugger interface, support for arranging for the inferior to hit + a breakpoint after mapping in the shared libraries. This function + enables that breakpoint. + + For SunOS, there is a special flag location (in_debugger) which we + set to 1. When the dynamic linker sees this flag set, it will set + a breakpoint at a location known only to itself, after saving the + original contents of that place and the breakpoint address itself, + in it's own internal structures. When we resume the inferior, it + will eventually take a SIGTRAP when it runs into the breakpoint. + We handle this (in a different place) by restoring the contents of + the breakpointed location (which is only known after it stops), + chasing around to locate the shared libraries that have been + loaded, then resuming. + + For SVR4, the debugger interface structure contains a member (r_brk) + which is statically initialized at the time the shared library is + built, to the offset of a function (_r_debug_state) which is guaran- + teed to be called once before mapping in a library, and again when + the mapping is complete. At the time we are examining this member, + it contains only the unrelocated offset of the function, so we have + to do our own relocation. Later, when the dynamic linker actually + runs, it relocates r_brk to be the actual address of _r_debug_state(). + + The debugger interface structure also contains an enumeration which + is set to either RT_ADD or RT_DELETE prior to changing the mapping, + depending upon whether or not the library is being mapped or unmapped, + and then set to RT_CONSISTENT after the library is mapped/unmapped. +*/ + +static int +enable_break () +{ + int success = 0; + +#ifndef SVR4_SHARED_LIBS + + int j; + int in_debugger; + + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return (0); + } + + /* Calc address of debugger interface structure */ + + debug_addr = (CORE_ADDR) dynamic_copy.ldd; + + /* Calc address of `in_debugger' member of debugger interface structure */ + + flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger - + (char *) &debug_copy); + + /* Write a value of 1 to this member. */ + + in_debugger = 1; + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + success = 1; + +#else /* SVR4_SHARED_LIBS */ + +#ifdef BKPT_AT_SYMBOL + + struct minimal_symbol *msymbol; + char **bkpt_namep; + asection *interp_sect; + + /* First, remove all the solib event breakpoints. Their addresses + may have changed since the last time we ran the program. */ + remove_solib_event_breakpoints (); + +#ifdef SVR4_SHARED_LIBS + /* Find the .interp section; if not found, warn the user and drop + into the old breakpoint at symbol code. */ + interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); + if (interp_sect) + { + unsigned int interp_sect_size; + char *buf; + CORE_ADDR load_addr; + bfd *tmp_bfd; + CORE_ADDR sym_addr = 0; + + /* Read the contents of the .interp section into a local buffer; + the contents specify the dynamic linker this program uses. */ + interp_sect_size = bfd_section_size (exec_bfd, interp_sect); + buf = alloca (interp_sect_size); + bfd_get_section_contents (exec_bfd, interp_sect, + buf, 0, interp_sect_size); + + /* Now we need to figure out where the dynamic linker was + loaded so that we can load its symbols and place a breakpoint + in the dynamic linker itself. + + This address is stored on the stack. However, I've been unable + to find any magic formula to find it for Solaris (appears to + be trivial on Linux). Therefore, we have to try an alternate + mechanism to find the dynamic linker's base address. */ + tmp_bfd = bfd_openr (buf, gnutarget); + if (tmp_bfd == NULL) + goto bkpt_at_symbol; + + /* Make sure the dynamic linker's really a useful object. */ + if (!bfd_check_format (tmp_bfd, bfd_object)) + { + warning ("Unable to grok dynamic linker %s as an object file", buf); + bfd_close (tmp_bfd); + goto bkpt_at_symbol; + } + + /* We find the dynamic linker's base address by examining the + current pc (which point at the entry point for the dynamic + linker) and subtracting the offset of the entry point. */ + load_addr = read_pc () - tmp_bfd->start_address; + + /* Now try to set a breakpoint in the dynamic linker. */ + for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++) + { + sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep); + if (sym_addr != 0) + break; + } + + /* We're done with the temporary bfd. */ + bfd_close (tmp_bfd); + + if (sym_addr != 0) + { + create_solib_event_breakpoint (load_addr + sym_addr); + return 1; + } + + /* For whatever reason we couldn't set a breakpoint in the dynamic + linker. Warn and drop into the old code. */ +bkpt_at_symbol: + warning ("Unable to find dynamic linker breakpoint function."); + warning ("GDB will be unable to debug shared library initializers"); + warning ("and track explicitly loaded dynamic code."); + } +#endif + + /* Scan through the list of symbols, trying to look up the symbol and + set a breakpoint there. Terminate loop when we/if we succeed. */ + + breakpoint_addr = 0; + for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) + { + msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol)); + return 1; + } + } + + /* Nothing good happened. */ + return 0; + +#endif /* BKPT_AT_SYMBOL */ + +#endif /* !SVR4_SHARED_LIBS */ + + return (success); +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + + For SunOS executables, this first instruction is typically the + one at "_start", or a similar text label, regardless of whether + the executable is statically or dynamically linked. The runtime + startup code takes care of dynamically linking in any shared + libraries, once gdb allows the inferior to continue. + + For SVR4 executables, this first instruction is either the first + instruction in the dynamic linker (for dynamically linked + executables) or the instruction at "start" for statically linked + executables. For dynamically linked executables, the system + first exec's /lib/libc.so.N, which contains the dynamic linker, + and starts it running. The dynamic linker maps in any needed + shared libraries, maps in the actual user executable, and then + jumps to "start" in the user executable. + + For both SunOS shared libraries, and SVR4 shared libraries, we + can arrange to cooperate with the dynamic linker to discover the + names of shared libraries that are dynamically linked, and the + base addresses to which they are linked. + + 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. + */ + +void +solib_create_inferior_hook() +{ + /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base + yet. In fact, in the case of a SunOS4 executable being run on + Solaris, we can't get it yet. find_solib will get it when it needs + it. */ +#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL)) + if ((debug_base = locate_base ()) == 0) + { + /* Can't find the symbol or the executable is statically linked. */ + return; + } +#endif + + if (!enable_break ()) + { + warning ("shared library handler failed to enable breakpoint"); + return; + } + +#ifndef SVR4_SHARED_LIBS + /* Only SunOS 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. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = TARGET_SIGNAL_0; + do + { + target_resume (-1, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != TARGET_SIGNAL_TRAP); + stop_soon_quietly = 0; + + /* We are now either at the "mapping complete" breakpoint (or somewhere + else, a condition we aren't prepared to deal with anyway), so adjust + the PC as necessary after a breakpoint, disable the breakpoint, and + add any shared libraries that were mapped in. */ + + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + } + + if (!disable_break ()) + { + warning ("shared library handler failed to disable breakpoint"); + } + + if (auto_solib_add) + solib_add ((char *) 0, 0, (struct target_ops *) 0); +#endif +} + +/* + +LOCAL FUNCTION + + special_symbol_handling -- additional shared library symbol handling + +SYNOPSIS + + void special_symbol_handling (struct so_list *so) + +DESCRIPTION + + Once the symbols from a shared object have been loaded in the usual + way, we are called to do any system specific symbol handling that + is needed. + + For SunOS4, this consists of grunging around in the dynamic + linkers structures to find symbol definitions for "common" symbols + and adding them to the minimal symbol table for the runtime common + objfile. + +*/ + +static void +special_symbol_handling (so) +struct so_list *so; +{ +#ifndef SVR4_SHARED_LIBS + int j; + + if (debug_addr == 0) + { + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return; + } + + /* Calc address of debugger interface structure */ + /* FIXME, this needs work for cross-debugging of core files + (byteorder, size, alignment, etc). */ + + debug_addr = (CORE_ADDR) dynamic_copy.ldd; + } + + /* Read the debugger structure from the inferior, just to make sure + we have a current copy. */ + + j = target_read_memory (debug_addr, (char *) &debug_copy, + sizeof (debug_copy)); + if (j) + return; /* unreadable */ + + /* Get common symbol definitions for the loaded object. */ + + if (debug_copy.ldd_cp) + { + solib_add_common_symbols (debug_copy.ldd_cp); + } + +#endif /* !SVR4_SHARED_LIBS */ +} + + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +#endif /* HAVE_LINK_H */ + +void +_initialize_solib() +{ +#ifdef HAVE_LINK_H + + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); + + add_show_from_set + (add_set_cmd ("auto-solib-add", class_support, var_zinteger, + (char *) &auto_solib_add, + "Set autoloading of shared library symbols.\n\ +If nonzero, symbols from all shared object libraries will be loaded\n\ +automatically when the inferior begins execution or when the dynamic linker\n\ +informs gdb that a new library has been loaded. Otherwise, symbols\n\ +must be loaded manually, using `sharedlibrary'.", + &setlist), + &showlist); + +#endif /* HAVE_LINK_H */ +} diff --git a/contrib/gdb/gdb/solib.h b/contrib/gdb/gdb/solib.h new file mode 100644 index 000000000000..959e59ee5f2f --- /dev/null +++ b/contrib/gdb/gdb/solib.h @@ -0,0 +1,60 @@ +/* Shared library declarations for GDB, the GNU Debugger. + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct target_ops; +#endif + +/* Called when we free all symtabs, to free the shared library information + as well. */ + +#define CLEAR_SOLIB clear_solib + +extern void +clear_solib PARAMS ((void)); + +/* Called to add symbols from a shared library to gdb's symbol table. */ + +#define SOLIB_ADD(filename, from_tty, targ) \ + solib_add (filename, from_tty, targ) + +extern void +solib_add PARAMS ((char *, int, struct target_ops *)); + +/* Function to be called when the inferior starts up, to discover the names + of shared libraries that are dynamically linked, the base addresses to + which they are linked, and sufficient information to read in their symbols + at a later time. */ + +#define SOLIB_CREATE_INFERIOR_HOOK(PID) solib_create_inferior_hook() + +extern void +solib_create_inferior_hook PARAMS((void)); /* solib.c */ + +/* If we can't set a breakpoint, and it's in a shared library, just + disable it. */ + +#define DISABLE_UNSETTABLE_BREAK(addr) (solib_address(addr) != NULL) + +extern char * +solib_address PARAMS ((CORE_ADDR)); /* solib.c */ + +/* If ADDR lies in a shared library, return its name. */ + +#define PC_SOLIB(addr) solib_address (addr) diff --git a/contrib/gdb/gdb/somread.c b/contrib/gdb/gdb/somread.c new file mode 100644 index 000000000000..ab8d531cc275 --- /dev/null +++ b/contrib/gdb/gdb/somread.c @@ -0,0 +1,470 @@ +/* Read HP PA/Risc object files for GDB. + Copyright 1991, 1992, 1996 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "bfd.h" +#include "som.h" +#include "libhppa.h" +#include +#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 + +/* Various things we might complain about... */ + +static void +som_symfile_init PARAMS ((struct objfile *)); + +static void +som_new_init PARAMS ((struct objfile *)); + +static void +som_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); + +static void +som_symfile_finish PARAMS ((struct objfile *)); + +static void +som_symtab_read PARAMS ((bfd *, struct objfile *, + struct section_offsets *)); + +static struct section_offsets * +som_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +record_minimal_symbol PARAMS ((char *, CORE_ADDR, + enum minimal_symbol_type, + struct objfile *)); + +static void +record_minimal_symbol (name, address, ms_type, objfile) + char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; + struct objfile *objfile; +{ + name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); + prim_record_minimal_symbol (name, address, ms_type, objfile); +} + +/* + +LOCAL FUNCTION + + som_symtab_read -- read the symbol table of a SOM file + +SYNOPSIS + + void som_symtab_read (bfd *abfd, struct objfile *objfile, + struct section_offsets *section_offsets) + +DESCRIPTION + + 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 (abfd, objfile, section_offsets) + bfd *abfd; + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + unsigned int number_of_symbols; + int val, dynamic; + char *stringtab; + asection *shlib_info; + struct symbol_dictionary_record *buf, *bufp, *endbufp; + char *symname; + CONST int symsize = sizeof (struct 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); + + buf = alloca (symsize * number_of_symbols); + bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET); + val = bfd_read (buf, symsize * number_of_symbols, 1, abfd); + if (val != symsize * number_of_symbols) + error ("Couldn't read symbol dictionary!"); + + stringtab = alloca (obj_som_stringtab_size (abfd)); + bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET); + val = bfd_read (stringtab, obj_som_stringtab_size (abfd), 1, 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. The only reliable way I know of is to check for the + existance of a $SHLIB_INFO$ section with a non-zero size. */ + shlib_info = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$"); + if (shlib_info) + dynamic = (bfd_section_size (objfile->obfd, shlib_info) != 0); + else + dynamic = 0; + + endbufp = buf + number_of_symbols; + for (bufp = buf; bufp < endbufp; ++bufp) + { + enum minimal_symbol_type ms_type; + + QUIT; + + switch (bufp->symbol_scope) + { + case SS_UNIVERSAL: + case SS_EXTERNAL: + switch (bufp->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 = bufp->name.n_strx + stringtab; + ms_type = mst_text; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + case ST_ENTRY: + symname = bufp->name.n_strx + 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; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + case ST_STUB: + symname = bufp->name.n_strx + stringtab; + ms_type = mst_solib_trampoline; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + case ST_DATA: + symname = bufp->name.n_strx + stringtab; + bufp->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 (bufp->symbol_type) + { + case ST_SYM_EXT: + case ST_ARG_EXT: + continue; + + case ST_CODE: + symname = bufp->name.n_strx + stringtab; + ms_type = mst_file_text; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + + 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, "$PIC", 4) == 0)) + continue; + break; + + case ST_PRI_PROG: + case ST_SEC_PROG: + case ST_MILLICODE: + symname = bufp->name.n_strx + stringtab; + ms_type = mst_file_text; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + case ST_ENTRY: + symname = bufp->name.n_strx + 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_file_text; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + case ST_STUB: + symname = bufp->name.n_strx + stringtab; + ms_type = mst_solib_trampoline; + bufp->symbol_value += text_offset; +#ifdef SMASH_TEXT_ADDRESS + SMASH_TEXT_ADDRESS (bufp->symbol_value); +#endif + break; + + + case ST_DATA: + symname = bufp->name.n_strx + stringtab; + bufp->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. */ + case SS_UNSAT: + switch (bufp->symbol_type) + { + case ST_STORAGE: + symname = bufp->name.n_strx + stringtab; + bufp->symbol_value += data_offset; + ms_type = mst_data; + break; + + default: + continue; + } + break; + + default: + continue; + } + + if (bufp->name.n_strx > obj_som_stringtab_size (abfd)) + error ("Invalid symbol data; bad HP string table offset: %d", + bufp->name.n_strx); + + record_minimal_symbol (symname, + bufp->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. + + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). + + 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 (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; +{ + bfd *abfd = objfile->obfd; + struct cleanup *back_to; + + init_minimal_symbol_collection (); + back_to = make_cleanup (discard_minimal_symbols, 0); + + /* Process the normal SOM symbol table first. */ + + som_symtab_read (abfd, objfile, section_offsets); + + /* Now read information from the stabs debug sections. */ + stabsect_build_psymtabs (objfile, section_offsets, mainline, + "$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$"); + + /* Now read the native debug information. */ + hpread_build_psymtabs (objfile, section_offsets, mainline); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + install_minimal_symbols (objfile); + + /* Force hppa-tdep.c to re-read the unwind descriptors. */ + objfile->obj_private = NULL; + do_cleanups (back_to); +} + +/* 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 (ignore) + 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 (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_stab_info != NULL) + { + mfree (objfile -> md, objfile -> sym_stab_info); + } + hpread_symfile_finish (objfile); +} + +/* SOM specific initialization routine for reading symbols. */ + +static void +som_symfile_init (objfile) + 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; + hpread_symfile_init (objfile); +} + +/* SOM specific parsing routine for section offsets. + + Plain and simple for now. */ + +static struct section_offsets * +som_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + /* First see if we're a shared library. If so, get the section + offsets from the library, else get them from addr. */ + if (!som_solib_section_offsets (objfile, section_offsets)) + { + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + } + + return section_offsets; +} + +/* Register that we are able to handle SOM object file formats. */ + +static struct sym_fns som_sym_fns = +{ + bfd_target_som_flavour, + som_new_init, /* sym_new_init: init anything gbl to entire symtab */ + som_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + som_symfile_read, /* sym_read: read a symbol file into symtab */ + som_symfile_finish, /* sym_finish: finished with file, cleanup */ + som_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_somread () +{ + add_symtab_fns (&som_sym_fns); +} diff --git a/contrib/gdb/gdb/somsolib.c b/contrib/gdb/gdb/somsolib.c new file mode 100644 index 000000000000..1c32837be1d8 --- /dev/null +++ b/contrib/gdb/gdb/somsolib.c @@ -0,0 +1,820 @@ +/* Handle HP SOM shared libraries for GDB, the GNU Debugger. + Copyright 1993, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Written by the Center for Software Science at the Univerity of Utah +and by Cygnus Support. */ + + +#include "defs.h" + +#include "frame.h" +#include "bfd.h" +#include "som.h" +#include "libhppa.h" +#include "gdbcore.h" +#include "symtab.h" +#include "breakpoint.h" +#include "symfile.h" +#include "objfiles.h" +#include "inferior.h" +#include "gdb-stabs.h" +#include "gdbcmd.h" + +/* TODO: + + * Most of this code should work for hp300 shared libraries. Does + anyone care enough to weed out any SOM-isms. + + * Support for hpux8 dynamic linker. */ + +/* The basic structure which describes a dynamically loaded object. This + data structure is private to the dynamic linker and isn't found in + any HPUX include file. */ + +struct som_solib_mapped_entry +{ + /* The name of the library. */ + char *name; + + /* Version of this structure (it is expected to change again in hpux10). */ + unsigned char struct_version; + + /* Binding mode for this library. */ + unsigned char bind_mode; + + /* Version of this library. */ + short library_version; + + /* Start of text address, link-time text location, end of text address. */ + CORE_ADDR text_addr; + CORE_ADDR text_link_addr; + CORE_ADDR text_end; + + /* Start of data, start of bss and end of data. */ + CORE_ADDR data_start; + CORE_ADDR bss_start; + CORE_ADDR data_end; + + /* Value of linkage pointer (%r19). */ + CORE_ADDR got_value; + + /* Next entry. */ + struct som_solib_mapped_entry *next; + + /* There are other fields, but I don't have information as to what is + contained in them. */ +}; + +/* A structure to keep track of all the known shared objects. */ +struct so_list +{ + struct som_solib_mapped_entry som_solib; + struct objfile *objfile; + bfd *abfd; + struct section_table *sections; + struct section_table *sections_end; + struct so_list *next; +}; + +static struct so_list *so_list_head; + +static void som_sharedlibrary_info_command PARAMS ((char *, int)); + +/* Add symbols from shared libraries into the symtab list. */ + +void +som_solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + struct minimal_symbol *msymbol; + struct so_list *so_list_tail; + CORE_ADDR addr; + asection *shlib_info; + int status; + unsigned int dld_flags; + char buf[4], *re_err; + + /* First validate our arguments. */ + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + /* If we're debugging a core file, or have attached to a running + process, then som_solib_create_inferior_hook will not have been + called. + + We need to first determine if we're dealing with a dynamically + linked executable. If not, then return without an error or warning. + + We also need to examine __dld_flags to determine if the shared library + list is valid and to determine if the libraries have been privately + mapped. */ + if (symfile_objfile == NULL) + return; + + /* First see if the objfile was dynamically linked. */ + shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$"); + if (!shlib_info) + return; + + /* It's got a $SHLIB_INFO$ section, make sure it's not empty. */ + if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0) + return; + + msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL); + if (msymbol == NULL) + { + error ("Unable to find __dld_flags symbol in object file.\n"); + return; + } + + addr = SYMBOL_VALUE_ADDRESS (msymbol); + /* Read the current contents. */ + status = target_read_memory (addr, buf, 4); + if (status != 0) + { + error ("Unable to read __dld_flags\n"); + return; + } + dld_flags = extract_unsigned_integer (buf, 4); + + /* __dld_list may not be valid. If it's not valid tell the user. */ + if ((dld_flags & 4) == 0) + { + error ("__dld_list is not valid according to __dld_flags.\n"); + return; + } + + /* If the libraries were not mapped private, warn the user. */ + if ((dld_flags & 1) == 0) + warning ("The shared libraries were not privately mapped; setting a\nbreakpoint in a shared library will not work until you rerun the program.\n"); + + msymbol = lookup_minimal_symbol ("__dld_list", NULL, NULL); + if (!msymbol) + { + /* Older crt0.o files (hpux8) don't have __dld_list as a symbol, + but the data is still available if you know where to look. */ + msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL); + if (!msymbol) + { + error ("Unable to find dynamic library list.\n"); + return; + } + addr = SYMBOL_VALUE_ADDRESS (msymbol) - 8; + } + else + addr = SYMBOL_VALUE_ADDRESS (msymbol); + + status = target_read_memory (addr, buf, 4); + if (status != 0) + { + error ("Unable to find dynamic library list.\n"); + return; + } + + addr = extract_unsigned_integer (buf, 4); + + /* If addr is zero, then we're using an old dynamic loader which + doesn't maintain __dld_list. We'll have to use a completely + different approach to get shared library information. */ + if (addr == 0) + goto old_dld; + + /* Using the information in __dld_list is the preferred method + to get at shared library information. It doesn't depend on + any functions in /usr/lib/end.o and has a chance of working + with hpux10 when it is released. */ + status = target_read_memory (addr, buf, 4); + if (status != 0) + { + error ("Unable to find dynamic library list.\n"); + return; + } + + /* addr now holds the address of the first entry in the dynamic + library list. */ + addr = extract_unsigned_integer (buf, 4); + + /* Now that we have a pointer to the dynamic library list, walk + through it and add the symbols for each library. */ + + so_list_tail = so_list_head; + /* Find the end of the list of shared objects. */ + while (so_list_tail && so_list_tail->next) + so_list_tail = so_list_tail->next; + + while (1) + { + CORE_ADDR name_addr, text_addr; + unsigned int name_len; + char *name; + struct so_list *new_so; + struct so_list *so_list = so_list_head; + struct section_table *p; + struct stat statbuf; + + if (addr == 0) + break; + + /* Get a pointer to the name of this library. */ + status = target_read_memory (addr, buf, 4); + if (status != 0) + goto err; + + name_addr = extract_unsigned_integer (buf, 4); + name_len = 0; + while (1) + { + target_read_memory (name_addr + name_len, buf, 1); + if (status != 0) + goto err; + + name_len++; + if (*buf == '\0') + break; + } + name = alloca (name_len); + status = target_read_memory (name_addr, name, name_len); + if (status != 0) + goto err; + + /* See if we've already loaded something with this name. */ + while (so_list) + { + if (!strcmp (so_list->som_solib.name, name)) + break; + so_list = so_list->next; + } + + /* See if the file exists. If not, give a warning, but don't + die. */ + status = stat (name, &statbuf); + if (status == -1) + { + warning ("Can't find file %s referenced in dld_list.", name); + + status = target_read_memory (addr + 36, buf, 4); + if (status != 0) + goto err; + + addr = (CORE_ADDR) extract_unsigned_integer (buf, 4); + continue; + } + + /* If we've already loaded this one or it's the main program, skip it. */ + if (so_list || !strcmp (name, symfile_objfile->name)) + { + status = target_read_memory (addr + 36, buf, 4); + if (status != 0) + goto err; + + addr = (CORE_ADDR) extract_unsigned_integer (buf, 4); + continue; + } + + name = obsavestring (name, name_len - 1, + &symfile_objfile->symbol_obstack); + + status = target_read_memory (addr + 8, buf, 4); + if (status != 0) + goto err; + + text_addr = extract_unsigned_integer (buf, 4); + + + new_so = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *)new_so, 0, sizeof (struct so_list)); + if (so_list_head == NULL) + { + so_list_head = new_so; + so_list_tail = new_so; + } + else + { + so_list_tail->next = new_so; + so_list_tail = new_so; + } + + /* Fill in all the entries in GDB's shared library list. */ + new_so->som_solib.name = name; + status = target_read_memory (addr + 4, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.struct_version = extract_unsigned_integer (buf + 3, 1); + new_so->som_solib.bind_mode = extract_unsigned_integer (buf + 2, 1); + new_so->som_solib.library_version = extract_unsigned_integer (buf, 2); + new_so->som_solib.text_addr = text_addr; + + status = target_read_memory (addr + 12, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.text_link_addr = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 16, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.text_end = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 20, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.data_start = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 24, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.bss_start = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 28, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.data_end = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 32, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.got_value = extract_unsigned_integer (buf, 4); + + status = target_read_memory (addr + 36, buf, 4); + if (status != 0) + goto err; + + new_so->som_solib.next = (void *)extract_unsigned_integer (buf, 4); + addr = (CORE_ADDR)new_so->som_solib.next; + + new_so->objfile = symbol_file_add (name, from_tty, text_addr, 0, 0, 0); + new_so->abfd = new_so->objfile->obfd; + + if (!bfd_check_format (new_so->abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + name, bfd_errmsg (bfd_get_error ())); + } + + /* Now we need to build a section table for this library since + we might be debugging a core file from a dynamically linked + executable in which the libraries were not privately mapped. */ + if (build_section_table (new_so->abfd, + &new_so->sections, + &new_so->sections_end)) + { + error ("Unable to build section table for shared library\n."); + return; + } + + /* Relocate all the sections based on where they got loaded. */ + for (p = new_so->sections; p < new_so->sections_end; p++) + { + if (p->the_bfd_section->flags & SEC_CODE) + { + p->addr += text_addr - new_so->som_solib.text_link_addr; + p->endaddr += text_addr - new_so->som_solib.text_link_addr; + } + else if (p->the_bfd_section->flags & SEC_DATA) + { + p->addr += new_so->som_solib.data_start; + p->endaddr += new_so->som_solib.data_start; + } + } + + /* Now see if we need to map in the text and data for this shared + library (for example debugging a core file which does not use + private shared libraries.). + + Carefully peek at the first text address in the library. If the + read succeeds, then the libraries were privately mapped and were + included in the core dump file. + + If the peek failed, then the libraries were not privately mapped + and are not in the core file, we'll have to read them in ourselves. */ + status = target_read_memory (text_addr, buf, 4); + if (status != 0) + { + int old, new; + int update_coreops; + + /* We must update the to_sections field in the core_ops structure + here, otherwise we dereference a potential dangling pointer + for each call to target_read/write_memory within this routine. */ + update_coreops = core_ops.to_sections == target->to_sections; + + new = new_so->sections_end - new_so->sections; + /* Add sections from the shared library to the core target. */ + if (target->to_sections) + { + old = target->to_sections_end - target->to_sections; + target->to_sections = (struct section_table *) + xrealloc ((char *)target->to_sections, + ((sizeof (struct section_table)) * (old + new))); + } + else + { + old = 0; + target->to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * new); + } + target->to_sections_end = (target->to_sections + old + new); + + /* Update the to_sections field in the core_ops structure + if needed. */ + if (update_coreops) + { + core_ops.to_sections = target->to_sections; + core_ops.to_sections_end = target->to_sections_end; + } + + /* Copy over the old data before it gets clobbered. */ + memcpy ((char *)(target->to_sections + old), + new_so->sections, + ((sizeof (struct section_table)) * new)); + } + } + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); + return; + +old_dld: + error ("Debugging dynamic executables loaded via the hpux8 dld.sl is not supported.\n"); + return; + +err: + error ("Error while reading dynamic library list.\n"); + return; +} + + +/* This hook gets called just before the first instruction in the + inferior process is executed. + + This is our opportunity to set magic flags in the inferior so + that GDB can be notified when a shared library is mapped in and + to tell the dynamic linker that a private copy of the library is + needed (so GDB can set breakpoints in the library). + + __dld_flags is the location of the magic flags; as of this implementation + there are 3 flags of interest: + + bit 0 when set indicates that private copies of the libraries are needed + bit 1 when set indicates that the callback hook routine is valid + bit 2 when set indicates that the dynamic linker should maintain the + __dld_list structure when loading/unloading libraries. + + Note that shared libraries are not mapped in at this time, so we have + run the inferior until the libraries are mapped in. Typically this + means running until the "_start" is called. */ + +void +som_solib_create_inferior_hook() +{ + struct minimal_symbol *msymbol; + unsigned int dld_flags, status, have_endo; + asection *shlib_info; + char shadow_contents[BREAKPOINT_MAX], buf[4]; + struct objfile *objfile; + CORE_ADDR anaddr; + + /* First, remove all the solib event breakpoints. Their addresses + may have changed since the last time we ran the program. */ + remove_solib_event_breakpoints (); + + if (symfile_objfile == NULL) + return; + + /* First see if the objfile was dynamically linked. */ + shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$"); + if (!shlib_info) + return; + + /* It's got a $SHLIB_INFO$ section, make sure it's not empty. */ + if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0) + return; + + have_endo = 0; + /* Slam the pid of the process into __d_pid; failing is only a warning! */ + msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile); + if (msymbol == NULL) + { + warning ("Unable to find __d_pid symbol in object file."); + warning ("Suggest linking with /usr/lib/end.o."); + warning ("GDB will be unable to track shl_load/shl_unload calls"); + goto keep_going; + } + + anaddr = SYMBOL_VALUE_ADDRESS (msymbol); + store_unsigned_integer (buf, 4, inferior_pid); + status = target_write_memory (anaddr, buf, 4); + if (status != 0) + { + warning ("Unable to write __d_pid"); + warning ("Suggest linking with /usr/lib/end.o."); + warning ("GDB will be unable to track shl_load/shl_unload calls"); + goto keep_going; + } + + /* Get the value of _DLD_HOOK (an export stub) and put it in __dld_hook; + This will force the dynamic linker to call __d_trap when significant + events occur. */ + msymbol = lookup_minimal_symbol ("_DLD_HOOK", NULL, symfile_objfile); + if (msymbol == NULL) + { + warning ("Unable to find _DLD_HOOK symbol in object file."); + warning ("Suggest linking with /usr/lib/end.o."); + warning ("GDB will be unable to track shl_load/shl_unload calls"); + goto keep_going; + } + anaddr = SYMBOL_VALUE_ADDRESS (msymbol); + + /* Grrr, this might not be an export symbol! We have to find the + export stub. */ + ALL_OBJFILES (objfile) + { + struct unwind_table_entry *u; + extern struct unwind_table_entry *find_unwind_entry PARAMS ((CORE_ADDR pc)); + + /* What a crock. */ + msymbol = lookup_minimal_symbol_solib_trampoline (SYMBOL_NAME (msymbol), + NULL, objfile); + /* Found a symbol with the right name. */ + if (msymbol) + { + struct unwind_table_entry *u; + /* It must be a shared library trampoline. */ + if (SYMBOL_TYPE (msymbol) != mst_solib_trampoline) + continue; + + /* It must also be an export stub. */ + u = find_unwind_entry (SYMBOL_VALUE (msymbol)); + if (!u || u->stub_type != EXPORT) + continue; + + /* OK. Looks like the correct import stub. */ + anaddr = SYMBOL_VALUE (msymbol); + break; + } + } + store_unsigned_integer (buf, 4, anaddr); + + msymbol = lookup_minimal_symbol ("__dld_hook", NULL, symfile_objfile); + if (msymbol == NULL) + { + warning ("Unable to find __dld_hook symbol in object file."); + warning ("Suggest linking with /usr/lib/end.o."); + warning ("GDB will be unable to track shl_load/shl_unload calls"); + goto keep_going; + } + anaddr = SYMBOL_VALUE_ADDRESS (msymbol); + status = target_write_memory (anaddr, buf, 4); + + /* Now set a shlib_event breakpoint at __d_trap so we can track + significant shared library events. */ + msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile); + if (msymbol == NULL) + { + warning ("Unable to find __dld_d_trap symbol in object file."); + warning ("Suggest linking with /usr/lib/end.o."); + warning ("GDB will be unable to track shl_load/shl_unload calls"); + goto keep_going; + } + create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol)); + + /* We have all the support usually found in end.o, so we can track + shl_load and shl_unload calls. */ + have_endo = 1; + +keep_going: + + /* Get the address of __dld_flags, if no such symbol exists, then we can + not debug the shared code. */ + msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL); + if (msymbol == NULL) + { + error ("Unable to find __dld_flags symbol in object file.\n"); + goto keep_going; + return; + } + + anaddr = SYMBOL_VALUE_ADDRESS (msymbol); + /* Read the current contents. */ + status = target_read_memory (anaddr, buf, 4); + if (status != 0) + { + error ("Unable to read __dld_flags\n"); + return; + } + dld_flags = extract_unsigned_integer (buf, 4); + + /* Turn on the flags we care about. */ + dld_flags |= (0x5 | (have_endo << 1)); + store_unsigned_integer (buf, 4, dld_flags); + status = target_write_memory (anaddr, buf, 4); + if (status != 0) + { + error ("Unable to write __dld_flags\n"); + return; + } + + /* Now find the address of _start and set a breakpoint there. + We still need this code for two reasons: + + * Not all sites have /usr/lib/end.o, so it's not always + possible to track the dynamic linker's events. + + * At this time no events are triggered for shared libraries + loaded at startup time (what a crock). */ + + msymbol = lookup_minimal_symbol ("_start", NULL, symfile_objfile); + if (msymbol == NULL) + { + error ("Unable to find _start symbol in object file.\n"); + return; + } + + anaddr = SYMBOL_VALUE_ADDRESS (msymbol); + + /* Make the breakpoint at "_start" a shared library event breakpoint. */ + create_solib_event_breakpoint (anaddr); + + /* Wipe out all knowledge of old shared libraries since their + mapping can change from one exec to another! */ + while (so_list_head) + { + struct so_list *temp; + + free_objfile (so_list_head->objfile); + temp = so_list_head; + free (so_list_head); + so_list_head = temp->next; + } + clear_symtab_users (); +} + +/* Return the GOT value for the shared library in which ADDR belongs. If + ADDR isn't in any known shared library, return zero. */ + +CORE_ADDR +som_solib_get_got_by_pc (addr) + CORE_ADDR addr; +{ + struct so_list *so_list = so_list_head; + CORE_ADDR got_value = 0; + + while (so_list) + { + if (so_list->som_solib.text_addr <= addr + && so_list->som_solib.text_end > addr) + { + got_value = so_list->som_solib.got_value; + break; + } + so_list = so_list->next; + } + return got_value; +} + +int +som_solib_section_offsets (objfile, offsets) + struct objfile *objfile; + struct section_offsets *offsets; +{ + struct so_list *so_list = so_list_head; + + while (so_list) + { + /* Oh what a pain! We need the offsets before so_list->objfile + is valid. The BFDs will never match. Make a best guess. */ + if (strstr (objfile->name, so_list->som_solib.name)) + { + asection *private_section; + + /* The text offset is easy. */ + ANOFFSET (offsets, SECT_OFF_TEXT) + = (so_list->som_solib.text_addr + - so_list->som_solib.text_link_addr); + ANOFFSET (offsets, SECT_OFF_RODATA) + = ANOFFSET (offsets, SECT_OFF_TEXT); + + /* We should look at presumed_dp in the SOM header, but + that's not easily available. This should be OK though. */ + private_section = bfd_get_section_by_name (objfile->obfd, + "$PRIVATE$"); + if (!private_section) + { + warning ("Unable to find $PRIVATE$ in shared library!"); + ANOFFSET (offsets, SECT_OFF_DATA) = 0; + ANOFFSET (offsets, SECT_OFF_BSS) = 0; + return 1; + } + ANOFFSET (offsets, SECT_OFF_DATA) + = (so_list->som_solib.data_start - private_section->vma); + ANOFFSET (offsets, SECT_OFF_BSS) + = ANOFFSET (offsets, SECT_OFF_DATA); + return 1; + } + so_list = so_list->next; + } + return 0; +} + +/* Dump information about all the currently loaded shared libraries. */ + +static void +som_sharedlibrary_info_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + struct so_list *so_list = so_list_head; + + if (exec_bfd == NULL) + { + printf_unfiltered ("no exec file.\n"); + return; + } + + if (so_list == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + return; + } + + printf_unfiltered ("Shared Object Libraries\n"); + printf_unfiltered (" %-12s%-12s%-12s%-12s%-12s%-12s\n", + " flags", " tstart", " tend", " dstart", " dend", " dlt"); + while (so_list) + { + unsigned int flags; + + flags = so_list->som_solib.struct_version << 24; + flags |= so_list->som_solib.bind_mode << 16; + flags |= so_list->som_solib.library_version; + printf_unfiltered ("%s\n", so_list->som_solib.name); + printf_unfiltered (" %-12s", local_hex_string_custom (flags, "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom (so_list->som_solib.text_addr, "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom (so_list->som_solib.text_end, "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom (so_list->som_solib.data_start, "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom (so_list->som_solib.data_end, "08l")); + printf_unfiltered ("%-12s\n", + local_hex_string_custom (so_list->som_solib.got_value, "08l")); + so_list = so_list->next; + } +} + +static void +som_solib_sharedlibrary_command (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); + som_solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_som_solib () +{ + add_com ("sharedlibrary", class_files, som_solib_sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", som_sharedlibrary_info_command, + "Status of loaded shared object libraries."); + add_show_from_set + (add_set_cmd ("auto-solib-add", class_support, var_zinteger, + (char *) &auto_solib_add, + "Set autoloading of shared library symbols at startup.\n\ +If nonzero, symbols from all shared object libraries will be loaded\n\ +automatically when the inferior begins execution or when the dynamic linker\n\ +informs gdb that a new library has been loaded. Otherwise, symbols\n\ +must be loaded manually, using `sharedlibrary'.", + &setlist), + &showlist); + +} diff --git a/contrib/gdb/gdb/somsolib.h b/contrib/gdb/gdb/somsolib.h new file mode 100644 index 000000000000..6fe0200bb606 --- /dev/null +++ b/contrib/gdb/gdb/somsolib.h @@ -0,0 +1,51 @@ +/* HP SOM Shared library declarations for GDB, the GNU Debugger. + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Written by the Center for Software Science at the Univerity of Utah +and by Cygnus Support. */ + +#ifdef __STDC__ /* Forward decl's for prototypes */ +struct target_ops; +struct objfile; +struct section_offsets; +#endif + +/* Called to add symbols from a shared library to gdb's symbol table. */ + +#define SOLIB_ADD(filename, from_tty, targ) \ + som_solib_add (filename, from_tty, targ) + +extern void +som_solib_add PARAMS ((char *, int, struct target_ops *)); + +extern CORE_ADDR +som_solib_get_got_by_pc PARAMS ((CORE_ADDR)); + +extern int +som_solib_section_offsets PARAMS ((struct objfile *, struct section_offsets *)); + +/* Function to be called when the inferior starts up, to discover the names + of shared libraries that are dynamically linked, the base addresses to + which they are linked, and sufficient information to read in their symbols + at a later time. */ + +#define SOLIB_CREATE_INFERIOR_HOOK(PID) som_solib_create_inferior_hook() + +extern void +som_solib_create_inferior_hook PARAMS((void)); diff --git a/contrib/gdb/gdb/source.c b/contrib/gdb/gdb/source.c new file mode 100644 index 000000000000..5e7af031bc95 --- /dev/null +++ b/contrib/gdb/gdb/source.c @@ -0,0 +1,1506 @@ +/* List lines of source files for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "expression.h" +#include "language.h" +#include "command.h" +#include "gdbcmd.h" +#include "frame.h" +#include "value.h" + +#include +#include "gdb_string.h" +#include +#include "gdb_stat.h" +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include "gdbcore.h" +#include "gnu-regex.h" +#include "symfile.h" +#include "objfiles.h" +#include "annotate.h" +#include "gdbtypes.h" + +/* Prototypes for local functions. */ + +static int open_source_file PARAMS ((struct symtab *)); + +static int get_filename_and_charpos PARAMS ((struct symtab *, char **)); + +static void reverse_search_command PARAMS ((char *, int)); + +static void forward_search_command PARAMS ((char *, int)); + +static void line_info PARAMS ((char *, int)); + +static void list_command PARAMS ((char *, int)); + +static void ambiguous_line_spec PARAMS ((struct symtabs_and_lines *)); + +static void source_info PARAMS ((char *, int)); + +static void show_directories PARAMS ((char *, int)); + +static void find_source_lines PARAMS ((struct symtab *, int)); + +/* If we use this declaration, it breaks because of fucking ANSI "const" stuff + on some systems. We just have to not declare it at all, have it default + to int, and possibly botch on a few systems. Thanks, ANSIholes... */ +/* extern char *strstr(); */ + +/* Path of directories to search for source files. + Same format as the PATH environment variable's value. */ + +char *source_path; + +/* Symtab of default file for listing lines of. */ + +struct symtab *current_source_symtab; + +/* Default next line to list. */ + +int current_source_line; + +/* Default number of lines to print with commands like "list". + This is based on guessing how many long (i.e. more than chars_per_line + characters) lines there will be. To be completely correct, "list" + and friends should be rewritten to count characters and see where + things are wrapping, but that would be a fair amount of work. */ + +int lines_to_list = 10; + +/* Line number of last line printed. Default for various commands. + current_source_line is usually, but not always, the same as this. */ + +static int last_line_listed; + +/* First line number listed by last listing command. */ + +static int first_line_listed; + + +/* Set the source file default for the "list" command to be S. + + If S is NULL, and we don't have a default, find one. This + should only be called when the user actually tries to use the + default, since we produce an error if we can't find a reasonable + default. Also, since this can cause symbols to be read, doing it + before we need to would make things slower than necessary. */ + +void +select_source_symtab (s) + register struct symtab *s; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct partial_symtab *ps; + struct partial_symtab *cs_pst = 0; + struct objfile *ofp; + + if (s) + { + current_source_symtab = s; + current_source_line = 1; + return; + } + + if (current_source_symtab) + return; + + /* Make the default place to list be the function `main' + if one exists. */ + if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0, NULL)) + { + sals = decode_line_spec ("main", 1); + sal = sals.sals[0]; + free (sals.sals); + current_source_symtab = sal.symtab; + current_source_line = max (sal.line - (lines_to_list - 1), 1); + if (current_source_symtab) + return; + } + + /* All right; find the last file in the symtab list (ignoring .h's). */ + + current_source_line = 1; + + for (ofp = object_files; ofp != NULL; ofp = ofp -> next) + { + for (s = ofp -> symtabs; s; s = s->next) + { + char *name = s -> filename; + int len = strlen (name); + if (! (len > 2 && (STREQ (&name[len - 2], ".h")))) + { + current_source_symtab = s; + } + } + } + if (current_source_symtab) + return; + + /* Howabout the partial symbol tables? */ + + for (ofp = object_files; ofp != NULL; ofp = ofp -> next) + { + for (ps = ofp -> psymtabs; ps != NULL; ps = ps -> next) + { + char *name = ps -> filename; + int len = strlen (name); + if (! (len > 2 && (STREQ (&name[len - 2], ".h")))) + { + cs_pst = ps; + } + } + } + if (cs_pst) + { + if (cs_pst -> readin) + { + fatal ("Internal: select_source_symtab: readin pst found and no symtabs."); + } + else + { + current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst); + } + } + + error ("Can't find a default source file"); +} + +static void +show_directories (ignore, from_tty) + char *ignore; + int from_tty; +{ + puts_filtered ("Source directories searched: "); + puts_filtered (source_path); + puts_filtered ("\n"); +} + +/* Forget what we learned about line positions in source files, and + which directories contain them; must check again now since files + may be found in a different directory now. */ + +void +forget_cached_source_info () +{ + register struct symtab *s; + register struct objfile *objfile; + + for (objfile = object_files; objfile != NULL; objfile = objfile -> next) + { + for (s = objfile -> symtabs; s != NULL; s = s -> next) + { + if (s -> line_charpos != NULL) + { + mfree (objfile -> md, s -> line_charpos); + s -> line_charpos = NULL; + } + if (s -> fullname != NULL) + { + mfree (objfile -> md, s -> fullname); + s -> fullname = NULL; + } + } + } +} + +void +init_source_path () +{ + char buf[20]; + + sprintf (buf, "$cdir%c$cwd", DIRNAME_SEPARATOR); + source_path = strsave (buf); + forget_cached_source_info (); +} + +/* Add zero or more directories to the front of the source path. */ + +void +directory_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + dont_repeat (); + /* FIXME, this goes to "delete dir"... */ + if (dirname == 0) + { + if (query ("Reinitialize source path to empty? ")) + { + free (source_path); + init_source_path (); + } + } + else + mod_path (dirname, &source_path); + if (from_tty) + show_directories ((char *)0, from_tty); + forget_cached_source_info (); +} + +/* Add zero or more directories to the front of an arbitrary path. */ + +void +mod_path (dirname, which_path) + char *dirname; + char **which_path; +{ + char *old = *which_path; + int prefix = 0; + + if (dirname == 0) + return; + + dirname = strsave (dirname); + make_cleanup (free, dirname); + + do + { + char *name = dirname; + register char *p; + struct stat st; + + { + char *separator = strchr (name, DIRNAME_SEPARATOR); + char *space = strchr (name, ' '); + char *tab = strchr (name, '\t'); + + if (separator == 0 && space == 0 && tab == 0) + p = dirname = name + strlen (name); + else + { + p = 0; + if (separator != 0 && (p == 0 || separator < p)) + p = separator; + if (space != 0 && (p == 0 || space < p)) + p = space; + if (tab != 0 && (p == 0 || tab < p)) + p = tab; + dirname = p + 1; + while (*dirname == DIRNAME_SEPARATOR + || *dirname == ' ' + || *dirname == '\t') + ++dirname; + } + } + +#ifndef WIN32 + /* On win32 h:\ is different to h: */ + if (SLASH_P (p[-1])) + /* Sigh. "foo/" => "foo" */ + --p; +#endif + *p = '\0'; + + while (p[-1] == '.') + { + if (p - name == 1) + { + /* "." => getwd (). */ + name = current_directory; + goto append; + } + else if (SLASH_P (p[-2])) + { + if (p - name == 2) + { + /* "/." => "/". */ + *--p = '\0'; + goto append; + } + else + { + /* "...foo/." => "...foo". */ + p -= 2; + *p = '\0'; + continue; + } + } + else + break; + } + + if (name[0] == '~') + name = tilde_expand (name); + else if (!ROOTED_P (name) && name[0] != '$') + name = concat (current_directory, SLASH_STRING, name, NULL); + else + name = savestring (name, p - name); + make_cleanup (free, name); + + /* Unless it's a variable, check existence. */ + if (name[0] != '$') { + /* These are warnings, not errors, since we don't want a + non-existent directory in a .gdbinit file to stop processing + of the .gdbinit file. + + Whether they get added to the path is more debatable. Current + answer is yes, in case the user wants to go make the directory + or whatever. If the directory continues to not exist/not be + a directory/etc, then having them in the path should be + harmless. */ + if (stat (name, &st) < 0) + { + int save_errno = errno; + fprintf_unfiltered (gdb_stderr, "Warning: "); + print_sys_errmsg (name, save_errno); + } + else if ((st.st_mode & S_IFMT) != S_IFDIR) + warning ("%s is not a directory.", name); + } + + append: + { + register unsigned int len = strlen (name); + + p = *which_path; + while (1) + { + if (!strncmp (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; + } + if (p == 0) + { + char tinybuf[2]; + + 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, NULL); + old[prefix] = c; + *which_path = concat (temp, "", &old[prefix], NULL); + prefix = strlen (temp); + free (temp); + } + else + { + *which_path = concat (name, (old[0] ? tinybuf : old), old, NULL); + prefix = strlen (name); + } + free (old); + old = *which_path; + } + } + skip_dup: ; + } while (*dirname != '\0'); +} + + +static void +source_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct symtab *s = current_source_symtab; + + if (!s) + { + printf_filtered("No current source file.\n"); + return; + } + printf_filtered ("Current source file is %s\n", s->filename); + if (s->dirname) + printf_filtered ("Compilation directory is %s\n", s->dirname); + if (s->fullname) + printf_filtered ("Located in %s\n", s->fullname); + if (s->nlines) + printf_filtered ("Contains %d line%s.\n", s->nlines, + s->nlines == 1 ? "" : "s"); + + printf_filtered("Source language is %s.\n", language_str (s->language)); +} + + + +/* Open a file named STRING, searching path PATH (dir names sep by some char) + using mode MODE and protection bits PROT in the calls to open. + + If TRY_CWD_FIRST, try to open ./STRING before searching PATH. + (ie pretend the first element of PATH is "."). This also indicates + that a slash in STRING disables searching of the path (this is + so that "exec-file ./foo" or "symbol-file ./foo" insures that you + get that particular version of foo or an error message). + + If FILENAMED_OPENED is non-null, set it to a newly allocated string naming + the actual file opened (this string will always start with a "/". We + have to take special pains to avoid doubling the "/" between the directory + and the file, sigh! Emacs gets confuzzed by this when we print the + source file name!!! + + If a file is found, return the descriptor. + Otherwise, return -1, with errno set for the last name we tried to open. */ + +/* >>>> This should only allow files of certain types, + >>>> eg executable, non-directory */ +int +openp (path, try_cwd_first, string, mode, prot, filename_opened) + char *path; + int try_cwd_first; + char *string; + int mode; + int prot; + char **filename_opened; +{ + register int fd; + register char *filename; + register char *p, *p1; + register int len; + int alloclen; + + if (!path) + path = "."; + +#ifdef WIN32 + mode |= O_BINARY; +#endif + + if (try_cwd_first || SLASH_P (string[0])) + { + int i; + filename = string; + fd = open (filename, mode, prot); + if (fd >= 0) + goto done; + for (i = 0; string[i]; i++) + if (SLASH_P (string[i])) + goto done; + } + + /* ./foo => foo */ + while (string[0] == '.' && SLASH_P (string[1])) + string += 2; + + alloclen = strlen (path) + strlen (string) + 2; + filename = (char *) alloca (alloclen); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = (char *) strchr (p, DIRNAME_SEPARATOR); + if (p1) + len = p1 - p; + else + len = strlen (p); + + if (len == 4 && p[0] == '$' && p[1] == 'c' + && p[2] == 'w' && p[3] == 'd') { + /* Name is $cwd -- insert current directory name instead. */ + int newlen; + + /* First, realloc the filename buffer if too short. */ + len = strlen (current_directory); + newlen = len + strlen (string) + 2; + if (newlen > alloclen) { + alloclen = newlen; + filename = (char *) alloca (alloclen); + } + strcpy (filename, current_directory); + } else { + /* Normal file name in path -- just use it. */ + strncpy (filename, p, len); + filename[len] = 0; + } + + /* Remove trailing slashes */ + while (len > 0 && SLASH_P (filename[len-1])) + filename[--len] = 0; + + strcat (filename+len, SLASH_STRING); + strcat (filename, string); + + fd = open (filename, mode); + if (fd >= 0) break; + } + + done: + if (filename_opened) + { + if (fd < 0) + *filename_opened = (char *) 0; + else if (ROOTED_P (filename)) + *filename_opened = savestring (filename, strlen (filename)); + else + { + /* Beware the // my son, the Emacs barfs, the botch that catch... */ + + *filename_opened = concat (current_directory, + SLASH_CHAR + == current_directory[strlen(current_directory)-1] + ? "": SLASH_STRING, + filename, NULL); + } + } +#ifdef MPW + /* This is a debugging hack that can go away when all combinations + of Mac and Unix names are handled reasonably. */ + { + extern int debug_openp; + + if (debug_openp) + { + printf("openp on %s, path %s mode %d prot %d\n returned %d", + string, path, mode, prot, fd); + if (*filename_opened) + printf(" (filename is %s)", *filename_opened); + printf("\n"); + } + } +#endif /* MPW */ + + return fd; +} + +/* Open a source file given a symtab S. Returns a file descriptor or + negative number for error. */ + +static int +open_source_file (s) + struct symtab *s; +{ + char *path = source_path; + char *p; + int result; + char *fullname; + + /* Quick way out if we already know its full name */ + if (s->fullname) + { + result = open (s->fullname, O_RDONLY); + if (result >= 0) + return result; + /* Didn't work -- free old one, try again. */ + mfree (s->objfile->md, s->fullname); + s->fullname = NULL; + } + + if (s->dirname != NULL) + { + /* Replace a path entry of $cdir with the compilation directory name */ +#define cdir_len 5 + /* We cast strstr's result in case an ANSIhole has made it const, + which produces a "required warning" when assigned to a nonconst. */ + p = (char *)strstr (source_path, "$cdir"); + if (p && (p == path || p[-1] == DIRNAME_SEPARATOR) + && (p[cdir_len] == DIRNAME_SEPARATOR || p[cdir_len] == '\0')) + { + int len; + + path = (char *) + alloca (strlen (source_path) + 1 + strlen (s->dirname) + 1); + len = p - source_path; + strncpy (path, source_path, len); /* Before $cdir */ + strcpy (path + len, s->dirname); /* new stuff */ + strcat (path + len, source_path + len + cdir_len); /* After $cdir */ + } + } + + result = openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname); + if (result < 0) + { + /* Didn't work. Try using just the basename. */ + p = basename (s->filename); + if (p != s->filename) + result = openp (path, 0, p, O_RDONLY, 0, &s->fullname); + } +#ifdef MPW + if (result < 0) + { + /* Didn't work. Try using just the MPW basename. */ + p = (char *) mpw_basename (s->filename); + if (p != s->filename) + result = openp (path, 0, p, O_RDONLY, 0, &s->fullname); + } + if (result < 0) + { + /* Didn't work. Try using the mixed Unix/MPW basename. */ + p = (char *) mpw_mixed_basename (s->filename); + if (p != s->filename) + result = openp (path, 0, p, O_RDONLY, 0, &s->fullname); + } +#endif /* MPW */ + + if (result >= 0) + { + fullname = s->fullname; + s->fullname = mstrsave (s->objfile->md, s->fullname); + free (fullname); + } + return result; +} + +/* Return the path to the source file associated with symtab. Returns NULL + if no symtab. */ + +char * +symtab_to_filename (s) + struct symtab *s; +{ + int fd; + + if (!s) + return NULL; + + /* If we've seen the file before, just return fullname. */ + + if (s->fullname) + return s->fullname; + + /* Try opening the file to setup fullname */ + + fd = open_source_file (s); + if (fd < 0) + return s->filename; /* File not found. Just use short name */ + + /* Found the file. Cleanup and return the full name */ + + close (fd); + return s->fullname; +} + + +/* Create and initialize the table S->line_charpos that records + the positions of the lines in the source file, which is assumed + to be open on descriptor DESC. + All set S->nlines to the number of such lines. */ + +static void +find_source_lines (s, desc) + struct symtab *s; + int desc; +{ + struct stat st; + register char *data, *p, *end; + int nlines = 0; + int lines_allocated = 1000; + int *line_charpos; + long exec_mtime; + int size; + + line_charpos = (int *) xmmalloc (s -> objfile -> md, + lines_allocated * sizeof (int)); + if (fstat (desc, &st) < 0) + perror_with_name (s->filename); + + if (exec_bfd) + { + exec_mtime = bfd_get_mtime(exec_bfd); + if (exec_mtime && exec_mtime < st.st_mtime) + printf_filtered ("Source file is more recent than executable.\n"); + } + +#ifdef LSEEK_NOT_LINEAR + { + char c; + + /* Have to read it byte by byte to find out where the chars live */ + + line_charpos[0] = lseek (desc, 0, SEEK_CUR); + nlines = 1; + while (myread(desc, &c, 1)>0) + { + if (c == '\n') + { + if (nlines == lines_allocated) + { + lines_allocated *= 2; + line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + sizeof (int) * lines_allocated); + } + line_charpos[nlines++] = lseek (desc, 0, SEEK_CUR); + } + } + } +#else /* lseek linear. */ + { + struct cleanup *old_cleanups; + + /* st_size might be a large type, but we only support source files whose + size fits in an int. */ + size = (int) st.st_size; + + /* Use malloc, not alloca, because this may be pretty large, and we may + run into various kinds of limits on stack size. */ + data = (char *) xmalloc (size); + old_cleanups = make_cleanup (free, data); + + if (myread (desc, data, size) < 0) + perror_with_name (s->filename); + end = data + size; + p = data; + line_charpos[0] = 0; + nlines = 1; + while (p != end) + { + if (*p++ == '\n' + /* A newline at the end does not start a new line. */ + && p != end) + { + if (nlines == lines_allocated) + { + lines_allocated *= 2; + line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + sizeof (int) * lines_allocated); + } + line_charpos[nlines++] = p - data; + } + } + do_cleanups (old_cleanups); + } +#endif /* lseek linear. */ + s->nlines = nlines; + s->line_charpos = + (int *) xmrealloc (s -> objfile -> md, (char *) line_charpos, + nlines * sizeof (int)); + +} + +/* Return the character position of a line LINE in symtab S. + Return 0 if anything is invalid. */ + +#if 0 /* Currently unused */ + +int +source_line_charpos (s, line) + struct symtab *s; + int line; +{ + if (!s) return 0; + if (!s->line_charpos || line <= 0) return 0; + if (line > s->nlines) + line = s->nlines; + return s->line_charpos[line - 1]; +} + +/* Return the line number of character position POS in symtab S. */ + +int +source_charpos_line (s, chr) + register struct symtab *s; + register int chr; +{ + register int line = 0; + register int *lnp; + + if (s == 0 || s->line_charpos == 0) return 0; + lnp = s->line_charpos; + /* Files are usually short, so sequential search is Ok */ + while (line < s->nlines && *lnp <= chr) + { + line++; + lnp++; + } + if (line >= s->nlines) + line = s->nlines; + return line; +} + +#endif /* 0 */ + + +/* Get full pathname and line number positions for a symtab. + Return nonzero if line numbers may have changed. + Set *FULLNAME to actual name of the file as found by `openp', + or to 0 if the file is not found. */ + +static int +get_filename_and_charpos (s, fullname) + struct symtab *s; + char **fullname; +{ + register int desc, linenums_changed = 0; + + desc = open_source_file (s); + if (desc < 0) + { + if (fullname) + *fullname = NULL; + return 0; + } + if (fullname) + *fullname = s->fullname; + if (s->line_charpos == 0) linenums_changed = 1; + if (linenums_changed) find_source_lines (s, desc); + close (desc); + return linenums_changed; +} + +/* Print text describing the full name of the source file S + and the line number LINE and its corresponding character position. + The text starts with two Ctrl-z so that the Emacs-GDB interface + can easily find it. + + MID_STATEMENT is nonzero if the PC is not at the beginning of that line. + + Return 1 if successful, 0 if could not find the file. */ + +int +identify_source_line (s, line, mid_statement, pc) + struct symtab *s; + int line; + int mid_statement; + CORE_ADDR pc; +{ + if (s->line_charpos == 0) + get_filename_and_charpos (s, (char **)NULL); + if (s->fullname == 0) + return 0; + if (line > s->nlines) + /* Don't index off the end of the line_charpos array. */ + return 0; + annotate_source (s->fullname, line, s->line_charpos[line - 1], + mid_statement, pc); + + current_source_line = line; + first_line_listed = line; + last_line_listed = line; + current_source_symtab = s; + return 1; +} + +/* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ + +void +print_source_lines (s, line, stopline, noerror) + struct symtab *s; + int line, stopline; + int noerror; +{ + register int c; + register int desc; + register FILE *stream; + int nlines = stopline - line; + + /* Regardless of whether we can open the file, set current_source_symtab. */ + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + + desc = open_source_file (s); + if (desc < 0) + { + if (! noerror) { + char *name = alloca (strlen (s->filename) + 100); + sprintf (name, "%s:%d", s->filename, line); + print_sys_errmsg (name, errno); + } + return; + } + + if (s->line_charpos == 0) + find_source_lines (s, desc); + + if (line < 1 || line > s->nlines) + { + close (desc); + error ("Line number %d out of range; %s has %d lines.", + line, s->filename, s->nlines); + } + + if (lseek (desc, s->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (s->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + + while (nlines-- > 0) + { + c = fgetc (stream); + if (c == EOF) break; + last_line_listed = current_source_line; + printf_filtered ("%d\t", current_source_line++); + do + { + if (c < 040 && c != '\t' && c != '\n' && c != '\r') + printf_filtered ("^%c", c + 0100); + else if (c == 0177) + printf_filtered ("^?"); + else + printf_filtered ("%c", c); + } while (c != '\n' && (c = fgetc (stream)) >= 0); + } + + fclose (stream); +} + + + +/* Print a list of files and line numbers which a user may choose from + in order to list a function which was specified ambiguously (as with + `list classname::overloadedfuncname', for example). The vector in + SALS provides the filenames and line numbers. */ + +static void +ambiguous_line_spec (sals) + struct symtabs_and_lines *sals; +{ + int i; + + for (i = 0; i < sals->nelts; ++i) + printf_filtered("file: \"%s\", line number: %d\n", + sals->sals[i].symtab->filename, sals->sals[i].line); +} + +static void +list_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals, sals_end; + struct symtab_and_line sal, sal_end; + struct symbol *sym; + char *arg1; + int no_end = 1; + int dummy_end = 0; + int dummy_beg = 0; + int linenum_beg = 0; + char *p; + + if (!have_full_symbols () && !have_partial_symbols()) + error ("No symbol table is loaded. Use the \"file\" command."); + + /* Pull in a current source symtab if necessary */ + if (current_source_symtab == 0 && + (arg == 0 || arg[0] == '+' || arg[0] == '-')) + select_source_symtab (0); + + /* "l" or "l +" lists next ten lines. */ + + if (arg == 0 || STREQ (arg, "+")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, current_source_line, + current_source_line + lines_to_list, 0); + return; + } + + /* "l -" lists previous ten lines, the ones before the ten just listed. */ + if (STREQ (arg, "-")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, + max (first_line_listed - lines_to_list, 1), + first_line_listed, 0); + return; + } + + /* Now if there is only one argument, decode it in SAL + and set NO_END. + If there are two arguments, decode them in SAL and SAL_END + and clear NO_END; however, if one of the arguments is blank, + set DUMMY_BEG or DUMMY_END to record that fact. */ + + arg1 = arg; + if (*arg1 == ',') + dummy_beg = 1; + else + { + sals = decode_line_1 (&arg1, 0, 0, 0, 0); + + if (! sals.nelts) return; /* C++ */ + if (sals.nelts > 1) + { + ambiguous_line_spec (&sals); + free (sals.sals); + return; + } + + sal = sals.sals[0]; + free (sals.sals); + } + + /* Record whether the BEG arg is all digits. */ + + for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); + linenum_beg = (p == arg1); + + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == ',') + { + no_end = 0; + arg1++; + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == 0) + dummy_end = 1; + else + { + if (dummy_beg) + sals_end = decode_line_1 (&arg1, 0, 0, 0, 0); + else + sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0); + if (sals_end.nelts == 0) + return; + if (sals_end.nelts > 1) + { + ambiguous_line_spec (&sals_end); + free (sals_end.sals); + return; + } + sal_end = sals_end.sals[0]; + free (sals_end.sals); + } + } + + if (*arg1) + error ("Junk at end of line specification."); + + if (!no_end && !dummy_beg && !dummy_end + && sal.symtab != sal_end.symtab) + error ("Specified start and end are in different files."); + if (dummy_beg && dummy_end) + error ("Two empty args do not say what lines to list."); + + /* if line was specified by address, + first print exactly which line, and which file. + In this case, sal.symtab == 0 means address is outside + of all known source files, not that user failed to give a filename. */ + if (*arg == '*') + { + if (sal.symtab == 0) + /* FIXME-32x64--assumes sal.pc fits in long. */ + error ("No source file for address %s.", + local_hex_string((unsigned long) sal.pc)); + sym = find_pc_function (sal.pc); + if (sym) + { + print_address_numeric (sal.pc, 1, gdb_stdout); + printf_filtered (" is in "); + fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout); + printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line); + } + else + { + print_address_numeric (sal.pc, 1, gdb_stdout); + printf_filtered (" is at %s:%d.\n", + sal.symtab->filename, sal.line); + } + } + + /* If line was not specified by just a line number, + and it does not imply a symtab, it must be an undebuggable symbol + which means no source code. */ + + if (! linenum_beg && sal.symtab == 0) + error ("No line number known for %s.", arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + + if (dummy_beg && sal_end.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + if (dummy_beg) + print_source_lines (sal_end.symtab, + max (sal_end.line - (lines_to_list - 1), 1), + sal_end.line + 1, 0); + else if (sal.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + else if (no_end) + print_source_lines (sal.symtab, + max (sal.line - (lines_to_list / 2), 1), + sal.line + (lines_to_list / 2), 0); + else + print_source_lines (sal.symtab, sal.line, + (dummy_end + ? sal.line + lines_to_list + : sal_end.line + 1), + 0); +} + +/* Print info on range of pc's in a specified line. */ + +static void +line_info (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + CORE_ADDR start_pc, end_pc; + int i; + + if (arg == 0) + { + sal.symtab = current_source_symtab; + sal.line = last_line_listed; + sal.pc = 0; + sals.nelts = 1; + sals.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + sals.sals[0] = sal; + } + else + { + sals = decode_line_spec_1 (arg, 0); + + dont_repeat (); + } + + /* C++ More than one line may have been specified, as when the user + specifies an overloaded function name. Print info on them all. */ + for (i = 0; i < sals.nelts; i++) + { + sal = sals.sals[i]; + + if (sal.symtab == 0) + { + printf_filtered ("No line number information available"); + if (sal.pc != 0) + { + /* This is useful for "info line *0x7f34". If we can't tell the + user about a source line, at least let them have the symbolic + address. */ + printf_filtered (" for address "); + wrap_here (" "); + print_address (sal.pc, gdb_stdout); + } + else + printf_filtered ("."); + printf_filtered ("\n"); + } + else if (sal.line > 0 + && find_line_pc_range (sal, &start_pc, &end_pc)) + { + if (start_pc == end_pc) + { + printf_filtered ("Line %d of \"%s\"", + sal.line, sal.symtab->filename); + wrap_here (" "); + printf_filtered (" is at address "); + print_address (start_pc, gdb_stdout); + wrap_here (" "); + printf_filtered (" but contains no code.\n"); + } + else + { + printf_filtered ("Line %d of \"%s\"", + sal.line, sal.symtab->filename); + wrap_here (" "); + printf_filtered (" starts at address "); + print_address (start_pc, gdb_stdout); + wrap_here (" "); + printf_filtered (" and ends at "); + print_address (end_pc, gdb_stdout); + printf_filtered (".\n"); + } + + /* x/i should display this line's code. */ + set_next_address (start_pc); + + /* Repeating "info line" should do the following line. */ + last_line_listed = sal.line + 1; + + /* If this is the only line, show the source code. If it could + not find the file, don't do anything special. */ + if (annotation_level && sals.nelts == 1) + identify_source_line (sal.symtab, sal.line, 0, start_pc); + } + else + /* Is there any case in which we get here, and have an address + 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); + } + free (sals.sals); +} + +/* Commands to search the source file for a regexp. */ + +/* ARGSUSED */ +static void +forward_search_command (regex, from_tty) + char *regex; + int from_tty; +{ + register int c; + register int desc; + register FILE *stream; + int line = last_line_listed + 1; + char *msg; + + msg = (char *) re_comp (regex); + if (msg) + error (msg); + + if (current_source_symtab == 0) + select_source_symtab (0); + + /* Search from last_line_listed+1 in current_source_symtab */ + + desc = open_source_file (current_source_symtab); + if (desc < 0) + perror_with_name (current_source_symtab->filename); + + if (current_source_symtab->line_charpos == 0) + find_source_lines (current_source_symtab, desc); + + if (line < 1 || line > current_source_symtab->nlines) + { + close (desc); + error ("Expression not found"); + } + + if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (current_source_symtab->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + while (1) { + static char *buf = NULL; + register char *p; + int cursize, newsize; + + cursize = 256; + buf = xmalloc (cursize); + p = buf; + + c = getc (stream); + if (c == EOF) + break; + do { + *p++ = c; + if (p - buf == cursize) + { + newsize = cursize + cursize / 2; + buf = xrealloc (buf, newsize); + p = buf + cursize; + cursize = newsize; + } + } while (c != '\n' && (c = getc (stream)) >= 0); + + /* we now have a source line in buf, null terminate and match */ + *p = 0; + if (re_exec (buf) > 0) + { + /* Match! */ + fclose (stream); + print_source_lines (current_source_symtab, line, line+1, 0); + set_internalvar (lookup_internalvar ("_"), + value_from_longest (builtin_type_int, + (LONGEST) line)); + current_source_line = max (line - lines_to_list / 2, 1); + return; + } + line++; + } + + printf_filtered ("Expression not found\n"); + fclose (stream); +} + +/* ARGSUSED */ +static void +reverse_search_command (regex, from_tty) + char *regex; + int from_tty; +{ + register int c; + register int desc; + register FILE *stream; + int line = last_line_listed - 1; + char *msg; + + msg = (char *) re_comp (regex); + if (msg) + error (msg); + + if (current_source_symtab == 0) + select_source_symtab (0); + + /* Search from last_line_listed-1 in current_source_symtab */ + + desc = open_source_file (current_source_symtab); + if (desc < 0) + perror_with_name (current_source_symtab->filename); + + if (current_source_symtab->line_charpos == 0) + find_source_lines (current_source_symtab, desc); + + if (line < 1 || line > current_source_symtab->nlines) + { + close (desc); + error ("Expression not found"); + } + + if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (current_source_symtab->filename); + } + + stream = fdopen (desc, FOPEN_RT); + clearerr (stream); + while (line > 1) + { +/* FIXME!!! We walk right off the end of buf if we get a long line!!! */ + char buf[4096]; /* Should be reasonable??? */ + register char *p = buf; + + c = getc (stream); + if (c == EOF) + break; + do { + *p++ = c; + } while (c != '\n' && (c = getc (stream)) >= 0); + + /* We now have a source line in buf; null terminate and match. */ + *p = 0; + if (re_exec (buf) > 0) + { + /* Match! */ + fclose (stream); + print_source_lines (current_source_symtab, + line, line+1, 0); + set_internalvar (lookup_internalvar ("_"), + value_from_longest (builtin_type_int, + (LONGEST) line)); + current_source_line = max (line - lines_to_list / 2, 1); + return; + } + line--; + if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0) + { + fclose (stream); + perror_with_name (current_source_symtab->filename); + } + } + + printf_filtered ("Expression not found\n"); + fclose (stream); + return; +} + +void +_initialize_source () +{ + struct cmd_list_element *c; + current_source_symtab = 0; + init_source_path (); + + /* The intention is to use POSIX Basic Regular Expressions. + Always use the GNU regex routine for consistency across all hosts. + Our current GNU regex.c does not have all the POSIX features, so this is + just an approximation. */ + re_set_syntax (RE_SYNTAX_GREP); + + c = add_cmd ("directory", class_files, directory_command, + "Add directory DIR to beginning of search path for source files.\n\ +Forget cached info on source file locations and line positions.\n\ +DIR can also be $cwd for the current working directory, or $cdir for the\n\ +directory in which the source file was compiled into object code.\n\ +With no argument, reset the search path to $cdir:$cwd, the default.", + &cmdlist); + c->completer = filename_completer; + + add_cmd ("directories", no_class, show_directories, + "Current search path for finding source files.\n\ +$cwd in the path means the current working directory.\n\ +$cdir in the path means the compilation directory of the source file.", + &showlist); + + add_info ("source", source_info, + "Information about the current source file."); + + add_info ("line", line_info, + concat ("Core addresses of the code for a source line.\n\ +Line can be specified as\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ +", "\ +Default is to describe the last source line that was listed.\n\n\ +This sets the default address for \"x\" to the line's first instruction\n\ +so that \"x/i\" suffices to start examining the machine code.\n\ +The address is also stored as the value of \"$_\".", NULL)); + + add_com ("forward-search", class_files, forward_search_command, + "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 ("reverse-search", class_files, reverse_search_command, + "Search backward for regular expression (see regex(3)) from last line listed.\n\ +The matching line number is also stored as the value of \"$_\"."); + + add_com ("list", class_files, list_command, + concat ("List specified function or line.\n\ +With no argument, lists ten more lines after or around previous listing.\n\ +\"list -\" lists the ten lines before a previous ten-line listing.\n\ +One argument specifies a line, and ten lines are listed around that line.\n\ +Two arguments with comma between specify starting and ending lines to list.\n\ +", "\ +Lines can be specified in these ways:\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to list around the line containing that address.\n\ +With two args if one is empty it stands for ten lines away from the other arg.", NULL)); + + add_com_alias ("l", "list", class_files, 1); + + add_show_from_set + (add_set_cmd ("listsize", class_support, var_uinteger, + (char *)&lines_to_list, + "Set number of source lines gdb will list by default.", + &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/srec.h b/contrib/gdb/gdb/srec.h new file mode 100644 index 000000000000..1446bda3f174 --- /dev/null +++ b/contrib/gdb/gdb/srec.h @@ -0,0 +1,35 @@ +/* S-record download support for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +void load_srec PARAMS ((serial_t desc, const char *file, int maxrecsize, + int flags, int hashmark)); + +/* S-record capability flags */ + +/* Which record types are supported */ +#define SREC_2_BYTE_ADDR 0x00000001 +#define SREC_3_BYTE_ADDR 0x00000002 +#define SREC_4_BYTE_ADDR 0x00000004 +#define SREC_TERM_SHIFT 3 + +#define SREC_ALL (SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR \ + | ((SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR) \ + << SREC_TERM_SHIFT)) + +#define SREC_BINARY 0x00000040 /* Supports binary form of S-records */ diff --git a/contrib/gdb/gdb/stabsread.c b/contrib/gdb/gdb/stabsread.c new file mode 100644 index 000000000000..80fbd77e3f63 --- /dev/null +++ b/contrib/gdb/gdb/stabsread.c @@ -0,0 +1,4017 @@ +/* Support routines for decoding "stabs" debugging information format. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Support routines for reading and decoding debugging information in + the "stabs" format. This format is used with many systems that use + the a.out object file format, as well as some systems that use + COFF or ELF where the stabs data is placed in a special section. + Avoid placing any object file format specific code in this file. */ + +#include "defs.h" +#include "gdb_string.h" +#include "bfd.h" +#include "obstack.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "symfile.h" +#include "objfiles.h" +#include "aout/stab_gnu.h" /* We always use GNU stabs, not native */ +#include "libaout.h" +#include "aout/aout64.h" +#include "gdb-stabs.h" +#include "buildsym.h" +#include "complaints.h" +#include "demangle.h" +#include "language.h" + +#include + +/* Ask stabsread.h to define the vars it normally declares `extern'. */ +#define EXTERN /**/ +#include "stabsread.h" /* Our own declarations */ +#undef EXTERN + +/* The routines that read and process a complete stabs for a C struct or + C++ class pass lists of data member fields and lists of member function + fields in an instance of a field_info structure, as defined below. + This is part of some reorganization of low level C++ support and is + expected to eventually go away... (FIXME) */ + +struct field_info +{ + struct nextfield + { + struct nextfield *next; + + /* This is the raw visibility from the stab. It is not checked + for being one of the visibilities we recognize, so code which + examines this field better be able to deal. */ + int visibility; + + struct field field; + } *list; + struct next_fnfieldlist + { + struct next_fnfieldlist *next; + struct fn_fieldlist fn_fieldlist; + } *fnlist; +}; + +static struct type * +dbx_alloc_type PARAMS ((int [2], struct objfile *)); + +static long read_huge_number PARAMS ((char **, int, int *)); + +static struct type *error_type PARAMS ((char **, struct objfile *)); + +static void +patch_block_stabs PARAMS ((struct pending *, struct pending_stabs *, + struct objfile *)); + +static void +fix_common_block PARAMS ((struct symbol *, int)); + +static int +read_type_number PARAMS ((char **, int *)); + +static struct type * +read_range_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_sun_builtin_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_sun_floating_type PARAMS ((char **, int [2], struct objfile *)); + +static struct type * +read_enum_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type * +rs6000_builtin_type PARAMS ((int)); + +static int +read_member_functions PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_struct_fields PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_baseclasses PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +read_tilde_fields PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static int +attach_fn_fields_to_type PARAMS ((struct field_info *, struct type *)); + +static int +attach_fields_to_type PARAMS ((struct field_info *, struct type *, + struct objfile *)); + +static struct type * +read_struct_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type * +read_array_type PARAMS ((char **, struct type *, struct objfile *)); + +static struct type ** +read_args PARAMS ((char **, int, struct objfile *)); + +static int +read_cpp_abbrev PARAMS ((struct field_info *, char **, struct type *, + struct objfile *)); + +static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER,'\0' }; +static const char vb_name[] = { '_','v','b',CPLUS_MARKER,'\0' }; + +/* Define this as 1 if a pcc declaration of a char or short argument + gives the correct address. Otherwise assume pcc gives the + address of the corresponding int, which is not the same on a + big-endian machine. */ + +#ifndef BELIEVE_PCC_PROMOTION +#define BELIEVE_PCC_PROMOTION 0 +#endif + +struct complaint invalid_cpp_abbrev_complaint = + {"invalid C++ abbreviation `%s'", 0, 0}; + +struct complaint invalid_cpp_type_complaint = + {"C++ abbreviated type name unknown at symtab pos %d", 0, 0}; + +struct complaint member_fn_complaint = + {"member function type missing, got '%c'", 0, 0}; + +struct complaint const_vol_complaint = + {"const/volatile indicator missing, got '%c'", 0, 0}; + +struct complaint error_type_complaint = + {"debug info mismatch between compiler and debugger", 0, 0}; + +struct complaint invalid_member_complaint = + {"invalid (minimal) member type data format at symtab pos %d.", 0, 0}; + +struct complaint range_type_base_complaint = + {"base type %d of range type is not defined", 0, 0}; + +struct complaint reg_value_complaint = + {"register number %d too large (max %d) in symbol %s", 0, 0}; + +struct complaint vtbl_notfound_complaint = + {"virtual function table pointer not found when defining class `%s'", 0, 0}; + +struct complaint unrecognized_cplus_name_complaint = + {"Unknown C++ symbol name `%s'", 0, 0}; + +struct complaint rs6000_builtin_complaint = + {"Unknown builtin type %d", 0, 0}; + +struct complaint unresolved_sym_chain_complaint = + {"%s: common block `%s' from global_sym_chain unresolved", 0, 0}; + +struct complaint stabs_general_complaint = + {"%s", 0, 0}; + +/* Make a list of forward references which haven't been defined. */ + +static struct type **undef_types; +static int undef_types_allocated; +static int undef_types_length; +static struct symbol *current_symbol = NULL; + +/* Check for and handle cretinous stabs symbol name continuation! */ +#define STABS_CONTINUE(pp,objfile) \ + do { \ + if (**(pp) == '\\' || (**(pp) == '?' && (*(pp))[1] == '\0')) \ + *(pp) = next_symbol_text (objfile); \ + } while (0) + +/* FIXME: These probably should be our own types (like rs6000_builtin_type + has its own types) rather than builtin_type_*. */ +static struct type **os9k_type_vector[] = { + 0, + &builtin_type_int, + &builtin_type_char, + &builtin_type_long, + &builtin_type_short, + &builtin_type_unsigned_char, + &builtin_type_unsigned_short, + &builtin_type_unsigned_long, + &builtin_type_unsigned_int, + &builtin_type_float, + &builtin_type_double, + &builtin_type_void, + &builtin_type_long_double +}; + +static void os9k_init_type_vector PARAMS ((struct type **)); + +static void +os9k_init_type_vector(tv) + struct type **tv; +{ + int i; + for (i=0; i= n_this_object_header_files) + { + static struct complaint msg = {"\ +Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.", + 0, 0}; + complain (&msg, filenum, index, symnum); + goto error_return; + } + + if (filenum == 0) + { + if (index < 0) + { + /* Caller wants address of address of type. We think + that negative (rs6k builtin) types will never appear as + "lvalues", (nor should they), so we stuff the real type + pointer into a temp, and return its address. If referenced, + this will do the right thing. */ + static struct type *temp_type; + + temp_type = rs6000_builtin_type(index); + return &temp_type; + } + + /* Type is defined outside of header files. + Find it in this object file's type vector. */ + if (index >= type_vector_length) + { + old_len = type_vector_length; + if (old_len == 0) + { + type_vector_length = INITIAL_TYPE_VECTOR_LENGTH; + type_vector = (struct type **) + xmalloc (type_vector_length * sizeof (struct type *)); + } + while (index >= type_vector_length) + { + type_vector_length *= 2; + } + type_vector = (struct type **) + xrealloc ((char *) type_vector, + (type_vector_length * sizeof (struct type *))); + memset (&type_vector[old_len], 0, + (type_vector_length - old_len) * sizeof (struct type *)); + + if (os9k_stabs) + /* Deal with OS9000 fundamental types. */ + os9k_init_type_vector (type_vector); + } + return (&type_vector[index]); + } + else + { + real_filenum = this_object_header_files[filenum]; + + if (real_filenum >= n_header_files) + { + struct type *temp_type; + struct type **temp_type_p; + + warning ("GDB internal error: bad real_filenum"); + + error_return: + temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL); + temp_type_p = (struct type **) xmalloc (sizeof (struct type *)); + *temp_type_p = temp_type; + return temp_type_p; + } + + f = &header_files[real_filenum]; + + f_orig_length = f->length; + if (index >= f_orig_length) + { + while (index >= f->length) + { + f->length *= 2; + } + f->vector = (struct type **) + xrealloc ((char *) f->vector, f->length * sizeof (struct type *)); + memset (&f->vector[f_orig_length], 0, + (f->length - f_orig_length) * sizeof (struct type *)); + } + return (&f->vector[index]); + } +} + +/* Make sure there is a type allocated for type numbers TYPENUMS + and return the type object. + This can create an empty (zeroed) type object. + TYPENUMS may be (-1, -1) to return a new type object that is not + put into the type vector, and so may not be referred to by number. */ + +static struct type * +dbx_alloc_type (typenums, objfile) + int typenums[2]; + struct objfile *objfile; +{ + register struct type **type_addr; + + if (typenums[0] == -1) + { + return (alloc_type (objfile)); + } + + type_addr = dbx_lookup_type (typenums); + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (*type_addr == 0) + { + *type_addr = alloc_type (objfile); + } + + return (*type_addr); +} + +/* for all the stabs in a given stab vector, build appropriate types + and fix their symbols in given symbol vector. */ + +static void +patch_block_stabs (symbols, stabs, objfile) + struct pending *symbols; + struct pending_stabs *stabs; + struct objfile *objfile; +{ + int ii; + char *name; + char *pp; + struct symbol *sym; + + if (stabs) + { + + /* for all the stab entries, find their corresponding symbols and + patch their types! */ + + for (ii = 0; ii < stabs->count; ++ii) + { + name = stabs->stab[ii]; + pp = (char*) strchr (name, ':'); + while (pp[1] == ':') + { + pp += 2; + pp = (char *)strchr(pp, ':'); + } + sym = find_symbol_in_list (symbols, name, pp-name); + if (!sym) + { + /* FIXME-maybe: it would be nice if we noticed whether + the variable was defined *anywhere*, not just whether + it is defined in this compilation unit. But neither + xlc or GCC seem to need such a definition, and until + we do psymtabs (so that the minimal symbols from all + compilation units are available now), I'm not sure + how to get the information. */ + + /* On xcoff, if a global is defined and never referenced, + ld will remove it from the executable. There is then + a N_GSYM stab for it, but no regular (C_EXT) symbol. */ + sym = (struct symbol *) + obstack_alloc (&objfile->symbol_obstack, + sizeof (struct symbol)); + + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + SYMBOL_NAME (sym) = + obstack_copy0 (&objfile->symbol_obstack, name, pp - name); + pp += 2; + if (*(pp-1) == 'F' || *(pp-1) == 'f') + { + /* I don't think the linker does this with functions, + so as far as I know this is never executed. + But it doesn't hurt to check. */ + SYMBOL_TYPE (sym) = + lookup_function_type (read_type (&pp, objfile)); + } + else + { + SYMBOL_TYPE (sym) = read_type (&pp, objfile); + } + add_symbol_to_list (sym, &global_symbols); + } + else + { + pp += 2; + if (*(pp-1) == 'F' || *(pp-1) == 'f') + { + SYMBOL_TYPE (sym) = + lookup_function_type (read_type (&pp, objfile)); + } + else + { + SYMBOL_TYPE (sym) = read_type (&pp, objfile); + } + } + } + } +} + + +/* Read a number by which a type is referred to in dbx data, + or perhaps read a pair (FILENUM, TYPENUM) in parentheses. + Just a single number N is equivalent to (0,N). + Return the two numbers by storing them in the vector TYPENUMS. + TYPENUMS will then be used as an argument to dbx_lookup_type. + + Returns 0 for success, -1 for error. */ + +static int +read_type_number (pp, typenums) + register char **pp; + register int *typenums; +{ + int nbits; + if (**pp == '(') + { + (*pp)++; + typenums[0] = read_huge_number (pp, ',', &nbits); + if (nbits != 0) return -1; + typenums[1] = read_huge_number (pp, ')', &nbits); + if (nbits != 0) return -1; + } + else + { + typenums[0] = 0; + typenums[1] = read_huge_number (pp, 0, &nbits); + if (nbits != 0) return -1; + } + return 0; +} + + +#if !defined (REG_STRUCT_HAS_ADDR) +#define REG_STRUCT_HAS_ADDR(gcc_p,type) 0 +#endif + +/* ARGSUSED */ +struct symbol * +define_symbol (valu, string, desc, type, objfile) + CORE_ADDR valu; + char *string; + int desc; + int type; + struct objfile *objfile; +{ + register struct symbol *sym; + char *p = (char *) strchr (string, ':'); + int deftype; + int synonym = 0; + register int i; + + /* We would like to eliminate nameless symbols, but keep their types. + E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer + to type 2, but, should not create a symbol to address that type. Since + the symbol will be nameless, there is no way any user can refer to it. */ + + int nameless; + + /* Ignore syms with empty names. */ + if (string[0] == 0) + return 0; + + /* Ignore old-style symbols from cc -go */ + if (p == 0) + return 0; + + while (p[1] == ':') + { + p += 2; + p = strchr(p, ':'); + } + + /* If a nameless stab entry, all we need is the type, not the symbol. + e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */ + nameless = (p == string || ((string[0] == ' ') && (string[1] == ':'))); + + current_symbol = sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + + switch (type & N_TYPE) + { + case N_TEXT: + SYMBOL_SECTION(sym) = SECT_OFF_TEXT; + break; + case N_DATA: + SYMBOL_SECTION(sym) = SECT_OFF_DATA; + break; + case N_BSS: + SYMBOL_SECTION(sym) = SECT_OFF_BSS; + break; + } + + if (processing_gcc_compilation) + { + /* GCC 2.x puts the line number in desc. SunOS apparently puts in the + number of bytes occupied by a type or object, which we ignore. */ + SYMBOL_LINE(sym) = desc; + } + else + { + SYMBOL_LINE(sym) = 0; /* unknown */ + } + + if (is_cplus_marker (string[0])) + { + /* Special GNU C++ names. */ + switch (string[1]) + { + case 't': + SYMBOL_NAME (sym) = obsavestring ("this", strlen ("this"), + &objfile -> symbol_obstack); + break; + + case 'v': /* $vtbl_ptr_type */ + /* Was: SYMBOL_NAME (sym) = "vptr"; */ + goto normal; + + case 'e': + SYMBOL_NAME (sym) = obsavestring ("eh_throw", strlen ("eh_throw"), + &objfile -> symbol_obstack); + break; + + case '_': + /* This was an anonymous type that was never fixed up. */ + goto normal; + +#ifdef STATIC_TRANSFORM_NAME + case 'X': + /* SunPRO (3.0 at least) static variable encoding. */ + goto normal; +#endif + + default: + complain (&unrecognized_cplus_name_complaint, string); + goto normal; /* Do *something* with it */ + } + } + else + { + normal: + SYMBOL_LANGUAGE (sym) = current_subfile -> language; + SYMBOL_NAME (sym) = (char *) + obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1)); + /* Open-coded memcpy--saves function call time. */ + /* FIXME: Does it really? Try replacing with simple strcpy and + try it on an executable with a large symbol table. */ + /* FIXME: considering that gcc can open code memcpy anyway, I + doubt it. xoxorich. */ + { + register char *p1 = string; + register char *p2 = SYMBOL_NAME (sym); + while (p1 != p) + { + *p2++ = *p1++; + } + *p2++ = '\0'; + } + + /* If this symbol is from a C++ compilation, then attempt to cache the + demangled form for future reference. This is a typical time versus + space tradeoff, that was decided in favor of time because it sped up + C++ symbol lookups by a factor of about 20. */ + + SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack); + } + p++; + + /* Determine the type of name being defined. */ +#if 0 + /* Getting GDB to correctly skip the symbol on an undefined symbol + descriptor and not ever dump core is a very dodgy proposition if + we do things this way. I say the acorn RISC machine can just + fix their compiler. */ + /* The Acorn RISC machine's compiler can put out locals that don't + start with "234=" or "(3,4)=", so assume anything other than the + deftypes we know how to handle is a local. */ + if (!strchr ("cfFGpPrStTvVXCR", *p)) +#else + if (isdigit (*p) || *p == '(' || *p == '-') +#endif + deftype = 'l'; + else + deftype = *p++; + + switch (deftype) + { + case 'c': + /* c is a special case, not followed by a type-number. + SYMBOL:c=iVALUE for an integer constant symbol. + SYMBOL:c=rVALUE for a floating constant symbol. + SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + if (*p != '=') + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = error_type (&p, objfile); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + return sym; + } + ++p; + switch (*p++) + { + case 'r': + { + double d = atof (p); + char *dbl_valu; + + /* FIXME-if-picky-about-floating-accuracy: Should be using + target arithmetic to get the value. real.c in GCC + probably has the necessary code. */ + + /* FIXME: lookup_fundamental_type is a hack. We should be + creating a type especially for the type of float constants. + Problem is, what type should it be? + + Also, what should the name of this type be? Should we + be using 'S' constants (see stabs.texinfo) instead? */ + + SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile, + FT_DBL_PREC_FLOAT); + dbl_valu = (char *) + obstack_alloc (&objfile -> symbol_obstack, + TYPE_LENGTH (SYMBOL_TYPE (sym))); + store_floating (dbl_valu, TYPE_LENGTH (SYMBOL_TYPE (sym)), d); + SYMBOL_VALUE_BYTES (sym) = dbl_valu; + SYMBOL_CLASS (sym) = LOC_CONST_BYTES; + } + break; + case 'i': + { + /* Defining integer constants this way is kind of silly, + since 'e' constants allows the compiler to give not + only the value, but the type as well. C has at least + int, long, unsigned int, and long long as constant + types; other languages probably should have at least + unsigned as well as signed constants. */ + + /* We just need one int constant type for all objfiles. + It doesn't depend on languages or anything (arguably its + name should be a language-specific name for a type of + that size, but I'm inclined to say that if the compiler + wants a nice name for the type, it can use 'e'). */ + static struct type *int_const_type; + + /* Yes, this is as long as a *host* int. That is because we + use atoi. */ + if (int_const_type == NULL) + int_const_type = + init_type (TYPE_CODE_INT, + sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0, + "integer constant", + (struct objfile *)NULL); + SYMBOL_TYPE (sym) = int_const_type; + SYMBOL_VALUE (sym) = atoi (p); + SYMBOL_CLASS (sym) = LOC_CONST; + } + break; + case 'e': + /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value + can be represented as integral. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + if (*p != ',') + { + SYMBOL_TYPE (sym) = error_type (&p, objfile); + break; + } + ++p; + + /* If the value is too big to fit in an int (perhaps because + it is unsigned), or something like that, we silently get + a bogus value. The type and everything else about it is + correct. Ideally, we should be using whatever we have + available for parsing unsigned and long long values, + however. */ + SYMBOL_VALUE (sym) = atoi (p); + } + break; + default: + { + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = error_type (&p, objfile); + } + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + return sym; + + case 'C': + /* The name of a caught exception. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LABEL; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE_ADDRESS (sym) = valu; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'f': + /* A static function definition. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + /* fall into process_function_types. */ + + process_function_types: + /* Function result types are described as the result type in stabs. + We need to convert this to the function-returning-type-X type + in GDB. E.g. "int" is converted to "function returning int". */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC) + SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym)); + /* fall into process_prototype_types */ + + process_prototype_types: + /* Sun acc puts declared types of arguments here. We don't care + about their actual types (FIXME -- we should remember the whole + function prototype), but the list may define some new types + that we have to remember, so we must scan it now. */ + while (*p == ';') { + p++; + read_type (&p, objfile); + } + break; + + case 'F': + /* A global function definition. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + goto process_function_types; + + case 'G': + /* For a class G (global) symbol, it appears that the + value is not correct. It is necessary to search for the + corresponding linker definition to find the value. + These definitions appear at the end of the namelist. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + i = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i]; + global_sym_chain[i] = sym; + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + break; + + /* This case is faked by a conditional above, + when there is no code letter in the dbx data. + Dbx data never actually contains 'l'. */ + case 's': + case 'l': + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LOCAL; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'p': + if (*p == 'F') + /* pF is a two-letter code that means a function parameter in Fortran. + The type-number specifies the type of the return value. + Translate it into a pointer-to-function type. */ + { + p++; + SYMBOL_TYPE (sym) + = lookup_pointer_type + (lookup_function_type (read_type (&p, objfile))); + } + else + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* Normally this is a parameter, a LOC_ARG. On the i960, it + can also be a LOC_LOCAL_ARG depending on symbol type. */ +#ifndef DBX_PARM_SYMBOL_CLASS +#define DBX_PARM_SYMBOL_CLASS(type) LOC_ARG +#endif + + SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type); + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + + if (TARGET_BYTE_ORDER != BIG_ENDIAN) + { + /* On little-endian machines, this crud is never necessary, + and, if the extra bytes contain garbage, is harmful. */ + break; + } + + /* If it's gcc-compiled, if it says `short', believe it. */ + if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION) + break; + +#if !BELIEVE_PCC_PROMOTION + { + /* This is the signed type which arguments get promoted to. */ + static struct type *pcc_promotion_type; + /* This is the unsigned type which arguments get promoted to. */ + static struct type *pcc_unsigned_promotion_type; + + /* Call it "int" because this is mainly C lossage. */ + if (pcc_promotion_type == NULL) + pcc_promotion_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "int", NULL); + + if (pcc_unsigned_promotion_type == NULL) + pcc_unsigned_promotion_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", NULL); + +#if defined(BELIEVE_PCC_PROMOTION_TYPE) + /* This macro is defined on machines (e.g. sparc) where + we should believe the type of a PCC 'short' argument, + but shouldn't believe the address (the address is + the address of the corresponding int). + + My guess is that this correction, as opposed to changing + the parameter to an 'int' (as done below, for PCC + on most machines), is the right thing to do + on all machines, but I don't want to risk breaking + something that already works. On most PCC machines, + the sparc problem doesn't come up because the calling + function has to zero the top bytes (not knowing whether + the called function wants an int or a short), so there + is little practical difference between an int and a short + (except perhaps what happens when the GDB user types + "print short_arg = 0x10000;"). + + Hacked for SunOS 4.1 by gnu@cygnus.com. In 4.1, the compiler + actually produces the correct address (we don't need to fix it + up). I made this code adapt so that it will offset the symbol + if it was pointing at an int-aligned location and not + otherwise. This way you can use the same gdb for 4.0.x and + 4.1 systems. + + If the parameter is shorter than an int, and is integral + (e.g. char, short, or unsigned equivalent), and is claimed to + be passed on an integer boundary, don't believe it! Offset the + parameter's address to the tail-end of that integer. */ + + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT + && 0 == SYMBOL_VALUE (sym) % TYPE_LENGTH (pcc_promotion_type)) + { + SYMBOL_VALUE (sym) += TYPE_LENGTH (pcc_promotion_type) + - TYPE_LENGTH (SYMBOL_TYPE (sym)); + } + break; + +#else /* no BELIEVE_PCC_PROMOTION_TYPE. */ + + /* If PCC says a parameter is a short or a char, + it is really an int. */ + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) < TYPE_LENGTH (pcc_promotion_type) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_INT) + { + SYMBOL_TYPE (sym) = + TYPE_UNSIGNED (SYMBOL_TYPE (sym)) + ? pcc_unsigned_promotion_type + : pcc_promotion_type; + } + break; + +#endif /* no BELIEVE_PCC_PROMOTION_TYPE. */ + } +#endif /* !BELIEVE_PCC_PROMOTION. */ + + case 'P': + /* acc seems to use P to declare the prototypes of functions that + are referenced by this file. gdb is not prepared to deal + with this extra information. FIXME, it ought to. */ + if (type == N_FUN) + { + SYMBOL_TYPE (sym) = read_type (&p, objfile); + goto process_prototype_types; + } + /*FALLTHROUGH*/ + + case 'R': + /* Parameter which is in a register. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REGPARM; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu); + if (SYMBOL_VALUE (sym) >= NUM_REGS) + { + complain (®_value_complaint, SYMBOL_VALUE (sym), NUM_REGS, + SYMBOL_SOURCE_NAME (sym)); + SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */ + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'r': + /* Register variable (either global or local). */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu); + if (SYMBOL_VALUE (sym) >= NUM_REGS) + { + complain (®_value_complaint, SYMBOL_VALUE (sym), NUM_REGS, + SYMBOL_SOURCE_NAME (sym)); + SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */ + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + if (within_function) + { + /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same + name to represent an argument passed in a register. + GCC uses 'P' for the same case. So if we find such a symbol pair + we combine it into one 'P' symbol. For Sun cc we need to do this + regardless of REG_STRUCT_HAS_ADDR, because the compiler puts out + the 'p' symbol even if it never saves the argument onto the stack. + + On most machines, we want to preserve both symbols, so that + we can still get information about what is going on with the + stack (VAX for computing args_printed, using stack slots instead + of saved registers in backtraces, etc.). + + Note that this code illegally combines + main(argc) struct foo argc; { register struct foo argc; } + but this case is considered pathological and causes a warning + from a decent compiler. */ + + if (local_symbols + && local_symbols->nsyms > 0 +#ifndef USE_REGISTER_NOT_ARG + && REG_STRUCT_HAS_ADDR (processing_gcc_compilation, + SYMBOL_TYPE (sym)) + && (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_SET + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_BITSTRING) +#endif + ) + { + struct symbol *prev_sym; + prev_sym = local_symbols->symbol[local_symbols->nsyms - 1]; + if ((SYMBOL_CLASS (prev_sym) == LOC_REF_ARG + || SYMBOL_CLASS (prev_sym) == LOC_ARG) + && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym))) + { + SYMBOL_CLASS (prev_sym) = LOC_REGPARM; + /* Use the type from the LOC_REGISTER; that is the type + that is actually in that register. */ + SYMBOL_TYPE (prev_sym) = SYMBOL_TYPE (sym); + SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym); + sym = prev_sym; + break; + } + } + add_symbol_to_list (sym, &local_symbols); + } + else + add_symbol_to_list (sym, &file_symbols); + break; + + case 'S': + /* Static symbol at top level of file */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = valu; +#ifdef STATIC_TRANSFORM_NAME + if (SYMBOL_NAME (sym)[0] == '$') + { + struct minimal_symbol *msym; + msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, objfile); + if (msym != NULL) + { + SYMBOL_NAME (sym) = STATIC_TRANSFORM_NAME (SYMBOL_NAME (sym)); + SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msym); + } + } +#endif + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + + case 't': + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* For a nameless type, we don't want a create a symbol, thus we + did not use `sym'. Return without further processing. */ + if (nameless) return NULL; + + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + /* C++ vagaries: we may have a type which is derived from + a base type which did not have its name defined when the + derived class was output. We fill in the derived class's + base part member's name here in that case. */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) != NULL) + if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION) + && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym))) + { + int j; + for (j = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; j >= 0; j--) + if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) == 0) + TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), j) = + type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), j)); + } + + if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL) + { + /* gcc-2.6 or later (when using -fvtable-thunks) + emits a unique named type for a vtable entry. + Some gdb code depends on that specific name. */ + extern const char vtbl_ptr_name[]; + + if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR + && strcmp (SYMBOL_NAME (sym), vtbl_ptr_name)) + || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; PCC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type number + defined in the 't' symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + } + else + TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym); + } + + add_symbol_to_list (sym, &file_symbols); + break; + + case 'T': + /* Struct, union, or enum tag. For GNU C++, this can be be followed + by 't' which means we are typedef'ing it as well. */ + synonym = *p == 't'; + + if (synonym) + p++; + /* The semantics of C++ state that "struct foo { ... }" also defines + a typedef for "foo". Unfortunately, cfront never makes the typedef + when translating C++ into C. We make the typedef here so that + "ptype foo" works as expected for cfront translated code. */ + else if (current_subfile->language == language_cplus) + synonym = 1; + + SYMBOL_TYPE (sym) = read_type (&p, objfile); + + /* For a nameless type, we don't want a create a symbol, thus we + did not use `sym'. Return without further processing. */ + if (nameless) return NULL; + + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_TAG_NAME (SYMBOL_TYPE (sym)) + = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym)); + add_symbol_to_list (sym, &file_symbols); + + if (synonym) + { + /* Clone the sym and then modify it. */ + register struct symbol *typedef_sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + *typedef_sym = *sym; + SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF; + SYMBOL_VALUE (typedef_sym) = valu; + SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym)); + add_symbol_to_list (typedef_sym, &file_symbols); + } + break; + + case 'V': + /* Static symbol of local scope */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE_ADDRESS (sym) = valu; +#ifdef STATIC_TRANSFORM_NAME + if (SYMBOL_NAME (sym)[0] == '$') + { + struct minimal_symbol *msym; + msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, objfile); + if (msym != NULL) + { + SYMBOL_NAME (sym) = STATIC_TRANSFORM_NAME (SYMBOL_NAME (sym)); + SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msym); + } + } +#endif + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + if (os9k_stabs) + add_symbol_to_list (sym, &global_symbols); + else + add_symbol_to_list (sym, &local_symbols); + break; + + case 'v': + /* Reference parameter */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REF_ARG; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'a': + /* Reference parameter which is in a register. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu); + if (SYMBOL_VALUE (sym) >= NUM_REGS) + { + complain (®_value_complaint, SYMBOL_VALUE (sym), NUM_REGS, + SYMBOL_SOURCE_NAME (sym)); + SYMBOL_VALUE (sym) = SP_REGNUM; /* Known safe, though useless */ + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'X': + /* This is used by Sun FORTRAN for "function result value". + Sun claims ("dbx and dbxtool interfaces", 2nd ed) + that Pascal uses it too, but when I tried it Pascal used + "x:3" (local symbol) instead. */ + SYMBOL_TYPE (sym) = read_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_LOCAL; + SYMBOL_VALUE (sym) = valu; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + default: + SYMBOL_TYPE (sym) = error_type (&p, objfile); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_VALUE (sym) = 0; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + } + + /* When passing structures to a function, some systems sometimes pass + the address in a register, not the structure itself. */ + + if (REG_STRUCT_HAS_ADDR (processing_gcc_compilation, + SYMBOL_TYPE (sym)) + && ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT) + || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION) + || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_BITSTRING) + || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_SET))) + { + /* If REG_STRUCT_HAS_ADDR yields non-zero we have to + convert LOC_REGPARM to LOC_REGPARM_ADDR for structures and unions. */ + if (SYMBOL_CLASS (sym) == LOC_REGPARM) + SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR; + /* Likewise for converting LOC_ARG to LOC_REF_ARG (for the 7th and + subsequent arguments on the sparc, for example). */ + else if (SYMBOL_CLASS (sym) == LOC_ARG) + SYMBOL_CLASS (sym) = LOC_REF_ARG; + } + + return sym; +} + + +/* Skip rest of this symbol and return an error type. + + General notes on error recovery: error_type always skips to the + end of the symbol (modulo cretinous dbx symbol name continuation). + Thus code like this: + + if (*(*pp)++ != ';') + return error_type (pp, objfile); + + is wrong because if *pp starts out pointing at '\0' (typically as the + result of an earlier error), it will be incremented to point to the + start of the next symbol, which might produce strange results, at least + if you run off the end of the string table. Instead use + + if (**pp != ';') + return error_type (pp, objfile); + ++*pp; + + or + + if (**pp != ';') + foo = error_type (pp, objfile); + else + ++*pp; + + And in case it isn't obvious, the point of all this hair is so the compiler + can define new types and new syntaxes, and old versions of the + debugger will be able to read the new symbol tables. */ + +static struct type * +error_type (pp, objfile) + char **pp; + struct objfile *objfile; +{ + complain (&error_type_complaint); + while (1) + { + /* Skip to end of symbol. */ + while (**pp != '\0') + { + (*pp)++; + } + + /* Check for and handle cretinous dbx symbol name continuation! */ + if ((*pp)[-1] == '\\' || (*pp)[-1] == '?') + { + *pp = next_symbol_text (objfile); + } + else + { + break; + } + } + return (builtin_type_error); +} + + +/* Read type information or a type definition; return the type. Even + though this routine accepts either type information or a type + definition, the distinction is relevant--some parts of stabsread.c + assume that type information starts with a digit, '-', or '(' in + deciding whether to call read_type. */ + +struct type * +read_type (pp, objfile) + register char **pp; + struct objfile *objfile; +{ + register struct type *type = 0; + struct type *type1; + int typenums[2]; + int xtypenums[2]; + char type_descriptor; + + /* Size in bits of type if specified by a type attribute, or -1 if + there is no size attribute. */ + int type_size = -1; + + /* Used to distinguish string and bitstring from char-array and set. */ + int is_string = 0; + + /* Read type number if present. The type number may be omitted. + for instance in a two-dimensional array declared with type + "ar1;1;10;ar1;1;10;4". */ + if ((**pp >= '0' && **pp <= '9') + || **pp == '(' + || **pp == '-') + { + if (read_type_number (pp, typenums) != 0) + return error_type (pp, objfile); + + /* Type is not being defined here. Either it already exists, + or this is a forward reference to it. dbx_alloc_type handles + both cases. */ + if (**pp != '=') + return dbx_alloc_type (typenums, objfile); + + /* Type is being defined here. */ + /* Skip the '='. */ + ++(*pp); + + while (**pp == '@') + { + char *p = *pp + 1; + /* It might be a type attribute or a member type. */ + if (isdigit (*p) || *p == '(' || *p == '-') + /* Member type. */ + break; + else + { + /* Type attributes. */ + char *attr = p; + + /* Skip to the semicolon. */ + while (*p != ';' && *p != '\0') + ++p; + *pp = p; + if (*p == '\0') + return error_type (pp, objfile); + else + /* Skip the semicolon. */ + ++*pp; + + switch (*attr) + { + case 's': + type_size = atoi (attr + 1); + if (type_size <= 0) + type_size = -1; + break; + + case 'S': + is_string = 1; + break; + + default: + /* Ignore unrecognized type attributes, so future compilers + can invent new ones. */ + break; + } + } + } + /* Skip the type descriptor, we get it below with (*pp)[-1]. */ + ++(*pp); + } + else + { + /* 'typenums=' not present, type is anonymous. Read and return + the definition, but don't put it in the type vector. */ + typenums[0] = typenums[1] = -1; + (*pp)++; + } + + type_descriptor = (*pp)[-1]; + switch (type_descriptor) + { + case 'x': + { + enum type_code code; + + /* Used to index through file_symbols. */ + struct pending *ppt; + int i; + + /* Name including "struct", etc. */ + char *type_name; + + { + char *from, *to, *p, *q1, *q2; + + /* Set the type code according to the following letter. */ + switch ((*pp)[0]) + { + case 's': + code = TYPE_CODE_STRUCT; + break; + case 'u': + code = TYPE_CODE_UNION; + break; + case 'e': + code = TYPE_CODE_ENUM; + break; + default: + { + /* Complain and keep going, so compilers can invent new + cross-reference types. */ + static struct complaint msg = + {"Unrecognized cross-reference type `%c'", 0, 0}; + complain (&msg, (*pp)[0]); + code = TYPE_CODE_STRUCT; + break; + } + } + + q1 = strchr(*pp, '<'); + p = strchr(*pp, ':'); + if (p == NULL) + return error_type (pp, objfile); + while (q1 && p > q1 && p[1] == ':') + { + q2 = strchr(q1, '>'); + if (!q2 || q2 < p) + break; + p += 2; + p = strchr(p, ':'); + if (p == NULL) + return error_type (pp, objfile); + } + to = type_name = + (char *)obstack_alloc (&objfile->type_obstack, p - *pp + 1); + + /* Copy the name. */ + from = *pp + 1; + while (from < p) + *to++ = *from++; + *to = '\0'; + + /* Set the pointer ahead of the name which we just read, and + the colon. */ + *pp = from + 1; + } + + /* Now check to see whether the type has already been + declared. This was written for arrays of cross-referenced + types before we had TYPE_CODE_TARGET_STUBBED, so I'm pretty + sure it is not necessary anymore. But it might be a good + idea, to save a little memory. */ + + for (ppt = file_symbols; ppt; ppt = ppt->next) + for (i = 0; i < ppt->nsyms; i++) + { + struct symbol *sym = ppt->symbol[i]; + + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE + && (TYPE_CODE (SYMBOL_TYPE (sym)) == code) + && STREQ (SYMBOL_NAME (sym), type_name)) + { + obstack_free (&objfile -> type_obstack, type_name); + type = SYMBOL_TYPE (sym); + return type; + } + } + + /* Didn't find the type to which this refers, so we must + be dealing with a forward reference. Allocate a type + structure for it, and keep track of it so we can + fill in the rest of the fields when we get the full + type. */ + type = dbx_alloc_type (typenums, objfile); + TYPE_CODE (type) = code; + TYPE_TAG_NAME (type) = type_name; + INIT_CPLUS_SPECIFIC(type); + TYPE_FLAGS (type) |= TYPE_FLAG_STUB; + + add_undefined_type (type); + return type; + } + + case '-': /* RS/6000 built-in type */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '(': + + { + char *pp_saved; + + (*pp)--; + pp_saved = *pp; + + /* Peek ahead at the number to detect void. */ + if (read_type_number (pp, xtypenums) != 0) + return error_type (pp, objfile); + + if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) + /* It's being defined as itself. That means it is "void". */ + type = init_type (TYPE_CODE_VOID, 1, 0, NULL, objfile); + else + { + struct type *xtype; + + /* Go back to the number and have read_type get it. This means + that we can deal with something like t(1,2)=(3,4)=... which + the Lucid compiler uses. */ + *pp = pp_saved; + xtype = read_type (pp, objfile); + + /* The type is being defined to another type. So we copy the type. + This loses if we copy a C++ class and so we lose track of how + the names are mangled (but g++ doesn't output stabs like this + now anyway). */ + + type = alloc_type (objfile); + if (SYMBOL_LINE (current_symbol) == 0) + { + *type = *xtype; + /* The idea behind clearing the names is that the only purpose + for defining a type to another type is so that the name of + one can be different. So we probably don't need to worry + much about the case where the compiler doesn't give a name + to the new type. */ + TYPE_NAME (type) = NULL; + TYPE_TAG_NAME (type) = NULL; + } + else + { + TYPE_CODE (type) = TYPE_CODE_TYPEDEF; + TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB; + TYPE_TARGET_TYPE (type) = xtype; + } + } + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + } + + /* In the following types, we must be sure to overwrite any existing + type that the typenums refer to, rather than allocating a new one + and making the typenums point to the new one. This is because there + may already be pointers to the existing type (if it had been + forward-referenced), and we must change it to a pointer, function, + reference, or whatever, *in-place*. */ + + case '*': + type1 = read_type (pp, objfile); + type = make_pointer_type (type1, dbx_lookup_type (typenums)); + break; + + case '&': /* Reference to another type */ + type1 = read_type (pp, objfile); + type = make_reference_type (type1, dbx_lookup_type (typenums)); + break; + + case 'f': /* Function returning another type */ + if (os9k_stabs && **pp == '(') + { + /* Function prototype; parse it. + We must conditionalize this on os9k_stabs because otherwise + it could be confused with a Sun-style (1,3) typenumber + (I think). */ + struct type *t; + ++*pp; + while (**pp != ')') + { + t = read_type(pp, objfile); + if (**pp == ',') ++*pp; + } + } + type1 = read_type (pp, objfile); + type = make_function_type (type1, dbx_lookup_type (typenums)); + break; + + case 'k': /* Const qualifier on some type (Sun) */ + case 'c': /* Const qualifier on some type (OS9000) */ + /* Because 'c' means other things to AIX and 'k' is perfectly good, + only accept 'c' in the os9k_stabs case. */ + if (type_descriptor == 'c' && !os9k_stabs) + return error_type (pp, objfile); + type = read_type (pp, objfile); + /* FIXME! For now, we ignore const and volatile qualifiers. */ + break; + + case 'B': /* Volatile qual on some type (Sun) */ + case 'i': /* Volatile qual on some type (OS9000) */ + /* Because 'i' means other things to AIX and 'B' is perfectly good, + only accept 'i' in the os9k_stabs case. */ + if (type_descriptor == 'i' && !os9k_stabs) + return error_type (pp, objfile); + type = read_type (pp, objfile); + /* FIXME! For now, we ignore const and volatile qualifiers. */ + break; + +/* FIXME -- we should be doing smash_to_XXX types here. */ + case '@': /* Member (class & variable) type */ + { + struct type *domain = read_type (pp, objfile); + struct type *memtype; + + if (**pp != ',') + /* Invalid member type data format. */ + return error_type (pp, objfile); + ++*pp; + + memtype = read_type (pp, objfile); + type = dbx_alloc_type (typenums, objfile); + smash_to_member_type (type, domain, memtype); + } + break; + + case '#': /* Method (class & fn) type */ + if ((*pp)[0] == '#') + { + /* We'll get the parameter types from the name. */ + struct type *return_type; + + (*pp)++; + return_type = read_type (pp, objfile); + if (*(*pp)++ != ';') + complain (&invalid_member_complaint, symnum); + type = allocate_stub_method (return_type); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + else + { + struct type *domain = read_type (pp, objfile); + struct type *return_type; + struct type **args; + + if (**pp != ',') + /* Invalid member type data format. */ + return error_type (pp, objfile); + else + ++(*pp); + + return_type = read_type (pp, objfile); + args = read_args (pp, ';', objfile); + type = dbx_alloc_type (typenums, objfile); + smash_to_method_type (type, domain, return_type, args); + } + break; + + case 'r': /* Range type */ + type = read_range_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 'b': + if (os9k_stabs) + /* Const and volatile qualified type. */ + type = read_type (pp, objfile); + else + { + /* Sun ACC builtin int type */ + type = read_sun_builtin_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + break; + + case 'R': /* Sun ACC builtin float type */ + type = read_sun_floating_type (pp, typenums, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 'e': /* Enumeration type */ + type = dbx_alloc_type (typenums, objfile); + type = read_enum_type (pp, type, objfile); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + break; + + case 's': /* Struct type */ + case 'u': /* Union type */ + type = dbx_alloc_type (typenums, objfile); + switch (type_descriptor) + { + case 's': + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case 'u': + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + } + type = read_struct_type (pp, type, objfile); + break; + + case 'a': /* Array type */ + if (**pp != 'r') + return error_type (pp, objfile); + ++*pp; + + type = dbx_alloc_type (typenums, objfile); + type = read_array_type (pp, type, objfile); + if (is_string) + TYPE_CODE (type) = TYPE_CODE_STRING; + break; + + case 'S': + 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) = type; + break; + + default: + --*pp; /* Go back to the symbol in error */ + /* Particularly important if it was \0! */ + return error_type (pp, objfile); + } + + if (type == 0) + { + warning ("GDB internal error, type is NULL in stabsread.c\n"); + return error_type (pp, objfile); + } + + /* Size specified in a type attribute overrides any other size. */ + if (type_size != -1) + TYPE_LENGTH (type) = (type_size + TARGET_CHAR_BIT - 1) / TARGET_CHAR_BIT; + + return type; +} + +/* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1. + Return the proper type node for a given builtin type number. */ + +static struct type * +rs6000_builtin_type (typenum) + int typenum; +{ + /* We recognize types numbered from -NUMBER_RECOGNIZED to -1. */ +#define NUMBER_RECOGNIZED 34 + /* This includes an empty slot for type number -0. */ + static struct type *negative_types[NUMBER_RECOGNIZED + 1]; + struct type *rettype = NULL; + + if (typenum >= 0 || typenum < -NUMBER_RECOGNIZED) + { + complain (&rs6000_builtin_complaint, typenum); + return builtin_type_error; + } + if (negative_types[-typenum] != NULL) + return negative_types[-typenum]; + +#if TARGET_CHAR_BIT != 8 + #error This code wrong for TARGET_CHAR_BIT not 8 + /* These definitions all assume that TARGET_CHAR_BIT is 8. I think + that if that ever becomes not true, the correct fix will be to + make the size in the struct type to be in bits, not in units of + TARGET_CHAR_BIT. */ +#endif + + switch (-typenum) + { + case 1: + /* The size of this and all the other types are fixed, defined + by the debugging format. If there is a type called "int" which + is other than 32 bits, then it should use a new negative type + number (or avoid negative type numbers for that case). + See stabs.texinfo. */ + rettype = init_type (TYPE_CODE_INT, 4, 0, "int", NULL); + break; + case 2: + rettype = init_type (TYPE_CODE_INT, 1, 0, "char", NULL); + break; + case 3: + rettype = init_type (TYPE_CODE_INT, 2, 0, "short", NULL); + break; + case 4: + rettype = init_type (TYPE_CODE_INT, 4, 0, "long", NULL); + break; + case 5: + rettype = init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, + "unsigned char", NULL); + break; + case 6: + rettype = init_type (TYPE_CODE_INT, 1, 0, "signed char", NULL); + break; + case 7: + rettype = init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, + "unsigned short", NULL); + break; + case 8: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned int", NULL); + break; + case 9: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned", NULL); + case 10: + rettype = init_type (TYPE_CODE_INT, 4, TYPE_FLAG_UNSIGNED, + "unsigned long", NULL); + break; + case 11: + rettype = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL); + break; + case 12: + /* IEEE single precision (32 bit). */ + rettype = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL); + break; + case 13: + /* IEEE double precision (64 bit). */ + rettype = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL); + break; + case 14: + /* This is an IEEE double on the RS/6000, and different machines with + different sizes for "long double" should use different negative + type numbers. See stabs.texinfo. */ + rettype = init_type (TYPE_CODE_FLT, 8, 0, "long double", NULL); + break; + case 15: + rettype = init_type (TYPE_CODE_INT, 4, 0, "integer", NULL); + break; + case 16: + rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED, + "boolean", NULL); + break; + case 17: + rettype = init_type (TYPE_CODE_FLT, 4, 0, "short real", NULL); + break; + case 18: + rettype = init_type (TYPE_CODE_FLT, 8, 0, "real", NULL); + break; + case 19: + rettype = init_type (TYPE_CODE_ERROR, 0, 0, "stringptr", NULL); + break; + case 20: + rettype = init_type (TYPE_CODE_CHAR, 1, TYPE_FLAG_UNSIGNED, + "character", NULL); + break; + case 21: + rettype = init_type (TYPE_CODE_BOOL, 1, TYPE_FLAG_UNSIGNED, + "logical*1", NULL); + break; + case 22: + rettype = init_type (TYPE_CODE_BOOL, 2, TYPE_FLAG_UNSIGNED, + "logical*2", NULL); + break; + case 23: + rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED, + "logical*4", NULL); + break; + case 24: + rettype = init_type (TYPE_CODE_BOOL, 4, TYPE_FLAG_UNSIGNED, + "logical", NULL); + break; + case 25: + /* Complex type consisting of two IEEE single precision values. */ + rettype = init_type (TYPE_CODE_ERROR, 8, 0, "complex", NULL); + break; + case 26: + /* Complex type consisting of two IEEE double precision values. */ + rettype = init_type (TYPE_CODE_ERROR, 16, 0, "double complex", NULL); + break; + case 27: + rettype = init_type (TYPE_CODE_INT, 1, 0, "integer*1", NULL); + break; + case 28: + rettype = init_type (TYPE_CODE_INT, 2, 0, "integer*2", NULL); + break; + case 29: + rettype = init_type (TYPE_CODE_INT, 4, 0, "integer*4", NULL); + break; + case 30: + rettype = init_type (TYPE_CODE_CHAR, 2, 0, "wchar", NULL); + break; + case 31: + rettype = init_type (TYPE_CODE_INT, 8, 0, "long long", NULL); + break; + case 32: + rettype = init_type (TYPE_CODE_INT, 8, TYPE_FLAG_UNSIGNED, + "unsigned long long", NULL); + break; + case 33: + rettype = init_type (TYPE_CODE_INT, 8, TYPE_FLAG_UNSIGNED, + "logical*8", NULL); + break; + case 34: + rettype = init_type (TYPE_CODE_INT, 8, 0, "integer*8", NULL); + break; + } + negative_types[-typenum] = rettype; + return rettype; +} + +/* This page contains subroutines of read_type. */ + +#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */ +#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */ +#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */ +#define VISIBILITY_IGNORE '9' /* Optimized out or zero length */ + +/* Read member function stabs info for C++ classes. The form of each member + function data is: + + NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ; + + An example with two member functions is: + + afunc1::20=##15;:i;2A.;afunc2::20:i;2A.; + + For the case of overloaded operators, the format is op$::*.funcs, where + $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator + name (such as `+=') and `.' marks the end of the operator name. + + Returns 1 for success, 0 for failure. */ + +static int +read_member_functions (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + 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 + { + struct next_fnfield *next; + struct fn_field fn_field; + } *sublist; + struct type *look_ahead_type; + struct next_fnfieldlist *new_fnlist; + struct next_fnfield *new_sublist; + char *main_fn_name; + register char *p; + + /* Process each list until we find something that is not a member function + or find the end of the functions. */ + + while (**pp != ';') + { + /* We should be positioned at the start of the function name. + Scan forward to find the first ':' and if it is not the + first of a "::" delimiter, then this is not a member function. */ + p = *pp; + while (*p != ':') + { + p++; + } + if (p[1] != ':') + { + break; + } + + sublist = NULL; + look_ahead_type = NULL; + length = 0; + + new_fnlist = (struct next_fnfieldlist *) + xmalloc (sizeof (struct next_fnfieldlist)); + make_cleanup (free, new_fnlist); + memset (new_fnlist, 0, sizeof (struct next_fnfieldlist)); + + if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && is_cplus_marker ((*pp)[2])) + { + /* This is a completely wierd case. In order to stuff in the + names that might contain colons (the usual name delimiter), + Mike Tiemann defined a different name format which is + signalled if the identifier is "op$". In that case, the + format is "op$::XXXX." where XXXX is the name. This is + used for names like "+" or "=". YUUUUUUUK! FIXME! */ + /* This lets the user type "break operator+". + We could just put in "+" as the name, but that wouldn't + work for "*". */ + static char opname[32] = {'o', 'p', CPLUS_MARKER}; + char *o = opname + 3; + + /* Skip past '::'. */ + *pp = p + 2; + + STABS_CONTINUE (pp, objfile); + p = *pp; + while (*p != '.') + { + *o++ = *p++; + } + main_fn_name = savestring (opname, o - opname); + /* Skip past '.' */ + *pp = p + 1; + } + else + { + main_fn_name = savestring (*pp, p - *pp); + /* Skip past '::'. */ + *pp = p + 2; + } + new_fnlist -> fn_fieldlist.name = main_fn_name; + + do + { + new_sublist = + (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield)); + make_cleanup (free, new_sublist); + memset (new_sublist, 0, sizeof (struct next_fnfield)); + + /* Check for and handle cretinous dbx symbol name continuation! */ + if (look_ahead_type == NULL) + { + /* Normal case. */ + STABS_CONTINUE (pp, objfile); + + new_sublist -> fn_field.type = read_type (pp, objfile); + if (**pp != ':') + { + /* Invalid symtab info for member function. */ + return 0; + } + } + else + { + /* g++ version 1 kludge */ + new_sublist -> fn_field.type = look_ahead_type; + look_ahead_type = NULL; + } + + (*pp)++; + p = *pp; + while (*p != ';') + { + p++; + } + + /* If this is just a stub, then we don't have the real name here. */ + + if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB) + { + if (!TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type)) + TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type) = type; + new_sublist -> fn_field.is_stub = 1; + } + new_sublist -> fn_field.physname = savestring (*pp, p - *pp); + *pp = p + 1; + + /* Set this member function's visibility fields. */ + switch (*(*pp)++) + { + case VISIBILITY_PRIVATE: + new_sublist -> fn_field.is_private = 1; + break; + case VISIBILITY_PROTECTED: + new_sublist -> fn_field.is_protected = 1; + break; + } + + STABS_CONTINUE (pp, objfile); + switch (**pp) + { + case 'A': /* Normal functions. */ + new_sublist -> fn_field.is_const = 0; + new_sublist -> fn_field.is_volatile = 0; + (*pp)++; + break; + case 'B': /* `const' member functions. */ + new_sublist -> fn_field.is_const = 1; + new_sublist -> fn_field.is_volatile = 0; + (*pp)++; + break; + case 'C': /* `volatile' member function. */ + new_sublist -> fn_field.is_const = 0; + new_sublist -> fn_field.is_volatile = 1; + (*pp)++; + break; + case 'D': /* `const volatile' member function. */ + new_sublist -> fn_field.is_const = 1; + new_sublist -> fn_field.is_volatile = 1; + (*pp)++; + break; + case '*': /* File compiled with g++ version 1 -- no info */ + case '?': + case '.': + break; + default: + complain (&const_vol_complaint, **pp); + break; + } + + switch (*(*pp)++) + { + case '*': + { + int nbits; + /* virtual member function, followed by index. + The sign bit is set to distinguish pointers-to-methods + from virtual function indicies. Since the array is + in words, the quantity must be shifted left by 1 + on 16 bit machine, and by 2 on 32 bit machine, forcing + the sign bit out, and usable as a valid index into + the array. Remove the sign bit here. */ + new_sublist -> fn_field.voffset = + (0x7fffffff & read_huge_number (pp, ';', &nbits)) + 2; + if (nbits != 0) + return 0; + + STABS_CONTINUE (pp, objfile); + if (**pp == ';' || **pp == '\0') + { + /* Must be g++ version 1. */ + new_sublist -> fn_field.fcontext = 0; + } + else + { + /* Figure out from whence this virtual function came. + It may belong to virtual function table of + one of its baseclasses. */ + look_ahead_type = read_type (pp, objfile); + if (**pp == ':') + { + /* g++ version 1 overloaded methods. */ + } + else + { + new_sublist -> fn_field.fcontext = look_ahead_type; + if (**pp != ';') + { + return 0; + } + else + { + ++*pp; + } + look_ahead_type = NULL; + } + } + break; + } + case '?': + /* static member function. */ + new_sublist -> fn_field.voffset = VOFFSET_STATIC; + if (strncmp (new_sublist -> fn_field.physname, + main_fn_name, strlen (main_fn_name))) + { + new_sublist -> fn_field.is_stub = 1; + } + break; + + default: + /* error */ + complain (&member_fn_complaint, (*pp)[-1]); + /* Fall through into normal member function. */ + + case '.': + /* normal member function. */ + new_sublist -> fn_field.voffset = 0; + new_sublist -> fn_field.fcontext = 0; + break; + } + + new_sublist -> next = sublist; + sublist = new_sublist; + length++; + STABS_CONTINUE (pp, objfile); + } + while (**pp != ';' && **pp != '\0'); + + (*pp)++; + + new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *) + obstack_alloc (&objfile -> type_obstack, + sizeof (struct fn_field) * length); + memset (new_fnlist -> fn_fieldlist.fn_fields, 0, + sizeof (struct fn_field) * length); + for (i = length; (i--, sublist); sublist = sublist -> next) + { + new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field; + } + + new_fnlist -> fn_fieldlist.length = length; + new_fnlist -> next = fip -> fnlist; + fip -> fnlist = new_fnlist; + nfn_fields++; + total_length += length; + STABS_CONTINUE (pp, objfile); + } + + if (nfn_fields) + { + ALLOCATE_CPLUS_STRUCT_TYPE (type); + TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *) + TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields); + 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; +} + +/* Special GNU C++ name. + + Returns 1 for success, 0 for failure. "failure" means that we can't + keep parsing and it's time for error_type(). */ + +static int +read_cpp_abbrev (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + char *name; + char cpp_abbrev; + struct type *context; + + p = *pp; + if (*++p == 'v') + { + name = NULL; + cpp_abbrev = *++p; + + *pp = p + 1; + + /* At this point, *pp points to something like "22:23=*22...", + where the type number before the ':' is the "context" and + everything after is a regular type definition. Lookup the + type, find it's name, and construct the field name. */ + + context = read_type (pp, objfile); + + switch (cpp_abbrev) + { + case 'f': /* $vf -- a virtual function table pointer */ + fip->list->field.name = + obconcat (&objfile->type_obstack, vptr_name, "", ""); + break; + + case 'b': /* $vb -- a virtual bsomethingorother */ + name = type_name_no_tag (context); + if (name == NULL) + { + complain (&invalid_cpp_type_complaint, symnum); + name = "FOO"; + } + fip->list->field.name = + obconcat (&objfile->type_obstack, vb_name, name, ""); + break; + + default: + complain (&invalid_cpp_abbrev_complaint, *pp); + fip->list->field.name = + obconcat (&objfile->type_obstack, + "INVALID_CPLUSPLUS_ABBREV", "", ""); + break; + } + + /* At this point, *pp points to the ':'. Skip it and read the + field type. */ + + p = ++(*pp); + if (p[-1] != ':') + { + complain (&invalid_cpp_abbrev_complaint, *pp); + return 0; + } + fip->list->field.type = read_type (pp, objfile); + if (**pp == ',') + (*pp)++; /* Skip the comma. */ + else + return 0; + + { + int nbits; + fip->list->field.bitpos = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return 0; + } + /* This field is unpacked. */ + fip->list->field.bitsize = 0; + fip->list->visibility = VISIBILITY_PRIVATE; + } + else + { + complain (&invalid_cpp_abbrev_complaint, *pp); + /* We have no idea what syntax an unrecognized abbrev would have, so + better return 0. If we returned 1, we would need to at least advance + *pp to avoid an infinite loop. */ + return 0; + } + return 1; +} + +static void +read_one_struct_field (fip, pp, p, type, objfile) + struct field_info *fip; + char **pp; + char *p; + struct type *type; + struct objfile *objfile; +{ + /* The following is code to work around cfront generated stabs. + The stabs contains full mangled name for each field. + We try to demangle the name and extract the field name out of it. + */ + if (ARM_DEMANGLING && current_subfile->language == language_cplus) + { + char save_p; + char *dem, *dem_p; + save_p = *p; + *p = '\0'; + dem = cplus_demangle (*pp, DMGL_ANSI | DMGL_PARAMS); + if (dem != NULL) + { + dem_p = strrchr (dem, ':'); + if (dem_p != 0 && *(dem_p-1)==':') + dem_p++; + fip->list->field.name = + obsavestring (dem_p, strlen(dem_p), &objfile -> type_obstack); + } + else + { + fip->list->field.name = + obsavestring (*pp, p - *pp, &objfile -> type_obstack); + } + *p = save_p; + } + /* end of code for cfront work around */ + + else + fip -> list -> field.name = + obsavestring (*pp, p - *pp, &objfile -> type_obstack); + *pp = p + 1; + + /* This means we have a visibility for a field coming. */ + if (**pp == '/') + { + (*pp)++; + fip -> list -> visibility = *(*pp)++; + } + else + { + /* normal dbx-style format, no explicit visibility */ + fip -> list -> visibility = VISIBILITY_PUBLIC; + } + + fip -> list -> field.type = read_type (pp, objfile); + if (**pp == ':') + { + p = ++(*pp); +#if 0 + /* Possible future hook for nested types. */ + if (**pp == '!') + { + fip -> list -> field.bitpos = (long)-2; /* nested type */ + p = ++(*pp); + } + else +#endif + { + /* Static class member. */ + fip -> list -> field.bitpos = (long) -1; + } + while (*p != ';') + { + p++; + } + fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp); + *pp = p + 1; + return; + } + else if (**pp != ',') + { + /* Bad structure-type format. */ + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + + (*pp)++; /* Skip the comma. */ + + { + int nbits; + fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + { + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + { + complain (&stabs_general_complaint, "bad structure-type format"); + return; + } + } + + if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0) + { + /* This can happen in two cases: (1) at least for gcc 2.4.5 or so, + it is a field which has been optimized out. The correct stab for + this case is to use VISIBILITY_IGNORE, but that is a recent + invention. (2) It is a 0-size array. For example + union { int num; char str[0]; } foo. Printing "" for + str in "p foo" is OK, since foo.str (and thus foo.str[3]) + will continue to work, and a 0-size array as a whole doesn't + have any contents to print. + + I suspect this probably could also happen with gcc -gstabs (not + -gstabs+) for static fields, and perhaps other C++ extensions. + Hopefully few people use -gstabs with gdb, since it is intended + for dbx compatibility. */ + + /* Ignore this field. */ + fip -> list-> visibility = VISIBILITY_IGNORE; + } + else + { + /* Detect an unpacked field and mark it as such. + dbx gives a bit size for all fields. + Note that forward refs cannot be packed, + and treat enums as if they had the width of ints. */ + + if (TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_INT + && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_BOOL + && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM) + { + fip -> list -> field.bitsize = 0; + } + if ((fip -> list -> field.bitsize + == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type) + || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM + && (fip -> list -> field.bitsize + == TARGET_INT_BIT) + ) + ) + && + fip -> list -> field.bitpos % 8 == 0) + { + fip -> list -> field.bitsize = 0; + } + } +} + + +/* Read struct or class data fields. They have the form: + + NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ; + + At the end, we see a semicolon instead of a field. + + In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for + a static field. + + The optional VISIBILITY is one of: + + '/0' (VISIBILITY_PRIVATE) + '/1' (VISIBILITY_PROTECTED) + '/2' (VISIBILITY_PUBLIC) + '/9' (VISIBILITY_IGNORE) + + or nothing, for C style fields with public visibility. + + Returns 1 for success, 0 for failure. */ + +static int +read_struct_fields (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + struct nextfield *new; + + /* We better set p right now, in case there are no fields at all... */ + + p = *pp; + + /* Read each data member type until we find the terminating ';' at the end of + the data member list, or break for some other reason such as finding the + start of the member function list. */ + + while (**pp != ';') + { + if (os9k_stabs && **pp == ',') break; + STABS_CONTINUE (pp, objfile); + /* Get space to record the next field's data. */ + new = (struct nextfield *) xmalloc (sizeof (struct nextfield)); + make_cleanup (free, new); + memset (new, 0, sizeof (struct nextfield)); + new -> next = fip -> list; + fip -> list = new; + + /* Get the field name. */ + p = *pp; + + /* If is starts with CPLUS_MARKER it is a special abbreviation, + unless the CPLUS_MARKER is followed by an underscore, in + which case it is just the name of an anonymous type, which we + should handle like any other type name. */ + + if (is_cplus_marker (p[0]) && p[1] != '_') + { + if (!read_cpp_abbrev (fip, pp, type, objfile)) + return 0; + continue; + } + + /* Look for the ':' that separates the field name from the field + values. Data members are delimited by a single ':', while member + functions are delimited by a pair of ':'s. When we hit the member + functions (if any), terminate scan loop and return. */ + + while (*p != ':' && *p != '\0') + { + p++; + } + if (*p == '\0') + return 0; + + /* Check to see if we have hit the member functions yet. */ + if (p[1] == ':') + { + break; + } + read_one_struct_field (fip, pp, p, type, objfile); + } + if (p[0] == ':' && p[1] == ':') + { + /* chill the list of fields: the last entry (at the head) is a + partially constructed entry which we now scrub. */ + fip -> list = fip -> list -> next; + } + return 1; +} + +/* The stabs for C++ derived classes contain baseclass information which + is marked by a '!' character after the total size. This function is + called when we encounter the baseclass marker, and slurps up all the + baseclass information. + + Immediately following the '!' marker is the number of base classes that + the class is derived from, followed by information for each base class. + For each base class, there are two visibility specifiers, a bit offset + to the base class information within the derived class, a reference to + the type for the base class, and a terminating semicolon. + + A typical example, with two base classes, would be "!2,020,19;0264,21;". + ^^ ^ ^ ^ ^ ^ ^ + Baseclass information marker __________________|| | | | | | | + Number of baseclasses __________________________| | | | | | | + Visibility specifiers (2) ________________________| | | | | | + Offset in bits from start of class _________________| | | | | + Type number for base class ___________________________| | | | + Visibility specifiers (2) _______________________________| | | + Offset in bits from start of class ________________________| | + Type number of base class ____________________________________| + + Return 1 for success, 0 for (error-type-inducing) failure. */ + +static int +read_baseclasses (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + int i; + struct nextfield *new; + + if (**pp != '!') + { + return 1; + } + else + { + /* Skip the '!' baseclass information marker. */ + (*pp)++; + } + + ALLOCATE_CPLUS_STRUCT_TYPE (type); + { + int nbits; + TYPE_N_BASECLASSES (type) = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return 0; + } + +#if 0 + /* Some stupid compilers have trouble with the following, so break + it up into simpler expressions. */ + TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) + TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type))); +#else + { + int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type)); + char *pointer; + + pointer = (char *) TYPE_ALLOC (type, num_bytes); + TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer; + } +#endif /* 0 */ + + B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type)); + + for (i = 0; i < TYPE_N_BASECLASSES (type); i++) + { + new = (struct nextfield *) xmalloc (sizeof (struct nextfield)); + make_cleanup (free, new); + memset (new, 0, sizeof (struct nextfield)); + new -> next = fip -> list; + fip -> list = new; + new -> field.bitsize = 0; /* this should be an unpacked field! */ + + STABS_CONTINUE (pp, objfile); + switch (**pp) + { + case '0': + /* Nothing to do. */ + break; + case '1': + SET_TYPE_FIELD_VIRTUAL (type, i); + break; + default: + /* Unknown character. Complain and treat it as non-virtual. */ + { + static struct complaint msg = { + "Unknown virtual character `%c' for baseclass", 0, 0}; + complain (&msg, **pp); + } + } + ++(*pp); + + new -> visibility = *(*pp)++; + switch (new -> visibility) + { + case VISIBILITY_PRIVATE: + case VISIBILITY_PROTECTED: + case VISIBILITY_PUBLIC: + break; + default: + /* Bad visibility format. Complain and treat it as + public. */ + { + static struct complaint msg = { + "Unknown visibility `%c' for baseclass", 0, 0}; + complain (&msg, new -> visibility); + new -> visibility = VISIBILITY_PUBLIC; + } + } + + { + int nbits; + + /* The remaining value is the bit offset of the portion of the object + corresponding to this baseclass. Always zero in the absence of + multiple inheritance. */ + + new -> field.bitpos = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return 0; + } + + /* The last piece of baseclass information is the type of the + base class. Read it, and remember it's type name as this + field's name. */ + + new -> field.type = read_type (pp, objfile); + new -> field.name = type_name_no_tag (new -> field.type); + + /* skip trailing ';' and bump count of number of fields seen */ + if (**pp == ';') + (*pp)++; + else + return 0; + } + return 1; +} + +/* The tail end of stabs for C++ classes that contain a virtual function + pointer contains a tilde, a %, and a type number. + The type number refers to the base class (possibly this class itself) which + contains the vtable pointer for the current class. + + This function is called when we have parsed all the method declarations, + so we can look for the vptr base class info. */ + +static int +read_tilde_fields (fip, pp, type, objfile) + struct field_info *fip; + char **pp; + struct type *type; + struct objfile *objfile; +{ + register char *p; + + STABS_CONTINUE (pp, objfile); + + /* If we are positioned at a ';', then skip it. */ + if (**pp == ';') + { + (*pp)++; + } + + if (**pp == '~') + { + (*pp)++; + + if (**pp == '=' || **pp == '+' || **pp == '-') + { + /* Obsolete flags that used to indicate the presence + of constructors and/or destructors. */ + (*pp)++; + } + + /* Read either a '%' or the final ';'. */ + if (*(*pp)++ == '%') + { + /* The next number is the type number of the base class + (possibly our own class) which supplies the vtable for + this class. Parse it out, and search that class to find + its vtable pointer, and install those into TYPE_VPTR_BASETYPE + and TYPE_VPTR_FIELDNO. */ + + struct type *t; + int i; + + t = read_type (pp, objfile); + p = (*pp)++; + while (*p != '\0' && *p != ';') + { + p++; + } + if (*p == '\0') + { + /* Premature end of symbol. */ + return 0; + } + + TYPE_VPTR_BASETYPE (type) = t; + if (type == t) /* Our own class provides vtbl ptr */ + { + for (i = TYPE_NFIELDS (t) - 1; + i >= TYPE_N_BASECLASSES (t); + --i) + { + if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name, + sizeof (vptr_name) - 1)) + { + TYPE_VPTR_FIELDNO (type) = i; + goto gotit; + } + } + /* Virtual function table field not found. */ + complain (&vtbl_notfound_complaint, TYPE_NAME (type)); + return 0; + } + else + { + TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t); + } + + gotit: + *pp = p + 1; + } + } + return 1; +} + +static int +attach_fn_fields_to_type (fip, type) + struct field_info *fip; + register struct type *type; +{ + register int n; + + for (n = TYPE_NFN_FIELDS (type); + fip -> fnlist != NULL; + fip -> fnlist = fip -> fnlist -> next) + { + --n; /* Circumvent Sun3 compiler bug */ + TYPE_FN_FIELDLISTS (type)[n] = fip -> fnlist -> fn_fieldlist; + } + return 1; +} + +/* Create the vector of fields, and record how big it is. + We need this info to record proper virtual function table information + for this class's virtual functions. */ + +static int +attach_fields_to_type (fip, type, objfile) + struct field_info *fip; + register struct type *type; + struct objfile *objfile; +{ + register int nfields = 0; + register int non_public_fields = 0; + register struct nextfield *scan; + + /* Count up the number of fields that we have, as well as taking note of + whether or not there are any non-public fields, which requires us to + allocate and build the private_field_bits and protected_field_bits + bitfields. */ + + for (scan = fip -> list; scan != NULL; scan = scan -> next) + { + nfields++; + if (scan -> visibility != VISIBILITY_PUBLIC) + { + non_public_fields++; + } + } + + /* Now we know how many fields there are, and whether or not there are any + non-public fields. Record the field count, allocate space for the + array of fields, and create blank visibility bitfields if necessary. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields); + + if (non_public_fields) + { + ALLOCATE_CPLUS_STRUCT_TYPE (type); + + TYPE_FIELD_PRIVATE_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields); + + TYPE_FIELD_PROTECTED_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields); + + TYPE_FIELD_IGNORE_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields); + } + + /* Copy the saved-up fields into the field vector. Start from the head + of the list, adding to the tail of the field array, so that they end + up in the same order in the array in which they were added to the list. */ + + while (nfields-- > 0) + { + TYPE_FIELD (type, nfields) = fip -> list -> field; + switch (fip -> list -> visibility) + { + case VISIBILITY_PRIVATE: + SET_TYPE_FIELD_PRIVATE (type, nfields); + break; + + case VISIBILITY_PROTECTED: + SET_TYPE_FIELD_PROTECTED (type, nfields); + break; + + case VISIBILITY_IGNORE: + SET_TYPE_FIELD_IGNORE (type, nfields); + break; + + case VISIBILITY_PUBLIC: + break; + + default: + /* Unknown visibility. Complain and treat it as public. */ + { + static struct complaint msg = { + "Unknown visibility `%c' for field", 0, 0}; + complain (&msg, fip -> list -> visibility); + } + break; + } + fip -> list = fip -> list -> next; + } + return 1; +} + +/* Read the description of a structure (or union type) and return an object + describing the type. + + PP points to a character pointer that points to the next unconsumed token + in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;", + *PP will point to "4a:1,0,32;;". + + TYPE points to an incomplete type that needs to be filled in. + + OBJFILE points to the current objfile from which the stabs information is + being read. (Note that it is redundant in that TYPE also contains a pointer + to this same objfile, so it might be a good idea to eliminate it. FIXME). + */ + +static struct type * +read_struct_type (pp, type, objfile) + char **pp; + struct type *type; + struct objfile *objfile; +{ + struct cleanup *back_to; + struct field_info fi; + + fi.list = NULL; + fi.fnlist = NULL; + + back_to = make_cleanup (null_cleanup, 0); + + INIT_CPLUS_SPECIFIC (type); + TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB; + + /* First comes the total size in bytes. */ + + { + int nbits; + TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits); + if (nbits != 0) + return error_type (pp, objfile); + } + + /* Now read the baseclasses, if any, read the regular C struct or C++ + class member fields, attach the fields to the type, read the C++ + member functions, attach them to the type, and then read any tilde + field (baseclass specifier for the class holding the main vtable). */ + + if (!read_baseclasses (&fi, pp, type, objfile) + || !read_struct_fields (&fi, pp, type, objfile) + || !attach_fields_to_type (&fi, type, objfile) + || !read_member_functions (&fi, pp, type, objfile) + || !attach_fn_fields_to_type (&fi, type) + || !read_tilde_fields (&fi, pp, type, objfile)) + { + type = error_type (pp, objfile); + } + + do_cleanups (back_to); + return (type); +} + +/* Read a definition of an array type, + and create and return a suitable type object. + Also creates a range type which represents the bounds of that + array. */ + +static struct type * +read_array_type (pp, type, objfile) + register char **pp; + register struct type *type; + struct objfile *objfile; +{ + struct type *index_type, *element_type, *range_type; + int lower, upper; + int adjustable = 0; + int nbits; + + /* Format of an array type: + "ar;lower;upper;". + OS9000: "arlower,upper;". + + Fortran adjustable arrays use Adigits or Tdigits for lower or upper; + for these, produce a type like float[][]. */ + + if (os9k_stabs) + index_type = builtin_type_int; + else + { + index_type = read_type (pp, objfile); + if (**pp != ';') + /* Improper format of array type decl. */ + return error_type (pp, objfile); + ++*pp; + } + + if (!(**pp >= '0' && **pp <= '9') && **pp != '-') + { + (*pp)++; + adjustable = 1; + } + lower = read_huge_number (pp, os9k_stabs ? ',' : ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + if (!(**pp >= '0' && **pp <= '9') && **pp != '-') + { + (*pp)++; + adjustable = 1; + } + upper = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + element_type = read_type (pp, objfile); + + if (adjustable) + { + lower = 0; + upper = -1; + } + + range_type = + create_range_type ((struct type *) NULL, index_type, lower, upper); + type = create_array_type (type, element_type, range_type); + + return type; +} + + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (pp, type, objfile) + register char **pp; + register struct type *type; + struct objfile *objfile; +{ + register char *p; + char *name; + register long n; + register struct symbol *sym; + int nsyms = 0; + struct pending **symlist; + struct pending *osyms, *syms; + int o_nsyms; + int nbits; + int unsigned_enum = 1; + +#if 0 + /* FIXME! The stabs produced by Sun CC merrily define things that ought + to be file-scope, between N_FN entries, using N_LSYM. What's a mother + to do? For now, force all enum values to file scope. */ + if (within_function) + symlist = &local_symbols; + else +#endif + symlist = &file_symbols; + osyms = *symlist; + o_nsyms = osyms ? osyms->nsyms : 0; + + if (os9k_stabs) + { + /* Size. Perhaps this does not have to be conditionalized on + os9k_stabs (assuming the name of an enum constant can't start + with a digit). */ + read_huge_number (pp, 0, &nbits); + if (nbits != 0) + return error_type (pp, objfile); + } + + /* The aix4 compiler emits an extra field before the enum members; + my guess is it's a type of some sort. Just ignore it. */ + if (**pp == '-') + { + /* Skip over the type. */ + while (**pp != ':') + (*pp)++; + + /* Skip over the colon. */ + (*pp)++; + } + + /* Read the value-names and their values. + The input syntax is NAME:VALUE,NAME:VALUE, and so on. + A semicolon or comma instead of a NAME means the end. */ + while (**pp && **pp != ';' && **pp != ',') + { + STABS_CONTINUE (pp, objfile); + p = *pp; + while (*p != ':') p++; + name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack); + *pp = p + 1; + n = read_huge_number (pp, ',', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = name; + SYMBOL_LANGUAGE (sym) = current_subfile -> language; + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = n; + if (n < 0) + unsigned_enum = 0; + add_symbol_to_list (sym, symlist); + nsyms++; + } + + if (**pp == ';') + (*pp)++; /* Skip the semicolon. */ + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = TARGET_INT_BIT / HOST_CHAR_BIT; + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB; + if (unsigned_enum) + TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nsyms); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + /* Note that we preserve the order of the enum constants, so + that in something like "enum {FOO, LAST_THING=FOO}" we print + FOO, not LAST_THING. */ + + for (syms = *symlist, n = nsyms - 1; syms; syms = syms->next) + { + int last = syms == osyms ? o_nsyms : 0; + int j = syms->nsyms; + for (; --j >= last; --n) + { + struct symbol *xsym = syms->symbol[j]; + SYMBOL_TYPE (xsym) = type; + TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + if (syms == osyms) + break; + } + + return type; +} + +/* Sun's ACC uses a somewhat saner method for specifying the builtin + typedefs in every file (for int, long, etc): + + type = b ; ; + signed = u or s. Possible c in addition to u or s (for char?). + offset = offset from high order bit to start bit of type. + width is # bytes in object of this type, nbits is # bits in type. + + The width/offset stuff appears to be for small objects stored in + larger ones (e.g. `shorts' in `int' registers). We ignore it for now, + FIXME. */ + +static struct type * +read_sun_builtin_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + int type_bits; + int nbits; + int signed_type; + + switch (**pp) + { + case 's': + signed_type = 1; + break; + case 'u': + signed_type = 0; + break; + default: + return error_type (pp, objfile); + } + (*pp)++; + + /* For some odd reason, all forms of char put a c here. This is strange + because no other type has this honor. We can safely ignore this because + we actually determine 'char'acterness by the number of bits specified in + the descriptor. */ + + if (**pp == 'c') + (*pp)++; + + /* The first number appears to be the number of bytes occupied + by this type, except that unsigned short is 4 instead of 2. + Since this information is redundant with the third number, + we will ignore it. */ + read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + /* The second number is always 0, so ignore it too. */ + read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + /* The third number is the number of bits for this type. */ + type_bits = read_huge_number (pp, 0, &nbits); + if (nbits != 0) + return error_type (pp, objfile); + /* The type *should* end with a semicolon. If it are embedded + in a larger type the semicolon may be the only way to know where + the type ends. If this type is at the end of the stabstring we + can deal with the omitted semicolon (but we don't have to like + it). Don't bother to complain(), Sun's compiler omits the semicolon + for "void". */ + if (**pp == ';') + ++(*pp); + + if (type_bits == 0) + return init_type (TYPE_CODE_VOID, 1, + signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL, + objfile); + else + return init_type (TYPE_CODE_INT, + type_bits / TARGET_CHAR_BIT, + signed_type ? 0 : TYPE_FLAG_UNSIGNED, (char *)NULL, + objfile); +} + +static struct type * +read_sun_floating_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + int nbits; + int details; + int nbytes; + + /* The first number has more details about the type, for example + FN_COMPLEX. */ + details = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + /* The second number is the number of bytes occupied by this type */ + nbytes = read_huge_number (pp, ';', &nbits); + if (nbits != 0) + return error_type (pp, objfile); + + if (details == NF_COMPLEX || details == NF_COMPLEX16 + || details == NF_COMPLEX32) + /* This is a type we can't handle, but we do know the size. + We also will be able to give it a name. */ + return init_type (TYPE_CODE_ERROR, nbytes, 0, NULL, objfile); + + return init_type (TYPE_CODE_FLT, nbytes, 0, NULL, objfile); +} + +/* Read a number from the string pointed to by *PP. + The value of *PP is advanced over the number. + If END is nonzero, the character that ends the + number must match END, or an error happens; + and that character is skipped if it does match. + If END is zero, *PP is left pointing to that character. + + If the number fits in a long, set *BITS to 0 and return the value. + If not, set *BITS to be the number of bits in the number and return 0. + + If encounter garbage, set *BITS to -1 and return 0. */ + +static long +read_huge_number (pp, end, bits) + char **pp; + int end; + int *bits; +{ + char *p = *pp; + int sign = 1; + long n = 0; + int radix = 10; + char overflow = 0; + int nbits = 0; + int c; + long upper_limit; + + if (*p == '-') + { + sign = -1; + p++; + } + + /* Leading zero means octal. GCC uses this to output values larger + than an int (because that would be hard in decimal). */ + if (*p == '0') + { + radix = 8; + p++; + } + + if (os9k_stabs) + upper_limit = ULONG_MAX / radix; + else + upper_limit = LONG_MAX / radix; + + while ((c = *p++) >= '0' && c < ('0' + radix)) + { + if (n <= upper_limit) + { + n *= radix; + n += c - '0'; /* FIXME this overflows anyway */ + } + else + overflow = 1; + + /* This depends on large values being output in octal, which is + what GCC does. */ + if (radix == 8) + { + if (nbits == 0) + { + if (c == '0') + /* Ignore leading zeroes. */ + ; + else if (c == '1') + nbits = 1; + else if (c == '2' || c == '3') + nbits = 2; + else + nbits = 3; + } + else + nbits += 3; + } + } + if (end) + { + if (c && c != end) + { + if (bits != NULL) + *bits = -1; + return 0; + } + } + else + --p; + + *pp = p; + if (overflow) + { + if (nbits == 0) + { + /* Large decimal constants are an error (because it is hard to + count how many bits are in them). */ + if (bits != NULL) + *bits = -1; + return 0; + } + + /* -0x7f is the same as 0x80. So deal with it by adding one to + the number of bits. */ + if (sign == -1) + ++nbits; + if (bits) + *bits = nbits; + } + else + { + if (bits) + *bits = 0; + return n * sign; + } + /* It's *BITS which has the interesting information. */ + return 0; +} + +static struct type * +read_range_type (pp, typenums, objfile) + char **pp; + int typenums[2]; + struct objfile *objfile; +{ + char *orig_pp = *pp; + int rangenums[2]; + long n2, n3; + int n2bits, n3bits; + int self_subrange; + struct type *result_type; + struct type *index_type = NULL; + + /* First comes a type we are a subrange of. + In C it is usually 0, 1 or the type being defined. */ + if (read_type_number (pp, rangenums) != 0) + return error_type (pp, objfile); + self_subrange = (rangenums[0] == typenums[0] && + rangenums[1] == typenums[1]); + + if (**pp == '=') + { + *pp = orig_pp; + index_type = read_type (pp, objfile); + } + + /* A semicolon should now follow; skip it. */ + if (**pp == ';') + (*pp)++; + + /* The remaining two operands are usually lower and upper bounds + of the range. But in some special cases they mean something else. */ + n2 = read_huge_number (pp, ';', &n2bits); + n3 = read_huge_number (pp, ';', &n3bits); + + if (n2bits == -1 || n3bits == -1) + return error_type (pp, objfile); + + if (index_type) + goto handle_true_range; + + /* If limits are huge, must be large integral type. */ + if (n2bits != 0 || n3bits != 0) + { + char got_signed = 0; + char got_unsigned = 0; + /* Number of bits in the type. */ + int nbits = 0; + + /* Range from 0 to is an unsigned large integral type. */ + if ((n2bits == 0 && n2 == 0) && n3bits != 0) + { + got_unsigned = 1; + nbits = n3bits; + } + /* Range from to -1 is a large signed + integral type. Take care of the case where doesn't + fit in a long but -1 does. */ + else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1) + || (n2bits != 0 && n3bits == 0 + && (n2bits == sizeof (long) * HOST_CHAR_BIT) + && n3 == LONG_MAX)) + { + got_signed = 1; + nbits = n2bits; + } + + if (got_signed || got_unsigned) + { + return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT, + got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL, + objfile); + } + else + return error_type (pp, objfile); + } + + /* A type defined as a subrange of itself, with bounds both 0, is void. */ + if (self_subrange && n2 == 0 && n3 == 0) + return init_type (TYPE_CODE_VOID, 1, 0, NULL, objfile); + + /* If n3 is zero and n2 is positive, we want a floating type, + and n2 is the width in bytes. + + Fortran programs appear to use this for complex types also, + and they give no way to distinguish between double and single-complex! + + GDB does not have complex types. + + Just return the complex as a float of that size. It won't work right + for the complex values, but at least it makes the file loadable. */ + + if (n3 == 0 && n2 > 0) + { + return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile); + } + + /* If the upper bound is -1, it must really be an unsigned int. */ + + else if (n2 == 0 && n3 == -1) + { + /* It is unsigned int or unsigned long. */ + /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5 + compatibility hack. */ + return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, NULL, objfile); + } + + /* Special case: char is defined (Who knows why) as a subrange of + itself with range 0-127. */ + else if (self_subrange && n2 == 0 && n3 == 127) + return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile); + + else if (current_symbol && SYMBOL_LANGUAGE (current_symbol) == language_chill + && !self_subrange) + goto handle_true_range; + + /* We used to do this only for subrange of self or subrange of int. */ + else if (n2 == 0) + { + if (n3 < 0) + /* n3 actually gives the size. */ + return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED, + NULL, objfile); + if (n3 == 0xff) + return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile); + if (n3 == 0xffff) + return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile); + + /* -1 is used for the upper bound of (4 byte) "unsigned int" and + "unsigned long", and we already checked for that, + so don't need to test for it here. */ + } + /* I think this is for Convex "long long". Since I don't know whether + Convex sets self_subrange, I also accept that particular size regardless + of self_subrange. */ + else if (n3 == 0 && n2 < 0 + && (self_subrange + || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT)) + return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile); + else if (n2 == -n3 -1) + { + if (n3 == 0x7f) + return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile); + if (n3 == 0x7fff) + return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile); + if (n3 == 0x7fffffff) + return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile); + } + + /* We have a real range type on our hands. Allocate space and + return a real pointer. */ + handle_true_range: + + if (self_subrange) + index_type = builtin_type_int; + else + index_type = *dbx_lookup_type (rangenums); + if (index_type == NULL) + { + /* Does this actually ever happen? Is that why we are worrying + about dealing with it rather than just calling error_type? */ + + static struct type *range_type_index; + + complain (&range_type_base_complaint, rangenums[1]); + if (range_type_index == NULL) + range_type_index = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "range type index type", NULL); + index_type = range_type_index; + } + + result_type = create_range_type ((struct type *) NULL, index_type, n2, n3); + return (result_type); +} + +/* Read in an argument list. This is a list of types, separated by commas + and terminated with END. Return the list of types read in, or (struct type + **)-1 if there is an error. */ + +static struct type ** +read_args (pp, end, objfile) + char **pp; + int end; + struct objfile *objfile; +{ + /* FIXME! Remove this arbitrary limit! */ + struct type *types[1024], **rval; /* allow for fns of 1023 parameters */ + int n = 0; + + while (**pp != end) + { + if (**pp != ',') + /* Invalid argument list: no ','. */ + return (struct type **)-1; + (*pp)++; + STABS_CONTINUE (pp, objfile); + types[n++] = read_type (pp, objfile); + } + (*pp)++; /* get past `end' (the ':' character) */ + + if (n == 1) + { + rval = (struct type **) xmalloc (2 * sizeof (struct type *)); + } + else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID) + { + rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *)); + memset (rval + n, 0, sizeof (struct type *)); + } + else + { + rval = (struct type **) xmalloc (n * sizeof (struct type *)); + } + memcpy (rval, types, n * sizeof (struct type *)); + return rval; +} + +/* Common block handling. */ + +/* List of symbols declared since the last BCOMM. This list is a tail + of local_symbols. When ECOMM is seen, the symbols on the list + are noted so their proper addresses can be filled in later, + using the common block base address gotten from the assembler + stabs. */ + +static struct pending *common_block; +static int common_block_i; + +/* Name of the current common block. We get it from the BCOMM instead of the + ECOMM to match IBM documentation (even though IBM puts the name both places + like everyone else). */ +static char *common_block_name; + +/* Process a N_BCOMM symbol. The storage for NAME is not guaranteed + to remain after this function returns. */ + +void +common_block_start (name, objfile) + char *name; + struct objfile *objfile; +{ + if (common_block_name != NULL) + { + static struct complaint msg = { + "Invalid symbol data: common block within common block", + 0, 0}; + complain (&msg); + } + common_block = local_symbols; + common_block_i = local_symbols ? local_symbols->nsyms : 0; + common_block_name = obsavestring (name, strlen (name), + &objfile -> symbol_obstack); +} + +/* Process a N_ECOMM symbol. */ + +void +common_block_end (objfile) + struct objfile *objfile; +{ + /* Symbols declared since the BCOMM are to have the common block + start address added in when we know it. common_block and + common_block_i point to the first symbol after the BCOMM in + the local_symbols list; copy the list and hang it off the + symbol for the common block name for later fixup. */ + int i; + struct symbol *sym; + struct pending *new = 0; + struct pending *next; + int j; + + if (common_block_name == NULL) + { + static struct complaint msg = {"ECOMM symbol unmatched by BCOMM", 0, 0}; + complain (&msg); + return; + } + + sym = (struct symbol *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (sym) = common_block_name; + SYMBOL_CLASS (sym) = LOC_BLOCK; + + /* Now we copy all the symbols which have been defined since the BCOMM. */ + + /* Copy all the struct pendings before common_block. */ + for (next = local_symbols; + next != NULL && next != common_block; + next = next->next) + { + for (j = 0; j < next->nsyms; j++) + add_symbol_to_list (next->symbol[j], &new); + } + + /* Copy however much of COMMON_BLOCK we need. If COMMON_BLOCK is + NULL, it means copy all the local symbols (which we already did + above). */ + + if (common_block != NULL) + for (j = common_block_i; j < common_block->nsyms; j++) + add_symbol_to_list (common_block->symbol[j], &new); + + SYMBOL_TYPE (sym) = (struct type *) new; + + /* Should we be putting local_symbols back to what it was? + Does it matter? */ + + i = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i]; + global_sym_chain[i] = sym; + common_block_name = NULL; +} + +/* Add a common block's start address to the offset of each symbol + declared to be in it (by being between a BCOMM/ECOMM pair that uses + the common block name). */ + +static void +fix_common_block (sym, valu) + struct symbol *sym; + int valu; +{ + struct pending *next = (struct pending *) SYMBOL_TYPE (sym); + for ( ; next; next = next->next) + { + register int j; + for (j = next->nsyms - 1; j >= 0; j--) + SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu; + } +} + + + +/* What about types defined as forward references inside of a small lexical + scope? */ +/* Add a type to the list of undefined types to be checked through + once this file has been read in. */ + +void +add_undefined_type (type) + struct type *type; +{ + if (undef_types_length == undef_types_allocated) + { + undef_types_allocated *= 2; + undef_types = (struct type **) + xrealloc ((char *) undef_types, + undef_types_allocated * sizeof (struct type *)); + } + undef_types[undef_types_length++] = type; +} + +/* Go through each undefined type, see if it's still undefined, and fix it + up if possible. We have two kinds of undefined types: + + TYPE_CODE_ARRAY: Array whose target type wasn't defined yet. + Fix: update array length using the element bounds + and the target type's length. + TYPE_CODE_STRUCT, TYPE_CODE_UNION: Structure whose fields were not + yet defined at the time a pointer to it was made. + Fix: Do a full lookup on the struct/union tag. */ +void +cleanup_undefined_types () +{ + struct type **type; + + for (type = undef_types; type < undef_types + undef_types_length; type++) + { + switch (TYPE_CODE (*type)) + { + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ENUM: + { + /* Check if it has been defined since. Need to do this here + as well as in check_typedef to deal with the (legitimate in + C though not C++) case of several types with the same name + in different source files. */ + if (TYPE_FLAGS (*type) & TYPE_FLAG_STUB) + { + struct pending *ppt; + int i; + /* Name of the type, without "struct" or "union" */ + char *typename = TYPE_TAG_NAME (*type); + + if (typename == NULL) + { + static struct complaint msg = {"need a type name", 0, 0}; + complain (&msg); + break; + } + for (ppt = file_symbols; ppt; ppt = ppt->next) + { + for (i = 0; i < ppt->nsyms; i++) + { + struct symbol *sym = ppt->symbol[i]; + + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE + && (TYPE_CODE (SYMBOL_TYPE (sym)) == + TYPE_CODE (*type)) + && STREQ (SYMBOL_NAME (sym), typename)) + { + memcpy (*type, SYMBOL_TYPE (sym), + sizeof (struct type)); + } + } + } + } + } + break; + + default: + { + static struct complaint msg = {"\ +GDB internal error. cleanup_undefined_types with bad type %d.", 0, 0}; + complain (&msg, TYPE_CODE (*type)); + } + break; + } + } + + undef_types_length = 0; +} + +/* Scan through all of the global symbols defined in the object file, + assigning values to the debugging symbols that need to be assigned + to. Get these symbols from the minimal symbol table. */ + +void +scan_file_globals (objfile) + struct objfile *objfile; +{ + int hash; + struct minimal_symbol *msymbol; + struct symbol *sym, *prev; + + /* Avoid expensive loop through all minimal symbols if there are + no unresolved symbols. */ + for (hash = 0; hash < HASHSIZE; hash++) + { + if (global_sym_chain[hash]) + break; + } + if (hash >= HASHSIZE) + return; + + for (msymbol = objfile -> msymbols; + msymbol && SYMBOL_NAME (msymbol) != NULL; + msymbol++) + { + QUIT; + + /* Skip static symbols. */ + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_file_text: + case mst_file_data: + case mst_file_bss: + continue; + default: + break; + } + + prev = NULL; + + /* Get the hash index and check all the symbols + under that hash index. */ + + hash = hashname (SYMBOL_NAME (msymbol)); + + for (sym = global_sym_chain[hash]; sym;) + { + if (SYMBOL_NAME (msymbol)[0] == SYMBOL_NAME (sym)[0] && + STREQ(SYMBOL_NAME (msymbol) + 1, SYMBOL_NAME (sym) + 1)) + { + /* Splice this symbol out of the hash chain and + assign the value we have to it. */ + if (prev) + { + SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym); + } + else + { + global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym); + } + + /* Check to see whether we need to fix up a common block. */ + /* Note: this code might be executed several times for + the same symbol if there are multiple references. */ + + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + { + fix_common_block (sym, SYMBOL_VALUE_ADDRESS (msymbol)); + } + else + { + SYMBOL_VALUE_ADDRESS (sym) = SYMBOL_VALUE_ADDRESS (msymbol); + } + + SYMBOL_SECTION (sym) = SYMBOL_SECTION (msymbol); + + if (prev) + { + sym = SYMBOL_VALUE_CHAIN (prev); + } + else + { + sym = global_sym_chain[hash]; + } + } + else + { + prev = sym; + sym = SYMBOL_VALUE_CHAIN (sym); + } + } + } + + /* Change the storage class of any remaining unresolved globals to + LOC_UNRESOLVED and remove them from the chain. */ + for (hash = 0; hash < HASHSIZE; hash++) + { + sym = global_sym_chain[hash]; + while (sym) + { + prev = sym; + sym = SYMBOL_VALUE_CHAIN (sym); + + /* Change the symbol address from the misleading chain value + to address zero. */ + SYMBOL_VALUE_ADDRESS (prev) = 0; + + /* Complain about unresolved common block symbols. */ + if (SYMBOL_CLASS (prev) == LOC_STATIC) + SYMBOL_CLASS (prev) = LOC_UNRESOLVED; + else + complain (&unresolved_sym_chain_complaint, + objfile->name, SYMBOL_NAME (prev)); + } + } + memset (global_sym_chain, 0, sizeof (global_sym_chain)); +} + +/* 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. */ + +void +stabsread_init () +{ +} + +/* 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). */ + +void +stabsread_new_init () +{ + /* Empty the hash table of global syms looking for values. */ + memset (global_sym_chain, 0, sizeof (global_sym_chain)); +} + +/* Initialize anything that needs initializing at the same time as + start_symtab() is called. */ + +void start_stabs () +{ + global_stabs = NULL; /* AIX COFF */ + /* Leave FILENUM of 0 free for builtin types and this file's types. */ + n_this_object_header_files = 1; + type_vector_length = 0; + type_vector = (struct type **) 0; + + /* FIXME: If common_block_name is not already NULL, we should complain(). */ + common_block_name = NULL; + + os9k_stabs = 0; +} + +/* Call after end_symtab() */ + +void end_stabs () +{ + if (type_vector) + { + free ((char *) type_vector); + } + type_vector = 0; + type_vector_length = 0; + previous_stab_code = 0; +} + +void +finish_global_stabs (objfile) + struct objfile *objfile; +{ + if (global_stabs) + { + patch_block_stabs (global_symbols, global_stabs, objfile); + free ((PTR) global_stabs); + global_stabs = NULL; + } +} + +/* Initializer for this module */ + +void +_initialize_stabsread () +{ + undef_types_allocated = 20; + undef_types_length = 0; + undef_types = (struct type **) + xmalloc (undef_types_allocated * sizeof (struct type *)); +} diff --git a/contrib/gdb/gdb/stabsread.h b/contrib/gdb/gdb/stabsread.h new file mode 100644 index 000000000000..b348738fc028 --- /dev/null +++ b/contrib/gdb/gdb/stabsread.h @@ -0,0 +1,225 @@ +/* Include file for stabs debugging format support functions. + Copyright 1986-1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Definitions, prototypes, etc for stabs debugging format support + functions. + + Variables declared in this file can be defined by #define-ing + the name EXTERN to null. It is used to declare variables that + are normally extern, but which get defined in a single module + using this technique. */ + +#ifndef EXTERN +#define EXTERN extern +#endif + +/* Convert stab register number (from `r' declaration) to a gdb REGNUM. */ + +#ifndef STAB_REG_TO_REGNUM +#define STAB_REG_TO_REGNUM(VALUE) (VALUE) +#endif + +/* Hash table of global symbols whose values are not known yet. + They are chained thru the SYMBOL_VALUE_CHAIN, since we don't + have the correct data for that slot yet. + + The use of the LOC_BLOCK code in this chain is nonstandard-- + it refers to a FORTRAN common block rather than the usual meaning, and + the such LOC_BLOCK symbols use their fields in nonstandard ways. */ + +EXTERN struct symbol *global_sym_chain[HASHSIZE]; + +extern void common_block_start PARAMS ((char *, struct objfile *)); +extern void common_block_end PARAMS ((struct objfile *)); + +/* Kludge for xcoffread.c */ + +struct pending_stabs +{ + int count; + int length; + char *stab[1]; +}; + +EXTERN struct pending_stabs *global_stabs; + +/* The type code that process_one_symbol saw on its previous invocation. + Used to detect pairs of N_SO symbols. */ + +EXTERN int previous_stab_code; + +/* Support for Sun changes to dbx symbol format */ + +/* For each identified header file, we have a table of types defined + in that header file. + + header_files maps header file names to their type tables. + It is a vector of n_header_files elements. + Each element describes one header file. + It contains a vector of types. + + Sometimes it can happen that the same header file produces + different results when included in different places. + This can result from conditionals or from different + things done before including the file. + When this happens, there are multiple entries for the file in this table, + one entry for each distinct set of results. + The entries are distinguished by the INSTANCE field. + The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is + used to match header-file references to their corresponding data. */ + +struct header_file +{ + + /* Name of header file */ + + char *name; + + /* Numeric code distinguishing instances of one header file that produced + different results when included. It comes from the N_BINCL or N_EXCL. */ + + int instance; + + /* Pointer to vector of types */ + + struct type **vector; + + /* Allocated length (# elts) of that vector */ + + int length; + +}; + +EXTERN struct header_file *header_files; + +EXTERN int n_header_files; + +EXTERN int n_allocated_header_files; + +/* Within each object file, various header files are assigned numbers. + A type is defined or referred to with a pair of numbers + (FILENUM,TYPENUM) where FILENUM is the number of the header file + and TYPENUM is the number within that header file. + TYPENUM is the index within the vector of types for that header file. + + FILENUM == 1 is special; it refers to the main source of the object file, + and not to any header file. FILENUM != 1 is interpreted by looking it up + in the following table, which contains indices in header_files. */ + +EXTERN int *this_object_header_files; + +EXTERN int n_this_object_header_files; + +EXTERN int n_allocated_this_object_header_files; + +extern struct complaint unknown_symtype_complaint; +extern struct complaint unknown_symchar_complaint; + +extern struct type * +read_type PARAMS ((char **, struct objfile *)); + +extern void +cleanup_undefined_types PARAMS ((void)); + +extern struct type ** +dbx_lookup_type PARAMS ((int [2])); + +extern long +read_number PARAMS ((char **, int)); + +extern void +add_undefined_type PARAMS ((struct type *)); + +extern struct symbol * +define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *)); + +extern void +stabsread_init PARAMS ((void)); + +extern void +stabsread_new_init PARAMS ((void)); + +extern void +start_stabs PARAMS ((void)); + +extern void +end_stabs PARAMS ((void)); + +extern void +finish_global_stabs PARAMS ((struct objfile *objfile)); + +EXTERN int os9k_stabs; + +/* COFF files can have multiple .stab sections, if they are linked + using --split-by-reloc. This linked list is used to pass the + information into the functions in dbxread.c. */ +struct stab_section_list +{ + /* Next in list. */ + struct stab_section_list *next; + + /* Stab section. */ + asection *section; +}; + +/* Functions exported by dbxread.c. These are not in stabsread.c because + they are only used by some stabs readers. */ + +extern struct partial_symtab * +start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *, + CORE_ADDR, int, struct partial_symbol **, + struct partial_symbol **)); + +extern struct partial_symtab * +end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR, + struct partial_symtab **, int)); + +extern void +process_one_symbol PARAMS ((int, int, CORE_ADDR, char *, + struct section_offsets *, struct objfile *)); + +extern void elfstab_build_psymtabs + PARAMS ((struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, + file_ptr staboff, unsigned int stabsize, + file_ptr stabstroffset, + unsigned int stabstrsize)); + +extern void coffstab_build_psymtabs + PARAMS ((struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, + CORE_ADDR textaddr, unsigned int textsize, + struct stab_section_list *stabs, + file_ptr stabstroffset, + unsigned int stabstrsize)); + +extern void stabsect_build_psymtabs + PARAMS ((struct objfile *objfile, + struct section_offsets *section_offsets, + int mainline, + char *stab_name, + char *stabstr_name, + char *text_name)); + +extern void elfstab_offset_sections PARAMS ((struct objfile *, + struct partial_symtab *)); + +#undef EXTERN diff --git a/contrib/gdb/gdb/stack.c b/contrib/gdb/gdb/stack.c new file mode 100644 index 000000000000..be52e98cc04e --- /dev/null +++ b/contrib/gdb/gdb/stack.c @@ -0,0 +1,1502 @@ +/* Print and select stack frames for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "defs.h" +#include "gdb_string.h" +#include "value.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "frame.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "target.h" +#include "breakpoint.h" +#include "demangle.h" +#include "inferior.h" +#include "annotate.h" +#include "symfile.h" +#include "objfiles.h" + +static void return_command PARAMS ((char *, int)); + +static void down_command PARAMS ((char *, int)); + +static void down_silently_command PARAMS ((char *, int)); + +static void up_command PARAMS ((char *, int)); + +static void up_silently_command PARAMS ((char *, int)); + +static void frame_command PARAMS ((char *, int)); + +static void select_frame_command PARAMS ((char *, int)); + +static void args_info PARAMS ((char *, int)); + +static void print_frame_arg_vars PARAMS ((struct frame_info *, GDB_FILE *)); + +static void catch_info PARAMS ((char *, int)); + +static void locals_info PARAMS ((char *, int)); + +static void print_frame_label_vars PARAMS ((struct frame_info *, int, + GDB_FILE *)); + +static void print_frame_local_vars PARAMS ((struct frame_info *, GDB_FILE *)); + +static int print_block_frame_labels PARAMS ((struct block *, int *, + GDB_FILE *)); + +static int print_block_frame_locals PARAMS ((struct block *, + struct frame_info *, + GDB_FILE *)); + +static void backtrace_command PARAMS ((char *, int)); + +static struct frame_info *parse_frame_specification PARAMS ((char *)); + +static void frame_info PARAMS ((char *, int)); + +extern int addressprint; /* Print addresses, or stay symbolic only? */ +extern int info_verbose; /* Verbosity of symbol reading msgs */ +extern int lines_to_list; /* # of lines "list" command shows by default */ + +/* The "selected" stack frame is used by default for local and arg access. + May be zero, for no selected frame. */ + +struct frame_info *selected_frame; + +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +int selected_frame_level; + +/* Zero means do things normally; we are interacting directly with the + user. One means print the full filename and linenumber when a + frame is printed, and do so in a format emacs18/emacs19.22 can + parse. Two means print similar annotations, but in many more + cases and in a slightly different syntax. */ + +int annotation_level = 0; + + +struct print_stack_frame_args { + struct frame_info *fi; + int level; + int source; + int args; +}; + +static int print_stack_frame_stub PARAMS ((char *)); + +/* Pass the args the way catch_errors wants them. */ +static int +print_stack_frame_stub (args) + char *args; +{ + struct print_stack_frame_args *p = (struct print_stack_frame_args *)args; + + print_frame_info (p->fi, p->level, p->source, p->args); + return 0; +} + +/* Print a stack frame briefly. FRAME_INFI should be the frame info + and LEVEL should be its level in the stack (or -1 for level not defined). + This prints the level, the function executing, the arguments, + and the file name and line number. + If the pc is not at the beginning of the source line, + the actual pc is printed at the beginning. + + If SOURCE is 1, print the source line as well. + If SOURCE is -1, print ONLY the source line. */ + +void +print_stack_frame (fi, level, source) + struct frame_info *fi; + int level; + int source; +{ + struct print_stack_frame_args args; + + args.fi = fi; + args.level = level; + args.source = source; + args.args = 1; + + catch_errors (print_stack_frame_stub, (char *)&args, "", RETURN_MASK_ALL); +} + +struct print_args_args { + struct symbol *func; + struct frame_info *fi; +}; + +static int print_args_stub PARAMS ((char *)); + +/* Pass the args the way catch_errors wants them. */ + +static int +print_args_stub (args) + char *args; +{ + int numargs; + struct print_args_args *p = (struct print_args_args *)args; + + FRAME_NUM_ARGS (numargs, (p->fi)); + print_frame_args (p->func, p->fi, numargs, gdb_stdout); + return 0; +} + +/* LEVEL is the level of the frame, or -1 if it is the innermost frame + but we don't want to print the level. */ + +void +print_frame_info (fi, level, source, args) + struct frame_info *fi; + register int level; + int source; + int args; +{ + struct symtab_and_line sal; + struct symbol *func; + register char *funname = 0; + enum language funlang = language_unknown; + +#if 0 + char buf[MAX_REGISTER_RAW_SIZE]; + CORE_ADDR sp; + + /* On the 68k, this spends too much time in m68k_find_saved_regs. */ + + /* Get the value of SP_REGNUM relative to the frame. */ + get_saved_register (buf, (int *)NULL, (CORE_ADDR *)NULL, + FRAME_INFO_ID (fi), SP_REGNUM, (enum lval_type *)NULL); + sp = extract_address (buf, REGISTER_RAW_SIZE (SP_REGNUM)); + + /* This is not a perfect test, because if a function alloca's some + memory, puts some code there, and then jumps into it, then the test + will succeed even though there is no call dummy. Probably best is + to check for a bp_call_dummy breakpoint. */ + if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame)) +#else + if (frame_in_dummy (fi)) +#endif + { + annotate_frame_begin (level == -1 ? 0 : level, fi->pc); + + /* Do this regardless of SOURCE because we don't have any source + to list for this frame. */ + if (level >= 0) + printf_filtered ("#%-2d ", level); + annotate_function_call (); + printf_filtered ("\n"); + annotate_frame_end (); + return; + } + if (fi->signal_handler_caller) + { + annotate_frame_begin (level == -1 ? 0 : level, fi->pc); + + /* Do this regardless of SOURCE because we don't have any source + to list for this frame. */ + if (level >= 0) + printf_filtered ("#%-2d ", level); + annotate_signal_handler_caller (); + printf_filtered ("\n"); + annotate_frame_end (); + return; + } + + /* If fi is not the innermost frame, that normally means that fi->pc + points to *after* the call instruction, and we want to get the line + containing the call, never the next line. But if the next frame is + a signal_handler_caller or a dummy frame, then the next frame was + not entered as the result of a call, and we want to get the line + containing fi->pc. */ + sal = + find_pc_line (fi->pc, + fi->next != NULL + && !fi->next->signal_handler_caller + && !frame_in_dummy (fi->next)); + + func = find_pc_function (fi->pc); + 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). This also occurs if the user uses asm() to create + a function but not stabs for it (in a file compiled -g). + + 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; if this is + ever changed many parts of GDB will need to be changed (and we'll + create a find_pc_minimal_function or some such). */ + + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL + && (SYMBOL_VALUE_ADDRESS (msymbol) + > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) + { +#if 0 + /* There is no particular reason to think the line number + information is wrong. Someone might have just put in + a label with asm() but left the line numbers alone. */ + /* In this case we have no way of knowing the source file + and line number, so don't print them. */ + sal.symtab = 0; +#endif + /* We also don't know anything about the function besides + its address and name. */ + func = 0; + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + else + { + funname = SYMBOL_NAME (func); + funlang = SYMBOL_LANGUAGE (func); + } + } + else + { + if (find_pc_section (fi->pc)) + { + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL) + { + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + } + } + + if (source >= 0 || !sal.symtab) + { + annotate_frame_begin (level == -1 ? 0 : level, fi->pc); + + if (level >= 0) + printf_filtered ("#%-2d ", level); + if (addressprint) + if (fi->pc != sal.pc || !sal.symtab) + { + annotate_frame_address (); + print_address_numeric (fi->pc, 1, gdb_stdout); + annotate_frame_address_end (); + printf_filtered (" in "); + } + annotate_frame_function_name (); + fprintf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang, + DMGL_ANSI); + wrap_here (" "); + annotate_frame_args (); + fputs_filtered (" (", gdb_stdout); + if (args) + { + struct print_args_args args; + args.fi = fi; + args.func = func; + catch_errors (print_args_stub, (char *)&args, "", RETURN_MASK_ALL); + QUIT; + } + printf_filtered (")"); + if (sal.symtab && sal.symtab->filename) + { + annotate_frame_source_begin (); + wrap_here (" "); + printf_filtered (" at "); + annotate_frame_source_file (); + printf_filtered ("%s", sal.symtab->filename); + annotate_frame_source_file_end (); + printf_filtered (":"); + annotate_frame_source_line (); + printf_filtered ("%d", sal.line); + annotate_frame_source_end (); + } + +#ifdef PC_LOAD_SEGMENT + /* If we couldn't print out function name but if can figure out what + load segment this pc value is from, at least print out some info + about its load segment. */ + if (!funname) + { + annotate_frame_where (); + wrap_here (" "); + printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc)); + } +#endif +#ifdef PC_SOLIB + if (!funname) + { + char *lib = PC_SOLIB (fi->pc); + if (lib) + { + annotate_frame_where (); + wrap_here (" "); + printf_filtered (" from %s", lib); + } + } +#endif + printf_filtered ("\n"); + } + + if ((source != 0) && sal.symtab) + { + int done = 0; + int mid_statement = source < 0 && fi->pc != sal.pc; + if (annotation_level) + done = identify_source_line (sal.symtab, sal.line, mid_statement, + fi->pc); + if (!done) + { + if (addressprint && mid_statement) + { + print_address_numeric (fi->pc, 1, gdb_stdout); + printf_filtered ("\t"); + } + if (print_frame_info_listing_hook) + print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0); + else + print_source_lines (sal.symtab, sal.line, sal.line + 1, 0); + } + current_source_line = max (sal.line - lines_to_list/2, 1); + } + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + annotate_frame_end (); + + gdb_flush (gdb_stdout); +} + +/* Read a frame specification in whatever the appropriate format is. + Call error() if the specification is in any way invalid (i.e. + this function never returns NULL). */ + +static struct frame_info * +parse_frame_specification (frame_exp) + char *frame_exp; +{ + int numargs = 0; +#define MAXARGS 4 + CORE_ADDR args[MAXARGS]; + + if (frame_exp) + { + char *addr_string, *p; + struct cleanup *tmp_cleanup; + + while (*frame_exp == ' ') frame_exp++; + + while (*frame_exp) + { + if (numargs > MAXARGS) + error ("Too many args in frame specification"); + /* Parse an argument. */ + for (p = frame_exp; *p && *p != ' '; p++) + ; + addr_string = savestring(frame_exp, p - frame_exp); + + { + tmp_cleanup = make_cleanup (free, addr_string); + args[numargs++] = parse_and_eval_address (addr_string); + do_cleanups (tmp_cleanup); + } + + /* Skip spaces, move to possible next arg. */ + while (*p == ' ') p++; + frame_exp = p; + } + } + + switch (numargs) + { + case 0: + if (selected_frame == NULL) + error ("No selected frame."); + return selected_frame; + /* NOTREACHED */ + case 1: + { + int level = args[0]; + struct frame_info *fid = + find_relative_frame (get_current_frame (), &level); + struct frame_info *tfid; + + if (level == 0) + /* find_relative_frame was successful */ + return fid; + + /* If SETUP_ARBITRARY_FRAME is defined, then frame specifications + take at least 2 addresses. It is important to detect this case + here so that "frame 100" does not give a confusing error message + like "frame specification requires two addresses". This of course + does not solve the "frame 100" problem for machines on which + a frame specification can be made with one address. To solve + that, we need a new syntax for a specifying a frame by address. + I think the cleanest syntax is $frame(0x45) ($frame(0x23,0x45) for + two args, etc.), but people might think that is too much typing, + so I guess *0x23,0x45 would be a possible alternative (commas + really should be used instead of spaces to delimit; using spaces + normally works in an expression). */ +#ifdef SETUP_ARBITRARY_FRAME + error ("No frame %d", args[0]); +#endif + + /* If (s)he specifies the frame with an address, he deserves what + (s)he gets. Still, give the highest one that matches. */ + + for (fid = get_current_frame (); + fid && fid->frame != args[0]; + fid = get_prev_frame (fid)) + ; + + if (fid) + while ((tfid = get_prev_frame (fid)) && + (tfid->frame == args[0])) + fid = tfid; + + /* We couldn't identify the frame as an existing frame, but + perhaps we can create one with a single argument. */ + } + + default: +#ifdef SETUP_ARBITRARY_FRAME + return SETUP_ARBITRARY_FRAME (numargs, args); +#else + /* Usual case. Do it here rather than have everyone supply + a SETUP_ARBITRARY_FRAME that does this. */ + if (numargs == 1) + return create_new_frame (args[0], 0); + error ("Too many args in frame specification"); +#endif + /* NOTREACHED */ + } + /* NOTREACHED */ +} + +/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except + that if it is unsure about the answer, it returns 0 + instead of guessing (this happens on the VAX and i960, for example). + + On most machines, we never have to guess about the args address, + so FRAME_ARGS_ADDRESS{,_CORRECT} are the same. */ +#if !defined (FRAME_ARGS_ADDRESS_CORRECT) +#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS +#endif + +/* Print verbosely the selected frame or the frame at address ADDR. + This means absolutely all information in the frame is printed. */ + +static void +frame_info (addr_exp, from_tty) + char *addr_exp; + int from_tty; +{ + struct frame_info *fi; + struct frame_saved_regs fsr; + struct symtab_and_line sal; + struct symbol *func; + struct symtab *s; + struct frame_info *calling_frame_info; + int i, count, numregs; + char *funname = 0; + enum language funlang = language_unknown; + + if (!target_has_stack) + error ("No stack."); + + fi = parse_frame_specification (addr_exp); + if (fi == NULL) + error ("Invalid frame specified."); + + sal = find_pc_line (fi->pc, + fi->next != NULL + && !fi->next->signal_handler_caller + && !frame_in_dummy (fi->next)); + func = get_frame_function (fi); + s = find_pc_symtab(fi->pc); + if (func) + { + funname = SYMBOL_NAME (func); + funlang = SYMBOL_LANGUAGE (func); + } + else + { + register struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); + if (msymbol != NULL) + { + funname = SYMBOL_NAME (msymbol); + funlang = SYMBOL_LANGUAGE (msymbol); + } + } + calling_frame_info = get_prev_frame (fi); + + if (!addr_exp && selected_frame_level >= 0) + { + printf_filtered ("Stack level %d, frame at ", selected_frame_level); + print_address_numeric (fi->frame, 1, gdb_stdout); + printf_filtered (":\n"); + } + else + { + printf_filtered ("Stack frame at "); + print_address_numeric (fi->frame, 1, gdb_stdout); + printf_filtered (":\n"); + } + printf_filtered (" %s = ", reg_names[PC_REGNUM]); + print_address_numeric (fi->pc, 1, gdb_stdout); + + wrap_here (" "); + if (funname) + { + printf_filtered (" in "); + fprintf_symbol_filtered (gdb_stdout, funname, funlang, + DMGL_ANSI | DMGL_PARAMS); + } + wrap_here (" "); + if (sal.symtab) + printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line); + puts_filtered ("; "); + wrap_here (" "); + printf_filtered ("saved %s ", reg_names[PC_REGNUM]); + print_address_numeric (FRAME_SAVED_PC (fi), 1, gdb_stdout); + printf_filtered ("\n"); + + { + int frameless = 0; +#ifdef FRAMELESS_FUNCTION_INVOCATION + FRAMELESS_FUNCTION_INVOCATION (fi, frameless); +#endif + if (frameless) + printf_filtered (" (FRAMELESS),"); + } + + if (calling_frame_info) + { + printf_filtered (" called by frame at "); + print_address_numeric (calling_frame_info->frame, 1, gdb_stdout); + } + if (fi->next && calling_frame_info) + puts_filtered (","); + wrap_here (" "); + if (fi->next) + { + printf_filtered (" caller of frame at "); + print_address_numeric (fi->next->frame, 1, gdb_stdout); + } + if (fi->next || calling_frame_info) + puts_filtered ("\n"); + if (s) + printf_filtered (" source language %s.\n", language_str (s->language)); + +#ifdef PRINT_EXTRA_FRAME_INFO + PRINT_EXTRA_FRAME_INFO (fi); +#endif + + { + /* Address of the argument list for this frame, or 0. */ + CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi); + /* Number of args for this frame, or -1 if unknown. */ + int numargs; + + if (arg_list == 0) + printf_filtered (" Arglist at unknown address.\n"); + else + { + printf_filtered (" Arglist at "); + print_address_numeric (arg_list, 1, gdb_stdout); + printf_filtered (","); + + FRAME_NUM_ARGS (numargs, fi); + if (numargs < 0) + puts_filtered (" args: "); + else if (numargs == 0) + puts_filtered (" no args."); + else if (numargs == 1) + puts_filtered (" 1 arg: "); + else + printf_filtered (" %d args: ", numargs); + print_frame_args (func, fi, numargs, gdb_stdout); + puts_filtered ("\n"); + } + } + { + /* Address of the local variables for this frame, or 0. */ + CORE_ADDR arg_list = FRAME_LOCALS_ADDRESS (fi); + + if (arg_list == 0) + printf_filtered (" Locals at unknown address,"); + else + { + printf_filtered (" Locals at "); + print_address_numeric (arg_list, 1, gdb_stdout); + printf_filtered (","); + } + } + +#if defined (FRAME_FIND_SAVED_REGS) + get_frame_saved_regs (fi, &fsr); + /* The sp is special; what's returned isn't the save address, but + actually the value of the previous frame's sp. */ + printf_filtered (" Previous frame's sp is "); + print_address_numeric (fsr.regs[SP_REGNUM], 1, gdb_stdout); + printf_filtered ("\n"); + count = 0; + numregs = ARCH_NUM_REGS; + for (i = 0; i < numregs; i++) + if (fsr.regs[i] && i != SP_REGNUM) + { + if (count == 0) + puts_filtered (" Saved registers:\n "); + else + puts_filtered (","); + wrap_here (" "); + printf_filtered (" %s at ", reg_names[i]); + print_address_numeric (fsr.regs[i], 1, gdb_stdout); + count++; + } + if (count) + puts_filtered ("\n"); +#else /* Have FRAME_FIND_SAVED_REGS. */ + /* We could get some information about saved registers by calling + get_saved_register on each register. Which info goes with which frame + is necessarily lost, however, and I suspect that the users don't care + whether they get the info. */ + puts_filtered ("\n"); +#endif /* Have FRAME_FIND_SAVED_REGS. */ +} + +#if 0 +/* Set a limit on the number of frames printed by default in a + backtrace. */ + +static int backtrace_limit; + +static void +set_backtrace_limit_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + int count = parse_and_eval_address (count_exp); + + if (count < 0) + error ("Negative argument not meaningful as backtrace limit."); + + backtrace_limit = count; +} + +static void +backtrace_limit_info (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) + error ("\"Info backtrace-limit\" takes no arguments."); + + printf_unfiltered ("Backtrace limit: %d.\n", backtrace_limit); +} +#endif + +/* Print briefly all stack frames or just the innermost COUNT frames. */ + +static void +backtrace_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + struct frame_info *fi; + register int count; + register int i; + register struct frame_info *trailing; + register int trailing_level; + + if (!target_has_stack) + error ("No stack."); + + /* The following code must do two things. First, it must + set the variable TRAILING to the frame from which we should start + printing. Second, it must set the variable count to the number + of frames which we should print, or -1 if all of them. */ + trailing = get_current_frame (); + trailing_level = 0; + if (count_exp) + { + count = parse_and_eval_address (count_exp); + if (count < 0) + { + struct frame_info *current; + + count = -count; + + current = trailing; + while (current && count--) + { + QUIT; + current = get_prev_frame (current); + } + + /* Will stop when CURRENT reaches the top of the stack. TRAILING + will be COUNT below it. */ + while (current) + { + QUIT; + trailing = get_prev_frame (trailing); + current = get_prev_frame (current); + trailing_level++; + } + + count = -1; + } + } + else + count = -1; + + if (info_verbose) + { + struct partial_symtab *ps; + + /* Read in symbols for all of the frames. Need to do this in + a separate pass so that "Reading in symbols for xxx" messages + don't screw up the appearance of the backtrace. Also + if people have strong opinions against reading symbols for + backtrace this may have to be an option. */ + i = count; + for (fi = trailing; + fi != NULL && i--; + fi = get_prev_frame (fi)) + { + QUIT; + ps = find_pc_psymtab (fi->pc); + if (ps) + PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in */ + } + } + + for (i = 0, fi = trailing; + fi && count--; + i++, fi = get_prev_frame (fi)) + { + QUIT; + + /* Don't use print_stack_frame; if an error() occurs it probably + means further attempts to backtrace would fail (on the other + hand, perhaps the code does or could be fixed to make sure + the frame->prev field gets set to NULL in that case). */ + print_frame_info (fi, trailing_level + i, 0, 1); + } + + /* If we've stopped before the end, mention that. */ + if (fi && from_tty) + printf_filtered ("(More stack frames follow...)\n"); +} + +/* Print the local variables of a block B active in FRAME. + Return 1 if any variables were printed; 0 otherwise. */ + +static int +print_block_frame_locals (b, fi, stream) + struct block *b; + register struct frame_info *fi; + register GDB_FILE *stream; +{ + int nsyms; + register int i; + register struct symbol *sym; + register int values_printed = 0; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_LOCAL: + case LOC_REGISTER: + case LOC_STATIC: + case LOC_BASEREG: + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + fputs_filtered (" = ", stream); + print_variable_value (sym, fi, stream); + fprintf_filtered (stream, "\n"); + break; + + default: + /* Ignore symbols which are not locals. */ + break; + } + } + return values_printed; +} + +/* Same, but print labels. */ + +static int +print_block_frame_labels (b, have_default, stream) + struct block *b; + int *have_default; + register GDB_FILE *stream; +{ + int nsyms; + register int i; + register struct symbol *sym; + register int values_printed = 0; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (STREQ (SYMBOL_NAME (sym), "default")) + { + if (*have_default) + continue; + *have_default = 1; + } + if (SYMBOL_CLASS (sym) == LOC_LABEL) + { + struct symtab_and_line sal; + sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0); + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + if (addressprint) + { + fprintf_filtered (stream, " "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, stream); + } + fprintf_filtered (stream, " in file %s, line %d\n", + sal.symtab->filename, sal.line); + } + } + return values_printed; +} + +/* Print on STREAM all the local variables in frame FRAME, + including all the blocks active in that frame + at its current pc. + + Returns 1 if the job was done, + or 0 if nothing was printed because we have no info + on the function running in FRAME. */ + +static void +print_frame_local_vars (fi, stream) + register struct frame_info *fi; + register GDB_FILE *stream; +{ + register struct block *block = get_frame_block (fi); + register int values_printed = 0; + + if (block == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + while (block != 0) + { + if (print_block_frame_locals (block, fi, stream)) + values_printed = 1; + /* After handling the function's top-level block, stop. + Don't continue to its superblock, the block of + per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + if (!values_printed) + { + fprintf_filtered (stream, "No locals.\n"); + } +} + +/* Same, but print labels. */ + +static void +print_frame_label_vars (fi, this_level_only, stream) + register struct frame_info *fi; + int this_level_only; + register GDB_FILE *stream; +{ + register struct blockvector *bl; + register struct block *block = get_frame_block (fi); + register int values_printed = 0; + int index, have_default = 0; + char *blocks_printed; + CORE_ADDR pc = fi->pc; + + if (block == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + bl = blockvector_for_pc (BLOCK_END (block) - 4, &index); + blocks_printed = (char *) 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 (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. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + if (!values_printed && !this_level_only) + { + fprintf_filtered (stream, "No catches.\n"); + } +} + +/* ARGSUSED */ +static void +locals_info (args, from_tty) + char *args; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_local_vars (selected_frame, gdb_stdout); +} + +static void +catch_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_label_vars (selected_frame, 0, gdb_stdout); +} + +static void +print_frame_arg_vars (fi, stream) + register struct frame_info *fi; + register GDB_FILE *stream; +{ + struct symbol *func = get_frame_function (fi); + register struct block *b; + int nsyms; + register int i; + register struct symbol *sym, *sym2; + register int values_printed = 0; + + if (func == 0) + { + fprintf_filtered (stream, "No symbol table info available.\n"); + return; + } + + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_LOCAL_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + values_printed = 1; + fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream); + fputs_filtered (" = ", stream); + + /* We have to look up the symbol because arguments can have + two entries (one a parameter, one a local) and the one we + want is the local, which lookup_symbol will find for us. + This includes gcc1 (not gcc2) on the sparc when passing a + small structure and gcc2 when the argument type is float + and it is passed as a double and converted to float by + the prologue (in the latter case the type of the LOC_ARG + symbol is double and the type of the LOC_LOCAL symbol is + float). There are also LOC_ARG/LOC_REGISTER pairs which + are not combined in symbol-reading. */ + + sym2 = lookup_symbol (SYMBOL_NAME (sym), + b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL); + print_variable_value (sym2, fi, stream); + fprintf_filtered (stream, "\n"); + break; + + default: + /* Don't worry about things which aren't arguments. */ + break; + } + } + + if (!values_printed) + { + fprintf_filtered (stream, "No arguments.\n"); + } +} + +static void +args_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + if (!selected_frame) + error ("No frame selected."); + print_frame_arg_vars (selected_frame, gdb_stdout); +} + +/* Select frame FI, and note that its stack level is LEVEL. + LEVEL may be -1 if an actual level number is not known. */ + +void +select_frame (fi, level) + struct frame_info *fi; + int level; +{ + register struct symtab *s; + + selected_frame = fi; + selected_frame_level = level; + + /* Ensure that symbols for this frame are read in. Also, determine the + source language of this frame, and switch to it if desired. */ + if (fi) + { + s = find_pc_symtab (fi->pc); + if (s + && s->language != current_language->la_language + && s->language != language_unknown + && language_mode == language_mode_auto) { + set_language(s->language); + } + } +} + +/* Store the selected frame and its level into *FRAMEP and *LEVELP. + If there is no selected frame, *FRAMEP is set to NULL. */ + +void +record_selected_frame (frameaddrp, levelp) + CORE_ADDR *frameaddrp; + int *levelp; +{ + *frameaddrp = selected_frame ? selected_frame->frame : 0; + *levelp = selected_frame_level; +} + +/* Return the symbol-block in which the selected frame is executing. + Can return zero under various legitimate circumstances. */ + +struct block * +get_selected_block () +{ + if (!target_has_stack) + return 0; + + if (!selected_frame) + return get_current_block (); + return get_frame_block (selected_frame); +} + +/* Find a frame a certain number of levels away from FRAME. + LEVEL_OFFSET_PTR points to an int containing the number of levels. + Positive means go to earlier frames (up); negative, the reverse. + The int that contains the number of levels is counted toward + zero as the frames for those levels are found. + If the top or bottom frame is reached, that frame is returned, + but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates + how much farther the original request asked to go. */ + +struct frame_info * +find_relative_frame (frame, level_offset_ptr) + register struct frame_info *frame; + register int *level_offset_ptr; +{ + register struct frame_info *prev; + register struct frame_info *frame1; + + /* Going up is simple: just do get_prev_frame enough times + or until initial frame is reached. */ + while (*level_offset_ptr > 0) + { + prev = get_prev_frame (frame); + if (prev == 0) + break; + (*level_offset_ptr)--; + frame = prev; + } + /* Going down is just as simple. */ + if (*level_offset_ptr < 0) + { + while (*level_offset_ptr < 0) { + frame1 = get_next_frame (frame); + if (!frame1) + break; + frame = frame1; + (*level_offset_ptr)++; + } + } + return frame; +} + +/* The "select_frame" command. With no arg, NOP. + With arg LEVEL_EXP, select the frame at level LEVEL if it is a + valid level. Otherwise, treat level_exp as an address expression + and select it. See parse_frame_specification for more info on proper + frame expressions. */ + +/* ARGSUSED */ +static void +select_frame_command (level_exp, from_tty) + char *level_exp; + int from_tty; +{ + register struct frame_info *frame, *frame1; + unsigned int level = 0; + + if (!target_has_stack) + error ("No stack."); + + frame = parse_frame_specification (level_exp); + + /* Try to figure out what level this frame is. But if there is + no current stack, don't error out -- let the user set one. */ + frame1 = 0; + if (get_current_frame()) { + for (frame1 = get_prev_frame (0); + frame1 && frame1 != frame; + frame1 = get_prev_frame (frame1)) + level++; + } + + if (!frame1) + level = 0; + + select_frame (frame, level); +} + +/* The "frame" command. With no arg, print selected frame briefly. + With arg, behaves like select_frame and then prints the selected + frame. */ + +static void +frame_command (level_exp, from_tty) + char *level_exp; + int from_tty; +{ + select_frame_command (level_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame up one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +/* ARGSUSED */ +static void +up_silently_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + register struct frame_info *fi; + int count = 1, count1; + if (count_exp) + count = parse_and_eval_address (count_exp); + count1 = count; + + if (target_has_stack == 0 || selected_frame == 0) + error ("No stack."); + + fi = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + error ("Initial frame selected; you cannot go up."); + select_frame (fi, selected_frame_level + count - count1); +} + +static void +up_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + up_silently_command (count_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame down one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +/* ARGSUSED */ +static void +down_silently_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + register struct frame_info *frame; + int count = -1, count1; + if (count_exp) + count = - parse_and_eval_address (count_exp); + count1 = count; + + if (target_has_stack == 0 || selected_frame == 0) + error ("No stack."); + + frame = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + { + + /* We only do this if count_exp is not specified. That way "down" + means to really go down (and let me know if that is + impossible), but "down 9999" can be used to mean go all the way + down without getting an error. */ + + error ("Bottom (i.e., innermost) frame selected; you cannot go down."); + } + + select_frame (frame, selected_frame_level + count - count1); +} + + +static void +down_command (count_exp, from_tty) + char *count_exp; + int from_tty; +{ + down_silently_command (count_exp, from_tty); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +static void +return_command (retval_exp, from_tty) + char *retval_exp; + int from_tty; +{ + struct symbol *thisfun; + CORE_ADDR selected_frame_addr; + CORE_ADDR selected_frame_pc; + struct frame_info *frame; + value_ptr return_value = NULL; + + if (selected_frame == NULL) + error ("No selected frame."); + thisfun = get_frame_function (selected_frame); + selected_frame_addr = FRAME_FP (selected_frame); + selected_frame_pc = selected_frame->pc; + + /* Compute the return value (if any -- possibly getting errors here). */ + + if (retval_exp) + { + struct type *return_type = NULL; + + return_value = parse_and_eval (retval_exp); + + /* Cast return value to the return type of the function. */ + if (thisfun != NULL) + return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun)); + if (return_type == NULL) + return_type = builtin_type_int; + return_value = value_cast (return_type, return_value); + + /* Make sure we have fully evaluated it, since + it might live in the stack frame we're about to pop. */ + if (VALUE_LAZY (return_value)) + value_fetch_lazy (return_value); + } + + /* If interactive, require confirmation. */ + + if (from_tty) + { + if (thisfun != 0) + { + if (!query ("Make %s return now? ", SYMBOL_SOURCE_NAME (thisfun))) + { + error ("Not confirmed."); + /* NOTREACHED */ + } + } + else + if (!query ("Make selected stack frame return now? ")) + error ("Not confirmed."); + } + + /* Do the real work. Pop until the specified frame is current. We + use this method because the selected_frame is not valid after + a POP_FRAME. The pc comparison makes this work even if the + selected frame shares its fp with another frame. */ + + while (selected_frame_addr != (frame = get_current_frame())->frame + || selected_frame_pc != frame->pc) + POP_FRAME; + + /* Then pop that frame. */ + + POP_FRAME; + + /* Compute the return value (if any) and store in the place + for return values. */ + + if (retval_exp) + set_return_value (return_value); + + /* If interactive, print the frame that is now current. */ + + if (from_tty) + frame_command ("0", 1); + else + select_frame_command ("0", 0); +} + +/* Gets the language of the current frame. */ + +enum language +get_frame_language() +{ + register struct symtab *s; + enum language flang; /* The language of the current frame */ + + if (selected_frame) + { + s = find_pc_symtab(selected_frame->pc); + if (s) + flang = s->language; + else + flang = language_unknown; + } + else + flang = language_unknown; + + return flang; +} + +void +_initialize_stack () +{ +#if 0 + backtrace_limit = 30; +#endif + + add_com ("return", class_stack, return_command, + "Make selected stack frame return to its caller.\n\ +Control remains in the debugger, but when you continue\n\ +execution will resume in the frame above the one now selected.\n\ +If an argument is given, it is an expression for the value to return."); + + add_com ("up", class_stack, up_command, + "Select and print stack frame that called this one.\n\ +An argument says how many frames up to go."); + add_com ("up-silently", class_support, up_silently_command, + "Same as the `up' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("down", class_stack, down_command, + "Select and print stack frame called by this one.\n\ +An argument says how many frames down to go."); + add_com_alias ("do", "down", class_stack, 1); + add_com_alias ("dow", "down", class_stack, 1); + add_com ("down-silently", class_support, down_silently_command, + "Same as the `down' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("frame", class_stack, frame_command, + "Select and print a stack frame.\n\ +With no argument, print the selected stack frame. (See also \"info frame\").\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n\ +With argument, nothing is printed if input is coming from\n\ +a command file or a user-defined command."); + + add_com_alias ("f", "frame", class_stack, 1); + + add_com ("select-frame", class_stack, select_frame_command, + "Select a stack frame without printing anything.\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n"); + + add_com ("backtrace", class_stack, backtrace_command, + "Print backtrace of all stack frames, or innermost COUNT frames.\n\ +With a negative argument, print outermost -COUNT frames."); + add_com_alias ("bt", "backtrace", class_stack, 0); + add_com_alias ("where", "backtrace", class_alias, 0); + add_info ("stack", backtrace_command, + "Backtrace of the stack, or innermost COUNT frames."); + add_info_alias ("s", "stack", 1); + add_info ("frame", frame_info, + "All about selected stack frame, or frame at ADDR."); + add_info_alias ("f", "frame", 1); + add_info ("locals", locals_info, + "Local variables of current stack frame."); + add_info ("args", args_info, + "Argument variables of current stack frame."); + add_info ("catch", catch_info, + "Exceptions that can be caught in the current stack frame."); + +#if 0 + add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command, + "Specify maximum number of frames for \"backtrace\" to print by default.", + &setlist); + add_info ("backtrace-limit", backtrace_limit_info, + "The maximum number of frames for \"backtrace\" to print by default."); +#endif +} diff --git a/contrib/gdb/gdb/standalone.c b/contrib/gdb/gdb/standalone.c new file mode 100644 index 000000000000..13fc4768b4ed --- /dev/null +++ b/contrib/gdb/gdb/standalone.c @@ -0,0 +1,593 @@ +/* Interface to bare machine for GDB running as kernel debugger. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include "gdb_stat.h" + +#if defined (SIGTSTP) && defined (SIGIO) +#include +#include +#endif /* SIGTSTP and SIGIO defined (must be 4.2) */ + +#include "defs.h" +#include "signals.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + + +/* Random system calls, mostly no-ops to prevent link problems */ + +ioctl (desc, code, arg) +{} + +int (* signal ()) () +{} + +kill () +{} + +getpid () +{ + return 0; +} + +sigsetmask () +{} + +chdir () +{} + +char * +getcwd (buf, len) + char *buf; + unsigned int len; +{ + buf[0] = '/'; + buf[1] = 0; + return buf; +} + +/* Used to check for existence of .gdbinit. Say no. */ + +access () +{ + return -1; +} + +exit () +{ + error ("Fatal error; restarting."); +} + +/* Reading "files". The contents of some files are written into kdb's + data area before it is run. These files are used to contain the + symbol table for kdb to load, and the source files (in case the + kdb user wants to print them). The symbols are stored in a file + named "kdb-symbols" in a.out format (except that all the text and + data have been stripped to save room). + + The files are stored in the following format: + int number of bytes of data for this file, including these four. + char[] name of the file, ending with a null. + padding to multiple of 4 boundary. + char[] file contents. The length can be deduced from what was + specified before. There is no terminating null here. + + If the int at the front is zero, it means there are no more files. + + Opening a file in kdb returns a nonzero value to indicate success, + but the value does not matter. Only one file can be open, and only + for reading. All the primitives for input from the file know + which file is open and ignore what is specified for the descriptor + or for the stdio stream. + + Input with fgetc can be done either on the file that is open + or on stdin (which reads from the terminal through tty_input () */ + +/* Address of data for the files stored in format described above. */ +char *files_start; + +/* The file stream currently open: */ + +char *sourcebeg; /* beginning of contents */ +int sourcesize; /* size of contents */ +char *sourceptr; /* current read pointer */ +int sourceleft; /* number of bytes to eof */ + +/* "descriptor" for the file now open. + Incremented at each close. + If specified descriptor does not match this, + it means the program is trying to use a closed descriptor. + We report an error for that. */ + +int sourcedesc; + +open (filename, modes) + char *filename; + int modes; +{ + register char *next; + + if (modes) + { + errno = EROFS; + return -1; + } + + if (sourceptr) + { + errno = EMFILE; + return -1; + } + + for (next = files_start; * (int *) next; next += * (int *) next) + { + if (!STRCMP (next + 4, filename)) + { + sourcebeg = next + 4 + strlen (next + 4) + 1; + sourcebeg = (char *) (((int) sourcebeg + 3) & (-4)); + sourceptr = sourcebeg; + sourcesize = next + * (int *) next - sourceptr; + sourceleft = sourcesize; + return sourcedesc; + } + } + return 0; +} + +close (desc) + int desc; +{ + sourceptr = 0; + sourcedesc++; + /* Don't let sourcedesc get big enough to be confused with stdin. */ + if (sourcedesc == 100) + sourcedesc = 5; +} + +FILE * +fopen (filename, modes) + char *filename; + char *modes; +{ + return (FILE *) open (filename, *modes == 'w'); +} + +FILE * +fdopen (desc) + int desc; +{ + return (FILE *) desc; +} + +fclose (desc) + int desc; +{ + close (desc); +} + +fstat (desc, statbuf) + struct stat *statbuf; +{ + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + statbuf->st_size = sourcesize; +} + +myread (desc, destptr, size, filename) + int desc; + char *destptr; + int size; + char *filename; +{ + int len = min (sourceleft, size); + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + memcpy (destptr, sourceptr, len); + sourceleft -= len; + return len; +} + +int +fread (bufp, numelts, eltsize, stream) +{ + register int elts = min (numelts, sourceleft / eltsize); + register int len = elts * eltsize; + + if (stream != sourcedesc) + { + errno = EBADF; + return -1; + } + + memcpy (bufp, sourceptr, len); + sourceleft -= len; + return elts; +} + +int +fgetc (desc) + int desc; +{ + + if (desc == (int) stdin) + return tty_input (); + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (sourceleft-- <= 0) + return EOF; + return *sourceptr++; +} + +lseek (desc, pos) + int desc; + int pos; +{ + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (pos < 0 || pos > sourcesize) + { + errno = EINVAL; + return -1; + } + + sourceptr = sourcebeg + pos; + sourceleft = sourcesize - pos; +} + +/* Output in kdb can go only to the terminal, so the stream + specified may be ignored. */ + +printf (a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fprintf (ign, a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fwrite (buf, numelts, size, stream) + register char *buf; + int numelts, size; +{ + register int i = numelts * size; + while (i-- > 0) + fputc (*buf++, stream); +} + +fputc (c, ign) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + display_string (buf); +} + +/* sprintf refers to this, but loading this from the + library would cause fflush to be loaded from it too. + In fact there should be no need to call this (I hope). */ + +_flsbuf () +{ + error ("_flsbuf was actually called."); +} + +fflush (ign) +{ +} + +/* Entries into core and inflow, needed only to make things link ok. */ + +exec_file_command () +{} + +core_file_command () +{} + +char * +get_exec_file (err) + int err; +{ + /* Makes one printout look reasonable; value does not matter otherwise. */ + return "run"; +} + +/* Nonzero if there is a core file. */ + +have_core_file_p () +{ + return 0; +} + +kill_command () +{ + inferior_pid = 0; +} + +terminal_inferior () +{} + +terminal_ours () +{} + +terminal_init_inferior () +{} + +write_inferior_register () +{} + +read_inferior_register () +{} + +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + memcpy (myaddr, memaddr, len); +} + +/* Always return 0 indicating success. */ + +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + memcpy (memaddr, myaddr, len); + return 0; +} + +static REGISTER_TYPE saved_regs[NUM_REGS]; + +REGISTER_TYPE +read_register (regno) + int regno; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + return saved_regs[regno]; +} + +void +write_register (regno, value) + int regno; + REGISTER_TYPE value; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + saved_regs[regno] = value; +} + +/* System calls needed in relation to running the "inferior". */ + +vfork () +{ + /* Just appear to "succeed". Say the inferior's pid is 1. */ + return 1; +} + +/* These are called by code that normally runs in the inferior + that has just been forked. That code never runs, when standalone, + and these definitions are so it will link without errors. */ + +ptrace () +{} + +setpgrp () +{} + +execle () +{} + +_exit () +{} + +/* Malloc calls these. */ + +malloc_warning (str) + char *str; +{ + printf ("\n%s.\n\n", str); +} + +char *next_free; +char *memory_limit; + +char * +sbrk (amount) + int amount; +{ + if (next_free + amount > memory_limit) + return (char *) -1; + next_free += amount; + return next_free - amount; +} + +/* Various ways malloc might ask where end of memory is. */ + +char * +ulimit () +{ + return memory_limit; +} + +int +vlimit () +{ + return memory_limit - next_free; +} + +getrlimit (addr) + struct rlimit *addr; +{ + addr->rlim_cur = memory_limit - next_free; +} + +/* Context switching to and from program being debugged. */ + +/* GDB calls here to run the user program. + The frame pointer for this function is saved in + gdb_stack by save_frame_pointer; then we restore + all of the user program's registers, including PC and PS. */ + +static int fault_code; +static REGISTER_TYPE gdb_stack; + +resume () +{ + REGISTER_TYPE restore[NUM_REGS]; + + PUSH_FRAME_PTR; + save_frame_pointer (); + + memcpy (restore, saved_regs, sizeof restore); + POP_REGISTERS; + /* Control does not drop through here! */ +} + +save_frame_pointer (val) + CORE_ADDR val; +{ + gdb_stack = val; +} + +/* Fault handlers call here, running in the user program stack. + They must first push a fault code, + old PC, old PS, and any other info about the fault. + The exact format is machine-dependent and is known only + in the definition of PUSH_REGISTERS. */ + +fault () +{ + /* Transfer all registers and fault code to the stack + in canonical order: registers in order of GDB register number, + followed by fault code. */ + PUSH_REGISTERS; + + /* Transfer them to saved_regs and fault_code. */ + save_registers (); + + restore_gdb (); + /* Control does not reach here */ +} + +restore_gdb () +{ + CORE_ADDR new_fp = gdb_stack; + /* Switch to GDB's stack */ + POP_FRAME_PTR; + /* Return from the function `resume'. */ +} + +/* Assuming register contents and fault code have been pushed on the stack as + arguments to this function, copy them into the standard place + for the program's registers while GDB is running. */ + +save_registers (firstreg) + int firstreg; +{ + memcpy (saved_regs, &firstreg, sizeof saved_regs); + fault_code = (&firstreg)[NUM_REGS]; +} + +/* Store into the structure such as `wait' would return + the information on why the program faulted, + converted into a machine-independent signal number. */ + +static int fault_table[] = FAULT_TABLE; + +int +wait (w) + WAITTYPE *w; +{ + WSETSTOP (*w, fault_table[fault_code / FAULT_CODE_UNITS]); + return inferior_pid; +} + +/* Allocate a big space in which files for kdb to read will be stored. + Whatever is left is where malloc can allocate storage. + + Initialize it, so that there will be space in the executable file + for it. Then the files can be put into kdb by writing them into + kdb's executable file. */ + +/* The default size is as much space as we expect to be available + for kdb to use! */ + +#ifndef HEAP_SIZE +#define HEAP_SIZE 400000 +#endif + +char heap[HEAP_SIZE] = {0}; + +#ifndef STACK_SIZE +#define STACK_SIZE 100000 +#endif + +int kdb_stack_beg[STACK_SIZE / sizeof (int)]; +int kdb_stack_end; + +_initialize_standalone () +{ + register char *next; + + /* Find start of data on files. */ + + files_start = heap; + + /* Find the end of the data on files. */ + + for (next = files_start; * (int *) next; next += * (int *) next) {} + + /* That is where free storage starts for sbrk to give out. */ + next_free = next; + + memory_limit = heap + sizeof heap; +} + diff --git a/contrib/gdb/gdb/stop-gdb.c b/contrib/gdb/gdb/stop-gdb.c new file mode 100644 index 000000000000..8f22bf919578 --- /dev/null +++ b/contrib/gdb/gdb/stop-gdb.c @@ -0,0 +1,110 @@ +/* A client to make GDB return to command level in Mach 3. + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Authors: Jukka Virtanen and Peter Stout . + + A simple client to make GDB (versions 4.4 and later) on Mach 3 return + to the command level when it is waiting for the inferior to stop. + + Actions: Lookup the send right to the GDB message port from the + NetMsgServer. + + Send an asynchronous message with msgh_id + GDB_MESSAGE_ID_STOP to that port. + */ + +#include + +#include "defs.h" + +#include +#include +#include +#include +#include + +void +main (argc, argv) + int argc; + char **argv; +{ + kern_return_t kr; + mach_msg_header_t msg; + mach_port_t gdb_port; + char *host; + char *name; + + if (argc == 1) + argv[argc++] = GDB_DEF_NAME; + + if (argc != 2) + { + fprintf (stderr, "Usage : %s \n", argv[0]); + exit (1); + } + + /* Allow the user to specify a remote host. */ + host = strchr (argv[1], '@'); + if (host) + *(host++) = '\0'; + else + host = (char *) ""; + + name = malloc (strlen (argv[1]) + sizeof(GDB_NAME_PREFIX)); + if (name == NULL) + { + fprintf (stderr, "Unable to allocate memory for name."); + exit (1); + } + + strcpy (name, GDB_NAME_PREFIX); + strcat (name, argv[1]); + + /* Look up the GDB service port. For convenience, add the + GDB_NAME_PREFIX the argument before looking up the name. + For backwards compatibility, do it without. */ + + kr = netname_look_up (name_server_port, host, name, &gdb_port); + if (kr == NETNAME_NOT_CHECKED_IN) + kr = netname_look_up (name_server_port, host, argv[1], &gdb_port); + if (kr != KERN_SUCCESS) + { + fprintf (stderr, "Unable to lookup the GDB service port: %s.\n", + mach_error_string(kr)); + exit(1); + } + + /* Code generated by mig stub generator, with minor cleanups :-) + + simpleroutine stop_inferior(gdb_port : mach_port_t); */ + + msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0); + msg.msgh_remote_port = gdb_port; + msg.msgh_local_port = MACH_PORT_NULL; + msg.msgh_size = sizeof(msg); + msg.msgh_seqno = 0; + msg.msgh_id = GDB_MESSAGE_ID_STOP; + + kr = mach_msg_send (&msg); + if (kr != KERN_SUCCESS) + fprintf (stderr, "Message not sent, return code %d : %s\n", kr, + mach_error_string (kr)); + + exit (kr != KERN_SUCCESS); +} diff --git a/contrib/gdb/gdb/stuff.c b/contrib/gdb/gdb/stuff.c new file mode 100644 index 000000000000..eedbeab99986 --- /dev/null +++ b/contrib/gdb/gdb/stuff.c @@ -0,0 +1,174 @@ +/* Program to stuff files into a specially prepared space in kdb. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written 13-Mar-86 by David Bridgham. */ + +#include +#include +#include +#include "gdb_stat.h" +#include +#include + +main (argc, argv) + int argc; + char *argv[]; +{ + register char *cp; + char *outfile; + register int i; + int offset; + int out_fd, in_fd; + struct stat stat_buf; + int size, pad; + char buf[1024]; + static char zeros[4] = {0}; + + if (argc < 4) + err("Not enough arguments\nUsage: %s -o kdb file1 file2 ...\n", + argv[0]); + + outfile = 0; + for (i = 1; i < argc; i++) + { + if (STREQ (argv[i], "-o")) + outfile = argv[++i]; + } + if (outfile == 0) + err("Output file not specified\n"); + + offset = get_offset (outfile, "_heap"); + + out_fd = open (outfile, O_WRONLY); + if (out_fd < 0) + err ("Error opening %s for write: %s\n", outfile, strerror (errno)); + if (lseek (out_fd, offset, 0) < 0) + err ("Error seeking to heap in %s: %s\n", outfile, strerror (errno)); + + /* For each file listed on the command line, write it into the + * 'heap' of the output file. Make sure to skip the arguments + * that name the output file. */ + for (i = 1; i < argc; i++) + { + if (STREQ (argv[i], "-o")) + continue; + if ((in_fd = open (argv[i], O_RDONLY)) < 0) + err ("Error opening %s for read: %s\n", argv[i], + strerror (errno)); + if (fstat (in_fd, &stat_buf) < 0) + err ("Error stat'ing %s: %s\n", argv[i], strerror (errno)); + size = strlen (argv[i]); + pad = 4 - (size & 3); + size += pad + stat_buf.st_size + sizeof (int); + write (out_fd, &size, sizeof (int)); + write (out_fd, argv[i], strlen (argv[i])); + write (out_fd, zeros, pad); + while ((size = read (in_fd, buf, sizeof (buf))) > 0) + write (out_fd, buf, size); + close (in_fd); + } + size = 0; + write (out_fd, &size, sizeof (int)); + close (out_fd); + return (0); +} + +/* Read symbol table from file and returns the offset into the file + * where symbol sym_name is located. If error, print message and + * exit. */ +get_offset (file, sym_name) + char *file; + char *sym_name; +{ + int f; + struct exec file_hdr; + struct nlist *symbol_table; + int size; + char *strings; + + f = open (file, O_RDONLY); + if (f < 0) + err ("Error opening %s: %s\n", file, strerror (errno)); + if (read (f, &file_hdr, sizeof (file_hdr)) < 0) + err ("Error reading exec structure: %s\n", strerror (errno)); + if (N_BADMAG (file_hdr)) + err ("File %s not an a.out file\n", file); + + /* read in symbol table */ + if ((symbol_table = (struct nlist *)malloc (file_hdr.a_syms)) == 0) + err ("Couldn't allocate space for symbol table\n"); + if (lseek (f, N_SYMOFF (file_hdr), 0) == -1) + err ("lseek error: %s\n", strerror (errno)); + if (read (f, symbol_table, file_hdr.a_syms) == -1) + err ("Error reading symbol table from %s: %s\n", file, + strerror (errno)); + + /* read in string table */ + if (read (f, &size, 4) == -1) + err ("reading string table size: %s\n", strerror (errno)); + if ((strings = (char *)malloc (size)) == 0) + err ("Couldn't allocate memory for string table\n"); + if (read (f, strings, size - 4) == -1) + err ("reading string table: %s\n", strerror (errno)); + + /* Find the core address at which the first byte of kdb text segment + should be loaded into core when kdb is run. */ + origin = find_symbol ("_etext", symbol_table, file_hdr.a_syms, strings) + - file_hdr.a_text; + /* Find the core address at which the heap will appear. */ + coreaddr = find_symbol (sym_name, symbol_table, file_hdr.a_syms, strings); + /* Return address in file of the heap data space. */ + return (N_TXTOFF (file_hdr) + core_addr - origin); +} + +find_symbol (sym_name, symbol_table, length, strings) + char *sym_name; + struct nlist *symbol_table; + int length; + char *strings; +{ + register struct nlist *sym; + + /* Find symbol in question */ + for (sym = symbol_table; + sym != (struct nlist *)((char *)symbol_table + length); + sym++) + { + if ((sym->n_type & N_TYPE) != N_DATA) continue; + if (sym->n_un.n_strx == 0) continue; + if (STREQ (sym_name, strings + sym->n_un.n_strx - 4)) + return sym->n_value; + } + err ("Data symbol %s not found in %s\n", sym_name, file); +} + +/* VARARGS */ +void +err (va_alist) + va_dcl +{ + va_list args; + char *string; + + va_start (args); + string = va_arg (args, char *); + vfprintf (gdb_stderr, string, args); + va_end (args); + exit (-1); +} diff --git a/contrib/gdb/gdb/symfile.c b/contrib/gdb/gdb/symfile.c new file mode 100644 index 000000000000..62c4f619d5c0 --- /dev/null +++ b/contrib/gdb/gdb/symfile.c @@ -0,0 +1,1774 @@ +/* Generic symbol file reading for the GNU debugger, GDB. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "frame.h" +#include "target.h" +#include "value.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcmd.h" +#include "breakpoint.h" +#include "language.h" +#include "complaints.h" +#include "demangle.h" +#include "inferior.h" /* for write_pc */ + +#include "obstack.h" +#include + +#include +#include +#include "gdb_string.h" +#include "gdb_stat.h" +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Global variables owned by this file */ +int readnow_symbol_files; /* Read full symbols immediately */ + +struct complaint oldsyms_complaint = { + "Replacing old symbols for `%s'", 0, 0 +}; + +struct complaint empty_symtab_complaint = { + "Empty symbol table found for `%s'", 0, 0 +}; + +/* External variables and functions referenced. */ + +extern int info_verbose; + +/* Functions this file defines */ + +static void +set_initial_language PARAMS ((void)); + +static void +load_command PARAMS ((char *, int)); + +static void +add_symbol_file_command PARAMS ((char *, int)); + +static void +add_shared_symbol_files_command PARAMS ((char *, int)); + +static void +cashier_psymtab PARAMS ((struct partial_symtab *)); + +static int +compare_psymbols PARAMS ((const void *, const void *)); + +static int +compare_symbols PARAMS ((const void *, const void *)); + +static bfd * +symfile_bfd_open PARAMS ((char *)); + +static void +find_sym_fns PARAMS ((struct objfile *)); + +/* List of all available sym_fns. On gdb startup, each object file reader + calls add_symtab_fns() to register information on each format it is + prepared to read. */ + +static struct sym_fns *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 + +/* If true, then 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 want to have happen; but for very large programs, the startup + time will be excessive, and so if this is a problem, the user can + clear this flag and then add the shared library symbols as needed. + Note that there is a potential for confusion, since if the shared + library symbols are not loaded, commands like "info fun" will *not* + report all the functions that are actually present. */ + +int auto_solib_add = 1; + + +/* Since this function is called from within qsort, in an ANSI environment + it must conform to the prototype for qsort, which specifies that the + comparison function takes two "void *" pointers. */ + +static int +compare_symbols (s1p, s2p) + const PTR s1p; + const PTR s2p; +{ + register struct symbol **s1, **s2; + + s1 = (struct symbol **) s1p; + s2 = (struct symbol **) s2p; + + return (STRCMP (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2))); +} + +/* + +LOCAL FUNCTION + + compare_psymbols -- compare two partial symbols by name + +DESCRIPTION + + Given pointers to pointers to two partial symbol table entries, + compare them by name and return -N, 0, or +N (ala strcmp). + Typically used by sorting routines like qsort(). + +NOTES + + Does direct compare of first two characters before punting + and passing to strcmp for longer compares. Note that the + original version had a bug whereby two null strings or two + identically named one character strings would return the + comparison of memory following the null byte. + + */ + +static int +compare_psymbols (s1p, s2p) + const PTR s1p; + const PTR s2p; +{ + register char *st1 = SYMBOL_NAME (*(struct partial_symbol **) s1p); + register char *st2 = SYMBOL_NAME (*(struct partial_symbol **) s2p); + + if ((st1[0] - st2[0]) || !st1[0]) + { + return (st1[0] - st2[0]); + } + else if ((st1[1] - st2[1]) || !st1[1]) + { + return (st1[1] - st2[1]); + } + else + { + return (STRCMP (st1 + 2, st2 + 2)); + } +} + +void +sort_pst_symbols (pst) + struct partial_symtab *pst; +{ + /* Sort the global list; don't sort the static list */ + + qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset, + pst -> n_global_syms, sizeof (struct partial_symbol *), + compare_psymbols); +} + +/* Call sort_block_syms to sort alphabetically the symbols of one block. */ + +void +sort_block_syms (b) + register struct block *b; +{ + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); +} + +/* Call sort_symtab_syms to sort alphabetically + the symbols of each block of one symtab. */ + +void +sort_symtab_syms (s) + register struct symtab *s; +{ + register struct blockvector *bv; + int nbl; + int i; + register struct block *b; + + if (s == 0) + return; + bv = BLOCKVECTOR (s); + nbl = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < nbl; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SHOULD_SORT (b)) + sort_block_syms (b); + } +} + +/* 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. */ + +char * +obsavestring (ptr, size, obstackp) + char *ptr; + int size; + struct obstack *obstackp; +{ + register char *p = (char *) obstack_alloc (obstackp, size + 1); + /* Open-coded memcpy--saves function call time. + These strings are usually short. */ + { + register char *p1 = ptr; + register char *p2 = p; + char *end = ptr + size; + while (p1 != end) + *p2++ = *p1++; + } + p[size] = 0; + return p; +} + +/* Concatenate strings S1, S2 and S3; return the new string. + Space is found in the symbol_obstack. */ + +char * +obconcat (obstackp, s1, s2, s3) + struct obstack *obstackp; + const char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) obstack_alloc (obstackp, len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +/* True if we are nested inside psymtab_to_symtab. */ + +int currently_reading_symtab = 0; + +static void +decrement_reading_symtab (dummy) + void *dummy; +{ + currently_reading_symtab--; +} + +/* 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. */ + +struct symtab * +psymtab_to_symtab (pst) + register struct partial_symtab *pst; +{ + /* If it's been looked up before, return it. */ + if (pst->symtab) + return pst->symtab; + + /* If it has not yet been read in, read it. */ + if (!pst->readin) + { + struct cleanup *back_to = make_cleanup (decrement_reading_symtab, NULL); + currently_reading_symtab++; + (*pst->read_symtab) (pst); + do_cleanups (back_to); + } + + return pst->symtab; +} + +/* Initialize entry point information for this objfile. */ + +void +init_entry_point_info (objfile) + 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); + } + else + { + /* Examination of non-executable.o files. Short-circuit this stuff. */ + objfile -> ei.entry_point = INVALID_ENTRY_POINT; + } + objfile -> ei.entry_file_lowpc = INVALID_ENTRY_LOWPC; + objfile -> ei.entry_file_highpc = INVALID_ENTRY_HIGHPC; + objfile -> ei.entry_func_lowpc = INVALID_ENTRY_LOWPC; + objfile -> ei.entry_func_highpc = INVALID_ENTRY_HIGHPC; + objfile -> ei.main_func_lowpc = INVALID_ENTRY_LOWPC; + objfile -> ei.main_func_highpc = INVALID_ENTRY_HIGHPC; +} + +/* Get current entry point address. */ + +CORE_ADDR +entry_point_address() +{ + return symfile_objfile ? symfile_objfile->ei.entry_point : 0; +} + +/* Remember the lowest-addressed loadable section we've seen. + This function is called via bfd_map_over_sections. + + In case of equal vmas, the section with the largest size becomes the + lowest-addressed loadable section. + + If the vmas and sizes are equal, the last section is considered the + lowest-addressed loadable section. */ + +void +find_lowest_section (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR obj; +{ + asection **lowest = (asection **)obj; + + if (0 == (bfd_get_section_flags (abfd, sect) & SEC_LOAD)) + return; + if (!*lowest) + *lowest = sect; /* First loadable section */ + else if (bfd_section_vma (abfd, *lowest) > bfd_section_vma (abfd, sect)) + *lowest = sect; /* A lower loadable section */ + else if (bfd_section_vma (abfd, *lowest) == bfd_section_vma (abfd, sect) + && (bfd_section_size (abfd, (*lowest)) + <= bfd_section_size (abfd, sect))) + *lowest = sect; +} + +/* Process a symbol file, as either the main file or as a dynamically + loaded file. + + NAME is the file name (which will be tilde-expanded and made + absolute herein) (but we don't free or modify NAME itself). + FROM_TTY says how verbose to be. MAINLINE specifies whether this + is the main symbol file, or whether it's an extra symbol file such + as dynamically loaded code. If !mainline, ADDR is the address + where the text segment was loaded. If VERBO, the caller has printed + a verbose message about the symbol reading (and complaints can be + more terse about it). */ + +void +syms_from_objfile (objfile, addr, mainline, verbo) + struct objfile *objfile; + CORE_ADDR addr; + int mainline; + int verbo; +{ + struct section_offsets *section_offsets; + asection *lowest_sect; + struct cleanup *old_chain; + + init_entry_point_info (objfile); + find_sym_fns (objfile); + + /* Make sure that partially constructed symbol tables will be cleaned up + if an error occurs during symbol reading. */ + old_chain = make_cleanup (free_objfile, objfile); + + if (mainline) + { + /* We will modify the main symbol table, make sure that all its users + will be cleaned up if an error occurs during symbol reading. */ + make_cleanup (clear_symtab_users, 0); + + /* Since no error yet, throw away the old symbol table. */ + + if (symfile_objfile != NULL) + { + free_objfile (symfile_objfile); + symfile_objfile = NULL; + } + + /* Currently we keep symbols from the add-symbol-file command. + If the user wants to get rid of them, they should do "symbol-file" + without arguments first. Not sure this is the best behavior + (PR 2207). */ + + (*objfile -> sf -> sym_new_init) (objfile); + } + + /* Convert addr into an offset rather than an absolute address. + We find the lowest address of a loaded segment in the objfile, + and assume that is where that got loaded. Due to historical + precedent, we warn if that doesn't happen to be a text segment. */ + + if (mainline) + { + addr = 0; /* No offset from objfile addresses. */ + } + else + { + lowest_sect = bfd_get_section_by_name (objfile->obfd, ".text"); + if (lowest_sect == NULL) + bfd_map_over_sections (objfile->obfd, find_lowest_section, + (PTR) &lowest_sect); + + if (lowest_sect == NULL) + warning ("no loadable sections found in added symbol-file %s", + objfile->name); + else if ((bfd_get_section_flags (objfile->obfd, lowest_sect) & SEC_CODE) + == 0) + /* FIXME-32x64--assumes bfd_vma fits in long. */ + warning ("Lowest section in %s is %s at 0x%lx", + objfile->name, + bfd_section_name (objfile->obfd, lowest_sect), + (unsigned long) bfd_section_vma (objfile->obfd, lowest_sect)); + + if (lowest_sect) + addr -= bfd_section_vma (objfile->obfd, lowest_sect); + } + + /* Initialize symbol reading routines for this objfile, allow complaints to + appear for this new file, and record how verbose to be, then do the + initial symbol reading for this file. */ + + (*objfile -> sf -> sym_init) (objfile); + clear_complaints (1, verbo); + + section_offsets = (*objfile -> sf -> sym_offsets) (objfile, addr); + objfile->section_offsets = section_offsets; + +#ifndef IBM6000_TARGET + /* This is a SVR4/SunOS specific hack, I think. In any event, it + screws RS/6000. sym_offsets should be doing this sort of thing, + because it knows the mapping between bfd sections and + section_offsets. */ + /* This is a hack. As far as I can tell, section offsets are not + target dependent. They are all set to addr with a couple of + exceptions. The exceptions are sysvr4 shared libraries, whose + offsets are kept in solib structures anyway and rs6000 xcoff + which handles shared libraries in a completely unique way. + + Section offsets are built similarly, except that they are built + by adding addr in all cases because there is no clear mapping + from section_offsets into actual sections. Note that solib.c + has a different algorythm for finding section offsets. + + These should probably all be collapsed into some target + independent form of shared library support. FIXME. */ + + if (addr) + { + struct obj_section *s; + + for (s = objfile->sections; s < objfile->sections_end; ++s) + { + s->addr -= s->offset; + s->addr += addr; + s->endaddr -= s->offset; + s->endaddr += addr; + s->offset += addr; + } + } +#endif /* not IBM6000_TARGET */ + + (*objfile -> sf -> sym_read) (objfile, section_offsets, mainline); + + if (!have_partial_symbols () && !have_full_symbols ()) + { + wrap_here (""); + printf_filtered ("(no debugging symbols found)..."); + wrap_here (""); + } + + /* Don't allow char * to have a typename (else would get caddr_t). + Ditto void *. FIXME: Check whether this is now done by all the + symbol readers themselves (many of them now do), and if so remove + it from here. */ + + TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; + TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0; + + /* Mark the objfile has having had initial symbol read attempted. Note + that this does not mean we found any symbols... */ + + objfile -> flags |= OBJF_SYMS; + + /* Discard cleanups as symbol reading was successful. */ + + discard_cleanups (old_chain); + +/* Call this after reading in a new symbol table to give target dependant code + a crack at the new symbols. For instance, this could be used to update the + values of target-specific symbols GDB needs to keep track of (such as + _sigtramp, or whatever). */ + + TARGET_SYMFILE_POSTREAD (objfile); +} + +/* Perform required actions after either reading in the initial + symbols for a new objfile, or mapping in the symbols from a reusable + objfile. */ + +void +new_symfile_objfile (objfile, mainline, verbo) + struct objfile *objfile; + int mainline; + int verbo; +{ + + /* If this is the main symbol file we have to clean up all users of the + old main symbol file. Otherwise it is sufficient to fixup all the + breakpoints that may have been redefined by this symbol file. */ + if (mainline) + { + /* OK, make it the "real" symbol file. */ + symfile_objfile = objfile; + + clear_symtab_users (); + } + else + { + breakpoint_re_set (); + } + + /* We're done reading the symbol file; finish off complaints. */ + clear_complaints (0, verbo); +} + +/* Process a symbol file, as either the main file or as a dynamically + loaded file. + + NAME is the file name (which will be tilde-expanded and made + absolute herein) (but we don't free or modify NAME itself). + FROM_TTY says how verbose to be. MAINLINE specifies whether this + is the main symbol file, or whether it's an extra symbol file such + as dynamically loaded code. If !mainline, ADDR is the address + where the text segment was loaded. + + Upon success, returns a pointer to the objfile that was added. + Upon failure, jumps back to command level (never returns). */ + +struct objfile * +symbol_file_add (name, from_tty, addr, mainline, mapped, readnow) + char *name; + int from_tty; + CORE_ADDR addr; + int mainline; + int mapped; + int readnow; +{ + struct objfile *objfile; + struct partial_symtab *psymtab; + bfd *abfd; + + /* Open a bfd for the file, and give user a chance to burp if we'd be + interactively wiping out any existing symbols. */ + + abfd = symfile_bfd_open (name); + + if ((have_full_symbols () || have_partial_symbols ()) + && mainline + && from_tty + && !query ("Load new symbol table from \"%s\"? ", name)) + error ("Not confirmed."); + + objfile = allocate_objfile (abfd, mapped); + + /* If the objfile uses a mapped symbol file, and we have a psymtab for + it, then skip reading any symbols at this time. */ + + if ((objfile -> flags & OBJF_MAPPED) && (objfile -> flags & OBJF_SYMS)) + { + /* We mapped in an existing symbol table file that already has had + initial symbol reading performed, so we can skip that part. Notify + the user that instead of reading the symbols, they have been mapped. + */ + if (from_tty || info_verbose) + { + printf_filtered ("Mapped symbols for %s...", name); + wrap_here (""); + gdb_flush (gdb_stdout); + } + init_entry_point_info (objfile); + find_sym_fns (objfile); + } + else + { + /* We either created a new mapped symbol table, mapped an existing + symbol table file which has not had initial symbol reading + performed, or need to read an unmapped symbol table. */ + if (from_tty || info_verbose) + { + printf_filtered ("Reading symbols from %s...", name); + wrap_here (""); + gdb_flush (gdb_stdout); + } + syms_from_objfile (objfile, addr, mainline, from_tty); + } + + /* We now have at least a partial symbol table. Check to see if the + user requested that all symbols be read on initial access via either + the gdb startup command line or on a per symbol file basis. Expand + all partial symbol tables for this objfile if so. */ + + if (readnow || readnow_symbol_files) + { + if (from_tty || info_verbose) + { + printf_filtered ("expanding to full symbols..."); + wrap_here (""); + gdb_flush (gdb_stdout); + } + + for (psymtab = objfile -> psymtabs; + psymtab != NULL; + psymtab = psymtab -> next) + { + psymtab_to_symtab (psymtab); + } + } + + if (from_tty || info_verbose) + { + printf_filtered ("done.\n"); + gdb_flush (gdb_stdout); + } + + new_symfile_objfile (objfile, mainline, from_tty); + + return (objfile); +} + +/* This is the symbol-file command. Read the file, analyze its + symbols, and add a struct symtab to a symtab list. The syntax of + the command is rather bizarre--(1) buildargv implements various + quoting conventions which are undocumented and have little or + nothing in common with the way things are quoted (or not quoted) + elsewhere in GDB, (2) options are used, which are not generally + used in GDB (perhaps "set mapped on", "set readnow on" would be + better), (3) the order of options matters, which is contrary to GNU + conventions (because it is confusing and inconvenient). */ + +void +symbol_file_command (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + char *name = NULL; + CORE_ADDR text_relocation = 0; /* text_relocation */ + struct cleanup *cleanups; + int mapped = 0; + int readnow = 0; + + dont_repeat (); + + if (args == NULL) + { + if ((have_full_symbols () || have_partial_symbols ()) + && from_tty + && !query ("Discard symbol table from `%s'? ", + symfile_objfile -> name)) + error ("Not confirmed."); + free_all_objfiles (); + symfile_objfile = NULL; + if (from_tty) + { + printf_unfiltered ("No symbol file now.\n"); + } + } + else + { + if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + while (*argv != NULL) + { + if (STREQ (*argv, "-mapped")) + { + mapped = 1; + } + else if (STREQ (*argv, "-readnow")) + { + readnow = 1; + } + else if (**argv == '-') + { + error ("unknown option `%s'", *argv); + } + else + { + char *p; + + name = *argv; + + /* this is for rombug remote only, to get the text relocation by + using link command */ + p = strrchr(name, '/'); + if (p != NULL) p++; + else p = name; + + target_link(p, &text_relocation); + + if (text_relocation == (CORE_ADDR)0) + return; + else if (text_relocation == (CORE_ADDR)-1) + symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, + readnow); + else + symbol_file_add (name, from_tty, (CORE_ADDR)text_relocation, + 0, mapped, readnow); + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); + + set_initial_language (); + } + argv++; + } + + if (name == NULL) + { + error ("no symbol file name was specified"); + } + do_cleanups (cleanups); + } +} + +/* Set the initial language. + + A better solution would be to record the language in the psymtab when reading + partial symbols, and then use it (if known) to set the language. This would + be a win for formats that encode the language in an easily discoverable place, + such as DWARF. For stabs, we can jump through hoops looking for specially + named symbols or try to intuit the language from the specific type of stabs + we find, but we can't do that until later when we read in full symbols. + FIXME. */ + +static void +set_initial_language () +{ + struct partial_symtab *pst; + enum language lang = language_unknown; + + pst = find_main_psymtab (); + if (pst != NULL) + { + if (pst -> filename != NULL) + { + lang = deduce_language_from_filename (pst -> filename); + } + if (lang == language_unknown) + { + /* Make C the default language */ + lang = language_c; + } + set_language (lang); + expected_language = current_language; /* Don't warn the user */ + } +} + +/* Open file specified by NAME and hand it off to BFD for preliminary + analysis. Result is a newly initialized bfd *, which includes a newly + malloc'd` copy of NAME (tilde-expanded and made absolute). + In case of trouble, error() is called. */ + +static bfd * +symfile_bfd_open (name) + char *name; +{ + bfd *sym_bfd; + int desc; + char *absolute_name; + + name = tilde_expand (name); /* Returns 1st new malloc'd copy */ + + /* Look down path for it, allocate 2nd new malloc'd copy. */ + desc = openp (getenv ("PATH"), 1, name, O_RDONLY | O_BINARY, 0, &absolute_name); + if (desc < 0) + { + make_cleanup (free, name); + perror_with_name (name); + } + free (name); /* Free 1st new malloc'd copy */ + name = absolute_name; /* Keep 2nd malloc'd copy in bfd */ + /* It'll be freed in free_objfile(). */ + + sym_bfd = bfd_fdopenr (name, gnutarget, desc); + if (!sym_bfd) + { + close (desc); + make_cleanup (free, name); + error ("\"%s\": can't open to read symbols: %s.", name, + bfd_errmsg (bfd_get_error ())); + } + sym_bfd->cacheable = true; + + 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 (free, name); + error ("\"%s\": can't read symbols: %s.", name, + bfd_errmsg (bfd_get_error ())); + } + + return (sym_bfd); +} + +/* Link a new symtab_fns into the global symtab_fns list. Called on gdb + startup by the _initialize routine in each object file format reader, + to register information about each format the the reader is prepared + to handle. */ + +void +add_symtab_fns (sf) + struct sym_fns *sf; +{ + sf->next = symtab_fns; + symtab_fns = sf; +} + + +/* Initialize to read symbols from the symbol file sym_bfd. It either + returns or calls error(). The result is an initialized struct sym_fns + in the objfile structure, that contains cached information about the + symbol file. */ + +static void +find_sym_fns (objfile) + struct objfile *objfile; +{ + struct sym_fns *sf; + enum bfd_flavour our_flavour = bfd_get_flavour (objfile -> obfd); + char *our_target = bfd_get_target (objfile -> obfd); + + /* Special kludge for RS/6000 and PowerMac. See xcoffread.c. */ + if (STREQ (our_target, "aixcoff-rs6000") || + STREQ (our_target, "xcoff-powermac")) + our_flavour = (enum bfd_flavour)-1; + + /* Special kludge for apollo. See dstread.c. */ + if (STREQN (our_target, "apollo", 6)) + our_flavour = (enum bfd_flavour)-2; + + for (sf = symtab_fns; sf != NULL; sf = sf -> next) + { + if (our_flavour == sf -> sym_flavour) + { + objfile -> sf = sf; + return; + } + } + error ("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown.", + bfd_get_target (objfile -> obfd)); +} + +/* This function runs the load command of our current target. */ + +static void +load_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg == NULL) + arg = get_exec_file (1); + target_load (arg, from_tty); +} + +/* This version of "load" should be usable for any target. Currently + it is just used for remote targets, not inftarg.c or core files, + on the theory that only in that case is it useful. + + Avoiding xmodem and the like seems like a win (a) because we don't have + to worry about finding it, and (b) On VMS, fork() is very slow and so + we don't want to run a subprocess. On the other hand, I'm not sure how + performance compares. */ +void +generic_load (filename, from_tty) + char *filename; + int from_tty; +{ + struct cleanup *old_cleanups; + asection *s; + bfd *loadfile_bfd; + time_t start_time, end_time; /* Start and end times of download */ + unsigned long data_count; /* Number of bytes transferred to memory */ + + loadfile_bfd = bfd_openr (filename, gnutarget); + 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). */ + old_cleanups = make_cleanup (bfd_close, loadfile_bfd); + + if (!bfd_check_format (loadfile_bfd, bfd_object)) + { + error ("\"%s\" is not an object file: %s", filename, + bfd_errmsg (bfd_get_error ())); + } + + start_time = time (NULL); + + for (s = loadfile_bfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + bfd_size_type size; + + size = bfd_get_section_size_before_reloc (s); + if (size > 0) + { + char *buffer; + struct cleanup *old_chain; + bfd_vma vma; + + data_count += size; + + buffer = xmalloc (size); + old_chain = make_cleanup (free, buffer); + + vma = bfd_get_section_vma (loadfile_bfd, s); + + /* Is this really necessary? I guess it gives the user something + to look at during a long download. */ + printf_filtered ("Loading section %s, size 0x%lx vma ", + bfd_get_section_name (loadfile_bfd, s), + (unsigned long) size); + print_address_numeric (vma, 1, gdb_stdout); + printf_filtered ("\n"); + + bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size); + + target_write_memory (vma, buffer, size); + + do_cleanups (old_chain); + } + } + } + + end_time = time (NULL); + + /* We were doing this in remote-mips.c, I suspect it is right + for other targets too. */ + write_pc (loadfile_bfd->start_address); + + /* FIXME: are we supposed to call symbol_file_add or not? According to + a comment from remote-mips.c (where a call to symbol_file_add was + commented out), making the call confuses GDB if more than one file is + loaded in. remote-nindy.c had no call to symbol_file_add, but remote-vx.c + does. */ + + if (end_time != start_time) + printf_filtered ("Transfer rate: %d bits/sec.\n", + (data_count * 8)/(end_time - start_time)); + + do_cleanups (old_cleanups); +} + +/* This function allows the addition of incrementally linked object files. + It does not modify any state in the target, only in the debugger. */ + +/* ARGSUSED */ +static void +add_symbol_file_command (args, from_tty) + char *args; + int from_tty; +{ + char *name = NULL; + CORE_ADDR text_addr; + char *arg; + int readnow = 0; + int mapped = 0; + + dont_repeat (); + + if (args == NULL) + { + error ("add-symbol-file takes a file name and an address"); + } + + /* Make a copy of the string that we can safely write into. */ + + args = strdup (args); + make_cleanup (free, args); + + /* Pick off any -option args and the file name. */ + + while ((*args != '\000') && (name == NULL)) + { + while (isspace (*args)) {args++;} + arg = args; + while ((*args != '\000') && !isspace (*args)) {args++;} + if (*args != '\000') + { + *args++ = '\000'; + } + if (*arg != '-') + { + name = arg; + } + else if (STREQ (arg, "-mapped")) + { + mapped = 1; + } + else if (STREQ (arg, "-readnow")) + { + readnow = 1; + } + else + { + error ("unknown option `%s'", arg); + } + } + + /* After picking off any options and the file name, args should be + left pointing at the remainder of the command line, which should + be the address expression to evaluate. */ + + if (name == NULL) + { + error ("add-symbol-file takes a file name"); + } + name = tilde_expand (name); + make_cleanup (free, name); + + if (*args != '\000') + { + text_addr = parse_and_eval_address (args); + } + else + { + target_link(name, &text_addr); + if (text_addr == (CORE_ADDR)-1) + error("Don't know how to get text start location for this file"); + } + + /* FIXME-32x64: Assumes text_addr fits in a long. */ + if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n", + name, local_hex_string ((unsigned long)text_addr))) + error ("Not confirmed."); + + symbol_file_add (name, 0, text_addr, 0, mapped, readnow); + + /* Getting new symbols may change our opinion about what is + frameless. */ + reinit_frame_cache (); +} + +static void +add_shared_symbol_files_command (args, from_tty) + char *args; + int from_tty; +{ +#ifdef ADD_SHARED_SYMBOL_FILES + ADD_SHARED_SYMBOL_FILES (args, from_tty); +#else + error ("This command is not available in this configuration of GDB."); +#endif +} + +/* Re-read symbols if a symbol-file has changed. */ +void +reread_symbols () +{ + struct objfile *objfile; + long new_modtime; + int reread_one = 0; + struct stat new_statbuf; + int res; + + /* With the addition of shared libraries, this should be modified, + the load time should be saved in the partial symbol tables, since + different tables may come from different source files. FIXME. + This routine should then walk down each partial symbol table + and see if the symbol table that it originates from has been changed */ + + for (objfile = object_files; objfile; objfile = objfile->next) { + if (objfile->obfd) { +#ifdef IBM6000_TARGET + /* If this object is from a shared library, then you should + stat on the library name, not member name. */ + + if (objfile->obfd->my_archive) + res = stat (objfile->obfd->my_archive->filename, &new_statbuf); + else +#endif + res = stat (objfile->name, &new_statbuf); + if (res != 0) { + /* FIXME, should use print_sys_errmsg but it's not filtered. */ + printf_filtered ("`%s' has disappeared; keeping its symbols.\n", + objfile->name); + continue; + } + new_modtime = new_statbuf.st_mtime; + if (new_modtime != objfile->mtime) + { + struct cleanup *old_cleanups; + struct section_offsets *offsets; + int num_offsets; + int section_offsets_size; + char *obfd_filename; + + printf_filtered ("`%s' has changed; re-reading symbols.\n", + objfile->name); + + /* There are various functions like symbol_file_add, + symfile_bfd_open, syms_from_objfile, etc., which might + appear to do what we want. But they have various other + effects which we *don't* want. So we just do stuff + ourselves. We don't worry about mapped files (for one thing, + any mapped file will be out of date). */ + + /* If we get an error, blow away this objfile (not sure if + that is the correct response for things like shared + libraries). */ + old_cleanups = make_cleanup (free_objfile, objfile); + /* We need to do this whenever any symbols go away. */ + make_cleanup (clear_symtab_users, 0); + + /* 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_openr (obfd_filename, gnutarget); + if (objfile->obfd == NULL) + error ("Can't open %s to read symbols.", objfile->name); + /* 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, + bfd_errmsg (bfd_get_error ())); + + /* Save the offsets, we will nuke them with the rest of the + psymbol_obstack. */ + num_offsets = objfile->num_sections; + section_offsets_size = + sizeof (struct section_offsets) + + sizeof (objfile->section_offsets->offsets) * num_offsets; + offsets = (struct section_offsets *) alloca (section_offsets_size); + memcpy (offsets, objfile->section_offsets, section_offsets_size); + + /* Nuke all the state that we will re-read. Much of the following + code which sets things to NULL really is necessary to tell + other parts of GDB that there is nothing currently there. */ + + /* FIXME: Do we have to free a whole linked list, or is this + enough? */ + if (objfile->global_psymbols.list) + mfree (objfile->md, objfile->global_psymbols.list); + memset (&objfile -> global_psymbols, 0, + sizeof (objfile -> global_psymbols)); + if (objfile->static_psymbols.list) + mfree (objfile->md, objfile->static_psymbols.list); + memset (&objfile -> static_psymbols, 0, + sizeof (objfile -> static_psymbols)); + + /* Free the obstacks for non-reusable objfiles */ + obstack_free (&objfile -> psymbol_cache.cache, 0); + memset (&objfile -> psymbol_cache, 0, + sizeof (objfile -> psymbol_cache)); + obstack_free (&objfile -> psymbol_obstack, 0); + obstack_free (&objfile -> symbol_obstack, 0); + obstack_free (&objfile -> type_obstack, 0); + objfile->sections = NULL; + objfile->symtabs = NULL; + objfile->psymtabs = NULL; + objfile->free_psymtabs = NULL; + objfile->msymbols = NULL; + objfile->minimal_symbol_count= 0; + objfile->fundamental_types = NULL; + if (objfile -> sf != NULL) + { + (*objfile -> sf -> sym_finish) (objfile); + } + + /* We never make this a mapped file. */ + objfile -> md = NULL; + /* obstack_specify_allocation also initializes the obstack so + it is empty. */ + obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0, + xmalloc, free); + obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0, + xmalloc, free); + obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0, + xmalloc, free); + obstack_specify_allocation (&objfile -> type_obstack, 0, 0, + xmalloc, free); + if (build_objfile_section_table (objfile)) + { + error ("Can't find the file sections in `%s': %s", + objfile -> name, bfd_errmsg (bfd_get_error ())); + } + + /* We use the same section offsets as from last time. I'm not + sure whether that is always correct for shared libraries. */ + objfile->section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, section_offsets_size); + memcpy (objfile->section_offsets, offsets, section_offsets_size); + objfile->num_sections = num_offsets; + + /* What the hell is sym_new_init for, anyway? The concept of + distinguishing between the main file and additional files + in this way seems rather dubious. */ + if (objfile == symfile_objfile) + (*objfile->sf->sym_new_init) (objfile); + + (*objfile->sf->sym_init) (objfile); + clear_complaints (1, 1); + /* The "mainline" parameter is a hideous hack; I think leaving it + zero is OK since dbxread.c also does what it needs to do if + objfile->global_psymbols.size is 0. */ + (*objfile->sf->sym_read) (objfile, objfile->section_offsets, 0); + if (!have_partial_symbols () && !have_full_symbols ()) + { + wrap_here (""); + printf_filtered ("(no debugging symbols found)\n"); + wrap_here (""); + } + objfile -> flags |= OBJF_SYMS; + + /* We're done reading the symbol file; finish off complaints. */ + clear_complaints (0, 1); + + /* Getting new symbols may change our opinion about what is + frameless. */ + + reinit_frame_cache (); + + /* Discard cleanups as symbol reading was successful. */ + discard_cleanups (old_cleanups); + + /* If the mtime has changed between the time we set new_modtime + and now, we *want* this to be out of date, so don't call stat + again now. */ + objfile->mtime = new_modtime; + reread_one = 1; + + /* Call this after reading in a new symbol table to give target + dependant code a crack at the new symbols. For instance, this + could be used to update the values of target-specific symbols GDB + needs to keep track of (such as _sigtramp, or whatever). */ + + TARGET_SYMFILE_POSTREAD (objfile); + } + } + } + + if (reread_one) + clear_symtab_users (); +} + + +enum language +deduce_language_from_filename (filename) + char *filename; +{ + char *c; + + if (0 == filename) + ; /* Get default */ + else if (0 == (c = strrchr (filename, '.'))) + ; /* Get default. */ + else if (STREQ (c, ".c")) + return language_c; + else if (STREQ (c, ".cc") || STREQ (c, ".C") || STREQ (c, ".cxx") + || STREQ (c, ".cpp") || STREQ (c, ".cp") || STREQ (c, ".c++")) + return language_cplus; + else if (STREQ (c, ".ch") || STREQ (c, ".c186") || STREQ (c, ".c286")) + return language_chill; + else if (STREQ (c, ".f") || STREQ (c, ".F")) + return language_fortran; + else if (STREQ (c, ".mod")) + return language_m2; + else if (STREQ (c, ".s") || STREQ (c, ".S")) + return language_asm; + + return language_unknown; /* default */ +} + +/* allocate_symtab: + + Allocate and partly initialize a new symbol table. Return a pointer + to it. error() if no space. + + Caller must set these fields: + LINETABLE(symtab) + symtab->blockvector + symtab->dirname + symtab->free_code + symtab->free_ptr + initialize any EXTRA_SYMTAB_INFO + possibly free_named_symtabs (symtab->filename); + */ + +struct symtab * +allocate_symtab (filename, objfile) + char *filename; + struct objfile *objfile; +{ + register struct symtab *symtab; + + symtab = (struct symtab *) + obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symtab)); + memset (symtab, 0, sizeof (*symtab)); + symtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> symbol_obstack); + symtab -> fullname = NULL; + symtab -> language = deduce_language_from_filename (filename); + + /* Hook it to the objfile it comes from */ + + symtab -> objfile = objfile; + symtab -> next = objfile -> symtabs; + objfile -> symtabs = symtab; + +#ifdef INIT_EXTRA_SYMTAB_INFO + INIT_EXTRA_SYMTAB_INFO (symtab); +#endif + + return (symtab); +} + +struct partial_symtab * +allocate_psymtab (filename, objfile) + char *filename; + struct objfile *objfile; +{ + struct partial_symtab *psymtab; + + if (objfile -> free_psymtabs) + { + psymtab = objfile -> free_psymtabs; + objfile -> free_psymtabs = psymtab -> next; + } + else + psymtab = (struct partial_symtab *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct partial_symtab)); + + memset (psymtab, 0, sizeof (struct partial_symtab)); + psymtab -> filename = obsavestring (filename, strlen (filename), + &objfile -> psymbol_obstack); + psymtab -> symtab = NULL; + + /* Hook it to the objfile it comes from */ + + psymtab -> objfile = objfile; + psymtab -> next = objfile -> psymtabs; + objfile -> psymtabs = psymtab; + + return (psymtab); +} + + +/* Reset all data structures in gdb which may contain references to symbol + table date. */ + +void +clear_symtab_users () +{ + /* Someday, we should do better than this, by only blowing away + the things that really need to be blown. */ + clear_value_history (); + clear_displays (); + clear_internalvars (); + breakpoint_re_set (); + set_default_breakpoint (0, 0, 0, 0); + current_source_symtab = 0; + current_source_line = 0; + clear_pc_function_cache (); +} + +/* clear_symtab_users_once: + + This function is run after symbol reading, or from a cleanup. + If an old symbol table was obsoleted, the old symbol table + has been blown away, but the other GDB data structures that may + reference it have not yet been cleared or re-directed. (The old + symtab was zapped, and the cleanup queued, in free_named_symtab() + below.) + + This function can be queued N times as a cleanup, or called + directly; it will do all the work the first time, and then will be a + no-op until the next time it is queued. This works by bumping a + counter at queueing time. Much later when the cleanup is run, or at + the end of symbol processing (in case the cleanup is discarded), if + the queued count is greater than the "done-count", we do the work + and set the done-count to the queued count. If the queued count is + less than or equal to the done-count, we just ignore the call. This + is needed because reading a single .o file will often replace many + symtabs (one per .h file, for example), and we don't want to reset + the breakpoints N times in the user's face. + + The reason we both queue a cleanup, and call it directly after symbol + reading, is because the cleanup protects us in case of errors, but is + discarded if symbol reading is successful. */ + +#if 0 +/* FIXME: As free_named_symtabs is currently a big noop this function + is no longer needed. */ +static void +clear_symtab_users_once PARAMS ((void)); + +static int clear_symtab_users_queued; +static int clear_symtab_users_done; + +static void +clear_symtab_users_once () +{ + /* Enforce once-per-`do_cleanups'-semantics */ + if (clear_symtab_users_queued <= clear_symtab_users_done) + return; + clear_symtab_users_done = clear_symtab_users_queued; + + clear_symtab_users (); +} +#endif + +/* Delete the specified psymtab, and any others that reference it. */ + +static void +cashier_psymtab (pst) + struct partial_symtab *pst; +{ + struct partial_symtab *ps, *pprev = NULL; + int i; + + /* Find its previous psymtab in the chain */ + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { + if (ps == pst) + break; + pprev = ps; + } + + if (ps) { + /* Unhook it from the chain. */ + if (ps == pst->objfile->psymtabs) + pst->objfile->psymtabs = ps->next; + else + pprev->next = ps->next; + + /* FIXME, we can't conveniently deallocate the entries in the + partial_symbol lists (global_psymbols/static_psymbols) that + this psymtab points to. These just take up space until all + the psymtabs are reclaimed. Ditto the dependencies list and + filename, which are all in the psymbol_obstack. */ + + /* We need to cashier any psymtab that has this one as a dependency... */ +again: + for (ps = pst->objfile->psymtabs; ps; ps = ps->next) { + for (i = 0; i < ps->number_of_dependencies; i++) { + if (ps->dependencies[i] == pst) { + cashier_psymtab (ps); + goto again; /* Must restart, chain has been munged. */ + } + } + } + } +} + +/* If a symtab or psymtab for filename NAME is found, free it along + with any dependent breakpoints, displays, etc. + Used when loading new versions of object modules with the "add-file" + command. This is only called on the top-level symtab or psymtab's name; + it is not called for subsidiary files such as .h files. + + Return value is 1 if we blew away the environment, 0 if not. + FIXME. The return valu appears to never be used. + + FIXME. I think this is not the best way to do this. We should + work on being gentler to the environment while still cleaning up + all stray pointers into the freed symtab. */ + +int +free_named_symtabs (name) + char *name; +{ +#if 0 + /* FIXME: With the new method of each objfile having it's own + psymtab list, this function needs serious rethinking. In particular, + why was it ever necessary to toss psymtabs with specific compilation + unit filenames, as opposed to all psymtabs from a particular symbol + file? -- fnf + Well, the answer is that some systems permit reloading of particular + compilation units. We want to blow away any old info about these + compilation units, regardless of which objfiles they arrived in. --gnu. */ + + register struct symtab *s; + register struct symtab *prev; + register struct partial_symtab *ps; + struct blockvector *bv; + int blewit = 0; + + /* We only wack things if the symbol-reload switch is set. */ + if (!symbol_reloading) + return 0; + + /* Some symbol formats have trouble providing file names... */ + if (name == 0 || *name == '\0') + return 0; + + /* Look for a psymtab with the specified name. */ + +again2: + for (ps = partial_symtab_list; ps; ps = ps->next) { + if (STREQ (name, ps->filename)) { + cashier_psymtab (ps); /* Blow it away...and its little dog, too. */ + goto again2; /* Must restart, chain has been munged */ + } + } + + /* Look for a symtab with the specified name. */ + + for (s = symtab_list; s; s = s->next) + { + if (STREQ (name, s->filename)) + break; + prev = s; + } + + if (s) + { + if (s == symtab_list) + symtab_list = s->next; + else + prev->next = s->next; + + /* For now, queue a delete for all breakpoints, displays, etc., whether + or not they depend on the symtab being freed. This should be + changed so that only those data structures affected are deleted. */ + + /* But don't delete anything if the symtab is empty. + This test is necessary due to a bug in "dbxread.c" that + causes empty symtabs to be created for N_SO symbols that + contain the pathname of the object file. (This problem + has been fixed in GDB 3.9x). */ + + bv = BLOCKVECTOR (s); + if (BLOCKVECTOR_NBLOCKS (bv) > 2 + || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) + || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))) + { + complain (&oldsyms_complaint, name); + + clear_symtab_users_queued++; + make_cleanup (clear_symtab_users_once, 0); + blewit = 1; + } else { + complain (&empty_symtab_complaint, name); + } + + free_symtab (s); + } + else + { + /* It is still possible that some breakpoints will be affected + even though no symtab was found, since the file might have + been compiled without debugging, and hence not be associated + with a symtab. In order to handle this correctly, we would need + to keep a list of text address ranges for undebuggable files. + For now, we do nothing, since this is a fairly obscure case. */ + ; + } + + /* FIXME, what about the minimal symbol table? */ + return blewit; +#else + return (0); +#endif +} + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + + +struct partial_symtab * +start_psymtab_common (objfile, section_offsets, + filename, textlow, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + CORE_ADDR textlow; + struct partial_symbol **global_syms; + struct partial_symbol **static_syms; +{ + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (filename, objfile); + psymtab -> section_offsets = section_offsets; + psymtab -> textlow = textlow; + psymtab -> texthigh = psymtab -> textlow; /* default */ + psymtab -> globals_offset = global_syms - objfile -> global_psymbols.list; + psymtab -> statics_offset = static_syms - objfile -> static_psymbols.list; + return (psymtab); +} + +/* Add a symbol with a long value to a psymtab. + Since one arg is a struct, we pass in a ptr and deref it (sigh). */ + +void +add_psymbol_to_list (name, namelength, namespace, class, list, val, coreaddr, + language, objfile) + char *name; + int namelength; + namespace_enum namespace; + enum address_class class; + struct psymbol_allocation_list *list; + long val; /* Value as a long */ + CORE_ADDR coreaddr; /* Value as a CORE_ADDR */ + enum language language; + struct objfile *objfile; +{ + register struct partial_symbol *psym; + char *buf = alloca (namelength + 1); + /* psymbol is static so that there will be no uninitialized gaps in the + structure which might contain random data, causing cache misses in + bcache. */ + static struct partial_symbol psymbol; + + /* Create local copy of the partial symbol */ + memcpy (buf, name, namelength); + buf[namelength] = '\0'; + SYMBOL_NAME (&psymbol) = bcache (buf, namelength + 1, &objfile->psymbol_cache); + /* val and coreaddr are mutually exclusive, one of them *will* be zero */ + if (val != 0) + { + SYMBOL_VALUE (&psymbol) = val; + } + else + { + SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr; + } + SYMBOL_SECTION (&psymbol) = 0; + SYMBOL_LANGUAGE (&psymbol) = language; + PSYMBOL_NAMESPACE (&psymbol) = namespace; + PSYMBOL_CLASS (&psymbol) = class; + SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language); + + /* Stash the partial symbol away in the cache */ + psym = bcache (&psymbol, sizeof (struct partial_symbol), &objfile->psymbol_cache); + + /* Save pointer to partial symbol in psymtab, growing symtab if needed. */ + if (list->next >= list->list + list->size) + { + extend_psymbol_list (list, objfile); + } + *list->next++ = psym; + OBJSTAT (objfile, n_psyms++); +} + +/* Initialize storage for partial symbols. */ + +void +init_psymbol_list (objfile, total_symbols) + struct objfile *objfile; + int total_symbols; +{ + /* Free any previously allocated psymbol lists. */ + + if (objfile -> global_psymbols.list) + { + mfree (objfile -> md, (PTR)objfile -> global_psymbols.list); + } + if (objfile -> static_psymbols.list) + { + mfree (objfile -> md, (PTR)objfile -> static_psymbols.list); + } + + /* Current best guess is that approximately a twentieth + of the total symbols (in a debugging file) are global or static + oriented symbols */ + + objfile -> global_psymbols.size = total_symbols / 10; + objfile -> static_psymbols.size = total_symbols / 10; + objfile -> global_psymbols.next = + objfile -> global_psymbols.list = (struct partial_symbol **) + xmmalloc (objfile -> md, objfile -> global_psymbols.size + * sizeof (struct partial_symbol *)); + objfile -> static_psymbols.next = + objfile -> static_psymbols.list = (struct partial_symbol **) + xmmalloc (objfile -> md, objfile -> static_psymbols.size + * sizeof (struct partial_symbol *)); +} + +void +_initialize_symfile () +{ + struct cmd_list_element *c; + + c = add_cmd ("symbol-file", class_files, symbol_file_command, + "Load symbol table from executable file FILE.\n\ +The `file' command can also load symbol tables, as well as setting the file\n\ +to execute.", &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, + "Usage: add-symbol-file FILE ADDR\n\ +Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\ +ADDR is the starting address of the file's text.", + &cmdlist); + c->completer = filename_completer; + + c = add_cmd ("add-shared-symbol-files", class_files, + add_shared_symbol_files_command, + "Load the symbols from shared objects in the dynamic linker's link map.", + &cmdlist); + c = add_alias_cmd ("assf", "add-shared-symbol-files", class_files, 1, + &cmdlist); + + c = add_cmd ("load", class_files, load_command, + "Dynamically load FILE into the running program, and record its symbols\n\ +for access from GDB.", &cmdlist); + c->completer = filename_completer; + + add_show_from_set + (add_set_cmd ("symbol-reloading", class_support, var_boolean, + (char *)&symbol_reloading, + "Set dynamic symbol table reloading multiple times in one run.", + &setlist), + &showlist); + +} diff --git a/contrib/gdb/gdb/symfile.h b/contrib/gdb/gdb/symfile.h new file mode 100644 index 000000000000..d173f4e33d90 --- /dev/null +++ b/contrib/gdb/gdb/symfile.h @@ -0,0 +1,211 @@ +/* Definitions for reading symbol files into GDB. + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (SYMFILE_H) +#define SYMFILE_H + +/* This file requires that you first include "bfd.h". */ + +/* Partial symbols are stored in the psymbol_cache and pointers to them + are kept in a dynamically grown array that is obtained from malloc and + grown as necessary via realloc. Each objfile typically has two of these, + one for global symbols and one for static symbols. Although this adds + a level of indirection for storing or accessing the partial symbols, + it allows us to throw away duplicate psymbols and set all pointers + to the single saved instance. */ + +struct psymbol_allocation_list { + struct partial_symbol **list; /* Pointer to first partial symbol pointer*/ + struct partial_symbol **next; /* Pointer to next avail storage for pointer */ + int size; /* Number of symbols */ +}; + +/* Structure to keep track of symbol reading functions for various + object file types. */ + +struct sym_fns { + + /* BFD flavour that we handle, or (as a special kludge, see xcoffread.c, + (enum bfd_flavour)-1 for xcoff). */ + + enum bfd_flavour sym_flavour; + + /* Initializes anything that is global to the entire symbol table. It is + called during symbol_file_add, when we begin debugging an entirely new + program. */ + + void (*sym_new_init) PARAMS ((struct objfile *)); + + /* Reads any initial information from a symbol file, and initializes the + struct sym_fns SF in preparation for sym_read(). It is called every + time we read a symbol file for any reason. */ + + void (*sym_init) PARAMS ((struct objfile *)); + + /* sym_read (objfile, addr, mainline) + Reads a symbol file into a psymtab (or possibly a symtab). + OBJFILE is the objfile struct for the file we are reading. + SECTION_OFFSETS + are the offset between the file's specified section addresses and + their true addresses in memory. + MAINLINE is 1 if this is the + main symbol table being read, and 0 if a secondary + symbol file (e.g. shared library or dynamically loaded file) + is being read. */ + + void (*sym_read) PARAMS ((struct objfile *, struct section_offsets *, int)); + + /* Called when we are finished with an objfile. Should do all cleanup + that is specific to the object file format for the particular objfile. */ + + void (*sym_finish) PARAMS ((struct objfile *)); + + /* This function produces a file-dependent section_offsets structure, + allocated in the objfile's storage, and based on the parameter. + The parameter is currently a CORE_ADDR (FIXME!) for backward compatibility + with the higher levels of GDB. It should probably be changed to + a string, where NULL means the default, and others are parsed in a file + dependent way. The result of this function is handed in to sym_read. */ + + struct section_offsets *(*sym_offsets) PARAMS ((struct objfile *, CORE_ADDR)); + + /* Finds the next struct sym_fns. They are allocated and initialized + in whatever module implements the functions pointed to; an + initializer calls add_symtab_fns to add them to the global chain. */ + + struct sym_fns *next; + +}; + +extern void +extend_psymbol_list PARAMS ((struct psymbol_allocation_list *, + struct objfile *)); + +/* Add any kind of symbol to a psymbol_allocation_list. */ + +/* #include "demangle.h" */ + +extern void +add_psymbol_to_list PARAMS ((char *, int, namespace_enum, enum address_class, + struct psymbol_allocation_list *, long, CORE_ADDR, + enum language, struct objfile *)); + +extern void init_psymbol_list PARAMS ((struct objfile *, int)); + +extern void +sort_pst_symbols PARAMS ((struct partial_symtab *)); + +extern struct symtab * +allocate_symtab PARAMS ((char *, struct objfile *)); + +extern int +free_named_symtabs PARAMS ((char *)); + +extern void +fill_in_vptr_fieldno PARAMS ((struct type *)); + +extern void +add_symtab_fns PARAMS ((struct sym_fns *)); + +extern void +init_entry_point_info PARAMS ((struct objfile *)); + +extern void +syms_from_objfile PARAMS ((struct objfile *, CORE_ADDR, int, int)); + +extern void +new_symfile_objfile PARAMS ((struct objfile *, int, int)); + +extern struct partial_symtab * +start_psymtab_common PARAMS ((struct objfile *, struct section_offsets *, + char *, CORE_ADDR, + struct partial_symbol **, + struct partial_symbol **)); + +/* Sorting your symbols for fast lookup or alphabetical printing. */ + +extern void +sort_block_syms PARAMS ((struct block *)); + +extern void +sort_symtab_syms PARAMS ((struct symtab *)); + +/* 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 PARAMS ((char *, int, struct obstack *)); + +/* Concatenate strings S1, S2 and S3; return the new string. + Space is found in the symbol_obstack. */ + +extern char * +obconcat PARAMS ((struct obstack *obstackp, const char *, const char *, + const char *)); + + /* Variables */ + +/* whether to auto load solibs at startup time: 0/1. */ + +extern int auto_solib_add; + +/* From symfile.c */ + +extern struct partial_symtab * +allocate_psymtab PARAMS ((char *, struct objfile *)); + +extern void find_lowest_section PARAMS ((bfd *, asection *, PTR)); + +/* Remote targets may wish to use this as their load function. */ +extern void generic_load PARAMS ((char *name, int from_tty)); + +/* From dwarfread.c */ + +extern void +dwarf_build_psymtabs PARAMS ((struct objfile *, struct section_offsets *, int, + file_ptr, unsigned int, file_ptr, unsigned int)); + +/* 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 PARAMS ((struct objfile *, + const struct ecoff_debug_swap *, + struct ecoff_debug_info *, + struct section_offsets *)); + +extern void +elfmdebug_build_psymtabs PARAMS ((struct objfile *, + const struct ecoff_debug_swap *, + asection *, + struct section_offsets *)); + +/* From demangle.c */ + +extern void +set_demangling_style PARAMS ((char *)); + +#endif /* !defined(SYMFILE_H) */ diff --git a/contrib/gdb/gdb/symm-nat.c b/contrib/gdb/gdb/symm-nat.c new file mode 100644 index 000000000000..04610660cd58 --- /dev/null +++ b/contrib/gdb/gdb/symm-nat.c @@ -0,0 +1,846 @@ +/* Sequent Symmetry host interface, for GDB when running under Unix. + Copyright 1986, 1987, 1989, 1991, 1992, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* FIXME, some 387-specific items of use taken from i387-tdep.c -- ought to be + merged back in. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "target.h" + +/* FIXME: What is the _INKERNEL define for? */ +#define _INKERNEL +#include +#undef _INKERNEL +#include +#include +#include +#include +#include +#include +#include "gdb_stat.h" +#ifdef _SEQUENT_ +#include +#else +/* Dynix has only machine/ptrace.h, which is already included by sys/user.h */ +/* Dynix has no mptrace call */ +#define mptrace ptrace +#endif +#include "gdbcore.h" +#include +#include +#define TERMINAL struct sgttyb + +#include "gdbcore.h" + +void +store_inferior_registers(regno) +int regno; +{ + struct pt_regset regs; + int i; + extern char registers[]; + + /* FIXME: Fetching the registers is a kludge to initialize all elements + in the fpu and fpa status. This works for normal debugging, but + might cause problems when calling functions in the inferior. + At least fpu_control and fpa_pcr (probably more) should be added + to the registers array to solve this properly. */ + mptrace (XPT_RREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0); + + regs.pr_eax = *(int *)®isters[REGISTER_BYTE(0)]; + regs.pr_ebx = *(int *)®isters[REGISTER_BYTE(5)]; + regs.pr_ecx = *(int *)®isters[REGISTER_BYTE(2)]; + regs.pr_edx = *(int *)®isters[REGISTER_BYTE(1)]; + regs.pr_esi = *(int *)®isters[REGISTER_BYTE(6)]; + regs.pr_edi = *(int *)®isters[REGISTER_BYTE(7)]; + regs.pr_esp = *(int *)®isters[REGISTER_BYTE(14)]; + regs.pr_ebp = *(int *)®isters[REGISTER_BYTE(15)]; + regs.pr_eip = *(int *)®isters[REGISTER_BYTE(16)]; + regs.pr_flags = *(int *)®isters[REGISTER_BYTE(17)]; + for (i = 0; i < 31; i++) + { + regs.pr_fpa.fpa_regs[i] = + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)]; + } + memcpy (regs.pr_fpu.fpu_stack[0], ®isters[REGISTER_BYTE(ST0_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[1], ®isters[REGISTER_BYTE(ST1_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[2], ®isters[REGISTER_BYTE(ST2_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[3], ®isters[REGISTER_BYTE(ST3_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[4], ®isters[REGISTER_BYTE(ST4_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[5], ®isters[REGISTER_BYTE(ST5_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[6], ®isters[REGISTER_BYTE(ST6_REGNUM)], 10); + memcpy (regs.pr_fpu.fpu_stack[7], ®isters[REGISTER_BYTE(ST7_REGNUM)], 10); + mptrace (XPT_WREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0); +} + +void +fetch_inferior_registers (regno) + int regno; +{ + int i; + struct pt_regset regs; + extern char registers[]; + + registers_fetched (); + + mptrace (XPT_RREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0); + *(int *)®isters[REGISTER_BYTE(EAX_REGNUM)] = regs.pr_eax; + *(int *)®isters[REGISTER_BYTE(EBX_REGNUM)] = regs.pr_ebx; + *(int *)®isters[REGISTER_BYTE(ECX_REGNUM)] = regs.pr_ecx; + *(int *)®isters[REGISTER_BYTE(EDX_REGNUM)] = regs.pr_edx; + *(int *)®isters[REGISTER_BYTE(ESI_REGNUM)] = regs.pr_esi; + *(int *)®isters[REGISTER_BYTE(EDI_REGNUM)] = regs.pr_edi; + *(int *)®isters[REGISTER_BYTE(EBP_REGNUM)] = regs.pr_ebp; + *(int *)®isters[REGISTER_BYTE(ESP_REGNUM)] = regs.pr_esp; + *(int *)®isters[REGISTER_BYTE(EIP_REGNUM)] = regs.pr_eip; + *(int *)®isters[REGISTER_BYTE(EFLAGS_REGNUM)] = regs.pr_flags; + for (i = 0; i < FPA_NREGS; i++) + { + *(int *)®isters[REGISTER_BYTE(FP1_REGNUM+i)] = + regs.pr_fpa.fpa_regs[i]; + } + memcpy (®isters[REGISTER_BYTE(ST0_REGNUM)], regs.pr_fpu.fpu_stack[0], 10); + memcpy (®isters[REGISTER_BYTE(ST1_REGNUM)], regs.pr_fpu.fpu_stack[1], 10); + memcpy (®isters[REGISTER_BYTE(ST2_REGNUM)], regs.pr_fpu.fpu_stack[2], 10); + memcpy (®isters[REGISTER_BYTE(ST3_REGNUM)], regs.pr_fpu.fpu_stack[3], 10); + memcpy (®isters[REGISTER_BYTE(ST4_REGNUM)], regs.pr_fpu.fpu_stack[4], 10); + memcpy (®isters[REGISTER_BYTE(ST5_REGNUM)], regs.pr_fpu.fpu_stack[5], 10); + memcpy (®isters[REGISTER_BYTE(ST6_REGNUM)], regs.pr_fpu.fpu_stack[6], 10); + memcpy (®isters[REGISTER_BYTE(ST7_REGNUM)], regs.pr_fpu.fpu_stack[7], 10); +} + +/* FIXME: This should be merged with i387-tdep.c as well. */ +static +print_fpu_status(ep) +struct pt_regset ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + printf_unfiltered("80387:"); + if (ep.pr_fpu.fpu_ip == 0) { + printf_unfiltered(" not in use.\n"); + return; + } else { + printf_unfiltered("\n"); + } + if (ep.pr_fpu.fpu_status != 0) { + print_387_status_word (ep.pr_fpu.fpu_status); + } + print_387_control_word (ep.pr_fpu.fpu_control); + printf_unfiltered ("last exception: "); + printf_unfiltered ("opcode 0x%x; ", ep.pr_fpu.fpu_rsvd4); + printf_unfiltered ("pc 0x%x:0x%x; ", ep.pr_fpu.fpu_cs, ep.pr_fpu.fpu_ip); + printf_unfiltered ("operand 0x%x:0x%x\n", ep.pr_fpu.fpu_data_offset, ep.pr_fpu.fpu_op_sel); + + top = (ep.pr_fpu.fpu_status >> 11) & 7; + + printf_unfiltered ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep.pr_fpu.fpu_tag >> (fpreg * 2)) & 3) + { + case 0: printf_unfiltered ("valid "); break; + case 1: printf_unfiltered ("zero "); break; + case 2: printf_unfiltered ("trap "); break; + case 3: printf_unfiltered ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf_unfiltered ("%02x", ep.pr_fpu.fpu_stack[fpreg][i]); + + i387_to_double ((char *)ep.pr_fpu.fpu_stack[fpreg], (char *)&val); + printf_unfiltered (" %g\n", val); + } + if (ep.pr_fpu.fpu_rsvd1) + warning ("rsvd1 is 0x%x\n", ep.pr_fpu.fpu_rsvd1); + if (ep.pr_fpu.fpu_rsvd2) + warning ("rsvd2 is 0x%x\n", ep.pr_fpu.fpu_rsvd2); + if (ep.pr_fpu.fpu_rsvd3) + warning ("rsvd3 is 0x%x\n", ep.pr_fpu.fpu_rsvd3); + if (ep.pr_fpu.fpu_rsvd5) + warning ("rsvd5 is 0x%x\n", ep.pr_fpu.fpu_rsvd5); +} + + +print_1167_control_word(pcr) +unsigned int pcr; + +{ + int pcr_tmp; + + pcr_tmp = pcr & FPA_PCR_MODE; + printf_unfiltered("\tMODE= %#x; RND= %#x ", pcr_tmp, pcr_tmp & 12); + switch (pcr_tmp & 12) { + case 0: + printf_unfiltered("RN (Nearest Value)"); + break; + case 1: + printf_unfiltered("RZ (Zero)"); + break; + case 2: + printf_unfiltered("RP (Positive Infinity)"); + break; + case 3: + printf_unfiltered("RM (Negative Infinity)"); + break; + } + printf_unfiltered("; IRND= %d ", pcr_tmp & 2); + if (0 == pcr_tmp & 2) { + printf_unfiltered("(same as RND)\n"); + } else { + printf_unfiltered("(toward zero)\n"); + } + pcr_tmp = pcr & FPA_PCR_EM; + printf_unfiltered("\tEM= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_EM_DM) printf_unfiltered(" DM"); + if (pcr_tmp & FPA_PCR_EM_UOM) printf_unfiltered(" UOM"); + if (pcr_tmp & FPA_PCR_EM_PM) printf_unfiltered(" PM"); + if (pcr_tmp & FPA_PCR_EM_UM) printf_unfiltered(" UM"); + if (pcr_tmp & FPA_PCR_EM_OM) printf_unfiltered(" OM"); + if (pcr_tmp & FPA_PCR_EM_ZM) printf_unfiltered(" ZM"); + if (pcr_tmp & FPA_PCR_EM_IM) printf_unfiltered(" IM"); + printf_unfiltered("\n"); + pcr_tmp = FPA_PCR_CC; + printf_unfiltered("\tCC= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_20MHZ) printf_unfiltered(" 20MHZ"); + if (pcr_tmp & FPA_PCR_CC_Z) printf_unfiltered(" Z"); + if (pcr_tmp & FPA_PCR_CC_C2) printf_unfiltered(" C2"); + + /* Dynix defines FPA_PCR_CC_C0 to 0x100 and ptx defines + FPA_PCR_CC_C1 to 0x100. Use whichever is defined and assume + the OS knows what it is doing. */ +#ifdef FPA_PCR_CC_C1 + if (pcr_tmp & FPA_PCR_CC_C1) printf_unfiltered(" C1"); +#else + if (pcr_tmp & FPA_PCR_CC_C0) printf_unfiltered(" C0"); +#endif + + switch (pcr_tmp) + { + case FPA_PCR_CC_Z: + printf_unfiltered(" (Equal)"); + break; +#ifdef FPA_PCR_CC_C1 + case FPA_PCR_CC_C1: +#else + case FPA_PCR_CC_C0: +#endif + printf_unfiltered(" (Less than)"); + break; + case 0: + printf_unfiltered(" (Greater than)"); + break; + case FPA_PCR_CC_Z | +#ifdef FPA_PCR_CC_C1 + FPA_PCR_CC_C1 +#else + FPA_PCR_CC_C0 +#endif + | FPA_PCR_CC_C2: + printf_unfiltered(" (Unordered)"); + break; + default: + printf_unfiltered(" (Undefined)"); + break; + } + printf_unfiltered("\n"); + pcr_tmp = pcr & FPA_PCR_AE; + printf_unfiltered("\tAE= %#x", pcr_tmp); + if (pcr_tmp & FPA_PCR_AE_DE) printf_unfiltered(" DE"); + if (pcr_tmp & FPA_PCR_AE_UOE) printf_unfiltered(" UOE"); + if (pcr_tmp & FPA_PCR_AE_PE) printf_unfiltered(" PE"); + if (pcr_tmp & FPA_PCR_AE_UE) printf_unfiltered(" UE"); + if (pcr_tmp & FPA_PCR_AE_OE) printf_unfiltered(" OE"); + if (pcr_tmp & FPA_PCR_AE_ZE) printf_unfiltered(" ZE"); + if (pcr_tmp & FPA_PCR_AE_EE) printf_unfiltered(" EE"); + if (pcr_tmp & FPA_PCR_AE_IE) printf_unfiltered(" IE"); + printf_unfiltered("\n"); +} + +print_1167_regs(regs) +long regs[FPA_NREGS]; + +{ + int i; + + union { + double d; + long l[2]; + } xd; + union { + float f; + long l; + } xf; + + + for (i = 0; i < FPA_NREGS; i++) { + xf.l = regs[i]; + printf_unfiltered("%%fp%d: raw= %#x, single= %f", i+1, regs[i], xf.f); + if (!(i & 1)) { + printf_unfiltered("\n"); + } else { + xd.l[1] = regs[i]; + xd.l[0] = regs[i+1]; + printf_unfiltered(", double= %f\n", xd.d); + } + } +} + +print_fpa_status(ep) +struct pt_regset ep; + +{ + + printf_unfiltered("WTL 1167:"); + if (ep.pr_fpa.fpa_pcr !=0) { + printf_unfiltered("\n"); + print_1167_control_word(ep.pr_fpa.fpa_pcr); + print_1167_regs(ep.pr_fpa.fpa_regs); + } else { + printf_unfiltered(" not in use.\n"); + } +} + +#if 0 /* disabled because it doesn't go through the target vector. */ +i386_float_info () +{ + char ubuf[UPAGES*NBPG]; + struct pt_regset regset; + + if (have_inferior_p()) + { + PTRACE_READ_REGS (inferior_pid, (PTRACE_ARG3_TYPE) ®set); + } + else + { + int corechan = bfd_cache_lookup (core_bfd); + if (lseek (corechan, 0, 0) < 0) + { + perror ("seek on core file"); + } + if (myread (corechan, ubuf, UPAGES*NBPG) < 0) + { + perror ("read on core file"); + } + /* only interested in the floating point registers */ + regset.pr_fpu = ((struct user *) ubuf)->u_fpusave; + regset.pr_fpa = ((struct user *) ubuf)->u_fpasave; + } + print_fpu_status(regset); + print_fpa_status(regset); +} +#endif + +static volatile int got_sigchld; + +/*ARGSUSED*/ +/* This will eventually be more interesting. */ +void +sigchld_handler(signo) + int signo; +{ + got_sigchld++; +} + +/* + * Signals for which the default action does not cause the process + * to die. See for where this came from (alas, we + * can't use those macros directly) + */ +#ifndef sigmask +#define sigmask(s) (1 << ((s) - 1)) +#endif +#define SIGNALS_DFL_SAFE sigmask(SIGSTOP) | sigmask(SIGTSTP) | \ + sigmask(SIGTTIN) | sigmask(SIGTTOU) | sigmask(SIGCHLD) | \ + sigmask(SIGCONT) | sigmask(SIGWINCH) | sigmask(SIGPWR) | \ + sigmask(SIGURG) | sigmask(SIGPOLL) + +#ifdef ATTACH_DETACH +/* + * Thanks to XPT_MPDEBUGGER, we have to mange child_wait(). + */ +int +child_wait(pid, status) + int pid; + struct target_waitstatus *status; +{ + int save_errno, rv, xvaloff, saoff, sa_hand; + struct pt_stop pt; + struct user u; + sigset_t set; + /* Host signal number for a signal which the inferior terminates with, or + 0 if it hasn't terminated due to a signal. */ + static int death_by_signal = 0; +#ifdef SVR4_SHARED_LIBS /* use this to distinguish ptx 2 vs ptx 4 */ + prstatus_t pstatus; +#endif + + do { + set_sigint_trap(); /* Causes SIGINT to be passed on to the + attached process. */ + save_errno = errno; + + got_sigchld = 0; + + sigemptyset(&set); + + while (got_sigchld == 0) { + sigsuspend(&set); + } + + clear_sigint_trap(); + + rv = mptrace(XPT_STOPSTAT, 0, (char *)&pt, 0); + if (-1 == rv) { + printf("XPT_STOPSTAT: errno %d\n", errno); /* DEBUG */ + continue; + } + + pid = pt.ps_pid; + + if (pid != inferior_pid) { + /* NOTE: the mystery fork in csh/tcsh needs to be ignored. + * We should not return new children for the initial run + * of a process until it has done the exec. + */ + /* inferior probably forked; send it on its way */ + rv = mptrace(XPT_UNDEBUG, pid, 0, 0); + if (-1 == rv) { + printf("child_wait: XPT_UNDEBUG: pid %d: %s\n", pid, + safe_strerror(errno)); + } + continue; + } + /* FIXME: Do we deal with fork notification correctly? */ + switch (pt.ps_reason) { + case PTS_FORK: + /* multi proc: treat like PTS_EXEC */ + /* + * Pretend this didn't happen, since gdb isn't set up + * to deal with stops on fork. + */ + rv = ptrace(PT_CONTSIG, pid, 1, 0); + if (-1 == rv) { + printf("PTS_FORK: PT_CONTSIG: error %d\n", errno); + } + continue; + case PTS_EXEC: + /* + * Pretend this is a SIGTRAP. + */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case PTS_EXIT: + /* + * Note: we stop before the exit actually occurs. Extract + * the exit code from the uarea. If we're stopped in the + * exit() system call, the exit code will be in + * u.u_ap[0]. An exit due to an uncaught signal will have + * something else in here, see the comment in the default: + * case, below. Finally,let the process exit. + */ + if (death_by_signal) + { + status->kind = TARGET_WAITKIND_SIGNALED; + status->value.sig = target_signal_from_host (death_by_signal); + death_by_signal = 0; + break; + } + xvaloff = (unsigned long)&u.u_ap[0] - (unsigned long)&u; + errno = 0; + rv = ptrace(PT_RUSER, pid, (char *)xvaloff, 0); + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = rv; + /* + * addr & data to mptrace() don't matter here, since + * the process is already dead. + */ + rv = mptrace(XPT_UNDEBUG, pid, 0, 0); + if (-1 == rv) { + printf("child_wait: PTS_EXIT: XPT_UNDEBUG: pid %d error %d\n", pid, + errno); + } + break; + case PTS_WATCHPT_HIT: + fatal("PTS_WATCHPT_HIT\n"); + break; + default: + /* stopped by signal */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = target_signal_from_host (pt.ps_reason); + death_by_signal = 0; + + if (0 == (SIGNALS_DFL_SAFE & sigmask(pt.ps_reason))) { + break; + } + /* else default action of signal is to die */ +#ifdef SVR4_SHARED_LIBS + rv = ptrace(PT_GET_PRSTATUS, pid, (char *)&pstatus, 0); + if (-1 == rv) + error("child_wait: signal %d PT_GET_PRSTATUS: %s\n", + pt.ps_reason, safe_strerror(errno)); + if (pstatus.pr_cursig != pt.ps_reason) { + printf("pstatus signal %d, pt signal %d\n", + pstatus.pr_cursig, pt.ps_reason); + } + sa_hand = (int)pstatus.pr_action.sa_handler; +#else + saoff = (unsigned long)&u.u_sa[0] - (unsigned long)&u; + saoff += sizeof(struct sigaction) * (pt.ps_reason - 1); + errno = 0; + sa_hand = ptrace(PT_RUSER, pid, (char *)saoff, 0); + if (errno) + error("child_wait: signal %d: RUSER: %s\n", + pt.ps_reason, safe_strerror(errno)); +#endif + if ((int)SIG_DFL == sa_hand) { + /* we will be dying */ + death_by_signal = pt.ps_reason; + } + break; + } + + } while (pid != inferior_pid); /* Some other child died or stopped */ + + return pid; +} +#else /* !ATTACH_DETACH */ +/* + * Simple child_wait() based on inftarg.c child_wait() for use until + * the MPDEBUGGER child_wait() works properly. This will go away when + * that is fixed. + */ +child_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + int save_errno; + int status; + + do { + pid = wait (&status); + save_errno = errno; + + if (pid == -1) + { + if (save_errno == EINTR) + continue; + fprintf (stderr, "Child process unexpectedly missing: %s.\n", + safe_strerror (save_errno)); + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return -1; + } + } while (pid != inferior_pid); /* Some other child died or stopped */ + store_waitstatus (ourstatus, status); + return pid; +} +#endif /* ATTACH_DETACH */ + + + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return ptrace (request, pid, addr, data); +} + +int +call_mptrace(request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return mptrace(request, pid, addr, data); +} + +#if defined (DEBUG_PTRACE) +/* For the rest of the file, use an extra level of indirection */ +/* This lets us breakpoint usefully on call_ptrace. */ +#define ptrace call_ptrace +#define mptrace call_mptrace +#endif + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + + /* For MPDEBUGGER, don't use PT_KILL, since the child will stop + again with a PTS_EXIT. Just hit him with SIGKILL (so he stops) + and detach. */ + + kill (inferior_pid, SIGKILL); +#ifdef ATTACH_DETACH + detach(SIGKILL); +#else /* ATTACH_DETACH */ + ptrace(PT_KILL, inferior_pid, 0, 0); + wait((int *)NULL); +#endif /* ATTACH_DETACH */ + target_mourn_inferior (); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (pid, step, signal) + int pid; + int step; + enum target_signal signal; +{ + errno = 0; + + if (pid == -1) + pid = inferior_pid; + + /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) + + If this system does not support PT_SSTEP, a higher level function will + have called single_step() to transmute the step request into a + continue request (by setting breakpoints on all possible successor + instructions), so we don't have to worry about that here. */ + + if (step) + ptrace (PT_SSTEP, pid, (PTRACE_ARG3_TYPE) 1, signal); + else + ptrace (PT_CONTSIG, pid, (PTRACE_ARG3_TYPE) 1, signal); + + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef ATTACH_DETACH +/* Start debugging the process whose number is PID. */ +int +attach (pid) + int pid; +{ + sigset_t set; + int rv; + + rv = mptrace(XPT_DEBUG, pid, 0, 0); + if (-1 == rv) { + error("mptrace(XPT_DEBUG): %s", safe_strerror(errno)); + } + rv = mptrace(XPT_SIGNAL, pid, 0, SIGSTOP); + if (-1 == rv) { + error("mptrace(XPT_SIGNAL): %s", safe_strerror(errno)); + } + attach_flag = 1; + return pid; +} + +void +detach (signo) + int signo; +{ + int rv; + + rv = mptrace(XPT_UNDEBUG, inferior_pid, 1, signo); + if (-1 == rv) { + error("mptrace(XPT_UNDEBUG): %s", safe_strerror(errno)); + } + attach_flag = 0; +} + +#endif /* ATTACH_DETACH */ + +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif + + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (PTRACE_XFER_TYPE); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) + / sizeof (PTRACE_XFER_TYPE); + /* Allocate buffer of that many longwords. */ + register PTRACE_XFER_TYPE *buffer + = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_RTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, + 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_RTEXT, inferior_pid, + ((PTRACE_ARG3_TYPE) + (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))), + 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + myaddr, + len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WDATA, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + buffer[i] = ptrace (PT_RTEXT, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + memcpy (myaddr, + (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), + len); + } + return len; +} + + +void +_initialize_symm_nat () +{ +#ifdef ATTACH_DETACH +/* + * the MPDEBUGGER is necessary for process tree debugging and attach + * to work, but it alters the behavior of debugged processes, so other + * things (at least child_wait()) will have to change to accomodate + * that. + * + * Note that attach is not implemented in dynix 3, and not in ptx + * until version 2.1 of the OS. + */ + int rv; + sigset_t set; + struct sigaction sact; + + rv = mptrace(XPT_MPDEBUGGER, 0, 0, 0); + if (-1 == rv) { + fatal("_initialize_symm_nat(): mptrace(XPT_MPDEBUGGER): %s", + safe_strerror(errno)); + } + + /* + * Under MPDEBUGGER, we get SIGCLHD when a traced process does + * anything of interest. + */ + + /* + * Block SIGCHLD. We leave it blocked all the time, and then + * call sigsuspend() in child_wait() to wait for the child + * to do something. None of these ought to fail, but check anyway. + */ + sigemptyset(&set); + rv = sigaddset(&set, SIGCHLD); + if (-1 == rv) { + fatal("_initialize_symm_nat(): sigaddset(SIGCHLD): %s", + safe_strerror(errno)); + } + rv = sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); + if (-1 == rv) { + fatal("_initialize_symm_nat(): sigprocmask(SIG_BLOCK): %s", + safe_strerror(errno)); + } + + sact.sa_handler = sigchld_handler; + sigemptyset(&sact.sa_mask); + sact.sa_flags = SA_NOCLDWAIT; /* keep the zombies away */ + rv = sigaction(SIGCHLD, &sact, (struct sigaction *)NULL); + if (-1 == rv) { + fatal("_initialize_symm_nat(): sigaction(SIGCHLD): %s", + safe_strerror(errno)); + } +#endif +} diff --git a/contrib/gdb/gdb/symm-tdep.c b/contrib/gdb/gdb/symm-tdep.c new file mode 100644 index 000000000000..aaf73e94a74e --- /dev/null +++ b/contrib/gdb/gdb/symm-tdep.c @@ -0,0 +1,93 @@ +/* Sequent Symmetry target interface, for GDB. + Copyright (C) 1986, 1987, 1989, 1991, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* many 387-specific items of use taken from i386-dep.c */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include "gdb_stat.h" +#include "gdbcore.h" +#include + +void +symmetry_extract_return_value(type, regbuf, valbuf) + struct type *type; + char *regbuf; + char *valbuf; +{ + union { + double d; + int l[2]; + } xd; + struct minimal_symbol *msymbol; + float f; + + if (TYPE_CODE_FLT == TYPE_CODE(type)) { + msymbol = lookup_minimal_symbol ("1167_flt", NULL, NULL); + if (msymbol != NULL) { + /* found "1167_flt" means 1167, %fp2-%fp3 */ + /* float & double; 19= %fp2, 20= %fp3 */ + /* no single precision on 1167 */ + xd.l[1] = *((int *)®buf[REGISTER_BYTE(19)]); + xd.l[0] = *((int *)®buf[REGISTER_BYTE(20)]); + switch (TYPE_LENGTH(type)) { + case 4: + /* FIXME: broken for cross-debugging. */ + f = (float) xd.d; + memcpy (valbuf, &f, TYPE_LENGTH(type)); + break; + case 8: + /* FIXME: broken for cross-debugging. */ + memcpy (valbuf, &xd.d, TYPE_LENGTH(type)); + break; + default: + error("Unknown floating point size"); + break; + } + } else { + /* 387 %st(0), gcc uses this */ + i387_to_double(((int *)®buf[REGISTER_BYTE(3)]), + &xd.d); + switch (TYPE_LENGTH(type)) { + case 4: /* float */ + f = (float) xd.d; + /* FIXME: broken for cross-debugging. */ + memcpy (valbuf, &f, 4); + break; + case 8: /* double */ + /* FIXME: broken for cross-debugging. */ + memcpy (valbuf, &xd.d, 8); + break; + default: + error("Unknown floating point size"); + break; + } + } + } else { + memcpy (valbuf, regbuf, TYPE_LENGTH (type)); + } +} diff --git a/contrib/gdb/gdb/symmisc.c b/contrib/gdb/gdb/symmisc.c new file mode 100644 index 000000000000..db58cdd96817 --- /dev/null +++ b/contrib/gdb/gdb/symmisc.c @@ -0,0 +1,1053 @@ +/* Do various things to symbol tables (other than lookup), for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "breakpoint.h" +#include "command.h" +#include "obstack.h" +#include "language.h" +#include "bcache.h" + +#include "gdb_string.h" + +#ifndef DEV_TTY +#define DEV_TTY "/dev/tty" +#endif + +/* Unfortunately for debugging, stderr is usually a macro. This is painful + when calling functions that take FILE *'s from the debugger. + So we make a variable which has the same value and which is accessible when + debugging GDB with itself. Because stdin et al need not be constants, + we initialize them in the _initialize_symmisc function at the bottom + of the file. */ +FILE *std_in; +FILE *std_out; +FILE *std_err; + +/* Prototypes for local functions */ + +static void +dump_symtab PARAMS ((struct objfile *, struct symtab *, GDB_FILE *)); + +static void +dump_psymtab PARAMS ((struct objfile *, struct partial_symtab *, GDB_FILE *)); + +static void +dump_msymbols PARAMS ((struct objfile *, GDB_FILE *)); + +static void +dump_objfile PARAMS ((struct objfile *)); + +static int +block_depth PARAMS ((struct block *)); + +static void +print_partial_symbols PARAMS ((struct partial_symbol **, int, char *, GDB_FILE *)); + +struct print_symbol_args { + struct symbol *symbol; + int depth; + GDB_FILE *outfile; +}; + +static int print_symbol PARAMS ((char *)); + +static void +free_symtab_block PARAMS ((struct objfile *, struct block *)); + + +/* Free a struct block <- B and all the symbols defined in that block. */ + +static void +free_symtab_block (objfile, b) + struct objfile *objfile; + struct block *b; +{ + register int i, n; + n = BLOCK_NSYMS (b); + for (i = 0; i < n; i++) + { + mfree (objfile -> md, SYMBOL_NAME (BLOCK_SYM (b, i))); + mfree (objfile -> md, (PTR) BLOCK_SYM (b, i)); + } + mfree (objfile -> md, (PTR) b); +} + +/* Free all the storage associated with the struct symtab <- S. + Note that some symtabs have contents malloc'ed structure by structure, + while some have contents that all live inside one big block of memory, + and some share the contents of another symbol table and so you should + not free the contents on their behalf (except sometimes the linetable, + which maybe per symtab even when the rest is not). + It is s->free_code that says which alternative to use. */ + +void +free_symtab (s) + register struct symtab *s; +{ + register int i, n; + register struct blockvector *bv; + + switch (s->free_code) + { + case free_nothing: + /* All the contents are part of a big block of memory (an obstack), + and some other symtab is in charge of freeing that block. + Therefore, do nothing. */ + break; + + case free_contents: + /* Here all the contents were malloc'ed structure by structure + and must be freed that way. */ + /* First free the blocks (and their symbols. */ + bv = BLOCKVECTOR (s); + n = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < n; i++) + free_symtab_block (s -> objfile, BLOCKVECTOR_BLOCK (bv, i)); + /* Free the blockvector itself. */ + mfree (s -> objfile -> md, (PTR) bv); + /* Also free the linetable. */ + + case free_linetable: + /* Everything will be freed either by our `free_ptr' + or by some other symtab, except for our linetable. + Free that now. */ + if (LINETABLE (s)) + mfree (s -> objfile -> md, (PTR) LINETABLE (s)); + break; + } + + /* If there is a single block of memory to free, free it. */ + if (s -> free_ptr != NULL) + mfree (s -> objfile -> md, s -> free_ptr); + + /* Free source-related stuff */ + if (s -> line_charpos != NULL) + mfree (s -> objfile -> md, (PTR) s -> line_charpos); + if (s -> fullname != NULL) + mfree (s -> objfile -> md, s -> fullname); + mfree (s -> objfile -> md, (PTR) s); +} + +#if MAINTENANCE_CMDS + +void +print_symbol_bcache_statistics () +{ + struct objfile *objfile; + + immediate_quit++; + ALL_OBJFILES (objfile) + { + printf_filtered ("Byte cache statistics for '%s':\n", objfile -> name); + print_bcache_statistics (&objfile -> psymbol_cache, "partial symbol cache"); + } + immediate_quit--; +} + +void +print_objfile_statistics () +{ + struct objfile *objfile; + + immediate_quit++; + ALL_OBJFILES (objfile) + { + printf_filtered ("Statistics for '%s':\n", objfile -> name); + if (OBJSTAT (objfile, n_stabs) > 0) + printf_filtered (" Number of \"stab\" symbols read: %d\n", + OBJSTAT (objfile, n_stabs)); + if (OBJSTAT (objfile, n_minsyms) > 0) + printf_filtered (" Number of \"minimal symbols read: %d\n", + OBJSTAT (objfile, n_minsyms)); + if (OBJSTAT (objfile, n_psyms) > 0) + printf_filtered (" Number of \"partial symbols read: %d\n", + OBJSTAT (objfile, n_psyms)); + if (OBJSTAT (objfile, n_syms) > 0) + printf_filtered (" Number of \"full symbols read: %d\n", + OBJSTAT (objfile, n_syms)); + if (OBJSTAT (objfile, n_types) > 0) + printf_filtered (" Number of \"types defined: %d\n", + OBJSTAT (objfile, n_types)); + if (OBJSTAT (objfile, sz_strtab) > 0) + printf_filtered (" Space used by a.out string tables: %d\n", + OBJSTAT (objfile, sz_strtab)); + printf_filtered (" Total memory used for psymbol obstack: %d\n", + obstack_memory_used (&objfile -> psymbol_obstack)); + printf_filtered (" Total memory used for psymbol cache: %d\n", + obstack_memory_used (&objfile -> psymbol_cache.cache)); + printf_filtered (" Total memory used for symbol obstack: %d\n", + obstack_memory_used (&objfile -> symbol_obstack)); + printf_filtered (" Total memory used for type obstack: %d\n", + obstack_memory_used (&objfile -> type_obstack)); + } + immediate_quit--; +} + +static void +dump_objfile (objfile) + struct objfile *objfile; +{ + struct symtab *symtab; + struct partial_symtab *psymtab; + + printf_filtered ("\nObject file %s: ", objfile -> name); + printf_filtered ("Objfile at "); + gdb_print_address (objfile, gdb_stdout); + printf_filtered (", bfd at "); + gdb_print_address (objfile->obfd, gdb_stdout); + printf_filtered (", %d minsyms\n\n", + objfile->minimal_symbol_count); + + if (objfile -> psymtabs) + { + printf_filtered ("Psymtabs:\n"); + for (psymtab = objfile -> psymtabs; + psymtab != NULL; + psymtab = psymtab -> next) + { + printf_filtered ("%s at ", + psymtab -> filename); + gdb_print_address (psymtab, gdb_stdout); + printf_filtered (", "); + if (psymtab -> objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } + + if (objfile -> symtabs) + { + printf_filtered ("Symtabs:\n"); + for (symtab = objfile -> symtabs; + symtab != NULL; + symtab = symtab->next) + { + printf_filtered ("%s at ", symtab -> filename); + gdb_print_address (symtab, gdb_stdout); + printf_filtered (", "); + if (symtab -> objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } +} + +/* Print minimal symbols from this objfile. */ + +static void +dump_msymbols (objfile, outfile) + struct objfile *objfile; + GDB_FILE *outfile; +{ + struct minimal_symbol *msymbol; + int index; + char ms_type; + + fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile -> name); + if (objfile -> minimal_symbol_count == 0) + { + fprintf_filtered (outfile, "No minimal symbols found.\n"); + return; + } + for (index = 0, msymbol = objfile -> msymbols; + SYMBOL_NAME (msymbol) != NULL; msymbol++, index++) + { + switch (msymbol -> type) + { + case mst_unknown: + ms_type = 'u'; + break; + case mst_text: + ms_type = 'T'; + break; + case mst_solib_trampoline: + ms_type = 'S'; + break; + case mst_data: + ms_type = 'D'; + break; + case mst_bss: + ms_type = 'B'; + break; + case mst_abs: + ms_type = 'A'; + break; + case mst_file_text: + ms_type = 't'; + break; + case mst_file_data: + ms_type = 'd'; + break; + case mst_file_bss: + ms_type = 'b'; + break; + default: + ms_type = '?'; + break; + } + fprintf_filtered (outfile, "[%2d] %c %#10lx %s", index, ms_type, + SYMBOL_VALUE_ADDRESS (msymbol), SYMBOL_NAME (msymbol)); + if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL) + { + fprintf_filtered (outfile, " %s", SYMBOL_DEMANGLED_NAME (msymbol)); + } +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (msymbol->filename) + fprintf_filtered (outfile, " %s", msymbol->filename); +#endif + fputs_filtered ("\n", outfile); + } + if (objfile -> minimal_symbol_count != index) + { + warning ("internal error: minimal symbol count %d != %d", + objfile -> minimal_symbol_count, index); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_psymtab (objfile, psymtab, outfile) + struct objfile *objfile; + struct partial_symtab *psymtab; + GDB_FILE *outfile; +{ + int i; + + fprintf_filtered (outfile, "\nPartial symtab for source file %s ", + psymtab -> filename); + fprintf_filtered (outfile, "(object "); + gdb_print_address (psymtab, outfile); + fprintf_filtered (outfile, ")\n\n"); + fprintf_unfiltered (outfile, " Read from object file %s (", + objfile -> name); + gdb_print_address (objfile, outfile); + fprintf_unfiltered (outfile, ")\n"); + + if (psymtab -> readin) + { + fprintf_filtered (outfile, + " Full symtab was read (at "); + gdb_print_address (psymtab->symtab, outfile); + fprintf_filtered (outfile, " by function at "); + gdb_print_address ((PTR)psymtab->read_symtab, outfile); + fprintf_filtered (outfile, ")\n"); + } + + fprintf_filtered (outfile, " Relocate symbols by "); + for (i = 0; i < psymtab->objfile->num_sections; ++i) + { + if (i != 0) + fprintf_filtered (outfile, ", "); + wrap_here (" "); + print_address_numeric (ANOFFSET (psymtab->section_offsets, i), + 1, + outfile); + } + fprintf_filtered (outfile, "\n"); + + fprintf_filtered (outfile, " Symbols cover text addresses "); + print_address_numeric (psymtab->textlow, 1, outfile); + fprintf_filtered (outfile, "-"); + print_address_numeric (psymtab->texthigh, 1, outfile); + fprintf_filtered (outfile, "\n"); + fprintf_filtered (outfile, " Depends on %d other partial symtabs.\n", + psymtab -> number_of_dependencies); + for (i = 0; i < psymtab -> number_of_dependencies; i++) + { + fprintf_filtered (outfile, " %d ", i); + gdb_print_address (psymtab -> dependencies[i], outfile); + fprintf_filtered (outfile, " %s\n", + psymtab -> dependencies[i] -> filename); + } + if (psymtab -> n_global_syms > 0) + { + print_partial_symbols (objfile -> global_psymbols.list + + psymtab -> globals_offset, + psymtab -> n_global_syms, "Global", outfile); + } + if (psymtab -> n_static_syms > 0) + { + print_partial_symbols (objfile -> static_psymbols.list + + psymtab -> statics_offset, + psymtab -> n_static_syms, "Static", outfile); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_symtab (objfile, symtab, outfile) + struct objfile *objfile; + struct symtab *symtab; + GDB_FILE *outfile; +{ + register int i, j; + int len, blen; + register struct linetable *l; + struct blockvector *bv; + register struct block *b; + int depth; + + fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename); + fprintf_filtered (outfile, "Read from object file %s (", objfile->name); + gdb_print_address (objfile, outfile); + fprintf_filtered (outfile, ")\n"); + fprintf_filtered (outfile, "Language: %s\n", language_str (symtab -> language)); + + /* First print the line table. */ + l = LINETABLE (symtab); + if (l) + { + fprintf_filtered (outfile, "\nLine table:\n\n"); + len = l->nitems; + for (i = 0; i < len; i++) + { + fprintf_filtered (outfile, " line %d at ", l->item[i].line); + print_address_numeric (l->item[i].pc, 1, outfile); + fprintf_filtered (outfile, "\n"); + } + } + /* Now print the block info. */ + fprintf_filtered (outfile, "\nBlockvector:\n\n"); + bv = BLOCKVECTOR (symtab); + len = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < len; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + depth = block_depth (b) * 2; + print_spaces (depth, outfile); + fprintf_filtered (outfile, "block #%03d (object ", i); + gdb_print_address (b, outfile); + fprintf_filtered (outfile, ") "); + fprintf_filtered (outfile, "["); + print_address_numeric (BLOCK_START (b), 1, outfile); + fprintf_filtered (outfile, ".."); + print_address_numeric (BLOCK_END (b), 1, outfile); + fprintf_filtered (outfile, "]"); + if (BLOCK_SUPERBLOCK (b)) + { + fprintf_filtered (outfile, " (under "); + gdb_print_address (BLOCK_SUPERBLOCK (b), outfile); + fprintf_filtered (outfile, ")"); + } + if (BLOCK_FUNCTION (b)) + { + fprintf_filtered (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b))); + if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL) + { + fprintf_filtered (outfile, " %s", + SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b))); + } + } + if (BLOCK_GCC_COMPILED(b)) + fprintf_filtered (outfile, " gcc%d compiled", BLOCK_GCC_COMPILED(b)); + fprintf_filtered (outfile, "\n"); + blen = BLOCK_NSYMS (b); + for (j = 0; j < blen; j++) + { + struct print_symbol_args s; + s.symbol = BLOCK_SYM (b, j); + s.depth = depth + 1; + s.outfile = outfile; + catch_errors (print_symbol, &s, "Error printing symbol:\n", + RETURN_MASK_ALL); + } + } + fprintf_filtered (outfile, "\n"); +} + +void +maintenance_print_symbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + GDB_FILE *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct symtab *s; + + dont_repeat (); + + if (args == NULL) + { + error ("\ +Arguments missing: an output file name and an optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, (char *) outfile); + + immediate_quit++; + ALL_SYMTABS (objfile, s) + if (symname == NULL || (STREQ (symname, s -> filename))) + dump_symtab (objfile, s, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE. ARGS->DEPTH says how + far to indent. ARGS is really a struct print_symbol_args *, but is + declared as char * to get it past catch_errors. Returns 0 for error, + 1 for success. */ + +static int +print_symbol (args) + char *args; +{ + struct symbol *symbol = ((struct print_symbol_args *)args)->symbol; + int depth = ((struct print_symbol_args *)args)->depth; + GDB_FILE *outfile = ((struct print_symbol_args *)args)->outfile; + + print_spaces (depth, outfile); + if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE) + { + fprintf_filtered (outfile, "label %s at ", SYMBOL_SOURCE_NAME (symbol)); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + fprintf_filtered (outfile, "\n"); + return 1; + } + if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE) + { + if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol))) + { + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + else + { + fprintf_filtered (outfile, "%s %s = ", + (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM + ? "enum" + : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT + ? "struct" : "union")), + SYMBOL_NAME (symbol)); + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + fprintf_filtered (outfile, ";\n"); + } + else + { + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + fprintf_filtered (outfile, "typedef "); + if (SYMBOL_TYPE (symbol)) + { + /* Print details of types, except for enums where it's clutter. */ + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol), + outfile, + TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM, + depth); + fprintf_filtered (outfile, "; "); + } + else + fprintf_filtered (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol)); + + switch (SYMBOL_CLASS (symbol)) + { + case LOC_CONST: + fprintf_filtered (outfile, "const %ld (0x%lx),", + SYMBOL_VALUE (symbol), + SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + { + unsigned i; + struct type *type = check_typedef (SYMBOL_TYPE (symbol)); + fprintf_filtered (outfile, "const %u hex bytes:", + TYPE_LENGTH (type)); + for (i = 0; i < TYPE_LENGTH (type); i++) + fprintf_filtered (outfile, " %02x", + (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]); + fprintf_filtered (outfile, ","); + } + break; + + case LOC_STATIC: + fprintf_filtered (outfile, "static at "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1,outfile); + fprintf_filtered (outfile, ","); + break; + + case LOC_REGISTER: + fprintf_filtered (outfile, "register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf_filtered (outfile, "arg at offset 0x%lx,", + SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL_ARG: + fprintf_filtered (outfile, "arg at offset 0x%lx from fp,", + SYMBOL_VALUE (symbol)); + break; + + case LOC_REF_ARG: + fprintf_filtered (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM: + fprintf_filtered (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM_ADDR: + fprintf_filtered (outfile, "address parameter register %ld,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf_filtered (outfile, "local at offset 0x%lx,", + SYMBOL_VALUE (symbol)); + break; + + case LOC_BASEREG: + fprintf_filtered (outfile, "local at 0x%lx from register %d", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_BASEREG_ARG: + fprintf_filtered (outfile, "arg at 0x%lx from register %d,", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf_filtered (outfile, "label at "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + break; + + case LOC_BLOCK: + fprintf_filtered (outfile, "block (object "); + gdb_print_address (SYMBOL_BLOCK_VALUE (symbol), outfile); + fprintf_filtered (outfile, ") starting at "); + print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)), + 1, + outfile); + fprintf_filtered (outfile, ","); + break; + + case LOC_UNRESOLVED: + fprintf_filtered (outfile, "unresolved"); + break; + + case LOC_OPTIMIZED_OUT: + fprintf_filtered (outfile, "optimized out"); + break; + + default: + fprintf_filtered (outfile, "botched symbol class %x", + SYMBOL_CLASS (symbol)); + break; + } + } + fprintf_filtered (outfile, "\n"); + return 1; +} + +void +maintenance_print_psymbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + GDB_FILE *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct partial_symtab *ps; + + dont_repeat (); + + if (args == NULL) + { + error ("print-psymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, (char *) argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, outfile); + + immediate_quit++; + ALL_PSYMTABS (objfile, ps) + if (symname == NULL || (STREQ (symname, ps -> filename))) + dump_psymtab (objfile, ps, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +static void +print_partial_symbols (p, count, what, outfile) + struct partial_symbol **p; + int count; + char *what; + GDB_FILE *outfile; +{ + fprintf_filtered (outfile, " %s partial symbols:\n", what); + while (count-- > 0) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_NAME(*p)); + if (SYMBOL_DEMANGLED_NAME (*p) != NULL) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (*p)); + } + fputs_filtered (", ", outfile); + switch (SYMBOL_NAMESPACE (*p)) + { + case UNDEF_NAMESPACE: + fputs_filtered ("undefined namespace, ", outfile); + break; + case VAR_NAMESPACE: + /* This is the usual thing -- don't print it */ + break; + case STRUCT_NAMESPACE: + fputs_filtered ("struct namespace, ", outfile); + break; + case LABEL_NAMESPACE: + fputs_filtered ("label namespace, ", outfile); + break; + default: + fputs_filtered (", ", outfile); + break; + } + switch (SYMBOL_CLASS (*p)) + { + case LOC_UNDEF: + fputs_filtered ("undefined", outfile); + break; + case LOC_CONST: + fputs_filtered ("constant int", outfile); + break; + case LOC_STATIC: + fputs_filtered ("static", outfile); + break; + case LOC_REGISTER: + fputs_filtered ("register", outfile); + break; + case LOC_ARG: + fputs_filtered ("pass by value", outfile); + break; + case LOC_REF_ARG: + fputs_filtered ("pass by reference", outfile); + break; + case LOC_REGPARM: + fputs_filtered ("register parameter", outfile); + break; + case LOC_REGPARM_ADDR: + fputs_filtered ("register address parameter", outfile); + break; + case LOC_LOCAL: + fputs_filtered ("stack parameter", outfile); + break; + case LOC_TYPEDEF: + fputs_filtered ("type", outfile); + break; + case LOC_LABEL: + fputs_filtered ("label", outfile); + break; + case LOC_BLOCK: + fputs_filtered ("function", outfile); + break; + case LOC_CONST_BYTES: + fputs_filtered ("constant bytes", outfile); + break; + case LOC_LOCAL_ARG: + fputs_filtered ("shuffled arg", outfile); + break; + case LOC_UNRESOLVED: + fputs_filtered ("unresolved", outfile); + break; + case LOC_OPTIMIZED_OUT: + fputs_filtered ("optimized out", outfile); + break; + default: + fputs_filtered ("", outfile); + break; + } + fputs_filtered (", ", outfile); + /* FIXME-32x64: Need to use SYMBOL_VALUE_ADDRESS, etc.; this + could be 32 bits when some of the other fields in the union + are 64. */ + fprintf_filtered (outfile, "0x%lx\n", SYMBOL_VALUE (*p)); + p++; + } +} + +void +maintenance_print_msymbols (args, from_tty) + char *args; + int from_tty; +{ + char **argv; + GDB_FILE *outfile; + struct cleanup *cleanups; + char *filename = DEV_TTY; + char *symname = NULL; + struct objfile *objfile; + + dont_repeat (); + + if (args == NULL) + { + error ("print-msymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup (freeargv, argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (free, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup (fclose, outfile); + + immediate_quit++; + ALL_OBJFILES (objfile) + if (symname == NULL || (STREQ (symname, objfile -> name))) + dump_msymbols (objfile, outfile); + immediate_quit--; + fprintf_filtered (outfile, "\n\n"); + do_cleanups (cleanups); +} + +void +maintenance_print_objfiles (ignore, from_tty) + char *ignore; + int from_tty; +{ + struct objfile *objfile; + + dont_repeat (); + + immediate_quit++; + ALL_OBJFILES (objfile) + dump_objfile (objfile); + immediate_quit--; +} + +/* Check consistency of psymtabs and symtabs. */ + +void +maintenance_check_symtabs (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct symbol *sym; + register struct partial_symbol **psym; + register struct symtab *s = NULL; + register struct partial_symtab *ps; + struct blockvector *bv; + register struct objfile *objfile; + register struct block *b; + int length; + + ALL_PSYMTABS (objfile, ps) + { + s = PSYMTAB_TO_SYMTAB(ps); + if (s == NULL) + continue; + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + psym = ps->objfile->static_psymbols.list + ps->statics_offset; + length = ps->n_static_syms; + while (length--) + { + sym = lookup_block_symbol (b, SYMBOL_NAME (*psym), + SYMBOL_NAMESPACE (*psym)); + if (!sym) + { + printf_filtered ("Static symbol `"); + puts_filtered (SYMBOL_NAME (*psym)); + printf_filtered ("' only found in "); + puts_filtered (ps->filename); + printf_filtered (" psymtab\n"); + } + psym++; + } + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + psym = ps->objfile->global_psymbols.list + ps->globals_offset; + length = ps->n_global_syms; + while (length--) + { + sym = lookup_block_symbol (b, SYMBOL_NAME (*psym), + SYMBOL_NAMESPACE (*psym)); + if (!sym) + { + printf_filtered ("Global symbol `"); + puts_filtered (SYMBOL_NAME (*psym)); + printf_filtered ("' only found in "); + puts_filtered (ps->filename); + printf_filtered (" psymtab\n"); + } + psym++; + } + if (ps->texthigh < ps->textlow) + { + printf_filtered ("Psymtab "); + puts_filtered (ps->filename); + printf_filtered (" covers bad range "); + print_address_numeric (ps->textlow, 1, stdout); + printf_filtered (" - "); + print_address_numeric (ps->texthigh, 1, stdout); + printf_filtered ("\n"); + continue; + } + if (ps->texthigh == 0) + continue; + if (ps->textlow < BLOCK_START (b) || ps->texthigh > BLOCK_END (b)) + { + printf_filtered ("Psymtab "); + puts_filtered (ps->filename); + printf_filtered (" covers "); + print_address_numeric (ps->textlow, 1, stdout); + printf_filtered (" - "); + print_address_numeric (ps->texthigh, 1, stdout); + printf_filtered (" but symtab covers only "); + print_address_numeric (BLOCK_START (b), 1, stdout); + printf_filtered (" - "); + print_address_numeric (BLOCK_END (b), 1, stdout); + printf_filtered ("\n"); + } + } +} + + +/* Return the nexting depth of a block within other blocks in its symtab. */ + +static int +block_depth (block) + struct block *block; +{ + register int i = 0; + while ((block = BLOCK_SUPERBLOCK (block)) != NULL) + { + i++; + } + return i; +} + +#endif /* MAINTENANCE_CMDS */ + + +/* Increase the space allocated for LISTP, which is probably + global_psymbols or static_psymbols. This space will eventually + be freed in free_objfile(). */ + +void +extend_psymbol_list (listp, objfile) + register struct psymbol_allocation_list *listp; + struct objfile *objfile; +{ + int new_size; + if (listp->size == 0) + { + new_size = 255; + listp->list = (struct partial_symbol **) + xmmalloc (objfile -> md, new_size * sizeof (struct partial_symbol *)); + } + else + { + new_size = listp->size * 2; + listp->list = (struct partial_symbol **) + xmrealloc (objfile -> md, (char *) listp->list, + new_size * sizeof (struct partial_symbol *)); + } + /* Next assumes we only went one over. Should be good if + program works correctly */ + listp->next = listp->list + listp->size; + listp->size = new_size; +} + + +/* Do early runtime initializations. */ +void +_initialize_symmisc () +{ + std_in = stdin; + std_out = stdout; + std_err = stderr; +} diff --git a/contrib/gdb/gdb/symtab.c b/contrib/gdb/gdb/symtab.c new file mode 100644 index 000000000000..41605bc89ae1 --- /dev/null +++ b/contrib/gdb/gdb/symtab.c @@ -0,0 +1,3346 @@ +/* Symbol table lookup for the GNU debugger, GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "frame.h" +#include "target.h" +#include "value.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcmd.h" +#include "call-cmds.h" +#include "gnu-regex.h" +#include "expression.h" +#include "language.h" +#include "demangle.h" + +#include "obstack.h" + +#include +#include +#include "gdb_string.h" +#include "gdb_stat.h" +#include + +/* Prototypes for local functions */ + +extern int +find_methods PARAMS ((struct type *, char *, struct symbol **)); + +static void +completion_list_add_name PARAMS ((char *, char *, int, char *, char *)); + +static void +build_canonical_line_spec PARAMS ((struct symtab_and_line *, char *, char ***)); + +static struct symtabs_and_lines +decode_line_2 PARAMS ((struct symbol *[], int, int, char ***)); + +static void +rbreak_command PARAMS ((char *, int)); + +static void +types_info PARAMS ((char *, int)); + +static void +functions_info PARAMS ((char *, int)); + +static void +variables_info PARAMS ((char *, int)); + +static void +sources_info PARAMS ((char *, int)); + +static void +list_symbols PARAMS ((char *, int, int, int)); + +static void +output_source_filename PARAMS ((char *, int *)); + +static char * +operator_chars PARAMS ((char *, char **)); + +static int find_line_common PARAMS ((struct linetable *, int, int *)); + +static struct partial_symbol * +lookup_partial_symbol PARAMS ((struct partial_symtab *, const char *, + int, namespace_enum)); + +static struct symtab * +lookup_symtab_1 PARAMS ((char *)); + +/* */ + +/* The single non-language-specific builtin type */ +struct type *builtin_type_error; + +/* Block in which the most recently searched-for symbol was found. + Might be better to make this a parameter to lookup_symbol and + value_of_this. */ + +const struct block *block_found; + +char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command."; + +/* While the C++ support is still in flux, issue a possibly helpful hint on + using the new command completion feature on single quoted demangled C++ + symbols. Remove when loose ends are cleaned up. FIXME -fnf */ + +void +cplusplus_hint (name) + char *name; +{ + while (*name == '\'') + name++; + printf_filtered ("Hint: try '%s or '%s\n", name, name); + printf_filtered ("(Note leading single quote.)\n"); +} + +/* Check for a symtab of a specific name; first in symtabs, then in + psymtabs. *If* there is no '/' in the name, a match after a '/' + in the symtab filename will also work. */ + +static struct symtab * +lookup_symtab_1 (name) + char *name; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register char *slash; + register struct objfile *objfile; + + got_symtab: + + /* First, search for an exact match */ + + ALL_SYMTABS (objfile, s) + if (STREQ (name, s->filename)) + return s; + + slash = strchr (name, '/'); + + /* Now, search for a matching tail (only if name doesn't have any dirs) */ + + if (!slash) + ALL_SYMTABS (objfile, s) + { + char *p = s -> filename; + char *tail = strrchr (p, '/'); + + if (tail) + p = tail + 1; + + if (STREQ (p, name)) + return s; + } + + /* Same search rules as above apply here, but now we look thru the + psymtabs. */ + + ps = lookup_partial_symtab (name); + if (!ps) + return (NULL); + + if (ps -> readin) + error ("Internal: readin %s pst for `%s' found when no symtab found.", + ps -> filename, name); + + s = PSYMTAB_TO_SYMTAB (ps); + + if (s) + return s; + + /* At this point, we have located the psymtab for this file, but + the conversion to a symtab has failed. This usually happens + when we are looking up an include file. In this case, + PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has + been created. So, we need to run through the symtabs again in + order to find the file. + XXX - This is a crock, and should be fixed inside of the the + symbol parsing routines. */ + goto got_symtab; +} + +/* Lookup the symbol table of a source file named NAME. Try a couple + of variations if the first lookup doesn't work. */ + +struct symtab * +lookup_symtab (name) + char *name; +{ + register struct symtab *s; +#if 0 + register char *copy; +#endif + + s = lookup_symtab_1 (name); + if (s) return s; + +#if 0 + /* This screws c-exp.y:yylex if there is both a type "tree" and a symtab + "tree.c". */ + + /* If name not found as specified, see if adding ".c" helps. */ + /* Why is this? Is it just a user convenience? (If so, it's pretty + questionable in the presence of C++, FORTRAN, etc.). It's not in + the GDB manual. */ + + copy = (char *) alloca (strlen (name) + 3); + strcpy (copy, name); + strcat (copy, ".c"); + s = lookup_symtab_1 (copy); + if (s) return s; +#endif /* 0 */ + + /* We didn't find anything; die. */ + return 0; +} + +/* Lookup the partial symbol table of a source file named NAME. + *If* there is no '/' in the name, a match after a '/' + in the psymtab filename will also work. */ + +struct partial_symtab * +lookup_partial_symtab (name) +char *name; +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (STREQ (name, pst -> filename)) + { + return (pst); + } + } + + /* Now, search for a matching tail (only if name doesn't have any dirs) */ + + if (!strchr (name, '/')) + ALL_PSYMTABS (objfile, pst) + { + char *p = pst -> filename; + char *tail = strrchr (p, '/'); + + if (tail) + p = tail + 1; + + if (STREQ (p, name)) + return (pst); + } + + return (NULL); +} + +/* Demangle a GDB method stub type. + Note that this function is g++ specific. */ + +char * +gdb_mangle_name (type, i, j) + struct type *type; + int i, j; +{ + int mangled_name_len; + char *mangled_name; + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + struct fn_field *method = &f[j]; + char *field_name = TYPE_FN_FIELDLIST_NAME (type, i); + char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); + 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)? */ + int is_full_physname_constructor; + + int is_constructor; + int is_destructor = DESTRUCTOR_PREFIX_P (physname); + /* Need a new type prefix. */ + char *const_prefix = method->is_const ? "C" : ""; + char *volatile_prefix = method->is_volatile ? "V" : ""; + char buf[20]; + int len = (newname == NULL ? 0 : strlen (newname)); + + is_full_physname_constructor = + ((physname[0]=='_' && physname[1]=='_' && + (isdigit(physname[2]) || physname[2]=='Q' || physname[2]=='t')) + || (strncmp(physname, "__ct", 4) == 0)); + + is_constructor = + is_full_physname_constructor || (newname && STREQ(field_name, newname)); + + if (!is_destructor) + is_destructor = (strncmp(physname, "__dt", 4) == 0); + + if (is_destructor || is_full_physname_constructor) + { + mangled_name = (char*) xmalloc(strlen(physname)+1); + strcpy(mangled_name, physname); + return mangled_name; + } + + if (len == 0) + { + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + if (strcmp(buf, "__") == 0) + buf[0] = '\0'; + } + else if (newname != NULL && strchr (newname, '<') != NULL) + { + /* Template methods are fully mangled. */ + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + newname = NULL; + len = 0; + } + else + { + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + } + mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) + + strlen (buf) + len + + strlen (physname) + + 1); + + /* Only needed for GNU-mangled names. ANSI-mangled names + work with the normal mechanisms. */ + if (OPNAME_PREFIX_P (field_name)) + { + const char *opname = cplus_mangle_opname (field_name + 3, 0); + if (opname == NULL) + error ("No mangling for \"%s\"", field_name); + mangled_name_len += strlen (opname); + mangled_name = (char *)xmalloc (mangled_name_len); + + strncpy (mangled_name, field_name, 3); + mangled_name[3] = '\0'; + strcat (mangled_name, opname); + } + else + { + mangled_name = (char *)xmalloc (mangled_name_len); + if (is_constructor) + mangled_name[0] = '\0'; + else + strcpy (mangled_name, field_name); + } + strcat (mangled_name, buf); + /* If the class doesn't have a name, i.e. newname NULL, then we just + mangle it using 0 for the length of the class. Thus it gets mangled + as something starting with `::' rather than `classname::'. */ + if (newname != NULL) + strcat (mangled_name, newname); + + strcat (mangled_name, physname); + return (mangled_name); +} + + +/* Find which partial symtab on contains PC. Return 0 if none. */ + +struct partial_symtab * +find_pc_psymtab (pc) + register CORE_ADDR pc; +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (pc >= pst->textlow && pc < pst->texthigh) + { + struct minimal_symbol *msymbol; + struct partial_symtab *tpst; + + /* An objfile that has its functions reordered might have + many partial symbol tables containing the PC, but + we want the partial symbol table that contains the + function containing the PC. */ + if (!(objfile->flags & OBJF_REORDERED)) + return (pst); + + msymbol = lookup_minimal_symbol_by_pc (pc); + if (msymbol == NULL) + return (pst); + + for (tpst = pst; tpst != NULL; tpst = tpst->next) + { + if (pc >= tpst->textlow && pc < tpst->texthigh) + { + struct partial_symbol *p; + + p = find_pc_psymbol (tpst, pc); + if (p != NULL + && SYMBOL_VALUE_ADDRESS(p) + == SYMBOL_VALUE_ADDRESS (msymbol)) + return (tpst); + } + } + return (pst); + } + } + return (NULL); +} + +/* Find which partial symbol within a psymtab contains PC. Return 0 + if none. Check all psymtabs if PSYMTAB is 0. */ +struct partial_symbol * +find_pc_psymbol (psymtab, pc) + struct partial_symtab *psymtab; + CORE_ADDR pc; +{ + struct partial_symbol *best = NULL, *p, **pp; + CORE_ADDR best_pc; + + if (!psymtab) + psymtab = find_pc_psymtab (pc); + if (!psymtab) + return 0; + + best_pc = psymtab->textlow - 1; + + /* 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) + < psymtab->n_global_syms); + pp++) + { + p = *pp; + if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE + && SYMBOL_CLASS (p) == LOC_BLOCK + && pc >= SYMBOL_VALUE_ADDRESS (p) + && SYMBOL_VALUE_ADDRESS (p) > best_pc) + { + best_pc = SYMBOL_VALUE_ADDRESS (p); + best = p; + } + } + for (pp = psymtab->objfile->static_psymbols.list + psymtab->statics_offset; + (pp - (psymtab->objfile->static_psymbols.list + psymtab->statics_offset) + < psymtab->n_static_syms); + pp++) + { + p = *pp; + if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE + && SYMBOL_CLASS (p) == LOC_BLOCK + && pc >= SYMBOL_VALUE_ADDRESS (p) + && SYMBOL_VALUE_ADDRESS (p) > best_pc) + { + best_pc = SYMBOL_VALUE_ADDRESS (p); + best = p; + } + } + if (best_pc == psymtab->textlow - 1) + return 0; + return best; +} + + +/* Find the definition for a specified symbol name NAME + in namespace NAMESPACE, visible from lexical block BLOCK. + Returns the struct symbol pointer, or zero if no symbol is found. + If SYMTAB is non-NULL, store the symbol table in which the + symbol was found there, or NULL if not found. + C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if + NAME is a field of the current implied argument `this'. If so set + *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero. + 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 + 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, and + nindy_frame_chain_valid in nindy-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++ code). */ + +struct symbol * +lookup_symbol (name, block, namespace, is_a_field_of_this, symtab) + const char *name; + register const struct block *block; + const namespace_enum namespace; + int *is_a_field_of_this; + struct symtab **symtab; +{ + register struct symbol *sym; + register struct symtab *s = NULL; + register struct partial_symtab *ps; + struct blockvector *bv; + register struct objfile *objfile; + register struct block *b; + register struct minimal_symbol *msymbol; + + /* Search specified block and its superiors. */ + + while (block != 0) + { + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + { + /* Search the list of symtabs for one which contains the + address of the start of this block. */ + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + goto found; + } +found: + *symtab = s; + } + + return (sym); + } + block = BLOCK_SUPERBLOCK (block); + } + + /* FIXME: this code is never executed--block is always NULL at this + point. What is it trying to do, anyway? We already should have + checked the STATIC_BLOCK above (it is the superblock of top-level + blocks). Why is VAR_NAMESPACE special-cased? */ + /* Don't need to mess with the psymtabs; if we have a block, + that file is read in. If we don't, then we deal later with + all the psymtab stuff that needs checking. */ + if (namespace == VAR_NAMESPACE && block != NULL) + { + struct block *b; + /* Find the right symtab. */ + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + if (BLOCK_START (b) <= BLOCK_START (block) + && BLOCK_END (b) > BLOCK_START (block)) + { + sym = lookup_block_symbol (b, name, VAR_NAMESPACE); + if (sym) + { + block_found = b; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + } + } + + + /* C++: If requested to do so by the caller, + check to see if NAME is a field of `this'. */ + if (is_a_field_of_this) + { + struct value *v = value_of_this (0); + + *is_a_field_of_this = 0; + if (v && check_field (v, name)) + { + *is_a_field_of_this = 1; + if (symtab != NULL) + *symtab = NULL; + return 0; + } + } + + /* Now search all global blocks. Do the symtab's first, then + check the psymtab's */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + /* Check for the possibility of the symbol being a function or + a mangled variable that is stored in one of the minimal symbol tables. + Eventually, all global symbols might be resolved in this way. */ + + if (namespace == VAR_NAMESPACE) + { + msymbol = lookup_minimal_symbol (name, NULL, NULL); + if (msymbol != NULL) + { + s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)); + if (s != NULL) + { + /* This is a function which has a symtab for its address. */ + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), + namespace); + /* We kept static functions in minimal symbol table as well as + in static scope. We want to find them in the symbol table. */ + if (!sym) { + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, SYMBOL_NAME (msymbol), + namespace); + } + + /* sym == 0 if symbol was found in the minimal symbol table + but not in the symtab. + Return 0 to use the msymbol definition of "foo_". + + This happens for Fortran "foo_" symbols, + which are "foo" in the symtab. + + This can also happen if "asm" is used to make a + regular symbol but not a debugging symbol, e.g. + asm(".globl _main"); + asm("_main:"); + */ + + if (symtab != NULL) + *symtab = s; + return sym; + } + else if (MSYMBOL_TYPE (msymbol) != mst_text + && MSYMBOL_TYPE (msymbol) != mst_file_text + && !STREQ (name, SYMBOL_NAME (msymbol))) + { + /* This is a mangled variable, look it up by its + mangled name. */ + return lookup_symbol (SYMBOL_NAME (msymbol), block, + namespace, is_a_field_of_this, symtab); + } + /* There are no debug symbols for this file, or we are looking + for an unmangled variable. + Try to find a matching static symbol below. */ + } + } + + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: global symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + /* Now search all per-file blocks. + Not strictly correct, but more useful than an error. + Do the symtabs first, then check the psymtabs */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + sym = lookup_block_symbol (block, name, namespace); + if (!sym) + error ("Internal: static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); + if (symtab != NULL) + *symtab = s; + return sym; + } + } + + if (symtab != NULL) + *symtab = NULL; + return 0; +} + +/* Look, in partial_symtab PST, for symbol NAME. Check the global + symbols if GLOBAL, the static symbols if not */ + +static struct partial_symbol * +lookup_partial_symbol (pst, name, global, namespace) + struct partial_symtab *pst; + const char *name; + int global; + namespace_enum namespace; +{ + struct partial_symbol **start, **psym; + struct partial_symbol **top, **bottom, **center; + int length = (global ? pst->n_global_syms : pst->n_static_syms); + int do_linear_search = 1; + + if (length == 0) + { + return (NULL); + } + + start = (global ? + pst->objfile->global_psymbols.list + pst->globals_offset : + pst->objfile->static_psymbols.list + pst->statics_offset ); + + if (global) /* This means we can use a binary search. */ + { + do_linear_search = 0; + + /* Binary search. This search is guaranteed to end with center + pointing at the earliest partial symbol with the correct + name. At that point *all* partial symbols with that name + will be checked against the correct namespace. */ + + bottom = start; + top = start + length - 1; + while (top > bottom) + { + center = bottom + (top - bottom) / 2; + if (!(center < top)) + abort (); + if (!do_linear_search && SYMBOL_LANGUAGE (*center) == language_cplus) + { + do_linear_search = 1; + } + if (STRCMP (SYMBOL_NAME (*center), name) >= 0) + { + top = center; + } + else + { + bottom = center + 1; + } + } + if (!(top == bottom)) + abort (); + while (STREQ (SYMBOL_NAME (*top), name)) + { + if (SYMBOL_NAMESPACE (*top) == namespace) + { + return (*top); + } + top ++; + } + } + + /* Can't use a binary search or else we found during the binary search that + we should also do a linear search. */ + + if (do_linear_search) + { + for (psym = start; psym < start + length; psym++) + { + if (namespace == SYMBOL_NAMESPACE (*psym)) + { + if (SYMBOL_MATCHES_NAME (*psym, name)) + { + return (*psym); + } + } + } + } + + return (NULL); +} + +/* Find the psymtab containing main(). */ +/* FIXME: What about languages without main() or specially linked + executables that have no main() ? */ + +struct partial_symtab * +find_main_psymtab () +{ + register struct partial_symtab *pst; + register struct objfile *objfile; + + ALL_PSYMTABS (objfile, pst) + { + if (lookup_partial_symbol (pst, "main", 1, VAR_NAMESPACE)) + { + return (pst); + } + } + return (NULL); +} + +/* Search BLOCK for symbol NAME in NAMESPACE. + + Note that if NAME is the demangled form of a C++ symbol, we will fail + to find a match during the binary search of the non-encoded names, but + for now we don't worry about the slight inefficiency of looking for + a match we'll never find, since it will go pretty quick. Once the + binary search terminates, we drop through and do a straight linear + search on the symbols. Each symbol which is marked as being a C++ + symbol (language_cplus set) has both the encoded and non-encoded names + tested for a match. */ + +struct symbol * +lookup_block_symbol (block, name, namespace) + register const struct block *block; + const char *name; + const namespace_enum namespace; +{ + register int bot, top, inc; + register struct symbol *sym; + register struct symbol *sym_found = NULL; + register int do_linear_search = 1; + + /* If the blocks's symbols were sorted, start with a binary search. */ + + if (BLOCK_SHOULD_SORT (block)) + { + /* Reset the linear search flag so if the binary search fails, we + won't do the linear search once unless we find some reason to + do so, such as finding a C++ symbol during the binary search. + Note that for C++ modules, ALL the symbols in a block should + end up marked as C++ symbols. */ + + do_linear_search = 0; + top = BLOCK_NSYMS (block); + bot = 0; + + /* Advance BOT to not far before the first symbol whose name is NAME. */ + + while (1) + { + inc = (top - bot + 1); + /* No need to keep binary searching for the last few bits worth. */ + if (inc < 4) + { + break; + } + inc = (inc >> 1) + bot; + sym = BLOCK_SYM (block, inc); + if (!do_linear_search && SYMBOL_LANGUAGE (sym) == language_cplus) + { + do_linear_search = 1; + } + if (SYMBOL_NAME (sym)[0] < name[0]) + { + bot = inc; + } + else if (SYMBOL_NAME (sym)[0] > name[0]) + { + top = inc; + } + else if (STRCMP (SYMBOL_NAME (sym), name) < 0) + { + bot = inc; + } + else + { + top = inc; + } + } + + /* Now scan forward until we run out of symbols, find one whose + name is greater than NAME, or find one we want. If there is + more than one symbol with the right name and namespace, we + return the first one; I believe it is now impossible for us + to encounter two symbols with the same name and namespace + here, because blocks containing argument symbols are no + longer sorted. */ + + top = BLOCK_NSYMS (block); + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + inc = SYMBOL_NAME (sym)[0] - name[0]; + if (inc == 0) + { + inc = STRCMP (SYMBOL_NAME (sym), name); + } + if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace) + { + return (sym); + } + if (inc > 0) + { + break; + } + bot++; + } + } + + /* Here if block isn't sorted, or we fail to find a match during the + binary search above. If during the binary search above, we find a + symbol which is a C++ symbol, then we have re-enabled the linear + search flag which was reset when starting the binary search. + + This loop is equivalent to the loop above, but hacked greatly for speed. + + Note that parameter symbols do not always show up last in the + list; this loop makes sure to take anything else other than + parameter symbols first; it only uses parameter symbols as a + last resort. Note that this only takes up extra computation + time on a match. */ + + if (do_linear_search) + { + top = BLOCK_NSYMS (block); + bot = 0; + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + if (SYMBOL_NAMESPACE (sym) == namespace && + SYMBOL_MATCHES_NAME (sym, name)) + { + sym_found = sym; + if (SYMBOL_CLASS (sym) != LOC_ARG && + SYMBOL_CLASS (sym) != LOC_LOCAL_ARG && + SYMBOL_CLASS (sym) != LOC_REF_ARG && + SYMBOL_CLASS (sym) != LOC_REGPARM && + SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR && + SYMBOL_CLASS (sym) != LOC_BASEREG_ARG) + { + break; + } + } + bot++; + } + } + return (sym_found); /* Will be NULL if not found. */ +} + + +/* Return the symbol for the function which contains a specified + lexical block, described by a struct block BL. */ + +struct symbol * +block_function (bl) + struct block *bl; +{ + while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) + bl = BLOCK_SUPERBLOCK (bl); + + return BLOCK_FUNCTION (bl); +} + +/* Find the symtab associated with PC. Look through the psymtabs and read in + another symtab if necessary. */ + +struct symtab * +find_pc_symtab (pc) + register CORE_ADDR pc; +{ + register struct block *b; + struct blockvector *bv; + register struct symtab *s = NULL; + register struct symtab *best_s = NULL; + register struct partial_symtab *ps; + register struct objfile *objfile; + int distance = 0; + + /* Search all symtabs for the one whose file contains our address, and which + is the smallest of all the ones containing the address. This is designed + to deal with a case like symtab a is at 0x1000-0x2000 and 0x3000-0x4000 + and symtab b is at 0x2000-0x3000. So the GLOBAL_BLOCK for a is from + 0x1000-0x4000, but for address 0x2345 we want to return symtab b. + + This happens for native ecoff format, where code from included files + gets its own symtab. The symtab for the included file should have + been read in already via the dependency mechanism. + It might be swifter to create several symtabs with the same name + like xcoff does (I'm not sure). + + It also happens for objfiles that have their functions reordered. + For these, the symtab we are looking for is not necessarily read in. */ + + ALL_SYMTABS (objfile, s) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc + && (distance == 0 + || BLOCK_END (b) - BLOCK_START (b) < distance)) + { + /* For an objfile that has its functions reordered, + find_pc_psymtab will find the proper partial symbol table + and we simply return its corresponding symtab. */ + if ((objfile->flags & OBJF_REORDERED) && objfile->psymtabs) + { + ps = find_pc_psymtab (pc); + if (ps) + s = PSYMTAB_TO_SYMTAB (ps); + else + s = NULL; + return (s); + } + distance = BLOCK_END (b) - BLOCK_START (b); + best_s = s; + } + } + + if (best_s != NULL) + return(best_s); + + s = NULL; + ps = find_pc_psymtab (pc); + if (ps) + { + if (ps->readin) + /* Might want to error() here (in case symtab is corrupt and + will cause a core dump), but maybe we can successfully + continue, so let's not. */ + /* FIXME-32x64: assumes pc fits in a long */ + warning ("\ +(Internal error: pc 0x%lx in read in psymtab, but not in symtab.)\n", + (unsigned long) pc); + s = PSYMTAB_TO_SYMTAB (ps); + } + return (s); +} + +#if 0 + +/* Find the closest symbol value (of any sort -- function or variable) + for a given address value. Slow but complete. (currently unused, + mainly because it is too slow. We could fix it if each symtab and + psymtab had contained in it the addresses ranges of each of its + sections, which also would be required to make things like "info + line *0x2345" cause psymtabs to be converted to symtabs). */ + +struct symbol * +find_addr_symbol (addr, symtabp, symaddrp) + CORE_ADDR addr; + struct symtab **symtabp; + CORE_ADDR *symaddrp; +{ + struct symtab *symtab, *best_symtab; + struct objfile *objfile; + register int bot, top; + register struct symbol *sym; + register CORE_ADDR sym_addr; + struct block *block; + int blocknum; + + /* Info on best symbol seen so far */ + + register CORE_ADDR best_sym_addr = 0; + struct symbol *best_sym = 0; + + /* FIXME -- we should pull in all the psymtabs, too! */ + ALL_SYMTABS (objfile, symtab) + { + /* Search the global and static blocks in this symtab for + the closest symbol-address to the desired address. */ + + for (blocknum = GLOBAL_BLOCK; blocknum <= STATIC_BLOCK; blocknum++) + { + QUIT; + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), blocknum); + top = BLOCK_NSYMS (block); + for (bot = 0; bot < top; bot++) + { + sym = BLOCK_SYM (block, bot); + switch (SYMBOL_CLASS (sym)) + { + case LOC_STATIC: + case LOC_LABEL: + sym_addr = SYMBOL_VALUE_ADDRESS (sym); + break; + + case LOC_BLOCK: + sym_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + break; + + default: + continue; + } + + if (sym_addr <= addr) + if (sym_addr > best_sym_addr) + { + /* Quit if we found an exact match. */ + best_sym = sym; + best_sym_addr = sym_addr; + best_symtab = symtab; + if (sym_addr == addr) + goto done; + } + } + } + } + + done: + if (symtabp) + *symtabp = best_symtab; + if (symaddrp) + *symaddrp = best_sym_addr; + return best_sym; +} +#endif /* 0 */ + +/* Find the source file and line number for a given PC value. + Return a structure containing a symtab pointer, a line number, + and a pc range for the entire source line. + The value's .pc field is NOT the specified pc. + NOTCURRENT nonzero means, if specified pc is on a line boundary, + use the line that ends there. Otherwise, in that case, the line + that begins there is used. */ + +/* The big complication here is that a line may start in one file, and end just + before the start of another file. This usually occurs when you #include + code in the middle of a subroutine. To properly find the end of a line's PC + range, we must search all symtabs associated with this compilation unit, and + find the one whose first PC is closer than that of the next line in this + symtab. */ + +/* If it's worth the effort, we could be using a binary search. */ + +struct symtab_and_line +find_pc_line (pc, notcurrent) + CORE_ADDR pc; + int notcurrent; +{ + struct symtab *s; + register struct linetable *l; + register int len; + register int i; + register struct linetable_entry *item; + struct symtab_and_line val; + struct blockvector *bv; + + /* Info on best line seen so far, and where it starts, and its file. */ + + struct linetable_entry *best = NULL; + CORE_ADDR best_end = 0; + struct symtab *best_symtab = 0; + + /* Store here the first line number + of a file which contains the line at the smallest pc after PC. + If we don't find a line whose range contains PC, + 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. */ + + struct linetable_entry *prev; + + /* If this pc is not from the current frame, + it is the address of the end of a call instruction. + Quite likely that is the start of the following statement. + But what we want is the statement containing the instruction. + Fudge the pc to make sure we get that. */ + + if (notcurrent) pc -= 1; + + s = find_pc_symtab (pc); + if (!s) + { + val.symtab = 0; + val.line = 0; + val.pc = pc; + val.end = 0; + return val; + } + + bv = BLOCKVECTOR (s); + + /* Look at all the symtabs that share this blockvector. + They all have the same apriori range, that we found was right; + but they have different line tables. */ + + for (; s && BLOCKVECTOR (s) == bv; s = s->next) + { + /* Find the best line in this symtab. */ + l = LINETABLE (s); + if (!l) + continue; + len = l->nitems; + if (len <= 0) + { + /* I think len can be zero if the symtab lacks line numbers + (e.g. gcc -g1). (Either that or the LINETABLE is NULL; + I'm not sure which, and maybe it depends on the symbol + reader). */ + continue; + } + + prev = NULL; + item = l->item; /* Get first line info */ + + /* 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; + } + + for (i = 0; i < len; i++, item++) + { + /* Return the last line that did not start after PC. */ + if (item->pc > pc) + break; + + prev = item; + } + + /* At this point, prev points at the line whose start addr is <= pc, and + item points at the next line. If we ran off the end of the linetable + (pc >= start of the last line), then prev == item. If pc < start of + the first line, prev will not be set. */ + + /* Is this file's best line closer than the best in the other files? + If so, record this file, and its best line, as best so far. */ + + if (prev && (!best || prev->pc > best->pc)) + { + best = prev; + best_symtab = s; + /* If another line is in the linetable, and its PC is closer + than the best_end we currently have, take it as best_end. */ + if (i < len && (best_end == 0 || best_end > item->pc)) + best_end = item->pc; + } + } + + if (!best_symtab) + { + if (!alt_symtab) + { /* If we didn't find any line # info, just + return zeros. */ + val.symtab = 0; + val.line = 0; + val.pc = pc; + val.end = 0; + } + else + { + val.symtab = alt_symtab; + val.line = alt->line - 1; + + /* Don't return line 0, that means that we didn't find the line. */ + if (val.line == 0) ++val.line; + + val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + val.end = alt->pc; + } + } + else + { + val.symtab = best_symtab; + val.line = best->line; + val.pc = best->pc; + if (best_end && (!alt || best_end < alt->pc)) + val.end = best_end; + else if (alt) + val.end = alt->pc; + else + val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + } + return val; +} + +static int find_line_symtab PARAMS ((struct symtab *, int, struct linetable **, + int *, int *)); + +/* Find line number LINE in any symtab whose name is the same as + SYMTAB. + + If found, return 1, set *LINETABLE to the linetable in which it was + found, set *INDEX to the index in the linetable of the best entry + found, and set *EXACT_MATCH nonzero if the value returned is an + exact match. + + If not found, return 0. */ + +static int +find_line_symtab (symtab, line, linetable, index, exact_match) + struct symtab *symtab; + int line; + struct linetable **linetable; + int *index; + int *exact_match; +{ + int exact; + + /* BEST_INDEX and BEST_LINETABLE identify the smallest linenumber > LINE + so far seen. */ + + int best_index; + struct linetable *best_linetable; + + /* First try looking it up in the given symtab. */ + best_linetable = LINETABLE (symtab); + best_index = find_line_common (best_linetable, line, &exact); + if (best_index < 0 || !exact) + { + /* Didn't find an exact match. So we better keep looking for + another symtab with the same name. In the case of xcoff, + multiple csects for one source file (produced by IBM's FORTRAN + compiler) produce multiple symtabs (this is unavoidable + assuming csects can be at arbitrary places in memory and that + the GLOBAL_BLOCK of a symtab has a begin and end address). */ + + /* BEST is the smallest linenumber > LINE so far seen, + or 0 if none has been seen so far. + BEST_INDEX and BEST_LINETABLE identify the item for it. */ + int best; + + struct objfile *objfile; + struct symtab *s; + + if (best_index >= 0) + best = best_linetable->item[best_index].line; + else + best = 0; + + ALL_SYMTABS (objfile, s) + { + struct linetable *l; + int ind; + + if (!STREQ (symtab->filename, s->filename)) + continue; + l = LINETABLE (s); + ind = find_line_common (l, line, &exact); + if (ind >= 0) + { + if (exact) + { + best_index = ind; + best_linetable = l; + goto done; + } + if (best == 0 || l->item[ind].line < best) + { + best = l->item[ind].line; + best_index = ind; + best_linetable = l; + } + } + } + } + done: + if (best_index < 0) + return 0; + + if (index) + *index = best_index; + if (linetable) + *linetable = best_linetable; + if (exact_match) + *exact_match = exact; + return 1; +} + +/* Find the PC value for a given source file and line number. + Returns zero for invalid line number. + The source file is specified with a struct symtab. */ + +CORE_ADDR +find_line_pc (symtab, line) + struct symtab *symtab; + int line; +{ + struct linetable *l; + int ind; + + if (symtab == 0) + return 0; + if (find_line_symtab (symtab, line, &l, &ind, NULL)) + return l->item[ind].pc; + else + return 0; +} + +/* Find the range of pc values in a line. + Store the starting pc of the line into *STARTPTR + and the ending pc (start of next line) into *ENDPTR. + Returns 1 to indicate success. + Returns 0 if could not find the specified line. */ + +int +find_line_pc_range (sal, startptr, endptr) + struct symtab_and_line sal; + CORE_ADDR *startptr, *endptr; +{ + CORE_ADDR startaddr; + struct symtab_and_line found_sal; + + startaddr = sal.pc; + if (startaddr == 0) + { + startaddr = find_line_pc (sal.symtab, sal.line); + } + if (startaddr == 0) + return 0; + + /* This whole function is based on address. For example, if line 10 has + two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then + "info line *0x123" should say the line goes from 0x100 to 0x200 + and "info line *0x355" should say the line goes from 0x300 to 0x400. + This also insures that we never give a range like "starts at 0x134 + and ends at 0x12c". */ + + found_sal = find_pc_line (startaddr, 0); + if (found_sal.line != sal.line) + { + /* The specified line (sal) has zero bytes. */ + *startptr = found_sal.pc; + *endptr = found_sal.pc; + } + else + { + *startptr = found_sal.pc; + *endptr = found_sal.end; + } + return 1; +} + +/* Given a line table and a line number, return the index into the line + table for the pc of the nearest line whose number is >= the specified one. + Return -1 if none is found. The value is >= 0 if it is an index. + + Set *EXACT_MATCH nonzero if the value returned is an exact match. */ + +static int +find_line_common (l, lineno, exact_match) + register struct linetable *l; + register int lineno; + int *exact_match; +{ + register int i; + register int len; + + /* BEST is the smallest linenumber > LINENO so far seen, + or 0 if none has been seen so far. + BEST_INDEX identifies the item for it. */ + + int best_index = -1; + int best = 0; + + if (lineno <= 0) + return -1; + if (l == 0) + return -1; + + len = l->nitems; + for (i = 0; i < len; i++) + { + register struct linetable_entry *item = &(l->item[i]); + + if (item->line == lineno) + { + /* Return the first (lowest address) entry which matches. */ + *exact_match = 1; + return i; + } + + if (item->line > lineno && (best == 0 || item->line < best)) + { + best = item->line; + best_index = i; + } + } + + /* If we got here, we didn't get an exact match. */ + + *exact_match = 0; + return best_index; +} + +int +find_pc_line_pc_range (pc, startptr, endptr) + CORE_ADDR pc; + CORE_ADDR *startptr, *endptr; +{ + struct symtab_and_line sal; + sal = find_pc_line (pc, 0); + *startptr = sal.pc; + *endptr = sal.end; + return sal.symtab != 0; +} + +/* Given a function symbol SYM, find the symtab and line for the start + of the function. + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside the function. */ + +static struct symtab_and_line +find_function_start_sal PARAMS ((struct symbol *sym, int)); + +static struct symtab_and_line +find_function_start_sal (sym, funfirstline) + struct symbol *sym; + int funfirstline; +{ + CORE_ADDR pc; + struct symtab_and_line sal; + + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + if (funfirstline) + { + pc += FUNCTION_START_OFFSET; + SKIP_PROLOGUE (pc); + } + sal = find_pc_line (pc, 0); + +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* Convex: no need to suppress code on first line, if any */ + sal.pc = pc; +#else + /* Check if SKIP_PROLOGUE left us in mid-line, and the next + line is still part of the same function. */ + if (sal.pc != pc + && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= sal.end + && sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) + { + /* First pc of next line */ + pc = sal.end; + /* Recalculate the line number (might not be N+1). */ + sal = find_pc_line (pc, 0); + } + sal.pc = pc; +#endif + + return sal; +} + +/* If P is of the form "operator[ \t]+..." where `...' is + some legitimate operator text, return a pointer to the + beginning of the substring of the operator text. + Otherwise, return "". */ +static char * +operator_chars (p, end) + char *p; + char **end; +{ + *end = ""; + if (strncmp (p, "operator", 8)) + return *end; + p += 8; + + /* Don't get faked out by `operator' being part of a longer + identifier. */ + if (isalpha(*p) || *p == '_' || *p == '$' || *p == '\0') + return *end; + + /* Allow some whitespace between `operator' and the operator symbol. */ + while (*p == ' ' || *p == '\t') + p++; + + /* Recognize 'operator TYPENAME'. */ + + if (isalpha(*p) || *p == '_' || *p == '$') + { + register char *q = p+1; + while (isalnum(*q) || *q == '_' || *q == '$') + q++; + *end = q; + return p; + } + + switch (*p) + { + case '!': + case '=': + case '*': + case '/': + case '%': + case '^': + if (p[1] == '=') + *end = p+2; + else + *end = p+1; + return p; + case '<': + case '>': + case '+': + case '-': + case '&': + case '|': + if (p[1] == '=' || p[1] == p[0]) + *end = p+2; + else + *end = p+1; + return p; + case '~': + case ',': + *end = p+1; + return p; + case '(': + if (p[1] != ')') + error ("`operator ()' must be specified without whitespace in `()'"); + *end = p+2; + return p; + case '?': + if (p[1] != ':') + error ("`operator ?:' must be specified without whitespace in `?:'"); + *end = p+2; + return p; + case '[': + if (p[1] != ']') + error ("`operator []' must be specified without whitespace in `[]'"); + *end = p+2; + return p; + default: + error ("`operator %s' not supported", p); + break; + } + *end = ""; + return *end; +} + +/* Return the number of methods described for TYPE, including the + methods from types it derives from. This can't be done in the symbol + reader because the type of the baseclass might still be stubbed + when the definition of the derived class is parsed. */ + +static int total_number_of_methods PARAMS ((struct type *type)); + +static int +total_number_of_methods (type) + struct type *type; +{ + int n; + int count; + + CHECK_TYPEDEF (type); + count = TYPE_NFN_FIELDS_TOTAL (type); + + for (n = 0; n < TYPE_N_BASECLASSES (type); n++) + count += total_number_of_methods (TYPE_BASECLASS (type, n)); + + return count; +} + +/* Recursive helper function for decode_line_1. + Look for methods named NAME in type T. + Return number of matches. + Put matches in SYM_ARR, which should have been allocated with + a size of total_number_of_methods (T) * sizeof (struct symbol *). + Note that this function is g++ specific. */ + +int +find_methods (t, name, sym_arr) + struct type *t; + char *name; + struct symbol **sym_arr; +{ + int i1 = 0; + int ibase; + struct symbol *sym_class; + char *class_name = type_name_no_tag (t); + /* Ignore this class if it doesn't have a name. This is ugly, but + unless we figure out how to get the physname without the name of + the class, then the loop can't do any good. */ + if (class_name + && (sym_class = lookup_symbol (class_name, + (struct block *)NULL, + STRUCT_NAMESPACE, + (int *)NULL, + (struct symtab **)NULL))) + { + int method_counter; + /* FIXME: Shouldn't this just be CHECK_TYPEDEF (t)? */ + t = SYMBOL_TYPE (sym_class); + for (method_counter = TYPE_NFN_FIELDS (t) - 1; + method_counter >= 0; + --method_counter) + { + int field_counter; + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter); + char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter); + char dem_opname[64]; + + if (strncmp(method_name, "__", 2)==0 || + strncmp(method_name, "op", 2)==0 || + strncmp(method_name, "type", 4)==0 ) + { + if (cplus_demangle_opname(method_name, dem_opname, DMGL_ANSI)) + method_name = dem_opname; + else if (cplus_demangle_opname(method_name, dem_opname, 0)) + method_name = dem_opname; + } + if (STREQ (name, method_name)) + /* Find all the fields with that name. */ + for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1; + field_counter >= 0; + --field_counter) + { + char *phys_name; + if (TYPE_FN_FIELD_STUB (f, field_counter)) + check_stub_method (t, method_counter, field_counter); + phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter); + /* Destructor is handled by caller, dont add it to the list */ + if (DESTRUCTOR_PREFIX_P (phys_name)) + continue; + + /* FIXME: Why are we looking this up in the + SYMBOL_BLOCK_VALUE (sym_class)? It is intended as a hook + for nested types? If so, it should probably hook to the + type, not the symbol. mipsread.c is the only symbol + reader which sets the SYMBOL_BLOCK_VALUE for types, and + this is not documented in symtab.h. -26Aug93. */ + + sym_arr[i1] = lookup_symbol (phys_name, + SYMBOL_BLOCK_VALUE (sym_class), + VAR_NAMESPACE, + (int *) NULL, + (struct symtab **) NULL); + if (sym_arr[i1]) i1++; + else + { + fputs_filtered("(Cannot find method ", gdb_stdout); + fprintf_symbol_filtered (gdb_stdout, phys_name, + language_cplus, + DMGL_PARAMS | DMGL_ANSI); + fputs_filtered(" - possibly inlined.)\n", gdb_stdout); + } + } + } + } + + /* Only search baseclasses if there is no match yet, since names in + derived classes override those in baseclasses. + + FIXME: The above is not true; it is only true of member functions + if they have the same number of arguments (??? - section 13.1 of the + ARM says the function members are not in the same scope but doesn't + really spell out the rules in a way I understand. In any case, if + the number of arguments differ this is a case in which we can overload + rather than hiding without any problem, and gcc 2.4.5 does overload + rather than hiding in this case). */ + + if (i1) + return i1; + for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++) + i1 += find_methods(TYPE_BASECLASS(t, ibase), name, + sym_arr + i1); + return i1; +} + +/* Helper function for decode_line_1. + Build a canonical line spec in CANONICAL if it is non-NULL and if + the SAL has a symtab. + If SYMNAME is non-NULL the canonical line spec is `filename:symname'. + If SYMNAME is NULL the line number from SAL is used and the canonical + line spec is `filename:linenum'. */ + +static void +build_canonical_line_spec (sal, symname, canonical) + struct symtab_and_line *sal; + char *symname; + char ***canonical; +{ + char **canonical_arr; + char *canonical_name; + char *filename; + struct symtab *s = sal->symtab; + + if (s == (struct symtab *)NULL + || s->filename == (char *)NULL + || canonical == (char ***)NULL) + return; + + canonical_arr = (char **) xmalloc (sizeof (char *)); + *canonical = canonical_arr; + + filename = s->filename; + if (symname != NULL) + { + canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2); + sprintf (canonical_name, "%s:%s", filename, symname); + } + else + { + canonical_name = xmalloc (strlen (filename) + 30); + sprintf (canonical_name, "%s:%d", filename, sal->line); + } + canonical_arr[0] = canonical_name; +} + +/* Parse a string that specifies a line number. + Pass the address of a char * variable; that variable will be + advanced over the characters actually parsed. + + The string can be: + + LINENUM -- that line number in current file. PC returned is 0. + FILE:LINENUM -- that line in that file. PC returned is 0. + FUNCTION -- line number of openbrace of that function. + PC returned is the start of the function. + VARIABLE -- line number of definition of that variable. + PC returned is 0. + FILE:FUNCTION -- likewise, but prefer functions in that file. + *EXPR -- line in which address EXPR appears. + + FUNCTION may be an undebuggable function found in minimal symbol table. + + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside a function when a function is specified, and it is + not OK to specify a variable or type to get its line number. + + DEFAULT_SYMTAB specifies the file to use if none is specified. + It defaults to current_source_symtab. + DEFAULT_LINE specifies the line number to use for relative + line numbers (that start with signs). Defaults to current_source_line. + If CANONICAL is non-NULL, store an array of strings containing the canonical + line specs there if necessary. Currently overloaded member functions and + line numbers or static functions without a filename yield a canonical + line spec. The array and the line spec strings are allocated on the heap, + it is the callers responsibility to free them. + + Note that it is possible to return zero for the symtab + if no file is validly specified. Callers must check that. + Also, the line number returned may be invalid. */ + +/* We allow single quotes in various places. This is a hideous + kludge, which exists because the completer can't yet deal with the + lack of single quotes. FIXME: write a linespec_completer which we + can use as appropriate instead of make_symbol_completion_list. */ + +struct symtabs_and_lines +decode_line_1 (argptr, funfirstline, default_symtab, default_line, canonical) + char **argptr; + int funfirstline; + struct symtab *default_symtab; + int default_line; + char ***canonical; +{ + struct symtabs_and_lines values; +#ifdef HPPA_COMPILER_BUG + /* FIXME: The native HP 9000/700 compiler has a bug which appears + when optimizing this file with target i960-vxworks. I haven't + been able to construct a simple test case. The problem is that + in the second call to SKIP_PROLOGUE below, the compiler somehow + does not realize that the statement val = find_pc_line (...) will + change the values of the fields of val. It extracts the elements + into registers at the top of the block, and does not update the + registers after the call to find_pc_line. You can check this by + inserting a printf at the end of find_pc_line to show what values + it is returning for val.pc and val.end and another printf after + the call to see what values the function actually got (remember, + this is compiling with cc -O, with this patch removed). You can + also examine the assembly listing: search for the second call to + skip_prologue; the LDO statement before the next call to + find_pc_line loads the address of the structure which + find_pc_line will return; if there is a LDW just before the LDO, + which fetches an element of the structure, then the compiler + still has the bug. + + Setting val to volatile avoids the problem. We must undef + volatile, because the HPPA native compiler does not define + __STDC__, although it does understand volatile, and so volatile + will have been defined away in defs.h. */ +#undef volatile + volatile struct symtab_and_line val; +#define volatile /*nothing*/ +#else + struct symtab_and_line val; +#endif + register char *p, *p1; + char *q, *pp; +#if 0 + char *q1; +#endif + register struct symtab *s; + + register struct symbol *sym; + /* The symtab that SYM was found in. */ + struct symtab *sym_symtab; + + register CORE_ADDR pc; + register struct minimal_symbol *msymbol; + char *copy; + struct symbol *sym_class; + int i1; + int is_quoted, has_parens; + struct symbol **sym_arr; + struct type *t; + char *saved_arg = *argptr; + extern char *gdb_completer_quote_characters; + + /* Defaults have defaults. */ + + if (default_symtab == 0) + { + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + /* See if arg is *PC */ + + if (**argptr == '*') + { + (*argptr)++; + pc = parse_and_eval_address_1 (argptr); + values.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + values.sals[0] = find_pc_line (pc, 0); + values.sals[0].pc = pc; + return values; + } + + /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ + + s = NULL; + is_quoted = (**argptr + && strchr (gdb_completer_quote_characters, **argptr) != NULL); + has_parens = ((pp = strchr (*argptr, '(')) != NULL + && (pp = strchr (pp, ')')) != NULL); + + for (p = *argptr; *p; p++) + { + if (p[0] == '<') + { + while(++p && *p != '>'); + if (!p) + { + error ("non-matching '<' and '>' in command"); + } + } + if (p[0] == ':' || p[0] == ' ' || p[0] == '\t') + break; + } + while (p[0] == ' ' || p[0] == '\t') p++; + + if ((p[0] == ':') && !has_parens) + { + + /* C++ */ + if (is_quoted) *argptr = *argptr+1; + if (p[1] ==':') + { + /* Extract the class name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = 0; + + /* Discard the class name from the arg. */ + p = p1 + 2; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0, + (struct symtab **)NULL); + + if (sym_class && + (t = check_typedef (SYMBOL_TYPE (sym_class)), + (TYPE_CODE (t) == TYPE_CODE_STRUCT + || TYPE_CODE (t) == TYPE_CODE_UNION))) + { + /* Arg token is not digits => try it as a function name + Find the next token(everything up to end or next blank). */ + if (**argptr + && strchr (gdb_completer_quote_characters, **argptr) != NULL) + { + p = skip_quoted(*argptr); + *argptr = *argptr + 1; + } + else + { + p = *argptr; + while (*p && *p!=' ' && *p!='\t' && *p!=',' && *p!=':') p++; + } +/* + q = operator_chars (*argptr, &q1); + if (q1 - q) + { + char *opname; + char *tmp = alloca (q1 - q + 1); + memcpy (tmp, q, q1 - q); + tmp[q1 - q] = '\0'; + opname = cplus_mangle_opname (tmp, DMGL_ANSI); + if (opname == NULL) + { + error_begin (); + printf_filtered ("no mangling for \"%s\"\n", tmp); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + copy = (char*) alloca (3 + strlen(opname)); + sprintf (copy, "__%s", opname); + p = q1; + } + else +*/ + { + copy = (char *) alloca (p - *argptr + 1 ); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = '\0'; + if (p != *argptr + && copy[p - *argptr - 1] + && strchr (gdb_completer_quote_characters, + copy[p - *argptr - 1]) != NULL) + copy[p - *argptr - 1] = '\0'; + } + + /* no line number may be specified */ + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + sym = 0; + i1 = 0; /* counter for the symbol array */ + sym_arr = (struct symbol **) alloca(total_number_of_methods (t) + * sizeof(struct symbol *)); + + /* Cfront objects don't have fieldlists. */ + if (destructor_name_p (copy, t) && TYPE_FN_FIELDLISTS (t) != NULL) + { + /* destructors are a special case. */ + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0); + int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1; + /* gcc 1.x puts destructor in last field, + gcc 2.x puts destructor in first field. */ + char *phys_name = TYPE_FN_FIELD_PHYSNAME (f, len); + if (!DESTRUCTOR_PREFIX_P (phys_name)) + { + phys_name = TYPE_FN_FIELD_PHYSNAME (f, 0); + if (!DESTRUCTOR_PREFIX_P (phys_name)) + phys_name = ""; + } + sym_arr[i1] = + lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class), + VAR_NAMESPACE, 0, (struct symtab **)NULL); + if (sym_arr[i1]) i1++; + } + else + i1 = find_methods (t, copy, sym_arr); + if (i1 == 1) + { + /* There is exactly one field with that name. */ + sym = sym_arr[0]; + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + values.sals[0] = find_function_start_sal (sym, + funfirstline); + } + else + { + values.nelts = 0; + } + return values; + } + if (i1 > 0) + { + /* There is more than one field with that name + (overloaded). Ask the user which one to use. */ + return decode_line_2 (sym_arr, i1, funfirstline, canonical); + } + else + { + char *tmp; + + if (OPNAME_PREFIX_P (copy)) + { + tmp = (char *)alloca (strlen (copy+3) + 9); + strcpy (tmp, "operator "); + strcat (tmp, copy+3); + } + else + tmp = copy; + error_begin (); + if (tmp[0] == '~') + printf_filtered + ("the class `%s' does not have destructor defined\n", + SYMBOL_SOURCE_NAME(sym_class)); + else + printf_filtered + ("the class %s does not have any method named %s\n", + SYMBOL_SOURCE_NAME(sym_class), tmp); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + } + else + { + error_begin (); + /* The quotes are important if copy is empty. */ + printf_filtered + ("can't find class, struct, or union named \"%s\"\n", copy); + cplusplus_hint (saved_arg); + return_to_top_level (RETURN_ERROR); + } + } + /* end of C++ */ + + + /* Extract the file name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = 0; + + /* Find that file's data. */ + s = lookup_symtab (copy); + if (s == 0) + { + if (!have_full_symbols () && !have_partial_symbols ()) + error (no_symtab_msg); + error ("No source file named %s.", copy); + } + + /* Discard the file name from the arg. */ + p = p1 + 1; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + } + + /* S is specified file's symtab, or 0 if no file specified. + arg no longer contains the file name. */ + + /* Check whether arg is all digits (and sign) */ + + q = *argptr; + if (*q == '-' || *q == '+') q++; + while (*q >= '0' && *q <= '9') + q++; + + if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',')) + { + /* We found a token consisting of all digits -- at least one digit. */ + enum sign {none, plus, minus} sign = none; + + /* We might need a canonical line spec if no file was specified. */ + int need_canonical = (s == 0) ? 1 : 0; + + /* This is where we need to make sure that we have good defaults. + We must guarantee that this section of code is never executed + when we are called with just a function name, since + select_source_symtab calls us with such an argument */ + + if (s == 0 && default_symtab == 0) + { + select_source_symtab (0); + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + if (**argptr == '+') + sign = plus, (*argptr)++; + else if (**argptr == '-') + sign = minus, (*argptr)++; + val.line = atoi (*argptr); + switch (sign) + { + case plus: + if (q == *argptr) + val.line = 5; + if (s == 0) + val.line = default_line + val.line; + break; + case minus: + if (q == *argptr) + val.line = 15; + if (s == 0) + val.line = default_line - val.line; + else + val.line = 1; + break; + case none: + break; /* No need to adjust val.line. */ + } + + while (*q == ' ' || *q == '\t') q++; + *argptr = q; + if (s == 0) + s = default_symtab; + val.symtab = s; + val.pc = 0; + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = val; + values.nelts = 1; + if (need_canonical) + build_canonical_line_spec (values.sals, NULL, canonical); + return values; + } + + /* Arg token is not digits => try it as a variable name + Find the next token (everything up to end or next whitespace). */ + + if (**argptr == '$') /* Convenience variable */ + p = skip_quoted (*argptr + 1); + else if (is_quoted) + { + p = skip_quoted (*argptr); + if (p[-1] != '\'') + error ("Unmatched single quote."); + } + else if (has_parens) + { + p = pp+1; + } + else + { + p = skip_quoted(*argptr); + } + + copy = (char *) alloca (p - *argptr + 1); + memcpy (copy, *argptr, p - *argptr); + copy[p - *argptr] = '\0'; + if (p != *argptr + && copy[0] + && copy[0] == copy [p - *argptr - 1] + && strchr (gdb_completer_quote_characters, copy[0]) != NULL) + { + copy [p - *argptr - 1] = '\0'; + copy++; + } + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + /* See if it's a convenience variable */ + + if (*copy == '$') + { + value_ptr valx; + int need_canonical = (s == 0) ? 1 : 0; + + valx = value_of_internalvar (lookup_internalvar (copy + 1)); + if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT) + error ("Convenience variables used in line specs must have integer values."); + + val.symtab = s ? s : default_symtab; + val.line = value_as_long (valx); + val.pc = 0; + + values.sals = (struct symtab_and_line *)xmalloc (sizeof val); + values.sals[0] = val; + values.nelts = 1; + + if (need_canonical) + build_canonical_line_spec (values.sals, NULL, canonical); + + return values; + } + + + /* Look up that token as a variable. + If file specified, use that file's per-file block to start with. */ + + sym = lookup_symbol (copy, + (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) + : get_selected_block ()), + VAR_NAMESPACE, 0, &sym_symtab); + + if (sym != NULL) + { + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* Arg is the name of a function */ + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = find_function_start_sal (sym, funfirstline); + values.nelts = 1; + + /* Don't use the SYMBOL_LINE; if used at all it points to + the line containing the parameters or thereabouts, not + the first line of code. */ + + /* We might need a canonical line spec if it is a static + function. */ + if (s == 0) + { + struct blockvector *bv = BLOCKVECTOR (sym_symtab); + struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL) + build_canonical_line_spec (values.sals, copy, canonical); + } + return values; + } + else + { + if (funfirstline) + error ("\"%s\" is not a function", copy); + else if (SYMBOL_LINE (sym) != 0) + { + /* We know its line number. */ + values.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + memset (&values.sals[0], 0, sizeof (values.sals[0])); + values.sals[0].symtab = sym_symtab; + values.sals[0].line = SYMBOL_LINE (sym); + return values; + } + else + /* This can happen if it is compiled with a compiler which doesn't + put out line numbers for variables. */ + /* FIXME: Shouldn't we just set .line and .symtab to zero + and return? For example, "info line foo" could print + the address. */ + error ("Line number not known for symbol \"%s\"", copy); + } + } + + msymbol = lookup_minimal_symbol (copy, NULL, NULL); + if (msymbol != NULL) + { + val.symtab = 0; + val.line = 0; + val.pc = SYMBOL_VALUE_ADDRESS (msymbol); + if (funfirstline) + { + val.pc += FUNCTION_START_OFFSET; + SKIP_PROLOGUE (val.pc); + } + values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line)); + values.sals[0] = val; + values.nelts = 1; + return values; + } + + if (!have_full_symbols () && + !have_partial_symbols () && !have_minimal_symbols ()) + error (no_symtab_msg); + + error ("Function \"%s\" not defined.", copy); + return values; /* for lint */ +} + +struct symtabs_and_lines +decode_line_spec (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtabs_and_lines sals; + if (string == 0) + error ("Empty line specification."); + sals = decode_line_1 (&string, funfirstline, + current_source_symtab, current_source_line, + (char ***)NULL); + if (*string) + error ("Junk at end of line specification: %s", string); + return sals; +} + +/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to + operate on (ask user if necessary). + If CANONICAL is non-NULL return a corresponding array of mangled names + as canonical line specs there. */ + +static struct symtabs_and_lines +decode_line_2 (sym_arr, nelts, funfirstline, canonical) + struct symbol *sym_arr[]; + int nelts; + int funfirstline; + char ***canonical; +{ + struct symtabs_and_lines values, return_values; + char *args, *arg1; + int i; + char *prompt; + char *symname; + struct cleanup *old_chain; + char **canonical_arr = (char **)NULL; + + values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line)); + return_values.sals = (struct symtab_and_line *) xmalloc (nelts * sizeof(struct symtab_and_line)); + old_chain = make_cleanup (free, return_values.sals); + + if (canonical) + { + canonical_arr = (char **) xmalloc (nelts * sizeof (char *)); + make_cleanup (free, canonical_arr); + memset (canonical_arr, 0, nelts * sizeof (char *)); + *canonical = canonical_arr; + } + + i = 0; + printf_unfiltered("[0] cancel\n[1] all\n"); + while (i < nelts) + { + if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK) + { + values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline); + printf_unfiltered ("[%d] %s at %s:%d\n", + (i+2), + SYMBOL_SOURCE_NAME (sym_arr[i]), + values.sals[i].symtab->filename, + values.sals[i].line); + } + else + printf_unfiltered ("?HERE\n"); + i++; + } + + if ((prompt = getenv ("PS2")) == NULL) + { + prompt = ">"; + } + printf_unfiltered("%s ",prompt); + gdb_flush(gdb_stdout); + + args = command_line_input ((char *) NULL, 0, "overload-choice"); + + if (args == 0 || *args == 0) + error_no_arg ("one or more choice numbers"); + + i = 0; + while (*args) + { + int num; + + arg1 = args; + while (*arg1 >= '0' && *arg1 <= '9') arg1++; + if (*arg1 && *arg1 != ' ' && *arg1 != '\t') + error ("Arguments must be choice numbers."); + + num = atoi (args); + + if (num == 0) + error ("cancelled"); + else if (num == 1) + { + if (canonical_arr) + { + for (i = 0; i < nelts; i++) + { + if (canonical_arr[i] == NULL) + { + symname = SYMBOL_NAME (sym_arr[i]); + canonical_arr[i] = savestring (symname, strlen (symname)); + } + } + } + memcpy (return_values.sals, values.sals, + (nelts * sizeof(struct symtab_and_line))); + return_values.nelts = nelts; + discard_cleanups (old_chain); + return return_values; + } + + if (num > nelts + 2) + { + printf_unfiltered ("No choice number %d.\n", num); + } + else + { + num -= 2; + if (values.sals[num].pc) + { + if (canonical_arr) + { + symname = SYMBOL_NAME (sym_arr[num]); + make_cleanup (free, symname); + canonical_arr[i] = savestring (symname, strlen (symname)); + } + return_values.sals[i++] = values.sals[num]; + values.sals[num].pc = 0; + } + else + { + printf_unfiltered ("duplicate request for %d ignored.\n", num); + } + } + + args = arg1; + while (*args == ' ' || *args == '\t') args++; + } + return_values.nelts = i; + discard_cleanups (old_chain); + return return_values; +} + + +/* 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. */ +static void +output_source_filename (name, first) + char *name; + int *first; +{ + /* Table of files printed so far. Since a single source file can + result in several partial symbol tables, we need to avoid printing + it more than once. Note: if some of the psymtabs are read in and + some are not, it gets printed both under "Source files for which + symbols have been read" and "Source files for which symbols will + be read in on demand". I consider this a reasonable way to deal + with the situation. I'm not sure whether this can also happen for + symtabs; it doesn't hurt to check. */ + static 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; + + char **p; + + if (*first) + { + if (tab == NULL) + tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab)); + tab_cur_size = 0; + } + + /* Is NAME in tab? */ + for (p = tab; p < tab + tab_cur_size; p++) + if (STREQ (*p, name)) + /* Yes; don't print it again. */ + return; + /* No; add it to tab. */ + if (tab_cur_size == tab_alloc_size) + { + tab_alloc_size *= 2; + tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab)); + } + tab[tab_cur_size++] = name; + + if (*first) + { + *first = 0; + } + else + { + printf_filtered (", "); + } + + wrap_here (""); + fputs_filtered (name, gdb_stdout); +} + +static void +sources_info (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register struct objfile *objfile; + int first; + + if (!have_full_symbols () && !have_partial_symbols ()) + { + error (no_symtab_msg); + } + + printf_filtered ("Source files for which symbols have been read in:\n\n"); + + first = 1; + ALL_SYMTABS (objfile, s) + { + output_source_filename (s -> filename, &first); + } + printf_filtered ("\n\n"); + + printf_filtered ("Source files for which symbols will be read in on demand:\n\n"); + + first = 1; + ALL_PSYMTABS (objfile, ps) + { + if (!ps->readin) + { + output_source_filename (ps -> filename, &first); + } + } + printf_filtered ("\n"); +} + +/* List all symbols (if REGEXP is NULL) or all symbols matching REGEXP. + If CLASS is zero, list all symbols except functions, type names, and + constants (enums). + If CLASS is 1, list only functions. + If CLASS is 2, list only type names. + If CLASS is 3, list only method names. + + BPT is non-zero if we should set a breakpoint at the functions + we find. */ + +static void +list_symbols (regexp, class, bpt, from_tty) + char *regexp; + int class; + int bpt; + int from_tty; +{ + register struct symtab *s; + register struct partial_symtab *ps; + register struct blockvector *bv; + struct blockvector *prev_bv = 0; + register struct block *b; + register int i, j; + register struct symbol *sym; + struct partial_symbol **psym; + struct objfile *objfile; + struct minimal_symbol *msymbol; + char *val; + static char *classnames[] + = {"variable", "function", "type", "method"}; + int found_in_file = 0; + int found_misc = 0; + static enum minimal_symbol_type types[] + = {mst_data, mst_text, mst_abs, mst_unknown}; + static enum minimal_symbol_type types2[] + = {mst_bss, mst_file_text, mst_abs, mst_unknown}; + static enum minimal_symbol_type types3[] + = {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown}; + static enum minimal_symbol_type types4[] + = {mst_file_bss, mst_text, mst_abs, mst_unknown}; + enum minimal_symbol_type ourtype = types[class]; + enum minimal_symbol_type ourtype2 = types2[class]; + enum minimal_symbol_type ourtype3 = types3[class]; + enum minimal_symbol_type ourtype4 = types4[class]; + + if (regexp != NULL) + { + /* Make sure spacing is right for C++ operators. + This is just a courtesy to make the matching less sensitive + to how many spaces the user leaves between 'operator' + and or . */ + char *opend; + char *opname = operator_chars (regexp, &opend); + if (*opname) + { + int fix = -1; /* -1 means ok; otherwise number of spaces needed. */ + if (isalpha(*opname) || *opname == '_' || *opname == '$') + { + /* There should 1 space between 'operator' and 'TYPENAME'. */ + if (opname[-1] != ' ' || opname[-2] == ' ') + fix = 1; + } + else + { + /* There should 0 spaces between 'operator' and 'OPERATOR'. */ + if (opname[-1] == ' ') + fix = 0; + } + /* If wrong number of spaces, fix it. */ + if (fix >= 0) + { + char *tmp = (char*) alloca(opend-opname+10); + sprintf(tmp, "operator%.*s%s", fix, " ", opname); + regexp = tmp; + } + } + + if (0 != (val = re_comp (regexp))) + error ("Invalid regexp (%s): %s", val, regexp); + } + + /* Search through the partial symtabs *first* for all symbols + matching the regexp. That way we don't have to reproduce all of + the machinery below. */ + + ALL_PSYMTABS (objfile, ps) + { + struct partial_symbol **bound, **gbound, **sbound; + int keep_going = 1; + + if (ps->readin) 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 (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 it would match (logic taken from loop below) + load the file and go on to the next one */ + if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (*psym)) + && ((class == 0 && SYMBOL_CLASS (*psym) != LOC_TYPEDEF + && SYMBOL_CLASS (*psym) != LOC_BLOCK) + || (class == 1 && SYMBOL_CLASS (*psym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (*psym) == LOC_TYPEDEF) + || (class == 3 && SYMBOL_CLASS (*psym) == LOC_BLOCK))) + { + PSYMTAB_TO_SYMTAB(ps); + keep_going = 0; + } + } + psym++; + } + } + + /* Here, we search through the minimal symbol tables for functions + and variables that match, and force their symbols to be read. + This is in particular necessary for demangled variable names, + which are no longer put into the partial symbol tables. + 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. + If the lookup fails, set found_misc so that we will rescan to print + any matching symbols without debug info. + */ + + if (class == 0 || class == 1) + { + ALL_MSYMBOLS (objfile, msymbol) + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2 || + MSYMBOL_TYPE (msymbol) == ourtype3 || + MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol))) + { + if (class == 1 + || lookup_symbol (SYMBOL_NAME (msymbol), + (struct block *) NULL, + VAR_NAMESPACE, + 0, (struct symtab **) NULL) == NULL) + found_misc = 1; + } + } + } + } + } + + /* Printout here so as to get after the "Reading in symbols" + messages which will be generated above. */ + if (!bpt) + printf_filtered (regexp + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[class], + regexp); + + ALL_SYMTABS (objfile, s) + { + found_in_file = 0; + bv = BLOCKVECTOR (s); + /* Often many files share a blockvector. + Scan each blockvector only once so that + we don't get every symbol many times. + It happens that the first symtab in the list + for any given blockvector is the main file. */ + if (bv != prev_bv) + for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + /* Skip the sort if this block is always sorted. */ + if (!BLOCK_SHOULD_SORT (b)) + sort_block_syms (b); + for (j = 0; j < BLOCK_NSYMS (b); j++) + { + QUIT; + sym = BLOCK_SYM (b, j); + if ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym)) + && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK + && SYMBOL_CLASS (sym) != LOC_CONST) + || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK))) + { + if (bpt) + { + /* Set a breakpoint here, if it's a function */ + if (class == 1) + { + /* There may be more than one function with the + same name but in different files. In order to + set breakpoints on all of them, we must give + both the file name and the function name to + break_command. + Quoting the symbol name gets rid of problems + with mangled symbol names that contain + CPLUS_MARKER characters. */ + char *string = + (char *) alloca (strlen (s->filename) + + strlen (SYMBOL_NAME(sym)) + + 4); + strcpy (string, s->filename); + strcat (string, ":'"); + strcat (string, SYMBOL_NAME(sym)); + strcat (string, "'"); + break_command (string, from_tty); + } + } + else if (!found_in_file) + { + fputs_filtered ("\nFile ", gdb_stdout); + fputs_filtered (s->filename, gdb_stdout); + fputs_filtered (":\n", gdb_stdout); + } + found_in_file = 1; + + if (class != 2 && i == STATIC_BLOCK) + printf_filtered ("static "); + + /* Typedef that is not a C++ class */ + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE) + c_typedef_print (SYMBOL_TYPE(sym), sym, gdb_stdout); + /* variable, func, or typedef-that-is-c++-class */ + else if (class < 2 || + (class == 2 && + SYMBOL_NAMESPACE(sym) == STRUCT_NAMESPACE)) + { + type_print (SYMBOL_TYPE (sym), + (SYMBOL_CLASS (sym) == LOC_TYPEDEF + ? "" : SYMBOL_SOURCE_NAME (sym)), + gdb_stdout, 0); + + printf_filtered (";\n"); + } + else + { +# if 0 /* FIXME, why is this zapped out? */ + char buf[1024]; + c_type_print_base (TYPE_FN_FIELD_TYPE(t, i), + gdb_stdout, 0, 0); + c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), + gdb_stdout, 0); + sprintf (buf, " %s::", type_name_no_tag (t)); + cp_type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), + buf, name, gdb_stdout); +# endif + } + } + } + } + prev_bv = bv; + } + + /* 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 || class != 1) + { + found_in_file = 0; + ALL_MSYMBOLS (objfile, msymbol) + { + if (MSYMBOL_TYPE (msymbol) == ourtype || + MSYMBOL_TYPE (msymbol) == ourtype2 || + MSYMBOL_TYPE (msymbol) == ourtype3 || + MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (regexp == NULL || SYMBOL_MATCHES_REGEXP (msymbol)) + { + /* Functions: Look up by address. */ + if (class != 1 || + (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))) + { + /* Variables/Absolutes: Look up by name */ + if (lookup_symbol (SYMBOL_NAME (msymbol), + (struct block *) NULL, VAR_NAMESPACE, + 0, (struct symtab **) NULL) == NULL) + { + if (bpt) + { + break_command (SYMBOL_NAME (msymbol), from_tty); + printf_filtered (" %s;\n", + SYMBOL_SOURCE_NAME (msymbol)); + continue; + } + if (!found_in_file) + { + printf_filtered ("\nNon-debugging symbols:\n"); + found_in_file = 1; + } + printf_filtered (" %08lx %s\n", + (unsigned long) SYMBOL_VALUE_ADDRESS (msymbol), + SYMBOL_SOURCE_NAME (msymbol)); + } + } + } + } + } + } +} + +static void +variables_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 0, 0, from_tty); +} + +static void +functions_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 1, 0, from_tty); +} + +static void +types_info (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 2, 0, from_tty); +} + +#if 0 +/* Tiemann says: "info methods was never implemented." */ +static void +methods_info (regexp) + char *regexp; +{ + list_symbols (regexp, 3, 0, from_tty); +} +#endif /* 0 */ + +/* Breakpoint all functions matching regular expression. */ +static void +rbreak_command (regexp, from_tty) + char *regexp; + int from_tty; +{ + list_symbols (regexp, 1, 1, from_tty); +} + + +/* Return Nonzero if block a is lexically nested within block b, + or if a and b have the same pc range. + Return zero otherwise. */ +int +contained_in (a, b) + struct block *a, *b; +{ + if (!a || !b) + return 0; + return BLOCK_START (a) >= BLOCK_START (b) + && BLOCK_END (a) <= BLOCK_END (b); +} + + +/* Helper routine for make_symbol_completion_list. */ + +static int return_val_size; +static int return_val_index; +static char **return_val; + +#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \ + do { \ + if (SYMBOL_DEMANGLED_NAME (symbol) != NULL) \ + /* Put only the mangled name on the list. */ \ + /* Advantage: "b foo" completes to "b foo(int, int)" */ \ + /* Disadvantage: "b foo__i" doesn't complete. */ \ + completion_list_add_name \ + (SYMBOL_DEMANGLED_NAME (symbol), (sym_text), (len), (text), (word)); \ + else \ + completion_list_add_name \ + (SYMBOL_NAME (symbol), (sym_text), (len), (text), (word)); \ + } while (0) + +/* Test to see if the symbol specified by SYMNAME (which is already + demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN + characters. If so, add it to the current completion list. */ + +static void +completion_list_add_name (symname, sym_text, sym_text_len, text, word) + char *symname; + char *sym_text; + int sym_text_len; + char *text; + char *word; +{ + int newsize; + int i; + + /* clip symbols that cannot match */ + + if (strncmp (symname, sym_text, sym_text_len) != 0) + { + return; + } + + /* Clip any symbol names that we've already considered. (This is a + time optimization) */ + + for (i = 0; i < return_val_index; ++i) + { + if (STREQ (symname, return_val[i])) + { + return; + } + } + + /* We have a match for a completion, so add SYMNAME to the current list + of matches. Note that the name is moved to freshly malloc'd space. */ + + { + char *new; + if (word == sym_text) + { + new = xmalloc (strlen (symname) + 5); + strcpy (new, symname); + } + else if (word > sym_text) + { + /* Return some portion of symname. */ + new = xmalloc (strlen (symname) + 5); + strcpy (new, symname + (word - sym_text)); + } + else + { + /* Return some of SYM_TEXT plus symname. */ + new = xmalloc (strlen (symname) + (sym_text - word) + 5); + strncpy (new, word, sym_text - word); + new[sym_text - word] = '\0'; + strcat (new, symname); + } + + /* Recheck for duplicates if we intend to add a modified symbol. */ + if (word != sym_text) + { + for (i = 0; i < return_val_index; ++i) + { + if (STREQ (new, return_val[i])) + { + free (new); + return; + } + } + } + + 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; + } +} + +/* 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. + + Problem: All of the symbols have to be copied because readline frees them. + I'm not going to worry about this; hopefully there won't be that many. */ + +char ** +make_symbol_completion_list (text, word) + char *text; + char *word; +{ + register struct symbol *sym; + register struct symtab *s; + register struct partial_symtab *ps; + register struct minimal_symbol *msymbol; + register struct objfile *objfile; + register struct block *b, *surrounding_static_block = 0; + register int i, j; + struct partial_symbol **psym; + /* The symbol we are completing on. Points in same buffer as text. */ + char *sym_text; + /* Length of sym_text. */ + int sym_text_len; + + /* Now look for the symbol we are supposed to complete on. + FIXME: This should be language-specific. */ + { + char *p; + char quote_found; + char *quote_pos = NULL; + + /* First see if this is a quoted string. */ + quote_found = '\0'; + for (p = text; *p != '\0'; ++p) + { + if (quote_found != '\0') + { + if (*p == quote_found) + /* Found close quote. */ + quote_found = '\0'; + else if (*p == '\\' && p[1] == quote_found) + /* A backslash followed by the quote character + doesn't end the string. */ + ++p; + } + else if (*p == '\'' || *p == '"') + { + quote_found = *p; + quote_pos = p; + } + } + if (quote_found == '\'') + /* A string within single quotes can be a symbol, so complete on it. */ + sym_text = quote_pos + 1; + else if (quote_found == '"') + /* A double-quoted string is never a symbol, nor does it make sense + to complete it any other way. */ + return NULL; + else + { + /* It is not a quoted string. Break it based on the characters + which are in symbols. */ + while (p > text) + { + if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0') + --p; + else + break; + } + sym_text = p; + } + } + + sym_text_len = strlen (sym_text); + + return_val_size = 100; + return_val_index = 0; + return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *)); + return_val[0] = NULL; + + /* Look through the partial symtabs for all symbols which begin + by matching SYM_TEXT. Add each one that you find to the list. */ + + ALL_PSYMTABS (objfile, ps) + { + /* If the psymtab's been read in we'll get it when we search + through the blockvector. */ + if (ps->readin) continue; + + for (psym = objfile->global_psymbols.list + ps->globals_offset; + psym < (objfile->global_psymbols.list + ps->globals_offset + + ps->n_global_syms); + psym++) + { + /* If interrupted, then quit. */ + QUIT; + COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); + } + + for (psym = objfile->static_psymbols.list + ps->statics_offset; + psym < (objfile->static_psymbols.list + ps->statics_offset + + ps->n_static_syms); + psym++) + { + QUIT; + COMPLETION_LIST_ADD_SYMBOL (*psym, sym_text, sym_text_len, text, word); + } + } + + /* At this point scan through the misc symbol vectors and add each + symbol you find to the list. Eventually we want to ignore + 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); + } + + /* Search upwards from currently selected frame (so that we can + complete on local vars. */ + + for (b = get_selected_block (); b != NULL; b = BLOCK_SUPERBLOCK (b)) + { + if (!BLOCK_SUPERBLOCK (b)) + { + surrounding_static_block = b; /* For elmin of dups */ + } + + /* Also catch fields of types defined in this places which match our + text string. Only complete on types visible from current context. */ + + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) + { + struct type *t = SYMBOL_TYPE (sym); + enum type_code c = TYPE_CODE (t); + + if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT) + { + for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++) + { + if (TYPE_FIELD_NAME (t, j)) + { + completion_list_add_name (TYPE_FIELD_NAME (t, j), + sym_text, sym_text_len, text, word); + } + } + } + } + } + } + + /* Go through the symtabs and check the externs and statics for + symbols which match. */ + + ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + ALL_SYMTABS (objfile, s) + { + QUIT; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + /* Don't do this block twice. */ + if (b == surrounding_static_block) continue; + for (i = 0; i < BLOCK_NSYMS (b); i++) + { + sym = BLOCK_SYM (b, i); + COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word); + } + } + + return (return_val); +} + +/* Determine if PC is in the prologue of a function. The prologue is the area + between the first instruction of a function, and the first executable line. + Returns 1 if PC *might* be in prologue, 0 if definately *not* in prologue. + + If non-zero, func_start is where we thing the prologue starts, possibly + by previous examination of symbol table information. + */ + +int +in_prologue (pc, func_start) + CORE_ADDR pc; + CORE_ADDR func_start; +{ + struct symtab_and_line sal; + CORE_ADDR func_addr, func_end; + + if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + goto nosyms; /* Might be in prologue */ + + sal = find_pc_line (func_addr, 0); + + if (sal.line == 0) + goto nosyms; + + if (sal.end > func_addr + && sal.end <= func_end) /* Is prologue in function? */ + return pc < sal.end; /* Yes, is pc in prologue? */ + + /* The line after the prologue seems to be outside the function. In this + case, tell the caller to find the prologue the hard way. */ + + return 1; + +/* Come here when symtabs don't contain line # info. In this case, it is + likely that the user has stepped into a library function w/o symbols, or + is doing a stepi/nexti through code without symbols. */ + + nosyms: + +/* If func_start is zero (meaning unknown) then we don't know whether pc is + in the prologue or not. I.E. it might be. */ + + if (!func_start) return 1; + +/* We need to call the target-specific prologue skipping functions with the + function's start address because PC may be pointing at an instruction that + could be mistakenly considered part of the prologue. */ + + SKIP_PROLOGUE (func_start); + + return pc < func_start; +} + + +void +_initialize_symtab () +{ + add_info ("variables", variables_info, + "All global and static variable names, or those matching REGEXP."); + add_info ("functions", functions_info, + "All function names, or those matching REGEXP."); + + /* FIXME: This command has at least the following problems: + 1. It prints builtin types (in a very strange and confusing fashion). + 2. It doesn't print right, e.g. with + typedef struct foo *FOO + type_print prints "FOO" when we want to make it (in this situation) + print "struct foo *". + I also think "ptype" or "whatis" is more likely to be useful (but if + there is much disagreement "info types" can be fixed). */ + add_info ("types", types_info, + "All type names, or those matching REGEXP."); + +#if 0 + add_info ("methods", methods_info, + "All method names, or those matching REGEXP::REGEXP.\n\ +If the class qualifier is omitted, it is assumed to be the current scope.\n\ +If the first REGEXP is omitted, then all methods matching the second REGEXP\n\ +are listed."); +#endif + add_info ("sources", sources_info, + "Source files in the program."); + + add_com ("rbreak", no_class, rbreak_command, + "Set a breakpoint for all functions matching REGEXP."); + + /* Initialize the one built-in type that isn't language dependent... */ + builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0, + "", (struct objfile *) NULL); +} diff --git a/contrib/gdb/gdb/symtab.h b/contrib/gdb/gdb/symtab.h new file mode 100644 index 000000000000..274d19876f24 --- /dev/null +++ b/contrib/gdb/gdb/symtab.h @@ -0,0 +1,1222 @@ +/* Symbol table definitions for GDB. + Copyright 1986, 1989, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (SYMTAB_H) +#define SYMTAB_H 1 + +/* Some definitions and declarations to go with use of obstacks. */ + +#include "obstack.h" +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +#include "bcache.h" + +/* Don't do this; it means that if some .o's are compiled with GNU C + and some are not (easy to do accidentally the way we configure + things; also it is a pain to have to "make clean" every time you + want to switch compilers), then GDB dies a horrible death. */ +/* GNU C supports enums that are bitfields. Some compilers don't. */ +#if 0 && defined(__GNUC__) && !defined(BYTE_BITFIELD) +#define BYTE_BITFIELD :8; +#else +#define BYTE_BITFIELD /*nothing*/ +#endif + +/* Define a structure for the information that is common to all symbol types, + including minimal symbols, partial symbols, and full symbols. In a + multilanguage environment, some language specific information may need to + be recorded along with each symbol. + + These fields are ordered to encourage good packing, since we frequently + have tens or hundreds of thousands of these. */ + +struct general_symbol_info +{ + /* Name of the symbol. This is a required field. Storage for the name is + allocated on the psymbol_obstack or symbol_obstack for the associated + objfile. */ + + 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 + SYMBOL_CLASS. See comments there for more details. All of these + are in host byte order (though what they point to might be in + target byte order, e.g. LOC_CONST_BYTES). */ + + 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; + + struct block *block; + + char *bytes; + + CORE_ADDR address; + + /* for opaque typedef struct chain */ + + struct symbol *chain; + } + value; + + /* Since one and only one language can apply, wrap the language specific + information inside a union. */ + + union + { + struct cplus_specific /* For C++ */ + { + char *demangled_name; + } cplus_specific; + struct chill_specific /* For Chill */ + { + char *demangled_name; + } chill_specific; + } language_specific; + + /* Record the source code language that applies to this symbol. + This is used to select one of the fields from the language specific + union above. */ + + enum language language BYTE_BITFIELD; + + /* Which section is this symbol in? This is an index into + section_offsets for this objfile. Negative means that the symbol + does not get relocated relative to a section. + Disclaimer: currently this is just used for xcoff, so don't + expect all symbol-reading code to set it correctly (the ELF code + also tries to set it correctly). */ + + short section; +}; + +#define SYMBOL_NAME(symbol) (symbol)->ginfo.name +#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_BLOCK_VALUE(symbol) (symbol)->ginfo.value.block +#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain +#define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language +#define SYMBOL_SECTION(symbol) (symbol)->ginfo.section + +#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ + (symbol)->ginfo.language_specific.cplus_specific.demangled_name + +/* Macro that initializes the language dependent portion of a symbol + depending upon the language for the symbol. */ + +#define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \ + do { \ + SYMBOL_LANGUAGE (symbol) = language; \ + if (SYMBOL_LANGUAGE (symbol) == language_cplus) \ + { \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \ + } \ + else if (SYMBOL_LANGUAGE (symbol) == language_chill) \ + { \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \ + } \ + else \ + { \ + memset (&(symbol)->ginfo.language_specific, 0, \ + sizeof ((symbol)->ginfo.language_specific)); \ + } \ + } while (0) + +/* Macro that attempts to initialize the demangled name for a symbol, + based on the language of that symbol. If the language is set to + language_auto, it will attempt to find any demangling algorithm + that works and then set the language appropriately. If no demangling + of any kind is found, the language is set back to language_unknown, + so we can avoid doing this work again the next time we encounter + the symbol. Any required space to store the name is obtained from the + specified obstack. */ + +#define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack) \ + do { \ + char *demangled = NULL; \ + if (SYMBOL_LANGUAGE (symbol) == language_cplus \ + || SYMBOL_LANGUAGE (symbol) == language_auto) \ + { \ + demangled = \ + cplus_demangle (SYMBOL_NAME (symbol), DMGL_PARAMS | DMGL_ANSI);\ + if (demangled != NULL) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_cplus; \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = \ + obsavestring (demangled, strlen (demangled), (obstack)); \ + free (demangled); \ + } \ + else \ + { \ + SYMBOL_CPLUS_DEMANGLED_NAME (symbol) = NULL; \ + } \ + } \ + if (demangled == NULL \ + && (SYMBOL_LANGUAGE (symbol) == language_chill \ + || SYMBOL_LANGUAGE (symbol) == language_auto)) \ + { \ + demangled = \ + chill_demangle (SYMBOL_NAME (symbol)); \ + if (demangled != NULL) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_chill; \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = \ + obsavestring (demangled, strlen (demangled), (obstack)); \ + free (demangled); \ + } \ + else \ + { \ + SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; \ + } \ + } \ + if (SYMBOL_LANGUAGE (symbol) == language_auto) \ + { \ + SYMBOL_LANGUAGE (symbol) = language_unknown; \ + } \ + } while (0) + +/* Macro that returns the demangled name for a symbol based on the language + for that symbol. If no demangled name exists, returns NULL. */ + +#define SYMBOL_DEMANGLED_NAME(symbol) \ + (SYMBOL_LANGUAGE (symbol) == language_cplus \ + ? SYMBOL_CPLUS_DEMANGLED_NAME (symbol) \ + : (SYMBOL_LANGUAGE (symbol) == language_chill \ + ? SYMBOL_CHILL_DEMANGLED_NAME (symbol) \ + : NULL)) + +#define SYMBOL_CHILL_DEMANGLED_NAME(symbol) \ + (symbol)->ginfo.language_specific.chill_specific.demangled_name + +/* Macro that returns the "natural source name" of a symbol. In C++ this is + the "demangled" form of the name if demangle is on and the "mangled" form + of the name if demangle is off. In other languages this is just the + symbol name. The result should never be NULL. */ + +#define SYMBOL_SOURCE_NAME(symbol) \ + (demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + ? SYMBOL_DEMANGLED_NAME (symbol) \ + : SYMBOL_NAME (symbol)) + +/* Macro that returns the "natural assembly name" of a symbol. In C++ this is + the "mangled" form of the name if demangle is off, or if demangle is on and + asm_demangle is off. Otherwise if asm_demangle is on it is the "demangled" + form. In other languages this is just the symbol name. The result should + never be NULL. */ + +#define SYMBOL_LINKAGE_NAME(symbol) \ + (demangle && asm_demangle && SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + ? SYMBOL_DEMANGLED_NAME (symbol) \ + : SYMBOL_NAME (symbol)) + +/* 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. */ + +#define SYMBOL_MATCHES_NAME(symbol, name) \ + (STREQ (SYMBOL_NAME (symbol), (name)) \ + || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + && strcmp_iw (SYMBOL_DEMANGLED_NAME (symbol), (name)) == 0)) + +/* Macro that tests a symbol for an re-match against the last compiled regular + expression. First test the unencoded name, then look for and test a C++ + encoded name if it exists. + Evaluates to zero if the match fails, or nonzero if it succeeds. */ + +#define SYMBOL_MATCHES_REGEXP(symbol) \ + (re_exec (SYMBOL_NAME (symbol)) != 0 \ + || (SYMBOL_DEMANGLED_NAME (symbol) != NULL \ + && re_exec (SYMBOL_DEMANGLED_NAME (symbol)) != 0)) + +/* Define a simple structure used to hold some very basic information about + all defined global symbols (text, data, bss, abs, etc). The only required + information is the general_symbol_info. + + In many cases, even if a file was compiled with no special options for + debugging at all, as long as was not stripped it will contain sufficient + information to build a useful minimal symbol table using this structure. + Even when a file contains enough debugging information to build a full + symbol table, these minimal symbols are still useful for quickly mapping + between names and addresses, and vice versa. They are also sometimes + used to figure out what full symbol table entries need to be read in. */ + +struct minimal_symbol +{ + + /* The general symbol info required for all types of symbols. + + The SYMBOL_VALUE_ADDRESS contains the address that this symbol + corresponds to. */ + + struct general_symbol_info ginfo; + + /* The info field is available for caching machine-specific information that + The AMD 29000 tdep.c uses it to remember things it has decoded from the + instructions in the function header, so it doesn't have to rederive the + info constantly (over a serial line). It is initialized to zero and + stays that way until target-dependent code sets it. Storage for any data + pointed to by this field should be allocated on the symbol_obstack for + the associated objfile. The type would be "void *" except for reasons + of compatibility with older compilers. This field is optional. */ + + char *info; + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + /* Which source file is this symbol in? Only relevant for mst_file_*. */ + char *filename; +#endif + + /* Classification types for this symbol. These should be taken as "advisory + only", since if gdb can't easily figure out a classification it simply + selects mst_unknown. It may also have to guess when it can't figure out + which is a better match between two types (mst_data versus mst_bss) for + example. Since the minimal symbol info is sometimes derived from the + BFD library's view of a file, we need to live with what information bfd + supplies. */ + + enum minimal_symbol_type + { + mst_unknown = 0, /* Unknown type, the default */ + mst_text, /* Generally executable instructions */ + mst_data, /* Generally initialized data */ + mst_bss, /* Generally uninitialized data */ + mst_abs, /* Generally absolute (nonrelocatable) */ + /* GDB uses mst_solib_trampoline for the start address of a shared + library trampoline entry. Breakpoints for shared library functions + are put there if the shared library is not yet loaded. + After the shared library is loaded, lookup_minimal_symbol will + prefer the minimal symbol from the shared library (usually + a mst_text symbol) over the mst_solib_trampoline symbol, and the + breakpoints will be moved to their true address in the shared + library via breakpoint_re_set. */ + mst_solib_trampoline, /* Shared library trampoline code */ + /* For the mst_file* types, the names are only guaranteed to be unique + within a given .o file. */ + mst_file_text, /* Static version of mst_text */ + mst_file_data, /* Static version of mst_data */ + mst_file_bss /* Static version of mst_bss */ + } type BYTE_BITFIELD; + +}; + +#define MSYMBOL_INFO(msymbol) (msymbol)->info +#define MSYMBOL_TYPE(msymbol) (msymbol)->type + + +/* All of the name-scope contours of the program + are represented by `struct block' objects. + All of these objects are pointed to by the blockvector. + + Each block represents one name scope. + Each lexical context has its own block. + + The blockvector begins with some special blocks. + The GLOBAL_BLOCK contains all the symbols defined in this compilation + whose scope is the entire program linked together. + The STATIC_BLOCK contains all the symbols whose scope is the + entire compilation excluding other separate compilations. + Blocks starting with the FIRST_LOCAL_BLOCK are not special. + + Each block records a range of core addresses for the code that + is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK + give, for the range of code, the entire range of code produced + by the compilation that the symbol segment belongs to. + + The blocks appear in the blockvector + in order of increasing starting-address, + and, within that, in order of decreasing ending-address. + + This implies that within the body of one function + the blocks appear in the order of a depth-first tree walk. */ + +struct blockvector +{ + /* Number of blocks in the list. */ + int nblocks; + /* The blocks themselves. */ + struct block *block[1]; +}; + +#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks +#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n] + +/* Special block numbers */ + +#define GLOBAL_BLOCK 0 +#define STATIC_BLOCK 1 +#define FIRST_LOCAL_BLOCK 2 + +struct block +{ + + /* Addresses in the executable code that are in this block. */ + + CORE_ADDR startaddr; + CORE_ADDR endaddr; + + /* The symbol that names this block, if the block is the body of a + function; otherwise, zero. */ + + struct symbol *function; + + /* The `struct block' for the containing block, or 0 if none. + + The superblock of a top-level local block (i.e. a function in the + case of C) is the STATIC_BLOCK. The superblock of the + STATIC_BLOCK is the GLOBAL_BLOCK. */ + + struct block *superblock; + + /* Version of GCC used to compile the function corresponding + to this block, or 0 if not compiled with GCC. When possible, + GCC should be compatible with the native compiler, or if that + is not feasible, the differences should be fixed during symbol + reading. As of 16 Apr 93, this flag is never used to distinguish + between gcc2 and the native compiler. + + If there is no function corresponding to this block, this meaning + of this flag is undefined. */ + + unsigned char gcc_compile_flag; + + /* Number of local symbols. */ + + int nsyms; + + /* The symbols. If some of them are arguments, then they must be + in the order in which we would like to print them. */ + + struct symbol *sym[1]; +}; + +#define BLOCK_START(bl) (bl)->startaddr +#define BLOCK_END(bl) (bl)->endaddr +#define BLOCK_NSYMS(bl) (bl)->nsyms +#define BLOCK_SYM(bl, n) (bl)->sym[n] +#define BLOCK_FUNCTION(bl) (bl)->function +#define BLOCK_SUPERBLOCK(bl) (bl)->superblock +#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag + +/* Nonzero if symbols of block BL should be sorted alphabetically. + Don't sort a block which corresponds to a function. If we did the + sorting would have to preserve the order of the symbols for the + arguments. */ + +#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40 && BLOCK_FUNCTION (bl) == NULL) + + +/* Represent one symbol name; a variable, constant, function or typedef. */ + +/* Different name spaces for symbols. Looking up a symbol specifies a + namespace and ignores symbol definitions in other name spaces. */ + +typedef enum +{ + /* UNDEF_NAMESPACE is used when a namespace has not been discovered or + none of the following apply. This usually indicates an error either + in the symbol information or in gdb's handling of symbols. */ + + UNDEF_NAMESPACE, + + /* VAR_NAMESPACE is the usual namespace. In C, this contains variables, + function names, typedef names and enum type values. */ + + VAR_NAMESPACE, + + /* STRUCT_NAMESPACE is used in C to hold struct, union and enum type names. + Thus, if `struct foo' is used in a C program, it produces a symbol named + `foo' in the STRUCT_NAMESPACE. */ + + STRUCT_NAMESPACE, + + /* LABEL_NAMESPACE may be used for names of labels (for gotos); + currently it is not used and labels are not recorded at all. */ + + LABEL_NAMESPACE +} namespace_enum; + +/* An address-class says where to find the value of a symbol. */ + +enum address_class +{ + /* Not used; catches errors */ + + LOC_UNDEF, + + /* Value is constant int SYMBOL_VALUE, host byteorder */ + + LOC_CONST, + + /* Value is at fixed address SYMBOL_VALUE_ADDRESS */ + + LOC_STATIC, + + /* Value is in register. SYMBOL_VALUE is the register number. */ + + LOC_REGISTER, + + /* It's an argument; the value is at SYMBOL_VALUE offset in arglist. */ + + LOC_ARG, + + /* Value address is at SYMBOL_VALUE offset in arglist. */ + + LOC_REF_ARG, + + /* Value is in register number SYMBOL_VALUE. Just like LOC_REGISTER + except this is an argument. Probably the cleaner way to handle + this would be to separate address_class (which would include + separate ARG and LOCAL to deal with FRAME_ARGS_ADDRESS versus + FRAME_LOCALS_ADDRESS), and an is_argument flag. + + For some symbol formats (stabs, for some compilers at least), + the compiler generates two symbols, an argument and a register. + In some cases we combine them to a single LOC_REGPARM in symbol + reading, but currently not for all cases (e.g. it's passed on the + stack and then loaded into a register). */ + + LOC_REGPARM, + + /* Value is in specified register. Just like LOC_REGPARM except the + register holds the address of the argument instead of the argument + itself. This is currently used for the passing of structs and unions + on sparc and hppa. It is also used for call by reference where the + address is in a register, at least by mipsread.c. */ + + LOC_REGPARM_ADDR, + + /* Value is a local variable at SYMBOL_VALUE offset in stack frame. */ + + LOC_LOCAL, + + /* Value not used; definition in SYMBOL_TYPE. Symbols in the namespace + STRUCT_NAMESPACE all have this class. */ + + LOC_TYPEDEF, + + /* Value is address SYMBOL_VALUE_ADDRESS in the code */ + + LOC_LABEL, + + /* In a symbol table, value is SYMBOL_BLOCK_VALUE of a `struct block'. + In a partial symbol table, SYMBOL_VALUE_ADDRESS is the start address + of the block. Function names have this class. */ + + LOC_BLOCK, + + /* Value is a constant byte-sequence pointed to by SYMBOL_VALUE_BYTES, in + target byte order. */ + + LOC_CONST_BYTES, + + /* Value is arg at SYMBOL_VALUE offset in stack frame. Differs from + LOC_LOCAL in that symbol is an argument; differs from LOC_ARG in + that we find it in the frame (FRAME_LOCALS_ADDRESS), not in the + arglist (FRAME_ARGS_ADDRESS). Added for i960, which passes args + in regs then copies to frame. */ + + LOC_LOCAL_ARG, + + /* Value is at SYMBOL_VALUE offset from the current value of + register number SYMBOL_BASEREG. This exists mainly for the same + things that LOC_LOCAL and LOC_ARG do; but we need to do this + instead because on 88k DWARF gives us the offset from the + frame/stack pointer, rather than the offset from the "canonical + frame address" used by COFF, stabs, etc., and we don't know how + to convert between these until we start examining prologues. + + Note that LOC_BASEREG is much less general than a DWARF expression. + We don't need the generality (at least not yet), and storing a general + DWARF expression would presumably take up more space than the existing + scheme. */ + + LOC_BASEREG, + + /* Same as LOC_BASEREG but it is an argument. */ + + LOC_BASEREG_ARG, + + /* Value is at fixed address, but the address of the variable has + to be determined from the minimal symbol table whenever the + variable is referenced. + This happens if debugging information for a global symbol is + emitted and the corresponding minimal symbol is defined + in another object file or runtime common storage. + The linker might even remove the minimal symbol if the global + symbol is never referenced, in which case the symbol remains + unresolved. */ + + LOC_UNRESOLVED, + + /* The variable does not actually exist in the program. + The value is ignored. */ + + LOC_OPTIMIZED_OUT +}; + +struct symbol +{ + + /* The general symbol info required for all types of symbols. */ + + struct general_symbol_info ginfo; + + /* Data type of value */ + + struct type *type; + + /* Name space code. */ + + namespace_enum namespace BYTE_BITFIELD; + + /* Address class */ + + enum address_class aclass BYTE_BITFIELD; + + /* Line number of definition. FIXME: Should we really make the assumption + that nobody will try to debug files longer than 64K lines? What about + machine generated programs? */ + + unsigned short line; + + /* Some symbols require an additional value to be recorded on a per- + symbol basis. Stash those values here. */ + + union + { + /* Used by LOC_BASEREG and LOC_BASEREG_ARG. */ + short basereg; + } + aux_value; +}; + +#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace +#define SYMBOL_CLASS(symbol) (symbol)->aclass +#define SYMBOL_TYPE(symbol) (symbol)->type +#define SYMBOL_LINE(symbol) (symbol)->line +#define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg + +/* A partial_symbol records the name, namespace, and address class of + symbols whose types we have not parsed yet. For functions, it also + contains their memory address, so we can find them from a PC value. + Each partial_symbol sits in a partial_symtab, all of which are chained + on a partial symtab list and which points to the corresponding + normal symtab once the partial_symtab has been referenced. */ + +struct partial_symbol +{ + + /* The general symbol info required for all types of symbols. */ + + struct general_symbol_info ginfo; + + /* Name space code. */ + + namespace_enum namespace BYTE_BITFIELD; + + /* Address class (for info_symbols) */ + + enum address_class aclass BYTE_BITFIELD; + +}; + +#define PSYMBOL_NAMESPACE(psymbol) (psymbol)->namespace +#define PSYMBOL_CLASS(psymbol) (psymbol)->aclass + + +/* Source-file information. This describes the relation between source files, + ine numbers and addresses in the program text. */ + +struct sourcevector +{ + int length; /* Number of source files described */ + struct source *source[1]; /* Descriptions of the files */ +}; + +/* Each item represents a line-->pc (or the reverse) mapping. This is + somewhat more wasteful of space than one might wish, but since only + the files which are actually debugged are read in to core, we don't + waste much space. */ + +struct linetable_entry +{ + int line; + CORE_ADDR pc; +}; + +/* The order of entries in the linetable is significant. They should + be sorted by increasing values of the pc field. If there is more than + one entry for a given pc, then I'm not sure what should happen (and + I not sure whether we currently handle it the best way). + + Example: a C for statement generally looks like this + + 10 0x100 - for the init/test part of a for stmt. + 20 0x200 + 30 0x300 + 10 0x400 - for the increment part of a for stmt. + + */ + +struct linetable +{ + int nitems; + + /* Actually NITEMS elements. If you don't like this use of the + `struct hack', you can shove it up your ANSI (seriously, if the + committee tells us how to do it, we can probably go along). */ + struct linetable_entry item[1]; +}; + +/* All the information on one source file. */ + +struct source +{ + char *name; /* Name of file */ + struct linetable contents; +}; + +/* How to relocate the symbols from each section in a symbol file. + Each struct contains an array of offsets. + The ordering and meaning of the offsets is file-type-dependent; + typically it is indexed by section numbers or symbol types or + something like that. + + To give us flexibility in changing the internal representation + of these offsets, the ANOFFSET macro must be used to insert and + extract offset values in the struct. */ + +struct section_offsets + { + CORE_ADDR offsets[1]; /* As many as needed. */ + }; + +#define ANOFFSET(secoff, whichone) (secoff->offsets[whichone]) + +/* Each source file or header is represented by a struct symtab. + These objects are chained through the `next' field. */ + +struct symtab + { + + /* Chain of all existing symtabs. */ + + struct symtab *next; + + /* List of all symbol scope blocks for this symtab. May be shared + between different symtabs (and normally is for all the symtabs + in a given compilation unit). */ + + struct blockvector *blockvector; + + /* Table mapping core addresses to line numbers for this file. + Can be NULL if none. Never shared between different symtabs. */ + + struct linetable *linetable; + + /* Section in objfile->section_offsets for the blockvector and + the linetable. Probably always SECT_OFF_TEXT. */ + + int block_line_section; + + /* If several symtabs share a blockvector, exactly one of them + should be designed the primary, so that the blockvector + is relocated exactly once by objfile_relocate. */ + + int primary; + + /* Name of this source file. */ + + char *filename; + + /* Directory in which it was compiled, or NULL if we don't know. */ + + char *dirname; + + /* This component says how to free the data we point to: + free_contents => do a tree walk and free each object. + free_nothing => do nothing; some other symtab will free + the data this one uses. + free_linetable => free just the linetable. FIXME: Is this redundant + with the primary field? */ + + enum free_code + { + free_nothing, free_contents, free_linetable + } + free_code; + + /* Pointer to one block of storage to be freed, if nonzero. */ + /* This is IN ADDITION to the action indicated by free_code. */ + + char *free_ptr; + + /* Total number of lines found in source file. */ + + int nlines; + + /* line_charpos[N] is the position of the (N-1)th line of the + source file. "position" means something we can lseek() to; it + is not guaranteed to be useful any other way. */ + + int *line_charpos; + + /* Language of this source file. */ + + enum language language; + + /* String of version information. May be zero. */ + + char *version; + + /* Full name of file as found by searching the source path. + NULL if not yet known. */ + + char *fullname; + + /* Object file from which this symbol information was read. */ + + struct objfile *objfile; + + /* Anything extra for this symtab. This is for target machines + with special debugging info of some sort (which cannot just + be represented in a normal symtab). */ + +#if defined (EXTRA_SYMTAB_INFO) + EXTRA_SYMTAB_INFO +#endif + + }; + +#define BLOCKVECTOR(symtab) (symtab)->blockvector +#define LINETABLE(symtab) (symtab)->linetable + + +/* 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 + list of names of global symbols which are located in this file. + They are all chained on partial symtab lists. + + Even after the source file has been read into a symtab, the + partial_symtab remains around. They are allocated on an obstack, + psymbol_obstack. FIXME, this is bad for dynamic linking or VxWorks- + style execution of a bunch of .o's. */ + +struct partial_symtab +{ + + /* Chain of all existing partial symtabs. */ + + struct partial_symtab *next; + + /* Name of the source file which this partial_symtab defines */ + + char *filename; + + /* 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; + + /* Range of text addresses covered by this file; texthigh is the + beginning of the next section. */ + + CORE_ADDR textlow; + CORE_ADDR texthigh; + + /* Array of pointers to all of the partial_symtab's which this one + depends on. Since this array can only be set to previous or + the current (?) psymtab, this dependency tree is guaranteed not + to have any loops. "depends on" means that symbols must be read + for the dependencies before being read for this psymtab; this is + for type references in stabs, where if foo.c includes foo.h, declarations + in foo.h may use type numbers defined in foo.c. For other debugging + formats there may be no need to use dependencies. */ + + struct partial_symtab **dependencies; + + int number_of_dependencies; + + /* 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 + within global_psymbols[]. */ + + int globals_offset; + int n_global_syms; + + /* Static symbol list. This list will *not* be sorted after readin; + to find a symbol in it, exhaustive search must be used. This is + reasonable because searches through this list will eventually + lead to either the read in of a files symbols for real (assumed + to take a *lot* of time; check) or an error (and we don't care + how long errors take). This is an offset and size within + static_psymbols[]. */ + + int statics_offset; + int n_static_syms; + + /* 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. */ + + struct symtab *symtab; + + /* Pointer to function which will read in the symtab corresponding to + this psymtab. */ + + void (*read_symtab) PARAMS ((struct partial_symtab *)); + + /* Information that lets read_symtab() locate the part of the symbol table + that this psymtab corresponds to. This information is private to the + format-dependent symbol reading routines. For further detail examine + the various symbol reading modules. Should really be (void *) but is + (char *) as with other such gdb variables. (FIXME) */ + + char *read_symtab_private; + + /* Non-zero if the symtab corresponding to this psymtab has been readin */ + + unsigned char readin; +}; + +/* 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)) + + +/* The virtual function table is now an array of structures which have the + form { int16 offset, delta; void *pfn; }. + + In normal virtual function tables, OFFSET is unused. + DELTA is the amount which is added to the apparent object's base + address in order to point to the actual object to which the + virtual function should be applied. + PFN is a pointer to the virtual function. + + Note that this macro is g++ specific (FIXME). */ + +#define VTBL_FNADDR_OFFSET 2 + +/* Macro that yields non-zero value iff NAME is the prefix for C++ operator + names. If you leave out the parenthesis here you will lose! + Currently 'o' 'p' CPLUS_MARKER is used for both the symbol in the + symbol-file and the names in gdb's symbol table. + Note that this macro is g++ specific (FIXME). */ + +#define OPNAME_PREFIX_P(NAME) \ + ((NAME)[0] == 'o' && (NAME)[1] == 'p' && is_cplus_marker ((NAME)[2])) + +/* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl + names. Note that this macro is g++ specific (FIXME). + '_vt$' is the old cfront-style vtables; '_VT$' is the new + style, using thunks (where '$' is really CPLUS_MARKER). */ + +#define VTBL_PREFIX_P(NAME) \ + ((NAME)[0] == '_' \ + && (((NAME)[1] == 'V' && (NAME)[2] == 'T') \ + || ((NAME)[1] == 'v' && (NAME)[2] == 't')) \ + && is_cplus_marker ((NAME)[3])) + +/* Macro that yields non-zero value iff NAME is the prefix for C++ destructor + names. Note that this macro is g++ specific (FIXME). */ + +#define DESTRUCTOR_PREFIX_P(NAME) \ + ((NAME)[0] == '_' && is_cplus_marker ((NAME)[1]) && (NAME)[2] == '_') + + +/* External variables and functions for the objects described above. */ + +/* This symtab variable specifies the current file for printing source lines */ + +extern struct symtab *current_source_symtab; + +/* This is the next line to print for listing source lines. */ + +extern int current_source_line; + +/* See the comment in symfile.c about how current_objfile is used. */ + +extern struct objfile *current_objfile; + +/* True if we are nested inside psymtab_to_symtab. */ + +extern int currently_reading_symtab; + +/* From utils.c. */ +extern int demangle; +extern int asm_demangle; + +extern struct symtab * +lookup_symtab PARAMS ((char *)); + +extern struct symbol * +lookup_symbol PARAMS ((const char *, const struct block *, + const namespace_enum, int *, struct symtab **)); + +extern struct symbol * +lookup_block_symbol PARAMS ((const struct block *, const char *, + const namespace_enum)); + +extern struct type * +lookup_struct PARAMS ((char *, struct block *)); + +extern struct type * +lookup_union PARAMS ((char *, struct block *)); + +extern struct type * +lookup_enum PARAMS ((char *, struct block *)); + +extern struct symbol * +block_function PARAMS ((struct block *)); + +extern struct symbol * +find_pc_function PARAMS ((CORE_ADDR)); + +extern int find_pc_partial_function + PARAMS ((CORE_ADDR, char **, CORE_ADDR *, CORE_ADDR *)); + +extern void +clear_pc_function_cache PARAMS ((void)); + +extern struct partial_symtab * +lookup_partial_symtab PARAMS ((char *)); + +extern struct partial_symtab * +find_pc_psymtab PARAMS ((CORE_ADDR)); + +extern struct symtab * +find_pc_symtab PARAMS ((CORE_ADDR)); + +extern struct partial_symbol * +find_pc_psymbol PARAMS ((struct partial_symtab *, CORE_ADDR)); + +extern int +find_pc_line_pc_range PARAMS ((CORE_ADDR, CORE_ADDR *, CORE_ADDR *)); + +extern int +contained_in PARAMS ((struct block *, struct block *)); + +extern void +reread_symbols PARAMS ((void)); + +/* Macro for name of symbol to indicate a file compiled with gcc. */ +#ifndef GCC_COMPILED_FLAG_SYMBOL +#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled." +#endif + +/* Macro for name of symbol to indicate a file compiled with gcc2. */ +#ifndef GCC2_COMPILED_FLAG_SYMBOL +#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 PARAMS ((const char *, CORE_ADDR, + enum minimal_symbol_type, + struct objfile *)); + +extern struct minimal_symbol *prim_record_minimal_symbol_and_info + PARAMS ((const char *, CORE_ADDR, + enum minimal_symbol_type, + char *info, int section, + struct objfile *)); + +#ifdef SOFUN_ADDRESS_MAYBE_MISSING +extern CORE_ADDR find_stab_function_addr PARAMS ((char *, + struct partial_symtab *, + struct objfile *)); +#endif + +extern struct minimal_symbol * +lookup_minimal_symbol PARAMS ((const char *, const char *, struct objfile *)); + +extern struct minimal_symbol * +lookup_minimal_symbol_text PARAMS ((const char *, const char *, struct objfile *)); + +struct minimal_symbol * +lookup_minimal_symbol_solib_trampoline PARAMS ((const char *, + const char *, + struct objfile *)); + +extern struct minimal_symbol * +lookup_minimal_symbol_by_pc PARAMS ((CORE_ADDR)); + +extern struct minimal_symbol * +lookup_solib_trampoline_symbol_by_pc PARAMS ((CORE_ADDR)); + +extern CORE_ADDR +find_solib_trampoline_target PARAMS ((CORE_ADDR)); + +extern void +init_minimal_symbol_collection PARAMS ((void)); + +extern void +discard_minimal_symbols PARAMS ((int)); + +extern void +install_minimal_symbols PARAMS ((struct objfile *)); + +/* Sort all the minimal symbols in OBJFILE. */ + +extern void msymbols_sort PARAMS ((struct objfile *objfile)); + +struct symtab_and_line +{ + struct symtab *symtab; + + /* Line number. Line numbers start at 1 and proceed through symtab->nlines. + 0 is never a valid line number; it is used to indicate that line number + information is not available. */ + int line; + + CORE_ADDR pc; + CORE_ADDR end; +}; + +struct symtabs_and_lines +{ + struct symtab_and_line *sals; + int nelts; +}; + +/* 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. */ + +extern struct symtab_and_line +find_pc_line PARAMS ((CORE_ADDR, int)); + +/* Given an address, return the nearest symbol at or below it in memory. + Optionally return the symtab it's from through 2nd arg, and the + address in inferior memory of the symbol through 3rd arg. */ + +extern struct symbol * +find_addr_symbol PARAMS ((CORE_ADDR, struct symtab **, CORE_ADDR *)); + +/* Given a symtab and line number, return the pc there. */ + +extern CORE_ADDR +find_line_pc PARAMS ((struct symtab *, int)); + +extern int +find_line_pc_range PARAMS ((struct symtab_and_line, + CORE_ADDR *, CORE_ADDR *)); + +extern void +resolve_sal_pc PARAMS ((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 PARAMS ((char *, int)); + +extern struct symtabs_and_lines +decode_line_spec_1 PARAMS ((char *, int)); + +extern struct symtabs_and_lines +decode_line_1 PARAMS ((char **, int, struct symtab *, int, char ***)); + +/* Symmisc.c */ + +#if MAINTENANCE_CMDS + +void +maintenance_print_symbols PARAMS ((char *, int)); + +void +maintenance_print_psymbols PARAMS ((char *, int)); + +void +maintenance_print_msymbols PARAMS ((char *, int)); + +void +maintenance_print_objfiles PARAMS ((char *, int)); + +void +maintenance_check_symtabs PARAMS ((char *, int)); + +#endif + +extern void +free_symtab PARAMS ((struct symtab *)); + +/* Symbol-reading stuff in symfile.c and solib.c. */ + +extern struct symtab * +psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +extern void +clear_solib PARAMS ((void)); + +extern struct objfile * +symbol_file_add PARAMS ((char *, int, CORE_ADDR, int, int, int)); + +/* source.c */ + +extern int +identify_source_line PARAMS ((struct symtab *, int, int, CORE_ADDR)); + +extern void +print_source_lines PARAMS ((struct symtab *, int, int, int)); + +extern void +forget_cached_source_info PARAMS ((void)); + +extern void +select_source_symtab PARAMS ((struct symtab *)); + +extern char **make_symbol_completion_list PARAMS ((char *, char *)); + +/* symtab.c */ + +extern struct partial_symtab * +find_main_psymtab PARAMS ((void)); + +/* blockframe.c */ + +extern struct blockvector * +blockvector_for_pc PARAMS ((CORE_ADDR, int *)); + +/* symfile.c */ + +extern void +clear_symtab_users PARAMS ((void)); + +extern enum language +deduce_language_from_filename PARAMS ((char *)); + +/* symtab.c */ + +extern int +in_prologue PARAMS ((CORE_ADDR pc, CORE_ADDR func_start)); + +#endif /* !defined(SYMTAB_H) */ diff --git a/contrib/gdb/gdb/target.c b/contrib/gdb/gdb/target.c new file mode 100644 index 000000000000..fc0dfd9b22cc --- /dev/null +++ b/contrib/gdb/gdb/target.c @@ -0,0 +1,1858 @@ +/* Select target systems and architectures at runtime for GDB. + Copyright 1990, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include +#include +#include "gdb_string.h" +#include "target.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "wait.h" +#include + +extern int errno; + +static void +target_info PARAMS ((char *, int)); + +static void +cleanup_target PARAMS ((struct target_ops *)); + +static void +maybe_kill_then_create_inferior PARAMS ((char *, char *, char **)); + +static void +maybe_kill_then_attach PARAMS ((char *, int)); + +static void +kill_or_be_killed PARAMS ((int)); + +static void +default_terminal_info PARAMS ((char *, int)); + +static int +nosymbol PARAMS ((char *, CORE_ADDR *)); + +static void +tcomplain PARAMS ((void)); + +static int +nomemory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +static int +return_zero PARAMS ((void)); + +static void +ignore PARAMS ((void)); + +static void +target_command PARAMS ((char *, int)); + +static struct target_ops * +find_default_run_target PARAMS ((char *)); + +/* Pointer to array of target architecture structures; the size of the + array; the current index into the array; the allocated size of the + array. */ +struct target_ops **target_structs; +unsigned target_struct_size; +unsigned target_struct_index; +unsigned target_struct_allocsize; +#define DEFAULT_ALLOCSIZE 10 + +/* The initial current target, so that there is always a semi-valid + current target. */ + +struct target_ops dummy_target = { + "None", /* to_shortname */ + "None", /* to_longname */ + "", /* to_doc */ + 0, /* to_open */ + 0, /* to_close */ + find_default_attach, /* to_attach */ + 0, /* to_detach */ + 0, /* to_resume */ + 0, /* to_wait */ + 0, /* to_fetch_registers */ + 0, /* to_store_registers */ + 0, /* to_prepare_to_store */ + 0, /* to_xfer_memory */ + 0, /* to_files_info */ + 0, /* to_insert_breakpoint */ + 0, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + 0, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + find_default_create_inferior, /* to_create_inferior */ + 0, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + 0, /* to_thread_alive */ + 0, /* to_stop */ + dummy_stratum, /* to_stratum */ + 0, /* to_next */ + 0, /* to_next */ + 0, /* to_has_all_memory */ + 0, /* to_has_memory */ + 0, /* to_has_registers */ + 0, /* to_has_execution */ + 0, /* to_sections */ + 0, /* to_sections_end */ + OPS_MAGIC, /* to_magic */ +}; + +/* Top of target stack. */ + +struct target_stack_item *target_stack; + +/* The target structure we are currently using to talk to a process + or file or whatever "inferior" we have. */ + +struct target_ops current_target; + +/* Command list for target. */ + +static struct cmd_list_element *targetlist = NULL; + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +int attach_flag; + +#ifdef MAINTENANCE_CMDS +/* Non-zero if we want to see trace of target level stuff. */ + +static int targetdebug = 0; + +static void setup_target_debug PARAMS ((void)); + +#endif + +/* The user just typed 'target' without the name of a target. */ + +/* ARGSUSED */ +static void +target_command (arg, from_tty) + char *arg; + int from_tty; +{ + fputs_filtered ("Argument required (target name). Try `help target'\n", + gdb_stdout); +} + +/* Add a possible target architecture to the list. */ + +void +add_target (t) + struct target_ops *t; +{ + if (!target_structs) + { + target_struct_allocsize = DEFAULT_ALLOCSIZE; + target_structs = (struct target_ops **) xmalloc + (target_struct_allocsize * sizeof (*target_structs)); + } + if (target_struct_size >= target_struct_allocsize) + { + target_struct_allocsize *= 2; + target_structs = (struct target_ops **) + xrealloc ((char *) target_structs, + target_struct_allocsize * sizeof (*target_structs)); + } + target_structs[target_struct_size++] = t; +/* cleanup_target (t);*/ + + if (targetlist == NULL) + add_prefix_cmd ("target", class_run, target_command, + "Connect to a target machine or process.\n\ +The first argument is the type or protocol of the target machine.\n\ +Remaining arguments are interpreted by the target protocol. For more\n\ +information on the arguments for a particular protocol, type\n\ +`help target ' followed by the protocol name.", + &targetlist, "target ", 0, &cmdlist); + add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist); +} + +/* Stub functions */ + +static void +ignore () +{ +} + +/* ARGSUSED */ +static int +nomemory (memaddr, myaddr, len, write, t) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *t; +{ + errno = EIO; /* Can't read/write this location */ + return 0; /* No bytes handled */ +} + +static void +tcomplain () +{ + error ("You can't do that when your target is `%s'", + current_target.to_shortname); +} + +void +noprocess () +{ + error ("You can't do that without a process to debug"); +} + +/* ARGSUSED */ +static int +nosymbol (name, addrp) + char *name; + CORE_ADDR *addrp; +{ + return 1; /* Symbol does not exist in target env */ +} + +/* ARGSUSED */ +static void +default_terminal_info (args, from_tty) + char *args; + int from_tty; +{ + printf_unfiltered("No saved terminal information.\n"); +} + +/* This is the default target_create_inferior and target_attach function. + If the current target is executing, it asks whether to kill it off. + If this function returns without calling error(), it has killed off + the target, and the operation should be attempted. */ + +static void +kill_or_be_killed (from_tty) + int from_tty; +{ + if (target_has_execution) + { + printf_unfiltered ("You are already running a program:\n"); + target_files_info (); + if (query ("Kill it? ")) { + target_kill (); + if (target_has_execution) + error ("Killing the program did not help."); + return; + } else { + error ("Program not killed."); + } + } + tcomplain(); +} + +static void +maybe_kill_then_attach (args, from_tty) + char *args; + int from_tty; +{ + kill_or_be_killed (from_tty); + target_attach (args, from_tty); +} + +static void +maybe_kill_then_create_inferior (exec, args, env) + char *exec; + char *args; + char **env; +{ + kill_or_be_killed (0); + target_create_inferior (exec, args, env); +} + +/* Clean up a target struct so it no longer has any zero pointers in it. + We default entries, at least to stubs that print error messages. */ + +static void +cleanup_target (t) + struct target_ops *t; +{ + +#define de_fault(field, value) \ + if (!t->field) t->field = value + + /* FIELD DEFAULT VALUE */ + + de_fault (to_open, (void (*)())tcomplain); + de_fault (to_close, (void (*)())ignore); + de_fault (to_attach, maybe_kill_then_attach); + de_fault (to_detach, (void (*)())ignore); + de_fault (to_resume, (void (*)())noprocess); + de_fault (to_wait, (int (*)())noprocess); + de_fault (to_fetch_registers, (void (*)())ignore); + de_fault (to_store_registers, (void (*)())noprocess); + de_fault (to_prepare_to_store, (void (*)())noprocess); + de_fault (to_xfer_memory, (int (*)())nomemory); + de_fault (to_files_info, (void (*)())ignore); + de_fault (to_insert_breakpoint, memory_insert_breakpoint); + de_fault (to_remove_breakpoint, memory_remove_breakpoint); + de_fault (to_terminal_init, ignore); + de_fault (to_terminal_inferior, ignore); + de_fault (to_terminal_ours_for_output,ignore); + de_fault (to_terminal_ours, ignore); + de_fault (to_terminal_info, default_terminal_info); + de_fault (to_kill, (void (*)())noprocess); + de_fault (to_load, (void (*)())tcomplain); + de_fault (to_lookup_symbol, nosymbol); + de_fault (to_create_inferior, maybe_kill_then_create_inferior); + de_fault (to_mourn_inferior, (void (*)())noprocess); + de_fault (to_can_run, return_zero); + de_fault (to_notice_signals, (void (*)())ignore); + de_fault (to_thread_alive, (int (*)())ignore); + de_fault (to_stop, (void (*)())ignore); + +#undef de_fault +} + +/* Go through the target stack from top to bottom, copying over zero entries in + current_target. In effect, we are doing class inheritance through the + pushed target vectors. */ + +static void +update_current_target () +{ + struct target_stack_item *item; + struct target_ops *t; + + /* First, reset current_target */ + memset (¤t_target, 0, sizeof current_target); + + for (item = target_stack; item; item = item->next) + { + t = item->target_ops; + +#define INHERIT(FIELD, TARGET) \ + if (!current_target.FIELD) \ + current_target.FIELD = TARGET->FIELD + + INHERIT (to_shortname, t); + INHERIT (to_longname, t); + INHERIT (to_doc, t); + INHERIT (to_open, t); + INHERIT (to_close, t); + INHERIT (to_attach, t); + INHERIT (to_detach, t); + INHERIT (to_resume, t); + INHERIT (to_wait, t); + INHERIT (to_fetch_registers, t); + INHERIT (to_store_registers, t); + INHERIT (to_prepare_to_store, t); + INHERIT (to_xfer_memory, t); + INHERIT (to_files_info, t); + INHERIT (to_insert_breakpoint, t); + INHERIT (to_remove_breakpoint, t); + INHERIT (to_terminal_init, t); + INHERIT (to_terminal_inferior, t); + INHERIT (to_terminal_ours_for_output, t); + INHERIT (to_terminal_ours, t); + INHERIT (to_terminal_info, t); + INHERIT (to_kill, t); + INHERIT (to_load, t); + INHERIT (to_lookup_symbol, t); + INHERIT (to_create_inferior, t); + INHERIT (to_mourn_inferior, t); + INHERIT (to_can_run, t); + INHERIT (to_notice_signals, t); + INHERIT (to_thread_alive, t); + INHERIT (to_stop, t); + INHERIT (to_stratum, t); + INHERIT (DONT_USE, t); + INHERIT (to_has_all_memory, t); + INHERIT (to_has_memory, t); + INHERIT (to_has_stack, t); + INHERIT (to_has_registers, t); + INHERIT (to_has_execution, t); + INHERIT (to_sections, t); + INHERIT (to_sections_end, t); + INHERIT (to_magic, t); + +#undef INHERIT + } +} + +/* Push a new target type into the stack of the existing target accessors, + possibly superseding some of the existing accessors. + + Result is zero if the pushed target ended up on top of the stack, + nonzero if at least one target is on top of it. + + Rather than allow an empty stack, we always have the dummy target at + the bottom stratum, so we can call the function vectors without + checking them. */ + +int +push_target (t) + struct target_ops *t; +{ + struct target_stack_item *cur, *prev, *tmp; + + /* Check magic number. If wrong, it probably means someone changed + the struct definition, but not all the places that initialize one. */ + if (t->to_magic != OPS_MAGIC) + { + fprintf_unfiltered(gdb_stderr, + "Magic number of %s target struct wrong\n", + t->to_shortname); + abort(); + } + + /* Find the proper stratum to install this target in. */ + + for (prev = NULL, cur = target_stack; cur; prev = cur, cur = cur->next) + { + if ((int)(t->to_stratum) >= (int)(cur->target_ops->to_stratum)) + break; + } + + /* If there's already targets at this stratum, remove them. */ + + if (cur) + while (t->to_stratum == cur->target_ops->to_stratum) + { + /* There's already something on this stratum. Close it off. */ + (cur->target_ops->to_close) (0); + if (prev) + prev->next = cur->next; /* Unchain old target_ops */ + else + target_stack = cur->next; /* Unchain first on list */ + tmp = cur->next; + free (cur); + cur = tmp; + } + + /* We have removed all targets in our stratum, now add the new one. */ + + tmp = (struct target_stack_item *) + xmalloc (sizeof (struct target_stack_item)); + tmp->next = cur; + tmp->target_ops = t; + + if (prev) + prev->next = tmp; + else + target_stack = tmp; + + update_current_target (); + + cleanup_target (¤t_target); /* Fill in the gaps */ + +#ifdef MAINTENANCE_CMDS + if (targetdebug) + setup_target_debug (); +#endif + + return prev != 0; +} + +/* Remove a target_ops vector from the stack, wherever it may be. + Return how many times it was removed (0 or 1). */ + +int +unpush_target (t) + struct target_ops *t; +{ + struct target_stack_item *cur, *prev; + + if (t->to_close) + t->to_close (0); /* Let it clean up */ + + /* Look for the specified target. Note that we assume that a target + can only occur once in the target stack. */ + + for (cur = target_stack, prev = NULL; cur; prev = cur, cur = cur->next) + if (cur->target_ops == t) + break; + + if (!cur) + return 0; /* Didn't find target_ops, quit now */ + + /* Unchain the target */ + + if (!prev) + target_stack = cur->next; + else + prev->next = cur->next; + + free (cur); /* Release the target_stack_item */ + + update_current_target (); + cleanup_target (¤t_target); + + return 1; +} + +void +pop_target () +{ + (current_target.to_close)(0); /* Let it clean up */ + if (unpush_target (target_stack->target_ops) == 1) + return; + + fprintf_unfiltered(gdb_stderr, + "pop_target couldn't find target %s\n", + current_target.to_shortname); + abort(); +} + +#undef MIN +#define MIN(A, B) (((A) <= (B)) ? (A) : (B)) + +/* target_read_string -- read a null terminated string, up to LEN bytes, + from MEMADDR in target. Set *ERRNOP to the errno code, or 0 if successful. + Set *STRING to a pointer to malloc'd memory containing the data; the caller + is responsible for freeing it. Return the number of bytes successfully + read. */ + +int +target_read_string (memaddr, string, len, errnop) + CORE_ADDR memaddr; + char **string; + int len; + int *errnop; +{ + int tlen, origlen, offset, i; + char buf[4]; + int errcode = 0; + char *buffer; + int buffer_allocated; + char *bufptr; + unsigned int nbytes_read = 0; + + /* Small for testing. */ + buffer_allocated = 4; + buffer = xmalloc (buffer_allocated); + bufptr = buffer; + + origlen = len; + + while (len > 0) + { + tlen = MIN (len, 4 - (memaddr & 3)); + offset = memaddr & 3; + + errcode = target_xfer_memory (memaddr & ~3, buf, 4, 0); + if (errcode != 0) + goto done; + + if (bufptr - buffer + tlen > buffer_allocated) + { + unsigned int bytes; + bytes = bufptr - buffer; + buffer_allocated *= 2; + buffer = xrealloc (buffer, buffer_allocated); + bufptr = buffer + bytes; + } + + for (i = 0; i < tlen; i++) + { + *bufptr++ = buf[i + offset]; + if (buf[i + offset] == '\000') + { + nbytes_read += i + 1; + goto done; + } + } + + memaddr += tlen; + len -= tlen; + nbytes_read += tlen; + } + done: + if (errnop != NULL) + *errnop = errcode; + if (string != NULL) + *string = buffer; + return nbytes_read; +} + +/* Read LEN bytes of target memory at address MEMADDR, placing the results in + GDB's memory at MYADDR. Returns either 0 for success or an errno value + if any error occurs. + + If an error occurs, no guarantee is made about the contents of the data at + MYADDR. In particular, the caller should not depend upon partial reads + filling the buffer with good data. There is no way for the caller to know + how much good data might have been transfered anyway. Callers that can + deal with partial reads should call target_read_memory_partial. */ + +int +target_read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 0); +} + +/* Read LEN bytes of target memory at address MEMADDR, placing the results + in GDB's memory at MYADDR. Returns a count of the bytes actually read, + and optionally an errno value in the location pointed to by ERRNOPTR + if ERRNOPTR is non-null. */ + +int +target_read_memory_partial (memaddr, myaddr, len, errnoptr) + CORE_ADDR memaddr; + char *myaddr; + int len; + int *errnoptr; +{ + int nread; /* Number of bytes actually read. */ + int errcode; /* Error from last read. */ + + /* First try a complete read. */ + errcode = target_xfer_memory (memaddr, myaddr, len, 0); + if (errcode == 0) + { + /* Got it all. */ + nread = len; + } + else + { + /* Loop, reading one byte at a time until we get as much as we can. */ + for (errcode = 0, nread = 0; len > 0 && errcode == 0; nread++, len--) + { + errcode = target_xfer_memory (memaddr++, myaddr++, 1, 0); + } + /* If an error, the last read was unsuccessful, so adjust count. */ + if (errcode != 0) + { + nread--; + } + } + if (errnoptr != NULL) + { + *errnoptr = errcode; + } + return (nread); +} + +int +target_write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 1); +} + +/* Move memory to or from the targets. Iterate until all of it has + been moved, if necessary. The top target gets priority; anything + it doesn't want, is offered to the next one down, etc. Note the + business with curlen: if an early target says "no, but I have a + boundary overlapping this xfer" then we shorten what we offer to + the subsequent targets so the early guy will get a chance at the + tail before the subsequent ones do. + + Result is 0 or errno value. */ + +int +target_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + int curlen; + int res; + struct target_ops *t; + struct target_stack_item *item; + + /* to_xfer_memory is not guaranteed to set errno, even when it returns + 0. */ + errno = 0; + + /* The quick case is that the top target does it all. */ + res = current_target.to_xfer_memory + (memaddr, myaddr, len, write, ¤t_target); + if (res == len) + return 0; + + if (res > 0) + goto bump; + /* If res <= 0 then we call it again in the loop. Ah well. */ + + for (; len > 0;) + { + curlen = len; /* Want to do it all */ + for (item = target_stack; item; item = item->next) + { + t = item->target_ops; + if (!t->to_has_memory) + continue; + + res = t->to_xfer_memory (memaddr, myaddr, curlen, write, t); + if (res > 0) + break; /* Handled all or part of xfer */ + if (t->to_has_all_memory) + break; + } + + if (res <= 0) + { + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. Return error. */ + if (!write) + memset (myaddr, 0, len); + if (errno == 0) + return EIO; + else + return errno; + } +bump: + memaddr += res; + myaddr += res; + len -= res; + } + return 0; /* We managed to cover it all somehow. */ +} + + +/* ARGSUSED */ +static void +target_info (args, from_tty) + char *args; + int from_tty; +{ + struct target_ops *t; + struct target_stack_item *item; + int has_all_mem = 0; + + if (symfile_objfile != NULL) + printf_unfiltered ("Symbols from \"%s\".\n", symfile_objfile->name); + +#ifdef FILES_INFO_HOOK + if (FILES_INFO_HOOK ()) + return; +#endif + + for (item = target_stack; item; item = item->next) + { + t = item->target_ops; + + if (!t->to_has_memory) + continue; + + if ((int)(t->to_stratum) <= (int)dummy_stratum) + continue; + if (has_all_mem) + printf_unfiltered("\tWhile running this, GDB does not access memory from...\n"); + printf_unfiltered("%s:\n", t->to_longname); + (t->to_files_info)(t); + has_all_mem = t->to_has_all_memory; + } +} + +/* This is to be called by the open routine before it does + anything. */ + +void +target_preopen (from_tty) + int from_tty; +{ + dont_repeat(); + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill (); + else + error ("Program not killed."); + } + + /* Calling target_kill may remove the target from the stack. But if + it doesn't (which seems like a win for UDI), remove it now. */ + + if (target_has_execution) + pop_target (); +} + +/* Detach a target after doing deferred register stores. */ + +void +target_detach (args, from_tty) + char *args; + int from_tty; +{ + /* Handle any optimized stores to the inferior. */ +#ifdef DO_DEFERRED_STORES + DO_DEFERRED_STORES; +#endif + (current_target.to_detach) (args, from_tty); +} + +void +target_link (modname, t_reloc) + char *modname; + CORE_ADDR *t_reloc; +{ + if (STREQ(current_target.to_shortname, "rombug")) + { + (current_target.to_lookup_symbol) (modname, t_reloc); + if (*t_reloc == 0) + error("Unable to link to %s and get relocation in rombug", modname); + } + else + *t_reloc = (CORE_ADDR)-1; +} + +/* Look through the list of possible targets for a target that can + execute a run or attach command without any other data. This is + used to locate the default process stratum. + + Result is always valid (error() is called for errors). */ + +static struct target_ops * +find_default_run_target (do_mesg) + char *do_mesg; +{ + struct target_ops **t; + struct target_ops *runable = NULL; + int count; + + count = 0; + + for (t = target_structs; t < target_structs + target_struct_size; + ++t) + { + if ((*t)->to_can_run && target_can_run(*t)) + { + runable = *t; + ++count; + } + } + + if (count != 1) + error ("Don't know how to %s. Try \"help target\".", do_mesg); + + return runable; +} + +void +find_default_attach (args, from_tty) + char *args; + int from_tty; +{ + struct target_ops *t; + + t = find_default_run_target("attach"); + (t->to_attach) (args, from_tty); + return; +} + +void +find_default_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + struct target_ops *t; + + t = find_default_run_target("run"); + (t->to_create_inferior) (exec_file, allargs, env); + return; +} + +static int +return_zero () +{ + return 0; +} + +struct target_ops * +find_core_target () +{ + struct target_ops **t; + struct target_ops *runable = NULL; + int count; + + count = 0; + + for (t = target_structs; t < target_structs + target_struct_size; + ++t) + { + if ((*t)->to_stratum == core_stratum) + { + runable = *t; + ++count; + } + } + + return(count == 1 ? runable : NULL); +} + +/* The inferior process has died. Long live the inferior! */ + +void +generic_mourn_inferior () +{ + extern int show_breakpoint_hit_counts; + + inferior_pid = 0; + attach_flag = 0; + breakpoint_init_inferior (); + registers_changed (); + +#ifdef CLEAR_DEFERRED_STORES + /* Delete any pending stores to the inferior... */ + CLEAR_DEFERRED_STORES; +#endif + + reopen_exec_file (); + reinit_frame_cache (); + + /* It is confusing to the user for ignore counts to stick around + from previous runs of the inferior. So clear them. */ + /* However, it is more confusing for the ignore counts to disappear when + using hit counts. So don't clear them if we're counting hits. */ + if (!show_breakpoint_hit_counts) + breakpoint_clear_ignore_counts (); +} + +/* This table must match in order and size the signals in enum target_signal + in target.h. */ +static struct { + char *name; + char *string; + } signals [] = +{ + {"0", "Signal 0"}, + {"SIGHUP", "Hangup"}, + {"SIGINT", "Interrupt"}, + {"SIGQUIT", "Quit"}, + {"SIGILL", "Illegal instruction"}, + {"SIGTRAP", "Trace/breakpoint trap"}, + {"SIGABRT", "Aborted"}, + {"SIGEMT", "Emulation trap"}, + {"SIGFPE", "Arithmetic exception"}, + {"SIGKILL", "Killed"}, + {"SIGBUS", "Bus error"}, + {"SIGSEGV", "Segmentation fault"}, + {"SIGSYS", "Bad system call"}, + {"SIGPIPE", "Broken pipe"}, + {"SIGALRM", "Alarm clock"}, + {"SIGTERM", "Terminated"}, + {"SIGURG", "Urgent I/O condition"}, + {"SIGSTOP", "Stopped (signal)"}, + {"SIGTSTP", "Stopped (user)"}, + {"SIGCONT", "Continued"}, + {"SIGCHLD", "Child status changed"}, + {"SIGTTIN", "Stopped (tty input)"}, + {"SIGTTOU", "Stopped (tty output)"}, + {"SIGIO", "I/O possible"}, + {"SIGXCPU", "CPU time limit exceeded"}, + {"SIGXFSZ", "File size limit exceeded"}, + {"SIGVTALRM", "Virtual timer expired"}, + {"SIGPROF", "Profiling timer expired"}, + {"SIGWINCH", "Window size changed"}, + {"SIGLOST", "Resource lost"}, + {"SIGUSR1", "User defined signal 1"}, + {"SIGUSR2", "User defined signal 2"}, + {"SIGPWR", "Power fail/restart"}, + {"SIGPOLL", "Pollable event occurred"}, + {"SIGWIND", "SIGWIND"}, + {"SIGPHONE", "SIGPHONE"}, + {"SIGWAITING", "Process's LWPs are blocked"}, + {"SIGLWP", "Signal LWP"}, + {"SIGDANGER", "Swap space dangerously low"}, + {"SIGGRANT", "Monitor mode granted"}, + {"SIGRETRACT", "Need to relinguish monitor mode"}, + {"SIGMSG", "Monitor mode data available"}, + {"SIGSOUND", "Sound completed"}, + {"SIGSAK", "Secure attention"}, + {"SIGPRIO", "SIGPRIO"}, + {"SIG33", "Real-time event 33"}, + {"SIG34", "Real-time event 34"}, + {"SIG35", "Real-time event 35"}, + {"SIG36", "Real-time event 36"}, + {"SIG37", "Real-time event 37"}, + {"SIG38", "Real-time event 38"}, + {"SIG39", "Real-time event 39"}, + {"SIG40", "Real-time event 40"}, + {"SIG41", "Real-time event 41"}, + {"SIG42", "Real-time event 42"}, + {"SIG43", "Real-time event 43"}, + {"SIG44", "Real-time event 44"}, + {"SIG45", "Real-time event 45"}, + {"SIG46", "Real-time event 46"}, + {"SIG47", "Real-time event 47"}, + {"SIG48", "Real-time event 48"}, + {"SIG49", "Real-time event 49"}, + {"SIG50", "Real-time event 50"}, + {"SIG51", "Real-time event 51"}, + {"SIG52", "Real-time event 52"}, + {"SIG53", "Real-time event 53"}, + {"SIG54", "Real-time event 54"}, + {"SIG55", "Real-time event 55"}, + {"SIG56", "Real-time event 56"}, + {"SIG57", "Real-time event 57"}, + {"SIG58", "Real-time event 58"}, + {"SIG59", "Real-time event 59"}, + {"SIG60", "Real-time event 60"}, + {"SIG61", "Real-time event 61"}, + {"SIG62", "Real-time event 62"}, + {"SIG63", "Real-time event 63"}, + + {NULL, "Unknown signal"}, + {NULL, "Internal error: printing TARGET_SIGNAL_DEFAULT"}, + + /* Last entry, used to check whether the table is the right size. */ + {NULL, "TARGET_SIGNAL_MAGIC"} +}; + +/* Return the string for a signal. */ +char * +target_signal_to_string (sig) + enum target_signal sig; +{ + return signals[sig].string; +} + +/* Return the name for a signal. */ +char * +target_signal_to_name (sig) + enum target_signal sig; +{ + if (sig == TARGET_SIGNAL_UNKNOWN) + /* I think the code which prints this will always print it along with + the string, so no need to be verbose. */ + return "?"; + return signals[sig].name; +} + +/* Given a name, return its signal. */ +enum target_signal +target_signal_from_name (name) + char *name; +{ + enum target_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 + 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; + signals[sig].name != NULL; + sig = (enum target_signal)((int)sig + 1)) + if (STREQ (name, signals[sig].name)) + return sig; + return TARGET_SIGNAL_UNKNOWN; +} + +/* The following functions are to help certain targets deal + with the signal/waitstatus stuff. They could just as well be in + 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 (hostsig) + 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; + +#if defined (SIGHUP) + if (hostsig == SIGHUP) return TARGET_SIGNAL_HUP; +#endif +#if defined (SIGINT) + if (hostsig == SIGINT) return TARGET_SIGNAL_INT; +#endif +#if defined (SIGQUIT) + if (hostsig == SIGQUIT) return TARGET_SIGNAL_QUIT; +#endif +#if defined (SIGILL) + if (hostsig == SIGILL) return TARGET_SIGNAL_ILL; +#endif +#if defined (SIGTRAP) + if (hostsig == SIGTRAP) return TARGET_SIGNAL_TRAP; +#endif +#if defined (SIGABRT) + if (hostsig == SIGABRT) return TARGET_SIGNAL_ABRT; +#endif +#if defined (SIGEMT) + if (hostsig == SIGEMT) return TARGET_SIGNAL_EMT; +#endif +#if defined (SIGFPE) + if (hostsig == SIGFPE) return TARGET_SIGNAL_FPE; +#endif +#if defined (SIGKILL) + if (hostsig == SIGKILL) return TARGET_SIGNAL_KILL; +#endif +#if defined (SIGBUS) + if (hostsig == SIGBUS) return TARGET_SIGNAL_BUS; +#endif +#if defined (SIGSEGV) + if (hostsig == SIGSEGV) return TARGET_SIGNAL_SEGV; +#endif +#if defined (SIGSYS) + if (hostsig == SIGSYS) return TARGET_SIGNAL_SYS; +#endif +#if defined (SIGPIPE) + if (hostsig == SIGPIPE) return TARGET_SIGNAL_PIPE; +#endif +#if defined (SIGALRM) + if (hostsig == SIGALRM) return TARGET_SIGNAL_ALRM; +#endif +#if defined (SIGTERM) + if (hostsig == SIGTERM) return TARGET_SIGNAL_TERM; +#endif +#if defined (SIGUSR1) + if (hostsig == SIGUSR1) return TARGET_SIGNAL_USR1; +#endif +#if defined (SIGUSR2) + if (hostsig == SIGUSR2) return TARGET_SIGNAL_USR2; +#endif +#if defined (SIGCLD) + if (hostsig == SIGCLD) return TARGET_SIGNAL_CHLD; +#endif +#if defined (SIGCHLD) + if (hostsig == SIGCHLD) return TARGET_SIGNAL_CHLD; +#endif +#if defined (SIGPWR) + if (hostsig == SIGPWR) return TARGET_SIGNAL_PWR; +#endif +#if defined (SIGWINCH) + if (hostsig == SIGWINCH) return TARGET_SIGNAL_WINCH; +#endif +#if defined (SIGURG) + if (hostsig == SIGURG) return TARGET_SIGNAL_URG; +#endif +#if defined (SIGIO) + if (hostsig == SIGIO) return TARGET_SIGNAL_IO; +#endif +#if defined (SIGPOLL) + if (hostsig == SIGPOLL) return TARGET_SIGNAL_POLL; +#endif +#if defined (SIGSTOP) + if (hostsig == SIGSTOP) return TARGET_SIGNAL_STOP; +#endif +#if defined (SIGTSTP) + if (hostsig == SIGTSTP) return TARGET_SIGNAL_TSTP; +#endif +#if defined (SIGCONT) + if (hostsig == SIGCONT) return TARGET_SIGNAL_CONT; +#endif +#if defined (SIGTTIN) + if (hostsig == SIGTTIN) return TARGET_SIGNAL_TTIN; +#endif +#if defined (SIGTTOU) + if (hostsig == SIGTTOU) return TARGET_SIGNAL_TTOU; +#endif +#if defined (SIGVTALRM) + if (hostsig == SIGVTALRM) return TARGET_SIGNAL_VTALRM; +#endif +#if defined (SIGPROF) + if (hostsig == SIGPROF) return TARGET_SIGNAL_PROF; +#endif +#if defined (SIGXCPU) + if (hostsig == SIGXCPU) return TARGET_SIGNAL_XCPU; +#endif +#if defined (SIGXFSZ) + if (hostsig == SIGXFSZ) return TARGET_SIGNAL_XFSZ; +#endif +#if defined (SIGWIND) + if (hostsig == SIGWIND) return TARGET_SIGNAL_WIND; +#endif +#if defined (SIGPHONE) + if (hostsig == SIGPHONE) return TARGET_SIGNAL_PHONE; +#endif +#if defined (SIGLOST) + if (hostsig == SIGLOST) return TARGET_SIGNAL_LOST; +#endif +#if defined (SIGWAITING) + if (hostsig == SIGWAITING) return TARGET_SIGNAL_WAITING; +#endif +#if defined (SIGLWP) + if (hostsig == SIGLWP) return TARGET_SIGNAL_LWP; +#endif +#if defined (SIGDANGER) + if (hostsig == SIGDANGER) return TARGET_SIGNAL_DANGER; +#endif +#if defined (SIGGRANT) + if (hostsig == SIGGRANT) return TARGET_SIGNAL_GRANT; +#endif +#if defined (SIGRETRACT) + if (hostsig == SIGRETRACT) return TARGET_SIGNAL_RETRACT; +#endif +#if defined (SIGMSG) + if (hostsig == SIGMSG) return TARGET_SIGNAL_MSG; +#endif +#if defined (SIGSOUND) + if (hostsig == SIGSOUND) return TARGET_SIGNAL_SOUND; +#endif +#if defined (SIGSAK) + if (hostsig == SIGSAK) return TARGET_SIGNAL_SAK; +#endif +#if defined (SIGPRIO) + if (hostsig == SIGPRIO) return TARGET_SIGNAL_PRIO; +#endif +#if defined (REALTIME_LO) + if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) + return (enum target_signal) + (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33); +#endif + return TARGET_SIGNAL_UNKNOWN; +} + +int +target_signal_to_host (oursig) + enum target_signal oursig; +{ + switch (oursig) + { + case TARGET_SIGNAL_0: return 0; + +#if defined (SIGHUP) + case TARGET_SIGNAL_HUP: return SIGHUP; +#endif +#if defined (SIGINT) + case TARGET_SIGNAL_INT: return SIGINT; +#endif +#if defined (SIGQUIT) + case TARGET_SIGNAL_QUIT: return SIGQUIT; +#endif +#if defined (SIGILL) + case TARGET_SIGNAL_ILL: return SIGILL; +#endif +#if defined (SIGTRAP) + case TARGET_SIGNAL_TRAP: return SIGTRAP; +#endif +#if defined (SIGABRT) + case TARGET_SIGNAL_ABRT: return SIGABRT; +#endif +#if defined (SIGEMT) + case TARGET_SIGNAL_EMT: return SIGEMT; +#endif +#if defined (SIGFPE) + case TARGET_SIGNAL_FPE: return SIGFPE; +#endif +#if defined (SIGKILL) + case TARGET_SIGNAL_KILL: return SIGKILL; +#endif +#if defined (SIGBUS) + case TARGET_SIGNAL_BUS: return SIGBUS; +#endif +#if defined (SIGSEGV) + case TARGET_SIGNAL_SEGV: return SIGSEGV; +#endif +#if defined (SIGSYS) + case TARGET_SIGNAL_SYS: return SIGSYS; +#endif +#if defined (SIGPIPE) + case TARGET_SIGNAL_PIPE: return SIGPIPE; +#endif +#if defined (SIGALRM) + case TARGET_SIGNAL_ALRM: return SIGALRM; +#endif +#if defined (SIGTERM) + case TARGET_SIGNAL_TERM: return SIGTERM; +#endif +#if defined (SIGUSR1) + case TARGET_SIGNAL_USR1: return SIGUSR1; +#endif +#if defined (SIGUSR2) + case TARGET_SIGNAL_USR2: return SIGUSR2; +#endif +#if defined (SIGCHLD) || defined (SIGCLD) + case TARGET_SIGNAL_CHLD: +#if defined (SIGCHLD) + return SIGCHLD; +#else + return SIGCLD; +#endif +#endif /* SIGCLD or SIGCHLD */ +#if defined (SIGPWR) + case TARGET_SIGNAL_PWR: return SIGPWR; +#endif +#if defined (SIGWINCH) + case TARGET_SIGNAL_WINCH: return SIGWINCH; +#endif +#if defined (SIGURG) + case TARGET_SIGNAL_URG: return SIGURG; +#endif +#if defined (SIGIO) + case TARGET_SIGNAL_IO: return SIGIO; +#endif +#if defined (SIGPOLL) + case TARGET_SIGNAL_POLL: return SIGPOLL; +#endif +#if defined (SIGSTOP) + case TARGET_SIGNAL_STOP: return SIGSTOP; +#endif +#if defined (SIGTSTP) + case TARGET_SIGNAL_TSTP: return SIGTSTP; +#endif +#if defined (SIGCONT) + case TARGET_SIGNAL_CONT: return SIGCONT; +#endif +#if defined (SIGTTIN) + case TARGET_SIGNAL_TTIN: return SIGTTIN; +#endif +#if defined (SIGTTOU) + case TARGET_SIGNAL_TTOU: return SIGTTOU; +#endif +#if defined (SIGVTALRM) + case TARGET_SIGNAL_VTALRM: return SIGVTALRM; +#endif +#if defined (SIGPROF) + case TARGET_SIGNAL_PROF: return SIGPROF; +#endif +#if defined (SIGXCPU) + case TARGET_SIGNAL_XCPU: return SIGXCPU; +#endif +#if defined (SIGXFSZ) + case TARGET_SIGNAL_XFSZ: return SIGXFSZ; +#endif +#if defined (SIGWIND) + case TARGET_SIGNAL_WIND: return SIGWIND; +#endif +#if defined (SIGPHONE) + case TARGET_SIGNAL_PHONE: return SIGPHONE; +#endif +#if defined (SIGLOST) + case TARGET_SIGNAL_LOST: return SIGLOST; +#endif +#if defined (SIGWAITING) + case TARGET_SIGNAL_WAITING: return SIGWAITING; +#endif +#if defined (SIGLWP) + case TARGET_SIGNAL_LWP: return SIGLWP; +#endif +#if defined (SIGDANGER) + case TARGET_SIGNAL_DANGER: return SIGDANGER; +#endif +#if defined (SIGGRANT) + case TARGET_SIGNAL_GRANT: return SIGGRANT; +#endif +#if defined (SIGRETRACT) + case TARGET_SIGNAL_RETRACT: return SIGRETRACT; +#endif +#if defined (SIGMSG) + case TARGET_SIGNAL_MSG: return SIGMSG; +#endif +#if defined (SIGSOUND) + case TARGET_SIGNAL_SOUND: return SIGSOUND; +#endif +#if defined (SIGSAK) + case TARGET_SIGNAL_SAK: return SIGSAK; +#endif +#if defined (SIGPRIO) + case TARGET_SIGNAL_PRIO: return SIGPRIO; +#endif + default: +#if defined (REALTIME_LO) + if (oursig >= TARGET_SIGNAL_REALTIME_33 + && oursig <= TARGET_SIGNAL_REALTIME_63) + { + int retsig = + (int)oursig - (int)TARGET_SIGNAL_REALTIME_33 + REALTIME_LO; + if (retsig < REALTIME_HI) + return retsig; + } +#endif + /* 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.\n", + target_signal_to_name (oursig)); + return 0; + } +} + +/* Helper function for child_wait and the Lynx derivatives of child_wait. + HOSTSTATUS is the waitstatus from wait() or the equivalent; store our + translation of that in OURSTATUS. */ +void +store_waitstatus (ourstatus, hoststatus) + struct target_waitstatus *ourstatus; + int hoststatus; +{ +#ifdef CHILD_SPECIAL_WAITSTATUS + /* CHILD_SPECIAL_WAITSTATUS should return nonzero and set *OURSTATUS + if it wants to deal with hoststatus. */ + if (CHILD_SPECIAL_WAITSTATUS (ourstatus, hoststatus)) + return; +#endif + + if (WIFEXITED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = WEXITSTATUS (hoststatus); + } + else if (!WIFSTOPPED (hoststatus)) + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = target_signal_from_host (WTERMSIG (hoststatus)); + } + else + { + ourstatus->kind = TARGET_WAITKIND_STOPPED; + ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus)); + } +} + +/* 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 obscelescent. 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 (num) + 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."); +} + +/* Returns zero to leave the inferior alone, one to interrupt it. */ +int (*target_activity_function) PARAMS ((void)); +int target_activity_fd; + +/* Convert a normal process ID to a string. Returns the string in a static + buffer. */ + +char * +normal_pid_to_str (pid) + int pid; +{ + static char buf[30]; + + if (STREQ (current_target.to_shortname, "remote")) + sprintf (buf, "thread %d", pid); + else + sprintf (buf, "process %d", pid); + + return buf; +} + +#ifdef MAINTENANCE_CMDS +static struct target_ops debug_target; + +static void +debug_to_open (args, from_tty) + char *args; + int from_tty; +{ + debug_target.to_open (args, from_tty); + + fprintf_unfiltered (stderr, "target_open (%s, %d)\n", args, from_tty); +} + +static void +debug_to_close (quitting) + int quitting; +{ + debug_target.to_close (quitting); + + fprintf_unfiltered (stderr, "target_close (%d)\n", quitting); +} + +static void +debug_to_attach (args, from_tty) + char *args; + int from_tty; +{ + debug_target.to_attach (args, from_tty); + + fprintf_unfiltered (stderr, "target_attach (%s, %d)\n", args, from_tty); +} + +static void +debug_to_detach (args, from_tty) + char *args; + int from_tty; +{ + debug_target.to_detach (args, from_tty); + + fprintf_unfiltered (stderr, "target_detach (%s, %d)\n", args, from_tty); +} + +static void +debug_to_resume (pid, step, siggnal) + int pid; + int step; + enum target_signal siggnal; +{ + debug_target.to_resume (pid, step, siggnal); + + fprintf_unfiltered (stderr, "target_resume (%d, %s, %s)\n", pid, + step ? "step" : "continue", + target_signal_to_name (siggnal)); +} + +static int +debug_to_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int retval; + + retval = debug_target.to_wait (pid, status); + + fprintf_unfiltered (stderr, "target_wait (%d, status) = %d, ", pid, retval); + fprintf_unfiltered (stderr, "status->kind = "); + switch (status->kind) + { + case TARGET_WAITKIND_EXITED: + fprintf_unfiltered (stderr, "exited, status = %d\n", status->value.integer); + break; + case TARGET_WAITKIND_STOPPED: + fprintf_unfiltered (stderr, "stopped, signal = %s\n", + target_signal_to_name (status->value.sig)); + break; + case TARGET_WAITKIND_SIGNALLED: + fprintf_unfiltered (stderr, "signalled, signal = %s\n", + target_signal_to_name (status->value.sig)); + break; + case TARGET_WAITKIND_LOADED: + fprintf_unfiltered (stderr, "loaded\n"); + break; + case TARGET_WAITKIND_SPURIOUS: + fprintf_unfiltered (stderr, "spurious\n"); + break; + default: + fprintf_unfiltered (stderr, "unknown???\n"); + break; + } + + return retval; +} + +static void +debug_to_fetch_registers (regno) + int regno; +{ + debug_target.to_fetch_registers (regno); + + fprintf_unfiltered (stderr, "target_fetch_registers (%s)", + regno != -1 ? reg_names[regno] : "-1"); + if (regno != -1) + fprintf_unfiltered (stderr, " = 0x%x %d", read_register (regno), + read_register (regno)); + fprintf_unfiltered (stderr, "\n"); +} + +static void +debug_to_store_registers (regno) + int regno; +{ + debug_target.to_store_registers (regno); + + if (regno >= 0 && regno < NUM_REGS) + fprintf_unfiltered (stderr, "target_store_registers (%s) = 0x%x %d\n", + reg_names[regno], read_register (regno), + read_register (regno)); + else + fprintf_unfiltered (stderr, "target_store_registers (%d)\n", regno); +} + +static void +debug_to_prepare_to_store () +{ + debug_target.to_prepare_to_store (); + + fprintf_unfiltered (stderr, "target_prepare_to_store ()\n"); +} + +static int +debug_to_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + int retval; + + retval = debug_target.to_xfer_memory (memaddr, myaddr, len, write, target); + + fprintf_unfiltered (stderr, "target_xfer_memory (0x%x, xxx, %d, %s, xxx) = %d", + memaddr, len, write ? "write" : "read", retval); + + if (retval > 0) + { + int i; + + fputs_unfiltered (", bytes =", gdb_stderr); + for (i = 0; i < retval; i++) + fprintf_unfiltered (stderr, " %02x", myaddr[i] & 0xff); + } + + fputc_unfiltered ('\n', gdb_stderr); + + return retval; +} + +static void +debug_to_files_info (target) + struct target_ops *target; +{ + debug_target.to_files_info (target); + + fprintf_unfiltered (stderr, "target_files_info (xxx)\n"); +} + +static int +debug_to_insert_breakpoint (addr, save) + CORE_ADDR addr; + char *save; +{ + int retval; + + retval = debug_target.to_insert_breakpoint (addr, save); + + fprintf_unfiltered (stderr, "target_insert_breakpoint (0x%x, xxx) = %d\n", + addr, retval); + return retval; +} + +static int +debug_to_remove_breakpoint (addr, save) + CORE_ADDR addr; + char *save; +{ + int retval; + + retval = debug_target.to_remove_breakpoint (addr, save); + + fprintf_unfiltered (stderr, "target_remove_breakpoint (0x%x, xxx) = %d\n", + addr, retval); + return retval; +} + +static void +debug_to_terminal_init () +{ + debug_target.to_terminal_init (); + + fprintf_unfiltered (stderr, "target_terminal_init ()\n"); +} + +static void +debug_to_terminal_inferior () +{ + debug_target.to_terminal_inferior (); + + fprintf_unfiltered (stderr, "target_terminal_inferior ()\n"); +} + +static void +debug_to_terminal_ours_for_output () +{ + debug_target.to_terminal_ours_for_output (); + + fprintf_unfiltered (stderr, "target_terminal_ours_for_output ()\n"); +} + +static void +debug_to_terminal_ours () +{ + debug_target.to_terminal_ours (); + + fprintf_unfiltered (stderr, "target_terminal_ours ()\n"); +} + +static void +debug_to_terminal_info (arg, from_tty) + char *arg; + int from_tty; +{ + debug_target.to_terminal_info (arg, from_tty); + + fprintf_unfiltered (stderr, "target_terminal_info (%s, %d)\n", arg, + from_tty); +} + +static void +debug_to_kill () +{ + debug_target.to_kill (); + + fprintf_unfiltered (stderr, "target_kill ()\n"); +} + +static void +debug_to_load (args, from_tty) + char *args; + int from_tty; +{ + debug_target.to_load (args, from_tty); + + fprintf_unfiltered (stderr, "target_load (%s, %d)\n", args, from_tty); +} + +static int +debug_to_lookup_symbol (name, addrp) + char *name; + CORE_ADDR *addrp; +{ + int retval; + + retval = debug_target.to_lookup_symbol (name, addrp); + + fprintf_unfiltered (stderr, "target_lookup_symbol (%s, xxx)\n", name); + + return retval; +} + +static void +debug_to_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + debug_target.to_create_inferior (exec_file, args, env); + + fprintf_unfiltered (stderr, "target_create_inferior (%s, %s, xxx)\n", + exec_file, args); +} + +static void +debug_to_mourn_inferior () +{ + debug_target.to_mourn_inferior (); + + fprintf_unfiltered (stderr, "target_mourn_inferior ()\n"); +} + +static int +debug_to_can_run () +{ + int retval; + + retval = debug_target.to_can_run (); + + fprintf_unfiltered (stderr, "target_can_run () = %d\n", retval); + + return retval; +} + +static void +debug_to_notice_signals (pid) + int pid; +{ + debug_target.to_notice_signals (pid); + + fprintf_unfiltered (stderr, "target_notice_signals (%d)\n", pid); +} + +static int +debug_to_thread_alive (pid) + int pid; +{ + debug_target.to_thread_alive (pid); + + fprintf_unfiltered (stderr, "target_thread_alive (%d)\n", pid); + return (0); +} + +static void +debug_to_stop () +{ + debug_target.to_stop (); + + fprintf_unfiltered (stderr, "target_stop ()\n"); +} + +static void +setup_target_debug () +{ + memcpy (&debug_target, ¤t_target, sizeof debug_target); + + current_target.to_open = debug_to_open; + current_target.to_close = debug_to_close; + current_target.to_attach = debug_to_attach; + current_target.to_detach = debug_to_detach; + current_target.to_resume = debug_to_resume; + current_target.to_wait = debug_to_wait; + current_target.to_fetch_registers = debug_to_fetch_registers; + current_target.to_store_registers = debug_to_store_registers; + current_target.to_prepare_to_store = debug_to_prepare_to_store; + current_target.to_xfer_memory = debug_to_xfer_memory; + current_target.to_files_info = debug_to_files_info; + current_target.to_insert_breakpoint = debug_to_insert_breakpoint; + current_target.to_remove_breakpoint = debug_to_remove_breakpoint; + current_target.to_terminal_init = debug_to_terminal_init; + current_target.to_terminal_inferior = debug_to_terminal_inferior; + current_target.to_terminal_ours_for_output = debug_to_terminal_ours_for_output; + current_target.to_terminal_ours = debug_to_terminal_ours; + current_target.to_terminal_info = debug_to_terminal_info; + current_target.to_kill = debug_to_kill; + current_target.to_load = debug_to_load; + current_target.to_lookup_symbol = debug_to_lookup_symbol; + current_target.to_create_inferior = debug_to_create_inferior; + current_target.to_mourn_inferior = debug_to_mourn_inferior; + current_target.to_can_run = debug_to_can_run; + current_target.to_notice_signals = debug_to_notice_signals; + current_target.to_thread_alive = debug_to_thread_alive; + current_target.to_stop = debug_to_stop; +} +#endif /* MAINTENANCE_CMDS */ + +static char targ_desc[] = + "Names of targets and files being debugged.\n\ +Shows the entire stack of targets currently in use (including the exec-file,\n\ +core-file, and process, if any), as well as the symbol file name."; + +void +initialize_targets () +{ + push_target (&dummy_target); + + add_info ("target", target_info, targ_desc); + add_info ("files", target_info, targ_desc); + +#ifdef MAINTENANCE_CMDS + add_show_from_set ( + add_set_cmd ("targetdebug", class_maintenance, var_zinteger, + (char *)&targetdebug, + "Set target debugging.\n\ +When non-zero, target debugging is enabled.", &setlist), + &showlist); +#endif + + if (!STREQ (signals[TARGET_SIGNAL_LAST].string, "TARGET_SIGNAL_MAGIC")) + abort (); +} diff --git a/contrib/gdb/gdb/target.h b/contrib/gdb/gdb/target.h new file mode 100644 index 000000000000..fa2291da9b71 --- /dev/null +++ b/contrib/gdb/gdb/target.h @@ -0,0 +1,765 @@ +/* Interface between GDB and target environments, including files and processes + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (TARGET_H) +#define TARGET_H + +/* This include file defines the interface between the main part + of the debugger, and the part which is target-specific, or + specific to the communications interface between us and the + target. + + A TARGET is an interface between the debugger and a particular + kind of file or process. Targets can be STACKED in STRATA, + so that more than one target can potentially respond to a request. + In particular, memory accesses will walk down the stack of targets + until they find a target that is interested in handling that particular + address. STRATA are artificial boundaries on the stack, within + which particular kinds of targets live. Strata exist so that + people don't get confused by pushing e.g. a process target and then + a file target, and wondering why they can't see the current values + of variables any more (the file target is handling them and they + never get to the process target). So when you push a file target, + it goes into the file stratum, which is always below the process + stratum. */ + +#include "bfd.h" + +enum strata { + dummy_stratum, /* The lowest of the low */ + file_stratum, /* Executable files, etc */ + core_stratum, /* Core dump files */ + download_stratum, /* Downloading of remote targets */ + process_stratum /* Executing processes */ +}; + +/* Stuff for target_wait. */ + +/* Generally, what has the program done? */ +enum target_waitkind { + /* The program has exited. The exit status is in value.integer. */ + TARGET_WAITKIND_EXITED, + + /* The program has stopped with a signal. Which signal is in value.sig. */ + TARGET_WAITKIND_STOPPED, + + /* The program has terminated with a signal. Which signal is in + value.sig. */ + TARGET_WAITKIND_SIGNALLED, + + /* The program is letting us know that it dynamically loaded something + (e.g. it called load(2) on AIX). */ + TARGET_WAITKIND_LOADED, + + /* Nothing happened, but we stopped anyway. This perhaps should be handled + within target_wait, but I'm not sure target_wait should be resuming the + inferior. */ + TARGET_WAITKIND_SPURIOUS + }; + +/* The numbering of these signals is chosen to match traditional unix + signals (insofar as various unices use the same numbers, anyway). + It is also the numbering of the GDB remote protocol. Other remote + protocols, if they use a different numbering, should make sure to + translate appropriately. */ + +/* This is based strongly on Unix/POSIX signals for several reasons: + (1) This set of signals represents a widely-accepted attempt to + represent events of this sort in a portable fashion, (2) we want a + signal to make it from wait to child_wait to the user intact, (3) many + remote protocols use a similar encoding. However, it is + recognized that this set of signals has limitations (such as not + distinguishing between various kinds of SIGSEGV, or not + distinguishing hitting a breakpoint from finishing a single step). + So in the future we may get around this either by adding additional + signals for breakpoint, single-step, etc., or by adding signal + codes; the latter seems more in the spirit of what BSD, System V, + etc. are doing to address these issues. */ + +/* For an explanation of what each signal means, see + target_signal_to_string. */ + +enum target_signal { + /* Used some places (e.g. stop_signal) to record the concept that + there is no signal. */ + TARGET_SIGNAL_0 = 0, + TARGET_SIGNAL_FIRST = 0, + TARGET_SIGNAL_HUP = 1, + TARGET_SIGNAL_INT = 2, + TARGET_SIGNAL_QUIT = 3, + TARGET_SIGNAL_ILL = 4, + TARGET_SIGNAL_TRAP = 5, + TARGET_SIGNAL_ABRT = 6, + TARGET_SIGNAL_EMT = 7, + TARGET_SIGNAL_FPE = 8, + TARGET_SIGNAL_KILL = 9, + TARGET_SIGNAL_BUS = 10, + TARGET_SIGNAL_SEGV = 11, + TARGET_SIGNAL_SYS = 12, + TARGET_SIGNAL_PIPE = 13, + TARGET_SIGNAL_ALRM = 14, + TARGET_SIGNAL_TERM = 15, + TARGET_SIGNAL_URG = 16, + TARGET_SIGNAL_STOP = 17, + TARGET_SIGNAL_TSTP = 18, + TARGET_SIGNAL_CONT = 19, + TARGET_SIGNAL_CHLD = 20, + TARGET_SIGNAL_TTIN = 21, + TARGET_SIGNAL_TTOU = 22, + TARGET_SIGNAL_IO = 23, + TARGET_SIGNAL_XCPU = 24, + TARGET_SIGNAL_XFSZ = 25, + TARGET_SIGNAL_VTALRM = 26, + TARGET_SIGNAL_PROF = 27, + TARGET_SIGNAL_WINCH = 28, + TARGET_SIGNAL_LOST = 29, + TARGET_SIGNAL_USR1 = 30, + TARGET_SIGNAL_USR2 = 31, + TARGET_SIGNAL_PWR = 32, + /* Similar to SIGIO. Perhaps they should have the same number. */ + TARGET_SIGNAL_POLL = 33, + TARGET_SIGNAL_WIND = 34, + TARGET_SIGNAL_PHONE = 35, + TARGET_SIGNAL_WAITING = 36, + TARGET_SIGNAL_LWP = 37, + TARGET_SIGNAL_DANGER = 38, + TARGET_SIGNAL_GRANT = 39, + TARGET_SIGNAL_RETRACT = 40, + TARGET_SIGNAL_MSG = 41, + TARGET_SIGNAL_SOUND = 42, + TARGET_SIGNAL_SAK = 43, + TARGET_SIGNAL_PRIO = 44, + TARGET_SIGNAL_REALTIME_33 = 45, + TARGET_SIGNAL_REALTIME_34 = 46, + TARGET_SIGNAL_REALTIME_35 = 47, + TARGET_SIGNAL_REALTIME_36 = 48, + TARGET_SIGNAL_REALTIME_37 = 49, + TARGET_SIGNAL_REALTIME_38 = 50, + TARGET_SIGNAL_REALTIME_39 = 51, + TARGET_SIGNAL_REALTIME_40 = 52, + TARGET_SIGNAL_REALTIME_41 = 53, + TARGET_SIGNAL_REALTIME_42 = 54, + TARGET_SIGNAL_REALTIME_43 = 55, + TARGET_SIGNAL_REALTIME_44 = 56, + TARGET_SIGNAL_REALTIME_45 = 57, + TARGET_SIGNAL_REALTIME_46 = 58, + TARGET_SIGNAL_REALTIME_47 = 59, + TARGET_SIGNAL_REALTIME_48 = 60, + TARGET_SIGNAL_REALTIME_49 = 61, + TARGET_SIGNAL_REALTIME_50 = 62, + TARGET_SIGNAL_REALTIME_51 = 63, + TARGET_SIGNAL_REALTIME_52 = 64, + TARGET_SIGNAL_REALTIME_53 = 65, + TARGET_SIGNAL_REALTIME_54 = 66, + TARGET_SIGNAL_REALTIME_55 = 67, + TARGET_SIGNAL_REALTIME_56 = 68, + TARGET_SIGNAL_REALTIME_57 = 69, + TARGET_SIGNAL_REALTIME_58 = 70, + TARGET_SIGNAL_REALTIME_59 = 71, + TARGET_SIGNAL_REALTIME_60 = 72, + TARGET_SIGNAL_REALTIME_61 = 73, + TARGET_SIGNAL_REALTIME_62 = 74, + TARGET_SIGNAL_REALTIME_63 = 75, + + /* Some signal we don't know about. */ + TARGET_SIGNAL_UNKNOWN, + + /* Use whatever signal we use when one is not specifically specified + (for passing to proceed and so on). */ + TARGET_SIGNAL_DEFAULT, + + /* Last and unused enum value, for sizing arrays, etc. */ + TARGET_SIGNAL_LAST +}; + +struct target_waitstatus { + enum target_waitkind kind; + + /* Exit status or signal number. */ + union { + int integer; + enum target_signal sig; + } value; +}; + +/* Return the string for a signal. */ +extern char *target_signal_to_string PARAMS ((enum target_signal)); + +/* Return the name (SIGHUP, etc.) for a signal. */ +extern char *target_signal_to_name PARAMS ((enum target_signal)); + +/* Given a name (SIGHUP, etc.), return its signal. */ +enum target_signal target_signal_from_name PARAMS ((char *)); + +/* If certain kinds of activity happen, target_wait should perform + callbacks. */ +/* Right now we just call (*TARGET_ACTIVITY_FUNCTION) if I/O is possible + on TARGET_ACTIVITY_FD. */ +extern int target_activity_fd; +/* Returns zero to leave the inferior alone, one to interrupt it. */ +extern int (*target_activity_function) PARAMS ((void)); + +struct target_ops +{ + char *to_shortname; /* Name this target type */ + char *to_longname; /* Name for printing */ + char *to_doc; /* Documentation. Does not include trailing + newline, and starts with a one-line descrip- + tion (probably similar to to_longname). */ + void (*to_open) PARAMS ((char *, int)); + void (*to_close) PARAMS ((int)); + void (*to_attach) PARAMS ((char *, int)); + void (*to_detach) PARAMS ((char *, int)); + void (*to_resume) PARAMS ((int, int, enum target_signal)); + int (*to_wait) PARAMS ((int, struct target_waitstatus *)); + void (*to_fetch_registers) PARAMS ((int)); + void (*to_store_registers) PARAMS ((int)); + void (*to_prepare_to_store) PARAMS ((void)); + + /* Transfer LEN bytes of memory between GDB address MYADDR and + target address MEMADDR. If WRITE, transfer them to the target, else + transfer them from the target. TARGET is the target from which we + get this function. + + Return value, N, is one of the following: + + 0 means that we can't handle this. If errno has been set, it is the + error which prevented us from doing it (FIXME: What about bfd_error?). + + positive (call it N) means that we have transferred N bytes + starting at MEMADDR. We might be able to handle more bytes + beyond this length, but no promises. + + negative (call its absolute value N) means that we cannot + transfer right at MEMADDR, but we could transfer at least + something at MEMADDR + N. */ + + int (*to_xfer_memory) PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int write, + struct target_ops * target)); + +#if 0 + /* Enable this after 4.12. */ + + /* Search target memory. Start at STARTADDR and take LEN bytes of + target memory, and them with MASK, and compare to DATA. If they + match, set *ADDR_FOUND to the address we found it at, store the data + we found at LEN bytes starting at DATA_FOUND, and return. If + not, add INCREMENT to the search address and keep trying until + the search address is outside of the range [LORANGE,HIRANGE). + + If we don't find anything, set *ADDR_FOUND to (CORE_ADDR)0 and return. */ + void (*to_search) PARAMS ((int len, char *data, char *mask, + CORE_ADDR startaddr, int increment, + CORE_ADDR lorange, CORE_ADDR hirange, + CORE_ADDR *addr_found, char *data_found)); + +#define target_search(len, data, mask, startaddr, increment, lorange, hirange, addr_found, data_found) \ + (*current_target.to_search) (len, data, mask, startaddr, increment, \ + lorange, hirange, addr_found, data_found) +#endif /* 0 */ + + void (*to_files_info) PARAMS ((struct target_ops *)); + int (*to_insert_breakpoint) PARAMS ((CORE_ADDR, char *)); + int (*to_remove_breakpoint) PARAMS ((CORE_ADDR, char *)); + void (*to_terminal_init) PARAMS ((void)); + void (*to_terminal_inferior) PARAMS ((void)); + void (*to_terminal_ours_for_output) PARAMS ((void)); + void (*to_terminal_ours) PARAMS ((void)); + void (*to_terminal_info) PARAMS ((char *, int)); + void (*to_kill) PARAMS ((void)); + void (*to_load) PARAMS ((char *, int)); + int (*to_lookup_symbol) PARAMS ((char *, CORE_ADDR *)); + void (*to_create_inferior) PARAMS ((char *, char *, char **)); + void (*to_mourn_inferior) PARAMS ((void)); + int (*to_can_run) PARAMS ((void)); + void (*to_notice_signals) PARAMS ((int pid)); + int (*to_thread_alive) PARAMS ((int pid)); + void (*to_stop) PARAMS ((void)); + enum strata to_stratum; + struct target_ops + *DONT_USE; /* formerly to_next */ + int to_has_all_memory; + int to_has_memory; + int to_has_stack; + int to_has_registers; + int to_has_execution; + struct section_table + *to_sections; + struct section_table + *to_sections_end; + int to_magic; + /* Need sub-structure for target machine related rather than comm related? */ +}; + +/* Magic number for checking ops size. If a struct doesn't end with this + number, somebody changed the declaration but didn't change all the + places that initialize one. */ + +#define OPS_MAGIC 3840 + +/* The ops structure for our "current" target process. This should + never be NULL. If there is no target, it points to the dummy_target. */ + +extern struct target_ops current_target; + +/* An item on the target stack. */ + +struct target_stack_item +{ + struct target_stack_item *next; + struct target_ops *target_ops; +}; + +/* The target stack. */ + +extern struct target_stack_item *target_stack; + +/* Define easy words for doing these operations on our current target. */ + +#define target_shortname (current_target.to_shortname) +#define target_longname (current_target.to_longname) + +/* The open routine takes the rest of the parameters from the command, + and (if successful) pushes a new target onto the stack. + Targets should supply this routine, if only to provide an error message. */ +#define target_open(name, from_tty) \ + (*current_target.to_open) (name, from_tty) + +/* Does whatever cleanup is required for a target that we are no longer + going to be calling. Argument says whether we are quitting gdb and + should not get hung in case of errors, or whether we want a clean + termination even if it takes a while. This routine is automatically + always called just before a routine is popped off the target stack. + Closing file descriptors and freeing memory are typical things it should + do. */ + +#define target_close(quitting) \ + (*current_target.to_close) (quitting) + +/* Attaches to a process on the target side. Arguments are as passed + to the `attach' command by the user. This routine can be called + when the target is not on the target-stack, if the target_can_run + routine returns 1; in that case, it must push itself onto the stack. + Upon exit, the target should be ready for normal operations, and + should be ready to deliver the status of the process immediately + (without waiting) to an upcoming target_wait call. */ + +#define target_attach(args, from_tty) \ + (*current_target.to_attach) (args, from_tty) + +/* Takes a program previously attached to and detaches it. + The program may resume execution (some targets do, some don't) and will + no longer stop on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. ARGS is arguments + typed by the user (e.g. a signal to send the process). FROM_TTY + says whether to be verbose or not. */ + +extern void +target_detach PARAMS ((char *, int)); + +/* Resume execution of the target process PID. STEP says whether to + single-step or to run free; SIGGNAL is the signal to be given to + the target, or TARGET_SIGNAL_0 for no signal. The caller may not + pass TARGET_SIGNAL_DEFAULT. */ + +#define target_resume(pid, step, siggnal) \ + (*current_target.to_resume) (pid, step, siggnal) + +/* Wait for process pid to do something. Pid = -1 to wait for any pid + to do something. Return pid of child, or -1 in case of error; + store status through argument pointer STATUS. Note that it is + *not* OK to return_to_top_level out of target_wait without popping + the debugging target from the stack; GDB isn't prepared to get back + to the prompt with a debugging target but without the frame cache, + stop_pc, etc., set up. */ + +#define target_wait(pid, status) \ + (*current_target.to_wait) (pid, status) + +/* Fetch register REGNO, or all regs if regno == -1. No result. */ + +#define target_fetch_registers(regno) \ + (*current_target.to_fetch_registers) (regno) + +/* Store at least register REGNO, or all regs if REGNO == -1. + It can store as many registers as it wants to, so target_prepare_to_store + must have been previously called. Calls error() if there are problems. */ + +#define target_store_registers(regs) \ + (*current_target.to_store_registers) (regs) + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that REGISTERS contains all the registers from the program being + debugged. */ + +#define target_prepare_to_store() \ + (*current_target.to_prepare_to_store) () + +extern int target_read_string PARAMS ((CORE_ADDR, char **, int, int *)); + +extern int +target_read_memory PARAMS ((CORE_ADDR, char *, int)); + +extern int +target_read_memory_partial PARAMS ((CORE_ADDR, char *, int, int *)); + +extern int +target_write_memory PARAMS ((CORE_ADDR, char *, int)); + +extern int +xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +extern int +child_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +/* Transfer LEN bytes between target address MEMADDR and GDB address MYADDR. + Returns 0 for success, errno code for failure (which includes partial + transfers--if you want a more useful response to partial transfers, try + target_read_memory_partial). */ + +extern int target_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int write)); + +/* From exec.c */ + +extern void +print_section_info PARAMS ((struct target_ops *, bfd *)); + +/* Print a line about the current target. */ + +#define target_files_info() \ + (*current_target.to_files_info) (¤t_target) + +/* Insert a breakpoint at address ADDR in the target machine. + SAVE is a pointer to memory allocated for saving the + target contents. It is guaranteed by the caller to be long enough + to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or + an errno value. */ + +#define target_insert_breakpoint(addr, save) \ + (*current_target.to_insert_breakpoint) (addr, save) + +/* Remove a breakpoint at address ADDR in the target machine. + SAVE is a pointer to the same save area + that was previously passed to target_insert_breakpoint. + Result is 0 for success, or an errno value. */ + +#define target_remove_breakpoint(addr, save) \ + (*current_target.to_remove_breakpoint) (addr, save) + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +#define target_terminal_init() \ + (*current_target.to_terminal_init) () + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +#define target_terminal_inferior() \ + (*current_target.to_terminal_inferior) () + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +#define target_terminal_ours_for_output() \ + (*current_target.to_terminal_ours_for_output) () + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +#define target_terminal_ours() \ + (*current_target.to_terminal_ours) () + +/* Print useful information about our terminal status, if such a thing + exists. */ + +#define target_terminal_info(arg, from_tty) \ + (*current_target.to_terminal_info) (arg, from_tty) + +/* Kill the inferior process. Make it go away. */ + +#define target_kill() \ + (*current_target.to_kill) () + +/* Load an executable file into the target process. This is expected to + not only bring new code into the target process, but also to update + GDB's symbol tables to match. */ + +#define target_load(arg, from_tty) \ + (*current_target.to_load) (arg, from_tty) + +/* Look up a symbol in the target's symbol table. NAME is the symbol + name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol + should be returned. The result is 0 if successful, nonzero if the + symbol does not exist in the target environment. This function should + not call error() if communication with the target is interrupted, since + it is called from symbol reading, but should return nonzero, possibly + doing a complain(). */ + +#define target_lookup_symbol(name, addrp) \ + (*current_target.to_lookup_symbol) (name, addrp) + +/* Start an inferior process and set inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). + On VxWorks and various standalone systems, we ignore exec_file. */ + +#define target_create_inferior(exec_file, args, env) \ + (*current_target.to_create_inferior) (exec_file, args, env) + +/* The inferior process has died. Do what is right. */ + +#define target_mourn_inferior() \ + (*current_target.to_mourn_inferior) () + +/* Does target have enough data to do a run or attach command? */ + +#define target_can_run(t) \ + ((t)->to_can_run) () + +/* post process changes to signal handling in the inferior. */ + +#define target_notice_signals(pid) \ + (*current_target.to_notice_signals) (pid) + +/* Check to see if a thread is still alive. */ + +#define target_thread_alive(pid) \ + (*current_target.to_thread_alive) (pid) + +/* Make target stop in a continuable fashion. (For instance, under Unix, this + should act like SIGSTOP). This function is normally used by GUIs to + implement a stop button. */ + +#define target_stop() current_target.to_stop () + +/* Pointer to next target in the chain, e.g. a core file and an exec file. */ + +#define target_next \ + (current_target.to_next) + +/* Does the target include all of memory, or only part of it? This + determines whether we look up the target chain for other parts of + memory if this target can't satisfy a request. */ + +#define target_has_all_memory \ + (current_target.to_has_all_memory) + +/* Does the target include memory? (Dummy targets don't.) */ + +#define target_has_memory \ + (current_target.to_has_memory) + +/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until + we start a process.) */ + +#define target_has_stack \ + (current_target.to_has_stack) + +/* Does the target have registers? (Exec files don't.) */ + +#define target_has_registers \ + (current_target.to_has_registers) + +/* Does the target have execution? Can we make it jump (through + hoops), or pop its stack a few times? FIXME: If this is to work that + way, it needs to check whether an inferior actually exists. + remote-udi.c and probably other targets can be the current target + when the inferior doesn't actually exist at the moment. Right now + this just tells us whether this target is *capable* of execution. */ + +#define target_has_execution \ + (current_target.to_has_execution) + +extern void target_link PARAMS ((char *, CORE_ADDR *)); + +/* Converts a process id to a string. Usually, the string just contains + `process xyz', but on some systems it may contain + `process xyz thread abc'. */ + +#ifndef target_pid_to_str +#define target_pid_to_str(PID) \ + normal_pid_to_str (PID) +extern char *normal_pid_to_str PARAMS ((int pid)); +#endif + +/* Hook to call target-dependant code after reading in a new symbol table. */ + +#ifndef TARGET_SYMFILE_POSTREAD +#define TARGET_SYMFILE_POSTREAD(OBJFILE) +#endif + +/* Hook to call target dependant code just after inferior target process has + started. */ + +#ifndef TARGET_CREATE_INFERIOR_HOOK +#define TARGET_CREATE_INFERIOR_HOOK(PID) +#endif + +/* Hardware watchpoint interfaces. */ + +/* Returns non-zero if we were stopped by a hardware watchpoint (memory read or + write). */ + +#ifndef STOPPED_BY_WATCHPOINT +#define STOPPED_BY_WATCHPOINT(w) 0 +#endif + +/* Provide defaults for systems that don't support hardware watchpoints. */ + +#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS + +/* Returns non-zero if we can set a hardware watchpoint of type TYPE. TYPE is + one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint, or + bp_hardware_breakpoint. CNT is the number of such watchpoints used so far + (including this one?). OTHERTYPE is who knows what... */ + +#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(TYPE,CNT,OTHERTYPE) 0 + +/* Set/clear a hardware watchpoint starting at ADDR, for LEN bytes. TYPE is 1 + for read and 2 for read/write accesses. Returns 0 for success, non-zero for + failure. */ + +#define target_remove_watchpoint(ADDR,LEN,TYPE) -1 +#define target_insert_watchpoint(ADDR,LEN,TYPE) -1 + +#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */ + +#ifndef target_insert_hw_breakpoint +#define target_remove_hw_breakpoint(ADDR,SHADOW) -1 +#define target_insert_hw_breakpoint(ADDR,SHADOW) -1 +#endif + +#ifndef target_stopped_data_address +#define target_stopped_data_address() 0 +#endif + +/* If defined, then we need to decr pc by this much after a hardware break- + point. Presumably this overrides DECR_PC_AFTER_BREAK... */ + +#ifndef DECR_PC_AFTER_HW_BREAK +#define DECR_PC_AFTER_HW_BREAK 0 +#endif + +/* Routines for maintenance of the target structures... + + add_target: Add a target to the list of all possible targets. + + push_target: Make this target the top of the stack of currently used + targets, within its particular stratum of the stack. Result + is 0 if now atop the stack, nonzero if not on top (maybe + should warn user). + + unpush_target: Remove this from the stack of currently used targets, + no matter where it is on the list. Returns 0 if no + change, 1 if removed from stack. + + pop_target: Remove the top thing on the stack of current targets. */ + +extern void +add_target PARAMS ((struct target_ops *)); + +extern int +push_target PARAMS ((struct target_ops *)); + +extern int +unpush_target PARAMS ((struct target_ops *)); + +extern void +target_preopen PARAMS ((int)); + +extern void +pop_target PARAMS ((void)); + +/* Struct section_table maps address ranges to file sections. It is + mostly used with BFD files, but can be used without (e.g. for handling + raw disks, or files not in formats handled by BFD). */ + +struct section_table { + CORE_ADDR addr; /* Lowest address in section */ + CORE_ADDR endaddr; /* 1+highest address in section */ + + sec_ptr the_bfd_section; + + bfd *bfd; /* BFD file pointer */ +}; + +/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. + Returns 0 if OK, 1 on error. */ + +extern int +build_section_table PARAMS ((bfd *, struct section_table **, + struct section_table **)); + +/* From mem-break.c */ + +extern int +memory_remove_breakpoint PARAMS ((CORE_ADDR, char *)); + +extern int +memory_insert_breakpoint PARAMS ((CORE_ADDR, char *)); + +/* From target.c */ + +void +noprocess PARAMS ((void)); + +void +find_default_attach PARAMS ((char *, int)); + +void +find_default_create_inferior PARAMS ((char *, char *, char **)); + +struct target_ops * +find_core_target PARAMS ((void)); + +/* Stuff that should be shared among the various remote targets. */ + +/* Debugging level. 0 is off, and non-zero values mean to print some debug + information (higher values, more information). */ +extern int remote_debug; + +/* Speed in bits per second, or -1 which means don't mess with the speed. */ +extern int baud_rate; + +/* Functions for helping to write a native target. */ + +/* This is for native targets which use a unix/POSIX-style waitstatus. */ +extern void store_waitstatus PARAMS ((struct target_waitstatus *, int)); + +/* Convert between host signal numbers and enum target_signal's. */ +extern enum target_signal target_signal_from_host PARAMS ((int)); +extern int target_signal_to_host PARAMS ((enum target_signal)); + +/* Convert from a number used in a GDB command to an enum target_signal. */ +extern enum target_signal target_signal_from_command PARAMS ((int)); + +#endif /* !defined (TARGET_H) */ diff --git a/contrib/gdb/gdb/terminal.h b/contrib/gdb/gdb/terminal.h new file mode 100644 index 000000000000..9cae179d729e --- /dev/null +++ b/contrib/gdb/gdb/terminal.h @@ -0,0 +1,89 @@ +/* Terminal interface definitions for GDB, the GNU Debugger. + Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (TERMINAL_H) +#define TERMINAL_H 1 + + +/* If we're using autoconf, it will define HAVE_TERMIOS_H, + HAVE_TERMIO_H and HAVE_SGTTY_H for us. One day we can rewrite + ser-unix.c and inflow.c to inspect those names instead of + HAVE_TERMIOS, HAVE_TERMIO and the implicit HAVE_SGTTY (when neither + HAVE_TERMIOS or HAVE_TERMIO is set). Until then, make sure that + nothing has already defined the one of the names, and do the right + thing. */ + +/* nothing works with go32, and the headers aren't complete */ +#if !defined (__GO32__) +#if !defined (HAVE_TERMIOS) && !defined(HAVE_TERMIO) && !defined(HAVE_SGTTY) +#if defined(HAVE_TERMIOS_H) +#define HAVE_TERMIOS +#elif defined(HAVE_TERMIO_H) +#define HAVE_TERMIO +#elif defined(HAVE_SGTTY_H) +#define HAVE_SGTTY +#endif +#endif +#endif + +#if defined(HAVE_TERMIOS) +#include +#endif + + +#if !defined(__GO32__) && !defined(__WIN32__) && !defined (HAVE_TERMIOS) + +/* Define a common set of macros -- BSD based -- and redefine whatever + the system offers to make it look like that. FIXME: serial.h and + ser-*.c deal with this in a much cleaner fashion; as soon as stuff + is converted to use them, can get rid of this crap. */ + +#ifdef HAVE_TERMIO + +#include + +#undef TIOCGETP +#define TIOCGETP TCGETA +#undef TIOCSETN +#define TIOCSETN TCSETA +#undef TIOCSETP +#define TIOCSETP TCSETAF +#define TERMINAL struct termio + +#else /* sgtty */ + +#include +#include +#include +#define TERMINAL struct sgttyb + +#endif /* sgtty */ +#endif + +extern void new_tty PARAMS ((void)); + +/* Do we have job control? Can be assumed to always be the same within + a given run of GDB. In inflow.c. */ +extern int job_control; + +/* Set the process group of the caller to its own pid, or do nothing if + we lack job control. */ +extern int gdb_setpgid PARAMS ((void)); + +#endif /* !defined (TERMINAL_H) */ diff --git a/contrib/gdb/gdb/thread.c b/contrib/gdb/gdb/thread.c new file mode 100644 index 000000000000..d3ed393b2cec --- /dev/null +++ b/contrib/gdb/gdb/thread.c @@ -0,0 +1,476 @@ +/* Multi-process/thread control for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1993 + + Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" +#include "target.h" +#include "thread.h" +#include "command.h" +#include "gdbcmd.h" + +#include +#include +#include + +/*#include "lynxos-core.h"*/ + +struct thread_info +{ + struct thread_info *next; + int pid; /* Actual process id */ + int num; /* Convenient handle */ + CORE_ADDR prev_pc; /* State from wait_for_inferior */ + CORE_ADDR prev_func_start; + char *prev_func_name; + struct breakpoint *step_resume_breakpoint; + struct breakpoint *through_sigtramp_breakpoint; + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + CORE_ADDR step_frame_address; + int trap_expected; + int handling_longjmp; + int another_trap; +}; + +static struct thread_info *thread_list = NULL; +static int highest_thread_num; + +static void thread_command PARAMS ((char * tidstr, int from_tty)); + +static void prune_threads PARAMS ((void)); + +static void thread_switch PARAMS ((int pid)); + +static struct thread_info * find_thread_id PARAMS ((int num)); + +void +init_thread_list () +{ + struct thread_info *tp, *tpnext; + + if (!thread_list) + return; + + for (tp = thread_list; tp; tp = tpnext) + { + tpnext = tp->next; + free (tp); + } + + thread_list = NULL; + highest_thread_num = 0; +} + +void +add_thread (pid) + int pid; +{ + struct thread_info *tp; + + tp = (struct thread_info *) xmalloc (sizeof (struct thread_info)); + + tp->pid = pid; + tp->num = ++highest_thread_num; + tp->prev_pc = 0; + tp->prev_func_start = 0; + tp->prev_func_name = NULL; + tp->step_range_start = 0; + tp->step_range_end = 0; + tp->step_frame_address =0; + tp->step_resume_breakpoint = 0; + tp->through_sigtramp_breakpoint = 0; + tp->handling_longjmp = 0; + tp->trap_expected = 0; + tp->another_trap = 0; + tp->next = thread_list; + thread_list = tp; +} + +static struct thread_info * +find_thread_id (num) + int num; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->num == num) + return tp; + + return NULL; +} + +int +valid_thread_id (num) + int num; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->num == num) + return 1; + + return 0; +} + +int +pid_to_thread_id (pid) + int pid; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == pid) + return tp->num; + + return 0; +} + +int +in_thread_list (pid) + int pid; +{ + struct thread_info *tp; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == pid) + return 1; + + return 0; /* Never heard of 'im */ +} + +/* Load infrun state for the thread PID. */ + +void load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, + trap_expected, step_resume_breakpoint, + through_sigtramp_breakpoint, step_range_start, + step_range_end, step_frame_address, + handling_longjmp, another_trap) + int pid; + CORE_ADDR *prev_pc; + CORE_ADDR *prev_func_start; + char **prev_func_name; + int *trap_expected; + struct breakpoint **step_resume_breakpoint; + struct breakpoint **through_sigtramp_breakpoint; + CORE_ADDR *step_range_start; + CORE_ADDR *step_range_end; + CORE_ADDR *step_frame_address; + int *handling_longjmp; + int *another_trap; +{ + struct thread_info *tp; + + /* If we can't find the thread, then we're debugging a single threaded + process. No need to do anything in that case. */ + tp = find_thread_id (pid_to_thread_id (pid)); + if (tp == NULL) + return; + + *prev_pc = tp->prev_pc; + *prev_func_start = tp->prev_func_start; + *prev_func_name = tp->prev_func_name; + *step_resume_breakpoint = tp->step_resume_breakpoint; + *step_range_start = tp->step_range_start; + *step_range_end = tp->step_range_end; + *step_frame_address = tp->step_frame_address; + *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint; + *handling_longjmp = tp->handling_longjmp; + *trap_expected = tp->trap_expected; + *another_trap = tp->another_trap; +} + +/* Save infrun state for the thread PID. */ + +void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name, + trap_expected, step_resume_breakpoint, + through_sigtramp_breakpoint, step_range_start, + step_range_end, step_frame_address, + handling_longjmp, another_trap) + int pid; + CORE_ADDR prev_pc; + CORE_ADDR prev_func_start; + char *prev_func_name; + int trap_expected; + struct breakpoint *step_resume_breakpoint; + struct breakpoint *through_sigtramp_breakpoint; + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + CORE_ADDR step_frame_address; + int handling_longjmp; + int another_trap; +{ + struct thread_info *tp; + + /* If we can't find the thread, then we're debugging a single-threaded + process. Nothing to do in that case. */ + tp = find_thread_id (pid_to_thread_id (pid)); + if (tp == NULL) + return; + + tp->prev_pc = prev_pc; + tp->prev_func_start = prev_func_start; + tp->prev_func_name = prev_func_name; + tp->step_resume_breakpoint = step_resume_breakpoint; + tp->step_range_start = step_range_start; + tp->step_range_end = step_range_end; + tp->step_frame_address = step_frame_address; + tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint; + tp->handling_longjmp = handling_longjmp; + tp->trap_expected = trap_expected; + tp->another_trap = another_trap; +} + +static void +prune_threads () +{ + struct thread_info *tp, *tpprev; + + tpprev = 0; + + for (tp = thread_list; tp; tp = tp->next) + if (tp->pid == -1) + { + if (tpprev) + tpprev->next = tp->next; + else + thread_list = NULL; + + free (tp); + } + else + tpprev = tp; +} + +/* Print information about currently known threads */ + +static void +info_threads_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct thread_info *tp; + int current_pid = inferior_pid; + + /* Avoid coredumps which would happen if we tried to access a NULL + selected_frame. */ + if (!target_has_stack) error ("No stack."); + + for (tp = thread_list; tp; tp = tp->next) + { + if (! target_thread_alive (tp->pid)) + { + tp->pid = -1; /* Mark it as dead */ + continue; + } + + if (tp->pid == current_pid) + printf_filtered ("* "); + else + printf_filtered (" "); + + printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid)); + + thread_switch (tp->pid); + print_stack_frame (selected_frame, -1, 0); + } + + thread_switch (current_pid); + prune_threads (); +} + +/* Switch from one thread to another. */ + +static void +thread_switch (pid) + int pid; +{ + if (pid == inferior_pid) + return; + + inferior_pid = pid; + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc(); + select_frame (get_current_frame (), 0); +} + +static void +restore_current_thread (pid) + int pid; +{ + if (pid != inferior_pid) + thread_switch (pid); +} + +/* Apply a GDB command to a list of threads. List syntax is a whitespace + seperated list of numbers, or ranges, or the keyword `all'. Ranges consist + of two numbers seperated by a hyphen. Examples: + + thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4 + thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9 + thread apply all p x/i $pc Apply x/i $pc cmd to all threads +*/ + +static void +thread_apply_all_command (cmd, from_tty) + char *cmd; + int from_tty; +{ + struct thread_info *tp; + struct cleanup *old_chain; + + if (cmd == NULL || *cmd == '\000') + error ("Please specify a command following the thread ID list"); + + old_chain = make_cleanup (restore_current_thread, inferior_pid); + + for (tp = thread_list; tp; tp = tp->next) + { + thread_switch (tp->pid); + printf_filtered ("\nThread %d (%s):\n", tp->num, + target_pid_to_str (inferior_pid)); + execute_command (cmd, from_tty); + } +} + +static void +thread_apply_command (tidlist, from_tty) + char *tidlist; + int from_tty; +{ + char *cmd; + char *p; + struct cleanup *old_chain; + + if (tidlist == NULL || *tidlist == '\000') + error ("Please specify a thread ID list"); + + for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++); + + if (*cmd == '\000') + error ("Please specify a command following the thread ID list"); + + old_chain = make_cleanup (restore_current_thread, inferior_pid); + + while (tidlist < cmd) + { + struct thread_info *tp; + int start, end; + + start = strtol (tidlist, &p, 10); + if (p == tidlist) + error ("Error parsing %s", tidlist); + tidlist = p; + + while (*tidlist == ' ' || *tidlist == '\t') + tidlist++; + + if (*tidlist == '-') /* Got a range of IDs? */ + { + tidlist++; /* Skip the - */ + end = strtol (tidlist, &p, 10); + if (p == tidlist) + error ("Error parsing %s", tidlist); + tidlist = p; + + while (*tidlist == ' ' || *tidlist == '\t') + tidlist++; + } + else + end = start; + + for (; start <= end; start++) + { + tp = find_thread_id (start); + + if (!tp) + { + warning ("Unknown thread %d.", start); + continue; + } + + thread_switch (tp->pid); + printf_filtered ("\nThread %d (%s):\n", tp->num, + target_pid_to_str (inferior_pid)); + execute_command (cmd, from_tty); + } + } +} + +/* Switch to the specified thread. Will dispatch off to thread_apply_command + if prefix of arg is `apply'. */ + +static void +thread_command (tidstr, from_tty) + char *tidstr; + int from_tty; +{ + int num; + struct thread_info *tp; + + if (!tidstr) + error ("Please specify a thread ID. Use the \"info threads\" command to\n\ +see the IDs of currently known threads."); + + num = atoi (tidstr); + + tp = find_thread_id (num); + + if (!tp) + error ("Thread ID %d not known. Use the \"info threads\" command to\n\ +see the IDs of currently known threads.", num); + + thread_switch (tp->pid); + + printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid)); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +void +_initialize_thread () +{ + static struct cmd_list_element *thread_cmd_list = NULL; + static struct cmd_list_element *thread_apply_list = NULL; + extern struct cmd_list_element *cmdlist; + + add_info ("threads", info_threads_command, + "IDs of currently known threads."); + + add_prefix_cmd ("thread", class_run, thread_command, + "Use this command to switch between threads.\n\ +The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, + &cmdlist); + + add_prefix_cmd ("apply", class_run, thread_apply_command, + "Apply a command to a list of threads.", + &thread_apply_list, "apply ", 1, &thread_cmd_list); + + add_cmd ("all", class_run, thread_apply_all_command, + "Apply a command to all threads.", + &thread_apply_list); + + add_com_alias ("t", "thread", class_run, 1); +} diff --git a/contrib/gdb/gdb/thread.h b/contrib/gdb/gdb/thread.h new file mode 100644 index 000000000000..6777887af2e5 --- /dev/null +++ b/contrib/gdb/gdb/thread.h @@ -0,0 +1,46 @@ +/* Multi-process/thread control defs for GDB, the GNU debugger. + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993 + + Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef THREAD_H +#define THREAD_H + +extern void init_thread_list PARAMS ((void)); + +extern void add_thread PARAMS ((int pid)); + +extern int in_thread_list PARAMS ((int pid)); + +extern int pid_to_thread_id PARAMS ((int pid)); + +extern int valid_thread_id PARAMS ((int thread)); + +extern void load_infrun_state PARAMS ((int, CORE_ADDR *, CORE_ADDR *, char **, + int *, struct breakpoint **, + struct breakpoint **, CORE_ADDR *, + CORE_ADDR *, CORE_ADDR *, int *, int *)); + +extern void save_infrun_state PARAMS ((int, CORE_ADDR, CORE_ADDR, char *, + int, struct breakpoint *, + struct breakpoint *, CORE_ADDR, + CORE_ADDR, CORE_ADDR, int, int)); + +#endif /* THREAD_H */ diff --git a/contrib/gdb/gdb/top.c b/contrib/gdb/gdb/top.c new file mode 100644 index 000000000000..088bcd9d16df --- /dev/null +++ b/contrib/gdb/gdb/top.c @@ -0,0 +1,3557 @@ +/* Top level stuff for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "call-cmds.h" +#include "symtab.h" +#include "inferior.h" +#include "signals.h" +#include "target.h" +#include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "language.h" +#include "terminal.h" /* For job_control. */ +#include "annotate.h" +#include +#include "top.h" + +/* readline include files */ +#include "readline.h" +#include "history.h" + +/* readline defines this. */ +#undef savestring + +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "gdb_string.h" +#ifndef NO_SYS_FILE +#include +#endif +#include +#include "gdb_stat.h" +#include + +extern void initialize_targets PARAMS ((void)); + +extern void initialize_utils PARAMS ((void)); + +/* Prototypes for local functions */ + +static char * line_completion_function PARAMS ((char *, int, char *, int)); + +static char * readline_line_completion_function PARAMS ((char *, int)); + +static void command_loop_marker PARAMS ((int)); + +static void while_command PARAMS ((char *, int)); + +static void if_command PARAMS ((char *, int)); + +static struct command_line * +build_command_line PARAMS ((enum command_control_type, char *)); + +static struct command_line * +get_command_line PARAMS ((enum command_control_type, char *)); + +static void realloc_body_list PARAMS ((struct command_line *, int)); + +static enum misc_command_type read_next_line PARAMS ((struct command_line **)); + +static enum command_control_type +recurse_read_control_structure PARAMS ((struct command_line *)); + +static struct cleanup * setup_user_args PARAMS ((char *)); + +static char * locate_arg PARAMS ((char *)); + +static char * insert_args PARAMS ((char *)); + +static void arg_cleanup PARAMS ((void)); + +static void init_main PARAMS ((void)); + +static void init_cmd_lists PARAMS ((void)); + +static void float_handler PARAMS ((int)); + +static void init_signals PARAMS ((void)); + +static void set_verbose PARAMS ((char *, int, struct cmd_list_element *)); + +#ifdef TARGET_BYTE_ORDER_SELECTABLE + +static void set_endian PARAMS ((char *, int)); + +static void set_endian_big PARAMS ((char *, int)); + +static void set_endian_little PARAMS ((char *, int)); + +static void set_endian_auto PARAMS ((char *, int)); + +static void show_endian PARAMS ((char *, int)); + +#endif + +static void show_history PARAMS ((char *, int)); + +static void set_history PARAMS ((char *, int)); + +static void set_history_size_command PARAMS ((char *, int, + struct cmd_list_element *)); + +static void show_commands PARAMS ((char *, int)); + +static void echo_command PARAMS ((char *, int)); + +static void pwd_command PARAMS ((char *, int)); + +static void show_version PARAMS ((char *, int)); + +static void document_command PARAMS ((char *, int)); + +static void define_command PARAMS ((char *, int)); + +static void validate_comname PARAMS ((char *)); + +static void help_command PARAMS ((char *, int)); + +static void show_command PARAMS ((char *, int)); + +static void info_command PARAMS ((char *, int)); + +static void complete_command PARAMS ((char *, int)); + +static void do_nothing PARAMS ((int)); + +static int quit_cover PARAMS ((char *)); + +static void disconnect PARAMS ((int)); + +static void source_cleanup PARAMS ((FILE *)); + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +/* Initialization file name for gdb. This is overridden in some configs. */ + +#ifndef GDBINIT_FILENAME +#define GDBINIT_FILENAME ".gdbinit" +#endif +char gdbinit[] = GDBINIT_FILENAME; + +int inhibit_gdbinit = 0; + +/* If nonzero, and GDB has been configured to be able to use windows, + attempt to open them upon startup. */ + +int use_windows = 1; + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* Canonical host name as a string. */ + +extern char *host_name; + +/* Canonical target name as a string. */ + +extern char *target_name; + +extern char lang_frame_mismatch_warn[]; /* language.c */ + +/* Flag for whether we want all the "from_tty" gubbish printed. */ + +int caution = 1; /* Default is yes, sigh. */ + +/* Define all cmd_list_elements. */ + +/* Chain containing all defined commands. */ + +struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +struct cmd_list_element *deletelist; + +/* Chain containing all defined "enable breakpoint" subcommands. */ + +struct cmd_list_element *enablebreaklist; + +/* Chain containing all defined set subcommands */ + +struct cmd_list_element *setlist; + +/* Chain containing all defined unset subcommands */ + +struct cmd_list_element *unsetlist; + +/* Chain containing all defined show subcommands. */ + +struct cmd_list_element *showlist; + +#ifdef TARGET_BYTE_ORDER_SELECTABLE +/* Chain containing the \"set endian\" commands. */ + +struct cmd_list_element *endianlist; +#endif + +/* Chain containing all defined \"set history\". */ + +struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ + +struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +struct cmd_list_element *unsethistlist; + +/* Chain containing all defined maintenance subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenancelist; +#endif + +/* Chain containing all defined "maintenance info" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceinfolist; +#endif + +/* Chain containing all defined "maintenance print" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceprintlist; +#endif + +struct cmd_list_element *setprintlist; + +struct cmd_list_element *showprintlist; + +struct cmd_list_element *setchecklist; + +struct cmd_list_element *showchecklist; + +/* stdio stream that command input is being read from. Set to stdin normally. + Set by source_command to the file we are sourcing. Set to NULL if we are + executing a user-defined command. */ + +FILE *instream; + +/* Current working directory. */ + +char *current_directory; + +/* The directory name is actually stored here (usually). */ +char gdb_dirbuf[1024]; + +/* Function to call before reading a command, if nonzero. + The function receives two args: an input stream, + and a prompt string. */ + +void (*window_hook) PARAMS ((FILE *, char *)); + +int epoch_interface; +int xgdb_verbose; + +/* gdb prints this when reading a command interactively */ +static char *prompt; + +/* Buffer used for reading command lines, and the size + allocated for it so far. */ + +char *line; +int linesize = 100; + +/* Nonzero if the current command is modified by "server ". This + affects things like recording into the command history, comamnds + repeating on RETURN, etc. This is so a user interface (emacs, GUI, + whatever) can issue its own commands and also send along commands + from the user, and have the user not notice that the user interface + is issuing commands too. */ +int server_command; + +/* Baud rate specified for talking to serial target systems. Default + is left as -1, so targets can choose their own defaults. */ +/* FIXME: This means that "show remotebaud" and gr_files_info can print -1 + or (unsigned int)-1. This is a Bad User Interface. */ + +int baud_rate = -1; + +/* Non-zero tells remote* modules to output debugging info. */ + +int remote_debug = 0; + +/* Level of control structure. */ +static int control_level; + +/* Structure for arguments to user defined functions. */ +#define MAXUSERARGS 10 +struct user_args +{ + struct user_args *next; + struct + { + char *arg; + int len; + } a[MAXUSERARGS]; + int count; +} *user_args; + +/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */ + +#ifndef STOP_SIGNAL +#ifdef SIGTSTP +#define STOP_SIGNAL SIGTSTP +static void stop_sig PARAMS ((int)); +#endif +#endif + +/* Some System V have job control but not sigsetmask(). */ +#if !defined (HAVE_SIGSETMASK) +#if !defined (USG) +#define HAVE_SIGSETMASK 1 +#else +#define HAVE_SIGSETMASK 0 +#endif +#endif + +#if 0 == (HAVE_SIGSETMASK) +#define sigsetmask(n) +#endif + +/* Hooks for alternate command interfaces. */ + +/* Called after most modules have been initialized, but before taking users + command file. */ + +void (*init_ui_hook) PARAMS ((void)); + +/* Called instead of command_loop at top level. Can be invoked via + return_to_top_level. */ + +void (*command_loop_hook) PARAMS ((void)); + + +/* Called instead of fputs for all output. */ + +void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, FILE *stream)); + +/* Called when the target says something to the host, which may + want to appear in a different window. */ + +void (*target_output_hook) PARAMS ((char *)); + +/* Called from print_frame_info to list the line we stopped in. */ + +void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, int line, + int stopline, int noerror)); +/* Replaces most of query. */ + +int (*query_hook) PARAMS (()); + +/* Called from gdb_flush to flush output. */ + +void (*flush_hook) PARAMS ((FILE *stream)); + +/* Called as appropriate to notify the interface of the specified breakpoint + conditions. */ + +void (*create_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); +void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); +void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); + +/* Called during long calculations to allow GUI to repair window damage, and to + check for stop buttons, etc... */ + +void (*interactive_hook) PARAMS ((void)); + +/* Called when the registers have changed, as a hint to a GUI + to minimize window update. */ + +void (*registers_changed_hook) PARAMS ((void)); + +/* Called when going to wait for the target. Usually allows the GUI to run + while waiting for target events. */ + +int (*target_wait_hook) PARAMS ((int pid, struct target_waitstatus *status)); + +/* Used by UI as a wrapper around command execution. May do various things + like enabling/disabling buttons, etc... */ + +void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd, + int from_tty)); + + +/* Takes control from error (). Typically used to prevent longjmps out of the + middle of the GUI. Usually used in conjunction with a catch routine. */ + +NORETURN void (*error_hook) PARAMS (()) ATTR_NORETURN; + + +/* Where to go for return_to_top_level (RETURN_ERROR). */ +jmp_buf error_return; +/* Where to go for return_to_top_level (RETURN_QUIT). */ +jmp_buf quit_return; + +/* Return for reason REASON. This generally gets back to the command + loop, but can be caught via catch_errors. */ + +NORETURN void +return_to_top_level (reason) + enum return_reason reason; +{ + quit_flag = 0; + immediate_quit = 0; + + /* Perhaps it would be cleaner to do this via the cleanup chain (not sure + I can think of a reason why that is vital, though). */ + bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */ + + disable_current_display (); + do_cleanups (ALL_CLEANUPS); + + if (annotation_level > 1) + switch (reason) + { + case RETURN_QUIT: + annotate_quit (); + break; + case RETURN_ERROR: + annotate_error (); + break; + } + + (NORETURN void) longjmp + (reason == RETURN_ERROR ? error_return : quit_return, 1); +} + +/* Call FUNC with arg ARGS, catching any errors. If there is no + error, return the value returned by FUNC. If there is an error, + print ERRSTRING, print the specific error message, then return + zero. + + Must not be called with immediate_quit in effect (bad things might + happen, say we got a signal in the middle of a memcpy to quit_return). + This is an OK restriction; with very few exceptions immediate_quit can + be replaced by judicious use of QUIT. + + MASK specifies what to catch; it is normally set to + RETURN_MASK_ALL, if for no other reason than that the code which + calls catch_errors might not be set up to deal with a quit which + isn't caught. But if the code can deal with it, it generally + should be RETURN_MASK_ERROR, unless for some reason it is more + useful to abort only the portion of the operation inside the + catch_errors. Note that quit should return to the command line + fairly quickly, even if some further processing is being done. */ + +int +catch_errors (func, args, errstring, mask) + int (*func) PARAMS ((char *)); + PTR args; + char *errstring; + return_mask mask; +{ + jmp_buf saved_error; + jmp_buf saved_quit; + jmp_buf tmp_jmp; + int val; + struct cleanup *saved_cleanup_chain; + char *saved_error_pre_print; + char *saved_quit_pre_print; + + saved_cleanup_chain = save_cleanups (); + saved_error_pre_print = error_pre_print; + saved_quit_pre_print = quit_pre_print; + + if (mask & RETURN_MASK_ERROR) + { + memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf)); + error_pre_print = errstring; + } + if (mask & RETURN_MASK_QUIT) + { + memcpy (saved_quit, quit_return, sizeof (jmp_buf)); + quit_pre_print = errstring; + } + + if (setjmp (tmp_jmp) == 0) + { + if (mask & RETURN_MASK_ERROR) + memcpy (error_return, tmp_jmp, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (quit_return, tmp_jmp, sizeof (jmp_buf)); + val = (*func) (args); + } + else + val = 0; + + restore_cleanups (saved_cleanup_chain); + + if (mask & RETURN_MASK_ERROR) + { + memcpy (error_return, saved_error, sizeof (jmp_buf)); + error_pre_print = saved_error_pre_print; + } + if (mask & RETURN_MASK_QUIT) + { + memcpy (quit_return, saved_quit, sizeof (jmp_buf)); + quit_pre_print = saved_quit_pre_print; + } + return val; +} + +/* Handler for SIGHUP. */ + +static void +disconnect (signo) +int signo; +{ + catch_errors (quit_cover, NULL, + "Could not kill the program being debugged", RETURN_MASK_ALL); + signal (SIGHUP, SIG_DFL); + kill (getpid (), SIGHUP); +} + +/* Just a little helper function for disconnect(). */ + +static int +quit_cover (s) +char *s; +{ + caution = 0; /* Throw caution to the wind -- we're exiting. + This prevents asking the user dumb questions. */ + quit_command((char *)0, 0); + return 0; +} + +/* Line number we are currently in in a file which is being sourced. */ +static int source_line_number; + +/* Name of the file we are sourcing. */ +static char *source_file_name; + +/* Buffer containing the error_pre_print used by the source stuff. + Malloc'd. */ +static char *source_error; +static int source_error_allocated; + +/* Something to glom on to the start of error_pre_print if source_file_name + is set. */ +static char *source_pre_error; + +/* Clean up on error during a "source" command (or execution of a + user-defined command). */ + +static void +source_cleanup (stream) + FILE *stream; +{ + /* Restore the previous input stream. */ + instream = stream; +} + +/* Read commands from STREAM. */ +void +read_command_file (stream) + FILE *stream; +{ + struct cleanup *cleanups; + + cleanups = make_cleanup (source_cleanup, instream); + instream = stream; + command_loop (); + do_cleanups (cleanups); +} + +extern void init_proc (); + +void (*pre_init_ui_hook) PARAMS ((void)); + +void +gdb_init () +{ + if (pre_init_ui_hook) + pre_init_ui_hook (); + + /* Run the init function of each source file */ + + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + current_directory = gdb_dirbuf; + + init_cmd_lists (); /* This needs to be done first */ + initialize_targets (); /* Setup target_terminal macros for utils.c */ + initialize_utils (); /* Make errors and warnings possible */ + initialize_all_files (); + init_main (); /* But that omits this file! Do it now */ + init_signals (); + + init_proc (); + + /* We need a default language for parsing expressions, so simple things like + "set width 0" won't fail if no language is explicitly set in a config file + or implicitly set by reading an executable during startup. */ + set_language (language_c); + expected_language = current_language; /* don't warn about the change. */ + + if (init_ui_hook) + init_ui_hook (); +} + +/* Allocate, initialize a new command line structure for one of the + control commands (if/while). */ + +static struct command_line * +build_command_line (type, args) + enum command_control_type type; + char *args; +{ + struct command_line *cmd; + + if (args == NULL) + error ("if/while commands require arguments.\n"); + + cmd = (struct command_line *)xmalloc (sizeof (struct command_line)); + cmd->next = NULL; + cmd->control_type = type; + + cmd->body_count = 1; + cmd->body_list + = (struct command_line **)xmalloc (sizeof (struct command_line *) + * cmd->body_count); + memset (cmd->body_list, 0, sizeof (struct command_line *) * cmd->body_count); + cmd->line = savestring (args, strlen (args)); + return cmd; +} + +/* Build and return a new command structure for the control commands + such as "if" and "while". */ + +static struct command_line * +get_command_line (type, arg) + enum command_control_type type; + char *arg; +{ + struct command_line *cmd; + struct cleanup *old_chain = NULL; + + /* Allocate and build a new command line structure. */ + cmd = build_command_line (type, arg); + + old_chain = make_cleanup (free_command_lines, &cmd); + + /* Read in the body of this command. */ + if (recurse_read_control_structure (cmd) == invalid_control) + { + warning ("error reading in control structure\n"); + do_cleanups (old_chain); + return NULL; + } + + discard_cleanups (old_chain); + return cmd; +} + +/* Recursively print a command (including full control structures). */ +void +print_command_line (cmd, depth) + struct command_line *cmd; + unsigned int depth; +{ + unsigned int i; + + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", gdb_stdout); + } + + /* A simple command, print it and return. */ + if (cmd->control_type == simple_control) + { + fputs_filtered (cmd->line, gdb_stdout); + fputs_filtered ("\n", gdb_stdout); + return; + } + + /* loop_continue to jump to the start of a while loop, print it + and return. */ + if (cmd->control_type == continue_control) + { + fputs_filtered ("loop_continue\n", gdb_stdout); + return; + } + + /* loop_break to break out of a while loop, print it and return. */ + if (cmd->control_type == break_control) + { + fputs_filtered ("loop_break\n", gdb_stdout); + return; + } + + /* A while command. Recursively print its subcommands before returning. */ + if (cmd->control_type == while_control) + { + struct command_line *list; + fputs_filtered ("while ", gdb_stdout); + fputs_filtered (cmd->line, gdb_stdout); + fputs_filtered ("\n", gdb_stdout); + list = *cmd->body_list; + while (list) + { + print_command_line (list, depth + 1); + list = list->next; + } + } + + /* An if command. Recursively print both arms before returning. */ + if (cmd->control_type == if_control) + { + fputs_filtered ("if ", gdb_stdout); + fputs_filtered (cmd->line, gdb_stdout); + fputs_filtered ("\n", gdb_stdout); + /* The true arm. */ + print_command_line (cmd->body_list[0], depth + 1); + + /* Show the false arm if it exists. */ + if (cmd->body_count == 2) + { + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", gdb_stdout); + } + fputs_filtered ("else\n", gdb_stdout); + print_command_line (cmd->body_list[1], depth + 1); + } + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", gdb_stdout); + } + fputs_filtered ("end\n", gdb_stdout); + } +} + +/* Execute the command in CMD. */ + +enum command_control_type +execute_control_command (cmd) + struct command_line *cmd; +{ + struct expression *expr; + struct command_line *current; + struct cleanup *old_chain = 0; + value_ptr val; + int loop; + enum command_control_type ret; + char *new_line; + + switch (cmd->control_type) + { + case simple_control: + /* A simple command, execute it and return. */ + new_line = insert_args (cmd->line); + if (!new_line) + return invalid_control; + old_chain = make_cleanup (free_current_contents, &new_line); + execute_command (new_line, 0); + ret = cmd->control_type; + break; + + case continue_control: + case break_control: + /* Return for "continue", and "break" so we can either + continue the loop at the top, or break out. */ + ret = cmd->control_type; + break; + + case while_control: + { + /* Parse the loop control expression for the while statement. */ + new_line = insert_args (cmd->line); + if (!new_line) + return invalid_control; + old_chain = make_cleanup (free_current_contents, &new_line); + expr = parse_expression (new_line); + make_cleanup (free_current_contents, &expr); + + ret = simple_control; + loop = 1; + + /* Keep iterating so long as the expression is true. */ + while (loop == 1) + { + /* Evaluate the expression. */ + val = evaluate_expression (expr); + + /* If the value is false, then break out of the loop. */ + if (!value_true (val)) + break; + + /* Execute the body of the while statement. */ + current = *cmd->body_list; + while (current) + { + ret = execute_control_command (current); + + /* If we got an error, or a "break" command, then stop + looping. */ + if (ret == invalid_control || ret == break_control) + { + loop = 0; + break; + } + + /* If we got a "continue" command, then restart the loop + at this point. */ + if (ret == continue_control) + break; + + /* Get the next statement. */ + current = current->next; + } + } + + /* Reset RET so that we don't recurse the break all the way down. */ + if (ret == break_control) + ret = simple_control; + + break; + } + + case if_control: + { + new_line = insert_args (cmd->line); + if (!new_line) + return invalid_control; + old_chain = make_cleanup (free_current_contents, &new_line); + /* Parse the conditional for the if statement. */ + expr = parse_expression (new_line); + make_cleanup (free_current_contents, &expr); + + current = NULL; + ret = simple_control; + + /* Evaluate the conditional. */ + val = evaluate_expression (expr); + + /* Choose which arm to take commands from based on the value of the + conditional expression. */ + if (value_true (val)) + current = *cmd->body_list; + else if (cmd->body_count == 2) + current = *(cmd->body_list + 1); + + /* Execute commands in the given arm. */ + while (current) + { + ret = execute_control_command (current); + + /* If we got an error, get out. */ + if (ret != simple_control) + break; + + /* Get the next statement in the body. */ + current = current->next; + } + + break; + } + + default: + warning ("Invalid control type in command structure."); + return invalid_control; + } + + if (old_chain) + do_cleanups (old_chain); + + return ret; +} + +/* "while" command support. Executes a body of statements while the + loop condition is nonzero. */ + +static void +while_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct command_line *command = NULL; + + control_level = 1; + command = get_command_line (while_control, arg); + + if (command == NULL) + return; + + execute_control_command (command); + free_command_lines (&command); +} + +/* "if" command support. Execute either the true or false arm depending + on the value of the if conditional. */ + +static void +if_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct command_line *command = NULL; + + control_level = 1; + command = get_command_line (if_control, arg); + + if (command == NULL) + return; + + execute_control_command (command); + free_command_lines (&command); +} + +/* Cleanup */ +static void +arg_cleanup () +{ + struct user_args *oargs = user_args; + if (!user_args) + fatal ("Internal error, arg_cleanup called with no user args.\n"); + + user_args = user_args->next; + free (oargs); +} + +/* Bind the incomming arguments for a user defined command to + $arg0, $arg1 ... $argMAXUSERARGS. */ + +static struct cleanup * +setup_user_args (p) + char *p; +{ + struct user_args *args; + struct cleanup *old_chain; + unsigned int arg_count = 0; + + args = (struct user_args *)xmalloc (sizeof (struct user_args)); + memset (args, 0, sizeof (struct user_args)); + + args->next = user_args; + user_args = args; + + old_chain = make_cleanup (arg_cleanup, 0); + + if (p == NULL) + return old_chain; + + while (*p) + { + char *start_arg; + + if (arg_count >= MAXUSERARGS) + { + error ("user defined function may only have %d arguments.\n", + MAXUSERARGS); + return old_chain; + } + + /* Strip whitespace. */ + while (*p == ' ' || *p == '\t') + p++; + + /* P now points to an argument. */ + start_arg = p; + user_args->a[arg_count].arg = p; + + /* Get to the end of this argument. */ + while (*p && *p != ' ' && *p != '\t') + p++; + + user_args->a[arg_count].len = p - start_arg; + arg_count++; + user_args->count++; + } + return old_chain; +} + +/* Given character string P, return a point to the first argument ($arg), + or NULL if P contains no arguments. */ + +static char * +locate_arg (p) + char *p; +{ + while ((p = strchr (p, '$'))) + { + if (strncmp (p, "$arg", 4) == 0 && isdigit (p[4])) + return p; + p++; + } + return NULL; +} + +/* Insert the user defined arguments stored in user_arg into the $arg + arguments found in line, with the updated copy being placed into nline. */ + +static char * +insert_args (line) + char *line; +{ + char *p, *save_line, *new_line; + unsigned len, i; + + /* First we need to know how much memory to allocate for the new line. */ + save_line = line; + len = 0; + while ((p = locate_arg (line))) + { + len += p - line; + i = p[4] - '0'; + + if (i >= user_args->count) + { + error ("Missing argument %d in user function.\n", i); + return NULL; + } + len += user_args->a[i].len; + line = p + 5; + } + + /* Don't forget the tail. */ + len += strlen (line); + + /* Allocate space for the new line and fill it in. */ + new_line = (char *)xmalloc (len + 1); + if (new_line == NULL) + return NULL; + + /* Restore pointer to beginning of old line. */ + line = save_line; + + /* Save pointer to beginning of new line. */ + save_line = new_line; + + while ((p = locate_arg (line))) + { + int i, len; + + memcpy (new_line, line, p - line); + new_line += p - line; + i = p[4] - '0'; + + len = user_args->a[i].len; + if (len) + { + memcpy (new_line, user_args->a[i].arg, len); + new_line += len; + } + line = p + 5; + } + /* Don't forget the tail. */ + strcpy (new_line, line); + + /* Return a pointer to the beginning of the new line. */ + return save_line; +} + +void +execute_user_command (c, args) + struct cmd_list_element *c; + char *args; +{ + register struct command_line *cmdlines; + struct cleanup *old_chain; + enum command_control_type ret; + + old_chain = setup_user_args (args); + + cmdlines = c->user_commands; + if (cmdlines == 0) + /* Null command */ + return; + + /* Set the instream to 0, indicating execution of a + user-defined function. */ + old_chain = make_cleanup (source_cleanup, instream); + instream = (FILE *) 0; + while (cmdlines) + { + ret = execute_control_command (cmdlines); + if (ret != simple_control && ret != break_control) + { + warning ("Error in control structure.\n"); + break; + } + cmdlines = cmdlines->next; + } + do_cleanups (old_chain); +} + +/* Execute the line P as a command. + Pass FROM_TTY as second argument to the defining function. */ + +void +execute_command (p, from_tty) + char *p; + int from_tty; +{ + register struct cmd_list_element *c; + register enum language flang; + static int warned = 0; + extern FILE *serial_logfp; + + free_all_values (); + + /* This can happen when command_line_input hits end of file. */ + if (p == NULL) + return; + + if (serial_logfp != NULL) + serial_log_command (p); + + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + char *arg; + + c = lookup_cmd (&p, cmdlist, "", 0, 1); + /* Pass null arg rather than an empty one. */ + arg = *p ? p : 0; + + /* Clear off trailing whitespace, except for set and complete command. */ + if (arg && c->type != set_cmd && c->function.cfunc != complete_command) + { + p = arg + strlen (arg) - 1; + while (p >= arg && (*p == ' ' || *p == '\t')) + p--; + *(p + 1) = '\0'; + } + + /* If this command has been hooked, run the hook first. */ + if (c->hook) + execute_user_command (c->hook, (char *)0); + + if (c->class == class_user) + execute_user_command (c, arg); + else if (c->type == set_cmd || c->type == show_cmd) + do_setshow_command (arg, from_tty & caution, c); + else if (c->function.cfunc == NO_FUNCTION) + error ("That is not a command, just a help topic."); + else if (call_command_hook) + call_command_hook (c, arg, from_tty & caution); + else + (*c->function.cfunc) (arg, from_tty & caution); + } + + /* Tell the user if the language has changed (except first time). */ + if (current_language != expected_language) + { + if (language_mode == language_mode_auto) { + language_info (1); /* Print what changed. */ + } + warned = 0; + } + + /* Warn the user if the working language does not match the + language of the current frame. Only warn the user if we are + actually running the program, i.e. there is a stack. */ + /* FIXME: This should be cacheing the frame and only running when + the frame changes. */ + + if (target_has_stack) + { + flang = get_frame_language (); + if (!warned + && flang != language_unknown + && flang != current_language->la_language) + { + printf_filtered ("%s\n", lang_frame_mismatch_warn); + warned = 1; + } + } +} + +/* ARGSUSED */ +static void +command_loop_marker (foo) + int foo; +{ +} + +/* Read commands from `instream' and execute them + until end of file or error reading instream. */ + +void +command_loop () +{ + struct cleanup *old_chain; + char *command; + int stdin_is_tty = ISATTY (stdin); + long time_at_cmd_start; +#ifdef HAVE_SBRK + long space_at_cmd_start; +#endif + extern int display_time; + extern int display_space; + + while (!feof (instream)) + { + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + if (instream == stdin && stdin_is_tty) + reinitialize_more_filter (); + old_chain = make_cleanup (command_loop_marker, 0); + command = command_line_input (instream == stdin ? prompt : (char *) NULL, + instream == stdin, "prompt"); + if (command == 0) + return; + + time_at_cmd_start = get_run_time (); + + if (display_space) + { +#ifdef HAVE_SBRK + extern char **environ; + char *lim = (char *) sbrk (0); + + space_at_cmd_start = (long) (lim - (char *) &environ); +#endif + } + + execute_command (command, instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + + if (display_time) + { + long cmd_time = get_run_time () - time_at_cmd_start; + + printf_unfiltered ("Command execution time: %ld.%06ld\n", + cmd_time / 1000000, cmd_time % 1000000); + } + + if (display_space) + { +#ifdef HAVE_SBRK + extern char **environ; + char *lim = (char *) sbrk (0); + long space_now = lim - (char *) &environ; + long space_diff = space_now - space_at_cmd_start; + + printf_unfiltered ("Space used: %ld (%c%ld for this command)\n", + space_now, + (space_diff >= 0 ? '+' : '-'), + space_diff); +#endif + } + } +} + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + if (server_command) + return; + + /* If we aren't reading from standard input, we are saving the last + thing read from stdin in line and don't want to delete it. Null lines + won't repeat here in any case. */ + if (instream == stdin) + *line = 0; +} + +/* Read a line from the stream "instream" without command line editing. + + It prints PRROMPT once at the start. + Action is compatible with "readline", e.g. space for the result is + malloc'd and should be freed by the caller. + + A NULL return means end of file. */ +char * +gdb_readline (prrompt) + char *prrompt; +{ + int c; + char *result; + int input_index = 0; + int result_size = 80; + + if (prrompt) + { + /* Don't use a _filtered function here. It causes the assumed + character position to be off, since the newline we read from + the user is not accounted for. */ + fputs_unfiltered (prrompt, gdb_stdout); +#ifdef MPW + /* Move to a new line so the entered line doesn't have a prompt + on the front of it. */ + fputs_unfiltered ("\n", gdb_stdout); +#endif /* MPW */ + gdb_flush (gdb_stdout); + } + + result = (char *) xmalloc (result_size); + + while (1) + { + /* Read from stdin if we are executing a user defined command. + This is the right thing for prompt_for_continue, at least. */ + c = fgetc (instream ? instream : stdin); + + if (c == EOF) + { + if (input_index > 0) + /* The last line does not end with a newline. Return it, and + if we are called again fgetc will still return EOF and + we'll return NULL then. */ + break; + free (result); + return NULL; + } + + if (c == '\n') + break; + + result[input_index++] = c; + while (input_index >= result_size) + { + result_size *= 2; + result = (char *) xrealloc (result, result_size); + } + } + + result[input_index++] = '\0'; + return result; +} + +/* Variables which control command line editing and history + substitution. These variables are given default values at the end + of this file. */ +static int command_editing_p; +static int history_expansion_p; +static int write_history_p; +static int history_size; +static char *history_filename; + +/* readline uses the word breaks for two things: + (1) In figuring out where to point the TEXT parameter to the + rl_completion_entry_function. Since we don't use TEXT for much, + it doesn't matter a lot what the word breaks are for this purpose, but + it does affect how much stuff M-? lists. + (2) If one of the matches contains a word break character, readline + will quote it. That's why we switch between + gdb_completer_word_break_characters and + gdb_completer_command_word_break_characters. I'm not sure when + we need this behavior (perhaps for funky characters in C++ symbols?). */ + +/* Variables which are necessary for fancy command line editing. */ +char *gdb_completer_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-"; + +/* When completing on command names, we remove '-' from the list of + word break characters, since we use it in command names. If the + readline library sees one in any of the current completion strings, + it thinks that the string needs to be quoted and automatically supplies + a leading quote. */ +char *gdb_completer_command_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,"; + +/* Characters that can be used to quote completion strings. Note that we + can't include '"' because the gdb C parser treats such quoted sequences + as strings. */ +char *gdb_completer_quote_characters = + "'"; + +/* Functions that are used as part of the fancy command line editing. */ + +/* This can be used for functions which don't want to complete on symbols + but don't want to complete on anything else either. */ +/* ARGSUSED */ +char ** +noop_completer (text, prefix) + char *text; + char *prefix; +{ + return NULL; +} + +/* Complete on filenames. */ +char ** +filename_completer (text, word) + char *text; + char *word; +{ + /* From readline. */ + extern char *filename_completion_function (); + 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 *)); + + subsequent_name = 0; + while (1) + { + char *p; + p = 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; + } + /* Like emacs, don't complete on old versions. Especially useful + in the "source" command. */ + if (p[strlen (p) - 1] == '~') + continue; + + { + char *q; + if (word == text) + /* Return exactly p. */ + return_val[return_val_used++] = 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; + free (p); + } + else + { + /* Return some of TEXT plus p. */ + q = xmalloc (strlen (p) + (text - word) + 5); + strncpy (q, word, text - word); + q[text - word] = '\0'; + strcat (q, p); + return_val[return_val_used++] = q; + free (p); + } + } + subsequent_name = 1; + } +#if 0 + /* There is no way to do this just long enough to affect quote inserting + without also affecting the next completion. This should be fixed in + readline. FIXME. */ + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = ""; +#endif + return return_val; +} + +/* Here are some useful test cases for completion. FIXME: These should + be put in the test suite. They should be tested with both M-? and TAB. + + "show output-" "radix" + "show output" "-radix" + "p" ambiguous (commands starting with p--path, print, printf, etc.) + "p " ambiguous (all symbols) + "info t foo" no completions + "info t " no completions + "info t" ambiguous ("info target", "info terminal", etc.) + "info ajksdlfk" no completions + "info ajksdlfk " no completions + "info" " " + "info " ambiguous (all info commands) + "p \"a" no completions (string constant) + "p 'a" ambiguous (all symbols starting with a) + "p b-a" ambiguous (all symbols starting with a) + "p b-" ambiguous (all symbols) + "file Make" "file" (word break hard to screw up here) + "file ../gdb.stabs/we" "ird" (needs to not break word at slash) + */ + +/* Generate completions one by one for the completer. Each time we are + called return another potential completion to the caller. + line_completion just completes on commands or passes the buck to the + command's completer function, the stuff specific to symbol completion + is in make_symbol_completion_list. + + TEXT is the caller's idea of the "word" we are looking at. + + MATCHES is the number of matches that have currently been collected from + calling this completion function. When zero, then we need to initialize, + otherwise the initialization has already taken place and we can just + return the next potential completion string. + + LINE_BUFFER is available to be looked at; it contains the entire text + of the line. POINT is the offset in that line of the cursor. You + should pretend that the line ends at POINT. + + Returns NULL if there are no more completions, else a pointer to a string + which is a possible completion, it is the caller's responsibility to + free the string. */ + +static char * +line_completion_function (text, matches, line_buffer, point) + char *text; + int matches; + char *line_buffer; + int point; +{ + static char **list = (char **)NULL; /* Cache of completions */ + static int index; /* Next cached completion */ + char *output = NULL; + char *tmp_command, *p; + /* Pointer within tmp_command which corresponds to text. */ + char *word; + struct cmd_list_element *c, *result_list; + + if (matches == 0) + { + /* The caller is beginning to accumulate a new set of completions, so + we need to find all of them now, and cache them for returning one at + a time on future calls. */ + + if (list) + { + /* Free the storage used by LIST, but not by the strings inside. + This is because rl_complete_internal () frees the strings. */ + free ((PTR)list); + } + list = 0; + index = 0; + + /* Choose the default set of word break characters to break completions. + If we later find out that we are doing completions on command strings + (as opposed to strings supplied by the individual command completer + functions, which can be any string) then we will switch to the + special word break set for command strings, which leaves out the + '-' character used in some commands. */ + + rl_completer_word_break_characters = + gdb_completer_word_break_characters; + + /* Decide whether to complete on a list of gdb commands or on symbols. */ + tmp_command = (char *) alloca (point + 1); + p = tmp_command; + + strncpy (tmp_command, line_buffer, point); + tmp_command[point] = '\0'; + /* Since text always contains some number of characters leading up + to point, we can find the equivalent position in tmp_command + by subtracting that many characters from the end of tmp_command. */ + word = tmp_command + point - strlen (text); + + if (point == 0) + { + /* An empty line we want to consider ambiguous; that is, it + could be any command. */ + c = (struct cmd_list_element *) -1; + result_list = 0; + } + else + { + c = lookup_cmd_1 (&p, cmdlist, &result_list, 1); + } + + /* Move p up to the next interesting thing. */ + while (*p == ' ' || *p == '\t') + { + p++; + } + + if (!c) + { + /* It is an unrecognized command. So there are no + possible completions. */ + list = NULL; + } + else if (c == (struct cmd_list_element *) -1) + { + char *q; + + /* lookup_cmd_1 advances p up to the first ambiguous thing, but + doesn't advance over that thing itself. Do so now. */ + q = p; + while (*q && (isalnum (*q) || *q == '-' || *q == '_')) + ++q; + if (q != tmp_command + point) + { + /* There is something beyond the ambiguous + command, so there are no possible completions. For + example, "info t " or "info t foo" does not complete + to anything, because "info t" can be "info target" or + "info terminal". */ + list = NULL; + } + else + { + /* We're trying to complete on the command which was ambiguous. + This we can deal with. */ + if (result_list) + { + list = complete_on_cmdlist (*result_list->prefixlist, p, + word); + } + else + { + list = complete_on_cmdlist (cmdlist, p, word); + } + /* Insure that readline does the right thing with respect to + inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* We've recognized a full command. */ + + if (p == tmp_command + point) + { + /* There is no non-whitespace in the line beyond the command. */ + + if (p[-1] == ' ' || p[-1] == '\t') + { + /* The command is followed by whitespace; we need to complete + on whatever comes after command. */ + if (c->prefixlist) + { + /* It is a prefix command; what comes after it is + a subcommand (e.g. "info "). */ + list = complete_on_cmdlist (*c->prefixlist, p, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + else if (c->enums) + { + list = complete_on_enum (c->enums, p, word); + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + else + { + /* It is a normal command; what comes after it is + completed by the command's completer function. */ + list = (*c->completer) (p, word); + } + } + else + { + /* The command is not followed by whitespace; we need to + complete on the command itself. e.g. "p" which is a + command itself but also can complete to "print", "ptype" + etc. */ + char *q; + + /* Find the command we are completing on. */ + q = p; + while (q > tmp_command) + { + if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_') + --q; + else + break; + } + + list = complete_on_cmdlist (result_list, q, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* There is non-whitespace beyond the command. */ + + if (c->prefixlist && !c->allow_unknown) + { + /* It is an unrecognized subcommand of a prefix command, + e.g. "info adsfkdj". */ + list = NULL; + } + else if (c->enums) + { + list = complete_on_enum (c->enums, p, word); + } + else + { + /* It is a normal command. */ + list = (*c->completer) (p, word); + } + } + } + } + + /* 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. */ + + if (list) + { + output = list[index]; + if (output) + { + index++; + } + } + +#if 0 + /* Can't do this because readline hasn't yet checked the word breaks + for figuring out whether to insert a quote. */ + if (output == NULL) + /* Make sure the word break characters are set back to normal for the + next time that readline tries to complete something. */ + rl_completer_word_break_characters = + gdb_completer_word_break_characters; +#endif + + return (output); +} + +/* Line completion interface function for readline. */ + +static char * +readline_line_completion_function (text, matches) + char *text; + int matches; +{ + return line_completion_function (text, matches, rl_line_buffer, rl_point); +} + +/* Skip over a possibly quoted word (as defined by the quote characters + and word break characters the completer uses). Returns pointer to the + location after the "word". */ + +char * +skip_quoted (str) + char *str; +{ + char quote_char = '\0'; + char *scan; + + for (scan = str; *scan != '\0'; scan++) + { + if (quote_char != '\0') + { + /* Ignore everything until the matching close quote char */ + if (*scan == quote_char) + { + /* Found matching close quote. */ + scan++; + break; + } + } + else if (strchr (gdb_completer_quote_characters, *scan)) + { + /* Found start of a quoted string. */ + quote_char = *scan; + } + else if (strchr (gdb_completer_word_break_characters, *scan)) + { + break; + } + } + return (scan); +} + + +#ifdef STOP_SIGNAL +static void +stop_sig (signo) +int signo; +{ +#if STOP_SIGNAL == SIGTSTP + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); +#else + signal (STOP_SIGNAL, stop_sig); +#endif + printf_unfiltered ("%s", prompt); + gdb_flush (gdb_stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + dont_repeat (); +} +#endif /* STOP_SIGNAL */ + +/* Initialize signal handlers. */ +static void +do_nothing (signo) +int signo; +{ +} + +static void +init_signals () +{ + signal (SIGINT, request_quit); + + /* If SIGTRAP was set to SIG_IGN, then the SIG_IGN will get passed + to the inferior and breakpoints will be ignored. */ +#ifdef SIGTRAP + signal (SIGTRAP, SIG_DFL); +#endif + + /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get + passed to the inferior, which we don't want. It would be + possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but + on BSD4.3 systems using vfork, that can affect the + GDB process as well as the inferior (the signal handling tables + might be in memory, shared between the two). Since we establish + a handler for SIGQUIT, when we call exec it will set the signal + to SIG_DFL for us. */ + signal (SIGQUIT, do_nothing); + if (signal (SIGHUP, do_nothing) != SIG_IGN) + signal (SIGHUP, disconnect); + signal (SIGFPE, float_handler); + +#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) + signal (SIGWINCH, SIGWINCH_HANDLER); +#endif +} + +/* Read one line from the command input stream `instream' + into the local static buffer `linebuffer' (whose current length + is `linelength'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. + + NULL is returned for end of file. + + *If* the instream == stdin & stdin is a terminal, the line read + is copied into the file line saver (global var char *line, + length linesize) so that it can be duplicated. + + This routine either uses fancy command line editing or + simple input as the user has requested. */ + +char * +command_line_input (prrompt, repeat, annotation_suffix) + char *prrompt; + int repeat; + char *annotation_suffix; +{ + static char *linebuffer = 0; + static unsigned linelength = 0; + register char *p; + char *p1; + char *rl; + char *local_prompt = prrompt; + char *nline; + char got_eof = 0; + + /* The annotation suffix must be non-NULL. */ + if (annotation_suffix == NULL) + annotation_suffix = ""; + + if (annotation_level > 1 && instream == stdin) + { + local_prompt = alloca ((prrompt == NULL ? 0 : strlen (prrompt)) + + strlen (annotation_suffix) + 40); + if (prrompt == NULL) + local_prompt[0] = '\0'; + else + strcpy (local_prompt, prrompt); + strcat (local_prompt, "\n\032\032"); + strcat (local_prompt, annotation_suffix); + strcat (local_prompt, "\n"); + } + + if (linebuffer == 0) + { + linelength = 80; + linebuffer = (char *) xmalloc (linelength); + } + + p = linebuffer; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, stop_sig); +#endif + + while (1) + { + /* Make sure that all output has been output. Some machines may let + you get away with leaving out some of the gdb_flush, but not all. */ + wrap_here (""); + gdb_flush (gdb_stdout); + gdb_flush (gdb_stderr); + + if (source_file_name != NULL) + { + ++source_line_number; + sprintf (source_error, + "%s%s:%d: Error in sourced command file:\n", + source_pre_error, + source_file_name, + source_line_number); + error_pre_print = source_error; + } + + if (annotation_level > 1 && instream == stdin) + { + printf_unfiltered ("\n\032\032pre-"); + printf_unfiltered (annotation_suffix); + printf_unfiltered ("\n"); + } + + /* Don't use fancy stuff if not talking to stdin. */ + if (command_editing_p && instream == stdin + && ISATTY (instream)) + rl = readline (local_prompt); + else + rl = gdb_readline (local_prompt); + + if (annotation_level > 1 && instream == stdin) + { + printf_unfiltered ("\n\032\032post-"); + printf_unfiltered (annotation_suffix); + printf_unfiltered ("\n"); + } + + if (!rl || rl == (char *) EOF) + { + got_eof = 1; + break; + } + if (strlen(rl) + 1 + (p - linebuffer) > linelength) + { + linelength = strlen(rl) + 1 + (p - linebuffer); + nline = (char *) xrealloc (linebuffer, linelength); + p += nline - linebuffer; + linebuffer = nline; + } + p1 = rl; + /* Copy line. Don't copy null at end. (Leaves line alone + if this was just a newline) */ + while (*p1) + *p++ = *p1++; + + free (rl); /* Allocated in readline. */ + + if (p == linebuffer || *(p - 1) != '\\') + break; + + p--; /* Put on top of '\'. */ + local_prompt = (char *) 0; + } + +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, SIG_DFL); +#endif + immediate_quit--; + + if (got_eof) + return NULL; + +#define SERVER_COMMAND_LENGTH 7 + server_command = + (p - linebuffer > SERVER_COMMAND_LENGTH) + && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH); + if (server_command) + { + /* Note that we don't set `line'. Between this and the check in + dont_repeat, this insures that repeating will still do the + right thing. */ + *p = '\0'; + return linebuffer + SERVER_COMMAND_LENGTH; + } + + /* Do history expansion if that is wished. */ + if (history_expansion_p && instream == stdin + && ISATTY (instream)) + { + char *history_value; + int expanded; + + *p = '\0'; /* Insert null now. */ + expanded = history_expand (linebuffer, &history_value); + if (expanded) + { + /* Print the changes. */ + printf_unfiltered ("%s\n", history_value); + + /* If there was an error, call this function again. */ + if (expanded < 0) + { + free (history_value); + return command_line_input (prrompt, repeat, annotation_suffix); + } + if (strlen (history_value) > linelength) + { + linelength = strlen (history_value) + 1; + linebuffer = (char *) xrealloc (linebuffer, linelength); + } + strcpy (linebuffer, history_value); + p = linebuffer + strlen(linebuffer); + free (history_value); + } + } + + /* If we just got an empty line, and that is supposed + to repeat the previous command, return the value in the + global buffer. */ + if (repeat && p == linebuffer) + return line; + for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++) ; + if (repeat && !*p1) + return line; + + *p = 0; + + /* Add line to history if appropriate. */ + if (instream == stdin + && ISATTY (stdin) && *linebuffer) + add_history (linebuffer); + + /* Note: lines consisting solely of comments are added to the command + history. This is useful when you type a command, and then + realize you don't want to execute it quite yet. You can comment + out the command and then later fetch it from the value history + and remove the '#'. The kill ring is probably better, but some + people are in the habit of commenting things out. */ + if (*p1 == '#') + *p1 = '\0'; /* Found a comment. */ + + /* Save into global buffer if appropriate. */ + if (repeat) + { + if (linelength > linesize) + { + line = xrealloc (line, linelength); + linesize = linelength; + } + strcpy (line, linebuffer); + return line; + } + + return linebuffer; +} + + +/* Expand the body_list of COMMAND so that it can hold NEW_LENGTH + code bodies. This is typically used when we encounter an "else" + clause for an "if" command. */ + +static void +realloc_body_list (command, new_length) + struct command_line *command; + int new_length; +{ + int n; + struct command_line **body_list; + + n = command->body_count; + + /* Nothing to do? */ + if (new_length <= n) + return; + + body_list = (struct command_line **) + xmalloc (sizeof (struct command_line *) * new_length); + + memcpy (body_list, command->body_list, sizeof (struct command_line *) * n); + + free (command->body_list); + command->body_list = body_list; + command->body_count = new_length; +} + +/* Read one line from the input stream. If the command is an "else" or + "end", return such an indication to the caller. */ + +static enum misc_command_type +read_next_line (command) + struct command_line **command; +{ + char *p, *p1, *prompt_ptr, control_prompt[256]; + int i = 0; + + if (control_level >= 254) + error ("Control nesting too deep!\n"); + + /* Set a prompt based on the nesting of the control commands. */ + if (instream == stdin) + { + for (i = 0; i < control_level; i++) + control_prompt[i] = ' '; + control_prompt[i] = '>'; + control_prompt[i+1] = '\0'; + prompt_ptr = (char *)&control_prompt[0]; + } + else + prompt_ptr = NULL; + + p = command_line_input (prompt_ptr, instream == stdin, "commands"); + + /* Not sure what to do here. */ + if (p == NULL) + return end_command; + + /* Strip leading and trailing whitespace. */ + while (*p == ' ' || *p == '\t') + p++; + + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) + p1--; + + /* Blanks and comments don't really do anything, but we need to + distinguish them from else, end and other commands which can be + executed. */ + if (p1 == p || p[0] == '#') + return nop_command; + + /* Is this the end of a simple, while, or if control structure? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + return end_command; + + /* Is the else clause of an if control structure? */ + if (p1 - p == 4 && !strncmp (p, "else", 4)) + return else_command; + + /* Check for while, if, break, continue, etc and build a new command + line structure for them. */ + if (p1 - p > 5 && !strncmp (p, "while", 5)) + *command = build_command_line (while_control, p + 6); + else if (p1 - p > 2 && !strncmp (p, "if", 2)) + *command = build_command_line (if_control, p + 3); + else if (p1 - p == 5 && !strncmp (p, "loop_break", 5)) + { + *command = (struct command_line *) + xmalloc (sizeof (struct command_line)); + (*command)->next = NULL; + (*command)->line = NULL; + (*command)->control_type = break_control; + (*command)->body_count = 0; + (*command)->body_list = NULL; + } + else if (p1 - p == 8 && !strncmp (p, "loop_continue", 8)) + { + *command = (struct command_line *) + xmalloc (sizeof (struct command_line)); + (*command)->next = NULL; + (*command)->line = NULL; + (*command)->control_type = continue_control; + (*command)->body_count = 0; + (*command)->body_list = NULL; + } + else + { + /* A normal command. */ + *command = (struct command_line *) + xmalloc (sizeof (struct command_line)); + (*command)->next = NULL; + (*command)->line = savestring (p, p1 - p); + (*command)->control_type = simple_control; + (*command)->body_count = 0; + (*command)->body_list = NULL; + } + + /* Nothing special. */ + return ok_command; +} + +/* Recursively read in the control structures and create a command_line + tructure from them. + + The parent_control parameter is the control structure in which the + following commands are nested. */ + +static enum command_control_type +recurse_read_control_structure (current_cmd) + struct command_line *current_cmd; +{ + int current_body, i; + enum misc_command_type val; + enum command_control_type ret; + struct command_line **body_ptr, *child_tail, *next; + + child_tail = NULL; + current_body = 1; + + /* Sanity checks. */ + if (current_cmd->control_type == simple_control) + { + error ("Recursed on a simple control type\n"); + return invalid_control; + } + + if (current_body > current_cmd->body_count) + { + error ("Allocated body is smaller than this command type needs\n"); + return invalid_control; + } + + /* Read lines from the input stream and build control structures. */ + while (1) + { + dont_repeat (); + + next = NULL; + val = read_next_line (&next); + + /* Just skip blanks and comments. */ + if (val == nop_command) + continue; + + if (val == end_command) + { + if (current_cmd->control_type == while_control + || current_cmd->control_type == if_control) + { + /* Success reading an entire control structure. */ + ret = simple_control; + break; + } + else + { + ret = invalid_control; + break; + } + } + + /* Not the end of a control structure. */ + if (val == else_command) + { + if (current_cmd->control_type == if_control + && current_body == 1) + { + realloc_body_list (current_cmd, 2); + current_body = 2; + child_tail = NULL; + continue; + } + else + { + ret = invalid_control; + break; + } + } + + if (child_tail) + { + child_tail->next = next; + } + else + { + body_ptr = current_cmd->body_list; + for (i = 1; i < current_body; i++) + body_ptr++; + + *body_ptr = next; + + } + + child_tail = next; + + /* If the latest line is another control structure, then recurse + on it. */ + if (next->control_type == while_control + || next->control_type == if_control) + { + control_level++; + ret = recurse_read_control_structure (next); + control_level--; + + if (ret != simple_control) + break; + } + } + + dont_repeat (); + + return ret; +} + + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *head, *tail, *next; + struct cleanup *old_chain; + enum command_control_type ret; + enum misc_command_type val; + + head = tail = NULL; + old_chain = NULL; + + while (1) + { + val = read_next_line (&next); + + /* Ignore blank lines or comments. */ + if (val == nop_command) + continue; + + if (val == end_command) + { + ret = simple_control; + break; + } + + if (val != ok_command) + { + ret = invalid_control; + break; + } + + if (next->control_type == while_control + || next->control_type == if_control) + { + control_level++; + ret = recurse_read_control_structure (next); + control_level--; + + if (ret == invalid_control) + break; + } + + if (tail) + { + tail->next = next; + } + else + { + head = next; + old_chain = make_cleanup (free_command_lines, &head); + } + tail = next; + } + + dont_repeat (); + + if (head) + { + if (ret != invalid_control) + { + discard_cleanups (old_chain); + return head; + } + else + do_cleanups (old_chain); + } + + return NULL; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + struct command_line **blist; + int i; + + while (l) + { + if (l->body_count > 0) + { + blist = l->body_list; + for (i = 0; i < l->body_count; i++, blist++) + free_command_lines (blist); + } + next = l->next; + free (l->line); + free ((PTR)l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, no_class, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +/* ARGSUSED */ +static void +info_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"info\" must be followed by the name of an info command.\n"); + help_list (infolist, "info ", -1, gdb_stdout); +} + +/* The "complete" command is used by Emacs to implement completion. */ + +/* ARGSUSED */ +static void +complete_command (arg, from_tty) + char *arg; + int from_tty; +{ + int i; + int argpoint; + char *completion; + + dont_repeat (); + + if (arg == NULL) + arg = ""; + argpoint = strlen (arg); + + for (completion = line_completion_function (arg, i = 0, arg, argpoint); + completion; + completion = line_completion_function (arg, ++i, arg, argpoint)) + { + printf_unfiltered ("%s\n", completion); + free (completion); + } +} + +/* The "show" command with no arguments shows all the settings. */ + +/* ARGSUSED */ +static void +show_command (arg, from_tty) + char *arg; + int from_tty; +{ + cmd_show_list (showlist, from_tty, ""); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, class, fun, doc, &cmdlist); +} + +/* Add an alias or abbreviation command to the list of commands. */ + +void +add_com_alias (name, oldname, class, abbrev_flag) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); +} + +void +error_no_arg (why) + char *why; +{ + error ("Argument required (%s).", why); +} + +/* ARGSUSED */ +static void +help_command (command, from_tty) + char *command; + int from_tty; /* Ignored */ +{ + help_cmd (command, gdb_stdout); +} + +static void +validate_comname (comname) + char *comname; +{ + register char *p; + + if (comname == 0) + error_no_arg ("name of command to define"); + + p = comname; + while (*p) + { + if (!isalnum(*p) && *p != '-' && *p != '_') + error ("Junk in argument list: \"%s\"", p); + p++; + } +} + +/* This is just a placeholder in the command data structures. */ +static void +user_defined_command (ignore, from_tty) + char *ignore; + int from_tty; +{ +} + +static void +define_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct command_line *cmds; + register struct cmd_list_element *c, *newc, *hookc = 0; + char *tem = comname; +#define HOOK_STRING "hook-" +#define HOOK_LEN 5 + + validate_comname (comname); + + /* Look it up, and verify that we got an exact match. */ + c = lookup_cmd (&tem, cmdlist, "", -1, 1); + if (c && !STREQ (comname, c->name)) + c = 0; + + if (c) + { + if (c->class == class_user || c->class == class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, c->name)) + error ("Command \"%s\" not redefined.", c->name); + } + + /* If this new command is a hook, then mark the command which it + is hooking. Note that we allow hooking `help' commands, so that + we can hook the `stop' pseudo-command. */ + + if (!strncmp (comname, HOOK_STRING, HOOK_LEN)) + { + /* Look up cmd it hooks, and verify that we got an exact match. */ + tem = comname+HOOK_LEN; + hookc = lookup_cmd (&tem, cmdlist, "", -1, 0); + if (hookc && !STREQ (comname+HOOK_LEN, hookc->name)) + hookc = 0; + if (!hookc) + { + warning ("Your new `%s' command does not hook any existing command.", + comname); + if (!query ("Proceed? ")) + error ("Not confirmed."); + } + } + + comname = savestring (comname, strlen (comname)); + + /* If the rest of the commands will be case insensitive, this one + should behave in the same manner. */ + for (tem = comname; *tem; tem++) + if (isupper(*tem)) *tem = tolower(*tem); + + if (from_tty) + { + printf_unfiltered ("Type commands for definition of \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + gdb_flush (gdb_stdout); + } + + control_level = 0; + cmds = read_command_lines (); + + if (c && c->class == class_user) + free_command_lines (&c->user_commands); + + newc = add_cmd (comname, class_user, user_defined_command, + (c && c->class == class_user) + ? c->doc : savestring ("User-defined.", 13), &cmdlist); + newc->user_commands = cmds; + + /* If this new command is a hook, then mark both commands as being + tied. */ + if (hookc) + { + hookc->hook = newc; /* Target gets hooked. */ + newc->hookee = hookc; /* We are marked as hooking target cmd. */ + } +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0, 1); + + if (c->class != class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf_unfiltered ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +void +print_gnu_advertisement () +{ + printf_unfiltered ("\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"show copying\" to see the conditions.\n\ +There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\ +"); +} + +void +print_gdb_version (stream) + GDB_FILE *stream; +{ + fprintf_filtered (stream, "\ +GDB %s (%s", version, host_name); + + if (!STREQ (host_name, target_name)) + fprintf_filtered (stream, " --target %s", target_name); + + fprintf_filtered (stream, "), "); + wrap_here(""); + fprintf_filtered (stream, "Copyright 1996 Free Software Foundation, Inc."); +} + +/* ARGSUSED */ +static void +show_version (args, from_tty) + char *args; + int from_tty; +{ + immediate_quit++; + print_gnu_advertisement (); + print_gdb_version (gdb_stdout); + printf_filtered ("\n"); + immediate_quit--; +} + +/* xgdb calls this to reprint the usual GDB prompt. Obsolete now that xgdb + is obsolete. */ + +void +print_prompt () +{ + printf_unfiltered ("%s", prompt); + gdb_flush (gdb_stdout); +} + +void +quit_command (args, from_tty) + char *args; + int from_tty; +{ + int exit_code = 0; + + /* An optional expression may be used to cause gdb to terminate with the + value of that expression. */ + if (args) + { + value_ptr val = parse_and_eval (args); + + exit_code = (int) value_as_long (val); + } + + if (inferior_pid != 0 && target_has_execution) + { + if (attach_flag) + { + if (query ("The program is running. Quit anyway (and detach it)? ")) + target_detach (args, from_tty); + else + error ("Not confirmed."); + } + else + { + if (query ("The program is running. Quit anyway (and kill it)? ")) + target_kill (); + else + error ("Not confirmed."); + } + } + /* UDI wants this, to kill the TIP. */ + target_close (1); + + /* Save the history information if it is appropriate to do so. */ + if (write_history_p && history_filename) + write_history (history_filename); + + exit (exit_code); +} + +/* Returns whether GDB is running on a terminal and whether the user + desires that questions be asked of them on that terminal. */ + +int +input_from_terminal_p () +{ + return gdb_has_a_terminal () && (instream == stdin) & caution; +} + +/* ARGSUSED */ +static void +pwd_command (args, from_tty) + char *args; + int from_tty; +{ + if (args) error ("The \"pwd\" command does not take an argument: %s", args); + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + + if (!STREQ (gdb_dirbuf, current_directory)) + printf_unfiltered ("Working directory %s\n (canonically %s).\n", + current_directory, gdb_dirbuf); + else + printf_unfiltered ("Working directory %s.\n", current_directory); +} + +void +cd_command (dir, from_tty) + char *dir; + int from_tty; +{ + int len; + /* Found something other than leading repetitions of "/..". */ + int found_real_path; + char *p; + + /* If the new directory is absolute, repeat is a no-op; if relative, + repeat might be useful but is more likely to be a mistake. */ + dont_repeat (); + + if (dir == 0) + error_no_arg ("new working directory"); + + dir = tilde_expand (dir); + make_cleanup (free, dir); + + if (chdir (dir) < 0) + perror_with_name (dir); + + len = strlen (dir); + dir = savestring (dir, len - (len > 1 && SLASH_P(dir[len-1]))); + if (ROOTED_P(dir)) + current_directory = dir; + else + { + if (SLASH_P (current_directory[0]) && current_directory[1] == '\0') + current_directory = concat (current_directory, dir, NULL); + else + current_directory = concat (current_directory, SLASH_STRING, dir, NULL); + free (dir); + } + + /* Now simplify any occurrences of `.' and `..' in the pathname. */ + + found_real_path = 0; + for (p = current_directory; *p;) + { + if (SLASH_P (p[0]) && p[1] == '.' && (p[2] == 0 || SLASH_P (p[2]))) + strcpy (p, p + 2); + else if (SLASH_P (p[0]) && p[1] == '.' && p[2] == '.' + && (p[3] == 0 || SLASH_P (p[3]))) + { + if (found_real_path) + { + /* Search backwards for the directory just before the "/.." + and obliterate it and the "/..". */ + char *q = p; + while (q != current_directory && ! SLASH_P (q[-1])) + --q; + + if (q == current_directory) + /* current_directory is + a relative pathname ("can't happen"--leave it alone). */ + ++p; + else + { + strcpy (q - 1, p + 3); + p = q - 1; + } + } + else + /* We are dealing with leading repetitions of "/..", for example + "/../..", which is the Mach super-root. */ + p += 3; + } + else + { + found_real_path = 1; + ++p; + } + } + + forget_cached_source_info (); + + if (from_tty) + pwd_command ((char *) 0, 1); +} + +struct source_cleanup_lines_args { + int old_line; + char *old_file; + char *old_pre_error; + char *old_error_pre_print; +}; + +static void +source_cleanup_lines (args) + PTR args; +{ + struct source_cleanup_lines_args *p = + (struct source_cleanup_lines_args *)args; + source_line_number = p->old_line; + source_file_name = p->old_file; + source_pre_error = p->old_pre_error; + error_pre_print = p->old_error_pre_print; +} + +/* ARGSUSED */ +void +source_command (args, from_tty) + char *args; + int from_tty; +{ + FILE *stream; + struct cleanup *old_cleanups; + char *file = args; + struct source_cleanup_lines_args old_lines; + int needed_length; + + if (file == NULL) + { + error ("source command requires pathname of file to source."); + } + + file = tilde_expand (file); + old_cleanups = make_cleanup (free, file); + + stream = fopen (file, FOPEN_RT); + if (stream == 0) + perror_with_name (file); + + make_cleanup (fclose, stream); + + old_lines.old_line = source_line_number; + old_lines.old_file = source_file_name; + old_lines.old_pre_error = source_pre_error; + old_lines.old_error_pre_print = error_pre_print; + make_cleanup (source_cleanup_lines, &old_lines); + source_line_number = 0; + source_file_name = file; + source_pre_error = error_pre_print == NULL ? "" : error_pre_print; + source_pre_error = savestring (source_pre_error, strlen (source_pre_error)); + make_cleanup (free, source_pre_error); + /* This will get set every time we read a line. So it won't stay "" for + long. */ + error_pre_print = ""; + + needed_length = strlen (source_file_name) + strlen (source_pre_error) + 80; + if (source_error_allocated < needed_length) + { + source_error_allocated *= 2; + if (source_error_allocated < needed_length) + source_error_allocated = needed_length; + if (source_error == NULL) + source_error = xmalloc (source_error_allocated); + else + source_error = xrealloc (source_error, source_error_allocated); + } + + read_command_file (stream); + + do_cleanups (old_cleanups); +} + +/* ARGSUSED */ +static void +echo_command (text, from_tty) + char *text; + int from_tty; +{ + char *p = text; + register int c; + + if (text) + while ((c = *p++) != '\0') + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + return; + + c = parse_escape (&p); + if (c >= 0) + printf_filtered ("%c", c); + } + else + printf_filtered ("%c", c); + } + + /* Force this output to appear now. */ + wrap_here (""); + gdb_flush (gdb_stdout); +} + +/* ARGSUSED */ +static void +dont_repeat_command (ignored, from_tty) + char *ignored; + int from_tty; +{ + *line = 0; /* Can't call dont_repeat here because we're not + necessarily reading from stdin. */ +} + +#ifdef TARGET_BYTE_ORDER_SELECTABLE + +/* Functions to manipulate the endianness of the target. */ + +#ifndef TARGET_BYTE_ORDER_DEFAULT +#define TARGET_BYTE_ORDER_DEFAULT BIG_ENDIAN +#endif + +int target_byte_order = TARGET_BYTE_ORDER_DEFAULT; + +static int target_byte_order_auto = 1; + +/* Called if the user enters ``set endian'' without an argument. */ +static void +set_endian (args, from_tty) + char *args; + int from_tty; +{ + printf_unfiltered ("\"set endian\" must be followed by \"auto\", \"big\" or \"little\".\n"); + show_endian (args, from_tty); +} + +/* Called by ``set endian big''. */ +static void +set_endian_big (args, from_tty) + char *args; + int from_tty; +{ + target_byte_order = BIG_ENDIAN; + target_byte_order_auto = 0; +} + +/* Called by ``set endian little''. */ +static void +set_endian_little (args, from_tty) + char *args; + int from_tty; +{ + target_byte_order = LITTLE_ENDIAN; + target_byte_order_auto = 0; +} + +/* Called by ``set endian auto''. */ +static void +set_endian_auto (args, from_tty) + char *args; + int from_tty; +{ + target_byte_order_auto = 1; +} + +/* Called by ``show endian''. */ +static void +show_endian (args, from_tty) + char *args; + int from_tty; +{ + const char *msg = + (target_byte_order_auto + ? "The target endianness is set automatically (currently %s endian)\n" + : "The target is assumed to be %s endian\n"); + printf_unfiltered ((char *) msg, TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little"); +} + +#endif /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ + +/* Set the endianness from a BFD. */ +void +set_endian_from_file (abfd) + bfd *abfd; +{ +#ifdef TARGET_BYTE_ORDER_SELECTABLE + int want; + + if (bfd_big_endian (abfd)) + want = BIG_ENDIAN; + else + want = LITTLE_ENDIAN; + if (target_byte_order_auto) + target_byte_order = want; + else if (target_byte_order != want) + warning ("%s endian file does not match %s endian target.", + want == BIG_ENDIAN ? "big" : "little", + TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little"); + +#else /* ! defined (TARGET_BYTE_ORDER_SELECTABLE) */ + + if (bfd_big_endian (abfd) + ? TARGET_BYTE_ORDER != BIG_ENDIAN + : TARGET_BYTE_ORDER == BIG_ENDIAN) + warning ("%s endian file does not match %s endian target.", + bfd_big_endian (abfd) ? "big" : "little", + TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little"); + +#endif /* ! defined (TARGET_BYTE_ORDER_SELECTABLE) */ +} + +/* Functions to manipulate command line editing control variables. */ + +/* Number of commands to print in each call to show_commands. */ +#define Hist_print 10 +static void +show_commands (args, from_tty) + char *args; + int from_tty; +{ + /* Index for history commands. Relative to history_base. */ + int offset; + + /* Number of the history entry which we are planning to display next. + Relative to history_base. */ + static int num = 0; + + /* The first command in the history which doesn't exist (i.e. one more + than the number of the last command). Relative to history_base. */ + int hist_len; + + extern HIST_ENTRY *history_get PARAMS ((int)); + + /* Print out some of the commands from the command history. */ + /* First determine the length of the history list. */ + hist_len = history_size; + for (offset = 0; offset < history_size; offset++) + { + if (!history_get (history_base + offset)) + { + hist_len = offset; + break; + } + } + + if (args) + { + if (args[0] == '+' && args[1] == '\0') + /* "info editing +" should print from the stored position. */ + ; + else + /* "info editing " should print around command number . */ + num = (parse_and_eval_address (args) - history_base) - Hist_print / 2; + } + /* "show commands" means print the last Hist_print commands. */ + else + { + num = hist_len - Hist_print; + } + + if (num < 0) + num = 0; + + /* If there are at least Hist_print commands, we want to display the last + Hist_print rather than, say, the last 6. */ + if (hist_len - num < Hist_print) + { + num = hist_len - Hist_print; + if (num < 0) + num = 0; + } + + for (offset = num; offset < num + Hist_print && offset < hist_len; offset++) + { + printf_filtered ("%5d %s\n", history_base + offset, + (history_get (history_base + offset))->line); + } + + /* The next command we want to display is the next one that we haven't + displayed yet. */ + num += Hist_print; + + /* If the user repeats this command with return, it should do what + "show commands +" does. This is unnecessary if arg is null, + because "show commands +" is not useful after "show commands". */ + if (from_tty && args) + { + args[0] = '+'; + args[1] = '\0'; + } +} + +/* Called by do_setshow_command. */ +/* ARGSUSED */ +static void +set_history_size_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + if (history_size == INT_MAX) + unstifle_history (); + else if (history_size >= 0) + stifle_history (history_size); + else + { + history_size = INT_MAX; + error ("History size must be non-negative"); + } +} + +/* ARGSUSED */ +static void +set_history (args, from_tty) + char *args; + int from_tty; +{ + printf_unfiltered ("\"set history\" must be followed by the name of a history subcommand.\n"); + help_list (sethistlist, "set history ", -1, gdb_stdout); +} + +/* ARGSUSED */ +static void +show_history (args, from_tty) + char *args; + int from_tty; +{ + cmd_show_list (showhistlist, from_tty, ""); +} + +int info_verbose = 0; /* Default verbose msgs off */ + +/* Called by do_setshow_command. An elaborate joke. */ +/* ARGSUSED */ +static void +set_verbose (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + char *cmdname = "verbose"; + struct cmd_list_element *showcmd; + + showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1); + + if (info_verbose) + { + c->doc = "Set verbose printing of informational messages."; + showcmd->doc = "Show verbose printing of informational messages."; + } + else + { + c->doc = "Set verbosity."; + showcmd->doc = "Show verbosity."; + } +} + +static void +float_handler (signo) +int signo; +{ + /* This message is based on ANSI C, section 4.7. Note that integer + divide by zero causes this, so "float" is a misnomer. */ + signal (SIGFPE, float_handler); + error ("Erroneous arithmetic operation."); +} + + +static void +init_cmd_lists () +{ + cmdlist = NULL; + infolist = NULL; + enablelist = NULL; + disablelist = NULL; + deletelist = NULL; + enablebreaklist = NULL; + setlist = NULL; + unsetlist = NULL; + showlist = NULL; +#ifdef TARGET_BYTE_ORDER_SELECTABLE + endianlist = NULL; +#endif + sethistlist = NULL; + showhistlist = NULL; + unsethistlist = NULL; +#if MAINTENANCE_CMDS + maintenancelist = NULL; + maintenanceinfolist = NULL; + maintenanceprintlist = NULL; +#endif + setprintlist = NULL; + showprintlist = NULL; + setchecklist = NULL; + showchecklist = NULL; +} + +/* Init the history buffer. Note that we are called after the init file(s) + * have been read so that the user can change the history file via his + * .gdbinit file (for instance). The GDBHISTFILE environment variable + * overrides all of this. + */ + +void +init_history() +{ + char *tmpenv; + + tmpenv = getenv ("HISTSIZE"); + if (tmpenv) + history_size = atoi (tmpenv); + else if (!history_size) + history_size = 256; + + stifle_history (history_size); + + tmpenv = getenv ("GDBHISTFILE"); + if (tmpenv) + history_filename = savestring (tmpenv, strlen(tmpenv)); + else if (!history_filename) { + /* We include the current directory so that if the user changes + directories the file written will be the same as the one + that was read. */ + history_filename = concat (current_directory, "/.gdb_history", NULL); + } + read_history (history_filename); +} + +static void +init_main () +{ + struct cmd_list_element *c; + +#ifdef TARGET_BYTE_ORDER_SELECTABLE + + add_prefix_cmd ("endian", class_support, set_endian, + "Set endianness of target.", + &endianlist, "set endian ", 0, &setlist); + add_cmd ("big", class_support, set_endian_big, + "Set target as being big endian.", &endianlist); + add_cmd ("little", class_support, set_endian_little, + "Set target as being little endian.", &endianlist); + add_cmd ("auto", class_support, set_endian_auto, + "Select target endianness automatically.", &endianlist); + add_cmd ("endian", class_support, show_endian, + "Show endianness of target.", &showlist); + +#endif /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ + +#ifdef DEFAULT_PROMPT + prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); +#else + prompt = savestring ("(gdb) ", 6); +#endif + + /* Set the important stuff up for command editing. */ + command_editing_p = 1; + history_expansion_p = 0; + write_history_p = 0; + + /* Setup important stuff for command line editing. */ + rl_completion_entry_function = (int (*)()) readline_line_completion_function; + rl_completer_word_break_characters = gdb_completer_word_break_characters; + rl_completer_quote_characters = gdb_completer_quote_characters; + rl_readline_name = "gdb"; + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("internals", class_maintenance, NO_FUNCTION, + "Maintenance commands.\n\ +Some gdb commands are provided just for use by gdb maintainers.\n\ +These commands are subject to frequent change, and may not be as\n\ +well documented as user commands.", + &cmdlist); + add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist); + add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist); + add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + c = add_cmd ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started.", &cmdlist); + c->completer = filename_completer; + + add_show_from_set + (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt, + "Set gdb's prompt", + &setlist), + &showlist); + + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +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."); + +#ifdef __STDC__ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#else + /* Punt file name, we can't help it easily. */ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#endif + c->completer = filename_completer; + + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + add_com ("dont-repeat", class_support, dont_repeat_command, "Don't repeat this command.\n\ +Primarily used inside of user-defined commands that should not be repeated when\n\ +hitting return."); + + c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose, + "Set ", + &setlist), + add_show_from_set (c, &showlist); + c->function.sfunc = set_verbose; + set_verbose (NULL, 0, c); + + add_show_from_set + (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p, + "Set editing of command lines as they are typed.\n\ +Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\ +Without an argument, command line editing is enabled. To edit, use\n\ +EMACS-like or VI-like commands like control-P or ESC.", &setlist), + &showlist); + + add_prefix_cmd ("history", class_support, set_history, + "Generic command for setting command history parameters.", + &sethistlist, "set history ", 0, &setlist); + add_prefix_cmd ("history", class_support, show_history, + "Generic command for showing command history parameters.", + &showhistlist, "show history ", 0, &showlist); + + add_show_from_set + (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p, + "Set history expansion on command input.\n\ +Without an argument, history expansion is enabled.", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p, + "Set saving of the history record on exit.\n\ +Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\ +Without an argument, saving is enabled.", &sethistlist), + &showhistlist); + + c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size, + "Set the size of the command history, \n\ +ie. the number of previous commands to keep a record of.", &sethistlist); + add_show_from_set (c, &showhistlist); + c->function.sfunc = set_history_size_command; + + add_show_from_set + (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, + "Set the filename in which to record the command history\n\ + (the list of previous commands of which a record is kept).", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("confirm", class_support, var_boolean, + (char *)&caution, + "Set whether to confirm potentially dangerous operations.", + &setlist), + &showlist); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for showing things about the program being debugged.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_com ("complete", class_obscure, complete_command, + "List the completions for the rest of the line as a command."); + + add_prefix_cmd ("show", class_info, show_command, + "Generic command for showing things about the debugger.", + &showlist, "show ", 0, &cmdlist); + /* Another way to get at the same thing. */ + add_info ("set", show_command, "Show all GDB settings."); + + add_cmd ("commands", no_class, show_commands, + "Show the history of commands you typed.\n\ +You can supply a command number to start with, or a `+' to start after\n\ +the previous command number shown.", + &showlist); + + add_cmd ("version", no_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_show_from_set (add_set_cmd ("remotebaud", no_class, + var_zinteger, (char *)&baud_rate, + "Set baud rate for remote serial I/O.\n\ +This value is used to set the speed of the serial port when debugging\n\ +using remote targets.", &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("remotedebug", no_class, var_zinteger, (char *)&remote_debug, + "Set debugging of remote protocol.\n\ +When enabled, each packet sent or received with the remote target\n\ +is displayed.", &setlist), + &showlist); +} diff --git a/contrib/gdb/gdb/top.h b/contrib/gdb/gdb/top.h new file mode 100644 index 000000000000..661f4ef20deb --- /dev/null +++ b/contrib/gdb/gdb/top.h @@ -0,0 +1,48 @@ +/* Top level stuff for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* From top.c. */ +extern char *line; +extern int linesize; +extern FILE *instream; +extern char gdb_dirbuf[1024]; +extern int inhibit_gdbinit; +extern int epoch_interface; +extern char gdbinit[]; + +/* Generally one should use catch_errors rather than manipulating these + directly. The exception is main(). */ +extern jmp_buf error_return; +extern jmp_buf quit_return; + +extern void print_gdb_version PARAMS ((GDB_FILE *)); +extern void print_gnu_advertisement PARAMS ((void)); + +extern void source_command PARAMS ((char *, int)); +extern void cd_command PARAMS ((char *, int)); +extern void read_command_file PARAMS ((FILE *)); +extern void init_history PARAMS ((void)); +extern void command_loop PARAMS ((void)); +extern void quit_command PARAMS ((char *, int)); + +/* From random places. */ +extern int mapped_symbol_files; +extern int readnow_symbol_files; +#define ALL_CLEANUPS ((struct cleanup *)0) diff --git a/contrib/gdb/gdb/typeprint.c b/contrib/gdb/gdb/typeprint.c new file mode 100644 index 000000000000..6b1c6de1d196 --- /dev/null +++ b/contrib/gdb/gdb/typeprint.c @@ -0,0 +1,302 @@ +/* Language independent support for printing types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "command.h" +#include "gdbcmd.h" +#include "target.h" +#include "language.h" +#include "demangle.h" + +#include "gdb_string.h" +#include + +static void +ptype_command PARAMS ((char *, int)); + +static struct type * +ptype_eval PARAMS ((struct expression *)); + +static void +whatis_command PARAMS ((char *, int)); + +static void +whatis_exp PARAMS ((char *, int)); + +/* Print a description of a type TYPE in the form of a declaration of a + variable named VARSTRING. (VARSTRING is demangled if necessary.) + Output goes to STREAM (via stdio). + If SHOW is positive, we show the contents of the outermost level + of structure even if there is a type name that could be used instead. + If SHOW is negative, we never show the details of elements' types. */ + +void +type_print (type, varstring, stream, show) + struct type *type; + char *varstring; + GDB_FILE *stream; + int show; +{ + LA_PRINT_TYPE (type, varstring, stream, show, 0); +} + +/* Print type of EXP, or last thing in value history if EXP == NULL. + show is passed to type_print. */ + +static void +whatis_exp (exp, show) + char *exp; + int show; +{ + struct expression *expr; + register value_ptr val; + register struct cleanup *old_chain = NULL; + + if (exp) + { + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_type (expr); + } + else + val = access_value_history (0); + + printf_filtered ("type = "); + type_print (VALUE_TYPE (val), "", gdb_stdout, show); + printf_filtered ("\n"); + + if (exp) + do_cleanups (old_chain); +} + +/* ARGSUSED */ +static void +whatis_command (exp, from_tty) + char *exp; + int from_tty; +{ + /* Most of the time users do not want to see all the fields + in a structure. If they do they can use the "ptype" command. + Hence the "-1" below. */ + whatis_exp (exp, -1); +} + +/* Simple subroutine for ptype_command. */ + +static struct type * +ptype_eval (exp) + struct expression *exp; +{ + if (exp->elts[0].opcode == OP_TYPE) + { + return (exp->elts[1].type); + } + else + { + return (NULL); + } +} + +/* TYPENAME is either the name of a type, or an expression. */ + +/* ARGSUSED */ +static void +ptype_command (typename, from_tty) + char *typename; + int from_tty; +{ + register struct type *type; + struct expression *expr; + register struct cleanup *old_chain; + + if (typename == NULL) + { + /* Print type of last thing in value history. */ + whatis_exp (typename, 1); + } + else + { + expr = parse_expression (typename); + old_chain = make_cleanup (free_current_contents, &expr); + type = ptype_eval (expr); + if (type != NULL) + { + /* User did "ptype " */ + printf_filtered ("type = "); + type_print (type, "", gdb_stdout, 1); + printf_filtered ("\n"); + do_cleanups (old_chain); + } + else + { + /* User did "ptype " */ + do_cleanups (old_chain); + whatis_exp (typename, 1); + } + } +} + +/* Print integral scalar data VAL, of type TYPE, onto stdio stream STREAM. + Used to print data from type structures in a specified type. For example, + array bounds may be characters or booleans in some languages, and this + allows the ranges to be printed in their "natural" form rather than as + decimal integer values. + + FIXME: This is here simply because only the type printing routines + currently use it, and it wasn't clear if it really belonged somewhere + else (like printcmd.c). There are a lot of other gdb routines that do + something similar, but they are generally concerned with printing values + that come from the inferior in target byte order and target size. */ + +void +print_type_scalar (type, val, stream) + struct type *type; + LONGEST val; + GDB_FILE *stream; +{ + unsigned int i; + unsigned len; + + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + + case TYPE_CODE_ENUM: + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + if (TYPE_FIELD_BITPOS (type, i) == val) + { + break; + } + } + if (i < len) + { + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + + case TYPE_CODE_INT: + print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val); + break; + + case TYPE_CODE_CHAR: + LA_PRINT_CHAR ((unsigned char) val, stream); + break; + + case TYPE_CODE_BOOL: + fprintf_filtered (stream, val ? "TRUE" : "FALSE"); + break; + + case TYPE_CODE_RANGE: + print_type_scalar (TYPE_TARGET_TYPE (type), val, stream); + return; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_STRING: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_REF: + error ("internal error: unhandled type in print_type_scalar"); + break; + + default: + error ("Invalid type code in symbol table."); + } + gdb_flush (stream); +} + +#if MAINTENANCE_CMDS + +/* Dump details of a type specified either directly or indirectly. + Uses the same sort of type lookup mechanism as ptype_command() + and whatis_command(). */ + +void +maintenance_print_type (typename, from_tty) + char *typename; + int from_tty; +{ + register value_ptr val; + register struct type *type; + register struct cleanup *old_chain; + struct expression *expr; + + if (typename != NULL) + { + expr = parse_expression (typename); + old_chain = make_cleanup (free_current_contents, &expr); + if (expr -> elts[0].opcode == OP_TYPE) + { + /* The user expression names a type directly, just use that type. */ + type = expr -> elts[1].type; + } + else + { + /* The user expression may name a type indirectly by naming an + object of that type. Find that indirectly named type. */ + val = evaluate_type (expr); + type = VALUE_TYPE (val); + } + if (type != NULL) + { + recursive_dump_type (type, 0); + } + do_cleanups (old_chain); + } +} + +#endif /* MAINTENANCE_CMDS */ + + +void +_initialize_typeprint () +{ + + add_com ("ptype", class_vars, ptype_command, + "Print definition of type TYPE.\n\ +Argument may be a type name defined by typedef, or \"struct STRUCT-TAG\"\n\ +or \"class CLASS-NAME\" or \"union UNION-TAG\" or \"enum ENUM-TAG\".\n\ +The selected stack frame's lexical context is used to look up the name."); + + add_com ("whatis", class_vars, whatis_command, + "Print data type of expression EXP."); + +} diff --git a/contrib/gdb/gdb/typeprint.h b/contrib/gdb/gdb/typeprint.h new file mode 100644 index 000000000000..0dc32cdeca15 --- /dev/null +++ b/contrib/gdb/gdb/typeprint.h @@ -0,0 +1,21 @@ +/* Language independent support for printing types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +void +print_type_scalar PARAMS ((struct type *type, LONGEST, GDB_FILE *)); diff --git a/contrib/gdb/gdb/umax-xdep.c b/contrib/gdb/gdb/umax-xdep.c new file mode 100644 index 000000000000..d54519e63846 --- /dev/null +++ b/contrib/gdb/gdb/umax-xdep.c @@ -0,0 +1,133 @@ +/* umax host stuff. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include + +#include "gdbcore.h" +#include +#define PTRACE_ATTACH PT_ATTACH +#define PTRACE_DETACH PT_FREEPROC + +#include +#include "gdb_stat.h" + +/* Work with core dump and executable files, for GDB. + This code would be in corefile.c if it weren't machine-dependent. */ + +void +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the program with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct ptrace_user u; + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + u.pt_dsize; + stack_start = stack_end - u.pt_ssize; + data_offset = sizeof u; + stack_offset = data_offset + u.pt_dsize; + reg_offset = 0; + + memcpy (&core_aouthdr, &u.pt_aouthdr, sizeof (AOUTHDR)); + printf_unfiltered ("Core file is from \"%s\".\n", u.pt_comm); + if (u.pt_signal > 0) + printf_unfiltered ("Program terminated with signal %d, %s.\n", + u.pt_signal, safe_strsignal (u.pt_signal)); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename, NULL); + } + + flush_cached_frames (); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf_unfiltered ("No core file now.\n"); +} diff --git a/contrib/gdb/gdb/utils.c b/contrib/gdb/gdb/utils.c new file mode 100644 index 000000000000..513551430f64 --- /dev/null +++ b/contrib/gdb/gdb/utils.c @@ -0,0 +1,1948 @@ +/* General utility routines for GDB, the GNU debugger. + Copyright 1986, 1989, 1990, 1991, 1992, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#if !defined(__GO32__) && !defined(__WIN32__) && !defined(MPW) +#include +#include +#include +#endif +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include +#include "gdb_string.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "signals.h" +#include "gdbcmd.h" +#include "serial.h" +#include "bfd.h" +#include "target.h" +#include "demangle.h" +#include "expression.h" +#include "language.h" +#include "annotate.h" + +#include "readline.h" + +/* readline defines this. */ +#undef savestring + +/* Prototypes for local functions */ + +#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK) +#else + +static void +malloc_botch PARAMS ((void)); + +#endif /* NO_MMALLOC, etc */ + +static void +fatal_dump_core PARAMS((char *, ...)); + +static void +prompt_for_continue PARAMS ((void)); + +static void +set_width_command PARAMS ((char *, int, struct cmd_list_element *)); + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero if we have job control. */ + +int job_control; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, rather + than waiting until QUIT is executed. Be careful in setting this; + code which executes with immediate_quit set has to be very careful + about being able to deal with being interrupted at any time. It is + almost always better to use QUIT; the only exception I can think of + is being able to quit out of a system call (using EINTR loses if + the SIGINT happens between the previous QUIT and the system call). + To immediately quit in the case in which a SIGINT happens between + the previous QUIT and setting immediate_quit (desirable anytime we + expect to block), call QUIT after setting immediate_quit. */ + +int immediate_quit; + +/* Nonzero means that encoded C++ names should be printed out in their + C++ form rather than raw. */ + +int demangle = 1; + +/* Nonzero means that encoded C++ names should be printed out in their + C++ form even in assembler language displays. If this is set, but + DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls. */ + +int asm_demangle = 0; + +/* Nonzero means that strings with character values >0x7F should be printed + as octal escapes. Zero means just print the value (e.g. it's an + international character, and the terminal or window can cope.) */ + +int sevenbit_strings = 0; + +/* String to be printed before error messages, if any. */ + +char *error_pre_print; + +/* String to be printed before quit messages, if any. */ + +char *quit_pre_print; + +/* String to be printed before warning messages, if any. */ + +char *warning_pre_print = "\nwarning: "; + +/* 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 (function, arg) + void (*function) PARAMS ((PTR)); + PTR arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; /* Do this first incase recursion */ + (*ptr->function) (ptr->arg); + free (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 (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free ((PTR)ptr); + } +} + +/* Set the cleanup_chain to 0, and return the old cleanup chain. */ +struct cleanup * +save_cleanups () +{ + struct cleanup *old_chain = cleanup_chain; + + cleanup_chain = 0; + return old_chain; +} + +/* Restore the cleanup chain from a previously saved chain. */ +void +restore_cleanups (chain) + struct cleanup *chain; +{ + cleanup_chain = chain; +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Provide a known function that does nothing, to use as a base for + 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. */ + +/* ARGSUSED */ +void +null_cleanup (arg) + char **arg; +{ +} + + +/* Print a warning message. Way to use this is to call warning_begin, + output the warning message (use unfiltered output to gdb_stderr), + ending in a newline. There is not currently a warning_end that you + call afterwards, but such a thing might be added if it is useful + for a GUI to separate warning messages from other output. + + FIXME: Why do warnings use unfiltered output and errors filtered? + Is this anything other than a historical accident? */ + +void +warning_begin () +{ + target_terminal_ours (); + wrap_here(""); /* Force out any buffered output */ + gdb_flush (gdb_stdout); + if (warning_pre_print) + fprintf_unfiltered (gdb_stderr, warning_pre_print); +} + +/* Print a warning message. + The first argument STRING is the warning message, used as a fprintf string, + and the remaining args are passed as arguments to it. + The primary difference between warnings and errors is that a warning + does not force the return to command level. */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +warning (char *string, ...) +#else +warning (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + + va_start (args); + string = va_arg (args, char *); +#endif + warning_begin (); + vfprintf_unfiltered (gdb_stderr, string, args); + fprintf_unfiltered (gdb_stderr, "\n"); + va_end (args); +} + +/* Start the printing of an error message. Way to use this is to call + this, output the error message (use filtered output to gdb_stderr + (FIXME: Some callers, like memory_error, use gdb_stdout)), ending + in a newline, and then call return_to_top_level (RETURN_ERROR). + error() provides a convenient way to do this for the special case + that the error message can be formatted with a single printf call, + but this is more general. */ +void +error_begin () +{ + target_terminal_ours (); + wrap_here (""); /* Force out any buffered output */ + gdb_flush (gdb_stdout); + + annotate_error_begin (); + + if (error_pre_print) + fprintf_filtered (gdb_stderr, error_pre_print); +} + +/* Print an error message and return to command level. + The first argument STRING is the error message, used as a fprintf string, + and the remaining args are passed as arguments to it. */ + +#ifdef ANSI_PROTOTYPES +NORETURN void +error (char *string, ...) +#else +void +error (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + va_start (args); +#endif + if (error_hook) + (*error_hook) (); + else + { + error_begin (); +#ifdef ANSI_PROTOTYPES + vfprintf_filtered (gdb_stderr, string, args); +#else + { + char *string1; + + string1 = va_arg (args, char *); + vfprintf_filtered (gdb_stderr, string1, args); + } +#endif + fprintf_filtered (gdb_stderr, "\n"); + va_end (args); + return_to_top_level (RETURN_ERROR); + } +} + + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + The arguments are printed a la printf. + + This function cannot be declared volatile (NORETURN) in an + ANSI environment because exit() is not declared volatile. */ + +/* VARARGS */ +NORETURN void +#ifdef ANSI_PROTOTYPES +fatal (char *string, ...) +#else +fatal (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + va_start (args); + string = va_arg (args, char *); +#endif + fprintf_unfiltered (gdb_stderr, "\ngdb: "); + vfprintf_unfiltered (gdb_stderr, string, args); + fprintf_unfiltered (gdb_stderr, "\n"); + va_end (args); + exit (1); +} + +/* Print an error message and exit, dumping core. + The arguments are printed a la printf (). */ + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +fatal_dump_core (char *string, ...) +#else +fatal_dump_core (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, string); +#else + char *string; + + va_start (args); + string = va_arg (args, char *); +#endif + /* "internal error" is always correct, since GDB should never dump + core, no matter what the input. */ + fprintf_unfiltered (gdb_stderr, "\ngdb internal error: "); + vfprintf_unfiltered (gdb_stderr, string, args); + fprintf_unfiltered (gdb_stderr, "\n"); + va_end (args); + + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + /* We should never get here, but just in case... */ + exit (1); +} + +/* The strerror() function can return NULL for errno values that are + out of range. Provide a "safe" version that always returns a + printable string. */ + +char * +safe_strerror (errnum) + int errnum; +{ + char *msg; + static char buf[32]; + + if ((msg = strerror (errnum)) == NULL) + { + sprintf (buf, "(undocumented errno %d)", errnum); + msg = buf; + } + return (msg); +} + +/* The strsignal() function can return NULL for signal values that are + out of range. Provide a "safe" version that always returns a + printable string. */ + +char * +safe_strsignal (signo) + int signo; +{ + char *msg; + static char buf[32]; + + if ((msg = strsignal (signo)) == NULL) + { + sprintf (buf, "(undocumented signal %d)", signo); + msg = buf; + } + return (msg); +} + + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + char *err; + char *combined; + + err = safe_strerror (errno); + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + /* I understand setting these is a matter of taste. Still, some people + may clear errno but not know about bfd_error. Doing this here is not + unreasonable. */ + bfd_set_error (bfd_error_no_error); + errno = 0; + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + char *err; + char *combined; + + err = safe_strerror (errcode); + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + /* We want anything which was printed on stdout to come out first, before + this message. */ + gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stderr, "%s.\n", combined); +} + +/* Control C eventually causes this to be called, at a convenient time. */ + +void +quit () +{ + serial_t gdb_stdout_serial = serial_fdopen (1); + + target_terminal_ours (); + + /* We want all output to appear now, before we print "Quit". We + have 3 levels of buffering we have to flush (it's possible that + some of these should be changed to flush the lower-level ones + too): */ + + /* 1. The _filtered buffer. */ + wrap_here ((char *)0); + + /* 2. The stdio buffer. */ + gdb_flush (gdb_stdout); + gdb_flush (gdb_stderr); + + /* 3. The system-level buffer. */ + SERIAL_FLUSH_OUTPUT (gdb_stdout_serial); + SERIAL_UN_FDOPEN (gdb_stdout_serial); + + annotate_error_begin (); + + /* Don't use *_filtered; we don't want to prompt the user to continue. */ + if (quit_pre_print) + fprintf_unfiltered (gdb_stderr, quit_pre_print); + + if (job_control + /* If there is no terminal switching for this target, then we can't + possibly get screwed by the lack of job control. */ + || current_target.to_terminal_ours == NULL) + fprintf_unfiltered (gdb_stderr, "Quit\n"); + else + fprintf_unfiltered (gdb_stderr, + "Quit (expect signal SIGINT when the program is resumed)\n"); + return_to_top_level (RETURN_QUIT); +} + + +#if defined(__GO32__)||defined(WINGDB) + +/* In the absence of signals, poll keyboard for a quit. + Called from #define QUIT pollquit() in xm-go32.h. */ + +void +pollquit() +{ + if (kbhit ()) + { + int k = getkey (); + if (k == 1) { + quit_flag = 1; + quit(); + } + else if (k == 2) { + immediate_quit = 1; + quit (); + } + else + { + /* We just ignore it */ + fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n"); + } + } +} + + +#endif +#if defined(__GO32__)||defined(WINGDB) +void notice_quit() +{ + if (kbhit ()) + { + int k = getkey (); + if (k == 1) { + quit_flag = 1; + } + else if (k == 2) + { + immediate_quit = 1; + } + else + { + fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n"); + } + } +} +#else +void notice_quit() +{ + /* Done by signals */ +} +#endif +/* Control C comes here */ + +void +request_quit (signo) + int signo; +{ + quit_flag = 1; + /* Restore the signal handler. Harmless with BSD-style signals, needed + for System V-style signals. So just always do it, rather than worrying + about USG defines and stuff like that. */ + signal (signo, request_quit); + + +#ifdef REQUEST_QUIT + REQUEST_QUIT; +#else + if (immediate_quit) + quit (); +#endif +} + + +/* Memory management stuff (malloc friends). */ + +#if defined (NO_MMALLOC) + +/* Make a substitute size_t for non-ANSI compilers. */ + +#ifdef _AIX +#include +#else /* Not AIX */ +#ifndef __STDC__ +#ifndef size_t +#define size_t unsigned int +#endif +#endif +#endif /* Not AIX */ + +PTR +mmalloc (md, size) + PTR md; + size_t size; +{ + return malloc (size); +} + +PTR +mrealloc (md, ptr, size) + PTR md; + PTR ptr; + size_t size; +{ + if (ptr == 0) /* Guard against old realloc's */ + return malloc (size); + else + return realloc (ptr, size); +} + +void +mfree (md, ptr) + PTR md; + PTR ptr; +{ + free (ptr); +} + +#endif /* NO_MMALLOC */ + +#if defined (NO_MMALLOC) || defined (NO_MMALLOC_CHECK) + +void +init_malloc (md) + PTR md; +{ +} + +#else /* have mmalloc and want corruption checking */ + +static void +malloc_botch () +{ + fatal_dump_core ("Memory corruption"); +} + +/* Attempt to install hooks in mmalloc/mrealloc/mfree for the heap specified + by MD, to detect memory corruption. Note that MD may be NULL to specify + the default heap that grows via sbrk. + + Note that for freshly created regions, we must call mmcheck prior to any + mallocs in the region. Otherwise, any region which was allocated prior to + installing the checking hooks, which is later reallocated or freed, will + fail the checks! The mmcheck function only allows initial hooks to be + installed before the first mmalloc. However, anytime after we have called + mmcheck the first time to install the checking hooks, we can call it again + to update the function pointer to the memory corruption handler. + + Returns zero on failure, non-zero on success. */ + +void +init_malloc (md) + PTR md; +{ + if (!mmcheck (md, malloc_botch)) + { + warning ("internal error: failed to install memory consistency checks"); + } + + mmtrace (); +} + +#endif /* Have mmalloc and want corruption checking */ + +/* Called when a memory allocation fails, with the number of bytes of + memory requested in SIZE. */ + +NORETURN void +nomem (size) + long size; +{ + if (size > 0) + { + fatal ("virtual memory exhausted: can't allocate %ld bytes.", size); + } + else + { + fatal ("virtual memory exhausted."); + } +} + +/* Like mmalloc but get error if no storage available, and protect against + the caller wanting to allocate zero bytes. Whether to return NULL for + a zero byte request, or translate the request into a request for one + byte of zero'd storage, is a religious issue. */ + +PTR +xmmalloc (md, size) + PTR md; + long size; +{ + register PTR val; + + if (size == 0) + { + val = NULL; + } + else if ((val = mmalloc (md, size)) == NULL) + { + nomem (size); + } + return (val); +} + +/* Like mrealloc but get error if no storage available. */ + +PTR +xmrealloc (md, ptr, size) + PTR md; + PTR ptr; + long size; +{ + register PTR val; + + if (ptr != NULL) + { + val = mrealloc (md, ptr, size); + } + else + { + val = mmalloc (md, size); + } + if (val == NULL) + { + nomem (size); + } + return (val); +} + +/* Like malloc but get error if no storage available, and protect against + the caller wanting to allocate zero bytes. */ + +PTR +xmalloc (size) + long size; +{ + return (xmmalloc ((PTR) NULL, size)); +} + +/* Like mrealloc but get error if no storage available. */ + +PTR +xrealloc (ptr, size) + PTR ptr; + long size; +{ + return (xmrealloc ((PTR) NULL, ptr, size)); +} + + +/* My replacement for the read system call. + Used like `read' but keeps going if `read' returns too soon. */ + +int +myread (desc, addr, len) + int desc; + char *addr; + int len; +{ + register int val; + int orglen = len; + + while (len > 0) + { + val = read (desc, addr, len); + if (val < 0) + return val; + if (val == 0) + return orglen - len; + len -= val; + addr += val; + } + return orglen; +} + +/* Make a copy of the string at PTR with SIZE 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 (ptr, size) + const char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + memcpy (p, ptr, size); + p[size] = 0; + return p; +} + +char * +msavestring (md, ptr, size) + PTR md; + const char *ptr; + int size; +{ + register char *p = (char *) xmmalloc (md, size + 1); + memcpy (p, ptr, size); + p[size] = 0; + return p; +} + +/* The "const" is so it compiles under DGUX (which prototypes strsave + in . FIXME: This should be named "xstrsave", shouldn't it? + Doesn't real strsave return NULL if out of memory? */ +char * +strsave (ptr) + const char *ptr; +{ + return savestring (ptr, strlen (ptr)); +} + +char * +mstrsave (md, ptr) + PTR md; + const char *ptr; +{ + return (msavestring (md, ptr, strlen (ptr))); +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Print a host address. */ + +void +gdb_print_address (addr, stream) + PTR addr; + GDB_FILE *stream; +{ + + /* We could use the %p conversion specifier to fprintf if we had any + way of knowing whether this host supports it. But the following + should work on the Alpha and on 32 bit machines. */ + + fprintf_filtered (stream, "0x%lx", (unsigned long)addr); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +/* VARARGS */ +int +#ifdef ANSI_PROTOTYPES +query (char *ctlstr, ...) +#else +query (va_alist) + va_dcl +#endif +{ + va_list args; + register int answer; + register int ans2; + int retval; + +#ifdef ANSI_PROTOTYPES + va_start (args, ctlstr); +#else + char *ctlstr; + va_start (args); + ctlstr = va_arg (args, char *); +#endif + + if (query_hook) + { + return query_hook (ctlstr, args); + } + + /* Automatically answer "yes" if input is not from a terminal. */ + if (!input_from_terminal_p ()) + return 1; +#ifdef MPW + /* FIXME Automatically answer "yes" if called from MacGDB. */ + if (mac_app) + return 1; +#endif /* MPW */ + + while (1) + { + wrap_here (""); /* Flush any buffered output */ + gdb_flush (gdb_stdout); + + if (annotation_level > 1) + printf_filtered ("\n\032\032pre-query\n"); + + vfprintf_filtered (gdb_stdout, ctlstr, args); + printf_filtered ("(y or n) "); + + if (annotation_level > 1) + printf_filtered ("\n\032\032query\n"); + +#ifdef MPW + /* If not in MacGDB, move to a new line so the entered line doesn't + have a prompt on the front of it. */ + if (!mac_app) + fputs_unfiltered ("\n", gdb_stdout); +#endif /* MPW */ + + gdb_flush (gdb_stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer == EOF) /* C-d */ + { + retval = 1; + break; + } + if (answer != '\n') /* Eat rest of input line, to EOF or newline */ + do + { + ans2 = fgetc (stdin); + clearerr (stdin); + } + while (ans2 != EOF && ans2 != '\n'); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + { + retval = 1; + break; + } + if (answer == 'N') + { + retval = 0; + break; + } + printf_filtered ("Please answer y or n.\n"); + } + + if (annotation_level > 1) + printf_filtered ("\n\032\032post-query\n"); + return retval; +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + should point to the character after the \. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return 007; /* Bell (alert) char */ + case 'b': + return '\b'; + case 'e': /* Escape character */ + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that this routine should only + be call for printing things which are independent of the language + of the program being debugged. */ + +void +gdb_printchar (c, stream, quoter) + register int c; + FILE *stream; + int quoter; +{ + + c &= 0xFF; /* Avoid sign bit follies */ + + if ( c < 0x20 || /* Low control chars */ + (c >= 0x7F && c < 0xA0) || /* DEL, High controls */ + (sevenbit_strings && c >= 0x80)) { /* high order bit set */ + 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; + } + } else { + if (c == '\\' || c == quoter) + fputs_filtered ("\\", stream); + fprintf_filtered (stream, "%c", c); + } +} + +/* Number of lines per page or UINT_MAX if paging is disabled. */ +static unsigned int lines_per_page; +/* Number of chars per line or UNIT_MAX is line folding is disabled. */ +static unsigned int chars_per_line; +/* Current count of lines printed on this page, chars on this line. */ +static unsigned int lines_printed, chars_printed; + +/* Buffer and start column of buffered text, for doing smarter word- + wrapping. When someone calls wrap_here(), we start buffering output + that comes through fputs_filtered(). If we see a newline, we just + spit it out and forget about the wrap_here(). If we see another + wrap_here(), we spit it out and remember the newer one. If we see + the end of the line, we spit out a newline, the indent, and then + the buffered output. */ + +/* Malloc'd buffer with chars_per_line+2 bytes. Contains characters which + are waiting to be output (they have already been counted in chars_printed). + When wrap_buffer[0] is null, the buffer is empty. */ +static char *wrap_buffer; + +/* Pointer in wrap_buffer to the next character to fill. */ +static char *wrap_pointer; + +/* String to indent by if the wrap occurs. Must not be NULL if wrap_column + is non-zero. */ +static char *wrap_indent; + +/* Column number on the screen where wrap_buffer begins, or 0 if wrapping + is not in effect. */ +static int wrap_column; + +/* ARGSUSED */ +static void +set_width_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + if (!wrap_buffer) + { + wrap_buffer = (char *) xmalloc (chars_per_line + 2); + wrap_buffer[0] = '\0'; + } + else + wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2); + wrap_pointer = wrap_buffer; /* Start it at the beginning */ +} + +/* Wait, so the user can read what's on the screen. Prompt the user + to continue by pressing RETURN. */ + +static void +prompt_for_continue () +{ + char *ignore; + char cont_prompt[120]; + + if (annotation_level > 1) + printf_unfiltered ("\n\032\032pre-prompt-for-continue\n"); + + strcpy (cont_prompt, + "---Type to continue, or q to quit---"); + if (annotation_level > 1) + strcat (cont_prompt, "\n\032\032prompt-for-continue\n"); + + /* We must do this *before* we call gdb_readline, else it will eventually + call us -- thinking that we're trying to print beyond the end of the + screen. */ + reinitialize_more_filter (); + + immediate_quit++; + /* On a real operating system, the user can quit with SIGINT. + But not on GO32. + + 'q' is provided on all systems so users don't have to change habits + from system to system, and because telling them what to do in + the prompt is more user-friendly than expecting them to think of + SIGINT. */ + /* Call readline, not gdb_readline, because GO32 readline handles control-C + whereas control-C to gdb_readline will cause the user to get dumped + out to DOS. */ + ignore = readline (cont_prompt); + + if (annotation_level > 1) + printf_unfiltered ("\n\032\032post-prompt-for-continue\n"); + + if (ignore) + { + char *p = ignore; + while (*p == ' ' || *p == '\t') + ++p; + if (p[0] == 'q') + request_quit (SIGINT); + free (ignore); + } + immediate_quit--; + + /* Now we have to do this again, so that GDB will know that it doesn't + need to save the ---Type --- line at the top of the screen. */ + reinitialize_more_filter (); + + dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */ +} + +/* Reinitialize filter; ie. tell it to reset to original values. */ + +void +reinitialize_more_filter () +{ + lines_printed = 0; + chars_printed = 0; +} + +/* Indicate that if the next sequence of characters overflows the line, + a newline should be inserted here rather than when it hits the end. + If INDENT is non-null, it is a string to be printed to indent the + wrapped part on the next line. INDENT must remain accessible until + the next call to wrap_here() or until a newline is printed through + fputs_filtered(). + + If the line is already overfull, we immediately print a newline and + the indentation, and disable further wrapping. + + If we don't know the width of lines, but we know the page height, + we must not wrap words, but should still keep track of newlines + that were explicitly printed. + + INDENT should not contain tabs, as that will mess up the char count + on the next line. FIXME. + + This routine is guaranteed to force out any output which has been + squirreled away in the wrap_buffer, so wrap_here ((char *)0) can be + used to force out output from the wrap_buffer. */ + +void +wrap_here(indent) + char *indent; +{ + /* This should have been allocated, but be paranoid anyway. */ + if (!wrap_buffer) + abort (); + + if (wrap_buffer[0]) + { + *wrap_pointer = '\0'; + fputs_unfiltered (wrap_buffer, gdb_stdout); + } + wrap_pointer = wrap_buffer; + wrap_buffer[0] = '\0'; + if (chars_per_line == UINT_MAX) /* No line overflow checking */ + { + wrap_column = 0; + } + else if (chars_printed >= chars_per_line) + { + puts_filtered ("\n"); + if (indent != NULL) + puts_filtered (indent); + wrap_column = 0; + } + else + { + wrap_column = chars_printed; + if (indent == NULL) + wrap_indent = ""; + else + wrap_indent = indent; + } +} + +/* Ensure that whatever gets printed next, using the filtered output + commands, starts at the beginning of the line. I.E. if there is + any pending output for the current line, flush it and start a new + line. Otherwise do nothing. */ + +void +begin_line () +{ + if (chars_printed > 0) + { + puts_filtered ("\n"); + } +} + + +GDB_FILE * +gdb_fopen (name, mode) + char * name; + char * mode; +{ + return fopen (name, mode); +} + +void +gdb_flush (stream) + FILE *stream; +{ + if (flush_hook) + { + flush_hook (stream); + return; + } + + fflush (stream); +} + +/* Like fputs but if FILTER is true, pause after every screenful. + + Regardless of FILTER can wrap at points other than the final + character of a line. + + Unlike fputs, fputs_maybe_filtered does not return a value. + It is OK for LINEBUFFER to be NULL, in which case just don't print + anything. + + Note that a longjmp to top level may occur in this routine (only if + FILTER is true) (since prompt_for_continue may do so) so this + routine should not be called when cleanups are not in place. */ + +static void +fputs_maybe_filtered (linebuffer, stream, filter) + const char *linebuffer; + FILE *stream; + int filter; +{ + const char *lineptr; + + if (linebuffer == 0) + return; + + /* Don't do any filtering if it is disabled. */ + if (stream != gdb_stdout + || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)) + { + fputs_unfiltered (linebuffer, stream); + return; + } + + /* Go through and output each character. Show line extension + when this is necessary; prompt user for new page when this is + necessary. */ + + lineptr = linebuffer; + while (*lineptr) + { + /* Possible new page. */ + if (filter && + (lines_printed >= lines_per_page - 1)) + prompt_for_continue (); + + while (*lineptr && *lineptr != '\n') + { + /* Print a single line. */ + if (*lineptr == '\t') + { + if (wrap_column) + *wrap_pointer++ = '\t'; + else + fputc_unfiltered ('\t', stream); + /* Shifting right by 3 produces the number of tab stops + we have already passed, and then adding one and + shifting left 3 advances to the next tab stop. */ + chars_printed = ((chars_printed >> 3) + 1) << 3; + lineptr++; + } + else + { + if (wrap_column) + *wrap_pointer++ = *lineptr; + else + fputc_unfiltered (*lineptr, stream); + chars_printed++; + lineptr++; + } + + if (chars_printed >= chars_per_line) + { + unsigned int save_chars = chars_printed; + + chars_printed = 0; + lines_printed++; + /* If we aren't actually wrapping, don't output newline -- + if chars_per_line is right, we probably just overflowed + anyway; if it's wrong, let us keep going. */ + if (wrap_column) + fputc_unfiltered ('\n', stream); + + /* Possible new page. */ + if (lines_printed >= lines_per_page - 1) + prompt_for_continue (); + + /* Now output indentation and wrapped string */ + if (wrap_column) + { + fputs_unfiltered (wrap_indent, stream); + *wrap_pointer = '\0'; /* Null-terminate saved stuff */ + fputs_unfiltered (wrap_buffer, stream); /* and eject it */ + /* FIXME, this strlen is what prevents wrap_indent from + containing tabs. However, if we recurse to print it + and count its chars, we risk trouble if wrap_indent is + longer than (the user settable) chars_per_line. + Note also that this can set chars_printed > chars_per_line + if we are printing a long string. */ + chars_printed = strlen (wrap_indent) + + (save_chars - wrap_column); + wrap_pointer = wrap_buffer; /* Reset buffer */ + wrap_buffer[0] = '\0'; + wrap_column = 0; /* And disable fancy wrap */ + } + } + } + + if (*lineptr == '\n') + { + chars_printed = 0; + wrap_here ((char *)0); /* Spit out chars, cancel further wraps */ + lines_printed++; + fputc_unfiltered ('\n', stream); + lineptr++; + } + } +} + +void +fputs_filtered (linebuffer, stream) + const char *linebuffer; + FILE *stream; +{ + fputs_maybe_filtered (linebuffer, stream, 1); +} + +int +putchar_unfiltered (c) + int c; +{ + char buf[2]; + + buf[0] = c; + buf[1] = 0; + fputs_unfiltered (buf, gdb_stdout); + return c; +} + +int +fputc_unfiltered (c, stream) + int c; + FILE * stream; +{ + char buf[2]; + + buf[0] = c; + buf[1] = 0; + fputs_unfiltered (buf, stream); + return c; +} + + +/* Print a variable number of ARGS using format FORMAT. If this + information is going to put the amount written (since the last call + to REINITIALIZE_MORE_FILTER or the last page break) over the page size, + call prompt_for_continue to get the users permision to continue. + + Unlike fprintf, this function does not return a value. + + We implement three variants, vfprintf (takes a vararg list and stream), + fprintf (takes a stream to write on), and printf (the usual). + + Note also that a longjmp to top level may occur in this routine + (since prompt_for_continue may do so) so this routine should not be + called when cleanups are not in place. */ + +static void +vfprintf_maybe_filtered (stream, format, args, filter) + FILE *stream; + char *format; + va_list args; + int filter; +{ + char *linebuffer; + struct cleanup *old_cleanups; + + vasprintf (&linebuffer, format, args); + if (linebuffer == NULL) + { + fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr); + exit (1); + } + old_cleanups = make_cleanup (free, linebuffer); + fputs_maybe_filtered (linebuffer, stream, filter); + do_cleanups (old_cleanups); +} + + +void +vfprintf_filtered (stream, format, args) + FILE *stream; + const char *format; + va_list args; +{ + vfprintf_maybe_filtered (stream, format, args, 1); +} + +void +vfprintf_unfiltered (stream, format, args) + FILE *stream; + const char *format; + va_list args; +{ + char *linebuffer; + struct cleanup *old_cleanups; + + vasprintf (&linebuffer, format, args); + if (linebuffer == NULL) + { + fputs_unfiltered ("\ngdb: virtual memory exhausted.\n", gdb_stderr); + exit (1); + } + old_cleanups = make_cleanup (free, linebuffer); + fputs_unfiltered (linebuffer, stream); + do_cleanups (old_cleanups); +} + +void +vprintf_filtered (format, args) + const char *format; + va_list args; +{ + vfprintf_maybe_filtered (gdb_stdout, format, args, 1); +} + +void +vprintf_unfiltered (format, args) + const char *format; + va_list args; +{ + vfprintf_unfiltered (gdb_stdout, format, args); +} + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +fprintf_filtered (FILE *stream, const char *format, ...) +#else +fprintf_filtered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + FILE *stream; + char *format; + + va_start (args); + stream = va_arg (args, FILE *); + format = va_arg (args, char *); +#endif + vfprintf_filtered (stream, format, args); + va_end (args); +} + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +fprintf_unfiltered (FILE *stream, const char *format, ...) +#else +fprintf_unfiltered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + FILE *stream; + char *format; + + va_start (args); + stream = va_arg (args, FILE *); + format = va_arg (args, char *); +#endif + vfprintf_unfiltered (stream, format, args); + va_end (args); +} + +/* Like fprintf_filtered, but prints its result indented. + Called as fprintfi_filtered (spaces, stream, format, ...); */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +fprintfi_filtered (int spaces, FILE *stream, const char *format, ...) +#else +fprintfi_filtered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + int spaces; + FILE *stream; + char *format; + + va_start (args); + spaces = va_arg (args, int); + stream = va_arg (args, FILE *); + format = va_arg (args, char *); +#endif + print_spaces_filtered (spaces, stream); + + vfprintf_filtered (stream, format, args); + va_end (args); +} + + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +printf_filtered (const char *format, ...) +#else +printf_filtered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + + va_start (args); + format = va_arg (args, char *); +#endif + vfprintf_filtered (gdb_stdout, format, args); + va_end (args); +} + + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +printf_unfiltered (const char *format, ...) +#else +printf_unfiltered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + + va_start (args); + format = va_arg (args, char *); +#endif + vfprintf_unfiltered (gdb_stdout, format, args); + va_end (args); +} + +/* Like printf_filtered, but prints it's result indented. + Called as printfi_filtered (spaces, format, ...); */ + +/* VARARGS */ +void +#ifdef ANSI_PROTOTYPES +printfi_filtered (int spaces, const char *format, ...) +#else +printfi_filtered (va_alist) + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + int spaces; + char *format; + + va_start (args); + spaces = va_arg (args, int); + format = va_arg (args, char *); +#endif + print_spaces_filtered (spaces, gdb_stdout); + vfprintf_filtered (gdb_stdout, format, args); + va_end (args); +} + +/* Easy -- but watch out! + + This routine is *not* a replacement for puts()! puts() appends a newline. + This one doesn't, and had better not! */ + +void +puts_filtered (string) + const char *string; +{ + fputs_filtered (string, gdb_stdout); +} + +void +puts_unfiltered (string) + const char *string; +{ + fputs_unfiltered (string, gdb_stdout); +} + +/* Return a pointer to N spaces and a null. The pointer is good + until the next call to here. */ +char * +n_spaces (n) + int n; +{ + register char *t; + static char *spaces; + static int max_spaces; + + if (n > max_spaces) + { + if (spaces) + free (spaces); + spaces = (char *) xmalloc (n+1); + for (t = spaces+n; t != spaces;) + *--t = ' '; + spaces[n] = '\0'; + max_spaces = n; + } + + return spaces + max_spaces - n; +} + +/* Print N spaces. */ +void +print_spaces_filtered (n, stream) + int n; + FILE *stream; +{ + fputs_filtered (n_spaces (n), stream); +} + +/* C++ demangler stuff. */ + +/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language + LANG, using demangling args ARG_MODE, and print it filtered to STREAM. + If the name is not mangled, or the language for the name is unknown, or + demangling is off, the name is printed in its "raw" form. */ + +void +fprintf_symbol_filtered (stream, name, lang, arg_mode) + FILE *stream; + char *name; + enum language lang; + int arg_mode; +{ + char *demangled; + + if (name != NULL) + { + /* If user wants to see raw output, no problem. */ + if (!demangle) + { + fputs_filtered (name, stream); + } + else + { + switch (lang) + { + case language_cplus: + demangled = cplus_demangle (name, arg_mode); + break; + case language_chill: + demangled = chill_demangle (name); + break; + default: + demangled = NULL; + break; + } + fputs_filtered (demangled ? demangled : name, stream); + if (demangled != NULL) + { + free (demangled); + } + } + } +} + +/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any + differences in whitespace. Returns 0 if they match, non-zero if they + don't (slightly different than strcmp()'s range of return values). + + As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO". + This "feature" is useful when searching for matching C++ function names + (such as if the user types 'break FOO', where FOO is a mangled C++ + function). */ + +int +strcmp_iw (string1, string2) + const char *string1; + const char *string2; +{ + while ((*string1 != '\0') && (*string2 != '\0')) + { + while (isspace (*string1)) + { + string1++; + } + while (isspace (*string2)) + { + string2++; + } + if (*string1 != *string2) + { + break; + } + if (*string1 != '\0') + { + string1++; + string2++; + } + } + return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0'); +} + + +void +initialize_utils () +{ + struct cmd_list_element *c; + + c = add_set_cmd ("width", class_support, var_uinteger, + (char *)&chars_per_line, + "Set number of characters gdb thinks are in a line.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_width_command; + + add_show_from_set + (add_set_cmd ("height", class_support, + var_uinteger, (char *)&lines_per_page, + "Set number of lines gdb thinks are in a page.", &setlist), + &showlist); + + /* These defaults will be used if we are unable to get the correct + values from termcap. */ +#if defined(__GO32__) || defined(__WIN32__) + lines_per_page = ScreenRows(); + chars_per_line = ScreenCols(); +#else + lines_per_page = 24; + chars_per_line = 80; + +#ifndef MPW + /* No termcap under MPW, although might be cool to do something + by looking at worksheet or console window sizes. */ + /* Initialize the screen height and width from termcap. */ + { + char *termtype = getenv ("TERM"); + + /* Positive means success, nonpositive means failure. */ + int status; + + /* 2048 is large enough for all known terminals, according to the + GNU termcap manual. */ + char term_buffer[2048]; + + if (termtype) + { + status = tgetent (term_buffer, termtype); + if (status > 0) + { + int val; + + val = tgetnum ("li"); + if (val >= 0) + lines_per_page = val; + else + /* The number of lines per page is not mentioned + in the terminal description. This probably means + that paging is not useful (e.g. emacs shell window), + so disable paging. */ + lines_per_page = UINT_MAX; + + val = tgetnum ("co"); + if (val >= 0) + chars_per_line = val; + } + } + } +#endif /* MPW */ + +#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) + + /* If there is a better way to determine the window size, use it. */ + SIGWINCH_HANDLER (); +#endif +#endif + /* If the output is not a terminal, don't paginate it. */ + if (!ISATTY (gdb_stdout)) + lines_per_page = UINT_MAX; + + set_width_command ((char *)NULL, 0, c); + + add_show_from_set + (add_set_cmd ("demangle", class_support, var_boolean, + (char *)&demangle, + "Set demangling of encoded C++ names when displaying symbols.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("sevenbit-strings", class_support, var_boolean, + (char *)&sevenbit_strings, + "Set printing of 8-bit characters in strings as \\nnn.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("asm-demangle", class_support, var_boolean, + (char *)&asm_demangle, + "Set demangling of C++ names in disassembly listings.", + &setprintlist), + &showprintlist); +} + +/* Machine specific function to handle SIGWINCH signal. */ + +#ifdef SIGWINCH_HANDLER_BODY + SIGWINCH_HANDLER_BODY +#endif + diff --git a/contrib/gdb/gdb/valarith.c b/contrib/gdb/gdb/valarith.c new file mode 100644 index 000000000000..c03d0a4a2ef0 --- /dev/null +++ b/contrib/gdb/gdb/valarith.c @@ -0,0 +1,1213 @@ +/* Perform arithmetic and other operations on values, for GDB. + Copyright 1986, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "value.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "target.h" +#include "language.h" +#include "demangle.h" +#include "gdb_string.h" + +/* Define whether or not the C operator '/' truncates towards zero for + differently signed operands (truncation direction is undefined in C). */ + +#ifndef TRUNCATION_TOWARDS_ZERO +#define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2) +#endif + +static value_ptr value_subscripted_rvalue PARAMS ((value_ptr, value_ptr, int)); + + +value_ptr +value_add (arg1, arg2) + value_ptr arg1, arg2; +{ + register value_ptr valint, valptr; + register int len; + struct type *type1, *type2, *valptrtype; + + COERCE_NUMBER (arg1); + COERCE_NUMBER (arg2); + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + + if ((TYPE_CODE (type1) == TYPE_CODE_PTR + || TYPE_CODE (type2) == TYPE_CODE_PTR) + && + (TYPE_CODE (type1) == TYPE_CODE_INT + || TYPE_CODE (type2) == TYPE_CODE_INT)) + /* Exactly one argument is a pointer, and one is an integer. */ + { + if (TYPE_CODE (type1) == TYPE_CODE_PTR) + { + valptr = arg1; + valint = arg2; + valptrtype = type1; + } + else + { + valptr = arg2; + valint = arg1; + valptrtype = type2; + } + len = TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (valptrtype))); + if (len == 0) len = 1; /* For (void *) */ + return value_from_longest (valptrtype, + value_as_long (valptr) + + (len * value_as_long (valint))); + } + + return value_binop (arg1, arg2, BINOP_ADD); +} + +value_ptr +value_sub (arg1, arg2) + value_ptr arg1, arg2; +{ + struct type *type1, *type2; + COERCE_NUMBER (arg1); + COERCE_NUMBER (arg2); + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + + if (TYPE_CODE (type1) == TYPE_CODE_PTR) + { + if (TYPE_CODE (type2) == TYPE_CODE_INT) + { + /* pointer - integer. */ + LONGEST sz = TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type1))); + return value_from_longest + (VALUE_TYPE (arg1), + value_as_long (arg1) - (sz * value_as_long (arg2))); + } + else if (TYPE_CODE (type2) == TYPE_CODE_PTR + && TYPE_LENGTH (TYPE_TARGET_TYPE (type1)) + == TYPE_LENGTH (TYPE_TARGET_TYPE (type2))) + { + /* pointer to - pointer to . */ + LONGEST sz = TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type1))); + return value_from_longest + (builtin_type_long, /* FIXME -- should be ptrdiff_t */ + (value_as_long (arg1) - value_as_long (arg2)) / sz); + } + else + { + error ("\ +First argument of `-' is a pointer and second argument is neither\n\ +an integer nor a pointer of the same type."); + } + } + + return value_binop (arg1, arg2, BINOP_SUB); +} + +/* Return the value of ARRAY[IDX]. + See comments in value_coerce_array() for rationale for reason for + doing lower bounds adjustment here rather than there. + FIXME: Perhaps we should validate that the index is valid and if + verbosity is set, warn about invalid indices (but still use them). */ + +value_ptr +value_subscript (array, idx) + value_ptr array, idx; +{ + value_ptr bound; + int c_style = current_language->c_style_arrays; + struct type *tarray; + + COERCE_REF (array); + tarray = check_typedef (VALUE_TYPE (array)); + COERCE_VARYING_ARRAY (array, tarray); + + if (TYPE_CODE (tarray) == TYPE_CODE_ARRAY + || TYPE_CODE (tarray) == TYPE_CODE_STRING) + { + struct type *range_type = TYPE_INDEX_TYPE (tarray); + LONGEST lowerbound, upperbound; + get_discrete_bounds (range_type, &lowerbound, &upperbound); + + if (VALUE_LVAL (array) != lval_memory) + return value_subscripted_rvalue (array, idx, lowerbound); + + if (c_style == 0) + { + LONGEST index = value_as_long (idx); + if (index >= lowerbound && index <= upperbound) + return value_subscripted_rvalue (array, idx, lowerbound); + warning ("array or string index out of range"); + /* fall doing C stuff */ + c_style = 1; + } + + if (lowerbound != 0) + { + bound = value_from_longest (builtin_type_int, (LONGEST) lowerbound); + idx = value_sub (idx, bound); + } + + array = value_coerce_array (array); + } + + if (TYPE_CODE (tarray) == TYPE_CODE_BITSTRING) + { + struct type *range_type = TYPE_INDEX_TYPE (tarray); + LONGEST index = value_as_long (idx); + value_ptr v; + int offset, byte, bit_index; + LONGEST lowerbound, upperbound; + get_discrete_bounds (range_type, &lowerbound, &upperbound); + if (index < lowerbound || index > upperbound) + error ("bitstring index out of range"); + index -= lowerbound; + offset = index / TARGET_CHAR_BIT; + byte = *((char*)VALUE_CONTENTS (array) + offset); + bit_index = index % TARGET_CHAR_BIT; + byte >>= (BITS_BIG_ENDIAN ? TARGET_CHAR_BIT - 1 - bit_index : bit_index); + v = value_from_longest (LA_BOOL_TYPE, byte & 1); + VALUE_BITPOS (v) = bit_index; + VALUE_BITSIZE (v) = 1; + VALUE_LVAL (v) = VALUE_LVAL (array); + if (VALUE_LVAL (array) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (array); + VALUE_OFFSET (v) = offset + VALUE_OFFSET (array); + return v; + } + + if (c_style) + return value_ind (value_add (array, idx)); + else + error ("not an array or string"); +} + +/* Return the value of EXPR[IDX], expr an aggregate rvalue + (eg, a vector register). This routine used to promote floats + to doubles, but no longer does. */ + +static value_ptr +value_subscripted_rvalue (array, idx, lowerbound) + value_ptr array, idx; + int lowerbound; +{ + struct type *array_type = check_typedef (VALUE_TYPE (array)); + struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type)); + unsigned int elt_size = TYPE_LENGTH (elt_type); + LONGEST index = value_as_long (idx); + unsigned int elt_offs = elt_size * longest_to_int (index - lowerbound); + value_ptr v; + + if (index < lowerbound || elt_offs >= TYPE_LENGTH (array_type)) + error ("no such vector element"); + + v = allocate_value (elt_type); + if (VALUE_LAZY (array)) + VALUE_LAZY (v) = 1; + else + memcpy (VALUE_CONTENTS (v), VALUE_CONTENTS (array) + elt_offs, elt_size); + + if (VALUE_LVAL (array) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + else + VALUE_LVAL (v) = VALUE_LVAL (array); + VALUE_ADDRESS (v) = VALUE_ADDRESS (array); + VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs; + return v; +} + +/* Check to see if either argument is a structure. This is called so + we know whether to go ahead with the normal binop or look for a + user defined function instead. + + For now, we do not overload the `=' operator. */ + +int +binop_user_defined_p (op, arg1, arg2) + enum exp_opcode op; + value_ptr arg1, arg2; +{ + struct type *type1, *type2; + if (op == BINOP_ASSIGN || op == BINOP_CONCAT) + return 0; + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + return (TYPE_CODE (type1) == TYPE_CODE_STRUCT + || TYPE_CODE (type2) == TYPE_CODE_STRUCT + || (TYPE_CODE (type1) == TYPE_CODE_REF + && TYPE_CODE (TYPE_TARGET_TYPE (type1)) == TYPE_CODE_STRUCT) + || (TYPE_CODE (type2) == TYPE_CODE_REF + && TYPE_CODE (TYPE_TARGET_TYPE (type2)) == TYPE_CODE_STRUCT)); +} + +/* Check to see if argument is a structure. This is called so + we know whether to go ahead with the normal unop or look for a + user defined function instead. + + For now, we do not overload the `&' operator. */ + +int unop_user_defined_p (op, arg1) + enum exp_opcode op; + value_ptr arg1; +{ + struct type *type1; + if (op == UNOP_ADDR) + return 0; + type1 = check_typedef (VALUE_TYPE (arg1)); + for (;;) + { + if (TYPE_CODE (type1) == TYPE_CODE_STRUCT) + return 1; + else if (TYPE_CODE (type1) == TYPE_CODE_REF) + type1 = TYPE_TARGET_TYPE (type1); + else + return 0; + } +} + +/* We know either arg1 or arg2 is a structure, so try to find the right + user defined function. Create an argument vector that calls + arg1.operator @ (arg1,arg2) and return that value (where '@' is any + binary operator which is legal for GNU C++). + + OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP + is the opcode saying how to modify it. Otherwise, OTHEROP is + unused. */ + +value_ptr +value_x_binop (arg1, arg2, op, otherop) + value_ptr arg1, arg2; + enum exp_opcode op, otherop; +{ + value_ptr * argvec; + char *ptr; + char tstr[13]; + int static_memfuncp; + + COERCE_REF (arg1); + COERCE_REF (arg2); + COERCE_ENUM (arg1); + COERCE_ENUM (arg2); + + /* now we know that what we have to do is construct our + arg vector and find the right function to call it with. */ + + if (TYPE_CODE (check_typedef (VALUE_TYPE (arg1))) != TYPE_CODE_STRUCT) + error ("Can't do that binary op on that type"); /* FIXME be explicit */ + + argvec = (value_ptr *) alloca (sizeof (value_ptr) * 4); + argvec[1] = value_addr (arg1); + argvec[2] = arg2; + argvec[3] = 0; + + /* make the right function name up */ + strcpy(tstr, "operator__"); + ptr = tstr+8; + switch (op) + { + case BINOP_ADD: strcpy(ptr,"+"); break; + case BINOP_SUB: strcpy(ptr,"-"); break; + case BINOP_MUL: strcpy(ptr,"*"); break; + case BINOP_DIV: strcpy(ptr,"/"); break; + case BINOP_REM: strcpy(ptr,"%"); break; + case BINOP_LSH: strcpy(ptr,"<<"); break; + case BINOP_RSH: strcpy(ptr,">>"); break; + case BINOP_BITWISE_AND: strcpy(ptr,"&"); break; + case BINOP_BITWISE_IOR: strcpy(ptr,"|"); break; + case BINOP_BITWISE_XOR: strcpy(ptr,"^"); break; + case BINOP_LOGICAL_AND: strcpy(ptr,"&&"); break; + case BINOP_LOGICAL_OR: strcpy(ptr,"||"); break; + case BINOP_MIN: strcpy(ptr,"?"); break; + case BINOP_ASSIGN: strcpy(ptr,"="); break; + case BINOP_ASSIGN_MODIFY: + switch (otherop) + { + case BINOP_ADD: strcpy(ptr,"+="); break; + case BINOP_SUB: strcpy(ptr,"-="); break; + case BINOP_MUL: strcpy(ptr,"*="); break; + case BINOP_DIV: strcpy(ptr,"/="); break; + case BINOP_REM: strcpy(ptr,"%="); break; + case BINOP_BITWISE_AND: strcpy(ptr,"&="); break; + case BINOP_BITWISE_IOR: strcpy(ptr,"|="); break; + case BINOP_BITWISE_XOR: strcpy(ptr,"^="); break; + case BINOP_MOD: /* invalid */ + default: + error ("Invalid binary operation specified."); + } + break; + case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break; + case BINOP_EQUAL: strcpy(ptr,"=="); break; + case BINOP_NOTEQUAL: strcpy(ptr,"!="); break; + case BINOP_LESS: strcpy(ptr,"<"); break; + case BINOP_GTR: strcpy(ptr,">"); break; + case BINOP_GEQ: strcpy(ptr,">="); break; + case BINOP_LEQ: strcpy(ptr,"<="); break; + case BINOP_MOD: /* invalid */ + default: + error ("Invalid binary operation specified."); + } + + argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure"); + + if (argvec[0]) + { + if (static_memfuncp) + { + argvec[1] = argvec[0]; + argvec++; + } + return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); +#ifdef lint + return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1); +#endif +} + +/* We know that arg1 is a structure, so try to find a unary user + defined operator that matches the operator in question. + Create an argument vector that calls arg1.operator @ (arg1) + and return that value (where '@' is (almost) any unary operator which + is legal for GNU C++). */ + +value_ptr +value_x_unop (arg1, op) + value_ptr arg1; + enum exp_opcode op; +{ + value_ptr * argvec; + char *ptr, *mangle_ptr; + char tstr[13], mangle_tstr[13]; + int static_memfuncp; + + COERCE_REF (arg1); + COERCE_ENUM (arg1); + + /* now we know that what we have to do is construct our + arg vector and find the right function to call it with. */ + + if (TYPE_CODE (check_typedef (VALUE_TYPE (arg1))) != TYPE_CODE_STRUCT) + error ("Can't do that unary op on that type"); /* FIXME be explicit */ + + argvec = (value_ptr *) alloca (sizeof (value_ptr) * 3); + argvec[1] = value_addr (arg1); + argvec[2] = 0; + + /* make the right function name up */ + strcpy(tstr,"operator__"); + ptr = tstr+8; + strcpy(mangle_tstr, "__"); + mangle_ptr = mangle_tstr+2; + switch (op) + { + case UNOP_PREINCREMENT: strcpy(ptr,"++"); break; + case UNOP_PREDECREMENT: strcpy(ptr,"++"); break; + case UNOP_POSTINCREMENT: strcpy(ptr,"++"); break; + case UNOP_POSTDECREMENT: strcpy(ptr,"++"); break; + case UNOP_LOGICAL_NOT: strcpy(ptr,"!"); break; + case UNOP_COMPLEMENT: strcpy(ptr,"~"); break; + case UNOP_NEG: strcpy(ptr,"-"); break; + default: + error ("Invalid binary operation specified."); + } + + argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure"); + + if (argvec[0]) + { + if (static_memfuncp) + { + argvec[1] = argvec[0]; + argvec++; + } + return call_function_by_hand (argvec[0], 1 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); + return 0; /* For lint -- never reached */ +} + + +/* Concatenate two values with the following conditions: + + (1) Both values must be either bitstring values or character string + values and the resulting value consists of the concatenation of + ARG1 followed by ARG2. + + or + + One value must be an integer value and the other value must be + either a bitstring value or character string value, which is + to be repeated by the number of times specified by the integer + value. + + + (2) Boolean values are also allowed and are treated as bit string + values of length 1. + + (3) Character values are also allowed and are treated as character + string values of length 1. +*/ + +value_ptr +value_concat (arg1, arg2) + value_ptr arg1, arg2; +{ + register value_ptr inval1, inval2, outval; + int inval1len, inval2len; + int count, idx; + char *ptr; + char inchar; + struct type *type1 = check_typedef (VALUE_TYPE (arg1)); + struct type *type2 = check_typedef (VALUE_TYPE (arg2)); + + COERCE_VARYING_ARRAY (arg1, type1); + COERCE_VARYING_ARRAY (arg2, type2); + + /* First figure out if we are dealing with two values to be concatenated + or a repeat count and a value to be repeated. INVAL1 is set to the + first of two concatenated values, or the repeat count. INVAL2 is set + to the second of the two concatenated values or the value to be + repeated. */ + + if (TYPE_CODE (type2) == TYPE_CODE_INT) + { + struct type *tmp = type1; + type1 = tmp; + tmp = type2; + inval1 = arg2; + inval2 = arg1; + } + else + { + inval1 = arg1; + inval2 = arg2; + } + + /* Now process the input values. */ + + if (TYPE_CODE (type1) == TYPE_CODE_INT) + { + /* We have a repeat count. Validate the second value and then + construct a value repeated that many times. */ + if (TYPE_CODE (type2) == TYPE_CODE_STRING + || TYPE_CODE (type2) == TYPE_CODE_CHAR) + { + count = longest_to_int (value_as_long (inval1)); + inval2len = TYPE_LENGTH (type2); + ptr = (char *) alloca (count * inval2len); + if (TYPE_CODE (type2) == TYPE_CODE_CHAR) + { + inchar = (char) unpack_long (type2, + VALUE_CONTENTS (inval2)); + for (idx = 0; idx < count; idx++) + { + *(ptr + idx) = inchar; + } + } + else + { + for (idx = 0; idx < count; idx++) + { + memcpy (ptr + (idx * inval2len), VALUE_CONTENTS (inval2), + inval2len); + } + } + outval = value_string (ptr, count * inval2len); + } + else if (TYPE_CODE (type2) == TYPE_CODE_BITSTRING + || TYPE_CODE (type2) == TYPE_CODE_BOOL) + { + error ("unimplemented support for bitstring/boolean repeats"); + } + else + { + error ("can't repeat values of that type"); + } + } + else if (TYPE_CODE (type1) == TYPE_CODE_STRING + || TYPE_CODE (type1) == TYPE_CODE_CHAR) + { + /* We have two character strings to concatenate. */ + if (TYPE_CODE (type2) != TYPE_CODE_STRING + && TYPE_CODE (type2) != TYPE_CODE_CHAR) + { + error ("Strings can only be concatenated with other strings."); + } + inval1len = TYPE_LENGTH (type1); + inval2len = TYPE_LENGTH (type2); + ptr = (char *) alloca (inval1len + inval2len); + if (TYPE_CODE (type1) == TYPE_CODE_CHAR) + { + *ptr = (char) unpack_long (type1, VALUE_CONTENTS (inval1)); + } + else + { + memcpy (ptr, VALUE_CONTENTS (inval1), inval1len); + } + if (TYPE_CODE (type2) == TYPE_CODE_CHAR) + { + *(ptr + inval1len) = + (char) unpack_long (type2, VALUE_CONTENTS (inval2)); + } + else + { + memcpy (ptr + inval1len, VALUE_CONTENTS (inval2), inval2len); + } + outval = value_string (ptr, inval1len + inval2len); + } + else if (TYPE_CODE (type1) == TYPE_CODE_BITSTRING + || TYPE_CODE (type1) == TYPE_CODE_BOOL) + { + /* We have two bitstrings to concatenate. */ + if (TYPE_CODE (type2) != TYPE_CODE_BITSTRING + && TYPE_CODE (type2) != TYPE_CODE_BOOL) + { + error ("Bitstrings or booleans can only be concatenated with other bitstrings or booleans."); + } + error ("unimplemented support for bitstring/boolean concatenation."); + } + else + { + /* We don't know how to concatenate these operands. */ + error ("illegal operands for concatenation."); + } + return (outval); +} + + + +/* Perform a binary operation on two operands which have reasonable + representations as integers or floats. This includes booleans, + characters, integers, or floats. + Does not support addition and subtraction on pointers; + use value_add or value_sub if you want to handle those possibilities. */ + +value_ptr +value_binop (arg1, arg2, op) + value_ptr arg1, arg2; + enum exp_opcode op; +{ + register value_ptr val; + struct type *type1, *type2; + + COERCE_REF (arg1); + COERCE_REF (arg2); + COERCE_ENUM (arg1); + COERCE_ENUM (arg2); + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + + if ((TYPE_CODE (type1) != TYPE_CODE_FLT + && TYPE_CODE (type1) != TYPE_CODE_CHAR + && TYPE_CODE (type1) != TYPE_CODE_INT + && TYPE_CODE (type1) != TYPE_CODE_BOOL + && TYPE_CODE (type1) != TYPE_CODE_RANGE) + || + (TYPE_CODE (type2) != TYPE_CODE_FLT + && TYPE_CODE (type2) != TYPE_CODE_CHAR + && TYPE_CODE (type2) != TYPE_CODE_INT + && TYPE_CODE (type2) != TYPE_CODE_BOOL + && TYPE_CODE (type2) != TYPE_CODE_RANGE)) + error ("Argument to arithmetic operation not a number or boolean."); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT + || + TYPE_CODE (type2) == TYPE_CODE_FLT) + { + /* FIXME-if-picky-about-floating-accuracy: Should be doing this + in target format. real.c in GCC probably has the necessary + code. */ + DOUBLEST v1, v2, v; + v1 = value_as_double (arg1); + v2 = value_as_double (arg2); + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + default: + error ("Integer-only operation on floating point number."); + } + + /* If either arg was long double, make sure that value is also long + double. */ + + if (TYPE_LENGTH(type1) * 8 > TARGET_DOUBLE_BIT + || TYPE_LENGTH(type2) * 8 > TARGET_DOUBLE_BIT) + val = allocate_value (builtin_type_long_double); + else + val = allocate_value (builtin_type_double); + + store_floating (VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + else if (TYPE_CODE (type1) == TYPE_CODE_BOOL + && + TYPE_CODE (type2) == TYPE_CODE_BOOL) + { + LONGEST v1, v2, v; + v1 = value_as_long (arg1); + v2 = value_as_long (arg2); + + switch (op) + { + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + default: + error ("Invalid operation on booleans."); + } + + val = allocate_value (type1); + store_signed_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (type1), + v); + } + else + /* Integral operations here. */ + /* FIXME: Also mixed integral/booleans, with result an integer. */ + /* FIXME: This implements ANSI C rules (also correct for C++). + What about FORTRAN and chill? */ + { + unsigned int promoted_len1 = TYPE_LENGTH (type1); + unsigned int promoted_len2 = TYPE_LENGTH (type2); + int is_unsigned1 = TYPE_UNSIGNED (type1); + int is_unsigned2 = TYPE_UNSIGNED (type2); + unsigned int result_len; + int unsigned_operation; + + /* Determine type length and signedness after promotion for + both operands. */ + if (promoted_len1 < TYPE_LENGTH (builtin_type_int)) + { + is_unsigned1 = 0; + promoted_len1 = TYPE_LENGTH (builtin_type_int); + } + if (promoted_len2 < TYPE_LENGTH (builtin_type_int)) + { + is_unsigned2 = 0; + promoted_len2 = TYPE_LENGTH (builtin_type_int); + } + + /* Determine type length of the result, and if the operation should + be done unsigned. + Use the signedness of the operand with the greater length. + If both operands are of equal length, use unsigned operation + if one of the operands is unsigned. */ + if (promoted_len1 > promoted_len2) + { + unsigned_operation = is_unsigned1; + result_len = promoted_len1; + } + else if (promoted_len2 > promoted_len1) + { + unsigned_operation = is_unsigned2; + result_len = promoted_len2; + } + else + { + unsigned_operation = is_unsigned1 || is_unsigned2; + result_len = promoted_len1; + } + + if (unsigned_operation) + { + unsigned LONGEST v1, v2, v; + v1 = (unsigned LONGEST) value_as_long (arg1); + v2 = (unsigned LONGEST) value_as_long (arg2); + + /* Truncate values to the type length of the result. */ + if (result_len < sizeof (unsigned LONGEST)) + { + v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1; + v2 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1; + } + + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + case BINOP_REM: + v = v1 % v2; + break; + + case BINOP_MOD: + /* Knuth 1.2.4, integer only. Note that unlike the C '%' op, + v1 mod 0 has a defined value, v1. */ + /* Chill specifies that v2 must be > 0, so check for that. */ + if (current_language -> la_language == language_chill + && value_as_long (arg2) <= 0) + { + error ("Second operand of MOD must be greater than zero."); + } + if (v2 == 0) + { + v = v1; + } + else + { + v = v1/v2; + /* Note floor(v1/v2) == v1/v2 for unsigned. */ + v = v1 - (v2 * v); + } + break; + + case BINOP_LSH: + v = v1 << v2; + break; + + case BINOP_RSH: + v = v1 >> v2; + break; + + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + case BINOP_LOGICAL_AND: + v = v1 && v2; + break; + + case BINOP_LOGICAL_OR: + v = v1 || v2; + break; + + case BINOP_MIN: + v = v1 < v2 ? v1 : v2; + break; + + case BINOP_MAX: + v = v1 > v2 ? v1 : v2; + break; + + case BINOP_EQUAL: + v = v1 == v2; + break; + + case BINOP_LESS: + v = v1 < v2; + break; + + default: + error ("Invalid binary operation on numbers."); + } + + /* This is a kludge to get around the fact that we don't + know how to determine the result type from the types of + the operands. (I'm not really sure how much we feel the + need to duplicate the exact rules of the current + language. They can get really hairy. But not to do so + makes it hard to document just what we *do* do). */ + + /* Can't just call init_type because we wouldn't know what + name to give the type. */ + val = allocate_value + (result_len > TARGET_LONG_BIT / HOST_CHAR_BIT + ? builtin_type_unsigned_long_long + : builtin_type_unsigned_long); + store_unsigned_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + else + { + LONGEST v1, v2, v; + v1 = value_as_long (arg1); + v2 = value_as_long (arg2); + + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + case BINOP_REM: + v = v1 % v2; + break; + + case BINOP_MOD: + /* Knuth 1.2.4, integer only. Note that unlike the C '%' op, + X mod 0 has a defined value, X. */ + /* Chill specifies that v2 must be > 0, so check for that. */ + if (current_language -> la_language == language_chill + && v2 <= 0) + { + error ("Second operand of MOD must be greater than zero."); + } + if (v2 == 0) + { + v = v1; + } + else + { + v = v1/v2; + /* Compute floor. */ + if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0)) + { + v--; + } + v = v1 - (v2 * v); + } + break; + + case BINOP_LSH: + v = v1 << v2; + break; + + case BINOP_RSH: + v = v1 >> v2; + break; + + case BINOP_BITWISE_AND: + v = v1 & v2; + break; + + case BINOP_BITWISE_IOR: + v = v1 | v2; + break; + + case BINOP_BITWISE_XOR: + v = v1 ^ v2; + break; + + case BINOP_LOGICAL_AND: + v = v1 && v2; + break; + + case BINOP_LOGICAL_OR: + v = v1 || v2; + break; + + case BINOP_MIN: + v = v1 < v2 ? v1 : v2; + break; + + case BINOP_MAX: + v = v1 > v2 ? v1 : v2; + break; + + case BINOP_EQUAL: + v = v1 == v2; + break; + + case BINOP_LESS: + v = v1 < v2; + break; + + default: + error ("Invalid binary operation on numbers."); + } + + /* This is a kludge to get around the fact that we don't + know how to determine the result type from the types of + the operands. (I'm not really sure how much we feel the + need to duplicate the exact rules of the current + language. They can get really hairy. But not to do so + makes it hard to document just what we *do* do). */ + + /* Can't just call init_type because we wouldn't know what + name to give the type. */ + val = allocate_value + (result_len > TARGET_LONG_BIT / HOST_CHAR_BIT + ? builtin_type_long_long + : builtin_type_long); + store_signed_integer (VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val)), + v); + } + } + + return val; +} + +/* Simulate the C operator ! -- return 1 if ARG1 contains zero. */ + +int +value_logical_not (arg1) + value_ptr arg1; +{ + register int len; + register char *p; + struct type *type1; + + COERCE_NUMBER (arg1); + type1 = check_typedef (VALUE_TYPE (arg1)); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT) + return 0 == value_as_double (arg1); + + len = TYPE_LENGTH (type1); + p = VALUE_CONTENTS (arg1); + + while (--len >= 0) + { + if (*p++) + break; + } + + return len < 0; +} + +/* Simulate the C operator == by returning a 1 + iff ARG1 and ARG2 have equal contents. */ + +int +value_equal (arg1, arg2) + register value_ptr arg1, arg2; + +{ + register int len; + register char *p1, *p2; + struct type *type1, *type2; + enum type_code code1; + enum type_code code2; + + COERCE_NUMBER (arg1); + COERCE_NUMBER (arg2); + + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + code1 = TYPE_CODE (type1); + code2 = TYPE_CODE (type2); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + return longest_to_int (value_as_long (value_binop (arg1, arg2, + BINOP_EQUAL))); + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) == value_as_double (arg2); + + /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever + is bigger. */ + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT) + return value_as_pointer (arg1) == (CORE_ADDR) value_as_long (arg2); + else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT) + return (CORE_ADDR) value_as_long (arg1) == value_as_pointer (arg2); + + else if (code1 == code2 + && ((len = (int) TYPE_LENGTH (type1)) + == (int) TYPE_LENGTH (type2))) + { + p1 = VALUE_CONTENTS (arg1); + p2 = VALUE_CONTENTS (arg2); + while (--len >= 0) + { + if (*p1++ != *p2++) + break; + } + return len < 0; + } + else + { + error ("Invalid type combination in equality test."); + return 0; /* For lint -- never reached */ + } +} + +/* Simulate the C operator < by returning 1 + iff ARG1's contents are less than ARG2's. */ + +int +value_less (arg1, arg2) + register value_ptr arg1, arg2; +{ + register enum type_code code1; + register enum type_code code2; + struct type *type1, *type2; + + COERCE_NUMBER (arg1); + COERCE_NUMBER (arg2); + + type1 = check_typedef (VALUE_TYPE (arg1)); + type2 = check_typedef (VALUE_TYPE (arg2)); + code1 = TYPE_CODE (type1); + code2 = TYPE_CODE (type2); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + return longest_to_int (value_as_long (value_binop (arg1, arg2, + BINOP_LESS))); + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) < value_as_double (arg2); + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) + return value_as_pointer (arg1) < value_as_pointer (arg2); + + /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever + is bigger. */ + else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT) + return value_as_pointer (arg1) < (CORE_ADDR) value_as_long (arg2); + else if (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT) + return (CORE_ADDR) value_as_long (arg1) < value_as_pointer (arg2); + + else + { + error ("Invalid type combination in ordering comparison."); + return 0; + } +} + +/* The unary operators - and ~. Both free the argument ARG1. */ + +value_ptr +value_neg (arg1) + register value_ptr arg1; +{ + register struct type *type; + + COERCE_REF (arg1); + COERCE_ENUM (arg1); + + type = check_typedef (VALUE_TYPE (arg1)); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return value_from_double (type, - value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_INT) + return value_from_longest (type, - value_as_long (arg1)); + else { + error ("Argument to negate operation not a number."); + return 0; /* For lint -- never reached */ + } +} + +value_ptr +value_complement (arg1) + register value_ptr arg1; +{ + COERCE_REF (arg1); + COERCE_ENUM (arg1); + + if (TYPE_CODE (check_typedef (VALUE_TYPE (arg1))) != TYPE_CODE_INT) + error ("Argument to complement operation not an integer."); + + return value_from_longest (VALUE_TYPE (arg1), ~ value_as_long (arg1)); +} + +/* The INDEX'th bit of SET value whose VALUE_TYPE is TYPE, + and whose VALUE_CONTENTS is valaddr. + Return -1 if out of range, -2 other error. */ + +int +value_bit_index (type, valaddr, index) + struct type *type; + char *valaddr; + int index; +{ + LONGEST low_bound, high_bound; + LONGEST word; + unsigned rel_index; + struct type *range = TYPE_FIELD_TYPE (type, 0); + if (get_discrete_bounds (range, &low_bound, &high_bound) < 0) + return -2; + if (index < low_bound || index > high_bound) + return -1; + rel_index = index - low_bound; + word = unpack_long (builtin_type_unsigned_char, + valaddr + (rel_index / TARGET_CHAR_BIT)); + rel_index %= TARGET_CHAR_BIT; + if (BITS_BIG_ENDIAN) + rel_index = TARGET_CHAR_BIT - 1 - rel_index; + return (word >> rel_index) & 1; +} + +value_ptr +value_in (element, set) + value_ptr element, set; +{ + int member; + struct type *settype = check_typedef (VALUE_TYPE (set)); + struct type *eltype = check_typedef (VALUE_TYPE (element)); + if (TYPE_CODE (eltype) == TYPE_CODE_RANGE) + eltype = TYPE_TARGET_TYPE (eltype); + if (TYPE_CODE (settype) != TYPE_CODE_SET) + error ("Second argument of 'IN' has wrong type"); + if (TYPE_CODE (eltype) != TYPE_CODE_INT + && TYPE_CODE (eltype) != TYPE_CODE_CHAR + && TYPE_CODE (eltype) != TYPE_CODE_ENUM + && TYPE_CODE (eltype) != TYPE_CODE_BOOL) + error ("First argument of 'IN' has wrong type"); + member = value_bit_index (settype, VALUE_CONTENTS (set), + value_as_long (element)); + if (member < 0) + error ("First argument of 'IN' not in range"); + return value_from_longest (LA_BOOL_TYPE, member); +} + +void +_initialize_valarith () +{ +} diff --git a/contrib/gdb/gdb/valops.c b/contrib/gdb/gdb/valops.c new file mode 100644 index 000000000000..684b224cc885 --- /dev/null +++ b/contrib/gdb/gdb/valops.c @@ -0,0 +1,2346 @@ +/* Perform non-arithmetic operations on values, for GDB. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" +#include "target.h" +#include "demangle.h" +#include "language.h" + +#include +#include "gdb_string.h" + +/* Default to coercing float to double in function calls only when there is + no prototype. Otherwise on targets where the debug information is incorrect + for either the prototype or non-prototype case, we can force it by defining + COERCE_FLOAT_TO_DOUBLE in the target configuration file. */ + +#ifndef COERCE_FLOAT_TO_DOUBLE +#define COERCE_FLOAT_TO_DOUBLE (param_type == NULL) +#endif + +/* Local functions. */ + +static int typecmp PARAMS ((int staticp, struct type *t1[], value_ptr t2[])); + +static CORE_ADDR find_function_addr PARAMS ((value_ptr, struct type **)); + +static CORE_ADDR value_push PARAMS ((CORE_ADDR, value_ptr)); + +static value_ptr search_struct_field PARAMS ((char *, value_ptr, int, + struct type *, int)); + +static value_ptr search_struct_method PARAMS ((char *, value_ptr *, + value_ptr *, + int, int *, struct type *)); + +static int check_field_in PARAMS ((struct type *, const char *)); + +static CORE_ADDR allocate_space_in_inferior PARAMS ((int)); + +static value_ptr cast_into_complex PARAMS ((struct type *, value_ptr)); + +#define VALUE_SUBSTRING_START(VAL) VALUE_FRAME(VAL) + +/* Flag for whether we want to abandon failed expression evals by default. */ + +#if 0 +static int auto_abandon = 0; +#endif + + +/* Find the address of function name NAME in the inferior. */ + +value_ptr +find_function_in_inferior (name) + char *name; +{ + register struct symbol *sym; + sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL); + if (sym != NULL) + { + if (SYMBOL_CLASS (sym) != LOC_BLOCK) + { + error ("\"%s\" exists in this program but is not a function.", + name); + } + return value_of_variable (sym, NULL); + } + else + { + struct minimal_symbol *msymbol = lookup_minimal_symbol(name, NULL, NULL); + if (msymbol != NULL) + { + struct type *type; + LONGEST maddr; + type = lookup_pointer_type (builtin_type_char); + type = lookup_function_type (type); + type = lookup_pointer_type (type); + maddr = (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol); + return value_from_longest (type, maddr); + } + else + { + error ("evaluation of this expression requires the program to have a function \"%s\".", name); + } + } +} + +/* Allocate NBYTES of space in the inferior using the inferior's malloc + and return a value that is a pointer to the allocated space. */ + +value_ptr +value_allocate_space_in_inferior (len) + int len; +{ + value_ptr blocklen; + register value_ptr val = find_function_in_inferior ("malloc"); + + blocklen = value_from_longest (builtin_type_int, (LONGEST) len); + val = call_function_by_hand (val, 1, &blocklen); + if (value_logical_not (val)) + { + error ("No memory available to program."); + } + return val; +} + +static CORE_ADDR +allocate_space_in_inferior (len) + int len; +{ + return value_as_long (value_allocate_space_in_inferior (len)); +} + +/* Cast value ARG2 to type TYPE and return as a value. + More general than a C cast: accepts any two types of the same length, + and if ARG2 is an lvalue it can be cast into anything at all. */ +/* In C++, casts may change pointer or object representations. */ + +value_ptr +value_cast (type, arg2) + struct type *type; + register value_ptr arg2; +{ + register enum type_code code1; + register enum type_code code2; + register int scalar; + struct type *type2; + + if (VALUE_TYPE (arg2) == type) + return arg2; + + CHECK_TYPEDEF (type); + code1 = TYPE_CODE (type); + COERCE_REF(arg2); + type2 = check_typedef (VALUE_TYPE (arg2)); + + /* A cast to an undetermined-length array_type, such as (TYPE [])OBJECT, + is treated like a cast to (TYPE [N])OBJECT, + where N is sizeof(OBJECT)/sizeof(TYPE). */ + if (code1 == TYPE_CODE_ARRAY) + { + struct type *element_type = TYPE_TARGET_TYPE (type); + unsigned element_length = TYPE_LENGTH (check_typedef (element_type)); + if (element_length > 0 + && TYPE_ARRAY_UPPER_BOUND_TYPE (type) == BOUND_CANNOT_BE_DETERMINED) + { + struct type *range_type = TYPE_INDEX_TYPE (type); + int val_length = TYPE_LENGTH (type2); + LONGEST low_bound, high_bound, new_length; + if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) + low_bound = 0, high_bound = 0; + new_length = val_length / element_length; + if (val_length % element_length != 0) + warning("array element type size does not divide object size in cast"); + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + range_type = create_range_type ((struct type *) NULL, + TYPE_TARGET_TYPE (range_type), + low_bound, + new_length + low_bound - 1); + VALUE_TYPE (arg2) = create_array_type ((struct type *) NULL, + element_type, range_type); + return arg2; + } + } + + if (current_language->c_style_arrays + && TYPE_CODE (type2) == TYPE_CODE_ARRAY) + arg2 = value_coerce_array (arg2); + + if (TYPE_CODE (type2) == TYPE_CODE_FUNC) + arg2 = value_coerce_function (arg2); + + type2 = check_typedef (VALUE_TYPE (arg2)); + COERCE_VARYING_ARRAY (arg2, type2); + code2 = TYPE_CODE (type2); + + if (code1 == TYPE_CODE_COMPLEX) + return cast_into_complex (type, arg2); + if (code1 == TYPE_CODE_BOOL || code1 == TYPE_CODE_CHAR) + code1 = TYPE_CODE_INT; + if (code2 == TYPE_CODE_BOOL || code2 == TYPE_CODE_CHAR) + code2 = TYPE_CODE_INT; + + scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT + || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE); + + if ( code1 == TYPE_CODE_STRUCT + && code2 == TYPE_CODE_STRUCT + && TYPE_NAME (type) != 0) + { + /* Look in the type of the source to see if it contains the + type of the target as a superclass. If so, we'll need to + offset the object in addition to changing its type. */ + value_ptr v = search_struct_field (type_name_no_tag (type), + arg2, 0, type2, 1); + if (v) + { + VALUE_TYPE (v) = type; + return v; + } + } + if (code1 == TYPE_CODE_FLT && scalar) + return value_from_double (type, value_as_double (arg2)); + else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM + || code1 == TYPE_CODE_RANGE) + && (scalar || code2 == TYPE_CODE_PTR)) + return value_from_longest (type, value_as_long (arg2)); + else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) + { + if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) + { + /* Look in the type of the source to see if it contains the + type of the target as a superclass. If so, we'll need to + offset the pointer rather than just change its type. */ + struct type *t1 = check_typedef (TYPE_TARGET_TYPE (type)); + struct type *t2 = check_typedef (TYPE_TARGET_TYPE (type2)); + if ( TYPE_CODE (t1) == TYPE_CODE_STRUCT + && TYPE_CODE (t2) == TYPE_CODE_STRUCT + && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */ + { + value_ptr v = search_struct_field (type_name_no_tag (t1), + value_ind (arg2), 0, t2, 1); + if (v) + { + v = value_addr (v); + VALUE_TYPE (v) = type; + return v; + } + } + /* No superclass found, just fall through to change ptr type. */ + } + VALUE_TYPE (arg2) = type; + return arg2; + } + else if (chill_varying_type (type)) + { + struct type *range1, *range2, *eltype1, *eltype2; + value_ptr val; + int count1, count2; + LONGEST low_bound, high_bound; + char *valaddr, *valaddr_data; + if (code2 == TYPE_CODE_BITSTRING) + error ("not implemented: converting bitstring to varying type"); + if ((code2 != TYPE_CODE_ARRAY && code2 != TYPE_CODE_STRING) + || (eltype1 = check_typedef (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 1))), + eltype2 = check_typedef (TYPE_TARGET_TYPE (type2)), + (TYPE_LENGTH (eltype1) != TYPE_LENGTH (eltype2) + /* || TYPE_CODE (eltype1) != TYPE_CODE (eltype2) */ ))) + error ("Invalid conversion to varying type"); + range1 = TYPE_FIELD_TYPE (TYPE_FIELD_TYPE (type, 1), 0); + range2 = TYPE_FIELD_TYPE (type2, 0); + if (get_discrete_bounds (range1, &low_bound, &high_bound) < 0) + count1 = -1; + else + count1 = high_bound - low_bound + 1; + if (get_discrete_bounds (range2, &low_bound, &high_bound) < 0) + count1 = -1, count2 = 0; /* To force error before */ + else + count2 = high_bound - low_bound + 1; + if (count2 > count1) + error ("target varying type is too small"); + val = allocate_value (type); + valaddr = VALUE_CONTENTS_RAW (val); + valaddr_data = valaddr + TYPE_FIELD_BITPOS (type, 1) / 8; + /* Set val's __var_length field to count2. */ + store_signed_integer (valaddr, TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)), + count2); + /* Set the __var_data field to count2 elements copied from arg2. */ + memcpy (valaddr_data, VALUE_CONTENTS (arg2), + count2 * TYPE_LENGTH (eltype2)); + /* Zero the rest of the __var_data field of val. */ + memset (valaddr_data + count2 * TYPE_LENGTH (eltype2), '\0', + (count1 - count2) * TYPE_LENGTH (eltype2)); + return val; + } + else if (VALUE_LVAL (arg2) == lval_memory) + { + return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + } + else if (code1 == TYPE_CODE_VOID) + { + return value_zero (builtin_type_void, not_lval); + } + else + { + error ("Invalid cast."); + return 0; + } +} + +/* Create a value of type TYPE that is zero, and return it. */ + +value_ptr +value_zero (type, lv) + struct type *type; + enum lval_type lv; +{ + register value_ptr val = allocate_value (type); + + memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (check_typedef (type))); + VALUE_LVAL (val) = lv; + + return val; +} + +/* Return a value with type TYPE located at ADDR. + + Call value_at only if the data needs to be fetched immediately; + if we can be 'lazy' and defer the fetch, perhaps indefinately, call + value_at_lazy instead. value_at_lazy simply records the address of + the data and sets the lazy-evaluation-required flag. The lazy flag + is tested in the VALUE_CONTENTS macro, which is used if and when + the contents are actually required. */ + +value_ptr +value_at (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value_ptr val; + + if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) + error ("Attempt to dereference a generic pointer."); + + val = allocate_value (type); + + read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type)); + + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + + return val; +} + +/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */ + +value_ptr +value_at_lazy (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value_ptr val; + + if (TYPE_CODE (check_typedef (type)) == TYPE_CODE_VOID) + error ("Attempt to dereference a generic pointer."); + + val = allocate_value (type); + + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + VALUE_LAZY (val) = 1; + + return val; +} + +/* Called only from the VALUE_CONTENTS macro, if the current data for + a variable needs to be loaded into VALUE_CONTENTS(VAL). Fetches the + data from the user's process, and clears the lazy flag to indicate + that the data in the buffer is valid. + + If the value is zero-length, we avoid calling read_memory, which would + abort. We mark the value as fetched anyway -- all 0 bytes of it. + + This function returns a value because it is used in the VALUE_CONTENTS + macro as part of an expression, where a void would not work. The + value is ignored. */ + +int +value_fetch_lazy (val) + register value_ptr val; +{ + CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val); + int length = TYPE_LENGTH (VALUE_TYPE (val)); + + if (length) + read_memory (addr, VALUE_CONTENTS_RAW (val), length); + VALUE_LAZY (val) = 0; + return 0; +} + + +/* Store the contents of FROMVAL into the location of TOVAL. + Return a new value with the location of TOVAL and contents of FROMVAL. */ + +value_ptr +value_assign (toval, fromval) + register value_ptr toval, fromval; +{ + register struct type *type; + register value_ptr val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + int use_buffer = 0; + + if (!toval->modifiable) + error ("Left operand of assignment is not a modifiable lvalue."); + + COERCE_REF (toval); + + type = VALUE_TYPE (toval); + if (VALUE_LVAL (toval) != lval_internalvar) + fromval = value_cast (type, fromval); + else + COERCE_ARRAY (fromval); + CHECK_TYPEDEF (type); + + /* If TOVAL is a special machine register requiring conversion + of program values to a special raw format, + convert FROMVAL's contents now, with result in `raw_buffer', + and set USE_BUFFER to the number of bytes to write. */ + +#ifdef REGISTER_CONVERTIBLE + if (VALUE_REGNO (toval) >= 0 + && REGISTER_CONVERTIBLE (VALUE_REGNO (toval))) + { + int regno = VALUE_REGNO (toval); + if (REGISTER_CONVERTIBLE (regno)) + { + struct type *fromtype = check_typedef (VALUE_TYPE (fromval)); + REGISTER_CONVERT_TO_RAW (fromtype, regno, + VALUE_CONTENTS (fromval), raw_buffer); + use_buffer = REGISTER_RAW_SIZE (regno); + } + } +#endif + + switch (VALUE_LVAL (toval)) + { + case lval_internalvar: + set_internalvar (VALUE_INTERNALVAR (toval), fromval); + return value_copy (VALUE_INTERNALVAR (toval)->value); + + case lval_internalvar_component: + set_internalvar_component (VALUE_INTERNALVAR (toval), + VALUE_OFFSET (toval), + VALUE_BITPOS (toval), + VALUE_BITSIZE (toval), + fromval); + break; + + case lval_memory: + if (VALUE_BITSIZE (toval)) + { + char buffer[sizeof (LONGEST)]; + /* We assume that the argument to read_memory is in units of + host chars. FIXME: Is that correct? */ + int len = (VALUE_BITPOS (toval) + + VALUE_BITSIZE (toval) + + HOST_CHAR_BIT - 1) + / HOST_CHAR_BIT; + + if (len > (int) sizeof (LONGEST)) + error ("Can't handle bitfields which don't fit in a %d bit word.", + sizeof (LONGEST) * HOST_CHAR_BIT); + + read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + buffer, len); + modify_field (buffer, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + buffer, len); + } + else if (use_buffer) + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + break; + + case lval_register: + if (VALUE_BITSIZE (toval)) + { + char buffer[sizeof (LONGEST)]; + int len = REGISTER_RAW_SIZE (VALUE_REGNO (toval)); + + if (len > (int) sizeof (LONGEST)) + error ("Can't handle bitfields in registers larger than %d bits.", + sizeof (LONGEST) * HOST_CHAR_BIT); + + if (VALUE_BITPOS (toval) + VALUE_BITSIZE (toval) + > len * HOST_CHAR_BIT) + /* Getting this right would involve being very careful about + byte order. */ + error ("\ +Can't handle bitfield which doesn't fit in a single register."); + + read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + buffer, len); + modify_field (buffer, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + buffer, len); + } + else if (use_buffer) + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + { + /* Do any conversion necessary when storing this type to more + than one register. */ +#ifdef REGISTER_CONVERT_FROM_TYPE + memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + REGISTER_CONVERT_FROM_TYPE(VALUE_REGNO (toval), type, raw_buffer); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, TYPE_LENGTH (type)); +#else + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); +#endif + } + /* Assigning to the stack pointer, frame pointer, and other + (architecture and calling convention specific) registers may + cause the frame cache to be out of date. We just do this + on all assignments to registers for simplicity; I doubt the slowdown + matters. */ + reinit_frame_cache (); + break; + + case lval_reg_frame_relative: + { + /* value is stored in a series of registers in the frame + specified by the structure. Copy that value out, modify + it, and copy it back in. */ + int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type)); + int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval)); + int byte_offset = VALUE_OFFSET (toval) % reg_size; + int reg_offset = VALUE_OFFSET (toval) / reg_size; + int amount_copied; + + /* Make the buffer large enough in all cases. */ + char *buffer = (char *) alloca (amount_to_copy + + sizeof (LONGEST) + + MAX_REGISTER_RAW_SIZE); + + int regno; + struct frame_info *frame; + + /* Figure out which frame this is in currently. */ + for (frame = get_current_frame (); + frame && FRAME_FP (frame) != VALUE_FRAME (toval); + frame = get_prev_frame (frame)) + ; + + if (!frame) + error ("Value being assigned to is no longer active."); + + amount_to_copy += (reg_size - amount_to_copy % reg_size); + + /* Copy it out. */ + for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, + amount_copied = 0); + amount_copied < amount_to_copy; + amount_copied += reg_size, regno++) + { + get_saved_register (buffer + amount_copied, + (int *)NULL, (CORE_ADDR *)NULL, + frame, regno, (enum lval_type *)NULL); + } + + /* Modify what needs to be modified. */ + if (VALUE_BITSIZE (toval)) + modify_field (buffer + byte_offset, + value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + else if (use_buffer) + memcpy (buffer + byte_offset, raw_buffer, use_buffer); + else + memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval), + TYPE_LENGTH (type)); + + /* Copy it back. */ + for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, + amount_copied = 0); + amount_copied < amount_to_copy; + amount_copied += reg_size, regno++) + { + enum lval_type lval; + CORE_ADDR addr; + int optim; + + /* Just find out where to put it. */ + get_saved_register ((char *)NULL, + &optim, &addr, frame, regno, &lval); + + if (optim) + error ("Attempt to assign to a value that was optimized out."); + if (lval == lval_memory) + write_memory (addr, buffer + amount_copied, reg_size); + else if (lval == lval_register) + write_register_bytes (addr, buffer + amount_copied, reg_size); + else + error ("Attempt to assign to an unmodifiable value."); + } + } + break; + + + default: + error ("Left operand of assignment is not an lvalue."); + } + + /* If the field does not entirely fill a LONGEST, then zero the sign bits. + If the field is signed, and is negative, then sign extend. */ + if ((VALUE_BITSIZE (toval) > 0) + && (VALUE_BITSIZE (toval) < 8 * (int) sizeof (LONGEST))) + { + LONGEST fieldval = value_as_long (fromval); + LONGEST valmask = (((unsigned LONGEST) 1) << VALUE_BITSIZE (toval)) - 1; + + fieldval &= valmask; + if (!TYPE_UNSIGNED (type) && (fieldval & (valmask ^ (valmask >> 1)))) + fieldval |= ~valmask; + + fromval = value_from_longest (type, fieldval); + } + + val = value_copy (toval); + memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval), + TYPE_LENGTH (type)); + VALUE_TYPE (val) = type; + + return val; +} + +/* Extend a value VAL to COUNT repetitions of its type. */ + +value_ptr +value_repeat (arg1, count) + value_ptr arg1; + int count; +{ + register value_ptr val; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Only values in memory can be extended with '@'."); + if (count < 1) + error ("Invalid number %d of repetitions.", count); + + val = allocate_repeat_value (VALUE_TYPE (arg1), count); + + read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), + VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (VALUE_TYPE (val))); + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1); + + return val; +} + +value_ptr +value_of_variable (var, b) + struct symbol *var; + struct block *b; +{ + value_ptr val; + struct frame_info *frame; + + if (b == NULL) + /* Use selected frame. */ + frame = NULL; + else + { + frame = block_innermost_frame (b); + if (frame == NULL && symbol_read_needs_frame (var)) + { + if (BLOCK_FUNCTION (b) != NULL + && SYMBOL_NAME (BLOCK_FUNCTION (b)) != NULL) + error ("No frame is currently executing in block %s.", + SYMBOL_NAME (BLOCK_FUNCTION (b))); + else + error ("No frame is currently executing in specified block"); + } + } + val = read_var_value (var, frame); + if (val == 0) + error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var)); + return val; +} + +/* Given a value which is an array, return a value which is a pointer to its + first element, regardless of whether or not the array has a nonzero lower + bound. + + FIXME: A previous comment here indicated that this routine should be + substracting the array's lower bound. It's not clear to me that this + is correct. Given an array subscripting operation, it would certainly + work to do the adjustment here, essentially computing: + + (&array[0] - (lowerbound * sizeof array[0])) + (index * sizeof array[0]) + + However I believe a more appropriate and logical place to account for + the lower bound is to do so in value_subscript, essentially computing: + + (&array[0] + ((index - lowerbound) * sizeof array[0])) + + As further evidence consider what would happen with operations other + than array subscripting, where the caller would get back a value that + had an address somewhere before the actual first element of the array, + and the information about the lower bound would be lost because of + the coercion to pointer type. + */ + +value_ptr +value_coerce_array (arg1) + value_ptr arg1; +{ + register struct type *type = check_typedef (VALUE_TYPE (arg1)); + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + return value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Given a value which is a function, return a value which is a pointer + to it. */ + +value_ptr +value_coerce_function (arg1) + value_ptr arg1; +{ + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + return value_from_longest (lookup_pointer_type (VALUE_TYPE (arg1)), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Return a pointer value for the object for which ARG1 is the contents. */ + +value_ptr +value_addr (arg1) + value_ptr arg1; +{ + struct type *type = check_typedef (VALUE_TYPE (arg1)); + if (TYPE_CODE (type) == TYPE_CODE_REF) + { + /* Copy the value, but change the type from (T&) to (T*). + We keep the same location information, which is efficient, + and allows &(&X) to get the location containing the reference. */ + value_ptr arg2 = value_copy (arg1); + VALUE_TYPE (arg2) = lookup_pointer_type (TYPE_TARGET_TYPE (type)); + return arg2; + } + if (TYPE_CODE (type) == TYPE_CODE_FUNC) + return value_coerce_function (arg1); + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + return value_from_longest (lookup_pointer_type (VALUE_TYPE (arg1)), + (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1))); +} + +/* Given a value of a pointer type, apply the C unary * operator to it. */ + +value_ptr +value_ind (arg1) + value_ptr arg1; +{ + struct type *type1; + COERCE_ARRAY (arg1); + type1 = check_typedef (VALUE_TYPE (arg1)); + + if (TYPE_CODE (type1) == TYPE_CODE_MEMBER) + error ("not implemented: member types in value_ind"); + + /* Allow * on an integer so we can cast it to whatever we want. + This returns an int, which seems like the most C-like thing + to do. "long long" variables are rare enough that + BUILTIN_TYPE_LONGEST would seem to be a mistake. */ + if (TYPE_CODE (type1) == TYPE_CODE_INT) + return value_at (builtin_type_int, + (CORE_ADDR) value_as_long (arg1)); + else if (TYPE_CODE (type1) == TYPE_CODE_PTR) + return value_at_lazy (TYPE_TARGET_TYPE (type1), value_as_pointer (arg1)); + error ("Attempt to take contents of a non-pointer value."); + return 0; /* For lint -- never reached */ +} + +/* Pushing small parts of stack frames. */ + +/* Push one word (the size of object that a register holds). */ + +CORE_ADDR +push_word (sp, word) + CORE_ADDR sp; + unsigned LONGEST word; +{ + register int len = REGISTER_SIZE; + char buffer[MAX_REGISTER_RAW_SIZE]; + + store_unsigned_integer (buffer, len, word); +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, buffer, len); +#else /* stack grows upward */ + write_memory (sp, buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push LEN bytes with data at BUFFER. */ + +CORE_ADDR +push_bytes (sp, buffer, len) + CORE_ADDR sp; + char *buffer; + int len; +{ +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, buffer, len); +#else /* stack grows upward */ + write_memory (sp, buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push onto the stack the specified value VALUE. */ + +static CORE_ADDR +value_push (sp, arg) + register CORE_ADDR sp; + value_ptr arg; +{ + register int len = TYPE_LENGTH (VALUE_TYPE (arg)); + +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, VALUE_CONTENTS (arg), len); +#else /* stack grows upward */ + write_memory (sp, VALUE_CONTENTS (arg), len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Perform the standard coercions that are specified + for arguments to be passed to C functions. + + If PARAM_TYPE is non-NULL, it is the expected parameter type. */ + +static value_ptr +value_arg_coerce (arg, param_type) + value_ptr arg; + struct type *param_type; +{ + register struct type *arg_type = check_typedef (VALUE_TYPE (arg)); + register struct type *type + = param_type ? check_typedef (param_type) : arg_type; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_REF: + if (TYPE_CODE (arg_type) != TYPE_CODE_REF) + { + arg = value_addr (arg); + VALUE_TYPE (arg) = param_type; + return arg; + } + break; + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_BOOL: + case TYPE_CODE_ENUM: + if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int)) + type = builtin_type_int; + break; + case TYPE_CODE_FLT: + /* coerce float to double, unless the function prototype specifies float */ + if (COERCE_FLOAT_TO_DOUBLE) + { + if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double)) + type = builtin_type_double; + else if (TYPE_LENGTH (type) > TYPE_LENGTH (builtin_type_double)) + type = builtin_type_long_double; + } + break; + case TYPE_CODE_FUNC: + type = lookup_pointer_type (type); + break; + case TYPE_CODE_ARRAY: + if (current_language->c_style_arrays) + type = lookup_pointer_type (TYPE_TARGET_TYPE (type)); + break; + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_RANGE: + case TYPE_CODE_STRING: + case TYPE_CODE_BITSTRING: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_COMPLEX: + default: + break; + } + + return value_cast (type, arg); +} + +/* Determine a function's address and its return type from its value. + Calls error() if the function is not valid for calling. */ + +static CORE_ADDR +find_function_addr (function, retval_type) + value_ptr function; + struct type **retval_type; +{ + register struct type *ftype = check_typedef (VALUE_TYPE (function)); + register enum type_code code = TYPE_CODE (ftype); + struct type *value_type; + CORE_ADDR funaddr; + + /* If it's a member function, just look at the function + part of it. */ + + /* Determine address to call. */ + if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) + { + funaddr = VALUE_ADDRESS (function); + value_type = TYPE_TARGET_TYPE (ftype); + } + else if (code == TYPE_CODE_PTR) + { + funaddr = value_as_pointer (function); + ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); + if (TYPE_CODE (ftype) == TYPE_CODE_FUNC + || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + { +#ifdef CONVERT_FROM_FUNC_PTR_ADDR + /* FIXME: This is a workaround for the unusual function + pointer representation on the RS/6000, see comment + in config/rs6000/tm-rs6000.h */ + funaddr = CONVERT_FROM_FUNC_PTR_ADDR (funaddr); +#endif + value_type = TYPE_TARGET_TYPE (ftype); + } + else + value_type = builtin_type_int; + } + else if (code == TYPE_CODE_INT) + { + /* Handle the case of functions lacking debugging info. + Their values are characters since their addresses are char */ + if (TYPE_LENGTH (ftype) == 1) + funaddr = value_as_pointer (value_addr (function)); + else + /* Handle integer used as address of a function. */ + funaddr = (CORE_ADDR) value_as_long (function); + + value_type = builtin_type_int; + } + else + error ("Invalid data type for function to be called."); + + *retval_type = value_type; + return funaddr; +} + +#if defined (CALL_DUMMY) +/* All this stuff with a dummy frame may seem unnecessarily complicated + (why not just save registers in GDB?). The purpose of pushing a dummy + frame which looks just like a real frame is so that if you call a + function and then hit a breakpoint (get a signal, etc), "backtrace" + will look right. Whether the backtrace needs to actually show the + stack at the time the inferior function was called is debatable, but + it certainly needs to not display garbage. So if you are contemplating + making dummy frames be different from normal frames, consider that. */ + +/* Perform a function call in the inferior. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a value representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. + + ARGS is modified to contain coerced values. */ + +value_ptr +call_function_by_hand (function, nargs, args) + value_ptr function; + int nargs; + value_ptr *args; +{ + register CORE_ADDR sp; + register int i; + CORE_ADDR start_sp; + /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word + is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it + and remove any extra bytes which might exist because unsigned LONGEST is + bigger than REGISTER_SIZE. */ + static unsigned LONGEST dummy[] = CALL_DUMMY; + char dummy1[REGISTER_SIZE * sizeof dummy / sizeof (unsigned LONGEST)]; + CORE_ADDR old_sp; + struct type *value_type; + unsigned char struct_return; + CORE_ADDR struct_addr; + struct inferior_status inf_status; + struct cleanup *old_chain; + CORE_ADDR funaddr; + int using_gcc; + CORE_ADDR real_pc; + struct type *ftype = check_typedef (SYMBOL_TYPE (function)); + + if (!target_has_execution) + noprocess(); + + save_inferior_status (&inf_status, 1); + old_chain = make_cleanup (restore_inferior_status, &inf_status); + + /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers + (and POP_FRAME for restoring them). (At least on most machines) + they are saved on the stack in the inferior. */ + PUSH_DUMMY_FRAME; + + old_sp = sp = read_sp (); + +#if 1 INNER_THAN 2 /* Stack grows down */ + sp -= sizeof dummy1; + start_sp = sp; +#else /* Stack grows up */ + start_sp = sp; + sp += sizeof dummy1; +#endif + + funaddr = find_function_addr (function, &value_type); + CHECK_TYPEDEF (value_type); + + { + struct block *b = block_for_pc (funaddr); + /* If compiled without -g, assume GCC. */ + using_gcc = b == NULL ? 0 : BLOCK_GCC_COMPILED (b); + } + + /* Are we returning a value using a structure return or a normal + value return? */ + + struct_return = using_struct_return (function, funaddr, value_type, + using_gcc); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ + for (i = 0; i < (int) (sizeof (dummy) / sizeof (dummy[0])); i++) + store_unsigned_integer (&dummy1[i * REGISTER_SIZE], + REGISTER_SIZE, + (unsigned LONGEST)dummy[i]); + +#ifdef GDB_TARGET_IS_HPPA + real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); +#else + FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, + value_type, using_gcc); + real_pc = start_sp; +#endif + +#if CALL_DUMMY_LOCATION == ON_STACK + write_memory (start_sp, (char *)dummy1, sizeof dummy1); +#endif /* On stack. */ + +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END + /* Convex Unix prohibits executing in the stack segment. */ + /* Hope there is empty room at the top of the text segment. */ + { + extern CORE_ADDR text_end; + static checked = 0; + if (!checked) + for (start_sp = text_end - sizeof dummy1; start_sp < text_end; ++start_sp) + if (read_memory_integer (start_sp, 1) != 0) + error ("text segment full -- no place to put call"); + checked = 1; + sp = old_sp; + real_pc = text_end - sizeof dummy1; + write_memory (real_pc, (char *)dummy1, sizeof dummy1); + } +#endif /* Before text_end. */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END + { + extern CORE_ADDR text_end; + int errcode; + sp = old_sp; + real_pc = text_end; + errcode = target_write_memory (real_pc, (char *)dummy1, sizeof dummy1); + if (errcode != 0) + error ("Cannot write text segment -- call_function failed"); + } +#endif /* After text_end. */ + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + real_pc = funaddr; +#endif /* At entry point. */ + +#ifdef lint + sp = old_sp; /* It really is used, for some ifdef's... */ +#endif + + if (nargs < TYPE_NFIELDS (ftype)) + error ("too few arguments in function call"); + + for (i = nargs - 1; i >= 0; i--) + { + struct type *param_type; + if (TYPE_NFIELDS (ftype) > i) + param_type = TYPE_FIELD_TYPE (ftype, i); + else + param_type = 0; + args[i] = value_arg_coerce (args[i], param_type); + } + +#if defined (REG_STRUCT_HAS_ADDR) + { + /* This is a machine like the sparc, where we may need to pass a pointer + to the structure, not the structure itself. */ + for (i = nargs - 1; i >= 0; i--) + { + struct type *arg_type = check_typedef (VALUE_TYPE (args[i])); + if ((TYPE_CODE (arg_type) == TYPE_CODE_STRUCT + || TYPE_CODE (arg_type) == TYPE_CODE_UNION + || TYPE_CODE (arg_type) == TYPE_CODE_ARRAY + || TYPE_CODE (arg_type) == TYPE_CODE_STRING + || TYPE_CODE (arg_type) == TYPE_CODE_BITSTRING + || TYPE_CODE (arg_type) == TYPE_CODE_SET + || (TYPE_CODE (arg_type) == TYPE_CODE_FLT + && TYPE_LENGTH (arg_type) > 8) + ) + && REG_STRUCT_HAS_ADDR (using_gcc, arg_type)) + { + CORE_ADDR addr; + int len = TYPE_LENGTH (arg_type); +#ifdef STACK_ALIGN + int aligned_len = STACK_ALIGN (len); +#else + int aligned_len = len; +#endif +#if !(1 INNER_THAN 2) + /* The stack grows up, so the address of the thing we push + is the stack pointer before we push it. */ + addr = sp; +#else + sp -= aligned_len; +#endif + /* Push the structure. */ + write_memory (sp, VALUE_CONTENTS (args[i]), len); +#if 1 INNER_THAN 2 + /* The stack grows down, so the address of the thing we push + is the stack pointer after we push it. */ + addr = sp; +#else + sp += aligned_len; +#endif + /* The value we're going to pass is the address of the thing + we just pushed. */ + args[i] = value_from_longest (lookup_pointer_type (value_type), + (LONGEST) addr); + } + } + } +#endif /* REG_STRUCT_HAS_ADDR. */ + + /* Reserve space for the return structure to be written on the + stack, if necessary */ + + if (struct_return) + { + int len = TYPE_LENGTH (value_type); +#ifdef STACK_ALIGN + len = STACK_ALIGN (len); +#endif +#if 1 INNER_THAN 2 + sp -= len; + struct_addr = sp; +#else + struct_addr = sp; + sp += len; +#endif + } + +#ifdef STACK_ALIGN + /* If stack grows down, we must leave a hole at the top. */ + { + int len = 0; + + for (i = nargs - 1; i >= 0; i--) + len += TYPE_LENGTH (VALUE_TYPE (args[i])); +#ifdef CALL_DUMMY_STACK_ADJUST + len += CALL_DUMMY_STACK_ADJUST; +#endif +#if 1 INNER_THAN 2 + sp -= STACK_ALIGN (len) - len; +#else + sp += STACK_ALIGN (len) - len; +#endif + } +#endif /* STACK_ALIGN */ + +#ifdef PUSH_ARGUMENTS + PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr); +#else /* !PUSH_ARGUMENTS */ + for (i = nargs - 1; i >= 0; i--) + sp = value_push (sp, args[i]); +#endif /* !PUSH_ARGUMENTS */ + +#ifdef CALL_DUMMY_STACK_ADJUST +#if 1 INNER_THAN 2 + sp -= CALL_DUMMY_STACK_ADJUST; +#else + sp += CALL_DUMMY_STACK_ADJUST; +#endif +#endif /* CALL_DUMMY_STACK_ADJUST */ + + /* Store the address at which the structure is supposed to be + written. Note that this (and the code which reserved the space + above) assumes that gcc was used to compile this function. Since + it doesn't cost us anything but space and if the function is pcc + it will ignore this value, we will make that assumption. + + Also note that on some machines (like the sparc) pcc uses a + convention like gcc's. */ + + if (struct_return) + STORE_STRUCT_RETURN (struct_addr, sp); + + /* Write the stack pointer. This is here because the statements above + might fool with it. On SPARC, this write also stores the register + window into the right place in the new stack frame, which otherwise + wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */ + write_sp (sp); + + { + char retbuf[REGISTER_BYTES]; + char *name; + struct symbol *symbol; + + name = NULL; + symbol = find_pc_function (funaddr); + if (symbol) + { + name = SYMBOL_SOURCE_NAME (symbol); + } + else + { + /* Try the minimal symbols. */ + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr); + + if (msymbol) + { + name = SYMBOL_SOURCE_NAME (msymbol); + } + } + if (name == NULL) + { + char format[80]; + sprintf (format, "at %s", local_hex_format ()); + name = alloca (80); + /* FIXME-32x64: assumes funaddr fits in a long. */ + sprintf (name, format, (unsigned long) funaddr); + } + + /* Execute the stack dummy routine, calling FUNCTION. + When it is done, discard the empty frame + after storing the contents of all regs into retbuf. */ + if (run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf)) + { + /* We stopped somewhere besides the call dummy. */ + + /* If we did the cleanups, we would print a spurious error message + (Unable to restore previously selected frame), would write the + registers from the inf_status (which is wrong), and would do other + wrong things (like set stop_bpstat to the wrong thing). */ + discard_cleanups (old_chain); + /* Prevent memory leak. */ + bpstat_clear (&inf_status.stop_bpstat); + + /* The following error message used to say "The expression + which contained the function call has been discarded." It + is a hard concept to explain in a few words. Ideally, GDB + would be able to resume evaluation of the expression when + the function finally is done executing. Perhaps someday + this will be implemented (it would not be easy). */ + + /* FIXME: Insert a bunch of wrap_here; name can be very long if it's + a C++ name with arguments and stuff. */ + error ("\ +The program being debugged stopped while in a function called from GDB.\n\ +When the function (%s) is done executing, GDB will silently\n\ +stop (instead of continuing to evaluate the expression containing\n\ +the function call).", name); + } + + do_cleanups (old_chain); + + /* Figure out the value returned by the function. */ + return value_being_returned (value_type, retbuf, struct_return); + } +} +#else /* no CALL_DUMMY. */ +value_ptr +call_function_by_hand (function, nargs, args) + value_ptr function; + int nargs; + value_ptr *args; +{ + error ("Cannot invoke functions on this machine."); +} +#endif /* no CALL_DUMMY. */ + + +/* Create a value for an array by allocating space in the inferior, copying + the data into that space, and then setting up an array value. + + The array bounds are set from LOWBOUND and HIGHBOUND, and the array is + populated from the values passed in ELEMVEC. + + The element type of the array is inherited from the type of the + first element, and all elements must have the same size (though we + don't currently enforce any restriction on their types). */ + +value_ptr +value_array (lowbound, highbound, elemvec) + int lowbound; + int highbound; + value_ptr *elemvec; +{ + int nelem; + int idx; + unsigned int typelength; + value_ptr val; + struct type *rangetype; + struct type *arraytype; + CORE_ADDR addr; + + /* Validate that the bounds are reasonable and that each of the elements + have the same size. */ + + nelem = highbound - lowbound + 1; + if (nelem <= 0) + { + error ("bad array bounds (%d, %d)", lowbound, highbound); + } + typelength = TYPE_LENGTH (VALUE_TYPE (elemvec[0])); + for (idx = 1; idx < nelem; idx++) + { + if (TYPE_LENGTH (VALUE_TYPE (elemvec[idx])) != typelength) + { + error ("array elements must all be the same size"); + } + } + + rangetype = create_range_type ((struct type *) NULL, builtin_type_int, + lowbound, highbound); + arraytype = create_array_type ((struct type *) NULL, + VALUE_TYPE (elemvec[0]), rangetype); + + if (!current_language->c_style_arrays) + { + val = allocate_value (arraytype); + for (idx = 0; idx < nelem; idx++) + { + memcpy (VALUE_CONTENTS_RAW (val) + (idx * typelength), + VALUE_CONTENTS (elemvec[idx]), + typelength); + } + return val; + } + + /* Allocate space to store the array in the inferior, and then initialize + it by copying in each element. FIXME: Is it worth it to create a + local buffer in which to collect each value and then write all the + bytes in one operation? */ + + addr = allocate_space_in_inferior (nelem * typelength); + for (idx = 0; idx < nelem; idx++) + { + write_memory (addr + (idx * typelength), VALUE_CONTENTS (elemvec[idx]), + typelength); + } + + /* Create the array type and set up an array value to be evaluated lazily. */ + + val = value_at_lazy (arraytype, addr); + return (val); +} + +/* Create a value for a string constant by allocating space in the inferior, + copying the data into that space, and returning the address with type + TYPE_CODE_STRING. PTR points to the string constant data; LEN is number + of characters. + Note that string types are like array of char types with a lower bound of + zero and an upper bound of LEN - 1. Also note that the string may contain + embedded null bytes. */ + +value_ptr +value_string (ptr, len) + char *ptr; + int len; +{ + value_ptr val; + int lowbound = current_language->string_lower_bound; + struct type *rangetype = create_range_type ((struct type *) NULL, + builtin_type_int, + lowbound, len + lowbound - 1); + struct type *stringtype + = create_string_type ((struct type *) NULL, rangetype); + CORE_ADDR addr; + + if (current_language->c_style_arrays == 0) + { + val = allocate_value (stringtype); + memcpy (VALUE_CONTENTS_RAW (val), ptr, len); + return val; + } + + + /* Allocate space to store the string in the inferior, and then + copy LEN bytes from PTR in gdb to that address in the inferior. */ + + addr = allocate_space_in_inferior (len); + write_memory (addr, ptr, len); + + val = value_at_lazy (stringtype, addr); + return (val); +} + +value_ptr +value_bitstring (ptr, len) + char *ptr; + int len; +{ + value_ptr val; + struct type *domain_type = create_range_type (NULL, builtin_type_int, + 0, len - 1); + struct type *type = create_set_type ((struct type*) NULL, domain_type); + TYPE_CODE (type) = TYPE_CODE_BITSTRING; + val = allocate_value (type); + memcpy (VALUE_CONTENTS_RAW (val), ptr, TYPE_LENGTH (type)); + return val; +} + +/* See if we can pass arguments in T2 to a function which takes arguments + of types T1. Both t1 and t2 are NULL-terminated vectors. If some + arguments need coercion of some sort, then the coerced values are written + into T2. Return value is 0 if the arguments could be matched, or the + position at which they differ if not. + + STATICP is nonzero if the T1 argument list came from a + static member function. + + For non-static member functions, we ignore the first argument, + which is the type of the instance variable. This is because we want + to handle calls with objects from derived classes. This is not + entirely correct: we should actually check to make sure that a + requested operation is type secure, shouldn't we? FIXME. */ + +static int +typecmp (staticp, t1, t2) + int staticp; + struct type *t1[]; + value_ptr t2[]; +{ + int i; + + if (t2 == 0) + return 1; + if (staticp && t1 == 0) + return t2[1] != 0; + if (t1 == 0) + return 1; + if (TYPE_CODE (t1[0]) == TYPE_CODE_VOID) return 0; + if (t1[!staticp] == 0) return 0; + for (i = !staticp; t1[i] && TYPE_CODE (t1[i]) != TYPE_CODE_VOID; i++) + { + struct type *tt1, *tt2; + if (! t2[i]) + return i+1; + tt1 = check_typedef (t1[i]); + tt2 = check_typedef (VALUE_TYPE(t2[i])); + if (TYPE_CODE (tt1) == TYPE_CODE_REF + /* We should be doing hairy argument matching, as below. */ + && (TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (tt1))) == TYPE_CODE (tt2))) + { + if (TYPE_CODE (tt2) == TYPE_CODE_ARRAY) + t2[i] = value_coerce_array (t2[i]); + else + t2[i] = value_addr (t2[i]); + continue; + } + + while (TYPE_CODE (tt1) == TYPE_CODE_PTR + && ( TYPE_CODE (tt2) == TYPE_CODE_ARRAY + || TYPE_CODE (tt2) == TYPE_CODE_PTR)) + { + tt1 = check_typedef (TYPE_TARGET_TYPE(tt1)); + tt2 = check_typedef (TYPE_TARGET_TYPE(tt2)); + } + if (TYPE_CODE(tt1) == TYPE_CODE(tt2)) continue; + /* Array to pointer is a `trivial conversion' according to the ARM. */ + + /* We should be doing much hairier argument matching (see section 13.2 + of the ARM), but as a quick kludge, just check for the same type + code. */ + if (TYPE_CODE (t1[i]) != TYPE_CODE (VALUE_TYPE (t2[i]))) + return i+1; + } + if (!t1[i]) return 0; + return t2[i] ? i+1 : 0; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and search in it assuming it has (class) type TYPE. + If found, return value, else return NULL. + + If LOOKING_FOR_BASECLASS, then instead of looking for struct fields, + look for a baseclass named NAME. */ + +static value_ptr +search_struct_field (name, arg1, offset, type, looking_for_baseclass) + char *name; + register value_ptr arg1; + int offset; + register struct type *type; + int looking_for_baseclass; +{ + int i; + + CHECK_TYPEDEF (type); + + if (! looking_for_baseclass) + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + value_ptr v; + if (TYPE_FIELD_STATIC (type, i)) + { + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (sym == NULL) + error ("Internal error: could not find physical static variable named %s", + phys_name); + v = value_at (TYPE_FIELD_TYPE (type, i), + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + } + else + v = value_primitive_field (arg1, offset, i, type); + if (v == 0) + error("there is no field named %s", name); + return v; + } + + if (t_field_name + && (t_field_name[0] == '\0' + || (TYPE_CODE (type) == TYPE_CODE_UNION + && STREQ (t_field_name, "else")))) + { + struct type *field_type = TYPE_FIELD_TYPE (type, i); + if (TYPE_CODE (field_type) == TYPE_CODE_UNION + || TYPE_CODE (field_type) == TYPE_CODE_STRUCT) + { + /* Look for a match through the fields of an anonymous union, + or anonymous struct. C++ provides anonymous unions. + + In the GNU Chill implementation of variant record types, + each has an (anonymous) union type, + each member of the union represents a . + Each is represented as a struct, + with a member for each . */ + + value_ptr v; + int new_offset = offset; + + /* This is pretty gross. In G++, the offset in an anonymous + union is relative to the beginning of the enclosing struct. + In the GNU Chill implementation of variant records, + the bitpos is zero in an anonymous union field, so we + have to add the offset of the union here. */ + if (TYPE_CODE (field_type) == TYPE_CODE_STRUCT + || (TYPE_NFIELDS (field_type) > 0 + && TYPE_FIELD_BITPOS (field_type, 0) == 0)) + new_offset += TYPE_FIELD_BITPOS (type, i) / 8; + + v = search_struct_field (name, arg1, new_offset, field_type, + looking_for_baseclass); + if (v) + return v; + } + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + value_ptr v; + struct type *basetype = check_typedef (TYPE_BASECLASS (type, i)); + /* If we are looking for baseclasses, this is what we get when we + hit them. But it could happen that the base part's member name + is not yet filled in. */ + int found_baseclass = (looking_for_baseclass + && TYPE_BASECLASS_NAME (type, i) != NULL + && STREQ (name, TYPE_BASECLASS_NAME (type, i))); + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + int boffset = VALUE_OFFSET (arg1) + offset; + boffset = baseclass_offset (type, i, + VALUE_CONTENTS (arg1) + boffset, + VALUE_ADDRESS (arg1) + boffset); + if (boffset == -1) + error ("virtual baseclass botch"); + if (found_baseclass) + { + value_ptr v2 = allocate_value (basetype); + VALUE_LVAL (v2) = VALUE_LVAL (arg1); + VALUE_ADDRESS (v2) = VALUE_ADDRESS (arg1); + VALUE_OFFSET (v2) = VALUE_OFFSET (arg1) + offset + boffset; + if (VALUE_LAZY (arg1)) + VALUE_LAZY (v2) = 1; + else + memcpy (VALUE_CONTENTS_RAW (v2), + VALUE_CONTENTS_RAW (arg1) + offset + boffset, + TYPE_LENGTH (basetype)); + return v2; + } + v = search_struct_field (name, arg1, offset + boffset, + TYPE_BASECLASS (type, i), + looking_for_baseclass); + } + else if (found_baseclass) + v = value_primitive_field (arg1, offset, i, type); + else + v = search_struct_field (name, arg1, + offset + TYPE_BASECLASS_BITPOS (type, i) / 8, + basetype, looking_for_baseclass); + if (v) return v; + } + return NULL; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and search in it assuming it has (class) type TYPE. + If found, return value, else if name matched and args not return (value)-1, + else return NULL. */ + +static value_ptr +search_struct_method (name, arg1p, args, offset, static_memfuncp, type) + char *name; + register value_ptr *arg1p, *args; + int offset, *static_memfuncp; + register struct type *type; +{ + int i; + value_ptr v; + int name_matched = 0; + char dem_opname[64]; + + CHECK_TYPEDEF (type); + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--) + { + char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i); + if (strncmp(t_field_name, "__", 2)==0 || + strncmp(t_field_name, "op", 2)==0 || + strncmp(t_field_name, "type", 4)==0 ) + { + if (cplus_demangle_opname(t_field_name, dem_opname, DMGL_ANSI)) + t_field_name = dem_opname; + else if (cplus_demangle_opname(t_field_name, dem_opname, 0)) + t_field_name = dem_opname; + } + if (t_field_name && STREQ (t_field_name, name)) + { + int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1; + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + name_matched = 1; + + if (j > 0 && args == 0) + error ("cannot resolve overloaded method `%s'", name); + while (j >= 0) + { + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (type, i, j); + if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j), + TYPE_FN_FIELD_ARGS (f, j), args)) + { + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + return value_virtual_fn_field (arg1p, f, j, type, offset); + if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp) + *static_memfuncp = 1; + v = value_fn_field (arg1p, f, j, type, offset); + if (v != NULL) return v; + } + j--; + } + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + int base_offset; + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + base_offset = VALUE_OFFSET (*arg1p) + offset; + base_offset = + baseclass_offset (type, i, + VALUE_CONTENTS (*arg1p) + base_offset, + VALUE_ADDRESS (*arg1p) + base_offset); + if (base_offset == -1) + error ("virtual baseclass botch"); + } + else + { + base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8; + } + v = search_struct_method (name, arg1p, args, base_offset + offset, + static_memfuncp, TYPE_BASECLASS (type, i)); + if (v == (value_ptr) -1) + { + name_matched = 1; + } + else if (v) + { +/* FIXME-bothner: Why is this commented out? Why is it here? */ +/* *arg1p = arg1_tmp;*/ + return v; + } + } + if (name_matched) return (value_ptr) -1; + else return NULL; +} + +/* Given *ARGP, a value of type (pointer to a)* structure/union, + extract the component named NAME from the ultimate target structure/union + and return it as a value with its appropriate type. + ERR is used in the error message if *ARGP's type is wrong. + + C++: ARGS is a list of argument types to aid in the selection of + an appropriate method. Also, handle derived types. + + STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location + where the truthvalue of whether the function that was resolved was + a static member function or not is stored. + + ERR is an error message to be printed in case the field is not found. */ + +value_ptr +value_struct_elt (argp, args, name, static_memfuncp, err) + register value_ptr *argp, *args; + char *name; + int *static_memfuncp; + char *err; +{ + register struct type *t; + value_ptr v; + + COERCE_ARRAY (*argp); + + t = check_typedef (VALUE_TYPE (*argp)); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + *argp = value_ind (*argp); + /* Don't coerce fn pointer to fn and then back again! */ + if (TYPE_CODE (VALUE_TYPE (*argp)) != TYPE_CODE_FUNC) + COERCE_ARRAY (*argp); + t = check_typedef (VALUE_TYPE (*argp)); + } + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in value_struct_elt"); + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Attempt to extract a component of a value that is not a %s.", err); + + /* Assume it's not, unless we see that it is. */ + if (static_memfuncp) + *static_memfuncp =0; + + if (!args) + { + /* if there are no arguments ...do this... */ + + /* Try as a field first, because if we succeed, there + is less work to be done. */ + v = search_struct_field (name, *argp, 0, t, 0); + if (v) + return v; + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + if (destructor_name_p (name, t)) + error ("Cannot get value of destructor"); + + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); + + if (v == (value_ptr) -1) + error ("Cannot take address of a method"); + else if (v == 0) + { + if (TYPE_NFN_FIELDS (t)) + error ("There is no member or method named %s.", name); + else + error ("There is no member named %s.", name); + } + return v; + } + + if (destructor_name_p (name, t)) + { + if (!args[1]) + { + /* destructors are a special case. */ + v = value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0), + TYPE_FN_FIELDLIST_LENGTH (t, 0), 0, 0); + if (!v) error("could not find destructor function named %s.", name); + else return v; + } + else + { + error ("destructor should not have any argument"); + } + } + else + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); + + if (v == (value_ptr) -1) + { + error("Argument list of %s mismatch with component in the structure.", name); + } + else if (v == 0) + { + /* See if user tried to invoke data as function. If so, + hand it back. If it's not callable (i.e., a pointer to function), + gdb should give an error. */ + v = search_struct_field (name, *argp, 0, t, 0); + } + + if (!v) + error ("Structure has no component named %s.", name); + return v; +} + +/* C++: return 1 is NAME is a legitimate name for the destructor + of type TYPE. If TYPE does not have a destructor, or + if NAME is inappropriate for TYPE, an error is signaled. */ +int +destructor_name_p (name, type) + const char *name; + const struct type *type; +{ + /* destructors are a special case. */ + + if (name[0] == '~') + { + char *dname = type_name_no_tag (type); + char *cp = strchr (dname, '<'); + unsigned int len; + + /* Do not compare the template part for template classes. */ + if (cp == NULL) + len = strlen (dname); + else + len = cp - dname; + if (strlen (name + 1) != len || !STREQN (dname, name + 1, len)) + error ("name of destructor must equal name of class"); + else + return 1; + } + return 0; +} + +/* Helper function for check_field: 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_in (type, name) + register struct type *type; + const char *name; +{ + register int i; + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + if (t_field_name && STREQ (t_field_name, name)) + return 1; + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + /* Destructors are a special case. */ + if (destructor_name_p (name, type)) + return 1; + + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) + { + if (STREQ (TYPE_FN_FIELDLIST_NAME (type, i), name)) + return 1; + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + if (check_field_in (TYPE_BASECLASS (type, i), name)) + return 1; + + return 0; +} + + +/* C++: Given ARG1, a value of type (pointer to a)* structure/union, + return 1 if the component named NAME from the ultimate + target structure/union is defined, otherwise, return 0. */ + +int +check_field (arg1, name) + register value_ptr arg1; + const char *name; +{ + register struct type *t; + + COERCE_ARRAY (arg1); + + t = VALUE_TYPE (arg1); + + /* Follow pointers until we get to a non-pointer. */ + + for (;;) + { + CHECK_TYPEDEF (t); + if (TYPE_CODE (t) != TYPE_CODE_PTR && TYPE_CODE (t) != TYPE_CODE_REF) + break; + t = TYPE_TARGET_TYPE (t); + } + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in check_field"); + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: `this' is not an aggregate"); + + return check_field_in (t, name); +} + +/* C++: Given an aggregate type CURTYPE, and a member name NAME, + return the address of this member as a "pointer to member" + type. If INTYPE is non-null, then it will be the type + of the member we are looking for. This will help us resolve + "pointers to member functions". This function is used + to resolve user expressions of the form "DOMAIN::NAME". */ + +value_ptr +value_struct_elt_for_reference (domain, offset, curtype, name, intype) + struct type *domain, *curtype, *intype; + int offset; + char *name; +{ + register struct type *t = curtype; + register int i; + value_ptr v; + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: non-aggregate type to value_struct_elt_for_reference"); + + for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--) + { + char *t_field_name = TYPE_FIELD_NAME (t, i); + + if (t_field_name && STREQ (t_field_name, name)) + { + if (TYPE_FIELD_STATIC (t, i)) + { + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (sym == NULL) + error ("Internal error: could not find physical static variable named %s", + phys_name); + return value_at (SYMBOL_TYPE (sym), + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + } + if (TYPE_FIELD_PACKED (t, i)) + error ("pointers to bitfield members not allowed"); + + return value_from_longest + (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i), + domain)), + offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3)); + } + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + /* Destructors are a special case. */ + if (destructor_name_p (name, t)) + { + error ("member pointers to destructors not implemented yet"); + } + + /* Perform all necessary dereferencing. */ + while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR) + intype = TYPE_TARGET_TYPE (intype); + + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i) + { + char *t_field_name = TYPE_FN_FIELDLIST_NAME (t, i); + char dem_opname[64]; + + if (strncmp(t_field_name, "__", 2)==0 || + strncmp(t_field_name, "op", 2)==0 || + strncmp(t_field_name, "type", 4)==0 ) + { + if (cplus_demangle_opname(t_field_name, dem_opname, DMGL_ANSI)) + t_field_name = dem_opname; + else if (cplus_demangle_opname(t_field_name, dem_opname, 0)) + t_field_name = dem_opname; + } + if (t_field_name && STREQ (t_field_name, name)) + { + int j = TYPE_FN_FIELDLIST_LENGTH (t, i); + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); + + if (intype == 0 && j > 1) + error ("non-unique member `%s' requires type instantiation", name); + if (intype) + { + while (j--) + if (TYPE_FN_FIELD_TYPE (f, j) == intype) + break; + if (j < 0) + error ("no member function matches that type instantiation"); + } + else + j = 0; + + if (TYPE_FN_FIELD_STUB (f, j)) + check_stub_method (t, i, j); + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + { + return value_from_longest + (lookup_reference_type + (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), + domain)), + (LONGEST) METHOD_PTR_FROM_VOFFSET (TYPE_FN_FIELD_VOFFSET (f, j))); + } + else + { + struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), + 0, VAR_NAMESPACE, 0, NULL); + if (s == NULL) + { + v = 0; + } + else + { + v = read_var_value (s, 0); +#if 0 + VALUE_TYPE (v) = lookup_reference_type + (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), + domain)); +#endif + } + return v; + } + } + } + for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--) + { + value_ptr v; + int base_offset; + + if (BASETYPE_VIA_VIRTUAL (t, i)) + base_offset = 0; + else + base_offset = TYPE_BASECLASS_BITPOS (t, i) / 8; + v = value_struct_elt_for_reference (domain, + offset + base_offset, + TYPE_BASECLASS (t, i), + name, + intype); + if (v) + return v; + } + return 0; +} + +/* C++: return the value of the class instance variable, if one exists. + Flag COMPLAIN signals an error if the request is made in an + inappropriate context. */ + +value_ptr +value_of_this (complain) + int complain; +{ + struct symbol *func, *sym; + struct block *b; + int i; + static const char funny_this[] = "this"; + value_ptr this; + + if (selected_frame == 0) + if (complain) + error ("no frame selected"); + else return 0; + + func = get_frame_function (selected_frame); + if (!func) + { + if (complain) + error ("no `this' in nameless context"); + else return 0; + } + + b = SYMBOL_BLOCK_VALUE (func); + i = BLOCK_NSYMS (b); + if (i <= 0) + if (complain) + error ("no args, no `this'"); + else return 0; + + /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER + symbol instead of the LOC_ARG one (if both exist). */ + sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE); + if (sym == NULL) + { + if (complain) + error ("current stack frame not in method"); + else + return NULL; + } + + this = read_var_value (sym, selected_frame); + if (this == 0 && complain) + error ("`this' argument at unknown address"); + return this; +} + +/* Create a slice (sub-string, sub-array) of ARRAY, that is LENGTH elements + long, starting at LOWBOUND. The result has the same lower bound as + the original ARRAY. */ + +value_ptr +value_slice (array, lowbound, length) + value_ptr array; + int lowbound, length; +{ + struct type *slice_range_type, *slice_type, *range_type; + LONGEST lowerbound, upperbound, offset; + value_ptr slice; + struct type *array_type; + array_type = check_typedef (VALUE_TYPE (array)); + COERCE_VARYING_ARRAY (array, array_type); + if (TYPE_CODE (array_type) != TYPE_CODE_ARRAY + && TYPE_CODE (array_type) != TYPE_CODE_STRING + && TYPE_CODE (array_type) != TYPE_CODE_BITSTRING) + error ("cannot take slice of non-array"); + range_type = TYPE_INDEX_TYPE (array_type); + if (get_discrete_bounds (range_type, &lowerbound, &upperbound) < 0) + error ("slice from bad array or bitstring"); + if (lowbound < lowerbound || length < 0 + || lowbound + length - 1 > upperbound + /* Chill allows zero-length strings but not arrays. */ + || (current_language->la_language == language_chill + && length == 0 && TYPE_CODE (array_type) == TYPE_CODE_ARRAY)) + error ("slice out of range"); + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + slice_range_type = create_range_type ((struct type*) NULL, + TYPE_TARGET_TYPE (range_type), + lowerbound, lowerbound + length - 1); + if (TYPE_CODE (array_type) == TYPE_CODE_BITSTRING) + { + int i; + slice_type = create_set_type ((struct type*) NULL, slice_range_type); + TYPE_CODE (slice_type) = TYPE_CODE_BITSTRING; + slice = value_zero (slice_type, not_lval); + for (i = 0; i < length; i++) + { + int element = value_bit_index (array_type, + VALUE_CONTENTS (array), + lowbound + i); + if (element < 0) + error ("internal error accessing bitstring"); + else if (element > 0) + { + int j = i % TARGET_CHAR_BIT; + if (BITS_BIG_ENDIAN) + j = TARGET_CHAR_BIT - 1 - j; + VALUE_CONTENTS_RAW (slice)[i / TARGET_CHAR_BIT] |= (1 << j); + } + } + /* We should set the address, bitssize, and bitspos, so the clice + can be used on the LHS, but that may require extensions to + value_assign. For now, just leave as a non_lval. FIXME. */ + } + else + { + struct type *element_type = TYPE_TARGET_TYPE (array_type); + offset + = (lowbound - lowerbound) * TYPE_LENGTH (check_typedef (element_type)); + slice_type = create_array_type ((struct type*) NULL, element_type, + slice_range_type); + TYPE_CODE (slice_type) = TYPE_CODE (array_type); + slice = allocate_value (slice_type); + if (VALUE_LAZY (array)) + VALUE_LAZY (slice) = 1; + else + memcpy (VALUE_CONTENTS (slice), VALUE_CONTENTS (array) + offset, + TYPE_LENGTH (slice_type)); + if (VALUE_LVAL (array) == lval_internalvar) + VALUE_LVAL (slice) = lval_internalvar_component; + else + VALUE_LVAL (slice) = VALUE_LVAL (array); + VALUE_ADDRESS (slice) = VALUE_ADDRESS (array); + VALUE_OFFSET (slice) = VALUE_OFFSET (array) + offset; + } + return slice; +} + +/* Assuming chill_varying_type (VARRAY) is true, return an equivalent + value as a fixed-length array. */ + +value_ptr +varying_to_slice (varray) + value_ptr varray; +{ + struct type *vtype = check_typedef (VALUE_TYPE (varray)); + LONGEST length = unpack_long (TYPE_FIELD_TYPE (vtype, 0), + VALUE_CONTENTS (varray) + + TYPE_FIELD_BITPOS (vtype, 0) / 8); + return value_slice (value_primitive_field (varray, 0, 1, vtype), 0, length); +} + +/* Create a value for a FORTRAN complex number. Currently most of + the time values are coerced to COMPLEX*16 (i.e. a complex number + composed of 2 doubles. This really should be a smarter routine + that figures out precision inteligently as opposed to assuming + doubles. FIXME: fmb */ + +value_ptr +value_literal_complex (arg1, arg2, type) + value_ptr arg1; + value_ptr arg2; + struct type *type; +{ + register value_ptr val; + struct type *real_type = TYPE_TARGET_TYPE (type); + + val = allocate_value (type); + arg1 = value_cast (real_type, arg1); + arg2 = value_cast (real_type, arg2); + + memcpy (VALUE_CONTENTS_RAW (val), + VALUE_CONTENTS (arg1), TYPE_LENGTH (real_type)); + memcpy (VALUE_CONTENTS_RAW (val) + TYPE_LENGTH (real_type), + VALUE_CONTENTS (arg2), TYPE_LENGTH (real_type)); + return val; +} + +/* Cast a value into the appropriate complex data type. */ + +static value_ptr +cast_into_complex (type, val) + struct type *type; + register value_ptr val; +{ + struct type *real_type = TYPE_TARGET_TYPE (type); + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_COMPLEX) + { + struct type *val_real_type = TYPE_TARGET_TYPE (VALUE_TYPE (val)); + value_ptr re_val = allocate_value (val_real_type); + value_ptr im_val = allocate_value (val_real_type); + + memcpy (VALUE_CONTENTS_RAW (re_val), + VALUE_CONTENTS (val), TYPE_LENGTH (val_real_type)); + memcpy (VALUE_CONTENTS_RAW (im_val), + VALUE_CONTENTS (val) + TYPE_LENGTH (val_real_type), + TYPE_LENGTH (val_real_type)); + + return value_literal_complex (re_val, im_val, type); + } + else if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT) + return value_literal_complex (val, value_zero (real_type, not_lval), type); + else + error ("cannot cast non-number to complex"); +} + +void +_initialize_valops () +{ +#if 0 + add_show_from_set + (add_set_cmd ("abandon", class_support, var_boolean, (char *)&auto_abandon, + "Set automatic abandonment of expressions upon failure.", + &setlist), + &showlist); +#endif +} diff --git a/contrib/gdb/gdb/valprint.c b/contrib/gdb/gdb/valprint.c new file mode 100644 index 000000000000..ce113cecd7fa --- /dev/null +++ b/contrib/gdb/gdb/valprint.c @@ -0,0 +1,1015 @@ +/* Print values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "target.h" +#include "obstack.h" +#include "language.h" +#include "demangle.h" +#include "annotate.h" + +#include + +/* Prototypes for local functions */ + +static void +print_hex_chars PARAMS ((GDB_FILE *, unsigned char *, unsigned int)); + +static void +show_print PARAMS ((char *, int)); + +static void +set_print PARAMS ((char *, int)); + +static void +set_radix PARAMS ((char *, int)); + +static void +show_radix PARAMS ((char *, int)); + +static void +set_input_radix PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_input_radix_1 PARAMS ((int, unsigned)); + +static void +set_output_radix PARAMS ((char *, int, struct cmd_list_element *)); + +static void +set_output_radix_1 PARAMS ((int, unsigned)); + +/* Maximum number of chars to print for a string pointer value or vector + contents, or UINT_MAX for no limit. Note that "set print elements 0" + stores UINT_MAX in print_max, which displays in a show command as + "unlimited". */ + +unsigned int print_max; +#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */ + +/* Default input and output radixes, and output format letter. */ + +unsigned input_radix = 10; +unsigned output_radix = 10; +int output_format = 0; + +/* Print repeat counts if there are more than this many repetitions of an + element in an array. Referenced by the low level language dependent + print routines. */ + +unsigned int repeat_count_threshold = 10; + +/* If nonzero, stops printing of char arrays at first null. */ + +int stop_print_at_null; + +/* Controls pretty printing of structures. */ + +int prettyprint_structs; + +/* Controls pretty printing of arrays. */ + +int prettyprint_arrays; + +/* If nonzero, causes unions inside structures or other unions to be + printed. */ + +int unionprint; /* Controls printing of nested unions. */ + +/* If nonzero, causes machine addresses to be printed in certain contexts. */ + +int addressprint; /* Controls printing of machine addresses */ + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter, or 0 for natural format using TYPE). + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + The PRETTY parameter controls prettyprinting. + + If the data are a string pointer, returns the number of string characters + printed. + + FIXME: The data at VALADDR is in target byte order. If gdb is ever + enhanced to be able to debug more than the single target it was compiled + for (specific CPU type and thus specific target byte ordering), then + either the print routines are going to have to take this into account, + or the data is going to have to be passed into here already converted + to the host byte ordering, whichever is more convenient. */ + + +int +val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + struct type *real_type = check_typedef (type); + if (pretty == Val_pretty_default) + { + pretty = prettyprint_structs ? Val_prettyprint : Val_no_prettyprint; + } + + QUIT; + + /* Ensure that the type is complete and not just a stub. If the type is + only a stub and we can't find and substitute its complete type, then + print appropriate string and return. */ + + if (TYPE_FLAGS (real_type) & TYPE_FLAG_STUB) + { + fprintf_filtered (stream, ""); + gdb_flush (stream); + return (0); + } + + return (LA_VAL_PRINT (type, valaddr, address, stream, format, deref_ref, + recurse, pretty)); +} + +/* Print the value VAL in C-ish syntax on stream STREAM. + FORMAT is a format-letter, or 0 for print in natural format of data type. + If the object printed is a string pointer, returns + the number of string bytes printed. */ + +int +value_print (val, stream, format, pretty) + value_ptr val; + GDB_FILE *stream; + int format; + enum val_prettyprint pretty; +{ + if (val == 0) + { + printf_filtered ("
"); + return 0; + } + if (VALUE_OPTIMIZED_OUT (val)) + { + printf_filtered (""); + return 0; + } + return LA_VALUE_PRINT (val, stream, format, pretty); +} + +/* Called by various _val_print routines to print + TYPE_CODE_INT's. TYPE is the type. VALADDR is the address of the + value. STREAM is where to print the value. */ + +void +val_print_type_code_int (type, valaddr, stream) + struct type *type; + char *valaddr; + GDB_FILE *stream; +{ + if (TYPE_LENGTH (type) > sizeof (LONGEST)) + { + LONGEST val; + + if (TYPE_UNSIGNED (type) + && extract_long_unsigned_integer (valaddr, TYPE_LENGTH (type), + &val)) + { + print_longest (stream, 'u', 0, val); + } + else + { + /* Signed, or we couldn't turn an unsigned value into a + LONGEST. For signed values, one could assume two's + complement (a reasonable assumption, I think) and do + better than this. */ + print_hex_chars (stream, (unsigned char *) valaddr, + TYPE_LENGTH (type)); + } + } + else + { +#ifdef PRINT_TYPELESS_INTEGER + PRINT_TYPELESS_INTEGER (stream, type, unpack_long (type, valaddr)); +#else + print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, + unpack_long (type, valaddr)); +#endif + } +} + +/* Print a number according to FORMAT which is one of d,u,x,o,b,h,w,g. + The raison d'etre of this function is to consolidate printing of LONG_LONG's + into this one function. Some platforms have long longs but don't have a + printf() that supports "ll" in the format string. We handle these by seeing + if the number is actually a long, and if not we just bail out and print the + number in hex. The format chars b,h,w,g are from + print_scalar_formatted(). If USE_LOCAL, format it according to the current + language (this should be used for most integers which GDB prints, the + exception is things like protocols where the format of the integer is + a protocol thing, not a user-visible thing). */ + +void +print_longest (stream, format, use_local, val_long) + GDB_FILE *stream; + int format; + int use_local; + LONGEST val_long; +{ +#if defined (CC_HAS_LONG_LONG) && !defined (PRINTF_HAS_LONG_LONG) + long vtop, vbot; + + vtop = val_long >> (sizeof (long) * HOST_CHAR_BIT); + vbot = (long) val_long; + + if ((format == 'd' && (val_long < INT_MIN || val_long > INT_MAX)) + || ((format == 'u' || format == 'x') && (unsigned long long)val_long > UINT_MAX)) + { + fprintf_filtered (stream, "0x%lx%08lx", vtop, vbot); + return; + } +#endif + +#ifdef PRINTF_HAS_LONG_LONG + switch (format) + { + case 'd': + fprintf_filtered (stream, + use_local ? local_decimal_format_custom ("ll") + : "%lld", + val_long); + break; + case 'u': + fprintf_filtered (stream, "%llu", val_long); + break; + case 'x': + fprintf_filtered (stream, + use_local ? local_hex_format_custom ("ll") + : "%llx", + val_long); + break; + case 'o': + fprintf_filtered (stream, + use_local ? local_octal_format_custom ("ll") + : "%llo", + val_long); + break; + case 'b': + fprintf_filtered (stream, local_hex_format_custom ("02ll"), val_long); + break; + case 'h': + fprintf_filtered (stream, local_hex_format_custom ("04ll"), val_long); + break; + case 'w': + fprintf_filtered (stream, local_hex_format_custom ("08ll"), val_long); + break; + case 'g': + fprintf_filtered (stream, local_hex_format_custom ("016ll"), val_long); + break; + default: + abort (); + } +#else /* !PRINTF_HAS_LONG_LONG */ + /* In the following it is important to coerce (val_long) to a long. It does + nothing if !LONG_LONG, but it will chop off the top half (which we know + we can ignore) if the host supports long longs. */ + + switch (format) + { + case 'd': + fprintf_filtered (stream, + use_local ? local_decimal_format_custom ("l") + : "%ld", + (long) val_long); + break; + case 'u': + fprintf_filtered (stream, "%lu", (unsigned long) val_long); + break; + case 'x': + fprintf_filtered (stream, + use_local ? local_hex_format_custom ("l") + : "%lx", + (long) val_long); + break; + case 'o': + fprintf_filtered (stream, + use_local ? local_octal_format_custom ("l") + : "%lo", + (long) val_long); + break; + case 'b': + fprintf_filtered (stream, local_hex_format_custom ("02l"), + (long) val_long); + break; + case 'h': + fprintf_filtered (stream, local_hex_format_custom ("04l"), + (long) val_long); + break; + case 'w': + fprintf_filtered (stream, local_hex_format_custom ("08l"), + (long) val_long); + break; + case 'g': + fprintf_filtered (stream, local_hex_format_custom ("016l"), + (long) val_long); + break; + default: + abort (); + } +#endif /* !PRINTF_HAS_LONG_LONG */ +} + +/* This used to be a macro, but I don't think it is called often enough + to merit such treatment. */ +/* Convert a LONGEST to an int. This is used in contexts (e.g. number of + arguments to a function, number in a value history, register number, etc.) + where the value must not be larger than can fit in an int. */ + +int +longest_to_int (arg) + LONGEST arg; +{ + + /* This check is in case a system header has botched the + definition of INT_MIN, like on BSDI. */ + if (sizeof (LONGEST) <= sizeof (int)) + return arg; + + if (arg > INT_MAX || arg < INT_MIN) + error ("Value out of range."); + + return arg; +} + +/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR, + on STREAM. */ + +void +print_floating (valaddr, type, stream) + char *valaddr; + struct type *type; + GDB_FILE *stream; +{ + DOUBLEST doub; + int inv; + unsigned len = TYPE_LENGTH (type); + +#if defined (IEEE_FLOAT) + + /* Check for NaN's. Note that this code does not depend on us being + on an IEEE conforming system. It only depends on the target + machine using IEEE representation. This means (a) + cross-debugging works right, and (2) IEEE_FLOAT can (and should) + be defined for systems like the 68881, which uses IEEE + representation, but is not IEEE conforming. */ + + { + unsigned long low, high; + /* Is the sign bit 0? */ + int nonnegative; + /* Is it is a NaN (i.e. the exponent is all ones and + the fraction is nonzero)? */ + int is_nan; + + if (len == 4) + { + /* It's single precision. */ + /* Assume that floating point byte order is the same as + integer byte order. */ + low = extract_unsigned_integer (valaddr, 4); + nonnegative = ((low & 0x80000000) == 0); + is_nan = ((((low >> 23) & 0xFF) == 0xFF) + && 0 != (low & 0x7FFFFF)); + low &= 0x7fffff; + high = 0; + } + else if (len == 8) + { + /* It's double precision. Get the high and low words. */ + + /* Assume that floating point byte order is the same as + integer byte order. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + low = extract_unsigned_integer (valaddr + 4, 4); + high = extract_unsigned_integer (valaddr, 4); + } + else + { + low = extract_unsigned_integer (valaddr, 4); + high = extract_unsigned_integer (valaddr + 4, 4); + } + nonnegative = ((high & 0x80000000) == 0); + is_nan = (((high >> 20) & 0x7ff) == 0x7ff + && ! ((((high & 0xfffff) == 0)) && (low == 0))); + high &= 0xfffff; + } + else + /* Extended. We can't detect NaNs for extendeds yet. Also note + that currently extendeds get nuked to double in + REGISTER_CONVERTIBLE. */ + is_nan = 0; + + if (is_nan) + { + /* The meaning of the sign and fraction is not defined by IEEE. + But the user might know what they mean. For example, they + (in an implementation-defined manner) distinguish between + signaling and quiet NaN's. */ + if (high) + fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonnegative, + high, low); + else + fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low); + return; + } + } +#endif /* IEEE_FLOAT. */ + + doub = unpack_double (type, valaddr, &inv); + if (inv) + { + fprintf_filtered (stream, ""); + return; + } + + if (len < sizeof (double)) + fprintf_filtered (stream, "%.9g", (double) doub); + else if (len == sizeof (double)) + fprintf_filtered (stream, "%.17g", (double) doub); + else +#ifdef PRINTF_HAS_LONG_DOUBLE + fprintf_filtered (stream, "%.35Lg", doub); +#else + /* This at least wins with values that are representable as doubles */ + fprintf_filtered (stream, "%.17g", (double) doub); +#endif +} + +/* VALADDR points to an integer of LEN bytes. Print it in hex on stream. */ + +static void +print_hex_chars (stream, valaddr, len) + GDB_FILE *stream; + unsigned char *valaddr; + unsigned len; +{ + unsigned char *p; + + /* FIXME: We should be not printing leading zeroes in most cases. */ + + fprintf_filtered (stream, local_hex_format_prefix ()); + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = valaddr; + p < valaddr + len; + p++) + { + fprintf_filtered (stream, "%02x", *p); + } + } + else + { + for (p = valaddr + len - 1; + p >= valaddr; + p--) + { + fprintf_filtered (stream, "%02x", *p); + } + } + fprintf_filtered (stream, local_hex_format_suffix ()); +} + +/* Called by various _val_print routines to print elements of an + array in the form ", , , ...". + + (FIXME?) Assumes array element separator is a comma, which is correct + for all languages currently handled. + (FIXME?) Some languages have a notation for repeated array elements, + perhaps we should try to use that notation when appropriate. + */ + +void +val_print_array_elements (type, valaddr, address, stream, format, deref_ref, + recurse, pretty, i) + struct type *type; + char *valaddr; + CORE_ADDR address; + GDB_FILE *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; + unsigned int i; +{ + unsigned int things_printed = 0; + unsigned len; + struct type *elttype; + unsigned eltlen; + /* Position of the array element we are examining to see + whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (check_typedef (elttype)); + len = TYPE_LENGTH (type) / eltlen; + + annotate_array_section_begin (i, elttype); + + for (; i < len && things_printed < print_max; i++) + { + if (i != 0) + { + if (prettyprint_arrays) + { + fprintf_filtered (stream, ",\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + fprintf_filtered (stream, ", "); + } + } + wrap_here (n_spaces (2 + 2 * recurse)); + + rep1 = i + 1; + reps = 1; + while ((rep1 < len) && + !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) + { + ++reps; + ++rep1; + } + + if (reps > repeat_count_threshold) + { + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + annotate_elt_rep (reps); + fprintf_filtered (stream, " ", reps); + annotate_elt_rep_end (); + + i = rep1 - 1; + things_printed += repeat_count_threshold; + } + else + { + val_print (elttype, valaddr + i * eltlen, 0, stream, format, + deref_ref, recurse + 1, pretty); + annotate_elt (); + things_printed++; + } + } + annotate_array_section_end (); + if (i < len) + { + fprintf_filtered (stream, "..."); + } +} + +/* Print a string from the inferior, starting at ADDR and printing up to LEN + characters, to STREAM. If LEN is zero, printing stops at the first null + byte, otherwise printing proceeds (including null bytes) until either + print_max or LEN characters have been printed, whichever is smaller. */ + +/* FIXME: All callers supply LEN of zero. Supplying a non-zero LEN is + pointless, this routine just then becomes a convoluted version of + target_read_memory_partial. Removing all the LEN stuff would simplify + this routine enormously. + + FIXME: Use target_read_string. */ + +int +val_print_string (addr, len, stream) + CORE_ADDR addr; + unsigned int len; + GDB_FILE *stream; +{ + int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */ + int errcode; /* Errno returned from bad reads. */ + unsigned int fetchlimit; /* Maximum number of bytes to fetch. */ + unsigned int nfetch; /* Bytes to fetch / bytes fetched. */ + unsigned int chunksize; /* Size of each fetch, in bytes. */ + unsigned int bufsize; /* Size of current fetch buffer. */ + char *buffer = NULL; /* Dynamically growable fetch buffer. */ + char *bufptr; /* Pointer to next available byte in buffer. */ + char *limit; /* First location past end of fetch buffer. */ + struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */ + char peekchar; /* Place into which we can read one char. */ + + /* First we need to figure out the limit on the number of characters we are + going to attempt to fetch and print. This is actually pretty simple. If + LEN is nonzero, then the limit is the minimum of LEN and print_max. If + LEN is zero, then the limit is print_max. This is true regardless of + whether print_max is zero, UINT_MAX (unlimited), or something in between, + because finding the null byte (or available memory) is what actually + limits the fetch. */ + + fetchlimit = (len == 0 ? print_max : min (len, print_max)); + + /* Now decide how large of chunks to try to read in one operation. This + is also pretty simple. If LEN is nonzero, then we want fetchlimit bytes, + so we might as well read them all in one operation. If LEN is zero, we + are looking for a null terminator to end the fetching, so we might as + well read in blocks that are large enough to be efficient, but not so + large as to be slow if fetchlimit happens to be large. So we choose the + minimum of 8 and fetchlimit. We used to use 200 instead of 8 but + 200 is way too big for remote debugging over a serial line. */ + + chunksize = (len == 0 ? min (8, fetchlimit) : fetchlimit); + + /* Loop until we either have all the characters to print, or we encounter + some error, such as bumping into the end of the address space. */ + + bufsize = 0; + do { + QUIT; + /* Figure out how much to fetch this time, and grow the buffer to fit. */ + nfetch = min (chunksize, fetchlimit - bufsize); + bufsize += nfetch; + if (buffer == NULL) + { + buffer = (char *) xmalloc (bufsize); + bufptr = buffer; + } + else + { + discard_cleanups (old_chain); + buffer = (char *) xrealloc (buffer, bufsize); + bufptr = buffer + bufsize - nfetch; + } + old_chain = make_cleanup (free, buffer); + + /* Read as much as we can. */ + nfetch = target_read_memory_partial (addr, bufptr, nfetch, &errcode); + if (len != 0) + { + addr += nfetch; + bufptr += nfetch; + } + else + { + /* Scan this chunk for the null byte that terminates the string + to print. If found, we don't need to fetch any more. Note + that bufptr is explicitly left pointing at the next character + after the null byte, or at the next character after the end of + the buffer. */ + limit = bufptr + nfetch; + while (bufptr < limit) + { + ++addr; + ++bufptr; + if (bufptr[-1] == '\0') + { + /* We don't care about any error which happened after + the NULL terminator. */ + errcode = 0; + break; + } + } + } + } while (errcode == 0 /* no error */ + && bufsize < fetchlimit /* no overrun */ + && !(len == 0 && *(bufptr - 1) == '\0')); /* no null term */ + + /* bufptr and addr now point immediately beyond the last byte which we + consider part of the string (including a '\0' which ends the string). */ + + /* We now have either successfully filled the buffer to fetchlimit, or + terminated early due to an error or finding a null byte when LEN is + zero. */ + + if (len == 0 && bufptr > buffer && *(bufptr - 1) != '\0') + { + /* We didn't find a null terminator we were looking for. Attempt + to peek at the next character. If not successful, or it is not + a null byte, then force ellipsis to be printed. */ + if (target_read_memory (addr, &peekchar, 1) != 0 || peekchar != '\0') + { + force_ellipsis = 1; + } + } + else if ((len != 0 && errcode != 0) || (len > bufptr - buffer)) + { + /* Getting an error when we have a requested length, or fetching less + than the number of characters actually requested, always make us + print ellipsis. */ + force_ellipsis = 1; + } + + QUIT; + + /* If we get an error before fetching anything, don't print a string. + But if we fetch something and then get an error, print the string + and then the error message. */ + if (errcode == 0 || bufptr > buffer) + { + if (addressprint) + { + fputs_filtered (" ", stream); + } + LA_PRINT_STRING (stream, buffer, bufptr - buffer, force_ellipsis); + } + + if (errcode != 0) + { + if (errcode == EIO) + { + fprintf_filtered (stream, "
"); + } + else + { + fprintf_filtered (stream, " ", safe_strerror (errcode)); + } + } + gdb_flush (stream); + do_cleanups (old_chain); + return (bufptr - buffer); +} + + +/* Validate an input or output radix setting, and make sure the user + knows what they really did here. Radix setting is confusing, e.g. + setting the input radix to "10" never changes it! */ + +/* ARGSUSED */ +static void +set_input_radix (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + set_input_radix_1 (from_tty, *(unsigned *)c->var); +} + +/* ARGSUSED */ +static void +set_input_radix_1 (from_tty, radix) + int from_tty; + unsigned radix; +{ + /* We don't currently disallow any input radix except 0 or 1, which don't + make any mathematical sense. In theory, we can deal with any input + radix greater than 1, even if we don't have unique digits for every + value from 0 to radix-1, but in practice we lose on large radix values. + We should either fix the lossage or restrict the radix range more. + (FIXME). */ + + if (radix < 2) + { + error ("Nonsense input radix ``decimal %u''; input radix unchanged.", + radix); + } + input_radix = radix; + if (from_tty) + { + printf_filtered ("Input radix now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* ARGSUSED */ +static void +set_output_radix (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + set_output_radix_1 (from_tty, *(unsigned *)c->var); +} + +static void +set_output_radix_1 (from_tty, radix) + int from_tty; + unsigned radix; +{ + /* Validate the radix and disallow ones that we aren't prepared to + handle correctly, leaving the radix unchanged. */ + switch (radix) + { + case 16: + output_format = 'x'; /* hex */ + break; + case 10: + output_format = 0; /* decimal */ + break; + case 8: + output_format = 'o'; /* octal */ + break; + default: + error ("Unsupported output radix ``decimal %u''; output radix unchanged.", + radix); + } + output_radix = radix; + if (from_tty) + { + printf_filtered ("Output radix now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* Set both the input and output radix at once. Try to set the output radix + first, since it has the most restrictive range. An radix that is valid as + an output radix is also valid as an input radix. + + It may be useful to have an unusual input radix. If the user wishes to + set an input radix that is not valid as an output radix, he needs to use + the 'set input-radix' command. */ + +static void +set_radix (arg, from_tty) + char *arg; + int from_tty; +{ + unsigned radix; + + radix = (arg == NULL) ? 10 : parse_and_eval_address (arg); + set_output_radix_1 (0, radix); + set_input_radix_1 (0, radix); + if (from_tty) + { + printf_filtered ("Input and output radices now set to decimal %u, hex %x, octal %o.\n", + radix, radix, radix); + } +} + +/* Show both the input and output radices. */ + +/*ARGSUSED*/ +static void +show_radix (arg, from_tty) + char *arg; + int from_tty; +{ + if (from_tty) + { + if (input_radix == output_radix) + { + printf_filtered ("Input and output radices set to decimal %u, hex %x, octal %o.\n", + input_radix, input_radix, input_radix); + } + else + { + printf_filtered ("Input radix set to decimal %u, hex %x, octal %o.\n", + input_radix, input_radix, input_radix); + printf_filtered ("Output radix set to decimal %u, hex %x, octal %o.\n", + output_radix, output_radix, output_radix); + } + } +} + + +/*ARGSUSED*/ +static void +set_print (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ( +"\"set print\" must be followed by the name of a print subcommand.\n"); + help_list (setprintlist, "set print ", -1, gdb_stdout); +} + +/*ARGSUSED*/ +static void +show_print (args, from_tty) + char *args; + int from_tty; +{ + cmd_show_list (showprintlist, from_tty, ""); +} + +void +_initialize_valprint () +{ + struct cmd_list_element *c; + + add_prefix_cmd ("print", no_class, set_print, + "Generic command for setting how things print.", + &setprintlist, "set print ", 0, &setlist); + add_alias_cmd ("p", "print", no_class, 1, &setlist); + /* prefer set print to set prompt */ + add_alias_cmd ("pr", "print", no_class, 1, &setlist); + + add_prefix_cmd ("print", no_class, show_print, + "Generic command for showing print settings.", + &showprintlist, "show print ", 0, &showlist); + add_alias_cmd ("p", "print", no_class, 1, &showlist); + add_alias_cmd ("pr", "print", no_class, 1, &showlist); + + add_show_from_set + (add_set_cmd ("elements", no_class, var_uinteger, (char *)&print_max, + "Set limit on string chars or array elements to print.\n\ +\"set print elements 0\" causes there to be no limit.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("null-stop", no_class, var_boolean, + (char *)&stop_print_at_null, + "Set printing of char arrays to stop at first null char.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("repeats", no_class, var_uinteger, + (char *)&repeat_count_threshold, + "Set threshold for repeated print elements.\n\ +\"set print repeats 0\" causes all elements to be individually printed.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("pretty", class_support, var_boolean, + (char *)&prettyprint_structs, + "Set prettyprinting of structures.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("union", class_support, var_boolean, (char *)&unionprint, + "Set printing of unions interior to structures.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("array", class_support, var_boolean, + (char *)&prettyprint_arrays, + "Set prettyprinting of arrays.", + &setprintlist), + &showprintlist); + + add_show_from_set + (add_set_cmd ("address", class_support, var_boolean, (char *)&addressprint, + "Set printing of addresses.", + &setprintlist), + &showprintlist); + + c = add_set_cmd ("input-radix", class_support, var_uinteger, + (char *)&input_radix, + "Set default input radix for entering numbers.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_input_radix; + + c = add_set_cmd ("output-radix", class_support, var_uinteger, + (char *)&output_radix, + "Set default output radix for printing of values.", + &setlist); + add_show_from_set (c, &showlist); + c->function.sfunc = set_output_radix; + + /* The "set radix" and "show radix" commands are special in that they are + like normal set and show commands but allow two normally independent + variables to be either set or shown with a single command. So the + usual add_set_cmd() and add_show_from_set() commands aren't really + appropriate. */ + add_cmd ("radix", class_support, set_radix, + "Set default input and output number radices.\n\ +Use 'set input-radix' or 'set output-radix' to independently set each.\n\ +Without an argument, sets both radices back to the default value of 10.", + &setlist); + add_cmd ("radix", class_support, show_radix, + "Show the default input and output number radices.\n\ +Use 'show input-radix' or 'show output-radix' to independently show each.", + &showlist); + + /* Give people the defaults which they are used to. */ + prettyprint_structs = 0; + prettyprint_arrays = 0; + unionprint = 1; + addressprint = 1; + print_max = PRINT_MAX_DEFAULT; +} diff --git a/contrib/gdb/gdb/valprint.h b/contrib/gdb/gdb/valprint.h new file mode 100644 index 000000000000..c486deeff997 --- /dev/null +++ b/contrib/gdb/gdb/valprint.h @@ -0,0 +1,44 @@ +/* Declarations for value printing routines for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +extern int prettyprint_arrays; /* Controls pretty printing of arrays. */ +extern int prettyprint_structs; /* Controls pretty printing of structures */ +extern int prettyprint_arrays; /* Controls pretty printing of arrays. */ + +extern int vtblprint; /* Controls printing of vtbl's */ +extern int unionprint; /* Controls printing of nested unions. */ +extern int addressprint; /* Controls pretty printing of addresses. */ +extern int objectprint; /* Controls looking up an object's derived type + using what we find in its vtables. */ + +extern unsigned int print_max; /* Max # of chars for strings/vectors */ + +extern int output_format; + +extern int stop_print_at_null; /* Stop printing at null char? */ + +extern void +val_print_array_elements PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, + int, int, int, enum val_prettyprint, int)); + +extern void +val_print_type_code_int PARAMS ((struct type *, char *, GDB_FILE *)); + diff --git a/contrib/gdb/gdb/value.h b/contrib/gdb/gdb/value.h new file mode 100644 index 000000000000..23636959b185 --- /dev/null +++ b/contrib/gdb/gdb/value.h @@ -0,0 +1,491 @@ +/* Definitions for values of C expressions, for GDB. + Copyright 1986, 1987, 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (VALUE_H) +#define VALUE_H 1 + +/* + * The structure which defines the type of a value. It should never + * be possible for a program lval value to survive over a call to the inferior + * (ie to be put into the history list or an internal variable). + */ +enum lval_type { + /* Not an lval. */ + not_lval, + /* In memory. Could be a saved register. */ + lval_memory, + /* In a register. */ + lval_register, + /* In a gdb internal variable. */ + lval_internalvar, + /* Part of a gdb internal variable (structure field). */ + lval_internalvar_component, + /* In a register series in a frame not the current one, which may have been + partially saved or saved in different places (otherwise would be + lval_register or lval_memory). */ + lval_reg_frame_relative +}; + +struct value + { + /* Type of value; either not an lval, or one of the various + different possible kinds of lval. */ + enum lval_type lval; + /* Is it modifiable? Only relevant if lval != not_lval. */ + int modifiable; + /* Location of value (if lval). */ + union + { + /* Address in inferior or byte of registers structure. */ + CORE_ADDR address; + /* Pointer to internal variable. */ + struct internalvar *internalvar; + /* Number of register. Only used with + lval_reg_frame_relative. */ + int regnum; + } location; + /* Describes offset of a value within lval a structure in bytes. */ + int offset; + /* Only used for bitfields; number of bits contained in them. */ + int bitsize; + /* Only used for bitfields; position of start of field. + For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB. + For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */ + int bitpos; + /* Frame value is relative to. In practice, this address is only + used if the value is stored in several registers in other than + the current frame, and these registers have not all been saved + at the same place in memory. This will be described in the + lval enum above as "lval_reg_frame_relative". */ + CORE_ADDR frame_addr; + /* Type of the value. */ + struct type *type; + /* Values are stored in a chain, so that they can be deleted + easily over calls to the inferior. Values assigned to internal + variables or put into the value history are taken off this + list. */ + struct value *next; + + /* ??? When is this used? */ + union { + CORE_ADDR memaddr; + char *myaddr; + } substring_addr; + + /* Register number if the value is from a register. Is not kept + if you take a field of a structure that is stored in a + register. Shouldn't it be? */ + short regno; + /* If zero, contents of this value are in the contents field. + If nonzero, contents are in inferior memory at address + in the location.address field plus the offset field + (and the lval field should be lval_memory). */ + char lazy; + /* If nonzero, this is the value of a variable which does not + actually exist in the program. */ + char optimized_out; + /* Actual contents of the value. For use of this value; setting + it uses the stuff above. Not valid if lazy is nonzero. + Target byte-order. We force it to be aligned properly for any + possible value. */ + union { + long contents[1]; + double force_double_align; + LONGEST force_longlong_align; + char *literal_data; + } aligner; + + }; + +typedef struct value *value_ptr; + +#define VALUE_TYPE(val) (val)->type +#define VALUE_LAZY(val) (val)->lazy +/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of + the gdb buffer used to hold a copy of the contents of the lval. + VALUE_CONTENTS is used when the contents of the buffer are needed -- + it uses value_fetch_lazy() to load the buffer from the process being + debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is + used when data is being stored into the buffer, or when it is + certain that the contents of the buffer are valid. */ +#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents) +#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\ + VALUE_CONTENTS_RAW(val)) +extern int value_fetch_lazy PARAMS ((value_ptr val)); + +#define VALUE_LVAL(val) (val)->lval +#define VALUE_ADDRESS(val) (val)->location.address +#define VALUE_INTERNALVAR(val) (val)->location.internalvar +#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum) +#define VALUE_FRAME(val) ((val)->frame_addr) +#define VALUE_OFFSET(val) (val)->offset +#define VALUE_BITSIZE(val) (val)->bitsize +#define VALUE_BITPOS(val) (val)->bitpos +#define VALUE_NEXT(val) (val)->next +#define VALUE_REGNO(val) (val)->regno +#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out) + +/* Convert a REF to the object referenced. */ + +#define COERCE_REF(arg) \ +{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_REF) \ + arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \ + unpack_long (VALUE_TYPE (arg), \ + VALUE_CONTENTS (arg)));} + +/* If ARG is an array, convert it to a pointer. + If ARG is an enum, convert it to an integer. + If ARG is a function, convert it to a function pointer. + + References are dereferenced. */ + +#define COERCE_ARRAY(arg) \ +do { COERCE_REF(arg); \ + if (current_language->c_style_arrays \ + && TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \ + arg = value_coerce_array (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \ + arg = value_coerce_function (arg); \ +} while (0) + +#define COERCE_NUMBER(arg) \ + do { COERCE_ARRAY(arg); COERCE_ENUM(arg); } while (0) + +#define COERCE_VARYING_ARRAY(arg, real_arg_type) \ +{ if (chill_varying_type (real_arg_type)) \ + arg = varying_to_slice (arg), real_arg_type = VALUE_TYPE (arg); } + +/* If ARG is an enum, convert it to an integer. */ + +#define COERCE_ENUM(arg) { \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* Internal variables (variables for convenience of use of debugger) + are recorded as a chain of these structures. */ + +struct internalvar +{ + struct internalvar *next; + char *name; + value_ptr value; +}; + +/* Pointer to member function. Depends on compiler implementation. */ + +#define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000) +#define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET)) +#define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR)) + + +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" + +#ifdef __STDC__ +struct frame_info; +struct fn_field; +#endif + +extern void +print_address_demangle PARAMS ((CORE_ADDR, GDB_FILE *, int)); + +extern LONGEST value_as_long PARAMS ((value_ptr val)); + +extern DOUBLEST value_as_double PARAMS ((value_ptr val)); + +extern CORE_ADDR value_as_pointer PARAMS ((value_ptr val)); + +extern LONGEST unpack_long PARAMS ((struct type *type, char *valaddr)); + +extern DOUBLEST unpack_double PARAMS ((struct type *type, char *valaddr, + int *invp)); + +extern CORE_ADDR unpack_pointer PARAMS ((struct type *type, char *valaddr)); + +extern LONGEST unpack_field_as_long PARAMS ((struct type *type, char *valaddr, + int fieldno)); + +extern value_ptr value_from_longest PARAMS ((struct type *type, LONGEST num)); + +extern value_ptr value_from_double PARAMS ((struct type *type, DOUBLEST num)); + +extern value_ptr value_at PARAMS ((struct type *type, CORE_ADDR addr)); + +extern value_ptr value_at_lazy PARAMS ((struct type *type, CORE_ADDR addr)); + +extern value_ptr value_from_register PARAMS ((struct type *type, int regnum, + struct frame_info * frame)); + +extern value_ptr value_of_variable PARAMS ((struct symbol *var, + struct block *b)); + +extern value_ptr value_of_register PARAMS ((int regnum)); + +extern int symbol_read_needs_frame PARAMS ((struct symbol *)); + +extern value_ptr read_var_value PARAMS ((struct symbol *var, + struct frame_info *frame)); + +extern value_ptr locate_var_value PARAMS ((struct symbol *var, + struct frame_info *frame)); + +extern value_ptr allocate_value PARAMS ((struct type *type)); + +extern value_ptr allocate_repeat_value PARAMS ((struct type *type, int count)); + +extern value_ptr value_mark PARAMS ((void)); + +extern void value_free_to_mark PARAMS ((value_ptr mark)); + +extern value_ptr value_string PARAMS ((char *ptr, int len)); +extern value_ptr value_bitstring PARAMS ((char *ptr, int len)); + +extern value_ptr value_array PARAMS ((int lowbound, int highbound, + value_ptr *elemvec)); + +extern value_ptr value_concat PARAMS ((value_ptr arg1, value_ptr arg2)); + +extern value_ptr value_binop PARAMS ((value_ptr arg1, value_ptr arg2, + enum exp_opcode op)); + +extern value_ptr value_add PARAMS ((value_ptr arg1, value_ptr arg2)); + +extern value_ptr value_sub PARAMS ((value_ptr arg1, value_ptr arg2)); + +extern value_ptr value_coerce_array PARAMS ((value_ptr arg1)); + +extern value_ptr value_coerce_function PARAMS ((value_ptr arg1)); + +extern value_ptr value_ind PARAMS ((value_ptr arg1)); + +extern value_ptr value_addr PARAMS ((value_ptr arg1)); + +extern value_ptr value_assign PARAMS ((value_ptr toval, value_ptr fromval)); + +extern value_ptr value_neg PARAMS ((value_ptr arg1)); + +extern value_ptr value_complement PARAMS ((value_ptr arg1)); + +extern value_ptr value_struct_elt PARAMS ((value_ptr *argp, value_ptr *args, + char *name, + int *static_memfuncp, char *err)); + +extern value_ptr value_struct_elt_for_reference PARAMS ((struct type *domain, + int offset, + struct type *curtype, + char *name, + struct type *intype)); + +extern value_ptr value_field PARAMS ((value_ptr arg1, int fieldno)); + +extern value_ptr value_primitive_field PARAMS ((value_ptr arg1, int offset, + int fieldno, + struct type *arg_type)); + +extern value_ptr value_cast PARAMS ((struct type *type, value_ptr arg2)); + +extern value_ptr value_zero PARAMS ((struct type *type, enum lval_type lv)); + +extern value_ptr value_repeat PARAMS ((value_ptr arg1, int count)); + +extern value_ptr value_subscript PARAMS ((value_ptr array, value_ptr idx)); + +extern value_ptr value_from_vtable_info PARAMS ((value_ptr arg, + struct type *type)); + +extern value_ptr value_being_returned PARAMS ((struct type *valtype, + char retbuf[REGISTER_BYTES], + int struct_return)); + +extern value_ptr value_in PARAMS ((value_ptr element, value_ptr set)); + +extern int value_bit_index PARAMS ((struct type *type, char *addr, int index)); + +extern int using_struct_return PARAMS ((value_ptr function, CORE_ADDR funcaddr, + struct type *value_type, int gcc_p)); + +extern void set_return_value PARAMS ((value_ptr val)); + +extern value_ptr evaluate_expression PARAMS ((struct expression *exp)); + +extern value_ptr evaluate_type PARAMS ((struct expression *exp)); + +extern value_ptr evaluate_subexp_with_coercion PARAMS ((struct expression *, + int *, enum noside)); + +extern value_ptr parse_and_eval PARAMS ((char *exp)); + +extern value_ptr parse_to_comma_and_eval PARAMS ((char **expp)); + +extern struct type *parse_and_eval_type PARAMS ((char *p, int length)); + +extern CORE_ADDR parse_and_eval_address PARAMS ((char *exp)); + +extern CORE_ADDR parse_and_eval_address_1 PARAMS ((char **expptr)); + +extern value_ptr access_value_history PARAMS ((int num)); + +extern value_ptr value_of_internalvar PARAMS ((struct internalvar *var)); + +extern void set_internalvar PARAMS ((struct internalvar *var, value_ptr val)); + +extern void set_internalvar_component PARAMS ((struct internalvar *var, + int offset, + int bitpos, int bitsize, + value_ptr newvalue)); + +extern struct internalvar *lookup_internalvar PARAMS ((char *name)); + +extern int value_equal PARAMS ((value_ptr arg1, value_ptr arg2)); + +extern int value_less PARAMS ((value_ptr arg1, value_ptr arg2)); + +extern int value_logical_not PARAMS ((value_ptr arg1)); + +/* C++ */ + +extern value_ptr value_of_this PARAMS ((int complain)); + +extern value_ptr value_x_binop PARAMS ((value_ptr arg1, value_ptr arg2, + enum exp_opcode op, + enum exp_opcode otherop)); + +extern value_ptr value_x_unop PARAMS ((value_ptr arg1, enum exp_opcode op)); + +extern value_ptr value_fn_field PARAMS ((value_ptr *arg1p, struct fn_field *f, + int j, + struct type* type, int offset)); + +extern value_ptr value_virtual_fn_field PARAMS ((value_ptr *arg1p, + struct fn_field *f, int j, + struct type *type, + int offset)); + +extern int binop_user_defined_p PARAMS ((enum exp_opcode op, + value_ptr arg1, value_ptr arg2)); + +extern int unop_user_defined_p PARAMS ((enum exp_opcode op, value_ptr arg1)); + +extern int destructor_name_p PARAMS ((const char *name, + const struct type *type)); + +#define value_free(val) free ((PTR)val) + +extern void free_all_values PARAMS ((void)); + +extern void release_value PARAMS ((value_ptr val)); + +extern int record_latest_value PARAMS ((value_ptr val)); + +extern void registers_changed PARAMS ((void)); + +extern void read_register_bytes PARAMS ((int regbyte, char *myaddr, int len)); + +extern void write_register_bytes PARAMS ((int regbyte, char *myaddr, int len)); + +extern void +read_register_gen PARAMS ((int regno, char *myaddr)); + +extern CORE_ADDR +read_register PARAMS ((int regno)); + +extern void +write_register PARAMS ((int regno, LONGEST val)); + +extern void +supply_register PARAMS ((int regno, char *val)); + +extern void +get_saved_register PARAMS ((char *raw_buffer, int *optimized, + CORE_ADDR *addrp, struct frame_info *frame, + int regnum, enum lval_type *lval)); + +extern void +modify_field PARAMS ((char *addr, LONGEST fieldval, int bitpos, int bitsize)); + +extern void +type_print PARAMS ((struct type *type, char *varstring, GDB_FILE *stream, + int show)); + +extern char *baseclass_addr PARAMS ((struct type *type, int index, + char *valaddr, + value_ptr *valuep, int *errp)); + +extern void +print_longest PARAMS ((GDB_FILE *stream, int format, int use_local, + LONGEST val)); + +extern void +print_floating PARAMS ((char *valaddr, struct type *type, GDB_FILE *stream)); + +extern int value_print PARAMS ((value_ptr val, GDB_FILE *stream, int format, + enum val_prettyprint pretty)); + +extern void +value_print_array_elements PARAMS ((value_ptr val, GDB_FILE* stream, + int format, enum val_prettyprint pretty)); + +extern value_ptr +value_release_to_mark PARAMS ((value_ptr mark)); + +extern int +val_print PARAMS ((struct type *type, char *valaddr, CORE_ADDR address, + GDB_FILE *stream, int format, int deref_ref, + int recurse, enum val_prettyprint pretty)); + +extern int +val_print_string PARAMS ((CORE_ADDR addr, unsigned int len, GDB_FILE *stream)); + +extern void +print_variable_value PARAMS ((struct symbol *var, struct frame_info *frame, + GDB_FILE *stream)); + +extern int check_field PARAMS ((value_ptr, const char *)); + +extern void +c_typedef_print PARAMS ((struct type *type, struct symbol *news, GDB_FILE *stream)); + +extern char * +internalvar_name PARAMS ((struct internalvar *var)); + +extern void +clear_value_history PARAMS ((void)); + +extern void +clear_internalvars PARAMS ((void)); + +/* From values.c */ + +extern value_ptr value_copy PARAMS ((value_ptr)); + +extern int baseclass_offset PARAMS ((struct type *, int, char *, CORE_ADDR)); + +/* From valops.c */ + +extern value_ptr varying_to_slice PARAMS ((value_ptr)); + +extern value_ptr value_slice PARAMS ((value_ptr, int, int)); + +extern value_ptr call_function_by_hand PARAMS ((value_ptr, int, value_ptr *)); + +extern value_ptr value_literal_complex PARAMS ((value_ptr, value_ptr, struct type*)); + +#endif /* !defined (VALUE_H) */ diff --git a/contrib/gdb/gdb/values.c b/contrib/gdb/gdb/values.c new file mode 100644 index 000000000000..a3b6abdad6f8 --- /dev/null +++ b/contrib/gdb/gdb/values.c @@ -0,0 +1,1418 @@ +/* Low level packing and unpacking of values for GDB, the GNU Debugger. + Copyright 1986, 1987, 1989, 1991, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "gdbcore.h" +#include "frame.h" +#include "command.h" +#include "gdbcmd.h" +#include "target.h" +#include "language.h" +#include "scm-lang.h" +#include "demangle.h" + +/* Local function prototypes. */ + +static value_ptr value_headof PARAMS ((value_ptr, struct type *, + struct type *)); + +static void show_values PARAMS ((char *, int)); + +static void show_convenience PARAMS ((char *, int)); + +/* The value-history records all the values printed + by print commands during this session. Each chunk + records 60 consecutive values. The first chunk on + the chain records the most recent values. + The total number of values is in value_history_count. */ + +#define VALUE_HISTORY_CHUNK 60 + +struct value_history_chunk +{ + struct value_history_chunk *next; + value_ptr values[VALUE_HISTORY_CHUNK]; +}; + +/* Chain of chunks now in use. */ + +static struct value_history_chunk *value_history_chain; + +static int value_history_count; /* Abs number of last entry stored */ + +/* List of all value objects currently allocated + (except for those released by calls to release_value) + This is so they can be freed after each command. */ + +static value_ptr all_values; + +/* Allocate a value that has the correct length for type TYPE. */ + +value_ptr +allocate_value (type) + struct type *type; +{ + register value_ptr val; + struct type *atype = check_typedef (type); + + val = (struct value *) xmalloc (sizeof (struct value) + TYPE_LENGTH (atype)); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REGNO (val) = -1; + VALUE_LAZY (val) = 0; + VALUE_OPTIMIZED_OUT (val) = 0; + val->modifiable = 1; + return val; +} + +/* Allocate a value that has the correct length + for COUNT repetitions type TYPE. */ + +value_ptr +allocate_repeat_value (type, count) + struct type *type; + int count; +{ + int low_bound = current_language->string_lower_bound; /* ??? */ + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + struct type *range_type + = create_range_type ((struct type *) NULL, builtin_type_int, + low_bound, count + low_bound - 1); + /* FIXME-type-allocation: need a way to free this type when we are + done with it. */ + return allocate_value (create_array_type ((struct type *) NULL, + type, range_type)); +} + +/* Return a mark in the value chain. All values allocated after the + mark is obtained (except for those released) are subject to being freed + if a subsequent value_free_to_mark is passed the mark. */ +value_ptr +value_mark () +{ + return all_values; +} + +/* Free all values allocated since MARK was obtained by value_mark + (except for those released). */ +void +value_free_to_mark (mark) + value_ptr mark; +{ + value_ptr val, next; + + for (val = all_values; val && val != mark; val = next) + { + next = VALUE_NEXT (val); + value_free (val); + } + all_values = val; +} + +/* Free all the values that have been allocated (except for those released). + Called after each command, successful or not. */ + +void +free_all_values () +{ + register value_ptr val, next; + + for (val = all_values; val; val = next) + { + next = VALUE_NEXT (val); + value_free (val); + } + + all_values = 0; +} + +/* Remove VAL from the chain all_values + so it will not be freed automatically. */ + +void +release_value (val) + register value_ptr val; +{ + register value_ptr v; + + if (all_values == val) + { + all_values = val->next; + return; + } + + for (v = all_values; v; v = v->next) + { + if (v->next == val) + { + v->next = val->next; + break; + } + } +} + +/* Release all values up to mark */ +value_ptr +value_release_to_mark (mark) + value_ptr mark; +{ + value_ptr val, next; + + for (val = next = all_values; next; next = VALUE_NEXT (next)) + if (VALUE_NEXT (next) == mark) + { + all_values = VALUE_NEXT (next); + VALUE_NEXT (next) = 0; + return val; + } + all_values = 0; + return val; +} + +/* Return a copy of the value ARG. + It contains the same contents, for same memory address, + but it's a different block of storage. */ + +value_ptr +value_copy (arg) + value_ptr arg; +{ + register struct type *type = VALUE_TYPE (arg); + register value_ptr val = allocate_value (type); + VALUE_LVAL (val) = VALUE_LVAL (arg); + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); + VALUE_OFFSET (val) = VALUE_OFFSET (arg); + VALUE_BITPOS (val) = VALUE_BITPOS (arg); + VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); + VALUE_FRAME (val) = VALUE_FRAME (arg); + VALUE_REGNO (val) = VALUE_REGNO (arg); + VALUE_LAZY (val) = VALUE_LAZY (arg); + VALUE_OPTIMIZED_OUT (val) = VALUE_OPTIMIZED_OUT (arg); + val->modifiable = arg->modifiable; + if (!VALUE_LAZY (val)) + { + memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS_RAW (arg), + TYPE_LENGTH (VALUE_TYPE (arg))); + } + return val; +} + +/* Access to the value history. */ + +/* Record a new value in the value history. + Returns the absolute history index of the entry. + Result of -1 indicates the value was not saved; otherwise it is the + value history index of this new item. */ + +int +record_latest_value (val) + value_ptr val; +{ + int i; + + /* We don't want this value to have anything to do with the inferior anymore. + In particular, "set $1 = 50" should not affect the variable from which + the value was taken, and fast watchpoints should be able to assume that + a value on the value history never changes. */ + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + /* We preserve VALUE_LVAL so that the user can find out where it was fetched + from. This is a bit dubious, because then *&$1 does not just return $1 + but the current contents of that location. c'est la vie... */ + val->modifiable = 0; + release_value (val); + + /* Here we treat value_history_count as origin-zero + and applying to the value being stored now. */ + + i = value_history_count % VALUE_HISTORY_CHUNK; + if (i == 0) + { + register struct value_history_chunk *new + = (struct value_history_chunk *) + xmalloc (sizeof (struct value_history_chunk)); + memset (new->values, 0, sizeof new->values); + new->next = value_history_chain; + value_history_chain = new; + } + + value_history_chain->values[i] = val; + + /* Now we regard value_history_count as origin-one + and applying to the value just stored. */ + + return ++value_history_count; +} + +/* Return a copy of the value in the history with sequence number NUM. */ + +value_ptr +access_value_history (num) + int num; +{ + register struct value_history_chunk *chunk; + register int i; + register int absnum = num; + + if (absnum <= 0) + absnum += value_history_count; + + if (absnum <= 0) + { + if (num == 0) + error ("The history is empty."); + else if (num == 1) + error ("There is only one value in the history."); + else + error ("History does not go back to $$%d.", -num); + } + if (absnum > value_history_count) + error ("History has not yet reached $%d.", absnum); + + absnum--; + + /* Now absnum is always absolute and origin zero. */ + + chunk = value_history_chain; + for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; + i > 0; i--) + chunk = chunk->next; + + return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); +} + +/* Clear the value history entirely. + Must be done when new symbol tables are loaded, + because the type pointers become invalid. */ + +void +clear_value_history () +{ + register struct value_history_chunk *next; + register int i; + register value_ptr val; + + while (value_history_chain) + { + for (i = 0; i < VALUE_HISTORY_CHUNK; i++) + if ((val = value_history_chain->values[i]) != NULL) + free ((PTR)val); + next = value_history_chain->next; + free ((PTR)value_history_chain); + value_history_chain = next; + } + value_history_count = 0; +} + +static void +show_values (num_exp, from_tty) + char *num_exp; + int from_tty; +{ + register int i; + register value_ptr val; + static int num = 1; + + if (num_exp) + { + /* "info history +" should print from the stored position. + "info history " should print around value number . */ + if (num_exp[0] != '+' || num_exp[1] != '\0') + num = parse_and_eval_address (num_exp) - 5; + } + else + { + /* "info history" means print the last 10 values. */ + num = value_history_count - 9; + } + + if (num <= 0) + num = 1; + + for (i = num; i < num + 10 && i <= value_history_count; i++) + { + val = access_value_history (i); + printf_filtered ("$%d = ", i); + value_print (val, gdb_stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + + /* The next "info history +" should start after what we just printed. */ + num += 10; + + /* Hitting just return after this command should do the same thing as + "info history +". If num_exp is null, this is unnecessary, since + "info history +" is not useful after "info history". */ + if (from_tty && num_exp) + { + num_exp[0] = '+'; + num_exp[1] = '\0'; + } +} + +/* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. + The user refers to them with a '$' prefix + that does not appear in the variable names stored internally. */ + +static struct internalvar *internalvars; + +/* Look up an internal variable with name NAME. NAME should not + normally include a dollar sign. + + If the specified internal variable does not exist, + one is created, with a void value. */ + +struct internalvar * +lookup_internalvar (name) + char *name; +{ + register struct internalvar *var; + + for (var = internalvars; var; var = var->next) + if (STREQ (var->name, name)) + return var; + + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, NULL); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + var->next = internalvars; + internalvars = var; + return var; +} + +value_ptr +value_of_internalvar (var) + struct internalvar *var; +{ + register value_ptr val; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + return VALUE_OF_TRAPPED_INTERNALVAR (var); +#endif + + val = value_copy (var->value); + if (VALUE_LAZY (val)) + value_fetch_lazy (val); + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +void +set_internalvar_component (var, offset, bitpos, bitsize, newval) + struct internalvar *var; + int offset, bitpos, bitsize; + value_ptr newval; +{ + register char *addr = VALUE_CONTENTS (var->value) + offset; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset); +#endif + + if (bitsize) + modify_field (addr, value_as_long (newval), + bitpos, bitsize); + else + memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval))); +} + +void +set_internalvar (var, val) + struct internalvar *var; + value_ptr val; +{ + value_ptr newval; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0); +#endif + + newval = value_copy (val); + newval->modifiable = 1; + + /* Force the value to be fetched from the target now, to avoid problems + later when this internalvar is referenced and the target is gone or + has changed. */ + if (VALUE_LAZY (newval)) + value_fetch_lazy (newval); + + /* Begin code which must not call error(). If var->value points to + something free'd, an error() obviously leaves a dangling pointer. + But we also get a danling pointer if var->value points to + something in the value chain (i.e., before release_value is + called), because after the error free_all_values will get called before + long. */ + free ((PTR)var->value); + var->value = newval; + release_value (newval); + /* End code which must not call error(). */ +} + +char * +internalvar_name (var) + struct internalvar *var; +{ + return var->name; +} + +/* Free all internalvars. Done when new symtabs are loaded, + because that makes the values invalid. */ + +void +clear_internalvars () +{ + register struct internalvar *var; + + while (internalvars) + { + var = internalvars; + internalvars = var->next; + free ((PTR)var->name); + free ((PTR)var->value); + free ((PTR)var); + } +} + +static void +show_convenience (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct internalvar *var; + int varseen = 0; + + for (var = internalvars; var; var = var->next) + { +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + continue; +#endif + if (!varseen) + { + varseen = 1; + } + printf_filtered ("$%s = ", var->name); + value_print (var->value, gdb_stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + if (!varseen) + printf_unfiltered ("No debugger convenience variables now defined.\n\ +Convenience variables have names starting with \"$\";\n\ +use \"set\" as in \"set $foo = 5\" to define them.\n"); +} + +/* Extract a value as a C number (either long or double). + Knows how to convert fixed values to double, or + floating values to long. + Does not deallocate the value. */ + +LONGEST +value_as_long (val) + register value_ptr val; +{ + /* This coerces arrays and functions, which is necessary (e.g. + in disassemble_command). It also dereferences references, which + I suspect is the most logical thing to do. */ + COERCE_ARRAY (val); + return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); +} + +DOUBLEST +value_as_double (val) + register value_ptr val; +{ + DOUBLEST foo; + int inv; + + foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv); + if (inv) + error ("Invalid floating value found in program."); + return foo; +} +/* Extract a value as a C pointer. + Does not deallocate the value. */ +CORE_ADDR +value_as_pointer (val) + value_ptr val; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ +#if 0 + /* ADDR_BITS_REMOVE is wrong if we are being called for a + non-address (e.g. argument to "signal", "info break", etc.), or + for pointers to char, in which the low bits *are* significant. */ + return ADDR_BITS_REMOVE(value_as_long (val)); +#else + return value_as_long (val); +#endif +} + +/* Unpack raw data (copied from debugee, target byte order) at VALADDR + as a long, or as a double, assuming the raw data is described + by type TYPE. Knows how to convert different sizes of values + and can convert between fixed and floating point. We don't assume + any alignment for the raw data. Return value is in host byte order. + + If you want functions and arrays to be coerced to pointers, and + references to be dereferenced, call value_as_long() instead. + + C++: It is assumed that the front-end has taken care of + all matters concerning pointers to members. A pointer + to member which reaches here is considered to be equivalent + to an INT (or some size). After all, it is only an offset. */ + +LONGEST +unpack_long (type, valaddr) + struct type *type; + char *valaddr; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + if (current_language->la_language == language_scm + && is_scmvalue_type (type)) + return scm_unpack (type, valaddr, TYPE_CODE_INT); + + switch (code) + { + case TYPE_CODE_TYPEDEF: + return unpack_long (check_typedef (type), valaddr); + case TYPE_CODE_ENUM: + case TYPE_CODE_BOOL: + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_RANGE: + if (nosign) + return extract_unsigned_integer (valaddr, len); + else + return extract_signed_integer (valaddr, len); + + case TYPE_CODE_FLT: + return extract_floating (valaddr, len); + + case TYPE_CODE_PTR: + case TYPE_CODE_REF: + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + return extract_address (valaddr, len); + + case TYPE_CODE_MEMBER: + error ("not implemented: member types in unpack_long"); + + default: + error ("Value can't be converted to integer."); + } + return 0; /* Placate lint. */ +} + +/* Return a double value from the specified type and address. + INVP points to an int which is set to 0 for valid value, + 1 for invalid value (bad float format). In either case, + the returned double is OK to use. Argument is in target + format, result is in host format. */ + +DOUBLEST +unpack_double (type, valaddr, invp) + struct type *type; + char *valaddr; + int *invp; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + *invp = 0; /* Assume valid. */ + CHECK_TYPEDEF (type); + if (code == TYPE_CODE_FLT) + { +#ifdef INVALID_FLOAT + if (INVALID_FLOAT (valaddr, len)) + { + *invp = 1; + return 1.234567891011121314; + } +#endif + return extract_floating (valaddr, len); + } + else if (nosign) + { + /* Unsigned -- be sure we compensate for signed LONGEST. */ + return (unsigned LONGEST) unpack_long (type, valaddr); + } + else + { + /* Signed -- we are OK with unpack_long. */ + return unpack_long (type, valaddr); + } +} + +/* Unpack raw data (copied from debugee, target byte order) at VALADDR + as a CORE_ADDR, assuming the raw data is described by type TYPE. + We don't assume any alignment for the raw data. Return value is in + host byte order. + + If you want functions and arrays to be coerced to pointers, and + references to be dereferenced, call value_as_pointer() instead. + + C++: It is assumed that the front-end has taken care of + all matters concerning pointers to members. A pointer + to member which reaches here is considered to be equivalent + to an INT (or some size). After all, it is only an offset. */ + +CORE_ADDR +unpack_pointer (type, valaddr) + struct type *type; + char *valaddr; +{ + /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure + whether we want this to be true eventually. */ + return unpack_long (type, valaddr); +} + +/* Given a value ARG1 (offset by OFFSET bytes) + of a struct or union type ARG_TYPE, + extract and return the value of one of its fields. + FIELDNO says which field. + + For C++, must also be able to return values from static fields */ + +value_ptr +value_primitive_field (arg1, offset, fieldno, arg_type) + register value_ptr arg1; + int offset; + register int fieldno; + register struct type *arg_type; +{ + register value_ptr v; + register struct type *type; + + CHECK_TYPEDEF (arg_type); + type = TYPE_FIELD_TYPE (arg_type, fieldno); + + /* Handle packed fields */ + + offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; + if (TYPE_FIELD_BITSIZE (arg_type, fieldno)) + { + v = value_from_longest (type, + unpack_field_as_long (arg_type, + VALUE_CONTENTS (arg1), + fieldno)); + VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8; + VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno); + } + else + { + v = allocate_value (type); + if (VALUE_LAZY (arg1)) + VALUE_LAZY (v) = 1; + else + memcpy (VALUE_CONTENTS_RAW (v), VALUE_CONTENTS_RAW (arg1) + offset, + TYPE_LENGTH (type)); + } + VALUE_LVAL (v) = VALUE_LVAL (arg1); + if (VALUE_LVAL (arg1) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1); + VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1); + return v; +} + +/* Given a value ARG1 of a struct or union type, + extract and return the value of one of its fields. + FIELDNO says which field. + + For C++, must also be able to return values from static fields */ + +value_ptr +value_field (arg1, fieldno) + register value_ptr arg1; + register int fieldno; +{ + return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1)); +} + +/* Return a non-virtual function as a value. + F is the list of member functions which contains the desired method. + J is an index into F which provides the desired method. */ + +value_ptr +value_fn_field (arg1p, f, j, type, offset) + value_ptr *arg1p; + struct fn_field *f; + int j; + struct type *type; + int offset; +{ + register value_ptr v; + register struct type *ftype = TYPE_FN_FIELD_TYPE (f, j); + struct symbol *sym; + + sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), + 0, VAR_NAMESPACE, 0, NULL); + if (! sym) + return NULL; +/* + error ("Internal error: could not find physical method named %s", + TYPE_FN_FIELD_PHYSNAME (f, j)); +*/ + + v = allocate_value (ftype); + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + VALUE_TYPE (v) = ftype; + + if (arg1p) + { + if (type != VALUE_TYPE (*arg1p)) + *arg1p = value_ind (value_cast (lookup_pointer_type (type), + value_addr (*arg1p))); + + /* Move the `this' pointer according to the offset. + VALUE_OFFSET (*arg1p) += offset; + */ + } + + return v; +} + +/* Return a virtual function as a value. + ARG1 is the object which provides the virtual function + table pointer. *ARG1P is side-effected in calling this function. + F is the list of member functions which contains the desired virtual + function. + J is an index into F which provides the desired virtual function. + + TYPE is the type in which F is located. */ +value_ptr +value_virtual_fn_field (arg1p, f, j, type, offset) + value_ptr *arg1p; + struct fn_field *f; + int j; + struct type *type; + int offset; +{ + value_ptr arg1 = *arg1p; + struct type *type1 = check_typedef (VALUE_TYPE (arg1)); + struct type *entry_type; + /* First, get the virtual function table pointer. That comes + with a strange type, so cast it to type `pointer to long' (which + should serve just fine as a function type). Then, index into + the table, and convert final value to appropriate function type. */ + value_ptr entry, vfn, vtbl; + value_ptr vi = value_from_longest (builtin_type_int, + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + struct type *fcontext = TYPE_FN_FIELD_FCONTEXT (f, j); + struct type *context; + if (fcontext == NULL) + /* We don't have an fcontext (e.g. the program was compiled with + g++ version 1). Try to get the vtbl from the TYPE_VPTR_BASETYPE. + This won't work right for multiple inheritance, but at least we + should do as well as GDB 3.x did. */ + fcontext = TYPE_VPTR_BASETYPE (type); + context = lookup_pointer_type (fcontext); + /* Now context is a pointer to the basetype containing the vtbl. */ + if (TYPE_TARGET_TYPE (context) != type1) + { + arg1 = value_ind (value_cast (context, value_addr (arg1))); + type1 = check_typedef (VALUE_TYPE (arg1)); + } + + context = type1; + /* Now context is the basetype containing the vtbl. */ + + /* This type may have been defined before its virtual function table + was. If so, fill in the virtual function table entry for the + type now. */ + if (TYPE_VPTR_FIELDNO (context) < 0) + fill_in_vptr_fieldno (context); + + /* The virtual function table is now an array of structures + which have the form { int16 offset, delta; void *pfn; }. */ + vtbl = value_ind (value_primitive_field (arg1, 0, + TYPE_VPTR_FIELDNO (context), + TYPE_VPTR_BASETYPE (context))); + + /* Index into the virtual function table. This is hard-coded because + looking up a field is not cheap, and it may be important to save + time, e.g. if the user has set a conditional breakpoint calling + a virtual function. */ + entry = value_subscript (vtbl, vi); + entry_type = check_typedef (VALUE_TYPE (entry)); + + if (TYPE_CODE (entry_type) == TYPE_CODE_STRUCT) + { + /* Move the `this' pointer according to the virtual function table. */ + VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0)); + + if (! VALUE_LAZY (arg1)) + { + VALUE_LAZY (arg1) = 1; + value_fetch_lazy (arg1); + } + + vfn = value_field (entry, 2); + } + else if (TYPE_CODE (entry_type) == TYPE_CODE_PTR) + vfn = entry; + else + error ("I'm confused: virtual function table has bad type"); + /* Reinstantiate the function pointer with the correct type. */ + VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); + + *arg1p = arg1; + return vfn; +} + +/* ARG is a pointer to an object we know to be at least + a DTYPE. BTYPE is the most derived basetype that has + already been searched (and need not be searched again). + After looking at the vtables between BTYPE and DTYPE, + return the most derived type we find. The caller must + be satisfied when the return value == DTYPE. + + FIXME-tiemann: should work with dossier entries as well. */ + +static value_ptr +value_headof (in_arg, btype, dtype) + value_ptr in_arg; + struct type *btype, *dtype; +{ + /* First collect the vtables we must look at for this object. */ + /* FIXME-tiemann: right now, just look at top-most vtable. */ + value_ptr arg, vtbl, entry, best_entry = 0; + int i, nelems; + int offset, best_offset = 0; + struct symbol *sym; + CORE_ADDR pc_for_sym; + char *demangled_name; + struct minimal_symbol *msymbol; + + btype = TYPE_VPTR_BASETYPE (dtype); + CHECK_TYPEDEF (btype); + arg = in_arg; + if (btype != dtype) + arg = value_cast (lookup_pointer_type (btype), arg); + vtbl = value_ind (value_field (value_ind (arg), TYPE_VPTR_FIELDNO (btype))); + + /* Check that VTBL looks like it points to a virtual function table. */ + msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl)); + if (msymbol == NULL + || (demangled_name = SYMBOL_NAME (msymbol)) == NULL + || !VTBL_PREFIX_P (demangled_name)) + { + /* If we expected to find a vtable, but did not, let the user + know that we aren't happy, but don't throw an error. + FIXME: there has to be a better way to do this. */ + struct type *error_type = (struct type *)xmalloc (sizeof (struct type)); + memcpy (error_type, VALUE_TYPE (in_arg), sizeof (struct type)); + TYPE_NAME (error_type) = savestring ("suspicious *", sizeof ("suspicious *")); + VALUE_TYPE (in_arg) = error_type; + return in_arg; + } + + /* Now search through the virtual function table. */ + entry = value_ind (vtbl); + nelems = longest_to_int (value_as_long (value_field (entry, 2))); + for (i = 1; i <= nelems; i++) + { + entry = value_subscript (vtbl, value_from_longest (builtin_type_int, + (LONGEST) i)); + /* This won't work if we're using thunks. */ + if (TYPE_CODE (check_typedef (VALUE_TYPE (entry))) != TYPE_CODE_STRUCT) + break; + offset = longest_to_int (value_as_long (value_field (entry, 0))); + /* If we use '<=' we can handle single inheritance + * where all offsets are zero - just use the first entry found. */ + if (offset <= best_offset) + { + best_offset = offset; + best_entry = entry; + } + } + /* Move the pointer according to BEST_ENTRY's offset, and figure + out what type we should return as the new pointer. */ + if (best_entry == 0) + { + /* An alternative method (which should no longer be necessary). + * But we leave it in for future use, when we will hopefully + * have optimizes the vtable to use thunks instead of offsets. */ + /* Use the name of vtable itself to extract a base type. */ + demangled_name += 4; /* Skip _vt$ prefix. */ + } + else + { + pc_for_sym = value_as_pointer (value_field (best_entry, 2)); + sym = find_pc_function (pc_for_sym); + demangled_name = cplus_demangle (SYMBOL_NAME (sym), DMGL_ANSI); + *(strchr (demangled_name, ':')) = '\0'; + } + sym = lookup_symbol (demangled_name, 0, VAR_NAMESPACE, 0, 0); + if (sym == NULL) + error ("could not find type declaration for `%s'", demangled_name); + if (best_entry) + { + free (demangled_name); + arg = value_add (value_cast (builtin_type_int, arg), + value_field (best_entry, 0)); + } + else arg = in_arg; + VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym)); + return arg; +} + +/* ARG is a pointer object of type TYPE. If TYPE has virtual + function tables, probe ARG's tables (including the vtables + of its baseclasses) to figure out the most derived type that ARG + could actually be a pointer to. */ + +value_ptr +value_from_vtable_info (arg, type) + value_ptr arg; + struct type *type; +{ + /* Take care of preliminaries. */ + if (TYPE_VPTR_FIELDNO (type) < 0) + fill_in_vptr_fieldno (type); + if (TYPE_VPTR_FIELDNO (type) < 0) + return 0; + + return value_headof (arg, 0, type); +} + +/* Return true if the INDEXth field of TYPE is a virtual baseclass + pointer which is for the base class whose type is BASECLASS. */ + +static int +vb_match (type, index, basetype) + struct type *type; + int index; + struct type *basetype; +{ + struct type *fieldtype; + char *name = TYPE_FIELD_NAME (type, index); + char *field_class_name = NULL; + + if (*name != '_') + return 0; + /* gcc 2.4 uses _vb$. */ + if (name[1] == 'v' && name[2] == 'b' && is_cplus_marker (name[3])) + field_class_name = name + 4; + /* gcc 2.5 will use __vb_. */ + if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_') + field_class_name = name + 5; + + if (field_class_name == NULL) + /* This field is not a virtual base class pointer. */ + return 0; + + /* It's a virtual baseclass pointer, now we just need to find out whether + it is for this baseclass. */ + fieldtype = TYPE_FIELD_TYPE (type, index); + if (fieldtype == NULL + || TYPE_CODE (fieldtype) != TYPE_CODE_PTR) + /* "Can't happen". */ + return 0; + + /* What we check for is that either the types are equal (needed for + nameless types) or have the same name. This is ugly, and a more + elegant solution should be devised (which would probably just push + the ugliness into symbol reading unless we change the stabs format). */ + if (TYPE_TARGET_TYPE (fieldtype) == basetype) + return 1; + + if (TYPE_NAME (basetype) != NULL + && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL + && STREQ (TYPE_NAME (basetype), + TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)))) + return 1; + return 0; +} + +/* Compute the offset of the baseclass which is + the INDEXth baseclass of class TYPE, + for value at VALADDR (in host) at ADDRESS (in target). + The result is the offset of the baseclass value relative + to (the address of)(ARG) + OFFSET. + + -1 is returned on error. */ + +int +baseclass_offset (type, index, valaddr, address) + struct type *type; + int index; + char *valaddr; + CORE_ADDR address; +{ + struct type *basetype = TYPE_BASECLASS (type, index); + + if (BASETYPE_VIA_VIRTUAL (type, index)) + { + /* Must hunt for the pointer to this virtual baseclass. */ + register int i, len = TYPE_NFIELDS (type); + register int n_baseclasses = TYPE_N_BASECLASSES (type); + + /* First look for the virtual baseclass pointer + in the fields. */ + for (i = n_baseclasses; i < len; i++) + { + if (vb_match (type, i, basetype)) + { + CORE_ADDR addr + = unpack_pointer (TYPE_FIELD_TYPE (type, i), + valaddr + (TYPE_FIELD_BITPOS (type, i) / 8)); + + return addr - (LONGEST) address; + } + } + /* Not in the fields, so try looking through the baseclasses. */ + for (i = index+1; i < n_baseclasses; i++) + { + int boffset = + baseclass_offset (type, i, valaddr, address); + if (boffset) + return boffset; + } + /* Not found. */ + return -1; + } + + /* Baseclass is easily computed. */ + return TYPE_BASECLASS_BITPOS (type, index) / 8; +} + +/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at + VALADDR. + + Extracting bits depends on endianness of the machine. Compute the + number of least significant bits to discard. For big endian machines, + we compute the total number of bits in the anonymous object, subtract + off the bit count from the MSB of the object to the MSB of the + bitfield, then the size of the bitfield, which leaves the LSB discard + count. For little endian machines, the discard count is simply the + number of bits from the LSB of the anonymous object to the LSB of the + bitfield. + + If the field is signed, we also do sign extension. */ + +LONGEST +unpack_field_as_long (type, valaddr, fieldno) + struct type *type; + char *valaddr; + int fieldno; +{ + unsigned LONGEST val; + unsigned LONGEST valmask; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + int lsbcount; + + val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val)); + + /* Extract bits. See comment above. */ + + if (BITS_BIG_ENDIAN) + lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize); + else + lsbcount = (bitpos % 8); + val >>= lsbcount; + + /* If the field does not entirely fill a LONGEST, then zero the sign bits. + If the field is signed, and is negative, then sign extend. */ + + if ((bitsize > 0) && (bitsize < 8 * (int) sizeof (val))) + { + valmask = (((unsigned LONGEST) 1) << bitsize) - 1; + val &= valmask; + if (!TYPE_UNSIGNED (TYPE_FIELD_TYPE (type, fieldno))) + { + if (val & (valmask ^ (valmask >> 1))) + { + val |= ~valmask; + } + } + } + return (val); +} + +/* Modify the value of a bitfield. ADDR points to a block of memory in + target byte order; the bitfield starts in the byte pointed to. FIELDVAL + is the desired value of the field, in host byte order. BITPOS and BITSIZE + indicate which bits (in target bit order) comprise the bitfield. */ + +void +modify_field (addr, fieldval, bitpos, bitsize) + char *addr; + LONGEST fieldval; + int bitpos, bitsize; +{ + LONGEST oword; + + /* If a negative fieldval fits in the field in question, chop + off the sign extension bits. */ + if (bitsize < (8 * (int) sizeof (fieldval)) + && (~fieldval & ~((1 << (bitsize - 1)) - 1)) == 0) + fieldval = fieldval & ((1 << bitsize) - 1); + + /* Warn if value is too big to fit in the field in question. */ + if (bitsize < (8 * (int) sizeof (fieldval)) + && 0 != (fieldval & ~((1<= size of oword */ + if (bitsize < 8 * (int) sizeof (oword)) + oword &= ~(((((unsigned LONGEST)1) << bitsize) - 1) << bitpos); + else + oword &= ~((~(unsigned LONGEST)0) << bitpos); + oword |= fieldval << bitpos; + + store_signed_integer (addr, sizeof oword, oword); +} + +/* Convert C numbers into newly allocated values */ + +value_ptr +value_from_longest (type, num) + struct type *type; + register LONGEST num; +{ + register value_ptr val = allocate_value (type); + register enum type_code code; + register int len; + retry: + code = TYPE_CODE (type); + len = TYPE_LENGTH (type); + + switch (code) + { + case TYPE_CODE_TYPEDEF: + type = check_typedef (type); + goto retry; + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_BOOL: + case TYPE_CODE_RANGE: + store_signed_integer (VALUE_CONTENTS_RAW (val), len, num); + break; + + case TYPE_CODE_REF: + case TYPE_CODE_PTR: + /* This assumes that all pointers of a given length + have the same form. */ + store_address (VALUE_CONTENTS_RAW (val), len, (CORE_ADDR) num); + break; + + default: + error ("Unexpected type encountered for integer constant."); + } + return val; +} + +value_ptr +value_from_double (type, num) + struct type *type; + DOUBLEST num; +{ + register value_ptr val = allocate_value (type); + struct type *base_type = check_typedef (type); + register enum type_code code = TYPE_CODE (base_type); + register int len = TYPE_LENGTH (base_type); + + if (code == TYPE_CODE_FLT) + { + store_floating (VALUE_CONTENTS_RAW (val), len, num); + } + else + error ("Unexpected type encountered for floating constant."); + + return val; +} + +/* Deal with the value that is "about to be returned". */ + +/* Return the value that a function returning now + would be returning to its caller, assuming its type is VALTYPE. + RETBUF is where we look for what ought to be the contents + of the registers (in raw form). This is because it is often + desirable to restore old values to those registers + after saving the contents of interest, and then call + this function using the saved values. + struct_return is non-zero when the function in question is + using the structure return conventions on the machine in question; + 0 when it is using the value returning conventions (this often + means returning pointer to where structure is vs. returning value). */ + +value_ptr +value_being_returned (valtype, retbuf, struct_return) + register struct type *valtype; + char retbuf[REGISTER_BYTES]; + int struct_return; + /*ARGSUSED*/ +{ + register value_ptr val; + CORE_ADDR addr; + +#if defined (EXTRACT_STRUCT_VALUE_ADDRESS) + /* If this is not defined, just use EXTRACT_RETURN_VALUE instead. */ + if (struct_return) { + addr = EXTRACT_STRUCT_VALUE_ADDRESS (retbuf); + if (!addr) + error ("Function return value unknown"); + return value_at (valtype, addr); + } +#endif + + val = allocate_value (valtype); + CHECK_TYPEDEF (valtype); + EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val)); + + return val; +} + +/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of + EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc + and TYPE is the type (which is known to be struct, union or array). + + On most machines, the struct convention is used unless we are + using gcc and the type is of a special size. */ +/* As of about 31 Mar 93, GCC was changed to be compatible with the + native compiler. GCC 2.3.3 was the last release that did it the + old way. Since gcc2_compiled was not changed, we have no + way to correctly win in all cases, so we just do the right thing + for gcc1 and for gcc2 after this change. Thus it loses for gcc + 2.0-2.3.3. This is somewhat unfortunate, but changing gcc2_compiled + would cause more chaos than dealing with some struct returns being + handled wrong. */ +#if !defined (USE_STRUCT_CONVENTION) +#define USE_STRUCT_CONVENTION(gcc_p, type)\ + (!((gcc_p == 1) && (TYPE_LENGTH (value_type) == 1 \ + || TYPE_LENGTH (value_type) == 2 \ + || TYPE_LENGTH (value_type) == 4 \ + || TYPE_LENGTH (value_type) == 8 \ + ) \ + )) +#endif + +/* Some fundamental types (such as long double) are returned on the stack for + certain architectures. This macro should return true for any type besides + struct, union or array that gets returned on the stack. */ + +#ifndef RETURN_VALUE_ON_STACK +#define RETURN_VALUE_ON_STACK(TYPE) 0 +#endif + +/* Return true if the function specified is using the structure returning + convention on this machine to return arguments, or 0 if it is using + the value returning convention. FUNCTION is the value representing + the function, FUNCADDR is the address of the function, and VALUE_TYPE + is the type returned by the function. GCC_P is nonzero if compiled + with GCC. */ + +int +using_struct_return (function, funcaddr, value_type, gcc_p) + value_ptr function; + CORE_ADDR funcaddr; + struct type *value_type; + int gcc_p; + /*ARGSUSED*/ +{ + register enum type_code code = TYPE_CODE (value_type); + + if (code == TYPE_CODE_ERROR) + error ("Function return type unknown."); + + if (code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION + || code == TYPE_CODE_ARRAY + || RETURN_VALUE_ON_STACK (value_type)) + return USE_STRUCT_CONVENTION (gcc_p, value_type); + + return 0; +} + +/* Store VAL so it will be returned if a function returns now. + Does not verify that VAL's type matches what the current + function wants to return. */ + +void +set_return_value (val) + value_ptr val; +{ + struct type *type = check_typedef (VALUE_TYPE (val)); + register enum type_code code = TYPE_CODE (type); + + if (code == TYPE_CODE_ERROR) + error ("Function return type unknown."); + + if ( code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION) /* FIXME, implement struct return. */ + error ("GDB does not support specifying a struct or union return value."); + + STORE_RETURN_VALUE (type, VALUE_CONTENTS (val)); +} + +void +_initialize_values () +{ + add_cmd ("convenience", no_class, show_convenience, + "Debugger convenience (\"$foo\") variables.\n\ +These variables are created when you assign them values;\n\ +thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\ +A few convenience variables are given values automatically:\n\ +\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\ +\"$__\" holds the contents of the last address examined with \"x\".", + &showlist); + + add_cmd ("values", no_class, show_values, + "Elements of value history around item number IDX (or last ten).", + &showlist); +} diff --git a/contrib/gdb/gdb/xcoffread.c b/contrib/gdb/gdb/xcoffread.c new file mode 100644 index 000000000000..7704a5fba406 --- /dev/null +++ b/contrib/gdb/gdb/xcoffread.c @@ -0,0 +1,2767 @@ +/* Read AIX xcoff symbol tables and convert to internal format, for GDB. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + Free Software Foundation, Inc. + Derived from coffread.c, dbxread.c, and a lot of hacking. + Contributed by IBM 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* RS/6000 and PowerPC only: + Needs xcoff_add_toc_to_loadinfo and xcoff_init_loadinfo in + rs6000-tdep.c from target. + However, if you define FAKING_RS6000, then this code will link with + any target. */ + +#include "defs.h" +#include "bfd.h" + +#include +#include +#include +#include "gdb_string.h" + +#include +#ifndef NO_SYS_FILE +#include +#endif +#include "gdb_stat.h" + +#include "coff/internal.h" +#include "libcoff.h" /* FIXME, internal data from BFD */ +#include "coff/rs6000.h" + +#include "symtab.h" +#include "gdbtypes.h" +#include "symfile.h" +#include "objfiles.h" +#include "buildsym.h" +#include "stabsread.h" +#include "expression.h" +#include "language.h" /* Needed inside partial-stab.h */ +#include "complaints.h" + +#include "gdb-stabs.h" + +/* For interface with stabsread.c. */ +#include "aout/stab_gnu.h" + +/* For interface with partial-stab.h. */ +#define N_UNDF 0 /* Undefined symbol */ +#undef N_ABS +#define N_ABS 2 +#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ +#define N_FN 0x1f /* File name of .o file */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* We put a pointer to this structure in the read_symtab_private field + of the psymtab. */ + +struct symloc { + + /* First symbol number for this file. */ + + int first_symnum; + + /* Number of symbols in the section of the symbol table devoted to + this file's symbols (actually, the section bracketed may contain + more than just this file's symbols). If numsyms is 0, the only + reason for this thing's existence is the dependency list. Nothing + else will happen when it is read in. */ + + int numsyms; + + /* Position of the start of the line number information for this psymtab. */ + unsigned int lineno_off; +}; + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + + +/* Simplified internal version of coff symbol table information */ + +struct coff_symbol { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_naux; /* 0 if syment only, 1 if syment + auxent */ + long c_value; + unsigned char c_sclass; + int c_secnum; + unsigned int c_type; +}; + +/* last function's saved coff symbol `cs' */ + +static struct coff_symbol fcn_cs_saved; + +static bfd *symfile_bfd; + +/* Core address of start and end of text of current source file. + This is calculated from the first function seen after a C_FILE + symbol. */ + + +static CORE_ADDR cur_src_end_addr; + +/* Core address of the end of the first object file. */ + +static CORE_ADDR first_object_file_end; + +/* initial symbol-table-debug-string vector length */ + +#define INITIAL_STABVECTOR_LENGTH 40 + +/* Nonzero if within a function (so symbols should be local, + if nothing says specifically). */ + +int within_function; + +/* Size of a COFF symbol. I think it is always 18, so I'm not sure + there is any reason not to just use a #define, but might as well + ask BFD for the size and store it here, I guess. */ + +static unsigned local_symesz; + +struct coff_symfile_info { + file_ptr min_lineno_offset; /* Where in file lowest line#s are */ + file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ + + /* Pointer to the string table. */ + char *strtbl; + + /* Pointer to debug section. */ + char *debugsec; + + /* Pointer to the a.out symbol table. */ + char *symtbl; + + /* Number of symbols in symtbl. */ + int symtbl_num_syms; +}; + +static struct complaint storclass_complaint = + {"Unexpected storage class: %d", 0, 0}; + +static struct complaint bf_notfound_complaint = + {"line numbers off, `.bf' symbol not found", 0, 0}; + +static struct complaint ef_complaint = + {"Mismatched .ef symbol ignored starting at symnum %d", 0, 0}; + +static struct complaint eb_complaint = + {"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; + +static void +enter_line_range PARAMS ((struct subfile *, unsigned, unsigned, + CORE_ADDR, CORE_ADDR, unsigned *)); + +static void +init_stringtab PARAMS ((bfd *, file_ptr, struct objfile *)); + +static void +xcoff_symfile_init PARAMS ((struct objfile *)); + +static void +xcoff_new_init PARAMS ((struct objfile *)); + +static void +xcoff_symfile_finish PARAMS ((struct objfile *)); + +static struct section_offsets * +xcoff_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +find_linenos PARAMS ((bfd *, sec_ptr, PTR)); + +static char * +coff_getfilename PARAMS ((union internal_auxent *, struct objfile *)); + +static void +read_symbol PARAMS ((struct internal_syment *, int)); + +static int +read_symbol_lineno PARAMS ((int)); + +static int +read_symbol_nvalue PARAMS ((int)); + +static struct symbol * +process_xcoff_symbol PARAMS ((struct coff_symbol *, struct objfile *)); + +static void +read_xcoff_symtab PARAMS ((struct partial_symtab *)); + +static void +add_stab_to_list PARAMS ((char *, struct pending_stabs **)); + + +/* Translate from a COFF section number (target_index) to a SECT_OFF_* + code. */ +static int secnum_to_section PARAMS ((int, struct objfile *)); + +struct find_targ_sec_arg { + int targ_index; + int *resultp; +}; + +static void find_targ_sec PARAMS ((bfd *, asection *, void *)); + +static void find_targ_sec (abfd, sect, obj) + bfd *abfd; + asection *sect; + PTR obj; +{ + struct find_targ_sec_arg *args = (struct find_targ_sec_arg *)obj; + if (sect->target_index == args->targ_index) + { + /* This is the section. Figure out what SECT_OFF_* code it is. */ + if (bfd_get_section_flags (abfd, sect) & SEC_CODE) + *args->resultp = SECT_OFF_TEXT; + else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) + *args->resultp = SECT_OFF_DATA; + else + *args->resultp = SECT_OFF_BSS; + } +} + +/* Return the section number (SECT_OFF_*) that CS points to. */ +static int +secnum_to_section (secnum, objfile) + int secnum; + struct objfile *objfile; +{ + int off = SECT_OFF_TEXT; + struct find_targ_sec_arg args; + args.targ_index = secnum; + args.resultp = &off; + bfd_map_over_sections (objfile->obfd, find_targ_sec, &args); + return off; +} + +/* add a given stab string into given stab vector. */ + +static void +add_stab_to_list (stabname, stabvector) +char *stabname; +struct pending_stabs **stabvector; +{ + if ( *stabvector == NULL) { + *stabvector = (struct pending_stabs *) + xmalloc (sizeof (struct pending_stabs) + + INITIAL_STABVECTOR_LENGTH * sizeof (char*)); + (*stabvector)->count = 0; + (*stabvector)->length = INITIAL_STABVECTOR_LENGTH; + } + else if ((*stabvector)->count >= (*stabvector)->length) { + (*stabvector)->length += INITIAL_STABVECTOR_LENGTH; + *stabvector = (struct pending_stabs *) + xrealloc ((char *) *stabvector, sizeof (struct pending_stabs) + + (*stabvector)->length * sizeof (char*)); + } + (*stabvector)->stab [(*stabvector)->count++] = stabname; +} + +/* Linenos are processed on a file-by-file basis. + + Two reasons: + + 1) xlc (IBM's native c compiler) postpones static function code + emission to the end of a compilation unit. This way it can + determine if those functions (statics) are needed or not, and + can do some garbage collection (I think). This makes line + numbers and corresponding addresses unordered, and we end up + with a line table like: + + + lineno addr + foo() 10 0x100 + 20 0x200 + 30 0x300 + + foo3() 70 0x400 + 80 0x500 + 90 0x600 + + static foo2() + 40 0x700 + 50 0x800 + 60 0x900 + + and that breaks gdb's binary search on line numbers, if the + above table is not sorted on line numbers. And that sort + should be on function based, since gcc can emit line numbers + like: + + 10 0x100 - for the init/test part of a for stmt. + 20 0x200 + 30 0x300 + 10 0x400 - for the increment part of a for stmt. + + arrange_linetable() will do this sorting. + + 2) aix symbol table might look like: + + c_file // beginning of a new file + .bi // beginning of include file + .ei // end of include file + .bi + .ei + + basically, .bi/.ei pairs do not necessarily encapsulate + their scope. They need to be recorded, and processed later + on when we come the end of the compilation unit. + Include table (inclTable) and process_linenos() handle + that. */ + +/* compare line table entry addresses. */ + +static int +compare_lte (lte1, lte2) + struct linetable_entry *lte1, *lte2; +{ + return lte1->pc - lte2->pc; +} + +/* Give a line table with function entries are marked, arrange its functions + in assending order and strip off function entry markers and return it in + a newly created table. If the old one is good enough, return the old one. */ +/* FIXME: I think all this stuff can be replaced by just passing + sort_linevec = 1 to end_symtab. */ + +static struct linetable * +arrange_linetable (oldLineTb) + struct linetable *oldLineTb; /* old linetable */ +{ + int ii, jj, + newline, /* new line count */ + function_count; /* # of functions */ + + struct linetable_entry *fentry; /* function entry vector */ + int fentry_size; /* # of function entries */ + struct linetable *newLineTb; /* new line table */ + +#define NUM_OF_FUNCTIONS 20 + + fentry_size = NUM_OF_FUNCTIONS; + fentry = (struct linetable_entry*) + xmalloc (fentry_size * sizeof (struct linetable_entry)); + + for (function_count=0, ii=0; ii nitems; ++ii) { + + if (oldLineTb->item[ii].line == 0) { /* function entry found. */ + + if (function_count >= fentry_size) { /* make sure you have room. */ + fentry_size *= 2; + fentry = (struct linetable_entry*) + xrealloc (fentry, fentry_size * sizeof (struct linetable_entry)); + } + fentry[function_count].line = ii; + fentry[function_count].pc = oldLineTb->item[ii].pc; + ++function_count; + } + } + + if (function_count == 0) { + free (fentry); + return oldLineTb; + } + else if (function_count > 1) + qsort (fentry, function_count, sizeof(struct linetable_entry), compare_lte); + + /* allocate a new line table. */ + newLineTb = (struct linetable *) + xmalloc + (sizeof (struct linetable) + + (oldLineTb->nitems - function_count) * sizeof (struct linetable_entry)); + + /* if line table does not start with a function beginning, copy up until + a function begin. */ + + newline = 0; + if (oldLineTb->item[0].line != 0) + for (newline=0; + newline < oldLineTb->nitems && oldLineTb->item[newline].line; ++newline) + newLineTb->item[newline] = oldLineTb->item[newline]; + + /* Now copy function lines one by one. */ + + for (ii=0; ii < function_count; ++ii) { + for (jj = fentry[ii].line + 1; + jj < oldLineTb->nitems && oldLineTb->item[jj].line != 0; + ++jj, ++newline) + newLineTb->item[newline] = oldLineTb->item[jj]; + } + free (fentry); + newLineTb->nitems = oldLineTb->nitems - function_count; + return newLineTb; +} + +/* include file support: C_BINCL/C_EINCL pairs will be kept in the + following `IncludeChain'. At the end of each symtab (end_symtab), + we will determine if we should create additional symtab's to + represent if (the include files. */ + + +typedef struct _inclTable { + char *name; /* include filename */ + + /* Offsets to the line table. end points to the last entry which is + part of this include file. */ + int begin, end; + + struct subfile *subfile; + unsigned funStartLine; /* start line # of its function */ +} InclTable; + +#define INITIAL_INCLUDE_TABLE_LENGTH 20 +static InclTable *inclTable; /* global include table */ +static int inclIndx; /* last entry to table */ +static int inclLength; /* table length */ +static int inclDepth; /* nested include depth */ + +static void allocate_include_entry PARAMS ((void)); + +static void +record_include_begin (cs) +struct coff_symbol *cs; +{ + if (inclDepth) + { + /* In xcoff, we assume include files cannot be nested (not in .c files + of course, but in corresponding .s files.). */ + + /* This can happen with old versions of GCC. + GCC 2.3.3-930426 does not exhibit this on a test case which + a user said produced the message for him. */ + static struct complaint msg = {"Nested C_BINCL symbols", 0, 0}; + complain (&msg); + } + ++inclDepth; + + allocate_include_entry (); + + inclTable [inclIndx].name = cs->c_name; + inclTable [inclIndx].begin = cs->c_value; +} + +static void +record_include_end (cs) +struct coff_symbol *cs; +{ + InclTable *pTbl; + + if (inclDepth == 0) + { + static struct complaint msg = {"Mismatched C_BINCL/C_EINCL pair", 0, 0}; + complain (&msg); + } + + allocate_include_entry (); + + pTbl = &inclTable [inclIndx]; + pTbl->end = cs->c_value; + + --inclDepth; + ++inclIndx; +} + +static void +allocate_include_entry () +{ + if (inclTable == NULL) + { + inclTable = (InclTable *) + xmalloc (sizeof (InclTable) * INITIAL_INCLUDE_TABLE_LENGTH); + memset (inclTable, + '\0', sizeof (InclTable) * INITIAL_INCLUDE_TABLE_LENGTH); + inclLength = INITIAL_INCLUDE_TABLE_LENGTH; + inclIndx = 0; + } + else if (inclIndx >= inclLength) + { + inclLength += INITIAL_INCLUDE_TABLE_LENGTH; + inclTable = (InclTable *) + xrealloc (inclTable, sizeof (InclTable) * inclLength); + memset (inclTable + inclLength - INITIAL_INCLUDE_TABLE_LENGTH, + '\0', sizeof (InclTable)*INITIAL_INCLUDE_TABLE_LENGTH); + } +} + +/* Global variable to pass the psymtab down to all the routines involved + in psymtab to symtab processing. */ +static struct partial_symtab *this_symtab_psymtab; + +/* given the start and end addresses of a compilation unit (or a csect, + at times) process its lines and create appropriate line vectors. */ + +static void +process_linenos (start, end) + CORE_ADDR start, end; +{ + int offset, ii; + file_ptr max_offset = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->max_lineno_offset; + + /* subfile structure for the main compilation unit. */ + struct subfile main_subfile; + + /* In the main source file, any time we see a function entry, we + reset this variable to function's absolute starting line number. + All the following line numbers in the function are relative to + this, and we record absolute line numbers in record_line(). */ + + unsigned int main_source_baseline = 0; + + unsigned *firstLine; + + offset = + ((struct symloc *)this_symtab_psymtab->read_symtab_private)->lineno_off; + if (offset == 0) + goto return_after_cleanup; + + memset (&main_subfile, '\0', sizeof (main_subfile)); + + if (inclIndx == 0) + /* All source lines were in the main source file. None in include files. */ + + enter_line_range (&main_subfile, offset, 0, start, end, + &main_source_baseline); + + else + { + /* There was source with line numbers in include files. */ + main_source_baseline = 0; + for (ii=0; ii < inclIndx; ++ii) + { + struct subfile *tmpSubfile; + + /* If there is main file source before include file, enter it. */ + if (offset < inclTable[ii].begin) + { + enter_line_range + (&main_subfile, offset, inclTable[ii].begin - LINESZ, + start, 0, &main_source_baseline); + } + + /* Have a new subfile for the include file. */ + + tmpSubfile = inclTable[ii].subfile = + (struct subfile *) xmalloc (sizeof (struct subfile)); + + memset (tmpSubfile, '\0', sizeof (struct subfile)); + firstLine = &(inclTable[ii].funStartLine); + + /* Enter include file's lines now. */ + enter_line_range (tmpSubfile, inclTable[ii].begin, + inclTable[ii].end, start, 0, firstLine); + + if (offset <= inclTable[ii].end) + offset = inclTable[ii].end + LINESZ; + } + + /* All the include files' line have been processed at this point. Now, + enter remaining lines of the main file, if any left. */ + if (offset < max_offset + 1 - LINESZ) + { + enter_line_range (&main_subfile, offset, 0, start, end, + &main_source_baseline); + } + } + + /* Process main file's line numbers. */ + if (main_subfile.line_vector) + { + struct linetable *lineTb, *lv; + + lv = main_subfile.line_vector; + + /* Line numbers are not necessarily ordered. xlc compilation will + put static function to the end. */ + + lineTb = arrange_linetable (lv); + if (lv == lineTb) + { + current_subfile->line_vector = (struct linetable *) + xrealloc (lv, (sizeof (struct linetable) + + lv->nitems * sizeof (struct linetable_entry))); + } + else + { + free (lv); + current_subfile->line_vector = lineTb; + } + + current_subfile->line_vector_length = + current_subfile->line_vector->nitems; + } + + /* Now, process included files' line numbers. */ + + for (ii=0; ii < inclIndx; ++ii) + { + if ((inclTable[ii].subfile)->line_vector) /* Useless if!!! FIXMEmgo */ + { + struct linetable *lineTb, *lv; + + lv = (inclTable[ii].subfile)->line_vector; + + /* Line numbers are not necessarily ordered. xlc compilation will + put static function to the end. */ + + lineTb = arrange_linetable (lv); + + push_subfile (); + + /* For the same include file, we might want to have more than one + subfile. This happens if we have something like: + + ...... + #include "foo.h" + ...... + #include "foo.h" + ...... + + while foo.h including code in it. (stupid but possible) + Since start_subfile() looks at the name and uses an + existing one if finds, we need to provide a fake name and + fool it. */ + +#if 0 + start_subfile (inclTable[ii].name, (char*)0); +#else + { + /* Pick a fake name that will produce the same results as this + one when passed to deduce_language_from_filename. Kludge on + top of kludge. */ + char *fakename = strrchr (inclTable[ii].name, '.'); + if (fakename == NULL) + fakename = " ?"; + start_subfile (fakename, (char*)0); + free (current_subfile->name); + } + current_subfile->name = strdup (inclTable[ii].name); +#endif + + if (lv == lineTb) + { + current_subfile->line_vector = + (struct linetable *) xrealloc + (lv, (sizeof (struct linetable) + + lv->nitems * sizeof (struct linetable_entry))); + + } + else + { + free (lv); + current_subfile->line_vector = lineTb; + } + + current_subfile->line_vector_length = + current_subfile->line_vector->nitems; + start_subfile (pop_subfile (), (char*)0); + } + } + + return_after_cleanup: + + /* We don't want to keep alloc/free'ing the global include file table. */ + inclIndx = 0; + + /* Start with a fresh subfile structure for the next file. */ + memset (&main_subfile, '\0', sizeof (struct subfile)); +} + +void +aix_process_linenos () +{ + /* process line numbers and enter them into line vector */ + process_linenos (last_source_start_addr, cur_src_end_addr); +} + + +/* Enter a given range of lines into the line vector. + can be called in the following two ways: + enter_line_range (subfile, beginoffset, endoffset, startaddr, 0, firstLine) or + enter_line_range (subfile, beginoffset, 0, startaddr, endaddr, firstLine) + + endoffset points to the last line table entry that we should pay + attention to. */ + +static void +enter_line_range (subfile, beginoffset, endoffset, startaddr, endaddr, + firstLine) + struct subfile *subfile; + unsigned beginoffset, endoffset; /* offsets to line table */ + CORE_ADDR startaddr, endaddr; + unsigned *firstLine; +{ + unsigned int curoffset; + CORE_ADDR addr; + struct external_lineno ext_lnno; + struct internal_lineno int_lnno; + unsigned int limit_offset; + bfd *abfd; + + if (endoffset == 0 && startaddr == 0 && endaddr == 0) + return; + curoffset = beginoffset; + limit_offset = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->max_lineno_offset; + + if (endoffset != 0) + { + if (endoffset >= limit_offset) + { + static struct complaint msg = + {"Bad line table offset in C_EINCL directive", 0, 0}; + complain (&msg); + return; + } + limit_offset = endoffset; + } + else + limit_offset -= 1; + abfd = this_symtab_psymtab->objfile->obfd; + + while (curoffset <= limit_offset) + { + bfd_seek (abfd, curoffset, SEEK_SET); + bfd_read (&ext_lnno, sizeof (struct external_lineno), 1, abfd); + bfd_coff_swap_lineno_in (abfd, &ext_lnno, &int_lnno); + + /* Find the address this line represents. */ + addr = (int_lnno.l_lnno + ? int_lnno.l_addr.l_paddr + : read_symbol_nvalue (int_lnno.l_addr.l_symndx)); + addr += ANOFFSET (this_symtab_psymtab->objfile->section_offsets, + SECT_OFF_TEXT); + + if (addr < startaddr || (endaddr && addr >= endaddr)) + return; + + if (int_lnno.l_lnno == 0) + { + *firstLine = read_symbol_lineno (int_lnno.l_addr.l_symndx); + record_line (subfile, 0, addr); + --(*firstLine); + } + else + record_line (subfile, *firstLine + int_lnno.l_lnno, addr); + curoffset += LINESZ; + } +} + + +/* Save the vital information for use when closing off the current file. + NAME is the file name the symbols came from, START_ADDR is the first + text address for the file, and SIZE is the number of bytes of text. */ + +#define complete_symtab(name, start_addr) { \ + last_source_file = savestring (name, strlen (name)); \ + last_source_start_addr = start_addr; \ +} + + +/* Refill the symbol table input buffer + and set the variables that control fetching entries from it. + Reports an error if no data available. + This function can read past the end of the symbol table + (into the string table) but this does no harm. */ + +/* Reading symbol table has to be fast! Keep the followings as macros, rather + than functions. */ + +#define RECORD_MINIMAL_SYMBOL(NAME, ADDR, TYPE, SECTION, OBJFILE) \ +{ \ + char *namestr; \ + namestr = (NAME); \ + if (namestr[0] == '.') ++namestr; \ + prim_record_minimal_symbol_and_info (namestr, (ADDR), (TYPE), \ + (char *)NULL, (SECTION), (OBJFILE)); \ + misc_func_recorded = 1; \ +} + + +/* xcoff has static blocks marked in `.bs', `.es' pairs. They cannot be + nested. At any given time, a symbol can only be in one static block. + This is the base address of current static block, zero if non exists. */ + +static int static_block_base = 0; + +/* Section number for the current static block. */ + +static int static_block_section = -1; + +/* true if space for symbol name has been allocated. */ + +static int symname_alloced = 0; + +/* Next symbol to read. Pointer into raw seething symbol table. */ + +static char *raw_symbol; + +/* This is the function which stabsread.c calls to get symbol + continuations. */ +static char * +xcoff_next_symbol_text (objfile) + struct objfile *objfile; +{ + struct internal_syment symbol; + static struct complaint msg = + {"Unexpected symbol continuation", 0, 0}; + char *retval; + /* FIXME: is this the same as the passed arg? */ + objfile = this_symtab_psymtab->objfile; + + bfd_coff_swap_sym_in (objfile->obfd, raw_symbol, &symbol); + if (symbol.n_zeroes) + { + complain (&msg); + + /* Return something which points to '\0' and hope the symbol reading + code does something reasonable. */ + retval = ""; + } + else if (symbol.n_sclass & 0x80) + { + retval = + ((struct coff_symfile_info *)objfile->sym_private)->debugsec + + symbol.n_offset; + raw_symbol += + coff_data (objfile->obfd)->local_symesz; + ++symnum; + } + else + { + complain (&msg); + + /* Return something which points to '\0' and hope the symbol reading + code does something reasonable. */ + retval = ""; + } + return retval; +} + +/* Read symbols for a given partial symbol table. */ + +static void +read_xcoff_symtab (pst) + struct partial_symtab *pst; +{ + struct objfile *objfile = pst->objfile; + bfd *abfd = objfile->obfd; + char *raw_auxptr; /* Pointer to first raw aux entry for sym */ + char *strtbl = ((struct coff_symfile_info *)objfile->sym_private)->strtbl; + char *debugsec = + ((struct coff_symfile_info *)objfile->sym_private)->debugsec; + + struct internal_syment symbol[1]; + union internal_auxent main_aux; + struct coff_symbol cs[1]; + CORE_ADDR file_start_addr = 0; + CORE_ADDR file_end_addr = 0; + + int next_file_symnum = -1; + unsigned int max_symnum; + int just_started = 1; + int depth = 0; + int fcn_start_addr = 0; + + struct coff_symbol fcn_stab_saved; + + /* fcn_cs_saved is global because process_xcoff_symbol needs it. */ + union internal_auxent fcn_aux_saved; + struct context_stack *new; + + char *filestring = " _start_ "; /* Name of the current file. */ + + char *last_csect_name; /* last seen csect's name and value */ + CORE_ADDR last_csect_val; + int last_csect_sec; + + this_symtab_psymtab = pst; + + /* Get the appropriate COFF "constants" related to the file we're + handling. */ + local_symesz = coff_data (abfd)->local_symesz; + + last_source_file = NULL; + last_csect_name = 0; + last_csect_val = 0; + + start_stabs (); + start_symtab (filestring, (char *)NULL, file_start_addr); + symnum = ((struct symloc *)pst->read_symtab_private)->first_symnum; + max_symnum = + symnum + ((struct symloc *)pst->read_symtab_private)->numsyms; + first_object_file_end = 0; + + raw_symbol = + ((struct coff_symfile_info *) objfile->sym_private)->symtbl + + symnum * local_symesz; + + while (symnum < max_symnum) + { + + QUIT; /* make this command interruptable. */ + + /* READ_ONE_SYMBOL (symbol, cs, symname_alloced); */ + /* read one symbol into `cs' structure. After processing the + whole symbol table, only string table will be kept in memory, + symbol table and debug section of xcoff will be freed. Thus + we can mark symbols with names in string table as + `alloced'. */ + { + int ii; + + /* Swap and align the symbol into a reasonable C structure. */ + bfd_coff_swap_sym_in (abfd, raw_symbol, symbol); + + cs->c_symnum = symnum; + cs->c_naux = symbol->n_numaux; + if (symbol->n_zeroes) + { + symname_alloced = 0; + /* We must use the original, unswapped, name here so the name field + pointed to by cs->c_name will persist throughout xcoffread. If + we use the new field, it gets overwritten for each symbol. */ + cs->c_name = ((struct external_syment *)raw_symbol)->e.e_name; + /* If it's exactly E_SYMNMLEN characters long it isn't + '\0'-terminated. */ + if (cs->c_name[E_SYMNMLEN - 1] != '\0') + { + char *p; + p = obstack_alloc (&objfile->symbol_obstack, E_SYMNMLEN + 1); + strncpy (p, cs->c_name, E_SYMNMLEN); + p[E_SYMNMLEN] = '\0'; + cs->c_name = p; + symname_alloced = 1; + } + } + else if (symbol->n_sclass & 0x80) + { + cs->c_name = debugsec + symbol->n_offset; + symname_alloced = 0; + } + else + { + /* in string table */ + cs->c_name = strtbl + (int)symbol->n_offset; + symname_alloced = 1; + } + cs->c_value = symbol->n_value; + cs->c_sclass = symbol->n_sclass; + cs->c_secnum = symbol->n_scnum; + cs->c_type = (unsigned)symbol->n_type; + + raw_symbol += coff_data (abfd)->local_symesz; + ++symnum; + + /* Save addr of first aux entry. */ + raw_auxptr = raw_symbol; + + /* Skip all the auxents associated with this symbol. */ + for (ii = symbol->n_numaux; ii; --ii) + { + raw_symbol += coff_data (abfd)->local_auxesz; + ++symnum; + } + } + + /* if symbol name starts with ".$" or "$", ignore it. */ + if (cs->c_name[0] == '$' + || (cs->c_name[1] == '$' && cs->c_name[0] == '.')) + continue; + + if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) + { + if (last_source_file) + { + pst->symtab = + end_symtab (cur_src_end_addr, objfile, SECT_OFF_TEXT); + end_stabs (); + } + + start_stabs (); + start_symtab ("_globals_", (char *)NULL, (CORE_ADDR)0); + cur_src_end_addr = first_object_file_end; + /* done with all files, everything from here on is globals */ + } + + /* if explicitly specified as a function, treat is as one. */ + if (ISFCN(cs->c_type) && cs->c_sclass != C_TPDEF) + { + bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, + 0, cs->c_naux, &main_aux); + goto function_entry_point; + } + + if ((cs->c_sclass == C_EXT || cs->c_sclass == C_HIDEXT) + && cs->c_naux == 1) + { + /* Dealing with a symbol with a csect entry. */ + +#define CSECT(PP) ((PP)->x_csect) +#define CSECT_LEN(PP) (CSECT(PP).x_scnlen.l) +#define CSECT_ALIGN(PP) (SMTYP_ALIGN(CSECT(PP).x_smtyp)) +#define CSECT_SMTYP(PP) (SMTYP_SMTYP(CSECT(PP).x_smtyp)) +#define CSECT_SCLAS(PP) (CSECT(PP).x_smclas) + + /* Convert the auxent to something we can access. */ + bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, + 0, cs->c_naux, &main_aux); + + switch (CSECT_SMTYP (&main_aux)) + { + + case XTY_ER: + /* Ignore all external references. */ + continue; + + case XTY_SD: + /* A section description. */ + { + switch (CSECT_SCLAS (&main_aux)) + { + + case XMC_PR: + { + + /* A program csect is seen. We have to allocate one + symbol table for each program csect. Normally gdb + prefers one symtab for each source file. In case + of AIX, one source file might include more than one + [PR] csect, and they don't have to be adjacent in + terms of the space they occupy in memory. Thus, one + single source file might get fragmented in the + memory and gdb's file start and end address + approach does not work! GCC (and I think xlc) seem + to put all the code in the unnamed program csect. */ + + if (last_csect_name) + { + complete_symtab (filestring, file_start_addr); + cur_src_end_addr = file_end_addr; + end_symtab (file_end_addr, objfile, SECT_OFF_TEXT); + end_stabs (); + start_stabs (); + /* Give all csects for this source file the same + name. */ + start_symtab (filestring, NULL, (CORE_ADDR)0); + } + + /* If this is the very first csect seen, + basically `__start'. */ + if (just_started) + { + first_object_file_end + = cs->c_value + CSECT_LEN (&main_aux); + just_started = 0; + } + + file_start_addr = + cs->c_value + ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT); + file_end_addr = file_start_addr + CSECT_LEN (&main_aux); + + if (cs->c_name && cs->c_name[0] == '.') + { + last_csect_name = cs->c_name; + last_csect_val = cs->c_value; + last_csect_sec = secnum_to_section (cs->c_secnum, objfile); + } + } + continue; + + /* All other symbols are put into the minimal symbol + table only. */ + + case XMC_RW: + continue; + + case XMC_TC0: + continue; + + case XMC_TC: + continue; + + default: + /* Ignore the symbol. */ + continue; + } + } + break; + + case XTY_LD: + + switch (CSECT_SCLAS (&main_aux)) + { + case XMC_PR: + /* a function entry point. */ + function_entry_point: + + fcn_start_addr = cs->c_value; + + /* save the function header info, which will be used + when `.bf' is seen. */ + fcn_cs_saved = *cs; + fcn_aux_saved = main_aux; + continue; + + case XMC_GL: + /* shared library function trampoline code entry point. */ + continue; + + case XMC_DS: + /* The symbols often have the same names as debug symbols for + functions, and confuse lookup_symbol. */ + continue; + + default: + /* xlc puts each variable in a separate csect, so we get + an XTY_SD for each variable. But gcc puts several + variables in a csect, so that each variable only gets + an XTY_LD. This will typically be XMC_RW; I suspect + XMC_RO and XMC_BS might be possible too. + These variables are put in the minimal symbol table + only. */ + continue; + } + break; + + case XTY_CM: + /* Common symbols are put into the minimal symbol table only. */ + continue; + + default: + break; + } + } + + switch (cs->c_sclass) + { + + case C_FILE: + + /* c_value field contains symnum of next .file entry in table + or symnum of first global after last .file. */ + + next_file_symnum = cs->c_value; + + /* Complete symbol table for last object file containing + debugging information. */ + + /* Whether or not there was a csect in the previous file, we + have to call `end_stabs' and `start_stabs' to reset + type_vector, line_vector, etc. structures. */ + + complete_symtab (filestring, file_start_addr); + cur_src_end_addr = file_end_addr; + end_symtab (file_end_addr, objfile, SECT_OFF_TEXT); + end_stabs (); + + /* XCOFF, according to the AIX 3.2 documentation, puts the filename + in cs->c_name. But xlc 1.3.0.2 has decided to do things the + standard COFF way and put it in the auxent. We use the auxent if + the symbol is ".file" and an auxent exists, otherwise use the symbol + itself. Simple enough. */ + if (!strcmp (cs->c_name, ".file") && cs->c_naux > 0) + { + bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, + 0, cs->c_naux, &main_aux); + filestring = coff_getfilename (&main_aux, objfile); + } + else + filestring = cs->c_name; + + start_stabs (); + start_symtab (filestring, (char *)NULL, (CORE_ADDR)0); + last_csect_name = 0; + + /* reset file start and end addresses. A compilation unit with no text + (only data) should have zero file boundaries. */ + file_start_addr = file_end_addr = 0; + break; + + case C_FUN: + fcn_stab_saved = *cs; + break; + + case C_FCN: + if (STREQ (cs->c_name, ".bf")) + { + CORE_ADDR off = ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT); + bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, + 0, cs->c_naux, &main_aux); + + within_function = 1; + + new = push_context (0, fcn_start_addr + off); + + new->name = define_symbol + (fcn_cs_saved.c_value + off, + fcn_stab_saved.c_name, 0, 0, objfile); + if (new->name != NULL) + SYMBOL_SECTION (new->name) = SECT_OFF_TEXT; + } + else if (STREQ (cs->c_name, ".ef")) + { + + bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, + 0, cs->c_naux, &main_aux); + + /* The value of .ef is the address of epilogue code; + not useful for gdb. */ + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&ef_complaint, cs->c_symnum); + within_function = 0; + break; + } + new = pop_context (); + /* Stack must be empty now. */ + if (context_stack_depth > 0 || new == NULL) + { + complain (&ef_complaint, cs->c_symnum); + within_function = 0; + break; + } + + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, + (fcn_cs_saved.c_value + + fcn_aux_saved.x_sym.x_misc.x_fsize + + ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT)), + objfile); + within_function = 0; + } + break; + + case C_BSTAT: + /* Begin static block. */ + { + struct internal_syment symbol; + + read_symbol (&symbol, cs->c_value); + static_block_base = symbol.n_value; + static_block_section = + secnum_to_section (symbol.n_scnum, objfile); + } + break; + + case C_ESTAT: + /* End of static block. */ + static_block_base = 0; + static_block_section = -1; + break; + + case C_ARG: + case C_REGPARM: + case C_REG: + case C_TPDEF: + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + { + static struct complaint msg = + {"Unrecognized storage class %d.", 0, 0}; + complain (&msg, cs->c_sclass); + } + break; + + case C_LABEL: + case C_NULL: + /* Ignore these. */ + break; + + case C_HIDEXT: + case C_STAT: + break; + + case C_BINCL: + /* beginning of include file */ + /* In xlc output, C_BINCL/C_EINCL pair doesn't show up in sorted + order. Thus, when wee see them, we might not know enough info + to process them. Thus, we'll be saving them into a table + (inclTable) and postpone their processing. */ + + record_include_begin (cs); + break; + + case C_EINCL: + /* End of include file. */ + /* See the comment after case C_BINCL. */ + record_include_end (cs); + break; + + case C_BLOCK: + if (STREQ (cs->c_name, ".bb")) + { + depth++; + new = push_context (depth, + (cs->c_value + + ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT))); + } + else if (STREQ (cs->c_name, ".eb")) + { + if (context_stack_depth <= 0) + { /* We attempted to pop an empty context stack */ + complain (&eb_complaint, cs->c_symnum); + break; + } + new = pop_context (); + if (depth-- != new->depth) + { + complain (&eb_complaint, cs->c_symnum); + break; + } + if (local_symbols && context_stack_depth > 0) + { + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, + (cs->c_value + + ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT)), + objfile); + } + local_symbols = new->locals; + } + break; + + default: + process_xcoff_symbol (cs, objfile); + break; + } + } + + if (last_source_file) + { + struct symtab *s; + + complete_symtab (filestring, file_start_addr); + cur_src_end_addr = file_end_addr; + s = end_symtab (file_end_addr, objfile, SECT_OFF_TEXT); + /* When reading symbols for the last C_FILE of the objfile, try + to make sure that we set pst->symtab to the symtab for the + file, not to the _globals_ symtab. I'm not sure whether this + actually works right or when/if it comes up. */ + if (pst->symtab == NULL) + pst->symtab = s; + end_stabs (); + } +} + +#define SYMBOL_DUP(SYMBOL1, SYMBOL2) \ + (SYMBOL2) = (struct symbol *) \ + obstack_alloc (&objfile->symbol_obstack, sizeof (struct symbol)); \ + *(SYMBOL2) = *(SYMBOL1); + + +#define SYMNAME_ALLOC(NAME, ALLOCED) \ + (ALLOCED) ? (NAME) : obstack_copy0 (&objfile->symbol_obstack, (NAME), strlen (NAME)); + + +static struct type *func_symbol_type; +static struct type *var_symbol_type; + +/* process one xcoff symbol. */ + +static struct symbol * +process_xcoff_symbol (cs, objfile) + register struct coff_symbol *cs; + struct objfile *objfile; +{ + struct symbol onesymbol; + register struct symbol *sym = &onesymbol; + struct symbol *sym2 = NULL; + char *name, *pp; + + int sec; + CORE_ADDR off; + + if (cs->c_secnum < 0) + { + /* The value is a register number, offset within a frame, etc., + and does not get relocated. */ + off = 0; + sec = -1; + } + else + { + sec = secnum_to_section (cs->c_secnum, objfile); + off = ANOFFSET (objfile->section_offsets, sec); + } + + name = cs->c_name; + if (name[0] == '.') + ++name; + + memset (sym, '\0', sizeof (struct symbol)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = cs->c_value + off; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_SECTION (sym) = secnum_to_section (cs->c_secnum, objfile); + + if (ISFCN (cs->c_type)) + { + /* At this point, we don't know the type of the function. This + will be patched with the type from its stab entry later on in + patch_block_stabs (), unless the file was compiled without -g. */ + + SYMBOL_NAME (sym) = SYMNAME_ALLOC (name, symname_alloced); + SYMBOL_TYPE (sym) = func_symbol_type; + + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_DUP (sym, sym2); + + if (cs->c_sclass == C_EXT) + add_symbol_to_list (sym2, &global_symbols); + else if (cs->c_sclass == C_HIDEXT || cs->c_sclass == C_STAT) + add_symbol_to_list (sym2, &file_symbols); + } + else + { + /* In case we can't figure out the type, provide default. */ + SYMBOL_TYPE (sym) = var_symbol_type; + + switch (cs->c_sclass) + { +#if 0 + /* The values of functions and global symbols are now resolved + via the global_sym_chain in stabsread.c. */ + case C_FUN: + if (fcn_cs_saved.c_sclass == C_EXT) + add_stab_to_list (name, &global_stabs); + else + add_stab_to_list (name, &file_stabs); + break; + + case C_GSYM: + add_stab_to_list (name, &global_stabs); + break; +#endif + + case C_BCOMM: + common_block_start (cs->c_name, objfile); + break; + + case C_ECOMM: + common_block_end (objfile); + break; + + default: + complain (&storclass_complaint, cs->c_sclass); + /* FALLTHROUGH */ + + case C_DECL: + case C_PSYM: + case C_RPSYM: + case C_ECOML: + case C_LSYM: + case C_RSYM: + case C_GSYM: + + { + sym = define_symbol (cs->c_value + off, cs->c_name, 0, 0, objfile); + if (sym != NULL) + { + SYMBOL_SECTION (sym) = sec; + } + return sym; + } + + case C_STSYM: + + /* For xlc (not GCC), the 'V' symbol descriptor is used for + all statics and we need to distinguish file-scope versus + function-scope using within_function. We do this by + changing the string we pass to define_symbol to use 'S' + where we need to, which is not necessarily super-clean, + but seems workable enough. */ + + if (*name == ':' || (pp = (char *) strchr(name, ':')) == NULL) + return NULL; + + ++pp; + if (*pp == 'V' && !within_function) + *pp = 'S'; + sym = define_symbol ((cs->c_value + + ANOFFSET (objfile->section_offsets, + static_block_section)), + cs->c_name, 0, 0, objfile); + if (sym != NULL) + { + SYMBOL_VALUE (sym) += static_block_base; + SYMBOL_SECTION (sym) = static_block_section; + } + return sym; + + } + } + return sym2; +} + +/* Extract the file name from the aux entry of a C_FILE symbol. Return + only the last component of the name. Result is in static storage and + is only good for temporary use. */ + +static char * +coff_getfilename (aux_entry, objfile) + union internal_auxent *aux_entry; + struct objfile *objfile; +{ + static char buffer[BUFSIZ]; + register char *temp; + char *result; + + if (aux_entry->x_file.x_n.x_zeroes == 0) + strcpy (buffer, + ((struct coff_symfile_info *)objfile->sym_private)->strtbl + + aux_entry->x_file.x_n.x_offset); + else + { + strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); + buffer[FILNMLEN] = '\0'; + } + result = buffer; + + /* FIXME: We should not be throwing away the information about what + directory. It should go into dirname of the symtab, or some such + place. */ + if ((temp = strrchr (result, '/')) != NULL) + result = temp + 1; + return (result); +} + +/* Set *SYMBOL to symbol number symno in symtbl. */ +static void +read_symbol (symbol, symno) + struct internal_syment *symbol; + int symno; +{ + int nsyms = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->symtbl_num_syms; + char *stbl = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->symtbl; + if (symno < 0 || symno >= nsyms) + { + static struct complaint msg = + {"Invalid symbol offset", 0, 0}; + complain (&msg); + symbol->n_value = 0; + symbol->n_scnum = -1; + return; + } + bfd_coff_swap_sym_in (this_symtab_psymtab->objfile->obfd, + stbl + (symno*local_symesz), + symbol); +} + +/* Get value corresponding to symbol number symno in symtbl. */ + +static int +read_symbol_nvalue (symno) + int symno; +{ + struct internal_syment symbol[1]; + + read_symbol (symbol, symno); + return symbol->n_value; +} + + +/* Find the address of the function corresponding to symno, where + symno is the symbol pointed to by the linetable. */ + +static int +read_symbol_lineno (symno) + int symno; +{ + int nsyms = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->symtbl_num_syms; + char *stbl = + ((struct coff_symfile_info *)this_symtab_psymtab->objfile->sym_private) + ->symtbl; + struct internal_syment symbol[1]; + union internal_auxent main_aux[1]; + + if (symno < 0) + { + complain (&bf_notfound_complaint); + return 0; + } + + /* Note that just searching for a short distance (e.g. 50 symbols) + is not enough, at least in the following case. + + .extern foo + [many .stabx entries] + [a few functions, referring to foo] + .globl foo + .bf + + What happens here is that the assembler moves the .stabx entries + to right before the ".bf" for foo, but the symbol for "foo" is before + all the stabx entries. See PR gdb/2222. */ + + /* Maintaining a table of .bf entries might be preferable to this search. + If I understand things correctly it would need to be done only for + the duration of a single psymtab to symtab conversion. */ + while (symno < nsyms) + { + bfd_coff_swap_sym_in (symfile_bfd, + stbl + (symno * local_symesz), symbol); + if (symbol->n_sclass == C_FCN && STREQ (symbol->n_name, ".bf")) + goto gotit; + symno += symbol->n_numaux + 1; + } + + complain (&bf_notfound_complaint); + return 0; + +gotit: + /* take aux entry and return its lineno */ + symno++; + bfd_coff_swap_aux_in (this_symtab_psymtab->objfile->obfd, + stbl + symno * local_symesz, + symbol->n_type, symbol->n_sclass, + 0, symbol->n_numaux, main_aux); + + return main_aux->x_sym.x_misc.x_lnsz.x_lnno; +} + +/* Support for line number handling */ + +/* This function is called for every section; it finds the outer limits + * of the line table (minimum and maximum file offset) so that the + * mainline code can read the whole thing for efficiency. + */ +static void +find_linenos (abfd, asect, vpinfo) + bfd *abfd; + sec_ptr asect; + PTR vpinfo; +{ + struct coff_symfile_info *info; + int size, count; + file_ptr offset, maxoff; + + count = asect->lineno_count; + + if (!STREQ (asect->name, ".text") || count == 0) + return; + + size = count * coff_data (abfd)->local_linesz; + info = (struct coff_symfile_info *)vpinfo; + offset = asect->line_filepos; + maxoff = offset + size; + + if (offset < info->min_lineno_offset || info->min_lineno_offset == 0) + info->min_lineno_offset = offset; + + if (maxoff > info->max_lineno_offset) + info->max_lineno_offset = maxoff; +} + +static void xcoff_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *)); + +static void +xcoff_psymtab_to_symtab_1 (pst) + 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. Shouldn't happen.\n", + pst->filename); + return; + } + + /* Read in all partial symtabs on which this one is dependent */ + 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) + { + 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); + } + xcoff_psymtab_to_symtab_1 (pst->dependencies[i]); + } + + if (((struct symloc *)pst->read_symtab_private)->numsyms != 0) + { + /* Init stuff necessary for reading in symbols. */ + stabsread_init (); + buildsym_init (); + old_chain = make_cleanup (really_free_pendings, 0); + + read_xcoff_symtab (pst); + sort_symtab_syms (pst->symtab); + + do_cleanups (old_chain); + } + + pst->readin = 1; +} + +static void xcoff_psymtab_to_symtab PARAMS ((struct partial_symtab *)); + +/* Read in all of the symbols for a given psymtab for real. + Be verbose about it if the user wants that. */ + +static void +xcoff_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + bfd *sym_bfd; + + if (!pst) + return; + + if (pst->readin) + { + fprintf_unfiltered + (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return; + } + + if (((struct symloc *)pst->read_symtab_private)->numsyms != 0 + || pst->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); + gdb_flush (gdb_stdout); + } + + sym_bfd = pst->objfile->obfd; + + next_symbol_text_func = xcoff_next_symbol_text; + + xcoff_psymtab_to_symtab_1 (pst); + + /* 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); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered ("done.\n"); + } +} + +static void +xcoff_new_init (objfile) + struct objfile *objfile; +{ + stabsread_new_init (); + buildsym_new_init (); +} + +/* Do initialization in preparation for reading symbols from OBJFILE. + + We will only be called if this is an XCOFF or XCOFF-like file. + BFD handles figuring out the format of the file, and code in symfile.c + uses BFD's determination to vector to us. */ + +static void +xcoff_symfile_init (objfile) + struct objfile *objfile; +{ + /* Allocate struct to keep track of the symfile */ + objfile -> sym_private = xmmalloc (objfile -> md, + sizeof (struct coff_symfile_info)); + + /* XCOFF 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); +} + +/* 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 +xcoff_symfile_finish (objfile) + struct objfile *objfile; +{ + if (objfile -> sym_private != NULL) + { + mfree (objfile -> md, objfile -> sym_private); + } + + /* Start with a fresh include table for the next objfile. */ + if (inclTable) + { + free (inclTable); + inclTable = NULL; + } + inclIndx = inclLength = inclDepth = 0; +} + + +static void +init_stringtab (abfd, offset, objfile) + bfd *abfd; + file_ptr offset; + struct objfile *objfile; +{ + long length; + int val; + unsigned char lengthbuf[4]; + char *strtbl; + + ((struct coff_symfile_info *)objfile->sym_private)->strtbl = NULL; + + if (bfd_seek (abfd, offset, SEEK_SET) < 0) + error ("cannot seek to string table in %s: %s", + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); + + val = bfd_read ((char *)lengthbuf, 1, sizeof lengthbuf, abfd); + length = bfd_h_get_32 (abfd, lengthbuf); + + /* If no string table is needed, then the file may end immediately + after the symbols. Just return with `strtbl' set to NULL. */ + + if (val != sizeof lengthbuf || length < sizeof lengthbuf) + return; + + /* Allocate string table from symbol_obstack. We will need this table + as long as we have its symbol table around. */ + + strtbl = (char *) obstack_alloc (&objfile->symbol_obstack, length); + ((struct coff_symfile_info *)objfile->sym_private)->strtbl = strtbl; + + /* Copy length buffer, the first byte is usually zero and is + used for stabs with a name length of zero. */ + memcpy (strtbl, lengthbuf, sizeof lengthbuf); + if (length == sizeof lengthbuf) + return; + + val = bfd_read (strtbl + sizeof lengthbuf, 1, length - sizeof lengthbuf, + abfd); + + if (val != length - sizeof lengthbuf) + error ("cannot read string table from %s: %s", + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); + if (strtbl[length - 1] != '\0') + error ("bad symbol file: string table does not end with null character"); + + return; +} + +/* If we have not yet seen a function for this psymtab, this is 0. If we + have seen one, it is the offset in the line numbers of the line numbers + for the psymtab. */ +static unsigned int first_fun_line_offset; + +static struct partial_symtab *xcoff_start_psymtab + PARAMS ((struct objfile *, struct section_offsets *, char *, int, + struct partial_symbol **, struct partial_symbol **)); + +/* Allocate and partially fill a partial symtab. It will be + completely filled at the end of the symbol list. + + SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR + is the address relative to which its symbols are (incremental) or 0 + (normal). */ + +static struct partial_symtab * +xcoff_start_psymtab (objfile, section_offsets, + filename, first_symnum, global_syms, static_syms) + struct objfile *objfile; + struct section_offsets *section_offsets; + char *filename; + int first_symnum; + struct partial_symbol **global_syms; + struct partial_symbol **static_syms; +{ + struct partial_symtab *result = + start_psymtab_common (objfile, section_offsets, + filename, + /* We fill in textlow later. */ + 0, + global_syms, static_syms); + + result->read_symtab_private = (char *) + obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc)); + ((struct symloc *)result->read_symtab_private)->first_symnum = first_symnum; + result->read_symtab = xcoff_psymtab_to_symtab; + + /* Deduce the source language from the filename for this psymtab. */ + psymtab_language = deduce_language_from_filename (filename); + + return result; +} + +static struct partial_symtab *xcoff_end_psymtab + PARAMS ((struct partial_symtab *, char **, int, int, + struct partial_symtab **, int)); + +/* Close off the current usage of PST. + Returns PST, or NULL if the partial symtab was empty and thrown away. + + CAPPING_SYMBOL_NUMBER is the end of pst (exclusive). + + INCLUDE_LIST, NUM_INCLUDES, DEPENDENCY_LIST, and NUMBER_DEPENDENCIES + are the information for includes and dependencies. */ + +static struct partial_symtab * +xcoff_end_psymtab (pst, include_list, num_includes, capping_symbol_number, + dependency_list, number_dependencies) + struct partial_symtab *pst; + char **include_list; + int num_includes; + int capping_symbol_number; + struct partial_symtab **dependency_list; + int number_dependencies; +{ + int i; + struct objfile *objfile = pst -> objfile; + + if (capping_symbol_number != -1) + ((struct symloc *)pst->read_symtab_private)->numsyms = + capping_symbol_number + - ((struct symloc *)pst->read_symtab_private)->first_symnum; + ((struct symloc *)pst->read_symtab_private)->lineno_off = + first_fun_line_offset; + first_fun_line_offset = 0; + 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); + + pst->number_of_dependencies = number_dependencies; + if (number_dependencies) + { + pst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + number_dependencies * sizeof (struct partial_symtab *)); + memcpy (pst->dependencies, dependency_list, + number_dependencies * sizeof (struct partial_symtab *)); + } + else + pst->dependencies = 0; + + for (i = 0; i < num_includes; i++) + { + struct partial_symtab *subpst = + allocate_psymtab (include_list[i], objfile); + + subpst->section_offsets = pst->section_offsets; + subpst->read_symtab_private = + (char *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc)); + ((struct symloc *)subpst->read_symtab_private)->first_symnum = 0; + ((struct symloc *)subpst->read_symtab_private)->numsyms = 0; + subpst->textlow = 0; + subpst->texthigh = 0; + + /* We could save slight bits of space by only making one of these, + shared by the entire set of include files. FIXME-someday. */ + subpst->dependencies = (struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct partial_symtab *)); + subpst->dependencies[0] = pst; + subpst->number_of_dependencies = 1; + + subpst->globals_offset = + subpst->n_global_syms = + subpst->statics_offset = + subpst->n_static_syms = 0; + + subpst->readin = 0; + subpst->symtab = 0; + subpst->read_symtab = pst->read_symtab; + } + + sort_pst_symbols (pst); + + /* If there is already a psymtab or symtab for a file of this name, + remove it. (If there is a symtab, more drastic things also + happen.) This happens in VxWorks. */ + free_named_symtabs (pst->filename); + + if (num_includes == 0 + && number_dependencies == 0 + && pst->n_global_syms == 0 + && pst->n_static_syms == 0) + { + /* Throw away this psymtab, it's empty. We can't deallocate it, since + it is on the obstack, but we can forget to chain it on the list. */ + /* Empty psymtabs happen as a result of header files which don't have + any symbols in them. There can be a lot of them. */ + struct partial_symtab *prev_pst; + + /* First, snip it out of the psymtab chain */ + + if (pst->objfile->psymtabs == pst) + pst->objfile->psymtabs = pst->next; + else + for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next) + if (prev_pst->next == pst) + prev_pst->next = pst->next; + + /* Next, put it on a free list for recycling */ + + pst->next = pst->objfile->free_psymtabs; + pst->objfile->free_psymtabs = pst; + + /* Indicate that psymtab was thrown away. */ + pst = (struct partial_symtab *)NULL; + } + return pst; +} + +static void swap_sym PARAMS ((struct internal_syment *, + union internal_auxent *, char **, char **, + unsigned int *, + struct objfile *)); + +/* Swap raw symbol at *RAW and put the name in *NAME, the symbol in + *SYMBOL, the first auxent in *AUX. Advance *RAW and *SYMNUMP over + the symbol and its auxents. */ + +static void +swap_sym (symbol, aux, name, raw, symnump, objfile) + struct internal_syment *symbol; + union internal_auxent *aux; + char **name; + char **raw; + unsigned int *symnump; + struct objfile *objfile; +{ + bfd_coff_swap_sym_in (objfile->obfd, *raw, symbol); + if (symbol->n_zeroes) + { + /* If it's exactly E_SYMNMLEN characters long it isn't + '\0'-terminated. */ + if (symbol->n_name[E_SYMNMLEN - 1] != '\0') + { + /* FIXME: wastes memory for symbols which we don't end up putting + into the minimal symbols. */ + char *p; + p = obstack_alloc (&objfile->psymbol_obstack, E_SYMNMLEN + 1); + strncpy (p, symbol->n_name, E_SYMNMLEN); + p[E_SYMNMLEN] = '\0'; + *name = p; + } + else + /* Point to the unswapped name as that persists as long as the + objfile does. */ + *name = ((struct external_syment *)*raw)->e.e_name; + } + else if (symbol->n_sclass & 0x80) + { + *name = ((struct coff_symfile_info *)objfile->sym_private)->debugsec + + symbol->n_offset; + } + else + { + *name = ((struct coff_symfile_info *)objfile->sym_private)->strtbl + + symbol->n_offset; + } + ++*symnump; + *raw += coff_data (objfile->obfd)->local_symesz; + if (symbol->n_numaux > 0) + { + bfd_coff_swap_aux_in (objfile->obfd, *raw, symbol->n_type, + symbol->n_sclass, 0, symbol->n_numaux, aux); + + *symnump += symbol->n_numaux; + *raw += coff_data (objfile->obfd)->local_symesz * symbol->n_numaux; + } +} + +static void +scan_xcoff_symtab (section_offsets, objfile) + struct section_offsets *section_offsets; + struct objfile *objfile; +{ + int toc_offset = 0; /* toc offset value in data section. */ + char *filestring = NULL; + + char *namestring; + int past_first_source_file = 0; + bfd *abfd; + unsigned int nsyms; + + /* Current partial symtab */ + struct partial_symtab *pst; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + + char *sraw_symbol; + struct internal_syment symbol; + union internal_auxent main_aux; + unsigned int ssymnum; + + char *last_csect_name = NULL; /* last seen csect's name and value */ + CORE_ADDR last_csect_val = 0; + int last_csect_sec = 0; + int misc_func_recorded = 0; /* true if any misc. function */ + + pst = (struct partial_symtab *) 0; + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + last_source_file = NULL; + + abfd = objfile->obfd; + + sraw_symbol = ((struct coff_symfile_info *)objfile->sym_private)->symtbl; + nsyms = ((struct coff_symfile_info *)objfile->sym_private)->symtbl_num_syms; + ssymnum = 0; + while (ssymnum < nsyms) + { + int sclass = ((struct external_syment *)sraw_symbol)->e_sclass[0] & 0xff; + /* This is the type we pass to partial-stab.h. A less kludgy solution + would be to break out partial-stab.h into its various parts--shuffle + off the DBXREAD_ONLY stuff to dbxread.c, and make separate + pstab-norm.h (for most types), pstab-sol.h (for N_SOL), etc. */ + int stype; + + QUIT; + + switch (sclass) + { + case C_EXT: + case C_HIDEXT: + { + /* The CSECT auxent--always the last auxent. */ + union internal_auxent csect_aux; + unsigned int symnum_before = ssymnum; + + swap_sym (&symbol, &main_aux, &namestring, &sraw_symbol, + &ssymnum, objfile); + if (symbol.n_numaux > 1) + { + bfd_coff_swap_aux_in + (objfile->obfd, + sraw_symbol - coff_data(abfd)->local_symesz, + symbol.n_type, + symbol.n_sclass, + symbol.n_numaux - 1, + symbol.n_numaux, + &csect_aux); + } + else + csect_aux = main_aux; + + /* If symbol name starts with ".$" or "$", ignore it. */ + if (namestring[0] == '$' + || (namestring[0] == '.' && namestring[1] == '$')) + break; + + switch (csect_aux.x_csect.x_smtyp & 0x7) + { + case XTY_SD: + switch (csect_aux.x_csect.x_smclas) + { + case XMC_PR: + if (last_csect_name) + { + /* If no misc. function recorded in the last + seen csect, enter it as a function. This + will take care of functions like strcmp() + compiled by xlc. */ + + if (!misc_func_recorded) + { + RECORD_MINIMAL_SYMBOL + (last_csect_name, last_csect_val, + mst_text, last_csect_sec, + objfile); + } + + if (pst != NULL) + { + /* We have to allocate one psymtab for + each program csect, because their text + sections need not be adjacent. */ + xcoff_end_psymtab + (pst, psymtab_include_list, + includes_used, + symnum_before, + dependency_list, dependencies_used); + includes_used = 0; + dependencies_used = 0; + /* Give all psymtabs for this source file the same + name. */ + pst = xcoff_start_psymtab + (objfile, section_offsets, + filestring, + symnum_before, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + } + } + if (namestring && namestring[0] == '.') + { + last_csect_name = namestring; + last_csect_val = symbol.n_value; + last_csect_sec = + secnum_to_section (symbol.n_scnum, objfile); + } + if (pst != NULL) + { + CORE_ADDR highval = + symbol.n_value + csect_aux.x_csect.x_scnlen.l; + if (highval > pst->texthigh) + pst->texthigh = highval; + if (pst->textlow == 0 || symbol.n_value < pst->textlow) + pst->textlow = symbol.n_value; + } + misc_func_recorded = 0; + break; + + case XMC_RW: + /* Data variables are recorded in the minimal symbol + table, except for section symbols. */ + if (*namestring != '.') + prim_record_minimal_symbol_and_info + (namestring, symbol.n_value, + sclass == C_HIDEXT ? mst_file_data : mst_data, + NULL, secnum_to_section (symbol.n_scnum, objfile), + objfile); + break; + + case XMC_TC0: + if (toc_offset) + warning ("More than one XMC_TC0 symbol found."); + toc_offset = symbol.n_value; + break; + + case XMC_TC: + /* These symbols tell us where the TOC entry for a + variable is, not the variable itself. */ + break; + + default: + break; + } + break; + + case XTY_LD: + switch (csect_aux.x_csect.x_smclas) + { + case XMC_PR: + /* A function entry point. */ + + if (first_fun_line_offset == 0 && symbol.n_numaux > 1) + first_fun_line_offset = + main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; + RECORD_MINIMAL_SYMBOL + (namestring, symbol.n_value, + sclass == C_HIDEXT ? mst_file_text : mst_text, + secnum_to_section (symbol.n_scnum, objfile), + objfile); + break; + + case XMC_GL: + /* shared library function trampoline code entry + point. */ + + /* record trampoline code entries as + mst_solib_trampoline symbol. When we lookup mst + symbols, we will choose mst_text over + mst_solib_trampoline. */ + RECORD_MINIMAL_SYMBOL + (namestring, symbol.n_value, + mst_solib_trampoline, + secnum_to_section (symbol.n_scnum, objfile), + objfile); + break; + + case XMC_DS: + /* The symbols often have the same names as + debug symbols for functions, and confuse + lookup_symbol. */ + break; + + default: + + /* xlc puts each variable in a separate csect, + so we get an XTY_SD for each variable. But + gcc puts several variables in a csect, so + that each variable only gets an XTY_LD. We + still need to record them. This will + typically be XMC_RW; I suspect XMC_RO and + XMC_BS might be possible too. */ + if (*namestring != '.') + prim_record_minimal_symbol_and_info + (namestring, symbol.n_value, + sclass == C_HIDEXT ? mst_file_data : mst_data, + NULL, secnum_to_section (symbol.n_scnum, objfile), + objfile); + break; + } + break; + + case XTY_CM: + switch (csect_aux.x_csect.x_smclas) + { + case XMC_RW: + case XMC_BS: + /* Common variables are recorded in the minimal symbol + table, except for section symbols. */ + if (*namestring != '.') + prim_record_minimal_symbol_and_info + (namestring, symbol.n_value, + sclass == C_HIDEXT ? mst_file_bss : mst_bss, + NULL, secnum_to_section (symbol.n_scnum, objfile), + objfile); + break; + } + break; + + default: + break; + } + } + break; + case C_FILE: + { + unsigned int symnum_before; + + symnum_before = ssymnum; + swap_sym (&symbol, &main_aux, &namestring, &sraw_symbol, + &ssymnum, objfile); + + /* See if the last csect needs to be recorded. */ + + if (last_csect_name && !misc_func_recorded) + { + + /* If no misc. function recorded in the last seen csect, enter + it as a function. This will take care of functions like + strcmp() compiled by xlc. */ + + RECORD_MINIMAL_SYMBOL + (last_csect_name, last_csect_val, + mst_text, last_csect_sec, objfile); + } + + if (pst) + { + xcoff_end_psymtab (pst, psymtab_include_list, includes_used, + symnum_before, + dependency_list, dependencies_used); + includes_used = 0; + dependencies_used = 0; + } + first_fun_line_offset = 0; + + /* XCOFF, according to the AIX 3.2 documentation, puts the + filename in cs->c_name. But xlc 1.3.0.2 has decided to + do things the standard COFF way and put it in the auxent. + We use the auxent if the symbol is ".file" and an auxent + exists, otherwise use the symbol itself. */ + if (!strcmp (namestring, ".file") && symbol.n_numaux > 0) + { + filestring = coff_getfilename (&main_aux, objfile); + } + else + filestring = namestring; + + pst = xcoff_start_psymtab (objfile, section_offsets, + filestring, + symnum_before, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + last_csect_name = NULL; + } + break; + + default: + { + static struct complaint msg = + {"Storage class %d not recognized during scan", 0, 0}; + complain (&msg, sclass); + } + /* FALLTHROUGH */ + + /* C_FCN is .bf and .ef symbols. I think it is sufficient + to handle only the C_FUN and C_EXT. */ + case C_FCN: + + case C_BSTAT: + case C_ESTAT: + case C_ARG: + case C_REGPARM: + case C_REG: + case C_TPDEF: + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + case C_LABEL: + case C_NULL: + + /* C_EINCL means we are switching back to the main file. But there + is no reason to care; the only thing we want to know about + includes is the names of all the included (.h) files. */ + case C_EINCL: + + case C_BLOCK: + + /* I don't think C_STAT is used in xcoff; C_HIDEXT appears to be + used instead. */ + case C_STAT: + + /* I don't think the name of the common block (as opposed to the + variables within it) is something which is user visible + currently. */ + case C_BCOMM: + case C_ECOMM: + + case C_PSYM: + case C_RPSYM: + + /* I think we can ignore C_LSYM; types on xcoff seem to use C_DECL + so C_LSYM would appear to be only for locals. */ + case C_LSYM: + + case C_AUTO: + case C_RSYM: + { + /* We probably could save a few instructions by assuming that + C_LSYM, C_PSYM, etc., never have auxents. */ + int naux1 = + ((struct external_syment *)sraw_symbol)->e_numaux[0] + 1; + ssymnum += naux1; + sraw_symbol += sizeof (struct external_syment) * naux1; + } + break; + + case C_BINCL: + stype = N_SOL; + goto pstab; + + case C_FUN: + /* The value of the C_FUN is not the address of the function (it + appears to be the address before linking), but as long as it + is smaller than the actual address, then find_pc_partial_function + will use the minimal symbols instead. I hope. */ + + case C_GSYM: + case C_ECOML: + case C_DECL: + case C_STSYM: + stype = N_LSYM; + pstab:; + swap_sym (&symbol, &main_aux, &namestring, &sraw_symbol, + &ssymnum, objfile); +#define CUR_SYMBOL_TYPE stype +#define CUR_SYMBOL_VALUE symbol.n_value + +/* START_PSYMTAB and END_PSYMTAB are never used, because they are only + called from DBXREAD_ONLY or N_SO code. Likewise for the symnum + variable. */ +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms) 0 +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps)\ + do {} while (0) +/* We have already set the namestring. */ +#define SET_NAMESTRING() /* */ + +#include "partial-stab.h" + } + } + + if (pst) + { + xcoff_end_psymtab (pst, psymtab_include_list, includes_used, + ssymnum, + dependency_list, dependencies_used); + } + + /* Record the toc offset value of this symbol table into ldinfo structure. + If no XMC_TC0 is found, toc_offset should be zero. Another place to obtain + this information would be file auxiliary header. */ + +#ifndef FAKING_RS6000 + xcoff_add_toc_to_loadinfo (toc_offset); +#endif +} + +/* Scan and build partial symbols for a symbol file. + We have been initialized by a call to dbx_symfile_init, which + put all the relevant info into a "struct dbx_symfile_info", + hung off the objfile structure. + + SECTION_OFFSETS contains offsets relative to which the symbols in the + various sections are (depending where the sections were actually loaded). + MAINLINE is true if we are reading the main symbol + table (as opposed to a shared lib or dynamically loaded file). */ + +static void +xcoff_initial_scan (objfile, section_offsets, mainline) + struct objfile *objfile; + struct section_offsets *section_offsets; + int mainline; /* FIXME comments above */ +{ + bfd *abfd; + int val; + struct cleanup *back_to; + int num_symbols; /* # of symbols */ + file_ptr symtab_offset; /* symbol table and */ + file_ptr stringtab_offset; /* string table file offsets */ + struct coff_symfile_info *info; + char *name; + unsigned int size; + +#ifndef FAKING_RS6000 + /* Initialize load info structure. */ + if (mainline) + xcoff_init_loadinfo (); +#endif + + info = (struct coff_symfile_info *) objfile -> sym_private; + symfile_bfd = abfd = objfile->obfd; + name = objfile->name; + + num_symbols = bfd_get_symcount (abfd); /* # of symbols */ + symtab_offset = obj_sym_filepos (abfd); /* symbol table file offset */ + stringtab_offset = symtab_offset + + num_symbols * coff_data(abfd)->local_symesz; + + info->min_lineno_offset = 0; + info->max_lineno_offset = 0; + bfd_map_over_sections (abfd, find_linenos, info); + + if (num_symbols > 0) + { + /* Read the string table. */ + init_stringtab (abfd, stringtab_offset, objfile); + + /* Read the .debug section, if present. */ + { + sec_ptr secp; + bfd_size_type length; + char *debugsec = NULL; + + secp = bfd_get_section_by_name (abfd, ".debug"); + if (secp) + { + length = bfd_section_size (abfd, secp); + if (length) + { + debugsec = + (char *) obstack_alloc (&objfile->symbol_obstack, length); + + if (!bfd_get_section_contents (abfd, secp, debugsec, + (file_ptr) 0, length)) + { + error ("Error reading .debug section of `%s': %s", + name, bfd_errmsg (bfd_get_error ())); + } + } + } + ((struct coff_symfile_info *)objfile->sym_private)->debugsec = + debugsec; + } + } + + /* Read the symbols. We keep them in core because we will want to + access them randomly in read_symbol*. */ + val = bfd_seek (abfd, symtab_offset, SEEK_SET); + if (val < 0) + error ("Error reading symbols from %s: %s", + name, bfd_errmsg (bfd_get_error ())); + size = coff_data (abfd)->local_symesz * num_symbols; + ((struct coff_symfile_info *)objfile->sym_private)->symtbl = + obstack_alloc (&objfile->symbol_obstack, size); + ((struct coff_symfile_info *)objfile->sym_private)->symtbl_num_syms = + num_symbols; + + val = bfd_read (((struct coff_symfile_info *)objfile->sym_private)->symtbl, + size, 1, abfd); + if (val != size) + perror_with_name ("reading symbol table"); + + /* If we are reinitializing, or if we have never loaded syms yet, init */ + if (mainline + || objfile->global_psymbols.size == 0 + || objfile->static_psymbols.size == 0) + /* I'm not sure how how good num_symbols is; the rule of thumb in + init_psymbol_list was developed for a.out. On the one hand, + num_symbols includes auxents. On the other hand, it doesn't + include N_SLINE. */ + init_psymbol_list (objfile, num_symbols); + + pending_blocks = 0; + back_to = make_cleanup (really_free_pendings, 0); + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. */ + + scan_xcoff_symtab (section_offsets, objfile); + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); + + do_cleanups (back_to); +} + +static struct section_offsets * +xcoff_symfile_offsets (objfile, addr) + struct objfile *objfile; + CORE_ADDR addr; +{ + struct section_offsets *section_offsets; + int i; + + objfile->num_sections = SECT_OFF_MAX; + section_offsets = (struct section_offsets *) + obstack_alloc + (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * objfile->num_sections); + + /* syms_from_objfile kindly subtracts from addr the bfd_section_vma + of the .text section. This strikes me as wrong--whether the + offset to be applied to symbol reading is relative to the start + address of the section depends on the symbol format. In any + event, this whole "addr" concept is pretty broken (it doesn't + handle any section but .text sensibly), so just ignore the addr + parameter and use 0. rs6000-nat.c will set the correct section + offsets via objfile_relocate. */ + for (i = 0; i < objfile->num_sections; ++i) + ANOFFSET (section_offsets, i) = 0; + + return section_offsets; +} + +/* Register our ability to parse symbols for xcoff BFD files. */ + +static struct sym_fns xcoff_sym_fns = +{ + + /* Because the bfd uses coff_flavour, we need to specially kludge + the flavour. It is possible that coff and xcoff should be merged as + they do have fundamental similarities (for example, the extra storage + classes used for stabs could presumably be recognized in any COFF file). + However, in addition to obvious things like all the csect hair, there are + some subtler differences between xcoffread.c and coffread.c, notably + the fact that coffread.c has no need to read in all the symbols, but + xcoffread.c reads all the symbols and does in fact randomly access them + (in C_BSTAT and line number processing). */ + + (enum bfd_flavour)-1, + + xcoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ + xcoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + xcoff_initial_scan, /* sym_read: read a symbol file into symtab */ + xcoff_symfile_finish, /* sym_finish: finished with file, cleanup */ + xcoff_symfile_offsets, /* sym_offsets: xlate offsets ext->int form */ + NULL /* next: pointer to next struct sym_fns */ +}; + +void +_initialize_xcoffread () +{ + add_symtab_fns(&xcoff_sym_fns); + + func_symbol_type = init_type (TYPE_CODE_FUNC, 1, 0, + "", NULL); + TYPE_TARGET_TYPE (func_symbol_type) = builtin_type_int; + var_symbol_type = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0, + "", NULL); +} diff --git a/contrib/gdb/gdb/xcoffsolib.c b/contrib/gdb/gdb/xcoffsolib.c new file mode 100644 index 000000000000..edcfda11a4d3 --- /dev/null +++ b/contrib/gdb/gdb/xcoffsolib.c @@ -0,0 +1,211 @@ +/* Shared library support for RS/6000 (xcoff) object files, for GDB. + Copyright 1991, 1992 Free Software Foundation. + Contributed by IBM 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if 0 +#include +#include +#endif + +#include "defs.h" +#include "bfd.h" +#include "xcoffsolib.h" +#include "inferior.h" + +#ifdef SOLIB_SYMBOLS_MANUAL + +extern struct symtab *current_source_symtab; +extern int current_source_line; + +/* The real work of adding a shared library file to the symtab and + the section list. */ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + char *val; + struct vmap *vp = vmap; + struct objfile *obj; + struct symtab *saved_symtab; + int saved_line; + + int loaded = 0; /* true if any shared obj loaded */ + int matched = 0; /* true if any shared obj matched */ + + if (arg_string == 0) + re_comp ("."); + else if (val = (char *) re_comp (arg_string)) { + error ("Invalid regexp: %s", val); + } + if (!vp || !vp->nxt) + return; + + /* save current symbol table and line number, in case they get changed + in symbol loading process. */ + + saved_symtab = current_source_symtab; + saved_line = current_source_line; + + /* skip over the first vmap, it is the main program, always loaded. */ + vp = vp->nxt; + + for (; vp; vp = vp->nxt) { + + if (re_exec (vp->name) || (*vp->member && re_exec (vp->member))) { + + matched = 1; + + /* if already loaded, continue with the next one. */ + if (vp->loaded) { + + printf_unfiltered ("%s%s%s%s: already loaded.\n", + *vp->member ? "(" : "", + vp->member, + *vp->member ? ") " : "", + vp->name); + continue; + } + + printf_unfiltered ("Loading %s%s%s%s...", + *vp->member ? "(" : "", + vp->member, + *vp->member ? ") " : "", + vp->name); + gdb_flush (gdb_stdout); + + /* This is gross and doesn't work. If this code is re-enabled, + just stick a objfile member into the struct vmap; that's the + way solib.c (for SunOS/SVR4) does it. */ + obj = lookup_objfile_bfd (vp->bfd); + if (!obj) { + warning ("\nObj structure for the shared object not found. Loading failed."); + continue; + } + + syms_from_objfile (obj, 0, 0, 0); + new_symfile_objfile (obj, 0, 0); + vmap_symtab (vp, 0, 0); + printf_unfiltered ("Done.\n"); + loaded = vp->loaded = 1; + } + } + /* if any shared object is loaded, then misc_func_vector needs sorting. */ + if (loaded) { +#if 0 + sort_misc_function_vector (); +#endif + current_source_symtab = saved_symtab; + current_source_line = saved_line; + + /* Getting new symbols might change our opinion about what is frameless. + Is this correct?? FIXME. */ +/* reinit_frame_cache(); */ + } + else if (!matched) + printf_unfiltered ("No matching shared object found.\n"); +} +#endif /* SOLIB_SYMBOLS_MANUAL */ + +/* Return the module name of a given text address. Note that returned buffer + is not persistent. */ + +char * +pc_load_segment_name (addr) +CORE_ADDR addr; +{ + static char buffer [BUFSIZ]; + struct vmap *vp = vmap; + + buffer [0] = buffer [1] = '\0'; + for (; vp; vp = vp->nxt) + if (vp->tstart <= addr && addr < vp->tend) { + if (*vp->member) { + buffer [0] = '('; + strcat (&buffer[1], vp->member); + strcat (buffer, ")"); + } + strcat (buffer, vp->name); + return buffer; + } + return "(unknown load module)"; +} + +static void solib_info PARAMS ((char *, int)); + +static void +solib_info (args, from_tty) + char *args; + int from_tty; +{ + struct vmap *vp = vmap; + + /* Check for new shared libraries loaded with load (). */ + xcoff_relocate_symtab (inferior_pid); + + if (vp == NULL || vp->nxt == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + return; + } + + /* Skip over the first vmap, it is the main program, always loaded. */ + vp = vp->nxt; + + printf_unfiltered ("\ +Text Range Data Range Syms Shared Object Library\n"); + + for (; vp != NULL; vp = vp->nxt) + { + printf_unfiltered ("0x%08x-0x%08x 0x%08x-0x%08x %s %s%s%s%s\n", + vp->tstart, vp->tend, + vp->dstart, vp->dend, + vp->loaded ? "Yes" : "No ", + *vp->member ? "(" : "", + vp->member, + *vp->member ? ") " : "", + vp->name); + } +} + +void +sharedlibrary_command (args, from_tty) + char *args; + int from_tty; +{ + dont_repeat (); + + /* Check for new shared libraries loaded with load (). */ + xcoff_relocate_symtab (inferior_pid); + +#ifdef SOLIB_SYMBOLS_MANUAL + solib_add (args, from_tty, (struct target_ops *)0); +#endif /* SOLIB_SYMBOLS_MANUAL */ +} + +void +_initialize_solib() +{ + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", solib_info, + "Status of loaded shared object libraries"); +} diff --git a/contrib/gdb/gdb/xcoffsolib.h b/contrib/gdb/gdb/xcoffsolib.h new file mode 100644 index 000000000000..9d10b2e5d2d9 --- /dev/null +++ b/contrib/gdb/gdb/xcoffsolib.h @@ -0,0 +1,56 @@ +/* Data structures for RS/6000 shared libraries, for GDB. + Copyright 1991, 1992, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The vmap struct is used to describe the virtual address space of + the target we are manipulating. The first entry is always the "exec" + file. Subsequent entries correspond to other objects that are + mapped into the address space of a process created from the "exec" file. + These are either in response to exec()ing the file, in which case all + shared libraries are loaded, or a "load" system call, followed by the + user's issuance of a "load" command. */ + +struct vmap { + struct vmap *nxt; /* ptr to next in chain */ + bfd *bfd; /* BFD for mappable object library */ + char *name; /* ptr to object file name */ + char *member; /* ptr to member name */ + CORE_ADDR tstart; /* virtual addr where member is mapped */ + CORE_ADDR tend; /* virtual upper bound of member */ + CORE_ADDR tadj; /* heuristically derived adjustment */ + CORE_ADDR dstart; /* virtual address of data start */ + CORE_ADDR dend; /* vitrual address of data end */ + + /* This is NULL for the exec-file. */ + struct objfile *objfile; + + unsigned loaded:1; /* True if symbols are loaded */ + unsigned padding:15; +}; + + +struct vmap_and_bfd { + bfd *pbfd; + struct vmap *pvmap; +}; + +extern struct vmap *vmap; + +void +add_text_to_loadinfo PARAMS ((CORE_ADDR textaddr, CORE_ADDR dataaddr)); + diff --git a/contrib/gdb/gdb/xmodem.c b/contrib/gdb/gdb/xmodem.c new file mode 100644 index 000000000000..dd13b873c149 --- /dev/null +++ b/contrib/gdb/gdb/xmodem.c @@ -0,0 +1,284 @@ +/* XMODEM support for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "serial.h" +#include "target.h" +#include "xmodem.h" + +/* These definitions are for xmodem protocol. */ + +#define SOH 0x01 +#define STX 0x02 +#define ACK 0x06 +#define NAK 0x15 +#define EOT 0x04 +#define CANCEL 0x18 + +static int blknum; /* XMODEM block number */ +static int crcflag; /* Sez we are using CRC's instead of cksums */ + +static int +readchar (desc, timeout) + serial_t desc; + int timeout; +{ + int c; + + c = SERIAL_READCHAR (desc, timeout); + + if (remote_debug > 0) + fputc_unfiltered (c, gdb_stderr); + + if (c >= 0) + return c; + + if (c == SERIAL_TIMEOUT) + error ("Timeout reading from remote system."); + + perror_with_name ("xmodem.c:readchar()"); +} + +#define CRC16 0x1021 /* Generator polynomial (X^16 + X^12 + X^5 + 1) */ + +static unsigned short *crctab; + +/* Call this to init the fast CRC-16 calculation table. */ + +static void +crcinit () +{ + static int crctab_inited = 0; + int val; + + if (crctab_inited == 1) + return; + + crctab = xmalloc (256 * sizeof (short)); + + for (val = 0; val <= 255; val++) + { + int i; + unsigned int crc; + + crc = val << 8; + + for (i = 0; i < 8; ++i) + { + crc <<= 1; + + if (crc & 0x10000) + crc ^= CRC16; + } + + crctab [val] = crc; + } + + crctab_inited = 1; +} + +/* Calculate a CRC-16 for the LEN byte message pointed at by P. */ + +static unsigned short +docrc (p, len) + unsigned char *p; + int len; +{ + unsigned short crc = 0; + + while (len-- > 0) + crc = (crc << 8) ^ crctab [(crc >> 8) ^ *p++]; + + return crc; +} + +/* Start up the transmit process. Reset state variables. Wait for receiver to + send NAK or CRC request. */ + +int +xmodem_init_xfer (desc) + serial_t desc; +{ + int c; + int i; + + blknum = 1; + crcflag = 0; + crcinit (); + + for (i = 1; i <= 10; i++) + { + c = readchar (desc, 6); + + switch (c) + { + case 'C': + crcflag = 1; + case NAK: + return 0; + default: + fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c); + continue; + case CANCEL: /* target aborted load */ + fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n"); + continue; + } + } + error ("xmodem_init_xfer: Too many unexpected characters."); +} + +/* Take 128 bytes of data and make a packet out of it. + * + * Each packet looks like this: + * +-----+-------+-------+------+-----+ + * | SOH | Seq1. | Seq2. | data | SUM | + * +-----+-------+-------+------+-----+ + * SOH = 0x01 + * Seq1 = The sequence number. + * Seq2 = The complement of the sequence number. + * Data = A 128 bytes of data. + * SUM = Add the contents of the 128 bytes and use the low-order + * 8 bits of the result. + * + * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the + * remote system. PACKET must be XMODEM_PACKETSIZE bytes long. The data must + * start 3 bytes after the beginning of the packet to leave room for the + * XMODEM header. LEN is the length of the data portion of the packet (and + * must be <= 128 bytes). If it is < 128 bytes, ^Z padding will be added. + */ + +void +xmodem_send_packet (desc, packet, len, hashmark) + serial_t desc; + unsigned char *packet; + int len; + int hashmark; +{ + int i; + int retries; + int pktlen; + int datasize; + + /* build the packet header */ + + packet[1] = blknum; + packet[2] = ~blknum; + + blknum++; + + if (len <= XMODEM_DATASIZE) + { + packet[0] = SOH; + datasize = XMODEM_DATASIZE; + } + else if (len <= XMODEM_1KDATASIZE) + { + packet[0] = STX; + datasize = XMODEM_1KDATASIZE; + } + else + abort (); /* Packet way too large */ + + /* Add ^Z padding if packet < 128 (or 1024) bytes */ + + memset (packet + 3 + len, '\026', datasize - len); + + if (crcflag) + { + int crc; + + crc = docrc (packet + 3, datasize); + + packet[3 + datasize] = crc >> 8; + packet[3 + datasize + 1] = crc; + pktlen = datasize + 5; + } + else + { + int sum; + + sum = 0; + for (i = 3; i < datasize + 3; i++) + sum += packet[i]; + + packet[3 + datasize] = sum; /* add the checksum */ + pktlen = datasize + 4; + } + + for (retries = 3; retries >= 0; retries--) + { + int c; + + SERIAL_WRITE (desc, packet, pktlen); + + c = readchar (desc, 3); + switch (c) + { + case ACK: + return; + case NAK: + if (!hashmark) + continue; + putchar_unfiltered ('-'); + gdb_flush (gdb_stdout); + continue; + case CANCEL: + error ("xmodem_send_packet: Transfer aborted by receiver."); + default: + fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); + continue; + } + } + + SERIAL_WRITE (desc, "\004", 1); /* Send an EOT */ + + error ("xmodem_send_packet: Excessive retries."); +} + +/* Finish off the transfer. Send out the EOT, and wait for an ACK. */ + +void +xmodem_finish_xfer (desc) + serial_t desc; +{ + int retries; + + for (retries = 10; retries >= 0; retries--) + { + int c; + + SERIAL_WRITE (desc, "\004", 1); /* Send an EOT */ + + c = readchar (desc, 3); + switch (c) + { + case ACK: + return; + case NAK: + continue; + case CANCEL: + error ("xmodem_finish_xfer: Transfer aborted by receiver."); + default: + fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); + continue; + } + } + + error ("xmodem_finish_xfer: Excessive retries."); +} diff --git a/contrib/gdb/gdb/xmodem.h b/contrib/gdb/gdb/xmodem.h new file mode 100644 index 000000000000..03036120fc6c --- /dev/null +++ b/contrib/gdb/gdb/xmodem.h @@ -0,0 +1,29 @@ +/* XMODEM support for GDB, the GNU debugger. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +int xmodem_init_xfer PARAMS ((serial_t desc)); +void send_xmodem_packet PARAMS ((serial_t desc, unsigned char *packet, int len, + int hashmark)); +void xmodem_finish_xfer PARAMS ((serial_t desc)); + +#define XMODEM_DATASIZE 128 /* The data size is ALWAYS 128 */ +#define XMODEM_1KDATASIZE 1024 /* Unless it's 1024!!! */ +#define XMODEM_PACKETSIZE 133 /* data + packet headers and crc */ +#define XMODEM_1KPACKETSIZE 1024 + 5 /* data + packet headers and crc */ +#define XMODEM_DATAOFFSET 3 /* Offset to start of actual data */ diff --git a/contrib/gdb/include/COPYING b/contrib/gdb/include/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/contrib/gdb/include/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/gdb/include/ChangeLog b/contrib/gdb/include/ChangeLog new file mode 100644 index 000000000000..3594591bb962 --- /dev/null +++ b/contrib/gdb/include/ChangeLog @@ -0,0 +1,973 @@ +Tue Mar 12 17:29:46 1996 Ian Lance Taylor + + * bfdlink.h (bfd_wrapped_link_hash_lookup): Declare. + (struct bfd_link_info): Add wrap_hash field. + +Wed Feb 14 16:49:17 1996 Martin Anantharaman + + * ieee.h (ieee_record_enum_type): Define + ieee_external_reference_info_enum. + +Fri Feb 2 17:09:25 1996 Doug Evans + + * dis-asm.h (DISASM_RAW_INSN): Delete. + +Tue Jan 23 09:21:47 1996 Doug Evans + + * dis-asm.h (INIT_DISASSEMBLE_INFO): Set endian to BFD_ENDIAN_UNKNOWN. + New argument FPRINTF_FUNC. + +Mon Jan 22 16:37:59 1996 Doug Evans + + * dis-asm.h (disassemble_info): New members arch, mach, endian. + (INIT_DISASSEMBLE_INFO): Initialize them. + (DISASM_RAW_INSN{,FLAG}): Define. + +Thu Jan 18 11:32:38 1996 Ian Lance Taylor + + * demangle.h (cplus_demangle_opname): Change opname parameter to + const char *. + (cplus_mangle_opname): Change return type and opname parameter to + const char *. + +Fri Jan 5 00:01:22 1996 Ian Lance Taylor + + * ieee.h (enum ieee_record): Add ieee_asn_record_enum, + ieee_at_record_enum, ieee_ty_record_enum, ieee_atn_record_enum, + ieee_bb_record_enum, and ieee_be_record_enum. + +Wed Jan 3 13:12:09 1996 Fred Fish + + * obstack.h: Update copyright to 1996. + (_obstack_memory_used): Declare. + (obstack_memory_used): Define macro. + +Thu Dec 28 11:42:12 1995 Ian Lance Taylor + + * libiberty.h (xstrdup): Declare. + +Thu Dec 21 14:47:17 1995 Michael Meissner + + * wait.h: Protect all macros with #ifndef. + +Tue Oct 24 21:45:40 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Add static_link field. + +Tue Sep 12 16:28:04 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Add symbol parameter to + warning callback. + +Fri Sep 1 13:11:51 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Change warning callback + to take BFD, section, and address arguments. + +Thu Aug 31 16:45:12 1995 steve chamberlain + + * bfdlink.h (struct bfd_link_info): Remove PE stuff. + +Tue Aug 22 03:18:23 1995 Ken Raeburn + + * libiberty.h: Declare xstrerror. From Pat Rankin. + +Mon Aug 21 18:11:36 1995 steve chamberlain + + * bfdlink.h (struct bfd_link_info): Remove PE stuff. + +Wed Aug 2 08:14:12 1995 Doug Evans + + * dis-asm.h (print_insn_sparc64): Declare. + +Mon Jul 10 13:26:49 1995 Eric Youngdale + + * bfdlink.h (struct bfd_link_info): Add new field symbolic. + +Sun Jul 2 17:48:40 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_info): Change type of base_file to + PTR. + +Thu Jun 29 00:02:45 1995 Steve Chamberlain + + * bfdlink.h (struct bfd_link_info): Added base_file member. + +Tue Jun 20 16:40:04 1995 Steve Chamberlain + + * ansidecl.h: win32s is ANSI enough. + +Thu May 18 04:25:50 1995 Ken Raeburn + + Wed May 10 14:28:16 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * dis-asm.h (print_insn_arm): Delete declaration. + (print_insn_{little,big}_arm): New declarations. + + * floatformat.h (floatformat_arm_ext): Declare. + +Sat May 13 10:14:08 1995 Steve Chamberlain + + * coff/pe.h: New file. + * bfdlink.h (subsytem, stack_heap_parameters): New. + * coff/i386.h (NT_SECTION_ALIGNMENT, NT_FILE_ALIGNMENT, + NT_DEF_RESERVE, NT_DEF_COMMIT): New. + * coff/internal.h (internal_filehdr): New fields for PE. + (IMAGE_DATA_DIRECTORY): New. + (internal_aouthdr): New fields for PE. + +Thu May 4 14:36:42 1995 Jason Merrill + + * demangle.h: Don't include ansidecl.h if IN_GCC. + + +Tue Feb 21 00:37:28 1995 Jeff Law (law@snake.cs.utah.edu) + + * hp-symtab.h: Don't use bitfield enumerations, the HP C compiler + does not handle them correctly. + + +Thu Feb 9 14:20:27 1995 Ian Lance Taylor + + * libiberty.h (basename): Don't declare parameter type; some + systems have this in their header files. + +Wed Feb 8 17:35:38 1995 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_hash_entry): Change format of common + symbol information, to remove restrictions on maximum size and + alignment power, by using a pointer to a structure instead. + +Mon Feb 6 14:55:32 1995 Ian Lance Taylor + + * bfdlink.h (enum bfd_link_hash_type): Rename bfd_link_hash_weak + to bfd_link_hash_undefweak. Add bfd_link_hash_defweak. + +Mon Jan 16 21:00:23 1995 Stan Shebs + + * dis-asm.h (GDB_INIT_DISASSEMBLE_INFO, etc): Remove all + GDB-specific definitions. + +Sun Jan 15 18:39:35 1995 Steve Chamberlain + + * dis-asm.h (print_insn_w65): Declare. + +Thu Jan 12 17:51:17 1995 Ken Raeburn + + * libiberty.h (hex_p): Fix sense of test. + +Wed Jan 11 22:36:40 1995 Ken Raeburn + + * libiberty.h (_hex_array_size, _hex_bad, _hex_value, hex_init, + hex_p, hex_value): New macros and declarations, for hex.c. + +Fri Jan 6 17:44:14 1995 Ian Lance Taylor + + * dis-asm.h: Make idempotent. + +Wed Dec 14 13:08:43 1994 Stan Shebs + + * progress.h: New file, empty definitions for progress macros. + + +Fri Nov 25 00:14:05 1994 Jeff Law (law@snake.cs.utah.edu) + + * hp-symtab.h: New file describing the debug symbols emitted + by the HP C compilers. + +Fri Nov 11 15:48:37 1994 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_hash_entry): Change u.c.size from 24 + to 26 bits, and change u.c.alignment_power from 8 to 6 bits. 6 + bit in the alignment power is enough for a 64 bit address space. + +Mon Oct 31 13:02:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * demangle.h (cplus_mangle_opname): Declare. + +Tue Oct 25 11:38:02 1994 Ian Lance Taylor + + * bfdlink.h (struct bfd_link_callbacks): Fix comments for + multiple_common field. + +Sun Sep 04 17:58:10 1994 Richard Earnshaw (rwe@pegasus.esprit.ec.org) + + * aout/aout64.h: Only define QMAGIC if it isn't already defined. + + * dis-asm.h: Add support for the ARM. + +Wed Aug 10 12:51:41 1994 Doug Evans (dje@canuck.cygnus.com) + + * libiberty.h (strsignal): Document its existence even if we + can't declare it. + +Tue Aug 2 14:40:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * os9k.h: Remove u_int16, u_int32, and owner_id typedefs and + expand their uses. Those names conflict with Mach headers. + +Fri Jul 22 14:17:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * bfdlink.h (struct bfd_link_hash_entry): Change u.c.size into a + bitfield. Add field u.c.alignment_power. + +Sun Jul 10 00:26:39 1994 Ian Dall (dall@hfrd.dsto.gov.au) + + * dis-asm.h: Add print_insn_ns32k declaration. + +Mon Jun 20 17:13:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * bfdlink.h (bfd_link_hash_table): Make creator a const pointer. + +Sat Jun 18 16:09:32 1994 Stan Shebs (shebs@andros.cygnus.com) + + * demangle.h (cplus_demangle_opname): Declare. + +Thu Jun 16 15:19:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_info): Add new field shared. + +Mon Jun 6 14:39:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_hash_entry): Remove written field: + not needed for all backends. + +Thu Apr 28 19:06:50 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * dis-asm.h (disassembler): Declare. + +Fri Apr 1 00:38:17 1994 Jim Wilson (wilson@mole.gnu.ai.mit.edu) + + * obstack.h: Delete use of IN_GCC to control whether + stddef.h or gstddef.h is included. + +Tue Mar 22 13:06:02 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (enum bfd_link_order_type): Add bfd_data_link_order. + (struct bfd_link_order): Add data field to union. + +Mon Mar 21 18:45:26 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Change bitsize argument + to add_to_set to reloc. Remove bitsize argument from constructor. + Comment that reloc_overflow, reloc_dangerous and unattached_reloc + must handle NULL pointers for reloc location. + (enum bfd_link_order_type): Add bfd_section_reloc_link_order and + bfd_symbol_reloc_link_order. + (struct bfd_link_order): Add reloc field to union. + (struct bfd_link_order_reloc): Define. + +Mon Mar 14 12:27:50 1994 Ian Lance Taylor (ian@cygnus.com) + + * ieee-float.h: Removed; no longer used. + +Tue Mar 1 18:10:49 1994 Kung Hsu (kung@mexican.cygnus.com) + + * os9k.h: os9000 target specific header file, the header of the + object file is used now. + +Sun Feb 27 21:52:26 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * floatformat.h: New file, intended to replace ieee-float.h. + +Sun Feb 20 17:15:42 1994 Ian Lance Taylor (ian@lisa.cygnus.com) + + * ansidecl.h (ANSI_PROTOTYPES): Define if using ANSI prototypes. + +Wed Feb 16 01:07:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * libiberty.h: Don't declare strsignal, to avoid conflicts with + Solaris system header files. + +Sat Feb 12 22:11:32 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * libiberty.h (xexit): Use __volatile__ to avoid losing if + compiling with gcc -traditional. + +Thu Feb 10 14:05:41 1994 Ian Lance Taylor (ian@cygnus.com) + + * libiberty.h: New file. Declares functions provided by + libiberty. + +Tue Feb 8 05:19:52 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + Handle obstack_chunk_alloc returning NULL. This allows + obstacks to be used by libraries, without forcing them + to call exit or longjmp. + * obstack.h (struct obstack): Add alloc_failed flag. + _obstack_begin, _obstack_begin_1): Declare to return int, not void. + (obstack_finish): If alloc_failed, return NULL. + (obstack_base, obstack_next_free, objstack_object_size): + If alloc_failed, return 0. + (obstack_grow, obstack_grow0, obstack_1grow, obstack_ptr_grow, + obstack_int_grow, obstack_blank): If alloc_failed, do nothing that + could corrupt the obstack. + +Mon Jan 24 15:06:05 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Add name, reloc_name and + addend argments to reloc_overflow callback. + +Fri Jan 21 19:13:12 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h (print_insn_big_powerpc, print_insn_little_powerpc, + print_insn_rs6000): Declare. + +Thu Jan 6 14:15:55 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfdlink.h (struct bfd_link_callbacks): Add bitsize argument to + add_to_set field. Add new callback named constructor. + +Thu Dec 30 10:44:06 1993 Ian Lance Taylor (ian@rtl.cygnus.com) + + * bfdlink.h: New file for new BFD linker backend routines. + +Mon Nov 29 10:43:57 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h (enum dis_insn_tyupe): Remove non-ANSI trailing comma. + +Sat Oct 2 20:42:26 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h: Move comment to right place. + +Mon Aug 9 19:03:35 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * obstack.h (obstack_chunkfun, obstack_freefun): Add defns from + previous version. Are these Cygnus local changes? + +Fri Aug 6 17:05:47 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * getopt.h, obstack.h: Update to latest FSF version. + +Mon Aug 2 16:37:14 1993 Stu Grossman (grossman at cygnus.com) + + * coff/i386.h: Add Lynx magic number. + +Mon Aug 2 14:45:29 1993 John Gilmore (gnu@cygnus.com) + + * dis-asm.h: Move enum outside of struct defn to avoid warnings. + +Mon Aug 2 08:49:30 1993 Stu Grossman (grossman at cygnus.com) + + * wait.h (WEXITSTATUS, WSTOPSIG): Mask down to 8 bits. This is + for systems that store stuff into the high 16 bits of a wait + status. + +Fri Jul 30 18:38:02 1993 John Gilmore (gnu@cygnus.com) + + * dis-asm.h: Add new fields insn_info_valid, branch_delay_insns, + data_size, insn_type, target, target2. These are used to return + information from the instruction decoders back to the calling + program. Add comments, make more readable. + +Mon Jul 19 22:14:14 1993 Fred Fish (fnf@deneb.cygnus.com) + + * nlm: New directory containing NLM/NetWare includes. + +Thu Jul 15 12:10:04 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * dis-asm.h (struct disassemble_info): New field application_data. + +Thu Jul 15 12:41:15 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * dis-asm.h: Added declaration of print_insn_m88k. + +Thu Jul 8 09:05:26 1993 Doug Evans (dje@canuck.cygnus.com) + + * opcode/h8300.h: Lots of little fixes for the h8/300h. + +Fri Jul 2 10:31:59 1993 Ian Lance Taylor (ian@cygnus.com) + + * ansidecl.h: Use ANSI macros if __mips and _SYSTYPE_SVR4 are + defined, since RISC/OS cc handles ANSI declarations in SVR4 mode + but does not define __STDC__. + +Sun Jun 20 18:27:52 1993 Ken Raeburn (raeburn@poseidon.cygnus.com) + + * dis-asm.h: Don't need to include ansidecl.h any more. + +Fri Jun 18 03:22:10 1993 John Gilmore (gnu@cygnus.com) + + * oasys.h: Eliminate "int8_type", "int16_type", "int32_type", and + their variants. These changes are coordinated with corresponding + changes in ../bfd/oasys.c. + +Wed Jun 16 10:43:08 1993 Fred Fish (fnf@cygnus.com) + + * bfd.h: Note that it has been removed. + +Tue Jun 8 12:16:03 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + Support for H8/300-H + * dis-asm.h (print_insn_h8300, print_insn_h8300h): Declare it. + * coff/h8300.h: New magic number. + * coff/internal.h: New relocations. + * opcode/h8300.h: Lots of new opcodes. + +Tue Jun 1 07:35:03 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * ansidecl.h (const): Don't define it if it's already defined. + +Thu May 27 18:19:51 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * dis-asm.h (print_insn_hppa): Declare it. + + * bfd.h: Moved to bfd directory. Small stub here includes it + without requiring "-I../bfd". + +Thu Apr 29 12:06:13 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * bfd.h: Updated with BSF_FUNCTION. + +Mon Apr 26 18:15:50 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h, dis-asm.h: Updated with Hitachi SH. + +Fri Apr 23 18:41:38 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: Updated with alpha changes. + * dis-asm.h: Added alpha. + +Fri Apr 16 17:35:30 1993 Jim Kingdon (kingdon@cygnus.com) + + * bfd.h: Update for signed bfd_*get_*. + +Thu Apr 15 09:24:21 1993 Jim Kingdon (kingdon@cygnus.com) + + * bfd.h: Updated for file_truncated error. + +Thu Apr 8 10:53:47 1993 Ian Lance Taylor (ian@cygnus.com) + + * ansidecl.h: If no ANSI, define const to be empty. + +Thu Apr 1 09:00:10 1993 Jim Kingdon (kingdon@cygnus.com) + + * dis-asm.h: Declare a29k and i960 print_insn_*. + + * dis-asm.h: Add print_address_func and related stuff. + + * dis-asm.h (dis_asm_read_memory): Fix prototype. + +Wed Mar 31 17:40:16 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h: Add print_insn_sparc. + +Wed Mar 31 17:51:42 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Updated for BFD_RELOC_MIPS_GPREL and bfd_[gs]et_gp_size + prototypes. + +Wed Mar 31 16:35:12 1993 Stu Grossman (grossman@cygnus.com) + + * dis-asm.h: (disassemble_info): Fix typo in prototype of + dis_asm_memory_error(). + +Tue Mar 30 19:09:23 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-asm.h (disassembler_info): Add read_memory_func, + memory_error_func, buffer, and length. + ({GDB_,}INIT_DISASSEMBLE_INFO): Set them. + print_insn_*: Remove second argument. + +Tue Mar 30 14:48:55 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: Update for lma field of section. + +Tue Mar 30 12:22:55 1993 Jim Kingdon (kingdon@cygnus.com) + + * ansidecl.h: Use ANSI versions on AIX regardless of __STDC__. + +Fri Mar 19 14:49:49 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * dis-asm.h: Add h8500. + +Thu Mar 18 13:49:09 1993 Per Bothner (bothner@rtl.cygnus.com) + + * ieee-float.h: Moved from ../gdb. + * dis-asm.h: New file. Interface to dis-assembler. + +Thu Mar 11 10:52:57 1993 Fred Fish (fnf@cygnus.com) + + * demangle.h (DMGL_NO_OPTS): Add define (set to 0) to use + in place of bare 0, for readability reasons. + +Tue Mar 2 17:50:11 1993 Fred Fish (fnf@cygnus.com) + + * demangle.h: Replace all references to cfront with ARM. + +Tue Feb 23 12:21:14 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update for new elements in JUMP_TABLE. + +Tue Feb 16 00:51:30 1993 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update for BFD_VERSION 2.1. + +Tue Jan 26 11:49:20 1993 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update for SEC_IS_COMMON flag. + +Tue Jan 19 12:25:12 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.h: Update for bfd_asymbol_value bug fix. + +Fri Jan 8 16:37:18 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * bfd.h: Update to include ECOFF tdata and target_flavour. + +Sun Dec 27 17:52:30 1992 Fred Fish (fnf@cygnus.com) + + * bfd.h: Add declaration for bfd_get_size(). + +Tue Dec 22 22:42:46 1992 Fred Fish (fnf@cygnus.com) + + * demangle.h: Protect file from multiple inclusions with + #if !defined(DEMANGLE_H)...#define DEMANGLE_H...#endif. + +Mon Dec 21 21:25:50 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h: Update to get hppa_core_struct from bfd.c. + +Thu Dec 17 00:42:35 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update to get tekhex tdata name change from bfd. + +Mon Nov 9 23:55:42 1992 John Gilmore (gnu@cygnus.com) + + * ansidecl.h: Update comments to discourage use of EXFUN. + +Thu Nov 5 16:35:44 1992 Ian Lance Taylor (ian@cygnus.com) + + * bfd.h: Update to bring in SEC_SHARED_LIBRARY. + +Thu Nov 5 03:21:32 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update to match EXFUN, bfd_seclet_struct, and SDEF + cleanups in bfd. + +Wed Nov 4 07:28:05 1992 Ken Raeburn (raeburn@cygnus.com) + + * bout.h (N_CALLNAME, N_BALNAME): Define as char-type values, so + widening works consistently. + +Fri Oct 16 03:17:08 1992 John Gilmore (gnu@cygnus.com) + + * getopt.h: Update to Revised Standard FSF Version. + +Thu Oct 15 21:43:22 1992 K. Richard Pixley (rich@sendai.cygnus.com) + + * getopt.h (struct option): use the provided enum for has_arg. + + * demangle.h (AUTO_DEMANGLING, GNU_DEMANGLING, + LUCID_DEMANGLING): ultrix compilers require enums to be + enums and ints to be ints and casts where they meet. cast some + enums into ints. + +Thu Oct 15 04:35:51 1992 John Gilmore (gnu@cygnus.com) + + * bfd.h: Update after comment changes. + +Thu Oct 8 09:03:02 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h (bfd_get_symbol_leading_char): new macro for getting in xvec + +Thu Sep 3 09:10:50 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h (struct reloc_howto_struct): size needs to be signed if + it's going to hold negative values. + +Sun Aug 30 17:50:27 1992 Per Bothner (bothner@rtl.cygnus.com) + + * demangle.h: New file, moved from ../gdb. Made independent + of gdb. Allow demangling style option to be passed as a + parameter to cplus_demangle(), but using the + current_demangling_style global as the default. + +Sat Aug 29 10:07:55 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Merge comment change from current FSF version. + +Thu Aug 27 12:59:29 1992 Brendan Kehoe (brendan@cygnus.com) + + * bfd.h: add we32k + +Tue Aug 25 15:07:47 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: new after Z8000 stuff + +Mon Aug 17 09:01:23 1992 Ken Raeburn (raeburn@cygnus.com) + + * bfd.h: Regenerated after page/segment size changes. + +Sat Aug 1 13:46:31 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Merge changes from current FSF version. + +Mon Jul 20 21:06:23 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h (area_id, flags): Remove, replace with extra_arg, + use_extra_arg, and maybe_empty_object. + * obstack.h (OBSTACK_MAYBE_EMPTY_OBJECT, OBSTACK_MMALLOC_LIKE): + Remove, replaced by maybe_empty_object and use_extra_arg bitfields. + * obstack.h (obstack_full_begin, _obstack_begin): Remove area_id + and flags arguments. + * obstack.h (obstack_alloc_arg): New macro to set extra_arg. + +Thu Jul 16 08:12:44 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * bfd.h: new after adding BFD_IS_RELAXABLE + +Sat Jul 4 03:22:23 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Regen after adding BSF_FILE. + +Mon Jun 29 14:18:36 1992 Fred Fish (fnf at sunfish) + + * obstack.h: Convert bcopy() use to memcpy(), which is more + portable, more standard, and can take advantage of gcc's builtin + functions for increased performance. + +Thu Jun 25 04:46:08 1992 John Gilmore (gnu at cygnus.com) + + * ansidecl.h (PARAMS): Incorporate this macro from gdb's defs.h. + It's a cleaner way to forward-declare function prototypes. + +Fri Jun 19 15:46:32 1992 Stu Grossman (grossman at cygnus.com) + + * bfd.h: HPPA merge. + +Tue Jun 16 21:30:56 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: gratuitous white space changes merged from other prep + releases. + +Thu Jun 11 01:10:55 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Regen'd from bfd.c after removing elf_core_tdata_struct. + +Mon May 18 17:29:03 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: merged changes from make-3.62.11. + + * getopt.h: merged changes from grep-1.6 (alpha). + +Fri May 8 14:53:32 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.h: merged changes from bison-1.18. + +Sat Mar 14 17:25:20 1992 Fred Fish (fnf@cygnus.com) + + * obstack.h: Add "area_id" and "flags" members to obstack + structure. Add obstack_chunkfun() and obstack_freefun() to + set functions explicitly. Convert maybe_empty_object to + a bit in "flags". + +Thu Feb 27 22:01:02 1992 Per Bothner (bothner@cygnus.com) + + * wait.h (WIFSTOPPED): Add IBM rs6000-specific version. + +Fri Feb 21 20:49:20 1992 John Gilmore (gnu at cygnus.com) + + * obstack.h: Add obstack_full_begin. + * bfd.h, obstack.h: Protolint. + +Thu Jan 30 01:18:42 1992 John Gilmore (gnu at cygnus.com) + + * bfd.h: Remove comma from enum declaration. + +Mon Jan 27 22:01:13 1992 Steve Chamberlain (sac at cygnus.com) + + * bfd.h : new target entr, bfd_relax_section + +Wed Dec 18 17:19:44 1991 Stu Grossman (grossman at cygnus.com) + + * bfd.h, ieee.h, opcode/m68k.h, opcode/sparc.h: ANSIfy enums. + +Thu Dec 12 20:59:56 1991 John Gilmore (gnu at cygnus.com) + + * fopen-same.h, fopen-bin.h: New files for configuring + whether fopen distinguishes binary files or not. For use + by host-dependent config files. + +Sat Nov 30 20:46:43 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * bfd.h: change the documentation format. + + * created coff, elf and opcode and aout directories. Moved: + + aout64.h ==> aout/aout64.h + ar.h ==> aout/ar.h + a.out.encap.h ==> aout/encap.h + a.out.host.h ==> aout/host.h + a.out.hp.h ==> aout/hp.h + a.out.sun4.h ==> aout/sun4.h + ranlib.h ==> aout/ranlib.h + reloc.h ==> aout/reloc.h + stab.def ==> aout/stab.def + stab.gnu.h ==> aout/stab_gnu.h + + coff-a29k.h ==> coff/a29k.h + coff-h8300.h ==> coff/h8300.h + coff-i386.h ==> coff/i386.h + coff-i960.h ==> coff/i960.h + internalcoff.h ==> coff/internal.h + coff-m68k.h ==> coff/m68k.h + coff-m88k.h ==> coff/m88k.h + coff-mips.h ==> coff/mips.h + coff-rs6000.h ==> coff/rs6000.h + + elf-common.h ==> elf/common.h + dwarf.h ==> elf/dwarf.h + elf-external.h ==> elf/external.h + elf-internal.h ==> elf/internal.h + + a29k-opcode.h ==> opcode/a29k.h + arm-opcode.h ==> opcode/arm.h + h8300-opcode.h ==> opcode/h8300.h + i386-opcode.h ==> opcode/i386.h + i860-opcode.h ==> opcode/i860.h + i960-opcode.h ==> opcode/i960.h + m68k-opcode.h ==> opcode/m68k.h + m88k-opcode.h ==> opcode/m88k.h + mips-opcode.h ==> opcode/mips.h + np1-opcode.h ==> opcode/np1.h + ns32k-opcode.h ==> opcode/ns32k.h + pn-opcode.h ==> opcode/pn.h + pyr-opcode.h ==> opcode/pyr.h + sparc-opcode.h ==> opcode/sparc.h + tahoe-opcode.h ==> opcode/tahoe.h + vax-opcode.h ==> opcode/vax.h + + + +Wed Nov 27 10:38:31 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * internalcoff.h: (internal_scnhdr) took out #def dependency, now + s_nreloc and s_nlnno are always long. (internal_reloc): allways + has an offset field now. + +Fri Nov 22 08:12:58 1991 John Gilmore (gnu at cygnus.com) + + * coff-rs6000.h: Lint; use unsigned chars for external fields. + * internalcoff.h: Lint; cast storage classes to signed char. + +Thu Nov 21 21:01:05 1991 Per Bothner (bothner at cygnus.com) + + * stab.def: Remove the GNU extended type codes (e.g. N_SETT). + * aout64.h: The heuristic for distinguishing between + sunos-style and bsd-style ZMAGIC files (wrt. where the + text segment starts) is moved into (the default definition of) + the macro N_HEADER_IN_TEXT. This definition is only used + if no other definition is used - e.g. bfd/newsos3.c defines + N_HEADER_IN_TEXT(x) to be always 0 (as before). + +Thu Nov 21 11:53:03 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h (N_TXTADDR, N_TXTOFF, N_TXTSIZE): New definitions + that should handle all uses. LOGICAL_ versions deleted. + Eliminate N_HEADER_IN_TEXT, using a_entry to determine which + kind of zmagic a.out file we are looking at. + * coff-rs6000.h: Typo. + +Tue Nov 19 18:43:37 1991 Per Bothner (bothner at cygnus.com) + + (Note: This is a revised entry, as was aout64.h.) + * aout64.h: Some cleanups of N_TXTADDR and N_TXTOFF: + Will now work for both old- and new-style ZMAGIC files, + depending on N_HEADER_IN_TEXT macro. + Add LOGICAL_TXTADDR, LOICAL_TXTOFF and LOGICAL_TXTSIZE + that don't count the exec header as part + of the text segment, to be consistent with bfd. + * a.out.sun4.h: Simplified/fixed for previous change. + +Mon Nov 18 00:02:06 1991 Fred Fish (fnf at cygnus.com) + + * dwarf.h: Update to DWARF draft 5 version from gcc2. + +Thu Nov 14 19:44:59 1991 Per Bothner (bothner at cygnus.com) + + * stab.def: Added defs for extended GNU symbol types, + such as N_SETT. These are normally ifdef'd out (because + of conflicts with a.out.gnu.h), but are used by bfb_stab_name(). + +Thu Nov 14 19:17:03 1991 Fred Fish (fnf at cygnus.com) + + * elf-common.h: Add defines to support ELF symbol table code. + +Mon Nov 11 19:01:06 1991 Fred Fish (fnf at cygnus.com) + + * elf-internal.h, elf-external.h, elf-common.h: Add support for + note sections, which are used in ELF core files to hold copies + of various /proc structures. + +Thu Nov 7 08:58:26 1991 Steve Chamberlain (sac at cygnus.com) + + * internalcoff.h: took out the M88 dependency in the lineno + struct. + * coff-m88k.h: defines GET_LINENO_LNNO and PUT_LINENO_LNNO to use + 32bit linno entries. + * a29k-opcode.h: fixed encoding of mtacc + +Sun Nov 3 11:54:22 1991 Per Bothner (bothner at cygnus.com) + + * bfd.h: Updated from ../bfd/bfd-in.h (q.v). + +Fri Nov 1 11:13:53 1991 John Gilmore (gnu at cygnus.com) + + * internalcoff.h: Add x_csect defines. + +Fri Oct 25 03:18:20 1991 John Gilmore (gnu at cygnus.com) + + * Rename COFF-related files in `coff-ARCH.h' form. + coff-a29k.h, coff-i386.h, coff-i960.h, coff-m68k.h, coff-m88k.h, + coff-mips.h, coff-rs6000.h to be exact. + +Thu Oct 24 22:11:11 1991 John Gilmore (gnu at cygnus.com) + + RS/6000 support, by Metin G. Ozisik, Mimi Phûông-Thåo Võ, and + John Gilmore. + + * a.out.gnu.h: Update slightly. + * bfd.h: Add new error code, fix doc, add bfd_arch_rs6000. + * internalcoff.h: Add more F_ codes for filehdr. Add + rs/6000-dependent fields to aouthdr. Add storage classes + to syments. Add 6000-specific auxent. Add r_size in reloc. + * rs6000coff.c: New file. + +Thu Oct 24 04:13:20 1991 Fred Fish (fnf at cygnus.com) + + * dwarf.h: New file for dwarf support. Copied from gcc2 + distribution. + +Wed Oct 16 13:31:45 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h: Remove PAGE_SIZE defines; they are target-dependent. + Add N_FN_SEQ for N_FN symbol type used on Sequent machines. + * stab.def: Include N_FN_SEQ in table. + * bout.h: External formats of structures use unsigned chars. + +Fri Oct 11 12:40:43 1991 Steve Chamberlain (steve at cygnus.com) + + * bfd.h:upgrade from bfd.c + * internalcoff.h: add n_name, n_zeroes and n_offset macros + * amdcoff.h: Define OMAGIC and AOUTHDRSZ. + +Fri Oct 11 10:58:06 1991 Per Bothner (bothner at cygnus.com) + + * a.out.host.h: Change SEGMENT_SIZE to 0x1000 for Sony. + * bfd.h (align_power): Add (actually move) comment. + +Tue Oct 8 15:29:32 1991 Per Bothner (bothner at cygnus.com) + + * sys/h-rtbsd.h: Define MISSING_VFPRINT (for binutils/bucomm.c). + +Sun Oct 6 19:24:39 1991 John Gilmore (gnu at cygnus.com) + + * aout64.h: Move struct internal_exec to ../bfd/libaout.h so + it can be shared by all `a.out-family' code. Rename + EXTERNAL_LIST_SIZE to EXTERNAL_NLIST_SIZE. Use basic types + for nlist members, and make strx integral rather than pointer. + More commentary on n_type values. + * bout.h: Provide a struct external_exec rather than an + internal_exec. + * m68kcoff.h: Remove `tagentries' which snuck in from the i960 + COFF port. + +Fri Oct 4 01:25:59 1991 John Gilmore (gnu at cygnus.com) + + * h8300-opcode.h: Remove `_enum' from the typedef for an enum. + * bfd.h: Update to match bfd changes. + + * sys/h-i386mach.h, sysdep.h: Add 386 Mach host support. + +Tue Oct 1 04:58:42 1991 John Gilmore (gnu at cygnus.com) + + * bfd.h, elf-common.h, elf-external.h, elf-internal.h: + Add preliminary ELF support, sufficient for GDB, from Fred Fish. + * sysdep.h, sys/h-amix.h: Support Amiga SVR4. + + * sys/h-vaxult.h: Make it work. (David Taylor ) + * a.out.vax.h: Remove unused and confusing file. + +Mon Sep 30 12:52:35 1991 Per Bothner (bothner at cygnus.com) + + * sysdep.h: Define NEWSOS3_SYS, and use it. + +Fri Sep 20 13:38:21 1991 John Gilmore (gnu at cygnus.com) + + * a.out.gnu.h (N_FN): Its value *really is* 0x1F. + Fix it, and add comments warning about or-ing N_EXT with it + and/or N_WARNING. + * aout64.h (N_FN): Fix value, add comments about N_EXT. + * stab.def (table at end): Update to show all the type + values <0x20, including low order bits. Move N_FN to + its rightful place. + +Tue Sep 17 17:41:37 1991 Stu Grossman (grossman at cygnus.com) + + * sys/h-irix3.h: sgi/irix support. + +Tue Sep 17 07:52:59 1991 John Gilmore (gnu at cygint.cygnus.com) + + * stab.def (N_DEFD): Add GNU Modula-2 debug stab, from Andrew + Beers. + +Thu Sep 12 14:12:59 1991 John Gilmore (gnu at cygint.cygnus.com) + + * internalcoff.h (SYMNMLEN, FILNMLEN, DIMNUM): Define these + for internalcoff, separately from the various external coff's. + * amdcoff.h, bcs88kcoff.h, i386coff.h, intel-coff.h, m68kcoff.h, + m88k-bcs.h: Prefix SYMNMLEN, FILNMLEN, and DIMNUM with E_'s for + the external struct definitions. + * ecoff.h: Remove these #define's, kludge no longer needed. + + * sys/h-ultra3.h: Add new Ultracomputer host. + * sysdep.h: Add ULTRA3_SYM1_SYS and use it. + +Tue Sep 10 10:11:46 1991 John Gilmore (gnu at cygint.cygnus.com) + + * i386coff.h (LINESZ): Always 6, not based on sizeof(). + (Fix from Peter Schauer .) + +Wed Sep 4 08:58:37 1991 John Gilmore (gnu at cygint.cygnus.com) + + * a.out.gnu.h, aout64.h: Add N_WARNING. Change N_FN to 0x0E, + to match SunOS and BSD. Add N_COMM as 0x12 for SunOS shared lib + support. + * stab.def: Add N_COMM to table, fix overlap comment. + +Tue Sep 3 06:29:20 1991 John Gilmore (gnu at cygint.cygnus.com) + + Merge with latest FSF versions of these files. + + * stab.gnu.h: Add LAST_UNUSED_STAB_CODE. + * stab.def: Update to GPL2. Move N_WARNING out, since not a + debug symbol. Change comments, and reorder table to numeric + order. Update final table comment. + (N_DSLINE, N_BSLINE): Renumber from 0x66 and 0x68, to 0x46 and 0x48. + + * obstack.h: GPL2. Merge. + +Fri Aug 23 01:54:23 1991 John Gilmore (gnu at cygint.cygnus.com) + + * a.out.gnu.h, a.out.sun4.h: Make SEGMENT_SIZE able to depend + on the particular a.out being examined. + * a.out.sun4.h: Define segment sizes for Sun-3's and Sun-4's. + * FIXME: a.out.gnu.h is almost obsolete. + * FIXME: a.out.sun4.h should be renamed a.out.sun.h now. + +Wed Aug 21 20:32:13 1991 John Gilmore (gnu at cygint.cygnus.com) + + * Start a ChangeLog for the includes directory. + + * a.out.gnu.h (N_FN): Fix value -- was 15, should be 0x1E. + * stab.def: Update allocation table in comments at end, + to reflect reality as I know it. + + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/contrib/gdb/include/ansidecl.h b/contrib/gdb/include/ansidecl.h new file mode 100644 index 000000000000..be04e42d56a3 --- /dev/null +++ b/contrib/gdb/include/ansidecl.h @@ -0,0 +1,141 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992 Free Software Foundation, Inc. + This file is part of the GNU C 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + LONG_DOUBLE `long double' `double' + VOLATILE `volatile' `' + SIGNED `signed' `' + PTRCONST `void *const' `char *' + ANSI_PROTOTYPES 1 not defined + + CONST is also defined, but is obsolete. Just use const. + + DEFUN (name, arglist, args) + + Defines function NAME. + + ARGLIST lists the arguments, separated by commas and enclosed in + parentheses. ARGLIST becomes the argument list in traditional C. + + ARGS list the arguments with their types. It becomes a prototype in + ANSI C, and the type declarations in traditional C. Arguments should + be separated with `AND'. For functions with a variable number of + arguments, the last thing listed should be `DOTS'. + + DEFUN_VOID (name) + + Defines a function NAME, which takes no arguments. + + obsolete -- EXFUN (name, (prototype)) -- obsolete. + + Replaced by PARAMS. Do not use; will disappear someday soon. + Was used in external function declarations. + In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in + parentheses). In traditional C it is `NAME()'. + For a function that takes no arguments, PROTOTYPE should be `(void)'. + + PARAMS ((args)) + + We could use the EXFUN macro to handle prototype declarations, but + the name is misleading and the result is ugly. So we just define a + simple macro to handle the parameter lists, as in: + + static int foo PARAMS ((int, char)); + + This produces: `static int foo();' or `static int foo (int, char);' + + EXFUN would have done it like this: + + static int EXFUN (foo, (int, char)); + + but the function is not external...and it's hard to visually parse + the function name out of the mess. EXFUN should be considered + obsolete; new code should be written to use PARAMS. + + For example: + extern int printf PARAMS ((CONST char *format DOTS)); + int DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) { ... } + void DEFUN_VOID(abort) { ... } +*/ + +#ifndef _ANSIDECL_H + +#define _ANSIDECL_H 1 + + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ + +#define PTR void * +#define PTRCONST void *CONST +#define LONG_DOUBLE long double + +#define AND , +#define NOARGS void +#define CONST const +#define VOLATILE volatile +#define SIGNED signed +#define DOTS , ... + +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) + +#define PROTO(type, name, arglist) type name arglist +#define PARAMS(paramlist) paramlist +#define ANSI_PROTOTYPES 1 + +#else /* Not ANSI C. */ + +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define AND ; +#define NOARGS +#define CONST +#ifndef const /* some systems define it in header files for non-ansi mode */ +#define const +#endif +#define VOLATILE +#define SIGNED +#define DOTS + +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#define PROTO(type, name, arglist) type name () +#define PARAMS(paramlist) () + +#endif /* ANSI C. */ + +#endif /* ansidecl.h */ diff --git a/contrib/gdb/include/aout/ChangeLog b/contrib/gdb/include/aout/ChangeLog new file mode 100644 index 000000000000..307448bc87fd --- /dev/null +++ b/contrib/gdb/include/aout/ChangeLog @@ -0,0 +1,174 @@ +Mon Mar 11 12:15:52 1996 Ian Lance Taylor + + * stab.def: Use __define_stab_duplicate rather than __define_stab + for duplicate entries N_BROWS and N_MOD2. + * stab_gnu.h (__define_stab_duplicate): Define before including + stab.def. + +Fri Oct 27 17:47:16 1995 Niklas Hallqvist + + * aout64.h, host.h, hp300hpux.h, sun4.h: Changed PAGE_SIZE to + TARGET_PAGE_SIZE. + +Tue Sep 12 12:07:02 1995 Ian Lance Taylor + + * sun4.h (struct internal_sun4_dynamic_link): Change all fields + from long to unsigned long. + +Wed Jul 12 00:15:13 1995 Ken Raeburn + + * sun4.h (PAGE_SIZE): Undefine before defining. + +Thu Jun 16 14:22:55 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * aout64.h (BMAGIC): Define. + +Sat Jun 11 16:16:09 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + Add weak symbols as an extension to a.out. + * aout64.h (N_WEAKU, N_WEAKA, N_WEAKT, N_WEAKD, N_WEAKB): Define. + * stab.def: Update symbol value table. + +Thu Jun 2 17:13:38 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * sun4.h (EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE): Correct from 28 to + 24. Fix up ld_got comment. + +Wed Mar 30 00:31:49 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dynix3.h: Cleanup, adapt to current bfd version. + +Sat Feb 26 10:25:53 1994 Ian Lance Taylor (ian@cygnus.com) + + * aout64.h: Add casts to avoid warnings from SVR4 cc. + +Fri Feb 11 12:56:04 1994 Stan Shebs (shebs@andros.cygnus.com) + + * ar.h (ARMAG, ARMAGB, ARFMAG): Change '\n' to '\012', for greater + portability. + +Fri Jan 21 00:59:06 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * sun4.h: Added information about SunOS shared libraries. + +Fri Jan 7 08:20:13 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * aout64.h (N_TXTADDR): Add comment regarding OMAGIC and NMAGIC. + +Sat Dec 25 14:55:41 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * aout64.h (N_DATOFF): Don't pad (revert change of 8 Jul 1993). + +Tue Nov 16 15:43:46 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * aout64.h: New macros ZMAGIC_DISK_BLOCK_SIZE and N_DISK_BLOCK_SIZE + for Linux ZMAGIC. + (N_TXTOFF, N_DATOFF): Use them. + +Thu Nov 4 00:33:48 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * aout64.h (RELOC_STD_BITS_RELATIVE_LITTLE): Fixed value to match + sun3 system; used to overlap other fields. + (RELOC_STD_BITS_JMPTABLE_LITTLE): Likewise. + +Wed Nov 3 13:48:27 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * aout64.h (RELOC_STD_BITS_BASEREL_LITTLE): Make it 0x10 (Ken's + suggestion) to avoid conflict with RELOC_STD_BITS_EXTERN_LITTLE. + +Fri Oct 29 15:09:52 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * hp300hpux.h (N_SHARED_LIB): Define to be 0. + +Mon Sep 13 21:00:56 1993 John Gilmore (gnu@cygnus.com) + + * ar.h (ARMAP_TIME_OFFSET): Add and describe. + +Mon Aug 23 Sean Fagan (sef@cygnus.com) + + * aout64.h [ARCH_SIZE != 64]: Allow N_BADMAG to be overridden. + +Mon Aug 16 14:30:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stab_gnu.h: Include aout/stab.def not just stab.def. + +Sun Jul 18 21:41:47 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * dynix3.h: New, for symmetry running dynix. + +Thu Jul 8 12:52:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * aout64.h (N_BADMAG): Recognize QMAGIC. + N_TXTOFF, N_TXTADDR, N_TXTSIZE: Special code for QMAGIC. + N_DATOFF: Pad text size if we need to. + +Fri Jun 18 19:19:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * stab.def (N_ECOML): Fix comment. + +Mon May 31 09:21:30 1993 Jim Kingdon (kingdon@cygnus.com) + + * stab.def: Remove Solaris information on N_FUN stabstring grammar; + I've transferred it to gdb/doc/stabs.texinfo, where it belongs. + +Mon May 10 05:48:43 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * hp300hpux.h: Patch from Glenn Engel for linker problem and + compatibility fix: + (OMAGIC, NMAGIC): New definitions. + (SHAREMAGIC): Deleted. + (HPUX_DOT_O_MAGIC): New macro. + (_N_BADMAG): Adjusted. + (N_HEADER_IN_TEXT, N_DATADDR): New macros. + +Thu Apr 29 12:07:37 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * hp300hpux.h: New file from Glenn Engel, glenne@lsid.hp.com. + +Tue Apr 27 05:51:04 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * aout64.h (struct external_exec, *MAGIC, N_BADMAG): Don't define + if `external_exec' is already defined as a macro. + (N_DATOFF, N_TRELOFF, N_DRELOFF, N_SYMOFF, N_STROFF): Don't define + if already defined. + (struct external_nlist, EXTERNAL_NLIST_SIZE): Don't define if + `external_nlist' is already defined as a macro. + +Sat Aug 15 04:23:02 1992 John Gilmore (gnu@cygnus.com) + + * adobe.h: Add description of a.out.adobe format. + +Fri Jul 3 00:36:52 1992 John Gilmore (gnu at cygnus.com) + + * stab.def: Update more Solaris definitions. + * stab_gnu.h: Add N_SO language types, and Solaris basic float types. + +Sun Jun 14 10:53:53 1992 John Gilmore (gnu at cygnus.com) + + * stab.def: Update descriptions of Solaris-2 stabs; add N_UNDF. + +Thu Jun 11 01:12:07 1992 John Gilmore (gnu at cygnus.com) + + * stab.def: Add N_OBJ and N_OPT from Solaris-2. + +Thu Jan 30 18:12:44 1992 John Gilmore (gnu at cygnus.com) + + * aout/aout64.h: N_TXTSIZE needs some more parentheses. + I don't trust C precedence. + +Wed Dec 18 14:32:01 1991 Per Bothner (bothner at cygnus.com) + + * aout/aout64.h: Move common sunos-specific test + to recognize shared libraries into new macro N_SHARED_LIB. + Use it to simplify&reformat N_TXTADDR, N_TXTOFF, N_TXTSIZE. + +Sat Nov 30 20:34:52 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * ChangeLog, aout64.h, ar.h, encap.h, host.h, hp.h, ranlib.h, + reloc.h, stab.def, stab_gnu.h, sun4.h: All moved from the + devo/include directory + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/include/aout/adobe.h b/contrib/gdb/include/aout/adobe.h new file mode 100644 index 000000000000..3d2f15c6cb72 --- /dev/null +++ b/contrib/gdb/include/aout/adobe.h @@ -0,0 +1,297 @@ +/* `a.out.adobe' differences from standard a.out files */ + +#ifndef __A_OUT_ADOBE_H__ +#define __A_OUT_ADOBE_H__ + +#define BYTES_IN_WORD 4 + +/* Struct external_exec is the same. */ + +/* This is the layout on disk of the 32-bit or 64-bit exec header. */ + +struct external_exec +{ + bfd_byte e_info[4]; /* magic number and stuff */ + bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */ + bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */ + bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */ + bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */ + bfd_byte e_entry[BYTES_IN_WORD]; /* start address */ + bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */ + bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */ +}; + +#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) + +/* Magic numbers for a.out files */ + +#undef ZMAGIC +#define ZMAGIC 0xAD0BE /* Cute, eh? */ +#undef OMAGIC +#undef NMAGIC + +#define N_BADMAG(x) ((x).a_info != ZMAGIC) + +/* By default, segment size is constant. But some machines override this + to be a function of the a.out header (e.g. machine type). */ +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif +#undef N_SEGSIZE /* FIXMEXXXX */ + +/* Segment information for the a.out.Adobe format is specified after the + file header. It contains N segment descriptors, followed by one with + a type of zero. + + The actual text of the segments starts at N_TXTOFF in the file, + regardless of how many or how few segment headers there are. */ + +struct external_segdesc { + unsigned char e_type[1]; + unsigned char e_size[3]; + unsigned char e_virtbase[4]; + unsigned char e_filebase[4]; +}; + +struct internal_segdesc { + unsigned int a_type:8; /* Segment type N_TEXT, N_DATA, 0 */ + unsigned int a_size:24; /* Segment size */ + bfd_vma a_virtbase; /* Virtual address */ + unsigned int a_filebase; /* Base address in object file */ +}; + +#define N_TXTADDR(x) \ + +/* This is documented to be at 1024, but appears to really be at 2048. + FIXME?! */ +#define N_TXTOFF(x) 2048 + +#define N_TXTSIZE(x) ((x).a_text) + +#define N_DATADDR(x) + +#define N_BSSADDR(x) + +/* Offsets of the various portions of the file after the text segment. */ + +#define N_DATOFF(x) ( N_TXTOFF(x) + N_TXTSIZE(x) ) +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) + +/* Symbols */ +struct external_nlist { + bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */ + bfd_byte e_type[1]; /* type of symbol */ + bfd_byte e_other[1]; /* misc info (usually empty) */ + bfd_byte e_desc[2]; /* description field */ + bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */ +}; + +#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) + +struct internal_nlist { + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +}; + +/* The n_type field is the symbol type, containing: */ + +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol -- defined at particular addr */ +#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ +#define N_FN 0x1f /* File name of .o file */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ +#define N_TYPE 0x1e +#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */ + +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Relocations + + There are two types of relocation flavours for a.out systems, + standard and extended. The standard form is used on systems where the + instruction has room for all the bits of an offset to the operand, whilst + the extended form is used when an address operand has to be split over n + instructions. Eg, on the 68k, each move instruction can reference + the target with a displacement of 16 or 32 bits. On the sparc, move + instructions use an offset of 14 bits, so the offset is stored in + the reloc field, and the data in the section is ignored. +*/ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct reloc_std_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ +}; + +#define RELOC_STD_BITS_PCREL_BIG 0x80 +#define RELOC_STD_BITS_PCREL_LITTLE 0x01 + +#define RELOC_STD_BITS_LENGTH_BIG 0x60 +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */ +#define RELOC_STD_BITS_LENGTH_LITTLE 0x06 +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG 0x10 +#define RELOC_STD_BITS_EXTERN_LITTLE 0x08 + +#define RELOC_STD_BITS_BASEREL_BIG 0x08 +#define RELOC_STD_BITS_BASEREL_LITTLE 0x08 + +#define RELOC_STD_BITS_JMPTABLE_BIG 0x04 +#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04 + +#define RELOC_STD_BITS_RELATIVE_BIG 0x02 +#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02 + +#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */ + +struct reloc_std_internal +{ + bfd_vma r_address; /* Address (within segment) to be relocated. */ + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in files the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + unsigned int r_relative:1; /* "relative relocation" */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; + + +/* EXTENDED RELOCS */ + +struct reloc_ext_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ + bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */ +}; + +#define RELOC_EXT_BITS_EXTERN_BIG 0x80 +#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01 + +#define RELOC_EXT_BITS_TYPE_BIG 0x1F +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8 +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +/* Bytes per relocation entry */ +#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) + +enum reloc_type +{ + /* simple relocations */ + RELOC_8, /* data[0:7] = addend + sv */ + RELOC_16, /* data[0:15] = addend + sv */ + RELOC_32, /* data[0:31] = addend + sv */ + /* pc-rel displacement */ + RELOC_DISP8, /* data[0:7] = addend - pc + sv */ + RELOC_DISP16, /* data[0:15] = addend - pc + sv */ + RELOC_DISP32, /* data[0:31] = addend - pc + sv */ + /* Special */ + RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ + RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ + RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ + RELOC_22, /* data[0:21] = (addend + sv) */ + RELOC_13, /* data[0:12] = (addend + sv) */ + RELOC_LO10, /* data[0:9] = (addend + sv) */ + RELOC_SFA_BASE, + RELOC_SFA_OFF13, + /* P.I.C. (base-relative) */ + RELOC_BASE10, /* Not sure - maybe we can do this the */ + RELOC_BASE13, /* right way now */ + RELOC_BASE22, + /* for some sort of pc-rel P.I.C. (?) */ + RELOC_PC10, + RELOC_PC22, + /* P.I.C. jump table */ + RELOC_JMP_TBL, + /* reputedly for shared libraries somehow */ + RELOC_SEGOFF16, + RELOC_GLOB_DAT, + RELOC_JMP_SLOT, + RELOC_RELATIVE, + + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ + RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ + + /* 29K relocation types */ + RELOC_JUMPTARG, + RELOC_CONST, + RELOC_CONSTH, + + NO_RELOC + }; + + +struct reloc_internal { + bfd_vma r_address; /* offset of of data to relocate */ + long r_index; /* symbol table index of symbol */ + enum reloc_type r_type; /* relocation type */ + bfd_vma r_addend; /* datum addend */ +}; + +#endif /* __A_OUT_ADOBE_H__ */ diff --git a/contrib/gdb/include/aout/aout64.h b/contrib/gdb/include/aout/aout64.h new file mode 100644 index 000000000000..76f1140b6826 --- /dev/null +++ b/contrib/gdb/include/aout/aout64.h @@ -0,0 +1,475 @@ +/* `a.out' object-file definitions, including extensions to 64-bit fields */ + +#ifndef __A_OUT_64_H__ +#define __A_OUT_64_H__ + +/* This is the layout on disk of the 32-bit or 64-bit exec header. */ + +#ifndef external_exec +struct external_exec +{ + bfd_byte e_info[4]; /* magic number and stuff */ + bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */ + bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */ + bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */ + bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */ + bfd_byte e_entry[BYTES_IN_WORD]; /* start address */ + bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */ + bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */ +}; + +#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) + +/* Magic numbers for a.out files */ + +#if ARCH_SIZE==64 +#define OMAGIC 0x1001 /* Code indicating object file */ +#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */ +#define NMAGIC 0x1003 /* Code indicating pure executable. */ + +/* There is no 64-bit QMAGIC as far as I know. */ + +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#else +#define OMAGIC 0407 /* ...object file or impure executable. */ +#define NMAGIC 0410 /* Code indicating pure executable. */ +#define ZMAGIC 0413 /* Code indicating demand-paged executable. */ +#define BMAGIC 0415 /* Used by a b.out object. */ + +/* This indicates a demand-paged executable with the header in the text. + It is used by 386BSD (and variants) and Linux, at least. */ +#ifndef QMAGIC +#define QMAGIC 0314 +#endif +# ifndef N_BADMAG +# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +# endif /* N_BADMAG */ +#endif + +#endif + +#ifdef QMAGIC +#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC) +#else +#define N_IS_QMAGIC(x) (0) +#endif + +/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is + the finest granularity at which you can page something, thus it + controls the padding (if any) before the text segment of a ZMAGIC + file. N_SEGSIZE is the resolution at which things can be marked as + read-only versus read/write, so it controls the padding between the + text segment and the data segment (in memory; on disk the padding + between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same + for most machines, but different for sun3. */ + +/* By default, segment size is constant. But some machines override this + to be a function of the a.out header (e.g. machine type). */ + +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + +/* Virtual memory address of the text section. + This is getting very complicated. A good reason to discard a.out format + for something that specifies these fields explicitly. But til then... + + * OMAGIC and NMAGIC files: + (object files: text for "relocatable addr 0" right after the header) + start at 0, offset is EXEC_BYTES_SIZE, size as stated. + * The text address, offset, and size of ZMAGIC files depend + on the entry point of the file: + * entry point below TEXT_START_ADDR: + (hack for SunOS shared libraries) + start at 0, offset is 0, size as stated. + * If N_HEADER_IN_TEXT(x) is true (which defaults to being the + case when the entry point is EXEC_BYTES_SIZE or further into a page): + no padding is needed; text can start after exec header. Sun + considers the text segment of such files to include the exec header; + for BFD's purposes, we don't, which makes more work for us. + start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE, + size as stated minus EXEC_BYTES_SIZE. + * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when + the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page + aligned)): (padding is needed so that text can start at a page boundary) + start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated. + + Specific configurations may want to hardwire N_HEADER_IN_TEXT, + for efficiency or to allow people to play games with the entry point. + In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos, + and as 0 for most other hosts (Sony News, Vax Ultrix, etc). + (Do this in the appropriate bfd target file.) + (The default is a heuristic that will break if people try changing + the entry point, perhaps with the ld -e flag.) + + * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true, + and for which the starting address is TARGET_PAGE_SIZE (or should this be + SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC). + */ + +/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header + in the text. */ +#ifndef N_HEADER_IN_TEXT +#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE) +#endif + +/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC + files. */ +#ifndef N_SHARED_LIB +#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR) +#endif + +/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on + the assumption that we are dealing with a .o file, not an + executable. This is necessary for OMAGIC (but means we don't work + right on the output from ld -N); more questionable for NMAGIC. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(x) \ + (/* The address of a QMAGIC file is always one page in, */ \ + /* with the header in the text. */ \ + N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \ + N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\ + TEXT_START_ADDR /* a page of padding */\ + ) +#endif + +/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding + to make the text segment start at a certain boundary. For most + systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the + time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is + not what TARGET_PAGE_SIZE needs to be for QMAGIC. */ + +#ifndef ZMAGIC_DISK_BLOCK_SIZE +#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE +#endif + +#define N_DISK_BLOCK_SIZE(x) \ + (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE) + +/* Offset in an a.out of the start of the text section. */ +#ifndef N_TXTOFF +#define N_TXTOFF(x) \ + (/* For {O,N,Q}MAGIC, no padding. */ \ + N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + EXEC_BYTES_SIZE : /* no padding */\ + ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\ + ) +#endif +/* Size of the text section. It's always as stated, except that we + offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF + for ZMAGIC files that nominally include the exec header + as part of the first page of text. (BFD doesn't consider the + exec header to be part of the text segment.) */ +#ifndef N_TXTSIZE +#define N_TXTSIZE(x) \ + (/* For QMAGIC, we don't consider the header part of the text section. */\ + N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \ + (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \ + N_HEADER_IN_TEXT(x) ? \ + (x).a_text - EXEC_BYTES_SIZE: /* no padding */\ + (x).a_text /* a page of padding */\ + ) +#endif +/* The address of the data segment in virtual memory. + It is the text segment address, plus text segment size, rounded + up to a N_SEGSIZE boundary for pure or pageable files. */ +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1)))) +#endif +/* The address of the BSS segment -- immediately after the data segment. */ + +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +/* Offsets of the various portions of the file after the text segment. */ + +/* For {Q,Z}MAGIC, there is padding to make the data segment start on + a page boundary. Most of the time the a_text field (and thus + N_TXTSIZE) already contains this padding. It is possible that for + BSDI and/or 386BSD it sometimes doesn't contain the padding, and + perhaps we should be adding it here. But this seems kind of + questionable and probably should be BSDI/386BSD-specific if we do + do it. + + For NMAGIC (at least for hp300 BSD, probably others), there is + padding in memory only, not on disk, so we must *not* ever pad here + for NMAGIC. */ + +#ifndef N_DATOFF +#define N_DATOFF(x) \ + (N_TXTOFF(x) + N_TXTSIZE(x)) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#endif +#ifndef N_DRELOFF +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#endif +#ifndef N_SYMOFF +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#endif +#ifndef N_STROFF +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#endif + +/* Symbols */ +#ifndef external_nlist +struct external_nlist { + bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */ + bfd_byte e_type[1]; /* type of symbol */ + bfd_byte e_other[1]; /* misc info (usually empty) */ + bfd_byte e_desc[2]; /* description field */ + bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */ +}; +#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) +#endif + +struct internal_nlist { + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +}; + +/* The n_type field is the symbol type, containing: */ + +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol -- defined at particular addr */ +#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ +#define N_FN 0x1f /* File name of .o file */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ +#define N_TYPE 0x1e +#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */ + +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Weak symbols. These are a GNU extension to the a.out format. The + semantics are those of ELF weak symbols. Weak symbols are always + externally visible. The N_WEAK? values are squeezed into the + available slots. The value of a N_WEAKU symbol is 0. The values + of the other types are the definitions. */ +#define N_WEAKU 0x0d /* Weak undefined symbol. */ +#define N_WEAKA 0x0e /* Weak absolute symbol. */ +#define N_WEAKT 0x0f /* Weak text symbol. */ +#define N_WEAKD 0x10 /* Weak data symbol. */ +#define N_WEAKB 0x11 /* Weak bss symbol. */ + +/* Relocations + + There are two types of relocation flavours for a.out systems, + standard and extended. The standard form is used on systems where the + instruction has room for all the bits of an offset to the operand, whilst + the extended form is used when an address operand has to be split over n + instructions. Eg, on the 68k, each move instruction can reference + the target with a displacement of 16 or 32 bits. On the sparc, move + instructions use an offset of 14 bits, so the offset is stored in + the reloc field, and the data in the section is ignored. +*/ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct reloc_std_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ +}; + +#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80) +#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01) + +#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60) +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 +#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06) +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10) +#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08) + +#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08) +#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10) + +#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04) +#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20) + +#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02) +#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40) + +#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */ + +struct reloc_std_internal +{ + bfd_vma r_address; /* Address (within segment) to be relocated. */ + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in files the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + unsigned int r_relative:1; /* "relative relocation" */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; + + +/* EXTENDED RELOCS */ + +struct reloc_ext_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ + bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */ +}; + +#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80) +#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01) + +#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F) +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8) +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +/* Bytes per relocation entry */ +#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) + +enum reloc_type +{ + /* simple relocations */ + RELOC_8, /* data[0:7] = addend + sv */ + RELOC_16, /* data[0:15] = addend + sv */ + RELOC_32, /* data[0:31] = addend + sv */ + /* pc-rel displacement */ + RELOC_DISP8, /* data[0:7] = addend - pc + sv */ + RELOC_DISP16, /* data[0:15] = addend - pc + sv */ + RELOC_DISP32, /* data[0:31] = addend - pc + sv */ + /* Special */ + RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ + RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ + RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ + RELOC_22, /* data[0:21] = (addend + sv) */ + RELOC_13, /* data[0:12] = (addend + sv) */ + RELOC_LO10, /* data[0:9] = (addend + sv) */ + RELOC_SFA_BASE, + RELOC_SFA_OFF13, + /* P.I.C. (base-relative) */ + RELOC_BASE10, /* Not sure - maybe we can do this the */ + RELOC_BASE13, /* right way now */ + RELOC_BASE22, + /* for some sort of pc-rel P.I.C. (?) */ + RELOC_PC10, + RELOC_PC22, + /* P.I.C. jump table */ + RELOC_JMP_TBL, + /* reputedly for shared libraries somehow */ + RELOC_SEGOFF16, + RELOC_GLOB_DAT, + RELOC_JMP_SLOT, + RELOC_RELATIVE, + + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ + RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ + + /* 29K relocation types */ + RELOC_JUMPTARG, + RELOC_CONST, + RELOC_CONSTH, + + /* All the new ones I can think of, for sparc v9 */ + + RELOC_64, /* data[0:63] = addend + sv */ + RELOC_DISP64, /* data[0:63] = addend - pc + sv */ + RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */ + RELOC_DISP21, /* data[0:20] = addend - pc + sv */ + RELOC_DISP14, /* data[0:13] = addend - pc + sv */ + /* Q . + What are the other ones, + Since this is a clean slate, can we throw away the ones we dont + understand ? Should we sort the values ? What about using a + microcode format like the 68k ? + */ + NO_RELOC + }; + + +struct reloc_internal { + bfd_vma r_address; /* offset of of data to relocate */ + long r_index; /* symbol table index of symbol */ + enum reloc_type r_type; /* relocation type */ + bfd_vma r_addend; /* datum addend */ +}; + +/* Q. + Should the length of the string table be 4 bytes or 8 bytes ? + + Q. + What about archive indexes ? + + */ + +#endif /* __A_OUT_64_H__ */ diff --git a/contrib/gdb/include/aout/ar.h b/contrib/gdb/include/aout/ar.h new file mode 100644 index 000000000000..7b5dcdabd106 --- /dev/null +++ b/contrib/gdb/include/aout/ar.h @@ -0,0 +1,36 @@ +/* archive file definition for GNU software */ + +/* So far this is correct for BSDish archives. Don't forget that + files must begin on an even byte boundary. */ + +#ifndef __GNU_AR_H__ +#define __GNU_AR_H__ + +/* Note that the usual '\n' in magic strings may translate to different + characters, as allowed by ANSI. '\012' has a fixed value, and remains + compatible with existing BSDish archives. */ + +#define ARMAG "!\012" /* For COFF and a.out archives */ +#define ARMAGB "!\012" /* For b.out archives */ +#define SARMAG 8 +#define ARFMAG "`\012" + +/* The ar_date field of the armap (__.SYMDEF) member of an archive + must be greater than the modified date of the entire file, or + BSD-derived linkers complain. We originally write the ar_date with + this offset from the real file's mod-time. After finishing the + file, we rewrite ar_date if it's not still greater than the mod date. */ + +#define ARMAP_TIME_OFFSET 60 + +struct ar_hdr { + char ar_name[16]; /* name of this member */ + char ar_date[12]; /* file mtime */ + char ar_uid[6]; /* owner uid; printed as decimal */ + char ar_gid[6]; /* owner gid; printed as decimal */ + char ar_mode[8]; /* file mode, printed as octal */ + char ar_size[10]; /* file size, printed as decimal */ + char ar_fmag[2]; /* should contain ARFMAG */ +}; + +#endif /* __GNU_AR_H__ */ diff --git a/contrib/gdb/include/aout/dynix3.h b/contrib/gdb/include/aout/dynix3.h new file mode 100644 index 000000000000..efeeebfc4ccd --- /dev/null +++ b/contrib/gdb/include/aout/dynix3.h @@ -0,0 +1,71 @@ +/* + * a.out specifics for Sequent Symmetry running Dynix 3.x + */ +#ifndef A_OUT_DYNIX3_H +#define A_OUT_DYNIX3_H + +#define external_exec dynix_external_exec + +/* struct exec for Dynix 3 + * + * a_gdtbl and a_bootstrap are only for standalone binaries. + * Shared data fields are not supported by the kernel as of Dynix 3.1, + * but are supported by Dynix compiler programs. + */ +struct dynix_external_exec { + unsigned char e_info[4]; + unsigned char e_text[4]; + unsigned char e_data[4]; + unsigned char e_bss[4]; + unsigned char e_syms[4]; + unsigned char e_entry[4]; + unsigned char e_trsize[4]; + unsigned char e_drsize[4]; + unsigned char e_g_code[8], e_g_data[8], e_g_desc[8]; + unsigned char e_shdata[4]; + unsigned char e_shbss[4]; + unsigned char e_shdrsize[4]; + unsigned char e_bootstrap[44]; + unsigned char e_reserved[12]; + unsigned char e_version[4]; +}; + +#define EXEC_BYTES_SIZE (128) + +/* + * All executables under Dynix are demand paged with read-only text, + * Thus no NMAGIC. + * + * ZMAGIC has a page of 0s at virtual 0, + * XMAGIC has an invalid page at virtual 0 + */ +#define OMAGIC 0x12eb /* .o */ +#define ZMAGIC 0x22eb /* zero @ 0, demand load */ +#define XMAGIC 0x32eb /* invalid @ 0, demand load */ +#define SMAGIC 0x42eb /* standalone, not supported here */ + +#define N_BADMAG(x) ((OMAGIC != N_MAGIC(x)) && \ + (ZMAGIC != N_MAGIC(x)) && \ + (XMAGIC != N_MAGIC(x)) && \ + (SMAGIC != N_MAGIC(x))) + +#define N_ADDRADJ(x) ((ZMAGIC == N_MAGIC(x) || XMAGIC == N_MAGIC(x)) ? 0x1000 : 0) + +#define N_TXTOFF(x) (EXEC_BYTES_SIZE) +#define N_DATOFF(x) (N_TXTOFF(x) + N_TXTSIZE(x)) +#define N_SHDATOFF(x) (N_DATOFF(x) + (x).a_data) +#define N_TRELOFF(x) (N_SHDATOFF(x) + (x).a_shdata) +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#define N_SHDRELOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#define N_SYMOFF(x) (N_SHDRELOFF(x) + (x).a_shdrsize) +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) + +#define N_TXTADDR(x) \ + (((OMAGIC == N_MAGIC(x)) || (SMAGIC == N_MAGIC(x))) ? 0 \ + : TEXT_START_ADDR + EXEC_BYTES_SIZE) + +#define N_TXTSIZE(x) \ + (((OMAGIC == N_MAGIC(x)) || (SMAGIC == N_MAGIC(x))) ? ((x).a_text) \ + : ((x).a_text - N_ADDRADJ(x) - EXEC_BYTES_SIZE)) + +#endif /* A_OUT_DYNIX3_H */ diff --git a/contrib/gdb/include/aout/encap.h b/contrib/gdb/include/aout/encap.h new file mode 100644 index 000000000000..b215d49be168 --- /dev/null +++ b/contrib/gdb/include/aout/encap.h @@ -0,0 +1,135 @@ +/* Yet Another Try at encapsulating bsd object files in coff. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + Written by Pace Willisson 12/9/88 + + This file is obsolete. It needs to be converted to just define a bunch + of stuff that BFD can use to do coff-encapsulated files. --gnu@cygnus.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * We only use the coff headers to tell the kernel + * how to exec the file. Therefore, the only fields that need to + * be filled in are the scnptr and vaddr for the text and data + * sections, and the vaddr for the bss. As far as coff is concerned, + * there is no symbol table, relocation, or line numbers. + * + * A normal bsd header (struct exec) is placed after the coff headers, + * and before the real text. I defined a the new fields 'a_machtype' + * and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is + * true, then the bsd header is preceeded by a coff header. Macros + * like N_TXTOFF and N_TXTADDR use this field to find the bsd header. + * + * The only problem is to track down the bsd exec header. The + * macros HEADER_OFFSET, etc do this. + */ + +#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */ + +/* Describe the COFF header used for encapsulation. */ + +struct coffheader +{ + /* filehdr */ + unsigned short f_magic; + unsigned short f_nscns; + long f_timdat; + long f_symptr; + long f_nsyms; + unsigned short f_opthdr; + unsigned short f_flags; + /* aouthdr */ + short magic; + short vstamp; + long tsize; + long dsize; + long bsize; + long entry; + long text_start; + long data_start; + struct coffscn + { + char s_name[8]; + long s_paddr; + long s_vaddr; + long s_size; + long s_scnptr; + long s_relptr; + long s_lnnoptr; + unsigned short s_nreloc; + unsigned short s_nlnno; + long s_flags; + } scns[3]; +}; + +/* Describe some of the parameters of the encapsulation, + including how to find the encapsulated BSD header. */ + +/* FIXME, this is dumb. The same tools can't handle a.outs for different + architectures, just because COFF_MAGIC is different; so you need a + separate GNU nm for every architecture!!? Unfortunately, it needs to + be this way, since the COFF_MAGIC value is determined by the kernel + we're trying to fool here. */ + +#define COFF_MAGIC_I386 0514 /* I386MAGIC */ +#define COFF_MAGIC_M68K 0520 /* MC68MAGIC */ +#define COFF_MAGIC_A29K 0x17A /* Used by asm29k cross-tools */ + +#ifdef COFF_MAGIC +short __header_offset_temp; +#define HEADER_OFFSET(f) \ + (__header_offset_temp = 0, \ + fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \ + fseek ((f), -sizeof (short), 1), \ + __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0) +#else +#define HEADER_OFFSET(f) 0 +#endif + +#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1)) + +/* Describe the characteristics of the BSD header + that appears inside the encapsulation. */ + +/* Encapsulated coff files that are linked ZMAGIC have a text segment + offset just past the header (and a matching TXTADDR), excluding + the headers from the text segment proper but keeping the physical + layout and the virtual memory layout page-aligned. + + Non-encapsulated a.out files that are linked ZMAGIC have a text + segment that starts at 0 and an N_TXTADR similarly offset to 0. + They too are page-aligned with each other, but they include the + a.out header as part of the text. + + The _N_HDROFF gets sizeof struct exec added to it, so we have + to compensate here. See . */ + +#undef _N_HDROFF +#undef N_TXTADDR +#undef N_DATADDR + +#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) : 0) + +/* Address of text segment in memory after it is loaded. */ +#define N_TXTADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) + sizeof (struct exec) : 0) +#define SEGMENT_SIZE 0x400000 + +#define N_DATADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \ + (N_TXTADDR(x)+(x).a_text)) diff --git a/contrib/gdb/include/aout/host.h b/contrib/gdb/include/aout/host.h new file mode 100644 index 000000000000..8e36212716c1 --- /dev/null +++ b/contrib/gdb/include/aout/host.h @@ -0,0 +1,22 @@ +/* Parameters about the a.out format, based on the host system on which + the program is compiled. */ + +/* Address of data segment in memory after it is loaded. + It is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#ifndef SEGMENT_SIZE +#if defined(hp300) || defined(pyr) +#define SEGMENT_SIZE page_size +#endif +#ifdef sony +#define SEGMENT_SIZE 0x1000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define TARGET_PAGE_SIZE 0x400 +#define SEGMENT_SIZE TARGET_PAGE_SIZE +#endif +#endif /*!defined(SEGMENT_SIZE)*/ + diff --git a/contrib/gdb/include/aout/hp.h b/contrib/gdb/include/aout/hp.h new file mode 100644 index 000000000000..002f49cf453d --- /dev/null +++ b/contrib/gdb/include/aout/hp.h @@ -0,0 +1,82 @@ +/* Special version of for use under hp-ux. + Copyright 1988, 1991 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* THIS FILE IS OBSOLETE. It needs to be revised as a variant "external" + a.out format for use with BFD. */ + +/* The `exec' structure and overall layout must be close to HP's when + we are running on an HP system, otherwise we will not be able to + execute the resulting file. */ + +/* Allow this file to be included twice. */ +#ifndef __GNU_EXEC_MACROS__ + +struct exec +{ + unsigned short a_machtype; /* machine type */ + unsigned short a_magic; /* magic number */ + unsigned long a_spare1; + unsigned long a_spare2; + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned long a_trsize; /* length of relocation info for text, in bytes */ + unsigned long a_drsize; /* length of relocation info for data, in bytes */ + unsigned long a_spare3; /* HP = pascal interface size */ + unsigned long a_spare4; /* HP = symbol table size */ + unsigned long a_spare5; /* HP = debug name table size */ + unsigned long a_entry; /* start address */ + unsigned long a_spare6; /* HP = source line table size */ + unsigned long a_spare7; /* HP = value table size */ + unsigned long a_syms; /* length of symbol table data in file, in bytes */ + unsigned long a_spare8; +}; + +/* Tell a.out.gnu.h not to define `struct exec'. */ +#define __STRUCT_EXEC_OVERRIDE__ + +#include "../a.out.gnu.h" + +#undef N_MAGIC +#undef N_MACHTYPE +#undef N_FLAGS +#undef N_SET_INFO +#undef N_SET_MAGIC +#undef N_SET_MACHTYPE +#undef N_SET_FLAGS + +#define N_MAGIC(exec) ((exec) . a_magic) +#define N_MACHTYPE(exec) ((exec) . a_machtype) +#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic)) +#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype)) + +#undef N_BADMAG +#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x))) + +#define _N_BADMACH(x) \ +(((N_MACHTYPE (x)) != HP9000S200_ID) && \ + ((N_MACHTYPE (x)) != HP98x6_ID)) + +#define HP98x6_ID 0x20A +#define HP9000S200_ID 0x20C + +#undef _N_HDROFF +#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec))) + +#define SEGMENT_SIZE 0x1000 + +#endif /* __GNU_EXEC_MACROS__ */ diff --git a/contrib/gdb/include/aout/hp300hpux.h b/contrib/gdb/include/aout/hp300hpux.h new file mode 100644 index 000000000000..44d5196144da --- /dev/null +++ b/contrib/gdb/include/aout/hp300hpux.h @@ -0,0 +1,119 @@ +/* Special version of for use under hp-ux. + Copyright (C) 1988,1993 Free Software Foundation, Inc. */ + +struct hp300hpux_exec_bytes +{ + unsigned char e_info[4]; /* a_machtype/a_magic */ + unsigned char e_spare1[4]; + unsigned char e_spare2[4]; + unsigned char e_text[4]; /* length of text, in bytes */ + unsigned char e_data[4]; /* length of data, in bytes */ + unsigned char e_bss[4]; /* length of uninitialized data area , in bytes */ + unsigned char e_trsize[4]; /* length of relocation info for text, in bytes*/ + unsigned char e_drsize[4]; /* length of relocation info for data, in bytes*/ + unsigned char e_passize[4];/* HP = pascal interface size */ + unsigned char e_syms[4]; /* HP = symbol table size */ + unsigned char e_spare5[4]; /* HP = debug name table size */ + unsigned char e_entry[4]; /* start address */ + unsigned char e_spare6[4]; /* HP = source line table size */ + unsigned char e_supsize[4];/* HP = value table size */ + unsigned char e_drelocs[4]; + unsigned char e_extension[4]; /* file offset of extension */ +}; +#define EXEC_BYTES_SIZE 64 + +struct hp300hpux_nlist_bytes + { + unsigned char e_value[4]; + unsigned char e_type[1]; + unsigned char e_length[1]; /* length of ascii symbol name */ + unsigned char e_almod[2]; /* alignment mod */ + unsigned char e_shlib[2]; /* info about dynamic linking */ + }; +#define EXTERNAL_NLIST_SIZE 10 + +struct hp300hpux_reloc + { + unsigned char r_address[4];/* offset of of data to relocate */ + unsigned char r_index[2]; /* symbol table index of symbol */ + unsigned char r_type[1]; /* relocation type */ + unsigned char r_length[1]; /* length of item to reloc */ + }; + +struct hp300hpux_header_extension +{ + unsigned char e_syms[4]; + unsigned char unique_headers[12*4]; + unsigned char e_header[2]; /* type of header */ + unsigned char e_version[2]; /* version */ + unsigned char e_size[4]; /* bytes following*/ + unsigned char e_extension[4];/* file offset of next extension */ +}; +#define EXTERNAL_EXTENSION_HEADER_SIZE (16*4) + +/* hpux separates object files (0x106) and impure executables (0x107) */ +/* but the bfd code does not distinguish between them. Since we want to*/ +/* read hpux .o files, we add an special define and use it below in */ +/* offset and address calculations. */ + +#define HPUX_DOT_O_MAGIC 0x106 +#define OMAGIC 0x107 /* object file or impure executable. */ +#define NMAGIC 0x108 /* Code indicating pure executable. */ +#define ZMAGIC 0x10B /* demand-paged executable. */ + +#define N_HEADER_IN_TEXT(x) 0 + +#if 0 /* libaout.h only uses the lower 8 bits */ +#define HP98x6_ID 0x20A +#define HP9000S200_ID 0x20C +#endif +#define HP98x6_ID 0x0A +#define HP9000S200_ID 0x0C + +#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x))) + +#define N_DATADDR(x) \ + ((N_MAGIC(x)==OMAGIC || N_MAGIC(x)==HPUX_DOT_O_MAGIC) ? \ + (N_TXTADDR(x)+N_TXTSIZE(x)) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1)))) + +#define _N_BADMACH(x) \ +(((N_MACHTYPE (x)) != HP9000S200_ID) && \ + ((N_MACHTYPE (x)) != HP98x6_ID)) + +#define _N_BADMAG(x) (N_MAGIC(x) != HPUX_DOT_O_MAGIC \ + && N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC ) + +#undef _N_HDROFF +#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec))) + +#undef N_DATOFF +#undef N_PASOFF +#undef N_SYMOFF +#undef N_SUPOFF +#undef N_TRELOFF +#undef N_DRELOFF +#undef N_STROFF + +#define N_DATOFF(x) ( N_TXTOFF(x) + N_TXTSIZE(x) ) +#define N_PASOFF(x) ( N_DATOFF(x) + (x).a_data) +#define N_SYMOFF(x) ( N_PASOFF(x) /* + (x).a_passize*/ ) +#define N_SUPOFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#define N_TRELOFF(x) ( N_SUPOFF(x) /* + 0 (x).a_supsize*/ ) +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#define N_EXTHOFF(x) ( N_DRELOFF(x) /* + 0 (x).a_drsize */) +#define N_STROFF(x) ( 0 /* no string table */ ) + +/* use these when the file has gnu symbol tables */ +#define N_GNU_TRELOFF(x) (N_DATOFF(x) + (x).a_data) +#define N_GNU_DRELOFF(x) (N_GNU_TRELOFF(x) + (x).a_trsize) +#define N_GNU_SYMOFF(x) (N_GNU_DRELOFF(x) + (x).a_drsize) + +#define TARGET_PAGE_SIZE 0x1000 +#define SEGMENT_SIZE 0x1000 +#define TEXT_START_ADDR 0 + +#undef N_SHARED_LIB +#define N_SHARED_LIB(x) ( 0 /* no shared libraries */ ) diff --git a/contrib/gdb/include/aout/hppa.h b/contrib/gdb/include/aout/hppa.h new file mode 100644 index 000000000000..7e185de768a4 --- /dev/null +++ b/contrib/gdb/include/aout/hppa.h @@ -0,0 +1,7 @@ +#include "filehdr.h" +#include "aouthdr.h" +#include "scnhdr.h" +#include "spacehdr.h" +#include "syms.h" + + diff --git a/contrib/gdb/include/aout/ranlib.h b/contrib/gdb/include/aout/ranlib.h new file mode 100644 index 000000000000..982600514b65 --- /dev/null +++ b/contrib/gdb/include/aout/ranlib.h @@ -0,0 +1,62 @@ +/* ranlib.h -- archive library index member definition for GNU. + Copyright 1990-1991 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The Symdef member of an archive contains two things: + a table that maps symbol-string offsets to file offsets, + and a symbol-string table. All the symbol names are + run together (each with trailing null) in the symbol-string + table. There is a single longword bytecount on the front + of each of these tables. Thus if we have two symbols, + "foo" and "_bar", that are in archive members at offsets + 200 and 900, it would look like this: + 16 ; byte count of index table + 0 ; offset of "foo" in string table + 200 ; offset of foo-module in file + 4 ; offset of "bar" in string table + 900 ; offset of bar-module in file + 9 ; byte count of string table + "foo\0_bar\0" ; string table */ + +#define RANLIBMAG "__.SYMDEF" /* Archive file name containing index */ +#define RANLIBSKEW 3 /* Creation time offset */ + +/* Format of __.SYMDEF: + First, a longword containing the size of the 'symdef' data that follows. + Second, zero or more 'symdef' structures. + Third, a longword containing the length of symbol name strings. + Fourth, zero or more symbol name strings (each followed by a null). */ + +struct symdef + { + union + { + unsigned long string_offset; /* In the file */ + char *name; /* In memory, sometimes */ + } s; + /* this points to the front of the file header (AKA member header -- + a struct ar_hdr), not to the front of the file or into the file). + in other words it only tells you which file to read */ + unsigned long file_offset; + }; + +/* Compatability with BSD code */ + +#define ranlib symdef +#define ran_un s +#define ran_strx string_offset +#define ran_name name +#define ran_off file_offset diff --git a/contrib/gdb/include/aout/reloc.h b/contrib/gdb/include/aout/reloc.h new file mode 100644 index 000000000000..563c552a3578 --- /dev/null +++ b/contrib/gdb/include/aout/reloc.h @@ -0,0 +1,66 @@ +/* reloc.h -- Header file for relocation information. + Copyright 1989-1991 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Relocation types for a.out files using reloc_info_extended + (SPARC and AMD 29000). */ + +#ifndef _RELOC_H_READ_ +#define _RELOC_H_READ_ 1 + +enum reloc_type + { + RELOC_8, RELOC_16, RELOC_32, /* simple relocations */ + RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */ + RELOC_WDISP30, RELOC_WDISP22, + RELOC_HI22, RELOC_22, + RELOC_13, RELOC_LO10, + RELOC_SFA_BASE, RELOC_SFA_OFF13, + RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */ + RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */ + RELOC_JMP_TBL, /* P.I.C. jump table */ + RELOC_SEGOFF16, /* reputedly for shared libraries somehow */ + RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, + RELOC_HLO10, + + /* 29K relocation types */ + RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH, + + RELOC_WDISP14, RELOC_WDISP21, + + NO_RELOC + }; + +#define RELOC_TYPE_NAMES \ +"8", "16", "32", "DISP8", \ +"DISP16", "DISP32", "WDISP30", "WDISP22", \ +"HI22", "22", "13", "LO10", \ +"SFA_BASE", "SFAOFF13", "BASE10", "BASE13", \ +"BASE22", "PC10", "PC22", "JMP_TBL", \ +"SEGOFF16", "GLOB_DAT", "JMP_SLOT", "RELATIVE", \ +"11", "WDISP2_14", "WDISP19", "HHI22", \ +"HLO10", \ +"JUMPTARG", "CONST", "CONSTH", "WDISP14", \ +"WDISP21", \ +"NO_RELOC" + +#endif /* _RELOC_H_READ_ */ + +/* end of reloc.h */ diff --git a/contrib/gdb/include/aout/stab.def b/contrib/gdb/include/aout/stab.def new file mode 100644 index 000000000000..3c6b456d3a97 --- /dev/null +++ b/contrib/gdb/include/aout/stab.def @@ -0,0 +1,264 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files + overlaps the N_UNDF used for ordinary symbols. In ELF files, the + debug information is in a different file section, so there is no conflict. + This symbol's n_value gives the size of the string section associated + with this file. The symbol's n_strx (relative to the just-updated + string section start address) gives the name of the source file, + e.g. "foo.c", without any path information. The symbol's n_desc gives + the count of upcoming symbols associated with this file (not including + this one). */ +/* __define_stab (N_UNDF, 0x00, "UNDF") */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Solaris2: Read-only data symbols. */ +__define_stab (N_ROSYM, 0x2c, "ROSYM") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris 2. Like N_SO, but for the object file. Two in + a row provide the build directory and the relative path of the .o from it. + Solaris2 uses this to avoid putting the stabs info into the linked + executable; this stab goes into the ".stab.index" section, and the debugger + reads the real stabs directly from the .o files instead. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris 2. Options for the debugger, related to the + source language for this module. E.g. whether to use ANSI + integral promotions or traditional integral promotions. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. On Solaris2, the line number is + relative to the start of the current function. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab_duplicate (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* New in Solaris2. Function start/body/end line numbers. */ +__define_stab(N_FLINE, 0x4C, "FLINE") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab_duplicate (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Solaris2: Last stab emitted for module. */ +__define_stab (N_ENDM, 0x62, "ENDM") + +/* Name of main source file. + Value is starting text address of the compilation. + If multiple N_SO's appear, the first to contain a trailing / is the + compilation directory. The first to not contain a trailing / is the + source file name, relative to the compilation directory. Others (perhaps + resulting from cfront) are ignored. + On Solaris2, value is undefined, but desc is a source-language code. */ + +__define_stab (N_SO, 0x64, "SO") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* Member of a common block; value is offset within the common block. + This should occur within a BCOMM/ECOMM pair. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* Solaris2: Pascal "with" statement: type,,0,0,offset */ +__define_stab (N_WITH, 0xea, "WITH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | + | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | + + | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | + | 11 WEAKB | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 ENDM | 64 SO | 66 | + | 68 | 6A | 6C | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA WITH | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/contrib/gdb/include/aout/stab_gnu.h b/contrib/gdb/include/aout/stab_gnu.h new file mode 100644 index 000000000000..7d18e14a2634 --- /dev/null +++ b/contrib/gdb/include/aout/stab_gnu.h @@ -0,0 +1,37 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, +#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "aout/stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab + +/* Definitions of "desc" field for N_SO stabs in Solaris2. */ + +#define N_SO_AS 1 +#define N_SO_C 2 +#define N_SO_ANSI_C 3 +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 +#define N_SO_PASCAL 6 + +/* Solaris2: Floating point type values in basic types. */ + +#define NF_NONE 0 +#define NF_SINGLE 1 /* IEEE 32-bit */ +#define NF_DOUBLE 2 /* IEEE 64-bit */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double (whatever that is) */ + +#endif /* __GNU_STAB_ */ diff --git a/contrib/gdb/include/aout/sun4.h b/contrib/gdb/include/aout/sun4.h new file mode 100644 index 000000000000..f42a0dd45988 --- /dev/null +++ b/contrib/gdb/include/aout/sun4.h @@ -0,0 +1,219 @@ +/* SPARC-specific values for a.out files */ + +/* Some systems, e.g., AIX, may have defined this in header files already + included. */ +#undef TARGET_PAGE_SIZE +#define TARGET_PAGE_SIZE 0x2000 /* 8K. aka NBPG in */ +/* Note that some SPARCs have 4K pages, some 8K, some others. */ + +#define SEG_SIZE_SPARC TARGET_PAGE_SIZE +#define SEG_SIZE_SUN3 0x20000 /* Resolution of r/w protection hw */ + +#define TEXT_START_ADDR TARGET_PAGE_SIZE /* Location 0 is not accessible */ +#define N_HEADER_IN_TEXT(x) 1 + +/* Non-default definitions of the accessor macros... */ + +/* Segment size varies on Sun-3 versus Sun-4. */ + +#define N_SEGSIZE(x) (N_MACHTYPE(x) == M_SPARC? SEG_SIZE_SPARC: \ + N_MACHTYPE(x) == M_68020? SEG_SIZE_SUN3: \ + /* Guess? */ TARGET_PAGE_SIZE) + +/* Virtual Address of text segment from the a.out file. For OMAGIC, + (almost always "unlinked .o's" these days), should be zero. + Sun added a kludge so that shared libraries linked ZMAGIC get + an address of zero if a_entry (!!!) is lower than the otherwise + expected text address. These kludges have gotta go! + For linked files, should reflect reality if we know it. */ + +/* This differs from the version in aout64.h (which we override by defining + it here) only for NMAGIC (we return TEXT_START_ADDR+EXEC_BYTES_SIZE; + they return 0). */ + +#define N_TXTADDR(x) \ + (N_MAGIC(x)==OMAGIC? 0 \ + : (N_MAGIC(x) == ZMAGIC && (x).a_entry < TEXT_START_ADDR)? 0 \ + : TEXT_START_ADDR+EXEC_BYTES_SIZE) + +/* When a file is linked against a shared library on SunOS 4, the + dynamic bit in the exec header is set, and the first symbol in the + symbol table is __DYNAMIC. Its value is the address of the + following structure. */ + +struct external_sun4_dynamic +{ + /* The version number of the structure. SunOS 4.1.x creates files + with version number 3, which is what this structure is based on. + According to gdb, version 2 is similar. I believe that version 2 + used a different type of procedure linkage table, and there may + have been other differences. */ + bfd_byte ld_version[4]; + /* The virtual address of a 28 byte structure used in debugging. + The contents are filled in at run time by ld.so. */ + bfd_byte ldd[4]; + /* The virtual address of another structure with information about + how to relocate the executable at run time. */ + bfd_byte ld[4]; +}; + +/* The size of the debugging structure pointed to by the debugger + field of __DYNAMIC. */ +#define EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE (24) + +/* The structure pointed to by the linker field of __DYNAMIC. As far + as I can tell, most of the addresses in this structure are offsets + within the file, but some are actually virtual addresses. */ + +struct internal_sun4_dynamic_link +{ + /* Linked list of loaded objects. This is filled in at runtime by + ld.so and probably by dlopen. */ + unsigned long ld_loaded; + + /* The address of the list of names of shared objects which must be + included at runtime. Each entry in the list is 16 bytes: the 4 + byte address of the string naming the object (e.g., for -lc this + is "c"); 4 bytes of flags--the high bit is whether to search for + the object using the library path; the 2 byte major version + number; the 2 byte minor version number; the 4 byte address of + the next entry in the list (zero if this is the last entry). The + version numbers seem to only be non-zero when doing library + searching. */ + unsigned long ld_need; + + /* The address of the path to search for the shared objects which + must be included. This points to a string in PATH format which + is generated from the -L arguments to the linker. According to + the man page, ld.so implicitly adds ${LD_LIBRARY_PATH} to the + beginning of this string and /lib:/usr/lib:/usr/local/lib to the + end. The string is terminated by a null byte. This field is + zero if there is no additional path. */ + unsigned long ld_rules; + + /* The address of the global offset table. This appears to be a + virtual address, not a file offset. The first entry in the + global offset table seems to be the virtual address of the + sun4_dynamic structure (the same value as the __DYNAMIC symbol). + The global offset table is used for PIC code to hold the + addresses of variables. A dynamically linked file which does not + itself contain PIC code has a four byte global offset table. */ + unsigned long ld_got; + + /* The address of the procedure linkage table. This appears to be a + virtual address, not a file offset. + + On a SPARC, the table is composed of 12 byte entries, each of + which consists of three instructions. The first entry is + sethi %hi(0),%g1 + jmp %g1 + nop + These instructions are changed by ld.so into a jump directly into + ld.so itself. Each subsequent entry is + save %sp, -96, %sp + call
+ + The reloc_number is the number of the reloc to use to resolve + this entry. The reloc will be a JMP_SLOT reloc against some + symbol that is not defined in this object file but should be + defined in a shared object (if it is not, ld.so will report a + runtime error and exit). The constant 0x010000000 turns the + reloc number into a sethi of %g0, which does nothing since %g0 is + hardwired to zero. + + When one of these entries is executed, it winds up calling into + ld.so. ld.so looks at the reloc number, available via the return + address, to determine which entry this is. It then looks at the + reloc and patches up the entry in the table into a sethi and jmp + to the real address followed by a nop. This means that the reloc + lookup only has to happen once, and it also means that the + relocation only needs to be done if the function is actually + called. The relocation is expensive because ld.so must look up + the symbol by name. + + The size of the procedure linkage table is given by the ld_plt_sz + field. */ + unsigned long ld_plt; + + /* The address of the relocs. These are in the same format as + ordinary relocs. Symbol index numbers refer to the symbols + pointed to by ld_stab. I think the only way to determine the + number of relocs is to assume that all the bytes from ld_rel to + ld_hash contain reloc entries. */ + unsigned long ld_rel; + + /* The address of a hash table of symbols. The hash table has + roughly the same number of entries as there are dynamic symbols; + I think the only way to get the exact size is to assume that + every byte from ld_hash to ld_stab is devoted to the hash table. + + Each entry in the hash table is eight bytes. The first four + bytes are a symbol index into the dynamic symbols. The second + four bytes are the index of the next hash table entry in the + bucket. The ld_buckets field gives the number of buckets, say B. + The first B entries in the hash table each start a bucket which + is chained through the second four bytes of each entry. A value + of zero ends the chain. + + The hash function is simply + h = 0; + while (*string != '\0') + h = (h << 1) + *string++; + h &= 0x7fffffff; + + To look up a symbol, compute the hash value of the name. Take + the modulos of hash value and the number of buckets. Start at + that entry in the hash table. See if the symbol (from the first + four bytes of the hash table entry) has the name you are looking + for. If not, use the chain field (the second four bytes of the + hash table entry) to move on to the next entry in this bucket. + If the chain field is zero you have reached the end of the + bucket, and the symbol is not in the hash table. */ + unsigned long ld_hash; + + /* The address of the symbol table. This is a list of + external_nlist structures. The string indices are relative to + the ld_symbols field. I think the only way to determine the + number of symbols is to assume that all the bytes between ld_stab + and ld_symbols are external_nlist structures. */ + unsigned long ld_stab; + + /* I don't know what this is for. It seems to always be zero. */ + unsigned long ld_stab_hash; + + /* The number of buckets in the hash table. */ + unsigned long ld_buckets; + + /* The address of the symbol string table. The first string in this + string table need not be the empty string. */ + unsigned long ld_symbols; + + /* The size in bytes of the symbol string table. */ + unsigned long ld_symb_size; + + /* The size in bytes of the text segment. */ + unsigned long ld_text; + + /* The size in bytes of the procedure linkage table. */ + unsigned long ld_plt_sz; +}; + +/* The external form of the structure. */ + +struct external_sun4_dynamic_link +{ + bfd_byte ld_loaded[4]; + bfd_byte ld_need[4]; + bfd_byte ld_rules[4]; + bfd_byte ld_got[4]; + bfd_byte ld_plt[4]; + bfd_byte ld_rel[4]; + bfd_byte ld_hash[4]; + bfd_byte ld_stab[4]; + bfd_byte ld_stab_hash[4]; + bfd_byte ld_buckets[4]; + bfd_byte ld_symbols[4]; + bfd_byte ld_symb_size[4]; + bfd_byte ld_text[4]; + bfd_byte ld_plt_sz[4]; +}; diff --git a/contrib/gdb/include/bfdlink.h b/contrib/gdb/include/bfdlink.h new file mode 100644 index 000000000000..47d80b8c195f --- /dev/null +++ b/contrib/gdb/include/bfdlink.h @@ -0,0 +1,452 @@ +/* bfdlink.h -- header file for BFD link routines + Copyright 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BFDLINK_H +#define BFDLINK_H + +/* Which symbols to strip during a link. */ +enum bfd_link_strip +{ + strip_none, /* Don't strip any symbols. */ + strip_debugger, /* Strip debugging symbols. */ + strip_some, /* keep_hash is the list of symbols to keep. */ + strip_all /* Strip all symbols. */ +}; + +/* Which local symbols to discard during a link. This is irrelevant + if strip_all is used. */ +enum bfd_link_discard +{ + discard_none, /* Don't discard any locals. */ + discard_l, /* Discard locals with a certain prefix. */ + discard_all /* Discard all locals. */ +}; + +/* These are the possible types of an entry in the BFD link hash + table. */ + +enum bfd_link_hash_type +{ + bfd_link_hash_new, /* Symbol is new. */ + bfd_link_hash_undefined, /* Symbol seen before, but undefined. */ + bfd_link_hash_undefweak, /* Symbol is weak and undefined. */ + bfd_link_hash_defined, /* Symbol is defined. */ + bfd_link_hash_defweak, /* Symbol is weak and defined. */ + bfd_link_hash_common, /* Symbol is common. */ + bfd_link_hash_indirect, /* Symbol is an indirect link. */ + bfd_link_hash_warning /* Like indirect, but warn if referenced. */ +}; + +/* The linking routines use a hash table which uses this structure for + its elements. */ + +struct bfd_link_hash_entry +{ + /* Base hash table entry structure. */ + struct bfd_hash_entry root; + /* Type of this entry. */ + enum bfd_link_hash_type type; + + /* Undefined and common symbols are kept in a linked list through + this field. This field is not in the union because that would + force us to remove entries from the list when we changed their + type, which would force the list to be doubly linked, which would + waste more memory. When an undefined or common symbol is + created, it should be added to this list, the head of which is in + the link hash table itself. As symbols are defined, they need + not be removed from the list; anything which reads the list must + doublecheck the symbol type. + + Weak symbols are not kept on this list. + + Defined and defweak symbols use this field as a reference marker. + If the field is not NULL, or this structure is the tail of the + undefined symbol list, the symbol has been referenced. If the + symbol is undefined and becomes defined, this field will + automatically be non-NULL since the symbol will have been on the + undefined symbol list. */ + struct bfd_link_hash_entry *next; + /* A union of information depending upon the type. */ + union + { + /* Nothing is kept for bfd_hash_new. */ + /* bfd_link_hash_undefined, bfd_link_hash_undefweak. */ + struct + { + bfd *abfd; /* BFD symbol was found in. */ + } undef; + /* bfd_link_hash_defined, bfd_link_hash_defweak. */ + struct + { + bfd_vma value; /* Symbol value. */ + asection *section; /* Symbol section. */ + } def; + /* bfd_link_hash_indirect, bfd_link_hash_warning. */ + struct + { + struct bfd_link_hash_entry *link; /* Real symbol. */ + const char *warning; /* Warning (bfd_link_hash_warning only). */ + } i; + /* bfd_link_hash_common. */ + struct + { + /* The linker needs to know three things about common + symbols: the size, the alignment, and the section in + which the symbol should be placed. We store the size + here, and we allocate a small structure to hold the + section and the alignment. The alignment is stored as a + power of two. We don't store all the information + directly because we don't want to increase the size of + the union; this structure is a major space user in the + linker. */ + bfd_size_type size; /* Common symbol size. */ + struct bfd_link_hash_common_entry + { + unsigned int alignment_power; /* Alignment. */ + asection *section; /* Symbol section. */ + } *p; + } c; + } u; +}; + +/* This is the link hash table. It is a derived class of + bfd_hash_table. */ + +struct bfd_link_hash_table +{ + /* The hash table itself. */ + struct bfd_hash_table table; + /* The back end which created this hash table. This indicates the + type of the entries in the hash table, which is sometimes + important information when linking object files of different + types together. */ + const bfd_target *creator; + /* A linked list of undefined and common symbols, linked through the + next field in the bfd_link_hash_entry structure. */ + struct bfd_link_hash_entry *undefs; + /* Entries are added to the tail of the undefs list. */ + struct bfd_link_hash_entry *undefs_tail; +}; + +/* Look up an entry in a link hash table. If FOLLOW is true, this + follows bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ +extern struct bfd_link_hash_entry *bfd_link_hash_lookup + PARAMS ((struct bfd_link_hash_table *, const char *, boolean create, + boolean copy, boolean follow)); + +/* Look up an entry in the main linker hash table if the symbol might + be wrapped. This should only be used for references to an + undefined symbol, not for definitions of a symbol. */ + +extern struct bfd_link_hash_entry *bfd_wrapped_link_hash_lookup + PARAMS ((bfd *, struct bfd_link_info *, const char *, boolean, boolean, + boolean)); + +/* Traverse a link hash table. */ +extern void bfd_link_hash_traverse + PARAMS ((struct bfd_link_hash_table *, + boolean (*) (struct bfd_link_hash_entry *, PTR), + PTR)); + +/* Add an entry to the undefs list. */ +extern void bfd_link_add_undef + PARAMS ((struct bfd_link_hash_table *, struct bfd_link_hash_entry *)); + +/* This structure holds all the information needed to communicate + between BFD and the linker when doing a link. */ + +struct bfd_link_info +{ + /* Function callbacks. */ + const struct bfd_link_callbacks *callbacks; + /* true if BFD should generate a relocateable object file. */ + boolean relocateable; + /* true if BFD should generate a shared object. */ + boolean shared; + /* true if BFD should pre-bind symbols in a shared object. */ + boolean symbolic; + /* true if shared objects should be linked directly, not shared. */ + boolean static_link; + /* Which symbols to strip. */ + enum bfd_link_strip strip; + /* Which local symbols to discard. */ + enum bfd_link_discard discard; + /* The local symbol prefix to discard if using discard_l. */ + unsigned int lprefix_len; + const char *lprefix; + /* true if symbols should be retained in memory, false if they + should be freed and reread. */ + boolean keep_memory; + /* The list of input BFD's involved in the link. These are chained + together via the link_next field. */ + bfd *input_bfds; + /* If a symbol should be created for each input BFD, this is section + where those symbols should be placed. It must be a section in + the output BFD. It may be NULL, in which case no such symbols + will be created. This is to support CREATE_OBJECT_SYMBOLS in the + linker command language. */ + asection *create_object_symbols_section; + /* Hash table handled by BFD. */ + struct bfd_link_hash_table *hash; + /* Hash table of symbols to keep. This is NULL unless strip is + strip_some. */ + struct bfd_hash_table *keep_hash; + /* Hash table of symbols to report back via notice_callback. If + this is NULL no symbols are reported back. */ + struct bfd_hash_table *notice_hash; + /* Hash table of symbols which are being wrapped (the --wrap linker + option). If this is NULL, no symbols are being wrapped. */ + struct bfd_hash_table *wrap_hash; + + /* If a base output file is wanted, then this points to it */ + PTR base_file; +}; + +/* This structures holds a set of callback functions. These are + called by the BFD linker routines. The first argument to each + callback function is the bfd_link_info structure being used. Each + function returns a boolean value. If the function returns false, + then the BFD function which called it will return with a failure + indication. */ + +struct bfd_link_callbacks +{ + /* A function which is called when an object is added from an + archive. ABFD is the archive element being added. NAME is the + name of the symbol which caused the archive element to be pulled + in. */ + boolean (*add_archive_element) PARAMS ((struct bfd_link_info *, + bfd *abfd, + const char *name)); + /* A function which is called when a symbol is found with multiple + definitions. NAME is the symbol which is defined multiple times. + OBFD is the old BFD, OSEC is the old section, OVAL is the old + value, NBFD is the new BFD, NSEC is the new section, and NVAL is + the new value. OBFD may be NULL. OSEC and NSEC may be + bfd_com_section or bfd_ind_section. */ + boolean (*multiple_definition) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *obfd, + asection *osec, + bfd_vma oval, + bfd *nbfd, + asection *nsec, + bfd_vma nval)); + /* A function which is called when a common symbol is defined + multiple times. NAME is the symbol appearing multiple times. + OBFD is the BFD of the existing symbol; it may be NULL if this is + not known. OTYPE is the type of the existing symbol, which may + be bfd_link_hash_defined, bfd_link_hash_defweak, + bfd_link_hash_common, or bfd_link_hash_indirect. If OTYPE is + bfd_link_hash_common, OSIZE is the size of the existing symbol. + NBFD is the BFD of the new symbol. NTYPE is the type of the new + symbol, one of bfd_link_hash_defined, bfd_link_hash_common, or + bfd_link_hash_indirect. If NTYPE is bfd_link_hash_common, NSIZE + is the size of the new symbol. */ + boolean (*multiple_common) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *obfd, + enum bfd_link_hash_type otype, + bfd_vma osize, + bfd *nbfd, + enum bfd_link_hash_type ntype, + bfd_vma nsize)); + /* A function which is called to add a symbol to a set. ENTRY is + the link hash table entry for the set itself (e.g., + __CTOR_LIST__). RELOC is the relocation to use for an entry in + the set when generating a relocateable file, and is also used to + get the size of the entry when generating an executable file. + ABFD, SEC and VALUE identify the value to add to the set. */ + boolean (*add_to_set) PARAMS ((struct bfd_link_info *, + struct bfd_link_hash_entry *entry, + bfd_reloc_code_real_type reloc, + bfd *abfd, asection *sec, bfd_vma value)); + /* A function which is called when the name of a g++ constructor or + destructor is found. This is only called by some object file + formats. CONSTRUCTOR is true for a constructor, false for a + destructor. This will use BFD_RELOC_CTOR when generating a + relocateable file. NAME is the name of the symbol found. ABFD, + SECTION and VALUE are the value of the symbol. */ + boolean (*constructor) PARAMS ((struct bfd_link_info *, + boolean constructor, + const char *name, bfd *abfd, asection *sec, + bfd_vma value)); + /* A function which is called to issue a linker warning. For + example, this is called when there is a reference to a warning + symbol. WARNING is the warning to be issued. SYMBOL is the name + of the symbol which triggered the warning; it may be NULL if + there is none. ABFD, SECTION and ADDRESS identify the location + which trigerred the warning; either ABFD or SECTION or both may + be NULL if the location is not known. */ + boolean (*warning) PARAMS ((struct bfd_link_info *, + const char *warning, const char *symbol, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a relocation is attempted against + an undefined symbol. NAME is the symbol which is undefined. + ABFD, SECTION and ADDRESS identify the location from which the + reference is made. In some cases SECTION may be NULL. */ + boolean (*undefined_symbol) PARAMS ((struct bfd_link_info *, + const char *name, bfd *abfd, + asection *section, bfd_vma address)); + /* A function which is called when a reloc overflow occurs. NAME is + the name of the symbol or section the reloc is against, + RELOC_NAME is the name of the relocation, and ADDEND is any + addend that is used. ABFD, SECTION and ADDRESS identify the + location at which the overflow occurs; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*reloc_overflow) PARAMS ((struct bfd_link_info *, + const char *name, + const char *reloc_name, bfd_vma addend, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a dangerous reloc is performed. + The canonical example is an a29k IHCONST reloc which does not + follow an IHIHALF reloc. MESSAGE is an appropriate message. + ABFD, SECTION and ADDRESS identify the location at which the + problem occurred; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*reloc_dangerous) PARAMS ((struct bfd_link_info *, + const char *message, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a reloc is found to be attached + to a symbol which is not being written out. NAME is the name of + the symbol. ABFD, SECTION and ADDRESS identify the location of + the reloc; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*unattached_reloc) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a symbol in notice_hash is + defined or referenced. NAME is the symbol. ABFD, SECTION and + ADDRESS are the value of the symbol. If SECTION is + bfd_und_section, this is a reference. */ + boolean (*notice) PARAMS ((struct bfd_link_info *, const char *name, + bfd *abfd, asection *section, bfd_vma address)); +}; + +/* The linker builds link_order structures which tell the code how to + include input data in the output file. */ + +/* These are the types of link_order structures. */ + +enum bfd_link_order_type +{ + bfd_undefined_link_order, /* Undefined. */ + bfd_indirect_link_order, /* Built from a section. */ + bfd_fill_link_order, /* Fill with a 16 bit constant. */ + bfd_data_link_order, /* Set to explicit data. */ + bfd_section_reloc_link_order, /* Relocate against a section. */ + bfd_symbol_reloc_link_order /* Relocate against a symbol. */ +}; + +/* This is the link_order structure itself. These form a chain + attached to the section whose contents they are describing. */ + +struct bfd_link_order +{ + /* Next link_order in chain. */ + struct bfd_link_order *next; + /* Type of link_order. */ + enum bfd_link_order_type type; + /* Offset within output section. */ + bfd_vma offset; + /* Size within output section. */ + bfd_size_type size; + /* Type specific information. */ + union + { + struct + { + /* Section to include. If this is used, then + section->output_section must be the section the + link_order is attached to, section->output_offset must + equal the link_order offset field, and section->_raw_size + must equal the link_order size field. Maybe these + restrictions should be relaxed someday. */ + asection *section; + } indirect; + struct + { + /* Value to fill with. */ + unsigned int value; + } fill; + struct + { + /* Data to put into file. The size field gives the number + of bytes which this field points to. */ + bfd_byte *contents; + } data; + struct + { + /* Description of reloc to generate. Used for + bfd_section_reloc_link_order and + bfd_symbol_reloc_link_order. */ + struct bfd_link_order_reloc *p; + } reloc; + } u; +}; + +/* A linker order of type bfd_section_reloc_link_order or + bfd_symbol_reloc_link_order means to create a reloc against a + section or symbol, respectively. This is used to implement -Ur to + generate relocs for the constructor tables. The + bfd_link_order_reloc structure describes the reloc that BFD should + create. It is similar to a arelent, but I didn't use arelent + because the linker does not know anything about most symbols, and + any asymbol structure it creates will be partially meaningless. + This information could logically be in the bfd_link_order struct, + but I didn't want to waste the space since these types of relocs + are relatively rare. */ + +struct bfd_link_order_reloc +{ + /* Reloc type. */ + bfd_reloc_code_real_type reloc; + + union + { + /* For type bfd_section_reloc_link_order, this is the section + the reloc should be against. This must be a section in the + output BFD, not any of the input BFDs. */ + asection *section; + /* For type bfd_symbol_reloc_link_order, this is the name of the + symbol the reloc should be against. */ + const char *name; + } u; + + /* Addend to use. The object file should contain zero. The BFD + backend is responsible for filling in the contents of the object + file correctly. For some object file formats (e.g., COFF) the + addend must be stored into in the object file, and for some + (e.g., SPARC a.out) it is kept in the reloc. */ + bfd_vma addend; +}; + +/* Allocate a new link_order for a section. */ +extern struct bfd_link_order *bfd_new_link_order PARAMS ((bfd *, asection *)); + +#endif diff --git a/contrib/gdb/include/bout.h b/contrib/gdb/include/bout.h new file mode 100644 index 000000000000..8fc28cc3d6d7 --- /dev/null +++ b/contrib/gdb/include/bout.h @@ -0,0 +1,182 @@ +/* + * This file is a modified version of 'a.out.h'. It is to be used in all + * GNU tools modified to support the i80960 (or tools that operate on + * object files created by such tools). + * + * All i80960 development is done in a CROSS-DEVELOPMENT environment. I.e., + * object code is generated on, and executed under the direction of a symbolic + * debugger running on, a host system. We do not want to be subject to the + * vagaries of which host it is or whether it supports COFF or a.out format, + * or anything else. We DO want to: + * + * o always generate the same format object files, regardless of host. + * + * o have an 'a.out' header that we can modify for our own purposes + * (the 80960 is typically an embedded processor and may require + * enhanced linker support that the normal a.out.h header can't + * accommodate). + * + * As for byte-ordering, the following rules apply: + * + * o Text and data that is actually downloaded to the target is always + * in i80960 (little-endian) order. + * + * o All other numbers (in the header, symbols, relocation directives) + * are in host byte-order: object files CANNOT be lifted from a + * little-end host and used on a big-endian (or vice versa) without + * modification. + * ==> THIS IS NO LONGER TRUE USING BFD. WE CAN GENERATE ANY BYTE ORDER + * FOR THE HEADER, AND READ ANY BYTE ORDER. PREFERENCE WOULD BE TO + * USE LITTLE-ENDIAN BYTE ORDER THROUGHOUT, REGARDLESS OF HOST. <== + * + * o The downloader ('comm960') takes care to generate a pseudo-header + * with correct (i80960) byte-ordering before shipping text and data + * off to the NINDY monitor in the target systems. Symbols and + * relocation info are never sent to the target. + */ + + +#define BMAGIC 0415 +/* We don't accept the following (see N_BADMAG macro). + * They're just here so GNU code will compile. + */ +#define OMAGIC 0407 /* old impure format */ +#define NMAGIC 0410 /* read-only text */ +#define ZMAGIC 0413 /* demand load format */ + +/* FILE HEADER + * All 'lengths' are given as a number of bytes. + * All 'alignments' are for relinkable files only; an alignment of + * 'n' indicates the corresponding segment must begin at an + * address that is a multiple of (2**n). + */ +struct external_exec { + /* Standard stuff */ + unsigned char e_info[4]; /* Identifies this as a b.out file */ + unsigned char e_text[4]; /* Length of text */ + unsigned char e_data[4]; /* Length of data */ + unsigned char e_bss[4]; /* Length of uninitialized data area */ + unsigned char e_syms[4]; /* Length of symbol table */ + unsigned char e_entry[4]; /* Runtime start address */ + unsigned char e_trsize[4]; /* Length of text relocation info */ + unsigned char e_drsize[4]; /* Length of data relocation info */ + + /* Added for i960 */ + unsigned char e_tload[4]; /* Text runtime load address */ + unsigned char e_dload[4]; /* Data runtime load address */ + unsigned char e_talign[1]; /* Alignment of text segment */ + unsigned char e_dalign[1]; /* Alignment of data segment */ + unsigned char e_balign[1]; /* Alignment of bss segment */ + unsigned char e_relaxable[1]; /* Assembled with enough info to allow linker to relax */ +}; + +#define EXEC_BYTES_SIZE (sizeof (struct external_exec)) + +/* These macros use the a_xxx field names, since they operate on the exec + structure after it's been byte-swapped and realigned on the host machine. */ +#define N_BADMAG(x) (((x).a_info)!=BMAGIC) +#define N_TXTOFF(x) EXEC_BYTES_SIZE +#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) +#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data ) +#define N_TRELOFF N_TROFF +#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize ) +#define N_DRELOFF N_DROFF +#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize ) +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#define N_DATADDR(x) ( (x).a_dload ) + +/* Address of text segment in memory after it is loaded. */ +#if !defined (N_TXTADDR) +#define N_TXTADDR(x) 0 +#endif + +/* A single entry in the symbol table + */ +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; /* Index into string table */ + } n_un; + unsigned char n_type; /* See below */ + char n_other; /* Used in i80960 support -- see below */ + short n_desc; + unsigned long n_value; +}; + + +/* Legal values of n_type + */ +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol */ +#define N_TEXT 4 /* Text symbol */ +#define N_DATA 6 /* Data symbol */ +#define N_BSS 8 /* BSS symbol */ +#define N_FN 31 /* Filename symbol */ + +#define N_EXT 1 /* External symbol (OR'd in with one of above) */ +#define N_TYPE 036 /* Mask for all the type bits */ +#define N_STAB 0340 /* Mask for all bits used for SDB entries */ + +/* MEANING OF 'n_other' + * + * If non-zero, the 'n_other' fields indicates either a leaf procedure or + * a system procedure, as follows: + * + * 1 <= n_other <= 32 : + * The symbol is the entry point to a system procedure. + * 'n_value' is the address of the entry, as for any other + * procedure. The system procedure number (which can be used in + * a 'calls' instruction) is (n_other-1). These entries come from + * '.sysproc' directives. + * + * n_other == N_CALLNAME + * the symbol is the 'call' entry point to a leaf procedure. + * The *next* symbol in the symbol table must be the corresponding + * 'bal' entry point to the procedure (see following). These + * entries come from '.leafproc' directives in which two different + * symbols are specified (the first one is represented here). + * + * + * n_other == N_BALNAME + * the symbol is the 'bal' entry point to a leaf procedure. + * These entries result from '.leafproc' directives in which only + * one symbol is specified, or in which the same symbol is + * specified twice. + * + * Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry, + * but not every N_BALNAME entry must have an N_CALLNAME entry. + */ +#define N_CALLNAME ((char)-1) +#define N_BALNAME ((char)-2) +#define IS_CALLNAME(x) (N_CALLNAME == (x)) +#define IS_BALNAME(x) (N_BALNAME == (x)) +#define IS_OTHER(x) ((x)>0 && (x) <=32) + +#define b_out_relocation_info relocation_info +struct relocation_info { + int r_address; /* File address of item to be relocated */ + unsigned +#define r_index r_symbolnum + r_symbolnum:24,/* Index of symbol on which relocation is based, + * if r_extern is set. Otherwise set to + * either N_TEXT, N_DATA, or N_BSS to + * indicate section on which relocation is + * based. + */ + r_pcrel:1, /* 1 => relocate PC-relative; else absolute + * On i960, pc-relative implies 24-bit + * address, absolute implies 32-bit. + */ + r_length:2, /* Number of bytes to relocate: + * 0 => 1 byte + * 1 => 2 bytes -- used for 13 bit pcrel + * 2 => 4 bytes + */ + r_extern:1, + r_bsr:1, /* Something for the GNU NS32K assembler */ + r_disp:1, /* Something for the GNU NS32K assembler */ + r_callj:1, /* 1 if relocation target is an i960 'callj' */ + r_relaxable:1; /* 1 if enough info is left to relax + the data */ +}; diff --git a/contrib/gdb/include/coff/ChangeLog b/contrib/gdb/include/coff/ChangeLog new file mode 100644 index 000000000000..06c7f80f468a --- /dev/null +++ b/contrib/gdb/include/coff/ChangeLog @@ -0,0 +1,622 @@ +Thu Mar 14 15:22:44 1996 Jeffrey A Law (law@cygnus.com) + + * internal.h (R_MEM_INDIRECT): New reloc for the h8300. + +Fri Feb 9 10:44:11 1996 Ian Lance Taylor + + * aux-coff.h: Rename from aux.h, to avoid problems on hapless DOS + systems which think that aux is a com port. + +Mon Feb 5 18:35:00 1996 Ian Lance Taylor + + * i960.h (F_I960HX): Define. + +Wed Jan 31 13:11:54 1996 Richard Henderson + + * aux.h: New file. + * internal.h, m68k.h: Protect against multiple inclusion. + +Wed Nov 22 13:48:39 1995 Ian Lance Taylor + + * ecoff.h (_RCONST, STYP_RCONST, RELOC_SECTION_RCONST): Define. + (NUM_RELOC_SECTIONS): Update. + * symconst.h (scRConst): Define. + +Tue Nov 14 18:54:29 1995 Ian Lance Taylor + + * internal.h (C_NT_WEAK): Define. + +Thu Nov 9 14:08:30 1995 Ian Lance Taylor + + * rs6000.h (STYP_OVRFLO): Define. + +Tue Nov 7 14:38:45 1995 Kim Knuttila + + * coff/powerpc.h (IMAGE_NT_OPTIONAL_HDR_MAGIC): Added define. + * coff/pe.h: Added defines for file level flags + +Mon Nov 6 17:28:01 1995 Harry Dolan + + * i860.h: New file, based on i386.h. + +Wed Nov 1 15:25:18 1995 Manfred Hollstein KS/EF4A 60/1F/110 #40283 + + * m68k.h (PAGEMAGICEXECSWAPPED): Define. + (PAGEMAGICPEXECSWAPPED): Define. + (PAGEMAGICPEXECTSHLIB): Define. + (PAGEMAGICPEXECPAGED): Define. + (_COMMENT): DEFINE. + * m88k.h (_COMMENT): Define. + +Wed Oct 18 18:36:19 1995 Geoffrey Noer + + * sym.h: #if 0'd out runtime_pdr struct because it chokes + Visual C++ and there aren't any references to it elsewhere in gdb. + +Mon Oct 16 11:12:24 1995 Ian Lance Taylor + + * rs6000.h (SMALL_AOUTSZ): Define. + + * internal.h (XMC_TD): Define. + +Tue Oct 10 18:41:03 1995 Ian Lance Taylor + + * internal.h (struct internal_aouthdr): Add o_cputype field. + * rs6000.h (AOUTHDR): Rename o_resv1 to o_cputype. + +Mon Oct 9 14:45:46 1995 Ian Lance Taylor + + * rs6000.h (AOUTHDR): Add o_maxdata field. Add comments. + (_PAD, _LOADER): Define. + (STYP_LOADER): Define. + * internal.h (struct internal_aouthdr): Add o_maxdata field. + +Thu Oct 5 10:02:57 1995 Ian Lance Taylor + + * ecoff.h: Define section name macros and STYP macros for various + Alpha sections: .got, .hash, .dynsym, .dynstr, .rel.dyn, .conflic, + .comment, .liblist, .dynamic. + +Wed Oct 4 10:56:35 1995 Kim Knuttila + + * pe.h: Moved DOSMAGIC and NT_SIGNATURE defines here + * powerpc.h: removed DOSMAGIC, NT_SIGNATURE, and DEFAULT_* defines + Also removed other unused defines (various MAGIC ones) + * i386.h: removed DOSMAGIC, NT_SIGNATURE, and DEFAULT_* defines + * arm.h: removed DOSMAGIC, NT_SIGNATURE, and DEFAULT_* defines + * apollo.h: removed unused DEFAULT_* defines + * alpha.h: removed unused DEFAULT_* defines + * h8500.h: removed unused DEFAULT_* defines + * h8300.h: removed unused DEFAULT_* defines + * i960.h: removed unused DEFAULT_* defines + * m88k.h: removed unused DEFAULT_* defines + * we32k.h: removed unused DEFAULT_* defines + * rs6000.h: removed unused DEFAULT_* defines + * mips.h: removed unused DEFAULT_* defines + * m68k.h: removed unused DEFAULT_* defines + * z8k.h: removed unused DEFAULT_* defines + * w65.h: removed unused DEFAULT_* defines + * sparc.h: removed unused DEFAULT_* defines + * sh.h: removed unused DEFAULT_* defines + +Fri Sep 29 08:40:08 1995 Kim Knuttila + + * powerpc.h: Reformatted to GNU coding conventions. + +Wed Sep 27 06:50:50 1995 Kim Knuttila + + * pe.h: added defines for more section characteristics + * powerpc.h (new file): base coff definitions for ppc PE + +Tue Sep 12 12:08:20 1995 Ian Lance Taylor + + * internal.h (struct internal_syment): Change n_numaux field from + char to unsigned char. + +Fri Sep 1 15:39:36 1995 Kazumoto Kojima + + * mips.h (struct rpdr_ext): Define. + +Thu Aug 31 16:51:50 1995 steve chamberlain + + * internal.h (internal_aouthdr, internal_filehdr): + don't indirect the pe stuff. + +Tue Aug 29 14:16:07 1995 steve chamberlain + + * i386.h (NT_DEF_RESERVE, NT_DEF_COMMIT): Make the same + as 'the other' compiler. + * internal.h (NT_IMAGE_BASE): Deleted. + (NT_EXE_IMAGE_BASE, NT_DLL_IMAGE_BASE): New. + (PE_DEF_SECTION_ALIGNMENT, PE_DEF_FILE_ALIGNMENT): New. + (R_IMAGEBASE): New. + +Mon Aug 21 18:12:19 1995 steve chamberlain + + * internal.h: (internal_filehdr): Moved PE stuff into + internal_extra_pe_filehdr. + (internal_aouthdr): Moved PE stuff into + interanl_extra_pe_aouthdr. + +Mon Jul 24 14:05:39 1995 Ian Lance Taylor + + * internal.h: Move R_SH_* relocs from here... + * sh.h: ...to here. + (R_SH_SWITCH16, R_SH_SWITCH32): Define. + (R_SH_USES, R_SH_COUNT, R_SH_ALIGN): Define. + +Thu Jun 29 00:04:25 1995 Steve Chamberlain + + * internal.h (NT_DEF_RESERVE, NT_DEF_COMMIT): Increase a lot. + +Tue May 16 15:08:20 1995 Ken Raeburn + + * internal.h (NT_subsystem, NT_stack_heap): Delete + +Tue May 16 15:08:20 1995 Ken Raeburn + + * internal.h (NT_subsystem, NT_stack_heap): Now extern. + +Tue Feb 14 17:59:37 1995 Ian Lance Taylor + + * ecoff.h (struct ecoff_fdrtab_entry): Define. + (struct ecoff_find_line): Define. + +Sat Feb 4 14:38:03 1995 David Mosberger-Tang + + * sym.h (struct pdr): field "prof" added. + + * alpha.h (PDR_BITS1_PROF_*): added, macros for PDR_BITS*_RESERVED_* + updated accordingly. + +Sun Jan 15 18:38:33 1995 Steve Chamberlain + + * w65.h: New file. + +Wed Nov 23 22:43:38 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * sh.h (SH_ARCH_MAGIC_BIG, SH_ARCH_MAGIC_LITTLE): New. + (SHBADMAG): Changed to suit. + +Tue Jul 26 17:46:08 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i960.h (F_I960JX): New macro. + +Wed Jul 6 00:48:57 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha.h: Add definitions for alpha file header flags, encoding + the object type of the file. + +Mon Jun 20 13:47:01 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * ecoff.h (ecoff_swap_tir_in): Remove declaration. + (ecoff_swap_tir_out): Likewise. + (ecoff_swap_rndx_in, ecoff_swap_rndx_out): Likewise. + (struct ecoff_debug_swap): Add new fields: swap_tir_in, + swap_rndx_in, swap_tir_out, swap_rndx_out, read_debug_info. + +Sun Jun 12 03:51:52 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * symconst.h: Pick up SGI define for stIndirect. + +Fri Apr 22 13:05:28 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (REGINFO): Don't define. + (struct ecoff_reginfo): Don't define. + + * sh.h (SH_ARCH_MAGIC): Rename from SHMAGIC. SHMAGIC is used by + several targets to mean a shared library. + (SHBADMAG): Corresponding change. + +Thu Apr 14 13:00:53 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (RELOC_BITS3_TYPE_BIG): Changed from 0x1e to 0x3e. + (RELOC_BITS3_TYPEHI_LITTLE): Define. + (RELOC_BITS3_TYPEHI_SH_LITTLE): Define. + (MIPS_R_PCREL16): Change value from 8 to 12 to match Irix 4. + (MIPS_R_RELHI): Define. + (MIPS_R_RELLO): Define. + (MIPS_R_SWITCH): Change value from 9 to 22. + +Thu Apr 7 14:19:35 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (MIPS_R_SWITCH): Define. + +Thu Mar 31 19:28:33 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * internal.h (internal_aouthdr): Added comments for Apollo fields. + +Thu Mar 31 16:28:02 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (STYP_ECOFF_LIB): Define as used on Irix 4. + +Fri Mar 25 17:16:55 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (struct ecoff_debug_info): Add adjust field. + (struct ecoff_value_adjust): Define. + +Tue Mar 22 13:22:47 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (MIPS_R_PCREL16): Define. + +Sat Feb 26 10:26:38 1994 Ian Lance Taylor (ian@cygnus.com) + + * ecoff.h: Add casts to avoid warnings from SVR4 cc. + +Mon Feb 21 09:48:46 1994 Ian Lance Taylor (ian@lisa.cygnus.com) + + * sym.h (struct runtime_pdr): Make field adr bfd_vma, not unsigned + long. + (SYMR): Make field value bfd_vma, not long. + +Fri Feb 4 23:35:53 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * rs6000.h (STYP_DEBUG): Define. + +Wed Feb 2 14:31:37 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h (union internal_auxent): Change x_csect.x_scnlen into + a union of a long and a pointer to a symbol. XCOFF sometimes uses + this field as a symbol index. + +Mon Jan 10 23:54:25 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (ecoff_debug_info): Remove fields line_end, + external_dnr_end, external_pdr_end, external_sym_end, + external_opt_end, external_aux_end, ss_end, external_fdr_end. + Replace ifdbase with ifdmap. + +Wed Jan 5 17:05:36 1994 Ken Raeburn (raeburn@deneb.cygnus.com) + + * ecoff.h (STYP_EXTENDESC, STYP_COMMENT, STYP_XDATA, STYP_PDATA): + Define. + +Wed Jan 5 16:58:24 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (NUM_RELOC_SECTIONS): Define. + +Tue Dec 21 09:24:56 1993 Ken Raeburn (raeburn@rtl.cygnus.com) + + * sparc.h (struct external_reloc): Rename field r_addend to + r_offset. + +Sat Dec 11 16:12:32 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h (R_DISP7, R_SH_IMM16): New reloc types. + +Tue Nov 23 14:23:19 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (struct ecoff_debug_swap): Added *_end fields for all + the symbolic information pointers. + + * sym.h: Named the EXTR structure ecoff_extr. + +Fri Nov 19 08:21:18 1993 Ken Raeburn (raeburn@rover.cygnus.com) + + * sparc.h (RELSZ): Use correct size. + +Wed Nov 17 17:18:16 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (struct ecoff_debug_info): Define. + +Tue Nov 2 17:56:57 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (struct ecoff_debug_swap): Define. + +Thu Oct 28 17:07:50 1993 Stan Shebs (shebs@rtl.cygnus.com) + + * i386.h (I386LYNXMAGIC): Rename to LYNXCOFFMAGIC. + * m68k.h (LYNXCOFFMAGIC): Define. + * sparc.h: New file. + +Tue Oct 19 15:34:50 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * alpha.h (external_aouthdr): Split four byte padding field into + two byte bldrev field and two byte padding field. + + * ecoff.h (_LITA, _PDATA, _XDATA, STYP_LITA): Defined. + +Wed Oct 13 15:52:34 1993 Ken Raeburn (raeburn@cygnus.com) + + Sun Oct 10 17:27:10 1993 Troy Rollo (troy@cbme.unsw.edu.au) + + * coff/internal.h: Added o_sri, o_inlib and o_vid for Apollos + as well as R_DIR16. + + * coff/apollo.h: New file + +Mon Oct 11 17:16:48 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (REGINFO, struct ecoff_reginfo): Define. + +Tue Oct 5 10:52:53 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * rs6000.h: Change non-ASCII characters in comment to octal + escapes. + +Tue Sep 28 03:27:04 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * ecoff.h (_FINI, STYP_ECOFF_FINI): Add to support .fini section. + +Fri Sep 24 11:53:53 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (BADMAG): Recognize MIPS_MAGIC_LITTLE3 and MIPS_MAGIC_BIG3. + * ecoff.h: Define MIPS_MAGIC_LITTLE3 and MIPS_MAGIC_BIG3. + +Thu Sep 23 21:07:14 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * mips.h (BADMAG): Recognize MIPS_MAGIC_LITTLE2 and MIPS_MAGIC_BIG2. + * ecoff.h: Define MIPS_MAGIC_LITTLE2 and MIPS_MAGIC_BIG2. + +Thu Sep 16 20:27:21 1993 Jim Kingdon (kingdon@cirdan.cygnus.com) + + * sym.h, symconst.h: Add comment stating these files are not part + of GDB, GAS, etc. In 1991, when we asked rms whether we could + include these files in GDB (although they are copyrighted by + someone besides the FSF), he said it was OK if they were not + considered part of GDB. + +Fri Sep 10 17:40:35 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (AUX_PUT_ANY): Cast val argument to bfd_vma. + + * alpha.c (external_aouthdr): Need four bytes of padding between + vstamp and tsize. + +Tue Sep 7 14:20:43 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff.h (AUX_GET_ANY, AUX_PUT_ANY): Changed to reflect further + change in bfd swapping routine names. + +Tue Sep 7 10:15:17 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ecoff.h (AUX_GET_ANY): Change name of _do_getb32 to reflect bfd + changes. + +Fri Aug 13 14:30:32 1993 Ian Lance Taylor (ian@cygnus.com) + + * ecoff.h (RELOC_SECTION_NONE): Define. + +Thu Aug 12 11:24:42 1993 Ian Lance Taylor (ian@cygnus.com) + + * alpha.h (struct external_reloc): Add r_symndx field. + (RELSZ): Correct. + (RELOC_BITS*): Correct. + (ALPHA_R_*): Define. + * ecoff.h (RELOC_SECTION_{XDATA,PDATA,FINI,LITA,ABS}): Define. + (r_extern): Undefine. + * internal.h (struct internal_reloc): Make r_vaddr bfd_vma rather + than long. Add r_extern field. + + * alpha.h (PDR_BITS*): Define. + * sym.h (PDR): Give correct names to new fields. + + * ecoff.h: Moved MIPS reloc definitions from here... + * mips.h: to here. + +Tue Aug 3 11:17:53 1993 Ian Lance Taylor (ian@cygnus.com) + + * alpha.h: Corrected external symbolic debugging structures to + match actual usage. + * internal.h (internal_filehdr, internal_aouthdr, + internal_scnhdr): Changed type of some fields to bfd_vma so they + can hold 64 bits. + * sym.h (HDRR, FDR, PDR, EXTR): Likewise. + (PDR): Added new fields found on Alpha. + * symconst.h (magicSym2): Define; new value found on Alpha. + + * ecoff.h: New file. + * alpha.h, mips.h: Moved common information into ecoff.h. Moved + external structure definitions in from ecoff-ext.h. + * ecoff-ext.h: Removed; information now in alpha.h and mips.h. + +Sun Jul 18 21:43:59 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * i386.h: Recognize I386PTXMAGIC. + +Fri Jul 16 09:54:35 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (MIPS_AOUT_{OZ}MAGIC): Renamed from {OZ}MAGIC. + +Thu Jul 15 12:23:55 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m88k.h (union external_auxent): Move x_fcn back inside x_fcnary. + ({GET,PUT}_FCN_{LNNOPTR,ENDNDX}): Adjust accordingly. + +Sun Jul 11 18:00:18 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m68k.h: Define MC68KBCSMAGIC. + +Thu Jun 10 11:46:28 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (_INIT, STYP_MIPS_INIT): Define (used on Irix4). + (STYP_OTHER_LOAD): Define as STYP_MIPS_INIT. + +Wed Jun 9 15:09:09 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (OMAGIC): Define. + +Mon Apr 26 18:04:47 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h, sh.h: Support for SH. + +Sat Apr 24 21:34:59 1993 Jim Kingdon (kingdon@cygnus.com) + + * a29k.h: Define _LIT. + +Fri Apr 23 18:41:23 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * alpha.h: New file. + +Thu Apr 8 12:36:34 1993 Ian Lance Taylor (ian@cygnus.com) + + * internal.h (C_SHADOW, C_VERSION): Copied in from m88k.h. + * m88k.h, i386.h, we32k.h: Don't define all the storage classes; + they're already in internal.h. + +Wed Apr 7 11:51:24 1993 Jim Kingdon (kingdon@cygnus.com) + + * internal.h: Change n_sclass to unsigned char. + Change C_EFCN to 0xff, change RS/6000 dbx symbols + to no longer be signed. + +Fri Mar 19 14:52:56 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h: Add H8/500 reloc types. + +Wed Mar 17 09:46:03 1993 Ian Lance Taylor (ian@cygnus.com) + + * ecoff-ext.h (AUX_PUT_ANY): Don't use void values in branches of + conditional expression. + +Thu Mar 4 14:12:06 1993 Ian Lance Taylor (ian@cygnus.com) + + * ecoff-ext.h (AUX_GET_*): Rewrote to use new macro AUX_GET_ANY. + (AUX_PUT_*): New macros corresponding to the AUX_GET macros. + (ecoff_swap_tir_out): Added prototype. + + * mips.h (N_BTMASK, N_TMASK, N_BTSHFT, N_TSHIFT): Define; these + are needed to interpret gcc debugging output. + +Tue Feb 9 07:43:27 1993 Ian Lance Taylor (ian@cygnus.com) + + * we32k.h (BTYPE, ISPTR, ISFCN, ISARY, DECREF): Removed + more definitions duplicated in internal.h. + +Wed Feb 3 09:18:24 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (RELOC_BITS3_TYPE_*): Correct for big endian machines. + +Mon Jan 25 11:35:51 1993 Ian Lance Taylor (ian@cygnus.com) + + * internal.h (internal_aouthdr): Added additional fields used only + by MIPS ECOFF. + +Thu Jan 21 10:28:38 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h (AOUTHDR): Added additional fields used by ECOFF. + +Tue Jan 19 12:21:19 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i386.h, we32k.h (N_*, T_*, DT_*): Removed still more definitions + duplicated in internal.h. + + * mips.h (RELOC_SECTION_*, ECOFF_R_*): Defined constants for ECOFF + relocs. + +Fri Jan 15 18:17:00 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff-ext.h: Added prototypes for new ECOFF swapping functions. + (opt_ext): New structure. + * mips.h (ZMAGIC): Defined to be 0413. + (_LIB): Defined to be ".lib" + (external_reloc): MIPS ECOFF relocs are only 8 bytes. Added + macros to aid in swapping. + +Fri Jan 8 16:19:26 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ecoff-ext.h: Added prototypes for ECOFF swapping functions. + * internal.h (internal_scnhdr): Always provide s_align field, not + just on i960. + (internal_reloc): Always provide r_size field, not just on + RS/6000. + * mips.h (_RDATA, _SDATA, _SBSS, _LIT4, _LIT8, STYP_RDATA, + STYP_SDATA, STYP_SBSS, STYP_LIT4, STYP_LIT8): Defined. + (CODE_MASK, MIPS_IS_STAB, MIPS_MARK_STAB, MIPS_UNMARK_STAB, + STABS_SYMBOL): Moved in from gdb/mipsread.c. + +Wed Jan 6 14:01:46 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i386.h, we32k.h: removed STYP_* defines, since they duplicated + those in internal.h. + +Tue Dec 29 15:40:07 1992 Ian Lance Taylor (ian@cygnus.com) + + * i386.h: define I386AIXMAGIC for Danbury AIX PS/2 compiler. + +Sat Dec 12 16:07:57 1992 Ian Lance Taylor (ian@cygnus.com) + + * i386.h: don't define BTYPE, ISPTR, ISFCN, ISARY, DECREF: they + are defined in internal.h. + +Thu Nov 12 09:52:01 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h: (internal_reloc): r_offset is now a long. + * z8k.h: slight comment enhancement + +Wed Sep 30 07:46:08 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h: changed z8k reloc types + +Fri Aug 28 10:16:31 1992 Brendan Kehoe (brendan@cygnus.com) + + * we32k.h: new file + +Thu Aug 27 13:00:01 1992 Brendan Kehoe (brendan@cygnus.com) + + * symconst.h: comment out cruft at the end of #endif + +Tue Aug 25 15:06:49 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h: added #define for STYP_LIT, removed from a29k and + h8300. + + * z8k.h: added z8000 support + +Thu Jul 16 16:32:00 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * internal.h: added R_RELLONG_NEG reloc type + +Fri Jun 12 20:11:04 1992 John Gilmore (gnu at cygnus.com) + + * symconst.h: Fix unterminated comment. + +Wed Jun 10 07:57:49 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * i386.h: a.out magic numbers from + mohring@informatik.tu-muenchen.de + +Mon Jun 8 20:13:33 1992 John Gilmore (gnu at cygnus.com) + + * ecoff-ext.h, mips.h: Use unsigned chars everywhere. + (Suggested by Antti Miettinen.) + +Tue Apr 14 15:18:44 1992 John Gilmore (gnu at cygnus.com) + + * sym.h: Add comments. + * symconst.h: Merge with Fred's changes. + +Tue Apr 14 14:30:05 1992 Fred Fish (fnf@cygnus.com) + + * symconst.h: Pick up SGI defines for stStruct, stUnion, stEnum, + langCplusplus, and langCplusplusV2. + +Thu Apr 2 19:47:43 1992 John Gilmore (gnu at cygnus.com) + + * sym.h, symconst.h: MIPS has provided redistributable versions + of these files. Thanks! + * ecoff-ext.h: Add weakext bit to match new sym.h. + +Fri Mar 6 00:10:46 1992 John Gilmore (gnu at cygnus.com) + + * ecoff-ext.h: Add relative file descriptors. + +Thu Feb 27 11:53:04 1992 John Gilmore (gnu at cygnus.com) + + * ecoff-ext.h: New file for external (in-file) form of ecoff + symbol structures. + +Thu Feb 6 11:33:32 1992 Steve Chamberlain (sac at rtl.cygnus.com) + + * h8300.h: made the external_lineno l_lnno field 4 bytes wide. + andded GET/PUT_LINENO_LNNO macros + +Sat Nov 30 20:38:35 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * ChangeLog, a29k.h, h8300.h, i386.h, i960.h, internal.h, m68k.h, + m88k.h, mips.h, rs6000.h: move from above coff-.h + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/include/coff/a29k.h b/contrib/gdb/include/coff/a29k.h new file mode 100644 index 000000000000..13b35f251afd --- /dev/null +++ b/contrib/gdb/include/coff/a29k.h @@ -0,0 +1,305 @@ +/* COFF spec for AMD 290*0 + Contributed by David Wood @ New York University. + */ + +#ifndef AMD +# define AMD +#endif + +/****************************************************************/ + +/* +** File Header and related definitions +*/ + +struct external_filehdr +{ + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof (FILHDR) + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** Magic numbers for Am29000 +** (AT&T will assign the "real" magic number) +*/ + +#define SIPFBOMAGIC 0572 /* Am29000 (Byte 0 is MSB) */ +#define SIPRBOMAGIC 0573 /* Am29000 (Byte 0 is LSB) */ + + +#define A29K_MAGIC_BIG SIPFBOMAGIC +#define A29K_MAGIC_LITTLE SIPRBOMAGIC +#define A29KBADMAG(x) (((x).f_magic!=A29K_MAGIC_BIG) && \ + ((x).f_magic!=A29K_MAGIC_LITTLE)) + +#define OMAGIC A29K_MAGIC_BIG +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** File header flags currently known to us. +** +** Am29000 will use the F_AR32WR and F_AR32W flags to indicate +** the byte ordering in the file. +*/ + +/*--------------------------------------------------------------*/ + +/* +** Optional (a.out) header +*/ + +typedef struct external_aouthdr +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) +#define AOUTHDRSZ (sizeof(AOUTHDR)) + +/* aouthdr magic numbers */ +#define NMAGIC 0410 /* separate i/d executable */ +#define SHMAGIC 0406 /* NYU/Ultra3 shared data executable + (writable text) */ + +#define _ETEXT "_etext" + +/*--------------------------------------------------------------*/ + +/* +** Section header and related definitions +*/ + +struct external_scnhdr +{ + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof (SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _LIT ".lit" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** Section types - with additional section type for global +** registers which will be relocatable for the Am29000. +** +** In instances where it is necessary for a linker to produce an +** output file which contains text or data not based at virtual +** address 0, e.g. for a ROM, then the linker should accept +** address base information as command input and use PAD sections +** to skip over unused addresses. +*/ + +#define STYP_BSSREG 0x1200 /* Global register area (like STYP_INFO) */ +#define STYP_ENVIR 0x2200 /* Environment (like STYP_INFO) */ +#define STYP_ABS 0x4000 /* Absolute (allocated, not reloc, loaded) */ + +/*--------------------------------------------------------------*/ + +/* +** Relocation information declaration and related definitions +*/ + +struct external_reloc { + char r_vaddr[4]; /* (virtual) address of reference */ + char r_symndx[4]; /* index into symbol table */ + char r_type[2]; /* relocation type */ +}; + +#define RELOC struct external_reloc +#define RELSZ 10 /* sizeof (RELOC) */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** Relocation types for the Am29000 +*/ + +#define R_ABS 0 /* reference is absolute */ + +#define R_IREL 030 /* instruction relative (jmp/call) */ +#define R_IABS 031 /* instruction absolute (jmp/call) */ +#define R_ILOHALF 032 /* instruction low half (const) */ +#define R_IHIHALF 033 /* instruction high half (consth) part 1 */ +#define R_IHCONST 034 /* instruction high half (consth) part 2 */ + /* constant offset of R_IHIHALF relocation */ +#define R_BYTE 035 /* relocatable byte value */ +#define R_HWORD 036 /* relocatable halfword value */ +#define R_WORD 037 /* relocatable word value */ + +#define R_IGLBLRC 040 /* instruction global register RC */ +#define R_IGLBLRA 041 /* instruction global register RA */ +#define R_IGLBLRB 042 /* instruction global register RB */ + +/* +NOTE: +All the "I" forms refer to 29000 instruction formats. The linker is +expected to know how the numeric information is split and/or aligned +within the instruction word(s). R_BYTE works for instructions, too. + +If the parameter to a CONSTH instruction is a relocatable type, two +relocation records are written. The first has an r_type of R_IHIHALF +(33 octal) and a normal r_vaddr and r_symndx. The second relocation +record has an r_type of R_IHCONST (34 octal), a normal r_vaddr (which +is redundant), and an r_symndx containing the 32-bit constant offset +to the relocation instead of the actual symbol table index. This +second record is always written, even if the constant offset is zero. +The constant fields of the instruction are set to zero. +*/ + +/*--------------------------------------------------------------*/ + +/* +** Line number entry declaration and related definitions +*/ + +struct external_lineno +{ + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + +#define LINENO struct external_lineno +#define LINESZ 6 /* sizeof (LINENO) */ + +/*--------------------------------------------------------------*/ + +/* +** Symbol entry declaration and related definitions +*/ + +#define E_SYMNMLEN 8 /* Number of characters in a symbol name */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define SYMENT struct external_syment +#define SYMESZ sizeof(SYMENT) + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** Storage class definitions - new classes for global registers. +*/ + +#define C_GLBLREG 19 /* global register */ +#define C_EXTREG 20 /* external global register */ +#define C_DEFREG 21 /* ext. def. of global register */ + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* +** Derived symbol mask/shifts. +*/ + +#define N_BTMASK (0xf) +#define N_BTSHFT (4) +#define N_TMASK (0x30) +#define N_TSHIFT (2) + +/*--------------------------------------------------------------*/ + +/* +** Auxiliary symbol table entry declaration and related +** definitions. +*/ + +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ +}; + +#define AUXENT union external_auxent +#define AUXESZ 18 diff --git a/contrib/gdb/include/coff/alpha.h b/contrib/gdb/include/coff/alpha.h new file mode 100644 index 000000000000..1f1bfb6ccc7f --- /dev/null +++ b/contrib/gdb/include/coff/alpha.h @@ -0,0 +1,342 @@ +/* ECOFF support on Alpha machines. + coff/ecoff.h must be included before this file. */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + unsigned char f_magic[2]; /* magic number */ + unsigned char f_nscns[2]; /* number of sections */ + unsigned char f_timdat[4]; /* time & date stamp */ + unsigned char f_symptr[8]; /* file pointer to symtab */ + unsigned char f_nsyms[4]; /* number of symtab entries */ + unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ + unsigned char f_flags[2]; /* flags */ +}; + +/* Magic numbers are defined in coff/ecoff.h. */ +#define ALPHA_ECOFF_BADMAG(x) ((x).f_magic!=ALPHA_MAGIC) + +/* The object type is encoded in the f_flags. */ +#define F_ALPHA_OBJECT_TYPE_MASK 0x3000 +#define F_ALPHA_NO_SHARED 0x1000 +#define F_ALPHA_SHARABLE 0x2000 +#define F_ALPHA_CALL_SHARED 0x3000 + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct external_aouthdr +{ + unsigned char magic[2]; /* type of file */ + unsigned char vstamp[2]; /* version stamp */ + unsigned char bldrev[2]; /* ?? */ + unsigned char padding[2]; /* pad to quadword boundary */ + unsigned char tsize[8]; /* text size in bytes */ + unsigned char dsize[8]; /* initialized data " " */ + unsigned char bsize[8]; /* uninitialized data " " */ + unsigned char entry[8]; /* entry pt. */ + unsigned char text_start[8]; /* base of text used for this file */ + unsigned char data_start[8]; /* base of data used for this file */ + unsigned char bss_start[8]; /* base of bss used for this file */ + unsigned char gprmask[4]; /* bitmask of general registers used */ + unsigned char fprmask[4]; /* bitmask of floating point registers used */ + unsigned char gp_value[8]; /* value for gp register */ +} AOUTHDR; + +/* compute size of a header */ + +#define AOUTSZ (sizeof(AOUTHDR)) + +/********************** SECTION HEADER **********************/ + +struct external_scnhdr { + unsigned char s_name[8]; /* section name */ + unsigned char s_paddr[8]; /* physical address, aliased s_nlib */ + unsigned char s_vaddr[8]; /* virtual address */ + unsigned char s_size[8]; /* section size */ + unsigned char s_scnptr[8]; /* file ptr to raw data for section */ + unsigned char s_relptr[8]; /* file ptr to relocation */ + unsigned char s_lnnoptr[8]; /* file ptr to line numbers */ + unsigned char s_nreloc[2]; /* number of relocation entries */ + unsigned char s_nlnno[2]; /* number of line number entries*/ + unsigned char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + unsigned char r_vaddr[8]; + unsigned char r_symndx[4]; + unsigned char r_bits[4]; +}; + +#define RELOC struct external_reloc +#define RELSZ 16 + +/* Constants to unpack the r_bits field. The Alpha seems to always be + little endian, so I haven't bothered to define big endian variants + of these. */ + +#define RELOC_BITS0_TYPE_LITTLE 0xff +#define RELOC_BITS0_TYPE_SH_LITTLE 0 + +#define RELOC_BITS1_EXTERN_LITTLE 0x01 + +#define RELOC_BITS1_OFFSET_LITTLE 0x7e +#define RELOC_BITS1_OFFSET_SH_LITTLE 1 + +#define RELOC_BITS1_RESERVED_LITTLE 0x80 +#define RELOC_BITS1_RESERVED_SH_LITTLE 7 +#define RELOC_BITS2_RESERVED_LITTLE 0xff +#define RELOC_BITS2_RESERVED_SH_LEFT_LITTLE 1 +#define RELOC_BITS3_RESERVED_LITTLE 0x03 +#define RELOC_BITS3_RESERVED_SH_LEFT_LITTLE 9 + +#define RELOC_BITS3_SIZE_LITTLE 0xfc +#define RELOC_BITS3_SIZE_SH_LITTLE 2 + +/* The r_type field in a reloc is one of the following values. */ +#define ALPHA_R_IGNORE 0 +#define ALPHA_R_REFLONG 1 +#define ALPHA_R_REFQUAD 2 +#define ALPHA_R_GPREL32 3 +#define ALPHA_R_LITERAL 4 +#define ALPHA_R_LITUSE 5 +#define ALPHA_R_GPDISP 6 +#define ALPHA_R_BRADDR 7 +#define ALPHA_R_HINT 8 +#define ALPHA_R_SREL16 9 +#define ALPHA_R_SREL32 10 +#define ALPHA_R_SREL64 11 +#define ALPHA_R_OP_PUSH 12 +#define ALPHA_R_OP_STORE 13 +#define ALPHA_R_OP_PSUB 14 +#define ALPHA_R_OP_PRSHIFT 15 +#define ALPHA_R_GPVALUE 16 + +/********************** SYMBOLIC INFORMATION **********************/ + +/* Written by John Gilmore. */ + +/* ECOFF uses COFF-like section structures, but its own symbol format. + This file defines the symbol format in fields whose size and alignment + will not vary on different host systems. */ + +/* File header as a set of bytes */ + +struct hdr_ext { + unsigned char h_magic[2]; + unsigned char h_vstamp[2]; + unsigned char h_ilineMax[4]; + unsigned char h_idnMax[4]; + unsigned char h_ipdMax[4]; + unsigned char h_isymMax[4]; + unsigned char h_ioptMax[4]; + unsigned char h_iauxMax[4]; + unsigned char h_issMax[4]; + unsigned char h_issExtMax[4]; + unsigned char h_ifdMax[4]; + unsigned char h_crfd[4]; + unsigned char h_iextMax[4]; + unsigned char h_cbLine[8]; + unsigned char h_cbLineOffset[8]; + unsigned char h_cbDnOffset[8]; + unsigned char h_cbPdOffset[8]; + unsigned char h_cbSymOffset[8]; + unsigned char h_cbOptOffset[8]; + unsigned char h_cbAuxOffset[8]; + unsigned char h_cbSsOffset[8]; + unsigned char h_cbSsExtOffset[8]; + unsigned char h_cbFdOffset[8]; + unsigned char h_cbRfdOffset[8]; + unsigned char h_cbExtOffset[8]; +}; + +/* File descriptor external record */ + +struct fdr_ext { + unsigned char f_adr[8]; + unsigned char f_cbLineOffset[8]; + unsigned char f_cbLine[8]; + unsigned char f_cbSs[8]; + unsigned char f_rss[4]; + unsigned char f_issBase[4]; + unsigned char f_isymBase[4]; + unsigned char f_csym[4]; + unsigned char f_ilineBase[4]; + unsigned char f_cline[4]; + unsigned char f_ioptBase[4]; + unsigned char f_copt[4]; + unsigned char f_ipdFirst[4]; + unsigned char f_cpd[4]; + unsigned char f_iauxBase[4]; + unsigned char f_caux[4]; + unsigned char f_rfdBase[4]; + unsigned char f_crfd[4]; + unsigned char f_bits1[1]; + unsigned char f_bits2[3]; + unsigned char f_padding[4]; +}; + +#define FDR_BITS1_LANG_BIG 0xF8 +#define FDR_BITS1_LANG_SH_BIG 3 +#define FDR_BITS1_LANG_LITTLE 0x1F +#define FDR_BITS1_LANG_SH_LITTLE 0 + +#define FDR_BITS1_FMERGE_BIG 0x04 +#define FDR_BITS1_FMERGE_LITTLE 0x20 + +#define FDR_BITS1_FREADIN_BIG 0x02 +#define FDR_BITS1_FREADIN_LITTLE 0x40 + +#define FDR_BITS1_FBIGENDIAN_BIG 0x01 +#define FDR_BITS1_FBIGENDIAN_LITTLE 0x80 + +#define FDR_BITS2_GLEVEL_BIG 0xC0 +#define FDR_BITS2_GLEVEL_SH_BIG 6 +#define FDR_BITS2_GLEVEL_LITTLE 0x03 +#define FDR_BITS2_GLEVEL_SH_LITTLE 0 + +/* We ignore the `reserved' field in bits2. */ + +/* Procedure descriptor external record */ + +struct pdr_ext { + unsigned char p_adr[8]; + unsigned char p_cbLineOffset[8]; + unsigned char p_isym[4]; + unsigned char p_iline[4]; + unsigned char p_regmask[4]; + unsigned char p_regoffset[4]; + unsigned char p_iopt[4]; + unsigned char p_fregmask[4]; + unsigned char p_fregoffset[4]; + unsigned char p_frameoffset[4]; + unsigned char p_lnLow[4]; + unsigned char p_lnHigh[4]; + unsigned char p_gp_prologue[1]; + unsigned char p_bits1[1]; + unsigned char p_bits2[1]; + unsigned char p_localoff[1]; + unsigned char p_framereg[2]; + unsigned char p_pcreg[2]; +}; + +#define PDR_BITS1_GP_USED_BIG 0x80 +#define PDR_BITS1_REG_FRAME_BIG 0x40 +#define PDR_BITS1_PROF_BIG 0x20 +#define PDR_BITS1_RESERVED_BIG 0x1f +#define PDR_BITS1_RESERVED_SH_LEFT_BIG 8 +#define PDR_BITS2_RESERVED_BIG 0xff +#define PDR_BITS2_RESERVED_SH_BIG 0 + +#define PDR_BITS1_GP_USED_LITTLE 0x01 +#define PDR_BITS1_REG_FRAME_LITTLE 0x02 +#define PDR_BITS1_PROF_LITTLE 0x04 +#define PDR_BITS1_RESERVED_LITTLE 0xf8 +#define PDR_BITS1_RESERVED_SH_LITTLE 3 +#define PDR_BITS2_RESERVED_LITTLE 0xff +#define PDR_BITS2_RESERVED_SH_LEFT_LITTLE 5 + +/* Line numbers */ + +struct line_ext { + unsigned char l_line[4]; +}; + +/* Symbol external record */ + +struct sym_ext { + unsigned char s_value[8]; + unsigned char s_iss[4]; + unsigned char s_bits1[1]; + unsigned char s_bits2[1]; + unsigned char s_bits3[1]; + unsigned char s_bits4[1]; +}; + +#define SYM_BITS1_ST_BIG 0xFC +#define SYM_BITS1_ST_SH_BIG 2 +#define SYM_BITS1_ST_LITTLE 0x3F +#define SYM_BITS1_ST_SH_LITTLE 0 + +#define SYM_BITS1_SC_BIG 0x03 +#define SYM_BITS1_SC_SH_LEFT_BIG 3 +#define SYM_BITS1_SC_LITTLE 0xC0 +#define SYM_BITS1_SC_SH_LITTLE 6 + +#define SYM_BITS2_SC_BIG 0xE0 +#define SYM_BITS2_SC_SH_BIG 5 +#define SYM_BITS2_SC_LITTLE 0x07 +#define SYM_BITS2_SC_SH_LEFT_LITTLE 2 + +#define SYM_BITS2_RESERVED_BIG 0x10 +#define SYM_BITS2_RESERVED_LITTLE 0x08 + +#define SYM_BITS2_INDEX_BIG 0x0F +#define SYM_BITS2_INDEX_SH_LEFT_BIG 16 +#define SYM_BITS2_INDEX_LITTLE 0xF0 +#define SYM_BITS2_INDEX_SH_LITTLE 4 + +#define SYM_BITS3_INDEX_SH_LEFT_BIG 8 +#define SYM_BITS3_INDEX_SH_LEFT_LITTLE 4 + +#define SYM_BITS4_INDEX_SH_LEFT_BIG 0 +#define SYM_BITS4_INDEX_SH_LEFT_LITTLE 12 + +/* External symbol external record */ + +struct ext_ext { + struct sym_ext es_asym; + unsigned char es_bits1[1]; + unsigned char es_bits2[3]; + unsigned char es_ifd[4]; +}; + +#define EXT_BITS1_JMPTBL_BIG 0x80 +#define EXT_BITS1_JMPTBL_LITTLE 0x01 + +#define EXT_BITS1_COBOL_MAIN_BIG 0x40 +#define EXT_BITS1_COBOL_MAIN_LITTLE 0x02 + +#define EXT_BITS1_WEAKEXT_BIG 0x20 +#define EXT_BITS1_WEAKEXT_LITTLE 0x04 + +/* Dense numbers external record */ + +struct dnr_ext { + unsigned char d_rfd[4]; + unsigned char d_index[4]; +}; + +/* Relative file descriptor */ + +struct rfd_ext { + unsigned char rfd[4]; +}; + +/* Optimizer symbol external record */ + +struct opt_ext { + unsigned char o_bits1[1]; + unsigned char o_bits2[1]; + unsigned char o_bits3[1]; + unsigned char o_bits4[1]; + struct rndx_ext o_rndx; + unsigned char o_offset[4]; +}; + +#define OPT_BITS2_VALUE_SH_LEFT_BIG 16 +#define OPT_BITS2_VALUE_SH_LEFT_LITTLE 0 + +#define OPT_BITS3_VALUE_SH_LEFT_BIG 8 +#define OPT_BITS3_VALUE_SH_LEFT_LITTLE 8 + +#define OPT_BITS4_VALUE_SH_LEFT_BIG 0 +#define OPT_BITS4_VALUE_SH_LEFT_LITTLE 16 diff --git a/contrib/gdb/include/coff/apollo.h b/contrib/gdb/include/coff/apollo.h new file mode 100644 index 000000000000..c481d482e8bf --- /dev/null +++ b/contrib/gdb/include/coff/apollo.h @@ -0,0 +1,248 @@ +/*** coff information for Apollo M68K */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Motorola 68000/68008/68010/68020 */ +#define MC68MAGIC 0520 +#define MC68KWRMAGIC 0520 /* writeable text segments */ +#define MC68TVMAGIC 0521 +#define MC68KROMAGIC 0521 /* readonly shareable text segments */ +#define MC68KPGMAGIC 0522 /* demand paged text segments */ +#define M68MAGIC 0210 +#define M68TVMAGIC 0211 + +/* Apollo 68000-based machines have a different magic number. This comes + * from /usr/include/apollo/filehdr.h + */ +#define APOLLOM68KMAGIC 0627 + +#define OMAGIC M68MAGIC +#define M68KBADMAG(x) (((x).f_magic!=MC68MAGIC) && ((x).f_magic!=MC68KWRMAGIC) && ((x).f_magic!=MC68TVMAGIC) && \ + ((x).f_magic!=MC68KROMAGIC) && ((x).f_magic!=MC68KPGMAGIC) && ((x).f_magic!=M68MAGIC) && ((x).f_magic!=M68TVMAGIC) && \ + ((x).f_magic!=APOLLOM68KMAGIC) ) + + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ + char o_sri[4]; /* Apollo specific - .sri data pointer */ + char o_inlib[4]; /* Apollo specific - .inlib data pointer */ + char vid[8]; /* Apollo specific - 64 bit version ID */ +} +AOUTHDR; + +#define APOLLO_COFF_VERSION_NUMBER 1 /* the value of the aouthdr magic */ +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + +/********************** SECTION HEADER **********************/ + +struct external_scnhdr { + /* Apollo allow for larger section names by allowing it to be in + * the string table. + */ + char s_name[8]; + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* If s_zeores is all zeroes, s_offset gives the real location of the name + * in the string table. + */ + +#define s_zeroes section_name.s_name +#define s_offset (section_name.s_name+4) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _TV ".tv" +#define _INIT ".init" +#define _FINI ".fini" +#define _LINES ".lines" +#define _BLOCKS ".blocks" +#define _SRI ".sri" /* Static Resource Information (systype, + et al.) */ +#define _MIR ".mir" /* Module Information Records */ +#define _APTV ".aptv" /* Apollo-style transfer vectors. */ +#define _INLIB ".inlib" /* Shared Library information */ +#define _RWDI ".rwdi" /* Read/write data initialization directives for + compressed sections */ +#define _UNWIND ".unwind" /* Stack unwind information */ + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +#ifdef M68K_COFF_OFFSET + char r_offset[4]; +#endif + +}; + + +#define RELOC struct external_reloc + +#define RELSZ sizeof(struct external_reloc) + +/* Apollo specific STYP flags */ + +#define STYP_RELOCATED_NOT_LOADED 0x00010000 /* Section is relocated normally during linking, but need + not be loaded during program execution */ +#define STYP_DEBUG 0x00020000 /* debug section */ +#define STYP_OVERLAY 0x00040000 /* Section is overlayed */ +#define STYP_INSTRUCTION 0x00200000 /* Section contains executable code */ + +#define STYP_ZERO 0x00800000 /* Section is initialized to zero */ +#define STYP_INSTALLED 0x02000000 /* Section should be installable in KGT */ +#define STYP_LOOK_INSTALLED 0x04000000 /* Look for section in KGT */ +#define STYP_SECALIGN1 0x08000000 /* Specially aligned section */ +#define STYP_SECALIGN2 0x10000000 /* " " " */ +#define STYP_COMPRESSED 0x20000000 /* No section data per se (s_scnptr = 0), but there are + initialization directives for it in .rwdi section + (used in conjunction with STYP_BSS) */ diff --git a/contrib/gdb/include/coff/arm.h b/contrib/gdb/include/coff/arm.h new file mode 100644 index 000000000000..33b11cbb1de8 --- /dev/null +++ b/contrib/gdb/include/coff/arm.h @@ -0,0 +1,215 @@ +/*** coff information for the ARM */ + + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + + + +#define ARMMAGIC 0xa00 /* I just made these up */ + +#define ARMBADMAG(x) (((x).f_magic != ARMMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ + + +} +AOUTHDR; + + +#define AOUTSZ (sizeof(AOUTHDR)) + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC 0413 /* demand load format, eg normal ld output */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + + +/* define some NT default values */ +/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */ +#define NT_SECTION_ALIGNMENT 0x1000 +#define NT_FILE_ALIGNMENT 0x200 +#define NT_DEF_RESERVE 0x100000 +#define NT_DEF_COMMIT 0x1000 + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 6 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + +# define _ETEXT "etext" + + +/********************** RELOCATION DIRECTIVES **********************/ + + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; + char r_offset[4]; +}; + + +#define RELOC struct external_reloc +#define RELSZ sizeof (RELOC) diff --git a/contrib/gdb/include/coff/aux-coff.h b/contrib/gdb/include/coff/aux-coff.h new file mode 100644 index 000000000000..c89c124d3e05 --- /dev/null +++ b/contrib/gdb/include/coff/aux-coff.h @@ -0,0 +1,31 @@ +/* Modifications of internal.h and m68k.h needed by A/UX + Suggested by Ian Lance Taylor */ + +#ifndef GNU_COFF_AUX_H +#define GNU_COFF_AUX_H 1 + +#include "coff/internal.h" +#include "coff/m68k.h" + +/* Section contains 64-byte padded pathnames of shared libraries */ +#undef STYP_LIB +#define STYP_LIB 0x200 + +/* Section contains shared library initialization code */ +#undef STYP_INIT +#define STYP_INIT 0x400 + +/* Section contains .ident information */ +#undef STYP_IDENT +#define STYP_IDENT 0x800 + +/* Section types used by bfd and gas not defined (directly) by A/UX */ +#undef STYP_OVER +#define STYP_OVER 0 +#undef STYP_INFO +#define STYP_INFO STYP_IDENT + +/* Traditional name of the section tagged with STYP_LIB */ +#define _LIB ".lib" + +#endif /* GNU_COFF_AUX_H */ diff --git a/contrib/gdb/include/coff/ecoff.h b/contrib/gdb/include/coff/ecoff.h new file mode 100644 index 000000000000..120f88849e0e --- /dev/null +++ b/contrib/gdb/include/coff/ecoff.h @@ -0,0 +1,408 @@ +#ifndef ECOFF_H +#define ECOFF_H + +/* Generic ECOFF support. + This does not include symbol information, found in sym.h and + symconst.h. */ + +/* Mips magic numbers used in filehdr. MIPS_MAGIC_LITTLE is used on + little endian machines. MIPS_MAGIC_BIG is used on big endian + machines. Where is MIPS_MAGIC_1 from? */ +#define MIPS_MAGIC_1 0x0180 +#define MIPS_MAGIC_LITTLE 0x0162 +#define MIPS_MAGIC_BIG 0x0160 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 2. */ +#define MIPS_MAGIC_LITTLE2 0x0166 +#define MIPS_MAGIC_BIG2 0x0163 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 3. */ +#define MIPS_MAGIC_LITTLE3 0x142 +#define MIPS_MAGIC_BIG3 0x140 + +/* Alpha magic numbers used in filehdr. */ +#define ALPHA_MAGIC 0x183 + +/* Magic numbers used in a.out header. */ +#define ECOFF_AOUT_OMAGIC 0407 /* not demand paged (ld -N). */ +#define ECOFF_AOUT_ZMAGIC 0413 /* demand load format, eg normal ld output */ + +/* Names of special sections. */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _RDATA ".rdata" +#define _SDATA ".sdata" +#define _SBSS ".sbss" +#define _LITA ".lita" +#define _LIT4 ".lit4" +#define _LIT8 ".lit8" +#define _LIB ".lib" +#define _INIT ".init" +#define _FINI ".fini" +#define _PDATA ".pdata" +#define _XDATA ".xdata" +#define _GOT ".got" +#define _HASH ".hash" +#define _DYNSYM ".dynsym" +#define _DYNSTR ".dynstr" +#define _RELDYN ".rel.dyn" +#define _CONFLIC ".conflic" +#define _COMMENT ".comment" +#define _LIBLIST ".liblist" +#define _DYNAMIC ".dynamic" +#define _RCONST ".rconst" + +/* ECOFF uses some additional section flags. */ +#define STYP_RDATA 0x100 +#define STYP_SDATA 0x200 +#define STYP_SBSS 0x400 +#define STYP_GOT 0x1000 +#define STYP_DYNAMIC 0x2000 +#define STYP_DYNSYM 0x4000 +#define STYP_RELDYN 0x8000 +#define STYP_DYNSTR 0x10000 +#define STYP_HASH 0x20000 +#define STYP_LIBLIST 0x40000 +#define STYP_CONFLIC 0x100000 +#define STYP_ECOFF_FINI 0x1000000 +#define STYP_EXTENDESC 0x2000000 /* 0x02FFF000 bits => scn type, rest clr */ +#define STYP_LITA 0x4000000 +#define STYP_LIT8 0x8000000 +#define STYP_LIT4 0x10000000 +#define STYP_ECOFF_LIB 0x40000000 +#define STYP_ECOFF_INIT 0x80000000 +#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI) + +/* extended section types */ +#define STYP_COMMENT 0x2100000 +#define STYP_RCONST 0x2200000 +#define STYP_XDATA 0x2400000 +#define STYP_PDATA 0x2800000 + +/* The linker needs a section to hold small common variables while + linking. There is no convenient way to create it when the linker + needs it, so we always create one for each BFD. We then avoid + writing it out. */ +#define SCOMMON ".scommon" + +/* If the extern bit in a reloc is 1, then r_symndx is an index into + the external symbol table. If the extern bit is 0, then r_symndx + indicates a section, and is one of the following values. */ +#define RELOC_SECTION_NONE 0 +#define RELOC_SECTION_TEXT 1 +#define RELOC_SECTION_RDATA 2 +#define RELOC_SECTION_DATA 3 +#define RELOC_SECTION_SDATA 4 +#define RELOC_SECTION_SBSS 5 +#define RELOC_SECTION_BSS 6 +#define RELOC_SECTION_INIT 7 +#define RELOC_SECTION_LIT8 8 +#define RELOC_SECTION_LIT4 9 +#define RELOC_SECTION_XDATA 10 +#define RELOC_SECTION_PDATA 11 +#define RELOC_SECTION_FINI 12 +#define RELOC_SECTION_LITA 13 +#define RELOC_SECTION_ABS 14 +#define RELOC_SECTION_RCONST 15 + +#define NUM_RELOC_SECTIONS 16 + +/********************** STABS **********************/ + +/* gcc uses mips-tfile to output type information in special stabs + entries. These must match the corresponding definition in + gcc/config/mips.h. At some point, these should probably go into a + shared include file, but currently gcc and gdb do not share any + directories. */ +#define CODE_MASK 0x8F300 +#define ECOFF_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK) +#define ECOFF_MARK_STAB(code) ((code)+CODE_MASK) +#define ECOFF_UNMARK_STAB(code) ((code)-CODE_MASK) +#define STABS_SYMBOL "@stabs" + +/********************** COFF **********************/ + +/* gcc also uses mips-tfile to output COFF debugging information. + These are the values it uses when outputting the .type directive. + These should also be in a shared include file. */ +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +/********************** AUX **********************/ + +/* The auxiliary type information is the same on all known ECOFF + targets. I can't see any reason that it would ever change, so I am + going to gamble and define the external structures here, in the + target independent ECOFF header file. The internal forms are + defined in coff/sym.h, which was originally donated by MIPS + Computer Systems. */ + +/* Type information external record */ + +struct tir_ext { + unsigned char t_bits1[1]; + unsigned char t_tq45[1]; + unsigned char t_tq01[1]; + unsigned char t_tq23[1]; +}; + +#define TIR_BITS1_FBITFIELD_BIG ((unsigned int) 0x80) +#define TIR_BITS1_FBITFIELD_LITTLE ((unsigned int) 0x01) + +#define TIR_BITS1_CONTINUED_BIG ((unsigned int) 0x40) +#define TIR_BITS1_CONTINUED_LITTLE ((unsigned int) 0x02) + +#define TIR_BITS1_BT_BIG ((unsigned int) 0x3F) +#define TIR_BITS1_BT_SH_BIG 0 +#define TIR_BITS1_BT_LITTLE ((unsigned int) 0xFC) +#define TIR_BITS1_BT_SH_LITTLE 2 + +#define TIR_BITS_TQ4_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ4_SH_BIG 4 +#define TIR_BITS_TQ5_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ5_SH_BIG 0 +#define TIR_BITS_TQ4_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ4_SH_LITTLE 0 +#define TIR_BITS_TQ5_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ5_SH_LITTLE 4 + +#define TIR_BITS_TQ0_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ0_SH_BIG 4 +#define TIR_BITS_TQ1_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ1_SH_BIG 0 +#define TIR_BITS_TQ0_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ0_SH_LITTLE 0 +#define TIR_BITS_TQ1_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ1_SH_LITTLE 4 + +#define TIR_BITS_TQ2_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ2_SH_BIG 4 +#define TIR_BITS_TQ3_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ3_SH_BIG 0 +#define TIR_BITS_TQ2_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ2_SH_LITTLE 0 +#define TIR_BITS_TQ3_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ3_SH_LITTLE 4 + +/* Relative symbol external record */ + +struct rndx_ext { + unsigned char r_bits[4]; +}; + +#define RNDX_BITS0_RFD_SH_LEFT_BIG 4 +#define RNDX_BITS1_RFD_BIG ((unsigned int) 0xF0) +#define RNDX_BITS1_RFD_SH_BIG 4 + +#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0 +#define RNDX_BITS1_RFD_LITTLE ((unsigned int) 0x0F) +#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8 + +#define RNDX_BITS1_INDEX_BIG ((unsigned int) 0x0F) +#define RNDX_BITS1_INDEX_SH_LEFT_BIG 16 +#define RNDX_BITS2_INDEX_SH_LEFT_BIG 8 +#define RNDX_BITS3_INDEX_SH_LEFT_BIG 0 + +#define RNDX_BITS1_INDEX_LITTLE ((unsigned int) 0xF0) +#define RNDX_BITS1_INDEX_SH_LITTLE 4 +#define RNDX_BITS2_INDEX_SH_LEFT_LITTLE 4 +#define RNDX_BITS3_INDEX_SH_LEFT_LITTLE 12 + +/* Auxiliary symbol information external record */ + +union aux_ext { + struct tir_ext a_ti; + struct rndx_ext a_rndx; + unsigned char a_dnLow[4]; + unsigned char a_dnHigh[4]; + unsigned char a_isym[4]; + unsigned char a_iss[4]; + unsigned char a_width[4]; + unsigned char a_count[4]; +}; + +#define AUX_GET_ANY(bigend, ax, field) \ + ((bigend) ? bfd_getb32 ((ax)->field) : bfd_getl32 ((ax)->field)) + +#define AUX_GET_DNLOW(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnLow) +#define AUX_GET_DNHIGH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnHigh) +#define AUX_GET_ISYM(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_isym) +#define AUX_GET_ISS(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_iss) +#define AUX_GET_WIDTH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_width) +#define AUX_GET_COUNT(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_count) + +#define AUX_PUT_ANY(bigend, val, ax, field) \ + ((bigend) \ + ? (bfd_putb32 ((bfd_vma) (val), (ax)->field), 0) \ + : (bfd_putl32 ((bfd_vma) (val), (ax)->field), 0)) + +#define AUX_PUT_DNLOW(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnLow) +#define AUX_PUT_DNHIGH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnHigh) +#define AUX_PUT_ISYM(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_isym) +#define AUX_PUT_ISS(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_iss) +#define AUX_PUT_WIDTH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_width) +#define AUX_PUT_COUNT(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_count) + +/********************** SYMBOLS **********************/ + +/* For efficiency, gdb deals directly with the unswapped symbolic + information (that way it only takes the time to swap information + that it really needs to read). gdb originally retrieved the + information directly from the BFD backend information, but that + strategy, besides being sort of ugly, does not work for MIPS ELF, + which also uses ECOFF debugging information. This structure holds + pointers to the (mostly) unswapped symbolic information. */ + +struct ecoff_debug_info +{ + /* The swapped ECOFF symbolic header. */ + HDRR symbolic_header; + + /* Pointers to the unswapped symbolic information. Note that the + pointers to external structures point to different sorts of + information on different ECOFF targets. The ecoff_debug_swap + structure provides the sizes of the structures and the functions + needed to swap the information in and out. These pointers are + all pointers to arrays, not single structures. They will be NULL + if there are no instances of the relevant structure. These + fields are also used by the assembler to output ECOFF debugging + information. */ + unsigned char *line; + PTR external_dnr; /* struct dnr_ext */ + PTR external_pdr; /* struct pdr_ext */ + PTR external_sym; /* struct sym_ext */ + PTR external_opt; /* struct opt_ext */ + union aux_ext *external_aux; + char *ss; + char *ssext; + PTR external_fdr; /* struct fdr_ext */ + PTR external_rfd; /* struct rfd_ext */ + PTR external_ext; /* struct ext_ext */ + + /* These fields are used when linking. They may disappear at some + point. */ + char *ssext_end; + PTR external_ext_end; + + /* When linking, this field holds a mapping from the input FDR + numbers to the output numbers, and is used when writing out the + external symbols. It is NULL if no mapping is required. */ + RFDT *ifdmap; + + /* The swapped FDR information. Currently this is never NULL, but + code using this structure should probably double-check in case + this changes in the future. This is a pointer to an array, not a + single structure. */ + FDR *fdr; + + /* When relaxing MIPS embedded PIC code, we may need to adjust + symbol values when they are output. This is a linked list of + structures indicating how values should be adjusted. There is no + requirement that the entries be in any order, or that they not + overlap. This field is normally NULL, in which case no + adjustments need to be made. */ + struct ecoff_value_adjust *adjust; +}; + +/* This structure describes how to adjust symbol values when + outputting MIPS embedded PIC code. These adjustments only apply to + the internal symbols, as the external symbol values will come from + the hash table and have already been adjusted. */ + +struct ecoff_value_adjust +{ + /* Next entry on adjustment list. */ + struct ecoff_value_adjust *next; + /* Starting VMA of adjustment. This is the VMA in the ECOFF file, + not the offset from the start of the section. Thus it should + indicate a particular section. */ + bfd_vma start; + /* Ending VMA of adjustment. */ + bfd_vma end; + /* Adjustment. This should be added to the value of the symbol, or + FDR. This is zero for the last entry in the array. */ + long adjust; +}; + +/* These structures are used by the ECOFF find_nearest_line function. */ + +struct ecoff_fdrtab_entry +{ + /* Base address in .text of this FDR. */ + bfd_vma base_addr; + FDR *fdr; +}; + +struct ecoff_find_line +{ + /* Allocated memory to hold function and file names. */ + char *find_buffer; + + /* FDR table, sorted by address: */ + long fdrtab_len; + struct ecoff_fdrtab_entry *fdrtab; +}; + +/********************** SWAPPING **********************/ + +/* The generic ECOFF code needs to be able to swap debugging + information in and out in the specific format used by a particular + ECOFF implementation. This structure provides the information + needed to do this. */ + +struct ecoff_debug_swap +{ + /* Symbol table magic number. */ + int sym_magic; + /* Alignment of debugging information. E.g., 4. */ + bfd_size_type debug_align; + /* Sizes of external symbolic information. */ + bfd_size_type external_hdr_size; + bfd_size_type external_dnr_size; + bfd_size_type external_pdr_size; + bfd_size_type external_sym_size; + bfd_size_type external_opt_size; + bfd_size_type external_fdr_size; + bfd_size_type external_rfd_size; + bfd_size_type external_ext_size; + /* Functions to swap in external symbolic data. */ + void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *)); + void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *)); + void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *)); + void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)); + void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)); + void (*swap_tir_in) PARAMS ((int, const struct tir_ext *, TIR *)); + void (*swap_rndx_in) PARAMS ((int, const struct rndx_ext *, RNDXR *)); + /* Functions to swap out external symbolic data. */ + void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR)); + void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR)); + void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)); + void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)); + void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR)); + void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)); + void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)); + void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)); + void (*swap_tir_out) PARAMS ((int, const TIR *, struct tir_ext *)); + void (*swap_rndx_out) PARAMS ((int, const RNDXR *, struct rndx_ext *)); + /* Function to read symbol data and set up pointers in + ecoff_debug_info structure. The section argument is used for + ELF, not straight ECOFF. */ + boolean (*read_debug_info) PARAMS ((bfd *, asection *, + struct ecoff_debug_info *)); +}; + +#endif /* ! defined (ECOFF_H) */ diff --git a/contrib/gdb/include/coff/h8300.h b/contrib/gdb/include/coff/h8300.h new file mode 100644 index 000000000000..8fe8f6165fed --- /dev/null +++ b/contrib/gdb/include/coff/h8300.h @@ -0,0 +1,203 @@ +/*** coff information for Hitachi H8/300 and H8/300-H */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + + +#define H8300MAGIC 0x8300 +#define H8300HMAGIC 0x8301 + + +#define H8300BADMAG(x) (((x).f_magic!=H8300MAGIC)) +#define H8300HBADMAG(x) (((x).f_magic!=H8300HMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[4]; /* line number */ +}; + +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)); +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + +/* The external reloc has an offset field, because some of the reloc + types on the h8 don't have room in the instruction for the entire + offset - eg the strange jump and high page addressing modes */ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_offset[4]; + char r_type[2]; + char r_stuff[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 16 + + + + diff --git a/contrib/gdb/include/coff/h8500.h b/contrib/gdb/include/coff/h8500.h new file mode 100644 index 000000000000..5a8c9feace90 --- /dev/null +++ b/contrib/gdb/include/coff/h8500.h @@ -0,0 +1,201 @@ +/*** coff information for Hitachi H8/500 */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + + +#define H8500MAGIC 0x8500 + + +#define H8500BADMAG(x) ((0xffff && ((x).f_magic)!=H8500MAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[4]; /* line number */ +}; + +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)); +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + +/* The external reloc has an offset field, because some of the reloc + types on the h8 don't have room in the instruction for the entire + offset - eg the strange jump and high page addressing modes */ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_offset[4]; + char r_type[2]; + char r_stuff[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 16 + + + + diff --git a/contrib/gdb/include/coff/i386.h b/contrib/gdb/include/coff/i386.h new file mode 100644 index 000000000000..b7ecf0b6e140 --- /dev/null +++ b/contrib/gdb/include/coff/i386.h @@ -0,0 +1,224 @@ +/*** coff information for Intel 386/486. */ + + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + + + +#define I386MAGIC 0x14c +#define I386PTXMAGIC 0x154 +#define I386AIXMAGIC 0x175 + +/* This is Lynx's all-platform magic number for executables. */ + +#define LYNXCOFFMAGIC 0415 + +#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \ + && (x).f_magic != I386AIXMAGIC \ + && (x).f_magic != I386PTXMAGIC \ + && (x).f_magic != LYNXCOFFMAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ + + +} +AOUTHDR; + + +#define AOUTSZ (sizeof(AOUTHDR)) + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC 0413 /* demand load format, eg normal ld output */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + + +/* define some NT default values */ +/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */ +#define NT_SECTION_ALIGNMENT 0x1000 +#define NT_FILE_ALIGNMENT 0x200 +#define NT_DEF_RESERVE 0x100000 +#define NT_DEF_COMMIT 0x1000 + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 6 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + +# define _ETEXT "etext" + + +/********************** RELOCATION DIRECTIVES **********************/ + + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 10 + diff --git a/contrib/gdb/include/coff/i860.h b/contrib/gdb/include/coff/i860.h new file mode 100644 index 000000000000..e09ec5f0e51b --- /dev/null +++ b/contrib/gdb/include/coff/i860.h @@ -0,0 +1,204 @@ +/* This file was hacked from i386.h [dolan@ssd.intel.com] */ + +/*** coff information for Intel 860. */ + + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + + + +#define I860MAGIC 0x14d + +#define I860BADMAG(x) ((x).f_magic != I860MAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTSZ (sizeof(AOUTHDR)) + +/* FIXME: What are the a.out magic numbers? */ + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 6 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + +# define _ETEXT "etext" + + +/********************** RELOCATION DIRECTIVES **********************/ + + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 10 diff --git a/contrib/gdb/include/coff/i960.h b/contrib/gdb/include/coff/i960.h new file mode 100644 index 000000000000..c20893c94781 --- /dev/null +++ b/contrib/gdb/include/coff/i960.h @@ -0,0 +1,251 @@ +/*** coff information for 80960. Origins: Intel corp, natch. */ + +/* NOTE: Tagentries (cf TAGBITS) are no longer used by the 960 */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +#define OMAGIC (0407) /* old impure format. data immediately + follows text. both sections are rw. */ +#define NMAGIC (0410) /* split i&d, read-only text */ + +/* +* Intel 80960 (I960) processor flags. +* F_I960TYPE == mask for processor type field. +*/ + +#define F_I960TYPE (0xf000) +#define F_I960CORE (0x1000) +#define F_I960KB (0x2000) +#define F_I960SB (0x2000) +#define F_I960MC (0x3000) +#define F_I960XA (0x4000) +#define F_I960CA (0x5000) +#define F_I960KA (0x6000) +#define F_I960SA (0x6000) +#define F_I960JX (0x7000) +#define F_I960HX (0x8000) + + +/** i80960 Magic Numbers +*/ + +#define I960ROMAGIC (0x160) /* read-only text segments */ +#define I960RWMAGIC (0x161) /* read-write text segments */ + +#define I960BADMAG(x) (((x).f_magic!=I960ROMAGIC) && ((x).f_magic!=I960RWMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ 20 + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +typedef struct { + unsigned long phys_addr; + unsigned long bitarray; +} TAGBITS; + + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ + char tagentries[4]; /* number of tag entries to follow */ +} +AOUTHDR; + +/* return a pointer to the tag bits array */ + +#define TAGPTR(aout) ((TAGBITS *) (&(aout.tagentries)+1)) + +/* compute size of a header */ + +/*#define AOUTSZ(aout) (sizeof(AOUTHDR)+(aout.tagentries*sizeof(TAGBITS)))*/ +#define AOUTSZ (sizeof(AOUTHDR)) + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ + char s_align[4]; /* section alignment */ +}; + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ + char padding[2]; /* force alignment */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 8 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_flags[2]; + char e_type[4]; + char e_sclass[1]; + char e_numaux[1]; + char pad2[2]; +}; + + + + +#define N_BTMASK (0x1f) +#define N_TMASK (0x60) +#define N_BTSHFT (5) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + /****************************************** + * I960-specific *2nd* aux. entry formats + ******************************************/ + struct { + /* This is a very old typo that keeps getting propagated. */ +#define x_stdindx x_stindx + char x_stindx[4]; /* sys. table entry */ + } x_sc; /* system call entry */ + + struct { + char x_balntry[4]; /* BAL entry point */ + } x_bal; /* BAL-callable function */ + + struct { + char x_timestamp[4]; /* time stamp */ + char x_idstring[20]; /* producer identity string */ + } x_ident; /* Producer ident info */ + +}; + + + +#define SYMENT struct external_syment +#define SYMESZ sizeof(SYMENT) /* FIXME - calc by hand */ +#define AUXENT union external_auxent +#define AUXESZ sizeof(AUXENT) /* FIXME - calc by hand */ + +# define _ETEXT "_etext" + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; + char pad[2]; +}; + + +/* Relevent values for r_type and i960. Would someone please document them */ + + +#define RELOC struct external_reloc +#define RELSZ 12 + diff --git a/contrib/gdb/include/coff/internal.h b/contrib/gdb/include/coff/internal.h new file mode 100644 index 000000000000..b43cf766421c --- /dev/null +++ b/contrib/gdb/include/coff/internal.h @@ -0,0 +1,648 @@ +/* Internal format of COFF object file data structures, for GNU BFD. + This file is part of BFD, the Binary File Descriptor library. */ + +#ifndef GNU_COFF_INTERNAL_H +#define GNU_COFF_INTERNAL_H 1 + +/* First, make "signed char" work, even on old compilers. */ +#ifndef signed +#ifndef __STDC__ +#define signed /**/ +#endif +#endif + +/********************** FILE HEADER **********************/ + +/* extra stuff in a PE header. */ + +struct internal_extra_pe_filehdr +{ + /* DOS header data follows for PE stuff */ + unsigned short e_magic; /* Magic number, 0x5a4d */ + unsigned short e_cblp; /* Bytes on last page of file, 0x90 */ + unsigned short e_cp; /* Pages in file, 0x3 */ + unsigned short e_crlc; /* Relocations, 0x0 */ + unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */ + unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */ + unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */ + unsigned short e_ss; /* Initial (relative) SS value, 0x0 */ + unsigned short e_sp; /* Initial SP value, 0xb8 */ + unsigned short e_csum; /* Checksum, 0x0 */ + unsigned short e_ip; /* Initial IP value, 0x0 */ + unsigned short e_cs; /* Initial (relative) CS value, 0x0 */ + unsigned short e_lfarlc; /* File address of relocation table, 0x40 */ + unsigned short e_ovno; /* Overlay number, 0x0 */ + unsigned short e_res[4]; /* Reserved words, all 0x0 */ + unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */ + unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */ + unsigned short e_res2[10]; /* Reserved words, all 0x0 */ + bfd_vma e_lfanew; /* File address of new exe header, 0x80 */ + unsigned long dos_message[16]; /* text which always follows dos header */ + bfd_vma nt_signature; /* required NT signature, 0x4550 */ +}; + +struct internal_filehdr +{ + struct internal_extra_pe_filehdr pe; + + /* standard coff internal info */ + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + bfd_vma f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR16WR file is 16-bit little-endian + * F_AR32WR file is 32-bit little-endian + * F_AR32W file is 32-bit big-endian + * F_DYNLOAD rs/6000 aix: dynamically loadable w/imports & exports + * F_SHROBJ rs/6000 aix: file is a shared object + * F_DLL PE format DLL + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) +#define F_AR16WR (0x0080) +#define F_AR32WR (0x0100) +#define F_AR32W (0x0200) +#define F_DYNLOAD (0x1000) +#define F_SHROBJ (0x2000) +#define F_DLL (0x2000) + +/* extra structure which is used in the optional header */ +typedef struct _IMAGE_DATA_DIRECTORY +{ + bfd_vma VirtualAddress; + long Size; +} IMAGE_DATA_DIRECTORY; +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +/* default image base for NT */ +#define NT_EXE_IMAGE_BASE 0x400000 +#define NT_DLL_IMAGE_BASE 0x10000000 + +/* Extra stuff in a PE aouthdr */ + +#define PE_DEF_SECTION_ALIGNMENT 0x1000 +#define PE_DEF_FILE_ALIGNMENT 0x200 + +struct internal_extra_pe_aouthdr +{ + /* PE stuff */ + bfd_vma ImageBase; /* address of specific location in memory that + file is located, NT default 0x10000 */ + + bfd_vma SectionAlignment; /* section alignment default 0x1000 */ + bfd_vma FileAlignment; /* file alignment default 0x200 */ + short MajorOperatingSystemVersion; /* minimum version of the operating */ + short MinorOperatingSystemVersion; /* system req'd for exe, default to 1*/ + short MajorImageVersion; /* user defineable field to store version of */ + short MinorImageVersion; /* exe or dll being created, default to 0 */ + short MajorSubsystemVersion; /* minimum subsystem version required to */ + short MinorSubsystemVersion; /* run exe; default to 3.1 */ + long Reserved1; /* seems to be 0 */ + long SizeOfImage; /* size of memory to allocate for prog */ + long SizeOfHeaders; /* size of PE header and section table */ + long CheckSum; /* set to 0 */ + short Subsystem; + + /* type of subsystem exe uses for user interface, + possible values: + 1 - NATIVE Doesn't require a subsystem + 2 - WINDOWS_GUI runs in Windows GUI subsystem + 3 - WINDOWS_CUI runs in Windows char sub. (console app) + 5 - OS2_CUI runs in OS/2 character subsystem + 7 - POSIX_CUI runs in Posix character subsystem */ + short DllCharacteristics; /* flags for DLL init, use 0 */ + bfd_vma SizeOfStackReserve; /* amount of memory to reserve */ + bfd_vma SizeOfStackCommit; /* amount of memory initially committed for + initial thread's stack, default is 0x1000 */ + bfd_vma SizeOfHeapReserve; /* amount of virtual memory to reserve and */ + bfd_vma SizeOfHeapCommit; /* commit, don't know what to defaut it to */ + long LoaderFlags; /* can probably set to 0 */ + long NumberOfRvaAndSizes; /* number of entries in next entry, 16 */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +}; + +/********************** AOUT "OPTIONAL HEADER" **********************/ +struct internal_aouthdr +{ + short magic; /* type of file */ + short vstamp; /* version stamp */ + bfd_vma tsize; /* text size in bytes, padded to FW bdry*/ + bfd_vma dsize; /* initialized data " " */ + bfd_vma bsize; /* uninitialized data " " */ + bfd_vma entry; /* entry pt. */ + bfd_vma text_start; /* base of text used for this file */ + bfd_vma data_start; /* base of data used for this file */ + + /* i960 stuff */ + unsigned long tagentries; /* number of tag entries to follow */ + + /* RS/6000 stuff */ + unsigned long o_toc; /* address of TOC */ + short o_snentry; /* section number for entry point */ + short o_sntext; /* section number for text */ + short o_sndata; /* section number for data */ + short o_sntoc; /* section number for toc */ + short o_snloader; /* section number for loader section */ + short o_snbss; /* section number for bss */ + short o_algntext; /* max alignment for text */ + short o_algndata; /* max alignment for data */ + short o_modtype; /* Module type field, 1R,RE,RO */ + short o_cputype; /* Encoded CPU type */ + unsigned long o_maxstack; /* max stack size allowed. */ + unsigned long o_maxdata; /* max data size allowed. */ + + /* ECOFF stuff */ + bfd_vma bss_start; /* Base of bss section. */ + bfd_vma gp_value; /* GP register value. */ + unsigned long gprmask; /* General registers used. */ + unsigned long cprmask[4]; /* Coprocessor registers used. */ + unsigned long fprmask; /* Floating pointer registers used. */ + + /* Apollo stuff */ + long o_inlib; /* inlib data */ + long o_sri; /* Static Resource Information */ + long vid[2]; /* Version id */ + + + struct internal_extra_pe_aouthdr pe; + +}; + +/********************** STORAGE CLASSES **********************/ + +/* This used to be defined as -1, but now n_sclass is unsigned. */ +#define C_EFCN 0xff /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib */ + +/* New storage classes for WINDOWS_NT */ +#define C_SECTION 104 /* section name */ +#define C_NT_WEAK 105 /* weak external */ + + /* New storage classes for 80960 */ + +/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */ +#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */ + +#define C_SCALL 107 /* Procedure reachable via system call */ +#define C_LEAFEXT 108 /* External leaf */ +#define C_LEAFSTAT 113 /* Static leaf */ +#define C_OPTVAR 109 /* Optimized variable */ +#define C_DEFINE 110 /* Preprocessor #define */ +#define C_PRAGMA 111 /* Advice to compiler or linker */ +#define C_SEGMENT 112 /* 80960 segment name */ + + /* Storage classes for m88k */ +#define C_SHADOW 107 /* shadow symbol */ +#define C_VERSION 108 /* coff version symbol */ + + /* New storage classes for RS/6000 */ +#define C_HIDEXT 107 /* Un-named external symbol */ +#define C_BINCL 108 /* Marks beginning of include file */ +#define C_EINCL 109 /* Marks ending of include file */ + + /* storage classes for stab symbols for RS/6000 */ +#define C_GSYM (0x80) +#define C_LSYM (0x81) +#define C_PSYM (0x82) +#define C_RSYM (0x83) +#define C_RPSYM (0x84) +#define C_STSYM (0x85) +#define C_TCSYM (0x86) +#define C_BCOMM (0x87) +#define C_ECOML (0x88) +#define C_ECOMM (0x89) +#define C_DECL (0x8c) +#define C_ENTRY (0x8d) +#define C_FUN (0x8e) +#define C_BSTAT (0x8f) +#define C_ESTAT (0x90) + +/********************** SECTION HEADER **********************/ +struct internal_scnhdr +{ + char s_name[8]; /* section name */ + bfd_vma s_paddr; /* physical address, aliased s_nlib */ + bfd_vma s_vaddr; /* virtual address */ + bfd_vma s_size; /* section size */ + bfd_vma s_scnptr; /* file ptr to raw data for section */ + bfd_vma s_relptr; /* file ptr to relocation */ + bfd_vma s_lnnoptr; /* file ptr to line numbers */ + unsigned long s_nreloc; /* number of relocation entries */ + unsigned long s_nlnno; /* number of line number entries*/ + long s_flags; /* flags */ + long s_align; /* used on I960 */ +}; + +/* + * s_flags "type" + */ +#define STYP_REG (0x0000) /* "regular": allocated, relocated, loaded */ +#define STYP_DSECT (0x0001) /* "dummy": relocated only*/ +#define STYP_NOLOAD (0x0002) /* "noload": allocated, relocated, not loaded */ +#define STYP_GROUP (0x0004) /* "grouped": formed of input sections */ +#define STYP_PAD (0x0008) /* "padding": not allocated, not relocated, loaded */ +#define STYP_COPY (0x0010) /* "copy": for decision function used by field update; not allocated, not relocated, + loaded; reloc & lineno entries processed normally */ +#define STYP_TEXT (0x0020) /* section contains text only */ +#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile + will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will + update all process invocations. */ +#define STYP_DATA (0x0040) /* section contains data only */ +#define STYP_BSS (0x0080) /* section contains bss only */ +#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */ +#define STYP_INFO (0x0200) /* comment: not allocated not relocated, not loaded */ +#define STYP_OVER (0x0400) /* overlay: relocated not allocated or loaded */ +#define STYP_LIB (0x0800) /* for .lib: same as INFO */ +#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */ +#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a + + word of contiguous bytes + beginning on a word boundary. */ + +#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */ + + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ + +struct internal_lineno +{ + union + { + long l_symndx; /* function name symbol index, iff l_lnno == 0*/ + long l_paddr; /* (physical) address of line number */ + } l_addr; + unsigned long l_lnno; /* line number */ +}; + +/********************** SYMBOLS **********************/ + +#define SYMNMLEN 8 /* # characters in a symbol name */ +#define FILNMLEN 14 /* # characters in a file name */ +#define DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct internal_syment +{ + union + { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct + { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + long n_value; /* value of symbol */ + short n_scnum; /* section number */ + unsigned short n_flags; /* copy of flags from filhdr */ + unsigned short n_type; /* type and derived type */ + unsigned char n_sclass; /* storage class */ + unsigned char n_numaux; /* number of aux. entries */ +}; + +#define n_name _n._n_name +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + + +/* Relocatable symbols have number of the section in which they are defined, + or one of the following: */ + +#define N_UNDEF ((short)0) /* undefined symbol */ +#define N_ABS ((short)-1) /* value of symbol is absolute */ +#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */ +#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */ +#define P_TV ((short)-4) /* indicates symbol needs postload transfer vector*/ + +/* + * Type of a symbol, in low N bits of the word + */ +#define T_NULL 0 +#define T_VOID 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration*/ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ +#define T_LNGDBL 16 /* long double */ + +/* + * derived types, in n_type +*/ +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#define BTYPE(x) ((x) & N_BTMASK) + +#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) +#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) +#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) +#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG) +#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) + + +union internal_auxent +{ + struct + { + + union + { + long l; /* str, un, or enum tag indx */ + struct coff_ptr_struct *p; + } x_tagndx; + + union + { + struct + { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str/union/array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + + union + { + struct + { /* if ISFCN, tag, or .bb */ + long x_lnnoptr; /* ptr to fcn line # */ + union + { /* entry ndx past block end */ + long l; + struct coff_ptr_struct *p; + } x_endndx; + } x_fcn; + + struct + { /* if ISARY, up to 4 dimen. */ + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + + unsigned short x_tvndx; /* tv index */ + } x_sym; + + union + { + char x_fname[FILNMLEN]; + struct + { + long x_zeroes; + long x_offset; + } x_n; + } x_file; + + struct + { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* # relocation entries */ + unsigned short x_nlinno; /* # line numbers */ + } x_scn; + + struct + { + long x_tvfill; /* tv fill value */ + unsigned short x_tvlen; /* length of .tv */ + unsigned short x_tvran[2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + /****************************************** + * RS/6000-specific auxent - last auxent for every external symbol + ******************************************/ + struct + { + union + { /* csect length or enclosing csect */ + long l; + struct coff_ptr_struct *p; + } x_scnlen; + long x_parmhash; /* parm type hash index */ + unsigned short x_snhash; /* sect num with parm hash */ + unsigned char x_smtyp; /* symbol align and type */ + /* 0-4 - Log 2 of alignment */ + /* 5-7 - symbol type */ + unsigned char x_smclas; /* storage mapping class */ + long x_stab; /* dbx stab info index */ + unsigned short x_snstab; /* sect num with dbx stab */ + } x_csect; /* csect definition information */ + +/* x_smtyp values: */ + +#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */ +#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */ +/* Symbol type values: */ +#define XTY_ER 0 /* External reference */ +#define XTY_SD 1 /* Csect definition */ +#define XTY_LD 2 /* Label definition */ +#define XTY_CM 3 /* .BSS */ +#define XTY_EM 4 /* Error message */ +#define XTY_US 5 /* "Reserved for internal use" */ + +/* x_smclas values: */ + +#define XMC_PR 0 /* Read-only program code */ +#define XMC_RO 1 /* Read-only constant */ +#define XMC_DB 2 /* Read-only debug dictionary table */ +#define XMC_TC 3 /* Read-write general TOC entry */ +#define XMC_UA 4 /* Read-write unclassified */ +#define XMC_RW 5 /* Read-write data */ +#define XMC_GL 6 /* Read-only global linkage */ +#define XMC_XO 7 /* Read-only extended operation */ +#define XMC_SV 8 /* Read-only supervisor call */ +#define XMC_BS 9 /* Read-write BSS */ +#define XMC_DS 10 /* Read-write descriptor csect */ +#define XMC_UC 11 /* Read-write unnamed Fortran common */ +#define XMC_TI 12 /* Read-only traceback index csect */ +#define XMC_TB 13 /* Read-only traceback table csect */ +/* 14 ??? */ +#define XMC_TC0 15 /* Read-write TOC anchor */ +#define XMC_TD 16 /* Read-write data in TOC */ + + /****************************************** + * I960-specific *2nd* aux. entry formats + ******************************************/ + struct + { + /* This is a very old typo that keeps getting propagated. */ +#define x_stdindx x_stindx + long x_stindx; /* sys. table entry */ + } x_sc; /* system call entry */ + + struct + { + unsigned long x_balntry; /* BAL entry point */ + } x_bal; /* BAL-callable function */ + + struct + { + unsigned long x_timestamp; /* time stamp */ + char x_idstring[20]; /* producer identity string */ + } x_ident; /* Producer ident info */ + +}; + +/********************** RELOCATION DIRECTIVES **********************/ + +struct internal_reloc +{ + bfd_vma r_vaddr; /* Virtual address of reference */ + long r_symndx; /* Index into symbol table */ + unsigned short r_type; /* Relocation type */ + unsigned char r_size; /* Used by RS/6000 and ECOFF */ + unsigned char r_extern; /* Used by ECOFF */ + unsigned long r_offset; /* Used by Alpha ECOFF, SPARC, others */ +}; + +#define R_RELBYTE 017 +#define R_RELWORD 020 +#define R_PCRBYTE 022 +#define R_PCRWORD 023 +#define R_PCRLONG 024 + +#define R_DIR16 01 +#define R_DIR32 06 +#define R_PCLONG 020 +#define R_RELBYTE 017 +#define R_RELWORD 020 +#define R_IMAGEBASE 07 + + +#define R_PCR16L 128 +#define R_PCR26L 129 +#define R_VRT16 130 +#define R_HVRT16 131 +#define R_LVRT16 132 +#define R_VRT32 133 +#define R_RELLONG (0x11) /* Direct 32-bit relocation */ +#define R_IPRSHORT (0x18) +#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */ +#define R_IPRLONG (0x1a) +#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */ +#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */ +#define R_GETSEG (0x1d) +#define R_GETPA (0x1e) +#define R_TAGWORD (0x1f) +#define R_JUMPTARG 0x20 /* strange 29k 00xx00xx reloc */ + + +#define R_MOVB1 0x41 /* Special h8 16bit or 8 bit reloc for mov.b */ +#define R_MOVB2 0x42 /* Special h8 opcode for 8bit which could be 16 */ +#define R_JMP1 0x43 /* Special h8 16bit jmp which could be pcrel */ +#define R_JMP2 0x44 /* a branch which used to be a jmp */ +#define R_RELLONG_NEG 0x45 + +#define R_JMPL1 0x46 /* Special h8 24bit jmp which could be pcrel */ +#define R_JMPL_B8 0x47 /* a 8 bit pcrel which used to be a jmp */ + +#define R_MOVLB1 0x48 /* Special h8 24bit or 8 bit reloc for mov.b */ +#define R_MOVLB2 0x49 /* Special h8 opcode for 8bit which could be 24 */ + +/* An h8300 memory indirect jump/call. Forces the address of the jump/call + target into the function vector (in page zero), and the address of the + vector entry to be placed in the jump/call instruction. */ +#define R_MEM_INDIRECT 0x4a + +/* Z8k modes */ +#define R_IMM16 0x01 /* 16 bit abs */ +#define R_JR 0x02 /* jr 8 bit disp */ +#define R_IMM4L 0x23 /* low nibble */ +#define R_IMM8 0x22 /* 8 bit abs */ +#define R_IMM32 R_RELLONG /* 32 bit abs */ +#define R_CALL R_DA /* Absolute address which could be a callr */ +#define R_JP R_DA /* Absolute address which could be a jp */ +#define R_REL16 0x04 /* 16 bit PC rel */ +#define R_CALLR 0x05 /* callr 12 bit disp */ +#define R_SEG 0x10 /* set if in segmented mode */ +#define R_IMM4H 0x24 /* high nibble */ +#define R_DISP7 0x25 /* djnz displacement */ + +/* H8500 modes */ + +#define R_H8500_IMM8 1 /* 8 bit immediate */ +#define R_H8500_IMM16 2 /* 16 bit immediate */ +#define R_H8500_PCREL8 3 /* 8 bit pcrel */ +#define R_H8500_PCREL16 4 /* 16 bit pcrel */ +#define R_H8500_HIGH8 5 /* high 8 bits of 24 bit address */ +#define R_H8500_LOW16 7 /* low 16 bits of 24 bit immediate */ +#define R_H8500_IMM24 6 /* 24 bit immediate */ +#define R_H8500_IMM32 8 /* 32 bit immediate */ +#define R_H8500_HIGH16 9 /* high 16 bits of 32 bit immediate */ + +/* W65 modes */ + +#define R_W65_ABS8 1 /* addr & 0xff */ +#define R_W65_ABS16 2 /* addr & 0xffff */ +#define R_W65_ABS24 3 /* addr & 0xffffff */ + +#define R_W65_ABS8S8 4 /* (addr >> 8) & 0xff */ +#define R_W65_ABS8S16 5 /* (addr >> 16) & 0xff */ + +#define R_W65_ABS16S8 6 /* (addr >> 8) & 0ffff */ +#define R_W65_ABS16S16 7 /* (addr >> 16) & 0ffff */ + +#define R_W65_PCR8 8 +#define R_W65_PCR16 9 + +#define R_W65_DP 10 /* direct page 8 bits only */ + +#endif /* GNU_COFF_INTERNAL_H */ diff --git a/contrib/gdb/include/coff/m68k.h b/contrib/gdb/include/coff/m68k.h new file mode 100644 index 000000000000..a3c15be16184 --- /dev/null +++ b/contrib/gdb/include/coff/m68k.h @@ -0,0 +1,221 @@ +/*** coff information for M68K */ + +#ifndef GNU_COFF_M68K_H +#define GNU_COFF_M68K_H 1 + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Motorola 68000/68008/68010/68020 */ +#define MC68MAGIC 0520 +#define MC68KWRMAGIC 0520 /* writeable text segments */ +#define MC68TVMAGIC 0521 +#define MC68KROMAGIC 0521 /* readonly shareable text segments */ +#define MC68KPGMAGIC 0522 /* demand paged text segments */ +#define M68MAGIC 0210 +#define M68TVMAGIC 0211 + +/* this is the magic of the Bull dpx/2 */ +#define MC68KBCSMAGIC 0526 + +/* This is Lynx's all-platform magic number for executables. */ + +#define LYNXCOFFMAGIC 0415 + +#define OMAGIC M68MAGIC + +/* This intentionally does not include MC68KBCSMAGIC; it only includes + magic numbers which imply that names do not have underscores. */ +#define M68KBADMAG(x) (((x).f_magic!=MC68MAGIC) && ((x).f_magic!=MC68KWRMAGIC) && ((x).f_magic!=MC68TVMAGIC) && \ + ((x).f_magic!=MC68KROMAGIC) && ((x).f_magic!=MC68KPGMAGIC) && ((x).f_magic!=M68MAGIC) && ((x).f_magic!=M68TVMAGIC) && ((x).f_magic!=LYNXCOFFMAGIC) ) + +/* Magic numbers for the a.out header. */ + +#define PAGEMAGICEXECSWAPPED 0407 /* executable (swapped) */ +#define PAGEMAGICPEXECSWAPPED 0410 /* pure executable (swapped) */ +#define PAGEMAGICPEXECTSHLIB 0443 /* pure executable (target shared library) */ +#define PAGEMAGICPEXECPAGED 0413 /* pure executable (paged) */ + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +#ifdef M68K_COFF_OFFSET + char r_offset[4]; +#endif + +}; + + +#define RELOC struct external_reloc + +#define RELSZ sizeof(struct external_reloc) + +#endif /* GNU_COFF_M68K_H */ diff --git a/contrib/gdb/include/coff/m88k.h b/contrib/gdb/include/coff/m88k.h new file mode 100644 index 000000000000..9068dd3f1245 --- /dev/null +++ b/contrib/gdb/include/coff/m88k.h @@ -0,0 +1,218 @@ +/*** coff information for 88k bcs */ + +/********************** FILE HEADER **********************/ +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +#define MC88MAGIC 0540 /* 88k BCS executable */ +#define MC88DMAGIC 0541 /* DG/UX executable */ +#define MC88OMAGIC 0555 /* Object file */ + +#define MC88BADMAG(x) (((x).f_magic!=MC88MAGIC) &&((x).f_magic!=MC88DMAGIC) && ((x).f_magic != MC88OMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +#define PAGEMAGIC3 0414 /* Split i&d, zero mapped */ +#define PAGEMAGICBCS 0413 + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +/* compute size of a header */ + +#define AOUTSZ (sizeof(AOUTHDR)) + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr +{ + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[4]; /* number of relocation entries */ + char s_nlnno[4]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno{ + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + + char l_lnno[4]; + +}; + +#define LINENO struct external_lineno +#define LINESZ 8 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; + char pad2[2]; +}; + + + + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + + +/* Note that this isn't the same shape as other coffs */ +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + /* 4 */ + union { + char x_fsize[4]; /* size of function */ + struct { + char x_lnno[4]; /* declaration line number */ + char x_size[4]; /* str/union/array size */ + } x_lnsz; + } x_misc; + + /* 12 */ + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + /* 20 */ + + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[4]; /* # relocation entries */ + char x_nlinno[4]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + +}; + +#define GET_FCN_LNNOPTR(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *)ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#define GET_FCN_ENDNDX(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#define PUT_FCN_LNNOPTR(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#define PUT_FCN_ENDNDX(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#define GET_LNSZ_SIZE(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size) +#define GET_LNSZ_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno) +#define PUT_LNSZ_LNNO(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno) +#define PUT_LNSZ_SIZE(abfd, in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size) +#define GET_SCN_SCNLEN(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_scnlen) +#define GET_SCN_NRELOC(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_nreloc) +#define GET_SCN_NLINNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_nlinno) +#define PUT_SCN_SCNLEN(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_scn.x_scnlen) +#define PUT_SCN_NRELOC(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *)ext->x_scn.x_nreloc) +#define PUT_SCN_NLINNO(abfd,in, ext) bfd_h_put_32(abfd,in, (bfd_byte *) ext->x_scn.x_nlinno) +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)) +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + + + +#define SYMENT struct external_syment +#define SYMESZ 20 +#define AUXENT union external_auxent +#define AUXESZ 20 + + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; + char r_offset[2]; +}; + +#define RELOC struct external_reloc +#define RELSZ 12 + +#define NO_TVNDX diff --git a/contrib/gdb/include/coff/mips.h b/contrib/gdb/include/coff/mips.h new file mode 100644 index 000000000000..f35187e83b17 --- /dev/null +++ b/contrib/gdb/include/coff/mips.h @@ -0,0 +1,368 @@ +/* ECOFF support on MIPS machines. + coff/ecoff.h must be included before this file. */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + unsigned char f_magic[2]; /* magic number */ + unsigned char f_nscns[2]; /* number of sections */ + unsigned char f_timdat[4]; /* time & date stamp */ + unsigned char f_symptr[4]; /* file pointer to symtab */ + unsigned char f_nsyms[4]; /* number of symtab entries */ + unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ + unsigned char f_flags[2]; /* flags */ +}; + +/* Magic numbers are defined in coff/ecoff.h. */ +#define MIPS_ECOFF_BADMAG(x) (((x).f_magic!=MIPS_MAGIC_1) && \ + ((x).f_magic!=MIPS_MAGIC_LITTLE) &&\ + ((x).f_magic!=MIPS_MAGIC_BIG) && \ + ((x).f_magic!=MIPS_MAGIC_LITTLE2) && \ + ((x).f_magic!=MIPS_MAGIC_BIG2) && \ + ((x).f_magic!=MIPS_MAGIC_LITTLE3) && \ + ((x).f_magic!=MIPS_MAGIC_BIG3)) + +#define FILHDR struct external_filehdr +#define FILHSZ 20 + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct external_aouthdr +{ + unsigned char magic[2]; /* type of file */ + unsigned char vstamp[2]; /* version stamp */ + unsigned char tsize[4]; /* text size in bytes, padded to FW bdry*/ + unsigned char dsize[4]; /* initialized data " " */ + unsigned char bsize[4]; /* uninitialized data " " */ + unsigned char entry[4]; /* entry pt. */ + unsigned char text_start[4]; /* base of text used for this file */ + unsigned char data_start[4]; /* base of data used for this file */ + unsigned char bss_start[4]; /* base of bss used for this file */ + unsigned char gprmask[4]; /* ?? */ + unsigned char cprmask[4][4]; /* ?? */ + unsigned char gp_value[4]; /* value for gp register */ +} AOUTHDR; + +/* compute size of a header */ + +#define AOUTSZ (sizeof(AOUTHDR)) + +/********************** SECTION HEADER **********************/ + +struct external_scnhdr { + unsigned char s_name[8]; /* section name */ + unsigned char s_paddr[4]; /* physical address, aliased s_nlib */ + unsigned char s_vaddr[4]; /* virtual address */ + unsigned char s_size[4]; /* section size */ + unsigned char s_scnptr[4]; /* file ptr to raw data for section */ + unsigned char s_relptr[4]; /* file ptr to relocation */ + unsigned char s_lnnoptr[4]; /* file ptr to line numbers */ + unsigned char s_nreloc[2]; /* number of relocation entries */ + unsigned char s_nlnno[2]; /* number of line number entries*/ + unsigned char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + unsigned char r_vaddr[4]; + unsigned char r_bits[4]; +}; + +#define RELOC struct external_reloc +#define RELSZ 8 + +/* MIPS ECOFF uses a packed 8 byte format for relocs. These constants + are used to unpack the r_bits field. */ + +#define RELOC_BITS0_SYMNDX_SH_LEFT_BIG 16 +#define RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE 0 + +#define RELOC_BITS1_SYMNDX_SH_LEFT_BIG 8 +#define RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE 8 + +#define RELOC_BITS2_SYMNDX_SH_LEFT_BIG 0 +#define RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE 16 + +/* Originally, ECOFF used four bits for the reloc type and had three + reserved bits. Irix 4 added another bit for the reloc type, which + was easy because it was big endian and one of the spare bits became + the new most significant bit. To make this also work for little + endian ECOFF, we need to wrap one of the reserved bits around to + become the most significant bit of the reloc type. */ +#define RELOC_BITS3_TYPE_BIG 0x3E +#define RELOC_BITS3_TYPE_SH_BIG 1 +#define RELOC_BITS3_TYPE_LITTLE 0x78 +#define RELOC_BITS3_TYPE_SH_LITTLE 3 +#define RELOC_BITS3_TYPEHI_LITTLE 0x04 +#define RELOC_BITS3_TYPEHI_SH_LITTLE 2 + +#define RELOC_BITS3_EXTERN_BIG 0x01 +#define RELOC_BITS3_EXTERN_LITTLE 0x80 + +/* The r_type field in a reloc is one of the following values. I + don't know if any other values can appear. These seem to be all + that occur in the Ultrix 4.2 libraries. */ +#define MIPS_R_IGNORE 0 +#define MIPS_R_REFHALF 1 +#define MIPS_R_REFWORD 2 +#define MIPS_R_JMPADDR 3 +#define MIPS_R_REFHI 4 +#define MIPS_R_REFLO 5 +#define MIPS_R_GPREL 6 +#define MIPS_R_LITERAL 7 + +/* These reloc types are a Cygnus extension used when generating + position independent code for embedded systems. The numbers are + taken from Irix 4, but at least for internal relocs Irix 5 does not + give them the same meaning. For an internal reloc the symbol index + of RELHI and RELLO is modified as described below for + MIPS_R_SWITCH. */ +#define MIPS_R_PCREL16 12 +#define MIPS_R_RELHI 13 +#define MIPS_R_RELLO 14 + +/* This reloc type is a Cygnus extension used when generating position + independent code for embedded systems. It is used for an entry in + a switch table, which looks like this: + .word $L3-$LS12 + The object file will contain the correct difference, and does not + require adjustment. However, when the linker is relaxing PC + relative calls, it is possible for $L3 to move farther away. This + reloc always appears in the .text section, and is always against + the .text section. However, the symbol index is not + RELOC_SECTION_TEXT. It is, instead, the distance between this + switch table entry and $LS12. Thus, the original value of $L12 is + vaddr - symndx + and the original value of $L3 is + vaddr - symndx + addend + where addend is the value in the object file. Knowing this, the + linker can know whether the addend in the object file must be + adjusted. */ +#define MIPS_R_SWITCH 22 + +/********************** STABS **********************/ + +#define MIPS_IS_STAB ECOFF_IS_STAB +#define MIPS_MARK_STAB ECOFF_MARK_STAB +#define MIPS_UNMARK_STAB ECOFF_UNMARK_STAB + +/********************** SYMBOLIC INFORMATION **********************/ + +/* Written by John Gilmore. */ + +/* ECOFF uses COFF-like section structures, but its own symbol format. + This file defines the symbol format in fields whose size and alignment + will not vary on different host systems. */ + +/* File header as a set of bytes */ + +struct hdr_ext { + unsigned char h_magic[2]; + unsigned char h_vstamp[2]; + unsigned char h_ilineMax[4]; + unsigned char h_cbLine[4]; + unsigned char h_cbLineOffset[4]; + unsigned char h_idnMax[4]; + unsigned char h_cbDnOffset[4]; + unsigned char h_ipdMax[4]; + unsigned char h_cbPdOffset[4]; + unsigned char h_isymMax[4]; + unsigned char h_cbSymOffset[4]; + unsigned char h_ioptMax[4]; + unsigned char h_cbOptOffset[4]; + unsigned char h_iauxMax[4]; + unsigned char h_cbAuxOffset[4]; + unsigned char h_issMax[4]; + unsigned char h_cbSsOffset[4]; + unsigned char h_issExtMax[4]; + unsigned char h_cbSsExtOffset[4]; + unsigned char h_ifdMax[4]; + unsigned char h_cbFdOffset[4]; + unsigned char h_crfd[4]; + unsigned char h_cbRfdOffset[4]; + unsigned char h_iextMax[4]; + unsigned char h_cbExtOffset[4]; +}; + +/* File descriptor external record */ + +struct fdr_ext { + unsigned char f_adr[4]; + unsigned char f_rss[4]; + unsigned char f_issBase[4]; + unsigned char f_cbSs[4]; + unsigned char f_isymBase[4]; + unsigned char f_csym[4]; + unsigned char f_ilineBase[4]; + unsigned char f_cline[4]; + unsigned char f_ioptBase[4]; + unsigned char f_copt[4]; + unsigned char f_ipdFirst[2]; + unsigned char f_cpd[2]; + unsigned char f_iauxBase[4]; + unsigned char f_caux[4]; + unsigned char f_rfdBase[4]; + unsigned char f_crfd[4]; + unsigned char f_bits1[1]; + unsigned char f_bits2[3]; + unsigned char f_cbLineOffset[4]; + unsigned char f_cbLine[4]; +}; + +#define FDR_BITS1_LANG_BIG 0xF8 +#define FDR_BITS1_LANG_SH_BIG 3 +#define FDR_BITS1_LANG_LITTLE 0x1F +#define FDR_BITS1_LANG_SH_LITTLE 0 + +#define FDR_BITS1_FMERGE_BIG 0x04 +#define FDR_BITS1_FMERGE_LITTLE 0x20 + +#define FDR_BITS1_FREADIN_BIG 0x02 +#define FDR_BITS1_FREADIN_LITTLE 0x40 + +#define FDR_BITS1_FBIGENDIAN_BIG 0x01 +#define FDR_BITS1_FBIGENDIAN_LITTLE 0x80 + +#define FDR_BITS2_GLEVEL_BIG 0xC0 +#define FDR_BITS2_GLEVEL_SH_BIG 6 +#define FDR_BITS2_GLEVEL_LITTLE 0x03 +#define FDR_BITS2_GLEVEL_SH_LITTLE 0 + +/* We ignore the `reserved' field in bits2. */ + +/* Procedure descriptor external record */ + +struct pdr_ext { + unsigned char p_adr[4]; + unsigned char p_isym[4]; + unsigned char p_iline[4]; + unsigned char p_regmask[4]; + unsigned char p_regoffset[4]; + unsigned char p_iopt[4]; + unsigned char p_fregmask[4]; + unsigned char p_fregoffset[4]; + unsigned char p_frameoffset[4]; + unsigned char p_framereg[2]; + unsigned char p_pcreg[2]; + unsigned char p_lnLow[4]; + unsigned char p_lnHigh[4]; + unsigned char p_cbLineOffset[4]; +}; + +/* Runtime procedure table */ + +struct rpdr_ext { + unsigned char p_adr[4]; + unsigned char p_regmask[4]; + unsigned char p_regoffset[4]; + unsigned char p_fregmask[4]; + unsigned char p_fregoffset[4]; + unsigned char p_frameoffset[4]; + unsigned char p_framereg[2]; + unsigned char p_pcreg[2]; + unsigned char p_irpss[4]; + unsigned char p_reserved[4]; + unsigned char p_exception_info[4]; +}; + +/* Line numbers */ + +struct line_ext { + unsigned char l_line[4]; +}; + +/* Symbol external record */ + +struct sym_ext { + unsigned char s_iss[4]; + unsigned char s_value[4]; + unsigned char s_bits1[1]; + unsigned char s_bits2[1]; + unsigned char s_bits3[1]; + unsigned char s_bits4[1]; +}; + +#define SYM_BITS1_ST_BIG 0xFC +#define SYM_BITS1_ST_SH_BIG 2 +#define SYM_BITS1_ST_LITTLE 0x3F +#define SYM_BITS1_ST_SH_LITTLE 0 + +#define SYM_BITS1_SC_BIG 0x03 +#define SYM_BITS1_SC_SH_LEFT_BIG 3 +#define SYM_BITS1_SC_LITTLE 0xC0 +#define SYM_BITS1_SC_SH_LITTLE 6 + +#define SYM_BITS2_SC_BIG 0xE0 +#define SYM_BITS2_SC_SH_BIG 5 +#define SYM_BITS2_SC_LITTLE 0x07 +#define SYM_BITS2_SC_SH_LEFT_LITTLE 2 + +#define SYM_BITS2_RESERVED_BIG 0x10 +#define SYM_BITS2_RESERVED_LITTLE 0x08 + +#define SYM_BITS2_INDEX_BIG 0x0F +#define SYM_BITS2_INDEX_SH_LEFT_BIG 16 +#define SYM_BITS2_INDEX_LITTLE 0xF0 +#define SYM_BITS2_INDEX_SH_LITTLE 4 + +#define SYM_BITS3_INDEX_SH_LEFT_BIG 8 +#define SYM_BITS3_INDEX_SH_LEFT_LITTLE 4 + +#define SYM_BITS4_INDEX_SH_LEFT_BIG 0 +#define SYM_BITS4_INDEX_SH_LEFT_LITTLE 12 + +/* External symbol external record */ + +struct ext_ext { + unsigned char es_bits1[1]; + unsigned char es_bits2[1]; + unsigned char es_ifd[2]; + struct sym_ext es_asym; +}; + +#define EXT_BITS1_JMPTBL_BIG 0x80 +#define EXT_BITS1_JMPTBL_LITTLE 0x01 + +#define EXT_BITS1_COBOL_MAIN_BIG 0x40 +#define EXT_BITS1_COBOL_MAIN_LITTLE 0x02 + +#define EXT_BITS1_WEAKEXT_BIG 0x20 +#define EXT_BITS1_WEAKEXT_LITTLE 0x04 + +/* Dense numbers external record */ + +struct dnr_ext { + unsigned char d_rfd[4]; + unsigned char d_index[4]; +}; + +/* Relative file descriptor */ + +struct rfd_ext { + unsigned char rfd[4]; +}; + +/* Optimizer symbol external record */ + +struct opt_ext { + unsigned char o_bits1[1]; + unsigned char o_bits2[1]; + unsigned char o_bits3[1]; + unsigned char o_bits4[1]; + struct rndx_ext o_rndx; + unsigned char o_offset[4]; +}; + +#define OPT_BITS2_VALUE_SH_LEFT_BIG 16 +#define OPT_BITS2_VALUE_SH_LEFT_LITTLE 0 + +#define OPT_BITS3_VALUE_SH_LEFT_BIG 8 +#define OPT_BITS3_VALUE_SH_LEFT_LITTLE 8 + +#define OPT_BITS4_VALUE_SH_LEFT_BIG 0 +#define OPT_BITS4_VALUE_SH_LEFT_LITTLE 16 diff --git a/contrib/gdb/include/coff/pe.h b/contrib/gdb/include/coff/pe.h new file mode 100644 index 000000000000..f13b8b979ea6 --- /dev/null +++ b/contrib/gdb/include/coff/pe.h @@ -0,0 +1,161 @@ +/* PE COFF header information */ + +#ifndef _PE_H +#define _PE_H + +/* NT specific file attributes */ +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* additional flags to be set for section headers to allow the NT loader to + read and write to the section data (to replace the addresses of data in + dlls for one thing); also to execute the section in .text's case */ +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +/* + * Section characteristics added for ppc-nt + */ + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */ + +#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ + +#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */ +#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */ +#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */ + +#define IMAGE_SCN_MEM_FARDATA 0x00008000 + +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 + + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */ +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */ +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ +#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ + + +/* Magic values that are true for all dos/nt implementations */ +#define DOSMAGIC 0x5a4d +#define NT_SIGNATURE 0x00004550 + + /* NT allows long filenames, we want to accommodate this. This may break + some of the bfd functions */ +#undef FILNMLEN +#define FILNMLEN 18 /* # characters in a file name */ + + +#ifdef COFF_IMAGE_WITH_PE +/* The filehdr is only weired in images */ + +#undef FILHDR +struct external_PE_filehdr +{ + /* DOS header fields */ + char e_magic[2]; /* Magic number, 0x5a4d */ + char e_cblp[2]; /* Bytes on last page of file, 0x90 */ + char e_cp[2]; /* Pages in file, 0x3 */ + char e_crlc[2]; /* Relocations, 0x0 */ + char e_cparhdr[2]; /* Size of header in paragraphs, 0x4 */ + char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0 */ + char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF */ + char e_ss[2]; /* Initial (relative) SS value, 0x0 */ + char e_sp[2]; /* Initial SP value, 0xb8 */ + char e_csum[2]; /* Checksum, 0x0 */ + char e_ip[2]; /* Initial IP value, 0x0 */ + char e_cs[2]; /* Initial (relative) CS value, 0x0 */ + char e_lfarlc[2]; /* File address of relocation table, 0x40 */ + char e_ovno[2]; /* Overlay number, 0x0 */ + char e_res[4][2]; /* Reserved words, all 0x0 */ + char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0 */ + char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0 */ + char e_res2[10][2]; /* Reserved words, all 0x0 */ + char e_lfanew[4]; /* File address of new exe header, 0x80 */ + char dos_message[16][4]; /* other stuff, always follow DOS header */ + char nt_signature[4]; /* required NT signature, 0x4550 */ + + /* From standard header */ + + + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ + +}; + + +#define FILHDR struct external_PE_filehdr + + +#endif + +typedef struct +{ + AOUTHDR standard; + + /* NT extra fields; see internal.h for descriptions */ + char ImageBase[4]; + char SectionAlignment[4]; + char FileAlignment[4]; + char MajorOperatingSystemVersion[2]; + char MinorOperatingSystemVersion[2]; + char MajorImageVersion[2]; + char MinorImageVersion[2]; + char MajorSubsystemVersion[2]; + char MinorSubsystemVersion[2]; + char Reserved1[4]; + char SizeOfImage[4]; + char SizeOfHeaders[4]; + char CheckSum[4]; + char Subsystem[2]; + char DllCharacteristics[2]; + char SizeOfStackReserve[4]; + char SizeOfStackCommit[4]; + char SizeOfHeapReserve[4]; + char SizeOfHeapCommit[4]; + char LoaderFlags[4]; + char NumberOfRvaAndSizes[4]; + /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ + char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */ + +} PEAOUTHDR; + + +#undef AOUTSZ +#define AOUTSZ sizeof(PEAOUTHDR) + +#undef E_FILNMLEN +#define E_FILNMLEN 18 /* # characters in a file name */ +#endif + + + diff --git a/contrib/gdb/include/coff/powerpc.h b/contrib/gdb/include/coff/powerpc.h new file mode 100644 index 000000000000..6866fc8a0dc7 --- /dev/null +++ b/contrib/gdb/include/coff/powerpc.h @@ -0,0 +1,196 @@ +/* Basic coff information for the PowerPC + * + * Based on coff/rs6000.h, coff/i386.h and others. + * + * Initial release: Kim Knuttila (krk@cygnus.com) + */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + +/* extra NT defines */ +#define PPCMAGIC 0760 /* peeked on aa PowerPC Windows NT box */ +#define DOSMAGIC 0x5a4d /* from arm.h, i386.h */ +#define NT_SIGNATURE 0x00004550 /* from arm.h, i386.h */ + +/* from winnt.h */ +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b + +#define PPCBADMAG(x) ((x).f_magic != PPCMAGIC) + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) + + +/********************** SECTION HEADER **********************/ + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries */ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0 */ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + +#define LINENO struct external_lineno +#define LINESZ 6 + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ + +/* Allow the file name length to be overridden in the including file */ +#ifndef E_FILNMLEN +#define E_FILNMLEN 14 +#endif + +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; +}; + +#define AUXENT union external_auxent +#define AUXESZ 18 + +#define _ETEXT "etext" + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + +#define RELOC struct external_reloc +#define RELSZ 10 + diff --git a/contrib/gdb/include/coff/rs6000.h b/contrib/gdb/include/coff/rs6000.h new file mode 100644 index 000000000000..62a6f86cc7c8 --- /dev/null +++ b/contrib/gdb/include/coff/rs6000.h @@ -0,0 +1,242 @@ +/* IBM RS/6000 "XCOFF" file definitions for BFD. + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + FIXME: Can someone provide a transliteration of this name into ASCII? + Using the following chars caused a compiler warning on HIUX (so I replaced + them with octal escapes), and isn't useful without an understanding of what + character set it is. + Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM + and John Gilmore of Cygnus Support. */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + /* IBM RS/6000 */ +#define U802WRMAGIC 0730 /* writeable text segments **chh** */ +#define U802ROMAGIC 0735 /* readonly sharable text segments */ +#define U802TOCMAGIC 0737 /* readonly text segments and TOC */ + +#define BADMAG(x) \ + ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \ + (x).f_magic != U802TOCMAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + unsigned char magic[2]; /* type of file */ + unsigned char vstamp[2]; /* version stamp */ + unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */ + unsigned char dsize[4]; /* initialized data " " */ + unsigned char bsize[4]; /* uninitialized data " " */ + unsigned char entry[4]; /* entry pt. */ + unsigned char text_start[4]; /* base of text used for this file */ + unsigned char data_start[4]; /* base of data used for this file */ + unsigned char o_toc[4]; /* address of TOC */ + unsigned char o_snentry[2]; /* section number of entry point */ + unsigned char o_sntext[2]; /* section number of .text section */ + unsigned char o_sndata[2]; /* section number of .data section */ + unsigned char o_sntoc[2]; /* section number of TOC */ + unsigned char o_snloader[2]; /* section number of .loader section */ + unsigned char o_snbss[2]; /* section number of .bss section */ + unsigned char o_algntext[2]; /* .text alignment */ + unsigned char o_algndata[2]; /* .data alignment */ + unsigned char o_modtype[2]; /* module type (??) */ + unsigned char o_cputype[2]; /* cpu type */ + unsigned char o_maxstack[4]; /* max stack size (??) */ + unsigned char o_maxdata[4]; /* max data size (??) */ + unsigned char o_resv2[12]; /* reserved */ +} +AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) +#define SMALL_AOUTSZ (28) + +#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */ +#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */ +#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */ + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _PAD ".pad" +#define _LOADER ".loader" + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* XCOFF uses a special .loader section with type STYP_LOADER. */ +#define STYP_LOADER 0x1000 + +/* XCOFF uses a special .debug section with type STYP_DEBUG. */ +#define STYP_DEBUG 0x2000 + +/* XCOFF handles line number or relocation overflow by creating + another section header with STYP_OVRFLO set. */ +#define STYP_OVRFLO 0x8000 + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + struct { + unsigned char x_scnlen[4]; + unsigned char x_parmhash[4]; + unsigned char x_snhash[2]; + unsigned char x_smtyp[1]; + unsigned char x_smclas[1]; + unsigned char x_stab[4]; + unsigned char x_snstab[2]; + } x_csect; + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 +#define DBXMASK 0x80 /* for dbx storage mask */ +#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK) + + + +/********************** RELOCATION DIRECTIVES **********************/ + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_size[1]; + char r_type[1]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 10 + +#define DEFAULT_DATA_SECTION_ALIGNMENT 4 +#define DEFAULT_BSS_SECTION_ALIGNMENT 4 +#define DEFAULT_TEXT_SECTION_ALIGNMENT 4 +/* For new sections we havn't heard of before */ +#define DEFAULT_SECTION_ALIGNMENT 4 diff --git a/contrib/gdb/include/coff/sh.h b/contrib/gdb/include/coff/sh.h new file mode 100644 index 000000000000..af49674a9ee8 --- /dev/null +++ b/contrib/gdb/include/coff/sh.h @@ -0,0 +1,253 @@ +/*** coff information for Hitachi SH */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + + +#define SH_ARCH_MAGIC_BIG 0x0500 +#define SH_ARCH_MAGIC_LITTLE 0x0550 /* Little endian SH */ + + +#define SHBADMAG(x) \ + (((x).f_magic!=SH_ARCH_MAGIC_BIG) && \ + ((x).f_magic!=SH_ARCH_MAGIC_LITTLE)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[4]; /* line number */ +}; + +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)); +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + +/* The external reloc has an offset field, because some of the reloc + types on the h8 don't have room in the instruction for the entire + offset - eg the strange jump and high page addressing modes */ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_offset[4]; + char r_type[2]; + char r_stuff[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 16 + +/* SH relocation types. Not all of these are actually used. */ + +#define R_SH_UNUSED 0 /* only used internally */ +#define R_SH_PCREL8 3 /* 8 bit pcrel */ +#define R_SH_PCREL16 4 /* 16 bit pcrel */ +#define R_SH_HIGH8 5 /* high 8 bits of 24 bit address */ +#define R_SH_LOW16 7 /* low 16 bits of 24 bit immediate */ +#define R_SH_IMM24 6 /* 24 bit immediate */ +#define R_SH_PCDISP8BY4 9 /* PC rel 8 bits *4 +ve */ +#define R_SH_PCDISP8BY2 10 /* PC rel 8 bits *2 +ve */ +#define R_SH_PCDISP8 11 /* 8 bit branch */ +#define R_SH_PCDISP 12 /* 12 bit branch */ +#define R_SH_IMM32 14 /* 32 bit immediate */ +#define R_SH_IMM8 16 /* 8 bit immediate */ +#define R_SH_IMM8BY2 17 /* 8 bit immediate *2 */ +#define R_SH_IMM8BY4 18 /* 8 bit immediate *4 */ +#define R_SH_IMM4 19 /* 4 bit immediate */ +#define R_SH_IMM4BY2 20 /* 4 bit immediate *2 */ +#define R_SH_IMM4BY4 21 /* 4 bit immediate *4 */ +#define R_SH_PCRELIMM8BY2 22 /* PC rel 8 bits *2 unsigned */ +#define R_SH_PCRELIMM8BY4 23 /* PC rel 8 bits *4 unsigned */ +#define R_SH_IMM16 24 /* 16 bit immediate */ + +/* The switch table reloc types are used for relaxing. They are + generated for expressions such as + .word L1 - L2 + The r_offset field holds the difference between the reloc address + and L2. */ +#define R_SH_SWITCH16 25 /* 16 bit switch table entry */ +#define R_SH_SWITCH32 26 /* 16 bit switch table entry */ + +/* The USES reloc type is used for relaxing. The compiler will + generate .uses pseudo-ops when it finds a function call which it + can relax. The r_offset field of the USES reloc holds the PC + relative offset to the instruction which loads the register used in + the function call. */ +#define R_SH_USES 27 /* .uses pseudo-op */ + +/* The COUNT reloc type is used for relaxing. The assembler will + generate COUNT relocs for addresses referred to by the register + loads associated with USES relocs. The r_offset field of the COUNT + reloc holds the number of times the address is references in the + object file. */ +#define R_SH_COUNT 28 /* Count of constant pool uses */ + +/* The ALIGN reloc type is used for relaxing. The r_offset field is + the power of two to which subsequent portions of the object file + must be aligned. */ +#define R_SH_ALIGN 29 /* .align pseudo-op */ + + + diff --git a/contrib/gdb/include/coff/sparc.h b/contrib/gdb/include/coff/sparc.h new file mode 100644 index 000000000000..0e3217b25f13 --- /dev/null +++ b/contrib/gdb/include/coff/sparc.h @@ -0,0 +1,209 @@ +/*** coff information for Sparc. */ + +/* This file is an amalgamation of several standard include files that + define coff format, such as filehdr.h, aouthdr.h, and so forth. In + addition, all datatypes have been translated into character arrays of + (presumed) equivalent size. This is necessary so that this file can + be used with different systems while still yielding the same results. */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr +{ + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +#define F_RELFLG (0x0001) /* relocation info stripped */ +#define F_EXEC (0x0002) /* file is executable */ +#define F_LNNO (0x0004) /* line numbers stripped */ +#define F_LSYMS (0x0008) /* local symbols stripped */ + +#define SPARCMAGIC (0540) + +/* This is Lynx's all-platform magic number for executables. */ + +#define LYNXCOFFMAGIC (0415) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC 0413 /* demand load format, eg normal ld output */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + +/********************** SECTION HEADER **********************/ + +struct external_scnhdr +{ + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* Names of "special" sections. */ + +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _TV ".tv" +#define _INIT ".init" +#define _FINI ".fini" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + Line numbers are grouped on a per function basis; first entry in a function + grouping will have l_lnno = 0 and in place of physical address will be the + symbol table index of the function name. */ + +struct external_lineno +{ + union { + char l_symndx[4]; /* fn name symbol index, iff l_lnno == 0 */ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + +#define LINENO struct external_lineno +#define LINESZ (6) + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN (8) /* # characters in a symbol name */ +#define E_FILNMLEN (14) /* # characters in a file name */ +#define E_DIMNUM (4) /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; +#if 0 /* of doubtful value */ + char e_nptr[2][4]; + struct { + char e_leading_zero[1]; + char e_dbx_type[1]; + char e_dbx_desc[2]; + } e_dbx; +#endif + } e; + + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; + char padding[2]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent +{ + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* .tv section info (in auxent of sym .tv)) */ + + char x_fill[20]; /* forces to 20-byte size */ +}; + +#define SYMENT struct external_syment +#define SYMESZ 20 +#define AUXENT union external_auxent +#define AUXESZ 20 + +#define _ETEXT "etext" + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; + char r_spare[2]; + char r_offset[4]; +}; + +#define RELOC struct external_reloc +#define RELSZ sizeof (RELOC) + diff --git a/contrib/gdb/include/coff/sym.h b/contrib/gdb/include/coff/sym.h new file mode 100644 index 000000000000..76204af59adc --- /dev/null +++ b/contrib/gdb/include/coff/sym.h @@ -0,0 +1,484 @@ +/* Declarations of internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ +#ifndef _SYM_H +#define _SYM_H + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* + * This file contains the definition of the Third Eye Symbol Table. + * + * Symbols are assumed to be in 'encounter order' - i.e. the order that + * the things they represent were encountered by the compiler/assembler/loader. + * EXCEPT for globals! These are assumed to be bunched together, + * probably right after the last 'normal' symbol. Globals ARE sorted + * in ascending order. + * + * ----------------------------------------------------------------------- + * A brief word about Third Eye naming/use conventions: + * + * All arrays and index's are 0 based. + * All "ifooMax" values are the highest legal value PLUS ONE. This makes + * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". + * + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + */ + + +/* + * Symbolic Header (HDR) structure. + * As long as all the pointers are set correctly, + * we don't care WHAT order the various sections come out in! + * + * A file produced solely for the use of CDB will probably NOT have + * any instructions or data areas in it, as these are available + * in the original. + */ + +typedef struct { + short magic; /* to verify validity of the table */ + short vstamp; /* version stamp */ + long ilineMax; /* number of line number entries */ + bfd_vma cbLine; /* number of bytes for line number entries */ + bfd_vma cbLineOffset; /* offset to start of line number entries*/ + long idnMax; /* max index into dense number table */ + bfd_vma cbDnOffset; /* offset to start dense number table */ + long ipdMax; /* number of procedures */ + bfd_vma cbPdOffset; /* offset to procedure descriptor table */ + long isymMax; /* number of local symbols */ + bfd_vma cbSymOffset; /* offset to start of local symbols*/ + long ioptMax; /* max index into optimization symbol entries */ + bfd_vma cbOptOffset; /* offset to optimization symbol entries */ + long iauxMax; /* number of auxillary symbol entries */ + bfd_vma cbAuxOffset; /* offset to start of auxillary symbol entries*/ + long issMax; /* max index into local strings */ + bfd_vma cbSsOffset; /* offset to start of local strings */ + long issExtMax; /* max index into external strings */ + bfd_vma cbSsExtOffset; /* offset to start of external strings */ + long ifdMax; /* number of file descriptor entries */ + bfd_vma cbFdOffset; /* offset to file descriptor table */ + long crfd; /* number of relative file descriptor entries */ + bfd_vma cbRfdOffset; /* offset to relative file descriptor table */ + long iextMax; /* max index into external symbols */ + bfd_vma cbExtOffset; /* offset to start of external symbol entries*/ + /* If you add machine dependent fields, add them here */ + } HDRR, *pHDRR; +#define cbHDRR sizeof(HDRR) +#define hdrNil ((pHDRR)0) + +/* + * The FDR and PDR structures speed mapping of address <-> name. + * They are sorted in ascending memory order and are kept in + * memory by CDB at runtime. + */ + +/* + * File Descriptor + * + * There is one of these for EVERY FILE, whether compiled with + * full debugging symbols or not. The name of a file should be + * the path name given to the compiler. This allows the user + * to simply specify the names of the directories where the COMPILES + * were done, and we will be able to find their files. + * A field whose comment starts with "R - " indicates that it will be + * setup at runtime. + */ +typedef struct fdr { + bfd_vma adr; /* memory address of beginning of file */ + long rss; /* file name (of source, if known) */ + long issBase; /* file's string space */ + bfd_vma cbSs; /* number of bytes in the ss */ + long isymBase; /* beginning of symbols */ + long csym; /* count file's of symbols */ + long ilineBase; /* file's line symbols */ + long cline; /* count of file's line symbols */ + long ioptBase; /* file's optimization entries */ + long copt; /* count of file's optimization entries */ + unsigned short ipdFirst;/* start of procedures for this file */ + short cpd; /* count of procedures for this file */ + long iauxBase; /* file's auxiliary entries */ + long caux; /* count of file's auxiliary entries */ + long rfdBase; /* index into the file indirect table */ + long crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ + unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ + unsigned reserved : 22; /* reserved for future use */ + bfd_vma cbLineOffset; /* byte offset from header for this file ln's */ + bfd_vma cbLine; /* size of lines for this file */ + } FDR, *pFDR; +#define cbFDR sizeof(FDR) +#define fdNil ((pFDR)0) +#define ifdNil -1 +#define ifdTemp 0 +#define ilnNil -1 + + +/* + * Procedure Descriptor + * + * There is one of these for EVERY TEXT LABEL. + * If a procedure is in a file with full symbols, then isym + * will point to the PROC symbols, else it will point to the + * global symbol for the label. + */ + +typedef struct pdr { + bfd_vma adr; /* memory address of start of procedure */ + long isym; /* start of local symbol entries */ + long iline; /* start of line number entries*/ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long iopt; /* start of optimization symbol entries*/ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long lnLow; /* lowest line in the procedure */ + long lnHigh; /* highest line in the procedure */ + bfd_vma cbLineOffset; /* byte offset for this procedure from the fd base */ + /* These fields are new for 64 bit ECOFF. */ + unsigned gp_prologue : 8; /* byte size of GP prologue */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned prof : 1; /* true if compiled with -pg */ + unsigned reserved : 13; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + } PDR, *pPDR; +#define cbPDR sizeof(PDR) +#define pdNil ((pPDR) 0) +#define ipdNil -1 + +/* + * The structure of the runtime procedure descriptor created by the loader + * for use by the static exception system. + */ +/* + * If 0'd out because exception_info chokes Visual C++ and because there + * don't seem to be any references to this structure elsewhere in gdb. + */ +#if 0 +typedef struct runtime_pdr { + bfd_vma adr; /* memory address of start of procedure */ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long irpss; /* index into the runtime string table */ + long reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) +#endif + +/* + * Line Numbers + * + * Line Numbers are segregated from the normal symbols because they + * are [1] smaller , [2] are of no interest to your + * average loader, and [3] are never needed in the middle of normal + * scanning and therefore slow things down. + * + * By definition, the first LINER for any given procedure will have + * the first line of a procedure and represent the first address. + */ + +typedef long LINER, *pLINER; +#define lineNil ((pLINER)0) +#define cbLINER sizeof(LINER) +#define ilineNil -1 + + + +/* + * The Symbol Structure (GFW, to those who Know!) + */ + +typedef struct { + long iss; /* index into String Space of name */ + bfd_vma value; /* value of symbol */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ + } SYMR, *pSYMR; +#define symNil ((pSYMR)0) +#define cbSYMR sizeof(SYMR) +#define isymNil -1 +#define indexNil 0xfffff +#define issNil -1 +#define issNull 0 + + +/* The following converts a memory resident string to an iss. + * This hack is recognized in SbFIss, in sym.c of the debugger. + */ +#define IssFSb(sb) (0x80000000 | ((unsigned long)(sb))) + +/* E X T E R N A L S Y M B O L R E C O R D + * + * Same as the SYMR except it contains file context to determine where + * the index is. + */ +typedef struct ecoff_extr { + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:13; /* reserved for future use */ + int ifd; /* where the iss and index fields point into */ + SYMR asym; /* symbol for the external */ + } EXTR, *pEXTR; +#define extNil ((pEXTR)0) +#define cbEXTR sizeof(EXTR) + + +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ + +/* + * Type Information Record + */ +typedef struct { + unsigned fBitfield : 1; /* set if bit width is specified */ + unsigned continued : 1; /* indicates additional TQ info in next AUX */ + unsigned bt : 6; /* basic type */ + unsigned tq4 : 4; + unsigned tq5 : 4; + /* ---- 16 bit boundary ---- */ + unsigned tq0 : 4; + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq2 : 4; + unsigned tq3 : 4; + } TIR, *pTIR; +#define cbTIR sizeof(TIR) +#define tiNil ((pTIR)0) +#define itqMax 6 + +/* + * Relative symbol record + * + * If the rfd field is 4095, the index field indexes into the global symbol + * table. + */ + +typedef struct { + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ + } RNDXR, *pRNDXR; +#define cbRNDXR sizeof(RNDXR) +#define rndxNil ((pRNDXR)0) + +/* dense numbers or sometimes called block numbers are stored in this type, + * a rfd of 0xffffffff is an index into the global table. + */ +typedef struct { + unsigned long rfd; /* index into the file table */ + unsigned long index; /* index int sym/aux/iss tables */ + } DNR, *pDNR; +#define cbDNR sizeof(DNR) +#define dnNil ((pDNR)0) + + + +/* + * Auxillary information occurs only if needed. + * It ALWAYS occurs in this order when present. + + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + btTypedef): + rsym.index == iaux for btSet or btRange + else rsym.index == isym + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays + dimLow0 + dimHigh0 + ... + rndxMax-1 + dimLowMax-1 + dimHighMax-1 + width in bits if (bit field), width in bits. + */ +#define cAuxMax (6 + (idimMax*3)) + +/* a union of all possible info in the AUX universe */ +typedef union { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + long dnLow; /* low dimension */ + long dnHigh; /* high dimension */ + long isym; /* symbol table index (end of proc) */ + long iss; /* index into string space (not used) */ + long width; /* width for non-default sized struc fields */ + long count; /* count of ranges for variant arm */ + } AUXU, *pAUXU; +#define cbAUXU sizeof(AUXU) +#define auxNil ((pAUXU)0) +#define iauxNil -1 + + +/* + * Optimization symbols + * + * Optimization symbols contain some overlap information with the normal + * symbol table. In particular, the proc information + * is somewhat redundant but necessary to easily find the other information + * present. + * + * All of the offsets are relative to the beginning of the last otProc + */ + +typedef struct { + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + unsigned long offset; /* relative offset this occured */ + } OPTR, *pOPTR; +#define optNil ((pOPTR) 0) +#define cbOPTR sizeof(OPTR) +#define ioptNil -1 + +/* + * File Indirect + * + * When a symbol is referenced across files the following procedure is used: + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table + * + */ + +typedef long RFDT, *pRFDT; +#define cbRFDT sizeof(RFDT) +#define rfdNil -1 + +/* + * The file indirect table in the mips loader is known as an array of FITs. + * This is done to keep the code in the loader readable in the area where + * these tables are merged. Note this is only a name change. + */ +typedef long FIT, *pFIT; +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) + +#ifdef _LANGUAGE_PASCAL +#define ifdNil -1 +#define ilnNil -1 +#define ipdNil -1 +#define ilineNil -1 +#define isymNil -1 +#define indexNil 16#fffff +#define issNil -1 +#define issNull 0 +#define itqMax 6 +#define iauxNil -1 +#define ioptNil -1 +#define rfdNil -1 +#define ifiNil -1 +#endif /* _LANGUAGE_PASCAL */ + + +/* Dense numbers + * + * Rather than use file index, symbol index pairs to represent symbols + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. + */ + +/* + * The following table defines the meaning of each SYM field as + * a function of the "st". (scD/B == scData OR scBss) + * + * Note: the value "isymMac" is used by symbols that have the concept + * of enclosing a block of related information. This value is the + * isym of the first symbol AFTER the end associated with the primary + * symbol. For example if a procedure was at isym==90 and had an + * isymMac==155, the associated end would be at isym==154, and the + * symbol at 155 would probably (although not necessarily) be the + * symbol for the next procedure. This allows rapid skipping over + * internal information of various sorts. "stEnd"s ALWAYS have the + * isym of the primary symbol that started the block. + * + +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) + (mipsread thinks the case below has a bit, not byte, offset.) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) + +stBlock scText address isymMac (text block) + (the code seems to think that rather than scNil, we see scInfo for + the two cases below.) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) + + (New types added by SGI to simplify things:) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) + +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) + +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol + +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) + + * + */ +#endif diff --git a/contrib/gdb/include/coff/symconst.h b/contrib/gdb/include/coff/symconst.h new file mode 100644 index 000000000000..f40eef2a3115 --- /dev/null +++ b/contrib/gdb/include/coff/symconst.h @@ -0,0 +1,177 @@ +/* Declarations of constants for internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* glevels for field in FDR */ +#define GLEVEL_0 2 +#define GLEVEL_1 1 +#define GLEVEL_2 0 /* for upward compat reasons. */ +#define GLEVEL_3 3 + +/* magic number fo symheader */ +#define magicSym 0x7009 +/* The Alpha uses this value instead, for some reason. */ +#define magicSym2 0x1992 + +/* Language codes */ +#define langC 0 +#define langPascal 1 +#define langFortran 2 +#define langAssembler 3 /* one Assembley inst might map to many mach */ +#define langMachine 4 +#define langNil 5 +#define langAda 6 +#define langPl1 7 +#define langCobol 8 +#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ +#define langCplusplus 9 /* FIXME: Collides with langStdc */ +#define langCplusplusV2 10 /* SGI addition */ +#define langMax 11 /* maximun allowed 32 -- 5 bits */ + +/* The following are value definitions for the fields in the SYMR */ + +/* + * Storage Classes + */ + +#define scNil 0 +#define scText 1 /* text symbol */ +#define scData 2 /* initialized data symbol */ +#define scBss 3 /* un-initialized data symbol */ +#define scRegister 4 /* value of symbol is register number */ +#define scAbs 5 /* value of symbol is absolute */ +#define scUndefined 6 /* who knows? */ +#define scCdbLocal 7 /* variable's value is IN se->va.?? */ +#define scBits 8 /* this is a bit field */ +#define scCdbSystem 9 /* variable's value is IN CDB's address space */ +#define scDbx 9 /* overlap dbx internal use */ +#define scRegImage 10 /* register value saved on stack */ +#define scInfo 11 /* symbol contains debugger information */ +#define scUserStruct 12 /* address in struct user for current process */ +#define scSData 13 /* load time only small data */ +#define scSBss 14 /* load time only small common */ +#define scRData 15 /* load time only read only data */ +#define scVar 16 /* Var parameter (fortran,pascal) */ +#define scCommon 17 /* common variable */ +#define scSCommon 18 /* small common */ +#define scVarRegister 19 /* Var parameter in a register */ +#define scVariant 20 /* Variant record */ +#define scSUndefined 21 /* small undefined(external) data */ +#define scInit 22 /* .init section symbol */ +#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ +#define scXData 24 /* exception handling data */ +#define scPData 25 /* Procedure section */ +#define scFini 26 /* .fini section */ +#define scRConst 27 /* .rconst section */ +#define scMax 32 + + +/* + * Symbol Types + */ + +#define stNil 0 /* Nuthin' special */ +#define stGlobal 1 /* external symbol */ +#define stStatic 2 /* static */ +#define stParam 3 /* procedure argument */ +#define stLocal 4 /* local variable */ +#define stLabel 5 /* label */ +#define stProc 6 /* " " Procedure */ +#define stBlock 7 /* beginnning of block */ +#define stEnd 8 /* end (of anything) */ +#define stMember 9 /* member (of anything - struct/union/enum */ +#define stTypedef 10 /* type definition */ +#define stFile 11 /* file name */ +#define stRegReloc 12 /* register relocation */ +#define stForward 13 /* forwarding address */ +#define stStaticProc 14 /* load time only static procs */ +#define stConstant 15 /* const */ +#define stStaParam 16 /* Fortran static parameters */ + /* These new symbol types have been recently added to SGI machines. */ +#define stStruct 26 /* Beginning of block defining a struct type */ +#define stUnion 27 /* Beginning of block defining a union type */ +#define stEnum 28 /* Beginning of block defining an enum type */ +#define stIndirect 34 /* Indirect type specification */ + /* Pseudo-symbols - internal to debugger */ +#define stStr 60 /* string */ +#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ +#define stExpr 62 /* 2+2 vs. 4 */ +#define stType 63 /* post-coersion SER */ +#define stMax 64 + +/* definitions for fields in TIR */ + +/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ +#define tqNil 0 /* bt is what you see */ +#define tqPtr 1 /* pointer */ +#define tqProc 2 /* procedure */ +#define tqArray 3 /* duh */ +#define tqFar 4 /* longer addressing - 8086/8 land */ +#define tqVol 5 /* volatile */ +#define tqConst 6 /* const */ +#define tqMax 8 + +/* basic types as seen in ti.bt */ +#define btNil 0 /* undefined (also, enum members) */ +#define btAdr 1 /* address - integer same size as pointer */ +#define btChar 2 /* character */ +#define btUChar 3 /* unsigned character */ +#define btShort 4 /* short */ +#define btUShort 5 /* unsigned short */ +#define btInt 6 /* int */ +#define btUInt 7 /* unsigned int */ +#define btLong 8 /* long */ +#define btULong 9 /* unsigned long */ +#define btFloat 10 /* float (real) */ +#define btDouble 11 /* Double (real) */ +#define btStruct 12 /* Structure (Record) */ +#define btUnion 13 /* Union (variant) */ +#define btEnum 14 /* Enumerated */ +#define btTypedef 15 /* defined via a typedef, isymRef points */ +#define btRange 16 /* subrange of int */ +#define btSet 17 /* pascal sets */ +#define btComplex 18 /* fortran complex */ +#define btDComplex 19 /* fortran double complex */ +#define btIndirect 20 /* forward or unnamed typedef */ +#define btFixedDec 21 /* Fixed Decimal */ +#define btFloatDec 22 /* Float Decimal */ +#define btString 23 /* Varying Length Character String */ +#define btBit 24 /* Aligned Bit String */ +#define btPicture 25 /* Picture */ +#define btVoid 26 /* void */ +#define btLongLong 27 /* long long */ +#define btULongLong 28 /* unsigned long long */ +#define btMax 64 + +#if (_MFG == _MIPS) +/* optimization type codes */ +#define otNil 0 +#define otReg 1 /* move var to reg */ +#define otBlock 2 /* begin basic block */ +#define otProc 3 /* procedure */ +#define otInline 4 /* inline procedure */ +#define otEnd 5 /* whatever you started */ +#define otMax 6 /* KEEP UP TO DATE */ +#endif /* (_MFG == _MIPS) */ diff --git a/contrib/gdb/include/coff/w65.h b/contrib/gdb/include/coff/w65.h new file mode 100644 index 000000000000..c80b9fee5de0 --- /dev/null +++ b/contrib/gdb/include/coff/w65.h @@ -0,0 +1,201 @@ +/*** coff information for WDC 65816 */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + + +#define W65MAGIC 0x6500 + + +#define W65BADMAG(x) (((x).f_magic!=W65MAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[4]; /* line number */ +}; + +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)); +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + +/* The external reloc has an offset field, because some of the reloc + types on the w65 don't have room in the instruction for the entire + offset - eg the strange jump and high page addressing modes */ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_offset[4]; + char r_type[2]; + char r_stuff[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 16 + + + + diff --git a/contrib/gdb/include/coff/we32k.h b/contrib/gdb/include/coff/we32k.h new file mode 100644 index 000000000000..414c4506e0b0 --- /dev/null +++ b/contrib/gdb/include/coff/we32k.h @@ -0,0 +1,206 @@ +/*** coff information for we32k */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) +#define F_BM32B (0020000) +#define F_BM32MAU (0040000) + +#define WE32KMAGIC 0x170 /* we32k sans transfer vector */ +#define FBOMAGIC 0x170 /* we32k sans transfer vector */ +#define MTVMAGIC 0x171 /* we32k with transfer vector */ +#define RBOMAGIC 0x172 /* reserved */ +#define WE32KBADMAG(x) (((x).f_magic != WE32KMAGIC) \ + && ((x).f_magic != FBOMAGIC) \ + && ((x).f_magic != RBOMAGIC) \ + && ((x).f_magic != MTVMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + +#define AOUTSZ (sizeof(AOUTHDR)) + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _TV ".tv" +#define _INIT ".init" +#define _FINI ".fini" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + +# define _ETEXT "etext" + + +/********************** RELOCATION DIRECTIVES **********************/ + + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ sizeof(RELOC) + diff --git a/contrib/gdb/include/coff/z8k.h b/contrib/gdb/include/coff/z8k.h new file mode 100644 index 000000000000..48817952829f --- /dev/null +++ b/contrib/gdb/include/coff/z8k.h @@ -0,0 +1,201 @@ +/*** coff information for Zilog Z800N */ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Type of cpu is stored in flags */ +#define F_Z8001 0x1000 +#define F_Z8002 0x2000 +#define F_MACHMASK 0xf000 + +#define Z8KMAGIC 0x8000 + +#define Z8KBADMAG(x) (((x).f_magic!=Z8KMAGIC)) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTHDRSZ (sizeof(AOUTHDR)) +#define AOUTSZ (sizeof(AOUTHDR)) + + + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" + + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[4]; /* line number */ +}; + +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) (ext->l_lnno)); +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_32(abfd,val, (bfd_byte *) (ext->l_lnno)); + +#define LINENO struct external_lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + + + +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + + +/********************** RELOCATION DIRECTIVES **********************/ + +/* The external reloc has an offset field, because some of the reloc + types on the z8k don't have room in the instruction for the entire + offset - eg with segments */ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_offset[4]; + char r_type[2]; + char r_stuff[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 16 + diff --git a/contrib/gdb/include/demangle.h b/contrib/gdb/include/demangle.h new file mode 100644 index 000000000000..d4d0a3f428e3 --- /dev/null +++ b/contrib/gdb/include/demangle.h @@ -0,0 +1,108 @@ +/* Defs for interface to demanglers. + Copyright 1992, 1995, 1996 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#ifdef IN_GCC + +/* Add prototype support. */ +#ifndef PROTO +#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) +#define PROTO(ARGS) ARGS +#else +#define PROTO(ARGS) () +#endif +#endif + +#define PARAMS(ARGS) PROTO(ARGS) + +#ifdef __STDC__ +#define PTR void * +#else +#ifndef const +#define const +#endif +#define PTR char * +#endif + +#else /* ! IN_GCC */ +#include +#endif /* IN_GCC */ + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM) + +extern char * +cplus_demangle PARAMS ((const char *mangled, int options)); + +extern int +cplus_demangle_opname PARAMS ((const char *opname, char *result, int options)); + +extern const char * +cplus_mangle_opname PARAMS ((const char *opname, int options)); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling PARAMS ((int ch)); + +#endif /* DEMANGLE_H */ diff --git a/contrib/gdb/include/dis-asm.h b/contrib/gdb/include/dis-asm.h new file mode 100644 index 000000000000..d70bd514e9cd --- /dev/null +++ b/contrib/gdb/include/dis-asm.h @@ -0,0 +1,175 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#include +#include "bfd.h" + +typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + FILE *stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + int buffer_length; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (FPRINTF_FUNC), \ + (INFO).stream = (STREAM), \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).flags = 0, \ + (INFO).insn_info_valid = 0 + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/contrib/gdb/include/elf/ChangeLog b/contrib/gdb/include/elf/ChangeLog new file mode 100644 index 000000000000..b56f9bb1d8dd --- /dev/null +++ b/contrib/gdb/include/elf/ChangeLog @@ -0,0 +1,195 @@ +Mon Feb 19 01:55:56 1996 Doug Evans + + * sparc.h (R_SPARC_{PLT32,HIPLT22,LOPLT10,PCPLT32,PCPLT22, + PCPLT10,5,6}): Don't define ifdef SPARC64_OLD_RELOCS. + +Tue Feb 6 11:33:58 1996 Doug Evans + + * sparc.h (enum sparc_elf_reloc_type): Define. + +Wed Jan 17 09:09:16 1996 Doug Evans + + * common.h: Define EM_SPARC32PLUS. + * sparc.h: New file. + +Thu Jan 11 16:27:34 1996 Michael Meissner + + * ppc.h (SHF_EXCLUDE, SHT_ORDERED): New fields from the abi. + +Thu Nov 30 16:47:18 1995 Ian Lance Taylor + + * internal.h (struct elf_segment_map): Add includes_filehdr and + includes_phdrs fields. + +Tue Nov 28 16:58:10 1995 Ian Lance Taylor + + * internal.h (struct elf_segment_map): Define. + +Tue Oct 31 15:19:36 1995 Fred Fish + + * common.h, dwarf.h, external.h, hppa.h, internal.h, + mips.h, ppc.h: Protect against multiple inclusions. + +Thu Sep 21 13:51:58 1995 Michael Meissner + + * ppc.h (EF_PPC_RELOCATABLE_LIB): Add new flag bit. + +Fri Sep 1 15:32:17 1995 Kazumoto Kojima + + * mips.h: Add some definitions used on Irix 5. + +Tue Jun 20 10:18:28 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa.h (CPU_PA_RISC1_0): Protect from redefinitions. + (CPU_PA_RISC1_1): Likewise. + +Wed Mar 8 18:14:37 1995 Michael Meissner + + * ppc.h: New file for PowerPC support. + +Tue Feb 14 13:59:13 1995 Michael Meissner + + * common.h (EM_PPC): Use offical value of 20, not 17. + (EM_PPC_OLD): Define this to be the old value of EM_PPC. + + +Tue Jan 24 09:40:59 1995 Michael Meissner + + * common.h (EM_PPC): New macro, PowerPC machine id. + +Tue Jan 17 10:51:38 1995 Ian Lance Taylor + + * mips.h (SHT_MIPS_MSYM, SHT_MIPS_DWARF, SHT_MIPS_EVENTS): Define. + + +Mon Oct 17 13:43:59 1994 Ian Lance Taylor + + * internal.h (Elf_Internal_Shdr): Remove rawdata and size fields. + Add bfd_section field. + +Tue May 24 16:11:50 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (Elf32_External_gptab): Define. + +Mon May 16 13:22:04 1994 Jeff Law (law@snake.cs.utah.edu) + + * common.h (EM_HPPA): Delete. + (EM_PARISC): Add. + * hppa.h: New file. + +Mon May 9 13:27:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * common.h (SHN_LORESERVE): Rename from SHN_LORESERV. + (ELF32_R_TYPE, ELF32_R_INFO): Don't rely on size of unsigned char. + (ELF64_R_TYPE): Don't rely on size of unsigned long. + +Mon Apr 25 15:53:09 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h (Elf_Internal_Shdr): Use PTR, not void *. + +Fri Mar 11 00:34:59 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips.h (SHN_MIPS_TEXT, SHN_MIPS_DATA): Define. + +Sat Mar 5 14:08:54 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * internal.h: Remove Elf32_*, Elf64_* typedefs. These names + cause conflicts with system headers, e.g. link.h in gdb/solib.c. + Combine 32- and 64-bit versions of *_Internal_Dyn. + * common.h: Replace uses of Elf64_Word, Elf64_Xword typedefs + by their expansion. + * mips.h: Replace uses of Elf32_Word, Elf32_Sword, Elf32_Addr + typedefs by their expansion. Add DT_MIPS_RLD_MAP definition. + +Fri Feb 18 10:39:54 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * common.h (EM_CYGNUS_POWERPC): Define. This may be temporary, + depending upon how quickly I can find a real PowerPC ABI. + +Mon Feb 7 08:27:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * internal.h: Change HOST_64_BIT to BFD_HOST_64_BIT. + +Wed Feb 2 14:12:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * common.h: Add comments regarding value of EM_HPPA and how to + pick an unofficial value. + +Wed Nov 17 17:14:26 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (SHT_MIPS_OPTIONS): Define. + +Mon Nov 8 17:57:00 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h: Added some more MIPS ABI macro definitions. + +Wed Nov 3 22:07:17 1993 Ken Raeburn (raeburn@rtl.cygnus.com) + + * common.h (EM_MIPS_RS4_BE): New macro. + +Tue Oct 12 07:28:18 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h: New file. MIPS ABI specific information. + +Mon Jun 21 13:13:43 1993 Ken Raeburn (raeburn@poseidon.cygnus.com) + + * internal.h: Combined 32- and 64-bit versions of all structures + except *_Internal_Dyn. This will simply the assembler interface, + and some bfd code. + +Tue May 25 02:00:16 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * external.h, internal.h, common.h: Added 64-bit versions of some + structures and macros. Renamed old versions to put "32" in the + name. Some are unchanged. + +Thu Apr 29 12:12:20 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * common.h (EM_HPPA, NT_VERSION, STN_UNDEF, DT_*): New macros. + * external.h (Elf_External_Dyn): New type. + + * internal.h (Elf_Intenral_Shdr): New field `size'. + (Elf_Internal_Dyn): New type. + +Tue Apr 20 16:03:45 1993 Fred Fish (fnf@cygnus.com) + + * dwarf.h (LANG_CHILL): Change value to one randomly picked in + the user defined range, to reduce probability of collisions. + +Sun Nov 15 09:34:02 1992 Fred Fish (fnf@cygnus.com) + + * dwarf.h (AT_src_coords): Whitespace change only. + * dwarf.h (AT_body_begin, AT_body_end, LANG_MODULA2): + Add from latest gcc. + * dwarf.h (LANG_CHILL): Add as GNU extension. + +Sat Aug 1 13:46:53 1992 Fred Fish (fnf@cygnus.com) + + * dwarf.h: Replace with current version from gcc distribution. + +Fri Jun 19 19:05:09 1992 John Gilmore (gnu at cygnus.com) + + * internal.h: Add real struct tags to all the Type_Defs, so they + can be used in prototypes where the Type_Defs are not known. + +Fri Apr 3 20:58:58 1992 Mark Eichin (eichin at cygnus.com) + + * common.h: added ELF_R_{SYM,TYPE,INFO} for handling relocation + info + added EM_MIPS, and corrected value of EM_860 based on System V ABI + manual. + + * external.h: added Elf_External_{Rel,Rela}. + + * internal.h: added Elf_Internal_{Rel,Rela}. + added rawdata to Elf_Internal_Shdr. + +Sat Nov 30 20:43:59 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * common.h, dwarf.h, external.h, internal.h, ChangeLog; moved from + ../elf- + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/include/elf/common.h b/contrib/gdb/include/elf/common.h new file mode 100644 index 000000000000..c9e74741c575 --- /dev/null +++ b/contrib/gdb/include/elf/common.h @@ -0,0 +1,239 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that are common to both the internal and external representations. + For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory) + and external (in-file) representations. */ + +#ifndef _ELF_COMMON_H +#define _ELF_COMMON_H + +/* Fields in e_ident[] */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7F /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 /* File version */ + +#define EI_PAD 7 /* Start of padding bytes */ + + +/* Values for e_type, which identifies the object file type */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOPROC 0xFF00 /* Processor-specific */ +#define ET_HIPROC 0xFFFF /* Processor-specific */ + +/* Values for e_machine, which identifies the architecture */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ + +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + +#define EM_PPC 20 /* PowerPC */ + +/* If it is necessary to assign new unofficial EM_* values, please pick large + random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision + with official or non-GNU unofficial values. */ + +/* Cygnus PowerPC ELF backend. Written in the absence of an ABI. */ +#define EM_CYGNUS_POWERPC 0x9025 + +/* Old version of PowerPC, this should be removed shortly. */ +#define EM_PPC_OLD 17 + + +/* Values for e_version */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ + +/* Values for program header, p_type field */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_LOPROC 0x70000000 /* Processor-specific */ +#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ + +/* Program segment permissions, in program header p_flags field */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ + +/* Values for section header, sh_type field */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program specific (private) data */ +#define SHT_SYMTAB 2 /* Link editing symbol table */ +#define SHT_STRTAB 3 /* A string table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* A symbol hash table */ +#define SHT_DYNAMIC 6 /* Information for dynamic linking */ +#define SHT_NOTE 7 /* Information that marks file */ +#define SHT_NOBITS 8 /* Section occupies no space in file */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Dynamic linking symbol table */ +#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */ +#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */ +#define SHT_LOUSER 0x80000000 /* Application-specific semantics */ +#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */ + +/* Values for section header, sh_flags field */ + +#define SHF_WRITE (1 << 0) /* Writable data during execution */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */ +#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */ + +/* Values of note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ + +/* Values of note segment descriptor types for object files. */ +/* (Only for hppa right now. Should this be moved elsewhere?) */ + +#define NT_VERSION 1 /* Contains a version string. */ + +/* These three macros disassemble and assemble a symbol table st_info field, + which contains the symbol binding and symbol type. The STB_ and STT_ + defines identify the binding and type. */ + +#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4) +#define ELF_ST_TYPE(val) ((val) & 0xF) +#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF)) + +#define STN_UNDEF 0 /* undefined symbol index */ + +#define STB_LOCAL 0 /* Symbol not visible outside obj */ +#define STB_GLOBAL 1 /* Symbol visible outside obj */ +#define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_LOPROC 13 /* Application-specific semantics */ +#define STB_HIPROC 15 /* Application-specific semantics */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol gives a file name */ +#define STT_LOPROC 13 /* Application-specific semantics */ +#define STT_HIPROC 15 /* Application-specific semantics */ + +/* Special section indices, which may show up in st_shndx fields, among + other places. */ + +#define SHN_UNDEF 0 /* Undefined section reference */ +#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ +#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */ +#define SHN_HIPROC 0xFF1F /* End range of appl-specific */ +#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */ +#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */ + +/* relocation info handling macros */ + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((i) & 0xff) +#define ELF32_R_INFO(s,t) (((s) << 8) + ((t) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(s,t) (((bfd_vma) (s) << 32) + (bfd_vma) (t)) + +/* Dynamic section tags */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +#endif /* _ELF_COMMON_H */ diff --git a/contrib/gdb/include/elf/dwarf.h b/contrib/gdb/include/elf/dwarf.h new file mode 100644 index 000000000000..4333d5eda40f --- /dev/null +++ b/contrib/gdb/include/elf/dwarf.h @@ -0,0 +1,319 @@ +/* Declarations and definitions of codes relating to the DWARF symbolic + debugging information format. + + Written by Ron Guilmette (rfg@ncd.com) + +Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 1.0.1 (April 8, 1992) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. +*/ + +#ifndef _ELF_DWARF_H +#define _ELF_DWARF_H + +/* Tag names and codes. */ + +enum dwarf_tag { + TAG_padding = 0x0000, + TAG_array_type = 0x0001, + TAG_class_type = 0x0002, + TAG_entry_point = 0x0003, + TAG_enumeration_type = 0x0004, + TAG_formal_parameter = 0x0005, + TAG_global_subroutine = 0x0006, + TAG_global_variable = 0x0007, + /* 0x0008 -- reserved */ + /* 0x0009 -- reserved */ + TAG_label = 0x000a, + TAG_lexical_block = 0x000b, + TAG_local_variable = 0x000c, + TAG_member = 0x000d, + /* 0x000e -- reserved */ + TAG_pointer_type = 0x000f, + TAG_reference_type = 0x0010, + TAG_compile_unit = 0x0011, + TAG_string_type = 0x0012, + TAG_structure_type = 0x0013, + TAG_subroutine = 0x0014, + TAG_subroutine_type = 0x0015, + TAG_typedef = 0x0016, + TAG_union_type = 0x0017, + TAG_unspecified_parameters = 0x0018, + TAG_variant = 0x0019, + TAG_common_block = 0x001a, + TAG_common_inclusion = 0x001b, + TAG_inheritance = 0x001c, + TAG_inlined_subroutine = 0x001d, + TAG_module = 0x001e, + TAG_ptr_to_member_type = 0x001f, + TAG_set_type = 0x0020, + TAG_subrange_type = 0x0021, + TAG_with_stmt = 0x0022, + + /* GNU extensions */ + + TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */ + TAG_namelist = 0x8001, /* For Fortran 90 */ + TAG_function_template = 0x8002, /* for C++ */ + TAG_class_template = 0x8003 /* for C++ */ +}; + +#define TAG_lo_user 0x8000 /* implementation-defined range start */ +#define TAG_hi_user 0xffff /* implementation-defined range end */ +#define TAG_source_file TAG_compile_unit /* for backward compatibility */ + +/* Form names and codes. */ + +enum dwarf_form { + FORM_ADDR = 0x1, + FORM_REF = 0x2, + FORM_BLOCK2 = 0x3, + FORM_BLOCK4 = 0x4, + FORM_DATA2 = 0x5, + FORM_DATA4 = 0x6, + FORM_DATA8 = 0x7, + FORM_STRING = 0x8 +}; + +/* Attribute names and codes. */ + +enum dwarf_attribute { + AT_sibling = (0x0010|FORM_REF), + AT_location = (0x0020|FORM_BLOCK2), + AT_name = (0x0030|FORM_STRING), + AT_fund_type = (0x0050|FORM_DATA2), + AT_mod_fund_type = (0x0060|FORM_BLOCK2), + AT_user_def_type = (0x0070|FORM_REF), + AT_mod_u_d_type = (0x0080|FORM_BLOCK2), + AT_ordering = (0x0090|FORM_DATA2), + AT_subscr_data = (0x00a0|FORM_BLOCK2), + AT_byte_size = (0x00b0|FORM_DATA4), + AT_bit_offset = (0x00c0|FORM_DATA2), + AT_bit_size = (0x00d0|FORM_DATA4), + /* (0x00e0|FORM_xxxx) -- reserved */ + AT_element_list = (0x00f0|FORM_BLOCK4), + AT_stmt_list = (0x0100|FORM_DATA4), + AT_low_pc = (0x0110|FORM_ADDR), + AT_high_pc = (0x0120|FORM_ADDR), + AT_language = (0x0130|FORM_DATA4), + AT_member = (0x0140|FORM_REF), + AT_discr = (0x0150|FORM_REF), + AT_discr_value = (0x0160|FORM_BLOCK2), + /* (0x0170|FORM_xxxx) -- reserved */ + /* (0x0180|FORM_xxxx) -- reserved */ + AT_string_length = (0x0190|FORM_BLOCK2), + AT_common_reference = (0x01a0|FORM_REF), + AT_comp_dir = (0x01b0|FORM_STRING), + AT_const_value_string = (0x01c0|FORM_STRING), + AT_const_value_data2 = (0x01c0|FORM_DATA2), + AT_const_value_data4 = (0x01c0|FORM_DATA4), + AT_const_value_data8 = (0x01c0|FORM_DATA8), + AT_const_value_block2 = (0x01c0|FORM_BLOCK2), + AT_const_value_block4 = (0x01c0|FORM_BLOCK4), + AT_containing_type = (0x01d0|FORM_REF), + AT_default_value_addr = (0x01e0|FORM_ADDR), + AT_default_value_data2 = (0x01e0|FORM_DATA2), + AT_default_value_data4 = (0x01e0|FORM_DATA4), + AT_default_value_data8 = (0x01e0|FORM_DATA8), + AT_default_value_string = (0x01e0|FORM_STRING), + AT_friends = (0x01f0|FORM_BLOCK2), + AT_inline = (0x0200|FORM_STRING), + AT_is_optional = (0x0210|FORM_STRING), + AT_lower_bound_ref = (0x0220|FORM_REF), + AT_lower_bound_data2 = (0x0220|FORM_DATA2), + AT_lower_bound_data4 = (0x0220|FORM_DATA4), + AT_lower_bound_data8 = (0x0220|FORM_DATA8), + AT_private = (0x0240|FORM_STRING), + AT_producer = (0x0250|FORM_STRING), + AT_program = (0x0230|FORM_STRING), + AT_protected = (0x0260|FORM_STRING), + AT_prototyped = (0x0270|FORM_STRING), + AT_public = (0x0280|FORM_STRING), + AT_pure_virtual = (0x0290|FORM_STRING), + AT_return_addr = (0x02a0|FORM_BLOCK2), + AT_abstract_origin = (0x02b0|FORM_REF), + AT_start_scope = (0x02c0|FORM_DATA4), + AT_stride_size = (0x02e0|FORM_DATA4), + AT_upper_bound_ref = (0x02f0|FORM_REF), + AT_upper_bound_data2 = (0x02f0|FORM_DATA2), + AT_upper_bound_data4 = (0x02f0|FORM_DATA4), + AT_upper_bound_data8 = (0x02f0|FORM_DATA8), + AT_virtual = (0x0300|FORM_STRING), + + /* GNU extensions. */ + + AT_sf_names = (0x8000|FORM_DATA4), + AT_src_info = (0x8010|FORM_DATA4), + AT_mac_info = (0x8020|FORM_DATA4), + AT_src_coords = (0x8030|FORM_DATA4), + AT_body_begin = (0x8040|FORM_ADDR), + AT_body_end = (0x8050|FORM_ADDR) +}; + +#define AT_lo_user 0x8000 /* implementation-defined range start */ +#define AT_hi_user 0xffff /* implementation-defined range end */ + +/* Location atom names and codes. */ + +enum dwarf_location_atom { + OP_REG = 0x01, + OP_BASEREG = 0x02, + OP_ADDR = 0x03, + OP_CONST = 0x04, + OP_DEREF2 = 0x05, + OP_DEREF4 = 0x06, + OP_ADD = 0x07 +}; + +#define OP_LO_USER 0x80 /* implementation-defined range start */ +#define OP_HI_USER 0xff /* implementation-defined range end */ + +/* Fundamental type names and codes. */ + +enum dwarf_fundamental_type { + FT_char = 0x0001, + FT_signed_char = 0x0002, + FT_unsigned_char = 0x0003, + FT_short = 0x0004, + FT_signed_short = 0x0005, + FT_unsigned_short = 0x0006, + FT_integer = 0x0007, + FT_signed_integer = 0x0008, + FT_unsigned_integer = 0x0009, + FT_long = 0x000a, + FT_signed_long = 0x000b, + FT_unsigned_long = 0x000c, + FT_pointer = 0x000d, /* an alias for (void *) */ + FT_float = 0x000e, + FT_dbl_prec_float = 0x000f, + FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */ + FT_complex = 0x0011, /* breaks "classic" svr4 SDB */ + FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */ + /* 0x0013 -- reserved */ + FT_void = 0x0014, + FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */ + FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */ + FT_label = 0x0017, + + /* GNU extensions + The low order byte must indicate the size (in bytes) for the type. + All of these types will probably break "classic" svr4 SDB */ + + FT_long_long = 0x8008, + FT_signed_long_long = 0x8108, + FT_unsigned_long_long = 0x8208, + + FT_int8 = 0x9001, + FT_signed_int8 = 0x9101, + FT_unsigned_int8 = 0x9201, + FT_int16 = 0x9302, + FT_signed_int16 = 0x9402, + FT_unsigned_int16 = 0x9502, + FT_int32 = 0x9604, + FT_signed_int32 = 0x9704, + FT_unsigned_int32 = 0x9804, + FT_int64 = 0x9908, + FT_signed_int64 = 0x9a08, + FT_unsigned_int64 = 0x9b08, + + FT_real32 = 0xa004, + FT_real64 = 0xa108, + FT_real96 = 0xa20c, + FT_real128 = 0xa310 +}; + +#define FT_lo_user 0x8000 /* implementation-defined range start */ +#define FT_hi_user 0xffff /* implementation defined range end */ + +/* Type modifier names and codes. */ + +enum dwarf_type_modifier { + MOD_pointer_to = 0x01, + MOD_reference_to = 0x02, + MOD_const = 0x03, + MOD_volatile = 0x04 +}; + +#define MOD_lo_user 0x80 /* implementation-defined range start */ +#define MOD_hi_user 0xff /* implementation-defined range end */ + +/* Array ordering names and codes. */ + +enum dwarf_array_dim_ordering { + ORD_row_major = 0, + ORD_col_major = 1 +}; + +/* Array subscript format names and codes. */ + +enum dwarf_subscr_data_formats { + FMT_FT_C_C = 0x0, + FMT_FT_C_X = 0x1, + FMT_FT_X_C = 0x2, + FMT_FT_X_X = 0x3, + FMT_UT_C_C = 0x4, + FMT_UT_C_X = 0x5, + FMT_UT_X_C = 0x6, + FMT_UT_X_X = 0x7, + FMT_ET = 0x8 +}; + +/* Derived from above for ease of use. */ + +#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \ + (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \ + | ((_UB_CONST_P) ? 0 : 2) \ + | ((_LB_CONST_P) ? 0 : 1)) + +/* Source language names and codes. */ + +enum dwarf_source_language { + LANG_C89 = 0x00000001, + LANG_C = 0x00000002, + LANG_ADA83 = 0x00000003, + LANG_C_PLUS_PLUS = 0x00000004, + LANG_COBOL74 = 0x00000005, + LANG_COBOL85 = 0x00000006, + LANG_FORTRAN77 = 0x00000007, + LANG_FORTRAN90 = 0x00000008, + LANG_PASCAL83 = 0x00000009, + LANG_MODULA2 = 0x0000000a, + + /* GNU extensions */ + + LANG_CHILL = 0x00009af3 /* random value for GNU Chill */ +}; + +#define LANG_lo_user 0x00008000 /* implementation-defined range start */ +#define LANG_hi_user 0x0000ffff /* implementation-defined range end */ + +/* Names and codes for GNU "macinfo" extension. */ + +enum dwarf_macinfo_record_type { + MACINFO_start = 's', + MACINFO_resume = 'r', + MACINFO_define = 'd', + MACINFO_undef = 'u' +}; + +#endif /* _ELF_DWARF_H */ diff --git a/contrib/gdb/include/elf/external.h b/contrib/gdb/include/elf/external.h new file mode 100644 index 000000000000..e6618cb752fa --- /dev/null +++ b/contrib/gdb/include/elf/external.h @@ -0,0 +1,195 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented externally by the BFD library. + I.E. it describes the in-file representation of ELF. It requires + the elf-common.h file which contains the portions that are common to + both the internal and external representations. */ + +/* The 64-bit stuff is kind of random. Perhaps someone will publish a + spec someday. */ + +#ifndef _ELF_EXTERNAL_H +#define _ELF_EXTERNAL_H + +/* ELF Header (32-bit implementations) */ + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[4]; /* Entry point virtual address */ + unsigned char e_phoff[4]; /* Program header table file offset */ + unsigned char e_shoff[4]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf32_External_Ehdr; + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[8]; /* Entry point virtual address */ + unsigned char e_phoff[8]; /* Program header table file offset */ + unsigned char e_shoff[8]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf64_External_Ehdr; + +/* Program header */ + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_offset[4]; /* Segment file offset */ + unsigned char p_vaddr[4]; /* Segment virtual address */ + unsigned char p_paddr[4]; /* Segment physical address */ + unsigned char p_filesz[4]; /* Segment size in file */ + unsigned char p_memsz[4]; /* Segment size in memory */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_align[4]; /* Segment alignment, file & memory */ +} Elf32_External_Phdr; + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_offset[8]; /* Segment file offset */ + unsigned char p_vaddr[8]; /* Segment virtual address */ + unsigned char p_paddr[8]; /* Segment physical address */ + unsigned char p_filesz[8]; /* Segment size in file */ + unsigned char p_memsz[8]; /* Segment size in memory */ + unsigned char p_align[8]; /* Segment alignment, file & memory */ +} Elf64_External_Phdr; + +/* Section header */ + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[4]; /* Miscellaneous section attributes */ + unsigned char sh_addr[4]; /* Section virtual addr at execution */ + unsigned char sh_offset[4]; /* Section file offset */ + unsigned char sh_size[4]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[4]; /* Section alignment */ + unsigned char sh_entsize[4]; /* Entry size if section holds table */ +} Elf32_External_Shdr; + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[8]; /* Miscellaneous section attributes */ + unsigned char sh_addr[8]; /* Section virtual addr at execution */ + unsigned char sh_offset[8]; /* Section file offset */ + unsigned char sh_size[8]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[8]; /* Section alignment */ + unsigned char sh_entsize[8]; /* Entry size if section holds table */ +} Elf64_External_Shdr; + +/* Symbol table entry */ + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_value[4]; /* Value of the symbol */ + unsigned char st_size[4]; /* Associated symbol size */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ +} Elf32_External_Sym; + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ + unsigned char st_value[8]; /* Value of the symbol */ + unsigned char st_size[8]; /* Associated symbol size */ +} Elf64_External_Sym; + +/* Note segments */ + +typedef struct { + unsigned char namesz[4]; /* Size of entry's owner string */ + unsigned char descsz[4]; /* Size of the note descriptor */ + unsigned char type[4]; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ +} Elf_External_Note; + +/* Relocation Entries */ +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ +} Elf32_External_Rel; + +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ + unsigned char r_addend[4]; /* Constant addend used to compute value */ +} Elf32_External_Rela; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ +} Elf64_External_Rel; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ + unsigned char r_addend[8]; /* Constant addend used to compute value */ +} Elf64_External_Rela; + +/* dynamic section structure */ + +typedef struct { + unsigned char d_tag[4]; /* entry tag value */ + union { + unsigned char d_val[4]; + unsigned char d_ptr[4]; + } d_un; +} Elf32_External_Dyn; + +typedef struct { + unsigned char d_tag[8]; /* entry tag value */ + union { + unsigned char d_val[8]; + unsigned char d_ptr[8]; + } d_un; +} Elf64_External_Dyn; + +#endif /* _ELF_EXTERNAL_H */ diff --git a/contrib/gdb/include/elf/hppa.h b/contrib/gdb/include/elf/hppa.h new file mode 100644 index 000000000000..c34077fa1947 --- /dev/null +++ b/contrib/gdb/include/elf/hppa.h @@ -0,0 +1,94 @@ +/* HPPA ELF support for BFD. + Copyright (C) 1993, 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the HPPA ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_HPPA_H +#define _ELF_HPPA_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Target processor IDs to be placed in the low 16 bits of the flags + field. Note these names are shared with SOM, and therefore do not + follow ELF naming conventions. */ + +/* PA 1.0 big endian. */ +#ifndef CPU_PA_RISC1_0 +#define CPU_PA_RISC1_0 0x0000020b +#endif + +/* PA 1.1 big endian. */ +#ifndef CPU_PA_RISC1_1 +#define CPU_PA_RISC1_1 0x00000210 +#endif + +/* PA 1.0 little endian (unsupported) is 0x0000028b. */ +/* PA 1.1 little endian (unsupported) is 0x00000290. */ + +/* Trap null address dereferences. */ +#define ELF_PARISC_TRAPNIL 0x00010000 + +/* .PARISC.archext section is present. */ +#define EF_PARISC_EXT 0x00020000 + +/* Processor specific section types. */ + +/* Holds the global offset table, a table of pointers to external + data. */ +#define SHT_PARISC_GOT SHT_LOPROC+0 + +/* Nonloadable section containing information in architecture + extensions used by the code. */ +#define SHT_PARISC_ARCH SHT_LOPROC+1 + +/* Section in which $global$ is defined. */ +#define SHT_PARISC_GLOBAL SHT_LOPROC+2 + +/* Section holding millicode routines (mul, div, rem, dyncall, etc. */ +#define SHT_PARISC_MILLI SHT_LOPROC+3 + +/* Section holding unwind information for use by debuggers. */ +#define SHT_PARISC_UNWIND SHT_LOPROC+4 + +/* Section holding the procedure linkage table. */ +#define SHT_PARISC_PLT SHT_LOPROC+5 + +/* Short initialized and uninitialized data. */ +#define SHT_PARISC_SDATA SHT_LOPROC+6 +#define SHT_PARISC_SBSS SHT_LOPROC+7 + +/* Optional section holding argument location/relocation info. */ +#define SHT_PARISC_SYMEXTN SHT_LOPROC+8 + +/* Option section for linker stubs. */ +#define SHT_PARISC_STUBS SHT_LOPROC+9 + +/* Processor specific section flags. */ + +/* This section is near the global data pointer and thus allows short + addressing modes to be used. */ +#define SHF_PARISC_SHORT 0x20000000 + +/* Processor specific symbol types. */ + +/* Millicode function entry point. */ +#define STT_PARISC_MILLICODE STT_LOPROC+0 + +#endif /* _ELF_HPPA_H */ diff --git a/contrib/gdb/include/elf/internal.h b/contrib/gdb/include/elf/internal.h new file mode 100644 index 000000000000..6375e892051d --- /dev/null +++ b/contrib/gdb/include/elf/internal.h @@ -0,0 +1,207 @@ +/* ELF support for BFD. + Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented internally in the BFD library. + I.E. it describes the in-memory representation of ELF. It requires + the elf-common.h file which contains the portions that are common to + both the internal and external representations. */ + + +/* NOTE that these structures are not kept in the same order as they appear + in the object file. In some cases they've been reordered for more optimal + packing under various circumstances. */ + +#ifndef _ELF_INTERNAL_H +#define _ELF_INTERNAL_H + +/* ELF Header */ + +#define EI_NIDENT 16 /* Size of e_ident[] */ + +typedef struct elf_internal_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + bfd_vma e_entry; /* Entry point virtual address */ + bfd_signed_vma e_phoff; /* Program header table file offset */ + bfd_signed_vma e_shoff; /* Section header table file offset */ + unsigned long e_version; /* Identifies object file version */ + unsigned long e_flags; /* Processor-specific flags */ + unsigned short e_type; /* Identifies object file type */ + unsigned short e_machine; /* Specifies required architecture */ + unsigned short e_ehsize; /* ELF header size in bytes */ + unsigned short e_phentsize; /* Program header table entry size */ + unsigned short e_phnum; /* Program header table entry count */ + unsigned short e_shentsize; /* Section header table entry size */ + unsigned short e_shnum; /* Section header table entry count */ + unsigned short e_shstrndx; /* Section header string table index */ +} Elf_Internal_Ehdr; + +#define elf32_internal_ehdr elf_internal_ehdr +#define Elf32_Internal_Ehdr Elf_Internal_Ehdr +#define elf64_internal_ehdr elf_internal_ehdr +#define Elf64_Internal_Ehdr Elf_Internal_Ehdr + +/* Program header */ + +struct elf_internal_phdr { + unsigned long p_type; /* Identifies program segment type */ + unsigned long p_flags; /* Segment flags */ + bfd_vma p_offset; /* Segment file offset */ + bfd_vma p_vaddr; /* Segment virtual address */ + bfd_vma p_paddr; /* Segment physical address */ + bfd_vma p_filesz; /* Segment size in file */ + bfd_vma p_memsz; /* Segment size in memory */ + bfd_vma p_align; /* Segment alignment, file & memory */ +}; + +typedef struct elf_internal_phdr Elf_Internal_Phdr; +#define elf32_internal_phdr elf_internal_phdr +#define Elf32_Internal_Phdr Elf_Internal_Phdr +#define elf64_internal_phdr elf_internal_phdr +#define Elf64_Internal_Phdr Elf_Internal_Phdr + +/* Section header */ + +typedef struct elf_internal_shdr { + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + bfd_vma sh_flags; /* Miscellaneous section attributes */ + bfd_vma sh_addr; /* Section virtual addr at execution */ + bfd_size_type sh_size; /* Size of section in bytes */ + bfd_size_type sh_entsize; /* Entry size if section holds table */ + unsigned long sh_link; /* Index of another section */ + unsigned long sh_info; /* Additional section information */ + file_ptr sh_offset; /* Section file offset */ + unsigned int sh_addralign; /* Section alignment */ + + /* The internal rep also has some cached info associated with it. */ + asection * bfd_section; /* Associated BFD section. */ + PTR contents; /* Section contents. */ +} Elf_Internal_Shdr; + +#define elf32_internal_shdr elf_internal_shdr +#define Elf32_Internal_Shdr Elf_Internal_Shdr +#define elf64_internal_shdr elf_internal_shdr +#define Elf64_Internal_Shdr Elf_Internal_Shdr + +/* Symbol table entry */ + +struct elf_internal_sym { + bfd_vma st_value; /* Value of the symbol */ + bfd_vma st_size; /* Associated symbol size */ + unsigned long st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + unsigned short st_shndx; /* Associated section index */ +}; + +typedef struct elf_internal_sym Elf_Internal_Sym; + +#define elf32_internal_sym elf_internal_sym +#define elf64_internal_sym elf_internal_sym +#define Elf32_Internal_Sym Elf_Internal_Sym +#define Elf64_Internal_Sym Elf_Internal_Sym + +/* Note segments */ + +typedef struct elf_internal_note { + unsigned long namesz; /* Size of entry's owner string */ + unsigned long descsz; /* Size of the note descriptor */ + unsigned long type; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ +} Elf_Internal_Note; +#define Elf32_Internal_Note Elf_Internal_Note +#define elf32_internal_note elf_internal_note + +/* Relocation Entries */ + +typedef struct elf_internal_rel { + bfd_vma r_offset; /* Location at which to apply the action */ + /* This needs to support 64-bit values in elf64. */ + bfd_vma r_info; /* index and type of relocation */ +} Elf_Internal_Rel; + +#define elf32_internal_rel elf_internal_rel +#define Elf32_Internal_Rel Elf_Internal_Rel +#define elf64_internal_rel elf_internal_rel +#define Elf64_Internal_Rel Elf_Internal_Rel + +typedef struct elf_internal_rela { + bfd_vma r_offset; /* Location at which to apply the action */ + bfd_vma r_info; /* Index and Type of relocation */ + bfd_signed_vma r_addend; /* Constant addend used to compute value */ +} Elf_Internal_Rela; + +#define elf32_internal_rela elf_internal_rela +#define elf64_internal_rela elf_internal_rela +#define Elf32_Internal_Rela Elf_Internal_Rela +#define Elf64_Internal_Rela Elf_Internal_Rela + +/* dynamic section structure */ + +typedef struct elf_internal_dyn { + /* This needs to support 64-bit values in elf64. */ + bfd_vma d_tag; /* entry tag value */ + union { + /* This needs to support 64-bit values in elf64. */ + bfd_vma d_val; + bfd_vma d_ptr; + } d_un; +} Elf_Internal_Dyn; + +#define elf32_internal_dyn elf_internal_dyn +#define elf64_internal_dyn elf_internal_dyn +#define Elf32_Internal_Dyn Elf_Internal_Dyn +#define Elf64_Internal_Dyn Elf_Internal_Dyn + +/* This structure is used to describe how sections should be assigned + to program segments. */ + +struct elf_segment_map +{ + /* Next program segment. */ + struct elf_segment_map *next; + /* Program segment type. */ + unsigned long p_type; + /* Program segment flags. */ + unsigned long p_flags; + /* Program segment physical address. */ + bfd_vma p_paddr; + /* Whether the p_flags field is valid; if not, the flags are based + on the section flags. */ + unsigned int p_flags_valid : 1; + /* Whether the p_paddr field is valid; if not, the physical address + is based on the section lma values. */ + unsigned int p_paddr_valid : 1; + /* Whether this segment includes the file header. */ + unsigned int includes_filehdr : 1; + /* Whether this segment includes the program headers. */ + unsigned int includes_phdrs : 1; + /* Number of sections (may be 0). */ + unsigned int count; + /* Sections. Actual number of elements is in count field. */ + asection *sections[1]; +}; + +#endif /* _ELF_INTERNAL_H */ diff --git a/contrib/gdb/include/elf/mips.h b/contrib/gdb/include/elf/mips.h new file mode 100644 index 000000000000..f0d8cd789650 --- /dev/null +++ b/contrib/gdb/include/elf/mips.h @@ -0,0 +1,298 @@ +/* MIPS ELF support for BFD. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + + By Ian Lance Taylor, Cygnus Support, , from + information in the System V Application Binary Interface, MIPS + Processor Supplement. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MIPS ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_MIPS_H +#define _ELF_MIPS_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* At least one .noreorder directive appears in the source. */ +#define EF_MIPS_NOREORDER 0x00000001 + +/* File contains position independent code. */ +#define EF_MIPS_PIC 0x00000002 + +/* Code in file uses the standard calling sequence for calling + position independent code. */ +#define EF_MIPS_CPIC 0x00000004 + +/* Four bit MIPS architecture field. */ +#define EF_MIPS_ARCH 0xf0000000 + +/* -mips1 code. */ +#define E_MIPS_ARCH_1 0x00000000 + +/* -mips2 code. */ +#define E_MIPS_ARCH_2 0x10000000 + +/* -mips3 code. */ +#define E_MIPS_ARCH_3 0x20000000 + +/* Processor specific section indices. These sections do not actually + exist. Symbols with a st_shndx field corresponding to one of these + values have a special meaning. */ + +/* Defined and allocated common symbol. Value is virtual address. If + relocated, alignment must be preserved. */ +#define SHN_MIPS_ACOMMON 0xff00 + +/* Defined and allocated text symbol. Value is virtual address. + Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */ +#define SHN_MIPS_TEXT 0xff01 + +/* Defined and allocated data symbol. Value is virtual address. + Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */ +#define SHN_MIPS_DATA 0xff02 + +/* Small common symbol. */ +#define SHN_MIPS_SCOMMON 0xff03 + +/* Small undefined symbol. */ +#define SHN_MIPS_SUNDEFINED 0xff04 + +/* Processor specific section types. */ + +/* Section contains the set of dynamic shared objects used when + statically linking. */ +#define SHT_MIPS_LIBLIST 0x70000000 + +/* I'm not sure what this is, but it's used on Irix 5. */ +#define SHT_MIPS_MSYM 0x70000001 + +/* Section contains list of symbols whose definitions conflict with + symbols defined in shared objects. */ +#define SHT_MIPS_CONFLICT 0x70000002 + +/* Section contains the global pointer table. */ +#define SHT_MIPS_GPTAB 0x70000003 + +/* Section contains microcode information. The exact format is + unspecified. */ +#define SHT_MIPS_UCODE 0x70000004 + +/* Section contains some sort of debugging information. The exact + format is unspecified. It's probably ECOFF symbols. */ +#define SHT_MIPS_DEBUG 0x70000005 + +/* Section contains register usage information. */ +#define SHT_MIPS_REGINFO 0x70000006 + +/* Section contains miscellaneous options (used on Irix). */ +#define SHT_MIPS_OPTIONS 0x7000000d + +/* DWARF debugging section (used on Irix 6). */ +#define SHT_MIPS_DWARF 0x7000001e + +/* Events section. This appears on Irix 6. I don't know what it + means. */ +#define SHT_MIPS_EVENTS 0x70000021 + +/* A section of type SHT_MIPS_LIBLIST contains an array of the + following structure. The sh_link field is the section index of the + string table. The sh_info field is the number of entries in the + section. */ +typedef struct +{ + /* String table index for name of shared object. */ + unsigned long l_name; + /* Time stamp. */ + unsigned long l_time_stamp; + /* Checksum of symbol names and common sizes. */ + unsigned long l_checksum; + /* String table index for version. */ + unsigned long l_version; + /* Flags. */ + unsigned long l_flags; +} Elf32_Lib; + +/* The l_flags field of an Elf32_Lib structure may contain the + following flags. */ + +/* Require an exact match at runtime. */ +#define LL_EXACT_MATCH 0x00000001 + +/* Ignore version incompatibilities at runtime. */ +#define LL_IGNORE_INT_VER 0x00000002 + +/* A section of type SHT_MIPS_CONFLICT is an array of indices into the + .dynsym section. Each element has the following type. */ +typedef unsigned long Elf32_Conflict; + +/* A section of type SHT_MIPS_GPTAB contains information about how + much GP space would be required for different -G arguments. This + information is only used so that the linker can provide informative + suggestions as to the best -G value to use. The sh_info field is + the index of the section for which this information applies. The + contents of the section are an array of the following union. The + first element uses the gt_header field. The remaining elements use + the gt_entry field. */ +typedef union +{ + struct + { + /* -G value actually used for this object file. */ + unsigned long gt_current_g_value; + /* Unused. */ + unsigned long gt_unused; + } gt_header; + struct + { + /* If this -G argument has been used... */ + unsigned long gt_g_value; + /* ...this many GP section bytes would be required. */ + unsigned long gt_bytes; + } gt_entry; +} Elf32_gptab; + +/* The external version of Elf32_gptab. */ + +typedef union +{ + struct + { + unsigned char gt_current_g_value[4]; + unsigned char gt_unused[4]; + } gt_header; + struct + { + unsigned char gt_g_value[4]; + unsigned char gt_bytes[4]; + } gt_entry; +} Elf32_External_gptab; + +/* A section of type SHT_MIPS_REGINFO contains the following + structure. */ +typedef struct +{ + /* Mask of general purpose registers used. */ + unsigned long ri_gprmask; + /* Mask of co-processor registers used. */ + unsigned long ri_cprmask[4]; + /* GP register value for this object file. */ + long ri_gp_value; +} Elf32_RegInfo; + +/* The external version of the Elf_RegInfo structure. */ +typedef struct +{ + unsigned char ri_gprmask[4]; + unsigned char ri_cprmask[4][4]; + unsigned char ri_gp_value[4]; +} Elf32_External_RegInfo; + +/* MIPS ELF .reginfo swapping routines. */ +extern void bfd_mips_elf32_swap_reginfo_in + PARAMS ((bfd *, const Elf32_External_RegInfo *, Elf32_RegInfo *)); +extern void bfd_mips_elf32_swap_reginfo_out + PARAMS ((bfd *, const Elf32_RegInfo *, Elf32_External_RegInfo *)); + +/* Processor specific section flags. */ + +/* This section must be in the global data area. */ +#define SHF_MIPS_GPREL 0x10000000 + +/* Processor specific program header types. */ + +/* Register usage information. Identifies one .reginfo section. */ +#define PT_MIPS_REGINFO 0x70000000 + +/* Runtime procedure table. */ +#define PT_MIPS_RTPROC 0x70000001 + +/* Processor specific dynamic array tags. */ + +/* 32 bit version number for runtime linker interface. */ +#define DT_MIPS_RLD_VERSION 0x70000001 + +/* Time stamp. */ +#define DT_MIPS_TIME_STAMP 0x70000002 + +/* Checksum of external strings and common sizes. */ +#define DT_MIPS_ICHECKSUM 0x70000003 + +/* Index of version string in string table. */ +#define DT_MIPS_IVERSION 0x70000004 + +/* 32 bits of flags. */ +#define DT_MIPS_FLAGS 0x70000005 + +/* Base address of the segment. */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 + +/* Address of .conflict section. */ +#define DT_MIPS_CONFLICT 0x70000008 + +/* Address of .liblist section. */ +#define DT_MIPS_LIBLIST 0x70000009 + +/* Number of local global offset table entries. */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a + +/* Number of entries in the .conflict section. */ +#define DT_MIPS_CONFLICTNO 0x7000000b + +/* Number of entries in the .liblist section. */ +#define DT_MIPS_LIBLISTNO 0x70000010 + +/* Number of entries in the .dynsym section. */ +#define DT_MIPS_SYMTABNO 0x70000011 + +/* Index of first external dynamic symbol not referenced locally. */ +#define DT_MIPS_UNREFEXTNO 0x70000012 + +/* Index of first dynamic symbol in global offset table. */ +#define DT_MIPS_GOTSYM 0x70000013 + +/* Number of page table entries in global offset table. */ +#define DT_MIPS_HIPAGENO 0x70000014 + +/* Address of run time loader map, used for debugging. */ +#define DT_MIPS_RLD_MAP 0x70000016 + +/* Flags which may appear in a DT_MIPS_FLAGS entry. */ + +/* No flags. */ +#define RHF_NONE 0x00000000 + +/* Uses shortcut pointers. */ +#define RHF_QUICKSTART 0x00000001 + +/* Hash size is not a power of two. */ +#define RHF_NOTPOT 0x00000002 + +/* Ignore LD_LIBRARY_PATH. */ +#define RHS_NO_LIBRARY_REPLACEMENT \ + 0x00000004 + +/* Special values for the st_other field in the symbol table. These + are used in an Irix 5 dynamic symbol table. */ + +#define STO_DEFAULT 0x00 +#define STO_INTERNAL 0x01 +#define STO_HIDDEN 0x02 +#define STO_PROTECTED 0x03 + +#endif /* _ELF_MIPS_H */ diff --git a/contrib/gdb/include/elf/ppc.h b/contrib/gdb/include/elf/ppc.h new file mode 100644 index 000000000000..1da118ddd842 --- /dev/null +++ b/contrib/gdb/include/elf/ppc.h @@ -0,0 +1,54 @@ +/* PPC ELF support for BFD. + Copyright (C) 1995 Free Software Foundation, Inc. + + By Michael Meissner, Cygnus Support, , from information + in the System V Application Binary Interface, PowerPC Processor Supplement + and the PowerPC Embedded Application Binary Interface (eabi). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the PPC ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_PPC_H +#define _ELF_PPC_H + +/* Processor specific flags for the ELF header e_flags field. */ + +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + + /* CYGNUS local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag */ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ + +/* Processor specific section headers, sh_type field */ + +#define SHT_ORDERED SHT_HIPROC /* Link editor is to sort the \ + entries in this section \ + based on the address \ + specified in the associated \ + symbol table entry. */ + +/* Processor specific section flags, sh_flags field */ + +#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude \ + this section from executable \ + and shared objects that it \ + builds when those objects \ + are not to be furhter \ + relocated. */ +#endif /* _ELF_PPC_H */ diff --git a/contrib/gdb/include/elf/sparc.h b/contrib/gdb/include/elf/sparc.h new file mode 100644 index 000000000000..84408e31adda --- /dev/null +++ b/contrib/gdb/include/elf/sparc.h @@ -0,0 +1,73 @@ +/* SPARC ELF support for BFD. + Copyright (C) 1996 Free Software Foundation, Inc. + + By Doug Evans, Cygnus Support, . + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_SPARC_H +#define _ELF_SPARC_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* These are defined by Sun. */ + +#define EF_SPARC_32PLUS_MASK 0xffff00 /* bits indicating V8+ type */ +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ + +/* Relocation types. */ + +enum elf_sparc_reloc_type { + R_SPARC_NONE = 0, + R_SPARC_8, R_SPARC_16, R_SPARC_32, + R_SPARC_DISP8, R_SPARC_DISP16, R_SPARC_DISP32, + R_SPARC_WDISP30, R_SPARC_WDISP22, + R_SPARC_HI22, R_SPARC_22, + R_SPARC_13, R_SPARC_LO10, + R_SPARC_GOT10, R_SPARC_GOT13, R_SPARC_GOT22, + R_SPARC_PC10, R_SPARC_PC22, + R_SPARC_WPLT30, + R_SPARC_COPY, + R_SPARC_GLOB_DAT, R_SPARC_JMP_SLOT, + R_SPARC_RELATIVE, + R_SPARC_UA32, + + /* ??? These 6 relocs are new but not currently used. For binary + compatility in the sparc64-elf toolchain, we leave them out. + A non-binary upward compatible change is expected for sparc64-elf. */ +#ifndef SPARC64_OLD_RELOCS + /* ??? New relocs on the UltraSPARC. Not sure what they're for yet. */ + R_SPARC_PLT32, R_SPARC_HIPLT22, R_SPARC_LOPLT10, + R_SPARC_PCPLT32, R_SPARC_PCPLT22, R_SPARC_PCPLT10, +#endif + + /* v9 relocs */ + R_SPARC_10, R_SPARC_11, R_SPARC_64, + R_SPARC_OLO10, R_SPARC_HH22, R_SPARC_HM10, R_SPARC_LM22, + R_SPARC_PC_HH22, R_SPARC_PC_HM10, R_SPARC_PC_LM22, + R_SPARC_WDISP16, R_SPARC_WDISP19, + R_SPARC_GLOB_JMP, + R_SPARC_7, +#ifndef SPARC64_OLD_RELOCS + R_SPARC_5, R_SPARC_6, +#endif + + R_SPARC_max +}; + +#endif /* _ELF_SPARC_H */ diff --git a/contrib/gdb/include/floatformat.h b/contrib/gdb/include/floatformat.h new file mode 100644 index 000000000000..01e3dcb2944d --- /dev/null +++ b/contrib/gdb/include/floatformat.h @@ -0,0 +1,88 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +#include "ansidecl.h" + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +enum floatformat_byteorders { floatformat_little, floatformat_big }; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Amount added to "true" exponent. 0x3fff for many IEEE extendeds. */ + unsigned int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_arm_ext; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double PARAMS ((const struct floatformat *, char *, double *)); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double PARAMS ((const struct floatformat *, + double *, char *)); + +#endif /* defined (FLOATFORMAT_H) */ diff --git a/contrib/gdb/include/fopen-bin.h b/contrib/gdb/include/fopen-bin.h new file mode 100644 index 000000000000..b868f63d46d1 --- /dev/null +++ b/contrib/gdb/include/fopen-bin.h @@ -0,0 +1,27 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + [Update] + + This version is for "binary" systems, where text and binary files are + different. An example is Mess-Dose. Many Unix systems could also + cope with a "b" in the string, indicating binary files, but some reject this + (and thereby don't conform to ANSI C, but what else is new?). + + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "rb" +#define FOPEN_WB "wb" +#define FOPEN_AB "ab" +#define FOPEN_RUB "r+b" +#define FOPEN_WUB "w+b" +#define FOPEN_AUB "a+b" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/contrib/gdb/include/fopen-same.h b/contrib/gdb/include/fopen-same.h new file mode 100644 index 000000000000..0f37529d33e0 --- /dev/null +++ b/contrib/gdb/include/fopen-same.h @@ -0,0 +1,27 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + [Update] + + This version is for "same" systems, where text and binary files are + the same. An example is Unix. Many Unix systems could also add a + "b" to the string, indicating binary files, but some reject this + (and thereby don't conform to ANSI C, but what else is new?). + + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "r" +#define FOPEN_WB "w" +#define FOPEN_AB "a" +#define FOPEN_RUB "r+" +#define FOPEN_WUB "w+" +#define FOPEN_AUB "a+" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/contrib/gdb/include/gdbm.h b/contrib/gdb/include/gdbm.h new file mode 100644 index 000000000000..3ebc26d198a7 --- /dev/null +++ b/contrib/gdb/include/gdbm.h @@ -0,0 +1,91 @@ +/* GNU DBM - DataBase Manager include file + Copyright 1989, 1991 Free Software Foundation, Inc. + Written by Philip A. Nelson. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* You may contact the author by: + e-mail: phil@wwu.edu + us-mail: Philip A. Nelson + Computer Science Department + Western Washington University + Bellingham, WA 98226 + phone: (206) 676-3035 + +*************************************************************************/ + +/* Parameters to gdbm_open for READERS, WRITERS, and WRITERS who + can create the database. */ +#define GDBM_READER 0 +#define GDBM_WRITER 1 +#define GDBM_WRCREAT 2 +#define GDBM_NEWDB 3 + +/* Parameters to gdbm_store for simple insertion or replacement. */ +#define GDBM_INSERT 0 +#define GDBM_REPLACE 1 + + +/* The data and key structure. This structure is defined for compatibility. */ +typedef struct { + char *dptr; + int dsize; + } datum; + + +/* The file information header. This is good enough for most applications. */ +typedef struct {int dummy[10];} *GDBM_FILE; + + +/* These are the routines! */ + +extern GDBM_FILE gdbm_open (); + +extern void gdbm_close (); + +extern datum gdbm_fetch (); + +extern int gdbm_store (); + +extern int gdbm_delete (); + +extern datum gdbm_firstkey (); + +extern datum gdbm_nextkey (); + +extern int gdbm_reorganize (); + + +/* gdbm sends back the following error codes in the variable gdbm_errno. */ +typedef enum { NO_ERROR, + MALLOC_ERROR, + BLOCK_SIZE_ERROR, + FILE_OPEN_ERROR, + FILE_WRITE_ERROR, + FILE_SEEK_ERROR, + FILE_READ_ERROR, + BAD_MAGIC_NUMBER, + EMPTY_DATABASE, + CANT_BE_READER, + CANT_BE_WRITER, + READER_CANT_RECOVER, + READER_CANT_DELETE, + READER_CANT_STORE, + READER_CANT_REORGANIZE, + UNKNOWN_UPDATE, + ITEM_NOT_FOUND, + REORGANIZE_FAILED, + CANNOT_REPLACE} + gdbm_error; diff --git a/contrib/gdb/include/getopt.h b/contrib/gdb/include/getopt.h new file mode 100644 index 000000000000..abf915383200 --- /dev/null +++ b/contrib/gdb/include/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/contrib/gdb/include/hp-symtab.h b/contrib/gdb/include/hp-symtab.h new file mode 100644 index 000000000000..051c4c63ed2d --- /dev/null +++ b/contrib/gdb/include/hp-symtab.h @@ -0,0 +1,983 @@ +/* Definitions and structures for reading debug symbols from the + native HP C compiler. + + Written by the Center for Software Science at the University of Utah + and by Cygnus Support. + + Copyright 1994 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef HP_SYMTAB_INCLUDED +#define HP_SYMTAB_INCLUDED + +/* General information: + + This header file defines and describes only the basic data structures + necessary to read debug symbols produced by the HP C compiler using the + SOM object file format. Definitions and structures used by other compilers + for other languages or object file formats may be missing. + (For a full description of the debug format, ftp hpux-symtab.h from + jaguar.cs.utah.edu:/dist). + + + Debug symbols are contained entirely within an unloadable space called + $DEBUG$. $DEBUG$ contains several subspaces which group related + debug symbols. + + $GNTT$ contains information for global variables, types and contants. + + $LNTT$ contains information for procedures (including nesting), scoping + information, local variables, types, and constants. + + $SLT$ contains source line information so that code addresses may be + mapped to source lines. + + $VT$ contains various strings and constants for named objects (variables, + typedefs, functions, etc). Strings are stored as null-terminated character + lists. Constants always begin on word boundaries. The first byte of + the VT must be zero (a null string). + + $XT$ is not currently used by GDB. + + Many structures within the subspaces point to other structures within + the same subspace, or to structures within a different subspace. These + pointers are represented as a structure index from the beginning of + the appropriate subspace. */ + +/* Used to describe where a constant is stored. */ +enum location_type +{ + LOCATION_IMMEDIATE, + LOCATION_PTR, + LOCATION_VT, +}; + +/* Languages supported by this debug format. Within the data structures + this type is limited to 4 bits for a maximum of 16 languages. */ +enum hp_language +{ + HP_LANGUAGE_UNKNOWN, + HP_LANGUAGE_C, + HP_LANGUAGE_F77, + HP_LANGUAGE_PASCAL, + HP_LANGUAGE_COBOL, + HP_LANGUAGE_BASIC, + HP_LANGUAGE_ADA, + HP_LANGUAGE_CPLUSPLUS, +}; + + +/* Basic data types available in this debug format. Within the data + structures this type is limited to 5 bits for a maximum of 32 basic + data types. */ +enum hp_type +{ + HP_TYPE_UNDEFINED, + HP_TYPE_BOOLEAN, + HP_TYPE_CHAR, + HP_TYPE_INT, + HP_TYPE_UNSIGNED_INT, + HP_TYPE_REAL, + HP_TYPE_COMPLEX, + HP_TYPE_STRING200, + HP_TYPE_LONGSTRING200, + HP_TYPE_TEXT, + HP_TYPE_FLABEL, + HP_TYPE_FTN_STRING_SPEC, + HP_TYPE_MOD_STRING_SPEC, + HP_TYPE_PACKED_DECIMAL, + HP_TYPE_REAL_3000, + HP_TYPE_MOD_STRING_3000, + HP_TYPE_ANYPOINTER, + HP_TYPE_GLOBAL_ANYPOINTER, + HP_TYPE_LOCAL_ANYPOINTER, + HP_TYPE_COMPLEXS3000, + HP_TYPE_FTN_STRING_S300_COMPAT, + HP_TYPE_FTN_STRING_VAX_COMPAT, + HP_TYPE_BOOLEAN_S300_COMPAT, + HP_TYPE_BOOLEAN_VAX_COMPAT, + HP_TYPE_WIDE_CHAR, + HP_TYPE_LONG, + HP_TYPE_UNSIGNED_LONG, + HP_TYPE_DOUBLE, + HP_TYPE_TEMPLATE_ARG, +}; + +/* An immediate name and type table entry. + + extension and immediate will always be one. + global will always be zero. + hp_type is the basic type this entry describes. + bitlength is the length in bits for the basic type. */ +struct dnttp_immediate +{ + unsigned int extension: 1; + unsigned int immediate: 1; + unsigned int global: 1; + unsigned int type: 5; + unsigned int bitlength: 24; +}; + +/* A nonimmediate name and type table entry. + + extension will always be one. + immediate will always be zero. + if global is zero, this entry points into the LNTT + if global is one, this entry points into the GNTT + index is the index within the GNTT or LNTT for this entry. */ +struct dnttp_nonimmediate +{ + unsigned int extension: 1; + unsigned int immediate: 1; + unsigned int global: 1; + unsigned int index: 29; +}; + +/* A pointer to an entry in the GNTT and LNTT tables. It has two + forms depending on the type being described. + + The immediate form is used for simple entries and is one + word. + + The nonimmediate form is used for complex entries and contains + an index into the LNTT or GNTT which describes the entire type. + + If a dnttpointer is -1, then it is a NIL entry. */ + +#define DNTTNIL (-1) +typedef union dnttpointer +{ + struct dnttp_immediate dntti; + struct dnttp_nonimmediate dnttp; + int word; +} dnttpointer; + +/* An index into the source line table. As with dnttpointers, a sltpointer + of -1 indicates a NIL entry. */ +#define SLTNIL (-1) +typedef int sltpointer; + +/* Unsigned byte offset into the VT. */ +typedef unsigned int vtpointer; + +/* A DNTT entry (used within the GNTT and LNTT). + + DNTT entries are variable sized objects, but are always a multiple + of 3 words (we call each group of 3 words a "block"). + + The first bit in each block is an extension bit. This bit is zero + for the first block of a DNTT entry. If the entry requires more + than one block, then this bit is set to one in all blocks after + the first one. */ + +/* Each DNTT entry describes a particular debug symbol (beginning of + a source file, a function, variables, structures, etc. + + The type of the DNTT entry is stored in the "kind" field within the + DNTT entry itself. */ + +enum dntt_entry_type +{ + DNTT_TYPE_NIL = -1, + DNTT_TYPE_SRCFILE, + DNTT_TYPE_MODULE, + DNTT_TYPE_FUNCTION, + DNTT_TYPE_ENTRY, + DNTT_TYPE_BEGIN, + DNTT_TYPE_END, + DNTT_TYPE_IMPORT, + DNTT_TYPE_LABEL, + DNTT_TYPE_FPARAM, + DNTT_TYPE_SVAR, + DNTT_TYPE_DVAR, + DNTT_TYPE_HOLE1, + DNTT_TYPE_CONST, + DNTT_TYPE_TYPEDEF, + DNTT_TYPE_TAGDEF, + DNTT_TYPE_POINTER, + DNTT_TYPE_ENUM, + DNTT_TYPE_MEMENUM, + DNTT_TYPE_SET, + DNTT_TYPE_SUBRANGE, + DNTT_TYPE_ARRAY, + DNTT_TYPE_STRUCT, + DNTT_TYPE_UNION, + DNTT_TYPE_FIELD, + DNTT_TYPE_VARIANT, + DNTT_TYPE_FILE, + DNTT_TYPE_FUNCTYPE, + DNTT_TYPE_WITH, + DNTT_TYPE_COMMON, + DNTT_TYPE_COBSTRUCT, + DNTT_TYPE_XREF, + DNTT_TYPE_SA, + DNTT_TYPE_MACRO, + DNTT_TYPE_BLOCKDATA, + DNTT_TYPE_CLASS_SCOPE, + DNTT_TYPE_REFERENCE, + DNTT_TYPE_PTRMEM, + DNTT_TYPE_PTRMEMFUNC, + DNTT_TYPE_CLASS, + DNTT_TYPE_GENFIELD, + DNTT_TYPE_VFUNC, + DNTT_TYPE_MEMACCESS, + DNTT_TYPE_INHERITANCE, + DNTT_TYPE_FRIEND_CLASS, + DNTT_TYPE_FRIEND_FUNC, + DNTT_TYPE_MODIFIER, + DNTT_TYPE_OBJECT_ID, + DNTT_TYPE_MEMFUNC, + DNTT_TYPE_TEMPLATE, + DNTT_TYPE_TEMPLATE_ARG, + DNTT_TYPE_FUNC_TEMPLATE, + DNTT_TYPE_LINK, + DNTT_TYPE_MAX, +}; + +/* DNTT_TYPE_SRCFILE: + + One DNTT_TYPE_SRCFILE symbol is output for the start of each source + file and at the begin and end of an included file. A DNTT_TYPE_SRCFILE + entry is also output before each DNTT_TYPE_FUNC symbol so that debuggers + can determine what file a function was defined in. + + LANGUAGE describes the source file's language. + + NAME points to an VT entry providing the source file's name. + + Note the name used for DNTT_TYPE_SRCFILE entries are exactly as seen + by the compiler (ie they may be relative or absolute). C include files + via <> inclusion must use absolute paths. + + ADDRESS points to an SLT entry from which line number and code locations + may be determined. */ + +struct dntt_type_srcfile +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int language: 4; + unsigned int unused: 17; + vtpointer name; + sltpointer address; +}; + +/* DNTT_TYPE_MODULE: + + A DNTT_TYPE_MODULE symbol is emitted for the start of a pascal + module or C source file. + + Each DNTT_TYPE_MODULE must have an associated DNTT_TYPE_END symbol. + + NAME points to a VT entry providing the module's name. Note C + source files are considered nameless modules. + + ALIAS point to a VT entry providing a secondary name. + + ADDRESS points to an SLT entry from which line number and code locations + may be determined. */ + +struct dntt_type_module +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int unused: 21; + vtpointer name; + vtpointer alias; + dnttpointer unused2; + sltpointer address; +}; + +/* DNTT_TYPE_FUNCTION: + + A DNTT_TYPE_FUNCTION symbol is emitted for each function definition; + a DNTT_TYPE_ENTRY symbols is used for secondary entry points. Both + symbols used the dntt_type_function structure. + + Each DNTT_TYPE_FUNCTION must have a matching DNTT_TYPE_END. + + GLOBAL is nonzero if the function has global scope. + + LANGUAGE describes the function's source language. + + OPT_LEVEL describes the optimization level the function was compiled + with. + + VARARGS is nonzero if the function uses varargs. + + NAME points to a VT entry providing the function's name. + + ALIAS points to a VT entry providing a secondary name for the function. + + FIRSTPARAM points to a LNTT entry which describes the parameter list. + + ADDRESS points to an SLT entry from which line number and code locations + may be determined. + + ENTRYADDR is the memory address corresponding the the function's entry point + + RETVAL points to a LNTT entry describing the function's return value. + + LOWADDR is the lowest memory address associated with this function. + + HIADDR is the highest memory address associated with this function. */ + +struct dntt_type_function +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int global: 1; + unsigned int language: 4; + unsigned int nest_level: 5; + unsigned int opt_level: 2; + unsigned int varargs: 1; + unsigned int lang_info: 4; + unsigned int inlined: 1; + unsigned int localalloc: 1; + unsigned int expansion: 1; + unsigned int unused: 1; + vtpointer name; + vtpointer alias; + dnttpointer firstparam; + sltpointer address; + CORE_ADDR entryaddr; + dnttpointer retval; + CORE_ADDR lowaddr; + CORE_ADDR hiaddr; +}; + +/* DNTT_TYPE_BEGIN: + + A DNTT_TYPE_BEGIN symbol is emitted to begin a new nested scope. + Every DNTT_TYPE_BEGIN symbol must have a matching DNTT_TYPE_END symbol. + + CLASSFLAG is nonzero if this is the beginning of a c++ class definition. + + ADDRESS points to an SLT entry from which line number and code locations + may be determined. */ + +struct dntt_type_begin +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int classflag: 1; + unsigned int unused: 20; + sltpointer address; +}; + +/* DNTT_TYPE_END: + + A DNTT_TYPE_END symbol is emitted when closing a scope started by + a DNTT_TYPE_MODULE, DNTT_TYPE_FUNCTION, and DNTT_TYPE_BEGIN symbols. + + ENDKIND describes what type of scope the DNTT_TYPE_END is closing + (DNTT_TYPE_MODULE, DNTT_TYPE_BEGIN, etc). + + CLASSFLAG is nonzero if this is the end of a c++ class definition. + + ADDRESS points to an SLT entry from which line number and code locations + may be determined. + + BEGINSCOPE points to the LNTT entry which opened the scope. */ + +struct dntt_type_end +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int endkind: 10; + unsigned int classflag: 1; + unsigned int unused: 10; + sltpointer address; + dnttpointer beginscope; +}; + +/* DNTT_TYPE_IMPORT is unused by GDB. */ +/* DNTT_TYPE_LABEL is unused by GDB. */ + +/* DNTT_TYPE_FPARAM: + + A DNTT_TYPE_FPARAM symbol is emitted for a function argument. When + chained together the symbols represent an argument list for a function. + + REGPARAM is nonzero if this parameter was passed in a register. + + INDIRECT is nonzero if this parameter is a pointer to the parameter + (pass by reference or pass by value for large items). + + LONGADDR is nonzero if the parameter is a 64bit pointer. + + NAME is a pointer into the VT for the parameter's name. + + LOCATION describes where the parameter is stored. Depending on the + parameter type LOCATION could be a register number, or an offset + from the stack pointer. + + TYPE points to a NTT entry describing the type of this parameter. + + NEXTPARAM points to the LNTT entry describing the next parameter. */ + +struct dntt_type_fparam +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int regparam: 1; + unsigned int indirect: 1; + unsigned int longaddr: 1; + unsigned int copyparam: 1; + unsigned int dflt: 1; + unsigned int unused: 16; + vtpointer name; + int location; + dnttpointer type; + dnttpointer nextparam; + int misc; +}; + +/* DNTT_TYPE_SVAR: + + A DNTT_TYPE_SVAR is emitted to describe a variable in static storage. + + GLOBAL is nonzero if the variable has global scope. + + INDIRECT is nonzero if the variable is a pointer to an object. + + LONGADDR is nonzero if the variable is in long pointer space. + + STATICMEM is nonzero if the variable is a member of a class. + + A_UNION is nonzero if the variable is an anonymous union member. + + NAME is a pointer into the VT for the variable's name. + + LOCATION provides the memory address for the variable. + + TYPE is a pointer into either the GNTT or LNTT which describes + the type of this variable. */ + +struct dntt_type_svar +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int global: 1; + unsigned int indirect: 1; + unsigned int longaddr: 1; + unsigned int staticmem: 1; + unsigned int a_union: 1; + unsigned int unused: 16; + vtpointer name; + CORE_ADDR location; + dnttpointer type; + unsigned int offset; + unsigned int displacement; +}; + +/* DNTT_TYPE_DVAR: + + A DNTT_TYPE_DVAR is emitted to describe automatic variables and variables + held in registers. + + GLOBAL is nonzero if the variable has global scope. + + INDIRECT is nonzero if the variable is a pointer to an object. + + REGVAR is nonzero if the variable is in a register. + + A_UNION is nonzero if the variable is an anonymous union member. + + NAME is a pointer into the VT for the variable's name. + + LOCATION provides the memory address or register number for the variable. + + TYPE is a pointer into either the GNTT or LNTT which describes + the type of this variable. */ + +struct dntt_type_dvar +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int global: 1; + unsigned int indirect: 1; + unsigned int regvar: 1; + unsigned int a_union: 1; + unsigned int unused: 17; + vtpointer name; + int location; + dnttpointer type; + unsigned int offset; +}; + +/* DNTT_TYPE_CONST: + + A DNTT_TYPE_CONST symbol is emitted for program constants. + + GLOBAL is nonzero if the constant has global scope. + + INDIRECT is nonzero if the constant is a pointer to an object. + + LOCATION_TYPE describes where to find the constant's value + (in the VT, memory, or embedded in an instruction). + + CLASSMEM is nonzero if the constant is a member of a class. + + NAME is a pointer into the VT for the constant's name. + + LOCATION provides the memory address, register number or pointer + into the VT for the constant's value. + + TYPE is a pointer into either the GNTT or LNTT which describes + the type of this variable. */ + +struct dntt_type_const +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int global: 1; + unsigned int indirect: 1; + unsigned int: 3; + unsigned int classmem: 1; + unsigned int unused: 15; + vtpointer name; + CORE_ADDR location; + dnttpointer type; + unsigned int offset; + unsigned int displacement; +}; + +/* DNTT_TYPE_TYPEDEF and DNTT_TYPE_TAGDEF: + + The same structure is used to describe typedefs and tagdefs. + + DNTT_TYPE_TYPEDEFS are associated with C "typedefs". + + DNTT_TYPE_TAGDEFs are associated with C "struct", "union", and "enum" + tags, which may have the same name as a typedef in the same scope. + + GLOBAL is nonzero if the typedef/tagdef has global scope. + + TYPEINFO is used to determine if full type information is available + for a tag. (usually 1, but can be zero for opaque types in C). + + NAME is a pointer into the VT for the constant's name. + + TYPE points to the underlying type for the typedef/tagdef in the + GNTT or LNTT. */ + +struct dntt_type_type +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int global: 1; + unsigned int typeinfo: 1; + unsigned int unused: 19; + vtpointer name; + dnttpointer type; +}; + +/* DNTT_TYPE_POINTER: + + Used to describe a pointer to an underlying type. + + POINTSTO is a pointer into the GNTT or LNTT for the type which this + pointer points to. + + BITLENGTH is the length of the pointer (not the underlying type). */ + +struct dntt_type_pointer +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int unused: 21; + dnttpointer pointsto; + unsigned int bitlength; +}; + + +/* DNTT_TYPE_ENUM: + + Used to describe enumerated types. + + FIRSTMEM is a pointer to a DNTT_TYPE_MEMENUM in the GNTT/LNTT which + describes the first member (and contains a pointer to the chain of + members). + + BITLENGTH is the number of bits used to hold the values of the enum's + members. */ + +struct dntt_type_enum +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int unused: 21; + dnttpointer firstmem; + unsigned int bitlength; +}; + +/* DNTT_TYPE_MEMENUM + + Used to describe members of an enumerated type. + + CLASSMEM is nonzero if this member is part of a class. + + NAME points into the VT for the name of this member. + + VALUE is the value of this enumeration member. + + NEXTMEM points to the next DNTT_TYPE_MEMENUM in the chain. */ + +struct dntt_type_memenum +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int classmem: 1; + unsigned int unused: 20; + vtpointer name; + unsigned int value; + dnttpointer nextmem; +}; + +/* DNTT_TYPE_SET + + DECLARATION describes the bitpacking of the set. + + SUBTYPE points to a DNTT entry describing the type of the members. + + BITLENGTH is the size of the set. */ + +struct dntt_type_set +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int declaration: 2; + unsigned int unused: 19; + dnttpointer subtype; + unsigned int bitlength; +}; + +/* DNTT_TYPE_SUBRANGE + + DYN_LOW describes the lower bound of the subrange: + + 00 for a constant lower bound (found in LOWBOUND). + + 01 for a dynamic lower bound with the lower bound found in the the + memory address pointed to by LOWBOUND. + + 10 for a dynamic lower bound described by an variable found in the + DNTT/LNTT (LOWBOUND would be a pointer into the DNTT/LNTT). + + DYN_HIGH is similar to DYN_LOW, except it describes the upper bound. + + SUBTYPE points to the type of the subrange. + + BITLENGTH is the length in bits needed to describe the subrange's + values. */ + +struct dntt_type_subrange +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int dyn_low: 2; + unsigned int dyn_high: 2; + unsigned int unused: 17; + int lowbound; + int highbound; + dnttpointer subtype; + unsigned int bitlength; +}; + +/* DNTT_TYPE_ARRAY + + DECLARATION describes the bit packing used in the array. + + ARRAYISBYTES is nonzero if the field in arraylength describes the + length in bytes rather than in bits. A value of zero is used to + describe an array with size 2**32. + + ELEMISBYTES is nonzero if the length if each element in the array + is describes in bytes rather than bits. A value of zero is used + to an element with size 2**32. + + ELEMORDER is nonzero if the elements are indexed in increasing order. + + JUSTIFIED if the elements are left justified to index zero. + + ARRAYLENGTH is the length of the array. + + INDEXTYPE is a DNTT pointer to the type used to index the array. + + ELEMTYPE is a DNTT pointer to the type for the array elements. + + ELEMLENGTH is the length of each element in the array (including + any padding). + + Multi-dimensional arrays are represented by ELEMTYPE pointing to + another DNTT_TYPE_ARRAY. */ + +struct dntt_type_array +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int declaration: 2; + unsigned int dyn_low: 2; + unsigned int dyn_high: 2; + unsigned int arrayisbytes: 1; + unsigned int elemisbytes: 1; + unsigned int elemorder: 1; + unsigned int justified: 1; + unsigned int unused: 11; + unsigned int arraylength; + dnttpointer indextype; + dnttpointer elemtype; + unsigned int elemlength; +}; + +/* DNTT_TYPE_STRUCT + + DNTT_TYPE_STRUCT is used to describe a C structure. + + DECLARATION describes the bitpacking used. + + FIRSTFIELD is a DNTT pointer to the first field of the structure + (each field contains a pointer to the next field, walk the list + to access all fields of the structure). + + VARTAGFIELD and VARLIST are used for Pascal variant records. + + BITLENGTH is the size of the structure in bits. */ + +struct dntt_type_struct +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int declaration: 2; + unsigned int unused: 19; + dnttpointer firstfield; + dnttpointer vartagfield; + dnttpointer varlist; + unsigned int bitlength; +}; + +/* DNTT_TYPE_UNION + + DNTT_TYPE_UNION is used to describe a C union. + + FIRSTFIELD is a DNTT pointer to the beginning of the field chain. + + BITLENGTH is the size of the union in bits. */ + +struct dntt_type_union +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int unused: 21; + dnttpointer firstfield; + unsigned int bitlength; +}; + +/* DNTT_TYPE_FIELD + + DNTT_TYPE_FIELD describes one field in a structure or union. + + VISIBILITY is used to describe the visibility of the field + (for c++. public = 0, protected = 1, private = 2). + + A_UNION is nonzero if this field is a member of an anonymous union. + + STATICMEM is nonzero if this field is a static member of a template. + + NAME is a pointer into the VT for the name of the field. + + BITOFFSET gives the offset of this field in bits from the beginning + of the structure or union this field is a member of. + + TYPE is a DNTT pointer to the type describing this field. + + BITLENGTH is the size of the entry in bits. + + NEXTFIELD is a DNTT pointer to the next field in the chain. */ + +struct dntt_type_field +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int visibility: 2; + unsigned int a_union: 1; + unsigned int staticmem: 1; + unsigned int unused: 17; + vtpointer name; + unsigned int bitoffset; + dnttpointer type; + unsigned int bitlength; + dnttpointer nextfield; +}; + +/* DNTT_TYPE_VARIANT is unused by GDB. */ +/* DNTT_TYPE_FILE is unused by GDB. */ + +/* DNTT_TYPE_COMMON is unused by GDB. */ +/* DNTT_TYPE_LINK is unused by GDB. */ +/* DNTT_TYPE_FFUNC_LINK is unused by GDB. */ +/* DNTT_TYPE_TEMPLATE is unused by GDB. */ + +/* DNTT_TYPE_FUNCTYPE + + VARARGS is nonzero if this function uses varargs. + + FIRSTPARAM is a DNTT pointer to the first entry in the parameter + chain. + + RETVAL is a DNTT pointer to the type of the return value. */ + +struct dntt_type_functype +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int varargs: 1; + unsigned int info: 4; + unsigned int unused: 16; + unsigned int bitlength; + dnttpointer firstparam; + dnttpointer retval; +}; + +/* DNTT_TYPE_WITH is unued by GDB. */ +/* DNTT_TYPE_COBSTRUCT is unused by GDB. */ +/* DNTT_TYPE_MODIFIER is unused by GDB. */ +/* DNTT_TYPE_GENFIELD is unused by GDB. */ +/* DNTT_TYPE_MEMACCESS is unused by GDB. */ +/* DNTT_TYPE_VFUNC is unused by GDB. */ +/* DNTT_TYPE_CLASS_SCOPE is unused by GDB. */ +/* DNTT_TYPE_FRIEND_CLASS is unused by GDB. */ +/* DNTT_TYPE_FRIEND_FUNC is unused by GDB. */ +/* DNTT_TYPE_CLASS unused by GDB. */ +/* DNTT_TYPE_TEMPLATE unused by GDB. */ +/* DNTT_TYPE_TEMPL_ARG is unused by GDB. */ +/* DNTT_TYPE_PTRMEM not used by GDB */ +/* DNTT_TYPE_INHERITANCE is unused by GDB. */ +/* DNTT_TYPE_OBJECT_ID is unused by GDB. */ +/* DNTT_TYPE_XREF is unused by GDB. */ +/* DNTT_TYPE_SA is unused by GDB. */ + +/* DNTT_TYPE_GENERIC and DNTT_TYPE_BLOCK are convience structures + so we can examine a DNTT entry in a generic fashion. */ +struct dntt_type_generic +{ + unsigned int word[9]; +}; + +struct dntt_type_block +{ + unsigned int extension: 1; + unsigned int kind: 10; + unsigned int unused: 21; + unsigned int word[2]; +}; + +/* One entry in a DNTT (either the LNTT or GNTT). */ +union dnttentry +{ + struct dntt_type_srcfile dsfile; + struct dntt_type_module dmodule; + struct dntt_type_function dfunc; + struct dntt_type_function dentry; + struct dntt_type_begin dbegin; + struct dntt_type_end dend; + struct dntt_type_fparam dfparam; + struct dntt_type_svar dsvar; + struct dntt_type_dvar ddvar; + struct dntt_type_const dconst; + struct dntt_type_type dtype; + struct dntt_type_type dtag; + struct dntt_type_pointer dptr; + struct dntt_type_enum denum; + struct dntt_type_memenum dmember; + struct dntt_type_set dset; + struct dntt_type_subrange dsubr; + struct dntt_type_array darray; + struct dntt_type_struct dstruct; + struct dntt_type_union dunion; + struct dntt_type_field dfield; + struct dntt_type_functype dfunctype; + struct dntt_type_generic dgeneric; + struct dntt_type_block dblock; +}; + +/* Source line entry types. */ +enum slttype +{ + SLT_NORMAL, + SLT_SRCFILE, + SLT_MODULE, + SLT_FUNCTION, + SLT_ENTRY, + SLT_BEGIN, + SLT_END, + SLT_WITH, + SLT_EXIT, + SLT_ASSIST, + SLT_MARKER, +}; + +/* A normal source line entry. Simply provides a mapping of a source + line number to a code address. + + SLTDESC will always be SLT_NORMAL or SLT_EXIT. */ + +struct slt_normal +{ + unsigned int sltdesc: 4; + unsigned int line: 28; + CORE_ADDR address; +}; + +/* A special source line entry. Provides a mapping of a declaration + to a line number. These entries point back into the DNTT which + references them. */ + +struct slt_special +{ + unsigned int sltdesc: 4; + unsigned int line: 28; + dnttpointer backptr; +}; + +/* Used to describe nesting. + + For nested languages, an slt_assist entry must follow each SLT_FUNC + entry in the SLT. The address field will point forward to the + first slt_normal entry within the function's scope. */ + +struct slt_assist +{ + unsigned int sltdesc: 4; + unsigned int unused: 28; + sltpointer address; +}; + +struct slt_generic +{ + unsigned int word[2]; +}; + +union sltentry +{ + struct slt_normal snorm; + struct slt_special sspec; + struct slt_assist sasst; + struct slt_generic sgeneric; +}; + +#endif /* HP_SYMTAB_INCLUDED */ diff --git a/contrib/gdb/include/ieee.h b/contrib/gdb/include/ieee.h new file mode 100644 index 000000000000..5ade39d33e35 --- /dev/null +++ b/contrib/gdb/include/ieee.h @@ -0,0 +1,139 @@ +/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file + Contributed by Cygnus Support. */ + +#define N_W_VARIABLES 8 +#define Module_Beginning 0xe0 + +typedef struct ieee_module { + char *processor; + char *module_name; +} ieee_module_begin_type; + +#define Address_Descriptor 0xec +typedef struct ieee_address { +bfd_vma number_of_bits_mau; + bfd_vma number_of_maus_in_address; + + unsigned char byte_order; +#define IEEE_LITTLE 0xcc +#define IEEE_BIG 0xcd +} ieee_address_descriptor_type; + +typedef union ieee_w_variable { + file_ptr offset[N_W_VARIABLES]; + struct { + file_ptr extension_record; + file_ptr environmental_record; + file_ptr section_part; + file_ptr external_part; + file_ptr debug_information_part; + file_ptr data_part; + file_ptr trailer_part; + file_ptr me_record; + } r; +} ieee_w_variable_type; + + + + + +typedef enum ieee_record +{ + ieee_number_start_enum = 0x00, + ieee_number_end_enum=0x7f, + ieee_number_repeat_start_enum = 0x80, + ieee_number_repeat_end_enum = 0x88, + ieee_number_repeat_4_enum = 0x84, + ieee_number_repeat_3_enum = 0x83, + ieee_number_repeat_2_enum = 0x82, + ieee_number_repeat_1_enum = 0x81, + ieee_module_beginning_enum = 0xe0, + ieee_module_end_enum = 0xe1, + ieee_extension_length_1_enum = 0xde, + ieee_extension_length_2_enum = 0xdf, + ieee_section_type_enum = 0xe6, + ieee_section_alignment_enum = 0xe7, + ieee_external_symbol_enum = 0xe8, + ieee_comma = 0x90, + ieee_external_reference_enum = 0xe9, + ieee_set_current_section_enum = 0xe5, + ieee_address_descriptor_enum = 0xec, + ieee_load_constant_bytes_enum = 0xed, + ieee_load_with_relocation_enum = 0xe4, + + ieee_variable_A_enum = 0xc1, + ieee_variable_B_enum = 0xc2, + ieee_variable_C_enum = 0xc3, + ieee_variable_D_enum = 0xc4, + ieee_variable_E_enum = 0xc5, + ieee_variable_F_enum = 0xc6, + ieee_variable_G_enum = 0xc7, + ieee_variable_H_enum = 0xc8, + ieee_variable_I_enum = 0xc9, + ieee_variable_J_enum = 0xca, + ieee_variable_K_enum = 0xcb, + ieee_variable_L_enum = 0xcc, + ieee_variable_M_enum = 0xcd, + ieee_variable_N_enum = 0xce, + ieee_variable_O_enum = 0xcf, + ieee_variable_P_enum = 0xd0, + ieee_variable_Q_enum = 0xd1, + ieee_variable_R_enum = 0xd2, + ieee_variable_S_enum = 0xd3, + ieee_variable_T_enum = 0xd4, + ieee_variable_U_enum = 0xd5, + ieee_variable_V_enum = 0xd6, + ieee_variable_W_enum = 0xd7, + ieee_variable_X_enum = 0xd8, + ieee_variable_Y_enum = 0xd9, + ieee_variable_Z_enum = 0xda, + ieee_function_plus_enum = 0xa5, + ieee_function_minus_enum = 0xa6, + ieee_function_signed_open_b_enum = 0xba, + ieee_function_signed_close_b_enum = 0xbb, + + ieee_function_unsigned_open_b_enum = 0xbc, + ieee_function_unsigned_close_b_enum = 0xbd, + + ieee_function_either_open_b_enum = 0xbe, + ieee_function_either_close_b_enum = 0xbf, + ieee_record_seperator_enum = 0xdb, + + ieee_e2_first_byte_enum = 0xe2, + ieee_section_size_enum = 0xe2d3, + ieee_physical_region_size_enum = 0xe2c1, + ieee_region_base_address_enum = 0xe2c2, + ieee_mau_size_enum = 0xe2c6, + ieee_m_value_enum = 0xe2cd, + ieee_section_base_address_enum = 0xe2cc, + ieee_asn_record_enum = 0xe2ce, + ieee_section_offset_enum = 0xe2d2, + ieee_value_starting_address_enum = 0xe2c7, + ieee_assign_value_to_variable_enum = 0xe2d7, + ieee_set_current_pc_enum = 0xe2d0, + ieee_value_record_enum = 0xe2c9, + ieee_nn_record = 0xf0, + ieee_at_record_enum = 0xf1, + ieee_ty_record_enum = 0xf2, + ieee_attribute_record_enum = 0xf1c9, + ieee_atn_record_enum = 0xf1ce, + ieee_external_reference_info_record_enum = 0xf1d8, + ieee_weak_external_reference_enum= 0xf4, + ieee_repeat_data_enum = 0xf7, + ieee_bb_record_enum = 0xf8, + ieee_be_record_enum = 0xf9 +} ieee_record_enum_type; + + +typedef struct ieee_section { + unsigned int section_index; + unsigned int section_type; + char *section_name; + unsigned int parent_section_index; + unsigned int sibling_section_index; + unsigned int context_index; +} ieee_section_type; +#define IEEE_REFERENCE_BASE 11 +#define IEEE_PUBLIC_BASE 32 +#define IEEE_SECTION_NUMBER_BASE 1 + diff --git a/contrib/gdb/include/libiberty.h b/contrib/gdb/include/libiberty.h new file mode 100644 index 000000000000..dc083c8fe38a --- /dev/null +++ b/contrib/gdb/include/libiberty.h @@ -0,0 +1,133 @@ +/* Function declarations for libiberty. + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. */ + +#ifndef LIBIBERTY_H +#define LIBIBERTY_H + +#include "ansidecl.h" + +/* Build an argument vector from a string. Allocates memory using + malloc. Use freeargv to free the vector. */ + +extern char **buildargv PARAMS ((char *)); + +/* Free a vector returned by buildargv. */ + +extern void freeargv PARAMS ((char **)); + +/* Return the last component of a path name. */ + +extern char *basename (); + +/* Concatenate an arbitrary number of strings, up to (char *) NULL. + Allocates memory using xmalloc. */ + +extern char *concat PARAMS ((const char *, ...)); + +/* Check whether two file descriptors refer to the same file. */ + +extern int fdmatch PARAMS ((int fd1, int fd2)); + +/* Get the amount of time the process has run, in microseconds. */ + +extern long get_run_time PARAMS ((void)); + +/* Allocate memory filled with spaces. Allocates using malloc. */ + +extern const char *spaces PARAMS ((int count)); + +/* Return the maximum error number for which strerror will return a + string. */ + +extern int errno_max PARAMS ((void)); + +/* Return the name of an errno value (e.g., strerrno (EINVAL) returns + "EINVAL"). */ + +extern const char *strerrno PARAMS ((int)); + +/* Given the name of an errno value, return the value. */ + +extern int strtoerrno PARAMS ((const char *)); + +/* ANSI's strerror(), but more robust. */ + +extern char *xstrerror PARAMS ((int)); + +/* Return the maximum signal number for which strsignal will return a + string. */ + +extern int signo_max PARAMS ((void)); + +/* Return a signal message string for a signal number + (e.g., strsignal (SIGHUP) returns something like "Hangup"). */ +/* This is commented out as it can conflict with one in system headers. + We still document its existence though. */ + +/*extern const char *strsignal PARAMS ((int));*/ + +/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns + "SIGHUP"). */ + +extern const char *strsigno PARAMS ((int)); + +/* Given the name of a signal, return its number. */ + +extern int strtosigno PARAMS ((const char *)); + +/* Register a function to be run by xexit. Returns 0 on success. */ + +extern int xatexit PARAMS ((void (*fn) (void))); + +/* Exit, calling all the functions registered with xatexit. */ + +#ifndef __GNUC__ +extern void xexit PARAMS ((int status)); +#else +typedef void libiberty_voidfn PARAMS ((int status)); +__volatile__ libiberty_voidfn xexit; +#endif + +/* Set the program name used by xmalloc. */ + +extern void xmalloc_set_program_name PARAMS ((const char *)); + +/* Allocate memory without fail. If malloc fails, this will print a + message to stderr (using the name set by xmalloc_set_program_name, + if any) and then call xexit. + + FIXME: We do not declare the parameter type (size_t) in order to + avoid conflicts with other declarations of xmalloc that exist in + programs which use libiberty. */ + +extern PTR xmalloc (); + +/* Reallocate memory without fail. This works like xmalloc. + + FIXME: We do not declare the parameter types for the same reason as + xmalloc. */ + +extern PTR xrealloc (); + +/* Copy a string into a memory buffer without fail. */ + +extern char *xstrdup PARAMS ((const char *)); + +/* hex character manipulation routines */ + +#define _hex_array_size 256 +#define _hex_bad 99 +extern char _hex_value[_hex_array_size]; +extern void hex_init PARAMS ((void)); +#define hex_p(c) (hex_value (c) != _hex_bad) +/* If you change this, note well: Some code relies on side effects in + the argument being performed exactly once. */ +#define hex_value(c) (_hex_value[(unsigned char) (c)]) + +#endif /* ! defined (LIBIBERTY_H) */ diff --git a/contrib/gdb/include/mpw/ChangeLog b/contrib/gdb/include/mpw/ChangeLog new file mode 100644 index 000000000000..8dbad87eab47 --- /dev/null +++ b/contrib/gdb/include/mpw/ChangeLog @@ -0,0 +1,61 @@ +Tue Feb 27 12:23:04 1996 Raymond Jou + + * mpw.h (HAVE_VPRINTF): Add and define to have the value 1. + +Fri Dec 29 14:40:46 1995 Stan Shebs + + * mpw.h (HAVE_STDLIB_H, etc): Define to have the value 1. + (HAVE_FCNTL_H): Define. + +Mon Dec 11 15:39:06 1995 Stan Shebs + + * mpw.h (open, access): Define as mpw_open and mpw_access. + +Thu Nov 9 15:38:37 1995 Stan Shebs + + * mpw.h: Include unix.h if USE_MW_HEADERS, otherwise include + various original MPW include files (ioctl.h, etc). + (EIO): Define if not defined. + * sys/ioctl.h: Remove, not needed. + +Wed Oct 25 12:30:44 1995 Stan Shebs + + * mpw.h: Don't include errno.h or ioctl.h. + (ENOENT, EACCES, ENOSYS): Define if not defined. + (fdopen): Declare if __STDC__. + (R_OK, W_OK, X_OK): Define if not defined. + +Tue Sep 26 14:57:21 1995 Stan Shebs + + * mpw.h: New file, universally useful MPW host definitions. + Many of these used to live in bfd/hosts/mpw.h. + * grp.h: Remove RCS comment. + * sys/ioctl.h: Add a comment line. + +Wed Dec 14 13:12:14 1994 Stan Shebs + + * spin.h: New file, cursor spinning for progress. + +Thu Jun 30 15:32:07 1994 Stan Shebs (shebs@andros.cygnus.com) + + * fcntl.h (open): Allow optional third arg. + +Thu Apr 14 12:54:51 1994 Stan Shebs (shebs@andros.cygnus.com) + + * dir.h, dirent.h, fcntl.h, grp.h, pwd.h, stat.h: New files. + * sys/ioctl.h: New file. + +Mon Feb 21 09:44:45 1994 Stan Shebs (shebs@andros.cygnus.com) + + * sys/stat.h (struct stat): New field st_rsize. + (S_IFMT, etc): Use different bit positions. + (fstat): Add parameter names to prototype. + +Mon Jan 31 19:30:16 1994 Stan Shebs (shebs@andros.cygnus.com) + + * README: New file. + * utime.h, varargs.h: New files, simulated Posix. + * sys/{file,param,resource,stat,time,types}.h: New files, more + simulated Posix. + + diff --git a/contrib/gdb/include/mpw/README b/contrib/gdb/include/mpw/README new file mode 100644 index 000000000000..10e92de79f68 --- /dev/null +++ b/contrib/gdb/include/mpw/README @@ -0,0 +1 @@ +This is a collection of include files that help imitate Posix in MPW. diff --git a/contrib/gdb/include/mpw/dir.h b/contrib/gdb/include/mpw/dir.h new file mode 100644 index 000000000000..e6ccd2d59227 --- /dev/null +++ b/contrib/gdb/include/mpw/dir.h @@ -0,0 +1,23 @@ +/* The header gives the layout of a directory. */ + +#pragma once + +#ifndef _DIR_H +#define _DIR_H + +#ifndef _TYPES_H /* not quite right */ +#include +#endif + +#define DIRBLKSIZ 512 /* size of directory block */ + +#ifndef DIRSIZ +#define DIRSIZ 14 +#endif + +struct direct { + ino_t d_ino; + char d_name[DIRSIZ]; +}; + +#endif /* _DIR_H */ diff --git a/contrib/gdb/include/mpw/dirent.h b/contrib/gdb/include/mpw/dirent.h new file mode 100644 index 000000000000..38000b2c5f36 --- /dev/null +++ b/contrib/gdb/include/mpw/dirent.h @@ -0,0 +1,31 @@ +#ifndef __dirent_h +#define __dirent_h + +#include "sys/dir.h" + +struct dirent { + long d_ino; /* inode number of entry */ + off_t d_off; /* offset of disk directory entry */ + unsigned short d_reclen; /* length of this record */ + char d_name[1]; /* name of file */ +}; + +/* +#define DIRENTBASESIZE \ + (((struct dirent *) 0)->d_name - (char *) 0) +#define DIRENTSIZE(namelen) \ + ((DIRENTBASESIZE + (namelen) + NBPW) & ~(NBPW - 1)) +*/ + +/* from Mips posix/dirent.h */ + +/* +#undef rewinddir +*/ + +extern DIR *opendir(); +extern struct dirent *readdir(); +extern void rewinddir(); +extern int closedir(); + +#endif /* ! __dirent_h */ diff --git a/contrib/gdb/include/mpw/fcntl.h b/contrib/gdb/include/mpw/fcntl.h new file mode 100644 index 000000000000..30999b4b17df --- /dev/null +++ b/contrib/gdb/include/mpw/fcntl.h @@ -0,0 +1,124 @@ +/* + * FCntl.h -- faccess(), fcntl(), and open() mode flags + * + * Portions copyright American Telephone & Telegraph + * Used with permission, Apple Computer Inc. (1985,1988,1990,1992) + * All rights reserved. + */ + +#ifndef __FCNTL__ +#define __FCNTL__ + +#ifndef __TYPES__ +#include +#endif + +/* + * For use by lseek(): + */ + +#ifndef __STDIO__ /* these defns exactly paralled in StdIO.h for fseek() */ +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 +#endif + +/* + * faccess() commands; for general use + */ + /* 'd' => "directory" ops */ +#define F_DELETE (('d'<<8)|0x01) +#define F_RENAME (('d'<<8)|0x02) + +/* + * more faccess() commands; for use only by MPW tools + */ + +#define F_OPEN (('d'<<8)|0x00) /* reserved for operating system use */ + /* 'e' => "editor" ops */ +#define F_GTABINFO (('e'<<8)|0x00) /* get tab offset for file */ +#define F_STABINFO (('e'<<8)|0x01) /* set " " " " */ +#define F_GFONTINFO (('e'<<8)|0x02) /* get font number and size for file */ +#define F_SFONTINFO (('e'<<8)|0x03) /* set " " " " " " */ +#define F_GPRINTREC (('e'<<8)|0x04) /* get print record for file */ +#define F_SPRINTREC (('e'<<8)|0x05) /* set " " " " */ +#define F_GSELINFO (('e'<<8)|0x06) /* get selection information for file */ +#define F_SSELINFO (('e'<<8)|0x07) /* set " " " " */ +#define F_GWININFO (('e'<<8)|0x08) /* get current window position */ +#define F_SWININFO (('e'<<8)|0x09) /* set " " " */ +#define F_GSCROLLINFO (('e'<<8)|0x0A) /* get scroll information */ +#define F_SSCROLLINFO (('e'<<8)|0x0B) /* set " " */ +#define F_GMARKER (('e'<<8)|0x0D) /* Get Marker */ +#define F_SMARKER (('e'<<8)|0x0C) /* Set " */ +#define F_GSAVEONCLOSE (('e'<<8)|0x0F) /* Get Save on close */ +#define F_SSAVEONCLOSE (('e'<<8)|0x0E) /* Set " " " */ + +/* + * argument structures used by various faccess() commands + */ + +struct MarkElement { + int start; /* start position of mark */ + int end; /* end position */ + unsigned char charCount; /* number of chars in mark name */ + char name[64]; /* mark name */ +} ; /* note: marker names may be up to 64 characters long */ + +#ifndef __cplusplus +typedef struct MarkElement MarkElement; +#endif + +struct SelectionRecord { + long startingPos; + long endingPos; + long displayTop; +}; + +#ifndef __cplusplus +typedef struct SelectionRecord SelectionRecord; +#endif + + +/* + * Mode values accessible to open() + */ +#define O_RDONLY 0 /* Bits 0 and 1 are used internally */ +#define O_WRONLY 1 /* Values 0..2 are historical */ +#define O_RDWR 2 /* NOTE: it goes 0, 1, 2, *!* 8, 16, 32, ... */ +#define O_APPEND (1<< 3) /* append (writes guaranteed at the end) */ +#define O_RSRC (1<< 4) /* Open the resource fork */ +#define O_ALIAS (1<< 5) /* Open alias file */ +#define O_CREAT (1<< 8) /* Open with file create */ +#define O_TRUNC (1<< 9) /* Open with truncation */ +#define O_EXCL (1<<10) /* w/ O_CREAT: Exclusive "create-only" */ +#define O_BINARY (1<<11) /* Open as a binary stream */ +#define O_NRESOLVE (1<<14) /* Don't resolve any aliases */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * function prototypes + */ +int close(int); +int creat(const char*); +int dup(int filedes); /* OBSOLETE: fcntl(filedes, F_DUPFD, 0) is preferred */ +int faccess(char*, unsigned int, long*); +int fcntl(int, unsigned int, int); +long lseek(int, long, int); +int open(const char*, int, ...); +int read(int, char*, unsigned); +int unlink(char*); +int write(int, const char*, unsigned); + +#ifdef __cplusplus +} +#endif + +/* + * fcntl() commands + */ +#define F_DUPFD 0 /* Duplicate files (file descriptor) */ + +#endif __FCNTL__ diff --git a/contrib/gdb/include/mpw/grp.h b/contrib/gdb/include/mpw/grp.h new file mode 100644 index 000000000000..faf2c6a6be9b --- /dev/null +++ b/contrib/gdb/include/mpw/grp.h @@ -0,0 +1,10 @@ +#pragma once + +#include "sys/types.h" + +struct group { + char *gr_name; + gid_t gr_gid; + char *gr_passwd; + char **gr_mem; +}; diff --git a/contrib/gdb/include/mpw/mpw.h b/contrib/gdb/include/mpw/mpw.h new file mode 100644 index 000000000000..58702e725ff8 --- /dev/null +++ b/contrib/gdb/include/mpw/mpw.h @@ -0,0 +1,130 @@ +/* Mac MPW host-specific definitions. */ + +#ifndef __INCLUDE_MPW_H +#define __INCLUDE_MPW_H + +#ifndef MPW +#define MPW +#endif + +/* MPW C is basically ANSI, but doesn't actually enable __STDC__, + nor does it allow __STDC__ to be #defined. */ + +#ifndef ALMOST_STDC +#define ALMOST_STDC +#endif + +#include +#include +#include + +#define HAVE_TIME_T_IN_TIME_H 1 + +#define HAVE_STDLIB_H 1 + +#define HAVE_ERRNO_H 1 + +#define HAVE_STDDEF_H 1 + +#define HAVE_STRING_H 1 + +#define HAVE_STDARG_H 1 + +#define HAVE_VPRINTF 1 + +#ifdef USE_MW_HEADERS + +#include + +#else + +#include +#include +#include + +#define HAVE_FCNTL_H 1 + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#ifndef fileno +#define fileno(fp) ((fp)->_file) +#endif + +/* stdio.h does not define this if __STDC__, so define here. */ + +#ifdef __STDC__ +FILE *fdopen(int fildes, const char *mode); +#endif + +#endif /* USE_MW_HEADERS */ + +/* Add ersatz definitions, for systems that lack them. */ + +#ifndef EIO +#define EIO 96 +#endif +#ifndef ENOENT +#define ENOENT 97 +#endif +#ifndef EACCES +#define EACCES 98 +#endif +#ifndef ENOSYS +#define ENOSYS 99 +#endif + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +/* Binary files have different characteristics; for instance, no cr/nl + translation. */ + +#define USE_BINARY_FOPEN + +#include + +#ifdef MPW_C +#undef __PTR_TO_INT +#define __PTR_TO_INT(P) ((int)(P)) +#undef __INT_TO_PTR +#define __INT_TO_PTR(P) ((char *)(P)) +#endif /* MPW_C */ + +#define NO_FCNTL + +int fstat (); + +FILE *mpw_fopen (); +int mpw_fseek (); +int mpw_fread (); +int mpw_fwrite (); +int mpw_access (); +int mpw_open (); +int mpw_creat (); +void mpw_abort (void); + +/* Map these standard functions to improved versions in libiberty. */ + +#define fopen mpw_fopen +#define fseek mpw_fseek +#define fread mpw_fread +#define fwrite mpw_fwrite +#define open mpw_open +#define access mpw_access +#define creat mpw_creat +#define abort mpw_abort + +#define POSIX_UTIME + +#define LOSING_TOTALLY + +/* Define this so that files will be closed before being unlinked. */ + +#define CLOSE_BEFORE_UNLINK + +#endif /* __INCLUDE_MPW_H */ diff --git a/contrib/gdb/include/mpw/pwd.h b/contrib/gdb/include/mpw/pwd.h new file mode 100644 index 000000000000..2d4fb70401aa --- /dev/null +++ b/contrib/gdb/include/mpw/pwd.h @@ -0,0 +1,15 @@ +#ifndef __pwd_h +#define __pwd_h + +#include + +struct passwd { + char *pw_name; + uid_t pw_uid; + gid_t pw_gid; + char *pw_dir; + char *pw_shell; + char *pw_passwd; +}; + +#endif /* ! __pwd_h */ diff --git a/contrib/gdb/include/mpw/spin.h b/contrib/gdb/include/mpw/spin.h new file mode 100644 index 000000000000..867d14502c00 --- /dev/null +++ b/contrib/gdb/include/mpw/spin.h @@ -0,0 +1,64 @@ +/* Progress macros that use SpinCursor in MPW. + Copyright (C) 1994 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SPIN_H +#define _SPIN_H + +/* For MPW, progress macros just need to "spin the cursor" frequently, + preferably several times per second on a 68K Mac. */ + +/* In order to determine if we're meeting the goal, define this macro + and information about frequency of spinning will be collected and + displayed. */ + +#define SPIN_MEASUREMENT + +#include + +/* Programs use this macro to indicate the start of a lengthy + activity. STR identifies the particular activity, while N + indicates the expected duration, in unspecified units. If N is + zero, then the expected time to completion is unknown. */ + +#undef START_PROGRESS +#define START_PROGRESS(STR,N) mpw_start_progress (STR, N, __FILE__, __LINE__); + +/* Programs use this macro to indicate that progress has been made on a + lengthy activity. */ + +#undef PROGRESS +#ifdef SPIN_MEASUREMENT +#define PROGRESS(X) mpw_progress_measured (X, __FILE__, __LINE__); +#else +#define PROGRESS(X) mpw_progress (X); +#endif + +/* Programs use this macro to indicate the end of a lengthy activity. + STR must match a STR passed to START_PROGRESS previously. */ + +#undef END_PROGRESS +#define END_PROGRESS(STR) mpw_end_progress (STR, __FILE__, __LINE__); + +extern void mpw_start_progress (char *, int, char *, int); + +extern void mpw_progress (int); + +extern void mpw_progress_measured (int, char *, int); + +extern void mpw_end_progress (char *, char *, int); + +#endif /* _SPIN_H */ diff --git a/contrib/gdb/include/mpw/stat.h b/contrib/gdb/include/mpw/stat.h new file mode 100644 index 000000000000..057b8d531139 --- /dev/null +++ b/contrib/gdb/include/mpw/stat.h @@ -0,0 +1,75 @@ +/* The header defines a struct that is used in the stat() and + * fstat functions. The information in this struct comes from the i-node of + * some file. These calls are the only approved way to inspect i-nodes. + */ + +#ifndef _STAT_H +#define _STAT_H + +#ifndef _TYPES_H /* not quite right */ +#include +#endif + +struct stat { + dev_t st_dev; /* major/minor device number */ + ino_t st_ino; /* i-node number */ + mode_t st_mode; /* file mode, protection bits, etc. */ + short int st_nlink; /* # links; TEMPORARY HACK: should be nlink_t*/ + uid_t st_uid; /* uid of the file's owner */ + short int st_gid; /* gid; TEMPORARY HACK: should be gid_t */ + dev_t st_rdev; + off_t st_size; /* file size */ + time_t st_atime; /* time of last access */ + time_t st_mtime; /* time of last data modification */ + time_t st_ctime; /* time of last file status change */ +}; + +/* Traditional mask definitions for st_mode. */ +#define S_IFMT 0170000 /* type of file */ +#define S_IFREG 0100000 /* regular */ +#define S_IFBLK 0060000 /* block special */ +#define S_IFDIR 0040000 /* directory */ +#define S_IFCHR 0020000 /* character special */ +#define S_IFIFO 0010000 /* this is a FIFO */ +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ + /* next is reserved for future use */ +#define S_ISVTX 01000 /* save swapped text even after use */ + +/* POSIX masks for st_mode. */ +#define S_IRWXU 00700 /* owner: rwx------ */ +#define S_IRUSR 00400 /* owner: r-------- */ +#define S_IWUSR 00200 /* owner: -w------- */ +#define S_IXUSR 00100 /* owner: --x------ */ + +#define S_IRWXG 00070 /* group: ---rwx--- */ +#define S_IRGRP 00040 /* group: ---r----- */ +#define S_IWGRP 00020 /* group: ----w---- */ +#define S_IXGRP 00010 /* group: -----x--- */ + +#define S_IRWXO 00007 /* others: ------rwx */ +#define S_IROTH 00004 /* others: ------r-- */ +#define S_IWOTH 00002 /* others: -------w- */ +#define S_IXOTH 00001 /* others: --------x */ + +/* The following macros test st_mode (from POSIX Sec. 5.6.1.1. */ +#define S_ISREG(m) ((m & S_IFMT) == S_IFREG) /* is a reg file */ +#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) /* is a directory */ +#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) /* is a char spec */ +#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) /* is a block spec */ +#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO) /* is a pipe/FIFO */ + + +/* Function Prototypes. */ +#ifndef _ANSI_H +#include +#endif + +_PROTOTYPE( int chmod, (const char *_path, int _mode) ); +_PROTOTYPE( int fstat, (int _fildes, struct stat *_buf) ); +_PROTOTYPE( int mkdir, (const char *_path, int _mode) ); +_PROTOTYPE( int mkfifo, (const char *_path, int _mode) ); +_PROTOTYPE( int stat , (const char *_path, struct stat *_buf) ); +_PROTOTYPE( mode_t umask, (int _cmask) ); + +#endif /* _STAT_H */ diff --git a/contrib/gdb/include/mpw/sys/file.h b/contrib/gdb/include/mpw/sys/file.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/contrib/gdb/include/mpw/sys/file.h @@ -0,0 +1 @@ +/* empty */ diff --git a/contrib/gdb/include/mpw/sys/param.h b/contrib/gdb/include/mpw/sys/param.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/contrib/gdb/include/mpw/sys/param.h @@ -0,0 +1 @@ +/* empty */ diff --git a/contrib/gdb/include/mpw/sys/resource.h b/contrib/gdb/include/mpw/sys/resource.h new file mode 100644 index 000000000000..d39439d61d52 --- /dev/null +++ b/contrib/gdb/include/mpw/sys/resource.h @@ -0,0 +1,9 @@ +#ifndef __SYS_RESOURCE_H__ +#define __SYS_RESOURCE_H__ + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; +}; + +#endif /* __SYS_RESOURCE_H__ */ diff --git a/contrib/gdb/include/mpw/sys/stat.h b/contrib/gdb/include/mpw/sys/stat.h new file mode 100644 index 000000000000..b65c72e10c6a --- /dev/null +++ b/contrib/gdb/include/mpw/sys/stat.h @@ -0,0 +1,44 @@ +/* Imitation sys/stat.h. */ + +#ifndef __SYS_STAT_H__ +#define __SYS_STAT_H__ + +#include +#include + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + short st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + off_t st_rsize; + time_t st_atime; + int st_spare1; + time_t st_mtime; + int st_spare2; + time_t st_ctime; + int st_spare3; + long st_blksize; + long st_blocks; + long st_spare4[2]; +}; + +#define S_IFMT 0170000L +#define S_IFDIR 0040000L +#define S_IFREG 0100000L +#define S_IREAD 0400 +#define S_IWRITE 0200 +#define S_IEXEC 0100 + +#define S_IFIFO 010000 /* FIFO special */ +#define S_IFCHR 020000 /* character special */ +#define S_IFBLK 030000 /* block special */ + +int stat (char *path, struct stat *buf); +int fstat (int fd, struct stat *buf); + +#endif /* __SYS_STAT_H___ */ diff --git a/contrib/gdb/include/mpw/sys/time.h b/contrib/gdb/include/mpw/sys/time.h new file mode 100644 index 000000000000..f9e485232a21 --- /dev/null +++ b/contrib/gdb/include/mpw/sys/time.h @@ -0,0 +1,13 @@ +/* Imitation sys/time.h. */ + +#ifndef __SYS_TIME_H__ +#define __SYS_TIME_H__ + +#include + +struct timeval { + long tv_sec; + long tv_usec; +}; + +#endif /* __SYS_TIME_H__ */ diff --git a/contrib/gdb/include/mpw/sys/types.h b/contrib/gdb/include/mpw/sys/types.h new file mode 100644 index 000000000000..d7d9c9f44ba0 --- /dev/null +++ b/contrib/gdb/include/mpw/sys/types.h @@ -0,0 +1,15 @@ +/* Imitation sys/types.h. */ + +#ifndef __SYS_TYPES_H__ +#define __SYS_TYPES_H__ + +#include + +typedef short dev_t; +typedef short ino_t; +typedef unsigned short mode_t; +typedef unsigned short uid_t; +typedef unsigned short gid_t; +typedef long off_t; + +#endif /* __SYS_TYPES_H__ */ diff --git a/contrib/gdb/include/mpw/utime.h b/contrib/gdb/include/mpw/utime.h new file mode 100644 index 000000000000..e8bf66f2ba5c --- /dev/null +++ b/contrib/gdb/include/mpw/utime.h @@ -0,0 +1,7 @@ + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +int utime (char *, struct utimbuf *); diff --git a/contrib/gdb/include/mpw/varargs.h b/contrib/gdb/include/mpw/varargs.h new file mode 100644 index 000000000000..acb9e4504a2d --- /dev/null +++ b/contrib/gdb/include/mpw/varargs.h @@ -0,0 +1,9 @@ +/* varargs.h. */ +#ifndef __va_list__ +#define __va_list__ +typedef char *va_list; +#endif +#define va_dcl int va_alist; +#define va_start(list) list = (char *) &va_alist +#define va_end(list) +#define va_arg(list,mode) ((mode *)(list += sizeof(mode)))[-1] diff --git a/contrib/gdb/include/nlm/ChangeLog b/contrib/gdb/include/nlm/ChangeLog new file mode 100644 index 000000000000..d9ea3d09e0aa --- /dev/null +++ b/contrib/gdb/include/nlm/ChangeLog @@ -0,0 +1,83 @@ +Fri May 6 13:31:04 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * external.h (nlmNAME(External_Custom_Header)): Add length, + dataOffset, and dataStamp field. + (nlmNAME(External_Cygnus_Ext_Header)): Remove. + * internal.h (Nlm_Internal_Custom_Header): Add hdrLength, + dataOffset, dataStamp and hdr fields. + +Fri Apr 22 11:12:39 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * external.h (struct nlmNAME(external_cygnus_ext_header)): Rename + from nlmNAME(external_cygnus_section_header). Change stamp field + to 8 bytes. Add bytes field. + * internal.h (nlm_internal_cygnus_ext_header): Rename from + nlm_internal_cygnus_section_header. Change stamp field to 8 + bytes. + +Thu Apr 21 11:57:09 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h (struct nlm_internal_cygnus_section_header): Define. + * external.h (struct nlmNAME(external_cygnus_section_header): + Define. + +Wed Apr 20 14:27:43 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h (struct nlm_internal_custom_header): Remove + debugRecOffset and debugRecLength fields. Add data field. + * external.h (struct nlmNAME(external_custom_header)): Remove + debugRecOffset and debugRecLength fields. + +Mon Feb 7 08:28:40 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * internal.h: Change HOST_64_BIT to BFD_HOST_64_BIT. + +Thu Dec 2 14:14:48 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * alpha-ext.h: New file describing formats of information in Alpha + NetWare files. + * common.h: Define some non-external Alpha information. + +Wed Nov 17 17:38:58 1993 Sean Eric Fagan (sef@cygnus.com) + + * external.h: Don't define external_fixed_header here. + * i386-ext.h, sparc32-ext.h: New header files to define + external_fixed_header for particular CPU's. + +Wed Oct 27 11:45:56 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h (Nlm_Internal_Extended_Header): Added fields + sharedDebugRecordOffset and sharedDebugRecordCount. + * external.h (NlmNAME(External_Extended_Header)): Likewise. + + * common.h (NLM_SIGNATURE): Do not define (it's different for each + backend). + +Tue Aug 31 13:24:15 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * internal.h: Change length fields of type char to type unsigned + char. + +Sat Jul 31 02:12:14 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * common.h (NLM_HIBIT, NLM_HEADER_VERSION): Define. + +Thu Jul 22 16:09:47 1993 Fred Fish (fnf@deneb.cygnus.com) + + * common.h (NLM_CAT*, NLM_ARCH_SIZE, NLM_TARGET_LONG_SIZE, + NLM_TARGET_ADDRESS_SIZE, NLM_NAME, NlmNAME, nlmNAME): New + macros. + * external.h (TARGET_LONG_SIZE, TARGET_ADDRESS_SIZE): Remove + macros, convert usages to NLM_ equivalents. + * external.h: Use nlmNAME and NlmNAME macros to derive both + 32 and 64 bit versions. + +Mon Jul 19 22:12:40 1993 Fred Fish (fnf@deneb.cygnus.com) + + * (common.h, external.h, internal.h): New files for NLM/NetWare + support. + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/include/nlm/alpha-ext.h b/contrib/gdb/include/nlm/alpha-ext.h new file mode 100644 index 000000000000..37199dd1dc0d --- /dev/null +++ b/contrib/gdb/include/nlm/alpha-ext.h @@ -0,0 +1,166 @@ +/* Alpha NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + By Ian Lance Taylor, Cygnus Support + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* An Alpha NLM starts with an instance of this structure. */ + +struct nlm32_alpha_external_prefix_header +{ + /* Magic number. Must be NLM32_ALPHA_MAGIC. */ + unsigned char magic[4]; + /* Format descriptor. Current value is 2. */ + unsigned char format[4]; + /* Size of prefix header. */ + unsigned char size[4]; + /* Padding. */ + unsigned char pad1[4]; + /* More fields may be added later, supposedly. */ +}; + +/* The external format of an Alpha NLM reloc. This is the same as an + Alpha ECOFF reloc. */ + +struct nlm32_alpha_external_reloc +{ + unsigned char r_vaddr[8]; + unsigned char r_symndx[4]; + unsigned char r_bits[4]; +}; + +/* Constants to unpack the r_bits field of a reloc. */ + +#define RELOC_BITS0_TYPE_LITTLE 0xff +#define RELOC_BITS0_TYPE_SH_LITTLE 0 + +#define RELOC_BITS1_EXTERN_LITTLE 0x01 + +#define RELOC_BITS1_OFFSET_LITTLE 0x7e +#define RELOC_BITS1_OFFSET_SH_LITTLE 1 + +#define RELOC_BITS1_RESERVED_LITTLE 0x80 +#define RELOC_BITS1_RESERVED_SH_LITTLE 7 +#define RELOC_BITS2_RESERVED_LITTLE 0xff +#define RELOC_BITS2_RESERVED_SH_LEFT_LITTLE 1 +#define RELOC_BITS3_RESERVED_LITTLE 0x03 +#define RELOC_BITS3_RESERVED_SH_LEFT_LITTLE 9 + +#define RELOC_BITS3_SIZE_LITTLE 0xfc +#define RELOC_BITS3_SIZE_SH_LITTLE 2 + +/* The external format of the fixed header. */ + +typedef struct nlm32_alpha_external_fixed_header +{ + + /* The signature field identifies the file as an NLM. It must contain + the signature string, which depends upon the NLM target. */ + + unsigned char signature[24]; + + /* The version of the header. At this time, the highest version number + is 4. */ + + unsigned char version[4]; + + /* The name of the module, which must be a DOS name (1-8 characters followed + by a period and a 1-3 character extension). The first byte is the byte + length of the name and the last byte is a null terminator byte. This + field is fixed length, and any unused bytes should be null bytes. The + value is set by the OUTPUT keyword to NLMLINK. */ + + unsigned char moduleName[14]; + + /* Padding to make it come out correct. */ + + unsigned char pad1[2]; + + /* The byte offset of the code image from the start of the file. */ + + unsigned char codeImageOffset[4]; + + /* The size of the code image, in bytes. */ + + unsigned char codeImageSize[4]; + + /* The byte offset of the data image from the start of the file. */ + + unsigned char dataImageOffset[4]; + + /* The size of the data image, in bytes. */ + + unsigned char dataImageSize[4]; + + /* The size of the uninitialized data region that the loader is to be + allocated at load time. Uninitialized data follows the initialized + data in the NLM address space. */ + + unsigned char uninitializedDataSize[4]; + + /* The byte offset of the custom data from the start of the file. The + custom data is set by the CUSTOM keyword to NLMLINK. It is possible + for this to be EOF if there is no custom data. */ + + unsigned char customDataOffset[4]; + + /* The size of the custom data, in bytes. */ + + unsigned char customDataSize[4]; + + /* The byte offset of the module dependencies from the start of the file. + The module dependencies are determined by the MODULE keyword in + NLMLINK. */ + + unsigned char moduleDependencyOffset[4]; + + /* The number of module dependencies at the moduleDependencyOffset. */ + + unsigned char numberOfModuleDependencies[4]; + + /* The byte offset of the relocation fixup data from the start of the file */ + + unsigned char relocationFixupOffset[4]; + + unsigned char numberOfRelocationFixups[4]; + + unsigned char externalReferencesOffset[4]; + + unsigned char numberOfExternalReferences[4]; + + unsigned char publicsOffset[4]; + + unsigned char numberOfPublics[4]; + + /* The byte offset of the internal debug info from the start of the file. + It is possible for this to be EOF if there is no debug info. */ + + unsigned char debugInfoOffset[4]; + + unsigned char numberOfDebugRecords[4]; + + unsigned char codeStartOffset[4]; + + unsigned char exitProcedureOffset[4]; + + unsigned char checkUnloadProcedureOffset[4]; + + unsigned char moduleType[4]; + + unsigned char flags[4]; + +} Nlm32_alpha_External_Fixed_Header; diff --git a/contrib/gdb/include/nlm/common.h b/contrib/gdb/include/nlm/common.h new file mode 100644 index 000000000000..e96550a92f6d --- /dev/null +++ b/contrib/gdb/include/nlm/common.h @@ -0,0 +1,124 @@ +/* NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of NLM support for BFD, and contains the portions + that are common to both the internal and external representations. */ + +/* Semi-portable string concatenation in cpp. + The NLM_CAT4 hack is to avoid a problem with some strict ANSI C + preprocessors. The problem is, "32_" or "64_" are not a valid + preprocessing tokens, and we don't want extra underscores (e.g., + "nlm_32_"). The XNLM_CAT2 macro will cause the inner NLM_CAT macros + to be evaluated first, producing still-valid pp-tokens. Then the + final concatenation can be done. (Sigh.) */ + +#ifdef SABER +# define NLM_CAT(a,b) a##b +# define NLM_CAT3(a,b,c) a##b##c +# define NLM_CAT4(a,b,c,d) a##b##c##d +#else +# ifdef __STDC__ +# define NLM_CAT(a,b) a##b +# define NLM_CAT3(a,b,c) a##b##c +# define XNLM_CAT2(a,b) NLM_CAT(a,b) +# define NLM_CAT4(a,b,c,d) XNLM_CAT2(NLM_CAT(a,b),NLM_CAT(c,d)) +# else +# define NLM_CAT(a,b) a/**/b +# define NLM_CAT3(a,b,c) a/**/b/**/c +# define NLM_CAT4(a,b,c,d) a/**/b/**/c/**/d +# endif +#endif + +/* If NLM_ARCH_SIZE is not defined, default to 32. NLM_ARCH_SIZE is + optionally defined by the application. */ + +#ifndef NLM_ARCH_SIZE +# define NLM_ARCH_SIZE 32 +#endif + +#if NLM_ARCH_SIZE == 32 +# define NLM_TARGET_LONG_SIZE 4 +# define NLM_TARGET_ADDRESS_SIZE 4 +# define NLM_NAME(x,y) NLM_CAT4(x,32,_,y) +# define NLM_HIBIT (((bfd_vma) 1) << 31) +#endif +#if NLM_ARCH_SIZE == 64 +# define NLM_TARGET_LONG_SIZE 8 +# define NLM_TARGET_ADDRESS_SIZE 8 +# define NLM_NAME(x,y) NLM_CAT4(x,64,_,y) +# define NLM_HIBIT (((bfd_vma) 1) << 63) +#endif + +#define NlmNAME(X) NLM_NAME(Nlm,X) +#define nlmNAME(X) NLM_NAME(nlm,X) + +/* Give names to things that should not change. */ + +#define NLM_MAX_DESCRIPTION_LENGTH 127 +#define NLM_MAX_SCREEN_NAME_LENGTH 71 +#define NLM_MAX_THREAD_NAME_LENGTH 71 +#define NLM_MAX_COPYRIGHT_MESSAGE_LENGTH 255 +#define NLM_OTHER_DATA_LENGTH 400 /* FIXME */ +#define NLM_OLD_THREAD_NAME_LENGTH 5 +#define NLM_SIGNATURE_SIZE 24 +#define NLM_HEADER_VERSION 4 +#define NLM_MODULE_NAME_SIZE 14 +#define NLM_DEFAULT_STACKSIZE (8 * 1024) + +/* Alpha information. This should probably be in a separate Alpha + header file, but it can't go in alpha-ext.h because some of it is + needed by nlmconv.c. */ + +/* Magic number in Alpha prefix header. */ +#define NLM32_ALPHA_MAGIC (0x83561840) + +/* The r_type field in an Alpha reloc is one of the following values. */ +#define ALPHA_R_IGNORE 0 +#define ALPHA_R_REFLONG 1 +#define ALPHA_R_REFQUAD 2 +#define ALPHA_R_GPREL32 3 +#define ALPHA_R_LITERAL 4 +#define ALPHA_R_LITUSE 5 +#define ALPHA_R_GPDISP 6 +#define ALPHA_R_BRADDR 7 +#define ALPHA_R_HINT 8 +#define ALPHA_R_SREL16 9 +#define ALPHA_R_SREL32 10 +#define ALPHA_R_SREL64 11 +#define ALPHA_R_OP_PUSH 12 +#define ALPHA_R_OP_STORE 13 +#define ALPHA_R_OP_PSUB 14 +#define ALPHA_R_OP_PRSHIFT 15 +#define ALPHA_R_GPVALUE 16 +#define ALPHA_R_NW_RELOC 250 + +/* A local reloc, other than ALPHA_R_GPDISP or ALPHA_R_IGNORE, must be + against one of these symbol indices. */ +#define ALPHA_RELOC_SECTION_TEXT 1 +#define ALPHA_RELOC_SECTION_DATA 3 + +/* An ALPHA_R_NW_RELOC has one of these values in the size field. If + it is SETGP, the r_vaddr field holds the GP value to use. If it is + LITA, the r_vaddr field holds the address of the .lita section and + the r_symndx field holds the size of the .lita section. */ +#define ALPHA_R_NW_RELOC_SETGP 1 +#define ALPHA_R_NW_RELOC_LITA 2 diff --git a/contrib/gdb/include/nlm/external.h b/contrib/gdb/include/nlm/external.h new file mode 100644 index 000000000000..f77a5bb3dda0 --- /dev/null +++ b/contrib/gdb/include/nlm/external.h @@ -0,0 +1,174 @@ +/* NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of NLM support for BFD, and contains the portions + that describe how NLM is represented externally by the BFD library. + I.E. it describes the in-file representation of NLM. It requires + the nlm/common.h file which contains the portions that are common to + both the internal and external representations. + + Note that an NLM header consists of three parts: + + (1) A fixed length header that has specific fields of known length, + at specific offsets in the file. + + (2) A variable length header that has specific fields in a specific + order, but some fields may be variable length. + + (3) A auxiliary header that has various optional fields in no specific + order. There is no way to identify the end of the auxiliary headers + except by finding a header without a recognized 'stamp'. + + The exact format of the fixed length header unfortunately varies + from one NLM target to another, due to padding. Each target + defines the correct external format in a separate header file. + +*/ + +/* NLM Header */ + +/* The version header is one of the optional auxiliary headers and + follows the fixed length and variable length NLM headers. */ + +typedef struct nlmNAME(external_version_header) +{ + + /* The header is recognized by "VeRsIoN#" in the stamp field. */ + char stamp[8]; + + unsigned char majorVersion[NLM_TARGET_LONG_SIZE]; + + unsigned char minorVersion[NLM_TARGET_LONG_SIZE]; + + unsigned char revision[NLM_TARGET_LONG_SIZE]; + + unsigned char year[NLM_TARGET_LONG_SIZE]; + + unsigned char month[NLM_TARGET_LONG_SIZE]; + + unsigned char day[NLM_TARGET_LONG_SIZE]; + +} NlmNAME(External_Version_Header); + + +typedef struct nlmNAME(external_copyright_header) +{ + + /* The header is recognized by "CoPyRiGhT=" in the stamp field. */ + + char stamp[10]; + + unsigned char copyrightMessageLength[1]; + + /* There is a variable length field here called 'copyrightMessage' + that is the length specified by copyrightMessageLength. */ + +} NlmNAME(External_Copyright_Header); + + +typedef struct nlmNAME(external_extended_header) +{ + + /* The header is recognized by "MeSsAgEs" in the stamp field. */ + + char stamp[8]; + + unsigned char languageID[NLM_TARGET_LONG_SIZE]; + + unsigned char messageFileOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char messageFileLength[NLM_TARGET_LONG_SIZE]; + + unsigned char messageCount[NLM_TARGET_LONG_SIZE]; + + unsigned char helpFileOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char helpFileLength[NLM_TARGET_LONG_SIZE]; + + unsigned char RPCDataOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char RPCDataLength[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedCodeOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedCodeLength[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedDataOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedDataLength[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedRelocationFixupOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedRelocationFixupCount[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedExternalReferenceOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedExternalReferenceCount[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedPublicsOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedPublicsCount[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedDebugRecordOffset[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedDebugRecordCount[NLM_TARGET_LONG_SIZE]; + + unsigned char sharedInitializationOffset[NLM_TARGET_ADDRESS_SIZE]; + + unsigned char SharedExitProcedureOffset[NLM_TARGET_ADDRESS_SIZE]; + + unsigned char productID[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved0[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved1[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved2[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved3[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved4[NLM_TARGET_LONG_SIZE]; + + unsigned char reserved5[NLM_TARGET_LONG_SIZE]; + +} NlmNAME(External_Extended_Header); + + +typedef struct nlmNAME(external_custom_header) +{ + + /* The header is recognized by "CuStHeAd" in the stamp field. */ + char stamp[8]; + + /* Length of this header. */ + unsigned char length[NLM_TARGET_LONG_SIZE]; + + /* Offset to data. */ + unsigned char dataOffset[NLM_TARGET_LONG_SIZE]; + + /* Length of data. */ + unsigned char dataLength[NLM_TARGET_LONG_SIZE]; + + /* Stamp for this customer header--we recognize "CyGnUsEx". */ + char dataStamp[8]; + +} NlmNAME(External_Custom_Header); diff --git a/contrib/gdb/include/nlm/i386-ext.h b/contrib/gdb/include/nlm/i386-ext.h new file mode 100644 index 000000000000..d33ad2da770a --- /dev/null +++ b/contrib/gdb/include/nlm/i386-ext.h @@ -0,0 +1,116 @@ +/* i386 NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The external format of the fixed header. */ + +typedef struct nlm32_i386_external_fixed_header +{ + + /* The signature field identifies the file as an NLM. It must contain + the signature string, which depends upon the NLM target. */ + + unsigned char signature[24]; + + /* The version of the header. At this time, the highest version number + is 4. */ + + unsigned char version[4]; + + /* The name of the module, which must be a DOS name (1-8 characters followed + by a period and a 1-3 character extension). The first byte is the byte + length of the name and the last byte is a null terminator byte. This + field is fixed length, and any unused bytes should be null bytes. The + value is set by the OUTPUT keyword to NLMLINK. */ + + unsigned char moduleName[14]; + + /* The byte offset of the code image from the start of the file. */ + + unsigned char codeImageOffset[4]; + + /* The size of the code image, in bytes. */ + + unsigned char codeImageSize[4]; + + /* The byte offset of the data image from the start of the file. */ + + unsigned char dataImageOffset[4]; + + /* The size of the data image, in bytes. */ + + unsigned char dataImageSize[4]; + + /* The size of the uninitialized data region that the loader is to be + allocated at load time. Uninitialized data follows the initialized + data in the NLM address space. */ + + unsigned char uninitializedDataSize[4]; + + /* The byte offset of the custom data from the start of the file. The + custom data is set by the CUSTOM keyword to NLMLINK. It is possible + for this to be EOF if there is no custom data. */ + + unsigned char customDataOffset[4]; + + /* The size of the custom data, in bytes. */ + + unsigned char customDataSize[4]; + + /* The byte offset of the module dependencies from the start of the file. + The module dependencies are determined by the MODULE keyword in + NLMLINK. */ + + unsigned char moduleDependencyOffset[4]; + + /* The number of module dependencies at the moduleDependencyOffset. */ + + unsigned char numberOfModuleDependencies[4]; + + /* The byte offset of the relocation fixup data from the start of the file */ + + unsigned char relocationFixupOffset[4]; + + unsigned char numberOfRelocationFixups[4]; + + unsigned char externalReferencesOffset[4]; + + unsigned char numberOfExternalReferences[4]; + + unsigned char publicsOffset[4]; + + unsigned char numberOfPublics[4]; + + /* The byte offset of the internal debug info from the start of the file. + It is possible for this to be EOF if there is no debug info. */ + + unsigned char debugInfoOffset[4]; + + unsigned char numberOfDebugRecords[4]; + + unsigned char codeStartOffset[4]; + + unsigned char exitProcedureOffset[4]; + + unsigned char checkUnloadProcedureOffset[4]; + + unsigned char moduleType[4]; + + unsigned char flags[4]; + +} Nlm32_i386_External_Fixed_Header; diff --git a/contrib/gdb/include/nlm/internal.h b/contrib/gdb/include/nlm/internal.h new file mode 100644 index 000000000000..dd27dc407f59 --- /dev/null +++ b/contrib/gdb/include/nlm/internal.h @@ -0,0 +1,309 @@ +/* NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of NLM support for BFD, and contains the portions + that describe how NLM is represented internally in the BFD library. + I.E. it describes the in-memory representation of NLM. It requires + the nlm/common.h file which contains the portions that are common to + both the internal and external representations. */ + +#if 0 + +/* Types used by various structures, functions, etc. */ + +typedef unsigned long Nlm32_Addr; /* Unsigned program address */ +typedef unsigned long Nlm32_Off; /* Unsigned file offset */ +typedef long Nlm32_Sword; /* Signed large integer */ +typedef unsigned long Nlm32_Word; /* Unsigned large integer */ +typedef unsigned short Nlm32_Half; /* Unsigned medium integer */ +typedef unsigned char Nlm32_Char; /* Unsigned tiny integer */ + +#ifdef BFD_HOST_64_BIT +typedef unsigned BFD_HOST_64_BIT Nlm64_Addr; +typedef unsigned BFD_HOST_64_BIT Nlm64_Off; +typedef BFD_HOST_64_BIT Nlm64_Sxword; +typedef unsigned BFD_HOST_64_BIT Nlm64_Xword; +#endif +typedef long Nlm64_Sword; +typedef unsigned long Nlm64_Word; +typedef unsigned short Nlm64_Half; + +#endif /* 0 */ + +/* This structure contains the internal form of the portion of the NLM + header that is fixed length. */ + +typedef struct nlm_internal_fixed_header +{ + /* The signature field identifies the file as an NLM. It must contain + the signature string, which depends upon the NLM target. */ + + char signature[NLM_SIGNATURE_SIZE]; + + /* The version of the header. At this time, the highest version number + is 4. */ + + long version; + + /* The name of the module, which must be a DOS name (1-8 characters followed + by a period and a 1-3 character extension. The first byte is the byte + length of the name and the last byte is a null terminator byte. This + field is fixed length, and any unused bytes should be null bytes. The + value is set by the OUTPUT keyword to NLMLINK. */ + + char moduleName[NLM_MODULE_NAME_SIZE]; + + /* The byte offset of the code image from the start of the file. */ + + file_ptr codeImageOffset; + + /* The size of the code image, in bytes. */ + + bfd_size_type codeImageSize; + + /* The byte offset of the data image from the start of the file. */ + + file_ptr dataImageOffset; + + /* The size of the data image, in bytes. */ + + bfd_size_type dataImageSize; + + /* The size of the uninitialized data region that the loader is to be + allocated at load time. Uninitialized data follows the initialized + data in the NLM address space. */ + + bfd_size_type uninitializedDataSize; + + /* The byte offset of the custom data from the start of the file. The + custom data is set by the CUSTOM keyword to NLMLINK. */ + + file_ptr customDataOffset; + + /* The size of the custom data, in bytes. */ + + bfd_size_type customDataSize; + + /* The byte offset of the module dependencies from the start of the file. + The module dependencies are determined by the MODULE keyword in + NLMLINK. */ + + file_ptr moduleDependencyOffset; + + /* The number of module dependencies at the moduleDependencyOffset. */ + + long numberOfModuleDependencies; + + /* The byte offset of the relocation fixup data from the start of the file */ + + file_ptr relocationFixupOffset; + long numberOfRelocationFixups; + file_ptr externalReferencesOffset; + long numberOfExternalReferences; + file_ptr publicsOffset; + long numberOfPublics; + file_ptr debugInfoOffset; + long numberOfDebugRecords; + file_ptr codeStartOffset; + file_ptr exitProcedureOffset; + file_ptr checkUnloadProcedureOffset; + long moduleType; + long flags; +} Nlm_Internal_Fixed_Header; + +#define nlm32_internal_fixed_header nlm_internal_fixed_header +#define Nlm32_Internal_Fixed_Header Nlm_Internal_Fixed_Header +#define nlm64_internal_fixed_header nlm_internal_fixed_header +#define Nlm64_Internal_Fixed_Header Nlm_Internal_Fixed_Header + +/* This structure contains the portions of the NLM header that are either + variable in size in the external representation, or else are not at a + fixed offset relative to the start of the NLM header due to preceding + variable sized fields. + + Note that all the fields must exist in the external header, and in + the order used here (the same order is used in the internal form + for consistency, not out of necessity). */ + +typedef struct nlm_internal_variable_header +{ + + /* The descriptionLength field contains the length of the text in + descriptionText, excluding the null terminator. The descriptionText + field contains the NLM description obtained from the DESCRIPTION + keyword in NLMLINK plus the null byte terminator. The descriptionText + can be up to NLM_MAX_DESCRIPTION_LENGTH characters. */ + + unsigned char descriptionLength; + char descriptionText[NLM_MAX_DESCRIPTION_LENGTH + 1]; + + /* The stackSize field contains the size of the stack in bytes, as + specified by the STACK or STACKSIZE keyword in NLMLINK. If no size + is specified, the default is NLM_DEFAULT_STACKSIZE. */ + + long stackSize; + + /* The reserved field is included only for completeness. It should contain + zero. */ + + long reserved; + + /* This field is fixed length, should contain " LONG" (note leading + space), and is unused. */ + + char oldThreadName[NLM_OLD_THREAD_NAME_LENGTH]; + + /* The screenNameLength field contains the length of the actual text stored + in the screenName field, excluding the null byte terminator. The + screenName field contains the screen name as specified by the SCREENNAME + keyword in NLMLINK, and can be up to NLM_MAX_SCREEN_NAME_LENGTH + characters. */ + + unsigned char screenNameLength; + char screenName[NLM_MAX_SCREEN_NAME_LENGTH + 1]; + + /* The threadNameLength field contains the length of the actual text stored + in the threadName field, excluding the null byte terminator. The + threadName field contains the thread name as specified by the THREADNAME + keyword in NLMLINK, and can be up to NLM_MAX_THREAD_NAME_LENGTH + characters. */ + + unsigned char threadNameLength; + char threadName[NLM_MAX_THREAD_NAME_LENGTH + 1]; + +} Nlm_Internal_Variable_Header; + +#define nlm32_internal_variable_header nlm_internal_variable_header +#define Nlm32_Internal_Variable_Header Nlm_Internal_Variable_Header +#define nlm64_internal_variable_header nlm_internal_variable_header +#define Nlm64_Internal_Variable_Header Nlm_Internal_Variable_Header + +/* The version header is one of the optional auxiliary headers and + follows the fixed length and variable length NLM headers. */ + +typedef struct nlm_internal_version_header +{ + /* The header is recognized by "VeRsIoN#" in the stamp field. */ + char stamp[8]; + long majorVersion; + long minorVersion; + long revision; + long year; + long month; + long day; +} Nlm_Internal_Version_Header; + +#define nlm32_internal_version_header nlm_internal_version_header +#define Nlm32_Internal_Version_Header Nlm_Internal_Version_Header +#define nlm64_internal_version_header nlm_internal_version_header +#define Nlm64_Internal_Version_Header Nlm_Internal_Version_Header + +typedef struct nlm_internal_copyright_header +{ + /* The header is recognized by "CoPyRiGhT=" in the stamp field. */ + char stamp[10]; + unsigned char copyrightMessageLength; + char copyrightMessage[NLM_MAX_COPYRIGHT_MESSAGE_LENGTH]; +} Nlm_Internal_Copyright_Header; + +#define nlm32_internal_copyright_header nlm_internal_copyright_header +#define Nlm32_Internal_Copyright_Header Nlm_Internal_Copyright_Header +#define nlm64_internal_copyright_header nlm_internal_copyright_header +#define Nlm64_Internal_Copyright_Header Nlm_Internal_Copyright_Header + +typedef struct nlm_internal_extended_header +{ + /* The header is recognized by "MeSsAgEs" in the stamp field. */ + char stamp[8]; + long languageID; + file_ptr messageFileOffset; + bfd_size_type messageFileLength; + long messageCount; + file_ptr helpFileOffset; + bfd_size_type helpFileLength; + file_ptr RPCDataOffset; + bfd_size_type RPCDataLength; + file_ptr sharedCodeOffset; + bfd_size_type sharedCodeLength; + file_ptr sharedDataOffset; + bfd_size_type sharedDataLength; + file_ptr sharedRelocationFixupOffset; + long sharedRelocationFixupCount; + file_ptr sharedExternalReferenceOffset; + long sharedExternalReferenceCount; + file_ptr sharedPublicsOffset; + long sharedPublicsCount; + file_ptr sharedDebugRecordOffset; + long sharedDebugRecordCount; + bfd_vma SharedInitializationOffset; + bfd_vma SharedExitProcedureOffset; + long productID; + long reserved0; + long reserved1; + long reserved2; + long reserved3; + long reserved4; + long reserved5; +} Nlm_Internal_Extended_Header; + +#define nlm32_internal_extended_header nlm_internal_extended_header +#define Nlm32_Internal_Extended_Header Nlm_Internal_Extended_Header +#define nlm64_internal_extended_header nlm_internal_extended_header +#define Nlm64_Internal_Extended_Header Nlm_Internal_Extended_Header + +/* The format of a custom header as stored internally is different + from the external format. This is how we store a custom header + which we do not recognize. */ + +typedef struct nlm_internal_custom_header +{ + /* The header is recognized by "CuStHeAd" in the stamp field. */ + char stamp[8]; + bfd_size_type hdrLength; + file_ptr dataOffset; + bfd_size_type dataLength; + char dataStamp[8]; + PTR hdr; +} Nlm_Internal_Custom_Header; + +#define nlm32_internal_custom_header nlm_internal_custom_header +#define Nlm32_Internal_Custom_Header Nlm_Internal_Custom_Header +#define nlm64_internal_custom_header nlm_internal_custom_header +#define Nlm64_Internal_Custom_Header Nlm_Internal_Custom_Header + +/* The internal Cygnus header is written out externally as a custom + header. We don't try to replicate that structure here. */ + +typedef struct nlm_internal_cygnus_ext_header +{ + /* The header is recognized by "CyGnUsEx" in the stamp field. */ + char stamp[8]; + /* File location of debugging information. */ + file_ptr offset; + /* Length of debugging information. */ + bfd_size_type length; +} Nlm_Internal_Cygnus_Ext_Header; + +#define nlm32_internal_cygnus_ext_header nlm_internal_cygnus_ext_header +#define Nlm32_Internal_Cygnus_Ext_Header Nlm_Internal_Cygnus_Ext_Header +#define nlm64_internal_cygnus_ext_header nlm_internal_cygnus_ext_header +#define Nlm64_Internal_Cygnus_Ext_Header Nlm_Internal_Cygnus_Ext_Header diff --git a/contrib/gdb/include/nlm/ppc-ext.h b/contrib/gdb/include/nlm/ppc-ext.h new file mode 100644 index 000000000000..0aae10772f56 --- /dev/null +++ b/contrib/gdb/include/nlm/ppc-ext.h @@ -0,0 +1,163 @@ +/* PowerPC NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1994 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef OLDFORMAT + +/* The format of a PowerPC NLM changed. These structures are only + used in the old format. */ + +/* A PowerPC NLM starts with an instance of this structure. */ + +struct nlm32_powerpc_external_prefix_header +{ + /* Signature. Must be "AppleNLM". */ + char signature[8]; + /* Version number. Current value is 1. */ + unsigned char headerVersion[4]; + /* ??. Should be set to 0. */ + unsigned char origins[4]; + /* File creation date in standard Unix time format (seconds since + 1/1/70). */ + unsigned char date[4]; +}; + +#define NLM32_POWERPC_SIGNATURE "AppleNLM" +#define NLM32_POWERPC_HEADER_VERSION 1 + +/* The external format of a PowerPC NLM reloc. This is the same as an + XCOFF dynamic reloc. */ + +struct nlm32_powerpc_external_reloc +{ + /* Address. */ + unsigned char l_vaddr[4]; + /* Symbol table index. This is 0 for .text and 1 for .data. 2 + means .bss, but I don't know if it is used. In XCOFF, larger + numbers are indices into the dynamic symbol table, but they are + presumably not used in an NLM. */ + unsigned char l_symndx[4]; + /* Relocation type. */ + unsigned char l_rtype[2]; + /* Section number being relocated. */ + unsigned char l_rsecnm[2]; +}; + +#endif /* OLDFORMAT */ + +/* The external format of the fixed header. */ + +typedef struct nlm32_powerpc_external_fixed_header +{ + + /* The signature field identifies the file as an NLM. It must contain + the signature string, which depends upon the NLM target. */ + + unsigned char signature[24]; + + /* The version of the header. At this time, the highest version number + is 4. */ + + unsigned char version[4]; + + /* The name of the module, which must be a DOS name (1-8 characters followed + by a period and a 1-3 character extension). The first byte is the byte + length of the name and the last byte is a null terminator byte. This + field is fixed length, and any unused bytes should be null bytes. The + value is set by the OUTPUT keyword to NLMLINK. */ + + unsigned char moduleName[14]; + + /* Padding to make it come out correct. */ + + unsigned char pad1[2]; + + /* The byte offset of the code image from the start of the file. */ + + unsigned char codeImageOffset[4]; + + /* The size of the code image, in bytes. */ + + unsigned char codeImageSize[4]; + + /* The byte offset of the data image from the start of the file. */ + + unsigned char dataImageOffset[4]; + + /* The size of the data image, in bytes. */ + + unsigned char dataImageSize[4]; + + /* The size of the uninitialized data region that the loader is to be + allocated at load time. Uninitialized data follows the initialized + data in the NLM address space. */ + + unsigned char uninitializedDataSize[4]; + + /* The byte offset of the custom data from the start of the file. The + custom data is set by the CUSTOM keyword to NLMLINK. It is possible + for this to be EOF if there is no custom data. */ + + unsigned char customDataOffset[4]; + + /* The size of the custom data, in bytes. */ + + unsigned char customDataSize[4]; + + /* The byte offset of the module dependencies from the start of the file. + The module dependencies are determined by the MODULE keyword in + NLMLINK. */ + + unsigned char moduleDependencyOffset[4]; + + /* The number of module dependencies at the moduleDependencyOffset. */ + + unsigned char numberOfModuleDependencies[4]; + + /* The byte offset of the relocation fixup data from the start of the file */ + + unsigned char relocationFixupOffset[4]; + + unsigned char numberOfRelocationFixups[4]; + + unsigned char externalReferencesOffset[4]; + + unsigned char numberOfExternalReferences[4]; + + unsigned char publicsOffset[4]; + + unsigned char numberOfPublics[4]; + + /* The byte offset of the internal debug info from the start of the file. + It is possible for this to be EOF if there is no debug info. */ + + unsigned char debugInfoOffset[4]; + + unsigned char numberOfDebugRecords[4]; + + unsigned char codeStartOffset[4]; + + unsigned char exitProcedureOffset[4]; + + unsigned char checkUnloadProcedureOffset[4]; + + unsigned char moduleType[4]; + + unsigned char flags[4]; + +} Nlm32_powerpc_External_Fixed_Header; diff --git a/contrib/gdb/include/nlm/sparc32-ext.h b/contrib/gdb/include/nlm/sparc32-ext.h new file mode 100644 index 000000000000..0deb2dee9230 --- /dev/null +++ b/contrib/gdb/include/nlm/sparc32-ext.h @@ -0,0 +1,120 @@ +/* SPARC NLM (NetWare Loadable Module) support for BFD. + Copyright (C) 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The external format of the fixed header. */ + +typedef struct nlm32_sparc_external_fixed_header +{ + + /* The signature field identifies the file as an NLM. It must contain + the signature string, which depends upon the NLM target. */ + + unsigned char signature[24]; + + /* The version of the header. At this time, the highest version number + is 4. */ + + unsigned char version[4]; + + /* The name of the module, which must be a DOS name (1-8 characters followed + by a period and a 1-3 character extension). The first byte is the byte + length of the name and the last byte is a null terminator byte. This + field is fixed length, and any unused bytes should be null bytes. The + value is set by the OUTPUT keyword to NLMLINK. */ + + unsigned char moduleName[14]; + + /* Padding to make it come out correct. */ + + unsigned char pad1[2]; + + /* The byte offset of the code image from the start of the file. */ + + unsigned char codeImageOffset[4]; + + /* The size of the code image, in bytes. */ + + unsigned char codeImageSize[4]; + + /* The byte offset of the data image from the start of the file. */ + + unsigned char dataImageOffset[4]; + + /* The size of the data image, in bytes. */ + + unsigned char dataImageSize[4]; + + /* The size of the uninitialized data region that the loader is to be + allocated at load time. Uninitialized data follows the initialized + data in the NLM address space. */ + + unsigned char uninitializedDataSize[4]; + + /* The byte offset of the custom data from the start of the file. The + custom data is set by the CUSTOM keyword to NLMLINK. It is possible + for this to be EOF if there is no custom data. */ + + unsigned char customDataOffset[4]; + + /* The size of the custom data, in bytes. */ + + unsigned char customDataSize[4]; + + /* The byte offset of the module dependencies from the start of the file. + The module dependencies are determined by the MODULE keyword in + NLMLINK. */ + + unsigned char moduleDependencyOffset[4]; + + /* The number of module dependencies at the moduleDependencyOffset. */ + + unsigned char numberOfModuleDependencies[4]; + + /* The byte offset of the relocation fixup data from the start of the file */ + + unsigned char relocationFixupOffset[4]; + + unsigned char numberOfRelocationFixups[4]; + + unsigned char externalReferencesOffset[4]; + + unsigned char numberOfExternalReferences[4]; + + unsigned char publicsOffset[4]; + + unsigned char numberOfPublics[4]; + + /* The byte offset of the internal debug info from the start of the file. + It is possible for this to be EOF if there is no debug info. */ + + unsigned char debugInfoOffset[4]; + + unsigned char numberOfDebugRecords[4]; + + unsigned char codeStartOffset[4]; + + unsigned char exitProcedureOffset[4]; + + unsigned char checkUnloadProcedureOffset[4]; + + unsigned char moduleType[4]; + + unsigned char flags[4]; + +} Nlm32_sparc_External_Fixed_Header; diff --git a/contrib/gdb/include/oasys.h b/contrib/gdb/include/oasys.h new file mode 100644 index 000000000000..867d2503134e --- /dev/null +++ b/contrib/gdb/include/oasys.h @@ -0,0 +1,152 @@ +/* Oasys object format header file for BFD. + Contributed by Cygnus Support. */ + +#define OASYS_MAX_SEC_COUNT 16 +/* **** */ + +typedef struct oasys_archive_header { + unsigned int version; + char create_date[12]; + char revision_date[12]; + unsigned int mod_count; + file_ptr mod_tbl_offset; + unsigned int sym_tbl_size; + unsigned int sym_count; + file_ptr sym_tbl_offset; + unsigned int xref_count; + file_ptr xref_lst_offset; +} oasys_archive_header_type; + +typedef struct oasys_extarchive_header { + bfd_byte version[4]; + bfd_byte create_date[12]; + bfd_byte revision_date[12]; + bfd_byte mod_count[4]; + bfd_byte mod_tbl_offset[4]; + bfd_byte sym_tbl_size[4]; + bfd_byte sym_count[4]; + bfd_byte sym_tbl_offset[4]; + bfd_byte xref_count[4]; + bfd_byte xref_lst_offset[4]; +} oasys_extarchive_header_type; + +typedef struct oasys_module_table { + int mod_number; + char mod_date[12]; + unsigned int mod_size; + unsigned int dep_count; + unsigned int depee_count; + file_ptr file_offset; + unsigned int sect_count; + char *module_name; + unsigned int module_name_size; +} oasys_module_table_type; + + +typedef struct oasys_extmodule_table_a { + bfd_byte mod_number[4]; + bfd_byte mod_date[12]; + bfd_byte mod_size[4]; + bfd_byte dep_count[4]; + bfd_byte depee_count[4]; + bfd_byte sect_count[4]; + bfd_byte file_offset[4]; + bfd_byte mod_name[32]; +} oasys_extmodule_table_type_a_type; + +typedef struct oasys_extmodule_table_b { + bfd_byte mod_number[4]; + bfd_byte mod_date[12]; + bfd_byte mod_size[4]; + bfd_byte dep_count[4]; + bfd_byte depee_count[4]; + bfd_byte sect_count[4]; + bfd_byte file_offset[4]; + bfd_byte mod_name_length[4]; +} oasys_extmodule_table_type_b_type; + + +typedef enum oasys_record { + oasys_record_is_end_enum = 0, + oasys_record_is_data_enum = 1, + oasys_record_is_symbol_enum = 2, + oasys_record_is_header_enum = 3, + oasys_record_is_named_section_enum = 4, + oasys_record_is_com_enum = 5, + oasys_record_is_debug_enum = 6, + oasys_record_is_section_enum = 7, + oasys_record_is_debug_file_enum = 8, + oasys_record_is_module_enum = 9, + oasys_record_is_local_enum = 10 +} oasys_record_enum_type; + + + +typedef struct oasys_record_header { + unsigned char length; + unsigned char check_sum; + unsigned char type; + unsigned char fill; +} oasys_record_header_type; + +typedef struct oasys_data_record { + oasys_record_header_type header; + unsigned char relb; + bfd_byte addr[4]; + /* maximum total size of data record is 255 bytes */ + bfd_byte data[246]; +} oasys_data_record_type; + +typedef struct oasys_header_record { + oasys_record_header_type header; + unsigned char version_number; + unsigned char rev_number; + char module_name[26-6]; + char description[64-26]; +} oasys_header_record_type; + +#define OASYS_VERSION_NUMBER 0 +#define OASYS_REV_NUMBER 0 + +typedef struct oasys_symbol_record { + oasys_record_header_type header; + unsigned char relb; + bfd_byte value[4]; + bfd_byte refno[2]; + char name[64]; +} oasys_symbol_record_type; + +#define RELOCATION_PCREL_BIT 0x80 +#define RELOCATION_32BIT_BIT 0x40 +#define RELOCATION_TYPE_BITS 0x30 +#define RELOCATION_TYPE_ABS 0x00 +#define RELOCATION_TYPE_REL 0x10 +#define RELOCATION_TYPE_UND 0x20 +#define RELOCATION_TYPE_COM 0x30 +#define RELOCATION_SECT_BITS 0x0f + +typedef struct oasys_section_record { + oasys_record_header_type header; + unsigned char relb; + bfd_byte value[4]; + bfd_byte vma[4]; + bfd_byte fill[3]; +} oasys_section_record_type; + +typedef struct oasys_end_record { + oasys_record_header_type header; + unsigned char relb; + bfd_byte entry[4]; + bfd_byte fill[2]; + bfd_byte zero; +} oasys_end_record_type; + +typedef union oasys_record_union { + oasys_record_header_type header; + oasys_data_record_type data; + oasys_section_record_type section; + oasys_symbol_record_type symbol; + oasys_header_record_type first; + oasys_end_record_type end; + bfd_byte pad[256]; +} oasys_record_union_type; diff --git a/contrib/gdb/include/obstack.h b/contrib/gdb/include/obstack.h new file mode 100644 index 000000000000..416b8bf53151 --- /dev/null +++ b/contrib/gdb/include/obstack.h @@ -0,0 +1,518 @@ +/* obstack.h - object stack macros + Copyright (C) 1988, 89, 90, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published by the +Free Software Foundation; either version 2, 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 Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef __OBSTACK_H__ +#define __OBSTACK_H__ + +/* We use subtraction of (char *)0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +#define __PTR_TO_INT(P) ((P) - (char *)0) +#endif + +#ifndef __INT_TO_PTR +#define __INT_TO_PTR(P) ((P) + (char *)0) +#endif + +/* We need the type of the resulting object. In ANSI C it is ptrdiff_t + but in traditional C it is usually long. If we are in ANSI C and + don't already have ptrdiff_t get it. */ + +#if defined (__STDC__) && ! defined (offsetof) +#if defined (__GNUC__) && defined (IN_GCC) +/* On Next machine, the system's stddef.h screws up if included + after we have defined just ptrdiff_t, so include all of stddef.h. + Otherwise, define just ptrdiff_t, which is all we need. */ +#ifndef __NeXT__ +#define __need_ptrdiff_t +#endif +#endif + +#include +#endif + +#ifdef __STDC__ +#define PTR_INT_TYPE ptrdiff_t +#else +#define PTR_INT_TYPE long +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + PTR_INT_TYPE temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ + char *extra_arg; /* first arg for chunk alloc/dealloc funcs */ + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ + unsigned alloc_failed:1; /* chunk alloc func returned 0 */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +#ifdef __STDC__ +extern void _obstack_newchunk (struct obstack *, int); +extern void _obstack_free (struct obstack *, void *); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (), void (*) ()); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (), void (*) (), void *); +extern int _obstack_memory_used (struct obstack *); +#else +extern void _obstack_newchunk (); +extern void _obstack_free (); +extern int _obstack_begin (); +extern int _obstack_begin_1 (); +extern int _obstack_memory_used (); +#endif + +#ifdef __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); +int obstack_memory_used (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->alloc_failed ? 0 : (h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->alloc_failed ? 0 : (h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun)) + +#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg)) + +#define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun)) + +#define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)()) (newfreefun)) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#define obstack_memory_used(h) _obstack_memory_used (h) + +#if defined (__GNUC__) && defined (__STDC__) +#if __GNUC__ < 2 +#define __extension__ +#endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +#define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + __o->alloc_failed ? 0 : \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +#define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + if (!__o->alloc_failed) \ + { \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + } \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + if (!__o->alloc_failed) \ + { \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + } \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, 1); \ + if (!__o->alloc_failed) \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +#define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ + if (!__o->alloc_failed) \ + *((void **)__o->next_free)++ = ((void *)datum); \ + (void) 0; }) + +#define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (int) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (int)); \ + if (!__o->alloc_failed) \ + *((int *)__o->next_free)++ = ((int)datum); \ + (void) 0; }) + +#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + if (!__o->alloc_failed) \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +#define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *value; \ + if (__o1->alloc_failed) \ + value = 0; \ + else \ + { \ + value = (void *) __o1->object_base; \ + if (__o1->next_free == value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\ + & ~ (__o1->alignment_mask)); \ + if (__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + } \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +#define obstack_object_size(h) \ + (unsigned) ((h)->alloc_failed ? 0 : (h)->next_free - (h)->object_base) + +#define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ + +#define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + (bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp))) + +#define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + (bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0))) + +#define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + (*((h)->next_free)++ = (datum)))) + +#define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + (*((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum)))) + +#define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + (*((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum)))) + +#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + ((h)->alloc_failed ? 0 : \ + ((h)->next_free += (h)->temp))) + +#define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +#define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_finish(h) \ +( (h)->alloc_failed ? 0 : \ + (((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp))) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#endif /* not __OBSTACK_H__ */ diff --git a/contrib/gdb/include/opcode/ChangeLog b/contrib/gdb/include/opcode/ChangeLog new file mode 100644 index 000000000000..f56df4bd5985 --- /dev/null +++ b/contrib/gdb/include/opcode/ChangeLog @@ -0,0 +1,812 @@ +Thu Mar 7 15:08:23 1996 Doug Evans + + * sparc.h (O): Mark operand letter as in use. + +Tue Feb 20 20:46:21 1996 Doug Evans + + * sparc.h (sparc_{encode,decode}_sparclet_cpreg): Declare. + Mark operand letters uU as in use. + +Mon Feb 19 01:59:08 1996 Doug Evans + + * sparc.h (sparc_opcode_arch_val): Add SPARC_OPCODE_ARCH_SPARCLET. + (sparc_opcode_arch): Delete member `conflicts'. Add `supported'. + (SPARC_OPCODE_SUPPORTED): New macro. + (SPARC_OPCODE_CONFLICT_P): Rewrite. + (F_NOTV9): Delete. + +Fri Feb 16 12:23:34 1996 Jeffrey A Law (law@cygnus.com) + + * sparc.h (sparc_opcode_lookup_arch) Make return type in + declaration consistent with return type in definition. + +Wed Feb 14 18:14:11 1996 Alan Modra + + * i386.h (i386_optab): Remove Data32 from pushf and popf. + +Thu Feb 8 14:27:21 1996 James Carlson + + * i386.h (i386_regtab): Add 80486 test registers. + +Mon Feb 5 18:35:46 1996 Ian Lance Taylor + + * i960.h (I_HX): Define. + (i960_opcodes): Add HX instruction. + +Mon Jan 29 12:43:39 1996 Ken Raeburn + + * i386.h: Fix waiting forms of finit, fstenv, fsave, fstsw, fstcw, + and fclex. + +Wed Jan 24 22:36:59 1996 Doug Evans + + * sparc.h (enum sparc_opcode_arch_val): Replaces sparc_architecture. + (SPARC_OPCODE_CONFLICT_P): Renamed from ARCHITECTURES_CONFLICT_P. + (bfd_* defines): Delete. + (sparc_opcode_archs): Replaces architecture_pname. + (sparc_opcode_lookup_arch): Declare. + (NUMOPCODES): Delete. + +Mon Jan 22 08:24:32 1996 Doug Evans + + * sparc.h (enum sparc_architecture): Add v9a. + (ARCHITECTURES_CONFLICT_P): Update. + +Thu Dec 28 13:27:53 1995 John Hassey + + * i386.h: Added Pentium Pro instructions. + +Thu Nov 2 22:59:22 1995 Ian Lance Taylor + + * m68k.h: Document new 'W' operand place. + +Tue Oct 24 10:49:10 1995 Jeffrey A Law (law@cygnus.com) + + * hppa.h: Add lci and syncdma instructions. + +Mon Oct 23 11:09:16 1995 James G. Smith + + * mips.h: Added INSN_4100 flag to mark NEC VR4100 specific + instructions. + +Mon Oct 16 10:28:15 1995 Michael Meissner + + * ppc.h (PPC_OPCODE_{COMMON,ANY}): New opcode flags for + assembler's -mcom and -many switches. + +Wed Oct 11 16:56:33 1995 Ken Raeburn + + * i386.h: Fix cmpxchg8b extension opcode description. + +Thu Oct 5 18:03:36 1995 Ken Raeburn + + * i386.h: Add Pentium instructions wrmsr, rdtsc, rdmsr, cmpxchg8b, + and register cr4. + +Tue Sep 19 15:26:43 1995 Ian Lance Taylor + + * m68k.h: Change comment: split type P into types 0, 1 and 2. + +Wed Aug 30 13:50:55 1995 Doug Evans + + * sparc.h (sparc_{encode,decode}_prefetch): Declare. + +Tue Aug 29 15:34:58 1995 Doug Evans + + * sparc.h (sparc_{encode,decode}_{asi,membar}): Declare. + +Wed Aug 2 18:32:19 1995 Ian Lance Taylor + + * m68kmri.h: Remove. + + * m68k.h: Move tables into opcodes/m68k-opc.c, leaving just the + declarations. Remove F_ALIAS and flag field of struct + m68k_opcode. Change arch field of struct m68k_opcode to unsigned + int. Make name and args fields of struct m68k_opcode const. + +Wed Aug 2 08:16:46 1995 Doug Evans + + * sparc.h (F_NOTV9): Define. + +Tue Jul 11 14:20:42 1995 Jeff Spiegel + + * mips.h (INSN_4010): Define. + +Wed Jun 21 18:49:51 1995 Ken Raeburn + + * m68k.h (TBL1): Reverse sense of "round" argument in result. + + Changes from Andreas Schwab : + * m68k.h: Fix argument descriptions of coprocessor + instructions to allow only alterable operands where appropriate. + [!NO_DEFAULT_SIZES]: An omitted size defaults to `w'. + (m68k_opcode_aliases): Add more aliases. + + +Fri Apr 14 22:15:34 1995 Ken Raeburn + + * m68k.h: Added explcitly short-sized conditional branches, and a + bunch of aliases (fmov*, ftest*, tdivul) to support gcc's + svr4-based configurations. + + +Mon Mar 13 21:30:01 1995 Ken Raeburn + + Mon Feb 27 08:36:39 1995 Bryan Ford + * i386.h: added missing Data16/Data32 flags to a few instructions. + +Wed Mar 8 15:19:53 1995 Ian Lance Taylor + + * mips.h (OP_MASK_FR, OP_SH_FR): Define. + (OP_MASK_BCC, OP_SH_BCC): Define. + (OP_MASK_PREFX, OP_SH_PREFX): Define. + (OP_MASK_CCC, OP_SH_CCC): Define. + (INSN_READ_FPR_R): Define. + (INSN_RFE): Delete. + +Wed Mar 8 03:13:23 1995 Ken Raeburn + + * m68k.h (enum m68k_architecture): Deleted. + (struct m68k_opcode_alias): New type. + (m68k_opcodes): Now const. Deleted opcode aliases with exactly + matching constraints, values and flags. As a side effect of this, + the MOTOROLA_SYNTAX_ONLY and MIT_SYNTAX_ONLY macros, which so far + as I know were never used, now may need re-examining. + (numopcodes): Now const. + (m68k_opcode_aliases, numaliases): New variables. + (endop): Deleted. + [DONT_DEFINE_TABLE]: Declare numopcodes, numaliases, and + m68k_opcode_aliases; update declaration of m68k_opcodes. + + +Mon Mar 6 10:02:00 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa.h (delay_type): Delete unused enumeration. + (pa_opcode): Replace unused delayed field with an architecture + field. + (pa_opcodes): Mark each instruction as either PA1.0 or PA1.1. + +Fri Mar 3 16:10:24 1995 Ian Lance Taylor + + * mips.h (INSN_ISA4): Define. + +Fri Feb 24 19:13:37 1995 Ian Lance Taylor + + * mips.h (M_DLA_AB, M_DLI): Define. + +Thu Feb 23 17:33:09 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa.h (fstwx): Fix single-bit error. + +Wed Feb 15 12:19:52 1995 Ian Lance Taylor + + * mips.h (M_ULD, M_ULD_A, M_USD, M_USD_A): Define. + + +Mon Feb 6 10:35:23 1995 J.T. Conklin + + * i386.h: added cpuid instruction , and dr[0-7] aliases for the + debug registers. From Charles Hannum (mycroft@netbsd.org). + +Mon Feb 6 03:31:54 1995 Ken Raeburn + + Changes from Bryan Ford for 16-bit + i386 support: + * i386.h (MOV_AX_DISP32): New macro. + (i386_optab): Added Data16 and Data32 as needed. Added "w" forms + of several call/return instructions. + (ADDR_PREFIX_OPCODE): New macro. + +Mon Jan 23 16:45:43 1995 Ken Raeburn + + Sat Jan 21 17:50:38 1995 Pat Rankin (rankin@eql.caltech.edu) + + * ../include/opcode/vax.h (struct vot_wot, field `args'): make + it pointer to const char; + (struct vot, field `name'): ditto. + +Thu Jan 19 14:47:53 1995 Ken Raeburn + + * vax.h: Supply and properly group all values in end sentinel. + +Tue Jan 17 10:55:30 1995 Ian Lance Taylor + + * mips.h (INSN_ISA, INSN_4650): Define. + + + +Wed Oct 19 13:34:17 1994 Ian Lance Taylor + + * a29k.h: Add operand type 'I' for `inv' and `iretinv'. On + systems with a separate instruction and data cache, such as the + 29040, these instructions take an optional argument. + +Wed Sep 14 17:44:20 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips.h (INSN_STORE_MEMORY): Correct value to not conflict with + INSN_TRAP. + +Tue Sep 6 11:39:08 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips.h (INSN_STORE_MEMORY): Define. + +Thu Jul 28 19:28:07 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * sparc.h: Document new operand type 'x'. + +Tue Jul 26 17:48:05 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i960.h (I_CX2): New instruction category. It includes + instructions available on Cx and Jx processors. + (I_JX): New instruction category, for JX-only instructions. + (i960_opcodes): Put eshro and sysctl in I_CX2 category. Added + Jx-only instructions, in I_JX category. + +Wed Jul 13 18:43:47 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * ns32k.h (endop): Made pointer const too. + +Sun Jul 10 11:01:09 1994 Ian Dall (dall@hfrd.dsto.gov.au) + + * ns32k.h: Drop Q operand type as there is no correct use + for it. Add I and Z operand types which allow better checking. + +Thu Jul 7 12:34:48 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * h8300.h (xor.l) :fix bit pattern. + (L_2): New size of operand. + (trapa): Use it. + +Fri Jun 10 16:38:11 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m68k.h: Move "trap" before "tpcc" to change disassembly. + +Fri Jun 3 15:57:36 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * sparc.h: Include v9 definitions. + +Thu Jun 2 12:23:17 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * m68k.h (m68060): Defined. + (m68040up, mfloat, mmmu): Include it. + (struct m68k_opcode): Widen `arch' field. + (m68k_opcodes): Updated for M68060. Removed comments that were + instructions commented out by "JF" years ago. + +Thu Apr 28 18:31:14 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * m68k.h (struct m68k_opcode): Shorten `arch' field to 8 bits, and + add a one-bit `flags' field. + (F_ALIAS): New macro. + +Wed Apr 27 11:29:52 1994 Steve Chamberlain (sac@cygnus.com) + + * h8300.h (dec, inc): Get encoding right. + +Mon Apr 4 13:12:43 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc.h (struct powerpc_operand): Removed signedp field; just use + a flag instead. + (PPC_OPERAND_SIGNED): Define. + (PPC_OPERAND_SIGNOPT): Define. + +Thu Mar 31 19:34:08 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i386.h (IS_JUMP_ON_ECX_ZERO, "jcxz" pattern): Operand size + prefix is 0x66, not 0x67. Patch from H.J. Lu (hlu@nynexst.com). + +Thu Mar 3 15:51:05 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i386.h: Reverse last change. It'll be handled in gas instead. + +Thu Feb 24 15:29:05 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i386.h (sar): Disabled the two-operand Imm1 form, since it was + slower on the 486 and used the implicit shift count despite the + explicit operand. The one-operand form is still available to get + the shorter form with the implicit shift count. + +Thu Feb 17 12:27:52 1994 Torbjorn Granlund (tege@mexican.cygnus.com) + + * hppa.h: Fix typo in fstws arg string. + +Wed Feb 9 21:23:52 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc.h (struct powerpc_opcode): Make operands field unsigned. + +Mon Feb 7 19:14:58 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc.h (PPC_OPCODE_601): Define. + +Fri Feb 4 23:43:50 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa.h (addb): Use '@' for addb and addib pseudo ops. + (so we can determine valid completers for both addb and addb[tf].) + + * hppa.h (xmpyu): No floating point format specifier for the + xmpyu instruction. + +Fri Feb 4 23:36:52 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc.h (PPC_OPERAND_NEXT): Define. + (PPC_OPERAND_NEGATIVE): Change value to make room for above. + (struct powerpc_macro): Define. + (powerpc_macros, powerpc_num_macros): Declare. + +Fri Jan 21 19:13:50 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc.h: New file. Header file for PowerPC opcode table. + +Mon Jan 17 00:14:23 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa.h: More minor template fixes for sfu and copr (to allow + for easier disassembly). + + * hppa.h: Fix templates for all the sfu and copr instructions. + +Wed Dec 15 15:12:42 1993 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i386.h (push): Permit Imm16 operand too. + +Sat Dec 11 16:14:06 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * h8300.h (andc): Exists in base arch. + +Wed Dec 1 12:15:32 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * From Hisashi MINAMINO + * hppa.h: #undef NONE to avoid conflict with hiux include files. + +Sun Nov 21 22:06:57 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa.h: Add FP quadword store instructions. + +Wed Nov 17 17:13:16 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h: (M_J_A): Added. + (M_LA): Removed. + +Mon Nov 8 12:12:47 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (OP_MASK_CACHE, OP_SH_CACHE): Define. From Ted Lemon + . + +Sun Nov 7 00:30:11 1993 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa.h: Immediate field in probei instructions is unsigned, + not low-sign extended. + +Wed Nov 3 10:30:00 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m88k.h (RRI10MASK): Change from 0xfc00ffe0 to 0xfc00fc00. + +Tue Nov 2 12:41:30 1993 Ken Raeburn (raeburn@rover.cygnus.com) + + * i386.h: Add "fxch" without operand. + +Mon Nov 1 18:13:03 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (M_JAL_1, M_JAL_2, M_JAL_A): Added. + +Sat Oct 2 22:26:11 1993 Jeffrey A Law (law@snake.cs.utah.edu) + + * hppa.h: Add gfw and gfr to the opcode table. + +Wed Sep 29 16:23:00 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * m88k.h: extended to handle m88110. + +Tue Sep 28 19:19:08 1993 Jeffrey A Law (law@snake.cs.utah.edu) + + * hppa.h (be, ble): Use operand type 'z' to denote absolute branch + addresses. + +Tue Sep 14 14:04:35 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i960.h (i960_opcodes): Properly bracket initializers. + +Mon Sep 13 12:50:52 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * m88k.h (BOFLAG): rewrite to avoid nested comment. + +Mon Sep 13 15:46:06 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m68k.h (two): Protect second argument with parentheses. + +Fri Sep 10 16:29:47 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * i386.h (i386_optab): Added new instruction "rsm" (for i386sl). + Deleted old in/out instructions in "#if 0" section. + +Thu Sep 9 17:42:19 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i386.h (i386_optab): Properly bracket initializers. + +Wed Aug 25 13:50:56 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * hppa.h (pa_opcode): Use '|' for movb and movib insns. (From + Jeff Law, law@cs.utah.edu). + +Mon Aug 23 16:55:03 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * i386.h (lcall): Accept Imm32 operand also. + +Mon Aug 23 12:43:11 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (M_ABSU): Removed (absolute value of unsigned number??). + (M_DABS): Added. + +Thu Aug 19 15:08:37 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h (INSN_*): Changed values. Removed unused definitions. + Added INSN_COND_BRANCH_LIKELY, INSN_ISA2 and INSN_ISA3. Split + INSN_LOAD_DELAY into INSN_LOAD_MEMORY_DELAY and + INSN_LOAD_COPROC_DELAY. Split INSN_COPROC_DELAY into + INSN_COPROC_MOVE_DELAY and INSN_COPROC_MEMORY_DELAY. + (M_*): Added new values for r6000 and r4000 macros. + (ANY_DELAY): Removed. + +Wed Aug 18 15:37:48 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h: Added M_LI_S and M_LI_SS. + +Tue Aug 17 07:08:08 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * h8300.h: Get some rare mov.bs correct. + +Thu Aug 5 09:15:17 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc.h: Don't define const ourself; rely on ansidecl.h having + been included. + +Fri Jul 30 18:41:11 1993 John Gilmore (gnu@cygnus.com) + + * sparc.h (F_JSR, F_UNBR, F_CONDBR): Add new flags to mark + jump instructions, for use in disassemblers. + +Thu Jul 22 07:25:27 1993 Ian Lance Taylor (ian@cygnus.com) + + * m88k.h: Make bitfields just unsigned, not unsigned long or + unsigned short. + +Wed Jul 21 11:55:31 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * hppa.h: New argument type 'y'. Use in various float instructions. + +Mon Jul 19 17:17:03 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * hppa.h (break): First immediate field is unsigned. + + * hppa.h: Add rfir instruction. + +Sun Jul 18 16:28:08 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * mips.h: Split the actual table out into ../../opcodes/mips-opc.c. + +Fri Jul 16 09:59:29 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h: Reworked the hazard information somewhat, and fixed some + bugs in the instruction hazard descriptions. + +Thu Jul 15 12:42:01 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m88k.h: Corrected a couple of opcodes. + +Tue Jul 6 15:17:35 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips.h: Replaced with version from Ralph Campbell and OSF. The + new version includes instruction hazard information, but is + otherwise reasonably similar. + +Thu Jul 1 20:36:17 1993 Doug Evans (dje@canuck.cygnus.com) + + * h8300.h: Fix typo in UNOP3 (affected sh[al][lr].l). + +Fri Jun 11 18:38:44 1993 Ken Raeburn (raeburn@cygnus.com) + + Patches from Jeff Law, law@cs.utah.edu: + * hppa.h: Clean up some of the OLD_TABLE, non-OLD_TABLE braindamage. + Make the tables be the same for the following instructions: + "bb", "addb[tf]", "addib[tf]", "add", "add[loc]", "addco", + "sh[123]add", "sh[123]add[lo]", "sub", "sub[obt]", "sub[bt]o", + "ds", "comclr", "addi", "addi[ot]", "addito", "subi", "subio", + "comiclr", "fadd", "fsub", "fmpy", "fdiv", "fsqrt", "fabs", + "frnd", "fcpy", "fcnvff", "fcnvxf", "fcnvfx", "fcnvfxt", + "fcmp", and "ftest". + + * hppa.h: Make new and old tables the same for "break", "mtctl", + "mfctl", "bb", "ssm", "rsm", "xmpyu", "fmpyadd", "fmpysub". + Fix typo in last patch. Collapse several #ifdefs into a + single #ifdef. + + * hppa.h: Delete remaining OLD_TABLE code. Bring some + of the comments up-to-date. + + * hppa.h: Update "free list" of letters and update + comments describing each letter's function. + +Fri Jun 4 15:41:37 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * h8300.h: checkpoint, includes H8/300-H opcodes. + +Thu Jun 3 15:42:59 1993 Stu Grossman (grossman@cygnus.com) + + * Patches from Jeffrey Law . + * hppa.h: Rework single precision FP + instructions so that they correctly disassemble code + PA1.1 code. + +Thu May 27 19:21:22 1993 Bruce Bauman (boot@osf.org) + + * i386.h (i386_optab, mov pattern): Remove Mem16 restriction from + mov to allow instructions like mov ss,xyz(ecx) to assemble. + +Tue May 25 00:39:40 1993 Ken Raeburn (raeburn@cygnus.com) + + * hppa.h: Use new version from Utah if OLD_TABLE isn't defined; + gdb will define it for now. + +Mon May 24 15:20:06 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * sparc.h: Don't end enumerator list with comma. + +Fri May 14 15:15:50 1993 Ian Lance Taylor (ian@cygnus.com) + + * Based on patches from davidj@ICSI.Berkeley.EDU (David Johnson): + * mips.h (OP_MASK_COPZ, OP_SH_COPZ): Define. + ("bc2t"): Correct typo. + ("[ls]wc[023]"): Use T rather than t. + ("c[0123]"): Define general coprocessor instructions. + +Mon May 10 06:02:25 1993 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + * m68k.h: Move split point for gcc compilation more towards + middle. + +Fri Apr 9 13:26:16 1993 Jim Kingdon (kingdon@cygnus.com) + + * rs6k.h: Clean up instructions for primary opcode 19 (many were + simply wrong, ics, rfi, & rfsvc were missing). + Add "a" to opr_ext for "bb". Doc fix. + +Thu Mar 18 13:45:31 1993 Per Bothner (bothner@rtl.cygnus.com) + + * i386.h: 486 extensions from John Hassey (hassey@dg-rtp.dg.com). + * mips.h: Add casts, to suppress warnings about shifting too much. + * m68k.h: Document the placement code '9'. + +Thu Feb 18 02:03:14 1993 John Gilmore (gnu@cygnus.com) + + * m68k.h (BREAK_UP_BIG_DECL, AND_OTHER_PART): Add kludge which + allows callers to break up the large initialized struct full of + opcodes into two half-sized ones. This permits GCC to compile + this module, since it takes exponential space for initializers. + (numopcodes, endop): Revise to use AND_OTHER_PART in size calcs. + +Thu Feb 4 02:06:56 1993 John Gilmore (gnu@cygnus.com) + + * a29k.h: Remove RCS crud, update GPL to v2, update copyrights. + * convex.h: Added, from GDB's convx-opcode.h. Added CONST to all + initialized structs in it. + +Thu Jan 28 21:32:22 1993 John Gilmore (gnu@cygnus.com) + + Delta 88 changes inspired by Carl Greco, : + * m88k.h (PMEM): Avoid previous definition from . + (AND): Change to AND_ to avoid ansidecl.h `AND' conflict. + +Sat Jan 23 18:10:49 PST 1993 Ralph Campbell (ralphc@pyramid.com) + + * mips.h: document "i" and "j" operands correctly. + +Thu Jan 7 15:58:13 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips.h: Removed endianness dependency. + +Sun Jan 3 14:13:35 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * h8300.h: include info on number of cycles per instruction. + +Mon Dec 21 21:29:08 1992 Stu Grossman (grossman at cygnus.com) + + * hppa.h: Move handy aliases to the front. Fix masks for extract + and deposit instructions. + +Sat Dec 12 16:09:48 1992 Ian Lance Taylor (ian@cygnus.com) + + * i386.h: accept shld and shrd both with and without the shift + count argument, which is always %cl. + +Fri Nov 27 17:13:18 1992 Ken Raeburn (raeburn at cygnus.com) + + * i386.h (i386_optab_end, i386_regtab_end): Now const. + (one_byte_segment_defaults, two_byte_segment_defaults, + i386_prefixtab_end): Ditto. + +Mon Nov 23 10:47:25 1992 Ken Raeburn (raeburn@cygnus.com) + + * vax.h (bb*): Use "v" (bitfield type), not "a" (address operand) + for operand 2; from John Carr, jfc@dsg.dec.com. + +Wed Nov 4 07:36:49 1992 Ken Raeburn (raeburn@cygnus.com) + + * m68k.h: Define FIXED_SIZE_BRANCH, so bsr and bra instructions + always use 16-bit offsets. Makes calculated-size jump tables + feasible. + +Fri Oct 16 22:52:43 1992 Ken Raeburn (raeburn@cygnus.com) + + * i386.h: Fix one-operand forms of in* and out* patterns. + +Tue Sep 22 14:08:14 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * m68k.h: Added CPU32 support. + +Tue Sep 22 00:38:41 1992 John Gilmore (gnu@cygnus.com) + + * mips.h (break): Disassemble the argument. Patch from + jonathan@cs.stanford.edu (Jonathan Stone). + +Wed Sep 9 11:25:28 1992 Ian Lance Taylor (ian@cygnus.com) + + * m68k.h: merged Motorola and MIT syntax. + +Thu Sep 3 09:33:22 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * m68k.h (pmove): make the tests less strict, the 68k book is + wrong. + +Tue Aug 25 23:25:19 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * m68k.h (m68ec030): Defined as alias for 68030. + (m68k_opcodes): New type characters "3" for 68030 MMU regs and "t" + for immediate 0-7 added. Set up some opcodes (ptest, bkpt) to use + them. Tightened description of "fmovex" to distinguish it from + some "pmove" encodings. Added "pmove" for 68030 MMU regs, cleaned + up descriptions that claimed versions were available for chips not + supporting them. Added "pmovefd". + +Mon Aug 24 12:04:51 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * m68k.h: fix where the . goes in divull + +Wed Aug 19 11:22:24 1992 Ian Lance Taylor (ian@cygnus.com) + + * m68k.h: the cas2 instruction is supposed to be written with + indirection on the last two operands, which can be either data or + address registers. Added a new operand type 'r' which accepts + either register type. Added new cases for cas2l and cas2w which + use them. Corrected masks for cas2 which failed to recognize use + of address register. + +Fri Aug 14 14:20:38 1992 Per Bothner (bothner@cygnus.com) + + * m68k.h: Merged in patches (mostly m68040-specific) from + Colin Smith . + + * m68k.h: Merged m68kmri.h and m68k.h (using the former as a + base). Also cleaned up duplicates, re-ordered instructions for + the sake of dis-assembling (so aliases come after standard names). + * m68kmri.h: Now just defines some macros, and #includes m68k.h. + +Wed Aug 12 16:38:15 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * m68kmri.h: added various opcodes. Moved jbxx to bxxes. Filled in + all missing .s + +Mon Aug 10 23:22:33 1992 Ken Raeburn (raeburn@cygnus.com) + + * sparc.h: Moved tables to BFD library. + + * i386.h (i386_optab): Add fildq, fistpq aliases used by gcc. + +Sun Jun 28 13:29:03 1992 Fred Fish (fnf@cygnus.com) + + * h8300.h: Finish filling in all the holes in the opcode table, + so that the Lucid C compiler can digest this as well... + +Fri Jun 26 21:27:17 1992 John Gilmore (gnu at cygnus.com) + + * i386.h: Add setc, setnc, addr16, data16, repz, repnz aliases. + Fix opcodes on various sizes of fild/fist instructions + (16bit=no suffix, 32bit="l" suffix, 64bit="ll" suffix). + Use tabs to indent for comments. Fixes suggested by Minh Tran-Le. + +Thu Jun 25 16:13:26 1992 Stu Grossman (grossman at cygnus.com) + + * h8300.h: Fill in all the holes in the opcode table so that the + losing HPUX C compiler can digest this... + +Thu Jun 11 12:15:25 1992 John Gilmore (gnu at cygnus.com) + + * mips.h: Fix decoding of coprocessor instructions, somewhat. + (Fix by Eric Anderson, 3jean@maas-neotek.arc.nasa.gov.) + +Thu May 28 11:17:44 1992 Jim Wilson (wilson@sphagnum.cygnus.com) + + * sparc.h: Add new architecture variant sparclite; add its scan + and divscc opcodes. Define ARCHITECTURES_CONFLICT_P macro. + +Tue May 5 14:23:27 1992 Per Bothner (bothner@rtl.cygnus.com) + + * mips.h: Add some more opcode synonyms (from Frank Yellin, + fy@lucid.com). + +Thu Apr 16 18:25:26 1992 Per Bothner (bothner@cygnus.com) + + * rs6k.h: New version from IBM (Metin). + +Thu Apr 9 00:31:19 1992 Per Bothner (bothner@rtl.cygnus.com) + + * rs6k.h: Fix incorrect extended opcode for instructions `fm' + and `fd'. (From metin@ibmpa.awdpa.ibm.com (Metin G. Ozisik).) + +Tue Apr 7 13:38:47 1992 Stu Grossman (grossman at cygnus.com) + + * rs6k.h: Move from ../../gdb/rs6k-opcode.h. + +Fri Apr 3 11:30:20 1992 Fred Fish (fnf@cygnus.com) + + * m68k.h (one, two): Cast macro args to unsigned to suppress + complaints from compiler and lint about integer overflow during + shift. + +Sun Mar 29 12:22:08 1992 John Gilmore (gnu at cygnus.com) + + * sparc.h (OP): Avoid signed overflow when shifting to high order bit. + +Fri Mar 6 00:22:38 1992 John Gilmore (gnu at cygnus.com) + + * mips.h: Make bitfield layout depend on the HOST compiler, + not on the TARGET system. + +Fri Feb 21 01:29:51 1992 K. Richard Pixley (rich@cygnus.com) + + * i386.h: added inb, inw, outb, outw opcodes, added att syntax for + scmp, slod, smov, ssca, ssto. Curtesy Minh Tran-Le + . + +Thu Jan 30 07:31:44 1992 Steve Chamberlain (sac at rtl.cygnus.com) + + * h8300.h: turned op_type enum into #define list + +Thu Jan 30 01:07:24 1992 John Gilmore (gnu at cygnus.com) + + * sparc.h: Remove "cypress" architecture. Remove "fitox" and + similar instructions -- they've been renamed to "fitoq", etc. + REALLY fix tsubcctv. Fix "fcmpeq" and "fcmpq" which had wrong + number of arguments. + * h8300.h: Remove extra ; which produces compiler warning. + +Tue Jan 28 22:59:22 1992 Stu Grossman (grossman at cygnus.com) + + * sparc.h: fix opcode for tsubcctv. + +Tue Jan 7 17:19:39 1992 K. Richard Pixley (rich at cygnus.com) + + * sparc.h: fba and cba are now aliases for fb and cb respectively. + +Fri Dec 27 10:55:50 1991 Per Bothner (bothner at cygnus.com) + + * sparc.h (nop): Made the 'lose' field be even tighter, + so only a standard 'nop' is disassembled as a nop. + +Sun Dec 22 12:18:18 1991 Michael Tiemann (tiemann at cygnus.com) + + * sparc.h (nop): Add RD_GO to `lose' so that only %g0 in dest is + disassembled as a nop. + +Tue Dec 10 00:22:20 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * sparc.h: fix a typo. + +Sat Nov 30 20:40:51 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * a29k.h, arm.h, h8300.h, i386.h, i860.h, i960.h , m68k.h, + m88k.h, mips.h , np1.h, ns32k.h, pn.h, pyr.h, sparc.h, tahoe.h, + vax.h, ChangeLog: renamed from ../-opcode.h + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/include/opcode/a29k.h b/contrib/gdb/include/opcode/a29k.h new file mode 100644 index 000000000000..002e127d15ef --- /dev/null +++ b/contrib/gdb/include/opcode/a29k.h @@ -0,0 +1,285 @@ +/* Table of opcodes for the AMD 29000 family. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB and GAS. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct a29k_opcode { + /* Name of the instruction. */ + char *name; + + /* Opcode word */ + unsigned long opcode; + + /* A string of characters which describe the operands. + Valid characters are: + , Itself. The character appears in the assembly code. + a RA. The register number is in bits 8-15 of the instruction. + b RB. The register number is in bits 0-7 of the instruction. + c RC. The register number is in bits 16-23 of the instruction. + i An immediate operand is in bits 0-7 of the instruction. + x Bits 0-7 and 16-23 of the instruction are bits 0-7 and 8-15 + (respectively) of the immediate operand. + h Same as x but the instruction contains bits 16-31 of the + immediate operand. + X Same as x but bits 16-31 of the signed immediate operand + are set to 1 (thus the operand is always negative). + P,A Bits 0-7 and 16-23 of the instruction are bits 2-9 and 10-17 + (respectively) of the immediate operand. + P=PC-relative, sign-extended to 32 bits. + A=Absolute, zero-extended to 32 bits. + e CE bit (bit 23) for a load/store instruction. + n Control field (bits 16-22) for a load/store instruction. + v Immediate operand in bits 16-23 of the instruction. + (used for trap numbers). + s SA. Special-purpose register number in bits 8-15 + of the instruction. + u UI--bit 7 of the instruction. + r RND--bits 4-6 of the instruction. + d FD--bits 2-3 of the instruction. + f FS--bits 0-1 of the instruction. + I ID--bits 16-17 of the instruction. + + Extensions for 29050: + + d FMT--bits 2-3 of the instruction (not really new). + f ACN--bits 0-1 of the instruction (not really new). + F FUNC--Special function in bits 18-21 of the instruction. + C ACN--bits 16-17 specifying the accumlator register. */ + char *args; +}; + +#ifndef CONST +#define CONST +#endif /* CONST */ + +static CONST struct a29k_opcode a29k_opcodes[] = +{ + +{ "add", 0x14000000, "c,a,b" }, +{ "add", 0x15000000, "c,a,i" }, +{ "addc", 0x1c000000, "c,a,b" }, +{ "addc", 0x1d000000, "c,a,i" }, +{ "addcs", 0x18000000, "c,a,b" }, +{ "addcs", 0x19000000, "c,a,i" }, +{ "addcu", 0x1a000000, "c,a,b" }, +{ "addcu", 0x1b000000, "c,a,i" }, +{ "adds", 0x10000000, "c,a,b" }, +{ "adds", 0x11000000, "c,a,i" }, +{ "addu", 0x12000000, "c,a,b" }, +{ "addu", 0x13000000, "c,a,i" }, +{ "and", 0x90000000, "c,a,b" }, +{ "and", 0x91000000, "c,a,i" }, +{ "andn", 0x9c000000, "c,a,b" }, +{ "andn", 0x9d000000, "c,a,i" }, +{ "aseq", 0x70000000, "v,a,b" }, +{ "aseq", 0x71000000, "v,a,i" }, +{ "asge", 0x5c000000, "v,a,b" }, +{ "asge", 0x5d000000, "v,a,i" }, +{ "asgeu", 0x5e000000, "v,a,b" }, +{ "asgeu", 0x5f000000, "v,a,i" }, +{ "asgt", 0x58000000, "v,a,b" }, +{ "asgt", 0x59000000, "v,a,i" }, +{ "asgtu", 0x5a000000, "v,a,b" }, +{ "asgtu", 0x5b000000, "v,a,i" }, +{ "asle", 0x54000000, "v,a,b" }, +{ "asle", 0x55000000, "v,a,i" }, +{ "asleu", 0x56000000, "v,a,b" }, +{ "asleu", 0x57000000, "v,a,i" }, +{ "aslt", 0x50000000, "v,a,b" }, +{ "aslt", 0x51000000, "v,a,i" }, +{ "asltu", 0x52000000, "v,a,b" }, +{ "asltu", 0x53000000, "v,a,i" }, +{ "asneq", 0x72000000, "v,a,b" }, +{ "asneq", 0x73000000, "v,a,i" }, +{ "call", 0xa8000000, "a,P" }, +{ "call", 0xa9000000, "a,A" }, +{ "calli", 0xc8000000, "a,b" }, +{ "class", 0xe6000000, "c,a,f" }, +{ "clz", 0x08000000, "c,b" }, +{ "clz", 0x09000000, "c,i" }, +{ "const", 0x03000000, "a,x" }, +{ "consth", 0x02000000, "a,h" }, +{ "consthz", 0x05000000, "a,h" }, +{ "constn", 0x01000000, "a,X" }, +{ "convert", 0xe4000000, "c,a,u,r,d,f" }, +{ "cpbyte", 0x2e000000, "c,a,b" }, +{ "cpbyte", 0x2f000000, "c,a,i" }, +{ "cpeq", 0x60000000, "c,a,b" }, +{ "cpeq", 0x61000000, "c,a,i" }, +{ "cpge", 0x4c000000, "c,a,b" }, +{ "cpge", 0x4d000000, "c,a,i" }, +{ "cpgeu", 0x4e000000, "c,a,b" }, +{ "cpgeu", 0x4f000000, "c,a,i" }, +{ "cpgt", 0x48000000, "c,a,b" }, +{ "cpgt", 0x49000000, "c,a,i" }, +{ "cpgtu", 0x4a000000, "c,a,b" }, +{ "cpgtu", 0x4b000000, "c,a,i" }, +{ "cple", 0x44000000, "c,a,b" }, +{ "cple", 0x45000000, "c,a,i" }, +{ "cpleu", 0x46000000, "c,a,b" }, +{ "cpleu", 0x47000000, "c,a,i" }, +{ "cplt", 0x40000000, "c,a,b" }, +{ "cplt", 0x41000000, "c,a,i" }, +{ "cpltu", 0x42000000, "c,a,b" }, +{ "cpltu", 0x43000000, "c,a,i" }, +{ "cpneq", 0x62000000, "c,a,b" }, +{ "cpneq", 0x63000000, "c,a,i" }, +{ "dadd", 0xf1000000, "c,a,b" }, +{ "ddiv", 0xf7000000, "c,a,b" }, +{ "deq", 0xeb000000, "c,a,b" }, +{ "dge", 0xef000000, "c,a,b" }, +{ "dgt", 0xed000000, "c,a,b" }, +{ "div", 0x6a000000, "c,a,b" }, +{ "div", 0x6b000000, "c,a,i" }, +{ "div0", 0x68000000, "c,b" }, +{ "div0", 0x69000000, "c,i" }, +{ "divide", 0xe1000000, "c,a,b" }, +{ "dividu", 0xe3000000, "c,a,b" }, +{ "divl", 0x6c000000, "c,a,b" }, +{ "divl", 0x6d000000, "c,a,i" }, +{ "divrem", 0x6e000000, "c,a,b" }, +{ "divrem", 0x6f000000, "c,a,i" }, +{ "dmac", 0xd9000000, "F,C,a,b" }, +{ "dmsm", 0xdb000000, "c,a,b" }, +{ "dmul", 0xf5000000, "c,a,b" }, +{ "dsub", 0xf3000000, "c,a,b" }, +{ "emulate", 0xd7000000, "v,a,b" }, +{ "exbyte", 0x0a000000, "c,a,b" }, +{ "exbyte", 0x0b000000, "c,a,i" }, +{ "exhw", 0x7c000000, "c,a,b" }, +{ "exhw", 0x7d000000, "c,a,i" }, +{ "exhws", 0x7e000000, "c,a" }, +{ "extract", 0x7a000000, "c,a,b" }, +{ "extract", 0x7b000000, "c,a,i" }, +{ "fadd", 0xf0000000, "c,a,b" }, +{ "fdiv", 0xf6000000, "c,a,b" }, +{ "fdmul", 0xf9000000, "c,a,b" }, +{ "feq", 0xea000000, "c,a,b" }, +{ "fge", 0xee000000, "c,a,b" }, +{ "fgt", 0xec000000, "c,a,b" }, +{ "fmac", 0xd8000000, "F,C,a,b" }, +{ "fmsm", 0xda000000, "c,a,b" }, +{ "fmul", 0xf4000000, "c,a,b" }, +{ "fsub", 0xf2000000, "c,a,b" }, +{ "halt", 0x89000000, "" }, +{ "inbyte", 0x0c000000, "c,a,b" }, +{ "inbyte", 0x0d000000, "c,a,i" }, +{ "inhw", 0x78000000, "c,a,b" }, +{ "inhw", 0x79000000, "c,a,i" }, +{ "inv", 0x9f000000, "I" }, +{ "iret", 0x88000000, "" }, +{ "iretinv", 0x8c000000, "I" }, +{ "jmp", 0xa0000000, "P" }, +{ "jmp", 0xa1000000, "A" }, +{ "jmpf", 0xa4000000, "a,P" }, +{ "jmpf", 0xa5000000, "a,A" }, +{ "jmpfdec", 0xb4000000, "a,P" }, +{ "jmpfdec", 0xb5000000, "a,A" }, +{ "jmpfi", 0xc4000000, "a,b" }, +{ "jmpi", 0xc0000000, "b" }, +{ "jmpt", 0xac000000, "a,P" }, +{ "jmpt", 0xad000000, "a,A" }, +{ "jmpti", 0xcc000000, "a,b" }, +{ "load", 0x16000000, "e,n,a,b" }, +{ "load", 0x17000000, "e,n,a,i" }, +{ "loadl", 0x06000000, "e,n,a,b" }, +{ "loadl", 0x07000000, "e,n,a,i" }, +{ "loadm", 0x36000000, "e,n,a,b" }, +{ "loadm", 0x37000000, "e,n,a,i" }, +{ "loadset", 0x26000000, "e,n,a,b" }, +{ "loadset", 0x27000000, "e,n,a,i" }, +{ "mfacc", 0xe9000100, "c,d,f" }, +{ "mfsr", 0xc6000000, "c,s" }, +{ "mftlb", 0xb6000000, "c,a" }, +{ "mtacc", 0xe8010000, "a,d,f" }, +{ "mtsr", 0xce000000, "s,b" }, +{ "mtsrim", 0x04000000, "s,x" }, +{ "mttlb", 0xbe000000, "a,b" }, +{ "mul", 0x64000000, "c,a,b" }, +{ "mul", 0x65000000, "c,a,i" }, +{ "mull", 0x66000000, "c,a,b" }, +{ "mull", 0x67000000, "c,a,i" }, +{ "multiplu", 0xe2000000, "c,a,b" }, +{ "multiply", 0xe0000000, "c,a,b" }, +{ "multm", 0xde000000, "c,a,b" }, +{ "multmu", 0xdf000000, "c,a,b" }, +{ "mulu", 0x74000000, "c,a,b" }, +{ "mulu", 0x75000000, "c,a,i" }, +{ "nand", 0x9a000000, "c,a,b" }, +{ "nand", 0x9b000000, "c,a,i" }, +{ "nop", 0x70400101, "" }, +{ "nor", 0x98000000, "c,a,b" }, +{ "nor", 0x99000000, "c,a,i" }, +{ "or", 0x92000000, "c,a,b" }, +{ "or", 0x93000000, "c,a,i" }, +{ "orn", 0xaa000000, "c,a,b" }, +{ "orn", 0xab000000, "c,a,i" }, + +/* The description of "setip" in Chapter 8 ("instruction set") of the user's + manual claims that these are absolute register numbers. But section + 7.2.1 explains that they are not. The latter is correct, so print + these normally ("lr0", "lr5", etc.). */ +{ "setip", 0x9e000000, "c,a,b" }, + +{ "sll", 0x80000000, "c,a,b" }, +{ "sll", 0x81000000, "c,a,i" }, +{ "sqrt", 0xe5000000, "c,a,f" }, +{ "sra", 0x86000000, "c,a,b" }, +{ "sra", 0x87000000, "c,a,i" }, +{ "srl", 0x82000000, "c,a,b" }, +{ "srl", 0x83000000, "c,a,i" }, +{ "store", 0x1e000000, "e,n,a,b" }, +{ "store", 0x1f000000, "e,n,a,i" }, +{ "storel", 0x0e000000, "e,n,a,b" }, +{ "storel", 0x0f000000, "e,n,a,i" }, +{ "storem", 0x3e000000, "e,n,a,b" }, +{ "storem", 0x3f000000, "e,n,a,i" }, +{ "sub", 0x24000000, "c,a,b" }, +{ "sub", 0x25000000, "c,a,i" }, +{ "subc", 0x2c000000, "c,a,b" }, +{ "subc", 0x2d000000, "c,a,i" }, +{ "subcs", 0x28000000, "c,a,b" }, +{ "subcs", 0x29000000, "c,a,i" }, +{ "subcu", 0x2a000000, "c,a,b" }, +{ "subcu", 0x2b000000, "c,a,i" }, +{ "subr", 0x34000000, "c,a,b" }, +{ "subr", 0x35000000, "c,a,i" }, +{ "subrc", 0x3c000000, "c,a,b" }, +{ "subrc", 0x3d000000, "c,a,i" }, +{ "subrcs", 0x38000000, "c,a,b" }, +{ "subrcs", 0x39000000, "c,a,i" }, +{ "subrcu", 0x3a000000, "c,a,b" }, +{ "subrcu", 0x3b000000, "c,a,i" }, +{ "subrs", 0x30000000, "c,a,b" }, +{ "subrs", 0x31000000, "c,a,i" }, +{ "subru", 0x32000000, "c,a,b" }, +{ "subru", 0x33000000, "c,a,i" }, +{ "subs", 0x20000000, "c,a,b" }, +{ "subs", 0x21000000, "c,a,i" }, +{ "subu", 0x22000000, "c,a,b" }, +{ "subu", 0x23000000, "c,a,i" }, +{ "xnor", 0x96000000, "c,a,b" }, +{ "xnor", 0x97000000, "c,a,i" }, +{ "xor", 0x94000000, "c,a,b" }, +{ "xor", 0x95000000, "c,a,i" }, + +{ "", 0x0, "" } /* Dummy entry, not included in NUM_OPCODES. This + lets code examine entry i+1 without checking + if we've run off the end of the table. */ +}; + +CONST unsigned int num_opcodes = (((sizeof a29k_opcodes) / (sizeof a29k_opcodes[0])) - 1); diff --git a/contrib/gdb/include/opcode/arm.h b/contrib/gdb/include/opcode/arm.h new file mode 100644 index 000000000000..c7087eb9ed4c --- /dev/null +++ b/contrib/gdb/include/opcode/arm.h @@ -0,0 +1,294 @@ +/* ARM opcode list. + Copyright (C) 1989, Free Software Foundation, Inc. + +This file is part of GDB and GAS. + +GDB and GAS are 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 1, or (at your option) +any later version. + +GDB and GAS are 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 GDB or GAS; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* types of instruction (encoded in bits 26 and 27 of the instruction) */ + +#define TYPE_ARITHMETIC 0 +#define TYPE_LDR_STR 1 +#define TYPE_BLOCK_BRANCH 2 +#define TYPE_SWI 3 + +/* bit 25 decides whether an instruction is a block move or a branch */ +#define SUBTYPE_BLOCK 0 +#define SUBTYPE_BRANCH 1 + +/* codes to distinguish the arithmetic instructions */ + +#define OPCODE_AND 0 +#define OPCODE_EOR 1 +#define OPCODE_SUB 2 +#define OPCODE_RSB 3 +#define OPCODE_ADD 4 +#define OPCODE_ADC 5 +#define OPCODE_SBC 6 +#define OPCODE_RSC 7 +#define OPCODE_TST 8 +#define OPCODE_TEQ 9 +#define OPCODE_CMP 10 +#define OPCODE_CMN 11 +#define OPCODE_ORR 12 +#define OPCODE_MOV 13 +#define OPCODE_BIC 14 +#define OPCODE_MVN 15 + +/* condition codes */ + +#define COND_EQ 0 +#define COND_NE 1 +#define COND_CS 2 +#define COND_CC 3 +#define COND_MI 4 +#define COND_PL 5 +#define COND_VS 6 +#define COND_VC 7 +#define COND_HI 8 +#define COND_LS 9 +#define COND_GE 10 +#define COND_LT 11 +#define COND_GT 12 +#define COND_LE 13 +#define COND_AL 14 +#define COND_NV 15 + +/* Describes the format of an ARM machine instruction */ + +struct generic_fmt { + unsigned rest :25; /* the rest of the instruction */ + unsigned subtype :1; /* used to decide between block and branch */ + unsigned type :2; /* one of TYPE_* */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +struct arith_fmt { + unsigned operand2 :12; /* #nn or rn or rn shift #m or rn shift rm */ + unsigned dest :4; /* place where the answer goes */ + unsigned operand1 :4; /* first operand to instruction */ + unsigned set :1; /* == 1 means set processor flags */ + unsigned opcode :4; /* one of OPCODE_* defined above */ + unsigned immed :1; /* operand2 is an immediate value */ + unsigned type :2; /* == TYPE_ARITHMETIC */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +struct ldr_str_fmt { + unsigned offset :12; /* #nn or rn or rn shift #m */ + unsigned reg :4; /* destination for LDR, source for STR */ + unsigned base :4; /* base register */ + unsigned is_load :1; /* == 1 for LDR */ + unsigned writeback :1; /* == 1 means write back (base+offset) into base */ + unsigned byte :1; /* == 1 means byte access else word */ + unsigned up :1; /* == 1 means add offset else subtract it */ + unsigned pre_index :1; /* == 1 means [a,b] form else [a],b form */ + unsigned immed :1; /* == 0 means immediate offset */ + unsigned type :2; /* == TYPE_LDR_STR */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +struct block_fmt { + unsigned mask :16; /* register mask */ + unsigned base :4; /* register used as base of move */ + unsigned is_load :1; /* == 1 for LDM */ + unsigned writeback :1; /* == 1 means update base after move */ + unsigned set :1; /* == 1 means set flags in pc if included in mask */ + unsigned increment :1; /* == 1 means increment base register */ + unsigned before :1; /* == 1 means inc/dec before each move */ + unsigned is_block :1; /* == SUBTYPE_BLOCK */ + unsigned type :2; /* == TYPE_BLOCK_BRANCH */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +struct branch_fmt { + unsigned dest :24; /* destination of the branch */ + unsigned link :1; /* branch with link (function call) */ + unsigned is_branch :1; /* == SUBTYPE_BRANCH */ + unsigned type :2; /* == TYPE_BLOCK_BRANCH */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +#define ROUND_N 0 +#define ROUND_P 1 +#define ROUND_M 2 +#define ROUND_Z 3 + +#define FLOAT2_MVF 0 +#define FLOAT2_MNF 1 +#define FLOAT2_ABS 2 +#define FLOAT2_RND 3 +#define FLOAT2_SQT 4 +#define FLOAT2_LOG 5 +#define FLOAT2_LGN 6 +#define FLOAT2_EXP 7 +#define FLOAT2_SIN 8 +#define FLOAT2_COS 9 +#define FLOAT2_TAN 10 +#define FLOAT2_ASN 11 +#define FLOAT2_ACS 12 +#define FLOAT2_ATN 13 + +#define FLOAT3_ADF 0 +#define FLOAT3_MUF 1 +#define FLOAT3_SUF 2 +#define FLOAT3_RSF 3 +#define FLOAT3_DVF 4 +#define FLOAT3_RDF 5 +#define FLOAT3_POW 6 +#define FLOAT3_RPW 7 +#define FLOAT3_RMF 8 +#define FLOAT3_FML 9 +#define FLOAT3_FDV 10 +#define FLOAT3_FRD 11 +#define FLOAT3_POL 12 + +struct float2_fmt { + unsigned operand2 :3; /* second operand */ + unsigned immed :1; /* == 1 if second operand is a constant */ + unsigned pad1 :1; /* == 0 */ + unsigned rounding :2; /* ROUND_* */ + unsigned is_double :1; /* == 1 if precision is double (only if not extended) */ + unsigned pad2 :4; /* == 1 */ + unsigned dest :3; /* destination */ + unsigned is_2_op :1; /* == 1 if 2 operand ins */ + unsigned operand1 :3; /* first operand (only of is_2_op == 0) */ + unsigned is_extended :1; /* == 1 if precision is extended */ + unsigned opcode :4; /* FLOAT2_* or FLOAT3_* depending on is_2_op */ + unsigned must_be_2 :2; /* == 2 */ + unsigned type :2; /* == TYPE_SWI */ + unsigned cond :4; /* COND_* */ +}; + +struct swi_fmt { + unsigned argument :24; /* argument to SWI (syscall number) */ + unsigned must_be_3 :2; /* == 3 */ + unsigned type :2; /* == TYPE_SWI */ + unsigned cond :4; /* one of COND_* defined above */ +}; + +union insn_fmt { + struct generic_fmt generic; + struct arith_fmt arith; + struct ldr_str_fmt ldr_str; + struct block_fmt block; + struct branch_fmt branch; + struct swi_fmt swi; + unsigned long ins; +}; + +struct opcode { + unsigned long value, mask; /* recognise instruction if (op&mask)==value */ + char *assembler; /* how to disassemble this instruction */ +}; + +/* format of the assembler string : + + %% % + %d print the bitfield in decimal + %x print the bitfield in hex + %r print as an ARM register + %f print a floating point constant if >7 else an fp register + %c print condition code (always bits 28-31) + %P print floating point precision in arithmetic insn + %Q print floating point precision in ldf/stf insn + %R print floating point rounding mode + %'c print specified char iff bit is one + %`c print specified char iff bit is zero + %?ab print a if bit is one else print b + %p print 'p' iff bits 12-15 are 15 + %o print operand2 (immediate or register + shift) + %a print address for ldr/str instruction + %b print branch destination + %A print address for ldc/stc/ldf/stf instruction + %m print register mask for ldm/stm instruction +*/ + +static struct opcode opcodes[] = { + /* ARM instructions */ + 0x00000090, 0x0fe000f0, "mul%20's %12-15r, %16-19r, %0-3r", + 0x00200090, 0x0fe000f0, "mla%20's %12-15r, %16-19r, %0-3r, %8-11r", + 0x00000000, 0x0de00000, "and%c%20's %12-15r, %16-19r, %o", + 0x00200000, 0x0de00000, "eor%c%20's %12-15r, %16-19r, %o", + 0x00400000, 0x0de00000, "sub%c%20's %12-15r, %16-19r, %o", + 0x00600000, 0x0de00000, "rsb%c%20's %12-15r, %16-19r, %o", + 0x00800000, 0x0de00000, "add%c%20's %12-15r, %16-19r, %o", + 0x00a00000, 0x0de00000, "adc%c%20's %12-15r, %16-19r, %o", + 0x00c00000, 0x0de00000, "sbc%c%20's %12-15r, %16-19r, %o", + 0x00e00000, 0x0de00000, "rsc%c%20's %12-15r, %16-19r, %o", + 0x01000000, 0x0de00000, "tst%c%p %16-19r, %o", + 0x01200000, 0x0de00000, "teq%c%p %16-19r, %o", + 0x01400000, 0x0de00000, "cmp%c%p %16-19r, %o", + 0x01600000, 0x0de00000, "cmn%c%p %16-19r, %o", + 0x01800000, 0x0de00000, "orr%c%20's %12-15r, %16-19r, %o", + 0x01a00000, 0x0de00000, "mov%c%20's %12-15r, %o", + 0x01c00000, 0x0de00000, "bic%c%20's %12-15r, %16-19r, %o", + 0x01e00000, 0x0de00000, "mvn%c%20's %12-15r, %o", + 0x04000000, 0x0c100000, "str%c%22'b %12-15r, %a", + 0x04100000, 0x0c100000, "ldr%c%22'b %12-15r, %a", + 0x08000000, 0x0e100000, "stm%c%23?id%24?ba %16-19r%22`!, %m", + 0x08100000, 0x0e100000, "ldm%c%23?id%24?ba %16-19r%22`!, %m%22'^", + 0x0a000000, 0x0e000000, "b%c%24'l %b", + 0x0f000000, 0x0f000000, "swi%c %0-23x", + /* Floating point coprocessor instructions */ + 0x0e000100, 0x0ff08f10, "adf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e100100, 0x0ff08f10, "muf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e200100, 0x0ff08f10, "suf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e300100, 0x0ff08f10, "rsf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e400100, 0x0ff08f10, "dvf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e500100, 0x0ff08f10, "rdf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e600100, 0x0ff08f10, "pow%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e700100, 0x0ff08f10, "rpw%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e800100, 0x0ff08f10, "rmf%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e900100, 0x0ff08f10, "fml%c%P%R %12-14f, %16-18f, %0-3f", + 0x0ea00100, 0x0ff08f10, "fdv%c%P%R %12-14f, %16-18f, %0-3f", + 0x0eb00100, 0x0ff08f10, "frd%c%P%R %12-14f, %16-18f, %0-3f", + 0x0ec00100, 0x0ff08f10, "pol%c%P%R %12-14f, %16-18f, %0-3f", + 0x0e008100, 0x0ff08f10, "mvf%c%P%R %12-14f, %0-3f", + 0x0e108100, 0x0ff08f10, "mnf%c%P%R %12-14f, %0-3f", + 0x0e208100, 0x0ff08f10, "abs%c%P%R %12-14f, %0-3f", + 0x0e308100, 0x0ff08f10, "rnd%c%P%R %12-14f, %0-3f", + 0x0e408100, 0x0ff08f10, "sqt%c%P%R %12-14f, %0-3f", + 0x0e508100, 0x0ff08f10, "log%c%P%R %12-14f, %0-3f", + 0x0e608100, 0x0ff08f10, "lgn%c%P%R %12-14f, %0-3f", + 0x0e708100, 0x0ff08f10, "exp%c%P%R %12-14f, %0-3f", + 0x0e808100, 0x0ff08f10, "sin%c%P%R %12-14f, %0-3f", + 0x0e908100, 0x0ff08f10, "cos%c%P%R %12-14f, %0-3f", + 0x0ea08100, 0x0ff08f10, "tan%c%P%R %12-14f, %0-3f", + 0x0eb08100, 0x0ff08f10, "asn%c%P%R %12-14f, %0-3f", + 0x0ec08100, 0x0ff08f10, "acs%c%P%R %12-14f, %0-3f", + 0x0ed08100, 0x0ff08f10, "atn%c%P%R %12-14f, %0-3f", + 0x0e000110, 0x0ff00f1f, "flt%c%P%R %16-18f, %12-15r", + 0x0e100110, 0x0fff0f98, "fix%c%R %12-15r, %0-2f", + 0x0e200110, 0x0fff0fff, "wfs%c %12-15r", + 0x0e300110, 0x0fff0fff, "rfs%c %12-15r", + 0x0e400110, 0x0fff0fff, "wfc%c %12-15r", + 0x0e500110, 0x0fff0fff, "rfc%c %12-15r", + 0x0e90f110, 0x0ff8fff0, "cmf%c %16-18f, %0-3f", + 0x0eb0f110, 0x0ff8fff0, "cnf%c %16-18f, %0-3f", + 0x0ed0f110, 0x0ff8fff0, "cmfe%c %16-18f, %0-3f", + 0x0ef0f110, 0x0ff8fff0, "cnfe%c %16-18f, %0-3f", + 0x0c000100, 0x0e100f00, "stf%c%Q %12-14f, %A", + 0x0c100100, 0x0e100f00, "ldf%c%Q %12-14f, %A", + /* Generic coprocessor instructions */ + 0x0e000000, 0x0f000010, "cdp%c %8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}", + 0x0e000010, 0x0f100010, "mrc%c %8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}", + 0x0e100010, 0x0f100010, "mcr%c %8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}", + 0x0c000000, 0x0e100000, "stc%c%22`l %8-11d, cr%12-15d, %A", + 0x0c100000, 0x0e100000, "ldc%c%22`l %8-11d, cr%12-15d, %A", + /* the rest */ + 0x00000000, 0x00000000, "undefined instruction %0-31x", +}; +#define N_OPCODES (sizeof opcodes / sizeof opcodes[0]) diff --git a/contrib/gdb/include/opcode/convex.h b/contrib/gdb/include/opcode/convex.h new file mode 100644 index 000000000000..efaeebb65a5f --- /dev/null +++ b/contrib/gdb/include/opcode/convex.h @@ -0,0 +1,1711 @@ +/* Information for instruction disassembly on the Convex. + Copyright 1989, 1993 Free Software Foundation. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CONST +#define CONST +#endif /* CONST */ + +#define xxx 0 +#define rrr 1 +#define rr 2 +#define rxr 3 +#define r 4 +#define nops 5 +#define nr 6 +#define pcrel 7 +#define lr 8 +#define rxl 9 +#define rlr 10 +#define rrl 11 +#define iml 12 +#define imr 13 +#define a1r 14 +#define a1l 15 +#define a2r 16 +#define a2l 17 +#define a3 18 +#define a4 19 +#define a5 20 +#define V 1 +#define S 2 +#define VM 3 +#define A 4 +#define VL 5 +#define VS 6 +#define VLS 7 +#define PSW 8 +/* Prevent an error during "make depend". */ +#if !defined (PC) +#define PC 9 +#endif +#define ITR 10 +#define VV 11 +#define ITSR 12 +#define TOC 13 +#define CIR 14 +#define TTR 15 +#define VMU 16 +#define VML 17 +#define ICR 18 +#define TCPU 19 +#define CPUID 20 +#define TID 21 + +CONST char *op[] = { + "", + "v0\0v1\0v2\0v3\0v4\0v5\0v6\0v7", + "s0\0s1\0s2\0s3\0s4\0s5\0s6\0s7", + "vm", + "sp\0a1\0a2\0a3\0a4\0a5\0ap\0fp", + "vl", + "vs", + "vls", + "psw", + "pc", + "itr", + "vv", + "itsr", + "toc", + "cir", + "ttr", + "vmu", + "vml", + "icr", + "tcpu", + "cpuid", + "tid", +}; + +CONST struct formstr format0[] = { + {0,0,rrr,V,S,S}, /* mov */ + {0,0,rrr,S,S,V}, /* mov */ + {1,1,rrr,V,V,V}, /* merg.t */ + {2,1,rrr,V,V,V}, /* mask.t */ + {1,2,rrr,V,S,V}, /* merg.f */ + {2,2,rrr,V,S,V}, /* mask.f */ + {1,1,rrr,V,S,V}, /* merg.t */ + {2,1,rrr,V,S,V}, /* mask.t */ + {3,3,rrr,V,V,V}, /* mul.s */ + {3,4,rrr,V,V,V}, /* mul.d */ + {4,3,rrr,V,V,V}, /* div.s */ + {4,4,rrr,V,V,V}, /* div.d */ + {3,3,rrr,V,S,V}, /* mul.s */ + {3,4,rrr,V,S,V}, /* mul.d */ + {4,3,rrr,V,S,V}, /* div.s */ + {4,4,rrr,V,S,V}, /* div.d */ + {5,0,rrr,V,V,V}, /* and */ + {6,0,rrr,V,V,V}, /* or */ + {7,0,rrr,V,V,V}, /* xor */ + {8,0,rrr,V,V,V}, /* shf */ + {5,0,rrr,V,S,V}, /* and */ + {6,0,rrr,V,S,V}, /* or */ + {7,0,rrr,V,S,V}, /* xor */ + {8,0,rrr,V,S,V}, /* shf */ + {9,3,rrr,V,V,V}, /* add.s */ + {9,4,rrr,V,V,V}, /* add.d */ + {10,3,rrr,V,V,V}, /* sub.s */ + {10,4,rrr,V,V,V}, /* sub.d */ + {9,3,rrr,V,S,V}, /* add.s */ + {9,4,rrr,V,S,V}, /* add.d */ + {10,3,rrr,V,S,V}, /* sub.s */ + {10,4,rrr,V,S,V}, /* sub.d */ + {9,5,rrr,V,V,V}, /* add.b */ + {9,6,rrr,V,V,V}, /* add.h */ + {9,7,rrr,V,V,V}, /* add.w */ + {9,8,rrr,V,V,V}, /* add.l */ + {9,5,rrr,V,S,V}, /* add.b */ + {9,6,rrr,V,S,V}, /* add.h */ + {9,7,rrr,V,S,V}, /* add.w */ + {9,8,rrr,V,S,V}, /* add.l */ + {10,5,rrr,V,V,V}, /* sub.b */ + {10,6,rrr,V,V,V}, /* sub.h */ + {10,7,rrr,V,V,V}, /* sub.w */ + {10,8,rrr,V,V,V}, /* sub.l */ + {10,5,rrr,V,S,V}, /* sub.b */ + {10,6,rrr,V,S,V}, /* sub.h */ + {10,7,rrr,V,S,V}, /* sub.w */ + {10,8,rrr,V,S,V}, /* sub.l */ + {3,5,rrr,V,V,V}, /* mul.b */ + {3,6,rrr,V,V,V}, /* mul.h */ + {3,7,rrr,V,V,V}, /* mul.w */ + {3,8,rrr,V,V,V}, /* mul.l */ + {3,5,rrr,V,S,V}, /* mul.b */ + {3,6,rrr,V,S,V}, /* mul.h */ + {3,7,rrr,V,S,V}, /* mul.w */ + {3,8,rrr,V,S,V}, /* mul.l */ + {4,5,rrr,V,V,V}, /* div.b */ + {4,6,rrr,V,V,V}, /* div.h */ + {4,7,rrr,V,V,V}, /* div.w */ + {4,8,rrr,V,V,V}, /* div.l */ + {4,5,rrr,V,S,V}, /* div.b */ + {4,6,rrr,V,S,V}, /* div.h */ + {4,7,rrr,V,S,V}, /* div.w */ + {4,8,rrr,V,S,V}, /* div.l */ +}; + +CONST struct formstr format1[] = { + {11,0,xxx,0,0,0}, /* exit */ + {12,0,a3,0,0,0}, /* jmp */ + {13,2,a3,0,0,0}, /* jmpi.f */ + {13,1,a3,0,0,0}, /* jmpi.t */ + {14,2,a3,0,0,0}, /* jmpa.f */ + {14,1,a3,0,0,0}, /* jmpa.t */ + {15,2,a3,0,0,0}, /* jmps.f */ + {15,1,a3,0,0,0}, /* jmps.t */ + {16,0,a3,0,0,0}, /* tac */ + {17,0,a1r,A,0,0}, /* ldea */ + {18,8,a1l,VLS,0,0}, /* ld.l */ + {18,9,a1l,VM,0,0}, /* ld.x */ + {19,0,a3,0,0,0}, /* tas */ + {20,0,a3,0,0,0}, /* pshea */ + {21,8,a2l,VLS,0,0}, /* st.l */ + {21,9,a2l,VM,0,0}, /* st.x */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {22,0,a3,0,0,0}, /* call */ + {23,0,a3,0,0,0}, /* calls */ + {24,0,a3,0,0,0}, /* callq */ + {25,0,a1r,A,0,0}, /* pfork */ + {26,5,a2r,S,0,0}, /* ste.b */ + {26,6,a2r,S,0,0}, /* ste.h */ + {26,7,a2r,S,0,0}, /* ste.w */ + {26,8,a2r,S,0,0}, /* ste.l */ + {18,5,a1r,A,0,0}, /* ld.b */ + {18,6,a1r,A,0,0}, /* ld.h */ + {18,7,a1r,A,0,0}, /* ld.w */ + {27,7,a1r,A,0,0}, /* incr.w */ + {21,5,a2r,A,0,0}, /* st.b */ + {21,6,a2r,A,0,0}, /* st.h */ + {21,7,a2r,A,0,0}, /* st.w */ + {27,8,a1r,S,0,0}, /* incr.l */ + {18,5,a1r,S,0,0}, /* ld.b */ + {18,6,a1r,S,0,0}, /* ld.h */ + {18,7,a1r,S,0,0}, /* ld.w */ + {18,8,a1r,S,0,0}, /* ld.l */ + {21,5,a2r,S,0,0}, /* st.b */ + {21,6,a2r,S,0,0}, /* st.h */ + {21,7,a2r,S,0,0}, /* st.w */ + {21,8,a2r,S,0,0}, /* st.l */ + {18,5,a1r,V,0,0}, /* ld.b */ + {18,6,a1r,V,0,0}, /* ld.h */ + {18,7,a1r,V,0,0}, /* ld.w */ + {18,8,a1r,V,0,0}, /* ld.l */ + {21,5,a2r,V,0,0}, /* st.b */ + {21,6,a2r,V,0,0}, /* st.h */ + {21,7,a2r,V,0,0}, /* st.w */ + {21,8,a2r,V,0,0}, /* st.l */ +}; + +CONST struct formstr format2[] = { + {28,5,rr,A,A,0}, /* cvtw.b */ + {28,6,rr,A,A,0}, /* cvtw.h */ + {29,7,rr,A,A,0}, /* cvtb.w */ + {30,7,rr,A,A,0}, /* cvth.w */ + {28,5,rr,S,S,0}, /* cvtw.b */ + {28,6,rr,S,S,0}, /* cvtw.h */ + {29,7,rr,S,S,0}, /* cvtb.w */ + {30,7,rr,S,S,0}, /* cvth.w */ + {28,3,rr,S,S,0}, /* cvtw.s */ + {31,7,rr,S,S,0}, /* cvts.w */ + {32,3,rr,S,S,0}, /* cvtd.s */ + {31,4,rr,S,S,0}, /* cvts.d */ + {31,8,rr,S,S,0}, /* cvts.l */ + {32,8,rr,S,S,0}, /* cvtd.l */ + {33,3,rr,S,S,0}, /* cvtl.s */ + {33,4,rr,S,S,0}, /* cvtl.d */ + {34,0,rr,A,A,0}, /* ldpa */ + {8,0,nr,A,0,0}, /* shf */ + {18,6,nr,A,0,0}, /* ld.h */ + {18,7,nr,A,0,0}, /* ld.w */ + {33,7,rr,S,S,0}, /* cvtl.w */ + {28,8,rr,S,S,0}, /* cvtw.l */ + {35,1,rr,S,S,0}, /* plc.t */ + {36,0,rr,S,S,0}, /* tzc */ + {37,6,rr,A,A,0}, /* eq.h */ + {37,7,rr,A,A,0}, /* eq.w */ + {37,6,nr,A,0,0}, /* eq.h */ + {37,7,nr,A,0,0}, /* eq.w */ + {37,5,rr,S,S,0}, /* eq.b */ + {37,6,rr,S,S,0}, /* eq.h */ + {37,7,rr,S,S,0}, /* eq.w */ + {37,8,rr,S,S,0}, /* eq.l */ + {38,6,rr,A,A,0}, /* leu.h */ + {38,7,rr,A,A,0}, /* leu.w */ + {38,6,nr,A,0,0}, /* leu.h */ + {38,7,nr,A,0,0}, /* leu.w */ + {38,5,rr,S,S,0}, /* leu.b */ + {38,6,rr,S,S,0}, /* leu.h */ + {38,7,rr,S,S,0}, /* leu.w */ + {38,8,rr,S,S,0}, /* leu.l */ + {39,6,rr,A,A,0}, /* ltu.h */ + {39,7,rr,A,A,0}, /* ltu.w */ + {39,6,nr,A,0,0}, /* ltu.h */ + {39,7,nr,A,0,0}, /* ltu.w */ + {39,5,rr,S,S,0}, /* ltu.b */ + {39,6,rr,S,S,0}, /* ltu.h */ + {39,7,rr,S,S,0}, /* ltu.w */ + {39,8,rr,S,S,0}, /* ltu.l */ + {40,6,rr,A,A,0}, /* le.h */ + {40,7,rr,A,A,0}, /* le.w */ + {40,6,nr,A,0,0}, /* le.h */ + {40,7,nr,A,0,0}, /* le.w */ + {40,5,rr,S,S,0}, /* le.b */ + {40,6,rr,S,S,0}, /* le.h */ + {40,7,rr,S,S,0}, /* le.w */ + {40,8,rr,S,S,0}, /* le.l */ + {41,6,rr,A,A,0}, /* lt.h */ + {41,7,rr,A,A,0}, /* lt.w */ + {41,6,nr,A,0,0}, /* lt.h */ + {41,7,nr,A,0,0}, /* lt.w */ + {41,5,rr,S,S,0}, /* lt.b */ + {41,6,rr,S,S,0}, /* lt.h */ + {41,7,rr,S,S,0}, /* lt.w */ + {41,8,rr,S,S,0}, /* lt.l */ + {9,7,rr,S,A,0}, /* add.w */ + {8,0,rr,A,A,0}, /* shf */ + {0,0,rr,A,A,0}, /* mov */ + {0,0,rr,S,A,0}, /* mov */ + {0,7,rr,S,S,0}, /* mov.w */ + {8,0,rr,S,S,0}, /* shf */ + {0,0,rr,S,S,0}, /* mov */ + {0,0,rr,A,S,0}, /* mov */ + {5,0,rr,A,A,0}, /* and */ + {6,0,rr,A,A,0}, /* or */ + {7,0,rr,A,A,0}, /* xor */ + {42,0,rr,A,A,0}, /* not */ + {5,0,rr,S,S,0}, /* and */ + {6,0,rr,S,S,0}, /* or */ + {7,0,rr,S,S,0}, /* xor */ + {42,0,rr,S,S,0}, /* not */ + {40,3,rr,S,S,0}, /* le.s */ + {40,4,rr,S,S,0}, /* le.d */ + {41,3,rr,S,S,0}, /* lt.s */ + {41,4,rr,S,S,0}, /* lt.d */ + {9,3,rr,S,S,0}, /* add.s */ + {9,4,rr,S,S,0}, /* add.d */ + {10,3,rr,S,S,0}, /* sub.s */ + {10,4,rr,S,S,0}, /* sub.d */ + {37,3,rr,S,S,0}, /* eq.s */ + {37,4,rr,S,S,0}, /* eq.d */ + {43,6,rr,A,A,0}, /* neg.h */ + {43,7,rr,A,A,0}, /* neg.w */ + {3,3,rr,S,S,0}, /* mul.s */ + {3,4,rr,S,S,0}, /* mul.d */ + {4,3,rr,S,S,0}, /* div.s */ + {4,4,rr,S,S,0}, /* div.d */ + {9,6,rr,A,A,0}, /* add.h */ + {9,7,rr,A,A,0}, /* add.w */ + {9,6,nr,A,0,0}, /* add.h */ + {9,7,nr,A,0,0}, /* add.w */ + {9,5,rr,S,S,0}, /* add.b */ + {9,6,rr,S,S,0}, /* add.h */ + {9,7,rr,S,S,0}, /* add.w */ + {9,8,rr,S,S,0}, /* add.l */ + {10,6,rr,A,A,0}, /* sub.h */ + {10,7,rr,A,A,0}, /* sub.w */ + {10,6,nr,A,0,0}, /* sub.h */ + {10,7,nr,A,0,0}, /* sub.w */ + {10,5,rr,S,S,0}, /* sub.b */ + {10,6,rr,S,S,0}, /* sub.h */ + {10,7,rr,S,S,0}, /* sub.w */ + {10,8,rr,S,S,0}, /* sub.l */ + {3,6,rr,A,A,0}, /* mul.h */ + {3,7,rr,A,A,0}, /* mul.w */ + {3,6,nr,A,0,0}, /* mul.h */ + {3,7,nr,A,0,0}, /* mul.w */ + {3,5,rr,S,S,0}, /* mul.b */ + {3,6,rr,S,S,0}, /* mul.h */ + {3,7,rr,S,S,0}, /* mul.w */ + {3,8,rr,S,S,0}, /* mul.l */ + {4,6,rr,A,A,0}, /* div.h */ + {4,7,rr,A,A,0}, /* div.w */ + {4,6,nr,A,0,0}, /* div.h */ + {4,7,nr,A,0,0}, /* div.w */ + {4,5,rr,S,S,0}, /* div.b */ + {4,6,rr,S,S,0}, /* div.h */ + {4,7,rr,S,S,0}, /* div.w */ + {4,8,rr,S,S,0}, /* div.l */ +}; + +CONST struct formstr format3[] = { + {32,3,rr,V,V,0}, /* cvtd.s */ + {31,4,rr,V,V,0}, /* cvts.d */ + {33,4,rr,V,V,0}, /* cvtl.d */ + {32,8,rr,V,V,0}, /* cvtd.l */ + {0,0,rrl,S,S,VM}, /* mov */ + {0,0,rlr,S,VM,S}, /* mov */ + {0,0,0,0,0,0}, + {44,0,rr,S,S,0}, /* lop */ + {36,0,rr,V,V,0}, /* tzc */ + {44,0,rr,V,V,0}, /* lop */ + {0,0,0,0,0,0}, + {42,0,rr,V,V,0}, /* not */ + {8,0,rr,S,V,0}, /* shf */ + {35,1,rr,V,V,0}, /* plc.t */ + {45,2,rr,V,V,0}, /* cprs.f */ + {45,1,rr,V,V,0}, /* cprs.t */ + {37,3,rr,V,V,0}, /* eq.s */ + {37,4,rr,V,V,0}, /* eq.d */ + {43,3,rr,V,V,0}, /* neg.s */ + {43,4,rr,V,V,0}, /* neg.d */ + {37,3,rr,S,V,0}, /* eq.s */ + {37,4,rr,S,V,0}, /* eq.d */ + {43,3,rr,S,S,0}, /* neg.s */ + {43,4,rr,S,S,0}, /* neg.d */ + {40,3,rr,V,V,0}, /* le.s */ + {40,4,rr,V,V,0}, /* le.d */ + {41,3,rr,V,V,0}, /* lt.s */ + {41,4,rr,V,V,0}, /* lt.d */ + {40,3,rr,S,V,0}, /* le.s */ + {40,4,rr,S,V,0}, /* le.d */ + {41,3,rr,S,V,0}, /* lt.s */ + {41,4,rr,S,V,0}, /* lt.d */ + {37,5,rr,V,V,0}, /* eq.b */ + {37,6,rr,V,V,0}, /* eq.h */ + {37,7,rr,V,V,0}, /* eq.w */ + {37,8,rr,V,V,0}, /* eq.l */ + {37,5,rr,S,V,0}, /* eq.b */ + {37,6,rr,S,V,0}, /* eq.h */ + {37,7,rr,S,V,0}, /* eq.w */ + {37,8,rr,S,V,0}, /* eq.l */ + {40,5,rr,V,V,0}, /* le.b */ + {40,6,rr,V,V,0}, /* le.h */ + {40,7,rr,V,V,0}, /* le.w */ + {40,8,rr,V,V,0}, /* le.l */ + {40,5,rr,S,V,0}, /* le.b */ + {40,6,rr,S,V,0}, /* le.h */ + {40,7,rr,S,V,0}, /* le.w */ + {40,8,rr,S,V,0}, /* le.l */ + {41,5,rr,V,V,0}, /* lt.b */ + {41,6,rr,V,V,0}, /* lt.h */ + {41,7,rr,V,V,0}, /* lt.w */ + {41,8,rr,V,V,0}, /* lt.l */ + {41,5,rr,S,V,0}, /* lt.b */ + {41,6,rr,S,V,0}, /* lt.h */ + {41,7,rr,S,V,0}, /* lt.w */ + {41,8,rr,S,V,0}, /* lt.l */ + {43,5,rr,V,V,0}, /* neg.b */ + {43,6,rr,V,V,0}, /* neg.h */ + {43,7,rr,V,V,0}, /* neg.w */ + {43,8,rr,V,V,0}, /* neg.l */ + {43,5,rr,S,S,0}, /* neg.b */ + {43,6,rr,S,S,0}, /* neg.h */ + {43,7,rr,S,S,0}, /* neg.w */ + {43,8,rr,S,S,0}, /* neg.l */ +}; + +CONST struct formstr format4[] = { + {46,0,nops,0,0,0}, /* nop */ + {47,0,pcrel,0,0,0}, /* br */ + {48,2,pcrel,0,0,0}, /* bri.f */ + {48,1,pcrel,0,0,0}, /* bri.t */ + {49,2,pcrel,0,0,0}, /* bra.f */ + {49,1,pcrel,0,0,0}, /* bra.t */ + {50,2,pcrel,0,0,0}, /* brs.f */ + {50,1,pcrel,0,0,0}, /* brs.t */ +}; + +CONST struct formstr format5[] = { + {51,5,rr,V,V,0}, /* ldvi.b */ + {51,6,rr,V,V,0}, /* ldvi.h */ + {51,7,rr,V,V,0}, /* ldvi.w */ + {51,8,rr,V,V,0}, /* ldvi.l */ + {28,3,rr,V,V,0}, /* cvtw.s */ + {31,7,rr,V,V,0}, /* cvts.w */ + {28,8,rr,V,V,0}, /* cvtw.l */ + {33,7,rr,V,V,0}, /* cvtl.w */ + {52,5,rxr,V,V,0}, /* stvi.b */ + {52,6,rxr,V,V,0}, /* stvi.h */ + {52,7,rxr,V,V,0}, /* stvi.w */ + {52,8,rxr,V,V,0}, /* stvi.l */ + {52,5,rxr,S,V,0}, /* stvi.b */ + {52,6,rxr,S,V,0}, /* stvi.h */ + {52,7,rxr,S,V,0}, /* stvi.w */ + {52,8,rxr,S,V,0}, /* stvi.l */ +}; + +CONST struct formstr format6[] = { + {53,0,r,A,0,0}, /* ldsdr */ + {54,0,r,A,0,0}, /* ldkdr */ + {55,3,r,S,0,0}, /* ln.s */ + {55,4,r,S,0,0}, /* ln.d */ + {56,0,nops,0,0,0}, /* patu */ + {57,0,r,A,0,0}, /* pate */ + {58,0,nops,0,0,0}, /* pich */ + {59,0,nops,0,0,0}, /* plch */ + {0,0,lr,PSW,A,0}, /* mov */ + {0,0,rxl,A,PSW,0}, /* mov */ + {0,0,lr,PC,A,0}, /* mov */ + {60,0,r,S,0,0}, /* idle */ + {0,0,lr,ITR,S,0}, /* mov */ + {0,0,rxl,S,ITR,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,rxl,S,ITSR,0}, /* mov */ + {61,0,nops,0,0,0}, /* rtnq */ + {62,0,nops,0,0,0}, /* cfork */ + {63,0,nops,0,0,0}, /* rtn */ + {64,0,nops,0,0,0}, /* wfork */ + {65,0,nops,0,0,0}, /* join */ + {66,0,nops,0,0,0}, /* rtnc */ + {67,3,r,S,0,0}, /* exp.s */ + {67,4,r,S,0,0}, /* exp.d */ + {68,3,r,S,0,0}, /* sin.s */ + {68,4,r,S,0,0}, /* sin.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {69,3,r,S,0,0}, /* cos.s */ + {69,4,r,S,0,0}, /* cos.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {70,7,r,A,0,0}, /* psh.w */ + {0,0,0,0,0,0}, + {71,7,r,A,0,0}, /* pop.w */ + {0,0,0,0,0,0}, + {70,7,r,S,0,0}, /* psh.w */ + {70,8,r,S,0,0}, /* psh.l */ + {71,7,r,S,0,0}, /* pop.w */ + {71,8,r,S,0,0}, /* pop.l */ + {72,0,nops,0,0,0}, /* eni */ + {73,0,nops,0,0,0}, /* dsi */ + {74,0,nops,0,0,0}, /* bkpt */ + {75,0,nops,0,0,0}, /* msync */ + {76,0,r,S,0,0}, /* mski */ + {77,0,r,S,0,0}, /* xmti */ + {0,0,rxl,S,VV,0}, /* mov */ + {78,0,nops,0,0,0}, /* tstvv */ + {0,0,lr,VS,A,0}, /* mov */ + {0,0,rxl,A,VS,0}, /* mov */ + {0,0,lr,VL,A,0}, /* mov */ + {0,0,rxl,A,VL,0}, /* mov */ + {0,7,lr,VS,S,0}, /* mov.w */ + {0,7,rxl,S,VS,0}, /* mov.w */ + {0,7,lr,VL,S,0}, /* mov.w */ + {0,7,rxl,S,VL,0}, /* mov.w */ + {79,0,r,A,0,0}, /* diag */ + {80,0,nops,0,0,0}, /* pbkpt */ + {81,3,r,S,0,0}, /* sqrt.s */ + {81,4,r,S,0,0}, /* sqrt.d */ + {82,0,nops,0,0,0}, /* casr */ + {0,0,0,0,0,0}, + {83,3,r,S,0,0}, /* atan.s */ + {83,4,r,S,0,0}, /* atan.d */ +}; + +CONST struct formstr format7[] = { + {84,5,r,V,0,0}, /* sum.b */ + {84,6,r,V,0,0}, /* sum.h */ + {84,7,r,V,0,0}, /* sum.w */ + {84,8,r,V,0,0}, /* sum.l */ + {85,0,r,V,0,0}, /* all */ + {86,0,r,V,0,0}, /* any */ + {87,0,r,V,0,0}, /* parity */ + {0,0,0,0,0,0}, + {88,5,r,V,0,0}, /* max.b */ + {88,6,r,V,0,0}, /* max.h */ + {88,7,r,V,0,0}, /* max.w */ + {88,8,r,V,0,0}, /* max.l */ + {89,5,r,V,0,0}, /* min.b */ + {89,6,r,V,0,0}, /* min.h */ + {89,7,r,V,0,0}, /* min.w */ + {89,8,r,V,0,0}, /* min.l */ + {84,3,r,V,0,0}, /* sum.s */ + {84,4,r,V,0,0}, /* sum.d */ + {90,3,r,V,0,0}, /* prod.s */ + {90,4,r,V,0,0}, /* prod.d */ + {88,3,r,V,0,0}, /* max.s */ + {88,4,r,V,0,0}, /* max.d */ + {89,3,r,V,0,0}, /* min.s */ + {89,4,r,V,0,0}, /* min.d */ + {90,5,r,V,0,0}, /* prod.b */ + {90,6,r,V,0,0}, /* prod.h */ + {90,7,r,V,0,0}, /* prod.w */ + {90,8,r,V,0,0}, /* prod.l */ + {35,2,lr,VM,S,0}, /* plc.f */ + {35,1,lr,VM,S,0}, /* plc.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr formatx[] = { + {0,0,0,0,0,0}, +}; + +CONST struct formstr format1a[] = { + {91,0,imr,A,0,0}, /* halt */ + {92,0,a4,0,0,0}, /* sysc */ + {18,6,imr,A,0,0}, /* ld.h */ + {18,7,imr,A,0,0}, /* ld.w */ + {5,0,imr,A,0,0}, /* and */ + {6,0,imr,A,0,0}, /* or */ + {7,0,imr,A,0,0}, /* xor */ + {8,0,imr,A,0,0}, /* shf */ + {9,6,imr,A,0,0}, /* add.h */ + {9,7,imr,A,0,0}, /* add.w */ + {10,6,imr,A,0,0}, /* sub.h */ + {10,7,imr,A,0,0}, /* sub.w */ + {3,6,imr,A,0,0}, /* mul.h */ + {3,7,imr,A,0,0}, /* mul.w */ + {4,6,imr,A,0,0}, /* div.h */ + {4,7,imr,A,0,0}, /* div.w */ + {18,7,iml,VL,0,0}, /* ld.w */ + {18,7,iml,VS,0,0}, /* ld.w */ + {0,0,0,0,0,0}, + {8,7,imr,S,0,0}, /* shf.w */ + {93,0,a5,0,0,0}, /* trap */ + {0,0,0,0,0,0}, + {37,6,imr,A,0,0}, /* eq.h */ + {37,7,imr,A,0,0}, /* eq.w */ + {38,6,imr,A,0,0}, /* leu.h */ + {38,7,imr,A,0,0}, /* leu.w */ + {39,6,imr,A,0,0}, /* ltu.h */ + {39,7,imr,A,0,0}, /* ltu.w */ + {40,6,imr,A,0,0}, /* le.h */ + {40,7,imr,A,0,0}, /* le.w */ + {41,6,imr,A,0,0}, /* lt.h */ + {41,7,imr,A,0,0}, /* lt.w */ +}; + +CONST struct formstr format1b[] = { + {18,4,imr,S,0,0}, /* ld.d */ + {18,10,imr,S,0,0}, /* ld.u */ + {18,8,imr,S,0,0}, /* ld.l */ + {18,7,imr,S,0,0}, /* ld.w */ + {5,0,imr,S,0,0}, /* and */ + {6,0,imr,S,0,0}, /* or */ + {7,0,imr,S,0,0}, /* xor */ + {8,0,imr,S,0,0}, /* shf */ + {9,6,imr,S,0,0}, /* add.h */ + {9,7,imr,S,0,0}, /* add.w */ + {10,6,imr,S,0,0}, /* sub.h */ + {10,7,imr,S,0,0}, /* sub.w */ + {3,6,imr,S,0,0}, /* mul.h */ + {3,7,imr,S,0,0}, /* mul.w */ + {4,6,imr,S,0,0}, /* div.h */ + {4,7,imr,S,0,0}, /* div.w */ + {9,3,imr,S,0,0}, /* add.s */ + {10,3,imr,S,0,0}, /* sub.s */ + {3,3,imr,S,0,0}, /* mul.s */ + {4,3,imr,S,0,0}, /* div.s */ + {40,3,imr,S,0,0}, /* le.s */ + {41,3,imr,S,0,0}, /* lt.s */ + {37,6,imr,S,0,0}, /* eq.h */ + {37,7,imr,S,0,0}, /* eq.w */ + {38,6,imr,S,0,0}, /* leu.h */ + {38,7,imr,S,0,0}, /* leu.w */ + {39,6,imr,S,0,0}, /* ltu.h */ + {39,7,imr,S,0,0}, /* ltu.w */ + {40,6,imr,S,0,0}, /* le.h */ + {40,7,imr,S,0,0}, /* le.w */ + {41,6,imr,S,0,0}, /* lt.h */ + {41,7,imr,S,0,0}, /* lt.w */ +}; + +CONST struct formstr e0_format0[] = { + {10,3,rrr,S,V,V}, /* sub.s */ + {10,4,rrr,S,V,V}, /* sub.d */ + {4,3,rrr,S,V,V}, /* div.s */ + {4,4,rrr,S,V,V}, /* div.d */ + {10,11,rrr,S,V,V}, /* sub.s.f */ + {10,12,rrr,S,V,V}, /* sub.d.f */ + {4,11,rrr,S,V,V}, /* div.s.f */ + {4,12,rrr,S,V,V}, /* div.d.f */ + {3,11,rrr,V,V,V}, /* mul.s.f */ + {3,12,rrr,V,V,V}, /* mul.d.f */ + {4,11,rrr,V,V,V}, /* div.s.f */ + {4,12,rrr,V,V,V}, /* div.d.f */ + {3,11,rrr,V,S,V}, /* mul.s.f */ + {3,12,rrr,V,S,V}, /* mul.d.f */ + {4,11,rrr,V,S,V}, /* div.s.f */ + {4,12,rrr,V,S,V}, /* div.d.f */ + {5,2,rrr,V,V,V}, /* and.f */ + {6,2,rrr,V,V,V}, /* or.f */ + {7,2,rrr,V,V,V}, /* xor.f */ + {8,2,rrr,V,V,V}, /* shf.f */ + {5,2,rrr,V,S,V}, /* and.f */ + {6,2,rrr,V,S,V}, /* or.f */ + {7,2,rrr,V,S,V}, /* xor.f */ + {8,2,rrr,V,S,V}, /* shf.f */ + {9,11,rrr,V,V,V}, /* add.s.f */ + {9,12,rrr,V,V,V}, /* add.d.f */ + {10,11,rrr,V,V,V}, /* sub.s.f */ + {10,12,rrr,V,V,V}, /* sub.d.f */ + {9,11,rrr,V,S,V}, /* add.s.f */ + {9,12,rrr,V,S,V}, /* add.d.f */ + {10,11,rrr,V,S,V}, /* sub.s.f */ + {10,12,rrr,V,S,V}, /* sub.d.f */ + {9,13,rrr,V,V,V}, /* add.b.f */ + {9,14,rrr,V,V,V}, /* add.h.f */ + {9,15,rrr,V,V,V}, /* add.w.f */ + {9,16,rrr,V,V,V}, /* add.l.f */ + {9,13,rrr,V,S,V}, /* add.b.f */ + {9,14,rrr,V,S,V}, /* add.h.f */ + {9,15,rrr,V,S,V}, /* add.w.f */ + {9,16,rrr,V,S,V}, /* add.l.f */ + {10,13,rrr,V,V,V}, /* sub.b.f */ + {10,14,rrr,V,V,V}, /* sub.h.f */ + {10,15,rrr,V,V,V}, /* sub.w.f */ + {10,16,rrr,V,V,V}, /* sub.l.f */ + {10,13,rrr,V,S,V}, /* sub.b.f */ + {10,14,rrr,V,S,V}, /* sub.h.f */ + {10,15,rrr,V,S,V}, /* sub.w.f */ + {10,16,rrr,V,S,V}, /* sub.l.f */ + {3,13,rrr,V,V,V}, /* mul.b.f */ + {3,14,rrr,V,V,V}, /* mul.h.f */ + {3,15,rrr,V,V,V}, /* mul.w.f */ + {3,16,rrr,V,V,V}, /* mul.l.f */ + {3,13,rrr,V,S,V}, /* mul.b.f */ + {3,14,rrr,V,S,V}, /* mul.h.f */ + {3,15,rrr,V,S,V}, /* mul.w.f */ + {3,16,rrr,V,S,V}, /* mul.l.f */ + {4,13,rrr,V,V,V}, /* div.b.f */ + {4,14,rrr,V,V,V}, /* div.h.f */ + {4,15,rrr,V,V,V}, /* div.w.f */ + {4,16,rrr,V,V,V}, /* div.l.f */ + {4,13,rrr,V,S,V}, /* div.b.f */ + {4,14,rrr,V,S,V}, /* div.h.f */ + {4,15,rrr,V,S,V}, /* div.w.f */ + {4,16,rrr,V,S,V}, /* div.l.f */ +}; + +CONST struct formstr e0_format1[] = { + {0,0,0,0,0,0}, + {94,0,a3,0,0,0}, /* tst */ + {95,0,a3,0,0,0}, /* lck */ + {96,0,a3,0,0,0}, /* ulk */ + {17,0,a1r,S,0,0}, /* ldea */ + {97,0,a1r,A,0,0}, /* spawn */ + {98,0,a1r,A,0,0}, /* ldcmr */ + {99,0,a2r,A,0,0}, /* stcmr */ + {100,0,a1r,A,0,0}, /* popr */ + {101,0,a2r,A,0,0}, /* pshr */ + {102,7,a1r,A,0,0}, /* rcvr.w */ + {103,7,a2r,A,0,0}, /* matm.w */ + {104,7,a2r,A,0,0}, /* sndr.w */ + {104,8,a2r,S,0,0}, /* sndr.l */ + {102,8,a1r,S,0,0}, /* rcvr.l */ + {103,8,a2r,S,0,0}, /* matm.l */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {105,7,a2r,A,0,0}, /* putr.w */ + {105,8,a2r,S,0,0}, /* putr.l */ + {106,7,a1r,A,0,0}, /* getr.w */ + {106,8,a1r,S,0,0}, /* getr.l */ + {26,13,a2r,S,0,0}, /* ste.b.f */ + {26,14,a2r,S,0,0}, /* ste.h.f */ + {26,15,a2r,S,0,0}, /* ste.w.f */ + {26,16,a2r,S,0,0}, /* ste.l.f */ + {107,7,a2r,A,0,0}, /* matr.w */ + {108,7,a2r,A,0,0}, /* mat.w */ + {109,7,a1r,A,0,0}, /* get.w */ + {110,7,a1r,A,0,0}, /* rcv.w */ + {0,0,0,0,0,0}, + {111,7,a1r,A,0,0}, /* inc.w */ + {112,7,a2r,A,0,0}, /* put.w */ + {113,7,a2r,A,0,0}, /* snd.w */ + {107,8,a2r,S,0,0}, /* matr.l */ + {108,8,a2r,S,0,0}, /* mat.l */ + {109,8,a1r,S,0,0}, /* get.l */ + {110,8,a1r,S,0,0}, /* rcv.l */ + {0,0,0,0,0,0}, + {111,8,a1r,S,0,0}, /* inc.l */ + {112,8,a2r,S,0,0}, /* put.l */ + {113,8,a2r,S,0,0}, /* snd.l */ + {18,13,a1r,V,0,0}, /* ld.b.f */ + {18,14,a1r,V,0,0}, /* ld.h.f */ + {18,15,a1r,V,0,0}, /* ld.w.f */ + {18,16,a1r,V,0,0}, /* ld.l.f */ + {21,13,a2r,V,0,0}, /* st.b.f */ + {21,14,a2r,V,0,0}, /* st.h.f */ + {21,15,a2r,V,0,0}, /* st.w.f */ + {21,16,a2r,V,0,0}, /* st.l.f */ +}; + +CONST struct formstr e0_format2[] = { + {28,5,rr,V,V,0}, /* cvtw.b */ + {28,6,rr,V,V,0}, /* cvtw.h */ + {29,7,rr,V,V,0}, /* cvtb.w */ + {30,7,rr,V,V,0}, /* cvth.w */ + {28,13,rr,V,V,0}, /* cvtw.b.f */ + {28,14,rr,V,V,0}, /* cvtw.h.f */ + {29,15,rr,V,V,0}, /* cvtb.w.f */ + {30,15,rr,V,V,0}, /* cvth.w.f */ + {31,8,rr,V,V,0}, /* cvts.l */ + {32,7,rr,V,V,0}, /* cvtd.w */ + {33,3,rr,V,V,0}, /* cvtl.s */ + {28,4,rr,V,V,0}, /* cvtw.d */ + {31,16,rr,V,V,0}, /* cvts.l.f */ + {32,15,rr,V,V,0}, /* cvtd.w.f */ + {33,11,rr,V,V,0}, /* cvtl.s.f */ + {28,12,rr,V,V,0}, /* cvtw.d.f */ + {114,0,rr,S,S,0}, /* enal */ + {8,7,rr,S,S,0}, /* shf.w */ + {115,0,rr,S,S,0}, /* enag */ + {0,0,0,0,0,0}, + {28,4,rr,S,S,0}, /* cvtw.d */ + {32,7,rr,S,S,0}, /* cvtd.w */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,S,S,0}, /* frint.s */ + {116,4,rr,S,S,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,3,rr,V,V,0}, /* frint.s */ + {116,4,rr,V,V,0}, /* frint.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,11,rr,V,V,0}, /* frint.s.f */ + {116,12,rr,V,V,0}, /* frint.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,3,rr,V,V,0}, /* sqrt.s */ + {81,4,rr,V,V,0}, /* sqrt.d */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,11,rr,V,V,0}, /* sqrt.s.f */ + {81,12,rr,V,V,0}, /* sqrt.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e0_format3[] = { + {32,11,rr,V,V,0}, /* cvtd.s.f */ + {31,12,rr,V,V,0}, /* cvts.d.f */ + {33,12,rr,V,V,0}, /* cvtl.d.f */ + {32,16,rr,V,V,0}, /* cvtd.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,2,rr,V,V,0}, /* tzc.f */ + {44,2,rr,V,V,0}, /* lop.f */ + {117,2,rr,V,V,0}, /* xpnd.f */ + {42,2,rr,V,V,0}, /* not.f */ + {8,2,rr,S,V,0}, /* shf.f */ + {35,17,rr,V,V,0}, /* plc.t.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,11,rr,V,V,0}, /* eq.s.f */ + {37,12,rr,V,V,0}, /* eq.d.f */ + {43,11,rr,V,V,0}, /* neg.s.f */ + {43,12,rr,V,V,0}, /* neg.d.f */ + {37,11,rr,S,V,0}, /* eq.s.f */ + {37,12,rr,S,V,0}, /* eq.d.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,11,rr,V,V,0}, /* le.s.f */ + {40,12,rr,V,V,0}, /* le.d.f */ + {41,11,rr,V,V,0}, /* lt.s.f */ + {41,12,rr,V,V,0}, /* lt.d.f */ + {40,11,rr,S,V,0}, /* le.s.f */ + {40,12,rr,S,V,0}, /* le.d.f */ + {41,11,rr,S,V,0}, /* lt.s.f */ + {41,12,rr,S,V,0}, /* lt.d.f */ + {37,13,rr,V,V,0}, /* eq.b.f */ + {37,14,rr,V,V,0}, /* eq.h.f */ + {37,15,rr,V,V,0}, /* eq.w.f */ + {37,16,rr,V,V,0}, /* eq.l.f */ + {37,13,rr,S,V,0}, /* eq.b.f */ + {37,14,rr,S,V,0}, /* eq.h.f */ + {37,15,rr,S,V,0}, /* eq.w.f */ + {37,16,rr,S,V,0}, /* eq.l.f */ + {40,13,rr,V,V,0}, /* le.b.f */ + {40,14,rr,V,V,0}, /* le.h.f */ + {40,15,rr,V,V,0}, /* le.w.f */ + {40,16,rr,V,V,0}, /* le.l.f */ + {40,13,rr,S,V,0}, /* le.b.f */ + {40,14,rr,S,V,0}, /* le.h.f */ + {40,15,rr,S,V,0}, /* le.w.f */ + {40,16,rr,S,V,0}, /* le.l.f */ + {41,13,rr,V,V,0}, /* lt.b.f */ + {41,14,rr,V,V,0}, /* lt.h.f */ + {41,15,rr,V,V,0}, /* lt.w.f */ + {41,16,rr,V,V,0}, /* lt.l.f */ + {41,13,rr,S,V,0}, /* lt.b.f */ + {41,14,rr,S,V,0}, /* lt.h.f */ + {41,15,rr,S,V,0}, /* lt.w.f */ + {41,16,rr,S,V,0}, /* lt.l.f */ + {43,13,rr,V,V,0}, /* neg.b.f */ + {43,14,rr,V,V,0}, /* neg.h.f */ + {43,15,rr,V,V,0}, /* neg.w.f */ + {43,16,rr,V,V,0}, /* neg.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e0_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e0_format5[] = { + {51,13,rr,V,V,0}, /* ldvi.b.f */ + {51,14,rr,V,V,0}, /* ldvi.h.f */ + {51,15,rr,V,V,0}, /* ldvi.w.f */ + {51,16,rr,V,V,0}, /* ldvi.l.f */ + {28,11,rr,V,V,0}, /* cvtw.s.f */ + {31,15,rr,V,V,0}, /* cvts.w.f */ + {28,16,rr,V,V,0}, /* cvtw.l.f */ + {33,15,rr,V,V,0}, /* cvtl.w.f */ + {52,13,rxr,V,V,0}, /* stvi.b.f */ + {52,14,rxr,V,V,0}, /* stvi.h.f */ + {52,15,rxr,V,V,0}, /* stvi.w.f */ + {52,16,rxr,V,V,0}, /* stvi.l.f */ + {52,13,rxr,S,V,0}, /* stvi.b.f */ + {52,14,rxr,S,V,0}, /* stvi.h.f */ + {52,15,rxr,S,V,0}, /* stvi.w.f */ + {52,16,rxr,S,V,0}, /* stvi.l.f */ +}; + +CONST struct formstr e0_format6[] = { + {0,0,rxl,S,CIR,0}, /* mov */ + {0,0,lr,CIR,S,0}, /* mov */ + {0,0,lr,TOC,S,0}, /* mov */ + {0,0,lr,CPUID,S,0}, /* mov */ + {0,0,rxl,S,TTR,0}, /* mov */ + {0,0,lr,TTR,S,0}, /* mov */ + {118,0,nops,0,0,0}, /* ctrsl */ + {119,0,nops,0,0,0}, /* ctrsg */ + {0,0,rxl,S,VMU,0}, /* mov */ + {0,0,lr,VMU,S,0}, /* mov */ + {0,0,rxl,S,VML,0}, /* mov */ + {0,0,lr,VML,S,0}, /* mov */ + {0,0,rxl,S,ICR,0}, /* mov */ + {0,0,lr,ICR,S,0}, /* mov */ + {0,0,rxl,S,TCPU,0}, /* mov */ + {0,0,lr,TCPU,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {120,0,nops,0,0,0}, /* stop */ + {0,0,0,0,0,0}, + {0,0,rxl,S,TID,0}, /* mov */ + {0,0,lr,TID,S,0}, /* mov */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e0_format7[] = { + {84,13,r,V,0,0}, /* sum.b.f */ + {84,14,r,V,0,0}, /* sum.h.f */ + {84,15,r,V,0,0}, /* sum.w.f */ + {84,16,r,V,0,0}, /* sum.l.f */ + {85,2,r,V,0,0}, /* all.f */ + {86,2,r,V,0,0}, /* any.f */ + {87,2,r,V,0,0}, /* parity.f */ + {0,0,0,0,0,0}, + {88,13,r,V,0,0}, /* max.b.f */ + {88,14,r,V,0,0}, /* max.h.f */ + {88,15,r,V,0,0}, /* max.w.f */ + {88,16,r,V,0,0}, /* max.l.f */ + {89,13,r,V,0,0}, /* min.b.f */ + {89,14,r,V,0,0}, /* min.h.f */ + {89,15,r,V,0,0}, /* min.w.f */ + {89,16,r,V,0,0}, /* min.l.f */ + {84,11,r,V,0,0}, /* sum.s.f */ + {84,12,r,V,0,0}, /* sum.d.f */ + {90,11,r,V,0,0}, /* prod.s.f */ + {90,12,r,V,0,0}, /* prod.d.f */ + {88,11,r,V,0,0}, /* max.s.f */ + {88,12,r,V,0,0}, /* max.d.f */ + {89,11,r,V,0,0}, /* min.s.f */ + {89,12,r,V,0,0}, /* min.d.f */ + {90,13,r,V,0,0}, /* prod.b.f */ + {90,14,r,V,0,0}, /* prod.h.f */ + {90,15,r,V,0,0}, /* prod.w.f */ + {90,16,r,V,0,0}, /* prod.l.f */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e1_format0[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {10,18,rrr,S,V,V}, /* sub.s.t */ + {10,19,rrr,S,V,V}, /* sub.d.t */ + {4,18,rrr,S,V,V}, /* div.s.t */ + {4,19,rrr,S,V,V}, /* div.d.t */ + {3,18,rrr,V,V,V}, /* mul.s.t */ + {3,19,rrr,V,V,V}, /* mul.d.t */ + {4,18,rrr,V,V,V}, /* div.s.t */ + {4,19,rrr,V,V,V}, /* div.d.t */ + {3,18,rrr,V,S,V}, /* mul.s.t */ + {3,19,rrr,V,S,V}, /* mul.d.t */ + {4,18,rrr,V,S,V}, /* div.s.t */ + {4,19,rrr,V,S,V}, /* div.d.t */ + {5,1,rrr,V,V,V}, /* and.t */ + {6,1,rrr,V,V,V}, /* or.t */ + {7,1,rrr,V,V,V}, /* xor.t */ + {8,1,rrr,V,V,V}, /* shf.t */ + {5,1,rrr,V,S,V}, /* and.t */ + {6,1,rrr,V,S,V}, /* or.t */ + {7,1,rrr,V,S,V}, /* xor.t */ + {8,1,rrr,V,S,V}, /* shf.t */ + {9,18,rrr,V,V,V}, /* add.s.t */ + {9,19,rrr,V,V,V}, /* add.d.t */ + {10,18,rrr,V,V,V}, /* sub.s.t */ + {10,19,rrr,V,V,V}, /* sub.d.t */ + {9,18,rrr,V,S,V}, /* add.s.t */ + {9,19,rrr,V,S,V}, /* add.d.t */ + {10,18,rrr,V,S,V}, /* sub.s.t */ + {10,19,rrr,V,S,V}, /* sub.d.t */ + {9,20,rrr,V,V,V}, /* add.b.t */ + {9,21,rrr,V,V,V}, /* add.h.t */ + {9,22,rrr,V,V,V}, /* add.w.t */ + {9,23,rrr,V,V,V}, /* add.l.t */ + {9,20,rrr,V,S,V}, /* add.b.t */ + {9,21,rrr,V,S,V}, /* add.h.t */ + {9,22,rrr,V,S,V}, /* add.w.t */ + {9,23,rrr,V,S,V}, /* add.l.t */ + {10,20,rrr,V,V,V}, /* sub.b.t */ + {10,21,rrr,V,V,V}, /* sub.h.t */ + {10,22,rrr,V,V,V}, /* sub.w.t */ + {10,23,rrr,V,V,V}, /* sub.l.t */ + {10,20,rrr,V,S,V}, /* sub.b.t */ + {10,21,rrr,V,S,V}, /* sub.h.t */ + {10,22,rrr,V,S,V}, /* sub.w.t */ + {10,23,rrr,V,S,V}, /* sub.l.t */ + {3,20,rrr,V,V,V}, /* mul.b.t */ + {3,21,rrr,V,V,V}, /* mul.h.t */ + {3,22,rrr,V,V,V}, /* mul.w.t */ + {3,23,rrr,V,V,V}, /* mul.l.t */ + {3,20,rrr,V,S,V}, /* mul.b.t */ + {3,21,rrr,V,S,V}, /* mul.h.t */ + {3,22,rrr,V,S,V}, /* mul.w.t */ + {3,23,rrr,V,S,V}, /* mul.l.t */ + {4,20,rrr,V,V,V}, /* div.b.t */ + {4,21,rrr,V,V,V}, /* div.h.t */ + {4,22,rrr,V,V,V}, /* div.w.t */ + {4,23,rrr,V,V,V}, /* div.l.t */ + {4,20,rrr,V,S,V}, /* div.b.t */ + {4,21,rrr,V,S,V}, /* div.h.t */ + {4,22,rrr,V,S,V}, /* div.w.t */ + {4,23,rrr,V,S,V}, /* div.l.t */ +}; + +CONST struct formstr e1_format1[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {26,20,a2r,S,0,0}, /* ste.b.t */ + {26,21,a2r,S,0,0}, /* ste.h.t */ + {26,22,a2r,S,0,0}, /* ste.w.t */ + {26,23,a2r,S,0,0}, /* ste.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {18,20,a1r,V,0,0}, /* ld.b.t */ + {18,21,a1r,V,0,0}, /* ld.h.t */ + {18,22,a1r,V,0,0}, /* ld.w.t */ + {18,23,a1r,V,0,0}, /* ld.l.t */ + {21,20,a2r,V,0,0}, /* st.b.t */ + {21,21,a2r,V,0,0}, /* st.h.t */ + {21,22,a2r,V,0,0}, /* st.w.t */ + {21,23,a2r,V,0,0}, /* st.l.t */ +}; + +CONST struct formstr e1_format2[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {28,20,rr,V,V,0}, /* cvtw.b.t */ + {28,21,rr,V,V,0}, /* cvtw.h.t */ + {29,22,rr,V,V,0}, /* cvtb.w.t */ + {30,22,rr,V,V,0}, /* cvth.w.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {31,23,rr,V,V,0}, /* cvts.l.t */ + {32,22,rr,V,V,0}, /* cvtd.w.t */ + {33,18,rr,V,V,0}, /* cvtl.s.t */ + {28,19,rr,V,V,0}, /* cvtw.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {116,18,rr,V,V,0}, /* frint.s.t */ + {116,19,rr,V,V,0}, /* frint.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {81,18,rr,V,V,0}, /* sqrt.s.t */ + {81,19,rr,V,V,0}, /* sqrt.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e1_format3[] = { + {32,18,rr,V,V,0}, /* cvtd.s.t */ + {31,19,rr,V,V,0}, /* cvts.d.t */ + {33,19,rr,V,V,0}, /* cvtl.d.t */ + {32,23,rr,V,V,0}, /* cvtd.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {36,1,rr,V,V,0}, /* tzc.t */ + {44,1,rr,V,V,0}, /* lop.t */ + {117,1,rr,V,V,0}, /* xpnd.t */ + {42,1,rr,V,V,0}, /* not.t */ + {8,1,rr,S,V,0}, /* shf.t */ + {35,24,rr,V,V,0}, /* plc.t.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {37,18,rr,V,V,0}, /* eq.s.t */ + {37,19,rr,V,V,0}, /* eq.d.t */ + {43,18,rr,V,V,0}, /* neg.s.t */ + {43,19,rr,V,V,0}, /* neg.d.t */ + {37,18,rr,S,V,0}, /* eq.s.t */ + {37,19,rr,S,V,0}, /* eq.d.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {40,18,rr,V,V,0}, /* le.s.t */ + {40,19,rr,V,V,0}, /* le.d.t */ + {41,18,rr,V,V,0}, /* lt.s.t */ + {41,19,rr,V,V,0}, /* lt.d.t */ + {40,18,rr,S,V,0}, /* le.s.t */ + {40,19,rr,S,V,0}, /* le.d.t */ + {41,18,rr,S,V,0}, /* lt.s.t */ + {41,19,rr,S,V,0}, /* lt.d.t */ + {37,20,rr,V,V,0}, /* eq.b.t */ + {37,21,rr,V,V,0}, /* eq.h.t */ + {37,22,rr,V,V,0}, /* eq.w.t */ + {37,23,rr,V,V,0}, /* eq.l.t */ + {37,20,rr,S,V,0}, /* eq.b.t */ + {37,21,rr,S,V,0}, /* eq.h.t */ + {37,22,rr,S,V,0}, /* eq.w.t */ + {37,23,rr,S,V,0}, /* eq.l.t */ + {40,20,rr,V,V,0}, /* le.b.t */ + {40,21,rr,V,V,0}, /* le.h.t */ + {40,22,rr,V,V,0}, /* le.w.t */ + {40,23,rr,V,V,0}, /* le.l.t */ + {40,20,rr,S,V,0}, /* le.b.t */ + {40,21,rr,S,V,0}, /* le.h.t */ + {40,22,rr,S,V,0}, /* le.w.t */ + {40,23,rr,S,V,0}, /* le.l.t */ + {41,20,rr,V,V,0}, /* lt.b.t */ + {41,21,rr,V,V,0}, /* lt.h.t */ + {41,22,rr,V,V,0}, /* lt.w.t */ + {41,23,rr,V,V,0}, /* lt.l.t */ + {41,20,rr,S,V,0}, /* lt.b.t */ + {41,21,rr,S,V,0}, /* lt.h.t */ + {41,22,rr,S,V,0}, /* lt.w.t */ + {41,23,rr,S,V,0}, /* lt.l.t */ + {43,20,rr,V,V,0}, /* neg.b.t */ + {43,21,rr,V,V,0}, /* neg.h.t */ + {43,22,rr,V,V,0}, /* neg.w.t */ + {43,23,rr,V,V,0}, /* neg.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e1_format4[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e1_format5[] = { + {51,20,rr,V,V,0}, /* ldvi.b.t */ + {51,21,rr,V,V,0}, /* ldvi.h.t */ + {51,22,rr,V,V,0}, /* ldvi.w.t */ + {51,23,rr,V,V,0}, /* ldvi.l.t */ + {28,18,rr,V,V,0}, /* cvtw.s.t */ + {31,22,rr,V,V,0}, /* cvts.w.t */ + {28,23,rr,V,V,0}, /* cvtw.l.t */ + {33,22,rr,V,V,0}, /* cvtl.w.t */ + {52,20,rxr,V,V,0}, /* stvi.b.t */ + {52,21,rxr,V,V,0}, /* stvi.h.t */ + {52,22,rxr,V,V,0}, /* stvi.w.t */ + {52,23,rxr,V,V,0}, /* stvi.l.t */ + {52,20,rxr,S,V,0}, /* stvi.b.t */ + {52,21,rxr,S,V,0}, /* stvi.h.t */ + {52,22,rxr,S,V,0}, /* stvi.w.t */ + {52,23,rxr,S,V,0}, /* stvi.l.t */ +}; + +CONST struct formstr e1_format6[] = { + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +CONST struct formstr e1_format7[] = { + {84,20,r,V,0,0}, /* sum.b.t */ + {84,21,r,V,0,0}, /* sum.h.t */ + {84,22,r,V,0,0}, /* sum.w.t */ + {84,23,r,V,0,0}, /* sum.l.t */ + {85,1,r,V,0,0}, /* all.t */ + {86,1,r,V,0,0}, /* any.t */ + {87,1,r,V,0,0}, /* parity.t */ + {0,0,0,0,0,0}, + {88,20,r,V,0,0}, /* max.b.t */ + {88,21,r,V,0,0}, /* max.h.t */ + {88,22,r,V,0,0}, /* max.w.t */ + {88,23,r,V,0,0}, /* max.l.t */ + {89,20,r,V,0,0}, /* min.b.t */ + {89,21,r,V,0,0}, /* min.h.t */ + {89,22,r,V,0,0}, /* min.w.t */ + {89,23,r,V,0,0}, /* min.l.t */ + {84,18,r,V,0,0}, /* sum.s.t */ + {84,19,r,V,0,0}, /* sum.d.t */ + {90,18,r,V,0,0}, /* prod.s.t */ + {90,19,r,V,0,0}, /* prod.d.t */ + {88,18,r,V,0,0}, /* max.s.t */ + {88,19,r,V,0,0}, /* max.d.t */ + {89,18,r,V,0,0}, /* min.s.t */ + {89,19,r,V,0,0}, /* min.d.t */ + {90,20,r,V,0,0}, /* prod.b.t */ + {90,21,r,V,0,0}, /* prod.h.t */ + {90,22,r,V,0,0}, /* prod.w.t */ + {90,23,r,V,0,0}, /* prod.l.t */ + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, + {0,0,0,0,0,0}, +}; + +char *lop[] = { + "mov", /* 0 */ + "merg", /* 1 */ + "mask", /* 2 */ + "mul", /* 3 */ + "div", /* 4 */ + "and", /* 5 */ + "or", /* 6 */ + "xor", /* 7 */ + "shf", /* 8 */ + "add", /* 9 */ + "sub", /* 10 */ + "exit", /* 11 */ + "jmp", /* 12 */ + "jmpi", /* 13 */ + "jmpa", /* 14 */ + "jmps", /* 15 */ + "tac", /* 16 */ + "ldea", /* 17 */ + "ld", /* 18 */ + "tas", /* 19 */ + "pshea", /* 20 */ + "st", /* 21 */ + "call", /* 22 */ + "calls", /* 23 */ + "callq", /* 24 */ + "pfork", /* 25 */ + "ste", /* 26 */ + "incr", /* 27 */ + "cvtw", /* 28 */ + "cvtb", /* 29 */ + "cvth", /* 30 */ + "cvts", /* 31 */ + "cvtd", /* 32 */ + "cvtl", /* 33 */ + "ldpa", /* 34 */ + "plc", /* 35 */ + "tzc", /* 36 */ + "eq", /* 37 */ + "leu", /* 38 */ + "ltu", /* 39 */ + "le", /* 40 */ + "lt", /* 41 */ + "not", /* 42 */ + "neg", /* 43 */ + "lop", /* 44 */ + "cprs", /* 45 */ + "nop", /* 46 */ + "br", /* 47 */ + "bri", /* 48 */ + "bra", /* 49 */ + "brs", /* 50 */ + "ldvi", /* 51 */ + "stvi", /* 52 */ + "ldsdr", /* 53 */ + "ldkdr", /* 54 */ + "ln", /* 55 */ + "patu", /* 56 */ + "pate", /* 57 */ + "pich", /* 58 */ + "plch", /* 59 */ + "idle", /* 60 */ + "rtnq", /* 61 */ + "cfork", /* 62 */ + "rtn", /* 63 */ + "wfork", /* 64 */ + "join", /* 65 */ + "rtnc", /* 66 */ + "exp", /* 67 */ + "sin", /* 68 */ + "cos", /* 69 */ + "psh", /* 70 */ + "pop", /* 71 */ + "eni", /* 72 */ + "dsi", /* 73 */ + "bkpt", /* 74 */ + "msync", /* 75 */ + "mski", /* 76 */ + "xmti", /* 77 */ + "tstvv", /* 78 */ + "diag", /* 79 */ + "pbkpt", /* 80 */ + "sqrt", /* 81 */ + "casr", /* 82 */ + "atan", /* 83 */ + "sum", /* 84 */ + "all", /* 85 */ + "any", /* 86 */ + "parity", /* 87 */ + "max", /* 88 */ + "min", /* 89 */ + "prod", /* 90 */ + "halt", /* 91 */ + "sysc", /* 92 */ + "trap", /* 93 */ + "tst", /* 94 */ + "lck", /* 95 */ + "ulk", /* 96 */ + "spawn", /* 97 */ + "ldcmr", /* 98 */ + "stcmr", /* 99 */ + "popr", /* 100 */ + "pshr", /* 101 */ + "rcvr", /* 102 */ + "matm", /* 103 */ + "sndr", /* 104 */ + "putr", /* 105 */ + "getr", /* 106 */ + "matr", /* 107 */ + "mat", /* 108 */ + "get", /* 109 */ + "rcv", /* 110 */ + "inc", /* 111 */ + "put", /* 112 */ + "snd", /* 113 */ + "enal", /* 114 */ + "enag", /* 115 */ + "frint", /* 116 */ + "xpnd", /* 117 */ + "ctrsl", /* 118 */ + "ctrsg", /* 119 */ + "stop", /* 120 */ +}; + +char *rop[] = { + "", /* 0 */ + ".t", /* 1 */ + ".f", /* 2 */ + ".s", /* 3 */ + ".d", /* 4 */ + ".b", /* 5 */ + ".h", /* 6 */ + ".w", /* 7 */ + ".l", /* 8 */ + ".x", /* 9 */ + ".u", /* 10 */ + ".s.f", /* 11 */ + ".d.f", /* 12 */ + ".b.f", /* 13 */ + ".h.f", /* 14 */ + ".w.f", /* 15 */ + ".l.f", /* 16 */ + ".t.f", /* 17 */ + ".s.t", /* 18 */ + ".d.t", /* 19 */ + ".b.t", /* 20 */ + ".h.t", /* 21 */ + ".w.t", /* 22 */ + ".l.t", /* 23 */ + ".t.t", /* 24 */ +}; diff --git a/contrib/gdb/include/opcode/h8300.h b/contrib/gdb/include/opcode/h8300.h new file mode 100644 index 000000000000..9d726e2e38e6 --- /dev/null +++ b/contrib/gdb/include/opcode/h8300.h @@ -0,0 +1,550 @@ +/* Opcode table for the H8-300 + Copyright (C) 1991,1992 Free Software Foundation. + Written by Steve Chamberlain, sac@cygnus.com. + + This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Instructions are stored as a sequence of nibbles. + If the nibble has value 15 or less then the representation is complete. + Otherwise, we record what it contains with several flags. */ + +typedef int op_type; + +#define Hex0 0 +#define Hex1 1 +#define Hex2 2 +#define Hex3 3 +#define Hex4 4 +#define Hex5 5 +#define Hex6 6 +#define Hex7 7 +#define Hex8 8 +#define Hex9 9 +#define HexA 10 +#define HexB 11 +#define HexC 12 +#define HexD 13 +#define HexE 14 +#define HexF 15 + +#define START 0x20 +#define SRC 0x40 +#define DST 0x80 +#define L_8 0x01 +#define L_16 0x02 +#define L_32 0x04 +#define L_P 0x08 +#define L_24 0x10 + +#define REG 0x100 +#define IMM 0x1000 +#define DISP 0x2000 +#define IND 0x4000 +#define INC 0x8000 +#define DEC 0x10000 +#define L_3 0x20000 +#define KBIT 0x40000 +#define DBIT 0x80000 +#define DISPREG 0x100000 +#define IGNORE 0x200000 +#define E 0x400000 /* FIXME: end of nibble sequence? */ +#define L_2 0x800000 +#define CCR 0x4000000 +#define ABS 0x8000000 +#define B30 0x1000000 /* bit 3 must be low */ +#define B31 0x2000000 /* bit 3 must be high */ +#define ABSJMP 0x10000000 +#define ABSMOV 0x20000000 +#define PCREL 0x40000000 +#define MEMIND 0x80000000 + +#define IMM3 IMM|L_3 +#define IMM2 IMM|L_2 + +#define SIZE (L_2|L_3|L_8|L_16|L_32|L_P|L_24) +#define MODE (REG|IMM|DISP|IND|INC|DEC|CCR|ABS|MEMIND) + +#define RD8 (DST|L_8|REG) +#define RD16 (DST|L_16|REG) +#define RD32 (DST|L_32|REG) +#define RS8 (SRC|L_8|REG) +#define RS16 (SRC|L_16|REG) +#define RS32 (SRC|L_32|REG) + +#define RSP (SRC|L_P|REG) +#define RDP (DST|L_P|REG) + +#define IMM8 (IMM|SRC|L_8) +#define IMM16 (IMM|SRC|L_16) +#define IMM32 (IMM|SRC|L_32) + +#define ABS8SRC (SRC|ABS|L_8) +#define ABS8DST (DST|ABS|L_8) + +#define DISP8 (PCREL|L_8) +#define DISP16 (PCREL|L_16) + +#define DISP8SRC (DISP|L_8|SRC) +#define DISP16SRC (DISP|L_16|SRC) + +#define DISP8DST (DISP|L_8|DST) +#define DISP16DST (DISP|L_16|DST) + +#define ABS16SRC (SRC|ABS|L_16) +#define ABS16DST (DST|ABS|L_16) +#define ABS24SRC (SRC|ABS|L_24) +#define ABS24DST (DST|ABS|L_24) + +#define RDDEC (DST|DEC) +#define RSINC (SRC|INC) + +#define RDIND (DST|IND) +#define RSIND (SRC|IND) + +#if 1 +#define OR8 RS8 /* ??? OR as in One Register? */ +#define OR16 RS16 +#define OR32 RS32 +#else +#define OR8 RD8 +#define OR16 RD16 +#define OR32 RD32 +#endif + +struct code +{ + op_type nib[30]; +}; + +struct arg +{ + op_type nib[3]; +}; + +struct h8_opcode +{ + int how; + int inbase; + int time; + char *name; + struct arg args; + struct code data; + int length; + int noperands; + int idx; + int size; +}; + +#ifdef DEFINE_TABLE + +#define BITOP(code, imm, name, op00, op01,op10,op11, op20,op21)\ +{ code, 1, 2, name, {imm,RD8,E}, {op00, op01, imm, RD8, E, 0, 0, 0, 0}, 0, 0, 0, 0},\ +{ code, 1, 6, name, {imm,RDIND,E}, {op10, op11, B30|RDIND, 0, op00,op01, imm, 0, E}, 0, 0, 0, 0},\ +{ code, 1, 6, name, {imm,ABS8DST,E},{op20, op21, ABS8DST, IGNORE, op00,op01, imm, 0,E}, 0, 0, 0, 0} + +#define EBITOP(code, imm, name, op00, op01,op10,op11, op20,op21)\ + BITOP(code,imm, name, op00+1, op01, op10,op11, op20,op21),\ + BITOP(code,RS8, name, op00, op01, op10,op11, op20,op21) + +#define WTWOP(code,name, op1, op2) \ +{ code, 1, 2, name, {RS16, RD16, E}, { op1, op2, RS16, RD16, E, 0, 0, 0, 0}, 0, 0, 0, 0} + +#define BRANCH(code, name, op) \ +{ code, 1, 4,name,{DISP8,E,0}, { 0x4, op, DISP8, IGNORE, E, 0, 0, 0, 0}, 0, 0, 0, 0}, \ +{ code, 0, 6,name,{DISP16,E,0}, { 0x5, 0x8, op, 0x0, DISP16, IGNORE, IGNORE, IGNORE, E,0}, 0, 0, 0, 0} + +#define SOP(code, x,name) \ +{code, 1, x, name + +#define NEW_SOP(code, in,x,name) \ +{code, in, x, name +#define EOP ,0,0,0 } + +#define TWOOP(code, name, op1, op2,op3) \ +{ code,1, 2,name, {IMM8, RD8, E}, { op1, RD8, IMM8, IGNORE, E, 0, 0, 0, 0}, 0, 0, 0, 0},\ +{ code, 1, 2,name, {RS8, RD8, E}, { op2, op3, RS8, RD8, E, 0, 0, 0, 0}, 0, 0, 0, 0} + +#define UNOP(code,name, op1, op2) \ +{ code, 1, 2, name, {OR8, E, 0}, { op1, op2, 0, OR8, E, 0, 0, 0, 0}, 0, 0, 0, 0} + +#define UNOP3(code, name, op1, op2, op3) \ +{ O(code,SB), 1, 2, name, {OR8, E, 0}, {op1, op2, op3+0, OR8, E, 0, 0, 0, 0}, 0, 0, 0, 0}, \ +{ O(code,SW), 0, 2, name, {OR16, E, 0}, {op1, op2, op3+1, OR16, E, 0, 0, 0, 0}, 0, 0, 0, 0}, \ +{ O(code,SL), 0, 2, name, {OR32, E, 0}, {op1, op2, op3+3, OR32|B30, E, 0, 0, 0, 0}, 0, 0, 0, 0} + +#define IMM32LIST IMM32,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE +#define IMM24LIST IMM24,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE +#define IMM16LIST IMM16,IGNORE,IGNORE,IGNORE +#define A16LIST L_16,IGNORE,IGNORE,IGNORE +#define DISP24LIST DISP|L_24,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE +#define ABS24LIST ABS|L_24,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE +#define A24LIST L_24,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE +#define PREFIX32 0x0,0x1,0x0,0x0 +#define PREFIXLDC 0x0,0x1,0x4,0x0 + + +#define O(op, size) (op*4+size) + +#define O_RECOMPILE 0 +#define O_ADD 1 +#define O_ADDX 2 +#define O_AND 3 +#define O_BAND 4 +#define O_BRA 5 +#define O_BRN 6 +#define O_BHI 7 +#define O_BLS 8 +#define O_BCC 9 +#define O_BCS 10 +#define O_BNE 11 +#define O_BVC 12 +#define O_BVS 13 +#define O_BPL 14 +#define O_BMI 15 +#define O_BGE 16 +#define O_BLT 17 +#define O_BGT 18 +#define O_BLE 19 +#define O_ANDC 20 +#define O_BEQ 21 +#define O_BCLR 22 +#define O_BIAND 23 +#define O_BILD 24 +#define O_BIOR 25 +#define O_BIXOR 26 +#define O_BIST 27 +#define O_BLD 28 +#define O_BNOT 29 +#define O_BSET 30 +#define O_BSR 31 +#define O_BXOR 32 +#define O_CMP 33 +#define O_DAA 34 +#define O_DAS 35 +#define O_DEC 36 +#define O_DIVU 37 +#define O_DIVS 38 +#define O_INC 39 +#define O_LDC 40 +#define O_MOV_TO_MEM 41 +#define O_OR 42 +#define O_ROTL 43 +#define O_ROTR 44 +#define O_ROTXL 45 +#define O_ROTXR 46 +#define O_BPT 47 +#define O_SHAL 48 +#define O_SHAR 49 +#define O_SHLL 50 +#define O_SHLR 51 +#define O_SUB 52 +#define O_SUBS 53 +#define O_TRAPA 54 +#define O_XOR 55 +#define O_XORC 56 +#define O_BOR 57 +#define O_BST 58 +#define O_BTST 59 +#define O_EEPMOV 60 +#define O_EXTS 61 +#define O_EXTU 62 +#define O_JMP 63 +#define O_JSR 64 +#define O_MULU 65 +#define O_MULS 66 +#define O_NOP 67 +#define O_NOT 68 +#define O_ORC 69 +#define O_RTE 70 +#define O_STC 71 +#define O_SUBX 72 +#define O_NEG 73 +#define O_RTS 74 +#define O_SLEEP 75 +#define O_ILL 76 +#define O_ADDS 77 +#define O_SYSCALL 78 +#define O_MOV_TO_REG 79 +#define O_LAST 80 +#define SB 0 +#define SW 1 +#define SL 2 + + +/* FIXME: Lots of insns have "E, 0, 0, 0, 0" in the nibble code sequences. + Methinks the zeroes aren't necessary. Once confirmed, nuke 'em. */ + +struct h8_opcode h8_opcodes[] = +{ + TWOOP(O(O_ADD,SB),"add.b", 0x8, 0x0,0x8), + + NEW_SOP(O(O_ADD,SW),1,2,"add.w"),{RS16,RD16,E },{0x0,0x9,RS16,RD16,E} EOP, + NEW_SOP(O(O_ADD,SW),0,4,"add.w"),{IMM16,RD16,E },{0x7,0x9,0x1,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + NEW_SOP(O(O_ADD,SL),0,2,"add.l"),{RS32,RD32,E }, {0x0,0xA,B31|RS32,B30|RD32,E} EOP, + NEW_SOP(O(O_ADD,SL),0,6,"add.l"),{IMM32,RD32,E },{0x7,0xA,0x1,B30|RD32,IMM32LIST,E} EOP, + NEW_SOP(O(O_ADDS,SL),1,2,"adds"), {KBIT,RDP,E}, {0x0,0xB,KBIT,RDP,E,0,0,0,0} EOP, + + TWOOP(O(O_ADDX,SB),"addx",0x9,0x0,0xE), + TWOOP(O(O_AND,SB), "and.b",0xE,0x1,0x6), + + NEW_SOP(O(O_AND,SW),0,2,"and.w"),{RS16,RD16,E },{0x6,0x6,RS16,RD16,E} EOP, + NEW_SOP(O(O_AND,SW),0,4,"and.w"),{IMM16,RD16,E },{0x7,0x9,0x6,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + + NEW_SOP(O(O_AND,SL),0,6,"and.l"),{IMM32,RD32,E },{0x7,0xA,0x6,B30|RD32,IMM32LIST,E} EOP, + NEW_SOP(O(O_AND,SL),0,2,"and.l") ,{RS32,RD32,E },{0x0,0x1,0xF,0x0,0x6,0x6,B30|RS32,B30|RD32,E} EOP, + + NEW_SOP(O(O_ANDC,SB),1,2,"andc"), {IMM8,CCR,E},{ 0x0,0x6,IMM8,IGNORE,E,0,0,0,0} EOP, + + BITOP(O(O_BAND,SB), IMM3,"band",0x7,0x6,0x7,0xC,0x7,0xE), + BRANCH(O(O_BRA,SB),"bra",0x0), + BRANCH(O(O_BRA,SB),"bt",0x0), + BRANCH(O(O_BRN,SB),"brn",0x1), + BRANCH(O(O_BRN,SB),"bf",0x1), + BRANCH(O(O_BHI,SB),"bhi",0x2), + BRANCH(O(O_BLS,SB),"bls",0x3), + BRANCH(O(O_BCC,SB),"bcc",0x4), + BRANCH(O(O_BCC,SB),"bhs",0x4), + BRANCH(O(O_BCS,SB),"bcs",0x5), + BRANCH(O(O_BCS,SB),"blo",0x5), + BRANCH(O(O_BNE,SB),"bne",0x6), + BRANCH(O(O_BEQ,SB),"beq",0x7), + BRANCH(O(O_BVC,SB),"bvc",0x8), + BRANCH(O(O_BVS,SB),"bvs",0x9), + BRANCH(O(O_BPL,SB),"bpl",0xA), + BRANCH(O(O_BMI,SB),"bmi",0xB), + BRANCH(O(O_BGE,SB),"bge",0xC), + BRANCH(O(O_BLT,SB),"blt",0xD), + BRANCH(O(O_BGT,SB),"bgt",0xE), + BRANCH(O(O_BLE,SB),"ble",0xF), + + EBITOP(O(O_BCLR,SB),IMM3, "bclr", 0x6,0x2,0x7,0xD,0x7,0xF), + BITOP(O(O_BIAND,SB),IMM3|B31,"biand",0x7,0x6,0x7,0xC,0x7,0xE), + BITOP(O(O_BILD,SB), IMM3|B31,"bild", 0x7,0x7,0x7,0xC,0x7,0xE), + BITOP(O(O_BIOR,SB), IMM3|B31,"bior", 0x7,0x4,0x7,0xC,0x7,0xE), + BITOP(O(O_BIST,SB), IMM3|B31,"bist", 0x6,0x7,0x7,0xD,0x7,0xF), + BITOP(O(O_BIXOR,SB),IMM3|B31,"bixor",0x7,0x5,0x7,0xC,0x7,0xE), + BITOP(O(O_BLD,SB), IMM3|B30,"bld", 0x7,0x7,0x7,0xC,0x7,0xE), + EBITOP(O(O_BNOT,SB),IMM3|B30,"bnot", 0x6,0x1,0x7,0xD,0x7,0xF), + BITOP(O(O_BOR,SB), IMM3|B30,"bor", 0x7,0x4,0x7,0xC,0x7,0xE), + EBITOP(O(O_BSET,SB),IMM3|B30,"bset", 0x6,0x0,0x7,0xD,0x7,0xF), + + SOP(O(O_BSR,SB),6,"bsr"),{DISP8,E,0},{ 0x5,0x5,DISP8,IGNORE,E,0,0,0,0} EOP, + SOP(O(O_BSR,SB),6,"bsr"),{DISP16,E,0},{ 0x5,0xC,0x0,0x0,DISP16,IGNORE,IGNORE,IGNORE,E,0,0,0,0} EOP, + BITOP(O(O_BST,SB), IMM3|B30,"bst",0x6,0x7,0x7,0xD,0x7,0xF), + EBITOP(O(O_BTST,SB), IMM3|B30,"btst",0x6,0x3,0x7,0xC,0x7,0xE), + BITOP(O(O_BXOR,SB), IMM3|B30,"bxor",0x7,0x5,0x7,0xC,0x7,0xE), + + TWOOP(O(O_CMP,SB), "cmp.b",0xA,0x1,0xC), + WTWOP(O(O_CMP,SW), "cmp.w",0x1,0xD), + + NEW_SOP(O(O_CMP,SW),1,2,"cmp.w"),{RS16,RD16,E },{0x1,0xD,RS16,RD16,E} EOP, + NEW_SOP(O(O_CMP,SW),0,4,"cmp.w"),{IMM16,RD16,E },{0x7,0x9,0x2,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + + NEW_SOP(O(O_CMP,SL),0,6,"cmp.l"),{IMM32,RD32,E },{0x7,0xA,0x2,B30|RD32,IMM32LIST,E} EOP, + NEW_SOP(O(O_CMP,SL),0,2,"cmp.l") ,{RS32,RD32,E },{0x1,0xF,B31|RS32,B30|RD32,E} EOP, + + UNOP(O(O_DAA,SB), "daa",0x0,0xF), + UNOP(O(O_DAS,SB), "das",0x1,0xF), + UNOP(O(O_DEC,SB), "dec.b",0x1,0xA), + + NEW_SOP(O(O_DEC, SW),0,2,"dec.w") ,{DBIT,RD16,E },{0x1,0xB,0x5|DBIT,RD16,E} EOP, + NEW_SOP(O(O_DEC, SL),0,2,"dec.l") ,{DBIT,RD32,E },{0x1,0xB,0x7|DBIT,RD32|B30,E} EOP, + + NEW_SOP(O(O_DIVU,SB),1,6,"divxu.b"), {RS8,RD16,E}, {0x5,0x1,RS8,RD16,E,0,0,0,0}EOP, + NEW_SOP(O(O_DIVU,SW),0,20,"divxu.w"),{RS16,RD32,E},{0x5,0x3,RS16,B30|RD32,E}EOP, + + NEW_SOP(O(O_DIVS,SB),0,20,"divxs.b") ,{RS8,RD16,E },{0x0,0x1,0xD,0x0,0x5,0x1,RS8,RD16,E} EOP, + NEW_SOP(O(O_DIVS,SW),0,02,"divxs.w") ,{RS16,RD32,E },{0x0,0x1,0xD,0x0,0x5,0x3,RS16,B30|RD32,E} EOP, + + NEW_SOP(O(O_EEPMOV,SB),1,50,"eepmov"),{ E,0,0},{0x7,0xB,0x5,0xC,0x5,0x9,0x8,0xF,E}EOP, + NEW_SOP(O(O_EEPMOV,SW),0,50,"eepmovw"),{E,0,0},{0x7,0xB,0xD,0x4,0x5,0x9,0x8,0xF,E} EOP, + + NEW_SOP(O(O_EXTS,SW),0,2,"exts.w"),{OR16,E,0},{0x1,0x7,0xD,OR16,E }EOP, + NEW_SOP(O(O_EXTS,SL),0,2,"exts.l"),{OR32,E,0},{0x1,0x7,0xF,OR32|B30,E }EOP, + + NEW_SOP(O(O_EXTU,SW),0,2,"extu.w"),{OR16,E,0},{0x1,0x7,0x5,OR16,E }EOP, + NEW_SOP(O(O_EXTU,SL),0,2,"extu.l"),{OR32,E,0},{0x1,0x7,0x7,OR32|B30,E }EOP, + + UNOP(O(O_INC,SB), "inc",0x0,0xA), + + NEW_SOP(O(O_INC,SW),0,2,"inc.w") ,{DBIT,RD16,E },{0x0,0xB,0x5|DBIT,RD16,E} EOP, + NEW_SOP(O(O_INC,SL),0,2,"inc.l") ,{DBIT,RD32,E },{0x0,0xB,0x7|DBIT,RD32|B30,E} EOP, + + SOP(O(O_JMP,SB),4,"jmp"),{RSIND,E,0},{0x5,0x9,B30|RSIND,0x0,E,0,0,0,0}EOP, + SOP(O(O_JMP,SB),6,"jmp"),{SRC|ABSJMP,E,0},{0x5,0xA,SRC|ABSJMP,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_JMP,SB),8,"jmp"),{SRC|MEMIND,E,0},{0x5,0xB,SRC|MEMIND,IGNORE,E,0,0,0,0}EOP, + + SOP(O(O_JSR,SB),6,"jsr"),{SRC|RSIND,E,0}, {0x5,0xD,B30|RSIND,0x0,E,0,0,0,0}EOP, + SOP(O(O_JSR,SB),8,"jsr"),{SRC|ABSJMP,E,0},{0x5,0xE,SRC|ABSJMP,IGNORE,IGNORE,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_JSR,SB),8,"jsr"),{SRC|MEMIND,E,0},{0x5,0xF,SRC|MEMIND,IGNORE,E,0,0,0,0}EOP, + + NEW_SOP(O(O_LDC,SB),1,2,"ldc"),{IMM8,CCR,E}, { 0x0,0x7,IMM8,IGNORE,E,0,0,0,0}EOP, + NEW_SOP(O(O_LDC,SB),1,2,"ldc"),{OR8,CCR,E}, { 0x0,0x3,0x0,OR8,E,0,0,0,0}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{ABS16SRC,CCR,E}, {PREFIXLDC,0x6,0xB,0x0,0x0,ABS16SRC,IGNORE,IGNORE,IGNORE,E}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{ABS24SRC,CCR,E}, {PREFIXLDC,0x6,0xB,0x2,0x0,0x0,0x0,SRC|ABS24LIST,E}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{DISP|SRC|L_16,CCR,E},{PREFIXLDC,0x6,0x9,B30|DISPREG,0,DISP|L_16,IGNORE,IGNORE,IGNORE,E}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{DISP|SRC|L_24,CCR,E},{PREFIXLDC,0x7,0x8,B30|DISPREG,0,0x6,0xB,0x2,0x0,0x0,0x0,SRC|DISP24LIST,E}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{RSINC,CCR,E}, {PREFIXLDC,0x6,0xD,B30|RSINC,0x0,E}EOP, + NEW_SOP(O(O_LDC,SB),0,2,"ldc"),{RSIND,CCR,E}, {PREFIXLDC,0x6,0x9,B30|RDIND,0x0,E} EOP, + + + SOP(O(O_MOV_TO_REG,SB),4,"mov.b"),{ABSMOV|ABS|SRC|L_16,RD8,E}, { 0x6,0xA,0x0,RD8,ABSMOV|SRC|ABS|A16LIST,E}EOP, + SOP(O(O_MOV_TO_REG,SB),6,"mov.b"),{ABSMOV|ABS|SRC|L_24,RD8,E }, { 0x6,0xA,0x2,RD8,0x0,0x0,SRC|ABSMOV|ABS|A24LIST,E }EOP, + SOP(O(O_MOV_TO_MEM,SB),4,"mov.b"),{RS8,ABSMOV|ABS|L_16|DST,E}, { 0x6,0xA,0x8,RS8,ABSMOV|DST|ABS|A16LIST,E}EOP, + SOP(O(O_MOV_TO_MEM,SB),6,"mov.b"),{RS8,ABSMOV|ABS|DST|L_24,E }, { 0x6,0xA,0xA,RS8,0x0,0x0,DST|ABSMOV|ABS|A24LIST,E }EOP, + + SOP(O(O_MOV_TO_REG,SB),6,"mov.b"),{DISP|L_24|SRC,RD8,E}, { 0x7,0x8,B30|DISPREG,0x0,0x6,0xA,0x2,RD8,0x0,0x0,SRC|DISP24LIST,E}EOP, + SOP(O(O_MOV_TO_MEM,SB),6,"mov.b"),{RS8,DISP|L_24|DST,E}, { 0x7,0x8,B30|DISPREG,0x0,0x6,0xA,0xA,RS8,0x0,0x0,DST|DISP24LIST,E}EOP, + + + + SOP(O(O_MOV_TO_REG,SB),2,"mov.b"),{RS8,RD8,E}, { 0x0,0xC,RS8,RD8,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SB),2,"mov.b"),{IMM8,RD8,E}, { 0xF,RD8,IMM8,IGNORE,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SB),4,"mov.b"),{RSIND,RD8,E}, { 0x6,0x8,B30|RSIND,RD8,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SB),6,"mov.b"),{DISP16SRC,RD8,E}, { 0x6,0xE,B30|DISPREG,RD8,DISP16SRC,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_REG,SB),6,"mov.b"),{RSINC,RD8,E}, { 0x6,0xC,B30|RSINC,RD8,E,0,0,0,0}EOP, + + SOP(O(O_MOV_TO_REG,SB),4,"mov.b"),{ABS8SRC,RD8,E}, { 0x2,RD8,ABS8SRC,IGNORE,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_MEM,SB),4,"mov.b"),{RS8,RDIND,E}, { 0x6,0x8,RDIND|B31,RS8,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_MEM,SB),6,"mov.b"),{RS8,DISP16DST,E}, { 0x6,0xE,DISPREG|B31,RS8,DISP16DST,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_MEM,SB),6,"mov.b"),{RS8,RDDEC|B31,E}, { 0x6,0xC,RDDEC|B31,RS8,E,0,0,0,0}EOP, + + SOP(O(O_MOV_TO_MEM,SB),4,"mov.b"),{RS8,ABS8DST,E}, { 0x3,RS8,ABS8DST,IGNORE,E,0,0,0,0}EOP, + + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,RDIND,E}, { 0x6,0x9,RDIND|B31,RS16,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SW),6,"mov.w"),{DISP|L_24|SRC,RD16,E},{ 0x7,0x8,B30|DISPREG,0x0,0x6,0xB,0x2,RD16,0x0,0x0,SRC|DISP24LIST,E}EOP, + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,DISP|L_24|DST,E},{ 0x7,0x8,B30|DISPREG,0x0,0x6,0xB,0xA,RS16,0x0,0x0,DST|DISP24LIST,E}EOP, + SOP(O(O_MOV_TO_REG,SW),6,"mov.w"),{ABS|L_24|SRC,RD16,E },{ 0x6,0xB,0x2,RD16,0x0,0x0,SRC|ABS24LIST,E }EOP, + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,ABS|L_24|DST,E },{ 0x6,0xB,0xA,RS16,0x0,0x0,DST|ABS24LIST,E }EOP, + SOP(O(O_MOV_TO_REG,SW),2,"mov.w"),{RS16,RD16,E}, { 0x0,0xD,RS16, RD16,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SW),4,"mov.w"),{IMM16,RD16,E}, { 0x7,0x9,0x0,RD16,IMM16,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_REG,SW),4,"mov.w"),{RSIND,RD16,E}, { 0x6,0x9,B30|RSIND,RD16,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SW),6,"mov.w"),{DISP16SRC,RD16,E}, { 0x6,0xF,B30|DISPREG,RD16,DISP16SRC,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_REG,SW),6,"mov.w"),{RSINC,RD16,E}, { 0x6,0xD,B30|RSINC,RD16,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_REG,SW),6,"mov.w"),{ABS16SRC,RD16,E}, { 0x6,0xB,0x0,RD16,ABS16SRC,IGNORE,IGNORE,IGNORE,E}EOP, + + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,DISP16DST,E}, { 0x6,0xF,DISPREG|B31,RS16,DISP16DST,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,RDDEC,E}, { 0x6,0xD,RDDEC|B31,RS16,E,0,0,0,0}EOP, + SOP(O(O_MOV_TO_MEM,SW),6,"mov.w"),{RS16,ABS16DST,E}, { 0x6,0xB,0x8,RS16,ABS16DST,IGNORE,IGNORE,IGNORE,E}EOP, + + SOP(O(O_MOV_TO_REG,SL),4,"mov.l"),{IMM32,RD32,E}, { 0x7,0xA,0x0,B30|RD32,IMM32LIST,E}EOP, + SOP(O(O_MOV_TO_REG,SL),2,"mov.l"),{RS32,RD32,E}, { 0x0,0xF,B31|RS32,B30|RD32,E,0,0,0,0}EOP, + + SOP(O(O_MOV_TO_REG,SL),4,"mov.l"),{RSIND,RD32,E}, { PREFIX32,0x6,0x9,RSIND|B30,B30|RD32,E,0,0,0,0 }EOP, + SOP(O(O_MOV_TO_REG,SL),6,"mov.l"),{DISP16SRC,RD32,E}, { PREFIX32,0x6,0xF,DISPREG|B30,B30|RD32,DISP16SRC,IGNORE,IGNORE,IGNORE,E }EOP, + SOP(O(O_MOV_TO_REG,SL),6,"mov.l"),{DISP|L_24|SRC,RD32,E},{ PREFIX32,0x7,0x8,B30|DISPREG,0x0,0x6,0xB,0x2,B30|RD32,0x0,0x0,SRC|DISP24LIST,E }EOP, + SOP(O(O_MOV_TO_REG,SL),6,"mov.l"),{RSINC,RD32,E}, { PREFIX32,0x6,0xD,B30|RSINC,B30|RD32,E,0,0,0,0 }EOP, + SOP(O(O_MOV_TO_REG,SL),6,"mov.l"),{ABS16SRC,RD32,E}, { PREFIX32,0x6,0xB,0x0,B30|RD32,ABS16SRC,IGNORE,IGNORE,IGNORE,E }EOP, + SOP(O(O_MOV_TO_REG,SL),6,"mov.l"),{ABS24SRC,RD32,E }, { PREFIX32,0x6,0xB,0x2,B30|RD32,0x0,0x0,SRC|ABS24LIST,E }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,RDIND,E}, { PREFIX32,0x6,0x9,RDIND|B31,B30|RS32,E,0,0,0,0 }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,DISP16DST,E}, { PREFIX32,0x6,0xF,DISPREG|B31,B30|RS32,DISP16DST,IGNORE,IGNORE,IGNORE,E }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,DISP|L_24|DST,E},{ PREFIX32,0x7,0x8,B31|DISPREG,0x0,0x6,0xB,0xA,B30|RS32,0x0,0x0,DST|DISP24LIST,E }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,RDDEC,E}, { PREFIX32,0x6,0xD,RDDEC|B31,B30|RS32,E,0,0,0,0 }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,ABS16DST,E}, { PREFIX32,0x6,0xB,0x8,B30|RS32,ABS16DST,IGNORE,IGNORE,IGNORE,E }EOP, + SOP(O(O_MOV_TO_MEM,SL),6,"mov.l"),{RS32,ABS24DST,E }, { PREFIX32,0x6,0xB,0xA,B30|RS32,0x0,0x0,DST|ABS24LIST,E }EOP, + + SOP(O(O_MOV_TO_REG,SB),10,"movfpe"),{ABS16SRC,RD8,E},{ 0x6,0xA,0x4,RD8,ABS16SRC,IGNORE,IGNORE,IGNORE,E}EOP, + SOP(O(O_MOV_TO_MEM,SB),10,"movtpe"),{RS8,ABS16DST,E},{ 0x6,0xA,0xC,RS8,ABS16DST,IGNORE,IGNORE,IGNORE,E}EOP, + + NEW_SOP(O(O_MULU,SB),1,14,"mulxu.b"),{RS8,RD16,E}, { 0x5,0x0,RS8,RD16,E,0,0,0,0}EOP, + NEW_SOP(O(O_MULU,SW),0,14,"mulxu.w"),{RS16,RD32,E},{ 0x5,0x2,RS16,B30|RD32,E,0,0,0,0}EOP, + + NEW_SOP(O(O_MULS,SB),0,20,"mulxs.b"),{RS8,RD16,E}, { 0x0,0x1,0xc,0x0,0x5,0x0,RS8,RD16,E}EOP, + NEW_SOP(O(O_MULS,SW),0,20,"mulxs.w"),{RS16,RD32,E},{ 0x0,0x1,0xc,0x0,0x5,0x2,RS16,B30|RD32,E}EOP, + + /* ??? This can use UNOP3. */ + NEW_SOP(O(O_NEG,SB),1,2,"neg.b"),{ OR8,E, 0},{ 0x1,0x7,0x8,OR8,E,0,0,0,0}EOP, + NEW_SOP(O(O_NEG,SW),0,2,"neg.w"),{ OR16,E,0},{ 0x1,0x7,0x9,OR16,E}EOP, + NEW_SOP(O(O_NEG,SL),0,2,"neg.l"),{ OR32,E,0},{ 0x1,0x7,0xB,B30|OR32,E}EOP, + + NEW_SOP(O(O_NOP,SB),1,2,"nop"),{E,0,0},{ 0x0,0x0,0x0,0x0,E,0,0,0,0}EOP, + + /* ??? This can use UNOP3. */ + NEW_SOP(O(O_NOT,SB),1,2,"not.b"),{ OR8,E, 0},{ 0x1,0x7,0x0,OR8,E,0,0,0,0}EOP, + NEW_SOP(O(O_NOT,SW),0,2,"not.w"),{ OR16,E,0},{ 0x1,0x7,0x1,OR16,E}EOP, + NEW_SOP(O(O_NOT,SL),0,2,"not.l"),{ OR32,E,0},{ 0x1,0x7,0x3,B30|OR32,E}EOP, + + TWOOP(O(O_OR, SB),"or.b",0xC,0x1,0x4), + NEW_SOP(O(O_OR,SW),0,4,"or.w"),{IMM16,RD16,E },{0x7,0x9,0x4,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + NEW_SOP(O(O_OR,SW),0,2,"or.w"),{RS16,RD16,E },{0x6,0x4,RS16,RD16,E} EOP, + + NEW_SOP(O(O_OR,SL),0,6,"or.l"),{IMM32,RD32,E },{0x7,0xA,0x4,B30|RD32,IMM32LIST,E} EOP, + NEW_SOP(O(O_OR,SL),0,2,"or.l"),{RS32,RD32,E },{0x0,0x1,0xF,0x0,0x6,0x4,B30|RS32,B30|RD32,E} EOP, + + NEW_SOP(O(O_ORC,SB),1,2,"orc"),{IMM8,CCR,E},{ 0x0,0x4,IMM8,IGNORE,E,0,0,0,0}EOP, + + NEW_SOP(O(O_MOV_TO_REG,SW),1,6,"pop.w"),{OR16,E,0},{ 0x6,0xD,0x7,OR16,E,0,0,0,0}EOP, + NEW_SOP(O(O_MOV_TO_REG,SL),0,6,"pop.l"),{OR32,E,0},{ PREFIX32,0x6,0xD,0x7,OR32|B30,E,0,0,0,0}EOP, + NEW_SOP(O(O_MOV_TO_MEM,SW),1,6,"push.w"),{OR16,E,0},{ 0x6,0xD,0xF,OR16,E,0,0,0,0}EOP, + NEW_SOP(O(O_MOV_TO_MEM,SL),0,6,"push.l"),{OR32,E,0},{ PREFIX32,0x6,0xD,0xF,OR32|B30,E,0,0,0,0}EOP, + + UNOP3(O_ROTL, "rotl", 0x1,0x2,0x8), + UNOP3(O_ROTR, "rotr", 0x1,0x3,0x8), + UNOP3(O_ROTXL, "rotxl",0x1,0x2,0x0), + UNOP3(O_ROTXR, "rotxr",0x1,0x3,0x0), + + SOP(O(O_BPT,SB), 10,"bpt"),{E,0,0},{ 0x7,0xA,0xF,0xF,E,0,0,0,0}EOP, + SOP(O(O_RTE,SB), 10,"rte"),{E,0,0},{ 0x5,0x6,0x7,0x0,E,0,0,0,0}EOP, + SOP(O(O_RTS,SB), 8,"rts"),{E,0,0},{ 0x5,0x4,0x7,0x0,E,0,0,0,0}EOP, + + UNOP3(O_SHAL, "shal",0x1,0x0,0x8), + UNOP3(O_SHAR, "shar",0x1,0x1,0x8), + UNOP3(O_SHLL, "shll",0x1,0x0,0x0), + UNOP3(O_SHLR, "shlr",0x1,0x1,0x0), + + SOP(O(O_SLEEP,SB),2,"sleep"),{E,0,0},{ 0x0,0x1,0x8,0x0,E,0,0,0,0} EOP, + + NEW_SOP(O(O_STC,SB), 1,2,"stc"),{CCR,RD8,E},{ 0x0,0x2,0x0,RD8,E,0,0,0,0} EOP, + + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,RSIND,E}, {PREFIXLDC,0x6,0x9,B31|RDIND,0x0,E} EOP, + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,DISP|DST|L_16,E},{PREFIXLDC,0x6,0x9,B31|DISPREG,0,DST|DISP|L_16,IGNORE,IGNORE,IGNORE,E}EOP, + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,DISP|DST|L_24,E},{PREFIXLDC,0x7,0x8,B31|DISPREG,0,0x6,0xB,0x2,0x0,0x0,0x0,DST|DISP24LIST,E}EOP, + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,RDDEC,E}, {PREFIXLDC,0x6,0xD,B31|RDDEC,0x0,E}EOP, + + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,ABS16SRC,E}, {PREFIXLDC,0x6,0xB,0x8,0x0,ABS16DST,IGNORE,IGNORE,IGNORE,E}EOP, + NEW_SOP(O(O_STC,SB),0,2,"stc"),{CCR,ABS24SRC,E}, {PREFIXLDC,0x6,0xB,0xA,0x0,0x0,0x0,DST|ABS24LIST,E}EOP, + + SOP(O(O_SUB,SB),2,"sub.b"),{RS8,RD8,E},{ 0x1,0x8,RS8,RD8,E,0,0,0,0}EOP, + + NEW_SOP(O(O_SUB,SW),1,2,"sub.w"),{RS16,RD16,E }, {0x1,0x9,RS16,RD16,E} EOP, + NEW_SOP(O(O_SUB,SW),0,4,"sub.w"),{IMM16,RD16,E }, {0x7,0x9,0x3,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + NEW_SOP(O(O_SUB,SL),0,2,"sub.l") ,{RS32,RD32,E }, {0x1,0xA,B31|RS32,B30|RD32,E} EOP, + NEW_SOP(O(O_SUB,SL),0,6,"sub.l"), {IMM32,RD32,E },{0x7,0xA,0x3,B30|RD32,IMM32LIST,E} EOP, + + SOP(O(O_SUBS,SL),2,"subs"),{KBIT,RDP,E},{ 0x1,0xB,KBIT,RDP,E,0,0,0,0}EOP, + TWOOP(O(O_SUBX,SB),"subx",0xB,0x1,0xE), + + NEW_SOP(O(O_TRAPA,SB),0,2,"trapa"),{ IMM2,E}, {0x5,0x7,IMM2,IGNORE,E }EOP, + + TWOOP(O(O_XOR, SB),"xor",0xD,0x1,0x5), + + NEW_SOP(O(O_XOR,SW),0,4,"xor.w"),{IMM16,RD16,E },{0x7,0x9,0x5,RD16,IMM16,IGNORE,IGNORE,IGNORE,E} EOP, + NEW_SOP(O(O_XOR,SW),0,2,"xor.w"),{RS16,RD16,E },{0x6,0x5,RS16,RD16,E} EOP, + + NEW_SOP(O(O_XOR,SL),0,6,"xor.l"),{IMM32,RD32,E },{0x7,0xA,0x5,B30|RD32,IMM32LIST,E} EOP, + NEW_SOP(O(O_XOR,SL),0,2,"xor.l") ,{RS32,RD32,E },{0x0,0x1,0xF,0x0,0x6,0x5,B30|RS32,B30|RD32,E} EOP, + + SOP(O(O_XORC,SB),2,"xorc"),{IMM8,CCR,E},{ 0x0,0x5,IMM8,IGNORE,E,0,0,0,0}EOP, + 0 +}; +#else +extern struct h8_opcode h8_opcodes[] ; +#endif + + + + diff --git a/contrib/gdb/include/opcode/hppa.h b/contrib/gdb/include/opcode/hppa.h new file mode 100644 index 000000000000..6f50e6bbea62 --- /dev/null +++ b/contrib/gdb/include/opcode/hppa.h @@ -0,0 +1,471 @@ +/* Table of opcodes for the PA-RISC. + Copyright (C) 1990, 1991, 1993, 1995 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB 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 1, or (at your option) +any later version. + +GAS/GDB 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 GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ + +/* There are two kinds of delay slot nullification: normal which is + * controled by the nullification bit, and conditional, which depends + * on the direction of the branch and its success or failure. + * + * NONE is unfortunately #defined in the hiux system include files. + * #undef it away. + */ +#undef NONE +struct pa_opcode +{ + const char *name; + unsigned long int match; /* Bits that must be set... */ + unsigned long int mask; /* ... in these bits. */ + char *args; + enum pa_arch arch; +}; + +/* + All hppa opcodes are 32 bits. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character + for each operand of the instruction. + + Bit positions in this description follow HP usage of lsb = 31, + "at" is lsb of field. + + In the args field, the following characters must match exactly: + + '+,() ' + + In the args field, the following characters are unused: + + ' "#$% *+- ./ 3 :; = ' + ' B L [\] _' + ' e gh lm qr { } ' + + Here are all the characters: + + ' !"#$%&'()*+-,./0123456789:;<=>?@' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + 'abcdefghijklmnopqrstuvwxyz{|}~' + +Kinds of operands: + x integer register field at 15. + b integer register field at 10. + t integer register field at 31. + y floating point register field at 31 + 5 5 bit immediate at 15. + s 2 bit space specifier at 17. + S 3 bit space specifier at 18. + c indexed load completer. + C short load and store completer. + Y Store Bytes Short completer + < non-negated compare/subtract conditions. + a compare/subtract conditions + d non-negated add conditions + & logical instruction conditions + U unit instruction conditions + > shift/extract/deposit conditions. + ~ bvb,bb conditions + V 5 bit immediate value at 31 + i 11 bit immediate value at 31 + j 14 bit immediate value at 31 + k 21 bit immediate value at 31 + n nullification for branch instructions + N nullification for spop and copr instructions + w 12 bit branch displacement + W 17 bit branch displacement (PC relative) + z 17 bit branch displacement (just a number, not an address) + +Also these: + + p 5 bit shift count at 26 (to support the SHD instruction) encoded as + 31-p + P 5 bit bit position at 26 + T 5 bit field length at 31 (encoded as 32-T) + A 13 bit immediate at 18 (to support the BREAK instruction) + ^ like b, but describes a control register + Z System Control Completer (to support LPA, LHA, etc.) + D 26 bit immediate at 31 (to support the DIAG instruction) + + f 3 bit Special Function Unit identifier at 25 + O 20 bit Special Function Unit operation split between 15 bits at 20 + and 5 bits at 31 + o 15 bit Special Function Unit operation at 20 + 2 22 bit Special Function Unit operation split between 17 bits at 20 + and 5 bits at 31 + 1 15 bit Special Function Unit operation split between 10 bits at 20 + and 5 bits at 31 + 0 10 bit Special Function Unit operation split between 5 bits at 20 + and 5 bits at 31 + u 3 bit coprocessor unit identifier at 25 + F Source Floating Point Operand Format Completer encoded 2 bits at 20 + I Source Floating Point Operand Format Completer encoded 1 bits at 20 + (for 0xe format FP instructions) + G Destination Floating Point Operand Format Completer encoded 2 bits at 18 + M Floating-Point Compare Conditions (encoded as 5 bits at 31) + ? non-negated/negated compare/subtract conditions. + @ non-negated/negated add conditions. + ! non-negated add conditions. + + s 2 bit space specifier at 17. + b register field at 10. + r 5 bit immediate value at 31 (for the break instruction) + (very similar to V above, except the value is unsigned instead of + low_sign_ext) + R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) + (same as r above, except the value is in a different location) + Q 5 bit immediate value at 10 (a bit position specified in + the bb instruction. It's the same as r above, except the + value is in a different location) + | shift/extract/deposit conditions when used in a conditional branch + +And these (PJH) for PA-89 F.P. registers and instructions: + + v a 't' operand type extended to handle L/R register halves. + E a 'b' operand type extended to handle L/R register halves. + X an 'x' operand type extended to handle L/R register halves. + J a 'b' operand type further extended to handle extra 1.1 registers + K a 'x' operand type further extended to handle extra 1.1 registers + 4 a variation of the 'b' operand type for 'fmpyadd' and 'fmpysub' + 6 a variation of the 'x' operand type for 'fmpyadd' and 'fmpysub' + 7 a variation of the 't' operand type for 'fmpyadd' and 'fmpysub' + 8 5 bit register field at 20 (used in 'fmpyadd' and 'fmpysub') + 9 5 bit register field at 25 (used in 'fmpyadd' and 'fmpysub') + H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' + (very similar to 'F') +*/ + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic must be + consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +static const struct pa_opcode pa_opcodes[] = +{ + +/* pseudo-instructions */ + +{ "b", 0xe8000000, 0xffe0e000, "nW", pa10}, /* bl foo,r0 */ +{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10}, /* ldo val(r0),r */ +{ "comib", 0x84000000, 0xfc000000, "?n5,b,w", pa10}, /* comib{tf}*/ +{ "comb", 0x80000000, 0xfc000000, "?nx,b,w", pa10}, /* comb{tf} */ +{ "addb", 0xa0000000, 0xfc000000, "@nx,b,w", pa10}, /* addb{tf} */ +{ "addib", 0xa4000000, 0xfc000000, "@n5,b,w", pa10}, /* addib{tf}*/ +{ "nop", 0x08000240, 0xffffffff, "", pa10}, /* or 0,0,0 */ +{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10}, /* or r,0,t */ +{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10}, /* mtctl r,cr11 */ + +/* Loads and Stores for integer registers. */ +{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10}, +{ "ldw", 0x48000000, 0xfc000000, "j(b),x", pa10}, +{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10}, +{ "ldh", 0x44000000, 0xfc000000, "j(b),x", pa10}, +{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10}, +{ "ldb", 0x40000000, 0xfc000000, "j(b),x", pa10}, +{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10}, +{ "stw", 0x68000000, 0xfc000000, "x,j(b)", pa10}, +{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10}, +{ "sth", 0x64000000, 0xfc000000, "x,j(b)", pa10}, +{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10}, +{ "stb", 0x60000000, 0xfc000000, "x,j(b)", pa10}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10}, +{ "ldwm", 0x4c000000, 0xfc000000, "j(b),x", pa10}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10}, +{ "stwm", 0x6c000000, 0xfc000000, "x,j(b)", pa10}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cx(s,b),t", pa10}, +{ "ldwx", 0x0c000080, 0xfc001fc0, "cx(b),t", pa10}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cx(s,b),t", pa10}, +{ "ldhx", 0x0c000040, 0xfc001fc0, "cx(b),t", pa10}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cx(s,b),t", pa10}, +{ "ldbx", 0x0c000000, 0xfc001fc0, "cx(b),t", pa10}, +{ "ldwax", 0x0c000180, 0xfc00dfc0, "cx(b),t", pa10}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cx(s,b),t", pa10}, +{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cx(b),t", pa10}, +{ "ldws", 0x0c001080, 0xfc001fc0, "C5(s,b),t", pa10}, +{ "ldws", 0x0c001080, 0xfc001fc0, "C5(b),t", pa10}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "C5(s,b),t", pa10}, +{ "ldhs", 0x0c001040, 0xfc001fc0, "C5(b),t", pa10}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "C5(s,b),t", pa10}, +{ "ldbs", 0x0c001000, 0xfc001fc0, "C5(b),t", pa10}, +{ "ldwas", 0x0c001180, 0xfc00dfc0, "C5(b),t", pa10}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "C5(s,b),t", pa10}, +{ "ldcws", 0x0c0011c0, 0xfc001fc0, "C5(b),t", pa10}, +{ "stws", 0x0c001280, 0xfc001fc0, "Cx,V(s,b)", pa10}, +{ "stws", 0x0c001280, 0xfc001fc0, "Cx,V(b)", pa10}, +{ "sths", 0x0c001240, 0xfc001fc0, "Cx,V(s,b)", pa10}, +{ "sths", 0x0c001240, 0xfc001fc0, "Cx,V(b)", pa10}, +{ "stbs", 0x0c001200, 0xfc001fc0, "Cx,V(s,b)", pa10}, +{ "stbs", 0x0c001200, 0xfc001fc0, "Cx,V(b)", pa10}, +{ "stwas", 0x0c001380, 0xfc00dfc0, "Cx,V(b)", pa10}, +{ "stbys", 0x0c001300, 0xfc001fc0, "Yx,V(s,b)", pa10}, +{ "stbys", 0x0c001300, 0xfc001fc0, "Yx,V(b)", pa10}, + +/* Immediate instructions. */ +{ "ldo", 0x34000000, 0xfc00c000, "j(b),x", pa10}, +{ "ldil", 0x20000000, 0xfc000000, "k,b", pa10}, +{ "addil", 0x28000000, 0xfc000000, "k,b", pa10}, + +/* Branching instructions. */ +{ "bl", 0xe8000000, 0xfc00e000, "nW,b", pa10}, +{ "gate", 0xe8002000, 0xfc00e000, "nW,b", pa10}, +{ "blr", 0xe8004000, 0xfc00e001, "nx,b", pa10}, +{ "bv", 0xe800c000, 0xfc00e001, "nx(b)", pa10}, +{ "bv", 0xe800c000, 0xfc00e001, "n(b)", pa10}, +{ "be", 0xe0000000, 0xfc000000, "nz(S,b)", pa10}, +{ "ble", 0xe4000000, 0xfc000000, "nz(S,b)", pa10}, +{ "movb", 0xc8000000, 0xfc000000, "|nx,b,w", pa10}, +{ "movib", 0xcc000000, 0xfc000000, "|n5,b,w", pa10}, +{ "combt", 0x80000000, 0xfc000000, "x,b,t", pa10}, +{ "shd", 0xd0000800, 0xfc001c00, ">x,b,p,t", pa10}, +{ "vextru", 0xd0001000, 0xfc001fe0, ">b,T,x", pa10}, +{ "vextrs", 0xd0001400, 0xfc001fe0, ">b,T,x", pa10}, +{ "extru", 0xd0001800, 0xfc001c00, ">b,P,T,x", pa10}, +{ "extrs", 0xd0001c00, 0xfc001c00, ">b,P,T,x", pa10}, +{ "zvdep", 0xd4000000, 0xfc001fe0, ">x,T,b", pa10}, +{ "vdep", 0xd4000400, 0xfc001fe0, ">x,T,b", pa10}, +{ "zdep", 0xd4000800, 0xfc001c00, ">x,p,T,b", pa10}, +{ "dep", 0xd4000c00, 0xfc001c00, ">x,p,T,b", pa10}, +{ "zvdepi", 0xd4001000, 0xfc001fe0, ">5,T,b", pa10}, +{ "vdepi", 0xd4001400, 0xfc001fe0, ">5,T,b", pa10}, +{ "zdepi", 0xd4001800, 0xfc001c00, ">5,p,T,b", pa10}, +{ "depi", 0xd4001c00, 0xfc001c00, ">5,p,T,b", pa10}, + +/* System Control Instructions */ + +{ "break", 0x00000000, 0xfc001fe0, "r,A", pa10}, +{ "rfi", 0x00000c00, 0xffffffff, "", pa10}, +{ "rfir", 0x00000ca0, 0xffffffff, "", pa11}, +{ "ssm", 0x00000d60, 0xffe0ffe0, "R,t", pa10}, +{ "rsm", 0x00000e60, 0xffe0ffe0, "R,t", pa10}, +{ "mtsm", 0x00001860, 0xffe0ffff, "x", pa10}, +{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10}, +{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(b),t", pa10}, +{ "mtsp", 0x00001820, 0xffe01fff, "x,S", pa10}, +{ "mtctl", 0x00001840, 0xfc00ffff, "x,^", pa10}, +{ "mfsp", 0x000004a0, 0xffff1fe0, "S,t", pa10}, +{ "mfctl", 0x000008a0, 0xfc1fffe0, "^,t", pa10}, +{ "sync", 0x00000400, 0xffffffff, "", pa10}, +{ "syncdma", 0x00100400, 0xffffffff, "", pa10}, +{ "prober", 0x04001180, 0xfc003fe0, "(s,b),x,t", pa10}, +{ "prober", 0x04001180, 0xfc003fe0, "(b),x,t", pa10}, +{ "proberi", 0x04003180, 0xfc003fe0, "(s,b),R,t", pa10}, +{ "proberi", 0x04003180, 0xfc003fe0, "(b),R,t", pa10}, +{ "probew", 0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10}, +{ "probew", 0x040011c0, 0xfc003fe0, "(b),x,t", pa10}, +{ "probewi", 0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10}, +{ "probewi", 0x040031c0, 0xfc003fe0, "(b),R,t", pa10}, +{ "lpa", 0x04001340, 0xfc003fc0, "Zx(s,b),t", pa10}, +{ "lpa", 0x04001340, 0xfc003fc0, "Zx(b),t", pa10}, +{ "lha", 0x04001300, 0xfc003fc0, "Zx(s,b),t", pa10}, +{ "lha", 0x04001300, 0xfc003fc0, "Zx(b),t", pa10}, +{ "lci", 0x04001300, 0xfc003fe0, "x(s,b),t", pa10}, +{ "lci", 0x04001300, 0xfc003fe0, "x(b),t", pa10}, +{ "pdtlb", 0x04001200, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "pdtlb", 0x04001200, 0xfc003fdf, "Zx(b)", pa10}, +{ "pitlb", 0x04000200, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "pitlb", 0x04000200, 0xfc003fdf, "Zx(b)", pa10}, +{ "pdtlbe", 0x04001240, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "pdtlbe", 0x04001240, 0xfc003fdf, "Zx(b)", pa10}, +{ "pitlbe", 0x04000240, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "pitlbe", 0x04000240, 0xfc003fdf, "Zx(b)", pa10}, +{ "idtlba", 0x04001040, 0xfc003fff, "x,(s,b)", pa10}, +{ "idtlba", 0x04001040, 0xfc003fff, "x,(b)", pa10}, +{ "iitlba", 0x04000040, 0xfc003fff, "x,(s,b)", pa10}, +{ "iitlba", 0x04000040, 0xfc003fff, "x,(b)", pa10}, +{ "idtlbp", 0x04001000, 0xfc003fff, "x,(s,b)", pa10}, +{ "idtlbp", 0x04001000, 0xfc003fff, "x,(b)", pa10}, +{ "iitlbp", 0x04000000, 0xfc003fff, "x,(s,b)", pa10}, +{ "iitlbp", 0x04000000, 0xfc003fff, "x,(b)", pa10}, +{ "pdc", 0x04001380, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "pdc", 0x04001380, 0xfc003fdf, "Zx(b)", pa10}, +{ "fdc", 0x04001280, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "fdc", 0x04001280, 0xfc003fdf, "Zx(b)", pa10}, +{ "fic", 0x04000280, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "fic", 0x04000280, 0xfc003fdf, "Zx(b)", pa10}, +{ "fdce", 0x040012c0, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "fdce", 0x040012c0, 0xfc003fdf, "Zx(b)", pa10}, +{ "fice", 0x040002c0, 0xfc003fdf, "Zx(s,b)", pa10}, +{ "fice", 0x040002c0, 0xfc003fdf, "Zx(b)", pa10}, +{ "diag", 0x14000000, 0xfc000000, "D", pa10}, + +/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either + the Timex FPU or the Mustang ERS (not sure which) manual. */ +{ "gfw", 0x04001680, 0xfc003fdf, "Zx(s,b)", pa11}, +{ "gfw", 0x04001680, 0xfc003fdf, "Zx(b)", pa11}, +{ "gfr", 0x04001a80, 0xfc003fdf, "Zx(s,b)", pa11}, +{ "gfr", 0x04001a80, 0xfc003fdf, "Zx(b)", pa11}, + +/* Floating Point Coprocessor Instructions */ + +{ "fldwx", 0x24000000, 0xfc001f80, "cx(s,b),v", pa10}, +{ "fldwx", 0x24000000, 0xfc001f80, "cx(b),v", pa10}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cx(s,b),y", pa10}, +{ "flddx", 0x2c000000, 0xfc001fc0, "cx(b),y", pa10}, +{ "fstwx", 0x24000200, 0xfc001f80, "cv,x(s,b)", pa10}, +{ "fstwx", 0x24000200, 0xfc001f80, "cv,x(b)", pa10}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cy,x(s,b)", pa10}, +{ "fstdx", 0x2c000200, 0xfc001fc0, "cy,x(b)", pa10}, +{ "fstqx", 0x3c000200, 0xfc001fc0, "cy,x(s,b)", pa10}, +{ "fstqx", 0x3c000200, 0xfc001fc0, "cy,x(b)", pa10}, +{ "fldws", 0x24001000, 0xfc001f80, "C5(s,b),v", pa10}, +{ "fldws", 0x24001000, 0xfc001f80, "C5(b),v", pa10}, +{ "fldds", 0x2c001000, 0xfc001fc0, "C5(s,b),y", pa10}, +{ "fldds", 0x2c001000, 0xfc001fc0, "C5(b),y", pa10}, +{ "fstws", 0x24001200, 0xfc001f80, "Cv,5(s,b)", pa10}, +{ "fstws", 0x24001200, 0xfc001f80, "Cv,5(b)", pa10}, +{ "fstds", 0x2c001200, 0xfc001fc0, "Cy,5(s,b)", pa10}, +{ "fstds", 0x2c001200, 0xfc001fc0, "Cy,5(b)", pa10}, +{ "fstqs", 0x3c001200, 0xfc001fc0, "Cy,5(s,b)", pa10}, +{ "fstqs", 0x3c001200, 0xfc001fc0, "Cy,5(b)", pa10}, +{ "fadd", 0x30000600, 0xfc00e7e0, "FE,X,v", pa10}, +{ "fadd", 0x38000600, 0xfc00e720, "IJ,K,v", pa10}, +{ "fsub", 0x30002600, 0xfc00e7e0, "FE,X,v", pa10}, +{ "fsub", 0x38002600, 0xfc00e720, "IJ,K,v", pa10}, +{ "fmpy", 0x30004600, 0xfc00e7e0, "FE,X,v", pa10}, +{ "fmpy", 0x38004600, 0xfc00e720, "IJ,K,v", pa10}, +{ "fdiv", 0x30006600, 0xfc00e7e0, "FE,X,v", pa10}, +{ "fdiv", 0x38006600, 0xfc00e720, "IJ,K,v", pa10}, +{ "fsqrt", 0x30008000, 0xfc1fe7e0, "FE,v", pa10}, +{ "fsqrt", 0x38008000, 0xfc1fe720, "FJ,v", pa10}, +{ "fabs", 0x30006000, 0xfc1fe7e0, "FE,v", pa10}, +{ "fabs", 0x38006000, 0xfc1fe720, "FJ,v", pa10}, +{ "frem", 0x30008600, 0xfc00e7e0, "FE,X,v", pa10}, +{ "frem", 0x38008600, 0xfc00e720, "FJ,K,v", pa10}, +{ "frnd", 0x3000a000, 0xfc1fe7e0, "FE,v", pa10}, +{ "frnd", 0x3800a000, 0xfc1fe720, "FJ,v", pa10}, +{ "fcpy", 0x30004000, 0xfc1fe7e0, "FE,v", pa10}, +{ "fcpy", 0x38004000, 0xfc1fe720, "FJ,v", pa10}, +{ "fcnvff", 0x30000200, 0xfc1f87e0, "FGE,v", pa10}, +{ "fcnvff", 0x38000200, 0xfc1f8720, "FGJ,v", pa10}, +{ "fcnvxf", 0x30008200, 0xfc1f87e0, "FGE,v", pa10}, +{ "fcnvxf", 0x38008200, 0xfc1f8720, "FGJ,v", pa10}, +{ "fcnvfx", 0x30010200, 0xfc1f87e0, "FGE,v", pa10}, +{ "fcnvfx", 0x38010200, 0xfc1f8720, "FGJ,v", pa10}, +{ "fcnvfxt", 0x30018200, 0xfc1f87e0, "FGE,v", pa10}, +{ "fcnvfxt", 0x38018200, 0xfc1f8720, "FGJ,v", pa10}, +{ "fcmp", 0x30000400, 0xfc00e7e0, "FME,X", pa10}, +{ "fcmp", 0x38000400, 0xfc00e720, "IMJ,K", pa10}, +{ "xmpyu", 0x38004700, 0xfc00e720, "E,X,v", pa11}, +{ "fmpyadd", 0x18000000, 0xfc000000, "H4,6,7,9,8", pa11}, +{ "fmpysub", 0x98000000, 0xfc000000, "H4,6,7,9,8", pa11}, +{ "ftest", 0x30002420, 0xffffffff, "", pa10}, + + +/* Assist Instructions */ + +{ "spop0", 0x10000000, 0xfc000600, "f,ON", pa10}, +{ "spop1", 0x10000200, 0xfc000600, "f,oNt", pa10}, +{ "spop2", 0x10000400, 0xfc000600, "f,1Nb", pa10}, +{ "spop3", 0x10000600, 0xfc000600, "f,0Nx,b", pa10}, +{ "copr", 0x30000000, 0xfc000000, "u,2N", pa10}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucx(s,b),t", pa10}, +{ "cldwx", 0x24000000, 0xfc001e00, "ucx(b),t", pa10}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucx(s,b),t", pa10}, +{ "clddx", 0x2c000000, 0xfc001e00, "ucx(b),t", pa10}, +{ "cstwx", 0x24000200, 0xfc001e00, "uct,x(s,b)", pa10}, +{ "cstwx", 0x24000200, 0xfc001e00, "uct,x(b)", pa10}, +{ "cstdx", 0x2c000200, 0xfc001e00, "uct,x(s,b)", pa10}, +{ "cstdx", 0x2c000200, 0xfc001e00, "uct,x(b)", pa10}, +{ "cldws", 0x24001000, 0xfc001e00, "uC5(s,b),t", pa10}, +{ "cldws", 0x24001000, 0xfc001e00, "uC5(b),t", pa10}, +{ "cldds", 0x2c001000, 0xfc001e00, "uC5(s,b),t", pa10}, +{ "cldds", 0x2c001000, 0xfc001e00, "uC5(b),t", pa10}, +{ "cstws", 0x24001200, 0xfc001e00, "uCt,5(s,b)", pa10}, +{ "cstws", 0x24001200, 0xfc001e00, "uCt,5(b)", pa10}, +{ "cstds", 0x2c001200, 0xfc001e00, "uCt,5(s,b)", pa10}, +{ "cstds", 0x2c001200, 0xfc001e00, "uCt,5(b)", pa10}, +}; + +#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) + +/* SKV 12/18/92. Added some denotations for various operands. */ + +#define PA_IMM11_AT_31 'i' +#define PA_IMM14_AT_31 'j' +#define PA_IMM21_AT_31 'k' +#define PA_DISP12 'w' +#define PA_DISP17 'W' + +#define N_HPPA_OPERAND_FORMATS 5 diff --git a/contrib/gdb/include/opcode/i386.h b/contrib/gdb/include/opcode/i386.h new file mode 100644 index 000000000000..849a86fa7b25 --- /dev/null +++ b/contrib/gdb/include/opcode/i386.h @@ -0,0 +1,898 @@ +/* i386-opcode.h -- Intel 80386 opcode table + Copyright 1989, 1991, 1992, 1995 Free Software Foundation. + +This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +static const template i386_optab[] = { + +#define _ None +/* move instructions */ +#define MOV_AX_DISP32 0xa0 +{ "mov", 2, 0xa0, _, DW|NoModrm, { Disp32, Acc, 0 } }, +{ "mov", 2, 0x88, _, DW|Modrm, { Reg, Reg|Mem, 0 } }, +{ "mov", 2, 0xb0, _, ShortFormW, { Imm, Reg, 0 } }, +{ "mov", 2, 0xc6, _, W|Modrm, { Imm, Reg|Mem, 0 } }, +{ "mov", 2, 0x8c, _, D|Modrm, { SReg3|SReg2, Reg16|Mem, 0 } }, +/* move to/from control debug registers */ +{ "mov", 2, 0x0f20, _, D|Modrm, { Control, Reg32, 0} }, +{ "mov", 2, 0x0f21, _, D|Modrm, { Debug, Reg32, 0} }, +{ "mov", 2, 0x0f24, _, D|Modrm, { Test, Reg32, 0} }, + +/* move with sign extend */ +/* "movsbl" & "movsbw" must not be unified into "movsb" to avoid + conflict with the "movs" string move instruction. Thus, + {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg16|Reg32, 0} }, + is not kosher; we must seperate the two instructions. */ +{"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm|Data32, { Reg8|Mem, Reg32, 0} }, +{"movsbw", 2, 0x0fbe, _, ReverseRegRegmem|Modrm|Data16, { Reg8|Mem, Reg16, 0} }, +{"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, { Reg16|Mem, Reg32, 0} }, + +/* move with zero extend */ +{"movzb", 2, 0x0fb6, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg16|Reg32, 0} }, +{"movzwl", 2, 0x0fb7, _, ReverseRegRegmem|Modrm, { Reg16|Mem, Reg32, 0} }, + +/* push instructions */ +{"push", 1, 0x50, _, ShortForm, { WordReg,0,0 } }, +{"push", 1, 0xff, 0x6, Modrm, { WordReg|WordMem, 0, 0 } }, +{"push", 1, 0x6a, _, NoModrm, { Imm8S, 0, 0} }, +{"push", 1, 0x68, _, NoModrm, { Imm16|Imm32, 0, 0} }, +{"push", 1, 0x06, _, Seg2ShortForm, { SReg2,0,0 } }, +{"push", 1, 0x0fa0, _, Seg3ShortForm, { SReg3,0,0 } }, +/* push all */ +{"pusha", 0, 0x60, _, NoModrm, { 0, 0, 0 } }, + +/* pop instructions */ +{"pop", 1, 0x58, _, ShortForm, { WordReg,0,0 } }, +{"pop", 1, 0x8f, 0x0, Modrm, { WordReg|WordMem, 0, 0 } }, +#define POP_SEG_SHORT 0x7 +{"pop", 1, 0x07, _, Seg2ShortForm, { SReg2,0,0 } }, +{"pop", 1, 0x0fa1, _, Seg3ShortForm, { SReg3,0,0 } }, +/* pop all */ +{"popa", 0, 0x61, _, NoModrm, { 0, 0, 0 } }, + +/* xchg exchange instructions + xchg commutes: we allow both operand orders */ +{"xchg", 2, 0x90, _, ShortForm, { WordReg, Acc, 0 } }, +{"xchg", 2, 0x90, _, ShortForm, { Acc, WordReg, 0 } }, +{"xchg", 2, 0x86, _, W|Modrm, { Reg, Reg|Mem, 0 } }, +{"xchg", 2, 0x86, _, W|Modrm, { Reg|Mem, Reg, 0 } }, + +/* in/out from ports */ +{"in", 2, 0xe4, _, W|NoModrm, { Imm8, Acc, 0 } }, +{"in", 2, 0xec, _, W|NoModrm, { InOutPortReg, Acc, 0 } }, +{"in", 1, 0xe4, _, W|NoModrm, { Imm8, 0, 0 } }, +{"in", 1, 0xec, _, W|NoModrm, { InOutPortReg, 0, 0 } }, +{"out", 2, 0xe6, _, W|NoModrm, { Acc, Imm8, 0 } }, +{"out", 2, 0xee, _, W|NoModrm, { Acc, InOutPortReg, 0 } }, +{"out", 1, 0xe6, _, W|NoModrm, { Imm8, 0, 0 } }, +{"out", 1, 0xee, _, W|NoModrm, { InOutPortReg, 0, 0 } }, + +/* load effective address */ +{"lea", 2, 0x8d, _, Modrm, { WordMem, WordReg, 0 } }, + +/* load segment registers from memory */ +{"lds", 2, 0xc5, _, Modrm, { Mem, Reg32, 0} }, +{"les", 2, 0xc4, _, Modrm, { Mem, Reg32, 0} }, +{"lfs", 2, 0x0fb4, _, Modrm, { Mem, Reg32, 0} }, +{"lgs", 2, 0x0fb5, _, Modrm, { Mem, Reg32, 0} }, +{"lss", 2, 0x0fb2, _, Modrm, { Mem, Reg32, 0} }, + +/* flags register instructions */ +{"clc", 0, 0xf8, _, NoModrm, { 0, 0, 0} }, +{"cld", 0, 0xfc, _, NoModrm, { 0, 0, 0} }, +{"cli", 0, 0xfa, _, NoModrm, { 0, 0, 0} }, +{"clts", 0, 0x0f06, _, NoModrm, { 0, 0, 0} }, +{"cmc", 0, 0xf5, _, NoModrm, { 0, 0, 0} }, +{"lahf", 0, 0x9f, _, NoModrm, { 0, 0, 0} }, +{"sahf", 0, 0x9e, _, NoModrm, { 0, 0, 0} }, +{"pushfl", 0, 0x9c, _, NoModrm|Data32, { 0, 0, 0} }, +{"popfl", 0, 0x9d, _, NoModrm|Data32, { 0, 0, 0} }, +{"pushfw", 0, 0x9c, _, NoModrm|Data16, { 0, 0, 0} }, +{"popfw", 0, 0x9d, _, NoModrm|Data16, { 0, 0, 0} }, +{"pushf", 0, 0x9c, _, NoModrm, { 0, 0, 0} }, +{"popf", 0, 0x9d, _, NoModrm, { 0, 0, 0} }, +{"stc", 0, 0xf9, _, NoModrm, { 0, 0, 0} }, +{"std", 0, 0xfd, _, NoModrm, { 0, 0, 0} }, +{"sti", 0, 0xfb, _, NoModrm, { 0, 0, 0} }, + +{"add", 2, 0x0, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"add", 2, 0x83, 0, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"add", 2, 0x4, _, W|NoModrm, { Imm, Acc, 0} }, +{"add", 2, 0x80, 0, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"inc", 1, 0x40, _, ShortForm, { WordReg, 0, 0} }, +{"inc", 1, 0xfe, 0, W|Modrm, { Reg|Mem, 0, 0} }, + +{"sub", 2, 0x28, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"sub", 2, 0x83, 5, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"sub", 2, 0x2c, _, W|NoModrm, { Imm, Acc, 0} }, +{"sub", 2, 0x80, 5, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"dec", 1, 0x48, _, ShortForm, { WordReg, 0, 0} }, +{"dec", 1, 0xfe, 1, W|Modrm, { Reg|Mem, 0, 0} }, + +{"sbb", 2, 0x18, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"sbb", 2, 0x83, 3, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"sbb", 2, 0x1c, _, W|NoModrm, { Imm, Acc, 0} }, +{"sbb", 2, 0x80, 3, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"cmp", 2, 0x38, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"cmp", 2, 0x83, 7, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"cmp", 2, 0x3c, _, W|NoModrm, { Imm, Acc, 0} }, +{"cmp", 2, 0x80, 7, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"test", 2, 0x84, _, W|Modrm, { Reg|Mem, Reg, 0} }, +{"test", 2, 0x84, _, W|Modrm, { Reg, Reg|Mem, 0} }, +{"test", 2, 0xa8, _, W|NoModrm, { Imm, Acc, 0} }, +{"test", 2, 0xf6, 0, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"and", 2, 0x20, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"and", 2, 0x83, 4, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"and", 2, 0x24, _, W|NoModrm, { Imm, Acc, 0} }, +{"and", 2, 0x80, 4, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"or", 2, 0x08, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"or", 2, 0x83, 1, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"or", 2, 0x0c, _, W|NoModrm, { Imm, Acc, 0} }, +{"or", 2, 0x80, 1, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"xor", 2, 0x30, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"xor", 2, 0x83, 6, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"xor", 2, 0x34, _, W|NoModrm, { Imm, Acc, 0} }, +{"xor", 2, 0x80, 6, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"adc", 2, 0x10, _, DW|Modrm, { Reg, Reg|Mem, 0} }, +{"adc", 2, 0x83, 2, Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"adc", 2, 0x14, _, W|NoModrm, { Imm, Acc, 0} }, +{"adc", 2, 0x80, 2, W|Modrm, { Imm, Reg|Mem, 0} }, + +{"neg", 1, 0xf6, 3, W|Modrm, { Reg|Mem, 0, 0} }, +{"not", 1, 0xf6, 2, W|Modrm, { Reg|Mem, 0, 0} }, + +{"aaa", 0, 0x37, _, NoModrm, { 0, 0, 0} }, +{"aas", 0, 0x3f, _, NoModrm, { 0, 0, 0} }, +{"daa", 0, 0x27, _, NoModrm, { 0, 0, 0} }, +{"das", 0, 0x2f, _, NoModrm, { 0, 0, 0} }, +{"aad", 0, 0xd50a, _, NoModrm, { 0, 0, 0} }, +{"aam", 0, 0xd40a, _, NoModrm, { 0, 0, 0} }, + +/* conversion insns */ +/* conversion: intel naming */ +{"cbw", 0, 0x98, _, NoModrm|Data16, { 0, 0, 0} }, +{"cwd", 0, 0x99, _, NoModrm|Data16, { 0, 0, 0} }, +{"cwde", 0, 0x98, _, NoModrm|Data32, { 0, 0, 0} }, +{"cdq", 0, 0x99, _, NoModrm|Data32, { 0, 0, 0} }, +/* att naming */ +{"cbtw", 0, 0x98, _, NoModrm|Data16, { 0, 0, 0} }, +{"cwtl", 0, 0x98, _, NoModrm|Data32, { 0, 0, 0} }, +{"cwtd", 0, 0x99, _, NoModrm|Data16, { 0, 0, 0} }, +{"cltd", 0, 0x99, _, NoModrm|Data32, { 0, 0, 0} }, + +/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are + expanding 64-bit multiplies, and *cannot* be selected to accomplish + 'imul %ebx, %eax' (opcode 0x0faf must be used in this case) + These multiplies can only be selected with single operand forms. */ +{"mul", 1, 0xf6, 4, W|Modrm, { Reg|Mem, 0, 0} }, +{"imul", 1, 0xf6, 5, W|Modrm, { Reg|Mem, 0, 0} }, + + + + +/* imulKludge here is needed to reverse the i.rm.reg & i.rm.regmem fields. + These instructions are exceptions: 'imul $2, %eax, %ecx' would put + '%eax' in the reg field and '%ecx' in the regmem field if we did not + switch them. */ +{"imul", 2, 0x0faf, _, Modrm|ReverseRegRegmem, { WordReg|Mem, WordReg, 0} }, +{"imul", 3, 0x6b, _, Modrm|ReverseRegRegmem, { Imm8S, WordReg|Mem, WordReg} }, +{"imul", 3, 0x69, _, Modrm|ReverseRegRegmem, { Imm16|Imm32, WordReg|Mem, WordReg} }, +/* + imul with 2 operands mimicks imul with 3 by puting register both + in i.rm.reg & i.rm.regmem fields +*/ +{"imul", 2, 0x6b, _, Modrm|imulKludge, { Imm8S, WordReg, 0} }, +{"imul", 2, 0x69, _, Modrm|imulKludge, { Imm16|Imm32, WordReg, 0} }, +{"div", 1, 0xf6, 6, W|Modrm, { Reg|Mem, 0, 0} }, +{"div", 2, 0xf6, 6, W|Modrm, { Reg|Mem, Acc, 0} }, +{"idiv", 1, 0xf6, 7, W|Modrm, { Reg|Mem, 0, 0} }, +{"idiv", 2, 0xf6, 7, W|Modrm, { Reg|Mem, Acc, 0} }, + +{"rol", 2, 0xd0, 0, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"rol", 2, 0xc0, 0, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"rol", 2, 0xd2, 0, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"rol", 1, 0xd0, 0, W|Modrm, { Reg|Mem, 0, 0} }, + +{"ror", 2, 0xd0, 1, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"ror", 2, 0xc0, 1, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"ror", 2, 0xd2, 1, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"ror", 1, 0xd0, 1, W|Modrm, { Reg|Mem, 0, 0} }, + +{"rcl", 2, 0xd0, 2, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"rcl", 2, 0xc0, 2, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"rcl", 2, 0xd2, 2, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"rcl", 1, 0xd0, 2, W|Modrm, { Reg|Mem, 0, 0} }, + +{"rcr", 2, 0xd0, 3, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"rcr", 2, 0xc0, 3, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"rcr", 2, 0xd2, 3, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"rcr", 1, 0xd0, 3, W|Modrm, { Reg|Mem, 0, 0} }, + +{"sal", 2, 0xd0, 4, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"sal", 2, 0xc0, 4, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"sal", 2, 0xd2, 4, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"sal", 1, 0xd0, 4, W|Modrm, { Reg|Mem, 0, 0} }, +{"shl", 2, 0xd0, 4, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"shl", 2, 0xc0, 4, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"shl", 2, 0xd2, 4, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"shl", 1, 0xd0, 4, W|Modrm, { Reg|Mem, 0, 0} }, + +{"shld", 3, 0x0fa4, _, Modrm, { Imm8, WordReg, WordReg|Mem} }, +{"shld", 3, 0x0fa5, _, Modrm, { ShiftCount, WordReg, WordReg|Mem} }, +{"shld", 2, 0x0fa5, _, Modrm, { WordReg, WordReg|Mem, 0} }, + +{"shr", 2, 0xd0, 5, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"shr", 2, 0xc0, 5, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"shr", 2, 0xd2, 5, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"shr", 1, 0xd0, 5, W|Modrm, { Reg|Mem, 0, 0} }, + +{"shrd", 3, 0x0fac, _, Modrm, { Imm8, WordReg, WordReg|Mem} }, +{"shrd", 3, 0x0fad, _, Modrm, { ShiftCount, WordReg, WordReg|Mem} }, +{"shrd", 2, 0x0fad, _, Modrm, { WordReg, WordReg|Mem, 0} }, + +{"sar", 2, 0xd0, 7, W|Modrm, { Imm1, Reg|Mem, 0} }, +{"sar", 2, 0xc0, 7, W|Modrm, { Imm8, Reg|Mem, 0} }, +{"sar", 2, 0xd2, 7, W|Modrm, { ShiftCount, Reg|Mem, 0} }, +{"sar", 1, 0xd0, 7, W|Modrm, { Reg|Mem, 0, 0} }, + +/* control transfer instructions */ +#define CALL_PC_RELATIVE 0xe8 +{"call", 1, 0xe8, _, JumpDword, { Disp32, 0, 0} }, +{"call", 1, 0xff, 2, Modrm|Data32, { Reg|Mem|JumpAbsolute, 0, 0} }, +{"callw", 1, 0xff, 2, Modrm|Data16, { Reg|Mem|JumpAbsolute, 0, 0} }, +#define CALL_FAR_IMMEDIATE 0x9a +{"lcall", 2, 0x9a, _, JumpInterSegment, { Imm16, Abs32|Imm32, 0} }, +{"lcall", 1, 0xff, 3, Modrm|Data32, { Mem, 0, 0} }, +{"lcallw", 1, 0xff, 3, Modrm|Data16, { Mem, 0, 0} }, + +#define JUMP_PC_RELATIVE 0xeb +{"jmp", 1, 0xeb, _, Jump, { Disp, 0, 0} }, +{"jmp", 1, 0xff, 4, Modrm, { Reg32|Mem|JumpAbsolute, 0, 0} }, +#define JUMP_FAR_IMMEDIATE 0xea +{"ljmp", 2, 0xea, _, JumpInterSegment, { Imm16, Imm32, 0} }, +{"ljmp", 1, 0xff, 5, Modrm|Data32, { Mem, 0, 0} }, + +{"ret", 0, 0xc3, _, NoModrm|Data32, { 0, 0, 0} }, +{"ret", 1, 0xc2, _, NoModrm|Data32, { Imm16, 0, 0} }, +{"retw", 0, 0xc3, _, NoModrm|Data16, { 0, 0, 0} }, +{"retw", 1, 0xc2, _, NoModrm|Data16, { Imm16, 0, 0} }, +{"lret", 0, 0xcb, _, NoModrm|Data32, { 0, 0, 0} }, +{"lret", 1, 0xca, _, NoModrm|Data32, { Imm16, 0, 0} }, +{"lretw", 0, 0xcb, _, NoModrm|Data16, { 0, 0, 0} }, +{"lretw", 1, 0xca, _, NoModrm|Data16, { Imm16, 0, 0} }, +{"enter", 2, 0xc8, _, NoModrm|Data32, { Imm16, Imm8, 0} }, +{"leave", 0, 0xc9, _, NoModrm|Data32, { 0, 0, 0} }, +{"enterw", 2, 0xc8, _, NoModrm|Data16, { Imm16, Imm8, 0} }, +{"leavew", 0, 0xc9, _, NoModrm|Data16, { 0, 0, 0} }, + +/* conditional jumps */ +{"jo", 1, 0x70, _, Jump, { Disp, 0, 0} }, + +{"jno", 1, 0x71, _, Jump, { Disp, 0, 0} }, + +{"jb", 1, 0x72, _, Jump, { Disp, 0, 0} }, +{"jc", 1, 0x72, _, Jump, { Disp, 0, 0} }, +{"jnae", 1, 0x72, _, Jump, { Disp, 0, 0} }, + +{"jnb", 1, 0x73, _, Jump, { Disp, 0, 0} }, +{"jnc", 1, 0x73, _, Jump, { Disp, 0, 0} }, +{"jae", 1, 0x73, _, Jump, { Disp, 0, 0} }, + +{"je", 1, 0x74, _, Jump, { Disp, 0, 0} }, +{"jz", 1, 0x74, _, Jump, { Disp, 0, 0} }, + +{"jne", 1, 0x75, _, Jump, { Disp, 0, 0} }, +{"jnz", 1, 0x75, _, Jump, { Disp, 0, 0} }, + +{"jbe", 1, 0x76, _, Jump, { Disp, 0, 0} }, +{"jna", 1, 0x76, _, Jump, { Disp, 0, 0} }, + +{"jnbe", 1, 0x77, _, Jump, { Disp, 0, 0} }, +{"ja", 1, 0x77, _, Jump, { Disp, 0, 0} }, + +{"js", 1, 0x78, _, Jump, { Disp, 0, 0} }, + +{"jns", 1, 0x79, _, Jump, { Disp, 0, 0} }, + +{"jp", 1, 0x7a, _, Jump, { Disp, 0, 0} }, +{"jpe", 1, 0x7a, _, Jump, { Disp, 0, 0} }, + +{"jnp", 1, 0x7b, _, Jump, { Disp, 0, 0} }, +{"jpo", 1, 0x7b, _, Jump, { Disp, 0, 0} }, + +{"jl", 1, 0x7c, _, Jump, { Disp, 0, 0} }, +{"jnge", 1, 0x7c, _, Jump, { Disp, 0, 0} }, + +{"jnl", 1, 0x7d, _, Jump, { Disp, 0, 0} }, +{"jge", 1, 0x7d, _, Jump, { Disp, 0, 0} }, + +{"jle", 1, 0x7e, _, Jump, { Disp, 0, 0} }, +{"jng", 1, 0x7e, _, Jump, { Disp, 0, 0} }, + +{"jnle", 1, 0x7f, _, Jump, { Disp, 0, 0} }, +{"jg", 1, 0x7f, _, Jump, { Disp, 0, 0} }, + +#if 0 /* XXX where are these macros used? + To get them working again, they need to take + an entire template as the parameter, + and check for Data16/Data32 flags. */ +/* these turn into pseudo operations when disp is larger than 8 bits */ +#define IS_JUMP_ON_CX_ZERO(o) \ + (o == 0x66e3) +#define IS_JUMP_ON_ECX_ZERO(o) \ + (o == 0xe3) +#endif + +{"jcxz", 1, 0xe3, _, JumpByte|Data16, { Disp, 0, 0} }, +{"jecxz", 1, 0xe3, _, JumpByte|Data32, { Disp, 0, 0} }, + +#define IS_LOOP_ECX_TIMES(o) \ + (o == 0xe2 || o == 0xe1 || o == 0xe0) + +{"loop", 1, 0xe2, _, JumpByte, { Disp, 0, 0} }, + +{"loopz", 1, 0xe1, _, JumpByte, { Disp, 0, 0} }, +{"loope", 1, 0xe1, _, JumpByte, { Disp, 0, 0} }, + +{"loopnz", 1, 0xe0, _, JumpByte, { Disp, 0, 0} }, +{"loopne", 1, 0xe0, _, JumpByte, { Disp, 0, 0} }, + +/* set byte on flag instructions */ +{"seto", 1, 0x0f90, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setno", 1, 0x0f91, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setb", 1, 0x0f92, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setc", 1, 0x0f92, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setnae", 1, 0x0f92, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setnb", 1, 0x0f93, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setnc", 1, 0x0f93, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setae", 1, 0x0f93, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"sete", 1, 0x0f94, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setz", 1, 0x0f94, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setne", 1, 0x0f95, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setnz", 1, 0x0f95, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setbe", 1, 0x0f96, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setna", 1, 0x0f96, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setnbe", 1, 0x0f97, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"seta", 1, 0x0f97, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"sets", 1, 0x0f98, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setns", 1, 0x0f99, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setp", 1, 0x0f9a, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setpe", 1, 0x0f9a, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setnp", 1, 0x0f9b, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setpo", 1, 0x0f9b, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setl", 1, 0x0f9c, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setnge", 1, 0x0f9c, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setnl", 1, 0x0f9d, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setge", 1, 0x0f9d, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setle", 1, 0x0f9e, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setng", 1, 0x0f9e, 0, Modrm, { Reg8|Mem, 0, 0} }, + +{"setnle", 1, 0x0f9f, 0, Modrm, { Reg8|Mem, 0, 0} }, +{"setg", 1, 0x0f9f, 0, Modrm, { Reg8|Mem, 0, 0} }, + +#define IS_STRING_INSTRUCTION(o) \ + ((o) == 0xa6 || (o) == 0x6c || (o) == 0x6e || (o) == 0x6e || \ + (o) == 0xac || (o) == 0xa4 || (o) == 0xae || (o) == 0xaa || \ + (o) == 0xd7) + +/* string manipulation */ +{"cmps", 0, 0xa6, _, W|NoModrm, { 0, 0, 0} }, +{"scmp", 0, 0xa6, _, W|NoModrm, { 0, 0, 0} }, +{"ins", 0, 0x6c, _, W|NoModrm, { 0, 0, 0} }, +{"outs", 0, 0x6e, _, W|NoModrm, { 0, 0, 0} }, +{"lods", 0, 0xac, _, W|NoModrm, { 0, 0, 0} }, +{"slod", 0, 0xac, _, W|NoModrm, { 0, 0, 0} }, +{"movs", 0, 0xa4, _, W|NoModrm, { 0, 0, 0} }, +{"smov", 0, 0xa4, _, W|NoModrm, { 0, 0, 0} }, +{"scas", 0, 0xae, _, W|NoModrm, { 0, 0, 0} }, +{"ssca", 0, 0xae, _, W|NoModrm, { 0, 0, 0} }, +{"stos", 0, 0xaa, _, W|NoModrm, { 0, 0, 0} }, +{"ssto", 0, 0xaa, _, W|NoModrm, { 0, 0, 0} }, +{"xlat", 0, 0xd7, _, NoModrm, { 0, 0, 0} }, + +/* bit manipulation */ +{"bsf", 2, 0x0fbc, _, Modrm|ReverseRegRegmem, { Reg|Mem, Reg, 0} }, +{"bsr", 2, 0x0fbd, _, Modrm|ReverseRegRegmem, { Reg|Mem, Reg, 0} }, +{"bt", 2, 0x0fa3, _, Modrm, { Reg, Reg|Mem, 0} }, +{"bt", 2, 0x0fba, 4, Modrm, { Imm8, Reg|Mem, 0} }, +{"btc", 2, 0x0fbb, _, Modrm, { Reg, Reg|Mem, 0} }, +{"btc", 2, 0x0fba, 7, Modrm, { Imm8, Reg|Mem, 0} }, +{"btr", 2, 0x0fb3, _, Modrm, { Reg, Reg|Mem, 0} }, +{"btr", 2, 0x0fba, 6, Modrm, { Imm8, Reg|Mem, 0} }, +{"bts", 2, 0x0fab, _, Modrm, { Reg, Reg|Mem, 0} }, +{"bts", 2, 0x0fba, 5, Modrm, { Imm8, Reg|Mem, 0} }, + +/* interrupts & op. sys insns */ +/* See gas/config/tc-i386.c for conversion of 'int $3' into the special + int 3 insn. */ +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +{"int", 1, 0xcd, _, NoModrm, { Imm8, 0, 0} }, +{"int3", 0, 0xcc, _, NoModrm, { 0, 0, 0} }, +{"into", 0, 0xce, _, NoModrm, { 0, 0, 0} }, +{"iret", 0, 0xcf, _, NoModrm|Data32, { 0, 0, 0} }, +{"iretw", 0, 0xcf, _, NoModrm|Data16, { 0, 0, 0} }, +/* i386sl, i486sl, later 486, and Pentium */ +{"rsm", 0, 0x0faa, _, NoModrm,{ 0, 0, 0} }, + +{"boundl", 2, 0x62, _, Modrm|Data32, { Reg32, Mem, 0} }, +{"boundw", 2, 0x62, _, Modrm|Data16, { Reg16, Mem, 0} }, + +{"hlt", 0, 0xf4, _, NoModrm, { 0, 0, 0} }, +{"wait", 0, 0x9b, _, NoModrm, { 0, 0, 0} }, +/* nop is actually 'xchgl %eax, %eax' */ +{"nop", 0, 0x90, _, NoModrm, { 0, 0, 0} }, + +/* protection control */ +{"arpl", 2, 0x63, _, Modrm, { Reg16, Reg16|Mem, 0} }, +{"lar", 2, 0x0f02, _, Modrm|ReverseRegRegmem, { WordReg|Mem, WordReg, 0} }, +{"lgdt", 1, 0x0f01, 2, Modrm, { Mem, 0, 0} }, +{"lidt", 1, 0x0f01, 3, Modrm, { Mem, 0, 0} }, +{"lldt", 1, 0x0f00, 2, Modrm, { WordReg|Mem, 0, 0} }, +{"lmsw", 1, 0x0f01, 6, Modrm, { WordReg|Mem, 0, 0} }, +{"lsl", 2, 0x0f03, _, Modrm|ReverseRegRegmem, { WordReg|Mem, WordReg, 0} }, +{"ltr", 1, 0x0f00, 3, Modrm, { WordReg|Mem, 0, 0} }, + +{"sgdt", 1, 0x0f01, 0, Modrm, { Mem, 0, 0} }, +{"sidt", 1, 0x0f01, 1, Modrm, { Mem, 0, 0} }, +{"sldt", 1, 0x0f00, 0, Modrm, { WordReg|Mem, 0, 0} }, +{"smsw", 1, 0x0f01, 4, Modrm, { WordReg|Mem, 0, 0} }, +{"str", 1, 0x0f00, 1, Modrm, { Reg16|Mem, 0, 0} }, + +{"verr", 1, 0x0f00, 4, Modrm, { WordReg|Mem, 0, 0} }, +{"verw", 1, 0x0f00, 5, Modrm, { WordReg|Mem, 0, 0} }, + +/* floating point instructions */ + +/* load */ +{"fld", 1, 0xd9c0, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"flds", 1, 0xd9, 0, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem float */ +{"fldl", 1, 0xdd, 0, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem double */ +{"fldl", 1, 0xd9c0, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"fild", 1, 0xdf, 0, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem word (16) */ +{"fildl", 1, 0xdb, 0, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem dword (32) */ +{"fildq",1, 0xdf, 5, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem qword (64) */ +{"fildll",1, 0xdf, 5, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem qword (64) */ +{"fldt", 1, 0xdb, 5, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem efloat */ +{"fbld", 1, 0xdf, 4, Modrm, { Mem, 0, 0} }, /* %st0 <-- mem bcd */ + +/* store (no pop) */ +{"fst", 1, 0xddd0, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"fsts", 1, 0xd9, 2, Modrm, { Mem, 0, 0} }, /* %st0 --> mem float */ +{"fstl", 1, 0xdd, 2, Modrm, { Mem, 0, 0} }, /* %st0 --> mem double */ +{"fstl", 1, 0xddd0, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"fist", 1, 0xdf, 2, Modrm, { Mem, 0, 0} }, /* %st0 --> mem word (16) */ +{"fistl", 1, 0xdb, 2, Modrm, { Mem, 0, 0} }, /* %st0 --> mem dword (32) */ + +/* store (with pop) */ +{"fstp", 1, 0xddd8, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"fstps", 1, 0xd9, 3, Modrm, { Mem, 0, 0} }, /* %st0 --> mem float */ +{"fstpl", 1, 0xdd, 3, Modrm, { Mem, 0, 0} }, /* %st0 --> mem double */ +{"fstpl", 1, 0xddd8, _, ShortForm, { FloatReg, 0, 0} }, /* register */ +{"fistp", 1, 0xdf, 3, Modrm, { Mem, 0, 0} }, /* %st0 --> mem word (16) */ +{"fistpl",1, 0xdb, 3, Modrm, { Mem, 0, 0} }, /* %st0 --> mem dword (32) */ +{"fistpq",1, 0xdf, 7, Modrm, { Mem, 0, 0} }, /* %st0 --> mem qword (64) */ +{"fistpll",1,0xdf, 7, Modrm, { Mem, 0, 0} }, /* %st0 --> mem qword (64) */ +{"fstpt", 1, 0xdb, 7, Modrm, { Mem, 0, 0} }, /* %st0 --> mem efloat */ +{"fbstp", 1, 0xdf, 6, Modrm, { Mem, 0, 0} }, /* %st0 --> mem bcd */ + +/* exchange %st with %st0 */ +{"fxch", 1, 0xd9c8, _, ShortForm, { FloatReg, 0, 0} }, +{"fxch", 0, 0xd9c9, _, NoModrm, { 0, 0, 0} }, /* alias for fxch %st, %st(1) */ + +/* comparison (without pop) */ +{"fcom", 1, 0xd8d0, _, ShortForm, { FloatReg, 0, 0} }, +{"fcoms", 1, 0xd8, 2, Modrm, { Mem, 0, 0} }, /* compare %st0, mem float */ +{"ficoml", 1, 0xda, 2, Modrm, { Mem, 0, 0} }, /* compare %st0, mem word */ +{"fcoml", 1, 0xdc, 2, Modrm, { Mem, 0, 0} }, /* compare %st0, mem double */ +{"fcoml", 1, 0xd8d0, _, ShortForm, { FloatReg, 0, 0} }, +{"ficoms", 1, 0xde, 2, Modrm, { Mem, 0, 0} }, /* compare %st0, mem dword */ + +/* comparison (with pop) */ +{"fcomp", 1, 0xd8d8, _, ShortForm, { FloatReg, 0, 0} }, +{"fcomps", 1, 0xd8, 3, Modrm, { Mem, 0, 0} }, /* compare %st0, mem float */ +{"ficompl", 1, 0xda, 3, Modrm, { Mem, 0, 0} }, /* compare %st0, mem word */ +{"fcompl", 1, 0xdc, 3, Modrm, { Mem, 0, 0} }, /* compare %st0, mem double */ +{"fcompl", 1, 0xd8d8, _, ShortForm, { FloatReg, 0, 0} }, +{"ficomps", 1, 0xde, 3, Modrm, { Mem, 0, 0} }, /* compare %st0, mem dword */ +{"fcompp", 0, 0xded9, _, NoModrm, { 0, 0, 0} }, /* compare %st0, %st1 & pop 2 */ + +/* unordered comparison (with pop) */ +{"fucom", 1, 0xdde0, _, ShortForm, { FloatReg, 0, 0} }, +{"fucomp", 1, 0xdde8, _, ShortForm, { FloatReg, 0, 0} }, +{"fucompp", 0, 0xdae9, _, NoModrm, { 0, 0, 0} }, /* ucompare %st0, %st1 & pop twice */ + +{"ftst", 0, 0xd9e4, _, NoModrm, { 0, 0, 0} }, /* test %st0 */ +{"fxam", 0, 0xd9e5, _, NoModrm, { 0, 0, 0} }, /* examine %st0 */ + +/* load constants into %st0 */ +{"fld1", 0, 0xd9e8, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- 1.0 */ +{"fldl2t", 0, 0xd9e9, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- log2(10) */ +{"fldl2e", 0, 0xd9ea, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- log2(e) */ +{"fldpi", 0, 0xd9eb, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- pi */ +{"fldlg2", 0, 0xd9ec, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- log10(2) */ +{"fldln2", 0, 0xd9ed, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- ln(2) */ +{"fldz", 0, 0xd9ee, _, NoModrm, { 0, 0, 0} }, /* %st0 <-- 0.0 */ + +/* arithmetic */ + +/* add */ +{"fadd", 1, 0xd8c0, _, ShortForm, { FloatReg, 0, 0} }, +{"fadd", 2, 0xd8c0, _, ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +{"fadd", 0, 0xdcc1, _, NoModrm, { 0, 0, 0} }, /* alias for fadd %st, %st(1) */ +{"faddp", 1, 0xdac0, _, ShortForm, { FloatReg, 0, 0} }, +{"faddp", 2, 0xdac0, _, ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +{"faddp", 0, 0xdec1, _, NoModrm, { 0, 0, 0} }, /* alias for faddp %st, %st(1) */ +{"fadds", 1, 0xd8, 0, Modrm, { Mem, 0, 0} }, +{"fiaddl", 1, 0xda, 0, Modrm, { Mem, 0, 0} }, +{"faddl", 1, 0xdc, 0, Modrm, { Mem, 0, 0} }, +{"fiadds", 1, 0xde, 0, Modrm, { Mem, 0, 0} }, + +/* sub */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fsub", 1, 0xd8e0, _, ShortForm, { FloatReg, 0, 0} }, +{"fsub", 2, 0xd8e0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fsub", 2, 0xdce8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fsub", 2, 0xdce0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fsub", 0, 0xdce1, _, NoModrm, { 0, 0, 0} }, +{"fsubp", 1, 0xdae0, _, ShortForm, { FloatReg, 0, 0} }, +{"fsubp", 2, 0xdae0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fsubp", 2, 0xdee8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fsubp", 2, 0xdee0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fsubp", 0, 0xdee1, _, NoModrm, { 0, 0, 0} }, +{"fsubs", 1, 0xd8, 4, Modrm, { Mem, 0, 0} }, +{"fisubl", 1, 0xda, 4, Modrm, { Mem, 0, 0} }, +{"fsubl", 1, 0xdc, 4, Modrm, { Mem, 0, 0} }, +{"fisubs", 1, 0xde, 4, Modrm, { Mem, 0, 0} }, + +/* sub reverse */ +{"fsubr", 1, 0xd8e8, _, ShortForm, { FloatReg, 0, 0} }, +{"fsubr", 2, 0xd8e8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fsubr", 2, 0xdce0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fsubr", 2, 0xdce8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fsubr", 0, 0xdce9, _, NoModrm, { 0, 0, 0} }, +{"fsubrp", 1, 0xdae8, _, ShortForm, { FloatReg, 0, 0} }, +{"fsubrp", 2, 0xdae8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fsubrp", 2, 0xdee0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fsubrp", 2, 0xdee8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fsubrp", 0, 0xdee9, _, NoModrm, { 0, 0, 0} }, +{"fsubrs", 1, 0xd8, 5, Modrm, { Mem, 0, 0} }, +{"fisubrl", 1, 0xda, 5, Modrm, { Mem, 0, 0} }, +{"fsubrl", 1, 0xdc, 5, Modrm, { Mem, 0, 0} }, +{"fisubrs", 1, 0xde, 5, Modrm, { Mem, 0, 0} }, + +/* mul */ +{"fmul", 1, 0xd8c8, _, ShortForm, { FloatReg, 0, 0} }, +{"fmul", 2, 0xd8c8, _, ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +{"fmul", 0, 0xdcc9, _, NoModrm, { 0, 0, 0} }, +{"fmulp", 1, 0xdac8, _, ShortForm, { FloatReg, 0, 0} }, +{"fmulp", 2, 0xdac8, _, ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +{"fmulp", 0, 0xdec9, _, NoModrm, { 0, 0, 0} }, +{"fmuls", 1, 0xd8, 1, Modrm, { Mem, 0, 0} }, +{"fimull", 1, 0xda, 1, Modrm, { Mem, 0, 0} }, +{"fmull", 1, 0xdc, 1, Modrm, { Mem, 0, 0} }, +{"fimuls", 1, 0xde, 1, Modrm, { Mem, 0, 0} }, + +/* div */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fdiv", 1, 0xd8f0, _, ShortForm, { FloatReg, 0, 0} }, +{"fdiv", 2, 0xd8f0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fdiv", 2, 0xdcf8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fdiv", 2, 0xdcf0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fdiv", 0, 0xdcf1, _, NoModrm, { 0, 0, 0} }, +{"fdivp", 1, 0xdaf0, _, ShortForm, { FloatReg, 0, 0} }, +{"fdivp", 2, 0xdaf0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fdivp", 2, 0xdef8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fdivp", 2, 0xdef0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fdivp", 0, 0xdef1, _, NoModrm, { 0, 0, 0} }, +{"fdivs", 1, 0xd8, 6, Modrm, { Mem, 0, 0} }, +{"fidivl", 1, 0xda, 6, Modrm, { Mem, 0, 0} }, +{"fdivl", 1, 0xdc, 6, Modrm, { Mem, 0, 0} }, +{"fidivs", 1, 0xde, 6, Modrm, { Mem, 0, 0} }, + +/* div reverse */ +{"fdivr", 1, 0xd8f8, _, ShortForm, { FloatReg, 0, 0} }, +{"fdivr", 2, 0xd8f8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fdivr", 2, 0xdcf0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fdivr", 2, 0xdcf8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fdivr", 0, 0xdcf9, _, NoModrm, { 0, 0, 0} }, +{"fdivrp", 1, 0xdaf8, _, ShortForm, { FloatReg, 0, 0} }, +{"fdivrp", 2, 0xdaf8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +#ifdef NON_BROKEN_OPCODES +{"fdivrp", 2, 0xdef0, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#else +{"fdivrp", 2, 0xdef8, _, ShortForm, { FloatAcc, FloatReg, 0} }, +#endif +{"fdivrp", 0, 0xdef9, _, NoModrm, { 0, 0, 0} }, +{"fdivrs", 1, 0xd8, 7, Modrm, { Mem, 0, 0} }, +{"fidivrl", 1, 0xda, 7, Modrm, { Mem, 0, 0} }, +{"fdivrl", 1, 0xdc, 7, Modrm, { Mem, 0, 0} }, +{"fidivrs", 1, 0xde, 7, Modrm, { Mem, 0, 0} }, + +{"f2xm1", 0, 0xd9f0, _, NoModrm, { 0, 0, 0} }, +{"fyl2x", 0, 0xd9f1, _, NoModrm, { 0, 0, 0} }, +{"fptan", 0, 0xd9f2, _, NoModrm, { 0, 0, 0} }, +{"fpatan", 0, 0xd9f3, _, NoModrm, { 0, 0, 0} }, +{"fxtract", 0, 0xd9f4, _, NoModrm, { 0, 0, 0} }, +{"fprem1", 0, 0xd9f5, _, NoModrm, { 0, 0, 0} }, +{"fdecstp", 0, 0xd9f6, _, NoModrm, { 0, 0, 0} }, +{"fincstp", 0, 0xd9f7, _, NoModrm, { 0, 0, 0} }, +{"fprem", 0, 0xd9f8, _, NoModrm, { 0, 0, 0} }, +{"fyl2xp1", 0, 0xd9f9, _, NoModrm, { 0, 0, 0} }, +{"fsqrt", 0, 0xd9fa, _, NoModrm, { 0, 0, 0} }, +{"fsincos", 0, 0xd9fb, _, NoModrm, { 0, 0, 0} }, +{"frndint", 0, 0xd9fc, _, NoModrm, { 0, 0, 0} }, +{"fscale", 0, 0xd9fd, _, NoModrm, { 0, 0, 0} }, +{"fsin", 0, 0xd9fe, _, NoModrm, { 0, 0, 0} }, +{"fcos", 0, 0xd9ff, _, NoModrm, { 0, 0, 0} }, + +{"fchs", 0, 0xd9e0, _, NoModrm, { 0, 0, 0} }, +{"fabs", 0, 0xd9e1, _, NoModrm, { 0, 0, 0} }, + +/* processor control */ +{"fninit", 0, 0xdbe3, _, NoModrm, { 0, 0, 0} }, +{"finit", 0, 0x9bdbe3, _, NoModrm, { 0, 0, 0} }, +{"fldcw", 1, 0xd9, 5, Modrm, { Mem, 0, 0} }, +{"fnstcw", 1, 0xd9, 7, Modrm, { Mem, 0, 0} }, +{"fstcw", 1, 0x9bd9, 7, Modrm, { Mem, 0, 0} }, +{"fnstsw", 1, 0xdfe0, _, NoModrm, { Acc, 0, 0} }, +{"fnstsw", 1, 0xdd, 7, Modrm, { Mem, 0, 0} }, +{"fnstsw", 0, 0xdfe0, _, NoModrm, { 0, 0, 0} }, +{"fstsw", 1, 0x9bdfe0, _, NoModrm, { Acc, 0, 0} }, +{"fstsw", 1, 0x9bdd, 7, Modrm, { Mem, 0, 0} }, +{"fstsw", 0, 0x9bdfe0, _, NoModrm, { 0, 0, 0} }, +{"fnclex", 0, 0xdbe2, _, NoModrm, { 0, 0, 0} }, +{"fclex", 0, 0x9bdbe2, _, NoModrm, { 0, 0, 0} }, +/* + We ignore the short format (287) versions of fstenv/fldenv & fsave/frstor + instructions; i'm not sure how to add them or how they are different. + My 386/387 book offers no details about this. +*/ +{"fnstenv", 1, 0xd9, 6, Modrm, { Mem, 0, 0} }, +{"fstenv", 1, 0x9bd9, 6, Modrm, { Mem, 0, 0} }, +{"fldenv", 1, 0xd9, 4, Modrm, { Mem, 0, 0} }, +{"fnsave", 1, 0xdd, 6, Modrm, { Mem, 0, 0} }, +{"fsave", 1, 0x9bdd, 6, Modrm, { Mem, 0, 0} }, +{"frstor", 1, 0xdd, 4, Modrm, { Mem, 0, 0} }, + +{"ffree", 1, 0xddc0, _, ShortForm, { FloatReg, 0, 0} }, +{"fnop", 0, 0xd9d0, _, NoModrm, { 0, 0, 0} }, +{"fwait", 0, 0x9b, _, NoModrm, { 0, 0, 0} }, + +/* + opcode prefixes; we allow them as seperate insns too + (see prefix table below) +*/ +{"aword", 0, 0x67, _, NoModrm, { 0, 0, 0} }, +{"addr16", 0, 0x67, _, NoModrm, { 0, 0, 0} }, +{"word", 0, 0x66, _, NoModrm, { 0, 0, 0} }, +{"data16", 0, 0x66, _, NoModrm, { 0, 0, 0} }, +{"lock", 0, 0xf0, _, NoModrm, { 0, 0, 0} }, +{"cs", 0, 0x2e, _, NoModrm, { 0, 0, 0} }, +{"ds", 0, 0x3e, _, NoModrm, { 0, 0, 0} }, +{"es", 0, 0x26, _, NoModrm, { 0, 0, 0} }, +{"fs", 0, 0x64, _, NoModrm, { 0, 0, 0} }, +{"gs", 0, 0x65, _, NoModrm, { 0, 0, 0} }, +{"ss", 0, 0x36, _, NoModrm, { 0, 0, 0} }, +{"rep", 0, 0xf3, _, NoModrm, { 0, 0, 0} }, +{"repe", 0, 0xf3, _, NoModrm, { 0, 0, 0} }, +{"repz", 0, 0xf3, _, NoModrm, { 0, 0, 0} }, +{"repne", 0, 0xf2, _, NoModrm, { 0, 0, 0} }, +{"repnz", 0, 0xf2, _, NoModrm, { 0, 0, 0} }, + +/* 486 extensions */ + +{"bswap", 1, 0x0fc8, _, ShortForm, { Reg32,0,0 } }, +{"xadd", 2, 0x0fc0, _, DW|Modrm, { Reg, Reg|Mem, 0 } }, +{"cmpxchg", 2, 0x0fb0, _, DW|Modrm, { Reg, Reg|Mem, 0 } }, +{"invd", 0, 0x0f08, _, NoModrm, { 0, 0, 0} }, +{"wbinvd", 0, 0x0f09, _, NoModrm, { 0, 0, 0} }, +{"invlpg", 1, 0x0f01, 7, Modrm, { Mem, 0, 0} }, + +/* 586 and late 486 extensions */ +{"cpuid", 0, 0x0fa2, _, NoModrm, { 0, 0, 0} }, + +/* Pentium extensions */ +{"wrmsr", 0, 0x0f30, _, NoModrm, { 0, 0, 0} }, +{"rdtsc", 0, 0x0f31, _, NoModrm, { 0, 0, 0} }, +{"rdmsr", 0, 0x0f32, _, NoModrm, { 0, 0, 0} }, +{"cmpxchg8b", 1, 0x0fc7, 1, Modrm, { Mem, 0, 0} }, + +/* Pentium Pro extensions */ +{"rdpmc", 0, 0x0f33, _, NoModrm, { 0, 0, 0} }, + +{"cmovo", 2, 0x0f40, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovno", 2, 0x0f41, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovb", 2, 0x0f42, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovae", 2, 0x0f43, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmove", 2, 0x0f44, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovne", 2, 0x0f45, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovbe", 2, 0x0f46, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmova", 2, 0x0f47, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovs", 2, 0x0f48, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovns", 2, 0x0f49, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovp", 2, 0x0f4a, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovnp", 2, 0x0f4b, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovl", 2, 0x0f4c, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovge", 2, 0x0f4d, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovle", 2, 0x0f4e, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, +{"cmovg", 2, 0x0f4f, _, W|Modrm|ReverseRegRegmem, { WordReg|WordMem, WordReg, 0} }, + +{"fcmovb", 2, 0xdac0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmove", 2, 0xdac8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovbe",2, 0xdad0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovu", 2, 0xdad8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnb", 2, 0xdbc0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovne", 2, 0xdbc8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnbe",2, 0xdbd0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnu", 2, 0xdbd8, _, ShortForm, { FloatReg, FloatAcc, 0} }, + +{"fcomi", 2, 0xdbf0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fucomi", 2, 0xdbe8, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcomip", 2, 0xdff0, _, ShortForm, { FloatReg, FloatAcc, 0} }, +{"fucomip",2, 0xdfe8, _, ShortForm, { FloatReg, FloatAcc, 0} }, + +{"", 0, 0, 0, 0, { 0, 0, 0} } /* sentinel */ +}; +#undef _ + +static const template *const i386_optab_end + = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]); + +/* 386 register table */ + +static const reg_entry i386_regtab[] = { + /* 8 bit regs */ + {"al", Reg8|Acc, 0}, {"cl", Reg8|ShiftCount, 1}, {"dl", Reg8, 2}, + {"bl", Reg8, 3}, + {"ah", Reg8, 4}, {"ch", Reg8, 5}, {"dh", Reg8, 6}, {"bh", Reg8, 7}, + /* 16 bit regs */ + {"ax", Reg16|Acc, 0}, {"cx", Reg16, 1}, {"dx", Reg16|InOutPortReg, 2}, {"bx", Reg16, 3}, + {"sp", Reg16, 4}, {"bp", Reg16, 5}, {"si", Reg16, 6}, {"di", Reg16, 7}, + /* 32 bit regs */ + {"eax", Reg32|Acc, 0}, {"ecx", Reg32, 1}, {"edx", Reg32, 2}, {"ebx", Reg32, 3}, + {"esp", Reg32, 4}, {"ebp", Reg32, 5}, {"esi", Reg32, 6}, {"edi", Reg32, 7}, + /* segment registers */ + {"es", SReg2, 0}, {"cs", SReg2, 1}, {"ss", SReg2, 2}, + {"ds", SReg2, 3}, {"fs", SReg3, 4}, {"gs", SReg3, 5}, + /* control registers */ + {"cr0", Control, 0}, {"cr2", Control, 2}, {"cr3", Control, 3}, + {"cr4", Control, 4}, + /* debug registers */ + {"db0", Debug, 0}, {"db1", Debug, 1}, {"db2", Debug, 2}, + {"db3", Debug, 3}, {"db6", Debug, 6}, {"db7", Debug, 7}, + {"dr0", Debug, 0}, {"dr1", Debug, 1}, {"dr2", Debug, 2}, + {"dr3", Debug, 3}, {"dr6", Debug, 6}, {"dr7", Debug, 7}, + /* test registers */ + {"tr3", Test, 3}, {"tr4", Test, 4}, {"tr5", Test, 5}, + {"tr6", Test, 6}, {"tr7", Test, 7}, + /* float registers */ + {"st(0)", FloatReg|FloatAcc, 0}, + {"st", FloatReg|FloatAcc, 0}, + {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, + {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, + {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7} +}; + +#define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ + +static const reg_entry *const i386_regtab_end + = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]); + +/* segment stuff */ +static const seg_entry cs = { "cs", 0x2e }; +static const seg_entry ds = { "ds", 0x3e }; +static const seg_entry ss = { "ss", 0x36 }; +static const seg_entry es = { "es", 0x26 }; +static const seg_entry fs = { "fs", 0x64 }; +static const seg_entry gs = { "gs", 0x65 }; +static const seg_entry null = { "", 0x0 }; + +/* + This table is used to store the default segment register implied by all + possible memory addressing modes. + It is indexed by the mode & modrm entries of the modrm byte as follows: + index = (mode<<3) | modrm; +*/ +static const seg_entry *const one_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &null, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +static const seg_entry *const two_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +static const prefix_entry i386_prefixtab[] = { +#define ADDR_PREFIX_OPCODE 0x67 + { "addr16", 0x67 }, /* address size prefix ==> 16bit addressing + * (How is this useful?) */ +#define WORD_PREFIX_OPCODE 0x66 + { "data16", 0x66 }, /* operand size prefix */ + { "lock", 0xf0 }, /* bus lock prefix */ + { "wait", 0x9b }, /* wait for coprocessor */ + { "cs", 0x2e }, { "ds", 0x3e }, /* segment overrides ... */ + { "es", 0x26 }, { "fs", 0x64 }, + { "gs", 0x65 }, { "ss", 0x36 }, +/* REPE & REPNE used to detect rep/repne with a non-string instruction */ +#define REPNE 0xf2 +#define REPE 0xf3 + { "rep", 0xf3 }, /* repeat string instructions */ + { "repe", 0xf3 }, { "repz", 0xf3 }, + { "repne", 0xf2 }, { "repnz", 0xf2 } +}; + +static const prefix_entry *const i386_prefixtab_end + = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]); + +/* end of i386-opcode.h */ diff --git a/contrib/gdb/include/opcode/i860.h b/contrib/gdb/include/opcode/i860.h new file mode 100644 index 000000000000..b6ebd25c6487 --- /dev/null +++ b/contrib/gdb/include/opcode/i860.h @@ -0,0 +1,491 @@ +/* Table of opcodes for the i860. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB 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 1, or (at your option) +any later version. + +GAS/GDB 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 GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ +struct i860_opcode +{ + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* Nonzero if this is a possible expand-instruction. */ + char expand; +}; + +enum expand_type +{ + E_MOV = 1, E_ADDR, E_U32, E_AND, E_S32, E_DELAY +}; + +/* + All i860 opcodes are 32 bits, except for the pseudoinstructions + and the operations utilizing a 32-bit address expression, an + unsigned 32-bit constant, or a signed 32-bit constant. + These opcodes are expanded into a two-instruction sequence for + any situation where the immediate operand does not fit in 32 bits. + In the case of the add and subtract operations the expansion is + to a three-instruction sequence (ex: orh, or, adds). In cases + where the address is to be relocated, the instruction is + expanded to handle the worse case, this could be optimized at + the final link if the actual address were known. + + The pseudoinstructions are: mov, fmov, pmov, nop, and fnop. + These instructions are implemented as a one or two instruction + sequence of other operations. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character + for each operand of the instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 src1 integer register. + 2 src2 integer register. + d dest register. + c ctrlreg control register. + i 16 bit immediate. + I 16 bit immediate, aligned. + 5 5 bit immediate. + l lbroff 26 bit PC relative immediate. + r sbroff 16 bit PC relative immediate. + s split 16 bit immediate. + S split 16 bit immediate, aligned. + e src1 floating point register. + f src2 floating point register. + g dest floating point register. + +*/ + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic must be + consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +static struct i860_opcode i860_opcodes[] = +{ + +/* REG-Format Instructions */ +{ "ld.c", 0x30000000, 0xcc000000, "c,d", 0 }, /* ld.c csrc2,idest */ +{ "ld.b", 0x00000000, 0xfc000000, "1(2),d", 0 }, /* ld.b isrc1(isrc2),idest */ +{ "ld.b", 0x04000000, 0xf8000000, "I(2),d", E_ADDR }, /* ld.b #const(isrc2),idest */ +{ "ld.s", 0x10000000, 0xec000001, "1(2),d", 0 }, /* ld.s isrc1(isrc2),idest */ +{ "ld.s", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.s #const(isrc2),idest */ +{ "ld.l", 0x10000001, 0xec000000, "1(2),d", 0 }, /* ld.l isrc1(isrc2),idest */ +{ "ld.l", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.l #const(isrc2),idest */ + +{ "st.c", 0x38000000, 0xc4000000, "1,c", 0 }, /* st.c isrc1ni,csrc2 */ +{ "st.b", 0x0c000000, 0xf0000000, "1,S(2)", E_ADDR }, /* st.b isrc1ni,#const(isrc2) */ +{ "st.s", 0x1c000000, 0xe0000000, "1,S(2)", E_ADDR }, /* st.s isrc1ni,#const(isrc2) */ +{ "st.l", 0x1c000001, 0xe0000000, "1,S(2)", E_ADDR }, /* st.l isrc1ni,#const(isrc2) */ + +{ "ixfr", 0x08000000, 0xf4000000, "1,g", 0 }, /* ixfr isrc1ni,fdest */ + +{ "fld.l", 0x20000002, 0xdc000001, "1(2),g", 0 }, /* fld.l isrc1(isrc2),fdest */ +{ "fld.l", 0x24000002, 0xd8000001, "i(2),g", E_ADDR }, /* fld.l #const(isrc2),fdest */ +{ "fld.l", 0x20000003, 0xdc000000, "1(2)++,g", 0 }, /* fld.l isrc1(isrc2)++,fdest */ +{ "fld.l", 0x24000003, 0xd8000000, "i(2)++,g", E_ADDR }, /* fld.l #const(isrc2)++,fdest */ +{ "fld.d", 0x20000000, 0xdc000007, "1(2),g", 0 }, /* fld.d isrc1(isrc2),fdest */ +{ "fld.d", 0x24000000, 0xd8000007, "i(2),g", E_ADDR }, /* fld.d #const(isrc2),fdest */ +{ "fld.d", 0x20000001, 0xdc000006, "1(2)++,g", 0 }, /* fld.d isrc1(isrc2)++,fdest */ +{ "fld.d", 0x24000001, 0xd8000006, "i(2)++,g", E_ADDR }, /* fld.d #const(isrc2)++,fdest */ +{ "fld.q", 0x20000004, 0xdc000003, "1(2),g", 0 }, /* fld.q isrc1(isrc2),fdest */ +{ "fld.q", 0x24000004, 0xd8000003, "i(2),g", E_ADDR }, /* fld.q #const(isrc2),fdest */ +{ "fld.q", 0x20000005, 0xdc000002, "1(2)++,g", 0 }, /* fld.q isrc1(isrc2)++,fdest */ +{ "fld.q", 0x24000005, 0xd8000002, "i(2)++,g", E_ADDR }, /* fld.q #const(isrc2)++,fdest */ + +{ "pfld.l", 0x60000000, 0x9c000003, "1(2),g", 0 }, /* pfld.l isrc1(isrc2),fdest */ +{ "pfld.l", 0x64000000, 0x98000003, "i(2),g", E_ADDR }, /* pfld.l #const(isrc2),fdest */ +{ "pfld.l", 0x60000001, 0x9c000002, "1(2)++,g", 0 }, /* pfld.l isrc1(isrc2)++,fdest */ +{ "pfld.l", 0x64000001, 0x98000002, "i(2)++,g", E_ADDR }, /* pfld.l #const(isrc2)++,fdest */ +{ "pfld.d", 0x60000000, 0x9c000007, "1(2),g", 0 }, /* pfld.d isrc1(isrc2),fdest */ +{ "pfld.d", 0x64000000, 0x98000007, "i(2),g", E_ADDR }, /* pfld.d #const(isrc2),fdest */ +{ "pfld.d", 0x60000001, 0x9c000006, "1(2)++,g", 0 }, /* pfld.d isrc1(isrc2)++,fdest */ +{ "pfld.d", 0x64000001, 0x98000006, "i(2)++,g", E_ADDR }, /* pfld.d #const(isrc2)++,fdest */ + +{ "fst.l", 0x28000002, 0xd4000001, "g,1(2)", 0 }, /* fst.l fdest,isrc1(isrc2) */ +{ "fst.l", 0x2c000002, 0xd0000001, "g,i(2)", E_ADDR }, /* fst.l fdest,#const(isrc2) */ +{ "fst.l", 0x28000003, 0xd4000000, "g,1(2)++", 0 }, /* fst.l fdest,isrc1(isrc2)++ */ +{ "fst.l", 0x2c000003, 0xd0000000, "g,i(2)++", E_ADDR }, /* fst.l fdest,#const(isrc2)++ */ +{ "fst.d", 0x28000000, 0xd4000007, "g,1(2)", 0 }, /* fst.d fdest,isrc1(isrc2) */ +{ "fst.d", 0x2c000000, 0xd0000007, "g,i(2)", E_ADDR }, /* fst.d fdest,#const(isrc2) */ +{ "fst.d", 0x28000001, 0xd4000006, "g,1(2)++", 0 }, /* fst.d fdest,isrc1(isrc2)++ */ +{ "fst.d", 0x2c000001, 0xd0000006, "g,i(2)++", E_ADDR }, /* fst.d fdest,#const(isrc2)++ */ + +{ "pst.d", 0x3c000000, 0xc0000007, "g,i(2)", E_ADDR }, /* pst.d fdest,#const(isrc2) */ +{ "pst.d", 0x3c000001, 0xc0000006, "g,i(2)++", E_ADDR }, /* pst.d fdest,#const(isrc2)++ */ + +{ "addu", 0x80000000, 0x7c000000, "1,2,d", 0 }, /* addu isrc1,isrc2,idest */ +{ "addu", 0x84000000, 0x78000000, "i,2,d", E_S32 }, /* addu #const,isrc2,idest */ +{ "adds", 0x90000000, 0x6c000000, "1,2,d", 0 }, /* adds isrc1,isrc2,idest */ +{ "adds", 0x94000000, 0x68000000, "i,2,d", E_S32 }, /* adds #const,isrc2,idest */ +{ "subu", 0x88000000, 0x74000000, "1,2,d", 0 }, /* subu isrc1,isrc2,idest */ +{ "subu", 0x8c000000, 0x70000000, "i,2,d", E_S32 }, /* subu #const,isrc2,idest */ +{ "subs", 0x98000000, 0x64000000, "1,2,d", 0 }, /* subs isrc1,isrc2,idest */ +{ "subs", 0x9c000000, 0x60000000, "i,2,d", E_S32 }, /* subs #const,isrc2,idest */ + +{ "shl", 0xa0000000, 0x5c000000, "1,2,d", 0 }, /* shl isrc1,isrc2,idest */ +{ "shl", 0xa4000000, 0x58000000, "i,2,d", 0 }, /* shl #const,isrc2,idest */ +{ "shr", 0xa8000000, 0x54000000, "1,2,d", 0 }, /* shr isrc1,isrc2,idest */ +{ "shr", 0xac000000, 0x50000000, "i,2,d", 0 }, /* shr #const,isrc2,idest */ +{ "shrd", 0xb0000000, 0x4c000000, "1,2,d", 0 }, /* shrd isrc1,isrc2,idest */ +{ "shra", 0xb8000000, 0x44000000, "1,2,d", 0 }, /* shra isrc1,isrc2,idest */ +{ "shra", 0xbc000000, 0x40000000, "i,2,d", 0 }, /* shra #const,isrc2,idest */ + +{ "mov", 0xa0000000, 0x5c00f800, "2,d", 0 }, /* shl r0,isrc2,idest */ +{ "mov", 0x94000000, 0x69e00000, "i,d", E_MOV }, /* adds #const,r0,idest */ +{ "nop", 0xa0000000, 0x5ffff800, "", 0 }, /* shl r0,r0,r0 */ +{ "fnop", 0xb0000000, 0x4ffff800, "", 0 }, /* shrd r0,r0,r0 */ + +{ "trap", 0x44000000, 0xb8000000, "1,2,d", 0 }, /* trap isrc1ni,isrc2,idest */ + +{ "flush", 0x34000000, 0xc81f0001, "i(2)", E_ADDR }, /* flush #const(isrc2) */ +{ "flush", 0x34000001, 0xc81f0000, "i(2)++", E_ADDR }, /* flush #const(isrc2)++ */ + +{ "and", 0xc0000000, 0x3c000000, "1,2,d", 0 }, /* and isrc1,isrc2,idest */ +{ "and", 0xc4000000, 0x38000000, "i,2,d", E_AND }, /* and #const,isrc2,idest */ +{ "andh", 0xc8000000, 0x34000000, "1,2,d", 0 }, /* andh isrc1,isrc2,idest */ +{ "andh", 0xcc000000, 0x30000000, "i,2,d", 0 }, /* andh #const,isrc2,idest */ +{ "andnot", 0xd0000000, 0x2c000000, "1,2,d", 0 }, /* andnot isrc1,isrc2,idest */ +{ "andnot", 0xd4000000, 0x28000000, "i,2,d", E_U32 }, /* andnot #const,isrc2,idest */ +{ "andnoth", 0xd8000000, 0x24000000, "1,2,d", 0 }, /* andnoth isrc1,isrc2,idest */ +{ "andnoth", 0xdc000000, 0x20000000, "i,2,d", 0 }, /* andnoth #const,isrc2,idest */ +{ "or", 0xe0000000, 0x1c000000, "1,2,d", 0 }, /* or isrc1,isrc2,idest */ +{ "or", 0xe4000000, 0x18000000, "i,2,d", E_U32 }, /* or #const,isrc2,idest */ +{ "orh", 0xe8000000, 0x14000000, "1,2,d", 0 }, /* orh isrc1,isrc2,idest */ +{ "orh", 0xec000000, 0x10000000, "i,2,d", 0 }, /* orh #const,isrc2,idest */ +{ "xor", 0xf0000000, 0x0c000000, "1,2,d", 0 }, /* xor isrc1,isrc2,idest */ +{ "xor", 0xf4000000, 0x08000000, "i,2,d", E_U32 }, /* xor #const,isrc2,idest */ +{ "xorh", 0xf8000000, 0x04000000, "1,2,d", 0 }, /* xorh isrc1,isrc2,idest */ +{ "xorh", 0xfc000000, 0x00000000, "i,2,d", 0 }, /* xorh #const,isrc2,idest */ + +{ "bte", 0x58000000, 0xa4000000, "1,2,s", 0 }, /* bte isrc1s,isrc2,sbroff */ +{ "bte", 0x5c000000, 0xa0000000, "5,2,s", 0 }, /* bte #const5,isrc2,sbroff */ +{ "btne", 0x50000000, 0xac000000, "1,2,s", 0 }, /* btne isrc1s,isrc2,sbroff */ +{ "btne", 0x54000000, 0xa8000000, "5,2,s", 0 }, /* btne #const5,isrc2,sbroff */ +{ "bla", 0xb4000000, 0x48000000, "1,2,s", E_DELAY }, /* bla isrc1s,isrc2,sbroff */ +{ "bri", 0x40000000, 0xbc000000, "1", E_DELAY }, /* bri isrc1ni */ + +/* Core Escape Instruction Format */ +{ "lock", 0x4c000001, 0xb000001e, "", 0 }, /* lock set BL in dirbase */ +{ "calli", 0x4c000002, 0xb000001d, "1", E_DELAY }, /* calli isrc1ni */ +{ "intovr", 0x4c000004, 0xb000001b, "", 0 }, /* intovr trap on integer overflow */ +{ "unlock", 0x4c000007, 0xb0000018, "", 0 }, /* unlock clear BL in dirbase */ + +/* CTRL-Format Instructions */ +{ "br", 0x68000000, 0x94000000, "l", E_DELAY }, /* br lbroff */ +{ "call", 0x6c000000, 0x90000000, "l", E_DELAY }, /* call lbroff */ +{ "bc", 0x70000000, 0x8c000000, "l", 0 }, /* bc lbroff */ +{ "bc.t", 0x74000000, 0x88000000, "l", E_DELAY }, /* bc.t lbroff */ +{ "bnc", 0x78000000, 0x84000000, "l", 0 }, /* bnc lbroff */ +{ "bnc.t", 0x7c000000, 0x80000000, "l", E_DELAY }, /* bnc.t lbroff */ + +/* Floating Point Escape Instruction Format - pfam.p fsrc1,fsrc2,fdest */ +{ "r2p1.ss", 0x48000400, 0xb40003ff, "e,f,g", 0 }, +{ "r2p1.sd", 0x48000480, 0xb400037f, "e,f,g", 0 }, +{ "r2p1.dd", 0x48000580, 0xb400027f, "e,f,g", 0 }, +{ "r2pt.ss", 0x48000401, 0xb40003fe, "e,f,g", 0 }, +{ "r2pt.sd", 0x48000481, 0xb400037e, "e,f,g", 0 }, +{ "r2pt.dd", 0x48000581, 0xb400027e, "e,f,g", 0 }, +{ "r2ap1.ss", 0x48000402, 0xb40003fd, "e,f,g", 0 }, +{ "r2ap1.sd", 0x48000482, 0xb400037d, "e,f,g", 0 }, +{ "r2ap1.dd", 0x48000582, 0xb400027d, "e,f,g", 0 }, +{ "r2apt.ss", 0x48000403, 0xb40003fc, "e,f,g", 0 }, +{ "r2apt.sd", 0x48000483, 0xb400037c, "e,f,g", 0 }, +{ "r2apt.dd", 0x48000583, 0xb400027c, "e,f,g", 0 }, +{ "i2p1.ss", 0x48000404, 0xb40003fb, "e,f,g", 0 }, +{ "i2p1.sd", 0x48000484, 0xb400037b, "e,f,g", 0 }, +{ "i2p1.dd", 0x48000584, 0xb400027b, "e,f,g", 0 }, +{ "i2pt.ss", 0x48000405, 0xb40003fa, "e,f,g", 0 }, +{ "i2pt.sd", 0x48000485, 0xb400037a, "e,f,g", 0 }, +{ "i2pt.dd", 0x48000585, 0xb400027a, "e,f,g", 0 }, +{ "i2ap1.ss", 0x48000406, 0xb40003f9, "e,f,g", 0 }, +{ "i2ap1.sd", 0x48000486, 0xb4000379, "e,f,g", 0 }, +{ "i2ap1.dd", 0x48000586, 0xb4000279, "e,f,g", 0 }, +{ "i2apt.ss", 0x48000407, 0xb40003f8, "e,f,g", 0 }, +{ "i2apt.sd", 0x48000487, 0xb4000378, "e,f,g", 0 }, +{ "i2apt.dd", 0x48000587, 0xb4000278, "e,f,g", 0 }, +{ "rat1p2.ss", 0x48000408, 0xb40003f7, "e,f,g", 0 }, +{ "rat1p2.sd", 0x48000488, 0xb4000377, "e,f,g", 0 }, +{ "rat1p2.dd", 0x48000588, 0xb4000277, "e,f,g", 0 }, +{ "m12apm.ss", 0x48000409, 0xb40003f6, "e,f,g", 0 }, +{ "m12apm.sd", 0x48000489, 0xb4000376, "e,f,g", 0 }, +{ "m12apm.dd", 0x48000589, 0xb4000276, "e,f,g", 0 }, +{ "ra1p2.ss", 0x4800040a, 0xb40003f5, "e,f,g", 0 }, +{ "ra1p2.sd", 0x4800048a, 0xb4000375, "e,f,g", 0 }, +{ "ra1p2.dd", 0x4800058a, 0xb4000275, "e,f,g", 0 }, +{ "m12ttpa.ss", 0x4800040b, 0xb40003f4, "e,f,g", 0 }, +{ "m12ttpa.sd", 0x4800048b, 0xb4000374, "e,f,g", 0 }, +{ "m12ttpa.dd", 0x4800058b, 0xb4000274, "e,f,g", 0 }, +{ "iat1p2.ss", 0x4800040c, 0xb40003f3, "e,f,g", 0 }, +{ "iat1p2.sd", 0x4800048c, 0xb4000373, "e,f,g", 0 }, +{ "iat1p2.dd", 0x4800058c, 0xb4000273, "e,f,g", 0 }, +{ "m12tpm.ss", 0x4800040d, 0xb40003f2, "e,f,g", 0 }, +{ "m12tpm.sd", 0x4800048d, 0xb4000372, "e,f,g", 0 }, +{ "m12tpm.dd", 0x4800058d, 0xb4000272, "e,f,g", 0 }, +{ "ia1p2.ss", 0x4800040e, 0xb40003f1, "e,f,g", 0 }, +{ "ia1p2.sd", 0x4800048e, 0xb4000371, "e,f,g", 0 }, +{ "ia1p2.dd", 0x4800058e, 0xb4000271, "e,f,g", 0 }, +{ "m12tpa.ss", 0x4800040f, 0xb40003f0, "e,f,g", 0 }, +{ "m12tpa.sd", 0x4800048f, 0xb4000370, "e,f,g", 0 }, +{ "m12tpa.dd", 0x4800058f, 0xb4000270, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfsm.p fsrc1,fsrc2,fdest */ +{ "r2s1.ss", 0x48000410, 0xb40003ef, "e,f,g", 0 }, +{ "r2s1.sd", 0x48000490, 0xb400036f, "e,f,g", 0 }, +{ "r2s1.dd", 0x48000590, 0xb400026f, "e,f,g", 0 }, +{ "r2st.ss", 0x48000411, 0xb40003ee, "e,f,g", 0 }, +{ "r2st.sd", 0x48000491, 0xb400036e, "e,f,g", 0 }, +{ "r2st.dd", 0x48000591, 0xb400026e, "e,f,g", 0 }, +{ "r2as1.ss", 0x48000412, 0xb40003ed, "e,f,g", 0 }, +{ "r2as1.sd", 0x48000492, 0xb400036d, "e,f,g", 0 }, +{ "r2as1.dd", 0x48000592, 0xb400026d, "e,f,g", 0 }, +{ "r2ast.ss", 0x48000413, 0xb40003ec, "e,f,g", 0 }, +{ "r2ast.sd", 0x48000493, 0xb400036c, "e,f,g", 0 }, +{ "r2ast.dd", 0x48000593, 0xb400026c, "e,f,g", 0 }, +{ "i2s1.ss", 0x48000414, 0xb40003eb, "e,f,g", 0 }, +{ "i2s1.sd", 0x48000494, 0xb400036b, "e,f,g", 0 }, +{ "i2s1.dd", 0x48000594, 0xb400026b, "e,f,g", 0 }, +{ "i2st.ss", 0x48000415, 0xb40003ea, "e,f,g", 0 }, +{ "i2st.sd", 0x48000495, 0xb400036a, "e,f,g", 0 }, +{ "i2st.dd", 0x48000595, 0xb400026a, "e,f,g", 0 }, +{ "i2as1.ss", 0x48000416, 0xb40003e9, "e,f,g", 0 }, +{ "i2as1.sd", 0x48000496, 0xb4000369, "e,f,g", 0 }, +{ "i2as1.dd", 0x48000596, 0xb4000269, "e,f,g", 0 }, +{ "i2ast.ss", 0x48000417, 0xb40003e8, "e,f,g", 0 }, +{ "i2ast.sd", 0x48000497, 0xb4000368, "e,f,g", 0 }, +{ "i2ast.dd", 0x48000597, 0xb4000268, "e,f,g", 0 }, +{ "rat1s2.ss", 0x48000418, 0xb40003e7, "e,f,g", 0 }, +{ "rat1s2.sd", 0x48000498, 0xb4000367, "e,f,g", 0 }, +{ "rat1s2.dd", 0x48000598, 0xb4000267, "e,f,g", 0 }, +{ "m12asm.ss", 0x48000419, 0xb40003e6, "e,f,g", 0 }, +{ "m12asm.sd", 0x48000499, 0xb4000366, "e,f,g", 0 }, +{ "m12asm.dd", 0x48000599, 0xb4000266, "e,f,g", 0 }, +{ "ra1s2.ss", 0x4800041a, 0xb40003e5, "e,f,g", 0 }, +{ "ra1s2.sd", 0x4800049a, 0xb4000365, "e,f,g", 0 }, +{ "ra1s2.dd", 0x4800059a, 0xb4000265, "e,f,g", 0 }, +{ "m12ttsa.ss", 0x4800041b, 0xb40003e4, "e,f,g", 0 }, +{ "m12ttsa.sd", 0x4800049b, 0xb4000364, "e,f,g", 0 }, +{ "m12ttsa.dd", 0x4800059b, 0xb4000264, "e,f,g", 0 }, +{ "iat1s2.ss", 0x4800041c, 0xb40003e3, "e,f,g", 0 }, +{ "iat1s2.sd", 0x4800049c, 0xb4000363, "e,f,g", 0 }, +{ "iat1s2.dd", 0x4800059c, 0xb4000263, "e,f,g", 0 }, +{ "m12tsm.ss", 0x4800041d, 0xb40003e2, "e,f,g", 0 }, +{ "m12tsm.sd", 0x4800049d, 0xb4000362, "e,f,g", 0 }, +{ "m12tsm.dd", 0x4800059d, 0xb4000262, "e,f,g", 0 }, +{ "ia1s2.ss", 0x4800041e, 0xb40003e1, "e,f,g", 0 }, +{ "ia1s2.sd", 0x4800049e, 0xb4000361, "e,f,g", 0 }, +{ "ia1s2.dd", 0x4800059e, 0xb4000261, "e,f,g", 0 }, +{ "m12tsa.ss", 0x4800041f, 0xb40003e0, "e,f,g", 0 }, +{ "m12tsa.sd", 0x4800049f, 0xb4000360, "e,f,g", 0 }, +{ "m12tsa.dd", 0x4800059f, 0xb4000260, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmam.p fsrc1,fsrc2,fdest */ +{ "mr2p1.ss", 0x48000000, 0xb40007ff, "e,f,g", 0 }, +{ "mr2p1.sd", 0x48000080, 0xb400077f, "e,f,g", 0 }, +{ "mr2p1.dd", 0x48000180, 0xb400067f, "e,f,g", 0 }, +{ "mr2pt.ss", 0x48000001, 0xb40007fe, "e,f,g", 0 }, +{ "mr2pt.sd", 0x48000081, 0xb400077e, "e,f,g", 0 }, +{ "mr2pt.dd", 0x48000181, 0xb400067e, "e,f,g", 0 }, +{ "mr2mp1.ss", 0x48000002, 0xb40007fd, "e,f,g", 0 }, +{ "mr2mp1.sd", 0x48000082, 0xb400077d, "e,f,g", 0 }, +{ "mr2mp1.dd", 0x48000182, 0xb400067d, "e,f,g", 0 }, +{ "mr2mpt.ss", 0x48000003, 0xb40007fc, "e,f,g", 0 }, +{ "mr2mpt.sd", 0x48000083, 0xb400077c, "e,f,g", 0 }, +{ "mr2mpt.dd", 0x48000183, 0xb400067c, "e,f,g", 0 }, +{ "mi2p1.ss", 0x48000004, 0xb40007fb, "e,f,g", 0 }, +{ "mi2p1.sd", 0x48000084, 0xb400077b, "e,f,g", 0 }, +{ "mi2p1.dd", 0x48000184, 0xb400067b, "e,f,g", 0 }, +{ "mi2pt.ss", 0x48000005, 0xb40007fa, "e,f,g", 0 }, +{ "mi2pt.sd", 0x48000085, 0xb400077a, "e,f,g", 0 }, +{ "mi2pt.dd", 0x48000185, 0xb400067a, "e,f,g", 0 }, +{ "mi2mp1.ss", 0x48000006, 0xb40007f9, "e,f,g", 0 }, +{ "mi2mp1.sd", 0x48000086, 0xb4000779, "e,f,g", 0 }, +{ "mi2mp1.dd", 0x48000186, 0xb4000679, "e,f,g", 0 }, +{ "mi2mpt.ss", 0x48000007, 0xb40007f8, "e,f,g", 0 }, +{ "mi2mpt.sd", 0x48000087, 0xb4000778, "e,f,g", 0 }, +{ "mi2mpt.dd", 0x48000187, 0xb4000678, "e,f,g", 0 }, +{ "mrmt1p2.ss", 0x48000008, 0xb40007f7, "e,f,g", 0 }, +{ "mrmt1p2.sd", 0x48000088, 0xb4000777, "e,f,g", 0 }, +{ "mrmt1p2.dd", 0x48000188, 0xb4000677, "e,f,g", 0 }, +{ "mm12mpm.ss", 0x48000009, 0xb40007f6, "e,f,g", 0 }, +{ "mm12mpm.sd", 0x48000089, 0xb4000776, "e,f,g", 0 }, +{ "mm12mpm.dd", 0x48000189, 0xb4000676, "e,f,g", 0 }, +{ "mrm1p2.ss", 0x4800000a, 0xb40007f5, "e,f,g", 0 }, +{ "mrm1p2.sd", 0x4800008a, 0xb4000775, "e,f,g", 0 }, +{ "mrm1p2.dd", 0x4800018a, 0xb4000675, "e,f,g", 0 }, +{ "mm12ttpm.ss",0x4800000b, 0xb40007f4, "e,f,g", 0 }, +{ "mm12ttpm.sd",0x4800008b, 0xb4000774, "e,f,g", 0 }, +{ "mm12ttpm.dd",0x4800018b, 0xb4000674, "e,f,g", 0 }, +{ "mimt1p2.ss", 0x4800000c, 0xb40007f3, "e,f,g", 0 }, +{ "mimt1p2.sd", 0x4800008c, 0xb4000773, "e,f,g", 0 }, +{ "mimt1p2.dd", 0x4800018c, 0xb4000673, "e,f,g", 0 }, +{ "mm12tpm.ss", 0x4800000d, 0xb40007f2, "e,f,g", 0 }, +{ "mm12tpm.sd", 0x4800008d, 0xb4000772, "e,f,g", 0 }, +{ "mm12tpm.dd", 0x4800018d, 0xb4000672, "e,f,g", 0 }, +{ "mim1p2.ss", 0x4800000e, 0xb40007f1, "e,f,g", 0 }, +{ "mim1p2.sd", 0x4800008e, 0xb4000771, "e,f,g", 0 }, +{ "mim1p2.dd", 0x4800018e, 0xb4000671, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmsm.p fsrc1,fsrc2,fdest */ +{ "mr2s1.ss", 0x48000010, 0xb40007ef, "e,f,g", 0 }, +{ "mr2s1.sd", 0x48000090, 0xb400076f, "e,f,g", 0 }, +{ "mr2s1.dd", 0x48000190, 0xb400066f, "e,f,g", 0 }, +{ "mr2st.ss", 0x48000011, 0xb40007ee, "e,f,g", 0 }, +{ "mr2st.sd", 0x48000091, 0xb400076e, "e,f,g", 0 }, +{ "mr2st.dd", 0x48000191, 0xb400066e, "e,f,g", 0 }, +{ "mr2ms1.ss", 0x48000012, 0xb40007ed, "e,f,g", 0 }, +{ "mr2ms1.sd", 0x48000092, 0xb400076d, "e,f,g", 0 }, +{ "mr2ms1.dd", 0x48000192, 0xb400066d, "e,f,g", 0 }, +{ "mr2mst.ss", 0x48000013, 0xb40007ec, "e,f,g", 0 }, +{ "mr2mst.sd", 0x48000093, 0xb400076c, "e,f,g", 0 }, +{ "mr2mst.dd", 0x48000193, 0xb400066c, "e,f,g", 0 }, +{ "mi2s1.ss", 0x48000014, 0xb40007eb, "e,f,g", 0 }, +{ "mi2s1.sd", 0x48000094, 0xb400076b, "e,f,g", 0 }, +{ "mi2s1.dd", 0x48000194, 0xb400066b, "e,f,g", 0 }, +{ "mi2st.ss", 0x48000015, 0xb40007ea, "e,f,g", 0 }, +{ "mi2st.sd", 0x48000095, 0xb400076a, "e,f,g", 0 }, +{ "mi2st.dd", 0x48000195, 0xb400066a, "e,f,g", 0 }, +{ "mi2ms1.ss", 0x48000016, 0xb40007e9, "e,f,g", 0 }, +{ "mi2ms1.sd", 0x48000096, 0xb4000769, "e,f,g", 0 }, +{ "mi2ms1.dd", 0x48000196, 0xb4000669, "e,f,g", 0 }, +{ "mi2mst.ss", 0x48000017, 0xb40007e8, "e,f,g", 0 }, +{ "mi2mst.sd", 0x48000097, 0xb4000768, "e,f,g", 0 }, +{ "mi2mst.dd", 0x48000197, 0xb4000668, "e,f,g", 0 }, +{ "mrmt1s2.ss", 0x48000018, 0xb40007e7, "e,f,g", 0 }, +{ "mrmt1s2.sd", 0x48000098, 0xb4000767, "e,f,g", 0 }, +{ "mrmt1s2.dd", 0x48000198, 0xb4000667, "e,f,g", 0 }, +{ "mm12msm.ss", 0x48000019, 0xb40007e6, "e,f,g", 0 }, +{ "mm12msm.sd", 0x48000099, 0xb4000766, "e,f,g", 0 }, +{ "mm12msm.dd", 0x48000199, 0xb4000666, "e,f,g", 0 }, +{ "mrm1s2.ss", 0x4800001a, 0xb40007e5, "e,f,g", 0 }, +{ "mrm1s2.sd", 0x4800009a, 0xb4000765, "e,f,g", 0 }, +{ "mrm1s2.dd", 0x4800019a, 0xb4000665, "e,f,g", 0 }, +{ "mm12ttsm.ss",0x4800001b, 0xb40007e4, "e,f,g", 0 }, +{ "mm12ttsm.sd",0x4800009b, 0xb4000764, "e,f,g", 0 }, +{ "mm12ttsm.dd",0x4800019b, 0xb4000664, "e,f,g", 0 }, +{ "mimt1s2.ss", 0x4800001c, 0xb40007e3, "e,f,g", 0 }, +{ "mimt1s2.sd", 0x4800009c, 0xb4000763, "e,f,g", 0 }, +{ "mimt1s2.dd", 0x4800019c, 0xb4000663, "e,f,g", 0 }, +{ "mm12tsm.ss", 0x4800001d, 0xb40007e2, "e,f,g", 0 }, +{ "mm12tsm.sd", 0x4800009d, 0xb4000762, "e,f,g", 0 }, +{ "mm12tsm.dd", 0x4800019d, 0xb4000662, "e,f,g", 0 }, +{ "mim1s2.ss", 0x4800001e, 0xb40007e1, "e,f,g", 0 }, +{ "mim1s2.sd", 0x4800009e, 0xb4000761, "e,f,g", 0 }, +{ "mim1s2.dd", 0x4800019e, 0xb4000661, "e,f,g", 0 }, + + +{ "fmul.ss", 0x48000020, 0xb40007df, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.sd", 0x480000a0, 0xb400075f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.dd", 0x480001a0, 0xb400065f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.ss", 0x48000420, 0xb40003df, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.sd", 0x480004a0, 0xb400035f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.dd", 0x480005a0, 0xb400025f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul3.dd", 0x480005a4, 0xb400025b, "e,f,g", 0 }, /* pfmul3.p fsrc1,fsrc2,fdest */ +{ "fmlow.dd", 0x480001a1, 0xb400065e, "e,f,g", 0 }, /* fmlow.dd fsrc1,fsrc2,fdest */ +{ "frcp.ss", 0x48000022, 0xb40007dd, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.sd", 0x480000a2, 0xb400075d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.dd", 0x480001a2, 0xb400065d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frsqr.ss", 0x48000023, 0xb40007dc, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.sd", 0x480000a3, 0xb400075c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.dd", 0x480001a3, 0xb400065c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "fadd.ss", 0x48000030, 0xb40007cf, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.sd", 0x480000b0, 0xb400074f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.dd", 0x480001b0, 0xb400064f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.ss", 0x48000430, 0xb40003cf, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.sd", 0x480004b0, 0xb400034f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.dd", 0x480005b0, 0xb400024f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "fsub.ss", 0x48000031, 0xb40007ce, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.sd", 0x480000b1, 0xb400074e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.dd", 0x480001b1, 0xb400064e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.ss", 0x48000431, 0xb40003ce, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.sd", 0x480004b1, 0xb400034e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.dd", 0x480005b1, 0xb400024e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "fix.ss", 0x48000032, 0xb40007cd, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "fix.sd", 0x480000b2, 0xb400074d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "fix.dd", 0x480001b2, 0xb400064d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "pfix.ss", 0x48000432, 0xb40003cd, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "pfix.sd", 0x480004b2, 0xb400034d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "pfix.dd", 0x480005b2, 0xb400024d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "famov.ss", 0x48000033, 0xb40007cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.ds", 0x48000133, 0xb40006cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.sd", 0x480000b3, 0xb400074c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.dd", 0x480001b3, 0xb400064c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "pfamov.ss", 0x48000433, 0xb40003cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.ds", 0x48000533, 0xb40002cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.sd", 0x480004b3, 0xb400034c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.dd", 0x480005b3, 0xb400024c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +/* pfgt has R bit cleared; pfle has R bit set */ +{ "pfgt.ss", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +{ "pfgt.sd", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +{ "pfgt.dd", 0x48000534, 0xb40002cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +/* pfgt has R bit cleared; pfle has R bit set */ +{ "pfle.ss", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfle.sd", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfle.dd", 0x480005b4, 0xb400024b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "ftrunc.ss", 0x4800003a, 0xb40007c5, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "ftrunc.sd", 0x480000ba, 0xb4000745, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "ftrunc.dd", 0x480001ba, 0xb4000645, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "pftrunc.ss", 0x4800043a, 0xb40003c5, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "pftrunc.sd", 0x480004ba, 0xb4000345, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "pftrunc.dd", 0x480005ba, 0xb4000245, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "fxfr", 0x48000040, 0xb40007bf, "e,d", 0 }, /* fxfr fsrc1,idest */ +{ "fiadd.ss", 0x48000049, 0xb40007b6, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "fiadd.dd", 0x480001c9, 0xb4000636, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.ss", 0x48000449, 0xb40003b6, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.dd", 0x480005c9, 0xb4000236, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "fisub.ss", 0x4800004d, 0xb40007b2, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "fisub.dd", 0x480001cd, 0xb4000632, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.ss", 0x4800044d, 0xb40003b2, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.dd", 0x480005cd, 0xb4000232, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "fzchkl", 0x48000057, 0xb40007a8, "e,f,g", 0 }, /* fzchkl fsrc1,fsrc2,fdest */ +{ "pfzchkl", 0x48000457, 0xb40003a8, "e,f,g", 0 }, /* pfzchkl fsrc1,fsrc2,fdest */ +{ "fzchks", 0x4800005f, 0xb40007a0, "e,f,g", 0 }, /* fzchks fsrc1,fsrc2,fdest */ +{ "pfzchks", 0x4800045f, 0xb40003a0, "e,f,g", 0 }, /* pfzchks fsrc1,fsrc2,fdest */ +{ "faddp", 0x48000050, 0xb40007af, "e,f,g", 0 }, /* faddp fsrc1,fsrc2,fdest */ +{ "pfaddp", 0x48000450, 0xb40003af, "e,f,g", 0 }, /* pfaddp fsrc1,fsrc2,fdest */ +{ "faddz", 0x48000051, 0xb40007ae, "e,f,g", 0 }, /* faddz fsrc1,fsrc2,fdest */ +{ "pfaddz", 0x48000451, 0xb40003ae, "e,f,g", 0 }, /* pfaddz fsrc1,fsrc2,fdest */ +{ "form", 0x4800005a, 0xb40007a5, "e,g", 0 }, /* form fsrc1,fdest */ +{ "pform", 0x4800045a, 0xb40003a5, "e,g", 0 }, /* pform fsrc1,fdest */ + +/* Floating point pseudo-instructions */ +{ "fmov.ss", 0x48000049, 0xb7e007b6, "e,g", 0 }, /* fiadd.ss fsrc1,f0,fdest */ +{ "fmov.dd", 0x480001c9, 0xb7e00636, "e,g", 0 }, /* fiadd.dd fsrc1,f0,fdest */ +{ "fmov.sd", 0x480000b0, 0xb7e0074f, "e,g", 0 }, /* fadd.sd fsrc1,f0,fdest */ +{ "fmov.ds", 0x48000130, 0xb7e006cf, "e,g", 0 }, /* fadd.ds fsrc1,f0,fdest */ +{ "pfmov.ds", 0x48000530, 0xb73002cf, "e,g", 0 }, /* pfadd.ds fsrc1,f0,fdest */ +{ "pfmov.dd", 0x480005c9, 0xb7e00236, "e,g", 0 }, /* pfiadd.dd fsrc1,f0,fdest */ + + +}; + +#define NUMOPCODES ((sizeof i860_opcodes)/(sizeof i860_opcodes[0])) + + diff --git a/contrib/gdb/include/opcode/i960.h b/contrib/gdb/include/opcode/i960.h new file mode 100644 index 000000000000..8030ad8a843e --- /dev/null +++ b/contrib/gdb/include/opcode/i960.h @@ -0,0 +1,509 @@ +/* Basic 80960 instruction formats. + * + * The 'COJ' instructions are actually COBR instructions with the 'b' in + * the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary: + * if the displacement will not fit in 13 bits, the assembler will replace them + * with the corresponding compare and branch instructions. + * + * All of the 'MEMn' instructions are the same format; the 'n' in the name + * indicates the default index scale factor (the size of the datum operated on). + * + * The FBRA formats are not actually an instruction format. They are the + * "convenience directives" for branching on floating-point comparisons, + * each of which generates 2 instructions (a 'bno' and one other branch). + * + * The CALLJ format is not actually an instruction format. It indicates that + * the instruction generated (a CTRL-format 'call') should have its relocation + * specially flagged for link-time replacement with a 'bal' or 'calls' if + * appropriate. + */ + +#define CTRL 0 +#define COBR 1 +#define COJ 2 +#define REG 3 +#define MEM1 4 +#define MEM2 5 +#define MEM4 6 +#define MEM8 7 +#define MEM12 8 +#define MEM16 9 +#define FBRA 10 +#define CALLJ 11 + +/* Masks for the mode bits in REG format instructions */ +#define M1 0x0800 +#define M2 0x1000 +#define M3 0x2000 + +/* Generate the 12-bit opcode for a REG format instruction by placing the + * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits + * 7-10. + */ + +#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7) + +/* Generate a template for a REG format instruction: place the opcode bits + * in the appropriate fields and OR in mode bits for the operands that will not + * be used. I.e., + * set m1=1, if src1 will not be used + * set m2=1, if src2 will not be used + * set m3=1, if dst will not be used + * + * Setting the "unused" mode bits to 1 speeds up instruction execution(!). + * The information is also useful to us because some 1-operand REG instructions + * use the src1 field, others the dst field; and some 2-operand REG instructions + * use src1/src2, others src1/dst. The set mode bits enable us to distinguish. + */ +#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */ +#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */ +#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */ +#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */ +#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */ +#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */ + +/* DESCRIPTOR BYTES FOR REGISTER OPERANDS + * + * Interpret names as follows: + * R: global or local register only + * RS: global, local, or (if target allows) special-function register only + * RL: global or local register, or integer literal + * RSL: global, local, or (if target allows) special-function register; + * or integer literal + * F: global, local, or floating-point register + * FL: global, local, or floating-point register; or literal (including + * floating point) + * + * A number appended to a name indicates that registers must be aligned, + * as follows: + * 2: register number must be multiple of 2 + * 4: register number must be multiple of 4 + */ + +#define SFR 0x10 /* Mask for the "sfr-OK" bit */ +#define LIT 0x08 /* Mask for the "literal-OK" bit */ +#define FP 0x04 /* Mask for "floating-point-OK" bit */ + +/* This macro ors the bits together. Note that 'align' is a mask + * for the low 0, 1, or 2 bits of the register number, as appropriate. + */ +#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr ) + +#define R OP( 0, 0, 0, 0 ) +#define RS OP( 0, 0, 0, SFR ) +#define RL OP( 0, LIT, 0, 0 ) +#define RSL OP( 0, LIT, 0, SFR ) +#define F OP( 0, 0, FP, 0 ) +#define FL OP( 0, LIT, FP, 0 ) +#define R2 OP( 1, 0, 0, 0 ) +#define RL2 OP( 1, LIT, 0, 0 ) +#define F2 OP( 1, 0, FP, 0 ) +#define FL2 OP( 1, LIT, FP, 0 ) +#define R4 OP( 3, 0, 0, 0 ) +#define RL4 OP( 3, LIT, 0, 0 ) +#define F4 OP( 3, 0, FP, 0 ) +#define FL4 OP( 3, LIT, FP, 0 ) + +#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */ + +/* Macros to extract info from the register operand descriptor byte 'od'. + */ +#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */ +#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */ +#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */ +#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0) + /* TRUE if reg #n is properly aligned */ +#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/ + +/* Description of a single i80960 instruction */ +struct i960_opcode { + long opcode; /* 32 bits, constant fields filled in, rest zeroed */ + char *name; /* Assembler mnemonic */ + short iclass; /* Class: see #defines below */ + char format; /* REG, COBR, CTRL, MEMn, COJ, FBRA, or CALLJ */ + char num_ops; /* Number of operands */ + char operand[3];/* Operand descriptors; same order as assembler instr */ +}; + +/* Classes of 960 intructions: + * - each instruction falls into one class. + * - each target architecture supports one or more classes. + * + * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass(). + */ +#define I_BASE 0x01 /* 80960 base instruction set */ +#define I_CX 0x02 /* 80960Cx instruction */ +#define I_DEC 0x04 /* Decimal instruction */ +#define I_FP 0x08 /* Floating point instruction */ +#define I_KX 0x10 /* 80960Kx instruction */ +#define I_MIL 0x20 /* Military instruction */ +#define I_CASIM 0x40 /* CA simulator instruction */ +#define I_CX2 0x80 /* Cx/Jx/Hx instructions */ +#define I_JX 0x100 /* Jx/Hx instruction */ +#define I_HX 0x200 /* Hx instructions */ + +/****************************************************************************** + * + * TABLE OF i960 INSTRUCTION DESCRIPTIONS + * + ******************************************************************************/ + +const struct i960_opcode i960_opcodes[] = { + + /* if a CTRL instruction has an operand, it's always a displacement */ + + /* callj default=='call' */ + { 0x09000000, "callj", I_BASE, CALLJ, 1, { 0, 0, 0 } }, + { 0x08000000, "b", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x09000000, "call", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x0a000000, "ret", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x0b000000, "bal", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x10000000, "bno", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* bf same as bno */ + { 0x10000000, "bf", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* bru same as bno */ + { 0x10000000, "bru", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x11000000, "bg", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* brg same as bg */ + { 0x11000000, "brg", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x12000000, "be", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* bre same as be */ + { 0x12000000, "bre", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x13000000, "bge", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* brge same as bge */ + { 0x13000000, "brge", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x14000000, "bl", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* brl same as bl */ + { 0x14000000, "brl", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x15000000, "bne", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* brlg same as bne */ + { 0x15000000, "brlg", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x16000000, "ble", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* brle same as ble */ + { 0x16000000, "brle", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x17000000, "bo", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* bt same as bo */ + { 0x17000000, "bt", I_BASE, CTRL, 1, { 0, 0, 0 } }, + /* bro same as bo */ + { 0x17000000, "bro", I_BASE, CTRL, 1, { 0, 0, 0 } }, + { 0x18000000, "faultno", I_BASE, CTRL, 0, { 0, 0, 0 } }, + /* faultf same as faultno */ + { 0x18000000, "faultf", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x19000000, "faultg", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1a000000, "faulte", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1b000000, "faultge", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1c000000, "faultl", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1d000000, "faultne", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1e000000, "faultle", I_BASE, CTRL, 0, { 0, 0, 0 } }, + { 0x1f000000, "faulto", I_BASE, CTRL, 0, { 0, 0, 0 } }, + /* faultt syn for faulto */ + { 0x1f000000, "faultt", I_BASE, CTRL, 0, { 0, 0, 0 } }, + + { 0x01000000, "syscall", I_CASIM,CTRL, 0, { 0, 0, 0 } }, + + /* If a COBR (or COJ) has 3 operands, the last one is always a + * displacement and does not appear explicitly in the table. + */ + + { 0x20000000, "testno", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x21000000, "testg", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x22000000, "teste", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x23000000, "testge", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x24000000, "testl", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x25000000, "testne", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x26000000, "testle", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x27000000, "testo", I_BASE, COBR, 1, { R, 0, 0 } }, + { 0x30000000, "bbc", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x31000000, "cmpobg", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x32000000, "cmpobe", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x33000000, "cmpobge", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x34000000, "cmpobl", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x35000000, "cmpobne", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x36000000, "cmpoble", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x37000000, "bbs", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x38000000, "cmpibno", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x39000000, "cmpibg", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3a000000, "cmpibe", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3b000000, "cmpibge", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3c000000, "cmpibl", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3d000000, "cmpibne", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3e000000, "cmpible", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x3f000000, "cmpibo", I_BASE, COBR, 3, { RL, RS, 0 } }, + { 0x31000000, "cmpojg", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x32000000, "cmpoje", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x33000000, "cmpojge", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x34000000, "cmpojl", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x35000000, "cmpojne", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x36000000, "cmpojle", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x38000000, "cmpijno", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x39000000, "cmpijg", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3a000000, "cmpije", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3b000000, "cmpijge", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3c000000, "cmpijl", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3d000000, "cmpijne", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3e000000, "cmpijle", I_BASE, COJ, 3, { RL, RS, 0 } }, + { 0x3f000000, "cmpijo", I_BASE, COJ, 3, { RL, RS, 0 } }, + + { 0x80000000, "ldob", I_BASE, MEM1, 2, { M, R, 0 } }, + { 0x82000000, "stob", I_BASE, MEM1, 2, { R, M, 0 } }, + { 0x84000000, "bx", I_BASE, MEM1, 1, { M, 0, 0 } }, + { 0x85000000, "balx", I_BASE, MEM1, 2, { M, R, 0 } }, + { 0x86000000, "callx", I_BASE, MEM1, 1, { M, 0, 0 } }, + { 0x88000000, "ldos", I_BASE, MEM2, 2, { M, R, 0 } }, + { 0x8a000000, "stos", I_BASE, MEM2, 2, { R, M, 0 } }, + { 0x8c000000, "lda", I_BASE, MEM1, 2, { M, R, 0 } }, + { 0x90000000, "ld", I_BASE, MEM4, 2, { M, R, 0 } }, + { 0x92000000, "st", I_BASE, MEM4, 2, { R, M, 0 } }, + { 0x98000000, "ldl", I_BASE, MEM8, 2, { M, R2, 0 } }, + { 0x9a000000, "stl", I_BASE, MEM8, 2, { R2, M, 0 } }, + { 0xa0000000, "ldt", I_BASE, MEM12, 2, { M, R4, 0 } }, + { 0xa2000000, "stt", I_BASE, MEM12, 2, { R4, M, 0 } }, + { 0xb0000000, "ldq", I_BASE, MEM16, 2, { M, R4, 0 } }, + { 0xb2000000, "stq", I_BASE, MEM16, 2, { R4, M, 0 } }, + { 0xc0000000, "ldib", I_BASE, MEM1, 2, { M, R, 0 } }, + { 0xc2000000, "stib", I_BASE, MEM1, 2, { R, M, 0 } }, + { 0xc8000000, "ldis", I_BASE, MEM2, 2, { M, R, 0 } }, + { 0xca000000, "stis", I_BASE, MEM2, 2, { R, M, 0 } }, + + { R_3(0x580), "notbit", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x581), "and", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x582), "andnot", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x583), "setbit", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x584), "notand", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x586), "xor", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x587), "or", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x588), "nor", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x589), "xnor", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_2D(0x58a), "not", I_BASE, REG, 2, { RSL,RS, 0 } }, + { R_3(0x58b), "ornot", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x58c), "clrbit", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x58d), "notor", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x58e), "nand", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x58f), "alterbit", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x590), "addo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x591), "addi", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x592), "subo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x593), "subi", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x598), "shro", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x59a), "shrdi", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x59b), "shri", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x59c), "shlo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x59d), "rotate", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x59e), "shli", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_2(0x5a0), "cmpo", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x5a1), "cmpi", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x5a2), "concmpo", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x5a3), "concmpi", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_3(0x5a4), "cmpinco", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x5a5), "cmpinci", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x5a6), "cmpdeco", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x5a7), "cmpdeci", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_2(0x5ac), "scanbyte", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x5ae), "chkbit", I_BASE, REG, 2, { RSL,RSL, 0 } }, + { R_3(0x5b0), "addc", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x5b2), "subc", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_2D(0x5cc), "mov", I_BASE, REG, 2, { RSL,RS, 0 } }, + { R_2D(0x5dc), "movl", I_BASE, REG, 2, { RL2,R2, 0 } }, + { R_2D(0x5ec), "movt", I_BASE, REG, 2, { RL4,R4, 0 } }, + { R_2D(0x5fc), "movq", I_BASE, REG, 2, { RL4,R4, 0 } }, + { R_3(0x610), "atmod", I_BASE, REG, 3, { RS, RSL,R } }, + { R_3(0x612), "atadd", I_BASE, REG, 3, { RS, RSL,RS } }, + { R_2D(0x640), "spanbit", I_BASE, REG, 2, { RSL,RS, 0 } }, + { R_2D(0x641), "scanbit", I_BASE, REG, 2, { RSL,RS, 0 } }, + { R_3(0x645), "modac", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x650), "modify", I_BASE, REG, 3, { RSL,RSL,R } }, + { R_3(0x651), "extract", I_BASE, REG, 3, { RSL,RSL,R } }, + { R_3(0x654), "modtc", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x655), "modpc", I_BASE, REG, 3, { RSL,RSL,R } }, + { R_1(0x660), "calls", I_BASE, REG, 1, { RSL, 0, 0 } }, + { R_0(0x66b), "mark", I_BASE, REG, 0, { 0, 0, 0 } }, + { R_0(0x66c), "fmark", I_BASE, REG, 0, { 0, 0, 0 } }, + { R_0(0x66d), "flushreg", I_BASE, REG, 0, { 0, 0, 0 } }, + { R_0(0x66f), "syncf", I_BASE, REG, 0, { 0, 0, 0 } }, + { R_3(0x670), "emul", I_BASE, REG, 3, { RSL,RSL,R2 } }, + { R_3(0x671), "ediv", I_BASE, REG, 3, { RSL,RL2,RS } }, + { R_2D(0x672), "cvtadr", I_CASIM,REG, 2, { RL, R2, 0 } }, + { R_3(0x701), "mulo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x708), "remo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x70b), "divo", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x741), "muli", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x748), "remi", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x749), "modi", I_BASE, REG, 3, { RSL,RSL,RS } }, + { R_3(0x74b), "divi", I_BASE, REG, 3, { RSL,RSL,RS } }, + + /* Floating-point instructions */ + + { R_2D(0x674), "cvtir", I_FP, REG, 2, { RL, F, 0 } }, + { R_2D(0x675), "cvtilr", I_FP, REG, 2, { RL, F, 0 } }, + { R_3(0x676), "scalerl", I_FP, REG, 3, { RL, FL2,F2 } }, + { R_3(0x677), "scaler", I_FP, REG, 3, { RL, FL, F } }, + { R_3(0x680), "atanr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x681), "logepr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x682), "logr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x683), "remr", I_FP, REG, 3, { FL, FL, F } }, + { R_2(0x684), "cmpor", I_FP, REG, 2, { FL, FL, 0 } }, + { R_2(0x685), "cmpr", I_FP, REG, 2, { FL, FL, 0 } }, + { R_2D(0x688), "sqrtr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x689), "expr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x68a), "logbnr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x68b), "roundr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x68c), "sinr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x68d), "cosr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x68e), "tanr", I_FP, REG, 2, { FL, F, 0 } }, + { R_1(0x68f), "classr", I_FP, REG, 1, { FL, 0, 0 } }, + { R_3(0x690), "atanrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x691), "logeprl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x692), "logrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x693), "remrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_2(0x694), "cmporl", I_FP, REG, 2, { FL2,FL2, 0 } }, + { R_2(0x695), "cmprl", I_FP, REG, 2, { FL2,FL2, 0 } }, + { R_2D(0x698), "sqrtrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x699), "exprl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x69a), "logbnrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x69b), "roundrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x69c), "sinrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x69d), "cosrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x69e), "tanrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_1(0x69f), "classrl", I_FP, REG, 1, { FL2, 0, 0 } }, + { R_2D(0x6c0), "cvtri", I_FP, REG, 2, { FL, R, 0 } }, + { R_2D(0x6c1), "cvtril", I_FP, REG, 2, { FL, R2, 0 } }, + { R_2D(0x6c2), "cvtzri", I_FP, REG, 2, { FL, R, 0 } }, + { R_2D(0x6c3), "cvtzril", I_FP, REG, 2, { FL, R2, 0 } }, + { R_2D(0x6c9), "movr", I_FP, REG, 2, { FL, F, 0 } }, + { R_2D(0x6d9), "movrl", I_FP, REG, 2, { FL2,F2, 0 } }, + { R_2D(0x6e1), "movre", I_FP, REG, 2, { FL4,F4, 0 } }, + { R_3(0x6e2), "cpysre", I_FP, REG, 3, { FL4,FL4,F4 } }, + { R_3(0x6e3), "cpyrsre", I_FP, REG, 3, { FL4,FL4,F4 } }, + { R_3(0x78b), "divr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x78c), "mulr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x78d), "subr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x78f), "addr", I_FP, REG, 3, { FL, FL, F } }, + { R_3(0x79b), "divrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x79c), "mulrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x79d), "subrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + { R_3(0x79f), "addrl", I_FP, REG, 3, { FL2,FL2,F2 } }, + + /* These are the floating point branch instructions. Each actually + * generates 2 branch instructions: the first a CTRL instruction with + * the indicated opcode, and the second a 'bno'. + */ + + { 0x12000000, "brue", I_FP, FBRA, 1, { 0, 0, 0 } }, + { 0x11000000, "brug", I_FP, FBRA, 1, { 0, 0, 0 } }, + { 0x13000000, "bruge", I_FP, FBRA, 1, { 0, 0, 0 } }, + { 0x14000000, "brul", I_FP, FBRA, 1, { 0, 0, 0 } }, + { 0x16000000, "brule", I_FP, FBRA, 1, { 0, 0, 0 } }, + { 0x15000000, "brulg", I_FP, FBRA, 1, { 0, 0, 0 } }, + + + /* Decimal instructions */ + + { R_3(0x642), "daddc", I_DEC, REG, 3, { RSL,RSL,RS } }, + { R_3(0x643), "dsubc", I_DEC, REG, 3, { RSL,RSL,RS } }, + { R_2D(0x644), "dmovt", I_DEC, REG, 2, { RSL,RS, 0 } }, + + + /* KX extensions */ + + { R_2(0x600), "synmov", I_KX, REG, 2, { R, R, 0 } }, + { R_2(0x601), "synmovl", I_KX, REG, 2, { R, R, 0 } }, + { R_2(0x602), "synmovq", I_KX, REG, 2, { R, R, 0 } }, + { R_2D(0x615), "synld", I_KX, REG, 2, { R, R, 0 } }, + + + /* MC extensions */ + + { R_3(0x603), "cmpstr", I_MIL, REG, 3, { R, R, RL } }, + { R_3(0x604), "movqstr", I_MIL, REG, 3, { R, R, RL } }, + { R_3(0x605), "movstr", I_MIL, REG, 3, { R, R, RL } }, + { R_2D(0x613), "inspacc", I_MIL, REG, 2, { R, R, 0 } }, + { R_2D(0x614), "ldphy", I_MIL, REG, 2, { R, R, 0 } }, + { R_3(0x617), "fill", I_MIL, REG, 3, { R, RL, RL } }, + { R_2D(0x646), "condrec", I_MIL, REG, 2, { R, R, 0 } }, + { R_2D(0x656), "receive", I_MIL, REG, 2, { R, R, 0 } }, + { R_3(0x662), "send", I_MIL, REG, 3, { R, RL, R } }, + { R_1(0x663), "sendserv", I_MIL, REG, 1, { R, 0, 0 } }, + { R_1(0x664), "resumprcs", I_MIL, REG, 1, { R, 0, 0 } }, + { R_1(0x665), "schedprcs", I_MIL, REG, 1, { R, 0, 0 } }, + { R_0(0x666), "saveprcs", I_MIL, REG, 0, { 0, 0, 0 } }, + { R_1(0x668), "condwait", I_MIL, REG, 1, { R, 0, 0 } }, + { R_1(0x669), "wait", I_MIL, REG, 1, { R, 0, 0 } }, + { R_1(0x66a), "signal", I_MIL, REG, 1, { R, 0, 0 } }, + { R_1D(0x673), "ldtime", I_MIL, REG, 1, { R2, 0, 0 } }, + + + /* CX extensions */ + + { R_3(0x5d8), "eshro", I_CX2, REG, 3, { RSL,RSL,RS } }, + { R_3(0x630), "sdma", I_CX, REG, 3, { RSL,RSL,RL } }, + { R_3(0x631), "udma", I_CX, REG, 0, { 0, 0, 0 } }, + { R_3(0x659), "sysctl", I_CX2, REG, 3, { RSL,RSL,RL } }, + + + /* Jx extensions. */ + { R_3(0x780), "addono", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x790), "addog", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7a0), "addoe", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7b0), "addoge", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7c0), "addol", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7d0), "addone", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7e0), "addole", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7f0), "addoo", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x781), "addino", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x791), "addig", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7a1), "addie", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7b1), "addige", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7c1), "addil", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7d1), "addine", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7e1), "addile", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7f1), "addio", I_JX, REG, 3, { RSL,RSL,RS } }, + + { R_2D(0x5ad), "bswap", I_JX, REG, 2, { RSL, RS, 0 } }, + + { R_2(0x594), "cmpob", I_JX, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x595), "cmpib", I_JX, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x596), "cmpos", I_JX, REG, 2, { RSL,RSL, 0 } }, + { R_2(0x597), "cmpis", I_JX, REG, 2, { RSL,RSL, 0 } }, + + { R_3(0x784), "selno", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x794), "selg", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7a4), "sele", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7b4), "selge", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7c4), "sell", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7d4), "selne", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7e4), "selle", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7f4), "selo", I_JX, REG, 3, { RSL,RSL,RS } }, + + { R_3(0x782), "subono", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x792), "subog", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7a2), "suboe", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7b2), "suboge", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7c2), "subol", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7d2), "subone", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7e2), "subole", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7f2), "suboo", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x783), "subino", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x793), "subig", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7a3), "subie", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7b3), "subige", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7c3), "subil", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7d3), "subine", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7e3), "subile", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_3(0x7f3), "subio", I_JX, REG, 3, { RSL,RSL,RS } }, + + { R_3(0x65c), "dcctl", I_JX, REG, 3, { RSL,RSL,RL } }, + { R_3(0x65b), "icctl", I_JX, REG, 3, { RSL,RSL,RS } }, + { R_2D(0x658), "intctl", I_JX, REG, 2, { RSL, RS, 0 } }, + { R_0(0x5b4), "intdis", I_JX, REG, 0, { 0, 0, 0 } }, + { R_0(0x5b5), "inten", I_JX, REG, 0, { 0, 0, 0 } }, + { R_0(0x65d), "halt", I_JX, REG, 0, { 0, 0, 0 } }, + + /* Hx extensions. */ + { 0xac000000, "dcinva", I_HX, MEM1, 1, { M, 0, 0 } }, + + /* END OF TABLE */ + + { 0, NULL, 0, 0, 0, { 0, 0, 0 } } +}; + + /* end of i960-opcode.h */ diff --git a/contrib/gdb/include/opcode/m68k.h b/contrib/gdb/include/opcode/m68k.h new file mode 100644 index 000000000000..e0b371c92bb7 --- /dev/null +++ b/contrib/gdb/include/opcode/m68k.h @@ -0,0 +1,297 @@ +/* Opcode table header for m680[01234]0/m6888[12]/m68851. + Copyright 1989, 1991, 1992, 1993, 1994, 1995 Free Software Foundation. + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* These are used as bit flags for the arch field in the m68k_opcode + structure. */ +#define _m68k_undef 0 +#define m68000 0x001 +#define m68008 m68000 /* synonym for -m68000. otherwise unused. */ +#define m68010 0x002 +#define m68020 0x004 +#define m68030 0x008 +#define m68ec030 m68030 /* similar enough to -m68030 to ignore differences; + gas will deal with the few differences. */ +#define m68040 0x010 +/* there is no 68050 */ +#define m68060 0x020 +#define m68881 0x040 +#define m68882 m68881 /* synonym for -m68881. otherwise unused. */ +#define m68851 0x080 +#define cpu32 0x100 /* e.g., 68332 */ + + /* handy aliases */ +#define m68040up (m68040 | m68060) +#define m68030up (m68030 | m68040up) +#define m68020up (m68020 | m68030up) +#define m68010up (m68010 | cpu32 | m68020up) +#define m68000up (m68000 | m68010up) + +#define mfloat (m68881 | m68882 | m68040 | m68060) +#define mmmu (m68851 | m68030 | m68040 | m68060) + +/* The structure used to hold information for an opcode. */ + +struct m68k_opcode +{ + /* The opcode name. */ + const char *name; + /* The opcode itself. */ + unsigned long opcode; + /* The mask used by the disassembler. */ + unsigned long match; + /* The arguments. */ + const char *args; + /* The architectures which support this opcode. */ + unsigned int arch; +}; + +/* The structure used to hold information for an opcode alias. */ + +struct m68k_opcode_alias +{ + /* The alias name. */ + const char *alias; + /* The instruction for which this is an alias. */ + const char *primary; +}; + +/* We store four bytes of opcode for all opcodes because that is the + most any of them need. The actual length of an instruction is + always at least 2 bytes, and is as much longer as necessary to hold + the operands it has. + + The match field is a mask saying which bits must match particular + opcode in order for an instruction to be an instance of that + opcode. + + The args field is a string containing two characters for each + operand of the instruction. The first specifies the kind of + operand; the second, the place it is stored. */ + +/* Kinds of operands: + Characters used: AaBCcDdFfIJkLlMOQRrSsTtUVWXYZ0123|*~%;@!&$?/#^+- + + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + a address register indirect only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + r either kind of register indirect only. Stored as 4 bits. + At the moment, used only for cas2 instruction. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 0x000 SFC Source Function Code reg [60, 40, 30, 20, 10] + 0x001 DFC Data Function Code reg [60, 40, 30, 20, 10] + 0x002 CACR Cache Control Register [60, 40, 30, 20] + 0x003 TC MMU Translation Control [60, 40] + 0x004 ITT0 Instruction Transparent + Translation reg 0 [60, 40] + 0x005 ITT1 Instruction Transparent + Translation reg 1 [60, 40] + 0x006 DTT0 Data Transparent + Translation reg 0 [60, 40] + 0x007 DTT1 Data Transparent + Translation reg 1 [60, 40] + 0x008 BUSCR Bus Control Register [60] + 0x800 USP User Stack Pointer [60, 40, 30, 20, 10] + 0x801 VBR Vector Base reg [60, 40, 30, 20, 10] + 0x802 CAAR Cache Address Register [ 30, 20] + 0x803 MSP Master Stack Pointer [ 40, 30, 20] + 0x804 ISP Interrupt Stack Pointer [ 40, 30, 20] + 0x805 MMUSR MMU Status reg [ 40] + 0x806 URP User Root Pointer [60, 40] + 0x807 SRP Supervisor Root Pointer [60, 40] + 0x808 PCR Processor Configuration reg [60] + + L Register list of the type d0-d7/a0-a7 etc. + (New! Improved! Can also hold fp0-fp7, as well!) + The assembler tries to see if the registers match the insn by + looking at where the insn wants them stored. + + l Register list like L, but with all the bits reversed. + Used for going the other way. . . + + c cache identifier which may be "nc" for no cache, "ic" + for instruction cache, "dc" for data cache, or "bc" + for both caches. Used in cinv and cpush. Always + stored in position "d". + + The remainder are all stored as 6 bits using an address mode and a + register number; they differ in which addressing modes they match. + + * all (modes 0-6,7.*) + ~ alterable memory (modes 2-6,7.0,7.1) + (not 0,1,7.~) + % alterable (modes 0-6,7.0,7.1)(not 7.~) + ; data (modes 0,2-6,7.*)(not 1) + @ data, but not immediate (modes 0,2-6,7.? ? ?) + (not 1,7.?) + This may really be ;, + the 68020 book says it is + ! control (modes 2,5,6,7.*-) + (not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1) + (not 0,1,7.? ? ?) + $ alterable data (modes 0,2-6,7.0,7.1) + (not 1,7.~) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1) + (not 1,3,4,7.~) + / control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3) + (not 1,3,4,7.4) + ` control, plus pre-dec, not simple indir. (modes 4,5,6,7.*-) + (not 0,1,2,3,7.4) */ + +/* For the 68851: */ +/* + I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + 0 32 bit pmmu register + Possible values: + 000 TC Translation Control Register (68030, 68851) + + 1 16 bit pmmu register + 111 AC Access Control (68851) + + 2 8 bit pmmu register + 100 CAL Current Access Level (68851) + 101 VAL Validate Access Level (68851) + 110 SCC Stack Change Control (68851) + + 3 68030-only pmmu registers (32 bit) + 010 TT0 Transparent Translation reg 0 + (aka Access Control reg 0 -- AC0 -- on 68ec030) + 011 TT1 Transparent Translation reg 1 + (aka Access Control reg 1 -- AC1 -- on 68ec030) + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer (68851) + 010 SRP Supervisor Root Pointer (68030, 68851) + 011 CRP Cpu Root Pointer (68030, 68851) + + f function code register (68030, 68851) + 0 SFC + 1 DFC + + V VAL register only (68851) + + X BADx, BACx (16 bit) + 100 BAD Breakpoint Acknowledge Data (68851) + 101 BAC Breakpoint Acknowledge Control (68851) + + Y PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030) + Z PCSR (68851) + + | memory (modes 2-6, 7.*) + + t address test level (68030 only) + Stored as 3 bits, range 0-7. + Also used for breakpoint instruction now. + +*/ + +/* Places to put an operand, for non-general operands: + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + 9 second word, shifted 5 + D store in both place 1 and place 3; for divul and divsl. + B first word, low byte, for branch displacements + W second word (entire), for branch displacements + L second and third words (entire), for branch displacements + (also overloaded for move16) + b second word, low byte + w second word (entire) [variable word/long branch offset for dbra] + W second word (entire) (must be signed 16 bit value) + l second and third word (entire) + g variable branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes +*/ + +extern const struct m68k_opcode m68k_opcodes[]; +extern const struct m68k_opcode_alias m68k_opcode_aliases[]; + +extern const int m68k_numopcodes, m68k_numaliases; + +/* end of m68k-opcode.h */ diff --git a/contrib/gdb/include/opcode/m88k.h b/contrib/gdb/include/opcode/m88k.h new file mode 100644 index 000000000000..a17fa0361dac --- /dev/null +++ b/contrib/gdb/include/opcode/m88k.h @@ -0,0 +1,923 @@ +/* Table of opcodes for the motorola 88k family. + Copyright 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB and GAS. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Disassembler Instruction Table + * + * The first field of the table is the opcode field. If an opcode + * is specified which has any non-opcode bits on, a system error + * will occur when the system attempts the install it into the + * instruction table. The second parameter is a pointer to the + * instruction mnemonic. Each operand is specified by offset, width, + * and type. The offset is the bit number of the least significant + * bit of the operand with bit 0 being the least significant bit of + * the instruction. The width is the number of bits used to specify + * the operand. The type specifies the output format to be used for + * the operand. The valid formats are: register, register indirect, + * hex constant, and bit field specification. The last field is a + * pointer to the next instruction in the linked list. These pointers + * are initialized by init_disasm(). + * + * Structure Format + * + * struct INSTAB { + * UPINT opcode; + * char *mnemonic; + * struct OPSPEC op1,op2,op3; + * struct SIM_FLAGS flgs; + * struct INSTAB *next; + * } + * + * struct OPSPEC { + * UPINT offset:5; + * UPINT width:6; + * UPINT type:5; + * } + * + * Revision History + * + * Revision 1.0 11/08/85 Creation date + * 1.1 02/05/86 Updated instruction mnemonic table MD + * 1.2 06/16/86 Updated SIM_FLAGS for floating point + * 1.3 09/20/86 Updated for new encoding + * 05/11/89 R. Trawick adapted from Motorola disassembler + */ + +#include + + +/* + * This file contains the structures and constants needed to build the M88000 + * simulator. It is the main include file, containing all the + * structures, macros and definitions except for the floating point + * instruction set. + */ + +/* + * The following flag informs the Simulator as to what type of byte ordering + * will be used. For instance, a BOFLAG = 1 indicates a DEC VAX and IBM type + * of ordering shall be used. +*/ + +/* # define BOFLAG 1 */ /* BYTE ORDERING FLAG */ + +/* define the number of bits in the primary opcode field of the instruction, + * the destination field, the source 1 and source 2 fields. + */ +# define OP 8 /* size of opcode field */ +# define DEST 6 /* size of destination */ +# define SOURCE1 6 /* size of source1 */ +# define SOURCE2 6 /* size of source2 */ + +# define REGs 32 /* number of registers */ + +# define WORD long +# define FLAG unsigned +# define STATE short + +# define TRUE 1 +# define FALSE 0 + +# define READ 0 +# define WRITE 1 + +/* The next four equates define the priorities that the various classes + * of instructions have regarding writing results back into registers and + * signalling exceptions. + */ +/* PMEM is also defined in on Delta 88's. Sigh! */ +#undef PMEM + +# define PINT 0 /* Integer Priority */ +# define PFLT 1 /* Floating Point Priority */ +# define PMEM 2 /* Memory Priority */ +# define NA 3 /* Not Applicable, instruction doesnt write to regs */ +# define HIPRI 3 /* highest of these priorities */ + +/* The instruction registers are an artificial mechanism to speed up + * simulator execution. In the real processor, an instruction register + * is 32 bits wide. In the simulator, the 32 bit instruction is kept in + * a structure field called rawop, and the instruction is partially decoded, + * and split into various fields and flags which make up the other fields + * of the structure. + * The partial decode is done when the instructions are initially loaded + * into simulator memory. The simulator code memory is not an array of + * 32 bit words, but is an array of instruction register structures. + * Yes this wastes memory, but it executes much quicker. + */ + +struct IR_FIELDS { + unsigned op:OP, + dest: DEST, + src1: SOURCE1, + src2: SOURCE2; + int ltncy, + extime, + wb_pri; /* writeback priority */ + unsigned imm_flags:2,/* immediate size */ + rs1_used:1, /* register source 1 used */ + rs2_used:1, /* register source 2 used */ + rsd_used:1, /* register source/dest. used */ + c_flag:1, /* complement */ + u_flag:1, /* upper half word */ + n_flag:1, /* execute next */ + wb_flag:1, /* uses writeback slot */ + dest_64:1, /* dest size */ + s1_64:1, /* source 1 size */ + s2_64:1, /* source 2 size */ + scale_flag:1, /* scaled register */ + brk_flg:1; + }; + +struct mem_segs { + struct mem_wrd *seg; /* pointer (returned by calloc) to segment */ + unsigned long baseaddr; /* base load address from file headers */ + unsigned long endaddr; /* Ending address of segment */ + int flags; /* segment control flags (none defined 12/5/86) */ +}; + +#define MAXSEGS (10) /* max number of segment allowed */ +#define MEMSEGSIZE (sizeof(struct mem_segs))/* size of mem_segs structure */ + + +#define BRK_RD (0x01) /* break on memory read */ +#define BRK_WR (0x02) /* break on memory write */ +#define BRK_EXEC (0x04) /* break on execution */ +#define BRK_CNT (0x08) /* break on terminal count */ + + +struct mem_wrd { + struct IR_FIELDS opcode; /* simulator instruction break down */ + union { + unsigned long l; /* memory element break down */ + unsigned short s[2]; + unsigned char c[4]; + } mem; +}; + +#define MEMWRDSIZE (sizeof(struct mem_wrd)) /* size of each 32 bit memory model */ + +/* External declarations */ + +extern struct mem_segs memory[]; +extern struct PROCESSOR m78000; + +struct PROCESSOR { + unsigned WORD + ip, /* execute instruction pointer */ + vbr, /* vector base register */ + psr; /* processor status register */ + + WORD S1bus, /* source 1 */ + S2bus, /* source 2 */ + Dbus, /* destination */ + DAbus, /* data address bus */ + ALU, + Regs[REGs], /* data registers */ + time_left[REGs], /* max clocks before reg is available */ + wb_pri[REGs], /* writeback priority of reg */ + SFU0_regs[REGs], /* integer unit control regs */ + SFU1_regs[REGs], /* floating point control regs */ + Scoreboard[REGs], + Vbr; + unsigned WORD scoreboard, + Psw, + Tpsw; + FLAG jump_pending:1; /* waiting for a jump instr. */ + }; + +# define i26bit 1 /* size of immediate field */ +# define i16bit 2 +# define i10bit 3 + +/* Definitions for fields in psr */ + +# define mode 31 +# define rbo 30 +# define ser 29 +# define carry 28 +# define sf7m 11 +# define sf6m 10 +# define sf5m 9 +# define sf4m 8 +# define sf3m 7 +# define sf2m 6 +# define sf1m 5 +# define mam 4 +# define inm 3 +# define exm 2 +# define trm 1 +# define ovfm 0 + +#define MODEMASK (1<<(mode-1)) +# define SILENT 0 /* simulate without output to crt */ +# define VERBOSE 1 /* simulate in verbose mode */ +# define PR_INSTR 2 /* only print instructions */ + +# define RESET 16 /* reset phase */ + +# define PHASE1 0 /* data path phases */ +# define PHASE2 1 + +/* the 1 clock operations */ + +# define ADDU 1 +# define ADDC 2 +# define ADDUC 3 +# define ADD 4 + +# define SUBU ADD+1 +# define SUBB ADD+2 +# define SUBUB ADD+3 +# define SUB ADD+4 + +# define AND_ ADD+5 +# define OR ADD+6 +# define XOR ADD+7 +# define CMP ADD+8 + +/* the LOADS */ + +# define LDAB CMP+1 +# define LDAH CMP+2 +# define LDA CMP+3 +# define LDAD CMP+4 + +# define LDB LDAD+1 +# define LDH LDAD+2 +# define LD LDAD+3 +# define LDD LDAD+4 +# define LDBU LDAD+5 +# define LDHU LDAD+6 + +/* the STORES */ + +# define STB LDHU+1 +# define STH LDHU+2 +# define ST LDHU+3 +# define STD LDHU+4 + +/* the exchange */ + +# define XMEMBU LDHU+5 +# define XMEM LDHU+6 + +/* the branches */ +# define JSR STD+1 +# define BSR STD+2 +# define BR STD+3 +# define JMP STD+4 +# define BB1 STD+5 +# define BB0 STD+6 +# define RTN STD+7 +# define BCND STD+8 + +/* the TRAPS */ +# define TB1 BCND+1 +# define TB0 BCND+2 +# define TCND BCND+3 +# define RTE BCND+4 +# define TBND BCND+5 + +/* the MISC instructions */ +# define MUL TBND + 1 +# define DIV MUL +2 +# define DIVU MUL +3 +# define MASK MUL +4 +# define FF0 MUL +5 +# define FF1 MUL +6 +# define CLR MUL +7 +# define SET MUL +8 +# define EXT MUL +9 +# define EXTU MUL +10 +# define MAK MUL +11 +# define ROT MUL +12 + +/* control register manipulations */ + +# define LDCR ROT +1 +# define STCR ROT +2 +# define XCR ROT +3 + +# define FLDCR ROT +4 +# define FSTCR ROT +5 +# define FXCR ROT +6 + + +# define NOP XCR +1 + +/* floating point instructions */ + +# define FADD NOP +1 +# define FSUB NOP +2 +# define FMUL NOP +3 +# define FDIV NOP +4 +# define FSQRT NOP +5 +# define FCMP NOP +6 +# define FIP NOP +7 +# define FLT NOP +8 +# define INT NOP +9 +# define NINT NOP +10 +# define TRNC NOP +11 +# define FLDC NOP +12 +# define FSTC NOP +13 +# define FXC NOP +14 + +# define UEXT(src,off,wid) ((((unsigned int)(src))>>(off)) & ((1<<(wid)) - 1)) +# define SEXT(src,off,wid) (((((int)(src))<<(32-((off)+(wid)))) >>(32-(wid))) ) +# define MAKE(src,off,wid) \ + ((((unsigned int)(src)) & ((1<<(wid)) - 1)) << (off)) + +# define opword(n) (unsigned long) (memaddr->mem.l) + +/* Constants and Masks */ + +#define SFU0 0x80000000 +#define SFU1 0x84000000 +#define SFU7 0x9c000000 +#define RRI10 0xf0000000 +#define RRR 0xf4000000 +#define SFUMASK 0xfc00ffe0 +#define RRRMASK 0xfc00ffe0 +#define RRI10MASK 0xfc00fc00 +#define DEFMASK 0xfc000000 +#define CTRL 0x0000f000 +#define CTRLMASK 0xfc00f800 + +/* Operands types */ + +enum operand_type { + HEX = 1, + REG = 2, + CONT = 3, + IND = 3, + BF = 4, + REGSC = 5 /* scaled register */, + CRREG = 6 /* control register */, + FCRREG = 7 /* floating point control register */, + PCREL = 8, + CONDMASK = 9, + XREG = 10, /* extended register */ + DEC = 11, /* decimal */ +}; + +/* Hashing Specification */ + +#define HASHVAL 79 + +/* Type definitions */ + +typedef unsigned int UINT; + +/* Structure templates */ + +#if never +typedef struct { + unsigned int offset:5; + unsigned int width:6; + unsigned int type:5; +} OPSPEC; +#endif + +typedef struct { + unsigned int offset; + unsigned int width; + enum operand_type type; +} OPSPEC; + + struct SIM_FLAGS { + int ltncy, /* latency (max number of clocks needed to execute) */ + extime, /* execution time (min number of clocks needed to execute) */ + wb_pri; /* writeback slot priority */ + unsigned op:OP, /* simulator version of opcode */ + imm_flags:2, /* 10,16 or 26 bit immediate flags */ + rs1_used:1, /* register source 1 used */ + rs2_used:1, /* register source 2 used */ + rsd_used:1, /* register source/dest used */ + c_flag:1, /* complement */ + u_flag:1, /* upper half word */ + n_flag:1, /* execute next */ + wb_flag:1, /* uses writeback slot */ + dest_64:1, /* double precision dest */ + s1_64:1, /* double precision source 1 */ + s2_64:1, /* double precision source 2 */ + scale_flag:1; /* register is scaled */ +}; + +typedef struct INSTRUCTAB { + unsigned int opcode; + char *mnemonic; + OPSPEC op1,op2,op3; + struct SIM_FLAGS flgs; + struct INSTRUCTAB *next; +} INSTAB; + + +#define NO_OPERAND {0,0,0} + +/* Opcode Mnemonic Op 1 Spec Op 2 Spec Op 3 Spec Simflags Next */ + +static INSTAB instructions[] = { + {0xf400c800,"jsr ",{0,5,REG} ,NO_OPERAND ,NO_OPERAND , {2,2,NA,JSR , 0,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf400cc00,"jsr.n ",{0,5,REG} ,NO_OPERAND ,NO_OPERAND , {1,1,NA,JSR , 0,0,1,0,0,0,1,1,0,0,0,0}, NULL }, + {0xf400c000,"jmp ",{0,5,REG} ,NO_OPERAND ,NO_OPERAND , {2,2,NA,JMP , 0,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf400c400,"jmp.n ",{0,5,REG} ,NO_OPERAND ,NO_OPERAND , {1,1,NA,JMP , 0,0,1,0,0,0,1,1,0,0,0,0}, NULL }, + {0xc8000000,"bsr ",{0,26,PCREL},NO_OPERAND ,NO_OPERAND , {2,2,NA,BSR , i26bit,0,0,0,0,0,0,1,0,0,0,0}, NULL }, + {0xcc000000,"bsr.n ",{0,26,PCREL},NO_OPERAND ,NO_OPERAND , {1,1,NA,BSR , i26bit,0,0,0,0,0,1,1,0,0,0,0}, NULL }, + {0xc0000000,"br ",{0,26,PCREL},NO_OPERAND ,NO_OPERAND , {2,2,NA,BR , i26bit,0,0,0,0,0,0,1,0,0,0,0}, NULL }, + {0xc4000000,"br.n ",{0,26,PCREL},NO_OPERAND ,NO_OPERAND , {1,1,NA,BR , i26bit,0,0,0,0,0,1,1,0,0,0,0}, NULL }, + {0xd0000000,"bb0 ",{21,5,HEX} ,{16,5,REG} ,{0,16,PCREL},{2,2,NA,BB0, i16bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xd4000000,"bb0.n ",{21,5,HEX} ,{16,5,REG} ,{0,16,PCREL},{1,1,NA,BB0, i16bit,0,1,0,0,0,1,1,0,0,0,0}, NULL }, + {0xd8000000,"bb1 ",{21,5,HEX},{16,5,REG} ,{0,16,PCREL},{2,2,NA,BB1, i16bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xdc000000,"bb1.n ",{21,5,HEX},{16,5,REG} ,{0,16,PCREL},{1,1,NA,BB1, i16bit,0,1,0,0,0,1,1,0,0,0,0}, NULL }, + {0xf000d000,"tb0 ",{21,5,HEX} ,{16,5,REG} ,{0,10,HEX}, {2,2,NA,TB0 , i10bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf000d800,"tb1 ",{21,5,HEX} ,{16,5,REG} ,{0,10,HEX}, {2,2,NA,TB1 , i10bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xe8000000,"bcnd ",{21,5,CONDMASK},{16,5,REG},{0,16,PCREL},{2,2,NA,BCND, i16bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xec000000,"bcnd.n ",{21,5,CONDMASK},{16,5,REG},{0,16,PCREL},{1,1,NA,BCND, i16bit,0,1,0,0,0,1,1,0,0,0,0}, NULL }, + {0xf000e800,"tcnd ",{21,5,CONDMASK},{16,5,REG},{0,10,HEX}, {2,2,NA,TCND, i10bit,0,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf8000000,"tbnd ",{16,5,REG} ,{0,16,HEX} ,NO_OPERAND , {2,2,NA,TBND, i10bit,1,0,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf400f800,"tbnd ",{16,5,REG} ,{0,5,REG} ,NO_OPERAND , {2,2,NA,TBND, 0,1,1,0,0,0,0,1,0,0,0,0}, NULL }, + {0xf400fc00,"rte ",NO_OPERAND ,NO_OPERAND ,NO_OPERAND , {2,2,NA,RTE , 0,0,0,0,0,0,0,1,0,0,0,0}, NULL }, + {0x1c000000,"ld.b ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LDB ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001c00,"ld.b ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LDB , 0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0x0c000000,"ld.bu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LDBU, i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4000c00,"ld.bu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LDBU ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0x18000000,"ld.h ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LDH ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001800,"ld.h ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LDH ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001a00,"ld.h ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,LDH ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0x08000000,"ld.hu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LDHU, i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4000800,"ld.hu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LDHU ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4000a00,"ld.hu ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,LDHU ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0x14000000,"ld ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LD ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001400,"ld ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LD ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001600,"ld ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,LD ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0x10000000,"ld.d ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,LDD ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001000,"ld.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LDD ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001200,"ld.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,LDD ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0xf4001500,"ld.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,LD ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4001700,"ld.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,LD ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0x2c000000,"st.b ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,NA,STB ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4002c00,"st.b ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,NA,STB ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0x28000000,"st.h ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,NA,STH ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4002800,"st.h ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,NA,STH ,0,1,1,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4002a00,"st.h ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,NA,STH ,0,1,1,1,0,0,0,1,0,0,0,1}, NULL }, + {0x24000000,"st ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,NA,ST ,i16bit,1,0,1,0,0,0,1,0,0,0,0}, NULL }, + {0xf4002400,"st ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,NA,ST ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4002600,"st ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,NA,ST ,0,1,1,1,0,0,0,1,0,0,0,1} ,NULL }, + {0x20000000,"st.d ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,NA,STD ,i16bit,0,1,0,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4002000,"st.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,NA,STD ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4002200,"st.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,NA,STD ,0,1,1,1,0,0,0,1,0,0,0,1} ,NULL }, + {0xf4002500,"st.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,NA,ST ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4002700,"st.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,NA,ST ,0,1,1,1,0,0,0,1,0,0,0,1} ,NULL }, +/* m88100 only: + {0x00000000,"xmem.bu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,XMEMBU ,i16bit,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + */ + {0xf4000000,"xmem.bu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,XMEM ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, +/* m88100 only: + {0x04000000,"xmem ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {3,1,PMEM,XMEM ,i16bit,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + */ + {0xf4000400,"xmem ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,XMEM ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4000600,"xmem ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,XMEM ,0,1,1,1,0,0,0,1,0,0,0,1} ,NULL }, + {0xf4000500,"xmem.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {3,1,PMEM,XMEM ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0xf4000700,"xmem.usr ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{3,1,PMEM,XMEM ,0,1,1,1,0,0,0,1,0,0,0,1} ,NULL }, +/* m88100 only: + {0xf4003e00,"lda.b ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,PINT,LDAH, 0,1,1,1,0,0,0,0,0,0,0,1} ,NULL }, + */ + {0xf4003e00,"lda.x ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,PINT,LDAH, 0,1,1,1,0,0,0,0,0,0,0,1} ,NULL }, + {0xf4003a00,"lda.h ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,PINT,LDAH, 0,1,1,1,0,0,0,0,0,0,0,1} ,NULL }, + {0xf4003600,"lda ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,PINT,LDA , 0,1,1,1,0,0,0,0,0,0,0,1} ,NULL }, + {0xf4003200,"lda.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REGSC},{1,1,PINT,LDAD, 0,1,1,1,0,0,0,0,0,0,0,1} ,NULL }, + + {0x80004000,"ldcr ",{21,5,REG} ,{5,6,CRREG} ,NO_OPERAND ,{1,1,PINT,LDCR, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x80008000,"stcr ",{16,5,REG} ,{5,6,CRREG} ,NO_OPERAND ,{1,1,PINT,STCR, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x8000c000,"xcr ",{21,5,REG} ,{16,5,REG} ,{5,6,CRREG},{1,1,PINT,XCR, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + + {0xf4006000,"addu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADDU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006200,"addu.ci ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADDU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006100,"addu.co ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADDU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006300,"addu.cio ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADDU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006400,"subu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUBU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006600,"subu.ci ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUBU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006500,"subu.co ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUBU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006700,"subu.cio ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUBU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006800,"divu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {32,32,PINT,DIVU, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4006900,"divu.d ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, NULL }, + {0xf4006e00,"muls ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, NULL }, + {0xf4006c00,"mulu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,4,PINT,MUL, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007000,"add ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADD , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007200,"add.ci ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADD , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007100,"add.co ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADD , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007300,"add.cio ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ADD , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007400,"sub ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUB , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007600,"sub.ci ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUB , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007500,"sub.co ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUB , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007700,"sub.cio ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SUB , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007800,"divs ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {32,32,PINT,DIV , 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4007c00,"cmp ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,CMP, 0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + + {0x60000000,"addu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,ADDU, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x64000000,"subu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,SUBU, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + + {0x68000000,"divu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {32,32,PINT,DIVU, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x6c000000,"mulu ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {4,1,PINT,MUL, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x70000000,"add ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,ADD, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x74000000,"sub ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,SUB, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x78000000,"divs ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {32,32,PINT,DIV, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x7c000000,"cmp ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,CMP, i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + + {0xf4004000,"and ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,AND_ ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4004400,"and.c ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,AND_ ,0,1,1,1,1,0,0,0,0,0,0,0} ,NULL }, + {0xf4005800,"or ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,OR ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4005c00,"or.c ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,OR ,0,1,1,1,1,0,0,0,0,0,0,0} ,NULL }, + {0xf4005000,"xor ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,XOR ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4005400,"xor.c ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,XOR ,0,1,1,1,1,0,0,0,0,0,0,0} ,NULL }, + {0x40000000,"and ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,AND_ ,i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x44000000,"and.u ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,AND_ ,i16bit,1,0,1,0,1,0,0,0,0,0,0} ,NULL }, + {0x58000000,"or ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,OR ,i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x5c000000,"or.u ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,OR ,i16bit,1,0,1,0,1,0,0,0,0,0,0} ,NULL }, + {0x50000000,"xor ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,XOR ,i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x54000000,"xor.u ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,XOR ,i16bit,1,0,1,0,1,0,0,0,0,0,0} ,NULL }, + {0x48000000,"mask ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,MASK ,i16bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0x4c000000,"mask.u ",{21,5,REG} ,{16,5,REG} ,{0,16,HEX}, {1,1,PINT,MASK ,i16bit,1,0,1,0,1,0,0,0,0,0,0} ,NULL }, + {0xf400ec00,"ff0 ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {1,1,PINT,FF0 ,0,0,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf400e800,"ff1 ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {1,1,PINT,FF1 ,0,0,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf0008000,"clr ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,CLR ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf0008800,"set ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,SET ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf0009000,"ext ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,EXT ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf0009800,"extu ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,EXTU ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf000a000,"mak ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,MAK ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf000a800,"rot ",{21,5,REG} ,{16,5,REG} ,{0,10,BF} , {1,1,PINT,ROT ,i10bit,1,0,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4008000,"clr ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,CLR ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4008800,"set ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,SET ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4009000,"ext ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,EXT ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf4009800,"extu ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,EXTU ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf400a000,"mak ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,MAK ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + {0xf400a800,"rot ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {1,1,PINT,ROT ,0,1,1,1,0,0,0,0,0,0,0,0} ,NULL }, + + {0x84002800,"fadd.sss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {5,1,PFLT,FADD ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84002880,"fadd.ssd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,0,0,1,0} ,NULL }, + {0x84002a00,"fadd.sds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,0,1,0,0} ,NULL }, + {0x84002a80,"fadd.sdd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,0,1,1,0} ,NULL }, + {0x84002820,"fadd.dss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x840028a0,"fadd.dsd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,1,0,1,0} ,NULL }, + {0x84002a20,"fadd.dds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,1,1,0,0} ,NULL }, + {0x84002aa0,"fadd.ddd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FADD ,0,1,1,1,0,0,0,1,1,1,1,0} ,NULL }, + {0x84003000,"fsub.sss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {5,1,PFLT,FSUB ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84003080,"fsub.ssd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,0,0,1,0} ,NULL }, + {0x84003200,"fsub.sds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,0,1,0,0} ,NULL }, + {0x84003280,"fsub.sdd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,0,1,1,0} ,NULL }, + {0x84003020,"fsub.dss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x840030a0,"fsub.dsd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,1,0,1,0} ,NULL }, + {0x84003220,"fsub.dds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,1,1,0,0} ,NULL }, + {0x840032a0,"fsub.ddd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,2,PFLT,FSUB ,0,1,1,1,0,0,0,1,1,1,1,0} ,NULL }, + {0x84000000,"fmul.sss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,1,PFLT,FMUL ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84000080,"fmul.ssd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,0,0,1,0} ,NULL }, + {0x84000200,"fmul.sds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,0,1,0,0} ,NULL }, + {0x84000280,"fmul.sdd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,0,1,1,0} ,NULL }, + {0x84000020,"fmul.dss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x840000a0,"fmul.dsd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,1,0,1,0} ,NULL }, + {0x84000220,"fmul.dds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,1,1,0,0} ,NULL }, + {0x840002a0,"fmul.ddd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {9,2,PFLT,FMUL ,0,1,1,1,0,0,0,1,1,1,1,0} ,NULL }, + {0x84007000,"fdiv.sss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {30,30,PFLT,FDIV ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84007080,"fdiv.ssd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,0,0,1,0} ,NULL }, + {0x84007200,"fdiv.sds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,0,1,0,0} ,NULL }, + {0x84007280,"fdiv.sdd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,0,1,1,0} ,NULL }, + {0x84007020,"fdiv.dss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x840070a0,"fdiv.dsd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,1,0,1,0} ,NULL }, + {0x84007220,"fdiv.dds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,1,1,0,0} ,NULL }, + {0x840072a0,"fdiv.ddd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {60,60,PFLT,FDIV ,0,1,1,1,0,0,0,1,1,1,1,0} ,NULL }, + {0x84007800,"fsqrt.ss ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,FLT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84007820,"fsqrt.sd ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,FLT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84007880,"fsqrt.ds ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,FLT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x840078a0,"fsqrt.dd ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {6,1,PFLT,FLT ,0,0,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x84003800,"fcmp.ss ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {5,1,PFLT,FCMP ,0,1,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84003880,"fcmp.sd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,1,PFLT,FCMP ,0,1,1,1,0,0,0,1,0,1,0,0} ,NULL }, + {0x84003a00,"fcmp.ds ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,1,PFLT,FCMP ,0,1,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x84003a80,"fcmp.dd ",{21,5,REG} ,{16,5,REG} ,{0,5,REG} , {6,1,PFLT,FCMP ,0,1,1,1,0,0,0,1,1,1,0,0} ,NULL }, + {0x84002000,"flt.s ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,FLT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84002020,"flt.d ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {6,1,PFLT,FLT ,0,0,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x84004800,"int.s ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,INT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84004880,"int.d ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {6,1,PFLT,INT ,0,0,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x84005000,"nint.s ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,INT ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84005080,"nint.d ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {6,1,PFLT,INT ,0,0,1,1,0,0,0,1,1,0,0,0} ,NULL }, + {0x84005800,"trnc.s ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {5,1,PFLT,TRNC ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x84005880,"trnc.d ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND , {6,1,PFLT,TRNC ,0,0,1,1,0,0,0,1,1,0,0,0} ,NULL }, + + {0x80004800,"fldcr ",{21,5,REG} ,{5,6,FCRREG} ,NO_OPERAND , {1,1,PFLT,FLDC ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x80008800,"fstcr ",{16,5,REG} ,{5,6,FCRREG} ,NO_OPERAND , {1,1,PFLT,FSTC ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + {0x8000c800,"fxcr ",{21,5,REG} ,{16,5,REG} ,{5,6,FCRREG} , {1,1,PFLT,FXC ,0,0,1,1,0,0,0,1,0,0,0,0} ,NULL }, + +/* The following are new for the 88110. */ + + {0x8400aaa0,"fadd.ddd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aa80,"fadd.dds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aac0,"fadd.ddx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aa20,"fadd.dsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aa00,"fadd.dss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aa40,"fadd.dsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ab20,"fadd.dxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ab00,"fadd.dxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ab40,"fadd.dxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a8a0,"fadd.sdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a880,"fadd.sds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a8c0,"fadd.sdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a820,"fadd.ssd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a800,"fadd.sss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a840,"fadd.ssx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a920,"fadd.sxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a900,"fadd.sxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400a940,"fadd.sxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400aca0,"fadd.xdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ac80,"fadd.xds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400acc0,"fadd.xdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ac20,"fadd.xsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ac00,"fadd.xss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ac40,"fadd.xsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ad20,"fadd.xxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ad00,"fadd.xxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ad40,"fadd.xxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400ba80,"fcmp.sdd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ba00,"fcmp.sds ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bb00,"fcmp.sdx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b880,"fcmp.ssd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b800,"fcmp.sss ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b900,"fcmp.ssx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bc80,"fcmp.sxd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bc00,"fcmp.sxs ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bd00,"fcmp.sxx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400baa0,"fcmpu.sdd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400ba20,"fcmpu.sds ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bb20,"fcmpu.sdx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b8a0,"fcmpu.ssd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b820,"fcmpu.sss ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b920,"fcmpu.ssx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bca0,"fcmpu.sxd ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bc20,"fcmpu.sxs ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400bd20,"fcmpu.sxx ",{21,5,REG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x84000820,"fcvt.sd ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84000880,"fcvt.ds ",{21,5,REG} ,{0,5,REG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x84008880,"fcvt.ds ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840088c0,"fcvt.dx ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008820,"fcvt.sd ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008840,"fcvt.sx ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008920,"fcvt.xd ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008900,"fcvt.xs ",{21,5,XREG} ,{0,5,XREG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400f2a0,"fdiv.ddd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f280,"fdiv.dds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f2c0,"fdiv.ddx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f220,"fdiv.dsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f200,"fdiv.dss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f240,"fdiv.dsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f320,"fdiv.dxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f300,"fdiv.dxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f340,"fdiv.dxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f0a0,"fdiv.sdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f080,"fdiv.sds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f0c0,"fdiv.sdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f020,"fdiv.ssd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f000,"fdiv.sss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f040,"fdiv.ssx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f120,"fdiv.sxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f100,"fdiv.sxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f140,"fdiv.sxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f4a0,"fdiv.xdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f480,"fdiv.xds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f4c0,"fdiv.xdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f420,"fdiv.xsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f400,"fdiv.xss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f440,"fdiv.xsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f520,"fdiv.xxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f500,"fdiv.xxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f540,"fdiv.xxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x84002220,"flt.ds ",{21,5,XREG} ,{0,5,REG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84002200,"flt.ss ",{21,5,XREG} ,{0,5,REG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84002240,"flt.xs ",{21,5,XREG} ,{0,5,REG} ,NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x840082a0,"fmul.ddd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008280,"fmul.dds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840082c0,"fmul.ddx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008220,"fmul.dsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008200,"fmul.dss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008240,"fmul.dsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008320,"fmul.dxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008300,"fmul.dxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008340,"fmul.dxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840080a0,"fmul.sdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008080,"fmul.sds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840080c0,"fmul.sdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008020,"fmul.ssd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008000,"fmul.sss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008040,"fmul.ssx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008120,"fmul.sxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008100,"fmul.sxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008140,"fmul.sxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840084a0,"fmul.xdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008480,"fmul.xds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x840084c0,"fmul.xdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008420,"fmul.xsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008400,"fmul.xss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008440,"fmul.xsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008520,"fmul.xxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008500,"fmul.xxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84008540,"fmul.xxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400f8a0,"fsqrt.dd ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f880,"fsqrt.ds ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f8c0,"fsqrt.dx ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f820,"fsqrt.sd ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f800,"fsqrt.ss ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f840,"fsqrt.sx ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f920,"fsqrt.xd ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f900,"fsqrt.xs ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400f940,"fsqrt.xx ",{21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400b2a0,"fsub.ddd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b280,"fsub.dds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b2c0,"fsub.ddx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b220,"fsub.dsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b200,"fsub.dss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b240,"fsub.dsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b320,"fsub.dxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b300,"fsub.dxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b340,"fsub.dxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b0a0,"fsub.sdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b080,"fsub.sds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b0c0,"fsub.sdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b020,"fsub.ssd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b000,"fsub.sss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b040,"fsub.ssx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b120,"fsub.sxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b100,"fsub.sxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b140,"fsub.sxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b4a0,"fsub.xdd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b480,"fsub.xds ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b4c0,"fsub.xdx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b420,"fsub.xsd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b400,"fsub.xss ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b440,"fsub.xsx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b520,"fsub.xxd ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b500,"fsub.xxs ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400b540,"fsub.xxx ",{21,5,XREG} ,{16,5,XREG} ,{0,5,XREG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400fc00,"illop", {0,2,DEC}, NO_OPERAND, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400c800,"int.ss ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400c880,"int.sd ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400c900,"int.sx ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x04000000,"ld ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x00000000,"ld.d ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x3c000000,"ld.x ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf0001400,"ld ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001000,"ld.d ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001800,"ld.x ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001500,"ld.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001100,"ld.d.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001900,"ld.x.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf0001600,"ld ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001200,"ld.d ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001a00,"ld.x ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001700,"ld.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001300,"ld.d.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0001b00,"ld.x.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400c000,"mov.s ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400c080,"mov.d ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84004200,"mov.s ", {21,5,XREG}, {0,5,REG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x84004280,"mov.d ", {21,5,XREG}, {0,5,REG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400c300,"mov ", {21,5,XREG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf4006d00,"mulu.d ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400d080,"nint.sd ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400d000,"nint.ss ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400d100,"nint.sx ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88002020,"padd.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88002040,"padd.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88002060,"padd ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x880021e0,"padds.s ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880021a0,"padds.s.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880021c0,"padds.s.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880020e0,"padds.u ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880020a0,"padds.u.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880020c0,"padds.u.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88002160,"padds.us ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88002120,"padds.us.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88002140,"padds.us.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88003860,"pcmp ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88000000,"pmul ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88006260,"ppack.16 ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006240,"ppack.16.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006460,"ppack.32 ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006420,"ppack.32.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006440,"ppack.32.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006160,"ppack.8 ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88007200,"prot ", {21,5,REG}, {16,5,REG}, {5,6,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88007800,"prot ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88003020,"psub.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88003040,"psub.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88003060,"psub ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x880031e0,"psubs.s ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880031a0,"psubs.s.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880031c0,"psubs.s.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880030e0,"psubs.u ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880030a0,"psubs.u.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x880030c0,"psubs.u.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88003160,"psubs.us ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88003120,"psubs.us.b ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88003140,"psubs.us.h ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x88006800,"punpk.n ", {21,5,REG}, {16,5,REG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x88006820,"punpk.b ", {21,5,REG}, {16,5,REG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x34000000,"st ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x30000000,"st.d ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x38000000,"st.x ", {21,5,XREG}, {16,5,REG}, {0,16,HEX}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf4002c80,"st.b.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002880,"st.h.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002480,"st.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002080,"st.d.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002d80,"st.b.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002980,"st.h.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002580,"st.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002180,"st.d.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf0002400,"st ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002000,"st.d ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002100,"st.d.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002180,"st.d.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002080,"st.d.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002500,"st.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002580,"st.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002480,"st.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002800,"st.x ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002900,"st.x.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002980,"st.x.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002880,"st.x.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REG}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf4002f80,"st.b.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002e80,"st.b.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002380,"st.d.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002280,"st.d.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002b80,"st.h.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002a80,"st.h.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002780,"st.usr.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf4002680,"st.wt ", {21,5,REG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0xf0002600,"st ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002200,"st.d ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002300,"st.d.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002380,"st.d.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002280,"st.d.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002700,"st.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002780,"st.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002680,"st.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002a00,"st.x ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002b00,"st.x.usr ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002b80,"st.x.usr.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0xf0002a80,"st.x.wt ", {21,5,XREG}, {16,5,REG}, {0,5,REGSC}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + + {0x8400d880,"trnc.sd ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400d800,"trnc.ss ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + {0x8400d900,"trnc.sx ", {21,5,REG}, {0,5,XREG}, NO_OPERAND, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NULL }, + +}; + +/* + * Local Variables: + * fill-column: 131 + * End: + */ diff --git a/contrib/gdb/include/opcode/mips.h b/contrib/gdb/include/opcode/mips.h new file mode 100644 index 000000000000..14ceec96119a --- /dev/null +++ b/contrib/gdb/include/opcode/mips.h @@ -0,0 +1,481 @@ +/* mips.h. Mips opcode list for GDB, the GNU debugger. + Copyright 1993, 1995 Free Software Foundation, Inc. + Contributed by Ralph Campbell and OSF + Commented and modified by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). + + The syscall instruction uses SYSCALL. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_SYSCALL 0xfffff +#define OP_SH_SYSCALL 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 + +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is instead the + ISA level of the macro (0 or 1 is always supported, 2 is ISA 2, + etc.). */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; +}; + +/* These are the characters which may appears in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall function code (OP_*_SYSCALL) + "x" accept and ignore register name + "z" must be zero register + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* MIPS ISA field--CPU level at which insn is supported. */ +#define INSN_ISA 0x70000000 +/* MIPS ISA 2 instruction (R6000 or R4000). */ +#define INSN_ISA2 0x10000000 +/* MIPS ISA 3 instruction (R4000). */ +#define INSN_ISA3 0x20000000 +/* MIPS R4650 instruction. */ +#define INSN_4650 0x30000000 +/* MIPS ISA 4 instruction (R8000). */ +#define INSN_ISA4 0x40000000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x50000000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x60000000 + +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* This is a list of macro expanded instructions. + * + * _I appended means immediate + * _A appended means address + * _AB appended means address with base register + * _D appended means 64 bit floating point constant + * _S appended means 32 bit floating point constant + */ +enum { + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE_I, + M_BNEL_I, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_ROL, + M_ROL_I, + M_ROR, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I +}; + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +extern const struct mips_opcode mips_opcodes[]; +extern const int bfd_mips_num_opcodes; +#define NUMOPCODES bfd_mips_num_opcodes diff --git a/contrib/gdb/include/opcode/np1.h b/contrib/gdb/include/opcode/np1.h new file mode 100644 index 000000000000..d23adc7566cf --- /dev/null +++ b/contrib/gdb/include/opcode/np1.h @@ -0,0 +1,422 @@ +/* Print GOULD NPL instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB 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 1, or (at your option) +any later version. + +GDB 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 GDB; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and at most four. The length of the + instruction is based on the opcode. + + The mask component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "lb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lbs", 0xec080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ld", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "li", 0xf8000000, 0xfc7f0000, "r,I", 4 }, +{ "lpa", 0x50080000, 0xfc080000, "r,xOA,X", 4 }, +{ "la", 0x50000000, 0xfc080000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lbp", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lhp", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lwp", 0x90000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ldp", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "lf", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xbc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0xdc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "zmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stbp", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sthp", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stwp", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stdp", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lil", 0xf80b0000, 0xfc7f0000, "r,D", 4 }, +{ "lwsl1", 0xec000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl2", 0xfc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl3", 0xfc080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "lvb", 0xb0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvh", 0xb0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "lvw", 0xb0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvd", 0xb0000002, 0xfc080002, "v,xOA,X", 4 }, +{ "liv", 0x3c040000, 0xfc0f0000, "v,R", 2 }, +{ "livf", 0x3c080000, 0xfc0f0000, "v,R", 2 }, +{ "stvb", 0xd0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvh", 0xd0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "stvw", 0xd0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvd", 0xd0000002, 0xfc080002, "v,xOA,X", 4 }, + +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnd", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trabs", 0x2c010000, 0xfc0f0000, "r,R", 2 }, +{ "trabsd", 0x2c090000, 0xfc0f0000, "r,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "xcr", 0x28040000, 0xfc0f0000, "r,R", 2 }, +{ "cxcr", 0x2c060000, 0xfc0f0000, "r,R", 2 }, +{ "cxcrd", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "trbr", 0x28030000, 0xfc0f0000, "b,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "tbrbr", 0x28010000, 0xfc0f0000, "b,B", 2 }, + +{ "trvv", 0x28050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvn", 0x2c050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvnd", 0x2c0d0000, 0xfc0f0000, "v,V", 2 }, +{ "trvab", 0x2c070000, 0xfc0f0000, "v,V", 2 }, +{ "trvabd", 0x2c0f0000, 0xfc0f0000, "v,V", 2 }, +{ "cmpv", 0x14060000, 0xfc0f0000, "v,V", 2 }, +{ "expv", 0x14070000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvlt", 0x10030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvle", 0x10040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvgt", 0x14030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvge", 0x14040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvveq", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvne", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvrlt", 0x100d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrle", 0x100e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrgt", 0x140d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrge", 0x140e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvreq", 0x100f0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrne", 0x140f0000, 0xfc0f0000, "v,R", 2 }, +{ "trvr", 0x140b0000, 0xfc0f0000, "r,V", 2 }, +{ "trrv", 0x140c0000, 0xfc0f0000, "v,R", 2 }, + +{ "bu", 0x40000000, 0xff880000, "xOA,X", 4 }, +{ "bns", 0x70080000, 0xff880000, "xOA,X", 4 }, +{ "bnco", 0x70880000, 0xff880000, "xOA,X", 4 }, +{ "bge", 0x71080000, 0xff880000, "xOA,X", 4 }, +{ "bne", 0x71880000, 0xff880000, "xOA,X", 4 }, +{ "bunge", 0x72080000, 0xff880000, "xOA,X", 4 }, +{ "bunle", 0x72880000, 0xff880000, "xOA,X", 4 }, +{ "bgt", 0x73080000, 0xff880000, "xOA,X", 4 }, +{ "bnany", 0x73880000, 0xff880000, "xOA,X", 4 }, +{ "bs" , 0x70000000, 0xff880000, "xOA,X", 4 }, +{ "bco", 0x70800000, 0xff880000, "xOA,X", 4 }, +{ "blt", 0x71000000, 0xff880000, "xOA,X", 4 }, +{ "beq", 0x71800000, 0xff880000, "xOA,X", 4 }, +{ "buge", 0x72000000, 0xff880000, "xOA,X", 4 }, +{ "bult", 0x72800000, 0xff880000, "xOA,X", 4 }, +{ "ble", 0x73000000, 0xff880000, "xOA,X", 4 }, +{ "bany", 0x73800000, 0xff880000, "xOA,X", 4 }, +{ "brlnk", 0x44000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bib", 0x48000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bih", 0x48080000, 0xfc080000, "r,xOA,X", 4 }, +{ "biw", 0x4c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bid", 0x4c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivb", 0x60000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivh", 0x60080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivw", 0x64000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivd", 0x64080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsb", 0x68000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsh", 0x68080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsw", 0x6c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsd", 0x6c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "camb", 0x80080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camh", 0x80000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x80000002, 0xfc080002, "r,xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "card", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "ci", 0xf8050000, 0xfc7f0000, "r,I", 4 }, +{ "chkbnd", 0x5c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "cavv", 0x10010000, 0xfc0f0000, "v,V", 2 }, +{ "cavr", 0x10020000, 0xfc0f0000, "v,R", 2 }, +{ "cavvd", 0x10090000, 0xfc0f0000, "v,V", 2 }, +{ "cavrd", 0x100b0000, 0xfc0f0000, "v,R", 2 }, + +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "ani", 0xf8080000, 0xfc7f0000, "r,I", 4 }, +{ "ormb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "oi", 0xf8090000, 0xfc7f0000, "r,I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eoi", 0xf80a0000, 0xfc7f0000, "r,I", 4 }, + +{ "anvv", 0x04010000, 0xfc0f0000, "v,V", 2 }, +{ "anvr", 0x04020000, 0xfc0f0000, "v,R", 2 }, +{ "orvv", 0x08010000, 0xfc0f0000, "v,V", 2 }, +{ "orvr", 0x08020000, 0xfc0f0000, "v,R", 2 }, +{ "eovv", 0x0c010000, 0xfc0f0000, "v,V", 2 }, +{ "eovr", 0x0c020000, 0xfc0f0000, "v,R", 2 }, + +{ "sacz", 0x100c0000, 0xfc0f0000, "r,R", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "sda", 0x3c030000, 0xfc0f0000, "r,R", 2 }, +{ "sdl", 0x3c020000, 0xfc0f0000, "r,R", 2 }, +{ "sdc", 0x3c010000, 0xfc0f0000, "r,R", 2 }, +{ "sdad", 0x3c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "sdld", 0x3c0a0000, 0xfc0f0000, "r,R", 2 }, + +{ "svda", 0x3c070000, 0xfc0f0000, "v,R", 2 }, +{ "svdl", 0x3c060000, 0xfc0f0000, "v,R", 2 }, +{ "svdc", 0x3c050000, 0xfc0f0000, "v,R", 2 }, +{ "svdad", 0x3c0e0000, 0xfc0f0000, "v,R", 2 }, +{ "svdld", 0x3c0d0000, 0xfc0f0000, "v,R", 2 }, + +{ "sbm", 0xac080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbm", 0xac000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbm", 0xa8080000, 0xfc080000, "f,xOA,X", 4 }, +{ "incmb", 0xa0000000, 0xfc080000, "xOA,X", 4 }, +{ "incmh", 0xa0080000, 0xfc080000, "xOA,X", 4 }, +{ "incmw", 0xa4000000, 0xfc080000, "xOA,X", 4 }, +{ "incmd", 0xa4080000, 0xfc080000, "xOA,X", 4 }, +{ "sbmd", 0x7c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zbmd", 0x7c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "tbmd", 0x78080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "ssm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zsm", 0x9c000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tsm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, + +{ "admb", 0xc8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admh", 0xc8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xc8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xc8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adi", 0xf8010000, 0xfc0f0000, "r,I", 4 }, +{ "sumb", 0xcc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumh", 0xcc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xcc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "sui", 0xf8020000, 0xfc0f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprd", 0x3c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "mpi", 0xf8030000, 0xfc0f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvi", 0xf8040000, 0xfc0f0000, "r,I", 4 }, +{ "exs", 0x38080000, 0xfc0f0000, "r,R", 2 }, + +{ "advv", 0x30000000, 0xfc0f0000, "v,V", 2 }, +{ "advvd", 0x30080000, 0xfc0f0000, "v,V", 2 }, +{ "adrv", 0x34000000, 0xfc0f0000, "v,R", 2 }, +{ "adrvd", 0x34080000, 0xfc0f0000, "v,R", 2 }, +{ "suvv", 0x30010000, 0xfc0f0000, "v,V", 2 }, +{ "suvvd", 0x30090000, 0xfc0f0000, "v,V", 2 }, +{ "surv", 0x34010000, 0xfc0f0000, "v,R", 2 }, +{ "survd", 0x34090000, 0xfc0f0000, "v,R", 2 }, +{ "mpvv", 0x30020000, 0xfc0f0000, "v,V", 2 }, +{ "mprv", 0x34020000, 0xfc0f0000, "v,R", 2 }, + +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "surfw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "surfd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,R", 2 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "rfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "rfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "rrfw", 0x0c0e0000, 0xfc0f0000, "r", 2 }, +{ "rrfd", 0x0c0f0000, 0xfc0f0000, "r", 2 }, + +{ "advvfw", 0x30040000, 0xfc0f0000, "v,V", 2 }, +{ "advvfd", 0x300c0000, 0xfc0f0000, "v,V", 2 }, +{ "adrvfw", 0x34040000, 0xfc0f0000, "v,R", 2 }, +{ "adrvfd", 0x340c0000, 0xfc0f0000, "v,R", 2 }, +{ "suvvfw", 0x30050000, 0xfc0f0000, "v,V", 2 }, +{ "suvvfd", 0x300d0000, 0xfc0f0000, "v,V", 2 }, +{ "survfw", 0x34050000, 0xfc0f0000, "v,R", 2 }, +{ "survfd", 0x340d0000, 0xfc0f0000, "v,R", 2 }, +{ "mpvvfw", 0x30060000, 0xfc0f0000, "v,V", 2 }, +{ "mpvvfd", 0x300e0000, 0xfc0f0000, "v,V", 2 }, +{ "mprvfw", 0x34060000, 0xfc0f0000, "v,R", 2 }, +{ "mprvfd", 0x340e0000, 0xfc0f0000, "v,R", 2 }, +{ "rvfw", 0x30070000, 0xfc0f0000, "v", 2 }, +{ "rvfd", 0x300f0000, 0xfc0f0000, "v", 2 }, + +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "cfpds", 0x3c090000, 0xfc0f0000, "r,R", 2 }, + +{ "fltvw", 0x080d0000, 0xfc0f0000, "v,V", 2 }, +{ "fltvd", 0x080f0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvw", 0x080c0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvd", 0x080e0000, 0xfc0f0000, "v,V", 2 }, +{ "cfpvds", 0x0c0d0000, 0xfc0f0000, "v,V", 2 }, + +{ "orvrn", 0x000a0000, 0xfc0f0000, "r,V", 2 }, +{ "andvrn", 0x00080000, 0xfc0f0000, "r,V", 2 }, +{ "frsteq", 0x04090000, 0xfc0f0000, "r,V", 2 }, +{ "sigma", 0x0c080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmad", 0x0c0a0000, 0xfc0f0000, "r,V", 2 }, +{ "sigmf", 0x08080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmfd", 0x080a0000, 0xfc0f0000, "r,V", 2 }, +{ "prodf", 0x04080000, 0xfc0f0000, "r,V", 2 }, +{ "prodfd", 0x040a0000, 0xfc0f0000, "r,V", 2 }, +{ "maxv", 0x10080000, 0xfc0f0000, "r,V", 2 }, +{ "maxvd", 0x100a0000, 0xfc0f0000, "r,V", 2 }, +{ "minv", 0x14080000, 0xfc0f0000, "r,V", 2 }, +{ "minvd", 0x140a0000, 0xfc0f0000, "r,V", 2 }, + +{ "lpsd", 0xf0000000, 0xfc080000, "xOA,X", 4 }, +{ "ldc", 0xf0080000, 0xfc080000, "xOA,X", 4 }, +{ "spm", 0x040c0000, 0xfc0f0000, "r", 2 }, +{ "rpm", 0x040d0000, 0xfc0f0000, "r", 2 }, +{ "tritr", 0x00070000, 0xfc0f0000, "r", 2 }, +{ "trrit", 0x00060000, 0xfc0f0000, "r", 2 }, +{ "rpswt", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "exr", 0xf8070000, 0xfc0f0000, "", 4 }, +{ "halt", 0x00000000, 0xfc0f0000, "", 2 }, +{ "wait", 0x00010000, 0xfc0f0000, "", 2 }, +{ "nop", 0x00020000, 0xfc0f0000, "", 2 }, +{ "eiae", 0x00030000, 0xfc0f0000, "", 2 }, +{ "efae", 0x000d0000, 0xfc0f0000, "", 2 }, +{ "diae", 0x000e0000, 0xfc0f0000, "", 2 }, +{ "dfae", 0x000f0000, 0xfc0f0000, "", 2 }, +{ "spvc", 0xf8060000, 0xfc0f0000, "r,T,N", 4 }, +{ "rdsts", 0x00090000, 0xfc0f0000, "r", 2 }, +{ "setcpu", 0x000c0000, 0xfc0f0000, "r", 2 }, +{ "cmc", 0x000b0000, 0xfc0f0000, "r", 2 }, +{ "trrcu", 0x00040000, 0xfc0f0000, "r", 2 }, +{ "attnio", 0x00050000, 0xfc0f0000, "", 2 }, +{ "fudit", 0x28080000, 0xfc0f0000, "", 2 }, +{ "break", 0x28090000, 0xfc0f0000, "", 2 }, +{ "frzss", 0x280a0000, 0xfc0f0000, "", 2 }, +{ "ripi", 0x04040000, 0xfc0f0000, "r,R", 2 }, +{ "xcp", 0x04050000, 0xfc0f0000, "r", 2 }, +{ "block", 0x04060000, 0xfc0f0000, "", 2 }, +{ "unblock", 0x04070000, 0xfc0f0000, "", 2 }, +{ "trsc", 0x08060000, 0xfc0f0000, "r,R", 2 }, +{ "tscr", 0x08070000, 0xfc0f0000, "r,R", 2 }, +{ "fq", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "flupte", 0x2c080000, 0xfc0f0000, "r", 2 }, +{ "rviu", 0x040f0000, 0xfc0f0000, "", 2 }, +{ "ldel", 0x280c0000, 0xfc0f0000, "r,R", 2 }, +{ "ldu", 0x280d0000, 0xfc0f0000, "r,R", 2 }, +{ "stdecc", 0x280b0000, 0xfc0f0000, "r,R", 2 }, +{ "trpc", 0x08040000, 0xfc0f0000, "r", 2 }, +{ "tpcr", 0x08050000, 0xfc0f0000, "r", 2 }, +{ "ghalt", 0x0c050000, 0xfc0f0000, "r", 2 }, +{ "grun", 0x0c040000, 0xfc0f0000, "", 2 }, +{ "tmpr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "trmp", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, + +{ "trrve", 0x28060000, 0xfc0f0000, "r", 2 }, +{ "trver", 0x28070000, 0xfc0f0000, "r", 2 }, +{ "trvlr", 0x280f0000, 0xfc0f0000, "r", 2 }, + +{ "linkfl", 0x18000000, 0xfc0f0000, "r,R", 2 }, +{ "linkbl", 0x18020000, 0xfc0f0000, "r,R", 2 }, +{ "linkfp", 0x18010000, 0xfc0f0000, "r,R", 2 }, +{ "linkbp", 0x18030000, 0xfc0f0000, "r,R", 2 }, +{ "linkpl", 0x18040000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkl", 0x18080000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkp", 0x18090000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktl", 0x180a0000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktp", 0x180b0000, 0xfc0f0000, "r,R", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/contrib/gdb/include/opcode/ns32k.h b/contrib/gdb/include/opcode/ns32k.h new file mode 100644 index 000000000000..42bb8b87aad6 --- /dev/null +++ b/contrib/gdb/include/opcode/ns32k.h @@ -0,0 +1,491 @@ +/* ns32k-opcode.h -- Opcode table for National Semi 32k processor + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS 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 1, or (at your option) +any later version. + +GAS 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 GAS; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifdef SEQUENT_COMPATABILITY +#define DEF_MODEC 20 +#define DEF_MODEL 21 +#endif + +#ifndef DEF_MODEC +#define DEF_MODEC 20 +#endif + +#ifndef DEF_MODEL +#define DEF_MODEL 20 +#endif +/* + After deciding the instruction entry (via hash.c) the instruction parser + will try to match the operands after the instruction to the required set + given in the entry operandfield. Every operand will result in a change in + the opcode or the addition of data to the opcode. + The operands in the source instruction are checked for inconsistent + semantics. + + F : 32 bit float general form + L : 64 bit float " + B : byte " + W : word " + D : double-word " + A : double-word gen-address-form ie no regs, no immediate + I : integer writeable gen int except immediate (A + reg) + Z : floating writeable gen float except immediate (Z + freg) + d : displacement + b : displacement - pc relative addressing acb + p : displacement - pc relative addressing br bcond bsr cxp + q : quick + i : immediate (8 bits) + This is not a standard ns32k operandtype, it is used to build + instructions like svc arg1,arg2 + Svc is the instruction SuperVisorCall and is sometimes used to + call OS-routines from usermode. Some args might be handy! + r : register number (3 bits) + O : setcfg instruction optionslist + C : cinv instruction optionslist + S : stringinstruction optionslist + U : registerlist save,enter + u : registerlist restore,exit + M : mmu register + P : cpu register + g : 3:rd operand of inss or exts instruction + G : 4:th operand of inss or exts instruction + Those operands are encoded in the same byte. + This byte is placed last in the instruction. + f : operand of sfsr + H : sequent-hack for bsr (Warning) + +column 1 instructions + 2 number of bits in opcode. + 3 number of bits in opcode explicitly + determined by the instruction type. + 4 opcodeseed, the number we build our opcode + from. + 5 operandtypes, used by operandparser. + 6 size in bytes of immediate +*/ +struct ns32k_opcode { + char *name; + unsigned char opcode_id_size; /* not used by the assembler */ + unsigned char opcode_size; + unsigned long opcode_seed; + char *operands; + unsigned char im_size; /* not used by dissassembler */ + char *default_args; /* default to those args when none given */ + char default_modec; /* default to this addr-mode when ambigous + ie when the argument of a general addr-mode + is a plain constant */ + char default_model; /* is a plain label */ +}; + +#ifdef comment +/* This section was from the gdb version of this file. */ + +#ifndef ns32k_opcodeT +#define ns32k_opcodeT int +#endif /* no ns32k_opcodeT */ + +struct not_wot /* ns32k opcode table: wot to do with this */ + /* particular opcode */ +{ + int obits; /* number of opcode bits */ + int ibits; /* number of instruction bits */ + ns32k_opcodeT code; /* op-code (may be > 8 bits!) */ + char *args; /* how to compile said opcode */ +}; + +struct not /* ns32k opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct not_wot detail; /* rest of opcode table [datum] */ +}; + +/* Instructions look like this: + + basic instruction--1, 2, or 3 bytes + index byte for operand A, if operand A is indexed--1 byte + index byte for operand B, if operand B is indexed--1 byte + addressing extension for operand A + addressing extension for operand B + implied operands + + Operand A is the operand listed first in the following opcode table. + Operand B is the operand listed second in the following opcode table. + All instructions have at most 2 general operands, so this is enough. + The implied operands are associated with operands other than A and B. + + Each operand has a digit and a letter. + + The digit gives the position in the assembly language. The letter, + one of the following, tells us what kind of operand it is. */ + +/* F : 32 bit float + * L : 64 bit float + * B : byte + * W : word + * D : double-word + * I : integer not immediate + * Z : floating not immediate + * d : displacement + * q : quick + * i : immediate (8 bits) + * r : register number (3 bits) + * p : displacement - pc relative addressing +*/ + + +#endif /* comment */ + +static const struct ns32k_opcode ns32k_opcodes[]= +{ + { "absf", 14,24, 0x35be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "absl", 14,24, 0x34be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "absb", 14,24, 0x304e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "absw", 14,24, 0x314e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "absd", 14,24, 0x334e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "acbb", 7,16, 0x4c, "2I1q3p", 1, "", DEF_MODEC,DEF_MODEL }, + { "acbw", 7,16, 0x4d, "2I1q3p", 2, "", DEF_MODEC,DEF_MODEL }, + { "acbd", 7,16, 0x4f, "2I1q3p", 4, "", DEF_MODEC,DEF_MODEL }, + { "addf", 14,24, 0x01be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "addl", 14,24, 0x00be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "addb", 6,16, 0x00, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "addw", 6,16, 0x01, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "addd", 6,16, 0x03, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "addcb", 6,16, 0x10, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "addcw", 6,16, 0x11, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "addcd", 6,16, 0x13, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "addpb", 14,24, 0x3c4e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "addpw", 14,24, 0x3d4e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "addpd", 14,24, 0x3f4e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "addqb", 7,16, 0x0c, "2I1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "addqw", 7,16, 0x0d, "2I1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "addqd", 7,16, 0x0f, "2I1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "addr", 6,16, 0x27, "1A2I", 4, "", 21,21 }, + { "adjspb", 11,16, 0x057c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "adjspw", 11,16, 0x057d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "adjspd", 11,16, 0x057f, "1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "andb", 6,16, 0x28, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "andw", 6,16, 0x29, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "andd", 6,16, 0x2b, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "ashb", 14,24, 0x044e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "ashw", 14,24, 0x054e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "ashd", 14,24, 0x074e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "beq", 8,8, 0x0a, "1p", 0, "", 21,21 }, + { "bne", 8,8, 0x1a, "1p", 0, "", 21,21 }, + { "bcs", 8,8, 0x2a, "1p", 0, "", 21,21 }, + { "bcc", 8,8, 0x3a, "1p", 0, "", 21,21 }, + { "bhi", 8,8, 0x4a, "1p", 0, "", 21,21 }, + { "bls", 8,8, 0x5a, "1p", 0, "", 21,21 }, + { "bgt", 8,8, 0x6a, "1p", 0, "", 21,21 }, + { "ble", 8,8, 0x7a, "1p", 0, "", 21,21 }, + { "bfs", 8,8, 0x8a, "1p", 0, "", 21,21 }, + { "bfc", 8,8, 0x9a, "1p", 0, "", 21,21 }, + { "blo", 8,8, 0xaa, "1p", 0, "", 21,21 }, + { "bhs", 8,8, 0xba, "1p", 0, "", 21,21 }, + { "blt", 8,8, 0xca, "1p", 0, "", 21,21 }, + { "bge", 8,8, 0xda, "1p", 0, "", 21,21 }, + { "but", 8,8, 0xea, "1p", 0, "", 21,21 }, + { "buf", 8,8, 0xfa, "1p", 0, "", 21,21 }, + { "bicb", 6,16, 0x08, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "bicw", 6,16, 0x09, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "bicd", 6,16, 0x0b, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "bicpsrb", 11,16, 0x17c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "bicpsrw", 11,16, 0x17d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "bispsrb", 11,16, 0x37c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "bispsrw", 11,16, 0x37d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "bpt", 8,8, 0xf2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "br", 8,8, 0xea, "1p", 0, "", 21,21 }, +#ifdef SEQUENT_COMPATABILITY + { "bsr", 8,8, 0x02, "1H", 0, "", 21,21 }, +#else + { "bsr", 8,8, 0x02, "1p", 0, "", 21,21 }, +#endif + { "caseb", 11,16, 0x77c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "casew", 11,16, 0x77d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "cased", 11,16, 0x77f, "1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cbitb", 14,24, 0x084e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "cbitw", 14,24, 0x094e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "cbitd", 14,24, 0x0b4e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "cbitib", 14,24, 0x0c4e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "cbitiw", 14,24, 0x0d4e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "cbitid", 14,24, 0x0f4e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "checkb", 11,24, 0x0ee, "2A3B1r", 1, "", DEF_MODEC,DEF_MODEL }, + { "checkw", 11,24, 0x1ee, "2A3W1r", 2, "", DEF_MODEC,DEF_MODEL }, + { "checkd", 11,24, 0x3ee, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "cinv", 14,24, 0x271e, "2D1C", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpf", 14,24, 0x09be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpl", 14,24, 0x08be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "cmpb", 6,16, 0x04, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpw", 6,16, 0x05, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpd", 6,16, 0x07, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpmb", 14,24, 0x04ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpmw", 14,24, 0x05ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpmd", 14,24, 0x07ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpqb", 7,16, 0x1c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpqw", 7,16, 0x1d, "2W1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpqd", 7,16, 0x1f, "2D1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpsb", 16,24, 0x040e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpsw", 16,24, 0x050e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpsd", 16,24, 0x070e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpst", 16,24, 0x840e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "comb", 14,24, 0x344e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "comw", 14,24, 0x354e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "comd", 14,24, 0x374e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "cvtp", 11,24, 0x036e, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "cxp", 8,8, 0x22, "1p", 0, "", 21,21 }, + { "cxpd", 11,16, 0x07f, "1A", 4, "", DEF_MODEC,DEF_MODEL }, + { "deib", 14,24, 0x2cce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "deiw", 14,24, 0x2dce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "deid", 14,24, 0x2fce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "dia", 8,8, 0xc2, "", 1, "", DEF_MODEC,DEF_MODEL }, + { "divf", 14,24, 0x21be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "divl", 14,24, 0x20be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "divb", 14,24, 0x3cce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "divw", 14,24, 0x3dce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "divd", 14,24, 0x3fce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "enter", 8,8, 0x82, "1U2d", 0, "", DEF_MODEC,DEF_MODEL }, + { "exit", 8,8, 0x92, "1u", 0, "", DEF_MODEC,DEF_MODEL }, + { "extb", 11,24, 0x02e, "2I3B1r4d", 1, "", DEF_MODEC,DEF_MODEL }, + { "extw", 11,24, 0x12e, "2I3W1r4d", 2, "", DEF_MODEC,DEF_MODEL }, + { "extd", 11,24, 0x32e, "2I3D1r4d", 4, "", DEF_MODEC,DEF_MODEL }, + { "extsb", 14,24, 0x0cce, "1I2I4G3g", 1, "", DEF_MODEC,DEF_MODEL }, + { "extsw", 14,24, 0x0dce, "1I2I4G3g", 2, "", DEF_MODEC,DEF_MODEL }, + { "extsd", 14,24, 0x0fce, "1I2I4G3g", 4, "", DEF_MODEC,DEF_MODEL }, + { "ffsb", 14,24, 0x046e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "ffsw", 14,24, 0x056e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "ffsd", 14,24, 0x076e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "flag", 8,8, 0xd2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "floorfb", 14,24, 0x3c3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorfw", 14,24, 0x3d3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorfd", 14,24, 0x3f3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorlb", 14,24, 0x383e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "floorlw", 14,24, 0x393e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "floorld", 14,24, 0x3b3e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "ibitb", 14,24, 0x384e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "ibitw", 14,24, 0x394e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "ibitd", 14,24, 0x3b4e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "indexb", 11,24, 0x42e, "2B3B1r", 1, "", DEF_MODEC,DEF_MODEL }, + { "indexw", 11,24, 0x52e, "2W3W1r", 2, "", DEF_MODEC,DEF_MODEL }, + { "indexd", 11,24, 0x72e, "2D3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "insb", 11,24, 0x0ae, "2B3I1r4d", 1, "", DEF_MODEC,DEF_MODEL }, + { "insw", 11,24, 0x1ae, "2W3I1r4d", 2, "", DEF_MODEC,DEF_MODEL }, + { "insd", 11,24, 0x3ae, "2D3I1r4d", 4, "", DEF_MODEC,DEF_MODEL }, + { "inssb", 14,24, 0x08ce, "1B2I4G3g", 1, "", DEF_MODEC,DEF_MODEL }, + { "inssw", 14,24, 0x09ce, "1W2I4G3g", 2, "", DEF_MODEC,DEF_MODEL }, + { "inssd", 14,24, 0x0bce, "1D2I4G3g", 4, "", DEF_MODEC,DEF_MODEL }, + { "jsr", 11,16, 0x67f, "1A", 4, "", 21,21 }, + { "jump", 11,16, 0x27f, "1A", 4, "", 21,21 }, + { "lfsr", 19,24, 0x00f3e,"1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "lmr", 15,24, 0x0b1e, "2D1M", 4, "", DEF_MODEC,DEF_MODEL }, + { "lprb", 7,16, 0x6c, "2B1P", 1, "", DEF_MODEC,DEF_MODEL }, + { "lprw", 7,16, 0x6d, "2W1P", 2, "", DEF_MODEC,DEF_MODEL }, + { "lprd", 7,16, 0x6f, "2D1P", 4, "", DEF_MODEC,DEF_MODEL }, + { "lshb", 14,24, 0x144e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "lshw", 14,24, 0x154e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "lshd", 14,24, 0x174e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "meib", 14,24, 0x24ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "meiw", 14,24, 0x25ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "meid", 14,24, 0x27ce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "modb", 14,24, 0x38ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "modw", 14,24, 0x39ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "modd", 14,24, 0x3bce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "movf", 14,24, 0x05be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "movl", 14,24, 0x04be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "movb", 6,16, 0x14, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "movw", 6,16, 0x15, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "movd", 6,16, 0x17, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "movbf", 14,24, 0x043e, "1B2Z", 1, "", DEF_MODEC,DEF_MODEL }, + { "movwf", 14,24, 0x053e, "1W2Z", 2, "", DEF_MODEC,DEF_MODEL }, + { "movdf", 14,24, 0x073e, "1D2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "movbl", 14,24, 0x003e, "1B2Z", 1, "", DEF_MODEC,DEF_MODEL }, + { "movwl", 14,24, 0x013e, "1W2Z", 2, "", DEF_MODEC,DEF_MODEL }, + { "movdl", 14,24, 0x033e, "1D2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "movfl", 14,24, 0x1b3e, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "movlf", 14,24, 0x163e, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "movmb", 14,24, 0x00ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL }, + { "movmw", 14,24, 0x01ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL }, + { "movmd", 14,24, 0x03ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL }, + { "movqb", 7,16, 0x5c, "2I1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "movqw", 7,16, 0x5d, "2I1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "movqd", 7,16, 0x5f, "2I1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "movsb", 16,24, 0x000e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsw", 16,24, 0x010e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsd", 16,24, 0x030e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movst", 16,24, 0x800e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsub", 14,24, 0x0cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "movsuw", 14,24, 0x0dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "movsud", 14,24, 0x0fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "movusb", 14,24, 0x1cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "movusw", 14,24, 0x1dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "movusd", 14,24, 0x1fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "movxbd", 14,24, 0x1cce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "movxwd", 14,24, 0x1dce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "movxbw", 14,24, 0x10ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "movzbd", 14,24, 0x18ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "movzwd", 14,24, 0x19ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "movzbw", 14,24, 0x14ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "mulf", 14,24, 0x31be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "mull", 14,24, 0x30be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "mulb", 14,24, 0x20ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "mulw", 14,24, 0x21ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "muld", 14,24, 0x23ce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "negf", 14,24, 0x15be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "negl", 14,24, 0x14be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "negb", 14,24, 0x204e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "negw", 14,24, 0x214e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "negd", 14,24, 0x234e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "nop", 8,8, 0xa2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "notb", 14,24, 0x244e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "notw", 14,24, 0x254e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "notd", 14,24, 0x274e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "orb", 6,16, 0x18, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "orw", 6,16, 0x19, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "ord", 6,16, 0x1b, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "quob", 14,24, 0x30ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "quow", 14,24, 0x31ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "quod", 14,24, 0x33ce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "rdval", 19,24, 0x0031e,"1A", 4, "", DEF_MODEC,DEF_MODEL }, + { "remb", 14,24, 0x34ce, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "remw", 14,24, 0x35ce, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "remd", 14,24, 0x37ce, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "restore", 8,8, 0x72, "1u", 0, "", DEF_MODEC,DEF_MODEL }, + { "ret", 8,8, 0x12, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "reti", 8,8, 0x52, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "rett", 8,8, 0x42, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "rotb", 14,24, 0x004e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "rotw", 14,24, 0x014e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "rotd", 14,24, 0x034e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "roundfb", 14,24, 0x243e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundfw", 14,24, 0x253e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundfd", 14,24, 0x273e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundlb", 14,24, 0x203e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "roundlw", 14,24, 0x213e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "roundld", 14,24, 0x233e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "rxp", 8,8, 0x32, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqb", 11,16, 0x3c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqw", 11,16, 0x3d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqd", 11,16, 0x3f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sneb", 11,16, 0xbc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "snew", 11,16, 0xbd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sned", 11,16, 0xbf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsb", 11,16, 0x13c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsw", 11,16, 0x13d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsd", 11,16, 0x13f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccb", 11,16, 0x1bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccw", 11,16, 0x1bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccd", 11,16, 0x1bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "shib", 11,16, 0x23c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "shiw", 11,16, 0x23d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "shid", 11,16, 0x23f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsb", 11,16, 0x2bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsw", 11,16, 0x2bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsd", 11,16, 0x2bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtb", 11,16, 0x33c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtw", 11,16, 0x33d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtd", 11,16, 0x33f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sleb", 11,16, 0x3bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slew", 11,16, 0x3bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sled", 11,16, 0x3bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsb", 11,16, 0x43c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsw", 11,16, 0x43d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsd", 11,16, 0x43f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcb", 11,16, 0x4bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcw", 11,16, 0x4bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcd", 11,16, 0x4bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "slob", 11,16, 0x53c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slow", 11,16, 0x53d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "slod", 11,16, 0x53f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsb", 11,16, 0x5bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsw", 11,16, 0x5bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsd", 11,16, 0x5bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltb", 11,16, 0x63c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltw", 11,16, 0x63d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltd", 11,16, 0x63f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgeb", 11,16, 0x6bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgew", 11,16, 0x6bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sged", 11,16, 0x6bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutb", 11,16, 0x73c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutw", 11,16, 0x73d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutd", 11,16, 0x73f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufb", 11,16, 0x7bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufw", 11,16, 0x7bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufd", 11,16, 0x7bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "save", 8,8, 0x62, "1U", 0, "", DEF_MODEC,DEF_MODEL }, + { "sbitb", 14,24, 0x184e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "sbitw", 14,24, 0x194e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "sbitd", 14,24, 0x1b4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "sbitib", 14,24, 0x1c4e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "sbitiw", 14,24, 0x1d4e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "sbitid", 14,24, 0x1f4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "setcfg", 15,24, 0x0b0e, "1O", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsr", 14,24, 0x373e, "1f", 0, "", DEF_MODEC,DEF_MODEL }, + { "skpsb", 16,24, 0x0c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpsw", 16,24, 0x0d0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpsd", 16,24, 0x0f0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpst", 16,24, 0x8c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "smr", 15,24, 0x0f1e, "2I1M", 4, "", DEF_MODEC,DEF_MODEL }, + { "sprb", 7,16, 0x2c, "2I1P", 1, "", DEF_MODEC,DEF_MODEL }, + { "sprw", 7,16, 0x2d, "2I1P", 2, "", DEF_MODEC,DEF_MODEL }, + { "sprd", 7,16, 0x2f, "2I1P", 4, "", DEF_MODEC,DEF_MODEL }, + { "subf", 14,24, 0x11be, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "subl", 14,24, 0x10be, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "subb", 6,16, 0x20, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "subw", 6,16, 0x21, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "subd", 6,16, 0x23, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "subcb", 6,16, 0x30, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "subcw", 6,16, 0x31, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "subcd", 6,16, 0x33, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "subpb", 14,24, 0x2c4e, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "subpw", 14,24, 0x2d4e, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "subpd", 14,24, 0x2f4e, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, +#ifdef NS32K_SVC_IMMED_OPERANDS + { "svc", 8,8, 0xe2, "2i1i", 1, "", DEF_MODEC,DEF_MODEL }, /* not really, but some unix uses it */ +#else + { "svc", 8,8, 0xe2, "", 0, "", DEF_MODEC,DEF_MODEL }, +#endif + { "tbitb", 6,16, 0x34, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "tbitw", 6,16, 0x35, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "tbitd", 6,16, 0x37, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfb", 14,24, 0x2c3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfw", 14,24, 0x2d3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfd", 14,24, 0x2f3e, "1F2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "trunclb", 14,24, 0x283e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "trunclw", 14,24, 0x293e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "truncld", 14,24, 0x2b3e, "1L2I", 8, "", DEF_MODEC,DEF_MODEL }, + { "wait", 8,8, 0xb2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "wrval", 19,24, 0x0071e,"1A", 0, "", DEF_MODEC,DEF_MODEL }, + { "xorb", 6,16, 0x38, "1B2I", 1, "", DEF_MODEC,DEF_MODEL }, + { "xorw", 6,16, 0x39, "1W2I", 2, "", DEF_MODEC,DEF_MODEL }, + { "xord", 6,16, 0x3b, "1D2I", 4, "", DEF_MODEC,DEF_MODEL }, + { "dotf", 14,24, 0x0dfe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "dotl", 14,24, 0x0cfe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "logbf", 14,24, 0x15fe, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "logbl", 14,24, 0x14fe, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, + { "polyf", 14,24, 0x09fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "polyl", 14,24, 0x08fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "scalbf", 14,24, 0x11fe, "1F2Z", 4, "", DEF_MODEC,DEF_MODEL }, + { "scalbl", 14,24, 0x10fe, "1L2Z", 8, "", DEF_MODEC,DEF_MODEL }, +}; + +static const int numopcodes=sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]); + +static const struct ns32k_opcode *const endop = ns32k_opcodes+sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]); + +#define MAX_ARGS 4 +#define ARG_LEN 50 + diff --git a/contrib/gdb/include/opcode/pn.h b/contrib/gdb/include/opcode/pn.h new file mode 100644 index 000000000000..0f59a2a53ce9 --- /dev/null +++ b/contrib/gdb/include/opcode/pn.h @@ -0,0 +1,282 @@ +/* Print GOULD PN (PowerNode) instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB 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 1, or (at your option) +any later version. + +GDB 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 GDB; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and at most four. The length of the + instruction is based on the opcode. + + The mask component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "abm", 0xa0080000, 0xfc080000, "f,xOA,X", 4 }, +{ "abr", 0x18080000, 0xfc0c0000, "r,f", 2 }, +{ "aci", 0xfc770000, 0xfc7f8000, "r,I", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adi", 0xc8010000, 0xfc7f0000, "r,I", 4 }, +{ "admb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "admh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrm", 0x38080000, 0xfc0f0000, "r,R", 2 }, +{ "ai", 0xfc030000, 0xfc07ffff, "I", 4 }, +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bcf", 0xf0000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bct", 0xec000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bei", 0x00060000, 0xffff0000, "", 2 }, +{ "bft", 0xf0000000, 0xff880000, "xOA,X", 4 }, +{ "bib", 0xf4000000, 0xfc780000, "r,xOA", 4 }, +{ "bid", 0xf4600000, 0xfc780000, "r,xOA", 4 }, +{ "bih", 0xf4200000, 0xfc780000, "r,xOA", 4 }, +{ "biw", 0xf4400000, 0xfc780000, "r,xOA", 4 }, +{ "bl", 0xf8800000, 0xff880000, "xOA,X", 4 }, +{ "bsub", 0x5c080000, 0xff8f0000, "", 2 }, +{ "bsubm", 0x28080000, 0xfc080000, "", 4 }, +{ "bu", 0xec000000, 0xff880000, "xOA,X", 4 }, +{ "call", 0x28080000, 0xfc0f0000, "", 2 }, +{ "callm", 0x5c080000, 0xff880000, "", 4 }, +{ "camb", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "camh", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x90000000, 0xfc080000, "r.xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "cd", 0xfc060000, 0xfc070000, "r,f", 4 }, +{ "cea", 0x000f0000, 0xffff0000, "", 2 }, +{ "ci", 0xc8050000, 0xfc7f0000, "r,I", 4 }, +{ "cmc", 0x040a0000, 0xfc7f0000, "r", 2 }, +{ "cmmb", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmmd", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "cmmh", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "cmmw", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmr", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "daci", 0xfc7f0000, 0xfc7f8000, "r,I", 4 }, +{ "dae", 0x000e0000, 0xffff0000, "", 2 }, +{ "dai", 0xfc040000, 0xfc07ffff, "I", 4 }, +{ "dci", 0xfc6f0000, 0xfc7f8000, "r,I", 4 }, +{ "di", 0xfc010000, 0xfc07ffff, "I", 4 }, +{ "dvfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "dvfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvi", 0xc8040000, 0xfc7f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvrfd", 0x380c0000, 0xfc0f0000, "r,R", 4 }, +{ "dvrfw", 0x38040000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "eae", 0x00080000, 0xffff0000, "", 2 }, +{ "eci", 0xfc670000, 0xfc7f8080, "r,I", 4 }, +{ "ecwcs", 0xfc4f0000, 0xfc7f8000, "", 4 }, +{ "ei", 0xfc000000, 0xfc07ffff, "I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eorm", 0x0c080000, 0xfc0f0000, "r,R", 2 }, +{ "es", 0x00040000, 0xfc7f0000, "r", 2 }, +{ "exm", 0xa8000000, 0xff880000, "xOA,X", 4 }, +{ "exr", 0xc8070000, 0xfc7f0000, "r", 2 }, +{ "exrr", 0xc8070002, 0xfc7f0002, "r", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "grio", 0xfc3f0000, 0xfc7f8000, "r,I", 4 }, +{ "halt", 0x00000000, 0xffff0000, "", 2 }, +{ "hio", 0xfc370000, 0xfc7f8000, "r,I", 4 }, +{ "jwcs", 0xfa080000, 0xff880000, "xOA,X", 4 }, +{ "la", 0x50000000, 0xfc000000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lb", 0xac080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lcs", 0x00030000, 0xfc7f0000, "r", 2 }, +{ "ld", 0xac000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lear", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lf", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xcc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lh", 0xac000001, 0xfc080001, "r,xOA,X", 4 }, +{ "li", 0xc8000000, 0xfc7f0000, "r,I", 4 }, +{ "lmap", 0x2c070000, 0xfc7f0000, "r", 2 }, +{ "lmb", 0xb0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lmd", 0xb0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lmh", 0xb0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lmw", 0xb0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnd", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lpsd", 0xf9800000, 0xff880000, "r,xOA,X", 4 }, +{ "lpsdcm", 0xfa800000, 0xff880000, "r,xOA,X", 4 }, +{ "lw", 0xac000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpi", 0xc8030000, 0xfc7f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "nop", 0x00020000, 0xffff0000, "", 2 }, +{ "ormb", 0x88080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0x88000002, 0xfc080002, "r,xOA,X", 4 }, +{ "ormh", 0x88000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0x88000000, 0xfc080000, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "orrm", 0x08080000, 0xfc0f0000, "r,R", 2 }, +{ "rdsts", 0x00090000, 0xfc7f0000, "r", 2 }, +{ "return", 0x280e0000, 0xfc7f0000, "", 2 }, +{ "ri", 0xfc020000, 0xfc07ffff, "I", 4 }, +{ "rnd", 0x00050000, 0xfc7f0000, "r", 2 }, +{ "rpswt", 0x040b0000, 0xfc7f0000, "r", 2 }, +{ "rschnl", 0xfc2f0000, 0xfc7f8000, "r,I", 4 }, +{ "rsctl", 0xfc470000, 0xfc7f8000, "r,I", 4 }, +{ "rwcs", 0x000b0000, 0xfc0f0000, "r,R", 2 }, +{ "sacz", 0x10080000, 0xfc0f0000, "r,R", 2 }, +{ "sbm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, +{ "sbr", 0x18000000, 0xfc0c0000, "r,f", 4 }, +{ "sea", 0x000d0000, 0xffff0000, "", 2 }, +{ "setcpu", 0x2c090000, 0xfc7f0000, "r", 2 }, +{ "sio", 0xfc170000, 0xfc7f8000, "r,I", 4 }, +{ "sipu", 0x000a0000, 0xffff0000, "", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "smc", 0x04070000, 0xfc070000, "", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "stmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stpio", 0xfc270000, 0xfc7f8000, "r,I", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sufd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sufw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sui", 0xc8020000, 0xfc7f0000, "r,I", 4 }, +{ "sumb", 0xbc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xbc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sumh", 0xbc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surm", 0x3c080000, 0xfc0f0000, "r,R", 2 }, +{ "svc", 0xc8060000, 0xffff0000, "", 4 }, +{ "tbm", 0xa4080000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbr", 0x180c0000, 0xfc0c0000, "r,f", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "tccr", 0x28040000, 0xfc7f0000, "", 2 }, +{ "td", 0xfc050000, 0xfc070000, "r,f", 4 }, +{ "tio", 0xfc1f0000, 0xfc7f8000, "r,I", 4 }, +{ "tmapr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "tpcbr", 0x280c0000, 0xfc7f0000, "r", 2 }, +{ "trbr", 0x2c010000, 0xfc0f0000, "b,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "trcc", 0x28050000, 0xfc7f0000, "", 2 }, +{ "trcm", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnm", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trrm", 0x2c080000, 0xfc0f0000, "r,R", 2 }, +{ "trsc", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "trsw", 0x28000000, 0xfc7f0000, "r", 2 }, +{ "tscr", 0x2c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "uei", 0x00070000, 0xffff0000, "", 2 }, +{ "wait", 0x00010000, 0xffff0000, "", 2 }, +{ "wcwcs", 0xfc5f0000, 0xfc7f8000, "", 4 }, +{ "wwcs", 0x000c0000, 0xfc0f0000, "r,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "xcr", 0x2c050000, 0xfc0f0000, "r,R", 2 }, +{ "xcrm", 0x2c0d0000, 0xfc0f0000, "r,R", 2 }, +{ "zbm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbr", 0x18040000, 0xfc0c0000, "r,f", 2 }, +{ "zmb", 0xf8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xf8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "zmh", 0xf8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xf8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zr", 0x0c000000, 0xfc0f0000, "r", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/contrib/gdb/include/opcode/ppc.h b/contrib/gdb/include/opcode/ppc.h new file mode 100644 index 000000000000..a9e3b24ab30e --- /dev/null +++ b/contrib/gdb/include/opcode/ppc.h @@ -0,0 +1,248 @@ +/* ppc.h -- Header file for PowerPC opcode table + Copyright 1994, 1995 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +This file is part of GDB, GAS, and the GNU binutils. + +GDB, GAS, and the GNU binutils are free software; you can redistribute +them and/or modify them under the terms of the GNU General Public +License as published by the Free Software Foundation; either version +1, or (at your option) any later version. + +GDB, GAS, and the GNU binutils are distributed in the hope that they +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 file; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef PPC_H +#define PPC_H + +/* The opcode table is an array of struct powerpc_opcode. */ + +struct powerpc_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned long opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned long mask; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The defined values + are listed below. */ + unsigned long flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[8]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct powerpc_opcode powerpc_opcodes[]; +extern const int powerpc_num_opcodes; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* Opcode is defined for the PowerPC architecture. */ +#define PPC_OPCODE_PPC (01) + +/* Opcode is defined for the POWER (RS/6000) architecture. */ +#define PPC_OPCODE_POWER (02) + +/* Opcode is defined for the POWER2 (Rios 2) architecture. */ +#define PPC_OPCODE_POWER2 (04) + +/* Opcode is only defined on 32 bit architectures. */ +#define PPC_OPCODE_32 (010) + +/* Opcode is only defined on 64 bit architectures. */ +#define PPC_OPCODE_64 (020) + +/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 + is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, + but it also supports many additional POWER instructions. */ +#define PPC_OPCODE_601 (040) + +/* Opcode is supported in both the Power and PowerPC architectures + (ie, compiler's -mcpu=common or assembler's -mcom). */ +#define PPC_OPCODE_COMMON (0100) + +/* Opcode is supported for any Power or PowerPC platform (this is + for the assembler's -many option, and it eliminates duplicates). */ +#define PPC_OPCODE_ANY (0200) + +/* A macro to extract the major opcode from an instruction. */ +#define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* The operands table is an array of struct powerpc_operand. */ + +struct powerpc_operand +{ + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned long (*insert) PARAMS ((unsigned long instruction, long op, + const char **errmsg)); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & PPC_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + long (*extract) PARAMS ((unsigned long instruction, int *invalid)); + + /* One bit syntax flags. */ + unsigned long flags; +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct powerpc_operand powerpc_operands[]; + +/* Values defined for the flags field of a struct powerpc_operand. */ + +/* This operand takes signed values. */ +#define PPC_OPERAND_SIGNED (01) + +/* This operand takes signed values, but also accepts a full positive + range of values when running in 32 bit mode. That is, if bits is + 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, + this flag is ignored. */ +#define PPC_OPERAND_SIGNOPT (02) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics such as mr, for which two + operands fields are identical. The assembler should call the + insert function with any op value. The disassembler should call + the extract function, ignore the return value, and check the value + placed in the valid argument. */ +#define PPC_OPERAND_FAKE (04) + +/* The next operand should be wrapped in parentheses rather than + separated from this one by a comma. This is used for the load and + store instructions which want their operands to look like + reg,displacement(reg) + */ +#define PPC_OPERAND_PARENS (010) + +/* This operand may use the symbolic names for the CR fields, which + are + lt 0 gt 1 eq 2 so 3 un 3 + cr0 0 cr1 1 cr2 2 cr3 3 + cr4 4 cr5 5 cr6 6 cr7 7 + These may be combined arithmetically, as in cr2*4+gt. These are + only supported on the PowerPC, not the POWER. */ +#define PPC_OPERAND_CR (020) + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define PPC_OPERAND_GPR (040) + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define PPC_OPERAND_FPR (0100) + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_RELATIVE (0200) + +/* This operand is an absolute branch address. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_ABSOLUTE (0400) + +/* This operand is optional, and is zero if omitted. This is used for + the optional BF and L fields in the comparison instructions. The + assembler must count the number of operands remaining on the line, + and the number of operands remaining for the opcode, and decide + whether this operand is present or not. The disassembler should + print this operand out only if it is not zero. */ +#define PPC_OPERAND_OPTIONAL (01000) + +/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand + is omitted, then for the next operand use this operand value plus + 1, ignoring the next operand field for the opcode. This wretched + hack is needed because the Power rotate instructions can take + either 4 or 5 operands. The disassembler should print this operand + out regardless of the PPC_OPERAND_OPTIONAL field. */ +#define PPC_OPERAND_NEXT (02000) + +/* This operand should be regarded as a negative number for the + purposes of overflow checking (i.e., the normal most negative + number is disallowed and one more than the normal most positive + number is allowed). This flag will only be set for a signed + operand. */ +#define PPC_OPERAND_NEGATIVE (04000) + +/* The POWER and PowerPC assemblers use a few macros. We keep them + with the operands table for simplicity. The macro table is an + array of struct powerpc_macro. */ + +struct powerpc_macro +{ + /* The macro name. */ + const char *name; + + /* The number of operands the macro takes. */ + unsigned int operands; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The values are the + same as those for the struct powerpc_opcode flags field. */ + unsigned long flags; + + /* A format string to turn the macro into a normal instruction. + Each %N in the string is replaced with operand number N (zero + based). */ + const char *format; +}; + +extern const struct powerpc_macro powerpc_macros[]; +extern const int powerpc_num_macros; + +#endif /* PPC_H */ diff --git a/contrib/gdb/include/opcode/pyr.h b/contrib/gdb/include/opcode/pyr.h new file mode 100644 index 000000000000..06632b8d9197 --- /dev/null +++ b/contrib/gdb/include/opcode/pyr.h @@ -0,0 +1,287 @@ +/* pyramid.opcode.h -- gdb initial attempt. */ + +/* pyramid opcode table: wot to do with this + particular opcode */ + +struct pyr_datum +{ + char nargs; + char * args; /* how to compile said opcode */ + unsigned long mask; /* Bit vector: which operand modes are valid + for this opcode */ + unsigned char code; /* op-code (always 6(?) bits */ +}; + +typedef struct pyr_insn_format { + unsigned int mode :4; + unsigned int operator :8; + unsigned int index_scale :2; + unsigned int index_reg :6; + unsigned int operand_1 :6; + unsigned int operand_2:6; +} pyr_insn_format; + + +/* We store four bytes of opcode for all opcodes. + Pyramid is sufficiently RISCy that: + - insns are always an integral number of words; + - the length of any insn can be told from the first word of + the insn. (ie, if there are zero, one, or two words of + immediate operand/offset). + + + The args component is a string containing two characters for each + operand of the instruction. The first specifies the kind of operand; + the second, the place it is stored. */ + +/* Kinds of operands: + mask assembler syntax description + 0x0001: movw Rn,Rn register to register + 0x0002: movw K,Rn quick immediate to register + 0x0004: movw I,Rn long immediate to register + 0x0008: movw (Rn),Rn register indirect to register + movw (Rn)[x],Rn register indirect to register + 0x0010: movw I(Rn),Rn offset register indirect to register + movw I(Rn)[x],Rn offset register indirect, indexed, to register + + 0x0020: movw Rn,(Rn) register to register indirect + 0x0040: movw K,(Rn) quick immediate to register indirect + 0x0080: movw I,(Rn) long immediate to register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + + 0x0400: movw Rn,I(Rn) register to register indirect+offset + 0x0800: movw K,I(Rn) quick immediate to register indirect+offset + 0x1000: movw I,I(Rn) long immediate to register indirect+offset + 0x1000: movw (Rn),I(Rn) register indirect to-register indirect+offset + 0x1000: movw I(Rn),I(Rn) register indirect+offset to register indirect + +offset + 0x0000: (irregular) ??? + + + Each insn has a four-bit field encoding the type(s) of its operands. +*/ + +/* Some common combinations + */ + +/* the first 5,(0x1|0x2|0x4|0x8|0x10) ie (1|2|4|8|16), ie ( 32 -1)*/ +#define GEN_TO_REG (31) + +#define UNKNOWN ((unsigned long)-1) +#define ANY (GEN_TO_REG | (GEN_TO_REG << 5) | (GEN_TO_REG << 15)) + +#define CONVERT (1|8|0x10|0x20|0x200) + +#define K_TO_REG (2) +#define I_TO_REG (4) +#define NOTK_TO_REG (GEN_TO_REG & ~K_TO_REG) +#define NOTI_TO_REG (GEN_TO_REG & ~I_TO_REG) + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ + +struct pyr_opcode /* pyr opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct pyr_datum datum; /* rest of opcode table [datum] */ +}; + +#define pyr_how args +#define pyr_nargs nargs +#define pyr_mask mask +#define pyr_name name + +struct pyr_opcode pyr_opcodes[] = +{ + {"movb", { 2, "", UNKNOWN, 0x11}, }, + {"movh", { 2, "", UNKNOWN, 0x12} }, + {"movw", { 2, "", ANY, 0x10} }, + {"movl", { 2, "", ANY, 0x13} }, + {"mnegw", { 2, "", (0x1|0x8|0x10), 0x14} }, + {"mnegf", { 2, "", 0x1, 0x15} }, + {"mnegd", { 2, "", 0x1, 0x16} }, + {"mcomw", { 2, "", (0x1|0x8|0x10), 0x17} }, + {"mabsw", { 2, "", (0x1|0x8|0x10), 0x18} }, + {"mabsf", { 2, "", 0x1, 0x19} }, + {"mabsd", { 2, "", 0x1, 0x1a} }, + {"mtstw", { 2, "", (0x1|0x8|0x10), 0x1c} }, + {"mtstf", { 2, "", 0x1, 0x1d} }, + {"mtstd", { 2, "", 0x1, 0x1e} }, + {"mova", { 2, "", 0x8|0x10, 0x1f} }, + {"movzbw", { 2, "", (0x1|0x8|0x10), 0x20} }, + {"movzhw", { 2, "", (0x1|0x8|0x10), 0x21} }, + /* 2 insns out of order here */ + {"movbl", { 2, "", 1, 0x4f} }, + {"filbl", { 2, "", 1, 0x4e} }, + + {"cvtbw", { 2, "", CONVERT, 0x22} }, + {"cvthw", { 2, "", CONVERT, 0x23} }, + {"cvtwb", { 2, "", CONVERT, 0x24} }, + {"cvtwh", { 2, "", CONVERT, 0x25} }, + {"cvtwf", { 2, "", CONVERT, 0x26} }, + {"cvtwd", { 2, "", CONVERT, 0x27} }, + {"cvtfw", { 2, "", CONVERT, 0x28} }, + {"cvtfd", { 2, "", CONVERT, 0x29} }, + {"cvtdw", { 2, "", CONVERT, 0x2a} }, + {"cvtdf", { 2, "", CONVERT, 0x2b} }, + + {"addw", { 2, "", GEN_TO_REG, 0x40} }, + {"addwc", { 2, "", GEN_TO_REG, 0x41} }, + {"subw", { 2, "", GEN_TO_REG, 0x42} }, + {"subwb", { 2, "", GEN_TO_REG, 0x43} }, + {"rsubw", { 2, "", GEN_TO_REG, 0x44} }, + {"mulw", { 2, "", GEN_TO_REG, 0x45} }, + {"emul", { 2, "", GEN_TO_REG, 0x47} }, + {"umulw", { 2, "", GEN_TO_REG, 0x46} }, + {"divw", { 2, "", GEN_TO_REG, 0x48} }, + {"ediv", { 2, "", GEN_TO_REG, 0x4a} }, + {"rdivw", { 2, "", GEN_TO_REG, 0x4b} }, + {"udivw", { 2, "", GEN_TO_REG, 0x49} }, + {"modw", { 2, "", GEN_TO_REG, 0x4c} }, + {"umodw", { 2, "", GEN_TO_REG, 0x4d} }, + + + {"addf", { 2, "", 1, 0x50} }, + {"addd", { 2, "", 1, 0x51} }, + {"subf", { 2, "", 1, 0x52} }, + {"subd", { 2, "", 1, 0x53} }, + {"mulf", { 2, "", 1, 0x56} }, + {"muld", { 2, "", 1, 0x57} }, + {"divf", { 2, "", 1, 0x58} }, + {"divd", { 2, "", 1, 0x59} }, + + + {"cmpb", { 2, "", UNKNOWN, 0x61} }, + {"cmph", { 2, "", UNKNOWN, 0x62} }, + {"cmpw", { 2, "", UNKNOWN, 0x60} }, + {"ucmpb", { 2, "", UNKNOWN, 0x66} }, + /* WHY no "ucmph"??? */ + {"ucmpw", { 2, "", UNKNOWN, 0x65} }, + {"xchw", { 2, "", UNKNOWN, 0x0f} }, + + + {"andw", { 2, "", GEN_TO_REG, 0x30} }, + {"orw", { 2, "", GEN_TO_REG, 0x31} }, + {"xorw", { 2, "", GEN_TO_REG, 0x32} }, + {"bicw", { 2, "", GEN_TO_REG, 0x33} }, + {"lshlw", { 2, "", GEN_TO_REG, 0x38} }, + {"ashlw", { 2, "", GEN_TO_REG, 0x3a} }, + {"ashll", { 2, "", GEN_TO_REG, 0x3c} }, + {"ashrw", { 2, "", GEN_TO_REG, 0x3b} }, + {"ashrl", { 2, "", GEN_TO_REG, 0x3d} }, + {"rotlw", { 2, "", GEN_TO_REG, 0x3e} }, + {"rotrw", { 2, "", GEN_TO_REG, 0x3f} }, + + /* push and pop insns are "going away next release". */ + {"pushw", { 2, "", GEN_TO_REG, 0x0c} }, + {"popw", { 2, "", (0x1|0x8|0x10), 0x0d} }, + {"pusha", { 2, "", (0x8|0x10), 0x0e} }, + + {"bitsw", { 2, "", UNKNOWN, 0x35} }, + {"bitcw", { 2, "", UNKNOWN, 0x36} }, + /* some kind of ibra/dbra insns??*/ + {"icmpw", { 2, "", UNKNOWN, 0x67} }, + {"dcmpw", { 2, "", (1|4|0x20|0x80|0x400|0x1000), 0x69} },/*FIXME*/ + {"acmpw", { 2, "", 1, 0x6b} }, + + /* Call is written as a 1-op insn, but is always (dis)assembled as a 2-op + insn with a 2nd op of tr14. The assembler will have to grok this. */ + {"call", { 2, "", GEN_TO_REG, 0x04} }, + {"call", { 1, "", GEN_TO_REG, 0x04} }, + + {"callk", { 1, "", UNKNOWN, 0x06} },/* system call?*/ + /* Ret is usually written as a 0-op insn, but gets disassembled as a + 1-op insn. The operand is always tr15. */ + {"ret", { 0, "", UNKNOWN, 0x09} }, + {"ret", { 1, "", UNKNOWN, 0x09} }, + {"adsf", { 2, "", (1|2|4), 0x08} }, + {"retd", { 2, "", UNKNOWN, 0x0a} }, + {"btc", { 2, "", UNKNOWN, 0x01} }, + {"bfc", { 2, "", UNKNOWN, 0x02} }, + /* Careful: halt is 0x00000000. Jump must have some other (mode?)bit set?? */ + {"jump", { 1, "", UNKNOWN, 0x00} }, + {"btp", { 2, "", UNKNOWN, 0xf00} }, + /* read control-stack pointer is another 1-or-2 operand insn. */ + {"rcsp", { 2, "", UNKNOWN, 0x01f} }, + {"rcsp", { 1, "", UNKNOWN, 0x01f} } +}; + +/* end: pyramid.opcode.h */ +/* One day I will have to take the time to find out what operands + are valid for these insns, and guess at what they mean. + + I can't imagine what the "I???" insns (iglob, etc) do. + + the arithmetic-sounding insns ending in "p" sound awfully like BCD + arithmetic insns: + dshlp -> Decimal SHift Left Packed + dshrp -> Decimal SHift Right Packed + and cvtlp would be convert long to packed. + I have no idea how the operands are interpreted; but having them be + a long register with (address, length) of an in-memory packed BCD operand + would not be surprising. + They are unlikely to be a packed bcd string: 64 bits of long give + is only 15 digits+sign, which isn't enough for COBOL. + */ +#if 0 + {"wcsp", { 2, "", UNKNOWN, 0x00} }, /*write csp?*/ + /* The OSx Operating System Porting Guide claims SSL does things + with tr12 (a register reserved to it) to do with static block-structure + references. SSL=Set Static Link? It's "Going away next release". */ + {"ssl", { 2, "", UNKNOWN, 0x00} }, + {"ccmps", { 2, "", UNKNOWN, 0x00} }, + {"lcd", { 2, "", UNKNOWN, 0x00} }, + {"uemul", { 2, "", UNKNOWN, 0x00} }, /*unsigned emul*/ + {"srf", { 2, "", UNKNOWN, 0x00} }, /*Gidget time???*/ + {"mnegp", { 2, "", UNKNOWN, 0x00} }, /move-neg phys?*/ + {"ldp", { 2, "", UNKNOWN, 0x00} }, /*load phys?*/ + {"ldti", { 2, "", UNKNOWN, 0x00} }, + {"ldb", { 2, "", UNKNOWN, 0x00} }, + {"stp", { 2, "", UNKNOWN, 0x00} }, + {"stti", { 2, "", UNKNOWN, 0x00} }, + {"stb", { 2, "", UNKNOWN, 0x00} }, + {"stu", { 2, "", UNKNOWN, 0x00} }, + {"addp", { 2, "", UNKNOWN, 0x00} }, + {"subp", { 2, "", UNKNOWN, 0x00} }, + {"mulp", { 2, "", UNKNOWN, 0x00} }, + {"divp", { 2, "", UNKNOWN, 0x00} }, + {"dshlp", { 2, "", UNKNOWN, 0x00} }, /* dec shl packed? */ + {"dshrp", { 2, "", UNKNOWN, 0x00} }, /* dec shr packed? */ + {"movs", { 2, "", UNKNOWN, 0x00} }, /*move (string?)?*/ + {"cmpp", { 2, "", UNKNOWN, 0x00} }, /* cmp phys?*/ + {"cmps", { 2, "", UNKNOWN, 0x00} }, /* cmp (string?)?*/ + {"cvtlp", { 2, "", UNKNOWN, 0x00} }, /* cvt long to p??*/ + {"cvtpl", { 2, "", UNKNOWN, 0x00} }, /* cvt p to l??*/ + {"dintr", { 2, "", UNKNOWN, 0x00} }, /* ?? intr ?*/ + {"rphysw", { 2, "", UNKNOWN, 0x00} }, /* read phys word?*/ + {"wphysw", { 2, "", UNKNOWN, 0x00} }, /* write phys word?*/ + {"cmovs", { 2, "", UNKNOWN, 0x00} }, + {"rsubw", { 2, "", UNKNOWN, 0x00} }, + {"bicpsw", { 2, "", UNKNOWN, 0x00} }, /* clr bit in psw? */ + {"bispsw", { 2, "", UNKNOWN, 0x00} }, /* set bit in psw? */ + {"eio", { 2, "", UNKNOWN, 0x00} }, /* ?? ?io ? */ + {"callp", { 2, "", UNKNOWN, 0x00} }, /* call phys?*/ + {"callr", { 2, "", UNKNOWN, 0x00} }, + {"lpcxt", { 2, "", UNKNOWN, 0x00} }, /*load proc context*/ + {"rei", { 2, "", UNKNOWN, 0x00} }, /*ret from intrpt*/ + {"rport", { 2, "", UNKNOWN, 0x00} }, /*read-port?*/ + {"rtod", { 2, "", UNKNOWN, 0x00} }, /*read-time-of-day?*/ + {"ssi", { 2, "", UNKNOWN, 0x00} }, + {"vtpa", { 2, "", UNKNOWN, 0x00} }, /*virt-to-phys-addr?*/ + {"wicl", { 2, "", UNKNOWN, 0x00} }, /* write icl ? */ + {"wport", { 2, "", UNKNOWN, 0x00} }, /*write-port?*/ + {"wtod", { 2, "", UNKNOWN, 0x00} }, /*write-time-of-day?*/ + {"flic", { 2, "", UNKNOWN, 0x00} }, + {"iglob", { 2, "", UNKNOWN, 0x00} }, /* I global? */ + {"iphys", { 2, "", UNKNOWN, 0x00} }, /* I physical? */ + {"ipid", { 2, "", UNKNOWN, 0x00} }, /* I pid? */ + {"ivect", { 2, "", UNKNOWN, 0x00} }, /* I vector? */ + {"lamst", { 2, "", UNKNOWN, 0x00} }, + {"tio", { 2, "", UNKNOWN, 0x00} }, +#endif diff --git a/contrib/gdb/include/opcode/rs6k.h b/contrib/gdb/include/opcode/rs6k.h new file mode 100644 index 000000000000..fac9cf43f354 --- /dev/null +++ b/contrib/gdb/include/opcode/rs6k.h @@ -0,0 +1,254 @@ +/* IBM RS/6000 instruction set definitions, for GNU software. */ + +/* These are all possible instruction formats as used in IBM Assembler + Language Reference, Appendix A. */ + +typedef enum { A=0, B, D, I, M, SC, X, XL, XO, XFL, XFX } InsnFmt; + +/* Extended opcode masks. Used for extracting extended opcode values from + instructions. Each instruction's format decides which mask applies. + They *should* retain the same order as the above formats. */ + +static int eopMask[] = + { 0x1f, 0, 0, 0, 0, 0, 0x3ff, 0x3ff, 0x1ff, 0x3ff, 0x3ff }; + +/* All the things you need to know about an opcode. */ + +typedef struct rs6000_insn { + char *operator; /* opcode name */ + char *opr_ext; /* opcode name extension */ + InsnFmt format; /* opcode format */ + char p_opcode; /* primary opcode */ + int e_opcode; /* extended opcode */ + char oprnd_format[6]; /* operand format */ +} OPCODE; + +/* operand format specifiers */ + +#define TO 1 +#define RA 2 +#define SI 3 +#define RT 4 +#define UI 5 +#define BF 6 +#define BFA 7 +#define BT 8 +#define BA 9 +#define BB 10 +#define BO 11 +#define BI 12 +#define RB 13 +#define RS 14 +#define SH 15 +#define MB 16 +#define ME 17 +#define SPR 18 +#define DIS 19 +#define FXM 21 +#define FRT 22 +#define NB 23 +#define FRS 24 +#define FRA 25 +#define FRB 26 +#define FRC 27 +#define FLM 28 +#define I 29 +#define LI 30 +#define A2 31 +#define TA14 32 /* 14 bit representation of target address */ +#define TA24 33 /* 24 bit representation of target address */ +#define FL1 34 +#define FL2 35 +#define LEV 36 + +/* RS/6000 INSTRUCTION SET + (sorted on primary and extended opcode) + + oprtr primary ext. +operator ext format opcode opcode operand format +------- ------- ------ ------- ------ --------------- */ + +struct rs6000_insn rs6k_ops [] = { + +{"ti", 0, D, 3, -1, {TO,RA,SI,0} }, +{"muli", 0, D, 7, -1, {RT,RA,SI,0} }, +{"sfi", 0, D, 8, -1, {RT,RA,SI,0} }, +{"dozi", 0, D, 9, -1, {RT,RA,SI,0} }, +{"cmpli", 0, D, 10, -1, {BF,RA,UI,0} }, +{"cmpi", 0, D, 11, -1, {BF,RA,SI,0} }, +{"ai", 0, D, 12, -1, {RT,RA,SI,0} }, +{"ai.", 0, D, 13, -1, {RT,RA,SI,0} }, +{"lil", 0, D, 14, -1, {RT,SI,0} }, /* same as `cal' */ +{"cal", 0, D, 14, -1, {RT,DIS,RA,0} }, +{"liu", 0, D, 15, -1, {RT, UI,0} }, /* same as `cau' */ +{"cau", 0, D, 15, -1, {RT,RA,UI,0} }, + +/* "1" indicates an exception--"bb" is only usable for some values of + BO, so the disassembler first matches this instruction and then changes + it to "bc" if that is the case. */ +{"bb", "1tfla", B, 16, -1, {LI,A2,0} }, +{"bc", "la", B, 16, -1, {BO,BI,TA14,0} }, + +{"svc", "la", SC, 17, -1, {LEV,FL1,FL2,0} }, +{"b", "la", I, 18, -1, {TA24,0} }, +{"mcrf", 0, XL, 19, 0, {BF,BFA,0} }, +{"bcr", "l", XL, 19, 16, {BO,BI,0} }, +{"crnor", 0, XL, 19, 33, {BT,BA,BB,0} }, +{"rfi", 0, X, 19, 50, {0} }, +{"rfsvc", 0, X, 19, 82, {0} }, +{"crandc", 0, XL, 19, 129, {BT,BA,BB,0} }, +{"ics", 0, X, 19, 150, {0} }, +{"crxor", 0, XL, 19, 193, {BT,BA,BB,0} }, +{"crnand", 0, XL, 19, 225, {BT,BA,BB,0} }, +{"crand", 0, XL, 19, 257, {BT,BA,BB,0} }, +{"creqv", 0, XL, 19, 289, {BT,BA,BB,0} }, +{"crorc", 0, XL, 19, 417, {BT,BA,BB,0} }, +{"cror", 0, XL, 19, 449, {BT,BA,BB,0} }, +{"bcc", "l", XL, 19, 528, {BO,BI,0} }, +{"rlimi", ".", M, 20, -1, {RA,RS,SH,MB,ME,0} /*??*/}, +{"rlinm", ".", M, 21, -1, {RA,RS,SH,MB,ME,0} /*??*/}, +{"rlmi", ".", M, 22, -1, {RA,RS,RB,MB,ME,0} /*??*/}, +{"rlnm", ".", M, 23, -1, {RA,RS,RB,MB,ME,0} /*??*/}, +{"oril", 0, D, 24, -1, {RA,RS,UI,0} }, +{"oriu", 0, D, 25, -1, {RA,RS,UI,0} }, +{"xoril", 0, D, 26, -1, {RA,RS,UI,0} }, +{"xoriu", 0, D, 27, -1, {RA,RS,UI,0} }, +{"andil.", 0, D, 28, -1, {RA,RS,UI,0} }, +{"andiu.", 0, D, 29, -1, {RA,RS,UI,0} }, +{"cmp", 0, X, 31, 0, {BF,RA,RB,0} }, +{"t", 0, X, 31, 4, {TO,RA,RB,0} }, +{"sf", "o.", XO, 31, 8, {RT,RA,RB,0} }, +{"a", "o.", XO, 31, 10, {RT,RA,RB,0} }, +{"mfcr", 0, X, 31, 19, {RT,0} }, +{"lx", 0, X, 31, 23, {RT,RA,RB,0} }, +{"sl", ".", X, 31, 24, {RA,RS,RB,0} }, +{"cntlz", ".", XO, 31, 26, {RA,RS,0} }, +{"and", ".", X, 31, 28, {RA,RS,RB,0} }, +{"maskg", ".", X, 31, 29, {RA,RS,RB,0} }, +{"cmpl", 0, X, 31, 32, {BF,RA,RB,0} }, +{"sfe", "o.", XO, 31, 136, {RT,RA,RB,0} }, +{"lux", 0, X, 31, 55, {RT,RA,RB,0} }, +{"andc", ".", X, 31, 60, {RA,RS,RB,0} }, +{"mfmsr", 0, X, 31, 83, {RT,0} }, +{"lbzx", 0, X, 31, 87, {RT,RA,RB,0} }, +{"neg", "o.", XO, 31, 104, {RT,RA,0} }, +{"mul", "o.", XO, 31, 107, {RT,RA,RB,0} }, +{"lbzux", 0, X, 31, 119, {RT,RA,RB,0} }, +{"nor", ".", X, 31, 124, {RA,RS,RB,0} }, +{"ae", "o.", XO, 31, 138, {RT,RA,RB,0} }, +{"mtcrf", 0, XFX, 31, 144, {FXM,RS,0} }, +{"stx", 0, X, 31, 151, {RS,RA,RB,0} }, +{"slq", ".", X, 31, 152, {RA,RS,RB,0} }, +{"sle", ".", X, 31, 153, {RA,RS,RB,0} }, +{"stux", 0, X, 31, 183, {RS,RA,RB,0} }, +{"sliq", ".", X, 31, 184, {RA,RS,SH,0} }, +{"sfze", "o.", XO, 31, 200, {RT,RA,0} }, +{"aze", "o.", XO, 31, 202, {RT,RA,0} }, +{"stbx", 0, X, 31, 215, {RS,RA,RB,0} }, +{"sllq", ".", X, 31, 216, {RA,RS,RB,0} }, +{"sleq", ".", X, 31, 217, {RA,RS,RB,0} }, +{"sfme", "o.", XO, 31, 232, {RT,RA,0} }, +{"ame", "o.", XO, 31, 234, {RT,RA,0} }, +{"muls", "o.", XO, 31, 235, {RT,RA,RB,0} }, +{"stbux", 0, X, 31, 247, {RS,RA,RB,0} }, +{"slliq", ".", X, 31, 248, {RA,RS,SH,0} }, +{"doz", "o.", X, 31, 264, {RT,RA,RB,0} }, +{"cax", "o.", XO, 31, 266, {RT,RA,RB,0} }, +{"lscbx", ".", X, 31, 277, {RT,RA,RB,0} }, +{"lhzx", 0, X, 31, 279, {RT,RA,RB,0} }, +{"eqv", ".", X, 31, 284, {RA,RS,RB,0} }, +{"lhzux", 0, X, 31, 311, {RT,RA,RB,0} }, +{"xor", ".", X, 31, 316, {RA,RS,RB,0} }, +{"div", "o.", XO, 31, 331, {RT,RA,RB,0} }, +{"mfspr", 0, X, 31, 339, {RT,SPR,0} }, +{"lhax", 0, X, 31, 343, {RT,RA,RB,0} }, +{"abs", "o.", XO, 31, 360, {RT,RA,0} }, +{"divs", "o.", XO, 31, 363, {RT,RA,RB,0} }, +{"lhaux", 0, X, 31, 375, {RT,RA,RB,0} }, +{"sthx", 0, X, 31, 407, {RS,RA,RB,0} }, +{"orc", ".", X, 31, 412, {RA,RS,RB,0} }, +{"sthux", 0, X, 31, 439, {RS,RA,RB,0} }, +{"or", ".", X, 31, 444, {RA,RS,RB,0} }, +{"mtspr", 0, X, 31, 467, {SPR,RS,0} }, +{"nand", ".", X, 31, 476, {RA,RS,RB,0} }, +{"nabs", "o.", XO, 31, 488, {RT,RA,0} }, +{"mcrxr", 0, X, 31, 512, {BF,0} }, +{"lsx", 0, X, 31, 533, {RT,RA,RB,0} }, +{"lbrx", 0, X, 31, 534, {RT,RA,RB,0} }, +{"lfsx", 0, X, 31, 535, {FRT,RA,RB,0} }, +{"sr", ".", X, 31, 536, {RA,RS,RB,0} }, +{"rrib", ".", X, 31, 537, {RA,RS,RB,0} }, +{"maskir", ".", X, 31, 541, {RA,RS,RB,0} }, +{"lfsux", 0, X, 31, 567, {FRT,RA,RB,0} }, +{"lsi", 0, X, 31, 597, {RT,RA,NB,0} }, +{"lfdx", 0, X, 31, 599, {FRT,RA,RB,0} }, +{"lfdux", 0, X, 31, 631, {FRT,RA,RB,0} }, +{"stsx", 0, X, 31, 661, {RS,RA,RB,0} }, +{"stbrx", 0, X, 31, 662, {RS,RA,RB,0} }, +{"stfsx", 0, X, 31, 663, {FRS,RA,RB,0} }, +{"srq", ".", X, 31, 664, {RA,RS,RB,0} }, +{"sre", ".", X, 31, 665, {RA,RS,RB,0} }, +{"stfsux", 0, X, 31, 695, {FRS,RA,RB,0} }, +{"sriq", ".", X, 31, 696, {RA,RS,SH,0} }, +{"stsi", 0, X, 31, 725, {RS,RA,NB,0} }, +{"stfdx", 0, X, 31, 727, {FRS,RA,RB,0} }, +{"srlq", ".", X, 31, 728, {RA,RS,RB,0} }, +{"sreq", ".", X, 31, 729, {RA,RS,RB,0} }, +{"stfdux", 0, X, 31, 759, {FRS,RA,RB,0} }, +{"srliq", ".", X, 31, 760, {RA,RS,SH,0} }, +{"lhbrx", 0, X, 31, 790, {RT,RA,RB,0} }, +{"sra", ".", X, 31, 792, {RA,RS,RB,0} }, +{"srai", ".", X, 31, 824, {RA,RS,SH,0} }, +{"sthbrx", 0, X, 31, 918, {RS,RA,RB,0} }, +{"sraq", ".", X, 31, 920, {RA,RS,RB,0} }, +{"srea", ".", X, 31, 921, {RA,RS,RB,0} }, +{"exts", ".", X, 31, 922, {RA,RS,0} }, +{"sraiq", ".", X, 31, 952, {RA,RS,SH,0} }, +{"l", 0, D, 32, -1, {RT,DIS,RA,0} }, +{"lu", 0, D, 33, -1, {RT,DIS,RA,0} }, +{"lbz", 0, D, 34, -1, {RT,DIS,RA,0} }, +{"lbzu", 0, D, 35, -1, {RT,DIS,RA,0} }, +{"st", 0, D, 36, -1, {RS,DIS,RA,0} }, +{"stu", 0, D, 37, -1, {RS,DIS,RA,0} }, +{"stb", 0, D, 38, -1, {RS,DIS,RA,0} }, +{"stbu", 0, D, 39, -1, {RS,DIS,RA,0} }, +{"lhz", 0, D, 40, -1, {RT,DIS,RA,0} }, +{"lhzu", 0, D, 41, -1, {RT,DIS,RA,0} }, +{"lha", 0, D, 42, -1, {RT,DIS,RA,0} }, +{"lhau", 0, D, 43, -1, {RT,DIS,RA,0} }, +{"sth", 0, D, 44, -1, {RS,DIS,RA,0} }, +{"sthu", 0, D, 45, -1, {RS,DIS,RA,0} }, +{"lm", 0, D, 46, -1, {RT,DIS,RA,0} }, +{"stm", 0, D, 47, -1, {RS,DIS,RA,0} }, +{"lfs", 0, D, 48, -1, {FRT,DIS,RA,0} }, +{"lfsu", 0, D, 49, -1, {FRT,DIS,RA,0} }, +{"lfd", 0, D, 50, -1, {FRT,DIS,RA,0} }, +{"lfdu", 0, D, 51, -1, {FRT,DIS,RA,0} }, +{"stfs", 0, D, 52, -1, {FRS,DIS,RA,0} }, +{"stfsu", 0, D, 53, -1, {FRS,DIS,RA,0} }, +{"stfd", 0, D, 54, -1, {FRS,DIS,RA,0} }, +{"stfdu", 0, D, 55, -1, {FRS,DIS,RA,0} }, +{"fcmpu", 0, X, 63, 0, {BF,FRA,FRB,0} }, +{"frsp", ".", X, 63, 12, {FRT,FRB,0} }, +{"fd", ".", A, 63, 18, {FRT,FRA,FRB,0} }, +{"fs", ".", A, 63, 20, {FRT,FRA,FRB,0} }, +{"fa", ".", A, 63, 21, {FRT,FRA,FRB,0} }, +{"fm", ".", A, 63, 25, {FRT,FRA,FRC,0} }, +{"fms", ".", A, 63, 28, {FRT,FRA,FRC,FRB,0} }, +{"fma", ".", A, 63, 29, {FRT,FRA,FRC,FRB,0} }, +{"fnms", ".", A, 63, 30, {FRT,FRA,FRC,FRB,0} }, +{"fnma", ".", A, 63, 31, {FRT,FRA,FRC,FRB,0} }, +{"fcmpo", 0, X, 63, 32, {BF,FRA,FRB,0} }, +{"mtfsb1", ".", X, 63, 38, {BT,0} }, +{"fneg", ".", X, 63, 40, {FRT,FRB,0} }, +{"mcrfs", 0, X, 63, 64, {BF,BFA,0} }, +{"mtfsb0", ".", X, 63, 70, {BT,0} }, +{"fmr", ".", X, 63, 72, {FRT,FRB,0} }, +{"mtfsfi", ".", X, 63, 134, {BF,I,0} }, +{"fnabs", ".", X, 63, 136, {FRT,FRB,0} }, +{"fabs", ".", X, 63, 264, {FRT,FRB,0} }, +{"mffs", ".", X, 63, 583, {FRT,0} }, +{"mtfsf", ".", XFL, 63, 711, {FLM,FRB,0} }, +}; + +#define NOPCODES (sizeof (rs6k_ops) / sizeof (struct rs6000_insn)) diff --git a/contrib/gdb/include/opcode/sparc.h b/contrib/gdb/include/opcode/sparc.h new file mode 100644 index 000000000000..b9281e6070cb --- /dev/null +++ b/contrib/gdb/include/opcode/sparc.h @@ -0,0 +1,220 @@ +/* Definitions for opcode table for the sparc. + Copyright (C) 1989, 1991, 1992, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and +the GNU Binutils. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS/GDB 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 GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The SPARC opcode table (and other related data) is defined in + the opcodes library in sparc-opc.c. If you change anything here, make + sure you fix up that file, and vice versa. */ + + /* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* List of instruction sets variations. + These values are such that each element is either a superset of a + preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P + returns non-zero. + The values are indices into `sparc_opcode_archs' defined in sparc-opc.c. + Don't change this without updating sparc-opc.c. */ + +enum sparc_opcode_arch_val { + SPARC_OPCODE_ARCH_V6 = 0, + SPARC_OPCODE_ARCH_V7, + SPARC_OPCODE_ARCH_V8, + SPARC_OPCODE_ARCH_SPARCLET, + SPARC_OPCODE_ARCH_SPARCLITE, + /* v9 variants must appear last */ + SPARC_OPCODE_ARCH_V9, + SPARC_OPCODE_ARCH_V9A, /* v9 with ultrasparc additions */ + SPARC_OPCODE_ARCH_BAD /* error return from sparc_opcode_lookup_arch */ +}; + +/* The highest architecture in the table. */ +#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1) + +/* Table of cpu variants. */ + +struct sparc_opcode_arch { + const char *name; + /* Mask of sparc_opcode_arch_val's supported. + EG: For v7 this would be ((1 << v6) | (1 << v7)). */ + /* These are short's because sparc_opcode.architecture is. */ + short supported; +}; + +extern const struct sparc_opcode_arch sparc_opcode_archs[]; + +/* Given architecture name, look up it's sparc_opcode_arch_val value. */ +extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch (); + +/* Return the bitmask of supported architectures for ARCH. */ +#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) + +/* Non-zero if ARCH1 conflicts with ARCH2. + IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ +#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ +(((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH1)) \ + && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH2))) + +/* Structure of an opcode table entry. */ + +struct sparc_opcode { + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* This was called "delayed" in versions before the flags. */ + char flags; + short architecture; /* Bitmask of sparc_opcode_arch_val's. */ +}; + +#define F_DELAYED 1 /* Delayed branch */ +#define F_ALIAS 2 /* Alias for a "real" instruction */ +#define F_UNBR 4 /* Unconditional branch */ +#define F_CONDBR 8 /* Conditional branch */ +#define F_JSR 16 /* Subroutine call */ +/* FIXME: Add F_ANACHRONISTIC flag for v9. */ + +/* + +All sparc opcodes are 32 bits, except for the `set' instruction (really a +macro), which is 64 bits. It is handled as a special case. + +The match component is a mask saying which bits must match a particular +opcode in order for an instruction to be an instance of that opcode. + +The args component is a string containing one character for each operand of the +instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + K MEMBAR mask (7 bits). (v9) + j 10 bit Immediate. (v9) + I 11 bit Immediate. (v9) + i 13 bit Immediate. + n 22 bit immediate. + k 2+14 bit PC relative immediate. (v9) + G 19 bit PC relative immediate. (v9) + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + N Branch predict clear ",pn" (v9) + T Branch predict set ",pt" (v9) + z %icc. (v9) + Z %xcc. (v9) + q Floating point queue. + r Single register that is both rs1 and rd. + O Single register that is both rs2 and rd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + u sparclet coprocessor registers in rd position + U sparclet coprocessor registers in rs1 position + E %ccr. (v9) + s %fprs. (v9) + P %pc. (v9) + W %tick. (v9) + o %asi. (v9) + 6 %fcc0. (v9) + 7 %fcc1. (v9) + 8 %fcc2. (v9) + 9 %fcc3. (v9) + ! Privileged Register in rd (v9) + ? Privileged Register in rs1 (v9) + * Prefetch function constant. (v9) + x OPF field (v9 impdep). + +The following chars are unused: (note: ,[] are used as punctuation) +[XY3450] + +*/ + +#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ +#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ +#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */ +#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ +#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */ +#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ +#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ +#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ +#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ +#define F1(x) (OP(x)) +#define DISP30(x) ((x)&0x3fffffff) +#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ +#define RS2(x) ((x)&0x1f) /* rs2 field */ +#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ +#define RD(x) (((x)&0x1f) << 25) /* destination register field */ +#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ +#define ASI_RS2(x) (SIMM13(x)) +#define MEMBAR(x) ((x)&0x7f) + +#define ANNUL (1<<29) +#define BPRED (1<<19) /* v9 */ +#define IMMED F3I(1) +#define RD_G0 RD(~0) +#define RS1_G0 RS1(~0) +#define RS2_G0 RS2(~0) + +extern struct sparc_opcode sparc_opcodes[]; +extern const int sparc_num_opcodes; + +int sparc_encode_asi (); +char *sparc_decode_asi (); +int sparc_encode_membar (); +char *sparc_decode_membar (); +int sparc_encode_prefetch (); +char *sparc_decode_prefetch (); +int sparc_encode_sparclet_cpreg (); +char *sparc_decode_sparclet_cpreg (); + +/* + * Local Variables: + * fill-column: 131 + * comment-column: 0 + * End: + */ + +/* end of sparc.h */ diff --git a/contrib/gdb/include/opcode/tahoe.h b/contrib/gdb/include/opcode/tahoe.h new file mode 100644 index 000000000000..b5cee249ee44 --- /dev/null +++ b/contrib/gdb/include/opcode/tahoe.h @@ -0,0 +1,213 @@ +/* + * Ported by the State University of New York at Buffalo by the Distributed + * Computer Systems Lab, Department of Computer Science, 1991. + */ + +#ifndef tahoe_opcodeT +#define tahoe_opcodeT int +#endif /* no tahoe_opcodeT */ + +struct vot_wot /* tahoe opcode table: wot to do with this */ + /* particular opcode */ +{ + char * args; /* how to compile said opcode */ + tahoe_opcodeT code; /* op-code (may be > 8 bits!) */ +}; + +struct vot /* tahoe opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct vot_wot detail; /* rest of opcode table [datum] */ +}; + +#define vot_how args +#define vot_code code +#define vot_detail detail +#define vot_name name + +static struct vot +votstrs[] = +{ +{ "halt", {"", 0x00 } }, +{ "sinf", {"", 0x05 } }, +{ "ldf", {"rl", 0x06 } }, +{ "ldd", {"rq", 0x07 } }, +{ "addb2", {"rbmb", 0x08 } }, +{ "movb", {"rbwb", 0x09 } }, +{ "addw2", {"rwmw", 0x0a } }, +{ "movw", {"rwww", 0x0b } }, +{ "addl2", {"rlml", 0x0c } }, +{ "movl", {"rlwl", 0x0d } }, +{ "bbs", {"rlvlbw", 0x0e } }, +{ "nop", {"", 0x10 } }, +{ "brb", {"bb", 0x11 } }, +{ "brw", {"bw", 0x13 } }, +{ "cosf", {"", 0x15 } }, +{ "lnf", {"rl", 0x16 } }, +{ "lnd", {"rq", 0x17 } }, +{ "addb3", {"rbrbwb", 0x18 } }, +{ "cmpb", {"rbwb", 0x19 } }, +{ "addw3", {"rwrwww", 0x1a } }, +{ "cmpw", {"rwww", 0x1b } }, +{ "addl3", {"rlrlwl", 0x1c } }, +{ "cmpl", {"rlwl", 0x1d } }, +{ "bbc", {"rlvlbw", 0x1e } }, +{ "rei", {"", 0x20 } }, +{ "bneq", {"bb", 0x21 } }, +{ "bnequ", {"bb", 0x21 } }, +{ "cvtwl", {"rwwl", 0x23 } }, +{ "stf", {"wl", 0x26 } }, +{ "std", {"wq", 0x27 } }, +{ "subb2", {"rbmb", 0x28 } }, +{ "mcomb", {"rbwb", 0x29 } }, +{ "subw2", {"rwmw", 0x2a } }, +{ "mcomw", {"rwww", 0x2b } }, +{ "subl2", {"rlml", 0x2c } }, +{ "mcoml", {"rlwl", 0x2d } }, +{ "emul", {"rlrlrlwq", 0x2e } }, +{ "aoblss", {"rlmlbw", 0x2f } }, +{ "bpt", {"", 0x30 } }, +{ "beql", {"bb", 0x31 } }, +{ "beqlu", {"bb", 0x31 } }, +{ "cvtwb", {"rwwb", 0x33 } }, +{ "logf", {"", 0x35 } }, +{ "cmpf", {"rl", 0x36 } }, +{ "cmpd", {"rq", 0x37 } }, +{ "subb3", {"rbrbwb", 0x38 } }, +{ "bitb", {"rbrb", 0x39 } }, +{ "subw3", {"rwrwww", 0x3a } }, +{ "bitw", {"rwrw", 0x3b } }, +{ "subl3", {"rlrlwl", 0x3c } }, +{ "bitl", {"rlrl", 0x3d } }, +{ "ediv", {"rlrqwlwl", 0x3e } }, +{ "aobleq", {"rlmlbw", 0x3f } }, +{ "ret", {"", 0x40 } }, +{ "bgtr", {"bb", 0x41 } }, +{ "sqrtf", {"", 0x45 } }, +{ "cmpf2", {"rl", 0x46 } }, +{ "cmpd2", {"rqrq", 0x47 } }, +{ "shll", {"rbrlwl", 0x48 } }, +{ "clrb", {"wb", 0x49 } }, +{ "shlq", {"rbrqwq", 0x4a } }, +{ "clrw", {"ww", 0x4b } }, +{ "mull2", {"rlml", 0x4c } }, +{ "clrl", {"wl", 0x4d } }, +{ "shal", {"rbrlwl", 0x4e } }, +{ "bleq", {"bb", 0x51 } }, +{ "expf", {"", 0x55 } }, +{ "tstf", {"", 0x56 } }, +{ "tstd", {"", 0x57 } }, +{ "shrl", {"rbrlwl", 0x58 } }, +{ "tstb", {"rb", 0x59 } }, +{ "shrq", {"rbrqwq", 0x5a } }, +{ "tstw", {"rw", 0x5b } }, +{ "mull3", {"rlrlwl", 0x5c } }, +{ "tstl", {"rl", 0x5d } }, +{ "shar", {"rbrlwl", 0x5e } }, +{ "bbssi", {"rlmlbw", 0x5f } }, +{ "ldpctx", {"", 0x60 } }, +{ "pushd", {"", 0x67 } }, +{ "incb", {"mb", 0x69 } }, +{ "incw", {"mw", 0x6b } }, +{ "divl2", {"rlml", 0x6c } }, +{ "incl", {"ml", 0x6d } }, +{ "cvtlb", {"rlwb", 0x6f } }, +{ "svpctx", {"", 0x70 } }, +{ "jmp", {"ab", 0x71 } }, +{ "cvlf", {"rl", 0x76 } }, +{ "cvld", {"rl", 0x77 } }, +{ "decb", {"mb", 0x79 } }, +{ "decw", {"mw", 0x7b } }, +{ "divl3", {"rlrlwl", 0x7c } }, +{ "decl", {"ml", 0x7d } }, +{ "cvtlw", {"rlww", 0x7f } }, +{ "bgeq", {"bb", 0x81 } }, +{ "movs2", {"abab", 0x82 } }, +{ "cvfl", {"wl", 0x86 } }, +{ "cvdl", {"wl", 0x87 } }, +{ "orb2", {"rbmb", 0x88 } }, +{ "cvtbl", {"rbwl", 0x89 } }, +{ "orw2", {"rwmw", 0x8a } }, +{ "bispsw", {"rw", 0x8b } }, +{ "orl2", {"rlml", 0x8c } }, +{ "adwc", {"rlml", 0x8d } }, +{ "adda", {"rlml", 0x8e } }, +{ "blss", {"bb", 0x91 } }, +{ "cmps2", {"abab", 0x92 } }, +{ "ldfd", {"rl", 0x97 } }, +{ "orb3", {"rbrbwb", 0x98 } }, +{ "cvtbw", {"rbww", 0x99 } }, +{ "orw3", {"rwrwww", 0x9a } }, +{ "bicpsw", {"rw", 0x9b } }, +{ "orl3", {"rlrlwl", 0x9c } }, +{ "sbwc", {"rlml", 0x9d } }, +{ "suba", {"rlml", 0x9e } }, +{ "bgtru", {"bb", 0xa1 } }, +{ "cvdf", {"", 0xa6 } }, +{ "andb2", {"rbmb", 0xa8 } }, +{ "movzbl", {"rbwl", 0xa9 } }, +{ "andw2", {"rwmw", 0xaa } }, +{ "loadr", {"rwal", 0xab } }, +{ "andl2", {"rlml", 0xac } }, +{ "mtpr", {"rlrl", 0xad } }, +{ "ffs", {"rlwl", 0xae } }, +{ "blequ", {"bb", 0xb1 } }, +{ "negf", {"", 0xb6 } }, +{ "negd", {"", 0xb7 } }, +{ "andb3", {"rbrbwb", 0xb8 } }, +{ "movzbw", {"rbww", 0xb9 } }, +{ "andw3", {"rwrwww", 0xba } }, +{ "storer", {"rwal", 0xbb } }, +{ "andl3", {"rlrlwl", 0xbc } }, +{ "mfpr", {"rlwl", 0xbd } }, +{ "ffc", {"rlwl", 0xbe } }, +{ "calls", {"rbab", 0xbf } }, +{ "prober", {"rbabrl", 0xc0 } }, +{ "bvc", {"bb", 0xc1 } }, +{ "movs3", {"ababrw", 0xc2 } }, +{ "movzwl", {"rwwl", 0xc3 } }, +{ "addf", {"rl", 0xc6 } }, +{ "addd", {"rq", 0xc7 } }, +{ "xorb2", {"rbmb", 0xc8 } }, +{ "movob", {"rbwb", 0xc9 } }, +{ "xorw2", {"rwmw", 0xca } }, +{ "movow", {"rwww", 0xcb } }, +{ "xorl2", {"rlml", 0xcc } }, +{ "movpsl", {"wl", 0xcd } }, +{ "kcall", {"rw", 0xcf } }, +{ "probew", {"rbabrl", 0xd0 } }, +{ "bvs", {"bb", 0xd1 } }, +{ "cmps3", {"ababrw", 0xd2 } }, +{ "subf", {"rq", 0xd6 } }, +{ "subd", {"rq", 0xd7 } }, +{ "xorb3", {"rbrbwb", 0xd8 } }, +{ "pushb", {"rb", 0xd9 } }, +{ "xorw3", {"rwrwww", 0xda } }, +{ "pushw", {"rw", 0xdb } }, +{ "xorl3", {"rlrlwl", 0xdc } }, +{ "pushl", {"rl", 0xdd } }, +{ "insque", {"abab", 0xe0 } }, +{ "bcs", {"bb", 0xe1 } }, +{ "bgequ", {"bb", 0xe1 } }, +{ "mulf", {"rq", 0xe6 } }, +{ "muld", {"rq", 0xe7 } }, +{ "mnegb", {"rbwb", 0xe8 } }, +{ "movab", {"abwl", 0xe9 } }, +{ "mnegw", {"rwww", 0xea } }, +{ "movaw", {"awwl", 0xeb } }, +{ "mnegl", {"rlwl", 0xec } }, +{ "moval", {"alwl", 0xed } }, +{ "remque", {"ab", 0xf0 } }, +{ "bcc", {"bb", 0xf1 } }, +{ "blssu", {"bb", 0xf1 } }, +{ "divf", {"rq", 0xf6 } }, +{ "divd", {"rq", 0xf7 } }, +{ "movblk", {"alalrw", 0xf8 } }, +{ "pushab", {"ab", 0xf9 } }, +{ "pushaw", {"aw", 0xfb } }, +{ "casel", {"rlrlrl", 0xfc } }, +{ "pushal", {"al", 0xfd } }, +{ "callf", {"rbab", 0xfe } }, +{ "" , "" } /* empty is end sentinel */ + +}; diff --git a/contrib/gdb/include/opcode/vax.h b/contrib/gdb/include/opcode/vax.h new file mode 100644 index 000000000000..f3afebde7e3b --- /dev/null +++ b/contrib/gdb/include/opcode/vax.h @@ -0,0 +1,382 @@ +/* Vax opcde list. + Copyright (C) 1989, 1995 Free Software Foundation, Inc. + +This file is part of GDB and GAS. + +GDB and GAS are 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 1, or (at your option) +any later version. + +GDB and GAS are 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 GDB or GAS; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef vax_opcodeT +#define vax_opcodeT int +#endif /* no vax_opcodeT */ + +struct vot_wot /* vax opcode table: wot to do with this */ + /* particular opcode */ +{ + const char *args; /* how to compile said opcode */ + vax_opcodeT code; /* op-code (may be > 8 bits!) */ +}; + +struct vot /* vax opcode text */ +{ + const char *name; /* opcode name: lowercase string [key] */ + struct vot_wot detail; /* rest of opcode table [datum] */ +}; + +#define vot_how args +#define vot_code code +#define vot_detail detail +#define vot_name name + +static const struct vot +votstrs[] = +{ +{ "halt", {"", 0x00 } }, +{ "nop", {"", 0x01 } }, +{ "rei", {"", 0x02 } }, +{ "bpt", {"", 0x03 } }, +{ "ret", {"", 0x04 } }, +{ "rsb", {"", 0x05 } }, +{ "ldpctx", {"", 0x06 } }, +{ "svpctx", {"", 0x07 } }, +{ "cvtps", {"rwabrwab", 0x08 } }, +{ "cvtsp", {"rwabrwab", 0x09 } }, +{ "index", {"rlrlrlrlrlwl", 0x0a } }, +{ "crc", {"abrlrwab", 0x0b } }, +{ "prober", {"rbrwab", 0x0c } }, +{ "probew", {"rbrwab", 0x0d } }, +{ "insque", {"abab", 0x0e } }, +{ "remque", {"abwl", 0x0f } }, +{ "bsbb", {"bb", 0x10 } }, +{ "brb", {"bb", 0x11 } }, +{ "bneq", {"bb", 0x12 } }, +{ "bnequ", {"bb", 0x12 } }, +{ "beql", {"bb", 0x13 } }, +{ "beqlu", {"bb", 0x13 } }, +{ "bgtr", {"bb", 0x14 } }, +{ "bleq", {"bb", 0x15 } }, +{ "jsb", {"ab", 0x16 } }, +{ "jmp", {"ab", 0x17 } }, +{ "bgeq", {"bb", 0x18 } }, +{ "blss", {"bb", 0x19 } }, +{ "bgtru", {"bb", 0x1a } }, +{ "blequ", {"bb", 0x1b } }, +{ "bvc", {"bb", 0x1c } }, +{ "bvs", {"bb", 0x1d } }, +{ "bcc", {"bb", 0x1e } }, +{ "bgequ", {"bb", 0x1e } }, +{ "blssu", {"bb", 0x1f } }, +{ "bcs", {"bb", 0x1f } }, +{ "addp4", {"rwabrwab", 0x20 } }, +{ "addp6", {"rwabrwabrwab", 0x21 } }, +{ "subp4", {"rwabrwab", 0x22 } }, +{ "subp6", {"rwabrwabrwab", 0x23 } }, +{ "cvtpt", {"rwababrwab", 0x24 } }, +{ "mulp", {"rwabrwabrwab", 0x25 } }, +{ "cvttp", {"rwababrwab", 0x26 } }, +{ "divp", {"rwabrwabrwab", 0x27 } }, +{ "movc3", {"rwabab", 0x28 } }, +{ "cmpc3", {"rwabab", 0x29 } }, +{ "scanc", {"rwababrb", 0x2a } }, +{ "spanc", {"rwababrb", 0x2b } }, +{ "movc5", {"rwabrbrwab", 0x2c } }, +{ "cmpc5", {"rwabrbrwab", 0x2d } }, +{ "movtc", {"rwabrbabrwab", 0x2e } }, +{ "movtuc", {"rwabrbabrwab", 0x2f } }, +{ "bsbw", {"bw", 0x30 } }, +{ "brw", {"bw", 0x31 } }, +{ "cvtwl", {"rwwl", 0x32 } }, +{ "cvtwb", {"rwwb", 0x33 } }, +{ "movp", {"rwabab", 0x34 } }, +{ "cmpp3", {"rwabab", 0x35 } }, +{ "cvtpl", {"rwabwl", 0x36 } }, +{ "cmpp4", {"rwabrwab", 0x37 } }, +{ "editpc", {"rwababab", 0x38 } }, +{ "matchc", {"rwabrwab", 0x39 } }, +{ "locc", {"rbrwab", 0x3a } }, +{ "skpc", {"rbrwab", 0x3b } }, +{ "movzwl", {"rwwl", 0x3c } }, +{ "acbw", {"rwrwmwbw", 0x3d } }, +{ "movaw", {"awwl", 0x3e } }, +{ "pushaw", {"aw", 0x3f } }, +{ "addf2", {"rfmf", 0x40 } }, +{ "addf3", {"rfrfwf", 0x41 } }, +{ "subf2", {"rfmf", 0x42 } }, +{ "subf3", {"rfrfwf", 0x43 } }, +{ "mulf2", {"rfmf", 0x44 } }, +{ "mulf3", {"rfrfwf", 0x45 } }, +{ "divf2", {"rfmf", 0x46 } }, +{ "divf3", {"rfrfwf", 0x47 } }, +{ "cvtfb", {"rfwb", 0x48 } }, +{ "cvtfw", {"rfww", 0x49 } }, +{ "cvtfl", {"rfwl", 0x4a } }, +{ "cvtrfl", {"rfwl", 0x4b } }, +{ "cvtbf", {"rbwf", 0x4c } }, +{ "cvtwf", {"rwwf", 0x4d } }, +{ "cvtlf", {"rlwf", 0x4e } }, +{ "acbf", {"rfrfmfbw", 0x4f } }, +{ "movf", {"rfwf", 0x50 } }, +{ "cmpf", {"rfrf", 0x51 } }, +{ "mnegf", {"rfwf", 0x52 } }, +{ "tstf", {"rf", 0x53 } }, +{ "emodf", {"rfrbrfwlwf", 0x54 } }, +{ "polyf", {"rfrwab", 0x55 } }, +{ "cvtfd", {"rfwd", 0x56 } }, + /* opcode 57 is not defined yet */ +{ "adawi", {"rwmw", 0x58 } }, + /* opcode 59 is not defined yet */ + /* opcode 5a is not defined yet */ + /* opcode 5b is not defined yet */ +{ "insqhi", {"abaq", 0x5c } }, +{ "insqti", {"abaq", 0x5d } }, +{ "remqhi", {"aqwl", 0x5e } }, +{ "remqti", {"aqwl", 0x5f } }, +{ "addd2", {"rdmd", 0x60 } }, +{ "addd3", {"rdrdwd", 0x61 } }, +{ "subd2", {"rdmd", 0x62 } }, +{ "subd3", {"rdrdwd", 0x63 } }, +{ "muld2", {"rdmd", 0x64 } }, +{ "muld3", {"rdrdwd", 0x65 } }, +{ "divd2", {"rdmd", 0x66 } }, +{ "divd3", {"rdrdwd", 0x67 } }, +{ "cvtdb", {"rdwb", 0x68 } }, +{ "cvtdw", {"rdww", 0x69 } }, +{ "cvtdl", {"rdwl", 0x6a } }, +{ "cvtrdl", {"rdwl", 0x6b } }, +{ "cvtbd", {"rbwd", 0x6c } }, +{ "cvtwd", {"rwwd", 0x6d } }, +{ "cvtld", {"rlwd", 0x6e } }, +{ "acbd", {"rdrdmdbw", 0x6f } }, +{ "movd", {"rdwd", 0x70 } }, +{ "cmpd", {"rdrd", 0x71 } }, +{ "mnegd", {"rdwd", 0x72 } }, +{ "tstd", {"rd", 0x73 } }, +{ "emodd", {"rdrbrdwlwd", 0x74 } }, +{ "polyd", {"rdrwab", 0x75 } }, +{ "cvtdf", {"rdwf", 0x76 } }, + /* opcode 77 is not defined yet */ +{ "ashl", {"rbrlwl", 0x78 } }, +{ "ashq", {"rbrqwq", 0x79 } }, +{ "emul", {"rlrlrlwq", 0x7a } }, +{ "ediv", {"rlrqwlwl", 0x7b } }, +{ "clrd", {"wd", 0x7c } }, +{ "clrg", {"wg", 0x7c } }, +{ "clrq", {"wd", 0x7c } }, +{ "movq", {"rqwq", 0x7d } }, +{ "movaq", {"aqwl", 0x7e } }, +{ "movad", {"adwl", 0x7e } }, +{ "pushaq", {"aq", 0x7f } }, +{ "pushad", {"ad", 0x7f } }, +{ "addb2", {"rbmb", 0x80 } }, +{ "addb3", {"rbrbwb", 0x81 } }, +{ "subb2", {"rbmb", 0x82 } }, +{ "subb3", {"rbrbwb", 0x83 } }, +{ "mulb2", {"rbmb", 0x84 } }, +{ "mulb3", {"rbrbwb", 0x85 } }, +{ "divb2", {"rbmb", 0x86 } }, +{ "divb3", {"rbrbwb", 0x87 } }, +{ "bisb2", {"rbmb", 0x88 } }, +{ "bisb3", {"rbrbwb", 0x89 } }, +{ "bicb2", {"rbmb", 0x8a } }, +{ "bicb3", {"rbrbwb", 0x8b } }, +{ "xorb2", {"rbmb", 0x8c } }, +{ "xorb3", {"rbrbwb", 0x8d } }, +{ "mnegb", {"rbwb", 0x8e } }, +{ "caseb", {"rbrbrb", 0x8f } }, +{ "movb", {"rbwb", 0x90 } }, +{ "cmpb", {"rbrb", 0x91 } }, +{ "mcomb", {"rbwb", 0x92 } }, +{ "bitb", {"rbrb", 0x93 } }, +{ "clrb", {"wb", 0x94 } }, +{ "tstb", {"rb", 0x95 } }, +{ "incb", {"mb", 0x96 } }, +{ "decb", {"mb", 0x97 } }, +{ "cvtbl", {"rbwl", 0x98 } }, +{ "cvtbw", {"rbww", 0x99 } }, +{ "movzbl", {"rbwl", 0x9a } }, +{ "movzbw", {"rbww", 0x9b } }, +{ "rotl", {"rbrlwl", 0x9c } }, +{ "acbb", {"rbrbmbbw", 0x9d } }, +{ "movab", {"abwl", 0x9e } }, +{ "pushab", {"ab", 0x9f } }, +{ "addw2", {"rwmw", 0xa0 } }, +{ "addw3", {"rwrwww", 0xa1 } }, +{ "subw2", {"rwmw", 0xa2 } }, +{ "subw3", {"rwrwww", 0xa3 } }, +{ "mulw2", {"rwmw", 0xa4 } }, +{ "mulw3", {"rwrwww", 0xa5 } }, +{ "divw2", {"rwmw", 0xa6 } }, +{ "divw3", {"rwrwww", 0xa7 } }, +{ "bisw2", {"rwmw", 0xa8 } }, +{ "bisw3", {"rwrwww", 0xa9 } }, +{ "bicw2", {"rwmw", 0xaa } }, +{ "bicw3", {"rwrwww", 0xab } }, +{ "xorw2", {"rwmw", 0xac } }, +{ "xorw3", {"rwrwww", 0xad } }, +{ "mnegw", {"rwww", 0xae } }, +{ "casew", {"rwrwrw", 0xaf } }, +{ "movw", {"rwww", 0xb0 } }, +{ "cmpw", {"rwrw", 0xb1 } }, +{ "mcomw", {"rwww", 0xb2 } }, +{ "bitw", {"rwrw", 0xb3 } }, +{ "clrw", {"ww", 0xb4 } }, +{ "tstw", {"rw", 0xb5 } }, +{ "incw", {"mw", 0xb6 } }, +{ "decw", {"mw", 0xb7 } }, +{ "bispsw", {"rw", 0xb8 } }, +{ "bicpsw", {"rw", 0xb9 } }, +{ "popr", {"rw", 0xba } }, +{ "pushr", {"rw", 0xbb } }, +{ "chmk", {"rw", 0xbc } }, +{ "chme", {"rw", 0xbd } }, +{ "chms", {"rw", 0xbe } }, +{ "chmu", {"rw", 0xbf } }, +{ "addl2", {"rlml", 0xc0 } }, +{ "addl3", {"rlrlwl", 0xc1 } }, +{ "subl2", {"rlml", 0xc2 } }, +{ "subl3", {"rlrlwl", 0xc3 } }, +{ "mull2", {"rlml", 0xc4 } }, +{ "mull3", {"rlrlwl", 0xc5 } }, +{ "divl2", {"rlml", 0xc6 } }, +{ "divl3", {"rlrlwl", 0xc7 } }, +{ "bisl2", {"rlml", 0xc8 } }, +{ "bisl3", {"rlrlwl", 0xc9 } }, +{ "bicl2", {"rlml", 0xca } }, +{ "bicl3", {"rlrlwl", 0xcb } }, +{ "xorl2", {"rlml", 0xcc } }, +{ "xorl3", {"rlrlwl", 0xcd } }, +{ "mnegl", {"rlwl", 0xce } }, +{ "casel", {"rlrlrl", 0xcf } }, +{ "movl", {"rlwl", 0xd0 } }, +{ "cmpl", {"rlrl", 0xd1 } }, +{ "mcoml", {"rlwl", 0xd2 } }, +{ "bitl", {"rlrl", 0xd3 } }, +{ "clrf", {"wf", 0xd4 } }, +{ "clrl", {"wl", 0xd4 } }, +{ "tstl", {"rl", 0xd5 } }, +{ "incl", {"ml", 0xd6 } }, +{ "decl", {"ml", 0xd7 } }, +{ "adwc", {"rlml", 0xd8 } }, +{ "sbwc", {"rlml", 0xd9 } }, +{ "mtpr", {"rlrl", 0xda } }, +{ "mfpr", {"rlwl", 0xdb } }, +{ "movpsl", {"wl", 0xdc } }, +{ "pushl", {"rl", 0xdd } }, +{ "moval", {"alwl", 0xde } }, +{ "movaf", {"afwl", 0xde } }, +{ "pushal", {"al", 0xdf } }, +{ "pushaf", {"af", 0xdf } }, +{ "bbs", {"rlvbbb", 0xe0 } }, +{ "bbc", {"rlvbbb", 0xe1 } }, +{ "bbss", {"rlvbbb", 0xe2 } }, +{ "bbcs", {"rlvbbb", 0xe3 } }, +{ "bbsc", {"rlvbbb", 0xe4 } }, +{ "bbcc", {"rlvbbb", 0xe5 } }, +{ "bbssi", {"rlvbbb", 0xe6 } }, +{ "bbcci", {"rlvbbb", 0xe7 } }, +{ "blbs", {"rlbb", 0xe8 } }, +{ "blbc", {"rlbb", 0xe9 } }, +{ "ffs", {"rlrbvbwl", 0xea } }, +{ "ffc", {"rlrbvbwl", 0xeb } }, +{ "cmpv", {"rlrbvbrl", 0xec } }, +{ "cmpzv", {"rlrbvbrl", 0xed } }, +{ "extv", {"rlrbvbwl", 0xee } }, +{ "extzv", {"rlrbvbwl", 0xef } }, +{ "insv", {"rlrlrbvb", 0xf0 } }, +{ "acbl", {"rlrlmlbw", 0xf1 } }, +{ "aoblss", {"rlmlbb", 0xf2 } }, +{ "aobleq", {"rlmlbb", 0xf3 } }, +{ "sobgeq", {"mlbb", 0xf4 } }, +{ "sobgtr", {"mlbb", 0xf5 } }, +{ "cvtlb", {"rlwb", 0xf6 } }, +{ "cvtlw", {"rlww", 0xf7 } }, +{ "ashp", {"rbrwabrbrwab", 0xf8 } }, +{ "cvtlp", {"rlrwab", 0xf9 } }, +{ "callg", {"abab", 0xfa } }, +{ "calls", {"rlab", 0xfb } }, +{ "xfc", {"", 0xfc } }, + /* undefined opcodes here */ +{ "cvtdh", {"rdwh", 0x32fd } }, +{ "cvtgf", {"rgwh", 0x33fd } }, +{ "addg2", {"rgmg", 0x40fd } }, +{ "addg3", {"rgrgwg", 0x41fd } }, +{ "subg2", {"rgmg", 0x42fd } }, +{ "subg3", {"rgrgwg", 0x43fd } }, +{ "mulg2", {"rgmg", 0x44fd } }, +{ "mulg3", {"rgrgwg", 0x45fd } }, +{ "divg2", {"rgmg", 0x46fd } }, +{ "divg3", {"rgrgwg", 0x47fd } }, +{ "cvtgb", {"rgwb", 0x48fd } }, +{ "cvtgw", {"rgww", 0x49fd } }, +{ "cvtgl", {"rgwl", 0x4afd } }, +{ "cvtrgl", {"rgwl", 0x4bfd } }, +{ "cvtbg", {"rbwg", 0x4cfd } }, +{ "cvtwg", {"rwwg", 0x4dfd } }, +{ "cvtlg", {"rlwg", 0x4efd } }, +{ "acbg", {"rgrgmgbw", 0x4ffd } }, +{ "movg", {"rgwg", 0x50fd } }, +{ "cmpg", {"rgrg", 0x51fd } }, +{ "mnegg", {"rgwg", 0x52fd } }, +{ "tstg", {"rg", 0x53fd } }, +{ "emodg", {"rgrwrgwlwg", 0x54fd } }, +{ "polyg", {"rgrwab", 0x55fd } }, +{ "cvtgh", {"rgwh", 0x56fd } }, + /* undefined opcodes here */ +{ "addh2", {"rhmh", 0x60fd } }, +{ "addh3", {"rhrhwh", 0x61fd } }, +{ "subh2", {"rhmh", 0x62fd } }, +{ "subh3", {"rhrhwh", 0x63fd } }, +{ "mulh2", {"rhmh", 0x64fd } }, +{ "mulh3", {"rhrhwh", 0x65fd } }, +{ "divh2", {"rhmh", 0x66fd } }, +{ "divh3", {"rhrhwh", 0x67fd } }, +{ "cvthb", {"rhwb", 0x68fd } }, +{ "cvthw", {"rhww", 0x69fd } }, +{ "cvthl", {"rhwl", 0x6afd } }, +{ "cvtrhl", {"rhwl", 0x6bfd } }, +{ "cvtbh", {"rbwh", 0x6cfd } }, +{ "cvtwh", {"rwwh", 0x6dfd } }, +{ "cvtlh", {"rlwh", 0x6efd } }, +{ "acbh", {"rhrhmhbw", 0x6ffd } }, +{ "movh", {"rhwh", 0x70fd } }, +{ "cmph", {"rhrh", 0x71fd } }, +{ "mnegh", {"rhwh", 0x72fd } }, +{ "tsth", {"rh", 0x73fd } }, +{ "emodh", {"rhrwrhwlwh", 0x74fd } }, +{ "polyh", {"rhrwab", 0x75fd } }, +{ "cvthg", {"rhwg", 0x76fd } }, + /* undefined opcodes here */ +{ "clrh", {"wh", 0x7cfd } }, +{ "clro", {"wo", 0x7cfd } }, +{ "movo", {"rowo", 0x7dfd } }, +{ "movah", {"ahwl", 0x7efd } }, +{ "movao", {"aowl", 0x7efd } }, +{ "pushah", {"ah", 0x7ffd } }, +{ "pushao", {"ao", 0x7ffd } }, + /* undefined opcodes here */ +{ "cvtfh", {"rfwh", 0x98fd } }, +{ "cvtfg", {"rfwg", 0x99fd } }, + /* undefined opcodes here */ +{ "cvthf", {"rhwf", 0xf6fd } }, +{ "cvthd", {"rhwd", 0xf7fd } }, + /* undefined opcodes here */ +{ "bugl", {"rl", 0xfdff } }, +{ "bugw", {"rw", 0xfeff } }, + /* undefined opcodes here */ + +{ "", {"", 0} } /* empty is end sentinel */ + +}; /* votstrs */ + +/* end: vax.opcode.h */ diff --git a/contrib/gdb/include/os9k.h b/contrib/gdb/include/os9k.h new file mode 100644 index 000000000000..0f2eed2d3b1b --- /dev/null +++ b/contrib/gdb/include/os9k.h @@ -0,0 +1,169 @@ +#if !defined(_MODULE_H) +#define _MODULE_H + +/* OS-9000 i386 module header definitions */ +#define _MPF386 + +/* sizeof common header less parity field */ +#define N_M_PARITY (sizeof(mh_com)-sizeof(unisgned short)) +#define OLD_M_PARITY 46 +#define M_PARITY N_M_PARITY + +#ifdef _MPF68K +#define MODSYNC 0x4afd /* module header sync code for 680x0 processors */ +#endif + +#ifdef _MPF386 +#define MODSYNC 0x4afc /* module header sync code for 80386 processors */ +#endif + +#define MODREV 1 /* module format revision 1 */ +#define CRCCON 0x800fe3 /* crc polynomial constant */ + +/* Module access permission values */ +#define MP_OWNER_READ 0x0001 +#define MP_OWNER_WRITE 0x0002 +#define MP_OWNER_EXEC 0x0004 +#define MP_GROUP_READ 0x0010 +#define MP_GROUP_WRITE 0x0020 +#define MP_GROUP_EXEC 0x0040 +#define MP_WORLD_READ 0x0100 +#define MP_WORLD_WRITE 0x0200 +#define MP_WORLD_EXEC 0x0400 +#define MP_WORLD_ACCESS 0x0777 +#define MP_OWNER_MASK 0x000f +#define MP_GROUP_MASK 0x00f0 +#define MP_WORLD_MASK 0x0f00 +#define MP_SYSTM_MASK 0xf000 + +/* Module Type/Language values */ +#define MT_ANY 0 +#define MT_PROGRAM 0x0001 +#define MT_SUBROUT 0x0002 +#define MT_MULTI 0x0003 +#define MT_DATA 0x0004 +#define MT_TRAPLIB 0x000b +#define MT_SYSTEM 0x000c +#define MT_FILEMAN 0x000d +#define MT_DEVDRVR 0x000e +#define MT_DEVDESC 0x000f +#define MT_MASK 0xff00 + +#define ML_ANY 0 +#define ML_OBJECT 1 +#define ML_ICODE 2 +#define ML_PCODE 3 +#define ML_CCODE 4 +#define ML_CBLCODE 5 +#define ML_FRTNCODE 6 +#define ML_MASK 0x00ff + +#define mktypelang(type,lang) (((type)<<8)|(lang)) + +/* Module Attribute values */ +#define MA_REENT 0x80 +#define MA_GHOST 0x40 +#define MA_SUPER 0x20 +#define MA_MASK 0xff00 +#define MR_MASK 0x00ff + +#define mkattrevs(attr, revs) (((attr)<<8)|(revs)) + +#define m_user m_owner.grp_usr.usr +#define m_group m_owner.grp_usr.grp +#define m_group_user m_owner.group_user + +/* macro definitions for accessing module header fields */ +#define MODNAME(mod) ((u_char*)((u_char*)mod + ((Mh_com)mod)->m_name)) +#if 0 +/* Appears not to be used, and the u_int32 typedef is gone (because it + conflicted with a Mach header. */ +#define MODSIZE(mod) ((u_int32)((Mh_com)mod)->m_size) +#endif /* 0 */ +#define MHCOM_BYTES_SIZE 80 +#define N_BADMAG(a) (((a).a_info) != MODSYNC) + +typedef struct mh_com { + /* sync bytes ($4afc). */ + unsigned char m_sync[2]; + unsigned char m_sysrev[2]; /* system revision check value */ + unsigned char + m_size[4]; /* module size */ + unsigned char + m_owner[4]; /* group/user id */ + unsigned char + m_name[4]; /* offset to module name */ + unsigned char + m_access[2], /* access permissions */ + m_tylan[2], /* type/lang */ + m_attrev[2], /* rev/attr */ + m_edit[2]; /* edition */ + unsigned char + m_needs[4], /* module hardware requirements flags. (reserved) */ + m_usage[4], /* comment string offset */ + m_symbol[4], /* symbol table offset */ + m_exec[4], /* offset to execution entry point */ + m_excpt[4], /* offset to exception entry point */ + m_data[4], /* data storage requirement */ + m_stack[4], /* stack size */ + m_idata[4], /* offset to initialized data */ + m_idref[4], /* offset to data reference lists */ + m_init[4], /* initialization routine offset */ + m_term[4]; /* termination routine offset */ + unsigned char + m_ident[2]; /* ident code for ident program */ + char + m_spare[8]; /* reserved bytes */ + unsigned char + m_parity[2]; /* header parity */ +} mh_com,*Mh_com; + +/* Executable memory module */ +typedef mh_com *Mh_exec,mh_exec; + +/* Data memory module */ +typedef mh_com *Mh_data,mh_data; + +/* File manager memory module */ +typedef mh_com *Mh_fman,mh_fman; + +/* device driver module */ +typedef mh_com *Mh_drvr,mh_drvr; + +/* trap handler module */ +typedef mh_com mh_trap, *Mh_trap; + +/* Device descriptor module */ +typedef mh_com *Mh_dev,mh_dev; + +/* Configuration module */ +typedef mh_com *Mh_config, mh_config; + +#if 0 + +#if !defined(_MODDIR_H) +/* go get _os_fmod (and others) */ +#include +#endif + +error_code _os_crc(void *, u_int32, int *); +error_code _os_datmod(char *, u_int32, u_int16 *, u_int16 *, u_int32, void **, mh_data **); +error_code _os_get_moddir(void *, u_int32 *); +error_code _os_initdata(mh_com *, void *); +error_code _os_link(char **, mh_com **, void **, u_int16 *, u_int16 *); +error_code _os_linkm(mh_com *, void **, u_int16 *, u_int16 *); +error_code _os_load(char *, mh_com **, void **, u_int32, u_int16 *, u_int16 *, u_int32); +error_code _os_mkmodule(char *, u_int32, u_int16 *, u_int16 *, u_int32, void **, mh_com **, u_int32); +error_code _os_modaddr(void *, mh_com **); +error_code _os_setcrc(mh_com *); +error_code _os_slink(u_int32, char *, void **, void **, mh_com **); +error_code _os_slinkm(u_int32, mh_com *, void **, void **); +error_code _os_unlink(mh_com *); +error_code _os_unload(char *, u_int32); +error_code _os_tlink(u_int32, char *, void **, mh_trap **, void *, u_int32); +error_code _os_tlinkm(u_int32, mh_com *, void **, void *, u_int32); +error_code _os_iodel(mh_com *); +error_code _os_vmodul(mh_com *, mh_com *, u_int32); +#endif /* 0 */ + +#endif diff --git a/contrib/gdb/include/progress.h b/contrib/gdb/include/progress.h new file mode 100644 index 000000000000..f18318a45140 --- /dev/null +++ b/contrib/gdb/include/progress.h @@ -0,0 +1,37 @@ +/* Default definitions for progress macros. + Copyright (C) 1994 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The default definitions below are intended to be replaced by real + definitions, if building the tools for an interactive programming + environment. */ + +#ifndef _PROGRESS_H +#define _PROGRESS_H + +#ifndef START_PROGRESS +#define START_PROGRESS(STR,N) +#endif + +#ifndef PROGRESS +#define PROGRESS(X) +#endif + +#ifndef END_PROGRESS +#define END_PROGRESS(STR) +#endif + +#endif /* _PROGRESS_H */ diff --git a/contrib/gdb/include/wait.h b/contrib/gdb/include/wait.h new file mode 100644 index 000000000000..fa3c9ccb1d7e --- /dev/null +++ b/contrib/gdb/include/wait.h @@ -0,0 +1,63 @@ +/* Define how to access the int that the wait system call stores. + This has been compatible in all Unix systems since time immemorial, + but various well-meaning people have defined various different + words for the same old bits in the same old int (sometimes claimed + to be a struct). We just know it's an int and we use these macros + to access the bits. */ + +/* The following macros are defined equivalently to their definitions + in POSIX.1. We fail to define WNOHANG and WUNTRACED, which POSIX.1 + defines, since our code does not use waitpid(). We + also fail to declare wait() and waitpid(). */ + +#ifndef WIFEXITED +#define WIFEXITED(w) (((w)&0377) == 0) +#endif + +#ifndef WIFSIGNALED +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#endif + +#ifndef WIFSTOPPED +#ifdef IBM6000 + +/* Unfortunately, the above comment (about being compatible in all Unix + systems) is not quite correct for AIX, sigh. And AIX 3.2 can generate + status words like 0x57c (sigtrap received after load), and gdb would + choke on it. */ + +#define WIFSTOPPED(w) ((w)&0x40) + +#else +#define WIFSTOPPED(w) (((w)&0377) == 0177) +#endif +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(w) (((w) >> 8) & 0377) /* same as WRETCODE */ +#endif + +#ifndef WTERMSIG +#define WTERMSIG(w) ((w) & 0177) +#endif + +#ifndef WSTOPSIG +#define WSTOPSIG WEXITSTATUS +#endif + +/* These are not defined in POSIX, but are used by our programs. */ + +#define WAITTYPE int + +#ifndef WCOREDUMP +#define WCOREDUMP(w) (((w)&0200) != 0) +#endif + +#ifndef WSETEXIT +#define WSETEXIT(w,status) ((w) = (0 | ((status) << 8))) +#endif + +#ifndef WSETSTOP +#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8))) +#endif + diff --git a/contrib/gdb/libiberty/COPYING.LIB b/contrib/gdb/libiberty/COPYING.LIB new file mode 100644 index 000000000000..eb685a5ec981 --- /dev/null +++ b/contrib/gdb/libiberty/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/contrib/gdb/libiberty/ChangeLog b/contrib/gdb/libiberty/ChangeLog new file mode 100644 index 000000000000..b28ef2f6ed52 --- /dev/null +++ b/contrib/gdb/libiberty/ChangeLog @@ -0,0 +1,1815 @@ +Tue Mar 19 22:02:07 1996 Jason Merrill + + * cplus-dem.c (demangle_template): Fix for non-mangled pointer + arguments. + +Fri Mar 8 17:24:18 1996 Ian Lance Taylor + + * configure.in: If srcdir is `.' and with_target_subdir is not + `.', then set MULTISRCTOP before calling config-ml.in. + +Thu Mar 7 13:37:10 1996 Stan Shebs + + * mpw.c (mpw_open): Add debugging output option. + +Wed Mar 6 17:36:03 1996 Jason Merrill + + * cplus-dem.c (demangle_template): Fix for address-of-extern arguments. + +Tue Feb 27 12:00:50 1996 Raymond Jou + + * mpw.c (mpwify_filename): Change 6 to 5 in + strncmp (unixname, "/tmp/", 5). + +Tue Feb 20 10:55:53 1996 Ian Lance Taylor + + * cplus-dem.c (demangle_template): Initialize is_bool. Correctly + handle 0 as a pointer value parameter. + +Mon Feb 5 16:41:44 1996 Ian Lance Taylor + + * Makefile.in (all): Depend upon required-list. + (required-list): New target. + (clean): Remove required-list. + +Wed Jan 31 10:19:41 1996 Steve Chamberlain + + * win32.c: Deleted. + * config.table (i386-*-win32): Deleted. + * config/mh-i386win32: Deleted. + +Thu Jan 18 11:34:17 1996 Ian Lance Taylor + + * cplus-dem.c (cplus_demangle_opname): Change opname parameter to + const char *. + (cplus_mangle_opname): Change return type and opname parameter to + const char *. Don't cast return value. + +Tue Jan 16 12:13:11 1996 Stan Shebs + + * mpw.c: Include Timer.h, in order to get m68k Microseconds trap + definition. + +Wed Jan 3 13:15:04 1996 Fred Fish + + * obstack.c: Update copyright to 1996. + (_obstack_memory_used): Define new function. Called via + obstack_memory_used macro. + +Thu Dec 28 11:39:40 1995 Ian Lance Taylor + + * xstrdup.c: New file. + * Makefile.in (CFILES): Add xstrdup.c. + (REQUIRED_OFILES): Add xstrdup.o. + (xstrdup.o): New target. + +Mon Dec 11 18:18:52 1995 Mike Stump + + * atexit.c: New stub to provide atexit on systems that have + on_exit, like SunOS 4.1.x systems. + * functions.def (on_exit, atexit): Ditto. + +Mon Dec 11 15:42:14 1995 Stan Shebs + + * mpw.c (mpw_abort): Remove decl. + (mpw_access): Move debugging printf. + +Sat Dec 2 01:25:23 1995 Ian Lance Taylor + + * config.table: Consistently use ${host} rather than ${xhost} or + ${target}. + * configure.in: Don't bother to set ${xhost} before calling + config.table. + +Tue Nov 28 14:16:57 1995 Brendan Kehoe + + * Makefile.in (.c.o): Use test instead of the left bracket, to + avoid problems with some versions of make. + +Tue Nov 28 11:45:17 1995 Stan Shebs + + * mpw-make.sed: Fix INCDIR edit to work with Nov 14 change. + +Tue Nov 21 11:26:34 1995 Fred Fish + + * config/mh-hpux: Remove. It was only used to define EXTRA_OFILES, + which was set to just alloca.o, which is now automatically marked + as needed by the autoconfiguration process. + +Tue Nov 21 14:15:06 1995 Ian Lance Taylor + + * config.table: Check ${with_cross_host} rather than comparing + ${host} and ${target}. + +Thu Nov 16 14:34:42 1995 Ian Lance Taylor + + * configure.in: If with_target_subdir is empty, set xhost to + ${host} rather than ${target} before calling config.table. + +Tue Nov 14 01:38:30 1995 Doug Evans + + * Makefile.in (MULTITOP): Deleted. + (MULTISRCTOP, MULTIBUILDTOP): New. + (FLAGS_TO_PASS): Delete INCDIR. + (INCDIR): Add $(MULTISRCTOP). + (install_to_libdir): Add $(MULTISUBDIR). Call $(MULTIDO). + * configure.in: Delete call to cfg-ml-com.in. Call config-ml.in + instead of cfg-ml-pos.in. + (cross-compile check): Change to test for with_target_subdir. + (EXTRA_LINKS): Delete. + +Sun Nov 12 12:13:04 1995 Stan Shebs + + * mpw-make.sed: Add getpagesize.c.o to needed-list. + * mpw.c [USE_MW_HEADERS]: Conditionalize compiling of + functions that are supplied by Metrowerks libraries. + (fstat): Clean up descriptor->pointer conversion code. + (InstallConsole, etc): Empty definitions, for when linking + with SIOUX. + +Sun Nov 5 19:25:27 1995 Per Bothner + + * Makefile.in (FLAGS_TO_PASS): Also pass PICFLAGS. + (.c.o): Stylistic change. + +Thu Nov 2 12:06:29 1995 Ian Lance Taylor + + * strtol.c, strtoul.c: Don't include . From + phdm@info.ucl.ac.be (Philippe De Muyter). + +Wed Nov 1 11:59:36 1995 Ian Lance Taylor + + * configure.in: Correct sed call. + +Mon Oct 30 13:03:45 1995 Per Bothner + + * configure.in: Clean up / simplify for native. + + * configure.in: Merge in stuff from ../xiberty/configure.in. + * Makefile.in (CC): Add definition (so it can be overrridden + by ../configure). + +Tue Oct 24 17:57:27 1995 Stan Shebs + + * mpw-make.sed: Leave strerror.c.o in standard list of functions. + * mpw.c (R_OK, ENOENT, EACCESS, ENOSYS): Remove. + (link): Remove useless definition with error return. + (last_microseconds, warn_if_spin_delay, record_for_spin_delay): + Use UnsignedWide type for microsecond counts. + +Thu Oct 19 10:52:07 1995 Michael Meissner + + * memcmp.c (memcmp): Argument types are const void *, not void + *const. + + * strncasecmp.c (strncasecmp): Include ansidecl.h/stdarg.h, not + sys/types.h. + * strcasecmp.c (strcasecmp): Ditto. + +Tue Oct 10 11:03:24 1995 Fred Fish + + * Makefile.in (BISON): Remove macro. + +Tue Sep 26 15:06:46 1995 Stan Shebs + + * Makefile.in (HFILES): Add default empty definition. + * mpw-config.in (config.h): Only update if changed. + * mpw-make.in: Remove. + * mpw-make.sed: New file, edits Makefile.in into MPW makefile. + * mpw.c: Remove semi-clone of strerror code. + (sys_nerr, sys_errlist): Define here. + (Microseconds): Only define as A-line trap if m68k Mac. + +Wed Sep 20 12:53:32 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New synonym for distclean. + +Mon Aug 28 19:47:52 1995 Per Bothner + + * config.table: For host, generalize rs6000-ibm-aix* + to *-ibm-aix* so we also include powerpc. + +Tue Aug 22 03:18:05 1995 Ken Raeburn + + Fri Jun 16 18:35:40 1995 Pat Rankin (rankin@eql.caltech.edu) + + * xstrerror.c: New file. + * Makefile.in, vmsbuild.com: Compile it. + +Mon Jul 31 12:16:32 1995 steve chamberlain + + * config.table (i386-*-win32): New. + +Fri Jul 21 11:35:52 1995 Doug Evans + + * Makefile.in (MULTITOP): New variable. + (MULTIDIRS, MULTISUBDIR, MULTIDO, MULTICLEAN): Likewise. + (all): Add multilib support. + (install_to_tooldir, *clean): Likewise. + +Mon Jul 10 11:47:27 1995 Ken Raeburn + + * makefile.dos (OBJS): Add hex.o. From DJ Delorie. + +Fri Jun 30 17:28:59 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vmsbuild.com: create "new-lib.olb", build libiberty under that + name, and then make it become "liberty.olb" when done, so that an + incomplete build attempt never leaves behind something which looks + like a complete library. + +Thu Jun 29 00:22:02 1995 Steve Chamberlain + + * config/mh-i386pe: New file for PE hosts. + * config.table: Understand PE hosts. + +Wed Jun 28 19:13:23 1995 Jason Merrill + + * cplus-dem.c: Update from gcc. + + * argv.c, dummy.c: If __STDC__, #include "alloca-conf.h" after + . + * alloca-norm.h: If __STDC__, declare alloca with its parameter. + +Thu Jun 22 18:57:47 1995 Stan Shebs + + * mpw-make.in (ALL_CFLAGS): Define NEED_basename. + * mpw.c: Only test DebugPI once whenever printing debug info. + (mpwify_filename): If filename is /tmp/foo, change it into :_foo, + also fix to not write on input filename buffer. + (mpw_access): Use stat() instead of open(), works for directories + as well as files. + +Mon Jun 19 00:33:22 1995 Jason Merrill + + * Makefile.in: Massage broken shells that require 'else true'. + +Sat Jun 17 23:21:58 1995 Fred Fish + + * alloca-norm.h: Declare alloca as type "PTR" to match functions.def. + Declare __builtin_alloca in the sparc case, as argv.c did. + * argv.c: Replace inline version of alloca-norm.h at start of file with + a #include of alloca-conf.h. Precede it with an include of ansidecl.h + because alloca-norm.h needs to declare alloca as "PTR". + +Mon Jun 12 14:24:26 1995 Steve Chamberlain + + * win32.c: New file. + +Fri Jun 9 15:16:14 1995 Jason Merrill + + * dummy.c: #include "alloca-conf.h". + +Wed Jun 7 11:46:23 1995 Jason Merrill + + * Makefile.in (mostlyclean): Remove stamp-picdir. + (clean): Don't. + +Mon Jun 5 18:46:06 1995 Jason Merrill + + * config.table (frags): Use toplevel pic frags. + + * Makefile.in (PICFLAG): New macro. + (all): Depend on stamp-picdir. + (needed-list): Ditto. + (.c.o): Also build pic object. + (stamp-picdir): New rule. + (mostlyclean): Remove pic. + (clean): Remove stamp-picdir. + +Fri Mar 24 16:55:48 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vmsbuild.com (config.h): Add `#define NEED_basename'. + +Tue May 23 10:12:46 1995 Per Bothner + + * clock.c, getopt.c, strtod.c, vsprintf.c: Change from using LGPL + to libio-style copyright. + * getpagesize.c: Remove FSF copyright. + +Sat May 20 12:30:23 1995 Ken Raeburn + + Added improved VMS support from Pat Rankin: + + Fri Mar 17 18:40:36 1995 Pat Rankin (rankin@eql.caltech.edu) + + * vmsbuild.com: new file. + + * getpagesize.c (getpagesize): implement for VMS; + * strerror.c (strerror, strerrno, strtoerrno): add rudimentary + support for EVMSERR. + +Thu May 18 17:01:42 1995 Ken Raeburn + + Wed May 10 14:28:16 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * floatformat.c (floatformat_arm_ext): Define. + +Tue May 16 13:30:59 1995 Per Bothner + + * basename.c, bcmp.c, getcwd.c, insque.c, rename.c, sigsetmask.c, + strerror.c, strsignal.c: Remove FSF copyright. + * sigsetmask.c: #include - seems to be needed by ISC. + +Mon May 15 19:53:17 1995 Per Bothner + + * bcopy.c, bzero.c, memcmp.c, memcpy.c, memset.c, strchr.c, + strrchr.c, strstr.c, vfork.c: Remove FSF Copyright, because this + might contaminate libstdc++ with the LGPL. (OK'd by RMS 11 Oct 94.) + * strchr.c, strrchr.c: Add cast to suppress const warning. + +Thu May 4 14:36:42 1995 Jason Merrill + + * cplus-dem.c: Use const instead of CONST. Don't include + ansidecl.h directly. + +Wed Apr 19 01:30:27 1995 Jason Merrill + + * cplus-dem.c: Don't include libiberty.h. Do declare xmalloc and + xrealloc. + (-DMAIN): Don't rely on an externally-defined version number; + instead, require the version number to be defined as a + preprocessor macro. Handle the RS/6000 leading dot. Define + xmalloc, xrealloc and fatal. Don't strip a leading underscore + if we couldn't demangle the word. + +Tue Apr 4 13:03:51 1995 Stan Shebs + + (Old mpw.c change descriptions retained for informational value.) + * mpw.c (warning_threshold): Default to .4 sec. + (overflow_count, current_progress): New globals. + (warn_if_spin_delay): Include current progress type, + such as program name, in message. + (mpw_start_progress): Set current_progress variable from arg. + (mpw_end_progress): Report spin delays by power-of-two-size + buckets instead of constant-size buckets. + + * mpw.c: Clean up formatting, types, returns, etc. + (ENOSYS): Define. + (mpw_fread, mpw_fwrite): Define. + (sleep): Define correctly. + + * mpw.c: New code to implement cursor spinning support. + (umask): New function. + (mpw_fopen, mpw_fseek, stat, fstat): Call PROGRESS. + + * mpw.c (mpw_basename, mpw_mixed_basename): New functions, find + basenames for MPW and MPW/Unix filenames. + (mpw_special_init): New function, calls Macsbug if desired. + + * mpw.c: Add GPL notice. + (mpwify_filename): Add more transformations. + (mpw_fopen): Call mpwify_filename on file names. + (rename): Remove. + (chdir, getcwd): Add simple definitions. + + * mpw.c: Random cleanups, remove unused code bits. + Added copy of strerror.c for gcc's use. + (stat, fstat, _stat): New versions based on Guido van Rossum code. + + * mpw.c (mpw_fseek): Make it work correctly when doing SEEK_CUR. + + * mpw.c (stat): Remove hack definition, get from sys/stat.h. + (fork, vfork, etc): Print error messages if called. + (getrusage, sbrk, environ, isatty, link, utime, mkdir, rmdir, + rename, chown): Define. + + * mpw-config.in: New file, MPW version of configure.in. + * mpw-make.in: New file, MPW version of Makefile.in. + * mpw.c: New file, MPW compatibility routines. + +Fri Mar 24 14:10:30 1995 Jim Kingdon (kingdon@lioth.cygnus.com) + + * basename.c: Include config.h before checking for NEED_basename. + +Thu Mar 23 19:09:54 1995 Jason Merrill + + * functions.def: Add DEFFUNC for basename. + + * basename.c: Only define basename if NEED_basename. + +Thu Mar 16 13:36:05 1995 Jason Merrill + + * config.table: Fix --enable-shared logic for native builds. + +Mon Mar 13 11:05:11 1995 Jason Merrill + + * cplus-dem.c (demangle_template): Demangle bool literals properly. + +Mon Mar 6 23:57:28 1995 Stu Grossman (grossman@cygnus.com) + + * strtol.c strtoul.c: Replace these with less buggy versions from + NetBSD. (strtoul in particular couldn't handle base 16.) + +Wed Mar 1 15:59:01 1995 Ian Lance Taylor + + * config/mt-vxworks5 (HDEFINES): Define NO_SYS_PARAM_H. + + * clock.c: If NO_SYS_PARAM_H is defined, don't include + . + * getcwd.c, getpagesize.c, getruntime.c: Likewise. + +Fri Feb 17 15:40:55 1995 Ian Lance Taylor + + * getruntime.c (get_run_time): Don't assume that CLOCKS_PER_SEC is + a number; ANSI appears to permit any expression, including a + function call. + + * config.table (*-*-vxworks5*): Use mt-vxworks5 when configuring + xiberty. + * config/mt-vxworks5: New file. + +Thu Feb 9 14:19:45 1995 Ian Lance Taylor + + * basename.c (basename): Change argument to be const. + +Wed Feb 8 18:06:52 1995 Jason Merrill + + * Makefile.in (lneeded-list): Don't worry about xmalloc. + +Sun Jan 15 00:40:36 1995 Jeff Law (law@snake.cs.utah.edu) + + * Makefile.in (distclean): Delete xhost-mkfrag. + +Thu Jan 12 16:54:18 1995 Jason Merrill + + * Makefile.in (lneeded-list): If alloca.o is needed, so is xmalloc.o. + +Wed Jan 11 22:39:56 1995 Ken Raeburn + + * hex.c: New file. + * Makefile.in (REQUIRED_OFILES, CFILES): List it. + (hex.o): Add dependencies. + + * cplus-dem.c (demangle_prefix): For GNU style constructor and + destructor names, try demangling the remainder of the string. + +Wed Dec 28 00:49:15 1994 Ian Lance Taylor + + * vasprintf.c (int_vasprintf): New static function. + (vasprintf): Use int_vasprintf. Removes assumption that va_list + is assignment compatible. + +Sat Nov 5 19:29:12 1994 Jason Merrill (jason@phydeaux.cygnus.com) + + * Makefile.in (LIBCFLAGS): New variable. + (FLAGS_TO_PASS): Pass it. + (.c.o): Use it. + +Thu Nov 3 19:09:47 1994 Ken Raeburn + + * getopt.c, getopt1.c: Do compile these functions under Linux, + since many native versions are based on glibc but are buggy. + +Mon Oct 24 15:16:46 1994 Per Bothner + + * vasprintf.c: Make 'format' arg be const, to avoid a mismatch + with prototype in GNU libc. Support stdarg.h as well as varargs.h. + +Tue Oct 11 17:48:27 1994 Jason Merrill (jason@phydeaux.cygnus.com) + + * Makefile.in (REQUIRED_OFILES): Add vasprintf.o. + * functions.def: Remove vasprintf. + +Wed Sep 14 17:04:55 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * xmalloc.c (first_break): New static variable. + (xmalloc_set_program_name): Record sbrk (0) in first_break. + (xmalloc): If memory allocation fails, try to report how much + memory was allocated by the program up to this point. + (xrealloc): Likewise. + +Sun Sep 04 17:58:10 1994 Richard Earnshaw (rwe@pegasus.esprit.ec.org) + + * Makefile.in (ERRORS_CC): New variable, defaulted to $(CC). Use it + when linking dummy. + * config.table: Add host RISCiX Makefile frag. + * config/mh-riscix: New file. + +Thu Aug 25 17:29:44 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * Makefile.in (FLAGS_TO_PASS): Define. + ($(RULE1)): Use $(FLAGS_TO_PASS). + +Wed Aug 24 17:08:47 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * vasprintf.c: Include . + (vasprintf): Add casts to void for va_arg to avoid gcc warnings. + * xatexit.c: Declare malloc. + +Fri Aug 19 15:29:12 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_args): Fix a bug in previous patch (the + one below). + +Thu Aug 18 14:37:14 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle args): Handle ARM repeat encoding where + the type index is greater than 9. + +Wed Aug 17 16:13:49 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_qualified): accept optional '_' between + qualified name. This is baecause the template name may end with + numeric and can mixed up with the length of next qualified name. + +Wed Aug 3 05:52:14 1994 D. V. Henkel-Wallace (gumby@cygnus.com) + + * config/mt-sunos4: Use our standard location for cross-includes + and cross-libs when the target is also a "host" environment (ie no + newlib; includes and such don't belong to us). This is specific + to the Cygnus Support environment. + +Tue Aug 2 15:25:12 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_template): demangle as xxx<'Q'> not + xxx. + +Mon Aug 1 17:02:48 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (main): flush stdout to make pipe work. + +Sat Jul 16 12:56:32 1994 Stan Shebs (shebs@andros.cygnus.com) + + * config.table (*-*-cxux7*): Recognize. + * floatformat.c (floatformat_m88110_ext) [HARRIS_FLOAT_FORMAT]: + Harris-specific float format. + * config/mh-cxux7: New file. + +Wed Jun 29 00:26:17 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cplus-dem.c (demangle_template): Make sure that the result of + consume_count doesn't index beyond the end of the string. + +Mon Jun 20 23:54:37 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cplus-dem.c (gnu_special): Handle vtable mangling of gcc-2.4.5 and + earlier. Improve test for new vtable mangling. Change output back + to `virtual table'. + +Mon Jun 20 11:37:30 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * obstack.c: Always compile this code, even if using the GNU + library. Avoids problems with relatively recent binary + incompatibility. + +Thu Jun 16 17:54:01 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * cplus-dem.c: Include libiberty.h. + (xmalloc, xrealloc, free): Don't declare. + (strstr): Don't declare parameters. + (xmalloc, xrealloc): Don't define. + (long_options): Add no-strip-underscores. + (main): Call xmalloc_set_program_name. Pass n in short options to + getopt_long. Handle option 'n' to not strip underscores. + (usage): Mention -n and --no-strip-underscores. + +Sun Jun 12 01:37:09 1994 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c (demangle_template): Separate consecutive >'s with a + space. + (gnu_special): Demangle template and qualified names in a vtable name. + +Fri May 27 12:27:52 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + From gas-2.3 and binutils-2.4 net releases: + + Wed May 11 22:32:00 1994 DJ Delorie (dj@ctron.com) + + * makefile.dos: [new] Makefile for dos/go32 + * configure.bat: update for latest files + * msdos.c: remove some functions now in libc.a + +Fri May 20 18:53:32 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * cplus-dem.c (gnu_special): Recognize thunks, as well as + the new naming style for vtables (when -fvtable-thunks). + +Wed May 18 13:34:06 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (XTRAFLAGS): Don't define. + (.c.o, dummy.o): Don't use XTRAFLAGS. + ($(RULE1)): Don't pass XTRAFLAGS down in recursive call. + +Fri May 13 16:02:12 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * vasprintf.c: New file. + * Makefile.in, functions.def: Add it. + +Fri May 13 16:20:28 1994 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c (demangle_fund_type): Grok bool. + +Fri May 6 14:44:21 1994 Steve Chamberlain (sac@cygnus.com) + + * config.table: Add go32 + * config/mh-go32: New template. + +Fri May 6 11:01:59 1994 D. V. Henkel-Wallace (gumby@rtl.cygnus.com) + + * config.table, config/mt-sunos4: config for when sun4 is cross target. + +Mon Apr 11 00:54:33 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GCC__] [not __STDC__]: + Declare strlen to return int. Don't include stddef.h. + +Fri Apr 1 00:38:17 1994 Jim Wilson (wilson@mole.gnu.ai.mit.edu) + + * getopt.c: Delete use of IN_GCC to control whether + stddef.h or gstddef.h is included. + +Thu Apr 14 14:00:56 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_signature): Fix a bug in template function + type numbering. + +Wed Apr 13 17:23:03 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_signature): Fix template function with arm + style argument type number, Tn. + +Wed Apr 13 17:11:15 1994 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c (optable): Add new[] and delete[]. + +Fri Apr 8 11:21:42 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * argv.c (buildargv): Don't produce empty argument just because + there is trailing whitespace. + +Wed Apr 6 11:42:14 1994 Kung Hsu (kung@mexican.cygnus.com) + + * cplus-dem.c (demangle_template): fix 'Q' qualified name bug. + Handle 'p' same as 'P'. + * cplus-dem.c (do_type): Handle 'p' same as 'P'. + +Sat Mar 26 12:00:13 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * floatformat.c (get_field, put_field): Fix off by one error in + little endian case. + +Thu Mar 24 10:40:19 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * floatformat.c (floatformat_from_double): Pass unsigned char *, + not char *, to put_field. + +Fri Mar 18 12:34:33 1994 Per Bothner (bothner@kalessin.cygnus.com) + + * memmove.c: Re-wrote; placed in public domain. + +Wed Mar 16 10:33:07 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * cplus-dem.c (demangle_prefix): If ARM demangling, don't treat + __Q* as a constructor. + +Mon Mar 14 12:26:02 1994 Ian Lance Taylor (ian@cygnus.com) + + * ieee-float.c: Removed; no longer used. + * Makefile.in: Changed accordingly. + +Mon Mar 7 12:28:17 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * floatformat.c (get_field): Removed unused local variable i. + (put_field): Removed unused local variable i. + +Sun Feb 27 21:50:11 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * floatformat.c: New file, intended to replace ieee-float.c. + * Makefile.in: Change accordingly. + +Thu Feb 24 11:51:12 1994 David J. Mackenzie (djm@rtl.cygnus.com) + + * getopt.c: Remove #ifdef GETOPT_COMPAT and #if 0 code. + (_getopt_initialize): New function, broken out of _getopt_internal. + (_getopt_internal): + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + +Thu Feb 10 14:44:16 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GNUC__] [not IN_GCC]: + Test just __STDC__, not emacs. + +Wed Feb 9 00:14:00 1994 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * getopt.c [not __GNU_LIBRARY__] [__GNUC__] [not IN_GCC] + [emacs] [not __STDC__]: Don't include stddef.h. Don't declare strlen. + +Fri Dec 24 19:43:00 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * getopt.c (_NO_PROTO): Define before config.h is included. + +Mon Sep 20 15:59:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c, getopt1.c [emacs || CONFIG_BROKETS]: Include + only under these, else "config.h". + +Thu Aug 12 18:16:49 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * getopt.c, getopt1.c [HAVE_CONFIG_H]: Include + instead of "config.h". + +Sun Feb 20 17:17:01 1994 Ian Lance Taylor (ian@lisa.cygnus.com) + + * concat.c: Check ANSI_PROTOTYPES rather than __STDC__ to decide + whether to use prototypes or not. + * strerror.c (const): Never undefine; let ansidecl.h handle it. + * strsignal.c (const): Likewise. + +Thu Feb 17 13:27:35 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * xatexit.c (_xexit_cleanup): Declare as extern; don't initialize. + Merging common and initialized variables need not be supported by + ANSI C compilers. + (xatexit): Initialize _xexit_cleanup if not already set. + * xexit.c: Comment fix. + +Wed Feb 16 01:15:36 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * xmalloc.c: Don't declare xexit; it's declared in libiberty.h. + (xrealloc): If oldmem is NULL, allocate with malloc, rather than + assuming that realloc works correctly. + +Tue Feb 15 09:26:16 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * concat.c, ieee-float.c: Replace inclusion of + with explicit function declarations, as recommended by Ian Taylor. + +Sat Feb 12 10:31:11 1994 David J. Mackenzie (djm@rtl.cygnus.com) + + * xmalloc.c (xmalloc, xrealloc): Use PTR and size_t throughout. + (malloc, realloc): Declare. + +Thu Feb 10 17:08:19 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * argv.c, basename.c: Include ansidecl.h and libiberty.h. + * concat.c, fdmatch.c, getruntime.c, spaces.c: Likewise. + * strerror.c, strsignal.c, xatexit.c, xexit.c: Likewise. + * xmalloc.c: Likewise. + * concat.c: Don't declare xmalloc. If __STDC__, use + macros, not macros. + * spaces.c (spaces): Make return type const. Don't crash if + malloc returns NULL. + * strerror.c (struct error_info): Make name and msg fields const. + (error_names): Make const. + (strerrno): Make const. + (strtoerrno): Make argument const. + * strsignal.c (struct signal_info): Make name and msg fields + const. + (signal_names, sys_siglist): Make const. + (strsignal, strsigno): Make const. + (strtosigno): Make argument const. + * xatexit.c: Declare parameter types. + * xmalloc.c (name): Make const. + (xmalloc_set_program_name): Make argument const. + * Makefile.in (INCDIR): Define. + (.c.o): Use $(INCDIR). + (dummy.o): Likewise. + (argv.o, basename.o): New targets; depend on libiberty.h. + (concat.o, fdmatch.o, getruntime.o, spaces.o): Likewise. + (strerror.o, strsignal.o, xatexit.o, xexit.o): Likewise. + (xmalloc.o): Likewise. + (cplus-dem.o): New target; depend on demangle.h. + (getopt.o, getopt1.o): New targets; depend on getopt.h. + (ieee-float.o): New target; depend on ieee-float.h. + (obstack.o): New target; depend on obstack.h. + +Tue Feb 8 05:29:08 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + Handle obstack_chunk_alloc returning NULL. This allows + obstacks to be used by libraries, without forcing them + to call exit or longjmp. + * obstack.c (_obstack_begin, _obstack_begin_1, _obstack_newchunk): + If CALL_CHUNKFUN returns NULL, set alloc_failed, else clear it. + (_obstack_begin, _obstack_begin_1): Return 1 if successful, 0 if not. + +Tue Feb 8 00:32:28 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * concat.c, ieee-float.c: Include . + +Sun Feb 6 21:28:46 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * xmalloc.c (xmalloc_set_program_name): New function. + (xmalloc, xrealloc): Include the name in the error message, if set. + + * Replace atexit.c with xatexit.c. + * Makefile.in (CFILES), functions.def: Change references. + +Sat Feb 5 14:02:32 1994 Stan Shebs (shebs@andros.cygnus.com) + + * getruntime.c (get_run_time): Use getrusage or times if + HAVE_GETRUSAGE or HAVE_TIMES are defined. + +Fri Feb 4 15:49:38 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * atexit.c: New file. + * Makefile.in (CFILES), functions.def: Add it. + * xexit.c: New file. + * Makefile.in (CFILES, REQUIRED_OFILES): Add it. + * xmalloc.c (xmalloc, xrealloc): Call xexit instead of exit. + Change request for 0 bytes into request for 1 byte. + +Wed Feb 2 11:36:49 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * xmalloc.c (xmalloc, xrealloc): Print size using %lu, and cast to + unsigned long, to avoid warnings. + +Fri Jan 28 17:49:06 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * dummy.c: Don't include time.h ever; always define clock_t as + "unsigned long". Until gcc/fixincludes ensures that clock_t + exists, __STDC__ isn't a sufficient test. And if clock() doesn't + exist, clock_t probably doesn't either. + +Mon Jan 24 11:52:31 1994 Stan Shebs (shebs@andros.cygnus.com) + + * clock.c, getruntime.c: New files. + * Makefile.in: Add to file lists. + * functions.def (clock): Add to list. + * dummy.c (time.h): Add if __STDC__. + (clock_t): #define as "unsigned long" if not __STDC__. + +Tue Jan 11 11:27:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * strtod.c: Declare atof. From edler@jan.ultra.nyu.edu (Jan + Edler). + +Tue Dec 28 14:17:30 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (errors): Use CFLAGS as well as LDFLAGS when + linking. + +Fri Dec 17 12:26:07 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c (demangle_arm_pt): New function. Common code + for ARM template demangling. + * cplus-dem.c (demangle_class_name): Use demangle_arm_pt. + * cplus-dem.c (demangle_prefix): Likewise. + +Tue Nov 30 15:47:48 1993 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c (cplus_demangle_opname): Add CONST to please gcc. + +Sat Nov 27 11:05:50 1993 Fred Fish (fnf@cygnus.com) + + Merge changes from tom@basil.icce.rug.nl (Tom R.Hageman) + * strerror.c, strsignal.c: As a small space optimization, don't + include messages when they aren't actually used. + + Merge changes from takefive.co.at!joe (Josef Leherbauer) + * cplus-dem.c (demangle_prefix, demangle_function_name, + cplus_demangle_opname): Fixes for systems where cplus_marker + is something other than '$'. + +Fri Nov 26 13:51:11 1993 Per Bothner (bothner@kalessin.cygnus.com) + + * waitpid.c: Simple-minded approcimation to waitpid + using vanilla wait. + * functions.def, Makefile.in: Update accordingly, + +Thu Nov 18 18:01:15 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c(demangle_template): fix bug template instantiation + with value of user defined type. + +Wed Nov 17 18:30:21 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c(cplus_demangle_opname): add the subject new function + to support unified search of operator in class. + +Wed Nov 10 09:47:22 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + gcc -Wall lint: + * strtoul.c (strtoul): use "(digit = *s) != '\0'" not just + "digit = *s" as condition in while loop. + +Tue Nov 9 15:52:22 1993 Mark Eichin (eichin@cygnus.com) + + * Makefile.in: pass SHELL to recursive make + +Thu Nov 4 12:09:26 1993 Per Bothner (bothner@kalessin.cygnus.com) + + * vfprintf.c, vprintf.c, vsprintf.c: Make format arg + be (const char*), for ANSI (and gcc w/fixproto) consistency. + +Thu Nov 4 08:29:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config.table: Make *-*-hiux* use mh-hpux. + +Fri Oct 22 07:53:15 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * config.table: Add * to end of all OS names. + +Tue Oct 19 17:12:01 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * Makefile.in (lneeded-list): ensure that object file names are + not duplicated, as multiple instances of the same object file in + a library causes problems on some machines + +Mon Oct 18 21:59:28 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * strcasecmp.c, strncasecmp.c: Change u_char to unsigned char. + +Fri Oct 15 22:17:11 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * strncasecmp.c: new file, implements strncasecmp + * strcasecmp.c: new file, implement strcasecmp + + * Makefile.in (CFILES): list these two new source files + + * functions.def: add strcasecmp and strncasecmp entries + +Fri Oct 15 14:53:05 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * strtoul.c (strtoul), strtol.c (strtol): Handle overflow + according to ANSI C. + +Thu Oct 14 16:34:19 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c: add support of ARM global constructor/destructor, + and 'G' for passing record or union in parameter. + +Wed Oct 13 13:36:19 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Fix comment to clarify that stuff in REQUIRED_OFILES + should not be in functions.def. + +Wed Oct 13 13:13:38 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * functions.def: Removed xmalloc. Stuff in REQUIRED_OFILES should + not be in functions.def. + +Mon Oct 4 18:26:39 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c: change globl constructor/destructor to proper name + +Tue Sep 28 18:11:07 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c: fix bug in constructor/destructor + +Tue Sep 28 16:20:49 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c: support both old and new _vt$... vtbl mangled names + +Fri Sep 24 19:07:16 1993 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c: Fix demangle_template prototype + +Fri Sep 24 17:32:55 1993 Kung Hsu (kung@cirdan.cygnus.com) + + * cplus-dem.c: fix template demangling + * cplus-dem.c: fix const type demangling + * cplus-dem.c: fix constructor/destructor, virtual table, + qualifier, global constructor/destructor demangling + +Wed Sep 1 23:13:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * strsignal.c, strerror.c: Use fully-bracketed initializer to + keep gcc -Wall happy. + +Fri Aug 27 10:30:09 1993 Jason Merrill (jason@deneb.cygnus.com) + + * cplus-dem.c (do_type): Add CONSTS to make gcc happy with last + patch. + +Fri Aug 27 11:24:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + Patch from Paul Flinders: + * cplus-dem.c (do_type): Deal with arrays. + +Tue Aug 24 14:23:50 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * cplus-dem.c (demangle_qualified: Deal with GNU format for more + than 9 classes. + +Wed Aug 18 19:50:29 1993 Jason Merrill (jason@deneb.cygnus.com) + + * Makefile.in (dummy.o): Redirect to /dev/null to avoid "variable + not initialized" warnings under HP/UX + +Sun Aug 15 20:42:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * strerror.c: Move include of stdio.h after sys_errlist #define. + Also remove NULL definition (stdio.h always defines NULL, so it + never did anything but clutter up the code). + +Sat Aug 14 14:21:49 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * Makefile.in, functions.def: handle xmalloc.c + + * xmalloc.c: provide xmalloc and xrealloc functions + +Thu Aug 12 17:38:57 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * cplus-dem.c: Fix a comment. + +Sat Aug 7 13:56:35 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * getopt1.c: Declare const the way getopt.c does. + +Fri Aug 6 17:03:13 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * obstack.c, alloca.c: Update from FSF. + * getopt.c, getopt1.c: Update to current FSF version, which + doesn't use alloca. + +Tue Jul 27 14:03:57 1993 Brendan Kehoe (brendan@lisa.cygnus.com) + + * Makefile.in (demangle): Add the target with a message saying + where demangle went. + +Mon Jul 26 15:49:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Remove obsolete `demangle' target. + +Thu Jul 22 08:31:01 1993 Fred Fish (fnf@deneb.cygnus.com) + + * cplus-dem.c (arm_special): Apply patch from arg@lucid.com to + avoid infinite loop on vtbl symbols with disambiguating "junk" + tacked on the end. + +Mon Jul 19 14:10:37 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) + + * strsignal.c: work around some systems losing definitions of + sys_siglist + + * config/mh-lynxos: this system has a losing definition of + sys_siglist + + * config.table: use mh-lynxos for *-*-lynxos + +Mon Jul 19 17:08:52 1993 Ken Raeburn (raeburn@rtl.cygnus.com) + + * config.table: Add support for HPPA BSD hosts. + + * config/mh-hpbsd: New file. + +Mon Jul 12 18:00:40 1993 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in (TAGS): make work when srcdir != objdir. + +Sun Jun 27 15:35:31 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * cplus-dem.c (main): Add long options, including --help and + --version. + (usage): New function from code in main. + +Tue Jun 22 11:37:38 1993 Per Bothner (bothner@deneb.cygnus.com) + + * config.table: New shell scipt, sourced by both ./configure,in + and ../xiberty/configure.in, to avoid maintainance lossages. + * configure.in and ../xiberty/configure.in: Use config.table. + + * configure.in: Don't use mh-aix for AIX 3.2, only for 3.1. + * configure.in: Map *-*-irix* (except irix4) to mh-sysv. + * ../xiberty/configure.in: Update from ./configure.in. + +Tue Jun 15 17:05:31 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: remove parentdir support + +Wed May 26 12:59:09 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cplus-dem.c (xrealloc): Match definition with prototype. + +Tue May 25 14:27:51 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cplus-dem.c (demangle_prefix): Demangle cfront + local variables as an extension to ARM demangling. + +Fri May 21 09:53:57 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * ieee-float.c: Don't require pointers to double to be aligned. + +Tue May 18 17:12:10 1993 Fred Fish (fnf@cygnus.com) + + (merge changes from dlong@cse.ucsc.edu) + * cplus-dem.c (consume_count): Simplify. + * cplus-dem.c (arm_pt, demangle_class_name): New functions. + * cplus-dem.c (various): Calls to arm_pt, demangle_class_name. + + * cplus-dem.c (xmalloc, xrealloc, strstr): Make extern decls into + full prototypes. + * cplus-dem.c (free): Add prototype. + * cplus-dem.c (optable): Fully bracketize initializer. + +Fri May 14 17:13:05 1993 Per Bothner (bothner@cygnus.com) + + * cplus-dem.c: Whether initial underscores are stripped + depends on the external variable prepends_underscore + (which is generated by the binutils Makefile). + +Fri May 14 07:32:20 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * cplus-dem.c (mop_up, arm_special): Remove some unused variables. + +Tue May 4 20:31:59 1993 Fred Fish (fnf@cygnus.com) + + * cplus-dem.c (consume_count): Return zero if arg does not + start with digit, and don't consume any input. + +Tue May 4 08:10:28 1993 Jim Kingdon (kingdon@cygnus.com) + + * Makefile.in (demangle): Use ${srcdir} not $^. + + * strtod.c: New file, needed at least for BSD 4.3. + +Sun May 2 11:30:42 1993 Fred Fish (fnf@cygnus.com) + + * strsignal.c (sys_siglist): For ANSI compilations, type is + "const char *const". Also remove conditionalization on __STDC__ + since const is defined away for non-ANSI. + +Wed Apr 28 19:29:55 1993 Ken Raeburn (raeburn@deneb.cygnus.com) + + * configure.in: Recognize *-*-hpux. + * config/mh-hpux: New file. + +Tue Apr 27 15:22:19 1993 Per Bothner (bothner@cygnus.com) + + * tmpnam.c: Added ANSI tmpnam() function. + * functions.def, Makefile.in: Update accordingly. + +Tue Apr 27 13:38:38 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * cplus-dem.c (demangle_function_name): Get the demangling of + stop__1A right. + +Fri Apr 16 23:48:24 1993 Jim Kingdon (kingdon at calvin) + + * cplus-dem.c: Declare strstr return type. + +Fri Mar 26 12:01:26 1993 Jim Kingdon (kingdon@cygnus.com) + + * strsignal.c: Add some AIX signals. + +Thu Mar 25 15:17:23 1993 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in (MAKEOVERRIDES): Define to be empty. + +Wed Mar 24 01:59:25 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: add installcheck & dvi targets + +Thu Mar 18 14:05:44 1993 Per Bothner (bothner@rtl.cygnus.com) + + * ieee-float.c: New file, moved from ../gdb (since it is + needed by ../opcode/m68k-dis.c). + +Tue Mar 2 17:47:31 1993 Fred Fish (fnf@cygnus.com) + + * cplus-dem.c: Replace all references to cfront with ARM. + +Fri Feb 26 00:17:07 1993 Per Bothner (bothner@rtl.cygnus.com) + + * cplus-dem.c: Fix main program (when compiled with -DMAIN) + to be more useful as a filter. + +Sat Feb 20 21:41:39 1993 Brendan Kehoe (brendan@lisa.cygnus.com) + + * Makefile.in (install_to_libdir, install_to_tooldir): Go into the + destination directory before running $(RANLIB), in case that + program tries to create a file in the current directory as part of + its work. + +Thu Feb 18 23:00:19 1993 John Gilmore (gnu@cygnus.com) + + * strsignal.c (sys_siglist): Remove yet another *%^&%&$# "const" + because BSD 4.4 lacks one. Isn't this fun? + +Thu Feb 18 11:24:25 1993 Fred Fish (fnf@cygnus.com) + + * cplus-dem.c (demangle_signature): Set func_done after + demangling a template. + * cplus-dem.c (demangle_template): Fix several small bugs + in demangling GNU style templates. + * cplus-dem.c (demangle_prefix): Fix for templates in GNU + style constructors. + * cplus-dem.c (gnu_special): Fix for templates in GNU style + static data members. + +Tue Feb 16 17:28:35 1993 Fred Fish (fnf@cygnus.com) + + * cplus-dem.c (demangle_signature): Modify to include type + modifiers like static and const in remembered types. + +Thu Feb 11 22:20:47 1993 Fred Fish (fnf@cygnus.com) + + * cplus-dem.c (demangled_qualified): Add new parameter that tells + whether to prepend or append the qualifiers. + * cplus-dem.c (string_prepends): Used now, remove #if 0. + * cplus-dem.c (demangle_signature): Call demangle_qualified + with prepending. + * cplus_dem.c (gnu_special): Recognize static data members that + use qualified names. + * cplus-dem.c (demangle_qualified): Accumulate qualifiers in a + temporary buffer and the prepend or append them to the result, + as specified by the new "append" flag. + * cplus-dem.c (do_type): Call demangled_qualified with + appending. + +Mon Dec 28 10:47:19 1992 Ken Raeburn (raeburn@cygnus.com) + + * strsignal.c (signal_table): Now const. + (init_signal_tables): Variable eip now points to const. + + * strerror.c (error_table): Now const. + (init_error_tables): Variable eip now points to const. + +Tue Dec 15 15:36:50 1992 Per Bothner (bothner@cygnus.com) + + * memchr.c (memchr): New (ANSI standard) function. + * Makefile.in, functions.def: Added memchr. + * Makefile.in (AR_FLAGS): Use rc instad of non-standard cq. + +Wed Dec 2 22:49:10 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * getopt.c: remove use of USG around , which never meant + anything anyway + + * config/mh-{aix,apollo68,ncr3000,sysv,sysv4}: removed definitions + of USG and USGr4 + +Thu Nov 19 03:09:33 1992 Brendan Kehoe (brendan@lisa.cygnus.com) + + * cplus-dem.c (demangle_fund_type): Recognize `w', a wide character; + it's now a type according to the ANSI X3J16 working paper; output + "wchar_t" for it. + (demangle_template): Accept `w' as an integral type. + (xmalloc, xrealloc): Use `char *', not `PTR'. Cast calls to their + counterparts malloc and realloc to `char *'. + (main): Exit with a 0 status. + * Makefile.in (demangle): Don't expect the user to define + DEMANGLE, instead force to be cplus-dem.c. Look in $(srcdir)/../include + for demangle.h. Pass it any HDEFINES or XTRAFLAGS. + +Wed Nov 18 18:56:20 1992 John Gilmore (gnu@cygnus.com) + + * Makefile.in (AR_FLAGS): Avoid verbosity. + * config/mh-sysv4: Remove AR_FLAGS override, use INSTALL=cp, + replace USGr4 with HAVE_SYSCONF. + * config/mh-solaris: Remove; mh-sysv4 works now. + * getpagesize.c: Replace USGr4 with HAVE_SYSCONF. + * configure.in: Simplify host matching table, remove separate + solaris config file. + +Sun Nov 15 09:35:16 1992 Fred Fish (fnf@cygnus.com) + + * configure.in (i[34]86-*-solaris2*): Add, use mh-sysv4. + +Tue Nov 3 21:27:03 1992 Brendan Kehoe (brendan@cygnus.com) + + * cplus-dem.c (xmalloc, xrealloc): Add decls. + (remember_type): Don't cast xmalloc. + (string_need): Likewise; don't cast xrealloc either. + +Fri Oct 23 08:52:01 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in, functions.defs, rename.c: added simple + implementation of rename, since some binutils programs use it. + +Thu Oct 15 15:18:22 1992 Per Bothner (bothner@cygnus.com) + + * strsignal.c: Add appropriate 'const' to sys_siglist + extern declaration (if __STDC__). (Needed for Linux.) + * strsignal.c (strsignal): Add cast to remove const-ness. + +Fri Oct 9 03:22:55 1992 John Gilmore (gnu@cygnus.com) + + * Makefile.in (needed.awk, needed2.awk): Remove erroneous \'s + before "'s, diagnosed by BSD 4.4 awk. + +Thu Oct 8 15:25:12 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: create config.h and needed-list through $(CONFIG_H) + and $(NEEDED_LIST), to give some hooks for xiberty. + +Thu Oct 1 23:31:42 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * configure.in: use cpu-vendor-triple instead of nested cases + +Wed Sep 30 11:26:59 1992 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in, argv.c, basename.c, bcmp.c, bcopy.c, bzero.c, + concat.c, cplus-dem.c, fdmatch.c, getcwd.c, getopt.c, getopt1.c, + getpagesize.c, insque.c, memcmp.c, memcpy.c, memmove.c, memset.c, + obstack.c, sigsetmask.c, spaces.c, strchr.c, strerror.c, + strrchr.c, strsignal.c, strstr.c, vfork.c, vsprintf.c: + Convert from using GPL to LGPL. + +Sat Sep 26 04:01:30 1992 John Gilmore (gnu@cygnus.com) + + * Makefile.in (errors): Leave dummy.o and dummy around so that + we can see how the needed list was generated (it's sometimes wrong). + (mostlyclean): Remove them. + +Mon Sep 21 14:50:42 1992 Ian Lance Taylor (ian@cygnus.com) + + * getcwd.c: supply a default if MAXPATHLEN is not defined. + + * config/mh-irix4: set EXTRA_OFILES to alloca.o, from WRS. + +Wed Sep 9 12:41:48 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: Use XTRAFLAGS when compiling, so that xiberty works + when cross-compiling. + +Thu Sep 3 13:29:39 1992 K. Richard Pixley (rich@sendai.cygnus.com) + + * cplus-dem.c: (demangle_prefix): reduction in strength of strstr + as a time optimization. + + * cplus-dem.c (cplus_demangle): remove strpbrk test. Appears to + be more expensive than simply demangling. + + * cplus-dem.c (cplus_match): new function. + +Tue Sep 1 15:24:04 1992 Per Bothner (bothner@rtl.cygnus.com) + + * cplus-dem.c: #include , to define NULL. + Define current_demangling_style. + +Sun Aug 30 17:58:19 1992 Per Bothner (bothner@rtl.cygnus.com) + + * cplus-dem.c: New file, moved from ../gdb. + * cplus-dem.c (set_cplus_marker_for_demangling): New exported + function, to avoid compiling in target-dependency for CPLUS_MARKER. + * cplus-dem.c (cplus_demangle): Allow demangling style option + to be passed as a parameter, but using the global variable + current_demangling_style as a default. + * Makefile.in: Update for cplus-dem.c + +Sat Aug 29 10:44:09 1992 Fred Fish (fnf@cygnus.com) + + * obstack.c: Merge in comment changes from FSF version. Now + matches the FSF version exactly. + +Fri Aug 28 18:39:08 1992 John Gilmore (gnu@cygnus.com) + + * obstack.c (CALL_FREEFUN): Can't use ?: with void values (at + least on losing DECstations!); use if-then-else instead. + +Wed Aug 19 14:40:34 1992 Ian Lance Taylor (ian@cygnus.com) + + * Makefile.in: always create installation directories. + +Mon Aug 10 17:33:40 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: clean up definition of CFILES, more comments + +Sat Aug 8 23:10:59 1992 Fred Fish (fnf@cygnus.com) + + * getopt.c (my_index): Make first arg const to match strchr, + which it sometimes is remapped to. + +Sat Aug 1 13:48:50 1992 Fred Fish (fnf@cygnus.com) + + * obstack.c (DEFAULT_ALIGNMENT): Update to match FSF version. + * obstack.c (_obstack_begin): Initialize use_extra_arg. + * obstack.c (_obstack_begin_1): New, from FSF version. + +Mon Jul 20 21:07:58 1992 Fred Fish (fnf@cygnus.com) + + * obstack.c (CALL_CHECKFUN, CALL_FREEFUN): Use use_extra_arg and + extra_arg. + * obstack.c (_obstack_begin): Remove area_id and flags arguments + (previously added for mmalloc support, interface has changed). + Also convert flags usage to use use_extra_arg and maybe_empty_object. + +Fri Jul 10 00:41:53 1992 Fred Fish (fnf@cygnus.com) + + * argv.c: Move expandargv inline and eliminate static variables. + Rewrite to always allocate in powers of two. Fix to return an + argv with a single null string arg if passed a null string. + +Fri Jul 3 20:27:29 1992 Fred Fish (fnf@cygnus.com) + + * random.c, sigsetmask.c, strerror.c, strsignal.c: Remove + "(void)" casts from function calls where the return value is + ignored, in accordance with GNU coding standards. + +Mon Jun 29 10:54:19 1992 Fred Fish (fnf at cygnus.com) + + * bcopy.c, strerror.c, strsignal.c: Lint. + +Thu Jun 25 09:18:41 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * getopt.c: merge changes from make. + +Thu Jun 25 04:43:22 1992 John Gilmore (gnu at cygnus.com) + + * alloca.c: Incorporate fixes from gdb/alloca.c. + FIXME: Eventually move gdb's alloca configuration files here, + and remove gdb/alloca.c and its Makefile.in support. + +Tue Jun 23 21:56:30 1992 Fred Fish (fnf@cygnus.com) + + * dummy.c: Define NOTHING to /*nothing*/, change return type + of main to int and return zero. + * functions.def: Supply NOTHING as the fourth arg to macros + that don't have an explicit arg, to satisfy picky preprocessors. + +Wed Jun 17 18:13:58 1992 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in: Clean up *clean rules, as per standards.texi. + +Tue Jun 16 16:11:59 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * getopt.c, getopt1.c: merged largely gratuitous, mostly + whitespace diffs from other prep distributions. + +Mon Jun 15 12:25:46 1992 Fred Fish (fnf@cygnus.com) + + * config/mh-ncr3000 (INSTALL): Don't use /usr/ucb/install, + it is broken on ncr 3000's. + +Mon Jun 15 01:03:26 1992 John Gilmore (gnu at cygnus.com) + + * sigsetmask.c: Rewrite. Old one was very confused about its + arguments and result. New one can't do much, but at least knows + what it can't do, and it's good enough for GDB's use. + +Sun Jun 14 15:17:40 1992 Stu Grossman (grossman at cygnus.com) + + * functions.def: Use proper prototype for strtoul. + +Fri Jun 12 19:22:40 1992 John Gilmore (gnu at cygnus.com) + + * Makefile.in: Add random.c. + * config/mh-*: Use "true" rather than "echo >/dev/null" for ranlib. + * configure.in: update solaris2 config. + +Wed Jun 10 16:31:29 1992 Fred Fish (fnf@cygnus.com) + + * random.c: Add for random() and srandom(). + * functions.def: Add random + +Tue Jun 9 17:27:18 1992 Fred Fish (fnf@cygnus.com) + + * config/{mh-ncr3000, mh-sysv4}: Add definition for INSTALL + using /usr/ucb/install. + +Mon Jun 1 13:20:17 1992 Per Bothner (bothner@rtl.cygnus.com) + + * strerror.c: Kludge to guard against a conflict with + possible declaration of sys_errlist in errno.h. + +Sun May 31 15:07:47 1992 Mark Eichin (eichin at cygnus.com) + + * configure.in, config/mh-solaris: add solaris2 config support. + +Fri May 29 17:23:23 1992 Per Bothner (bothner@rtl.cygnus.com) + + * sigsetmask.c: #ifdef out sigsetmask if SIG_SETMASK + is not defined (should be defined in signal.h, says Posix.). + +Mon May 18 17:35:04 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.c: merged changes from make-3.62.11. + +Fri May 8 14:53:07 1992 K. Richard Pixley (rich@cygnus.com) + + * getopt.c: merged changes from bison-1.18. + +Tue May 5 11:51:40 1992 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in: Don't have $(EXTRA_OFILES) depend on config.h, + since that introduces a circular dependency. + ($(EXTRA_OFILES) are used to build config.h.) + + * strtoul.c: Fixes to handle non-decimal bases better. + +Wed Apr 22 09:27:51 1992 Fred Fish (fnf@cygnus.com) + + * config/mh-ncr3000: Replace MINUS_G with CFLAGS. + * Makefile.dos: Finish MINUS_G eradication. + * Makefile.in (CFILES): Add strsignal.c. + * Makefile.in (REQUIRED_OFILES): Add strerror.o strsignal.o + * Makefile.in (needed-list): Split creation of errors file to + separate make target. + * Makefile.in (config.h, needed2.awk, errors): New targets. + * Makefile.in (clean): Split to multiple lines, add needed2.awk + and config.h. + * dummy.c (DEFFUNC, DEFVAR): Add defines and undefs. + * functions.def (strerror): Remove from optional list. + * functions.def (sys_nerr, sys_errlist, sys_siglist): DEFVAR's + * functions.def (strerror, psignal): DEFFUNC's + * strerror.c: Rewrite from scratch to use sys_errlist only if + available, add errno_max(), add strerrno(), add strtoerrno(), + add test driver. + * strsignal.c: New file, signal equivalent to strerror.c. + Uses sys_siglist if available, defines signo_max(), strsignal(), + strsigno(), strtosigno(), psignal(), and test driver. + +Mon Apr 20 20:49:32 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: do not print recursion line. + + * Makefile.in: allow CFLAGS to be passed in from command line. + Removed MINUS_G. Default CFLAGS to -g. + +Mon Apr 20 12:57:46 1992 Per Bothner (bothner@rtl.cygnus.com) + + * config/mh-aix: New. EXTRA_OFILES lists copysign.o, + so libg++ users don't have to be inconvenienced by a + libc.a bug (libc.a needs copysign, but doesn't define it!). + * configure.in: Use config/mh-aix. + * strtoul.c: Handle '-' as required by ANSI. + Clean up radix handling. + * strstr.c: Fix buggy algorithm. + * Makefile.in: Change so that ${EXTRA_OFILES} is + appended to needed-list (which is used by libg++). + +Fri Apr 10 22:51:41 1992 Fred Fish (fnf@cygnus.com) + + * configure.in: Recognize new ncr3000 config. + * config/mh-ncr3000: New config file. + +Wed Apr 1 23:31:43 1992 John Gilmore (gnu at cygnus.com) + + * argv.c, dummy.c: Lint. + +Tue Mar 31 18:46:44 1992 Fred Fish (fnf@cygnus.com) + + * config/mh-sysv4: New config file. + * configure.in (host_makefile_frag): Set to config/mh-sysv4 for + host_os == sysv4. + * getpagesize.c: For SVR4, use sysconf(_SC_PAGESIZE) to get + pagesize. + +Sun Mar 29 12:26:42 1992 John Gilmore (gnu at cygnus.com) + + * getopt.c: Lint. + +Fri Mar 27 08:32:55 1992 Fred Fish (fnf@cygnus.com) + + * functions.def (alloca): Fix return type and args to avoid + type clash with gcc's builtin alloca. + +Tue Mar 24 23:33:42 1992 K. Richard Pixley (rich@cygnus.com) + + * configure.in, config/mh-irix4: irix4 support. + + * Makefile.in, functions.def, alloca.c: added alloca. + +Tue Mar 24 17:34:46 1992 Stu Grossman (grossman at cygnus.com) + + * obstack.c (CALL_FREEFUN): Make it compile on DECstations. + +Thu Mar 19 13:57:42 1992 Fred Fish (fnf@cygnus.com) + + * argv.c: Fix various external function definitions to be + correct in an ANSI compilation environment. + +Sat Mar 14 17:28:17 1992 Fred Fish (fnf@cygnus.com) + + * obstack.c: Changes to support calling mmalloc functions, + which take an additional argument over malloc functions. + +Fri Mar 6 22:01:10 1992 K. Richard Pixley (rich@cygnus.com) + + * added check target. + +Thu Feb 27 22:19:39 1992 Per Bothner (bothner@cygnus.com) + + * argv.c: #include alloca-conf.h (needed by AIX). + +Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in: removed traces of namesubdir, + -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced + copyrights to '92, changed some from Cygnus to FSF. + +Sat Feb 22 01:09:21 1992 Stu Grossman (grossman at cygnus.com) + + * argv.c: Check in Fred's version which fixes problems with + alloca(). + +Fri Feb 7 21:46:08 1992 Stu Grossman (grossman at cygnus.com) + + * makefile.dos: Remove NUL to keep patch from failing. + +Thu Jan 30 22:48:41 1992 Stu Grossman (grossman at cygnus.com) + + * getopt.c (_getopt_internal): Fix usage of enum has_arg. + +Mon Jan 20 18:53:23 1992 Stu Grossman (grossman at cygnus.com) + + * getopt.c, getopt1.c, ../include/getopt.h: Get latest versions. + +Sat Jan 18 16:53:01 1992 Fred Fish (fnf at cygnus.com) + + * argv.c: New file to build and destroy standard argument + vectors from a command string. + + * Makefile.in: Add argv.c and argv.o to appropriate macros. + +Fri Dec 20 12:12:57 1991 Fred Fish (fnf at cygnus.com) + + * configure.in: Change svr4 references to sysv4. + + * rindex.c: Declare return type of externally used function + strrchr(). + +Thu Dec 19 18:35:03 1991 John Gilmore (gnu at cygnus.com) + + * Makefile.in: Remove "***" in normal output, since Make produces + this on errors, and it's convenient to search for. + +Tue Dec 17 23:21:30 1991 Per Bothner (bothner at cygnus.com) + + * memcmp.c, memcpy.c, memmove.c, memset.c, strchr.c, strrchr.c: + New ANSI functions. The old non-ANSI functions (such as bcopy) + should be avoided. + * bcopy.c: Fix to correctly handle overlapping regions. + * index.c, rindex.c: Re-write in terms of strchr() and strrchr(). + * functions.def: Add the new functions. + * functions.def: Add 4th parameter to DEF macro, + an ansidecl.h-style prototype. + * dummy.c: Use expanded DEF macro to create a dummy function + call, with correct parameter types. (This avoids some + complaints from gcc about predefined builtins.) + + Move the functionality of config/mh-default into Makefile.in. + This avoid duplication, and simplifies things slightly. + * Makefile.in: Tweak so we don't need config/mh-default. + * README: Update. + * configure.in: No longer need config/mh-default. + * config/mh-default: Deleted. + * config/mh-sysv: Remove lines copied from old mh-default. + +Tue Dec 17 05:46:46 1991 John Gilmore (gnu at cygnus.com) + + * fdmatch.c (fdmatch): Don't compare st_rdev, which is for + 'mknod' device numbers. + +Mon Dec 16 12:25:34 1991 Fred Fish (fnf at cygnus.com) + + * fdmatch.c, Makefile.in: Add new function that takes two + open file descriptors and returns nonzero if they refer to + the same file, zero otherwise. (used in gdb) + +Wed Dec 11 17:40:39 1991 Steve Chamberlain (sac at rtl.cygnus.com) + From DJ: + * msdos.c: stub functions for dos. + * makefile.dos, configdj.bat: new. + * getopt.c: Don't include alloca-conf.h in a GO32 world. + + +Tue Dec 10 04:14:49 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: infodir belongs in datadir. + +Fri Dec 6 23:26:45 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: remove spaces following hyphens because bsd make + can't cope. added standards.text support. install using + INSTALL_DATA. + + * configure.in: remove commontargets as it is no longer a + recognized hook. + +Thu Dec 5 22:46:46 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * Makefile.in: idestdir and ddestdir go away. Added copyrights + and shift gpl to v2. Added ChangeLog if it didn't exist. docdir + and mandir now keyed off datadir by default. + +Fri Nov 22 19:15:29 1991 John Gilmore (gnu at cygnus.com) + + * Makefile.in: find-needed.awk does not fit in 14 chars. + + * Makefile.in: Suppress error checking when compiling the test + program, because Ultrix make/sh aborts there due to a bug. + +Fri Nov 22 12:23:17 1991 Per Bothner (bothner at cygnus.com) + + * Makefile.in: Re-did how EXTRA_OFILES is used to be more useful. + * README: Explained how the auto-configuration works, + and how to add new files and/or configurations. + +Fri Nov 22 09:45:23 1991 John Gilmore (gnu at cygnus.com) + + * strtoul.c: Avoid defining ULONG_MAX if already defined; + cast a const char * to char * for pedants. + + * getopt.c: Only define "const" after local include files get to, + and only if they haven't defined it. + +Thu Nov 21 16:58:53 1991 John Gilmore (gnu at cygnus.com) + + * getcwd.c (remove getwd.c): GNU code should call getcwd(). We + emulate it with getwd() if available. This avoids callers having + to find a MAXPATHLEN or PATH_MAX value from somewhere. + * Makefile.in, functions.def: getwd->getcwd. + * configure.in: Use generic case for every system. + * config/mh-{delta88,mach,rs6000,svr4}: Remove. + * config/mh-sysv: Use default handling, just add -DUSG. + +Thu Nov 14 10:58:05 1991 Per Bothner (bothner at cygnus.com) + + * Makefile.in, config/mh-default: Re-do make magic + so that for the default ("automatic") mode we only + compile the files we actually need. Do this using + a recursive make: The top-level generates the list + of needed files (loosely, the ones missing in libc), + and then passes that list to the recursive make. + * config/mh-mach: Remove obsolete STRERROR-{C,O} macros. + +Tue Nov 12 19:10:57 1991 John Gilmore (gnu at cygnus.com) + + RS/6000 host support (grumble). + + * configure.in: Build alloca-conf.h file from alloca-norm.h + (everything else) or alloca-botch.h (rs/6000). + * Makefile.in: Include . on the include path. + * getopt.c: Use alloca-conf.h. + * alloca-norm.h: How to declare alloca on reasonable machines. + * alloca-botch.h: How to declare alloca on braindead machines. + +Tue Nov 12 09:21:48 1991 Fred Fish (fnf at cygnus.com) + + * concat.c : New file, like concat() in gdb but can take a + variable number of arguments rather than fixed at 3 args. For + now, client applications must supply an xmalloc(), which is a + front end function to malloc() that deals with out-of-memory + conditions. + + * Makefile.in: Add concat.c and concat.o to appropriate macros. + +Sat Nov 9 13:29:59 1991 Fred Fish (fnf at cygnus.com) + + * config/mh-svr4: Add sigsetmask to list of required functions. + +Sun Nov 3 11:57:56 1991 Per Bothner (bothner at cygnus.com) + + * vsprintf.c: New file. + * functions.def, Makefile.in: Add vsprintf. + +Sun Oct 27 16:31:22 1991 John Gilmore (gnu at cygnus.com) + + * configure.in, config/mh-rs6000: Add rs/6000 host support. + * Makefile.in: Compile with debug info. + +Fri Oct 25 17:01:12 1991 Per Bothner (bothner at cygnus.com) + + * Makefile.in, configure.in, and new files: dummy.c, functions.def, + config/mf-default: Added a default configuration mode, + which includes into libiberty.a functions that are "missing" in libc. + * strdup.c, vprintf.c, vfprintf.c: New files. + +Thu Oct 24 02:29:26 1991 Fred Fish (fnf at cygnus.com) + + * config/hmake-svr4: New file. + + * config/hmake-sysv: Add HOST_CFILES and HOST_OFILES. + + * basename.c, bcmp.c, bcopy.c, bzero.c, getpagesize.c getwd.c, + index.c, insque.c, rindex.c, spaces.c, strstr.c, vfork.c: New + files containing either portable C versions or emulations using + native library calls. + + * strerror.c: Add copyright, internal documentation, etc. + + * strtol.c: Replace hardwired hex constants with some more + portable macros. Remove illegal (according to gcc) cast. + + * strtoul.c: Replace hardwired hex constant with more portable + macro. + + * Makefile.in: Move TARGETLIB and CFLAGS where makefile fragments + can override them. Add new source and object file names to CFILES + and OFILES respectively. + + * configure.in: Add support for SVR4 makefile fragments. + +Tue Oct 22 19:00:23 1991 Steve Chamberlain (steve at cygnus.com) + + * Makefile.in: Move RANLIB, AR and AR_FLAGS to where they can be + over-ridden by config/hmake-* + * configure.in: added m88kcvs to sysv list + +Fri Oct 4 01:29:08 1991 John Gilmore (gnu at cygnus.com) + + * Makefile.in: Most hosts need strerror, but one or two don't, + and they override these definitions in the host-dependent makefile + fragment. + * config/hmake-mach: The odd man out on strerror -- it's supplied. + * strerror.c: New file. + + * strtol.c, strtoul.c: Add strtol to libiberty, since Mach lacks + it and bfd uses it. + * configure.in, Makefile.in, config/hmake-mach: Only configure + strtol & strotoul in on Mach. + +Tue Sep 3 06:36:23 1991 John Gilmore (gnu at cygint.cygnus.com) + + * obstack.c: Merge with latest FSF version. + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/libiberty/Makefile.in b/contrib/gdb/libiberty/Makefile.in new file mode 100644 index 000000000000..7f11d51439de --- /dev/null +++ b/contrib/gdb/libiberty/Makefile.in @@ -0,0 +1,321 @@ +# +# Makefile +# Copyright (C) 1990, 1991, 1992, 1995 Free Software Foundation +# +# This file is part of the libiberty library. +# Libiberty is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# Libiberty 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with libiberty; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +# This file was written, and is maintained by K. Richard Pixley +# . + +# +# Makefile for libiberty directory +# + +srcdir = . + +prefix = /usr/local + +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib + +datadir = $(prefix)/lib + +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +oldincludedir = +docdir = $(datadir)/doc + +SHELL = /bin/sh + +# Multilib support variables. +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = +MULTIDO = true +MULTICLEAN = true + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +AR = ar +AR_FLAGS = rc + +ERRORS_CC = $(CC) +CC = cc +CFLAGS = -g +LIBCFLAGS = $(CFLAGS) +MAKEINFO = makeinfo +RANLIB = ranlib + +PICFLAG = + +MAKEOVERRIDES = + +TARGETLIB = libiberty.a + +CONFIG_H = lconfig.h +NEEDED_LIST = lneeded-list + +# HOST_OFILES contains the list of objects that should be in the +# library (in addition to the REQUIRED_OFILES and EXTRA_OFILES). +# A configuration may override this with a fixed list a object files +# names (hard to maintain), or some other way to generate a list. +HOST_OFILES=`cat needed-list` + +# Extra targets that the top-level target depends on. +# Specifically, what needs to be made before HOST_OFILES can be used. +# Can be empty if HOST_OFILES is just a list of file names. +DO_ALSO = needed-list + +# A configuration can specify extra .o files that should be included, +# even if they are in libc. (Perhaps the libc version is buggy.) +EXTRA_OFILES = + +# Flags to pass to a recursive make. +FLAGS_TO_PASS = \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "EXTRA_OFILES=$(EXTRA_OFILES)" \ + "HDEFINES=$(HDEFINES)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LOADLIBES=$(LOADLIBES)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "SHELL=$(SHELL)" + +all: stamp-picdir $(TARGETLIB) required-list + @if [ "$(RULE1)" != "not-used" ]; then \ + $(MULTIDO) $(FLAGS_TO_PASS) multi-do DO=all; \ + else true; \ + fi + +.PHONY: check installcheck +check installcheck: + + +#### Host, target, and site specific Makefile fragments come in here. +### + +INCDIR=$(srcdir)/$(MULTISRCTOP)../include + +COMPILE.c = $(CC) -c $(LIBCFLAGS) -I. -I$(INCDIR) $(HDEFINES) +.c.o: + test -z "$(PICFLAG)" || \ + $(COMPILE.c) $(PICFLAG) $< -o pic/$@ + $(COMPILE.c) $< + +# The default target just invokes make recursively. +# However, the automatic configuration (in config/mh_default). +# first causes it to figure out the objects missing in libc. +info install-info clean-info dvi: + +# Include files that are in this directory. +HFILES = + +# NOTE: If you add new files to the library, add them to this list +# (alphabetical), and add them to REQUIRED_OFILES or 'functions.def'. +CFILES = alloca.c argv.c basename.c bcmp.c bcopy.c bzero.c \ + clock.c concat.c cplus-dem.c fdmatch.c \ + getcwd.c getopt.c getopt1.c getpagesize.c getruntime.c \ + floatformat.c hex.c index.c insque.c \ + memchr.c memcmp.c memcpy.c memmove.c memset.c \ + obstack.c random.c rename.c rindex.c sigsetmask.c spaces.c \ + strcasecmp.c strncasecmp.c \ + strchr.c strdup.c strerror.c strrchr.c strsignal.c \ + strstr.c strtod.c strtol.c strtoul.c tmpnam.c \ + vasprintf.c vfork.c vfprintf.c vprintf.c vsprintf.c waitpid.c \ + xatexit.c xexit.c xmalloc.c xstrdup.c xstrerror.c +# These are always included in the library. +REQUIRED_OFILES = argv.o basename.o concat.o cplus-dem.o fdmatch.o \ + getopt.o getopt1.o getruntime.o hex.o \ + floatformat.o obstack.o spaces.o strerror.o strsignal.o \ + vasprintf.o xatexit.o xexit.o xmalloc.o xstrdup.o xstrerror.o + +# Do we want/need any config overrides? +# + +STAGESTUFF = $(TARGETLIB) *.o + +INSTALL_DEST = libdir +install: install_to_$(INSTALL_DEST) + +install_to_libdir: all + $(INSTALL_DATA) $(TARGETLIB) $(libdir)/$(TARGETLIB).n + ( cd $(libdir) ; $(RANLIB) $(libdir)/$(TARGETLIB).n ) + mv -f $(libdir)/$(TARGETLIB).n $(libdir)$(MULTISUBDIR)/$(TARGETLIB) + @$(MULTIDO) $(FLAGS_TO_PASS) multi-do DO=install + +install_to_tooldir: all + $(INSTALL_DATA) $(TARGETLIB) $(tooldir)/lib/$(TARGETLIB).n + ( cd $(tooldir) ; $(RANLIB) $(tooldir)/lib/$(TARGETLIB).n ) + mv -f $(tooldir)/lib/$(TARGETLIB).n $(tooldir)/lib$(MULTISUBDIR)/$(TARGETLIB) + @$(MULTIDO) $(FLAGS_TO_PASS) multi-do DO=install + +# The default configuration adds to libiberty all those functions that are +# missing in libc. More precisely, it includes whatever $(CC) fails to find. +# Then a sed+awk combination translates the ld error messages into +# a list of .o files. + +needed-list: stamp-picdir $(NEEDED_LIST) + cp $(NEEDED_LIST) needed-list + +lneeded-list: $(EXTRA_OFILES) needed.awk errors + rm -f lneeded-list + f=""; \ + for i in `awk -f needed.awk >lneeded-list + +# Generate an awk script that looks for functions in functions.def + +needed.awk: $(srcdir)/functions.def Makefile + echo "# !Automatically generated from $(srcdir)/functions.def"\ + "- DO NOT EDIT!" >needed.awk + grep '^DEF(' < $(srcdir)/functions.def \ + | sed -e '/DEF/s|DEF.\([^,]*\).*|/\1/ { printf "\1.o " }|' \ + >>needed.awk + +config.h: $(CONFIG_H) + cp $(CONFIG_H) config.h + +lconfig.h: needed2.awk errors + echo "/* !Automatically generated from $(srcdir)/functions.def"\ + "- DO NOT EDIT! */" >lconfig.h + awk -f needed2.awk >lconfig.h + +# Generate an awk script that looks for variables in functions.def + +needed2.awk: $(srcdir)/functions.def Makefile + echo "# !Automatically generated from $(srcdir)/functions.def"\ + "- DO NOT EDIT!" >needed2.awk + grep '^DEFVAR(' < $(srcdir)/functions.def \ + | sed -e '/DEFVAR/s|DEFVAR.\([^,]*\).*|/\1/ { printf "#ifndef NEED_\1\\n#define NEED_\1\\n#endif\\n" }|' \ + >>needed2.awk + grep '^DEFFUNC(' < $(srcdir)/functions.def \ + | sed -e '/DEFFUNC/s|DEFFUNC.\([^,]*\).*|/\1/ { printf "#ifndef NEED_\1\\n#define NEED_\1\\n#endif\\n" }|' \ + >>needed2.awk + +dummy.o: $(srcdir)/dummy.c $(srcdir)/functions.def + $(CC) -c $(CFLAGS) -I. -I$(INCDIR) $(HDEFINES) $(srcdir)/dummy.c 2>/dev/null + +errors: dummy.o $(EXTRA_OFILES) + -($(ERRORS_CC) -o dummy $(CFLAGS) $(LDFLAGS) $(ERRORS_LDFLAGS) dummy.o $(EXTRA_OFILES) $(LOADLIBES)) >errors 2>&1 || true + +# required-list is used when building a shared bfd/opcodes/libiberty library. +required-list: Makefile + echo $(REQUIRED_OFILES) > required-list + +$(HOST_OFILES) $(REQUIRED_OFILES) : config.h + +RULE1 = $(TARGETLIB) +$(RULE1): $(REQUIRED_OFILES) $(DO_ALSO) .always. + @$(MAKE) RULE1=not-used RULE2=$(TARGETLIB) $(FLAGS_TO_PASS) \ + "HOST_OFILES=$(HOST_OFILES)" + +# Rule invoked by recursive make in $(RULE1). +RULE2 = not-used +$(RULE2): $(REQUIRED_OFILES) $(HOST_OFILES) + rm -rf $(TARGETLIB) + $(AR) $(AR_FLAGS) $(TARGETLIB) \ + $(REQUIRED_OFILES) $(HOST_OFILES) + $(RANLIB) $(TARGETLIB) + +stamp-picdir: + if [ -n "$(PICFLAG)" ] && [ ! -d pic ]; then \ + mkdir pic; \ + else true; fi + touch stamp-picdir + +.always.: +# Do nothing. + +.PHONY: all etags tags ls clean stage1 stage2 .always. + +etags tags: TAGS + +TAGS: $(CFILES) $(HFILES) + etags `for i in $(HFILES) $(CFILES); do echo $(srcdir)/$$i ; done` + +# The standalone demangler (c++filt) has been moved to binutils. +demangle: + @echo "The standalone demangler, now named c++filt, is now" + @echo "a part of binutils." + @false + +ls: + @echo Makefile $(HFILES) $(CFILES) + +# Need to deal with profiled libraries, too. + +mostlyclean: + rm -rf *.o pic core errs \#* *.E a.out + rm -f needed.awk needed2.awk errors dummy needed-list config.h + rm -f $(CONFIG_H) $(NEEDED_LIST) stamp-picdir + @$(MULTICLEAN) multi-clean DO=mostlyclean +clean: mostlyclean + rm -f *.a required-list + @$(MULTICLEAN) multi-clean DO=clean +distclean: clean + rm -f *~ Makefile config.status alloca-conf.h xhost-mkfrag TAGS + @$(MULTICLEAN) multi-clean DO=distclean +maintainer-clean realclean: distclean + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + +argv.o: $(INCDIR)/libiberty.h +basename.o: $(INCDIR)/libiberty.h +concat.o: $(INCDIR)/libiberty.h +cplus-dem.o: $(INCDIR)/demangle.h +fdmatch.o: $(INCDIR)/libiberty.h +getopt.o: $(INCDIR)/getopt.h +getopt1.o: $(INCDIR)/getopt.h +getruntime.o: $(INCDIR)/libiberty.h +hex.o: $(INCDIR)/libiberty.h +floatformat.o: $(INCDIR)/floatformat.h +obstack.o: $(INCDIR)/obstack.h +spaces.o: $(INCDIR)/libiberty.h +strerror.o: $(INCDIR)/libiberty.h +strsignal.o: $(INCDIR)/libiberty.h +xatexit.o: $(INCDIR)/libiberty.h +xexit.o: $(INCDIR)/libiberty.h +xmalloc.o: $(INCDIR)/libiberty.h +xstrdup.o: $(INCDIR)/libiberty.h +xstrerror.o: $(INCDIR)/libiberty.h diff --git a/contrib/gdb/libiberty/README b/contrib/gdb/libiberty/README new file mode 100644 index 000000000000..5081bbac1968 --- /dev/null +++ b/contrib/gdb/libiberty/README @@ -0,0 +1,129 @@ +This directory contains the -liberty library of free software. +It is a collection of subroutines used by various GNU programs. +Current members include: + + getopt -- get options from command line + obstack -- stacks of arbitrarily-sized objects + strerror -- error message strings corresponding to errno + strtol -- string-to-long conversion + strtoul -- string-to-unsigned-long conversion + +We expect many of the GNU subroutines that are floating around to +eventually arrive here. + +To build the library, do: + + ./configure HOSTTYPE + make + +Please report bugs and fixes to "bug-gnu-utils@prep.ai.mit.edu". Thank you. + +ADDING A NEW FILE +================= + +There are two sets of files: Those that are "required" will be +included in the library for all configurations, while those +that are "optional" will be included in the library only if "needed." + +To add a new required file, edit Makefile to add the source file +name to CFILES and the object file to REQUIRED_OFILES. + +Adding a new optional file is more fragile. As a general rule, +an optional file will be included in the library if it provides +functionality missing in the "standard" C library. +For most hosts, the Makefile automatically figures out which +functionality is missing by compiling and linking a dummy test +program, and examining the error messages. + +So to get this to work, you should do the following: + +1) Select one function defined in the file you're adding. +For example, the getcwd function. +2) Add that function to the list in the file functions.def. +3) The name of the new file must be the same as the function +you've chosen with the .c suffix added. E.g. getcwd() must be +defined in getcwd.c. (The file can define other functions as well.) +4) In Makefile.in, add the name of the source file (e.g. getcwd.c) +to CFILES. + +The file you've added (e.g. getcwd.c) should compile and work +on all hosts where it is needed (e.g. not found when linking +the dummy.c program). It does not have to work or even +compile on hosts where it is not needed. + +HOW THE AUTOMATIC CONFIGURATION WORKS +===================================== + +The libiberty.a target (in RULE1) depends on $(DO_ALSO). +For normal configurations, DO_ALSO=needed-list. + +So needed-list is first made. The needed-list rule compiles +dummy.c. Because dummy.c includes functions.def, the +resulting object file will contain a call to each of the +optional functions (for simplicity assume each optional file +defines a single function). This object file will be linked +against the standard libraries (as defined by using $(CC) +and various flags). Any function missing will causes the +linker to emit an error message. We assume the name +of the missing function(s) are in the error message(s). +The awk script find-needed.awk has been generated from +functions.def. It is used to search the linker output +messages for words that match the functions listed in +functions.def. The list of functions found is written +on a single line to the file needed-list. + +After needed-list has been generated, the libiberty.a +target (in RULE1) just calls 'make' recursively. +It passes the contents of needed-list using the +definition (expanded) HOST_OFILES="`cat needed-list`". +It also tells the inferior 'make' to use RULE2. + +The inferior 'make' is very conventional: The main +rule is $(RULE2) (which is libiberty.a). It depends +on a list of object files: $(REQUIRED_OFILES) $(HOST_OFILES) +(and $(EXTRA_OFILES), which is usually empty). The superior +'make' passes in $(HOST_OFILES); the others are fixed +in the Makefile. + +ADDING A NEW CONFIGURATION +========================== + +On most hosts you should be able to use the scheme for automatically +figuring out which files are needed. In that case, you probably +don't need a special Makefile stub for that configuration. + +If the fully automatic scheme doesn't work, you may be able to get +by with defining EXTRA_OFILES in your Makefile stub. This is +a list of object file names that should be treated as required +for this configuration - they will be included in libiberty.a, +regardless of whatever might be in the C library. Moreover, +when the dummy.c program is linked, it will be linked with +$(EXTRA_OFILES). Therefore, if a function in functions.def +is defined by one of the EXTRA_OFILES, it will not be listed as +"needed". Thus if your hal9000 host needs a special implementation +of getcwd, you can just create hal9000-getcwd.c, and define: + EXTRA_OFILES=hal9000-getcwd.o +Or if you want to use the libiberty version of strstr(), +even though there is a version in the C library (it might be +buggy or slow), just define: + EXTRA_OFILES=strstr.o + +You can create a "manual" host configuration FOO with a file +config/mh-FOO. In it, the HOST_OFILES macro should explicitly +list that subset of the optional files that should be in the +library. You should also set: + DO_ALSO = +This overrides all of the magic needed to automatically +determine which files are "needed." However, keeping that list +up to date is another matter... + +HOW THE MANUAL CONFIGURATION WORKS +================================== + +This also uses a recursive make, but the superior make +does not do anything interesting - it just calls the +inferior make with HOST_OFILES defined as $(HOST_OFILES), +which is the list you created in your configuration. + +You probably don't want to depend on manual configuration, +because keeping the HOST_OFILES list up-to-date will be a pain. diff --git a/contrib/gdb/libiberty/alloca-botch.h b/contrib/gdb/libiberty/alloca-botch.h new file mode 100644 index 000000000000..c909573f58c6 --- /dev/null +++ b/contrib/gdb/libiberty/alloca-botch.h @@ -0,0 +1,5 @@ +/* RS/6000 AIX botched alloca and requires a pragma, which ordinary compilers + throw up about, so we have to put it in a specially-configured file. + Like this one. */ + +#pragma alloca diff --git a/contrib/gdb/libiberty/alloca-norm.h b/contrib/gdb/libiberty/alloca-norm.h new file mode 100644 index 000000000000..8d91b5ad4295 --- /dev/null +++ b/contrib/gdb/libiberty/alloca-norm.h @@ -0,0 +1,16 @@ +/* "Normal" configuration for alloca. */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#ifdef sparc +#include +extern char *__builtin_alloca(); /* Stupid include file doesn't declare it */ +#else +#ifdef __STDC__ +PTR alloca (size_t); +#else +PTR alloca (); /* must agree with functions.def */ +#endif +#endif /* sparc */ +#endif /* not __GNUC__ */ diff --git a/contrib/gdb/libiberty/alloca.c b/contrib/gdb/libiberty/alloca.c new file mode 100644 index 000000000000..9c472ead6dfc --- /dev/null +++ b/contrib/gdb/libiberty/alloca.c @@ -0,0 +1,475 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + J.Otto Tennant contributed the Cray support. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* If compiling with GCC, this file's not needed. */ +#ifndef alloca + +#ifdef emacs +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif /* static */ +#endif /* emacs */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif + +#if __STDC__ +typedef void *pointer; +#else +typedef char *pointer; +#endif + +#define NULL 0 + +/* Different portions of Emacs need to call different versions of + malloc. The Emacs executable needs alloca to call xmalloc, because + ordinary malloc isn't protected from input signals. On the other + hand, the utilities in lib-src need alloca to call malloc; some of + them are very simple, and don't have an xmalloc routine. + + Non-Emacs programs expect this to call use xmalloc. + + Callers below should use malloc. */ + +#ifndef emacs +#define malloc xmalloc +extern pointer xmalloc (); +#endif + +/* Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* Direction unknown. */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ + +#else /* STACK_DIRECTION == 0; need run-time code. */ + +static int stack_dir; /* 1 or -1 once known. */ +#define STACK_DIR stack_dir + +static void +find_stack_direction () +{ + static char *addr = NULL; /* Address of first `dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (dummy) > addr) + stack_dir = 1; /* Stack grew upward. */ + else + stack_dir = -1; /* Stack grew downward. */ + } +} + +#endif /* STACK_DIRECTION == 0 */ + +/* An "alloca header" is used to: + (a) chain together all alloca'ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc + alignment chunk size. The following default should work okay. */ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* To force sizeof(header). */ + struct + { + union hdr *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +} header; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a pointer to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +pointer +alloca (size) + unsigned size; +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* Traverses linked list. */ + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = malloc (sizeof (header) + size); + /* Address of header. */ + + ((header *) new)->h.next = last_alloca_header; + ((header *) new)->h.deep = depth; + + last_alloca_header = (header *) new; + + /* User storage begins just after header. */ + + return (pointer) ((char *) new + sizeof (header)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY */ + +#endif /* no alloca */ diff --git a/contrib/gdb/libiberty/argv.c b/contrib/gdb/libiberty/argv.c new file mode 100644 index 000000000000..40582abe4082 --- /dev/null +++ b/contrib/gdb/libiberty/argv.c @@ -0,0 +1,328 @@ +/* Create and destroy argument vectors (argv's) + Copyright (C) 1992 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Create and destroy argument vectors. An argument vector is simply an + array of string pointers, terminated by a NULL pointer. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#define isspace(ch) ((ch) == ' ' || (ch) == '\t') + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ + +#include +extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */ +extern size_t strlen (const char *s); /* 4.11.6.3 */ +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */ +extern void free (void *ptr); /* 4.10.3.2 */ +extern char *strdup (const char *s); /* Non-ANSI */ + +#else /* !__STDC__ */ + +extern char *memcpy (); /* Copy memory region */ +extern int strlen (); /* Count length of string */ +extern char *malloc (); /* Standard memory allocater */ +extern char *realloc (); /* Standard memory reallocator */ +extern void free (); /* Free malloc'd memory */ +extern char *strdup (); /* Duplicate a string */ + +#endif /* __STDC__ */ + +#include "alloca-conf.h" + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOS +#define EOS '\0' +#endif + +#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ + + +/* + +NAME + + freeargv -- free an argument vector + +SYNOPSIS + + void freeargv (vector) + char **vector; + +DESCRIPTION + + Free an argument vector that was built using buildargv. Simply scans + through the vector, freeing the memory for each argument until the + terminating NULL is found, and then frees the vector itself. + +RETURNS + + No value. + +*/ + +void freeargv (vector) +char **vector; +{ + register char **scan; + + if (vector != NULL) + { + for (scan = vector; *scan != NULL; scan++) + { + free (*scan); + } + free (vector); + } +} + +/* + +NAME + + buildargv -- build an argument vector from a string + +SYNOPSIS + + char **buildargv (sp) + char *sp; + +DESCRIPTION + + Given a pointer to a string, parse the string extracting fields + separated by whitespace and optionally enclosed within either single + or double quotes (which are stripped off), and build a vector of + pointers to copies of the string for each field. The input string + remains unchanged. + + All of the memory for the pointer array and copies of the string + is obtained from malloc. All of the memory can be returned to the + system with the single function call freeargv, which takes the + returned result of buildargv, as it's argument. + + The memory for the argv array is dynamically expanded as necessary. + +RETURNS + + Returns a pointer to the argument vector if successful. Returns NULL + if the input string pointer is NULL or if there is insufficient + memory to complete building the argument vector. + +NOTES + + In order to provide a working buffer for extracting arguments into, + with appropriate stripping of quotes and translation of backslash + sequences, we allocate a working buffer at least as long as the input + string. This ensures that we always have enough space in which to + work, since the extracted arg is never larger than the input string. + + If the input is a null string (as opposed to a NULL pointer), then + buildarg returns an argv that has one arg, a null string. + + Argv is always kept terminated with a NULL arg pointer, so it can + be passed to freeargv at any time, or returned, as appropriate. +*/ + +char **buildargv (input) +char *input; +{ + char *arg; + char *copybuf; + int squote = 0; + int dquote = 0; + int bsquote = 0; + int argc = 0; + int maxargc = 0; + char **argv = NULL; + char **nargv; + + if (input != NULL) + { + copybuf = alloca (strlen (input) + 1); + /* Is a do{}while to always execute the loop once. Always return an + argv, even for null strings. See NOTES above, test case below. */ + do + { + /* Pick off argv[argc] */ + while (isspace (*input)) + { + input++; + } + if ((maxargc == 0) || (argc >= (maxargc - 1))) + { + /* argv needs initialization, or expansion */ + if (argv == NULL) + { + maxargc = INITIAL_MAXARGC; + nargv = (char **) malloc (maxargc * sizeof (char *)); + } + else + { + maxargc *= 2; + nargv = (char **) realloc (argv, maxargc * sizeof (char *)); + } + if (nargv == NULL) + { + if (argv != NULL) + { + freeargv (argv); + argv = NULL; + } + break; + } + argv = nargv; + argv[argc] = NULL; + } + /* Begin scanning arg */ + arg = copybuf; + while (*input != EOS) + { + if (isspace (*input) && !squote && !dquote && !bsquote) + { + break; + } + else + { + if (bsquote) + { + bsquote = 0; + *arg++ = *input; + } + else if (*input == '\\') + { + bsquote = 1; + } + else if (squote) + { + if (*input == '\'') + { + squote = 0; + } + else + { + *arg++ = *input; + } + } + else if (dquote) + { + if (*input == '"') + { + dquote = 0; + } + else + { + *arg++ = *input; + } + } + else + { + if (*input == '\'') + { + squote = 1; + } + else if (*input == '"') + { + dquote = 1; + } + else + { + *arg++ = *input; + } + } + input++; + } + } + *arg = EOS; + argv[argc] = strdup (copybuf); + if (argv[argc] == NULL) + { + freeargv (argv); + argv = NULL; + break; + } + argc++; + argv[argc] = NULL; + + while (isspace (*input)) + { + input++; + } + } + while (*input != EOS); + } + return (argv); +} + +#ifdef MAIN + +/* Simple little test driver. */ + +static char *tests[] = +{ + "a simple command line", + "arg 'foo' is single quoted", + "arg \"bar\" is double quoted", + "arg \"foo bar\" has embedded whitespace", + "arg 'Jack said \\'hi\\'' has single quotes", + "arg 'Jack said \\\"hi\\\"' has double quotes", + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", + + /* This should be expanded into only one argument. */ + "trailing-whitespace ", + + "", + NULL +}; + +main () +{ + char **argv; + char **test; + char **targs; + + for (test = tests; *test != NULL; test++) + { + printf ("buildargv(\"%s\")\n", *test); + if ((argv = buildargv (*test)) == NULL) + { + printf ("failed!\n\n"); + } + else + { + for (targs = argv; *targs != NULL; targs++) + { + printf ("\t\"%s\"\n", *targs); + } + printf ("\n"); + } + freeargv (argv); + } + +} + +#endif /* MAIN */ diff --git a/contrib/gdb/libiberty/atexit.c b/contrib/gdb/libiberty/atexit.c new file mode 100644 index 000000000000..4463cb695018 --- /dev/null +++ b/contrib/gdb/libiberty/atexit.c @@ -0,0 +1,14 @@ +/* Wrapper to implement ANSI C's atexit using SunOS's on_exit. */ +/* This function is in the public domain. --Mike Stump. */ + +#ifndef NEED_on_exit +int +atexit(f) + void (*f)(); +{ + /* If the system doesn't provide a definition for atexit, use on_exit + if the system provides that. */ + on_exit (f, 0); + return 0; +} +#endif diff --git a/contrib/gdb/libiberty/basename.c b/contrib/gdb/libiberty/basename.c new file mode 100644 index 000000000000..689b0c2d39a0 --- /dev/null +++ b/contrib/gdb/libiberty/basename.c @@ -0,0 +1,43 @@ +/* Return the basename of a pathname. + This file is in the public domain. */ + +/* +NAME + basename -- return pointer to last component of a pathname + +SYNOPSIS + char *basename (const char *name) + +DESCRIPTION + Given a pointer to a string containing a typical pathname + (/usr/src/cmd/ls/ls.c for example), returns a pointer to the + last component of the pathname ("ls.c" in this case). + +BUGS + Presumes a UNIX style path with UNIX style separators. +*/ + +#include "ansidecl.h" +#include "libiberty.h" + +#include "config.h" + +#ifdef NEED_basename + +char * +basename (name) + const char *name; +{ + const char *base = name; + + while (*name) + { + if (*name++ == '/') + { + base = name; + } + } + return (char *) base; +} + +#endif diff --git a/contrib/gdb/libiberty/bcmp.c b/contrib/gdb/libiberty/bcmp.c new file mode 100644 index 000000000000..11e4417db159 --- /dev/null +++ b/contrib/gdb/libiberty/bcmp.c @@ -0,0 +1,49 @@ +/* bcmp + This function is in the public domain. */ + +/* + +NAME + + bcmp -- compare two memory regions + +SYNOPSIS + + int bcmp (char *from, char *to, int count) + +DESCRIPTION + + Compare two memory regions and return zero if they are identical, + non-zero otherwise. If count is zero, return zero. + +NOTES + + No guarantee is made about the non-zero returned value. In + particular, the results may be signficantly different than + strcmp(), where the return value is guaranteed to be less than, + equal to, or greater than zero, according to lexicographical + sorting of the compared regions. + +BUGS + +*/ + + +int +bcmp (from, to, count) + char *from, *to; + int count; +{ + int rtnval = 0; + + while (count-- > 0) + { + if (*from++ != *to++) + { + rtnval = 1; + break; + } + } + return (rtnval); +} + diff --git a/contrib/gdb/libiberty/bcopy.c b/contrib/gdb/libiberty/bcopy.c new file mode 100644 index 000000000000..b655363d879e --- /dev/null +++ b/contrib/gdb/libiberty/bcopy.c @@ -0,0 +1,35 @@ +/* bcopy -- copy memory regions of arbitary length + +NAME + bcopy -- copy memory regions of arbitrary length + +SYNOPSIS + void bcopy (char *in, char *out, int length) + +DESCRIPTION + Copy LENGTH bytes from memory region pointed to by IN to memory + region pointed to by OUT. + +BUGS + Significant speed improvements can be made in some cases by + implementing copies of multiple bytes simultaneously, or unrolling + the copy loop. + +*/ + +void +bcopy (src, dest, len) + register char *src, *dest; + int len; +{ + if (dest < src) + while (len--) + *dest++ = *src++; + else + { + char *lasts = src + (len-1); + char *lastd = dest + (len-1); + while (len--) + *(char *)lastd-- = *(char *)lasts--; + } +} diff --git a/contrib/gdb/libiberty/bzero.c b/contrib/gdb/libiberty/bzero.c new file mode 100644 index 000000000000..d01644b7f4b8 --- /dev/null +++ b/contrib/gdb/libiberty/bzero.c @@ -0,0 +1,31 @@ +/* Portable version of bzero for systems without it. + This function is in the public domain. */ + +/* +NAME + bzero -- zero the contents of a specified memory region + +SYNOPSIS + void bzero (char *to, int count) + +DESCRIPTION + Zero COUNT bytes of memory pointed to by TO. + +BUGS + Significant speed enhancements may be made in some environments + by zeroing more than a single byte at a time, or by unrolling the + loop. + +*/ + + +void +bzero (to, count) + char *to; + int count; +{ + while (count-- > 0) + { + *to++ = 0; + } +} diff --git a/contrib/gdb/libiberty/clock.c b/contrib/gdb/libiberty/clock.c new file mode 100644 index 000000000000..b60de1657a45 --- /dev/null +++ b/contrib/gdb/libiberty/clock.c @@ -0,0 +1,73 @@ +/* ANSI-compatible clock function. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +#ifdef HAVE_GETRUSAGE +#include +#include +#endif + +#ifdef HAVE_TIMES +#ifndef NO_SYS_PARAM_H +#include +#endif +#include +#endif + +/* FIXME: should be able to declare as clock_t. */ + +long +clock () +{ +#ifdef HAVE_GETRUSAGE + struct rusage rusage; + + getrusage (0, &rusage); + return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec + + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec); +#else +#ifdef HAVE_TIMES + struct tms tms; + + times (&tms); + return (tms.tms_utime + tms.tms_stime) * (1000000 / HZ); +#else +#ifdef VMS + struct + { + int proc_user_time; + int proc_system_time; + int child_user_time; + int child_system_time; + } vms_times; + + times (&vms_times); + return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000; +#else + /* A fallback, if nothing else available. */ + return 0; +#endif /* VMS */ +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ +} + diff --git a/contrib/gdb/libiberty/concat.c b/contrib/gdb/libiberty/concat.c new file mode 100644 index 000000000000..5b132c85764f --- /dev/null +++ b/contrib/gdb/libiberty/concat.c @@ -0,0 +1,167 @@ +/* Concatenate variable number of strings. + Copyright (C) 1991, 1994 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* + +NAME + + concat -- concatenate a variable number of strings + +SYNOPSIS + + #include + + char *concat (s1, s2, s3, ..., NULL) + +DESCRIPTION + + Concatenate a variable number of strings and return the result + in freshly malloc'd memory. + + Returns NULL if insufficient memory is available. The argument + list is terminated by the first NULL pointer encountered. Pointers + to empty strings are ignored. + +NOTES + + This function uses xmalloc() which is expected to be a front end + function to malloc() that deals with low memory situations. In + typical use, if malloc() returns NULL then xmalloc() diverts to an + error handler routine which never returns, and thus xmalloc will + never return a NULL pointer. If the client application wishes to + deal with low memory situations itself, it should supply an xmalloc + that just directly invokes malloc and blindly returns whatever + malloc returns. +*/ + + +#include "ansidecl.h" +#include "libiberty.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#ifdef __STDC__ +#include +extern size_t strlen (const char *s); +#else +extern int strlen (); +#endif + +#define NULLP (char *)0 + +/* VARARGS */ +#ifdef ANSI_PROTOTYPES +char * +concat (const char *first, ...) +#else +char * +concat (va_alist) + va_dcl +#endif +{ + register int length; + register char *newstr; + register char *end; + register const char *arg; + va_list args; +#ifndef ANSI_PROTOTYPES + const char *first; +#endif + + /* First compute the size of the result and get sufficient memory. */ + +#ifdef ANSI_PROTOTYPES + va_start (args, first); +#else + va_start (args); + first = va_arg (args, const char *); +#endif + + if (first == NULLP) + length = 0; + else + { + length = strlen (first); + while ((arg = va_arg (args, const char *)) != NULLP) + { + length += strlen (arg); + } + } + newstr = (char *) xmalloc (length + 1); + va_end (args); + + /* Now copy the individual pieces to the result string. */ + + if (newstr != NULLP) + { +#ifdef ANSI_PROTOTYPES + va_start (args, first); +#else + va_start (args); + first = va_arg (args, const char *); +#endif + end = newstr; + if (first != NULLP) + { + arg = first; + while (*arg) + { + *end++ = *arg++; + } + while ((arg = va_arg (args, const char *)) != NULLP) + { + while (*arg) + { + *end++ = *arg++; + } + } + } + *end = '\000'; + va_end (args); + } + + return (newstr); +} + +#ifdef MAIN + +/* Simple little test driver. */ + +#include + +int +main () +{ + printf ("\"\" = \"%s\"\n", concat (NULLP)); + printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); + printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); + printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); + printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); + printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); + printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); + return 0; +} + +#endif diff --git a/contrib/gdb/libiberty/config.table b/contrib/gdb/libiberty/config.table new file mode 100644 index 000000000000..1b67dd5ae883 --- /dev/null +++ b/contrib/gdb/libiberty/config.table @@ -0,0 +1,63 @@ +case "${host}" in + rs6000-ibm-aix3.1 | rs6000-ibm-aix) + frag=mh-aix + files=${xsrcdir}alloca-botch.h ;; + *-ibm-aix*) files=${xsrcdir}alloca-botch.h ;; + arm-*-riscix*) frag=mh-riscix ;; + m68k-apollo-bsd*) frag=mh-a68bsd ;; + m68k-apollo-sysv*) frag=mh-apollo68 ;; + i[345]86-ncr-sysv4*) frag=mh-ncr3000 ;; + *-*-cxux7*) frag=mh-cxux7 ;; + *-*-lynxos*) frag=mh-lynxos ;; + *-*-dgux*) frag=mh-sysv ;; + hppa*-hp-bsd*) frag=mh-hpbsd ;; + *-*-hpux*) frag=mh-hpux ;; + *-*-hiux*) frag=mh-hpux ;; + *-*-irix4*) frag=mh-irix4 ;; + *-*-irix*) frag=mh-sysv ;; + *-*-m88kbcs*) frag=mh-sysv ;; + *-*-solaris2*) frag=mh-sysv4 ;; + *-*-sysv4*) frag=mh-sysv4 ;; + *-*-sysv*) frag=mh-sysv ;; + *-*-go32) frag=mh-go32 ;; + + *-*-vxworks5*) + # VxWorks 5 needs special action, because the usual + # autoconfiguration scheme does not work. + frag=mt-vxworks5 + ;; +esac + +# Try to handle funky case of solaris 2 -> sun 4. +case "${host}" in + sparc-sun-sunos4.1.3) + if [ "${with_cross_host}" != "${host}" ] ; then + frag=mt-sunos4 + fi + ;; +esac + +frags=$frag + +# If they didn't specify --enable-shared, don't generate shared libs. +if [ "${enable_shared}" = "yes" ]; then + case "${host}" in + hppa*-*-*) frags="${frags} ../../config/mh-papic" ;; + i[345]86-*-*) frags="${frags} ../../config/mh-x86pic" ;; + *-*-*) frags="${frags} ../../config/mh-${host_cpu}pic" ;; + esac +fi + +echo "# Warning: this fragment is automatically generated" > temp-frag + +for frag in ${frags}; do + frag=${srcdir}/${xsrcdir}config/$frag + if [ -f ${frag} ]; then + echo "Appending ${frag} to xhost-mkfrag" + echo "# Following fragment copied from ${frag}" >> temp-frag + cat ${frag} >> temp-frag + fi +done + +frag=xhost-mkfrag +${moveifchange} temp-frag xhost-mkfrag diff --git a/contrib/gdb/libiberty/config/mh-a68bsd b/contrib/gdb/libiberty/config/mh-a68bsd new file mode 100644 index 000000000000..3c5a237e60ba --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-a68bsd @@ -0,0 +1,2 @@ +RANLIB=ranlib +CC= cc -A ansi -A runtype,any -A systype,any -U__STDC__ diff --git a/contrib/gdb/libiberty/config/mh-aix b/contrib/gdb/libiberty/config/mh-aix new file mode 100644 index 000000000000..c7b848d976aa --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-aix @@ -0,0 +1,10 @@ +HDEFINES = -D__IEEE_BIG_ENDIAN +RANLIB=true +INSTALL=cp + +# Most releases of AIX 3.1 include an incorrect internal version of copysign +# in libc.a for use by some libc public functions including modf. The public +# version of copysign in libm.a is usable. For the sake of libg++ (which +# uses modf), we add copysign here. Supposedly, this problem is fixed in AIX +# 3.1.8 and above, including all releases of AIX 3.2. +EXTRA_OFILES = copysign.o diff --git a/contrib/gdb/libiberty/config/mh-apollo68 b/contrib/gdb/libiberty/config/mh-apollo68 new file mode 100644 index 000000000000..651770ce31cd --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-apollo68 @@ -0,0 +1,2 @@ +RANLIB=true +CC= cc -A ansi -A runtype,any -A systype,any -U__STDC__ diff --git a/contrib/gdb/libiberty/config/mh-cxux7 b/contrib/gdb/libiberty/config/mh-cxux7 new file mode 100644 index 000000000000..6d4d30bf46ff --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-cxux7 @@ -0,0 +1,3 @@ +HDEFINES = -DHAVE_SYSCONF -DHARRIS_FLOAT_FORMAT +RANLIB=true +INSTALL = cp diff --git a/contrib/gdb/libiberty/config/mh-go32 b/contrib/gdb/libiberty/config/mh-go32 new file mode 100644 index 000000000000..7c9fe4fa0bf0 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-go32 @@ -0,0 +1,4 @@ +HDEFINES=-DHAVE_GETRUSAGE +CC=i386-go32-gcc -O2 -fno-omit-frame-pointer +AR=i386-go32-ar +RANLIB=i386-go32-ranlib diff --git a/contrib/gdb/libiberty/config/mh-hpbsd b/contrib/gdb/libiberty/config/mh-hpbsd new file mode 100644 index 000000000000..ce11dcd6ac98 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-hpbsd @@ -0,0 +1,2 @@ +# HPPA hosts using BSD +RANLIB=true diff --git a/contrib/gdb/libiberty/config/mh-irix4 b/contrib/gdb/libiberty/config/mh-irix4 new file mode 100644 index 000000000000..ace767827122 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-irix4 @@ -0,0 +1,4 @@ +CC = cc -cckr +RANLIB = true +INSTALL = cp +EXTRA_OFILES = alloca.o diff --git a/contrib/gdb/libiberty/config/mh-lynxos b/contrib/gdb/libiberty/config/mh-lynxos new file mode 100644 index 000000000000..2f22110e880c --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-lynxos @@ -0,0 +1 @@ +HDEFINES = -DLOSING_SYS_SIGLIST diff --git a/contrib/gdb/libiberty/config/mh-ncr3000 b/contrib/gdb/libiberty/config/mh-ncr3000 new file mode 100644 index 000000000000..3a45c22b1281 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-ncr3000 @@ -0,0 +1,19 @@ +# Host configuration file for an NCR 3000 (i486/SVR4) system. + +# The NCR 3000 ships with a MetaWare compiler installed as /bin/cc. +# This compiler not only emits obnoxious copyright messages every time +# you run it, but it chokes and dies on a whole bunch of GNU source +# files. Default to using the AT&T compiler installed in /usr/ccs/ATT/cc. +# Unfortunately though, the AT&T compiler sometimes generates code that +# the assembler barfs on if -g is used, so disable it by default as well. +CC = /usr/ccs/ATT/cc +CFLAGS = + +RANLIB = true + +# The /usr/ucb/install program is incompatible (complains about unknown +# group staff). Use good old cp... +INSTALL = cp + +# The l flag generates a warning from the SVR4 archiver, remove it. +AR_FLAGS = cq diff --git a/contrib/gdb/libiberty/config/mh-riscix b/contrib/gdb/libiberty/config/mh-riscix new file mode 100644 index 000000000000..0209279de56a --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-riscix @@ -0,0 +1,6 @@ +# The native linker only reports the first undefined symbol if linking with a +# shared library. So build using gcc and link statically (this requires +# gcc 2.6.0 or above). + +ERRORS_CC = gcc +ERRORS_LDFLAGS = -static diff --git a/contrib/gdb/libiberty/config/mh-sysv b/contrib/gdb/libiberty/config/mh-sysv new file mode 100644 index 000000000000..eb102d550108 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-sysv @@ -0,0 +1 @@ +RANLIB=true diff --git a/contrib/gdb/libiberty/config/mh-sysv4 b/contrib/gdb/libiberty/config/mh-sysv4 new file mode 100644 index 000000000000..4d1aa3cd61d5 --- /dev/null +++ b/contrib/gdb/libiberty/config/mh-sysv4 @@ -0,0 +1,3 @@ +HDEFINES = -DHAVE_SYSCONF +RANLIB=true +INSTALL = cp diff --git a/contrib/gdb/libiberty/config/mt-sunos4 b/contrib/gdb/libiberty/config/mt-sunos4 new file mode 100644 index 000000000000..c25baa6ead68 --- /dev/null +++ b/contrib/gdb/libiberty/config/mt-sunos4 @@ -0,0 +1,2 @@ +XTRAFLAGS = -isystem /s1/cygnus/dejagnu/sparc-sun-sunos4.1.3/include/ +LOADLIBES = -L/s1/cygnus/dejagnu/sparc-sun-sunos4.1.3/lib diff --git a/contrib/gdb/libiberty/config/mt-vxworks5 b/contrib/gdb/libiberty/config/mt-vxworks5 new file mode 100644 index 000000000000..f1a46d361ae2 --- /dev/null +++ b/contrib/gdb/libiberty/config/mt-vxworks5 @@ -0,0 +1,27 @@ +# VxWorks 5.x target Makefile fragment. +# The autoconfiguration fails for a VxWorks target, because the +# libraries are actually on the target board, not in the file system. +# Therefore, we compute the dependencies by hand. + +HDEFINES = -DNO_SYS_PARAM_H +CONFIG_H = vxconfig.h +NEEDED_LIST = vxneeded-list + +vxconfig.h: Makefile + if [ -f ../newlib/Makefile ]; then \ + $(MAKE) $(FLAGS_TO_PASS) xconfig.h; \ + cp xconfig.h vxconfig.h; \ + else \ + echo "#define NEED_sys_nerr 1" >vxconfig.h; \ + echo "#define NEED_sys_errlist 1" >>vxconfig.h; \ + echo "#define NEED_sys_siglist 1" >>vxconfig.h; \ + echo "#define NEED_psignal 1" >>vxconfig.h; \ + fi + +vxneeded-list: Makefile + if [ -f ../newlib/Makefile ]; then \ + $(MAKE) $(FLAGS_TO_PASS) xneeded-list; \ + cp xneeded-list vxneeded-list; \ + else \ + echo getopt.o getpagesize.o insque.o random.o strcasecmp.o strncasecmp.o strdup.o vfork.o sigsetmask.o waitpid.o >vxneeded-list; \ + fi diff --git a/contrib/gdb/libiberty/configure.bat b/contrib/gdb/libiberty/configure.bat new file mode 100644 index 000000000000..ed33777174b3 --- /dev/null +++ b/contrib/gdb/libiberty/configure.bat @@ -0,0 +1,15 @@ +@echo off +if "%1" == "h8/300" goto h8300 + +echo Configuring libiberty for go32 +copy Makefile.dos Makefile +echo #define NEED_sys_siglist 1 >> config.h +echo #define NEED_psignal 1 >> config.h +update alloca-normal.h alloca-conf.h +goto exit + +:h8300 +echo Configuring libiberty for H8/300 +copy Makefile.dos Makefile + +:exit diff --git a/contrib/gdb/libiberty/configure.in b/contrib/gdb/libiberty/configure.in new file mode 100644 index 000000000000..84e4eac6c89e --- /dev/null +++ b/contrib/gdb/libiberty/configure.in @@ -0,0 +1,77 @@ +# This file is a shell script fragment that supplies the information +# necessary for a configure script to process the program in +# this directory. For more information, look at ../configure. + +configdirs= +srctrigger=getopt1.c +srcname="-liberty library" + +# per-host: + +files="alloca-norm.h" +links="alloca-conf.h" + +. ${srcdir}/config.table +host_makefile_frag=${frag} + +# per-target: + +# post-target: + +# If this is the target libiberty, check at compile time whether we are using +# newlib. If we are, we already know the files we need, since the linker +# will fail when run on some of the newlib targets. +if [ -n "${with_target_subdir}" ] ; then + cat > Makefile.tem <<'!EOF!' +CONFIG_H = xconfig.h +NEEDED_LIST = xneeded-list + +xconfig.h: Makefile + if [ -f ../newlib/Makefile ]; then \ + echo "#define NEED_sys_nerr 1" >xconfig.h; \ + echo "#define NEED_sys_errlist 1" >>xconfig.h; \ + echo "#define NEED_sys_siglist 1" >>xconfig.h; \ + echo "#define NEED_psignal 1" >>xconfig.h; \ + else \ + $(MAKE) $(FLAGS_TO_PASS) lconfig.h; \ + cp lconfig.h xconfig.h; \ + fi + +xneeded-list: Makefile + if [ -f ../newlib/Makefile ]; then \ + echo insque.o random.o strdup.o alloca.o >xneeded-list; \ + else \ + $(MAKE) $(FLAGS_TO_PASS) lneeded-list; \ + cp lneeded-list xneeded-list; \ + fi +!EOF! +sed -e "/^####/ r Makefile.tem" \ + -e '/INSTALL_DEST =/s/libdir/tooldir/' ${Makefile} > Makefile.tem3 +mv Makefile.tem3 ${Makefile} +rm -f Makefile.tem +fi + +# We need multilib support, but only if configuring for the target. +if [ -n "${with_target_subdir}" ] ; then + case ${srcdir} in + .) + if [ "${with_target_subdir}" != "." ] ; then + + # Set MULTISRCTOP to the value we need if we are not doing + # multilib. This will be overridden if --enable-multilib was + # used. + sed -e "s:^MULTISRCTOP[ ]*=.*$:MULTISRCTOP = ../:" \ + ${Makefile} > Makefile.tem + rm -f ${Makefile} + mv Makefile.tem ${Makefile} + + . ${srcdir}/${with_multisrctop}../../config-ml.in + else + . ${srcdir}/${with_multisrctop}../config-ml.in + fi + ;; + *) + . ${srcdir}/../config-ml.in + ;; + esac +fi diff --git a/contrib/gdb/libiberty/copysign.c b/contrib/gdb/libiberty/copysign.c new file mode 100644 index 000000000000..0b5f8c3d9df8 --- /dev/null +++ b/contrib/gdb/libiberty/copysign.c @@ -0,0 +1,140 @@ +#include + +#ifdef __IEEE_BIG_ENDIAN + +typedef union +{ + double value; + struct + { + unsigned int sign : 1; + unsigned int exponent: 11; + unsigned int fraction0:4; + unsigned int fraction1:16; + unsigned int fraction2:16; + unsigned int fraction3:16; + + } number; + struct + { + unsigned int sign : 1; + unsigned int exponent: 11; + unsigned int quiet:1; + unsigned int function0:3; + unsigned int function1:16; + unsigned int function2:16; + unsigned int function3:16; + } nan; + struct + { + unsigned long msw; + unsigned long lsw; + } parts; + long aslong[2]; +} __ieee_double_shape_type; + +#endif + +#ifdef __IEEE_LITTLE_ENDIAN + +typedef union +{ + double value; + struct + { +#ifdef __SMALL_BITFIELDS + unsigned int fraction3:16; + unsigned int fraction2:16; + unsigned int fraction1:16; + unsigned int fraction0: 4; +#else + unsigned int fraction1:32; + unsigned int fraction0:20; +#endif + unsigned int exponent :11; + unsigned int sign : 1; + } number; + struct + { +#ifdef __SMALL_BITFIELDS + unsigned int function3:16; + unsigned int function2:16; + unsigned int function1:16; + unsigned int function0:3; +#else + unsigned int function1:32; + unsigned int function0:19; +#endif + unsigned int quiet:1; + unsigned int exponent: 11; + unsigned int sign : 1; + } nan; + struct + { + unsigned long lsw; + unsigned long msw; + } parts; + + long aslong[2]; + +} __ieee_double_shape_type; + +#endif + +#ifdef __IEEE_BIG_ENDIAN +typedef union +{ + float value; + struct + { + unsigned int sign : 1; + unsigned int exponent: 8; + unsigned int fraction0: 7; + unsigned int fraction1: 16; + } number; + struct + { + unsigned int sign:1; + unsigned int exponent:8; + unsigned int quiet:1; + unsigned int function0:6; + unsigned int function1:16; + } nan; + long p1; + +} __ieee_float_shape_type; +#endif + +#ifdef __IEEE_LITTLE_ENDIAN +typedef union +{ + float value; + struct + { + unsigned int fraction0: 7; + unsigned int fraction1: 16; + unsigned int exponent: 8; + unsigned int sign : 1; + } number; + struct + { + unsigned int function1:16; + unsigned int function0:6; + unsigned int quiet:1; + unsigned int exponent:8; + unsigned int sign:1; + } nan; + long p1; + +} __ieee_float_shape_type; +#endif + + +double DEFUN(copysign, (x, y), double x AND double y) +{ + __ieee_double_shape_type a,b; + b.value = y; + a.value = x; + a.number.sign =b.number.sign; + return a.value; +} diff --git a/contrib/gdb/libiberty/cplus-dem.c b/contrib/gdb/libiberty/cplus-dem.c new file mode 100644 index 000000000000..a7f868022789 --- /dev/null +++ b/contrib/gdb/libiberty/cplus-dem.c @@ -0,0 +1,3019 @@ +/* Demangler for GNU C++ + Copyright 1989, 1991, 1994, 1995, 1996 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.uucp) + Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This file exports two functions; cplus_mangle_opname and cplus_demangle. + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +#include +#include +#include + +#include +#undef CURRENT_DEMANGLING_STYLE +#define CURRENT_DEMANGLING_STYLE work->options + +extern char *xmalloc PARAMS((unsigned)); +extern char *xrealloc PARAMS((char *, unsigned)); + +char * +mystrstr (s1, s2) + char *s1, *s2; +{ + register char *p = s1; + register int len = strlen (s2); + + for (; (p = strchr (p, *s2)) != 0; p++) + { + if (strncmp (p, s2, len) == 0) + { + return (p); + } + } + return (0); +} + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +#if !defined (CPLUS_MARKER) +#define CPLUS_MARKER '$' +#endif + +enum demangling_styles current_demangling_style = gnu_demangling; + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +void +set_cplus_marker_for_demangling (ch) + int ch; +{ + cplus_markers[0] = ch; +} + +/* Stuff that is shared between sub-routines. + * Using a shared structure allows cplus_demangle to be reentrant. */ + +struct work_stuff +{ + int options; + char **typevec; + int ntypes; + int typevec_size; + int constructor; + int destructor; + int static_type; /* A static member function */ + int const_type; /* A const member function */ +}; + +#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) + +static const struct optable +{ + const char *in; + const char *out; + int flags; +} optable[] = { + {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ + {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ + {"new", " new", 0}, /* old (1.91, and 1.x) */ + {"delete", " delete", 0}, /* old (1.91, and 1.x) */ + {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ + {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ + {"as", "=", DMGL_ANSI}, /* ansi */ + {"ne", "!=", DMGL_ANSI}, /* old, ansi */ + {"eq", "==", DMGL_ANSI}, /* old, ansi */ + {"ge", ">=", DMGL_ANSI}, /* old, ansi */ + {"gt", ">", DMGL_ANSI}, /* old, ansi */ + {"le", "<=", DMGL_ANSI}, /* old, ansi */ + {"lt", "<", DMGL_ANSI}, /* old, ansi */ + {"plus", "+", 0}, /* old */ + {"pl", "+", DMGL_ANSI}, /* ansi */ + {"apl", "+=", DMGL_ANSI}, /* ansi */ + {"minus", "-", 0}, /* old */ + {"mi", "-", DMGL_ANSI}, /* ansi */ + {"ami", "-=", DMGL_ANSI}, /* ansi */ + {"mult", "*", 0}, /* old */ + {"ml", "*", DMGL_ANSI}, /* ansi */ + {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ + {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ + {"convert", "+", 0}, /* old (unary +) */ + {"negate", "-", 0}, /* old (unary -) */ + {"trunc_mod", "%", 0}, /* old */ + {"md", "%", DMGL_ANSI}, /* ansi */ + {"amd", "%=", DMGL_ANSI}, /* ansi */ + {"trunc_div", "/", 0}, /* old */ + {"dv", "/", DMGL_ANSI}, /* ansi */ + {"adv", "/=", DMGL_ANSI}, /* ansi */ + {"truth_andif", "&&", 0}, /* old */ + {"aa", "&&", DMGL_ANSI}, /* ansi */ + {"truth_orif", "||", 0}, /* old */ + {"oo", "||", DMGL_ANSI}, /* ansi */ + {"truth_not", "!", 0}, /* old */ + {"nt", "!", DMGL_ANSI}, /* ansi */ + {"postincrement","++", 0}, /* old */ + {"pp", "++", DMGL_ANSI}, /* ansi */ + {"postdecrement","--", 0}, /* old */ + {"mm", "--", DMGL_ANSI}, /* ansi */ + {"bit_ior", "|", 0}, /* old */ + {"or", "|", DMGL_ANSI}, /* ansi */ + {"aor", "|=", DMGL_ANSI}, /* ansi */ + {"bit_xor", "^", 0}, /* old */ + {"er", "^", DMGL_ANSI}, /* ansi */ + {"aer", "^=", DMGL_ANSI}, /* ansi */ + {"bit_and", "&", 0}, /* old */ + {"ad", "&", DMGL_ANSI}, /* ansi */ + {"aad", "&=", DMGL_ANSI}, /* ansi */ + {"bit_not", "~", 0}, /* old */ + {"co", "~", DMGL_ANSI}, /* ansi */ + {"call", "()", 0}, /* old */ + {"cl", "()", DMGL_ANSI}, /* ansi */ + {"alshift", "<<", 0}, /* old */ + {"ls", "<<", DMGL_ANSI}, /* ansi */ + {"als", "<<=", DMGL_ANSI}, /* ansi */ + {"arshift", ">>", 0}, /* old */ + {"rs", ">>", DMGL_ANSI}, /* ansi */ + {"ars", ">>=", DMGL_ANSI}, /* ansi */ + {"component", "->", 0}, /* old */ + {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ + {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ + {"indirect", "*", 0}, /* old */ + {"method_call", "->()", 0}, /* old */ + {"addr", "&", 0}, /* old (unary &) */ + {"array", "[]", 0}, /* old */ + {"vc", "[]", DMGL_ANSI}, /* ansi */ + {"compound", ", ", 0}, /* old */ + {"cm", ", ", DMGL_ANSI}, /* ansi */ + {"cond", "?:", 0}, /* old */ + {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ + {"max", ">?", 0}, /* old */ + {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ + {"min", "*", DMGL_ANSI} /* ansi */ +}; + + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_prepend(str, " ");} +#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_append(str, " ");} + +#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ + +/* Prototypes for local functions */ + +static char * +mop_up PARAMS ((struct work_stuff *, string *, int)); + +#if 0 +static int +demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *)); +#endif + +static int +demangle_template PARAMS ((struct work_stuff *work, const char **, string *, + string *)); + +static int +demangle_qualified PARAMS ((struct work_stuff *, const char **, string *, + int, int)); + +static int +demangle_class PARAMS ((struct work_stuff *, const char **, string *)); + +static int +demangle_fund_type PARAMS ((struct work_stuff *, const char **, string *)); + +static int +demangle_signature PARAMS ((struct work_stuff *, const char **, string *)); + +static int +demangle_prefix PARAMS ((struct work_stuff *, const char **, string *)); + +static int +gnu_special PARAMS ((struct work_stuff *, const char **, string *)); + +static int +arm_special PARAMS ((struct work_stuff *, const char **, string *)); + +static void +string_need PARAMS ((string *, int)); + +static void +string_delete PARAMS ((string *)); + +static void +string_init PARAMS ((string *)); + +static void +string_clear PARAMS ((string *)); + +#if 0 +static int +string_empty PARAMS ((string *)); +#endif + +static void +string_append PARAMS ((string *, const char *)); + +static void +string_appends PARAMS ((string *, string *)); + +static void +string_appendn PARAMS ((string *, const char *, int)); + +static void +string_prepend PARAMS ((string *, const char *)); + +static void +string_prependn PARAMS ((string *, const char *, int)); + +static int +get_count PARAMS ((const char **, int *)); + +static int +consume_count PARAMS ((const char **)); + +static int +demangle_args PARAMS ((struct work_stuff *, const char **, string *)); + +static int +do_type PARAMS ((struct work_stuff *, const char **, string *)); + +static int +do_arg PARAMS ((struct work_stuff *, const char **, string *)); + +static void +demangle_function_name PARAMS ((struct work_stuff *, const char **, string *, + const char *)); + +static void +remember_type PARAMS ((struct work_stuff *, const char *, int)); + +static void +forget_types PARAMS ((struct work_stuff *)); + +static void +string_prepends PARAMS ((string *, string *)); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + Trying to consume something that isn't a count results in + no consumption of input and a return of 0. */ + +static int +consume_count (type) + const char **type; +{ + int count = 0; + + while (isdigit (**type)) + { + count *= 10; + count += **type - '0'; + (*type)++; + } + return (count); +} + +int +cplus_demangle_opname (opname, result, options) + const char *opname; + char *result; + int options; +{ + int len, i, len1, ret; + string type; + struct work_stuff work[1]; + const char *tem; + + len = strlen(opname); + result[0] = '\0'; + ret = 0; + work->options = options; + + if (opname[0] == '_' && opname[1] == '_' + && opname[2] == 'o' && opname[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = opname + 4; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + else if (opname[0] == '_' && opname[1] == '_' + && opname[2] >= 'a' && opname[2] <= 'z' + && opname[3] >= 'a' && opname[3] <= 'z') + { + if (opname[4] == '\0') + { + /* Operator. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, opname + 2, 2) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + else + { + if (opname[2] == 'a' && opname[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, opname + 2, 3) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + } + else if (len >= 3 + && opname[0] == 'o' + && opname[1] == 'p' + && strchr (cplus_markers, opname[2]) != NULL) + { + /* see if it's an assignment expression */ + if (len >= 10 /* op$assign_ */ + && memcmp (opname + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + len1 = len - 10; + if (strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 10, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + strcat (result, "="); + ret = 1; + break; + } + } + } + else + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + len1 = len - 3; + if (strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 3, len1) == 0) + { + strcat (result, "operator"); + strcat (result, optable[i].out); + ret = 1; + break; + } + } + } + } + else if (len >= 5 && memcmp (opname, "type", 4) == 0 + && strchr (cplus_markers, opname[4]) != NULL) + { + /* type conversion operator */ + tem = opname + 5; + if (do_type (work, &tem, &type)) + { + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + ret = 1; + } + } + return ret; + +} +/* Takes operator name as e.g. "++" and returns mangled + operator name (e.g. "postincrement_expr"), or NULL if not found. + + If OPTIONS & DMGL_ANSI == 1, return the ANSI name; + if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ + +const char * +cplus_mangle_opname (opname, options) + const char *opname; + int options; +{ + int i; + int len; + + len = strlen (opname); + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].out) == len + && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) + && memcmp (optable[i].out, opname, len) == 0) + return optable[i].in; + } + return (0); +} + +/* check to see whether MANGLED can match TEXT in the first TEXT_LEN + characters. */ + +int cplus_match (mangled, text, text_len) + const char *mangled; + char *text; + int text_len; +{ + if (strncmp (mangled, text, text_len) != 0) { + return(0); /* cannot match either */ + } else { + return(1); /* matches mangled, may match demangled */ + } +} + +/* char *cplus_demangle (const char *mangled, int options) + + If MANGLED is a mangled function name produced by GNU C++, then + a pointer to a malloced string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + The OPTIONS arg may contain one or more of the following bits: + + DMGL_ANSI ANSI qualifiers such as `const' and `void' are + included. + DMGL_PARAMS Function parameters are included. + + For example, + + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" + cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 0) => "A::foo" + + cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 0) => "A::foo" + + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + MANGLED. */ + +char * +cplus_demangle (mangled, options) + const char *mangled; + int options; +{ + string decl; + int success = 0; + struct work_stuff work[1]; + char *demangled = NULL; + + if ((mangled != NULL) && (*mangled != '\0')) + { + memset ((char *) work, 0, sizeof (work)); + work -> options = options; + if ((work->options & DMGL_STYLE_MASK) == 0) + work->options |= (int)current_demangling_style & DMGL_STYLE_MASK; + + string_init (&decl); + + /* First check to see if gnu style demangling is active and if the + string to be demangled contains a CPLUS_MARKER. If so, attempt to + recognize one of the gnu special forms rather than looking for a + standard prefix. In particular, don't worry about whether there + is a "__" string in the mangled string. Consider "_$_5__foo" for + example. */ + + if ((AUTO_DEMANGLING || GNU_DEMANGLING)) + { + success = gnu_special (work, &mangled, &decl); + } + if (!success) + { + success = demangle_prefix (work, &mangled, &decl); + } + if (success && (*mangled != '\0')) + { + success = demangle_signature (work, &mangled, &decl); + } + if (work->constructor == 2) + { + string_prepend(&decl, "global constructors keyed to "); + work->constructor = 0; + } + else if (work->destructor == 2) + { + string_prepend(&decl, "global destructors keyed to "); + work->destructor = 0; + } + demangled = mop_up (work, &decl, success); + } + return (demangled); +} + +static char * +mop_up (work, declp, success) + struct work_stuff *work; + string *declp; + int success; +{ + char *demangled = NULL; + + /* Discard the remembered types, if any. */ + + forget_types (work); + if (work -> typevec != NULL) + { + free ((char *) work -> typevec); + } + + /* If demangling was successful, ensure that the demangled string is null + terminated and return it. Otherwise, free the demangling decl. */ + + if (!success) + { + string_delete (declp); + } + else + { + string_appendn (declp, "", 1); + demangled = declp -> b; + } + return (demangled); +} + +/* + +LOCAL FUNCTION + + demangle_signature -- demangle the signature part of a mangled name + +SYNOPSIS + + static int + demangle_signature (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the signature portion of the mangled name. + + DECLP is the string where demangled output is being built. At + entry it contains the demangled root name from the mangled name + prefix. I.E. either a demangled operator name or the root function + name. In some special cases, it may contain nothing. + + *MANGLED points to the current unconsumed location in the mangled + name. As tokens are consumed and demangling is performed, the + pointer is updated to continuously point at the next token to + be consumed. + + Demangling GNU style mangled names is nasty because there is no + explicit token that marks the start of the outermost function + argument list. +*/ + +static int +demangle_signature (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int success = 1; + int func_done = 0; + int expect_func = 0; + const char *oldmangled = NULL; + string trawname; + string tname; + + while (success && (**mangled != '\0')) + { + switch (**mangled) + { + case 'Q': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'S': + /* Static member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> static_type = 1; + break; + + case 'C': + /* a const member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> const_type = 1; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_class (work, mangled, declp); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'F': + /* Function */ + /* ARM style demangling includes a specific 'F' character after + the class name. For GNU style, it is just implied. So we can + safely just consume any 'F' at this point and be compatible + with either style. */ + + oldmangled = NULL; + func_done = 1; + (*mangled)++; + + /* For lucid/ARM style we have to forget any types we might + have remembered up to this point, since they were not argument + types. GNU style considers all types seen as available for + back references. See comment in demangle_args() */ + + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + break; + + case 't': + /* G++ Template */ + string_init(&trawname); + string_init(&tname); + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_template (work, mangled, &tname, &trawname); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + string_append(&tname, "::"); + string_prepends(declp, &tname); + if (work -> destructor & 1) + { + string_prepend (&trawname, "~"); + string_appends (declp, &trawname); + work->destructor -= 1; + } + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_appends (declp, &trawname); + work->constructor -= 1; + } + string_delete(&trawname); + string_delete(&tname); + oldmangled = NULL; + expect_func = 1; + break; + + case '_': + /* At the outermost level, we cannot have a return type specified, + so if we run into another '_' at this point we are dealing with + a mangled name that is either bogus, or has been mangled by + some algorithm we don't know how to deal with. So just + reject the entire demangling. */ + success = 0; + break; + + default: + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = 1; + success = demangle_args (work, mangled, declp); + } + else + { + /* Non-GNU demanglers use a specific token to mark the start + of the outermost function argument tokens. Typically 'F', + for ARM-demangling, for example. So if we find something + we are not prepared for, it must be an error. */ + success = 0; + } + break; + } +/* + if (AUTO_DEMANGLING || GNU_DEMANGLING) +*/ + { + if (success && expect_func) + { + func_done = 1; + success = demangle_args (work, mangled, declp); + } + } + } + if (success && !func_done) + { + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added to + the current declp. Note that with ARM, the first case + represents the name of a static data member 'foo::bar', + which is in the current declp, so we leave it alone. */ + success = demangle_args (work, mangled, declp); + } + } + if (success && work -> static_type && PRINT_ARG_TYPES) + { + string_append (declp, " static"); + } + if (success && work -> const_type && PRINT_ARG_TYPES) + { + string_append (declp, " const"); + } + return (success); +} + +#if 0 + +static int +demangle_method_args (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int success = 0; + + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + return (success); +} + +#endif + +static int +demangle_template (work, mangled, tname, trawname) + struct work_stuff *work; + const char **mangled; + string *tname; + string *trawname; +{ + int i; + int is_pointer; + int is_real; + int is_integral; + int is_char; + int is_bool; + int r; + int need_comma = 0; + int success = 0; + int done; + const char *old_p; + const char *start; + int symbol_len; + string temp; + + (*mangled)++; + start = *mangled; + /* get template name */ + if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r) + { + return (0); + } + if (trawname) + string_appendn (trawname, *mangled, r); + string_appendn (tname, *mangled, r); + *mangled += r; + string_append (tname, "<"); + /* get size of template parameter list */ + if (!get_count (mangled, &r)) + { + return (0); + } + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + else + { + /* otherwise, value parameter */ + old_p = *mangled; + is_pointer = 0; + is_real = 0; + is_integral = 0; + is_char = 0; + is_bool = 0; + done = 0; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); +/* + if (success) + { + string_appends (tname, &temp); + } +*/ + string_delete(&temp); + if (!success) + { + break; + } +/* + string_append (tname, "="); +*/ + while (*old_p && !done) + { + switch (*old_p) + { + case 'P': + case 'p': + case 'R': + done = is_pointer = 1; + break; + case 'C': /* const */ + case 'S': /* explicitly signed [char] */ + case 'U': /* unsigned */ + case 'V': /* volatile */ + case 'F': /* function */ + case 'M': /* member function */ + case 'O': /* ??? */ + old_p++; + continue; + case 'Q': /* qualified name */ + done = is_integral = 1; + break; + case 'T': /* remembered type */ + abort (); + break; + case 'v': /* void */ + abort (); + break; + case 'x': /* long long */ + case 'l': /* long */ + case 'i': /* int */ + case 's': /* short */ + case 'w': /* wchar_t */ + done = is_integral = 1; + break; + case 'b': /* bool */ + done = is_bool = 1; + break; + case 'c': /* char */ + done = is_char = 1; + break; + case 'r': /* long double */ + case 'd': /* double */ + case 'f': /* float */ + done = is_real = 1; + break; + default: + /* it's probably user defined type, let's assume + it's integral, it seems hard to figure out + what it really is */ + done = is_integral = 1; + } + } + if (is_integral) + { + if (**mangled == 'm') + { + string_appendn (tname, "-", 1); + (*mangled)++; + } + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + else if (is_char) + { + char tmp[2]; + int val; + if (**mangled == 'm') + { + string_appendn (tname, "-", 1); + (*mangled)++; + } + string_appendn (tname, "'", 1); + val = consume_count(mangled); + if (val == 0) + { + success = 0; + break; + } + tmp[0] = (char)val; + tmp[1] = '\0'; + string_appendn (tname, &tmp[0], 1); + string_appendn (tname, "'", 1); + } + else if (is_bool) + { + int val = consume_count (mangled); + if (val == 0) + string_appendn (tname, "false", 5); + else if (val == 1) + string_appendn (tname, "true", 4); + else + success = 0; + } + else if (is_real) + { + if (**mangled == 'm') + { + string_appendn (tname, "-", 1); + (*mangled)++; + } + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (tname, ".", 1); + (*mangled)++; + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (tname, "e", 1); + (*mangled)++; + while (isdigit (**mangled)) + { + string_appendn (tname, *mangled, 1); + (*mangled)++; + } + } + } + else if (is_pointer) + { + if (!get_count (mangled, &symbol_len)) + { + success = 0; + break; + } + if (symbol_len == 0) + string_appendn (tname, "0", 1); + else + { + char *p = xmalloc (symbol_len + 1), *q; + strncpy (p, *mangled, symbol_len); + p [symbol_len] = '\0'; + q = cplus_demangle (p, work->options); + string_appendn (tname, "&", 1); + if (q) + { + string_append (tname, q); + free (q); + } + else + string_append (tname, p); + free (p); + } + *mangled += symbol_len; + } + } + need_comma = 1; + } + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, ">"); + +/* + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + } +*/ + return (success); +} + +static int +arm_pt (work, mangled, n, anchor, args) + struct work_stuff *work; + const char *mangled; + int n; + const char **anchor, **args; +{ + /* ARM template? */ + if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + return 0; +} + +static void +demangle_arm_pt (work, mangled, n, declp) + struct work_stuff *work; + const char **mangled; + int n; + string *declp; +{ + const char *p; + const char *args; + const char *e = *mangled + n; + + /* ARM template? */ + if (arm_pt (work, *mangled, n, &p, &args)) + { + string arg; + string_init (&arg); + string_appendn (declp, *mangled, p - *mangled); + string_append (declp, "<"); + /* should do error checking here */ + while (args < e) { + string_clear (&arg); + do_type (work, &args, &arg); + string_appends (declp, &arg); + string_append (declp, ","); + } + string_delete (&arg); + --declp->p; + string_append (declp, ">"); + } + else + { + string_appendn (declp, *mangled, n); + } + *mangled += n; +} + +static int +demangle_class_name (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int n; + int success = 0; + + n = consume_count (mangled); + if (strlen (*mangled) >= n) + { + demangle_arm_pt (work, mangled, n, declp); + success = 1; + } + + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_class -- demangle a mangled class sequence + +SYNOPSIS + + static int + demangle_class (struct work_stuff *work, const char **mangled, + strint *declp) + +DESCRIPTION + + DECLP points to the buffer into which demangling is being done. + + *MANGLED points to the current token to be demangled. On input, + it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) + On exit, it points to the next token after the mangled class on + success, or the first unconsumed token on failure. + + If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then + we are demangling a constructor or destructor. In this case + we prepend "class::class" or "class::~class" to DECLP. + + Otherwise, we prepend "class::" to the current DECLP. + + Reset the constructor/destructor flags once they have been + "consumed". This allows demangle_class to be called later during + the same demangling, to do normal class demangling. + + Returns 1 if demangling is successful, 0 otherwise. + +*/ + +static int +demangle_class (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int success = 0; + string class_name; + + string_init (&class_name); + if (demangle_class_name (work, mangled, &class_name)) + { + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_prepends (declp, &class_name); + if (work -> destructor & 1) + { + string_prepend (declp, "~"); + work -> destructor -= 1; + } + else + { + work -> constructor -= 1; + } + } + string_prepend (declp, "::"); + string_prepends (declp, &class_name); + success = 1; + } + string_delete (&class_name); + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_prefix -- consume the mangled name prefix and find signature + +SYNOPSIS + + static int + demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the prefix of the mangled name. + + DECLP points to the string buffer into which demangled output is + placed. On entry, the buffer is empty. On exit it contains + the root function name, the demangled operator name, or in some + special cases either nothing or the completely demangled result. + + MANGLED points to the current pointer into the mangled name. As each + token of the mangled name is consumed, it is updated. Upon entry + the current mangled name pointer points to the first character of + the mangled name. Upon exit, it should point to the first character + of the signature if demangling was successful, or to the first + unconsumed character if demangling of the prefix was unsuccessful. + + Returns 1 on success, 0 otherwise. + */ + +static int +demangle_prefix (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int success = 1; + const char *scan; + int i; + + if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) + { + char *marker = strchr (cplus_markers, (*mangled)[8]); + if (marker != NULL && *marker == (*mangled)[10]) + { + if ((*mangled)[9] == 'D') + { + /* it's a GNU global destructor to be executed at program exit */ + (*mangled) += 11; + work->destructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + else if ((*mangled)[9] == 'I') + { + /* it's a GNU global constructor to be executed at program init */ + (*mangled) += 11; + work->constructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + } + } + else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0) + { + /* it's a ARM global destructor to be executed at program exit */ + (*mangled) += 7; + work->destructor = 2; + } + else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0) + { + /* it's a ARM global constructor to be executed at program initial */ + (*mangled) += 7; + work->constructor = 2; + } + +/* This block of code is a reduction in strength time optimization + of: + scan = mystrstr (*mangled, "__"); */ + + { + scan = *mangled; + + do { + scan = strchr (scan, '_'); + } while (scan != NULL && *++scan != '_'); + + if (scan != NULL) --scan; + } + + if (scan != NULL) + { + /* We found a sequence of two or more '_', ensure that we start at + the last pair in the sequence. */ + i = strspn (scan, "_"); + if (i > 2) + { + scan += (i - 2); + } + } + + if (scan == NULL) + { + success = 0; + } + else if (work -> static_type) + { + if (!isdigit (scan[0]) && (scan[0] != 't')) + { + success = 0; + } + } + else if ((scan == *mangled) && + (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't'))) + { + /* The ARM says nothing about the mangling of local variables. + But cfront mangles local variables by prepending __ + to them. As an extension to ARM demangling we handle this case. */ + if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2])) + { + *mangled = scan + 2; + consume_count (mangled); + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + else + { + /* A GNU style constructor starts with __[0-9Qt]. But cfront uses + names like __Q2_3foo3bar for nested type names. So don't accept + this style of constructor for cfront demangling. */ + if (!(LUCID_DEMANGLING || ARM_DEMANGLING)) + work -> constructor += 1; + *mangled = scan + 2; + } + } + else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't')) + { + /* Mangled name starts with "__". Skip over any leading '_' characters, + then find the next "__" that separates the prefix from the signature. + */ + if (!(ARM_DEMANGLING || LUCID_DEMANGLING) + || (arm_special (work, mangled, declp) == 0)) + { + while (*scan == '_') + { + scan++; + } + if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) + { + /* No separator (I.E. "__not_mangled"), or empty signature + (I.E. "__not_mangled_either__") */ + success = 0; + } + else + { + demangle_function_name (work, mangled, declp, scan); + } + } + } + else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') + { + /* Cfront-style parameterized type. Handled later as a signature. */ + success = 1; + + /* ARM template? */ + demangle_arm_pt (work, mangled, strlen (*mangled), declp); + } + else if (*(scan + 2) != '\0') + { + /* Mangled name does not start with "__" but does have one somewhere + in there with non empty stuff after it. Looks like a global + function name. */ + demangle_function_name (work, mangled, declp, scan); + } + else + { + /* Doesn't look like a mangled name */ + success = 0; + } + + if (!success && (work->constructor == 2 || work->destructor == 2)) + { + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + gnu_special -- special handling of gnu mangled strings + +SYNOPSIS + + static int + gnu_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special GNU style mangling forms that don't fit + the normal pattern. For example: + + _$_3foo (destructor for class foo) + _vt$foo (foo virtual table) + _vt$foo$bar (foo::bar virtual table) + __vt_foo (foo virtual table, new style with thunks) + _3foo$varname (static data member) + _Q22rs2tu$vw (static data member) + __t6vector1Zii (constructor with template) + __thunk_4__$_7ostream (virtual function thunk) + */ + +static int +gnu_special (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int n; + int success = 1; + const char *p; + + if ((*mangled)[0] == '_' + && strchr (cplus_markers, (*mangled)[1]) != NULL + && (*mangled)[2] == '_') + { + /* Found a GNU style destructor, get past "__" */ + (*mangled) += 3; + work -> destructor += 1; + } + else if ((*mangled)[0] == '_' + && (((*mangled)[1] == '_' + && (*mangled)[2] == 'v' + && (*mangled)[3] == 't' + && (*mangled)[4] == '_') + || ((*mangled)[1] == 'v' + && (*mangled)[2] == 't' + && strchr (cplus_markers, (*mangled)[3]) != NULL))) + { + /* Found a GNU style virtual table, get past "_vt" + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + if ((*mangled)[2] == 'v') + (*mangled) += 5; /* New style, with thunks: "__vt_" */ + else + (*mangled) += 4; /* Old style, no thunks: "_vt" */ + while (**mangled != '\0') + { + p = strpbrk (*mangled, cplus_markers); + switch (**mangled) + { + case 'Q': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0); + break; + default: + if (isdigit(*mangled[0])) + { + n = consume_count(mangled); + } + else + { + n = strcspn (*mangled, cplus_markers); + } + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + + if (success && ((p == NULL) || (p == *mangled))) + { + if (p != NULL) + { + string_append (declp, "::"); + (*mangled)++; + } + } + else + { + success = 0; + break; + } + } + if (success) + string_append (declp, " virtual table"); + } + else if ((*mangled)[0] == '_' + && (strchr("0123456789Qt", (*mangled)[1]) != NULL) + && (p = strpbrk (*mangled, cplus_markers)) != NULL) + { + /* static data member, "_3foo$varname" for example */ + (*mangled)++; + switch (**mangled) + { + case 'Q': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0); + break; + default: + n = consume_count (mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + if (success && (p == *mangled)) + { + /* Consumed everything up to the cplus_marker, append the + variable name. */ + (*mangled)++; + string_append (declp, "::"); + n = strlen (*mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + else + { + success = 0; + } + } + else if (strncmp (*mangled, "__thunk_", 8) == 0) + { + int delta = ((*mangled) += 8, consume_count (mangled)); + char *method = cplus_demangle (++*mangled, work->options); + if (method) + { + char buf[50]; + sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); + string_append (declp, buf); + string_append (declp, method); + free (method); + n = strlen (*mangled); + (*mangled) += n; + } + else + { + success = 0; + } + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + arm_special -- special handling of ARM/lucid mangled strings + +SYNOPSIS + + static int + arm_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special ARM style mangling forms that don't fit + the normal pattern. For example: + + __vtbl__3foo (foo virtual table) + __vtbl__3foo__3bar (bar::foo virtual table) + + */ + +static int +arm_special (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + int n; + int success = 1; + const char *scan; + + if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) + { + /* Found a ARM style virtual table, get past ARM_VTABLE_STRING + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + scan = *mangled + ARM_VTABLE_STRLEN; + while (*scan != '\0') /* first check it can be demangled */ + { + n = consume_count (&scan); + if (n==0) + { + return (0); /* no good */ + } + scan += n; + if (scan[0] == '_' && scan[1] == '_') + { + scan += 2; + } + } + (*mangled) += ARM_VTABLE_STRLEN; + while (**mangled != '\0') + { + n = consume_count (mangled); + string_prependn (declp, *mangled, n); + (*mangled) += n; + if ((*mangled)[0] == '_' && (*mangled)[1] == '_') + { + string_prepend (declp, "::"); + (*mangled) += 2; + } + } + string_append (declp, " virtual table"); + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_qualified -- demangle 'Q' qualified name strings + +SYNOPSIS + + static int + demangle_qualified (struct work_stuff *, const char *mangled, + string *result, int isfuncname, int append); + +DESCRIPTION + + Demangle a qualified name, such as "Q25Outer5Inner" which is + the mangled form of "Outer::Inner". The demangled output is + prepended or appended to the result string according to the + state of the append flag. + + If isfuncname is nonzero, then the qualified name we are building + is going to be used as a member function name, so if it is a + constructor or destructor function, append an appropriate + constructor or destructor name. I.E. for the above example, + the result for use as a constructor is "Outer::Inner::Inner" + and the result for use as a destructor is "Outer::Inner::~Inner". + +BUGS + + Numeric conversion is ASCII dependent (FIXME). + + */ + +static int +demangle_qualified (work, mangled, result, isfuncname, append) + struct work_stuff *work; + const char **mangled; + string *result; + int isfuncname; + int append; +{ + int qualifiers; + int namelength; + int success = 1; + const char *p; + char num[2]; + string temp; + + string_init (&temp); + switch ((*mangled)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is preceded + by an underscore (to distinguish it from the <= 9 case) and followed + by an underscore. */ + p = *mangled + 2; + qualifiers = atoi (p); + if (!isdigit (*p) || *p == '0') + success = 0; + + /* Skip the digits. */ + while (isdigit (*p)) + ++p; + + if (*p != '_') + success = 0; + + *mangled = p + 1; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* The count is in a single digit. */ + num[0] = (*mangled)[1]; + num[1] = '\0'; + qualifiers = atoi (num); + + /* If there is an underscore after the digit, skip it. This is + said to be for ARM-qualified names, but the ARM makes no + mention of such an underscore. Perhaps cfront uses one. */ + if ((*mangled)[2] == '_') + { + (*mangled)++; + } + (*mangled) += 2; + break; + + case '0': + default: + success = 0; + } + + if (!success) + return success; + + /* Pick off the names and collect them in the temp buffer in the order + in which they are found, separated by '::'. */ + + while (qualifiers-- > 0) + { + if (*mangled[0] == '_') + *mangled = *mangled + 1; + if (*mangled[0] == 't') + { + success = demangle_template(work, mangled, &temp, 0); + if (!success) break; + } + else + { + namelength = consume_count (mangled); + if (strlen (*mangled) < namelength) + { + /* Simple sanity check failed */ + success = 0; + break; + } + string_appendn (&temp, *mangled, namelength); + *mangled += namelength; + } + if (qualifiers > 0) + { + string_appendn (&temp, "::", 2); + } + } + + /* If we are using the result as a function name, we need to append + the appropriate '::' separated constructor or destructor name. + We do this here because this is the most convenient place, where + we already have a pointer to the name and the length of the name. */ + + if (isfuncname && (work->constructor & 1 || work->destructor & 1)) + { + string_appendn (&temp, "::", 2); + if (work -> destructor & 1) + { + string_append (&temp, "~"); + } + string_appendn (&temp, (*mangled) - namelength, namelength); + } + + /* Now either prepend the temp buffer to the result, or append it, + depending upon the state of the append flag. */ + + if (append) + { + string_appends (result, &temp); + } + else + { + if (!STRING_EMPTY (result)) + { + string_appendn (&temp, "::", 2); + } + string_prepends (result, &temp); + } + + string_delete (&temp); + return (success); +} + +/* + +LOCAL FUNCTION + + get_count -- convert an ascii count to integer, consuming tokens + +SYNOPSIS + + static int + get_count (const char **type, int *count) + +DESCRIPTION + + Return 0 if no conversion is performed, 1 if a string is converted. +*/ + +static int +get_count (type, count) + const char **type; + int *count; +{ + const char *p; + int n; + + if (!isdigit (**type)) + { + return (0); + } + else + { + *count = **type - '0'; + (*type)++; + if (isdigit (**type)) + { + p = *type; + n = *count; + do + { + n *= 10; + n += *p - '0'; + p++; + } + while (isdigit (*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + } + return (1); +} + +/* result will be initialised here; it will be freed on failure */ + +static int +do_type (work, mangled, result) + struct work_stuff *work; + const char **mangled; + string *result; +{ + int n; + int done; + int success; + string decl; + const char *remembered_type; + int constp; + int volatilep; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**mangled) + { + + /* A pointer type */ + case 'P': + case 'p': + (*mangled)++; + string_prepend (&decl, "*"); + break; + + /* A reference type */ + case 'R': + (*mangled)++; + string_prepend (&decl, "&"); + break; + + /* An array */ + case 'A': + { + const char *p = ++(*mangled); + + string_prepend (&decl, "("); + string_append (&decl, ")["); + /* Copy anything up until the next underscore (the size of the + array). */ + while (**mangled && **mangled != '_') + ++(*mangled); + if (**mangled == '_') + { + string_appendn (&decl, p, *mangled - p); + string_append (&decl, "]"); + *mangled += 1; + } + else + success = 0; + break; + } + + /* A back reference to a previously seen type */ + case 'T': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> ntypes) + { + success = 0; + } + else + { + remembered_type = work -> typevec[n]; + mangled = &remembered_type; + } + break; + + /* A function */ + case 'F': + (*mangled)++; + if (!STRING_EMPTY (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + /* After picking off the function args, we expect to either find the + function return type (preceded by an '_') or the end of the + string. */ + if (!demangle_args (work, mangled, &decl) + || (**mangled != '_' && **mangled != '\0')) + { + success = 0; + } + if (success && (**mangled == '_')) + { + (*mangled)++; + } + break; + + case 'M': + case 'O': + { + constp = 0; + volatilep = 0; + + member = **mangled == 'M'; + (*mangled)++; + if (!isdigit (**mangled)) + { + success = 0; + break; + } + n = consume_count (mangled); + if (strlen (*mangled) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *mangled, n); + string_prepend (&decl, "("); + *mangled += n; + if (member) + { + if (**mangled == 'C') + { + (*mangled)++; + constp = 1; + } + if (**mangled == 'V') + { + (*mangled)++; + volatilep = 1; + } + if (*(*mangled)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !demangle_args (work, mangled, &decl)) + || **mangled != '_') + { + success = 0; + break; + } + (*mangled)++; + if (! PRINT_ANSI_QUALIFIERS) + { + break; + } + if (constp) + { + APPEND_BLANK (&decl); + string_append (&decl, "const"); + } + if (volatilep) + { + APPEND_BLANK (&decl); + string_append (&decl, "volatile"); + } + break; + } + case 'G': + (*mangled)++; + break; + + case 'C': + (*mangled)++; +/* + if ((*mangled)[1] == 'P') + { +*/ + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (&decl)) + { + string_prepend (&decl, " "); + } + string_prepend (&decl, "const"); + } + break; +/* + } +*/ + + /* fall through */ + default: + done = 1; + break; + } + } + + switch (**mangled) + { + /* A qualified name, such as "Outer::Inner". */ + case 'Q': + success = demangle_qualified (work, mangled, result, 0, 1); + break; + + default: + success = demangle_fund_type (work, mangled, result); + break; + } + + if (success) + { + if (!STRING_EMPTY (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + } + else + { + string_delete (result); + } + string_delete (&decl); + return (success); +} + +/* Given a pointer to a type string that represents a fundamental type + argument (int, long, unsigned int, etc) in TYPE, a pointer to the + string in which the demangled output is being built in RESULT, and + the WORK structure, decode the types and add them to the result. + + For example: + + "Ci" => "const int" + "Sl" => "signed long" + "CUs" => "const unsigned short" + + */ + +static int +demangle_fund_type (work, mangled, result) + struct work_stuff *work; + const char **mangled; + string *result; +{ + int done = 0; + int success = 1; + + /* First pick off any type qualifiers. There can be more than one. */ + + while (!done) + { + switch (**mangled) + { + case 'C': + (*mangled)++; + if (PRINT_ANSI_QUALIFIERS) + { + APPEND_BLANK (result); + string_append (result, "const"); + } + break; + case 'U': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "unsigned"); + break; + case 'S': /* signed char only */ + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "signed"); + break; + case 'V': + (*mangled)++; + if (PRINT_ANSI_QUALIFIERS) + { + APPEND_BLANK (result); + string_append (result, "volatile"); + } + break; + default: + done = 1; + break; + } + } + + /* Now pick off the fundamental type. There can be only one. */ + + switch (**mangled) + { + case '\0': + case '_': + break; + case 'v': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "void"); + break; + case 'x': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long long"); + break; + case 'l': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long"); + break; + case 'i': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "int"); + break; + case 's': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "short"); + break; + case 'b': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "bool"); + break; + case 'c': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "char"); + break; + case 'w': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "wchar_t"); + break; + case 'r': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long double"); + break; + case 'd': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "double"); + break; + case 'f': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "float"); + break; + case 'G': + (*mangled)++; + if (!isdigit (**mangled)) + { + success = 0; + break; + } + /* fall through */ + /* An explicit type, such as "6mytype" or "7integer" */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + APPEND_BLANK (result); + if (!demangle_class_name (work, mangled, result)) { + --result->p; + success = 0; + } + break; + case 't': + success = demangle_template(work,mangled, result, 0); + break; + default: + success = 0; + break; + } + + return (success); +} + +/* `result' will be initialized in do_type; it will be freed on failure */ + +static int +do_arg (work, mangled, result) + struct work_stuff *work; + const char **mangled; + string *result; +{ + const char *start = *mangled; + + if (!do_type (work, mangled, result)) + { + return (0); + } + else + { + remember_type (work, start, *mangled - start); + return (1); + } +} + +static void +remember_type (work, start, len) + struct work_stuff *work; + const char *start; + int len; +{ + char *tem; + + if (work -> ntypes >= work -> typevec_size) + { + if (work -> typevec_size == 0) + { + work -> typevec_size = 3; + work -> typevec = + (char **) xmalloc (sizeof (char *) * work -> typevec_size); + } + else + { + work -> typevec_size *= 2; + work -> typevec = + (char **) xrealloc ((char *)work -> typevec, + sizeof (char *) * work -> typevec_size); + } + } + tem = xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> typevec[work -> ntypes++] = tem; +} + +/* Forget the remembered types, but not the type vector itself. */ + +static void +forget_types (work) + struct work_stuff *work; +{ + int i; + + while (work -> ntypes > 0) + { + i = --(work -> ntypes); + if (work -> typevec[i] != NULL) + { + free (work -> typevec[i]); + work -> typevec[i] = NULL; + } + } +} + +/* Process the argument list part of the signature, after any class spec + has been consumed, as well as the first 'F' character (if any). For + example: + + "__als__3fooRT0" => process "RT0" + "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" + + DECLP must be already initialised, usually non-empty. It won't be freed + on failure. + + Note that g++ differs significantly from ARM and lucid style mangling + with regards to references to previously seen types. For example, given + the source fragment: + + class foo { + public: + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); + }; + + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + + g++ produces the names: + + __3fooiRT0iT2iT2 + foo__FiR3fooiT1iT1 + + while lcc (and presumably other ARM style compilers as well) produces: + + foo__FiR3fooT1T2T1T2 + __ct__3fooFiR3fooT1T2T1T2 + + Note that g++ bases it's type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases it's type numbers starting + at one and only considers types after it has seen the 'F' character + indicating the start of the function args. For lucid/ARM style, we + account for this difference by discarding any previously seen types when + we see the 'F' character, and subtracting one from the type number + reference. + + */ + +static int +demangle_args (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + string arg; + int need_comma = 0; + int r; + int t; + const char *tem; + char temptype; + + if (PRINT_ARG_TYPES) + { + string_append (declp, "("); + if (**mangled == '\0') + { + string_append (declp, "void"); + } + } + + while (**mangled != '_' && **mangled != '\0' && **mangled != 'e') + { + if ((**mangled == 'N') || (**mangled == 'T')) + { + temptype = *(*mangled)++; + + if (temptype == 'N') + { + if (!get_count (mangled, &r)) + { + return (0); + } + } + else + { + r = 1; + } + if (ARM_DEMANGLING && work -> ntypes >= 10) + { + /* If we have 10 or more types we might have more than a 1 digit + index so we'll have to consume the whole count here. This + will lose if the next thing is a type name preceded by a + count but it's impossible to demangle that case properly + anyway. Eg if we already have 12 types is T12Pc "(..., type1, + Pc, ...)" or "(..., type12, char *, ...)" */ + if ((t = consume_count(mangled)) == 0) + { + return (0); + } + } + else + { + if (!get_count (mangled, &t)) + { + return (0); + } + } + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + t--; + } + /* Validate the type index. Protect against illegal indices from + malformed type strings. */ + if ((t < 0) || (t >= work -> ntypes)) + { + return (0); + } + while (--r >= 0) + { + tem = work -> typevec[t]; + if (need_comma && PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, &tem, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma & PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + if (!do_arg (work, mangled, &arg)) + { + return (0); + } + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + + if (**mangled == 'e') + { + (*mangled)++; + if (PRINT_ARG_TYPES) + { + if (need_comma) + { + string_append (declp, ","); + } + string_append (declp, "..."); + } + } + + if (PRINT_ARG_TYPES) + { + string_append (declp, ")"); + } + return (1); +} + +static void +demangle_function_name (work, mangled, declp, scan) + struct work_stuff *work; + const char **mangled; + string *declp; + const char *scan; +{ + int i; + int len; + string type; + const char *tem; + + string_appendn (declp, (*mangled), scan - (*mangled)); + string_need (declp, 1); + *(declp -> p) = '\0'; + + /* Consume the function name, including the "__" separating the name + from the signature. We are guaranteed that SCAN points to the + separator. */ + + (*mangled) = scan + 2; + + if (LUCID_DEMANGLING || ARM_DEMANGLING) + { + + /* See if we have an ARM style constructor or destructor operator. + If so, then just record it, clear the decl, and return. + We can't build the actual constructor/destructor decl until later, + when we recover the class name from the signature. */ + + if (strcmp (declp -> b, "__ct") == 0) + { + work -> constructor += 1; + string_clear (declp); + return; + } + else if (strcmp (declp -> b, "__dt") == 0) + { + work -> destructor += 1; + string_clear (declp); + return; + } + } + + if (declp->p - declp->b >= 3 + && declp->b[0] == 'o' + && declp->b[1] == 'p' + && strchr (cplus_markers, declp->b[2]) != NULL) + { + /* see if it's an assignment expression */ + if (declp->p - declp->b >= 10 /* op$assign_ */ + && memcmp (declp->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + len = declp->p - declp->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 10, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + string_append (declp, "="); + break; + } + } + } + else + { + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + int len = declp->p - declp->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 3, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 + && strchr (cplus_markers, declp->b[4]) != NULL) + { + /* type conversion operator */ + tem = declp->b + 5; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] == 'o' && declp->b[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = declp->b + 4; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] >= 'a' && declp->b[2] <= 'z' + && declp->b[3] >= 'a' && declp->b[3] <= 'z') + { + if (declp->b[4] == '\0') + { + /* Operator. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, declp->b + 2, 2) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + else + { + if (declp->b[2] == 'a' && declp->b[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, declp->b + 2, 3) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + } +} + +/* a mini string-handling package */ + +static void +string_need (s, n) + string *s; + int n; +{ + int tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + tem = s->p - s->b; + n += tem; + n *= 2; + s->b = xrealloc (s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (s) + string *s; +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (s) + string *s; +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (s) + string *s; +{ + s->p = s->b; +} + +#if 0 + +static int +string_empty (s) + string *s; +{ + return (s->b == s->p); +} + +#endif + +static void +string_append (p, s) + string *p; + const char *s; +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (p, s) + string *p, *s; +{ + int n; + + if (s->b != s->p) + { + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; + } +} + +static void +string_appendn (p, s, n) + string *p; + const char *s; + int n; +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prepend (p, s) + string *p; + const char *s; +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +static void +string_prepends (p, s) + string *p, *s; +{ + if (s->b != s->p) + { + string_prependn (p, s->b, s->p - s->b); + } +} + +static void +string_prependn (p, s, n) + string *p; + const char *s; + int n; +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +/* To generate a standalone demangler program for testing purposes, + just compile and link this file with -DMAIN and libiberty.a. When + run, it demangles each command line arg, or each stdin string, and + prints the result on stdout. */ + +#ifdef MAIN + +static void +demangle_it (mangled_name) + char *mangled_name; +{ + char *result; + + result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI); + if (result == NULL) + { + printf ("%s\n", mangled_name); + } + else + { + printf ("%s\n", result); + free (result); + } +} + +#include "getopt.h" + +static char *program_name; +static char *program_version = VERSION; + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, "\ +Usage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\ + [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\ + [--help] [--version] [arg...]\n", + program_name); + exit (status); +} + +#define MBUF_SIZE 512 +char mbuffer[MBUF_SIZE]; + +/* Defined in the automatically-generated underscore.c. */ +extern int prepends_underscore; + +int strip_underscore = 0; + +static struct option long_options[] = { + {"strip-underscores", no_argument, 0, '_'}, + {"format", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"no-strip-underscores", no_argument, 0, 'n'}, + {"version", no_argument, 0, 'v'}, + {0, no_argument, 0, 0} +}; + +int +main (argc, argv) + int argc; + char **argv; +{ + char *result; + int c; + + program_name = argv[0]; + + strip_underscore = prepends_underscore; + + while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF) + { + switch (c) + { + case '?': + usage (stderr, 1); + break; + case 'h': + usage (stdout, 0); + case 'n': + strip_underscore = 0; + break; + case 'v': + printf ("GNU %s version %s\n", program_name, program_version); + exit (0); + case '_': + strip_underscore = 1; + break; + case 's': + if (strcmp (optarg, "gnu") == 0) + { + current_demangling_style = gnu_demangling; + } + else if (strcmp (optarg, "lucid") == 0) + { + current_demangling_style = lucid_demangling; + } + else if (strcmp (optarg, "arm") == 0) + { + current_demangling_style = arm_demangling; + } + else + { + fprintf (stderr, "%s: unknown demangling style `%s'\n", + program_name, optarg); + exit (1); + } + break; + } + } + + if (optind < argc) + { + for ( ; optind < argc; optind++) + { + demangle_it (argv[optind]); + } + } + else + { + for (;;) + { + int i = 0; + c = getchar (); + /* Try to read a label. */ + while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.')) + { + if (i >= MBUF_SIZE-1) + break; + mbuffer[i++] = c; + c = getchar (); + } + if (i > 0) + { + int skip_first = 0; + + if (mbuffer[0] == '.') + ++skip_first; + if (strip_underscore && mbuffer[skip_first] == '_') + ++skip_first; + + if (skip_first > i) + skip_first = i; + + mbuffer[i] = 0; + + result = cplus_demangle (mbuffer + skip_first, + DMGL_PARAMS | DMGL_ANSI); + if (result) + { + if (mbuffer[0] == '.') + putc ('.', stdout); + fputs (result, stdout); + free (result); + } + else + fputs (mbuffer, stdout); + + fflush (stdout); + } + if (c == EOF) + break; + putchar (c); + } + } + + exit (0); +} + +static void +fatal (str) + char *str; +{ + fprintf (stderr, "%s: %s\n", program_name, str); + exit (1); +} + +char * malloc (); +char * realloc (); + +char * +xmalloc (size) + unsigned size; +{ + register char *value = (char *) malloc (size); + if (value == 0) + fatal ("virtual memory exhausted"); + return value; +} + +char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *value = (char *) realloc (ptr, size); + if (value == 0) + fatal ("virtual memory exhausted"); + return value; +} +#endif /* main */ diff --git a/contrib/gdb/libiberty/dummy.c b/contrib/gdb/libiberty/dummy.c new file mode 100644 index 000000000000..08da647e30eb --- /dev/null +++ b/contrib/gdb/libiberty/dummy.c @@ -0,0 +1,49 @@ +#include + +#ifdef __STDC__ +#include +#define clock_t unsigned long +#define DEF(NAME, RETURN_TYPE, ARGLIST, ARGS) extern RETURN_TYPE NAME (ARGS); +#define DEFFUNC(NAME, RETURN_TYPE, ARGLIST, ARGS) extern RETURN_TYPE NAME (ARGS); +#else +#define void int +#define size_t unsigned long +#define clock_t unsigned long +#define DEF(NAME, RETURN_TYPE, ARGLIST, ARGS) extern RETURN_TYPE NAME (); +#define DEFFUNC(NAME, RETURN_TYPE, ARGLIST, ARGS) extern RETURN_TYPE NAME (); +#endif + +#define DEFVAR(NAME,DECL,USE) extern DECL; + +#define NOTHING /*nothing*/ + +#include "alloca-conf.h" +#include "functions.def" + +/* Always use our: getopt.o getopt1.o obstack.o spaces.o */ + +int +main (argc, argv) + int argc; char **argv; +{ + +/* Create a dummy function call for each DEF-defined function. */ + +#undef DEF +#undef DEFVAR +#undef DEFFUNC +#undef AND +#define AND = 0; +/* ARGS expands into a set of declaration. NAME ARG_LIST expands + info a function call that uses those variables as actual parameters. + If the function has been DEF'ed correctly, we can pass the right + number and types of parameters, which is nice. (E.g. gcc may + otherwise complain about the wrong number of parameters to certain + builtins.) */ +#define DEF(NAME, RETURN_TYPE, ARG_LIST, ARGS) { ARGS; NAME ARG_LIST; } +#define DEFVAR(NAME, DECL, USE) { USE; } +#define DEFFUNC(NAME, RETURN_TYPE, ARG_LIST, ARGS) { ARGS; NAME ARG_LIST; } +#include "functions.def" + + return (0); +} diff --git a/contrib/gdb/libiberty/fdmatch.c b/contrib/gdb/libiberty/fdmatch.c new file mode 100644 index 000000000000..7af039f5a2b8 --- /dev/null +++ b/contrib/gdb/libiberty/fdmatch.c @@ -0,0 +1,73 @@ +/* Compare two open file descriptors to see if they refer to the same file. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* + +NAME + + fdmatch -- see if two file descriptors refer to same file + +SYNOPSIS + + int fdmatch (int fd1, int fd2) + +DESCRIPTION + + Check to see if two open file descriptors refer to the same file. + This is useful, for example, when we have an open file descriptor + for an unnamed file, and the name of a file that we believe to + correspond to that fd. This can happen when we are exec'd with + an already open file (stdout for example) or from the SVR4 /proc + calls that return open file descriptors for mapped address spaces. + All we have to do is open the file by name and check the two file + descriptors for a match, which is done by comparing major&minor + device numbers and inode numbers. + +BUGS + + (FIXME: does this work for networks?) + It works for NFS, which assigns a device number to each mount. + +*/ + +#include "ansidecl.h" +#include "libiberty.h" +#include +#include + +int fdmatch (fd1, fd2) + int fd1; + int fd2; +{ + struct stat sbuf1; + struct stat sbuf2; + + if ((fstat (fd1, &sbuf1) == 0) && + (fstat (fd2, &sbuf2) == 0) && + (sbuf1.st_dev == sbuf2.st_dev) && + (sbuf1.st_ino == sbuf2.st_ino)) + { + return (1); + } + else + { + return (0); + } +} diff --git a/contrib/gdb/libiberty/floatformat.c b/contrib/gdb/libiberty/floatformat.c new file mode 100644 index 000000000000..655f4ea9264b --- /dev/null +++ b/contrib/gdb/libiberty/floatformat.c @@ -0,0 +1,385 @@ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "floatformat.h" +#include /* ldexp */ +#ifdef __STDC__ +#include +extern void *memcpy (void *s1, const void *s2, size_t n); +extern void *memset (void *s, int c, size_t n); +#else +extern char *memcpy (); +extern char *memset (); +#endif + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +/* floatformats for IEEE single and double, big and little endian. */ +const struct floatformat floatformat_ieee_single_big = +{ + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no +}; +const struct floatformat floatformat_ieee_single_little = +{ + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no +}; +const struct floatformat floatformat_ieee_double_big = +{ + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no +}; +const struct floatformat floatformat_ieee_double_little = +{ + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no +}; + +const struct floatformat floatformat_i387_ext = +{ + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes +}; +const struct floatformat floatformat_m68881_ext = +{ + /* Note that the bits from 16 to 31 are unused. */ + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, floatformat_intbit_yes +}; +const struct floatformat floatformat_i960_ext = +{ + /* Note that the bits from 0 to 15 are unused. */ + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes +}; +const struct floatformat floatformat_m88110_ext = +{ +#ifdef HARRIS_FLOAT_FORMAT + /* Harris uses raw format 128 bytes long, but the number is just an ieee + double, and the last 64 bits are wasted. */ + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, + floatformat_intbit_no +#else + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes +#endif /* HARRIS_FLOAT_FORMAT */ +}; +const struct floatformat floatformat_arm_ext = +{ + /* Bits 1 to 16 are unused. */ + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes +}; + +static unsigned long get_field PARAMS ((unsigned char *, + enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int)); + +/* Extract a field which starts at START and is LEN bytes long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (data, order, total_len, start, len) + unsigned char *data; + enum floatformat_byteorders order; + unsigned int total_len; + unsigned int start; + unsigned int len; +{ + unsigned long result; + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + result = *(data + cur_byte) >> (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while (cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + /* This is the last byte; zero out the bits which are not part of + this field. */ + result |= + (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) + << cur_bitshift; + else + result |= *(data + cur_byte) << cur_bitshift; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } + return result; +} + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +floatformat_to_double (fmt, from, to) + const struct floatformat *fmt; + char *from; + double *to; +{ + unsigned char *ufrom = (unsigned char *)from; + double dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + /* Note that if exponent indicates a NaN, we can't really do anything useful + (not knowing if the host has NaN's, or how to build one). So it will + end up as an infinity or something close; that is OK. */ + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + exponent -= fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + while (mant_bits_left > 0) + { + int exp_bits; + exp_bits = mant_bits_left < 32 ? mant_bits_left : 32; + if (mant_bits_left == fmt->man_len + && exp_bits == 32 + && fmt->intbit == floatformat_intbit_no) + { + /* If there is no integer bit, we need to get only 31 bits + so we have room for an integer bit that we create. */ + mant_bits = 31; + } + else + mant_bits = exp_bits; + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + if (mant_bits_left == fmt->man_len) + mant |= 0x80000000; + dto += ldexp ((double)mant, exponent - (exp_bits - 1)); + exponent -= exp_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + memcpy (to, &dto, sizeof (dto)); +} + +static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int, + unsigned long)); + +/* Set a field which starts at START and is LEN bytes long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (data, order, total_len, start, len, stuff_to_put) + unsigned char *data; + enum floatformat_byteorders order; + unsigned int total_len; + unsigned int start; + unsigned int len; + unsigned long stuff_to_put; +{ + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + *(data + cur_byte) &= + ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); + *(data + cur_byte) |= + (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while (cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + { + /* This is the last byte. */ + *(data + cur_byte) &= + ~((1 << (len - cur_bitshift)) - 1); + *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); + } + else + *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) + & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_double (fmt, from, to) + CONST struct floatformat *fmt; + double *from; + char *to; +{ + double dfrom; + int exponent; + double mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *)to; + + memcpy (&dfrom, from, sizeof (dfrom)); + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); + if (dfrom == 0) + return; /* Result is zero */ + if (dfrom != dfrom) + { + /* From is NaN */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + /* Be sure it's not infinity, but NaN value is irrel */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, + 32, 1); + return; + } + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); + dfrom = -dfrom; + } + + /* How to tell an infinity from an ordinary number? FIXME-someday */ + + mant = frexp (dfrom, &exponent); + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, + exponent + fmt->exp_bias - 1); + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = (unsigned long)mant; + mant -= mant_long; + + /* If the integer bit is implicit, then we need to discard it. + If we are discarding a zero, we should be (but are not) creating + a denormalized number which means adjusting the exponent + (I think). */ + if (mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no) + { + mant_long &= 0x7fffffff; + mant_bits -= 1; + } + else if (mant_bits < 32) + { + /* The bits we want are in the most significant MANT_BITS bits of + mant_long. Move them to the least significant. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } +} + + +#ifdef IEEE_DEBUG + +/* This is to be run on a host which uses IEEE floating point. */ + +void +ieee_test (n) + double n; +{ + double result; + char exten[16]; + + floatformat_to_double (&floatformat_ieee_double_big, &n, &result); + if (n != result) + printf ("Differ(to): %.20g -> %.20g\n", n, result); + floatformat_from_double (&floatformat_ieee_double_big, &n, &result); + if (n != result) + printf ("Differ(from): %.20g -> %.20g\n", n, result); + + floatformat_from_double (&floatformat_m68881_ext, &n, exten); + floatformat_to_double (&floatformat_m68881_ext, exten, &result); + if (n != result) + printf ("Differ(to+from): %.20g -> %.20g\n", n, result); + +#if IEEE_DEBUG > 1 + /* This is to be run on a host which uses 68881 format. */ + { + long double ex = *(long double *)exten; + if (ex != n) + printf ("Differ(from vs. extended): %.20g\n", n); + } +#endif +} + +int +main () +{ + ieee_test (0.5); + ieee_test (256.0); + ieee_test (0.12345); + ieee_test (234235.78907234); + ieee_test (-512.0); + ieee_test (-0.004321); + return 0; +} +#endif diff --git a/contrib/gdb/libiberty/functions.def b/contrib/gdb/libiberty/functions.def new file mode 100644 index 000000000000..8becc89fc64b --- /dev/null +++ b/contrib/gdb/libiberty/functions.def @@ -0,0 +1,67 @@ +/* + * List of function definitions that may *optionally* be included + * in libiberty.a. The function names must match the filenames, + * e.g. bzero() is defined in bzero.c. (While each file can contain + * extra functions, do not list them.) + * + * In the default libiberty configuration, these object files + * (e.g bzero.o) are included if and only if cc fails to find + * the corresponding function in libc. + */ + +DEF(atexit, int, (f), void (*f)()) +DEF(bcmp, int, (s1, s2, length), char *s1 AND char *s2 AND int length ) +DEF(bcopy, void, (s1, s2, length), char *s1 AND char *s2 AND int length ) +DEF(bzero, void, (s, length), char *s AND int length) +DEF(clock, clock_t, (), NOTHING) +DEF(getopt, int, (argc, argv, optstring), + int argc AND char **argv AND CONST char *optstring) +DEF(getpagesize, int , (), NOTHING) +DEF(getcwd, char*, (buf, len), char *buf AND int len) +DEF(index, char*, (s, c), char *s AND int c) +DEF(insque, void, (), NOTHING) +DEF(memchr, PTR, (s, c, length), CONST PTR s AND int c AND size_t length) +DEF(memcmp, int, (s1, s2, length), + CONST PTR s1 AND CONST PTR s2 AND size_t length) +DEF(memcpy, PTR, (s1, s2, length), PTR s1 AND CONST PTR s2 AND size_t length) +DEF(memmove, PTR, (s1, s2, length), PTR s1 AND CONST PTR s2 AND size_t length) +DEF(memset, PTR, (s, val, length), PTR s AND int val AND size_t length ) +DEF(random, long int, (), NOTHING) +DEF(rename, int, (f, t), char *f AND char *t) +DEF(rindex, char*, (s, c), char *s AND int c) +DEF(strcasecmp, int, (s1, s2), char *s1 AND char *s2) +DEF(strncasecmp, int, (s1, s2, n), char *s1 AND char *s2 AND int n) +DEF(strchr, char*, (s, c), CONST char *s AND int c) +DEF(strdup, char*, (s1), char * s1) +DEF(strrchr, char*, (s, c), CONST char *s AND int c) +DEF(strstr, char*, (), NOTHING) +DEF(strtod, double, (), NOTHING) +DEF(strtol, long, (), NOTHING) +DEF(strtoul, unsigned long, (), NOTHING) +DEF(tmpnam, char *, (s), char * s) +DEF(vfork, int, (), NOTHING) +DEF(vfprintf, int, (), NOTHING) +DEF(vprintf, int, (), NOTHING) +DEF(vsprintf, int, (), NOTHING) +DEF(sigsetmask, int, (), NOTHING) +DEF(alloca, PTR, (size), size_t size) +DEF(waitpid, int, (pid, statp, opts), int pid AND int* statp AND int opts ) + +/* List of global variables that we want to look for in the host + environment, and to generate an entry NEED_ in config.h + if they are not found. The first arg is the variable name, the + second arg is how to declare the variable, and the third is how to + use it. */ + +DEFVAR(sys_nerr, int sys_nerr, sys_nerr = 0) +DEFVAR(sys_errlist, char *sys_errlist[], sys_errlist[0] = 0) +DEFVAR(sys_siglist, char *sys_siglist[], sys_siglist[0] = 0) + +/* List of global functions that we want to look for in the host + environment, and to generate an entry NEED_ in config.h + if they are not found. */ + +DEFFUNC(strerror, char*, (), NOTHING) +DEFFUNC(psignal, void, (signo, message), unsigned signo AND char *message) +DEFFUNC(basename, char *, (name), CONST char *name) +DEFFUNC(on_exit, void, (f, arg), void (*f)() AND char *arg) diff --git a/contrib/gdb/libiberty/getcwd.c b/contrib/gdb/libiberty/getcwd.c new file mode 100644 index 000000000000..60c1dd84eed9 --- /dev/null +++ b/contrib/gdb/libiberty/getcwd.c @@ -0,0 +1,52 @@ +/* Emulate getcwd using getwd. + This function is in the public domain. */ + +/* +NAME + getcwd -- get absolute pathname for current working directory + +SYNOPSIS + char *getcwd (char pathname[len], len) + +DESCRIPTION + Copy the absolute pathname for the current working directory into + the supplied buffer and return a pointer to the buffer. If the + current directory's path doesn't fit in LEN characters, the result + is NULL and errno is set. + +BUGS + Emulated via the getwd() call, which is reasonable for most + systems that do not have getcwd(). + +*/ + +#ifndef NO_SYS_PARAM_H +#include +#endif +#include + +extern char *getwd (); +extern int errno; + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +char * +getcwd (buf, len) + char *buf; + int len; +{ + char ourbuf[MAXPATHLEN]; + char *result; + + result = getwd (ourbuf); + if (result) { + if (strlen (ourbuf) >= len) { + errno = ERANGE; + return 0; + } + strcpy (buf, ourbuf); + } + return buf; +} diff --git a/contrib/gdb/libiberty/getopt.c b/contrib/gdb/libiberty/getopt.c new file mode 100644 index 000000000000..458dca22b448 --- /dev/null +++ b/contrib/gdb/libiberty/getopt.c @@ -0,0 +1,757 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95 + Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#if defined (emacs) || defined (CONFIG_BROKETS) +/* We use instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include +#else +#include "config.h" +#endif +#endif + +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ +/* Many versions of the Linux C library include older, broken versions + of these routines, which will break the linker's command-line + parsing. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined (__linux__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#ifndef __STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + optstring = _getopt_initialize (optstring); + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/gdb/libiberty/getopt1.c b/contrib/gdb/libiberty/getopt1.c new file mode 100644 index 000000000000..c3400e5b6436 --- /dev/null +++ b/contrib/gdb/libiberty/getopt1.c @@ -0,0 +1,190 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#if defined (emacs) || defined (CONFIG_BROKETS) +/* We use instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include +#else +#include "config.h" +#endif +#endif + +#include "getopt.h" + +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ +/* Many versions of the Linux C library include older, broken versions + of these routines, which will break the linker's command-line + parsing. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined (__linux__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/gdb/libiberty/getpagesize.c b/contrib/gdb/libiberty/getpagesize.c new file mode 100644 index 000000000000..e9784b8520b8 --- /dev/null +++ b/contrib/gdb/libiberty/getpagesize.c @@ -0,0 +1,89 @@ +/* Emulation of getpagesize() for systems that need it. */ + +/* + +NAME + + getpagesize -- return the number of bytes in page of memory + +SYNOPSIS + + int getpagesize (void) + +DESCRIPTION + + Returns the number of bytes in a page of memory. This is the + granularity of many of the system memory management routines. + No guarantee is made as to whether or not it is the same as the + basic memory management hardware page size. + +BUGS + + Is intended as a reasonable replacement for systems where this + is not provided as a system call. The value of 4096 may or may + not be correct for the systems where it is returned as the default + value. + +*/ + +#ifndef VMS + +#include +#ifndef NO_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYSCONF +#include +#define GNU_OUR_PAGESIZE sysconf(_SC_PAGESIZE) +#else +#ifdef PAGESIZE +#define GNU_OUR_PAGESIZE PAGESIZE +#else /* no PAGESIZE */ +#ifdef EXEC_PAGESIZE +#define GNU_OUR_PAGESIZE EXEC_PAGESIZE +#else /* no EXEC_PAGESIZE */ +#ifdef NBPG +#define GNU_OUR_PAGESIZE (NBPG * CLSIZE) +#ifndef CLSIZE +#define CLSIZE 1 +#endif /* CLSIZE */ +#else /* no NBPG */ +#ifdef NBPC +#define GNU_OUR_PAGESIZE NBPC +#else /* no NBPC */ +#define GNU_OUR_PAGESIZE 4096 /* Just punt and use reasonable value */ +#endif /* NBPC */ +#endif /* NBPG */ +#endif /* EXEC_PAGESIZE */ +#endif /* PAGESIZE */ +#endif /* HAVE_SYSCONF */ + +int +getpagesize () +{ + return (GNU_OUR_PAGESIZE); +} + +#else /* VMS */ + +#if 0 /* older distributions of gcc-vms are missing */ +#include +#endif +#ifndef SYI$_PAGE_SIZE /* VMS V5.4 and earlier didn't have this yet */ +#define SYI$_PAGE_SIZE 4452 +#endif +extern unsigned long lib$getsyi(const unsigned short *,...); + +int getpagesize () +{ + long pagsiz = 0L; + unsigned short itmcod = SYI$_PAGE_SIZE; + + (void) lib$getsyi (&itmcod, (void *) &pagsiz); + if (pagsiz == 0L) + pagsiz = 512L; /* VAX default */ + return (int) pagsiz; +} + +#endif /* VMS */ diff --git a/contrib/gdb/libiberty/getruntime.c b/contrib/gdb/libiberty/getruntime.c new file mode 100644 index 000000000000..1be3b4c4a2a0 --- /dev/null +++ b/contrib/gdb/libiberty/getruntime.c @@ -0,0 +1,82 @@ +/* Return time used so far, in microseconds. + Copyright (C) 1994 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ansidecl.h" +#include "libiberty.h" + +/* There are several ways to get elapsed execution time; unfortunately no + single way is available for all host systems, nor are there reliable + ways to find out which way is correct for a given host. */ + +#include + +/* These should go away when libiberty uses autoconf. */ + +#if defined(__sun__) && !defined(__svr4__) +#define HAVE_GETRUSAGE +#endif + +#ifdef HAVE_SYSCONF +#define HAVE_TIMES +#endif + +#ifdef HAVE_GETRUSAGE +#include +#include +#endif + +#ifdef HAVE_TIMES +#ifndef NO_SYS_PARAM_H +#include +#endif +#include +#endif + +/* This is a fallback; if wrong, it will likely make obviously wrong + results. */ + +#ifndef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 1 +#endif + +long +get_run_time () +{ +#ifdef HAVE_GETRUSAGE + struct rusage rusage; + + getrusage (0, &rusage); + return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec + + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec); +#else /* ! HAVE_GETRUSAGE */ +#ifdef HAVE_TIMES + struct tms tms; + + times (&tms); + return (tms.tms_utime + tms.tms_stime) * (1000000 / HZ); +#else /* ! HAVE_TIMES */ + /* Fall back on clock and hope it's correctly implemented. */ + const long clocks_per_sec = CLOCKS_PER_SEC; + if (clocks_per_sec <= 1000000) + return clock () * (1000000 / clocks_per_sec); + else + return clock () / clocks_per_sec; +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ +} diff --git a/contrib/gdb/libiberty/hex.c b/contrib/gdb/libiberty/hex.c new file mode 100644 index 000000000000..3a2eef03d4c0 --- /dev/null +++ b/contrib/gdb/libiberty/hex.c @@ -0,0 +1,33 @@ +/* Hex character manipulation support. + Copyright (C) 1995 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libiberty.h" + +char _hex_value[_hex_array_size]; + +void hex_init () +{ + int i; + for (i = 0; i < _hex_array_size; i++) + _hex_value[i] = _hex_bad; + for (i = 0; i < 10; i++) + _hex_value['0' + i] = i; + for (i = 0; i < 6; i++) + _hex_value['a' + i] = _hex_value['A' + i] = 10 + i; +} diff --git a/contrib/gdb/libiberty/index.c b/contrib/gdb/libiberty/index.c new file mode 100644 index 000000000000..e5a00f54d946 --- /dev/null +++ b/contrib/gdb/libiberty/index.c @@ -0,0 +1,11 @@ +/* Stub implementation of (obsolete) index(). */ + +extern char * strchr(); + +char * +index (s, c) + char *s; + int c; +{ + return strchr (s, c); +} diff --git a/contrib/gdb/libiberty/insque.c b/contrib/gdb/libiberty/insque.c new file mode 100644 index 000000000000..775019f8fffc --- /dev/null +++ b/contrib/gdb/libiberty/insque.c @@ -0,0 +1,50 @@ +/* insque(3C) routines + This file is in the public domain. */ + +/* +NAME + insque, remque -- insert, remove an element from a queue + +SYNOPSIS + struct qelem { + struct qelem *q_forw; + struct qelem *q_back; + char q_data[]; + }; + + void insque (struct qelem *elem, struct qelem *pred) + + void remque (struct qelem *elem) + +DESCRIPTION + Routines to manipulate queues built from doubly linked lists. + The insque routine inserts ELEM in the queue immediately after + PRED. The remque routine removes ELEM from its containing queue. +*/ + + +struct qelem { + struct qelem *q_forw; + struct qelem *q_back; +}; + + +void +insque (elem, pred) + struct qelem *elem; + struct qelem *pred; +{ + elem -> q_forw = pred -> q_forw; + pred -> q_forw -> q_back = elem; + elem -> q_back = pred; + pred -> q_forw = elem; +} + + +void +remque (elem) + struct qelem *elem; +{ + elem -> q_forw -> q_back = elem -> q_back; + elem -> q_back -> q_forw = elem -> q_forw; +} diff --git a/contrib/gdb/libiberty/makefile.dos b/contrib/gdb/libiberty/makefile.dos new file mode 100644 index 000000000000..7eba62c33953 --- /dev/null +++ b/contrib/gdb/libiberty/makefile.dos @@ -0,0 +1,29 @@ +CFLAGS=-O2 + +OBJS = \ + argv.o \ + basename.o \ + concat.o \ + cplus-dem.o \ + fdmatch.o \ + floatformat.o \ + getopt.o \ + getopt1.o \ + getruntime.o \ + hex.o \ + msdos.o \ + obstack.o \ + spaces.o \ + strerror.o \ + strsignal.o \ + xatexit.o \ + xexit.o \ + xmalloc.o \ + $E + +.c.o: + gcc -I../include $(CFLAGS) -c $< + +libiberty.a : $(OBJS) + -rm libiberty.a + ar rvs libiberty.a $(OBJS) diff --git a/contrib/gdb/libiberty/memchr.c b/contrib/gdb/libiberty/memchr.c new file mode 100644 index 000000000000..93ef43d3f88d --- /dev/null +++ b/contrib/gdb/libiberty/memchr.c @@ -0,0 +1,60 @@ +/* +FUNCTION + <>---find character in memory + +INDEX + memchr + +ANSI_SYNOPSIS + #include + void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>); + +TRAD_SYNOPSIS + #include + void *memchr(<[src]>, <[c]>, <[length]>) + void *<[src]>; + void *<[c]>; + size_t <[length]>; + +DESCRIPTION + This function searches memory starting at <<*<[src]>>> for the + character <[c]>. The search only ends with the first + occurrence of <[c]>, or after <[length]> characters; in + particular, <> does not terminate the search. + +RETURNS + If the character <[c]> is found within <[length]> characters + of <<*<[src]>>>, a pointer to the character is returned. If + <[c]> is not found, then <> is returned. + +PORTABILITY +<> requires no supporting OS subroutines. + +QUICKREF + memchr ansi pure + +*/ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +PTR +memchr (src_void, c, length) + register CONST PTR src_void; + int c; + size_t length; +{ + CONST unsigned char *src = (CONST unsigned char *)src_void; + + while (--length >= 0) + { + if (*src == c) + return (PTR)src; + src++; + } + return NULL; +} diff --git a/contrib/gdb/libiberty/memcmp.c b/contrib/gdb/libiberty/memcmp.c new file mode 100644 index 000000000000..127ae0c8019d --- /dev/null +++ b/contrib/gdb/libiberty/memcmp.c @@ -0,0 +1,38 @@ +/* memcmp -- compare two memory regions. + This function is in the public domain. */ + +/* +NAME + memcmp -- compare two memory regions + +SYNOPSIS + int memcmp (const void *from, const void *to, size_t count) + +DESCRIPTION + Compare two memory regions and return less than, + equal to, or greater than zero, according to lexicographical + ordering of the compared regions. +*/ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +int +DEFUN(memcmp, (str1, str2, count), + const PTR str1 AND const PTR str2 AND size_t count) +{ + register unsigned char *s1 = (unsigned char*)str1; + register unsigned char *s2 = (unsigned char*)str2; + + while (count-- > 0) + { + if (*s1++ != *s2++) + return s1[-1] < s2[-1] ? -1 : 1; + } + return 0; +} + diff --git a/contrib/gdb/libiberty/memcpy.c b/contrib/gdb/libiberty/memcpy.c new file mode 100644 index 000000000000..c28208a0f7e8 --- /dev/null +++ b/contrib/gdb/libiberty/memcpy.c @@ -0,0 +1,28 @@ +/* memcpy (the standard C function) + This function is in the public domain. */ + +/* +NAME + memcpy -- copy memory regions of arbitary length + +SYNOPSIS + void* memcpy (void *out, const void *in, size_t n); + +DESCRIPTION + Copy LENGTH bytes from memory region pointed to by IN to memory + region pointed to by OUT. +*/ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +PTR +DEFUN(memcpy, (out, in, length), PTR out AND CONST PTR in AND size_t length) +{ + bcopy(in, out, length); + return out; +} diff --git a/contrib/gdb/libiberty/memmove.c b/contrib/gdb/libiberty/memmove.c new file mode 100644 index 000000000000..818fc2496622 --- /dev/null +++ b/contrib/gdb/libiberty/memmove.c @@ -0,0 +1,18 @@ +/* Wrapper to implement ANSI C's memmove using BSD's bcopy. */ +/* This function is in the public domain. --Per Bothner. */ +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +PTR +memmove (s1, s2, n) + PTR s1; + CONST PTR s2; + size_t n; +{ + bcopy (s2, s1, n); + return s1; +} diff --git a/contrib/gdb/libiberty/memset.c b/contrib/gdb/libiberty/memset.c new file mode 100644 index 000000000000..5f54831e83c4 --- /dev/null +++ b/contrib/gdb/libiberty/memset.c @@ -0,0 +1,19 @@ +/* memset + This implementation is in the public domain. */ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +PTR +DEFUN(memset, (dest, val, len), + PTR dest AND register int val AND register size_t len) +{ + register unsigned char *ptr = (unsigned char*)dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} diff --git a/contrib/gdb/libiberty/mpw-config.in b/contrib/gdb/libiberty/mpw-config.in new file mode 100644 index 000000000000..829d8e730d46 --- /dev/null +++ b/contrib/gdb/libiberty/mpw-config.in @@ -0,0 +1,9 @@ +# MPW configuration fragment for libiberty. + +forward-include "{srcdir}"alloca-norm.h alloca-conf.h + +Echo '/* config.h. Generated by mpw-configure. */' > "{o}"config.new + +MoveIfChange "{o}"config.new "{o}"config.h + + diff --git a/contrib/gdb/libiberty/mpw-make.sed b/contrib/gdb/libiberty/mpw-make.sed new file mode 100644 index 000000000000..f99eb1a44074 --- /dev/null +++ b/contrib/gdb/libiberty/mpw-make.sed @@ -0,0 +1,49 @@ +# Sed commands to finish translating libiberty's Unix makefile to MPW syntax. + +# Comment out a useless thing. +/^\.always\./s/^/#/ + +# Replace the auto-generated list with the list of what we know we need. +s/`cat needed-list`/"{o}"alloca.c.o "{o}"bcopy.c.o "{o}"getpagesize.c.o "{o}"insque.c.o "{o}"mpw.c.o "{o}"strcasecmp.c.o "{o}"strdup.c.o "{o}"strncasecmp.c.o/ + +# Paste in some desirable definitions. +/^###$/a\ +\ +HDEFINES = -d NEED_sys_siglist -d NEED_sys_errlist -d NEED_basename -d NEED_strcasecmp -d NEED_strncasecmp\ +INCLUDES = -i : -i {INCDIR}: -i {INCDIR}:mpw: -i ::extra-include: -i "{s}"\ +\ +.c.o \\Option-f .c\ + {CC} {DepDir}{Default}.c {LIBCFLAGS} {INCLUDES} {HDEFINES} @SEGMENT_FLAG@ -o {TargDir}{Default}.c.o\ + +# Remove dependency on needed-list, which we don't use. +/DO_ALSO =/s/needed-list// + +/INCDIR=/s/"{srcdir}"{MULTISRCTOP}::/"{topsrcdir}"/ + +# Whack out the COMPILE.c trickiness. +/^COMPILE.c /,/^$/d + +# Remove the multido trickiness from the "all" target. +/^all \\Option-f/,/^$/c\ +all \\Option-f {TARGETLIB}\ + + +# Remove the RULE1/RULE2 crud. +/if \[/,/fi/d +/^RULE1 =/,/RULE2 =/d +/RULE2/s/RULE2/TARGETLIB/ + +# Don't want fdmatch ever. +s/ "{o}"fdmatch.c.o// + +# Fix paths to generated files. +/config.h/s/"{s}"config.h/"{o}"config.h/ + +# Whack out config rebuild rules. +/^"{o}"config.h \\Option-f/,/^$/d + + + + + + diff --git a/contrib/gdb/libiberty/mpw.c b/contrib/gdb/libiberty/mpw.c new file mode 100644 index 000000000000..b93e1008697b --- /dev/null +++ b/contrib/gdb/libiberty/mpw.c @@ -0,0 +1,1010 @@ +/* MPW-Unix compatibility library. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This should only be compiled and linked under MPW. */ + +#include "mpw.h" + +#include + +#ifndef USE_MW_HEADERS +#include +#include +#endif + +#include +#include + +#include + +/* Initialize to 0 at first, then set to errno_max() later. */ + +int sys_nerr = 0; + +/* Debug flag for pathname hacking. Set this to one and rebuild. */ + +int DebugPI = 0; + +void +mpwify_filename(char *unixname, char *macname) +{ + int i, j, in_middle, terminate = 0; + + /* (should truncate 255 chars from end of name, not beginning) */ + if (strlen (unixname) > 255) + { + fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n", + unixname); + terminate = 1; + } + /* Abs Unix path to abs Mac path. */ + if (*unixname == '/') + { + if (strncmp (unixname, "/tmp/", 5) == 0) + { + /* A temporary name, make a more Mac-flavored tmpname. */ + /* A better choice would be {Boot}Trash:foo, but that would + require being able to identify the boot disk's and trashcan's + name. Another option would be to have an env var, so user + can point it at a ramdisk. */ + strncpy (macname, unixname, 255); + if (terminate) + macname[255] = '\0'; + macname[0] = ':'; + macname[4] = '_'; + } + else + { + /* Assume that the leading component is a valid disk name. */ + strncpy (macname, unixname + 1, 255); + } + } + else + { + /* If this is a "Unix-only" pathname, assume relative. */ + if (strchr (unixname, '/') && ! strchr (unixname, ':')) + { + macname[0] = ':'; + strncpy (macname + 1, unixname, 255); + } + else + { + /* Otherwise copy it verbatim. */ + /* ... but if of the form ":/foo", lose the extra colon; + the slash will be made into a colon shortly. */ + if (unixname[0] == ':' && unixname[1] == '/') + ++unixname; + strncpy (macname, unixname, 255); + } + } + if (terminate) + macname[255] = '\0'; + for (i = 0; macname[i] != '\0'; ++i) + { + if (macname[i] == '/') + macname[i] = ':'; + } + in_middle = 0; + j = 0; + for (i = 0; macname[i] != '\0'; ++i) + { + /* We're in the middle of the name when a char is not a colon. */ + if (macname[i] != ':') + in_middle = 1; + /* Copy chars verbatim, *unless* the char is the first of a pair + of colons in the middle of a pathname. */ + if (!(in_middle && macname[i] == ':' && macname[i+1] == ':')) + macname[j++] = macname[i]; + } + macname[j] = '\0'; + /* If we have a trailing ":.", make it into a ":". */ + if (j >= 2 && macname[j-2] == ':' && macname[j-1] == '.') + macname[j-1] = '\0'; + if (DebugPI) + { + fprintf (stderr, "# Made \"%s\"\n", unixname); + fprintf (stderr, "# into \"%s\"\n", macname); + } +} + +/* MPW-flavored basename finder. */ + +char * +mpw_basename (name) + char *name; +{ + char *base = name; + + while (*name) + { + if (*name++ == ':') + { + base = name; + } + } + return base; +} + +/* Mixed MPW/Unix basename finder. This can be led astray by + filenames with slashes in them and come up with a basename that + either corresponds to no file or (worse) to some other file, so + should only be tried if other methods of finding a file via a + basename have failed. */ + +char * +mpw_mixed_basename (name) + char *name; +{ + char *base = name; + + while (*name) + { + if (*name == '/' || *name == ':') + { + base = name + 1; + } + ++name; + } + return base; +} + +/* This function is fopen() modified to create files that are type TEXT + or 'BIN ', and always of type 'MPS '. */ + +FILE * +mpw_fopen (char *name, char *mode) +{ +#undef fopen + int errnum; + FILE *fp; + char tmpname[256]; + + mpwify_filename (name, tmpname); + PROGRESS (1); + fp = fopen (tmpname, mode); + errnum = errno; + + /* If writing, need to set type and creator usefully. */ + if (strchr (mode, 'w')) + { + char *pname = (char *) malloc (strlen (tmpname) + 2); + OSErr e; + struct FInfo fi; + + pname[0] = strlen (tmpname); + strcpy (pname+1, tmpname); + + e = GetFInfo ((ConstStr255Param) pname, 0, &fi); + /* should do spiffier error handling */ + if (e != 0) + fprintf(stderr, "GetFInfo returns %d\n", e); + if (strchr (mode, 'b')) + { + fi.fdType = (OSType) 'BIN '; + } + else + { + fi.fdType = (OSType) 'TEXT'; + } + fi.fdCreator = (OSType) 'MPS '; + e = SetFInfo ((ConstStr255Param) pname, 0, &fi); + if (e != 0) + fprintf(stderr, "SetFInfo returns %d\n", e); + free (pname); + } + if (fp == NULL) + errno = errnum; + return fp; +} + +/* This is a version of fseek() modified to fill the file with zeros + if seeking past the end of it. */ + +#define ZEROBLKSIZE 4096 + +char zeros[ZEROBLKSIZE]; + +int +mpw_fseek (FILE *fp, int offset, int whence) +{ +#undef fseek + int cursize, numleft; + + PROGRESS (1); + if (whence == SEEK_SET) + { + fseek (fp, 0, SEEK_END); + cursize = ftell (fp); + if (offset > cursize) + { + numleft = offset - cursize; + while (numleft > ZEROBLKSIZE) + { + /* This might fail, should check for that. */ + PROGRESS (1); + fwrite (zeros, 1, ZEROBLKSIZE, fp); + numleft -= ZEROBLKSIZE; + } + PROGRESS (1); + fwrite (zeros, 1, numleft, fp); + fflush (fp); + } + } + return fseek (fp, offset, whence); +} + +int +mpw_fread (char *ptr, int size, int nitems, FILE *stream) +{ +#undef fread + int rslt; + + PROGRESS (1); + rslt = fread (ptr, size, nitems, stream); + PROGRESS (1); + return rslt; +} + +int +mpw_fwrite (char *ptr, int size, int nitems, FILE *stream) +{ +#undef fwrite + int rslt; + + PROGRESS (1); + rslt = fwrite (ptr, size, nitems, stream); + PROGRESS (1); + return rslt; +} + +int +link () +{ + fprintf (stderr, "link not available!\n"); + mpw_abort (); +} + +int +fork () +{ + fprintf (stderr, "fork not available!\n"); + mpw_abort (); +} + +int +vfork () +{ + fprintf (stderr, "vfork not available!\n"); + mpw_abort (); + return (-1); +} + +int +pipe (int *fd) +{ + fprintf (stderr, "pipe not available!\n"); + mpw_abort (); + return (-1); +} + +#ifndef USE_MW_HEADERS +int +execvp (char *file, char **argv) +{ + fprintf (stderr, "execvp not available!\n"); + mpw_abort (); + return (-1); +} + +int +execv (char *path, char **argv) +{ + fprintf (stderr, "execv not available!\n"); + mpw_abort (); + return (-1); +} +#endif + +int +kill (int pid, int sig) +{ + fprintf (stderr, "kill not available!\n"); + mpw_abort (); + return (-1); +} + +int +wait (int *status) +{ + *status = 0; + return 0; +} + +#ifndef USE_MW_HEADERS +int +sleep (int seconds) +{ + unsigned long start_time, now; + + time (&start_time); + + while (1) + { + PROGRESS (1); + time (&now); + if (now > start_time + seconds) + return 0; + } +} +#endif + +void +putenv (char *str) +{ + /* The GCC driver calls this to do things for collect2, but we + don't care about collect2. */ +} + +int +chmod (char *path, int mode) +{ + /* Pretend it was all OK. */ + return 0; +} + +#ifndef USE_MW_HEADERS +int +getuid () +{ + /* One value is as good as another... */ + return 0; +} + +int +getgid () +{ + /* One value is as good as another... */ + return 0; +} +#endif + +/* Instead of coredumping, which is not a normal Mac facility, we + drop into Macsbug. If we then "g" from Macsbug, the program will + exit cleanly. */ + +void +mpw_abort () +{ + /* Make sure no output still buffered up, then zap into MacsBug. */ + fflush(stdout); + fflush(stderr); + printf("## Abort! ##\n"); +#ifdef MPW_SADE + SysError(8005); +#else + Debugger(); +#endif + /* "g" in MacsBug will then cause a regular error exit. */ + exit (1); +} + +/* Imitation getrusage based on the ANSI clock() function. */ + +int +getrusage (int who, struct rusage *rusage) +{ + int clk = clock (); + +#if 0 + rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC; + rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000; + rusage->ru_stime.tv_sec = 0; + rusage->ru_stime.tv_usec = 0; +#endif +} + +int +sbrk () +{ + return 0; +} + +#ifndef USE_MW_HEADERS +int +isatty (int fd) +{ + return 0; +} + +/* This is inherited from Timothy Murray's Posix library. */ + +#include "utime.h" + +int +utime (char *filename, struct utimbuf *times) +{ + CInfoPBRec cipbr; + HFileInfo *fpb = (HFileInfo *) &cipbr; + DirInfo *dpb = (DirInfo *) &cipbr; + unsigned char pname[256]; + short err; + + strcpy ((char *) pname, filename); + c2pstr (pname); + + dpb->ioDrDirID = 0L; + fpb->ioNamePtr = pname; + fpb->ioVRefNum = 0; + fpb->ioFDirIndex = 0; + fpb->ioFVersNum = 0; + err = PBGetCatInfo (&cipbr, 0); + if (err != noErr) { + errno = ENOENT; + return -1; + } + dpb->ioDrDirID = 0L; + fpb->ioFlMdDat = times->modtime; + fpb->ioFlCrDat = times->actime; + err = PBSetCatInfo (&cipbr, 0); + if (err != noErr) { + errno = EACCES; + return -1; + } + return 0; +} + +int +mkdir (char *path, int mode) +{ + errno = ENOSYS; + return -1; +} + +int +rmdir () +{ + errno = ENOSYS; + return -1; +} +#endif + +chown () +{ + errno = ENOSYS; + return -1; +} + +char *myenviron[] = {NULL}; + +char **environ = myenviron; + +#ifndef USE_MW_HEADERS + +/* Minimal 'stat' emulation: tells directories from files and + gives length and mtime. + + Derived from code written by Guido van Rossum, CWI, Amsterdam + and placed by him in the public domain. */ + +extern int __uid, __gid; + +int __uid = 0; +int __gid = 0; + +/* Bits in ioFlAttrib: */ +#define LOCKBIT (1<<0) /* File locked */ +#define DIRBIT (1<<4) /* It's a directory */ + +/* Macified "stat" in which filename is given relative to a directory, + specified by long DirID. */ + +static int +_stat (char *name, long dirid, struct stat *buf) +{ + CInfoPBRec cipbr; + HFileInfo *fpb = (HFileInfo*) &cipbr; + DirInfo *dpb = (DirInfo*) &cipbr; + Str255 pname; + short err; + + /* Make a temp copy of the name and pascalize. */ + strcpy ((char *) pname, name); + c2pstr (pname); + + cipbr.dirInfo.ioDrDirID = dirid; + cipbr.hFileInfo.ioNamePtr = pname; + cipbr.hFileInfo.ioVRefNum = 0; + cipbr.hFileInfo.ioFDirIndex = 0; + cipbr.hFileInfo.ioFVersNum = 0; + err = PBGetCatInfo (&cipbr, 0); + if (err != noErr) + { + errno = ENOENT; + return -1; + } + /* Mac files are readable if they can be accessed at all. */ + buf->st_mode = 0444; + /* Mark unlocked files as writeable. */ + if (!(fpb->ioFlAttrib & LOCKBIT)) + buf->st_mode |= 0222; + if (fpb->ioFlAttrib & DIRBIT) + { + /* Mark directories as "executable". */ + buf->st_mode |= 0111 | S_IFDIR; + buf->st_size = dpb->ioDrNmFls; + buf->st_rsize = 0; + } + else + { + buf->st_mode |= S_IFREG; + /* Mark apps as "executable". */ + if (fpb->ioFlFndrInfo.fdType == 'APPL') + buf->st_mode |= 0111; + /* Fill in the sizes of data and resource forks. */ + buf->st_size = fpb->ioFlLgLen; + buf->st_rsize = fpb->ioFlRLgLen; + } + /* Fill in various times. */ + buf->st_atime = fpb->ioFlCrDat; + buf->st_mtime = fpb->ioFlMdDat; + buf->st_ctime = fpb->ioFlCrDat; + /* Set up an imitation inode number. */ + buf->st_ino = (unsigned short) fpb->ioDirID; + /* Set up an imitation device. */ + GetVRefNum (buf->st_ino, &buf->st_dev); + buf->st_uid = __uid; + buf->st_gid = __gid; +/* buf->st_FlFndrInfo = fpb->ioFlFndrInfo; */ + return 0; +} + +/* stat() sets up an empty dirid. */ + +int +stat (char *path, struct stat *buf) +{ + long rslt, errnum; + char tmpname[256]; + + mpwify_filename (path, tmpname); + if (DebugPI) + fprintf (stderr, "# stat (%s, %x)", tmpname, buf); + PROGRESS (1); + rslt = _stat (tmpname, 0L, buf); + errnum = errno; + if (DebugPI) + { + fprintf (stderr, " -> %d", rslt); + if (rslt != 0) + fprintf (stderr, " (errno is %d)", errnum); + fprintf (stderr, "\n"); + fflush (stderr); + } + if (rslt != 0) + errno = errnum; + return rslt; +} + +int +fstat (int fd, struct stat *buf) +{ + FCBPBRec fcb; + FILE *fp; + Str255 pathname; + long dirid = 0L, temp; + long rslt, errnum; + short err; + + if (DebugPI) + fprintf (stderr, "# fstat (%d, %x)", fd, buf); + PROGRESS (1); + pathname[0] = 0; +#ifdef FIOFNAME + /* Use an MPW-specific ioctl to get the pathname associated with + the file descriptor. */ + ioctl (fd, FIOFNAME, (long *) pathname); +#else + you lose +#endif + if (DebugPI) + fprintf (stderr, " (name is %s)", pathname); + dirid = 0L /* fcb.ioFCBParID */ ; + rslt = _stat ((char *) pathname, dirid, buf); + errnum = errno; + if (DebugPI) + { + fprintf (stderr, " -> %d", rslt); + if (rslt != 0) + fprintf (stderr, " (errno is %d)", errnum); + fprintf (stderr, "\n"); + fflush (stderr); + } + if (rslt != 0) + errno = errnum; + return rslt; +} + +#endif /* n USE_MW_HEADERS */ + +chdir () +{ + errno = ENOSYS; + return (-1); +} + +char * +getcwd (char *buf, int size) +{ + if (buf == NULL) + buf = (char *) malloc (size); + strcpy(buf, ":"); + return buf; +} + +/* This should probably be more elaborate for MPW. */ + +char * +getpwd () +{ + return ":"; +} + +int +mpw_open (char *filename, int arg2, int arg3) +{ +#undef open + int fd, errnum = 0; + char tmpname[256]; + + mpwify_filename (filename, tmpname); + fd = open (tmpname, arg2); + errnum = errno; + + if (DebugPI) + { + fprintf (stderr, "# open (%s, %d, %d)", tmpname, arg2, arg3); + fprintf (stderr, " -> %d", fd); + if (fd == -1) + fprintf (stderr, " (errno is %d)", errnum); + fprintf (stderr, "\n"); + } + if (fd == -1) + errno = errnum; + return fd; +} + +int +mpw_access (char *filename, unsigned int cmd) +{ +#undef access + + int rslt, errnum = 0; + struct stat st; + char tmpname[256]; + + mpwify_filename (filename, tmpname); + if (cmd & R_OK || cmd & X_OK) + { + rslt = stat (tmpname, &st); + errnum = errno; + if (rslt >= 0) + { + if (((st.st_mode & 004 == 0) && (cmd & R_OK)) + || ((st.st_mode & 002 == 0) && (cmd & W_OK)) + || ((st.st_mode & 001 == 0) && (cmd & X_OK))) + { + rslt = -1; + errnum = EACCES; + } + } + } + if (DebugPI) + { + fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd); + fprintf (stderr, " -> %d", rslt); + if (rslt != 0) + fprintf (stderr, " (errno is %d)", errnum); + fprintf (stderr, "\n"); + } + if (rslt != 0) + errno = errnum; + return rslt; +} + +/* The MPW library creat() has no mode argument. */ + +int +mpw_creat (char *path, /* mode_t */ int mode) +{ +#undef creat + +#ifdef USE_MW_HEADERS + return creat (path, mode); +#else + return creat (path); +#endif +} + +/* This is a hack to get control in an MPW tool before it crashes the + machine. */ + +mpw_special_init (name) + char *name; +{ + if (strstr (name, "DEBUG")) + DebugStr("\pat beginning of program"); +} + +static int current_umask; + +int +umask(int mask) +{ + int oldmask = current_umask; + + current_umask = mask; + return oldmask; +} + +/* Cursor-spinning stuff that includes metering of spin rate and delays. */ + +/* Nonzero when cursor spinning has been set up properly. */ + +int cursor_inited; + +/* Nonzero if spin should be measured and excessive delays reported. */ + +int measure_spin; + +/* Nonzero if spin histogram and rate data should be written out. */ + +int dump_spin_data; + +long warning_threshold = 400000; + +long bucket_size = 1024; + +long bucket_power = 10; + +long numbuckets = 300; + +int *delay_counts; + +int overflow_count; + +char *current_progress; + +static UnsignedWide last_microseconds; + +static char *last_spin_file = ""; + +static int last_spin_line; + +void +warn_if_spin_delay (char *file, int line) +{ + long diff, ix; + UnsignedWide now; + + Microseconds(&now); + + diff = now.lo - last_microseconds.lo; + + if (diff > warning_threshold) + fprintf (stderr, "# %s: %ld.%06ld sec delay getting from %s:%d to %s:%d\n", + (current_progress ? current_progress : ""), + diff / 1000000, diff % 1000000, + last_spin_file, last_spin_line, file, line); + if (dump_spin_data) + { + if (diff >= 0) + { + ix = diff >> bucket_power; + if (ix >= 0 && ix < numbuckets && delay_counts != NULL) + ++delay_counts[ix]; + else + ++overflow_count; + } + else + fprintf (stderr, "raw diff is %ld (?)\n", diff); + } +} + +void +record_for_spin_delay (char *file, int line) +{ + Microseconds (&last_microseconds); + last_spin_file = file; + last_spin_line = line; +} + +void +mpw_start_progress (char *str, int n, char *file, int line) +{ + int i; + char *measure, *threshold; + + if (!cursor_inited) + { + InitCursorCtl (nil); + cursor_inited = 1; + record_for_spin_delay (file, line); + measure = getenv ("MEASURE_SPIN"); + if (measure != NULL && measure[0] != '\0') + { + measure_spin = 1; + if (strcmp (measure, "all") == 0) + dump_spin_data = 1; + } + threshold = getenv ((const char *) "SPIN_WARN_THRESHOLD"); + if (threshold != NULL && threshold[0] != '\0') + warning_threshold = atol (threshold); + if (dump_spin_data) + { + if (delay_counts == NULL) + delay_counts = (int *) malloc (numbuckets * sizeof (int)); + for (i = 0; i < numbuckets; ++i) + delay_counts[i] = 0; + overflow_count = 0; + } + } + current_progress = str; + + sys_nerr = errno_max (); + + mpw_special_init (str); +} + +void +mpw_progress (int n) +{ + SpinCursor (32); +} + +void +mpw_progress_measured (int n, char *file, int line) +{ + if (measure_spin) + warn_if_spin_delay (file, line); + SpinCursor (32); + if (measure_spin) + record_for_spin_delay (file, line); +} + +void +mpw_end_progress (char *str, char *file, int line) +{ + long i, delay, count = 0, sum = 0, avgdelay, spinrate; + long curpower = 0, curgroup = 0; + + /* Warn if it's been a while since the last spin. */ + if (measure_spin) + warn_if_spin_delay (file, line); + + /* Dump all the nonzero delay counts and an approximation of the delay. */ + if (dump_spin_data && delay_counts != NULL) + { + for (i = 0; i < numbuckets; ++i) + { + delay = (i + 1) * bucket_size; + sum += delay_counts[i] * (i + 1); + count += delay_counts[i]; + if (delay <= (1 << curpower)) + { + curgroup += delay_counts[i]; + } + else + { + if (curgroup > 0) + fprintf (stderr, + "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n", + (str ? str : ""), + curgroup, + (1 << curpower) / 1000000, + (1 << curpower) % 1000000, + (1 << (curpower + 1)) / 1000000, + (1 << (curpower + 1)) % 1000000); + ++curpower; + curgroup = 0; + } + } + if (count > 0) + { + avgdelay = (sum * bucket_size) / count; + spinrate = 1000000 / avgdelay; + fprintf (stderr, "# %s: Average spin rate is %d times/sec\n", + (str ? str : ""), spinrate); + } + } +} + +#ifdef PROGRESS_TEST + +/* Test program. */ + +main () +{ + int i, j; + double x = 1.0, y = 2.4; + long start = Microseconds (), tm; FIXME + + START_PROGRESS ("hi", 0); + + for (i = 0; i < 1000; ++i) + { + PROGRESS (1); + + for (j = 0; j < (i * 100); ++j) + { + x += (x * y) / j; + } + } + + END_PROGRESS ("hi"); + + tm = Microseconds () - start; + + printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000); +} + +#endif + +#ifdef USE_MW_HEADERS +/* Empty definitions for Metrowerks' SIOUX console library. */ + +#ifndef __CONSOLE__ +#include +#endif + +short +InstallConsole(short fd) +{ +#pragma unused (fd) + return 0; +} + +void +RemoveConsole(void) +{ +} + +long +WriteCharsToConsole(char *buf, long n) +{ +#pragma unused (buf, n) + return 0; +} + +long ReadCharsFromConsole(char *buf, long n) +{ +#pragma unused (buf, n) + return 0; +} + +extern char * +__ttyname(long fd) +{ + static char *__devicename = "null device"; + + if (fd >= 0 && fd <= 2) + return (__devicename); + return NULL; +} + +#endif diff --git a/contrib/gdb/libiberty/msdos.c b/contrib/gdb/libiberty/msdos.c new file mode 100644 index 000000000000..923e64d4ede6 --- /dev/null +++ b/contrib/gdb/libiberty/msdos.c @@ -0,0 +1,15 @@ +char msg[] = "No vfork available - aborting\n"; +vfork() +{ + write(1, msg, sizeof(msg)); +} + +sigsetmask() +{ + /* no signals support in go32 (yet) */ +} + +waitpid() +{ + return -1; +} diff --git a/contrib/gdb/libiberty/obstack.c b/contrib/gdb/libiberty/obstack.c new file mode 100644 index 000000000000..2d380940efce --- /dev/null +++ b/contrib/gdb/libiberty/obstack.c @@ -0,0 +1,507 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988, 89, 90, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published by the +Free Software Foundation; either version 2, 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 Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "obstack.h" + +/* This is just to get __GNU_LIBRARY__ defined. */ +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +/* CYGNUS LOCAL. No, don't comment the code out. We will be using + ../include/obstack.h, which was changed relatively recently in a + way that is not binary compatible. Until we feel confident that + nobody is using the old obstack.c code, force the use of this code. + This issue will arise anytime a change is made which is not binary + compatible. +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) +*/ +#if 1 + + +#ifdef __STDC__ +#define POINTER void * +#else +#define POINTER char * +#endif + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT \ + ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0)) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Define a macro that either calls functions with the traditional malloc/free + calling interface, or calls functions with the mmalloc/mfree interface + (that adds an extra first argument), based on the state of use_extra_arg. + For free, do not use ?:, since some compilers, like the MIPS compilers, + do not allow (expr) ? void : void. */ + +#define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(h)->chunkfun) ((size))) + +#define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(h)->freefun) ((old_chunk)); \ + } while (0) + + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. + + Return nonzero if successful, zero if out of memory. + To recover from an out of memory error, + free up some memory, then call this again. */ + +int +_obstack_begin (h, size, alignment, chunkfun, freefun) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->use_extra_arg = 0; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + { + h->alloc_failed = 1; + return 0; + } + h->alloc_failed = 0; + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + return 1; +} + +int +_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); + POINTER arg; +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->extra_arg = arg; + h->use_extra_arg = 1; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + { + h->alloc_failed = 1; + return 0; + } + h->alloc_failed = 0; + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + return 1; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (h, length) + struct obstack *h; + int length; +{ + register struct _obstack_chunk* old_chunk = h->chunk; + register struct _obstack_chunk* new_chunk; + register long new_size; + register int obj_size = h->next_free - h->object_base; + register int i; + int already; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = CALL_CHUNKFUN (h, new_size); + if (!new_chunk) + { + h->alloc_failed = 1; + return; + } + h->alloc_failed = 0; + h->chunk = new_chunk; + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + new_chunk->contents[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. + But not if that chunk might contain an empty object. */ + if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) + { + new_chunk->prev = old_chunk->prev; + CALL_FREEFUN (h, old_chunk); + } + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +#ifdef __STDC__ +/* Suppress -Wmissing-prototypes warning. We don't want to declare this in + obstack.h because it is just for debugging. */ +int _obstack_allocated_p (struct obstack *h, POINTER obj); +#endif + +int +_obstack_allocated_p (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +#undef obstack_free + +/* This function has two names with identical definitions. + This is the first one, called from non-ANSI code. */ + +void +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *)(obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* This function is used from ANSI code. */ + +void +obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *)(obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +int +_obstack_memory_used (h) + struct obstack *h; +{ + register struct _obstack_chunk* lp; + register int nbytes = 0; + + for (lp = h->chunk; lp != 0; lp = lp->prev) + { + nbytes += lp->limit - (char *) lp; + } + return nbytes; +} + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +#endif /* 0 */ + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/contrib/gdb/libiberty/random.c b/contrib/gdb/libiberty/random.c new file mode 100644 index 000000000000..e205719832b9 --- /dev/null +++ b/contrib/gdb/libiberty/random.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + */ + +#include + +#if 0 + +#include +#include +#include +#include + +#else + +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */ +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits*/ + +#ifdef __STDC__ +# define PTR void * +# define NULL (void *) 0 +#else +# define PTR char * +# define NULL 0 +#endif + +#endif + +long int random (); + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initiallized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroeth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroeth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least thi + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroeth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static long int randtbl[DEG_3 + 1] = + { TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, + 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, + 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, + 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, + 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, + 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 + }; + +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + +static long int *fptr = &randtbl[SEP_3 + 1]; +static long int *rptr = &randtbl[1]; + + + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroeth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + +static long int *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +void +srandom (x) + unsigned int x; +{ + state[0] = x; + if (rand_type != TYPE_0) + { + register long int i; + for (i = 1; i < rand_deg; ++i) + state[i] = (1103515145 * state[i - 1]) + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; ++i) + random(); + } +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +PTR +initstate (seed, arg_state, n) + unsigned int seed; + PTR arg_state; + unsigned long n; +{ + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + if (n < BREAK_1) + { + if (n < BREAK_0) + { + errno = EINVAL; + return NULL; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } + else if (n < BREAK_2) + { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } + else if (n < BREAK_3) + { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } + else if (n < BREAK_4) + { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } + else + { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + + state = &((long int *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + end_ptr = &state[rand_deg]; + srandom(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + return ostate; +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroeth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ + +PTR +setstate (arg_state) + PTR arg_state; +{ + register long int *new_state = (long int *) arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + PTR ostate = (PTR) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + switch (type) + { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + /* State info munged. */ + errno = EINVAL; + return NULL; + } + + state = &new_state[1]; + if (rand_type != TYPE_0) + { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + /* Set end_ptr too. */ + end_ptr = &state[rand_deg]; + + return ostate; +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all ther other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int +random () +{ + if (rand_type == TYPE_0) + { + state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; + return state[0]; + } + else + { + long int i; + *fptr += *rptr; + /* Chucking least random bit. */ + i = (*fptr >> 1) & LONG_MAX; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + return i; + } +} diff --git a/contrib/gdb/libiberty/rename.c b/contrib/gdb/libiberty/rename.c new file mode 100644 index 000000000000..ae26e2d00407 --- /dev/null +++ b/contrib/gdb/libiberty/rename.c @@ -0,0 +1,22 @@ +/* rename -- rename a file + This function is in the public domain. */ + +/* Rename a file. */ + +#include + +int +rename (zfrom, zto) + char *zfrom; + char *zto; +{ + if (link (zfrom, zto) < 0) + { + if (errno != EEXIST) + return -1; + if (unlink (zto) < 0 + || link (zfrom, zto) < 0) + return -1; + } + return unlink (zfrom); +} diff --git a/contrib/gdb/libiberty/rindex.c b/contrib/gdb/libiberty/rindex.c new file mode 100644 index 000000000000..061d1269f178 --- /dev/null +++ b/contrib/gdb/libiberty/rindex.c @@ -0,0 +1,11 @@ +/* Stub implementation of (obsolete) rindex(). */ + +extern char *strrchr (); + +char * +rindex (s, c) + char *s; + int c; +{ + return strrchr (s, c); +} diff --git a/contrib/gdb/libiberty/sigsetmask.c b/contrib/gdb/libiberty/sigsetmask.c new file mode 100644 index 000000000000..2a09e6a6c5ac --- /dev/null +++ b/contrib/gdb/libiberty/sigsetmask.c @@ -0,0 +1,30 @@ +/* Version of sigsetmask.c + Written by Steve Chamberlain (sac@cygnus.com). + Contributed by Cygnus Support. + This file is in the public doamin. */ + +/* Set the current signal mask to the set provided, and return the + previous value */ + +#define _POSIX_SOURCE +#include +/* Including seems to be needed by ISC. */ +#include +#include + +#ifdef SIG_SETMASK +int +DEFUN(sigsetmask,(set), + int set) +{ + sigset_t new; + sigset_t old; + + sigemptyset (&new); + if (set != 0) { + abort(); /* FIXME, we don't know how to translate old mask to new */ + } + sigprocmask(SIG_SETMASK, &new, &old); + return 1; /* FIXME, we always return 1 as old value. */ +} +#endif diff --git a/contrib/gdb/libiberty/spaces.c b/contrib/gdb/libiberty/spaces.c new file mode 100644 index 000000000000..7ea8532d7f6f --- /dev/null +++ b/contrib/gdb/libiberty/spaces.c @@ -0,0 +1,71 @@ +/* Allocate memory region filled with spaces. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +NAME + + spaces -- return a pointer to a buffer full of spaces + +SYNOPSIS + + char *spaces (int count) + +DESCRIPTION + + Returns a pointer to a memory region filled with the specified + number of spaces and null terminated. The returned pointer is + valid until at least the next call. + +BUGS + +*/ + +#include "ansidecl.h" +#include "libiberty.h" + +const char * +spaces (count) + int count; +{ + register char *t; + static char *buf; + static int maxsize; + extern char *malloc (); + extern void free (); + + if (count > maxsize) + { + if (buf) + { + free (buf); + } + buf = malloc (count + 1); + if (buf == (char *) 0) + return 0; + for (t = buf + count ; t != buf ; ) + { + *--t = ' '; + } + maxsize = count; + buf[count] = '\0'; + } + return (const char *) (buf + maxsize - count); +} + diff --git a/contrib/gdb/libiberty/strcasecmp.c b/contrib/gdb/libiberty/strcasecmp.c new file mode 100644 index 000000000000..53387ca1b3ee --- /dev/null +++ b/contrib/gdb/libiberty/strcasecmp.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; +#endif /* LIBC_SCCS and not lint */ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static unsigned char charmap[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; + +int +strcasecmp(s1, s2) + const char *s1, *s2; +{ + register unsigned char u1, u2; + + for (;;) { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } +} + diff --git a/contrib/gdb/libiberty/strchr.c b/contrib/gdb/libiberty/strchr.c new file mode 100644 index 000000000000..22976ce248af --- /dev/null +++ b/contrib/gdb/libiberty/strchr.c @@ -0,0 +1,34 @@ +/* Portable version of strchr() + This function is in the public domain. */ + +/* +NAME + strchr -- return pointer to first occurance of a character + +SYNOPSIS + char *strchr (const char *s, int c) + +DESCRIPTION + Returns a pointer to the first occurance of character C in + string S, or a NULL pointer if no occurance is found. + +BUGS + Behavior when character is the null character is implementation + dependent. +*/ + +#include + +char * +strchr (s, c) + register CONST char *s; + int c; +{ + do { + if (*s == c) + { + return (char*)s; + } + } while (*s++); + return (0); +} diff --git a/contrib/gdb/libiberty/strdup.c b/contrib/gdb/libiberty/strdup.c new file mode 100644 index 000000000000..1785b34f2745 --- /dev/null +++ b/contrib/gdb/libiberty/strdup.c @@ -0,0 +1,10 @@ +char * +strdup(s) + char *s; +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} diff --git a/contrib/gdb/libiberty/strerror.c b/contrib/gdb/libiberty/strerror.c new file mode 100644 index 000000000000..9f3f92b3d1a7 --- /dev/null +++ b/contrib/gdb/libiberty/strerror.c @@ -0,0 +1,829 @@ +/* Extended support for using errno values. + Written by Fred Fish. fnf@cygnus.com + This file is in the public domain. --Per Bothner. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#include "config.h" + +#ifndef NEED_sys_errlist +/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) + might declare sys_errlist in a way that the compiler might consider + incompatible with our later declaration, perhaps by using const + attributes. So we hide the declaration in errno.h (if any) using a + macro. */ +#define sys_errlist sys_errlist__ +#endif + +#include +#include + +#ifndef NEED_sys_errlist +#undef sys_errlist +#endif + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ +#include +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ +#else /* !__STDC__ */ +extern char *malloc (); /* Standard memory allocater */ +extern char *memset (); +#endif /* __STDC__ */ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* Translation table for errno values. See intro(2) in most UNIX systems + Programmers Reference Manuals. + + Note that this table is generally only accessed when it is used at runtime + to initialize errno name and message tables that are indexed by errno + value. + + Not all of these errnos will exist on all systems. This table is the only + thing that should have to be updated as new error numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct error_info +{ + int value; /* The numeric value from */ + const char *name; /* The equivalent symbolic value */ +#ifdef NEED_sys_errlist + const char *msg; /* Short message about this value */ +#endif +}; + +#ifdef NEED_sys_errlist +# define ENTRY(value, name, msg) {value, name, msg} +#else +# define ENTRY(value, name, msg) {value, name} +#endif + +static const struct error_info error_table[] = +{ +#if defined (EPERM) + ENTRY(EPERM, "EPERM", "Not owner"), +#endif +#if defined (ENOENT) + ENTRY(ENOENT, "ENOENT", "No such file or directory"), +#endif +#if defined (ESRCH) + ENTRY(ESRCH, "ESRCH", "No such process"), +#endif +#if defined (EINTR) + ENTRY(EINTR, "EINTR", "Interrupted system call"), +#endif +#if defined (EIO) + ENTRY(EIO, "EIO", "I/O error"), +#endif +#if defined (ENXIO) + ENTRY(ENXIO, "ENXIO", "No such device or address"), +#endif +#if defined (E2BIG) + ENTRY(E2BIG, "E2BIG", "Arg list too long"), +#endif +#if defined (ENOEXEC) + ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"), +#endif +#if defined (EBADF) + ENTRY(EBADF, "EBADF", "Bad file number"), +#endif +#if defined (ECHILD) + ENTRY(ECHILD, "ECHILD", "No child processes"), +#endif +#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ + ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"), +#endif +#if defined (EAGAIN) + ENTRY(EAGAIN, "EAGAIN", "No more processes"), +#endif +#if defined (ENOMEM) + ENTRY(ENOMEM, "ENOMEM", "Not enough space"), +#endif +#if defined (EACCES) + ENTRY(EACCES, "EACCES", "Permission denied"), +#endif +#if defined (EFAULT) + ENTRY(EFAULT, "EFAULT", "Bad address"), +#endif +#if defined (ENOTBLK) + ENTRY(ENOTBLK, "ENOTBLK", "Block device required"), +#endif +#if defined (EBUSY) + ENTRY(EBUSY, "EBUSY", "Device busy"), +#endif +#if defined (EEXIST) + ENTRY(EEXIST, "EEXIST", "File exists"), +#endif +#if defined (EXDEV) + ENTRY(EXDEV, "EXDEV", "Cross-device link"), +#endif +#if defined (ENODEV) + ENTRY(ENODEV, "ENODEV", "No such device"), +#endif +#if defined (ENOTDIR) + ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"), +#endif +#if defined (EISDIR) + ENTRY(EISDIR, "EISDIR", "Is a directory"), +#endif +#if defined (EINVAL) + ENTRY(EINVAL, "EINVAL", "Invalid argument"), +#endif +#if defined (ENFILE) + ENTRY(ENFILE, "ENFILE", "File table overflow"), +#endif +#if defined (EMFILE) + ENTRY(EMFILE, "EMFILE", "Too many open files"), +#endif +#if defined (ENOTTY) + ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"), +#endif +#if defined (ETXTBSY) + ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"), +#endif +#if defined (EFBIG) + ENTRY(EFBIG, "EFBIG", "File too large"), +#endif +#if defined (ENOSPC) + ENTRY(ENOSPC, "ENOSPC", "No space left on device"), +#endif +#if defined (ESPIPE) + ENTRY(ESPIPE, "ESPIPE", "Illegal seek"), +#endif +#if defined (EROFS) + ENTRY(EROFS, "EROFS", "Read-only file system"), +#endif +#if defined (EMLINK) + ENTRY(EMLINK, "EMLINK", "Too many links"), +#endif +#if defined (EPIPE) + ENTRY(EPIPE, "EPIPE", "Broken pipe"), +#endif +#if defined (EDOM) + ENTRY(EDOM, "EDOM", "Math argument out of domain of func"), +#endif +#if defined (ERANGE) + ENTRY(ERANGE, "ERANGE", "Math result not representable"), +#endif +#if defined (ENOMSG) + ENTRY(ENOMSG, "ENOMSG", "No message of desired type"), +#endif +#if defined (EIDRM) + ENTRY(EIDRM, "EIDRM", "Identifier removed"), +#endif +#if defined (ECHRNG) + ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"), +#endif +#if defined (EL2NSYNC) + ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"), +#endif +#if defined (EL3HLT) + ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"), +#endif +#if defined (EL3RST) + ENTRY(EL3RST, "EL3RST", "Level 3 reset"), +#endif +#if defined (ELNRNG) + ENTRY(ELNRNG, "ELNRNG", "Link number out of range"), +#endif +#if defined (EUNATCH) + ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"), +#endif +#if defined (ENOCSI) + ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"), +#endif +#if defined (EL2HLT) + ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"), +#endif +#if defined (EDEADLK) + ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"), +#endif +#if defined (ENOLCK) + ENTRY(ENOLCK, "ENOLCK", "No record locks available"), +#endif +#if defined (EBADE) + ENTRY(EBADE, "EBADE", "Invalid exchange"), +#endif +#if defined (EBADR) + ENTRY(EBADR, "EBADR", "Invalid request descriptor"), +#endif +#if defined (EXFULL) + ENTRY(EXFULL, "EXFULL", "Exchange full"), +#endif +#if defined (ENOANO) + ENTRY(ENOANO, "ENOANO", "No anode"), +#endif +#if defined (EBADRQC) + ENTRY(EBADRQC, "EBADRQC", "Invalid request code"), +#endif +#if defined (EBADSLT) + ENTRY(EBADSLT, "EBADSLT", "Invalid slot"), +#endif +#if defined (EDEADLOCK) + ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"), +#endif +#if defined (EBFONT) + ENTRY(EBFONT, "EBFONT", "Bad font file format"), +#endif +#if defined (ENOSTR) + ENTRY(ENOSTR, "ENOSTR", "Device not a stream"), +#endif +#if defined (ENODATA) + ENTRY(ENODATA, "ENODATA", "No data available"), +#endif +#if defined (ETIME) + ENTRY(ETIME, "ETIME", "Timer expired"), +#endif +#if defined (ENOSR) + ENTRY(ENOSR, "ENOSR", "Out of streams resources"), +#endif +#if defined (ENONET) + ENTRY(ENONET, "ENONET", "Machine is not on the network"), +#endif +#if defined (ENOPKG) + ENTRY(ENOPKG, "ENOPKG", "Package not installed"), +#endif +#if defined (EREMOTE) + ENTRY(EREMOTE, "EREMOTE", "Object is remote"), +#endif +#if defined (ENOLINK) + ENTRY(ENOLINK, "ENOLINK", "Link has been severed"), +#endif +#if defined (EADV) + ENTRY(EADV, "EADV", "Advertise error"), +#endif +#if defined (ESRMNT) + ENTRY(ESRMNT, "ESRMNT", "Srmount error"), +#endif +#if defined (ECOMM) + ENTRY(ECOMM, "ECOMM", "Communication error on send"), +#endif +#if defined (EPROTO) + ENTRY(EPROTO, "EPROTO", "Protocol error"), +#endif +#if defined (EMULTIHOP) + ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"), +#endif +#if defined (EDOTDOT) + ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"), +#endif +#if defined (EBADMSG) + ENTRY(EBADMSG, "EBADMSG", "Not a data message"), +#endif +#if defined (ENAMETOOLONG) + ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"), +#endif +#if defined (EOVERFLOW) + ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"), +#endif +#if defined (ENOTUNIQ) + ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"), +#endif +#if defined (EBADFD) + ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"), +#endif +#if defined (EREMCHG) + ENTRY(EREMCHG, "EREMCHG", "Remote address changed"), +#endif +#if defined (ELIBACC) + ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"), +#endif +#if defined (ELIBBAD) + ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"), +#endif +#if defined (ELIBSCN) + ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"), +#endif +#if defined (ELIBMAX) + ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"), +#endif +#if defined (ELIBEXEC) + ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"), +#endif +#if defined (EILSEQ) + ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"), +#endif +#if defined (ENOSYS) + ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"), +#endif +#if defined (ELOOP) + ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"), +#endif +#if defined (ERESTART) + ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"), +#endif +#if defined (ESTRPIPE) + ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"), +#endif +#if defined (ENOTEMPTY) + ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"), +#endif +#if defined (EUSERS) + ENTRY(EUSERS, "EUSERS", "Too many users"), +#endif +#if defined (ENOTSOCK) + ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"), +#endif +#if defined (EDESTADDRREQ) + ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"), +#endif +#if defined (EMSGSIZE) + ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"), +#endif +#if defined (EPROTOTYPE) + ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"), +#endif +#if defined (ENOPROTOOPT) + ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"), +#endif +#if defined (EPROTONOSUPPORT) + ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"), +#endif +#if defined (ESOCKTNOSUPPORT) + ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"), +#endif +#if defined (EOPNOTSUPP) + ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"), +#endif +#if defined (EPFNOSUPPORT) + ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"), +#endif +#if defined (EAFNOSUPPORT) + ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"), +#endif +#if defined (EADDRINUSE) + ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"), +#endif +#if defined (EADDRNOTAVAIL) + ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"), +#endif +#if defined (ENETDOWN) + ENTRY(ENETDOWN, "ENETDOWN", "Network is down"), +#endif +#if defined (ENETUNREACH) + ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"), +#endif +#if defined (ENETRESET) + ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"), +#endif +#if defined (ECONNABORTED) + ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"), +#endif +#if defined (ECONNRESET) + ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"), +#endif +#if defined (ENOBUFS) + ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"), +#endif +#if defined (EISCONN) + ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"), +#endif +#if defined (ENOTCONN) + ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"), +#endif +#if defined (ESHUTDOWN) + ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"), +#endif +#if defined (ETOOMANYREFS) + ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"), +#endif +#if defined (ETIMEDOUT) + ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"), +#endif +#if defined (ECONNREFUSED) + ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"), +#endif +#if defined (EHOSTDOWN) + ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"), +#endif +#if defined (EHOSTUNREACH) + ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"), +#endif +#if defined (EALREADY) + ENTRY(EALREADY, "EALREADY", "Operation already in progress"), +#endif +#if defined (EINPROGRESS) + ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"), +#endif +#if defined (ESTALE) + ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"), +#endif +#if defined (EUCLEAN) + ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"), +#endif +#if defined (ENOTNAM) + ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"), +#endif +#if defined (ENAVAIL) + ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"), +#endif +#if defined (EISNAM) + ENTRY(EISNAM, "EISNAM", "Is a named type file"), +#endif +#if defined (EREMOTEIO) + ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"), +#endif + ENTRY(0, NULL, NULL) +}; + +#ifdef EVMSERR +/* This is not in the table, because the numeric value of EVMSERR (32767) + lies outside the range of sys_errlist[]. */ +static struct { int value; const char *name, *msg; } + evmserr = { EVMSERR, "EVMSERR", "VMS-specific error" }; +#endif + +/* Translation table allocated and initialized at runtime. Indexed by the + errno value to find the equivalent symbolic value. */ + +static const char **error_names; +static int num_error_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the errno value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifdef NEED_sys_errlist + +static int sys_nerr; +static const char **sys_errlist; + +#else + +extern int sys_nerr; +extern char *sys_errlist[]; + +#endif + + +/* + +NAME + + init_error_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_error_tables (); + +DESCRIPTION + + Using the error_table, which is initialized at compile time, generate + the error_names and the sys_errlist (if needed) tables, which are + indexed at runtime by a specific errno value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_error_tables () +{ + const struct error_info *eip; + int nbytes; + + /* If we haven't already scanned the error_table once to find the maximum + errno value, then go find it now. */ + + if (num_error_names == 0) + { + for (eip = error_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_error_names) + { + num_error_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the error_names table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (error_names == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((error_names = (const char **) malloc (nbytes)) != NULL) + { + memset (error_names, 0, nbytes); + for (eip = error_table; eip -> name != NULL; eip++) + { + error_names[eip -> value] = eip -> name; + } + } + } + +#ifdef NEED_sys_errlist + + /* Now attempt to allocate the sys_errlist table, zero it out, and then + initialize it from the statically initialized error_table. */ + + if (sys_errlist == NULL) + { + nbytes = num_error_names * sizeof (char *); + if ((sys_errlist = (const char **) malloc (nbytes)) != NULL) + { + memset (sys_errlist, 0, nbytes); + sys_nerr = num_error_names; + for (eip = error_table; eip -> name != NULL; eip++) + { + sys_errlist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + +/* + +NAME + + errno_max -- return the max errno value + +SYNOPSIS + + int errno_max (); + +DESCRIPTION + + Returns the maximum errno value for which a corresponding symbolic + name or message is available. Note that in the case where + we use the sys_errlist supplied by the system, it is possible for + there to be more symbolic names than messages, or vice versa. + In fact, the manual page for perror(3C) explicitly warns that one + should check the size of the table (sys_nerr) before indexing it, + since new error codes may be added to the system before they are + added to the table. Thus sys_nerr might be smaller than value + implied by the largest errno value defined in . + + We return the maximum value that can be used to obtain a meaningful + symbolic name or message. + +*/ + +int +errno_max () +{ + int maxsize; + + if (error_names == NULL) + { + init_error_tables (); + } + maxsize = MAX (sys_nerr, num_error_names); + return (maxsize - 1); +} + +#ifdef NEED_strerror + +/* + +NAME + + strerror -- map an error number to an error message string + +SYNOPSIS + + char *strerror (int errnoval) + +DESCRIPTION + + Maps an errno number to an error message string, the contents of + which are implementation defined. On systems which have the external + variables sys_nerr and sys_errlist, these strings will be the same + as the ones used by perror(). + + If the supplied error number is within the valid range of indices + for the sys_errlist, but no message is available for the particular + error number, then returns the string "Error NUM", where NUM is the + error number. + + If the supplied error number is not a valid index into sys_errlist, + returns NULL. + + The returned string is only guaranteed to be valid only until the + next call to strerror. + +*/ + +char * +strerror (errnoval) + int errnoval; +{ + char *msg; + static char buf[32]; + +#ifdef NEED_sys_errlist + + if (error_names == NULL) + { + init_error_tables (); + } + +#endif + + if ((errnoval < 0) || (errnoval >= sys_nerr)) + { +#ifdef EVMSERR + if (errnoval == evmserr.value) + msg = evmserr.msg; + else +#endif + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) + { + /* In range, but no sys_errlist or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + msg = buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = (char *) sys_errlist[errnoval]; + } + + return (msg); +} + +#endif /* NEED_strerror */ + + +/* + +NAME + + strerrno -- map an error number to a symbolic name string + +SYNOPSIS + + const char *strerrno (int errnoval) + +DESCRIPTION + + Given an error number returned from a system call (typically + returned in errno), returns a pointer to a string containing the + symbolic name of that error number, as found in . + + If the supplied error number is within the valid range of indices + for symbolic names, but no name is available for the particular + error number, then returns the string "Error NUM", where NUM is + the error number. + + If the supplied error number is not within the range of valid + indices, then returns NULL. + +BUGS + + The contents of the location pointed to are only guaranteed to be + valid until the next call to strerrno. + +*/ + +const char * +strerrno (errnoval) + int errnoval; +{ + const char *name; + static char buf[32]; + + if (error_names == NULL) + { + init_error_tables (); + } + + if ((errnoval < 0) || (errnoval >= num_error_names)) + { +#ifdef EVMSERR + if (errnoval == evmserr.value) + name = evmserr.name; + else +#endif + /* Out of range, just return NULL */ + name = NULL; + } + else if ((error_names == NULL) || (error_names[errnoval] == NULL)) + { + /* In range, but no error_names or no entry at this index. */ + sprintf (buf, "Error %d", errnoval); + name = (const char *) buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = error_names[errnoval]; + } + + return (name); +} + +/* + +NAME + + strtoerrno -- map a symbolic errno name to a numeric value + +SYNOPSIS + + int strtoerrno (char *name) + +DESCRIPTION + + Given the symbolic name of a error number, map it to an errno value. + If no translation is found, returns 0. + +*/ + +int +strtoerrno (name) + const char *name; +{ + int errnoval = 0; + + if (name != NULL) + { + if (error_names == NULL) + { + init_error_tables (); + } + for (errnoval = 0; errnoval < num_error_names; errnoval++) + { + if ((error_names[errnoval] != NULL) && + (strcmp (name, error_names[errnoval]) == 0)) + { + break; + } + } + if (errnoval == num_error_names) + { +#ifdef EVMSERR + if (strcmp (name, evmserr.name) == 0) + errnoval = evmserr.value; + else +#endif + errnoval = 0; + } + } + return (errnoval); +} + + +/* A simple little main that does nothing but print all the errno translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +#include + +int +main () +{ + int errn; + int errnmax; + const char *name; + char *msg; + char *strerror (); + + errnmax = errno_max (); + printf ("%d entries in names table.\n", num_error_names); + printf ("%d entries in messages table.\n", sys_nerr); + printf ("%d is max useful index.\n", errnmax); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (errn = 0; errn <= errnmax; errn++) + { + name = strerrno (errn); + name = (name == NULL) ? "" : name; + msg = strerror (errn); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", errn, name, msg); + } + + return 0; +} + +#endif diff --git a/contrib/gdb/libiberty/strncasecmp.c b/contrib/gdb/libiberty/strncasecmp.c new file mode 100644 index 000000000000..4485cac7a6a2 --- /dev/null +++ b/contrib/gdb/libiberty/strncasecmp.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; +#endif /* LIBC_SCCS and not lint */ + +#include +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static unsigned char charmap[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; + +int +strncasecmp(s1, s2, n) + const char *s1, *s2; + register size_t n; +{ + register unsigned char u1, u2; + + for (; n != 0; --n) { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } + return 0; +} diff --git a/contrib/gdb/libiberty/strrchr.c b/contrib/gdb/libiberty/strrchr.c new file mode 100644 index 000000000000..30f9e8a3658a --- /dev/null +++ b/contrib/gdb/libiberty/strrchr.c @@ -0,0 +1,34 @@ +/* Portable version of strrchr(). + This function is in the public domain. */ + +/* +NAME + strrchr -- return pointer to last occurance of a character + +SYNOPSIS + char *strrchr (const char *s, int c) + +DESCRIPTION + Returns a pointer to the last occurance of character C in + string S, or a NULL pointer if no occurance is found. + +BUGS + Behavior when character is the null character is implementation + dependent. +*/ + +#include + +char * +strrchr (s, c) + register CONST char *s; + int c; +{ + char *rtnval = 0; + + do { + if (*s == c) + rtnval = (char*) s; + } while (*s++); + return (rtnval); +} diff --git a/contrib/gdb/libiberty/strsignal.c b/contrib/gdb/libiberty/strsignal.c new file mode 100644 index 000000000000..c4dd63c80981 --- /dev/null +++ b/contrib/gdb/libiberty/strsignal.c @@ -0,0 +1,627 @@ +/* Extended support for using signal values. + Written by Fred Fish. fnf@cygnus.com + This file is in the public domain. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#include "config.h" + +#ifdef LOSING_SYS_SIGLIST +#define sys_siglist no_such_symbol +#endif + +#include +#include + +/* Routines imported from standard C runtime libraries. */ + +#ifdef __STDC__ +#include +extern void *malloc (size_t size); /* 4.10.3.3 */ +extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ +#else /* !__STDC__ */ +extern char *malloc (); /* Standard memory allocater */ +extern char *memset (); +#endif /* __STDC__ */ + +#ifdef LOSING_SYS_SIGLIST +#undef sys_siglist +#endif + + +#ifndef NULL +# ifdef __STDC__ +# define NULL (void *) 0 +# else +# define NULL 0 +# endif +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* Translation table for signal values. + + Note that this table is generally only accessed when it is used at runtime + to initialize signal name and message tables that are indexed by signal + value. + + Not all of these signals will exist on all systems. This table is the only + thing that should have to be updated as new signal numbers are introduced. + It's sort of ugly, but at least its portable. */ + +struct signal_info +{ + int value; /* The numeric value from */ + const char *name; /* The equivalent symbolic value */ +#ifdef NEED_sys_siglist + const char *msg; /* Short message about this value */ +#endif +}; + +#ifdef NEED_sys_siglist +# define ENTRY(value, name, msg) {value, name, msg} +#else +# define ENTRY(value, name, msg) {value, name} +#endif + +static const struct signal_info signal_table[] = +{ +#if defined (SIGHUP) + ENTRY(SIGHUP, "SIGHUP", "Hangup"), +#endif +#if defined (SIGINT) + ENTRY(SIGINT, "SIGINT", "Interrupt"), +#endif +#if defined (SIGQUIT) + ENTRY(SIGQUIT, "SIGQUIT", "Quit"), +#endif +#if defined (SIGILL) + ENTRY(SIGILL, "SIGILL", "Illegal instruction"), +#endif +#if defined (SIGTRAP) + ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"), +#endif +/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT + overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ +#if defined (SIGIOT) + ENTRY(SIGIOT, "SIGIOT", "IOT trap"), +#endif +#if defined (SIGABRT) + ENTRY(SIGABRT, "SIGABRT", "Aborted"), +#endif +#if defined (SIGEMT) + ENTRY(SIGEMT, "SIGEMT", "Emulation trap"), +#endif +#if defined (SIGFPE) + ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"), +#endif +#if defined (SIGKILL) + ENTRY(SIGKILL, "SIGKILL", "Killed"), +#endif +#if defined (SIGBUS) + ENTRY(SIGBUS, "SIGBUS", "Bus error"), +#endif +#if defined (SIGSEGV) + ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"), +#endif +#if defined (SIGSYS) + ENTRY(SIGSYS, "SIGSYS", "Bad system call"), +#endif +#if defined (SIGPIPE) + ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"), +#endif +#if defined (SIGALRM) + ENTRY(SIGALRM, "SIGALRM", "Alarm clock"), +#endif +#if defined (SIGTERM) + ENTRY(SIGTERM, "SIGTERM", "Terminated"), +#endif +#if defined (SIGUSR1) + ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"), +#endif +#if defined (SIGUSR2) + ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"), +#endif +/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD + overrides SIGCLD. SIGCHLD is in POXIX.1 */ +#if defined (SIGCLD) + ENTRY(SIGCLD, "SIGCLD", "Child status changed"), +#endif +#if defined (SIGCHLD) + ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"), +#endif +#if defined (SIGPWR) + ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"), +#endif +#if defined (SIGWINCH) + ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"), +#endif +#if defined (SIGURG) + ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"), +#endif +#if defined (SIGIO) + /* "I/O pending" has also been suggested, but is misleading since the + signal only happens when the process has asked for it, not everytime + I/O is pending. */ + ENTRY(SIGIO, "SIGIO", "I/O possible"), +#endif +#if defined (SIGPOLL) + ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"), +#endif +#if defined (SIGSTOP) + ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"), +#endif +#if defined (SIGTSTP) + ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"), +#endif +#if defined (SIGCONT) + ENTRY(SIGCONT, "SIGCONT", "Continued"), +#endif +#if defined (SIGTTIN) + ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"), +#endif +#if defined (SIGTTOU) + ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"), +#endif +#if defined (SIGVTALRM) + ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"), +#endif +#if defined (SIGPROF) + ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"), +#endif +#if defined (SIGXCPU) + ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"), +#endif +#if defined (SIGXFSZ) + ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"), +#endif +#if defined (SIGWIND) + ENTRY(SIGWIND, "SIGWIND", "SIGWIND"), +#endif +#if defined (SIGPHONE) + ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"), +#endif +#if defined (SIGLOST) + ENTRY(SIGLOST, "SIGLOST", "Resource lost"), +#endif +#if defined (SIGWAITING) + ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"), +#endif +#if defined (SIGLWP) + ENTRY(SIGLWP, "SIGLWP", "Signal LWP"), +#endif +#if defined (SIGDANGER) + ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"), +#endif +#if defined (SIGGRANT) + ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"), +#endif +#if defined (SIGRETRACT) + ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"), +#endif +#if defined (SIGMSG) + ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"), +#endif +#if defined (SIGSOUND) + ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"), +#endif +#if defined (SIGSAK) + ENTRY(SIGSAK, "SIGSAK", "Secure attention"), +#endif + ENTRY(0, NULL, NULL) +}; + +/* Translation table allocated and initialized at runtime. Indexed by the + signal value to find the equivalent symbolic value. */ + +static const char **signal_names; +static int num_signal_names = 0; + +/* Translation table allocated and initialized at runtime, if it does not + already exist in the host environment. Indexed by the signal value to find + the descriptive string. + + We don't export it for use in other modules because even though it has the + same name, it differs from other implementations in that it is dynamically + initialized rather than statically initialized. */ + +#ifdef NEED_sys_siglist + +static int sys_nsig; +static const char **sys_siglist; + +#else + +static int sys_nsig = NSIG; +extern const char * const sys_siglist[]; + +#endif + + +/* + +NAME + + init_signal_tables -- initialize the name and message tables + +SYNOPSIS + + static void init_signal_tables (); + +DESCRIPTION + + Using the signal_table, which is initialized at compile time, generate + the signal_names and the sys_siglist (if needed) tables, which are + indexed at runtime by a specific signal value. + +BUGS + + The initialization of the tables may fail under low memory conditions, + in which case we don't do anything particularly useful, but we don't + bomb either. Who knows, it might succeed at a later point if we free + some memory in the meantime. In any case, the other routines know + how to deal with lack of a table after trying to initialize it. This + may or may not be considered to be a bug, that we don't specifically + warn about this particular failure mode. + +*/ + +static void +init_signal_tables () +{ + const struct signal_info *eip; + int nbytes; + + /* If we haven't already scanned the signal_table once to find the maximum + signal value, then go find it now. */ + + if (num_signal_names == 0) + { + for (eip = signal_table; eip -> name != NULL; eip++) + { + if (eip -> value >= num_signal_names) + { + num_signal_names = eip -> value + 1; + } + } + } + + /* Now attempt to allocate the signal_names table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (signal_names == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((signal_names = (const char **) malloc (nbytes)) != NULL) + { + memset (signal_names, 0, nbytes); + for (eip = signal_table; eip -> name != NULL; eip++) + { + signal_names[eip -> value] = eip -> name; + } + } + } + +#ifdef NEED_sys_siglist + + /* Now attempt to allocate the sys_siglist table, zero it out, and then + initialize it from the statically initialized signal_table. */ + + if (sys_siglist == NULL) + { + nbytes = num_signal_names * sizeof (char *); + if ((sys_siglist = (const char **) malloc (nbytes)) != NULL) + { + memset (sys_siglist, 0, nbytes); + sys_nsig = num_signal_names; + for (eip = signal_table; eip -> name != NULL; eip++) + { + sys_siglist[eip -> value] = eip -> msg; + } + } + } + +#endif + +} + + +/* + +NAME + + signo_max -- return the max signo value + +SYNOPSIS + + int signo_max (); + +DESCRIPTION + + Returns the maximum signo value for which a corresponding symbolic + name or message is available. Note that in the case where + we use the sys_siglist supplied by the system, it is possible for + there to be more symbolic names than messages, or vice versa. + In fact, the manual page for psignal(3b) explicitly warns that one + should check the size of the table (NSIG) before indexing it, + since new signal codes may be added to the system before they are + added to the table. Thus NSIG might be smaller than value + implied by the largest signo value defined in . + + We return the maximum value that can be used to obtain a meaningful + symbolic name or message. + +*/ + +int +signo_max () +{ + int maxsize; + + if (signal_names == NULL) + { + init_signal_tables (); + } + maxsize = MAX (sys_nsig, num_signal_names); + return (maxsize - 1); +} + + +/* + +NAME + + strsignal -- map a signal number to a signal message string + +SYNOPSIS + + const char *strsignal (int signo) + +DESCRIPTION + + Maps an signal number to an signal message string, the contents of + which are implementation defined. On systems which have the external + variable sys_siglist, these strings will be the same as the ones used + by psignal(). + + If the supplied signal number is within the valid range of indices + for the sys_siglist, but no message is available for the particular + signal number, then returns the string "Signal NUM", where NUM is the + signal number. + + If the supplied signal number is not a valid index into sys_siglist, + returns NULL. + + The returned string is only guaranteed to be valid only until the + next call to strsignal. + +*/ + +const char * +strsignal (signo) + int signo; +{ + const char *msg; + static char buf[32]; + +#ifdef NEED_sys_siglist + + if (signal_names == NULL) + { + init_signal_tables (); + } + +#endif + + if ((signo < 0) || (signo >= sys_nsig)) + { + /* Out of range, just return NULL */ + msg = NULL; + } + else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) + { + /* In range, but no sys_siglist or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + msg = (const char *) buf; + } + else + { + /* In range, and a valid message. Just return the message. */ + msg = (const char *) sys_siglist[signo]; + } + + return (msg); +} + + +/* + +NAME + + strsigno -- map an signal number to a symbolic name string + +SYNOPSIS + + const char *strsigno (int signo) + +DESCRIPTION + + Given an signal number, returns a pointer to a string containing + the symbolic name of that signal number, as found in . + + If the supplied signal number is within the valid range of indices + for symbolic names, but no name is available for the particular + signal number, then returns the string "Signal NUM", where NUM is + the signal number. + + If the supplied signal number is not within the range of valid + indices, then returns NULL. + +BUGS + + The contents of the location pointed to are only guaranteed to be + valid until the next call to strsigno. + +*/ + +const char * +strsigno (signo) + int signo; +{ + const char *name; + static char buf[32]; + + if (signal_names == NULL) + { + init_signal_tables (); + } + + if ((signo < 0) || (signo >= num_signal_names)) + { + /* Out of range, just return NULL */ + name = NULL; + } + else if ((signal_names == NULL) || (signal_names[signo] == NULL)) + { + /* In range, but no signal_names or no entry at this index. */ + sprintf (buf, "Signal %d", signo); + name = (const char *) buf; + } + else + { + /* In range, and a valid name. Just return the name. */ + name = signal_names[signo]; + } + + return (name); +} + + +/* + +NAME + + strtosigno -- map a symbolic signal name to a numeric value + +SYNOPSIS + + int strtosigno (char *name) + +DESCRIPTION + + Given the symbolic name of a signal, map it to a signal number. + If no translation is found, returns 0. + +*/ + +int +strtosigno (name) + const char *name; +{ + int signo = 0; + + if (name != NULL) + { + if (signal_names == NULL) + { + init_signal_tables (); + } + for (signo = 0; signo < num_signal_names; signo++) + { + if ((signal_names[signo] != NULL) && + (strcmp (name, signal_names[signo]) == 0)) + { + break; + } + } + if (signo == num_signal_names) + { + signo = 0; + } + } + return (signo); +} + + +/* + +NAME + + psignal -- print message about signal to stderr + +SYNOPSIS + + void psignal (unsigned signo, char *message); + +DESCRIPTION + + Print to the standard error the message, followed by a colon, + followed by the description of the signal specified by signo, + followed by a newline. +*/ + +#ifdef NEED_psignal + +void +psignal (signo, message) + unsigned signo; + char *message; +{ + if (signal_names == NULL) + { + init_signal_tables (); + } + if ((signo <= 0) || (signo >= sys_nsig)) + { + fprintf (stderr, "%s: unknown signal\n", message); + } + else + { + fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]); + } +} + +#endif /* NEED_psignal */ + + +/* A simple little main that does nothing but print all the signal translations + if MAIN is defined and this file is compiled and linked. */ + +#ifdef MAIN + +#include + +int +main () +{ + int signo; + int maxsigno; + const char *name; + const char *msg; + + maxsigno = signo_max (); + printf ("%d entries in names table.\n", num_signal_names); + printf ("%d entries in messages table.\n", sys_nsig); + printf ("%d is max useful index.\n", maxsigno); + + /* Keep printing values until we get to the end of *both* tables, not + *either* table. Note that knowing the maximum useful index does *not* + relieve us of the responsibility of testing the return pointer for + NULL. */ + + for (signo = 0; signo <= maxsigno; signo++) + { + name = strsigno (signo); + name = (name == NULL) ? "" : name; + msg = strsignal (signo); + msg = (msg == NULL) ? "" : msg; + printf ("%-4d%-18s%s\n", signo, name, msg); + } + + return 0; +} + +#endif diff --git a/contrib/gdb/libiberty/strstr.c b/contrib/gdb/libiberty/strstr.c new file mode 100644 index 000000000000..fab36e3fb3d4 --- /dev/null +++ b/contrib/gdb/libiberty/strstr.c @@ -0,0 +1,51 @@ +/* Simple implementation of strstr for systems without it. + This function is in the public domain. */ + +/* + +NAME + + strstr -- locate first occurance of a substring + +SYNOPSIS + + #include + + char *strstr (char *s1, char *s2) + +DESCRIPTION + + Locates the first occurance in the string pointed to by S1 of + the string pointed to by S2. Returns a pointer to the substring + found, or a NULL pointer if not found. If S2 points to a string + with zero length, the function returns S1. + +BUGS + +*/ + + +/* FIXME: The above description is ANSI compiliant. This routine has not + been validated to comply with it. -fnf */ + +char * +strstr (s1, s2) + char *s1, *s2; +{ + register char *p = s1; + extern char *strchr (); + extern int strncmp (); +#if __GNUC__==2 + extern __SIZE_TYPE__ strlen (); +#endif + register int len = strlen (s2); + + for (; (p = strchr (p, *s2)) != 0; p++) + { + if (strncmp (p, s2, len) == 0) + { + return (p); + } + } + return (0); +} diff --git a/contrib/gdb/libiberty/strtod.c b/contrib/gdb/libiberty/strtod.c new file mode 100644 index 000000000000..c86c73de9b38 --- /dev/null +++ b/contrib/gdb/libiberty/strtod.c @@ -0,0 +1,122 @@ +/* Implementation of strtod for systems with atof. + Copyright (C) 1991, 1995 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +#include + +extern double atof (); + +/* Disclaimer: this is currently just used by CHILL in GDB and therefore + has not been tested well. It may have been tested for nothing except + that it compiles. */ + +double +strtod (str, ptr) + char *str; + char **ptr; +{ + char *p; + + if (ptr == (char **)0) + return atof (str); + + p = str; + + while (isspace (*p)) + ++p; + + if (*p == '+' || *p == '-') + ++p; + + /* INF or INFINITY. */ + if ((p[0] == 'i' || p[0] == 'I') + && (p[1] == 'n' || p[1] == 'N') + && (p[2] == 'f' || p[2] == 'F')) + { + if ((p[3] == 'i' || p[3] == 'I') + && (p[4] == 'n' || p[4] == 'N') + && (p[5] == 'i' || p[5] == 'I') + && (p[6] == 't' || p[6] == 'T') + && (p[7] == 'y' || p[7] == 'Y')) + { + *ptr = p + 7; + return atof (str); + } + else + { + *ptr = p + 3; + return atof (str); + } + } + + /* NAN or NAN(foo). */ + if ((p[0] == 'n' || p[0] == 'N') + && (p[1] == 'a' || p[1] == 'A') + && (p[2] == 'n' || p[2] == 'N')) + { + p += 3; + if (*p == '(') + { + ++p; + while (*p != '\0' && *p != ')') + ++p; + if (*p == ')') + ++p; + } + *ptr = p; + return atof (str); + } + + /* digits, with 0 or 1 periods in it. */ + if (isdigit (*p) || *p == '.') + { + int got_dot = 0; + while (isdigit (*p) || (!got_dot && *p == '.')) + { + if (*p == '.') + got_dot = 1; + ++p; + } + + /* Exponent. */ + if (*p == 'e' || *p == 'E') + { + int i; + i = 1; + if (p[i] == '+' || p[i] == '-') + ++i; + if (isdigit (p[i])) + { + while (isdigit (p[i])) + ++i; + *ptr = p + i; + return atof (str); + } + } + *ptr = p; + return atof (str); + } + /* Didn't find any digits. Doesn't look like a number. */ + *ptr = str; + return 0.0; +} diff --git a/contrib/gdb/libiberty/strtol.c b/contrib/gdb/libiberty/strtol.c new file mode 100644 index 000000000000..db27ee0a8759 --- /dev/null +++ b/contrib/gdb/libiberty/strtol.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#if 0 +#include +#endif +#include "ansidecl.h" + +/* FIXME: It'd be nice to configure around these, but the include files are too + painful. These macros should at least be more portable than hardwired hex + constants. */ + +#ifndef ULONG_MAX +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */ +#endif + +#ifndef LONG_MAX +#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF */ +#endif + +#ifndef LONG_MIN +#define LONG_MIN ((long)(~LONG_MAX)) /* 0x80000000 */ +#endif + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(nptr, endptr, base) + CONST char *nptr; + char **endptr; + register int base; +{ + register CONST char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/contrib/gdb/libiberty/strtoul.c b/contrib/gdb/libiberty/strtoul.c new file mode 100644 index 000000000000..40902452fed3 --- /dev/null +++ b/contrib/gdb/libiberty/strtoul.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#if 0 +#include +#endif +#include "ansidecl.h" + +#ifndef ULONG_MAX +#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF */ +#endif + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(nptr, endptr, base) + CONST char *nptr; + char **endptr; + register int base; +{ + register CONST char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/contrib/gdb/libiberty/tmpnam.c b/contrib/gdb/libiberty/tmpnam.c new file mode 100644 index 000000000000..c06146774252 --- /dev/null +++ b/contrib/gdb/libiberty/tmpnam.c @@ -0,0 +1,39 @@ +#include + +#ifndef L_tmpnam +#define L_tmpname 100 +#endif +#ifndef P_tmpdir +#define P_tmpdir "/usr/tmp" +#endif + +static char tmpnam_buffer[L_tmpnam]; +static int tmpnam_counter; + +extern int getpid (); + +char * +tmpnam (s) + char *s; +{ + int pid = getpid (); + + if (s == NULL) + s = tmpnam_buffer; + + /* Generate the filename and make sure that there isn't one called + it already. */ + + while (1) + { + FILE *f; + sprintf (s, "%s/%s%x.%x", P_tmpdir, "t", pid, tmpnam_counter); + f = fopen (s, "r"); + if (f == NULL) + break; + tmpnam_counter++; + fclose (f); + } + + return s; +} diff --git a/contrib/gdb/libiberty/vasprintf.c b/contrib/gdb/libiberty/vasprintf.c new file mode 100644 index 000000000000..3794cbd2c4fb --- /dev/null +++ b/contrib/gdb/libiberty/vasprintf.c @@ -0,0 +1,165 @@ +/* Like vsprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1994 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +#ifdef TEST +int global_total_width; +#endif + +unsigned long strtoul (); +char *malloc (); + +static int +int_vasprintf (result, format, args) + char **result; + const char *format; + va_list *args; +{ + const char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap; + + memcpy ((PTR) &ap, (PTR) args, sizeof (va_list)); + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, &p, 10); + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, &p, 10); + } + while (strchr ("hlL", *p)) + ++p; + /* Should be big enough for any format specifier except %s. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + (void) va_arg (ap, int); + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + (void) va_arg (ap, double); + break; + case 's': + total_width += strlen (va_arg (ap, char *)); + break; + case 'p': + case 'n': + (void) va_arg (ap, char *); + break; + } + } + } +#ifdef TEST + global_total_width = total_width; +#endif + *result = malloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, *args); + else + return 0; +} + +int +vasprintf (result, format, args) + char **result; + const char *format; + va_list args; +{ + return int_vasprintf (result, format, &args); +} + +#ifdef TEST +void +checkit +#ifdef __STDC__ + (const char* format, ...) +#else + (va_alist) + va_dcl +#endif +{ + va_list args; + char *result; + +#ifdef __STDC__ + va_start (args, format); +#else + char *format; + va_start (args); + format = va_arg (args, char *); +#endif + vasprintf (&result, format, args); + if (strlen (result) < global_total_width) + printf ("PASS: "); + else + printf ("FAIL: "); + printf ("%d %s\n", global_total_width, result); +} + +int +main () +{ + checkit ("%d", 0x12345678); + checkit ("%200d", 5); + checkit ("%.300d", 6); + checkit ("%100.150d", 7); + checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333"); + checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); +} +#endif /* TEST */ diff --git a/contrib/gdb/libiberty/vfork.c b/contrib/gdb/libiberty/vfork.c new file mode 100644 index 000000000000..86c45919f660 --- /dev/null +++ b/contrib/gdb/libiberty/vfork.c @@ -0,0 +1,8 @@ +/* Emulate vfork using just plain fork, for systems without a real vfork. + This function is in the public domain. */ + +int +vfork () +{ + return (fork ()); +} diff --git a/contrib/gdb/libiberty/vfprintf.c b/contrib/gdb/libiberty/vfprintf.c new file mode 100644 index 000000000000..ce3fdf9c4745 --- /dev/null +++ b/contrib/gdb/libiberty/vfprintf.c @@ -0,0 +1,13 @@ +#include +#include +#include +#undef vfprintf + +int +vfprintf (file, format, ap) + FILE *file; + const char *format; + va_list ap; +{ + return _doprnt (format, ap, file); +} diff --git a/contrib/gdb/libiberty/vmsbuild.com b/contrib/gdb/libiberty/vmsbuild.com new file mode 100644 index 000000000000..e1c203f9f472 --- /dev/null +++ b/contrib/gdb/libiberty/vmsbuild.com @@ -0,0 +1,142 @@ +$! libiberty/vmsbuild.com -- build liberty.olb for VMS host, VMS target +$! +$ CC = "gcc /noVerbose/Debug/Incl=([],[-.include])" +$ LIBR = "library /Obj" +$ LINK = "link" +$ DELETE= "delete /noConfirm" +$ SEARCH= "search /Exact" +$ ECHO = "write sys$output" +$ ABORT = "exit %x002C" +$! +$ LIB_NAME = "liberty.olb" !this is what we're going to construct +$ WORK_LIB = "new-lib.olb" !used to guard against an incomplete build +$ +$! manually copied from Makefile.in +$ REQUIRED_OFILES = "argv.o basename.o concat.o cplus-dem.o fdmatch.o "- + + "getopt.o getopt1.o getruntime.o hex.o "- + + "floatformat.o obstack.o spaces.o strerror.o strsignal.o "- + + "vasprintf.o xatexit.o xexit.o xmalloc.o xstrerror.o" +$! anything not caught by link+search of dummy.* should be added here +$ EXTRA_OFILES = "" +$! +$! move to the directory which contains this command procedure +$ old_dir = f$environ("DEFAULT") +$ new_dir = f$parse("_._;",f$environ("PROCEDURE")) - "_._;" +$ set default 'new_dir' +$ +$ ECHO "Starting libiberty build..." +$ create config.h +/* libiberty config.h for VMS */ +#define NEED_sys_siglist +#define NEED_psignal +#define NEED_basename +$ if f$search("alloca-conf.h").eqs."" then - + copy alloca-norm.h alloca-conf.h +$ LIBR 'WORK_LIB' /Create +$ +$! first pass: compile "required" modules +$ ofiles = REQUIRED_OFILES + " " + EXTRA_OFILES +$ gosub do_ofiles +$ +$! second pass: process dummy.c, using the first pass' results +$ ECHO " now checking run-time library for missing functionality" +$ if f$search("dummy.obj").nes."" then DELETE dummy.obj;* +$ define/noLog sys$error _NL: !can't use /User_Mode here due to gcc +$ define/noLog sys$output _NL: ! driver's use of multiple image activation +$ on error then continue +$ 'CC' dummy.c +$ deassign sys$error !restore, more or less +$ deassign sys$output +$ if f$search("dummy.obj").eqs."" then goto pass2_failure1 +$! link dummy.obj, capturing full linker feedback in dummy.map +$ oldmsg = f$environ("MESSAGE") +$ set message /Facility/Severity/Identification/Text +$ define/User sys$output _NL: +$ define/User sys$error _NL: +$ LINK/Map=dummy.map/noExe dummy.obj,'WORK_LIB'/Libr,- + gnu_cc:[000000]gcclib.olb/Libr,sys$library:vaxcrtl.olb/Libr +$ set message 'oldmsg' +$ if f$search("dummy.map").eqs."" then goto pass2_failure2 +$ DELETE dummy.obj;* +$ SEARCH dummy.map "%LINK-I-UDFSYM" /Output=dummy.list +$ DELETE dummy.map;* +$ ECHO " check completed" +$! we now have a file with one entry per line of unresolvable symbols +$ ofiles = "" +$ if f$trnlnm("IFILE$").nes."" then close/noLog ifile$ +$ open/Read ifile$ dummy.list +$iloop: read/End=idone ifile$ iline +$ iline = f$edit(iline,"COMPRESS,TRIM,LOWERCASE") +$ ofiles = ofiles + " " + f$element(1," ",iline) + ".o" +$ goto iloop +$idone: close ifile$ +$ DELETE dummy.list;* +$ +$! third pass: compile "missing" modules collected in pass 2 +$ gosub do_ofiles +$ +$! finish up +$ LIBR 'WORK_LIB' /Compress /Output='LIB_NAME' !new-lib.olb -> liberty.olb +$ DELETE 'WORK_LIB';* +$ +$! all done +$ ECHO "Completed libiberty build." +$ type sys$input: + + You many wish to do + $ COPY LIBERTY.OLB GNU_CC:[000000] + so that this run-time library resides in the same location as gcc's + support library. When building gas, be sure to leave the original + copy of liberty.olb here so that gas's build procedure can find it. + +$ set default 'old_dir' +$ exit +$ +$! +$! compile each element of the space-delimited list 'ofiles' +$! +$do_ofiles: +$ ofiles = f$edit(ofiles,"COMPRESS,TRIM") +$ i = 0 +$oloop: +$ f = f$element(i," ",ofiles) +$ if f.eqs." " then goto odone +$ f = f - ".o" !strip dummy suffix +$ ECHO " ''f'" +$ 'CC' 'f'.c +$ LIBR 'WORK_LIB' 'f'.obj /Insert +$ DELETE 'f'.obj;* +$ i = i + 1 +$ goto oloop +$odone: +$ return +$ +$! +$pass2_failure1: +$! if we reach here, dummy.c failed to compile and we're really stuck +$ type sys$input: + + Cannot compile the library contents checker (dummy.c + functions.def), + so cannot continue! + +$! attempt the compile again, without suppressing diagnostic messages this time +$ on error then ABORT +0*f$verify(v) +$ v = f$verify(1) +$ 'CC' dummy.c +$ ABORT +0*f$verify(v) !'f$verify(0)' +$! +$pass2_failure2: +$! should never reach here.. +$ type sys$input: + + Cannot link the library contents checker (dummy.obj), so cannot continue! + +$! attempt the link again, without suppressing diagnostic messages this time +$ on error then ABORT +0*f$verify(v) +$ v = f$verify(1) +$ LINK/Map=dummy.map/noExe dummy.obj,'WORK_LIB'/Libr,- + gnu_cc:[000000]gcclib.olb/Libr,sys$library:vaxcrtl.olb/Libr +$ ABORT +0*f$verify(v) !'f$verify(0)' +$ +$! not reached +$ exit diff --git a/contrib/gdb/libiberty/vprintf.c b/contrib/gdb/libiberty/vprintf.c new file mode 100644 index 000000000000..63ac53c965ad --- /dev/null +++ b/contrib/gdb/libiberty/vprintf.c @@ -0,0 +1,11 @@ +#include +#include +#include +#undef vprintf +int +vprintf (format, ap) + const char *format; + va_list ap; +{ + return vfprintf (stdout, format, ap); +} diff --git a/contrib/gdb/libiberty/vsprintf.c b/contrib/gdb/libiberty/vsprintf.c new file mode 100644 index 000000000000..bf0760cf6d38 --- /dev/null +++ b/contrib/gdb/libiberty/vsprintf.c @@ -0,0 +1,55 @@ +/* Simple implementation of vsprintf for systems without it. + Highly system-dependent, but should work on most "traditional" + implementations of stdio; newer ones should already have vsprintf. + Written by Per Bothner of Cygnus Support. + Based on libg++'s "form" (written by Doug Lea; dl@rocky.oswego.edu). + Copyright (C) 1991, 1995 Free Software Foundation, Inc. + +This file is part of the libiberty library. This library is free +software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +As a special exception, if you link this library with files +compiled with a GNU compiler to produce an executable, this does not cause +the resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. */ + +#include +#include +#include +#undef vsprintf + +int +vsprintf (buf, format, ap) + char *buf; + const char *format; + va_list ap; +{ + FILE b; + int ret; +#ifdef VMS + b->_flag = _IOWRT|_IOSTRG; + b->_ptr = buf; + b->_cnt = 12000; +#else + b._flag = _IOWRT|_IOSTRG; + b._ptr = buf; + b._cnt = 12000; +#endif + ret = _doprnt(format, ap, &b); + putc('\0', &b); + return ret; + +} diff --git a/contrib/gdb/libiberty/waitpid.c b/contrib/gdb/libiberty/waitpid.c new file mode 100644 index 000000000000..23db0b932d2e --- /dev/null +++ b/contrib/gdb/libiberty/waitpid.c @@ -0,0 +1,11 @@ +int +waitpid (pid, stat_loc, options) + int pid, *stat_loc, options; +{ + for (;;) + { + int wpid = wait(stat_loc); + if (wpid == pid || wpid == -1) + return wpid; + } +} diff --git a/contrib/gdb/libiberty/xatexit.c b/contrib/gdb/libiberty/xatexit.c new file mode 100644 index 000000000000..7dd27e143f81 --- /dev/null +++ b/contrib/gdb/libiberty/xatexit.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + */ + +/* Adapted from newlib/libc/stdlib/{,at}exit.[ch]. + If you use xatexit, you must call xexit instead of exit. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#include + +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +/* For systems with larger pointers than ints, this must be declared. */ +PTR malloc PARAMS ((size_t)); + +static void xatexit_cleanup PARAMS ((void)); + +/* Pointer to function run by xexit. */ +extern void (*_xexit_cleanup) (); + +#define XATEXIT_SIZE 32 + +struct xatexit { + struct xatexit *next; /* next in list */ + int ind; /* next index in this table */ + void (*fns[XATEXIT_SIZE]) PARAMS ((void)); /* the table itself */ +}; + +/* Allocate one struct statically to guarantee that we can register + at least a few handlers. */ +static struct xatexit xatexit_first; + +/* Points to head of LIFO stack. */ +static struct xatexit *xatexit_head = &xatexit_first; + +/* Register function FN to be run by xexit. + Return 0 if successful, -1 if not. */ + +int +xatexit (fn) + void (*fn) PARAMS ((void)); +{ + register struct xatexit *p; + + /* Tell xexit to call xatexit_cleanup. */ + if (!_xexit_cleanup) + _xexit_cleanup = xatexit_cleanup; + + p = xatexit_head; + if (p->ind >= XATEXIT_SIZE) + { + if ((p = (struct xatexit *) malloc (sizeof *p)) == NULL) + return -1; + p->ind = 0; + p->next = xatexit_head; + xatexit_head = p; + } + p->fns[p->ind++] = fn; + return 0; +} + +/* Call any cleanup functions. */ + +static void +xatexit_cleanup () +{ + register struct xatexit *p; + register int n; + + for (p = xatexit_head; p; p = p->next) + for (n = p->ind; --n >= 0;) + (*p->fns[n]) (); +} diff --git a/contrib/gdb/libiberty/xexit.c b/contrib/gdb/libiberty/xexit.c new file mode 100644 index 000000000000..98baeca475d9 --- /dev/null +++ b/contrib/gdb/libiberty/xexit.c @@ -0,0 +1,36 @@ +/* xexit.c -- Run any exit handlers, then exit. + Copyright (C) 1994 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#include + +/* This variable is set by xatexit if it is called. This way, xmalloc + doesn't drag xatexit into the link. */ +void (*_xexit_cleanup) (); + +void +xexit (code) + int code; +{ + if (_xexit_cleanup != NULL) + (*_xexit_cleanup) (); + exit (code); +} diff --git a/contrib/gdb/libiberty/xmalloc.c b/contrib/gdb/libiberty/xmalloc.c new file mode 100644 index 000000000000..95967abe3004 --- /dev/null +++ b/contrib/gdb/libiberty/xmalloc.c @@ -0,0 +1,106 @@ +/* memory allocation routines with error checking. + Copyright 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ansidecl.h" +#include "libiberty.h" + +#include + +#ifdef __STDC__ +#include +#else +#define size_t unsigned long +#endif + +/* For systems with larger pointers than ints, these must be declared. */ +PTR malloc PARAMS ((size_t)); +PTR realloc PARAMS ((PTR, size_t)); + +/* The program name if set. */ +static const char *name = ""; + +/* The initial sbrk, set when the program name is set. */ +static char *first_break = NULL; + +void +xmalloc_set_program_name (s) + const char *s; +{ + name = s; + if (first_break == NULL) + first_break = (char *) sbrk (0); +} + +PTR +xmalloc (size) + size_t size; +{ + PTR newmem; + + if (size == 0) + size = 1; + newmem = malloc (size); + if (!newmem) + { + extern char **environ; + size_t allocated; + + if (first_break != NULL) + allocated = (char *) sbrk (0) - first_break; + else + allocated = (char *) sbrk (0) - (char *) &environ; + fprintf (stderr, + "\n%s%sCan not allocate %lu bytes after allocating %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size, (unsigned long) allocated); + xexit (1); + } + return (newmem); +} + +PTR +xrealloc (oldmem, size) + PTR oldmem; + size_t size; +{ + PTR newmem; + + if (size == 0) + size = 1; + if (!oldmem) + newmem = malloc (size); + else + newmem = realloc (oldmem, size); + if (!newmem) + { + extern char **environ; + size_t allocated; + + if (first_break != NULL) + allocated = (char *) sbrk (0) - first_break; + else + allocated = (char *) sbrk (0) - (char *) &environ; + fprintf (stderr, + "\n%s%sCan not reallocate %lu bytes after allocating %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size, (unsigned long) allocated); + xexit (1); + } + return (newmem); +} diff --git a/contrib/gdb/libiberty/xstrdup.c b/contrib/gdb/libiberty/xstrdup.c new file mode 100644 index 000000000000..9d08bc704055 --- /dev/null +++ b/contrib/gdb/libiberty/xstrdup.c @@ -0,0 +1,17 @@ +/* xstrdup.c -- Duplicate a string in memory, using xmalloc. + This trivial function is in the public domain. + Ian Lance Taylor, Cygnus Support, December 1995. */ + +#include "ansidecl.h" +#include "libiberty.h" + +char * +xstrdup (s) + const char *s; +{ + char *ret; + + ret = xmalloc (strlen (s) + 1); + strcpy (ret, s); + return ret; +} diff --git a/contrib/gdb/libiberty/xstrerror.c b/contrib/gdb/libiberty/xstrerror.c new file mode 100644 index 000000000000..d05369ac9725 --- /dev/null +++ b/contrib/gdb/libiberty/xstrerror.c @@ -0,0 +1,54 @@ +/* xstrerror.c -- jacket routine for more robust strerror() usage. + Fri Jun 16 18:30:00 1995 Pat Rankin + This code is in the public domain. */ + +#include "libiberty.h" +#include "config.h" + +#ifdef VMS +#include +#if !defined (__STRICT_ANSI__) && !defined (__HIDE_FORBIDDEN_NAMES) +extern char *strerror PARAMS ((int,...)); +#define DONT_DECLARE_STRERROR +#endif +#endif /* VMS */ + +#ifndef DONT_DECLARE_STRERROR +extern char *strerror PARAMS ((int)); +#endif + +/* If strerror returns NULL, we'll format the number into a static buffer. */ + +#define ERRSTR_FMT "undocumented error #%d" +static char xstrerror_buf[sizeof ERRSTR_FMT + 20]; + +/* Like strerror, but result is never a null pointer. */ + +char * +xstrerror (errnum) + int errnum; +{ + char *errstr; +#ifdef VMS + char *(*vmslib_strerror) PARAMS ((int,...)); + + /* Override any possibly-conflicting declaration from system header. */ + vmslib_strerror = (char *(*) PARAMS ((int,...))) strerror; + /* Second argument matters iff first is EVMSERR, but it's simpler to + pass it unconditionally. `vaxc$errno' is declared in + and maintained by the run-time library in parallel to `errno'. + We assume that `errnum' corresponds to the last value assigned to + errno by the run-time library, hence vaxc$errno will be relevant. */ + errstr = (*vmslib_strerror) (errnum, vaxc$errno); +#else + errstr = strerror (errnum); +#endif + + /* If `errnum' is out of range, result might be NULL. We'll fix that. */ + if (!errstr) + { + sprintf (xstrerror_buf, ERRSTR_FMT, errnum); + errstr = xstrerror_buf; + } + return errstr; +} diff --git a/contrib/gdb/opcodes/ChangeLog b/contrib/gdb/opcodes/ChangeLog new file mode 100644 index 000000000000..589c1a234ac7 --- /dev/null +++ b/contrib/gdb/opcodes/ChangeLog @@ -0,0 +1,1772 @@ +Sun Apr 7 15:06:17 1996 Fred Fish + + From: Miles Bader + * configure.in: Use AC_CHECK_TOOL to find AR & RANLIB. + * configure: Regenerate with autoconf. + +Sat Mar 16 13:04:07 1996 Fred Fish + + * z8kgen.c (internal, gas): Call xmalloc rather than unchecked + malloc. + +Tue Mar 12 12:14:10 1996 Ian Lance Taylor + + * configure: Rebuild with autoconf 2.8. + +Thu Mar 7 15:11:10 1996 Doug Evans + + * sparc-dis.c (print_insn_sparc): Handle 'O' operand char like 'r'. + * sparc-opc.c (sparc_opcodes): Use 'O' operand char for `neg reg'. + +Tue Mar 5 15:51:57 1996 Ian Lance Taylor + + * configure.in: Don't set SHLIB or SHLINK to an empty string, + since they appear as targets in Makefile.in. + * configure: Rebuild. + +Mon Feb 26 13:03:40 1996 Stan Shebs + + * mpw-make.sed: Edit out shared library support bits. + +Tue Feb 20 20:48:28 1996 Doug Evans + + * sparc-opc.c (v8,v6notv9): Add MASK_SPARCLET. + (sparc_opcode_archs): Add MASK_V8 to sparclet entry. + (sparc_opcodes): Add sparclet insns. + (sparclet_cpreg_table): New static local. + (sparc_{encode,decode}_sparclet_cpreg): New functions. + * sparc-dis.c (print_insn_sparc): Handle sparclet cpregs. + +Tue Feb 20 11:02:44 1996 Alan Modra + + * i386-dis.c (index16): New static variable. + (putop): Print jecxz for 32 bit case, jcxz for 16 bit, not the + other way around. + (OP_indirE): Return result of OP_E. + (OP_E): Check for 16 bit addressing mode, and disassemble + correctly. Optimised 32 bit case a little. Don't print + "(base,index,scale)" when sib specifies only an offset. + +Mon Feb 19 12:32:17 1996 Ian Lance Taylor + + * configure.in: Set and substitute SHLIB_DEP. + * configure: Rebuild. + * Makefile.in (SHLIB_DEP): New variable. + (LIBIBERTY_LISTS, BFD_LIST): New variables. + (stamp-piclist): Depend upon LIBIBERTY_LISTS and BFD_LIST. If + COMMON_SHLIB, add them to piclist with appropriate modifications. + ($(SHLIB)): Depend upon $(SHLIB_DEP). Don't check COMMON_SHLIB + here: just use piclist. + +Mon Feb 19 02:03:50 1996 Doug Evans + + * sparc-dis.c (MASK_V9,V9_ONLY_P,V9_P): Define. + (print_insn_sparc): Rewrite v9/not-v9 tests. + (compare_opcodes): Likewise. + * sparc-opc.c (MASK_): Define. + (v6,v7,v8,sparclite,v9,v9a): Redefine. + (sparclet,v6notv9): Define. + (sparc_opcode_archs): Delete member `conflicts'. Add `supported'. + (sparc_opcodes): Delete F_NOTV9, use v6notv9 instead. + +Thu Feb 15 14:45:05 1996 Ian Lance Taylor + + * configure.in: Call AC_PROG_CC before configure.host. + * configure: Rebuild. + + * Makefile.in (SONAME): Remove leading ../bfd/ from $(SHLIB). + +Wed Feb 14 19:01:27 1996 Alan Modra + + * i386-dis.c (onebyte_has_modrm): New static array. + (twobyte_has_modrm): New static array. + (print_insn_i386): Only fetch the mod/reg/rm byte if it is needed. + +Tue Feb 13 15:15:01 1996 Ian Lance Taylor + + * Makefile.in ($(SHLINK)): Check ts against $(SHLIB), not + $(SHLINK). + +Mon Feb 12 16:26:06 1996 Michael Meissner + + * ppc-opc.c (PPC): Undef, so default defination on Windows NT + doesn't conflict. + +Wed Feb 7 13:59:54 1996 Ian Lance Taylor + + * m68k-opc.c (m68k_opcodes): The bkpt instruction is supported on + m68010up, not just m68020up | cpu32. + + * Makefile.in (SONAME): New variable. + ($(SHLINK)): Make a link to the transformed name, as well. + (stamp-tshlink): New target. + (install): Skip stamp-tshlink during install. + +Tue Feb 6 12:28:54 1996 Ian Lance Taylor + + * configure.in: Call AC_ARG_PROGRAM. + * configure: Rebuild. + * Makefile.in (program_transform_name): New variable. + (install): Transform library name before installing it. + +Mon Feb 5 16:14:42 1996 Ian Lance Taylor + + * i960-dis.c (mem): Add HX dcinva instruction. + + Support for building as a shared library, based on patches from + Alan Modra : + * configure.in: Add AC_ARG_ENABLE for shared and commonbfdlib. + New substitutions: ALLLIBS, PICFLAG, SHLIB, SHLIB_CC, + SHLIB_CFLAGS, COMMON_SHLIB, SHLINK. + * configure: Rebuild. + * Makefile.in (ALLLIBS): New variable. + (PICFLAG, SHLIB, SHLIB_CC, SHLIB_CFLAGS): New variables. + (COMMON_SHLIB, SHLINK): New variables. + (.c.o): If PICFLAG is set, compile twice, once PIC, once normal. + (STAGESTUFF): Remove variable. + (all): Depend upon $(ALLLIBS) rather than $(TARGETLIB). + (stamp-piclist, piclist): New targets. + ($(SHLIB), $(SHLINK)): New targets. + ($(OFILES)): Depend upon stamp-picdir. + (disassemble.o): Build twice if PICFLAG is set. + (MOSTLYCLEAN): Add pic/*.o. + (clean): Remove $(SHLIB), $(SHLINK), piclist, and stamp-piclist. + (distclean): Remove pic and stamp-picdir. + (install): Install shared libraries. + (stamp-picdir): New target. + +Fri Feb 2 17:15:25 1996 Doug Evans + + * sparc-dis.c (print_insn_sparc): Delete DISASM_RAW_INSN support. + Print unknown instruction as "unknown", rather than in hex. + +Tue Jan 30 14:06:08 1996 Ian Lance Taylor + + * dis-buf.c: Include "sysdep.h" before "dis-asm.h". + +Thu Jan 25 20:24:07 1996 Doug Evans + + * sparc-opc.c (sparc_opcode_archs): Mark v8/sparclite as conflicting. + +Thu Jan 25 11:56:49 1996 Ian Lance Taylor + + * i386-dis.c (print_insn_i386): Only fetch the mod/reg/rm byte + when necessary. From Ulrich Drepper + . + +Thu Jan 25 03:39:10 1996 Doug Evans + + * sparc-dis.c (print_insn_sparc): NUMOPCODES replaced with + sparc_num_opcodes. Update architecture enum values. + * sparc-opc.c (sparc_opcode_archs): Replaces architecture_pname. + (sparc_opcode_lookup_arch): New function. + (sparc_num_opcodes): Renamed from bfd_sparc_num_opcodes. + (sparc_opcodes): Add v9a shutdown insn. + +Mon Jan 22 08:29:59 1996 Doug Evans + + * sparc-dis.c (print_insn_sparc): Renamed from print_insn. + If DISASM_RAW_INSN, print insn in hex. Handle v9a as opcode + architecture. + (print_insn_sparc64): Deleted. + * disassemble.c (disassembler, case bfd_arch_sparc): Always use + print_insn_sparc. + + * sparc-opc.c (architecture_pname): Add v9a. + +Fri Jan 12 14:35:58 1996 David Mosberger-Tang + + * alpha-opc.h (alpha_insn_set): VAX floating point opcode was + incorrectly defined as 0x16 when it should be 0x15. + (FLOAT_FORMAT_MASK): function code is 11 bits, not just 7 bits! + (alpha_insn_set): added cvtst and cvttq float ops. Also added + excb (exception barrier) which is defined in the Alpha + Architecture Handbook version 2. + * alpha-dis.c (print_insn_alpha): Fixed special-case decoding for + OPERATE_FORMAT_CODE type instructions. The bug caused mulq to be + disassembled as or, for example. + +Wed Jan 10 12:37:22 1996 Ian Lance Taylor + + * mips-dis.c (print_insn_arg): Print cases 'i' and 'u' in hex. + (_print_insn_mips): Change i from int to unsigned int. + +Thu Jan 4 17:21:10 1996 David Edelsohn + + * ppc-opc.c (powerpc_opcodes): tlbi POWER opcode form different + from tlbie PowerPC opcode. Add PPC603 tlbld and tlbli. + +Thu Dec 28 13:29:19 1995 John Hassey + + * i386-dis.c: Added Pentium Pro instructions. + +Tue Dec 19 22:56:35 1995 Michael Meissner + + * ppc-opc.c (fsqrt{,.}): Duplicate for PowerPC in addition to + being for Power2. + +Fri Dec 15 14:14:15 1995 J.T. Conklin + + * sh-opc.h (sh_nibble_type): Added REG_B. + (sh_arg_type): Added A_REG_B. + (sh_table): Added pref and bank reg versions of ldc, ldc.l, stc + and stc.l opcodes. + * sh-dis.c (print_insn_shx): Added cases for REG_B and A_REG_B. + +Fri Dec 15 16:44:31 1995 Ian Lance Taylor + + * disassemble.c (disassembler): Use new bfd_big_endian macro. + +Tue Dec 12 12:22:24 1995 Ian Lance Taylor + + * Makefile.in (distclean): Remove stamp-h. From Ronald + F. Guilmette . + +Tue Dec 5 13:42:44 1995 Stan Shebs + + From David Mosberger-Tang : + * alpha-dis.c (print_insn_alpha): fixed decoding of cpys + instruction. + +Mon Dec 4 12:29:05 1995 J.T. Conklin + + * sh-opc.h (sh_arg_type): Added A_SSR and A_SPC. + (sh_table): Added many SH3 opcodes. + * sh-dis.c (print_insn_shx): Added cases for A_SSR and A_SPC. + +Fri Dec 1 07:42:18 1995 Michael Meissner + + * ppc-opc.c (subfc., subfco): Mark this PPCCOM, not PPC. + (subco,subco.): Mark this PPC, not PPCCOM. + +Mon Nov 27 13:09:52 1995 Ian Lance Taylor + + * configure: Rebuild with autoconf 2.7. + +Tue Nov 21 18:28:06 1995 Ian Lance Taylor + + * configure: Rebuild with autoconf 2.6. + +Wed Nov 15 19:02:53 1995 Ken Raeburn + + * configure.in: Sort list of architectures. Accept but do nothing + for alliant, convex, pyramid, romp, and tahoe. + +Wed Nov 8 20:18:59 1995 Ian Lance Taylor + + * a29k-dis.c (print_special): Change num to unsigned int. + +Wed Nov 8 20:10:35 1995 Eric Freudenthal + + * a29k-dis.c (print_insn): Cast insn24 to unsigned long when + shifting it. + +Tue Nov 7 15:21:06 1995 Ian Lance Taylor + + * configure.in: Call AC_CHECK_PROG to find and cache AR. + * configure: Rebuilt. + +Mon Nov 6 17:39:47 1995 Harry Dolan + + * configure.in: Add case for bfd_i860_arch. + * configure: Rebuild. + +Fri Nov 3 12:45:31 1995 Ian Lance Taylor + + * m68k-opc.c (m68k_opcodes): Correct fmoveml operands. + * m68k-dis.c (NEXTSINGLE): Change i to unsigned int. + (NEXTDOUBLE): Likewise. + (print_insn_m68k): Don't match fmoveml if there is more than one + register in the list. + (print_insn_arg): Handle a place of '8' for a type of 'L'. + +Thu Nov 2 23:06:33 1995 Ian Lance Taylor + + * m68k-opc.c: Use #W rather than #w. + * m68k-dis.c (print_insn_arg): Handle new 'W' place. + +Wed Nov 1 13:30:24 1995 Ian Lance Taylor + + * m68k-opc.c (m68k_opcode_aliases): Add dbfw as an alias for dbf, + and likewise for all the dbxx opcodes. + +Mon Oct 30 20:50:40 1995 Fred Fish + + * arc-dis.c: Include elf-bfd.h rather than libelf.h. + +Mon Oct 23 11:11:34 1995 James G. Smith + + * mips-opc.c: Added shorthand (V1) for INSN_4100 manifest. Added + the VR4100 specific instructions to the mips_opcodes structure. + +Thu Oct 19 11:05:23 1995 Stan Shebs + + * mpw-config.in, mpw-make.sed: Remove ugly workaround for + ugly Metrowerks bug in CW6, is fixed in CW7. + +Mon Oct 16 12:59:01 1995 Michael Meissner + + * ppc-opc.c (whole file): Add flags for common/any support. + +Tue Oct 10 11:06:07 1995 Fred Fish + + * Makefile.in (BISON): Remove macro. + (FLAGS_TO_PASS): Remove BISON. + +Fri Oct 6 16:26:45 1995 Ken Raeburn + + Mon Sep 25 22:49:32 1995 Andreas Schwab + + * m68k-dis.c (print_insn_m68k): Recognize all two-word + instructions that take no args by looking at the match mask. + (print_insn_arg): Always print "%" before register names. + [case 'c']: Use "nc" for the no-cache case, as recognized by gas. + [case '_']: Don't print "@#" before address. + [case 'J']: Use "%s" as format string, not register name. + [case 'B']: Treat place == 'C' like 'l' and 'L'. + +Thu Oct 5 22:16:20 1995 Ken Raeburn + + * i386-dis.c: Describe cmpxchg8b operand, and spell the opcode + name correctly. + +Tue Oct 3 08:30:20 1995 steve chamberlain + + From David Mosberger-Tang + + * alpha-opc.h (MEMORY_FUNCTION_FORMAT_MASK): added. + (alpha_insn_set): added definitions for VAX floating point + instructions (Unix compilers don't generate these, but handcoded + assembly might still use them). + + * alpha-dis.c (print_insn_alpha): added support for disassembling + the miscellaneous instructions in the Alpha instruction set. + +Tue Sep 26 18:47:20 1995 Stan Shebs + + * mpw-config.in: Add m68k-opc.c.o to BFD_MACHINES for m68k, + no longer create sysdep.h, sed ppc-opc.c to work around a + serious Metrowerks C bug. + * mpw-make.in: Remove. + * mpw-make.sed: New file, used by mpw-configure to edit + Makefile.in into an MPW makefile. + +Wed Sep 20 12:55:28 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New synonym for realclean. + +Tue Sep 19 15:28:36 1995 Ian Lance Taylor + + * m68k-opc.c: Split pmove patterns which use 'P' into patterns + which use '0', '1', and '2' instead. Specify the proper size for + a pmove immediate operand. Correct the pmovefd patterns to be + moves to a register, not from a register. + * m68k-dis.c (print_insn_arg): Replace 'P' with '0', '1', '2'. + +Thu Sep 14 11:58:22 1995 Doug Evans + + * sparc-opc.c (sparc_opcodes): Mark all insns that reference + %psr, %wim, %tbr as F_NOTV9. + +Fri Sep 8 01:07:38 1995 Ian Lance Taylor + + * Makefile.in (Makefile): Just rebuild Makefile when running + config.status. + (config.h, stamp-h): New targets. + * configure.in: Call AC_CONFIG_HEADER and AC_CANONICAL_SYSTEM + earlier. Don't bother to call AC_ARG_PROGRAM. Touch stamp-h when + rebuilding config.h. + * configure: Rebuild. + + * mips-opc.c: Change unaligned loads and stores with "t,A" + operands to use "t,A(b)". + +Thu Sep 7 19:02:46 1995 Jim Wilson + + * sh-dis.c (print_insn_shx): Add F_FR0 support. + +Thu Sep 7 19:02:46 1995 Jim Wilson + + * sh-dis.c (print_insn_shx): Change loop over op->arg[n] to iterate + until 3 instead of until 2. + +Wed Sep 6 21:21:33 1995 Ian Lance Taylor + + * Makefile.in (ALL_CFLAGS): Define. + (.c.o, disassemble.o): Use $(ALL_CFLAGS). + (MOSTLYCLEAN): Add config.log. + (distclean): Don't remove config.log. + * configure.in: Substitute HDEFINES. + * configure: Rebuild. + +Wed Sep 6 15:08:09 1995 Jim Wilson + + * sh-opc.h (sh_arg_type): Add F_FR0. + (sh_table, case fmac): Add F_FR0 as first argument. + +Wed Sep 6 15:08:09 1995 Jim Wilson + + * sh-opc.h (sh_opcode_info): Increase arg array size to 4. + +Tue Sep 5 18:28:10 1995 Doug Evans + + * sparc-dis.c: Remove all references to NO_V9. + +Tue Sep 5 20:03:26 1995 Ian Lance Taylor + + * aclocal.m4: Just include ../bfd/aclocal.m4. + * configure: Rebuild. + +Tue Sep 5 16:09:59 1995 Doug Evans + + * sparc-dis.c (X_DISP19): Define. + (print_insn, case 'G'): Use it. + (print_insn, case 'L'): Sign extend displacement. + +Mon Sep 4 14:28:46 1995 Ian Lance Taylor + + * configure.in: Run ../bfd/configure.host before AC_PROG_CC. + Subsitute CFLAGS and AR. Call AC_PROG_INSTALL. Don't substitute + host_makefile_frag or frags. + * aclocal.m4: New file. + * configure: Rebuild. + * Makefile.in (INSTALL): Set to @INSTALL@. + (INSTALL_PROGRAM): Set to @INSTALL_PROGRAM@. + (INSTALL_DATA): Set to @INSTALL_DATA@. + (AR): Set to @AR@. + (AR_FLAGS): Set to rc rather than qc. + (CC): Define as @CC@. + (CFLAGS): Set to @CFLAGS@. + (@host_makefile_frag@): Remove. + (config.status): Remove dependency upon @frags@. + + * configure.in: ../bfd/config.bfd now just sets shell variables. + Use them rather than looking through target Makefile fragments. + * configure: Rebuild. + +Thu Aug 31 12:35:32 1995 Jim Wilson + + * sh-opc.h (ftrc): Change FPUL_N to FPUL_M. + +Wed Aug 30 13:52:28 1995 Doug Evans + + * sparc-opc.c (sparc_opcodes): Delete duplicate wr %y insn. + Add clrx, iprefetch, signx, clruw, cas, casl, casx, casxl synthetic + sparc64 insns. + + * sparc-opc.c (sparc_opcodes): Fix prefetcha insn. + (lookup_{name,value}): New functions. + (prefetch_table): New static local. + (sparc_{encode,decode}_prefetch): New functions. + * sparc-dis.c (print_insn): Handle '*' arg (prefetch function). + +Wed Aug 30 11:11:58 1995 Jim Wilson + + * sh-opc.h: Add blank lines to improve readabililty of sh3e + instructions. + +Wed Aug 30 11:09:38 1995 Jim Wilson + + * sh-dis.c: Correct comment on first line of file. + +Tue Aug 29 15:37:18 1995 Doug Evans + + * disassemble.c (disassembler): Handle bfd_mach_sparc64. + + * sparc-opc.c (asi, membar): New static locals. + (sparc_{encode,decode}_{asi,membar}): New functions. + (sparc_opcodes, membar insn): Fix. + * sparc-dis.c (print_insn): Call sparc_decode_asi. + Support decoding of membar masks. + (X_MEMBAR): Define. + +Sat Aug 26 21:22:48 1995 Ian Lance Taylor + + * m68k-opc.c (m68k_opcode_aliases): Add br, brs, brb, brw, brl. + +Mon Aug 21 17:33:36 1995 Ian Lance Taylor + + * m68k-opc.c (m68k_opcode_aliases): Add bhib as an alias for bhis, + and likewise for the other branches. Add bhs as an alias for bcc, + and likewise for the size variants. Add dbhs as an alias for + dbcc. + +Fri Aug 11 13:40:24 1995 Jeff Law (law@snake.cs.utah.edu) + + * sh-opc.h (FP sts instructions): Update to match reality. + +Mon Aug 7 16:12:58 1995 Ian Lance Taylor + + * m68k-dis.c: (fpcr_names): Add % before all register names. + (reg_names): Likewise. + (print_insn_arg): Don't explicitly print % before register names. + Add % before register names in static array names. In case 'r', + print data registers as `@(Dn)', not `Dn@'. When printing a + memory address, don't print @# before it. + (print_indexed): Change base_disp and outer_disp from int to + bfd_vma. Print using MIT syntax, not mutant invalid Motorola + syntax. Sign extend 8 byte displacement correctly. + (print_base): Print using MIT syntax. Print zpc when appropriate. + Change parameter disp from int to bfd_vma. + + * m68k-opc.c (m68k_opcode_aliases): Add jsrl and jsrs as aliases + for jsr. + +Mon Aug 7 02:21:40 1995 Jeff Law (law@snake.cs.utah.edu) + + * sh-dis.c (print_insn_shx): Handle new operand types F_REG_N, + F_REG_M, FPSCR_M, FPSCR_N, FPUL_M and FPUL_N. + * sh-opc.h (sh_arg_type): Add new operand types. + (sh_table): Add new opcodes from SH3E Floating Point ISA. + +Sat Aug 5 16:50:14 1995 Fred Fish + + * Makefile.in (distclean): Remove generated file config.h. + +Sat Aug 5 16:50:14 1995 Fred Fish + + * Makefile.in (distclean): Remove generated file config.h. + +Wed Aug 2 18:33:40 1995 Ian Lance Taylor + + * m68k-opc.c: New file, holding tables from include/opcode/m68k.h. + Clean up tables. + * m68k-dis.c: Remove BREAK_UP_BIG_DECL stuff. + (opcode): Remove. + (print_insn_m68k): Change d to be const. Use m68k_numopcodes + rather than numopcodes. Use m68k_opcodes rather than removed + opcode function. Don't check F_ALIAS. + (print_insn_arg): Change first parameter to be const char *. + * Makefile.in (ALL_MACHINES): Add m68k-opc.o. + (m68k-opc.o): New target. + * configure.in: Build m68k-opc.o for bfd_m68k_arch. + * configure: Rebuild. + +Wed Aug 2 08:23:38 1995 Doug Evans + + * sparc-dis.c (HASH_SIZE, HASH_INSN): Define. + (opcode_bits, opcode_hash_table): New variables. + (opcodes_initialized): Renamed from opcodes_sorted. + (build_hash_table): New function. + (is_delayed_branch): Use hash table. + (print_insn): Renamed from print_insn_sparc, made static. + Build and use hash table. If !sparc64, ignore sparc64 insns, + and vice-versa if sparc64. + (print_insn_sparc, print_insn_sparc64): New functions. + (compare_opcodes): Move sparc64 opcodes to end. + Print commutative insns with constant second. + * sparc-opc.c (all non-v9 insns): Use flag F_NOTV9 instead of F_ALIAS. + +Tue Aug 1 00:12:49 1995 Ian Lance Taylor + + * sh-dis.c (print_insn_shx): Remove unused local dslot. Use + print_address_func for A_BDISP12 and A_BDISP8. Correct test which + avoids printing a delay slot in a delay slot. + * sh-opc.h (sh_table): Fully bracket last entry. + +Mon Jul 31 12:04:47 1995 Doug Evans + + * sparc-opc.c (sllx, srax, srlx): Fix disassembly. + +Wed Jul 12 00:59:34 1995 Ken Raeburn + + * configure.in: Get host_makefile_frag from ${srcdir}. + + * configure.in: Autoconfiscated. Check for string[s].h. Create + config.h from config.in. Don't set up sysdep.h link. + * sysdep.h: New file. + * configure, config.in: New files, generated from configure.in. + * Makefile.in: Updated to be processed autoconf-style. + (distclean): Keep sysdep.h. Remove config.log and config.cache. + (Makefile): Depend on config.status. + (config.status): New rule. + * configure.bat: Update Makefile substitutions. + +Tue Jul 11 14:23:37 1995 Jeff Spiegel + + * mips-opc.c (L1): Define. + (mips_opcodes): Add R4010 instructions: flushi, flushd, flushid, + addciu, madd, maddu, ffc, ffs, msub, msubu, selsi, selsr, waiti, + and wb. + +Tue Jul 11 11:49:49 1995 Ian Lance Taylor + + * mips-opc.c (mips_opcodes): For the move pseudo-op, prefer daddu + if ISA 3 and addu otherwise, replacing or, since some MIPS chips + have multiple add units but only a single logical unit. + + * ppc-opc.c (powerpc_operands): Change CR to use a bitsize of 3, + shifted by 18, without any insertion or extraction function. + (insert_cr, extract_cr): Remove. + +Wed Jun 21 20:05:39 1995 Ken Raeburn + + * m68k-dis.c (print_insn_arg, print_indexed): Print "%" before + register names. + +Thu Jun 15 17:23:31 1995 Stan Shebs + + * mpw-config.in: Add sh and i386 configs, remove sparc config. + * sh-opc.h: Add copyright. + +Mon Jun 5 03:30:43 1995 Ken Raeburn + + * Makefile.in (crunch-m68k): Delete extra target accidentally + checked in a while ago. + +Wed May 24 16:22:13 1995 Jim Wilson + + * sh-opc.h (sh_table): Add SH3 support. + +Wed May 24 14:16:08 1995 Steve Chamberlain + + * sh-opc.h: Added bsrf and braf. + +Wed May 10 14:28:16 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * arm-opc.h (arm_opcodes): Add 64-bit multiply patterns. Delete + bogus [ls]fm{ea,fd} patterns. + + * arm-opc.h (arm_opcodes): Correct typos in stm, ldm, std, and ldc. + * arm-dis.c (print_insn_arm): Make GIVEN a parameter, don't try and + initialize it from memory. Make function static. + (print_insn_{big,little}_arm): New functions. + * disassemble.c (disassembler, case bfd_arch_arm): Disassemble for + the correct endianness. + + +Mon Apr 24 14:18:05 1995 Jason Molenda (crash@phydeaux.cygnus.com> + + * sh-opc.h (sh_nibble_type, sh_arg_type): remove trailing , from + enum list. + +Wed Apr 19 14:07:03 1995 Michael Meissner + + * m68k-dis.c (opcode): Finish change made by Kung Hsu on April + 17th, so that it builds again using GCC as the compiler. + +Tue Apr 18 12:14:51 1995 Ken Raeburn + + * mips-dis.c (print_insn_little_mips): Cast return value from + bfd_getl32 from bfd_vma to unsigned long, because _print_insn_mips + expects an unsigned long, and that might be fewer words of + argument storage (e.g., if bfd_vma is long long on a 32-bit + machine). + (print_insn_big_mips): Likewise with bfd_getb32 value. + (_print_insn_mips): Now static. + +Mon Apr 17 12:23:28 1995 Kung Hsu + + * m68k-dis.c: Take out #define BREAK_UP_BIG_DECL kludge, because + gcc memory hog problem with initializer is fixed. + + +Mon Apr 10 15:55:01 1995 Stan Shebs + + Merge in support for Mac MPW as a host. + (Old change descriptions retained for informational value.) + + * mpw-config.in (archname): Compute from the config. + (BFD_MACHINES, ARCHDEFS): Put into mk.tmp. + + * mpw-config.in (target_arch): Compute from canonical target. + (m68k, mips, powerpc, sparc): Add architectures. + * mpw-make.in (disassemble.c.o): Add. + (ALL_CFLAGS): Remove special flags (-mc68020 -mc68881 -model far). + + * mpw-config.in (BFD_MACHINES): Set to a default value. + * mpw-make.in (BFD_MACHINES): Remove wired-in value. + + * mpw-make.in (CSEARCH): Add extra-include to search path. + + * mpw-config.in (varargs.h): Don't create. + (sysdep.h): Create using forward-include. + * mpw-make.in (CSEARCH): Add include/mpw to search path. + + * mpw-config.in: New file, MPW version of configure.in. + * mpw-make.in: New file, MPW version of Makefile.in. + + +Fri Mar 31 14:23:38 1995 Ken Raeburn + + * alpha-dis.c (print_insn_alpha): Put empty statement after + default label. + +Tue Mar 21 10:51:40 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa-dis.c (sign_extend): Delete, redundant with libhppa.h version. + (low_sign_extend): Likewise. + (get_field): Delete unused function. + (set_field, deposit_14, deposit_21): Likewise. + +Fri Mar 17 15:55:53 1995 J.T. Conklin + + * i386-dis.c: Support for more pentium opcodes. From Guy Harris + (guy@netapp.com). + +Tue Mar 14 00:52:57 1995 Ken Raeburn (raeburn@kr-pc.cygnus.com) + + Sat Feb 11 17:22:41 1995 Klaus Kaempf (kkaempf@didymus.rmi.de) + + * alpha-opc.h (OSF_ASMCODE): define + print pal-code names as defined in App C of the + Alpha Architecture Reference Manual + + * alpha-dis.c: cleaned up output + print stylized code forms as defined in App A.4.3 of the + Alpha Architecture Reference Manual + +Wed Mar 8 15:21:14 1995 Ian Lance Taylor + + * mips-opc.c: Add new mips4 instructions. Don't set INSN_RFE for + `rfe'. + * mips-dis.c (print_insn_arg): Handle new argument types 'h', 'R', + 'N', and 'M'. + +Wed Mar 8 02:54:05 1995 Ken Raeburn + + * m68k-dis.c (opcode): New function. Returns address of opcode + table entry given index, even if the opcode table was split to + work around gcc bugs. + (print_insn_m68k): Call opcode instead of referencing m68k_opcodes + directly. + (BREAK_UP_BIG_DECL): Make secondary array static and const. + (reg_names): Now const. + (print_insn_arg): Arrays cacheFieldName and names now const. + (print_indexed): Array scales now const. + + +Tue Mar 7 16:41:21 1995 Ian Lance Taylor + + * ppc-opc.c: Sort recently added instructions by minor opcode + number within major opcode number. + +Mon Mar 6 10:04:36 1995 Jeff Law (law@snake.cs.utah.edu) + + * hppa-dis.c: Include libhppa.h. + +Fri Feb 24 19:15:36 1995 Ian Lance Taylor + + * mips-opc.c: Change dli to use M_DLI, and add dla. + +Mon Feb 20 23:54:38 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * Makefile.in (ALL_MACHINES): Add w65-dis.o. + + +Thu Feb 16 17:34:41 1995 Ian Lance Taylor + + * mips-opc.c: Add r4650 mul instruction. + +Wed Feb 15 15:45:20 1995 Ian Lance Taylor + + * mips-opc.c: Add uld and usd macros for unaligned double load and + store. + +Tue Feb 14 13:17:37 1995 Michael Meissner + + * ppc-opc.c (powerpc_opcodes): Add 403GA opcodes rfci, dccci, + mfdcr, mtdcr, icbt, iccci. + + +Thu Feb 9 12:28:13 1995 Stan Shebs + + * i960-dis.c (struct tabent, struct sparse_tabent): Change the + signed char fields to shorts, more portable. + +Wed Feb 8 17:29:29 1995 Stan Shebs + + * i960-dis.c (struct tabent, struct sparse_tabent): Declare the + char fields as signed chars, since they may have negative values. + +Mon Feb 6 10:52:06 1995 J.T. Conklin + + * i386-dis.c (dis386_twobyte): Add cpuid, From Charles Hannum + (mycroft@netbsd.org). + +Mon Jan 30 12:38:00 1995 Ian Lance Taylor + + From "Logg, Ed" : + * ppc-opc.c (extract_bdm): Correct parenthezisation. + * ppc-dis.c (print_insn_powerpc): Print .long before unrecognized + value. + +Thu Jan 26 18:32:08 1995 Ian Lance Taylor + + * ppc-opc.c: Changes based on patch from David Edelsohn + . + (powerpc_operands): Add operands SPRBAT and SPRG. Split TBR out of + SPR. + (FXM_MASK): Define. + (insert_tbr): New static function. + (extract_tbr): New static function. + (XFXFXM_MASK, XFXM): Define. + (XSPRBAT_MASK, XSPRG_MASK): Define. + (powerpc_opcodes): Add instructions to access special registers by + name. Add mtcr and mftbu. + +Tue Jan 17 10:56:43 1995 Ian Lance Taylor + + * mips-opc.c (P3): Define. + (mips_opcodes): Add mad and madu. + +Sun Jan 15 16:32:59 1995 Steve Chamberlain + + * configure.in: Add W65 support. + * disassemble.c: Likewise. + * w65-opc.h, w65-dis.c: New files. + +Wed Dec 28 22:15:33 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * h8300-dis.c (bfd_h8_disassemble): Add support for 2 bit + immediates. + + +Tue Dec 20 11:25:12 1994 Ian Lance Taylor + + * mips-opc.c: Add dli as a synonym for li. + + +Thu Dec 8 18:23:31 1994 Ken Raeburn + + * alpha-dis.c (print_insn_alpha): Handle call_pal instruction, and + print something for reserved opcode values, even if it won't + assemble again. + + * mips-dis.c (_print_insn_mips): When initializing, shift right + and mask, to avoid sign extension problems on the Alpha. + + * m68k-dis.c (print_insn_arg, case 'J'): Handle buscr and pcr + control registers. + + +Wed Nov 23 22:34:51 1994 Steve Chamberlain (sac@jonny.cygnus.com) + + * sh-opc.h (mov.l gbr): Get direction right. + * sh-dis.c (print_insn_shx): New function. + (print_insn_shl, print_insn_sh): Call print_insn_shx to + print opcodes with right byte order. + +Thu Nov 3 19:32:22 1994 Ken Raeburn + + * ns32k-dis.c (struct ns32k_option): Renamed from struct option, + to avoid conflicts with getopt. + +Mon Oct 31 18:48:10 1994 Ian Lance Taylor + + * hppa-dis.c (print_insn_hppa): Read the instruction using + bfd_getb32, so that it works on a little endian or 64 bit host. + Remove unused local variable op. + +Tue Oct 25 17:07:57 1994 Ian Lance Taylor + + * mips-opc.c: Use or instead of addu for pseudo-op move, since + addu does not work correctly if -mips3. + +Wed Oct 19 13:40:16 1994 Ian Lance Taylor + + * a29k-dis.c (print_special): Add special register names defined + on 29030, 29040 and 29050. + (print_insn): Handle new operand type 'I'. + +Wed Oct 12 11:59:55 1994 Ian Lance Taylor + + * Makefile.in (INSTALL): Use top level install.sh script. + +Wed Oct 5 19:16:29 1994 Ian Lance Taylor + + * sparc-dis.c: Rewrite to use bitfields, rather than a union, so + that it works on a little endian host. + +Tue Oct 4 12:14:21 1994 Ian Lance Taylor + + * configure.in: Use ${config_shell} when running config.bfd. + +Wed Sep 21 18:49:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips-opc.c (mips_opcodes): "dabs" is only available with -mips3. + +Thu Sep 15 16:30:22 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * a29k-dis.c (print_insn): Print the opcode. + +Wed Sep 14 17:52:14 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips-opc.c (mips_opcodes): Set WR_t for sc and scd. + +Sun Sep 11 22:32:17 1994 Jeff Law (law@snake.cs.utah.edu) + + * hppa-dis.c (reg_names): Use r26-r23 for arg0-arg3. + +Tue Sep 6 11:37:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips-opc.c: Set INSN_STORE_MEMORY flag for all instructions + which store a value into memory. + +Sun Sep 04 17:58:10 1994 Richard Earnshaw (rwe@pegasus.esprit.ec.org) + + * configure.in, Makefile.in, disassemble.c: Add support for the ARM. + * arm-dis.c, arm-opc.h: New files. + +Fri Aug 5 14:00:05 1994 Stan Shebs (shebs@andros.cygnus.com) + + * Makefile.in (ns32k-dis.o): Add dependency. + * ns32k-dis.c (print_insn_arg): Declare initialized local as + string, not as array of chars. + +Thu Jul 28 18:14:16 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * sparc-dis.c (print_insn_sparc): Handle new operand type 'x'. + + * sparc-opc.c: Added sparclite extended FP operations, and + versions of v9 impdep* instructions permitting specification of + the OPF field. + +Tue Jul 26 16:36:03 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * i960-dis.c (reg_names): Now const. + (struct sparse_tabent): New type, copied from array type in mem + function. + (ctrl): Local static array ctrl_tab now const. + (cobr): Local static array cobr_tab now const. + (mem): Local variables reg1, reg2, reg3 now point to const. Local + static variable mem_tab no longer explicitly initialized. Changed + mem_init to const array of struct sparse_tabent. + (reg): Local static variable reg_tab no longer explicitly + initialized. Changed reg_init to const array of struct + sparse_tabent. + (ea): Local static array scale_tab now const. + + * i960-dis.c (reg): Added i960JX instructions to reg_init table. + (REG_MAX): Updated. + +Tue Jul 19 21:00:00 1994 DJ Delorie (dj@ctron.com) + + * configure.bat: the disassember needs to be enabled for + "objdump -d" to work in djgpp. + +Wed Jul 13 18:01:58 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * ns32k-dis.c: Deleted all code in "#ifdef GDB". + (invalid_float): Enabled general version, doesn't require running + on ns32k host. Changed to take char* argument, and test for + explicitly specified sizes, instead of using sizeof() on host CPU + types. + (INVALID_FLOAT): Cast first argument. + (opt_u, opt_U, opt_O, opt_C, opt_S, list_P532, list_M532, + list_P032, list_M032): Now const. + (optlist, list_search): Made appropriate arguments now point to + const. + (print_insn_arg): Changed static array of one-character-string + pointers into a static const array of characters; fixed sprintf + statement accordingly. + +Sun Jul 10 00:27:47 1994 Ian Dall (dall@hfrd.dsto.gov.au) + + * opcodes/ns32k-dis.c: Semi-new file. Had apparently been dropped + from distribution. A ns32k-dis.c from a previous distribution has + been brought up to date and supports the new interface. + + * disassemble.c: define ARCH_ns32k and add case bfd_arch_ns32k. + + * configure.in: add bfd_ns32k_arch target support. + + * Makefile.in: add ns32k-dis.o to ALL_MACHINES. + Add ns32k-dis.c to CFILES. Add dependencies for ns32k-dis.o. + +Wed Jun 29 22:10:37 1994 Steve Chamberlain (sac@cygnus.com) + + * h8300-dis.c (bfd_h8_disassemble): Get 16bit branch + disassembly right. + +Tue Jun 28 13:22:06 1994 Stan Shebs (shebs@andros.cygnus.com) + + * h8300-dis.c, mips-dis.c: Don't use true and false. + +Thu Jun 23 12:53:19 1994 David J. Mackenzie (djm@rtl.cygnus.com) + + * configure.in: Change --with-targets to --enable-targets. + +Wed Jun 22 13:38:32 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * mips-dis.c (_print_insn_mips): Build a static hash table mapping + opcodes to the first instruction with that opcode, to speed + disassembly of large files. From ralphc@pyramid.com (Ralph + Campbell). + +Tue Jun 7 12:49:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * Makefile.in (mostlyclean): Fix typo (was mostyclean). + +Wed May 11 22:32:00 1994 DJ Delorie (dj@ctron.com) + + * configure.bat: update to latest makefile.in + +Sat May 7 17:13:21 1994 Steve Chamberlain (sac@cygnus.com) + + * a29k-dis.c (print_insn): Print 'x' type operand in hex. + * h8300-dis.c (bfd_h8_disassemble): Print 16bit rels correctly. + * sh-dis.c (print_insn_sh): Don't recur endlessly if delay + slot insn is in a delay slot. + * z8k-opc.h: (resflg): Fix patterns. + * h8500-opc.h Fix CR insn patterns. + +Fri May 6 14:34:46 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_opcodes): Put PowerPC versions of "cmp" and + "cmpl" before POWER versions, so that gas -many uses them. + +Thu Apr 28 18:32:36 1994 Ken Raeburn (raeburn@cujo.cygnus.com) + + * disassemble.c: New file. + * Makefile.in (OFILES): Add disassemble.o. + (disassemble.o): Provide dependencies; compile with $(ARCHDEFS). + * configure.in: Define ARCHDEFS in Makefile. Code taken from + binutils/configure.in. + + * m68k-dis.c (print_insn_m68k): If F_ALIAS flag is set, skip the + opcode being examined. + +Thu Apr 21 17:08:40 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_operands): Added RAL, RAM and RAS. + (insert_ral, insert_ram, insert_ras): New functions. + (powerpc_opcodes): Use RAL for load with update, RAM for lmw, and + RAS for store with update. + +Sat Apr 16 23:41:44 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_opcodes): Correct fcir. From David Edelsohn + (edelsohn@npac.syr.edu). + +Wed Apr 6 17:11:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c (mips_opcodes): Correct operands of "nor" with an + immediate argument. + +Mon Apr 4 16:30:46 1994 Doug Evans (dje@canuck.cygnus.com) + + * sparc-opc.c (sparc_opcodes): Fix "rd %fprs,%l0". + +Mon Apr 4 13:22:00 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_operands): The signedp field has been + removed, so don't initialize it. Set the PPC_OPERAND_SIGNED flag + instead. Add new operand SISIGNOPT. + (powerpc_opcodes): For lis, liu, addis, and cau use SISIGNOPT. + Based on patch from David Edelsohn (edelsohn@npac.syr.edu). + * ppc-dis.c (print_insn_powerpc): Check PPC_OPERAND_SIGNED rather + than signedp field. + +Wed Mar 30 00:31:49 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * i386-dis.c (struct private): Renamed to dis_private. `private' + is a reserved word for dynix cc. + +Mon Mar 28 13:00:15 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * configure.in: Change error message to refer to bfd/config.bfd + rather than bfd/configure.in. + +Mon Mar 28 12:28:30 1994 David Edelsohn (edelsohn@npac.syr.edu) + + * ppc-opc.c: Define POWER2 as short alias flag. + (powerpc_opcodes): Add POWER/2 opcodes lfq*, stfq*, fcir[z], and + fsqrt. + +Wed Mar 23 12:23:05 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i960-dis.c (print_insn_i960): Don't read a second word for + opcodes 0, 1, 2 and 3. + +Wed Mar 16 15:37:58 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * configure.in: Don't build m68881-ext.o for bfd_m68k_arch. + +Mon Mar 14 14:53:50 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m68881-ext.c: Removed; no longer used. + * Makefile.in: Changed accordingly. + + * m68k-dis.c (ext_format_68881): Don't declare. + (print_insn_m68k): If an instruction uses place 'i', it uses at + least four fixed bytes. + (print_insn_arg): Don't bump p by 2 for case 'I', place 'i'. For + extended float, convert to double using floatformat_to_double, not + ieee_extended_to_double, and fetch the data before converting it. + +Tue Mar 8 18:12:25 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: It's sqrt.s, not sqrt.w. From + davidj@ICSI.Berkeley.EDU (David Johnson). + +Tue Feb 8 16:55:27 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_opcodes): The POWER uses bdn[l][a] where the + PowerPC uses bdnz[l][a]. + +Tue Feb 8 00:32:28 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * dis-buf.c, i386-dis.c: Include sysdep.h. + +Mon Feb 7 19:22:23 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * configure.in (bfd_powerpc_arch): Use ppc-dis.o and ppc-opc.o. + + * ppc-opc.c (powerpc_opcodes): Mark POWER instructions supported + by Motorola PowerPC 601 with PPC_OPCODE_601. + * ppc-dis.c (print_insn_big_powerpc, print_insn_little_powerpc): + Disassemble Motorola PowerPC 601 instructions as well as normal + PowerPC instructions. + +Sun Feb 6 07:45:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) + + * i960-dis.c (reg, mem): Just use a static array instead of + calling xmalloc. + +Sat Feb 5 00:04:02 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-dis.c (print_insn_hppa): For '?' and '@' only adjust the + condition name index if this is for a negated condition. + + * hppa-dis.c (print_insn_hppa): No space before 'H' operand. + Floating point format for 'H' operand is backwards from normal + case (0 == double, 1 == single). For '4', '6', '7', '9', and '8' + operands (fmpyadd and fmpysub), handle bizarre register + translation correctly for single precision format. + + * hppa-dis.c (print_insn_hppa): Do not emit a space after 'F' + or 'I' operands if the next format specifier is 'M' (fcmp + condition completer). + +Feb 4 23:38:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c (powerpc_operands): New operand type MBE to handle a + single number giving a bitmask for the MB and ME fields of an M + form instruction. Change NB to accept 32, and turn it into 0; + also turn 0 into 32 when disassembling. Seperated SH from NB. + (insert_mbe, extract_mbe): New functions. + (insert_nb, extract_nb): New functions. + (SC_MASK): Mask out SA and LK bits. + (powerpc_opcodes): Change "cal" to use RT, D, RA rather than RT, + RA, SI. Change "liu" and "cau" to use UI rather than SI. Mark + "bctr" and "bctrl" as accepted by POWER. Change "rlwimi", + "rlimi", "rlwimi.", "rlimi.", "rlwinm", "rlinm", "rlwinm.", + "rlinm.", "rlmi", "rlmi.", "rlwnm", "rlnm", "rlwnm.", "rlnm." to + use MBE rather than MB. Add "mfmq" and "mtmq" POWER instructions. + (powerpc_macros): Define table of macro definitions. + (powerpc_num_macros): Define. + + * ppc-dis.c (print_insn_powerpc): Don't skip optional operands + if PPC_OPERAND_NEXT is set. + +Sat Jan 22 23:10:07 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * i960-dis.c (print_insn_i960): Make buffer bfd_byte instead of + char. Retrieve contents using bfd_getl32 instead of shifting. + +Fri Jan 21 19:01:39 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * ppc-opc.c: New file. Opcode table for PowerPC, including + opcodes for POWER (RS/6000). + * ppc-dis.c: New file. PowerPC and Power (RS/6000) disassembler. + * Makefile.in (ALL_MACHINES): Add ppc-dis.o and ppc-opc.o. + (CFILES): Add ppc-dis.c. + (ppc-dis.o, ppc-opc.o): New targets. + * configure.in: Build ppc-dis.o and ppc-opc.o for bfd_rs6000_arch. + +Mon Jan 17 20:05:49 1994 Jeffrey A. Law (law@snake.cs.utah.edu) + + * hppa-dis.c (print_insn_hppa): Handle 'N' in assembler template. + No space before 'u', 'f', or 'N'. + +Sun Jan 16 14:20:16 1994 Jim Kingdon (kingdon@deneb.cygnus.com) + + * i386-dis.c (print_insn_i386): Add FIXME comment regarding reading + farther than we should. + + * i386-dis.c (dis386): Use Yb and Yv for scasb and scasS. + +Thu Jan 6 12:38:05 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * sparc-dis.c m68k-dis.c alpha-dis.c a29k-dis.c: Fix comments. + +Wed Jan 5 11:56:21 1994 David J. Mackenzie (djm@thepub.cygnus.com) + + * i960-dis.c (print_insn_i960): Only read word2 if the instruction + needs it, to prevent reading past the end of a section. + +Wed Nov 17 17:20:12 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.h: Use macro for j instruction, to support SVR4 PIC. + Removed t,A case for la; always use t,A(b) case. + +Mon Nov 8 12:37:36 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + From Ted Lemen + * mips-dis.c (print_insn_arg): Handle 'k'. + * mips-opc.c: Make cache use k, not t. + +Sun Nov 7 23:52:34 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-opc.h, alpha-dis.c (print_insn_alpha): Add + FLOAT_MEMORY_FORMAT_CODE, FLOAT_BRANCH_FORMAT_CODE, correct + FLOAT_FORMAT_CODE to put out floating point register names. + +Mon Nov 1 18:17:51 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Use macros for jal variants, to support SVR4 PIC. + +Thu Oct 28 17:42:23 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * a29k-dis.c (print_insn): Use 0x%08x, not 0x%8x. + +Wed Oct 27 11:48:01 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c (dsll, dsra, dsrl): Added '>' cases for shift counts + larger than 32. Moved dsxx32 variants first for disassembler. + +Mon Oct 25 11:33:14 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * z8kgen.c, z8k-opc.h: Add full lda information. + +Tue Oct 19 12:39:25 1993 Jeffrey A Law (law@cs.utah.edu) + + * hppa-dis.c (print_insn_hppa): Do not emit a space after + movb instructions. Any necessary space will be emitted by + the code to handle nullification completers. + +Wed Oct 13 16:19:07 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Moved l.d down so that it disassembles as ldc1. + +Fri Oct 8 02:34:21 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-opc.h: Add ldl_l, fix typo for ldq_u. + * alpha-dis.c (print_insn_alpha): Add code for PAL_FORMAT_CODE. + +Tue Oct 5 17:47:53 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Correct lwu opcode value (book had it wrong). + +Thu Sep 30 11:26:18 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * z8k-dis.c (FETCH_DATA): get just the right amount of data. + (unpack_instr): Cope with ARG_IMM4M1 type instructions. + +Wed Sep 29 16:24:49 1993 K. Richard Pixley (rich@sendai.cygnus.com) + + * m88k-dis.c (m88kdis): comment change. Remove space after + printing mnemonic. + (printop): handle new arg types DEC and XREG for m88110. + +Tue Sep 28 19:20:16 1993 Jeffrey A Law (law@snake.cs.utah.edu) + + * hppa-dis.c (print_insn_hppa): Handle 'z' operand + type for absolute branch addresses. Delete special + "ble" and "be" code in 'W' operand code. + +Fri Sep 24 14:08:33 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Set hazard information correctly for branch + likely instructions. + +Fri Sep 17 04:41:17 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * alpha-dis.c (print_insn_alpha), alpha-opc.h: Fix bugs, use + info->fprintf_func for printing and info->print_address_func for + address output. + +Wed Sep 15 12:12:07 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Set INSN_TRAP for tXX instructions. + +Thu Sep 9 10:11:27 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: From davidj@ICSI.Berkeley.EDU (David Johnson): + Corrected second case of "b" for disassembler. + +Tue Sep 7 14:25:15 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-dis.c, m88k-dis.c: Don't include libbfd.h. Changed calls + to BFD swapping routines to correspond to BFD name changes. + +Thu Sep 2 10:35:25 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Change div machine instruction to be z,s,t rather + than s,t. Change div macro to be d,v,t rather than d,s,t. + Likewise for divu, ddiv, ddivu. Added z,s,t case for drem, dremu, + rem and remu which generates only the corresponding div + instruction. This is for compatibility with the MIPS assembler, + which only generates the simple machine instruction when an + explicit destination of $0 is used. + * mips-dis.c (print_insn_arg): Handle 'z' (always register zero). + +Thu Aug 26 17:41:44 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: From davidj@ICSI.Berkeley.EDU (David Johnson): Set + WR_31 hazard for bal, bgezal, bltzal. + +Thu Aug 26 17:20:02 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * hppa-dis.c (print_insn_hppa): Use print function + from within the disassemble_info, not fprintf_filtered. + +Wed Aug 25 13:51:40 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * hppa-dis.c (print_insn_hppa): Handle '|' like '>'. (From Jeff + Law, law@cs.utah.edu.) + +Mon Aug 23 12:44:05 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c ("absu"): Removed. + ("dabs"): Added. + +Fri Aug 20 10:52:52 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Added r6000 and r4000 instructions and macros. + Changed hazard information to distinguish between memory load + delays and coprocessor load delays. + +Wed Aug 18 15:39:23 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: li.d uses "T,L", not "S,F". Added li.s. + +Tue Aug 17 09:44:42 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * configure.in: Don't pass cpu to config.bfd. + +Tue Aug 17 12:23:52 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m88k-dis.c (m88kdis): Make class unsigned. + +Thu Aug 12 15:08:18 1993 Ian Lance Taylor (ian@cygnus.com) + + * alpha-dis.c (print_insn_alpha): One branch format case was + missing the instruction name. + +Wed Aug 11 19:29:39 1993 David J. Mackenzie (djm@thepub.cygnus.com) + + * Makefile.in (ALL_MACHINES): Renamed from DIS_LIBS. + Add the arch-specific auxiliary files. + (OFILES): Remove the arch-specific auxiliary files + and use BFD_MACHINES instead of DIS_LIBS. + * configure.in: Set BFD_MACHINES based on --with-targets option. + +Thu Aug 12 12:04:53 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: Added lwc1 E,A(b) to go with lwc1 T,A(b). Similarly + for swc1. + +Sun Aug 8 15:09:30 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc-opc.c: Change CONST to const to deal with gcc + -Dconst=__const -traditional. + +Fri Aug 6 10:58:55 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-opc.c: From davidj@ICSI.Berkeley.EDU (David Johnson): Took + coprocessor instructions out of #if 0, and made them use new + argument type "C". + +Thu Aug 5 17:11:06 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * sparc-dis.c: Include ansidecl.h before opcodes/sparc.h. + +Fri Jul 30 18:48:15 1993 John Gilmore (gnu@cygnus.com) + + * sparc-opc.c: Add F_JSR, F_UNBR, or F_CONDBR flags to each branch + instruction, for use by the disassembler. + + * sparc-dis.c (SEX): Add sign extension macro. Replace many + hand-coded sign extensions that depended on 32-bit host ints. + FIXME, we still depend on big-endian host bitfield ordering. + (sparc_print_insn): Set the insn_info_valid field, and the + other fields that describe the instruction being printed. + +Tue Jul 27 17:04:58 1993 Jim Wilson (wilson@sphagnum.cygnus.com) + + * sparc-opc.c (call): Accept all 6 addressing modes valid for + `jmp' instead of just one of them. + +Wed Jul 21 11:43:32 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * hppa-dis.c: Move floating registers from reg_names to fp_reg_names. + (fput_fp_reg_r): Renamed from fput_reg_r. + (fput_fp_reg): New function. + (print_insn_hppa): Use fput_fp_reg{,_r} where appropriate. + + * hppa-dis.c (print_insn_hppa, cases 'a', 'd'): Print space afterwards. + + * hppa-dis.c (print_insn_hppa, case 'd'): Use GET_COND not GET_FIELD. + +Mon Jul 19 13:52:21 1993 Jim Kingdon (kingdon@deneb.cygnus.com) + + * hppa-dis.c (print_insn_hppa): Use extract_5r_store for 'r'. + + * hppa-dis.c (print_insn_hppa, case '>'): If next character is 'n', + don't output a space. + + * hppa-dis.c (float_format_names): 10 is undefined, and 11 is quad. + +Sun Jul 18 16:30:02 1993 Jim Kingdon (kingdon@rtl.cygnus.com) + + * mips-opc.c: New file, containing opcode table from + ../include/opcode/mips.h. + * Makefile.in: Add it. + +Thu Jul 15 12:37:05 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * m88k-dis.c: New file, moved in from gdb and changed to use the + new dis-asm.h disassembler interface. + * Makefile.in (DIS_LIBS): Added m88k-dis.o. + (m88k-dis.o): New target. + +Tue Jul 13 10:04:16 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips-dis.c (print_insn_arg, _print_insn_mips): Made pointer to + argument string const char * to correspond to opcode/mips.h. + +Tue Jul 6 15:18:37 1993 Ian Lance Taylor (ian@cygnus.com) + + * mips-dis.c: Updated to account for name changes in new version + of opcode/mips.h. + * Makefile.in: Added header file dependencies. + +Sat Jul 3 23:47:56 1993 Doug Evans (dje@canuck.cygnus.com) + + * h8300-dis.c (bfd_h8_disassemble): Correct fetching of instruction. + +Thu Jul 1 12:23:38 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * m68k-dis.c (NEXTWORD, NEXTLONG): Use ((x) ^ 0x8000) - 0x8000 to sign + extend, rather than shifts. + +Sun Jun 20 20:56:56 1993 Ken Raeburn (raeburn@poseidon.cygnus.com) + + * Makefile.in: Undo 15 June change. + +Fri Jun 18 14:15:15 1993 Per Bothner (bothner@deneb.cygnus.com) + + * m68k-dis.c (print_insn_arg): Change return value to byte count + or error code. + * m68k-dis.c: Re-write to detect invalid operands before + printing anything, so we can handle this the same way we + handle invalid opcodes. + +Thu Jun 17 15:01:36 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * sh-dis.c, sh-opc.h: Understand some more opcodes. + +Wed Jun 16 13:48:05 1993 Ian Lance Taylor (ian@cygnus.com) + + * hppa-dis.c: Include and sysdep.h before other + header files. + +Tue Jun 15 21:45:26 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * sparc-dis.c: Don't declare qsort, since sysdep.h might. + + * configure.in: Do make sysdep.h link. + * Makefile.in: Search ../include. Don't search ../bfd. + +Tue Jun 15 13:36:10 1993 Stu Grossman (grossman@cygnus.com) + + Changes from Jeff Law, law@cs.utah.edu: + * hppa-dis.c: Fix typo. 'a' and 'd' were reversed. + Do not print a space before the completers specified by + 'a' and 'd'. + +Fri Jun 11 18:40:21 1993 Ken Raeburn (raeburn@cygnus.com) + + * mips-dis.c: No longer need to bomb out if HOST_64_BIT is + defined, since gdb has been fixed. + + Changes from Jeff Law, law@cs.utah.edu: + * hppa-dis.c (print_insn_hppa): Last argument to fput_reg, + fput_reg_r, fput_creg, fput_const, and fputs_filtered should + be a *disassemble_info, not a *FILE. + * hppa-dis.c: Support 'd', '!', and 'a'. + * hppa-dis.c: Support 's' to extract a 2 bit space register. + * hppa-dis.c: Delete cases which are no longer needed. + +Fri Jun 11 07:53:48 1993 Jim Kingdon (kingdon@cygnus.com) + + * m68k-dis.c (print_insn_{m68k,arg}): Add MMU codes. + +Tue Jun 8 12:25:01 1993 Steve Chamberlain (sac@phydeaux.cygnus.com) + + * h8300-dis.c: New file, removed from bfd/cpu-h8300.c, with + H8/300-H opcodes. + +Mon Jun 7 12:58:49 1993 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in (CSEARCH): Add -I../bfd for sysdep.h and bfd.h. + * configure.in: No longer need to configure to get sysdep.h. + +Thu Jun 3 15:56:49 1993 Stu Grossman (grossman@cygnus.com) + + * Patches from Jeffrey Law . + * hppa-dis.c: Support 'I', 'J', and 'K' in output + templates for 1.1 FP computational instructions. + +Tue May 25 13:05:48 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * h8500-dis.c (print_insn_h8500): Address argument is type + bfd_vma. + * z8k-dis.c (print_insn_z8k, print_insn_z8001, print_insn_z8002): + Ditto. + + * h8500-opc.h (addr_class_type): No comma at end of enumerator. + * sh-opc.h (sh_nibble_type, sh_arg_type): Ditto. + + * sparc-dis.c (compare_opcodes): Move static declaration to + top-level. + +Fri May 21 14:17:37 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * sparc-dis.c (print_insn_sparc): Implement 'n' argument for unimp + instruction, remove unimp hack from 'l' argument. + +Wed May 19 15:35:54 1993 Stu Grossman (grossman@cygnus.com) + + * z8k-dis.c (fetch_data): Use unsigned char to make ancient gcc's + happy. + +Fri May 14 15:22:46 1993 Ian Lance Taylor (ian@cygnus.com) + + * Based on patches from davidj@ICSI.Berkeley.EDU (David Johnson): + * mips-dis.c (print_insn_arg): Handle 'C' for general coprocessor + instructions. + +Fri May 14 00:09:14 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * hppa-dis.c: Include dis-asm.h before sysdep.h. Changed some + arrays of string pointers to 2-d arrays of chars, to save + space. + +Thu May 6 20:51:17 1993 Fred Fish (fnf@cygnus.com) + + * a29k-dis.c, alpha-dis.c, i960-dis.c, sparc-dis.c, z8k-dis.c: + Cast second arg to read_memory_func to "bfd_byte *", as necessary. + +Tue May 4 20:31:10 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * hppa-dis.c: New file from Utah, adapted to new disassembler + calling interface. + * Makefile.in: Include it. + +Mon Apr 26 18:17:42 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * sh-dis.c, sh-opc.h: New files. + +Fri Apr 23 18:51:22 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * alpha-dis.c, alpha-opc.h: New files. + +Tue Apr 6 12:54:08 1993 Peter Schauer (pes@regent.e-technik.tu-muenchen.de) + + * mips-dis.c: Sign extend 'j' and 'b' arguments, delta is a signed + value. + +Mon Apr 5 17:37:37 1993 John Gilmore (gnu@cygnus.com) + + * sparc-dis.c: Make "ta" the default trap instruction, "t" the alias. + +Fri Apr 2 07:24:27 1993 Ian Lance Taylor (ian@cygnus.com) + + * a29k-dis.c, sparc-dis.c, sparc-opc.c: Use CONST rather than + const. + +Thu Apr 1 11:20:43 1993 Jim Kingdon (kingdon@cygnus.com) + + * sparc-dis.c: Use fprintf_func a few places where I forgot, + and double percent signs a few places. + + * a29k-dis.c, i960-dis.c: New, merged from gdb and binutils. + + * i386-dis.c, m68k-dis.c, mips-dis.c, sparc-dis.c: + Use info->print_address_func not print_address. + + * dis-buf.c (generic_print_address): New function. + +Wed Mar 31 10:07:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * Makefile.in: Add sparc-dis.c. + sparc-dis.c: New file, merges binutils and gdb versions as follows: + From GDB: + Add `add' instruction to the set that get checked + for a preceding `sethi' in order to print an absolute address. + * (print_insn): Disassembly prefers real instructions. + (is_delayed_branch): Speed up. + * sparc-opcode.h: Add ALIAS bit to aliases. Fix up opcode tables. + Still missing some float ops, and needs testing. + * sparc-pinsn.c (print_insn): Eliminate 'set' test, subsumed by + F_ALIAS. Use printf, not fprintf, when not passing a file + pointer... + (compare_opcodes): Check that identical instructions have + identical opcodes, complain otherwise. + From binutils: + * New 'm' arg. + * Include reg_names. + From neither: + Use dis-asm.h/read_memory_func interface. + +Wed Mar 31 20:49:06 1993 K. Richard Pixley (rich@rtl.cygnus.com) + + * h8500-dis.c, i386-dis.c, m68k-dis.c, z8k-dis.c (fetch_data): + deliberately return non-zero to setjmp from longjmp. Otherwise + this code fails to compile. + +Wed Mar 31 17:04:31 1993 Stu Grossman (grossman@cygnus.com) + + * m68k-dis.c: Fix prototype for fetch_arg(). + +Wed Mar 31 10:07:04 1993 Jim Kingdon (kingdon@lioth.cygnus.com) + + * dis-buf.c: New file, for new read_memory_func interface. + Makefile.in (OFILES): Include it. + m68k-dis.c, i386-dis.c, h8500-dis.c, mips-dis.c, z8k-dis.c: + Use new read_memory_func interface. + +Mon Mar 29 14:02:17 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * h8500-dis.c (print_insn_h8500): Get sign of fp offsets right. + * h8500-opc.h: Fix couple of opcodes. + +Wed Mar 24 02:03:36 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com) + + * Makefile.in: add dvi & installcheck targets + +Mon Mar 22 18:55:04 1993 John Gilmore (gnu@cygnus.com) + + * Makefile.in: Update for h8500-dis.c. + +Fri Mar 19 14:27:17 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * h8500-dis.c, h8500-opc.h: New files + +Thu Mar 18 14:12:37 1993 Per Bothner (bothner@rtl.cygnus.com) + + * mips-dis.c, z8k-dis.c: Converted to use interface defined in + ../include/dis-asm.h. + * m68k-dis.c: New file (merge of ../binutils/m68k-pinsn.c + and ../gdb/m68k-pinsn.c). + * i386-dis.c: New file (merge of ../binutils/i386-pinsn.c + and ../gdb/i386-pinsn.c). + * m68881-ext.c: New file. Moved definition of + ext_format ext_format_68881 from ../gdb/m68k-tdep.c. + * Makefile.in: Adjust for new files. + * i386-dis.c: Patches from John Hassey (hassey@dg-rtp.dg.com). + * m68k-dis.c: Recognize '9' placement code, so (say) pflush + can be dis-assembled. + +Wed Feb 17 09:19:47 1993 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * mips-dis.c (print_insn_arg): Now returns void. + +Mon Jan 11 16:09:16 1993 Fred Fish (fnf@cygnus.com) + + * mips-dis.c (ansidecl.h): Include for benefit of sysdep.h + files that use the macros. + +Thu Jan 7 13:15:17 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * mips-dis.c: New file, from gdb/mips-pinsn.c. + * Makefile.in (DIS_LIBS): Added mips-dis.o. + (CFILES): Added mips-dis.c. + +Thu Jan 7 07:36:33 1993 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8k-dis.c (print_insn_z8001, print_insn_z8002): new routines + * z8kgen.c, z8k-opc.h: fix sizes of some shifts. + +Tue Dec 22 15:42:44 1992 Per Bothner (bothner@rtl.cygnus.com) + + * Makefile.in: Improve *clean rules. + * configure.in: Allow a default host. + +Tue Nov 17 19:53:54 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * Makefile.in: also use -I$(srcdir)/../bfd, since some sysdep + files include other sysdep files + +Thu Nov 12 16:10:37 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8k-dis.c z8k-opc.h z8kgen.c: checkpoint + +Fri Oct 9 04:56:05 1992 John Gilmore (gnu@cygnus.com) + + * configure.in: For host support, use ../bfd/configure.host + so it stays in sync with the ../bfd/hosts database. + +Thu Oct 1 23:38:54 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) + + * configure.in: use cpu-vendor-os triple instead of nested cases + +Wed Sep 30 16:09:20 1992 Michael Werner (mtw@cygnus.com) + + * z8k-dis.c (unparse_instr): fix bug where opcode returned was + *always* the wrong one. + +Wed Sep 30 07:42:17 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8kgen.c: added copyright info + +Tue Sep 29 12:20:21 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8k-dis.c (unparse_instr): prettier tabs + * z8kgen.c -> z8k-opc.h: bug fixes in tables + +Fri Sep 25 12:50:32 1992 Stu Grossman (grossman at cygnus.com) + + * configure.in: Add ncr* configuration. + * z8k-dis.c (struct instr_data_s): Make instr_asmsrc char to make + picayune ANSI compilers happy. + +Sep 20 08:50:55 1992 Fred Fish (fnf@cygnus.com) + + * configure.in (i386): Make i386 and i486 synonymous for now. + * configure.in (i[34]86-*-sysv4): Add my_host definition. + +Fri Sep 18 17:01:23 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (install): Fix typo. + +Fri Sep 18 02:04:24 1992 John Gilmore (gnu@cygnus.com) + + * Makefile.in (make): Remove obsolete crud. + (sparc-opc.o): Avoid Sun Make VPATH bug. + +Tue Sep 8 17:29:27 1992 K. Richard Pixley (rich@sendai.cygnus.com) + + * Makefile.in: since there are no SUBDIRS, remove rule and + references of subdir_do. + +Tue Sep 8 17:02:58 1992 Ken Raeburn (raeburn@cambridge.cygnus.com) + + * Makefile.in (install): Get the library name right here too. + Don't install bfd.h, since it's unrelated to this library. No + subdirs to recurse into, either. + (CFILES): The source file has a .c suffix, not .o. + + * sparc-opc.c: New file, moved from BFD. + * Makefile.in (OFILES): Build it. + +Thu Sep 3 16:59:20 1992 Michael Werner (mtw@cygnus.com) + + * z8k-dis.c: fixed forward refferences of some declarations. + +Mon Aug 31 16:09:45 1992 Michael Werner (mtw@cygnus.com) + + * Makefile.in: get the name of the library right + +Mon Aug 31 13:47:35 1992 Steve Chamberlain (sac@thepub.cygnus.com) + + * z8k-dis.c: knows how to disassemble z8k stuff + * z8k-opc.h: new file full of z8000 opcodes + + +Local Variables: +version-control: never +End: diff --git a/contrib/gdb/opcodes/Makefile.in b/contrib/gdb/opcodes/Makefile.in new file mode 100644 index 000000000000..c274cb173a46 --- /dev/null +++ b/contrib/gdb/opcodes/Makefile.in @@ -0,0 +1,305 @@ +# Makefile template for Configure for the opcodes library. +# Copyright (C) 1990, 1991, 1992, 1995 Free Software Foundation, Inc. +# Written by Cygnus Support. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +VPATH = @srcdir@ +srcdir = @srcdir@ + +prefix = @prefix@ + +program_transform_name = @program_transform_name@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +oldincludedir = +docdir = $(srcdir)/doc + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +AR = @AR@ +AR_FLAGS = rc +CC = @CC@ +CFLAGS = @CFLAGS@ +MAKEINFO = makeinfo +RANLIB = @RANLIB@ + +ALLLIBS = @ALLLIBS@ + +PICFLAG = @PICFLAG@ +SHLIB = @SHLIB@ +SHLIB_CC = @SHLIB_CC@ +SHLIB_CFLAGS = @SHLIB_CFLAGS@ +COMMON_SHLIB = @COMMON_SHLIB@ +SHLIB_DEP = @SHLIB_DEP@ +SHLINK = @SHLINK@ + +SONAME = lib`echo $(SHLIB) | sed -e 's,^\.\./bfd/,,' -e 's/^lib//' | sed '$(program_transform_name)'` + +INCDIR = $(srcdir)/../include +BFDDIR = $(srcdir)/../bfd +CSEARCH = -I. -I$(srcdir) -I../bfd -I$(INCDIR) -I$(BFDDIR) +DEP = mkdep + +TARGETLIB = libopcodes.a + +# To circumvent a Sun make VPATH bug, each file listed here +# should also have a foo.o: foo.c line further along in this file. + +ALL_MACHINES = a29k-dis.o alpha-dis.o h8300-dis.o h8500-dis.o \ + hppa-dis.o i386-dis.o i960-dis.o m68k-dis.o m68k-opc.o \ + m88k-dis.o mips-dis.o mips-opc.o sh-dis.o sparc-dis.o \ + sparc-opc.o z8k-dis.o ns32k-dis.o ppc-dis.o ppc-opc.o \ + arm-dis.o w65-dis.o + +OFILES = @BFD_MACHINES@ dis-buf.o disassemble.o + +FLAGS_TO_PASS = \ + "against=$(against)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "MAKEINFO=$(MAKEINFO)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" + +ALL_CFLAGS = $(CSEARCH) @HDEFINES@ $(CFLAGS) + +.c.o: + if [ -n "$(PICFLAG)" ]; then \ + $(CC) -c $(PICFLAG) $(ALL_CFLAGS) $< -o pic/$@; \ + else true; fi + $(CC) -c $(ALL_CFLAGS) $< + +# C source files that correspond to .o's. +CFILES = i386-dis.c z8k-dis.c m68k-dis.c mips-dis.c ns32k-dis.c ppc-dis.c + +all: $(ALLLIBS) + +.NOEXPORT: + +installcheck check: + +info: +clean-info: +install-info: +dvi: + +# HDEPFILES comes from the host config; TDEPFILES from the target config. + + +$(TARGETLIB): $(OFILES) + rm -f $(TARGETLIB) + $(AR) $(AR_FLAGS) $(TARGETLIB) $(OFILES) + $(RANLIB) $(TARGETLIB) + +LIBIBERTY_LISTS = ../libiberty/required-list ../libiberty/needed-list +BFD_LIST = ../bfd/piclist + +stamp-piclist: Makefile $(LIBIBERTY_LISTS) $(BFD_LIST) + rm -f tpiclist + if [ -n "$(PICFLAG)" ]; then \ + echo $(OFILES) | sed -e 's,\([^ ][^ ]*\),pic/\1,g' > tpiclist; \ + else \ + echo $(OFILES) > tpiclist; \ + fi + if [ "$(COMMON_SHLIB)" = "yes" ]; then \ + lobjs=`cat $(LIBIBERTY_LISTS)`; \ + if [ -n "$(PICFLAG)" ]; then \ + lobjs=`echo $$lobjs | sed -e 's,\([^ ][^ ]*\),pic/\1,g'`; \ + fi; \ + lobjs=`echo $$lobjs | sed -e 's,\([^ ][^ ]*\),../libiberty/\1,g'`; \ + echo $$lobjs >> tpiclist; \ + sed -e 's,\([^ ][^ ]*\),../bfd/\1,g' $(BFD_LIST) >> tpiclist; \ + else true; fi + $(srcdir)/../move-if-change tpiclist piclist + touch stamp-piclist + +piclist: stamp-piclist ; @true + +$(SHLIB): stamp-picdir $(OFILES) piclist $(SHLIB_DEP) + rm -f $(SHLIB) + $(SHLIB_CC) $(SHLIB_CFLAGS) -o $(SHLIB) `cat piclist` + +$(SHLINK): $(SHLIB) + ts=lib`echo $(SHLIB) | sed -e 's,^\.\./bfd/,,' -e 's/^lib//' | sed -e '$(program_transform_name)'`; \ + if [ "$(COMMON_SHLIB)" = "yes" ]; then \ + ts=../bfd/$$ts; \ + fi; \ + if [ "$$ts" != "$(SHLIB)" ]; then \ + rm -f $$ts; \ + ln -sf `echo $(SHLIB) | sed -e 's,^\.\./bfd/,,'` $$ts; \ + else true; fi + rm -f $(SHLINK) + ln -sf `echo $(SHLIB) | sed -e 's,^\.\./bfd/,,'` $(SHLINK) + +# This target creates libTARGET-opcodes.so.VERSION as a symlink to +# libopcodes.so.VERSION. It is used on SunOS, which does not have SONAME. +stamp-tshlink: $(SHLIB) + tf=lib`echo $(SHLIB) | sed -e 's,\.\./bfd/,,' -e 's/^lib//' | sed '$(program_transform_name)'`; \ + if [ "$(COMMON_SHLIB)" = "yes" ]; then \ + tf=../bfd/$$tf; \ + fi; \ + if [ "$$tf" != "$(SHLIB)" ]; then \ + rm -f $$tf; \ + ln -sf $(SHLIB) $$tf; \ + else true; fi + if [ "$(COMMON_SHLIB)" = "yes" ]; then \ + tf=lib`echo $(TARGETLIB) | sed -e 's/^lib//' | sed '$(program_transform_name)'`; \ + if [ "$$tf" != "$(TARGETLIB)" ]; then \ + rm -f $$tf; \ + ln -sf $(TARGETLIB) $$tf; \ + else true; fi; \ + else true; fi + touch stamp-tshlink + +$(OFILES): stamp-picdir + +disassemble.o: disassemble.c $(INCDIR)/dis-asm.h + if [ -n "$(PICFLAG)" ]; then \ + $(CC) -c @archdefs@ $(PICFLAG) $(ALL_CFLAGS) $(srcdir)/disassemble.c -o pic/disassemble.o; \ + else true; fi + $(CC) -c @archdefs@ $(ALL_CFLAGS) $(srcdir)/disassemble.c + +a29k-dis.o: a29k-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/a29k.h +dis-buf.o: dis-buf.c $(INCDIR)/dis-asm.h +h8500-dis.o: h8500-dis.c h8500-opc.h $(INCDIR)/dis-asm.h +h8300-dis.o: h8300-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/h8300.h +i386-dis.o: i386-dis.c $(INCDIR)/dis-asm.h +i960-dis.o: i960-dis.c $(INCDIR)/dis-asm.h +w65-dis.o: w65-dis.c +m68k-dis.o: m68k-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/floatformat.h \ + $(INCDIR)/opcode/m68k.h +m68k-opc.o: m68k-opc.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/m68k.h +mips-dis.o: mips-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/mips.h +mips-opc.o: mips-opc.c $(INCDIR)/opcode/mips.h +ppc-dis.o: ppc-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/ppc.h +ppc-opc.o: ppc-opc.c $(INCDIR)/opcode/ppc.h +sparc-dis.o: sparc-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/sparc.h +sparc-opc.o: sparc-opc.c $(INCDIR)/opcode/sparc.h +z8k-dis.o: z8k-dis.c z8k-opc.h $(INCDIR)/dis-asm.h +ns32k-dis.o: ns32k-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/ns32k.h +sh-dis.o: sh-dis.c sh-opc.h $(INCDIR)/dis-asm.h +alpha-dis.o: alpha-dis.c alpha-opc.h $(INCDIR)/dis-asm.h +hppa-dis.o: hppa-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/hppa.h +m88k-dis.o: m88k-dis.c $(INCDIR)/dis-asm.h $(INCDIR)/opcode/m88k.h +arm-dis.o: arm-dis.c arm-opc.h $(INCDIR)/dis-asm.h + +tags etags: TAGS + +TAGS: force + etags $(INCDIR)/*.h $(srcdir)/*.h $(srcdir)/*.c + +MOSTLYCLEAN = *.o core *.E *.p *.ip config.log pic/*.o +mostlyclean: + rm -rf $(MOSTLYCLEAN) +clean: + rm -f *.a $(MOSTLYCLEAN) $(SHLIB) $(SHLINK) piclist stamp-piclist +distclean: clean + rm -rf Makefile config.status TAGS config.cache config.h stamp-h \ + pic stamp-picdir +clobber realclean maintainer-clean: distclean + +# Mark everything as depending on config.status, since the timestamp on +# sysdep.h might actually move backwards if we reconfig and relink it +# to a different hosts/h-xxx.h file. This will force a recompile anyway. +RECONFIG = config.status + + + +# This target should be invoked before building a new release. +# 'VERSION' file must be present and contain a string of the form "x.y" +# +roll: + @V=`cat VERSION` ; \ + MAJ=`sed 's/\..*//' VERSION` ; \ + MIN=`sed 's/.*\.//' VERSION` ; \ + V=$$MAJ.`expr $$MIN + 1` ; \ + rm -f VERSION ; \ + echo $$V >VERSION ; \ + echo Version $$V + +# Dummy target to force execution of dependent targets. +# +force: + +install: $(ALLLIBS) + for f in $(ALLLIBS); do \ + if [ "$$f" = "stamp-tshlink" ]; then \ + continue; \ + fi; \ + tf=lib`echo $$f | sed -e 's,^\.\./bfd/,,' -e 's/^lib//' | sed '$(program_transform_name)'`; \ + rm -f $(libdir)/$$tf; \ + if [ "$$f" = "$(SHLINK)" ]; then \ + ts=lib`echo $(SHLIB) | sed -e 's,^\.\./bfd/,,' -e 's/^lib//' | sed '$(program_transform_name)'`; \ + ln -sf $$ts $(libdir)/$$tf; \ + elif [ "$$f" = "$(SHLIB)" ]; then \ + $(INSTALL_PROGRAM) $$f $(libdir)/$$tf; \ + else \ + $(INSTALL_DATA) $$f $(libdir)/$$tf; \ + $(RANLIB) $(libdir)/$$tf; \ + chmod a-x $(libdir)/$$tf; \ + fi; \ + done + +Makefile: Makefile.in config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status + +config.status : configure $(srcdir)/../bfd/configure.host $(srcdir)/../bfd/config.bfd + $(SHELL) config.status --recheck + +dep: $(CFILES) + mkdep $(CFLAGS) $? + +stamp-picdir: + if [ -n "$(PICFLAG)" ] && [ ! -d pic ]; then \ + mkdir pic; \ + else true; fi + touch stamp-picdir + +# What appears below is generated by a hacked mkdep using gcc -MM. + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY + diff --git a/contrib/gdb/opcodes/dis-buf.c b/contrib/gdb/opcodes/dis-buf.c new file mode 100644 index 000000000000..47a2e33ef44a --- /dev/null +++ b/contrib/gdb/opcodes/dis-buf.c @@ -0,0 +1,70 @@ +/* Disassemble from a buffer, for GNU. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sysdep.h" +#include "dis-asm.h" +#include + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (status, memaddr, info) + int status; + bfd_vma memaddr; + struct disassemble_info *info; +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%x is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + (*info->fprintf_func) (info->stream, "0x%x", addr); +} diff --git a/contrib/gdb/opcodes/disassemble.c b/contrib/gdb/opcodes/disassemble.c new file mode 100644 index 000000000000..b5d37aed476e --- /dev/null +++ b/contrib/gdb/opcodes/disassemble.c @@ -0,0 +1,166 @@ +/* Select disassembly routine for specified architecture. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "ansidecl.h" +#include "dis-asm.h" + +#ifdef ARCH_all +#define ARCH_a29k +#define ARCH_alpha +#define ARCH_arm +#define ARCH_h8300 +#define ARCH_h8500 +#define ARCH_hppa +#define ARCH_i386 +#define ARCH_i960 +#define ARCH_m68k +#define ARCH_m88k +#define ARCH_mips +#define ARCH_ns32k +#define ARCH_powerpc +#define ARCH_rs6000 +#define ARCH_sh +#define ARCH_sparc +#define ARCH_w65 +#define ARCH_z8k +#endif + +disassembler_ftype +disassembler (abfd) + bfd *abfd; +{ + enum bfd_architecture a = bfd_get_arch (abfd); + disassembler_ftype disassemble; + + switch (a) + { + /* If you add a case to this table, also add it to the + ARCH_all definition right above this function. */ +#ifdef ARCH_a29k + case bfd_arch_a29k: + /* As far as I know we only handle big-endian 29k objects. */ + disassemble = print_insn_big_a29k; + break; +#endif +#ifdef ARCH_alpha + case bfd_arch_alpha: + disassemble = print_insn_alpha; + break; +#endif +#ifdef ARCH_arm + case bfd_arch_arm: + if (bfd_big_endian (abfd)) + disassemble = print_insn_big_arm; + else + disassemble = print_insn_little_arm; + break; +#endif +#ifdef ARCH_h8300 + case bfd_arch_h8300: + if (bfd_get_mach(abfd) == bfd_mach_h8300h) + disassemble = print_insn_h8300h; + else + disassemble = print_insn_h8300; + break; +#endif +#ifdef ARCH_h8500 + case bfd_arch_h8500: + disassemble = print_insn_h8500; + break; +#endif +#ifdef ARCH_hppa + case bfd_arch_hppa: + disassemble = print_insn_hppa; + break; +#endif +#ifdef ARCH_i386 + case bfd_arch_i386: + disassemble = print_insn_i386; + break; +#endif +#ifdef ARCH_i960 + case bfd_arch_i960: + disassemble = print_insn_i960; + break; +#endif +#ifdef ARCH_m68k + case bfd_arch_m68k: + disassemble = print_insn_m68k; + break; +#endif +#ifdef ARCH_m88k + case bfd_arch_m88k: + disassemble = print_insn_m88k; + break; +#endif +#ifdef ARCH_ns32k + case bfd_arch_ns32k: + disassemble = print_insn_ns32k; + break; +#endif +#ifdef ARCH_mips + case bfd_arch_mips: + if (bfd_big_endian (abfd)) + disassemble = print_insn_big_mips; + else + disassemble = print_insn_little_mips; + break; +#endif +#ifdef ARCH_powerpc + case bfd_arch_powerpc: + if (bfd_big_endian (abfd)) + disassemble = print_insn_big_powerpc; + else + disassemble = print_insn_little_powerpc; + break; +#endif +#ifdef ARCH_rs6000 + case bfd_arch_rs6000: + disassemble = print_insn_rs6000; + break; +#endif +#ifdef ARCH_sh + case bfd_arch_sh: + if (bfd_big_endian (abfd)) + disassemble = print_insn_sh; + else + disassemble = print_insn_shl; + break; +#endif +#ifdef ARCH_sparc + case bfd_arch_sparc: + disassemble = print_insn_sparc; + break; +#endif +#ifdef ARCH_w65 + case bfd_arch_w65: + disassemble = print_insn_w65; + break; +#endif +#ifdef ARCH_z8k + case bfd_arch_z8k: + if (bfd_get_mach(abfd) == bfd_mach_z8001) + disassemble = print_insn_z8001; + else + disassemble = print_insn_z8002; + break; +#endif + default: + return 0; + } + return disassemble; +} diff --git a/contrib/gdb/opcodes/i386-dis.c b/contrib/gdb/opcodes/i386-dis.c new file mode 100644 index 000000000000..b781edc32079 --- /dev/null +++ b/contrib/gdb/opcodes/i386-dis.c @@ -0,0 +1,2031 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 89, 91, 93, 94, 95, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include "dis-asm.h" +#include "sysdep.h" + +#define MAXLEN 20 + +#include + +struct dis_private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define ONE OP_ONE, 0 +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG(); +int OP_J(), OP_SEG(); +int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); +int OP_D(), OP_T(), OP_rm(); + +static void dofloat (), putop (), append_prefix (), set_op (); +static int get16 (), get32 (); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 +#define GRP9 NULL, NULL, 16 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + int (*op1)(); + int bytemode1; + int (*op2)(); + int bytemode2; + int (*op3)(); + int bytemode3; +}; + +struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushl", es }, + { "popl", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushl", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushl", ss }, + { "popl", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushl", ds }, + { "popl", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushl", sIb }, /* push of byte really pushes 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cwtl" }, + { "cltd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Yb }, + { "scasS", eAX, Yv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "invd" }, + { "wbinvd" }, + { "(bad)" }, { "ud2a" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev }, + { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev }, + /* 48 */ + { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, + { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 68 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 70 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushl", fs }, + { "popl", fs }, + { "cpuid" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushl", gs }, + { "popl", gs }, + { "rsm" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "cmpxchgb", Eb, Gb }, + { "cmpxchgS", Ev, Gv }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "ud2b" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "xaddb", Eb, Gb }, + { "xaddS", Ev, Gv }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { GRP9 }, + /* c8 */ + { "bswap", eAX }, + { "bswap", eCX }, + { "bswap", eDX }, + { "bswap", eBX }, + { "bswap", eSP }, + { "bswap", eBP }, + { "bswap", eSI }, + { "bswap", eDI }, + /* d0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, +}; + +static const unsigned char onebyte_has_modrm[256] = { + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 +}; + +static const unsigned char twobyte_has_modrm[256] = { + 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend (); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; +static char *index16[] = { + "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx" +}; + +struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "invlpg", Ew }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + }, + /* GRP9 */ + { + { "(bad)" }, + { "cmpxchg8b", Ev }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +static void +ckprefix () +{ + prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static int dflag; +static int aflag; + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + struct dis386 *dp; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + unsigned char need_modrm; + + struct dis_private priv; + bfd_byte *inbuf = priv.the_buffer; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + FETCH_DATA (info, codep + 1); + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + (*info->fprintf_func) (info->stream, "fwait"); + return (1); + } + + /* these would be initialized to 0 if disassembling for 8086 or 286 */ + dflag = 1; + aflag = 1; + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + oappend ("addr16 "); + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + dp = &dis386_twobyte[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + } + codep++; + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) (op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) (op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) (op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return (codep - inbuf); +} + +char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 +int OP_ST(), OP_STi(); + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi }, + { "fcmove", ST, STi }, + { "fcmovbe",ST, STi }, + { "fcmovu", ST, STi }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "fcmovnb",ST, STi }, + { "fcmovne",ST, STi }, + { "fcmovnbe",ST, STi }, + { "fcmovnu",ST, STi }, + { FGRPdb_4 }, + { "fucomi", ST, STi }, + { "fcomi", ST, STi }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "fucomip",ST, STi }, + { "fcomip", ST, STi }, + { "(bad)" }, + }, +}; + + +char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat () +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg]); + obufp = op1out; + OP_E (v_mode); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm]); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf + && FETCH_DATA (the_info, codep + 1) + && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + } +} + +/* ARGSUSED */ +int +OP_ST (ignore) + int ignore; +{ + oappend ("%st"); + return (0); +} + +/* ARGSUSED */ +int +OP_STi (ignore) + int ignore; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); + return (0); +} + + +/* capital letters in template are macros */ +static void +putop (template) + char *template; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +static void +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +int +OP_indirE (bytemode) + int bytemode; +{ + oappend ("*"); + return OP_E (bytemode); +} + +int +OP_E (bytemode) + int bytemode; +{ + int disp; + + /* skip mod/rm byte */ + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend (""); + break; + } + return 0; + } + + disp = 0; + append_prefix (); + + if (aflag) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index; + int scale; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + if (base == 5) + { + havebase = 0; + disp = get32 (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *(char *)codep++; + break; + case 2: + disp = get32 (); + break; + } + + if (mod != 0 || base == 5) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if (rm == 6) + disp = (short) get16 (); + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *(char *)codep++; + break; + case 2: + disp = (short) get16 (); + break; + } + + if (mod != 0 || rm == 6) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (mod != 0 || rm != 6) + { + oappend ("("); + oappend (index16[rm]); + oappend (")"); + } + } + return 0; +} + +int +OP_G (bytemode) + int bytemode; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend (""); + break; + } + return (0); +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +static void +set_op (op) + int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +int +OP_REG (code) + int code; +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = ""; + break; + } + oappend (s); + return (0); +} + +int +OP_I (bytemode) + int bytemode; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +int +OP_sI (bytemode) + int bytemode; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *(char *)codep++; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = (short)get16(); + break; + case w_mode: + op = (short)get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +int +OP_J (bytemode) + int bytemode; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *(char *)codep++; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = (short)get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (""); + return (0); + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_SEG (dummy) + int dummy; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); + return (0); +} + +int +OP_DIR (size) + int size; +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + offset = (short)get16 (); + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend (""); + break; + } + return (0); +} + +/* ARGSUSED */ +int +OP_OFF (bytemode) + int bytemode; +{ + int off; + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_ESDI (dummy) + int dummy; +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +int +OP_DSSI (dummy) + int dummy; +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +int +OP_ONE (dummy) + int dummy; +{ + oappend ("1"); + return (0); +} + +/* ARGSUSED */ +int +OP_C (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_D (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +int +OP_T (dummy) + int dummy; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); + return (0); +} + +int +OP_rm (bytemode) + int bytemode; +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } + return (0); +} diff --git a/contrib/gdb/opcodes/sysdep.h b/contrib/gdb/opcodes/sysdep.h new file mode 100644 index 000000000000..f1556da1f2ea --- /dev/null +++ b/contrib/gdb/opcodes/sysdep.h @@ -0,0 +1,38 @@ +/* Random host-dependent support code. + Copyright (C) 1995 Free Software Foundation, Inc. + Written by Ken Raeburn. + +This file is part of libopcodes, the opcodes 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Do system-dependent stuff, mainly driven by autoconf-detected info. + + Well, some generic common stuff is done here too, like including + ansidecl.h. That's because the .h files in bfd/hosts files I'm + trying to replace often did that. If it can be dropped from this + file (check in a non-ANSI environment!), it should be. */ + +#include "config.h" + +#include + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif diff --git a/contrib/gdb/readline/doc/ChangeLog b/contrib/gdb/readline/doc/ChangeLog new file mode 100644 index 000000000000..2520a8522cd1 --- /dev/null +++ b/contrib/gdb/readline/doc/ChangeLog @@ -0,0 +1,12 @@ +Wed Sep 20 12:57:29 1995 Ian Lance Taylor + + * Makefile.in (maintainer-clean): New synonym for realclean. + +Tue Feb 2 11:40:04 1993 Roland H. Pesch (pesch@fowanton.cygnus.com) + + * Makefile.in: configurable (and useable) Makefile template + * Makefile: removed, replaced with configurable Makefile.in + * texindex.c texinfo.tex: remove, replacing w/refs to tools + elsewhere in distribution tree + * configure.in: pro forma configure stub + * ChangeLog: new file diff --git a/contrib/gdb/readline/doc/Makefile.in b/contrib/gdb/readline/doc/Makefile.in new file mode 100644 index 000000000000..451b9fec336f --- /dev/null +++ b/contrib/gdb/readline/doc/Makefile.in @@ -0,0 +1,94 @@ +## Copyright (C) 1993 Free Software Foundation, Inc. + +# Makefile for Readline documentation. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +srcdir = . + +prefix = /usr/local + +infodir = $(prefix)/info + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_DATA = $(INSTALL) + +# where to find texinfo +TEXIDIR=$(srcdir)/../../texinfo + +# where to find makeinfo, preferably one designed for texinfo-2 +MAKEINFO=makeinfo + +# auxiliary program for sorting Texinfo indices +TEXINDEX=texindex + +# Don Knuth's TeX formatter +TEX=tex + +#### Host, target, and site specific Makefile fragments come in here. +### + +all: info dvi + +install: install-info + +info: history.info readline.info + +dvi: history.dvi readline.dvi + +install-info: info + -parent=`echo $(infodir)|sed -e 's@/[^/]*$$@@'`; \ + if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi + -if [ -d $(infodir) ] ; then true ; else mkdir $(infodir) ; fi + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +history.info: hist.texinfo hsuser.texinfo hstech.texinfo + $(MAKEINFO) -I $(srcdir) -o ./history.info $(srcdir)/hist.texinfo + +history.dvi: hist.texinfo hsuser.texinfo hstech.texinfo $(TEXIDIR)/texinfo.tex + TEXINPUTS=${TEXIDIR}:$(srcdir):$$TEXINPUTS $(TEX) hist.texinfo + $(TEXINDEX) hist.?? + TEXINPUTS=${TEXIDIR}:$(srcdir):$$TEXINPUTS $(TEX) hist.texinfo + +readline.info: rlman.texinfo rluser.texinfo rltech.texinfo + $(MAKEINFO) -I $(srcdir) -o ./readline.info $(srcdir)/rlman.texinfo + +readline.dvi: rlman.texinfo rluser.texinfo rltech.texinfo + TEXINPUTS=${TEXIDIR}:$(srcdir):$$TEXINPUTS $(TEX) rlman.texinfo + $(TEXINDEX) rlman.?? + TEXINPUTS=${TEXIDIR}:$(srcdir):$$TEXINPUTS $(TEX) rlman.texinfo + +distclean: clean + rm -f Makefile config.status + +mostlyclean: clean + +realclean maintainer-clean: distclean + +clean: clean-info clean-dvi + +clean-info: + rm -f history.info* readline.info* + +clean-dvi: + rm -f hist.?? hist.??? + rm -f rlman.?? rlman.??? + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status diff --git a/contrib/gdb/readline/doc/configure.in b/contrib/gdb/readline/doc/configure.in new file mode 100644 index 000000000000..c082c568c65c --- /dev/null +++ b/contrib/gdb/readline/doc/configure.in @@ -0,0 +1,8 @@ +srcname="READLINE doc" +srctrigger=rlman.texinfo +# per-host: + +# per-target: + +files="" +links="" diff --git a/contrib/gdb/readline/doc/hist.texinfo b/contrib/gdb/readline/doc/hist.texinfo new file mode 100644 index 000000000000..629273810445 --- /dev/null +++ b/contrib/gdb/readline/doc/hist.texinfo @@ -0,0 +1,106 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename history.info +@settitle GNU Readline Library +@comment %**end of header (This is for running Texinfo on a region.) +@synindex vr fn +@setchapternewpage odd + +@ifinfo +This document describes the GNU History library, a programming tool that +provides a consistent user interface for recalling lines of previously +typed input. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@titlepage +@sp 10 +@center @titlefont{GNU History Library} +@center Brian Fox +@center Free Software Foundation +@center Version 1.1 +@center April 1991 + +@c Include the Distribution inside the titlepage environment so +@c that headings are turned off. + +@page + +This document describes the GNU History library, a programming tool that +provides a consistent user interface for recalling lines of previously +typed input. + +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +@end titlepage + +@ifinfo +@node Top +@top GNU History Library + +This document describes the GNU History library, a programming tool that +provides a consistent user interface for recalling lines of previously +typed input. + +@menu +* Using History Interactively:: GNU History User's Manual. +* Programming with GNU History:: GNU History Programmer's Manual. +* Concept Index:: Index of concepts described in this manual. +* Function and Variable Index:: Index of externally visible functions + and variables. +@end menu +@end ifinfo + +@include hsuser.texinfo +@include hstech.texinfo + +@node Concept Index +@appendix Concept Index +@printindex cp + +@node Function and Variable Index +@appendix Function and Variable Index +@printindex vr +@contents + +@bye diff --git a/contrib/gdb/readline/doc/hstech.texinfo b/contrib/gdb/readline/doc/hstech.texinfo new file mode 100644 index 000000000000..c3fe3f6a11fc --- /dev/null +++ b/contrib/gdb/readline/doc/hstech.texinfo @@ -0,0 +1,311 @@ +@ignore +This file documents the user interface to the GNU History library. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Authored by Brian Fox. + +Permission is granted to make and distribute verbatim copies of this manual +provided the copyright notice and this permission notice are preserved on +all copies. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ignore + +@node Programming with GNU History +@chapter Programming with GNU History + +This chapter describes how to interface the GNU History Library with +programs that you write. It should be considered a technical guide. +For information on the interactive use of GNU History, @pxref{Using +History Interactively}. + +@menu +* Introduction to History:: What is the GNU History library for? +* History Storage:: How information is stored. +* History Functions:: Functions that you can use. +* History Variables:: Variables that control behaviour. +* History Programming Example:: Example of using the GNU History Library. +@end menu + +@node Introduction to History +@section Introduction to History + +Many programs read input from the user a line at a time. The GNU history +library is able to keep track of those lines, associate arbitrary data with +each line, and utilize information from previous lines in making up new +ones. + +The programmer using the History library has available to him functions +for remembering lines on a history stack, associating arbitrary data +with a line, removing lines from the stack, searching through the stack +for a line containing an arbitrary text string, and referencing any line +on the stack directly. In addition, a history @dfn{expansion} function +is available which provides for a consistent user interface across many +different programs. + +The end-user using programs written with the History library has the +benifit of a consistent user interface, with a set of well-known +commands for manipulating the text of previous lines and using that text +in new commands. The basic history manipulation commands are similar to +the history substitution used by @code{Csh}. + +If the programmer desires, he can use the Readline library, which +includes some history manipulation by default, and has the added +advantage of Emacs style command line editing. + +@node History Storage +@section History Storage + +@example +typedef struct _hist_entry @{ + char *line; + char *data; +@} HIST_ENTRY; +@end example + +@node History Functions +@section History Functions + +This section describes the calling sequence for the various functions +present in GNU History. + +@defun {void using_history} () +Begin a session in which the history functions might be used. This +just initializes the interactive variables. +@end defun + +@defun {void add_history} (char *string) +Place @var{string} at the end of the history list. The associated data +field (if any) is set to @code{NULL}. +@end defun + +@defun {int where_history} () +Returns the number which says what history element we are now looking +at. +@end defun + +@defun {int history_set_pos} (int pos) +Set the position in the history list to @var{pos}. +@end defun + +@defun {int history_search_pos} (char *string, int direction, int pos) +Search for @var{string} in the history list, starting at @var{pos}, an +absolute index into the list. @var{direction}, if negative, says to search +backwards from @var{pos}, else forwards. Returns the absolute index of +the history element where @var{string} was found, or -1 otherwise. +@end defun + +@defun {HIST_ENTRY *remove_history} (); +Remove history element @var{which} from the history. The removed +element is returned to you so you can free the line, data, +and containing structure. +@end defun + +@defun {void stifle_history} (int max) +Stifle the history list, remembering only @var{max} number of entries. +@end defun + +@defun {int unstifle_history} (); +Stop stifling the history. This returns the previous amount the +history was stifled by. The value is positive if the history was +stifled, negative if it wasn't. +@end defun + +@defun {int read_history} (char *filename) +Add the contents of @var{filename} to the history list, a line at a +time. If @var{filename} is @code{NULL}, then read from +@file{~/.history}. Returns 0 if successful, or errno if not. +@end defun + +@defun {int read_history_range} (char *filename, int from, int to) +Read a range of lines from @var{filename}, adding them to the history list. +Start reading at the @var{from}'th line and end at the @var{to}'th. If +@var{from} is zero, start at the beginning. If @var{to} is less than +@var{from}, then read until the end of the file. If @var{filename} is +@code{NULL}, then read from @file{~/.history}. Returns 0 if successful, +or @code{errno} if not. +@end defun + +@defun {int write_history} (char *filename) +Append the current history to @var{filename}. If @var{filename} is +@code{NULL}, then append the history list to @file{~/.history}. Values +returned are as in @code{read_history ()}. +@end defun + +@defun {int append_history} (int nelements, char *filename) +Append @var{nelement} entries to @var{filename}. The entries appended +are from the end of the list minus @var{nelements} up to the end of the +list. +@end defun + +@defun {HIST_ENTRY *replace_history_entry} () +Make the history entry at @var{which} have @var{line} and @var{data}. +This returns the old entry so you can dispose of the data. In the case +of an invalid @var{which}, a @code{NULL} pointer is returned. +@end defun + +@defun {HIST_ENTRY *current_history} () +Return the history entry at the current position, as determined by +@code{history_offset}. If there is no entry there, return a @code{NULL} +pointer. +@end defun + +@defun {HIST_ENTRY *previous_history} () +Back up @var{history_offset} to the previous history entry, and return a +pointer to that entry. If there is no previous entry, return a +@code{NULL} pointer. +@end defun + +@defun {HIST_ENTRY *next_history} () +Move @code{history_offset} forward to the next history entry, and return +the a pointer to that entry. If there is no next entry, return a +@code{NULL} pointer. +@end defun + +@defun {HIST_ENTRY **history_list} () +Return a @code{NULL} terminated array of @code{HIST_ENTRY} which is the +current input history. Element 0 of this list is the beginning of time. +If there is no history, return @code{NULL}. +@end defun + +@defun {int history_search} (char *string, int direction) +Search the history for @var{string}, starting at @code{history_offset}. +If @var{direction} < 0, then the search is through previous entries, +else through subsequent. If @var{string} is found, then +@code{current_history ()} is the history entry, and the value of this +function is the offset in the line of that history entry that the +@var{string} was found in. Otherwise, nothing is changed, and a -1 is +returned. +@end defun + +@defun {int history_expand} (char *string, char **output) +Expand @var{string}, placing the result into @var{output}, a pointer +to a string. Returns: +@table @code +@item 0 +If no expansions took place (or, if the only change in +the text was the de-slashifying of the history expansion +character), +@item 1 +if expansions did take place, or +@item -1 +if there was an error in expansion. +@end table + +If an error ocurred in expansion, then @var{output} contains a descriptive +error message. +@end defun + +@defun {char *history_arg_extract} (int first, int last, char *string) +Extract a string segment consisting of the @var{first} through @var{last} +arguments present in @var{string}. Arguments are broken up as in +the GNU Bash shell. +@end defun + +@defun {int history_total_bytes} (); +Return the number of bytes that the primary history entries are using. +This just adds up the lengths of @code{the_history->lines}. +@end defun + +@node History Variables +@section History Variables + +This section describes the variables in GNU History that are externally +visible. + +@defvar {int history_base} +For convenience only. You set this when interpreting history commands. +It is the logical offset of the first history element. +@end defvar + +@node History Programming Example +@section History Programming Example + +The following snippet of code demonstrates simple use of the GNU History +Library. + +@smallexample +main () +@{ + char line[1024], *t; + int done = 0; + + line[0] = 0; + + while (!done) + @{ + fprintf (stdout, "history%% "); + t = gets (line); + + if (!t) + strcpy (line, "quit"); + + if (line[0]) + @{ + char *expansion; + int result; + + using_history (); + + result = history_expand (line, &expansion); + strcpy (line, expansion); + free (expansion); + if (result) + fprintf (stderr, "%s\n", line); + + if (result < 0) + continue; + + add_history (line); + @} + + if (strcmp (line, "quit") == 0) done = 1; + if (strcmp (line, "save") == 0) write_history (0); + if (strcmp (line, "read") == 0) read_history (0); + if (strcmp (line, "list") == 0) + @{ + register HIST_ENTRY **the_list = history_list (); + register int i; + + if (the_list) + for (i = 0; the_list[i]; i++) + fprintf (stdout, "%d: %s\n", + i + history_base, the_list[i]->line); + @} + if (strncmp (line, "delete", strlen ("delete")) == 0) + @{ + int which; + if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1) + @{ + HIST_ENTRY *entry = remove_history (which); + if (!entry) + fprintf (stderr, "No such entry %d\n", which); + else + @{ + free (entry->line); + free (entry); + @} + @} + else + @{ + fprintf (stderr, "non-numeric arg given to `delete'\n"); + @} + @} + @} +@} +@end smallexample + + + diff --git a/contrib/gdb/readline/doc/hsuser.texinfo b/contrib/gdb/readline/doc/hsuser.texinfo new file mode 100644 index 000000000000..cda0a688c74a --- /dev/null +++ b/contrib/gdb/readline/doc/hsuser.texinfo @@ -0,0 +1,153 @@ +@ignore +This file documents the user interface to the GNU History library. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Authored by Brian Fox. + +Permission is granted to make and distribute verbatim copies of this manual +provided the copyright notice and this permission notice are preserved on +all copies. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ignore + +@node Using History Interactively +@chapter Using History Interactively + +This chapter describes how to use the GNU History Library interactively, +from a user's standpoint. It should be considered a user's guide. For +information on using the GNU History Library in your own programs, +@pxref{Programming with GNU History}. + +@menu +* History Interaction:: What it feels like using History as a user. +@end menu + +@node History Interaction +@section History Interaction +@cindex expansion + +The History library provides a history expansion feature that is similar +to the history expansion in Csh. The following text describes the sytax +that you use to manipulate the history information. + +History expansion takes place in two parts. The first is to determine +which line from the previous history should be used during substitution. +The second is to select portions of that line for inclusion into the +current one. The line selected from the previous history is called the +@dfn{event}, and the portions of that line that are acted upon are +called @dfn{words}. The line is broken into words in the same fashion +that the Bash shell does, so that several English (or Unix) words +surrounded by quotes are considered as one word. + +@menu +* Event Designators:: How to specify which history line to use. +* Word Designators:: Specifying which words are of interest. +* Modifiers:: Modifying the results of susbstitution. +@end menu + +@node Event Designators +@subsection Event Designators +@cindex event designators + +An event designator is a reference to a command line entry in the +history list. + +@table @asis + +@item @code{!} +Start a history subsititution, except when followed by a space, tab, or +the end of the line... @key{=} or @key{(}. + +@item @code{!!} +Refer to the previous command. This is a synonym for @code{!-1}. + +@item @code{!n} +Refer to command line @var{n}. + +@item @code{!-n} +Refer to the command line @var{n} lines back. + +@item @code{!string} +Refer to the most recent command starting with @var{string}. + +@item @code{!?string}[@code{?}] +Refer to the most recent command containing @var{string}. + +@end table + +@node Word Designators +@subsection Word Designators + +A @key{:} separates the event specification from the word designator. It +can be omitted if the word designator begins with a @key{^}, @key{$}, +@key{*} or @key{%}. Words are numbered from the beginning of the line, +with the first word being denoted by a 0 (zero). + +@table @code + +@item 0 (zero) +The zero'th word. For many applications, this is the command word. + +@item n +The @var{n}'th word. + +@item ^ +The first argument. that is, word 1. + +@item $ +The last argument. + +@item % +The word matched by the most recent @code{?string?} search. + +@item x-y +A range of words; @code{-@var{y}} Abbreviates @code{0-@var{y}}. + +@item * +All of the words, excepting the zero'th. This is a synonym for @code{1-$}. +It is not an error to use @key{*} if there is just one word in the event. +The empty string is returned in that case. + +@end table + +@node Modifiers +@subsection Modifiers + +After the optional word designator, you can add a sequence of one or more +of the following modifiers, each preceded by a @key{:}. + +@table @code + +@item # +The entire command line typed so far. This means the current command, +not the previous command, so it really isn't a word designator, and doesn't +belong in this section. + +@item h +Remove a trailing pathname component, leaving only the head. + +@item r +Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename. + +@item e +Remove all but the suffix. + +@item t +Remove all leading pathname components, leaving the tail. + +@item p +Print the new command but do not execute it. +@end table diff --git a/contrib/gdb/readline/doc/inc-hist.texi b/contrib/gdb/readline/doc/inc-hist.texi new file mode 100644 index 000000000000..9cdde401cd2b --- /dev/null +++ b/contrib/gdb/readline/doc/inc-hist.texi @@ -0,0 +1,159 @@ +@ignore +This file is completely identical to hsuser.texinfo, except that it has the +reference to the programming manual removed. There are definately better ways +to do this! + +This file documents the user interface to the GNU History library. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. +Authored by Brian Fox. + +Permission is granted to make and distribute verbatim copies of this manual +provided the copyright notice and this permission notice are preserved on +all copies. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ignore + +@node Using History Interactively +@appendix Using History Interactively + +This chapter describes how to use the GNU History Library interactively, +from a user's standpoint. + +@menu +* History Interaction:: What it feels like using History as a user. +@end menu + +@node History Interaction +@section History Interaction +@cindex expansion + +The History library provides a history expansion feature similar +to the history expansion in @code{csh}. The following text describes the +syntax you use to manipulate history information. + +History expansion takes two parts. In the first part, determine +which line from the previous history will be used for substitution. +This line is called the @dfn{event}. +In the second part, select portions of that line for inclusion into the +current line. These portions are called @dfn{words}. +@value{GDBN} breaks the line into words in the same +way that the Bash shell does, so that several English (or Unix) words +surrounded by quotes are considered one word. + +@menu +* Event Designators:: How to specify which history line to use. +* Word Designators:: Specifying which words are of interest. +* Modifiers:: Modifying the results of susbstitution. +@end menu + +@node Event Designators +@subsection Event Designators +@cindex event designators + +An @dfn{event designator} is a reference to a command line entry in the +history list. + +@table @asis + +@item @code{!} +Start a history subsititution, except when followed by a space, tab, or +the end of the line... @key{=} or @key{(}. + +@item @code{!!} +Refer to the previous command. This is a synonym for @code{!-1}. + +@item @code{!n} +Refer to command line @var{n}. + +@item @code{!-n} +Refer to the command line @var{n} lines back. + +@item @code{!string} +Refer to the most recent command starting with @var{string}. + +@item @code{!?string}[@code{?}] +Refer to the most recent command containing @var{string}. + +@end table + +@node Word Designators +@subsection Word Designators + +A @key{:} separates the event designator from the @dfn{word designator}. +It can be omitted if the word designator begins with a @key{^}, @key{$}, +@key{*} or @key{%}. Words are numbered from the beginning of the line, +with the first word being denoted by a 0 (zero). + +@table @code + +@item 0 (zero) +The zero'th word. For many applications, this is the command word. + +@item n +The @var{n}'th word. + +@item ^ +The first argument. that is, word 1. + +@item $ +The last argument. + +@item % +The word matched by the most recent @code{?string?} search. + +@item x-y +A range of words; @code{-@var{y}} Abbreviates @code{0-@var{y}}. + +@item * +All of the words, excepting the zero'th. This is a synonym for @code{1-$}. +It is not an error to use @key{*} if there is just one word in the event. +The empty string is returned in that case. + +@end table + +@node Modifiers +@subsection Modifiers + +After the optional word designator, you can add a sequence of one or more +of the following @dfn{modifiers}, each preceded by a @key{:}. + +@table @code + +@item # +The entire command line typed so far. This means the current command, +not the previous command. +@c +@c FIXME: If it doesn't belong here, let's put it where it does. +@c +@c so it technically isn't a word designator and doesn't belong in +@c this section. + +@item h +Remove a trailing pathname component, leaving only the head. + +@item r +Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename. + +@item e +Remove all but the suffix. + +@item t +Remove all leading pathname components, leaving the tail. + +@item p +Print the new command but do not execute it. +@end table diff --git a/contrib/gdb/readline/doc/rlman.texinfo b/contrib/gdb/readline/doc/rlman.texinfo new file mode 100644 index 000000000000..f2e7fb6db919 --- /dev/null +++ b/contrib/gdb/readline/doc/rlman.texinfo @@ -0,0 +1,103 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename readline.info +@settitle GNU Readline Library +@comment %**end of header (This is for running Texinfo on a region.) +@synindex vr fn +@setchapternewpage odd + +@ifinfo +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +Copyright (C) 1988, 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@titlepage +@sp 10 +@center @titlefont{GNU Readline Library} +@center Brian Fox +@center Free Software Foundation +@center Version 1.1 +@center April 1991 + +@page +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +Published by the Free Software Foundation @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +@end titlepage + +@ifinfo +@node Top +@top GNU Readline Library + +This document describes the GNU Readline Library, a utility which aids +in the consistency of user interface across discrete programs that need +to provide a command line interface. + +@menu +* Command Line Editing:: GNU Readline User's Manual. +* Programming with GNU Readline:: GNU Readline Programmer's Manual. +* Concept Index:: Index of concepts described in this manual. +* Function and Variable Index:: Index of externally visible functions + and variables. +@end menu +@end ifinfo + +@include rluser.texinfo +@include rltech.texinfo + +@node Concept Index +@unnumbered Concept Index +@printindex cp + +@node Function and Variable Index +@unnumbered Function and Variable Index +@printindex fn + +@contents +@bye + diff --git a/contrib/gdb/readline/doc/rltech.texinfo b/contrib/gdb/readline/doc/rltech.texinfo new file mode 100644 index 000000000000..2048b7c29dfb --- /dev/null +++ b/contrib/gdb/readline/doc/rltech.texinfo @@ -0,0 +1,1012 @@ +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rltech.info +@comment %**end of header (This is for running Texinfo on a region.) +@setchapternewpage odd + +@ifinfo +This document describes the GNU Readline Library, a utility for aiding +in the consitency of user interface across discrete programs that need +to provide a command line interface. + +Copyright (C) 1988 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@node Programming with GNU Readline +@chapter Programming with GNU Readline + +This manual describes the interface between the GNU Readline Library and +user programs. If you are a programmer, and you wish to include the +features found in GNU Readline in your own programs, such as completion, +line editing, and interactive history manipulation, this documentation +is for you. + +@menu +* Default Behaviour:: Using the default behaviour of Readline. +* Custom Functions:: Adding your own functions to Readline. +* Custom Completers:: Supplanting or supplementing Readline's + completion functions. +@end menu + +@node Default Behaviour +@section Default Behaviour + +Many programs provide a command line interface, such as @code{mail}, +@code{ftp}, and @code{sh}. For such programs, the default behaviour of +Readline is sufficient. This section describes how to use Readline in +the simplest way possible, perhaps to replace calls in your code to +@code{gets ()}. + +@findex readline () +@cindex readline, function +The function @code{readline} prints a prompt and then reads and returns +a single line of text from the user. The line which @code{readline ()} +returns is allocated with @code{malloc ()}; you should @code{free ()} +the line when you are done with it. The declaration for @code{readline} +in ANSI C is + +@example +@code{char *readline (char *@var{prompt});} +@end example + +So, one might say +@example +@code{char *line = readline ("Enter a line: ");} +@end example +in order to read a line of text from the user. + +The line which is returned has the final newline removed, so only the +text of the line remains. + +If readline encounters an @code{EOF} while reading the line, and the +line is empty at that point, then @code{(char *)NULL} is returned. +Otherwise, the line is ended just as if a newline was typed. + +If you want the user to be able to get at the line later, (with +@key{C-p} for example), you must call @code{add_history ()} to save the +line away in a @dfn{history} list of such lines. + +@example +@code{add_history (line)}; +@end example + +For full details on the GNU History Library, see the associated manual. + +It is polite to avoid saving empty lines on the history list, since it +is rare than someone has a burning need to reuse a blank line. Here is +a function which usefully replaces the standard @code{gets ()} library +function: + +@example +/* A static variable for holding the line. */ +static char *line_read = (char *)NULL; + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +char * +do_gets () +@{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read != (char *)NULL) + @{ + free (line_read); + line_read = (char *)NULL; + @} + + /* Get a line from the user. */ + line_read = readline (""); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +@} +@end example + +The above code gives the user the default behaviour of @key{TAB} +completion: completion on file names. If you do not want readline to +complete on filenames, you can change the binding of the @key{TAB} key +with @code{rl_bind_key ()}. + +@findex rl_bind_key () +@example +@code{int rl_bind_key (int @var{key}, int (*@var{function})());} +@end example + +@code{rl_bind_key ()} takes 2 arguments; @var{key} is the character that +you want to bind, and @var{function} is the address of the function to +run when @var{key} is pressed. Binding @key{TAB} to @code{rl_insert ()} +makes @key{TAB} just insert itself. + +@code{rl_bind_key ()} returns non-zero if @var{key} is not a valid +ASCII character code (between 0 and 255). + +@example +@code{rl_bind_key ('\t', rl_insert);} +@end example + +This code should be executed once at the start of your program; you +might write a function called @code{initialize_readline ()} which +performs this and other desired initializations, such as installing +custom completers, etc. + +@node Custom Functions +@section Custom Functions + +Readline provides a great many functions for manipulating the text of +the line. But it isn't possible to anticipate the needs of all +programs. This section describes the various functions and variables +defined in within the Readline library which allow a user program to add +customized functionality to Readline. + +@menu +* The Function Type:: C declarations to make code readable. +* Function Naming:: How to give a function you write a name. +* Keymaps:: Making keymaps. +* Binding Keys:: Changing Keymaps. +* Function Writing:: Variables and calling conventions. +* Allowing Undoing:: How to make your functions undoable. +@end menu + +@node The Function Type +@subsection The Function Type + +For the sake of readabilty, we declare a new type of object, called +@dfn{Function}. A @code{Function} is a C language function which +returns an @code{int}. The type declaration for @code{Function} is: + +@noindent +@code{typedef int Function ();} + +The reason for declaring this new type is to make it easier to write +code describing pointers to C functions. Let us say we had a variable +called @var{func} which was a pointer to a function. Instead of the +classic C declaration + +@code{int (*)()func;} + +we have + +@code{Function *func;} + +@node Function Naming +@subsection Naming a Function + +The user can dynamically change the bindings of keys while using +Readline. This is done by representing the function with a descriptive +name. The user is able to type the descriptive name when referring to +the function. Thus, in an init file, one might find + +@example +Meta-Rubout: backward-kill-word +@end example + +This binds the keystroke @key{Meta-Rubout} to the function +@emph{descriptively} named @code{backward-kill-word}. You, as the +programmer, should bind the functions you write to descriptive names as +well. Readline provides a function for doing that: + +@defun rl_add_defun (char *name, Function *function, int key) +Add @var{name} to the list of named functions. Make @var{function} be +the function that gets called. If @var{key} is not -1, then bind it to +@var{function} using @code{rl_bind_key ()}. +@end defun + +Using this function alone is sufficient for most applications. It is +the recommended way to add a few functions to the default functions that +Readline has built in already. If you need to do more or different +things than adding a function to Readline, you may need to use the +underlying functions described below. + +@node Keymaps +@subsection Selecting a Keymap + +Key bindings take place on a @dfn{keymap}. The keymap is the +association between the keys that the user types and the functions that +get run. You can make your own keymaps, copy existing keymaps, and tell +Readline which keymap to use. + +@defun {Keymap rl_make_bare_keymap} () +Returns a new, empty keymap. The space for the keymap is allocated with +@code{malloc ()}; you should @code{free ()} it when you are done. +@end defun + +@defun {Keymap rl_copy_keymap} (Keymap map) +Return a new keymap which is a copy of @var{map}. +@end defun + +@defun {Keymap rl_make_keymap} () +Return a new keymap with the printing characters bound to rl_insert, +the lowercase Meta characters bound to run their equivalents, and +the Meta digits bound to produce numeric arguments. +@end defun + +@node Binding Keys +@subsection Binding Keys + +You associate keys with functions through the keymap. Here are +functions for doing that. + +@defun {int rl_bind_key} (int key, Function *function) +Binds @var{key} to @var{function} in the currently selected keymap. +Returns non-zero in the case of an invalid @var{key}. +@end defun + +@defun {int rl_bind_key_in_map} (int key, Function *function, Keymap map) +Bind @var{key} to @var{function} in @var{map}. Returns non-zero in the case +of an invalid @var{key}. +@end defun + +@defun {int rl_unbind_key} (int key) +Make @var{key} do nothing in the currently selected keymap. +Returns non-zero in case of error. +@end defun + +@defun {int rl_unbind_key_in_map} (int key, Keymap map) +Make @var{key} be bound to the null function in @var{map}. +Returns non-zero in case of error. +@end defun + +@defun rl_generic_bind (int type, char *keyseq, char *data, Keymap map) +Bind the key sequence represented by the string @var{keyseq} to the arbitrary +pointer @var{data}. @var{type} says what kind of data is pointed to by +@var{data}; right now this can be a function (@code{ISFUNC}), a macro +(@code{ISMACR}), or a keymap (@code{ISKMAP}). This makes new keymaps as +necessary. The initial place to do bindings is in @var{map}. +@end defun + +@node Function Writing +@subsection Writing a New Function + +In order to write new functions for Readline, you need to know the +calling conventions for keyboard invoked functions, and the names of the +variables that describe the current state of the line gathered so far. + +@defvar {char *rl_line_buffer} +This is the line gathered so far. You are welcome to modify the +contents of this, but see Undoing, below. +@end defvar + +@defvar {int rl_point} +The offset of the current cursor position in @var{rl_line_buffer}. +@end defvar + +@defvar {int rl_end} +The number of characters present in @code{rl_line_buffer}. When +@code{rl_point} is at the end of the line, then @code{rl_point} and +@code{rl_end} are equal. +@end defvar + +The calling sequence for a command @code{foo} looks like + +@example +@code{foo (int count, int key)} +@end example + +where @var{count} is the numeric argument (or 1 if defaulted) and +@var{key} is the key that invoked this function. + +It is completely up to the function as to what should be done with the +numeric argument; some functions use it as a repeat count, other +functions as a flag, and some choose to ignore it. In general, if a +function uses the numeric argument as a repeat count, it should be able +to do something useful with a negative argument as well as a positive +argument. At the very least, it should be aware that it can be passed a +negative argument. + +@node Allowing Undoing +@subsection Allowing Undoing + +Supporting the undo command is a painless thing to do, and makes your +functions much more useful to the end user. It is certainly easy to try +something if you know you can undo it. I could use an undo function for +the stock market. + +If your function simply inserts text once, or deletes text once, and it +calls @code{rl_insert_text ()} or @code{rl_delete_text ()} to do it, then +undoing is already done for you automatically, and you can safely skip +this section. + +If you do multiple insertions or multiple deletions, or any combination +of these operations, you should group them together into one operation. +This can be done with @code{rl_begin_undo_group ()} and +@code{rl_end_undo_group ()}. + +@defun rl_begin_undo_group () +Begins saving undo information in a group construct. The undo +information usually comes from calls to @code{rl_insert_text ()} and +@code{rl_delete_text ()}, but they could be direct calls to +@code{rl_add_undo ()}. +@end defun + +@defun rl_end_undo_group () +Closes the current undo group started with @code{rl_begin_undo_group +()}. There should be exactly one call to @code{rl_end_undo_group ()} +for every call to @code{rl_begin_undo_group ()}. +@end defun + +Finally, if you neither insert nor delete text, but directly modify the +existing text (e.g. change its case), you call @code{rl_modifying ()} +once, just before you modify the text. You must supply the indices of +the text range that you are going to modify. + +@defun rl_modifying (int start, int end) +Tell Readline to save the text between @var{start} and @var{end} as a +single undo unit. It is assumed that subsequent to this call you will +modify that range of text in some way. +@end defun + +@subsection An Example + +Here is a function which changes lowercase characters to the uppercase +equivalents, and uppercase characters to the lowercase equivalents. If +this function was bound to @samp{M-c}, then typing @samp{M-c} would +change the case of the character under point. Typing @samp{10 M-c} +would change the case of the following 10 characters, leaving the cursor on +the last character changed. + +@example +/* Invert the case of the COUNT following characters. */ +invert_case_line (count, key) + int count, key; +@{ + register int start, end; + + start = rl_point; + + if (count < 0) + @{ + direction = -1; + count = -count; + @} + else + direction = 1; + + /* Find the end of the range to modify. */ + end = start + (count * direction); + + /* Force it to be within range. */ + if (end > rl_end) + end = rl_end; + else if (end < 0) + end = -1; + + if (start > end) + @{ + int temp = start; + start = end; + end = temp; + @} + + if (start == end) + return; + + /* Tell readline that we are modifying the line, so save the undo + information. */ + rl_modifying (start, end); + + for (; start != end; start += direction) + @{ + if (uppercase_p (rl_line_buffer[start])) + rl_line_buffer[start] = to_lower (rl_line_buffer[start]); + else if (lowercase_p (rl_line_buffer[start])) + rl_line_buffer[start] = to_upper (rl_line_buffer[start]); + @} + /* Move point to on top of the last character changed. */ + rl_point = end - direction; +@} +@end example + +@node Custom Completers +@section Custom Completers + +Typically, a program that reads commands from the user has a way of +disambiguating commands and data. If your program is one of these, then +it can provide completion for either commands, or data, or both commands +and data. The following sections describe how your program and Readline +cooperate to provide this service to end users. + +@menu +* How Completing Works:: The logic used to do completion. +* Completion Functions:: Functions provided by Readline. +* Completion Variables:: Variables which control completion. +* A Short Completion Example:: An example of writing completer subroutines. +@end menu + +@node How Completing Works +@subsection How Completing Works + +In order to complete some text, the full list of possible completions +must be available. That is to say, it is not possible to accurately +expand a partial word without knowing what all of the possible words +that make sense in that context are. The GNU Readline library provides +the user interface to completion, and additionally, two of the most common +completion functions; filename and username. For completing other types +of text, you must write your own completion function. This section +describes exactly what those functions must do, and provides an example +function. + +There are three major functions used to perform completion: + +@enumerate +@item +The user-interface function @code{rl_complete ()}. This function is +called interactively with the same calling conventions as other +functions in readline intended for interactive use; i.e. @var{count}, +and @var{invoking-key}. It isolates the word to be completed and calls +@code{completion_matches ()} to generate a list of possible completions. +It then either lists the possible completions or actually performs the +completion, depending on which behaviour is desired. + +@item +The internal function @code{completion_matches ()} uses your +@dfn{generator} function to generate the list of possible matches, and +then returns the array of these matches. You should place the address +of your generator function in @code{rl_completion_entry_function}. + +@item +The generator function is called repeatedly from +@code{completion_matches ()}, returning a string each time. The +arguments to the generator function are @var{text} and @var{state}. +@var{text} is the partial word to be completed. @var{state} is zero the +first time the function is called, and a positive non-zero integer for +each subsequent call. When the generator function returns @code{(char +*)NULL} this signals @code{completion_matches ()} that there are no more +possibilities left. + +@end enumerate + +@defun rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{completion_matches ()}). The default is to do filename completion. +@end defun + +Note that @code{rl_complete ()} has the identical calling conventions as +any other key-invokable function; this is because by default it is bound +to the @samp{TAB} key. + +@defvar {Function *rl_completion_entry_function} +This is a pointer to the generator function for @code{completion_matches +()}. If the value of @code{rl_completion_entry_function} is +@code{(Function *)NULL} then the default filename generator function is +used, namely @code{filename_entry_function ()}. +@end defvar + +@node Completion Functions +@subsection Completion Functions + +Here is the complete list of callable completion functions present in +Readline. + +@defun rl_complete_internal (int what_to_do) +Complete the word at or before point. @var{what_to_do} says what to do +with the completion. A value of @samp{?} means list the possible +completions. @samp{TAB} means do standard completion. @samp{*} means +insert all of the possible completions. +@end defun + +@defun rl_complete (int ignore, int invoking_key) +Complete the word at or before point. You have supplied the function +that does the initial simple matching selection algorithm (see +@code{completion_matches ()}). The default is to do filename +completion. This just calls @code{rl_complete_internal ()} with an +argument of @samp{TAB}. +@end defun + +@defun rl_possible_completions () +List the possible completions. See description of @code{rl_complete +()}. This just calls @code{rl_complete_internal ()} with an argument of +@samp{?}. +@end defun + +@defun {char **completion_matches} (char *text, char *(*entry_function) ()) +Returns an array of @code{(char *)} which is a list of completions for +@var{text}. If there are no completions, returns @code{(char **)NULL}. +The first entry in the returned array is the substitution for @var{text}. +The remaining entries are the possible completions. The array is +terminated with a @code{NULL} pointer. + +@var{entry_function} is a function of two args, and returns a +@code{(char *)}. The first argument is @var{text}. The second is a +state argument; it is zero on the first call, and non-zero on subsequent +calls. It returns a @code{NULL} pointer to the caller when there are +no more matches. +@end defun + +@defun {char *filename_completion_function} (char *text, int state) +A generator function for filename completion in the general case. Note +that completion in the Bash shell is a little different because of all +the pathnames that must be followed when looking up the completion for a +command. +@end defun + +@defun {char *username_completion_function} (char *text, int state) +A completion generator for usernames. @var{text} contains a partial +username preceded by a random character (usually @samp{~}). +@end defun + +@node Completion Variables +@subsection Completion Variables + +@defvar {Function *rl_completion_entry_function} +A pointer to the generator function for @code{completion_matches ()}. +@code{NULL} means to use @code{filename_entry_function ()}, the default +filename completer. +@end defvar + +@defvar {Function *rl_attempted_completion_function} +A pointer to an alternative function to create matches. +The function is called with @var{text}, @var{start}, and @var{end}. +@var{start} and @var{end} are indices in @code{rl_line_buffer} saying +what the boundaries of @var{text} are. If this function exists and +returns @code{NULL} then @code{rl_complete ()} will call the value of +@code{rl_completion_entry_function} to generate matches, otherwise the +array of strings returned will be used. +@end defvar + +@defvar {int rl_completion_query_items} +Up to this many items will be displayed in response to a +possible-completions call. After that, we ask the user if she is sure +she wants to see them all. The default value is 100. +@end defvar + +@defvar {char *rl_basic_word_break_characters} +The basic list of characters that signal a break between words for the +completer routine. The contents of this variable is what breaks words +in the Bash shell, i.e. " \t\n\"\\'`@@$><=;|&@{(". +@end defvar + +@defvar {char *rl_completer_word_break_characters} +The list of characters that signal a break between words for +@code{rl_complete_internal ()}. The default list is the contents of +@code{rl_basic_word_break_characters}. +@end defvar + +@defvar {char *rl_special_prefixes} +The list of characters that are word break characters, but should be +left in @var{text} when it is passed to the completion function. +Programs can use this to help determine what kind of completing to do. +@end defvar + +@defvar {int rl_ignore_completion_duplicates} +If non-zero, then disallow duplicates in the matches. Default is 1. +@end defvar + +@defvar {int rl_filename_completion_desired} +Non-zero means that the results of the matches are to be treated as +filenames. This is @emph{always} zero on entry, and can only be changed +within a completion entry generator function. +@end defvar + +@defvar {Function *rl_ignore_some_completions_function} +This function, if defined, is called by the completer when real filename +completion is done, after all the matching names have been generated. +It is passed a @code{NULL} terminated array of @code{(char *)} known as +@var{matches} in the code. The 1st element (@code{matches[0]}) is the +maximal substring that is common to all matches. This function can +re-arrange the list of matches as required, but each deleted element of +the array must be @code{free()}'d. +@end defvar + +@node A Short Completion Example +@subsection A Short Completion Example + +Here is a small application demonstrating the use of the GNU Readline +library. It is called @code{fileman}, and the source code resides in +@file{readline/examples/fileman.c}. This sample application provides +completion of command names, line editing features, and access to the +history list. + +@page +@smallexample +/* fileman.c -- A tiny application which demonstrates how to use the + GNU Readline library. This application interactively allows users + to manipulate files and their modes. */ + +#include +#include +#include +#include +#include +#include +#include + +/* The names of functions that actually do the manipulation. */ +int com_list (), com_view (), com_rename (), com_stat (), com_pwd (); +int com_delete (), com_help (), com_cd (), com_quit (); + +/* A structure which contains information on the commands this program + can understand. */ + +typedef struct @{ + char *name; /* User printable name of the function. */ + Function *func; /* Function to call to do the job. */ + char *doc; /* Documentation for this function. */ +@} COMMAND; + +COMMAND commands[] = @{ + @{ "cd", com_cd, "Change to directory DIR" @}, + @{ "delete", com_delete, "Delete FILE" @}, + @{ "help", com_help, "Display this text" @}, + @{ "?", com_help, "Synonym for `help'" @}, + @{ "list", com_list, "List files in DIR" @}, + @{ "ls", com_list, "Synonym for `list'" @}, + @{ "pwd", com_pwd, "Print the current working directory" @}, + @{ "quit", com_quit, "Quit using Fileman" @}, + @{ "rename", com_rename, "Rename FILE to NEWNAME" @}, + @{ "stat", com_stat, "Print out statistics on FILE" @}, + @{ "view", com_view, "View the contents of FILE" @}, + @{ (char *)NULL, (Function *)NULL, (char *)NULL @} +@}; + +/* The name of this program, as taken from argv[0]. */ +char *progname; + +/* When non-zero, this global means the user is done using this program. */ +int done = 0; +@page +main (argc, argv) + int argc; + char **argv; +@{ + progname = argv[0]; + + initialize_readline (); /* Bind our completer. */ + + /* Loop reading and executing lines until the user quits. */ + while (!done) + @{ + char *line; + + line = readline ("FileMan: "); + + if (!line) + @{ + done = 1; /* Encountered EOF at top level. */ + @} + else + @{ + /* Remove leading and trailing whitespace from the line. + Then, if there is anything left, add it to the history list + and execute it. */ + stripwhite (line); + + if (*line) + @{ + add_history (line); + execute_line (line); + @} + @} + + if (line) + free (line); + @} + exit (0); +@} + +/* Execute a command line. */ +execute_line (line) + char *line; +@{ + register int i; + COMMAND *find_command (), *command; + char *word; + + /* Isolate the command word. */ + i = 0; + while (line[i] && !whitespace (line[i])) + i++; + + word = line; + + if (line[i]) + line[i++] = '\0'; + + command = find_command (word); + + if (!command) + @{ + fprintf (stderr, "%s: No such command for FileMan.\n", word); + return; + @} + + /* Get argument to command, if any. */ + while (whitespace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + (*(command->func)) (word); +@} + +/* Look up NAME as the name of a command, and return a pointer to that + command. Return a NULL pointer if NAME isn't a command name. */ +COMMAND * +find_command (name) + char *name; +@{ + register int i; + + for (i = 0; commands[i].name; i++) + if (strcmp (name, commands[i].name) == 0) + return (&commands[i]); + + return ((COMMAND *)NULL); +@} + +/* Strip whitespace from the start and end of STRING. */ +stripwhite (string) + char *string; +@{ + register int i = 0; + + while (whitespace (string[i])) + i++; + + if (i) + strcpy (string, string + i); + + i = strlen (string) - 1; + + while (i > 0 && whitespace (string[i])) + i--; + + string[++i] = '\0'; +@} +@page +/* **************************************************************** */ +/* */ +/* Interface to Readline Completion */ +/* */ +/* **************************************************************** */ + +/* Tell the GNU Readline library how to complete. We want to try to complete + on command names if this is the first word in the line, or on filenames + if not. */ +initialize_readline () +@{ + char **fileman_completion (); + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "FileMan"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (Function *)fileman_completion; +@} + +/* Attempt to complete on the contents of TEXT. START and END show the + region of TEXT that contains the word to complete. We can use the + entire line in case we want to do some simple parsing. Return the + array of matches, or NULL if there aren't any. */ +char ** +fileman_completion (text, start, end) + char *text; + int start, end; +@{ + char **matches; + char *command_generator (); + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + to complete. Otherwise it is the name of a file in the current + directory. */ + if (start == 0) + matches = completion_matches (text, command_generator); + + return (matches); +@} + +/* Generator function for command completion. STATE lets us know whether + to start from scratch; without any state (i.e. STATE == 0), then we + start at the top of the list. */ +char * +command_generator (text, state) + char *text; + int state; +@{ + static int list_index, len; + char *name; + + /* If this is a new word to complete, initialize now. This includes + saving the length of TEXT for efficiency, and initializing the index + variable to 0. */ + if (!state) + @{ + list_index = 0; + len = strlen (text); + @} + + /* Return the next name which partially matches from the command list. */ + while (name = commands[list_index].name) + @{ + list_index++; + + if (strncmp (name, text, len) == 0) + return (name); + @} + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +@} +@page +/* **************************************************************** */ +/* */ +/* FileMan Commands */ +/* */ +/* **************************************************************** */ + +/* String to pass to system (). This is for the LIST, VIEW and RENAME + commands. */ +static char syscom[1024]; + +/* List the file(s) named in arg. */ +com_list (arg) + char *arg; +@{ + if (!arg) + arg = "*"; + + sprintf (syscom, "ls -FClg %s", arg); + system (syscom); +@} + +com_view (arg) + char *arg; +@{ + if (!valid_argument ("view", arg)) + return; + + sprintf (syscom, "cat %s | more", arg); + system (syscom); +@} + +com_rename (arg) + char *arg; +@{ + too_dangerous ("rename"); +@} + +com_stat (arg) + char *arg; +@{ + struct stat finfo; + + if (!valid_argument ("stat", arg)) + return; + + if (stat (arg, &finfo) == -1) + @{ + perror (arg); + return; + @} + + printf ("Statistics for `%s':\n", arg); + + printf ("%s has %d link%s, and is %d bytes in length.\n", arg, + finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s", finfo.st_size); + printf (" Created on: %s", ctime (&finfo.st_ctime)); + printf (" Last access at: %s", ctime (&finfo.st_atime)); + printf ("Last modified at: %s", ctime (&finfo.st_mtime)); +@} + +com_delete (arg) + char *arg; +@{ + too_dangerous ("delete"); +@} + +/* Print out help for ARG, or for all of the commands if ARG is + not present. */ +com_help (arg) + char *arg; +@{ + register int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) + @{ + if (!*arg || (strcmp (arg, commands[i].name) == 0)) + @{ + printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); + printed++; + @} + @} + + if (!printed) + @{ + printf ("No commands match `%s'. Possibilties are:\n", arg); + + for (i = 0; commands[i].name; i++) + @{ + /* Print in six columns. */ + if (printed == 6) + @{ + printed = 0; + printf ("\n"); + @} + + printf ("%s\t", commands[i].name); + printed++; + @} + + if (printed) + printf ("\n"); + @} +@} + +/* Change to the directory ARG. */ +com_cd (arg) + char *arg; +@{ + if (chdir (arg) == -1) + perror (arg); + + com_pwd (""); +@} + +/* Print out the current working directory. */ +com_pwd (ignore) + char *ignore; +@{ + char dir[1024]; + + (void) getwd (dir); + + printf ("Current directory is %s\n", dir); +@} + +/* The user wishes to quit using this program. Just set DONE non-zero. */ +com_quit (arg) + char *arg; +@{ + done = 1; +@} + +/* Function which tells you that you can't do this. */ +too_dangerous (caller) + char *caller; +@{ + fprintf (stderr, + "%s: Too dangerous for me to distribute. Write it yourself.\n", + caller); +@} + +/* Return non-zero if ARG is a valid argument for CALLER, else print + an error message and return zero. */ +int +valid_argument (caller, arg) + char *caller, *arg; +@{ + if (!arg || !*arg) + @{ + fprintf (stderr, "%s: Argument required.\n", caller); + return (0); + @} + + return (1); +@} +@end smallexample diff --git a/contrib/gdb/readline/doc/rluser.texinfo b/contrib/gdb/readline/doc/rluser.texinfo new file mode 100644 index 000000000000..da1111148bf9 --- /dev/null +++ b/contrib/gdb/readline/doc/rluser.texinfo @@ -0,0 +1,566 @@ +@ignore +This file documents the end user interface to the GNU command line +editing feautres. It is to be an appendix to manuals for programs which +use these features. There is a document entitled "readline.texinfo" +which contains both end-user and programmer documentation for the GNU +Readline Library. + +Copyright (C) 1988 Free Software Foundation, Inc. + +Authored by Brian Fox. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +Permission is granted to make and distribute verbatim copies of this manual +provided the copyright notice and this permission notice are preserved on +all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +GNU Copyright statement is available to the distributee, and provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ignore + +@node Command Line Editing +@appendix Command Line Editing + +This text describes GNU's command line editing interface. + +@menu +* Introduction and Notation:: Notation used in this text. +* Readline Interaction:: The minimum set of commands for editing a line. +* Readline Init File:: Customizing Readline from a user's view. +@end menu + +@node Introduction and Notation +@section Introduction to Line Editing + +The following paragraphs describe the notation we use to represent +keystrokes. + +The text @key{C-k} is read as `Control-K' and describes the character +produced when the Control key is depressed and the @key{k} key is struck. + +The text @key{M-k} is read as `Meta-K' and describes the character +produced when the meta key (if you have one) is depressed, and the @key{k} +key is struck. If you do not have a meta key, the identical keystroke +can be generated by typing @key{ESC} @i{first}, and then typing @key{k}. +Either process is known as @dfn{metafying} the @key{k} key. + +The text @key{M-C-k} is read as `Meta-Control-k' and describes the +character produced by @dfn{metafying} @key{C-k}. + +In addition, several keys have their own names. Specifically, +@key{DEL}, @key{ESC}, @key{LFD}, @key{SPC}, @key{RET}, and @key{TAB} all +stand for themselves when seen in this text, or in an init file +(@pxref{Readline Init File}, for more info). + +@node Readline Interaction +@section Readline Interaction +@cindex interaction, readline + +Often during an interactive session you type in a long line of text, +only to notice that the first word on the line is misspelled. The +Readline library gives you a set of commands for manipulating the text +as you type it in, allowing you to just fix your typo, and not forcing +you to retype the majority of the line. Using these editing commands, +you move the cursor to the place that needs correction, and delete or +insert the text of the corrections. Then, when you are satisfied with +the line, you simply press @key{RET}. You do not have to be at the +end of the line to press @key{RET}; the entire line is accepted +regardless of the location of the cursor within the line. + +@menu +* Readline Bare Essentials:: The least you need to know about Readline. +* Readline Movement Commands:: Moving about the input line. +* Readline Killing Commands:: How to delete text, and how to get it back! +* Readline Arguments:: Giving numeric arguments to commands. +@end menu + +@node Readline Bare Essentials +@subsection Readline Bare Essentials + +In order to enter characters into the line, simply type them. The typed +character appears where the cursor was, and then the cursor moves one +space to the right. If you mistype a character, you can use @key{DEL} to +back up, and delete the mistyped character. + +Sometimes you may miss typing a character that you wanted to type, and +not notice your error until you have typed several other characters. In +that case, you can type @key{C-b} to move the cursor to the left, and then +correct your mistake. Aftwerwards, you can move the cursor to the right +with @key{C-f}. + +When you add text in the middle of a line, you will notice that characters +to the right of the cursor get `pushed over' to make room for the text +that you have inserted. Likewise, when you delete text behind the cursor, +characters to the right of the cursor get `pulled back' to fill in the +blank space created by the removal of the text. A list of the basic bare +essentials for editing the text of an input line follows. + +@table @asis +@item @key{C-b} +Move back one character. +@item @key{C-f} +Move forward one character. +@item @key{DEL} +Delete the character to the left of the cursor. +@item @key{C-d} +Delete the character underneath the cursor. +@item @w{Printing characters} +Insert itself into the line at the cursor. +@item @key{C-_} +Undo the last thing that you did. You can undo all the way back to an +empty line. +@end table + +@node Readline Movement Commands +@subsection Readline Movement Commands + +The above table describes the most basic possible keystrokes that you need +in order to do editing of the input line. For your convenience, many +other commands have been added in addition to @key{C-b}, @key{C-f}, +@key{C-d}, and @key{DEL}. Here are some commands for moving more rapidly +about the line. + +@table @key +@item C-a +Move to the start of the line. +@item C-e +Move to the end of the line. +@item M-f +Move forward a word. +@item M-b +Move backward a word. +@item C-l +Clear the screen, reprinting the current line at the top. +@end table + +Notice how @key{C-f} moves forward a character, while @key{M-f} moves +forward a word. It is a loose convention that control keystrokes +operate on characters while meta keystrokes operate on words. + +@node Readline Killing Commands +@subsection Readline Killing Commands + +@dfn{Killing} text means to delete the text from the line, but to save +it away for later use, usually by @dfn{yanking} it back into the line. +If the description for a command says that it `kills' text, then you can +be sure that you can get the text back in a different (or the same) +place later. + +Here is the list of commands for killing text. + +@table @key +@item C-k +Kill the text from the current cursor position to the end of the line. + +@item M-d +Kill from the cursor to the end of the current word, or if between +words, to the end of the next word. + +@item M-DEL +Kill from the cursor to the start of the previous word, or if between +words, to the start of the previous word. + +@item C-w +Kill from the cursor to the previous whitespace. This is different than +@key{M-DEL} because the word boundaries differ. + +@end table + +And, here is how to @dfn{yank} the text back into the line. + +@table @key +@item C-y +Yank the most recently killed text back into the buffer at the cursor. + +@item M-y +Rotate the kill-ring, and yank the new top. You can only do this if +the prior command is @key{C-y} or @key{M-y}. +@end table + +When you use a kill command, the text is saved in a @dfn{kill-ring}. +Any number of consecutive kills save all of the killed text together, so +that when you yank it back, you get it in one clean sweep. The kill +ring is not line specific; the text that you killed on a previously +typed line is available to be yanked back later, when you are typing +another line. + +@node Readline Arguments +@subsection Readline Arguments + +You can pass numeric arguments to Readline commands. Sometimes the +argument acts as a repeat count, other times it is the @i{sign} of the +argument that is significant. If you pass a negative argument to a +command which normally acts in a forward direction, that command will +act in a backward direction. For example, to kill text back to the +start of the line, you might type @key{M--} @key{C-k}. + +The general way to pass numeric arguments to a command is to type meta +digits before the command. If the first `digit' you type is a minus +sign (@key{-}), then the sign of the argument will be negative. Once +you have typed one meta digit to get the argument started, you can type +the remainder of the digits, and then the command. For example, to give +the @key{C-d} command an argument of 10, you could type @key{M-1 0 C-d}. + + +@node Readline Init File +@section Readline Init File + +Although the Readline library comes with a set of @sc{gnu} Emacs-like +keybindings, it is possible that you would like to use a different set +of keybindings. You can customize programs that use Readline by putting +commands in an @dfn{init} file in your home directory. The name of this +file is @file{~/.inputrc}. + +When a program which uses the Readline library starts up, the +@file{~/.inputrc} file is read, and the keybindings are set. + +In addition, the @key{C-x C-r} command re-reads this init file, thus +incorporating any changes that you might have made to it. + +@menu +* Readline Init Syntax:: Syntax for the commands in @file{~/.inputrc}. +* Readline vi Mode:: Switching to @code{vi} mode in Readline. +@end menu + +@node Readline Init Syntax +@subsection Readline Init Syntax + +There are only four constructs allowed in the @file{~/.inputrc} +file: + +@table @asis +@item Variable Settings +You can change the state of a few variables in Readline. You do this by +using the @code{set} command within the init file. Here is how you +would specify that you wish to use @code{vi} line editing commands: + +@example +set editing-mode vi +@end example + +Right now, there are only a few variables which can be set; so few in +fact, that we just iterate them here: + +@table @code + +@item editing-mode +@vindex editing-mode +The @code{editing-mode} variable controls which editing mode you are +using. By default, @sc{gnu} Readline starts up in Emacs editing mode, where +the keystrokes are most similar to Emacs. This variable can either be +set to @code{emacs} or @code{vi}. + +@item horizontal-scroll-mode +@vindex horizontal-scroll-mode +This variable can either be set to @code{On} or @code{Off}. Setting it +to @code{On} means that the text of the lines that you edit will scroll +horizontally on a single screen line when they are larger than the width +of the screen, instead of wrapping onto a new screen line. By default, +this variable is set to @code{Off}. + +@item mark-modified-lines +@vindex mark-modified-lines +This variable when set to @code{On}, says to display an asterisk +(@samp{*}) at the starts of history lines which have been modified. +This variable is off by default. + +@item prefer-visible-bell +@vindex prefer-visible-bell +If this variable is set to @code{On} it means to use a visible bell if +one is available, rather than simply ringing the terminal bell. By +default, the value is @code{Off}. +@end table + +@item Key Bindings +The syntax for controlling keybindings in the @file{~/.inputrc} file is +simple. First you have to know the @i{name} of the command that you +want to change. The following pages contain tables of the command name, +the default keybinding, and a short description of what the command +does. + +Once you know the name of the command, simply place the name of the key +you wish to bind the command to, a colon, and then the name of the +command on a line in the @file{~/.inputrc} file. The name of the key +can be expressed in different ways, depending on which is most +comfortable for you. + +@table @asis +@item @w{@var{keyname}: @var{function-name} or @var{macro}} +@var{keyname} is the name of a key spelled out in English. For example: +@example +Control-u: universal-argument +Meta-Rubout: backward-kill-word +Control-o: ">&output" +@end example + +In the above example, @key{C-u} is bound to the function +@code{universal-argument}, and @key{C-o} is bound to run the macro +expressed on the right hand side (that is, to insert the text +@samp{>&output} into the line). + +@item @w{"@var{keyseq}": @var{function-name} or @var{macro}} +@var{keyseq} differs from @var{keyname} above in that strings denoting +an entire key sequence can be specified. Simply place the key sequence +in double quotes. @sc{gnu} Emacs style key escapes can be used, as in the +following example: + +@example +"\C-u": universal-argument +"\C-x\C-r": re-read-init-file +"\e[11~": "Function Key 1" +@end example + +In the above example, @key{C-u} is bound to the function +@code{universal-argument} (just as it was in the first example), +@key{C-x C-r} is bound to the function @code{re-read-init-file}, and +@key{ESC [ 1 1 ~} is bound to insert the text @samp{Function Key 1}. + +@end table +@end table + +@menu +* Commands For Moving:: Moving about the line. +* Commands For History:: Getting at previous lines. +* Commands For Text:: Commands for changing text. +* Commands For Killing:: Commands for killing and yanking. +* Numeric Arguments:: Specifying numeric arguments, repeat counts. +* Commands For Completion:: Getting Readline to do the typing for you. +* Miscellaneous Commands:: Other miscillaneous commands. +@end menu + +@need 2000 +@node Commands For Moving +@subsubsection Commands For Moving + +@ftable @code +@item beginning-of-line (@key{C-a}) +Move to the start of the current line. + +@item end-of-line (@key{C-e}) +Move to the end of the line. + +@item forward-char (@key{C-f}) +Move forward a character. + +@item backward-char (@key{C-b}) +Move back a character. + +@item forward-word (@key{M-f}) +Move forward to the end of the next word. + +@item backward-word (@key{M-b}) +Move back to the start of this, or the previous, word. + +@item clear-screen (@key{C-l}) +Clear the screen leaving the current line at the top of the screen. + +@end ftable + +@need 2000 +@node Commands For History +@subsubsection Commands For Manipulating The History + +@ftable @code +@item accept-line (Newline, Return) +Accept the line regardless of where the cursor is. If this line is +non-empty, add it to the history list. If this line was a history +line, then restore the history line to its original state. + +@item previous-history (@key{C-p}) +Move `up' through the history list. + +@item next-history (@key{C-n}) +Move `down' through the history list. + +@item beginning-of-history (@key{M-<}) +Move to the first line in the history. + +@item end-of-history (@key{M->}) +Move to the end of the input history, i.e., the line you are entering. + +@item reverse-search-history (@key{C-r}) +Search backward starting at the current line and moving `up' through +the history as necessary. This is an incremental search. + +@item forward-search-history (@key{C-s}) +Search forward starting at the current line and moving `down' through +the the history as necessary. + +@end ftable + +@need 2000 +@node Commands For Text +@subsubsection Commands For Changing Text + +@ftable @code +@item delete-char (@key{C-d}) +Delete the character under the cursor. If the cursor is at the +beginning of the line, and there are no characters in the line, and +the last character typed was not @key{C-d}, then return EOF. + +@item backward-delete-char (Rubout) +Delete the character behind the cursor. A numeric argument says to kill +the characters instead of deleting them. + +@item quoted-insert (@key{C-q}, @key{C-v}) +Add the next character that you type to the line verbatim. This is +how to insert things like @key{C-q} for example. + +@item tab-insert (@key{M-TAB}) +Insert a tab character. + +@item self-insert (a, b, A, 1, !, ...) +Insert yourself. + +@item transpose-chars (@key{C-t}) +Drag the character before point forward over the character at point. +Point moves forward as well. If point is at the end of the line, then +transpose the two characters before point. Negative arguments don't work. + +@item transpose-words (@key{M-t}) +Drag the word behind the cursor past the word in front of the cursor +moving the cursor over that word as well. + +@item upcase-word (@key{M-u}) +Uppercase all letters in the current (or following) word. With a +negative argument, do the previous word, but do not move point. + +@item downcase-word (@key{M-l}) +Lowercase all letters in the current (or following) word. With a +negative argument, do the previous word, but do not move point. + +@item capitalize-word (@key{M-c}) +Uppercase the first letter in the current (or following) word. With a +negative argument, do the previous word, but do not move point. + +@end ftable + +@need 2000 +@node Commands For Killing +@subsubsection Killing And Yanking + +@ftable @code +@item kill-line (@key{C-k}) +Kill the text from the current cursor position to the end of the line. + +@item backward-kill-line () +Kill backward to the beginning of the line. This is normally unbound. + +@item kill-word (@key{M-d}) +Kill from the cursor to the end of the current word, or if between +words, to the end of the next word. + +@item backward-kill-word (@key{M-DEL}) +Kill the word behind the cursor. + +@item unix-line-discard (@key{C-u}) +Kill the whole line the way @key{C-u} used to in Unix line input. +The killed text is saved on the kill-ring. + +@item unix-word-rubout (@key{C-w}) +Kill the word the way @key{C-w} used to in Unix line input. +The killed text is saved on the kill-ring. This is different than +backward-kill-word because the word boundaries differ. + +@item yank (@key{C-y}) +Yank the top of the kill ring into the buffer at point. + +@item yank-pop (@key{M-y}) +Rotate the kill-ring, and yank the new top. You can only do this if +the prior command is yank or yank-pop. +@end ftable + +@need 2000 +@node Numeric Arguments +@subsubsection Specifying Numeric Arguments + +@ftable @code + +@item digit-argument (@key{M-0}, @key{M-1}, ... @key{M--}) +Add this digit to the argument already accumulating, or start a new +argument. @key{M--} starts a negative argument. + +@item universal-argument () +Do what @key{C-u} does in @sc{gnu} Emacs. By default, this is not bound. +@end ftable + + +@need 2000 +@node Commands For Completion +@subsubsection Letting Readline Type For You + +@ftable @code +@item complete (TAB) +Attempt to do completion on the text before point. This is +implementation defined. Generally, if you are typing a filename +argument, you can do filename completion; if you are typing a command, +you can do command completion, if you are typing in a symbol to GDB, you +can do symbol name completion, if you are typing in a variable to Bash, +you can do variable name completion. + +@item possible-completions (M-?) +List the possible completions of the text before point. +@end ftable + +@need 2000 +@node Miscellaneous Commands +@subsubsection Some Miscellaneous Commands + +@ftable @code + +@item re-read-init-file (@key{C-x} @key{C-r}) +Read in the contents of your @file{~/.inputrc} file, and incorporate +any bindings found there. + +@item abort (@key{C-g}) +Stop running the current editing command. + +@ignore +@c I have no idea what this means, and can't figure it out by +@c experiment, and can't find it in the readline source. +@c doc@cygnus.com, 20may1993. +@item do-uppercase-version (@key{M-a}, @key{M-b}, ...) +Run the command that is bound to your uppercase brother. +@end ignore + +@item prefix-meta (ESC) +Make the next character that you type be metafied. This is for people +without a meta key. Typing @key{ESC f} is equivalent to typing +@key{M-f}. + +@item undo (@key{C-_}) +Incremental undo, separately remembered for each line. + +@item revert-line (@key{M-r}) +Undo all changes made to this line. This is like typing the `undo' +command enough times to get back to the beginning. +@end ftable + +@need 2000 +@node Readline vi Mode +@subsection Readline @code{vi} Mode + +@cindex @code{vi} style command editing +@kindex toggle-editing-mode +While the Readline library does not have a full set of @code{vi} editing +functions, it does contain enough to allow simple editing of the line. + +In order to switch interactively between @sc{gnu} Emacs and @code{vi} +editing modes, use the command @key{M-C-j} (toggle-editing-mode). + +When you enter a line in @code{vi} mode, you are already placed in `insertion' +mode, as if you had typed an `i'. Pressing @key{ESC} switches you into +`edit' mode, where you can edit the text of the line with the standard +@code{vi} movement keys, move to previous history lines with `k', and following +lines with `j', and so forth. +